@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
@@ -7,6 +7,10 @@ unusedProperties: |
7
7
  - Sizes `small`, `large`
8
8
  ---
9
9
 
10
+ ```html:preview
11
+ <zn-textarea label="Comments" placeholder="Enter your feedback here..."></zn-textarea>
12
+ ```
13
+
10
14
  ## Examples
11
15
 
12
16
  ### Basic Textarea with Label
@@ -22,13 +26,30 @@ This component works with standard `<form>` elements. Please refer to the sectio
22
26
  on [form controls](/getting-started/form-controls) to learn more about form submission and client-side validation.
23
27
  :::
24
28
 
29
+ ### With Value
30
+
31
+ Set the initial value using the `value` attribute.
32
+
33
+ ```html:preview
34
+ <zn-textarea label="Description" value="This is some initial text content."></zn-textarea>
35
+ ```
36
+
37
+ You can also set the value using text content inside the element.
38
+
39
+ ```html:preview
40
+ <zn-textarea label="Notes">
41
+ This is the initial content set via text content.
42
+ It can span multiple lines.
43
+ </zn-textarea>
44
+ ```
45
+
25
46
  ### Help Text
26
47
 
27
48
  Add descriptive help text to a textarea with the `help-text` attribute. For help text that contains HTML, use the
28
49
  `help-text` slot instead.
29
50
 
30
51
  ```html:preview
31
- <zn-textarea transparent label="Month in review" help-text="Tell us the highlights. Be sure to include details about any financial performance anomalies."> </zn-textarea>
52
+ <zn-textarea label="Month in review" help-text="Tell us the highlights. Be sure to include details about any financial performance anomalies."></zn-textarea>
32
53
  <br />
33
54
  <zn-textarea label="Month in review">
34
55
  <div slot="help-text">Tell us the highlights. Be sure to include details about any financial performance <strong>anomalies</strong>.</div>
@@ -65,10 +86,18 @@ without errors.
65
86
  <zn-textarea label="Month in review" help-text="Tell us the highlights. Be sure to include details about any financial performance anomalies." context-note="Data synced 1 hr ago"></zn-textarea>
66
87
  ```
67
88
 
89
+ ### Placeholders
90
+
91
+ Use the `placeholder` attribute to add a placeholder.
92
+
93
+ ```html:preview
94
+ <zn-textarea label="Feedback" placeholder="Type something"></zn-textarea>
95
+ ```
96
+
68
97
  ### Rows
69
98
 
70
99
  Use the `rows` attribute to change the number of text rows that the textarea shows before the text starts to overflow
71
- and the textarea scrolls.
100
+ and the textarea scrolls. The default is 4 rows.
72
101
 
73
102
  ```html:preview
74
103
  <zn-textarea label="Textarea with 2 rows" rows="2"></zn-textarea>
@@ -78,35 +107,39 @@ and the textarea scrolls.
78
107
  <zn-textarea label="Textarea with 6 rows" rows="6"></zn-textarea>
79
108
  ```
80
109
 
81
- ### Placeholders
110
+ ### Sizes
82
111
 
83
- Use the `placeholder` attribute to add a placeholder.
112
+ Use the `size` attribute to change a textarea's size. Available sizes are `small`, `medium` (default), and `large`.
84
113
 
85
114
  ```html:preview
86
- <zn-textarea placeholder="Type something"></zn-textarea>
115
+ <zn-textarea label="Small textarea" size="small"></zn-textarea>
116
+ <br />
117
+ <zn-textarea label="Medium textarea" size="medium"></zn-textarea>
118
+ <br />
119
+ <zn-textarea label="Large textarea" size="large"></zn-textarea>
87
120
  ```
88
121
 
89
- ### Sizes
122
+ ### Resize Options
90
123
 
91
- Use the `size` attribute to change a textarea's size.
124
+ Control how the textarea can be resized using the `resize` attribute. Options are `vertical` (default), `none`, and `auto`.
125
+
126
+ #### Vertical Resize (Default)
127
+
128
+ By default, textareas can be resized vertically by the user.
92
129
 
