@kubex/zinc 1.0.25 → 1.0.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/.claude/project.md +556 -0
  2. package/.github/workflows/js_build_and_deploy.yaml +9 -10
  3. package/dist/custom-elements.json +13575 -8856
  4. package/dist/vscode.html-custom-data.json +583 -48
  5. package/dist/web-types.json +1441 -181
  6. package/dist/zn.d.ts +1645 -660
  7. package/dist/zn.min.css +1 -1
  8. package/dist/zn.min.js +1412 -893
  9. package/docs/_utilities/code-previews.cjs +10 -1
  10. package/docs/assets/scripts/docs.js +42 -18
  11. package/docs/data/data-table.json +229 -66
  12. package/docs/data/empty.json +6 -0
  13. package/docs/data/products-table.json +41 -193
  14. package/docs/pages/components/action-bar.md +121 -6
  15. package/docs/pages/components/alert.md +118 -15
  16. package/docs/pages/components/animated-button.md +299 -0
  17. package/docs/pages/components/audio-select.md +534 -0
  18. package/docs/pages/components/bulk-actions.md +79 -5
  19. package/docs/pages/components/button-group.md +235 -27
  20. package/docs/pages/components/button.md +139 -1
  21. package/docs/pages/components/chart.md +365 -9
  22. package/docs/pages/components/checkbox.md +387 -58
  23. package/docs/pages/components/chip.md +253 -33
  24. package/docs/pages/components/collapsible.md +393 -46
  25. package/docs/pages/components/cols.md +152 -30
  26. package/docs/pages/components/confirm.md +182 -16
  27. package/docs/pages/components/copy-button.md +169 -6
  28. package/docs/pages/components/data-select.md +194 -15
  29. package/docs/pages/components/data-table-filter.md +96 -5
  30. package/docs/pages/components/data-table-search.md +451 -0
  31. package/docs/pages/components/data-table-sort.md +66 -5
  32. package/docs/pages/components/data-table.md +727 -66
  33. package/docs/pages/components/datepicker.md +402 -7
  34. package/docs/pages/components/defined-label.md +120 -5
  35. package/docs/pages/components/dialog.md +339 -59
  36. package/docs/pages/components/dropdown.md +366 -11
  37. package/docs/pages/components/editor.md +604 -7
  38. package/docs/pages/components/empty-state.md +315 -16
  39. package/docs/pages/components/expanding-action.md +212 -28
  40. package/docs/pages/components/file.md +421 -12
  41. package/docs/pages/components/filter-container.md +158 -5
  42. package/docs/pages/components/filter-wrapper.md +167 -6
  43. package/docs/pages/components/form-group.md +383 -6
  44. package/docs/pages/components/hover-container.md +237 -6
  45. package/docs/pages/components/icon-picker.md +121 -0
  46. package/docs/pages/components/icon.md +454 -48
  47. package/docs/pages/components/inline-edit.md +787 -19
  48. package/docs/pages/components/input-group.md +207 -13
  49. package/docs/pages/components/input.md +194 -0
  50. package/docs/pages/components/item.md +18 -0
  51. package/docs/pages/components/key-container.md +115 -0
  52. package/docs/pages/components/key.md +101 -0
  53. package/docs/pages/components/menu.md +512 -6
  54. package/docs/pages/components/note.md +239 -36
  55. package/docs/pages/components/opt-group.md +107 -0
  56. package/docs/pages/components/pagination.md +332 -6
  57. package/docs/pages/components/pane.md +222 -6
  58. package/docs/pages/components/panel.md +213 -26
  59. package/docs/pages/components/popup.md +1354 -6
  60. package/docs/pages/components/priority-list.md +233 -0
  61. package/docs/pages/components/progress-bar.md +387 -6
  62. package/docs/pages/components/radio-group.md +242 -5
  63. package/docs/pages/components/radio.md +474 -6
  64. package/docs/pages/components/rating.md +331 -7
  65. package/docs/pages/components/reveal.md +524 -6
  66. package/docs/pages/components/scroll-container.md +552 -6
  67. package/docs/pages/components/select.md +762 -160
  68. package/docs/pages/components/skeleton.md +473 -30
  69. package/docs/pages/components/slideout.md +261 -5
  70. package/docs/pages/components/sp.md +99 -41
  71. package/docs/pages/components/split-button.md +347 -9
  72. package/docs/pages/components/split-pane.md +445 -6
  73. package/docs/pages/components/stat.md +549 -9
  74. package/docs/pages/components/status-indicator.md +230 -1
  75. package/docs/pages/components/stepper.md +563 -6
  76. package/docs/pages/components/tabs.md +439 -13
  77. package/docs/pages/components/textarea.md +415 -17
  78. package/docs/pages/components/tile.md +385 -26
  79. package/docs/pages/components/toggle.md +424 -6
  80. package/docs/pages/components/tooltip.md +367 -0
  81. package/docs/pages/components/translation-group.md +210 -0
  82. package/docs/pages/components/translations.md +319 -19
  83. package/docs/pages/components/vertical-stepper.md +401 -8
  84. package/docs/pages/components/well.md +300 -3
  85. package/docs/pages/getting-started/form-controls.md +162 -0
  86. package/docs/pages/index.md +116 -15
  87. package/package.json +5 -6
  88. package/scss/_global-spacing.scss +4 -0
  89. package/scss/_root.scss +2 -2
  90. package/scss/boot.scss +19 -0
  91. package/scss/shared/layout.scss +5 -0
  92. package/scss/themes/_light.scss +3 -3
  93. package/src/components/alert/alert.scss +1 -0
  94. package/src/components/animated-button/README.md +306 -0
  95. package/src/components/animated-button/animated-button.component.ts +229 -0
  96. package/src/components/animated-button/animated-button.scss +228 -0
  97. package/src/components/animated-button/animated-button.test.ts +143 -0
  98. package/src/components/animated-button/index.ts +12 -0
  99. package/src/components/button/button.component.ts +5 -0
  100. package/src/components/button-group/button-group.component.ts +25 -13
  101. package/src/components/button-group/button-group.scss +6 -0
  102. package/src/components/checkbox/checkbox.component.ts +4 -0
  103. package/src/components/checkbox/checkbox.scss +7 -4
  104. package/src/components/checkbox-group/checkbox-group.scss +7 -0
  105. package/src/components/chip/chip.component.ts +7 -2
  106. package/src/components/chip/chip.scss +16 -2
  107. package/src/components/collapsible/collapsible.component.ts +27 -20
  108. package/src/components/cols/cols.component.ts +14 -2
  109. package/src/components/cols/cols.scss +6 -12
  110. package/src/components/confirm/confirm.component.ts +7 -0
  111. package/src/components/copy-button/copy-button.component.ts +12 -11
  112. package/src/components/data-select/data-select.component.ts +215 -44
  113. package/src/components/data-select/data-select.scss +66 -6
  114. package/src/components/data-select/providers/currency-data-provider.ts +20 -6
  115. package/src/components/data-select/providers/provider.ts +1 -0
  116. package/src/components/data-select/providers/us-state-data-provider.ts +68 -0
  117. package/src/components/data-table/data-table.component.ts +81 -22
  118. package/src/components/data-table-search/data-table-search.component.ts +184 -0
  119. package/src/components/data-table-search/data-table-search.scss +17 -0
  120. package/src/components/data-table-search/data-table-search.test.ts +11 -0
  121. package/src/components/data-table-search/index.ts +12 -0
  122. package/src/components/datepicker/datepicker.component.ts +347 -13
  123. package/src/components/dialog/dialog.component.ts +1 -1
  124. package/src/components/empty-state/empty-state.scss +6 -1
  125. package/src/components/header/header.scss +3 -3
  126. package/src/components/icon/icon.component.ts +23 -1
  127. package/src/components/icon/icon.scss +23 -0
  128. package/src/components/icon-picker/brand-icons.ts +24 -0
  129. package/src/components/icon-picker/icon-picker.component.ts +407 -0
  130. package/src/components/icon-picker/icon-picker.scss +205 -0
  131. package/src/components/icon-picker/index.ts +12 -0
  132. package/src/components/icon-picker/line-icons.ts +612 -0
  133. package/src/components/icon-picker/material-icons.ts +14543 -0
  134. package/src/components/inline-edit/inline-edit.component.ts +190 -46
  135. package/src/components/inline-edit/inline-edit.scss +29 -0
  136. package/src/components/inline-edit/inline-edit.test.ts +314 -1
  137. package/src/components/input/input.component.ts +324 -5
  138. package/src/components/input/input.scss +87 -0
  139. package/src/components/input-group/input-group.component.ts +28 -7
  140. package/src/components/input-group/input-group.scss +48 -10
  141. package/src/components/item/item.component.ts +24 -3
  142. package/src/components/item/item.scss +18 -0
  143. package/src/components/key/index.ts +12 -0
  144. package/src/components/key/key.component.ts +47 -0
  145. package/src/components/key/key.scss +38 -0
  146. package/src/components/key-container/index.ts +12 -0
  147. package/src/components/key-container/key-container.component.ts +142 -0
  148. package/src/components/key-container/key-container.scss +33 -0
  149. package/src/components/menu-item/menu-item.component.ts +20 -0
  150. package/src/components/menu-item/menu-item.scss +69 -2
  151. package/src/components/navbar/navbar.component.ts +103 -11
  152. package/src/components/navbar/navbar.scss +6 -1
  153. package/src/components/opt-group/index.ts +12 -0
  154. package/src/components/opt-group/opt-group.component.ts +74 -0
  155. package/src/components/opt-group/opt-group.scss +37 -0
  156. package/src/components/opt-group/opt-group.test.ts +27 -0
  157. package/src/components/option/option.component.ts +1 -16
  158. package/src/components/option/option.scss +4 -0
  159. package/src/components/panel/panel.component.ts +10 -8
  160. package/src/components/panel/panel.scss +20 -0
  161. package/src/components/priority-list/index.ts +12 -0
  162. package/src/components/priority-list/priority-list.component.ts +611 -0
  163. package/src/components/priority-list/priority-list.scss +185 -0
  164. package/src/components/priority-list/priority-list.test.ts +139 -0
  165. package/src/components/progress-bar/progress-bar.component.ts +22 -16
  166. package/src/components/radio/radio.scss +10 -3
  167. package/src/components/select/select.component.ts +812 -72
  168. package/src/components/select/select.scss +108 -2
  169. package/src/components/select/select.test.ts +147 -2
  170. package/src/components/settings-container/settings-container.component.ts +44 -19
  171. package/src/components/settings-container/settings-container.scss +1 -1
  172. package/src/components/skeleton/skeleton.component.ts +6 -1
  173. package/src/components/slideout/slideout.scss +8 -3
  174. package/src/components/sp/sp.component.ts +3 -1
  175. package/src/components/sp/sp.scss +19 -0
  176. package/src/components/stepper/stepper.component.ts +16 -10
  177. package/src/components/textarea/textarea.scss +0 -4
  178. package/src/components/tile/tile.component.ts +12 -3
  179. package/src/components/tile/tile.scss +1 -1
  180. package/src/components/timer/timer.component.ts +15 -2
  181. package/src/components/toggle/toggle.component.ts +29 -26
  182. package/src/components/toggle/toggle.scss +13 -1
  183. package/src/components/translation-group/index.ts +12 -0
  184. package/src/components/translation-group/translation-group.component.ts +207 -0
  185. package/src/components/translation-group/translation-group.scss +8 -0
  186. package/src/components/translations/translations.component.ts +90 -44
  187. package/src/components/translations/translations.scss +4 -0
  188. package/src/components/vertical-stepper/vertical-stepper.component.ts +14 -9
  189. package/src/events/events.ts +12 -7
  190. package/src/events/zn-language-change.ts +7 -0
  191. package/src/events/zn-purchase.ts +11 -0
  192. package/src/events/zn-redirect.ts +7 -0
  193. package/src/events/zn-reorder.ts +7 -0
  194. package/src/events/zn-search-change.ts +11 -0
  195. package/src/events/zn-submit.ts +1 -1
  196. package/src/form-control.scss +4 -0
  197. package/src/internal/form-navigation.ts +510 -0
  198. package/src/internal/form.ts +6 -0
  199. package/src/zinc.ts +91 -83
