@marianmeres/stuic 3.45.3 → 3.47.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.
@@ -0,0 +1,95 @@
1
+ import type { HTMLAttributes } from "svelte/elements";
2
+ import type { TreeNodeDTO } from "@marianmeres/tree";
3
+ import type { Snippet } from "svelte";
4
+ export type TreeDropPosition = "before" | "after" | "inside";
5
+ export interface TreeMoveEvent<T = unknown> {
6
+ /** The node being dragged */
7
+ source: TreeNodeDTO<T>;
8
+ /** The node being dropped onto/near */
9
+ target: TreeNodeDTO<T>;
10
+ /** Where relative to target: 'before' (sibling above), 'after' (sibling below), 'inside' (child) */
11
+ position: TreeDropPosition;
12
+ }
13
+ export interface Props<T = unknown> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
14
+ /** The tree data (use tree.toJSON().children or raw TreeNodeDTO[]) */
15
+ items: TreeNodeDTO<T>[];
16
+ /** Render snippet for each item's content - receives (item, depth, isExpanded) */
17
+ renderItem?: Snippet<[TreeNodeDTO<T>, number, boolean]>;
18
+ /** Render snippet for item icon - receives (item, depth, isExpanded) */
19
+ renderIcon?: Snippet<[TreeNodeDTO<T>, number, boolean]>;
20
+ /** Active/selected item ID */
21
+ activeId?: string;
22
+ /** Callback to check if item is active (alternative to activeId) */
23
+ isActive?: (item: TreeNodeDTO<T>) => boolean;
24
+ /** Callback when an item is selected */
25
+ onSelect?: (item: TreeNodeDTO<T>) => void;
26
+ /** Callback when a branch is toggled */
27
+ onToggle?: (item: TreeNodeDTO<T>, expanded: boolean) => void;
28
+ /** Sort comparator (applied at each level) */
29
+ sort?: (a: TreeNodeDTO<T>, b: TreeNodeDTO<T>) => number;
30
+ /** Default expanded state for branches (default: false) */
31
+ defaultExpanded?: boolean;
32
+ /** Set of initially expanded branch IDs */
33
+ expandedIds?: Set<string>;
34
+ /** Enable localStorage persistence for expand/collapse state */
35
+ persistState?: boolean;
36
+ /** Storage key prefix for localStorage (default: 'stuic-tree') */
37
+ storageKeyPrefix?: string;
38
+ /** Enable drag-and-drop node reordering (default: false) */
39
+ draggable?: boolean;
40
+ /** Per-item drag control: return false to prevent dragging a specific item */
41
+ isDraggable?: (item: TreeNodeDTO<T>) => boolean;
42
+ /** Per-item drop target control: return false to prevent dropping onto a specific item */
43
+ isDropTarget?: (item: TreeNodeDTO<T>) => boolean;
44
+ /** Called on drop. Return false or throw to reject the move. */
45
+ onMove?: (event: TreeMoveEvent<T>) => void | false | Promise<void | false>;
46
+ /** Called when onMove throws an error */
47
+ onError?: (error: unknown) => void;
48
+ /** Delay in ms before auto-expanding a collapsed branch on drag-over (default: 800) */
49
+ dragExpandDelay?: number;
50
+ /** Skip all default styling */
51
+ unstyled?: boolean;
52
+ /** Classes for the wrapper element */
53
+ class?: string;
54
+ /** Element reference */
55
+ el?: HTMLElement;
56
+ /** Classes for individual items */
57
+ classItem?: string;
58
+ /** Classes for active items */
59
+ classItemActive?: string;
60
+ /** Classes for icons */
61
+ classIcon?: string;
62
+ /** Classes for labels */
63
+ classLabel?: string;
64
+ /** Classes for children container */
65
+ classChildren?: string;
66
+ /** Classes for chevron icon */
67
+ classChevron?: string;
68
+ }
69
+ export declare const TREE_BASE_CLASSES = "stuic-tree";
70
+ export declare const TREE_ITEM_CLASSES = "stuic-tree-item";
71
+ export declare const TREE_CHILDREN_CLASSES = "stuic-tree-children";
72
+ declare function $$render<T = unknown>(): {
73
+ props: Props<T>;
74
+ exports: {};
75
+ bindings: "el";
76
+ slots: {};
77
+ events: {};
78
+ };
79
+ declare class __sveltets_Render<T = unknown> {
80
+ props(): ReturnType<typeof $$render<T>>['props'];
81
+ events(): ReturnType<typeof $$render<T>>['events'];
82
+ slots(): ReturnType<typeof $$render<T>>['slots'];
83
+ bindings(): "el";
84
+ exports(): {};
85
+ }
86
+ interface $$IsomorphicComponent {
87
+ new <T = unknown>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
88
+ $$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
89
+ } & ReturnType<__sveltets_Render<T>['exports']>;
90
+ <T = unknown>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
91
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
92
+ }
93
+ declare const Tree: $$IsomorphicComponent;
94
+ type Tree<T = unknown> = InstanceType<typeof Tree<T>>;
95
+ export default Tree;
@@ -0,0 +1,186 @@
1
+ /* =============================================================================
2
+ TREE COMPONENT TOKENS
3
+ Override globally: :root { --stuic-tree-indent: 1.5rem; }
4
+ Override locally: <Tree style="--stuic-tree-indent: 2rem;">
5
+ ============================================================================= */
6
+
7
+ :root {
8
+ /* Structure tokens */
9
+ --stuic-tree-transition: 150ms;
10
+
11
+ /* Indentation per depth level */
12
+ --stuic-tree-indent: 1.25rem;
13
+
14
+ /* Item sizing */
15
+ --stuic-tree-item-padding-x: 0.375rem;
16
+ --stuic-tree-item-padding-y: 0.125rem;
17
+ --stuic-tree-item-height: 1.75rem;
18
+ --stuic-tree-item-font-size: var(--text-sm);
19
+ --stuic-tree-item-radius: var(--radius-sm);
20
+ --stuic-tree-item-gap: 0.25rem;
21
+
22
+ /* Chevron */
23
+ --stuic-tree-chevron-size: 14px;
24
+ --stuic-tree-chevron-opacity: 0.5;
25
+
26
+ /* Icon */
27
+ --stuic-tree-icon-opacity: 0.7;
28
+
29
+ /* Drag and drop */
30
+ --stuic-tree-item-opacity-dragging: 0.4;
31
+ --stuic-tree-drop-indicator-color: var(--stuic-color-primary);
32
+ --stuic-tree-drop-indicator-height: 2px;
33
+ --stuic-tree-item-bg-dragover: rgb(0 0 0 / 0.04);
34
+
35
+ /* Color tokens: Base */
36
+ --stuic-tree-item-bg: transparent;
37
+ --stuic-tree-item-text: inherit;
38
+
39
+ /* Color tokens: Hover */
40
+ --stuic-tree-item-bg-hover: rgb(0 0 0 / 0.06);
41
+ --stuic-tree-item-text-hover: inherit;
42
+
43
+ /* Color tokens: Active/Selected */
44
+ --stuic-tree-item-bg-active: var(--stuic-color-primary);
45
+ --stuic-tree-item-text-active: var(--stuic-color-primary-foreground);
46
+
47
+ /* Color tokens: Focused (keyboard) */
48
+ --stuic-tree-item-bg-focus: rgb(0 0 0 / 0.06);
49
+ --stuic-tree-item-text-focus: inherit;
50
+ }
51
+
52
+ :root.dark {
53
+ --stuic-tree-item-bg-hover: rgb(255 255 255 / 0.08);
54
+ --stuic-tree-item-bg-focus: rgb(255 255 255 / 0.08);
55
+ --stuic-tree-item-bg-dragover: rgb(255 255 255 / 0.04);
56
+ }
57
+
58
+ @layer components {
59
+ /* =============================================================================
60
+ BASE CONTAINER
61
+ ============================================================================= */
62
+
63
+ .stuic-tree {
64
+ display: flex;
65
+ flex-direction: column;
66
+ }
67
+
68
+ /* =============================================================================
69
+ CHILDREN CONTAINER
70
+ ============================================================================= */
71
+
72
+ .stuic-tree-children {
73
+ display: flex;
74
+ flex-direction: column;
75
+ }
76
+
77
+ /* =============================================================================
78
+ ITEM STYLES
79
+ ============================================================================= */
80
+
81
+ .stuic-tree-item {
82
+ /* Layout */
83
+ display: flex;
84
+ align-items: center;
85
+ gap: var(--stuic-tree-item-gap);
86
+ width: 100%;
87
+ min-height: var(--stuic-tree-item-height);
88
+
89
+ /* Padding */
90
+ padding: var(--stuic-tree-item-padding-y) var(--stuic-tree-item-padding-x);
91
+
92
+ /* Typography */
93
+ font-size: var(--stuic-tree-item-font-size);
94
+ text-align: left;
95
+ line-height: 1.2;
96
+
97
+ /* Visual */
98
+ border-radius: var(--stuic-tree-item-radius);
99
+ background: var(--stuic-tree-item-bg);
100
+ color: var(--stuic-tree-item-text);
101
+ border: none;
102
+
103
+ /* Interaction */
104
+ cursor: pointer;
105
+ user-select: none;
106
+ -webkit-tap-highlight-color: transparent;
107
+ transition:
108
+ background var(--stuic-tree-transition),
109
+ color var(--stuic-tree-transition);
110
+ }
111
+
112
+ /* Chevron opacity */
113
+ .stuic-tree-item > span:first-child {
114
+ opacity: var(--stuic-tree-chevron-opacity);
115
+ }
116
+
117
+ /* Icon opacity (second span when present) */
118
+ .stuic-tree-item > span:nth-child(2) {
119
+ opacity: var(--stuic-tree-icon-opacity);
120
+ }
121
+
122
+ /* =============================================================================
123
+ ITEM STATE STYLES
124
+ ============================================================================= */
125
+
126
+ /* Hover state */
127
+ .stuic-tree-item:hover:not([data-active]) {
128
+ background: var(--stuic-tree-item-bg-hover);
129
+ color: var(--stuic-tree-item-text-hover);
130
+ }
131
+
132
+ /* Focus styles */
133
+ .stuic-tree-item:focus {
134
+ outline: none;
135
+ }
136
+
137
+ .stuic-tree-item:focus-visible:not([data-active]) {
138
+ background: var(--stuic-tree-item-bg-focus);
139
+ color: var(--stuic-tree-item-text-focus);
140
+ }
141
+
142
+ /* Active/Selected state */
143
+ .stuic-tree-item[data-active] {
144
+ background: var(--stuic-tree-item-bg-active);
145
+ color: var(--stuic-tree-item-text-active);
146
+ }
147
+
148
+ /* Active state: full opacity on chevron and icon */
149
+ .stuic-tree-item[data-active] > span:first-child,
150
+ .stuic-tree-item[data-active] > span:nth-child(2) {
151
+ opacity: 1;
152
+ }
153
+
154
+ /* Focused state (keyboard navigation) */
155
+ .stuic-tree-item[data-focused]:not([data-active]) {
156
+ background: var(--stuic-tree-item-bg-focus);
157
+ color: var(--stuic-tree-item-text-focus);
158
+ }
159
+
160
+ /* =============================================================================
161
+ DRAG AND DROP
162
+ ============================================================================= */
163
+
164
+ .stuic-tree-item[data-dragging] {
165
+ opacity: var(--stuic-tree-item-opacity-dragging);
166
+ }
167
+
168
+ [role="treeitem"][data-drop-position="before"] > .stuic-tree-item,
169
+ [role="treeitem"][data-drop-position="after"] > .stuic-tree-item {
170
+ border-radius: 0;
171
+ }
172
+
173
+ [role="treeitem"][data-drop-position="before"] > .stuic-tree-item {
174
+ box-shadow: 0 var(--stuic-tree-drop-indicator-height) 0 0
175
+ var(--stuic-tree-drop-indicator-color) inset;
176
+ }
177
+
178
+ [role="treeitem"][data-drop-position="after"] > .stuic-tree-item {
179
+ box-shadow: 0 calc(-1 * var(--stuic-tree-drop-indicator-height)) 0 0
180
+ var(--stuic-tree-drop-indicator-color) inset;
181
+ }
182
+
183
+ [role="treeitem"][data-drop-position="inside"] > .stuic-tree-item {
184
+ background: var(--stuic-tree-item-bg-dragover);
185
+ }
186
+ }
@@ -0,0 +1,2 @@
1
+ export { default as Tree, type Props as TreeProps, type TreeMoveEvent, type TreeDropPosition, TREE_BASE_CLASSES, TREE_ITEM_CLASSES, TREE_CHILDREN_CLASSES, } from "./Tree.svelte";
2
+ export type { TreeNodeDTO } from "@marianmeres/tree";
@@ -0,0 +1 @@
1
+ export { default as Tree, TREE_BASE_CLASSES, TREE_ITEM_CLASSES, TREE_CHILDREN_CLASSES, } from "./Tree.svelte";
@@ -39,8 +39,10 @@ export { iconLucideGrip as iconGrip } from "@marianmeres/icons-fns/lucide/iconLu
39
39
  export { iconLucideGripHorizontal as iconGripHorizontal } from "@marianmeres/icons-fns/lucide/iconLucideGripHorizontal.js";
