@kubex/zinc 1.1.185 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.browserslistrc +2 -0
- package/.github/workflows/js_build_and_deploy.yaml +54 -1
- package/.github/workflows/test.yaml +27 -0
- package/dist/chunks/zn.UWJLIXDT.js +1 -0
- package/dist/custom-elements.json +10319 -2666
- package/dist/vscode.html-custom-data.json +1012 -57
- package/dist/web-types.json +2097 -145
- package/dist/zn.d.ts +2294 -416
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +2310 -1637
- package/docs/_includes/default.njk +4 -1
- package/docs/assets/scripts/docs.js +22 -6
- package/docs/assets/styles/docs.css +9 -2
- package/docs/data/report-table-day-compare.json +380 -0
- package/docs/data/report-table.json +314 -0
- package/docs/pages/components/avatar-group.md +57 -0
- package/docs/pages/components/badge.md +67 -0
- package/docs/pages/components/button.md +41 -1
- package/docs/pages/components/chat-message.md +16 -0
- package/docs/pages/components/checkbox.md +1 -1
- package/docs/pages/components/chip.md +25 -13
- package/docs/pages/components/color-picker.md +37 -0
- package/docs/pages/components/copy-button.md +2 -2
- package/docs/pages/components/data-table-filter.md +33 -50
- package/docs/pages/components/data-table-search.md +4 -4
- package/docs/pages/components/data-table.md +27 -3
- package/docs/pages/components/date-range.md +116 -0
- package/docs/pages/components/dialog.md +29 -37
- package/docs/pages/components/diff-row.md +28 -0
- package/docs/pages/components/diff.md +46 -0
- package/docs/pages/components/editor.md +55 -0
- package/docs/pages/components/icon.md +46 -1
- package/docs/pages/components/input.md +30 -11
- package/docs/pages/components/item.md +35 -0
- package/docs/pages/components/key-value.md +25 -0
- package/docs/pages/components/menu.md +74 -7
- package/docs/pages/components/nav-item.md +15 -0
- package/docs/pages/components/nav-list.md +132 -0
- package/docs/pages/components/navbar.md +100 -1
- package/docs/pages/components/page.md +242 -74
- package/docs/pages/components/priority-list.md +43 -5
- package/docs/pages/components/query-builder.md +23 -0
- package/docs/pages/components/radio-group.md +33 -1
- package/docs/pages/components/radio.md +1 -1
- package/docs/pages/components/report-table.md +202 -0
- package/docs/pages/components/stat.md +30 -0
- package/docs/pages/components/tile.md +11 -0
- package/docs/pages/components/tooltip.md +1 -1
- package/docs/pages/components/translation-grid.md +86 -0
- package/docs/pages/components/vertical-stepper.md +108 -64
- package/package.json +2 -1
- package/scss/_global-spacing.scss +2 -2
- package/scss/_root.scss +11 -171
- package/scss/boot.scss +14 -0
- package/scss/mixins/_helper-mixins.scss +24 -2
- package/scss/mixins/_motion-mixins.scss +126 -0
- package/scss/mixins/_spacing-mixins.scss +4 -3
- package/scss/mixins/_tab-indicator-mixins.scss +12 -0
- package/scss/mixins/_typography-mixins.scss +1 -1
- package/scss/mixins/index.scss +14 -0
- package/scss/shared/_base.scss +32 -1
- package/scss/shared/_button-mixin.scss +7 -5
- package/scss/shared/_table.scss +35 -4
- package/scss/shared/nav.scss +4 -0
- package/scss/shared/shimmer.scss +1 -1
- package/scss/table-controls.scss +206 -0
- package/scss/themes/_dark.scss +1 -3
- package/scss/themes/_index.scss +1 -1
- package/scss/themes/_light.scss +46 -6
- package/scss/themes/_modes.scss +11 -11
- package/scss/themes/_openbyte.scss +944 -0
- package/scss/themes/_typography.scss +4 -2
- package/scss/variables/index.scss +0 -9
- package/src/components/alert/alert.component.ts +14 -4
- package/src/components/alert/alert.scss +55 -69
- package/src/components/alert/alert.test.ts +8 -0
- package/src/components/animated-button/animated-button.component.ts +3 -2
- package/src/components/animated-button/animated-button.scss +6 -23
- package/src/components/animated-button/animated-button.test.ts +4 -3
- package/src/components/avatar-group/avatar-group.component.ts +84 -0
- package/src/components/avatar-group/avatar-group.scss +54 -0
- package/src/components/avatar-group/avatar-group.test.ts +59 -0
- package/src/components/avatar-group/index.ts +12 -0
- package/src/components/badge/badge.component.ts +49 -0
- package/src/components/badge/badge.scss +80 -0
- package/src/components/badge/badge.test.ts +34 -0
- package/src/components/badge/index.ts +12 -0
- package/src/components/bulk-actions/bulk-actions.component.ts +14 -2
- package/src/components/button/button.component.ts +228 -8
- package/src/components/button/button.scss +115 -32
- package/src/components/button/button.test.ts +122 -0
- package/src/components/button-menu/button-menu.component.ts +32 -11
- package/src/components/button-menu/button-menu.scss +5 -1
- package/src/components/channel-tile/channel-tile.component.ts +34 -27
- package/src/components/channel-tile/channel-tile.scss +76 -43
- package/src/components/chart/builders.test.ts +46 -0
- package/src/components/chart/builders.ts +27 -3
- package/src/components/chart/chart-live.test.ts +4 -6
- package/src/components/chart/chart.component.ts +125 -5
- package/src/components/chart/chart.scss +121 -0
- package/src/components/chart/chart.test.ts +81 -0
- package/src/components/chat-message/chat-message.component.ts +21 -1
- package/src/components/chat-message/chat-message.scss +13 -2
- package/src/components/chat-message/chat-message.test.ts +9 -0
- package/src/components/checkbox/checkbox.component.ts +61 -27
- package/src/components/checkbox/checkbox.scss +58 -25
- package/src/components/checkbox-group/checkbox-group.component.ts +7 -1
- package/src/components/chip/chip.component.ts +11 -1
- package/src/components/chip/chip.scss +91 -26
- package/src/components/chip/chip.test.ts +17 -0
- package/src/components/collapsible/collapsible.component.ts +17 -3
- package/src/components/collapsible/collapsible.scss +19 -10
- package/src/components/color-picker/color-picker.component.ts +277 -0
- package/src/components/color-picker/color-picker.scss +141 -0
- package/src/components/color-picker/color-picker.test.ts +57 -0
- package/src/components/color-picker/index.ts +12 -0
- package/src/components/cols/cols.component.ts +10 -0
- package/src/components/cols/cols.test.ts +17 -0
- package/src/components/confirm/confirm.component.ts +20 -6
- package/src/components/confirm/confirm.test.ts +52 -0
- package/src/components/content-block/content-block.component.ts +38 -9
- package/src/components/content-block/content-block.scss +11 -5
- package/src/components/content-block/content-block.test.ts +26 -0
- package/src/components/copy-button/copy-button.component.ts +2 -2
- package/src/components/copy-button/copy-button.scss +17 -4
- package/src/components/data-select/data-select.component.ts +3 -1
- package/src/components/data-table/data-table.component.ts +362 -140
- package/src/components/data-table/data-table.scss +136 -60
- package/src/components/data-table/data-table.test.ts +356 -4
- package/src/components/data-table-filter/data-table-filter.component.ts +426 -406
- package/src/components/data-table-filter/data-table-filter.scss +176 -148
- package/src/components/data-table-filter/data-table-filter.test.ts +271 -273
- package/src/components/data-table-search/data-table-search.component.ts +4 -2
- package/src/components/data-table-search/data-table-search.scss +8 -1
- package/src/components/data-table-search/data-table-search.test.ts +29 -0
- package/src/components/date-range/date-range-math.test.ts +78 -0
- package/src/components/date-range/date-range-math.ts +105 -0
- package/src/components/date-range/date-range.component.ts +375 -0
- package/src/components/date-range/date-range.scss +272 -0
- package/src/components/date-range/date-range.test.ts +247 -0
- package/src/components/date-range/index.ts +12 -0
- package/src/components/datepicker/datepicker.component.ts +44 -7
- package/src/components/datepicker/datepicker.scss +9 -0
- package/src/components/datepicker/datepicker.test.ts +2 -2
- package/src/components/dialog/dialog.component.ts +38 -19
- package/src/components/dialog/dialog.scss +65 -36
- package/src/components/dialog/dialog.test.ts +14 -0
- package/src/components/diff/diff.component.ts +55 -0
- package/src/components/diff/diff.scss +46 -0
- package/src/components/diff/diff.test.ts +15 -0
- package/src/components/diff/index.ts +12 -0
- package/src/components/diff-row/diff-row.component.ts +75 -0
- package/src/components/diff-row/diff-row.scss +70 -0
- package/src/components/diff-row/diff-row.test.ts +37 -0
- package/src/components/diff-row/index.ts +12 -0
- package/src/components/dropdown/dropdown.component.ts +12 -10
- package/src/components/dropdown/dropdown.scss +2 -0
- package/src/components/editor/editor.component.ts +159 -11
- package/src/components/editor/editor.scss +250 -1
- package/src/components/editor/editor.test.ts +31 -3
- package/src/components/editor/modules/ai/panel/ai-panel.scss +0 -1
- package/src/components/editor/modules/attachment/attachment.ts +53 -31
- package/src/components/editor/modules/context-menu/context-menu.ts +17 -0
- package/src/components/editor/modules/dialog/dialog.component.ts +23 -1
- package/src/components/editor/modules/dialog/dialog.test.ts +28 -0
- package/src/components/editor/modules/emoji/emoji.ts +4 -5
- package/src/components/editor/modules/merge-field/merge-field.ts +83 -0
- package/src/components/editor/modules/toolbar/toolbar.component.ts +121 -68
- package/src/components/editor/modules/toolbar/toolbar.scss +38 -0
- package/src/components/editor/modules/toolbar/toolbar.ts +25 -1
- package/src/components/empty-state/empty-state.component.ts +6 -1
- package/src/components/empty-state/empty-state.scss +21 -4
- package/src/components/expanding-action/expanding-action.component.ts +22 -34
- package/src/components/expanding-action/expanding-action.scss +3 -45
- package/src/components/expanding-action/expanding-action.test.ts +2 -1
- package/src/components/file/file.component.ts +30 -2
- package/src/components/file/file.scss +6 -0
- package/src/components/flow-builder/flow-builder.component.ts +36 -3
- package/src/components/flow-builder/flow-builder.scss +0 -6
- package/src/components/flow-builder/modules/flow-canvas/flow-canvas.component.ts +8 -0
- package/src/components/flow-builder/modules/flow-canvas/flow-canvas.scss +10 -5
- package/src/components/flow-builder/modules/flow-node/flow-node.component.ts +17 -0
- package/src/components/flow-builder/modules/flow-node/flow-node.scss +10 -0
- package/src/components/form-actions/form-actions.component.ts +48 -2
- package/src/components/form-actions/form-actions.scss +1 -1
- package/src/components/form-group/form-group.component.ts +10 -3
- package/src/components/form-group/form-group.scss +37 -4
- package/src/components/form-group/form-group.test.ts +10 -0
- package/src/components/header/header.component.ts +11 -4
- package/src/components/header/header.scss +47 -5
- package/src/components/hover-container/hover-container.component.ts +4 -5
- package/src/components/icon/icon.component.ts +95 -9
- package/src/components/icon/icon.scss +70 -6
- package/src/components/icon/icon.test.ts +55 -0
- package/src/components/icon-picker/icon-picker.component.ts +35 -1
- package/src/components/inline-edit/inline-edit.component.ts +38 -8
- package/src/components/inline-edit/inline-edit.scss +128 -19
- package/src/components/input/input.component.ts +173 -297
- package/src/components/input/input.scss +65 -43
- package/src/components/input/input.test.ts +86 -4
- package/src/components/item/item.component.ts +12 -0
- package/src/components/item/item.scss +102 -3
- package/src/components/item/item.test.ts +23 -0
- package/src/components/key/key.component.ts +2 -2
- package/src/components/key/key.scss +11 -0
- package/src/components/key-value/index.ts +12 -0
- package/src/components/key-value/key-value.component.ts +160 -0
- package/src/components/key-value/key-value.scss +20 -0
- package/src/components/key-value/key-value.test.ts +22 -0
- package/src/components/markdown-editor/markdown-editor.component.ts +8 -1
- package/src/components/menu/menu.component.ts +21 -2
- package/src/components/menu/menu.scss +43 -23
- package/src/components/menu/menu.test.ts +33 -0
- package/src/components/menu-item/menu-item.component.ts +13 -2
- package/src/components/menu-item/menu-item.scss +56 -23
- package/src/components/menu-item/menu-item.test.ts +31 -0
- package/src/components/menu-item/submenu-controller.ts +25 -15
- package/src/components/menu-label/index.ts +12 -0
- package/src/components/menu-label/menu-label.component.ts +30 -0
- package/src/components/menu-label/menu-label.scss +18 -0
- package/src/components/nav-item/index.ts +12 -0
- package/src/components/nav-item/nav-item.component.ts +83 -0
- package/src/components/nav-item/nav-item.scss +128 -0
- package/src/components/nav-list/index.ts +12 -0
- package/src/components/nav-list/nav-list.component.ts +313 -0
- package/src/components/nav-list/nav-list.scss +87 -0
- package/src/components/nav-list/nav-list.test.ts +250 -0
- package/src/components/navbar/navbar.component.ts +235 -171
- package/src/components/navbar/navbar.scss +333 -169
- package/src/components/navbar/navbar.test.ts +63 -143
- package/src/components/page/page.component.ts +114 -29
- package/src/components/page/page.scss +223 -95
- package/src/components/page/page.test.ts +214 -3
- package/src/components/page-builder/page-builder.component.ts +51 -5
- package/src/components/page-builder/page-builder.scss +6 -1
- package/src/components/page-nav/page-nav.component.ts +25 -3
- package/src/components/page-nav/page-nav.scss +10 -2
- package/src/components/pagination/pagination.scss +1 -1
- package/src/components/panel/panel.component.ts +14 -13
- package/src/components/panel/panel.scss +14 -10
- package/src/components/panel/panel.test.ts +42 -0
- package/src/components/popup/popup.component.ts +20 -13
- package/src/components/popup/popup.test.ts +21 -1
- package/src/components/priority-list/priority-list.component.ts +157 -172
- package/src/components/priority-list/priority-list.scss +113 -17
- package/src/components/priority-list/priority-list.test.ts +301 -3
- package/src/components/progress-bar/progress-bar.component.ts +1 -1
- package/src/components/progress-bar/progress-bar.scss +16 -4
- package/src/components/progress-tile/progress-tile.scss +1 -1
- package/src/components/query-builder/query-builder.component.ts +85 -10
- package/src/components/query-builder/query-builder.scss +7 -1
- package/src/components/query-builder/query-builder.test.ts +40 -0
- package/src/components/radio/radio.component.ts +57 -18
- package/src/components/radio/radio.scss +101 -26
- package/src/components/radio-group/radio-group.component.ts +45 -7
- package/src/components/radio-group/radio-group.scss +17 -0
- package/src/components/radio-group/radio-group.test.ts +63 -2
- package/src/components/rating/rating.component.ts +23 -0
- package/src/components/rating/rating.scss +1 -1
- package/src/components/remarkd-editor/remarkd-editor.component.ts +60 -5
- package/src/components/remarkd-editor/remarkd-editor.scss +12 -4
- package/src/components/report-table/index.ts +12 -0
- package/src/components/report-table/report-format.test.ts +86 -0
- package/src/components/report-table/report-format.ts +72 -0
- package/src/components/report-table/report-math.test.ts +74 -0
- package/src/components/report-table/report-math.ts +252 -0
- package/src/components/report-table/report-table.component.ts +681 -0
- package/src/components/report-table/report-table.scss +328 -0
- package/src/components/report-table/report-table.test.ts +702 -0
- package/src/components/reveal/reveal.component.ts +15 -1
- package/src/components/reveal/reveal.scss +5 -0
- package/src/components/schedule-builder/schedule-builder.component.ts +23 -8
- package/src/components/scroll-container/scroll-container.component.ts +19 -1
- package/src/components/scroll-container/scroll-container.scss +6 -1
- package/src/components/select/select.component.ts +52 -36
- package/src/components/select/select.scss +42 -25
- package/src/components/select/select.test.ts +14 -2
- package/src/components/settings-container/settings-container.scss +18 -5
- package/src/components/sidebar/sidebar.component.ts +8 -1
- package/src/components/sidebar/sidebar.scss +6 -1
- package/src/components/skeleton/skeleton.component.ts +3 -3
- package/src/components/skeleton/skeleton.scss +6 -6
- package/src/components/skeleton/skeleton.test.ts +9 -0
- package/src/components/slash-menu/slash-menu.scss +1 -1
- package/src/components/slideout/slideout.component.ts +20 -3
- package/src/components/slideout/slideout.scss +13 -6
- package/src/components/slideout/slideout.test.ts +19 -0
- package/src/components/split-button/split-button.component.ts +1 -1
- package/src/components/split-pane/split-pane.component.ts +71 -8
- package/src/components/split-pane/split-pane.scss +145 -41
- package/src/components/split-pane/split-pane.test.ts +23 -3
- package/src/components/stat/stat.component.ts +209 -14
- package/src/components/stat/stat.scss +305 -5
- package/src/components/stat/stat.test.ts +143 -2
- package/src/components/status-indicator/status-indicator.scss +22 -21
- package/src/components/stepper/stepper.scss +3 -3
- package/src/components/tab/tab.component.ts +1 -0
- package/src/components/table/table.component.ts +12 -1
- package/src/components/table/table.scss +21 -13
- package/src/components/table/table.test.ts +17 -0
- package/src/components/tabs/tabs.component.ts +150 -37
- package/src/components/tabs/tabs.scss +48 -7
- package/src/components/tabs/tabs.test.ts +169 -0
- package/src/components/textarea/textarea.component.ts +25 -3
- package/src/components/textarea/textarea.scss +10 -0
- package/src/components/textarea/textarea.test.ts +8 -4
- package/src/components/theme-editor/theme-editor.scss +0 -6
- package/src/components/tile/tile.component.ts +32 -2
- package/src/components/tile/tile.scss +40 -7
- package/src/components/tile/tile.test.ts +10 -0
- package/src/components/toggle/toggle.component.ts +23 -7
- package/src/components/toggle/toggle.scss +36 -29
- package/src/components/toggle/toggle.test.ts +17 -0
- package/src/components/tooltip/tooltip.component.ts +3 -0
- package/src/components/tooltip/tooltip.scss +11 -6
- package/src/components/tooltip/tooltip.test.ts +12 -0
- package/src/components/translation-field/index.ts +12 -0
- package/src/components/translation-field/translation-field.component.ts +55 -0
- package/src/components/translation-field/translation-field.scss +101 -0
- package/src/components/translation-fields/index.ts +12 -0
- package/src/components/translation-fields/translation-fields.component.ts +80 -0
- package/src/components/translation-fields/translation-fields.scss +60 -0
- package/src/components/translation-grid/index.ts +12 -0
- package/src/components/translation-grid/translation-grid.component.ts +157 -0
- package/src/components/translation-grid/translation-grid.scss +138 -0
- package/src/components/translation-grid/translation-grid.test.ts +28 -0
- package/src/components/vertical-stepper/vertical-stepper.component.ts +35 -9
- package/src/components/vertical-stepper/vertical-stepper.scss +110 -39
- package/src/components/vertical-stepper/vertical-stepper.test.ts +35 -0
- package/src/components/well/well.scss +2 -2
- package/src/events/events.ts +2 -0
- package/src/events/zn-chart-click.ts +13 -0
- package/src/events/zn-report-change.ts +7 -0
- package/src/form-control.scss +36 -3
- package/src/internal/anchored-popover.ts +175 -0
- package/src/internal/animate.ts +19 -5
- package/src/internal/cosmic-border.ts +15 -0
- package/src/internal/form.ts +1 -1
- package/src/internal/hover-intent.ts +15 -0
- package/src/internal/input-modality.ts +15 -0
- package/src/internal/pointer-intent.ts +37 -0
- package/src/internal/reorder.ts +632 -0
- package/src/internal/scroll.ts +51 -3
- package/src/internal/selection-card.ts +1 -1
- package/src/internal/tab-indicator.ts +92 -0
- package/src/internal/table-sort.ts +25 -0
- package/src/internal/table-tabs.ts +108 -0
- package/src/internal/test-drag.ts +35 -0
- package/src/internal/theme-openbyte.test.ts +126 -0
- package/src/internal/theme.ts +4 -4
- package/src/internal/zinc-element.ts +2 -2
- package/src/selection-card.scss +25 -0
- package/src/types/web-test-runner-commands.d.ts +1 -0
- package/src/utilities/color.test.ts +43 -0
- package/src/utilities/color.ts +189 -0
- package/src/zinc.ts +14 -0
- package/.github/workflows/eleventy_build.yml +0 -42
- package/scss/themes/_aura.scss +0 -114
|
@@ -71,4 +71,46 @@ describe('<zn-panel>', () => {
|
|
|
71
71
|
|
|
72
72
|
expect(el.shadowRoot!.querySelector('.panel')!.classList.contains('panel--empty')).to.be.false;
|
|
73
73
|
});
|
|
74
|
+
|
|
75
|
+
it('shows a description under the caption in the header', async () => {
|
|
76
|
+
const el = await fixture<HTMLElement>(html`<zn-panel caption="Identity" description="Shown to assessors">Body</zn-panel>`);
|
|
77
|
+
await (el as unknown as {updateComplete: Promise<unknown>}).updateComplete;
|
|
78
|
+
const header = el.shadowRoot!.querySelector('zn-header')!;
|
|
79
|
+
await (header as unknown as {updateComplete: Promise<unknown>}).updateComplete;
|
|
80
|
+
|
|
81
|
+
expect(header.shadowRoot!.querySelector('.header__description')!.textContent).to.equal('Shown to assessors');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('renders no description element without one', async () => {
|
|
85
|
+
const el = await fixture<HTMLElement>(html`<zn-panel caption="Identity">Body</zn-panel>`);
|
|
86
|
+
await (el as unknown as {updateComplete: Promise<unknown>}).updateComplete;
|
|
87
|
+
const header = el.shadowRoot!.querySelector('zn-header')!;
|
|
88
|
+
await (header as unknown as {updateComplete: Promise<unknown>}).updateComplete;
|
|
89
|
+
|
|
90
|
+
expect(header.shadowRoot!.querySelector('.header__description')).to.not.exist;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('transparent', () => {
|
|
94
|
+
// Safari has no overflow-clip-margin, so the room comes from a padding/negative-margin fallback there
|
|
95
|
+
it('leaves room outside the content for the focus ring of a flush control', async () => {
|
|
96
|
+
const el = await fixture(html`
|
|
97
|
+
<zn-panel transparent flush style="--zn-focus-ring-outset: 4px"><input></zn-panel> `);
|
|
98
|
+
const content = el.shadowRoot!.querySelector('.panel__content')!.getBoundingClientRect();
|
|
99
|
+
const input = el.querySelector('input')!.getBoundingClientRect();
|
|
100
|
+
const clipMargin = CSS.supports('overflow-clip-margin: 0px') ? 4 : 0;
|
|
101
|
+
|
|
102
|
+
expect(input.left - (content.left - clipMargin)).to.equal(4);
|
|
103
|
+
expect(input.top - (content.top - clipMargin)).to.equal(4);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('keeps the bottom edge of the header clickable', async () => {
|
|
107
|
+
const el = await fixture(html`
|
|
108
|
+
<zn-panel transparent caption="Example" style="--zn-focus-ring-outset: 4px"><input></zn-panel> `);
|
|
109
|
+
const header = el.shadowRoot!.querySelector('.panel__header')!;
|
|
110
|
+
const rect = header.getBoundingClientRect();
|
|
111
|
+
const hit = el.shadowRoot!.elementFromPoint(rect.left + 10, rect.bottom - 2);
|
|
112
|
+
|
|
113
|
+
expect(header.contains(hit)).to.be.true;
|
|
114
|
+
});
|
|
115
|
+
});
|
|
74
116
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import '../../events/zn-reposition';
|
|
1
2
|
import {arrow, autoUpdate, computePosition, flip, offset, platform, shift, size} from '@floating-ui/dom';
|
|
2
3
|
import {classMap} from 'lit/directives/class-map.js';
|
|
3
4
|
import {html, unsafeCSS} from 'lit';
|
|
4
|
-
import {offsetParent} from 'composed-offset-position';
|
|
5
5
|
import {property, query} from 'lit/decorators.js';
|
|
6
6
|
import ZincElement from '../../internal/zinc-element';
|
|
7
7
|
import type {CSSResultGroup} from 'lit';
|
|
@@ -65,7 +65,7 @@ export default class ZnPopup extends ZincElement {
|
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* The preferred placement of the popup. Note that the actual placement will vary as configured to keep the
|
|
68
|
-
* panel inside
|
|
68
|
+
* panel inside the viewport.
|
|
69
69
|
*/
|
|
70
70
|
@property({reflect: true}) placement:
|
|
71
71
|
| 'top'
|
|
@@ -206,7 +206,7 @@ export default class ZnPopup extends ZincElement {
|
|
|
206
206
|
|
|
207
207
|
disconnectedCallback() {
|
|
208
208
|
super.disconnectedCallback();
|
|
209
|
-
this.stop();
|
|
209
|
+
this.stop().then();
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
async updated(changedProps: Map<string, unknown>) {
|
|
@@ -214,12 +214,16 @@ export default class ZnPopup extends ZincElement {
|
|
|
214
214
|
|
|
215
215
|
// Start or stop the positioner when active changes
|
|
216
216
|
if (changedProps.has('active')) {
|
|
217
|
-
this.active
|
|
217
|
+
if (this.active) {
|
|
218
|
+
this.start();
|
|
219
|
+
} else {
|
|
220
|
+
this.stop().then();
|
|
221
|
+
}
|
|
218
222
|
}
|
|
219
223
|
|
|
220
224
|
// Update the anchor when anchor changes
|
|
221
225
|
if (changedProps.has('anchor')) {
|
|
222
|
-
this.handleAnchorChange();
|
|
226
|
+
await this.handleAnchorChange();
|
|
223
227
|
}
|
|
224
228
|
|
|
225
229
|
// All other properties will trigger a reposition when active
|
|
@@ -255,6 +259,10 @@ export default class ZnPopup extends ZincElement {
|
|
|
255
259
|
this.anchorEl.removeEventListener('mouseover', this.handleAnchorHover);
|
|
256
260
|
this.anchorEl.addEventListener('mouseover', this.handleAnchorHover);
|
|
257
261
|
}
|
|
262
|
+
|
|
263
|
+
if (this.active) {
|
|
264
|
+
this.start();
|
|
265
|
+
}
|
|
258
266
|
}
|
|
259
267
|
|
|
260
268
|
public handleAnchorHover = () => {
|
|
@@ -282,6 +290,9 @@ export default class ZnPopup extends ZincElement {
|
|
|
282
290
|
this.removeAttribute('data-current-placement');
|
|
283
291
|
this.style.removeProperty('--auto-size-available-width');
|
|
284
292
|
this.style.removeProperty('--auto-size-available-height');
|
|
293
|
+
// WebKit: going display:none and leaving the top layer in one style update leaves the popup's old box as
|
|
294
|
+
// stale scroll overflow on its container (scrollbars flash on close), so flush style between the two.
|
|
295
|
+
void getComputedStyle(this.popup).display;
|
|
285
296
|
this.popup.hidePopover();
|
|
286
297
|
requestAnimationFrame(() => resolve());
|
|
287
298
|
} else {
|
|
@@ -306,7 +317,7 @@ export default class ZnPopup extends ZincElement {
|
|
|
306
317
|
if (this.sync) {
|
|
307
318
|
middleware.push(
|
|
308
319
|
size({
|
|
309
|
-
apply: ({rects}: { rects: { reference: { width: number
|
|
320
|
+
apply: ({rects}: { rects: { reference: { width: number; height: number } } }) => {
|
|
310
321
|
const syncWidth = this.sync === 'width' || this.sync === 'both';
|
|
311
322
|
const syncHeight = this.sync === 'height' || this.sync === 'both';
|
|
312
323
|
|
|
@@ -350,7 +361,7 @@ export default class ZnPopup extends ZincElement {
|
|
|
350
361
|
size({
|
|
351
362
|
boundary: this.autoSizeBoundary,
|
|
352
363
|
padding: this.autoSizePadding,
|
|
353
|
-
apply: ({availableWidth, availableHeight}: { availableWidth: number
|
|
364
|
+
apply: ({availableWidth, availableHeight}: { availableWidth: number; availableHeight: number }) => {
|
|
354
365
|
if (this.autoSize === 'vertical' || this.autoSize === 'both') {
|
|
355
366
|
this.style.setProperty('--auto-size-available-height', `${availableHeight}px`);
|
|
356
367
|
} else {
|
|
@@ -381,11 +392,6 @@ export default class ZnPopup extends ZincElement {
|
|
|
381
392
|
);
|
|
382
393
|
}
|
|
383
394
|
|
|
384
|
-
const getOffsetParent =
|
|
385
|
-
this.strategy === 'absolute'
|
|
386
|
-
? (element: Element) => platform.getOffsetParent(element, offsetParent)
|
|
387
|
-
: platform.getOffsetParent;
|
|
388
|
-
|
|
389
395
|
// A closed popover has no size to measure, so it would first land on top of its anchor
|
|
390
396
|
if (this.popup.isConnected && !this.popup.matches(':popover-open')) {
|
|
391
397
|
this.popup.style.visibility = 'hidden';
|
|
@@ -396,9 +402,10 @@ export default class ZnPopup extends ZincElement {
|
|
|
396
402
|
placement: this.placement,
|
|
397
403
|
middleware,
|
|
398
404
|
strategy: this.strategy,
|
|
405
|
+
// The popup is a popover in the top layer, so the page, not any ancestor, is what it is positioned within
|
|
399
406
|
platform: {
|
|
400
407
|
...platform,
|
|
401
|
-
getOffsetParent
|
|
408
|
+
getOffsetParent: () => window
|
|
402
409
|
}
|
|
403
410
|
}).then(({x, y, middlewareData, placement}:
|
|
404
411
|
{ x: number; y: number; middlewareData: MiddlewareData; placement: string }) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
|
-
import { expect, fixture, html } from '@open-wc/testing';
|
|
2
|
+
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
|
|
3
|
+
import type ZnPopup from './popup.component';
|
|
3
4
|
|
|
4
5
|
describe('<zn-popup>', () => {
|
|
5
6
|
it('should render a component', async () => {
|
|
@@ -7,4 +8,23 @@ describe('<zn-popup>', () => {
|
|
|
7
8
|
|
|
8
9
|
expect(el).to.exist;
|
|
9
10
|
});
|
|
11
|
+
|
|
12
|
+
it('keeps following a new anchor set while open', async () => {
|
|
13
|
+
const wrapper = await fixture(html`
|
|
14
|
+
<div>
|
|
15
|
+
<button id="first">First</button>
|
|
16
|
+
<button id="second">Second</button>
|
|
17
|
+
<zn-popup anchor="first" active><div>Content</div></zn-popup>
|
|
18
|
+
</div>`);
|
|
19
|
+
const popup = wrapper.querySelector<ZnPopup>('zn-popup')!;
|
|
20
|
+
await oneEvent(popup, 'zn-reposition');
|
|
21
|
+
|
|
22
|
+
popup.anchor = 'second';
|
|
23
|
+
await oneEvent(popup, 'zn-reposition');
|
|
24
|
+
|
|
25
|
+
// The positioner repositions on window resize; a stopped one never would
|
|
26
|
+
const repositioned = oneEvent(popup, 'zn-reposition');
|
|
27
|
+
window.dispatchEvent(new Event('resize'));
|
|
28
|
+
await repositioned;
|
|
29
|
+
});
|
|
10
30
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {classMap} from "lit/directives/class-map.js";
|
|
2
|
+
import {clipCornerRadius, ReorderController} from '../../internal/reorder';
|
|
2
3
|
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
4
|
import {
|
|
4
5
|
FormControlController,
|
|
@@ -8,6 +9,7 @@ import {HasSlotController} from '../../internal/slot';
|
|
|
8
9
|
import {property, query, state} from 'lit/decorators.js';
|
|
9
10
|
import {repeat} from "lit/directives/repeat.js";
|
|
10
11
|
import ZincElement from '../../internal/zinc-element';
|
|
12
|
+
import ZnButton from '../button';
|
|
11
13
|
import ZnIcon from '../icon';
|
|
12
14
|
import type {ZincFormControl} from '../../internal/zinc-element';
|
|
13
15
|
|
|
@@ -35,11 +37,14 @@ function safeParse(value: string): unknown {
|
|
|
35
37
|
* @status experimental
|
|
36
38
|
* @since 1.0
|
|
37
39
|
*
|
|
40
|
+
* @dependency zn-button
|
|
38
41
|
* @dependency zn-icon
|
|
39
42
|
*
|
|
40
43
|
* @slot - The default slot where list items are placed. Each slotted element must have a `value` attribute that
|
|
41
44
|
* uniquely identifies the item. The component automatically assigns slot names to project each item into the
|
|
42
45
|
* correct position. The item's position in the list determines its priority (top = `priority-start`, incrementing).
|
|
46
|
+
* Use `zn-tile` items for titled rows with their own actions. Set `locked` on an item to pin it where it is.
|
|
47
|
+
* @slot action-{value} - Controls shown at the end of the item with that `value`.
|
|
43
48
|
* @slot label - The component's label. Required for proper accessibility. Alternatively, use the `label` attribute.
|
|
44
49
|
* @slot label-tooltip - Used to add text displayed in a tooltip next to the label.
|
|
45
50
|
* @slot help-text - Text that describes how to use the component. Alternatively, use the `help-text` attribute.
|
|
@@ -66,6 +71,7 @@ function safeParse(value: string): unknown {
|
|
|
66
71
|
*/
|
|
67
72
|
export default class ZnPriorityList extends ZincElement implements ZincFormControl {
|
|
68
73
|
static dependencies = {
|
|
74
|
+
'zn-button': ZnButton,
|
|
69
75
|
'zn-icon': ZnIcon,
|
|
70
76
|
};
|
|
71
77
|
|
|
@@ -90,6 +96,13 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
90
96
|
|
|
91
97
|
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
|
|
92
98
|
|
|
99
|
+
private readonly reorderController: ReorderController = new ReorderController(this, {
|
|
100
|
+
formControl: this.formControlController,
|
|
101
|
+
fallbackFields: () => this.name ? this.getPriorityMap().map(({key, priority}) => [`${this.name}[${key}]`, String(priority)]) : [],
|
|
102
|
+
modifier: 'alt',
|
|
103
|
+
focus: key => this.reorderRow(key)?.focus(),
|
|
104
|
+
});
|
|
105
|
+
|
|
93
106
|
@query('.priority-list__hidden-inputs') hiddenInputsContainer: HTMLDivElement;
|
|
94
107
|
|
|
95
108
|
/**
|
|
@@ -118,6 +131,9 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
118
131
|
|
|
119
132
|
@state() defaultValue: string[] = [];
|
|
120
133
|
|
|
134
|
+
/** The item holding the list's single tab stop. */
|
|
135
|
+
@state() private _focusKey = '';
|
|
136
|
+
|
|
121
137
|
/** The component's label. Required for proper accessibility. */
|
|
122
138
|
@property() label = '';
|
|
123
139
|
|
|
@@ -144,6 +160,23 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
144
160
|
/** The starting priority number. Defaults to 1. */
|
|
145
161
|
@property({type: Number, attribute: 'priority-start'}) priorityStart = 1;
|
|
146
162
|
|
|
163
|
+
/** Draws the items as rows divided edge to edge, for a list filling a flush panel; the label is kept for
|
|
164
|
+
* screen readers only. */
|
|
165
|
+
@property({type: Boolean, reflect: true}) flush = false;
|
|
166
|
+
|
|
167
|
+
/** Lets a click or Enter select an item as well as drag it, for a list that doubles as navigation. The click is
|
|
168
|
+
* passed on to the item, so a `tab` or link on it acts as if clicked. */
|
|
169
|
+
@property({type: Boolean, reflect: true}) selectable = false;
|
|
170
|
+
|
|
171
|
+
/** The selected item's value. An item marked active by zn-tabs takes precedence, so the list follows its tabs. */
|
|
172
|
+
@property({reflect: true}) selected = '';
|
|
173
|
+
|
|
174
|
+
/** Hides each item's priority number, for lists where the order shows the priority. */
|
|
175
|
+
@property({type: Boolean, attribute: 'hide-priority', reflect: true}) hidePriority = false;
|
|
176
|
+
|
|
177
|
+
/** Shows move up and move down buttons on each item. */
|
|
178
|
+
@property({type: Boolean, attribute: 'move-buttons', reflect: true}) moveButtons = false;
|
|
179
|
+
|
|
147
180
|
/**
|
|
148
181
|
* When set, the associated form will be submitted with the given action URL whenever items are reordered.
|
|
149
182
|
* If set to an empty string, the form will be submitted using its existing action.
|
|
@@ -157,11 +190,6 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
157
190
|
*/
|
|
158
191
|
@property() order = '';
|
|
159
192
|
|
|
160
|
-
// Drag state
|
|
161
|
-
@state() private draggedKey: string | null = null;
|
|
162
|
-
@state() private isDragging = false;
|
|
163
|
-
private dragOverKey: string | null = null;
|
|
164
|
-
|
|
165
193
|
/** Gets the validity state object. */
|
|
166
194
|
get validity(): ValidityState {
|
|
167
195
|
return validValidityState;
|
|
@@ -172,9 +200,21 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
172
200
|
return '';
|
|
173
201
|
}
|
|
174
202
|
|
|
203
|
+
private _itemObserver = new MutationObserver(() => this.requestUpdate());
|
|
204
|
+
|
|
175
205
|
connectedCallback() {
|
|
176
206
|
super.connectedCallback();
|
|
177
207
|
this.defaultValue = [...this._value];
|
|
208
|
+
this._itemObserver.observe(this, {
|
|
209
|
+
childList: true,
|
|
210
|
+
subtree: true,
|
|
211
|
+
attributeFilter: ['locked', 'class'],
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
disconnectedCallback() {
|
|
216
|
+
super.disconnectedCallback();
|
|
217
|
+
this._itemObserver.disconnect();
|
|
178
218
|
}
|
|
179
219
|
|
|
180
220
|
protected firstUpdated(_changedProperties: PropertyValues) {
|
|
@@ -267,188 +307,108 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
267
307
|
});
|
|
268
308
|
}
|
|
269
309
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
private _moveItem(fromIndex: number, toIndex: number) {
|
|
274
|
-
if (fromIndex === toIndex) return;
|
|
275
|
-
if (fromIndex < 0 || toIndex < 0) return;
|
|
276
|
-
if (fromIndex >= this._value.length || toIndex >= this._value.length) return;
|
|
310
|
+
private _item(key: string) {
|
|
311
|
+
return this.querySelector<HTMLElement>(`:scope > [value="${CSS.escape(key)}"]`);
|
|
312
|
+
}
|
|
277
313
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
314
|
+
/** @internal ReorderHost: the items' keys in order. */
|
|
315
|
+
reorderKeys() {
|
|
316
|
+
return [...this._value];
|
|
317
|
+
}
|
|
281
318
|
|
|
282
|
-
|
|
319
|
+
/** @internal ReorderHost: renders the items in a new order. */
|
|
320
|
+
applyReorder(keys: string[]) {
|
|
321
|
+
this._value = keys;
|
|
283
322
|
this._assignSlotNames();
|
|
284
323
|
this._syncHiddenInputs();
|
|
285
324
|
this.requestUpdate();
|
|
286
|
-
|
|
287
|
-
this.emit('zn-change');
|
|
288
|
-
this.emit('zn-reorder');
|
|
289
|
-
this._submitForm();
|
|
290
325
|
}
|
|
291
326
|
|
|
292
|
-
/**
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
if (this.formAction === undefined || this.formAction === null) return;
|
|
297
|
-
|
|
298
|
-
const form = this.getForm();
|
|
299
|
-
if (form) {
|
|
300
|
-
// Submitting through the controller announces the form before it is
|
|
301
|
-
// submitted, which is what lets a host intercept the submit: a submit
|
|
302
|
-
// event raised on a form inside a shadow root never reaches the document,
|
|
303
|
-
// so submitting it directly navigates the page instead.
|
|
304
|
-
const submitter = document.createElement('input');
|
|
305
|
-
submitter.type = 'submit';
|
|
306
|
-
if (this.formAction) {
|
|
307
|
-
submitter.setAttribute('formaction', this.formAction);
|
|
308
|
-
}
|
|
309
|
-
this.formControlController.submit(submitter);
|
|
310
|
-
} else if (this.formAction) {
|
|
311
|
-
// No parent form — create a temporary one to submit the priority data
|
|
312
|
-
const tempForm = document.createElement('form');
|
|
313
|
-
tempForm.method = 'post';
|
|
314
|
-
tempForm.action = this.formAction;
|
|
315
|
-
tempForm.hidden = true;
|
|
316
|
-
|
|
317
|
-
this._value.forEach((key, index) => {
|
|
318
|
-
if (this.name) {
|
|
319
|
-
const input = document.createElement('input');
|
|
320
|
-
input.type = 'hidden';
|
|
321
|
-
input.name = `${this.name}[${key}]`;
|
|
322
|
-
input.value = String(this.priorityStart + index);
|
|
323
|
-
tempForm.appendChild(input);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
document.body.appendChild(tempForm);
|
|
328
|
-
// requestSubmit raises a cancellable submit event, so a host can handle
|
|
329
|
-
// the submission rather than the browser navigating to formaction.
|
|
330
|
-
tempForm.requestSubmit();
|
|
331
|
-
tempForm.remove();
|
|
332
|
-
}
|
|
327
|
+
/** @internal ReorderHost: the row drawn for an item. */
|
|
328
|
+
reorderRow(key: string) {
|
|
329
|
+
const index = this._value.indexOf(key);
|
|
330
|
+
return this.shadowRoot?.querySelectorAll<HTMLElement>('.priority-list__item')[index] ?? null;
|
|
333
331
|
}
|
|
334
332
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
if (this.disabled) {
|
|
339
|
-
event.preventDefault();
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
this.draggedKey = key;
|
|
344
|
-
this.isDragging = true;
|
|
345
|
-
|
|
346
|
-
if (event.dataTransfer) {
|
|
347
|
-
event.dataTransfer.effectAllowed = 'move';
|
|
348
|
-
event.dataTransfer.setData('text/plain', key);
|
|
349
|
-
}
|
|
333
|
+
/** @internal ReorderHost: whether an item is pinned where it is. */
|
|
334
|
+
reorderLocked(key: string) {
|
|
335
|
+
return this._item(key)?.hasAttribute('locked') ?? false;
|
|
350
336
|
}
|
|
351
337
|
|
|
352
|
-
private
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
338
|
+
private async _handleStep(event: Event, key: string, step: number) {
|
|
339
|
+
event.stopPropagation();
|
|
340
|
+
const button = event.currentTarget as ZnButton;
|
|
341
|
+
const hadFocus = button.matches(':focus-within');
|
|
342
|
+
if (!this.reorderController.step(key, step) || !hadFocus) return;
|
|
343
|
+
|
|
344
|
+
// Moving the row can detach it, which drops focus even when the button stays enabled
|
|
345
|
+
await this.updateComplete;
|
|
346
|
+
const target = [button, ...button.parentElement!.querySelectorAll<ZnButton>('zn-button')].find(b => !b.disabled);
|
|
347
|
+
if (target) {
|
|
348
|
+
target.button.focus();
|
|
349
|
+
} else {
|
|
350
|
+
this.reorderRow(key)?.focus();
|
|
359
351
|
}
|
|
360
|
-
|
|
361
|
-
this.draggedKey = null;
|
|
362
|
-
this.dragOverKey = null;
|
|
363
|
-
this.isDragging = false;
|
|
364
352
|
}
|
|
365
353
|
|
|
366
|
-
|
|
367
|
-
event.preventDefault();
|
|
368
|
-
|
|
369
|
-
if (!this.draggedKey || this.draggedKey === key) return;
|
|
370
|
-
|
|
371
|
-
if (event.dataTransfer) {
|
|
372
|
-
event.dataTransfer.dropEffect = 'move';
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Move the item in real-time so other items shift around
|
|
376
|
-
const fromIndex = this._value.indexOf(this.draggedKey);
|
|
377
|
-
const toIndex = this._value.indexOf(key);
|
|
378
|
-
|
|
379
|
-
if (fromIndex === -1 || toIndex === -1 || fromIndex === toIndex) return;
|
|
380
|
-
|
|
381
|
-
const newOrder = [...this._value];
|
|
382
|
-
const [moved] = newOrder.splice(fromIndex, 1);
|
|
383
|
-
newOrder.splice(toIndex, 0, moved);
|
|
384
|
-
this._value = newOrder;
|
|
385
|
-
this._assignSlotNames();
|
|
386
|
-
this.requestUpdate();
|
|
354
|
+
// --- Keyboard Handlers ---
|
|
387
355
|
|
|
388
|
-
|
|
356
|
+
private _selectedKey(): string {
|
|
357
|
+
if (!this.selectable) return '';
|
|
358
|
+
const active = this._getSlottedItems().find(el => el.classList.contains('zn-tb-active'));
|
|
359
|
+
return active?.getAttribute('value') || this.selected;
|
|
389
360
|
}
|
|
390
361
|
|
|
391
|
-
private
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
362
|
+
private _select(key: string) {
|
|
363
|
+
if (!this.selectable) return;
|
|
364
|
+
this.selected = key;
|
|
365
|
+
const item = this._item(key);
|
|
366
|
+
if (!item) return;
|
|
367
|
+
item.click();
|
|
368
|
+
this.emit('zn-select', {detail: {item}});
|
|
369
|
+
}
|
|
395
370
|
|
|
396
|
-
|
|
397
|
-
|
|
371
|
+
private _matchClipCorners(row: HTMLElement) {
|
|
372
|
+
const radius = clipCornerRadius(this, row);
|
|
373
|
+
if (radius) {
|
|
374
|
+
row.style.setProperty('--zn-priority-list-drag-radius', radius);
|
|
375
|
+
} else {
|
|
376
|
+
row.style.removeProperty('--zn-priority-list-drag-radius');
|
|
398
377
|
}
|
|
399
378
|
}
|
|
400
379
|
|
|
401
|
-
private
|
|
402
|
-
event.
|
|
403
|
-
//
|
|
404
|
-
|
|
380
|
+
private _handleItemClick(event: MouseEvent, key: string) {
|
|
381
|
+
const path = event.composedPath();
|
|
382
|
+
// An action is its own control, and the click _select passes on to the item bubbles back through the row.
|
|
383
|
+
if (path.some(el => el instanceof HTMLElement && el.classList.contains('priority-list__actions'))
|
|
384
|
+
|| path.includes(this._item(key)!)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
this._select(key);
|
|
405
388
|
}
|
|
406
389
|
|
|
407
|
-
// --- Keyboard Handlers ---
|
|
408
|
-
|
|
409
390
|
private _handleKeyDown(event: KeyboardEvent, key: string) {
|
|
410
391
|
if (this.disabled) return;
|
|
411
392
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
switch (event.key) {
|
|
418
|
-
case 'ArrowUp':
|
|
419
|
-
if (index > 0) {
|
|
420
|
-
newIndex = index - 1;
|
|
421
|
-
}
|
|
422
|
-
break;
|
|
423
|
-
case 'ArrowDown':
|
|
424
|
-
if (index < this._value.length - 1) {
|
|
425
|
-
newIndex = index + 1;
|
|
426
|
-
}
|
|
427
|
-
break;
|
|
428
|
-
case 'Home':
|
|
429
|
-
if (index > 0) {
|
|
430
|
-
newIndex = 0;
|
|
431
|
-
}
|
|
432
|
-
break;
|
|
433
|
-
case 'End':
|
|
434
|
-
if (index < this._value.length - 1) {
|
|
435
|
-
newIndex = this._value.length - 1;
|
|
436
|
-
}
|
|
437
|
-
break;
|
|
438
|
-
default:
|
|
439
|
-
return;
|
|
393
|
+
if (this.selectable && (event.key === 'Enter' || event.key === ' ') && event.target === event.currentTarget) {
|
|
394
|
+
event.preventDefault();
|
|
395
|
+
this._select(key);
|
|
396
|
+
return;
|
|
440
397
|
}
|
|
441
398
|
|
|
442
|
-
if (
|
|
443
|
-
event.preventDefault();
|
|
444
|
-
this._moveItem(index, newIndex);
|
|
399
|
+
if (this.reorderController.handleKeyDown(event, key) || event.target !== event.currentTarget) return;
|
|
445
400
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
401
|
+
const index = this._value.indexOf(key);
|
|
402
|
+
const next = {
|
|
403
|
+
ArrowUp: index - 1,
|
|
404
|
+
ArrowDown: index + 1,
|
|
405
|
+
Home: 0,
|
|
406
|
+
End: this._value.length - 1,
|
|
407
|
+
}[event.key];
|
|
408
|
+
if (next === undefined) return;
|
|
409
|
+
|
|
410
|
+
event.preventDefault();
|
|
411
|
+
this.reorderRow(this._value[Math.max(0, Math.min(next, this._value.length - 1))])?.focus();
|
|
452
412
|
}
|
|
453
413
|
|
|
454
414
|
// --- Slot Change Handler ---
|
|
@@ -514,9 +474,18 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
514
474
|
if (changedProperties.has('value') || changedProperties.has('name') || changedProperties.has('priorityStart')) {
|
|
515
475
|
this._syncHiddenInputs();
|
|
516
476
|
}
|
|
477
|
+
|
|
478
|
+
// Re-measured on every render, as the placeholder moves into and out of the panel's corners during a drag.
|
|
479
|
+
// Runs before the reorder slide starts, so the row is measured in its final place.
|
|
480
|
+
const placeholder = this.shadowRoot?.querySelector<HTMLElement>('.priority-list__item--dragging');
|
|
481
|
+
if (placeholder) {
|
|
482
|
+
this._matchClipCorners(placeholder);
|
|
483
|
+
}
|
|
517
484
|
}
|
|
518
485
|
|
|
519
486
|
render() {
|
|
487
|
+
const selectedKey = this._selectedKey();
|
|
488
|
+
const tabStop = [this._focusKey, selectedKey].find(key => key && this._value.includes(key)) ?? this._value[0];
|
|
520
489
|
const hasLabelSlot = this.hasSlotController.test('label');
|
|
521
490
|
const hasLabelTooltipSlot = this.hasSlotController.test('label-tooltip');
|
|
522
491
|
const hasHelpTextSlot = this.hasSlotController.test('help-text');
|
|
@@ -562,42 +531,58 @@ export default class ZnPriorityList extends ZincElement implements ZincFormContr
|
|
|
562
531
|
class=${classMap({
|
|
563
532
|
'priority-list': true,
|
|
564
533
|
'priority-list--disabled': this.disabled,
|
|
565
|
-
'priority-list--drag-active': this.isDragging,
|
|
534
|
+
'priority-list--drag-active': this.reorderController.isDragging,
|
|
566
535
|
})}
|
|
567
536
|
role="listbox"
|
|
568
537
|
aria-label=${this.label || 'Reorderable list'}
|
|
569
538
|
aria-orientation="vertical">
|
|
570
|
-
${repeat(this._value, (key) => key, (key, index) =>
|
|
539
|
+
${repeat(this._value, (key) => key, (key, index) => {
|
|
540
|
+
const item = this._item(key);
|
|
541
|
+
const locked = item?.hasAttribute('locked') ?? false;
|
|
542
|
+
const caption = item?.getAttribute('caption') || key;
|
|
543
|
+
return html`
|
|
571
544
|
<div
|
|
572
545
|
part="item"
|
|
573
546
|
class=${classMap({
|
|
574
547
|
'priority-list__item': true,
|
|
575
|
-
'priority-list__item--dragging': this.draggedKey === key,
|
|
548
|
+
'priority-list__item--dragging': this.reorderController.draggedKey === key,
|
|
576
549
|
'priority-list__item--disabled': this.disabled,
|
|
550
|
+
'priority-list__item--locked': locked,
|
|
551
|
+
'priority-list__item--selectable': this.selectable,
|
|
552
|
+
'priority-list__item--selected': key === selectedKey,
|
|
577
553
|
})}
|
|
578
554
|
role="option"
|
|
579
|
-
tabindex=${this.disabled ? '
|
|
580
|
-
aria-selected
|
|
581
|
-
aria-label="${
|
|
582
|
-
|
|
583
|
-
@
|
|
584
|
-
@
|
|
585
|
-
@dragover=${(e: DragEvent) => this._handleDragOver(e, key)}
|
|
586
|
-
@dragleave=${(e: DragEvent) => this._handleDragLeave(e, key)}
|
|
587
|
-
@drop=${(e: DragEvent) => this._handleDrop(e)}
|
|
555
|
+
tabindex=${!this.disabled && key === tabStop ? '0' : '-1'}
|
|
556
|
+
aria-selected=${key === selectedKey ? 'true' : 'false'}
|
|
557
|
+
aria-label="${caption} - priority ${this.priorityStart + index}"
|
|
558
|
+
@pointerdown=${(e: PointerEvent) => this.reorderController.handlePointerDown(e, key)}
|
|
559
|
+
@focus=${() => { this._focusKey = key; }}
|
|
560
|
+
@click=${(e: MouseEvent) => this._handleItemClick(e, key)}
|
|
588
561
|
@keydown=${(e: KeyboardEvent) => this._handleKeyDown(e, key)}>
|
|
589
562
|
<span class="priority-list__handle" part="drag-handle">
|
|
590
|
-
<zn-icon src="drag_indicator" size="16"></zn-icon>
|
|
563
|
+
<zn-icon src="${locked ? 'lock@lu' : 'drag_indicator'}" size="16"></zn-icon>
|
|
591
564
|
</span>
|
|
592
565
|
<span class="priority-list__priority" part="priority">${this.priorityStart + index}</span>
|
|
593
566
|
<span class="priority-list__content" part="content">
|
|
594
567
|
<slot name="_item-${key}"></slot>
|
|
595
568
|
</span>
|
|
596
569
|
<span class="priority-list__actions" part="actions">
|
|
570
|
+
${this.moveButtons && !locked ? html`
|
|
571
|
+
<span class="priority-list__move">
|
|
572
|
+
<zn-button icon="chevron-up@lu" icon-size="18" icon-button="small" plain label="Move up"
|
|
573
|
+
tooltip="Move up"
|
|
574
|
+
?disabled=${this.disabled || !this.reorderController.canStep(key, -1)}
|
|
575
|
+
@click=${(e: Event) => this._handleStep(e, key, -1)}></zn-button>
|
|
576
|
+
<zn-button icon="chevron-down@lu" icon-size="18" icon-button="small" plain label="Move down"
|
|
577
|
+
tooltip="Move down"
|
|
578
|
+
?disabled=${this.disabled || !this.reorderController.canStep(key, 1)}
|
|
579
|
+
@click=${(e: Event) => this._handleStep(e, key, 1)}></zn-button>
|
|
580
|
+
</span>` : null}
|
|
597
581
|
<slot name="action-${key}"></slot>
|
|
598
582
|
</span>
|
|
599
583
|
</div>
|
|
600
|
-
|
|
584
|
+
`;
|
|
585
|
+
})}
|
|
601
586
|
</div>
|
|
602
587
|
|
|
603
588
|
<!-- Hidden default slot to capture light DOM children for initial detection -->
|