@kubex/zinc 1.0.24 → 1.0.98

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 (198) 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 +13431 -8728
  4. package/dist/vscode.html-custom-data.json +571 -37
  5. package/dist/web-types.json +1439 -181
  6. package/dist/zn.d.ts +1642 -661
  7. package/dist/zn.min.css +1 -1
  8. package/dist/zn.min.js +1407 -887
  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/key-container.md +115 -0
  51. package/docs/pages/components/key.md +101 -0
  52. package/docs/pages/components/menu.md +512 -6
  53. package/docs/pages/components/note.md +239 -36
  54. package/docs/pages/components/opt-group.md +107 -0
  55. package/docs/pages/components/pagination.md +332 -6
  56. package/docs/pages/components/pane.md +222 -6
  57. package/docs/pages/components/panel.md +213 -26
  58. package/docs/pages/components/popup.md +1354 -6
  59. package/docs/pages/components/priority-list.md +233 -0
  60. package/docs/pages/components/progress-bar.md +387 -6
  61. package/docs/pages/components/radio-group.md +242 -5
  62. package/docs/pages/components/radio.md +474 -6
  63. package/docs/pages/components/rating.md +331 -7
  64. package/docs/pages/components/reveal.md +524 -6
  65. package/docs/pages/components/scroll-container.md +552 -6
  66. package/docs/pages/components/select.md +762 -160
  67. package/docs/pages/components/skeleton.md +473 -30
  68. package/docs/pages/components/slideout.md +261 -5
  69. package/docs/pages/components/sp.md +99 -41
  70. package/docs/pages/components/split-button.md +347 -9
  71. package/docs/pages/components/split-pane.md +445 -6
  72. package/docs/pages/components/stat.md +549 -9
  73. package/docs/pages/components/status-indicator.md +230 -1
  74. package/docs/pages/components/stepper.md +563 -6
  75. package/docs/pages/components/tabs.md +439 -13
  76. package/docs/pages/components/textarea.md +415 -17
  77. package/docs/pages/components/tile.md +385 -26
  78. package/docs/pages/components/toggle.md +424 -6
  79. package/docs/pages/components/tooltip.md +367 -0
  80. package/docs/pages/components/translation-group.md +210 -0
  81. package/docs/pages/components/translations.md +319 -18
  82. package/docs/pages/components/vertical-stepper.md +401 -8
  83. package/docs/pages/components/well.md +300 -3
  84. package/docs/pages/getting-started/form-controls.md +162 -0
  85. package/docs/pages/index.md +116 -15
  86. package/package.json +5 -6
  87. package/scss/_global-spacing.scss +4 -0
  88. package/scss/_root.scss +2 -2
  89. package/scss/boot.scss +19 -0
  90. package/scss/shared/layout.scss +5 -0
  91. package/scss/themes/_light.scss +3 -3
  92. package/src/components/alert/alert.scss +1 -0
  93. package/src/components/animated-button/README.md +306 -0
  94. package/src/components/animated-button/animated-button.component.ts +229 -0
  95. package/src/components/animated-button/animated-button.scss +228 -0
  96. package/src/components/animated-button/animated-button.test.ts +143 -0
  97. package/src/components/animated-button/index.ts +12 -0
  98. package/src/components/button/button.component.ts +5 -0
  99. package/src/components/button-group/button-group.component.ts +25 -13
  100. package/src/components/button-group/button-group.scss +6 -0
  101. package/src/components/checkbox/checkbox.component.ts +4 -0
  102. package/src/components/checkbox/checkbox.scss +7 -4
  103. package/src/components/checkbox-group/checkbox-group.scss +7 -0
  104. package/src/components/chip/chip.component.ts +7 -2
  105. package/src/components/chip/chip.scss +16 -2
  106. package/src/components/collapsible/collapsible.component.ts +27 -20
  107. package/src/components/cols/cols.component.ts +14 -2
  108. package/src/components/cols/cols.scss +6 -12
  109. package/src/components/confirm/confirm.component.ts +7 -0
  110. package/src/components/copy-button/copy-button.component.ts +12 -11
  111. package/src/components/data-select/data-select.component.ts +215 -44
  112. package/src/components/data-select/data-select.scss +66 -6
  113. package/src/components/data-select/providers/currency-data-provider.ts +20 -6
  114. package/src/components/data-select/providers/provider.ts +1 -0
  115. package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
  116. package/src/components/data-table/data-table.component.ts +82 -23
  117. package/src/components/data-table-search/data-table-search.component.ts +184 -0
  118. package/src/components/data-table-search/data-table-search.scss +17 -0
  119. package/src/components/data-table-search/data-table-search.test.ts +11 -0
  120. package/src/components/data-table-search/index.ts +12 -0
  121. package/src/components/datepicker/datepicker.component.ts +347 -13
  122. package/src/components/dialog/dialog.component.ts +1 -1
  123. package/src/components/empty-state/empty-state.scss +6 -1
  124. package/src/components/header/header.scss +3 -3
  125. package/src/components/icon/icon.component.ts +23 -1
  126. package/src/components/icon/icon.scss +23 -0
  127. package/src/components/icon-picker/brand-icons.ts +24 -0
  128. package/src/components/icon-picker/icon-picker.component.ts +407 -0
  129. package/src/components/icon-picker/icon-picker.scss +205 -0
  130. package/src/components/icon-picker/index.ts +12 -0
  131. package/src/components/icon-picker/line-icons.ts +612 -0
  132. package/src/components/icon-picker/material-icons.ts +14543 -0
  133. package/src/components/inline-edit/inline-edit.component.ts +190 -46
  134. package/src/components/inline-edit/inline-edit.scss +29 -0
  135. package/src/components/inline-edit/inline-edit.test.ts +314 -1
  136. package/src/components/input/input.component.ts +328 -5
  137. package/src/components/input/input.scss +100 -4
  138. package/src/components/input-group/input-group.component.ts +28 -7
  139. package/src/components/input-group/input-group.scss +48 -10
  140. package/src/components/item/item.component.ts +11 -2
  141. package/src/components/item/item.scss +7 -0
  142. package/src/components/key/index.ts +12 -0
  143. package/src/components/key/key.component.ts +47 -0
  144. package/src/components/key/key.scss +38 -0
  145. package/src/components/key-container/index.ts +12 -0
  146. package/src/components/key-container/key-container.component.ts +142 -0
  147. package/src/components/key-container/key-container.scss +33 -0
  148. package/src/components/menu-item/menu-item.component.ts +20 -0
  149. package/src/components/menu-item/menu-item.scss +69 -2
  150. package/src/components/navbar/navbar.component.ts +103 -8
  151. package/src/components/navbar/navbar.scss +6 -1
  152. package/src/components/opt-group/index.ts +12 -0
  153. package/src/components/opt-group/opt-group.component.ts +74 -0
  154. package/src/components/opt-group/opt-group.scss +37 -0
  155. package/src/components/opt-group/opt-group.test.ts +27 -0
  156. package/src/components/option/option.component.ts +1 -16
  157. package/src/components/option/option.scss +4 -0
  158. package/src/components/panel/panel.component.ts +10 -8
  159. package/src/components/panel/panel.scss +20 -0
  160. package/src/components/priority-list/index.ts +12 -0
  161. package/src/components/priority-list/priority-list.component.ts +611 -0
  162. package/src/components/priority-list/priority-list.scss +185 -0
  163. package/src/components/priority-list/priority-list.test.ts +139 -0
  164. package/src/components/progress-bar/progress-bar.component.ts +22 -16
  165. package/src/components/radio/radio.scss +10 -3
  166. package/src/components/select/select.component.ts +812 -72
  167. package/src/components/select/select.scss +108 -2
  168. package/src/components/select/select.test.ts +147 -2
  169. package/src/components/settings-container/settings-container.component.ts +44 -19
  170. package/src/components/settings-container/settings-container.scss +1 -1
  171. package/src/components/skeleton/skeleton.component.ts +6 -1
  172. package/src/components/slideout/slideout.scss +8 -3
  173. package/src/components/sp/sp.component.ts +3 -1
  174. package/src/components/sp/sp.scss +19 -0
  175. package/src/components/stepper/stepper.component.ts +16 -10
  176. package/src/components/textarea/textarea.scss +0 -4
  177. package/src/components/tile/tile.component.ts +12 -3
  178. package/src/components/tile/tile.scss +1 -1
  179. package/src/components/timer/timer.component.ts +15 -2
  180. package/src/components/toggle/toggle.component.ts +29 -26
  181. package/src/components/toggle/toggle.scss +13 -1
  182. package/src/components/translation-group/index.ts +12 -0
  183. package/src/components/translation-group/translation-group.component.ts +207 -0
  184. package/src/components/translation-group/translation-group.scss +8 -0
  185. package/src/components/translations/translations.component.ts +90 -42
  186. package/src/components/translations/translations.scss +5 -1
  187. package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
  188. package/src/events/events.ts +12 -7
  189. package/src/events/zn-language-change.ts +7 -0
  190. package/src/events/zn-purchase.ts +11 -0
  191. package/src/events/zn-redirect.ts +7 -0
  192. package/src/events/zn-reorder.ts +7 -0
  193. package/src/events/zn-search-change.ts +11 -0
  194. package/src/events/zn-submit.ts +1 -1
  195. package/src/form-control.scss +4 -0
  196. package/src/internal/form-navigation.ts +510 -0
  197. package/src/internal/form.ts +6 -0
  198. package/src/zinc.ts +91 -83
