@kubex/zinc 1.1.97 → 1.1.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 (85) hide show
  1. package/AGENTS.md +5 -0
  2. package/CLAUDE.md +5 -0
  3. package/dist/chunks/zn.R2EAU6OS.js +1 -0
  4. package/dist/custom-elements.json +14747 -12528
  5. package/dist/vscode.html-custom-data.json +386 -61
  6. package/dist/web-types.json +1232 -481
  7. package/dist/zn.d.ts +529 -11
  8. package/dist/zn.min.js +649 -478
  9. package/docs/pages/components/background.md +143 -0
  10. package/docs/pages/components/button.md +11 -1
  11. package/docs/pages/components/chart.md +165 -3
  12. package/docs/pages/components/checkbox-group.md +13 -1
  13. package/docs/pages/components/checkbox.md +59 -1
  14. package/docs/pages/components/icon-picker.md +8 -0
  15. package/docs/pages/components/radio-group.md +12 -0
  16. package/docs/pages/components/radio.md +188 -0
  17. package/docs/pages/components/remarkd-editor.md +22 -0
  18. package/docs/pages/components/scroll-container.md +14 -15
  19. package/docs/pages/components/thumbnail-group.md +216 -0
  20. package/docs/pages/components/thumbnail.md +349 -0
  21. package/docs/pages/components/well.md +34 -0
  22. package/package.json +1 -1
  23. package/src/components/background/background.component.ts +111 -0
  24. package/src/components/background/background.scss +236 -0
  25. package/src/components/background/background.test.ts +120 -0
  26. package/src/components/background/index.ts +12 -0
  27. package/src/components/button/button.component.ts +8 -0
  28. package/src/components/chart/builders.test.ts +190 -1
  29. package/src/components/chart/builders.ts +246 -4
  30. package/src/components/chart/chart.component.ts +33 -1
  31. package/src/components/chart/chart.test.ts +66 -1
  32. package/src/components/chart/echarts-loader.ts +10 -0
  33. package/src/components/checkbox/checkbox.component.ts +62 -6
  34. package/src/components/checkbox/checkbox.scss +1 -0
  35. package/src/components/checkbox/checkbox.test.ts +56 -0
  36. package/src/components/checkbox-group/checkbox-group.component.ts +15 -0
  37. package/src/components/checkbox-group/checkbox-group.scss +23 -5
  38. package/src/components/checkbox-group/checkbox-group.test.ts +15 -0
  39. package/src/components/collapsible/collapsible.component.ts +49 -4
  40. package/src/components/collapsible/collapsible.scss +33 -14
  41. package/src/components/confirm/confirm.component.ts +3 -3
  42. package/src/components/confirm/confirm.test.ts +15 -0
  43. package/src/components/dialog/dialog.component.ts +3 -2
  44. package/src/components/editor/editor.component.ts +7 -6
  45. package/src/components/header/header.scss +2 -2
  46. package/src/components/icon-picker/icon-picker.component.ts +3 -0
  47. package/src/components/icon-picker/lucide-icons.ts +1756 -0
  48. package/src/components/navbar/navbar.scss +11 -0
  49. package/src/components/page/page.scss +1 -1
  50. package/src/components/radio/radio.component.ts +63 -7
  51. package/src/components/radio/radio.scss +1 -0
  52. package/src/components/radio/radio.test.ts +56 -0
  53. package/src/components/radio-group/radio-group.component.ts +16 -3
  54. package/src/components/radio-group/radio-group.scss +23 -4
  55. package/src/components/radio-group/radio-group.test.ts +15 -0
  56. package/src/components/remarkd-editor/remarkd-editor.component.ts +118 -5
  57. package/src/components/remarkd-editor/remarkd-editor.scss +8 -1
  58. package/src/components/remarkd-editor/remarkd-editor.test.ts +135 -0
  59. package/src/components/scroll-container/scroll-container.component.ts +15 -1
  60. package/src/components/scroll-container/scroll-container.scss +4 -2
  61. package/src/components/scroll-container/scroll-container.test.ts +13 -0
  62. package/src/components/slideout/slideout.component.ts +3 -2
  63. package/src/components/split-pane/split-pane.scss +21 -15
  64. package/src/components/thumbnail/index.ts +12 -0
  65. package/src/components/thumbnail/thumbnail.component.ts +460 -0
  66. package/src/components/thumbnail/thumbnail.scss +360 -0
  67. package/src/components/thumbnail/thumbnail.test.ts +379 -0
  68. package/src/components/thumbnail-group/index.ts +12 -0
  69. package/src/components/thumbnail-group/thumbnail-group.component.ts +268 -0
  70. package/src/components/thumbnail-group/thumbnail-group.scss +86 -0
  71. package/src/components/thumbnail-group/thumbnail-group.test.ts +151 -0
  72. package/src/components/tile/tile.scss +4 -2
  73. package/src/components/translation-group/translation-group.test.ts +22 -0
  74. package/src/components/translations/translations.component.ts +18 -3
  75. package/src/components/well/well.component.ts +22 -4
  76. package/src/components/well/well.scss +24 -0
  77. package/src/components/well/well.test.ts +43 -0
  78. package/src/form-control.scss +3 -1
  79. package/src/internal/conditional.ts +2 -2
  80. package/src/internal/form.ts +2 -1
  81. package/src/internal/selection-card.ts +19 -0
  82. package/src/selection-card.scss +187 -0
  83. package/src/utilities/query.test.ts +18 -1
  84. package/src/utilities/query.ts +8 -0
  85. package/src/zinc.ts +3 -0
