@platned/ui 0.6.1 → 0.7.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/README.md +7 -7
- package/dist/index.cjs +6198 -3852
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1505 -203
- package/dist/index.d.ts +1505 -203
- package/dist/index.js +5772 -3510
- package/dist/index.js.map +1 -1
- package/dist/sidebar.cjs +542 -876
- package/dist/sidebar.cjs.map +1 -1
- package/dist/sidebar.d.cts +56 -0
- package/dist/sidebar.d.ts +56 -0
- package/dist/sidebar.js +539 -894
- package/dist/sidebar.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +5 -3
- package/tailwind-preset.cjs +79 -0
package/dist/sidebar.js
CHANGED
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
// src/sidebar/index.tsx
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { createContext as createContext4, useContext as useContext4, useMemo as useMemo2 } from "react";
|
|
3
|
+
import { Link, useLocation } from "react-router-dom";
|
|
4
|
+
import { ChevronLeftIcon, ChevronRightIcon as ChevronRightIcon2, EllipsisVerticalIcon, LogOutIcon } from "lucide-react";
|
|
5
|
+
|
|
6
|
+
// src/lib/cn.ts
|
|
7
|
+
import { clsx } from "clsx";
|
|
8
|
+
import { extendTailwindMerge } from "tailwind-merge";
|
|
9
|
+
var FONT_SIZES = [
|
|
10
|
+
"body-micro",
|
|
11
|
+
"body-tiny",
|
|
12
|
+
"body-xs",
|
|
13
|
+
"body-sm",
|
|
14
|
+
"body",
|
|
15
|
+
"body-lg",
|
|
16
|
+
"heading-sm",
|
|
17
|
+
"heading",
|
|
18
|
+
"heading-lg",
|
|
19
|
+
"subheading-sm",
|
|
20
|
+
"subheading",
|
|
21
|
+
"subheading-lg",
|
|
22
|
+
"subtitle-sm",
|
|
23
|
+
"subtitle",
|
|
24
|
+
"subtitle-lg",
|
|
25
|
+
"title-sm",
|
|
26
|
+
"title",
|
|
27
|
+
"title-lg",
|
|
28
|
+
"title-hero",
|
|
29
|
+
"scale-01",
|
|
30
|
+
"scale-02",
|
|
31
|
+
"scale-03",
|
|
32
|
+
"scale-04",
|
|
33
|
+
"scale-05",
|
|
34
|
+
"scale-06",
|
|
35
|
+
"scale-07",
|
|
36
|
+
"scale-08",
|
|
37
|
+
"scale-09",
|
|
38
|
+
"scale-10",
|
|
39
|
+
"scale-12"
|
|
40
|
+
];
|
|
41
|
+
var twMerge = extendTailwindMerge({
|
|
42
|
+
extend: {
|
|
43
|
+
classGroups: {
|
|
44
|
+
"font-size": [{ text: [...FONT_SIZES] }]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
function cn(...inputs) {
|
|
49
|
+
return twMerge(clsx(inputs));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/lib/focus-ring.ts
|
|
53
|
+
var FOCUS_RING = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1 focus-visible:ring-offset-default";
|
|
54
|
+
var FOCUS_RING_INSET = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand";
|
|
4
55
|
|
|
5
56
|
// src/lib/slot.tsx
|
|
6
57
|
import {
|
|
@@ -8,7 +59,7 @@ import {
|
|
|
8
59
|
forwardRef,
|
|
9
60
|
isValidElement
|
|
10
61
|
} from "react";
|
|
11
|
-
import
|
|
62
|
+
import clsx2 from "clsx";
|
|
12
63
|
var Slot = forwardRef(function Slot2({ children, wrapChildren, ...slotProps }, forwardedRef) {
|
|
13
64
|
if (!isValidElement(children)) return null;
|
|
14
65
|
const child = children;
|
|
@@ -33,7 +84,7 @@ function mergeProps(slotProps, childProps) {
|
|
|
33
84
|
merged[key] = childValue ?? slotValue;
|
|
34
85
|
}
|
|
35
86
|
} else if (key === "className") {
|
|
36
|
-
merged[key] =
|
|
87
|
+
merged[key] = clsx2(slotValue, childValue);
|
|
37
88
|
} else if (key === "style") {
|
|
38
89
|
merged[key] = { ...slotValue, ...childValue };
|
|
39
90
|
} else {
|
|
@@ -70,27 +121,30 @@ function useControlSize(explicit) {
|
|
|
70
121
|
|
|
71
122
|
// src/components/forms/icon-button.tsx
|
|
72
123
|
import { forwardRef as forwardRef2 } from "react";
|
|
73
|
-
import
|
|
124
|
+
import clsx3 from "clsx";
|
|
74
125
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
75
126
|
var variantStyles = {
|
|
76
|
-
primary:
|
|
127
|
+
primary: clsx3(
|
|
77
128
|
"bg-brand border border-brand text-brand-on-brand",
|
|
78
129
|
"hover:bg-brand-hover",
|
|
79
|
-
"disabled:bg-disabled disabled:border-disabled disabled:text-disabled-on-disabled"
|
|
130
|
+
"disabled:bg-disabled disabled:border-disabled disabled:text-disabled-on-disabled",
|
|
131
|
+
"aria-disabled:bg-disabled aria-disabled:border-disabled aria-disabled:text-disabled-on-disabled"
|
|
80
132
|
),
|
|
81
133
|
// Neutral uses secondary background (light gray) for visual weight without a text label
|
|
82
|
-
neutral:
|
|
134
|
+
neutral: clsx3(
|
|
83
135
|
"bg-default-secondary border border-default text-default",
|
|
84
136
|
// icon turns brand blue on hover (Figma spec)
|
|
85
137
|
"hover:bg-default-secondary-hover hover:text-brand",
|
|
86
|
-
"disabled:bg-disabled disabled:border-disabled disabled:text-disabled-on-disabled"
|
|
138
|
+
"disabled:bg-disabled disabled:border-disabled disabled:text-disabled-on-disabled",
|
|
139
|
+
"aria-disabled:bg-disabled aria-disabled:border-disabled aria-disabled:text-disabled-on-disabled"
|
|
87
140
|
),
|
|
88
|
-
subtle:
|
|
141
|
+
subtle: clsx3(
|
|
89
142
|
"bg-transparent text-neutral",
|
|
90
143
|
// hover uses background-default-default-hover (#f5f5f5), icon turns brand blue (Figma spec)
|
|
91
144
|
"hover:bg-default-hover hover:text-brand",
|
|
92
145
|
// disabled needs explicit border since there is no base border
|
|
93
|
-
"disabled:bg-disabled disabled:border disabled:border-disabled disabled:text-disabled-on-disabled"
|
|
146
|
+
"disabled:bg-disabled disabled:border disabled:border-disabled disabled:text-disabled-on-disabled",
|
|
147
|
+
"aria-disabled:bg-disabled aria-disabled:border aria-disabled:border-disabled aria-disabled:text-disabled-on-disabled"
|
|
94
148
|
)
|
|
95
149
|
};
|
|
96
150
|
var sizeStyles = {
|
|
@@ -98,27 +152,52 @@ var sizeStyles = {
|
|
|
98
152
|
md: "size-9 rounded-lg [&_svg]:size-5",
|
|
99
153
|
sm: "size-6 rounded-full [&_svg]:size-4"
|
|
100
154
|
};
|
|
101
|
-
var IconButton = forwardRef2(function IconButton2({
|
|
102
|
-
|
|
155
|
+
var IconButton = forwardRef2(function IconButton2({
|
|
156
|
+
variant = "primary",
|
|
157
|
+
size: sizeProp,
|
|
158
|
+
asChild = false,
|
|
159
|
+
type,
|
|
160
|
+
disabled,
|
|
161
|
+
onClick,
|
|
162
|
+
children,
|
|
163
|
+
className,
|
|
164
|
+
...props
|
|
165
|
+
}, ref) {
|
|
166
|
+
const size = useControlSize(sizeProp);
|
|
167
|
+
const softDisabled = asChild && Boolean(disabled);
|
|
168
|
+
const handleClick = (event) => {
|
|
169
|
+
if (softDisabled) {
|
|
170
|
+
event.preventDefault();
|
|
171
|
+
event.stopPropagation();
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
onClick?.(event);
|
|
175
|
+
};
|
|
103
176
|
const rootProps = {
|
|
104
|
-
className
|
|
177
|
+
// `cn`, so a caller's `className` beats the size's radius and the variant's colours.
|
|
178
|
+
className: cn(
|
|
105
179
|
"inline-flex shrink-0 items-center justify-center transition-colors",
|
|
106
|
-
|
|
107
|
-
"disabled:cursor-not-allowed",
|
|
180
|
+
FOCUS_RING,
|
|
181
|
+
"disabled:cursor-not-allowed aria-disabled:cursor-not-allowed",
|
|
108
182
|
variantStyles[variant],
|
|
109
|
-
sizeStyles[
|
|
183
|
+
sizeStyles[size],
|
|
110
184
|
className
|
|
111
185
|
),
|
|
186
|
+
"data-variant": variant,
|
|
187
|
+
"data-size": size,
|
|
188
|
+
"aria-disabled": softDisabled || void 0,
|
|
189
|
+
onClick: handleClick,
|
|
112
190
|
...props
|
|
113
191
|
};
|
|
114
192
|
if (asChild) {
|
|
115
|
-
return /* @__PURE__ */ jsx2(Slot, { ref, ...rootProps, children });
|
|
193
|
+
return /* @__PURE__ */ jsx2(Slot, { ref, tabIndex: disabled ? -1 : void 0, ...rootProps, children });
|
|
116
194
|
}
|
|
117
195
|
return /* @__PURE__ */ jsx2(
|
|
118
196
|
"button",
|
|
119
197
|
{
|
|
120
198
|
ref,
|
|
121
199
|
type: type ?? "button",
|
|
200
|
+
disabled,
|
|
122
201
|
...rootProps,
|
|
123
202
|
children
|
|
124
203
|
}
|
|
@@ -126,7 +205,7 @@ var IconButton = forwardRef2(function IconButton2({ variant = "primary", size: s
|
|
|
126
205
|
});
|
|
127
206
|
|
|
128
207
|
// src/components/avatar/avatar.tsx
|
|
129
|
-
import
|
|
208
|
+
import clsx4 from "clsx";
|
|
130
209
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
131
210
|
var sizeStyles2 = {
|
|
132
211
|
lg: "size-10",
|
|
@@ -138,16 +217,16 @@ var initialTextStyles = {
|
|
|
138
217
|
md: "text-body-xs font-semibold",
|
|
139
218
|
sm: "text-body-tiny font-semibold"
|
|
140
219
|
};
|
|
141
|
-
function getShapeClass(shape,
|
|
220
|
+
function getShapeClass(shape, size) {
|
|
142
221
|
if (shape === "circle") return "rounded-full";
|
|
143
|
-
return
|
|
222
|
+
return size === "sm" ? "rounded" : "rounded-lg";
|
|
144
223
|
}
|
|
145
224
|
function Avatar(props) {
|
|
146
|
-
const { size
|
|
147
|
-
const base =
|
|
225
|
+
const { size = "lg", shape = "circle", className } = props;
|
|
226
|
+
const base = clsx4(
|
|
148
227
|
"shrink-0 overflow-hidden",
|
|
149
|
-
sizeStyles2[
|
|
150
|
-
getShapeClass(shape,
|
|
228
|
+
sizeStyles2[size],
|
|
229
|
+
getShapeClass(shape, size),
|
|
151
230
|
className
|
|
152
231
|
);
|
|
153
232
|
if (props.type === "image") {
|
|
@@ -163,16 +242,16 @@ function Avatar(props) {
|
|
|
163
242
|
return /* @__PURE__ */ jsx3(
|
|
164
243
|
"div",
|
|
165
244
|
{
|
|
166
|
-
className:
|
|
245
|
+
className: clsx4(base, "flex items-center justify-center"),
|
|
167
246
|
style: {
|
|
168
247
|
background: "linear-gradient(135deg, var(--color-graphic-blue) 30%, var(--color-graphic-red) 100%)"
|
|
169
248
|
},
|
|
170
249
|
children: /* @__PURE__ */ jsx3(
|
|
171
250
|
"span",
|
|
172
251
|
{
|
|
173
|
-
className:
|
|
252
|
+
className: clsx4(
|
|
174
253
|
"select-none leading-none text-brand-on-brand",
|
|
175
|
-
initialTextStyles[
|
|
254
|
+
initialTextStyles[size]
|
|
176
255
|
),
|
|
177
256
|
children: props.initial.charAt(0).toUpperCase()
|
|
178
257
|
}
|
|
@@ -181,52 +260,6 @@ function Avatar(props) {
|
|
|
181
260
|
);
|
|
182
261
|
}
|
|
183
262
|
|
|
184
|
-
// src/lib/cn.ts
|
|
185
|
-
import { clsx as clsx4 } from "clsx";
|
|
186
|
-
import { extendTailwindMerge } from "tailwind-merge";
|
|
187
|
-
var FONT_SIZES = [
|
|
188
|
-
"body-micro",
|
|
189
|
-
"body-tiny",
|
|
190
|
-
"body-xs",
|
|
191
|
-
"body-sm",
|
|
192
|
-
"body",
|
|
193
|
-
"body-lg",
|
|
194
|
-
"heading-sm",
|
|
195
|
-
"heading",
|
|
196
|
-
"heading-lg",
|
|
197
|
-
"subheading-sm",
|
|
198
|
-
"subheading",
|
|
199
|
-
"subheading-lg",
|
|
200
|
-
"subtitle-sm",
|
|
201
|
-
"subtitle",
|
|
202
|
-
"subtitle-lg",
|
|
203
|
-
"title-sm",
|
|
204
|
-
"title",
|
|
205
|
-
"title-lg",
|
|
206
|
-
"title-hero",
|
|
207
|
-
"scale-01",
|
|
208
|
-
"scale-02",
|
|
209
|
-
"scale-03",
|
|
210
|
-
"scale-04",
|
|
211
|
-
"scale-05",
|
|
212
|
-
"scale-06",
|
|
213
|
-
"scale-07",
|
|
214
|
-
"scale-08",
|
|
215
|
-
"scale-09",
|
|
216
|
-
"scale-10",
|
|
217
|
-
"scale-12"
|
|
218
|
-
];
|
|
219
|
-
var twMerge = extendTailwindMerge({
|
|
220
|
-
extend: {
|
|
221
|
-
classGroups: {
|
|
222
|
-
"font-size": [{ text: [...FONT_SIZES] }]
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
});
|
|
226
|
-
function cn(...inputs) {
|
|
227
|
-
return twMerge(clsx4(inputs));
|
|
228
|
-
}
|
|
229
|
-
|
|
230
263
|
// src/lib/use-controllable-state.ts
|
|
231
264
|
import { useCallback, useRef, useState } from "react";
|
|
232
265
|
function useControllableState({
|
|
@@ -252,197 +285,6 @@ function useControllableState({
|
|
|
252
285
|
return [current, setValue];
|
|
253
286
|
}
|
|
254
287
|
|
|
255
|
-
// src/lib/use-roving-focus.ts
|
|
256
|
-
import { useCallback as useCallback2, useEffect, useRef as useRef2, useState as useState2 } from "react";
|
|
257
|
-
function useRovingFocus({
|
|
258
|
-
orientation = "horizontal",
|
|
259
|
-
loop = true,
|
|
260
|
-
typeahead = false,
|
|
261
|
-
defaultIndex = 0,
|
|
262
|
-
onEscape
|
|
263
|
-
} = {}) {
|
|
264
|
-
const [activeIndex, setActiveIndex] = useState2(defaultIndex);
|
|
265
|
-
const items = useRef2([]);
|
|
266
|
-
const meta = useRef2([]);
|
|
267
|
-
const search = useRef2("");
|
|
268
|
-
const searchTimer = useRef2(null);
|
|
269
|
-
useEffect(
|
|
270
|
-
() => () => {
|
|
271
|
-
if (searchTimer.current) clearTimeout(searchTimer.current);
|
|
272
|
-
},
|
|
273
|
-
[]
|
|
274
|
-
);
|
|
275
|
-
const focusIndex = useCallback2((index) => {
|
|
276
|
-
const node = items.current[index];
|
|
277
|
-
if (!node) return;
|
|
278
|
-
setActiveIndex(index);
|
|
279
|
-
node.focus();
|
|
280
|
-
}, []);
|
|
281
|
-
const move = useCallback2(
|
|
282
|
-
(start, step) => {
|
|
283
|
-
const total = items.current.length;
|
|
284
|
-
if (total === 0) return;
|
|
285
|
-
for (let i = 1; i <= total; i++) {
|
|
286
|
-
let next = start + step * i;
|
|
287
|
-
if (loop) {
|
|
288
|
-
next = (next % total + total) % total;
|
|
289
|
-
} else if (next < 0 || next >= total) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
if (items.current[next] && !meta.current[next]?.disabled) {
|
|
293
|
-
focusIndex(next);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
},
|
|
298
|
-
[loop, focusIndex]
|
|
299
|
-
);
|
|
300
|
-
const moveToEdge = useCallback2(
|
|
301
|
-
(from) => {
|
|
302
|
-
const total = items.current.length;
|
|
303
|
-
if (total === 0) return;
|
|
304
|
-
move(from === "start" ? -1 : total, from === "start" ? 1 : -1);
|
|
305
|
-
},
|
|
306
|
-
[move]
|
|
307
|
-
);
|
|
308
|
-
const runTypeahead = useCallback2(
|
|
309
|
-
(char) => {
|
|
310
|
-
if (searchTimer.current) clearTimeout(searchTimer.current);
|
|
311
|
-
search.current += char.toLowerCase();
|
|
312
|
-
searchTimer.current = setTimeout(() => {
|
|
313
|
-
search.current = "";
|
|
314
|
-
}, 500);
|
|
315
|
-
const total = items.current.length;
|
|
316
|
-
const query = search.current;
|
|
317
|
-
for (let i = 1; i <= total; i++) {
|
|
318
|
-
const index = (activeIndex + i) % total;
|
|
319
|
-
if (meta.current[index]?.disabled) continue;
|
|
320
|
-
const label = meta.current[index]?.label?.toLowerCase();
|
|
321
|
-
if (label?.startsWith(query)) {
|
|
322
|
-
focusIndex(index);
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
},
|
|
327
|
-
[activeIndex, focusIndex]
|
|
328
|
-
);
|
|
329
|
-
const onKeyDown = useCallback2(
|
|
330
|
-
(event) => {
|
|
331
|
-
const { key } = event;
|
|
332
|
-
const vertical = orientation === "vertical" || orientation === "both";
|
|
333
|
-
const horizontal = orientation === "horizontal" || orientation === "both";
|
|
334
|
-
const next = vertical && key === "ArrowDown" || horizontal && key === "ArrowRight";
|
|
335
|
-
const prev = vertical && key === "ArrowUp" || horizontal && key === "ArrowLeft";
|
|
336
|
-
if (next || prev) {
|
|
337
|
-
event.preventDefault();
|
|
338
|
-
move(activeIndex, next ? 1 : -1);
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
if (key === "Home") {
|
|
342
|
-
event.preventDefault();
|
|
343
|
-
moveToEdge("start");
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
if (key === "End") {
|
|
347
|
-
event.preventDefault();
|
|
348
|
-
moveToEdge("end");
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
if (key === "Escape" && onEscape) {
|
|
352
|
-
onEscape();
|
|
353
|
-
return;
|
|
354
|
-
}
|
|
355
|
-
if (typeahead && key.length === 1 && key !== " " && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
356
|
-
event.preventDefault();
|
|
357
|
-
runTypeahead(key);
|
|
358
|
-
}
|
|
359
|
-
},
|
|
360
|
-
[orientation, activeIndex, move, moveToEdge, onEscape, typeahead, runTypeahead]
|
|
361
|
-
);
|
|
362
|
-
const itemProps = useCallback2(
|
|
363
|
-
(index, options = {}) => {
|
|
364
|
-
meta.current[index] = options;
|
|
365
|
-
return {
|
|
366
|
-
ref: (node) => {
|
|
367
|
-
items.current[index] = node;
|
|
368
|
-
},
|
|
369
|
-
// The roving part: exactly one item is in the tab sequence, so Tab enters the
|
|
370
|
-
// composite once and Tab again leaves it.
|
|
371
|
-
tabIndex: index === activeIndex ? 0 : -1,
|
|
372
|
-
onFocus: () => setActiveIndex(index),
|
|
373
|
-
"data-roving-index": index
|
|
374
|
-
};
|
|
375
|
-
},
|
|
376
|
-
[activeIndex]
|
|
377
|
-
);
|
|
378
|
-
return {
|
|
379
|
-
activeIndex,
|
|
380
|
-
setActiveIndex,
|
|
381
|
-
focusIndex,
|
|
382
|
-
moveToEdge,
|
|
383
|
-
itemProps,
|
|
384
|
-
containerProps: { onKeyDown }
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// src/components/overlays/floating.tsx
|
|
389
|
-
import { useRef as useRef3 } from "react";
|
|
390
|
-
import {
|
|
391
|
-
arrow,
|
|
392
|
-
autoUpdate,
|
|
393
|
-
flip,
|
|
394
|
-
offset,
|
|
395
|
-
shift,
|
|
396
|
-
size,
|
|
397
|
-
useFloating
|
|
398
|
-
} from "@floating-ui/react";
|
|
399
|
-
function useFloatingPanel({
|
|
400
|
-
open,
|
|
401
|
-
onOpenChange,
|
|
402
|
-
side = "bottom",
|
|
403
|
-
align = "center",
|
|
404
|
-
sideOffset = 6,
|
|
405
|
-
alignOffset = 0,
|
|
406
|
-
collisionPadding = 8,
|
|
407
|
-
withArrow = false,
|
|
408
|
-
matchAnchorWidth = false
|
|
409
|
-
}) {
|
|
410
|
-
const arrowRef = useRef3(null);
|
|
411
|
-
const placement = align === "center" ? side : `${side}-${align}`;
|
|
412
|
-
const floating = useFloating({
|
|
413
|
-
open,
|
|
414
|
-
onOpenChange,
|
|
415
|
-
placement,
|
|
416
|
-
// Only track while the panel is actually on screen. `autoUpdate` attaches scroll and
|
|
417
|
-
// resize listeners plus a ResizeObserver, so leaving it running on a closed panel
|
|
418
|
-
// would cost every consumer a listener per menu on the page.
|
|
419
|
-
whileElementsMounted: autoUpdate,
|
|
420
|
-
middleware: [
|
|
421
|
-
offset({ mainAxis: sideOffset, crossAxis: alignOffset }),
|
|
422
|
-
// `flip` before `shift`: try the opposite edge first, and only slide along the
|
|
423
|
-
// current one if neither edge fits. The reverse order produces panels that cling to
|
|
424
|
-
// the viewport edge when they had room to simply flip.
|
|
425
|
-
flip({ padding: collisionPadding }),
|
|
426
|
-
shift({ padding: collisionPadding }),
|
|
427
|
-
matchAnchorWidth && size({
|
|
428
|
-
padding: collisionPadding,
|
|
429
|
-
apply({ rects, elements, availableHeight }) {
|
|
430
|
-
elements.floating.style.setProperty(
|
|
431
|
-
"--panel-anchor-width",
|
|
432
|
-
`${rects.reference.width}px`
|
|
433
|
-
);
|
|
434
|
-
elements.floating.style.setProperty(
|
|
435
|
-
"--panel-available-height",
|
|
436
|
-
`${availableHeight}px`
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
}),
|
|
440
|
-
withArrow && arrow({ element: arrowRef, padding: 4 })
|
|
441
|
-
].filter(Boolean)
|
|
442
|
-
});
|
|
443
|
-
return { ...floating, arrowRef };
|
|
444
|
-
}
|
|
445
|
-
|
|
446
288
|
// src/components/overlays/menu-styles.ts
|
|
447
289
|
import clsx6 from "clsx";
|
|
448
290
|
|
|
@@ -474,256 +316,30 @@ var OVERLAY_ITEM_SIZE = {
|
|
|
474
316
|
md: "px-2.5 py-2 text-body-sm",
|
|
475
317
|
sm: "px-2 py-1.5 text-body-tiny"
|
|
476
318
|
};
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
return tone === "danger" ? "text-danger hover:bg-danger-tertiary focus:bg-danger-tertiary" : "text-default hover:bg-default-secondary focus:bg-default-secondary";
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
// src/components/overlays/overlay.ts
|
|
483
|
-
import { useEffect as useEffect3, useRef as useRef5 } from "react";
|
|
484
|
-
import { tabbable } from "tabbable";
|
|
485
|
-
|
|
486
|
-
// src/components/overlays/overlay-stack.ts
|
|
487
|
-
import { useEffect as useEffect2, useRef as useRef4, useState as useState3 } from "react";
|
|
488
|
-
var layers = [];
|
|
489
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
490
|
-
function notify() {
|
|
491
|
-
for (const listener of listeners) listener();
|
|
492
|
-
}
|
|
493
|
-
function topmost() {
|
|
494
|
-
return layers[layers.length - 1]?.id;
|
|
495
|
-
}
|
|
496
|
-
var scrollLocks = 0;
|
|
497
|
-
var restoreBody = null;
|
|
498
|
-
function lockScroll() {
|
|
499
|
-
scrollLocks += 1;
|
|
500
|
-
if (scrollLocks > 1 || typeof document === "undefined") return;
|
|
501
|
-
const { body, documentElement } = document;
|
|
502
|
-
const previousOverflow = body.style.overflow;
|
|
503
|
-
const previousPaddingRight = body.style.paddingRight;
|
|
504
|
-
const scrollbarWidth = window.innerWidth - documentElement.clientWidth;
|
|
505
|
-
if (scrollbarWidth > 0) {
|
|
506
|
-
const current = parseFloat(window.getComputedStyle(body).paddingRight) || 0;
|
|
507
|
-
body.style.paddingRight = `${current + scrollbarWidth}px`;
|
|
508
|
-
}
|
|
509
|
-
body.style.overflow = "hidden";
|
|
510
|
-
restoreBody = () => {
|
|
511
|
-
body.style.overflow = previousOverflow;
|
|
512
|
-
body.style.paddingRight = previousPaddingRight;
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
function unlockScroll() {
|
|
516
|
-
scrollLocks = Math.max(0, scrollLocks - 1);
|
|
517
|
-
if (scrollLocks === 0 && restoreBody) {
|
|
518
|
-
restoreBody();
|
|
519
|
-
restoreBody = null;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
var inerted = /* @__PURE__ */ new Set();
|
|
523
|
-
function applyInert(node) {
|
|
524
|
-
if (typeof document === "undefined" || !node) return;
|
|
525
|
-
let root = node;
|
|
526
|
-
while (root.parentElement && root.parentElement !== document.body) {
|
|
527
|
-
root = root.parentElement;
|
|
528
|
-
}
|
|
529
|
-
for (const child of Array.from(document.body.children)) {
|
|
530
|
-
if (child === root || !(child instanceof HTMLElement)) continue;
|
|
531
|
-
if (child.hasAttribute("inert")) continue;
|
|
532
|
-
child.setAttribute("inert", "");
|
|
533
|
-
inerted.add(child);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
function releaseInert() {
|
|
537
|
-
for (const el of inerted) el.removeAttribute("inert");
|
|
538
|
-
inerted.clear();
|
|
539
|
-
}
|
|
540
|
-
function useOverlayLayer(active, {
|
|
541
|
-
lockScroll: shouldLockScroll = true,
|
|
542
|
-
inertBackground = true,
|
|
543
|
-
panelRef
|
|
544
|
-
} = {}) {
|
|
545
|
-
const id = useRef4();
|
|
546
|
-
if (!id.current) id.current = /* @__PURE__ */ Symbol("overlay-layer");
|
|
547
|
-
const [isTopmost, setIsTopmost] = useState3(false);
|
|
548
|
-
useEffect2(() => {
|
|
549
|
-
if (!active) return;
|
|
550
|
-
const self = id.current;
|
|
551
|
-
layers.push({ id: self });
|
|
552
|
-
const sync = () => setIsTopmost(topmost() === self);
|
|
553
|
-
listeners.add(sync);
|
|
554
|
-
sync();
|
|
555
|
-
notify();
|
|
556
|
-
if (shouldLockScroll) lockScroll();
|
|
557
|
-
return () => {
|
|
558
|
-
const index = layers.findIndex((layer) => layer.id === self);
|
|
559
|
-
if (index !== -1) layers.splice(index, 1);
|
|
560
|
-
listeners.delete(sync);
|
|
561
|
-
notify();
|
|
562
|
-
if (shouldLockScroll) unlockScroll();
|
|
563
|
-
};
|
|
564
|
-
}, [active, shouldLockScroll]);
|
|
565
|
-
useEffect2(() => {
|
|
566
|
-
if (!active || !inertBackground) return;
|
|
567
|
-
if (inerted.size === 0) applyInert(panelRef?.current ?? null);
|
|
568
|
-
return () => {
|
|
569
|
-
if (layers.length <= 1) releaseInert();
|
|
570
|
-
};
|
|
571
|
-
}, [active, inertBackground, panelRef]);
|
|
572
|
-
return { isTopmost };
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// src/components/overlays/overlay.ts
|
|
576
|
-
function useOverlayDismiss({
|
|
577
|
-
onDismiss,
|
|
578
|
-
panelRef,
|
|
579
|
-
active = true,
|
|
580
|
-
closeOnEscape = true,
|
|
581
|
-
closeOnOutsidePress = true,
|
|
582
|
-
trapFocus = true,
|
|
583
|
-
lockScroll: lockScroll2 = true,
|
|
584
|
-
inertBackground = true,
|
|
585
|
-
autoFocus = true,
|
|
586
|
-
initialFocus,
|
|
587
|
-
returnFocus,
|
|
588
|
-
onEscapeKeyDown,
|
|
589
|
-
onInteractOutside
|
|
590
|
-
}) {
|
|
591
|
-
const { isTopmost } = useOverlayLayer(active, {
|
|
592
|
-
lockScroll: lockScroll2,
|
|
593
|
-
inertBackground,
|
|
594
|
-
panelRef
|
|
595
|
-
});
|
|
596
|
-
const handlers = useRef5({ onDismiss, onEscapeKeyDown, onInteractOutside });
|
|
597
|
-
handlers.current = { onDismiss, onEscapeKeyDown, onInteractOutside };
|
|
598
|
-
const isTopmostRef = useRef5(isTopmost);
|
|
599
|
-
isTopmostRef.current = isTopmost;
|
|
600
|
-
useEffect3(() => {
|
|
601
|
-
if (!active || !closeOnEscape) return;
|
|
602
|
-
function onKeyDown(event) {
|
|
603
|
-
if (event.key !== "Escape") return;
|
|
604
|
-
if (!isTopmostRef.current) return;
|
|
605
|
-
handlers.current.onEscapeKeyDown?.(event);
|
|
606
|
-
if (event.defaultPrevented) return;
|
|
607
|
-
handlers.current.onDismiss();
|
|
608
|
-
}
|
|
609
|
-
document.addEventListener("keydown", onKeyDown);
|
|
610
|
-
return () => document.removeEventListener("keydown", onKeyDown);
|
|
611
|
-
}, [active, closeOnEscape]);
|
|
612
|
-
useEffect3(() => {
|
|
613
|
-
if (!active || !closeOnOutsidePress) return;
|
|
614
|
-
function onPointerDown(event) {
|
|
615
|
-
if (!isTopmostRef.current) return;
|
|
616
|
-
const panel = panelRef.current;
|
|
617
|
-
if (!panel || panel.contains(event.target)) return;
|
|
618
|
-
handlers.current.onInteractOutside?.(event);
|
|
619
|
-
if (event.defaultPrevented) return;
|
|
620
|
-
handlers.current.onDismiss();
|
|
621
|
-
}
|
|
622
|
-
document.addEventListener("pointerdown", onPointerDown);
|
|
623
|
-
return () => document.removeEventListener("pointerdown", onPointerDown);
|
|
624
|
-
}, [active, closeOnOutsidePress, panelRef]);
|
|
625
|
-
useEffect3(() => {
|
|
626
|
-
if (!active || !trapFocus) return;
|
|
627
|
-
function onKeyDown(event) {
|
|
628
|
-
if (event.key !== "Tab" || !isTopmostRef.current) return;
|
|
629
|
-
const panel = panelRef.current;
|
|
630
|
-
if (!panel) return;
|
|
631
|
-
const items = tabbable(panel);
|
|
632
|
-
if (items.length === 0) {
|
|
633
|
-
event.preventDefault();
|
|
634
|
-
panel.focus({ preventScroll: true });
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
const first = items[0];
|
|
638
|
-
const last = items[items.length - 1];
|
|
639
|
-
const activeElement = document.activeElement;
|
|
640
|
-
const inside = panel.contains(activeElement);
|
|
641
|
-
if (event.shiftKey && (activeElement === first || !inside)) {
|
|
642
|
-
event.preventDefault();
|
|
643
|
-
last.focus();
|
|
644
|
-
} else if (!event.shiftKey && (activeElement === last || !inside)) {
|
|
645
|
-
event.preventDefault();
|
|
646
|
-
first.focus();
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
function onFocusIn(event) {
|
|
650
|
-
if (!isTopmostRef.current) return;
|
|
651
|
-
const panel = panelRef.current;
|
|
652
|
-
if (!panel) return;
|
|
653
|
-
if (panel.contains(event.target)) return;
|
|
654
|
-
const items = tabbable(panel);
|
|
655
|
-
(items[0] ?? panel).focus({ preventScroll: true });
|
|
656
|
-
}
|
|
657
|
-
document.addEventListener("keydown", onKeyDown);
|
|
658
|
-
document.addEventListener("focusin", onFocusIn);
|
|
659
|
-
return () => {
|
|
660
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
661
|
-
document.removeEventListener("focusin", onFocusIn);
|
|
662
|
-
};
|
|
663
|
-
}, [active, trapFocus, panelRef]);
|
|
664
|
-
useEffect3(() => {
|
|
665
|
-
if (!active) return;
|
|
666
|
-
const previouslyFocused = document.activeElement;
|
|
667
|
-
const panel = panelRef.current;
|
|
668
|
-
let observer = null;
|
|
669
|
-
if (panel && autoFocus) {
|
|
670
|
-
if (!panel.hasAttribute("tabindex")) panel.setAttribute("tabindex", "-1");
|
|
671
|
-
const focusTarget = () => {
|
|
672
|
-
const explicit = initialFocus?.current;
|
|
673
|
-
if (explicit) {
|
|
674
|
-
explicit.focus({ preventScroll: true });
|
|
675
|
-
return true;
|
|
676
|
-
}
|
|
677
|
-
const items = tabbable(panel);
|
|
678
|
-
if (items.length > 0) {
|
|
679
|
-
items[0].focus({ preventScroll: true });
|
|
680
|
-
return true;
|
|
681
|
-
}
|
|
682
|
-
return false;
|
|
683
|
-
};
|
|
684
|
-
if (!focusTarget()) {
|
|
685
|
-
panel.focus({ preventScroll: true });
|
|
686
|
-
observer = new MutationObserver(() => {
|
|
687
|
-
if (focusTarget()) {
|
|
688
|
-
observer?.disconnect();
|
|
689
|
-
observer = null;
|
|
690
|
-
}
|
|
691
|
-
});
|
|
692
|
-
observer.observe(panel, { childList: true, subtree: true });
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
return () => {
|
|
696
|
-
observer?.disconnect();
|
|
697
|
-
const target = returnFocus ? returnFocus.current : previouslyFocused;
|
|
698
|
-
if (target?.isConnected) target.focus({ preventScroll: true });
|
|
699
|
-
};
|
|
700
|
-
}, [active, panelRef, initialFocus, returnFocus, autoFocus]);
|
|
701
|
-
}
|
|
319
|
+
var OVERLAY_HEADING = "px-2.5 py-1.5 text-body-tiny font-semibold uppercase tracking-wide text-default-tertiary";
|
|
320
|
+
var OVERLAY_SEPARATOR = "-mx-1 my-1 h-px bg-divider";
|
|
702
321
|
|
|
703
322
|
// src/components/overlays/portal.tsx
|
|
704
|
-
import {
|
|
323
|
+
import { createContext as createContext2, useContext as useContext2, useEffect, useState as useState2 } from "react";
|
|
705
324
|
import { createPortal } from "react-dom";
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
325
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
326
|
+
var PortalContainerContext = createContext2(null);
|
|
327
|
+
function usePortalContainer() {
|
|
328
|
+
return useContext2(PortalContainerContext);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/lib/compose-event-handlers.ts
|
|
332
|
+
function composeEventHandlers(theirs, ours) {
|
|
333
|
+
return (event) => {
|
|
334
|
+
theirs?.(event);
|
|
335
|
+
if (!event.defaultPrevented) ours(event);
|
|
336
|
+
};
|
|
713
337
|
}
|
|
714
338
|
|
|
715
339
|
// src/components/overlays/tooltip.tsx
|
|
716
|
-
import {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
useCallback as useCallback3,
|
|
720
|
-
useEffect as useEffect5,
|
|
721
|
-
useId,
|
|
722
|
-
useRef as useRef6,
|
|
723
|
-
useState as useState5
|
|
724
|
-
} from "react";
|
|
725
|
-
import clsx7 from "clsx";
|
|
726
|
-
import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
|
|
340
|
+
import { useId } from "react";
|
|
341
|
+
import { Tooltip as TooltipPrimitive } from "radix-ui";
|
|
342
|
+
import { Fragment, jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
727
343
|
function Tooltip({
|
|
728
344
|
children,
|
|
729
345
|
title,
|
|
@@ -731,231 +347,243 @@ function Tooltip({
|
|
|
731
347
|
side = "top",
|
|
732
348
|
align = "center",
|
|
733
349
|
openDelay = 150,
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
defaultOpen = false,
|
|
350
|
+
open,
|
|
351
|
+
defaultOpen,
|
|
737
352
|
onOpenChange,
|
|
738
353
|
association = "describedby",
|
|
739
354
|
className
|
|
740
355
|
}) {
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
const schedule = useCallback3(
|
|
756
|
-
(next, delay) => {
|
|
757
|
-
clearTimer();
|
|
758
|
-
if (delay === 0) {
|
|
759
|
-
setOpen(next);
|
|
760
|
-
return;
|
|
356
|
+
const container = usePortalContainer();
|
|
357
|
+
const labelId = useId();
|
|
358
|
+
const labelled = association === "labelledby";
|
|
359
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
360
|
+
title && /* @__PURE__ */ jsx5("p", { className: "font-semibold", children: title }),
|
|
361
|
+
body && /* @__PURE__ */ jsx5("p", { className: cn(title && "mt-0.5 opacity-80"), children: body })
|
|
362
|
+
] });
|
|
363
|
+
return /* @__PURE__ */ jsx5(TooltipPrimitive.Provider, { delayDuration: openDelay, children: /* @__PURE__ */ jsxs(TooltipPrimitive.Root, { open, defaultOpen, onOpenChange, children: [
|
|
364
|
+
/* @__PURE__ */ jsx5(
|
|
365
|
+
TooltipPrimitive.Trigger,
|
|
366
|
+
{
|
|
367
|
+
asChild: true,
|
|
368
|
+
...labelled ? { "aria-labelledby": labelId, "aria-describedby": void 0 } : {},
|
|
369
|
+
children
|
|
761
370
|
}
|
|
762
|
-
timer.current = setTimeout(() => setOpen(next), delay);
|
|
763
|
-
},
|
|
764
|
-
[clearTimer, setOpen]
|
|
765
|
-
);
|
|
766
|
-
useEffect5(() => clearTimer, [clearTimer]);
|
|
767
|
-
const { refs, floatingStyles } = useFloatingPanel({
|
|
768
|
-
open,
|
|
769
|
-
onOpenChange: setOpen,
|
|
770
|
-
side,
|
|
771
|
-
align,
|
|
772
|
-
sideOffset: 6
|
|
773
|
-
});
|
|
774
|
-
useEffect5(() => {
|
|
775
|
-
refs.setReference(triggerNode);
|
|
776
|
-
}, [refs, triggerNode]);
|
|
777
|
-
useEffect5(() => {
|
|
778
|
-
if (!open) return;
|
|
779
|
-
function onKeyDown(event) {
|
|
780
|
-
if (event.key === "Escape") setOpen(false);
|
|
781
|
-
}
|
|
782
|
-
document.addEventListener("keydown", onKeyDown);
|
|
783
|
-
return () => document.removeEventListener("keydown", onKeyDown);
|
|
784
|
-
}, [open, setOpen]);
|
|
785
|
-
if (!isValidElement2(children)) return null;
|
|
786
|
-
const child = children;
|
|
787
|
-
const childProps = child.props;
|
|
788
|
-
const describedBy = association === "describedby" ? tooltipId : void 0;
|
|
789
|
-
const labelledBy = association === "labelledby" ? tooltipId : void 0;
|
|
790
|
-
const trigger = cloneElement2(child, {
|
|
791
|
-
ref: composeRefs(
|
|
792
|
-
(node) => setTriggerNode(node),
|
|
793
|
-
child.ref
|
|
794
371
|
),
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
childProps.onPointerLeave?.(event);
|
|
803
|
-
schedule(false, closeDelay);
|
|
804
|
-
},
|
|
805
|
-
// Focus, not just hover — this is the difference between a tooltip a keyboard user can
|
|
806
|
-
// read and one they cannot.
|
|
807
|
-
onFocus: (event) => {
|
|
808
|
-
childProps.onFocus?.(event);
|
|
809
|
-
schedule(true, 0);
|
|
810
|
-
},
|
|
811
|
-
onBlur: (event) => {
|
|
812
|
-
childProps.onBlur?.(event);
|
|
813
|
-
schedule(false, 0);
|
|
814
|
-
}
|
|
815
|
-
});
|
|
816
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
817
|
-
trigger,
|
|
818
|
-
(open || association === "labelledby") && /* @__PURE__ */ jsx4(Portal, { children: /* @__PURE__ */ jsxs(
|
|
819
|
-
"div",
|
|
372
|
+
labelled && /* @__PURE__ */ jsxs("span", { id: labelId, hidden: true, children: [
|
|
373
|
+
title,
|
|
374
|
+
body ? " " : null,
|
|
375
|
+
body
|
|
376
|
+
] }),
|
|
377
|
+
/* @__PURE__ */ jsx5(TooltipPrimitive.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx5(
|
|
378
|
+
TooltipPrimitive.Content,
|
|
820
379
|
{
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
className:
|
|
380
|
+
side,
|
|
381
|
+
align,
|
|
382
|
+
sideOffset: 6,
|
|
383
|
+
collisionPadding: 8,
|
|
384
|
+
className: cn(
|
|
826
385
|
"z-tooltip max-w-[260px] rounded-lg bg-neutral px-3 py-2 shadow-300",
|
|
827
386
|
"text-body-xs text-neutral-on-neutral",
|
|
828
|
-
!open && "sr-only",
|
|
829
387
|
className
|
|
830
388
|
),
|
|
831
|
-
children:
|
|
832
|
-
title && /* @__PURE__ */ jsx4("p", { className: "font-semibold", children: title }),
|
|
833
|
-
body && /* @__PURE__ */ jsx4("p", { className: clsx7(title && "mt-0.5 opacity-80"), children: body })
|
|
834
|
-
]
|
|
389
|
+
children: content
|
|
835
390
|
}
|
|
836
391
|
) })
|
|
837
|
-
] });
|
|
392
|
+
] }) });
|
|
838
393
|
}
|
|
839
394
|
|
|
840
395
|
// src/components/overlays/menu-core.tsx
|
|
841
396
|
import {
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
useContext as useContext2,
|
|
845
|
-
useId as useId2,
|
|
846
|
-
useMemo,
|
|
847
|
-
useRef as useRef7
|
|
397
|
+
forwardRef as forwardRef3,
|
|
398
|
+
useId as useId2
|
|
848
399
|
} from "react";
|
|
849
|
-
import
|
|
850
|
-
import {
|
|
851
|
-
import { jsx as
|
|
852
|
-
var
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
400
|
+
import clsx7 from "clsx";
|
|
401
|
+
import { CheckIcon, ChevronRightIcon } from "lucide-react";
|
|
402
|
+
import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
403
|
+
var MENU_PANEL_CLASSES = cn("z-popover", OVERLAY_PANEL_MENU, "focus:outline-none");
|
|
404
|
+
var ITEM_BASE = clsx7(
|
|
405
|
+
OVERLAY_ITEM_BASE,
|
|
406
|
+
OVERLAY_ITEM_SIZE.md,
|
|
407
|
+
// Highlight follows Radix's `data-highlighted`, which tracks pointer and keyboard alike.
|
|
408
|
+
// The ring marks the keyboard position on top of it: the tint alone, shared with hover,
|
|
409
|
+
// cannot tell a keyboard user which of two tinted items has focus.
|
|
410
|
+
FOCUS_RING_INSET,
|
|
411
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:text-disabled"
|
|
412
|
+
);
|
|
413
|
+
var ITEM_TONE = {
|
|
414
|
+
default: "text-default data-[highlighted]:bg-default-secondary",
|
|
415
|
+
danger: "text-danger data-[highlighted]:bg-danger-tertiary"
|
|
416
|
+
};
|
|
417
|
+
function stopToAncestors(event) {
|
|
418
|
+
event.stopPropagation();
|
|
859
419
|
}
|
|
860
|
-
function
|
|
861
|
-
|
|
862
|
-
const
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
typeahead: true,
|
|
868
|
-
onEscape: () => setOpen(false)
|
|
420
|
+
function focusMenuEdge(event, edge) {
|
|
421
|
+
if (event.target !== event.currentTarget) return;
|
|
422
|
+
const panel = event.currentTarget;
|
|
423
|
+
queueMicrotask(() => {
|
|
424
|
+
const items = panel.querySelectorAll('[role^="menuitem"]:not([data-disabled])');
|
|
425
|
+
if (edge === "end") items[items.length - 1]?.focus();
|
|
426
|
+
else if (document.activeElement === panel) items[0]?.focus();
|
|
869
427
|
});
|
|
870
|
-
const claimIndex = useCallback4(() => cursor.current++, []);
|
|
871
|
-
const resetIndices = useCallback4(() => {
|
|
872
|
-
cursor.current = 0;
|
|
873
|
-
}, []);
|
|
874
|
-
return useMemo(
|
|
875
|
-
() => ({
|
|
876
|
-
open,
|
|
877
|
-
setOpen,
|
|
878
|
-
menuId: `${baseId}-menu`,
|
|
879
|
-
triggerId: `${baseId}-trigger`,
|
|
880
|
-
claimIndex,
|
|
881
|
-
resetIndices,
|
|
882
|
-
pendingEdge,
|
|
883
|
-
roving
|
|
884
|
-
}),
|
|
885
|
-
[open, setOpen, baseId, claimIndex, resetIndices, roving]
|
|
886
|
-
);
|
|
887
428
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
429
|
+
function createMenuParts(P) {
|
|
430
|
+
const Item = forwardRef3(function MenuItem({ children, onSelect, tone = "default", disabled = false, icon, description, shortcut, textValue, className, ...rest }, ref) {
|
|
431
|
+
const descriptionId = useId2();
|
|
432
|
+
return /* @__PURE__ */ jsxs2(
|
|
433
|
+
P.Item,
|
|
434
|
+
{
|
|
435
|
+
ref,
|
|
436
|
+
disabled,
|
|
437
|
+
textValue,
|
|
438
|
+
onSelect,
|
|
439
|
+
"data-tone": tone,
|
|
440
|
+
"aria-describedby": description ? descriptionId : void 0,
|
|
441
|
+
className: cn(ITEM_BASE, ITEM_TONE[tone], className),
|
|
442
|
+
...rest,
|
|
443
|
+
children: [
|
|
444
|
+
icon && /* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "mt-0.5 flex size-4 shrink-0 items-center justify-center", children: icon }),
|
|
445
|
+
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
446
|
+
/* @__PURE__ */ jsx6("span", { className: "block truncate", children }),
|
|
447
|
+
description && /* @__PURE__ */ jsx6("span", { id: descriptionId, className: "mt-0.5 block text-body-tiny text-default-secondary", children: description })
|
|
448
|
+
] }),
|
|
449
|
+
shortcut && /* @__PURE__ */ jsx6("span", { className: "ml-auto shrink-0 pl-4 text-body-tiny text-default-tertiary", children: shortcut })
|
|
450
|
+
]
|
|
451
|
+
}
|
|
452
|
+
);
|
|
453
|
+
});
|
|
454
|
+
const CheckboxItem = forwardRef3(function MenuCheckboxItem({ children, checked, onCheckedChange, disabled = false, tone = "default", shortcut, textValue, className, ...rest }, ref) {
|
|
455
|
+
return /* @__PURE__ */ jsxs2(
|
|
456
|
+
P.CheckboxItem,
|
|
457
|
+
{
|
|
458
|
+
ref,
|
|
459
|
+
checked,
|
|
460
|
+
onCheckedChange: (next) => onCheckedChange?.(next === true),
|
|
461
|
+
onSelect: (event) => event.preventDefault(),
|
|
462
|
+
disabled,
|
|
463
|
+
textValue,
|
|
464
|
+
"data-tone": tone,
|
|
465
|
+
className: cn(ITEM_BASE, "items-center", ITEM_TONE[tone], className),
|
|
466
|
+
...rest,
|
|
467
|
+
children: [
|
|
468
|
+
/* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "flex size-4 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx6(P.ItemIndicator, { children: /* @__PURE__ */ jsx6(CheckIcon, { className: "size-3.5", strokeWidth: 3 }) }) }),
|
|
469
|
+
/* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", children }),
|
|
470
|
+
shortcut && /* @__PURE__ */ jsx6("span", { className: "ml-auto shrink-0 pl-4 text-body-tiny text-default-tertiary", children: shortcut })
|
|
471
|
+
]
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
});
|
|
475
|
+
function RadioGroup({ children, value, onValueChange }) {
|
|
476
|
+
return /* @__PURE__ */ jsx6(P.RadioGroup, { value, onValueChange, children });
|
|
477
|
+
}
|
|
478
|
+
const RadioItem = forwardRef3(function MenuRadioItem({ children, value, disabled = false, tone = "default", textValue, className, ...rest }, ref) {
|
|
479
|
+
return /* @__PURE__ */ jsxs2(
|
|
480
|
+
P.RadioItem,
|
|
481
|
+
{
|
|
482
|
+
ref,
|
|
483
|
+
value,
|
|
484
|
+
disabled,
|
|
485
|
+
textValue,
|
|
486
|
+
"data-tone": tone,
|
|
487
|
+
className: cn(ITEM_BASE, "items-center", ITEM_TONE[tone], className),
|
|
488
|
+
...rest,
|
|
489
|
+
children: [
|
|
490
|
+
/* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "flex size-4 shrink-0 items-center justify-center", children: /* @__PURE__ */ jsx6(P.ItemIndicator, { children: /* @__PURE__ */ jsx6("span", { className: "block size-1.5 rounded-full bg-current" }) }) }),
|
|
491
|
+
/* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", children })
|
|
492
|
+
]
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
});
|
|
496
|
+
const Group = forwardRef3(function MenuGroup({ children, label, className, ...rest }, ref) {
|
|
497
|
+
const labelId = useId2();
|
|
498
|
+
return /* @__PURE__ */ jsxs2(P.Group, { ref, "aria-labelledby": label ? labelId : void 0, className, ...rest, children: [
|
|
499
|
+
label && /* @__PURE__ */ jsx6("div", { id: labelId, className: OVERLAY_HEADING, children: label }),
|
|
500
|
+
children
|
|
501
|
+
] });
|
|
502
|
+
});
|
|
503
|
+
const Label = forwardRef3(function MenuLabel({ className, ...rest }, ref) {
|
|
504
|
+
return /* @__PURE__ */ jsx6(P.Label, { ref, className: cn(OVERLAY_HEADING, className), ...rest });
|
|
505
|
+
});
|
|
506
|
+
const Separator = forwardRef3(function MenuSeparator({ className, ...rest }, ref) {
|
|
507
|
+
return /* @__PURE__ */ jsx6(P.Separator, { ref, className: cn(OVERLAY_SEPARATOR, className), ...rest });
|
|
508
|
+
});
|
|
509
|
+
const Shortcut = forwardRef3(function MenuShortcut({ className, ...rest }, ref) {
|
|
510
|
+
return /* @__PURE__ */ jsx6("span", { ref, className: cn("ml-auto pl-4 text-body-tiny text-default-tertiary", className), ...rest });
|
|
511
|
+
});
|
|
512
|
+
function Sub({ children, open, defaultOpen, onOpenChange }) {
|
|
513
|
+
return /* @__PURE__ */ jsx6(P.Sub, { open, defaultOpen, onOpenChange, children });
|
|
514
|
+
}
|
|
515
|
+
const SubTrigger = forwardRef3(function MenuSubTrigger({ children, icon, disabled = false, textValue, className, ...rest }, ref) {
|
|
516
|
+
return /* @__PURE__ */ jsxs2(
|
|
517
|
+
P.SubTrigger,
|
|
518
|
+
{
|
|
519
|
+
ref,
|
|
520
|
+
disabled,
|
|
521
|
+
textValue,
|
|
522
|
+
className: cn(
|
|
523
|
+
ITEM_BASE,
|
|
524
|
+
"items-center",
|
|
525
|
+
ITEM_TONE.default,
|
|
526
|
+
"data-[state=open]:bg-default-secondary",
|
|
527
|
+
className
|
|
528
|
+
),
|
|
529
|
+
...rest,
|
|
530
|
+
children: [
|
|
531
|
+
icon && /* @__PURE__ */ jsx6("span", { "aria-hidden": true, className: "flex size-4 shrink-0 items-center justify-center", children: icon }),
|
|
532
|
+
/* @__PURE__ */ jsx6("span", { className: "min-w-0 flex-1 truncate", children }),
|
|
533
|
+
/* @__PURE__ */ jsx6(ChevronRightIcon, { "aria-hidden": true, className: "ml-auto size-4 shrink-0 text-default-tertiary" })
|
|
534
|
+
]
|
|
535
|
+
}
|
|
536
|
+
);
|
|
537
|
+
});
|
|
538
|
+
const SubContent = forwardRef3(function MenuSubContent({ className, onClick, onKeyDown, ...rest }, ref) {
|
|
539
|
+
const container = usePortalContainer();
|
|
540
|
+
return /* @__PURE__ */ jsx6(P.Portal, { container: container ?? void 0, children: /* @__PURE__ */ jsx6(
|
|
541
|
+
P.SubContent,
|
|
542
|
+
{
|
|
543
|
+
ref,
|
|
544
|
+
sideOffset: 4,
|
|
545
|
+
collisionPadding: 8,
|
|
546
|
+
className: cn(MENU_PANEL_CLASSES, className),
|
|
547
|
+
onClick: (event) => {
|
|
548
|
+
onClick?.(event);
|
|
549
|
+
stopToAncestors(event);
|
|
550
|
+
},
|
|
551
|
+
onKeyDown: (event) => {
|
|
552
|
+
onKeyDown?.(event);
|
|
553
|
+
stopToAncestors(event);
|
|
554
|
+
},
|
|
555
|
+
...rest
|
|
556
|
+
}
|
|
557
|
+
) });
|
|
558
|
+
});
|
|
559
|
+
return {
|
|
560
|
+
Item,
|
|
561
|
+
CheckboxItem,
|
|
562
|
+
RadioGroup,
|
|
563
|
+
RadioItem,
|
|
564
|
+
Group,
|
|
565
|
+
Label,
|
|
566
|
+
Separator,
|
|
567
|
+
Shortcut,
|
|
568
|
+
Sub,
|
|
569
|
+
SubTrigger,
|
|
570
|
+
SubContent
|
|
912
571
|
};
|
|
913
|
-
return /* @__PURE__ */ jsxs2(
|
|
914
|
-
"div",
|
|
915
|
-
{
|
|
916
|
-
role: "menuitem",
|
|
917
|
-
"aria-disabled": disabled || void 0,
|
|
918
|
-
"aria-describedby": description ? descriptionId : void 0,
|
|
919
|
-
...itemProps,
|
|
920
|
-
tabIndex: itemProps.tabIndex,
|
|
921
|
-
className: clsx8(ITEM_BASE, itemToneClasses(tone, disabled), className),
|
|
922
|
-
onClick: (event) => {
|
|
923
|
-
event.stopPropagation();
|
|
924
|
-
activate();
|
|
925
|
-
},
|
|
926
|
-
onKeyDown: (event) => {
|
|
927
|
-
if (event.key === "Enter" || event.key === " ") {
|
|
928
|
-
event.preventDefault();
|
|
929
|
-
activate();
|
|
930
|
-
}
|
|
931
|
-
},
|
|
932
|
-
...rest,
|
|
933
|
-
children: [
|
|
934
|
-
icon && /* @__PURE__ */ jsx5("span", { "aria-hidden": true, className: "mt-0.5 flex size-4 shrink-0 items-center justify-center", children: icon }),
|
|
935
|
-
/* @__PURE__ */ jsxs2("span", { className: "min-w-0 flex-1", children: [
|
|
936
|
-
/* @__PURE__ */ jsx5("span", { className: "block truncate", children }),
|
|
937
|
-
description && /* @__PURE__ */ jsx5("span", { id: descriptionId, className: "mt-0.5 block text-body-tiny text-default-secondary", children: description })
|
|
938
|
-
] }),
|
|
939
|
-
shortcut && /* @__PURE__ */ jsx5("span", { className: "ml-auto shrink-0 pl-4 text-body-tiny text-default-tertiary", children: shortcut })
|
|
940
|
-
]
|
|
941
|
-
}
|
|
942
|
-
);
|
|
943
572
|
}
|
|
944
|
-
var MenuRadioContext = createContext2(null);
|
|
945
573
|
|
|
946
574
|
// src/components/cards/scroll-area.tsx
|
|
947
|
-
import { forwardRef as
|
|
948
|
-
import
|
|
949
|
-
import { jsx as
|
|
575
|
+
import { forwardRef as forwardRef4, useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
576
|
+
import clsx8 from "clsx";
|
|
577
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
950
578
|
var OVERFLOW = {
|
|
951
579
|
vertical: "overflow-y-auto overflow-x-hidden",
|
|
952
580
|
horizontal: "overflow-x-auto overflow-y-hidden",
|
|
953
581
|
both: "overflow-auto"
|
|
954
582
|
};
|
|
955
|
-
var ScrollArea =
|
|
956
|
-
const localRef =
|
|
957
|
-
const [overflows, setOverflows] =
|
|
958
|
-
|
|
583
|
+
var ScrollArea = forwardRef4(function ScrollArea2({ children, axis = "vertical", label, className, ...rest }, ref) {
|
|
584
|
+
const localRef = useRef2(null);
|
|
585
|
+
const [overflows, setOverflows] = useState3(false);
|
|
586
|
+
useEffect2(() => {
|
|
959
587
|
const node = localRef.current;
|
|
960
588
|
if (!node) return;
|
|
961
589
|
const measure = () => {
|
|
@@ -972,7 +600,7 @@ var ScrollArea = forwardRef3(function ScrollArea2({ children, axis = "vertical",
|
|
|
972
600
|
if (node.firstElementChild) observer.observe(node.firstElementChild);
|
|
973
601
|
return () => observer.disconnect();
|
|
974
602
|
}, [axis, children]);
|
|
975
|
-
return /* @__PURE__ */
|
|
603
|
+
return /* @__PURE__ */ jsx7(
|
|
976
604
|
"div",
|
|
977
605
|
{
|
|
978
606
|
ref: composeRefs(localRef, ref),
|
|
@@ -980,7 +608,7 @@ var ScrollArea = forwardRef3(function ScrollArea2({ children, axis = "vertical",
|
|
|
980
608
|
"aria-label": overflows ? label : void 0,
|
|
981
609
|
tabIndex: overflows ? 0 : void 0,
|
|
982
610
|
"data-slot": "scroll-area",
|
|
983
|
-
className:
|
|
611
|
+
className: clsx8(
|
|
984
612
|
OVERFLOW[axis],
|
|
985
613
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1 focus-visible:ring-offset-default",
|
|
986
614
|
SCROLLBAR_CLASSES,
|
|
@@ -995,156 +623,134 @@ var ScrollArea = forwardRef3(function ScrollArea2({ children, axis = "vertical",
|
|
|
995
623
|
// src/components/overlays/dropdown-menu.tsx
|
|
996
624
|
import {
|
|
997
625
|
createContext as createContext3,
|
|
626
|
+
forwardRef as forwardRef5,
|
|
998
627
|
useContext as useContext3,
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
useRef as useRef9,
|
|
1002
|
-
useState as useState7
|
|
628
|
+
useMemo,
|
|
629
|
+
useRef as useRef3
|
|
1003
630
|
} from "react";
|
|
1004
|
-
import
|
|
1005
|
-
import {
|
|
1006
|
-
import { jsx as
|
|
1007
|
-
var
|
|
1008
|
-
function
|
|
1009
|
-
const value = useContext3(
|
|
1010
|
-
if (!value) throw new Error(
|
|
631
|
+
import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
|
|
632
|
+
import { EllipsisIcon } from "lucide-react";
|
|
633
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
634
|
+
var DropdownMenuStateContext = createContext3(null);
|
|
635
|
+
function useDropdownMenuState(part) {
|
|
636
|
+
const value = useContext3(DropdownMenuStateContext);
|
|
637
|
+
if (!value) throw new Error(`<${part}> must be used inside <DropdownMenu>`);
|
|
1011
638
|
return value;
|
|
1012
639
|
}
|
|
1013
640
|
function DropdownMenu({
|
|
1014
641
|
children,
|
|
1015
642
|
open: openProp,
|
|
1016
643
|
defaultOpen = false,
|
|
1017
|
-
onOpenChange
|
|
644
|
+
onOpenChange,
|
|
645
|
+
modal = false
|
|
1018
646
|
}) {
|
|
1019
647
|
const [open, setOpen] = useControllableState({
|
|
1020
648
|
value: openProp,
|
|
1021
649
|
defaultValue: defaultOpen,
|
|
1022
650
|
onChange: onOpenChange
|
|
1023
651
|
});
|
|
1024
|
-
const
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1027
|
-
return /* @__PURE__ */ jsx7(MenuContext.Provider, { value: menu, children: /* @__PURE__ */ jsx7(TriggerNodeContext.Provider, { value: anchor, children }) });
|
|
652
|
+
const pendingEdge = useRef3("start");
|
|
653
|
+
const state = useMemo(() => ({ setOpen, pendingEdge }), [setOpen]);
|
|
654
|
+
return /* @__PURE__ */ jsx8(DropdownMenuPrimitive.Root, { open, onOpenChange: setOpen, modal, children: /* @__PURE__ */ jsx8(DropdownMenuStateContext.Provider, { value: state, children }) });
|
|
1028
655
|
}
|
|
1029
|
-
|
|
1030
|
-
children,
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
event.
|
|
1049
|
-
|
|
1050
|
-
|
|
656
|
+
var DropdownMenuTrigger = forwardRef5(
|
|
657
|
+
function DropdownMenuTrigger2({ children, asChild = false, label = "Open menu", onClick, onPointerDown, onMouseDown, onKeyDown, ...rest }, ref) {
|
|
658
|
+
const state = useDropdownMenuState("DropdownMenuTrigger");
|
|
659
|
+
const handlers = {
|
|
660
|
+
onClick: (event) => {
|
|
661
|
+
onClick?.(event);
|
|
662
|
+
stopToAncestors(event);
|
|
663
|
+
},
|
|
664
|
+
onPointerDown: (event) => {
|
|
665
|
+
onPointerDown?.(event);
|
|
666
|
+
event.stopPropagation();
|
|
667
|
+
},
|
|
668
|
+
onMouseDown: (event) => {
|
|
669
|
+
onMouseDown?.(event);
|
|
670
|
+
stopToAncestors(event);
|
|
671
|
+
},
|
|
672
|
+
onKeyDown: (event) => {
|
|
673
|
+
onKeyDown?.(event);
|
|
674
|
+
if (event.defaultPrevented) return;
|
|
675
|
+
if (event.key === "ArrowUp") {
|
|
676
|
+
event.preventDefault();
|
|
677
|
+
state.pendingEdge.current = "end";
|
|
678
|
+
state.setOpen(true);
|
|
679
|
+
}
|
|
680
|
+
if (event.key === "Enter" || event.key === " ") stopToAncestors(event);
|
|
1051
681
|
}
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
682
|
+
};
|
|
683
|
+
if (asChild) {
|
|
684
|
+
return /* @__PURE__ */ jsx8(DropdownMenuPrimitive.Trigger, { ref, asChild: true, ...rest, ...handlers, children });
|
|
685
|
+
}
|
|
686
|
+
return /* @__PURE__ */ jsx8(DropdownMenuPrimitive.Trigger, { ref, asChild: true, ...rest, ...handlers, children: /* @__PURE__ */ jsx8(IconButton, { variant: "neutral", size: "sm", "aria-label": label, children: children ?? /* @__PURE__ */ jsx8(EllipsisIcon, { className: "size-4", "aria-hidden": true }) }) });
|
|
687
|
+
}
|
|
688
|
+
);
|
|
689
|
+
var DropdownMenuContent = forwardRef5(
|
|
690
|
+
function DropdownMenuContent2({
|
|
691
|
+
children,
|
|
692
|
+
side = "bottom",
|
|
693
|
+
align = "end",
|
|
694
|
+
sideOffset = 6,
|
|
695
|
+
container,
|
|
696
|
+
className,
|
|
697
|
+
onClick,
|
|
698
|
+
onKeyDown,
|
|
699
|
+
onFocus,
|
|
700
|
+
onCloseAutoFocus,
|
|
1056
701
|
...rest
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
|
|
702
|
+
}, ref) {
|
|
703
|
+
const state = useDropdownMenuState("DropdownMenuContent");
|
|
704
|
+
const inherited = usePortalContainer();
|
|
705
|
+
return /* @__PURE__ */ jsx8(DropdownMenuPrimitive.Portal, { container: container ?? inherited ?? void 0, children: /* @__PURE__ */ jsx8(
|
|
706
|
+
DropdownMenuPrimitive.Content,
|
|
707
|
+
{
|
|
708
|
+
ref,
|
|
709
|
+
side,
|
|
710
|
+
align,
|
|
711
|
+
sideOffset,
|
|
712
|
+
collisionPadding: 8,
|
|
713
|
+
loop: true,
|
|
714
|
+
className: cn(MENU_PANEL_CLASSES, className),
|
|
715
|
+
onCloseAutoFocus: composeEventHandlers(onCloseAutoFocus, () => {
|
|
716
|
+
state.pendingEdge.current = "start";
|
|
717
|
+
}),
|
|
718
|
+
onFocus: composeEventHandlers(onFocus, (event) => {
|
|
719
|
+
const edge = state.pendingEdge.current;
|
|
720
|
+
state.pendingEdge.current = "start";
|
|
721
|
+
focusMenuEdge(event, edge);
|
|
722
|
+
}),
|
|
723
|
+
onClick: (event) => {
|
|
724
|
+
onClick?.(event);
|
|
725
|
+
stopToAncestors(event);
|
|
726
|
+
},
|
|
727
|
+
onKeyDown: (event) => {
|
|
728
|
+
onKeyDown?.(event);
|
|
729
|
+
stopToAncestors(event);
|
|
730
|
+
if (event.key === "Tab") state.setOpen(false);
|
|
731
|
+
},
|
|
732
|
+
...rest,
|
|
733
|
+
children
|
|
734
|
+
}
|
|
735
|
+
) });
|
|
1060
736
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
children,
|
|
1075
|
-
side = "bottom",
|
|
1076
|
-
align = "end",
|
|
1077
|
-
sideOffset = 6,
|
|
1078
|
-
className,
|
|
1079
|
-
...rest
|
|
1080
|
-
}) {
|
|
1081
|
-
const menu = useMenu("DropdownMenuContent");
|
|
1082
|
-
const anchor = useTriggerNode();
|
|
1083
|
-
const panelRef = useRef9(null);
|
|
1084
|
-
const [panelNode, setPanelNode] = useState7(null);
|
|
1085
|
-
menu.resetIndices();
|
|
1086
|
-
const { refs, floatingStyles } = useFloatingPanel({
|
|
1087
|
-
open: menu.open,
|
|
1088
|
-
onOpenChange: menu.setOpen,
|
|
1089
|
-
side,
|
|
1090
|
-
align,
|
|
1091
|
-
sideOffset
|
|
1092
|
-
});
|
|
1093
|
-
useEffect7(() => {
|
|
1094
|
-
refs.setReference(anchor.triggerNode);
|
|
1095
|
-
}, [refs, anchor.triggerNode]);
|
|
1096
|
-
useOverlayDismiss({
|
|
1097
|
-
onDismiss: () => menu.setOpen(false),
|
|
1098
|
-
panelRef,
|
|
1099
|
-
active: menu.open,
|
|
1100
|
-
// A menu is not modal: the page behind stays readable and interactive, so none of the
|
|
1101
|
-
// dialog-grade side effects apply. Only Escape, outside-press and focus restore.
|
|
1102
|
-
trapFocus: false,
|
|
1103
|
-
lockScroll: false,
|
|
1104
|
-
inertBackground: false,
|
|
1105
|
-
// The menu owns its own initial focus below; a generic "first tabbable element" scan
|
|
1106
|
-
// would fight the roving tabindex, which exposes exactly one item at a time.
|
|
1107
|
-
autoFocus: false
|
|
1108
|
-
});
|
|
1109
|
-
const wasOpen = useRef9(false);
|
|
1110
|
-
useEffect7(() => {
|
|
1111
|
-
if (menu.open && panelNode && !wasOpen.current) {
|
|
1112
|
-
menu.roving.moveToEdge(menu.pendingEdge.current);
|
|
1113
|
-
menu.pendingEdge.current = "start";
|
|
1114
|
-
wasOpen.current = true;
|
|
1115
|
-
}
|
|
1116
|
-
if (!menu.open) wasOpen.current = false;
|
|
1117
|
-
}, [menu.open, panelNode, menu.roving, menu.pendingEdge]);
|
|
1118
|
-
if (!menu.open) return null;
|
|
1119
|
-
return /* @__PURE__ */ jsx7(Portal, { children: /* @__PURE__ */ jsx7(
|
|
1120
|
-
"div",
|
|
1121
|
-
{
|
|
1122
|
-
ref: composeRefs(
|
|
1123
|
-
panelRef,
|
|
1124
|
-
(node) => setPanelNode(node),
|
|
1125
|
-
refs.setFloating
|
|
1126
|
-
),
|
|
1127
|
-
id: menu.menuId,
|
|
1128
|
-
role: "menu",
|
|
1129
|
-
tabIndex: -1,
|
|
1130
|
-
"aria-orientation": "vertical",
|
|
1131
|
-
"aria-labelledby": menu.triggerId,
|
|
1132
|
-
style: floatingStyles,
|
|
1133
|
-
className: clsx10("z-popover", MENU_PANEL_CLASSES, className),
|
|
1134
|
-
...menu.roving.containerProps,
|
|
1135
|
-
onKeyDown: (event) => {
|
|
1136
|
-
menu.roving.containerProps.onKeyDown(event);
|
|
1137
|
-
if (event.key === "Tab") menu.setOpen(false);
|
|
1138
|
-
},
|
|
1139
|
-
...rest,
|
|
1140
|
-
children
|
|
1141
|
-
}
|
|
1142
|
-
) });
|
|
1143
|
-
}
|
|
737
|
+
);
|
|
738
|
+
var parts = createMenuParts(DropdownMenuPrimitive);
|
|
739
|
+
var DropdownMenuItem = parts.Item;
|
|
740
|
+
var DropdownMenuCheckboxItem = parts.CheckboxItem;
|
|
741
|
+
var DropdownMenuRadioGroup = parts.RadioGroup;
|
|
742
|
+
var DropdownMenuRadioItem = parts.RadioItem;
|
|
743
|
+
var DropdownMenuGroup = parts.Group;
|
|
744
|
+
var DropdownMenuLabel = parts.Label;
|
|
745
|
+
var DropdownMenuSeparator = parts.Separator;
|
|
746
|
+
var DropdownMenuShortcut = parts.Shortcut;
|
|
747
|
+
var DropdownMenuSub = parts.Sub;
|
|
748
|
+
var DropdownMenuSubTrigger = parts.SubTrigger;
|
|
749
|
+
var DropdownMenuSubContent = parts.SubContent;
|
|
1144
750
|
|
|
1145
751
|
// src/components/chrome/nav-item.tsx
|
|
1146
|
-
import
|
|
1147
|
-
import { Fragment as Fragment2, jsx as
|
|
752
|
+
import clsx9 from "clsx";
|
|
753
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1148
754
|
var SIZE = {
|
|
1149
755
|
sm: { box: "h-9 gap-2 rounded-lg px-3 py-1.5", label: "text-body-xs", square: "w-9" },
|
|
1150
756
|
md: { box: "h-11 gap-3 rounded-xl px-3.5 py-2.5", label: "text-body-sm", square: "w-11" }
|
|
@@ -1171,12 +777,12 @@ var VARIANT = {
|
|
|
1171
777
|
// `border-transparent` holds the 1px so the icon and label do not shift outward when a
|
|
1172
778
|
// row becomes the current one — the same trick, for the same reason, as `button.tsx`.
|
|
1173
779
|
// `bg-brand` still paints edge to edge, since backgrounds clip to the border box.
|
|
1174
|
-
active:
|
|
1175
|
-
inactive:
|
|
780
|
+
active: clsx9("border border-transparent", STATE.active),
|
|
781
|
+
inactive: clsx9("border border-default bg-default text-default-secondary", STATE.hover)
|
|
1176
782
|
},
|
|
1177
783
|
plain: {
|
|
1178
784
|
active: STATE.active,
|
|
1179
|
-
inactive:
|
|
785
|
+
inactive: clsx9("text-default-secondary", STATE.hover)
|
|
1180
786
|
}
|
|
1181
787
|
};
|
|
1182
788
|
function NavItem({
|
|
@@ -1185,14 +791,16 @@ function NavItem({
|
|
|
1185
791
|
isActive = false,
|
|
1186
792
|
indicator = false,
|
|
1187
793
|
collapsed = false,
|
|
1188
|
-
size
|
|
794
|
+
size = "md",
|
|
1189
795
|
variant = "card",
|
|
1190
796
|
asChild = false,
|
|
797
|
+
disabled = false,
|
|
1191
798
|
children,
|
|
1192
799
|
className,
|
|
800
|
+
onClick,
|
|
1193
801
|
...rest
|
|
1194
802
|
}) {
|
|
1195
|
-
const s = SIZE[
|
|
803
|
+
const s = SIZE[size];
|
|
1196
804
|
const v = VARIANT[variant];
|
|
1197
805
|
const rootProps = {
|
|
1198
806
|
// Only meaningful when `asChild` renders a real link — a decorative span with
|
|
@@ -1203,7 +811,9 @@ function NavItem({
|
|
|
1203
811
|
// you *are* (`aria-current="page"`), which is a different thing from a row you have
|
|
1204
812
|
// *picked* (`aria-selected`) — `TableRow` is the latter and says `selected`.
|
|
1205
813
|
"data-state": isActive ? "active" : void 0,
|
|
1206
|
-
|
|
814
|
+
"data-disabled": disabled || void 0,
|
|
815
|
+
"aria-disabled": disabled || void 0,
|
|
816
|
+
className: clsx9(
|
|
1207
817
|
"relative flex items-center transition-colors",
|
|
1208
818
|
// Unconditional: a row can also become focusable by the caller putting it inside a
|
|
1209
819
|
// link, which is how `src/sidebar/` uses it. A ring that only appears under `asChild`
|
|
@@ -1216,20 +826,31 @@ function NavItem({
|
|
|
1216
826
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1 focus-visible:ring-offset-default-secondary",
|
|
1217
827
|
s.box,
|
|
1218
828
|
// Expanded rows fill the nav; a collapsed one is a centred square, not a stretched row.
|
|
1219
|
-
collapsed ?
|
|
829
|
+
collapsed ? clsx9("justify-center", s.square) : "w-full",
|
|
1220
830
|
isActive ? v.active : v.inactive,
|
|
831
|
+
"data-[disabled]:cursor-not-allowed data-[disabled]:opacity-40 data-[disabled]:hover:bg-transparent data-[disabled]:hover:text-default-secondary",
|
|
1221
832
|
className
|
|
1222
833
|
),
|
|
1223
|
-
...rest
|
|
834
|
+
...rest,
|
|
835
|
+
// After the spread: a disabled row refuses the press (a router Link skips navigation when
|
|
836
|
+
// the event is prevented) and leaves the tab order, as a disabled control does.
|
|
837
|
+
...disabled ? { tabIndex: -1 } : {},
|
|
838
|
+
onClick: (event) => {
|
|
839
|
+
if (disabled) {
|
|
840
|
+
event.preventDefault();
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
onClick?.(event);
|
|
844
|
+
}
|
|
1224
845
|
};
|
|
1225
846
|
const content = /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1226
|
-
icon != null ? /* @__PURE__ */
|
|
847
|
+
icon != null ? /* @__PURE__ */ jsx9("span", { "aria-hidden": true, className: "shrink-0 [&_svg]:size-4", children: icon }) : (
|
|
1227
848
|
// Icons are optional, but the collapsed rail hides the label — so a row with neither
|
|
1228
849
|
// renders as an empty box. Through 0.5.0 that is exactly what a nav without icons
|
|
1229
850
|
// collapsed to, the docs site's own 36-row sidebar included. The monogram is
|
|
1230
851
|
// decorative in the same way the icon is: the `sr-only` label below still names the
|
|
1231
852
|
// row.
|
|
1232
|
-
collapsed && /* @__PURE__ */
|
|
853
|
+
collapsed && /* @__PURE__ */ jsx9(
|
|
1233
854
|
"span",
|
|
1234
855
|
{
|
|
1235
856
|
"aria-hidden": true,
|
|
@@ -1238,10 +859,10 @@ function NavItem({
|
|
|
1238
859
|
}
|
|
1239
860
|
)
|
|
1240
861
|
),
|
|
1241
|
-
/* @__PURE__ */
|
|
862
|
+
/* @__PURE__ */ jsx9(
|
|
1242
863
|
"span",
|
|
1243
864
|
{
|
|
1244
|
-
className:
|
|
865
|
+
className: clsx9(
|
|
1245
866
|
"min-w-0 truncate font-regular leading-snug",
|
|
1246
867
|
s.label,
|
|
1247
868
|
collapsed ? "sr-only" : "flex-1"
|
|
@@ -1249,7 +870,7 @@ function NavItem({
|
|
|
1249
870
|
children: label
|
|
1250
871
|
}
|
|
1251
872
|
),
|
|
1252
|
-
indicator && /* @__PURE__ */
|
|
873
|
+
indicator && /* @__PURE__ */ jsx9(
|
|
1253
874
|
"span",
|
|
1254
875
|
{
|
|
1255
876
|
role: "status",
|
|
@@ -1259,32 +880,35 @@ function NavItem({
|
|
|
1259
880
|
)
|
|
1260
881
|
] });
|
|
1261
882
|
if (asChild) {
|
|
1262
|
-
return /* @__PURE__ */
|
|
883
|
+
return /* @__PURE__ */ jsx9(Slot, { wrapChildren: () => content, ...rootProps, children });
|
|
1263
884
|
}
|
|
1264
|
-
return /* @__PURE__ */
|
|
885
|
+
return /* @__PURE__ */ jsx9("span", { ...rootProps, children: content });
|
|
1265
886
|
}
|
|
1266
887
|
|
|
888
|
+
// src/index.tsx
|
|
889
|
+
import { createColumnHelper } from "@tanstack/react-table";
|
|
890
|
+
|
|
1267
891
|
// src/sidebar/nav-tabs.tsx
|
|
1268
892
|
import { NavLink } from "react-router-dom";
|
|
1269
|
-
import
|
|
1270
|
-
import { jsx as
|
|
893
|
+
import clsx10 from "clsx";
|
|
894
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
1271
895
|
function NavTabs({ items, className }) {
|
|
1272
896
|
return (
|
|
1273
897
|
// The links inside are the tab stops.
|
|
1274
|
-
/* @__PURE__ */
|
|
898
|
+
/* @__PURE__ */ jsx10(
|
|
1275
899
|
"div",
|
|
1276
900
|
{
|
|
1277
|
-
className:
|
|
901
|
+
className: clsx10(
|
|
1278
902
|
"flex gap-6 overflow-x-auto border-b border-default",
|
|
1279
903
|
SCROLLBAR_CLASSES,
|
|
1280
904
|
className
|
|
1281
905
|
),
|
|
1282
|
-
children: items.map((tab) => /* @__PURE__ */
|
|
906
|
+
children: items.map((tab) => /* @__PURE__ */ jsx10(
|
|
1283
907
|
NavLink,
|
|
1284
908
|
{
|
|
1285
909
|
to: tab.to,
|
|
1286
910
|
end: tab.end,
|
|
1287
|
-
className: ({ isActive }) =>
|
|
911
|
+
className: ({ isActive }) => clsx10(
|
|
1288
912
|
"shrink-0 whitespace-nowrap border-b-2 pb-3 text-body-sm transition-colors",
|
|
1289
913
|
isActive ? "border-brand-emphasis font-semibold text-brand-emphasis" : "border-transparent font-medium text-default-secondary hover:text-default"
|
|
1290
914
|
),
|
|
@@ -1298,7 +922,7 @@ function NavTabs({ items, className }) {
|
|
|
1298
922
|
}
|
|
1299
923
|
|
|
1300
924
|
// src/sidebar/index.tsx
|
|
1301
|
-
import { Fragment as Fragment3, jsx as
|
|
925
|
+
import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1302
926
|
function AppSidebar({
|
|
1303
927
|
groups,
|
|
1304
928
|
footerNav,
|
|
@@ -1307,14 +931,20 @@ function AppSidebar({
|
|
|
1307
931
|
collapsible = true,
|
|
1308
932
|
collapsed: collapsedProp = false,
|
|
1309
933
|
onToggle,
|
|
1310
|
-
size
|
|
934
|
+
size = "md",
|
|
1311
935
|
variant = "card",
|
|
1312
936
|
width = "w-80",
|
|
1313
937
|
collapsedWidth = "w-20",
|
|
1314
938
|
className
|
|
1315
939
|
}) {
|
|
1316
940
|
const collapsed = collapsible && collapsedProp;
|
|
1317
|
-
|
|
941
|
+
const hashTargets = useMemo2(
|
|
942
|
+
() => new Set(
|
|
943
|
+
[...groups.flatMap((group) => group.items), ...footerNav ?? []].map((item) => item.to).filter((to) => to.includes("#"))
|
|
944
|
+
),
|
|
945
|
+
[groups, footerNav]
|
|
946
|
+
);
|
|
947
|
+
return /* @__PURE__ */ jsx11(HashTargets.Provider, { value: hashTargets, children: /* @__PURE__ */ jsxs4(
|
|
1318
948
|
"aside",
|
|
1319
949
|
{
|
|
1320
950
|
className: cn(
|
|
@@ -1324,7 +954,7 @@ function AppSidebar({
|
|
|
1324
954
|
className
|
|
1325
955
|
),
|
|
1326
956
|
children: [
|
|
1327
|
-
collapsible && onToggle && /* @__PURE__ */
|
|
957
|
+
collapsible && onToggle && /* @__PURE__ */ jsx11(
|
|
1328
958
|
"button",
|
|
1329
959
|
{
|
|
1330
960
|
type: "button",
|
|
@@ -1340,10 +970,10 @@ function AppSidebar({
|
|
|
1340
970
|
"shadow-100 transition-colors hover:bg-brand-tertiary-hover hover:text-brand",
|
|
1341
971
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-1 focus-visible:ring-offset-default"
|
|
1342
972
|
),
|
|
1343
|
-
children: collapsed ? /* @__PURE__ */
|
|
973
|
+
children: collapsed ? /* @__PURE__ */ jsx11(ChevronRightIcon2, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true }) : /* @__PURE__ */ jsx11(ChevronLeftIcon, { className: "size-3", strokeWidth: 2.5, "aria-hidden": true })
|
|
1344
974
|
}
|
|
1345
975
|
),
|
|
1346
|
-
brand && /* @__PURE__ */
|
|
976
|
+
brand && /* @__PURE__ */ jsx11(
|
|
1347
977
|
"div",
|
|
1348
978
|
{
|
|
1349
979
|
className: cn(
|
|
@@ -1353,24 +983,24 @@ function AppSidebar({
|
|
|
1353
983
|
children: typeof brand === "function" ? brand({ collapsed }) : brand
|
|
1354
984
|
}
|
|
1355
985
|
),
|
|
1356
|
-
/* @__PURE__ */
|
|
986
|
+
/* @__PURE__ */ jsx11(ScrollArea, { axis: "vertical", label: "Sidebar navigation", className: "min-h-0 flex-1", children: /* @__PURE__ */ jsx11("nav", { className: "flex flex-col gap-4 px-4 pb-3 pt-2", children: groups.map((group, groupIndex) => /* @__PURE__ */ jsx11(
|
|
1357
987
|
SidebarGroup,
|
|
1358
988
|
{
|
|
1359
989
|
group,
|
|
1360
990
|
showSeparator: groupIndex > 0,
|
|
1361
991
|
collapsed,
|
|
1362
|
-
size
|
|
992
|
+
size,
|
|
1363
993
|
variant
|
|
1364
994
|
},
|
|
1365
995
|
group.title ?? `group-${groupIndex}`
|
|
1366
996
|
)) }) }),
|
|
1367
997
|
(footerNav?.length || footer) && /* @__PURE__ */ jsxs4("div", { className: "flex shrink-0 flex-col", children: [
|
|
1368
|
-
footerNav && footerNav.length > 0 && /* @__PURE__ */
|
|
998
|
+
footerNav && footerNav.length > 0 && /* @__PURE__ */ jsx11("nav", { className: "flex flex-col gap-3 px-4 pt-2", children: footerNav.map((item) => /* @__PURE__ */ jsx11(
|
|
1369
999
|
SidebarLink,
|
|
1370
1000
|
{
|
|
1371
1001
|
item,
|
|
1372
1002
|
collapsed,
|
|
1373
|
-
size
|
|
1003
|
+
size,
|
|
1374
1004
|
variant
|
|
1375
1005
|
},
|
|
1376
1006
|
item.to
|
|
@@ -1379,13 +1009,13 @@ function AppSidebar({
|
|
|
1379
1009
|
] })
|
|
1380
1010
|
]
|
|
1381
1011
|
}
|
|
1382
|
-
);
|
|
1012
|
+
) });
|
|
1383
1013
|
}
|
|
1384
1014
|
function SidebarGroup({
|
|
1385
1015
|
group,
|
|
1386
1016
|
showSeparator,
|
|
1387
1017
|
collapsed,
|
|
1388
|
-
size
|
|
1018
|
+
size,
|
|
1389
1019
|
variant
|
|
1390
1020
|
}) {
|
|
1391
1021
|
return (
|
|
@@ -1393,8 +1023,8 @@ function SidebarGroup({
|
|
|
1393
1023
|
// stack. Through 0.5.0 this was `gap-1`, which packed them into a near-continuous block.
|
|
1394
1024
|
// The same gap spaces the separator and the heading, so neither needs a margin of its own.
|
|
1395
1025
|
/* @__PURE__ */ jsxs4("div", { className: "flex flex-col gap-3", children: [
|
|
1396
|
-
showSeparator && /* @__PURE__ */
|
|
1397
|
-
group.title && /* @__PURE__ */
|
|
1026
|
+
showSeparator && /* @__PURE__ */ jsx11(SidebarSeparator, {}),
|
|
1027
|
+
group.title && /* @__PURE__ */ jsx11(
|
|
1398
1028
|
"p",
|
|
1399
1029
|
{
|
|
1400
1030
|
className: cn(
|
|
@@ -1407,12 +1037,12 @@ function SidebarGroup({
|
|
|
1407
1037
|
children: group.title
|
|
1408
1038
|
}
|
|
1409
1039
|
),
|
|
1410
|
-
group.items.map((item) => /* @__PURE__ */
|
|
1040
|
+
group.items.map((item) => /* @__PURE__ */ jsx11(
|
|
1411
1041
|
SidebarLink,
|
|
1412
1042
|
{
|
|
1413
1043
|
item,
|
|
1414
1044
|
collapsed,
|
|
1415
|
-
size
|
|
1045
|
+
size,
|
|
1416
1046
|
variant
|
|
1417
1047
|
},
|
|
1418
1048
|
item.to
|
|
@@ -1420,37 +1050,52 @@ function SidebarGroup({
|
|
|
1420
1050
|
] })
|
|
1421
1051
|
);
|
|
1422
1052
|
}
|
|
1053
|
+
var HashTargets = createContext4(/* @__PURE__ */ new Set());
|
|
1054
|
+
function useRowActive(item) {
|
|
1055
|
+
const location = useLocation();
|
|
1056
|
+
const hashTargets = useContext4(HashTargets);
|
|
1057
|
+
const [path, hash] = item.to.split("#");
|
|
1058
|
+
const pathMatches = item.end ? location.pathname === path : location.pathname === path || location.pathname.startsWith(`${path.replace(/\/$/, "")}/`);
|
|
1059
|
+
if (!pathMatches) return false;
|
|
1060
|
+
if (hash !== void 0) return location.hash === `#${hash}`;
|
|
1061
|
+
return !hashTargets.has(`${location.pathname}${location.hash}`);
|
|
1062
|
+
}
|
|
1423
1063
|
function SidebarLink({
|
|
1424
1064
|
item,
|
|
1425
1065
|
collapsed,
|
|
1426
|
-
size
|
|
1066
|
+
size,
|
|
1427
1067
|
variant
|
|
1428
1068
|
}) {
|
|
1429
|
-
const
|
|
1430
|
-
|
|
1069
|
+
const active = useRowActive(item);
|
|
1070
|
+
const link = /* @__PURE__ */ jsx11(
|
|
1071
|
+
Link,
|
|
1431
1072
|
{
|
|
1432
1073
|
to: item.to,
|
|
1433
|
-
|
|
1074
|
+
"aria-current": active ? "page" : void 0,
|
|
1075
|
+
"aria-disabled": item.disabled || void 0,
|
|
1076
|
+
tabIndex: item.disabled ? -1 : void 0,
|
|
1077
|
+
onClick: item.disabled ? (event) => event.preventDefault() : void 0,
|
|
1434
1078
|
className: cn("block w-full no-underline", collapsed && "flex justify-center"),
|
|
1435
|
-
children:
|
|
1079
|
+
children: /* @__PURE__ */ jsx11(
|
|
1436
1080
|
NavItem,
|
|
1437
1081
|
{
|
|
1438
1082
|
icon: item.icon,
|
|
1439
1083
|
label: item.label,
|
|
1440
|
-
isActive,
|
|
1084
|
+
isActive: active,
|
|
1441
1085
|
indicator: item.indicator,
|
|
1086
|
+
disabled: item.disabled,
|
|
1442
1087
|
collapsed,
|
|
1443
|
-
size
|
|
1088
|
+
size,
|
|
1444
1089
|
variant
|
|
1445
1090
|
}
|
|
1446
1091
|
)
|
|
1447
1092
|
}
|
|
1448
1093
|
);
|
|
1449
1094
|
if (!collapsed) return link;
|
|
1450
|
-
return /* @__PURE__ */
|
|
1095
|
+
return /* @__PURE__ */ jsx11(Tooltip, { title: item.label, side: "right", children: link });
|
|
1451
1096
|
}
|
|
1452
1097
|
function SidebarSeparator({ className, ...rest }) {
|
|
1453
|
-
return /* @__PURE__ */
|
|
1098
|
+
return /* @__PURE__ */ jsx11("div", { "aria-hidden": true, className: cn("mx-1 h-px shrink-0 bg-divider", className), ...rest });
|
|
1454
1099
|
}
|
|
1455
1100
|
function SidebarUserCard({
|
|
1456
1101
|
name,
|
|
@@ -1463,38 +1108,38 @@ function SidebarUserCard({
|
|
|
1463
1108
|
const initial = name.trim().charAt(0);
|
|
1464
1109
|
const items = /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
1465
1110
|
menu,
|
|
1466
|
-
/* @__PURE__ */
|
|
1467
|
-
|
|
1111
|
+
/* @__PURE__ */ jsx11(
|
|
1112
|
+
DropdownMenuItem,
|
|
1468
1113
|
{
|
|
1469
|
-
icon: /* @__PURE__ */
|
|
1114
|
+
icon: /* @__PURE__ */ jsx11(LogOutIcon, { className: "size-3.5", "aria-hidden": true }),
|
|
1470
1115
|
onSelect: onLogout,
|
|
1471
1116
|
children: "Sign out"
|
|
1472
1117
|
}
|
|
1473
1118
|
)
|
|
1474
1119
|
] });
|
|
1475
1120
|
if (collapsed) {
|
|
1476
|
-
return /* @__PURE__ */
|
|
1477
|
-
/* @__PURE__ */
|
|
1478
|
-
/* @__PURE__ */
|
|
1121
|
+
return /* @__PURE__ */ jsx11("div", { className: cn("flex shrink-0 items-center justify-center p-4", className), children: /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
|
|
1122
|
+
/* @__PURE__ */ jsx11(DropdownMenuTrigger, { asChild: true, label: "User options", children: /* @__PURE__ */ jsx11("button", { type: "button", "aria-label": `${name} \u2014 user options`, className: "rounded-full", children: /* @__PURE__ */ jsx11(Avatar, { initial, size: "lg", shape: "circle" }) }) }),
|
|
1123
|
+
/* @__PURE__ */ jsx11(DropdownMenuContent, { side: "right", align: "end", children: items })
|
|
1479
1124
|
] }) });
|
|
1480
1125
|
}
|
|
1481
1126
|
return /* @__PURE__ */ jsxs4("div", { className: cn("flex shrink-0 items-center gap-2.5 p-4", className), children: [
|
|
1482
|
-
/* @__PURE__ */
|
|
1127
|
+
/* @__PURE__ */ jsx11(Avatar, { initial, size: "lg", shape: "circle" }),
|
|
1483
1128
|
/* @__PURE__ */ jsxs4("div", { className: "flex min-w-0 flex-1 flex-col gap-0.5", children: [
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
/* @__PURE__ */
|
|
1129
|
+
/* @__PURE__ */ jsx11("span", { className: "truncate text-body-sm font-semibold leading-snug text-default", children: name }),
|
|
1130
|
+
/* @__PURE__ */ jsx11("span", { className: "truncate text-body-tiny font-regular leading-none text-default-secondary", children: role })
|
|
1486
1131
|
] }),
|
|
1487
1132
|
/* @__PURE__ */ jsxs4(DropdownMenu, { children: [
|
|
1488
|
-
/* @__PURE__ */
|
|
1133
|
+
/* @__PURE__ */ jsx11(DropdownMenuTrigger, { asChild: true, label: "User options", children: /* @__PURE__ */ jsx11(
|
|
1489
1134
|
"button",
|
|
1490
1135
|
{
|
|
1491
1136
|
type: "button",
|
|
1492
1137
|
"aria-label": `${name} \u2014 user options`,
|
|
1493
1138
|
className: "flex size-6 shrink-0 items-center justify-center rounded-md text-default-secondary transition-colors hover:bg-brand-tertiary-hover hover:text-brand",
|
|
1494
|
-
children: /* @__PURE__ */
|
|
1139
|
+
children: /* @__PURE__ */ jsx11(EllipsisVerticalIcon, { className: "size-5", "aria-hidden": true })
|
|
1495
1140
|
}
|
|
1496
1141
|
) }),
|
|
1497
|
-
/* @__PURE__ */
|
|
1142
|
+
/* @__PURE__ */ jsx11(DropdownMenuContent, { side: "top", align: "end", children: items })
|
|
1498
1143
|
] })
|
|
1499
1144
|
] });
|
|
1500
1145
|
}
|