@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
@@ -0,0 +1,349 @@
1
+ ---
2
+ meta:
3
+ title: Thumbnail
4
+ description: A captioned image tile with a fixed aspect ratio, optional corner badges and actions, and optional link or selectable behaviour.
5
+ layout: component
6
+ ---
7
+
8
+ A thumbnail is a single media preview with its title beneath it. Thumbnails are usually placed inside a
9
+ [thumbnail group](/components/thumbnail-group), which lays them out as a scrollable row that expands into a grid.
10
+
11
+ ```html:preview
12
+ <div style="width: 200px;">
13
+ <zn-thumbnail
14
+ src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60"
15
+ caption="Tahoe Day">
16
+ </zn-thumbnail>
17
+ </div>
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### Aspect Ratio
23
+
24
+ The media frame is `16 / 9` by default. Set the `aspect-ratio` attribute to any CSS aspect ratio to change it — the
25
+ image is cropped to fill the frame, so captions stay aligned across a row whatever the source dimensions are.
26
+
27
+ ```html:preview
28
+ <div style="display: flex; gap: 16px;">
29
+ <div style="width: 160px;">
30
+ <zn-thumbnail
31
+ src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60"
32
+ caption="16 / 9">
33
+ </zn-thumbnail>
34
+ </div>
35
+ <div style="width: 160px;">
36
+ <zn-thumbnail
37
+ aspect-ratio="1 / 1"
38
+ src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60"
39
+ caption="1 / 1">
40
+ </zn-thumbnail>
41
+ </div>
42
+ <div style="width: 160px;">
43
+ <zn-thumbnail
44
+ aspect-ratio="3 / 4"
45
+ src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60"
46
+ caption="3 / 4">
47
+ </zn-thumbnail>
48
+ </div>
49
+ </div>
50
+ ```
51
+
52
+ The `--zn-thumbnail-aspect-ratio` custom property does the same thing, and because it inherits you can set it once on
53
+ any ancestor — a wrapper, or a [thumbnail group](/components/thumbnail-group) — to reshape every thumbnail beneath it.
54
+ A thumbnail's own `aspect-ratio` attribute still wins over an inherited value.
55
+
56
+ ```html:preview
57
+ <div style="display: flex; gap: 16px; --zn-thumbnail-aspect-ratio: 1 / 1;">
58
+ <div style="width: 160px;">
59
+ <zn-thumbnail
60
+ src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60"
61
+ caption="Inherited 1 / 1">
62
+ </zn-thumbnail>
63
+ </div>
64
+ <div style="width: 160px;">
65
+ <zn-thumbnail
66
+ src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60"
67
+ caption="Inherited 1 / 1">
68
+ </zn-thumbnail>
69
+ </div>
70
+ <div style="width: 160px;">
71
+ <zn-thumbnail
72
+ aspect-ratio="16 / 9"
73
+ src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60"
74
+ caption="Overridden">
75
+ </zn-thumbnail>
76
+ </div>
77
+ </div>
78
+ ```
79
+
80
+ ### Badges and Actions
81
+
82
+ The `badge` slot pins content to the bottom-left of the media and the `actions` slot pins it to the bottom-right. Use
83
+ `icon` for the common case of a single badge icon.
84
+
85
+ Each slotted element becomes its own chip, so several actions read as separate icons dotted along the thumbnail rather
86
+ than a single grouped pill. `--zn-thumbnail-chip-gap` controls the spacing between them, and
87
+ `--zn-thumbnail-chip-background` / `--zn-thumbnail-chip-color` restyle them.
88
+
89
+ A badge describes the asset rather than doing something, so it keeps the chip's shape but is held back on opacity
90
+ (`--zn-thumbnail-badge-opacity`, default `0.65`) and takes no pointer events — clicks pass straight through to the
91
+ thumbnail. Actions keep full opacity, the pointer cursor and a hover state. `--zn-thumbnail-chip-radius` rounds both off.
92
+
93
+ The overlay sits **outside** the thumbnail's link, so anything you put in `actions` keeps its own click behaviour — a
94
+ download link downloads, a button's handler runs — and never selects the thumbnail or follows its `href`.
95
+
96
+ ```html:preview
97
+ <div style="display: flex; gap: 16px;">
98
+ <div style="width: 180px;">
99
+ <zn-thumbnail
100
+ src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60"
101
+ caption="Sequoia Sunrise"
102
+ icon="play_arrow">
103
+ </zn-thumbnail>
104
+ </div>
105
+ <div style="width: 180px;">
106
+ <zn-thumbnail
107
+ src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60"
108
+ caption="One action"
109
+ icon="play_arrow">
110
+ <a slot="actions" href="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05" download>
111
+ <zn-icon src="download" size="14"></zn-icon>
112
+ </a>
113
+ </zn-thumbnail>
114
+ </div>
115
+ <div style="width: 180px;">
116
+ <zn-thumbnail
117
+ src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60"
118
+ caption="Three actions"
119
+ icon="play_arrow">
120
+ <zn-icon slot="actions" src="download" size="14"></zn-icon>
121
+ <zn-icon slot="actions" src="share" size="14"></zn-icon>
122
+ <zn-icon slot="actions" src="more_horiz" size="14"></zn-icon>
123
+ </zn-thumbnail>
124
+ </div>
125
+ </div>
126
+ ```
127
+
128
+ ### Preview
129
+
130
+ Provide `full-uri` and the thumbnail becomes previewable: activating it opens a full-screen overlay that grows out of
131
+ the thumbnail's position, over a backdrop, with rounded edges. Escape, the close button, or a click on the backdrop
132
+ shrinks it back to where it came from.
133
+
134
+ The panel takes the asset's own aspect ratio, so it wraps the image rather than letterboxing it in a fixed-shape box —
135
+ which also means the close button sits on the image's top-right corner, not on a surrounding container. It grows to
136
+ whichever of `--zn-thumbnail-preview-max-width` (70vw) or `--zn-thumbnail-preview-max-height` (70vh) it reaches first,
137
+ so it always leaves the page visible around it.
138
+
139
+ The ratio is measured from the thumbnail's own already-loaded image, which shares it with the full-size asset. That
140
+ keeps the panel's size known before the large file arrives, so the grow animation has a correct target from the first
141
+ frame; the thumbnail image is held behind it, blurred, in the meantime, and the panel resizes only if the full asset
142
+ turns out to be a genuinely different shape. Override the measurement with `--zn-thumbnail-preview-aspect-ratio` — for
143
+ slotted media that can't be measured, for instance — and round the corners with `--zn-thumbnail-preview-radius`.
144
+
145
+ ```html:preview
146
+ <div style="display: flex; gap: 16px;">
147
+ <div style="width: 180px;">
148
+ <zn-thumbnail
149
+ src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=400&q=50"
150
+ full-uri="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=2000&q=80"
151
+ caption="Tahoe Day">
152
+ </zn-thumbnail>
153
+ </div>
154
+ <div style="width: 180px;">
155
+ <zn-thumbnail
156
+ src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=400&q=50"
157
+ full-uri="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=2000&q=80"
158
+ caption="Sequoia Sunrise">
159
+ </zn-thumbnail>
160
+ </div>
161
+ </div>
162
+ ```
163
+
164
+ Because the preview opens in the browser's top layer, it escapes a [thumbnail group](/components/thumbnail-group)'s
165
+ scrolling row rather than being clipped by it.
166
+
167
+ #### Preview Trigger
168
+
169
+ By default a plain click opens the preview. Set `preview-trigger="button"` to put a dedicated expand control on the
170
+ media instead, leaving clicks free for selection or for the thumbnail's `href`.
171
+
172
+ ```html:preview
173
+ <zn-thumbnail-group caption="Pick a still" selectable>
174
+ <zn-thumbnail
175
+ value="tahoe"
176
+ preview-trigger="button"
177
+ src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=400&q=50"
178
+ full-uri="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=2000&q=80"
179
+ caption="Tahoe Day"
180
+ selected>
181
+ </zn-thumbnail>
182
+ <zn-thumbnail
183
+ value="sequoia"
184
+ preview-trigger="button"
185
+ src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=400&q=50"
186
+ full-uri="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=2000&q=80"
187
+ caption="Sequoia Sunrise">
188
+ </zn-thumbnail>
189
+ <zn-thumbnail
190
+ value="sonoma"
191
+ preview-trigger="button"
192
+ src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=400&q=50"
193
+ full-uri="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=2000&q=80"
194
+ caption="Sonoma Horizon">
195
+ </zn-thumbnail>
196
+ </zn-thumbnail-group>
197
+ ```
198
+
199
+ When both `href` and `full-uri` are set, a plain left click previews while modifier and middle clicks still open the
200
+ link in a new tab. Cancelling `zn-select` suppresses the preview (and the navigation) entirely, and `showPreview()` /
201
+ `hidePreview()` drive the overlay from script.
202
+
203
+ #### Previewing Other Media
204
+
205
+ The `preview` slot replaces the preview's contents, so the full-size asset doesn't have to be an image. Filling the
206
+ slot enables the preview on its own — `full-uri` isn't needed.
207
+
208
+ ```html:preview
209
+ <div style="width: 180px;">
210
+ <zn-thumbnail
211
+ src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&q=50"
212
+ caption="Big Sur">
213
+ <video slot="preview" controls autoplay muted
214
+ poster="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1200&q=70"
215
+ src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"></video>
216
+ </zn-thumbnail>
217
+ </div>
218
+ ```
219
+
220
+ ### Links
221
+
222
+ Set `href` to render the thumbnail as an anchor. `target` is forwarded to it.
223
+
224
+ ```html:preview
225
+ <div style="width: 180px;">
226
+ <zn-thumbnail
227
+ src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60"
228
+ caption="Goa Beaches"
229
+ href="https://unsplash.com"
230
+ target="_blank">
231
+ </zn-thumbnail>
232
+ </div>
233
+ ```
234
+
235
+ ### Selected
236
+
237
+ `selected` draws the accent ring. A [thumbnail group](/components/thumbnail-group) with `selectable` manages this for
238
+ you; set it by hand when you're tracking selection yourself from the `zn-select` event.
239
+
240
+ A thumbnail only enters the tab order when it's a link or when `selectable` is set — a group with `selectable` sets
241
+ that on its children for you. If you're handling `zn-select` yourself, set `selectable` too so the thumbnail is
242
+ reachable by keyboard and announced as a button.
243
+
244
+ ```html:preview
245
+ <div style="display: flex; gap: 16px;">
246
+ <div style="width: 180px;">
247
+ <zn-thumbnail
248
+ src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60"
249
+ caption="Selected"
250
+ selected>
251
+ </zn-thumbnail>
252
+ </div>
253
+ <div style="width: 180px;">
254
+ <zn-thumbnail
255
+ src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60"
256
+ caption="Not selected">
257
+ </zn-thumbnail>
258
+ </div>
259
+ </div>
260
+ ```
261
+
262
+ ### Active
263
+
264
+ `active` draws a ring in a second colour, for the thumbnail currently in use — playing, open, being edited — as opposed
265
+ to the one the user has picked. It's independent of `selected`, and takes the ring colour when a thumbnail is both.
266
+ Recolour either ring with `--zn-thumbnail-active-color` and `--zn-thumbnail-selected-color`.
267
+
268
+ ```html:preview
269
+ <div style="display: flex; gap: 16px;">
270
+ <div style="width: 160px;">
271
+ <zn-thumbnail
272
+ src="https://images.unsplash.com/photo-1439066615861-d1af74d74000?w=600&q=60"
273
+ caption="Idle">
274
+ </zn-thumbnail>
275
+ </div>
276
+ <div style="width: 160px;">
277
+ <zn-thumbnail
278
+ src="https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=600&q=60"
279
+ caption="Selected"
280
+ selected>
281
+ </zn-thumbnail>
282
+ </div>
283
+ <div style="width: 160px;">
284
+ <zn-thumbnail
285
+ src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60"
286
+ caption="Active"
287
+ icon="play_arrow"
288
+ active>
289
+ </zn-thumbnail>
290
+ </div>
291
+ <div style="width: 160px;">
292
+ <zn-thumbnail
293
+ src="https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=600&q=60"
294
+ caption="Both"
295
+ selected
296
+ active>
297
+ </zn-thumbnail>
298
+ </div>
299
+ </div>
300
+ ```
301
+
302
+ ### Disabled
303
+
304
+ A disabled thumbnail is dimmed, emits no `zn-select`, and renders as a plain element rather than a link.
305
+
306
+ ```html:preview
307
+ <div style="width: 180px;">
308
+ <zn-thumbnail
309
+ src="https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05?w=600&q=60"
310
+ caption="Processing"
311
+ href="/media/1"
312
+ disabled>
313
+ </zn-thumbnail>
314
+ </div>
315
+ ```
316
+
317
+ ### Custom Media
318
+
319
+ Leave `src` unset and slot your own media into the `image` slot (or the default slot) — a `<video>`, a `<canvas>`, or
320
+ an icon placeholder. Slotted media is stretched to fill the frame.
321
+
322
+ ```html:preview
323
+ <div style="display: flex; gap: 16px;">
324
+ <div style="width: 180px;">
325
+ <zn-thumbnail caption="No preview">
326
+ <zn-icon slot="image" src="image" size="32" color="disabled"></zn-icon>
327
+ </zn-thumbnail>
328
+ </div>
329
+ <div style="width: 180px;">
330
+ <zn-thumbnail caption="Colour block">
331
+ <div slot="image" style="background: linear-gradient(135deg, #8967ef, #38bdf8);"></div>
332
+ </zn-thumbnail>
333
+ </div>
334
+ </div>
335
+ ```
336
+
337
+ ### Without a Caption
338
+
339
+ Set `hide-caption` to render just the media frame.
340
+
341
+ ```html:preview
342
+ <div style="width: 180px;">
343
+ <zn-thumbnail
344
+ src="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=600&q=60"
345
+ caption="Hidden"
346
+ hide-caption>
347
+ </zn-thumbnail>
348
+ </div>
349
+ ```
@@ -45,6 +45,40 @@ Use the `inline` attribute to display the well as an inline-flex element, allowi
45
45
  </p>
46
46
  ```
