@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,360 @@
1
+ @use "../../wc";
2
+
3
+ // Defaults live in var() fallbacks rather than on :host, so a wrapper or a zn-thumbnail-group
4
+ // can set any of these once for every thumbnail beneath it.
5
+ $aspect-ratio: var(--zn-thumbnail-aspect-ratio, 16 / 9);
6
+ $radius: var(--zn-thumbnail-radius, var(--zn-border-radius));
7
+
8
+ // A badge, an action or the preview trigger — each one its own chip floating on the media, so
9
+ // several of them read as separate icons rather than one grouped container.
10
+ @mixin chip {
11
+ display: inline-flex;
12
+ align-items: center;
13
+ justify-content: center;
14
+ min-width: 20px;
15
+ min-height: 20px;
16
+ padding: 2px;
17
+ border: none;
18
+ border-radius: var(--zn-thumbnail-chip-radius, var(--zn-border-radius));
19
+ background-color: var(--zn-thumbnail-chip-background, rgba(0, 0, 0, 0.6));
20
+ color: var(--zn-thumbnail-chip-color, #fff);
21
+ line-height: 0;
22
+ transition: background-color var(--zn-transition-fast) ease-in-out;
23
+ }
24
+
25
+ // Actions and the preview trigger are controls, so they take the pointer.
26
+ @mixin chip-interactive {
27
+ @include chip;
28
+
29
+ cursor: pointer;
30
+
31
+ &:hover {
32
+ background-color: var(--zn-thumbnail-chip-background-hover, rgba(0, 0, 0, 0.8));
33
+ }
34
+ }
35
+
36
+ :host {
37
+ display: block;
38
+ min-width: 0;
39
+ }
40
+
41
+ .thumbnail {
42
+ position: relative;
43
+ min-width: 0;
44
+ }
45
+
46
+ .thumbnail__link {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: var(--zn-spacing-x-small);
50
+ min-width: 0;
51
+ color: inherit;
52
+ text-decoration: none;
53
+ outline: none;
54
+ }
55
+
56
+ .thumbnail--interactive .thumbnail__link {
57
+ cursor: pointer;
58
+ }
59
+
60
+ .thumbnail__media {
61
+ position: relative;
62
+ aspect-ratio: #{$aspect-ratio};
63
+ width: 100%;
64
+ overflow: hidden;
65
+ border-radius: #{$radius};
66
+ background-color: rgb(var(--zn-panel));
67
+ // One ring, driven by custom properties the state rules below reassign. Routing every state
68
+ // through the same declaration avoids specificity fights between hover and the
69
+ // selected / active states.
70
+ --thumbnail-ring-color: rgb(var(--zn-border-color));
71
+ --thumbnail-ring-width: 1px;
72
+ --thumbnail-ring-gap: 0px;
73
+ }
74
+
75
+ // The ring is drawn on a pseudo-element rather than on the frame itself: an inset shadow paints
76
+ // under the frame's content, so the image would cover it. Positioning this above the media keeps
77
+ // the ring visible over the image while staying out of layout, so the group's horizontal
78
+ // scroller can't clip it.
79
+ //
80
+ // The gap ring is painted under the accent ring, so only the part of it that the accent
81
+ // doesn't cover shows — holding the accent off the image. At a 0 gap the two spreads match
82
+ // and the gap ring disappears entirely.
83
+ .thumbnail__media::after {
84
+ content: '';
85
+ position: absolute;
86
+ inset: 0;
87
+ z-index: 1;
88
+ border-radius: inherit;
89
+ pointer-events: none;
90
+ box-shadow:
91
+ inset 0 0 0 var(--thumbnail-ring-width) var(--thumbnail-ring-color),
92
+ inset 0 0 0 calc(var(--thumbnail-ring-width) + var(--thumbnail-ring-gap)) rgb(var(--zn-body));
93
+ transition: box-shadow var(--zn-transition-fast) ease-in-out;
94
+ }
95
+
96
+ .thumbnail__image {
97
+ display: block;
98
+ width: 100%;
99
+ height: 100%;
100
+ object-fit: cover;
101
+ }
102
+
103
+ // Slotted media fills the frame; anything else (an icon placeholder, a label) is centred
104
+ // at its natural size.
105
+ .thumbnail__slotted-media {
106
+ display: grid;
107
+ place-items: center;
108
+ width: 100%;
109
+ height: 100%;
110
+ }
111
+
112
+ .thumbnail__slotted-media::slotted(img),
113
+ .thumbnail__slotted-media::slotted(video),
114
+ .thumbnail__slotted-media::slotted(canvas),
115
+ .thumbnail__slotted-media::slotted(picture),
116
+ .thumbnail__slotted-media::slotted(div) {
117
+ width: 100%;
118
+ height: 100%;
119
+ object-fit: cover;
120
+ }
121
+
122
+ .thumbnail__caption {
123
+ @include wc.text-style(table-content);
124
+
125
+ min-width: 0;
126
+ overflow: hidden;
127
+ text-align: center;
128
+ text-overflow: ellipsis;
129
+ white-space: nowrap;
130
+ }
131
+
132
+ /* Overlay
133
+ *
134
+ * A layer over the media frame only — it mirrors the media's width and aspect ratio rather than
135
+ * covering the caption too. It sits outside the link, and is transparent to pointer events except
136
+ * on the chips themselves, so slotted actions keep their own click behaviour while the rest of the
137
+ * media still activates the link.
138
+ */
139
+
140
+ .thumbnail__overlay {
141
+ position: absolute;
142
+ top: 0;
143
+ left: 0;
144
+ right: 0;
145
+ aspect-ratio: #{$aspect-ratio};
146
+ border-radius: #{$radius};
147
+ overflow: hidden;
148
+ pointer-events: none;
149
+ }
150
+
151
+ .thumbnail__badge,
152
+ .thumbnail__actions,
153
+ .thumbnail__preview-button {
154
+ position: absolute;
155
+ display: flex;
156
+ align-items: center;
157
+ // Adjacent markers are spaced apart rather than sharing one container.
158
+ gap: var(--zn-thumbnail-chip-gap, var(--zn-spacing-2x-small));
159
+ }
160
+
161
+ .thumbnail__badge {
162
+ bottom: var(--zn-spacing-2x-small);
163
+ left: var(--zn-spacing-2x-small);
164
+ pointer-events: none;
165
+ }
166
+
167
+ .thumbnail__actions,
168
+ .thumbnail__preview-button {
169
+ pointer-events: auto;
170
+ }
171
+
172
+ .thumbnail__actions {
173
+ bottom: var(--zn-spacing-2x-small);
174
+ right: var(--zn-spacing-2x-small);
175
+ }
176
+
177
+ .thumbnail__preview-button {
178
+ @include chip-interactive;
179
+
180
+ top: var(--zn-spacing-2x-small);
181
+ right: var(--zn-spacing-2x-small);
182
+ }
183
+
184
+ // The slots themselves disappear so each slotted item becomes a flex item of its positioner,
185
+ // picking up the gap between markers.
186
+ .thumbnail__badge-items,
187
+ .thumbnail__action-items {
188
+ display: contents;
189
+ }
190
+
191
+ // A badge describes the asset rather than doing something, so it shares the chip's shape but is
192
+ // held back on opacity — enough to read as a marker instead of a control sitting next to real ones.
193
+ .thumbnail__badge-icon,
194
+ .thumbnail__badge-items::slotted(*) {
195
+ @include chip;
196
+
197
+ cursor: default;
198
+ opacity: var(--zn-thumbnail-badge-opacity, 0.65);
199
+ }
200
+
201
+ .thumbnail__action-items::slotted(*) {
202
+ @include chip-interactive;
203
+ }
204
+
205
+ /* Ring states
206
+ *
207
+ * Hover is excluded on a thumbnail that already carries a state ring, so hovering a selected or
208
+ * active thumbnail can't repaint its ring in the hover colour.
209
+ */
210
+
211
+ .thumbnail:hover:not(.thumbnail--disabled):not(.thumbnail--selected):not(.thumbnail--active) .thumbnail__media {
212
+ --thumbnail-ring-color: rgb(var(--zn-primary));
213
+ }
214
+
215
+ .thumbnail--selected .thumbnail__media {
216
+ --thumbnail-ring-color: var(--zn-thumbnail-selected-color, rgb(var(--zn-primary)));
217
+ --thumbnail-ring-width: 2px;
218
+ --thumbnail-ring-gap: 1px;
219
+ }
220
+
221
+ // Listed after `selected` so an active-and-selected thumbnail shows the active colour.
222
+ .thumbnail--active .thumbnail__media {
223
+ --thumbnail-ring-color: var(--zn-thumbnail-active-color, rgb(var(--zn-color-success)));
224
+ --thumbnail-ring-width: 2px;
225
+ --thumbnail-ring-gap: 1px;
226
+ }
227
+
228
+ /* Focus */
229
+
230
+ .thumbnail__link:focus-visible .thumbnail__media {
231
+ outline: var(--zn-focus-ring);
232
+ outline-offset: calc(-1 * var(--zn-focus-ring-width));
233
+ }
234
+
235
+ .thumbnail__preview-button:focus-visible,
236
+ .thumbnail__action-items::slotted(*:focus-visible) {
237
+ outline: var(--zn-focus-ring);
238
+ outline-offset: 1px;
239
+ }
240
+
241
+ /* Disabled */
242
+
243
+ .thumbnail--disabled {
244
+ .thumbnail__link {
245
+ cursor: not-allowed;
246
+ }
247
+
248
+ .thumbnail__media,
249
+ .thumbnail__caption {
250
+ opacity: 0.5;
251
+ }
252
+ }
253
+
254
+ /* Preview
255
+ *
256
+ * A native modal dialog, so it lands in the top layer and escapes the group's scroll container
257
+ * and any ancestor stacking context. The dialog is a transparent full-screen stage; the visible
258
+ * backdrop is a plain element inside it so its fade can be animated alongside the panel.
259
+ */
260
+
261
+ .thumbnail__preview {
262
+ position: fixed;
263
+ inset: 0;
264
+ display: none;
265
+ width: 100%;
266
+ max-width: none;
267
+ height: 100%;
268
+ max-height: none;
269
+ padding: 0;
270
+ border: none;
271
+ background: transparent;
272
+ overflow: hidden;
273
+
274
+ &[open] {
275
+ display: grid;
276
+ place-items: center;
277
+ }
278
+
279
+ &::backdrop {
280
+ background: transparent;
281
+ }
282
+ }
283
+
284
+ .thumbnail__preview-backdrop {
285
+ position: fixed;
286
+ inset: 0;
287
+ background: var(--zn-overlay-background-color);
288
+ }
289
+
290
+ .thumbnail__preview-frame {
291
+ // The panel takes the asset's own aspect ratio — measured in JS and published as
292
+ // --zn-thumbnail-preview-measured-ratio — so it wraps the image rather than letterboxing it in a
293
+ // fixed-ratio box. That also puts the close button on the image's corner rather than a container's.
294
+ --preview-max-width: var(--zn-thumbnail-preview-max-width, 70vw);
295
+ --preview-max-height: var(--zn-thumbnail-preview-max-height, 70vh);
296
+ --preview-ratio: var(--zn-thumbnail-preview-aspect-ratio,
297
+ var(--zn-thumbnail-preview-measured-ratio, #{$aspect-ratio}));
298
+
299
+ position: relative;
300
+ // Grow to the width cap, unless the ratio would then push the height past its own cap — in which
301
+ // case the height leads and the width follows it. Sizing the panel from viewport units rather
302
+ // than from the image keeps it layout-determined, so the grow animation can measure its target
303
+ // before the full-size asset has loaded.
304
+ width: min(var(--preview-max-width), calc(var(--preview-max-height) * (var(--preview-ratio))));
305
+ max-width: var(--preview-max-width);
306
+ max-height: var(--preview-max-height);
307
+ aspect-ratio: var(--preview-ratio);
308
+ overflow: hidden;
309
+ border-radius: var(--zn-thumbnail-preview-radius, var(--zn-border-radius));
310
+ background-color: rgb(var(--zn-panel));
311
+ box-shadow: var(--zn-shadow-x-large);
312
+ // The panel is scaled down onto the thumbnail's box to open, so it has to transform
313
+ // about its own centre.
314
+ transform-origin: center center;
315
+ }
316
+
317
+ .thumbnail__preview-image,
318
+ .thumbnail__preview-placeholder {
319
+ display: block;
320
+ width: 100%;
321
+ height: 100%;
322
+ object-fit: contain;
323
+ }
324
+
325
+ // Held behind the full-size asset so the panel is never empty while it loads. Covered rather than
326
+ // contained, and slightly overscaled, so the blur's soft edge stays inside the panel.
327
+ .thumbnail__preview-placeholder {
328
+ position: absolute;
329
+ inset: 0;
330
+ object-fit: cover;
331
+ filter: blur(12px);
332
+ transform: scale(1.05);
333
+ }
334
+
335
+ .thumbnail__preview-media::slotted(*) {
336
+ position: relative;
337
+ display: block;
338
+ width: 100%;
339
+ height: 100%;
340
+ object-fit: contain;
341
+ }
342
+
343
+ .thumbnail__preview-image {
344
+ position: relative;
345
+ }
346
+
347
+ .thumbnail__preview-close {
348
+ @include chip-interactive;
349
+
350
+ position: absolute;
351
+ top: var(--zn-spacing-x-small);
352
+ right: var(--zn-spacing-x-small);
353
+ min-width: 28px;
354
+ min-height: 28px;
355
+
356
+ &:focus-visible {
357
+ outline: var(--zn-focus-ring);
358
+ outline-offset: 1px;
359
+ }
360
+ }