@@ -111,6 +111,194 @@ Add the `contained` attribute to draw a card-like container around a radio. This
111
111
  <zn-radio name="payment" value="bank" description="Direct bank transfer (3-5 business days)" contained>Bank Transfer</zn-radio>
112
112
  ```
113
113
 
114
+ Containers are rounded by default. Add `square` to square off the corners; setting it on a
115
+ [radio group](/components/radio-group) squares every radio in the group.
116
+
117
+ ```html:preview
118
+ <zn-radio-group name="delivery" value="standard" contained square>
119
+ <zn-radio value="standard" description="Arrives in 3-5 working days">Standard delivery</zn-radio>
120
+ <zn-radio value="express" description="Arrives the next working day">Express delivery</zn-radio>
121
+ </zn-radio-group>
122
+ ```
123
+
124
+ ### Selection Cards
125
+
126
+ A contained radio can combine an image, title, supporting text, and a freely positioned radio indicator. Set the title
127
+ with `card-title` (or use the default slot), and set supporting text with `description` (or the `description` slot).
128
+ Provide an image with `src` and `image-alt`, or place richer content such as `zn-icon` in the `image` slot.
129
+
130
+ Use these cards inside [`zn-radio-group`](/components/radio-group) for a single-select form input. Adding both
131
+ `contained` and `horizontal` to the group produces a responsive grid of equal-height cards that stacks when the
132
+ available width becomes narrow.
133
+
134
+ ```html:preview
135
+ <zn-radio-group label="Choose a pricing plan" name="plan" value="complete" contained horizontal>
136
+ <zn-radio
137
+ value="basic"
138
+ card-title="Basic"
139
+ description="For smaller businesses, with simple salaries and pay schedules."
140
+ control-position="top-right">
141
+ <zn-icon slot="image" src="support" size="64"></zn-icon>
142
+ </zn-radio>
143
+ <zn-radio
144
+ value="complete"
145
+ card-title="Complete"
146
+ description="For growing businesses that want to create a rewarding place to work."
147
+ control-position="top-right">
148
+ <zn-icon slot="image" src="potted_plant" size="64"></zn-icon>
149
+ </zn-radio>
150
+ </zn-radio-group>
151
+ ```
152
+
153
+ #### Image and Indicator Positions
154
+
155
+ Set `image-position` to `top`, `right`, `bottom`, or `left` (the default), and `control-position` to any corner,
156
+ edge centre, or `center`. Content is never placed underneath a positioned indicator — the card reserves a gutter for
157
+ it — so wider columns leave more room for text. Use `--zn-radio-group-column-width` on the group to control how many
158
+ cards sit in a row, or add `wrap` to the group to let cards grow to fill each line instead of sharing equal-width
159
+ columns.
160
+
161
+ ```html:preview
162
+ <zn-radio-group
163
+ label="Card position examples"
164
+ name="position-example"
165
+ contained
166
+ horizontal
167
+ style="--zn-radio-group-column-width: 24rem;">
168
+ <zn-radio
169
+ value="top"
170
+ card-title="Image above"
171
+ description="Top image, top-left control."
172
+ image-position="top"
173
+ control-position="top-left"
174
+ checked>
175
+ <zn-icon slot="image" src="image" size="48"></zn-icon>
176
+ </zn-radio>
177
+ <zn-radio
178
+ value="right"
179
+ card-title="Image right"
180
+ description="Right image, top-right control."
181
+ image-position="right"
182
+ control-position="top-right">
183
+ <zn-icon slot="image" src="image" size="48"></zn-icon>
184
+ </zn-radio>
185
+ <zn-radio
186
+ value="bottom"
187
+ card-title="Image below"
188
+ description="Bottom image, bottom-left control."
189
+ image-position="bottom"
190
+ control-position="bottom-left">
191
+ <zn-icon slot="image" src="image" size="48"></zn-icon>
192
+ </zn-radio>
193
+ <zn-radio
194
+ value="left"
195
+ card-title="Image left"
196
+ description="Left image, bottom-right control."
197
+ image-position="left"
198
+ control-position="bottom-right">
199
+ <zn-icon slot="image" src="image" size="48"></zn-icon>
200
+ </zn-radio>
201
+ </zn-radio-group>
202
+ ```
203
+
204
+ #### Indicators on an Edge
205
+
206
+ The indicator can also be centred along any edge of the card.
207
+
208
+ ```html:preview
209
+ <zn-radio-group
210
+ label="Additional indicator positions"
211
+ name="control-example"
212
+ contained
213
+ horizontal
214
+ style="--zn-radio-group-column-width: 18rem;">
215
+ <zn-radio
216
+ value="top-center"
217
+ card-title="Top center"
218
+ description="Centered along the top edge."
219
+ control-position="top-center">
220
+ <zn-icon slot="image" src="filter_center_focus" size="48"></zn-icon>
221
+ </zn-radio>
222
+ <zn-radio
223
+ value="center-right"
224
+ card-title="Center right"
225
+ description="Centered along the right edge."
226
+ control-position="center-right">
227
+ <zn-icon slot="image" src="filter_center_focus" size="48"></zn-icon>
228
+ </zn-radio>
229
+ <zn-radio
230
+ value="bottom-center"
231
+ card-title="Bottom center"
232
+ description="Centered along the bottom edge."
233
+ control-position="bottom-center">
234
+ <zn-icon slot="image" src="filter_center_focus" size="48"></zn-icon>
235
+ </zn-radio>
236
+ </zn-radio-group>
237
+ ```
238
+
239
+ #### Hiding the Radio Input
240
+
241
+ Set `control-position="none"` to hide the radio itself so the card *is* the control — selection is shown by the card's
242
+ highlighted border and background alone. Nothing is removed from the DOM: the native radio still receives focus, still
243
+ responds to arrow keys within a [radio group](/components/radio-group), still submits its value, and the whole card
244
+ stays clickable. Focusing a card in this state draws a focus ring around the card.
245
+
246
+ ```html:preview
247
+ <zn-radio-group label="Choose a theme" name="theme" value="light" contained horizontal>
248
+ <zn-radio
249
+ value="light"
250
+ card-title="Light"
251
+ description="Bright background with dark text."
252
+ image-position="top"
253
+ control-position="none">
254
+ <zn-icon slot="image" src="light_mode" size="48"></zn-icon>
255
+ </zn-radio>
256
+ <zn-radio
257
+ value="dark"
258
+ card-title="Dark"
259
+ description="Dark background with light text."
260
+ image-position="top"
261
+ control-position="none">
262
+ <zn-icon slot="image" src="dark_mode" size="48"></zn-icon>
263
+ </zn-radio>
264
+ <zn-radio
265
+ value="system"
266
+ card-title="System"
267
+ description="Follows your device setting."
268
+ image-position="top"
269
+ control-position="none">
270
+ <zn-icon slot="image" src="contrast" size="48"></zn-icon>
271
+ </zn-radio>
272
+ </zn-radio-group>
273
+ ```
274
+
275
+ It works just as well without an image, which gives a compact set of button-like options.
276
+
277
+ ```html:preview
278
+ <zn-radio-group label="Billing period" name="billing" value="annual" contained horizontal wrap>
279
+ <zn-radio value="monthly" card-title="Monthly" description="£29 per month" control-position="none"></zn-radio>
280
+ <zn-radio value="annual" card-title="Annual" description="£290 per year, two months free" control-position="none"></zn-radio>
281
+ </zn-radio-group>
282
+ ```
283
+
284
+ :::warning
285
+ Because a hidden indicator removes the usual radio affordance, keep the selected state obvious — a short title with
286
+ supporting text, as above, reads better than an image on its own.
287
+ :::
288
+
289
+ :::tip
290
+ Card attributes only apply to `contained` radios. `control-position` accepts `top-left`, `top-center`, `top-right`,
291
+ `center-left`, `center`, `center-right`, `bottom-left`, `bottom-center`, `bottom-right`, `none`, and the default
292
+ `start`, which keeps the standard inline radio.
293
+ :::
294
+
295
+ Card dimensions can be adjusted with `--zn-selection-card-image-width`, `--zn-selection-card-image-height`,
296
+ `--zn-selection-card-min-height`, and `--zn-selection-card-title-font-size`. Use `--zn-selection-card-padding` for the
297
+ inset around the card, `--zn-selection-card-gap` for the space between its regions,
298
+ `--zn-selection-card-control-offset` to change the indicator's distance from an edge,
299
+ `--zn-selection-card-content-min-width` for the width the text keeps before it wraps below a side image, and
300
+ `--zn-selection-card-border-radius` for the corner radius.
301
+
114
302
  ### Horizontal Layout
115
303
 
116
304
  Use the `horizontal` attribute to apply styles relevant to radios in a horizontal layout.
@@ -135,6 +135,28 @@ NOTE: The value is the same remarkd source either way."
135
135
  ></zn-remarkd-editor>
136
136
  ```