@@ -1,45 +1,454 @@
1
1
  ---
2
2
  meta:
3
3
  title: File
4
- description:
4
+ description: File controls allow users to select one or more files for upload through a button interface or drag-and-drop area.
5
5
  layout: component
6
6
  ---
7
7
 
8
+ ## Examples
9
+
10
+ ### Basic File Upload with Label
11
+
12
+ Use the `label` attribute to give the file control an accessible label.
13
+
8
14
  ```html:preview
9
- <zn-file multiple clearable></zn-file>
15
+ <zn-file label="Upload Document"></zn-file>
10
16
  ```
11
17
 
12
- ## Examples
18
+ :::tip
19
+ This component works with standard `<form>` elements. Please refer to the section on [form controls](/getting-started/form-controls) to learn more about form submission and client-side validation.
20
+ :::
13
21
 
14
- ### Label
22
+ ### Help Text
23
+
24
+ Add descriptive help text to a file control with the `help-text` attribute. For help text that contains HTML, use the `help-text` slot instead.
15
25
 
16
26
  ```html:preview
17
- <zn-file label="File Upload"></zn-file>
27
+ <zn-file label="Upload Resume" help-text="Accepted formats: PDF, DOC, DOCX (Max 5MB)"></zn-file>
28
+ <br />
29
+ <zn-file label="Upload Resume">
30
+ <div slot="help-text">Accepted formats: <strong>PDF, DOC, DOCX</strong> (Max 5MB)</div>
31
+ </zn-file>
18
32
  ```
