@reopt-ai/opt-ui 1.11.0 → 1.12.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.
Files changed (74) hide show
  1. package/COMPONENT_CATALOG.md +495 -230
  2. package/README.md +43 -5
  3. package/dist/core/index.cjs +2 -2
  4. package/dist/core/index.d.cts +2 -2
  5. package/dist/core/index.d.ts +2 -2
  6. package/dist/core/index.js +2 -2
  7. package/dist/docs/02-components/01-core.md +154 -85
  8. package/dist/docs/02-components/02-visuals.md +1 -1
  9. package/dist/docs/02-components/03-shells.md +349 -149
  10. package/dist/docs/02-components/04-surfaces.md +1 -1
  11. package/dist/docs/02-components/index.md +5 -5
  12. package/dist/docs/03-recipes/02-dashboards.md +126 -10
  13. package/dist/{field-sidebar-B5SQC35J.d.cts → field-sidebar-CrYlRZew.d.ts} +164 -154
  14. package/dist/{field-sidebar-DAuN4jPV.cjs → field-sidebar-oa6zOmcd.cjs} +1540 -1537
  15. package/dist/{field-sidebar-CBeWE8xX.d.ts → field-sidebar-uXmoyvd7.d.cts} +164 -154
  16. package/dist/{field-sidebar-BXl5RJ3q.js → field-sidebar-zkkqC7__.js} +1541 -1540
  17. package/dist/id-registry.cjs +78 -6
  18. package/dist/id-registry.d.cts +1 -2
  19. package/dist/id-registry.d.ts +1 -2
  20. package/dist/id-registry.js +78 -8
  21. package/dist/id-registry.json +168 -19
  22. package/dist/index.cjs +1127 -224
  23. package/dist/index.d.cts +567 -58
  24. package/dist/index.d.ts +567 -58
  25. package/dist/index.js +1118 -227
  26. package/dist/{key-pad-menu-BxTy_u0Q.d.cts → key-pad-menu-CwcY_Vps.d.cts} +2 -3
  27. package/dist/{key-pad-menu-wXkWn1I1.js → key-pad-menu-Di2aRGbM.js} +4 -6
  28. package/dist/{key-pad-menu-Cg6rZBie.cjs → key-pad-menu-SItoHPLu.cjs} +1 -1
  29. package/dist/{key-pad-menu-u5GTJl9B.d.ts → key-pad-menu-WBJShCJn.d.ts} +3 -4
  30. package/dist/meta.cjs +894 -28
  31. package/dist/meta.d.cts +12 -36
  32. package/dist/meta.d.ts +12 -36
  33. package/dist/meta.js +894 -30
  34. package/dist/query.d.cts +1 -2
  35. package/dist/query.d.ts +1 -2
  36. package/dist/query.js +0 -2
  37. package/dist/shells/index.cjs +1 -1
  38. package/dist/shells/index.d.cts +1 -1
  39. package/dist/shells/index.d.ts +1 -1
  40. package/dist/shells/index.js +1 -1
  41. package/dist/tailwind.css +7 -0
  42. package/dist/{text-truncate-DW78lg4S.d.cts → text-truncate-CQyfUZvq.d.cts} +31 -3
  43. package/dist/{text-truncate-DW78lg4S.d.ts → text-truncate-CQyfUZvq.d.ts} +31 -3
  44. package/dist/{text-truncate-C17HHCR-.js → text-truncate-DSuZECy0.js} +43 -10
  45. package/dist/{text-truncate-BZdL1k5Z.cjs → text-truncate-I1XLWmRa.cjs} +48 -7
  46. package/dist/theme/server.d.cts +1 -2
  47. package/dist/theme/server.d.ts +1 -2
  48. package/dist/theme/server.js +0 -2
  49. package/dist/visuals/index.js +0 -1
  50. package/package.json +4 -3
  51. package/dist/field-sidebar-B5SQC35J.d.cts.map +0 -1
  52. package/dist/field-sidebar-BXl5RJ3q.js.map +0 -1
  53. package/dist/field-sidebar-CBeWE8xX.d.ts.map +0 -1
  54. package/dist/id-registry.d.cts.map +0 -1
  55. package/dist/id-registry.d.ts.map +0 -1
  56. package/dist/id-registry.js.map +0 -1
  57. package/dist/index.d.cts.map +0 -1
  58. package/dist/index.d.ts.map +0 -1
  59. package/dist/index.js.map +0 -1
  60. package/dist/key-pad-menu-BxTy_u0Q.d.cts.map +0 -1
  61. package/dist/key-pad-menu-u5GTJl9B.d.ts.map +0 -1
  62. package/dist/key-pad-menu-wXkWn1I1.js.map +0 -1
  63. package/dist/meta.d.cts.map +0 -1
  64. package/dist/meta.d.ts.map +0 -1
  65. package/dist/meta.js.map +0 -1
  66. package/dist/query.d.cts.map +0 -1
  67. package/dist/query.d.ts.map +0 -1
  68. package/dist/query.js.map +0 -1
  69. package/dist/text-truncate-C17HHCR-.js.map +0 -1
  70. package/dist/text-truncate-DW78lg4S.d.cts.map +0 -1
  71. package/dist/text-truncate-DW78lg4S.d.ts.map +0 -1
  72. package/dist/theme/server.d.cts.map +0 -1
  73. package/dist/theme/server.d.ts.map +0 -1
  74. package/dist/theme/server.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,16 +1,355 @@
1
1
  "use client";
