@marianmeres/stuic 3.172.0 → 3.173.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.
Files changed (53) hide show
  1. package/AGENTS.md +2 -2
  2. package/API.md +56 -2
  3. package/README.md +14 -2
  4. package/dist/actions/resizable-width.svelte.d.ts +14 -28
  5. package/dist/actions/resizable-width.svelte.js +16 -171
  6. package/dist/attachments/index.d.ts +1 -0
  7. package/dist/attachments/index.js +1 -0
  8. package/dist/attachments/resizable.d.ts +113 -0
  9. package/dist/attachments/resizable.fixture.svelte +53 -0
  10. package/dist/attachments/resizable.fixture.svelte.d.ts +10 -0
  11. package/dist/attachments/resizable.js +295 -0
  12. package/dist/components/RangeSlider/README.md +291 -0
  13. package/dist/components/RangeSlider/RangeSlider.svelte +763 -0
  14. package/dist/components/RangeSlider/RangeSlider.svelte.d.ts +130 -0
  15. package/dist/components/RangeSlider/i18n-sk.d.ts +17 -0
  16. package/dist/components/RangeSlider/i18n-sk.js +19 -0
  17. package/dist/components/RangeSlider/i18n.d.ts +33 -0
  18. package/dist/components/RangeSlider/i18n.js +41 -0
  19. package/dist/components/RangeSlider/index.css +430 -0
  20. package/dist/components/RangeSlider/index.d.ts +3 -0
  21. package/dist/components/RangeSlider/index.js +3 -0
  22. package/dist/components/Rating/README.md +206 -0
  23. package/dist/components/Rating/Rating.svelte +355 -0
  24. package/dist/components/Rating/Rating.svelte.d.ts +82 -0
  25. package/dist/components/Rating/i18n-sk.d.ts +17 -0
  26. package/dist/components/Rating/i18n-sk.js +21 -0
  27. package/dist/components/Rating/i18n.d.ts +34 -0
  28. package/dist/components/Rating/i18n.js +42 -0
  29. package/dist/components/Rating/index.css +170 -0
  30. package/dist/components/Rating/index.d.ts +3 -0
  31. package/dist/components/Rating/index.js +3 -0
  32. package/dist/components/SplitPane/README.md +169 -0
  33. package/dist/components/SplitPane/SplitPane.svelte +202 -0
  34. package/dist/components/SplitPane/SplitPane.svelte.d.ts +67 -0
  35. package/dist/components/SplitPane/i18n-sk.d.ts +17 -0
  36. package/dist/components/SplitPane/i18n-sk.js +18 -0
  37. package/dist/components/SplitPane/i18n.d.ts +31 -0
  38. package/dist/components/SplitPane/i18n.js +39 -0
  39. package/dist/components/SplitPane/index.css +153 -0
  40. package/dist/components/SplitPane/index.d.ts +3 -0
  41. package/dist/components/SplitPane/index.js +3 -0
  42. package/dist/components/WithSidePanel/README.md +19 -16
  43. package/dist/icons/index.d.ts +2 -0
  44. package/dist/icons/index.js +3 -0
  45. package/dist/index.css +3 -0
  46. package/dist/index.d.ts +3 -0
  47. package/dist/index.js +3 -0
  48. package/docs/{maybe-todo.md → _archive/maybe-todo.md} +18 -7
  49. package/docs/architecture.md +1 -1
  50. package/docs/domains/actions.md +18 -18
  51. package/docs/domains/attachments.md +72 -9
  52. package/docs/domains/components.md +175 -32
  53. package/package.json +5 -5