137
137
 
138
+ ### Height
139
+
140
+ The editor never grows taller than the viewport: past that, its body scrolls and
141
+ the toolbar stays in reach. Override the cap with `--remarkd-editor-max-height` —
142
+ useful when the editor sits below a header and should only fill the space left on
143
+ screen.
144
+
145
+ All scrolling stays inside the editor's own body: adding a block or opening the
146
+ image / include picker brings the new content into view, and dragging a block to a
147
+ scroll edge keeps the content moving. Neither touches the page or panel around the
148
+ editor.
149
+
150
+ ```html:preview
151
+ <zn-remarkd-editor
152
+ style="--remarkd-editor-max-height: 20rem"
153
+ value="A short editor.
154
+
155
+ Add blocks from the toolbar and the body starts scrolling once the content
156
+ outgrows the 20rem cap set here."
157
+ ></zn-remarkd-editor>
158
+ ```
159
+
138
160
  ### Form Integration
139
161
 
140
162
  `zn-remarkd-editor` is a [form control](/getting-started/form-controls); its
@@ -5,10 +5,10 @@ meta:
5
5
  layout: component
6
6
  ---
7
7
 
8
- The scroll container provides a flexible scrolling area with optional header and footer slots that remain fixed while the main content scrolls. It supports automatic scrolling to the bottom, making it ideal for chat applications, activity feeds, and log viewers.
8
+ The scroll container provides a flexible scrolling area with optional header and footer slots that remain fixed while the main content scrolls. It supports automatic scrolling to the bottom, making it ideal for chat applications, activity feeds, and log viewers. Set `height` to constrain the block-level container and enable scrolling when its content exceeds that height.
9
9
 
