@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.
- package/.claude/project.md +556 -0
- package/.github/workflows/js_build_and_deploy.yaml +9 -10
- package/dist/custom-elements.json +13431 -8728
- package/dist/vscode.html-custom-data.json +571 -37
- package/dist/web-types.json +1439 -181
- package/dist/zn.d.ts +1642 -661
- package/dist/zn.min.css +1 -1
- package/dist/zn.min.js +1407 -887
- package/docs/_utilities/code-previews.cjs +10 -1
- package/docs/assets/scripts/docs.js +42 -18
- package/docs/data/data-table.json +229 -66
- package/docs/data/empty.json +6 -0
- package/docs/data/products-table.json +41 -193
- package/docs/pages/components/action-bar.md +121 -6
- package/docs/pages/components/alert.md +118 -15
- package/docs/pages/components/animated-button.md +299 -0
- package/docs/pages/components/audio-select.md +534 -0
- package/docs/pages/components/bulk-actions.md +79 -5
- package/docs/pages/components/button-group.md +235 -27
- package/docs/pages/components/button.md +139 -1
- package/docs/pages/components/chart.md +365 -9
- package/docs/pages/components/checkbox.md +387 -58
- package/docs/pages/components/chip.md +253 -33
- package/docs/pages/components/collapsible.md +393 -46
- package/docs/pages/components/cols.md +152 -30
- package/docs/pages/components/confirm.md +182 -16
- package/docs/pages/components/copy-button.md +169 -6
- package/docs/pages/components/data-select.md +194 -15
- package/docs/pages/components/data-table-filter.md +96 -5
- package/docs/pages/components/data-table-search.md +451 -0
- package/docs/pages/components/data-table-sort.md +66 -5
- package/docs/pages/components/data-table.md +727 -66
- package/docs/pages/components/datepicker.md +402 -7
- package/docs/pages/components/defined-label.md +120 -5
- package/docs/pages/components/dialog.md +339 -59
- package/docs/pages/components/dropdown.md +366 -11
- package/docs/pages/components/editor.md +604 -7
- package/docs/pages/components/empty-state.md +315 -16
- package/docs/pages/components/expanding-action.md +212 -28
- package/docs/pages/components/file.md +421 -12
- package/docs/pages/components/filter-container.md +158 -5
- package/docs/pages/components/filter-wrapper.md +167 -6
- package/docs/pages/components/form-group.md +383 -6
- package/docs/pages/components/hover-container.md +237 -6
- package/docs/pages/components/icon-picker.md +121 -0
- package/docs/pages/components/icon.md +454 -48
- package/docs/pages/components/inline-edit.md +787 -19
- package/docs/pages/components/input-group.md +207 -13
- package/docs/pages/components/input.md +194 -0
- package/docs/pages/components/key-container.md +115 -0
- package/docs/pages/components/key.md +101 -0
- package/docs/pages/components/menu.md +512 -6
- package/docs/pages/components/note.md +239 -36
- package/docs/pages/components/opt-group.md +107 -0
- package/docs/pages/components/pagination.md +332 -6
- package/docs/pages/components/pane.md +222 -6
- package/docs/pages/components/panel.md +213 -26
- package/docs/pages/components/popup.md +1354 -6
- package/docs/pages/components/priority-list.md +233 -0
- package/docs/pages/components/progress-bar.md +387 -6
- package/docs/pages/components/radio-group.md +242 -5
- package/docs/pages/components/radio.md +474 -6
- package/docs/pages/components/rating.md +331 -7
- package/docs/pages/components/reveal.md +524 -6
- package/docs/pages/components/scroll-container.md +552 -6
- package/docs/pages/components/select.md +762 -160
- package/docs/pages/components/skeleton.md +473 -30
- package/docs/pages/components/slideout.md +261 -5
- package/docs/pages/components/sp.md +99 -41
- package/docs/pages/components/split-button.md +347 -9
- package/docs/pages/components/split-pane.md +445 -6
- package/docs/pages/components/stat.md +549 -9
- package/docs/pages/components/status-indicator.md +230 -1
- package/docs/pages/components/stepper.md +563 -6
- package/docs/pages/components/tabs.md +439 -13
- package/docs/pages/components/textarea.md +415 -17
- package/docs/pages/components/tile.md +385 -26
- package/docs/pages/components/toggle.md +424 -6
- package/docs/pages/components/tooltip.md +367 -0
- package/docs/pages/components/translation-group.md +210 -0
- package/docs/pages/components/translations.md +319 -18
- package/docs/pages/components/vertical-stepper.md +401 -8
- package/docs/pages/components/well.md +300 -3
- package/docs/pages/getting-started/form-controls.md +162 -0
- package/docs/pages/index.md +116 -15
- package/package.json +5 -6
- package/scss/_global-spacing.scss +4 -0
- package/scss/_root.scss +2 -2
- package/scss/boot.scss +19 -0
- package/scss/shared/layout.scss +5 -0
- package/scss/themes/_light.scss +3 -3
- package/src/components/alert/alert.scss +1 -0
- package/src/components/animated-button/README.md +306 -0
- package/src/components/animated-button/animated-button.component.ts +229 -0
- package/src/components/animated-button/animated-button.scss +228 -0
- package/src/components/animated-button/animated-button.test.ts +143 -0
- package/src/components/animated-button/index.ts +12 -0
- package/src/components/button/button.component.ts +5 -0
- package/src/components/button-group/button-group.component.ts +25 -13
- package/src/components/button-group/button-group.scss +6 -0
- package/src/components/checkbox/checkbox.component.ts +4 -0
- package/src/components/checkbox/checkbox.scss +7 -4
- package/src/components/checkbox-group/checkbox-group.scss +7 -0
- package/src/components/chip/chip.component.ts +7 -2
- package/src/components/chip/chip.scss +16 -2
- package/src/components/collapsible/collapsible.component.ts +27 -20
- package/src/components/cols/cols.component.ts +14 -2
- package/src/components/cols/cols.scss +6 -12
- package/src/components/confirm/confirm.component.ts +7 -0
- package/src/components/copy-button/copy-button.component.ts +12 -11
- package/src/components/data-select/data-select.component.ts +215 -44
- package/src/components/data-select/data-select.scss +66 -6
- package/src/components/data-select/providers/currency-data-provider.ts +20 -6
- package/src/components/data-select/providers/provider.ts +1 -0
- package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
- package/src/components/data-table/data-table.component.ts +82 -23
- package/src/components/data-table-search/data-table-search.component.ts +184 -0
- package/src/components/data-table-search/data-table-search.scss +17 -0
- package/src/components/data-table-search/data-table-search.test.ts +11 -0
- package/src/components/data-table-search/index.ts +12 -0
- package/src/components/datepicker/datepicker.component.ts +347 -13
- package/src/components/dialog/dialog.component.ts +1 -1
- package/src/components/empty-state/empty-state.scss +6 -1
- package/src/components/header/header.scss +3 -3
- package/src/components/icon/icon.component.ts +23 -1
- package/src/components/icon/icon.scss +23 -0
- package/src/components/icon-picker/brand-icons.ts +24 -0
- package/src/components/icon-picker/icon-picker.component.ts +407 -0
- package/src/components/icon-picker/icon-picker.scss +205 -0
- package/src/components/icon-picker/index.ts +12 -0
- package/src/components/icon-picker/line-icons.ts +612 -0
- package/src/components/icon-picker/material-icons.ts +14543 -0
- package/src/components/inline-edit/inline-edit.component.ts +190 -46
- package/src/components/inline-edit/inline-edit.scss +29 -0
- package/src/components/inline-edit/inline-edit.test.ts +314 -1
- package/src/components/input/input.component.ts +328 -5
- package/src/components/input/input.scss +100 -4
- package/src/components/input-group/input-group.component.ts +28 -7
- package/src/components/input-group/input-group.scss +48 -10
- package/src/components/item/item.component.ts +11 -2
- package/src/components/item/item.scss +7 -0
- package/src/components/key/index.ts +12 -0
- package/src/components/key/key.component.ts +47 -0
- package/src/components/key/key.scss +38 -0
- package/src/components/key-container/index.ts +12 -0
- package/src/components/key-container/key-container.component.ts +142 -0
- package/src/components/key-container/key-container.scss +33 -0
- package/src/components/menu-item/menu-item.component.ts +20 -0
- package/src/components/menu-item/menu-item.scss +69 -2
- package/src/components/navbar/navbar.component.ts +103 -8
- package/src/components/navbar/navbar.scss +6 -1
- package/src/components/opt-group/index.ts +12 -0
- package/src/components/opt-group/opt-group.component.ts +74 -0
- package/src/components/opt-group/opt-group.scss +37 -0
- package/src/components/opt-group/opt-group.test.ts +27 -0
- package/src/components/option/option.component.ts +1 -16
- package/src/components/option/option.scss +4 -0
- package/src/components/panel/panel.component.ts +10 -8
- package/src/components/panel/panel.scss +20 -0
- package/src/components/priority-list/index.ts +12 -0
- package/src/components/priority-list/priority-list.component.ts +611 -0
- package/src/components/priority-list/priority-list.scss +185 -0
- package/src/components/priority-list/priority-list.test.ts +139 -0
- package/src/components/progress-bar/progress-bar.component.ts +22 -16
- package/src/components/radio/radio.scss +10 -3
- package/src/components/select/select.component.ts +812 -72
- package/src/components/select/select.scss +108 -2
- package/src/components/select/select.test.ts +147 -2
- package/src/components/settings-container/settings-container.component.ts +44 -19
- package/src/components/settings-container/settings-container.scss +1 -1
- package/src/components/skeleton/skeleton.component.ts +6 -1
- package/src/components/slideout/slideout.scss +8 -3
- package/src/components/sp/sp.component.ts +3 -1
- package/src/components/sp/sp.scss +19 -0
- package/src/components/stepper/stepper.component.ts +16 -10
- package/src/components/textarea/textarea.scss +0 -4
- package/src/components/tile/tile.component.ts +12 -3
- package/src/components/tile/tile.scss +1 -1
- package/src/components/timer/timer.component.ts +15 -2
- package/src/components/toggle/toggle.component.ts +29 -26
- package/src/components/toggle/toggle.scss +13 -1
- package/src/components/translation-group/index.ts +12 -0
- package/src/components/translation-group/translation-group.component.ts +207 -0
- package/src/components/translation-group/translation-group.scss +8 -0
- package/src/components/translations/translations.component.ts +90 -42
- package/src/components/translations/translations.scss +5 -1
- package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
- package/src/events/events.ts +12 -7
- package/src/events/zn-language-change.ts +7 -0
- package/src/events/zn-purchase.ts +11 -0
- package/src/events/zn-redirect.ts +7 -0
- package/src/events/zn-reorder.ts +7 -0
- package/src/events/zn-search-change.ts +11 -0
- package/src/events/zn-submit.ts +1 -1
- package/src/form-control.scss +4 -0
- package/src/internal/form-navigation.ts +510 -0
- package/src/internal/form.ts +6 -0
- 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
|
|
15
|
+
<zn-file label="Upload Document"></zn-file>
|
|
10
16
|
```
|
|
11
17
|
|
|
12
|
-
|
|
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
|
-
###
|
|
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="
|
|
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
|
-
###
|
|
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
|
|
39
|
+
<zn-file label="Upload Photos" multiple></zn-file>
|
|
24
40
|
```
|
|
25
41
|
|
|
26
|
-
###
|
|
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
|
|
47
|
+
<zn-file label="Upload Documents" multiple clearable></zn-file>
|
|
30
48
|
```
|
|
31
49
|
|
|
32
|
-
###
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
66
|
+
### Basic List Filtering
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Filter a simple list of items by adding the `data-filter` attribute.
|
|
69
69
|
|
|
70
|
-
|
|
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
|
-
|
|
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
|
+
```
|