@@ -0,0 +1,67 @@
1
+ import type { Snippet } from "svelte";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import type { ResizableInfo, ResizableUnits } from "../../attachments/resizable.js";
4
+ import type { TranslateFn } from "../../types.js";
5
+ export type SplitPaneOrientation = "horizontal" | "vertical";
6
+ /** Which pane carries the size; the other one flexes into the rest. */
7
+ export type SplitPanePrimary = "start" | "end";
8
+ export interface Props extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
9
+ /** Content of the first pane (left; top when vertical) */
10
+ start?: Snippet;
11
+ /** Content of the second pane (right; bottom when vertical) */
12
+ end?: Snippet;
13
+ /**
14
+ * `horizontal` (default) puts the panes side by side and resizes a width,
15
+ * `vertical` stacks them and resizes a height — the container then needs a
16
+ * definite height (`%` units resolve against it).
17
+ */
18
+ orientation?: SplitPaneOrientation;
19
+ /** Which pane the size applies to (the other one fills the rest). Default `start`. */
20
+ primary?: SplitPanePrimary;
21
+ /**
22
+ * Size of the primary pane in `units` (bindable). Default `50`. Written on every
23
+ * resize; writing it resizes the pane (clamped to `min` / `max`). A size stored
24
+ * under `key` wins over it on mount and is written back into the binding. The
25
+ * size the component mounted with is what double-click / Enter on the separator
26
+ * and `reset()` restore.
27
+ */
28
+ size?: number;
29
+ /** `%` (default) of the container, or `px`. Not meant to change after mount. */
30
+ units?: ResizableUnits;
31
+ /** Lower bound in `units`. `0` = none. */
32
+ min?: number;
33
+ /** Upper bound in `units`. `0` = none (`%` is still capped at 100). */
34
+ max?: number;
35
+ /** Keyboard step in `units` (Shift multiplies by 10). Default `1` for %, `10` for px. */
36
+ step?: number;
37
+ /** Persist the size under this key (`resizable-width-<key>` / `resizable-height-<key>`) */
38
+ key?: string | number | null;
39
+ /** Where `key` persists to. Default `session`. */
40
+ storage?: "local" | "session";
41
+ /** Renders the separator inert: no drag, no keyboard, not focusable */
42
+ disabled?: boolean;
43
+ /** Accessible name of the separator. Defaults to `t("resize")` — "Resize". */
44
+ label?: string;
45
+ /** Skip all default styling, use only custom classes */
46
+ unstyled?: boolean;
47
+ class?: string;
48
+ /** Classes for the first pane */
49
+ startClass?: string;
50
+ /** Classes for the second pane */
51
+ endClass?: string;
52
+ /** Classes for the separator */
53
+ separatorClass?: string;
54
+ /** Bindable root element reference */
55
+ el?: HTMLDivElement;
56
+ /** Bindable separator element reference */
57
+ separatorEl?: HTMLDivElement;
58
+ /** Fires whenever a size is applied: on mount, while dragging, per key press, on reset, on `size` writes */
59
+ onResize?: (info: ResizableInfo) => void;
60
+ /** Translation function for the separator's default name (`resize`). English built in. */
61
+ t?: TranslateFn;
62
+ }
63
+ declare const SplitPane: import("svelte").Component<Props, {
64
+ reset: () => void;
65
+ }, "el" | "size" | "separatorEl">;
66
+ type SplitPane = ReturnType<typeof SplitPane>;
67
+ export default SplitPane;
@@ -0,0 +1,17 @@
1
+ import type { SplitPaneMessages } from "./i18n.js";
2
+ /**
3
+ * Slovak message catalog for `SplitPane`. Opt-in — English stays the built-in
4
+ * default, and this module is only pulled into a bundle when it is actually
5
+ * imported (the component itself never references it).
6
+ *
7
+ * @example
8
+ * ```svelte
9
+ * <script>
10
+ * import { SplitPane, createSplitPaneT, SPLIT_PANE_MESSAGES_SK } from "@marianmeres/stuic";
11
+ * const t = createSplitPaneT(SPLIT_PANE_MESSAGES_SK);
12
+ * </script>
13
+ *
14
+ * <SplitPane {t}>…</SplitPane>
15
+ * ```
16
+ */
17
+ export declare const SPLIT_PANE_MESSAGES_SK: SplitPaneMessages;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Slovak message catalog for `SplitPane`. Opt-in — English stays the built-in
3
+ * default, and this module is only pulled into a bundle when it is actually
4
+ * imported (the component itself never references it).
5
+ *
6
+ * @example
7
+ * ```svelte
8
+ * <script>
9
+ * import { SplitPane, createSplitPaneT, SPLIT_PANE_MESSAGES_SK } from "@marianmeres/stuic";
10
+ * const t = createSplitPaneT(SPLIT_PANE_MESSAGES_SK);
11
+ * </script>
12
+ *
13
+ * <SplitPane {t}>…</SplitPane>
14
+ * ```
15
+ */
16
+ export const SPLIT_PANE_MESSAGES_SK = {
17
+ resize: "Zmeniť veľkosť",
18
+ };
@@ -0,0 +1,31 @@
1
+ import type { TranslateFn } from "../../types.js";
2
+ /**
3
+ * The built-in (English) message catalog of `SplitPane`. Also the fallback of
4
+ * every other bundled locale, so a locale missing a key still renders text.
5
+ */
6
+ export declare const SPLIT_PANE_MESSAGES_EN: {
7
+ /** Default accessible name of the separator (the drag handle) */
8
+ resize: string;
9
+ };
10
+ /** Every message key `SplitPane` may look up. */
11
+ export type SplitPaneMessageKey = keyof typeof SPLIT_PANE_MESSAGES_EN;
12
+ /** A (possibly partial) catalog for one locale. */
13
+ export type SplitPaneMessages = Record<SplitPaneMessageKey, string>;
14
+ /**
15
+ * Builds the `t` prop of `SplitPane` from a message catalog. Unknown or
16
+ * untranslated keys fall back to `fallbackMessages` (English by default), so a
17
+ * catalog may safely be partial and never renders a raw key.
18
+ *
19
+ * @example
20
+ * ```svelte
21
+ * <script>
22
+ * import { SplitPane, createSplitPaneT, SPLIT_PANE_MESSAGES_SK } from "@marianmeres/stuic";
23
+ * const t = createSplitPaneT(SPLIT_PANE_MESSAGES_SK);
24
+ * </script>
25
+ *
26
+ * <SplitPane {t}>…</SplitPane>
27
+ * ```
28
+ */
29
+ export declare function createSplitPaneT(messages: Partial<SplitPaneMessages> | Record<string, string>, fallbackMessages?: Partial<SplitPaneMessages> | Record<string, string>): TranslateFn;
30
+ /** The component's built-in English `t`. */
31
+ export declare const t_default: TranslateFn;
@@ -0,0 +1,39 @@
1
+ import { isPlainObject } from "../../utils/is-plain-object.js";
2
+ import { replaceMap } from "../../utils/replace-map.js";
3
+ /**
4
+ * The built-in (English) message catalog of `SplitPane`. Also the fallback of
5
+ * every other bundled locale, so a locale missing a key still renders text.
6
+ */
7
+ export const SPLIT_PANE_MESSAGES_EN = {
8
+ /** Default accessible name of the separator (the drag handle) */
9
+ resize: "Resize",
10
+ };
11
+ /**
12
+ * Builds the `t` prop of `SplitPane` from a message catalog. Unknown or
13
+ * untranslated keys fall back to `fallbackMessages` (English by default), so a
14
+ * catalog may safely be partial and never renders a raw key.
15
+ *
16
+ * @example
17
+ * ```svelte
18
+ * <script>
19
+ * import { SplitPane, createSplitPaneT, SPLIT_PANE_MESSAGES_SK } from "@marianmeres/stuic";
20
+ * const t = createSplitPaneT(SPLIT_PANE_MESSAGES_SK);
21
+ * </script>
22
+ *
23
+ * <SplitPane {t}>…</SplitPane>
24
+ * ```
25
+ */
26
+ export function createSplitPaneT(messages, fallbackMessages = SPLIT_PANE_MESSAGES_EN) {
27
+ return (k, values = null, fallback = "") => {
28
+ const out = messages[k] ??
29
+ fallbackMessages[k] ??
30
+ (typeof fallback === "string" ? fallback : k);
31
+ return isPlainObject(values)
32
+ ? replaceMap(out, values, {
33
+ preSearchKeyTransform: (k) => `{${k}}`,
34
+ })
35
+ : out;
36
+ };
37
+ }
38
+ /** The component's built-in English `t`. */
39
+ export const t_default = createSplitPaneT(SPLIT_PANE_MESSAGES_EN);
@@ -0,0 +1,153 @@
1
+ /* ============================================================================
2
+ SPLIT PANE COMPONENT TOKENS
3
+ Override globally: :root { --stuic-split-pane-separator-color: red; }
4
+ Override locally: <SplitPane style="--stuic-split-pane-separator-color: red;" />
5
+
6
+ The defaults reproduce the `resizable` attachment's built-in handle (the one
7
+ `resizableWidth` / `WithSidePanel` show): a faint 1px line with a small rounded grip.
8
+ ============================================================================ */
9
+
10
+ :root {
11
+ /* the separator line */
12
+ --stuic-split-pane-separator-color: rgb(0 0 0 / 0.2);
13
+ /* … while hovered, focused or dragged */
14
+ --stuic-split-pane-separator-color-hover: rgb(0 0 0 / 0.3);
15
+ --stuic-split-pane-separator-thickness: 1px;
16
+ /* invisible grab zone added on each side of the line */
17
+ --stuic-split-pane-separator-hit-area: 4px;
18
+ /* the centered grip on the line */
19
+ --stuic-split-pane-grip-color: var(--color-gray-300);
20
+ --stuic-split-pane-grip-color-hover: var(--color-gray-400);
21
+ --stuic-split-pane-grip-border-color: rgb(0 0 0 / 0.2);
22
+ --stuic-split-pane-grip-length: 20px;
23
+ --stuic-split-pane-grip-thickness: 9px;
24
+ --stuic-split-pane-grip-radius: 0.25rem;
25
+ --stuic-split-pane-ring-color: var(--stuic-color-ring);
26
+ }
27
+
28
+ :root.dark {
29
+ --stuic-split-pane-separator-color: rgb(255 255 255 / 0.1);
30
+ --stuic-split-pane-separator-color-hover: rgb(255 255 255 / 0.2);
31
+ --stuic-split-pane-grip-color: var(--color-gray-600);
32
+ --stuic-split-pane-grip-color-hover: var(--color-gray-500);
33
+ --stuic-split-pane-grip-border-color: rgb(255 255 255 / 0.2);
34
+ }
35
+
36
+ @layer components {
37
+ /* fills its container (a definite container height is what makes the panes scroll
38
+ instead of growing — and what `%` resolves against when vertical) */
39
+ .stuic-split-pane {
40
+ display: flex;
41
+ width: 100%;
42
+ height: 100%;
43
+ overflow: hidden;
44
+ }
45
+
46
+ .stuic-split-pane[data-orientation="horizontal"] {
47
+ flex-direction: row;
48
+ }
49
+
50
+ .stuic-split-pane[data-orientation="vertical"] {
51
+ flex-direction: column;
52
+ }
53
+
54
+ /* the non-primary pane fills what is left and may shrink below its content */
55
+ .stuic-split-pane-pane {
56
+ flex: 1 1 0%;
57
+ min-width: 0;
58
+ min-height: 0;
59
+ overflow: auto;
60
+ }
61
+
62
+ /* the primary pane is exactly its (inline) width / height */
63
+ .stuic-split-pane-pane[data-primary] {
64
+ flex: 0 0 auto;
65
+ }
66
+
67
+ .stuic-split-pane-separator {
68
+ position: relative;
69
+ z-index: 1;
70
+ flex: 0 0 var(--stuic-split-pane-separator-thickness);
71
+ background: var(--stuic-split-pane-separator-color);
72
+ touch-action: none;
73
+ user-select: none;
74
+ outline: none;
75
+ transition: background-color
76
+ var(--stuic-split-pane-transition, var(--stuic-transition));
77
+ }
78
+
79
+ .stuic-split-pane[data-orientation="horizontal"] > .stuic-split-pane-separator {
80
+ cursor: col-resize;
81
+ }
82
+
83
+ .stuic-split-pane[data-orientation="vertical"] > .stuic-split-pane-separator {
84
+ cursor: row-resize;
85
+ }
86
+
87
+ /* grab zone: wider than the line, invisible, paints above the panes (z-index) */
88
+ .stuic-split-pane-separator::before {
89
+ content: "";
90
+ position: absolute;
91
+ inset: 0;
92
+ }
93
+
94
+ .stuic-split-pane[data-orientation="horizontal"] > .stuic-split-pane-separator::before {
95
+ inset-inline: calc(-1 * var(--stuic-split-pane-separator-hit-area));
96
+ }
97
+
98
+ .stuic-split-pane[data-orientation="vertical"] > .stuic-split-pane-separator::before {
99
+ inset-block: calc(-1 * var(--stuic-split-pane-separator-hit-area));
100
+ }
101
+
102
+ /* grip: a small rounded tab centered on the line */
103
+ .stuic-split-pane-separator::after {
104
+ content: "";
105
+ position: absolute;
106
+ left: 50%;
107
+ top: 50%;
108
+ translate: -50% -50%;
109
+ box-sizing: border-box;
110
+ border: 1px solid var(--stuic-split-pane-grip-border-color);
111
+ border-radius: var(--stuic-split-pane-grip-radius);
112
+ background: var(--stuic-split-pane-grip-color);
113
+ transition: background-color
114
+ var(--stuic-split-pane-transition, var(--stuic-transition));
115
+ }
116
+
117
+ .stuic-split-pane[data-orientation="horizontal"] > .stuic-split-pane-separator::after {
118
+ width: var(--stuic-split-pane-grip-thickness);
119
+ height: var(--stuic-split-pane-grip-length);
120
+ }
121
+
122
+ .stuic-split-pane[data-orientation="vertical"] > .stuic-split-pane-separator::after {
123
+ width: var(--stuic-split-pane-grip-length);
124
+ height: var(--stuic-split-pane-grip-thickness);
125
+ }
126
+
127
+ .stuic-split-pane-separator:hover,
128
+ .stuic-split-pane-separator:focus-visible,
129
+ .stuic-split-pane-separator[data-resizing] {
130
+ background: var(--stuic-split-pane-separator-color-hover);
131
+ }
132
+
133
+ .stuic-split-pane-separator:hover::after,
134
+ .stuic-split-pane-separator:focus-visible::after,
135
+ .stuic-split-pane-separator[data-resizing]::after {
136
+ background: var(--stuic-split-pane-grip-color-hover);
137
+ }
138
+
139
+ .stuic-split-pane-separator:focus-visible {
140
+ outline: 2px solid var(--stuic-split-pane-ring-color);
141
+ outline-offset: 0;
142
+ }
143
+
144
+ /* inert: a plain divider */
145
+ .stuic-split-pane[data-disabled] > .stuic-split-pane-separator {
146
+ cursor: default;
147
+ background: var(--stuic-split-pane-separator-color);
148
+ }
149
+
150
+ .stuic-split-pane[data-disabled] > .stuic-split-pane-separator::after {
151
+ display: none;
152
+ }
153
+ }
@@ -0,0 +1,3 @@
1
+ export { default as SplitPane, type Props as SplitPaneProps, type SplitPaneOrientation, type SplitPanePrimary, } from "./SplitPane.svelte";
2
+ export { createSplitPaneT, SPLIT_PANE_MESSAGES_EN, type SplitPaneMessageKey, type SplitPaneMessages, } from "./i18n.js";
3
+ export { SPLIT_PANE_MESSAGES_SK } from "./i18n-sk.js";
@@ -0,0 +1,3 @@
1
+ export { default as SplitPane, } from "./SplitPane.svelte";
2
+ export { createSplitPaneT, SPLIT_PANE_MESSAGES_EN, } from "./i18n.js";
3
+ export { SPLIT_PANE_MESSAGES_SK } from "./i18n-sk.js";
@@ -7,22 +7,22 @@ auto-hides when the container width falls below a configurable threshold
7
7
 