2
- import { $ as PopoverContent, $n as OPT_TEXT_PRIMARY, $t as CompositeRow, A as FormRadioGroup, An as OPT_BADGE_YELLOW, At as DialogDescription, B as FormSwitch, Bn as OPT_FOCUS_VISIBLE, Bt as SelectPopover, C as FormIconPicker, Ct as ComboboxGroupLabel, D as FormProvider, Dn as OPT_BADGE_GREEN, Dt as ComboboxRoot, E as FormNumberInput, En as OPT_BADGE_BLUE, Et as ComboboxPopover, F as FormSelectItem, Fn as OPT_DOT_GRAY, Ft as DialogHeading, G as useFormStore, Gt as TabPanel, H as FormTextarea, Hn as OPT_INPUT, Ht as SelectTrigger, I as FormSelectPopover, In as OPT_DOT_GREEN, It as DialogPanel, J as TagInput, Jt as DisclosureRoot, K as DEFAULT_PRESETS, Kt as TabsRoot, L as FormSlider, Ln as OPT_DOT_RED, Lt as DialogRoot, M as FormReset, Mt as DialogDismiss, N as FormRoot, Nt as DialogFooter, O as FormPush, On as OPT_BADGE_NEUTRAL, Ot as AlertDialogPanel, P as FormSelect, Pt as DialogHeader, Q as PopoverClose, Qt as CompositeProvider, R as FormStarRating, Rn as OPT_DOT_YELLOW, Rt as SelectItem, S as FormGroupLabel, St as ComboboxGroup, T as FormLabel, Tt as ComboboxItem, U as useFieldValue, Ut as Tab, V as FormTagInput, Vn as OPT_HOVER_ITEM, Vt as SelectRoot, W as useFormContext, Wt as TabList, X as getIconRegistryEntry, Xt as Composite, Y as IconPicker, Yn as OPT_TD, Yt as DisclosureTrigger, Z as ColorPicker, Zt as CompositeItem, _ as FormDateRangePicker, _n as SkeletonTable, _t as MenuSeparator, a as resolveFieldType, an as Alert, ar as Kbd, at as ToolbarContainer, b as FormField, bt as MenubarRoot, c as CheckboxGroup, cn as EmptyState, ct as Tooltip, d as formatOptNumber, dn as koComboboxLabels, dt as MenuButtonArrow, en as CompositeZone, er as OPT_TEXT_SECONDARY, et as PopoverRoot, f as formatOptShortDate, fn as koStarRatingLabels, ft as MenuItem, g as FormControl, gn as SkeletonCard, gt as MenuRoot, h as FormColorPicker, hn as SkeletonAvatar, ht as MenuPopover, i as FieldToken, in as useInputId, it as ToolbarButton, j as FormRemove, jn as OPT_BORDER, jt as DialogDisclosure, k as FormRadio, kn as OPT_BADGE_RED, kt as DialogBody, ln as Button, lt as TooltipAnchor, m as FormCheckbox, mn as Skeleton, mt as MenuItemRadio, n as Highlight, nn as StarRating, nr as OPT_TH, nt as Slider, o as Pagination, on as Spinner, or as cn, ot as ToolbarRoot, p as formatOptTime, pn as StatCard, pt as MenuItemCheckbox, q as DateRangePicker, qt as DisclosureContent, r as FIELD_TYPE_TOKENS, rn as Input, rr as _objectSpread2, rt as NumberInput, s as Checkbox, sn as Badge, st as ToolbarSeparator, t as TextTruncate, tn as Meter, tr as OPT_TEXT_TERTIARY, tt as PopoverTrigger, u as formatOptDateTime, un as koBreadcrumbLabels, ut as TooltipProvider, v as FormDescription, vn as SkeletonText, vt as MenuTrigger, w as FormInput, wt as ComboboxInput, x as FormGroup, xt as ComboboxEmpty, y as FormError, yn as useControlledState, yt as MenubarContainer, z as FormSubmit, zn as OPT_FOCUS, zt as SelectLabel } from "./text-truncate-C17HHCR-.js";
3
- import { $ as Identity, A as PageHeader, B as DropdownTrigger, C as Logo, D as Section, E as ResizablePanelGroup, F as RadioGroup, G as Textarea, H as StepBuilder, I as DropdownContent, J as CardContent, K as Switch, L as DropdownItem, M as BlockLayout, N as LoadingOverlay, O as Container, P as Radio, Q as CardTitle, R as DropdownMenu, S as DrawerRoot, T as ResizablePanel, U as CircularProgress, V as ConditionBuilder, W as Progress, X as CardFooter, Y as CardDescription, Z as CardHeader, _ as getShaderFragment, a as THEME_PALETTES, at as AccordionItem, b as DrawerClose, c as ExpressionGroup, ct as Toggle, d as ShaderSurface, dt as Separator, et as Avatar, f as SHADER_OVERLAY_PARAM_KEYS, ft as Heading, g as SHADER_PRESET_IDS, h as SHADER_PRESETS, i as ColorPalettePicker, it as AccordionContent, j as createBlock, k as ScrollArea, l as Facet, lt as ToggleGroup, m as SHADER_PARAM_KEYS, n as InlineEdit, nt as DescriptionList, o as LiveRegion, ot as AccordionRoot, p as SHADER_PARAM_FALLBACK, pt as Text, q as Card, r as ColorPaletteDisplay, rt as Breadcrumb, s as Expression, st as AccordionTrigger, t as KeyPadMenu, tt as AvatarGroup, u as FacetGroup, ut as OtpField, v as getShaderPreset, w as ResizableHandle, x as DrawerPanel, y as VirtualList, z as DropdownSeparator } from "./key-pad-menu-wXkWn1I1.js";
4
- import { $ as CommandGroup, A as ToastProvider, B as FaqAccordion, C as Flyout, D as KeyValueEditor, E as WorkflowCanvas, F as BranchSelect, G as StatusSelect, H as EditorToolbar, I as EnvPanel, J as CommandPaletteTrigger, K as SearchCombobox, L as ProjectSwitcher, M as useToast, N as DataTable, O as FailureList, P as DomainTable, Q as CommandEmpty, R as DeploymentTimeline, S as useAutoRefresh, T as EventTimeline, U as SidebarNav, V as ContentTabs, W as AppMenubar, X as Command, Y as CommandPalette, Z as CommandDialog, _ as withoutField, a as formatQuery, b as DEFAULT_TIME_PRESETS, c as parseQueryWithDiagnostics, d as applyCellAction, et as CommandInput, f as fieldValues, g as withFieldValue, h as removeClause, i as formatClause, it as CommandShortcut, j as toast, k as NotificationToast, l as EMPTY_QUERY, m as queryFields, n as QueryBar, nt as CommandList, o as quoteValue, p as isEmptyQuery, q as DashboardGrid, r as describeClause, rt as CommandSeparator, s as parseQuery, t as FieldSidebar, tt as CommandItem, u as addClause, v as LogTable, w as ScoreBreakdown, x as TimeRangeControl, y as TimeSeriesPanel, z as SettingsForm } from "./field-sidebar-BXl5RJ3q.js";
2
+ import { $ as PopoverClose, $t as CompositeProvider, A as FormRadio, An as OPT_BADGE_RED, At as DialogBody, B as FormSubmit, Bn as OPT_FOCUS, Bt as SelectLabel, C as FormGroupLabel, Ct as ComboboxGroup, D as FormNumberInput, Dn as OPT_BADGE_BLUE, Dt as ComboboxPopover, E as FormLabel, Et as ComboboxItem, F as FormSelect, Ft as DialogHeader, G as useFormContext, Gt as TabList, H as FormTagInput, Hn as OPT_HOVER_ITEM, Ht as SelectRoot, I as FormSelectItem, In as OPT_DOT_GRAY, It as DialogHeading, J as DateRangePicker, Jt as DisclosureContent, K as useFormStore, Kt as TabPanel, L as FormSelectPopover, Ln as OPT_DOT_GREEN, Lt as DialogPanel, M as FormRemove, Mn as OPT_BORDER, Mt as DialogDisclosure, N as FormReset, Nt as DialogDismiss, O as FormProvider, On as OPT_BADGE_GREEN, Ot as ComboboxRoot, P as FormRoot, Pt as DialogFooter, Q as ColorPicker, Qt as CompositeItem, R as FormSlider, Rn as OPT_DOT_RED, Rt as DialogRoot, S as FormGroup, St as ComboboxEmpty, T as FormInput, Tt as ComboboxInput, U as FormTextarea, Un as OPT_INPUT, Ut as SelectTrigger, V as FormSwitch, Vn as OPT_FOCUS_VISIBLE, Vt as SelectPopover, W as useFieldValue, Wt as Tab, X as IconPicker, Xn as OPT_TD, Xt as DisclosureTrigger, Y as TagInput, Yt as DisclosureRoot, Z as getIconRegistryEntry, Zt as Composite, _ as FormControl, _n as SkeletonCard, _t as MenuRoot, a as FieldTokenLegend, an as useInputId, ar as _objectWithoutProperties, at as ToolbarButton, b as FormError, bn as useControlledState, bt as MenubarContainer, c as Checkbox, cn as Badge, ct as ToolbarSeparator, d as formatOptDateTime, dn as koBreadcrumbLabels, dt as TooltipProvider, en as CompositeRow, er as OPT_TEXT_PRIMARY, et as PopoverContent, f as formatOptNumber, fn as koComboboxLabels, ft as MenuButtonArrow, g as FormColorPicker, gn as SkeletonAvatar, gt as MenuPopover, h as FormCheckbox, hn as Skeleton, ht as MenuItemRadio, i as FieldToken, in as Input, ir as _objectSpread2, it as NumberInput, j as FormRadioGroup, jn as OPT_BADGE_YELLOW, jt as DialogDescription, k as FormPush, kn as OPT_BADGE_NEUTRAL, kt as AlertDialogPanel, l as CheckboxGroup, ln as EmptyState, lt as Tooltip, m as formatOptTime, mn as StatCard, mt as MenuItemCheckbox, n as Highlight, nn as Meter, nr as OPT_TEXT_TERTIARY, nt as PopoverTrigger, o as resolveFieldType, on as Alert, or as Kbd, ot as ToolbarContainer, p as formatOptShortDate, pn as koStarRatingLabels, pt as MenuItem, q as DEFAULT_PRESETS, qt as TabsRoot, r as FIELD_TYPE_TOKENS, rn as StarRating, rr as OPT_TH, rt as Slider, s as Pagination, sn as Spinner, sr as cn, st as ToolbarRoot, t as TextTruncate, tn as CompositeZone, tr as OPT_TEXT_SECONDARY, tt as PopoverRoot, un as Button, ut as TooltipAnchor, v as FormDateRangePicker, vn as SkeletonTable, vt as MenuSeparator, w as FormIconPicker, wt as ComboboxGroupLabel, x as FormField, xt as MenubarRoot, y as FormDescription, yn as SkeletonText, yt as MenuTrigger, z as FormStarRating, zn as OPT_DOT_YELLOW, zt as SelectItem } from "./text-truncate-DSuZECy0.js";
3
+ import { $ as Identity, A as PageHeader, B as DropdownTrigger, C as Logo, D as Section, E as ResizablePanelGroup, F as RadioGroup, G as Textarea, H as StepBuilder, I as DropdownContent, J as CardContent, K as Switch, L as DropdownItem, M as BlockLayout, N as LoadingOverlay, O as Container, P as Radio, Q as CardTitle, R as DropdownMenu, S as DrawerRoot, T as ResizablePanel, U as CircularProgress, V as ConditionBuilder, W as Progress, X as CardFooter, Y as CardDescription, Z as CardHeader, _ as getShaderFragment, a as THEME_PALETTES, at as AccordionItem, b as DrawerClose, c as ExpressionGroup, ct as Toggle, d as ShaderSurface, dt as Separator, et as Avatar, f as SHADER_OVERLAY_PARAM_KEYS, ft as Heading, g as SHADER_PRESET_IDS, h as SHADER_PRESETS, i as ColorPalettePicker, it as AccordionContent, j as createBlock, k as ScrollArea, l as Facet, lt as ToggleGroup, m as SHADER_PARAM_KEYS, n as InlineEdit, nt as DescriptionList, o as LiveRegion, ot as AccordionRoot, p as SHADER_PARAM_FALLBACK, pt as Text, q as Card, r as ColorPaletteDisplay, rt as Breadcrumb, s as Expression, st as AccordionTrigger, t as KeyPadMenu, tt as AvatarGroup, u as FacetGroup, ut as OtpField, v as getShaderPreset, w as ResizableHandle, x as DrawerPanel, y as VirtualList, z as DropdownSeparator } from "./key-pad-menu-Di2aRGbM.js";
4
+ import { $ as CommandGroup, A as ToastProvider, B as FaqAccordion, C as Flyout, D as KeyValueEditor, E as WorkflowCanvas, F as BranchSelect, G as StatusSelect, H as EditorToolbar, I as EnvPanel, J as CommandPaletteTrigger, K as SearchCombobox, L as ProjectSwitcher, M as useToast, N as DataTable, O as FailureList, P as DomainTable, Q as CommandEmpty, R as DeploymentTimeline, S as withoutField, T as EventTimeline, U as SidebarNav, V as ContentTabs, W as AppMenubar, X as Command, Y as CommandPalette, Z as CommandDialog, _ as fieldValues, a as TimeRangeControl, b as removeClause, c as describeClause, d as quoteValue, et as CommandInput, f as parseQuery, g as applyCellAction, h as addClause, i as DEFAULT_TIME_PRESETS, it as CommandShortcut, j as toast, k as NotificationToast, l as formatClause, m as EMPTY_QUERY, n as LogTable, nt as CommandList, o as useAutoRefresh, p as parseQueryWithDiagnostics, q as DashboardGrid, r as TimeSeriesPanel, rt as CommandSeparator, s as QueryBar, t as FieldSidebar, tt as CommandItem, u as formatQuery, v as isEmptyQuery, w as ScoreBreakdown, x as withFieldValue, y as queryFields, z as SettingsForm } from "./field-sidebar-zkkqC7__.js";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import * as React from "react";
7
7
  import { Component, createContext, useCallback, useContext, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
8
- import { CircleCheck, FilePen, GitMerge, MessageSquare, Rocket, Search, Sparkles, Trash2, User } from "lucide-react";
8
+ import { Radio as Radio$1, RadioGroupRoot } from "@reopt-ai/opt-ui-primitives";
9
+ import { Check, ChevronDown, CircleAlert, CircleCheck, Copy, FilePen, GitMerge, Info, MessageSquare, MoreHorizontal, Pencil, Rocket, Search, Sparkles, Trash2, TriangleAlert, User, X } from "lucide-react";
9
10
  import { generatePalette } from "@reopt-ai/opt-palette";
10
11
  import { EventSparkline, MetricsCard, ReportWidget, TrendChart } from "@reopt-ai/opt-charts";
11
12
  import { matchSorter } from "match-sorter";
12
13
  import { usePathname } from "next/navigation";
13
14
  export * from "@reopt-ai/opt-charts";
15
+ //#region src/core/callout.tsx
16
+ const _excluded$2 = [
17
+ "tone",
18
+ "title",
19
+ "icon",
20
+ "action",
21
+ "size",
22
+ "className",
23
+ "children"
24
+ ];
25
+ const toneStyles = {
26
+ info: "border-info/40 bg-info-subtle",
27
+ success: "border-success/40 bg-success-subtle",
28
+ warning: "border-warning/40 bg-warning-subtle",
29
+ danger: "border-danger/40 bg-danger-subtle",
30
+ neutral: "border-border bg-bg-subtle"
31
+ };
32
+ const iconTone = {
33
+ info: "text-info-fg",
34
+ success: "text-success-fg",
35
+ warning: "text-warning-fg",
36
+ danger: "text-danger-fg",
37
+ neutral: "text-text-tertiary"
38
+ };
39
+ const titleTone = {
40
+ info: "text-info-fg",
41
+ success: "text-success-fg",
42
+ warning: "text-warning-fg",
43
+ danger: "text-danger-fg",
44
+ neutral: "text-text-primary"
45
+ };
46
+ const defaultIcons = {
47
+ info: Info,
48
+ success: CircleCheck,
49
+ warning: TriangleAlert,
50
+ danger: CircleAlert,
51
+ neutral: null
52
+ };
53
+ const sizeStyles$3 = {
54
+ sm: "gap-2 p-2.5 text-xs [&_svg]:size-3.5",
55
+ md: "gap-3 p-3 text-sm [&_svg]:size-4"
56
+ };
57
+ /**
58
+ * Callout — a notice that belongs to the page, not to the moment.
59
+ *
60
+ * `Alert` reports something that just happened and can be dismissed once read.
61
+ * A callout is the opposite: it is part of the layout, it is true for as long
62
+ * as the condition holds, and dismissing it would only hide a fact that is
63
+ * still true. "12 new events to triage" above a list, or "these numbers come
64
+ * from a 10,000-row sample" above a chart — both are read many times and
65
+ * dismissed never.
66
+ *
67
+ * That is why there is no `onDismiss` here, and why `action` takes one control:
68
+ * a notice earns its space by naming the single thing to do about it.
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * <Callout tone="info" title="정리할 신규 이벤트 12개"
73
+ * action={<Button size="sm" onClick={showNew}>보기</Button>}>
74
+ * 7일 안에 처음 관측된 이벤트입니다.
75
+ * </Callout>
76
+ * ```
77
+ */
78
+ function Callout(_ref) {
79
+ let { tone = "info", title, icon, action, size = "md", className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$2);
80
+ const DefaultIcon = defaultIcons[tone];
81
+ const glyph = icon === void 0 ? DefaultIcon ? /* @__PURE__ */ jsx(DefaultIcon, { "aria-hidden": "true" }) : null : icon;
82
+ return /* @__PURE__ */ jsxs("div", _objectSpread2(_objectSpread2({ className: cn("flex items-start rounded-lg border", toneStyles[tone], sizeStyles$3[size], className) }, props), {}, {
83
+ "data-opt-id": "AT7TX",
84
+ "data-opt-slug": "callout.Callout",
85
+ "data-tone": tone,
86
+ children: [
87
+ glyph && /* @__PURE__ */ jsx("span", {
88
+ className: cn("mt-0.5 shrink-0", iconTone[tone]),
89
+ children: glyph
90
+ }),
91
+ /* @__PURE__ */ jsxs("div", {
92
+ className: "min-w-0 flex-1",
93
+ children: [title && /* @__PURE__ */ jsx("p", {
94
+ className: cn("font-medium", titleTone[tone]),
95
+ children: title
96
+ }), children && /* @__PURE__ */ jsx("div", {
97
+ className: cn("text-text-secondary", title && "mt-1"),
98
+ children
99
+ })]
100
+ }),
101
+ action && /* @__PURE__ */ jsx("div", {
102
+ className: "shrink-0 self-center",
103
+ children: action
104
+ })
105
+ ]
106
+ }));
107
+ }
108
+ //#endregion
109
+ //#region src/core/status-dot.tsx
110
+ const _excluded$1 = [
111
+ "tone",
112
+ "size",
113
+ "hint",
114
+ "className",
115
+ "children"
116
+ ];
117
+ const dotTone = {
118
+ neutral: "bg-text-tertiary",
119
+ muted: "bg-border-hover",
120
+ info: "bg-info",
121
+ success: "bg-success",
122
+ warning: "bg-warning",
123
+ danger: "bg-danger"
124
+ };
125
+ const textTone = {
126
+ neutral: "text-text-secondary",
127
+ muted: "text-text-tertiary",
128
+ info: "text-text-secondary",
129
+ success: "text-text-secondary",
130
+ warning: "text-text-secondary",
131
+ danger: "text-text-secondary"
132
+ };
133
+ const sizeStyles$2 = {
134
+ sm: "gap-1.5 text-[11px]",
135
+ md: "gap-2 text-xs"
136
+ };
137
+ const dotSize = {
138
+ sm: "size-1.5",
139
+ md: "size-2"
140
+ };
141
+ /**
142
+ * StatusDot — a state, said in a dot and a word.
143
+ *
144
+ * `Badge` is a chip: a filled pill that reads as a label somebody attached.
145
+ * A status is not attached, it is observed, and a column of seven filled pills
146
+ * is a column nobody scans. This is the other shape — a dot, the word, no
147
+ * chrome — which is what a dense table can afford to repeat on every row.
148
+ *
149
+ * The dot is decorative on purpose. It never carries meaning the text does not
150
+ * also carry, so the component cannot be used to say something in colour alone.
151
+ *
152
+ * @example
153
+ * ```tsx
154
+ * <StatusDot tone="warning" hint="7일 이상 수신되지 않음">비활성</StatusDot>
155
+ * ```
156
+ */
157
+ function StatusDot(_ref) {
158
+ let { tone = "neutral", size = "md", hint, className, children } = _ref, props = _objectWithoutProperties(_ref, _excluded$1);
159
+ return /* @__PURE__ */ jsxs("span", _objectSpread2(_objectSpread2({
160
+ className: cn("inline-flex items-center whitespace-nowrap", sizeStyles$2[size], textTone[tone], className),
161
+ title: hint
162
+ }, props), {}, {
163
+ "data-opt-id": "N51AT",
164
+ "data-opt-slug": "status-dot.StatusDot",
165
+ "data-tone": tone,
166
+ children: [/* @__PURE__ */ jsx("span", {
167
+ className: cn("shrink-0 rounded-full", dotSize[size], dotTone[tone]),
168
+ "aria-hidden": "true"
169
+ }), children]
170
+ }));
171
+ }
172
+ //#endregion
173
+ //#region src/core/copy-button.tsx
174
+ const _excluded = [
175
+ "value",
176
+ "variant",
177
+ "size",
178
+ "feedbackDuration",
179
+ "onCopy",
180
+ "labels",
181
+ "className",
182
+ "disabled",
183
+ "onClick"
184
+ ];
185
+ const defaultLabels$35 = {
186
+ copy: "복사",
187
+ copied: "복사됨",
188
+ failed: "복사할 수 없습니다"
189
+ };
190
+ const sizeStyles$1 = {
191
+ sm: "h-6 gap-1 text-[11px] [&>svg]:size-3",
192
+ md: "h-7 gap-1.5 text-xs [&>svg]:size-3.5"
193
+ };
194
+ const paddingStyles = {
195
+ icon: {
196
+ sm: "w-6 justify-center",
197
+ md: "w-7 justify-center"
198
+ },
199
+ text: {
200
+ sm: "px-1.5",
201
+ md: "px-2"
202
+ }
203
+ };
204
+ const stateIcon = {
205
+ idle: Copy,
206
+ copied: Check,
207
+ failed: X
208
+ };
209
+ const stateTone = {
210
+ idle: "text-text-tertiary hover:text-text-primary",
211
+ copied: "text-success-fg",
212
+ failed: "text-danger-fg"
213
+ };
214
+ /**
215
+ * CopyButton — put a value on the clipboard, and say whether it went.
216
+ *
217
+ * Copying an identifier is the most common thing a reader does with one: an
218
+ * event key, a property name, a request id. Every surface that shows one was
219
+ * writing this button again, and each copy re-decided what happens when the
220
+ * clipboard refuses — mostly by pretending it did not.
221
+ *
222
+ * The confirmed state is announced, not just drawn, so the answer reaches a
223
+ * reader who is not looking at the glyph.
224
+ *
225
+ * @example
226
+ * ```tsx
227
+ * <CopyButton value={event.name} labels={{ copy: "이벤트 키 복사" }} />
228
+ * ```
229
+ */
230
+ function CopyButton(_ref) {
231
+ let { value, variant = "icon", size = "md", feedbackDuration = 1500, onCopy, labels: customLabels, className, disabled, onClick } = _ref, props = _objectWithoutProperties(_ref, _excluded);
232
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$35), customLabels);
233
+ const [state, setState] = useState("idle");
234
+ const timer = useRef(null);
235
+ useEffect(() => () => {
236
+ if (timer.current) clearTimeout(timer.current);
237
+ }, []);
238
+ const handleClick = useCallback(async (event) => {
239
+ onClick === null || onClick === void 0 || onClick(event);
240
+ if (event.defaultPrevented) return;
241
+ let ok = false;
242
+ try {
243
+ await navigator.clipboard.writeText(value);
244
+ ok = true;
245
+ } catch (_unused) {
246
+ ok = false;
247
+ }
248
+ setState(ok ? "copied" : "failed");
249
+ onCopy === null || onCopy === void 0 || onCopy(ok);
250
+ if (timer.current) clearTimeout(timer.current);
251
+ timer.current = setTimeout(() => setState("idle"), feedbackDuration);
252
+ }, [
253
+ feedbackDuration,
254
+ onClick,
255
+ onCopy,
256
+ value
257
+ ]);
258
+ const Icon = stateIcon[state];
259
+ const label = state === "copied" ? labels.copied : state === "failed" ? labels.failed : labels.copy;
260
+ return /* @__PURE__ */ jsxs("button", _objectSpread2(_objectSpread2({
261
+ type: "button",
262
+ onClick: handleClick,
263
+ disabled,
264
+ "aria-label": variant === "icon" ? label : void 0,
265
+ className: cn("inline-flex shrink-0 items-center rounded transition-colors", "disabled:pointer-events-none disabled:opacity-50", OPT_FOCUS_VISIBLE, sizeStyles$1[size], paddingStyles[variant][size], stateTone[state], className)
266
+ }, props), {}, {
267
+ "data-opt-id": "E0C8T",
268
+ "data-opt-slug": "copy-button.CopyButton",
269
+ "data-copy-state": state,
270
+ children: [
271
+ /* @__PURE__ */ jsx(Icon, { "aria-hidden": "true" }),
272
+ variant === "text" && /* @__PURE__ */ jsx("span", { children: label }),
273
+ /* @__PURE__ */ jsx("span", {
274
+ role: "status",
275
+ "aria-live": "polite",
276
+ className: "sr-only",
277
+ children: state === "idle" ? "" : label
278
+ })
279
+ ]
280
+ }));
281
+ }
282
+ //#endregion
283
+ //#region src/core/segmented-control.tsx
284
+ const sizeStyles = {
285
+ sm: "h-7 text-[11px] [&_svg]:size-3",
286
+ md: "h-8 text-xs [&_svg]:size-3.5"
287
+ };
288
+ const segmentPadding = {
289
+ sm: "gap-1 px-2",
290
+ md: "gap-1.5 px-2.5"
291
+ };
292
+ /**
293
+ * SegmentedControl — one of a few views, all of them visible.
294
+ *
295
+ * A `Select` hides the alternatives behind a click; a `ToggleGroup` presses
296
+ * buttons that may be on together. Neither is what "이벤트 | 속성" is: exactly
297
+ * one is true, the set is small enough to show, and the reader is choosing a
298
+ * view rather than filtering anything.
299
+ *
300
+ * Built on the radio-group primitive rather than on buttons, so the arrow keys,
301
+ * the group name and the checked state come from the platform. A control that
302
+ * merely looks like a radiogroup is one a keyboard cannot drive.
303
+ *
304
+ * @example
305
+ * ```tsx
306
+ * <SegmentedControl
307
+ * aria-label="카탈로그 탭"
308
+ * options={[
309
+ * { value: "events", label: "이벤트", badge: 128 },
310
+ * { value: "properties", label: "속성", badge: 341 },
311
+ * ]}
312
+ * value={tab}
313
+ * onChange={setTab}
314
+ * />
315
+ * ```
316
+ */
317
+ function SegmentedControl({ options, value, onChange, size = "md", fullWidth = false, disabled = false, "aria-label": ariaLabel, className }) {
318
+ const name = useId();
319
+ return /* @__PURE__ */ jsx(RadioGroupRoot, {
320
+ value,
321
+ onValueChange: (next) => onChange(next),
322
+ disabled,
323
+ orientation: "horizontal",
324
+ name,
325
+ "aria-label": ariaLabel,
326
+ className: cn("inline-flex items-center rounded-lg border border-border bg-bg-subtle p-0.5", fullWidth && "flex w-full", sizeStyles[size], className),
327
+ "data-opt-id": "YKENE",
328
+ "data-opt-slug": "segmented-control.SegmentedControl",
329
+ children: options.map((option) => {
330
+ const selected = option.value === value;
331
+ const itemDisabled = disabled || option.disabled;
332
+ return /* @__PURE__ */ jsxs("label", {
333
+ className: cn("relative inline-flex h-full cursor-pointer items-center justify-center", "rounded-md font-medium whitespace-nowrap transition-colors", "has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-ring has-[:focus-visible]:ring-offset-1 has-[:focus-visible]:ring-offset-ring-offset", segmentPadding[size], fullWidth && "flex-1", selected ? "bg-surface text-text-primary shadow-sm" : "text-text-tertiary hover:text-text-secondary", itemDisabled && "pointer-events-none opacity-50"),
334
+ "data-selected": selected || void 0,
335
+ children: [
336
+ /* @__PURE__ */ jsx(Radio$1, {
337
+ value: option.value,
338
+ disabled: itemDisabled,
339
+ className: "sr-only"
340
+ }),
341
+ option.icon,
342
+ /* @__PURE__ */ jsx("span", { children: option.label }),
343
+ option.badge != null && /* @__PURE__ */ jsx("span", {
344
+ className: cn("tabular-nums", selected ? "text-text-tertiary" : "text-text-tertiary/70"),
345
+ children: option.badge
346
+ })
347
+ ]
348
+ }, option.value);
349
+ })
350
+ });
351
+ }
352
+ //#endregion
14
353
  //#region src/lib/schema-validator.ts