40
40
  export { iconLucideGripVertical as iconGripVertical } from "@marianmeres/icons-fns/lucide/iconLucideGripVertical.js";
41
41
  export { iconLucideLanguages as iconLanguages } from "@marianmeres/icons-fns/lucide/iconLucideLanguages.js";
42
+ export { iconLucideList as iconList } from "@marianmeres/icons-fns/lucide/iconLucideList.js";
42
43
  export { iconLucideMenu as iconMenu } from "@marianmeres/icons-fns/lucide/iconLucideMenu.js";
43
44
  export { iconLucideSearch as iconSearch } from "@marianmeres/icons-fns/lucide/iconLucideSearch.js";
45
+ export { iconLucideSlidersHorizontal as iconSlidersHorizontal } from "@marianmeres/icons-fns/lucide/iconLucideSlidersHorizontal.js";
44
46
  export { iconLucideSettings as iconSettings } from "@marianmeres/icons-fns/lucide/iconLucideSettings.js";
45
47
  export { iconLucideSquare as iconSquare } from "@marianmeres/icons-fns/lucide/iconLucideSquare.js";
46
48
  export { iconLucideUser as iconUser } from "@marianmeres/icons-fns/lucide/iconLucideUser.js";
@@ -44,8 +44,10 @@ export { iconLucideGrip as iconGrip } from "@marianmeres/icons-fns/lucide/iconLu
44
44
  export { iconLucideGripHorizontal as iconGripHorizontal } from "@marianmeres/icons-fns/lucide/iconLucideGripHorizontal.js";