47
47
 
48
+ ### Preformatted Content
49
+
50
+ Use the `pre` attribute to render the content inside a `pre` element. Whitespace and line breaks are preserved and the content is rendered in a monospace font. Long lines scroll horizontally rather than widening the well.
51
+
52
+ ```html:preview
53
+ <zn-well pre icon="terminal">$ zinc build --watch
54
+ compiling components...
55
+ done in 1.2s</zn-well>
56
+ ```
57
+
58
+ ### Breaking Long Words
59
+
60
+ Use the `break-long` attribute to break long unbroken strings — tokens, hashes, URLs — so they wrap inside the well instead of forcing it wider than its container.
61
+
62
+ ```html:preview
63
+ <div style="width: 320px;">
64
+ <p>Without <code>break-long</code>:</p>
65
+ <zn-well icon="key">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJVadQssw5c</zn-well>
66
+
67
+ <p>With <code>break-long</code>:</p>
68
+ <zn-well break-long icon="key">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJVadQssw5c</zn-well>
69
+ </div>
70
+ ```
71
+
72
+ ### Preformatted and Broken
73
+
74
+ Combine `pre` and `break-long` to keep the monospace font and line breaks while still wrapping long lines instead of scrolling them.
75
+
76
+ ```html:preview
77
+ <div style="width: 320px;">
78
+ <zn-well pre break-long icon="key">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJVadQssw5c</zn-well>
79
+ </div>
80
+ ```
81
+
48
82
  ### Inline vs Block
