@marianmeres/stuic 3.180.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/README.md +3 -1
- package/dist/components/FieldsBuilder/types.d.ts +7 -2
- package/dist/components/FieldsBuilder/utils.d.ts +2 -1
- package/dist/components/FieldsBuilder/utils.js +4 -15
- 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
package/dist/utils/tr.d.ts
CHANGED
|
@@ -1,25 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A value that may be a plain string or a locale-keyed object of translations
|
|
2
|
+
* A value that may be a plain string or a locale-keyed object of translations
|
|
3
|
+
* (`{ en: "Hello", sk: "Ahoj" }`).
|
|
3
4
|
*/
|
|
4
5
|
export type MaybeLocalized = string | Record<string, string>;
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
+
* Resolves a `MaybeLocalized` value to the text to display.
|
|
7
8
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* A plain string is returned as-is. A locale-keyed record (or a JSON string
|
|
10
|
+
* encoding one — how string-valued inputs such as `FieldInputLocalized` carry
|
|
11
|
+
* it) is resolved in this order:
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* 1. the first entry of `locale` (one locale, or a preference chain in order)
|
|
14
|
+
* that is non-empty — an empty entry counts as missing,
|
|
15
|
+
* 2. `fallback`, when one is given,
|
|
16
|
+
* 3. the first non-empty entry of the record,
|
|
17
|
+
* 4. `""`.
|
|
18
|
+
*
|
|
19
|
+
* So a record never renders as `[object Object]`, and a missing translation
|
|
20
|
+
* degrades to another language rather than to nothing. `null`/`undefined`
|
|
21
|
+
* yield `fallback ?? ""`.
|
|
22
|
+
*
|
|
23
|
+
* @param val - A plain string, a locale-keyed record, or a JSON string of one
|
|
24
|
+
* @param locale - The locale to look up, or a chain of locales in order of preference
|
|
25
|
+
* @param fallback - Text to use when none of `locale` has a non-empty entry
|
|
16
26
|
*
|
|
17
27
|
* @example
|
|
18
28
|
* ```ts
|
|
19
|
-
* tr(
|
|
20
|
-
* tr({ en:
|
|
21
|
-
* tr({ en:
|
|
22
|
-
* tr(
|
|
29
|
+
* tr("Hello", "sk"); // "Hello" (plain string returned as-is)
|
|
30
|
+
* tr({ en: "Hello", sk: "Ahoj" }, "sk"); // "Ahoj"
|
|
31
|
+
* tr({ en: "Hello", sk: "Ahoj" }, ["cs", "sk"]); // "Ahoj" (chain, in order)
|
|
32
|
+
* tr({ en: "Hello" }, "sk"); // "Hello" (first non-empty entry)
|
|
33
|
+
* tr({ en: "Hello" }, "sk", "—"); // "—" (explicit fallback wins)
|
|
34
|
+
* tr('{"en":"Hello","sk":"Ahoj"}', "sk"); // "Ahoj" (JSON string parsed)
|
|
23
35
|
* ```
|
|
24
36
|
*/
|
|
25
|
-
export declare function tr(val: MaybeLocalized | undefined | null, locale?: string, fallback?: string): string;
|
|
37
|
+
export declare function tr(val: MaybeLocalized | undefined | null, locale?: string | string[], fallback?: string): string;
|
package/dist/utils/tr.js
CHANGED
|
@@ -1,30 +1,54 @@
|
|
|
1
|
+
import { isPlainObject } from "./is-plain-object.js";
|
|
1
2
|
import { maybeJsonParse } from "./maybe-json-parse.js";
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Resolves a `MaybeLocalized` value to the text to display.
|
|
4
5
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* A plain string is returned as-is. A locale-keyed record (or a JSON string
|
|
7
|
+
* encoding one — how string-valued inputs such as `FieldInputLocalized` carry
|
|
8
|
+
* it) is resolved in this order:
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* 1. the first entry of `locale` (one locale, or a preference chain in order)
|
|
11
|
+
* that is non-empty — an empty entry counts as missing,
|
|
12
|
+
* 2. `fallback`, when one is given,
|
|
13
|
+
* 3. the first non-empty entry of the record,
|
|
14
|
+
* 4. `""`.
|
|
15
|
+
*
|
|
16
|
+
* So a record never renders as `[object Object]`, and a missing translation
|
|
17
|
+
* degrades to another language rather than to nothing. `null`/`undefined`
|
|
18
|
+
* yield `fallback ?? ""`.
|
|
19
|
+
*
|
|
20
|
+
* @param val - A plain string, a locale-keyed record, or a JSON string of one
|
|
21
|
+
* @param locale - The locale to look up, or a chain of locales in order of preference
|
|
22
|
+
* @param fallback - Text to use when none of `locale` has a non-empty entry
|
|
13
23
|
*
|
|
14
24
|
* @example
|
|
15
25
|
* ```ts
|
|
16
|
-
* tr(
|
|
17
|
-
* tr({ en:
|
|
18
|
-
* tr({ en:
|
|
19
|
-
* tr(
|
|
26
|
+
* tr("Hello", "sk"); // "Hello" (plain string returned as-is)
|
|
27
|
+
* tr({ en: "Hello", sk: "Ahoj" }, "sk"); // "Ahoj"
|
|
28
|
+
* tr({ en: "Hello", sk: "Ahoj" }, ["cs", "sk"]); // "Ahoj" (chain, in order)
|
|
29
|
+
* tr({ en: "Hello" }, "sk"); // "Hello" (first non-empty entry)
|
|
30
|
+
* tr({ en: "Hello" }, "sk", "—"); // "—" (explicit fallback wins)
|
|
31
|
+
* tr('{"en":"Hello","sk":"Ahoj"}', "sk"); // "Ahoj" (JSON string parsed)
|
|
20
32
|
* ```
|
|
21
33
|
*/
|
|
22
34
|
export function tr(val, locale, fallback) {
|
|
23
|
-
if (
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
//
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
if (val == null)
|
|
36
|
+
return fallback ?? "";
|
|
37
|
+
// only a plain object is a record; a string that parses to anything else
|
|
38
|
+
// ("2024", "null", "[1,2]") is just that string
|
|
39
|
+
const parsed = maybeJsonParse(val);
|
|
40
|
+
if (!isPlainObject(parsed))
|
|
41
|
+
return String(val);
|
|
42
|
+
const rec = parsed;
|
|
43
|
+
const chain = typeof locale === "string" ? [locale] : (locale ?? []);
|
|
44
|
+
for (const l of chain) {
|
|
45
|
+
if (l && Object.hasOwn(rec, l) && rec[l])
|
|
46
|
+
return String(rec[l]);
|
|
47
|
+
}
|
|
48
|
+
if (fallback !== undefined)
|
|
49
|
+
return fallback;
|
|
50
|
+
for (const v of Object.values(rec))
|
|
51
|
+
if (v)
|
|
52
|
+
return String(v);
|
|
53
|
+
return "";
|
|
30
54
|
}
|
|
@@ -83,8 +83,15 @@ Checked first, to avoid false positives:
|
|
|
83
83
|
feedback (icon + intent swap, localized label/name, sr live announcement),
|
|
84
84
|
`onCopied` / `onError` callbacks; the write is the reusable `copyToClipboard()`
|
|
85
85
|
util (async Clipboard API + `execCommand` fallback) in `utils/`.
|
|
86
|
-
13.
|
|
87
|
-
|
|
86
|
+
13. ~~**ColorPicker**~~ — ✅ shipped (see `src/lib/components/ColorPicker/`): a
|
|
87
|
+
`role="radiogroup"` swatch palette (roving tabindex, wrapping arrows, optional
|
|
88
|
+
"no color" swatch, `columns` grid) plus a custom row of the native
|
|
89
|
+
`<input type="color">` and a hex field; hidden input + `validate` with `required`,
|
|
90
|
+
`t` texts with Slovak bundled. Swatch values are never parsed — any CSS color
|
|
91
|
+
string, so `COLOR_PICKER_PALETTE_THEME` can hold `var(--stuic-color-*)` tokens and
|
|
92
|
+
the picked value keeps following the theme. Mobile needed no special path: the
|
|
93
|
+
native input opens the platform picker, so there is no popover to fight the
|
|
94
|
+
on-screen keyboard.
|
|
88
95
|
|
|
89
96
|
## Deliberately out of scope (or close enough to covered)
|
|
90
97
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
80 Svelte 5 component directories with consistent API patterns. All use runes-based reactivity.
|
|
6
6
|
|
|
7
7
|
## Component Categories
|
|
8
8
|
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
| Slider | Fancy range input (fill + optional thumb) |
|
|
36
36
|
| RangeSlider | Dual-thumb Slider: `start` ≤ `end` on one track, no crossing, `minRange`, two hidden inputs |
|
|
37
37
|
| Rating | Star rating: radiogroup input (half steps, hover preview, form + validate) or read-only display |
|
|
38
|
+
| ColorPicker | Swatch palette (radiogroup) + native picker & hex field; any CSS color, form + validate |
|
|
38
39
|
| TwCheck | Styled checkbox/radio |
|
|
39
40
|
| DropdownMenu | Popover menu |
|
|
40
41
|
| ContextMenu | Right-click / long-press menu at the cursor (the DropdownMenu engine + trigger semantics) |
|
|
@@ -882,6 +883,62 @@ Prefix: `--stuic-card-*`
|
|
|
882
883
|
|
|
883
884
|
---
|
|
884
885
|
|
|
886
|
+
## ColorPicker
|
|
887
|
+
|
|
888
|
+
A swatch palette plus a custom-color escape hatch. The palette is a `role="radiogroup"` of swatch buttons (roving tabindex, wrapping Left/Right, Up/Down by one _rendered_ row — measured from the layout, so it survives wrapping — Home/End, Delete/Backspace to clear, an optional crossed-out "no color" swatch); the custom row is the native `<input type="color">` next to a hex text field. A hidden input carries `name`/value with the `validate` action and `required` enforced (hidden inputs skip native constraint validation).
|
|
889
|
+
|
|
890
|
+
`columns` caps swatches per row rather than forcing a grid — a phone too narrow for N wraps to fewer instead of scrolling the page sideways.
|
|
891
|
+
|
|
892
|
+
Swatch values are **never parsed** — they go to CSS as `--stuic-color-picker-swatch-color`, so a palette may hold hex, `oklch(...)`, `transparent`, or `var(--stuic-color-primary)` (`COLOR_PICKER_PALETTE_THEME` does exactly that, and the stored value keeps following the theme). Selection is a ring drawn _outside_ the swatch, which reads on any color without luminance math. Mobile needs no special path: the native input opens the platform picker, so there is no popover to fight the on-screen keyboard; swatches grow to ~44px on a coarse pointer and the hex field carries the iOS zoom guard.
|
|
893
|
+
|
|
894
|
+
### Exports
|
|
895
|
+
|
|
896
|
+
| Export | Kind | Description |
|
|
897
|
+
| ---------------------------- | --------- | -------------------------------------------- |
|
|
898
|
+
| `ColorPicker` | component | Main component |
|
|
899
|
+
| `ColorPickerProps` | type | Props type |
|
|
900
|
+
| `ColorPickerCustom` | type | `"both" \| "native" \| "text" \| false` |
|
|
901
|
+
| `ColorPickerSwatch` | type | `string \| ColorPickerSwatchObject` |
|
|
902
|
+
| `ColorPickerSwatchObject` | type | `{ value, label? }` |
|
|
903
|
+
| `COLOR_PICKER_PALETTE` | constant | Default palette (12 hues + white/grey/black) |
|
|
904
|
+
| `COLOR_PICKER_PALETTE_THEME` | constant | Opt-in design-token palette |
|
|
905
|
+
| `createColorPickerT` | function | Builds the `t` prop from a (partial) catalog |
|
|
906
|
+
| `COLOR_PICKER_MESSAGES_EN` | constant | Built-in English catalog (also the fallback) |
|
|
907
|
+
| `COLOR_PICKER_MESSAGES_SK` | constant | Bundled Slovak catalog (opt-in) |
|
|
908
|
+
| `ColorPickerMessageKey` | type | Message key union |
|
|
909
|
+
| `ColorPickerMessages` | type | One locale's catalog |
|
|
910
|
+
|
|
911
|
+
### Key Props
|
|
912
|
+
|
|
913
|
+
| Prop | Type | Default | Description |
|
|
914
|
+
| ----------------------------------------------------- | --------------------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
915
|
+
| `value` | `string` | `""` | Bindable; any CSS color string, stored verbatim. `""` = no color |
|
|
916
|
+
| `palette` | `ColorPickerSwatch[]` | `COLOR_PICKER_PALETTE` | Color strings or `{ value, label }` objects; `[]` renders no palette |
|
|
917
|
+
| `columns` | `number` | — | Cap of N swatches per row (a narrower container wraps to fewer). Unset = as many as fit |
|
|
918
|
+
| `custom` | `"both" \| "native" \| "text" \| false` | `"both"` | Which custom-color controls render under the palette |
|
|
919
|
+
| `allowClear` | `boolean` | `true` | Clear swatch + Delete/Backspace + an emptied hex field |
|
|
920
|
+
| `name`, `required`, `validate`, `setValidationResult` | | | Form integration — same contract as the `Field*` components; imperative `validate()` / `clearValidation()` / `getValidation()` via `bind:this` |
|
|
921
|
+
| `onchange` | `(value: string) => void` | — | User **commits** only (see below) |
|
|
922
|
+
| `t` | `TranslateFn` | English | Group label, swatch names, "no color", custom-color labels, required message |
|
|
923
|
+
|
|
924
|
+
Class slots: `class`, `classSwatch`.
|
|
925
|
+
|
|
926
|
+
### Preview vs commit
|
|
927
|
+
|
|
928
|
+
`value` updates live while the native OS picker is dragged and while a valid color is typed into the hex field (so `bind:value` previews); `onchange` — and the hidden input's `change`, which is what re-runs validation — fires only on a commit: a swatch click, an arrow onto a _different_ swatch (a radio does not re-fire for the checked one), the native picker's `change`, or Enter/blur in the hex field. An unparseable hex field commits nothing and snaps back.
|
|
929
|
+
|
|
930
|
+
The hex field normalizes hex in any spelling (`#0f0`, `3b82f6`) to lowercase `#rrggbb`; anything else `CSS.supports("color", …)` accepts is kept verbatim. Because a focused field must own its own DOM value, it is written explicitly rather than driven by a reactive `value=` — Svelte skips a write when the expression matches what it last wrote, which is exactly the snap-back case.
|
|
931
|
+
|
|
932
|
+
### CSS Tokens
|
|
933
|
+
|
|
934
|
+
Prefix: `--stuic-color-picker-*`
|
|
935
|
+
|
|
936
|
+
`gap`, `custom-gap`, `swatch-size`, `swatch-size-touch`, `swatch-border`, `swatch-scale-hover`, `swatch-ring-width`, `swatch-ring-gap`, `swatch-ring-color`, `swatch-ring-gap-color`, `ring-width`, `ring-color`, `clear-color`, `clear-bg`, `text-width`, `text-bg`, `text-border`, `text-color`, `text-placeholder`, `text-font-family`, `text-font-size`, `text-font-size-touch-min`, `opacity-disabled`
|
|
937
|
+
|
|
938
|
+
Radius and border width use the shared-token fallback pattern (`swatch-radius` / `text-radius` / `*-border-width` → `--stuic-radius` / `--stuic-border-width`).
|
|
939
|
+
|
|
940
|
+
---
|
|
941
|
+
|
|
885
942
|
## ContextMenu
|
|
886
943
|
|
|
887
944
|
Right-click / long-press triggered menu positioned at the pointer. Wraps content into a context target area: `contextmenu` (right-click), long-press (touch/pen, via the `longPress` attachment), or Shift+F10 / the menu key open the menu anchored at the interaction point (an invisible 0×0 fixed anchor the underlying DropdownMenu positions against). The menu panel **is** a `DropdownMenu` — item model, keyboard navigation, search, overflow handling, and theming (`--stuic-dropdown-menu-*`) all come from there.
|