93
130
  ```html:preview
94
- <zn-textarea placeholder="Small" size="small"></zn-textarea>
95
- <br />
96
- <zn-textarea placeholder="Medium" size="medium"></zn-textarea>
97
- <br />
98
- <zn-textarea placeholder="Large" size="large"></zn-textarea>
131
+ <zn-textarea label="Vertically resizable" resize="vertical"></zn-textarea>
99
132
  ```
100
133
 
101
- ### Prevent Resizing
134
+ #### Prevent Resizing
102
135
 
103
- By default, textareas can be resized vertically by the user. To prevent resizing, set the `resize` attribute to `none`.
136
+ To prevent resizing, set the `resize` attribute to `none`.
104
137
 
105
138
  ```html:preview
106
- <zn-textarea label="Textarea with no resizing" resize="none"></zn-textarea>
139
+ <zn-textarea label="No resizing allowed" resize="none"></zn-textarea>
107
140
  ```
108
141
 
109
- ### Expand with Content
142
+ #### Auto-Resize
110
143
 
111
144
  Textareas will automatically resize to expand to fit their content when `resize` is set to `auto`.
112
145
 
@@ -116,5 +149,370 @@ Textareas will automatically resize to expand to fit their content when `resize`
116
149
  :::
117
150
 
118
151
  ```html:preview
119
- <zn-textarea label="Expanding textarea" resize="auto" value="Someones sitting in the shade today because someone planted a tree a long time ago. ... Keep typing to see the textarea expand..." rows="2"></zn-textarea>
152
+ <zn-textarea label="Expanding textarea" resize="auto" value="Someone's sitting in the shade today because someone planted a tree a long time ago..." rows="2"></zn-textarea>
153
+ ```
154
+
155
+ Try typing multiple lines in the textarea above to see it automatically expand.
156
+
157
+ ### Character Limits
158
+
159
+ Use the `maxlength` attribute to limit the number of characters that can be entered. The `minlength` attribute sets a minimum character requirement.
160
+
161
+ ```html:preview
162
+ <zn-textarea label="Tweet" maxlength="280" help-text="Maximum 280 characters"></zn-textarea>
163
+ <br />
164
+ <zn-textarea label="Review" minlength="20" maxlength="500" help-text="Must be between 20 and 500 characters"></zn-textarea>
165
+ ```
166
+
167
+ ### Disabled
168
+
169
+ Use the `disabled` attribute to disable a textarea.
170
+
171
+ ```html:preview
172
+ <zn-textarea label="Disabled textarea" disabled value="This textarea cannot be edited"></zn-textarea>
173
+ ```
174
+
175
+ ### Readonly
176
+
177
+ Use the `readonly` attribute to make a textarea read-only. Unlike disabled textareas, readonly textareas can still receive focus and their values are submitted with forms.
178
+
179
+ ```html:preview
180
+ <zn-textarea label="Readonly textarea" readonly value="This textarea is read-only but can be focused"></zn-textarea>
181
+ ```
182
+
183
+ ### Required
184
+
185
+ Use the `required` attribute to make a textarea required for form submission.
186
+
187
+ ```html:preview
188
+ <form class="textarea-required-form">
189
+ <zn-textarea name="feedback" label="Feedback" required help-text="This field is required"></zn-textarea>
190
+ <br />
191
+ <zn-button type="submit" color="success">Submit</zn-button>
192
+ </form>
193
+
194
+ <script type="module">
195
+ const form = document.querySelector('.textarea-required-form');
196
+
197
+ await customElements.whenDefined('zn-button');
198
+ await customElements.whenDefined('zn-textarea');
199
+
200
+ form.addEventListener('submit', (e) => {
201
+ e.preventDefault();
202
+ alert('Form submitted successfully!');
203
+ });
204
+ </script>
205
+ ```
206
+
207
+ ### Transparent Style
208
+
209
+ Use the `transparent` attribute to create a transparent textarea without a visible border.
210
+
211
+ ```html:preview
212
+ <zn-textarea label="Transparent textarea" transparent placeholder="Type here..."></zn-textarea>
213
+ ```
214
+
215
+ ### Flush Style
216
+
217
+ Use the `flush` attribute to remove padding from the textarea container.
218
+
219
+ ```html:preview
220
+ <zn-textarea label="Flush textarea" flush></zn-textarea>
221
+ ```
222
+
223
+ ### Text Input Options
224
+
225
+ #### Autocapitalize
226
+
227
+ Control automatic capitalization using the `autocapitalize` attribute.
228
+
229
+ ```html:preview
230
+ <zn-textarea label="Sentences" autocapitalize="sentences" placeholder="First letter of each sentence capitalized"></zn-textarea>
231
+ <br />
232
+ <zn-textarea label="Words" autocapitalize="words" placeholder="First letter of each word capitalized"></zn-textarea>
233
+ <br />
234
+ <zn-textarea label="Characters" autocapitalize="characters" placeholder="All letters capitalized"></zn-textarea>
235
+ ```
236
+
237
+ #### Spellcheck
238
+
239
+ Control spell checking with the `spellcheck` attribute. It's enabled by default.
240
+
241
+ ```html:preview
242
+ <zn-textarea label="Spellcheck enabled (default)" spellcheck="true" value="This haz a speling eror"></zn-textarea>
243
+ <br />
244
+ <zn-textarea label="Spellcheck disabled" spellcheck="false" value="This haz a speling eror"></zn-textarea>
245
+ ```
246
+
247
+ #### Autocorrect
248
+
249
+ Use the `autocorrect` attribute to control autocorrection on mobile devices.
250
+
251
+ ```html:preview
252
+ <zn-textarea label="With autocorrect" autocorrect="on"></zn-textarea>
253
+ <br />
254
+ <zn-textarea label="Without autocorrect" autocorrect="off"></zn-textarea>
255
+ ```
256
+
257
+ #### Input Mode
258
+
259
+ Use the `inputmode` attribute to control the type of virtual keyboard displayed on mobile devices.
260
+
261
+ ```html:preview
262
+ <zn-textarea label="Email" inputmode="email" placeholder="user@example.com"></zn-textarea>
263
+ <br />
264
+ <zn-textarea label="URL" inputmode="url" placeholder="https://example.com"></zn-textarea>
265
+ <br />
266
+ <zn-textarea label="Numeric" inputmode="numeric" placeholder="123456"></zn-textarea>
267
+ ```
268
+
269
+ #### Enter Key Hint
270
+
271
+ Use the `enterkeyhint` attribute to customize the label or icon of the Enter key on virtual keyboards.
272
+
273
+ ```html:preview
274
+ <zn-textarea label="Search" enterkeyhint="search"></zn-textarea>
275
+ <br />
276
+ <zn-textarea label="Message" enterkeyhint="send"></zn-textarea>
277
+ <br />
278
+ <zn-textarea label="Step" enterkeyhint="next"></zn-textarea>
279
+ ```
280
+
281
+ ### Form Integration
282
+
283
+ Textareas can be used in forms with various form-related attributes.
284
+
285
+ ```html:preview
286
+ <form class="textarea-form">
287
+ <zn-textarea name="comments" label="Comments" required minlength="10"></zn-textarea>
288
+ <br />
289
+ <zn-button type="submit" color="success">Submit</zn-button>
290
+ <zn-button type="reset" color="secondary">Reset</zn-button>
291
+ </form>
292
+
293
+ <script type="module">
294
+ const form = document.querySelector('.textarea-form');
295
+
296
+ await customElements.whenDefined('zn-button');
297
+ await customElements.whenDefined('zn-textarea');
298
+
299
+ form.addEventListener('submit', (e) => {
300
+ e.preventDefault();
301
+ const formData = new FormData(form);
302
+ const data = Object.fromEntries(formData);
303
+ alert('Form submitted!\n\n' + JSON.stringify(data, null, 2));
304
+ });
305
+ </script>
306
+ ```
307
+
308
+ ### Custom Validation
309
+
310
+ Use the `setCustomValidity()` method to set custom validation messages.
311
+
312
+ ```html:preview
313
+ <form class="textarea-validation-form">
314
+ <zn-textarea id="validation-textarea" name="review" label="Product Review" help-text="Must contain the word 'product'"></zn-textarea>
315
+ <br />
316
+ <zn-button type="submit" color="success">Submit</zn-button>
317
+ </form>
318
+
319
+ <script type="module">
320
+ const form = document.querySelector('.textarea-validation-form');
321
+ const textarea = document.getElementById('validation-textarea');
322
+
323
+ await customElements.whenDefined('zn-button');
324
+ await customElements.whenDefined('zn-textarea');
325
+
326
+ textarea.addEventListener('zn-input', () => {
327
+ if (textarea.value && !textarea.value.toLowerCase().includes('product')) {
328
+ textarea.setCustomValidity('Your review must mention the product');
329
+ } else {
330
+ textarea.setCustomValidity('');
331
+ }
332
+ });
333
+
334
+ form.addEventListener('submit', (e) => {
335
+ e.preventDefault();
336
+ if (form.checkValidity()) {
337
+ alert('Form submitted successfully!');
338
+ }
339
+ });
340
+ </script>
341
+ ```
342
+
343
+ ### Character Count Display
344
+
345
+ Create a character counter using the `zn-input` event and `maxlength` attribute.
346
+
347
+ ```html:preview
348
+ <div class="textarea-counter-container">
349
+ <zn-textarea
350
+ id="counter-textarea"
351
+ label="Description"
352
+ maxlength="200"
353
+ help-text="Maximum 200 characters"
354
+ ></zn-textarea>
355
+ <div id="char-count" style="text-align: right; margin-top: 0.5rem; font-size: 0.875rem; color: var(--zn-color-neutral-600);">
356
+ 0 / 200
357
+ </div>
358
+ </div>
359
+
360
+ <script type="module">
361
+ const textarea = document.getElementById('counter-textarea');
362
+ const counter = document.getElementById('char-count');
363
+
364
+ await customElements.whenDefined('zn-textarea');
365
+
366
+ textarea.addEventListener('zn-input', () => {
367
+ const length = textarea.value.length;
368
+ const max = textarea.maxlength;
369
+ counter.textContent = `${length} / ${max}`;
370
+
371
+ if (length > max * 0.9) {
372
+ counter.style.color = 'var(--zn-color-error-600)';
373
+ } else if (length > max * 0.75) {
374
+ counter.style.color = 'var(--zn-color-warning-600)';
375
+ } else {
376
+ counter.style.color = 'var(--zn-color-neutral-600)';
377
+ }
378
+ });
379
+ </script>
380
+ ```
381
+
382
+ ### Programmatic Control
383
+
384
+ Use methods to programmatically control the textarea.
385
+
386
+ ```html:preview
387
+ <zn-textarea id="control-textarea" label="Controlled Textarea" value="Initial text content"></zn-textarea>
388
+ <br />
389
+ <zn-button id="focus-btn">Focus</zn-button>
390
+ <zn-button id="blur-btn">Blur</zn-button>
391
+ <zn-button id="select-btn">Select All</zn-button>
392
+ <zn-button id="clear-btn" color="error">Clear</zn-button>
393
+
394
+ <script type="module">
395
+ const textarea = document.getElementById('control-textarea');
396
+ const focusBtn = document.getElementById('focus-btn');
397
+ const blurBtn = document.getElementById('blur-btn');
398
+ const selectBtn = document.getElementById('select-btn');
399
+ const clearBtn = document.getElementById('clear-btn');
400
+
401
+ await customElements.whenDefined('zn-button');
402
+ await customElements.whenDefined('zn-textarea');
403
+
404
+ focusBtn.addEventListener('click', () => textarea.focus());
405
+ blurBtn.addEventListener('click', () => textarea.blur());
406
+ selectBtn.addEventListener('click', () => textarea.select());
407
+ clearBtn.addEventListener('click', () => textarea.value = '');
408
+ </script>
409
+ ```
410
+
411
+ ### Selection and Range Methods
412
+
413
+ Use `setSelectionRange()` and `setRangeText()` methods to work with text selections.
414
+
415
+ ```html:preview
416
+ <zn-textarea id="selection-textarea" label="Text Selection Demo" value="The quick brown fox jumps over the lazy dog"></zn-textarea>
417
+ <br />
418
+ <zn-button id="select-word-btn">Select "brown"</zn-button>
419
+ <zn-button id="replace-word-btn">Replace "fox" with "cat"</zn-button>
420
+ <zn-button id="insert-text-btn">Insert at cursor</zn-button>
421
+
422
+ <script type="module">
423
+ const textarea = document.getElementById('selection-textarea');
424
+ const selectWordBtn = document.getElementById('select-word-btn');
425
+ const replaceWordBtn = document.getElementById('replace-word-btn');
426
+ const insertTextBtn = document.getElementById('insert-text-btn');
427
+
428
+ await customElements.whenDefined('zn-button');
429
+ await customElements.whenDefined('zn-textarea');
430
+
431
+ selectWordBtn.addEventListener('click', () => {
432
+ const text = textarea.value;
433
+ const start = text.indexOf('brown');
434
+ const end = start + 5;
435
+ textarea.setSelectionRange(start, end);
436
+ textarea.focus();
437
+ });
438
+
439
+ replaceWordBtn.addEventListener('click', () => {
440
+ const text = textarea.value;
441
+ const start = text.indexOf('fox');
442
+ const end = start + 3;
443
+ textarea.setRangeText('cat', start, end, 'select');
444
+ });
445
+
446
+ insertTextBtn.addEventListener('click', () => {
447
+ textarea.setRangeText(' [INSERTED]');
448
+ textarea.focus();
449
+ });
450
+ </script>
451
+ ```
452
+
453
+ ### Events
454
+
455
+ Listen to textarea events to respond to user interactions.
456
+
457
+ ```html:preview
458
+ <zn-textarea id="event-textarea" label="Event Demo" placeholder="Type or interact with this textarea"></zn-textarea>
459
+ <div id="event-log" style="margin-top: 1rem; padding: 1rem; background: var(--zn-color-neutral-100); border-radius: 4px; font-family: monospace; font-size: 0.875rem; max-height: 200px; overflow-y: auto;">
460
+ Events will appear here...
461
+ </div>
462
+
463
+ <script type="module">
464
+ const textarea = document.getElementById('event-textarea');
465
+ const eventLog = document.getElementById('event-log');
466
+
467
+ await customElements.whenDefined('zn-textarea');
468
+
469
+ function logEvent(eventName, detail = '') {
470
+ const time = new Date().toLocaleTimeString();
471
+ const message = `[${time}] ${eventName}${detail ? ': ' + detail : ''}`;
472
+ eventLog.innerHTML = message + '<br>' + eventLog.innerHTML;
473
+ }
474
+
475
+ textarea.addEventListener('zn-focus', () => logEvent('zn-focus'));
476
+ textarea.addEventListener('zn-blur', () => logEvent('zn-blur'));
477
+ textarea.addEventListener('zn-input', (e) => logEvent('zn-input', `value="${e.target.value}"`));
478
+ textarea.addEventListener('zn-change', (e) => logEvent('zn-change', `value="${e.target.value}"`));
479
+ textarea.addEventListener('zn-invalid', () => logEvent('zn-invalid'));
480
+ </script>
481
+ ```
482
+
483
+ ### Customizing Label Position
484
+
485
+ Use [CSS parts](#css-parts) to customize the way form controls are drawn. This example uses CSS grid to position the
486
+ label to the left of the control.
487
+
488
+ ```html:preview
489
+ <zn-textarea class="label-on-left" label="Bio" help-text="Tell us about yourself"></zn-textarea>
490
+ <zn-textarea class="label-on-left" label="Notes" help-text="Additional notes"></zn-textarea>
491
+
492
+ <style>
493
+ .label-on-left {
494
+ --label-width: 3.75rem;
495
+ --gap-width: 1rem;
496
+ }
497
+
498
+ .label-on-left + .label-on-left {
499
+ margin-top: var(--zn-spacing-medium);
500
+ }
501
+
502
+ .label-on-left::part(form-control) {
503
+ display: grid;
504
+ grid: auto / var(--label-width) 1fr;
505
+ gap: var(--zn-spacing-3x-small) var(--gap-width);
506
+ align-items: start;
507
+ }
508
+
509
+ .label-on-left::part(form-control-label) {
510
+ text-align: right;
511
+ padding-top: var(--zn-spacing-small);
512
+ }
513
+
514
+ .label-on-left::part(form-control-help-text) {
515
+ grid-column-start: 2;
516
+ }
517
+ </style>
120
518
  ```