49
83
 
50
84
  Compare the difference between inline and block (default) display modes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kubex/zinc",
3
- "version": "1.1.97",
3
+ "version": "1.1.99",
4
4
  "description": "A collection of web components for building web applications based off of @shoelace-style/Shoelace",
5
5
  "keywords": [
6
6
  "web components",
@@ -0,0 +1,111 @@
1
+ import {type CSSResultGroup, html, unsafeCSS} from 'lit';
2
+ import {property} from 'lit/decorators.js';
3
+ import {ResizeController} from '@lit-labs/observers/resize-controller.js';
4
+ import {styleMap} from 'lit/directives/style-map.js';
5
+ import ZincElement from '../../internal/zinc-element';
6
+ import ZnIcon from '../icon';
7
+
8
+ import styles from './background.scss';
9
+
10
+ export type BackgroundImageStrength = 'soft' | 'medium' | 'full';
11
+ export type BackgroundMotion = 'none' | 'drift' | 'breathe';
12
+ export type BackgroundOverlay = 'none' | 'soft' | 'strong';
13
+ export type BackgroundOverlayTone = 'light' | 'dark';
14
+
15
+ /**
16
+ * @summary Composes a colour, decorative image, image strength, optional motion and contrast overlay behind slotted content.
17
+ *
18
+ * @documentation https://zinc.style/components/background
19
+ * @status experimental
20
+ * @since 1.0
21
+ *
22
+ * @dependency zn-icon
23
+ *
24
+ * @slot - Content displayed above the background layers.
25
+ *
26
+ * @csspart base - The component's full-size background canvas.
27
+ * @csspart image - The decorative background image.
28
+ * @csspart overlay - The contrast overlay between the image and content.
29
+ * @csspart floating-icons - The non-interactive layer containing the floating icons.
30
+ * @csspart floating-icon - Each floating `zn-icon`.
31
+ * @csspart content - The wrapper around the default slot.
32
+ *
33
+ * @cssproperty --zn-background-color - Fallback colour when the `color` attribute is not set.
34
+ * @cssproperty --zn-background-image-position - Position of the background image. Defaults to `center`.
35
+ * @cssproperty --zn-background-overlay-angle - Direction of the overlay gradient. Defaults to `110deg`.
36
+ * @cssproperty --zn-background-floating-icon-color - Colour of the floating icons. Defaults to `currentColor`.
37
+ */
38
+ export default class ZnBackground extends ZincElement {
39
+ static styles: CSSResultGroup = unsafeCSS(styles);
40
+ static dependencies = {'zn-icon': ZnIcon};
41
+
42
+ private readonly resizeObserver = new ResizeController<number>(this, {
43
+ callback: entries => {
44
+ const width = entries[0]?.contentRect.width ?? this.offsetWidth;
45
+ return Math.max(1, Math.min(width * 0.05, 150));
46
+ },
47
+ });
48
+
49
+ /** URL of the decorative background image. */
50
+ @property() image = '';
51
+
52
+ /** CSS colour painted beneath the image. */
53
+ @property() color = '';
54
+
55
+ /** Visibility of the image: `soft` (30%), `medium` (62%) or `full` (100%). */
56
+ @property({attribute: 'image-strength', reflect: true}) imageStrength: BackgroundImageStrength = 'full';
57
+
58
+ /** Subtle animation applied to the image. Motion stops when reduced motion is requested. */
59
+ @property({reflect: true}) motion: BackgroundMotion = 'none';
60
+
61
+ /** Strength of the contrast gradient above the image. */
62
+ @property({reflect: true}) overlay: BackgroundOverlay = 'soft';
63
+
64
+ /** Whether the overlay uses a light or dark contrast treatment. */
65
+ @property({attribute: 'overlay-tone', reflect: true}) overlayTone: BackgroundOverlayTone = 'light';
66
+
67
+ /** Comma-separated Zinc icon names placed as ambient decoration. At most eight are rendered. */
68
+ @property({attribute: 'floating-icons'}) floatingIcons = '';
69
+
70
+ /** Pauses background motion without changing the selected motion treatment. */
71
+ @property({type: Boolean, reflect: true}) paused = false;
72
+
73
+ render() {
74
+ const floatingIcons = this.floatingIcons
75
+ .split(',')
76
+ .map(icon => icon.trim())
77
+ .filter(Boolean)
78
+ .slice(0, 8);
79
+ const floatingIconSize = this.resizeObserver.value ?? 1;
80
+
81
+ return html`
82
+ <div
83
+ part="base"
84
+ class="background"
85
+ style=${styleMap({'--_zn-background-color': this.color || undefined})}>
86
+ ${this.image ? html`
87
+ <img
88
+ part="image"
89
+ class="background__image"
90
+ src=${this.image}
91
+ alt=""
92
+ decoding="async">
93
+ ` : ''}
94
+ <div part="overlay" class="background__overlay" aria-hidden="true"></div>
95
+ ${floatingIcons.length ? html`
96
+ <div part="floating-icons" class="background__floating-icons" aria-hidden="true">
97
+ ${floatingIcons.map(icon => html`
98
+ <zn-icon
99
+ part="floating-icon"
100
+ class="background__floating-icon"
101
+ src=${icon}
102
+ size=${floatingIconSize}
103
+ aria-hidden="true"></zn-icon>
104
+ `)}
105
+ </div>
106
+ ` : ''}
107
+ <div part="content" class="background__content"><slot></slot></div>
108
+ </div>
109
+ `;
110
+ }
111
+ }