@marianmeres/stuic 3.179.0 → 3.181.0
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.
- package/AGENTS.md +2 -2
- package/dist/components/ColorPicker/ColorPicker.svelte +457 -0
- package/dist/components/ColorPicker/ColorPicker.svelte.d.ts +75 -0
- package/dist/components/ColorPicker/README.md +220 -0
- package/dist/components/ColorPicker/color-value.d.ts +32 -0
- package/dist/components/ColorPicker/color-value.js +55 -0
- package/dist/components/ColorPicker/i18n-sk.d.ts +17 -0
- package/dist/components/ColorPicker/i18n-sk.js +48 -0
- package/dist/components/ColorPicker/i18n.d.ts +64 -0
- package/dist/components/ColorPicker/i18n.js +75 -0
- package/dist/components/ColorPicker/index.css +275 -0
- package/dist/components/ColorPicker/index.d.ts +4 -0
- package/dist/components/ColorPicker/index.js +4 -0
- package/dist/components/ColorPicker/palettes.d.ts +41 -0
- package/dist/components/ColorPicker/palettes.js +49 -0
- package/dist/components/FieldsBuilder/FieldsBuilder.svelte +43 -18
- package/dist/components/FieldsBuilder/FieldsBuilder.svelte.d.ts +15 -1
- package/dist/components/FieldsBuilder/README.md +65 -30
- package/dist/components/FieldsBuilder/_internal/OptionsEditor.svelte +10 -1
- package/dist/components/FieldsBuilder/_internal/OptionsEditor.svelte.d.ts +3 -0
- package/dist/components/FieldsBuilder/types.d.ts +7 -2
- package/dist/components/FieldsBuilder/utils.d.ts +13 -3
- package/dist/components/FieldsBuilder/utils.js +9 -13
- package/dist/components/Nav/Nav.svelte +7 -2
- package/dist/components/Nav/Nav.svelte.d.ts +7 -2
- package/dist/components/Nav/README.md +2 -2
- package/dist/components/TabbedMenu/README.md +14 -13
- package/dist/components/TabbedMenu/TabbedMenu.svelte +7 -2
- package/dist/components/TabbedMenu/TabbedMenu.svelte.d.ts +7 -2
- package/dist/index.css +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/tr.d.ts +26 -14
- package/dist/utils/tr.js +43 -19
- package/docs/_archive/maybe-todo.md +9 -2
- package/docs/domains/components.md +58 -1
- package/package.json +1 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
COLOR PICKER COMPONENT TOKENS
|
|
3
|
+
Override globally: :root { --stuic-color-picker-swatch-size: 2rem; }
|
|
4
|
+
Override locally: <ColorPicker style="--stuic-color-picker-gap: 0.5rem;">
|
|
5
|
+
============================================================================ */
|
|
6
|
+
|
|
7
|
+
/* prettier-ignore */
|
|
8
|
+
:root {
|
|
9
|
+
/* Layout */
|
|
10
|
+
--stuic-color-picker-gap: 0.375rem;
|
|
11
|
+
--stuic-color-picker-custom-gap: 0.5rem;
|
|
12
|
+
--stuic-color-picker-swatch-size: 1.75rem;
|
|
13
|
+
/* Touch bump: the swatches are the whole hit target, so on a coarse pointer
|
|
14
|
+
they must reach the ~44px recommendation on their own. */
|
|
15
|
+
--stuic-color-picker-swatch-size-touch: 2.75rem;
|
|
16
|
+
|
|
17
|
+
/* Swatch: a hairline keeps white / transparent / near-background swatches
|
|
18
|
+
visible on any theme. */
|
|
19
|
+
--stuic-color-picker-swatch-border: color-mix(in oklab, var(--stuic-color-foreground) 20%, transparent);
|
|
20
|
+
--stuic-color-picker-swatch-scale-hover: 1.1;
|
|
21
|
+
|
|
22
|
+
/* Selected ring — drawn OUTSIDE the swatch (a gap of page background, then
|
|
23
|
+
the ring) so it reads on any color without measuring its luminance. */
|
|
24
|
+
--stuic-color-picker-swatch-ring-width: 2px;
|
|
25
|
+
--stuic-color-picker-swatch-ring-gap: 2px;
|
|
26
|
+
--stuic-color-picker-swatch-ring-color: var(--stuic-color-foreground);
|
|
27
|
+
--stuic-color-picker-swatch-ring-gap-color: var(--stuic-color-background);
|
|
28
|
+
|
|
29
|
+
/* Focus ring */
|
|
30
|
+
--stuic-color-picker-ring-width: 2px;
|
|
31
|
+
--stuic-color-picker-ring-color: var(--stuic-color-ring);
|
|
32
|
+
|
|
33
|
+
/* The "no color" swatch (diagonal slash) */
|
|
34
|
+
--stuic-color-picker-clear-color: var(--stuic-color-destructive);
|
|
35
|
+
--stuic-color-picker-clear-bg: transparent;
|
|
36
|
+
|
|
37
|
+
/* Hex text field */
|
|
38
|
+
--stuic-color-picker-text-width: 10ch;
|
|
39
|
+
--stuic-color-picker-text-bg: var(--stuic-color-input);
|
|
40
|
+
--stuic-color-picker-text-border: var(--stuic-color-border);
|
|
41
|
+
--stuic-color-picker-text-color: var(--stuic-color-foreground);
|
|
42
|
+
--stuic-color-picker-text-placeholder: color-mix(in oklab, var(--stuic-color-muted-foreground) 75%, transparent);
|
|
43
|
+
--stuic-color-picker-text-font-family: var(--font-mono);
|
|
44
|
+
--stuic-color-picker-text-font-size: var(--text-sm);
|
|
45
|
+
/* See the "IOS ZOOM GUARD" section at the bottom of this file. */
|
|
46
|
+
--stuic-color-picker-text-font-size-touch-min: 16px;
|
|
47
|
+
|
|
48
|
+
/* Disabled */
|
|
49
|
+
--stuic-color-picker-opacity-disabled: 0.5;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@layer components {
|
|
53
|
+
/* ============================================================================
|
|
54
|
+
BASE
|
|
55
|
+
============================================================================ */
|
|
56
|
+
|
|
57
|
+
.stuic-color-picker {
|
|
58
|
+
--_size: var(--stuic-color-picker-swatch-size);
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
align-items: flex-start;
|
|
62
|
+
gap: var(--stuic-color-picker-custom-gap);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.stuic-color-picker[data-disabled] {
|
|
66
|
+
opacity: var(--stuic-color-picker-opacity-disabled);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* ============================================================================
|
|
70
|
+
SWATCHES (the radiogroup)
|
|
71
|
+
============================================================================ */
|
|
72
|
+
|
|
73
|
+
.stuic-color-picker-swatches {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-wrap: wrap;
|
|
76
|
+
gap: var(--stuic-color-picker-gap);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* `columns` is a cap, not a grid: the row is exactly wide enough for N
|
|
80
|
+
swatches, so it holds N — and on a screen too narrow for that it wraps to
|
|
81
|
+
fewer instead of pushing the page sideways. (A real N-column grid would
|
|
82
|
+
overflow: 8 x 44px + gaps does not fit a phone.) The keyboard follows the
|
|
83
|
+
rendered rows, not this number — see `rowLength()`. */
|
|
84
|
+
.stuic-color-picker-swatches[data-columns] {
|
|
85
|
+
max-inline-size: calc(
|
|
86
|
+
var(--stuic-color-picker-columns, 6) * var(--_size) +
|
|
87
|
+
(var(--stuic-color-picker-columns, 6) - 1) * var(--stuic-color-picker-gap)
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* ============================================================================
|
|
92
|
+
SWATCH
|
|
93
|
+
============================================================================ */
|
|
94
|
+
|
|
95
|
+
.stuic-color-picker-swatch {
|
|
96
|
+
box-sizing: border-box;
|
|
97
|
+
inline-size: var(--_size);
|
|
98
|
+
block-size: var(--_size);
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 0;
|
|
101
|
+
appearance: none;
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
-webkit-tap-highlight-color: transparent;
|
|
104
|
+
background-color: var(--stuic-color-picker-swatch-color, transparent);
|
|
105
|
+
/* the hairline must not be tinted by the swatch color underneath it */
|
|
106
|
+
background-clip: padding-box;
|
|
107
|
+
border: var(--stuic-color-picker-swatch-border-width, var(--stuic-border-width)) solid
|
|
108
|
+
var(--stuic-color-picker-swatch-border);
|
|
109
|
+
border-radius: var(--stuic-color-picker-swatch-radius, var(--stuic-radius));
|
|
110
|
+
transition:
|
|
111
|
+
transform var(--stuic-color-picker-transition, var(--stuic-transition)),
|
|
112
|
+
box-shadow var(--stuic-color-picker-transition, var(--stuic-transition));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@media (hover: hover) {
|
|
116
|
+
.stuic-color-picker-swatch:hover:not(:disabled) {
|
|
117
|
+
transform: scale(var(--stuic-color-picker-swatch-scale-hover));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.stuic-color-picker-swatch:disabled {
|
|
122
|
+
cursor: default;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* The selected marker: a gap of background, then the ring. Two stacked
|
|
126
|
+
shadows rather than an outline, so the focus outline stays available. */
|
|
127
|
+
.stuic-color-picker-swatch[data-selected] {
|
|
128
|
+
box-shadow:
|
|
129
|
+
0 0 0 var(--stuic-color-picker-swatch-ring-gap)
|
|
130
|
+
var(--stuic-color-picker-swatch-ring-gap-color),
|
|
131
|
+
0 0 0
|
|
132
|
+
calc(
|
|
133
|
+
var(--stuic-color-picker-swatch-ring-gap) +
|
|
134
|
+
var(--stuic-color-picker-swatch-ring-width)
|
|
135
|
+
)
|
|
136
|
+
var(--stuic-color-picker-swatch-ring-color);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.stuic-color-picker-swatch:focus-visible {
|
|
140
|
+
outline: var(--stuic-color-picker-ring-width) solid
|
|
141
|
+
var(--stuic-color-picker-ring-color);
|
|
142
|
+
outline-offset: calc(
|
|
143
|
+
var(--stuic-color-picker-swatch-ring-gap) +
|
|
144
|
+
var(--stuic-color-picker-swatch-ring-width)
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* The "no color" swatch: a diagonal slash across an empty chip */
|
|
149
|
+
.stuic-color-picker-swatch[data-clear] {
|
|
150
|
+
background-color: var(--stuic-color-picker-clear-bg);
|
|
151
|
+
background-image: linear-gradient(
|
|
152
|
+
to top right,
|
|
153
|
+
transparent calc(50% - 0.5px),
|
|
154
|
+
var(--stuic-color-picker-clear-color) calc(50% - 0.5px),
|
|
155
|
+
var(--stuic-color-picker-clear-color) calc(50% + 0.5px),
|
|
156
|
+
transparent calc(50% + 0.5px)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/* ============================================================================
|
|
161
|
+
CUSTOM ROW (native picker + hex field)
|
|
162
|
+
============================================================================ */
|
|
163
|
+
|
|
164
|
+
.stuic-color-picker-custom {
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-wrap: wrap;
|
|
167
|
+
align-items: center;
|
|
168
|
+
gap: var(--stuic-color-picker-gap);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* The native `<input type="color">`, shaped like one more swatch. */
|
|
172
|
+
.stuic-color-picker-native {
|
|
173
|
+
box-sizing: border-box;
|
|
174
|
+
inline-size: var(--_size);
|
|
175
|
+
block-size: var(--_size);
|
|
176
|
+
margin: 0;
|
|
177
|
+
padding: 0;
|
|
178
|
+
appearance: none;
|
|
179
|
+
-webkit-appearance: none;
|
|
180
|
+
background: none;
|
|
181
|
+
cursor: pointer;
|
|
182
|
+
border: var(--stuic-color-picker-swatch-border-width, var(--stuic-border-width)) solid
|
|
183
|
+
var(--stuic-color-picker-swatch-border);
|
|
184
|
+
border-radius: var(--stuic-color-picker-swatch-radius, var(--stuic-radius));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.stuic-color-picker-native:disabled {
|
|
188
|
+
cursor: default;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.stuic-color-picker-native::-webkit-color-swatch-wrapper {
|
|
192
|
+
padding: 0;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.stuic-color-picker-native::-webkit-color-swatch {
|
|
196
|
+
border: none;
|
|
197
|
+
border-radius: calc(
|
|
198
|
+
var(--stuic-color-picker-swatch-radius, var(--stuic-radius)) - 1px
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.stuic-color-picker-native::-moz-color-swatch {
|
|
203
|
+
border: none;
|
|
204
|
+
border-radius: calc(
|
|
205
|
+
var(--stuic-color-picker-swatch-radius, var(--stuic-radius)) - 1px
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.stuic-color-picker-native:focus-visible {
|
|
210
|
+
outline: var(--stuic-color-picker-ring-width) solid
|
|
211
|
+
var(--stuic-color-picker-ring-color);
|
|
212
|
+
outline-offset: 2px;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/* The hex field. Deliberately not `.stuic-input` — that is a whole field
|
|
216
|
+
wrapper (label, description, error box); this is one bare control. */
|
|
217
|
+
.stuic-color-picker-text {
|
|
218
|
+
box-sizing: border-box;
|
|
219
|
+
inline-size: var(--stuic-color-picker-text-width);
|
|
220
|
+
min-inline-size: 0;
|
|
221
|
+
min-block-size: var(--_size);
|
|
222
|
+
padding-inline: 0.5rem;
|
|
223
|
+
padding-block: 0.25rem;
|
|
224
|
+
font-family: var(--stuic-color-picker-text-font-family);
|
|
225
|
+
font-size: var(--stuic-color-picker-text-font-size);
|
|
226
|
+
color: var(--stuic-color-picker-text-color);
|
|
227
|
+
background-color: var(--stuic-color-picker-text-bg);
|
|
228
|
+
border: var(--stuic-color-picker-text-border-width, var(--stuic-border-width)) solid
|
|
229
|
+
var(--stuic-color-picker-text-border);
|
|
230
|
+
border-radius: var(--stuic-color-picker-text-radius, var(--stuic-radius));
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.stuic-color-picker-text::placeholder {
|
|
234
|
+
color: var(--stuic-color-picker-text-placeholder);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.stuic-color-picker-text:focus-visible {
|
|
238
|
+
outline: var(--stuic-color-picker-ring-width) solid
|
|
239
|
+
var(--stuic-color-picker-ring-color);
|
|
240
|
+
outline-offset: 1px;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/* ============================================================================
|
|
244
|
+
TOUCH — the swatches are the entire hit target, so they carry the size
|
|
245
|
+
============================================================================ */
|
|
246
|
+
|
|
247
|
+
@media (pointer: coarse) {
|
|
248
|
+
.stuic-color-picker {
|
|
249
|
+
--_size: var(--stuic-color-picker-swatch-size-touch);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/* ============================================================================
|
|
255
|
+
IOS ZOOM GUARD
|
|
256
|
+
|
|
257
|
+
Mobile WebKit auto-zooms the viewport when a text control whose computed
|
|
258
|
+
font-size is below 16px receives focus, and the hex field defaults to 14px.
|
|
259
|
+
Same two conditions (and the same reasoning) as the guard in `Input/index.css`
|
|
260
|
+
— an Apple/WebKit engine AND a touch-capable device — and likewise unlayered,
|
|
261
|
+
so it also wins over a Tailwind text-size utility put on the field.
|
|
262
|
+
|
|
263
|
+
Opt out with `--stuic-color-picker-text-font-size-touch-min: 0px`.
|
|
264
|
+
============================================================================ */
|
|
265
|
+
|
|
266
|
+
@supports (font: -apple-system-body) or (-webkit-touch-callout: none) {
|
|
267
|
+
@media (any-pointer: coarse) {
|
|
268
|
+
.stuic-color-picker-text {
|
|
269
|
+
font-size: max(
|
|
270
|
+
var(--stuic-color-picker-text-font-size-touch-min),
|
|
271
|
+
var(--stuic-color-picker-text-font-size)
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as ColorPicker, type Props as ColorPickerProps, type ColorPickerCustom, } from "./ColorPicker.svelte";
|
|
2
|
+
export { COLOR_PICKER_PALETTE, COLOR_PICKER_PALETTE_THEME, type ColorPickerSwatch, type ColorPickerSwatchObject, } from "./palettes.js";
|
|
3
|
+
export { createColorPickerT, COLOR_PICKER_MESSAGES_EN, type ColorPickerMessageKey, type ColorPickerMessages, } from "./i18n.js";
|
|
4
|
+
export { COLOR_PICKER_MESSAGES_SK } from "./i18n-sk.js";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { default as ColorPicker, } from "./ColorPicker.svelte";
|
|
2
|
+
export { COLOR_PICKER_PALETTE, COLOR_PICKER_PALETTE_THEME, } from "./palettes.js";
|
|
3
|
+
export { createColorPickerT, COLOR_PICKER_MESSAGES_EN, } from "./i18n.js";
|
|
4
|
+
export { COLOR_PICKER_MESSAGES_SK } from "./i18n-sk.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/** One palette entry: a bare CSS color string, or a color with a label. */
|
|
2
|
+
export type ColorPickerSwatch = string | ColorPickerSwatchObject;
|
|
3
|
+
/** The object form of a palette entry. */
|
|
4
|
+
export interface ColorPickerSwatchObject {
|
|
5
|
+
/**
|
|
6
|
+
* Any CSS color string — `#3b82f6`, `oklch(62.8% 0.258 29.2)`, `rgb(0 0 0)`,
|
|
7
|
+
* `transparent`, or a custom property reference like
|
|
8
|
+
* `var(--stuic-color-primary)`. Rendered as-is; never parsed.
|
|
9
|
+
*/
|
|
10
|
+
value: string;
|
|
11
|
+
/**
|
|
12
|
+
* Accessible name (and `title`) of the swatch. Passed through the component's
|
|
13
|
+
* `t` with itself as the fallback, so plain labels ("Brand blue") render
|
|
14
|
+
* verbatim while short keys ("red") get translated by a bundled catalog.
|
|
15
|
+
* Defaults to `value`.
|
|
16
|
+
*/
|
|
17
|
+
label?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The default `palette` of `ColorPicker`: 12 fixed hues plus white / grey / black.
|
|
21
|
+
*
|
|
22
|
+
* Deliberately literal hex, not theme tokens — a swatch palette must read the
|
|
23
|
+
* same on every theme (several of the bundled ones are monochrome). Use
|
|
24
|
+
* {@link COLOR_PICKER_PALETTE_THEME} when theme-following colors are what you want.
|
|
25
|
+
*/
|
|
26
|
+
export declare const COLOR_PICKER_PALETTE: ColorPickerSwatch[];
|
|
27
|
+
/**
|
|
28
|
+
* An opt-in palette of design-token colors — pass it as `palette` when the picked
|
|
29
|
+
* color should follow the active theme:
|
|
30
|
+
*
|
|
31
|
+
* ```svelte
|
|
32
|
+
* <ColorPicker bind:value palette={COLOR_PICKER_PALETTE_THEME} />
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* The stored value is the `var(--stuic-color-*)` reference itself, so it keeps
|
|
36
|
+
* following the theme wherever it is later applied. Two consequences worth
|
|
37
|
+
* knowing: the native color input cannot display such a value (it falls back to
|
|
38
|
+
* black until the user picks a hex), and on the monochrome themes several of
|
|
39
|
+
* these resolve to near-identical greys.
|
|
40
|
+
*/
|
|
41
|
+
export declare const COLOR_PICKER_PALETTE_THEME: ColorPickerSwatch[];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default `palette` of `ColorPicker`: 12 fixed hues plus white / grey / black.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately literal hex, not theme tokens — a swatch palette must read the
|
|
5
|
+
* same on every theme (several of the bundled ones are monochrome). Use
|
|
6
|
+
* {@link COLOR_PICKER_PALETTE_THEME} when theme-following colors are what you want.
|
|
7
|
+
*/
|
|
8
|
+
export const COLOR_PICKER_PALETTE = [
|
|
9
|
+
{ value: "#ef4444", label: "red" },
|
|
10
|
+
{ value: "#f97316", label: "orange" },
|
|
11
|
+
{ value: "#f59e0b", label: "amber" },
|
|
12
|
+
{ value: "#eab308", label: "yellow" },
|
|
13
|
+
{ value: "#84cc16", label: "lime" },
|
|
14
|
+
{ value: "#22c55e", label: "green" },
|
|
15
|
+
{ value: "#14b8a6", label: "teal" },
|
|
16
|
+
{ value: "#06b6d4", label: "cyan" },
|
|
17
|
+
{ value: "#3b82f6", label: "blue" },
|
|
18
|
+
{ value: "#6366f1", label: "indigo" },
|
|
19
|
+
{ value: "#8b5cf6", label: "violet" },
|
|
20
|
+
{ value: "#ec4899", label: "pink" },
|
|
21
|
+
{ value: "#ffffff", label: "white" },
|
|
22
|
+
{ value: "#6b7280", label: "gray" },
|
|
23
|
+
{ value: "#000000", label: "black" },
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* An opt-in palette of design-token colors — pass it as `palette` when the picked
|
|
27
|
+
* color should follow the active theme:
|
|
28
|
+
*
|
|
29
|
+
* ```svelte
|
|
30
|
+
* <ColorPicker bind:value palette={COLOR_PICKER_PALETTE_THEME} />
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* The stored value is the `var(--stuic-color-*)` reference itself, so it keeps
|
|
34
|
+
* following the theme wherever it is later applied. Two consequences worth
|
|
35
|
+
* knowing: the native color input cannot display such a value (it falls back to
|
|
36
|
+
* black until the user picks a hex), and on the monochrome themes several of
|
|
37
|
+
* these resolve to near-identical greys.
|
|
38
|
+
*/
|
|
39
|
+
export const COLOR_PICKER_PALETTE_THEME = [
|
|
40
|
+
{ value: "var(--stuic-color-primary)", label: "primary" },
|
|
41
|
+
{ value: "var(--stuic-color-accent)", label: "accent" },
|
|
42
|
+
{ value: "var(--stuic-color-success)", label: "success" },
|
|
43
|
+
{ value: "var(--stuic-color-warning)", label: "warning" },
|
|
44
|
+
{ value: "var(--stuic-color-destructive)", label: "destructive" },
|
|
45
|
+
{ value: "var(--stuic-color-foreground)", label: "foreground" },
|
|
46
|
+
{ value: "var(--stuic-color-muted-foreground)", label: "muted_foreground" },
|
|
47
|
+
{ value: "var(--stuic-color-muted)", label: "muted" },
|
|
48
|
+
{ value: "var(--stuic-color-background)", label: "background" },
|
|
49
|
+
];
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import type { TranslateFn } from "../../types.js";
|
|
8
8
|
import type { THC } from "../Thc/Thc.svelte";
|
|
9
9
|
import type { InputWrapClassProps } from "../Input/types.js";
|
|
10
|
-
import type { FieldDef, FieldTypeDef } from "./types.js";
|
|
10
|
+
import type { FieldDef, FieldTypeDef, LocalizedText } from "./types.js";
|
|
11
11
|
|
|
12
12
|
type SnippetWithId = Snippet<[{ id: string }]>;
|
|
13
13
|
|
|
@@ -46,8 +46,22 @@
|
|
|
46
46
|
* strings.
|
|
47
47
|
*/
|
|
48
48
|
languages?: string[];
|
|
49
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* The canonical (authoring) language. Defaults to `languages[0]`. Drives
|
|
51
|
+
* key derivation, the "label required" rule and which input the label/
|
|
52
|
+
* description/option editors show collapsed. Also the display language
|
|
53
|
+
* unless `displayLanguage` is set.
|
|
54
|
+
*/
|
|
50
55
|
defaultLanguage?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Which translation of consumer-supplied localized data is DISPLAYED —
|
|
58
|
+
* field labels in the row list, announcements and the preview fallback;
|
|
59
|
+
* palette labels/descriptions; extras labels/placeholders/descriptions.
|
|
60
|
+
* Typically the current user's UI locale. Purely presentational: authoring
|
|
61
|
+
* stays on `defaultLanguage` (see above), which is also the fallback for a
|
|
62
|
+
* missing translation. Default: `defaultLanguage`.
|
|
63
|
+
*/
|
|
64
|
+
displayLanguage?: string;
|
|
51
65
|
languageLabels?: Record<string, string>;
|
|
52
66
|
/** Key policy. Default: lowercase snake_case starting with a letter. */
|
|
53
67
|
keyPattern?: RegExp;
|
|
@@ -165,6 +179,7 @@
|
|
|
165
179
|
style,
|
|
166
180
|
languages,
|
|
167
181
|
defaultLanguage,
|
|
182
|
+
displayLanguage,
|
|
168
183
|
languageLabels,
|
|
169
184
|
keyPattern,
|
|
170
185
|
keyMaxLength = DEFAULT_KEY_MAX_LENGTH,
|
|
@@ -244,6 +259,17 @@
|
|
|
244
259
|
let rows: Row[] = $state(fromValue(value ?? []));
|
|
245
260
|
|
|
246
261
|
const _defaultLanguage = $derived(defaultLanguage || languages?.[0]);
|
|
262
|
+
const _displayLanguage = $derived(displayLanguage || _defaultLanguage);
|
|
263
|
+
// display fallback chain: preferred → canonical → first non-empty entry
|
|
264
|
+
const _displayLanguages = $derived(
|
|
265
|
+
[_displayLanguage, _defaultLanguage].filter((l): l is string => !!l)
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
/** Read-only rendering of consumer-supplied localized data. */
|
|
269
|
+
function displayText(text: LocalizedText | null | undefined): string {
|
|
270
|
+
return getLocalizedText(text, _displayLanguages);
|
|
271
|
+
}
|
|
272
|
+
|
|
247
273
|
const typeByName = $derived(new Map(types.map((td) => [td.type, td])));
|
|
248
274
|
const visibleRows = $derived(rows.filter((r) => !r.deleted));
|
|
249
275
|
const maxReached = $derived(!!maxFields && visibleRows.length >= maxFields);
|
|
@@ -569,7 +595,7 @@
|
|
|
569
595
|
}
|
|
570
596
|
|
|
571
597
|
function rowLabel(row: Row): string {
|
|
572
|
-
return
|
|
598
|
+
return displayText(row.def.label) || String(t("untitled"));
|
|
573
599
|
}
|
|
574
600
|
|
|
575
601
|
// clear-then-set so REPEATED identical announcements (e.g. pressing "Move
|
|
@@ -597,6 +623,7 @@
|
|
|
597
623
|
reservedKeys,
|
|
598
624
|
maxFields,
|
|
599
625
|
defaultLanguage: _defaultLanguage,
|
|
626
|
+
displayLanguage: _displayLanguage,
|
|
600
627
|
t: tUtils,
|
|
601
628
|
}
|
|
602
629
|
)
|
|
@@ -831,7 +858,7 @@
|
|
|
831
858
|
{:else if entry.icon}
|
|
832
859
|
{@render entry.icon()}
|
|
833
860
|
{/if}
|
|
834
|
-
{
|
|
861
|
+
{displayText(entry.label)}
|
|
835
862
|
</span>
|
|
836
863
|
{/if}
|
|
837
864
|
{#if (showLabelError || showKeyError || showOptionsError || showExtrasError) && !row.deleted}
|
|
@@ -994,7 +1021,7 @@
|
|
|
994
1021
|
>
|
|
995
1022
|
{#each types as td (td.type)}
|
|
996
1023
|
<option value={td.type}>
|
|
997
|
-
{
|
|
1024
|
+
{displayText(td.label)}
|
|
998
1025
|
</option>
|
|
999
1026
|
{/each}
|
|
1000
1027
|
</select>
|
|
@@ -1016,7 +1043,7 @@
|
|
|
1016
1043
|
</div>
|
|
1017
1044
|
{#if entry.description}
|
|
1018
1045
|
<div class="fb-hint text-xs mt-0.5">
|
|
1019
|
-
{
|
|
1046
|
+
{displayText(entry.description)}
|
|
1020
1047
|
</div>
|
|
1021
1048
|
{/if}
|
|
1022
1049
|
{#if typeChanged(row)}
|
|
@@ -1043,6 +1070,7 @@
|
|
|
1043
1070
|
bind:options={row.def.options}
|
|
1044
1071
|
{languages}
|
|
1045
1072
|
defaultLanguage={_defaultLanguage}
|
|
1073
|
+
displayLanguage={_displayLanguage}
|
|
1046
1074
|
{languageLabels}
|
|
1047
1075
|
{disabled}
|
|
1048
1076
|
locked={!!row.def.lock?.options}
|
|
@@ -1077,7 +1105,7 @@
|
|
|
1077
1105
|
{@const exValue = extraText(row, ex.key)}
|
|
1078
1106
|
<div class="fb-extra">
|
|
1079
1107
|
<label class="fb-sub-label" for={exId}>
|
|
1080
|
-
{
|
|
1108
|
+
{displayText(ex.label)}
|
|
1081
1109
|
</label>
|
|
1082
1110
|
{#if ex.type === "string"}
|
|
1083
1111
|
<input
|
|
@@ -1086,10 +1114,7 @@
|
|
|
1086
1114
|
class={twMerge(INPUT_CLS, "fb-extra-input w-full")}
|
|
1087
1115
|
value={exValue}
|
|
1088
1116
|
maxlength={ex.maxlength}
|
|
1089
|
-
placeholder={
|
|
1090
|
-
ex.placeholder,
|
|
1091
|
-
_defaultLanguage
|
|
1092
|
-
) || undefined}
|
|
1117
|
+
placeholder={displayText(ex.placeholder) || undefined}
|
|
1093
1118
|
oninput={(e) =>
|
|
1094
1119
|
onExtraStringInput(
|
|
1095
1120
|
row,
|
|
@@ -1124,11 +1149,11 @@
|
|
|
1124
1149
|
{tabindex}
|
|
1125
1150
|
>
|
|
1126
1151
|
<option value="">
|
|
1127
|
-
{
|
|
1152
|
+
{displayText(ex.placeholder)}
|
|
1128
1153
|
</option>
|
|
1129
1154
|
{#each ex.options as opt (opt.value)}
|
|
1130
1155
|
<option value={opt.value}>
|
|
1131
|
-
{
|
|
1156
|
+
{displayText(opt.label)}
|
|
1132
1157
|
</option>
|
|
1133
1158
|
{/each}
|
|
1134
1159
|
<!-- a stored value outside the declared list stays
|
|
@@ -1141,7 +1166,7 @@
|
|
|
1141
1166
|
{/if}
|
|
1142
1167
|
{#if ex.description}
|
|
1143
1168
|
<div class="fb-hint text-xs mt-0.5">
|
|
1144
|
-
{
|
|
1169
|
+
{displayText(ex.description)}
|
|
1145
1170
|
</div>
|
|
1146
1171
|
{/if}
|
|
1147
1172
|
</div>
|
|
@@ -1158,10 +1183,10 @@
|
|
|
1158
1183
|
{tabindex}
|
|
1159
1184
|
/>
|
|
1160
1185
|
<span class="text-sm">
|
|
1161
|
-
{
|
|
1186
|
+
{displayText(ex.label)}
|
|
1162
1187
|
{#if ex.description}
|
|
1163
1188
|
<span class="fb-hint block text-xs">
|
|
1164
|
-
{
|
|
1189
|
+
{displayText(ex.description)}
|
|
1165
1190
|
</span>
|
|
1166
1191
|
{/if}
|
|
1167
1192
|
</span>
|
|
@@ -1291,14 +1316,14 @@
|
|
|
1291
1316
|
{:else}
|
|
1292
1317
|
<div class="fb-preview-fallback flex items-center gap-1.5 text-sm">
|
|
1293
1318
|
<span>
|
|
1294
|
-
{
|
|
1319
|
+
{displayText(f.label) || t("untitled")}
|
|
1295
1320
|
</span>
|
|
1296
1321
|
{#if f.required}
|
|
1297
1322
|
<span class="fb-row-required" aria-hidden="true">*</span>
|
|
1298
1323
|
{/if}
|
|
1299
1324
|
{#if pentry}
|
|
1300
1325
|
<span class="fb-chip">
|
|
1301
|
-
{
|
|
1326
|
+
{displayText(pentry.label)}
|
|
1302
1327
|
</span>
|
|
1303
1328
|
{/if}
|
|
1304
1329
|
</div>
|
|
@@ -42,8 +42,22 @@ export interface Props extends InputWrapClassProps, Record<string, any> {
|
|
|
42
42
|
* strings.
|
|
43
43
|
*/
|
|
44
44
|
languages?: string[];
|
|
45
|
-
/**
|
|
45
|
+
/**
|
|
46
|
+
* The canonical (authoring) language. Defaults to `languages[0]`. Drives
|
|
47
|
+
* key derivation, the "label required" rule and which input the label/
|
|
48
|
+
* description/option editors show collapsed. Also the display language
|
|
49
|
+
* unless `displayLanguage` is set.
|
|
50
|
+
*/
|
|
46
51
|
defaultLanguage?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Which translation of consumer-supplied localized data is DISPLAYED —
|
|
54
|
+
* field labels in the row list, announcements and the preview fallback;
|
|
55
|
+
* palette labels/descriptions; extras labels/placeholders/descriptions.
|
|
56
|
+
* Typically the current user's UI locale. Purely presentational: authoring
|
|
57
|
+
* stays on `defaultLanguage` (see above), which is also the fallback for a
|
|
58
|
+
* missing translation. Default: `defaultLanguage`.
|
|
59
|
+
*/
|
|
60
|
+
displayLanguage?: string;
|
|
47
61
|
languageLabels?: Record<string, string>;
|
|
48
62
|
/** Key policy. Default: lowercase snake_case starting with a letter. */
|
|
49
63
|
keyPattern?: RegExp;
|