@zovaris/sephiro 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components.css +2123 -107
- package/dist/index.css +2132 -105
- package/dist/index.d.ts +274 -4
- package/dist/index.js +2412 -312
- package/dist/index.js.map +1 -1
- package/dist/themes.css +11 -0
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -1,11 +1,60 @@
|
|
|
1
|
-
// src/atoms/
|
|
1
|
+
// src/atoms/Avatar/index.tsx
|
|
2
2
|
import { cn } from "cn";
|
|
3
|
+
import { useState } from "react";
|
|
3
4
|
|
|
4
5
|
// src/lib/node.ts
|
|
5
6
|
var node = (value) => value;
|
|
6
7
|
|
|
8
|
+
// src/atoms/Avatar/index.tsx
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
function initialsOf(name) {
|
|
11
|
+
if (!name) return "?";
|
|
12
|
+
const words = name.trim().split(/\s+/).slice(0, 2);
|
|
13
|
+
return words.map((word) => word[0]?.toUpperCase() ?? "").join("") || "?";
|
|
14
|
+
}
|
|
15
|
+
function Avatar({
|
|
16
|
+
src,
|
|
17
|
+
name,
|
|
18
|
+
size = "md",
|
|
19
|
+
status,
|
|
20
|
+
className,
|
|
21
|
+
...props
|
|
22
|
+
}) {
|
|
23
|
+
const [failed, setFailed] = useState(false);
|
|
24
|
+
const showImage = Boolean(src) && !failed;
|
|
25
|
+
return /* @__PURE__ */ jsxs(
|
|
26
|
+
"span",
|
|
27
|
+
{
|
|
28
|
+
...node(props),
|
|
29
|
+
className: cn("sph-avatar", className),
|
|
30
|
+
"data-size": size,
|
|
31
|
+
title: name,
|
|
32
|
+
children: [
|
|
33
|
+
showImage ? /* @__PURE__ */ jsx(
|
|
34
|
+
"img",
|
|
35
|
+
{
|
|
36
|
+
className: "sph-avatar__image",
|
|
37
|
+
src,
|
|
38
|
+
alt: name ?? "",
|
|
39
|
+
onError: () => setFailed(true)
|
|
40
|
+
}
|
|
41
|
+
) : /* @__PURE__ */ jsx("span", { className: "sph-avatar__initials", "aria-hidden": "true", children: initialsOf(name) }),
|
|
42
|
+
status !== void 0 && /* @__PURE__ */ jsx(
|
|
43
|
+
"span",
|
|
44
|
+
{
|
|
45
|
+
className: "sph-avatar__status",
|
|
46
|
+
"data-status": status,
|
|
47
|
+
"aria-hidden": "true"
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
7
55
|
// src/atoms/Badge/index.tsx
|
|
8
|
-
import {
|
|
56
|
+
import { cn as cn2 } from "cn";
|
|
57
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
9
58
|
function Badge({
|
|
10
59
|
variant = "neutral",
|
|
11
60
|
size = "sm",
|
|
@@ -13,11 +62,11 @@ function Badge({
|
|
|
13
62
|
children,
|
|
14
63
|
...props
|
|
15
64
|
}) {
|
|
16
|
-
return /* @__PURE__ */
|
|
65
|
+
return /* @__PURE__ */ jsx2(
|
|
17
66
|
"span",
|
|
18
67
|
{
|
|
19
68
|
...node(props),
|
|
20
|
-
className:
|
|
69
|
+
className: cn2("sph-badge", className),
|
|
21
70
|
"data-variant": variant,
|
|
22
71
|
"data-size": size,
|
|
23
72
|
children: node(children)
|
|
@@ -26,22 +75,22 @@ function Badge({
|
|
|
26
75
|
}
|
|
27
76
|
|
|
28
77
|
// src/atoms/Button/index.tsx
|
|
29
|
-
import { cn as
|
|
78
|
+
import { cn as cn4 } from "cn";
|
|
30
79
|
|
|
31
80
|
// src/atoms/Spinner/index.tsx
|
|
32
|
-
import { cn as
|
|
33
|
-
import { jsx as
|
|
81
|
+
import { cn as cn3 } from "cn";
|
|
82
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
34
83
|
function Spinner({
|
|
35
84
|
size = "md",
|
|
36
85
|
label,
|
|
37
86
|
className,
|
|
38
87
|
...props
|
|
39
88
|
}) {
|
|
40
|
-
return /* @__PURE__ */
|
|
89
|
+
return /* @__PURE__ */ jsx3(
|
|
41
90
|
"span",
|
|
42
91
|
{
|
|
43
92
|
...node(props),
|
|
44
|
-
className:
|
|
93
|
+
className: cn3("sph-spinner", `sph-spinner--${size}`, className),
|
|
45
94
|
role: label ? "status" : void 0,
|
|
46
95
|
"aria-label": label,
|
|
47
96
|
"aria-hidden": label ? void 0 : true
|
|
@@ -50,7 +99,7 @@ function Spinner({
|
|
|
50
99
|
}
|
|
51
100
|
|
|
52
101
|
// src/atoms/Button/index.tsx
|
|
53
|
-
import { jsx as
|
|
102
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
54
103
|
function Button({
|
|
55
104
|
variant = "secondary",
|
|
56
105
|
size = "md",
|
|
@@ -62,11 +111,11 @@ function Button({
|
|
|
62
111
|
"aria-busy": ariaBusy,
|
|
63
112
|
...props
|
|
64
113
|
}) {
|
|
65
|
-
return /* @__PURE__ */
|
|
114
|
+
return /* @__PURE__ */ jsxs2(
|
|
66
115
|
"button",
|
|
67
116
|
{
|
|
68
117
|
type,
|
|
69
|
-
className:
|
|
118
|
+
className: cn4("sph-button", className),
|
|
70
119
|
"data-variant": variant,
|
|
71
120
|
"data-size": size,
|
|
72
121
|
"data-loading": loading || void 0,
|
|
@@ -74,8 +123,8 @@ function Button({
|
|
|
74
123
|
...node(props),
|
|
75
124
|
"aria-busy": ariaBusy ?? (loading || void 0),
|
|
76
125
|
children: [
|
|
77
|
-
loading && /* @__PURE__ */
|
|
78
|
-
/* @__PURE__ */
|
|
126
|
+
loading && /* @__PURE__ */ jsx4(Spinner, { size: "sm" }),
|
|
127
|
+
/* @__PURE__ */ jsx4("span", { className: "sph-button__label", children: node(children) })
|
|
79
128
|
]
|
|
80
129
|
}
|
|
81
130
|
);
|
|
@@ -83,8 +132,8 @@ function Button({
|
|
|
83
132
|
|
|
84
133
|
// src/atoms/Checkbox/index.tsx
|
|
85
134
|
import { CheckIcon } from "@phosphor-icons/react";
|
|
86
|
-
import { cn as
|
|
87
|
-
import { jsx as
|
|
135
|
+
import { cn as cn5 } from "cn";
|
|
136
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
88
137
|
function Checkbox({
|
|
89
138
|
label,
|
|
90
139
|
size = "md",
|
|
@@ -92,7 +141,7 @@ function Checkbox({
|
|
|
92
141
|
className,
|
|
93
142
|
...props
|
|
94
143
|
}) {
|
|
95
|
-
const control = /* @__PURE__ */
|
|
144
|
+
const control = /* @__PURE__ */ jsx5(
|
|
96
145
|
"input",
|
|
97
146
|
{
|
|
98
147
|
...node(props),
|
|
@@ -103,16 +152,16 @@ function Checkbox({
|
|
|
103
152
|
}
|
|
104
153
|
);
|
|
105
154
|
if (label === void 0) return control;
|
|
106
|
-
return /* @__PURE__ */
|
|
155
|
+
return /* @__PURE__ */ jsxs3("label", { className: cn5("sph-checkbox", className), "data-size": size, children: [
|
|
107
156
|
control,
|
|
108
|
-
/* @__PURE__ */
|
|
109
|
-
/* @__PURE__ */
|
|
157
|
+
/* @__PURE__ */ jsx5("span", { className: "sph-checkbox__box", "aria-hidden": "true", children: /* @__PURE__ */ jsx5(CheckIcon, { className: "sph-checkbox__check" }) }),
|
|
158
|
+
/* @__PURE__ */ jsx5("span", { className: "sph-checkbox__label", children: node(label) })
|
|
110
159
|
] });
|
|
111
160
|
}
|
|
112
161
|
|
|
113
162
|
// src/atoms/IconButton/index.tsx
|
|
114
|
-
import { cn as
|
|
115
|
-
import { jsx as
|
|
163
|
+
import { cn as cn6 } from "cn";
|
|
164
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
116
165
|
function IconButton({
|
|
117
166
|
icon,
|
|
118
167
|
label,
|
|
@@ -124,26 +173,26 @@ function IconButton({
|
|
|
124
173
|
type = "button",
|
|
125
174
|
...props
|
|
126
175
|
}) {
|
|
127
|
-
return /* @__PURE__ */
|
|
176
|
+
return /* @__PURE__ */ jsx6(
|
|
128
177
|
"button",
|
|
129
178
|
{
|
|
130
179
|
...node(props),
|
|
131
180
|
type,
|
|
132
|
-
className:
|
|
181
|
+
className: cn6("sph-icon-button", className),
|
|
133
182
|
"data-size": size,
|
|
134
183
|
"data-variant": variant,
|
|
135
184
|
"data-loading": loading || void 0,
|
|
136
185
|
"aria-label": label,
|
|
137
186
|
"aria-busy": loading ? true : props["aria-busy"],
|
|
138
187
|
disabled: disabled || loading,
|
|
139
|
-
children: loading ? /* @__PURE__ */
|
|
188
|
+
children: loading ? /* @__PURE__ */ jsx6(Spinner, { size: size === "lg" ? "md" : "sm" }) : node(icon)
|
|
140
189
|
}
|
|
141
190
|
);
|
|
142
191
|
}
|
|
143
192
|
|
|
144
193
|
// src/atoms/Input/index.tsx
|
|
145
|
-
import { cn as
|
|
146
|
-
import { jsx as
|
|
194
|
+
import { cn as cn7 } from "cn";
|
|
195
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
147
196
|
function Input({
|
|
148
197
|
invalid = false,
|
|
149
198
|
size = "md",
|
|
@@ -151,31 +200,95 @@ function Input({
|
|
|
151
200
|
"aria-invalid": ariaInvalid,
|
|
152
201
|
...props
|
|
153
202
|
}) {
|
|
154
|
-
return /* @__PURE__ */
|
|
203
|
+
return /* @__PURE__ */ jsx7(
|
|
155
204
|
"input",
|
|
156
205
|
{
|
|
157
206
|
...node(props),
|
|
158
|
-
className:
|
|
207
|
+
className: cn7("sph-input", className),
|
|
159
208
|
"data-size": size,
|
|
160
209
|
"aria-invalid": ariaInvalid ?? (invalid || void 0)
|
|
161
210
|
}
|
|
162
211
|
);
|
|
163
212
|
}
|
|
164
213
|
|
|
214
|
+
// src/atoms/Kbd/index.tsx
|
|
215
|
+
import { cn as cn8 } from "cn";
|
|
216
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
217
|
+
function Kbd({ keys, className }) {
|
|
218
|
+
const caps = Array.isArray(keys) ? keys : [keys];
|
|
219
|
+
return /* @__PURE__ */ jsx8("kbd", { className: cn8("sph-kbd", className), children: caps.map((cap, index) => /* @__PURE__ */ jsx8("kbd", { className: "sph-kbd__key", children: node(cap) }, index)) });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/atoms/Progress/index.tsx
|
|
223
|
+
import { cn as cn9 } from "cn";
|
|
224
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
225
|
+
function Progress({
|
|
226
|
+
value,
|
|
227
|
+
label,
|
|
228
|
+
size = "md",
|
|
229
|
+
className,
|
|
230
|
+
...props
|
|
231
|
+
}) {
|
|
232
|
+
const determinate = typeof value === "number" && Number.isFinite(value);
|
|
233
|
+
const clamped = determinate ? Math.min(Math.max(value, 0), 100) : void 0;
|
|
234
|
+
return /* @__PURE__ */ jsx9(
|
|
235
|
+
"div",
|
|
236
|
+
{
|
|
237
|
+
...node(props),
|
|
238
|
+
className: cn9("sph-progress", className),
|
|
239
|
+
"data-size": size,
|
|
240
|
+
role: "progressbar",
|
|
241
|
+
"aria-label": label,
|
|
242
|
+
"aria-valuemin": determinate ? 0 : void 0,
|
|
243
|
+
"aria-valuemax": determinate ? 100 : void 0,
|
|
244
|
+
"aria-valuenow": clamped,
|
|
245
|
+
"aria-valuetext": clamped !== void 0 ? `${Math.round(clamped)}%` : void 0,
|
|
246
|
+
children: /* @__PURE__ */ jsx9("span", { className: "sph-progress__track", children: /* @__PURE__ */ jsx9(
|
|
247
|
+
"span",
|
|
248
|
+
{
|
|
249
|
+
className: "sph-progress__bar",
|
|
250
|
+
"data-indeterminate": determinate ? void 0 : "true",
|
|
251
|
+
style: determinate ? { width: `${clamped}%` } : void 0
|
|
252
|
+
}
|
|
253
|
+
) })
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/atoms/ScrollArea/index.tsx
|
|
259
|
+
import { cn as cn10 } from "cn";
|
|
260
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
261
|
+
function ScrollArea({
|
|
262
|
+
orientation = "vertical",
|
|
263
|
+
className,
|
|
264
|
+
children,
|
|
265
|
+
...props
|
|
266
|
+
}) {
|
|
267
|
+
return /* @__PURE__ */ jsx10(
|
|
268
|
+
"div",
|
|
269
|
+
{
|
|
270
|
+
...node(props),
|
|
271
|
+
className: cn10("sph-scroll-area", className),
|
|
272
|
+
"data-orientation": orientation,
|
|
273
|
+
children: node(children)
|
|
274
|
+
}
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
|
|
165
278
|
// src/atoms/Separator/index.tsx
|
|
166
|
-
import { cn as
|
|
167
|
-
import { jsx as
|
|
279
|
+
import { cn as cn11 } from "cn";
|
|
280
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
168
281
|
function Separator({
|
|
169
282
|
orientation = "horizontal",
|
|
170
283
|
decorative = true,
|
|
171
284
|
className,
|
|
172
285
|
...props
|
|
173
286
|
}) {
|
|
174
|
-
return /* @__PURE__ */
|
|
287
|
+
return /* @__PURE__ */ jsx11(
|
|
175
288
|
"hr",
|
|
176
289
|
{
|
|
177
290
|
...node(props),
|
|
178
|
-
className:
|
|
291
|
+
className: cn11("sph-separator", className),
|
|
179
292
|
"data-orientation": orientation,
|
|
180
293
|
role: decorative ? "presentation" : "separator",
|
|
181
294
|
"aria-orientation": decorative ? void 0 : orientation
|
|
@@ -184,8 +297,8 @@ function Separator({
|
|
|
184
297
|
}
|
|
185
298
|
|
|
186
299
|
// src/atoms/Skeleton/index.tsx
|
|
187
|
-
import { cn as
|
|
188
|
-
import { jsx as
|
|
300
|
+
import { cn as cn12 } from "cn";
|
|
301
|
+
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
189
302
|
function Skeleton({
|
|
190
303
|
width,
|
|
191
304
|
height,
|
|
@@ -194,11 +307,11 @@ function Skeleton({
|
|
|
194
307
|
"aria-label": ariaLabel,
|
|
195
308
|
...props
|
|
196
309
|
}) {
|
|
197
|
-
return /* @__PURE__ */
|
|
310
|
+
return /* @__PURE__ */ jsx12(
|
|
198
311
|
"span",
|
|
199
312
|
{
|
|
200
313
|
...node(props),
|
|
201
|
-
className:
|
|
314
|
+
className: cn12("sph-skeleton", className),
|
|
202
315
|
style: { ...style, width, height },
|
|
203
316
|
"aria-hidden": ariaLabel ? void 0 : true
|
|
204
317
|
}
|
|
@@ -206,9 +319,9 @@ function Skeleton({
|
|
|
206
319
|
}
|
|
207
320
|
|
|
208
321
|
// src/atoms/Slider/index.tsx
|
|
209
|
-
import { cn as
|
|
322
|
+
import { cn as cn13 } from "cn";
|
|
210
323
|
import { useId } from "react";
|
|
211
|
-
import { jsx as
|
|
324
|
+
import { jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
212
325
|
function Slider({
|
|
213
326
|
value,
|
|
214
327
|
onValueChange,
|
|
@@ -236,17 +349,17 @@ function Slider({
|
|
|
236
349
|
...style,
|
|
237
350
|
"--sph-slider-progress": `${progress}%`
|
|
238
351
|
};
|
|
239
|
-
return /* @__PURE__ */
|
|
352
|
+
return /* @__PURE__ */ jsxs4(
|
|
240
353
|
"div",
|
|
241
354
|
{
|
|
242
|
-
className:
|
|
355
|
+
className: cn13("sph-slider", className),
|
|
243
356
|
"data-size": size,
|
|
244
357
|
"data-disabled": disabled || void 0,
|
|
245
358
|
"data-invalid": invalid || void 0,
|
|
246
359
|
children: [
|
|
247
|
-
/* @__PURE__ */
|
|
248
|
-
/* @__PURE__ */
|
|
249
|
-
valueLabel !== void 0 && /* @__PURE__ */
|
|
360
|
+
/* @__PURE__ */ jsxs4("div", { className: "sph-slider__head", children: [
|
|
361
|
+
/* @__PURE__ */ jsx13("label", { className: "sph-slider__label", htmlFor: inputId, children: node(label) }),
|
|
362
|
+
valueLabel !== void 0 && /* @__PURE__ */ jsx13(
|
|
250
363
|
"output",
|
|
251
364
|
{
|
|
252
365
|
className: "sph-slider__value",
|
|
@@ -256,7 +369,7 @@ function Slider({
|
|
|
256
369
|
}
|
|
257
370
|
)
|
|
258
371
|
] }),
|
|
259
|
-
/* @__PURE__ */
|
|
372
|
+
/* @__PURE__ */ jsx13(
|
|
260
373
|
"input",
|
|
261
374
|
{
|
|
262
375
|
...node(props),
|
|
@@ -281,8 +394,8 @@ function Slider({
|
|
|
281
394
|
}
|
|
282
395
|
|
|
283
396
|
// src/atoms/Surface/index.tsx
|
|
284
|
-
import { cn as
|
|
285
|
-
import { jsx as
|
|
397
|
+
import { cn as cn14 } from "cn";
|
|
398
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
286
399
|
function Surface({
|
|
287
400
|
tone = "base",
|
|
288
401
|
padding = "md",
|
|
@@ -290,11 +403,11 @@ function Surface({
|
|
|
290
403
|
children,
|
|
291
404
|
...props
|
|
292
405
|
}) {
|
|
293
|
-
return /* @__PURE__ */
|
|
406
|
+
return /* @__PURE__ */ jsx14(
|
|
294
407
|
"div",
|
|
295
408
|
{
|
|
296
409
|
...node(props),
|
|
297
|
-
className:
|
|
410
|
+
className: cn14("sph-surface", className),
|
|
298
411
|
"data-tone": tone,
|
|
299
412
|
"data-padding": padding,
|
|
300
413
|
children: node(children)
|
|
@@ -303,8 +416,8 @@ function Surface({
|
|
|
303
416
|
}
|
|
304
417
|
|
|
305
418
|
// src/atoms/Textarea/index.tsx
|
|
306
|
-
import { cn as
|
|
307
|
-
import { jsx as
|
|
419
|
+
import { cn as cn15 } from "cn";
|
|
420
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
308
421
|
function Textarea({
|
|
309
422
|
invalid = false,
|
|
310
423
|
size = "md",
|
|
@@ -312,11 +425,11 @@ function Textarea({
|
|
|
312
425
|
"aria-invalid": ariaInvalid,
|
|
313
426
|
...props
|
|
314
427
|
}) {
|
|
315
|
-
return /* @__PURE__ */
|
|
428
|
+
return /* @__PURE__ */ jsx15(
|
|
316
429
|
"textarea",
|
|
317
430
|
{
|
|
318
431
|
...node(props),
|
|
319
|
-
className:
|
|
432
|
+
className: cn15("sph-textarea", className),
|
|
320
433
|
"data-size": size,
|
|
321
434
|
"aria-invalid": ariaInvalid ?? (invalid || void 0)
|
|
322
435
|
}
|
|
@@ -324,8 +437,8 @@ function Textarea({
|
|
|
324
437
|
}
|
|
325
438
|
|
|
326
439
|
// src/atoms/Toggle/index.tsx
|
|
327
|
-
import { cn as
|
|
328
|
-
import { jsx as
|
|
440
|
+
import { cn as cn16 } from "cn";
|
|
441
|
+
import { jsx as jsx16, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
329
442
|
function Toggle({
|
|
330
443
|
checked,
|
|
331
444
|
onCheckedChange,
|
|
@@ -338,7 +451,7 @@ function Toggle({
|
|
|
338
451
|
"aria-label": ariaLabel = label,
|
|
339
452
|
...props
|
|
340
453
|
}) {
|
|
341
|
-
return /* @__PURE__ */
|
|
454
|
+
return /* @__PURE__ */ jsxs5(
|
|
342
455
|
"button",
|
|
343
456
|
{
|
|
344
457
|
type: "button",
|
|
@@ -346,7 +459,7 @@ function Toggle({
|
|
|
346
459
|
"aria-checked": ariaChecked ?? checked,
|
|
347
460
|
"aria-label": ariaLabel ?? label,
|
|
348
461
|
disabled,
|
|
349
|
-
className:
|
|
462
|
+
className: cn16("sph-toggle", className),
|
|
350
463
|
"data-state": checked ? "checked" : "unchecked",
|
|
351
464
|
"data-size": size,
|
|
352
465
|
onClick: (event) => {
|
|
@@ -354,20 +467,77 @@ function Toggle({
|
|
|
354
467
|
if (!event.defaultPrevented) onCheckedChange(!checked);
|
|
355
468
|
},
|
|
356
469
|
...node(props),
|
|
357
|
-
children:
|
|
470
|
+
children: [
|
|
471
|
+
" ",
|
|
472
|
+
/* @__PURE__ */ jsx16("span", { className: "sph-toggle__track", children: /* @__PURE__ */ jsx16("span", { className: "sph-toggle__thumb" }) })
|
|
473
|
+
]
|
|
358
474
|
}
|
|
359
475
|
);
|
|
360
476
|
}
|
|
361
477
|
|
|
478
|
+
// src/lib/presence.ts
|
|
479
|
+
import { useEffect, useRef, useState as useState2 } from "react";
|
|
480
|
+
var SPEED_TOKEN = {
|
|
481
|
+
fast: "--sph-motion-fast",
|
|
482
|
+
normal: "--sph-motion-normal",
|
|
483
|
+
slow: "--sph-motion-slow"
|
|
484
|
+
};
|
|
485
|
+
var EXIT_FRAME_BUDGET = 40;
|
|
486
|
+
function parseDurationMs(value) {
|
|
487
|
+
const match = value.trim().match(/^(\d+(?:\.\d+)?)(ms|s)?$/);
|
|
488
|
+
if (!match) return 0;
|
|
489
|
+
const amount = Number.parseFloat(match[1]);
|
|
490
|
+
if (!Number.isFinite(amount) || amount <= 0) return 0;
|
|
491
|
+
return match[2] === "s" ? amount * 1e3 : amount;
|
|
492
|
+
}
|
|
493
|
+
function motionDurationMs(element, speed) {
|
|
494
|
+
if (typeof window === "undefined" || typeof getComputedStyle !== "function")
|
|
495
|
+
return 0;
|
|
496
|
+
const source = element ?? document.documentElement;
|
|
497
|
+
const raw = getComputedStyle(source).getPropertyValue(SPEED_TOKEN[speed]);
|
|
498
|
+
return Math.min(parseDurationMs(raw || "0ms"), 1200);
|
|
499
|
+
}
|
|
500
|
+
function usePresence(open, speed = "normal") {
|
|
501
|
+
const ref = useRef(null);
|
|
502
|
+
const [present, setPresent] = useState2(open);
|
|
503
|
+
const [leaving, setLeaving] = useState2(false);
|
|
504
|
+
useEffect(() => {
|
|
505
|
+
if (open) {
|
|
506
|
+
setLeaving(false);
|
|
507
|
+
setPresent(true);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (!present) return;
|
|
511
|
+
const duration = motionDurationMs(ref.current, speed);
|
|
512
|
+
if (duration <= 0) {
|
|
513
|
+
setPresent(false);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
setLeaving(true);
|
|
517
|
+
const timer = setTimeout(() => {
|
|
518
|
+
setPresent(false);
|
|
519
|
+
setLeaving(false);
|
|
520
|
+
}, duration + EXIT_FRAME_BUDGET);
|
|
521
|
+
return () => clearTimeout(timer);
|
|
522
|
+
}, [open, present, speed]);
|
|
523
|
+
return {
|
|
524
|
+
present,
|
|
525
|
+
leaving,
|
|
526
|
+
state: leaving ? "closed" : "open",
|
|
527
|
+
ref
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
|
|
362
531
|
// src/molecules/Alert/index.tsx
|
|
363
532
|
import { CheckIcon as CheckIcon2, InfoIcon, WarningIcon, XIcon } from "@phosphor-icons/react";
|
|
364
|
-
import { cn as
|
|
365
|
-
import {
|
|
533
|
+
import { cn as cn17 } from "cn";
|
|
534
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
535
|
+
import { jsx as jsx17, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
366
536
|
var alertIcons = {
|
|
367
|
-
info: /* @__PURE__ */
|
|
368
|
-
success: /* @__PURE__ */
|
|
369
|
-
warning: /* @__PURE__ */
|
|
370
|
-
danger: /* @__PURE__ */
|
|
537
|
+
info: /* @__PURE__ */ jsx17(InfoIcon, { size: 16 }),
|
|
538
|
+
success: /* @__PURE__ */ jsx17(CheckIcon2, { size: 16 }),
|
|
539
|
+
warning: /* @__PURE__ */ jsx17(WarningIcon, { size: 16 }),
|
|
540
|
+
danger: /* @__PURE__ */ jsx17(XIcon, { size: 16 })
|
|
371
541
|
};
|
|
372
542
|
function Alert({
|
|
373
543
|
variant = "info",
|
|
@@ -379,29 +549,53 @@ function Alert({
|
|
|
379
549
|
role,
|
|
380
550
|
...props
|
|
381
551
|
}) {
|
|
552
|
+
const rootRef = useRef2(null);
|
|
553
|
+
const timerRef = useRef2(void 0);
|
|
554
|
+
const [dismissing, setDismissing] = useState3(false);
|
|
555
|
+
useEffect2(
|
|
556
|
+
() => () => {
|
|
557
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
558
|
+
},
|
|
559
|
+
[]
|
|
560
|
+
);
|
|
561
|
+
const requestDismiss = () => {
|
|
562
|
+
if (onDismiss === void 0 || dismissing) return;
|
|
563
|
+
const duration = motionDurationMs(rootRef.current, "fast");
|
|
564
|
+
if (duration <= 0) {
|
|
565
|
+
onDismiss();
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
setDismissing(true);
|
|
569
|
+
timerRef.current = setTimeout(() => {
|
|
570
|
+
setDismissing(false);
|
|
571
|
+
onDismiss();
|
|
572
|
+
}, duration + 40);
|
|
573
|
+
};
|
|
382
574
|
if (title === void 0 && children === void 0) return null;
|
|
383
|
-
return /* @__PURE__ */
|
|
575
|
+
return /* @__PURE__ */ jsxs6(
|
|
384
576
|
"div",
|
|
385
577
|
{
|
|
578
|
+
ref: rootRef,
|
|
386
579
|
...node(props),
|
|
387
|
-
className:
|
|
580
|
+
className: cn17("sph-alert", className),
|
|
388
581
|
"data-variant": variant,
|
|
582
|
+
"data-state": dismissing ? "closed" : "open",
|
|
389
583
|
role: role ?? (variant === "danger" ? "alert" : "status"),
|
|
390
584
|
"aria-live": role ? void 0 : variant === "danger" ? "assertive" : "polite",
|
|
391
585
|
children: [
|
|
392
|
-
/* @__PURE__ */
|
|
393
|
-
/* @__PURE__ */
|
|
394
|
-
title !== void 0 && /* @__PURE__ */
|
|
395
|
-
children !== void 0 && /* @__PURE__ */
|
|
586
|
+
/* @__PURE__ */ jsx17("span", { className: "sph-alert__icon", "aria-hidden": "true", children: alertIcons[variant] }),
|
|
587
|
+
/* @__PURE__ */ jsxs6("div", { className: "sph-alert__body", children: [
|
|
588
|
+
title !== void 0 && /* @__PURE__ */ jsx17("p", { className: "sph-alert__title", children: node(title) }),
|
|
589
|
+
children !== void 0 && /* @__PURE__ */ jsx17("div", { className: "sph-alert__content", children: node(children) })
|
|
396
590
|
] }),
|
|
397
|
-
dismissible && /* @__PURE__ */
|
|
591
|
+
dismissible && /* @__PURE__ */ jsx17(
|
|
398
592
|
"button",
|
|
399
593
|
{
|
|
400
594
|
type: "button",
|
|
401
595
|
className: "sph-alert__dismiss",
|
|
402
596
|
"aria-label": "Dismiss notification",
|
|
403
|
-
onClick:
|
|
404
|
-
children: /* @__PURE__ */
|
|
597
|
+
onClick: requestDismiss,
|
|
598
|
+
children: /* @__PURE__ */ jsx17(XIcon, { size: 12, "aria-hidden": "true" })
|
|
405
599
|
}
|
|
406
600
|
)
|
|
407
601
|
]
|
|
@@ -410,9 +604,39 @@ function Alert({
|
|
|
410
604
|
}
|
|
411
605
|
var Notice = Alert;
|
|
412
606
|
|
|
607
|
+
// src/molecules/AvatarGroup/index.tsx
|
|
608
|
+
import { cn as cn18 } from "cn";
|
|
609
|
+
import { jsx as jsx18, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
610
|
+
function AvatarGroup({
|
|
611
|
+
avatars,
|
|
612
|
+
max = 4,
|
|
613
|
+
size = "md",
|
|
614
|
+
className,
|
|
615
|
+
...props
|
|
616
|
+
}) {
|
|
617
|
+
const shown = avatars.slice(0, Math.max(max, 1));
|
|
618
|
+
const overflow = avatars.length - shown.length;
|
|
619
|
+
return /* @__PURE__ */ jsxs7("span", { ...node(props), className: cn18("sph-avatar-group", className), children: [
|
|
620
|
+
shown.map((avatar, index) => /* @__PURE__ */ jsx18(
|
|
621
|
+
Avatar,
|
|
622
|
+
{
|
|
623
|
+
src: avatar.src,
|
|
624
|
+
name: avatar.name,
|
|
625
|
+
status: avatar.status,
|
|
626
|
+
size
|
|
627
|
+
},
|
|
628
|
+
`${avatar.src ?? avatar.name ?? "avatar"}-${index}`
|
|
629
|
+
)),
|
|
630
|
+
overflow > 0 && /* @__PURE__ */ jsxs7("span", { className: "sph-avatar sph-avatar--overflow", "data-size": size, children: [
|
|
631
|
+
"+",
|
|
632
|
+
overflow
|
|
633
|
+
] })
|
|
634
|
+
] });
|
|
635
|
+
}
|
|
636
|
+
|
|
413
637
|
// src/molecules/Card/index.tsx
|
|
414
|
-
import { cn as
|
|
415
|
-
import { jsx as
|
|
638
|
+
import { cn as cn19 } from "cn";
|
|
639
|
+
import { jsx as jsx19, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
416
640
|
function Card({
|
|
417
641
|
title,
|
|
418
642
|
description,
|
|
@@ -425,62 +649,707 @@ function Card({
|
|
|
425
649
|
...props
|
|
426
650
|
}) {
|
|
427
651
|
const hasHeader = header !== void 0 || title !== void 0 || description !== void 0;
|
|
428
|
-
return /* @__PURE__ */
|
|
652
|
+
return /* @__PURE__ */ jsxs8(
|
|
429
653
|
"article",
|
|
430
654
|
{
|
|
431
655
|
...node(props),
|
|
432
|
-
className:
|
|
656
|
+
className: cn19("sph-card", className),
|
|
433
657
|
"data-interactive": interactive || void 0,
|
|
434
658
|
"data-selected": selected || void 0,
|
|
435
659
|
children: [
|
|
436
|
-
hasHeader && /* @__PURE__ */
|
|
660
|
+
hasHeader && /* @__PURE__ */ jsxs8("header", { className: "sph-card__header", children: [
|
|
437
661
|
node(header),
|
|
438
|
-
title !== void 0 && /* @__PURE__ */
|
|
439
|
-
description !== void 0 && /* @__PURE__ */
|
|
662
|
+
title !== void 0 && /* @__PURE__ */ jsx19("h3", { className: "sph-card__title", children: node(title) }),
|
|
663
|
+
description !== void 0 && /* @__PURE__ */ jsx19("p", { className: "sph-card__description", children: node(description) })
|
|
440
664
|
] }),
|
|
441
|
-
children !== void 0 && /* @__PURE__ */
|
|
442
|
-
footer !== void 0 && /* @__PURE__ */
|
|
665
|
+
children !== void 0 && /* @__PURE__ */ jsx19("div", { className: "sph-card__content", children: node(children) }),
|
|
666
|
+
footer !== void 0 && /* @__PURE__ */ jsx19("footer", { className: "sph-card__footer", children: node(footer) })
|
|
443
667
|
]
|
|
444
668
|
}
|
|
445
669
|
);
|
|
446
670
|
}
|
|
447
671
|
|
|
448
|
-
// src/molecules/
|
|
449
|
-
import {
|
|
450
|
-
import { cn as
|
|
451
|
-
import {
|
|
452
|
-
import { jsx as
|
|
453
|
-
function
|
|
454
|
-
|
|
455
|
-
onClose,
|
|
456
|
-
title,
|
|
457
|
-
description,
|
|
672
|
+
// src/molecules/Collapsible/index.tsx
|
|
673
|
+
import { CaretRightIcon } from "@phosphor-icons/react";
|
|
674
|
+
import { cn as cn20 } from "cn";
|
|
675
|
+
import { useId as useId2, useState as useState4 } from "react";
|
|
676
|
+
import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
677
|
+
function Collapsible({
|
|
678
|
+
trigger,
|
|
458
679
|
children,
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
680
|
+
open,
|
|
681
|
+
defaultOpen = false,
|
|
682
|
+
onOpenChange,
|
|
683
|
+
disabled = false,
|
|
684
|
+
className,
|
|
685
|
+
...props
|
|
686
|
+
}) {
|
|
687
|
+
const [uncontrolled, setUncontrolled] = useState4(defaultOpen);
|
|
688
|
+
const isOpen = open ?? uncontrolled;
|
|
689
|
+
const contentId = `${useId2()}-content`;
|
|
690
|
+
const toggle = () => {
|
|
691
|
+
if (disabled) return;
|
|
692
|
+
const next = !isOpen;
|
|
693
|
+
setUncontrolled(next);
|
|
694
|
+
onOpenChange?.(next);
|
|
695
|
+
};
|
|
696
|
+
return /* @__PURE__ */ jsxs9(
|
|
697
|
+
"div",
|
|
698
|
+
{
|
|
699
|
+
...node(props),
|
|
700
|
+
className: cn20("sph-collapsible", className),
|
|
701
|
+
"data-state": isOpen ? "open" : "closed",
|
|
702
|
+
children: [
|
|
703
|
+
/* @__PURE__ */ jsxs9(
|
|
704
|
+
"button",
|
|
705
|
+
{
|
|
706
|
+
type: "button",
|
|
707
|
+
className: "sph-collapsible__trigger",
|
|
708
|
+
"aria-expanded": isOpen,
|
|
709
|
+
"aria-controls": contentId,
|
|
710
|
+
disabled,
|
|
711
|
+
onClick: toggle,
|
|
712
|
+
children: [
|
|
713
|
+
/* @__PURE__ */ jsx20("span", { className: "sph-collapsible__chevron", "aria-hidden": "true", children: /* @__PURE__ */ jsx20(CaretRightIcon, { size: 13, weight: "bold" }) }),
|
|
714
|
+
node(trigger)
|
|
715
|
+
]
|
|
716
|
+
}
|
|
717
|
+
),
|
|
718
|
+
/* @__PURE__ */ jsx20("div", { className: "sph-collapsible__body", id: contentId, children: /* @__PURE__ */ jsx20("div", { className: "sph-collapsible__inner", children: node(children) }) })
|
|
719
|
+
]
|
|
720
|
+
}
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// src/molecules/Combobox/index.tsx
|
|
725
|
+
import {
|
|
726
|
+
CaretDownIcon,
|
|
727
|
+
CheckIcon as CheckIcon3,
|
|
728
|
+
MagnifyingGlassIcon,
|
|
729
|
+
XIcon as XIcon2
|
|
730
|
+
} from "@phosphor-icons/react";
|
|
731
|
+
import { cn as cn21 } from "cn";
|
|
732
|
+
import { useEffect as useEffect4, useId as useId3, useMemo, useRef as useRef4, useState as useState6 } from "react";
|
|
733
|
+
import { createPortal } from "react-dom";
|
|
734
|
+
|
|
735
|
+
// src/lib/filter.ts
|
|
736
|
+
function matchText(text, query) {
|
|
737
|
+
const needle = query.trim().toLowerCase();
|
|
738
|
+
if (needle.length === 0) return { score: 0, indexes: [] };
|
|
739
|
+
const haystack = text.toLowerCase();
|
|
740
|
+
const indexes = [];
|
|
741
|
+
let score = 0;
|
|
742
|
+
let cursor = 0;
|
|
743
|
+
for (const char of needle) {
|
|
744
|
+
if (char === " ") continue;
|
|
745
|
+
const found = haystack.indexOf(char, cursor);
|
|
746
|
+
if (found < 0) return null;
|
|
747
|
+
indexes.push(found);
|
|
748
|
+
if (found === 0) score += 6;
|
|
749
|
+
const previous = found > 0 ? haystack[found - 1] : "";
|
|
750
|
+
const previousIsBoundary = previous === "" || !/[a-z0-9]/.test(previous);
|
|
751
|
+
if (previousIsBoundary) score += 4;
|
|
752
|
+
if (found === cursor && indexes.length > 1) score += 2;
|
|
753
|
+
score += 1;
|
|
754
|
+
cursor = found + 1;
|
|
755
|
+
}
|
|
756
|
+
score -= Math.min(haystack.length - needle.length, 10) * 0.1;
|
|
757
|
+
return { score, indexes };
|
|
758
|
+
}
|
|
759
|
+
function filterItems(items, query, read) {
|
|
760
|
+
const trimmed = query.trim();
|
|
761
|
+
if (trimmed.length === 0) return items.map((item) => ({ item, indexes: [] }));
|
|
762
|
+
const results = [];
|
|
763
|
+
for (const item of items) {
|
|
764
|
+
const { label, keywords } = read(item);
|
|
765
|
+
const onLabel = matchText(label, trimmed);
|
|
766
|
+
if (onLabel) {
|
|
767
|
+
results.push({ item, indexes: onLabel.indexes });
|
|
768
|
+
continue;
|
|
769
|
+
}
|
|
770
|
+
if (keywords && matchText(keywords, trimmed)) {
|
|
771
|
+
results.push({ item, indexes: [] });
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
return results;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// src/lib/highlight.tsx
|
|
778
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
779
|
+
function Highlight({
|
|
780
|
+
text,
|
|
781
|
+
indexes
|
|
782
|
+
}) {
|
|
783
|
+
if (indexes.length === 0) return node(text);
|
|
784
|
+
const parts = [];
|
|
785
|
+
let cursor = 0;
|
|
786
|
+
for (const position of indexes) {
|
|
787
|
+
if (position > cursor) parts.push(text.slice(cursor, position));
|
|
788
|
+
parts.push(
|
|
789
|
+
/* @__PURE__ */ jsx21("mark", { className: "sph-match", children: text.slice(position, position + 1) }, position)
|
|
790
|
+
);
|
|
791
|
+
cursor = position + 1;
|
|
792
|
+
}
|
|
793
|
+
if (cursor < text.length) parts.push(text.slice(cursor));
|
|
794
|
+
return node(parts);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// src/lib/overlay.ts
|
|
798
|
+
import { useEffect as useEffect3, useLayoutEffect, useRef as useRef3, useState as useState5 } from "react";
|
|
799
|
+
var useIsoLayoutEffect = typeof document === "undefined" ? useEffect3 : useLayoutEffect;
|
|
800
|
+
function clamp(value, min, max) {
|
|
801
|
+
const low = Math.min(min, max);
|
|
802
|
+
const high = Math.max(min, max);
|
|
803
|
+
return Math.min(Math.max(value, low), high);
|
|
804
|
+
}
|
|
805
|
+
function resolvePlacement(trigger, content, viewport, placement) {
|
|
806
|
+
const { side: wanted, align, offset, padding } = placement;
|
|
807
|
+
let side = wanted;
|
|
808
|
+
if (side === "left" || side === "right") {
|
|
809
|
+
const need = content.width + offset + padding;
|
|
810
|
+
const roomLeft = trigger.left - padding;
|
|
811
|
+
const roomRight = viewport.width - trigger.right - padding;
|
|
812
|
+
if (side === "left" && roomLeft < need && roomRight > roomLeft)
|
|
813
|
+
side = "right";
|
|
814
|
+
else if (side === "right" && roomRight < need && roomLeft > roomRight)
|
|
815
|
+
side = "left";
|
|
816
|
+
} else {
|
|
817
|
+
const need = content.height + offset + padding;
|
|
818
|
+
const roomBelow = viewport.height - trigger.bottom - padding;
|
|
819
|
+
const roomAbove = trigger.top - padding;
|
|
820
|
+
if (side === "bottom" && roomBelow < need && roomAbove > roomBelow)
|
|
821
|
+
side = "top";
|
|
822
|
+
else if (side === "top" && roomAbove < need && roomBelow > roomAbove)
|
|
823
|
+
side = "bottom";
|
|
824
|
+
}
|
|
825
|
+
let left;
|
|
826
|
+
let top;
|
|
827
|
+
if (side === "bottom" || side === "top") {
|
|
828
|
+
top = side === "bottom" ? trigger.bottom + offset : trigger.top - content.height - offset;
|
|
829
|
+
left = align === "start" ? trigger.left : align === "end" ? trigger.right - content.width : trigger.left + (trigger.width - content.width) / 2;
|
|
830
|
+
} else {
|
|
831
|
+
left = side === "right" ? trigger.right + offset : trigger.left - content.width - offset;
|
|
832
|
+
top = trigger.top + (trigger.height - content.height) / 2;
|
|
833
|
+
}
|
|
834
|
+
left = clamp(left, padding, viewport.width - content.width - padding);
|
|
835
|
+
top = clamp(top, padding, viewport.height - content.height - padding);
|
|
836
|
+
return { left: Math.round(left), top: Math.round(top), side };
|
|
837
|
+
}
|
|
838
|
+
function overlayOrigin(side, align) {
|
|
839
|
+
if (side === "left") return "right center";
|
|
840
|
+
if (side === "right") return "left center";
|
|
841
|
+
const edge = side === "bottom" ? "top" : "bottom";
|
|
842
|
+
if (align === "center") return `${edge} center`;
|
|
843
|
+
return `${edge} ${align === "start" ? "left" : "right"}`;
|
|
844
|
+
}
|
|
845
|
+
function usePortaled() {
|
|
846
|
+
const [portaled, setPortaled] = useState5(false);
|
|
847
|
+
useIsoLayoutEffect(() => {
|
|
848
|
+
setPortaled(true);
|
|
849
|
+
}, []);
|
|
850
|
+
return portaled;
|
|
851
|
+
}
|
|
852
|
+
function useOverlayPosition(triggerRef, contentRef, active, placement = {}) {
|
|
853
|
+
const {
|
|
854
|
+
side = "bottom",
|
|
855
|
+
align = "start",
|
|
856
|
+
offset = 4,
|
|
857
|
+
padding = 8,
|
|
858
|
+
matchWidth = false
|
|
859
|
+
} = placement;
|
|
860
|
+
const frameRef = useRef3(null);
|
|
861
|
+
useIsoLayoutEffect(() => {
|
|
862
|
+
if (!active) return;
|
|
863
|
+
const update = () => {
|
|
864
|
+
frameRef.current = null;
|
|
865
|
+
const trigger = triggerRef.current;
|
|
866
|
+
const content = contentRef.current;
|
|
867
|
+
if (!trigger || !content) return;
|
|
868
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
869
|
+
if (matchWidth)
|
|
870
|
+
content.style.width = `${Math.round(triggerRect.width)}px`;
|
|
871
|
+
content.style.position = "fixed";
|
|
872
|
+
const contentSize = {
|
|
873
|
+
width: content.offsetWidth,
|
|
874
|
+
height: content.offsetHeight
|
|
875
|
+
};
|
|
876
|
+
const resolved = resolvePlacement(
|
|
877
|
+
triggerRect,
|
|
878
|
+
contentSize,
|
|
879
|
+
{ width: window.innerWidth, height: window.innerHeight },
|
|
880
|
+
{ side, align, offset, padding }
|
|
881
|
+
);
|
|
882
|
+
const style = content.style;
|
|
883
|
+
style.left = `${resolved.left}px`;
|
|
884
|
+
style.top = `${resolved.top}px`;
|
|
885
|
+
style.right = "auto";
|
|
886
|
+
style.bottom = "auto";
|
|
887
|
+
style.translate = "none";
|
|
888
|
+
style.transformOrigin = overlayOrigin(resolved.side, align);
|
|
889
|
+
content.dataset.side = resolved.side;
|
|
890
|
+
};
|
|
891
|
+
const schedule = () => {
|
|
892
|
+
if (frameRef.current === null)
|
|
893
|
+
frameRef.current = requestAnimationFrame(update);
|
|
894
|
+
};
|
|
895
|
+
update();
|
|
896
|
+
window.addEventListener("resize", schedule);
|
|
897
|
+
document.addEventListener("scroll", schedule, {
|
|
898
|
+
capture: true,
|
|
899
|
+
passive: true
|
|
900
|
+
});
|
|
901
|
+
return () => {
|
|
902
|
+
window.removeEventListener("resize", schedule);
|
|
903
|
+
document.removeEventListener("scroll", schedule, { capture: true });
|
|
904
|
+
if (frameRef.current !== null) cancelAnimationFrame(frameRef.current);
|
|
905
|
+
};
|
|
906
|
+
}, [
|
|
907
|
+
active,
|
|
908
|
+
align,
|
|
909
|
+
matchWidth,
|
|
910
|
+
offset,
|
|
911
|
+
padding,
|
|
912
|
+
side,
|
|
913
|
+
contentRef,
|
|
914
|
+
triggerRef
|
|
915
|
+
]);
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// src/molecules/Combobox/index.tsx
|
|
919
|
+
import { jsx as jsx22, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
920
|
+
function readableLabel(option) {
|
|
921
|
+
return typeof option.label === "string" ? option.label : "";
|
|
922
|
+
}
|
|
923
|
+
function resolveActive(options, wanted) {
|
|
924
|
+
if (options.length === 0) return -1;
|
|
925
|
+
const start = Math.min(Math.max(wanted, 0), options.length - 1);
|
|
926
|
+
const enabled = (index) => !options[index]?.option.disabled;
|
|
927
|
+
if (enabled(start)) return start;
|
|
928
|
+
for (let index = start + 1; index < options.length; index += 1)
|
|
929
|
+
if (enabled(index)) return index;
|
|
930
|
+
for (let index = 0; index < start; index += 1)
|
|
931
|
+
if (enabled(index)) return index;
|
|
932
|
+
return start;
|
|
933
|
+
}
|
|
934
|
+
function Combobox({
|
|
935
|
+
options,
|
|
936
|
+
value,
|
|
937
|
+
values,
|
|
938
|
+
onValueChange,
|
|
939
|
+
onValuesChange,
|
|
940
|
+
placeholder = "Select\u2026",
|
|
941
|
+
searchPlaceholder = "Search\u2026",
|
|
942
|
+
emptyMessage = "No matches.",
|
|
943
|
+
disabled = false,
|
|
944
|
+
size = "md",
|
|
945
|
+
id,
|
|
946
|
+
ariaLabel,
|
|
462
947
|
className
|
|
463
948
|
}) {
|
|
464
|
-
const
|
|
465
|
-
const
|
|
466
|
-
const
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
949
|
+
const generatedId = useId3();
|
|
950
|
+
const controlId = id ?? `sph-combobox-${generatedId}`;
|
|
951
|
+
const listId = `${controlId}-list`;
|
|
952
|
+
const rootRef = useRef4(null);
|
|
953
|
+
const triggerRef = useRef4(null);
|
|
954
|
+
const listRef = useRef4(null);
|
|
955
|
+
const inputRef = useRef4(null);
|
|
956
|
+
const [open, setOpen] = useState6(false);
|
|
957
|
+
const [query, setQuery] = useState6("");
|
|
958
|
+
const [activeState, setActive] = useState6(0);
|
|
959
|
+
const multiple = values !== void 0;
|
|
960
|
+
const selectedValues = multiple ? values ?? [] : value ? [value] : [];
|
|
961
|
+
const {
|
|
962
|
+
present,
|
|
963
|
+
state,
|
|
964
|
+
ref: presenceRef
|
|
965
|
+
} = usePresence(open, "fast");
|
|
966
|
+
const portaled = usePortaled();
|
|
967
|
+
const visible = present && portaled;
|
|
968
|
+
useOverlayPosition(triggerRef, presenceRef, visible, {
|
|
969
|
+
side: "bottom",
|
|
970
|
+
align: "start",
|
|
971
|
+
offset: 4,
|
|
972
|
+
matchWidth: true
|
|
973
|
+
});
|
|
974
|
+
const sections = useMemo(() => {
|
|
975
|
+
const read = (option) => ({
|
|
976
|
+
label: readableLabel(option),
|
|
977
|
+
keywords: option.keywords
|
|
978
|
+
});
|
|
979
|
+
const filtered = filterItems(options, query, read);
|
|
980
|
+
const ungrouped = filtered.filter(
|
|
981
|
+
(entry) => entry.item.group === void 0
|
|
982
|
+
);
|
|
983
|
+
const groupNames = [
|
|
984
|
+
...new Set(
|
|
985
|
+
filtered.map((entry) => entry.item.group).filter((name) => name !== void 0)
|
|
986
|
+
)
|
|
987
|
+
];
|
|
988
|
+
const raw = [
|
|
989
|
+
...ungrouped.length > 0 ? [{ heading: void 0, entries: ungrouped }] : [],
|
|
990
|
+
...groupNames.map((name) => ({
|
|
991
|
+
heading: name,
|
|
992
|
+
entries: filtered.filter((entry) => entry.item.group === name)
|
|
993
|
+
}))
|
|
994
|
+
];
|
|
995
|
+
let order = 0;
|
|
996
|
+
const built = raw.map((section) => ({
|
|
997
|
+
heading: section.heading,
|
|
998
|
+
entries: section.entries.map((entry) => ({
|
|
999
|
+
option: entry.item,
|
|
1000
|
+
indexes: entry.indexes,
|
|
1001
|
+
activeId: `${listId}-option-${order}`,
|
|
1002
|
+
index: order++
|
|
1003
|
+
}))
|
|
1004
|
+
}));
|
|
1005
|
+
return built;
|
|
1006
|
+
}, [listId, options, query]);
|
|
1007
|
+
const flat = sections.flatMap((section) => section.entries);
|
|
1008
|
+
const active = resolveActive(flat, activeState);
|
|
1009
|
+
const close = () => {
|
|
1010
|
+
setOpen(false);
|
|
1011
|
+
setQuery("");
|
|
1012
|
+
};
|
|
1013
|
+
const toggleValue = (option) => {
|
|
1014
|
+
if (option.disabled) return;
|
|
1015
|
+
if (multiple) {
|
|
1016
|
+
const next = selectedValues.includes(option.value) ? selectedValues.filter((entry) => entry !== option.value) : [...selectedValues, option.value];
|
|
1017
|
+
onValuesChange?.(next);
|
|
1018
|
+
setQuery("");
|
|
1019
|
+
setActive(0);
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
onValueChange?.(option.value);
|
|
1023
|
+
close();
|
|
1024
|
+
};
|
|
1025
|
+
const removeValue = (entry) => {
|
|
1026
|
+
onValuesChange?.(selectedValues.filter((item) => item !== entry));
|
|
1027
|
+
};
|
|
1028
|
+
const activate = (index) => {
|
|
1029
|
+
const option = flat[index]?.option;
|
|
1030
|
+
if (!option) return;
|
|
1031
|
+
toggleValue(option);
|
|
1032
|
+
};
|
|
1033
|
+
const move = (direction) => {
|
|
1034
|
+
if (flat.length === 0) return;
|
|
1035
|
+
let index = active < 0 ? 0 : active;
|
|
1036
|
+
for (let step = 0; step < flat.length; step += 1) {
|
|
1037
|
+
index = (index + direction + flat.length) % flat.length;
|
|
1038
|
+
if (!flat[index]?.option.disabled) {
|
|
1039
|
+
setActive(index);
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
useEffect4(() => {
|
|
1045
|
+
if (!open) setQuery("");
|
|
1046
|
+
}, [open]);
|
|
1047
|
+
useEffect4(() => {
|
|
1048
|
+
setActive(0);
|
|
1049
|
+
}, [query]);
|
|
1050
|
+
useEffect4(() => {
|
|
1051
|
+
if (!visible) return;
|
|
1052
|
+
inputRef.current?.setAttribute("spellcheck", "false");
|
|
1053
|
+
requestAnimationFrame(() => inputRef.current?.focus());
|
|
1054
|
+
}, [visible]);
|
|
1055
|
+
useEffect4(() => {
|
|
1056
|
+
if (!visible) return;
|
|
477
1057
|
const handleKeyDown = (event) => {
|
|
478
1058
|
if (event.key === "Escape") {
|
|
479
|
-
|
|
480
|
-
|
|
1059
|
+
event.preventDefault();
|
|
1060
|
+
close();
|
|
481
1061
|
}
|
|
1062
|
+
};
|
|
1063
|
+
const handlePointerDown = (event) => {
|
|
1064
|
+
const target = event.target;
|
|
1065
|
+
if (!rootRef.current?.contains(target) && !presenceRef.current?.contains(target))
|
|
1066
|
+
close();
|
|
1067
|
+
};
|
|
1068
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1069
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
1070
|
+
return () => {
|
|
1071
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
1072
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
1073
|
+
};
|
|
1074
|
+
});
|
|
1075
|
+
useEffect4(() => {
|
|
1076
|
+
if (!visible || active < 0) return;
|
|
1077
|
+
listRef.current?.querySelector('[data-active="true"]')?.scrollIntoView({ block: "nearest" });
|
|
1078
|
+
}, [active, visible]);
|
|
1079
|
+
const handleInputKeyDown = (event) => {
|
|
1080
|
+
if (event.key === "ArrowDown") {
|
|
1081
|
+
event.preventDefault();
|
|
1082
|
+
move(1);
|
|
1083
|
+
} else if (event.key === "ArrowUp") {
|
|
1084
|
+
event.preventDefault();
|
|
1085
|
+
move(-1);
|
|
1086
|
+
} else if (event.key === "Home") {
|
|
1087
|
+
event.preventDefault();
|
|
1088
|
+
setActive(0);
|
|
1089
|
+
} else if (event.key === "End") {
|
|
1090
|
+
event.preventDefault();
|
|
1091
|
+
setActive(flat.length - 1);
|
|
1092
|
+
} else if (event.key === "Enter") {
|
|
1093
|
+
event.preventDefault();
|
|
1094
|
+
if (active >= 0) activate(active);
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
const handleTriggerKeyDown = (event) => {
|
|
1098
|
+
if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
|
|
1099
|
+
event.preventDefault();
|
|
1100
|
+
if (!disabled) setOpen(true);
|
|
1101
|
+
}
|
|
1102
|
+
};
|
|
1103
|
+
const labelOf = (entry) => readableLabel(
|
|
1104
|
+
options.find((option) => option.value === entry) ?? {
|
|
1105
|
+
value: entry,
|
|
1106
|
+
label: entry
|
|
1107
|
+
}
|
|
1108
|
+
);
|
|
1109
|
+
return /* @__PURE__ */ jsxs10(
|
|
1110
|
+
"div",
|
|
1111
|
+
{
|
|
1112
|
+
ref: rootRef,
|
|
1113
|
+
className: cn21("sph-combobox", className),
|
|
1114
|
+
"data-size": size,
|
|
1115
|
+
"data-open": open || void 0,
|
|
1116
|
+
children: [
|
|
1117
|
+
multiple ? /* @__PURE__ */ jsxs10(
|
|
1118
|
+
"div",
|
|
1119
|
+
{
|
|
1120
|
+
className: "sph-combobox__control",
|
|
1121
|
+
onClick: () => {
|
|
1122
|
+
if (!disabled) setOpen((current) => !current);
|
|
1123
|
+
},
|
|
1124
|
+
children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs10("div", { className: "sph-combobox__chips", children: [
|
|
1126
|
+
selectedValues.map((entry) => /* @__PURE__ */ jsxs10("span", { className: "sph-combobox__chip", children: [
|
|
1127
|
+
/* @__PURE__ */ jsx22("span", { className: "sph-combobox__chip-label", children: labelOf(entry) }),
|
|
1128
|
+
/* @__PURE__ */ jsx22(
|
|
1129
|
+
"button",
|
|
1130
|
+
{
|
|
1131
|
+
type: "button",
|
|
1132
|
+
className: "sph-combobox__chip-remove",
|
|
1133
|
+
"aria-label": `Remove ${labelOf(entry)}`,
|
|
1134
|
+
disabled,
|
|
1135
|
+
onClick: (event) => {
|
|
1136
|
+
event.stopPropagation();
|
|
1137
|
+
removeValue(entry);
|
|
1138
|
+
},
|
|
1139
|
+
children: /* @__PURE__ */ jsx22(XIcon2, { size: 10, "aria-hidden": "true" })
|
|
1140
|
+
}
|
|
1141
|
+
)
|
|
1142
|
+
] }, entry)),
|
|
1143
|
+
selectedValues.length === 0 && /* @__PURE__ */ jsx22("span", { className: "sph-combobox__placeholder", children: node(placeholder) })
|
|
1144
|
+
] }),
|
|
1145
|
+
/* @__PURE__ */ jsx22(
|
|
1146
|
+
"button",
|
|
1147
|
+
{
|
|
1148
|
+
type: "button",
|
|
1149
|
+
ref: triggerRef,
|
|
1150
|
+
className: "sph-combobox__toggle",
|
|
1151
|
+
"aria-label": ariaLabel ?? "Open suggestions",
|
|
1152
|
+
"aria-haspopup": "listbox",
|
|
1153
|
+
"aria-expanded": open,
|
|
1154
|
+
"aria-controls": open ? listId : void 0,
|
|
1155
|
+
disabled,
|
|
1156
|
+
onClick: (event) => {
|
|
1157
|
+
event.stopPropagation();
|
|
1158
|
+
if (!disabled) setOpen((current) => !current);
|
|
1159
|
+
},
|
|
1160
|
+
onKeyDown: handleTriggerKeyDown,
|
|
1161
|
+
children: /* @__PURE__ */ jsx22(
|
|
1162
|
+
CaretDownIcon,
|
|
1163
|
+
{
|
|
1164
|
+
className: "sph-combobox__caret",
|
|
1165
|
+
size: 13,
|
|
1166
|
+
"aria-hidden": "true"
|
|
1167
|
+
}
|
|
1168
|
+
)
|
|
1169
|
+
}
|
|
1170
|
+
)
|
|
1171
|
+
]
|
|
1172
|
+
}
|
|
1173
|
+
) : /* @__PURE__ */ jsxs10(
|
|
1174
|
+
"button",
|
|
1175
|
+
{
|
|
1176
|
+
type: "button",
|
|
1177
|
+
ref: triggerRef,
|
|
1178
|
+
className: "sph-combobox__control sph-combobox__control--button",
|
|
1179
|
+
"aria-label": ariaLabel,
|
|
1180
|
+
"aria-haspopup": "listbox",
|
|
1181
|
+
"aria-expanded": open,
|
|
1182
|
+
"aria-controls": open ? listId : void 0,
|
|
1183
|
+
disabled,
|
|
1184
|
+
onClick: () => {
|
|
1185
|
+
if (!disabled) setOpen((current) => !current);
|
|
1186
|
+
},
|
|
1187
|
+
onKeyDown: handleTriggerKeyDown,
|
|
1188
|
+
children: [
|
|
1189
|
+
/* @__PURE__ */ jsx22(
|
|
1190
|
+
"span",
|
|
1191
|
+
{
|
|
1192
|
+
className: selectedValues.length > 0 ? "sph-combobox__value" : "sph-combobox__placeholder",
|
|
1193
|
+
children: selectedValues.length > 0 ? node(
|
|
1194
|
+
options.find((option) => option.value === value)?.label ?? value
|
|
1195
|
+
) : node(placeholder)
|
|
1196
|
+
}
|
|
1197
|
+
),
|
|
1198
|
+
/* @__PURE__ */ jsx22(
|
|
1199
|
+
CaretDownIcon,
|
|
1200
|
+
{
|
|
1201
|
+
className: "sph-combobox__caret",
|
|
1202
|
+
size: 13,
|
|
1203
|
+
"aria-hidden": "true"
|
|
1204
|
+
}
|
|
1205
|
+
)
|
|
1206
|
+
]
|
|
1207
|
+
}
|
|
1208
|
+
),
|
|
1209
|
+
visible && createPortal(
|
|
1210
|
+
/* @__PURE__ */ jsxs10(
|
|
1211
|
+
"div",
|
|
1212
|
+
{
|
|
1213
|
+
ref: presenceRef,
|
|
1214
|
+
className: "sph-combobox__panel",
|
|
1215
|
+
"data-state": state,
|
|
1216
|
+
children: [
|
|
1217
|
+
/* @__PURE__ */ jsxs10("div", { className: "sph-combobox__search", children: [
|
|
1218
|
+
/* @__PURE__ */ jsx22(
|
|
1219
|
+
MagnifyingGlassIcon,
|
|
1220
|
+
{
|
|
1221
|
+
className: "sph-combobox__search-icon",
|
|
1222
|
+
size: 14,
|
|
1223
|
+
"aria-hidden": "true"
|
|
1224
|
+
}
|
|
1225
|
+
),
|
|
1226
|
+
/* @__PURE__ */ jsx22(
|
|
1227
|
+
"input",
|
|
1228
|
+
{
|
|
1229
|
+
ref: inputRef,
|
|
1230
|
+
className: "sph-combobox__input",
|
|
1231
|
+
type: "text",
|
|
1232
|
+
role: "combobox",
|
|
1233
|
+
"aria-expanded": true,
|
|
1234
|
+
"aria-controls": listId,
|
|
1235
|
+
"aria-activedescendant": active >= 0 ? flat[active]?.activeId : void 0,
|
|
1236
|
+
"aria-autocomplete": "list",
|
|
1237
|
+
"aria-label": searchPlaceholder,
|
|
1238
|
+
placeholder: searchPlaceholder,
|
|
1239
|
+
value: query,
|
|
1240
|
+
autoComplete: "off",
|
|
1241
|
+
onChange: (event) => setQuery(event.currentTarget.value),
|
|
1242
|
+
onKeyDown: handleInputKeyDown
|
|
1243
|
+
}
|
|
1244
|
+
)
|
|
1245
|
+
] }),
|
|
1246
|
+
/* @__PURE__ */ jsxs10(
|
|
1247
|
+
"div",
|
|
1248
|
+
{
|
|
1249
|
+
ref: listRef,
|
|
1250
|
+
className: "sph-combobox__list",
|
|
1251
|
+
id: listId,
|
|
1252
|
+
role: "listbox",
|
|
1253
|
+
"aria-label": ariaLabel ?? searchPlaceholder,
|
|
1254
|
+
"aria-multiselectable": multiple || void 0,
|
|
1255
|
+
children: [
|
|
1256
|
+
flat.length === 0 && /* @__PURE__ */ jsx22("div", { className: "sph-combobox__empty", role: "status", children: node(emptyMessage) }),
|
|
1257
|
+
sections.map((section) => /* @__PURE__ */ jsxs10(
|
|
1258
|
+
"div",
|
|
1259
|
+
{
|
|
1260
|
+
className: "sph-combobox__group",
|
|
1261
|
+
role: "group",
|
|
1262
|
+
"aria-labelledby": section.heading !== void 0 ? `${listId}-group-${section.heading}` : void 0,
|
|
1263
|
+
children: [
|
|
1264
|
+
section.heading !== void 0 && /* @__PURE__ */ jsx22(
|
|
1265
|
+
"div",
|
|
1266
|
+
{
|
|
1267
|
+
className: "sph-combobox__heading",
|
|
1268
|
+
id: `${listId}-group-${section.heading}`,
|
|
1269
|
+
children: section.heading
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
section.entries.map((entry) => {
|
|
1273
|
+
const option = entry.option;
|
|
1274
|
+
const isSelected = selectedValues.includes(option.value);
|
|
1275
|
+
return /* @__PURE__ */ jsxs10(
|
|
1276
|
+
"div",
|
|
1277
|
+
{
|
|
1278
|
+
id: entry.activeId,
|
|
1279
|
+
className: "sph-combobox__option",
|
|
1280
|
+
role: "option",
|
|
1281
|
+
"data-index": entry.index,
|
|
1282
|
+
"data-active": entry.index === active ? "true" : void 0,
|
|
1283
|
+
"data-disabled": option.disabled || void 0,
|
|
1284
|
+
"aria-selected": isSelected,
|
|
1285
|
+
"aria-disabled": option.disabled || void 0,
|
|
1286
|
+
onPointerEnter: () => {
|
|
1287
|
+
if (!option.disabled) setActive(entry.index);
|
|
1288
|
+
},
|
|
1289
|
+
onPointerDown: (event) => event.preventDefault(),
|
|
1290
|
+
onClick: () => activate(entry.index),
|
|
1291
|
+
children: [
|
|
1292
|
+
/* @__PURE__ */ jsx22(
|
|
1293
|
+
"span",
|
|
1294
|
+
{
|
|
1295
|
+
className: "sph-combobox__check",
|
|
1296
|
+
"data-checked": isSelected || void 0,
|
|
1297
|
+
"aria-hidden": "true",
|
|
1298
|
+
children: isSelected && /* @__PURE__ */ jsx22(CheckIcon3, { size: 13, weight: "bold" })
|
|
1299
|
+
}
|
|
1300
|
+
),
|
|
1301
|
+
/* @__PURE__ */ jsx22("span", { className: "sph-combobox__label", children: typeof option.label === "string" ? /* @__PURE__ */ jsx22(
|
|
1302
|
+
Highlight,
|
|
1303
|
+
{
|
|
1304
|
+
text: option.label,
|
|
1305
|
+
indexes: entry.indexes
|
|
1306
|
+
}
|
|
1307
|
+
) : node(option.label) })
|
|
1308
|
+
]
|
|
1309
|
+
},
|
|
1310
|
+
option.value
|
|
1311
|
+
);
|
|
1312
|
+
})
|
|
1313
|
+
]
|
|
1314
|
+
},
|
|
1315
|
+
section.heading ?? "section-root"
|
|
1316
|
+
))
|
|
1317
|
+
]
|
|
1318
|
+
}
|
|
1319
|
+
)
|
|
1320
|
+
]
|
|
1321
|
+
}
|
|
1322
|
+
),
|
|
1323
|
+
document.body
|
|
1324
|
+
)
|
|
1325
|
+
]
|
|
1326
|
+
}
|
|
1327
|
+
);
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// src/molecules/Dialog/index.tsx
|
|
1331
|
+
import { XIcon as XIcon3 } from "@phosphor-icons/react";
|
|
1332
|
+
import { cn as cn22 } from "cn";
|
|
1333
|
+
import { useEffect as useEffect6, useId as useId4 } from "react";
|
|
1334
|
+
|
|
1335
|
+
// src/lib/focus.ts
|
|
1336
|
+
import { useEffect as useEffect5 } from "react";
|
|
1337
|
+
var FOCUSABLE_SELECTOR = "button, [href], input, select, textarea, [tabindex]:not([tabindex='-1'])";
|
|
1338
|
+
function focusable(container) {
|
|
1339
|
+
return Array.from(
|
|
1340
|
+
container?.querySelectorAll(FOCUSABLE_SELECTOR) ?? []
|
|
1341
|
+
).filter((element) => !element.hasAttribute("disabled"));
|
|
1342
|
+
}
|
|
1343
|
+
function useFocusTrap(ref, active, initial) {
|
|
1344
|
+
useEffect5(() => {
|
|
1345
|
+
if (!active) return;
|
|
1346
|
+
requestAnimationFrame(() => {
|
|
1347
|
+
const target = initial?.current ?? focusable(ref.current)[0];
|
|
1348
|
+
target?.focus();
|
|
1349
|
+
});
|
|
1350
|
+
const handleKeyDown = (event) => {
|
|
482
1351
|
if (event.key !== "Tab") return;
|
|
483
|
-
const elements = focusable();
|
|
1352
|
+
const elements = focusable(ref.current);
|
|
484
1353
|
if (elements.length === 0) {
|
|
485
1354
|
event.preventDefault();
|
|
486
1355
|
return;
|
|
@@ -497,45 +1366,154 @@ function Dialog({
|
|
|
497
1366
|
};
|
|
498
1367
|
document.addEventListener("keydown", handleKeyDown);
|
|
499
1368
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1369
|
+
}, [active, initial, ref]);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// src/molecules/Dialog/index.tsx
|
|
1373
|
+
import { jsx as jsx23, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1374
|
+
function Dialog({
|
|
1375
|
+
open,
|
|
1376
|
+
onClose,
|
|
1377
|
+
title,
|
|
1378
|
+
description,
|
|
1379
|
+
children,
|
|
1380
|
+
footer,
|
|
1381
|
+
closeLabel = "Close dialog",
|
|
1382
|
+
closeOnOverlayClick = true,
|
|
1383
|
+
className
|
|
1384
|
+
}) {
|
|
1385
|
+
const id = useId4();
|
|
1386
|
+
const titleId = `${id}-title`;
|
|
1387
|
+
const descriptionId = description ? `${id}-description` : void 0;
|
|
1388
|
+
const { present, state, ref: dialogRef } = usePresence(open);
|
|
1389
|
+
useFocusTrap(dialogRef, open);
|
|
1390
|
+
useEffect6(() => {
|
|
1391
|
+
if (!open) return;
|
|
1392
|
+
const handleKeyDown = (event) => {
|
|
1393
|
+
if (event.key === "Escape") onClose();
|
|
1394
|
+
};
|
|
1395
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1396
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
500
1397
|
}, [onClose, open]);
|
|
501
|
-
if (!
|
|
502
|
-
return /* @__PURE__ */
|
|
1398
|
+
if (!present) return null;
|
|
1399
|
+
return /* @__PURE__ */ jsx23(
|
|
503
1400
|
"div",
|
|
504
1401
|
{
|
|
505
1402
|
className: "sph-dialog__backdrop",
|
|
1403
|
+
"data-state": state,
|
|
506
1404
|
role: "presentation",
|
|
507
1405
|
onMouseDown: (event) => {
|
|
508
1406
|
if (closeOnOverlayClick && event.target === event.currentTarget)
|
|
509
1407
|
onClose();
|
|
510
1408
|
},
|
|
511
|
-
children: /* @__PURE__ */
|
|
1409
|
+
children: /* @__PURE__ */ jsxs11(
|
|
512
1410
|
"section",
|
|
513
1411
|
{
|
|
514
1412
|
ref: dialogRef,
|
|
515
|
-
className:
|
|
1413
|
+
className: cn22("sph-dialog", className),
|
|
516
1414
|
role: "dialog",
|
|
517
1415
|
"aria-modal": "true",
|
|
518
1416
|
"aria-labelledby": titleId,
|
|
519
1417
|
"aria-describedby": descriptionId,
|
|
520
1418
|
children: [
|
|
521
|
-
/* @__PURE__ */
|
|
522
|
-
/* @__PURE__ */
|
|
523
|
-
/* @__PURE__ */
|
|
524
|
-
description !== void 0 && /* @__PURE__ */
|
|
1419
|
+
/* @__PURE__ */ jsxs11("header", { className: "sph-dialog__header", children: [
|
|
1420
|
+
/* @__PURE__ */ jsxs11("div", { className: "sph-dialog__heading", children: [
|
|
1421
|
+
/* @__PURE__ */ jsx23("h2", { id: titleId, className: "sph-dialog__title", children: node(title) }),
|
|
1422
|
+
description !== void 0 && /* @__PURE__ */ jsx23("p", { id: descriptionId, className: "sph-dialog__description", children: node(description) })
|
|
525
1423
|
] }),
|
|
526
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsx23(
|
|
527
1425
|
"button",
|
|
528
1426
|
{
|
|
529
1427
|
type: "button",
|
|
530
1428
|
className: "sph-dialog__close",
|
|
531
1429
|
"aria-label": closeLabel,
|
|
532
1430
|
onClick: onClose,
|
|
533
|
-
children: /* @__PURE__ */
|
|
1431
|
+
children: /* @__PURE__ */ jsx23(XIcon3, { size: 14, "aria-hidden": "true" })
|
|
534
1432
|
}
|
|
535
1433
|
)
|
|
536
1434
|
] }),
|
|
537
|
-
children !== void 0 && /* @__PURE__ */
|
|
538
|
-
footer !== void 0 && /* @__PURE__ */
|
|
1435
|
+
children !== void 0 && /* @__PURE__ */ jsx23("div", { className: "sph-dialog__content", children: node(children) }),
|
|
1436
|
+
footer !== void 0 && /* @__PURE__ */ jsx23("footer", { className: "sph-dialog__footer", children: node(footer) })
|
|
1437
|
+
]
|
|
1438
|
+
}
|
|
1439
|
+
)
|
|
1440
|
+
}
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// src/molecules/Drawer/index.tsx
|
|
1445
|
+
import { XIcon as XIcon4 } from "@phosphor-icons/react";
|
|
1446
|
+
import { cn as cn23 } from "cn";
|
|
1447
|
+
import { useEffect as useEffect7, useId as useId5 } from "react";
|
|
1448
|
+
import { jsx as jsx24, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1449
|
+
function Drawer({
|
|
1450
|
+
open,
|
|
1451
|
+
onClose,
|
|
1452
|
+
title,
|
|
1453
|
+
description,
|
|
1454
|
+
children,
|
|
1455
|
+
footer,
|
|
1456
|
+
side = "right",
|
|
1457
|
+
size = "md",
|
|
1458
|
+
closeLabel = "Close panel",
|
|
1459
|
+
closeOnOverlayClick = true,
|
|
1460
|
+
className
|
|
1461
|
+
}) {
|
|
1462
|
+
const id = useId5();
|
|
1463
|
+
const titleId = `${id}-title`;
|
|
1464
|
+
const descriptionId = description ? `${id}-description` : void 0;
|
|
1465
|
+
const { present, state, ref: drawerRef } = usePresence(open);
|
|
1466
|
+
useFocusTrap(drawerRef, open);
|
|
1467
|
+
useEffect7(() => {
|
|
1468
|
+
if (!open) return;
|
|
1469
|
+
const handleKeyDown = (event) => {
|
|
1470
|
+
if (event.key === "Escape") onClose();
|
|
1471
|
+
};
|
|
1472
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1473
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
1474
|
+
}, [onClose, open]);
|
|
1475
|
+
if (!present) return null;
|
|
1476
|
+
return /* @__PURE__ */ jsx24(
|
|
1477
|
+
"div",
|
|
1478
|
+
{
|
|
1479
|
+
className: "sph-drawer__backdrop",
|
|
1480
|
+
"data-state": state,
|
|
1481
|
+
"data-side": side,
|
|
1482
|
+
role: "presentation",
|
|
1483
|
+
onMouseDown: (event) => {
|
|
1484
|
+
if (closeOnOverlayClick && event.target === event.currentTarget)
|
|
1485
|
+
onClose();
|
|
1486
|
+
},
|
|
1487
|
+
children: /* @__PURE__ */ jsxs12(
|
|
1488
|
+
"section",
|
|
1489
|
+
{
|
|
1490
|
+
ref: drawerRef,
|
|
1491
|
+
className: cn23("sph-drawer", className),
|
|
1492
|
+
"data-side": side,
|
|
1493
|
+
"data-size": size,
|
|
1494
|
+
role: "dialog",
|
|
1495
|
+
"aria-modal": "true",
|
|
1496
|
+
"aria-labelledby": titleId,
|
|
1497
|
+
"aria-describedby": descriptionId,
|
|
1498
|
+
children: [
|
|
1499
|
+
/* @__PURE__ */ jsxs12("header", { className: "sph-drawer__header", children: [
|
|
1500
|
+
/* @__PURE__ */ jsxs12("div", { className: "sph-drawer__heading", children: [
|
|
1501
|
+
/* @__PURE__ */ jsx24("h2", { id: titleId, className: "sph-drawer__title", children: node(title) }),
|
|
1502
|
+
description !== void 0 && /* @__PURE__ */ jsx24("p", { id: descriptionId, className: "sph-drawer__description", children: node(description) })
|
|
1503
|
+
] }),
|
|
1504
|
+
/* @__PURE__ */ jsx24(
|
|
1505
|
+
"button",
|
|
1506
|
+
{
|
|
1507
|
+
type: "button",
|
|
1508
|
+
className: "sph-drawer__close",
|
|
1509
|
+
"aria-label": closeLabel,
|
|
1510
|
+
onClick: onClose,
|
|
1511
|
+
children: /* @__PURE__ */ jsx24(XIcon4, { size: 14, "aria-hidden": "true" })
|
|
1512
|
+
}
|
|
1513
|
+
)
|
|
1514
|
+
] }),
|
|
1515
|
+
children !== void 0 && /* @__PURE__ */ jsx24("div", { className: "sph-drawer__content", children: node(children) }),
|
|
1516
|
+
footer !== void 0 && /* @__PURE__ */ jsx24("footer", { className: "sph-drawer__footer", children: node(footer) })
|
|
539
1517
|
]
|
|
540
1518
|
}
|
|
541
1519
|
)
|
|
@@ -544,12 +1522,12 @@ function Dialog({
|
|
|
544
1522
|
}
|
|
545
1523
|
|
|
546
1524
|
// src/molecules/Field/index.tsx
|
|
547
|
-
import { cn as
|
|
548
|
-
import { useId as
|
|
1525
|
+
import { cn as cn25 } from "cn";
|
|
1526
|
+
import { useId as useId6 } from "react";
|
|
549
1527
|
|
|
550
1528
|
// src/molecules/FieldMessage/index.tsx
|
|
551
|
-
import { cn as
|
|
552
|
-
import { jsx as
|
|
1529
|
+
import { cn as cn24 } from "cn";
|
|
1530
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
553
1531
|
function FieldMessage({
|
|
554
1532
|
variant = "hint",
|
|
555
1533
|
className,
|
|
@@ -557,11 +1535,11 @@ function FieldMessage({
|
|
|
557
1535
|
...props
|
|
558
1536
|
}) {
|
|
559
1537
|
if (children === void 0 || children === null) return null;
|
|
560
|
-
return /* @__PURE__ */
|
|
1538
|
+
return /* @__PURE__ */ jsx25(
|
|
561
1539
|
"p",
|
|
562
1540
|
{
|
|
563
1541
|
...node(props),
|
|
564
|
-
className:
|
|
1542
|
+
className: cn24("sph-field-message", className),
|
|
565
1543
|
"data-variant": variant,
|
|
566
1544
|
role: variant === "error" ? "alert" : void 0,
|
|
567
1545
|
children: node(children)
|
|
@@ -570,7 +1548,7 @@ function FieldMessage({
|
|
|
570
1548
|
}
|
|
571
1549
|
|
|
572
1550
|
// src/molecules/Field/index.tsx
|
|
573
|
-
import { jsx as
|
|
1551
|
+
import { jsx as jsx26, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
574
1552
|
function Field({
|
|
575
1553
|
label,
|
|
576
1554
|
htmlFor,
|
|
@@ -581,24 +1559,145 @@ function Field({
|
|
|
581
1559
|
className,
|
|
582
1560
|
children
|
|
583
1561
|
}) {
|
|
584
|
-
const generatedId =
|
|
1562
|
+
const generatedId = useId6();
|
|
585
1563
|
const descriptionId = description ? `${generatedId}-description` : void 0;
|
|
586
1564
|
const messageId = message ? `${generatedId}-message` : void 0;
|
|
587
|
-
return /* @__PURE__ */
|
|
588
|
-
label !== void 0 && /* @__PURE__ */
|
|
589
|
-
/* @__PURE__ */
|
|
590
|
-
required && /* @__PURE__ */
|
|
1565
|
+
return /* @__PURE__ */ jsxs13("div", { className: cn25("sph-field", className), children: [
|
|
1566
|
+
label !== void 0 && /* @__PURE__ */ jsxs13("label", { className: "sph-field__label", htmlFor, children: [
|
|
1567
|
+
/* @__PURE__ */ jsx26("span", { children: node(label) }),
|
|
1568
|
+
required && /* @__PURE__ */ jsx26("span", { className: "sph-field__required", children: "Required" })
|
|
591
1569
|
] }),
|
|
592
|
-
description !== void 0 && description !== null && /* @__PURE__ */
|
|
593
|
-
/* @__PURE__ */
|
|
594
|
-
message !== void 0 && message !== null && /* @__PURE__ */
|
|
1570
|
+
description !== void 0 && description !== null && /* @__PURE__ */ jsx26("p", { id: descriptionId, className: "sph-field__description", children: node(description) }),
|
|
1571
|
+
/* @__PURE__ */ jsx26("div", { className: "sph-field__control", children: node(children) }),
|
|
1572
|
+
message !== void 0 && message !== null && /* @__PURE__ */ jsx26(FieldMessage, { id: messageId, variant: messageType, children: node(message) })
|
|
595
1573
|
] });
|
|
596
1574
|
}
|
|
597
1575
|
|
|
1576
|
+
// src/molecules/HoverCard/index.tsx
|
|
1577
|
+
import { cn as cn26 } from "cn";
|
|
1578
|
+
import { useEffect as useEffect8, useId as useId7, useRef as useRef5, useState as useState7 } from "react";
|
|
1579
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
1580
|
+
import { jsx as jsx27, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1581
|
+
function HoverCard({
|
|
1582
|
+
trigger,
|
|
1583
|
+
children,
|
|
1584
|
+
openDelay = 180,
|
|
1585
|
+
closeDelay = 140,
|
|
1586
|
+
placement = "bottom",
|
|
1587
|
+
ariaLabel = "Hover card",
|
|
1588
|
+
className
|
|
1589
|
+
}) {
|
|
1590
|
+
const id = useId7();
|
|
1591
|
+
const rootRef = useRef5(null);
|
|
1592
|
+
const triggerRef = useRef5(null);
|
|
1593
|
+
const timers = useRef5({});
|
|
1594
|
+
const [open, setOpen] = useState7(false);
|
|
1595
|
+
const {
|
|
1596
|
+
present,
|
|
1597
|
+
state,
|
|
1598
|
+
ref: contentRef
|
|
1599
|
+
} = usePresence(open, "fast");
|
|
1600
|
+
const portaled = usePortaled();
|
|
1601
|
+
useOverlayPosition(triggerRef, contentRef, present && portaled, {
|
|
1602
|
+
side: placement,
|
|
1603
|
+
align: "start",
|
|
1604
|
+
offset: 6
|
|
1605
|
+
});
|
|
1606
|
+
const clearTimers = () => {
|
|
1607
|
+
if (timers.current.open !== void 0)
|
|
1608
|
+
window.clearTimeout(timers.current.open);
|
|
1609
|
+
if (timers.current.close !== void 0)
|
|
1610
|
+
window.clearTimeout(timers.current.close);
|
|
1611
|
+
timers.current = {};
|
|
1612
|
+
};
|
|
1613
|
+
const requestOpen = () => {
|
|
1614
|
+
clearTimers();
|
|
1615
|
+
timers.current.open = window.setTimeout(() => setOpen(true), openDelay);
|
|
1616
|
+
};
|
|
1617
|
+
const requestClose = () => {
|
|
1618
|
+
clearTimers();
|
|
1619
|
+
timers.current.close = window.setTimeout(() => setOpen(false), closeDelay);
|
|
1620
|
+
};
|
|
1621
|
+
useEffect8(() => clearTimers, []);
|
|
1622
|
+
useEffect8(() => {
|
|
1623
|
+
if (!present || !portaled) return;
|
|
1624
|
+
const closeNow = () => {
|
|
1625
|
+
clearTimers();
|
|
1626
|
+
setOpen(false);
|
|
1627
|
+
};
|
|
1628
|
+
const handleKeyDown = (event) => {
|
|
1629
|
+
if (event.key === "Escape") closeNow();
|
|
1630
|
+
};
|
|
1631
|
+
const handlePointerDown = (event) => {
|
|
1632
|
+
const target = event.target;
|
|
1633
|
+
if (!rootRef.current?.contains(target) && !contentRef.current?.contains(target))
|
|
1634
|
+
closeNow();
|
|
1635
|
+
};
|
|
1636
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
1637
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
1638
|
+
return () => {
|
|
1639
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
1640
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
1641
|
+
};
|
|
1642
|
+
}, [contentRef, present, portaled]);
|
|
1643
|
+
const handleBlur = (event) => {
|
|
1644
|
+
const next = event.relatedTarget;
|
|
1645
|
+
if (next && (rootRef.current?.contains(next) || contentRef.current?.contains(next)))
|
|
1646
|
+
return;
|
|
1647
|
+
clearTimers();
|
|
1648
|
+
setOpen(false);
|
|
1649
|
+
};
|
|
1650
|
+
return /* @__PURE__ */ jsxs14(
|
|
1651
|
+
"div",
|
|
1652
|
+
{
|
|
1653
|
+
ref: rootRef,
|
|
1654
|
+
className: cn26("sph-hover-card", className),
|
|
1655
|
+
"data-open": open || void 0,
|
|
1656
|
+
onPointerEnter: requestOpen,
|
|
1657
|
+
onPointerLeave: requestClose,
|
|
1658
|
+
onBlur: handleBlur,
|
|
1659
|
+
children: [
|
|
1660
|
+
/* @__PURE__ */ jsx27(
|
|
1661
|
+
"button",
|
|
1662
|
+
{
|
|
1663
|
+
type: "button",
|
|
1664
|
+
ref: triggerRef,
|
|
1665
|
+
className: "sph-hover-card__trigger",
|
|
1666
|
+
"aria-haspopup": "dialog",
|
|
1667
|
+
"aria-expanded": open,
|
|
1668
|
+
"aria-controls": open ? id : void 0,
|
|
1669
|
+
onFocus: requestOpen,
|
|
1670
|
+
children: node(trigger)
|
|
1671
|
+
}
|
|
1672
|
+
),
|
|
1673
|
+
present && portaled && createPortal2(
|
|
1674
|
+
/* @__PURE__ */ jsx27(
|
|
1675
|
+
"div",
|
|
1676
|
+
{
|
|
1677
|
+
id,
|
|
1678
|
+
ref: contentRef,
|
|
1679
|
+
className: "sph-hover-card__content",
|
|
1680
|
+
"data-state": state,
|
|
1681
|
+
role: "dialog",
|
|
1682
|
+
"aria-label": ariaLabel,
|
|
1683
|
+
onPointerEnter: clearTimers,
|
|
1684
|
+
onPointerLeave: requestClose,
|
|
1685
|
+
onBlur: handleBlur,
|
|
1686
|
+
children: node(children)
|
|
1687
|
+
}
|
|
1688
|
+
),
|
|
1689
|
+
document.body
|
|
1690
|
+
)
|
|
1691
|
+
]
|
|
1692
|
+
}
|
|
1693
|
+
);
|
|
1694
|
+
}
|
|
1695
|
+
|
|
598
1696
|
// src/molecules/Menu/index.tsx
|
|
599
|
-
import { cn as
|
|
600
|
-
import { useEffect as
|
|
601
|
-
import {
|
|
1697
|
+
import { cn as cn27 } from "cn";
|
|
1698
|
+
import { useEffect as useEffect9, useId as useId8, useRef as useRef6, useState as useState8 } from "react";
|
|
1699
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
1700
|
+
import { jsx as jsx28, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
602
1701
|
function Menu({
|
|
603
1702
|
trigger,
|
|
604
1703
|
items,
|
|
@@ -608,18 +1707,32 @@ function Menu({
|
|
|
608
1707
|
disabled = false,
|
|
609
1708
|
className
|
|
610
1709
|
}) {
|
|
611
|
-
const rootRef =
|
|
612
|
-
const
|
|
613
|
-
const
|
|
1710
|
+
const rootRef = useRef6(null);
|
|
1711
|
+
const triggerRef = useRef6(null);
|
|
1712
|
+
const menuId = useId8();
|
|
1713
|
+
const [open, setOpen] = useState8(false);
|
|
1714
|
+
const {
|
|
1715
|
+
present,
|
|
1716
|
+
state,
|
|
1717
|
+
ref: contentRef
|
|
1718
|
+
} = usePresence(open, "fast");
|
|
1719
|
+
const portaled = usePortaled();
|
|
1720
|
+
useOverlayPosition(triggerRef, contentRef, present && portaled, {
|
|
1721
|
+
side: "bottom",
|
|
1722
|
+
align,
|
|
1723
|
+
offset: 4
|
|
1724
|
+
});
|
|
614
1725
|
const enabledIndexes = items.flatMap(
|
|
615
1726
|
(item, index) => !item.separator && !item.disabled ? [index] : []
|
|
616
1727
|
);
|
|
617
1728
|
const close = () => setOpen(false);
|
|
618
1729
|
const focusItem = (index) => document.getElementById(`${menuId}-${index}`)?.focus();
|
|
619
|
-
|
|
1730
|
+
useEffect9(() => {
|
|
620
1731
|
if (!open) return;
|
|
621
1732
|
const handlePointerDown = (event) => {
|
|
622
|
-
|
|
1733
|
+
const target = event.target;
|
|
1734
|
+
if (!rootRef.current?.contains(target) && !contentRef.current?.contains(target))
|
|
1735
|
+
close();
|
|
623
1736
|
};
|
|
624
1737
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
625
1738
|
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
@@ -661,58 +1774,75 @@ function Menu({
|
|
|
661
1774
|
const nextIndex = enabledIndexes[nextPosition];
|
|
662
1775
|
if (nextIndex !== void 0) focusItem(nextIndex);
|
|
663
1776
|
};
|
|
664
|
-
return /* @__PURE__ */
|
|
665
|
-
/* @__PURE__ */
|
|
1777
|
+
return /* @__PURE__ */ jsxs15("div", { id: menuId, ref: rootRef, className: cn27("sph-menu", className), children: [
|
|
1778
|
+
/* @__PURE__ */ jsx28(
|
|
666
1779
|
"button",
|
|
667
1780
|
{
|
|
668
1781
|
type: "button",
|
|
1782
|
+
ref: triggerRef,
|
|
669
1783
|
className: "sph-menu__trigger",
|
|
670
1784
|
"aria-label": label,
|
|
671
1785
|
"aria-haspopup": "menu",
|
|
672
1786
|
"aria-expanded": open,
|
|
1787
|
+
"aria-controls": open ? `${menuId}-menu` : void 0,
|
|
673
1788
|
disabled,
|
|
674
1789
|
onClick: () => setOpen((current) => !current),
|
|
675
1790
|
onKeyDown: handleKeyDown,
|
|
676
1791
|
children: node(trigger)
|
|
677
1792
|
}
|
|
678
1793
|
),
|
|
679
|
-
|
|
680
|
-
|
|
1794
|
+
present && portaled && createPortal3(
|
|
1795
|
+
/* @__PURE__ */ jsx28(
|
|
681
1796
|
"div",
|
|
682
1797
|
{
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1798
|
+
id: `${menuId}-menu`,
|
|
1799
|
+
ref: contentRef,
|
|
1800
|
+
className: "sph-menu__content",
|
|
1801
|
+
"data-align": align,
|
|
1802
|
+
"data-state": state,
|
|
1803
|
+
role: "menu",
|
|
1804
|
+
children: items.map(
|
|
1805
|
+
(item, index) => item.separator ? /* @__PURE__ */ jsx28(
|
|
1806
|
+
"div",
|
|
1807
|
+
{
|
|
1808
|
+
className: "sph-menu__separator",
|
|
1809
|
+
role: "separator"
|
|
1810
|
+
},
|
|
1811
|
+
`separator-${index}`
|
|
1812
|
+
) : /* @__PURE__ */ jsxs15(
|
|
1813
|
+
"button",
|
|
1814
|
+
{
|
|
1815
|
+
id: `${menuId}-${index}`,
|
|
1816
|
+
type: "button",
|
|
1817
|
+
role: "menuitem",
|
|
1818
|
+
className: "sph-menu__item",
|
|
1819
|
+
"data-danger": item.danger || void 0,
|
|
1820
|
+
disabled: item.disabled,
|
|
1821
|
+
onClick: () => choose(item),
|
|
1822
|
+
onKeyDown: (event) => handleItemKeyDown(event, index),
|
|
1823
|
+
children: [
|
|
1824
|
+
/* @__PURE__ */ jsxs15("span", { className: "sph-menu__item-label", children: [
|
|
1825
|
+
node(item.icon),
|
|
1826
|
+
/* @__PURE__ */ jsx28("span", { children: node(item.label) })
|
|
1827
|
+
] }),
|
|
1828
|
+
item.shortcut !== void 0 && /* @__PURE__ */ jsx28("span", { className: "sph-menu__shortcut", children: node(item.shortcut) })
|
|
1829
|
+
]
|
|
1830
|
+
},
|
|
1831
|
+
item.value ?? `item-${index}`
|
|
1832
|
+
)
|
|
1833
|
+
)
|
|
1834
|
+
}
|
|
1835
|
+
),
|
|
1836
|
+
document.body
|
|
1837
|
+
)
|
|
709
1838
|
] });
|
|
710
1839
|
}
|
|
711
1840
|
|
|
712
1841
|
// src/molecules/Popover/index.tsx
|
|
713
|
-
import { cn as
|
|
714
|
-
import { useEffect as
|
|
715
|
-
import {
|
|
1842
|
+
import { cn as cn28 } from "cn";
|
|
1843
|
+
import { useEffect as useEffect10, useId as useId9, useRef as useRef7, useState as useState9 } from "react";
|
|
1844
|
+
import { createPortal as createPortal4 } from "react-dom";
|
|
1845
|
+
import { jsx as jsx29, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
716
1846
|
function Popover({
|
|
717
1847
|
trigger,
|
|
718
1848
|
children,
|
|
@@ -724,18 +1854,32 @@ function Popover({
|
|
|
724
1854
|
disabled = false,
|
|
725
1855
|
className
|
|
726
1856
|
}) {
|
|
727
|
-
const id =
|
|
728
|
-
const rootRef =
|
|
729
|
-
const
|
|
1857
|
+
const id = useId9();
|
|
1858
|
+
const rootRef = useRef7(null);
|
|
1859
|
+
const triggerRef = useRef7(null);
|
|
1860
|
+
const [uncontrolledOpen, setUncontrolledOpen] = useState9(defaultOpen);
|
|
730
1861
|
const isOpen = open ?? uncontrolledOpen;
|
|
1862
|
+
const {
|
|
1863
|
+
present,
|
|
1864
|
+
state,
|
|
1865
|
+
ref: contentRef
|
|
1866
|
+
} = usePresence(isOpen, "fast");
|
|
1867
|
+
const portaled = usePortaled();
|
|
1868
|
+
useOverlayPosition(triggerRef, contentRef, present && portaled, {
|
|
1869
|
+
side: "bottom",
|
|
1870
|
+
align: placement,
|
|
1871
|
+
offset: 6
|
|
1872
|
+
});
|
|
731
1873
|
const setOpen = (next) => {
|
|
732
1874
|
setUncontrolledOpen(next);
|
|
733
1875
|
onOpenChange?.(next);
|
|
734
1876
|
};
|
|
735
|
-
|
|
1877
|
+
useEffect10(() => {
|
|
736
1878
|
if (!isOpen) return;
|
|
737
1879
|
const handlePointerDown = (event) => {
|
|
738
|
-
|
|
1880
|
+
const target = event.target;
|
|
1881
|
+
if (!rootRef.current?.contains(target) && !contentRef.current?.contains(target))
|
|
1882
|
+
setOpen(false);
|
|
739
1883
|
};
|
|
740
1884
|
const handleKeyDown = (event) => {
|
|
741
1885
|
if (event.key === "Escape") setOpen(false);
|
|
@@ -753,17 +1897,18 @@ function Popover({
|
|
|
753
1897
|
setOpen(true);
|
|
754
1898
|
}
|
|
755
1899
|
};
|
|
756
|
-
return /* @__PURE__ */
|
|
1900
|
+
return /* @__PURE__ */ jsxs16(
|
|
757
1901
|
"div",
|
|
758
1902
|
{
|
|
759
1903
|
ref: rootRef,
|
|
760
|
-
className:
|
|
1904
|
+
className: cn28("sph-popover", className),
|
|
761
1905
|
"data-open": isOpen || void 0,
|
|
762
1906
|
children: [
|
|
763
|
-
/* @__PURE__ */
|
|
1907
|
+
/* @__PURE__ */ jsx29(
|
|
764
1908
|
"button",
|
|
765
1909
|
{
|
|
766
1910
|
type: "button",
|
|
1911
|
+
ref: triggerRef,
|
|
767
1912
|
className: "sph-popover__trigger",
|
|
768
1913
|
"aria-haspopup": "dialog",
|
|
769
1914
|
"aria-expanded": isOpen,
|
|
@@ -774,16 +1919,21 @@ function Popover({
|
|
|
774
1919
|
children: node(trigger)
|
|
775
1920
|
}
|
|
776
1921
|
),
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1922
|
+
present && portaled && createPortal4(
|
|
1923
|
+
/* @__PURE__ */ jsx29(
|
|
1924
|
+
"div",
|
|
1925
|
+
{
|
|
1926
|
+
id,
|
|
1927
|
+
ref: contentRef,
|
|
1928
|
+
className: "sph-popover__content",
|
|
1929
|
+
"data-placement": placement,
|
|
1930
|
+
"data-state": state,
|
|
1931
|
+
role: "dialog",
|
|
1932
|
+
"aria-label": ariaLabel,
|
|
1933
|
+
children: node(children)
|
|
1934
|
+
}
|
|
1935
|
+
),
|
|
1936
|
+
document.body
|
|
787
1937
|
)
|
|
788
1938
|
]
|
|
789
1939
|
}
|
|
@@ -791,9 +1941,9 @@ function Popover({
|
|
|
791
1941
|
}
|
|
792
1942
|
|
|
793
1943
|
// src/molecules/RadioGroup/index.tsx
|
|
794
|
-
import { cn as
|
|
795
|
-
import { useId as
|
|
796
|
-
import { jsx as
|
|
1944
|
+
import { cn as cn29 } from "cn";
|
|
1945
|
+
import { useId as useId10 } from "react";
|
|
1946
|
+
import { jsx as jsx30, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
797
1947
|
function RadioGroup({
|
|
798
1948
|
value,
|
|
799
1949
|
options,
|
|
@@ -806,29 +1956,29 @@ function RadioGroup({
|
|
|
806
1956
|
disabled = false,
|
|
807
1957
|
className
|
|
808
1958
|
}) {
|
|
809
|
-
const groupId =
|
|
1959
|
+
const groupId = useId10();
|
|
810
1960
|
const descriptionId = description ? `${groupId}-description` : void 0;
|
|
811
|
-
return /* @__PURE__ */
|
|
1961
|
+
return /* @__PURE__ */ jsxs17(
|
|
812
1962
|
"fieldset",
|
|
813
1963
|
{
|
|
814
|
-
className:
|
|
1964
|
+
className: cn29("sph-radio-group", className),
|
|
815
1965
|
"data-size": size,
|
|
816
1966
|
"data-orientation": orientation,
|
|
817
1967
|
disabled,
|
|
818
1968
|
"aria-describedby": descriptionId,
|
|
819
1969
|
children: [
|
|
820
|
-
label !== void 0 && /* @__PURE__ */
|
|
821
|
-
description !== void 0 && /* @__PURE__ */
|
|
822
|
-
/* @__PURE__ */
|
|
1970
|
+
label !== void 0 && /* @__PURE__ */ jsx30("legend", { className: "sph-radio-group__legend", children: node(label) }),
|
|
1971
|
+
description !== void 0 && /* @__PURE__ */ jsx30("p", { id: descriptionId, className: "sph-radio-group__description", children: node(description) }),
|
|
1972
|
+
/* @__PURE__ */ jsx30("div", { className: "sph-radio-group__options", children: options.map((option, index) => {
|
|
823
1973
|
const optionId = `${groupId}-${index}`;
|
|
824
1974
|
const optionDescriptionId = option.description ? `${optionId}-description` : void 0;
|
|
825
|
-
return /* @__PURE__ */
|
|
1975
|
+
return /* @__PURE__ */ jsxs17(
|
|
826
1976
|
"label",
|
|
827
1977
|
{
|
|
828
1978
|
className: "sph-radio-group__option",
|
|
829
1979
|
"data-disabled": option.disabled || void 0,
|
|
830
1980
|
children: [
|
|
831
|
-
/* @__PURE__ */
|
|
1981
|
+
/* @__PURE__ */ jsx30(
|
|
832
1982
|
"input",
|
|
833
1983
|
{
|
|
834
1984
|
id: optionId,
|
|
@@ -841,10 +1991,10 @@ function RadioGroup({
|
|
|
841
1991
|
onChange: () => onValueChange(option.value)
|
|
842
1992
|
}
|
|
843
1993
|
),
|
|
844
|
-
/* @__PURE__ */
|
|
845
|
-
/* @__PURE__ */
|
|
846
|
-
/* @__PURE__ */
|
|
847
|
-
option.description !== void 0 && /* @__PURE__ */
|
|
1994
|
+
/* @__PURE__ */ jsx30("span", { className: "sph-radio-group__control", "aria-hidden": "true" }),
|
|
1995
|
+
/* @__PURE__ */ jsxs17("span", { className: "sph-radio-group__content", children: [
|
|
1996
|
+
/* @__PURE__ */ jsx30("span", { className: "sph-radio-group__label", children: node(option.label) }),
|
|
1997
|
+
option.description !== void 0 && /* @__PURE__ */ jsx30(
|
|
848
1998
|
"span",
|
|
849
1999
|
{
|
|
850
2000
|
id: optionDescriptionId,
|
|
@@ -864,10 +2014,11 @@ function RadioGroup({
|
|
|
864
2014
|
}
|
|
865
2015
|
|
|
866
2016
|
// src/molecules/Select/index.tsx
|
|
867
|
-
import { CaretDownIcon
|
|
868
|
-
import { cn as
|
|
869
|
-
import { useEffect as
|
|
870
|
-
import {
|
|
2017
|
+
import { CaretDownIcon as CaretDownIcon2, CheckIcon as CheckIcon4 } from "@phosphor-icons/react";
|
|
2018
|
+
import { cn as cn30 } from "cn";
|
|
2019
|
+
import { useEffect as useEffect11, useId as useId11, useRef as useRef8, useState as useState10 } from "react";
|
|
2020
|
+
import { createPortal as createPortal5 } from "react-dom";
|
|
2021
|
+
import { jsx as jsx31, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
871
2022
|
function nextEnabled(options, start, direction) {
|
|
872
2023
|
if (options.length === 0) return -1;
|
|
873
2024
|
for (let step = 1; step <= options.length; step += 1) {
|
|
@@ -888,25 +2039,40 @@ function Select({
|
|
|
888
2039
|
disabled = false,
|
|
889
2040
|
size = "md"
|
|
890
2041
|
}) {
|
|
891
|
-
const generatedId =
|
|
2042
|
+
const generatedId = useId11();
|
|
892
2043
|
const triggerId = id ?? `sph-select-${generatedId}`;
|
|
893
2044
|
const listboxId = `${triggerId}-listbox`;
|
|
894
|
-
const rootRef =
|
|
2045
|
+
const rootRef = useRef8(null);
|
|
2046
|
+
const triggerRef = useRef8(null);
|
|
895
2047
|
const selectedIndex = options.findIndex((option) => option.value === value);
|
|
896
2048
|
const firstEnabled2 = options.findIndex((option) => !option.disabled);
|
|
897
|
-
const [open, setOpen] =
|
|
898
|
-
const
|
|
2049
|
+
const [open, setOpen] = useState10(false);
|
|
2050
|
+
const {
|
|
2051
|
+
present,
|
|
2052
|
+
state,
|
|
2053
|
+
ref: listboxRef
|
|
2054
|
+
} = usePresence(open, "fast");
|
|
2055
|
+
const portaled = usePortaled();
|
|
2056
|
+
useOverlayPosition(triggerRef, listboxRef, present && portaled, {
|
|
2057
|
+
side: "bottom",
|
|
2058
|
+
align: "start",
|
|
2059
|
+
offset: 4,
|
|
2060
|
+
matchWidth: true
|
|
2061
|
+
});
|
|
2062
|
+
const [activeIndex, setActiveIndex] = useState10(
|
|
899
2063
|
selectedIndex >= 0 ? selectedIndex : firstEnabled2
|
|
900
2064
|
);
|
|
901
|
-
|
|
2065
|
+
useEffect11(() => {
|
|
902
2066
|
if (!open) return;
|
|
903
2067
|
const close = (event) => {
|
|
904
|
-
|
|
2068
|
+
const target = event.target;
|
|
2069
|
+
if (!rootRef.current?.contains(target) && !listboxRef.current?.contains(target))
|
|
2070
|
+
setOpen(false);
|
|
905
2071
|
};
|
|
906
2072
|
document.addEventListener("pointerdown", close);
|
|
907
2073
|
return () => document.removeEventListener("pointerdown", close);
|
|
908
2074
|
}, [open]);
|
|
909
|
-
|
|
2075
|
+
useEffect11(() => {
|
|
910
2076
|
if (!open)
|
|
911
2077
|
setActiveIndex(selectedIndex >= 0 ? selectedIndex : firstEnabled2);
|
|
912
2078
|
}, [firstEnabled2, open, selectedIndex]);
|
|
@@ -946,12 +2112,13 @@ function Select({
|
|
|
946
2112
|
}
|
|
947
2113
|
}
|
|
948
2114
|
const selected = selectedIndex >= 0 ? options[selectedIndex] : void 0;
|
|
949
|
-
return /* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
2115
|
+
return /* @__PURE__ */ jsxs18("div", { ref: rootRef, className: cn30("sph-select", className), "data-size": size, children: [
|
|
2116
|
+
/* @__PURE__ */ jsxs18(
|
|
951
2117
|
"button",
|
|
952
2118
|
{
|
|
953
2119
|
id: triggerId,
|
|
954
2120
|
type: "button",
|
|
2121
|
+
ref: triggerRef,
|
|
955
2122
|
className: "sph-select__trigger",
|
|
956
2123
|
"aria-label": ariaLabel,
|
|
957
2124
|
"aria-labelledby": ariaLabelledBy,
|
|
@@ -963,37 +2130,57 @@ function Select({
|
|
|
963
2130
|
onClick: () => setOpen((current) => !current),
|
|
964
2131
|
onKeyDown: handleKeyDown,
|
|
965
2132
|
children: [
|
|
966
|
-
/* @__PURE__ */
|
|
967
|
-
|
|
2133
|
+
/* @__PURE__ */ jsx31("span", { className: "sph-select__value", children: node(selected?.label ?? placeholder) }),
|
|
2134
|
+
/* @__PURE__ */ jsx31(
|
|
2135
|
+
CaretDownIcon2,
|
|
2136
|
+
{
|
|
2137
|
+
className: "sph-select__caret",
|
|
2138
|
+
style: { transform: open ? "rotate(180deg)" : void 0 },
|
|
2139
|
+
"aria-hidden": "true"
|
|
2140
|
+
}
|
|
2141
|
+
)
|
|
968
2142
|
]
|
|
969
2143
|
}
|
|
970
2144
|
),
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
2145
|
+
present && portaled && createPortal5(
|
|
2146
|
+
/* @__PURE__ */ jsx31(
|
|
2147
|
+
"div",
|
|
2148
|
+
{
|
|
2149
|
+
id: listboxId,
|
|
2150
|
+
ref: listboxRef,
|
|
2151
|
+
role: "listbox",
|
|
2152
|
+
className: "sph-select__listbox",
|
|
2153
|
+
"data-state": state,
|
|
2154
|
+
children: options.map((option, index) => /* @__PURE__ */ jsxs18(
|
|
2155
|
+
"button",
|
|
2156
|
+
{
|
|
2157
|
+
id: `${listboxId}-${index}`,
|
|
2158
|
+
type: "button",
|
|
2159
|
+
role: "option",
|
|
2160
|
+
"aria-selected": index === selectedIndex,
|
|
2161
|
+
disabled: option.disabled,
|
|
2162
|
+
className: "sph-select__option",
|
|
2163
|
+
"data-active": index === activeIndex || void 0,
|
|
2164
|
+
onPointerMove: () => !option.disabled && setActiveIndex(index),
|
|
2165
|
+
onClick: () => choose(index),
|
|
2166
|
+
children: [
|
|
2167
|
+
/* @__PURE__ */ jsx31("span", { children: node(option.label) }),
|
|
2168
|
+
index === selectedIndex && /* @__PURE__ */ jsx31(CheckIcon4, { className: "sph-select__check", "aria-hidden": "true" })
|
|
2169
|
+
]
|
|
2170
|
+
},
|
|
2171
|
+
option.value
|
|
2172
|
+
))
|
|
2173
|
+
}
|
|
2174
|
+
),
|
|
2175
|
+
document.body
|
|
2176
|
+
)
|
|
990
2177
|
] });
|
|
991
2178
|
}
|
|
992
2179
|
|
|
993
2180
|
// src/molecules/Tabs/index.tsx
|
|
994
|
-
import { cn as
|
|
995
|
-
import { useId as
|
|
996
|
-
import { jsx as
|
|
2181
|
+
import { cn as cn31 } from "cn";
|
|
2182
|
+
import { useId as useId12, useState as useState11 } from "react";
|
|
2183
|
+
import { jsx as jsx32, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
997
2184
|
function firstEnabled(items) {
|
|
998
2185
|
return items.find((item) => !item.disabled)?.value;
|
|
999
2186
|
}
|
|
@@ -1007,8 +2194,8 @@ function Tabs({
|
|
|
1007
2194
|
orientation = "horizontal",
|
|
1008
2195
|
className
|
|
1009
2196
|
}) {
|
|
1010
|
-
const generatedId =
|
|
1011
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
2197
|
+
const generatedId = useId12();
|
|
2198
|
+
const [uncontrolledValue, setUncontrolledValue] = useState11(
|
|
1012
2199
|
defaultValue ?? firstEnabled(items) ?? ""
|
|
1013
2200
|
);
|
|
1014
2201
|
const activeValue = value ?? uncontrolledValue;
|
|
@@ -1036,8 +2223,8 @@ function Tabs({
|
|
|
1036
2223
|
}
|
|
1037
2224
|
};
|
|
1038
2225
|
const panelId = `${generatedId}-panel`;
|
|
1039
|
-
return /* @__PURE__ */
|
|
1040
|
-
/* @__PURE__ */
|
|
2226
|
+
return /* @__PURE__ */ jsxs19("div", { className: cn31("sph-tabs", className), "data-orientation": orientation, children: [
|
|
2227
|
+
/* @__PURE__ */ jsx32(
|
|
1041
2228
|
"div",
|
|
1042
2229
|
{
|
|
1043
2230
|
className: "sph-tabs__list",
|
|
@@ -1046,7 +2233,7 @@ function Tabs({
|
|
|
1046
2233
|
"aria-orientation": orientation,
|
|
1047
2234
|
children: items.map((item, index) => {
|
|
1048
2235
|
const selected = item.value === activeValue;
|
|
1049
|
-
return /* @__PURE__ */
|
|
2236
|
+
return /* @__PURE__ */ jsx32(
|
|
1050
2237
|
"button",
|
|
1051
2238
|
{
|
|
1052
2239
|
id: `${generatedId}-${index}`,
|
|
@@ -1067,7 +2254,7 @@ function Tabs({
|
|
|
1067
2254
|
})
|
|
1068
2255
|
}
|
|
1069
2256
|
),
|
|
1070
|
-
activeItem && (activeItem.content !== void 0 || children !== void 0) && /* @__PURE__ */
|
|
2257
|
+
activeItem && (activeItem.content !== void 0 || children !== void 0) && /* @__PURE__ */ jsx32(
|
|
1071
2258
|
"div",
|
|
1072
2259
|
{
|
|
1073
2260
|
id: panelId,
|
|
@@ -1075,25 +2262,26 @@ function Tabs({
|
|
|
1075
2262
|
role: "tabpanel",
|
|
1076
2263
|
"aria-labelledby": `${generatedId}-${activeIndex}`,
|
|
1077
2264
|
children: node(activeItem.content ?? children)
|
|
1078
|
-
}
|
|
2265
|
+
},
|
|
2266
|
+
activeItem.content !== void 0 ? activeValue : "static"
|
|
1079
2267
|
)
|
|
1080
2268
|
] });
|
|
1081
2269
|
}
|
|
1082
2270
|
|
|
1083
2271
|
// src/molecules/Toast/index.tsx
|
|
1084
|
-
import { CheckIcon as
|
|
1085
|
-
import { cn as
|
|
1086
|
-
import { useEffect as
|
|
2272
|
+
import { CheckIcon as CheckIcon5, InfoIcon as InfoIcon2, WarningIcon as WarningIcon2, XIcon as XIcon5 } from "@phosphor-icons/react";
|
|
2273
|
+
import { cn as cn32 } from "cn";
|
|
2274
|
+
import { useEffect as useEffect12 } from "react";
|
|
1087
2275
|
import {
|
|
1088
2276
|
Toaster as SonnerToaster,
|
|
1089
2277
|
toast
|
|
1090
2278
|
} from "sonner";
|
|
1091
|
-
import { jsx as
|
|
2279
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
1092
2280
|
var toastIcons = {
|
|
1093
|
-
success: /* @__PURE__ */
|
|
1094
|
-
info: /* @__PURE__ */
|
|
1095
|
-
warning: /* @__PURE__ */
|
|
1096
|
-
error: /* @__PURE__ */
|
|
2281
|
+
success: /* @__PURE__ */ jsx33("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx33(CheckIcon5, { size: 20 }) }),
|
|
2282
|
+
info: /* @__PURE__ */ jsx33("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx33(InfoIcon2, { size: 20 }) }),
|
|
2283
|
+
warning: /* @__PURE__ */ jsx33("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx33(WarningIcon2, { size: 20 }) }),
|
|
2284
|
+
error: /* @__PURE__ */ jsx33("span", { className: "sph-toast__status-icon", children: /* @__PURE__ */ jsx33(XIcon5, { size: 20 }) })
|
|
1097
2285
|
};
|
|
1098
2286
|
function Toast({
|
|
1099
2287
|
open = true,
|
|
@@ -1106,7 +2294,7 @@ function Toast({
|
|
|
1106
2294
|
closeButton = true,
|
|
1107
2295
|
className
|
|
1108
2296
|
}) {
|
|
1109
|
-
|
|
2297
|
+
useEffect12(() => {
|
|
1110
2298
|
if (!open) return;
|
|
1111
2299
|
const options = {
|
|
1112
2300
|
id,
|
|
@@ -1114,7 +2302,7 @@ function Toast({
|
|
|
1114
2302
|
closeButton,
|
|
1115
2303
|
description: node(description),
|
|
1116
2304
|
duration,
|
|
1117
|
-
className:
|
|
2305
|
+
className: cn32("sph-toast", className),
|
|
1118
2306
|
unstyled: true
|
|
1119
2307
|
};
|
|
1120
2308
|
const toastId = variant === "success" ? toast.success(node(title), options) : variant === "warning" ? toast.warning(node(title), options) : variant === "danger" ? toast.error(node(title), options) : toast(node(title), options);
|
|
@@ -1134,7 +2322,7 @@ function ToastViewport({
|
|
|
1134
2322
|
expand = false,
|
|
1135
2323
|
...props
|
|
1136
2324
|
}) {
|
|
1137
|
-
return /* @__PURE__ */
|
|
2325
|
+
return /* @__PURE__ */ jsx33(
|
|
1138
2326
|
SonnerToaster,
|
|
1139
2327
|
{
|
|
1140
2328
|
...node(props),
|
|
@@ -1144,12 +2332,12 @@ function ToastViewport({
|
|
|
1144
2332
|
icons: toastIcons,
|
|
1145
2333
|
containerAriaLabel: label,
|
|
1146
2334
|
expand,
|
|
1147
|
-
className:
|
|
2335
|
+
className: cn32("sph-toast-viewport", className),
|
|
1148
2336
|
toastOptions: {
|
|
1149
2337
|
...toastOptions,
|
|
1150
2338
|
closeButton: toastOptions?.closeButton ?? closeButton,
|
|
1151
2339
|
closeButtonAriaLabel: toastOptions?.closeButtonAriaLabel ?? "Dismiss notification",
|
|
1152
|
-
className:
|
|
2340
|
+
className: cn32("sph-toast", toastOptions?.className),
|
|
1153
2341
|
unstyled: true
|
|
1154
2342
|
}
|
|
1155
2343
|
}
|
|
@@ -1157,8 +2345,8 @@ function ToastViewport({
|
|
|
1157
2345
|
}
|
|
1158
2346
|
|
|
1159
2347
|
// src/molecules/Toolbar/index.tsx
|
|
1160
|
-
import { cn as
|
|
1161
|
-
import { jsx as
|
|
2348
|
+
import { cn as cn33 } from "cn";
|
|
2349
|
+
import { jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1162
2350
|
function Toolbar({
|
|
1163
2351
|
label = "Toolbar",
|
|
1164
2352
|
orientation = "horizontal",
|
|
@@ -1169,29 +2357,30 @@ function Toolbar({
|
|
|
1169
2357
|
className,
|
|
1170
2358
|
...props
|
|
1171
2359
|
}) {
|
|
1172
|
-
return /* @__PURE__ */
|
|
2360
|
+
return /* @__PURE__ */ jsxs20(
|
|
1173
2361
|
"div",
|
|
1174
2362
|
{
|
|
1175
2363
|
...node(props),
|
|
1176
|
-
className:
|
|
2364
|
+
className: cn33("sph-toolbar", className),
|
|
1177
2365
|
"data-orientation": orientation,
|
|
1178
2366
|
"data-size": size,
|
|
1179
2367
|
role: "toolbar",
|
|
1180
2368
|
"aria-label": label,
|
|
1181
2369
|
"aria-orientation": orientation,
|
|
1182
2370
|
children: [
|
|
1183
|
-
start !== void 0 && /* @__PURE__ */
|
|
1184
|
-
children !== void 0 && /* @__PURE__ */
|
|
1185
|
-
end !== void 0 && /* @__PURE__ */
|
|
2371
|
+
start !== void 0 && /* @__PURE__ */ jsx34("div", { className: "sph-toolbar__start", children: node(start) }),
|
|
2372
|
+
children !== void 0 && /* @__PURE__ */ jsx34("div", { className: "sph-toolbar__content", children: node(children) }),
|
|
2373
|
+
end !== void 0 && /* @__PURE__ */ jsx34("div", { className: "sph-toolbar__end", children: node(end) })
|
|
1186
2374
|
]
|
|
1187
2375
|
}
|
|
1188
2376
|
);
|
|
1189
2377
|
}
|
|
1190
2378
|
|
|
1191
2379
|
// src/molecules/Tooltip/index.tsx
|
|
1192
|
-
import { cn as
|
|
1193
|
-
import { useId as
|
|
1194
|
-
import {
|
|
2380
|
+
import { cn as cn34 } from "cn";
|
|
2381
|
+
import { useId as useId13, useRef as useRef9, useState as useState12 } from "react";
|
|
2382
|
+
import { createPortal as createPortal6 } from "react-dom";
|
|
2383
|
+
import { jsx as jsx35, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1195
2384
|
function Tooltip({
|
|
1196
2385
|
content,
|
|
1197
2386
|
children,
|
|
@@ -1200,9 +2389,21 @@ function Tooltip({
|
|
|
1200
2389
|
disabled = false,
|
|
1201
2390
|
className
|
|
1202
2391
|
}) {
|
|
1203
|
-
const id =
|
|
1204
|
-
const timerRef =
|
|
1205
|
-
const
|
|
2392
|
+
const id = useId13();
|
|
2393
|
+
const timerRef = useRef9(void 0);
|
|
2394
|
+
const triggerRef = useRef9(null);
|
|
2395
|
+
const [visible, setVisible] = useState12(false);
|
|
2396
|
+
const {
|
|
2397
|
+
present,
|
|
2398
|
+
state,
|
|
2399
|
+
ref: contentRef
|
|
2400
|
+
} = usePresence(visible, "fast");
|
|
2401
|
+
const portaled = usePortaled();
|
|
2402
|
+
useOverlayPosition(triggerRef, contentRef, present && portaled, {
|
|
2403
|
+
side,
|
|
2404
|
+
align: "center",
|
|
2405
|
+
offset: 6
|
|
2406
|
+
});
|
|
1206
2407
|
const show = () => {
|
|
1207
2408
|
if (disabled) return;
|
|
1208
2409
|
timerRef.current = setTimeout(() => setVisible(true), delay);
|
|
@@ -1211,45 +2412,522 @@ function Tooltip({
|
|
|
1211
2412
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1212
2413
|
setVisible(false);
|
|
1213
2414
|
};
|
|
1214
|
-
return /* @__PURE__ */
|
|
2415
|
+
return /* @__PURE__ */ jsxs21(
|
|
1215
2416
|
"span",
|
|
1216
2417
|
{
|
|
1217
|
-
className:
|
|
2418
|
+
className: cn34("sph-tooltip", className),
|
|
1218
2419
|
onMouseEnter: show,
|
|
1219
2420
|
onMouseLeave: hide,
|
|
1220
2421
|
onFocus: show,
|
|
1221
2422
|
onBlur: hide,
|
|
1222
2423
|
children: [
|
|
1223
|
-
/* @__PURE__ */
|
|
2424
|
+
/* @__PURE__ */ jsx35(
|
|
1224
2425
|
"span",
|
|
1225
2426
|
{
|
|
2427
|
+
ref: triggerRef,
|
|
1226
2428
|
className: "sph-tooltip__trigger",
|
|
1227
2429
|
"aria-describedby": visible ? id : void 0,
|
|
1228
2430
|
children: node(children)
|
|
1229
2431
|
}
|
|
1230
2432
|
),
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
2433
|
+
present && portaled && createPortal6(
|
|
2434
|
+
/* @__PURE__ */ jsx35(
|
|
2435
|
+
"span",
|
|
2436
|
+
{
|
|
2437
|
+
id,
|
|
2438
|
+
ref: contentRef,
|
|
2439
|
+
className: "sph-tooltip__content",
|
|
2440
|
+
"data-side": side,
|
|
2441
|
+
"data-state": state,
|
|
2442
|
+
role: "tooltip",
|
|
2443
|
+
children: node(content)
|
|
2444
|
+
}
|
|
2445
|
+
),
|
|
2446
|
+
document.body
|
|
1242
2447
|
)
|
|
1243
2448
|
]
|
|
1244
2449
|
}
|
|
1245
2450
|
);
|
|
1246
2451
|
}
|
|
1247
2452
|
|
|
2453
|
+
// src/organisms/CommandPalette/index.tsx
|
|
2454
|
+
import { CaretRightIcon as CaretRightIcon2, MagnifyingGlassIcon as MagnifyingGlassIcon2 } from "@phosphor-icons/react";
|
|
2455
|
+
import { cn as cn35 } from "cn";
|
|
2456
|
+
import { useEffect as useEffect13, useId as useId14, useMemo as useMemo2, useRef as useRef10, useState as useState13 } from "react";
|
|
2457
|
+
import { createPortal as createPortal7 } from "react-dom";
|
|
2458
|
+
import { jsx as jsx36, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2459
|
+
function replay(element, className) {
|
|
2460
|
+
if (!element) return;
|
|
2461
|
+
element.classList.remove(className);
|
|
2462
|
+
void element.offsetWidth;
|
|
2463
|
+
element.classList.add(className);
|
|
2464
|
+
}
|
|
2465
|
+
function readableLabel2(item) {
|
|
2466
|
+
return typeof item.label === "string" ? item.label : "";
|
|
2467
|
+
}
|
|
2468
|
+
function crumbLabel(item, fallback) {
|
|
2469
|
+
const label = readableLabel2(item);
|
|
2470
|
+
if (label) return label;
|
|
2471
|
+
if (typeof item.value === "string" && item.value) return item.value;
|
|
2472
|
+
return fallback;
|
|
2473
|
+
}
|
|
2474
|
+
function resolveActive2(options, wanted) {
|
|
2475
|
+
if (options.length === 0) return -1;
|
|
2476
|
+
const start = Math.min(Math.max(wanted, 0), options.length - 1);
|
|
2477
|
+
const enabled = (index) => !options[index]?.item.disabled;
|
|
2478
|
+
if (enabled(start)) return start;
|
|
2479
|
+
for (let index = start + 1; index < options.length; index += 1)
|
|
2480
|
+
if (enabled(index)) return index;
|
|
2481
|
+
for (let index = 0; index < start; index += 1)
|
|
2482
|
+
if (enabled(index)) return index;
|
|
2483
|
+
return start;
|
|
2484
|
+
}
|
|
2485
|
+
function CommandPalette({
|
|
2486
|
+
open,
|
|
2487
|
+
onOpenChange,
|
|
2488
|
+
items,
|
|
2489
|
+
onSelect,
|
|
2490
|
+
placeholder = "Type a command or search\u2026",
|
|
2491
|
+
emptyMessage = "No results.",
|
|
2492
|
+
homeLabel = "Home",
|
|
2493
|
+
ariaLabel = "Command palette",
|
|
2494
|
+
hotkey = false,
|
|
2495
|
+
className
|
|
2496
|
+
}) {
|
|
2497
|
+
const listId = useId14();
|
|
2498
|
+
const rootRef = useRef10(null);
|
|
2499
|
+
const panelRef = useRef10(null);
|
|
2500
|
+
const bodyRef = useRef10(null);
|
|
2501
|
+
const innerRef = useRef10(null);
|
|
2502
|
+
const trackRef = useRef10(null);
|
|
2503
|
+
const indicatorRef = useRef10(null);
|
|
2504
|
+
const inputRef = useRef10(null);
|
|
2505
|
+
const previousPathLength = useRef10(null);
|
|
2506
|
+
const heightCleanup = useRef10(null);
|
|
2507
|
+
const [path, setPath] = useState13([]);
|
|
2508
|
+
const [query, setQuery] = useState13("");
|
|
2509
|
+
const [activeState, setActive] = useState13(0);
|
|
2510
|
+
const {
|
|
2511
|
+
present,
|
|
2512
|
+
state,
|
|
2513
|
+
ref: backdropRef
|
|
2514
|
+
} = usePresence(open, "normal");
|
|
2515
|
+
const portaled = usePortaled();
|
|
2516
|
+
const visible = present && portaled;
|
|
2517
|
+
useFocusTrap(rootRef, visible, inputRef);
|
|
2518
|
+
const levelItems = path.length > 0 ? path[path.length - 1]?.children ?? [] : items;
|
|
2519
|
+
const { sections, options } = useMemo2(() => {
|
|
2520
|
+
const read = (item) => ({
|
|
2521
|
+
label: readableLabel2(item),
|
|
2522
|
+
keywords: [
|
|
2523
|
+
item.keywords ?? "",
|
|
2524
|
+
...(item.children ?? []).map((child) => readableLabel2(child))
|
|
2525
|
+
].filter(Boolean).join(" ")
|
|
2526
|
+
});
|
|
2527
|
+
const filtered = filterItems(levelItems, query, read);
|
|
2528
|
+
const ungrouped = filtered.filter(
|
|
2529
|
+
(entry) => entry.item.group === void 0
|
|
2530
|
+
);
|
|
2531
|
+
const groupNames = [
|
|
2532
|
+
...new Set(
|
|
2533
|
+
filtered.map((entry) => entry.item.group).filter((name) => name !== void 0)
|
|
2534
|
+
)
|
|
2535
|
+
];
|
|
2536
|
+
const grouped = groupNames.map((name) => ({
|
|
2537
|
+
heading: name,
|
|
2538
|
+
entries: filtered.filter((entry) => entry.item.group === name)
|
|
2539
|
+
}));
|
|
2540
|
+
const raw = [
|
|
2541
|
+
...ungrouped.length > 0 ? [{ heading: void 0, entries: ungrouped }] : [],
|
|
2542
|
+
...grouped
|
|
2543
|
+
];
|
|
2544
|
+
let order = 0;
|
|
2545
|
+
const built = raw.map((section) => ({
|
|
2546
|
+
heading: section.heading,
|
|
2547
|
+
entries: section.entries.map((entry) => ({
|
|
2548
|
+
item: entry.item,
|
|
2549
|
+
indexes: entry.indexes,
|
|
2550
|
+
activeId: `${listId}-option-${order}`,
|
|
2551
|
+
index: order++
|
|
2552
|
+
}))
|
|
2553
|
+
}));
|
|
2554
|
+
return { sections: built, options: built.flatMap((s) => s.entries) };
|
|
2555
|
+
}, [levelItems, listId, query]);
|
|
2556
|
+
const active = resolveActive2(options, activeState);
|
|
2557
|
+
const close = () => onOpenChange(false);
|
|
2558
|
+
const back = () => {
|
|
2559
|
+
if (query) setQuery("");
|
|
2560
|
+
else if (path.length > 0) setPath(path.slice(0, -1));
|
|
2561
|
+
else close();
|
|
2562
|
+
};
|
|
2563
|
+
const activate = (index) => {
|
|
2564
|
+
const item = options[index]?.item;
|
|
2565
|
+
if (!item || item.disabled) return;
|
|
2566
|
+
if (item.children && item.children.length > 0) {
|
|
2567
|
+
setPath([...path, item]);
|
|
2568
|
+
setQuery("");
|
|
2569
|
+
return;
|
|
2570
|
+
}
|
|
2571
|
+
onSelect?.(item);
|
|
2572
|
+
close();
|
|
2573
|
+
};
|
|
2574
|
+
const move = (direction) => {
|
|
2575
|
+
if (options.length === 0) return;
|
|
2576
|
+
let index = active < 0 ? 0 : active;
|
|
2577
|
+
for (let step = 0; step < options.length; step += 1) {
|
|
2578
|
+
index = (index + direction + options.length) % options.length;
|
|
2579
|
+
if (!options[index]?.item.disabled) {
|
|
2580
|
+
setActive(index);
|
|
2581
|
+
return;
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
};
|
|
2585
|
+
const goToLevel = (length) => {
|
|
2586
|
+
setPath(path.slice(0, length));
|
|
2587
|
+
setQuery("");
|
|
2588
|
+
};
|
|
2589
|
+
const handleInputKeyDown = (event) => {
|
|
2590
|
+
if (event.key === "ArrowDown") {
|
|
2591
|
+
event.preventDefault();
|
|
2592
|
+
move(1);
|
|
2593
|
+
} else if (event.key === "ArrowUp") {
|
|
2594
|
+
event.preventDefault();
|
|
2595
|
+
move(-1);
|
|
2596
|
+
} else if (event.key === "Home") {
|
|
2597
|
+
event.preventDefault();
|
|
2598
|
+
setActive(0);
|
|
2599
|
+
} else if (event.key === "End") {
|
|
2600
|
+
event.preventDefault();
|
|
2601
|
+
setActive(options.length - 1);
|
|
2602
|
+
} else if (event.key === "Enter") {
|
|
2603
|
+
event.preventDefault();
|
|
2604
|
+
if (active >= 0) activate(active);
|
|
2605
|
+
}
|
|
2606
|
+
};
|
|
2607
|
+
useEffect13(() => {
|
|
2608
|
+
if (!open) {
|
|
2609
|
+
setPath([]);
|
|
2610
|
+
setQuery("");
|
|
2611
|
+
setActive(0);
|
|
2612
|
+
}
|
|
2613
|
+
}, [open]);
|
|
2614
|
+
useEffect13(() => {
|
|
2615
|
+
inputRef.current?.setAttribute("spellcheck", "false");
|
|
2616
|
+
}, [visible]);
|
|
2617
|
+
useEffect13(() => {
|
|
2618
|
+
setActive(0);
|
|
2619
|
+
}, [path, query]);
|
|
2620
|
+
useEffect13(() => {
|
|
2621
|
+
if (!hotkey) return;
|
|
2622
|
+
const handleHotkey = (event) => {
|
|
2623
|
+
if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "k") {
|
|
2624
|
+
event.preventDefault();
|
|
2625
|
+
onOpenChange(!open);
|
|
2626
|
+
}
|
|
2627
|
+
};
|
|
2628
|
+
document.addEventListener("keydown", handleHotkey);
|
|
2629
|
+
return () => document.removeEventListener("keydown", handleHotkey);
|
|
2630
|
+
}, [hotkey, onOpenChange, open]);
|
|
2631
|
+
useEffect13(() => {
|
|
2632
|
+
if (!visible) return;
|
|
2633
|
+
const handleKeyDown = (event) => {
|
|
2634
|
+
if (event.key !== "Escape") return;
|
|
2635
|
+
event.preventDefault();
|
|
2636
|
+
if (query) setQuery("");
|
|
2637
|
+
else if (path.length > 0) setPath(path.slice(0, -1));
|
|
2638
|
+
else close();
|
|
2639
|
+
};
|
|
2640
|
+
const handlePointerDown = (event) => {
|
|
2641
|
+
const target = event.target;
|
|
2642
|
+
if (!rootRef.current?.contains(target)) close();
|
|
2643
|
+
};
|
|
2644
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
2645
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
2646
|
+
return () => {
|
|
2647
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
2648
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
2649
|
+
};
|
|
2650
|
+
}, [onOpenChange, path, query, visible]);
|
|
2651
|
+
useEffect13(() => {
|
|
2652
|
+
if (!visible || active < 0) return;
|
|
2653
|
+
const option = trackRef.current?.querySelector(
|
|
2654
|
+
'[data-active="true"]'
|
|
2655
|
+
);
|
|
2656
|
+
option?.scrollIntoView({ block: "nearest" });
|
|
2657
|
+
}, [active, visible]);
|
|
2658
|
+
useIsoLayoutEffect(() => {
|
|
2659
|
+
const indicator = indicatorRef.current;
|
|
2660
|
+
const track = trackRef.current;
|
|
2661
|
+
if (!visible || !indicator || !track || active < 0) return;
|
|
2662
|
+
const option = track.querySelector(`[data-index="${active}"]`);
|
|
2663
|
+
if (!option) return;
|
|
2664
|
+
const trackRect = track.getBoundingClientRect();
|
|
2665
|
+
const optionRect = option.getBoundingClientRect();
|
|
2666
|
+
const first = !indicator.style.width;
|
|
2667
|
+
if (first) indicator.style.transition = "none";
|
|
2668
|
+
indicator.style.opacity = "1";
|
|
2669
|
+
indicator.style.width = `${optionRect.width}px`;
|
|
2670
|
+
indicator.style.height = `${optionRect.height}px`;
|
|
2671
|
+
indicator.style.transform = `translate(${optionRect.left - trackRect.left}px, ${optionRect.top - trackRect.top}px)`;
|
|
2672
|
+
if (first)
|
|
2673
|
+
requestAnimationFrame(() => {
|
|
2674
|
+
indicator.style.transition = "";
|
|
2675
|
+
});
|
|
2676
|
+
}, [active, options, present, portaled]);
|
|
2677
|
+
useIsoLayoutEffect(() => {
|
|
2678
|
+
const body = bodyRef.current;
|
|
2679
|
+
const inner = innerRef.current;
|
|
2680
|
+
if (!visible || !body || !inner) return;
|
|
2681
|
+
heightCleanup.current?.();
|
|
2682
|
+
heightCleanup.current = null;
|
|
2683
|
+
const duration = motionDurationMs(body, "fast");
|
|
2684
|
+
if (duration <= 0) {
|
|
2685
|
+
body.style.height = "";
|
|
2686
|
+
return;
|
|
2687
|
+
}
|
|
2688
|
+
const current = body.style.height ? Number.parseFloat(body.style.height) : body.getBoundingClientRect().height;
|
|
2689
|
+
if (!body.style.height) {
|
|
2690
|
+
body.style.height = `${current}px`;
|
|
2691
|
+
return;
|
|
2692
|
+
}
|
|
2693
|
+
const target = inner.getBoundingClientRect().height;
|
|
2694
|
+
if (Math.abs(current - target) < 1) {
|
|
2695
|
+
body.style.height = `${target}px`;
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2698
|
+
body.style.transition = "none";
|
|
2699
|
+
body.style.height = `${current}px`;
|
|
2700
|
+
void body.offsetHeight;
|
|
2701
|
+
body.style.transition = `height ${duration}ms var(--sph-ease-standard)`;
|
|
2702
|
+
body.style.height = `${target}px`;
|
|
2703
|
+
const settle = () => {
|
|
2704
|
+
body.style.transition = "";
|
|
2705
|
+
heightCleanup.current = null;
|
|
2706
|
+
};
|
|
2707
|
+
body.addEventListener("transitionend", settle, { once: true });
|
|
2708
|
+
heightCleanup.current = () => body.removeEventListener("transitionend", settle);
|
|
2709
|
+
}, [path, present, portaled, query, visible]);
|
|
2710
|
+
useIsoLayoutEffect(() => {
|
|
2711
|
+
if (!visible) {
|
|
2712
|
+
previousPathLength.current = null;
|
|
2713
|
+
return;
|
|
2714
|
+
}
|
|
2715
|
+
const previous = previousPathLength.current;
|
|
2716
|
+
previousPathLength.current = path.length;
|
|
2717
|
+
if (previous === null || previous === path.length) return;
|
|
2718
|
+
replay(panelRef.current, "sph-level-pulse");
|
|
2719
|
+
replay(trackRef.current, "sph-level-fade");
|
|
2720
|
+
}, [path, visible]);
|
|
2721
|
+
if (!visible) return null;
|
|
2722
|
+
return createPortal7(
|
|
2723
|
+
/* @__PURE__ */ jsx36(
|
|
2724
|
+
"div",
|
|
2725
|
+
{
|
|
2726
|
+
ref: backdropRef,
|
|
2727
|
+
className: "sph-palette__backdrop",
|
|
2728
|
+
"data-state": state,
|
|
2729
|
+
role: "presentation",
|
|
2730
|
+
children: /* @__PURE__ */ jsx36(
|
|
2731
|
+
"section",
|
|
2732
|
+
{
|
|
2733
|
+
ref: rootRef,
|
|
2734
|
+
className: cn35("sph-palette", className),
|
|
2735
|
+
role: "dialog",
|
|
2736
|
+
"aria-modal": "true",
|
|
2737
|
+
"aria-label": ariaLabel,
|
|
2738
|
+
children: /* @__PURE__ */ jsxs22("div", { ref: panelRef, className: "sph-palette__panel", children: [
|
|
2739
|
+
/* @__PURE__ */ jsxs22("nav", { className: "sph-palette__crumbs", "aria-label": "Breadcrumb", children: [
|
|
2740
|
+
" ",
|
|
2741
|
+
/* @__PURE__ */ jsx36(
|
|
2742
|
+
"button",
|
|
2743
|
+
{
|
|
2744
|
+
type: "button",
|
|
2745
|
+
className: "sph-palette__crumb sph-motion-in sph-motion-in--blur",
|
|
2746
|
+
"data-current": path.length === 0 || void 0,
|
|
2747
|
+
onClick: () => goToLevel(0),
|
|
2748
|
+
children: homeLabel
|
|
2749
|
+
}
|
|
2750
|
+
),
|
|
2751
|
+
path.flatMap((entry, index) => [
|
|
2752
|
+
/* @__PURE__ */ jsx36(
|
|
2753
|
+
"span",
|
|
2754
|
+
{
|
|
2755
|
+
className: "sph-palette__crumb-sep",
|
|
2756
|
+
"aria-hidden": "true",
|
|
2757
|
+
children: /* @__PURE__ */ jsx36(CaretRightIcon2, { size: 11, weight: "bold" })
|
|
2758
|
+
},
|
|
2759
|
+
`sep-${index}`
|
|
2760
|
+
),
|
|
2761
|
+
/* @__PURE__ */ jsx36(
|
|
2762
|
+
"button",
|
|
2763
|
+
{
|
|
2764
|
+
type: "button",
|
|
2765
|
+
className: "sph-palette__crumb sph-motion-in sph-motion-in--blur",
|
|
2766
|
+
"data-current": index === path.length - 1 || void 0,
|
|
2767
|
+
onClick: () => goToLevel(index + 1),
|
|
2768
|
+
children: crumbLabel(entry, homeLabel)
|
|
2769
|
+
},
|
|
2770
|
+
`crumb-${index}`
|
|
2771
|
+
)
|
|
2772
|
+
])
|
|
2773
|
+
] }),
|
|
2774
|
+
/* @__PURE__ */ jsxs22("div", { className: "sph-palette__search", children: [
|
|
2775
|
+
/* @__PURE__ */ jsx36(
|
|
2776
|
+
MagnifyingGlassIcon2,
|
|
2777
|
+
{
|
|
2778
|
+
className: "sph-palette__search-icon",
|
|
2779
|
+
size: 15,
|
|
2780
|
+
"aria-hidden": "true"
|
|
2781
|
+
}
|
|
2782
|
+
),
|
|
2783
|
+
/* @__PURE__ */ jsx36(
|
|
2784
|
+
"input",
|
|
2785
|
+
{
|
|
2786
|
+
ref: inputRef,
|
|
2787
|
+
className: "sph-palette__input",
|
|
2788
|
+
type: "text",
|
|
2789
|
+
role: "combobox",
|
|
2790
|
+
"aria-expanded": true,
|
|
2791
|
+
"aria-controls": listId,
|
|
2792
|
+
"aria-activedescendant": active >= 0 ? options[active]?.activeId : void 0,
|
|
2793
|
+
"aria-autocomplete": "list",
|
|
2794
|
+
"aria-label": ariaLabel,
|
|
2795
|
+
placeholder,
|
|
2796
|
+
value: query,
|
|
2797
|
+
autoComplete: "off",
|
|
2798
|
+
onChange: (event) => setQuery(event.currentTarget.value),
|
|
2799
|
+
onKeyDown: handleInputKeyDown
|
|
2800
|
+
}
|
|
2801
|
+
),
|
|
2802
|
+
/* @__PURE__ */ jsx36(
|
|
2803
|
+
"button",
|
|
2804
|
+
{
|
|
2805
|
+
type: "button",
|
|
2806
|
+
className: "sph-kbd sph-palette__escape",
|
|
2807
|
+
"aria-label": "Close command palette",
|
|
2808
|
+
onClick: close,
|
|
2809
|
+
children: /* @__PURE__ */ jsx36("span", { className: "sph-kbd__key", children: "Esc" })
|
|
2810
|
+
}
|
|
2811
|
+
)
|
|
2812
|
+
] }),
|
|
2813
|
+
/* @__PURE__ */ jsx36("div", { className: "sph-palette__body", ref: bodyRef, children: /* @__PURE__ */ jsx36(
|
|
2814
|
+
"div",
|
|
2815
|
+
{
|
|
2816
|
+
className: "sph-palette__list",
|
|
2817
|
+
ref: innerRef,
|
|
2818
|
+
id: listId,
|
|
2819
|
+
role: "listbox",
|
|
2820
|
+
"aria-label": ariaLabel,
|
|
2821
|
+
children: /* @__PURE__ */ jsxs22("div", { className: "sph-palette__track", ref: trackRef, children: [
|
|
2822
|
+
/* @__PURE__ */ jsx36(
|
|
2823
|
+
"span",
|
|
2824
|
+
{
|
|
2825
|
+
className: "sph-palette__indicator",
|
|
2826
|
+
ref: indicatorRef,
|
|
2827
|
+
role: "presentation"
|
|
2828
|
+
}
|
|
2829
|
+
),
|
|
2830
|
+
options.length === 0 && /* @__PURE__ */ jsx36("div", { className: "sph-palette__empty", role: "status", children: node(emptyMessage) }),
|
|
2831
|
+
sections.map((section) => /* @__PURE__ */ jsxs22(
|
|
2832
|
+
"div",
|
|
2833
|
+
{
|
|
2834
|
+
className: "sph-palette__group",
|
|
2835
|
+
role: "group",
|
|
2836
|
+
"aria-labelledby": section.heading !== void 0 ? `${listId}-group-${section.heading}` : void 0,
|
|
2837
|
+
children: [
|
|
2838
|
+
section.heading !== void 0 && /* @__PURE__ */ jsx36(
|
|
2839
|
+
"div",
|
|
2840
|
+
{
|
|
2841
|
+
className: "sph-palette__heading",
|
|
2842
|
+
id: `${listId}-group-${section.heading}`,
|
|
2843
|
+
children: section.heading
|
|
2844
|
+
}
|
|
2845
|
+
),
|
|
2846
|
+
section.entries.map((option) => {
|
|
2847
|
+
const item = option.item;
|
|
2848
|
+
const index = option.index;
|
|
2849
|
+
return /* @__PURE__ */ jsxs22(
|
|
2850
|
+
"div",
|
|
2851
|
+
{
|
|
2852
|
+
id: option.activeId,
|
|
2853
|
+
className: "sph-palette__option",
|
|
2854
|
+
role: "option",
|
|
2855
|
+
"data-index": index,
|
|
2856
|
+
"data-active": index === active ? "true" : void 0,
|
|
2857
|
+
"data-disabled": item.disabled || void 0,
|
|
2858
|
+
"aria-selected": index === active,
|
|
2859
|
+
"aria-disabled": item.disabled || void 0,
|
|
2860
|
+
onPointerEnter: () => {
|
|
2861
|
+
if (!item.disabled) setActive(index);
|
|
2862
|
+
},
|
|
2863
|
+
onPointerDown: (event) => event.preventDefault(),
|
|
2864
|
+
onClick: () => activate(index),
|
|
2865
|
+
children: [
|
|
2866
|
+
item.icon !== void 0 && /* @__PURE__ */ jsx36(
|
|
2867
|
+
"span",
|
|
2868
|
+
{
|
|
2869
|
+
className: "sph-palette__icon",
|
|
2870
|
+
"aria-hidden": "true",
|
|
2871
|
+
children: node(item.icon)
|
|
2872
|
+
}
|
|
2873
|
+
),
|
|
2874
|
+
/* @__PURE__ */ jsx36("span", { className: "sph-palette__label", children: typeof item.label === "string" ? /* @__PURE__ */ jsx36(
|
|
2875
|
+
Highlight,
|
|
2876
|
+
{
|
|
2877
|
+
text: item.label,
|
|
2878
|
+
indexes: option.indexes
|
|
2879
|
+
}
|
|
2880
|
+
) : node(item.label) }),
|
|
2881
|
+
item.badge !== void 0 && /* @__PURE__ */ jsx36("span", { className: "sph-palette__badge", children: node(item.badge) }),
|
|
2882
|
+
item.children && item.children.length > 0 ? /* @__PURE__ */ jsx36(
|
|
2883
|
+
"span",
|
|
2884
|
+
{
|
|
2885
|
+
className: "sph-palette__more",
|
|
2886
|
+
"aria-hidden": "true",
|
|
2887
|
+
children: /* @__PURE__ */ jsx36(CaretRightIcon2, { size: 13, weight: "bold" })
|
|
2888
|
+
}
|
|
2889
|
+
) : item.hint !== void 0 ? /* @__PURE__ */ jsx36("span", { className: "sph-palette__hint", children: node(item.hint) }) : item.shortcut !== void 0 && /* @__PURE__ */ jsx36(Kbd, { keys: item.shortcut })
|
|
2890
|
+
]
|
|
2891
|
+
},
|
|
2892
|
+
item.id ?? `${readableLabel2(item)}-${index}`
|
|
2893
|
+
);
|
|
2894
|
+
})
|
|
2895
|
+
]
|
|
2896
|
+
},
|
|
2897
|
+
section.heading ?? "section-root"
|
|
2898
|
+
))
|
|
2899
|
+
] })
|
|
2900
|
+
}
|
|
2901
|
+
) }),
|
|
2902
|
+
/* @__PURE__ */ jsxs22("footer", { className: "sph-palette__footer", "aria-hidden": "true", children: [
|
|
2903
|
+
/* @__PURE__ */ jsxs22("span", { className: "sph-palette__hintrow", children: [
|
|
2904
|
+
/* @__PURE__ */ jsx36(Kbd, { keys: "\u2191" }),
|
|
2905
|
+
/* @__PURE__ */ jsx36(Kbd, { keys: "\u2193" }),
|
|
2906
|
+
"navigate"
|
|
2907
|
+
] }),
|
|
2908
|
+
/* @__PURE__ */ jsxs22("span", { className: "sph-palette__hintrow", children: [
|
|
2909
|
+
/* @__PURE__ */ jsx36(Kbd, { keys: "\u21B5" }),
|
|
2910
|
+
"select"
|
|
2911
|
+
] }),
|
|
2912
|
+
/* @__PURE__ */ jsxs22("span", { className: "sph-palette__hintrow", children: [
|
|
2913
|
+
/* @__PURE__ */ jsx36(Kbd, { keys: "esc" }),
|
|
2914
|
+
path.length > 0 || query ? "back" : "close"
|
|
2915
|
+
] })
|
|
2916
|
+
] })
|
|
2917
|
+
] })
|
|
2918
|
+
}
|
|
2919
|
+
)
|
|
2920
|
+
}
|
|
2921
|
+
),
|
|
2922
|
+
document.body
|
|
2923
|
+
);
|
|
2924
|
+
}
|
|
2925
|
+
|
|
1248
2926
|
// src/organisms/EmptyState/index.tsx
|
|
1249
2927
|
import { TrayIcon } from "@phosphor-icons/react";
|
|
1250
|
-
import { cn as
|
|
1251
|
-
import { jsx as
|
|
1252
|
-
var emptyStateDefaultIcon = /* @__PURE__ */
|
|
2928
|
+
import { cn as cn36 } from "cn";
|
|
2929
|
+
import { jsx as jsx37, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
2930
|
+
var emptyStateDefaultIcon = /* @__PURE__ */ jsx37(TrayIcon, { size: 20 });
|
|
1253
2931
|
function EmptyState({
|
|
1254
2932
|
title,
|
|
1255
2933
|
description,
|
|
@@ -1259,25 +2937,429 @@ function EmptyState({
|
|
|
1259
2937
|
className,
|
|
1260
2938
|
...props
|
|
1261
2939
|
}) {
|
|
1262
|
-
return /* @__PURE__ */
|
|
2940
|
+
return /* @__PURE__ */ jsxs23(
|
|
1263
2941
|
"section",
|
|
1264
2942
|
{
|
|
1265
2943
|
...node(props),
|
|
1266
|
-
className:
|
|
2944
|
+
className: cn36("sph-empty-state", className),
|
|
1267
2945
|
"data-compact": compact || void 0,
|
|
1268
2946
|
children: [
|
|
1269
|
-
/* @__PURE__ */
|
|
1270
|
-
/* @__PURE__ */
|
|
1271
|
-
description !== void 0 && /* @__PURE__ */
|
|
1272
|
-
action !== void 0 && /* @__PURE__ */
|
|
2947
|
+
/* @__PURE__ */ jsx37("div", { className: "sph-empty-state__icon", "aria-hidden": "true", children: node(icon) }),
|
|
2948
|
+
/* @__PURE__ */ jsx37("h2", { className: "sph-empty-state__title", children: node(title) }),
|
|
2949
|
+
description !== void 0 && /* @__PURE__ */ jsx37("p", { className: "sph-empty-state__description", children: node(description) }),
|
|
2950
|
+
action !== void 0 && /* @__PURE__ */ jsx37("div", { className: "sph-empty-state__action", children: node(action) })
|
|
2951
|
+
]
|
|
2952
|
+
}
|
|
2953
|
+
);
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
// src/organisms/MagneticDropzone/index.tsx
|
|
2957
|
+
import { cn as cn37 } from "cn";
|
|
2958
|
+
import { useRef as useRef11, useState as useState14 } from "react";
|
|
2959
|
+
import { jsx as jsx38, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
2960
|
+
function MagneticDropzone({
|
|
2961
|
+
children,
|
|
2962
|
+
activeContent,
|
|
2963
|
+
onFiles,
|
|
2964
|
+
accept,
|
|
2965
|
+
multiple = true,
|
|
2966
|
+
disabled = false,
|
|
2967
|
+
className,
|
|
2968
|
+
...props
|
|
2969
|
+
}) {
|
|
2970
|
+
const zoneRef = useRef11(null);
|
|
2971
|
+
const inputRef = useRef11(null);
|
|
2972
|
+
const [dragging, setDragging] = useState14(false);
|
|
2973
|
+
const pull = (event) => {
|
|
2974
|
+
const zone = zoneRef.current;
|
|
2975
|
+
if (!zone) return;
|
|
2976
|
+
const rect = zone.getBoundingClientRect();
|
|
2977
|
+
const x = ((event.clientX - rect.left) / rect.width - 0.5) * 2;
|
|
2978
|
+
const y = ((event.clientY - rect.top) / rect.height - 0.5) * 2;
|
|
2979
|
+
zone.style.setProperty("--sph-pull-x", `${(x * 10).toFixed(1)}px`);
|
|
2980
|
+
zone.style.setProperty("--sph-pull-y", `${(y * 8).toFixed(1)}px`);
|
|
2981
|
+
};
|
|
2982
|
+
const reset = () => {
|
|
2983
|
+
const zone = zoneRef.current;
|
|
2984
|
+
if (!zone) return;
|
|
2985
|
+
zone.style.setProperty("--sph-pull-x", "0px");
|
|
2986
|
+
zone.style.setProperty("--sph-pull-y", "0px");
|
|
2987
|
+
};
|
|
2988
|
+
const handleDragOver = (event) => {
|
|
2989
|
+
if (disabled) return;
|
|
2990
|
+
event.preventDefault();
|
|
2991
|
+
if (!dragging) setDragging(true);
|
|
2992
|
+
pull(event);
|
|
2993
|
+
};
|
|
2994
|
+
const handleDragLeave = (event) => {
|
|
2995
|
+
const next = event.relatedTarget;
|
|
2996
|
+
if (next && zoneRef.current?.contains(next)) return;
|
|
2997
|
+
setDragging(false);
|
|
2998
|
+
reset();
|
|
2999
|
+
};
|
|
3000
|
+
const handleDrop = (event) => {
|
|
3001
|
+
if (disabled) return;
|
|
3002
|
+
event.preventDefault();
|
|
3003
|
+
setDragging(false);
|
|
3004
|
+
reset();
|
|
3005
|
+
const files = Array.from(event.dataTransfer?.files ?? []);
|
|
3006
|
+
if (files.length > 0) onFiles?.(multiple ? files : files.slice(0, 1));
|
|
3007
|
+
};
|
|
3008
|
+
const openPicker = () => {
|
|
3009
|
+
if (!disabled) inputRef.current?.click();
|
|
3010
|
+
};
|
|
3011
|
+
return /* @__PURE__ */ jsxs24(
|
|
3012
|
+
"div",
|
|
3013
|
+
{
|
|
3014
|
+
...node(props),
|
|
3015
|
+
ref: zoneRef,
|
|
3016
|
+
className: cn37("sph-dropzone", className),
|
|
3017
|
+
"data-active": dragging || void 0,
|
|
3018
|
+
"data-disabled": disabled || void 0,
|
|
3019
|
+
onDragOver: handleDragOver,
|
|
3020
|
+
onDragLeave: handleDragLeave,
|
|
3021
|
+
onDrop: handleDrop,
|
|
3022
|
+
onClick: openPicker,
|
|
3023
|
+
children: [
|
|
3024
|
+
/* @__PURE__ */ jsx38("div", { className: "sph-dropzone__content", children: node(
|
|
3025
|
+
dragging && activeContent !== void 0 ? activeContent : children
|
|
3026
|
+
) }),
|
|
3027
|
+
/* @__PURE__ */ jsx38(
|
|
3028
|
+
"input",
|
|
3029
|
+
{
|
|
3030
|
+
ref: inputRef,
|
|
3031
|
+
className: "sph-dropzone__input",
|
|
3032
|
+
type: "file",
|
|
3033
|
+
accept,
|
|
3034
|
+
multiple,
|
|
3035
|
+
"aria-hidden": "true",
|
|
3036
|
+
tabIndex: -1,
|
|
3037
|
+
disabled,
|
|
3038
|
+
onChange: (event) => {
|
|
3039
|
+
const files = Array.from(event.currentTarget.files ?? []);
|
|
3040
|
+
if (files.length > 0) onFiles?.(multiple ? files : files.slice(0, 1));
|
|
3041
|
+
event.currentTarget.value = "";
|
|
3042
|
+
}
|
|
3043
|
+
}
|
|
3044
|
+
)
|
|
3045
|
+
]
|
|
3046
|
+
}
|
|
3047
|
+
);
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
// src/organisms/ReasoningSteps/index.tsx
|
|
3051
|
+
import { cn as cn38 } from "cn";
|
|
3052
|
+
import { jsx as jsx39, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3053
|
+
function ReasoningSteps({
|
|
3054
|
+
steps,
|
|
3055
|
+
label = "Reasoning",
|
|
3056
|
+
open,
|
|
3057
|
+
defaultOpen = true,
|
|
3058
|
+
onOpenChange,
|
|
3059
|
+
className
|
|
3060
|
+
}) {
|
|
3061
|
+
const activeCount = steps.filter((step) => step.status === "active").length;
|
|
3062
|
+
return /* @__PURE__ */ jsx39("div", { className: cn38("sph-reasoning", className), children: /* @__PURE__ */ jsx39(
|
|
3063
|
+
Collapsible,
|
|
3064
|
+
{
|
|
3065
|
+
open,
|
|
3066
|
+
defaultOpen,
|
|
3067
|
+
onOpenChange,
|
|
3068
|
+
trigger: /* @__PURE__ */ jsxs25("span", { className: "sph-reasoning__trigger", children: [
|
|
3069
|
+
/* @__PURE__ */ jsx39("span", { className: "sph-reasoning__label", children: node(label) }),
|
|
3070
|
+
/* @__PURE__ */ jsxs25("span", { className: "sph-reasoning__meta", children: [
|
|
3071
|
+
activeCount > 0 && /* @__PURE__ */ jsxs25("span", { className: "sph-typing", "aria-hidden": "true", children: [
|
|
3072
|
+
/* @__PURE__ */ jsx39("i", {}),
|
|
3073
|
+
/* @__PURE__ */ jsx39("i", {}),
|
|
3074
|
+
/* @__PURE__ */ jsx39("i", {})
|
|
3075
|
+
] }),
|
|
3076
|
+
/* @__PURE__ */ jsxs25("span", { className: "sph-reasoning__count", children: [
|
|
3077
|
+
steps.length,
|
|
3078
|
+
" ",
|
|
3079
|
+
steps.length === 1 ? "step" : "steps"
|
|
3080
|
+
] })
|
|
3081
|
+
] })
|
|
3082
|
+
] }),
|
|
3083
|
+
children: /* @__PURE__ */ jsx39("ol", { className: "sph-reasoning__list", children: steps.map((step, index) => /* @__PURE__ */ jsxs25(
|
|
3084
|
+
"li",
|
|
3085
|
+
{
|
|
3086
|
+
className: "sph-reasoning__step",
|
|
3087
|
+
"data-status": step.status ?? "done",
|
|
3088
|
+
style: { animationDelay: `${index * 26}ms` },
|
|
3089
|
+
children: [
|
|
3090
|
+
/* @__PURE__ */ jsx39("span", { className: "sph-reasoning__marker", "aria-hidden": "true", children: /* @__PURE__ */ jsx39("span", { className: "sph-reasoning__dot" }) }),
|
|
3091
|
+
/* @__PURE__ */ jsxs25("span", { className: "sph-reasoning__body", children: [
|
|
3092
|
+
/* @__PURE__ */ jsx39("span", { className: "sph-reasoning__title", children: node(step.title) }),
|
|
3093
|
+
step.detail !== void 0 && /* @__PURE__ */ jsx39("span", { className: "sph-reasoning__detail", children: node(step.detail) })
|
|
3094
|
+
] }),
|
|
3095
|
+
/* @__PURE__ */ jsx39("span", { className: "sph-reasoning__status", children: step.status === "active" ? "thinking" : step.status === "pending" ? "queued" : "done" })
|
|
3096
|
+
]
|
|
3097
|
+
},
|
|
3098
|
+
step.id ?? index
|
|
3099
|
+
)) })
|
|
3100
|
+
}
|
|
3101
|
+
) });
|
|
3102
|
+
}
|
|
3103
|
+
|
|
3104
|
+
// src/organisms/Resizable/index.tsx
|
|
3105
|
+
import { cn as cn39 } from "cn";
|
|
3106
|
+
import { useMemo as useMemo3, useRef as useRef12, useState as useState15 } from "react";
|
|
3107
|
+
import { jsx as jsx40 } from "react/jsx-runtime";
|
|
3108
|
+
function clamp2(value, low, high) {
|
|
3109
|
+
return Math.min(Math.max(value, low), high);
|
|
3110
|
+
}
|
|
3111
|
+
function Resizable({
|
|
3112
|
+
panes,
|
|
3113
|
+
direction = "horizontal",
|
|
3114
|
+
sizes,
|
|
3115
|
+
defaultSizes,
|
|
3116
|
+
onSizesChange,
|
|
3117
|
+
min = 10,
|
|
3118
|
+
handleLabel = "Resize panels",
|
|
3119
|
+
className,
|
|
3120
|
+
...props
|
|
3121
|
+
}) {
|
|
3122
|
+
const rootRef = useRef12(null);
|
|
3123
|
+
const [uncontrolled, setUncontrolled] = useState15(
|
|
3124
|
+
() => defaultSizes ?? []
|
|
3125
|
+
);
|
|
3126
|
+
const [dragIndex, setDragIndex] = useState15(null);
|
|
3127
|
+
const drag = useRef12(null);
|
|
3128
|
+
const even = useMemo3(
|
|
3129
|
+
() => panes.map(() => 100 / Math.max(panes.length, 1)),
|
|
3130
|
+
[panes.length]
|
|
3131
|
+
);
|
|
3132
|
+
const candidate = sizes ?? uncontrolled;
|
|
3133
|
+
const active = candidate.length === panes.length && panes.length > 0 ? candidate : even;
|
|
3134
|
+
const commit = (next) => {
|
|
3135
|
+
setUncontrolled(next);
|
|
3136
|
+
onSizesChange?.(next);
|
|
3137
|
+
};
|
|
3138
|
+
const startDrag = (event, index) => {
|
|
3139
|
+
if (event.button !== 0) return;
|
|
3140
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
3141
|
+
if (!rect) return;
|
|
3142
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
3143
|
+
drag.current = {
|
|
3144
|
+
index,
|
|
3145
|
+
pointer: { x: event.clientX, y: event.clientY },
|
|
3146
|
+
sizes: [...active],
|
|
3147
|
+
extent: direction === "horizontal" ? rect.width : rect.height
|
|
3148
|
+
};
|
|
3149
|
+
setDragIndex(index);
|
|
3150
|
+
};
|
|
3151
|
+
const moveDrag = (event) => {
|
|
3152
|
+
const state = drag.current;
|
|
3153
|
+
if (!state || state.extent <= 0) return;
|
|
3154
|
+
const position = direction === "horizontal" ? event.clientX : event.clientY;
|
|
3155
|
+
const origin = direction === "horizontal" ? state.pointer.x : state.pointer.y;
|
|
3156
|
+
const delta = (position - origin) / state.extent * 100;
|
|
3157
|
+
const next = [...state.sizes];
|
|
3158
|
+
const before = next[state.index] ?? 0;
|
|
3159
|
+
const after = next[state.index + 1] ?? 0;
|
|
3160
|
+
const span = before + after;
|
|
3161
|
+
const moved = clamp2(before + delta, min, span - min);
|
|
3162
|
+
next[state.index] = moved;
|
|
3163
|
+
next[state.index + 1] = span - moved;
|
|
3164
|
+
commit(next);
|
|
3165
|
+
};
|
|
3166
|
+
const endDrag = (event) => {
|
|
3167
|
+
if (drag.current === null) return;
|
|
3168
|
+
drag.current = null;
|
|
3169
|
+
setDragIndex(null);
|
|
3170
|
+
if (event.pointerId !== void 0) {
|
|
3171
|
+
try {
|
|
3172
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
3173
|
+
} catch {
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
};
|
|
3177
|
+
const handleKeyDown = (event, index) => {
|
|
3178
|
+
const step = (event.shiftKey ? 10 : 2) * (direction === "horizontal" ? event.key === "ArrowLeft" ? -1 : event.key === "ArrowRight" ? 1 : 0 : event.key === "ArrowUp" ? -1 : event.key === "ArrowDown" ? 1 : 0);
|
|
3179
|
+
if (step === 0) return;
|
|
3180
|
+
event.preventDefault();
|
|
3181
|
+
const next = [...active];
|
|
3182
|
+
const before = next[index] ?? 0;
|
|
3183
|
+
const after = next[index + 1] ?? 0;
|
|
3184
|
+
const span = before + after;
|
|
3185
|
+
const moved = clamp2(before + step, min, span - min);
|
|
3186
|
+
next[index] = moved;
|
|
3187
|
+
next[index + 1] = span - moved;
|
|
3188
|
+
commit(next);
|
|
3189
|
+
};
|
|
3190
|
+
return /* @__PURE__ */ jsx40(
|
|
3191
|
+
"div",
|
|
3192
|
+
{
|
|
3193
|
+
...node(props),
|
|
3194
|
+
ref: rootRef,
|
|
3195
|
+
className: cn39("sph-resizable", className),
|
|
3196
|
+
"data-direction": direction,
|
|
3197
|
+
children: panes.flatMap((pane, index) => {
|
|
3198
|
+
const items = [
|
|
3199
|
+
/* @__PURE__ */ jsx40(
|
|
3200
|
+
"div",
|
|
3201
|
+
{
|
|
3202
|
+
className: "sph-resizable__pane",
|
|
3203
|
+
style: {
|
|
3204
|
+
flexGrow: active[index] ?? even[index] ?? 1,
|
|
3205
|
+
flexBasis: 0,
|
|
3206
|
+
minWidth: 0,
|
|
3207
|
+
minHeight: 0
|
|
3208
|
+
},
|
|
3209
|
+
children: node(pane)
|
|
3210
|
+
},
|
|
3211
|
+
`pane-${index}`
|
|
3212
|
+
)
|
|
3213
|
+
];
|
|
3214
|
+
if (index < panes.length - 1) {
|
|
3215
|
+
items.push(
|
|
3216
|
+
/* @__PURE__ */ jsx40(
|
|
3217
|
+
"div",
|
|
3218
|
+
{
|
|
3219
|
+
role: "separator",
|
|
3220
|
+
tabIndex: 0,
|
|
3221
|
+
"aria-orientation": direction === "horizontal" ? "vertical" : "horizontal",
|
|
3222
|
+
"aria-valuenow": Math.round(active[index] ?? 0),
|
|
3223
|
+
"aria-label": handleLabel,
|
|
3224
|
+
className: "sph-resizable__handle",
|
|
3225
|
+
"data-dragging": dragIndex === index || void 0,
|
|
3226
|
+
onPointerDown: (event) => startDrag(event, index),
|
|
3227
|
+
onPointerMove: moveDrag,
|
|
3228
|
+
onPointerUp: endDrag,
|
|
3229
|
+
onPointerCancel: endDrag,
|
|
3230
|
+
onKeyDown: (event) => handleKeyDown(event, index)
|
|
3231
|
+
},
|
|
3232
|
+
`handle-${index}`
|
|
3233
|
+
)
|
|
3234
|
+
);
|
|
3235
|
+
}
|
|
3236
|
+
return items;
|
|
3237
|
+
})
|
|
3238
|
+
}
|
|
3239
|
+
);
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
// src/organisms/Sidebar/index.tsx
|
|
3243
|
+
import { cn as cn40 } from "cn";
|
|
3244
|
+
import { useId as useId15, useState as useState16 } from "react";
|
|
3245
|
+
import { jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3246
|
+
function Sidebar({
|
|
3247
|
+
sections,
|
|
3248
|
+
value,
|
|
3249
|
+
defaultValue,
|
|
3250
|
+
onSelect,
|
|
3251
|
+
header,
|
|
3252
|
+
footer,
|
|
3253
|
+
collapsible = false,
|
|
3254
|
+
collapsed,
|
|
3255
|
+
defaultCollapsed = false,
|
|
3256
|
+
onCollapsedChange,
|
|
3257
|
+
ariaLabel = "Primary",
|
|
3258
|
+
className,
|
|
3259
|
+
...props
|
|
3260
|
+
}) {
|
|
3261
|
+
const listId = useId15();
|
|
3262
|
+
const [uncontrolled, setUncontrolled] = useState16(defaultCollapsed);
|
|
3263
|
+
const isCollapsed = collapsed ?? uncontrolled;
|
|
3264
|
+
const active = value ?? defaultValue;
|
|
3265
|
+
const toggleCollapsed = () => {
|
|
3266
|
+
const next = !isCollapsed;
|
|
3267
|
+
setUncontrolled(next);
|
|
3268
|
+
onCollapsedChange?.(next);
|
|
3269
|
+
};
|
|
3270
|
+
return /* @__PURE__ */ jsxs26(
|
|
3271
|
+
"aside",
|
|
3272
|
+
{
|
|
3273
|
+
...node(props),
|
|
3274
|
+
className: cn40("sph-sidebar", className),
|
|
3275
|
+
"data-collapsed": isCollapsed || void 0,
|
|
3276
|
+
children: [
|
|
3277
|
+
header !== void 0 && /* @__PURE__ */ jsx41("div", { className: "sph-sidebar__header", children: node(header) }),
|
|
3278
|
+
/* @__PURE__ */ jsxs26("nav", { className: "sph-sidebar__nav", "aria-label": ariaLabel, children: [
|
|
3279
|
+
sections.map((section, sectionIndex) => /* @__PURE__ */ jsxs26(
|
|
3280
|
+
"div",
|
|
3281
|
+
{
|
|
3282
|
+
className: "sph-sidebar__section",
|
|
3283
|
+
children: [
|
|
3284
|
+
section.title !== void 0 && /* @__PURE__ */ jsx41("div", { className: "sph-sidebar__section-title", "aria-hidden": "true", children: section.title }),
|
|
3285
|
+
section.items.map((item) => {
|
|
3286
|
+
const isActive = item.value === active;
|
|
3287
|
+
return /* @__PURE__ */ jsxs26(
|
|
3288
|
+
"button",
|
|
3289
|
+
{
|
|
3290
|
+
type: "button",
|
|
3291
|
+
className: "sph-sidebar__item",
|
|
3292
|
+
"data-active": isActive || void 0,
|
|
3293
|
+
"aria-current": isActive ? "page" : void 0,
|
|
3294
|
+
disabled: item.disabled,
|
|
3295
|
+
title: isCollapsed && typeof item.label === "string" ? item.label : void 0,
|
|
3296
|
+
onClick: () => onSelect?.(item.value),
|
|
3297
|
+
children: [
|
|
3298
|
+
item.icon !== void 0 && /* @__PURE__ */ jsx41("span", { className: "sph-sidebar__icon", "aria-hidden": "true", children: node(item.icon) }),
|
|
3299
|
+
/* @__PURE__ */ jsx41("span", { className: "sph-sidebar__label", children: node(item.label) }),
|
|
3300
|
+
item.badge !== void 0 && /* @__PURE__ */ jsx41("span", { className: "sph-sidebar__badge", children: node(item.badge) })
|
|
3301
|
+
]
|
|
3302
|
+
},
|
|
3303
|
+
item.value
|
|
3304
|
+
);
|
|
3305
|
+
})
|
|
3306
|
+
]
|
|
3307
|
+
},
|
|
3308
|
+
section.title ?? `section-${sectionIndex}`
|
|
3309
|
+
)),
|
|
3310
|
+
/* @__PURE__ */ jsx41("span", { id: `${listId}-hint`, className: "sph-visually-hidden", children: isCollapsed ? "Sidebar collapsed" : "Sidebar expanded" })
|
|
3311
|
+
] }),
|
|
3312
|
+
(footer !== void 0 || collapsible) && /* @__PURE__ */ jsxs26("div", { className: "sph-sidebar__footer", children: [
|
|
3313
|
+
footer !== void 0 && /* @__PURE__ */ jsx41("div", { className: "sph-sidebar__footer-content", children: node(footer) }),
|
|
3314
|
+
collapsible && /* @__PURE__ */ jsx41(
|
|
3315
|
+
"button",
|
|
3316
|
+
{
|
|
3317
|
+
type: "button",
|
|
3318
|
+
className: "sph-sidebar__toggle",
|
|
3319
|
+
"aria-expanded": !isCollapsed,
|
|
3320
|
+
"aria-label": isCollapsed ? "Expand sidebar" : "Collapse sidebar",
|
|
3321
|
+
onClick: toggleCollapsed,
|
|
3322
|
+
children: /* @__PURE__ */ jsx41("span", { "aria-hidden": "true", children: isCollapsed ? "\xBB" : "\xAB" })
|
|
3323
|
+
}
|
|
3324
|
+
)
|
|
3325
|
+
] })
|
|
1273
3326
|
]
|
|
1274
3327
|
}
|
|
1275
3328
|
);
|
|
1276
3329
|
}
|
|
1277
3330
|
|
|
3331
|
+
// src/organisms/StreamingText/index.tsx
|
|
3332
|
+
import { cn as cn41 } from "cn";
|
|
3333
|
+
import { jsx as jsx42 } from "react/jsx-runtime";
|
|
3334
|
+
function StreamingText({
|
|
3335
|
+
text,
|
|
3336
|
+
speed = 30,
|
|
3337
|
+
animated = true,
|
|
3338
|
+
className,
|
|
3339
|
+
...props
|
|
3340
|
+
}) {
|
|
3341
|
+
const tokens = text.split(/(\s+)/);
|
|
3342
|
+
let wordIndex = -1;
|
|
3343
|
+
return /* @__PURE__ */ jsx42("div", { ...node(props), className: cn41("sph-stream", className), children: tokens.map((token, index) => {
|
|
3344
|
+
if (token.trim().length === 0) return token;
|
|
3345
|
+
wordIndex += 1;
|
|
3346
|
+
const delay = animated ? wordIndex * speed : 0;
|
|
3347
|
+
return /* @__PURE__ */ jsx42(
|
|
3348
|
+
"span",
|
|
3349
|
+
{
|
|
3350
|
+
className: "sph-stream__word",
|
|
3351
|
+
"data-animated": animated || void 0,
|
|
3352
|
+
style: { animationDelay: `${delay}ms` },
|
|
3353
|
+
children: token
|
|
3354
|
+
},
|
|
3355
|
+
index
|
|
3356
|
+
);
|
|
3357
|
+
}) });
|
|
3358
|
+
}
|
|
3359
|
+
|
|
1278
3360
|
// src/organisms/Table/index.tsx
|
|
1279
|
-
import { cn as
|
|
1280
|
-
import { jsx as
|
|
3361
|
+
import { cn as cn42 } from "cn";
|
|
3362
|
+
import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1281
3363
|
function Table({
|
|
1282
3364
|
columns,
|
|
1283
3365
|
rows,
|
|
@@ -1290,7 +3372,7 @@ function Table({
|
|
|
1290
3372
|
className,
|
|
1291
3373
|
...props
|
|
1292
3374
|
}) {
|
|
1293
|
-
return /* @__PURE__ */
|
|
3375
|
+
return /* @__PURE__ */ jsx43("div", { className: cn42("sph-table-wrap", className), children: /* @__PURE__ */ jsxs27(
|
|
1294
3376
|
"table",
|
|
1295
3377
|
{
|
|
1296
3378
|
...node(props),
|
|
@@ -1299,8 +3381,8 @@ function Table({
|
|
|
1299
3381
|
"data-striped": striped || void 0,
|
|
1300
3382
|
"data-sticky-header": stickyHeader || void 0,
|
|
1301
3383
|
children: [
|
|
1302
|
-
caption !== void 0 && /* @__PURE__ */
|
|
1303
|
-
/* @__PURE__ */
|
|
3384
|
+
caption !== void 0 && /* @__PURE__ */ jsx43("caption", { children: node(caption) }),
|
|
3385
|
+
/* @__PURE__ */ jsx43("thead", { children: /* @__PURE__ */ jsx43("tr", { children: columns.map((column) => /* @__PURE__ */ jsx43(
|
|
1304
3386
|
"th",
|
|
1305
3387
|
{
|
|
1306
3388
|
scope: "col",
|
|
@@ -1310,7 +3392,7 @@ function Table({
|
|
|
1310
3392
|
},
|
|
1311
3393
|
column.key
|
|
1312
3394
|
)) }) }),
|
|
1313
|
-
/* @__PURE__ */
|
|
3395
|
+
/* @__PURE__ */ jsx43("tbody", { children: rows.length === 0 ? /* @__PURE__ */ jsx43("tr", { children: /* @__PURE__ */ jsx43("td", { className: "sph-table__empty", colSpan: columns.length, children: node(emptyMessage) }) }) : rows.map((row, rowIndex) => /* @__PURE__ */ jsx43("tr", { children: columns.map((column) => /* @__PURE__ */ jsx43("td", { "data-align": column.align ?? "start", children: node(
|
|
1314
3396
|
column.render ? column.render(row, rowIndex) : row[column.key]
|
|
1315
3397
|
) }, column.key)) }, rowKey ? String(row[rowKey]) : rowIndex)) })
|
|
1316
3398
|
]
|
|
@@ -1319,25 +3401,40 @@ function Table({
|
|
|
1319
3401
|
}
|
|
1320
3402
|
export {
|
|
1321
3403
|
Alert,
|
|
3404
|
+
Avatar,
|
|
3405
|
+
AvatarGroup,
|
|
1322
3406
|
Badge,
|
|
1323
3407
|
Button,
|
|
1324
3408
|
Card,
|
|
1325
3409
|
Checkbox,
|
|
3410
|
+
Collapsible,
|
|
3411
|
+
Combobox,
|
|
3412
|
+
CommandPalette,
|
|
1326
3413
|
Dialog,
|
|
3414
|
+
Drawer,
|
|
1327
3415
|
EmptyState,
|
|
1328
3416
|
Field,
|
|
1329
3417
|
FieldMessage,
|
|
3418
|
+
HoverCard,
|
|
1330
3419
|
IconButton,
|
|
1331
3420
|
Input,
|
|
3421
|
+
Kbd,
|
|
3422
|
+
MagneticDropzone,
|
|
1332
3423
|
Menu,
|
|
1333
3424
|
Notice,
|
|
1334
3425
|
Popover,
|
|
3426
|
+
Progress,
|
|
1335
3427
|
RadioGroup,
|
|
3428
|
+
ReasoningSteps,
|
|
3429
|
+
Resizable,
|
|
3430
|
+
ScrollArea,
|
|
1336
3431
|
Select,
|
|
1337
3432
|
Separator,
|
|
3433
|
+
Sidebar,
|
|
1338
3434
|
Skeleton,
|
|
1339
3435
|
Slider,
|
|
1340
3436
|
Spinner,
|
|
3437
|
+
StreamingText,
|
|
1341
3438
|
Surface,
|
|
1342
3439
|
Table,
|
|
1343
3440
|
Tabs,
|
|
@@ -1347,6 +3444,9 @@ export {
|
|
|
1347
3444
|
Toggle,
|
|
1348
3445
|
Toolbar,
|
|
1349
3446
|
Tooltip,
|
|
1350
|
-
|
|
3447
|
+
motionDurationMs,
|
|
3448
|
+
parseDurationMs,
|
|
3449
|
+
toast,
|
|
3450
|
+
usePresence
|
|
1351
3451
|
};
|
|
1352
3452
|
//# sourceMappingURL=index.js.map
|