@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,187 @@
1
+ @use "sass:map";
2
+
3
+ /*
4
+ * Shared presentation for "selection cards" — contained radios and checkboxes that
5
+ * render an image, a title, supporting text, and a repositionable indicator.
6
+ *
7
+ * The host component adds `.selection-card` (plus modifiers) to its `part="base"`
8
+ * element and renders `.selection-card__control`, `.selection-card__image-container`
9
+ * and `.selection-card__content` inside it. Everything is scoped to
10
+ * `:host([contained]) .selection-card` so these rules outrank the plain contained
11
+ * styles, and so a contained radio or checkbox without card content is untouched.
12
+ */
13
+
14
+ $control-positions: (
15
+ "top-left": (block: start, inline: start),
16
+ "top-center": (block: start, inline: center),
17
+ "top-right": (block: start, inline: end),
18
+ "center-left": (block: center, inline: start),
19
+ "center": (block: center, inline: center),
20
+ "center-right": (block: center, inline: end),
21
+ "bottom-left": (block: end, inline: start),
22
+ "bottom-center": (block: end, inline: center),
23
+ "bottom-right": (block: end, inline: end),
24
+ );
25
+
26
+ :host([contained]) .selection-card {
27
+ --selection-card-padding: var(--zn-selection-card-padding, var(--zn-spacing-large));
28
+ --selection-card-gap: var(--zn-selection-card-gap, var(--zn-spacing-medium));
29
+ --selection-card-image-width: var(--zn-selection-card-image-width, 5rem);
30
+ --selection-card-image-height: var(--zn-selection-card-image-height, 5rem);
31
+ --selection-card-control-offset: var(--zn-selection-card-control-offset, var(--zn-spacing-medium));
32
+
33
+ /* Space an edge-positioned control needs so content never runs underneath it. */
34
+ --selection-card-control-gutter: calc(var(--selection-card-control-offset) + var(--toggle-size) + var(--selection-card-gap));
35
+
36
+ align-items: center;
37
+ align-content: center;
38
+ gap: var(--selection-card-gap);
39
+ padding: var(--selection-card-padding);
40
+
41
+ .selection-card__content {
42
+ flex: 1 1 auto;
43
+ min-width: 0;
44
+ margin-inline-start: 0;
45
+ line-height: var(--zn-line-height-normal);
46
+ }
47
+
48
+ .selection-card__title {
49
+ display: block;
50
+ font-size: var(--zn-selection-card-title-font-size, var(--zn-font-size-large));
51
+ font-weight: var(--zn-font-weight-semibold);
52
+ line-height: var(--zn-line-height-dense);
53
+ }
54
+
55
+ /* Images */
56
+ &.selection-card--has-image {
57
+ min-height: var(--zn-selection-card-min-height, 9rem);
58
+
59
+ /* Beside an image the text keeps a readable column, and wraps below it when there isn't room. */
60
+ flex-wrap: wrap;
61
+
62
+ .selection-card__content {
63
+ flex-basis: var(--zn-selection-card-content-min-width, 8rem);
64
+ }
65
+ }
66
+
67
+ .selection-card__image-container {
68
+ flex: 0 0 auto;
69
+ display: flex;
70
+ align-items: center;
71
+ justify-content: center;
72
+
73
+ ::slotted(*) {
74
+ display: block;
75
+ max-width: 100%;
76
+ max-height: var(--selection-card-image-height);
77
+ }
78
+ }
79
+
80
+ .selection-card__image {
81
+ display: block;
82
+ width: var(--selection-card-image-width);
83
+ max-width: 100%;
84
+ height: var(--selection-card-image-height);
85
+ object-fit: contain;
86
+ }
87
+
88
+ /* The image renders before the content, so only trailing positions need reordering. */
89
+ &.selection-card--image-right,
90
+ &.selection-card--image-bottom {
91
+ .selection-card__image-container {
92
+ order: 2;
93
+ }
94
+
95
+ .selection-card__content {
96
+ order: 1;
97
+ }
98
+ }
99
+
100
+ &.selection-card--image-top,
101
+ &.selection-card--image-bottom {
102
+ flex-direction: column;
103
+ flex-wrap: nowrap;
104
+ align-items: stretch;
105
+ justify-content: center;
106
+
107
+ .selection-card__image-container {
108
+ align-self: center;
109
+ }
110
+
111
+ .selection-card__content {
112
+ /* The basis above is a width; in a column it would set the text block's height. */
113
+ flex: 0 0 auto;
114
+ text-align: center;
115
+ }
116
+
117
+ /* Centred text stays centred: mirror the gutter an edge control needs on both sides. */
118
+ @each $name, $position in $control-positions {
119
+ @if map.get($position, inline) != center {
120
+ &.selection-card--control-#{$name} {
121
+ padding-inline: var(--selection-card-control-gutter);
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ /* Positioned controls */
128
+ @each $name, $position in $control-positions {
129
+ $block: map.get($position, block);
130
+ $inline: map.get($position, inline);
131
+
132
+ &.selection-card--control-#{$name} {
133
+ @if $inline == start {
134
+ padding-inline-start: var(--selection-card-control-gutter);
135
+ } @else if $inline == end {
136
+ padding-inline-end: var(--selection-card-control-gutter);
137
+ } @else if $block == start {
138
+ padding-block-start: var(--selection-card-control-gutter);
139
+ } @else if $block == end {
140
+ padding-block-end: var(--selection-card-control-gutter);
141
+ }
142
+
143
+ .selection-card__control {
144
+ position: absolute;
145
+ z-index: 1;
146
+ transform: translate(var(--selection-card-control-shift-x, 0), var(--selection-card-control-shift-y, 0));
147
+
148
+ @if $block == center {
149
+ --selection-card-control-shift-y: -50%;
150
+
151
+ inset-block-start: 50%;
152
+ } @else {
153
+ inset-block-#{$block}: var(--selection-card-control-offset);
154
+ }
155
+
156
+ @if $inline == center {
157
+ --selection-card-control-shift-x: -50%;
158
+
159
+ inset-inline-start: 50%;
160
+ } @else {
161
+ inset-inline-#{$inline}: var(--selection-card-control-offset);
162
+ }
163
+ }
164
+ }
165
+ }
166
+
167
+ /* Hidden control — the card itself becomes the visible indicator. */
168
+ &.selection-card--control-none {
169
+ .selection-card__control {
170
+ display: none;
171
+ }
172
+
173
+ &:has(input:focus-visible) {
174
+ outline: var(--zn-focus-ring);
175
+ outline-offset: var(--zn-focus-ring-offset);
176
+ }
177
+ }
178
+ }
179
+
180
+ /* Contained radios and checkboxes are rounded by default; `square` opts out. */
181
+ :host([contained]) [part~="base"] {
182
+ border-radius: var(--zn-selection-card-border-radius, var(--zn-border-radius));
183
+ }
184
+
185
+ :host([square]) [part~="base"] {
186
+ border-radius: 0;
187
+ }
@@ -1,5 +1,5 @@
1
1
  import {expect, fixture, html} from '@open-wc/testing';
2
- import {deepQuery} from './query';
2
+ import {deepQuery, idSelector} from './query';
3
3
 
4
4
  describe('deepQuery', () => {
5
5
  it('returns null when no element matches', async () => {
@@ -61,3 +61,20 @@ describe('deepQuery', () => {
61
61
  expect(deepQuery('.needle', b)).to.be.null;
62
62
  });
63
63
  });
64
+
65
+ describe('idSelector', () => {
66
+ it('escapes characters that CSS would otherwise treat as syntax', async () => {
67
+ const id = 'delete-enum-cloud_hosting_&_infrastructure';
68
+ const el = await fixture<HTMLElement>(html`<div id="${id}"></div>`);
69
+
70
+ expect(() => document.querySelector(`#${id}`)).to.throw();
71
+ expect(document.querySelector(idSelector(id))).to.equal(el);
72
+ expect(el.matches(idSelector(id))).to.be.true;
73
+ });
74
+
75
+ it('accepts an id that already carries a leading hash', async () => {
76
+ const el = await fixture<HTMLElement>(html`<div id="plain-id"></div>`);
77
+
78
+ expect(document.querySelector(idSelector('#plain-id'))).to.equal(el);
79
+ });
80
+ });
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Builds a valid `#id` selector. Ids can legally contain characters that CSS treats as syntax (`&`, `.`, `:`,
3
+ * a leading digit), so they must be escaped before being used in `querySelector`/`matches`.
4
+ */
5
+ export function idSelector(id: string): string {
6
+ return `#${CSS.escape(id.startsWith('#') ? id.slice(1) : id)}`;
7
+ }
8
+
1
9
  export function deepQuery<T extends Element = Element>(
2
10
  selector: string,
3
11
  root: Document | ShadowRoot | Element = document,
package/src/zinc.ts CHANGED
@@ -115,6 +115,9 @@ export { default as ThemeEditor } from './components/theme-editor';
115
115
  export { default as SlashMenu } from './components/slash-menu';
116
116
  export { default as SlashItem } from './components/slash-item';
117
117
  export { default as ScheduleBuilder } from './components/schedule-builder';
118
+ export { default as Thumbnail } from './components/thumbnail';
119
+ export { default as ThumbnailGroup } from './components/thumbnail-group';
120
+ export { default as Background } from './components/background';
118
121
  /* plop:component */
119
122
 
120
123
  // Base Component