19
33
 
20
- ### Droparea
34
+ ### Multiple Files
35
+
36
+ Use the `multiple` attribute to allow users to select more than one file at a time.
21
37
 
22
38
  ```html:preview
23
- <zn-file accept="text/plain,image/*" multiple droparea></zn-file>
39
+ <zn-file label="Upload Photos" multiple></zn-file>
24
40
  ```
25
41
 
26
- ### Help Text
42
+ ### Clearable Files
43
+
44
+ Add the `clearable` attribute to display a close button next to each selected file, allowing users to remove individual files from the selection.
27
45
 
28
46
  ```html:preview
29
- <zn-file help-text="You can drag and drop files here"></zn-file>
47
+ <zn-file label="Upload Documents" multiple clearable></zn-file>
30
48
  ```
31
49
 
32
- ### Multiple Upload
50
+ ### Droparea Mode
51
+
52
+ Use the `droparea` attribute to render the file control as a large drag-and-drop area. This mode is ideal when file upload is a primary action on the page.
33
53
 
34
54
  ```html:preview
55
+ <zn-file label="Upload Files" droparea multiple></zn-file>
56
+ ```
57
+
58
+ ### Accepted File Types
35
59
 
36
- <zn-file multiple></zn-file>
60
+ Use the `accept` attribute to specify which file types are accepted. This controls which files appear in the file picker dialog and provides client-side validation.
61
+
62
+ ```html:preview
63
+ <zn-file label="Upload Images" accept="image/*" multiple></zn-file>
64
+ <br />
65
+ <zn-file label="Upload Document" accept=".pdf,.doc,.docx"></zn-file>
66
+ <br />
67
+ <zn-file label="Upload Text File" accept="text/plain"></zn-file>
37
68
  ```
38
69
 
