@kubex/zinc 1.0.25 → 1.0.99

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.
Files changed (199) hide show
  1. package/.claude/project.md +556 -0
  2. package/.github/workflows/js_build_and_deploy.yaml +9 -10
  3. package/dist/custom-elements.json +13575 -8856
  4. package/dist/vscode.html-custom-data.json +583 -48
  5. package/dist/web-types.json +1441 -181
  6. package/dist/zn.d.ts +1645 -660
  7. package/dist/zn.min.css +1 -1
  8. package/dist/zn.min.js +1412 -893
  9. package/docs/_utilities/code-previews.cjs +10 -1
  10. package/docs/assets/scripts/docs.js +42 -18
  11. package/docs/data/data-table.json +229 -66
  12. package/docs/data/empty.json +6 -0
  13. package/docs/data/products-table.json +41 -193
  14. package/docs/pages/components/action-bar.md +121 -6
  15. package/docs/pages/components/alert.md +118 -15
  16. package/docs/pages/components/animated-button.md +299 -0
  17. package/docs/pages/components/audio-select.md +534 -0
  18. package/docs/pages/components/bulk-actions.md +79 -5
  19. package/docs/pages/components/button-group.md +235 -27
  20. package/docs/pages/components/button.md +139 -1
  21. package/docs/pages/components/chart.md +365 -9
  22. package/docs/pages/components/checkbox.md +387 -58
  23. package/docs/pages/components/chip.md +253 -33
  24. package/docs/pages/components/collapsible.md +393 -46
  25. package/docs/pages/components/cols.md +152 -30
  26. package/docs/pages/components/confirm.md +182 -16
  27. package/docs/pages/components/copy-button.md +169 -6
  28. package/docs/pages/components/data-select.md +194 -15
  29. package/docs/pages/components/data-table-filter.md +96 -5
  30. package/docs/pages/components/data-table-search.md +451 -0
  31. package/docs/pages/components/data-table-sort.md +66 -5
  32. package/docs/pages/components/data-table.md +727 -66
  33. package/docs/pages/components/datepicker.md +402 -7
  34. package/docs/pages/components/defined-label.md +120 -5
  35. package/docs/pages/components/dialog.md +339 -59
  36. package/docs/pages/components/dropdown.md +366 -11
  37. package/docs/pages/components/editor.md +604 -7
  38. package/docs/pages/components/empty-state.md +315 -16
  39. package/docs/pages/components/expanding-action.md +212 -28
  40. package/docs/pages/components/file.md +421 -12
  41. package/docs/pages/components/filter-container.md +158 -5
  42. package/docs/pages/components/filter-wrapper.md +167 -6
  43. package/docs/pages/components/form-group.md +383 -6
  44. package/docs/pages/components/hover-container.md +237 -6
  45. package/docs/pages/components/icon-picker.md +121 -0
  46. package/docs/pages/components/icon.md +454 -48
  47. package/docs/pages/components/inline-edit.md +787 -19
  48. package/docs/pages/components/input-group.md +207 -13
  49. package/docs/pages/components/input.md +194 -0
  50. package/docs/pages/components/item.md +18 -0
  51. package/docs/pages/components/key-container.md +115 -0
  52. package/docs/pages/components/key.md +101 -0
  53. package/docs/pages/components/menu.md +512 -6
  54. package/docs/pages/components/note.md +239 -36
  55. package/docs/pages/components/opt-group.md +107 -0
  56. package/docs/pages/components/pagination.md +332 -6
  57. package/docs/pages/components/pane.md +222 -6
  58. package/docs/pages/components/panel.md +213 -26
  59. package/docs/pages/components/popup.md +1354 -6
  60. package/docs/pages/components/priority-list.md +233 -0
  61. package/docs/pages/components/progress-bar.md +387 -6
  62. package/docs/pages/components/radio-group.md +242 -5
  63. package/docs/pages/components/radio.md +474 -6
  64. package/docs/pages/components/rating.md +331 -7
  65. package/docs/pages/components/reveal.md +524 -6
  66. package/docs/pages/components/scroll-container.md +552 -6
  67. package/docs/pages/components/select.md +762 -160
  68. package/docs/pages/components/skeleton.md +473 -30
  69. package/docs/pages/components/slideout.md +261 -5
  70. package/docs/pages/components/sp.md +99 -41
  71. package/docs/pages/components/split-button.md +347 -9
  72. package/docs/pages/components/split-pane.md +445 -6
  73. package/docs/pages/components/stat.md +549 -9
  74. package/docs/pages/components/status-indicator.md +230 -1
  75. package/docs/pages/components/stepper.md +563 -6
  76. package/docs/pages/components/tabs.md +439 -13
  77. package/docs/pages/components/textarea.md +415 -17
  78. package/docs/pages/components/tile.md +385 -26
  79. package/docs/pages/components/toggle.md +424 -6
  80. package/docs/pages/components/tooltip.md +367 -0
  81. package/docs/pages/components/translation-group.md +210 -0
  82. package/docs/pages/components/translations.md +319 -19
  83. package/docs/pages/components/vertical-stepper.md +401 -8
  84. package/docs/pages/components/well.md +300 -3
  85. package/docs/pages/getting-started/form-controls.md +162 -0
  86. package/docs/pages/index.md +116 -15
  87. package/package.json +5 -6
  88. package/scss/_global-spacing.scss +4 -0
  89. package/scss/_root.scss +2 -2
  90. package/scss/boot.scss +19 -0
  91. package/scss/shared/layout.scss +5 -0
  92. package/scss/themes/_light.scss +3 -3
  93. package/src/components/alert/alert.scss +1 -0
  94. package/src/components/animated-button/README.md +306 -0
  95. package/src/components/animated-button/animated-button.component.ts +229 -0
  96. package/src/components/animated-button/animated-button.scss +228 -0
  97. package/src/components/animated-button/animated-button.test.ts +143 -0
  98. package/src/components/animated-button/index.ts +12 -0
  99. package/src/components/button/button.component.ts +5 -0
  100. package/src/components/button-group/button-group.component.ts +25 -13
  101. package/src/components/button-group/button-group.scss +6 -0
  102. package/src/components/checkbox/checkbox.component.ts +4 -0
  103. package/src/components/checkbox/checkbox.scss +7 -4
  104. package/src/components/checkbox-group/checkbox-group.scss +7 -0
  105. package/src/components/chip/chip.component.ts +7 -2
  106. package/src/components/chip/chip.scss +16 -2
  107. package/src/components/collapsible/collapsible.component.ts +27 -20
  108. package/src/components/cols/cols.component.ts +14 -2
  109. package/src/components/cols/cols.scss +6 -12
  110. package/src/components/confirm/confirm.component.ts +7 -0
  111. package/src/components/copy-button/copy-button.component.ts +12 -11
  112. package/src/components/data-select/data-select.component.ts +215 -44
  113. package/src/components/data-select/data-select.scss +66 -6
  114. package/src/components/data-select/providers/currency-data-provider.ts +20 -6
  115. package/src/components/data-select/providers/provider.ts +1 -0
  116. package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
  117. package/src/components/data-table/data-table.component.ts +81 -22
  118. package/src/components/data-table-search/data-table-search.component.ts +184 -0
  119. package/src/components/data-table-search/data-table-search.scss +17 -0
  120. package/src/components/data-table-search/data-table-search.test.ts +11 -0
  121. package/src/components/data-table-search/index.ts +12 -0
  122. package/src/components/datepicker/datepicker.component.ts +347 -13
  123. package/src/components/dialog/dialog.component.ts +1 -1
  124. package/src/components/empty-state/empty-state.scss +6 -1
  125. package/src/components/header/header.scss +3 -3
  126. package/src/components/icon/icon.component.ts +23 -1
  127. package/src/components/icon/icon.scss +23 -0
  128. package/src/components/icon-picker/brand-icons.ts +24 -0
  129. package/src/components/icon-picker/icon-picker.component.ts +407 -0
  130. package/src/components/icon-picker/icon-picker.scss +205 -0
  131. package/src/components/icon-picker/index.ts +12 -0
  132. package/src/components/icon-picker/line-icons.ts +612 -0
  133. package/src/components/icon-picker/material-icons.ts +14543 -0
  134. package/src/components/inline-edit/inline-edit.component.ts +190 -46
  135. package/src/components/inline-edit/inline-edit.scss +29 -0
  136. package/src/components/inline-edit/inline-edit.test.ts +314 -1
  137. package/src/components/input/input.component.ts +324 -5
  138. package/src/components/input/input.scss +87 -0
  139. package/src/components/input-group/input-group.component.ts +28 -7
  140. package/src/components/input-group/input-group.scss +48 -10
  141. package/src/components/item/item.component.ts +24 -3
  142. package/src/components/item/item.scss +18 -0
  143. package/src/components/key/index.ts +12 -0
  144. package/src/components/key/key.component.ts +47 -0
  145. package/src/components/key/key.scss +38 -0
  146. package/src/components/key-container/index.ts +12 -0
  147. package/src/components/key-container/key-container.component.ts +142 -0
  148. package/src/components/key-container/key-container.scss +33 -0
  149. package/src/components/menu-item/menu-item.component.ts +20 -0
  150. package/src/components/menu-item/menu-item.scss +69 -2
  151. package/src/components/navbar/navbar.component.ts +103 -11
  152. package/src/components/navbar/navbar.scss +6 -1
  153. package/src/components/opt-group/index.ts +12 -0
  154. package/src/components/opt-group/opt-group.component.ts +74 -0
  155. package/src/components/opt-group/opt-group.scss +37 -0
  156. package/src/components/opt-group/opt-group.test.ts +27 -0
  157. package/src/components/option/option.component.ts +1 -16
  158. package/src/components/option/option.scss +4 -0
  159. package/src/components/panel/panel.component.ts +10 -8
  160. package/src/components/panel/panel.scss +20 -0
  161. package/src/components/priority-list/index.ts +12 -0
  162. package/src/components/priority-list/priority-list.component.ts +611 -0
  163. package/src/components/priority-list/priority-list.scss +185 -0
  164. package/src/components/priority-list/priority-list.test.ts +139 -0
  165. package/src/components/progress-bar/progress-bar.component.ts +22 -16
  166. package/src/components/radio/radio.scss +10 -3
  167. package/src/components/select/select.component.ts +812 -72
  168. package/src/components/select/select.scss +108 -2
  169. package/src/components/select/select.test.ts +147 -2
  170. package/src/components/settings-container/settings-container.component.ts +44 -19
  171. package/src/components/settings-container/settings-container.scss +1 -1
  172. package/src/components/skeleton/skeleton.component.ts +6 -1
  173. package/src/components/slideout/slideout.scss +8 -3
  174. package/src/components/sp/sp.component.ts +3 -1
  175. package/src/components/sp/sp.scss +19 -0
  176. package/src/components/stepper/stepper.component.ts +16 -10
  177. package/src/components/textarea/textarea.scss +0 -4
  178. package/src/components/tile/tile.component.ts +12 -3
  179. package/src/components/tile/tile.scss +1 -1
  180. package/src/components/timer/timer.component.ts +15 -2
  181. package/src/components/toggle/toggle.component.ts +29 -26
  182. package/src/components/toggle/toggle.scss +13 -1
  183. package/src/components/translation-group/index.ts +12 -0
  184. package/src/components/translation-group/translation-group.component.ts +207 -0
  185. package/src/components/translation-group/translation-group.scss +8 -0
  186. package/src/components/translations/translations.component.ts +90 -44
  187. package/src/components/translations/translations.scss +4 -0
  188. package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
  189. package/src/events/events.ts +12 -7
  190. package/src/events/zn-language-change.ts +7 -0
  191. package/src/events/zn-purchase.ts +11 -0
  192. package/src/events/zn-redirect.ts +7 -0
  193. package/src/events/zn-reorder.ts +7 -0
  194. package/src/events/zn-search-change.ts +11 -0
  195. package/src/events/zn-submit.ts +1 -1
  196. package/src/form-control.scss +4 -0
  197. package/src/internal/form-navigation.ts +510 -0
  198. package/src/internal/form.ts +6 -0
  199. package/src/zinc.ts +91 -83
