@kubex/zinc 1.1.185 → 2.0.0
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 +9998 -2345
- package/dist/vscode.html-custom-data.json +1022 -67
- package/dist/web-types.json +2129 -177
- package/dist/zn.d.ts +2293 -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 +133 -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 +625 -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
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {classMap} from 'lit/directives/class-map.js';
|
|
2
|
+
import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
|
|
3
|
+
import {FormControlController} from '../../internal/form';
|
|
4
|
+
import {HasSlotController} from '../../internal/slot';
|
|
5
|
+
import {property, state} from 'lit/decorators.js';
|
|
6
|
+
import ZincElement, {type ZincFormControl} from '../../internal/zinc-element';
|
|
7
|
+
|
|
8
|
+
import formControlStyles from '../../form-control.scss';
|
|
9
|
+
import styles from './key-value.scss';
|
|
10
|
+
|
|
11
|
+
interface KeyValueRow {
|
|
12
|
+
key: string;
|
|
13
|
+
value: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @summary Edits a list of name and value pairs, submitted as a JSON object.
|
|
18
|
+
* @documentation https://zinc.style/components/key-value
|
|
19
|
+
* @status experimental
|
|
20
|
+
* @since 1.0
|
|
21
|
+
*
|
|
22
|
+
* @dependency zn-input
|
|
23
|
+
* @dependency zn-button
|
|
24
|
+
*
|
|
25
|
+
* @event zn-change - Emitted when a pair is added, removed or edited.
|
|
26
|
+
*
|
|
27
|
+
* @slot label - The label. Alternatively, use the `label` attribute.
|
|
28
|
+
* @slot help-text - Text under the pairs. Alternatively, use the `help-text` attribute.
|
|
29
|
+
*
|
|
30
|
+
* @csspart base - The component's base wrapper.
|
|
31
|
+
* @csspart row - Each name and value pair.
|
|
32
|
+
*/
|
|
33
|
+
export default class ZnKeyValue extends ZincElement implements ZincFormControl {
|
|
34
|
+
static styles: CSSResultGroup = [unsafeCSS(formControlStyles), unsafeCSS(styles)];
|
|
35
|
+
|
|
36
|
+
private readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
|
|
37
|
+
|
|
38
|
+
private readonly formControlController = new FormControlController(this, {
|
|
39
|
+
value: (control: ZnKeyValue) => control.value,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
@property() name = '';
|
|
43
|
+
|
|
44
|
+
/** The pairs as a JSON object, such as `{"1": "{{recipient.firstName}}"}`. */
|
|
45
|
+
@property() value = '{}';
|
|
46
|
+
|
|
47
|
+
@property() label = '';
|
|
48
|
+
|
|
49
|
+
@property({attribute: 'help-text'}) helpText = '';
|
|
50
|
+
|
|
51
|
+
@property({attribute: 'key-label'}) keyLabel = 'Name';
|
|
52
|
+
|
|
53
|
+
@property({attribute: 'value-label'}) valueLabel = 'Value';
|
|
54
|
+
|
|
55
|
+
@property({attribute: 'add-text'}) addText = 'Add';
|
|
56
|
+
|
|
57
|
+
/** Passed to each value input, so its slash menu can insert merge fields. */
|
|
58
|
+
@property({attribute: 'slash-items'}) slashItems = '';
|
|
59
|
+
|
|
60
|
+
@property({reflect: true}) form = '';
|
|
61
|
+
|
|
62
|
+
@property({type: Boolean, reflect: true}) disabled = false;
|
|
63
|
+
|
|
64
|
+
@state() private _rows: KeyValueRow[] = [];
|
|
65
|
+
|
|
66
|
+
get validity(): ValidityState {
|
|
67
|
+
return {valid: true} as ValidityState;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get validationMessage(): string {
|
|
71
|
+
return '';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
checkValidity(): boolean {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getForm(): HTMLFormElement | null {
|
|
79
|
+
return this.formControlController.getForm();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
reportValidity(): boolean {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setCustomValidity(): void {
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
protected willUpdate(changed: PropertyValues) {
|
|
90
|
+
if (changed.has('value') && this.value !== this._serialise()) {
|
|
91
|
+
this._rows = this._parse(this.value);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private _parse(value: string): KeyValueRow[] {
|
|
96
|
+
try {
|
|
97
|
+
const parsed: unknown = JSON.parse(value || '{}');
|
|
98
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
99
|
+
return Object.entries(parsed as Record<string, unknown>).map(([key, v]) => ({key, value: String(v ?? '')}));
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// An unreadable value starts empty rather than breaking the form
|
|
103
|
+
}
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private _serialise(): string {
|
|
108
|
+
const pairs: Record<string, string> = {};
|
|
109
|
+
this._rows.filter(row => row.key.trim()).forEach(row => pairs[row.key.trim()] = row.value);
|
|
110
|
+
return JSON.stringify(pairs);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
private _update(rows: KeyValueRow[]) {
|
|
114
|
+
this._rows = rows;
|
|
115
|
+
this.value = this._serialise();
|
|
116
|
+
this.emit('zn-change');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private _edit(index: number, field: keyof KeyValueRow, e: Event) {
|
|
120
|
+
const rows = [...this._rows];
|
|
121
|
+
rows[index] = {...rows[index], [field]: (e.target as HTMLInputElement).value};
|
|
122
|
+
this._update(rows);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
render() {
|
|
126
|
+
const hasLabel = this.label || this.hasSlotController.test('label');
|
|
127
|
+
const hasHelpText = this.helpText || this.hasSlotController.test('help-text');
|
|
128
|
+
|
|
129
|
+
return html`
|
|
130
|
+
<div part="base" class=${classMap({
|
|
131
|
+
'form-control': true,
|
|
132
|
+
'form-control--medium': true,
|
|
133
|
+
'form-control--has-label': !!hasLabel,
|
|
134
|
+
'form-control--has-help-text': !!hasHelpText,
|
|
135
|
+
})}>
|
|
136
|
+
<label class="form-control__label" aria-hidden=${hasLabel ? 'false' : 'true'}>
|
|
137
|
+
<slot name="label">${this.label}</slot>
|
|
138
|
+
</label>
|
|
139
|
+
|
|
140
|
+
<div class="key-value__rows">
|
|
141
|
+
${this._rows.map((row, index) => html`
|
|
142
|
+
<div part="row" class="key-value__row">
|
|
143
|
+
<zn-input class="key-value__key" placeholder=${this.keyLabel} .value=${row.key}
|
|
144
|
+
?disabled=${this.disabled} @zn-input=${(e: Event) => this._edit(index, 'key', e)}></zn-input>
|
|
145
|
+
<zn-input class="key-value__value" placeholder=${this.valueLabel} .value=${row.value}
|
|
146
|
+
slash-items=${this.slashItems} ?disabled=${this.disabled}
|
|
147
|
+
@zn-input=${(e: Event) => this._edit(index, 'value', e)}></zn-input>
|
|
148
|
+
<zn-button icon="x@lu" color="transparent" size="small" title="Remove" icon-button="small" plain ?disabled=${this.disabled}
|
|
149
|
+
@click=${() => this._update(this._rows.filter((_, i) => i !== index))}></zn-button>
|
|
150
|
+
</div>`)}
|
|
151
|
+
<zn-button class="key-value__add" icon="plus@lu" color="secondary" size="small" ?disabled=${this.disabled}
|
|
152
|
+
@click=${() => this._update([...this._rows, {key: '', value: ''}])}>${this.addText}</zn-button>
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div class="form-control__help-text" aria-hidden=${hasHelpText ? 'false' : 'true'}>
|
|
156
|
+
<slot name="help-text">${this.helpText}</slot>
|
|
157
|
+
</div>
|
|
158
|
+
</div>`;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
@use "../../wc";
|
|
2
|
+
|
|
3
|
+
:host {
|
|
4
|
+
display: block;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.key-value__rows {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
align-items: flex-start;
|
|
11
|
+
gap: var(--zn-spacing-x-small);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.key-value__row {
|
|
15
|
+
display: grid;
|
|
16
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) auto;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: var(--zn-spacing-x-small);
|
|
19
|
+
width: 100%;
|
|
20
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import '../../../dist/zn.min.js';
|
|
2
|
+
import {expect, fixture, html} from '@open-wc/testing';
|
|
3
|
+
import type ZnKeyValue from './key-value.component';
|
|
4
|
+
|
|
5
|
+
describe('<zn-key-value>', () => {
|
|
6
|
+
it('should show a row per pair in its value', async () => {
|
|
7
|
+
const el = await fixture<ZnKeyValue>(html`<zn-key-value value='{"1":"{{recipient.firstName}}","2":"x"}'></zn-key-value>`);
|
|
8
|
+
|
|
9
|
+
expect(el.shadowRoot!.querySelectorAll('.key-value__row').length).to.equal(2);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should submit the pairs as a JSON object, leaving out unnamed rows', async () => {
|
|
13
|
+
const form = await fixture<HTMLFormElement>(html`
|
|
14
|
+
<form><zn-key-value name="pairs" value='{"1":"a"}'></zn-key-value></form>`);
|
|
15
|
+
const el = form.querySelector<ZnKeyValue>('zn-key-value')!;
|
|
16
|
+
|
|
17
|
+
el.shadowRoot!.querySelector<HTMLElement>('.key-value__add')!.click();
|
|
18
|
+
await el.updateComplete;
|
|
19
|
+
|
|
20
|
+
expect(new FormData(form).get('pairs')).to.equal('{"1":"a"}');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -214,6 +214,13 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
|
|
|
214
214
|
this.viewMode = mode;
|
|
215
215
|
};
|
|
216
216
|
|
|
217
|
+
private handleKeyDown = (e: KeyboardEvent) => {
|
|
218
|
+
if (e.key === 'Escape' && this.expanded) {
|
|
219
|
+
e.stopPropagation();
|
|
220
|
+
this.expanded = false;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
|
|
217
224
|
private handleExpandToggle = () => {
|
|
218
225
|
this.expanded = !this.expanded;
|
|
219
226
|
};
|
|
@@ -290,7 +297,7 @@ export default class ZnMarkdownEditor extends ZnPanel implements ZincFormControl
|
|
|
290
297
|
'markdown-editor--split': this.viewMode === 'split',
|
|
291
298
|
'markdown-editor--preview-only': this.viewMode === 'preview',
|
|
292
299
|
'markdown-editor--expanded': this.expanded,
|
|
293
|
-
})}>
|
|
300
|
+
})} @keydown=${this.handleKeyDown}>
|
|
294
301
|
${hasLabel ? html`
|
|
295
302
|
<label class="markdown-editor__label">
|
|
296
303
|
<slot name="label">${this.label}</slot>
|
|
@@ -6,6 +6,7 @@ import ZnConfirm from "../confirm";
|
|
|
6
6
|
import ZnDropdown from "../dropdown";
|
|
7
7
|
import ZnIcon from "../icon";
|
|
8
8
|
import ZnMenuItem from "../menu-item";
|
|
9
|
+
import ZnMenuLabel from "../menu-label";
|
|
9
10
|
import ZnTooltip from "../tooltip";
|
|
10
11
|
|
|
11
12
|
import { classMap } from "lit/directives/class-map.js";
|
|
@@ -13,11 +14,16 @@ import styles from './menu.scss';
|
|
|
13
14
|
|
|
14
15
|
interface NavItem {
|
|
15
16
|
title: string;
|
|
17
|
+
/** `label` renders a section heading and `divider` a separator; anything else is an item. */
|
|
16
18
|
type: string;
|
|
17
19
|
path: string;
|
|
18
20
|
target: string;
|
|
19
21
|
icon: string;
|
|
20
22
|
style: string;
|
|
23
|
+
/** A semantic colour for the item, such as `error` for a destructive action. */
|
|
24
|
+
color?: string;
|
|
25
|
+
/** A keyboard shortcut shown at the end of the item. */
|
|
26
|
+
shortcut?: string;
|
|
21
27
|
confirm: {
|
|
22
28
|
type: string;
|
|
23
29
|
title: string;
|
|
@@ -56,6 +62,7 @@ export default class ZnMenu extends ZincElement {
|
|
|
56
62
|
'zn-dropdown': ZnDropdown,
|
|
57
63
|
'zn-icon': ZnIcon,
|
|
58
64
|
'zn-menu-item': ZnMenuItem,
|
|
65
|
+
'zn-menu-label': ZnMenuLabel,
|
|
59
66
|
'zn-tooltip': ZnTooltip,
|
|
60
67
|
};
|
|
61
68
|
|
|
@@ -118,6 +125,12 @@ export default class ZnMenu extends ZincElement {
|
|
|
118
125
|
if (item === null || item === undefined) {
|
|
119
126
|
return html``; // Skip null or undefined items
|
|
120
127
|
}
|
|
128
|
+
if (item.type === 'label') {
|
|
129
|
+
return html`<zn-menu-label>${item.title}</zn-menu-label>`;
|
|
130
|
+
}
|
|
131
|
+
if (item.type === 'divider') {
|
|
132
|
+
return html`<hr>`;
|
|
133
|
+
}
|
|
121
134
|
if (item?.confirm) {
|
|
122
135
|
return html`
|
|
123
136
|
<zn-confirm trigger="${ifDefined(item.confirm?.trigger)}"
|
|
@@ -129,6 +142,8 @@ export default class ZnMenu extends ZincElement {
|
|
|
129
142
|
@keydown=${this.handleKeyDown}
|
|
130
143
|
id="${item.confirm?.trigger}"
|
|
131
144
|
variant="${this.itemVariant}"
|
|
145
|
+
color="${ifDefined(item.color)}"
|
|
146
|
+
shortcut="${ifDefined(item.shortcut)}"
|
|
132
147
|
confirm>
|
|
133
148
|
${(item.icon) ? html`
|
|
134
149
|
<zn-icon src="${item.icon}" size="20" slot="prefix"></zn-icon>` : html``}
|
|
@@ -140,6 +155,8 @@ export default class ZnMenu extends ZincElement {
|
|
|
140
155
|
<zn-menu-item value="${item.title}"
|
|
141
156
|
href="${item.path}"
|
|
142
157
|
variant="${this.itemVariant}"
|
|
158
|
+
color="${ifDefined(item.color)}"
|
|
159
|
+
shortcut="${ifDefined(item.shortcut)}"
|
|
143
160
|
data-target="${ifDefined(item.target)}">
|
|
144
161
|
${(item.icon) ? html`
|
|
145
162
|
<zn-icon src="${item.icon}" size="20" slot="prefix"></zn-icon>` : html``}
|
|
@@ -197,8 +214,10 @@ export default class ZnMenu extends ZincElement {
|
|
|
197
214
|
event.preventDefault();
|
|
198
215
|
event.stopPropagation();
|
|
199
216
|
|
|
200
|
-
// Simulate a click to support @click handlers on menu items that also work with the keyboard
|
|
201
|
-
|
|
217
|
+
// Simulate a click to support @click handlers on menu items that also work with the keyboard. A link item's
|
|
218
|
+
// <a> is in its shadow root, and only a click on the anchor itself follows it.
|
|
219
|
+
const anchor = item?.shadowRoot?.querySelector<HTMLElement>('a#anchor');
|
|
220
|
+
(anchor ?? item)?.click();
|
|
202
221
|
}
|
|
203
222
|
|
|
204
223
|
// Move the selection when pressing down or up
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
.menu {
|
|
4
4
|
display: block;
|
|
5
5
|
position: relative;
|
|
6
|
-
padding: 1px;
|
|
6
|
+
padding: var(--zn-menu-padding, 1px);
|
|
7
7
|
border: 1px solid rgb(var(--zn-border-color)) !important;
|
|
8
|
-
border-radius: var(--zn-border-radius);
|
|
8
|
+
border-radius: var(--zn-menu-border-radius, var(--zn-border-radius));
|
|
9
9
|
width: fit-content;
|
|
10
10
|
min-width: var(--zn-menu-min-width, var(--zn-size-spanel));
|
|
11
11
|
// Unconstrained by default — a consumer that needs the menu to scroll inside a bounded
|
|
@@ -13,31 +13,16 @@
|
|
|
13
13
|
max-height: var(--zn-menu-max-height, none);
|
|
14
14
|
overflow: auto;
|
|
15
15
|
overscroll-behavior: none;
|
|
16
|
-
box-shadow: 0 4px 8px -4px rgba(33, 33, 33, 0.1);
|
|
16
|
+
box-shadow: var(--zn-menu-shadow, 0 4px 8px -4px rgba(33, 33, 33, 0.1));
|
|
17
17
|
// Same surface as the shell-header menus below, so every dropdown in the
|
|
18
18
|
// product reads as one material rather than splitting into --zn-panel menus
|
|
19
19
|
// and --zn-color-navigation ones depending on where it was mounted.
|
|
20
20
|
background-color: rgb(var(--zn-color-navigation, 255, 255, 255));
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// A submenu
|
|
24
|
-
:host([slot="submenu"]) .menu {
|
|
25
|
-
|
|
26
|
-
border-end-start-radius: 0;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Set by the submenu controller while this submenu extends past its parent's bottom edge.
|
|
30
|
-
:host([slot="submenu"][data-extends-below]) .menu {
|
|
31
|
-
border-end-start-radius: var(--zn-border-radius);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Set by the submenu controller on the parent menu while a submenu covers that corner.
|
|
35
|
-
:host([data-submenu-top]) .menu {
|
|
36
|
-
border-start-end-radius: 0;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
:host([data-submenu-bottom]) .menu {
|
|
40
|
-
border-end-end-radius: 0;
|
|
23
|
+
// A submenu sits just off its parent menu, so a page-level shadow would mostly land on the parent
|
|
24
|
+
:host([slot="submenu"]) .menu:not(.menu--shell) {
|
|
25
|
+
box-shadow: var(--zn-menu-submenu-shadow, 0 4px 12px rgba(13, 23, 56, 0.10), 0 1px 3px rgba(13, 23, 56, 0.06));
|
|
41
26
|
}
|
|
42
27
|
|
|
43
28
|
// A capped menu has to look scrollable, so the bar is always drawn rather than
|
|
@@ -73,7 +58,7 @@
|
|
|
73
58
|
border: 1px solid rgb(var(--zn-border-color));
|
|
74
59
|
border-radius: var(--zn-border-radius);
|
|
75
60
|
min-width: var(--zn-menu-min-width, 245px);
|
|
76
|
-
max-width: min(320px, calc(100vw - 16px));
|
|
61
|
+
max-width: var(--zn-menu-max-width, min(320px, calc(100vw - 16px)));
|
|
77
62
|
max-height: var(--zn-menu-max-height, none);
|
|
78
63
|
overflow-x: hidden;
|
|
79
64
|
overflow-y: auto;
|
|
@@ -84,6 +69,41 @@
|
|
|
84
69
|
}
|
|
85
70
|
|
|
86
71
|
|
|
72
|
+
// Width, style and colour are set apart so an unresolved colour token can't drop the line.
|
|
73
|
+
.menu > hr {
|
|
74
|
+
height: 0;
|
|
75
|
+
margin: var(--zn-menu-divider-margin, 4px 0);
|
|
76
|
+
border: 0;
|
|
77
|
+
border-top-width: 1px;
|
|
78
|
+
border-top-style: solid;
|
|
79
|
+
border-top-color: var(--zn-menu-divider-color, rgb(var(--zn-border-color)));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// !important because the page's own hr styles otherwise outrank ::slotted()
|
|
83
|
+
::slotted(hr) {
|
|
84
|
+
height: 0 !important;
|
|
85
|
+
margin: var(--zn-menu-divider-margin, 4px 0) !important;
|
|
86
|
+
border: 0 !important;
|
|
87
|
+
border-top-width: 1px !important;
|
|
88
|
+
border-top-style: solid !important;
|
|
89
|
+
border-top-color: var(--zn-menu-divider-color, rgb(var(--zn-border-color))) !important;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// A zn-confirm only contributes its dialog, so it must not claim a slot (or a gap) in the item stack.
|
|
93
|
+
zn-confirm, ::slotted(zn-confirm) {
|
|
94
|
+
display: contents;
|
|
95
|
+
}
|
|
96
|
+
|
|
87
97
|
::slotted(zn-menu-item + zn-menu-item) {
|
|
88
|
-
border-top: 1px solid rgb(var(--zn-border-color));
|
|
98
|
+
border-top: var(--zn-menu-item-divider, 1px solid rgb(var(--zn-border-color)));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// A group divider, shown even when the theme drops the line between items
|
|
102
|
+
::slotted(hr) {
|
|
103
|
+
flex: 0 0 auto;
|
|
104
|
+
margin: var(--zn-spacing-3x-small, 2px) 0;
|
|
105
|
+
border: none;
|
|
106
|
+
border-top-style: solid;
|
|
107
|
+
border-top-width: 1px;
|
|
108
|
+
border-top-color: rgb(var(--zn-border-color));
|
|
89
109
|
}
|
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
import '../../../dist/zn.min.js';
|
|
2
2
|
import { expect, fixture, html } from '@open-wc/testing';
|
|
3
|
+
import type ZnMenu from './menu.component';
|
|
3
4
|
|
|
4
5
|
describe('<zn-menu>', () => {
|
|
6
|
+
it('should draw a slotted hr as a divider', async () => {
|
|
7
|
+
const el = await fixture(html`<zn-menu><zn-menu-item>Edit</zn-menu-item><hr><zn-menu-item>Delete</zn-menu-item></zn-menu>`);
|
|
8
|
+
const style = getComputedStyle(el.querySelector('hr')!);
|
|
9
|
+
expect(style.borderTopStyle).to.equal('solid');
|
|
10
|
+
expect(style.borderBottomStyle).to.equal('none');
|
|
11
|
+
});
|
|
12
|
+
|
|
5
13
|
it('should render a component', async () => {
|
|
6
14
|
const el = await fixture(html` <zn-menu></zn-menu> `);
|
|
7
15
|
|
|
8
16
|
expect(el).to.exist;
|
|
9
17
|
});
|
|
18
|
+
|
|
19
|
+
it('should skip labels in keyboard navigation', async () => {
|
|
20
|
+
const el = await fixture<ZnMenu>(html`
|
|
21
|
+
<zn-menu><zn-menu-label>Customer</zn-menu-label><zn-menu-item>Send email</zn-menu-item></zn-menu>
|
|
22
|
+
`);
|
|
23
|
+
expect(el.getAllItems().map(item => item.textContent!.trim())).to.deep.equal(['Send email']);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should render labels, dividers, colours and shortcuts from actions', async () => {
|
|
27
|
+
const el = await fixture<ZnMenu>(html`<zn-menu></zn-menu>`);
|
|
28
|
+
el.actions = [
|
|
29
|
+
{type: 'label', title: 'Customer'},
|
|
30
|
+
{title: 'Send email', shortcut: 'E', path: '#'},
|
|
31
|
+
{type: 'divider'},
|
|
32
|
+
{title: 'Delete', color: 'error', path: '#'},
|
|
33
|
+
] as unknown as ZnMenu['actions'];
|
|
34
|
+
await el.updateComplete;
|
|
35
|
+
|
|
36
|
+
const root = el.shadowRoot!;
|
|
37
|
+
expect(root.querySelector('zn-menu-label')!.textContent).to.equal('Customer');
|
|
38
|
+
expect(root.querySelector('.menu > hr')).to.exist;
|
|
39
|
+
const items = [...root.querySelectorAll('zn-menu-item')];
|
|
40
|
+
expect(items[0].getAttribute('shortcut')).to.equal('E');
|
|
41
|
+
expect(items[1].getAttribute('color')).to.equal('error');
|
|
42
|
+
});
|
|
10
43
|
});
|
|
@@ -28,6 +28,7 @@ import styles from './menu-item.scss';
|
|
|
28
28
|
* @slot example - An example slot.
|
|
29
29
|
*
|
|
30
30
|
* @csspart base - The component's base wrapper.
|
|
31
|
+
* @csspart shortcut - The key cap showing the item's `shortcut`.
|
|
31
32
|
*
|
|
32
33
|
* @cssproperty --example - An example CSS custom property.
|
|
33
34
|
*/
|
|
@@ -100,6 +101,9 @@ export default class ZnMenuItem extends ZincElement {
|
|
|
100
101
|
/** Marks the menu item as currently active/selected. */
|
|
101
102
|
@property({type: Boolean, reflect: true}) active = false;
|
|
102
103
|
|
|
104
|
+
/** A keyboard shortcut shown as a key cap at the end of the item, such as `E` or `⌘K`. */
|
|
105
|
+
@property() shortcut: string;
|
|
106
|
+
|
|
103
107
|
private readonly localize = new LocalizeController(this);
|
|
104
108
|
private readonly hasSlotController = new HasSlotController(this, 'submenu');
|
|
105
109
|
private submenuController: SubmenuController = new SubmenuController(this, this.hasSlotController, this.localize);
|
|
@@ -142,9 +146,13 @@ export default class ZnMenuItem extends ZincElement {
|
|
|
142
146
|
if (!this.isSubmenu()) {
|
|
143
147
|
const composedPath = event.composedPath();
|
|
144
148
|
const closestMenu: Element | null = composedPath.find((el: Element) => el?.getAttribute?.('role') === 'menu') as Element;
|
|
145
|
-
if (this.confirm) return;
|
|
146
|
-
|
|
147
149
|
const dropdown = closestMenu?.closest('zn-dropdown') as ZnDropdown | null;
|
|
150
|
+
if (this.confirm) {
|
|
151
|
+
// The confirm dialog lives inside the dropdown panel, so the dropdown can only close once the dialog does
|
|
152
|
+
dropdown?.addEventListener('zn-close', () => dropdown.hide(), {once: true});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
148
156
|
if (!dropdown?.stayOpenOnSelect && !this.keepOpen) {
|
|
149
157
|
dropdown?.hide();
|
|
150
158
|
}
|
|
@@ -215,6 +223,7 @@ export default class ZnMenuItem extends ZincElement {
|
|
|
215
223
|
part="base"
|
|
216
224
|
data-path=${ifDefined(this.dataPath)}
|
|
217
225
|
href=${ifDefined(this.href)}
|
|
226
|
+
tabindex=${ifDefined(isLink ? '-1' : undefined)}
|
|
218
227
|
target=${ifDefined(isLink ? this.target : undefined)}
|
|
219
228
|
data-target=${ifDefined(isLink ? this.dataTarget : undefined)}
|
|
220
229
|
rel=${ifDefined(isLink ? this.rel : undefined)}
|
|
@@ -254,6 +263,8 @@ export default class ZnMenuItem extends ZincElement {
|
|
|
254
263
|
|
|
255
264
|
<slot name="suffix" part="suffix" class="menu-item__suffix"></slot>
|
|
256
265
|
|
|
266
|
+
${this.shortcut ? html`<kbd part="shortcut" class="menu-item__shortcut">${this.shortcut}</kbd>` : ''}
|
|
267
|
+
|
|
257
268
|
${this.checkedPosition === 'right' ? html`
|
|
258
269
|
<span part="checked-icon" class="menu-item__check">
|
|
259
270
|
<zn-icon src="check@lu" size="18" aria-hidden="true"></zn-icon>
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
@use "../../wc";
|
|
2
2
|
|
|
3
3
|
:host {
|
|
4
|
-
// Overlaps the parent menu's padding so the submenu's border lands on the parent's.
|
|
5
|
-
--submenu-offset: 1px;
|
|
6
4
|
// Baseline — standalone items (e.g. app/sidebar navigation): primary hover
|
|
7
5
|
--color: var(--zn-text-menu-link-color);
|
|
8
6
|
--hover-color: rgb(var(--zn-primary));
|
|
@@ -15,7 +13,7 @@
|
|
|
15
13
|
// its colour), no separators between rows. Set by the parent zn-menu.
|
|
16
14
|
:host([variant="dropdown"]) {
|
|
17
15
|
--hover-color: var(--color);
|
|
18
|
-
--hover-bg: rgba(0, 0, 0, 0.06);
|
|
16
|
+
--hover-bg: var(--zn-menu-item-hover-background, rgba(0, 0, 0, 0.06));
|
|
19
17
|
}
|
|
20
18
|
|
|
21
19
|
// Shell — app-shell header dropdown look: dark text, primary hover. Set by the
|
|
@@ -51,8 +49,10 @@
|
|
|
51
49
|
|
|
52
50
|
:host([variant="dropdown"]) .menu-item {
|
|
53
51
|
align-items: center;
|
|
54
|
-
|
|
52
|
+
min-height: var(--zn-menu-item-min-height, auto);
|
|
53
|
+
padding: var(--zn-menu-item-padding, var(--zn-spacing-small) var(--zn-spacing-large));
|
|
55
54
|
border-bottom-width: 0;
|
|
55
|
+
border-radius: var(--zn-menu-item-border-radius, 0);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
:host([variant="shell"]) .menu-item {
|
|
@@ -69,6 +69,11 @@
|
|
|
69
69
|
color: inherit;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// A zn-confirm only contributes its dialog, so it must not take part in the label's layout.
|
|
73
|
+
.menu-item__label::slotted(zn-confirm) {
|
|
74
|
+
display: contents;
|
|
75
|
+
}
|
|
76
|
+
|
|
72
77
|
.menu-item.menu-item--disabled {
|
|
73
78
|
outline: none;
|
|
74
79
|
opacity: 0.5;
|
|
@@ -167,7 +172,17 @@
|
|
|
167
172
|
|
|
168
173
|
.menu-item .menu-item__prefix::slotted(*) {
|
|
169
174
|
--icon-size: var(--zn-font-size-small);
|
|
170
|
-
margin-inline-end: var(--zn-spacing-small);
|
|
175
|
+
margin-inline-end: var(--zn-menu-item-icon-gap, var(--zn-spacing-small));
|
|
176
|
+
color: var(--zn-menu-item-icon-color, inherit);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// A status item's icon takes the item's colour
|
|
180
|
+
.menu-item--primary .menu-item__prefix::slotted(*),
|
|
181
|
+
.menu-item--info .menu-item__prefix::slotted(*),
|
|
182
|
+
.menu-item--error .menu-item__prefix::slotted(*),
|
|
183
|
+
.menu-item--warning .menu-item__prefix::slotted(*),
|
|
184
|
+
.menu-item--success .menu-item__prefix::slotted(*) {
|
|
185
|
+
color: inherit;
|
|
171
186
|
}
|
|
172
187
|
|
|
173
188
|
// Shell items space the icon via the row gap instead
|
|
@@ -185,6 +200,29 @@
|
|
|
185
200
|
margin-inline-start: var(--zn-spacing-x-small);
|
|
186
201
|
}
|
|
187
202
|
|
|
203
|
+
// A keyboard shortcut, drawn as a key cap at the end of the row
|
|
204
|
+
.menu-item__shortcut {
|
|
205
|
+
display: inline-flex;
|
|
206
|
+
align-items: center;
|
|
207
|
+
justify-content: center;
|
|
208
|
+
box-sizing: border-box;
|
|
209
|
+
flex: 0 0 auto;
|
|
210
|
+
min-width: 20px;
|
|
211
|
+
height: 20px;
|
|
212
|
+
margin-inline-start: var(--zn-spacing-medium);
|
|
213
|
+
padding: 0 5px;
|
|
214
|
+
border: 1px solid rgb(var(--zn-border-color));
|
|
215
|
+
border-bottom-width: 2px;
|
|
216
|
+
border-radius: 4px;
|
|
217
|
+
background: rgb(var(--zn-panel));
|
|
218
|
+
font-family: inherit;
|
|
219
|
+
font-style: normal;
|
|
220
|
+
font-size: 11px;
|
|
221
|
+
font-weight: var(--zn-font-weight-medium);
|
|
222
|
+
line-height: 1;
|
|
223
|
+
color: var(--zn-color-neutral-500);
|
|
224
|
+
}
|
|
225
|
+
|
|
188
226
|
/* Safe triangle */
|
|
189
227
|
.menu-item--submenu-expanded::after {
|
|
190
228
|
content: '';
|
|
@@ -256,11 +294,6 @@
|
|
|
256
294
|
|
|
257
295
|
zn-popup::part(popup) {
|
|
258
296
|
z-index: 100;
|
|
259
|
-
margin-left: var(--submenu-offset);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.menu-item--rtl zn-popup::part(popup) {
|
|
263
|
-
margin-left: calc(-1 * var(--submenu-offset));
|
|
264
297
|
}
|
|
265
298
|
|
|
266
299
|
@media (forced-colors: active) {
|
|
@@ -282,32 +315,32 @@ zn-popup::part(popup) {
|
|
|
282
315
|
// light accent such as velocity's neon lime).
|
|
283
316
|
.menu-item--primary {
|
|
284
317
|
--color: rgba(var(--zn-primary), 0.9);
|
|
285
|
-
--hover-color: rgb(var(--zn-color-on-primary, 255, 255, 255));
|
|
286
|
-
--hover-bg: rgba(var(--zn-primary), 0.9);
|
|
318
|
+
--hover-color: var(--zn-menu-item-primary-hover-color, rgb(var(--zn-color-on-primary, 255, 255, 255)));
|
|
319
|
+
--hover-bg: var(--zn-menu-item-primary-hover-background, rgba(var(--zn-primary), 0.9));
|
|
287
320
|
}
|
|
288
321
|
|
|
289
322
|
.menu-item--error {
|
|
290
|
-
--color:
|
|
291
|
-
--hover-color: rgb(var(--zn-color-on-error, 255, 255, 255));
|
|
292
|
-
--hover-bg: rgba(var(--zn-color-error), 0.9);
|
|
323
|
+
--color: var(--zn-color-danger-fg);
|
|
324
|
+
--hover-color: var(--zn-menu-item-danger-hover-color, rgb(var(--zn-color-on-error, 255, 255, 255)));
|
|
325
|
+
--hover-bg: var(--zn-menu-item-danger-hover-background, rgba(var(--zn-color-error), 0.9));
|
|
293
326
|
}
|
|
294
327
|
|
|
295
328
|
.menu-item--info {
|
|
296
329
|
--color: rgb(var(--zn-color-info));
|
|
297
|
-
--hover-color: rgb(var(--zn-color-on-info, 255, 255, 255));
|
|
298
|
-
--hover-bg: rgba(var(--zn-color-info), 0.9);
|
|
330
|
+
--hover-color: var(--zn-menu-item-info-hover-color, rgb(var(--zn-color-on-info, 255, 255, 255)));
|
|
331
|
+
--hover-bg: var(--zn-menu-item-info-hover-background, rgba(var(--zn-color-info), 0.9));
|
|
299
332
|
}
|
|
300
333
|
|
|
301
334
|
.menu-item--warning {
|
|
302
|
-
--color: rgb(var(--zn-color-warning));
|
|
303
|
-
--hover-color: rgb(var(--zn-color-on-warning, 255, 255, 255));
|
|
304
|
-
--hover-bg: rgba(var(--zn-color-warning), 0.9);
|
|
335
|
+
--color: var(--zn-color-warning-fg, rgb(var(--zn-color-warning)));
|
|
336
|
+
--hover-color: var(--zn-menu-item-warning-hover-color, rgb(var(--zn-color-on-warning, 255, 255, 255)));
|
|
337
|
+
--hover-bg: var(--zn-menu-item-warning-hover-background, rgba(var(--zn-color-warning), 0.9));
|
|
305
338
|
}
|
|
306
339
|
|
|
307
340
|
.menu-item--success {
|
|
308
|
-
--color: rgb(var(--zn-color-success));
|
|
309
|
-
--hover-color: rgb(var(--zn-color-on-success, 255, 255, 255));
|
|
310
|
-
--hover-bg: rgba(var(--zn-color-success), 0.9);
|
|
341
|
+
--color: var(--zn-color-success-fg, rgb(var(--zn-color-success)));
|
|
342
|
+
--hover-color: var(--zn-menu-item-success-hover-color, rgb(var(--zn-color-on-success, 255, 255, 255)));
|
|
343
|
+
--hover-bg: var(--zn-menu-item-success-hover-background, rgba(var(--zn-color-success), 0.9));
|
|
311
344
|
}
|
|
312
345
|
|
|
313
346
|
.menu-item--secondary {
|