70
+ :::tip
71
+ The `accept` attribute takes a comma-separated list of:
72
+ - File extensions (e.g., `.pdf`, `.jpg`)
73
+ - MIME types (e.g., `image/png`, `application/pdf`)
74
+ - MIME type wildcards (e.g., `image/*`, `video/*`)
75
+
76
+ See [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept) for more details.
77
+ :::
78
+
79
+ ### Droparea with Accepted Types
80
+
81
+ Combine `droparea` and `accept` for a prominent upload area with file type restrictions.
82
+
83
+ ```html:preview
84
+ <zn-file label="Upload Images" accept="image/*" multiple droparea></zn-file>
85
+ ```
86
+
87
+ ### Custom Droparea Icon
88
+
89
+ Use the `droparea-icon` slot to customize the icon displayed in the droparea.
90
+
91
+ ```html:preview
92
+ <zn-file label="Upload Photos" droparea multiple>
93
+ <zn-icon src="photo_library" slot="droparea-icon"></zn-icon>
94
+ </zn-file>
95
+ ```
96
+
97
+ ### Directory Upload
98
+
99
+ Use the `webkitdirectory` attribute to allow users to select entire directories instead of individual files. When a directory is selected, all files within it and its subdirectories are included.
100
+
101
+ ```html:preview
102
+ <zn-file label="Upload Folder" webkitdirectory></zn-file>
103
+ ```
104
+
105
+ :::warning
106
+ **Note:** The `webkitdirectory` attribute is non-standard but is supported in all major browsers. When this attribute is set, the `multiple` property is automatically enabled.
107
+ :::
108
+
109
+ ### Directory Droparea
110
+
111
+ Combine `webkitdirectory` with `droparea` for a drag-and-drop folder upload interface.
112
+
113
+ ```html:preview
114
+ <zn-file label="Upload Project Folder" webkitdirectory droparea></zn-file>
115
+ ```
116
+
117
+ ### Camera Capture
118
+
119
+ Use the `capture` attribute to prompt users to use their device's camera or microphone. This only works on mobile devices and requires the `accept` attribute to specify the media type.
120
+
121
+ ```html:preview
122
+ <zn-file label="Take Photo" accept="image/*" capture="environment"></zn-file>
123
+ <br />
124
+ <zn-file label="Take Selfie" accept="image/*" capture="user"></zn-file>
125
+ ```
126
+
127
+ :::warning
128
+ **Note:** The `capture` attribute only works on mobile devices with cameras and does not work with the `droparea` mode. The `environment` value activates the rear camera, while `user` activates the front-facing camera.
129
+ :::
130
+
39
131
  ### Hide Value
40
132
 