45
45
  export { iconLucideGripVertical as iconGripVertical } from "@marianmeres/icons-fns/lucide/iconLucideGripVertical.js";
46
46
  export { iconLucideLanguages as iconLanguages } from "@marianmeres/icons-fns/lucide/iconLucideLanguages.js";
47
+ export { iconLucideList as iconList } from "@marianmeres/icons-fns/lucide/iconLucideList.js";
47
48
  export { iconLucideMenu as iconMenu } from "@marianmeres/icons-fns/lucide/iconLucideMenu.js";
48
49
  export { iconLucideSearch as iconSearch } from "@marianmeres/icons-fns/lucide/iconLucideSearch.js";
50
+ export { iconLucideSlidersHorizontal as iconSlidersHorizontal } from "@marianmeres/icons-fns/lucide/iconLucideSlidersHorizontal.js";
49
51
  export { iconLucideSettings as iconSettings } from "@marianmeres/icons-fns/lucide/iconLucideSettings.js";
50
52
  export { iconLucideSquare as iconSquare } from "@marianmeres/icons-fns/lucide/iconLucideSquare.js";
51
53
  export { iconLucideUser as iconUser } from "@marianmeres/icons-fns/lucide/iconLucideUser.js";
package/dist/index.css CHANGED
@@ -37,6 +37,7 @@ In practice:
37
37
  @import "./components/LoginForm/index.css";
