@marianmeres/stuic 3.172.0 → 3.174.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 +19 -4
- package/API.md +56 -2
- package/README.md +21 -5
- package/dist/actions/resizable-width.svelte.d.ts +14 -28
- package/dist/actions/resizable-width.svelte.js +16 -171
- package/dist/attachments/index.d.ts +1 -0
- package/dist/attachments/index.js +1 -0
- package/dist/attachments/resizable.d.ts +113 -0
- package/dist/attachments/resizable.fixture.svelte +53 -0
- package/dist/attachments/resizable.fixture.svelte.d.ts +10 -0
- package/dist/attachments/resizable.js +295 -0
- package/dist/components/Button/README.md +11 -10
- package/dist/components/ButtonGroupRadio/README.md +52 -23
- package/dist/components/ButtonGroupRadio/index.css +6 -2
- package/dist/components/PricingTable/PricingTable.svelte +8 -14
- package/dist/components/PricingTable/README.md +29 -6
- package/dist/components/PricingTable/index.css +54 -0
- package/dist/components/RangeSlider/README.md +291 -0
- package/dist/components/RangeSlider/RangeSlider.svelte +763 -0
- package/dist/components/RangeSlider/RangeSlider.svelte.d.ts +130 -0
- package/dist/components/RangeSlider/i18n-sk.d.ts +17 -0
- package/dist/components/RangeSlider/i18n-sk.js +19 -0
- package/dist/components/RangeSlider/i18n.d.ts +33 -0
- package/dist/components/RangeSlider/i18n.js +41 -0
- package/dist/components/RangeSlider/index.css +430 -0
- package/dist/components/RangeSlider/index.d.ts +3 -0
- package/dist/components/RangeSlider/index.js +3 -0
- package/dist/components/Rating/README.md +206 -0
- package/dist/components/Rating/Rating.svelte +355 -0
- package/dist/components/Rating/Rating.svelte.d.ts +82 -0
- package/dist/components/Rating/i18n-sk.d.ts +17 -0
- package/dist/components/Rating/i18n-sk.js +21 -0
- package/dist/components/Rating/i18n.d.ts +34 -0
- package/dist/components/Rating/i18n.js +42 -0
- package/dist/components/Rating/index.css +170 -0
- package/dist/components/Rating/index.d.ts +3 -0
- package/dist/components/Rating/index.js +3 -0
- package/dist/components/SplitPane/README.md +169 -0
- package/dist/components/SplitPane/SplitPane.svelte +202 -0
- package/dist/components/SplitPane/SplitPane.svelte.d.ts +67 -0
- package/dist/components/SplitPane/i18n-sk.d.ts +17 -0
- package/dist/components/SplitPane/i18n-sk.js +18 -0
- package/dist/components/SplitPane/i18n.d.ts +31 -0
- package/dist/components/SplitPane/i18n.js +39 -0
- package/dist/components/SplitPane/index.css +153 -0
- package/dist/components/SplitPane/index.d.ts +3 -0
- package/dist/components/SplitPane/index.js +3 -0
- package/dist/components/WithSidePanel/README.md +19 -16
- package/dist/icons/index.d.ts +2 -0
- package/dist/icons/index.js +3 -0
- package/dist/index.css +17 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/docs/{maybe-todo.md → _archive/maybe-todo.md} +18 -7
- package/docs/architecture.md +1 -1
- package/docs/conventions.md +27 -7
- package/docs/domains/actions.md +18 -18
- package/docs/domains/attachments.md +72 -9
- package/docs/domains/components.md +175 -32
- package/docs/domains/theming.md +57 -13
- 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";
|
|
@@ -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()}
|
package/dist/icons/index.d.ts
CHANGED
|
@@ -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";
|
package/dist/icons/index.js
CHANGED
|
@@ -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
|
@@ -29,6 +29,20 @@ In practice:
|
|
|
29
29
|
These tokens provide a single point of control for cross-component properties.
|
|
30
30
|
Override globally: :root { --stuic-radius: 0; }
|
|
31
31
|
Override per-component: --stuic-button-radius: 9999px; (takes precedence)
|
|
32
|
+
|
|
33
|
+
NOTE on the mirrored names. The tokens below are TIER tokens, named
|
|
34
|
+
--stuic-{property}-{tier}, and they ARE declared here. Component override tokens
|
|
35
|
+
are the transposition, --stuic-{component}-{property}, and are NEVER declared --
|
|
36
|
+
they exist only as the first argument of a var() fallback at the usage site:
|
|
37
|
+
|
|
38
|
+
border-radius: var(--stuic-button-radius, var(--stuic-radius-button));
|
|
39
|
+
^ component token (3) ^ tier token (2, declared here)
|
|
40
|
+
|
|
41
|
+
So --stuic-radius-button (tier) applies to Button, SplitButton and ButtonGroupRadio,
|
|
42
|
+
while --stuic-button-radius (component) applies to Button alone. Same relationship
|
|
43
|
+
between --stuic-border-width-button and --stuic-button-border-width. "button" is the
|
|
44
|
+
only tier name that is also a component name, hence the only confusable pair -- do
|
|
45
|
+
not "fix" one into the other.
|
|
32
46
|
============================================================================ */
|
|
33
47
|
:root {
|
|
34
48
|
/* Radius: three tiers */
|
|
@@ -103,11 +117,14 @@ In practice:
|
|
|
103
117
|
@import "./components/Pill/index.css";
|
|
104
118
|
@import "./components/PricingTable/index.css";
|
|
105
119
|
@import "./components/Progress/index.css";
|
|
120
|
+
@import "./components/RangeSlider/index.css";
|
|
121
|
+
@import "./components/Rating/index.css";
|
|
106
122
|
@import "./components/Separator/index.css";
|
|
107
123
|
@import "./components/Skeleton/index.css";
|
|
108
124
|
@import "./components/Slider/index.css";
|
|
109
125
|
@import "./components/Spinner/index.css";
|
|
110
126
|
@import "./components/SplitButton/index.css";
|
|
127
|
+
@import "./components/SplitPane/index.css";
|
|
111
128
|
@import "./components/Stat/index.css";
|
|
112
129
|
@import "./components/Stepper/index.css";
|
|
113
130
|
@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.
|
|
53
|
-
|
|
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.
|
|
58
|
-
|
|
59
|
-
`
|
|
60
|
-
|
|
61
|
-
|
|
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
|
package/docs/architecture.md
CHANGED
package/docs/conventions.md
CHANGED
|
@@ -43,12 +43,14 @@ Global tokens in `src/lib/index.css` that control cross-component visual propert
|
|
|
43
43
|
/* Brutalist example — 7 lines to transform everything */
|
|
44
44
|
:root {
|
|
45
45
|
--stuic-radius: 0;
|
|
46
|
+
--stuic-radius-button: 0;
|
|
46
47
|
--stuic-radius-container: 0;
|
|
47
48
|
--stuic-shadow: none;
|
|
48
49
|
--stuic-shadow-hover: none;
|
|
49
50
|
--stuic-shadow-overlay: none;
|
|
50
51
|
--stuic-shadow-dialog: none;
|
|
51
52
|
--stuic-border-width: 0;
|
|
53
|
+
--stuic-border-width-button: 0;
|
|
52
54
|
}
|
|
53
55
|
```
|
|
54
56
|
|
|
@@ -79,16 +81,34 @@ Component CSS must reference shared tokens as **fallbacks at usage sites**, not
|
|
|
79
81
|
|
|
80
82
|
Per-component overrides (`--stuic-widget-radius: 0`) still take precedence over the shared fallback.
|
|
81
83
|
|
|
82
|
-
### Element vs Container
|
|
84
|
+
### Element vs Button vs Container
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
Three tiers of radius for natural visual hierarchy:
|
|
85
87
|
|
|
86
|
-
| Tier | Token | Default | Use for
|
|
87
|
-
| --------- | -------------------------- | ------------------ |
|
|
88
|
-
| Element | `--stuic-radius` | `var(--radius-md)` |
|
|
89
|
-
|
|
|
88
|
+
| Tier | Token | Default | Use for |
|
|
89
|
+
| --------- | -------------------------- | ------------------ | --------------------------------------------------- |
|
|
90
|
+
| Element | `--stuic-radius` | `var(--radius-md)` | Inputs, badges, list items, checkboxes, tabs |
|
|
91
|
+
| Button | `--stuic-radius-button` | `var(--radius-md)` | Buttons, split buttons, button groups |
|
|
92
|
+
| Container | `--stuic-radius-container` | `var(--radius-lg)` | Cards, modals, dropdowns, notifications, accordions |
|
|
90
93
|
|
|
91
|
-
**Rule of thumb:** if it wraps other interactive elements, it's a container.
|
|
94
|
+
**Rule of thumb:** if it wraps other interactive elements, it's a container. Buttons get
|
|
95
|
+
their own tier so a flat-input theme can still have pill buttons (and vice versa);
|
|
96
|
+
`--stuic-border-width-button` splits out the same way.
|
|
97
|
+
|
|
98
|
+
### Tier tokens vs component tokens
|
|
99
|
+
|
|
100
|
+
The two layers use mirrored names, which is easy to misread for the button tier:
|
|
101
|
+
|
|
102
|
+
| Name | Layer | Declared? | Scope |
|
|
103
|
+
| ----------------------------- | ------------------- | --------------------- | ----------------------------- |
|
|
104
|
+
| `--stuic-radius-button` | shared tier (2) | yes, in `index.css` | every button-family component |
|
|
105
|
+
| `--stuic-button-radius` | component token (3) | no, fallback arg only | `Button` only |
|
|
106
|
+
| `--stuic-border-width-button` | shared tier (2) | yes, in `index.css` | every button-family component |
|
|
107
|
+
| `--stuic-button-border-width` | component token (3) | no, fallback arg only | `Button` only |
|
|
108
|
+
|
|
109
|
+
Read it as `--stuic-{property}-{tier}` for tier tokens and `--stuic-{component}-{property}`
|
|
110
|
+
for component tokens. `button` is the only tier name that is also a component name, so it
|
|
111
|
+
is the only pair that reads as a transposition.
|
|
92
112
|
|
|
93
113
|
---
|
|
94
114
|
|
package/docs/domains/actions.md
CHANGED
|
@@ -8,24 +8,24 @@
|
|
|
8
8
|
|
|
9
9
|
## Available Actions
|
|
10
10
|
|
|
11
|
-
| Action | Purpose
|
|
12
|
-
| ------------------------- |
|
|
13
|
-
| `validate` | Form field validation with i18n support
|
|
14
|
-
| `focusTrap` | Keyboard focus containment (modals/dialogs)
|
|
15
|
-
| `autogrow` | Auto-resize textarea to content
|
|
16
|
-
| `autoscroll` | Auto-scroll container to bottom
|
|
17
|
-
| `dimBehind` | Dim everything behind a target element (simplified spotlight)
|
|
18
|
-
| `fileDropzone` | Drag-and-drop file handling
|
|
19
|
-
| `highlightDragover` | Visual feedback on drag-over
|
|
20
|
-
| `resizableWidth` | Draggable width resizing
|
|
21
|
-
| `draggable` | Pointer-delta drag handle (consumer owns the movement)
|
|
22
|
-
| `trim` | Auto-trim whitespace from input
|
|
23
|
-
| `typeahead` | Advanced autocomplete behavior
|
|
24
|
-
| `onSubmitValidityCheck` | Form submit validation
|
|
25
|
-
| `popover` | Popover positioning
|
|
26
|
-
| `spotlight` | Spotlight/coach mark overlay with cutout hole
|
|
27
|
-
| `tooltip` | Tooltip positioning and display
|
|
28
|
-
| `createTour` / `tourStep` | Multi-step onboarding tour (built on spotlight)
|
|
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
|
|