133
+ Use the `hide-value` attribute to suppress the display of selected file names. This is useful when you want to handle file display in a custom way or when working with the trigger slot.
134
+
135
+ ```html:preview
136
+ <zn-file label="Upload File" hide-value></zn-file>
137
+ ```
138
+
139
+ ### Disabled
140
+
141
+ Use the `disabled` attribute to disable the file control.
142
+
143
+ ```html:preview
144
+ <zn-file label="Upload Document" disabled></zn-file>
145
+ <br />
146
+ <zn-file label="Upload Files" droparea disabled></zn-file>
147
+ ```
148
+
149
+ ### Sizes
150
+
151
+ Use the `size` attribute to change the file control's size. Size `medium` is the default.
152
+
153
+ ```html:preview
154
+ <zn-file label="Small Upload" size="small"></zn-file>
155
+ <br />
156
+ <zn-file label="Medium Upload" size="medium"></zn-file>
157
+ <br />
158
+ <zn-file label="Large Upload" size="large"></zn-file>
159
+ ```
160
+
161
+ ### Required
162
+
163
+ Use the `required` attribute to make the file control mandatory. The form will not submit unless at least one file is selected.
164
+
41
165
  ```html:preview
166
+ <form class="file-required-form">
167
+ <zn-file name="document" label="Upload Required Document" required></zn-file>
168
+ <br />
169
+ <zn-button type="submit" variant="primary">Submit</zn-button>
170
+ </form>
171
+
172
+ <script type="module">
173
+ const form = document.querySelector('.file-required-form');
174
+
175
+ await Promise.all([
176
+ customElements.whenDefined('zn-button'),
177
+ customElements.whenDefined('zn-file')
178
+ ]).then(() => {
179
+ form.addEventListener('submit', (e) => {
180
+ e.preventDefault();
181
+ const formData = new FormData(form);
182
+ alert('Form submitted with files!');
183
+ });
184
+ });
185
+ </script>
186
+ ```
187
+
188
+ ### Custom Trigger
189
+
190
+ Use the `trigger` slot to provide completely custom content for the file control. The trigger will automatically handle click events to open the file picker and drag-and-drop functionality.
191
+
192
+ ```html:preview
193
+ <zn-file name="custom-upload" multiple>
194
+ <div slot="trigger" style="padding: 2rem; border: 2px dashed var(--zn-color-neutral-300); border-radius: var(--zn-border-radius-medium); text-align: center; cursor: pointer;">
195
+ <zn-icon src="cloud_upload" style="font-size: 3rem; color: var(--zn-color-primary-600);"></zn-icon>
196
+ <p style="margin: 0.5rem 0 0; font-weight: var(--zn-font-weight-semibold);">Click to upload or drag and drop</p>
197
+ <p style="margin: 0.25rem 0 0; font-size: var(--zn-font-size-small); color: var(--zn-color-neutral-600);">SVG, PNG, JPG or GIF (max. 800x400px)</p>
198
+ </div>
199
+ </zn-file>
200
+ ```
201
+
202
+ :::warning
203
+ **Note:** When using the `trigger` slot, the following attributes will not work: `label`, `droparea`, `help-text`, `size`, and `hide-value`. You must handle styling for the disabled state yourself if using the `disabled` attribute.
204
+ :::
205
+
206
+ ### Handling File Events
207
+
208
+ Listen to `zn-change` and `zn-input` events to respond when users select files. Access the selected files through the `files` property.
209
+
210
+ ```html:preview
211
+ <zn-file class="file-events" label="Upload Files" multiple></zn-file>
212
+ <div class="file-event-output"></div>
213
+
214
+ <script type="module">
215
+ const fileInput = document.querySelector('.file-events');
216
+ const output = document.querySelector('.file-event-output');
217
+
218
+ await customElements.whenDefined('zn-file');
219
+
220
+ fileInput.addEventListener('zn-change', (e) => {
221
+ const files = fileInput.files;
222
+ if (files && files.length > 0) {
223
+ const fileList = Array.from(files).map(f => `${f.name} (${(f.size / 1024).toFixed(2)} KB)`).join('<br>');
224
+ output.innerHTML = `<strong>Selected files:</strong><br>${fileList}`;
225
+ } else {
226
+ output.innerHTML = '';
227
+ }
228
+ });
229
+ </script>
230
+ ```
231
+
232
+ ### Error Handling
233
+
234
+ The file control emits a `zn-error` event when multiple files are dropped without the `multiple` attribute being set.
235
+
236
+ ```html:preview
237
+ <zn-file class="file-error" label="Upload Single File" droparea></zn-file>
238
+ <div class="error-output" style="color: var(--zn-color-danger-600); margin-top: 0.5rem;"></div>
239
+
240
+ <script type="module">
241
+ const fileInput = document.querySelector('.file-error');
242
+ const errorOutput = document.querySelector('.error-output');
243
+
244
+ await customElements.whenDefined('zn-file');
245
+
246
+ fileInput.addEventListener('zn-error', () => {
247
+ errorOutput.textContent = 'Error: Only one file can be uploaded at a time.';
248
+ setTimeout(() => {
249
+ errorOutput.textContent = '';
250
+ }, 3000);
251
+ });
252
+
253
+ fileInput.addEventListener('zn-change', () => {
254
+ errorOutput.textContent = '';
255
+ });
256
+ </script>
257
+ ```
258
+
259
+ ### Working with FileList
260
+
261
+ The `files` property returns a `FileList` object containing `File` objects. You can access file information such as name, size, type, and last modified date.
262
+
263
+ ```html:preview
264
+ <zn-file class="file-info" label="Upload Files" multiple clearable></zn-file>
265
+ <div class="file-info-output"></div>
266
+
267
+ <script type="module">
268
+ const fileInput = document.querySelector('.file-info');
269
+ const output = document.querySelector('.file-info-output');
270
+
271
+ await customElements.whenDefined('zn-file');
272
+
273
+ fileInput.addEventListener('zn-change', () => {
274
+ const files = fileInput.files;
275
+ if (files && files.length > 0) {
276
+ let html = '<table style="width: 100%; border-collapse: collapse; margin-top: 1rem;"><thead><tr style="text-align: left; border-bottom: 1px solid var(--zn-color-neutral-200);"><th>Name</th><th>Size</th><th>Type</th></tr></thead><tbody>';
277
+
278
+ Array.from(files).forEach(file => {
279
+ const sizeKB = (file.size / 1024).toFixed(2);
280
+ html += `<tr style="border-bottom: 1px solid var(--zn-color-neutral-100);"><td style="padding: 0.5rem 0;">${file.name}</td><td>${sizeKB} KB</td><td>${file.type || 'unknown'}</td></tr>`;
281
+ });
282
+
283
+ html += '</tbody></table>';
284
+ output.innerHTML = html;
285
+ } else {
286
+ output.innerHTML = '';
287
+ }
288
+ });
289
+ </script>
290
+ ```
291
+
292
+ ### Form Integration
293
+
294
+ File controls work seamlessly with forms. The selected files are submitted as part of the form data when using `FormData`.
295
+
296
+ ```html:preview
297
+ <form class="file-form" enctype="multipart/form-data">
298
+ <zn-input name="name" label="Your Name" required></zn-input>
299
+ <br />
300
+ <zn-file name="documents" label="Upload Documents" multiple clearable></zn-file>
301
+ <br />
302
+ <zn-button type="submit" variant="primary">Submit Form</zn-button>
303
+ <zn-button type="reset">Reset</zn-button>
304
+ </form>
305
+ <div class="form-output"></div>
306
+
307
+ <script type="module">
308
+ const form = document.querySelector('.file-form');
309
+ const output = document.querySelector('.form-output');
310
+
311
+ await Promise.all([
312
+ customElements.whenDefined('zn-button'),
313
+ customElements.whenDefined('zn-file'),
314
+ customElements.whenDefined('zn-input')
315
+ ]).then(() => {
316
+ form.addEventListener('submit', (e) => {
317
+ e.preventDefault();
318
+ const formData = new FormData(form);
319
+
320
+ let info = `<strong>Form Data:</strong><br>Name: ${formData.get('name')}<br>`;
321
+ const files = formData.getAll('documents');
322
+ if (files.length > 0) {
323
+ info += `<strong>Files (${files.length}):</strong><br>`;
324
+ files.forEach(file => {
325
+ info += `- ${file.name} (${(file.size / 1024).toFixed(2)} KB)<br>`;
326
+ });
327
+ }
328
+
329
+ output.innerHTML = info;
330
+ });
331
+
332
+ form.addEventListener('reset', () => {
333
+ output.innerHTML = '';
334
+ });
335
+ });
336
+ </script>
337
+ ```
338
+
339
+ ### Programmatic File Access
340
+
341
+ You can programmatically access and manipulate the file control's value and files.
342
+
343
+ ```html:preview
344
+ <zn-file class="file-programmatic" label="Upload Files" multiple></zn-file>
345
+ <br />
346
+ <zn-button class="get-files-btn">Get File Names</zn-button>
347
+ <zn-button class="clear-files-btn">Clear Files</zn-button>
348
+ <div class="programmatic-output"></div>
349
+
350
+ <script type="module">
351
+ const fileInput = document.querySelector('.file-programmatic');
352
+ const getFilesBtn = document.querySelector('.get-files-btn');
353
+ const clearFilesBtn = document.querySelector('.clear-files-btn');
354
+ const output = document.querySelector('.programmatic-output');
355
+
356
+ await Promise.all([
357
+ customElements.whenDefined('zn-button'),
358
+ customElements.whenDefined('zn-file')
359
+ ]).then(() => {
360
+ getFilesBtn.addEventListener('click', () => {
361
+ const files = fileInput.files;
362
+ if (files && files.length > 0) {
363
+ const fileNames = Array.from(files).map(f => f.name).join(', ');
364
+ output.innerHTML = `<strong>Selected files:</strong> ${fileNames}`;
365
+ } else {
366
+ output.innerHTML = 'No files selected';
367
+ }
368
+ });
369
+
370
+ clearFilesBtn.addEventListener('click', () => {
371
+ fileInput.value = '';
372
+ output.innerHTML = 'Files cleared';
373
+ });
374
+ });
375
+ </script>
376
+ ```
377
+
378
+ :::warning
379
+ **Note:** For security reasons, you can only set the `value` property to an empty string. You cannot programmatically set files. Users must select files through the file picker or drag-and-drop interface.
380
+ :::
381
+
382
+ ### Validation
383
+
384
+ The file control supports standard HTML5 form validation. Use the `required` attribute to make file selection mandatory.
385
+
386
+ ```html:preview
387
+ <form class="file-validation-form">
388
+ <zn-file name="avatar" label="Profile Picture" accept="image/*" required></zn-file>
389
+ <br />
390
+ <zn-button type="submit" variant="primary">Upload</zn-button>
391
+ </form>
392
+
393
+ <script type="module">
394
+ const form = document.querySelector('.file-validation-form');
395
+
396
+ await Promise.all([
397
+ customElements.whenDefined('zn-button'),
398
+ customElements.whenDefined('zn-file')
399
+ ]).then(() => {
400
+ form.addEventListener('submit', (e) => {
401
+ e.preventDefault();
402
+ alert('File uploaded successfully!');
403
+ });
404
+ });
405
+ </script>
406
+ ```
407
+
408
+ ### Custom Validation
409
+
410
+ You can set custom validation messages using the `setCustomValidity()` method.
411
+
412
+ ```html:preview
413
+ <form class="custom-validation-form">
414
+ <zn-file class="custom-validation" name="document" label="Upload PDF (max 2MB)" accept=".pdf"></zn-file>
415
+ <br />
416
+ <zn-button type="submit" variant="primary">Submit</zn-button>
417
+ </form>
418
+ <div class="custom-validation-output"></div>
419
+
420
+ <script type="module">
421
+ const form = document.querySelector('.custom-validation-form');
422
+ const fileInput = document.querySelector('.custom-validation');
423
+ const output = document.querySelector('.custom-validation-output');
424
+
425
+ await Promise.all([
426
+ customElements.whenDefined('zn-button'),
427
+ customElements.whenDefined('zn-file')
428
+ ]).then(() => {
429
+ fileInput.addEventListener('zn-change', () => {
430
+ const files = fileInput.files;
431
+ if (files && files.length > 0) {
432
+ const file = files[0];
433
+ const maxSize = 2 * 1024 * 1024; // 2MB
434
+
435
+ if (file.size > maxSize) {
436
+ fileInput.setCustomValidity('File size must not exceed 2MB');
437
+ output.innerHTML = `<span style="color: var(--zn-color-danger-600);">File too large: ${(file.size / 1024 / 1024).toFixed(2)} MB (max 2MB)</span>`;
438
+ } else {
439
+ fileInput.setCustomValidity('');
440
+ output.innerHTML = `<span style="color: var(--zn-color-success-600);">File size: ${(file.size / 1024).toFixed(2)} KB - Valid!</span>`;
441
+ }
442
+ }
443
+ });
42
444
 
43
- <zn-file hide-value></zn-file>
445
+ form.addEventListener('submit', (e) => {
446
+ e.preventDefault();
447
+ if (form.checkValidity()) {
448
+ alert('Form submitted!');
449
+ }
450
+ });
451
+ });
452
+ </script>
44
453
  ```
