Skip to content

Commit

Permalink
Implement searchbar_card for wave
Browse files Browse the repository at this point in the history
searchbar_card can be used to horizontally align textbox and button on the requirement. Fixes: #372
  • Loading branch information
VijithaEkanayake committed Dec 15, 2020
1 parent 80def55 commit f51ee5a
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 0 deletions.
16 changes: 16 additions & 0 deletions py/examples/searchbar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SearchBar
# SearchBar is used to align textbox and button components horizontally.
# searchbar_card can be used to horizontally align textbox and button on the requirement.
# ---
from h2o_wave import site, ui

page = site['/demo']


page["search_bar"] = ui.searchbar_card(
box="1 1 -1 1", items=[
ui.textbox(name='text', label='', placeholder='#wave', multiline=False, trigger=False),
ui.button(name="search", label="search", primary=True),
], direction=ui.SearchBarDirection.ROW, justify=ui.SearchBarJustify.CENTER)

page.save()
1 change: 1 addition & 0 deletions py/examples/tour.conf
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ form_menu.py
form_template.py
form_markup.py
stepper.py
searchbar.py
table_markdown.py
table.py
table_sort.py
Expand Down
105 changes: 105 additions & 0 deletions py/h2o_wave/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -5459,6 +5459,111 @@ def load(__d: Dict) -> 'Layout':
max_height,
)

class SearchBarDirection:
ROW = 'row'
COLUMN = 'column'


class SearchBarJustify:
START = 'start'
END = 'end'
CENTER = 'center'
BETWEEN = 'between'
AROUND = 'around'


class SearchBarAlign:
START = 'start'
END = 'end'
CENTER = 'center'
STRETCH = 'stretch'


class SearchBarWrap:
START = 'start'
END = 'end'
CENTER = 'center'
BETWEEN = 'between'
AROUND = 'around'
STRETCH = 'stretch'

class SearchBarCard:
"""Create a searchbar.
"""
def __init__(
self,
box: str,
items: Union[List[Component], str],
direction: Optional[str] = None,
justify: Optional[str] = None,
align: Optional[str] = None,
wrap: Optional[str] = None,
commands: Optional[List[Command]] = None,
):
self.box = box
"""A string indicating how to place this component on the page."""
self.items = items
"""The components in this searchbar."""
self.direction = direction
"""SearchBar direction. One of 'horizontal', 'vertical'. See enum h2o_wave.ui.SearchBarDirection."""
self.justify = justify
"""SearchBar strategy for main axis. One of 'start', 'end', 'center', 'between', 'around'. See enum h2o_wave.ui.SearchBarJustify."""
self.align = align
"""SearchBar strategy for cross axis. One of 'start', 'end', 'center', 'baseline', 'stretch'. See enum h2o_wave.ui.SearchBarAlign."""
self.wrap = wrap
"""SearchBar strategy. One of 'start', 'end', 'center', 'between', 'around', 'stretch'. See enum h2o_wave.ui.SearchBarWrap."""
self.commands = commands
"""Contextual menu commands for this component."""

def dump(self) -> Dict:
"""Returns the contents of this object as a dict."""
if self.box is None:
raise ValueError('SearchBarCard.box is required.')
if self.items is None:
raise ValueError('SearchBarCard.items is required.')
return _dump(
view='searchbar',
box=self.box,
items=self.items if isinstance(self.items, str) else [__e.dump() for __e in self.items],
direction=self.direction,
justify=self.justify,
align=self.align,
wrap=self.wrap,
commands=None if self.commands is None else [__e.dump() for __e in self.commands],
)

@staticmethod
def load(__d: Dict) -> 'SearchBarCard':
"""Creates an instance of this class using the contents of a dict."""
__d_box: Any = __d.get('box')
if __d_box is None:
raise ValueError('SearchBarCard.box is required.')
__d_items: Any = __d.get('items')
if __d_items is None:
raise ValueError('SearchBarCard.items is required.')
__d_direction: Any = __d.get('direction')
__d_justify: Any = __d.get('justify')
__d_align: Any = __d.get('align')
__d_wrap: Any = __d.get('wrap')
# if __d_direction is None:
# raise ValueError('SearchBarCard.direction is required.')
__d_commands: Any = __d.get('commands')
box: str = __d_box
items: Union[List[Component], str] = __d_items if isinstance(__d_items, str) else [Component.load(__e) for __e in __d_items]
direction: Optional[str] = __d_direction
justify: Optional[str] = __d_justify
align: Optional[str] = __d_align
wrap: Optional[str] = __d_wrap
commands: Optional[List[Command]] = None if __d_commands is None else [Command.load(__e) for __e in __d_commands]
return SearchBarCard(
box,
items,
direction,
justify,
align,
wrap,
commands,
)