10
10
  ```html:preview
11
- <zn-scroll-container style="height: 300px; display: block; border: 1px solid var(--zn-color-neutral-200);">
11
+ <zn-scroll-container height="300px" style="border: 1px solid var(--zn-color-neutral-200);">
12
12
  <div slot="header" style="padding: 1rem; background: var(--zn-color-neutral-100); border-bottom: 1px solid var(--zn-color-neutral-200);">
13
13
  <strong>Header Area</strong>
14
14
  </div>
@@ -39,7 +39,7 @@ The scroll container provides a flexible scrolling area with optional header and
39
39
  The most common use case is a simple vertical scrolling container. The main content area scrolls while header and footer remain fixed.
40
40
 
41
41
  ```html:preview
42
- <zn-scroll-container style="height: 400px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
42
+ <zn-scroll-container height="400px" style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
43
43
  <div style="padding: 1rem;">
44
44
  <h3 style="margin-top: 0;">Scrollable Content Area</h3>
45
45
  <p>This container has a fixed height and the content will scroll vertically when it exceeds the available space.</p>
@@ -60,7 +60,7 @@ The most common use case is a simple vertical scrolling container. The main cont
60
60
  Use the `header` slot to add a fixed header that remains visible while content scrolls.
61
61
 
62
62
  ```html:preview
63
- <zn-scroll-container style="height: 350px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
63
+ <zn-scroll-container height="350px" style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
64
64
  <div slot="header" style="padding: 1rem; background: var(--zn-color-primary-50); border-bottom: 2px solid var(--zn-color-primary-200);">
65
65
  <h3 style="margin: 0;">Document Title</h3>
66
66
  <p style="margin: 0.5rem 0 0 0; font-size: 0.875rem; color: var(--zn-color-neutral-600);">Last updated: January 23, 2026</p>
@@ -91,7 +91,7 @@ Use the `header` slot to add a fixed header that remains visible while content s
91
91
  Use the `footer` slot to add a fixed footer that remains at the bottom. The footer is positioned absolutely and the scrollable area has padding to account for its height.
92
92
 
93
93
  ```html:preview
94
- <zn-scroll-container style="height: 350px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
94
+ <zn-scroll-container height="350px" style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
95
95
  <div style="padding: 1rem;">
96
96
  <h4>Content Area</h4>
97
97
  <p>The footer remains fixed at the bottom while this content scrolls.</p>
@@ -116,7 +116,7 @@ Use the `footer` slot to add a fixed footer that remains at the bottom. The foot
116
116
  Combine both header and footer slots for maximum control. The scrollable area sits between them.
117
117
 
118
118
  ```html:preview
119
- <zn-scroll-container style="height: 400px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
119
+ <zn-scroll-container height="400px" style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
120
120
  <div slot="header" style="padding: 1rem; background: var(--zn-color-neutral-100); border-bottom: 1px solid var(--zn-color-neutral-200);">
121
121
  <h3 style="margin: 0;">Messages</h3>
122
122
  </div>
@@ -156,7 +156,7 @@ Combine both header and footer slots for maximum control. The scrollable area si
156
156
  Use the `start-scrolled` attribute to automatically scroll to the bottom when the component loads or when new content is added. This is perfect for chat interfaces, activity logs, and notification feeds.
157
157
 
158
158
  ```html:preview
159
- <zn-scroll-container start-scrolled style="height: 300px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
159
+ <zn-scroll-container height="300px" start-scrolled style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
160
160
  <div slot="header" style="padding: 1rem; background: var(--zn-color-neutral-100); border-bottom: 1px solid var(--zn-color-neutral-200);">
161
161
  <h4 style="margin: 0;">Activity Log</h4>
162
162
  </div>
@@ -198,7 +198,7 @@ Use the `start-scrolled` attribute to automatically scroll to the bottom when th
198
198
  A practical example showing how to build a chat interface with auto-scrolling and dynamic content.
199
199
 
