@adea-ai/ui 0.143.0 → 0.144.1
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/dist/components/composites/accent-picker/accent-picker.d.ts +1 -1
- package/dist/components/composites/accent-picker/accent-picker.d.ts.map +1 -1
- package/dist/components/composites/accent-picker/accent-picker.js +31 -21
- package/dist/components/composites/accent-picker/accent-picker.js.map +1 -1
- package/dist/components/composites/icon-picker/icon-picker.d.ts +16 -1
- package/dist/components/composites/icon-picker/icon-picker.d.ts.map +1 -1
- package/dist/components/composites/icon-picker/icon-picker.js +83 -5
- package/dist/components/composites/icon-picker/icon-picker.js.map +1 -1
- package/dist/components/composites/icon-picker/index.d.ts +1 -1
- package/dist/components/composites/icon-picker/index.d.ts.map +1 -1
- package/dist/components/composites/icon-picker/index.js +2 -2
- package/dist/components/composites/settings/settings-navigation.js +1 -1
- package/dist/components/composites/settings/settings-navigation.js.map +1 -1
- package/dist/components/composites/settings/settings.d.ts +8 -14
- package/dist/components/composites/settings/settings.d.ts.map +1 -1
- package/dist/components/composites/settings/settings.js +88 -37
- package/dist/components/composites/settings/settings.js.map +1 -1
- package/dist/components/composites/tree/tree.d.ts +6 -0
- package/dist/components/composites/tree/tree.d.ts.map +1 -1
- package/dist/components/composites/tree/tree.js +35 -14
- package/dist/components/composites/tree/tree.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/r/accent-picker.json +2 -2
- package/dist/r/icon-picker.json +1 -0
- package/dist/r/registry.json +6 -3
- package/dist/r/settings.json +3 -1
- package/dist/r/src/components/composites/accent-picker/accent-picker.tsx +37 -16
- package/dist/r/src/components/composites/icon-picker/icon-picker.tsx +65 -3
- package/dist/r/src/components/composites/icon-picker/index.ts +6 -1
- package/dist/r/src/components/composites/settings/settings-navigation.tsx +1 -1
- package/dist/r/src/components/composites/settings/settings.tsx +40 -5
- package/dist/r/src/components/composites/tree/tree.tsx +25 -0
- package/package.json +1 -1
- package/registry.json +6 -3
- package/src/components/composites/accent-picker/accent-picker.tsx +37 -16
- package/src/components/composites/icon-picker/icon-picker.tsx +65 -3
- package/src/components/composites/icon-picker/index.ts +6 -1
- package/src/components/composites/settings/settings-navigation.tsx +1 -1
- package/src/components/composites/settings/settings.tsx +40 -5
- package/src/components/composites/tree/tree.tsx +25 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
2
|
import { Heading } from "../../ui/typography/typography.js";
|
|
3
3
|
import { FormFieldContext, createFormFieldContext } from "../../../lib/form-field.js";
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../../ui/tooltip/tooltip.js";
|
|
4
5
|
import { className, createComponent, effect, insert, mergeProps, setAttribute, spread, template } from "solid-js/web";
|
|
6
|
+
import { CircleHelp } from "lucide-solid";
|
|
5
7
|
import { Show, createUniqueId, splitProps } from "solid-js";
|
|
6
8
|
//#region src/components/composites/settings/settings.tsx
|
|
7
9
|
var _tmpl$ = /*#__PURE__*/ template(`<p class="max-w-prose text-sm text-muted-foreground text-pretty">`);
|
|
8
10
|
var _tmpl$2 = /*#__PURE__*/ template(`<div class="flex shrink-0 items-center gap-2">`);
|
|
9
|
-
var _tmpl$3 = /*#__PURE__*/ template(`<section data-slot=settings-section><div class="flex items-start justify-between gap-4"><div class="flex min-w-0 flex-col gap-0.5"></div></div><div data-slot=settings-section-body>`);
|
|
10
|
-
var _tmpl$4 = /*#__PURE__*/ template(`<div data-slot=settings-row><div class="flex min-w-0 flex-col gap-0.5"><div data-slot=settings-row-label class="text-sm font-medium"></div></div><div data-slot=settings-row-control>`);
|
|
11
|
+
var _tmpl$3 = /*#__PURE__*/ template(`<section data-slot=settings-section><div class="flex items-start justify-between gap-4"><div class="flex min-w-0 flex-col gap-0.5"><div class="flex items-center gap-1.5"></div></div></div><div data-slot=settings-section-body>`);
|
|
12
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<div data-slot=settings-row><div class="flex min-w-0 flex-col gap-0.5"><div class="flex items-center gap-1.5"><div data-slot=settings-row-label class="text-sm font-medium"></div></div></div><div data-slot=settings-row-control>`);
|
|
11
13
|
var _tmpl$5 = /*#__PURE__*/ template(`<div data-slot=settings-field><div class="flex flex-col gap-0.5"><label class="text-sm font-medium"></label></div><div>`);
|
|
12
14
|
var _tmpl$6 = /*#__PURE__*/ template(`<div data-slot=settings-page>`);
|
|
13
15
|
/**
|
|
@@ -24,35 +26,70 @@ var _tmpl$6 = /*#__PURE__*/ template(`<div data-slot=settings-page>`);
|
|
|
24
26
|
* the first control inside it. `SettingsField` is the visual stacked layout;
|
|
25
27
|
* use `FormField` when the control needs label, help, or validation wiring.
|
|
26
28
|
*/
|
|
29
|
+
function HelpTip(props) {
|
|
30
|
+
return createComponent(Tooltip, { get children() {
|
|
31
|
+
return [createComponent(TooltipTrigger, {
|
|
32
|
+
as: "button",
|
|
33
|
+
type: "button",
|
|
34
|
+
"data-slot": "settings-row-help",
|
|
35
|
+
get ["aria-label"]() {
|
|
36
|
+
return `About ${props.label}`;
|
|
37
|
+
},
|
|
38
|
+
"class": "inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-none",
|
|
39
|
+
get children() {
|
|
40
|
+
return createComponent(CircleHelp, {
|
|
41
|
+
"class": "size-3.5",
|
|
42
|
+
"aria-hidden": "true"
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}), createComponent(TooltipContent, { get children() {
|
|
46
|
+
return props.help;
|
|
47
|
+
} })];
|
|
48
|
+
} });
|
|
49
|
+
}
|
|
27
50
|
function SettingsSection(props) {
|
|
28
51
|
const [local, rest] = splitProps(props, [
|
|
29
52
|
"class",
|
|
30
53
|
"title",
|
|
31
54
|
"description",
|
|
55
|
+
"help",
|
|
32
56
|
"action",
|
|
33
57
|
"bodyLayout",
|
|
34
58
|
"children"
|
|
35
59
|
]);
|
|
36
60
|
return (() => {
|
|
37
|
-
var _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$
|
|
61
|
+
var _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$3.firstChild, _el$7 = _el$2.nextSibling;
|
|
38
62
|
spread(_el$, mergeProps({ get ["class"]() {
|
|
39
63
|
return cn("flex flex-col gap-4 px-5 py-5", local.class);
|
|
40
64
|
} }, rest), false, true);
|
|
41
|
-
insert(_el$
|
|
65
|
+
insert(_el$4, createComponent(Heading, {
|
|
42
66
|
as: "h2",
|
|
43
67
|
size: "card",
|
|
44
68
|
get children() {
|
|
45
69
|
return local.title;
|
|
46
70
|
}
|
|
47
71
|
}), null);
|
|
72
|
+
insert(_el$4, createComponent(Show, {
|
|
73
|
+
get when() {
|
|
74
|
+
return local.help;
|
|
75
|
+
},
|
|
76
|
+
children: (help) => createComponent(HelpTip, {
|
|
77
|
+
get label() {
|
|
78
|
+
return local.title;
|
|
79
|
+
},
|
|
80
|
+
get help() {
|
|
81
|
+
return help();
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}), null);
|
|
48
85
|
insert(_el$3, createComponent(Show, {
|
|
49
86
|
get when() {
|
|
50
87
|
return local.description;
|
|
51
88
|
},
|
|
52
89
|
get children() {
|
|
53
|
-
var _el$
|
|
54
|
-
insert(_el$
|
|
55
|
-
return _el$
|
|
90
|
+
var _el$5 = _tmpl$();
|
|
91
|
+
insert(_el$5, () => local.description);
|
|
92
|
+
return _el$5;
|
|
56
93
|
}
|
|
57
94
|
}), null);
|
|
58
95
|
insert(_el$2, createComponent(Show, {
|
|
@@ -60,13 +97,13 @@ function SettingsSection(props) {
|
|
|
60
97
|
return local.action;
|
|
61
98
|
},
|
|
62
99
|
get children() {
|
|
63
|
-
var _el$
|
|
64
|
-
insert(_el$
|
|
65
|
-
return _el$
|
|
100
|
+
var _el$6 = _tmpl$2();
|
|
101
|
+
insert(_el$6, () => local.action);
|
|
102
|
+
return _el$6;
|
|
66
103
|
}
|
|
67
104
|
}), null);
|
|
68
|
-
insert(_el$
|
|
69
|
-
effect(() => className(_el$
|
|
105
|
+
insert(_el$7, () => local.children);
|
|
106
|
+
effect(() => className(_el$7, cn(local.bodyLayout === "content" ? "flex flex-col gap-4" : "divide-y divide-border rounded-xl border border-border [&>[data-slot=empty-description]]:p-4")));
|
|
70
107
|
return _el$;
|
|
71
108
|
})();
|
|
72
109
|
}
|
|
@@ -83,6 +120,7 @@ function SettingsRow(props) {
|
|
|
83
120
|
"class",
|
|
84
121
|
"label",
|
|
85
122
|
"description",
|
|
123
|
+
"help",
|
|
86
124
|
"orientation",
|
|
87
125
|
"bare",
|
|
88
126
|
"flush",
|
|
@@ -102,26 +140,39 @@ function SettingsRow(props) {
|
|
|
102
140
|
return createComponent(FormFieldContext.Provider, {
|
|
103
141
|
value: field,
|
|
104
142
|
get children() {
|
|
105
|
-
var _el$
|
|
106
|
-
spread(_el$
|
|
143
|
+
var _el$8 = _tmpl$4(), _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild, _el$1 = _el$0.firstChild, _el$11 = _el$9.nextSibling;
|
|
144
|
+
spread(_el$8, mergeProps({ get ["class"]() {
|
|
107
145
|
return cn("flex gap-4", local.flush ? "p-0" : "p-4", local.orientation === "vertical" ? "flex-col" : "flex-col sm:flex-row sm:items-center sm:justify-between", local.class);
|
|
108
146
|
} }, rest), false, true);
|
|
109
|
-
setAttribute(_el$
|
|
110
|
-
insert(_el$
|
|
111
|
-
insert(_el$
|
|
147
|
+
setAttribute(_el$1, "id", labelId);
|
|
148
|
+
insert(_el$1, () => local.label);
|
|
149
|
+
insert(_el$0, createComponent(Show, {
|
|
150
|
+
get when() {
|
|
151
|
+
return local.help;
|
|
152
|
+
},
|
|
153
|
+
children: (help) => createComponent(HelpTip, {
|
|
154
|
+
get label() {
|
|
155
|
+
return local.label;
|
|
156
|
+
},
|
|
157
|
+
get help() {
|
|
158
|
+
return help();
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
}), null);
|
|
162
|
+
insert(_el$9, createComponent(Show, {
|
|
112
163
|
get when() {
|
|
113
164
|
return local.description;
|
|
114
165
|
},
|
|
115
166
|
get children() {
|
|
116
|
-
var _el$
|
|
117
|
-
setAttribute(_el$
|
|
118
|
-
insert(_el$
|
|
119
|
-
return _el$
|
|
167
|
+
var _el$10 = _tmpl$();
|
|
168
|
+
setAttribute(_el$10, "id", descriptionId);
|
|
169
|
+
insert(_el$10, () => local.description);
|
|
170
|
+
return _el$10;
|
|
120
171
|
}
|
|
121
172
|
}), null);
|
|
122
|
-
insert(_el$
|
|
123
|
-
effect(() => className(_el$
|
|
124
|
-
return _el$
|
|
173
|
+
insert(_el$11, () => local.children);
|
|
174
|
+
effect(() => className(_el$11, cn("shrink-0", local.orientation === "vertical" && "w-full")));
|
|
175
|
+
return _el$8;
|
|
125
176
|
}
|
|
126
177
|
});
|
|
127
178
|
}
|
|
@@ -135,35 +186,35 @@ function SettingsField(props) {
|
|
|
135
186
|
"children"
|
|
136
187
|
]);
|
|
137
188
|
return (() => {
|
|
138
|
-
var _el$
|
|
139
|
-
spread(_el$
|
|
189
|
+
var _el$12 = _tmpl$5(), _el$13 = _el$12.firstChild, _el$14 = _el$13.firstChild, _el$16 = _el$13.nextSibling;
|
|
190
|
+
spread(_el$12, mergeProps({ get ["class"]() {
|
|
140
191
|
return cn("flex flex-col gap-2 p-4", local.class);
|
|
141
192
|
} }, rest), false, true);
|
|
142
|
-
insert(_el$
|
|
143
|
-
insert(_el$
|
|
193
|
+
insert(_el$14, () => local.label);
|
|
194
|
+
insert(_el$13, createComponent(Show, {
|
|
144
195
|
get when() {
|
|
145
196
|
return local.description;
|
|
146
197
|
},
|
|
147
198
|
get children() {
|
|
148
|
-
var _el$
|
|
149
|
-
insert(_el$
|
|
150
|
-
return _el$
|
|
199
|
+
var _el$15 = _tmpl$();
|
|
200
|
+
insert(_el$15, () => local.description);
|
|
201
|
+
return _el$15;
|
|
151
202
|
}
|
|
152
203
|
}), null);
|
|
153
|
-
insert(_el$
|
|
154
|
-
effect(() => setAttribute(_el$
|
|
155
|
-
return _el$
|
|
204
|
+
insert(_el$16, () => local.children);
|
|
205
|
+
effect(() => setAttribute(_el$14, "for", local.htmlFor));
|
|
206
|
+
return _el$12;
|
|
156
207
|
})();
|
|
157
208
|
}
|
|
158
209
|
/** A settings page's scrolling body, with the header sticky at the top. */
|
|
159
210
|
function SettingsPage(props) {
|
|
160
211
|
const [local, rest] = splitProps(props, ["class"]);
|
|
161
212
|
return (() => {
|
|
162
|
-
var _el$
|
|
163
|
-
spread(_el$
|
|
213
|
+
var _el$17 = _tmpl$6();
|
|
214
|
+
spread(_el$17, mergeProps({ get ["class"]() {
|
|
164
215
|
return cn("flex min-h-0 flex-1 flex-col overflow-y-auto", local.class);
|
|
165
216
|
} }, rest), false, false);
|
|
166
|
-
return _el$
|
|
217
|
+
return _el$17;
|
|
167
218
|
})();
|
|
168
219
|
}
|
|
169
220
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings.js","names":["ComponentProps","JSX","createUniqueId","Show","splitProps","createFormFieldContext","FormFieldContext","cn","Heading","SettingsSection","props","title","description","action","Element","bodyLayout","local","rest","_el$","_tmpl$3","_el$2","firstChild","_el$3","_el$6","nextSibling","_$spread","_$mergeProps","class","_$insert","_$createComponent","as","size","children","when","_el$4","_tmpl$","_el$5","_tmpl$2","_$effect","_$className","SettingsRow","label","orientation","bare","flush","rowId","labelId","descriptionId","field","defaultControlId","hint","error","undefined","group","Provider","value","_el$7","_tmpl$4","_el$8","_el$9","_el$1","_$setAttribute","_el$0","SettingsField","htmlFor","_el$10","_tmpl$5","_el$11","_el$12","_el$14","_el$13","SettingsPage","_el$15","_tmpl$6","_$mergeProps","_$createComponent","_$className","_$setAttribute"],"sources":["../../../../src/components/composites/settings/settings.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { createUniqueId, Show, splitProps } from 'solid-js'\nimport { createFormFieldContext, FormFieldContext } from '#lib/form-field'\nimport { cn } from '#lib/utils'\nimport { Heading } from '../../ui/typography'\n\n/**\n * SettingsSection and SettingsRow.\n *\n * A settings page is the most repetitive surface in any application, and the\n * one where drift is most visible: label sizes, control widths and description\n * placement all wander unless something fixes them.\n *\n * The row puts the label and description at the start and the control at the\n * end (stacked on a narrow window), so controls line up down the page's end\n * edge regardless of how long the labels are. `SettingsRow` also\n * exposes its label and description through the shared form-field context to\n * the first control inside it. `SettingsField` is the visual stacked layout;\n * use `FormField` when the control needs label, help, or validation wiring.\n */\nexport function SettingsSection(\n props: ComponentProps<'section'> & {\n title: string\n description?: string\n /** A control for the section as a whole, e.g. a master toggle. */\n action?: JSX.Element\n /** Use a spaced content stack for fields, alerts, and cards instead of divided rows. */\n bodyLayout?: 'rows' | 'content'\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'title',\n 'description',\n 'action',\n 'bodyLayout',\n 'children',\n ])\n\n return (\n <section\n data-slot=\"settings-section\"\n class={cn('flex flex-col gap-4 px-5 py-5', local.class)}\n {...rest}\n >\n <div class=\"flex items-start justify-between gap-4\">\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <Heading as=\"h2\" size=\"card\">\n {local.title}\n </Heading>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <Show when={local.action}>\n <div class=\"flex shrink-0 items-center gap-2\">{local.action}</div>\n </Show>\n </div>\n <div\n data-slot=\"settings-section-body\"\n class={cn(\n local.bodyLayout === 'content'\n ? 'flex flex-col gap-4'\n : 'divide-y divide-border rounded-xl border border-border [&>[data-slot=empty-description]]:p-4'\n )}\n >\n {local.children}\n </div>\n </section>\n )\n}\n\n/**\n * One setting: a label and description on the leading side, a control on the\n * trailing side.\n *\n * The label and description are linked to a shared control through field\n * context. An explicit `aria-label` or `aria-labelledby` on the control keeps\n * precedence; otherwise the visible row label names it.\n */\nexport function SettingsRow(\n props: ComponentProps<'div'> & {\n label: string\n description?: string\n /** Render a vertical stack when the control needs the full width. */\n orientation?: 'horizontal' | 'vertical'\n /** Hide the divider this row would otherwise contribute. */\n bare?: boolean\n /**\n * Drop the row's own 16px padding so its label and control sit on the same\n * edges as the fields around it. For a row placed loose in a\n * `bodyLayout=\"content\"` section, where nothing encloses it and the section's\n * gap already spaces it from its neighbours. Leave it off inside a divided\n * rows body or a `Card`, whose edge the padding is there to clear.\n */\n flush?: boolean\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'label',\n 'description',\n 'orientation',\n 'bare',\n 'flush',\n 'children',\n ])\n const rowId = createUniqueId()\n const labelId = `${rowId}-label`\n const descriptionId = `${rowId}-description`\n const field = createFormFieldContext({\n defaultControlId: rowId,\n labelId,\n descriptionId,\n hint: () => local.description,\n error: () => undefined,\n group: () => false,\n })\n\n return (\n <FormFieldContext.Provider value={field}>\n <div\n data-slot=\"settings-row\"\n class={cn(\n 'flex gap-4',\n local.flush ? 'p-0' : 'p-4',\n local.orientation === 'vertical'\n ? 'flex-col'\n : 'flex-col sm:flex-row sm:items-center sm:justify-between',\n local.class\n )}\n {...rest}\n >\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <div id={labelId} data-slot=\"settings-row-label\" class=\"text-sm font-medium\">\n {local.label}\n </div>\n <Show when={local.description}>\n <p id={descriptionId} class=\"max-w-prose text-sm text-muted-foreground text-pretty\">\n {local.description}\n </p>\n </Show>\n </div>\n <div\n data-slot=\"settings-row-control\"\n class={cn('shrink-0', local.orientation === 'vertical' && 'w-full')}\n >\n {local.children}\n </div>\n </div>\n </FormFieldContext.Provider>\n )\n}\n\n/** A stacked label-and-control pair, for a control too wide for a row. */\nexport function SettingsField(\n props: ComponentProps<'div'> & { label: string; description?: string; htmlFor?: string }\n) {\n const [local, rest] = splitProps(props, ['class', 'label', 'description', 'htmlFor', 'children'])\n\n return (\n <div data-slot=\"settings-field\" class={cn('flex flex-col gap-2 p-4', local.class)} {...rest}>\n <div class=\"flex flex-col gap-0.5\">\n <label for={local.htmlFor} class=\"text-sm font-medium\">\n {local.label}\n </label>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <div>{local.children}</div>\n </div>\n )\n}\n\n/** A settings page's scrolling body, with the header sticky at the top. */\nexport function SettingsPage(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"settings-page\"\n class={cn('flex min-h-0 flex-1 flex-col overflow-y-auto', local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"settings.js","names":["CircleHelp","ComponentProps","JSX","createUniqueId","Show","splitProps","createFormFieldContext","FormFieldContext","cn","Tooltip","TooltipContent","TooltipTrigger","Heading","HelpTip","props","label","help","_$createComponent","children","as","type","aria-label","SettingsSection","title","description","action","Element","bodyLayout","local","rest","_el$","_tmpl$3","_el$2","firstChild","_el$3","_el$4","_el$7","nextSibling","_$spread","_$mergeProps","class","_$insert","size","when","_el$5","_tmpl$","_el$6","_tmpl$2","_$effect","_$className","SettingsRow","orientation","bare","flush","rowId","labelId","descriptionId","field","defaultControlId","hint","error","undefined","group","Provider","value","_el$8","_tmpl$4","_el$9","_el$0","_el$1","_el$11","_$setAttribute","_el$10","SettingsField","htmlFor","_el$12","_tmpl$5","_el$13","_el$14","_el$16","_el$15","SettingsPage","_el$17","_tmpl$6","_$createComponent","_$mergeProps","_$className","_$setAttribute"],"sources":["../../../../src/components/composites/settings/settings.tsx"],"sourcesContent":["import { CircleHelp } from 'lucide-solid'\nimport type { ComponentProps, JSX } from 'solid-js'\nimport { createUniqueId, Show, splitProps } from 'solid-js'\nimport { createFormFieldContext, FormFieldContext } from '#lib/form-field'\nimport { cn } from '#lib/utils'\nimport { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip'\nimport { Heading } from '../../ui/typography'\n\n/**\n * SettingsSection and SettingsRow.\n *\n * A settings page is the most repetitive surface in any application, and the\n * one where drift is most visible: label sizes, control widths and description\n * placement all wander unless something fixes them.\n *\n * The row puts the label and description at the start and the control at the\n * end (stacked on a narrow window), so controls line up down the page's end\n * edge regardless of how long the labels are. `SettingsRow` also\n * exposes its label and description through the shared form-field context to\n * the first control inside it. `SettingsField` is the visual stacked layout;\n * use `FormField` when the control needs label, help, or validation wiring.\n */\nfunction HelpTip(props: { label: string; help: string }) {\n return (\n <Tooltip>\n <TooltipTrigger\n as=\"button\"\n type=\"button\"\n data-slot=\"settings-row-help\"\n aria-label={`About ${props.label}`}\n class=\"inline-flex size-4 items-center justify-center rounded-full text-muted-foreground hover:text-foreground focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-none\"\n >\n <CircleHelp class=\"size-3.5\" aria-hidden=\"true\" />\n </TooltipTrigger>\n <TooltipContent>{props.help}</TooltipContent>\n </Tooltip>\n )\n}\n\nexport function SettingsSection(\n props: ComponentProps<'section'> & {\n title: string\n description?: string\n /** A short explanation behind a help icon beside the title; prefer it to a long description. */\n help?: string\n /** A control for the section as a whole, e.g. a master toggle. */\n action?: JSX.Element\n /** Use a spaced content stack for fields, alerts, and cards instead of divided rows. */\n bodyLayout?: 'rows' | 'content'\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'title',\n 'description',\n 'help',\n 'action',\n 'bodyLayout',\n 'children',\n ])\n\n return (\n <section\n data-slot=\"settings-section\"\n class={cn('flex flex-col gap-4 px-5 py-5', local.class)}\n {...rest}\n >\n <div class=\"flex items-start justify-between gap-4\">\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <div class=\"flex items-center gap-1.5\">\n <Heading as=\"h2\" size=\"card\">\n {local.title}\n </Heading>\n <Show when={local.help}>{(help) => <HelpTip label={local.title} help={help()} />}</Show>\n </div>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <Show when={local.action}>\n <div class=\"flex shrink-0 items-center gap-2\">{local.action}</div>\n </Show>\n </div>\n <div\n data-slot=\"settings-section-body\"\n class={cn(\n local.bodyLayout === 'content'\n ? 'flex flex-col gap-4'\n : 'divide-y divide-border rounded-xl border border-border [&>[data-slot=empty-description]]:p-4'\n )}\n >\n {local.children}\n </div>\n </section>\n )\n}\n\n/**\n * One setting: a label and description on the leading side, a control on the\n * trailing side.\n *\n * The label and description are linked to a shared control through field\n * context. An explicit `aria-label` or `aria-labelledby` on the control keeps\n * precedence; otherwise the visible row label names it.\n */\nexport function SettingsRow(\n props: ComponentProps<'div'> & {\n label: string\n description?: string\n /**\n * A short explanation behind a help icon beside the label. Prefer it to a\n * long description: the row stays quiet and the explanation is one hover or\n * focus away.\n */\n help?: string\n /** Render a vertical stack when the control needs the full width. */\n orientation?: 'horizontal' | 'vertical'\n /** Hide the divider this row would otherwise contribute. */\n bare?: boolean\n /**\n * Drop the row's own 16px padding so its label and control sit on the same\n * edges as the fields around it. For a row placed loose in a\n * `bodyLayout=\"content\"` section, where nothing encloses it and the section's\n * gap already spaces it from its neighbours. Leave it off inside a divided\n * rows body or a `Card`, whose edge the padding is there to clear.\n */\n flush?: boolean\n }\n) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'label',\n 'description',\n 'help',\n 'orientation',\n 'bare',\n 'flush',\n 'children',\n ])\n const rowId = createUniqueId()\n const labelId = `${rowId}-label`\n const descriptionId = `${rowId}-description`\n const field = createFormFieldContext({\n defaultControlId: rowId,\n labelId,\n descriptionId,\n hint: () => local.description,\n error: () => undefined,\n group: () => false,\n })\n\n return (\n <FormFieldContext.Provider value={field}>\n <div\n data-slot=\"settings-row\"\n class={cn(\n 'flex gap-4',\n local.flush ? 'p-0' : 'p-4',\n local.orientation === 'vertical'\n ? 'flex-col'\n : 'flex-col sm:flex-row sm:items-center sm:justify-between',\n local.class\n )}\n {...rest}\n >\n <div class=\"flex min-w-0 flex-col gap-0.5\">\n <div class=\"flex items-center gap-1.5\">\n <div id={labelId} data-slot=\"settings-row-label\" class=\"text-sm font-medium\">\n {local.label}\n </div>\n <Show when={local.help}>{(help) => <HelpTip label={local.label} help={help()} />}</Show>\n </div>\n <Show when={local.description}>\n <p id={descriptionId} class=\"max-w-prose text-sm text-muted-foreground text-pretty\">\n {local.description}\n </p>\n </Show>\n </div>\n <div\n data-slot=\"settings-row-control\"\n class={cn('shrink-0', local.orientation === 'vertical' && 'w-full')}\n >\n {local.children}\n </div>\n </div>\n </FormFieldContext.Provider>\n )\n}\n\n/** A stacked label-and-control pair, for a control too wide for a row. */\nexport function SettingsField(\n props: ComponentProps<'div'> & { label: string; description?: string; htmlFor?: string }\n) {\n const [local, rest] = splitProps(props, ['class', 'label', 'description', 'htmlFor', 'children'])\n\n return (\n <div data-slot=\"settings-field\" class={cn('flex flex-col gap-2 p-4', local.class)} {...rest}>\n <div class=\"flex flex-col gap-0.5\">\n <label for={local.htmlFor} class=\"text-sm font-medium\">\n {local.label}\n </label>\n <Show when={local.description}>\n <p class=\"max-w-prose text-sm text-muted-foreground text-pretty\">{local.description}</p>\n </Show>\n </div>\n <div>{local.children}</div>\n </div>\n )\n}\n\n/** A settings page's scrolling body, with the header sticky at the top. */\nexport function SettingsPage(props: ComponentProps<'div'>) {\n const [local, rest] = splitProps(props, ['class'])\n return (\n <div\n data-slot=\"settings-page\"\n class={cn('flex min-h-0 flex-1 flex-col overflow-y-auto', local.class)}\n {...rest}\n />\n )\n}\n"],"mappings":"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"}
|
|
@@ -37,6 +37,12 @@ export type TreeProps = Omit<ComponentProps<'div'>, 'children' | 'role' | 'tabIn
|
|
|
37
37
|
* Keyboard behaviour is identical in both modes: Left/Right expand and collapse.
|
|
38
38
|
*/
|
|
39
39
|
disclosure?: TreeDisclosure;
|
|
40
|
+
/**
|
|
41
|
+
* Draw a vertical guide line down each ancestor level of a nested row, so a
|
|
42
|
+
* group of children reads as belonging to its parent. Off by default: a flat
|
|
43
|
+
* list or a dense file explorer carries its own rhythm.
|
|
44
|
+
*/
|
|
45
|
+
guides?: boolean;
|
|
40
46
|
/** Called for Enter or pointer activation. Domain action stays host-owned. */
|
|
41
47
|
onActivate?: (id: string, event: Event) => void;
|
|
42
48
|
/** Called for Space selection. Selection state stays host-owned. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/tree/tree.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/components/composites/tree/tree.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { cn } from "../../../lib/utils.js";
|
|
2
2
|
import { indexTreeItems, treeNavigationAction } from "./tree-navigation.js";
|
|
3
|
-
import { addEventListener, className, createComponent, delegateEvents, effect, insert, memo, mergeProps, setAttribute, spread, template, use } from "solid-js/web";
|
|
3
|
+
import { addEventListener, className, createComponent, delegateEvents, effect, insert, memo, mergeProps, setAttribute, setStyleProperty, spread, template, use } from "solid-js/web";
|
|
4
4
|
import { ChevronRight } from "lucide-solid";
|
|
5
|
-
import { createContext, createEffect, createMemo, createUniqueId, onCleanup, splitProps, useContext } from "solid-js";
|
|
5
|
+
import { For, Show, createContext, createEffect, createMemo, createUniqueId, onCleanup, splitProps, useContext } from "solid-js";
|
|
6
6
|
//#region src/components/composites/tree/tree.tsx
|
|
7
7
|
var _tmpl$ = /*#__PURE__*/ template(`<div>`);
|
|
8
8
|
var _tmpl$2 = /*#__PURE__*/ template(`<div><span></span><span class="min-w-0 flex-1 truncate">`);
|
|
9
|
-
var _tmpl$3 = /*#__PURE__*/ template(`<span class="
|
|
10
|
-
var _tmpl$4 = /*#__PURE__*/ template(`<span class="
|
|
11
|
-
var _tmpl$5 = /*#__PURE__*/ template(`<span
|
|
9
|
+
var _tmpl$3 = /*#__PURE__*/ template(`<span aria-hidden=true data-slot=tree-row-guide class="pointer-events-none absolute inset-y-0 w-px bg-border">`);
|
|
10
|
+
var _tmpl$4 = /*#__PURE__*/ template(`<span class="flex size-4 shrink-0 items-center justify-center [&_svg]:size-4">`);
|
|
11
|
+
var _tmpl$5 = /*#__PURE__*/ template(`<span class="ms-auto flex shrink-0 items-center gap-1 text-muted-foreground">`);
|
|
12
|
+
var _tmpl$6 = /*#__PURE__*/ template(`<span data-slot=tree-row-actions>`);
|
|
12
13
|
var TreeContext = createContext();
|
|
13
14
|
function useTreeContext() {
|
|
14
15
|
const tree = useContext(TreeContext);
|
|
@@ -55,6 +56,7 @@ function Tree(props) {
|
|
|
55
56
|
"onActiveIdChange",
|
|
56
57
|
"onExpand",
|
|
57
58
|
"disclosure",
|
|
59
|
+
"guides",
|
|
58
60
|
"onActivate",
|
|
59
61
|
"onSelectItem",
|
|
60
62
|
"onRequestReveal",
|
|
@@ -180,6 +182,7 @@ function Tree(props) {
|
|
|
180
182
|
activate: (id, event) => local.onActivate?.(id, event),
|
|
181
183
|
expand: (id, expanded) => local.onExpand?.(id, expanded),
|
|
182
184
|
disclosure: () => local.disclosure ?? "row",
|
|
185
|
+
guides: () => local.guides ?? false,
|
|
183
186
|
onActiveIdChange: local.onActiveIdChange
|
|
184
187
|
};
|
|
185
188
|
createEffect(() => {
|
|
@@ -341,6 +344,7 @@ function TreeRow(props) {
|
|
|
341
344
|
},
|
|
342
345
|
get ["class"]() {
|
|
343
346
|
return cn("group/tree-row flex min-h-row-sm w-full min-w-0 items-center gap-1.5 rounded-md pe-1.5 text-left text-sm outline-none transition-colors", "focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle", {
|
|
347
|
+
relative: tree.guides(),
|
|
344
348
|
"bg-primary-subtle text-foreground": local.selected,
|
|
345
349
|
"hover:bg-surface-hover": !local.selected
|
|
346
350
|
}, local.class);
|
|
@@ -352,6 +356,23 @@ function TreeRow(props) {
|
|
|
352
356
|
"onClick": handleClick,
|
|
353
357
|
"onDblClick": handleDoubleClick
|
|
354
358
|
}), false, true);
|
|
359
|
+
insert(_el$2, createComponent(Show, {
|
|
360
|
+
get when() {
|
|
361
|
+
return memo(() => !!tree.guides())() && local.item.level > 1;
|
|
362
|
+
},
|
|
363
|
+
get children() {
|
|
364
|
+
return createComponent(For, {
|
|
365
|
+
get each() {
|
|
366
|
+
return Array.from({ length: local.item.level - 1 }, (_, index) => index);
|
|
367
|
+
},
|
|
368
|
+
children: (index) => (() => {
|
|
369
|
+
var _el$5 = _tmpl$3();
|
|
370
|
+
setStyleProperty(_el$5, "inset-inline-start", `${6 + index * 12 + 7}px`);
|
|
371
|
+
return _el$5;
|
|
372
|
+
})()
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}), _el$3);
|
|
355
376
|
addEventListener(_el$3, "dblclick", markerTarget() ? handleMarkerDoubleClick : void 0, true);
|
|
356
377
|
addEventListener(_el$3, "click", markerTarget() ? handleMarkerClick : void 0, true);
|
|
357
378
|
addEventListener(_el$3, "mousedown", markerTarget() ? handleMarkerMouseDown : void 0, true);
|
|
@@ -367,18 +388,18 @@ function TreeRow(props) {
|
|
|
367
388
|
insert(_el$2, (() => {
|
|
368
389
|
var _c$2 = memo(() => !!local.leading);
|
|
369
390
|
return () => _c$2() ? (() => {
|
|
370
|
-
var _el$
|
|
371
|
-
insert(_el$
|
|
372
|
-
return _el$
|
|
391
|
+
var _el$6 = _tmpl$4();
|
|
392
|
+
insert(_el$6, () => local.leading);
|
|
393
|
+
return _el$6;
|
|
373
394
|
})() : null;
|
|
374
395
|
})(), _el$4);
|
|
375
396
|
insert(_el$4, () => local.children);
|
|
376
397
|
insert(_el$2, (() => {
|
|
377
398
|
var _c$3 = memo(() => !!local.trailing);
|
|
378
399
|
return () => _c$3() ? (() => {
|
|
379
|
-
var _el$
|
|
380
|
-
insert(_el$
|
|
381
|
-
return _el$
|
|
400
|
+
var _el$7 = _tmpl$5();
|
|
401
|
+
insert(_el$7, () => local.trailing);
|
|
402
|
+
return _el$7;
|
|
382
403
|
})() : null;
|
|
383
404
|
})(), null);
|
|
384
405
|
effect((_p$) => {
|
|
@@ -405,8 +426,8 @@ function TreeRow(props) {
|
|
|
405
426
|
function TreeRowActions(props) {
|
|
406
427
|
const [local, rest] = splitProps(props, ["class", "pinned"]);
|
|
407
428
|
return (() => {
|
|
408
|
-
var _el$
|
|
409
|
-
spread(_el$
|
|
429
|
+
var _el$8 = _tmpl$6();
|
|
430
|
+
spread(_el$8, mergeProps({
|
|
410
431
|
get ["data-pinned"]() {
|
|
411
432
|
return local.pinned ? "" : void 0;
|
|
412
433
|
},
|
|
@@ -414,7 +435,7 @@ function TreeRowActions(props) {
|
|
|
414
435
|
return cn("flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out", "group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100", local.class);
|
|
415
436
|
}
|
|
416
437
|
}, rest), false, false);
|
|
417
|
-
return _el$
|
|
438
|
+
return _el$8;
|
|
418
439
|
})();
|
|
419
440
|
}
|
|
420
441
|
var handleMarkerMouseDown = (event) => event.preventDefault();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","names":["ComponentProps","JSX","ChevronRight","createContext","createEffect","createMemo","createUniqueId","onCleanup","splitProps","useContext","cn","indexTreeItems","treeNavigationAction","TreeItemDescriptor","TreeNavigationIndex","TreeContextValue","idPrefix","activeId","index","register","id","element","HTMLDivElement","unregister","focusItem","noteFocus","noteBlur","next","EventTarget","activate","event","Event","expand","expanded","disclosure","TreeDisclosure","onActiveIdChange","TreeContext","useTreeContext","tree","Error","TreeAccessibleName","TreeProps","Omit","visibleItems","onExpand","onActivate","onSelectItem","onRequestReveal","onRowSizeChange","blockSize","selectionMode","children","Element","Tree","props","local","rest","effectiveActiveId","candidate","visible","byId","has","ids","rows","Map","rowIdsByElement","WeakMap","pendingFocusId","pendingFocusGuard","FocusEvent","requestedRevealId","focusedId","disposed","isInsideTreeRow","row","closest","focusIsOutsideTree","document","active","activeElement","body","documentElement","rowSizeObserver","ResizeObserver","undefined","entries","entry","get","target","borderBoxSize","HTMLElement","offsetHeight","Number","isFinite","setPendingFocus","removeEventListener","cancelPendingFocus","addEventListener","disconnect","requestReveal","focusWhenMounted","queueMicrotask","focus","context","set","observe","focusWasInside","Boolean","contains","delete","unobserve","fallbackId","handleKeyDown","EventHandler","KeyboardEvent","defaultPrevented","isActionTarget","currentTarget","action","key","preventDefault","type","_$createComponent","Provider","value","_el$","_tmpl$","_$spread","_$mergeProps","aria-multiselectable","class","_$insert","TreeRowProps","item","selected","leading","trailing","onDoubleClick","MouseEvent","TreeRow","registeredId","handleFocusOut","relatedTarget","setRef","nextId","handleFocus","handleClick","handleDoubleClick","position","positionById","markerTarget","expandable","handleMarkerClick","HTMLSpanElement","stopPropagation","_el$2","_tmpl$2","_el$3","firstChild","_el$4","nextSibling","_ref$","composeRefs","ref","_$use","encodeURIComponent","aria-level","level","aria-expanded","_$memo","aria-selected","aria-posinset","aria-setsize","setSize","tabIndex","data-tree-id","data-active","data-selected","data-expanded","String","style","Math","max","_$addEventListener","handleMarkerDoubleClick","handleMarkerMouseDown","_c$","_c$2","_el$5","_tmpl$3","_c$3","_el$6","_tmpl$4","_$effect","_p$","_v$","_v$2","e","_$setAttribute","t","_$className","TreeRowActions","pinned","_el$7","_tmpl$5","data-pinned","internal","external","_$delegateEvents","_$createComponent","_$mergeProps","_$use","_$memo","_$setAttribute","_$className","_$delegateEvents"],"sources":["../../../../src/components/composites/tree/tree.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { ChevronRight } from 'lucide-solid'\nimport {\n createContext,\n createEffect,\n createMemo,\n createUniqueId,\n onCleanup,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n indexTreeItems,\n treeNavigationAction,\n type TreeItemDescriptor,\n type TreeNavigationIndex,\n} from './tree-navigation'\n\ntype TreeContextValue = {\n idPrefix: string\n activeId: () => string | null\n index: () => TreeNavigationIndex\n register: (id: string, element: HTMLDivElement) => void\n unregister: (id: string, element: HTMLDivElement | undefined) => void\n focusItem: (id: string) => void\n noteFocus: (id: string) => void\n noteBlur: (next: EventTarget | null) => void\n activate: (id: string, event: Event) => void\n expand: (id: string, expanded: boolean) => void\n disclosure: () => TreeDisclosure\n onActiveIdChange: (id: string) => void\n}\n\nconst TreeContext = createContext<TreeContextValue>()\n\nfunction useTreeContext() {\n const tree = useContext(TreeContext)\n if (!tree) throw new Error('[adea-ui]: TreeRow must be used inside Tree.')\n return tree\n}\n\n/**\n * Who owns the pointer on a row's disclosure chevron.\n *\n * - `row` (default): the chevron is decoration; a click anywhere on the row,\n * chevron included, is a row activation. This is the file-explorer\n * convention, where the host's `onActivate` toggles a folder.\n * - `marker`: the chevron of an expandable row is its own pointer target. It\n * calls `onExpand(id, !expanded)` and nothing else; the rest of the row still\n * activates. For trees where expanding and selecting are independent (a\n * source list that selects a source and separately reveals its details).\n */\nexport type TreeDisclosure = 'row' | 'marker'\n\ntype TreeAccessibleName =\n | { 'aria-label': string; 'aria-labelledby'?: string }\n | { 'aria-label'?: string; 'aria-labelledby': string }\n\nexport type TreeProps = Omit<\n ComponentProps<'div'>,\n 'children' | 'role' | 'tabIndex' | 'onKeyDown' | 'aria-label' | 'aria-labelledby'\n> &\n TreeAccessibleName & {\n /** Complete, ordered projection of currently visible (expanded) items. */\n visibleItems: readonly TreeItemDescriptor[]\n /** The host-owned identity of the row that currently owns roving focus. */\n activeId: string | null\n /**\n * Called when keyboard or pointer navigation changes the active row, and when\n * the active row leaves `visibleItems` (collapsed away, filtered out) and the\n * first visible row takes over as the roving stop.\n */\n onActiveIdChange: (id: string) => void\n /** Called for Left/Right expand and collapse requests. */\n onExpand?: (id: string, expanded: boolean) => void\n /**\n * Opt-in pointer behaviour of the disclosure chevron; see {@link TreeDisclosure}.\n * Keyboard behaviour is identical in both modes: Left/Right expand and collapse.\n */\n disclosure?: TreeDisclosure\n /** Called for Enter or pointer activation. Domain action stays host-owned. */\n onActivate?: (id: string, event: Event) => void\n /** Called for Space selection. Selection state stays host-owned. */\n onSelectItem?: (id: string, event: Event) => void\n /** Ask the host window to mount/reveal an item before focus moves to it. */\n onRequestReveal?: (id: string) => void\n /** Report a mounted row's border-box block size in CSS pixels for host range math. */\n onRowSizeChange?: (id: string, blockSize: number) => void\n /** Declares a multi-select tree to assistive technology. */\n selectionMode?: 'single' | 'multiple'\n children?: JSX.Element\n }\n\n/**\n * Tree.\n *\n * Supplies semantic and keyboard behavior for a tree whose host owns the\n * visible projection, filesystem state, row window and domain actions. The\n * mounted children can be a small virtualized window; `visibleItems` remains\n * the complete ordered projection so keyboard movement and sibling positions\n * do not depend on which rows currently exist in the DOM.\n *\n * Kobalte 0.13.14 has no Tree primitive, so this component implements the\n * WAI-ARIA tree row navigation contract and leaves product state to callbacks.\n *\n * By default the disclosure chevron is decoration and a click anywhere on a\n * row activates it, so a file explorer can toggle a folder from `onActivate`.\n * Reach for `disclosure=\"marker\"` when expanding and selecting are separate\n * decisions: the chevron then calls only `onExpand`, and the rest of the row\n * calls only `onActivate`. The chevron stays `aria-hidden` and out of the tab\n * order in both modes; keyboard expansion is Left/Right either way.\n *\n * Collapsing is the one thing that can move focus without a key or a click on\n * the target row: when the active row leaves `visibleItems`, the first visible\n * row becomes the roving stop and `onActiveIdChange` is called with it. If the\n * removed row held focus, or was the last row the tree saw focused, focus moves\n * to that same row; if it had no focus, only the roving stop moves. Focus that\n * has already gone to a control outside the tree is never pulled back: the tree\n * forgets its last focused row when focus moves to an element outside it, and\n * the roving stop alone moves if that control still has focus when the row is\n * hidden. Focus the tree has asked for but not yet moved (a queued recovery, or a\n * keyboard move to a row the host has not mounted) is withdrawn when focus lands\n * outside the tree, and is checked again when a row mounts. This is the same in\n * both `disclosure` modes and for every way a host collapses a row.\n */\nexport function Tree(props: TreeProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'visibleItems',\n 'activeId',\n 'onActiveIdChange',\n 'onExpand',\n 'disclosure',\n 'onActivate',\n 'onSelectItem',\n 'onRequestReveal',\n 'onRowSizeChange',\n 'selectionMode',\n 'children',\n ])\n\n const index = createMemo(() => indexTreeItems(local.visibleItems))\n const effectiveActiveId = createMemo(() => {\n const candidate = local.activeId\n const visible = index()\n return candidate !== null && visible.byId.has(candidate) ? candidate : (visible.ids[0] ?? null)\n })\n const idPrefix = `tree-${createUniqueId()}`\n const rows = new Map<string, HTMLDivElement>()\n const rowIdsByElement = new WeakMap<HTMLDivElement, string>()\n let pendingFocusId: string | null = null\n let pendingFocusGuard: ((event: FocusEvent) => void) | undefined\n let requestedRevealId: string | null = null\n let focusedId: string | null = null\n let disposed = false\n const isInsideTreeRow = (element: Element) => {\n const row = element.closest('[role=\"treeitem\"]')\n return row instanceof HTMLDivElement && rowIdsByElement.has(row)\n }\n // True when a focusable control outside this tree owns focus. Nothing focused\n // (`body`) is not outside: that is where focus falls when a focused row is removed.\n const focusIsOutsideTree = () => {\n if (typeof document === 'undefined') return false\n const active = document.activeElement\n return (\n active instanceof Element &&\n active !== document.body &&\n active !== document.documentElement &&\n !isInsideTreeRow(active)\n )\n }\n const rowSizeObserver =\n typeof ResizeObserver === 'undefined'\n ? undefined\n : new ResizeObserver((entries) => {\n if (disposed) return\n for (const entry of entries) {\n const id = rowIdsByElement.get(entry.target as HTMLDivElement)\n const blockSize =\n entry.borderBoxSize[0]?.blockSize ?? (entry.target as HTMLElement).offsetHeight\n if (id !== undefined && Number.isFinite(blockSize) && blockSize > 0)\n local.onRowSizeChange?.(id, blockSize)\n }\n })\n\n // Focus the tree has asked for but not yet moved (a microtask away, or waiting for a\n // virtualised row to mount) is only a request. While one is pending, focus arriving\n // on a control outside the tree withdraws it, so a row mounting later cannot take\n // focus back from a control the user, or the host, has since chosen.\n const setPendingFocus = (id: string | null) => {\n pendingFocusId = id\n if (typeof document === 'undefined') return\n if (id === null) {\n if (pendingFocusGuard) document.removeEventListener('focusin', pendingFocusGuard, true)\n pendingFocusGuard = undefined\n } else if (!pendingFocusGuard) {\n pendingFocusGuard = (event) => {\n if (event.target instanceof Element && !isInsideTreeRow(event.target)) cancelPendingFocus()\n }\n document.addEventListener('focusin', pendingFocusGuard, true)\n }\n }\n // Withdrawing a request also drops the memory of the row it was recovering for:\n // nothing is left to recover.\n const cancelPendingFocus = () => {\n setPendingFocus(null)\n focusedId = null\n }\n\n onCleanup(() => {\n disposed = true\n setPendingFocus(null)\n rowSizeObserver?.disconnect()\n })\n\n const requestReveal = (id: string) => {\n if (requestedRevealId === id) return\n requestedRevealId = id\n local.onRequestReveal?.(id)\n }\n\n const focusWhenMounted = (id: string) => {\n queueMicrotask(() => {\n if (pendingFocusId !== id || effectiveActiveId() !== id) return\n const row = rows.get(id)\n if (!row || typeof document === 'undefined') return\n // Ownership is checked when focus would move, not when it was requested: a\n // control outside the tree may have taken focus since, and keeps it.\n if (focusIsOutsideTree()) {\n cancelPendingFocus()\n return\n }\n row.focus()\n if (document.activeElement === row) setPendingFocus(null)\n })\n }\n\n const focusItem = (id: string) => {\n setPendingFocus(id)\n local.onActiveIdChange(id)\n if (rows.has(id)) requestedRevealId = null\n else requestReveal(id)\n focusWhenMounted(id)\n }\n\n const context: TreeContextValue = {\n idPrefix,\n activeId: effectiveActiveId,\n index,\n register: (id, element) => {\n rows.set(id, element)\n rowIdsByElement.set(element, id)\n rowSizeObserver?.observe(element)\n if (requestedRevealId === id) requestedRevealId = null\n if (pendingFocusId === id) focusWhenMounted(id)\n },\n unregister: (id, element) => {\n if (rows.get(id) !== element) return\n const focusWasInside =\n !disposed &&\n Boolean(\n element && typeof document !== 'undefined' && element.contains(document.activeElement)\n )\n rows.delete(id)\n if (element) {\n rowIdsByElement.delete(element)\n rowSizeObserver?.unobserve(element)\n }\n if (requestedRevealId === id) requestedRevealId = null\n if (focusWasInside) {\n queueMicrotask(() => {\n const fallbackId = effectiveActiveId()\n if (disposed || fallbackId === null || pendingFocusId === fallbackId) return\n // Focus fell out of the removed row, but it may have been given to a control\n // outside the tree before this ran. Only nothing-focused (body) recovers.\n if (focusIsOutsideTree()) {\n focusedId = null\n return\n }\n focusItem(fallbackId)\n })\n }\n },\n focusItem,\n noteFocus: (id) => {\n focusedId = id\n },\n noteBlur: (next) => {\n // Focus moving to an element outside this tree ends the memory of the last\n // focused row and withdraws any focus the tree was still waiting to give a\n // row. A null target (focus to nothing, or the window losing focus) is\n // ambiguous, so both stay for the recovery below.\n if (next instanceof Element && !isInsideTreeRow(next)) cancelPendingFocus()\n },\n activate: (id, event) => local.onActivate?.(id, event),\n expand: (id, expanded) => local.onExpand?.(id, expanded),\n disclosure: () => local.disclosure ?? 'row',\n onActiveIdChange: local.onActiveIdChange,\n }\n\n // A filtered, collapsed-away or removed active ID falls back to the first\n // visible item. This keeps one treeitem in the sequential tab order while\n // notifying the host.\n createEffect(() => {\n const activeId = effectiveActiveId()\n if (activeId === null) return\n // If the projection removes the last row that took focus (a host filter, or\n // an ancestor collapsing), move focus to the same fallback that now owns the\n // roving tab stop, unless a control outside the tree has focus: that control\n // keeps it, and only the roving stop moves.\n if (focusedId !== null && !index().byId.has(focusedId) && pendingFocusId !== activeId) {\n if (focusIsOutsideTree()) {\n focusedId = null\n if (local.activeId !== activeId) local.onActiveIdChange(activeId)\n } else {\n focusItem(activeId)\n }\n } else if (local.activeId !== activeId) {\n local.onActiveIdChange(activeId)\n }\n // Preserve the active row in a caller-owned virtual window, including when\n // the pane mounts with its saved active row outside the initial render range.\n if (!rows.has(activeId)) requestReveal(activeId)\n if (pendingFocusId === activeId) focusWhenMounted(activeId)\n })\n\n const handleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (event) => {\n if (event.defaultPrevented || isActionTarget(event.target, event.currentTarget)) return\n\n const action = treeNavigationAction(index(), effectiveActiveId(), event.key)\n if (!action) return\n event.preventDefault()\n\n switch (action.type) {\n case 'focus':\n focusItem(action.id)\n break\n case 'expand':\n local.onExpand?.(action.id, action.expanded)\n break\n case 'activate':\n local.onActivate?.(action.id, event)\n break\n case 'select':\n local.onSelectItem?.(action.id, event)\n break\n }\n }\n\n return (\n <TreeContext.Provider value={context}>\n <div\n {...rest}\n role=\"tree\"\n aria-multiselectable={local.selectionMode === 'multiple' ? 'true' : undefined}\n data-slot=\"tree\"\n class={cn(\n /* A virtualized host remounts rows as it scrolls; scroll anchoring\n would latch onto the focused row and fight the scrollbar. */\n 'flex min-w-0 flex-col [overflow-anchor:none]',\n local.class\n )}\n onKeyDown={handleKeyDown}\n >\n {local.children}\n </div>\n </TreeContext.Provider>\n )\n}\n\nexport type TreeRowProps = Omit<\n ComponentProps<'div'>,\n | 'children'\n | 'role'\n | 'tabIndex'\n | 'onClick'\n | 'onFocus'\n | 'onDoubleClick'\n | 'style'\n | 'aria-level'\n | 'aria-expanded'\n | 'aria-selected'\n | 'aria-posinset'\n | 'aria-setsize'\n> & {\n item: TreeItemDescriptor\n /** Host-owned selection state; omitted for non-selectable trees. */\n selected?: boolean\n leading?: JSX.Element\n trailing?: JSX.Element\n children: JSX.Element\n onDoubleClick?: (id: string, event: MouseEvent & { currentTarget: HTMLDivElement }) => void\n}\n\n/**\n * TreeRow.\n *\n * Keeps the donor's disclosure marker, leading file/folder affordance, primary\n * label and trailing-action hierarchy while replacing the donor's button and\n * runtime callbacks with a shared treeitem and host-owned slots/actions.\n *\n * With `Tree`'s `disclosure=\"marker\"` the chevron of an expandable row is a\n * separate pointer target (`data-slot=\"tree-row-disclosure\"`) that only calls\n * `onExpand`. It is not focusable and has no role: the row remains the single\n * focus stop, Enter and Space still activate and select, and Left/Right still\n * expand and collapse, so the marker adds a pointer path and nothing else.\n * Pressing it does not move focus or the roving stop to its row; if the toggle\n * hides the focused row, `Tree` recovers focus as it does for any collapse (see\n * the `Tree` comment and docs/tree.md).\n */\nexport function TreeRow(props: TreeRowProps) {\n const tree = useTreeContext()\n const [local, rest] = splitProps(props, [\n 'class',\n 'item',\n 'selected',\n 'leading',\n 'trailing',\n 'children',\n 'onDoubleClick',\n 'ref',\n ])\n\n let row: HTMLDivElement | undefined\n let registeredId: string | undefined\n const id = () => local.item.id\n\n const handleFocusOut = (event: FocusEvent) => tree.noteBlur(event.relatedTarget)\n\n onCleanup(() => {\n row?.removeEventListener('focusout', handleFocusOut)\n tree.unregister(registeredId ?? id(), row)\n })\n\n const setRef = (element: HTMLDivElement) => {\n row = element\n registeredId = id()\n tree.register(registeredId, element)\n // A listener, not an `onFocusOut` prop, so a host's own handler is untouched.\n element.addEventListener('focusout', handleFocusOut)\n }\n\n createEffect(() => {\n const nextId = id()\n if (!row || registeredId === nextId) return\n if (registeredId !== undefined) tree.unregister(registeredId, row)\n registeredId = nextId\n tree.register(nextId, row)\n })\n\n const handleFocus = () => {\n tree.noteFocus(id())\n if (tree.activeId() !== id()) tree.onActiveIdChange(id())\n }\n\n const handleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n tree.focusItem(id())\n tree.activate(id(), event)\n }\n\n const handleDoubleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n local.onDoubleClick?.(id(), event)\n }\n\n const position = () => tree.index().positionById.get(id())\n // Only an expandable row has a chevron to press; a leaf's marker slot stays\n // part of the row so a click there is an ordinary row click.\n const markerTarget = () => tree.disclosure() === 'marker' && local.item.expandable\n\n const handleMarkerClick: JSX.EventHandler<HTMLSpanElement, MouseEvent> = (event) => {\n // The row's own handler would focus and activate the row.\n event.stopPropagation()\n tree.expand(id(), !local.item.expanded)\n }\n return (\n <div\n {...rest}\n ref={composeRefs(setRef, () => local.ref)}\n id={rest.id ?? `${tree.idPrefix}-item-${encodeURIComponent(id())}`}\n role=\"treeitem\"\n aria-level={local.item.level}\n aria-expanded={local.item.expandable ? (local.item.expanded ? 'true' : 'false') : undefined}\n aria-selected={local.selected === undefined ? undefined : local.selected ? 'true' : 'false'}\n aria-posinset={position()?.position}\n aria-setsize={position()?.setSize}\n tabIndex={tree.activeId() === id() ? 0 : -1}\n data-tree-id={id()}\n data-active={tree.activeId() === id() ? '' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-expanded={local.item.expandable ? String(local.item.expanded) : undefined}\n class={cn(\n 'group/tree-row flex min-h-row-sm w-full min-w-0 items-center gap-1.5 rounded-md pe-1.5 text-left text-sm outline-none transition-colors',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n style={{ 'padding-inline-start': `${6 + Math.max(0, local.item.level - 1) * 12}px` }}\n onFocus={handleFocus}\n onClick={handleClick}\n onDblClick={handleDoubleClick}\n >\n <span\n data-slot={markerTarget() ? 'tree-row-disclosure' : undefined}\n class={cn(\n 'flex',\n !markerTarget() && 'size-3.5',\n 'shrink-0 items-center justify-center text-muted-foreground',\n /* The glyph stays 14px wide but the target is not: it takes the row's full\n height (a flex child's `self-stretch`, so it follows row density and a\n tall trailing control) and the pseudo-element widens it to 26px, which\n stops at the row's own padding and gap, never over the icon or label. */\n markerTarget() &&\n 'relative w-3.5 cursor-pointer self-stretch hover:text-foreground after:absolute after:inset-y-0 after:-inset-x-1.5'\n )}\n onMouseDown={markerTarget() ? handleMarkerMouseDown : undefined}\n onClick={markerTarget() ? handleMarkerClick : undefined}\n onDblClick={markerTarget() ? handleMarkerDoubleClick : undefined}\n >\n {local.item.expandable ? (\n <ChevronRight\n aria-hidden=\"true\"\n class={cn('size-3.5 transition-transform', local.item.expanded && 'rotate-90')}\n />\n ) : null}\n </span>\n {local.leading ? (\n <span class=\"flex size-4 shrink-0 items-center justify-center [&_svg]:size-4\">\n {local.leading}\n </span>\n ) : null}\n <span class=\"min-w-0 flex-1 truncate\">{local.children}</span>\n {local.trailing ? (\n <span class=\"ms-auto flex shrink-0 items-center gap-1 text-muted-foreground\">\n {local.trailing}\n </span>\n ) : null}\n </div>\n )\n}\n\n/**\n * TreeRowActions.\n *\n * Row-level commands (rename, copy, delete) that stay out of the way until the\n * row is hovered or holds focus, so a long tree reads as names rather than a\n * wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that\n * must stay visible. `pinned` keeps the actions shown, e.g. while a destructive\n * action waits for its confirming second press.\n */\nexport function TreeRowActions(props: ComponentProps<'span'> & { pinned?: boolean }) {\n const [local, rest] = splitProps(props, ['class', 'pinned'])\n return (\n <span\n data-slot=\"tree-row-actions\"\n data-pinned={local.pinned ? '' : undefined}\n class={cn(\n 'flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out',\n 'group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n// Pressing the chevron must not move focus to its row: a mousedown on a\n// non-focusable child would otherwise focus the row, making it the roving stop\n// (and notifying `onActiveIdChange`) for what is a disclosure toggle, not a\n// selection. The press itself leaves focus where it was, so Left/Right keep\n// acting on the row the keyboard user left off at. It cannot stop the toggle\n// from hiding that row; `Tree` then recovers focus onto the first visible row.\nconst handleMarkerMouseDown: JSX.EventHandler<HTMLSpanElement, MouseEvent> = (event) =>\n event.preventDefault()\n// A double-click is two toggles; it must not also reach `onDoubleClick`\n// (rename, open) as though the row itself had been double-clicked.\nconst handleMarkerDoubleClick: JSX.EventHandler<HTMLSpanElement, MouseEvent> = (event) =>\n event.stopPropagation()\n\nfunction isActionTarget(target: EventTarget | null, currentTarget: HTMLElement): boolean {\n if (!(target instanceof Element) || target === currentTarget) return false\n return Boolean(\n target.closest(\n 'a, button, input, textarea, select, [contenteditable=\"true\"], [role=\"button\"], [data-tree-keyboard-stop]'\n )\n )\n}\n\nfunction composeRefs(\n internal: (element: HTMLDivElement) => void,\n external: () => ComponentProps<'div'>['ref']\n): (element: HTMLDivElement) => void {\n return (element) => {\n internal(element)\n const ref = external()\n if (typeof ref === 'function') ref(element)\n }\n}\n\nexport type { TreeItemDescriptor } from './tree-navigation'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tree.js","names":["ComponentProps","JSX","ChevronRight","createContext","createEffect","createMemo","createUniqueId","For","onCleanup","Show","splitProps","useContext","cn","indexTreeItems","treeNavigationAction","TreeItemDescriptor","TreeNavigationIndex","TreeContextValue","idPrefix","activeId","index","register","id","element","HTMLDivElement","unregister","focusItem","noteFocus","noteBlur","next","EventTarget","activate","event","Event","expand","expanded","disclosure","TreeDisclosure","guides","onActiveIdChange","TreeContext","useTreeContext","tree","Error","TreeAccessibleName","TreeProps","Omit","visibleItems","onExpand","onActivate","onSelectItem","onRequestReveal","onRowSizeChange","blockSize","selectionMode","children","Element","Tree","props","local","rest","effectiveActiveId","candidate","visible","byId","has","ids","rows","Map","rowIdsByElement","WeakMap","pendingFocusId","pendingFocusGuard","FocusEvent","requestedRevealId","focusedId","disposed","isInsideTreeRow","row","closest","focusIsOutsideTree","document","active","activeElement","body","documentElement","rowSizeObserver","ResizeObserver","undefined","entries","entry","get","target","borderBoxSize","HTMLElement","offsetHeight","Number","isFinite","setPendingFocus","removeEventListener","cancelPendingFocus","addEventListener","disconnect","requestReveal","focusWhenMounted","queueMicrotask","focus","context","set","observe","focusWasInside","Boolean","contains","delete","unobserve","fallbackId","handleKeyDown","EventHandler","KeyboardEvent","defaultPrevented","isActionTarget","currentTarget","action","key","preventDefault","type","_$createComponent","Provider","value","_el$","_tmpl$","_$spread","_$mergeProps","aria-multiselectable","class","_$insert","TreeRowProps","item","selected","leading","trailing","onDoubleClick","MouseEvent","TreeRow","registeredId","handleFocusOut","relatedTarget","setRef","nextId","handleFocus","handleClick","handleDoubleClick","position","positionById","markerTarget","expandable","handleMarkerClick","HTMLSpanElement","stopPropagation","_el$2","_tmpl$2","_el$3","firstChild","_el$4","nextSibling","_ref$","composeRefs","ref","_$use","encodeURIComponent","aria-level","level","aria-expanded","_$memo","aria-selected","aria-posinset","aria-setsize","setSize","tabIndex","data-tree-id","data-active","data-selected","data-expanded","String","relative","style","Math","max","when","each","Array","from","length","_","_el$5","_tmpl$3","_$setStyleProperty","_$addEventListener","handleMarkerDoubleClick","handleMarkerMouseDown","_c$","_c$2","_el$6","_tmpl$4","_c$3","_el$7","_tmpl$5","_$effect","_p$","_v$","_v$2","e","_$setAttribute","t","_$className","TreeRowActions","pinned","_el$8","_tmpl$6","data-pinned","internal","external","_$delegateEvents","_$createComponent","_$mergeProps","_$use","_$memo","_$setAttribute","_$className","_$delegateEvents"],"sources":["../../../../src/components/composites/tree/tree.tsx"],"sourcesContent":["import type { ComponentProps, JSX } from 'solid-js'\nimport { ChevronRight } from 'lucide-solid'\nimport {\n createContext,\n createEffect,\n createMemo,\n createUniqueId,\n For,\n onCleanup,\n Show,\n splitProps,\n useContext,\n} from 'solid-js'\nimport { cn } from '#lib/utils'\nimport {\n indexTreeItems,\n treeNavigationAction,\n type TreeItemDescriptor,\n type TreeNavigationIndex,\n} from './tree-navigation'\n\ntype TreeContextValue = {\n idPrefix: string\n activeId: () => string | null\n index: () => TreeNavigationIndex\n register: (id: string, element: HTMLDivElement) => void\n unregister: (id: string, element: HTMLDivElement | undefined) => void\n focusItem: (id: string) => void\n noteFocus: (id: string) => void\n noteBlur: (next: EventTarget | null) => void\n activate: (id: string, event: Event) => void\n expand: (id: string, expanded: boolean) => void\n disclosure: () => TreeDisclosure\n guides: () => boolean\n onActiveIdChange: (id: string) => void\n}\n\nconst TreeContext = createContext<TreeContextValue>()\n\nfunction useTreeContext() {\n const tree = useContext(TreeContext)\n if (!tree) throw new Error('[adea-ui]: TreeRow must be used inside Tree.')\n return tree\n}\n\n/**\n * Who owns the pointer on a row's disclosure chevron.\n *\n * - `row` (default): the chevron is decoration; a click anywhere on the row,\n * chevron included, is a row activation. This is the file-explorer\n * convention, where the host's `onActivate` toggles a folder.\n * - `marker`: the chevron of an expandable row is its own pointer target. It\n * calls `onExpand(id, !expanded)` and nothing else; the rest of the row still\n * activates. For trees where expanding and selecting are independent (a\n * source list that selects a source and separately reveals its details).\n */\nexport type TreeDisclosure = 'row' | 'marker'\n\ntype TreeAccessibleName =\n | { 'aria-label': string; 'aria-labelledby'?: string }\n | { 'aria-label'?: string; 'aria-labelledby': string }\n\nexport type TreeProps = Omit<\n ComponentProps<'div'>,\n 'children' | 'role' | 'tabIndex' | 'onKeyDown' | 'aria-label' | 'aria-labelledby'\n> &\n TreeAccessibleName & {\n /** Complete, ordered projection of currently visible (expanded) items. */\n visibleItems: readonly TreeItemDescriptor[]\n /** The host-owned identity of the row that currently owns roving focus. */\n activeId: string | null\n /**\n * Called when keyboard or pointer navigation changes the active row, and when\n * the active row leaves `visibleItems` (collapsed away, filtered out) and the\n * first visible row takes over as the roving stop.\n */\n onActiveIdChange: (id: string) => void\n /** Called for Left/Right expand and collapse requests. */\n onExpand?: (id: string, expanded: boolean) => void\n /**\n * Opt-in pointer behaviour of the disclosure chevron; see {@link TreeDisclosure}.\n * Keyboard behaviour is identical in both modes: Left/Right expand and collapse.\n */\n disclosure?: TreeDisclosure\n /**\n * Draw a vertical guide line down each ancestor level of a nested row, so a\n * group of children reads as belonging to its parent. Off by default: a flat\n * list or a dense file explorer carries its own rhythm.\n */\n guides?: boolean\n /** Called for Enter or pointer activation. Domain action stays host-owned. */\n onActivate?: (id: string, event: Event) => void\n /** Called for Space selection. Selection state stays host-owned. */\n onSelectItem?: (id: string, event: Event) => void\n /** Ask the host window to mount/reveal an item before focus moves to it. */\n onRequestReveal?: (id: string) => void\n /** Report a mounted row's border-box block size in CSS pixels for host range math. */\n onRowSizeChange?: (id: string, blockSize: number) => void\n /** Declares a multi-select tree to assistive technology. */\n selectionMode?: 'single' | 'multiple'\n children?: JSX.Element\n }\n\n/**\n * Tree.\n *\n * Supplies semantic and keyboard behavior for a tree whose host owns the\n * visible projection, filesystem state, row window and domain actions. The\n * mounted children can be a small virtualized window; `visibleItems` remains\n * the complete ordered projection so keyboard movement and sibling positions\n * do not depend on which rows currently exist in the DOM.\n *\n * Kobalte 0.13.14 has no Tree primitive, so this component implements the\n * WAI-ARIA tree row navigation contract and leaves product state to callbacks.\n *\n * By default the disclosure chevron is decoration and a click anywhere on a\n * row activates it, so a file explorer can toggle a folder from `onActivate`.\n * Reach for `disclosure=\"marker\"` when expanding and selecting are separate\n * decisions: the chevron then calls only `onExpand`, and the rest of the row\n * calls only `onActivate`. The chevron stays `aria-hidden` and out of the tab\n * order in both modes; keyboard expansion is Left/Right either way.\n *\n * Collapsing is the one thing that can move focus without a key or a click on\n * the target row: when the active row leaves `visibleItems`, the first visible\n * row becomes the roving stop and `onActiveIdChange` is called with it. If the\n * removed row held focus, or was the last row the tree saw focused, focus moves\n * to that same row; if it had no focus, only the roving stop moves. Focus that\n * has already gone to a control outside the tree is never pulled back: the tree\n * forgets its last focused row when focus moves to an element outside it, and\n * the roving stop alone moves if that control still has focus when the row is\n * hidden. Focus the tree has asked for but not yet moved (a queued recovery, or a\n * keyboard move to a row the host has not mounted) is withdrawn when focus lands\n * outside the tree, and is checked again when a row mounts. This is the same in\n * both `disclosure` modes and for every way a host collapses a row.\n */\nexport function Tree(props: TreeProps) {\n const [local, rest] = splitProps(props, [\n 'class',\n 'visibleItems',\n 'activeId',\n 'onActiveIdChange',\n 'onExpand',\n 'disclosure',\n 'guides',\n 'onActivate',\n 'onSelectItem',\n 'onRequestReveal',\n 'onRowSizeChange',\n 'selectionMode',\n 'children',\n ])\n\n const index = createMemo(() => indexTreeItems(local.visibleItems))\n const effectiveActiveId = createMemo(() => {\n const candidate = local.activeId\n const visible = index()\n return candidate !== null && visible.byId.has(candidate) ? candidate : (visible.ids[0] ?? null)\n })\n const idPrefix = `tree-${createUniqueId()}`\n const rows = new Map<string, HTMLDivElement>()\n const rowIdsByElement = new WeakMap<HTMLDivElement, string>()\n let pendingFocusId: string | null = null\n let pendingFocusGuard: ((event: FocusEvent) => void) | undefined\n let requestedRevealId: string | null = null\n let focusedId: string | null = null\n let disposed = false\n const isInsideTreeRow = (element: Element) => {\n const row = element.closest('[role=\"treeitem\"]')\n return row instanceof HTMLDivElement && rowIdsByElement.has(row)\n }\n // True when a focusable control outside this tree owns focus. Nothing focused\n // (`body`) is not outside: that is where focus falls when a focused row is removed.\n const focusIsOutsideTree = () => {\n if (typeof document === 'undefined') return false\n const active = document.activeElement\n return (\n active instanceof Element &&\n active !== document.body &&\n active !== document.documentElement &&\n !isInsideTreeRow(active)\n )\n }\n const rowSizeObserver =\n typeof ResizeObserver === 'undefined'\n ? undefined\n : new ResizeObserver((entries) => {\n if (disposed) return\n for (const entry of entries) {\n const id = rowIdsByElement.get(entry.target as HTMLDivElement)\n const blockSize =\n entry.borderBoxSize[0]?.blockSize ?? (entry.target as HTMLElement).offsetHeight\n if (id !== undefined && Number.isFinite(blockSize) && blockSize > 0)\n local.onRowSizeChange?.(id, blockSize)\n }\n })\n\n // Focus the tree has asked for but not yet moved (a microtask away, or waiting for a\n // virtualised row to mount) is only a request. While one is pending, focus arriving\n // on a control outside the tree withdraws it, so a row mounting later cannot take\n // focus back from a control the user, or the host, has since chosen.\n const setPendingFocus = (id: string | null) => {\n pendingFocusId = id\n if (typeof document === 'undefined') return\n if (id === null) {\n if (pendingFocusGuard) document.removeEventListener('focusin', pendingFocusGuard, true)\n pendingFocusGuard = undefined\n } else if (!pendingFocusGuard) {\n pendingFocusGuard = (event) => {\n if (event.target instanceof Element && !isInsideTreeRow(event.target)) cancelPendingFocus()\n }\n document.addEventListener('focusin', pendingFocusGuard, true)\n }\n }\n // Withdrawing a request also drops the memory of the row it was recovering for:\n // nothing is left to recover.\n const cancelPendingFocus = () => {\n setPendingFocus(null)\n focusedId = null\n }\n\n onCleanup(() => {\n disposed = true\n setPendingFocus(null)\n rowSizeObserver?.disconnect()\n })\n\n const requestReveal = (id: string) => {\n if (requestedRevealId === id) return\n requestedRevealId = id\n local.onRequestReveal?.(id)\n }\n\n const focusWhenMounted = (id: string) => {\n queueMicrotask(() => {\n if (pendingFocusId !== id || effectiveActiveId() !== id) return\n const row = rows.get(id)\n if (!row || typeof document === 'undefined') return\n // Ownership is checked when focus would move, not when it was requested: a\n // control outside the tree may have taken focus since, and keeps it.\n if (focusIsOutsideTree()) {\n cancelPendingFocus()\n return\n }\n row.focus()\n if (document.activeElement === row) setPendingFocus(null)\n })\n }\n\n const focusItem = (id: string) => {\n setPendingFocus(id)\n local.onActiveIdChange(id)\n if (rows.has(id)) requestedRevealId = null\n else requestReveal(id)\n focusWhenMounted(id)\n }\n\n const context: TreeContextValue = {\n idPrefix,\n activeId: effectiveActiveId,\n index,\n register: (id, element) => {\n rows.set(id, element)\n rowIdsByElement.set(element, id)\n rowSizeObserver?.observe(element)\n if (requestedRevealId === id) requestedRevealId = null\n if (pendingFocusId === id) focusWhenMounted(id)\n },\n unregister: (id, element) => {\n if (rows.get(id) !== element) return\n const focusWasInside =\n !disposed &&\n Boolean(\n element && typeof document !== 'undefined' && element.contains(document.activeElement)\n )\n rows.delete(id)\n if (element) {\n rowIdsByElement.delete(element)\n rowSizeObserver?.unobserve(element)\n }\n if (requestedRevealId === id) requestedRevealId = null\n if (focusWasInside) {\n queueMicrotask(() => {\n const fallbackId = effectiveActiveId()\n if (disposed || fallbackId === null || pendingFocusId === fallbackId) return\n // Focus fell out of the removed row, but it may have been given to a control\n // outside the tree before this ran. Only nothing-focused (body) recovers.\n if (focusIsOutsideTree()) {\n focusedId = null\n return\n }\n focusItem(fallbackId)\n })\n }\n },\n focusItem,\n noteFocus: (id) => {\n focusedId = id\n },\n noteBlur: (next) => {\n // Focus moving to an element outside this tree ends the memory of the last\n // focused row and withdraws any focus the tree was still waiting to give a\n // row. A null target (focus to nothing, or the window losing focus) is\n // ambiguous, so both stay for the recovery below.\n if (next instanceof Element && !isInsideTreeRow(next)) cancelPendingFocus()\n },\n activate: (id, event) => local.onActivate?.(id, event),\n expand: (id, expanded) => local.onExpand?.(id, expanded),\n disclosure: () => local.disclosure ?? 'row',\n guides: () => local.guides ?? false,\n onActiveIdChange: local.onActiveIdChange,\n }\n\n // A filtered, collapsed-away or removed active ID falls back to the first\n // visible item. This keeps one treeitem in the sequential tab order while\n // notifying the host.\n createEffect(() => {\n const activeId = effectiveActiveId()\n if (activeId === null) return\n // If the projection removes the last row that took focus (a host filter, or\n // an ancestor collapsing), move focus to the same fallback that now owns the\n // roving tab stop, unless a control outside the tree has focus: that control\n // keeps it, and only the roving stop moves.\n if (focusedId !== null && !index().byId.has(focusedId) && pendingFocusId !== activeId) {\n if (focusIsOutsideTree()) {\n focusedId = null\n if (local.activeId !== activeId) local.onActiveIdChange(activeId)\n } else {\n focusItem(activeId)\n }\n } else if (local.activeId !== activeId) {\n local.onActiveIdChange(activeId)\n }\n // Preserve the active row in a caller-owned virtual window, including when\n // the pane mounts with its saved active row outside the initial render range.\n if (!rows.has(activeId)) requestReveal(activeId)\n if (pendingFocusId === activeId) focusWhenMounted(activeId)\n })\n\n const handleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (event) => {\n if (event.defaultPrevented || isActionTarget(event.target, event.currentTarget)) return\n\n const action = treeNavigationAction(index(), effectiveActiveId(), event.key)\n if (!action) return\n event.preventDefault()\n\n switch (action.type) {\n case 'focus':\n focusItem(action.id)\n break\n case 'expand':\n local.onExpand?.(action.id, action.expanded)\n break\n case 'activate':\n local.onActivate?.(action.id, event)\n break\n case 'select':\n local.onSelectItem?.(action.id, event)\n break\n }\n }\n\n return (\n <TreeContext.Provider value={context}>\n <div\n {...rest}\n role=\"tree\"\n aria-multiselectable={local.selectionMode === 'multiple' ? 'true' : undefined}\n data-slot=\"tree\"\n class={cn(\n /* A virtualized host remounts rows as it scrolls; scroll anchoring\n would latch onto the focused row and fight the scrollbar. */\n 'flex min-w-0 flex-col [overflow-anchor:none]',\n local.class\n )}\n onKeyDown={handleKeyDown}\n >\n {local.children}\n </div>\n </TreeContext.Provider>\n )\n}\n\nexport type TreeRowProps = Omit<\n ComponentProps<'div'>,\n | 'children'\n | 'role'\n | 'tabIndex'\n | 'onClick'\n | 'onFocus'\n | 'onDoubleClick'\n | 'style'\n | 'aria-level'\n | 'aria-expanded'\n | 'aria-selected'\n | 'aria-posinset'\n | 'aria-setsize'\n> & {\n item: TreeItemDescriptor\n /** Host-owned selection state; omitted for non-selectable trees. */\n selected?: boolean\n leading?: JSX.Element\n trailing?: JSX.Element\n children: JSX.Element\n onDoubleClick?: (id: string, event: MouseEvent & { currentTarget: HTMLDivElement }) => void\n}\n\n/**\n * TreeRow.\n *\n * Keeps the donor's disclosure marker, leading file/folder affordance, primary\n * label and trailing-action hierarchy while replacing the donor's button and\n * runtime callbacks with a shared treeitem and host-owned slots/actions.\n *\n * With `Tree`'s `disclosure=\"marker\"` the chevron of an expandable row is a\n * separate pointer target (`data-slot=\"tree-row-disclosure\"`) that only calls\n * `onExpand`. It is not focusable and has no role: the row remains the single\n * focus stop, Enter and Space still activate and select, and Left/Right still\n * expand and collapse, so the marker adds a pointer path and nothing else.\n * Pressing it does not move focus or the roving stop to its row; if the toggle\n * hides the focused row, `Tree` recovers focus as it does for any collapse (see\n * the `Tree` comment and docs/tree.md).\n */\nexport function TreeRow(props: TreeRowProps) {\n const tree = useTreeContext()\n const [local, rest] = splitProps(props, [\n 'class',\n 'item',\n 'selected',\n 'leading',\n 'trailing',\n 'children',\n 'onDoubleClick',\n 'ref',\n ])\n\n let row: HTMLDivElement | undefined\n let registeredId: string | undefined\n const id = () => local.item.id\n\n const handleFocusOut = (event: FocusEvent) => tree.noteBlur(event.relatedTarget)\n\n onCleanup(() => {\n row?.removeEventListener('focusout', handleFocusOut)\n tree.unregister(registeredId ?? id(), row)\n })\n\n const setRef = (element: HTMLDivElement) => {\n row = element\n registeredId = id()\n tree.register(registeredId, element)\n // A listener, not an `onFocusOut` prop, so a host's own handler is untouched.\n element.addEventListener('focusout', handleFocusOut)\n }\n\n createEffect(() => {\n const nextId = id()\n if (!row || registeredId === nextId) return\n if (registeredId !== undefined) tree.unregister(registeredId, row)\n registeredId = nextId\n tree.register(nextId, row)\n })\n\n const handleFocus = () => {\n tree.noteFocus(id())\n if (tree.activeId() !== id()) tree.onActiveIdChange(id())\n }\n\n const handleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n tree.focusItem(id())\n tree.activate(id(), event)\n }\n\n const handleDoubleClick: JSX.EventHandler<HTMLDivElement, MouseEvent> = (event) => {\n if (isActionTarget(event.target, event.currentTarget)) return\n local.onDoubleClick?.(id(), event)\n }\n\n const position = () => tree.index().positionById.get(id())\n // Only an expandable row has a chevron to press; a leaf's marker slot stays\n // part of the row so a click there is an ordinary row click.\n const markerTarget = () => tree.disclosure() === 'marker' && local.item.expandable\n\n const handleMarkerClick: JSX.EventHandler<HTMLSpanElement, MouseEvent> = (event) => {\n // The row's own handler would focus and activate the row.\n event.stopPropagation()\n tree.expand(id(), !local.item.expanded)\n }\n return (\n <div\n {...rest}\n ref={composeRefs(setRef, () => local.ref)}\n id={rest.id ?? `${tree.idPrefix}-item-${encodeURIComponent(id())}`}\n role=\"treeitem\"\n aria-level={local.item.level}\n aria-expanded={local.item.expandable ? (local.item.expanded ? 'true' : 'false') : undefined}\n aria-selected={local.selected === undefined ? undefined : local.selected ? 'true' : 'false'}\n aria-posinset={position()?.position}\n aria-setsize={position()?.setSize}\n tabIndex={tree.activeId() === id() ? 0 : -1}\n data-tree-id={id()}\n data-active={tree.activeId() === id() ? '' : undefined}\n data-selected={local.selected ? '' : undefined}\n data-expanded={local.item.expandable ? String(local.item.expanded) : undefined}\n class={cn(\n 'group/tree-row flex min-h-row-sm w-full min-w-0 items-center gap-1.5 rounded-md pe-1.5 text-left text-sm outline-none transition-colors',\n 'focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-primary-subtle',\n {\n // Guide lines are positioned against the row; without them it keeps its original classes.\n relative: tree.guides(),\n 'bg-primary-subtle text-foreground': local.selected,\n 'hover:bg-surface-hover': !local.selected,\n },\n local.class\n )}\n style={{ 'padding-inline-start': `${6 + Math.max(0, local.item.level - 1) * 12}px` }}\n onFocus={handleFocus}\n onClick={handleClick}\n onDblClick={handleDoubleClick}\n >\n <Show when={tree.guides() && local.item.level > 1}>\n <For each={Array.from({ length: local.item.level - 1 }, (_, index) => index)}>\n {(index) => (\n <span\n aria-hidden=\"true\"\n data-slot=\"tree-row-guide\"\n class=\"pointer-events-none absolute inset-y-0 w-px bg-border\"\n style={{ 'inset-inline-start': `${6 + index * 12 + 7}px` }}\n />\n )}\n </For>\n </Show>\n <span\n data-slot={markerTarget() ? 'tree-row-disclosure' : undefined}\n class={cn(\n 'flex',\n !markerTarget() && 'size-3.5',\n 'shrink-0 items-center justify-center text-muted-foreground',\n /* The glyph stays 14px wide but the target is not: it takes the row's full\n height (a flex child's `self-stretch`, so it follows row density and a\n tall trailing control) and the pseudo-element widens it to 26px, which\n stops at the row's own padding and gap, never over the icon or label. */\n markerTarget() &&\n 'relative w-3.5 cursor-pointer self-stretch hover:text-foreground after:absolute after:inset-y-0 after:-inset-x-1.5'\n )}\n onMouseDown={markerTarget() ? handleMarkerMouseDown : undefined}\n onClick={markerTarget() ? handleMarkerClick : undefined}\n onDblClick={markerTarget() ? handleMarkerDoubleClick : undefined}\n >\n {local.item.expandable ? (\n <ChevronRight\n aria-hidden=\"true\"\n class={cn('size-3.5 transition-transform', local.item.expanded && 'rotate-90')}\n />\n ) : null}\n </span>\n {local.leading ? (\n <span class=\"flex size-4 shrink-0 items-center justify-center [&_svg]:size-4\">\n {local.leading}\n </span>\n ) : null}\n <span class=\"min-w-0 flex-1 truncate\">{local.children}</span>\n {local.trailing ? (\n <span class=\"ms-auto flex shrink-0 items-center gap-1 text-muted-foreground\">\n {local.trailing}\n </span>\n ) : null}\n </div>\n )\n}\n\n/**\n * TreeRowActions.\n *\n * Row-level commands (rename, copy, delete) that stay out of the way until the\n * row is hovered or holds focus, so a long tree reads as names rather than a\n * wall of buttons. Put it in `TreeRow`'s `trailing` slot beside any status that\n * must stay visible. `pinned` keeps the actions shown, e.g. while a destructive\n * action waits for its confirming second press.\n */\nexport function TreeRowActions(props: ComponentProps<'span'> & { pinned?: boolean }) {\n const [local, rest] = splitProps(props, ['class', 'pinned'])\n return (\n <span\n data-slot=\"tree-row-actions\"\n data-pinned={local.pinned ? '' : undefined}\n class={cn(\n 'flex shrink-0 items-center gap-1 opacity-0 transition-opacity ease-out',\n 'group-hover/tree-row:opacity-100 group-focus-within/tree-row:opacity-100 data-pinned:opacity-100',\n local.class\n )}\n {...rest}\n />\n )\n}\n\n// Pressing the chevron must not move focus to its row: a mousedown on a\n// non-focusable child would otherwise focus the row, making it the roving stop\n// (and notifying `onActiveIdChange`) for what is a disclosure toggle, not a\n// selection. The press itself leaves focus where it was, so Left/Right keep\n// acting on the row the keyboard user left off at. It cannot stop the toggle\n// from hiding that row; `Tree` then recovers focus onto the first visible row.\nconst handleMarkerMouseDown: JSX.EventHandler<HTMLSpanElement, MouseEvent> = (event) =>\n event.preventDefault()\n// A double-click is two toggles; it must not also reach `onDoubleClick`\n// (rename, open) as though the row itself had been double-clicked.\nconst handleMarkerDoubleClick: JSX.EventHandler<HTMLSpanElement, MouseEvent> = (event) =>\n event.stopPropagation()\n\nfunction isActionTarget(target: EventTarget | null, currentTarget: HTMLElement): boolean {\n if (!(target instanceof Element) || target === currentTarget) return false\n return Boolean(\n target.closest(\n 'a, button, input, textarea, select, [contenteditable=\"true\"], [role=\"button\"], [data-tree-keyboard-stop]'\n )\n )\n}\n\nfunction composeRefs(\n internal: (element: HTMLDivElement) => void,\n external: () => ComponentProps<'div'>['ref']\n): (element: HTMLDivElement) => void {\n return (element) => {\n internal(element)\n const ref = external()\n if (typeof ref === 'function') ref(element)\n }\n}\n\nexport type { TreeItemDescriptor } from './tree-navigation'\n"],"mappings":"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"}
|