class Dialog:
"""A dialog box (Dialog) is a temporary pop-up that takes focus from the page or app
Expand Down
33 changes: 33 additions & 0 deletions py/h2o_wave/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -1835,6 +1835,39 @@ def form_card(
)


def searchbar_card(
box: str,
items: Union[List[Component], str],
direction: Optional[str] = None,
justify: Optional[str] = None,
align: Optional[str] = None,
wrap: Optional[str] = None,
commands: Optional[List[Command]] = None,
) -> SearchBarCard:
"""Create a searchbar.
Args:
box: A string indicating how to place this component on the page.
items: The components in this searchbar.
direction: Layout direction. One of 'horizontal', 'vertical'. See enum h2o_wave.ui.FlexCardDirection.
justify: Layout strategy for main axis. One of 'start', 'end', 'center', 'between', 'around'. See enum h2o_wave.ui.FlexCardJustify.
align: Layout strategy for cross axis. One of 'start', 'end', 'center', 'baseline', 'stretch'. See enum h2o_wave.ui.FlexCardAlign.
wrap: Wrapping strategy. One of 'start', 'end', 'center', 'between', 'around', 'stretch'. See enum h2o_wave.ui.FlexCardWrap.
commands: Contextual menu commands for this component.
Returns:
A `h2o_wave.types.SearchBarCard` instance.
"""
return SearchBarCard(
box,
items,
direction,
justify,
align,
wrap,
commands,
)


def frame_card(
box: str,
title: str,
Expand Down
1 change: 1 addition & 0 deletions ui/src/cards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import './none'
import './pixel_art'
import './plot'
import './repeat'
import './searchbar'
import './small_series_stat'
import './small_stat'
import './tab'
Expand Down
20 changes: 20 additions & 0 deletions ui/src/searchbar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'
import { render } from '@testing-library/react'
import { View } from './form'
import * as T from './qd'

const
name = 'searchbar',
formProps: T.Card<any> = {
name,
state: {},
changed: T.box(false)
}

describe('Searchbar.tsx', () => {

it('Renders data-test attr', () => {
const { queryByTestId } = render(<View {...formProps} />)
expect(queryByTestId(name)).toBeInTheDocument()
})
})
125 changes: 125 additions & 0 deletions ui/src/searchbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import * as Fluent from '@fluentui/react'
import React from 'react'
import {Button, Buttons, XButtons, XStandAloneButton} from './button'
import {Label, XLabel} from './label'
import {cards} from './layout'
import {bond, Card, Dict, Packed, S, unpack, xid} from './qd'
import {Textbox, XTextbox} from './textbox'
import {getTheme} from './theme'
import {XToolTip} from './tooltip'


/** Create a SearchBar. */
export interface SearchBar {
/** Label. */
label?: Label;
/** Textbox. */
textbox?: Textbox;
/** Button. */
button?: Button;
/** Button set. */
buttons?: Buttons;
}

/** Create a searchbar. */
interface State {
/** The components in this searchbar. */
items: Packed<SearchBar[]>;

/** SearchBar direction. */
direction?: 'horizontal' | 'vertical'

/** SearchBar strategy for main axis. */
justify?: 'start' | 'end' | 'center' | 'between' | 'around'

/** SearchBar strategy for cross axis. */
align?: 'start' | 'end' | 'center' | 'baseline' | 'stretch'

/** SearchBar wrapping strategy. */
wrap?: 'start' | 'end' | 'center' | 'between' | 'around' | 'stretch'
}


const
theme = getTheme(),
defaults: Partial<State> = {items: []},
directions: Dict<S> = {
horizontal: 'row',
vertical: 'column',
},
justifications: Dict<S> = {
start: 'flex-start',
end: 'flex-end',
center: 'center',
between: 'space-between',
around: 'space-around',
},
alignments: Dict<S> = {
start: 'flex-start',
end: 'flex-end',
center: 'center',
baseline: 'baseline',
stretch: 'stretch',
},
wrappings: Dict<S> = {
start: 'flex-start',
end: 'flex-end',
center: 'center',
between: 'space-between',
around: 'space-around',
stretch: 'stretch',
},
toFlexStyle = (state: State): React.CSSProperties => {
const
css: React.CSSProperties = { display: 'flex', flexGrow: 1 },
direction = directions[state.direction || ''],
justify = justifications[state.justify || ''],
align = alignments[state.align || ''],
wrap = wrappings[state.wrap || '']

if (direction) css.flexDirection = direction as any
if (justify) css.justifyContent = justify
if (align) css.alignItems = align
if (wrap) {
css.flexWrap = 'wrap'
css.alignContent = wrap
}
return css
}


export const
XSearchBar = ({ items }: { items: SearchBar[] }) => {
const components = items.map(m => <XStandardSearchBar key={xid()} model={m} />)
return <>{components}</>
}

const
XStandardSearchBar = ({ model: m }: { model: SearchBar }) => {
if (m.label) return <XToolTip content={m.label.tooltip} expand={false}><XLabel model={m.label} /></XToolTip>
if (m.textbox) return <XToolTip content={m.textbox.tooltip}><XTextbox model={m.textbox} /></XToolTip>
if (m.buttons) return <XButtons model={m.buttons} />
if (m.button) return <XToolTip content={m.button.tooltip} showIcon={false} expand={false}><XStandAloneButton model={m.button} /></XToolTip>
return <Fluent.MessageBar messageBarType={Fluent.MessageBarType.severeWarning}>This component could not be rendered.</Fluent.MessageBar>
}

export const
View = bond(({ name, state, changed }: Card<State>) => {

const
render = () => {
const
s = theme.merge(defaults, state),
items = unpack<SearchBar[]>(s.items)
return (
<div data-test={name} style={toFlexStyle(state)}>
<XSearchBar items={items} />
</div>
)

}
return { render, changed }
})

cards.register('searchbar', View)

0 comments on commit f51ee5a

Please sign in to comment.