diff --git a/client-app/src/admin/AppModel.ts b/client-app/src/admin/AppModel.ts index 994d80c6b..9d207db71 100644 --- a/client-app/src/admin/AppModel.ts +++ b/client-app/src/admin/AppModel.ts @@ -42,7 +42,8 @@ export class AppModel extends BaseAppModel { {name: 'select', path: '/select'}, {name: 'webSockets', path: '/webSockets'}, {name: 'viewColumnFilters', path: '/viewColumnFilters'}, - {name: 'storeColumnFilters', path: '/storeColumnFilters'} + {name: 'storeColumnFilters', path: '/storeColumnFilters'}, + {name: 'button', path: '/button'} ] }, { diff --git a/client-app/src/admin/tests/TestsTab.ts b/client-app/src/admin/tests/TestsTab.ts index 9db6da0c5..9e9c17d45 100644 --- a/client-app/src/admin/tests/TestsTab.ts +++ b/client-app/src/admin/tests/TestsTab.ts @@ -13,6 +13,7 @@ import {dataViewTestPanel} from './dataview/DataViewTestPanel'; import {storeColumnFilterPanel} from './columnFilters/store/StoreColumnFilterPanel'; import {viewColumnFilterPanel} from './columnFilters/view/ViewColumnFilterPanel'; import {gridScrolling} from './gridScrolling/GridScrolling'; +import {buttonTestPanel} from './button/ButtonTestPanel'; export const testsTab = hoistCmp.factory(() => { return tabContainer({ @@ -39,7 +40,8 @@ export const testsTab = hoistCmp.factory(() => { id: 'viewColumnFilters', title: 'View Column Filters', content: viewColumnFilterPanel - } + }, + {id: 'button', title: 'Buttons', content: buttonTestPanel} ] } }); diff --git a/client-app/src/admin/tests/button/ButtonTestPanel.scss b/client-app/src/admin/tests/button/ButtonTestPanel.scss new file mode 100644 index 000000000..492f3c9a9 --- /dev/null +++ b/client-app/src/admin/tests/button/ButtonTestPanel.scss @@ -0,0 +1,43 @@ +.tb-split-button-test-panel { + background: var(--xh-bg); + border: var(--xh-border-solid); + margin: var(--xh-pad-px); + + &__inner { + display: flex; + flex-direction: column; + flex-wrap: wrap; + overflow-y: auto; + align-content: flex-start; + + .tb-button-example { + border: var(--xh-border-solid); + margin: var(--xh-pad-px); + width: 250px; + + .xh-split-button { + margin: var(--xh-pad-px); + } + + ul { + border-top: var(--xh-border-solid); + margin: var(--xh-pad-px) var(--xh-pad-half-px) 0 0; + padding: var(--xh-pad-half-px); + + li { + list-style: none; + font-family: var(--xh-font-family-mono); + font-size: var(--xh-font-size-small-px); + } + } + } + } +} + +.special-split-button { + .xh-split-button__menu-item, + .xh-split-button__primary { + font-weight: bold; + font-style: italic; + } +} diff --git a/client-app/src/admin/tests/button/ButtonTestPanel.ts b/client-app/src/admin/tests/button/ButtonTestPanel.ts new file mode 100644 index 000000000..3018ffbb5 --- /dev/null +++ b/client-app/src/admin/tests/button/ButtonTestPanel.ts @@ -0,0 +1,108 @@ +import {div, li, ul} from '@xh/hoist/cmp/layout'; +import {hoistCmp} from '@xh/hoist/core'; +import {splitButton} from '@xh/hoist/desktop/cmp/button'; +import {panel} from '@xh/hoist/desktop/cmp/panel'; +import {Icon} from '@xh/hoist/icon'; +import {elementFromContent} from '@xh/hoist/utils/react'; +import {castArray} from 'lodash'; +import './ButtonTestPanel.scss'; + +export const buttonTestPanel = hoistCmp.factory(() => { + return panel({ + className: 'xh-tiled-bg', + items: [splitButtonPanel()] + }); +}); + +const splitButtonPanel = hoistCmp.factory(() => { + const text = 'Hoist Apps', + recalls = { + text: 'FDA Recalls', + icon: Icon.health(), + actionFn: () => window.open('/recalls', '_blank') + }, + news = { + text: 'News', + icon: Icon.news(), + actionFn: () => window.open('/news', '_blank') + }, + portfolio = { + text: 'Portfolio', + icon: Icon.portfolio(), + actionFn: () => window.open('/portfolio', '_blank') + }, + menuItems = [portfolio, recalls, news], + defaultConf = { + text, + menuItems, + onClick: () => window.open('/app/examples', '_blank') + }; + + return panel({ + title: 'SplitButton', + className: 'tb-split-button-test-panel', + item: div({ + className: 'tb-split-button-test-panel__inner', + items: [ + example({ + content: () => splitButton({...defaultConf}) + }), + example({ + features: `menuSide: 'left'`, + content: () => splitButton({...defaultConf, menuSide: 'left'}) + }), + example({ + features: `minimal: true`, + content: () => splitButton({...defaultConf, minimal: true}) + }), + example({ + features: ['minimal: true', `intent: 'primary'`], + content: () => splitButton({...defaultConf, minimal: true, intent: 'primary'}) + }), + example({ + features: ['icon', `intent: 'success'`], + content: () => + splitButton({...defaultConf, icon: Icon.books(), intent: 'success'}) + }), + example({ + features: 'disabled: true', + content: () => splitButton({...defaultConf, disabled: true}) + }), + example({ + features: 'menuItems: []', + content: () => splitButton({...defaultConf, menuItems: []}) + }), + example({ + features: 'menuItems: undefined', + content: () => splitButton({...defaultConf, menuItems: undefined}) + }), + example({ + features: `menuItem props`, + content: () => + splitButton({ + ...defaultConf, + menuItems: [ + {...portfolio, intent: 'primary'}, + {...news, disabled: true}, + {...recalls} + ] + }) + }), + example({ + features: [`custom className`], + content: () => splitButton({...defaultConf, className: 'special-split-button'}) + }) + ] + }) + }); +}); + +const example = hoistCmp.factory(({features, content}) => + div({ + className: 'tb-button-example', + items: [ + elementFromContent(content), + features ? ul(castArray(features).map(it => li(it))) : null + ] + }) +); diff --git a/client-app/src/desktop/tabs/forms/ToolbarFormPanel.tsx b/client-app/src/desktop/tabs/forms/ToolbarFormPanel.tsx index db4a7f6ec..bcc11f1b1 100644 --- a/client-app/src/desktop/tabs/forms/ToolbarFormPanel.tsx +++ b/client-app/src/desktop/tabs/forms/ToolbarFormPanel.tsx @@ -6,7 +6,6 @@ import {panel} from '@xh/hoist/desktop/cmp/panel'; import {button} from '@xh/hoist/desktop/cmp/button'; import {form} from '@xh/hoist/cmp/form'; import {formField} from '@xh/hoist/desktop/cmp/form'; -import {toolbar} from '@xh/hoist/desktop/cmp/toolbar'; import { buttonGroupInput, checkbox, @@ -17,6 +16,8 @@ import { switchInput, textInput } from '@xh/hoist/desktop/cmp/input'; +import {toolbar, toolbarSep} from '@xh/hoist/desktop/cmp/toolbar'; + import {usStates} from '../../../core/data'; import {wrapper} from '../../common'; import {ToolbarFormPanelModel} from './ToolbarFormPanelModel'; @@ -138,6 +139,7 @@ export const toolbarFormPanel = hoistCmp.factory({ placeholder: 'Select a state...' }) }), + toolbarSep(), formField({ field: 'option3', item: radioInput({ diff --git a/client-app/src/desktop/tabs/panels/ToolbarPanel.ts b/client-app/src/desktop/tabs/panels/ToolbarPanel.ts index d24a0e511..cc09aa7b2 100644 --- a/client-app/src/desktop/tabs/panels/ToolbarPanel.ts +++ b/client-app/src/desktop/tabs/panels/ToolbarPanel.ts @@ -1,4 +1,5 @@ import {filler, hframe, placeholder, span} from '@xh/hoist/cmp/layout'; +import {splitButton} from '@xh/hoist/desktop/cmp/button'; import {creates, hoistCmp, XH} from '@xh/hoist/core'; import {button} from '@xh/hoist/desktop/cmp/button'; import {buttonGroupInput, select, switchInput} from '@xh/hoist/desktop/cmp/input'; @@ -69,6 +70,23 @@ const topBar = hoistCmp.factory(({model}) => menuItem({text: 'Menu Item 3'}) ) }), + splitButton({ + text: 'Split Buttons', + icon: Icon.books(), + onClick: () => window.open('/app/examples', '_blank'), + menuItems: [ + { + text: 'Portfolio App', + icon: Icon.portfolio(), + actionFn: () => window.open('/portfolio', '_blank') + }, + { + text: 'News App', + icon: Icon.news(), + actionFn: () => window.open('/news', '_blank') + } + ] + }), filler(), switchInput({ bind: 'enableTerminate', diff --git a/gradle.properties b/gradle.properties index 793047c56..ba9cd30e6 100755 --- a/gradle.properties +++ b/gradle.properties @@ -17,4 +17,4 @@ enableHotSwap=false org.gradle.daemon=true org.gradle.parallel=true -org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx1024M +org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Xmx1024M \ No newline at end of file