import { ApproxStructure, Assertions, GeneralSteps, Step, type StructAssert } from '@ephox/agar'; import { UnitTest } from '@ephox/bedrock-client'; import { Arr, Result } from '@ephox/katamari'; import { Css } from '@ephox/sugar'; import * as GuiFactory from 'ephox/alloy/api/component/GuiFactory'; import * as Memento from 'ephox/alloy/api/component/Memento'; import { Button } from 'ephox/alloy/api/ui/Button'; import { SplitFloatingToolbar } from 'ephox/alloy/api/ui/SplitFloatingToolbar'; import * as GuiSetup from 'ephox/alloy/test/GuiSetup'; import * as Sinks from 'ephox/alloy/test/Sinks'; import * as TestPartialToolbarGroup from 'ephox/alloy/test/toolbar/TestPartialToolbarGroup'; UnitTest.asynctest('SplitFloatingToolbarTest', (success, failure) => { const sinkComp = Sinks.relativeSink(); const anchorButtonMem = Memento.record(Button.sketch({ dom: { tag: 'button', classes: [ 'anchor-button' ], innerHtml: '-' } })); GuiSetup.setup((store, _doc, _body) => { const pPrimary = SplitFloatingToolbar.parts.primary({ dom: { tag: 'div', classes: [ 'test-toolbar-primary' ] }, shell: true }); return GuiFactory.build( SplitFloatingToolbar.sketch({ dom: { tag: 'div', classes: [ 'test-split-toolbar' ], styles: { width: '400px', outline: '2px solid blue' } }, lazySink: (_comp) => { return Result.value(sinkComp); }, components: [ pPrimary ], markers: { overflowToggledClass: 'test-more-button-toggled' }, parts: { 'overflow-group': TestPartialToolbarGroup.munge({ items: [ ] }), 'overflow-button': { dom: { tag: 'button', classes: [ 'more-button' ], innerHtml: '+' } }, 'overflow': { dom: { tag: 'div', classes: [ 'test-toolbar-overflow' ] } } }, onOpened: store.adder('onOpened'), onClosed: store.adder('onClosed') }) ); }, (doc, _body, gui, component, store) => { gui.add(sinkComp); gui.add(GuiFactory.build(anchorButtonMem.asSpec())); const makeButton = (itemSpec: { text: string }) => Button.sketch({ dom: { tag: 'button', innerHtml: itemSpec.text } }); const sResetWidth = (px: string) => Step.sync(() => { Css.set(component.element, 'width', px); SplitFloatingToolbar.refresh(component); }); const group1 = ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('test-toolbar-group') ], children: [ s.element('button', { html: str.is('A') }), s.element('button', { html: str.is('B') }) ] })); const group2 = ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('test-toolbar-group') ], children: [ s.element('button', { html: str.is('C') }), s.element('button', { html: str.is('D') }) ] })); const group3 = ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('test-toolbar-group') ], children: [ s.element('button', { html: str.is('E') }), s.element('button', { html: str.is('F') }), s.element('button', { html: str.is('G') }) ] })); const oGroup = ApproxStructure.build((s, str, arr) => s.element('div', { classes: [ arr.has('test-toolbar-group') ], children: [ s.element('button', { html: str.is('+') }) ] })); const sAssertGroups = (label: string, pGroups: StructAssert[], oGroups: StructAssert[]) => GeneralSteps.sequence([ Assertions.sAssertStructure( label, ApproxStructure.build((s, _str, arr) => s.element('div', { children: [ s.element('div', { classes: [ arr.has('test-toolbar-primary') ], children: pGroups }) ] })), component.element ), Assertions.sAssertStructure( label, ApproxStructure.build((s, str, arr) => s.element('div', { children: [ s.element('div', { attrs: { id: str.contains('aria-controls') }, children: [ s.element('div', { classes: [ arr.has('test-toolbar-overflow') ], children: oGroups }) ] }) ] })), sinkComp.element ) ]); const sAssertSplitFloatingToolbarToggleState = (expected: boolean) => Step.sync(() => { Assertions.assertEq('Expected split floating toolbar toggle state to be ' + expected, expected, SplitFloatingToolbar.isOpen(component)); }); const sToggleSplitFloatingToolbar = () => Step.sync(() => { SplitFloatingToolbar.toggle(component); }); return [ GuiSetup.mAddStyles(doc, [ '.test-toolbar-group { display: flex; }', '.test-split-toolbar > div { display: flex; }', '.test-split-toolbar button { width: 100px; }', '.test-toolbar-overflow button { width: 100px; }', '.test-split-toolbar button.more-button { width: 50px; }' ]), store.sAssertEq('Assert initial store state', [ ]), sAssertSplitFloatingToolbarToggleState(false), Step.sync(() => { const groups = TestPartialToolbarGroup.createGroups([ { items: Arr.map([{ text: 'A' }, { text: 'B' }], makeButton) }, { items: Arr.map([{ text: 'C' }, { text: 'D' }], makeButton) }, { items: Arr.map([{ text: 'E' }, { text: 'F' }, { text: 'G' }], makeButton) } ]); SplitFloatingToolbar.setGroups(component, groups); SplitFloatingToolbar.toggle(component); }), store.sAssertEq('Assert store contains toggled state', [ 'onOpened' ]), sAssertSplitFloatingToolbarToggleState(true), sAssertGroups('width=400px (1 +)', [ group1, oGroup ], [ group2, group3 ]), sResetWidth('250px'), sAssertGroups('width=300px (1 +)', [ group1, oGroup ], [ group2, group3 ]), sResetWidth('249px'), sAssertGroups('width=300px (+) (not enough space for the group and the +)', [ oGroup ], [ group1, group2, group3 ]), sResetWidth('400px'), sAssertGroups('width=400px (1 +)', [ group1, oGroup ], [ group2, group3 ]), sResetWidth('450px'), sAssertGroups('width=450px (1 +)', [ group1, group2, oGroup ], [ group3 ]), sResetWidth('670px'), sAssertGroups('width=670px, (1 2 +)', [ group1, group2, oGroup ], [ group3 ]), sResetWidth('700px'), sAssertGroups('width=700px, (1 2 +)', [ group1, group2, group3 ], [ ]), sResetWidth('400px'), sAssertGroups('width=400px (1 +)', [ group1, oGroup ], [ group2, group3 ]), store.sClear, sToggleSplitFloatingToolbar(), store.sAssertEq('Assert store contains toggled state', [ 'onClosed' ]), sAssertSplitFloatingToolbarToggleState(false), sToggleSplitFloatingToolbar(), store.sAssertEq('Assert store contains toggled state', [ 'onClosed', 'onOpened' ]), sAssertSplitFloatingToolbarToggleState(true), GuiSetup.mRemoveStyles ]; }, success, failure); });