200
200
  ```html:preview
201
- <zn-scroll-container id="chat-example" start-scrolled style="height: 450px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
201
+ <zn-scroll-container id="chat-example" height="450px" start-scrolled style="border: 1px solid var(--zn-color-neutral-200); border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);">
202
202
  <div slot="header" style="padding: 1rem; background: var(--zn-color-primary); color: white; display: flex; align-items: center; gap: 0.75rem;">
203
203
  <div style="width: 40px; height: 40px; border-radius: 50%; background: var(--zn-color-primary-700); display: flex; align-items: center; justify-content: center; font-weight: bold;">
204
204
  TC
@@ -274,7 +274,7 @@ A practical example showing how to build a chat interface with auto-scrolling an
274
274
  Perfect for displaying server logs, build output, or any streaming text content.
275
275
 
276
276
  ```html:preview
277
- <zn-scroll-container start-scrolled style="height: 350px; display: block; border: 1px solid var(--zn-color-neutral-800); border-radius: 4px; overflow: hidden; background: var(--zn-color-neutral-900);">
277
+ <zn-scroll-container height="350px" start-scrolled style="border: 1px solid var(--zn-color-neutral-800); border-radius: 4px; overflow: hidden; background: var(--zn-color-neutral-900);">
278
278
  <div slot="header" style="padding: 0.75rem 1rem; background: var(--zn-color-neutral-800); color: var(--zn-color-neutral-200); font-family: monospace; font-size: 0.875rem; border-bottom: 1px solid var(--zn-color-neutral-700);">
279
279
  <strong>build.log</strong> - Application Build Output
280
280
  </div>
@@ -307,7 +307,7 @@ Perfect for displaying server logs, build output, or any streaming text content.
307
307
  A practical example showing an activity feed that automatically scrolls to show the latest activity.
308
308
 
309
309
  ```html:preview
310
- <zn-scroll-container id="activity-feed" start-scrolled style="height: 400px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
310
+ <zn-scroll-container id="activity-feed" height="400px" start-scrolled style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
311
311
  <div slot="header" style="padding: 1rem; background: var(--zn-color-neutral-50); border-bottom: 1px solid var(--zn-color-neutral-200); display: flex; justify-content: space-between; align-items: center;">
312
312
  <h4 style="margin: 0;">Recent Activity</h4>
313
313
  <zn-chip size="small" type="info">Live</zn-chip>
@@ -358,7 +358,7 @@ A practical example showing an activity feed that automatically scrolls to show
358
358
  A comprehensive example showing how to build a notification center with categorized notifications.
359
359
 
360
360
  ```html:preview
361
- <zn-scroll-container start-scrolled style="height: 450px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 8px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
361
+ <zn-scroll-container height="450px" start-scrolled style="border: 1px solid var(--zn-color-neutral-200); border-radius: 8px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.1);">
362
362
  <div slot="header" style="padding: 1.25rem; background: var(--zn-color-white); border-bottom: 1px solid var(--zn-color-neutral-200);">
363
363
  <div style="display: flex; justify-content: space-between; align-items: center;">
364
364
  <div>
@@ -460,7 +460,7 @@ A comprehensive example showing how to build a notification center with categori
460
460
  You can programmatically scroll to the bottom using the `scrollEnd()` method.
461
461
 
462
462
  ```html:preview
463
- <zn-scroll-container id="programmatic-scroll" style="height: 300px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
463
+ <zn-scroll-container id="programmatic-scroll" height="300px" style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
464
464
  <div id="scroll-content" style="padding: 1rem;">
465
465
  <p>Content line 1</p>
466
466
  <p>Content line 2</p>
@@ -507,7 +507,7 @@ You can programmatically scroll to the bottom using the `scrollEnd()` method.
507
507
  The footer's height is automatically tracked and the scrollable area adjusts accordingly. This happens dynamically when the footer content changes size.
508
508
 
509
509
  ```html:preview
510
- <zn-scroll-container start-scrolled style="height: 400px; display: block; border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
510
+ <zn-scroll-container height="400px" start-scrolled style="border: 1px solid var(--zn-color-neutral-200); border-radius: 4px; overflow: hidden;">
511
511
  <div style="padding: 1rem;">
512
512
  <p>The scrollable area automatically adjusts its padding based on the footer's height.</p>
513
513
  <p>This ensures that content is never hidden behind the fixed footer.</p>
@@ -552,7 +552,7 @@ The footer's height is automatically tracked and the scrollable area adjusts acc
552
552
  A minimal example showing just the essential markup.
553
553
 
554
554
  ```html:preview
555
- <zn-scroll-container style="height: 250px; display: block; border: 1px solid var(--zn-color-neutral-200);">
555
+ <zn-scroll-container height="250px" style="border: 1px solid var(--zn-color-neutral-200);">
556
556
  <div style="padding: 1rem;">
557
557
  <p>Simple scrollable content without header or footer.</p>
558
558
  <p>Just add content to the default slot.</p>
@@ -565,4 +565,3 @@ A minimal example showing just the essential markup.
565
565
  </zn-scroll-container>
566
566
  ```
567
567
 