@@ -3,6 +3,7 @@ import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
3
3
  import {property} from 'lit/decorators.js';
4
4
  import ZincElement from '../../internal/zinc-element';
5
5
  import ZnIcon from "../icon";
6
+ import ZnTooltip from "../tooltip";
6
7
 
7
8
  import styles from './item.scss';
8
9
 
@@ -13,6 +14,7 @@ import styles from './item.scss';
13
14
  * @since 1.0
14
15
  *
15
16
  * @dependency zn-icon
17
+ * @dependency zn-tooltip
16
18
  *
17
19
  * @slot - The default slot. Can either be slotted or use the value attribute
18
20
  * @slot actions - Used for adding actions to a zn-item.
@@ -23,7 +25,8 @@ import styles from './item.scss';
23
25
  */
24
26
  export default class ZnItem extends ZincElement {
25
27
  static dependencies = {
26
- 'zn-icon': ZnIcon
28
+ 'zn-icon': ZnIcon,
29
+ 'zn-tooltip': ZnTooltip
27
30
  };
28
31
 
29
32
  static styles: CSSResultGroup = unsafeCSS(styles);
@@ -38,6 +41,8 @@ export default class ZnItem extends ZincElement {
38
41
 
39
42
  @property({attribute: 'edit-on-hover', type: Boolean}) editOnHover: boolean;
40
43
 
44
+ @property({attribute: 'help-tooltip'}) helpTooltip: string;
45
+
41
46
  @property() icon: string;
42
47
 
43
48
  @property() value: string;
@@ -52,7 +57,7 @@ export default class ZnItem extends ZincElement {
52
57
  @property({type: Boolean, attribute: 'align-end'}) alignEnd: boolean;
53
58
 
54
59
  // align items in the center
55
- @property({type: Boolean, attribute: 'align-center'}) alignCenter: boolean;
60
+ @property({type: Boolean, attribute: 'align-center'}) alignCenter: boolean;
56
61
 
57
62
  connectedCallback() {
58
63
  super.connectedCallback();
@@ -74,12 +79,28 @@ export default class ZnItem extends ZincElement {
74
79
  return slotContent > 0 || this.innerText.length > 0 || !(this.value === undefined || this.value === null)
75
80
  }
76
81
 
82
+ protected _hasRequiredSlot(): boolean {
83
+ const slotElements = this.querySelectorAll(":scope > *:not([slot])");
84
+ return Array.from(slotElements).some(el => el.hasAttribute && el.hasAttribute('required'));
85
+ }
86
+
77
87
  render() {
78
88
  const hasIcon = this.icon && this.icon.length > 0;
79
89
 
90
+ const hasHelpTooltip = this.helpTooltip?.length > 0;
91
+
80
92
  const headings = html`
81
93
  <div class="item__headings">
82
- <div class="item__caption" part="caption">${this.caption}</div>
94
+ <div class=${classMap({
95
+ 'item__caption': true,
96
+ 'item__caption--required': this._hasRequiredSlot(),
97
+ 'item__caption--has-help': hasHelpTooltip
98
+ })} part="caption">${this.caption}
99
+ ${hasHelpTooltip ? html`
100
+ <zn-tooltip class="item__help-tooltip" content="${this.helpTooltip}">
101
+ <zn-icon src="info"></zn-icon>
102
+ </zn-tooltip>` : ''}
103
+ </div>
83
104
  ${this.description ? html`
84
105
  <div class="item__description">${this.description}</div>` : ''}
85
106
  </div>`;
@@ -12,6 +12,7 @@
12
12
  flex-direction: row;
13
13
  padding: 0 var(--zn-spacing-medium);
14
14
  gap: var(--zn-spacing-2x-small);
15
+ min-height: 35px;
15
16
 
16
17
  @include wc.container-query(null, md) {
17
18
  --zn-item-label-max-width: 220px;
@@ -95,6 +96,23 @@
95
96
  line-height: var(--zn-line-height-loose);
96
97
  width: 100%;
97
98
  flex-shrink: 0;
99
+
100
+ &--has-help {
101
+ display: inline-flex;
102
+ align-items: center;
103
+ gap: var(--zn-spacing-2x-small);
104
+ }
105
+
106
+ &--required::after {
107
+ content: var(--zn-input-required-content);
108
+ margin-inline-start: var(--zn-input-required-content-offset);
109
+ color: var(--zn-input-required-content-color);
110
+ }
111
+ }
112
+
113
+ &__help-tooltip {
114
+ color: var(--zn-color-neutral-700);
115
+ font-size: var(--zn-font-size-small);
98
116
  }
99
117
 
100
118
  &__description {
@@ -0,0 +1,12 @@
1
+ import ZnKey from './key.component';
2
+
3
+ export * from './key.component';
4
+ export default ZnKey;
5
+
6
+ ZnKey.define('zn-key');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-key': ZnKey;
11
+ }
12
+ }
@@ -0,0 +1,47 @@
1
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
2
+ import {property} from 'lit/decorators.js';
3
+ import ZincElement from '../../internal/zinc-element';
4
+
5
+ import styles from './key.scss';
6
+
7
+ /**
8
+ * @summary A legend key item, typically used alongside charts to label and toggle visibility of data series by category.
9
+ * @documentation https://zinc.style/components/key
10
+ * @status experimental
11
+ * @since 1.0
12
+ *
13
+ * @slot - The description of the key.
14
+ */
15
+ export default class ZnKey extends ZincElement {
16
+ static styles: CSSResultGroup = unsafeCSS(styles);
17
+
18
+ @property() icon: string = '';
19
+ @property() attribute: string = '';
20
+ @property() value: string = '';
21
+ @property() color: 'primary' | 'success' | 'warning' | 'error' | 'info' | 'neutral' = 'primary';
22
+ @property({type: Boolean, reflect: true}) active: boolean = false;
23
+ @property({attribute: 'icon-size', type: Number}) iconSize: number = 24;
24
+
25
+ private _handleClick() {
26
+ this.active = !this.active;
27
+ this.emit('zn-change');
28
+ }
29
+
30
+ render() {
31
+ const chipType = this.active ? this.color : 'transparent';
32
+
33
+ return html`
34
+ <div class="key" @click="${this._handleClick}">
35
+ <zn-chip
36
+ .icon="${this.icon}"
37
+ .iconSize="${this.iconSize}"
38
+ .type="${chipType}"
39
+ size="medium"
40
+ ></zn-chip>
41
+ <div class="key__description">
42
+ <slot></slot>
43
+ </div>
44
+ </div>
45
+ `;
46
+ }
47
+ }
@@ -0,0 +1,38 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ display: block;
5
+ }
6
+
7
+ .key {
8
+ cursor: pointer;
9
+ display: flex;
10
+ flex-direction: row;
11
+ gap: var(--zn-spacing-medium);
12
+ align-items: center;
13
+ text-align: left;
14
+
15
+ &__description {
16
+ font-size: var(--zn-font-size-small);
17
+ color: rgb(var(--zn-text-body));
18
+ opacity: 0.7;
19
+ line-height: var(--zn-line-height-normal);
20
+ user-select: none;
21
+ }
22
+ }
23
+
24
+ :host([active]) .key__label {
25
+ color: rgb(var(--zn-text-heading));
26
+ font-weight: 600;
27
+ }
28
+
29
+ :host(:not([active])) {
30
+ .key__description {
31
+ opacity: 0.6;
32
+ }
33
+
34
+ zn-chip {
35
+ --zn-chip-color: rgb(var(--zn-text-body));
36
+ opacity: 0.5;
37
+ }
38
+ }
@@ -0,0 +1,12 @@
1
+ import ZnKeyContainer from './key-container.component';
2
+
3
+ export * from './key-container.component';
4
+ export default ZnKeyContainer;
5
+
6
+ ZnKeyContainer.define('zn-key-container');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-key-container': ZnKeyContainer;
11
+ }
12
+ }
@@ -0,0 +1,142 @@
1
+ import {classMap} from "lit/directives/class-map.js";
2
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
3
+ import {deepQuerySelectorAll} from "../../utilities/query";
4
+ import {property, query} from 'lit/decorators.js';
5
+ import ZincElement from '../../internal/zinc-element';
6
+ import type ZnKey from "../key/key.component";
7
+
8
+ import styles from './key-container.scss';
9
+
10
+ /**
11
+ * @summary A legend container that manages key items, typically used alongside charts to toggle visibility of data series by category.
12
+ * @documentation https://zinc.style/components/key-container
13
+ * @status experimental
14
+ * @since 1.0
15
+ *
16
+ * @slot - The content to be filtered.
17
+ * @slot keys - The key items (zn-key) that define the filters.
18
+ *
19
+ * @event zn-change - Emitted when the set of active keys changes.
20
+ */
21
+ export default class ZnKeyContainer extends ZincElement {
22
+ static styles: CSSResultGroup = unsafeCSS(styles);
23
+
24
+ @query('slot[name="keys"]') keysSlot: HTMLSlotElement;
25
+ @query('slot:not([name])') defaultSlot: HTMLSlotElement;
26
+
27
+ @property() position: 'top-end' | 'top-start' | 'bottom-end' | 'bottom-start' = 'bottom-start';
28
+ @property() target: string = ''; // ID of the target element containing items
29
+ @property({attribute: 'item-selector'}) itemSelector: string = '[data-type]';
30
+ @property({attribute: 'filter-attribute'}) filterAttribute: string = '';
31
+ @property({attribute: 'no-scroll', type: Boolean}) noScroll: boolean = false;
32
+
33
+ private _hiddenElements: Set<Element> = new Set();
34
+ private _targetElement: HTMLElement | null = null;
35
+
36
+ connectedCallback() {
37
+ super.connectedCallback();
38
+ this.updateFilters();
39
+ }
40
+
41
+ firstUpdated() {
42
+ if (this.target) {
43
+ const rootNode = this.getRootNode() as Document | ShadowRoot;
44
+ this._targetElement = rootNode.getElementById ? rootNode.getElementById(this.target) : document.getElementById(this.target);
45
+ }
46
+ this.updateFilters();
47
+ }
48
+
49
+ private _handleKeyChange() {
50
+ this.updateFilters();
51
+ this.emit('zn-change');
52
+ }
53
+
54
+ private getKeys(): ZnKey[] {
55
+ const keys = [];
56
+ if (this.keysSlot) {
57
+ keys.push(...this.keysSlot.assignedElements({flatten: true}));
58
+ }
59
+ if (this.defaultSlot) {
60
+ keys.push(...this.defaultSlot.assignedElements({flatten: true}));
61
+ }
62
+ return keys.filter(el => el.tagName.toLowerCase() === 'zn-key') as ZnKey[];
63
+ }
64
+
65
+ private updateFilters() {
66
+ const keys = this.getKeys();
67
+ if (!keys || keys.length === 0) return;
68
+
69
+ // Reset hidden elements
70
+ this._hiddenElements.forEach(el => el.removeAttribute('hidden'));
71
+ this._hiddenElements.clear();
72
+
73
+ if (this.target && !this._targetElement) {
74
+ const rootNode = this.getRootNode() as Document | ShadowRoot;
75
+ this._targetElement = rootNode.getElementById?.(this.target) ?? document.getElementById(this.target);
76
+ }
77
+ let root: Element | Document | DocumentFragment | null = this._targetElement ?? null;
78
+
79
+ if (!root) {
80
+ const slotElements = this.defaultSlot?.assignedElements({flatten: true}) ?? [];
81
+ root = slotElements.some(el => el.tagName !== 'ZN-KEY')
82
+ ? this
83
+ : this.parentElement ?? (this.parentNode as DocumentFragment);
84
+ }
85
+ if (!root) return;
86
+
87
+ const selector = this.filterAttribute ? `[${this.filterAttribute}]` : this.itemSelector;
88
+ const items = deepQuerySelectorAll(selector, root as HTMLElement, "");
89
+ items.forEach(item => {
90
+ if (item === this) return;
91
+
92
+ const matchesInactive = keys.some(key => !key.active && this.itemMatchesKey(item, key));
93
+ if (matchesInactive) {
94
+ item.setAttribute('hidden', '');
95
+ this._hiddenElements.add(item);
96
+ }
97
+ });
98
+ }
99
+
100
+ private itemMatchesKey(item: Element, key: ZnKey): boolean {
101
+ // 1. If the container specifies filterAttribute, use key.attribute as the value to look for
102
+ if (this.filterAttribute) {
103
+ const itemValue = item.getAttribute(this.filterAttribute);
104
+ if (!itemValue) return false;
105
+
106
+ const targetValue = key.attribute;
107
+ if (!targetValue) return false;
108
+
109
+ return itemValue.split(/\s+/).includes(targetValue);
110
+ }
111
+
112
+ // 2. If key specifies attribute and value
113
+ if (key.attribute && key.value) {
114
+ const itemValue = item.getAttribute(key.attribute);
115
+ if (!itemValue) return false;
116
+
117
+ return itemValue.split(/\s+/).includes(key.value);
118
+ }
119
+
120
+ // 3. If the key only specifies attribute (and no value), check for existence
121
+ if (key.attribute) {
122
+ return item.hasAttribute(key.attribute);
123
+ }
124
+
125
+ return false;
126
+ }
127
+
128
+ render() {
129
+ return html`
130
+ <div class="${classMap({
131
+ 'key-container': true,
132
+ 'key-container--scroll': !this.noScroll,
133
+ })}" @zn-change="${this._handleKeyChange}">
134
+ ${this.target ? '' : html`
135
+ <div class="key-container__content">
136
+ <slot @slotchange="${this.updateFilters.bind(this)}" class="key-container__keys"></slot>
137
+ </div>
138
+ `}
139
+ </div>
140
+ `;
141
+ }
142
+ }
@@ -0,0 +1,33 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ display: contents;
5
+ }
6
+
7
+ .key-container--scroll {
8
+ height: 100%;
9
+ width: 100%;
10
+ overflow: hidden;
11
+ position: relative;
12
+ }
13
+
14
+ .key-container__content {
15
+ height: 100%;
16
+ width: 100%;
17
+ overflow: auto;
18
+ box-sizing: border-box;
19
+ }
20
+
21
+ .key-container__keys {
22
+ display: flex;
23
+ flex-direction: column;
24
+ gap: var(--zn-spacing-medium);
25
+ }
26
+
27
+ ::slotted(zn-key) {
28
+ flex: 0 0 auto;
29
+ }
30
+
31
+ ::slotted([hidden]) {
32
+ display: none !important;
33
+ }
@@ -78,6 +78,21 @@ export default class ZnMenuItem extends ZincElement {
78
78
 
79
79
  @property({type: Boolean, reflect: true}) confirm = false;
80
80
 
81
+ /** Removes all padding from the menu item. */
82
+ @property({type: Boolean, reflect: true}) flush = false;
83
+
84
+ /** Removes horizontal (left/right) padding only. Ignored if flush is set. */
85
+ @property({type: Boolean, reflect: true, attribute: 'flush-x'}) flushX = false;
86
+
87
+ /** Removes vertical (top/bottom) padding only. Ignored if flush is set. */
88
+ @property({type: Boolean, reflect: true, attribute: 'flush-y'}) flushY = false;
89
+
90
+ /** Removes the border from the menu item. */
91
+ @property({type: Boolean, reflect: true, attribute: 'no-border'}) noBorder = false;
92
+
93
+ /** Marks the menu item as currently active/selected. */
94
+ @property({type: Boolean, reflect: true}) active = false;
95
+
81
96
  private readonly localize = new LocalizeController(this);
82
97
  private readonly hasSlotController = new HasSlotController(this, 'submenu');
83
98
  private submenuController: SubmenuController = new SubmenuController(this, this.hasSlotController, this.localize);
@@ -209,6 +224,11 @@ export default class ZnMenuItem extends ZincElement {
209
224
  'menu-item--success': this.color === 'success',
210
225
  'menu-item--warning': this.color === 'warning',
211
226
  'menu-item--transparent': this.color === 'transparent',
227
+ 'menu-item--flush': this.flush,
228
+ 'menu-item--flush-x': this.flushX && !this.flush,
229
+ 'menu-item--flush-y': this.flushY && !this.flush,
230
+ 'menu-item--no-border': this.noBorder,
231
+ 'menu-item--active': this.active,
212
232
 
213
233
  })}