38
38
  @import "./components/Checkout/index.css";
39
39
  @import "./components/CommandMenu/index.css";
40
+ @import "./components/CronInput/index.css";
40
41
  @import "./components/DataTable/index.css";
41
42
  @import "./components/DismissibleMessage/index.css";
42
43
  @import "./components/DropdownMenu/index.css";
@@ -57,6 +58,7 @@ In practice:
57
58
  @import "./components/Switch/index.css";
58
59
  @import "./components/TabbedMenu/index.css";
59
60
  @import "./components/ThemePreview/index.css";
61
+ @import "./components/Tree/index.css";
60
62
  @import "./components/TwCheck/index.css";
61
63
  @import "./components/WithSidePanel/index.css";
62
64
  @import "./components/X/index.css";
package/dist/index.d.ts CHANGED
@@ -37,6 +37,7 @@ export * from "./components/Checkout/index.js";
37
37
  export * from "./components/Collapsible/index.js";
38
38
  export * from "./components/ColorScheme/index.js";
39
39
  export * from "./components/CommandMenu/index.js";
40
+ export * from "./components/CronInput/index.js";
40
41
  export * from "./components/DataTable/index.js";
41
42
  export * from "./components/DismissibleMessage/index.js";
42
43
  export * from "./components/Drawer/index.js";