45
454
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  meta:
3
3
  title: Filter Container
4
- description:
4
+ description: A container component with a built-in search input that filters child elements based on their data-filter attribute. Automatically shows/hides items and sections based on search terms.
5
5
  layout: component
6
6
  ---
7
7
 
@@ -63,10 +63,163 @@ layout: component
63
63
 
64
64
  ## Examples
65
65
 
66
- ### First Example
66
+ ### Basic List Filtering
67
67
 
68
- TODO
68
+ Filter a simple list of items by adding the `data-filter` attribute.
69
69
 
70
- ### Second Example
70
+ ```html:preview
71
+ <zn-filter-container>
72
+ <div data-filter="Apple">Apple</div>
73
+ <div data-filter="Banana">Banana</div>
74
+ <div data-filter="Cherry">Cherry</div>
75
+ <div data-filter="Date">Date</div>
76
+ <div data-filter="Elderberry">Elderberry</div>
77
+ </zn-filter-container>
78
+ ```
79
+
80
+ ### Card List
81
+
82
+ Filter a list of card components.
83
+
84
+ ```html:preview
85
+ <zn-filter-container>
86
+ <div style="display: grid; gap: 10px;">
87
+ <zn-card data-filter="Product Alpha">
88
+ <div slot="header">Product Alpha</div>
89
+ <div>Description of Product Alpha</div>
90
+ </zn-card>
91
+ <zn-card data-filter="Product Beta">
92
+ <div slot="header">Product Beta</div>
93
+ <div>Description of Product Beta</div>
94
+ </zn-card>
95
+ <zn-card data-filter="Product Gamma">
96
+ <div slot="header">Product Gamma</div>
97
+ <div>Description of Product Gamma</div>
98
+ </zn-card>
99
+ </div>
100
+ </zn-filter-container>
101
+ ```
102
+
103
+ ### Grouped Sections
104
+
105
+ Filter items within multiple panel sections. Empty sections are automatically hidden.
106
+
107
+ ```html:preview
108
+ <zn-filter-container>
109
+ <zn-sp flush>
110
+ <zn-panel caption="Fruits">
111
+ <div data-filter="Apple" style="padding: 5px;">Apple</div>
112
+ <div data-filter="Banana" style="padding: 5px;">Banana</div>
113
+ <div data-filter="Cherry" style="padding: 5px;">Cherry</div>
114
+ </zn-panel>
115
+
116
+ <zn-panel caption="Vegetables">
117
+ <div data-filter="Carrot" style="padding: 5px;">Carrot</div>
118
+ <div data-filter="Broccoli" style="padding: 5px;">Broccoli</div>
119
+ <div data-filter="Spinach" style="padding: 5px;">Spinach</div>
120
+ </zn-panel>
121
+
122
+ <zn-panel caption="Grains">
123
+ <div data-filter="Rice" style="padding: 5px;">Rice</div>
124
+ <div data-filter="Wheat" style="padding: 5px;">Wheat</div>
125
+ <div data-filter="Oats" style="padding: 5px;">Oats</div>
126
+ </zn-panel>
127
+ </zn-sp>
128
+ </zn-filter-container>
129
+ ```
130
+
131
+ ### Contact List
132
+
133
+ Filter a contact list with names and emails.
134
+
135
+ ```html:preview
136
+ <zn-filter-container>
137
+ <zn-sp flush>
138
+ <zn-panel caption="Team Members">
139
+ <div style="display: flex; flex-direction: column;">
140
+ <div data-filter="Alice Johnson alice.johnson@company.com"
141
+ style="padding: 10px; border-bottom: 1px solid var(--zn-color-neutral-200);">
142
+ <strong>Alice Johnson</strong>
143
+ <div style="color: var(--zn-color-neutral-500); font-size: 0.9em;">alice.johnson@company.com</div>
144
+ </div>
145
+ <div data-filter="Bob Smith bob.smith@company.com"
146
+ style="padding: 10px; border-bottom: 1px solid var(--zn-color-neutral-200);">
147
+ <strong>Bob Smith</strong>
148
+ <div style="color: var(--zn-color-neutral-500); font-size: 0.9em;">bob.smith@company.com</div>
149
+ </div>
150
+ <div data-filter="Carol White carol.white@company.com"
151
+ style="padding: 10px; border-bottom: 1px solid var(--zn-color-neutral-200);">
152
+ <strong>Carol White</strong>
153
+ <div style="color: var(--zn-color-neutral-500); font-size: 0.9em;">carol.white@company.com</div>
154
+ </div>
155
+ </div>
156
+ </zn-panel>
157
+ </zn-sp>
158
+ </zn-filter-container>
159
+ ```
160
+
161
+ ### Custom Filter Attribute
162
+
163
+ Use a custom attribute name for filtering by setting the `attr` property.
71
164
 