@@ -1,20 +1,488 @@
1
1
  ---
2
2
  meta:
3
3
  title: Radio
4
- description:
4
+ description: Radios allow the user to select a single option from a group.
5
5
  layout: component
6
6
  ---
7
7
 
8
8
  ```html:preview
9
- <zn-radio></zn-radio>
9
+ <zn-radio>Radio option</zn-radio>
10
10
  ```
11
11
 
12
+ :::tip
13
+ This component works with standard `<form>` elements. Please refer to the section
14
+ on [form controls](/getting-started/form-controls) to learn more about form submission and client-side validation.
15
+ :::
16
+
12
17
  ## Examples
13
18
 
14
- ### First Example
19
+ ### Basic Radio
20
+
21
+ A basic radio button with a label.
22
+
23
+ ```html:preview
24
+ <zn-radio>Default option</zn-radio>
25
+ ```
26
+
27
+ ### Checked
28
+
29
+ Use the `checked` attribute to activate the radio by default.
30
+
31
+ ```html:preview
32
+ <zn-radio checked>Selected option</zn-radio>
33
+ ```
34
+
35
+ ### Disabled
36
+
37
+ Use the `disabled` attribute to disable the radio.
38
+
39
+ ```html:preview
40
+ <zn-radio disabled>Disabled radio</zn-radio>
41
+ <br />
42
+ <zn-radio disabled checked>Disabled and checked</zn-radio>
43
+ ```
44
+
45
+ ### Sizes
46
+
47
+ Use the `size` attribute to change the radio size. Available sizes are `small`, `medium` (default), and `large`.
48
+
49
+ ```html:preview
50
+ <zn-radio size="small">Small</zn-radio>
51
+ <br />
52
+ <zn-radio size="medium">Medium</zn-radio>
53
+ <br />
54
+ <zn-radio size="large">Large</zn-radio>
55
+ ```
56
+
57
+ ### Radio Groups
58
+
59
+ Radio buttons are typically used in groups where only one option can be selected. Radios with the same `name` will be mutually exclusive.
60
+
61
+ ```html:preview
62
+ <div id="basic-radio-group">
63
+ <zn-radio name="color" value="red">Red</zn-radio>
64
+ <br />
65
+ <zn-radio name="color" value="green">Green</zn-radio>
66
+ <br />
67
+ <zn-radio name="color" value="blue" checked>Blue</zn-radio>
68
+ </div>
69
+ ```
70
+
71
+ ### Description
72
+
73
+ Add descriptive help text to radios with the `description` attribute. For descriptions that contain HTML, use the `description` slot instead.
74
+
75
+ ```html:preview
76
+ <zn-radio name="plan" description="Best for individuals and small teams">Basic Plan</zn-radio>
77
+ <br />
78
+ <zn-radio name="plan" description="Includes advanced features and priority support">Pro Plan</zn-radio>
79
+ <br />
80
+ <zn-radio name="plan">
81
+ Enterprise Plan
82
+ <div slot="description">
83
+ Custom pricing with <strong>dedicated support</strong> and enterprise features.
84
+ </div>
85
+ </zn-radio>
86
+ ```
87
+
88
+ ### Label and Label Tooltip
89
+
90
+ Use the `label` attribute to add a form control label above the radio group. Use `label-tooltip` to provide additional context.
91
+
92
+ ```html:preview
93
+ <zn-radio label="Notification Preferences" label-tooltip="Choose how you want to be notified">
94
+ Email notifications
95
+ </zn-radio>
96
+ <br />
97
+ <zn-radio label="Notification Preferences" label-tooltip="Choose how you want to be notified">
98
+ SMS notifications
99
+ </zn-radio>
100
+ ```
101
+
102
+ ### Contained Style
103
+
104
+ Add the `contained` attribute to draw a card-like container around a radio. This style is useful for giving more emphasis to radio options.
105
+
106
+ ```html:preview
107
+ <zn-radio name="payment" value="credit" description="Pay with Visa, Mastercard, or Amex" contained checked>Credit Card</zn-radio>
108
+ <br />
109
+ <zn-radio name="payment" value="paypal" description="Fast and secure PayPal checkout" contained>PayPal</zn-radio>
110
+ <br />
111
+ <zn-radio name="payment" value="bank" description="Direct bank transfer (3-5 business days)" contained>Bank Transfer</zn-radio>
112
+ ```
113
+
114
+ ### Horizontal Layout
115
+
116
+ Use the `horizontal` attribute to apply styles relevant to radios in a horizontal layout.
117
+
118
+ ```html:preview
119
+ <div style="display: flex; gap: 1rem;">
120
+ <zn-radio name="size" horizontal>Small</zn-radio>
121
+ <zn-radio name="size" horizontal checked>Medium</zn-radio>
122
+ <zn-radio name="size" horizontal>Large</zn-radio>
123
+ </div>
124
+ ```
125
+
126
+ ### Selected Content
127
+
128
+ Use the `selected-content` slot to display additional content (such as an input field) inside a `contained` radio when it is checked. The slot is unstyled by default. Use `::part(selected-content)` to style the content as needed.
129
+
130
+ :::warning
131
+ **Note:** This feature only works with the `contained` style. The `selected-content` slot cannot be used for radios rendered with `ts_form_for`.
132
+ :::
133
+
134
+ ```html:preview
135
+ <zn-radio name="shipping" value="standard" contained checked>
136
+ Standard Shipping
137
+ <div slot="selected-content">
138
+ <p>Estimated delivery: 5-7 business days</p>
139
+ </div>
140
+ </zn-radio>
141
+ <br />
142
+ <zn-radio name="shipping" value="express" contained>
143
+ Express Shipping
144
+ <div slot="selected-content">
145
+ <p>Estimated delivery: 1-2 business days</p>
146
+ <zn-input style="width: 280px;" label="Delivery instructions" placeholder="e.g., Leave at door"></zn-input>
147
+ </div>
148
+ </zn-radio>
149
+ <style>
150
+ zn-radio::part(selected-content) {
151
+ font-size: 14px;
152
+ font-weight: normal;
153
+ color: #6D7176;
154
+ margin-top: 1rem;
155
+ }
156
+ </style>
157
+ ```
158
+
159
+ ### Form Integration
160
+
161
+ Radios work seamlessly with forms and will be submitted with form data. Only the selected radio's value will be submitted.
162
+
163
+ ```html:preview
164
+ <form id="radio-form">
165
+ <div style="margin-bottom: 1rem;">
166
+ <strong>Choose your plan:</strong>
167
+ <br /><br />
168
+ <zn-radio name="subscription" value="free">Free Plan</zn-radio>
169
+ <br />
170
+ <zn-radio name="subscription" value="pro" checked>Pro Plan - $9.99/mo</zn-radio>
171
+ <br />
172
+ <zn-radio name="subscription" value="enterprise">Enterprise Plan - Contact us</zn-radio>
173
+ </div>
174
+ <zn-button type="submit" color="primary">Submit</zn-button>
175
+ <zn-button type="reset" color="secondary">Reset</zn-button>
176
+ </form>
177
+
178
+ <script type="module">
179
+ const form = document.querySelector('#radio-form');
180
+ form.addEventListener('submit', (event) => {
181
+ event.preventDefault();
182
+ const formData = new FormData(form);
183
+ const data = Object.fromEntries(formData.entries());
184
+ alert('Form submitted: ' + JSON.stringify(data, null, 2));
185
+ });
186
+ </script>
187
+ ```
188
+
189
+ ### Required Validation
190
+
191
+ Use the `required` attribute to make the radio required. The form will not submit unless one of the radios in the group is selected.
192
+
193
+ ```html:preview
194
+ <form id="required-form">
195
+ <strong>Select your preferred contact method:</strong>
196
+ <br /><br />
197
+ <zn-radio name="contact" value="email" required>Email</zn-radio>
198
+ <br />
199
+ <zn-radio name="contact" value="phone" required>Phone</zn-radio>
200
+ <br />
201
+ <zn-radio name="contact" value="mail" required>Mail</zn-radio>
202
+ <br /><br />
203
+ <zn-button type="submit" color="primary">Submit</zn-button>
204
+ </form>
205
+
206
+ <script type="module">
207
+ const form = document.querySelector('#required-form');
208
+ form.addEventListener('submit', (event) => {
209
+ event.preventDefault();
210
+ alert('Form is valid!');
211
+ });
212
+ </script>
213
+ ```
214
+
215
+ ### Custom Validity
216
+
217
+ Use the `setCustomValidity()` method to set a custom validation message. This will prevent the form from submitting and make the browser display the error message you provide. To clear the error, call this function with an empty string.
218
+
219
+ ```html:preview
220
+ <form class="custom-validity">
221
+ <strong>Accept terms:</strong>
222
+ <br /><br />
223
+ <zn-radio name="terms" value="accept">I accept the terms</zn-radio>
224
+ <br />
225
+ <zn-radio name="terms" value="decline">I decline</zn-radio>
226
+ <br /><br />
227
+ <zn-button type="submit" color="primary">Submit</zn-button>
228
+ </form>
229
+ <script type="module">
230
+ const form = document.querySelector('.custom-validity');
231
+ const radios = form.querySelectorAll('zn-radio');
232
+ const errorMessage = 'You must accept the terms to continue';
233
+
234
+ // Set initial validity
235
+ customElements.whenDefined('zn-radio').then(async () => {
236
+ await Promise.all(Array.from(radios).map(r => r.updateComplete));
237
+ radios[0].setCustomValidity(errorMessage);
238
+ });
239
+
240
+ // Update validity on change
241
+ radios.forEach(radio => {
242
+ radio.addEventListener('zn-change', () => {
243
+ if (radio.value === 'accept' && radio.checked) {
244
+ radios.forEach(r => r.setCustomValidity(''));
245
+ } else if (radio.value === 'decline' && radio.checked) {
246
+ radios.forEach(r => r.setCustomValidity(errorMessage));
247
+ }
248
+ });
249
+ });
250
+
251
+ // Wait for controls to be defined before attaching form listeners
252
+ await Promise.all([
253
+ customElements.whenDefined('zn-radio')
254
+ ]).then(() => {
255
+ form.addEventListener('submit', event => {
256
+ event.preventDefault();
257
+ alert('All fields are valid!');
258
+ });
259
+ });
260
+ </script>
261
+ ```
262
+
263
+ ### External Form Association
264
+
265
+ Use the `form` attribute to associate the radio with a form element by ID, even if the radio is not a descendant of the form.
266
+
267
+ ```html:preview
268
+ <form id="external-form">
269
+ <zn-button type="submit" color="primary">Submit External Form</zn-button>
270
+ </form>
271
+
272
+ <br /><br />
273
+
274
+ <strong>Choose an option:</strong>
275
+ <br /><br />
276
+ <zn-radio form="external-form" name="external-option" value="option1" checked>Option 1</zn-radio>
277
+ <br />
278
+ <zn-radio form="external-form" name="external-option" value="option2">Option 2</zn-radio>
279
+
280
+ <script type="module">
281
+ const form = document.querySelector('#external-form');
282
+ form.addEventListener('submit', (event) => {
283
+ event.preventDefault();
284
+ const formData = new FormData(form);
285
+ alert('Selected: ' + formData.get('external-option'));
286
+ });
287
+ </script>
288
+ ```
289
+
290
+ ### Events
291
+
292
+ Radios emit several events that you can listen to:
293
+
294
+ - `zn-change` - Emitted when the checked state changes
295
+ - `zn-input` - Emitted when the radio receives input
296
+ - `zn-focus` - Emitted when the radio gains focus
297
+ - `zn-blur` - Emitted when the radio loses focus
298
+ - `zn-invalid` - Emitted when form validation fails
299
+
300
+ ```html:preview
301
+ <div>
302
+ <strong>Try interacting with the radios:</strong>
303
+ <br /><br />
304
+ <zn-radio class="event-radio" name="event-demo" value="option1" checked>Option 1</zn-radio>
305
+ <br />
306
+ <zn-radio class="event-radio" name="event-demo" value="option2">Option 2</zn-radio>
307
+ <br />
308
+ <zn-radio class="event-radio" name="event-demo" value="option3">Option 3</zn-radio>
309
+ <div id="event-output" style="margin-top: 1rem; padding: 1rem; background: #f5f5f5; border-radius: 4px;">
310
+ <strong>Events:</strong>
311
+ <ul id="event-list" style="margin: 0.5rem 0 0 0; padding-left: 1.5rem;"></ul>
312
+ </div>
313
+ </div>
314
+
315
+ <script type="module">
316
+ const radios = document.querySelectorAll('.event-radio');
317
+ const eventList = document.querySelector('#event-list');
318
+
319
+ function logEvent(eventName, detail = '') {
320
+ const li = document.createElement('li');
321
+ li.textContent = `${eventName}${detail ? ': ' + detail : ''}`;
322
+ eventList.insertBefore(li, eventList.firstChild);
15
323
 
16
- TODO
324
+ // Keep only last 5 events
325
+ while (eventList.children.length > 5) {
326
+ eventList.removeChild(eventList.lastChild);
327
+ }
328
+ }
17
329
 
18
- ### Second Example
330
+ radios.forEach(radio => {
331
+ radio.addEventListener('zn-change', (e) => {
332
+ logEvent('zn-change', `${e.target.value} selected`);
333
+ });
19
334
 
20
- TODO
335
+ radio.addEventListener('zn-input', () => {
336
+ logEvent('zn-input');
337
+ });
338
+
339
+ radio.addEventListener('zn-focus', (e) => {
340
+ logEvent('zn-focus', e.target.value);
341
+ });
342
+
343
+ radio.addEventListener('zn-blur', (e) => {
344
+ logEvent('zn-blur', e.target.value);
345
+ });
346
+ });
347
+ </script>
348
+ ```
349
+
350
+ ### Methods
351
+
352
+ Radios provide several methods for programmatic control:
353
+
354
+ - `click()` - Simulates a click on the radio
355
+ - `focus()` - Sets focus on the radio
356
+ - `blur()` - Removes focus from the radio
357
+ - `checkValidity()` - Checks validity without showing a message
358
+ - `reportValidity()` - Checks validity and shows the browser's validation message
359
+ - `setCustomValidity(message)` - Sets a custom validation message
360
+ - `getForm()` - Gets the associated form, if one exists
361
+
362
+ ```html:preview
363
+ <div>
364
+ <zn-radio id="method-radio-1" name="method-demo" checked>Option 1</zn-radio>
365
+ <br />
366
+ <zn-radio id="method-radio-2" name="method-demo">Option 2</zn-radio>
367
+ <br />
368
+ <zn-radio id="method-radio-3" name="method-demo">Option 3</zn-radio>
369
+ <br /><br />
370
+ <zn-button id="click-btn" size="small">Click Option 2</zn-button>
371
+ <zn-button id="focus-btn" size="small" color="info">Focus Option 3</zn-button>
372
+ <zn-button id="blur-btn" size="small" color="secondary">Blur All</zn-button>
373
+ <zn-button id="validate-btn" size="small" color="warning">Check Validity</zn-button>
374
+ </div>
375
+
376
+ <script type="module">
377
+ const radio1 = document.querySelector('#method-radio-1');
378
+ const radio2 = document.querySelector('#method-radio-2');
379
+ const radio3 = document.querySelector('#method-radio-3');
380
+
381
+ document.querySelector('#click-btn').addEventListener('click', () => {
382
+ radio2.click();
383
+ });
384
+
385
+ document.querySelector('#focus-btn').addEventListener('click', () => {
386
+ radio3.focus();
387
+ });
388
+
389
+ document.querySelector('#blur-btn').addEventListener('click', () => {
390
+ document.activeElement?.blur();
391
+ });
392
+
393
+ document.querySelector('#validate-btn').addEventListener('click', () => {
394
+ const isValid = radio1.checkValidity();
395
+ alert('Radio group is ' + (isValid ? 'valid' : 'invalid'));
396
+ });
397
+ </script>
398
+ ```
399
+
400
+ ### Complete Example
401
+
402
+ Here's a comprehensive example showing a radio group with contained style, descriptions, and selected content:
403
+
404
+ ```html:preview
405
+ <form id="complete-example">
406
+ <div style="max-width: 600px;">
407
+ <h3 style="margin-top: 0;">Choose Your Subscription</h3>
408
+
409
+ <zn-radio name="plan" value="starter" description="Perfect for getting started with basic features" contained>
410
+ Starter Plan - Free
411
+ <div slot="selected-content">
412
+ <p>Includes:</p>
413
+ <ul style="margin: 0.5rem 0; padding-left: 1.5rem;">
414
+ <li>Up to 3 users</li>
415
+ <li>5 GB storage</li>
416
+ <li>Community support</li>
417
+ </ul>
418
+ </div>
419
+ </zn-radio>
420
+
421
+ <br />
422
+
423
+ <zn-radio name="plan" value="professional" description="Advanced features for growing teams" contained checked>
424
+ Professional Plan - $29/month
425
+ <div slot="selected-content">
426
+ <p>Includes everything in Starter, plus:</p>
427
+ <ul style="margin: 0.5rem 0; padding-left: 1.5rem;">
428
+ <li>Up to 25 users</li>
429
+ <li>100 GB storage</li>
430
+ <li>Priority email support</li>
431
+ <li>Advanced analytics</li>
432
+ </ul>
433
+ </div>
434
+ </zn-radio>
435
+
436
+ <br />
437
+
438
+ <zn-radio name="plan" value="enterprise" description="Custom solutions for large organizations" contained>
439
+ Enterprise Plan - Custom pricing
440
+ <div slot="selected-content">
441
+ <p>Includes everything in Professional, plus:</p>
442
+ <ul style="margin: 0.5rem 0; padding-left: 1.5rem;">
443
+ <li>Unlimited users</li>
444
+ <li>Unlimited storage</li>
445
+ <li>24/7 phone support</li>
446
+ <li>Custom integrations</li>
447
+ <li>Dedicated account manager</li>
448
+ </ul>
449
+ <zn-input
450
+ style="width: 100%; margin-top: 1rem;"
451
+ label="Company name"
452
+ placeholder="Enter your company name"
453
+ required>
454
+ </zn-input>
455
+ </div>
456
+ </zn-radio>
457
+
458
+ <br /><br />
459
+ <zn-button type="submit" color="success" style="margin-right: 0.5rem;">Continue</zn-button>
460
+ <zn-button type="reset" color="secondary">Reset</zn-button>
461
+ </div>
462
+ </form>
463
+
464
+ <style>
465
+ zn-radio::part(selected-content) {
466
+ font-size: 14px;
467
+ font-weight: normal;
468
+ color: #6D7176;
469
+ margin-top: 1rem;
470
+ }
471
+
472
+ zn-radio::part(selected-content) p {
473
+ margin: 0 0 0.5rem 0;
474
+ font-weight: 500;
475
+ }
476
+ </style>
477
+
478
+ <script type="module">
479
+ const form = document.querySelector('#complete-example');
480
+ form.addEventListener('submit', (event) => {
481
+ event.preventDefault();
482
+ const formData = new FormData(form);
483
+ const plan = formData.get('plan');
484
+ const company = formData.get('company') || 'N/A';
485
+ alert(`Selected: ${plan}\nCompany: ${company}`);
486
+ });
487
+ </script>
488
+ ```