@@ -62,6 +63,7 @@ export * from "./components/Switch/index.js";
62
63
  export * from "./components/TabbedMenu/index.js";
63
64
  export * from "./components/Thc/index.js";
64
65
  export * from "./components/ThemePreview/index.js";
66
+ export * from "./components/Tree/index.js";
65
67
  export * from "./components/TwCheck/index.js";
66
68
  export * from "./components/TypeaheadInput/index.js";
67
69
  export * from "./components/WithSidePanel/index.js";
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ export * from "./components/Checkout/index.js";
38
38
  export * from "./components/Collapsible/index.js";
39
39
  export * from "./components/ColorScheme/index.js";
40
40
  export * from "./components/CommandMenu/index.js";
41
+ export * from "./components/CronInput/index.js";
41
42
  export * from "./components/DataTable/index.js";
42
43
  export * from "./components/DismissibleMessage/index.js";
43
44
  export * from "./components/Drawer/index.js";
@@ -63,6 +64,7 @@ export * from "./components/Switch/index.js";
63
64
  export * from "./components/TabbedMenu/index.js";
64
65
  export * from "./components/Thc/index.js";
65
66
  export * from "./components/ThemePreview/index.js";
67
+ export * from "./components/Tree/index.js";
66
68
  export * from "./components/TwCheck/index.js";
67
69
  export * from "./components/TypeaheadInput/index.js";
68
70
  export * from "./components/WithSidePanel/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "3.45.3",
3
+ "version": "3.47.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",
@@ -56,7 +56,7 @@
56
56
  "prettier": "^3.8.1",
57
57
  "prettier-plugin-svelte": "^3.5.1",
58
58
  "publint": "^0.3.18",
59
- "svelte": "^5.53.8",
59
+ "svelte": "^5.53.9",
60
60
  "svelte-check": "^4.4.5",
61
61
  "tailwindcss": "^4.2.1",
62
62
  "tsx": "^4.21.0",
@@ -67,11 +67,13 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@marianmeres/clog": "^3.15.2",
70
+ "@marianmeres/cron": "^1.0.1",
70
71
  "@marianmeres/icons-fns": "^5.0.0",
71
72
  "@marianmeres/item-collection": "^1.3.5",
72
73
  "@marianmeres/paging-store": "^2.0.2",
73
74
  "@marianmeres/parse-boolean": "^2.0.5",
74
75
  "@marianmeres/ticker": "^1.16.5",
76
+ "@marianmeres/tree": "^2.2.5",
75
77
  "esm-env": "^1.2.2",
76
78
  "libphonenumber-js": "^1.12.39",
77
79
  "runed": "^0.23.4",