72
- TODO
165
+ ```html:preview
166
+ <zn-filter-container attr="search">
167
+ <div data-search="Red Item">Red Item</div>
168
+ <div data-search="Blue Item">Blue Item</div>
169
+ <div data-search="Green Item">Green Item</div>
170
+ </zn-filter-container>
171
+ ```
172
+
173
+ ### Product Catalog
174
+
175
+ Filter products with multiple data points in the filter attribute.
176
+
177
+ ```html:preview
178
+ <zn-filter-container>
179
+ <div style="display: grid; gap: 10px;">
180
+ <zn-card data-filter="Laptop Computer Electronics">
181
+ <div slot="header">Laptop</div>
182
+ <div>Category: Electronics</div>
183
+ <div>Type: Computer</div>
184
+ </zn-card>
185
+ <zn-card data-filter="Smartphone Mobile Electronics">
186
+ <div slot="header">Smartphone</div>
187
+ <div>Category: Electronics</div>
188
+ <div>Type: Mobile</div>
189
+ </zn-card>
190
+ <zn-card data-filter="Headphones Audio Electronics">
191
+ <div slot="header">Headphones</div>
192
+ <div>Category: Electronics</div>
193
+ <div>Type: Audio</div>
194
+ </zn-card>
195
+ </div>
196
+ </zn-filter-container>
197
+ ```
198
+
199
+ ### Settings Menu
200
+
201
+ Filter configuration options in a settings interface.
202
+
203
+ ```html:preview
204
+ <zn-filter-container>
205
+ <zn-sp flush>
206
+ <zn-panel caption="Account Settings">
207
+ <div data-filter="Profile Information" style="padding: 10px;">Profile Information</div>
208
+ <div data-filter="Email Preferences" style="padding: 10px;">Email Preferences</div>
209
+ <div data-filter="Password Security" style="padding: 10px;">Password Security</div>
210
+ </zn-panel>
211
+
212
+ <zn-panel caption="Application Settings">
213
+ <div data-filter="Theme Appearance" style="padding: 10px;">Theme Appearance</div>
214
+ <div data-filter="Language Localization" style="padding: 10px;">Language Localization</div>
215
+ <div data-filter="Notifications Alerts" style="padding: 10px;">Notifications Alerts</div>
216
+ </zn-panel>
217
+
218
+ <zn-panel caption="Privacy Settings">
219
+ <div data-filter="Data Sharing" style="padding: 10px;">Data Sharing</div>
220
+ <div data-filter="Cookie Preferences" style="padding: 10px;">Cookie Preferences</div>
221
+ <div data-filter="Two-Factor Authentication" style="padding: 10px;">Two-Factor Authentication</div>
222
+ </zn-panel>
223
+ </zn-sp>
224
+ </zn-filter-container>
225
+ ```