@kuraykaraaslan/kui-react 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -0
- package/README.md +168 -0
- package/dist/AdvancedDataTable-F3DNXDKX.mjs +11 -0
- package/dist/DataTable-2G27T4E6.mjs +11 -0
- package/dist/DateRangePicker-AL32QB6L.mjs +11 -0
- package/dist/DropdownMenu-f5yV9dzM.d.mts +22 -0
- package/dist/DropdownMenu-f5yV9dzM.d.ts +22 -0
- package/dist/MapView-FERKPCDB.mjs +10 -0
- package/dist/ServerDataTable-RZV3K6KQ.mjs +11 -0
- package/dist/Tooltip-Bof5GvOc.d.mts +248 -0
- package/dist/Tooltip-Bof5GvOc.d.ts +248 -0
- package/dist/VideoPlayer-P3I6ESXJ.mjs +9 -0
- package/dist/app.d.mts +620 -0
- package/dist/app.d.ts +620 -0
- package/dist/app.js +7061 -0
- package/dist/app.mjs +100 -0
- package/dist/chunk-24BCQSLI.mjs +1 -0
- package/dist/chunk-45I3EDB2.mjs +90 -0
- package/dist/chunk-4IWCD7ID.mjs +1450 -0
- package/dist/chunk-5E2HXWFI.mjs +105 -0
- package/dist/chunk-C7AYI4XM.mjs +402 -0
- package/dist/chunk-J4D44TUA.mjs +1267 -0
- package/dist/chunk-KTEWZKNE.mjs +1020 -0
- package/dist/chunk-LMUQHL4Z.mjs +3829 -0
- package/dist/chunk-MD5OQ4J2.mjs +527 -0
- package/dist/chunk-MPJRPYIZ.mjs +1 -0
- package/dist/chunk-MPWUEQ7J.mjs +2422 -0
- package/dist/chunk-MTT5TKAJ.mjs +93 -0
- package/dist/chunk-RBDK7MWQ.mjs +46 -0
- package/dist/chunk-SVFQZPNZ.mjs +3648 -0
- package/dist/chunk-TZWBBMSG.mjs +1 -0
- package/dist/chunk-XA7J6PVJ.mjs +1488 -0
- package/dist/chunk-ZLYBRYWQ.mjs +726 -0
- package/dist/common.d.mts +921 -0
- package/dist/common.d.ts +921 -0
- package/dist/common.js +4991 -0
- package/dist/common.mjs +172 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +17563 -0
- package/dist/index.mjs +349 -0
- package/dist/ui.d.mts +937 -0
- package/dist/ui.d.ts +937 -0
- package/dist/ui.js +10095 -0
- package/dist/ui.mjs +163 -0
- package/package.json +114 -0
- package/styles/index.css +129 -0
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
__objRest,
|
|
4
|
+
__spreadProps,
|
|
5
|
+
__spreadValues,
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-RBDK7MWQ.mjs";
|
|
8
|
+
|
|
9
|
+
// modules/ui/Avatar.tsx
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
var sizeMap = {
|
|
12
|
+
xs: "h-6 w-6 text-xs",
|
|
13
|
+
sm: "h-8 w-8 text-xs",
|
|
14
|
+
md: "h-10 w-10 text-sm",
|
|
15
|
+
lg: "h-12 w-12 text-base",
|
|
16
|
+
xl: "h-16 w-16 text-lg"
|
|
17
|
+
};
|
|
18
|
+
var statusColorMap = {
|
|
19
|
+
online: "bg-success",
|
|
20
|
+
offline: "bg-text-disabled",
|
|
21
|
+
away: "bg-warning",
|
|
22
|
+
busy: "bg-error"
|
|
23
|
+
};
|
|
24
|
+
var statusDotSizeMap = {
|
|
25
|
+
xs: "h-1.5 w-1.5",
|
|
26
|
+
sm: "h-2 w-2",
|
|
27
|
+
md: "h-2.5 w-2.5",
|
|
28
|
+
lg: "h-3 w-3",
|
|
29
|
+
xl: "h-4 w-4"
|
|
30
|
+
};
|
|
31
|
+
function getInitials(name) {
|
|
32
|
+
return name.trim().split(/\s+/).map((w) => w[0]).slice(0, 2).join("").toUpperCase() || "?";
|
|
33
|
+
}
|
|
34
|
+
function Avatar({
|
|
35
|
+
src,
|
|
36
|
+
name,
|
|
37
|
+
size = "md",
|
|
38
|
+
status,
|
|
39
|
+
className
|
|
40
|
+
}) {
|
|
41
|
+
const sizeClass = sizeMap[size];
|
|
42
|
+
const inner = src ? (
|
|
43
|
+
// eslint-disable-next-line @next/next/no-img-element
|
|
44
|
+
/* @__PURE__ */ jsx(
|
|
45
|
+
"img",
|
|
46
|
+
{
|
|
47
|
+
src,
|
|
48
|
+
alt: name,
|
|
49
|
+
className: cn(sizeClass, "rounded-full object-cover border border-border shrink-0", className)
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
) : /* @__PURE__ */ jsx(
|
|
53
|
+
"span",
|
|
54
|
+
{
|
|
55
|
+
"aria-label": name,
|
|
56
|
+
className: cn(
|
|
57
|
+
sizeClass,
|
|
58
|
+
"rounded-full bg-primary-subtle text-primary font-semibold",
|
|
59
|
+
"flex items-center justify-center shrink-0 border border-primary-subtle select-none",
|
|
60
|
+
className
|
|
61
|
+
),
|
|
62
|
+
children: getInitials(name)
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
if (!status) return inner;
|
|
66
|
+
return /* @__PURE__ */ jsxs("span", { className: "relative inline-flex shrink-0", children: [
|
|
67
|
+
inner,
|
|
68
|
+
/* @__PURE__ */ jsx(
|
|
69
|
+
"span",
|
|
70
|
+
{
|
|
71
|
+
"aria-label": status,
|
|
72
|
+
className: cn(
|
|
73
|
+
"absolute bottom-0 right-0 rounded-full border-2 border-surface-base",
|
|
74
|
+
statusColorMap[status],
|
|
75
|
+
statusDotSizeMap[size]
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
] });
|
|
80
|
+
}
|
|
81
|
+
function AvatarGroup({
|
|
82
|
+
avatars,
|
|
83
|
+
max = 4,
|
|
84
|
+
size = "md"
|
|
85
|
+
}) {
|
|
86
|
+
const visible = avatars.slice(0, max);
|
|
87
|
+
const overflow = avatars.length - max;
|
|
88
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex -space-x-2", "aria-label": `${avatars.length} users`, children: [
|
|
89
|
+
visible.map((a, i) => /* @__PURE__ */ jsx(Avatar, __spreadProps(__spreadValues({}, a), { size, className: "ring-2 ring-surface-base" }), i)),
|
|
90
|
+
overflow > 0 && /* @__PURE__ */ jsxs(
|
|
91
|
+
"span",
|
|
92
|
+
{
|
|
93
|
+
className: cn(
|
|
94
|
+
sizeMap[size],
|
|
95
|
+
"rounded-full bg-surface-sunken text-text-secondary font-semibold text-xs",
|
|
96
|
+
"flex items-center justify-center shrink-0 ring-2 ring-surface-base border border-border select-none"
|
|
97
|
+
),
|
|
98
|
+
"aria-label": `${overflow} more`,
|
|
99
|
+
children: [
|
|
100
|
+
"+",
|
|
101
|
+
overflow
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
] });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// modules/ui/Badge.tsx
|
|
109
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
110
|
+
import { faXmark } from "@fortawesome/free-solid-svg-icons";
|
|
111
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
112
|
+
var variantMap = {
|
|
113
|
+
success: "bg-success-subtle text-success-fg",
|
|
114
|
+
error: "bg-error-subtle text-error-fg",
|
|
115
|
+
warning: "bg-warning-subtle text-warning-fg",
|
|
116
|
+
info: "bg-info-subtle text-info-fg",
|
|
117
|
+
neutral: "bg-surface-sunken text-text-secondary",
|
|
118
|
+
primary: "bg-primary-subtle text-primary"
|
|
119
|
+
};
|
|
120
|
+
var sizeMap2 = {
|
|
121
|
+
sm: "px-1.5 py-0 text-[10px]",
|
|
122
|
+
md: "px-2 py-0.5 text-xs",
|
|
123
|
+
lg: "px-3 py-1 text-sm"
|
|
124
|
+
};
|
|
125
|
+
var dotColorMap = {
|
|
126
|
+
success: "bg-success",
|
|
127
|
+
error: "bg-error",
|
|
128
|
+
warning: "bg-warning",
|
|
129
|
+
info: "bg-info",
|
|
130
|
+
neutral: "bg-text-disabled",
|
|
131
|
+
primary: "bg-primary"
|
|
132
|
+
};
|
|
133
|
+
function Badge(_a) {
|
|
134
|
+
var _b = _a, {
|
|
135
|
+
as,
|
|
136
|
+
children,
|
|
137
|
+
variant = "neutral",
|
|
138
|
+
size = "md",
|
|
139
|
+
dot = false,
|
|
140
|
+
dismissible = false,
|
|
141
|
+
onDismiss,
|
|
142
|
+
className
|
|
143
|
+
} = _b, rest = __objRest(_b, [
|
|
144
|
+
"as",
|
|
145
|
+
"children",
|
|
146
|
+
"variant",
|
|
147
|
+
"size",
|
|
148
|
+
"dot",
|
|
149
|
+
"dismissible",
|
|
150
|
+
"onDismiss",
|
|
151
|
+
"className"
|
|
152
|
+
]);
|
|
153
|
+
const Tag = as != null ? as : "span";
|
|
154
|
+
return /* @__PURE__ */ jsxs2(
|
|
155
|
+
Tag,
|
|
156
|
+
__spreadProps(__spreadValues({
|
|
157
|
+
className: cn(
|
|
158
|
+
"inline-flex items-center gap-1 rounded-full font-medium",
|
|
159
|
+
variantMap[variant],
|
|
160
|
+
sizeMap2[size],
|
|
161
|
+
className
|
|
162
|
+
)
|
|
163
|
+
}, rest), {
|
|
164
|
+
children: [
|
|
165
|
+
dot && /* @__PURE__ */ jsx2(
|
|
166
|
+
"span",
|
|
167
|
+
{
|
|
168
|
+
className: cn("h-1.5 w-1.5 rounded-full shrink-0", dotColorMap[variant]),
|
|
169
|
+
"aria-hidden": "true"
|
|
170
|
+
}
|
|
171
|
+
),
|
|
172
|
+
children,
|
|
173
|
+
dismissible && /* @__PURE__ */ jsx2(
|
|
174
|
+
"button",
|
|
175
|
+
{
|
|
176
|
+
type: "button",
|
|
177
|
+
"aria-label": "Remove",
|
|
178
|
+
onClick: onDismiss,
|
|
179
|
+
className: "ml-0.5 leading-none hover:opacity-70 transition-opacity focus-visible:outline-none rounded-full",
|
|
180
|
+
children: /* @__PURE__ */ jsx2(FontAwesomeIcon, { icon: faXmark, className: "w-2.5 h-2.5" })
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
]
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// modules/ui/Select.tsx
|
|
189
|
+
import { forwardRef, useEffect, useRef, useState } from "react";
|
|
190
|
+
import { FontAwesomeIcon as FontAwesomeIcon2 } from "@fortawesome/react-fontawesome";
|
|
191
|
+
import { faChevronUp, faChevronDown, faCheck } from "@fortawesome/free-solid-svg-icons";
|
|
192
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
193
|
+
function CustomSelect({
|
|
194
|
+
id,
|
|
195
|
+
label,
|
|
196
|
+
options,
|
|
197
|
+
placeholder,
|
|
198
|
+
hint,
|
|
199
|
+
error,
|
|
200
|
+
disabled,
|
|
201
|
+
required,
|
|
202
|
+
searchable,
|
|
203
|
+
className,
|
|
204
|
+
value,
|
|
205
|
+
onChange
|
|
206
|
+
}) {
|
|
207
|
+
const [open, setOpen] = useState(false);
|
|
208
|
+
const [search, setSearch] = useState("");
|
|
209
|
+
const containerRef = useRef(null);
|
|
210
|
+
const searchRef = useRef(null);
|
|
211
|
+
const hintId = hint ? `${id}-hint` : void 0;
|
|
212
|
+
const errorId = error ? `${id}-error` : void 0;
|
|
213
|
+
const describedBy = [hintId, errorId].filter(Boolean).join(" ") || void 0;
|
|
214
|
+
const selected = options.find((o) => o.value === value);
|
|
215
|
+
const filtered = searchable && search ? options.filter((o) => o.label.toLowerCase().includes(search.toLowerCase())) : options;
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (!open) {
|
|
218
|
+
setSearch("");
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (searchable) setTimeout(() => {
|
|
222
|
+
var _a;
|
|
223
|
+
return (_a = searchRef.current) == null ? void 0 : _a.focus();
|
|
224
|
+
}, 30);
|
|
225
|
+
function onOutside(e) {
|
|
226
|
+
if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
|
|
227
|
+
}
|
|
228
|
+
document.addEventListener("mousedown", onOutside);
|
|
229
|
+
return () => document.removeEventListener("mousedown", onOutside);
|
|
230
|
+
}, [open, searchable]);
|
|
231
|
+
function select(v) {
|
|
232
|
+
onChange == null ? void 0 : onChange(v);
|
|
233
|
+
setOpen(false);
|
|
234
|
+
}
|
|
235
|
+
function onKeyDown(e) {
|
|
236
|
+
if (e.key === "Escape") setOpen(false);
|
|
237
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
238
|
+
e.preventDefault();
|
|
239
|
+
setOpen((o) => !o);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return /* @__PURE__ */ jsxs3("div", { ref: containerRef, className: cn("space-y-1", className), children: [
|
|
243
|
+
/* @__PURE__ */ jsxs3("label", { id: `${id}-label`, className: "block text-sm font-medium text-text-primary", children: [
|
|
244
|
+
label,
|
|
245
|
+
required && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
246
|
+
/* @__PURE__ */ jsx3("span", { className: "text-error ml-1", "aria-hidden": "true", children: "*" }),
|
|
247
|
+
/* @__PURE__ */ jsx3("span", { className: "sr-only", children: "(required)" })
|
|
248
|
+
] })
|
|
249
|
+
] }),
|
|
250
|
+
/* @__PURE__ */ jsxs3(
|
|
251
|
+
"div",
|
|
252
|
+
{
|
|
253
|
+
role: "combobox",
|
|
254
|
+
tabIndex: disabled ? -1 : 0,
|
|
255
|
+
"aria-haspopup": "listbox",
|
|
256
|
+
"aria-expanded": open,
|
|
257
|
+
"aria-labelledby": `${id}-label`,
|
|
258
|
+
"aria-describedby": describedBy,
|
|
259
|
+
"aria-disabled": disabled,
|
|
260
|
+
"aria-required": required,
|
|
261
|
+
id,
|
|
262
|
+
onClick: () => !disabled && setOpen((o) => !o),
|
|
263
|
+
onKeyDown,
|
|
264
|
+
className: cn(
|
|
265
|
+
"flex items-center gap-2 w-full rounded-md border px-3 py-2 text-sm transition-colors cursor-pointer",
|
|
266
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
267
|
+
error ? "border-error ring-1 ring-error bg-error-subtle" : "border-border bg-surface-base",
|
|
268
|
+
disabled && "opacity-50 cursor-not-allowed bg-surface-sunken"
|
|
269
|
+
),
|
|
270
|
+
children: [
|
|
271
|
+
(selected == null ? void 0 : selected.icon) && /* @__PURE__ */ jsx3("span", { className: "shrink-0", children: selected.icon }),
|
|
272
|
+
/* @__PURE__ */ jsx3("span", { className: cn("flex-1", !selected && "text-text-disabled"), children: selected ? selected.label : placeholder != null ? placeholder : "Select\u2026" }),
|
|
273
|
+
/* @__PURE__ */ jsx3(FontAwesomeIcon2, { icon: open ? faChevronUp : faChevronDown, className: "w-3 h-3 text-text-disabled", "aria-hidden": "true" })
|
|
274
|
+
]
|
|
275
|
+
}
|
|
276
|
+
),
|
|
277
|
+
open && /* @__PURE__ */ jsxs3("div", { className: "z-20 w-full rounded-md border border-border bg-surface-raised shadow-lg overflow-hidden", children: [
|
|
278
|
+
searchable && /* @__PURE__ */ jsx3("div", { className: "p-2 border-b border-border", children: /* @__PURE__ */ jsx3(
|
|
279
|
+
"input",
|
|
280
|
+
{
|
|
281
|
+
ref: searchRef,
|
|
282
|
+
type: "text",
|
|
283
|
+
value: search,
|
|
284
|
+
onChange: (e) => setSearch(e.target.value),
|
|
285
|
+
placeholder: "Search\u2026",
|
|
286
|
+
className: cn(
|
|
287
|
+
"block w-full rounded-md border border-border bg-surface-base px-3 py-1.5 text-sm",
|
|
288
|
+
"text-text-primary placeholder:text-text-disabled",
|
|
289
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus"
|
|
290
|
+
)
|
|
291
|
+
}
|
|
292
|
+
) }),
|
|
293
|
+
/* @__PURE__ */ jsxs3("ul", { role: "listbox", "aria-labelledby": `${id}-label`, className: "py-1 max-h-48 overflow-y-auto", children: [
|
|
294
|
+
placeholder && !search && /* @__PURE__ */ jsx3(
|
|
295
|
+
"li",
|
|
296
|
+
{
|
|
297
|
+
role: "option",
|
|
298
|
+
"aria-selected": !value,
|
|
299
|
+
onClick: () => select(""),
|
|
300
|
+
tabIndex: 0,
|
|
301
|
+
onKeyDown: (e) => {
|
|
302
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
303
|
+
e.preventDefault();
|
|
304
|
+
select("");
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
className: cn(
|
|
308
|
+
"flex items-center gap-2 px-3 py-2 text-sm cursor-pointer text-text-disabled select-none",
|
|
309
|
+
"hover:bg-surface-overlay focus-visible:outline-none focus-visible:bg-surface-overlay"
|
|
310
|
+
),
|
|
311
|
+
children: placeholder
|
|
312
|
+
}
|
|
313
|
+
),
|
|
314
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx3("li", { className: "px-3 py-4 text-sm text-center text-text-secondary", children: "No results found." }) : filtered.map((opt) => {
|
|
315
|
+
const active = opt.value === value;
|
|
316
|
+
return /* @__PURE__ */ jsxs3(
|
|
317
|
+
"li",
|
|
318
|
+
{
|
|
319
|
+
role: "option",
|
|
320
|
+
"aria-selected": active,
|
|
321
|
+
onClick: () => select(opt.value),
|
|
322
|
+
tabIndex: 0,
|
|
323
|
+
onKeyDown: (e) => {
|
|
324
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
325
|
+
e.preventDefault();
|
|
326
|
+
select(opt.value);
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
className: cn(
|
|
330
|
+
"flex items-center gap-2 px-3 py-2 text-sm cursor-pointer select-none",
|
|
331
|
+
"hover:bg-surface-overlay transition-colors",
|
|
332
|
+
"focus-visible:outline-none focus-visible:bg-surface-overlay",
|
|
333
|
+
active && "text-primary font-medium"
|
|
334
|
+
),
|
|
335
|
+
children: [
|
|
336
|
+
opt.icon && /* @__PURE__ */ jsx3("span", { className: "shrink-0", "aria-hidden": "true", children: opt.icon }),
|
|
337
|
+
opt.label,
|
|
338
|
+
active && /* @__PURE__ */ jsx3(FontAwesomeIcon2, { icon: faCheck, className: "ml-auto w-3 h-3 text-primary", "aria-hidden": "true" })
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
opt.value
|
|
342
|
+
);
|
|
343
|
+
})
|
|
344
|
+
] })
|
|
345
|
+
] }),
|
|
346
|
+
hint && !error && /* @__PURE__ */ jsx3("p", { id: hintId, className: "text-xs text-text-secondary", children: hint }),
|
|
347
|
+
error && /* @__PURE__ */ jsx3("p", { id: errorId, className: "text-xs text-error", role: "alert", children: error })
|
|
348
|
+
] });
|
|
349
|
+
}
|
|
350
|
+
var Select = forwardRef(function Select2(_a, ref) {
|
|
351
|
+
var _b = _a, { id, label, options, placeholder, hint, error, disabled, required, searchable, className } = _b, props = __objRest(_b, ["id", "label", "options", "placeholder", "hint", "error", "disabled", "required", "searchable", "className"]);
|
|
352
|
+
const hasIcons = options.some((o) => o.icon);
|
|
353
|
+
if (hasIcons || searchable) {
|
|
354
|
+
const _a2 = props, { value, onChange } = _a2, rest = __objRest(_a2, ["value", "onChange"]);
|
|
355
|
+
return /* @__PURE__ */ jsx3(
|
|
356
|
+
CustomSelect,
|
|
357
|
+
__spreadValues({
|
|
358
|
+
id,
|
|
359
|
+
label,
|
|
360
|
+
options,
|
|
361
|
+
placeholder,
|
|
362
|
+
hint,
|
|
363
|
+
error,
|
|
364
|
+
disabled,
|
|
365
|
+
required,
|
|
366
|
+
searchable,
|
|
367
|
+
className,
|
|
368
|
+
value,
|
|
369
|
+
onChange: (v) => onChange == null ? void 0 : onChange({ target: { value: v } })
|
|
370
|
+
}, rest)
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
const hintId = hint ? `${id}-hint` : void 0;
|
|
374
|
+
const errorId = error ? `${id}-error` : void 0;
|
|
375
|
+
const describedBy = [hintId, errorId].filter(Boolean).join(" ") || void 0;
|
|
376
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("space-y-1", className), children: [
|
|
377
|
+
/* @__PURE__ */ jsxs3("label", { htmlFor: id, className: "block text-sm font-medium text-text-primary", children: [
|
|
378
|
+
label,
|
|
379
|
+
required && /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
380
|
+
/* @__PURE__ */ jsx3("span", { className: "text-error ml-1", "aria-hidden": "true", children: "*" }),
|
|
381
|
+
/* @__PURE__ */ jsx3("span", { className: "sr-only", children: "(required)" })
|
|
382
|
+
] })
|
|
383
|
+
] }),
|
|
384
|
+
/* @__PURE__ */ jsxs3(
|
|
385
|
+
"select",
|
|
386
|
+
__spreadProps(__spreadValues({
|
|
387
|
+
ref,
|
|
388
|
+
id,
|
|
389
|
+
disabled,
|
|
390
|
+
required,
|
|
391
|
+
"aria-describedby": describedBy,
|
|
392
|
+
"aria-invalid": !!error,
|
|
393
|
+
"data-testid": `select-${id}`,
|
|
394
|
+
className: cn(
|
|
395
|
+
"block w-full rounded-md border px-3 py-2 text-sm transition-colors appearance-none",
|
|
396
|
+
"bg-surface-base text-text-primary",
|
|
397
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus focus-visible:border-border-focus",
|
|
398
|
+
"disabled:opacity-50 disabled:cursor-not-allowed disabled:bg-surface-sunken",
|
|
399
|
+
error ? "border-error ring-1 ring-error bg-error-subtle" : "border-border"
|
|
400
|
+
)
|
|
401
|
+
}, props), {
|
|
402
|
+
children: [
|
|
403
|
+
placeholder && /* @__PURE__ */ jsx3("option", { value: "", children: placeholder }),
|
|
404
|
+
options.map((opt) => /* @__PURE__ */ jsx3("option", { value: opt.value, children: opt.label }, opt.value))
|
|
405
|
+
]
|
|
406
|
+
})
|
|
407
|
+
),
|
|
408
|
+
hint && !error && /* @__PURE__ */ jsx3("p", { id: hintId, className: "text-xs text-text-secondary", children: hint }),
|
|
409
|
+
error && /* @__PURE__ */ jsx3("p", { id: errorId, className: "text-xs text-error", role: "alert", children: error })
|
|
410
|
+
] });
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// modules/ui/AlertBanner.tsx
|
|
414
|
+
import { useState as useState2 } from "react";
|
|
415
|
+
import { FontAwesomeIcon as FontAwesomeIcon3 } from "@fortawesome/react-fontawesome";
|
|
416
|
+
import { faCircleCheck, faTriangleExclamation, faCircleXmark, faCircleInfo, faXmark as faXmark2 } from "@fortawesome/free-solid-svg-icons";
|
|
417
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
418
|
+
var variantMap2 = {
|
|
419
|
+
success: { container: "bg-success-subtle border-success text-success-fg", defaultIcon: /* @__PURE__ */ jsx4(FontAwesomeIcon3, { icon: faCircleCheck, className: "w-4 h-4" }) },
|
|
420
|
+
warning: { container: "bg-warning-subtle border-warning text-warning-fg", defaultIcon: /* @__PURE__ */ jsx4(FontAwesomeIcon3, { icon: faTriangleExclamation, className: "w-4 h-4" }) },
|
|
421
|
+
error: { container: "bg-error-subtle border-error text-error-fg", defaultIcon: /* @__PURE__ */ jsx4(FontAwesomeIcon3, { icon: faCircleXmark, className: "w-4 h-4" }) },
|
|
422
|
+
info: { container: "bg-info-subtle border-info text-info-fg", defaultIcon: /* @__PURE__ */ jsx4(FontAwesomeIcon3, { icon: faCircleInfo, className: "w-4 h-4" }) }
|
|
423
|
+
};
|
|
424
|
+
function AlertBanner({
|
|
425
|
+
variant = "info",
|
|
426
|
+
title,
|
|
427
|
+
message,
|
|
428
|
+
dismissible = false,
|
|
429
|
+
action,
|
|
430
|
+
icon,
|
|
431
|
+
className
|
|
432
|
+
}) {
|
|
433
|
+
const [dismissed, setDismissed] = useState2(false);
|
|
434
|
+
if (dismissed) return null;
|
|
435
|
+
const { container, defaultIcon } = variantMap2[variant];
|
|
436
|
+
return /* @__PURE__ */ jsxs4(
|
|
437
|
+
"div",
|
|
438
|
+
{
|
|
439
|
+
role: "alert",
|
|
440
|
+
className: cn(
|
|
441
|
+
"flex items-start gap-3 rounded-lg border p-4",
|
|
442
|
+
container,
|
|
443
|
+
className
|
|
444
|
+
),
|
|
445
|
+
children: [
|
|
446
|
+
/* @__PURE__ */ jsx4("span", { "aria-hidden": "true", className: "mt-0.5 shrink-0 font-bold", children: icon != null ? icon : defaultIcon }),
|
|
447
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex-1 text-sm min-w-0", children: [
|
|
448
|
+
title && /* @__PURE__ */ jsx4("p", { className: "font-semibold", children: title }),
|
|
449
|
+
/* @__PURE__ */ jsx4("p", { className: cn(title && "mt-0.5"), children: message }),
|
|
450
|
+
action && /* @__PURE__ */ jsx4("div", { className: "mt-2", children: action.href ? /* @__PURE__ */ jsx4(
|
|
451
|
+
"a",
|
|
452
|
+
{
|
|
453
|
+
href: action.href,
|
|
454
|
+
className: "text-xs font-semibold underline underline-offset-2 hover:opacity-70 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded",
|
|
455
|
+
children: action.label
|
|
456
|
+
}
|
|
457
|
+
) : /* @__PURE__ */ jsx4(
|
|
458
|
+
"button",
|
|
459
|
+
{
|
|
460
|
+
type: "button",
|
|
461
|
+
onClick: action.onClick,
|
|
462
|
+
className: "text-xs font-semibold underline underline-offset-2 hover:opacity-70 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded",
|
|
463
|
+
children: action.label
|
|
464
|
+
}
|
|
465
|
+
) })
|
|
466
|
+
] }),
|
|
467
|
+
dismissible && /* @__PURE__ */ jsx4(
|
|
468
|
+
"button",
|
|
469
|
+
{
|
|
470
|
+
type: "button",
|
|
471
|
+
"aria-label": "Dismiss",
|
|
472
|
+
onClick: () => setDismissed(true),
|
|
473
|
+
className: "shrink-0 hover:opacity-70 transition-opacity focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus rounded",
|
|
474
|
+
children: /* @__PURE__ */ jsx4(FontAwesomeIcon3, { icon: faXmark2, className: "w-4 h-4" })
|
|
475
|
+
}
|
|
476
|
+
)
|
|
477
|
+
]
|
|
478
|
+
}
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// modules/ui/DropdownMenu.tsx
|
|
483
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
484
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
485
|
+
function DropdownMenu({
|
|
486
|
+
trigger,
|
|
487
|
+
items,
|
|
488
|
+
header,
|
|
489
|
+
align = "left",
|
|
490
|
+
className
|
|
491
|
+
}) {
|
|
492
|
+
const [open, setOpen] = useState3(false);
|
|
493
|
+
const containerRef = useRef2(null);
|
|
494
|
+
useEffect2(() => {
|
|
495
|
+
if (!open) return;
|
|
496
|
+
function onOutside(e) {
|
|
497
|
+
var _a;
|
|
498
|
+
if (!((_a = containerRef.current) == null ? void 0 : _a.contains(e.target))) setOpen(false);
|
|
499
|
+
}
|
|
500
|
+
function onKey(e) {
|
|
501
|
+
if (e.key === "Escape") setOpen(false);
|
|
502
|
+
}
|
|
503
|
+
document.addEventListener("mousedown", onOutside);
|
|
504
|
+
document.addEventListener("keydown", onKey);
|
|
505
|
+
return () => {
|
|
506
|
+
document.removeEventListener("mousedown", onOutside);
|
|
507
|
+
document.removeEventListener("keydown", onKey);
|
|
508
|
+
};
|
|
509
|
+
}, [open]);
|
|
510
|
+
return /* @__PURE__ */ jsxs5("div", { ref: containerRef, className: cn("relative inline-block", className), children: [
|
|
511
|
+
/* @__PURE__ */ jsx5(
|
|
512
|
+
"div",
|
|
513
|
+
{
|
|
514
|
+
onClick: () => setOpen((p) => !p),
|
|
515
|
+
"aria-haspopup": "menu",
|
|
516
|
+
"aria-expanded": open,
|
|
517
|
+
children: trigger
|
|
518
|
+
}
|
|
519
|
+
),
|
|
520
|
+
open && /* @__PURE__ */ jsxs5(
|
|
521
|
+
"div",
|
|
522
|
+
{
|
|
523
|
+
role: "menu",
|
|
524
|
+
className: cn(
|
|
525
|
+
"absolute z-[60] mt-1 min-w-[10rem] rounded-lg border border-border bg-surface-raised shadow-lg py-1",
|
|
526
|
+
align === "right" ? "right-0" : "left-0"
|
|
527
|
+
),
|
|
528
|
+
children: [
|
|
529
|
+
header && /* @__PURE__ */ jsx5("div", { className: "border-b border-border mb-1", children: header }),
|
|
530
|
+
items.map((item, i) => {
|
|
531
|
+
if (item.type === "separator") {
|
|
532
|
+
return /* @__PURE__ */ jsx5("div", { role: "separator", className: "my-1 border-t border-border" }, i);
|
|
533
|
+
}
|
|
534
|
+
return /* @__PURE__ */ jsxs5(
|
|
535
|
+
"button",
|
|
536
|
+
{
|
|
537
|
+
role: "menuitem",
|
|
538
|
+
type: "button",
|
|
539
|
+
disabled: item.disabled,
|
|
540
|
+
onClick: () => {
|
|
541
|
+
var _a;
|
|
542
|
+
(_a = item.onClick) == null ? void 0 : _a.call(item);
|
|
543
|
+
setOpen(false);
|
|
544
|
+
},
|
|
545
|
+
className: cn(
|
|
546
|
+
"flex w-full items-center gap-2 px-3 py-2 text-sm text-left transition-colors",
|
|
547
|
+
"focus-visible:outline-none focus-visible:bg-surface-overlay",
|
|
548
|
+
item.danger ? "text-error hover:bg-error-subtle" : "text-text-primary hover:bg-surface-overlay",
|
|
549
|
+
item.disabled && "opacity-50 cursor-not-allowed"
|
|
550
|
+
),
|
|
551
|
+
children: [
|
|
552
|
+
item.icon && /* @__PURE__ */ jsx5("span", { "aria-hidden": "true", children: item.icon }),
|
|
553
|
+
item.label
|
|
554
|
+
]
|
|
555
|
+
},
|
|
556
|
+
i
|
|
557
|
+
);
|
|
558
|
+
})
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
)
|
|
562
|
+
] });
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// modules/ui/TagInput.tsx
|
|
566
|
+
import { useRef as useRef3, useState as useState4 } from "react";
|
|
567
|
+
import { FontAwesomeIcon as FontAwesomeIcon4 } from "@fortawesome/react-fontawesome";
|
|
568
|
+
import { faXmark as faXmark3 } from "@fortawesome/free-solid-svg-icons";
|
|
569
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
570
|
+
function TagInput({
|
|
571
|
+
id,
|
|
572
|
+
label,
|
|
573
|
+
hint,
|
|
574
|
+
error,
|
|
575
|
+
value,
|
|
576
|
+
onChange,
|
|
577
|
+
placeholder = "Type and press Enter or comma\u2026",
|
|
578
|
+
disabled,
|
|
579
|
+
className
|
|
580
|
+
}) {
|
|
581
|
+
const [input, setInput] = useState4("");
|
|
582
|
+
const [editingIdx, setEditingIdx] = useState4(null);
|
|
583
|
+
const [editValue, setEditValue] = useState4("");
|
|
584
|
+
const inputRef = useRef3(null);
|
|
585
|
+
const hintId = hint ? `${id}-hint` : void 0;
|
|
586
|
+
const errorId = error ? `${id}-error` : void 0;
|
|
587
|
+
const describedBy = [hintId, errorId].filter(Boolean).join(" ") || void 0;
|
|
588
|
+
function addTags(raw) {
|
|
589
|
+
const tags = raw.split(",").map((t) => t.trim()).filter(Boolean);
|
|
590
|
+
onChange([.../* @__PURE__ */ new Set([...value, ...tags])]);
|
|
591
|
+
setInput("");
|
|
592
|
+
}
|
|
593
|
+
function removeTag(idx) {
|
|
594
|
+
onChange(value.filter((_, i) => i !== idx));
|
|
595
|
+
}
|
|
596
|
+
function handleInputChange(v) {
|
|
597
|
+
if (v.includes(",")) {
|
|
598
|
+
const parts = v.split(",");
|
|
599
|
+
parts.slice(0, -1).forEach((p) => p.trim() && addTags(p));
|
|
600
|
+
setInput(parts[parts.length - 1]);
|
|
601
|
+
} else {
|
|
602
|
+
setInput(v);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function handleKeyDown(e) {
|
|
606
|
+
if ((e.key === "Enter" || e.key === ",") && input.trim()) {
|
|
607
|
+
e.preventDefault();
|
|
608
|
+
addTags(input);
|
|
609
|
+
} else if (e.key === "Backspace" && !input && value.length) {
|
|
610
|
+
removeTag(value.length - 1);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
function finishEdit() {
|
|
614
|
+
if (editingIdx === null) return;
|
|
615
|
+
const trimmed = editValue.trim();
|
|
616
|
+
if (trimmed) {
|
|
617
|
+
const next = [...value];
|
|
618
|
+
next[editingIdx] = trimmed;
|
|
619
|
+
onChange([...new Set(next)]);
|
|
620
|
+
}
|
|
621
|
+
setEditingIdx(null);
|
|
622
|
+
setEditValue("");
|
|
623
|
+
}
|
|
624
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn("space-y-1", className), children: [
|
|
625
|
+
/* @__PURE__ */ jsx6("label", { htmlFor: id, className: "block text-sm font-medium text-text-primary", children: label }),
|
|
626
|
+
/* @__PURE__ */ jsxs6(
|
|
627
|
+
"div",
|
|
628
|
+
{
|
|
629
|
+
onClick: () => {
|
|
630
|
+
var _a;
|
|
631
|
+
return (_a = inputRef.current) == null ? void 0 : _a.focus();
|
|
632
|
+
},
|
|
633
|
+
className: cn(
|
|
634
|
+
"flex flex-wrap gap-1.5 min-h-10 w-full rounded-md border px-3 py-2 transition-colors cursor-text",
|
|
635
|
+
"focus-within:ring-2 focus-within:ring-border-focus focus-within:border-border-focus",
|
|
636
|
+
disabled ? "opacity-50 cursor-not-allowed bg-surface-sunken border-border" : "bg-surface-base border-border",
|
|
637
|
+
error && "border-error ring-1 ring-error bg-error-subtle"
|
|
638
|
+
),
|
|
639
|
+
children: [
|
|
640
|
+
value.map(
|
|
641
|
+
(tag, i) => editingIdx === i ? /* @__PURE__ */ jsx6(
|
|
642
|
+
"input",
|
|
643
|
+
{
|
|
644
|
+
type: "text",
|
|
645
|
+
value: editValue,
|
|
646
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
647
|
+
onBlur: finishEdit,
|
|
648
|
+
onKeyDown: (e) => {
|
|
649
|
+
if (e.key === "Enter") {
|
|
650
|
+
e.preventDefault();
|
|
651
|
+
finishEdit();
|
|
652
|
+
}
|
|
653
|
+
if (e.key === "Escape") {
|
|
654
|
+
setEditingIdx(null);
|
|
655
|
+
setEditValue("");
|
|
656
|
+
}
|
|
657
|
+
},
|
|
658
|
+
autoFocus: true,
|
|
659
|
+
className: "inline-block w-24 rounded border border-border-focus bg-surface-base px-1.5 py-0.5 text-xs text-text-primary outline-none"
|
|
660
|
+
},
|
|
661
|
+
i
|
|
662
|
+
) : /* @__PURE__ */ jsxs6(
|
|
663
|
+
"span",
|
|
664
|
+
{
|
|
665
|
+
className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-primary-subtle text-primary",
|
|
666
|
+
onDoubleClick: () => {
|
|
667
|
+
if (!disabled) {
|
|
668
|
+
setEditingIdx(i);
|
|
669
|
+
setEditValue(tag);
|
|
670
|
+
}
|
|
671
|
+
},
|
|
672
|
+
title: "Double-click to edit",
|
|
673
|
+
children: [
|
|
674
|
+
tag,
|
|
675
|
+
!disabled && /* @__PURE__ */ jsx6(
|
|
676
|
+
"button",
|
|
677
|
+
{
|
|
678
|
+
type: "button",
|
|
679
|
+
onClick: (e) => {
|
|
680
|
+
e.stopPropagation();
|
|
681
|
+
removeTag(i);
|
|
682
|
+
},
|
|
683
|
+
"aria-label": `Remove ${tag}`,
|
|
684
|
+
className: "hover:opacity-70 focus-visible:outline-none rounded-full",
|
|
685
|
+
children: /* @__PURE__ */ jsx6(FontAwesomeIcon4, { icon: faXmark3, className: "w-2.5 h-2.5" })
|
|
686
|
+
}
|
|
687
|
+
)
|
|
688
|
+
]
|
|
689
|
+
},
|
|
690
|
+
i
|
|
691
|
+
)
|
|
692
|
+
),
|
|
693
|
+
!disabled && /* @__PURE__ */ jsx6(
|
|
694
|
+
"input",
|
|
695
|
+
{
|
|
696
|
+
ref: inputRef,
|
|
697
|
+
id,
|
|
698
|
+
value: input,
|
|
699
|
+
onChange: (e) => handleInputChange(e.target.value),
|
|
700
|
+
onKeyDown: handleKeyDown,
|
|
701
|
+
onBlur: () => {
|
|
702
|
+
if (input.trim()) addTags(input);
|
|
703
|
+
},
|
|
704
|
+
placeholder: value.length === 0 ? placeholder : void 0,
|
|
705
|
+
"aria-describedby": describedBy,
|
|
706
|
+
className: "flex-1 min-w-24 bg-transparent text-sm text-text-primary placeholder:text-text-disabled outline-none"
|
|
707
|
+
}
|
|
708
|
+
)
|
|
709
|
+
]
|
|
710
|
+
}
|
|
711
|
+
),
|
|
712
|
+
hint && !error && /* @__PURE__ */ jsx6("p", { id: hintId, className: "text-xs text-text-secondary", children: hint }),
|
|
713
|
+
!hint && !error && value.length > 0 && /* @__PURE__ */ jsx6("p", { className: "text-xs text-text-disabled", children: "Double-click a tag to edit it" }),
|
|
714
|
+
error && /* @__PURE__ */ jsx6("p", { id: errorId, className: "text-xs text-error", role: "alert", children: error })
|
|
715
|
+
] });
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
export {
|
|
719
|
+
Avatar,
|
|
720
|
+
AvatarGroup,
|
|
721
|
+
Badge,
|
|
722
|
+
Select,
|
|
723
|
+
AlertBanner,
|
|
724
|
+
DropdownMenu,
|
|
725
|
+
TagInput
|
|
726
|
+
};
|