8
8
  ## Props
9
9
 
10
- | Prop | Type | Default | Description |
11
- | -------------------- | ------------------------------------------- | --------- | ------------------------------------------------ |
12
- | `children` | `Snippet` | — | Main content |
13
- | `side` | `Snippet` | — | Side panel content |
14
- | `position` | `"left" \| "right"` | `"left"` | Side panel position |
15
- | `width` | `string` | `"300px"` | Side panel width (CSS value, px or %) |
16
- | `threshold` | `number` | `768` | Container width (px) below which side auto-hides |
17
- | `transition` | `boolean` | `true` | Enable Svelte slide transition |
18
- | `transitionDuration` | `number` | `200` | Transition duration in ms |
19
- | `open` | `boolean` | `true` | Desktop visibility state (bindable) |
20
- | `resizable` | `boolean \| Partial<ResizableWidthOptions>` | `false` | Enable drag-resizable side panel |
21
- | `classMain` | `string` | — | Custom class for main content div |
22
- | `classSide` | `string` | — | Custom class for side panel div |
23
- | `class` | `string` | — | Custom class for wrapper div |
24
- | `unstyled` | `boolean` | `false` | Skip all default styling |
25
- | `el` | `HTMLDivElement` | — | Bindable wrapper element reference |
10
+ | Prop | Type | Default | Description |
11
+ | -------------------- | ------------------------------------------- | --------- | ---------------------------------------------------------------------------------------- |
12
+ | `children` | `Snippet` | — | Main content |
13
+ | `side` | `Snippet` | — | Side panel content |
14
+ | `position` | `"left" \| "right"` | `"left"` | Side panel position |
15
+ | `width` | `string` | `"300px"` | Side panel width (CSS value, px or %) |
16
+ | `threshold` | `number` | `768` | Container width (px) below which side auto-hides |
17
+ | `transition` | `boolean` | `true` | Enable Svelte slide transition |
18
+ | `transitionDuration` | `number` | `200` | Transition duration in ms |
19
+ | `open` | `boolean` | `true` | Desktop visibility state (bindable) |
20
+ | `resizable` | `boolean \| Partial<ResizableWidthOptions>` | `false` | Enable drag-resizable side panel (the edge handle is also a keyboard-operable separator) |
21
+ | `classMain` | `string` | — | Custom class for main content div |
22
+ | `classSide` | `string` | — | Custom class for side panel div |
23
+ | `class` | `string` | — | Custom class for wrapper div |
24
+ | `unstyled` | `boolean` | `false` | Skip all default styling |
25
+ | `el` | `HTMLDivElement` | — | Bindable wrapper element reference |
26
26
 
