@zovaris/sephiro 0.6.1 → 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 +2119 -103
- package/dist/index.css +2129 -102
- package/dist/index.d.ts +274 -4
- package/dist/index.js +2409 -316
- 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
|
-
),
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
"div",
|
|
682
|
-
{
|
|
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
|
-
|
|
1793
|
+
),
|
|
1794
|
+
present && portaled && createPortal3(
|
|
1795
|
+
/* @__PURE__ */ jsx28(
|
|
1796
|
+
"div",
|
|
1797
|
+
{
|
|
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, CheckIcon as
|
|
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,9 +2130,9 @@ function Select({
|
|
|
963
2130
|
onClick: () => setOpen((current) => !current),
|
|
964
2131
|
onKeyDown: handleKeyDown,
|
|
965
2132
|
children: [
|
|
966
|
-
/* @__PURE__ */
|
|
967
|
-
/* @__PURE__ */
|
|
968
|
-
|
|
2133
|
+
/* @__PURE__ */ jsx31("span", { className: "sph-select__value", children: node(selected?.label ?? placeholder) }),
|
|
2134
|
+
/* @__PURE__ */ jsx31(
|
|
2135
|
+
CaretDownIcon2,
|
|
969
2136
|
{
|
|
970
2137
|
className: "sph-select__caret",
|
|
971
2138
|
style: { transform: open ? "rotate(180deg)" : void 0 },
|
|
@@ -975,32 +2142,45 @@ function Select({
|
|
|
975
2142
|
]
|
|
976
2143
|
}
|
|
977
2144
|
),
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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
|
+
)
|
|
997
2177
|
] });
|
|
998
2178
|
}
|
|
999
2179
|
|
|
1000
2180
|
// src/molecules/Tabs/index.tsx
|
|
1001
|
-
import { cn as
|
|
1002
|
-
import { useId as
|
|
1003
|
-
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";
|
|
1004
2184
|
function firstEnabled(items) {
|
|
1005
2185
|
return items.find((item) => !item.disabled)?.value;
|
|
1006
2186
|
}
|
|
@@ -1014,8 +2194,8 @@ function Tabs({
|
|
|
1014
2194
|
orientation = "horizontal",
|
|
1015
2195
|
className
|
|
1016
2196
|
}) {
|
|
1017
|
-
const generatedId =
|
|
1018
|
-
const [uncontrolledValue, setUncontrolledValue] =
|
|
2197
|
+
const generatedId = useId12();
|
|
2198
|
+
const [uncontrolledValue, setUncontrolledValue] = useState11(
|
|
1019
2199
|
defaultValue ?? firstEnabled(items) ?? ""
|
|
1020
2200
|
);
|
|
1021
2201
|
const activeValue = value ?? uncontrolledValue;
|
|
@@ -1043,8 +2223,8 @@ function Tabs({
|
|
|
1043
2223
|
}
|
|
1044
2224
|
};
|
|
1045
2225
|
const panelId = `${generatedId}-panel`;
|
|
1046
|
-
return /* @__PURE__ */
|
|
1047
|
-
/* @__PURE__ */
|
|
2226
|
+
return /* @__PURE__ */ jsxs19("div", { className: cn31("sph-tabs", className), "data-orientation": orientation, children: [
|
|
2227
|
+
/* @__PURE__ */ jsx32(
|
|
1048
2228
|
"div",
|
|
1049
2229
|
{
|
|
1050
2230
|
className: "sph-tabs__list",
|
|
@@ -1053,7 +2233,7 @@ function Tabs({
|
|
|
1053
2233
|
"aria-orientation": orientation,
|
|
1054
2234
|
children: items.map((item, index) => {
|
|
1055
2235
|
const selected = item.value === activeValue;
|
|
1056
|
-
return /* @__PURE__ */
|
|
2236
|
+
return /* @__PURE__ */ jsx32(
|
|
1057
2237
|
"button",
|
|
1058
2238
|
{
|
|
1059
2239
|
id: `${generatedId}-${index}`,
|
|
@@ -1074,7 +2254,7 @@ function Tabs({
|
|
|
1074
2254
|
})
|
|
1075
2255
|
}
|
|
1076
2256
|
),
|
|
1077
|
-
activeItem && (activeItem.content !== void 0 || children !== void 0) && /* @__PURE__ */
|
|
2257
|
+
activeItem && (activeItem.content !== void 0 || children !== void 0) && /* @__PURE__ */ jsx32(
|
|
1078
2258
|
"div",
|
|
1079
2259
|
{
|
|
1080
2260
|
id: panelId,
|
|
@@ -1082,25 +2262,26 @@ function Tabs({
|
|
|
1082
2262
|
role: "tabpanel",
|
|
1083
2263
|
"aria-labelledby": `${generatedId}-${activeIndex}`,
|
|
1084
2264
|
children: node(activeItem.content ?? children)
|
|
1085
|
-
}
|
|
2265
|
+
},
|
|
2266
|
+
activeItem.content !== void 0 ? activeValue : "static"
|
|
1086
2267
|
)
|
|
1087
2268
|
] });
|
|
1088
2269
|
}
|
|
1089
2270
|
|
|
1090
2271
|
// src/molecules/Toast/index.tsx
|
|
1091
|
-
import { CheckIcon as
|
|
1092
|
-
import { cn as
|
|
1093
|
-
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";
|
|
1094
2275
|
import {
|
|
1095
2276
|
Toaster as SonnerToaster,
|
|
1096
2277
|
toast
|
|
1097
2278
|
} from "sonner";
|
|
1098
|
-
import { jsx as
|
|
2279
|
+
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
1099
2280
|
var toastIcons = {
|
|
1100
|
-
success: /* @__PURE__ */
|
|
1101
|
-
info: /* @__PURE__ */
|
|
1102
|
-
warning: /* @__PURE__ */
|
|
1103
|
-
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 }) })
|
|
1104
2285
|
};
|
|
1105
2286
|
function Toast({
|
|
1106
2287
|
open = true,
|
|
@@ -1113,7 +2294,7 @@ function Toast({
|
|
|
1113
2294
|
closeButton = true,
|
|
1114
2295
|
className
|
|
1115
2296
|
}) {
|
|
1116
|
-
|
|
2297
|
+
useEffect12(() => {
|
|
1117
2298
|
if (!open) return;
|
|
1118
2299
|
const options = {
|
|
1119
2300
|
id,
|
|
@@ -1121,7 +2302,7 @@ function Toast({
|
|
|
1121
2302
|
closeButton,
|
|
1122
2303
|
description: node(description),
|
|
1123
2304
|
duration,
|
|
1124
|
-
className:
|
|
2305
|
+
className: cn32("sph-toast", className),
|
|
1125
2306
|
unstyled: true
|
|
1126
2307
|
};
|
|
1127
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);
|
|
@@ -1141,7 +2322,7 @@ function ToastViewport({
|
|
|
1141
2322
|
expand = false,
|
|
1142
2323
|
...props
|
|
1143
2324
|
}) {
|
|
1144
|
-
return /* @__PURE__ */
|
|
2325
|
+
return /* @__PURE__ */ jsx33(
|
|
1145
2326
|
SonnerToaster,
|
|
1146
2327
|
{
|
|
1147
2328
|
...node(props),
|
|
@@ -1151,12 +2332,12 @@ function ToastViewport({
|
|
|
1151
2332
|
icons: toastIcons,
|
|
1152
2333
|
containerAriaLabel: label,
|
|
1153
2334
|
expand,
|
|
1154
|
-
className:
|
|
2335
|
+
className: cn32("sph-toast-viewport", className),
|
|
1155
2336
|
toastOptions: {
|
|
1156
2337
|
...toastOptions,
|
|
1157
2338
|
closeButton: toastOptions?.closeButton ?? closeButton,
|
|
1158
2339
|
closeButtonAriaLabel: toastOptions?.closeButtonAriaLabel ?? "Dismiss notification",
|
|
1159
|
-
className:
|
|
2340
|
+
className: cn32("sph-toast", toastOptions?.className),
|
|
1160
2341
|
unstyled: true
|
|
1161
2342
|
}
|
|
1162
2343
|
}
|
|
@@ -1164,8 +2345,8 @@ function ToastViewport({
|
|
|
1164
2345
|
}
|
|
1165
2346
|
|
|
1166
2347
|
// src/molecules/Toolbar/index.tsx
|
|
1167
|
-
import { cn as
|
|
1168
|
-
import { jsx as
|
|
2348
|
+
import { cn as cn33 } from "cn";
|
|
2349
|
+
import { jsx as jsx34, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1169
2350
|
function Toolbar({
|
|
1170
2351
|
label = "Toolbar",
|
|
1171
2352
|
orientation = "horizontal",
|
|
@@ -1176,29 +2357,30 @@ function Toolbar({
|
|
|
1176
2357
|
className,
|
|
1177
2358
|
...props
|
|
1178
2359
|
}) {
|
|
1179
|
-
return /* @__PURE__ */
|
|
2360
|
+
return /* @__PURE__ */ jsxs20(
|
|
1180
2361
|
"div",
|
|
1181
2362
|
{
|
|
1182
2363
|
...node(props),
|
|
1183
|
-
className:
|
|
2364
|
+
className: cn33("sph-toolbar", className),
|
|
1184
2365
|
"data-orientation": orientation,
|
|
1185
2366
|
"data-size": size,
|
|
1186
2367
|
role: "toolbar",
|
|
1187
2368
|
"aria-label": label,
|
|
1188
2369
|
"aria-orientation": orientation,
|
|
1189
2370
|
children: [
|
|
1190
|
-
start !== void 0 && /* @__PURE__ */
|
|
1191
|
-
children !== void 0 && /* @__PURE__ */
|
|
1192
|
-
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) })
|
|
1193
2374
|
]
|
|
1194
2375
|
}
|
|
1195
2376
|
);
|
|
1196
2377
|
}
|
|
1197
2378
|
|
|
1198
2379
|
// src/molecules/Tooltip/index.tsx
|
|
1199
|
-
import { cn as
|
|
1200
|
-
import { useId as
|
|
1201
|
-
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";
|
|
1202
2384
|
function Tooltip({
|
|
1203
2385
|
content,
|
|
1204
2386
|
children,
|
|
@@ -1207,9 +2389,21 @@ function Tooltip({
|
|
|
1207
2389
|
disabled = false,
|
|
1208
2390
|
className
|
|
1209
2391
|
}) {
|
|
1210
|
-
const id =
|
|
1211
|
-
const timerRef =
|
|
1212
|
-
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
|
+
});
|
|
1213
2407
|
const show = () => {
|
|
1214
2408
|
if (disabled) return;
|
|
1215
2409
|
timerRef.current = setTimeout(() => setVisible(true), delay);
|
|
@@ -1218,45 +2412,522 @@ function Tooltip({
|
|
|
1218
2412
|
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1219
2413
|
setVisible(false);
|
|
1220
2414
|
};
|
|
1221
|
-
return /* @__PURE__ */
|
|
2415
|
+
return /* @__PURE__ */ jsxs21(
|
|
1222
2416
|
"span",
|
|
1223
2417
|
{
|
|
1224
|
-
className:
|
|
2418
|
+
className: cn34("sph-tooltip", className),
|
|
1225
2419
|
onMouseEnter: show,
|
|
1226
2420
|
onMouseLeave: hide,
|
|
1227
2421
|
onFocus: show,
|
|
1228
2422
|
onBlur: hide,
|
|
1229
2423
|
children: [
|
|
1230
|
-
/* @__PURE__ */
|
|
2424
|
+
/* @__PURE__ */ jsx35(
|
|
1231
2425
|
"span",
|
|
1232
2426
|
{
|
|
2427
|
+
ref: triggerRef,
|
|
1233
2428
|
className: "sph-tooltip__trigger",
|
|
1234
2429
|
"aria-describedby": visible ? id : void 0,
|
|
1235
2430
|
children: node(children)
|
|
1236
2431
|
}
|
|
1237
2432
|
),
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
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
|
|
1249
2447
|
)
|
|
1250
2448
|
]
|
|
1251
2449
|
}
|
|
1252
2450
|
);
|
|
1253
2451
|
}
|
|
1254
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
|
+
|
|
1255
2926
|
// src/organisms/EmptyState/index.tsx
|
|
1256
2927
|
import { TrayIcon } from "@phosphor-icons/react";
|
|
1257
|
-
import { cn as
|
|
1258
|
-
import { jsx as
|
|
1259
|
-
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 });
|
|
1260
2931
|
function EmptyState({
|
|
1261
2932
|
title,
|
|
1262
2933
|
description,
|
|
@@ -1266,25 +2937,429 @@ function EmptyState({
|
|
|
1266
2937
|
className,
|
|
1267
2938
|
...props
|
|
1268
2939
|
}) {
|
|
1269
|
-
return /* @__PURE__ */
|
|
2940
|
+
return /* @__PURE__ */ jsxs23(
|
|
1270
2941
|
"section",
|
|
1271
2942
|
{
|
|
1272
2943
|
...node(props),
|
|
1273
|
-
className:
|
|
2944
|
+
className: cn36("sph-empty-state", className),
|
|
1274
2945
|
"data-compact": compact || void 0,
|
|
1275
2946
|
children: [
|
|
1276
|
-
/* @__PURE__ */
|
|
1277
|
-
/* @__PURE__ */
|
|
1278
|
-
description !== void 0 && /* @__PURE__ */
|
|
1279
|
-
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
|
+
] })
|
|
1280
3326
|
]
|
|
1281
3327
|
}
|
|
1282
3328
|
);
|
|
1283
3329
|
}
|
|
1284
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
|
+
|
|
1285
3360
|
// src/organisms/Table/index.tsx
|
|
1286
|
-
import { cn as
|
|
1287
|
-
import { jsx as
|
|
3361
|
+
import { cn as cn42 } from "cn";
|
|
3362
|
+
import { jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
1288
3363
|
function Table({
|
|
1289
3364
|
columns,
|
|
1290
3365
|
rows,
|
|
@@ -1297,7 +3372,7 @@ function Table({
|
|
|
1297
3372
|
className,
|
|
1298
3373
|
...props
|
|
1299
3374
|
}) {
|
|
1300
|
-
return /* @__PURE__ */
|
|
3375
|
+
return /* @__PURE__ */ jsx43("div", { className: cn42("sph-table-wrap", className), children: /* @__PURE__ */ jsxs27(
|
|
1301
3376
|
"table",
|
|
1302
3377
|
{
|
|
1303
3378
|
...node(props),
|
|
@@ -1306,8 +3381,8 @@ function Table({
|
|
|
1306
3381
|
"data-striped": striped || void 0,
|
|
1307
3382
|
"data-sticky-header": stickyHeader || void 0,
|
|
1308
3383
|
children: [
|
|
1309
|
-
caption !== void 0 && /* @__PURE__ */
|
|
1310
|
-
/* @__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(
|
|
1311
3386
|
"th",
|
|
1312
3387
|
{
|
|
1313
3388
|
scope: "col",
|
|
@@ -1317,7 +3392,7 @@ function Table({
|
|
|
1317
3392
|
},
|
|
1318
3393
|
column.key
|
|
1319
3394
|
)) }) }),
|
|
1320
|
-
/* @__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(
|
|
1321
3396
|
column.render ? column.render(row, rowIndex) : row[column.key]
|
|
1322
3397
|
) }, column.key)) }, rowKey ? String(row[rowKey]) : rowIndex)) })
|
|
1323
3398
|
]
|
|
@@ -1326,25 +3401,40 @@ function Table({
|
|
|
1326
3401
|
}
|
|
1327
3402
|
export {
|
|
1328
3403
|
Alert,
|
|
3404
|
+
Avatar,
|
|
3405
|
+
AvatarGroup,
|
|
1329
3406
|
Badge,
|
|
1330
3407
|
Button,
|
|
1331
3408
|
Card,
|
|
1332
3409
|
Checkbox,
|
|
3410
|
+
Collapsible,
|
|
3411
|
+
Combobox,
|
|
3412
|
+
CommandPalette,
|
|
1333
3413
|
Dialog,
|
|
3414
|
+
Drawer,
|
|
1334
3415
|
EmptyState,
|
|
1335
3416
|
Field,
|
|
1336
3417
|
FieldMessage,
|
|
3418
|
+
HoverCard,
|
|
1337
3419
|
IconButton,
|
|
1338
3420
|
Input,
|
|
3421
|
+
Kbd,
|
|
3422
|
+
MagneticDropzone,
|
|
1339
3423
|
Menu,
|
|
1340
3424
|
Notice,
|
|
1341
3425
|
Popover,
|
|
3426
|
+
Progress,
|
|
1342
3427
|
RadioGroup,
|
|
3428
|
+
ReasoningSteps,
|
|
3429
|
+
Resizable,
|
|
3430
|
+
ScrollArea,
|
|
1343
3431
|
Select,
|
|
1344
3432
|
Separator,
|
|
3433
|
+
Sidebar,
|
|
1345
3434
|
Skeleton,
|
|
1346
3435
|
Slider,
|
|
1347
3436
|
Spinner,
|
|
3437
|
+
StreamingText,
|
|
1348
3438
|
Surface,
|
|
1349
3439
|
Table,
|
|
1350
3440
|
Tabs,
|
|
@@ -1354,6 +3444,9 @@ export {
|
|
|
1354
3444
|
Toggle,
|
|
1355
3445
|
Toolbar,
|
|
1356
3446
|
Tooltip,
|
|
1357
|
-
|
|
3447
|
+
motionDurationMs,
|
|
3448
|
+
parseDurationMs,
|
|
3449
|
+
toast,
|
|
3450
|
+
usePresence
|
|
1358
3451
|
};
|
|
1359
3452
|
//# sourceMappingURL=index.js.map
|