15
354
  /** Handles schema validator. */
16
355
  function schemaValidator(schema) {
@@ -85,7 +424,7 @@ function PageAside({ header, children, footer, widthClassName = "w-60", label, h
85
424
  PageAside.displayName = "PageAside";
86
425
  //#endregion
87
426
  //#region src/shells/task-list.tsx
88
- const defaultLabels$31 = {
427
+ const defaultLabels$34 = {
89
428
  title: "작업 목록",
90
429
  emptyMessage: "작업이 없습니다",
91
430
  completedOf: "{completed}/{total} 완료",
@@ -105,9 +444,9 @@ const defaultLabels$31 = {
105
444
  };
106
445
  /** Renders the task list component. */
107
446
  function TaskList({ tasks, title, onTaskClick, onTaskStatusChange, emptyMessage, showSubtasks = false, maxItems, labels: customLabels, className }) {
108
- const labels = _objectSpread2(_objectSpread2(_objectSpread2({}, defaultLabels$31), customLabels), {}, {
109
- priority: _objectSpread2(_objectSpread2({}, defaultLabels$31.priority), customLabels === null || customLabels === void 0 ? void 0 : customLabels.priority),
110
- status: _objectSpread2(_objectSpread2({}, defaultLabels$31.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status)
447
+ const labels = _objectSpread2(_objectSpread2(_objectSpread2({}, defaultLabels$34), customLabels), {}, {
448
+ priority: _objectSpread2(_objectSpread2({}, defaultLabels$34.priority), customLabels === null || customLabels === void 0 ? void 0 : customLabels.priority),
449
+ status: _objectSpread2(_objectSpread2({}, defaultLabels$34.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status)
111
450
  });
112
451
  const displayTitle = title !== null && title !== void 0 ? title : labels.title;
113
452
  const displayEmptyMessage = emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : labels.emptyMessage;
@@ -265,7 +604,7 @@ function TaskList({ tasks, title, onTaskClick, onTaskStatusChange, emptyMessage,
265
604
  }
266
605
  //#endregion
267
606
  //#region src/shells/activity-feed.tsx
268
- const defaultLabels$30 = {
607
+ const defaultLabels$33 = {
269
608
  title: "활동 피드",
270
609
  emptyMessage: "활동이 없습니다",
271
610
  moreItems: "{count}개 더 보기",
@@ -315,24 +654,24 @@ const variantBorder = {
315
654
  function ActivityFeed({ activities, title, maxItems, onActivityClick, onShowMore, emptyMessage, labels: customLabels, locale = "ko-KR", loading = false, layout = "list", renderActions, className }) {
316
655
  var _customLabels$timeAgo, _customLabels$timeAgo2, _customLabels$timeAgo3, _customLabels$timeAgo4, _customLabels$timeAgo5, _customLabels$timeAgo6, _customLabels$timeAgo7, _customLabels$timeAgo8, _customLabels$activit, _customLabels$activit2, _customLabels$activit3, _customLabels$activit4, _customLabels$activit5, _customLabels$activit6, _customLabels$activit7, _customLabels$activit8, _customLabels$activit9, _customLabels$activit10, _customLabels$activit11, _customLabels$activit12, _customLabels$activit13, _customLabels$activit14, _customLabels$title, _customLabels$emptyMe, _customLabels$moreIte;
317
656
  const mergedTimeAgo = {
318
- justNow: (_customLabels$timeAgo = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo2 = customLabels.timeAgo) === null || _customLabels$timeAgo2 === void 0 ? void 0 : _customLabels$timeAgo2.justNow) !== null && _customLabels$timeAgo !== void 0 ? _customLabels$timeAgo : defaultLabels$30.timeAgo.justNow,
319
- minutesAgo: (_customLabels$timeAgo3 = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo4 = customLabels.timeAgo) === null || _customLabels$timeAgo4 === void 0 ? void 0 : _customLabels$timeAgo4.minutesAgo) !== null && _customLabels$timeAgo3 !== void 0 ? _customLabels$timeAgo3 : defaultLabels$30.timeAgo.minutesAgo,
320
- hoursAgo: (_customLabels$timeAgo5 = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo6 = customLabels.timeAgo) === null || _customLabels$timeAgo6 === void 0 ? void 0 : _customLabels$timeAgo6.hoursAgo) !== null && _customLabels$timeAgo5 !== void 0 ? _customLabels$timeAgo5 : defaultLabels$30.timeAgo.hoursAgo,
321
- daysAgo: (_customLabels$timeAgo7 = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo8 = customLabels.timeAgo) === null || _customLabels$timeAgo8 === void 0 ? void 0 : _customLabels$timeAgo8.daysAgo) !== null && _customLabels$timeAgo7 !== void 0 ? _customLabels$timeAgo7 : defaultLabels$30.timeAgo.daysAgo
657
+ justNow: (_customLabels$timeAgo = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo2 = customLabels.timeAgo) === null || _customLabels$timeAgo2 === void 0 ? void 0 : _customLabels$timeAgo2.justNow) !== null && _customLabels$timeAgo !== void 0 ? _customLabels$timeAgo : defaultLabels$33.timeAgo.justNow,
658
+ minutesAgo: (_customLabels$timeAgo3 = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo4 = customLabels.timeAgo) === null || _customLabels$timeAgo4 === void 0 ? void 0 : _customLabels$timeAgo4.minutesAgo) !== null && _customLabels$timeAgo3 !== void 0 ? _customLabels$timeAgo3 : defaultLabels$33.timeAgo.minutesAgo,
659
+ hoursAgo: (_customLabels$timeAgo5 = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo6 = customLabels.timeAgo) === null || _customLabels$timeAgo6 === void 0 ? void 0 : _customLabels$timeAgo6.hoursAgo) !== null && _customLabels$timeAgo5 !== void 0 ? _customLabels$timeAgo5 : defaultLabels$33.timeAgo.hoursAgo,
660
+ daysAgo: (_customLabels$timeAgo7 = customLabels === null || customLabels === void 0 || (_customLabels$timeAgo8 = customLabels.timeAgo) === null || _customLabels$timeAgo8 === void 0 ? void 0 : _customLabels$timeAgo8.daysAgo) !== null && _customLabels$timeAgo7 !== void 0 ? _customLabels$timeAgo7 : defaultLabels$33.timeAgo.daysAgo
322
661
  };
323
662
  const mergedActivityVerbs = {
324
- created: (_customLabels$activit = customLabels === null || customLabels === void 0 || (_customLabels$activit2 = customLabels.activityVerbs) === null || _customLabels$activit2 === void 0 ? void 0 : _customLabels$activit2.created) !== null && _customLabels$activit !== void 0 ? _customLabels$activit : defaultLabels$30.activityVerbs.created,
325
- updated: (_customLabels$activit3 = customLabels === null || customLabels === void 0 || (_customLabels$activit4 = customLabels.activityVerbs) === null || _customLabels$activit4 === void 0 ? void 0 : _customLabels$activit4.updated) !== null && _customLabels$activit3 !== void 0 ? _customLabels$activit3 : defaultLabels$30.activityVerbs.updated,
326
- completed: (_customLabels$activit5 = customLabels === null || customLabels === void 0 || (_customLabels$activit6 = customLabels.activityVerbs) === null || _customLabels$activit6 === void 0 ? void 0 : _customLabels$activit6.completed) !== null && _customLabels$activit5 !== void 0 ? _customLabels$activit5 : defaultLabels$30.activityVerbs.completed,
327
- commented: (_customLabels$activit7 = customLabels === null || customLabels === void 0 || (_customLabels$activit8 = customLabels.activityVerbs) === null || _customLabels$activit8 === void 0 ? void 0 : _customLabels$activit8.commented) !== null && _customLabels$activit7 !== void 0 ? _customLabels$activit7 : defaultLabels$30.activityVerbs.commented,
328
- assigned: (_customLabels$activit9 = customLabels === null || customLabels === void 0 || (_customLabels$activit10 = customLabels.activityVerbs) === null || _customLabels$activit10 === void 0 ? void 0 : _customLabels$activit10.assigned) !== null && _customLabels$activit9 !== void 0 ? _customLabels$activit9 : defaultLabels$30.activityVerbs.assigned,
329
- deployed: (_customLabels$activit11 = customLabels === null || customLabels === void 0 || (_customLabels$activit12 = customLabels.activityVerbs) === null || _customLabels$activit12 === void 0 ? void 0 : _customLabels$activit12.deployed) !== null && _customLabels$activit11 !== void 0 ? _customLabels$activit11 : defaultLabels$30.activityVerbs.deployed,
330
- merged: (_customLabels$activit13 = customLabels === null || customLabels === void 0 || (_customLabels$activit14 = customLabels.activityVerbs) === null || _customLabels$activit14 === void 0 ? void 0 : _customLabels$activit14.merged) !== null && _customLabels$activit13 !== void 0 ? _customLabels$activit13 : defaultLabels$30.activityVerbs.merged
663
+ created: (_customLabels$activit = customLabels === null || customLabels === void 0 || (_customLabels$activit2 = customLabels.activityVerbs) === null || _customLabels$activit2 === void 0 ? void 0 : _customLabels$activit2.created) !== null && _customLabels$activit !== void 0 ? _customLabels$activit : defaultLabels$33.activityVerbs.created,
664
+ updated: (_customLabels$activit3 = customLabels === null || customLabels === void 0 || (_customLabels$activit4 = customLabels.activityVerbs) === null || _customLabels$activit4 === void 0 ? void 0 : _customLabels$activit4.updated) !== null && _customLabels$activit3 !== void 0 ? _customLabels$activit3 : defaultLabels$33.activityVerbs.updated,
665
+ completed: (_customLabels$activit5 = customLabels === null || customLabels === void 0 || (_customLabels$activit6 = customLabels.activityVerbs) === null || _customLabels$activit6 === void 0 ? void 0 : _customLabels$activit6.completed) !== null && _customLabels$activit5 !== void 0 ? _customLabels$activit5 : defaultLabels$33.activityVerbs.completed,
666
+ commented: (_customLabels$activit7 = customLabels === null || customLabels === void 0 || (_customLabels$activit8 = customLabels.activityVerbs) === null || _customLabels$activit8 === void 0 ? void 0 : _customLabels$activit8.commented) !== null && _customLabels$activit7 !== void 0 ? _customLabels$activit7 : defaultLabels$33.activityVerbs.commented,
667
+ assigned: (_customLabels$activit9 = customLabels === null || customLabels === void 0 || (_customLabels$activit10 = customLabels.activityVerbs) === null || _customLabels$activit10 === void 0 ? void 0 : _customLabels$activit10.assigned) !== null && _customLabels$activit9 !== void 0 ? _customLabels$activit9 : defaultLabels$33.activityVerbs.assigned,
668
+ deployed: (_customLabels$activit11 = customLabels === null || customLabels === void 0 || (_customLabels$activit12 = customLabels.activityVerbs) === null || _customLabels$activit12 === void 0 ? void 0 : _customLabels$activit12.deployed) !== null && _customLabels$activit11 !== void 0 ? _customLabels$activit11 : defaultLabels$33.activityVerbs.deployed,
669
+ merged: (_customLabels$activit13 = customLabels === null || customLabels === void 0 || (_customLabels$activit14 = customLabels.activityVerbs) === null || _customLabels$activit14 === void 0 ? void 0 : _customLabels$activit14.merged) !== null && _customLabels$activit13 !== void 0 ? _customLabels$activit13 : defaultLabels$33.activityVerbs.merged
331
670
  };
332
671
  const labels = {
333
- title: (_customLabels$title = customLabels === null || customLabels === void 0 ? void 0 : customLabels.title) !== null && _customLabels$title !== void 0 ? _customLabels$title : defaultLabels$30.title,
334
- emptyMessage: (_customLabels$emptyMe = customLabels === null || customLabels === void 0 ? void 0 : customLabels.emptyMessage) !== null && _customLabels$emptyMe !== void 0 ? _customLabels$emptyMe : defaultLabels$30.emptyMessage,
335
- moreItems: (_customLabels$moreIte = customLabels === null || customLabels === void 0 ? void 0 : customLabels.moreItems) !== null && _customLabels$moreIte !== void 0 ? _customLabels$moreIte : defaultLabels$30.moreItems,
672
+ title: (_customLabels$title = customLabels === null || customLabels === void 0 ? void 0 : customLabels.title) !== null && _customLabels$title !== void 0 ? _customLabels$title : defaultLabels$33.title,
673
+ emptyMessage: (_customLabels$emptyMe = customLabels === null || customLabels === void 0 ? void 0 : customLabels.emptyMessage) !== null && _customLabels$emptyMe !== void 0 ? _customLabels$emptyMe : defaultLabels$33.emptyMessage,
674
+ moreItems: (_customLabels$moreIte = customLabels === null || customLabels === void 0 ? void 0 : customLabels.moreItems) !== null && _customLabels$moreIte !== void 0 ? _customLabels$moreIte : defaultLabels$33.moreItems,
336
675
  timeAgo: mergedTimeAgo,
337
676
  activityVerbs: mergedActivityVerbs
338
677
  };
@@ -460,13 +799,13 @@ function ActivityFeed({ activities, title, maxItems, onActivityClick, onShowMore
460
799
  ActivityFeed.displayName = "ActivityFeed";
461
800
  //#endregion
462
801
  //#region src/shells/filter-bar.tsx
463
- const defaultLabels$29 = {
802
+ const defaultLabels$32 = {
464
803
  clearAll: "필터 초기화",
465
804
  searchPlaceholder: "검색..."
466
805
  };
467
806
  /** Renders the filter bar component. */
468
807
  function FilterBar({ filters, onFilterChange, onDateRangeChange, onClearAll, labels: customLabels, presetActions, className }) {
469
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$29), customLabels);
808
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$32), customLabels);
470
809
  const [searchValues, setSearchValues] = useState({});
471
810
  const [tagInputValues, setTagInputValues] = useState({});
472
811
  const [multiSelectOpen, setMultiSelectOpen] = useState({});
@@ -692,10 +1031,10 @@ function matchesShortcut(event, shortcut) {
692
1031
  if (requiresMeta && !event.metaKey) return false;
693
1032
  return event.key.toLowerCase() === key;
694
1033
  }
695
- const defaultLabels$28 = { title: "빠른 작업" };
1034
+ const defaultLabels$31 = { title: "빠른 작업" };
696
1035
  /** Renders the quick actions component. */
697
1036
  function QuickActions({ actions, title, layout = "grid", columns = 3, showDescriptionInGrid = false, bindShortcuts = false, labels: customLabels, className }) {
698
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$28), customLabels);
1037
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$31), customLabels);
699
1038
  const displayTitle = title !== null && title !== void 0 ? title : labels.title;
700
1039
  const titleId = useId();
701
1040
  useEffect(() => {
@@ -773,7 +1112,7 @@ function QuickActions({ actions, title, layout = "grid", columns = 3, showDescri
773
1112
  QuickActions.displayName = "QuickActions";
774
1113
  //#endregion
775
1114
  //#region src/shells/team-member-list.tsx
776
- const defaultLabels$27 = {
1115
+ const defaultLabels$30 = {
777
1116
  title: "팀원",
778
1117
  emptyMessage: "팀원이 없습니다",
779
1118
  onlineCount: "{online}/{total} 온라인",
@@ -794,7 +1133,7 @@ const statusDot = {
794
1133
  };
795
1134
  /** Renders the team member list component. */
796
1135
  function TeamMemberList({ members, title, layout = "list", maxDisplay, onMemberClick, onShowMore, emptyMessage, labels: customLabels, className }) {
797
- const labels = _objectSpread2(_objectSpread2(_objectSpread2({}, defaultLabels$27), customLabels), {}, { status: _objectSpread2(_objectSpread2({}, defaultLabels$27.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status) });
1136
+ const labels = _objectSpread2(_objectSpread2(_objectSpread2({}, defaultLabels$30), customLabels), {}, { status: _objectSpread2(_objectSpread2({}, defaultLabels$30.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status) });
798
1137
  const displayTitle = title !== null && title !== void 0 ? title : labels.title;
799
1138
  const displayEmptyMessage = emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : labels.emptyMessage;
800
1139
  const titleId = useId();
@@ -1694,7 +2033,7 @@ const COLOR_PRESETS = [
1694
2033
  "#f97316",
1695
2034
  "#14b8a6"
1696
2035
  ];
1697
- const defaultLabels$26 = {
2036
+ const defaultLabels$29 = {
1698
2037
  eventLabelPrefix: "Event",
1699
2038
  defaultAriaLabel: "Event icon"
1700
2039
  };
@@ -1725,7 +2064,7 @@ function getEventIconStyle(color) {
1725
2064
  /** Renders the event icon component. */
1726
2065
  function EventIcon({ icon, color, size = "md", className, labels: customLabels }) {
1727
2066
  var _iconEntry$label;
1728
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$26), customLabels);
2067
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$29), customLabels);
1729
2068
  const sizes = SIZE_MAP[size];
1730
2069
  const resolvedColor = (color === null || color === void 0 ? void 0 : color.trim()) ? color : void 0;
1731
2070
  const iconEntry = typeof icon === "string" ? getIconRegistryEntry(icon) : void 0;
@@ -1817,14 +2156,14 @@ function ConnectionIndicator({ status, tone, label, showLabel = true, pulse, cla
1817
2156
  ConnectionIndicator.displayName = "ConnectionIndicator";
1818
2157
  //#endregion
1819
2158
  //#region src/shells/floating-action-bar.tsx
1820
- const defaultLabels$25 = {
2159
+ const defaultLabels$28 = {
1821
2160
  toolbarAriaLabel: "Actions",
1822
2161
  selectedLabel: (count) => `${count} selected`,
1823
2162
  dismissAriaLabel: "Dismiss"
1824
2163
  };
1825
2164
  /** Renders the floating action bar component. */
1826
2165
  function FloatingActionBar({ actions, selectedCount, onAction, onDismiss, className, labels: customLabels }) {
1827
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$25), customLabels);
2166
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$28), customLabels);
1828
2167
  if (actions.length === 0) return null;
1829
2168
  return /* @__PURE__ */ jsxs("div", {
1830
2169
  role: "toolbar",
@@ -1861,7 +2200,7 @@ function FloatingActionBar({ actions, selectedCount, onAction, onDismiss, classN
1861
2200
  FloatingActionBar.displayName = "FloatingActionBar";
1862
2201
  //#endregion
1863
2202
  //#region src/shells/template-picker.tsx
1864
- const defaultLabels$24 = {
2203
+ const defaultLabels$27 = {
1865
2204
  ariaLabel: "Templates",
1866
2205
  defaultCategory: "General",
1867
2206
  searchPlaceholder: "Search templates...",
@@ -1869,7 +2208,7 @@ const defaultLabels$24 = {
1869
2208
  };
1870
2209
  /** Renders the template picker component. */
1871
2210
  function TemplatePicker({ templates, selected, onSelect, labels: customLabels, showSearch = false, className }) {
1872
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$24), customLabels);
2211
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$27), customLabels);
1873
2212
  const [search, setSearch] = React.useState("");
1874
2213
  const filtered = React.useMemo(() => {
1875
2214
  if (!showSearch || !search) return templates;
@@ -1955,7 +2294,7 @@ function TemplatePicker({ templates, selected, onSelect, labels: customLabels, s
1955
2294
  TemplatePicker.displayName = "TemplatePicker";
1956
2295
  //#endregion
1957
2296
  //#region src/shells/code-snippet-viewer.tsx
1958
- const defaultLabels$23 = {
2297
+ const defaultLabels$26 = {
1959
2298
  copy: "Copy",
1960
2299
  copied: "Copied!",
1961
2300
  codeRegion: "Code snippet"
@@ -1993,7 +2332,7 @@ const syntaxThemeClasses = {
1993
2332
  /** Renders the code snippet viewer component. */
1994
2333
  function CodeSnippetViewer({ code, language = "text", title, showLineNumbers = true, showCopyButton = true, maxHeight = 400, syntaxTheme = "default", className, labels: customLabels }) {
1995
2334
  var _syntaxThemeClasses$s;
1996
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$23), customLabels);
2335
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$26), customLabels);
1997
2336
  const [copied, setCopied] = React.useState(false);
1998
2337
  const lines = code.split("\n");
1999
2338
  const theme = (_syntaxThemeClasses$s = syntaxThemeClasses[syntaxTheme]) !== null && _syntaxThemeClasses$s !== void 0 ? _syntaxThemeClasses$s : syntaxThemeClasses.default;
@@ -2045,13 +2384,15 @@ function CodeSnippetViewer({ code, language = "text", title, showLineNumbers = t
2045
2384
  CodeSnippetViewer.displayName = "CodeSnippetViewer";
2046
2385
  //#endregion
2047
2386
  //#region src/shells/property-explorer.tsx
2048
- const defaultLabels$22 = {
2387
+ const defaultLabels$25 = {
2049
2388
  searchPlaceholder: "Search properties...",
2050
- noPropertiesFound: "No properties found"
2389
+ noPropertiesFound: "No properties found",
2390
+ edit: (property) => `${property} 편집`,
2391
+ hidden: "숨김"
2051
2392
  };
2052
2393
  /** Renders the property explorer component. */
2053
- function PropertyExplorer({ groups, onSelect, className, labels: customLabels }) {
2054
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$22), customLabels);
2394
+ function PropertyExplorer({ groups, onSelect, onEdit, className, labels: customLabels }) {
2395
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$25), customLabels);
2055
2396
  const [search, setSearch] = React.useState("");
2056
2397
  const filtered = React.useMemo(() => {
2057
2398
  if (!search) return groups;
@@ -2077,36 +2418,55 @@ function PropertyExplorer({ groups, onSelect, className, labels: customLabels })
2077
2418
  children: group.name
2078
2419
  }), /* @__PURE__ */ jsx("div", {
2079
2420
  className: "gap-element flex flex-col",
2080
- children: group.properties.map((prop) => /* @__PURE__ */ jsxs("button", {
2081
- onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(prop),
2082
- className: cn("flex w-full items-center justify-between rounded-md px-2.5 py-1.5 text-left", "hover:bg-bg-subtle transition-colors"),
2083
- children: [/* @__PURE__ */ jsxs("div", {
2084
- className: "min-w-0",
2085
- children: [
2086
- /* @__PURE__ */ jsx(FieldToken, {
2087
- type: resolveFieldType(prop.type),
2088
- size: "xs",
2089
- title: prop.type,
2090
- className: "mr-2 align-[-2px]"
2091
- }),
2092
- /* @__PURE__ */ jsx("span", {
2093
- className: "text-text-primary text-sm font-medium",
2094
- children: prop.name
2095
- }),
2096
- /* @__PURE__ */ jsx("span", {
2097
- className: "text-text-tertiary ml-2 font-mono text-xs",
2098
- children: prop.type
2099
- }),
2100
- prop.description && /* @__PURE__ */ jsx("p", {
2101
- className: "text-text-tertiary truncate text-xs",
2102
- children: prop.description
2421
+ children: group.properties.map((prop) => {
2422
+ var _prop$dataType;
2423
+ return /* @__PURE__ */ jsxs("div", {
2424
+ className: cn("hover:bg-bg-subtle flex items-center rounded-md transition-colors", prop.hidden && "opacity-60"),
2425
+ children: [/* @__PURE__ */ jsxs("button", {
2426
+ onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(prop),
2427
+ className: "flex min-w-0 flex-1 items-center justify-between px-2.5 py-1.5 text-left",
2428
+ children: [/* @__PURE__ */ jsxs("div", {
2429
+ className: "min-w-0",
2430
+ children: [
2431
+ /* @__PURE__ */ jsx(FieldToken, {
2432
+ type: (_prop$dataType = prop.dataType) !== null && _prop$dataType !== void 0 ? _prop$dataType : resolveFieldType(prop.type),
2433
+ size: "xs",
2434
+ title: prop.type,
2435
+ className: "mr-2 align-[-2px]"
2436
+ }),
2437
+ /* @__PURE__ */ jsx("span", {
2438
+ className: "text-text-primary text-sm font-medium",
2439
+ children: prop.name
2440
+ }),
2441
+ /* @__PURE__ */ jsx("span", {
2442
+ className: "text-text-tertiary ml-2 font-mono text-xs",
2443
+ children: prop.type
2444
+ }),
2445
+ prop.hidden && /* @__PURE__ */ jsx("span", {
2446
+ className: "text-text-tertiary ml-2 text-xs",
2447
+ children: labels.hidden
2448
+ }),
2449
+ prop.description && /* @__PURE__ */ jsx("p", {
2450
+ className: "text-text-tertiary truncate text-xs",
2451
+ children: prop.description
2452
+ })
2453
+ ]
2454
+ }), prop.eventCount !== void 0 && /* @__PURE__ */ jsx("span", {
2455
+ className: "text-text-tertiary ml-2 shrink-0 text-xs",
2456
+ children: formatOptNumber(prop.eventCount)
2457
+ })]
2458
+ }), onEdit && /* @__PURE__ */ jsx("button", {
2459
+ type: "button",
2460
+ onClick: () => onEdit(prop),
2461
+ "aria-label": labels.edit(prop.name),
2462
+ className: "text-text-tertiary hover:text-text-primary mr-1.5 shrink-0 rounded p-1",
2463
+ children: /* @__PURE__ */ jsx(Pencil, {
2464
+ "aria-hidden": "true",
2465
+ className: "size-3.5"
2103
2466
  })
2104
- ]
2105
- }), prop.eventCount !== void 0 && /* @__PURE__ */ jsx("span", {
2106
- className: "text-text-tertiary ml-2 shrink-0 text-xs",
2107
- children: formatOptNumber(prop.eventCount)
2108
- })]
2109
- }, prop.name))
2467
+ })]
2468
+ }, prop.name);
2469
+ })
2110
2470
  })] }, group.name)), filtered.length === 0 && /* @__PURE__ */ jsx("p", {
2111
2471
  className: "text-text-tertiary py-4 text-center text-sm",
2112
2472
  children: labels.noPropertiesFound
@@ -2117,14 +2477,14 @@ function PropertyExplorer({ groups, onSelect, className, labels: customLabels })
2117
2477
  PropertyExplorer.displayName = "PropertyExplorer";
2118
2478
  //#endregion
2119
2479
  //#region src/shells/query-results-table.tsx
2120
- const defaultLabels$21 = {
2480
+ const defaultLabels$24 = {
2121
2481
  emptyMessage: "No results",
2122
2482
  loadingMessage: "Running query...",
2123
2483
  rowsSuffix: "row(s)"
2124
2484
  };
2125
2485
  /** Renders the query results table component. */
2126
2486
  function QueryResultsTable({ columns, rows, maxHeight = 400, emptyMessage, loading = false, error, labels: customLabels, className }) {
2127
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$21), customLabels);
2487
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$24), customLabels);
2128
2488
  if (error) return /* @__PURE__ */ jsx("div", {
2129
2489
  className: cn("border-danger bg-danger-subtle rounded-lg border p-4", className),
2130
2490
  role: "alert",
@@ -2208,7 +2568,7 @@ function QueryResultsTable({ columns, rows, maxHeight = 400, emptyMessage, loadi
2208
2568
  QueryResultsTable.displayName = "QueryResultsTable";
2209
2569
  //#endregion
2210
2570
  //#region src/shells/alert-builder.tsx
2211
- const defaultLabels$20 = {
2571
+ const defaultLabels$23 = {
2212
2572
  alertNameLabel: "Alert name",
2213
2573
  conditionsLabel: "Conditions",
2214
2574
  metricLabel: "Metric",
@@ -2279,7 +2639,7 @@ function AlertBuilder({ value, onChange, metrics = [
2279
2639
  ], labels: customLabels, className }) {
2280
2640
  const resolvedMetrics = eventOptions ? eventOptions.map((e) => e.id) : metrics;
2281
2641
  const metricLabelMap = eventOptions ? Object.fromEntries(eventOptions.map((e) => [e.id, e.name])) : null;
2282
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$20), customLabels);
2642
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$23), customLabels);
2283
2643
  const alertNameId = React.useId();
2284
2644
  const conditionsId = React.useId();
2285
2645
  const checkFrequencyId = React.useId();
@@ -2434,7 +2794,7 @@ function AlertBuilder({ value, onChange, metrics = [
2434
2794
  AlertBuilder.displayName = "AlertBuilder";
2435
2795
  //#endregion
2436
2796
  //#region src/shells/sql-editor.tsx
2437
- const defaultLabels$19 = {
2797
+ const defaultLabels$22 = {
2438
2798
  placeholder: "SELECT * FROM events LIMIT 100",
2439
2799
  runHint: "Ctrl+Enter to run",
2440
2800
  runButton: "Run Query",
@@ -2442,7 +2802,7 @@ const defaultLabels$19 = {
2442
2802
  };
2443
2803
  /** Renders the sql editor component. */
2444
2804
  function SqlEditor({ value, onChange, onRun, onRunAndAdvance, placeholder, readOnly = false, height = 200, schema, completionSources, keymap: customKeymap, extensions: customExtensions, ariaLabel, autoFocus = false, showFooter, labels: customLabels, className }) {
2445
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$19), customLabels);
2805
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$22), customLabels);
2446
2806
  const fill = height === "fill";
2447
2807
  const footerVisible = showFooter !== null && showFooter !== void 0 ? showFooter : Boolean(onRun);
2448
2808
  const editorRef = React.useRef(null);
@@ -2614,7 +2974,7 @@ function SqlEditor({ value, onChange, onRun, onRunAndAdvance, placeholder, readO
2614
2974
  SqlEditor.displayName = "SqlEditor";
2615
2975
  //#endregion
2616
2976
  //#region src/shells/event-meta-editor.tsx
2617
- const defaultLabels$18 = {
2977
+ const defaultLabels$21 = {
2618
2978
  icon: "Icon",
2619
2979
  color: "Color",
2620
2980
  name: "Event name",
@@ -2628,8 +2988,8 @@ const defaultLabels$18 = {
2628
2988
  emptyTagsMessage: "No tags added yet."
2629
2989
  };
2630
2990
  /** Renders the event meta editor component. */
2631
- function EventMetaEditor({ value, onChange, icons, className, labels: customLabels }) {
2632
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$18), customLabels);
2991
+ function EventMetaEditor({ value, onChange, icons, sections, footer, className, labels: customLabels }) {
2992
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$21), customLabels);
2633
2993
  const hasTags = value.tags.length > 0;
2634
2994
  const nameId = React.useId();
2635
2995
  const displayNameId = React.useId();
@@ -2722,17 +3082,32 @@ function EventMetaEditor({ value, onChange, icons, className, labels: customLabe
2722
3082
  className: "text-text-tertiary mt-1 block text-xs",
2723
3083
  children: labels.emptyTagsMessage
2724
3084
  })
2725
- ] })
3085
+ ] }),
3086
+ sections === null || sections === void 0 ? void 0 : sections.map((section) => /* @__PURE__ */ jsxs("section", {
3087
+ className: "gap-element flex flex-col",
3088
+ children: [
3089
+ section.title && /* @__PURE__ */ jsx("span", {
3090
+ className: "text-text-tertiary block text-xs font-medium",
3091
+ children: section.title
3092
+ }),
3093
+ section.children,
3094
+ section.description && /* @__PURE__ */ jsx("span", {
3095
+ className: "text-text-tertiary block text-xs",
3096
+ children: section.description
3097
+ })
3098
+ ]
3099
+ }, section.id)),
3100
+ footer
2726
3101
  ]
2727
3102
  });
2728
3103
  }
2729
3104
  EventMetaEditor.displayName = "EventMetaEditor";
2730
3105
  //#endregion
2731
3106
  //#region src/shells/widget-grid.tsx
2732
- const defaultLabels$17 = { emptyMessage: "No widgets to display" };
3107
+ const defaultLabels$20 = { emptyMessage: "No widgets to display" };
2733
3108
  /** Renders the widget grid component. */
2734
3109
  function WidgetGrid({ widgets, cols = 12, rowHeight = 80, gap = 16, editable = false, onReorder, labels: customLabels, className }) {
2735
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$17), customLabels);
3110
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$20), customLabels);
2736
3111
  const [dragIdx, setDragIdx] = React.useState(null);
2737
3112
  const [overIdx, setOverIdx] = React.useState(null);
2738
3113
  if (widgets.length === 0) return /* @__PURE__ */ jsx("div", {
@@ -2777,7 +3152,7 @@ function WidgetGrid({ widgets, cols = 12, rowHeight = 80, gap = 16, editable = f
2777
3152
  WidgetGrid.displayName = "WidgetGrid";
2778
3153
  //#endregion
2779
3154
  //#region src/shells/report-builder.tsx
2780
- const defaultLabels$16 = {
3155
+ const defaultLabels$19 = {
2781
3156
  stepsLabel: "Report steps",
2782
3157
  stepType: "Chart Type",
2783
3158
  stepConfig: "Data Config",
@@ -2853,7 +3228,7 @@ const STEPS = [
2853
3228
  ];
2854
3229
  /** Renders the report builder component. */
2855
3230
  function ReportBuilder({ chartTypes = DEFAULT_CHART_TYPES, dataSources = [], onSave, onCancel, configForm, styleForm, preview, onChartTypeChange, onDataSourceChange, onStepChange, selectedChartType: controlledChartType, selectedDataSource: controlledDataSource, labels: customLabels, className }) {
2856
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$16), customLabels);
3231
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$19), customLabels);
2857
3232
  const [stepIndex, setStepIndex] = React.useState(0);
2858
3233
  const [internalChartType, setInternalChartType] = React.useState(null);
2859
3234
  const [internalDataSource, setInternalDataSource] = React.useState("");
@@ -3073,7 +3448,7 @@ function ReportBuilder({ chartTypes = DEFAULT_CHART_TYPES, dataSources = [], onS
3073
3448
  ReportBuilder.displayName = "ReportBuilder";
3074
3449
  //#endregion
3075
3450
  //#region src/shells/audit-timeline.tsx
3076
- const defaultLabels$15 = {
3451
+ const defaultLabels$18 = {
3077
3452
  title: "변경 이력",
3078
3453
  empty: "변경 이력이 없습니다",
3079
3454
  expand: "상세 보기",
@@ -3152,7 +3527,7 @@ function DiffTable({ changes, labels }) {
3152
3527
  }
3153
3528
  /** Renders the audit timeline component. */
3154
3529
  function AuditTimeline({ entries, labels: customLabels, className, onEntryClick }) {
3155
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$15), customLabels);
3530
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$18), customLabels);
3156
3531
  const [expandedIds, setExpandedIds] = React.useState(/* @__PURE__ */ new Set());
3157
3532
  const toggleExpanded = React.useCallback((id) => {
3158
3533
  setExpandedIds((prev) => {
@@ -3275,7 +3650,7 @@ function AuditTimeline({ entries, labels: customLabels, className, onEntryClick
3275
3650
  AuditTimeline.displayName = "AuditTimeline";
3276
3651
  //#endregion
3277
3652
  //#region src/shells/segment-builder.tsx
3278
- const defaultLabels$14 = {
3653
+ const defaultLabels$17 = {
3279
3654
  match: "Match",
3280
3655
  ofTheFollowing: "of the following",
3281
3656
  groupLabel: "Segment group",
@@ -3396,7 +3771,7 @@ function SegmentBuilder({ groups, onChange, eventOptions = [
3396
3771
  "New Users",
3397
3772
  "Power Users"
3398
3773
  ], className, labels: customLabels }) {
3399
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$14), customLabels);
3774
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$17), customLabels);
3400
3775
  const builderId = React.useId().replace(/:/g, "");
3401
3776
  const nextIdRef = React.useRef(1);
3402
3777
  const createId = React.useCallback(() => {
@@ -3609,7 +3984,7 @@ function SegmentBuilder({ groups, onChange, eventOptions = [
3609
3984
  SegmentBuilder.displayName = "SegmentBuilder";
3610
3985
  //#endregion
3611
3986
  //#region src/shells/insights-panel.tsx
3612
- const defaultLabels$13 = {
3987
+ const defaultLabels$16 = {
3613
3988
  title: "Insights",
3614
3989
  dismiss: "Dismiss",
3615
3990
  showDismissed: "Show dismissed",
@@ -3640,7 +4015,7 @@ const severityConfig = {
3640
4015
  /** Renders the insights panel component. */
3641
4016
  function InsightsPanel({ insights, stats, detectionTypes, onDetectionTypeToggle, detectionConfig, onDetectionConfigChange, onDismiss, onInsightClick, onStatClick, header, actions, labels: customLabels, className }) {
3642
4017
  var _detectionConfig$days, _detectionConfig$zSco;
3643
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$13), customLabels);
4018
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$16), customLabels);
3644
4019
  const [showDismissed, setShowDismissed] = React.useState(false);
3645
4020
  const visibleInsights = showDismissed ? insights : insights.filter((i) => !i.dismissed);
3646
4021
  const hasStats = stats && stats.length > 0;
@@ -4032,7 +4407,7 @@ function ExportButton({ data, columns, fileName = "export", formats = ["csv", "j
4032
4407
  ExportButton.displayName = "ExportButton";
4033
4408
  //#endregion
4034
4409
  //#region src/shells/summary-row.tsx
4035
- const defaultLabels$12 = {
4410
+ const defaultLabels$15 = {
4036
4411
  emptyTitle: "No summary stats",
4037
4412
  emptyDescription: "Provide at least one stat to render the summary row."
4038
4413
  };
@@ -4056,7 +4431,7 @@ const colsClass = {
4056
4431
  };
4057
4432
  /** Renders the summary row component. */
4058
4433
  function SummaryRow({ stats, columns = 4, onStatClick, selectedStatId, size = "md", formatValue, durationFractionDigits = 1, percentageFractionDigits = 1, loading = false, labels: customLabels, className }) {
4059
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$12), customLabels);
4434
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$15), customLabels);
4060
4435
  if (loading) return /* @__PURE__ */ jsx("div", {
4061
4436
  className: cn("gap-group grid", colsClass[columns], className),
4062
4437
  "data-opt-id": "FGFP3",
@@ -4096,6 +4471,505 @@ function SummaryRow({ stats, columns = 4, onStatClick, selectedStatId, size = "m
4096
4471
  }
4097
4472
  SummaryRow.displayName = "SummaryRow";
4098
4473
  //#endregion
4474
+ //#region src/lib/query/query-match.ts
4475
+ function toText(value) {
4476
+ if (value === null || value === void 0) return "";
4477
+ if (typeof value === "string") return value;
4478
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
4479
+ return JSON.stringify(value);
4480
+ }
4481
+ function compare(left, right) {
4482
+ const leftNumber = typeof left === "number" ? left : Number(toText(left));
4483
+ const rightNumber = Number(right);
4484
+ if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) return leftNumber - rightNumber;
4485
+ return toText(left).localeCompare(right);
4486
+ }
4487
+ function matchesClause(clause, read, searchable) {
4488
+ if (clause.type === "term") return searchable().toLowerCase().includes(clause.value.toLowerCase());
4489
+ const value = read(clause.field);
4490
+ switch (clause.operator) {
4491
+ case "exists": return value !== void 0 && value !== null && value !== "";
4492
+ case "eq": return clause.values.some((candidate) => toText(value).toLowerCase() === candidate.toLowerCase());
4493
+ case "contains": return clause.values.some((candidate) => toText(value).toLowerCase().includes(candidate.toLowerCase()));
4494
+ case "gt":
4495
+ var _clause$values$;
4496
+ return compare(value, (_clause$values$ = clause.values[0]) !== null && _clause$values$ !== void 0 ? _clause$values$ : "") > 0;
4497
+ case "gte":
4498
+ var _clause$values$2;
4499
+ return compare(value, (_clause$values$2 = clause.values[0]) !== null && _clause$values$2 !== void 0 ? _clause$values$2 : "") >= 0;
4500
+ case "lt":
4501
+ var _clause$values$3;
4502
+ return compare(value, (_clause$values$3 = clause.values[0]) !== null && _clause$values$3 !== void 0 ? _clause$values$3 : "") < 0;
4503
+ case "lte":
4504
+ var _clause$values$4;
4505
+ return compare(value, (_clause$values$4 = clause.values[0]) !== null && _clause$values$4 !== void 0 ? _clause$values$4 : "") <= 0;
4506
+ default: return true;
4507
+ }
4508
+ }
4509
+ /**
4510
+ * Whether one row satisfies every clause.
4511
+ *
4512
+ * `searchable` is lazy because most queries are field constraints, and
4513
+ * flattening a row to text for a term match nobody asked for is the expensive
4514
+ * part of filtering a live tail.
4515
+ */
4516
+ function matchesQuery(query, read, searchable) {
4517
+ return query.clauses.every((clause) => {
4518
+ const matched = matchesClause(clause, read, searchable);
4519
+ return clause.negated ? !matched : matched;
4520
+ });
4521
+ }
4522
+ /** Convenience for plain objects, including one level of nested properties. */
4523
+ function matchesQueryObject(query, row, options = {}) {
4524
+ const nested = options.nested ? row[options.nested] : void 0;
4525
+ const read = (field) => field in row ? row[field] : nested === null || nested === void 0 ? void 0 : nested[field];
4526
+ let cached = null;
4527
+ const searchable = () => {
4528
+ var _cached;
4529
+ (_cached = cached) !== null && _cached !== void 0 || (cached = [...Object.values(row).filter((value) => typeof value !== "object"), ...Object.values(nested !== null && nested !== void 0 ? nested : {})].map(toText).join(" "));
4530
+ return cached;
4531
+ };
4532
+ return matchesQuery(query, read, searchable);
4533
+ }
4534
+ //#endregion
4535
+ //#region src/lib/use-media-query.ts
4536
+ /**
4537
+ * Whether a media query matches, kept in sync with the browser.
4538
+ *
4539
+ * `useSyncExternalStore` rather than an effect: a layout that switches on width
4540
+ * must not render the wrong shape for a frame first. The server snapshot is the
4541
+ * caller's `serverFallback`, because the server does not know the viewport and
4542
+ * guessing "narrow" collapses a wide layout on every first paint.
4543
+ *
4544
+ * Internal. Exported from `lib` for the components in this package, not from
4545
+ * the package barrel — a hook that answers "is this viewport wide" invites
4546
+ * layout decisions that belong in CSS.
4547
+ */
4548
+ function useMediaQuery(query, serverFallback = false) {
4549
+ return useSyncExternalStore((onChange) => {
4550
+ if (typeof window === "undefined") return () => {};
4551
+ const list = window.matchMedia(query);
4552
+ list.addEventListener("change", onChange);
4553
+ return () => list.removeEventListener("change", onChange);
4554
+ }, () => typeof window === "undefined" ? serverFallback : window.matchMedia(query).matches, () => serverFallback);
4555
+ }
4556
+ //#endregion
4557
+ //#region src/shells/inspector-layout.tsx
4558
+ /** Tailwind needs whole class names, so the queries and widths are literals. */
4559
+ const breakpointQuery = {
4560
+ lg: "(min-width: 64rem)",
4561
+ xl: "(min-width: 80rem)",
4562
+ "2xl": "(min-width: 96rem)"
4563
+ };
4564
+ const pushWidth = {
4565
+ sm: "w-[22rem]",
4566
+ md: "w-[30rem]",
4567
+ lg: "w-[42rem]"
4568
+ };
4569
+ const flyoutSize = {
4570
+ sm: "sm",
4571
+ md: "md",
4572
+ lg: "lg"
4573
+ };
4574
+ /**
4575
+ * InspectorLayout — a list and the record it is showing, side by side.
4576
+ *
4577
+ * Reading a catalogue is a loop: look at the list, open one, decide, come back.
4578
+ * A dialog breaks that loop — it takes the list away, and coming back costs the
4579
+ * reader their scroll position and their place in the scan. This keeps both on
4580
+ * screen where there is room, and falls back to an overlay where there is not.
4581
+ *
4582
+ * Every surface that wanted this was writing `w-80 border-l` by hand and
4583
+ * re-deciding the two things that are easy to get wrong: which width switches
4584
+ * the layout, and whether the list stays mounted.
4585
+ *
4586
+ * Focus is deliberately **not** one of them. `Flyout` already remembers who
4587
+ * opened it and hands focus back on close, and its effect runs before this
4588
+ * one — a parent that also tried to capture `document.activeElement` would
4589
+ * read the panel the child had just focused and "restore" to a node that is
4590
+ * about to be removed. One owner, and it is the one closest to the panel.
4591
+ *
4592
+ * @example
4593
+ * ```tsx
4594
+ * <InspectorLayout
4595
+ * open={selected !== null}
4596
+ * onClose={() => setSelected(null)}
4597
+ * title={selected?.name}
4598
+ * inspector={<EventInspector name={selected?.name} />}
4599
+ * >
4600
+ * <DataTable … />
4601
+ * </InspectorLayout>
4602
+ * ```
4603
+ */
4604
+ function InspectorLayout({ children, inspector, open, onClose, title, description, actions, footer, breakpoint = "xl", width = "md", labels, className }) {
4605
+ const canPush = useMediaQuery(breakpointQuery[breakpoint], true);
4606
+ return /* @__PURE__ */ jsxs("div", {
4607
+ className: cn("flex min-w-0 items-stretch gap-group", className),
4608
+ "data-opt-id": "MN44T",
4609
+ "data-opt-slug": "inspector-layout.InspectorLayout",
4610
+ "data-inspector-mode": canPush ? "push" : "overlay",
4611
+ children: [/* @__PURE__ */ jsx("div", {
4612
+ className: "min-w-0 flex-1",
4613
+ children
4614
+ }), canPush ? open && /* @__PURE__ */ jsx("aside", {
4615
+ className: cn("shrink-0", pushWidth[width]),
4616
+ children: /* @__PURE__ */ jsx(Flyout, {
4617
+ open,
4618
+ onClose,
4619
+ type: "inline",
4620
+ title,
4621
+ description,
4622
+ actions,
4623
+ footer,
4624
+ labels,
4625
+ className: "h-full",
4626
+ children: inspector
4627
+ })
4628
+ }) : /* @__PURE__ */ jsx(Flyout, {
4629
+ open,
4630
+ onClose,
4631
+ type: "overlay",
4632
+ scrim: true,
4633
+ size: flyoutSize[width],
4634
+ title,
4635
+ description,
4636
+ actions,
4637
+ footer,
4638
+ labels,
4639
+ children: inspector
4640
+ })]
4641
+ });
4642
+ }
4643
+ //#endregion
4644
+ //#region src/shells/query-filter-bar.tsx
4645
+ const defaultLabels$14 = {
4646
+ placeholder: "검색하거나 필터를 입력하세요",
4647
+ ariaLabel: "검색",
4648
+ filtersAriaLabel: "필터",
4649
+ clearAll: "필터 지우기",
4650
+ activeCount: (count) => `${count}개 적용됨`
4651
+ };
4652
+ function toggleValue(query, field, value, active, multiSelect) {
4653
+ if (active) {
4654
+ const remaining = fieldValues(query, field).filter((it) => it !== value);
4655
+ const cleared = withoutField(query, field);
4656
+ return remaining.reduce((next, keep) => withFieldValue(next, field, keep), cleared);
4657
+ }
4658
+ return multiSelect ? withFieldValue(query, field, value) : withFieldValue(withoutField(query, field), field, value);
4659
+ }
4660
+ /**
4661
+ * QueryFilterBar — filter buttons and a query string that are the same thing.
4662
+ *
4663
+ * The failure this exists to prevent is two sources of truth. A search box
4664
+ * beside a row of filter buttons will drift: the buttons keep their own state,
4665
+ * the box keeps the text, and a link to the page carries one of them. Readers
4666
+ * find the two disagreeing and stop trusting either.
4667
+ *
4668
+ * So the buttons hold no state at all. Each one reads the query to decide
4669
+ * whether it is active and writes the query when clicked, which makes the
4670
+ * behaviour fall out for free: typing `status:archived` lights up the status
4671
+ * filter, clicking the filter puts `status:archived` in the box, and the URL
4672
+ * that carries the query carries the whole filter state with it.
4673
+ *
4674
+ * @example
4675
+ * ```tsx
4676
+ * <QueryFilterBar
4677
+ * value={query}
4678
+ * onChange={setQuery}
4679
+ * filters={[
4680
+ * { id: "conversion", label: "전환", kind: "is", field: "is", value: "conversion" },
4681
+ * { id: "status", label: "상태", kind: "field_value_selection", field: "status",
4682
+ * options: [{ value: "archived", label: "보관", count: 12 }] },
4683
+ * ]}
4684
+ * />
4685
+ * ```
4686
+ */
4687
+ function QueryFilterBar({ value, onChange, filters, fields, actions, showClauses = true, live = false, disabled = false, labels: customLabels, queryBarLabels, className }) {
4688
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$14), customLabels);
4689
+ const activeCount = useMemo(() => filters.reduce((count, filter) => {
4690
+ const values = fieldValues(value, filter.field);
4691
+ if (filter.kind === "field_value_selection") return count + values.length;
4692
+ return count + (filter.value && values.includes(filter.value) ? 1 : 0);
4693
+ }, 0), [filters, value]);
4694
+ return /* @__PURE__ */ jsxs("div", {
4695
+ className: cn("flex flex-col gap-element", className),
4696
+ "data-opt-id": "SK31N",
4697
+ "data-opt-slug": "query-filter-bar.QueryFilterBar",
4698
+ children: [/* @__PURE__ */ jsx(QueryBar, {
4699
+ value,
4700
+ onChange,
4701
+ fields,
4702
+ showClauses,
4703
+ live,
4704
+ disabled,
4705
+ labels: _objectSpread2(_objectSpread2({}, queryBarLabels), {}, {
4706
+ placeholder: labels.placeholder,
4707
+ ariaLabel: labels.ariaLabel
4708
+ })
4709
+ }), /* @__PURE__ */ jsxs("div", {
4710
+ className: "gap-element flex flex-wrap items-center",
4711
+ role: "group",
4712
+ "aria-label": labels.filtersAriaLabel,
4713
+ children: [
4714
+ filters.map((filter) => {
4715
+ var _filter$multiSelect, _filter$value;
4716
+ const values = fieldValues(value, filter.field);
4717
+ const multiSelect = (_filter$multiSelect = filter.multiSelect) !== null && _filter$multiSelect !== void 0 ? _filter$multiSelect : true;
4718
+ if (filter.kind === "field_value_selection") {
4719
+ var _filter$options, _filter$options2;
4720
+ const selected = (_filter$options = filter.options) === null || _filter$options === void 0 ? void 0 : _filter$options.filter((option) => values.includes(option.value));
4721
+ return /* @__PURE__ */ jsxs(PopoverRoot, { children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
4722
+ disabled,
4723
+ className: cn("inline-flex h-7 items-center gap-1 rounded-md border px-2 text-xs transition-colors", OPT_FOCUS_VISIBLE, (selected === null || selected === void 0 ? void 0 : selected.length) ? "border-accent bg-accent-subtle text-text-primary" : "border-border text-text-secondary hover:text-text-primary", disabled && "pointer-events-none opacity-50"),
4724
+ children: [
4725
+ /* @__PURE__ */ jsx("span", { children: filter.label }),
4726
+ (selected === null || selected === void 0 ? void 0 : selected.length) ? /* @__PURE__ */ jsx(Badge, {
4727
+ variant: "info",
4728
+ size: "sm",
4729
+ children: selected.length
4730
+ }) : null,
4731
+ /* @__PURE__ */ jsx(ChevronDown, {
4732
+ "aria-hidden": "true",
4733
+ className: "size-3"
4734
+ })
4735
+ ]
4736
+ }), /* @__PURE__ */ jsx(PopoverContent, {
4737
+ className: "min-w-48 p-1",
4738
+ children: /* @__PURE__ */ jsx("div", {
4739
+ role: "group",
4740
+ "aria-label": filter.label,
4741
+ children: (_filter$options2 = filter.options) === null || _filter$options2 === void 0 ? void 0 : _filter$options2.map((option) => {
4742
+ const active = values.includes(option.value);
4743
+ return /* @__PURE__ */ jsxs("button", {
4744
+ type: "button",
4745
+ disabled,
4746
+ "aria-pressed": active,
4747
+ onClick: () => onChange(toggleValue(value, filter.field, option.value, active, multiSelect)),
4748
+ className: cn("flex w-full items-center gap-2 rounded px-2 py-1.5 text-left text-xs", "hover:bg-bg-subtle", "disabled:pointer-events-none disabled:opacity-50", OPT_FOCUS_VISIBLE),
4749
+ children: [
4750
+ /* @__PURE__ */ jsx(Check, {
4751
+ "aria-hidden": "true",
4752
+ className: cn("size-3 shrink-0", active ? "opacity-100" : "opacity-0")
4753
+ }),
4754
+ /* @__PURE__ */ jsx("span", {
4755
+ className: "flex-1 truncate",
4756
+ children: option.label
4757
+ }),
4758
+ option.count != null && /* @__PURE__ */ jsx("span", {
4759
+ className: "text-text-tertiary tabular-nums",
4760
+ children: option.count
4761
+ })
4762
+ ]
4763
+ }, option.value);
4764
+ })
4765
+ })
4766
+ })] }, filter.id);
4767
+ }
4768
+ const filterValue = (_filter$value = filter.value) !== null && _filter$value !== void 0 ? _filter$value : filter.id;
4769
+ const active = values.includes(filterValue);
4770
+ return /* @__PURE__ */ jsx("button", {
4771
+ type: "button",
4772
+ disabled,
4773
+ "aria-pressed": active,
4774
+ onClick: () => onChange(toggleValue(value, filter.field, filterValue, active, multiSelect)),
4775
+ className: cn("inline-flex h-7 items-center rounded-md border px-2 text-xs transition-colors", OPT_FOCUS_VISIBLE, active ? "border-accent bg-accent-subtle text-text-primary" : "border-border text-text-secondary hover:text-text-primary", "disabled:pointer-events-none disabled:opacity-50"),
4776
+ children: filter.label
4777
+ }, filter.id);
4778
+ }),
4779
+ activeCount > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
4780
+ className: "text-text-tertiary text-xs",
4781
+ children: labels.activeCount(activeCount)
4782
+ }), /* @__PURE__ */ jsxs(Button, {
4783
+ variant: "ghost",
4784
+ size: "sm",
4785
+ disabled,
4786
+ onClick: () => onChange({ clauses: [] }),
4787
+ children: [/* @__PURE__ */ jsx(X, {
4788
+ "aria-hidden": "true",
4789
+ className: "size-3"
4790
+ }), labels.clearAll]
4791
+ })] }),
4792
+ actions
4793
+ ]
4794
+ })]
4795
+ });
4796
+ }
4797
+ /** Whether the bar is filtering anything — for an empty state's wording. */
4798
+ function hasActiveQuery(query) {
4799
+ return !isEmptyQuery(query);
4800
+ }
4801
+ //#endregion
4802
+ //#region src/shells/catalog-frame.tsx
4803
+ /**
4804
+ * CatalogRowActions — a row's actions, two of them visible.
4805
+ *
4806
+ * Beyond two, a row's action column starts competing with the row's content
4807
+ * for the reader's eye, so the rest go behind one menu. The click never
4808
+ * reaches the row: acting on a row and selecting it are different intentions,
4809
+ * and a table that does both at once is one a reader stops trusting.
4810
+ */
4811
+ function CatalogRowActions({ item, actions, visibleCount = 2, labels }) {
4812
+ var _labels$rowActions, _labels$moreActions;
4813
+ const applicable = actions.filter((action) => {
4814
+ var _action$available, _action$available2;
4815
+ return (_action$available = (_action$available2 = action.available) === null || _action$available2 === void 0 ? void 0 : _action$available2.call(action, item)) !== null && _action$available !== void 0 ? _action$available : true;
4816
+ });
4817
+ const visible = applicable.slice(0, visibleCount);
4818
+ const overflow = applicable.slice(visibleCount);
4819
+ return /* @__PURE__ */ jsxs("div", {
4820
+ className: "flex items-center justify-end gap-1",
4821
+ role: "group",
4822
+ "aria-label": (_labels$rowActions = labels === null || labels === void 0 ? void 0 : labels.rowActions) !== null && _labels$rowActions !== void 0 ? _labels$rowActions : "행 액션",
4823
+ onClick: (event) => event.stopPropagation(),
4824
+ children: [visible.map((action) => /* @__PURE__ */ jsxs(Button, {
4825
+ variant: "ghost",
4826
+ size: "sm",
4827
+ onClick: () => action.onSelect(item),
4828
+ children: [action.icon, action.label]
4829
+ }, action.id)), overflow.length > 0 && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownTrigger, {
4830
+ "aria-label": (_labels$moreActions = labels === null || labels === void 0 ? void 0 : labels.moreActions) !== null && _labels$moreActions !== void 0 ? _labels$moreActions : "더 보기",
4831
+ children: /* @__PURE__ */ jsx(MoreHorizontal, {
4832
+ "aria-hidden": "true",
4833
+ className: "size-4"
4834
+ })
4835
+ }), /* @__PURE__ */ jsx(DropdownContent, { children: overflow.map((action) => /* @__PURE__ */ jsx(DropdownItem, {
4836
+ onClick: () => action.onSelect(item),
4837
+ children: action.label
4838
+ }, action.id)) })] })]
4839
+ });
4840
+ }
4841
+ /**
4842
+ * Keeps a cell's own controls from also selecting the row.
4843
+ *
4844
+ * A click on a switch or a copy button reaches the row handler on its way up,
4845
+ * so toggling a flag would open the inspector at the same time.
4846
+ */
4847
+ function CatalogCellControls({ children }) {
4848
+ return /* @__PURE__ */ jsx("span", {
4849
+ className: "contents",
4850
+ onClick: (event) => event.stopPropagation(),
4851
+ children
4852
+ });
4853
+ }
4854
+ const defaultLabels$13 = {
4855
+ emptyTitle: "아직 아무것도 없습니다",
4856
+ emptyDescription: "데이터가 도착하면 여기에 나타납니다.",
4857
+ filteredEmptyTitle: "조건에 맞는 항목이 없습니다",
4858
+ filteredEmptyDescription: "필터를 지우면 전체 목록이 보입니다.",
4859
+ clearFilters: "필터 지우기",
4860
+ errorTitle: "목록을 불러오지 못했습니다",
4861
+ retry: "다시 시도"
4862
+ };
4863
+ /**
4864
+ * CatalogFrame — the shape every catalogue list has.
4865
+ *
4866
+ * Two catalogues (events, properties) differ only in their columns and their
4867
+ * words; everything around the table is the same, and writing it twice meant
4868
+ * two copies of the decisions that are easy to get wrong — that a failed read
4869
+ * must not look like an empty list, that an empty list reads differently when a
4870
+ * filter is on, and that a selection must not survive a filter change.
4871
+ *
4872
+ * The last one is enforced here rather than left to the caller. A bulk action
4873
+ * applied to rows the reader can no longer see is the kind of mistake that is
4874
+ * only noticed afterwards.
4875
+ */
4876
+ function CatalogFrame({ children, isEmpty, query, onQueryChange, filters, stats, onStatClick, notice, emptyActions, header, actions, toolbar, inspector, inspectorOpen, onInspectorClose, inspectorTitle, inspectorDescription, inspectorActions, inspectorFooter, inspectorWidth, page = 1, pageSize = 50, totalCount, onPageChange, selectedKeys, onSelectionChange, bulkActions, onBulkAction, error, onRetry, labels: customLabels, className }) {
4877
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$13), customLabels);
4878
+ const lastScope = useRef({
4879
+ query,
4880
+ page
4881
+ });
4882
+ useEffect(() => {
4883
+ const changed = lastScope.current.query !== query || lastScope.current.page !== page;
4884
+ lastScope.current = {
4885
+ query,
4886
+ page
4887
+ };
4888
+ if (changed && selectedKeys && selectedKeys.length > 0) onSelectionChange === null || onSelectionChange === void 0 || onSelectionChange([]);
4889
+ }, [
4890
+ query,
4891
+ page,
4892
+ selectedKeys,
4893
+ onSelectionChange
4894
+ ]);
4895
+ const filtering = !isEmptyQuery(query);
4896
+ const body = error ? /* @__PURE__ */ jsx(EmptyState, {
4897
+ tone: "error",
4898
+ hasBorder: true,
4899
+ title: labels.errorTitle,
4900
+ body: error,
4901
+ actions: onRetry ? /* @__PURE__ */ jsx(Button, {
4902
+ variant: "secondary",
4903
+ onClick: onRetry,
4904
+ children: labels.retry
4905
+ }) : void 0
4906
+ }) : isEmpty ? /* @__PURE__ */ jsx(EmptyState, {
4907
+ tone: "subdued",
4908
+ hasBorder: true,
4909
+ title: filtering ? labels.filteredEmptyTitle : labels.emptyTitle,
4910
+ description: filtering ? labels.filteredEmptyDescription : labels.emptyDescription,
4911
+ actions: filtering ? /* @__PURE__ */ jsx(Button, {
4912
+ variant: "secondary",
4913
+ onClick: () => onQueryChange({ clauses: [] }),
4914
+ children: labels.clearFilters
4915
+ }) : emptyActions
4916
+ }) : children;
4917
+ return /* @__PURE__ */ jsxs("div", {
4918
+ className: cn("flex flex-col gap-section", className),
4919
+ children: [
4920
+ (header || actions) && /* @__PURE__ */ jsxs("div", {
4921
+ className: "gap-group flex min-w-0 flex-col lg:flex-row lg:items-start lg:justify-between",
4922
+ children: [header && /* @__PURE__ */ jsx("div", {
4923
+ className: "min-w-0 flex-1",
4924
+ children: header
4925
+ }), actions && /* @__PURE__ */ jsx("div", {
4926
+ className: "gap-element flex flex-wrap items-center",
4927
+ children: actions
4928
+ })]
4929
+ }),
4930
+ stats && stats.length > 0 && /* @__PURE__ */ jsx(SummaryRow, {
4931
+ stats,
4932
+ onStatClick
4933
+ }),
4934
+ notice,
4935
+ toolbar && /* @__PURE__ */ jsx("div", {
4936
+ className: "gap-group flex flex-wrap items-center",
4937
+ children: toolbar
4938
+ }),
4939
+ filters && filters.length > 0 && /* @__PURE__ */ jsx(QueryFilterBar, {
4940
+ value: query,
4941
+ onChange: onQueryChange,
4942
+ filters,
4943
+ disabled: Boolean(error)
4944
+ }),
4945
+ /* @__PURE__ */ jsx(InspectorLayout, {
4946
+ open: inspectorOpen && Boolean(inspector),
4947
+ onClose: onInspectorClose,
4948
+ inspector,
4949
+ title: inspectorTitle,
4950
+ description: inspectorDescription,
4951
+ actions: inspectorActions,
4952
+ footer: inspectorFooter,
4953
+ width: inspectorWidth,
4954
+ children: /* @__PURE__ */ jsxs("div", {
4955
+ className: "gap-group flex flex-col",
4956
+ children: [body, onPageChange && totalCount != null && totalCount > pageSize && /* @__PURE__ */ jsx(Pagination, {
4957
+ currentPage: page,
4958
+ totalPages: Math.ceil(totalCount / pageSize),
4959
+ onPageChange
4960
+ })]
4961
+ })
4962
+ }),
4963
+ bulkActions && bulkActions.length > 0 && onBulkAction && selectedKeys && selectedKeys.length > 0 && /* @__PURE__ */ jsx(FloatingActionBar, {
4964
+ actions: bulkActions,
4965
+ selectedCount: selectedKeys.length,
4966
+ onAction: onBulkAction,
4967
+ onDismiss: () => onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange([])
4968
+ })
4969
+ ]
4970
+ });
4971
+ }
4972
+ //#endregion
4099
4973
  //#region src/shells/comparison-selector.tsx
4100
4974
  /** Renders the comparison selector component. */
4101
4975
  function ComparisonSelector({ segments, valueA, valueB, onChangeA, onChangeB, values, onValuesChange, maxItems = 5, labels: customLabels, className }) {
@@ -5250,7 +6124,7 @@ function ThemeSwitcher({ className, labels: userLabels, variant = "default", cus
5250
6124
  ThemeSwitcher.displayName = "ThemeSwitcher";
5251
6125
  //#endregion
5252
6126
  //#region src/shells/prompt-template.tsx
5253
- const defaultLabels$11 = {
6127
+ const defaultLabels$12 = {
5254
6128
  copy: "Copy",
5255
6129
  copied: "Copied!",
5256
6130
  copyFailed: "Copy failed"
@@ -5260,7 +6134,7 @@ function renderPrompt(template, values) {
5260
6134
  }
5261
6135
  /** Renders the prompt template component. */
5262
6136
  function PromptTemplate({ title, description, template, variables = [], className, labels: customLabels }) {
5263
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$11), customLabels);
6137
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$12), customLabels);
5264
6138
  const [values, setValues] = React.useState(() => {
5265
6139
  const initial = {};
5266
6140
  for (const v of variables) if (v.defaultValue) initial[v.name] = v.defaultValue;
@@ -5749,14 +6623,14 @@ function AsyncCombobox({ onSearch, debounceMs = 300, loadingText, minChars = 1,
5749
6623
  }
5750
6624
  //#endregion
5751
6625
  //#region src/shells/vertical-tabs.tsx
5752
- const defaultLabels$10 = {
6626
+ const defaultLabels$11 = {
5753
6627
  ariaLabel: "Vertical tabs",
5754
6628
  emptyMessage: "No tabs available"
5755
6629
  };
5756
6630
  /** Renders the vertical tabs component. */
5757
6631
  function VerticalTabs({ tabs, defaultTabId, labels: customLabels, className }) {
5758
6632
  var _tabs$;
5759
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$10), customLabels);
6633
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$11), customLabels);
5760
6634
  if (tabs.length === 0) return /* @__PURE__ */ jsx("div", {
5761
6635
  className: cn("text-text-secondary text-sm", className),
5762
6636
  "data-opt-id": "J81G4",
@@ -5765,6 +6639,7 @@ function VerticalTabs({ tabs, defaultTabId, labels: customLabels, className }) {
5765
6639
  });
5766
6640
  return /* @__PURE__ */ jsx(TabsRoot, {
5767
6641
  defaultSelectedId: defaultTabId !== null && defaultTabId !== void 0 ? defaultTabId : (_tabs$ = tabs[0]) === null || _tabs$ === void 0 ? void 0 : _tabs$.id,
6642
+ orientation: "vertical",
5768
6643
  "data-opt-id": "J81G4",
5769
6644
  "data-opt-slug": "vertical-tabs.VerticalTabs",
5770
6645
  children: /* @__PURE__ */ jsxs("div", {
@@ -5789,13 +6664,13 @@ function VerticalTabs({ tabs, defaultTabId, labels: customLabels, className }) {
5789
6664
  }
5790
6665
  //#endregion
5791
6666
  //#region src/shells/column-toggler.tsx
5792
- const defaultLabels$9 = {
6667
+ const defaultLabels$10 = {
5793
6668
  triggerLabel: (count) => `Columns (${count})`,
5794
6669
  emptyMessage: "No columns available"
5795
6670
  };
5796
6671
  /** Renders the column toggler component. */
5797
6672
  function ColumnToggler({ columns, visibleColumns, onChange, className, labels: customLabels }) {
5798
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$9), customLabels);
6673
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$10), customLabels);
5799
6674
  const visibleCount = visibleColumns.length;
5800
6675
  const hasColumns = columns.length > 0;
5801
6676
  const toggle = (id) => {
@@ -5874,7 +6749,7 @@ function BulkActions({ selectedCount, actions, onAction, onClear, labels: custom
5874
6749
  }
5875
6750
  //#endregion
5876
6751
  //#region src/shells/saved-filters.tsx
5877
- const defaultLabels$8 = {
6752
+ const defaultLabels$9 = {
5878
6753
  triggerLabel: (count) => `Saved Filters (${count})`,
5879
6754
  emptyMessage: "No saved filters",
5880
6755
  deleteLabel: (name) => `Delete ${name}`,
@@ -5885,7 +6760,7 @@ const defaultLabels$8 = {
5885
6760
  };
5886
6761
  /** Renders the saved filters component. */
5887
6762
  function SavedFilters({ currentFilters, presets, onSavePreset, onLoadPreset, onDeletePreset, className, labels: customLabels }) {
5888
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$8), customLabels);
6763
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$9), customLabels);
5889
6764
  const [newName, setNewName] = React.useState("");
5890
6765
  const [pendingDeleteId, setPendingDeleteId] = React.useState(null);
5891
6766
  const triggerId = React.useId();
@@ -6037,7 +6912,7 @@ function SavedFilters({ currentFilters, presets, onSavePreset, onLoadPreset, onD
6037
6912
  }
6038
6913
  //#endregion
6039
6914
  //#region src/shells/notification-center.tsx
6040
- const defaultLabels$7 = {
6915
+ const defaultLabels$8 = {
6041
6916
  triggerLabel: "Notifications",
6042
6917
  unreadSuffix: (count) => `(${count} unread)`,
6043
6918
  title: "Notifications",
@@ -6046,7 +6921,7 @@ const defaultLabels$7 = {
6046
6921
  };
6047
6922
  /** Renders the notification center component. */
6048
6923
  function NotificationCenter({ notifications, onMarkRead, onMarkAllRead, onAction, className, labels: customLabels }) {
6049
- const labels = _objectSpread2(_objectSpread2({}, defaultLabels$7), customLabels);
6924
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$8), customLabels);
6050
6925
  const unreadCount = notifications.filter((n) => !n.read).length;
6051
6926
  return /* @__PURE__ */ jsxs(PopoverRoot, {
6052
6927
  "data-opt-id": "7A0XY",
@@ -6250,9 +7125,29 @@ function AuditLog({ entries, onLoadMore, loading, labels: customLabels, classNam
6250
7125
  AuditLog.displayName = "AuditLog";
6251
7126
  //#endregion
6252
7127
  //#region src/shells/tree-table.tsx
7128
+ const defaultLabels$7 = {
7129
+ ariaLabel: "Tree table",
7130
+ expand: (rowLabel) => `Expand ${rowLabel}`,
7131
+ collapse: (rowLabel) => `Collapse ${rowLabel}`,
7132
+ level: (depth) => `Level ${depth}`
7133
+ };
7134
+ function flattenTree(nodes, expanded, depth = 0, ancestorsVisible = true) {
7135
+ return nodes.flatMap((node) => {
7136
+ var _node$children;
7137
+ const visible = ancestorsVisible;
7138
+ return [{
7139
+ node,
7140
+ depth,
7141
+ visible
7142
+ }, ...flattenTree((_node$children = node.children) !== null && _node$children !== void 0 ? _node$children : [], expanded, depth + 1, visible && expanded.has(node.id))];
7143
+ });
7144
+ }
6253
7145
  /** Renders the tree table component. */
6254
- function TreeTable({ data, columns, defaultExpanded = [], indentSize = 24, className }) {
7146
+ function TreeTable({ data, columns, defaultExpanded = [], indentSize = 24, getRowLabel, labels: customLabels, className, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy }) {
6255
7147
  const [expanded, setExpanded] = React.useState(() => new Set(defaultExpanded));
7148
+ const baseId = React.useId();
7149
+ const labels = _objectSpread2(_objectSpread2({}, defaultLabels$7), customLabels);
7150
+ const rows = flattenTree(data, expanded);
6256
7151
  const toggle = (id) => {
6257
7152
  setExpanded((prev) => {
6258
7153
  const next = new Set(prev);
@@ -6266,46 +7161,82 @@ function TreeTable({ data, columns, defaultExpanded = [], indentSize = 24, class
6266
7161
  if (typeof col.accessor === "function") return col.accessor(row);
6267
7162
  return String((_row$col$accessor = row[col.accessor]) !== null && _row$col$accessor !== void 0 ? _row$col$accessor : "");
6268
7163
  };
6269
- const renderRows = (nodes, depth) => nodes.flatMap((node) => {
6270
- const hasChildren = node.children && node.children.length > 0;
6271
- const isExpanded = expanded.has(node.id);
6272
- return [/* @__PURE__ */ jsx("tr", {
6273
- className: "border-border border-b",
6274
- children: columns.map((col, ci) => /* @__PURE__ */ jsx("td", {
6275
- className: cn(OPT_TD),
6276
- children: /* @__PURE__ */ jsxs("div", {
6277
- className: "flex items-center",
6278
- style: ci === 0 ? { paddingLeft: depth * indentSize } : void 0,
6279
- children: [
6280
- ci === 0 && hasChildren && /* @__PURE__ */ jsx("button", {
6281
- type: "button",
6282
- onClick: () => toggle(node.id),
6283
- className: cn("mr-1 flex h-5 w-5 items-center justify-center rounded text-xs", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset"),
6284
- "aria-expanded": isExpanded,
6285
- "aria-label": isExpanded ? "Collapse" : "Expand",
6286
- children: isExpanded ? "▼" : "▶"
6287
- }),
6288
- ci === 0 && !hasChildren && /* @__PURE__ */ jsx("span", { className: "mr-1 inline-block w-5" }),
6289
- getCellValue(node.data, col)
6290
- ]
6291
- })
6292
- }, col.id))
6293
- }, node.id), ...isExpanded && hasChildren ? renderRows(node.children, depth + 1) : []];
6294
- });
7164
+ const rowId = (id) => `${baseId}-row-${encodeURIComponent(id)}`;
7165
+ const resolveRowLabel = (node) => {
7166
+ if (getRowLabel) return getRowLabel(node);
7167
+ const firstColumn = columns[0];
7168
+ if (firstColumn) {
7169
+ const value = getCellValue(node.data, firstColumn);
7170
+ if (typeof value === "string" || typeof value === "number") return String(value);
7171
+ }
7172
+ return node.id;
7173
+ };
6295
7174
  return /* @__PURE__ */ jsx("div", {
6296
7175
  className: cn("overflow-auto", className),
6297
- "data-opt-id": "EJRTW",
7176
+ "data-opt-id": "PP194",
6298
7177
  "data-opt-slug": "tree-table.TreeTable",
6299
7178
  children: /* @__PURE__ */ jsxs("table", {
6300
7179
  className: cn("w-full border-collapse", OPT_BORDER),
7180
+ "aria-label": ariaLabelledBy == null ? ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : labels.ariaLabel : void 0,
7181
+ "aria-labelledby": ariaLabelledBy,
6301
7182
  children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", {
6302
7183
  className: "border-border border-b",
6303
7184
  children: columns.map((col) => /* @__PURE__ */ jsx("th", {
7185
+ scope: "col",
6304
7186
  className: cn(OPT_TH),
6305
7187
  style: { width: col.width },
6306
7188
  children: col.header
6307
7189
  }, col.id))
6308
- }) }), /* @__PURE__ */ jsx("tbody", { children: renderRows(data, 0) })]
7190
+ }) }), /* @__PURE__ */ jsx("tbody", { children: rows.map(({ node, depth, visible }) => {
7191
+ var _node$children$length, _node$children2, _node$children3;
7192
+ const hasChildren = ((_node$children$length = (_node$children2 = node.children) === null || _node$children2 === void 0 ? void 0 : _node$children2.length) !== null && _node$children$length !== void 0 ? _node$children$length : 0) > 0;
7193
+ const isExpanded = expanded.has(node.id);
7194
+ const resolvedRowLabel = resolveRowLabel(node);
7195
+ const controlledRows = ((_node$children3 = node.children) !== null && _node$children3 !== void 0 ? _node$children3 : []).map((child) => rowId(child.id)).join(" ");
7196
+ return /* @__PURE__ */ jsx("tr", {
7197
+ id: rowId(node.id),
7198
+ hidden: !visible,
7199
+ className: "border-border border-b",
7200
+ children: columns.map((col, columnIndex) => {
7201
+ const content = /* @__PURE__ */ jsxs("div", {
7202
+ className: "flex items-center",
7203
+ style: columnIndex === 0 ? { paddingLeft: depth * indentSize } : void 0,
7204
+ children: [
7205
+ columnIndex === 0 && hasChildren && /* @__PURE__ */ jsx("button", {
7206
+ type: "button",
7207
+ onClick: () => toggle(node.id),
7208
+ className: cn("mr-1 flex h-5 w-5 items-center justify-center rounded text-xs", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset"),
7209
+ "aria-expanded": isExpanded,
7210
+ "aria-controls": controlledRows || void 0,
7211
+ "aria-label": isExpanded ? labels.collapse(resolvedRowLabel) : labels.expand(resolvedRowLabel),
7212
+ children: /* @__PURE__ */ jsx("span", {
7213
+ "aria-hidden": "true",
7214
+ children: isExpanded ? "▼" : "▶"
7215
+ })
7216
+ }),
7217
+ columnIndex === 0 && !hasChildren && /* @__PURE__ */ jsx("span", { className: "mr-1 inline-block w-5" }),
7218
+ columnIndex === 0 && /* @__PURE__ */ jsxs("span", {
7219
+ className: "sr-only",
7220
+ children: [
7221
+ labels.level(depth + 1),
7222
+ ".",
7223
+ " "
7224
+ ]
7225
+ }),
7226
+ getCellValue(node.data, col)
7227
+ ]
7228
+ });
7229
+ return columnIndex === 0 ? /* @__PURE__ */ jsx("th", {
7230
+ scope: "row",
7231
+ className: cn(OPT_TD),
7232
+ children: content
7233
+ }, col.id) : /* @__PURE__ */ jsx("td", {
7234
+ className: cn(OPT_TD),
7235
+ children: content
7236
+ }, col.id);
7237
+ })
7238
+ }, node.id);
7239
+ }) })]
6309
7240
  })
6310
7241
  });
6311
7242
  }
@@ -7047,17 +7978,37 @@ function DataImportWizard({ fields, onImport, acceptedFormats = ".csv", labels:
7047
7978
  //#endregion
7048
7979
  //#region src/shells/mega-menu.tsx
7049
7980
  const defaultLabels$3 = { trigger: "Menu" };
7981
+ function MegaMenuItemContent({ item }) {
7982
+ return /* @__PURE__ */ jsxs(Fragment, { children: [item.icon && /* @__PURE__ */ jsx("span", {
7983
+ "aria-hidden": "true",
7984
+ className: "text-text-secondary mt-0.5 flex-shrink-0",
7985
+ children: item.icon
7986
+ }), /* @__PURE__ */ jsxs("span", {
7987
+ className: "flex flex-col text-left",
7988
+ children: [/* @__PURE__ */ jsx("span", {
7989
+ className: "text-text-primary text-sm font-medium",
7990
+ children: item.label
7991
+ }), item.description && /* @__PURE__ */ jsx("span", {
7992
+ className: "text-text-tertiary text-xs",
7993
+ children: item.description
7994
+ })]
7995
+ })] });
7996
+ }
7050
7997
  /** Renders the mega menu component. */
7051
- function MegaMenu({ menus, columns = 3, footer, triggerLabel, labels: customLabels, className }) {
7998
+ function MegaMenu({ menus, columns = 3, footer, triggerLabel, labels: customLabels, className, "aria-label": ariaLabel }) {
7999
+ var _ref;
7052
8000
  const labels = _objectSpread2(_objectSpread2({}, defaultLabels$3), customLabels);
7053
8001
  const resolvedTriggerLabel = triggerLabel !== null && triggerLabel !== void 0 ? triggerLabel : labels.trigger;
8002
+ const navigationLabel = (_ref = ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : labels.navigation) !== null && _ref !== void 0 ? _ref : `${resolvedTriggerLabel} navigation`;
8003
+ const itemClassName = "hover:bg-bg-subtle gap-element flex w-full items-start rounded-md p-2 transition-colors";
7054
8004
  if (menus.length === 0) return null;
7055
8005
  return /* @__PURE__ */ jsxs(PopoverRoot, {
7056
- "data-opt-id": "42177",
8006
+ "data-opt-id": "AHTK9",
7057
8007
  "data-opt-slug": "mega-menu.MegaMenu",
7058
8008
  children: [/* @__PURE__ */ jsxs(PopoverTrigger, {
7059
8009
  className: cn("border-border bg-surface text-text-primary hover:bg-bg-subtle inline-flex h-9 items-center gap-1.5 rounded-lg border px-3 text-sm font-medium", className),
7060
8010
  children: [resolvedTriggerLabel, /* @__PURE__ */ jsx("svg", {
8011
+ "aria-hidden": "true",
7061
8012
  width: "12",
7062
8013
  height: "12",
7063
8014
  viewBox: "0 0 12 12",
@@ -7066,38 +8017,41 @@ function MegaMenu({ menus, columns = 3, footer, triggerLabel, labels: customLabe
7066
8017
  strokeWidth: "1.5",
7067
8018
  children: /* @__PURE__ */ jsx("path", { d: "M3 5l3 3 3-3" })
7068
8019
  })]
7069
- }), /* @__PURE__ */ jsxs(PopoverContent, {
8020
+ }), /* @__PURE__ */ jsx(PopoverContent, {
7070
8021
  className: "w-auto max-w-2xl p-0",
7071
- children: [/* @__PURE__ */ jsx("div", {
7072
- className: "gap-group grid p-4",
7073
- style: { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` },
7074
- children: menus.map((section) => /* @__PURE__ */ jsxs("div", {
7075
- className: "gap-element flex flex-col",
7076
- children: [/* @__PURE__ */ jsx("h4", {
7077
- className: "text-text-tertiary text-xs font-semibold tracking-wider uppercase",
7078
- children: section.title
7079
- }), section.items.map((item) => /* @__PURE__ */ jsxs("a", {
7080
- href: item.href || "#",
7081
- className: "hover:bg-bg-subtle gap-element flex items-start rounded-md p-2 transition-colors",
7082
- children: [item.icon && /* @__PURE__ */ jsx("span", {
7083
- className: "text-text-secondary mt-0.5 flex-shrink-0",
7084
- children: item.icon
7085
- }), /* @__PURE__ */ jsxs("div", {
7086
- className: "flex flex-col",
7087
- children: [/* @__PURE__ */ jsx("span", {
7088
- className: "text-text-primary text-sm font-medium",
7089
- children: item.label
7090
- }), item.description && /* @__PURE__ */ jsx("span", {
7091
- className: "text-text-tertiary text-xs",
7092
- children: item.description
7093
- })]
8022
+ children: /* @__PURE__ */ jsxs("nav", {
8023
+ "aria-label": navigationLabel,
8024
+ children: [/* @__PURE__ */ jsx("div", {
8025
+ className: "gap-group grid p-4",
8026
+ style: { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` },
8027
+ children: menus.map((section) => /* @__PURE__ */ jsxs("div", {
8028
+ className: "gap-element flex flex-col",
8029
+ children: [/* @__PURE__ */ jsx("h4", {
8030
+ className: "text-text-tertiary text-xs font-semibold tracking-wider uppercase",
8031
+ children: section.title
8032
+ }), section.items.map((item) => {
8033
+ if (item.href != null) return /* @__PURE__ */ jsx("a", {
8034
+ href: item.href,
8035
+ className: itemClassName,
8036
+ children: /* @__PURE__ */ jsx(MegaMenuItemContent, { item })
8037
+ }, item.label);
8038
+ if (item.onSelect) return /* @__PURE__ */ jsx(PopoverClose, {
8039
+ onClick: item.onSelect,
8040
+ className: itemClassName,
8041
+ children: /* @__PURE__ */ jsx(MegaMenuItemContent, { item })
8042
+ }, item.label);
8043
+ return /* @__PURE__ */ jsx("span", {
8044
+ "aria-disabled": "true",
8045
+ className: cn(itemClassName, "cursor-not-allowed opacity-60"),
8046
+ children: /* @__PURE__ */ jsx(MegaMenuItemContent, { item })
8047
+ }, item.label);
7094
8048
  })]
7095
- }, item.label))]
7096
- }, section.title))
7097
- }), footer && /* @__PURE__ */ jsx("div", {
7098
- className: "border-border bg-bg-subtle border-t px-4 py-3",
7099
- children: footer
7100
- })]
8049
+ }, section.title))
8050
+ }), footer && /* @__PURE__ */ jsx("div", {
8051
+ className: "border-border bg-bg-subtle border-t px-4 py-3",
8052
+ children: footer
8053
+ })]
8054
+ })
7101
8055
  })]
7102
8056
  });
7103
8057
  }
@@ -8295,67 +9249,4 @@ const enStarRatingLabels = {
8295
9249
  };
8296
9250
  const enBreadcrumbLabels = { navAriaLabel: "Go to {label}" };
8297
9251
  //#endregion
8298
- //#region src/lib/query/query-match.ts
8299
- function toText(value) {
8300
- if (value === null || value === void 0) return "";
8301
- if (typeof value === "string") return value;
8302
- if (typeof value === "number" || typeof value === "boolean") return String(value);
8303
- return JSON.stringify(value);
8304
- }
8305
- function compare(left, right) {
8306
- const leftNumber = typeof left === "number" ? left : Number(toText(left));
8307
- const rightNumber = Number(right);
8308
- if (Number.isFinite(leftNumber) && Number.isFinite(rightNumber)) return leftNumber - rightNumber;
8309
- return toText(left).localeCompare(right);
8310
- }
8311
- function matchesClause(clause, read, searchable) {
8312
- if (clause.type === "term") return searchable().toLowerCase().includes(clause.value.toLowerCase());
8313
- const value = read(clause.field);
8314
- switch (clause.operator) {
8315
- case "exists": return value !== void 0 && value !== null && value !== "";
8316
- case "eq": return clause.values.some((candidate) => toText(value).toLowerCase() === candidate.toLowerCase());
8317
- case "contains": return clause.values.some((candidate) => toText(value).toLowerCase().includes(candidate.toLowerCase()));
8318
- case "gt":
8319
- var _clause$values$;
8320
- return compare(value, (_clause$values$ = clause.values[0]) !== null && _clause$values$ !== void 0 ? _clause$values$ : "") > 0;
8321
- case "gte":
8322
- var _clause$values$2;
8323
- return compare(value, (_clause$values$2 = clause.values[0]) !== null && _clause$values$2 !== void 0 ? _clause$values$2 : "") >= 0;
8324
- case "lt":
8325
- var _clause$values$3;
8326
- return compare(value, (_clause$values$3 = clause.values[0]) !== null && _clause$values$3 !== void 0 ? _clause$values$3 : "") < 0;
8327
- case "lte":
8328
- var _clause$values$4;
8329
- return compare(value, (_clause$values$4 = clause.values[0]) !== null && _clause$values$4 !== void 0 ? _clause$values$4 : "") <= 0;
8330
- default: return true;
8331
- }
8332
- }
8333
- /**
8334
- * Whether one row satisfies every clause.
8335
- *
8336
- * `searchable` is lazy because most queries are field constraints, and
8337
- * flattening a row to text for a term match nobody asked for is the expensive
8338
- * part of filtering a live tail.
8339
- */
8340
- function matchesQuery(query, read, searchable) {
8341
- return query.clauses.every((clause) => {
8342
- const matched = matchesClause(clause, read, searchable);
8343
- return clause.negated ? !matched : matched;
8344
- });
8345
- }
8346
- /** Convenience for plain objects, including one level of nested properties. */
8347
- function matchesQueryObject(query, row, options = {}) {
8348
- const nested = options.nested ? row[options.nested] : void 0;
8349
- const read = (field) => field in row ? row[field] : nested === null || nested === void 0 ? void 0 : nested[field];
8350
- let cached = null;
8351
- const searchable = () => {
8352
- var _cached;
8353
- (_cached = cached) !== null && _cached !== void 0 || (cached = [...Object.values(row).filter((value) => typeof value !== "object"), ...Object.values(nested !== null && nested !== void 0 ? nested : {})].map(toText).join(" "));
8354
- return cached;
8355
- };
8356
- return matchesQuery(query, read, searchable);
8357
- }
8358
- //#endregion
8359
- export { ALL_COMPOUND_THEMES, AccordionContent, AccordionItem, AccordionRoot, AccordionTrigger, ActivityFeed, Alert, AlertBuilder, AlertDialogPanel, AppMenubar, AppShell, AsyncCombobox, AuditLog, AuditTimeline, AuthForm, Avatar, AvatarGroup, Badge, BlockLayout, BlockLayout as SurfaceLayout, BranchSelect, Breadcrumb, BulkActions, Button, COLOR_PRESETS, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ChatInput, ChatMessageList, ChatSidebar, Checkbox, CheckboxGroup, CircularProgress, CodeDiffViewer, CodeSnippetViewer, ColorPaletteDisplay, ColorPalettePicker, ColorPicker, ColumnToggler, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxPopover, ComboboxRoot, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandPalette, CommandPaletteTrigger, CommandSeparator, CommandShortcut, ComparisonSelector, Composite, CompositeItem, CompositeProvider, CompositeRow, CompositeZone, ConditionBuilder, ConfirmDialog, ConnectionIndicator, Container, ContentTabs, DEFAULT_PRESETS, DEFAULT_TIME_PRESETS, DashboardGrid, DataImportWizard, DataTable, DateRangePicker, DeploymentTimeline, DescriptionList, DesignGuidePanel, DialogBody, DialogDescription, DialogDisclosure, DialogDismiss, DialogFooter, DialogHeader, DialogHeading, DialogPanel, DialogRoot, DisclosureContent, DisclosureRoot, DisclosureTrigger, DomainTable, DrawerClose, DrawerPanel, DrawerRoot, DropdownContent, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger, DynamicFieldForm, EMPTY_QUERY, EditorToolbar, EmptyState, EnvPanel, ErrorBoundary, EventIcon, EventMetaEditor, EventSparkline, EventTimeline, ExportButton, Expression, ExpressionGroup, FIELD_TYPE_TOKENS, FORCE_LIGHT_PRESETS, FORCE_LIGHT_PRESET_IDS, Facet, FacetGroup, FailureList, FaqAccordion, FeatureFlagPanel, FieldSidebar, FieldToken, FileUploadForm, FilterBar, FloatingActionBar, Flyout, FormCheckbox, FormColorPicker, FormControl, FormDateRangePicker, FormDescription, FormError, FormField, FormGroup, FormGroupLabel, FormIconPicker, FormInput, FormLabel, FormNumberInput, FormProvider, FormPush, FormRadio, FormRadioGroup, FormRemove, FormReset, FormRoot, FormSelect, FormSelectItem, FormSelectPopover, FormSlider, FormStarRating, FormSubmit, FormSwitch, FormTagInput, FormTextarea, GENERATED_THEME_ID_DEFAULT, GLOBAL_THEME_STYLE_ID, Heading, Highlight, IconPicker, Identity, InlineEdit, InlineEditTable, Input, InsightsPanel, KanbanBoard, Kbd, KeyPadMenu, KeyValueEditor, LiveRegion, LoadingOverlay, LogTable, Logo, MegaMenu, MenuButtonArrow, MenuItem, MenuItemCheckbox, MenuItemRadio, MenuPopover, MenuRoot, MenuSeparator, MenuTrigger, MenubarContainer, MenubarRoot, Meter, MetricsCard, NotificationCenter, NotificationToast, NumberInput, OPT_TEXT_PRIMARY, OPT_TEXT_SECONDARY, OptThemeControllerContext, OptThemeProvider, OtpField, POPULAR_ICONS, PageAside, PageHeader, Pagination, PopoverClose, PopoverContent, PopoverRoot, PopoverTrigger, Progress, ProjectSwitcher, PromptTemplate, PropertyExplorer, QueryBar, QueryResultsTable, QuickActions, Radio, RadioGroup, ReportBuilder, ReportWidget, ResizableHandle, ResizablePanel, ResizablePanelGroup, RichTextEditor, RouteFocusManager, SHADER_OVERLAY_PARAM_KEYS, SHADER_PARAM_FALLBACK, SHADER_PARAM_KEYS, SHADER_PRESETS, SHADER_PRESET_IDS, SavedFilters, ScoreBreakdown, ScrollArea, SearchCombobox, Section, SegmentBuilder, SelectItem, SelectLabel, SelectPopover, SelectRoot, SelectTrigger, Separator, SettingsForm, ShaderSurface, Sidebar, SidebarNav, Skeleton, SkeletonAvatar, SkeletonCard, SkeletonTable, SkeletonText, Slider, SpatialNavProvider, Spinner, SqlEditor, StarRating, StatCard, StatusSelect, StepBuilder, SummaryRow, Switch, THEME_PALETTES, THEME_PRESET_IDS, THEME_REGISTRY, THEME_SPEC_STORAGE_KEY, THEME_TOKENS_STORAGE_KEY, Tab, TabList, TabPanel, TabsRoot, TagInput, TaskList, TeamMemberList, TemplatePicker, Text, TextTruncate, Textarea, ThemeSwitcher, TimeRangeControl, TimeRangeSelector, TimeSeriesPanel, ToastProvider, Toggle, ToggleGroup, ToolbarButton, ToolbarContainer, ToolbarRoot, ToolbarSeparator, Tooltip, TooltipAnchor, TooltipProvider, TreeTable, TrendChart, VerticalTabs, VirtualList, WebhookConfig, WidgetGrid, WizardForm, WorkflowCanvas, addClause, applyCellAction, buildTokenCache, cn, coerceThemeMode, computeGeneratedTokens, computeSpatialTargets, createBlock, createBlock as createSurface, createThemeBootScript, defineThemeOverrides, describeClause, enBreadcrumbLabels, enComboboxLabels, enStarRatingLabels, fieldValues, formatClause, formatOptDateTime, formatOptNumber, formatOptShortDate, formatOptTime, formatQuery, generatedTheme, getCompoundIdForSpec, getCompoundTheme, getShaderFragment, getShaderPreset, getThemeDescriptor, getTrappedContextRole, isDescriptorSpec, isEmptyQuery, isForceLightSpec, isGeneratedSpec, isPresetSpec, isThemePresetId, koBreadcrumbLabels, koComboboxLabels, koStarRatingLabels, matchesQuery, matchesQueryObject, parseQuery, parseQueryWithDiagnostics, presetTheme, queryFields, quoteValue, readStoredTheme, removeClause, resolveDescriptor, resolveFieldType, resolveThemeMode, safeParseStoredSpec, safeParseStoredTokens, schemaValidator, serializeGeneratedTheme, serializeThemeRule, serializeTokenBody, shouldSkipArrow, toast, useAutoRefresh, useControlledState, useFieldValue, useFormContext, useFormStore, useInputId, useOptTheme, useOptThemeController, useOptionalOptTheme, useSidebar, useToast, withFieldValue, withoutField };
8360
-
8361
- //# sourceMappingURL=index.js.map
9252
+ export { ALL_COMPOUND_THEMES, AccordionContent, AccordionItem, AccordionRoot, AccordionTrigger, ActivityFeed, Alert, AlertBuilder, AlertDialogPanel, AppMenubar, AppShell, AsyncCombobox, AuditLog, AuditTimeline, AuthForm, Avatar, AvatarGroup, Badge, BlockLayout, BlockLayout as SurfaceLayout, BranchSelect, Breadcrumb, BulkActions, Button, COLOR_PRESETS, Callout, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CatalogCellControls, CatalogFrame, CatalogRowActions, ChatInput, ChatMessageList, ChatSidebar, Checkbox, CheckboxGroup, CircularProgress, CodeDiffViewer, CodeSnippetViewer, ColorPaletteDisplay, ColorPalettePicker, ColorPicker, ColumnToggler, ComboboxEmpty, ComboboxGroup, ComboboxGroupLabel, ComboboxInput, ComboboxItem, ComboboxPopover, ComboboxRoot, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandPalette, CommandPaletteTrigger, CommandSeparator, CommandShortcut, ComparisonSelector, Composite, CompositeItem, CompositeProvider, CompositeRow, CompositeZone, ConditionBuilder, ConfirmDialog, ConnectionIndicator, Container, ContentTabs, CopyButton, DEFAULT_PRESETS, DEFAULT_TIME_PRESETS, DashboardGrid, DataImportWizard, DataTable, DateRangePicker, DeploymentTimeline, DescriptionList, DesignGuidePanel, DialogBody, DialogDescription, DialogDisclosure, DialogDismiss, DialogFooter, DialogHeader, DialogHeading, DialogPanel, DialogRoot, DisclosureContent, DisclosureRoot, DisclosureTrigger, DomainTable, DrawerClose, DrawerPanel, DrawerRoot, DropdownContent, DropdownItem, DropdownMenu, DropdownSeparator, DropdownTrigger, DynamicFieldForm, EMPTY_QUERY, EditorToolbar, EmptyState, EnvPanel, ErrorBoundary, EventIcon, EventMetaEditor, EventSparkline, EventTimeline, ExportButton, Expression, ExpressionGroup, FIELD_TYPE_TOKENS, FORCE_LIGHT_PRESETS, FORCE_LIGHT_PRESET_IDS, Facet, FacetGroup, FailureList, FaqAccordion, FeatureFlagPanel, FieldSidebar, FieldToken, FieldTokenLegend, FileUploadForm, FilterBar, FloatingActionBar, Flyout, FormCheckbox, FormColorPicker, FormControl, FormDateRangePicker, FormDescription, FormError, FormField, FormGroup, FormGroupLabel, FormIconPicker, FormInput, FormLabel, FormNumberInput, FormProvider, FormPush, FormRadio, FormRadioGroup, FormRemove, FormReset, FormRoot, FormSelect, FormSelectItem, FormSelectPopover, FormSlider, FormStarRating, FormSubmit, FormSwitch, FormTagInput, FormTextarea, GENERATED_THEME_ID_DEFAULT, GLOBAL_THEME_STYLE_ID, Heading, Highlight, IconPicker, Identity, InlineEdit, InlineEditTable, Input, InsightsPanel, InspectorLayout, KanbanBoard, Kbd, KeyPadMenu, KeyValueEditor, LiveRegion, LoadingOverlay, LogTable, Logo, MegaMenu, MenuButtonArrow, MenuItem, MenuItemCheckbox, MenuItemRadio, MenuPopover, MenuRoot, MenuSeparator, MenuTrigger, MenubarContainer, MenubarRoot, Meter, MetricsCard, NotificationCenter, NotificationToast, NumberInput, OPT_TEXT_PRIMARY, OPT_TEXT_SECONDARY, OptThemeControllerContext, OptThemeProvider, OtpField, POPULAR_ICONS, PageAside, PageHeader, Pagination, PopoverClose, PopoverContent, PopoverRoot, PopoverTrigger, Progress, ProjectSwitcher, PromptTemplate, PropertyExplorer, QueryBar, QueryFilterBar, QueryResultsTable, QuickActions, Radio, RadioGroup, ReportBuilder, ReportWidget, ResizableHandle, ResizablePanel, ResizablePanelGroup, RichTextEditor, RouteFocusManager, SHADER_OVERLAY_PARAM_KEYS, SHADER_PARAM_FALLBACK, SHADER_PARAM_KEYS, SHADER_PRESETS, SHADER_PRESET_IDS, SavedFilters, ScoreBreakdown, ScrollArea, SearchCombobox, Section, SegmentBuilder, SegmentedControl, SelectItem, SelectLabel, SelectPopover, SelectRoot, SelectTrigger, Separator, SettingsForm, ShaderSurface, Sidebar, SidebarNav, Skeleton, SkeletonAvatar, SkeletonCard, SkeletonTable, SkeletonText, Slider, SpatialNavProvider, Spinner, SqlEditor, StarRating, StatCard, StatusDot, StatusSelect, StepBuilder, SummaryRow, Switch, THEME_PALETTES, THEME_PRESET_IDS, THEME_REGISTRY, THEME_SPEC_STORAGE_KEY, THEME_TOKENS_STORAGE_KEY, Tab, TabList, TabPanel, TabsRoot, TagInput, TaskList, TeamMemberList, TemplatePicker, Text, TextTruncate, Textarea, ThemeSwitcher, TimeRangeControl, TimeRangeSelector, TimeSeriesPanel, ToastProvider, Toggle, ToggleGroup, ToolbarButton, ToolbarContainer, ToolbarRoot, ToolbarSeparator, Tooltip, TooltipAnchor, TooltipProvider, TreeTable, TrendChart, VerticalTabs, VirtualList, WebhookConfig, WidgetGrid, WizardForm, WorkflowCanvas, addClause, applyCellAction, buildTokenCache, cn, coerceThemeMode, computeGeneratedTokens, computeSpatialTargets, createBlock, createBlock as createSurface, createThemeBootScript, defineThemeOverrides, describeClause, enBreadcrumbLabels, enComboboxLabels, enStarRatingLabels, fieldValues, formatClause, formatOptDateTime, formatOptNumber, formatOptShortDate, formatOptTime, formatQuery, generatedTheme, getCompoundIdForSpec, getCompoundTheme, getShaderFragment, getShaderPreset, getThemeDescriptor, getTrappedContextRole, hasActiveQuery, isDescriptorSpec, isEmptyQuery, isForceLightSpec, isGeneratedSpec, isPresetSpec, isThemePresetId, koBreadcrumbLabels, koComboboxLabels, koStarRatingLabels, matchesQuery, matchesQueryObject, parseQuery, parseQueryWithDiagnostics, presetTheme, queryFields, quoteValue, readStoredTheme, removeClause, resolveDescriptor, resolveFieldType, resolveThemeMode, safeParseStoredSpec, safeParseStoredTokens, schemaValidator, serializeGeneratedTheme, serializeThemeRule, serializeTokenBody, shouldSkipArrow, toast, useAutoRefresh, useControlledState, useFieldValue, useFormContext, useFormStore, useInputId, useOptTheme, useOptThemeController, useOptionalOptTheme, useSidebar, useToast, withFieldValue, withoutField };