@reopt-ai/opt-ui 1.10.0 → 1.12.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/COMPONENT_CATALOG.md +522 -218
- package/README.md +61 -7
- package/dist/core/index.cjs +10 -8
- package/dist/core/index.d.cts +3 -3
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +3 -3
- package/dist/docs/02-components/01-core.md +213 -96
- package/dist/docs/02-components/02-visuals.md +1 -1
- package/dist/docs/02-components/03-shells.md +334 -123
- package/dist/docs/02-components/04-surfaces.md +1 -1
- package/dist/docs/02-components/index.md +5 -5
- package/dist/docs/03-recipes/02-dashboards.md +126 -10
- package/dist/{field-sidebar-B6Ndr8HE.cjs → field-sidebar-BYgEmdy0.cjs} +2128 -1558
- package/dist/{field-sidebar-BXjvV7Cz.js → field-sidebar-BuO37l4c.js} +2111 -1561
- package/dist/{field-sidebar-nwcE9LC4.d.cts → field-sidebar-CrYlRZew.d.ts} +375 -154
- package/dist/{field-sidebar-DWfJAJlx.d.ts → field-sidebar-uXmoyvd7.d.cts} +375 -154
- package/dist/id-registry.cjs +124 -12
- package/dist/id-registry.d.cts +1 -2
- package/dist/id-registry.d.ts +1 -2
- package/dist/id-registry.js +124 -14
- package/dist/id-registry.json +265 -31
- package/dist/index.cjs +1162 -253
- package/dist/index.d.cts +573 -60
- package/dist/index.d.ts +573 -60
- package/dist/index.js +1134 -242
- package/dist/{key-pad-menu-DfZbeXhG.d.cts → key-pad-menu-CwcY_Vps.d.cts} +151 -7
- package/dist/{key-pad-menu-BQunU20e.js → key-pad-menu-Di2aRGbM.js} +388 -461
- package/dist/{key-pad-menu-D5mQcS5v.cjs → key-pad-menu-SItoHPLu.cjs} +490 -609
- package/dist/{key-pad-menu-BsgJMjD4.d.ts → key-pad-menu-WBJShCJn.d.ts} +152 -8
- package/dist/meta.cjs +1304 -168
- package/dist/meta.d.cts +12 -36
- package/dist/meta.d.ts +12 -36
- package/dist/meta.js +1304 -170
- package/dist/query.d.cts +1 -2
- package/dist/query.d.ts +1 -2
- package/dist/query.js +0 -2
- package/dist/shells/index.cjs +4 -1
- package/dist/shells/index.d.cts +2 -2
- package/dist/shells/index.d.ts +2 -2
- package/dist/shells/index.js +2 -2
- package/dist/{text-truncate-BGr7bB_8.d.cts → text-truncate-CQyfUZvq.d.cts} +48 -5
- package/dist/{text-truncate-BGr7bB_8.d.ts → text-truncate-CQyfUZvq.d.ts} +48 -5
- package/dist/{text-truncate-j6X3z7Pv.js → text-truncate-DSuZECy0.js} +446 -94
- package/dist/{text-truncate-CxdzAnhS.cjs → text-truncate-I1XLWmRa.cjs} +522 -90
- package/dist/theme/server.d.cts +1 -2
- package/dist/theme/server.d.ts +1 -2
- package/dist/theme/server.js +0 -2
- package/dist/visuals/index.js +0 -1
- package/package.json +4 -3
- package/dist/field-sidebar-BXjvV7Cz.js.map +0 -1
- package/dist/field-sidebar-DWfJAJlx.d.ts.map +0 -1
- package/dist/field-sidebar-nwcE9LC4.d.cts.map +0 -1
- package/dist/id-registry.d.cts.map +0 -1
- package/dist/id-registry.d.ts.map +0 -1
- package/dist/id-registry.js.map +0 -1
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/key-pad-menu-BQunU20e.js.map +0 -1
- package/dist/key-pad-menu-BsgJMjD4.d.ts.map +0 -1
- package/dist/key-pad-menu-DfZbeXhG.d.cts.map +0 -1
- package/dist/meta.d.cts.map +0 -1
- package/dist/meta.d.ts.map +0 -1
- package/dist/meta.js.map +0 -1
- package/dist/query.d.cts.map +0 -1
- package/dist/query.d.ts.map +0 -1
- package/dist/query.js.map +0 -1
- package/dist/text-truncate-BGr7bB_8.d.cts.map +0 -1
- package/dist/text-truncate-BGr7bB_8.d.ts.map +0 -1
- package/dist/text-truncate-j6X3z7Pv.js.map +0 -1
- package/dist/theme/server.d.cts.map +0 -1
- package/dist/theme/server.d.ts.map +0 -1
- package/dist/theme/server.js.map +0 -1
|
@@ -4,7 +4,7 @@ import { twMerge } from "tailwind-merge";
|
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import { createContext, forwardRef, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
7
|
-
import { AlertDialogPanel, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxPopover, ComboboxRoot, Composite, CompositeItem, CompositeProvider, CompositeRow, DialogDescription, DialogDisclosure, DialogDismiss, DialogHeading, DialogPanel, DialogRoot, DisclosureContent, DisclosureRoot, DisclosureTrigger, FormCheckbox, FormControl, FormDescription, FormError, FormField, FormGroup, FormGroupLabel, FormInput, FormLabel, FormProvider, FormPush, FormRadio, FormRadioGroup, FormRemove, FormReset, FormRoot, FormSubmit, FormSwitch, MenuButtonArrow, MenuItem, MenuItemCheckbox, MenuItemRadio, MenuPopover, MenuRoot, MenuSeparator, MenuTrigger, MenubarContainer, MenubarRoot, PopoverClose, PopoverContent, PopoverRoot, PopoverTrigger, SelectItem, SelectLabel, SelectPopover, SelectRoot, SelectTrigger, Tab, TabList, TabPanel, TabsRoot, ToolbarButton, ToolbarContainer, ToolbarRoot, ToolbarSeparator, Tooltip, TooltipAnchor, TooltipProvider, useFieldValue, useFormContext, useFormStore } from "@reopt-ai/opt-ui-primitives";
|
|
7
|
+
import { AlertDialogPanel, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxPopover, ComboboxRoot, Composite, CompositeItem, CompositeProvider, CompositeRow, DialogDescription, DialogDisclosure, DialogDismiss, DialogHeading, DialogPanel, DialogRoot, DisclosureContent, DisclosureRoot, DisclosureTrigger, FormCheckbox, FormControl, FormDescription, FormError, FormField, FormGroup, FormGroupLabel, FormInput, FormLabel, FormProvider, FormPush, FormRadio, FormRadioGroup, FormRemove, FormReset, FormRoot, FormSubmit, FormSwitch, MenuButtonArrow, MenuItem, MenuItemCheckbox, MenuItemRadio, MenuPopover, MenuRoot, MenuSeparator, MenuTrigger, MenubarContainer, MenubarRoot, Meter, PopoverClose, PopoverContent, PopoverRoot, PopoverTrigger, SelectItem, SelectLabel, SelectPopover, SelectRoot, SelectTrigger, Tab, TabList, TabPanel, TabsRoot, ToolbarButton, ToolbarContainer, ToolbarRoot, ToolbarSeparator, Tooltip, TooltipAnchor, TooltipProvider, useFieldValue, useFormContext, useFormStore } from "@reopt-ai/opt-ui-primitives";
|
|
8
8
|
import { AtSign, Bell, Binary, Braces, Brackets, Calendar, CalendarClock, CalendarDays, ChartColumn, Check, ChevronLeft, ChevronRight, CircleAlert, CircleCheck, CircleDollarSign, CircleHelp, CreditCard, Download, Eye, FileText, Fingerprint, Flag, Folder, Globe, Hash, Heart, Info, Layers, Link2, List, LogIn, Mail, MapPin, MessageCircle, MousePointerClick, Network, Percent, Search, Settings, Share2, ShoppingCart, Sigma, Star, Timer, ToggleLeft, TrendingUp, TriangleAlert, Type, Upload, User, UserPlus, XCircle, Zap } from "lucide-react";
|
|
9
9
|
//#region src/lib/cn.ts
|
|
10
10
|
/** Handles cn. */
|
|
@@ -120,6 +120,7 @@ const OPT_HOVER_ITEM = "[@media(any-hover:hover)]:hover:bg-accent-subtle active:
|
|
|
120
120
|
const OPT_BORDER = "border border-border";
|
|
121
121
|
const OPT_DIVIDER = "divide-border-subtle";
|
|
122
122
|
const OPT_SURFACE = "rounded-lg bg-surface shadow-sm";
|
|
123
|
+
const OPT_SURFACE_RAISED = "rounded-xl bg-surface-raised shadow-md";
|
|
123
124
|
const OPT_SURFACE_POPOVER = "z-50 rounded-lg border border-border bg-surface-overlay p-2 shadow-lg";
|
|
124
125
|
const OPT_TEXT_PRIMARY = "text-text-primary";
|
|
125
126
|
const OPT_TEXT_SECONDARY = "text-text-secondary";
|
|
@@ -149,7 +150,7 @@ const OPT_BUTTON_SECONDARY = "inline-flex h-10 items-center justify-center round
|
|
|
149
150
|
const OPT_TH = "px-3 py-2.5 text-left text-xs font-semibold uppercase tracking-wider text-text-tertiary";
|
|
150
151
|
const OPT_TD = "px-3 py-2.5 text-sm text-text-primary whitespace-nowrap";
|
|
151
152
|
const OPT_TD_MUTED = "px-3 py-2.5 text-sm text-text-tertiary whitespace-nowrap";
|
|
152
|
-
const OPT_TABLE_ROW_ACTIVE = "outline-none data-[
|
|
153
|
+
const OPT_TABLE_ROW_ACTIVE = "outline-none data-[focus-visible]:bg-accent-subtle data-[focus-visible]:outline-2 data-[focus-visible]:outline-ring data-[focus-visible]:-outline-offset-1";
|
|
153
154
|
const OPT_DISCLOSURE_TRIGGER = "flex w-full items-center justify-between px-4 py-3.5 text-left text-sm font-medium text-text-primary outline-none hover:underline decoration-border underline-offset-2 data-[focus-visible]:outline-2 data-[focus-visible]:outline-ring data-[focus-visible]:-outline-offset-2";
|
|
154
155
|
const OPT_DISCLOSURE_CONTENT = "overflow-hidden data-[enter]:animate-in data-[enter]:fade-in data-[leave]:animate-out data-[leave]:fade-out";
|
|
155
156
|
const OPT_ANIMATE_ENTER_EXIT = "data-[enter]:animate-in data-[enter]:fade-in data-[enter]:slide-in-from-top-1 data-[leave]:animate-out data-[leave]:fade-out";
|
|
@@ -218,44 +219,230 @@ function useControlledState(defaultValue, controlledValue, onChange) {
|
|
|
218
219
|
}, [isControlled, onChange])];
|
|
219
220
|
}
|
|
220
221
|
//#endregion
|
|
222
|
+
//#region src/core/skeleton.tsx
|
|
223
|
+
const _excluded$17 = [
|
|
224
|
+
"variant",
|
|
225
|
+
"width",
|
|
226
|
+
"height",
|
|
227
|
+
"lines",
|
|
228
|
+
"animated",
|
|
229
|
+
"className",
|
|
230
|
+
"style"
|
|
231
|
+
];
|
|
232
|
+
const _excluded2$9 = ["lines", "className"];
|
|
233
|
+
const _excluded3$8 = ["size", "className"];
|
|
234
|
+
const _excluded4$6 = ["className"];
|
|
235
|
+
const variantStyles$4 = {
|
|
236
|
+
text: "rounded h-4",
|
|
237
|
+
circular: "rounded-full",
|
|
238
|
+
rectangular: "rounded-lg"
|
|
239
|
+
};
|
|
240
|
+
/** Renders the skeleton component. */
|
|
241
|
+
function Skeleton(_ref) {
|
|
242
|
+
let { variant = "text", width, height, lines = 1, animated = true, className, style } = _ref, props = _objectWithoutProperties(_ref, _excluded$17);
|
|
243
|
+
const baseClass = cn("bg-bg-subtle", animated && "animate-pulse", variantStyles$4[variant], className);
|
|
244
|
+
const computedStyle = _objectSpread2({
|
|
245
|
+
width: typeof width === "number" ? `${width}px` : width,
|
|
246
|
+
height: typeof height === "number" ? `${height}px` : height
|
|
247
|
+
}, style);
|
|
248
|
+
if (variant === "text" && lines > 1) return /* @__PURE__ */ jsxs("div", {
|
|
249
|
+
className: "gap-element flex flex-col",
|
|
250
|
+
role: "status",
|
|
251
|
+
"aria-label": "Loading",
|
|
252
|
+
"data-opt-id": "EJT87",
|
|
253
|
+
"data-opt-slug": "skeleton.Skeleton",
|
|
254
|
+
children: [Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx("div", _objectSpread2({
|
|
255
|
+
className: cn(baseClass, i === lines - 1 && "w-4/5"),
|
|
256
|
+
style: i === lines - 1 ? void 0 : computedStyle
|
|
257
|
+
}, props), i)), /* @__PURE__ */ jsx("span", {
|
|
258
|
+
className: "sr-only",
|
|
259
|
+
children: "Loading..."
|
|
260
|
+
})]
|
|
261
|
+
});
|
|
262
|
+
return /* @__PURE__ */ jsx("div", _objectSpread2(_objectSpread2({
|
|
263
|
+
className: baseClass,
|
|
264
|
+
style: computedStyle,
|
|
265
|
+
role: "status",
|
|
266
|
+
"aria-label": "Loading"
|
|
267
|
+
}, props), {}, {
|
|
268
|
+
"data-opt-id": "EJT87",
|
|
269
|
+
"data-opt-slug": "skeleton.Skeleton",
|
|
270
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
271
|
+
className: "sr-only",
|
|
272
|
+
children: "Loading..."
|
|
273
|
+
})
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
/** Renders the skeleton text component. */
|
|
277
|
+
function SkeletonText(_ref2) {
|
|
278
|
+
let { lines = 3, className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded2$9);
|
|
279
|
+
return /* @__PURE__ */ jsx(Skeleton, _objectSpread2(_objectSpread2({
|
|
280
|
+
variant: "text",
|
|
281
|
+
lines,
|
|
282
|
+
className
|
|
283
|
+
}, props), {}, {
|
|
284
|
+
"data-opt-id": "MX3D5",
|
|
285
|
+
"data-opt-slug": "skeleton.SkeletonText"
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
/** Renders the skeleton avatar component. */
|
|
289
|
+
function SkeletonAvatar(_ref3) {
|
|
290
|
+
let { size = 40, className } = _ref3, props = _objectWithoutProperties(_ref3, _excluded3$8);
|
|
291
|
+
return /* @__PURE__ */ jsx(Skeleton, _objectSpread2(_objectSpread2({
|
|
292
|
+
variant: "circular",
|
|
293
|
+
width: size,
|
|
294
|
+
height: size,
|
|
295
|
+
className
|
|
296
|
+
}, props), {}, {
|
|
297
|
+
"data-opt-id": "MP0HZ",
|
|
298
|
+
"data-opt-slug": "skeleton.SkeletonAvatar"
|
|
299
|
+
}));
|
|
300
|
+
}
|
|
301
|
+
/** Renders the skeleton card component. */
|
|
302
|
+
function SkeletonCard(_ref4) {
|
|
303
|
+
let { className } = _ref4, props = _objectWithoutProperties(_ref4, _excluded4$6);
|
|
304
|
+
return /* @__PURE__ */ jsxs("div", _objectSpread2(_objectSpread2({ className: cn("gap-group flex flex-col", className) }, props), {}, {
|
|
305
|
+
"data-opt-id": "34V5D",
|
|
306
|
+
"data-opt-slug": "skeleton.SkeletonCard",
|
|
307
|
+
children: [
|
|
308
|
+
/* @__PURE__ */ jsx(Skeleton, {
|
|
309
|
+
variant: "rectangular",
|
|
310
|
+
height: 120
|
|
311
|
+
}),
|
|
312
|
+
/* @__PURE__ */ jsx(Skeleton, {
|
|
313
|
+
variant: "text",
|
|
314
|
+
width: "60%"
|
|
315
|
+
}),
|
|
316
|
+
/* @__PURE__ */ jsx(Skeleton, {
|
|
317
|
+
variant: "text",
|
|
318
|
+
lines: 2
|
|
319
|
+
})
|
|
320
|
+
]
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
/** Renders the skeleton table component. */
|
|
324
|
+
function SkeletonTable({ rows = 5, columns = 4, className }) {
|
|
325
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
326
|
+
className: cn("gap-element flex flex-col", className),
|
|
327
|
+
role: "status",
|
|
328
|
+
"aria-label": "Loading table",
|
|
329
|
+
"data-opt-id": "3KEDN",
|
|
330
|
+
"data-opt-slug": "skeleton.SkeletonTable",
|
|
331
|
+
children: [
|
|
332
|
+
/* @__PURE__ */ jsx("div", {
|
|
333
|
+
className: "border-border-subtle gap-group flex border-b pb-2",
|
|
334
|
+
children: Array.from({ length: columns }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, {
|
|
335
|
+
variant: "text",
|
|
336
|
+
className: "flex-1",
|
|
337
|
+
height: 16
|
|
338
|
+
}, i))
|
|
339
|
+
}),
|
|
340
|
+
Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx("div", {
|
|
341
|
+
className: "gap-group flex py-2",
|
|
342
|
+
children: Array.from({ length: columns }).map((_, colIndex) => /* @__PURE__ */ jsx(Skeleton, {
|
|
343
|
+
variant: "text",
|
|
344
|
+
className: "flex-1",
|
|
345
|
+
height: 14
|
|
346
|
+
}, colIndex))
|
|
347
|
+
}, rowIndex)),
|
|
348
|
+
/* @__PURE__ */ jsx("span", {
|
|
349
|
+
className: "sr-only",
|
|
350
|
+
children: "Loading..."
|
|
351
|
+
})
|
|
352
|
+
]
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
221
356
|
//#region src/core/stat-card.tsx
|
|
357
|
+
const TREND_GLYPH = {
|
|
358
|
+
up: "↑",
|
|
359
|
+
down: "↓",
|
|
360
|
+
neutral: "→"
|
|
361
|
+
};
|
|
362
|
+
/**
|
|
363
|
+
* Colour follows meaning, not direction. A rising bounce rate is a fall in
|
|
364
|
+
* quality, so a card declaring `polarity: "negative"` inverts the palette
|
|
365
|
+
* rather than congratulating the reader on a worse number.
|
|
366
|
+
*/
|
|
367
|
+
function deltaToneClass(trend, polarity) {
|
|
368
|
+
if (trend === "neutral") return OPT_TEXT_TERTIARY;
|
|
369
|
+
return (polarity === "positive" ? trend === "up" : trend === "down") ? "text-success-fg" : "text-danger-fg";
|
|
370
|
+
}
|
|
371
|
+
function sparkStroke(trend, polarity) {
|
|
372
|
+
if (!trend || trend === "neutral") return "var(--opt-chart-1)";
|
|
373
|
+
return (polarity === "positive" ? trend === "up" : trend === "down") ? "var(--opt-chart-diverging-positive)" : "var(--opt-chart-diverging-negative)";
|
|
374
|
+
}
|
|
222
375
|
/** Renders the stat card component. */
|
|
223
|
-
function StatCard({ title, value, change, trend, sparklineData, className }) {
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
className: "
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
376
|
+
function StatCard({ title, value, change, trend, polarity = "positive", description, hint, sparklineData, size = "md", loading = false, href, onSelect, selected = false, className }) {
|
|
377
|
+
const titleId = React.useId();
|
|
378
|
+
const hintId = React.useId();
|
|
379
|
+
const hasDelta = Boolean(change) && trend !== void 0;
|
|
380
|
+
const interactive = Boolean(href || onSelect);
|
|
381
|
+
const body = loading ? /* @__PURE__ */ jsxs("div", {
|
|
382
|
+
className: "flex flex-col gap-2",
|
|
383
|
+
children: [
|
|
384
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
|
|
385
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-32" }),
|
|
386
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-20" })
|
|
387
|
+
]
|
|
388
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
389
|
+
className: "flex items-start justify-between gap-4",
|
|
390
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
391
|
+
className: "flex min-w-0 flex-col gap-1",
|
|
392
|
+
children: [
|
|
393
|
+
/* @__PURE__ */ jsx("span", {
|
|
394
|
+
id: titleId,
|
|
395
|
+
className: cn(OPT_TEXT_SECONDARY, "truncate text-sm"),
|
|
396
|
+
children: title
|
|
397
|
+
}),
|
|
398
|
+
/* @__PURE__ */ jsx("span", {
|
|
399
|
+
className: cn(OPT_TEXT_PRIMARY, "font-bold tabular-nums", size === "sm" ? "text-xl" : "text-2xl"),
|
|
400
|
+
children: value
|
|
401
|
+
}),
|
|
402
|
+
hasDelta && /* @__PURE__ */ jsxs("span", {
|
|
403
|
+
className: cn("text-sm font-medium tabular-nums", deltaToneClass(trend, polarity)),
|
|
404
|
+
children: [
|
|
405
|
+
TREND_GLYPH[trend],
|
|
406
|
+
" ",
|
|
407
|
+
change
|
|
408
|
+
]
|
|
409
|
+
}),
|
|
410
|
+
description && /* @__PURE__ */ jsx("span", {
|
|
411
|
+
className: cn("text-text-tertiary", "text-xs"),
|
|
412
|
+
children: description
|
|
413
|
+
}),
|
|
414
|
+
hint && /* @__PURE__ */ jsx("span", {
|
|
415
|
+
id: hintId,
|
|
416
|
+
className: "sr-only",
|
|
417
|
+
children: hint
|
|
418
|
+
})
|
|
419
|
+
]
|
|
420
|
+
}), sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(MiniSparkline, {
|
|
421
|
+
data: sparklineData,
|
|
422
|
+
color: sparkStroke(trend, polarity)
|
|
423
|
+
})]
|
|
258
424
|
});
|
|
425
|
+
const shared = {
|
|
426
|
+
className: cn(OPT_SURFACE, OPT_BORDER, "flex flex-col gap-1", size === "sm" ? "p-4" : "p-5", interactive && [
|
|
427
|
+
"hover:border-border-hover",
|
|
428
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset",
|
|
429
|
+
"cursor-pointer text-left transition-colors"
|
|
430
|
+
], selected && "border-accent", className),
|
|
431
|
+
title: hint,
|
|
432
|
+
"aria-describedby": hint ? hintId : void 0,
|
|
433
|
+
"data-opt-id": "GAX47",
|
|
434
|
+
"data-opt-slug": "stat-card.StatCard"
|
|
435
|
+
};
|
|
436
|
+
if (href) return /* @__PURE__ */ jsx("a", _objectSpread2(_objectSpread2({
|
|
437
|
+
href,
|
|
438
|
+
"aria-current": selected ? "true" : void 0
|
|
439
|
+
}, shared), {}, { children: body }));
|
|
440
|
+
if (onSelect) return /* @__PURE__ */ jsx("button", _objectSpread2(_objectSpread2({
|
|
441
|
+
type: "button",
|
|
442
|
+
onClick: onSelect,
|
|
443
|
+
"aria-pressed": selected
|
|
444
|
+
}, shared), {}, { children: body }));
|
|
445
|
+
return /* @__PURE__ */ jsx("div", _objectSpread2(_objectSpread2({}, shared), {}, { children: body }));
|
|
259
446
|
}
|
|
260
447
|
function MiniSparkline({ data, color }) {
|
|
261
448
|
const width = 80;
|
|
@@ -307,7 +494,7 @@ const koBreadcrumbLabels = {
|
|
|
307
494
|
navAriaLabel: "{label}(으)로 이동" };
|
|
308
495
|
//#endregion
|
|
309
496
|
//#region src/core/button.tsx
|
|
310
|
-
const _excluded$
|
|
497
|
+
const _excluded$16 = [
|
|
311
498
|
"variant",
|
|
312
499
|
"size",
|
|
313
500
|
"loading",
|
|
@@ -318,24 +505,24 @@ const _excluded$15 = [
|
|
|
318
505
|
"children",
|
|
319
506
|
"aria-busy"
|
|
320
507
|
];
|
|
321
|
-
const variantStyles$
|
|
508
|
+
const variantStyles$3 = {
|
|
322
509
|
primary: "bg-accent text-accent-fg hover:bg-accent-hover active:bg-accent-active focus-visible:ring-offset-2",
|
|
323
510
|
secondary: "border border-border bg-surface text-text-primary hover:bg-bg-subtle active:bg-bg-muted focus-visible:ring-offset-1",
|
|
324
511
|
ghost: "text-text-secondary hover:bg-bg-subtle active:bg-bg-muted focus-visible:ring-offset-1",
|
|
325
512
|
danger: "bg-danger text-danger-fg hover:bg-danger active:bg-danger focus-visible:ring-offset-2"
|
|
326
513
|
};
|
|
327
|
-
const sizeStyles$
|
|
514
|
+
const sizeStyles$5 = {
|
|
328
515
|
sm: "h-[var(--opt-control-sm)] px-[var(--opt-control-padding-sm)] text-xs gap-[var(--opt-space-1-5)]",
|
|
329
516
|
md: "h-[var(--opt-control-md)] px-[var(--opt-control-padding-md)] text-sm gap-[var(--opt-space-2)]",
|
|
330
517
|
lg: "h-[var(--opt-control-lg)] px-[var(--opt-control-padding-lg)] text-base gap-[var(--opt-space-2)]"
|
|
331
518
|
};
|
|
332
519
|
/** Renders the button component. */
|
|
333
520
|
function Button(_ref) {
|
|
334
|
-
let { variant = "primary", size = "md", loading = false, leftIcon, rightIcon, className, disabled, children, "aria-busy": ariaBusy } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
521
|
+
let { variant = "primary", size = "md", loading = false, leftIcon, rightIcon, className, disabled, children, "aria-busy": ariaBusy } = _ref, props = _objectWithoutProperties(_ref, _excluded$16);
|
|
335
522
|
const isDisabled = disabled || loading;
|
|
336
523
|
return /* @__PURE__ */ jsxs("button", _objectSpread2(_objectSpread2({
|
|
337
524
|
type: "button",
|
|
338
|
-
className: cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", OPT_FOCUS_VISIBLE, variantStyles$
|
|
525
|
+
className: cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", OPT_FOCUS_VISIBLE, variantStyles$3[variant], sizeStyles$5[size], isDisabled && "pointer-events-none cursor-not-allowed opacity-50", className),
|
|
339
526
|
disabled: isDisabled
|
|
340
527
|
}, props), {}, {
|
|
341
528
|
"aria-busy": loading ? true : ariaBusy,
|
|
@@ -377,44 +564,68 @@ const iconSizeClasses = {
|
|
|
377
564
|
md: "text-4xl",
|
|
378
565
|
lg: "text-5xl"
|
|
379
566
|
};
|
|
567
|
+
const titleSizeClasses = {
|
|
568
|
+
sm: "text-base font-semibold",
|
|
569
|
+
md: "text-lg font-semibold",
|
|
570
|
+
lg: "text-xl font-semibold"
|
|
571
|
+
};
|
|
572
|
+
const iconToneClasses = {
|
|
573
|
+
default: OPT_TEXT_TERTIARY,
|
|
574
|
+
subdued: OPT_TEXT_TERTIARY,
|
|
575
|
+
error: "text-danger-fg"
|
|
576
|
+
};
|
|
577
|
+
function isActionList(actions) {
|
|
578
|
+
return Array.isArray(actions) && actions.every((entry) => typeof entry === "object" && entry !== null && "onClick" in entry);
|
|
579
|
+
}
|
|
380
580
|
/** Renders the empty state component. */
|
|
381
|
-
function EmptyState({ icon, title, description, actions, className, iconSize = "md", headingLevel = "h3" }) {
|
|
581
|
+
function EmptyState({ icon, title, description, body, footer, actions, className, iconSize = "md", headingLevel = "h3", titleSize = "md", layout = "vertical", hasBorder = false, tone = "default" }) {
|
|
382
582
|
const HeadingTag = headingLevel;
|
|
583
|
+
const horizontal = layout === "horizontal";
|
|
584
|
+
const hasActions = isActionList(actions) ? actions.length > 0 : Boolean(actions);
|
|
383
585
|
return /* @__PURE__ */ jsxs("div", {
|
|
384
|
-
role: "status",
|
|
586
|
+
role: tone === "error" ? "alert" : "status",
|
|
385
587
|
"aria-label": title,
|
|
386
|
-
className: cn("flex flex-
|
|
387
|
-
"data-opt-id": "
|
|
588
|
+
className: cn("flex px-4 py-12", horizontal ? "flex-row items-center justify-center gap-8 text-left" : "flex-col items-center justify-center text-center", hasBorder && ["border border-border", "rounded-xl"], tone === "subdued" && "bg-bg-subtle", className),
|
|
589
|
+
"data-opt-id": "MZV19",
|
|
388
590
|
"data-opt-slug": "empty-state.EmptyState",
|
|
389
|
-
children: [
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
children: action
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
591
|
+
children: [icon && /* @__PURE__ */ jsx("div", {
|
|
592
|
+
className: cn(iconToneClasses[tone], iconSizeClasses[iconSize], horizontal ? "shrink-0" : "mb-4"),
|
|
593
|
+
"aria-hidden": "true",
|
|
594
|
+
children: icon
|
|
595
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
596
|
+
className: cn("flex flex-col", horizontal ? "items-start" : "items-center"),
|
|
597
|
+
children: [
|
|
598
|
+
/* @__PURE__ */ jsx(HeadingTag, {
|
|
599
|
+
className: cn(titleSizeClasses[titleSize], OPT_TEXT_PRIMARY),
|
|
600
|
+
children: title
|
|
601
|
+
}),
|
|
602
|
+
body ? /* @__PURE__ */ jsx("div", {
|
|
603
|
+
className: cn("mt-2 max-w-md text-sm", OPT_TEXT_SECONDARY),
|
|
604
|
+
children: body
|
|
605
|
+
}) : description && /* @__PURE__ */ jsx("p", {
|
|
606
|
+
className: cn("mt-2 max-w-sm text-sm", "text-text-secondary"),
|
|
607
|
+
children: description
|
|
608
|
+
}),
|
|
609
|
+
hasActions && /* @__PURE__ */ jsx("div", {
|
|
610
|
+
className: cn("mt-6 flex flex-wrap items-center gap-3", !horizontal && "justify-center"),
|
|
611
|
+
children: isActionList(actions) ? actions.map((action) => /* @__PURE__ */ jsx(Button, {
|
|
612
|
+
onClick: action.onClick,
|
|
613
|
+
disabled: action.disabled,
|
|
614
|
+
variant: action.variant === "secondary" ? "secondary" : "primary",
|
|
615
|
+
children: action.label
|
|
616
|
+
}, action.id)) : actions
|
|
617
|
+
}),
|
|
618
|
+
footer && /* @__PURE__ */ jsx("div", {
|
|
619
|
+
className: cn("border-border-subtle mt-6 w-full border-t pt-4 text-sm", "text-text-tertiary"),
|
|
620
|
+
children: footer
|
|
621
|
+
})
|
|
622
|
+
]
|
|
623
|
+
})]
|
|
413
624
|
});
|
|
414
625
|
}
|
|
415
626
|
//#endregion
|
|
416
627
|
//#region src/core/badge.tsx
|
|
417
|
-
const _excluded$
|
|
628
|
+
const _excluded$15 = [
|
|
418
629
|
"variant",
|
|
419
630
|
"size",
|
|
420
631
|
"dot",
|
|
@@ -423,7 +634,7 @@ const _excluded$14 = [
|
|
|
423
634
|
"className",
|
|
424
635
|
"children"
|
|
425
636
|
];
|
|
426
|
-
const variantStyles$
|
|
637
|
+
const variantStyles$2 = {
|
|
427
638
|
default: "bg-bg-subtle text-text-secondary",
|
|
428
639
|
success: "bg-success-subtle text-success-fg",
|
|
429
640
|
warning: "bg-warning-subtle text-warning-fg",
|
|
@@ -444,19 +655,19 @@ const progressStroke = {
|
|
|
444
655
|
error: "stroke-danger",
|
|
445
656
|
info: "stroke-info"
|
|
446
657
|
};
|
|
447
|
-
const sizeStyles$
|
|
658
|
+
const sizeStyles$4 = {
|
|
448
659
|
sm: "px-1.5 py-0.5 text-[10px]",
|
|
449
660
|
md: "px-2 py-0.5 text-[11px]"
|
|
450
661
|
};
|
|
451
662
|
/** Renders the badge component. */
|
|
452
663
|
function Badge(_ref) {
|
|
453
|
-
let { variant = "default", size = "md", dot = false, progress, progressSize = 16, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
664
|
+
let { variant = "default", size = "md", dot = false, progress, progressSize = 16, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$15);
|
|
454
665
|
const hasProgress = progress != null;
|
|
455
666
|
const clampedProgress = hasProgress ? Math.min(100, Math.max(0, progress)) : 0;
|
|
456
667
|
const radius = (progressSize - 3) / 2;
|
|
457
668
|
const circumference = 2 * Math.PI * radius;
|
|
458
669
|
const offset = circumference - clampedProgress / 100 * circumference;
|
|
459
|
-
return /* @__PURE__ */ jsxs("span", _objectSpread2(_objectSpread2({ className: cn(OPT_BADGE, variantStyles$
|
|
670
|
+
return /* @__PURE__ */ jsxs("span", _objectSpread2(_objectSpread2({ className: cn(OPT_BADGE, variantStyles$2[variant], sizeStyles$4[size], className) }, props), {}, {
|
|
460
671
|
"data-opt-id": "9GBGZ",
|
|
461
672
|
"data-opt-slug": "badge.Badge",
|
|
462
673
|
children: [
|
|
@@ -496,24 +707,24 @@ function Badge(_ref) {
|
|
|
496
707
|
}
|
|
497
708
|
//#endregion
|
|
498
709
|
//#region src/core/spinner.tsx
|
|
499
|
-
const _excluded$
|
|
710
|
+
const _excluded$14 = [
|
|
500
711
|
"size",
|
|
501
712
|
"className",
|
|
502
713
|
"role",
|
|
503
714
|
"aria-hidden",
|
|
504
715
|
"aria-label"
|
|
505
716
|
];
|
|
506
|
-
const sizeStyles$
|
|
717
|
+
const sizeStyles$3 = {
|
|
507
718
|
sm: "h-4 w-4",
|
|
508
719
|
md: "h-6 w-6",
|
|
509
720
|
lg: "h-8 w-8"
|
|
510
721
|
};
|
|
511
722
|
/** Renders the spinner component. */
|
|
512
723
|
function Spinner(_ref) {
|
|
513
|
-
let { size = "md", className, role, "aria-hidden": ariaHidden, "aria-label": ariaLabel } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
724
|
+
let { size = "md", className, role, "aria-hidden": ariaHidden, "aria-label": ariaLabel } = _ref, props = _objectWithoutProperties(_ref, _excluded$14);
|
|
514
725
|
const isDecorative = ariaHidden === true || ariaHidden === "true";
|
|
515
726
|
return /* @__PURE__ */ jsxs("svg", _objectSpread2(_objectSpread2({
|
|
516
|
-
className: cn("animate-spin text-current", sizeStyles$
|
|
727
|
+
className: cn("animate-spin text-current", sizeStyles$3[size], className),
|
|
517
728
|
viewBox: "0 0 24 24",
|
|
518
729
|
fill: "none",
|
|
519
730
|
role: isDecorative ? void 0 : role !== null && role !== void 0 ? role : "status",
|
|
@@ -538,7 +749,7 @@ function Spinner(_ref) {
|
|
|
538
749
|
}
|
|
539
750
|
//#endregion
|
|
540
751
|
//#region src/core/alert.tsx
|
|
541
|
-
const _excluded$
|
|
752
|
+
const _excluded$13 = [
|
|
542
753
|
"variant",
|
|
543
754
|
"title",
|
|
544
755
|
"icon",
|
|
@@ -547,7 +758,7 @@ const _excluded$12 = [
|
|
|
547
758
|
"className",
|
|
548
759
|
"children"
|
|
549
760
|
];
|
|
550
|
-
const variantStyles = {
|
|
761
|
+
const variantStyles$1 = {
|
|
551
762
|
info: "border-info bg-info-subtle text-info-fg",
|
|
552
763
|
success: "border-success bg-success-subtle text-success-fg",
|
|
553
764
|
warning: "border-warning bg-warning-subtle text-warning-fg",
|
|
@@ -607,11 +818,11 @@ const defaultIcons = {
|
|
|
607
818
|
};
|
|
608
819
|
/** Renders the alert component. */
|
|
609
820
|
function Alert(_ref) {
|
|
610
|
-
let { variant = "info", title, icon, dismissible = false, onDismiss, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
821
|
+
let { variant = "info", title, icon, dismissible = false, onDismiss, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$13);
|
|
611
822
|
const displayIcon = icon !== null && icon !== void 0 ? icon : defaultIcons[variant];
|
|
612
823
|
return /* @__PURE__ */ jsx("div", _objectSpread2(_objectSpread2({
|
|
613
824
|
role: "alert",
|
|
614
|
-
className: cn("relative rounded-lg border p-4", variantStyles[variant], className)
|
|
825
|
+
className: cn("relative rounded-lg border p-4", variantStyles$1[variant], className)
|
|
615
826
|
}, props), {}, {
|
|
616
827
|
"data-opt-id": "4SPK6",
|
|
617
828
|
"data-opt-slug": "alert.Alert",
|
|
@@ -663,7 +874,7 @@ function useInputId(id, label, prefix) {
|
|
|
663
874
|
}
|
|
664
875
|
//#endregion
|
|
665
876
|
//#region src/core/input.tsx
|
|
666
|
-
const _excluded$
|
|
877
|
+
const _excluded$12 = [
|
|
667
878
|
"label",
|
|
668
879
|
"error",
|
|
669
880
|
"hint",
|
|
@@ -678,7 +889,7 @@ const _excluded$11 = [
|
|
|
678
889
|
const inputSizeStyles = OPT_INPUT_SIZE;
|
|
679
890
|
const Input = forwardRef((_ref, ref) => {
|
|
680
891
|
var _useInputId;
|
|
681
|
-
let { label, error, hint, leftIcon, rightIcon, fullWidth = false, size = "md", required, className, id } = _ref, props = _objectWithoutProperties(_ref, _excluded$
|
|
892
|
+
let { label, error, hint, leftIcon, rightIcon, fullWidth = false, size = "md", required, className, id } = _ref, props = _objectWithoutProperties(_ref, _excluded$12);
|
|
682
893
|
const fallbackId = useId().replace(/:/g, "");
|
|
683
894
|
const inputId = (_useInputId = useInputId(id, label, "input")) !== null && _useInputId !== void 0 ? _useInputId : `input-${fallbackId}`;
|
|
684
895
|
const hasError = Boolean(error);
|
|
@@ -828,6 +1039,65 @@ function StarRating({ value = 0, onChange, max = 5, readOnly = false, size = "md
|
|
|
828
1039
|
});
|
|
829
1040
|
}
|
|
830
1041
|
//#endregion
|
|
1042
|
+
//#region src/core/meter.tsx
|
|
1043
|
+
const _excluded$11 = [
|
|
1044
|
+
"value",
|
|
1045
|
+
"min",
|
|
1046
|
+
"max",
|
|
1047
|
+
"size",
|
|
1048
|
+
"variant",
|
|
1049
|
+
"showValue",
|
|
1050
|
+
"label",
|
|
1051
|
+
"getValueLabel",
|
|
1052
|
+
"className"
|
|
1053
|
+
];
|
|
1054
|
+
const sizeStyles$2 = {
|
|
1055
|
+
sm: "h-1",
|
|
1056
|
+
md: "h-2",
|
|
1057
|
+
lg: "h-3"
|
|
1058
|
+
};
|
|
1059
|
+
const variantStyles = {
|
|
1060
|
+
default: "bg-accent",
|
|
1061
|
+
success: "bg-success",
|
|
1062
|
+
warning: "bg-warning",
|
|
1063
|
+
error: "bg-danger"
|
|
1064
|
+
};
|
|
1065
|
+
/**
|
|
1066
|
+
* A scalar measurement within a known range (disk usage, score, capacity) —
|
|
1067
|
+
* `role="meter"`, distinct from Progress (task completion). Built on the
|
|
1068
|
+
* opt-ui-primitives Meter primitive, which owns the role/aria/valuetext.
|
|
1069
|
+
*/
|
|
1070
|
+
function Meter$1(_ref) {
|
|
1071
|
+
let { value, min = 0, max = 100, size = "md", variant = "default", showValue = false, label, getValueLabel, className } = _ref, props = _objectWithoutProperties(_ref, _excluded$11);
|
|
1072
|
+
const clamped = Math.min(Math.max(value, min), max);
|
|
1073
|
+
const percentage = max === min ? 0 : (clamped - min) / (max - min) * 100;
|
|
1074
|
+
return /* @__PURE__ */ jsxs("div", _objectSpread2(_objectSpread2({ className: cn("w-full", className) }, props), {}, {
|
|
1075
|
+
"data-opt-id": "G01TE",
|
|
1076
|
+
"data-opt-slug": "meter.Meter",
|
|
1077
|
+
children: [(showValue || label) && /* @__PURE__ */ jsxs("div", {
|
|
1078
|
+
className: "mb-1.5 flex items-center justify-between text-sm",
|
|
1079
|
+
children: [label && /* @__PURE__ */ jsx("span", {
|
|
1080
|
+
className: "text-text-primary font-medium",
|
|
1081
|
+
children: label
|
|
1082
|
+
}), showValue && /* @__PURE__ */ jsxs("span", {
|
|
1083
|
+
className: "text-text-tertiary",
|
|
1084
|
+
children: [Math.round(percentage), "%"]
|
|
1085
|
+
})]
|
|
1086
|
+
}), /* @__PURE__ */ jsx(Meter, {
|
|
1087
|
+
value: clamped,
|
|
1088
|
+
min,
|
|
1089
|
+
max,
|
|
1090
|
+
getValueLabel,
|
|
1091
|
+
"aria-label": label !== null && label !== void 0 ? label : `${Math.round(percentage)}%`,
|
|
1092
|
+
className: cn("bg-bg-subtle w-full overflow-hidden rounded-full", sizeStyles$2[size]),
|
|
1093
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1094
|
+
className: cn("h-full rounded-full transition-all duration-300 ease-out", variantStyles[variant]),
|
|
1095
|
+
style: { width: `${percentage}%` }
|
|
1096
|
+
})
|
|
1097
|
+
})]
|
|
1098
|
+
}));
|
|
1099
|
+
}
|
|
1100
|
+
//#endregion
|
|
831
1101
|
//#region src/core/composite-zone.tsx
|
|
832
1102
|
/** Renders the composite zone component. */
|
|
833
1103
|
function CompositeZone({ children, label, focusLoop = true, focusWrap = true, className }) {
|
|
@@ -3510,6 +3780,55 @@ function FormDateRangePicker(_ref35) {
|
|
|
3510
3780
|
}));
|
|
3511
3781
|
}
|
|
3512
3782
|
//#endregion
|
|
3783
|
+
//#region src/lib/formatters.ts
|
|
3784
|
+
const OPT_UI_DEFAULT_LOCALE = "ko-KR";
|
|
3785
|
+
const KST_OFFSET_MS = 324e5;
|
|
3786
|
+
function getKstDateParts(input) {
|
|
3787
|
+
const date = input instanceof Date ? input : new Date(input);
|
|
3788
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
3789
|
+
const kstDate = new Date(date.getTime() + KST_OFFSET_MS);
|
|
3790
|
+
return {
|
|
3791
|
+
year: kstDate.getUTCFullYear(),
|
|
3792
|
+
month: kstDate.getUTCMonth() + 1,
|
|
3793
|
+
day: kstDate.getUTCDate(),
|
|
3794
|
+
hour: kstDate.getUTCHours(),
|
|
3795
|
+
minute: kstDate.getUTCMinutes(),
|
|
3796
|
+
second: kstDate.getUTCSeconds()
|
|
3797
|
+
};
|
|
3798
|
+
}
|
|
3799
|
+
function pad2(value) {
|
|
3800
|
+
return String(value).padStart(2, "0");
|
|
3801
|
+
}
|
|
3802
|
+
function meridiem(hour) {
|
|
3803
|
+
return hour < 12 ? "오전" : "오후";
|
|
3804
|
+
}
|
|
3805
|
+
function hour12(hour) {
|
|
3806
|
+
const normalized = hour % 12;
|
|
3807
|
+
return normalized === 0 ? 12 : normalized;
|
|
3808
|
+
}
|
|
3809
|
+
/** Formats a date as Korean short date text in the opt-ui default timezone. */
|
|
3810
|
+
function formatOptShortDate(input) {
|
|
3811
|
+
const parts = getKstDateParts(input);
|
|
3812
|
+
if (!parts) return "-";
|
|
3813
|
+
return `${parts.month}월 ${parts.day}일`;
|
|
3814
|
+
}
|
|
3815
|
+
/** Formats a date as Korean clock time in the opt-ui default timezone. */
|
|
3816
|
+
function formatOptTime(input) {
|
|
3817
|
+
const parts = getKstDateParts(input);
|
|
3818
|
+
if (!parts) return "-";
|
|
3819
|
+
return `${meridiem(parts.hour)} ${pad2(hour12(parts.hour))}:${pad2(parts.minute)}`;
|
|
3820
|
+
}
|
|
3821
|
+
/** Formats a date as Korean date-time text in the opt-ui default timezone. */
|
|
3822
|
+
function formatOptDateTime(input) {
|
|
3823
|
+
const parts = getKstDateParts(input);
|
|
3824
|
+
if (!parts) return "-";
|
|
3825
|
+
return `${parts.year}. ${parts.month}. ${parts.day}. ${meridiem(parts.hour)} ${hour12(parts.hour)}:${pad2(parts.minute)}:${pad2(parts.second)}`;
|
|
3826
|
+
}
|
|
3827
|
+
/** Formats numbers without depending on the runtime default locale. */
|
|
3828
|
+
function formatOptNumber(value) {
|
|
3829
|
+
return new Intl.NumberFormat(OPT_UI_DEFAULT_LOCALE).format(value);
|
|
3830
|
+
}
|
|
3831
|
+
//#endregion
|
|
3513
3832
|
//#region src/core/checkbox.tsx
|
|
3514
3833
|
const _excluded$1 = [
|
|
3515
3834
|
"label",
|
|
@@ -4006,7 +4325,7 @@ const shapeStyles = {
|
|
|
4006
4325
|
* <FieldToken type={resolveFieldType(column.dataType)} title={column.name} />
|
|
4007
4326
|
* ```
|
|
4008
4327
|
*/
|
|
4009
|
-
function FieldToken({ type, size = "sm", fill = "subtle", shape = "square", title, decorative = false, className }) {
|
|
4328
|
+
function FieldToken({ type, size = "sm", fill = "subtle", shape = "square", title, decorative = false, withLabel = false, label: labelText, className }) {
|
|
4010
4329
|
var _FIELD_TYPE_TOKENS$ty;
|
|
4011
4330
|
const appearance = (_FIELD_TYPE_TOKENS$ty = FIELD_TYPE_TOKENS[type]) !== null && _FIELD_TYPE_TOKENS$ty !== void 0 ? _FIELD_TYPE_TOKENS$ty : FIELD_TYPE_TOKENS.unknown;
|
|
4012
4331
|
const Icon = appearance.icon;
|
|
@@ -4019,17 +4338,52 @@ function FieldToken({ type, size = "sm", fill = "subtle", shape = "square", titl
|
|
|
4019
4338
|
backgroundColor: `color-mix(in oklab, ${hue} 14%, transparent)`,
|
|
4020
4339
|
color: hue
|
|
4021
4340
|
} : { color: hue };
|
|
4022
|
-
|
|
4023
|
-
|
|
4341
|
+
const silent = decorative || withLabel;
|
|
4342
|
+
const glyph = /* @__PURE__ */ jsx("span", {
|
|
4343
|
+
className: cn("inline-flex shrink-0 items-center justify-center", sizeStyles[size], shapeStyles[shape], withLabel ? void 0 : className),
|
|
4024
4344
|
style,
|
|
4025
|
-
role:
|
|
4026
|
-
"aria-label":
|
|
4027
|
-
"aria-hidden":
|
|
4345
|
+
role: silent ? void 0 : "img",
|
|
4346
|
+
"aria-label": silent ? void 0 : label,
|
|
4347
|
+
"aria-hidden": silent ? true : void 0,
|
|
4028
4348
|
"data-opt-id": "V3AJ4",
|
|
4029
4349
|
"data-opt-slug": "field-token.FieldToken",
|
|
4030
4350
|
"data-field-type": type,
|
|
4031
4351
|
children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" })
|
|
4032
4352
|
});
|
|
4353
|
+
if (!withLabel) return glyph;
|
|
4354
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
4355
|
+
className: cn("inline-flex items-center gap-1.5 text-text-secondary", labelSize[size], className),
|
|
4356
|
+
"data-field-type": type,
|
|
4357
|
+
children: [glyph, /* @__PURE__ */ jsx("span", { children: labelText !== null && labelText !== void 0 ? labelText : appearance.name })]
|
|
4358
|
+
});
|
|
4359
|
+
}
|
|
4360
|
+
const labelSize = {
|
|
4361
|
+
xs: "text-[10px]",
|
|
4362
|
+
sm: "text-[11px]",
|
|
4363
|
+
md: "text-xs",
|
|
4364
|
+
lg: "text-sm"
|
|
4365
|
+
};
|
|
4366
|
+
/**
|
|
4367
|
+
* FieldTokenLegend — the glyph vocabulary, spelled out.
|
|
4368
|
+
*
|
|
4369
|
+
* The tokens are only worth their width if a reader can learn them, and the
|
|
4370
|
+
* cheapest place to learn them is next to the table that uses them. Rendered
|
|
4371
|
+
* from the same map the tokens read, so a legend cannot fall behind the set.
|
|
4372
|
+
*/
|
|
4373
|
+
function FieldTokenLegend({ types, size = "sm", labels, className }) {
|
|
4374
|
+
var _labels$heading;
|
|
4375
|
+
return /* @__PURE__ */ jsx("div", {
|
|
4376
|
+
className: cn("flex flex-wrap items-center gap-3", className),
|
|
4377
|
+
role: "group",
|
|
4378
|
+
"aria-label": (_labels$heading = labels === null || labels === void 0 ? void 0 : labels.heading) !== null && _labels$heading !== void 0 ? _labels$heading : "필드 타입",
|
|
4379
|
+
"data-opt-id": "FTLEG",
|
|
4380
|
+
"data-opt-slug": "field-token.FieldTokenLegend",
|
|
4381
|
+
children: types.map((type) => /* @__PURE__ */ jsx(FieldToken, {
|
|
4382
|
+
type,
|
|
4383
|
+
size,
|
|
4384
|
+
withLabel: true
|
|
4385
|
+
}, type))
|
|
4386
|
+
});
|
|
4033
4387
|
}
|
|
4034
4388
|
//#endregion
|
|
4035
4389
|
//#region src/core/highlight.tsx
|
|
@@ -4225,6 +4579,4 @@ function TextTruncate({ text, truncation = "startEnd", ellipsis = "…", width,
|
|
|
4225
4579
|
});
|
|
4226
4580
|
}
|
|
4227
4581
|
//#endregion
|
|
4228
|
-
export {
|
|
4229
|
-
|
|
4230
|
-
//# sourceMappingURL=text-truncate-j6X3z7Pv.js.map
|
|
4582
|
+
export { PopoverClose$1 as $, OPT_TEXT_LABEL as $n, CompositeProvider as $t, FormRadio$1 as A, OPT_BADGE_RED as An, DialogBody as At, FormSubmit$1 as B, OPT_FOCUS as Bn, SelectLabel$1 as Bt, FormGroupLabel$1 as C, getDescribedBy as Cn, ComboboxGroup$1 as Ct, FormNumberInput as D, OPT_BADGE_BLUE as Dn, ComboboxPopover$1 as Dt, FormLabel$1 as E, OPT_ANIMATE_ENTER_EXIT as En, ComboboxItem$1 as Et, FormSelect as F, OPT_DIVIDER as Fn, DialogHeader as Ft, useFormContext as G, OPT_ITEM_BASE as Gn, TabList$1 as Gt, FormTagInput as H, OPT_HOVER_ITEM as Hn, SelectRoot$1 as Ht, FormSelectItem as I, OPT_DOT_GRAY as In, DialogHeading$1 as It, DateRangePicker as J, OPT_SURFACE_RAISED as Jn, DisclosureContent$1 as Jt, useFormStore as K, OPT_SURFACE as Kn, TabPanel$1 as Kt, FormSelectPopover as L, OPT_DOT_GREEN as Ln, DialogPanel$1 as Lt, FormRemove$1 as M, OPT_BORDER as Mn, DialogDisclosure$1 as Mt, FormReset$1 as N, OPT_DISCLOSURE_CONTENT as Nn, DialogDismiss$1 as Nt, FormProvider$1 as O, OPT_BADGE_GREEN as On, ComboboxRoot$1 as Ot, FormRoot$1 as P, OPT_DISCLOSURE_TRIGGER as Pn, DialogFooter as Pt, ColorPicker as Q, OPT_TEXTAREA_SIZE as Qn, CompositeItem as Qt, FormSlider as R, OPT_DOT_RED as Rn, DialogRoot$1 as Rt, FormGroup$1 as S, RequiredMark as Sn, ComboboxEmpty as St, FormInput$1 as T, OPT_ANIMATE_DRAWER as Tn, ComboboxInput$1 as Tt, FormTextarea as U, OPT_INPUT as Un, SelectTrigger$1 as Ut, FormSwitch$1 as V, OPT_FOCUS_VISIBLE as Vn, SelectPopover$1 as Vt, useFieldValue as W, OPT_INPUT_ERROR as Wn, Tab$1 as Wt, IconPicker as X, OPT_TD as Xn, DisclosureTrigger$1 as Xt, TagInput as Y, OPT_TABLE_ROW_ACTIVE as Yn, DisclosureRoot$1 as Yt, getIconRegistryEntry as Z, OPT_TD_MUTED as Zn, Composite as Zt, FormControl$1 as _, SkeletonCard as _n, MenuRoot$1 as _t, FieldTokenLegend as a, useInputId as an, _objectWithoutProperties as ar, ToolbarButton$1 as at, FormError$1 as b, useControlledState as bn, MenubarContainer$1 as bt, Checkbox as c, Badge as cn, ToolbarSeparator$1 as ct, formatOptDateTime as d, koBreadcrumbLabels as dn, TooltipProvider$1 as dt, CompositeRow as en, OPT_TEXT_PRIMARY as er, PopoverContent$1 as et, formatOptNumber as f, koComboboxLabels as fn, MenuButtonArrow$1 as ft, FormColorPicker as g, SkeletonAvatar as gn, MenuPopover$1 as gt, FormCheckbox$1 as h, Skeleton as hn, MenuItemRadio$1 as ht, FieldToken as i, Input as in, _objectSpread2 as ir, NumberInput as it, FormRadioGroup$1 as j, OPT_BADGE_YELLOW as jn, DialogDescription$1 as jt, FormPush$1 as k, OPT_BADGE_NEUTRAL as kn, AlertDialogPanel$1 as kt, CheckboxGroup as l, EmptyState as ln, Tooltip$1 as lt, formatOptTime as m, StatCard as mn, MenuItemCheckbox$1 as mt, Highlight as n, Meter$1 as nn, OPT_TEXT_TERTIARY as nr, PopoverTrigger$1 as nt, resolveFieldType as o, Alert as on, Kbd as or, ToolbarContainer$1 as ot, formatOptShortDate as p, koStarRatingLabels as pn, MenuItem$1 as pt, DEFAULT_PRESETS as q, OPT_SURFACE_POPOVER as qn, TabsRoot$1 as qt, FIELD_TYPE_TOKENS as r, StarRating as rn, OPT_TH as rr, Slider as rt, Pagination as s, Spinner as sn, cn as sr, ToolbarRoot$1 as st, TextTruncate as t, CompositeZone as tn, OPT_TEXT_SECONDARY as tr, PopoverRoot$1 as tt, OPT_UI_DEFAULT_LOCALE as u, Button as un, TooltipAnchor$1 as ut, FormDateRangePicker as v, SkeletonTable as vn, MenuSeparator$1 as vt, FormIconPicker as w, OPT_ACTIVE_ITEM as wn, ComboboxGroupLabel$1 as wt, FormField$1 as x, FieldMessages as xn, MenubarRoot$1 as xt, FormDescription$1 as y, SkeletonText as yn, MenuTrigger$1 as yt, FormStarRating as z, OPT_DOT_YELLOW as zn, SelectItem$1 as zt };
|