@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
@@ -312,17 +312,31 @@ const commonCurrencyCodes = [
312
312
  ];
313
313
 
314
314
  const sortedCurrencyCodes = [...Object.keys(currencyCodeToName)].sort((a, b) => a.localeCompare(b));
315
- const allCurrencyCodes = [...commonCurrencyCodes, ...sortedCurrencyCodes];
316
- const uniqueCurrencyCodes = Array.from(new Set(allCurrencyCodes));
317
315
 
318
- export const currencyDataProvider: LocalDataProvider<DataProviderOption> = {
319
- getName: 'currency',
320
- getData: uniqueCurrencyCodes.map((code => {
316
+ export const currencyDataProvider = (allowCommon: boolean = false): LocalDataProvider<DataProviderOption> => {
317
+ const otherCurrencyCodes = sortedCurrencyCodes.filter(code => !commonCurrencyCodes.includes(code));
318
+ const currencyCodes = [...commonCurrencyCodes, ...otherCurrencyCodes];
319
+
320
+ const data: DataProviderOption[] = currencyCodes.map((code => {
321
321
  return {
322
322
  key: code,
323
323
  value: code.concat(' - ').concat(currencyCodeToName[code]),
324
324
  prefix: currencyCodeToSymbol[code] ? currencyCodeToSymbol[code] : ''
325
325
  }
326
- }))
326
+ }));
327
+
328
+ if (allowCommon) {
329
+ const commonOption: DataProviderOption = {
330
+ key: commonCurrencyCodes.join(','),
331
+ value: 'Common - USD, EUR, GBP, CAD & AUD',
332
+ prefix: ''
333
+ };
334
+ data.unshift(commonOption);
335
+ }
336
+
337
+ return {
338
+ getName: 'currency',
339
+ getData: data
340
+ };
327
341
  };
328
342
 
@@ -30,3 +30,4 @@ export * from './country-data-provider';
30
30
  export * from './currency-data-provider';
31
31
  export * from './color-data-provider';
32
32
  export * from './country-code-data-provider';
33
+ export * from './us-state-data-provider';
@@ -0,0 +1,68 @@
1
+ import type {DataProviderOption, LocalDataProvider} from "./provider";
2
+
3
+ const usStates: { [key: string]: string } = {
4
+ "AL": "Alabama",
5
+ "AK": "Alaska",
6
+ "AZ": "Arizona",
7
+ "AR": "Arkansas",
8
+ "CA": "California",
9
+ "CO": "Colorado",
10
+ "CT": "Connecticut",
11
+ "DE": "Delaware",
12
+ "FL": "Florida",
13
+ "GA": "Georgia",
14
+ "HI": "Hawaii",
15
+ "ID": "Idaho",
16
+ "IL": "Illinois",
17
+ "IN": "Indiana",
18
+ "IA": "Iowa",
19
+ "KS": "Kansas",
20
+ "KY": "Kentucky",
21
+ "LA": "Louisiana",
22
+ "ME": "Maine",
23
+ "MD": "Maryland",
24
+ "MA": "Massachusetts",
25
+ "MI": "Michigan",
26
+ "MN": "Minnesota",
27
+ "MS": "Mississippi",
28
+ "MO": "Missouri",
29
+ "MT": "Montana",
30
+ "NE": "Nebraska",
31
+ "NV": "Nevada",
32
+ "NH": "New Hampshire",
33
+ "NJ": "New Jersey",
34
+ "NM": "New Mexico",
35
+ "NY": "New York",
36
+ "NC": "North Carolina",
37
+ "ND": "North Dakota",
38
+ "OH": "Ohio",
39
+ "OK": "Oklahoma",
40
+ "OR": "Oregon",
41
+ "PA": "Pennsylvania",
42
+ "RI": "Rhode Island",
43
+ "SC": "South Carolina",
44
+ "SD": "South Dakota",
45
+ "TN": "Tennessee",
46
+ "TX": "Texas",
47
+ "UT": "Utah",
48
+ "VT": "Vermont",
49
+ "VA": "Virginia",
50
+ "WA": "Washington",
51
+ "WV": "West Virginia",
52
+ "WI": "Wisconsin",
53
+ "WY": "Wyoming",
54
+ "DC": "District of Columbia",
55
+ "AS": "American Samoa",
56
+ "GU": "Guam",
57
+ "MP": "Northern Mariana Islands",
58
+ "PR": "Puerto Rico",
59
+ "VI": "U.S. Virgin Islands",
60
+ };
61
+
62
+ export const usStateDataProvider: LocalDataProvider<DataProviderOption> = {
63
+ getName: 'state',
64
+ getData: Object.entries(usStates).map(([code, name]) => ({
65
+ key: code,
66
+ value: name,
67
+ }))
68
+ };
@@ -7,12 +7,14 @@ import {ref} from "lit/directives/ref.js";
7
7
  import {Task} from "@lit/task";
8
8
  import {unsafeHTML} from "lit/directives/unsafe-html.js";
9
9
  import {type ZnFilterChangeEvent} from "../../events/zn-filter-change";
10
+ import {type ZnSearchChangeEvent} from "../../events/zn-search-change";
10
11
  import ZincElement from '../../internal/zinc-element';
11
12
  import ZnButton from "../button";
12
13
  import ZnButtonGroup from "../button-group";
13
14
  import ZnChip from "../chip";
14
15
  import ZnConfirm from "../confirm";
15
16
  import ZnDataTableFilter from "../data-table-filter";
17
+ import ZnDataTableSearch from "../data-table-search";
16
18
  import ZnDropdown from "../dropdown";
17
19
  import ZnEmptyState from "../empty-state";
18
20
  import ZnHoverContainer from "../hover-container";
@@ -69,6 +71,7 @@ export enum ActionSlots {
69
71
  filter = 'filter',
70
72
  filter_top = 'filter-top',
71
73
  sort = 'sort',
74
+ search = 'search',
72
75
  inputs = 'inputs'
73
76
  }
74
77
 
@@ -81,6 +84,8 @@ interface ActionConfig {
81
84
  confirmTitle: string;
82
85
  confirmContent: string;
83
86
  icon: string;
87
+ iconSrc?: string;
88
+ color?: string;
84
89
  type: string;
85
90
  }
86
91
 
@@ -102,6 +107,7 @@ interface DataRequest {
102
107
  sortColumn: string;
103
108
  sortDirection: string;
104
109
  filter: string;
110
+ search: string;
105
111
  }
106
112
 
107
113
  type AllowedInputElement =
@@ -129,11 +135,18 @@ type AllowedInputElement =
129
135
  * @dependency zn-button-group
130
136
  * @dependency zn-confirm
131
137
  * @dependency zn-skeleton
132
- *
133
- * @event zn-event-name - Emitted as an example.
138
+ * @dependency zn-data-table-search
134
139
  *
135
140
  * @slot - The default slot.
136
- * @slot example - An example slot.
141
+ * @slot search - Slot for search component.
142
+ * @slot sort - Slot for sort component.
143
+ * @slot filter - Slot for filter component.
144
+ * @slot filter-top - Slot for top-level filter component.
145
+ * @slot delete-action - Slot for delete action button.
146
+ * @slot modify-action - Slot for modify action button.
147
+ * @slot create-action - Slot for create action button.
148
+ * @slot inputs - Slot for additional input controls.
149
+ * @slot empty-state - Slot for custom empty state.
137
150
  *
138
151
  * @csspart base - The component's base wrapper.
139
152
  *
@@ -153,6 +166,7 @@ export default class ZnDataTable extends ZincElement {
153
166
  'zn-confirm': ZnConfirm,
154
167
  'zn-skeleton': ZnSkeleton,
155
168
  'zn-style': ZnStyle,
169
+ 'zn-data-table-search': ZnDataTableSearch,
156
170
  };
157
171
 
158
172
  @property({attribute: 'data-uri'}) dataUri: string;
@@ -161,6 +175,7 @@ export default class ZnDataTable extends ZincElement {
161
175
  @property({attribute: 'sort-direction'}) sortDirection: string = "asc";
162
176
  @property({attribute: 'local-sort', type: Boolean}) localSort: boolean = false;
163
177
  @property({attribute: 'filter'}) filter: string = '';
178
+ @property({attribute: 'search'}) search: string = '';
164
179
  @property({attribute: 'wide-column'}) wideColumn: string;
165
180
  @property({attribute: 'key'}) key: string = 'id';
166
181
  @property({attribute: 'headers', type: Object}) headers: Record<string, HeaderConfig> = {};
@@ -222,13 +237,14 @@ export default class ZnDataTable extends ZincElement {
222
237
  private hasSlotController = new HasSlotController(
223
238
  this,
224
239
  '[default]',
225
- 'search-action',
240
+ ActionSlots.search.valueOf(),
226
241
  ActionSlots.delete.valueOf(),
227
242
  ActionSlots.modify.valueOf(),
228
243
  ActionSlots.create.valueOf(),
229
244
  ActionSlots.filter.valueOf(),
230
245
  ActionSlots.sort.valueOf(),
231
- ActionSlots.inputs.valueOf()
246
+ ActionSlots.inputs.valueOf(),
247
+ 'empty-state'
232
248
  );
233
249
 
234
250
  private _dataTask = new Task(this, {
@@ -248,6 +264,7 @@ export default class ZnDataTable extends ZincElement {
248
264
  sortColumn: this.sortColumn,
249
265
  sortDirection: this.sortDirection,
250
266
  filter: this.filter,
267
+ search: this.search,
251
268
  };
252
269
 
253
270
  // get all inputs that are in the inputs slot and add them to the
@@ -349,7 +366,8 @@ export default class ZnDataTable extends ZincElement {
349
366
  || this.hasSlotController.test(ActionSlots.create.valueOf())
350
367
  || this.hasSlotController.test(ActionSlots.sort.valueOf())
351
368
  || this.hasSlotController.test(ActionSlots.filter.valueOf())
352
- || this.hasSlotController.test(ActionSlots.filter_top.valueOf());
369
+ || this.hasSlotController.test(ActionSlots.filter_top.valueOf())
370
+ || this.hasSlotController.test(ActionSlots.search.valueOf());
353
371
 
354
372
  const hasInputs = this.hasSlotController.test(ActionSlots.inputs.valueOf());
355
373
 
@@ -373,7 +391,8 @@ export default class ZnDataTable extends ZincElement {
373
391
  }
374
392
  });
375
393
 
376
- this.addEventListener('zn-filter-change', this.changeEventListener);
394
+ this.addEventListener('zn-filter-change', this.filterChangeListener);
395
+ this.addEventListener('zn-search-change', this.searchChangeListener);
377
396
  }
378
397
 
379
398
  disconnectedCallback() {
@@ -381,17 +400,55 @@ export default class ZnDataTable extends ZincElement {
381
400
  if (this.resizeObserver) {
382
401
  this.resizeObserver.disconnect();
383
402
  }
384
- this.removeEventListener('zn-filter-change', this.changeEventListener);
403
+ this.removeEventListener('zn-filter-change', this.filterChangeListener);
404
+ this.removeEventListener('zn-search-change', this.searchChangeListener);
385
405
  }
386
406
 
387
- changeEventListener = (e: ZnFilterChangeEvent) => {
407
+ filterChangeListener = (e: ZnFilterChangeEvent) => {
388
408
  if (e.target instanceof ZnDataTableFilter) {
389
409
  this.filter = (e.target as ZnDataTableFilter).value as string;
390
410
  this._dataTask.run().then(r => r);
391
411
  }
392
412
  }
393
413
 
414
+ searchChangeListener = (e: ZnSearchChangeEvent) => {
415
+ const target = e.target as ZnDataTableSearch | null;
416
+ if (target && target.tagName === 'ZN-DATA-TABLE-SEARCH') {
417
+ this.search = target.value as string;
418
+
419
+ // Get form data and search URI from event detail if available
420
+ if (e.detail) {
421
+ const {formData, searchUri} = e.detail as { formData?: Record<string, unknown>; searchUri?: string };
422
+
423
+ // Merge form data into request params
424
+ if (formData && typeof formData === 'object') {
425
+ this.requestParams = {...this.requestParams, ...formData};
426
+ }
427
+
428
+ // Temporarily override dataUri for this search if searchUri is provided
429
+ if (searchUri) {
430
+ const originalUri = this.dataUri;
431
+ this.dataUri = searchUri;
432
+ this._dataTask.run().then(() => {
433
+ // Restore original URI after search
434
+ this.dataUri = originalUri;
435
+ });
436
+ return;
437
+ }
438
+ }
439
+
440
+ this._dataTask.run().then(r => r);
441
+ }
442
+ }
443
+
394
444
  emptyState() {
445
+ if (this.hasSlotController.test('empty-state')) {
446
+ return html`
447
+ <div class="table--empty">
448
+ <slot name="empty-state"></slot>
449
+ </div>`;
450
+ }
451
+
395
452
  return html`
396
453
  <div class="table--empty">
397
454
  <zn-empty-state
@@ -584,6 +641,7 @@ export default class ZnDataTable extends ZincElement {
584
641
  ${this.getActions()}
585
642
  </div>
586
643
  <div class="table__header__right">
644
+ <slot name="${ActionSlots.search.valueOf()}"></slot>
587
645
  <slot name="${ActionSlots.sort.valueOf()}"></slot>
588
646
  <slot name="${ActionSlots.filter.valueOf()}"></slot>
589
647
  </div>
@@ -1257,14 +1315,12 @@ export default class ZnDataTable extends ZincElement {
1257
1315
  }
1258
1316
 
1259
1317
  private renderActions(row: Row) {
1260
- if ((row.actions === null || row.actions === undefined) && this.rowHasActions) {
1261
- // return an empty cell to keep the table structure
1262
- return html`
1263
- <td></td>`;
1264
- }
1265
-
1266
1318
  if (!row.actions || row.actions.length === 0) {
1267
- return html``;
1319
+ if (this.rowHasActions) {
1320
+ return html`
1321
+ <td></td>`;
1322
+ }
1323
+ return nothing;
1268
1324
  }
1269
1325
 
1270
1326
  return html`
@@ -1288,9 +1344,11 @@ export default class ZnDataTable extends ZincElement {
1288
1344
  content="${action.confirmContent}"
1289
1345
  action="${action.uri}"
1290
1346
  show-loading></zn-confirm>
1291
- <zn-menu-item id="${triggerId}" confirm>
1292
- ${(action.icon) ? html`
1293
- <zn-icon src="${action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
1347
+ <zn-menu-item id="${triggerId}"
1348
+ color="${ifDefined(action.color || nothing)}"
1349
+ confirm>
1350
+ ${(action.icon || action.iconSrc) ? html`
1351
+ <zn-icon src="${action.iconSrc || action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
1294
1352
  ${action.text}
1295
1353
  </zn-menu-item>`;
1296
1354
  } else {
@@ -1298,9 +1356,10 @@ export default class ZnDataTable extends ZincElement {
1298
1356
  <zn-menu-item value="${action.text}"
1299
1357
  href="${action.uri}"
1300
1358
  gaid="${ifDefined(action.gaid || nothing)}"
1301
- data-target="${ifDefined(action.target || nothing)}">
1302
- ${(action.icon) ? html`
1303
- <zn-icon src="${action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
1359
+ data-target="${ifDefined(action.target || nothing)}"
1360
+ color="${ifDefined(action.color || nothing)}">
1361
+ ${(action.icon || action.iconSrc) ? html`
1362
+ <zn-icon src="${action.iconSrc || action.icon}" size="20" slot="prefix"></zn-icon>` : html``}
1304
1363
  ${action.text}
1305
1364
  </zn-menu-item>`;
1306
1365
  }
@@ -0,0 +1,184 @@
1
+ import {type CSSResultGroup, html, type PropertyValues, unsafeCSS} from 'lit';
2
+ import {FormControlController, validValidityState} from "../../internal/form";
3
+ import {property} from 'lit/decorators.js';
4
+ import ZincElement, {type ZincFormControl} from '../../internal/zinc-element';
5
+ import ZnInput from "../input";
6
+ import type ZnDataSelect from "../data-select";
7
+ import type ZnQueryBuilder from "../query-builder";
8
+ import type ZnSelect from "../select";
9
+
10
+ import styles from './data-table-search.scss';
11
+
12
+ type AllowedInputElement =
13
+ HTMLInputElement
14
+ | HTMLSelectElement
15
+ | HTMLTextAreaElement
16
+ | ZnInput
17
+ | ZnSelect
18
+ | ZnDataSelect
19
+ | ZnQueryBuilder
20
+
21
+ /**
22
+ * @summary A search component for data tables.
23
+ * @documentation https://zinc.style/components/data-table-search
24
+ * @status experimental
25
+ * @since 1.0
26
+ *
27
+ * @dependency zn-input
28
+ *
29
+ * @event zn-search-change - Emitted when the search value changes (debounced).
30
+ *
31
+ * @slot - The default slot for additional form inputs.
32
+ *
33
+ * @csspart base - The component's base wrapper.
34
+ *
35
+ * @property {string} name - The name of the search input field (default: "search").
36
+ * @property {string} value - The current search value.
37
+ * @property {string} placeholder - The placeholder text for the search input (default: "Search...").
38
+ * @property {string} helpText - Help text displayed below the search input.
39
+ * @property {string} searchUri - Optional URI to use for search operations.
40
+ * @property {number} debounceDelay - The delay in milliseconds before triggering a search (default: 500).
41
+ */
42
+ export default class ZnDataTableSearch extends ZincElement implements ZincFormControl {
43
+ static styles: CSSResultGroup = unsafeCSS(styles);
44
+ static dependencies = {
45
+ 'zn-input': ZnInput,
46
+ };
47
+
48
+ private _formController: FormControlController = new FormControlController(this, {});
49
+ private _searchTimeout?: number;
50
+
51
+ @property() name: string = "search";
52
+
53
+ @property() value: string = "";
54
+
55
+ @property() placeholder: string = "Search...";
56
+
57
+ @property({attribute: 'help-text'}) helpText: string = "";
58
+
59
+ @property({attribute: 'search-uri'}) searchUri: string | undefined;
60
+
61
+ @property({type: Number, attribute: 'debounce-delay'}) debounceDelay: number = 350;
62
+
63
+ get validationMessage(): string {
64
+ return '';
65
+ }
66
+
67
+ get validity(): ValidityState {
68
+ return validValidityState;
69
+ }
70
+
71
+ checkValidity(): boolean {
72
+ return true;
73
+ }
74
+
75
+ getForm(): HTMLFormElement | null {
76
+ return this._formController.getForm();
77
+ }
78
+
79
+ reportValidity(): boolean {
80
+ return true;
81
+ }
82
+
83
+ setCustomValidity(): void {
84
+ this._formController.updateValidity();
85
+ }
86
+
87
+ protected firstUpdated(_changedProperties: PropertyValues) {
88
+ super.firstUpdated(_changedProperties);
89
+ this._formController.updateValidity();
90
+ }
91
+
92
+ /**
93
+ * Collects form data from slotted input elements
94
+ */
95
+ getFormData(): Record<string, any> {
96
+ const params: Record<string, any> = {};
97
+ const slot = this.shadowRoot?.querySelector('slot');
98
+ if (!slot) return params;
99
+
100
+ const elements = slot.assignedElements({flatten: true});
101
+ const allowedInputs = ['zn-input', 'zn-select', 'zn-query-builder', 'zn-multiselect', 'zn-params-select', 'zn-datepicker', 'input', 'select', 'textarea'];
102
+
103
+ elements.forEach((element) => {
104
+ if (allowedInputs.includes(element.tagName.toLowerCase())) {
105
+ const input = element as AllowedInputElement;
106
+ const value = input.value as string || element.getAttribute('value');
107
+ const name = input.name || element.getAttribute('name');
108
+ if (name) {
109
+ params[name] = value;
110
+ }
111
+ }
112
+ });
113
+
114
+ return params;
115
+ }
116
+
117
+ handleInput = (e: Event) => {
118
+ const input = e.target as ZnInput;
119
+ this.value = input.value as string;
120
+ this._formController.updateValidity();
121
+
122
+ if (this._searchTimeout) {
123
+ window.clearTimeout(this._searchTimeout);
124
+ }
125
+
126
+ this._searchTimeout = window.setTimeout(() => {
127
+ this.emitSearchChange();
128
+ }, this.debounceDelay);
129
+ }
130
+
131
+ handleClear = () => {
132
+ if (this._searchTimeout) {
133
+ window.clearTimeout(this._searchTimeout);
134
+ }
135
+
136
+ this.value = "";
137
+ const input = this.shadowRoot?.querySelector('zn-input');
138
+ if (input) {
139
+ input.value = "";
140
+ }
141
+ this._formController.updateValidity();
142
+ this.emitSearchChange();
143
+ }
144
+
145
+ disconnectedCallback() {
146
+ super.disconnectedCallback();
147
+ if (this._searchTimeout) {
148
+ window.clearTimeout(this._searchTimeout);
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Emit the search change event with form data
154
+ */
155
+ private emitSearchChange() {
156
+ const formData = this.getFormData();
157
+ this.emit('zn-search-change', {
158
+ detail: {
159
+ value: this.value,
160
+ formData: formData,
161
+ searchUri: this.searchUri
162
+ }
163
+ });
164
+ }
165
+
166
+ render() {
167
+ return html`
168
+ <div class="data-table-search">
169
+ <zn-input
170
+ type="search"
171
+ name="${this.name}"
172
+ placeholder="${this.placeholder}"
173
+ help-text="${this.helpText}"
174
+ value="${this.value}"
175
+ clearable
176
+ @zn-input="${this.handleInput}"
177
+ @zn-clear="${this.handleClear}">
178
+ <zn-icon slot="prefix" src="search" size="20"></zn-icon>
179
+ </zn-input>
180
+ <slot style="display: none"></slot>
181
+ </div>
182
+ `;
183
+ }
184
+ }
@@ -0,0 +1,17 @@
1
+ @use "../../wc";
2
+
3
+ :host {
4
+ display: block;
5
+ }
6
+
7
+ .data-table-search {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: var(--zn-spacing-small);
11
+ min-width: 200px;
12
+ }
13
+
14
+ zn-input::part(form-control-help-text) {
15
+ font-size: var(--zn-input-help-text-font-size-small);
16
+ padding-left: var(--zn-spacing-2x-small);
17
+ }
@@ -0,0 +1,11 @@
1
+ import {expect, fixture, html} from '@open-wc/testing';
2
+ import type ZnDataTableSearch from './data-table-search.component';
3
+
4
+ describe('<zn-data-table-search>', () => {
5
+ it('should render a component', async () => {
6
+ const el = await fixture<ZnDataTableSearch>(html`
7
+ <zn-data-table-search></zn-data-table-search>`);
8
+
9
+ expect(el).to.exist;
10
+ });
11
+ });
@@ -0,0 +1,12 @@
1
+ import ZnDataTableSearch from './data-table-search.component';
2
+
3
+ export * from './data-table-search.component';
4
+ export default ZnDataTableSearch;
5
+
6
+ ZnDataTableSearch.define('zn-data-table-search');
7
+
8
+ declare global {
9
+ interface HTMLElementTagNameMap {
10
+ 'zn-data-table-search': ZnDataTableSearch;
11
+ }
12
+ }