27
27
  ## API (via `bind:this`)
28
28
 
@@ -67,6 +67,9 @@ auto-hides when the container width falls below a configurable threshold
67
67
 
68
68
  ### Resizable
69
69
 
70
+ The edge handle is a focusable `role="separator"` (the `resizable` attachment's): arrow keys
71
+ resize it (Shift ×10), Home / End go to `min` / `max`, Enter or double-click resets.
72
+
70
73
  ```svelte
71
74
  <WithSidePanel resizable={{ min: 200, max: 500, key: "sidebar", storage: "local" }}>
72
75
  {#snippet side()}
@@ -58,6 +58,8 @@ export { iconLucideSun as iconSun } from "@marianmeres/icons-fns/lucide/iconLuci
58
58
  export { iconLucideUser as iconUser } from "@marianmeres/icons-fns/lucide/iconLucideUser.js";
59
59
  export { iconLucideX as iconX } from "@marianmeres/icons-fns/lucide/iconLucideX.js";
60
60
  export { iconLucidePencil as iconPencil } from "@marianmeres/icons-fns/lucide/iconLucidePencil.js";
61
+ export { iconBsStar as iconStar } from "@marianmeres/icons-fns/bootstrap/iconBsStar.js";
62
+ export { iconBsStarFill as iconStarFill } from "@marianmeres/icons-fns/bootstrap/iconBsStarFill.js";
61
63
  export { iconLucideBold as iconBold } from "@marianmeres/icons-fns/lucide/iconLucideBold.js";
62
64
  export { iconLucideItalic as iconItalic } from "@marianmeres/icons-fns/lucide/iconLucideItalic.js";
63
65
  export { iconLucideHeading1 as iconHeading1 } from "@marianmeres/icons-fns/lucide/iconLucideHeading1.js";
@@ -63,6 +63,9 @@ export { iconLucideSun as iconSun } from "@marianmeres/icons-fns/lucide/iconLuci
63
63
  export { iconLucideUser as iconUser } from "@marianmeres/icons-fns/lucide/iconLucideUser.js";
64
64
  export { iconLucideX as iconX } from "@marianmeres/icons-fns/lucide/iconLucideX.js";
65
65
  export { iconLucidePencil as iconPencil } from "@marianmeres/icons-fns/lucide/iconLucidePencil.js";
66
+ // Rating Icons (Bootstrap)
67
+ export { iconBsStar as iconStar } from "@marianmeres/icons-fns/bootstrap/iconBsStar.js";
68
+ export { iconBsStarFill as iconStarFill } from "@marianmeres/icons-fns/bootstrap/iconBsStarFill.js";
66
69
  // Markdown Editor / formatting toolbar Icons (Lucide)
67
70
  // (bullet list reuses `iconList` and horizontal rule reuses `iconMinus` above)
68
71
  export { iconLucideBold as iconBold } from "@marianmeres/icons-fns/lucide/iconLucideBold.js";
package/dist/index.css CHANGED
@@ -103,11 +103,14 @@ In practice:
103
103
  @import "./components/Pill/index.css";
104
104
  @import "./components/PricingTable/index.css";
105
105
  @import "./components/Progress/index.css";
106
+ @import "./components/RangeSlider/index.css";
107
+ @import "./components/Rating/index.css";
106
108
  @import "./components/Separator/index.css";
107
109
  @import "./components/Skeleton/index.css";
108
110
  @import "./components/Slider/index.css";
109
111
  @import "./components/Spinner/index.css";
110
112
  @import "./components/SplitButton/index.css";
113
+ @import "./components/SplitPane/index.css";
111
114
  @import "./components/Stat/index.css";
112
115
  @import "./components/Stepper/index.css";
113
116
  @import "./components/Switch/index.css";
package/dist/index.d.ts CHANGED
@@ -73,12 +73,15 @@ export * from "./components/Pagination/index.js";
73
73
  export * from "./components/Pill/index.js";
74
74
  export * from "./components/PricingTable/index.js";
75
75
  export * from "./components/Progress/index.js";
76
+ export * from "./components/RangeSlider/index.js";
77
+ export * from "./components/Rating/index.js";
76
78
  export * from "./components/Separator/index.js";
77
79
  export * from "./components/Skeleton/index.js";
78
80
  export * from "./components/Slider/index.js";
79
81
  export * from "./components/SlidingPanels/index.js";
80
82
  export * from "./components/Spinner/index.js";
81
83
  export * from "./components/SplitButton/index.js";
84
+ export * from "./components/SplitPane/index.js";
82
85
  export * from "./components/Stat/index.js";
83
86
  export * from "./components/Stepper/index.js";
84
87
  export * from "./components/Switch/index.js";
package/dist/index.js CHANGED
@@ -79,12 +79,15 @@ export * from "./components/Pagination/index.js";
79
79
  export * from "./components/Pill/index.js";
80
80
  export * from "./components/PricingTable/index.js";
81
81
  export * from "./components/Progress/index.js";
82
+ export * from "./components/RangeSlider/index.js";
83
+ export * from "./components/Rating/index.js";
82
84
  export * from "./components/Separator/index.js";
83
85
  export * from "./components/Skeleton/index.js";
84
86
  export * from "./components/Slider/index.js";
85
87
  export * from "./components/SlidingPanels/index.js";
86
88
  export * from "./components/Spinner/index.js";
87
89
  export * from "./components/SplitButton/index.js";
90
+ export * from "./components/SplitPane/index.js";
88
91
  export * from "./components/Stat/index.js";
89
92
  export * from "./components/Stepper/index.js";
90
93
  export * from "./components/Switch/index.js";
@@ -49,16 +49,27 @@ Checked first, to avoid false positives:
49
49
  reusable `longPress` attachment), Shift+F10 / menu key.
50
50
  6. ~~**EmptyState**~~ — ✅ shipped (see `src/lib/components/EmptyState/`): icon +
51
51
  title + description + CTA placeholder for empty lists/tables/search results.
52
- 7. **Rating (stars)** — display + input variants. `FieldLikeButton` is adjacent but not
53
- this.
52
+ 7. ~~**Rating (stars)**~~ — ✅ shipped (see `src/lib/components/Rating/`): input
53
+ (radiogroup of per-star radios, half steps, hover preview, click-again-to-clear,
54
+ keyboard, hidden input + `validate` with `required`) and `readonly` display
55
+ (`role="img"`, fractional fill); custom `icon` / `iconEmpty`, `intent`, sizes,
56
+ `t` texts with Slovak bundled.
54
57
 
55
58
  ## Tier 3 — common, but judge by actual app needs
56
59
 
57
- 8. **SplitPane / resizable panels** — general two-pane draggable splitter
58
- (horizontal/vertical, min/max, persisted size). `actions/resizable-width`,
59
- `WithSidePanel`, and `persistent-state` already provide the pieces.
60
- 9. **Range slider (dual-thumb)** — `Slider` is deliberately single-value; a min/max
61
- range variant (price filters etc.) is a recurring ask.
60
+ 8. ~~**SplitPane / resizable panels**~~ — ✅ shipped (see `src/lib/components/SplitPane/`
61
+ and `src/lib/attachments/resizable.ts`): the `resizable-width` action generalised into a
62
+ `resizable` attachment (`axis: "x" | "y"`, `px` / `%`, `min` / `max`, `key` persistence,
63
+ `handle` for an own separator, `onInit` api) whose handle is an ARIA window splitter
64
+ (arrows / Home / End / Enter); `resizableWidth` stays as a thin wrapper over it, so
65
+ `WithSidePanel` got the keyboard for free. `SplitPane` wraps it: `start` / `end`
66
+ snippets, `orientation`, `primary`, `bind:size`, `reset()`, `disabled`, tokens, `t` with
67
+ Slovak bundled.
68
+ 9. ~~**Range slider (dual-thumb)**~~ — ✅ shipped (see `src/lib/components/RangeSlider/`):
69
+ `Slider`'s two-value sibling — `bind:start` / `bind:end` on one track with the fill
70
+ between them; nearest-thumb press, grab-to-drag, thumbs never cross (`minRange`),
71
+ per-thumb keyboard via two hidden range inputs (`nameStart` / `nameEnd`), ticks,
72
+ value labels, `validate` with the pair, `t` thumb names with Slovak bundled.
62
73
  10. ~~**Timeline / activity feed**~~ — ✅ shipped (see `src/lib/components/Timeline/`):
63
74
  vertical event list on a rail with dot / icon-bubble / custom (snippet) markers,
64
75
  per-item intent, `<time datetime>` support with an optional formatter, inline or
@@ -36,7 +36,7 @@ Layer 4: Internal Vars (--_bg, --_text, --_border)
36
36
 
37
37
  ```
38
38
  src/lib/
39
- ├── components/ # 75 component directories
39
+ ├── components/ # 78 component directories
40
40
  │ └── {Name}/
41
41
  │ ├── {Name}.svelte # Main component
42
42
  │ ├── index.ts # Exports
@@ -8,24 +8,24 @@
8
8
 
9
9
  ## Available Actions
10
10
 
11
- | Action | Purpose | File |
12
- | ------------------------- | ------------------------------------------------------------- | ------------------------------------ |
13
- | `validate` | Form field validation with i18n support | `validate.svelte.ts` |
14
- | `focusTrap` | Keyboard focus containment (modals/dialogs) | `focus-trap.ts` |
15
- | `autogrow` | Auto-resize textarea to content | `autogrow.svelte.ts` |
16
- | `autoscroll` | Auto-scroll container to bottom | `autoscroll.ts` |
17
- | `dimBehind` | Dim everything behind a target element (simplified spotlight) | `dim-behind/` |
18
- | `fileDropzone` | Drag-and-drop file handling | `file-dropzone.svelte.ts` |
19
- | `highlightDragover` | Visual feedback on drag-over | `highlight-dragover.svelte.ts` |
20
- | `resizableWidth` | Draggable width resizing | `resizable-width.svelte.ts` |
21
- | `draggable` | Pointer-delta drag handle (consumer owns the movement) | `draggable.svelte.ts` |
22
- | `trim` | Auto-trim whitespace from input | `trim.svelte.ts` |
23
- | `typeahead` | Advanced autocomplete behavior | `typeahead.svelte.ts` |
24
- | `onSubmitValidityCheck` | Form submit validation | `on-submit-validity-check.svelte.ts` |
25
- | `popover` | Popover positioning | `popover/` |
26
- | `spotlight` | Spotlight/coach mark overlay with cutout hole | `spotlight/` |
27
- | `tooltip` | Tooltip positioning and display | `tooltip/` |
28
- | `createTour` / `tourStep` | Multi-step onboarding tour (built on spotlight) | `onboarding/` |
11
+ | Action | Purpose | File |
12
+ | ------------------------- | ----------------------------------------------------------------------- | ------------------------------------ |
13
+ | `validate` | Form field validation with i18n support | `validate.svelte.ts` |
14
+ | `focusTrap` | Keyboard focus containment (modals/dialogs) | `focus-trap.ts` |
15
+ | `autogrow` | Auto-resize textarea to content | `autogrow.svelte.ts` |
16
+ | `autoscroll` | Auto-scroll container to bottom | `autoscroll.ts` |
17
+ | `dimBehind` | Dim everything behind a target element (simplified spotlight) | `dim-behind/` |
18
+ | `fileDropzone` | Drag-and-drop file handling | `file-dropzone.svelte.ts` |
19
+ | `highlightDragover` | Visual feedback on drag-over | `highlight-dragover.svelte.ts` |
20
+ | `resizableWidth` | Draggable width resizing (thin wrapper over the `resizable` attachment) | `resizable-width.svelte.ts` |
21
+ | `draggable` | Pointer-delta drag handle (consumer owns the movement) | `draggable.svelte.ts` |
22
+ | `trim` | Auto-trim whitespace from input | `trim.svelte.ts` |
23
+ | `typeahead` | Advanced autocomplete behavior | `typeahead.svelte.ts` |
24
+ | `onSubmitValidityCheck` | Form submit validation | `on-submit-validity-check.svelte.ts` |
25
+ | `popover` | Popover positioning | `popover/` |
26
+ | `spotlight` | Spotlight/coach mark overlay with cutout hole | `spotlight/` |
27
+ | `tooltip` | Tooltip positioning and display | `tooltip/` |
28
+ | `createTour` / `tourStep` | Multi-step onboarding tour (built on spotlight) | `onboarding/` |
29
29
 
30
30
  ---
31
31