214
234
  ?aria-haspopup="${this.isSubmenu()}"
@@ -23,7 +23,7 @@
23
23
  white-space: nowrap;
24
24
  cursor: pointer;
25
25
  border-bottom-width: 1px;
26
-
26
+ width: 100%;
27
27
  text-decoration: none;
28
28
  color: var(--color);
29
29
  }
@@ -44,6 +44,72 @@
44
44
  cursor: wait;
45
45
  }
46
46
 
47
+ // Flush variants - remove padding
48
+ .menu-item--flush {
49
+ padding: 0;
50
+ }
51
+
52
+ .menu-item--flush-x {
53
+ padding-left: 0;
54
+ padding-right: 0;
55
+ }
56
+
57
+ .menu-item--flush-y {
58
+ padding-top: 0;
59
+ padding-bottom: 0;
60
+ }
61
+
62
+ // No border variant
63
+ .menu-item--no-border {
64
+ border-bottom-width: 0;
65
+ }
66
+
67
+ // Active state - vertical strip indicator
68
+ .menu-item--active::before {
69
+ content: '';
70
+ position: absolute;
71
+ left: 0;
72
+ top: 0;
73
+ bottom: 0;
74
+ width: 3px;
75
+ background-color: var(--hover-color);
76
+ }
77
+
78
+ .menu-item.menu-item--active .menu-item__label {
79
+ font-weight: 700;
80
+ color: var(--hover-color);
81
+ }
82
+
83
+ .menu-item--rtl.menu-item--active::before {
84
+ left: auto;
85
+ right: 0;
86
+ }
87
+
88
+ // Active state with color variants
89
+ .menu-item--active.menu-item--primary::before {
90
+ background-color: rgb(var(--zn-primary));
91
+ }
92
+
93
+ .menu-item--active.menu-item--error::before {
94
+ background-color: rgb(var(--zn-color-error));
95
+ }
96
+
97
+ .menu-item--active.menu-item--info::before {
98
+ background-color: rgb(var(--zn-color-info));
99
+ }
100
+
101
+ .menu-item--active.menu-item--warning::before {
102
+ background-color: rgb(var(--zn-color-warning));
103
+ }
104
+
105
+ .menu-item--active.menu-item--success::before {
106
+ background-color: rgb(var(--zn-color-success));
107
+ }
108
+
109
+ .menu-item--active.menu-item--secondary::before {
110
+ background-color: rgb(var(--zn-accent));
111
+ }
112
+
47
113
  .menu-item .menu-item__label {
48
114
  display: flex;
49
115
  flex: 1 1 auto;
@@ -99,7 +165,8 @@
99
165
  }
100
166
 
101
167
  :host(:hover:not([aria-disabled='true'], :focus-visible)) .menu-item,
102
- .menu-item--submenu-expanded {
168
+ .menu-item--submenu-expanded,
169
+ .menu-item--active {
103
170
  background-color: var(--hover-bg);
104
171
  color: var(--hover-color);
105
172
  }