568
-
@@ -0,0 +1,216 @@
1
+ ---
2
+ meta:
3
+ title: Thumbnail Group
4
+ description: Lays a set of thumbnails out as a single scrollable row, with a Show All toggle that expands them into a wrapping grid.
5
+ layout: component
6
+ ---
7
+
8
+ A thumbnail group holds [thumbnails](/components/thumbnail) in one horizontally scrollable row. When they don't all fit,
9
+ a **Show All** toggle appears in the header; expanding drops the single-row restriction and reflows everything into a
10
+ wrapping grid. **Show Less** rolls it back to the row.
11
+
12
+ ```html:preview
13
+ <zn-thumbnail-group caption="Landscape">
14
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day" icon="play_arrow"></zn-thumbnail>
15
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise" icon="play_arrow"></zn-thumbnail>
16
+ <zn-thumbnail src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60" caption="Sonoma Horizon" icon="play_arrow"></zn-thumbnail>
17
+ <zn-thumbnail src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60" caption="Goa Beaches" icon="play_arrow"></zn-thumbnail>
18
+ <zn-thumbnail src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60" caption="Big Sur" icon="play_arrow"></zn-thumbnail>
19
+ <zn-thumbnail src="https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?w=600&q=60" caption="Yosemite Valley" icon="play_arrow"></zn-thumbnail>
20
+ <zn-thumbnail src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=600&q=60" caption="Hallstatt" icon="play_arrow"></zn-thumbnail>
21
+ <zn-thumbnail src="https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=600&q=60" caption="Falls" icon="play_arrow"></zn-thumbnail>
22
+ <zn-thumbnail src="https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=600&q=60" caption="Rolling Hills" icon="play_arrow"></zn-thumbnail>
23
+ <zn-thumbnail src="https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=600&q=60" caption="Coastline" icon="play_arrow"></zn-thumbnail>
24
+ </zn-thumbnail-group>
25
+ ```
26
+
27
+ The toggle is only rendered when it's needed — a group whose thumbnails already fit shows no toggle at all.
28
+
29
+ ```html:preview
30
+ <zn-thumbnail-group caption="Fits on one row">
31
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day"></zn-thumbnail>
32
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
33
+ </zn-thumbnail-group>
34
+ ```
35
+
36
+ ## Examples
37
+
38
+ ### Thumbnail Size and Shape
39
+
40
+ `thumbnail-width` sets the row's track width and, when expanded, the minimum column width the grid packs against.
41
+ `gap` sets the spacing between thumbnails, and `aspect-ratio` reshapes every thumbnail in the group.
42
+
43
+ ```html:preview
44
+ <zn-thumbnail-group caption="Square, compact" thumbnail-width="120px" gap="8px" aspect-ratio="1 / 1">
45
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day"></zn-thumbnail>
46
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
47
+ <zn-thumbnail src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60" caption="Sonoma Horizon"></zn-thumbnail>
48
+ <zn-thumbnail src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60" caption="Goa Beaches"></zn-thumbnail>
49
+ <zn-thumbnail src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60" caption="Big Sur"></zn-thumbnail>
50
+ <zn-thumbnail src="https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?w=600&q=60" caption="Yosemite Valley"></zn-thumbnail>
51
+ <zn-thumbnail src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=600&q=60" caption="Hallstatt"></zn-thumbnail>
52
+ <zn-thumbnail src="https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=600&q=60" caption="Falls"></zn-thumbnail>
53
+ <zn-thumbnail src="https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=600&q=60" caption="Rolling Hills"></zn-thumbnail>
54
+ <zn-thumbnail src="https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=600&q=60" caption="Coastline"></zn-thumbnail>
55
+ </zn-thumbnail-group>
56
+ ```
57
+
58
+ Those three attributes are shorthand for `--zn-thumbnail-width`, `--zn-thumbnail-gap` and
59
+ `--zn-thumbnail-aspect-ratio`, which you can set on the group directly instead. Because
60
+ [thumbnail](/components/thumbnail)'s custom properties all inherit, **any** of them — chip colours, corner radii,
61
+ preview sizing — can be set once on the group and will apply to every thumbnail in it.
62
+
63
+ ```html:preview
64
+ <zn-thumbnail-group
65
+ caption="Restyled from the group"
66
+ style="--zn-thumbnail-width: 120px;
67
+ --zn-thumbnail-gap: 8px;
68
+ --zn-thumbnail-radius: 16px;
69
+ --zn-thumbnail-chip-background: rgb(var(--zn-primary));
70
+ --zn-thumbnail-selected-color: rgb(var(--zn-color-warning));">
71
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day" icon="play_arrow" selected></zn-thumbnail>
72
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise" icon="play_arrow"></zn-thumbnail>
73
+ <zn-thumbnail src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60" caption="Sonoma Horizon" icon="play_arrow"></zn-thumbnail>
74
+ <zn-thumbnail src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60" caption="Goa Beaches" icon="play_arrow"></zn-thumbnail>
75
+ <zn-thumbnail src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60" caption="Big Sur" icon="play_arrow"></zn-thumbnail>
76
+ <zn-thumbnail src="https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?w=600&q=60" caption="Yosemite Valley" icon="play_arrow"></zn-thumbnail>
77
+ <zn-thumbnail src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=600&q=60" caption="Hallstatt" icon="play_arrow"></zn-thumbnail>
78
+ <zn-thumbnail src="https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=600&q=60" caption="Falls" icon="play_arrow"></zn-thumbnail>
79
+ <zn-thumbnail src="https://images.unsplash.com/photo-1472214103451-9374bd1c798e?w=600&q=60" caption="Rolling Hills" icon="play_arrow"></zn-thumbnail>
80
+ <zn-thumbnail src="https://images.unsplash.com/photo-1444927714506-8492d94b4e3d?w=600&q=60" caption="Coastline" icon="play_arrow"></zn-thumbnail>
81
+ </zn-thumbnail-group>
82
+ ```
83
+
84
+ ### Preview
85
+
86
+ Give the thumbnails a `full-uri` and clicking one opens a full-screen preview that grows out of its position in the
87
+ row. The preview opens in the browser's top layer, so it escapes the scrolling row instead of being clipped by it. See
88
+ [thumbnail](/components/thumbnail#preview) for the trigger options.
89
+
90
+ ```html:preview
91
+ <zn-thumbnail-group caption="Landscape">
92
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=400&q=50" full-uri="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=2000&q=80" caption="Tahoe Day" icon="play_arrow"></zn-thumbnail>
93
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=400&q=50" full-uri="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=2000&q=80" caption="Sequoia Sunrise" icon="play_arrow"></zn-thumbnail>
94
+ <zn-thumbnail src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=400&q=50" full-uri="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=2000&q=80" caption="Sonoma Horizon" icon="play_arrow"></zn-thumbnail>
95
+ <zn-thumbnail src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=400&q=50" full-uri="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=2000&q=80" caption="Goa Beaches" icon="play_arrow"></zn-thumbnail>
96
+ <zn-thumbnail src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&q=50" full-uri="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=2000&q=80" caption="Big Sur" icon="play_arrow"></zn-thumbnail>
97
+ <zn-thumbnail src="https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?w=400&q=50" full-uri="https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?w=2000&q=80" caption="Yosemite Valley" icon="play_arrow"></zn-thumbnail>
98
+ <zn-thumbnail src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=400&q=50" full-uri="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=2000&q=80" caption="Hallstatt" icon="play_arrow"></zn-thumbnail>
99
+ <zn-thumbnail src="https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=400&q=50" full-uri="https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=2000&q=80" caption="Falls" icon="play_arrow"></zn-thumbnail>
100
+ </zn-thumbnail-group>
101
+ ```
102
+
103
+ ### Selection
104
+
105
+ Add `selectable` and the group tracks a single selection for you: clicking a thumbnail moves the accent ring, updates
106
+ the group's `value`, and emits `zn-change`. A thumbnail marked `selected` in markup becomes the starting value.
107
+
108
+ ```html:preview
109
+ <zn-thumbnail-group caption="Pick a still" selectable>
110
+ <zn-thumbnail value="tahoe" src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day" selected></zn-thumbnail>
111
+ <zn-thumbnail value="sequoia" src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
112
+ <zn-thumbnail value="sonoma" src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60" caption="Sonoma Horizon"></zn-thumbnail>
113
+ <zn-thumbnail value="goa" src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60" caption="Goa Beaches"></zn-thumbnail>
114
+ </zn-thumbnail-group>
115
+ ```
116
+
117
+ ### Counting a Larger Set
118
+
119
+ When the row only holds the first page of a much larger set, set `total` so the toggle advertises the real size. The
120
+ toggle appears whenever `total` exceeds the number of slotted thumbnails, even if those all fit. Listen for `zn-expand`
121
+ to fetch and append the rest.
122
+
123
+ ```html:preview
124
+ <zn-thumbnail-group caption="Landscape" total="79" id="thumbnail-group-lazy">
125
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day"></zn-thumbnail>
126
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
127
+ <zn-thumbnail src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60" caption="Sonoma Horizon"></zn-thumbnail>
128
+ </zn-thumbnail-group>
129
+
130
+ <script>
131
+ const group = document.getElementById('thumbnail-group-lazy');
132
+
133
+ group.addEventListener('zn-expand', () => {
134
+ // Load the rest of the set the first time the group is expanded.
135
+ if (group.dataset.loaded) return;
136
+ group.dataset.loaded = 'true';
137
+
138
+ for (let i = 4; i <= group.total; i++) {
139
+ const thumbnail = document.createElement('zn-thumbnail');
140
+ thumbnail.caption = `Landscape ${i}`;
141
+ thumbnail.src = `https://picsum.photos/seed/landscape-${i}/480/270`;
142
+ group.append(thumbnail);
143
+ }
144
+ });
145
+ </script>
146
+ ```
147
+
148
+ ### Custom Labels
149
+
150
+ Override `show-all-label` and `show-less-label` for wording that suits the content. The count is appended to the
151
+ expand label in brackets.
152
+
153
+ ```html:preview
154
+ <zn-thumbnail-group
155
+ caption="Recordings"
156
+ total="24"
157
+ show-all-label="Browse all recordings"
158
+ show-less-label="Collapse">
159
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day"></zn-thumbnail>
160
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
161
+ </zn-thumbnail-group>
162
+ ```
163
+
164
+ ### Header Actions
165
+
166
+ The `actions` slot sits in the header before the toggle.
167
+
168
+ ```html:preview
169
+ <zn-thumbnail-group caption="Cityscape" total="41">
170
+ <zn-button slot="actions" outline icon="upload">Upload</zn-button>
171
+ <zn-thumbnail src="https://images.unsplash.com/photo-1512453979798-5ea266f8880c?w=600&q=60" caption="Dubai Skyline" icon="play_arrow"></zn-thumbnail>
172
+ <zn-thumbnail src="https://images.unsplash.com/photo-1518684079-3c830dcef090?w=600&q=60" caption="Dubai at Night" icon="play_arrow"></zn-thumbnail>
173
+ <zn-thumbnail src="https://images.unsplash.com/photo-1546412414-e1885259563a?w=600&q=60" caption="Dubai Creek" icon="play_arrow"></zn-thumbnail>
174
+ </zn-thumbnail-group>
175
+ ```
176
+
177
+ ### Always Showing the Toggle
178
+
179
+ `always-toggle` keeps the toggle on screen even when everything already fits — useful when the row is one of several
180
+ sibling groups and you want the headers to line up. `hide-toggle` does the opposite and suppresses it entirely,
181
+ leaving a plain scrolling row.
182
+
183
+ ```html:preview
184
+ <zn-thumbnail-group caption="Always" always-toggle>
185
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day"></zn-thumbnail>
186
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
187
+ </zn-thumbnail-group>
188
+
189
+ <zn-thumbnail-group caption="Never" hide-toggle>
190
+ <zn-thumbnail src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60" caption="Tahoe Day"></zn-thumbnail>
191
+ <zn-thumbnail src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60" caption="Sequoia Sunrise"></zn-thumbnail>
192
+ <zn-thumbnail src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60" caption="Sonoma Horizon"></zn-thumbnail>
193
+ <zn-thumbnail src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60" caption="Goa Beaches"></zn-thumbnail>
194
+ <zn-thumbnail src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60" caption="Big Sur"></zn-thumbnail>
195
+ <zn-thumbnail src="https://images.unsplash.com/photo-1418065460487-3e41a6c84dc5?w=600&q=60" caption="Yosemite Valley"></zn-thumbnail>
196
+ <zn-thumbnail src="https://images.unsplash.com/photo-1501785888041-af3ef285b470?w=600&q=60" caption="Hallstatt"></zn-thumbnail>
197
+ <zn-thumbnail src="https://images.unsplash.com/photo-1433086966358-54859d0ed716?w=600&q=60" caption="Falls"></zn-thumbnail>
198
+ </zn-thumbnail-group>
199
+ ```
200
+
201
+ ### Starting Expanded
202
+
203
+ Set `expanded` to open the grid on first paint, or call `show()` / `hide()` to drive it from script.
204
+
205
+ ```html:preview
206
+ <zn-thumbnail-group caption="Cityscape" expanded>
207
+ <zn-thumbnail src="https://images.unsplash.com/photo-1512453979798-5ea266f8880c?w=600&q=60" caption="Dubai Skyline" icon="play_arrow"></zn-thumbnail>
208
+ <zn-thumbnail src="https://images.unsplash.com/photo-1518684079-3c830dcef090?w=600&q=60" caption="Dubai at Night" icon="play_arrow"></zn-thumbnail>
209
+ <zn-thumbnail src="https://images.unsplash.com/photo-1546412414-e1885259563a?w=600&q=60" caption="Dubai Creek" icon="play_arrow"></zn-thumbnail>
210
+ <zn-thumbnail src="https://images.unsplash.com/photo-1502920917128-1aa500764cbd?w=600&q=60" caption="Dubai from Above" icon="play_arrow"></zn-thumbnail>
211
+ <zn-thumbnail src="https://images.unsplash.com/photo-1449824913935-59a10b8d2000?w=600&q=60" caption="Los Angeles Flyover" icon="play_arrow"></zn-thumbnail>
212
+ <zn-thumbnail src="https://images.unsplash.com/photo-1534190760961-74e8c1b5c3da?w=600&q=60" caption="Los Angeles Beach" icon="play_arrow"></zn-thumbnail>
213
+ <zn-thumbnail src="https://images.unsplash.com/photo-1444723121867-7a241cacace9?w=600&q=60" caption="Los Angeles at Night" icon="play_arrow"></zn-thumbnail>
214
+ <zn-thumbnail src="https://images.unsplash.com/photo-1513635269975-59663e0ac1ad?w=600&q=60" caption="London Evening" icon="play_arrow"></zn-thumbnail>
215
+ </zn-thumbnail-group>
216
+ ```