@reopt-ai/opt-ui 1.12.5 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +236 -0
- package/COMPONENT_CATALOG.md +670 -123
- package/README.md +9 -7
- package/dist/core/index.cjs +13 -13
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +2 -2
- package/dist/docs/02-components/01-core.md +260 -61
- package/dist/docs/02-components/02-visuals.md +1 -1
- package/dist/docs/02-components/03-shells.md +431 -63
- package/dist/docs/02-components/04-surfaces.md +1 -1
- package/dist/docs/02-components/index.md +4 -4
- package/dist/{field-sidebar-YaWHfLLW.d.ts → field-sidebar-CJ4HxP8D.d.cts} +824 -2
- package/dist/{field-sidebar-Ct8c9L4V.d.cts → field-sidebar-DnhpcT2A.d.ts} +824 -2
- package/dist/{field-sidebar-DwtrYSSt.cjs → field-sidebar-ePqFX6MN.cjs} +4339 -244
- package/dist/{field-sidebar-Ben7MQD4.js → field-sidebar-mSVCMAZp.js} +3976 -235
- package/dist/id-registry.cjs +80 -0
- package/dist/id-registry.js +80 -0
- package/dist/id-registry.json +170 -0
- package/dist/index.cjs +1096 -1476
- package/dist/index.d.cts +243 -92
- package/dist/index.d.ts +243 -92
- package/dist/index.js +1004 -1415
- package/dist/{key-pad-menu-BpQebDyw.cjs → key-pad-menu-BgtSL3xe.cjs} +60 -487
- package/dist/{key-pad-menu-CYYtS_Tl.js → key-pad-menu-CqFI6la9.js} +61 -422
- package/dist/{key-pad-menu-CwcY_Vps.d.cts → key-pad-menu-D6pYzaj-.d.cts} +14 -56
- package/dist/{key-pad-menu-WBJShCJn.d.ts → key-pad-menu-Yh7Fpb8m.d.ts} +14 -56
- package/dist/meta.cjs +1312 -12
- package/dist/meta.js +1312 -12
- package/dist/shells/index.cjs +20 -1
- package/dist/shells/index.d.cts +2 -2
- package/dist/shells/index.d.ts +2 -2
- package/dist/shells/index.js +2 -2
- package/dist/{text-truncate-CQyfUZvq.d.cts → text-truncate-Bbul-jMD.d.cts} +52 -30
- package/dist/{text-truncate-CQyfUZvq.d.ts → text-truncate-Bbul-jMD.d.ts} +52 -30
- package/dist/{text-truncate-Dlm7JwDf.js → text-truncate-Bd-0WkSP.js} +461 -97
- package/dist/{text-truncate-CqdiQuj8.cjs → text-truncate-BeYW6XZu.cjs} +523 -99
- package/dist/theme/server.cjs +2 -2
- package/dist/theme/server.d.cts +2 -2
- package/dist/theme/server.d.ts +2 -2
- package/dist/theme/server.js +2 -2
- package/package.json +6 -2
package/dist/index.cjs
CHANGED
|
@@ -1,114 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const require_text_truncate = require("./text-truncate-
|
|
4
|
-
const require_key_pad_menu = require("./key-pad-menu-
|
|
5
|
-
const require_field_sidebar = require("./field-sidebar-
|
|
3
|
+
const require_text_truncate = require("./text-truncate-BeYW6XZu.cjs");
|
|
4
|
+
const require_key_pad_menu = require("./key-pad-menu-BgtSL3xe.cjs");
|
|
5
|
+
const require_field_sidebar = require("./field-sidebar-ePqFX6MN.cjs");
|
|
6
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
7
|
let react = require("react");
|
|
8
8
|
react = require_text_truncate.__toESM(react, 1);
|
|
9
|
-
let _reopt_ai_opt_ui_primitives = require("@reopt-ai/opt-ui-primitives");
|
|
10
9
|
let lucide_react = require("lucide-react");
|
|
11
|
-
let _reopt_ai_opt_palette = require("@reopt-ai/opt-palette");
|
|
12
10
|
let _reopt_ai_opt_charts = require("@reopt-ai/opt-charts");
|
|
13
11
|
let match_sorter = require("match-sorter");
|
|
14
12
|
let next_navigation = require("next/navigation");
|
|
15
|
-
|
|
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: lucide_react.Info,
|
|
48
|
-
success: lucide_react.CircleCheck,
|
|
49
|
-
warning: lucide_react.TriangleAlert,
|
|
50
|
-
danger: lucide_react.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 = require_text_truncate._objectWithoutProperties(_ref, _excluded$2);
|
|
80
|
-
const DefaultIcon = defaultIcons[tone];
|
|
81
|
-
const glyph = icon === void 0 ? DefaultIcon ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultIcon, { "aria-hidden": "true" }) : null : icon;
|
|
82
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({
|
|
83
|
-
role: "status",
|
|
84
|
-
className: require_text_truncate.cn("flex items-start rounded-lg border", toneStyles[tone], sizeStyles$3[size], className)
|
|
85
|
-
}, props), {}, {
|
|
86
|
-
"data-opt-id": "AT7TX",
|
|
87
|
-
"data-opt-slug": "callout.Callout",
|
|
88
|
-
"data-tone": tone,
|
|
89
|
-
children: [
|
|
90
|
-
glyph && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
91
|
-
className: require_text_truncate.cn("mt-0.5 shrink-0", iconTone[tone]),
|
|
92
|
-
children: glyph
|
|
93
|
-
}),
|
|
94
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
95
|
-
className: "min-w-0 flex-1",
|
|
96
|
-
children: [title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
97
|
-
className: require_text_truncate.cn("font-medium", titleTone[tone]),
|
|
98
|
-
children: title
|
|
99
|
-
}), children && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
100
|
-
className: require_text_truncate.cn("text-text-secondary", title && "mt-1"),
|
|
101
|
-
children
|
|
102
|
-
})]
|
|
103
|
-
}),
|
|
104
|
-
action && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
105
|
-
className: "shrink-0 self-center",
|
|
106
|
-
children: action
|
|
107
|
-
})
|
|
108
|
-
]
|
|
109
|
-
}));
|
|
110
|
-
}
|
|
111
|
-
//#endregion
|
|
13
|
+
let _reopt_ai_opt_ui_primitives = require("@reopt-ai/opt-ui-primitives");
|
|
112
14
|
//#region src/core/status-dot.tsx
|
|
113
15
|
const _excluded$1 = [
|
|
114
16
|
"tone",
|
|
@@ -133,7 +35,7 @@ const textTone = {
|
|
|
133
35
|
warning: "text-text-secondary",
|
|
134
36
|
danger: "text-text-secondary"
|
|
135
37
|
};
|
|
136
|
-
const sizeStyles$
|
|
38
|
+
const sizeStyles$1 = {
|
|
137
39
|
sm: "gap-1.5 text-[11px]",
|
|
138
40
|
md: "gap-2 text-xs"
|
|
139
41
|
};
|
|
@@ -164,7 +66,7 @@ const dotSize = {
|
|
|
164
66
|
function StatusDot(_ref) {
|
|
165
67
|
let { tone = "neutral", size = "md", hint, className, children } = _ref, props = require_text_truncate._objectWithoutProperties(_ref, _excluded$1);
|
|
166
68
|
const dot = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({
|
|
167
|
-
className: require_text_truncate.cn("inline-flex items-center whitespace-nowrap", sizeStyles$
|
|
69
|
+
className: require_text_truncate.cn("inline-flex items-center whitespace-nowrap", sizeStyles$1[size], textTone[tone], hint && "focus-visible:ring-ring rounded-sm outline-none focus-visible:ring-2", className),
|
|
168
70
|
tabIndex: hint ? 0 : void 0
|
|
169
71
|
}, props), {}, {
|
|
170
72
|
"data-opt-id": "N51AT",
|
|
@@ -191,12 +93,12 @@ const _excluded = [
|
|
|
191
93
|
"disabled",
|
|
192
94
|
"onClick"
|
|
193
95
|
];
|
|
194
|
-
const defaultLabels$
|
|
96
|
+
const defaultLabels$34 = {
|
|
195
97
|
copy: "복사",
|
|
196
98
|
copied: "복사됨",
|
|
197
99
|
failed: "복사할 수 없습니다"
|
|
198
100
|
};
|
|
199
|
-
const sizeStyles
|
|
101
|
+
const sizeStyles = {
|
|
200
102
|
sm: "h-6 gap-1 text-[11px] [&>svg]:size-3",
|
|
201
103
|
md: "h-7 gap-1.5 text-xs [&>svg]:size-3.5"
|
|
202
104
|
};
|
|
@@ -238,7 +140,7 @@ const stateTone = {
|
|
|
238
140
|
*/
|
|
239
141
|
function CopyButton(_ref) {
|
|
240
142
|
let { value, variant = "icon", size = "md", feedbackDuration = 1500, onCopy, labels: customLabels, className, disabled, onClick } = _ref, props = require_text_truncate._objectWithoutProperties(_ref, _excluded);
|
|
241
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
143
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$34), customLabels);
|
|
242
144
|
const [state, setState] = (0, react.useState)("idle");
|
|
243
145
|
const timer = (0, react.useRef)(null);
|
|
244
146
|
(0, react.useEffect)(() => () => {
|
|
@@ -271,7 +173,7 @@ function CopyButton(_ref) {
|
|
|
271
173
|
onClick: handleClick,
|
|
272
174
|
disabled,
|
|
273
175
|
"aria-label": variant === "icon" ? label : void 0,
|
|
274
|
-
className: require_text_truncate.cn("inline-flex shrink-0 items-center rounded transition-colors", "disabled:pointer-events-none disabled:opacity-50", require_text_truncate.OPT_FOCUS_VISIBLE, sizeStyles
|
|
176
|
+
className: require_text_truncate.cn("inline-flex shrink-0 items-center rounded transition-colors", "disabled:pointer-events-none disabled:opacity-50", require_text_truncate.OPT_FOCUS_VISIBLE, sizeStyles[size], paddingStyles[variant][size], stateTone[state], className)
|
|
275
177
|
}, props), {}, {
|
|
276
178
|
"data-opt-id": "E0C8T",
|
|
277
179
|
"data-opt-slug": "copy-button.CopyButton",
|
|
@@ -289,76 +191,6 @@ function CopyButton(_ref) {
|
|
|
289
191
|
}));
|
|
290
192
|
}
|
|
291
193
|
//#endregion
|
|
292
|
-
//#region src/core/segmented-control.tsx
|
|
293
|
-
const sizeStyles = {
|
|
294
|
-
sm: "h-7 text-[11px] [&_svg]:size-3",
|
|
295
|
-
md: "h-8 text-xs [&_svg]:size-3.5"
|
|
296
|
-
};
|
|
297
|
-
const segmentPadding = {
|
|
298
|
-
sm: "gap-1 px-2",
|
|
299
|
-
md: "gap-1.5 px-2.5"
|
|
300
|
-
};
|
|
301
|
-
/**
|
|
302
|
-
* SegmentedControl — one of a few views, all of them visible.
|
|
303
|
-
*
|
|
304
|
-
* A `Select` hides the alternatives behind a click; a `ToggleGroup` presses
|
|
305
|
-
* buttons that may be on together. Neither is what "이벤트 | 속성" is: exactly
|
|
306
|
-
* one is true, the set is small enough to show, and the reader is choosing a
|
|
307
|
-
* view rather than filtering anything.
|
|
308
|
-
*
|
|
309
|
-
* Built on the radio-group primitive rather than on buttons, so the arrow keys,
|
|
310
|
-
* the group name and the checked state come from the platform. A control that
|
|
311
|
-
* merely looks like a radiogroup is one a keyboard cannot drive.
|
|
312
|
-
*
|
|
313
|
-
* @example
|
|
314
|
-
* ```tsx
|
|
315
|
-
* <SegmentedControl
|
|
316
|
-
* aria-label="카탈로그 탭"
|
|
317
|
-
* options={[
|
|
318
|
-
* { value: "events", label: "이벤트", badge: 128 },
|
|
319
|
-
* { value: "properties", label: "속성", badge: 341 },
|
|
320
|
-
* ]}
|
|
321
|
-
* value={tab}
|
|
322
|
-
* onChange={setTab}
|
|
323
|
-
* />
|
|
324
|
-
* ```
|
|
325
|
-
*/
|
|
326
|
-
function SegmentedControl({ options, value, onChange, size = "md", fullWidth = false, disabled = false, "aria-label": ariaLabel, className }) {
|
|
327
|
-
const name = (0, react.useId)();
|
|
328
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_reopt_ai_opt_ui_primitives.RadioGroupRoot, {
|
|
329
|
-
value,
|
|
330
|
-
onValueChange: (next) => onChange(next),
|
|
331
|
-
disabled,
|
|
332
|
-
orientation: "horizontal",
|
|
333
|
-
name,
|
|
334
|
-
"aria-label": ariaLabel,
|
|
335
|
-
className: require_text_truncate.cn("inline-flex items-center rounded-lg border border-border bg-bg-subtle p-0.5", fullWidth && "flex w-full", sizeStyles[size], className),
|
|
336
|
-
"data-opt-id": "YKENE",
|
|
337
|
-
"data-opt-slug": "segmented-control.SegmentedControl",
|
|
338
|
-
children: options.map((option) => {
|
|
339
|
-
const selected = option.value === value;
|
|
340
|
-
const itemDisabled = disabled || option.disabled;
|
|
341
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
342
|
-
className: require_text_truncate.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"),
|
|
343
|
-
"data-selected": selected || void 0,
|
|
344
|
-
children: [
|
|
345
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_reopt_ai_opt_ui_primitives.Radio, {
|
|
346
|
-
value: option.value,
|
|
347
|
-
disabled: itemDisabled,
|
|
348
|
-
className: "absolute inset-0 m-0 h-full w-full cursor-pointer opacity-0"
|
|
349
|
-
}),
|
|
350
|
-
option.icon,
|
|
351
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: option.label }),
|
|
352
|
-
option.badge != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
353
|
-
className: require_text_truncate.cn("tabular-nums", selected ? "text-text-tertiary" : "text-text-tertiary/70"),
|
|
354
|
-
children: option.badge
|
|
355
|
-
})
|
|
356
|
-
]
|
|
357
|
-
}, option.value);
|
|
358
|
-
})
|
|
359
|
-
});
|
|
360
|
-
}
|
|
361
|
-
//#endregion
|
|
362
194
|
//#region src/lib/schema-validator.ts
|
|
363
195
|
/** Handles schema validator. */
|
|
364
196
|
function schemaValidator(schema) {
|
|
@@ -433,7 +265,7 @@ function PageAside({ header, children, footer, widthClassName = "w-60", label, h
|
|
|
433
265
|
PageAside.displayName = "PageAside";
|
|
434
266
|
//#endregion
|
|
435
267
|
//#region src/shells/task-list.tsx
|
|
436
|
-
const defaultLabels$
|
|
268
|
+
const defaultLabels$33 = {
|
|
437
269
|
title: "작업 목록",
|
|
438
270
|
emptyMessage: "작업이 없습니다",
|
|
439
271
|
completedOf: "{completed}/{total} 완료",
|
|
@@ -453,9 +285,9 @@ const defaultLabels$34 = {
|
|
|
453
285
|
};
|
|
454
286
|
/** Renders the task list component. */
|
|
455
287
|
function TaskList({ tasks, title, onTaskClick, onTaskStatusChange, emptyMessage, showSubtasks = false, maxItems, labels: customLabels, className }) {
|
|
456
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
457
|
-
priority: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
458
|
-
status: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
288
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$33), customLabels), {}, {
|
|
289
|
+
priority: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$33.priority), customLabels === null || customLabels === void 0 ? void 0 : customLabels.priority),
|
|
290
|
+
status: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$33.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status)
|
|
459
291
|
});
|
|
460
292
|
const displayTitle = title !== null && title !== void 0 ? title : labels.title;
|
|
461
293
|
const displayEmptyMessage = emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : labels.emptyMessage;
|
|
@@ -613,7 +445,7 @@ function TaskList({ tasks, title, onTaskClick, onTaskStatusChange, emptyMessage,
|
|
|
613
445
|
}
|
|
614
446
|
//#endregion
|
|
615
447
|
//#region src/shells/activity-feed.tsx
|
|
616
|
-
const defaultLabels$
|
|
448
|
+
const defaultLabels$32 = {
|
|
617
449
|
title: "활동 피드",
|
|
618
450
|
emptyMessage: "활동이 없습니다",
|
|
619
451
|
moreItems: "{count}개 더 보기",
|
|
@@ -663,24 +495,24 @@ const variantBorder = {
|
|
|
663
495
|
function ActivityFeed({ activities, title, maxItems, onActivityClick, onShowMore, emptyMessage, labels: customLabels, locale = "ko-KR", loading = false, layout = "list", renderActions, className }) {
|
|
664
496
|
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;
|
|
665
497
|
const mergedTimeAgo = {
|
|
666
|
-
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$
|
|
667
|
-
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$
|
|
668
|
-
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$
|
|
669
|
-
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$
|
|
498
|
+
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$32.timeAgo.justNow,
|
|
499
|
+
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$32.timeAgo.minutesAgo,
|
|
500
|
+
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$32.timeAgo.hoursAgo,
|
|
501
|
+
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$32.timeAgo.daysAgo
|
|
670
502
|
};
|
|
671
503
|
const mergedActivityVerbs = {
|
|
672
|
-
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$
|
|
673
|
-
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$
|
|
674
|
-
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$
|
|
675
|
-
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$
|
|
676
|
-
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$
|
|
677
|
-
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$
|
|
678
|
-
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$
|
|
504
|
+
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$32.activityVerbs.created,
|
|
505
|
+
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$32.activityVerbs.updated,
|
|
506
|
+
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$32.activityVerbs.completed,
|
|
507
|
+
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$32.activityVerbs.commented,
|
|
508
|
+
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$32.activityVerbs.assigned,
|
|
509
|
+
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$32.activityVerbs.deployed,
|
|
510
|
+
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$32.activityVerbs.merged
|
|
679
511
|
};
|
|
680
512
|
const labels = {
|
|
681
|
-
title: (_customLabels$title = customLabels === null || customLabels === void 0 ? void 0 : customLabels.title) !== null && _customLabels$title !== void 0 ? _customLabels$title : defaultLabels$
|
|
682
|
-
emptyMessage: (_customLabels$emptyMe = customLabels === null || customLabels === void 0 ? void 0 : customLabels.emptyMessage) !== null && _customLabels$emptyMe !== void 0 ? _customLabels$emptyMe : defaultLabels$
|
|
683
|
-
moreItems: (_customLabels$moreIte = customLabels === null || customLabels === void 0 ? void 0 : customLabels.moreItems) !== null && _customLabels$moreIte !== void 0 ? _customLabels$moreIte : defaultLabels$
|
|
513
|
+
title: (_customLabels$title = customLabels === null || customLabels === void 0 ? void 0 : customLabels.title) !== null && _customLabels$title !== void 0 ? _customLabels$title : defaultLabels$32.title,
|
|
514
|
+
emptyMessage: (_customLabels$emptyMe = customLabels === null || customLabels === void 0 ? void 0 : customLabels.emptyMessage) !== null && _customLabels$emptyMe !== void 0 ? _customLabels$emptyMe : defaultLabels$32.emptyMessage,
|
|
515
|
+
moreItems: (_customLabels$moreIte = customLabels === null || customLabels === void 0 ? void 0 : customLabels.moreItems) !== null && _customLabels$moreIte !== void 0 ? _customLabels$moreIte : defaultLabels$32.moreItems,
|
|
684
516
|
timeAgo: mergedTimeAgo,
|
|
685
517
|
activityVerbs: mergedActivityVerbs
|
|
686
518
|
};
|
|
@@ -808,13 +640,13 @@ function ActivityFeed({ activities, title, maxItems, onActivityClick, onShowMore
|
|
|
808
640
|
ActivityFeed.displayName = "ActivityFeed";
|
|
809
641
|
//#endregion
|
|
810
642
|
//#region src/shells/filter-bar.tsx
|
|
811
|
-
const defaultLabels$
|
|
643
|
+
const defaultLabels$31 = {
|
|
812
644
|
clearAll: "필터 초기화",
|
|
813
645
|
searchPlaceholder: "검색..."
|
|
814
646
|
};
|
|
815
647
|
/** Renders the filter bar component. */
|
|
816
648
|
function FilterBar({ filters, onFilterChange, onDateRangeChange, onClearAll, labels: customLabels, presetActions, className }) {
|
|
817
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
649
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$31), customLabels);
|
|
818
650
|
const [searchValues, setSearchValues] = (0, react.useState)({});
|
|
819
651
|
const [tagInputValues, setTagInputValues] = (0, react.useState)({});
|
|
820
652
|
const [multiSelectOpen, setMultiSelectOpen] = (0, react.useState)({});
|
|
@@ -1001,7 +833,7 @@ function FilterBar({ filters, onFilterChange, onDateRangeChange, onClearAll, lab
|
|
|
1001
833
|
})]
|
|
1002
834
|
}, filter.id);
|
|
1003
835
|
}
|
|
1004
|
-
if (filter.type === "toggle") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
836
|
+
if (filter.type === "toggle") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Switch, {
|
|
1005
837
|
label: filter.label,
|
|
1006
838
|
size: "sm",
|
|
1007
839
|
checked: filter.value === true,
|
|
@@ -1040,10 +872,10 @@ function matchesShortcut(event, shortcut) {
|
|
|
1040
872
|
if (requiresMeta && !event.metaKey) return false;
|
|
1041
873
|
return event.key.toLowerCase() === key;
|
|
1042
874
|
}
|
|
1043
|
-
const defaultLabels$
|
|
875
|
+
const defaultLabels$30 = { title: "빠른 작업" };
|
|
1044
876
|
/** Renders the quick actions component. */
|
|
1045
877
|
function QuickActions({ actions, title, layout = "grid", columns = 3, showDescriptionInGrid = false, bindShortcuts = false, labels: customLabels, className }) {
|
|
1046
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
878
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$30), customLabels);
|
|
1047
879
|
const displayTitle = title !== null && title !== void 0 ? title : labels.title;
|
|
1048
880
|
const titleId = (0, react.useId)();
|
|
1049
881
|
(0, react.useEffect)(() => {
|
|
@@ -1121,7 +953,7 @@ function QuickActions({ actions, title, layout = "grid", columns = 3, showDescri
|
|
|
1121
953
|
QuickActions.displayName = "QuickActions";
|
|
1122
954
|
//#endregion
|
|
1123
955
|
//#region src/shells/team-member-list.tsx
|
|
1124
|
-
const defaultLabels$
|
|
956
|
+
const defaultLabels$29 = {
|
|
1125
957
|
title: "팀원",
|
|
1126
958
|
emptyMessage: "팀원이 없습니다",
|
|
1127
959
|
onlineCount: "{online}/{total} 온라인",
|
|
@@ -1142,7 +974,7 @@ const statusDot = {
|
|
|
1142
974
|
};
|
|
1143
975
|
/** Renders the team member list component. */
|
|
1144
976
|
function TeamMemberList({ members, title, layout = "list", maxDisplay, onMemberClick, onShowMore, emptyMessage, labels: customLabels, className }) {
|
|
1145
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
977
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$29), customLabels), {}, { status: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$29.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status) });
|
|
1146
978
|
const displayTitle = title !== null && title !== void 0 ? title : labels.title;
|
|
1147
979
|
const displayEmptyMessage = emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : labels.emptyMessage;
|
|
1148
980
|
const titleId = (0, react.useId)();
|
|
@@ -2042,7 +1874,7 @@ const COLOR_PRESETS = [
|
|
|
2042
1874
|
"#f97316",
|
|
2043
1875
|
"#14b8a6"
|
|
2044
1876
|
];
|
|
2045
|
-
const defaultLabels$
|
|
1877
|
+
const defaultLabels$28 = {
|
|
2046
1878
|
eventLabelPrefix: "Event",
|
|
2047
1879
|
defaultAriaLabel: "Event icon"
|
|
2048
1880
|
};
|
|
@@ -2073,7 +1905,7 @@ function getEventIconStyle(color) {
|
|
|
2073
1905
|
/** Renders the event icon component. */
|
|
2074
1906
|
function EventIcon({ icon, color, size = "md", className, labels: customLabels }) {
|
|
2075
1907
|
var _iconEntry$label;
|
|
2076
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
1908
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$28), customLabels);
|
|
2077
1909
|
const sizes = SIZE_MAP[size];
|
|
2078
1910
|
const resolvedColor = (color === null || color === void 0 ? void 0 : color.trim()) ? color : void 0;
|
|
2079
1911
|
const iconEntry = typeof icon === "string" ? require_text_truncate.getIconRegistryEntry(icon) : void 0;
|
|
@@ -2165,14 +1997,14 @@ function ConnectionIndicator({ status, tone, label, showLabel = true, pulse, cla
|
|
|
2165
1997
|
ConnectionIndicator.displayName = "ConnectionIndicator";
|
|
2166
1998
|
//#endregion
|
|
2167
1999
|
//#region src/shells/floating-action-bar.tsx
|
|
2168
|
-
const defaultLabels$
|
|
2000
|
+
const defaultLabels$27 = {
|
|
2169
2001
|
toolbarAriaLabel: "Actions",
|
|
2170
2002
|
selectedLabel: (count) => `${count} selected`,
|
|
2171
2003
|
dismissAriaLabel: "Dismiss"
|
|
2172
2004
|
};
|
|
2173
2005
|
/** Renders the floating action bar component. */
|
|
2174
2006
|
function FloatingActionBar({ actions, selectedCount, onAction, onDismiss, className, labels: customLabels }) {
|
|
2175
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
2007
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$27), customLabels);
|
|
2176
2008
|
if (actions.length === 0) return null;
|
|
2177
2009
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2178
2010
|
role: "toolbar",
|
|
@@ -2209,7 +2041,7 @@ function FloatingActionBar({ actions, selectedCount, onAction, onDismiss, classN
|
|
|
2209
2041
|
FloatingActionBar.displayName = "FloatingActionBar";
|
|
2210
2042
|
//#endregion
|
|
2211
2043
|
//#region src/shells/template-picker.tsx
|
|
2212
|
-
const defaultLabels$
|
|
2044
|
+
const defaultLabels$26 = {
|
|
2213
2045
|
ariaLabel: "Templates",
|
|
2214
2046
|
defaultCategory: "General",
|
|
2215
2047
|
searchPlaceholder: "Search templates...",
|
|
@@ -2217,7 +2049,7 @@ const defaultLabels$27 = {
|
|
|
2217
2049
|
};
|
|
2218
2050
|
/** Renders the template picker component. */
|
|
2219
2051
|
function TemplatePicker({ templates, selected, onSelect, labels: customLabels, showSearch = false, className }) {
|
|
2220
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
2052
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$26), customLabels);
|
|
2221
2053
|
const [search, setSearch] = react.useState("");
|
|
2222
2054
|
const filtered = react.useMemo(() => {
|
|
2223
2055
|
if (!showSearch || !search) return templates;
|
|
@@ -2303,7 +2135,7 @@ function TemplatePicker({ templates, selected, onSelect, labels: customLabels, s
|
|
|
2303
2135
|
TemplatePicker.displayName = "TemplatePicker";
|
|
2304
2136
|
//#endregion
|
|
2305
2137
|
//#region src/shells/code-snippet-viewer.tsx
|
|
2306
|
-
const defaultLabels$
|
|
2138
|
+
const defaultLabels$25 = {
|
|
2307
2139
|
copy: "Copy",
|
|
2308
2140
|
copied: "Copied!",
|
|
2309
2141
|
codeRegion: "Code snippet"
|
|
@@ -2341,7 +2173,7 @@ const syntaxThemeClasses = {
|
|
|
2341
2173
|
/** Renders the code snippet viewer component. */
|
|
2342
2174
|
function CodeSnippetViewer({ code, language = "text", title, showLineNumbers = true, showCopyButton = true, maxHeight = 400, syntaxTheme = "default", className, labels: customLabels }) {
|
|
2343
2175
|
var _syntaxThemeClasses$s;
|
|
2344
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
2176
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$25), customLabels);
|
|
2345
2177
|
const [copied, setCopied] = react.useState(false);
|
|
2346
2178
|
const lines = code.split("\n");
|
|
2347
2179
|
const theme = (_syntaxThemeClasses$s = syntaxThemeClasses[syntaxTheme]) !== null && _syntaxThemeClasses$s !== void 0 ? _syntaxThemeClasses$s : syntaxThemeClasses.default;
|
|
@@ -2393,7 +2225,7 @@ function CodeSnippetViewer({ code, language = "text", title, showLineNumbers = t
|
|
|
2393
2225
|
CodeSnippetViewer.displayName = "CodeSnippetViewer";
|
|
2394
2226
|
//#endregion
|
|
2395
2227
|
//#region src/shells/property-explorer.tsx
|
|
2396
|
-
const defaultLabels$
|
|
2228
|
+
const defaultLabels$24 = {
|
|
2397
2229
|
searchPlaceholder: "Search properties...",
|
|
2398
2230
|
noPropertiesFound: "No properties found",
|
|
2399
2231
|
edit: (property) => `${property} 편집`,
|
|
@@ -2401,7 +2233,7 @@ const defaultLabels$25 = {
|
|
|
2401
2233
|
};
|
|
2402
2234
|
/** Renders the property explorer component. */
|
|
2403
2235
|
function PropertyExplorer({ groups, onSelect, onEdit, className, labels: customLabels }) {
|
|
2404
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
2236
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$24), customLabels);
|
|
2405
2237
|
const [search, setSearch] = react.useState("");
|
|
2406
2238
|
const filtered = react.useMemo(() => {
|
|
2407
2239
|
if (!search) return groups;
|
|
@@ -2485,96 +2317,206 @@ function PropertyExplorer({ groups, onSelect, onEdit, className, labels: customL
|
|
|
2485
2317
|
}
|
|
2486
2318
|
PropertyExplorer.displayName = "PropertyExplorer";
|
|
2487
2319
|
//#endregion
|
|
2488
|
-
//#region src/
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
"
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
"
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
return
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2320
|
+
//#region src/lib/sql/statements.ts
|
|
2321
|
+
/**
|
|
2322
|
+
* Split editor text into statements on top-level semicolons.
|
|
2323
|
+
*
|
|
2324
|
+
* Blank statements (two semicolons in a row, a trailing semicolon) are dropped.
|
|
2325
|
+
*/
|
|
2326
|
+
function splitSqlStatements(text) {
|
|
2327
|
+
const out = [];
|
|
2328
|
+
let segmentStart = 0;
|
|
2329
|
+
let i = 0;
|
|
2330
|
+
const length = text.length;
|
|
2331
|
+
const push = (from, to) => {
|
|
2332
|
+
let start = from;
|
|
2333
|
+
let end = to;
|
|
2334
|
+
while (start < end && /\s/.test(text[start])) start++;
|
|
2335
|
+
while (end > start && /\s/.test(text[end - 1])) end--;
|
|
2336
|
+
if (end > start) out.push({
|
|
2337
|
+
text: text.slice(start, end),
|
|
2338
|
+
start,
|
|
2339
|
+
end
|
|
2340
|
+
});
|
|
2341
|
+
};
|
|
2342
|
+
while (i < length) {
|
|
2343
|
+
const ch = text[i];
|
|
2344
|
+
const next = text[i + 1];
|
|
2345
|
+
if (ch === "'" || ch === "\"" || ch === "`") {
|
|
2346
|
+
i = skipQuoted(text, i, ch);
|
|
2347
|
+
continue;
|
|
2348
|
+
}
|
|
2349
|
+
if (ch === "-" && next === "-") {
|
|
2350
|
+
i = skipLineComment(text, i + 2);
|
|
2351
|
+
continue;
|
|
2352
|
+
}
|
|
2353
|
+
if (ch === "/" && next === "*") {
|
|
2354
|
+
i = skipBlockComment(text, i + 2);
|
|
2355
|
+
continue;
|
|
2356
|
+
}
|
|
2357
|
+
if (ch === ";") {
|
|
2358
|
+
push(segmentStart, i);
|
|
2359
|
+
segmentStart = i + 1;
|
|
2360
|
+
}
|
|
2361
|
+
i++;
|
|
2362
|
+
}
|
|
2363
|
+
push(segmentStart, length);
|
|
2364
|
+
return out;
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* The statement the cursor is in, or the nearest one when the cursor sits in
|
|
2368
|
+
* the whitespace between two. `null` only when there are no statements.
|
|
2369
|
+
*
|
|
2370
|
+
* "Nearest" prefers the statement before the cursor: a reader who just typed a
|
|
2371
|
+
* semicolon and pressed run means the thing they finished, not the empty line
|
|
2372
|
+
* after it.
|
|
2373
|
+
*/
|
|
2374
|
+
function sqlStatementAtOffset(statements, offset) {
|
|
2375
|
+
var _before;
|
|
2376
|
+
if (statements.length === 0) return null;
|
|
2377
|
+
let before = null;
|
|
2378
|
+
for (const statement of statements) {
|
|
2379
|
+
if (offset >= statement.start && offset <= statement.end) return statement;
|
|
2380
|
+
if (statement.end < offset) before = statement;
|
|
2381
|
+
else break;
|
|
2382
|
+
}
|
|
2383
|
+
return (_before = before) !== null && _before !== void 0 ? _before : statements[0];
|
|
2384
|
+
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Whether the SQL uses a `{name}` placeholder outside strings and comments.
|
|
2387
|
+
* Also matches `{name.` and `{name(` so a `{filters(...)}` binding counts.
|
|
2388
|
+
*/
|
|
2389
|
+
function sqlUsesPlaceholder(sql, name) {
|
|
2390
|
+
const needle = `{${name}`;
|
|
2391
|
+
let i = 0;
|
|
2392
|
+
const length = sql.length;
|
|
2393
|
+
while (i < length) {
|
|
2394
|
+
const ch = sql[i];
|
|
2395
|
+
const next = sql[i + 1];
|
|
2396
|
+
if (ch === "'" || ch === "\"" || ch === "`") {
|
|
2397
|
+
i = skipQuoted(sql, i, ch);
|
|
2398
|
+
continue;
|
|
2399
|
+
}
|
|
2400
|
+
if (ch === "-" && next === "-") {
|
|
2401
|
+
i = skipLineComment(sql, i + 2);
|
|
2402
|
+
continue;
|
|
2403
|
+
}
|
|
2404
|
+
if (ch === "/" && next === "*") {
|
|
2405
|
+
i = skipBlockComment(sql, i + 2);
|
|
2406
|
+
continue;
|
|
2407
|
+
}
|
|
2408
|
+
if (sql.startsWith(needle, i)) {
|
|
2409
|
+
const after = sql[i + needle.length];
|
|
2410
|
+
if (after === "}" || after === "." || after === "(") return true;
|
|
2411
|
+
}
|
|
2412
|
+
i++;
|
|
2413
|
+
}
|
|
2414
|
+
return false;
|
|
2415
|
+
}
|
|
2416
|
+
/**
|
|
2417
|
+
* Replace every `{name}` placeholder outside strings and comments with the
|
|
2418
|
+
* given text. A `{name(...)}` binding is left alone — that form carries
|
|
2419
|
+
* arguments the caller must interpret, and a blind substitution would corrupt it.
|
|
2420
|
+
*/
|
|
2421
|
+
function replaceSqlPlaceholder(sql, name, replacement) {
|
|
2422
|
+
const needle = `{${name}}`;
|
|
2423
|
+
let out = "";
|
|
2424
|
+
let i = 0;
|
|
2425
|
+
const length = sql.length;
|
|
2426
|
+
while (i < length) {
|
|
2427
|
+
const ch = sql[i];
|
|
2428
|
+
const next = sql[i + 1];
|
|
2429
|
+
let skipTo = -1;
|
|
2430
|
+
if (ch === "'" || ch === "\"" || ch === "`") skipTo = skipQuoted(sql, i, ch);
|
|
2431
|
+
else if (ch === "-" && next === "-") skipTo = skipLineComment(sql, i + 2);
|
|
2432
|
+
else if (ch === "/" && next === "*") skipTo = skipBlockComment(sql, i + 2);
|
|
2433
|
+
if (skipTo !== -1) {
|
|
2434
|
+
out += sql.slice(i, skipTo);
|
|
2435
|
+
i = skipTo;
|
|
2436
|
+
continue;
|
|
2437
|
+
}
|
|
2438
|
+
if (sql.startsWith(needle, i)) {
|
|
2439
|
+
out += replacement;
|
|
2440
|
+
i += needle.length;
|
|
2441
|
+
continue;
|
|
2442
|
+
}
|
|
2443
|
+
out += ch;
|
|
2444
|
+
i++;
|
|
2445
|
+
}
|
|
2446
|
+
return out;
|
|
2447
|
+
}
|
|
2448
|
+
/** Names of every `{name}` / `{name.x}` placeholder, in order of first use. */
|
|
2449
|
+
function sqlPlaceholderNames(sql) {
|
|
2450
|
+
const names = [];
|
|
2451
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2452
|
+
let i = 0;
|
|
2453
|
+
const length = sql.length;
|
|
2454
|
+
while (i < length) {
|
|
2455
|
+
const ch = sql[i];
|
|
2456
|
+
const next = sql[i + 1];
|
|
2457
|
+
if (ch === "'" || ch === "\"" || ch === "`") {
|
|
2458
|
+
i = skipQuoted(sql, i, ch);
|
|
2459
|
+
continue;
|
|
2460
|
+
}
|
|
2461
|
+
if (ch === "-" && next === "-") {
|
|
2462
|
+
i = skipLineComment(sql, i + 2);
|
|
2463
|
+
continue;
|
|
2464
|
+
}
|
|
2465
|
+
if (ch === "/" && next === "*") {
|
|
2466
|
+
i = skipBlockComment(sql, i + 2);
|
|
2467
|
+
continue;
|
|
2468
|
+
}
|
|
2469
|
+
if (ch === "{") {
|
|
2470
|
+
const match = /^\{([A-Za-z_][A-Za-z0-9_]*)/.exec(sql.slice(i));
|
|
2471
|
+
if (match) {
|
|
2472
|
+
const name = match[1];
|
|
2473
|
+
if (!seen.has(name)) {
|
|
2474
|
+
seen.add(name);
|
|
2475
|
+
names.push(name);
|
|
2476
|
+
}
|
|
2477
|
+
i += match[0].length;
|
|
2478
|
+
continue;
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
i++;
|
|
2482
|
+
}
|
|
2483
|
+
return names;
|
|
2484
|
+
}
|
|
2485
|
+
function skipQuoted(text, from, quote) {
|
|
2486
|
+
let i = from + 1;
|
|
2487
|
+
const length = text.length;
|
|
2488
|
+
while (i < length) {
|
|
2489
|
+
const ch = text[i];
|
|
2490
|
+
if (ch === "\\") {
|
|
2491
|
+
i += 2;
|
|
2492
|
+
continue;
|
|
2493
|
+
}
|
|
2494
|
+
if (ch === quote) {
|
|
2495
|
+
if (text[i + 1] === quote) {
|
|
2496
|
+
i += 2;
|
|
2497
|
+
continue;
|
|
2498
|
+
}
|
|
2499
|
+
return i + 1;
|
|
2500
|
+
}
|
|
2501
|
+
i++;
|
|
2502
|
+
}
|
|
2503
|
+
return length;
|
|
2504
|
+
}
|
|
2505
|
+
function skipLineComment(text, from) {
|
|
2506
|
+
let i = from;
|
|
2507
|
+
const length = text.length;
|
|
2508
|
+
while (i < length && text[i] !== "\n") i++;
|
|
2509
|
+
return i;
|
|
2510
|
+
}
|
|
2511
|
+
function skipBlockComment(text, from) {
|
|
2512
|
+
let i = from;
|
|
2513
|
+
const length = text.length;
|
|
2514
|
+
while (i < length) {
|
|
2515
|
+
if (text[i] === "*" && text[i + 1] === "/") return i + 2;
|
|
2516
|
+
i++;
|
|
2517
|
+
}
|
|
2518
|
+
return length;
|
|
2576
2519
|
}
|
|
2577
|
-
QueryResultsTable.displayName = "QueryResultsTable";
|
|
2578
2520
|
//#endregion
|
|
2579
2521
|
//#region src/shells/alert-builder.tsx
|
|
2580
2522
|
const defaultLabels$23 = {
|
|
@@ -2802,188 +2744,8 @@ function AlertBuilder({ value, onChange, metrics = [
|
|
|
2802
2744
|
}
|
|
2803
2745
|
AlertBuilder.displayName = "AlertBuilder";
|
|
2804
2746
|
//#endregion
|
|
2805
|
-
//#region src/shells/sql-editor.tsx
|
|
2806
|
-
const defaultLabels$22 = {
|
|
2807
|
-
placeholder: "SELECT * FROM events LIMIT 100",
|
|
2808
|
-
runHint: "Ctrl+Enter to run",
|
|
2809
|
-
runButton: "Run Query",
|
|
2810
|
-
editor: "SQL 편집기"
|
|
2811
|
-
};
|
|
2812
|
-
/** Renders the sql editor component. */
|
|
2813
|
-
function SqlEditor({ value, onChange, onRun, onRunAndAdvance, placeholder, readOnly = false, height = 200, schema, completionSources, keymap: customKeymap, extensions: customExtensions, ariaLabel, autoFocus = false, showFooter, labels: customLabels, className }) {
|
|
2814
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$22), customLabels);
|
|
2815
|
-
const fill = height === "fill";
|
|
2816
|
-
const footerVisible = showFooter !== null && showFooter !== void 0 ? showFooter : Boolean(onRun);
|
|
2817
|
-
const editorRef = react.useRef(null);
|
|
2818
|
-
const viewRef = react.useRef(null);
|
|
2819
|
-
const completionCompartmentRef = react.useRef(null);
|
|
2820
|
-
const editableCompartmentRef = react.useRef(null);
|
|
2821
|
-
const buildCompletionRef = react.useRef(null);
|
|
2822
|
-
const latestValueRef = react.useRef(value);
|
|
2823
|
-
const onChangeRef = react.useRef(onChange);
|
|
2824
|
-
const onRunRef = react.useRef(onRun);
|
|
2825
|
-
const onRunAndAdvanceRef = react.useRef(onRunAndAdvance);
|
|
2826
|
-
const customKeymapRef = react.useRef(customKeymap);
|
|
2827
|
-
const schemaRef = react.useRef(schema);
|
|
2828
|
-
const completionSourcesRef = react.useRef(completionSources);
|
|
2829
|
-
const autoFocusRef = react.useRef(autoFocus);
|
|
2830
|
-
latestValueRef.current = value;
|
|
2831
|
-
onChangeRef.current = onChange;
|
|
2832
|
-
onRunRef.current = onRun;
|
|
2833
|
-
onRunAndAdvanceRef.current = onRunAndAdvance;
|
|
2834
|
-
customKeymapRef.current = customKeymap;
|
|
2835
|
-
schemaRef.current = schema;
|
|
2836
|
-
completionSourcesRef.current = completionSources;
|
|
2837
|
-
autoFocusRef.current = autoFocus;
|
|
2838
|
-
const autocompleteEnabled = react.useRef(schema !== void 0 || completionSources !== void 0).current;
|
|
2839
|
-
react.useEffect(() => {
|
|
2840
|
-
let view = null;
|
|
2841
|
-
let cancelled = false;
|
|
2842
|
-
async function init() {
|
|
2843
|
-
var _customKeymapRef$curr;
|
|
2844
|
-
const parent = editorRef.current;
|
|
2845
|
-
if (!parent) return;
|
|
2846
|
-
const [{ EditorView, keymap: cmKeymap, placeholder: cmPlaceholder }, { Compartment, EditorState }, langSql, { oneDark }, autocomplete] = await Promise.all([
|
|
2847
|
-
import("@codemirror/view"),
|
|
2848
|
-
import("@codemirror/state"),
|
|
2849
|
-
import("@codemirror/lang-sql"),
|
|
2850
|
-
import("@codemirror/theme-one-dark"),
|
|
2851
|
-
autocompleteEnabled ? import("@codemirror/autocomplete") : Promise.resolve(null)
|
|
2852
|
-
]);
|
|
2853
|
-
if (cancelled || !parent.isConnected) return;
|
|
2854
|
-
const completionCompartment = new Compartment();
|
|
2855
|
-
const editableCompartment = new Compartment();
|
|
2856
|
-
completionCompartmentRef.current = completionCompartment;
|
|
2857
|
-
editableCompartmentRef.current = editableCompartment;
|
|
2858
|
-
const buildCompletion = (nextSchema, nextSources) => {
|
|
2859
|
-
if (!autocomplete) return [];
|
|
2860
|
-
const dialect = langSql.PostgreSQL;
|
|
2861
|
-
return [autocomplete.autocompletion({ override: [
|
|
2862
|
-
langSql.schemaCompletionSource({
|
|
2863
|
-
dialect,
|
|
2864
|
-
schema: nextSchema !== null && nextSchema !== void 0 ? nextSchema : {}
|
|
2865
|
-
}),
|
|
2866
|
-
langSql.keywordCompletionSource(dialect),
|
|
2867
|
-
...nextSources !== null && nextSources !== void 0 ? nextSources : []
|
|
2868
|
-
] }), cmKeymap.of(autocomplete.completionKeymap)];
|
|
2869
|
-
};
|
|
2870
|
-
buildCompletionRef.current = buildCompletion;
|
|
2871
|
-
const runKeymap = [{
|
|
2872
|
-
key: "Shift-Enter",
|
|
2873
|
-
run: (target) => {
|
|
2874
|
-
const handler = onRunAndAdvanceRef.current;
|
|
2875
|
-
if (!handler) return false;
|
|
2876
|
-
handler(target.state.doc.toString());
|
|
2877
|
-
return true;
|
|
2878
|
-
}
|
|
2879
|
-
}, {
|
|
2880
|
-
key: "Mod-Enter",
|
|
2881
|
-
run: (target) => {
|
|
2882
|
-
const handler = onRunRef.current;
|
|
2883
|
-
if (!handler) return false;
|
|
2884
|
-
handler(target.state.doc.toString());
|
|
2885
|
-
return true;
|
|
2886
|
-
}
|
|
2887
|
-
}];
|
|
2888
|
-
const extensions = [
|
|
2889
|
-
langSql.PostgreSQL.extension,
|
|
2890
|
-
completionCompartment.of(buildCompletion(schemaRef.current, completionSourcesRef.current)),
|
|
2891
|
-
oneDark,
|
|
2892
|
-
cmKeymap.of([...(_customKeymapRef$curr = customKeymapRef.current) !== null && _customKeymapRef$curr !== void 0 ? _customKeymapRef$curr : [], ...runKeymap]),
|
|
2893
|
-
EditorView.theme({
|
|
2894
|
-
"&": { height: "100%" },
|
|
2895
|
-
"&.cm-focused": {
|
|
2896
|
-
outline: "2px solid var(--opt-ring)",
|
|
2897
|
-
outlineOffset: "-2px"
|
|
2898
|
-
},
|
|
2899
|
-
".cm-scroller": {
|
|
2900
|
-
height: "100%",
|
|
2901
|
-
overflow: "auto"
|
|
2902
|
-
}
|
|
2903
|
-
}),
|
|
2904
|
-
cmPlaceholder(placeholder !== null && placeholder !== void 0 ? placeholder : labels.placeholder),
|
|
2905
|
-
EditorView.lineWrapping,
|
|
2906
|
-
EditorView.updateListener.of((update) => {
|
|
2907
|
-
if (update.docChanged) onChangeRef.current(update.state.doc.toString());
|
|
2908
|
-
}),
|
|
2909
|
-
editableCompartment.of(EditorView.editable.of(!readOnly)),
|
|
2910
|
-
EditorView.contentAttributes.of({ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : labels.editor }),
|
|
2911
|
-
...customExtensions !== null && customExtensions !== void 0 ? customExtensions : []
|
|
2912
|
-
];
|
|
2913
|
-
view = new EditorView({
|
|
2914
|
-
state: EditorState.create({
|
|
2915
|
-
doc: latestValueRef.current,
|
|
2916
|
-
extensions
|
|
2917
|
-
}),
|
|
2918
|
-
parent
|
|
2919
|
-
});
|
|
2920
|
-
viewRef.current = view;
|
|
2921
|
-
if (autoFocusRef.current) view.focus();
|
|
2922
|
-
}
|
|
2923
|
-
init();
|
|
2924
|
-
return () => {
|
|
2925
|
-
cancelled = true;
|
|
2926
|
-
view === null || view === void 0 || view.destroy();
|
|
2927
|
-
if (viewRef.current === view) viewRef.current = null;
|
|
2928
|
-
completionCompartmentRef.current = null;
|
|
2929
|
-
editableCompartmentRef.current = null;
|
|
2930
|
-
buildCompletionRef.current = null;
|
|
2931
|
-
};
|
|
2932
|
-
}, []);
|
|
2933
|
-
react.useEffect(() => {
|
|
2934
|
-
const view = viewRef.current;
|
|
2935
|
-
if (view && view.state.doc.toString() !== value) view.dispatch({ changes: {
|
|
2936
|
-
from: 0,
|
|
2937
|
-
to: view.state.doc.length,
|
|
2938
|
-
insert: value
|
|
2939
|
-
} });
|
|
2940
|
-
}, [value]);
|
|
2941
|
-
react.useEffect(() => {
|
|
2942
|
-
const view = viewRef.current;
|
|
2943
|
-
const compartment = completionCompartmentRef.current;
|
|
2944
|
-
const build = buildCompletionRef.current;
|
|
2945
|
-
if (!view || !compartment || !build) return;
|
|
2946
|
-
view.dispatch({ effects: compartment.reconfigure(build(schema, completionSources)) });
|
|
2947
|
-
}, [schema, completionSources]);
|
|
2948
|
-
react.useEffect(() => {
|
|
2949
|
-
const view = viewRef.current;
|
|
2950
|
-
const compartment = editableCompartmentRef.current;
|
|
2951
|
-
if (!view || !compartment) return;
|
|
2952
|
-
let cancelled = false;
|
|
2953
|
-
import("@codemirror/view").then(({ EditorView }) => {
|
|
2954
|
-
if (cancelled || viewRef.current !== view) return;
|
|
2955
|
-
view.dispatch({ effects: compartment.reconfigure(EditorView.editable.of(!readOnly)) });
|
|
2956
|
-
});
|
|
2957
|
-
return () => {
|
|
2958
|
-
cancelled = true;
|
|
2959
|
-
};
|
|
2960
|
-
}, [readOnly]);
|
|
2961
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2962
|
-
className: require_text_truncate.cn("gap-element flex flex-col", fill && "h-full min-h-0", className),
|
|
2963
|
-
"data-opt-id": "RSGKV",
|
|
2964
|
-
"data-opt-slug": "sql-editor.SqlEditor",
|
|
2965
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2966
|
-
ref: editorRef,
|
|
2967
|
-
className: require_text_truncate.cn("border-border overflow-hidden rounded-lg border", fill && "min-h-0 flex-1"),
|
|
2968
|
-
style: fill ? void 0 : { height }
|
|
2969
|
-
}), footerVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2970
|
-
className: "flex flex-none items-center justify-between",
|
|
2971
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2972
|
-
className: "text-text-tertiary text-xs",
|
|
2973
|
-
children: labels.runHint
|
|
2974
|
-
}), onRun && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Button, {
|
|
2975
|
-
variant: "primary",
|
|
2976
|
-
size: "sm",
|
|
2977
|
-
onClick: () => onRun(value),
|
|
2978
|
-
children: labels.runButton
|
|
2979
|
-
})]
|
|
2980
|
-
})]
|
|
2981
|
-
});
|
|
2982
|
-
}
|
|
2983
|
-
SqlEditor.displayName = "SqlEditor";
|
|
2984
|
-
//#endregion
|
|
2985
2747
|
//#region src/shells/event-meta-editor.tsx
|
|
2986
|
-
const defaultLabels$
|
|
2748
|
+
const defaultLabels$22 = {
|
|
2987
2749
|
icon: "Icon",
|
|
2988
2750
|
color: "Color",
|
|
2989
2751
|
name: "Event name",
|
|
@@ -3001,7 +2763,7 @@ const defaultLabels$21 = {
|
|
|
3001
2763
|
};
|
|
3002
2764
|
/** Renders the event meta editor component. */
|
|
3003
2765
|
function EventMetaEditor({ value, onChange, icons, sections, footer, className, labels: customLabels }) {
|
|
3004
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
2766
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$22), customLabels);
|
|
3005
2767
|
const hasTags = value.tags.length > 0;
|
|
3006
2768
|
const nameId = react.useId();
|
|
3007
2769
|
const displayNameId = react.useId();
|
|
@@ -3124,10 +2886,10 @@ function EventMetaEditor({ value, onChange, icons, sections, footer, className,
|
|
|
3124
2886
|
EventMetaEditor.displayName = "EventMetaEditor";
|
|
3125
2887
|
//#endregion
|
|
3126
2888
|
//#region src/shells/widget-grid.tsx
|
|
3127
|
-
const defaultLabels$
|
|
2889
|
+
const defaultLabels$21 = { emptyMessage: "No widgets to display" };
|
|
3128
2890
|
/** Renders the widget grid component. */
|
|
3129
2891
|
function WidgetGrid({ widgets, cols = 12, rowHeight = 80, gap = 16, editable = false, onReorder, labels: customLabels, className }) {
|
|
3130
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
2892
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$21), customLabels);
|
|
3131
2893
|
const [dragIdx, setDragIdx] = react.useState(null);
|
|
3132
2894
|
const [overIdx, setOverIdx] = react.useState(null);
|
|
3133
2895
|
if (widgets.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -3172,7 +2934,7 @@ function WidgetGrid({ widgets, cols = 12, rowHeight = 80, gap = 16, editable = f
|
|
|
3172
2934
|
WidgetGrid.displayName = "WidgetGrid";
|
|
3173
2935
|
//#endregion
|
|
3174
2936
|
//#region src/shells/report-builder.tsx
|
|
3175
|
-
const defaultLabels$
|
|
2937
|
+
const defaultLabels$20 = {
|
|
3176
2938
|
stepsLabel: "Report steps",
|
|
3177
2939
|
stepType: "Chart Type",
|
|
3178
2940
|
stepConfig: "Data Config",
|
|
@@ -3248,7 +3010,7 @@ const STEPS = [
|
|
|
3248
3010
|
];
|
|
3249
3011
|
/** Renders the report builder component. */
|
|
3250
3012
|
function ReportBuilder({ chartTypes = DEFAULT_CHART_TYPES, dataSources = [], onSave, onCancel, configForm, styleForm, preview, onChartTypeChange, onDataSourceChange, onStepChange, selectedChartType: controlledChartType, selectedDataSource: controlledDataSource, labels: customLabels, className }) {
|
|
3251
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
3013
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$20), customLabels);
|
|
3252
3014
|
const [stepIndex, setStepIndex] = react.useState(0);
|
|
3253
3015
|
const [internalChartType, setInternalChartType] = react.useState(null);
|
|
3254
3016
|
const [internalDataSource, setInternalDataSource] = react.useState("");
|
|
@@ -3468,7 +3230,7 @@ function ReportBuilder({ chartTypes = DEFAULT_CHART_TYPES, dataSources = [], onS
|
|
|
3468
3230
|
ReportBuilder.displayName = "ReportBuilder";
|
|
3469
3231
|
//#endregion
|
|
3470
3232
|
//#region src/shells/audit-timeline.tsx
|
|
3471
|
-
const defaultLabels$
|
|
3233
|
+
const defaultLabels$19 = {
|
|
3472
3234
|
title: "변경 이력",
|
|
3473
3235
|
empty: "변경 이력이 없습니다",
|
|
3474
3236
|
expand: "상세 보기",
|
|
@@ -3547,7 +3309,7 @@ function DiffTable({ changes, labels }) {
|
|
|
3547
3309
|
}
|
|
3548
3310
|
/** Renders the audit timeline component. */
|
|
3549
3311
|
function AuditTimeline({ entries, labels: customLabels, className, onEntryClick }) {
|
|
3550
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
3312
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$19), customLabels);
|
|
3551
3313
|
const [expandedIds, setExpandedIds] = react.useState(/* @__PURE__ */ new Set());
|
|
3552
3314
|
const toggleExpanded = react.useCallback((id) => {
|
|
3553
3315
|
setExpandedIds((prev) => {
|
|
@@ -3670,7 +3432,7 @@ function AuditTimeline({ entries, labels: customLabels, className, onEntryClick
|
|
|
3670
3432
|
AuditTimeline.displayName = "AuditTimeline";
|
|
3671
3433
|
//#endregion
|
|
3672
3434
|
//#region src/shells/segment-builder.tsx
|
|
3673
|
-
const defaultLabels$
|
|
3435
|
+
const defaultLabels$18 = {
|
|
3674
3436
|
match: "Match",
|
|
3675
3437
|
ofTheFollowing: "of the following",
|
|
3676
3438
|
groupLabel: "Segment group",
|
|
@@ -3791,7 +3553,7 @@ function SegmentBuilder({ groups, onChange, eventOptions = [
|
|
|
3791
3553
|
"New Users",
|
|
3792
3554
|
"Power Users"
|
|
3793
3555
|
], className, labels: customLabels }) {
|
|
3794
|
-
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$
|
|
3556
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$18), customLabels);
|
|
3795
3557
|
const builderId = react.useId().replace(/:/g, "");
|
|
3796
3558
|
const nextIdRef = react.useRef(1);
|
|
3797
3559
|
const createId = react.useCallback(() => {
|
|
@@ -4003,57 +3765,754 @@ function SegmentBuilder({ groups, onChange, eventOptions = [
|
|
|
4003
3765
|
}
|
|
4004
3766
|
SegmentBuilder.displayName = "SegmentBuilder";
|
|
4005
3767
|
//#endregion
|
|
4006
|
-
//#region src/shells/
|
|
4007
|
-
const defaultLabels$
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
3768
|
+
//#region src/shells/criteria-builder.tsx
|
|
3769
|
+
const defaultLabels$17 = {
|
|
3770
|
+
builder: "조건 빌더",
|
|
3771
|
+
rootLogicLegend: "그룹 결합 방식",
|
|
3772
|
+
matchAllGroups: "모든 그룹 일치",
|
|
3773
|
+
matchAnyGroup: "하나 이상 일치",
|
|
3774
|
+
groupLogicLegend: (letter) => `그룹 ${letter} 조건 결합 방식`,
|
|
3775
|
+
matchAllCriteria: "모두 충족",
|
|
3776
|
+
matchAnyCriteria: "하나 이상 충족",
|
|
3777
|
+
and: "그리고",
|
|
3778
|
+
or: "또는",
|
|
3779
|
+
groupLabel: (letter) => `그룹 ${letter}`,
|
|
3780
|
+
criterionLabel: (letter, index) => `조건 ${letter}.${index}`,
|
|
3781
|
+
actionLabel: (action, target) => `${action}: ${target}`,
|
|
3782
|
+
addCriterion: "조건 추가",
|
|
3783
|
+
addGroup: "그룹 추가",
|
|
3784
|
+
kindMenuTitle: "조건 유형",
|
|
3785
|
+
duplicateCriterion: "조건 복제",
|
|
3786
|
+
removeCriterion: "조건 제거",
|
|
3787
|
+
moveUp: "위로 이동",
|
|
3788
|
+
moveDown: "아래로 이동",
|
|
3789
|
+
negate: "제외",
|
|
3790
|
+
duplicateGroup: "그룹 복제",
|
|
3791
|
+
removeGroup: "그룹 제거",
|
|
3792
|
+
emptyGroup: "이 그룹에는 아직 조건이 없습니다.",
|
|
3793
|
+
unknownKind: (kind) => `알 수 없는 조건 유형 "${kind}"`,
|
|
3794
|
+
unknownKindDescription: "이 조건은 표시할 수 없습니다. 유형을 바꾸거나 제거하세요.",
|
|
3795
|
+
replaceKind: "유형 바꾸기",
|
|
3796
|
+
emptyTitle: "조건이 없습니다",
|
|
3797
|
+
emptyDescription: "첫 그룹을 추가해 누가 포함되는지 정의하세요.",
|
|
3798
|
+
emptyAction: "첫 조건 추가",
|
|
3799
|
+
keyboardHint: "조건 추가 · 그룹 추가",
|
|
3800
|
+
maxGroupsReached: (max) => `그룹은 최대 ${max}개까지 추가할 수 있습니다.`,
|
|
3801
|
+
maxCriteriaReached: (max) => `한 그룹에는 조건을 최대 ${max}개까지 추가할 수 있습니다.`
|
|
4017
3802
|
};
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
3803
|
+
/** `A`, `B`, … `Z`, `AA`, `AB` — the badge a group wears. */
|
|
3804
|
+
function criteriaGroupLetter(index) {
|
|
3805
|
+
let n = Math.max(0, Math.floor(index));
|
|
3806
|
+
let out = "";
|
|
3807
|
+
do {
|
|
3808
|
+
out = String.fromCharCode(65 + n % 26) + out;
|
|
3809
|
+
n = Math.floor(n / 26) - 1;
|
|
3810
|
+
} while (n >= 0);
|
|
3811
|
+
return out;
|
|
3812
|
+
}
|
|
3813
|
+
function collectIds(value) {
|
|
3814
|
+
const ids = /* @__PURE__ */ new Set();
|
|
3815
|
+
for (const group of value.groups) {
|
|
3816
|
+
ids.add(group.id);
|
|
3817
|
+
for (const criterion of group.criteria) ids.add(criterion.id);
|
|
4033
3818
|
}
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
function
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
3819
|
+
return ids;
|
|
3820
|
+
}
|
|
3821
|
+
function uniqueId(base, taken) {
|
|
3822
|
+
if (!taken.has(base)) return base;
|
|
3823
|
+
let n = 2;
|
|
3824
|
+
while (taken.has(`${base}-${n}`)) n += 1;
|
|
3825
|
+
return `${base}-${n}`;
|
|
3826
|
+
}
|
|
3827
|
+
function replaceGroup(value, groupIndex, next) {
|
|
3828
|
+
return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: value.groups.map((group, i) => i === groupIndex ? next : group) });
|
|
3829
|
+
}
|
|
3830
|
+
/**
|
|
3831
|
+
* Moves one criterion a step up or down inside its group. Returns the same
|
|
3832
|
+
* value when the move is impossible, so a caller can `===` to know nothing
|
|
3833
|
+
* changed.
|
|
3834
|
+
*/
|
|
3835
|
+
function criteriaBuilderMove(value, groupIndex, index, direction) {
|
|
3836
|
+
const group = value.groups[groupIndex];
|
|
3837
|
+
if (!group) return value;
|
|
3838
|
+
const target = direction === "up" ? index - 1 : index + 1;
|
|
3839
|
+
if (index < 0 || target < 0 || target >= group.criteria.length) return value;
|
|
3840
|
+
const criteria = [...group.criteria];
|
|
3841
|
+
const [moved] = criteria.splice(index, 1);
|
|
3842
|
+
criteria.splice(target, 0, moved);
|
|
3843
|
+
return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria }));
|
|
3844
|
+
}
|
|
3845
|
+
/**
|
|
3846
|
+
* Inserts a copy of one criterion *before* the original, so the copy takes the
|
|
3847
|
+
* original's place in the reading order and the original follows as the thing
|
|
3848
|
+
* to edit.
|
|
3849
|
+
*/
|
|
3850
|
+
function criteriaBuilderDuplicate(value, groupIndex, index, clone) {
|
|
3851
|
+
const group = value.groups[groupIndex];
|
|
3852
|
+
const original = group === null || group === void 0 ? void 0 : group.criteria[index];
|
|
3853
|
+
if (!group || !original) return value;
|
|
3854
|
+
const criteria = [...group.criteria];
|
|
3855
|
+
criteria.splice(index, 0, clone(original));
|
|
3856
|
+
return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria }));
|
|
3857
|
+
}
|
|
3858
|
+
/** Removes one criterion. The group stays, even when it empties. */
|
|
3859
|
+
function criteriaBuilderRemove(value, groupIndex, index) {
|
|
3860
|
+
const group = value.groups[groupIndex];
|
|
3861
|
+
if (!group || index < 0 || index >= group.criteria.length) return value;
|
|
3862
|
+
return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria: group.criteria.filter((_, i) => i !== index) }));
|
|
3863
|
+
}
|
|
3864
|
+
/** Appends a criterion to a group, or inserts it at `at`. */
|
|
3865
|
+
function criteriaBuilderInsert(value, groupIndex, criterion, at) {
|
|
3866
|
+
const group = value.groups[groupIndex];
|
|
3867
|
+
if (!group) return value;
|
|
3868
|
+
const criteria = [...group.criteria];
|
|
3869
|
+
const position = at === void 0 ? criteria.length : Math.max(0, Math.min(at, criteria.length));
|
|
3870
|
+
criteria.splice(position, 0, criterion);
|
|
3871
|
+
return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria }));
|
|
3872
|
+
}
|
|
3873
|
+
/** Removes one group. */
|
|
3874
|
+
function criteriaBuilderRemoveGroup(value, groupIndex) {
|
|
3875
|
+
if (groupIndex < 0 || groupIndex >= value.groups.length) return value;
|
|
3876
|
+
return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: value.groups.filter((_, i) => i !== groupIndex) });
|
|
3877
|
+
}
|
|
3878
|
+
/** Inserts a copy of one group — every criterion cloned — before the original. */
|
|
3879
|
+
function criteriaBuilderDuplicateGroup(value, groupIndex, groupId, clone) {
|
|
3880
|
+
const group = value.groups[groupIndex];
|
|
3881
|
+
if (!group) return value;
|
|
3882
|
+
const copy = {
|
|
3883
|
+
id: groupId,
|
|
3884
|
+
logic: group.logic,
|
|
3885
|
+
criteria: group.criteria.map(clone)
|
|
3886
|
+
};
|
|
3887
|
+
const groups = [...value.groups];
|
|
3888
|
+
groups.splice(groupIndex, 0, copy);
|
|
3889
|
+
return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups });
|
|
3890
|
+
}
|
|
3891
|
+
const EDITABLE_TARGET = "input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [role=\"combobox\"], [role=\"textbox\"], [role=\"menu\"], [role=\"menuitem\"], [role=\"listbox\"], [role=\"option\"]";
|
|
3892
|
+
function isEditableTarget(target) {
|
|
3893
|
+
return target instanceof Element && target.closest(EDITABLE_TARGET) !== null;
|
|
3894
|
+
}
|
|
3895
|
+
function sectionKinds(kinds) {
|
|
3896
|
+
const sections = [];
|
|
3897
|
+
const byHeading = /* @__PURE__ */ new Map();
|
|
3898
|
+
for (const option of kinds) {
|
|
3899
|
+
let section = byHeading.get(option.group);
|
|
3900
|
+
if (!section) {
|
|
3901
|
+
section = {
|
|
3902
|
+
heading: option.group,
|
|
3903
|
+
entries: []
|
|
3904
|
+
};
|
|
3905
|
+
byHeading.set(option.group, section);
|
|
3906
|
+
sections.push(section);
|
|
3907
|
+
}
|
|
3908
|
+
section.entries.push({
|
|
3909
|
+
key: option.kind,
|
|
3910
|
+
kind: option.kind,
|
|
3911
|
+
negate: false,
|
|
3912
|
+
option
|
|
3913
|
+
});
|
|
3914
|
+
if (option.negatedLabel) section.entries.push({
|
|
3915
|
+
key: `${option.kind}:not`,
|
|
3916
|
+
kind: option.kind,
|
|
3917
|
+
negate: true,
|
|
3918
|
+
option
|
|
3919
|
+
});
|
|
3920
|
+
}
|
|
3921
|
+
return [...sections.filter((s) => s.heading === void 0), ...sections.filter((s) => s.heading !== void 0)];
|
|
3922
|
+
}
|
|
3923
|
+
function KindMenu({ kinds, menuLabel, triggerLabel, triggerAriaLabel, triggerIcon, disabled = false, disabledReason, variant = "ghost", onPick, addTarget }) {
|
|
3924
|
+
const sections = react.useMemo(() => sectionKinds(kinds), [kinds]);
|
|
3925
|
+
const trigger = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownTrigger, {
|
|
3926
|
+
disabled,
|
|
3927
|
+
"aria-label": triggerAriaLabel,
|
|
3928
|
+
title: disabled ? disabledReason : void 0,
|
|
3929
|
+
"data-criteria-add": addTarget,
|
|
3930
|
+
className: require_text_truncate.cn("inline-flex cursor-pointer items-center justify-center rounded-lg font-medium transition-colors", "h-[var(--opt-control-sm)] gap-[var(--opt-space-1-5)] px-[var(--opt-control-padding-sm)] text-xs", variant === "secondary" ? "border-border bg-surface text-text-primary hover:bg-bg-subtle active:bg-bg-muted border" : "text-text-secondary hover:bg-bg-subtle active:bg-bg-muted", "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50", "[&_svg]:size-3.5", require_text_truncate.OPT_FOCUS_VISIBLE),
|
|
3931
|
+
children: [triggerIcon, triggerLabel]
|
|
3932
|
+
});
|
|
3933
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownMenu, {
|
|
3934
|
+
animated: false,
|
|
3935
|
+
children: [trigger, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownContent, {
|
|
3936
|
+
"aria-label": menuLabel,
|
|
3937
|
+
"aria-labelledby": void 0,
|
|
3938
|
+
className: "min-w-56",
|
|
3939
|
+
children: sections.map((section, si) => {
|
|
3940
|
+
var _section$heading;
|
|
3941
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [
|
|
3942
|
+
si > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownSeparator, {}),
|
|
3943
|
+
section.heading !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3944
|
+
role: "presentation",
|
|
3945
|
+
className: "text-text-tertiary px-2 pt-1.5 pb-1 text-[11px] font-semibold tracking-wide uppercase",
|
|
3946
|
+
children: section.heading
|
|
3947
|
+
}),
|
|
3948
|
+
section.entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownItem, {
|
|
3949
|
+
onClick: () => onPick(entry.kind, entry.negate),
|
|
3950
|
+
className: "flex items-start gap-2",
|
|
3951
|
+
children: [entry.option.icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3952
|
+
className: "text-text-tertiary mt-0.5 shrink-0 [&_svg]:size-3.5",
|
|
3953
|
+
children: entry.option.icon
|
|
3954
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3955
|
+
className: "flex min-w-0 flex-col",
|
|
3956
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3957
|
+
className: require_text_truncate.cn("text-sm", entry.negate && "text-danger-fg"),
|
|
3958
|
+
children: entry.negate ? entry.option.negatedLabel : entry.option.label
|
|
3959
|
+
}), !entry.negate && entry.option.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3960
|
+
className: "text-text-tertiary text-xs",
|
|
3961
|
+
children: entry.option.description
|
|
3962
|
+
})]
|
|
3963
|
+
})]
|
|
3964
|
+
}, entry.key))
|
|
3965
|
+
] }, (_section$heading = section.heading) !== null && _section$heading !== void 0 ? _section$heading : "__none");
|
|
3966
|
+
})
|
|
3967
|
+
})]
|
|
3968
|
+
});
|
|
3969
|
+
}
|
|
3970
|
+
function IconAction({ icon, label, onClick, disabled = false, danger = false }) {
|
|
3971
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3972
|
+
type: "button",
|
|
3973
|
+
onClick,
|
|
3974
|
+
disabled,
|
|
3975
|
+
"aria-label": label,
|
|
3976
|
+
title: label,
|
|
3977
|
+
className: require_text_truncate.cn("inline-flex size-7 shrink-0 items-center justify-center rounded-md transition-colors [&_svg]:size-3.5", danger ? "text-text-tertiary hover:bg-danger-subtle hover:text-danger-fg" : "text-text-tertiary hover:bg-bg-muted hover:text-text-primary", "disabled:pointer-events-none disabled:opacity-40", require_text_truncate.OPT_FOCUS_VISIBLE),
|
|
3978
|
+
children: icon
|
|
3979
|
+
});
|
|
3980
|
+
}
|
|
3981
|
+
function LogicDivider({ label, emphasis }) {
|
|
3982
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3983
|
+
role: "separator",
|
|
3984
|
+
"aria-label": label,
|
|
3985
|
+
className: require_text_truncate.cn("flex items-center", emphasis === "root" ? "gap-group" : "gap-element"),
|
|
3986
|
+
children: [
|
|
3987
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: require_text_truncate.cn("h-px flex-1", emphasis === "root" ? "bg-border" : "bg-border-subtle") }),
|
|
3988
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3989
|
+
className: require_text_truncate.cn("text-[11px] font-semibold tracking-wide uppercase", emphasis === "root" ? "bg-bg-subtle text-text-secondary border-border rounded-full border px-2 py-0.5" : "text-text-tertiary"),
|
|
3990
|
+
children: label
|
|
3991
|
+
}),
|
|
3992
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: require_text_truncate.cn("h-px flex-1", emphasis === "root" ? "bg-border" : "bg-border-subtle") })
|
|
3993
|
+
]
|
|
3994
|
+
});
|
|
3995
|
+
}
|
|
3996
|
+
function Lettermark({ letter }) {
|
|
3997
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3998
|
+
"aria-hidden": "true",
|
|
3999
|
+
className: "bg-accent-subtle text-accent inline-flex size-6 shrink-0 items-center justify-center rounded-md text-xs font-semibold tabular-nums",
|
|
4000
|
+
children: letter
|
|
4001
|
+
});
|
|
4002
|
+
}
|
|
4003
|
+
/**
|
|
4004
|
+
* CriteriaBuilder — a two-level tree of criteria, edited as sentences.
|
|
4005
|
+
*
|
|
4006
|
+
* The builder owns what every criteria editor needs and nothing a particular
|
|
4007
|
+
* product does: groups and their AND/OR, the order of criteria, negation,
|
|
4008
|
+
* inline errors, the "add" menu, and the keyboard. The consumer owns the
|
|
4009
|
+
* criterion type and renders each one — usually as `Expression` chips whose
|
|
4010
|
+
* values open an editor — so the same shell serves a cohort of users, an
|
|
4011
|
+
* alert condition, or a feature-flag rollout without knowing which.
|
|
4012
|
+
*
|
|
4013
|
+
* Kinds the builder does not know render as an invalid row with a warning and
|
|
4014
|
+
* a replace/remove pair, never as some other kind's fields: a criterion saved
|
|
4015
|
+
* by a newer client should look broken, not silently different.
|
|
4016
|
+
*
|
|
4017
|
+
* @example
|
|
4018
|
+
* ```tsx
|
|
4019
|
+
* <CriteriaBuilder
|
|
4020
|
+
* value={value}
|
|
4021
|
+
* onChange={setValue}
|
|
4022
|
+
* kinds={[
|
|
4023
|
+
* { kind: "performed", label: "이벤트를 수행함", negatedLabel: "이벤트를 수행하지 않음" },
|
|
4024
|
+
* { kind: "property", label: "속성이 일치함" },
|
|
4025
|
+
* ]}
|
|
4026
|
+
* createCriterion={(kind, negate) => ({ id: nextId(), kind, negate, event: "" })}
|
|
4027
|
+
* renderCriterion={(c, api) => (
|
|
4028
|
+
* <ExpressionGroup>
|
|
4029
|
+
* <Expression description="이벤트" value={c.event} onClick={() => open(c.id)} />
|
|
4030
|
+
* </ExpressionGroup>
|
|
4031
|
+
* )}
|
|
4032
|
+
* />
|
|
4033
|
+
* ```
|
|
4034
|
+
*/
|
|
4035
|
+
function CriteriaBuilder({ value, onChange, kinds, createCriterion, renderCriterion, cloneCriterion, createGroupId, errors, maxGroups = 10, maxCriteriaPerGroup = 20, allowNegation = true, disabled = false, aside, labels: customLabels, className, "aria-label": ariaLabel }) {
|
|
4036
|
+
const labels = react.useMemo(() => require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$17), customLabels), [customLabels]);
|
|
4037
|
+
const baseId = react.useId().replace(/:/g, "");
|
|
4038
|
+
const nextGroupRef = react.useRef(1);
|
|
4039
|
+
const rootRef = react.useRef(null);
|
|
4040
|
+
const [pendingOpen, setPendingOpen] = react.useState(null);
|
|
4041
|
+
const knownKinds = react.useMemo(() => new Set(kinds.map((k) => k.kind)), [kinds]);
|
|
4042
|
+
const groupsFull = value.groups.length >= maxGroups;
|
|
4043
|
+
const newGroupId = react.useCallback(() => {
|
|
4044
|
+
const taken = collectIds(value);
|
|
4045
|
+
if (createGroupId) return uniqueId(createGroupId(), taken);
|
|
4046
|
+
let id = "";
|
|
4047
|
+
do
|
|
4048
|
+
id = `group-${nextGroupRef.current++}`;
|
|
4049
|
+
while (taken.has(id));
|
|
4050
|
+
return id;
|
|
4051
|
+
}, [createGroupId, value]);
|
|
4052
|
+
const clone = react.useCallback((criterion, taken) => {
|
|
4053
|
+
if (cloneCriterion) return cloneCriterion(criterion);
|
|
4054
|
+
const id = uniqueId(`${criterion.id}-copy`, taken);
|
|
4055
|
+
taken.add(id);
|
|
4056
|
+
return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, criterion), {}, { id });
|
|
4057
|
+
}, [cloneCriterion]);
|
|
4058
|
+
const addGroup = react.useCallback(() => {
|
|
4059
|
+
if (disabled || groupsFull) return null;
|
|
4060
|
+
const id = newGroupId();
|
|
4061
|
+
onChange(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: [...value.groups, {
|
|
4062
|
+
id,
|
|
4063
|
+
logic: "and",
|
|
4064
|
+
criteria: []
|
|
4065
|
+
}] }));
|
|
4066
|
+
return id;
|
|
4067
|
+
}, [
|
|
4068
|
+
disabled,
|
|
4069
|
+
groupsFull,
|
|
4070
|
+
newGroupId,
|
|
4071
|
+
onChange,
|
|
4072
|
+
value
|
|
4073
|
+
]);
|
|
4074
|
+
const addCriterion = react.useCallback((groupIndex, kind, negate) => {
|
|
4075
|
+
const group = value.groups[groupIndex];
|
|
4076
|
+
if (!group || group.criteria.length >= maxCriteriaPerGroup) return;
|
|
4077
|
+
onChange(criteriaBuilderInsert(value, groupIndex, createCriterion(kind, negate)));
|
|
4078
|
+
}, [
|
|
4079
|
+
createCriterion,
|
|
4080
|
+
maxCriteriaPerGroup,
|
|
4081
|
+
onChange,
|
|
4082
|
+
value
|
|
4083
|
+
]);
|
|
4084
|
+
const addFirst = react.useCallback((kind, negate) => {
|
|
4085
|
+
if (disabled) return;
|
|
4086
|
+
onChange(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: [{
|
|
4087
|
+
id: newGroupId(),
|
|
4088
|
+
logic: "and",
|
|
4089
|
+
criteria: [createCriterion(kind, negate)]
|
|
4090
|
+
}] }));
|
|
4091
|
+
}, [
|
|
4092
|
+
createCriterion,
|
|
4093
|
+
disabled,
|
|
4094
|
+
newGroupId,
|
|
4095
|
+
onChange,
|
|
4096
|
+
value
|
|
4097
|
+
]);
|
|
4098
|
+
const replaceCriterion = react.useCallback((groupIndex, index, kind, negate) => {
|
|
4099
|
+
const group = value.groups[groupIndex];
|
|
4100
|
+
const current = group === null || group === void 0 ? void 0 : group.criteria[index];
|
|
4101
|
+
if (!group || !current) return;
|
|
4102
|
+
const replacement = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, createCriterion(kind, negate)), {}, { id: current.id });
|
|
4103
|
+
onChange(replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria: group.criteria.map((c, i) => i === index ? replacement : c) })));
|
|
4104
|
+
}, [
|
|
4105
|
+
createCriterion,
|
|
4106
|
+
onChange,
|
|
4107
|
+
value
|
|
4108
|
+
]);
|
|
4109
|
+
const updateCriterion = react.useCallback((groupIndex, index, patch) => {
|
|
4110
|
+
const group = value.groups[groupIndex];
|
|
4111
|
+
if (!group) return;
|
|
4112
|
+
onChange(replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria: group.criteria.map((c, i) => i === index ? require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, c), patch) : c) })));
|
|
4113
|
+
}, [onChange, value]);
|
|
4114
|
+
const findAddTrigger = react.useCallback((groupId) => {
|
|
4115
|
+
var _rootRef$current$quer, _rootRef$current;
|
|
4116
|
+
return (_rootRef$current$quer = (_rootRef$current = rootRef.current) === null || _rootRef$current === void 0 ? void 0 : _rootRef$current.querySelector(`[data-criteria-add="${groupId.replace(/["\\]/g, "\\$&")}"]`)) !== null && _rootRef$current$quer !== void 0 ? _rootRef$current$quer : null;
|
|
4117
|
+
}, []);
|
|
4118
|
+
react.useEffect(() => {
|
|
4119
|
+
if (!pendingOpen) return;
|
|
4120
|
+
const trigger = findAddTrigger(pendingOpen);
|
|
4121
|
+
if (!trigger) return;
|
|
4122
|
+
setPendingOpen(null);
|
|
4123
|
+
trigger.focus();
|
|
4124
|
+
trigger.click();
|
|
4125
|
+
}, [
|
|
4126
|
+
findAddTrigger,
|
|
4127
|
+
pendingOpen,
|
|
4128
|
+
value
|
|
4129
|
+
]);
|
|
4130
|
+
const handleKeyDown = react.useCallback((event) => {
|
|
4131
|
+
if (disabled || event.defaultPrevented) return;
|
|
4132
|
+
if (event.altKey || event.ctrlKey || event.metaKey) return;
|
|
4133
|
+
if (isEditableTarget(event.target)) return;
|
|
4134
|
+
const key = event.key.toLowerCase();
|
|
4135
|
+
if (key === "g") {
|
|
4136
|
+
const id = addGroup();
|
|
4137
|
+
if (id) {
|
|
4138
|
+
event.preventDefault();
|
|
4139
|
+
setPendingOpen(id);
|
|
4140
|
+
}
|
|
4141
|
+
return;
|
|
4142
|
+
}
|
|
4143
|
+
if (key === "a") {
|
|
4144
|
+
const host = event.target instanceof Element ? event.target.closest("[data-criteria-group]") : null;
|
|
4145
|
+
const groupId = host === null || host === void 0 ? void 0 : host.dataset.criteriaGroup;
|
|
4146
|
+
const trigger = groupId ? findAddTrigger(groupId) : null;
|
|
4147
|
+
if (trigger && !trigger.disabled) {
|
|
4148
|
+
event.preventDefault();
|
|
4149
|
+
trigger.focus();
|
|
4150
|
+
trigger.click();
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
}, [
|
|
4154
|
+
addGroup,
|
|
4155
|
+
disabled,
|
|
4156
|
+
findAddTrigger
|
|
4157
|
+
]);
|
|
4158
|
+
const rootLogicOptions = react.useMemo(() => [{
|
|
4159
|
+
value: "and",
|
|
4160
|
+
label: labels.matchAllGroups
|
|
4161
|
+
}, {
|
|
4162
|
+
value: "or",
|
|
4163
|
+
label: labels.matchAnyGroup
|
|
4164
|
+
}], [labels]);
|
|
4165
|
+
const groupLogicOptions = react.useMemo(() => [{
|
|
4166
|
+
value: "and",
|
|
4167
|
+
label: labels.matchAllCriteria
|
|
4168
|
+
}, {
|
|
4169
|
+
value: "or",
|
|
4170
|
+
label: labels.matchAnyCriteria
|
|
4171
|
+
}], [labels]);
|
|
4172
|
+
const isEmpty = value.groups.length === 0;
|
|
4173
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4174
|
+
ref: rootRef,
|
|
4175
|
+
role: "group",
|
|
4176
|
+
"aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : labels.builder,
|
|
4177
|
+
className: require_text_truncate.cn("gap-section flex flex-col lg:flex-row", className),
|
|
4178
|
+
onKeyDown: handleKeyDown,
|
|
4179
|
+
"data-opt-id": "6F4JG",
|
|
4180
|
+
"data-opt-slug": "criteria-builder.CriteriaBuilder",
|
|
4181
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4182
|
+
className: "gap-group flex min-w-0 flex-1 flex-col",
|
|
4183
|
+
children: isEmpty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.EmptyState, {
|
|
4184
|
+
title: labels.emptyTitle,
|
|
4185
|
+
description: labels.emptyDescription,
|
|
4186
|
+
hasBorder: true,
|
|
4187
|
+
tone: "subdued",
|
|
4188
|
+
actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindMenu, {
|
|
4189
|
+
kinds,
|
|
4190
|
+
menuLabel: labels.kindMenuTitle,
|
|
4191
|
+
triggerLabel: labels.emptyAction,
|
|
4192
|
+
triggerAriaLabel: labels.emptyAction,
|
|
4193
|
+
triggerIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { "aria-hidden": "true" }),
|
|
4194
|
+
variant: "secondary",
|
|
4195
|
+
disabled,
|
|
4196
|
+
onPick: addFirst
|
|
4197
|
+
}),
|
|
4198
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4199
|
+
className: "gap-element inline-flex items-center",
|
|
4200
|
+
children: [
|
|
4201
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
|
|
4202
|
+
hint: true,
|
|
4203
|
+
children: "A"
|
|
4204
|
+
}),
|
|
4205
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
|
|
4206
|
+
hint: true,
|
|
4207
|
+
children: "G"
|
|
4208
|
+
}),
|
|
4209
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels.keyboardHint })
|
|
4210
|
+
]
|
|
4211
|
+
})
|
|
4212
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
4213
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
4214
|
+
className: "gap-group m-0 flex min-w-0 flex-wrap items-center border-0 p-0",
|
|
4215
|
+
children: [
|
|
4216
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
|
|
4217
|
+
className: "sr-only",
|
|
4218
|
+
children: labels.rootLogicLegend
|
|
4219
|
+
}),
|
|
4220
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_field_sidebar.SegmentedControl, {
|
|
4221
|
+
"aria-label": labels.rootLogicLegend,
|
|
4222
|
+
size: "sm",
|
|
4223
|
+
options: rootLogicOptions,
|
|
4224
|
+
value: value.logic,
|
|
4225
|
+
onChange: (logic) => onChange(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { logic })),
|
|
4226
|
+
disabled
|
|
4227
|
+
}),
|
|
4228
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4229
|
+
className: "text-text-tertiary gap-element hidden items-center text-xs sm:inline-flex",
|
|
4230
|
+
children: [
|
|
4231
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
|
|
4232
|
+
hint: true,
|
|
4233
|
+
children: "A"
|
|
4234
|
+
}),
|
|
4235
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
|
|
4236
|
+
hint: true,
|
|
4237
|
+
children: "G"
|
|
4238
|
+
}),
|
|
4239
|
+
labels.keyboardHint
|
|
4240
|
+
]
|
|
4241
|
+
})
|
|
4242
|
+
]
|
|
4243
|
+
}),
|
|
4244
|
+
value.groups.map((group, groupIndex) => {
|
|
4245
|
+
const letter = criteriaGroupLetter(groupIndex);
|
|
4246
|
+
const groupName = labels.groupLabel(letter);
|
|
4247
|
+
const groupLabelId = `${baseId}-${group.id}-label`;
|
|
4248
|
+
const groupError = errors === null || errors === void 0 ? void 0 : errors[group.id];
|
|
4249
|
+
const groupErrorId = `${baseId}-${group.id}-error`;
|
|
4250
|
+
const criteriaFull = group.criteria.length >= maxCriteriaPerGroup;
|
|
4251
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [groupIndex > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LogicDivider, {
|
|
4252
|
+
emphasis: "root",
|
|
4253
|
+
label: value.logic === "and" ? labels.and : labels.or
|
|
4254
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4255
|
+
role: "group",
|
|
4256
|
+
"aria-labelledby": groupLabelId,
|
|
4257
|
+
"aria-describedby": groupError ? groupErrorId : void 0,
|
|
4258
|
+
"data-criteria-group": group.id,
|
|
4259
|
+
"data-invalid": groupError ? true : void 0,
|
|
4260
|
+
className: require_text_truncate.cn("bg-bg-subtle gap-element flex flex-col rounded-lg border p-3", groupError ? "border-danger/40" : "border-border"),
|
|
4261
|
+
children: [
|
|
4262
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4263
|
+
id: groupLabelId,
|
|
4264
|
+
className: "sr-only",
|
|
4265
|
+
children: groupName
|
|
4266
|
+
}),
|
|
4267
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4268
|
+
className: "gap-element flex flex-wrap items-center justify-between",
|
|
4269
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4270
|
+
className: "gap-element flex items-center",
|
|
4271
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lettermark, { letter }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
4272
|
+
className: "m-0 border-0 p-0",
|
|
4273
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
|
|
4274
|
+
className: "sr-only",
|
|
4275
|
+
children: labels.groupLogicLegend(letter)
|
|
4276
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_field_sidebar.SegmentedControl, {
|
|
4277
|
+
"aria-label": labels.groupLogicLegend(letter),
|
|
4278
|
+
size: "sm",
|
|
4279
|
+
options: groupLogicOptions,
|
|
4280
|
+
value: group.logic,
|
|
4281
|
+
onChange: (logic) => onChange(replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { logic }))),
|
|
4282
|
+
disabled
|
|
4283
|
+
})]
|
|
4284
|
+
})]
|
|
4285
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4286
|
+
className: "flex items-center gap-0.5",
|
|
4287
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
|
|
4288
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Copy, { "aria-hidden": "true" }),
|
|
4289
|
+
label: labels.actionLabel(labels.duplicateGroup, groupName),
|
|
4290
|
+
disabled: disabled || groupsFull,
|
|
4291
|
+
onClick: () => {
|
|
4292
|
+
const taken = collectIds(value);
|
|
4293
|
+
const id = newGroupId();
|
|
4294
|
+
taken.add(id);
|
|
4295
|
+
onChange(criteriaBuilderDuplicateGroup(value, groupIndex, id, (c) => clone(c, taken)));
|
|
4296
|
+
}
|
|
4297
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
|
|
4298
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, { "aria-hidden": "true" }),
|
|
4299
|
+
label: labels.actionLabel(labels.removeGroup, groupName),
|
|
4300
|
+
disabled,
|
|
4301
|
+
danger: true,
|
|
4302
|
+
onClick: () => onChange(criteriaBuilderRemoveGroup(value, groupIndex))
|
|
4303
|
+
})]
|
|
4304
|
+
})]
|
|
4305
|
+
}),
|
|
4306
|
+
group.criteria.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4307
|
+
className: "text-text-tertiary text-xs",
|
|
4308
|
+
children: labels.emptyGroup
|
|
4309
|
+
}),
|
|
4310
|
+
group.criteria.map((criterion, index) => {
|
|
4311
|
+
const criterionName = labels.criterionLabel(letter, index + 1);
|
|
4312
|
+
const rowLabelId = `${baseId}-${criterion.id}-label`;
|
|
4313
|
+
const error = errors === null || errors === void 0 ? void 0 : errors[criterion.id];
|
|
4314
|
+
const errorId = `${baseId}-${criterion.id}-error`;
|
|
4315
|
+
const known = knownKinds.has(criterion.kind);
|
|
4316
|
+
const negated = criterion.negate === true;
|
|
4317
|
+
const api = {
|
|
4318
|
+
update: (patch) => updateCriterion(groupIndex, index, patch),
|
|
4319
|
+
invalid: Boolean(error) || !known,
|
|
4320
|
+
error,
|
|
4321
|
+
disabled,
|
|
4322
|
+
groupIndex,
|
|
4323
|
+
index
|
|
4324
|
+
};
|
|
4325
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LogicDivider, {
|
|
4326
|
+
emphasis: "group",
|
|
4327
|
+
label: group.logic === "and" ? labels.and : labels.or
|
|
4328
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4329
|
+
role: "group",
|
|
4330
|
+
"aria-labelledby": rowLabelId,
|
|
4331
|
+
"aria-describedby": error ? errorId : void 0,
|
|
4332
|
+
"data-criterion-kind": criterion.kind,
|
|
4333
|
+
"data-negated": negated || void 0,
|
|
4334
|
+
"data-invalid": error || !known ? true : void 0,
|
|
4335
|
+
className: require_text_truncate.cn("bg-surface gap-element flex flex-col rounded-md border p-2", error || !known ? "border-danger/40" : "border-border-subtle"),
|
|
4336
|
+
children: [
|
|
4337
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4338
|
+
id: rowLabelId,
|
|
4339
|
+
className: "sr-only",
|
|
4340
|
+
children: criterionName
|
|
4341
|
+
}),
|
|
4342
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4343
|
+
className: "gap-element flex flex-wrap items-start",
|
|
4344
|
+
children: [
|
|
4345
|
+
allowNegation && known && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4346
|
+
type: "button",
|
|
4347
|
+
"aria-pressed": negated,
|
|
4348
|
+
"aria-label": labels.actionLabel(labels.negate, criterionName),
|
|
4349
|
+
disabled,
|
|
4350
|
+
onClick: () => updateCriterion(groupIndex, index, { negate: !negated }),
|
|
4351
|
+
className: require_text_truncate.cn("inline-flex h-7 shrink-0 items-center rounded-md border px-2 text-[11px] font-semibold tracking-wide uppercase transition-colors", negated ? "border-danger/40 bg-danger-subtle text-danger-fg" : "border-border bg-bg-subtle text-text-tertiary hover:text-text-secondary", "disabled:pointer-events-none disabled:opacity-50", "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-ring-offset"),
|
|
4352
|
+
children: labels.negate
|
|
4353
|
+
}),
|
|
4354
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4355
|
+
className: "min-w-0 flex-1",
|
|
4356
|
+
children: known ? renderCriterion(criterion, api) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_field_sidebar.Callout, {
|
|
4357
|
+
tone: "warning",
|
|
4358
|
+
size: "sm",
|
|
4359
|
+
title: labels.unknownKind(criterion.kind),
|
|
4360
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.TriangleAlert, { "aria-hidden": "true" }),
|
|
4361
|
+
action: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindMenu, {
|
|
4362
|
+
kinds,
|
|
4363
|
+
menuLabel: labels.kindMenuTitle,
|
|
4364
|
+
triggerLabel: labels.replaceKind,
|
|
4365
|
+
triggerAriaLabel: labels.actionLabel(labels.replaceKind, criterionName),
|
|
4366
|
+
variant: "secondary",
|
|
4367
|
+
disabled,
|
|
4368
|
+
onPick: (kind, negate) => replaceCriterion(groupIndex, index, kind, negate)
|
|
4369
|
+
}),
|
|
4370
|
+
children: labels.unknownKindDescription
|
|
4371
|
+
})
|
|
4372
|
+
}),
|
|
4373
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4374
|
+
className: "flex items-center gap-0.5",
|
|
4375
|
+
children: [
|
|
4376
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
|
|
4377
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowUp, { "aria-hidden": "true" }),
|
|
4378
|
+
label: labels.actionLabel(labels.moveUp, criterionName),
|
|
4379
|
+
disabled: disabled || index === 0,
|
|
4380
|
+
onClick: () => onChange(criteriaBuilderMove(value, groupIndex, index, "up"))
|
|
4381
|
+
}),
|
|
4382
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
|
|
4383
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowDown, { "aria-hidden": "true" }),
|
|
4384
|
+
label: labels.actionLabel(labels.moveDown, criterionName),
|
|
4385
|
+
disabled: disabled || index === group.criteria.length - 1,
|
|
4386
|
+
onClick: () => onChange(criteriaBuilderMove(value, groupIndex, index, "down"))
|
|
4387
|
+
}),
|
|
4388
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
|
|
4389
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Copy, { "aria-hidden": "true" }),
|
|
4390
|
+
label: labels.actionLabel(labels.duplicateCriterion, criterionName),
|
|
4391
|
+
disabled: disabled || criteriaFull,
|
|
4392
|
+
onClick: () => onChange(criteriaBuilderDuplicate(value, groupIndex, index, (c) => clone(c, collectIds(value))))
|
|
4393
|
+
}),
|
|
4394
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
|
|
4395
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, { "aria-hidden": "true" }),
|
|
4396
|
+
label: labels.actionLabel(labels.removeCriterion, criterionName),
|
|
4397
|
+
disabled,
|
|
4398
|
+
danger: true,
|
|
4399
|
+
onClick: () => onChange(criteriaBuilderRemove(value, groupIndex, index))
|
|
4400
|
+
})
|
|
4401
|
+
]
|
|
4402
|
+
})
|
|
4403
|
+
]
|
|
4404
|
+
}),
|
|
4405
|
+
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4406
|
+
id: errorId,
|
|
4407
|
+
className: "text-danger-fg text-xs",
|
|
4408
|
+
children: error
|
|
4409
|
+
})
|
|
4410
|
+
]
|
|
4411
|
+
})] }, criterion.id);
|
|
4412
|
+
}),
|
|
4413
|
+
groupError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
4414
|
+
id: groupErrorId,
|
|
4415
|
+
className: "text-danger-fg text-xs",
|
|
4416
|
+
children: groupError
|
|
4417
|
+
}),
|
|
4418
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4419
|
+
className: "gap-element flex flex-wrap items-center",
|
|
4420
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindMenu, {
|
|
4421
|
+
kinds,
|
|
4422
|
+
menuLabel: labels.kindMenuTitle,
|
|
4423
|
+
triggerLabel: labels.addCriterion,
|
|
4424
|
+
triggerAriaLabel: labels.actionLabel(labels.addCriterion, groupName),
|
|
4425
|
+
triggerIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { "aria-hidden": "true" }),
|
|
4426
|
+
disabled: disabled || criteriaFull,
|
|
4427
|
+
disabledReason: labels.maxCriteriaReached(maxCriteriaPerGroup),
|
|
4428
|
+
onPick: (kind, negate) => addCriterion(groupIndex, kind, negate),
|
|
4429
|
+
addTarget: group.id
|
|
4430
|
+
}), criteriaFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4431
|
+
className: "text-text-tertiary text-xs",
|
|
4432
|
+
children: labels.maxCriteriaReached(maxCriteriaPerGroup)
|
|
4433
|
+
})]
|
|
4434
|
+
})
|
|
4435
|
+
]
|
|
4436
|
+
})] }, group.id);
|
|
4437
|
+
}),
|
|
4438
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4439
|
+
className: "gap-element flex flex-wrap items-center",
|
|
4440
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Button, {
|
|
4441
|
+
variant: "secondary",
|
|
4442
|
+
size: "sm",
|
|
4443
|
+
leftIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { "aria-hidden": "true" }),
|
|
4444
|
+
disabled: disabled || groupsFull,
|
|
4445
|
+
title: groupsFull ? labels.maxGroupsReached(maxGroups) : void 0,
|
|
4446
|
+
onClick: () => {
|
|
4447
|
+
const id = addGroup();
|
|
4448
|
+
if (id) setPendingOpen(id);
|
|
4449
|
+
},
|
|
4450
|
+
children: labels.addGroup
|
|
4451
|
+
}), groupsFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4452
|
+
className: "text-text-tertiary text-xs",
|
|
4453
|
+
children: labels.maxGroupsReached(maxGroups)
|
|
4454
|
+
})]
|
|
4455
|
+
})
|
|
4456
|
+
] })
|
|
4457
|
+
}), aside !== void 0 && aside !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
|
|
4458
|
+
className: "min-w-0 lg:w-72 lg:shrink-0",
|
|
4459
|
+
children: aside
|
|
4460
|
+
})]
|
|
4461
|
+
});
|
|
4462
|
+
}
|
|
4463
|
+
CriteriaBuilder.displayName = "CriteriaBuilder";
|
|
4464
|
+
//#endregion
|
|
4465
|
+
//#region src/shells/insights-panel.tsx
|
|
4466
|
+
const defaultLabels$16 = {
|
|
4467
|
+
title: "Insights",
|
|
4468
|
+
dismiss: "Dismiss",
|
|
4469
|
+
showDismissed: "Show dismissed",
|
|
4470
|
+
hideDismissed: "Hide dismissed",
|
|
4471
|
+
emptyTitle: "No insights",
|
|
4472
|
+
emptyDescription: "No anomalies or notable events detected.",
|
|
4473
|
+
detectionTitle: "Detection Settings",
|
|
4474
|
+
daysLabel: "Days",
|
|
4475
|
+
zScoreLabel: "Z-Score"
|
|
4476
|
+
};
|
|
4477
|
+
const severityConfig = {
|
|
4478
|
+
critical: {
|
|
4479
|
+
icon: "!!",
|
|
4480
|
+
color: "text-danger-fg",
|
|
4481
|
+
bg: "bg-danger-subtle border-danger"
|
|
4482
|
+
},
|
|
4483
|
+
warning: {
|
|
4484
|
+
icon: "!",
|
|
4485
|
+
color: "text-warning-fg",
|
|
4486
|
+
bg: "bg-warning-subtle border-warning"
|
|
4487
|
+
},
|
|
4488
|
+
info: {
|
|
4489
|
+
icon: "i",
|
|
4490
|
+
color: "text-info-fg",
|
|
4491
|
+
bg: "bg-info-subtle border-info"
|
|
4492
|
+
}
|
|
4493
|
+
};
|
|
4494
|
+
/** Renders the insights panel component. */
|
|
4495
|
+
function InsightsPanel({ insights, stats, detectionTypes, onDetectionTypeToggle, detectionConfig, onDetectionConfigChange, onDismiss, onInsightClick, onStatClick, header, actions, labels: customLabels, className }) {
|
|
4496
|
+
var _detectionConfig$days, _detectionConfig$zSco;
|
|
4497
|
+
const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$16), customLabels);
|
|
4498
|
+
const [showDismissed, setShowDismissed] = react.useState(false);
|
|
4499
|
+
const visibleInsights = showDismissed ? insights : insights.filter((i) => !i.dismissed);
|
|
4500
|
+
const hasStats = stats && stats.length > 0;
|
|
4501
|
+
const hasDetection = detectionTypes && detectionTypes.length > 0 || detectionConfig != null;
|
|
4502
|
+
const isEmpty = visibleInsights.length === 0;
|
|
4503
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4504
|
+
className: require_text_truncate.cn("gap-group flex flex-col", className),
|
|
4505
|
+
"data-opt-id": "HCYZV",
|
|
4506
|
+
"data-opt-slug": "insights-panel.InsightsPanel",
|
|
4507
|
+
children: [
|
|
4508
|
+
header || actions ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4509
|
+
className: "flex items-center justify-between",
|
|
4510
|
+
children: [header && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: header }), actions && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4511
|
+
className: "gap-element flex items-center",
|
|
4512
|
+
children: actions
|
|
4513
|
+
})]
|
|
4514
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4515
|
+
className: "flex items-center justify-between",
|
|
4057
4516
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
4058
4517
|
className: "text-text-primary text-lg font-semibold",
|
|
4059
4518
|
children: labels.title
|
|
@@ -4408,17 +4867,17 @@ function ExportButton({ data, columns, fileName = "export", formats = ["csv", "j
|
|
|
4408
4867
|
})
|
|
4409
4868
|
})]
|
|
4410
4869
|
});
|
|
4411
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4870
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownMenu, {
|
|
4412
4871
|
"data-opt-id": "MGP2B",
|
|
4413
4872
|
"data-opt-slug": "export-button.ExportButton",
|
|
4414
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
4873
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownTrigger, {
|
|
4415
4874
|
className: require_text_truncate.cn("inline-flex items-center justify-center rounded-lg font-medium transition-colors", "border-border bg-surface text-text-primary hover:bg-bg-subtle active:bg-bg-muted border", "h-8 gap-1.5 px-3 text-xs", className),
|
|
4416
4875
|
"aria-label": labels.export,
|
|
4417
4876
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4418
4877
|
"aria-hidden": "true",
|
|
4419
4878
|
children: "⬇"
|
|
4420
4879
|
}), labels.export]
|
|
4421
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
4880
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownContent, { children: formats.map((fmt, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [i > 0 && fmt === "pdf" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownSeparator, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownItem, {
|
|
4422
4881
|
onClick: () => handleExport(fmt),
|
|
4423
4882
|
children: formatLabels[fmt]
|
|
4424
4883
|
})] }, fmt)) })]
|
|
@@ -4565,28 +5024,6 @@ function matchesQueryObject(query, row, options = {}) {
|
|
|
4565
5024
|
return matchesQuery(query, read, searchable);
|
|
4566
5025
|
}
|
|
4567
5026
|
//#endregion
|
|
4568
|
-
//#region src/lib/use-media-query.ts
|
|
4569
|
-
/**
|
|
4570
|
-
* Whether a media query matches, kept in sync with the browser.
|
|
4571
|
-
*
|
|
4572
|
-
* `useSyncExternalStore` rather than an effect: a layout that switches on width
|
|
4573
|
-
* must not render the wrong shape for a frame first. The server snapshot is the
|
|
4574
|
-
* caller's `serverFallback`, because the server does not know the viewport and
|
|
4575
|
-
* guessing "narrow" collapses a wide layout on every first paint.
|
|
4576
|
-
*
|
|
4577
|
-
* Internal. Exported from `lib` for the components in this package, not from
|
|
4578
|
-
* the package barrel — a hook that answers "is this viewport wide" invites
|
|
4579
|
-
* layout decisions that belong in CSS.
|
|
4580
|
-
*/
|
|
4581
|
-
function useMediaQuery(query, serverFallback = false) {
|
|
4582
|
-
return (0, react.useSyncExternalStore)((onChange) => {
|
|
4583
|
-
if (typeof window === "undefined") return () => {};
|
|
4584
|
-
const list = window.matchMedia(query);
|
|
4585
|
-
list.addEventListener("change", onChange);
|
|
4586
|
-
return () => list.removeEventListener("change", onChange);
|
|
4587
|
-
}, () => typeof window === "undefined" ? serverFallback : window.matchMedia(query).matches, () => serverFallback);
|
|
4588
|
-
}
|
|
4589
|
-
//#endregion
|
|
4590
5027
|
//#region src/shells/inspector-layout.tsx
|
|
4591
5028
|
/** Tailwind needs whole class names, so the queries and widths are literals. */
|
|
4592
5029
|
const breakpointQuery = {
|
|
@@ -4635,7 +5072,7 @@ const flyoutSize = {
|
|
|
4635
5072
|
* ```
|
|
4636
5073
|
*/
|
|
4637
5074
|
function InspectorLayout({ children, inspector, open, onClose, title, description, actions, footer, breakpoint = "xl", width = "md", labels, className }) {
|
|
4638
|
-
const canPush = useMediaQuery(breakpointQuery[breakpoint], true);
|
|
5075
|
+
const canPush = require_field_sidebar.useMediaQuery(breakpointQuery[breakpoint], true);
|
|
4639
5076
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4640
5077
|
className: require_text_truncate.cn("flex min-w-0 items-stretch gap-group", className),
|
|
4641
5078
|
"data-opt-id": "MN44T",
|
|
@@ -4859,13 +5296,13 @@ function CatalogRowActions({ item, actions, visibleCount = 2, labels }) {
|
|
|
4859
5296
|
size: "sm",
|
|
4860
5297
|
onClick: () => action.onSelect(item),
|
|
4861
5298
|
children: [action.icon, action.label]
|
|
4862
|
-
}, action.id)), overflow.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
5299
|
+
}, action.id)), overflow.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownTrigger, {
|
|
4863
5300
|
"aria-label": (_labels$moreActions = labels === null || labels === void 0 ? void 0 : labels.moreActions) !== null && _labels$moreActions !== void 0 ? _labels$moreActions : "더 보기",
|
|
4864
5301
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.MoreHorizontal, {
|
|
4865
5302
|
"aria-hidden": "true",
|
|
4866
5303
|
className: "size-4"
|
|
4867
5304
|
})
|
|
4868
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5305
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownContent, { children: overflow.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownItem, {
|
|
4869
5306
|
onClick: () => action.onSelect(item),
|
|
4870
5307
|
children: action.label
|
|
4871
5308
|
}, action.id)) })] })]
|
|
@@ -5122,853 +5559,6 @@ function ComparisonSelector({ segments, valueA, valueB, onChangeA, onChangeB, va
|
|
|
5122
5559
|
});
|
|
5123
5560
|
}
|
|
5124
5561
|
ComparisonSelector.displayName = "ComparisonSelector";
|
|
5125
|
-
const THEME_REGISTRY = {
|
|
5126
|
-
default: {
|
|
5127
|
-
id: "default",
|
|
5128
|
-
label: "Default",
|
|
5129
|
-
description: "Blue accent, balanced radius & shadow",
|
|
5130
|
-
palette: {
|
|
5131
|
-
seed: "#2563eb",
|
|
5132
|
-
harmony: "split-complementary",
|
|
5133
|
-
radiusScale: "medium",
|
|
5134
|
-
shadowIntensity: "subtle",
|
|
5135
|
-
neutralTemperature: "cool"
|
|
5136
|
-
},
|
|
5137
|
-
switcherSwatches: [
|
|
5138
|
-
"hsl(221 83% 53%)",
|
|
5139
|
-
"hsl(142 71% 45%)",
|
|
5140
|
-
"hsl(38 92% 50%)"
|
|
5141
|
-
]
|
|
5142
|
-
},
|
|
5143
|
-
minimal: {
|
|
5144
|
-
id: "minimal",
|
|
5145
|
-
label: "Minimal",
|
|
5146
|
-
description: "Monochrome, no shadow, sharp edges",
|
|
5147
|
-
palette: {
|
|
5148
|
-
seed: "#333333",
|
|
5149
|
-
harmony: "analogous",
|
|
5150
|
-
radiusScale: "sharp",
|
|
5151
|
-
shadowIntensity: "none",
|
|
5152
|
-
neutralTemperature: "cool"
|
|
5153
|
-
},
|
|
5154
|
-
switcherSwatches: [
|
|
5155
|
-
"hsl(0 0% 20%)",
|
|
5156
|
-
"hsl(0 0% 45%)",
|
|
5157
|
-
"hsl(0 0% 70%)"
|
|
5158
|
-
]
|
|
5159
|
-
},
|
|
5160
|
-
natural: {
|
|
5161
|
-
id: "natural",
|
|
5162
|
-
label: "Natural",
|
|
5163
|
-
description: "Always light — sage accent, warm cream",
|
|
5164
|
-
forceLightOnly: true,
|
|
5165
|
-
palette: {
|
|
5166
|
-
seed: "#5a9376",
|
|
5167
|
-
harmony: "complementary",
|
|
5168
|
-
radiusScale: "medium",
|
|
5169
|
-
shadowIntensity: "subtle",
|
|
5170
|
-
neutralTemperature: "warm"
|
|
5171
|
-
},
|
|
5172
|
-
switcherSwatches: [
|
|
5173
|
-
"hsl(155 38% 45%)",
|
|
5174
|
-
"hsl(25 65% 55%)",
|
|
5175
|
-
"hsl(45 75% 50%)"
|
|
5176
|
-
]
|
|
5177
|
-
},
|
|
5178
|
-
pro: {
|
|
5179
|
-
id: "pro",
|
|
5180
|
-
label: "Pro",
|
|
5181
|
-
description: "Neon blue accent, mono headings, ultra-dense",
|
|
5182
|
-
palette: {
|
|
5183
|
-
seed: "#0080ff",
|
|
5184
|
-
harmony: "tetradic",
|
|
5185
|
-
radiusScale: "sharp",
|
|
5186
|
-
shadowIntensity: "subtle",
|
|
5187
|
-
neutralTemperature: "cool"
|
|
5188
|
-
},
|
|
5189
|
-
switcherSwatches: [
|
|
5190
|
-
"hsl(210 100% 55%)",
|
|
5191
|
-
"hsl(170 90% 48%)",
|
|
5192
|
-
"hsl(290 85% 60%)"
|
|
5193
|
-
]
|
|
5194
|
-
},
|
|
5195
|
-
"mono-dark": {
|
|
5196
|
-
id: "mono-dark",
|
|
5197
|
-
label: "Mono Dark",
|
|
5198
|
-
description: "OLED-friendly black, neon cyan accent, mono headings",
|
|
5199
|
-
palette: {
|
|
5200
|
-
seed: "#00d4ff",
|
|
5201
|
-
harmony: "tetradic",
|
|
5202
|
-
radiusScale: "sharp",
|
|
5203
|
-
shadowIntensity: "subtle",
|
|
5204
|
-
neutralTemperature: "cool"
|
|
5205
|
-
},
|
|
5206
|
-
switcherSwatches: [
|
|
5207
|
-
"hsl(190 100% 50%)",
|
|
5208
|
-
"hsl(0 0% 8%)",
|
|
5209
|
-
"hsl(280 90% 65%)"
|
|
5210
|
-
]
|
|
5211
|
-
}
|
|
5212
|
-
};
|
|
5213
|
-
/** All registered preset ids in declaration order. */
|
|
5214
|
-
const THEME_PRESET_IDS = Object.keys(THEME_REGISTRY);
|
|
5215
|
-
/** Look up a descriptor by id. Returns `undefined` for unknown ids. */
|
|
5216
|
-
function getThemeDescriptor(id) {
|
|
5217
|
-
return THEME_REGISTRY[id];
|
|
5218
|
-
}
|
|
5219
|
-
/** Type guard for a known preset id. */
|
|
5220
|
-
function isThemePresetId(id) {
|
|
5221
|
-
return id in THEME_REGISTRY;
|
|
5222
|
-
}
|
|
5223
|
-
/** Preset ids that suppress dark mode generation. */
|
|
5224
|
-
const FORCE_LIGHT_PRESET_IDS = new Set(THEME_PRESET_IDS.filter((id) => THEME_REGISTRY[id].forceLightOnly));
|
|
5225
|
-
/**
|
|
5226
|
-
* Map from removed preset ids to the closest surviving preset. Boot script and
|
|
5227
|
-
* `readStoredTheme` consult this so users with persisted `corporate`/`playful`
|
|
5228
|
-
* values silently land on a working preset on next page load instead of
|
|
5229
|
-
* showing the global default fallback for an unknown id.
|
|
5230
|
-
*
|
|
5231
|
-
* Keep this around indefinitely — localStorage values are forever and the
|
|
5232
|
-
* cost of two extra entries is negligible.
|
|
5233
|
-
*/
|
|
5234
|
-
const DEPRECATED_PRESET_MIGRATIONS = Object.freeze({
|
|
5235
|
-
corporate: "default",
|
|
5236
|
-
playful: "default"
|
|
5237
|
-
});
|
|
5238
|
-
/**
|
|
5239
|
-
* Resolve a possibly-deprecated preset id to a registered one. Returns the
|
|
5240
|
-
* input unchanged when it is already valid; returns the migration target when
|
|
5241
|
-
* it is a known deprecated id; returns `null` when the id is unknown
|
|
5242
|
-
* altogether (caller should fall back to its default).
|
|
5243
|
-
*/
|
|
5244
|
-
function migrateDeprecatedPresetId(id) {
|
|
5245
|
-
if (!id) return null;
|
|
5246
|
-
if (isThemePresetId(id)) return id;
|
|
5247
|
-
if (id in DEPRECATED_PRESET_MIGRATIONS) return DEPRECATED_PRESET_MIGRATIONS[id];
|
|
5248
|
-
return null;
|
|
5249
|
-
}
|
|
5250
|
-
//#endregion
|
|
5251
|
-
//#region src/lib/theme/theme-types.ts
|
|
5252
|
-
/**
|
|
5253
|
-
* Author canonical theme overrides with token-name autocomplete.
|
|
5254
|
-
* ThemeOverrides remains broad for backward compatibility with older custom
|
|
5255
|
-
* variables; new themes should use this helper as the governed entry point.
|
|
5256
|
-
*/
|
|
5257
|
-
function defineThemeOverrides(overrides) {
|
|
5258
|
-
return overrides;
|
|
5259
|
-
}
|
|
5260
|
-
/** Construct a `PresetThemeSpec` — convenience for the common case. */
|
|
5261
|
-
function presetTheme(preset, overrides) {
|
|
5262
|
-
return overrides ? {
|
|
5263
|
-
kind: "preset",
|
|
5264
|
-
preset,
|
|
5265
|
-
overrides
|
|
5266
|
-
} : {
|
|
5267
|
-
kind: "preset",
|
|
5268
|
-
preset
|
|
5269
|
-
};
|
|
5270
|
-
}
|
|
5271
|
-
/** Construct a `GeneratedThemeSpec` from an inline `PaletteConfig`. */
|
|
5272
|
-
function generatedTheme(palette, options) {
|
|
5273
|
-
return require_text_truncate._objectSpread2({
|
|
5274
|
-
kind: "generated",
|
|
5275
|
-
palette
|
|
5276
|
-
}, options);
|
|
5277
|
-
}
|
|
5278
|
-
/** True when `spec` references a registered preset id. */
|
|
5279
|
-
function isPresetSpec(spec) {
|
|
5280
|
-
return spec.kind === "preset";
|
|
5281
|
-
}
|
|
5282
|
-
/** True when `spec` carries an inline `PaletteConfig`. */
|
|
5283
|
-
function isGeneratedSpec(spec) {
|
|
5284
|
-
return spec.kind === "generated";
|
|
5285
|
-
}
|
|
5286
|
-
/** True when `spec` wraps a fully-formed `ThemeDescriptor`. */
|
|
5287
|
-
function isDescriptorSpec(spec) {
|
|
5288
|
-
return spec.kind === "descriptor";
|
|
5289
|
-
}
|
|
5290
|
-
//#endregion
|
|
5291
|
-
//#region src/lib/theme/theme-serialize.ts
|
|
5292
|
-
/**
|
|
5293
|
-
* theme-serialize.ts
|
|
5294
|
-
*
|
|
5295
|
-
* Pure helpers that turn a `ThemeSpec` into the artifacts the runtime needs:
|
|
5296
|
-
* resolved descriptor + mode, computed token maps for generated palettes, and
|
|
5297
|
-
* `<style>` CSS strings ready to be injected into `<head>`.
|
|
5298
|
-
*
|
|
5299
|
-
* Kept side-effect free so the boot script and the provider can share the
|
|
5300
|
-
* same logic without dragging React into the client bundle's critical path.
|
|
5301
|
-
*/
|
|
5302
|
-
/** Element id used for the global generated theme style tag. */
|
|
5303
|
-
const GLOBAL_THEME_STYLE_ID = "opt-global-theme";
|
|
5304
|
-
/** localStorage key for the persisted ThemeSpec (generated mode). */
|
|
5305
|
-
const THEME_SPEC_STORAGE_KEY = "opt-theme-spec";
|
|
5306
|
-
/**
|
|
5307
|
-
* localStorage key for the cached, pre-serialized token maps that match the
|
|
5308
|
-
* spec under `THEME_SPEC_STORAGE_KEY`. The boot script reads this directly so
|
|
5309
|
-
* it can inline tokens without invoking opt-palette at startup.
|
|
5310
|
-
*/
|
|
5311
|
-
const THEME_TOKENS_STORAGE_KEY = "opt-theme-tokens";
|
|
5312
|
-
/** Stable id used for unnamed generated themes. */
|
|
5313
|
-
const GENERATED_THEME_ID_DEFAULT = "generated";
|
|
5314
|
-
/** Cached token maps keyed by spec hash. Lazy-built per process. */
|
|
5315
|
-
const generatedCache = /* @__PURE__ */ new Map();
|
|
5316
|
-
/** Build a stable cache key for a `PaletteConfig`. */
|
|
5317
|
-
function paletteCacheKey(config) {
|
|
5318
|
-
return JSON.stringify(config);
|
|
5319
|
-
}
|
|
5320
|
-
/** Run opt-palette with caching. */
|
|
5321
|
-
function generatePaletteCached(config) {
|
|
5322
|
-
const key = paletteCacheKey(config);
|
|
5323
|
-
let cached = generatedCache.get(key);
|
|
5324
|
-
if (!cached) {
|
|
5325
|
-
cached = (0, _reopt_ai_opt_palette.generatePalette)(config);
|
|
5326
|
-
generatedCache.set(key, cached);
|
|
5327
|
-
}
|
|
5328
|
-
return cached;
|
|
5329
|
-
}
|
|
5330
|
-
/** Apply sparse override maps onto a base token record. */
|
|
5331
|
-
function applyOverrides(base, overrides, mode) {
|
|
5332
|
-
if (!overrides) return base;
|
|
5333
|
-
const merged = require_text_truncate._objectSpread2({}, base);
|
|
5334
|
-
if (overrides.shared) Object.assign(merged, overrides.shared);
|
|
5335
|
-
const modeOverrides = mode === "light" ? overrides.light : overrides.dark;
|
|
5336
|
-
if (modeOverrides) Object.assign(merged, modeOverrides);
|
|
5337
|
-
return merged;
|
|
5338
|
-
}
|
|
5339
|
-
/**
|
|
5340
|
-
* Stable id used in `<html data-theme>` and the `<style>` selector.
|
|
5341
|
-
* - preset → the preset id (force-light) or `${id}` / `${id}-dark`
|
|
5342
|
-
* - generated → `spec.id ?? "generated"` with `-dark` suffix when applicable
|
|
5343
|
-
* - descriptor → `descriptor.id` with same suffix logic
|
|
5344
|
-
*/
|
|
5345
|
-
function getCompoundIdForSpec(spec, resolvedMode, forceLightOnly) {
|
|
5346
|
-
const baseId = baseIdFor(spec);
|
|
5347
|
-
if (forceLightOnly) return baseId;
|
|
5348
|
-
return resolvedMode === "dark" ? `${baseId}-dark` : baseId;
|
|
5349
|
-
}
|
|
5350
|
-
function baseIdFor(spec) {
|
|
5351
|
-
var _spec$id;
|
|
5352
|
-
if (isPresetSpec(spec)) return spec.preset;
|
|
5353
|
-
if (isDescriptorSpec(spec)) return spec.descriptor.id;
|
|
5354
|
-
return (_spec$id = spec.id) !== null && _spec$id !== void 0 ? _spec$id : GENERATED_THEME_ID_DEFAULT;
|
|
5355
|
-
}
|
|
5356
|
-
/** Whether the given spec emits dark variants at all. */
|
|
5357
|
-
function isForceLightSpec(spec) {
|
|
5358
|
-
if (isPresetSpec(spec)) {
|
|
5359
|
-
const desc = THEME_REGISTRY[spec.preset];
|
|
5360
|
-
return (desc === null || desc === void 0 ? void 0 : desc.forceLightOnly) === true;
|
|
5361
|
-
}
|
|
5362
|
-
if (isDescriptorSpec(spec)) return spec.descriptor.forceLightOnly === true;
|
|
5363
|
-
return spec.forceLightOnly === true;
|
|
5364
|
-
}
|
|
5365
|
-
/**
|
|
5366
|
-
* Compute the inline tokens for a `GeneratedThemeSpec` or
|
|
5367
|
-
* `DescriptorThemeSpec` whose descriptor carries a `palette`. Returns `null`
|
|
5368
|
-
* for preset specs (their tokens live in the static CSS files).
|
|
5369
|
-
*/
|
|
5370
|
-
function computeGeneratedTokens(spec) {
|
|
5371
|
-
if (isPresetSpec(spec)) return null;
|
|
5372
|
-
let palette;
|
|
5373
|
-
let overrides;
|
|
5374
|
-
let id;
|
|
5375
|
-
let forceLight;
|
|
5376
|
-
if (isGeneratedSpec(spec)) {
|
|
5377
|
-
var _spec$id2;
|
|
5378
|
-
palette = spec.palette;
|
|
5379
|
-
overrides = spec.overrides;
|
|
5380
|
-
id = (_spec$id2 = spec.id) !== null && _spec$id2 !== void 0 ? _spec$id2 : GENERATED_THEME_ID_DEFAULT;
|
|
5381
|
-
forceLight = spec.forceLightOnly === true;
|
|
5382
|
-
} else {
|
|
5383
|
-
palette = spec.descriptor.palette;
|
|
5384
|
-
overrides = spec.overrides;
|
|
5385
|
-
id = spec.descriptor.id;
|
|
5386
|
-
forceLight = spec.descriptor.forceLightOnly === true;
|
|
5387
|
-
}
|
|
5388
|
-
if (!palette) return null;
|
|
5389
|
-
const generated = generatePaletteCached(palette);
|
|
5390
|
-
return {
|
|
5391
|
-
id,
|
|
5392
|
-
light: applyOverrides(generated.light, overrides, "light"),
|
|
5393
|
-
dark: forceLight ? null : applyOverrides(generated.dark, overrides, "dark")
|
|
5394
|
-
};
|
|
5395
|
-
}
|
|
5396
|
-
/**
|
|
5397
|
-
* Serialize a token record into a CSS rule body — `--name:value;...` — without
|
|
5398
|
-
* surrounding selector or braces. Values are not escaped; callers are
|
|
5399
|
-
* responsible for trusted input. Boot script and provider both rely on this
|
|
5400
|
-
* shape.
|
|
5401
|
-
*/
|
|
5402
|
-
function serializeTokenBody(tokens) {
|
|
5403
|
-
return Object.entries(tokens).map(([k, v]) => `${k}:${v}`).join(";");
|
|
5404
|
-
}
|
|
5405
|
-
/**
|
|
5406
|
-
* Build a CSS rule scoped to `[data-theme="<id>"]`.
|
|
5407
|
-
*/
|
|
5408
|
-
function serializeThemeRule(themeId, tokens) {
|
|
5409
|
-
return `[data-theme="${themeId}"]{${serializeTokenBody(tokens)}}`;
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Build the full CSS for a generated theme style tag — covers light + dark
|
|
5413
|
-
* selectors based on the computed tokens. Caller chooses the id used in
|
|
5414
|
-
* the selector (typically the spec base id).
|
|
5415
|
-
*/
|
|
5416
|
-
function serializeGeneratedTheme(tokens) {
|
|
5417
|
-
const { id, light, dark } = tokens;
|
|
5418
|
-
let css = serializeThemeRule(id, light);
|
|
5419
|
-
if (dark) css += serializeThemeRule(`${id}-dark`, dark);
|
|
5420
|
-
return css;
|
|
5421
|
-
}
|
|
5422
|
-
/**
|
|
5423
|
-
* Resolve a spec into its descriptor counterpart. Preset specs map to
|
|
5424
|
-
* `THEME_REGISTRY[preset]`. Generated specs are wrapped into a synthetic
|
|
5425
|
-
* descriptor so callers can treat them uniformly.
|
|
5426
|
-
*/
|
|
5427
|
-
function resolveDescriptor(spec) {
|
|
5428
|
-
if (isPresetSpec(spec)) {
|
|
5429
|
-
const desc = THEME_REGISTRY[spec.preset];
|
|
5430
|
-
if (!desc) throw new Error(`[opt-ui] Unknown theme preset id: "${spec.preset}". Registered ids: ${Object.keys(THEME_REGISTRY).join(", ")}`);
|
|
5431
|
-
return desc;
|
|
5432
|
-
}
|
|
5433
|
-
if (isDescriptorSpec(spec)) return spec.descriptor;
|
|
5434
|
-
return generatedSpecToDescriptor(spec);
|
|
5435
|
-
}
|
|
5436
|
-
function generatedSpecToDescriptor(spec) {
|
|
5437
|
-
var _spec$id3, _spec$label;
|
|
5438
|
-
return {
|
|
5439
|
-
id: (_spec$id3 = spec.id) !== null && _spec$id3 !== void 0 ? _spec$id3 : GENERATED_THEME_ID_DEFAULT,
|
|
5440
|
-
label: (_spec$label = spec.label) !== null && _spec$label !== void 0 ? _spec$label : "Custom",
|
|
5441
|
-
description: "Generated theme",
|
|
5442
|
-
palette: spec.palette,
|
|
5443
|
-
forceLightOnly: spec.forceLightOnly
|
|
5444
|
-
};
|
|
5445
|
-
}
|
|
5446
|
-
/**
|
|
5447
|
-
* Validate a `ThemeSpec` parsed from localStorage. Returns the spec on
|
|
5448
|
-
* success or `null` if any required field is missing or the preset id is
|
|
5449
|
-
* unknown. Defensive parsing — never throws.
|
|
5450
|
-
*/
|
|
5451
|
-
function safeParseStoredSpec(json) {
|
|
5452
|
-
if (!json) return null;
|
|
5453
|
-
try {
|
|
5454
|
-
const parsed = JSON.parse(json);
|
|
5455
|
-
if (!parsed || typeof parsed !== "object" || !("kind" in parsed)) return null;
|
|
5456
|
-
if (parsed.kind === "preset") {
|
|
5457
|
-
const preset = parsed.preset;
|
|
5458
|
-
if (typeof preset !== "string" || !isThemePresetId(preset)) return null;
|
|
5459
|
-
return {
|
|
5460
|
-
kind: "preset",
|
|
5461
|
-
preset
|
|
5462
|
-
};
|
|
5463
|
-
}
|
|
5464
|
-
if (parsed.kind === "generated") {
|
|
5465
|
-
const palette = parsed.palette;
|
|
5466
|
-
if (!isPaletteConfig(palette)) return null;
|
|
5467
|
-
return {
|
|
5468
|
-
kind: "generated",
|
|
5469
|
-
palette,
|
|
5470
|
-
id: typeof parsed.id === "string" ? parsed.id : void 0,
|
|
5471
|
-
label: typeof parsed.label === "string" ? parsed.label : void 0,
|
|
5472
|
-
forceLightOnly: parsed.forceLightOnly === true,
|
|
5473
|
-
overrides: isObjectMap(parsed.overrides) ? parsed.overrides : void 0
|
|
5474
|
-
};
|
|
5475
|
-
}
|
|
5476
|
-
return null;
|
|
5477
|
-
} catch (_unused) {
|
|
5478
|
-
return null;
|
|
5479
|
-
}
|
|
5480
|
-
}
|
|
5481
|
-
function isObjectMap(value) {
|
|
5482
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
5483
|
-
}
|
|
5484
|
-
function isPaletteConfig(value) {
|
|
5485
|
-
if (!isObjectMap(value)) return false;
|
|
5486
|
-
const v = value;
|
|
5487
|
-
return typeof v.seed === "string" && typeof v.harmony === "string" && typeof v.radiusScale === "string" && typeof v.shadowIntensity === "string" && typeof v.neutralTemperature === "string";
|
|
5488
|
-
}
|
|
5489
|
-
/**
|
|
5490
|
-
* Parse the cached token payload from localStorage. Returns `null` on any
|
|
5491
|
-
* shape mismatch — caller will recompute from the spec.
|
|
5492
|
-
*/
|
|
5493
|
-
function safeParseStoredTokens(json) {
|
|
5494
|
-
if (!json) return null;
|
|
5495
|
-
try {
|
|
5496
|
-
const parsed = JSON.parse(json);
|
|
5497
|
-
if (!parsed || typeof parsed.id !== "string" || !isObjectMap(parsed.light)) return null;
|
|
5498
|
-
return {
|
|
5499
|
-
id: parsed.id,
|
|
5500
|
-
light: parsed.light,
|
|
5501
|
-
dark: isObjectMap(parsed.dark) ? parsed.dark : void 0
|
|
5502
|
-
};
|
|
5503
|
-
} catch (_unused2) {
|
|
5504
|
-
return null;
|
|
5505
|
-
}
|
|
5506
|
-
}
|
|
5507
|
-
/** Build the storage payload that pairs with `opt-theme-spec`. */
|
|
5508
|
-
function buildTokenCache(tokens) {
|
|
5509
|
-
var _tokens$dark;
|
|
5510
|
-
return {
|
|
5511
|
-
id: tokens.id,
|
|
5512
|
-
light: tokens.light,
|
|
5513
|
-
dark: (_tokens$dark = tokens.dark) !== null && _tokens$dark !== void 0 ? _tokens$dark : void 0
|
|
5514
|
-
};
|
|
5515
|
-
}
|
|
5516
|
-
//#endregion
|
|
5517
|
-
//#region src/lib/theme/theme-resolution.ts
|
|
5518
|
-
/**
|
|
5519
|
-
* Registered preset id list. Preferred for runtime iteration.
|
|
5520
|
-
* @deprecated Prefer `THEME_PRESET_IDS` from `./presets`.
|
|
5521
|
-
*/
|
|
5522
|
-
const THEME_PRESET_VALUES = THEME_PRESET_IDS;
|
|
5523
|
-
const THEME_MODE_VALUES = [
|
|
5524
|
-
"light",
|
|
5525
|
-
"dark",
|
|
5526
|
-
"system"
|
|
5527
|
-
];
|
|
5528
|
-
const LEGACY_THEME_STORAGE_KEY = "opt-theme";
|
|
5529
|
-
const THEME_PRESET_STORAGE_KEY = "opt-preset";
|
|
5530
|
-
const THEME_MODE_STORAGE_KEY = "opt-mode";
|
|
5531
|
-
const DARK_MQ = "(prefers-color-scheme: dark)";
|
|
5532
|
-
/**
|
|
5533
|
-
* Presets that force light mode regardless of system dark/light preference.
|
|
5534
|
-
* Mirrors `FORCE_LIGHT_PRESET_IDS` from `./presets` — kept as alias for
|
|
5535
|
-
* existing imports.
|
|
5536
|
-
*/
|
|
5537
|
-
const FORCE_LIGHT_PRESETS = FORCE_LIGHT_PRESET_IDS;
|
|
5538
|
-
/** All valid compound theme names. Useful for static enumeration. */
|
|
5539
|
-
const ALL_COMPOUND_THEMES = THEME_PRESET_IDS.flatMap((id) => FORCE_LIGHT_PRESET_IDS.has(id) ? [id] : [id, `${id}-dark`]);
|
|
5540
|
-
function hasStorageMutation(storage) {
|
|
5541
|
-
return typeof storage.setItem === "function" && typeof storage.removeItem === "function";
|
|
5542
|
-
}
|
|
5543
|
-
/** Handles is theme mode. */
|
|
5544
|
-
function isThemeMode(value) {
|
|
5545
|
-
return typeof value === "string" && THEME_MODE_VALUES.includes(value);
|
|
5546
|
-
}
|
|
5547
|
-
/** Compute compound theme name from preset + resolved mode. */
|
|
5548
|
-
function getCompoundTheme(preset, resolvedMode) {
|
|
5549
|
-
if (FORCE_LIGHT_PRESETS.has(preset)) return preset;
|
|
5550
|
-
return resolvedMode === "dark" ? `${preset}-dark` : preset;
|
|
5551
|
-
}
|
|
5552
|
-
/** Handles resolve theme mode. */
|
|
5553
|
-
function resolveThemeMode(preset, mode, systemDark) {
|
|
5554
|
-
if (FORCE_LIGHT_PRESETS.has(preset)) return "light";
|
|
5555
|
-
if (mode === "system") return systemDark ? "dark" : "light";
|
|
5556
|
-
return mode;
|
|
5557
|
-
}
|
|
5558
|
-
/** Handles read stored theme. */
|
|
5559
|
-
function readStoredTheme(storage, defaultPreset, defaultMode, options = {}) {
|
|
5560
|
-
const legacy = storage.getItem(LEGACY_THEME_STORAGE_KEY);
|
|
5561
|
-
const storedPreset = storage.getItem(THEME_PRESET_STORAGE_KEY);
|
|
5562
|
-
const storedMode = storage.getItem(THEME_MODE_STORAGE_KEY);
|
|
5563
|
-
let preset = defaultPreset;
|
|
5564
|
-
if (typeof legacy === "string") {
|
|
5565
|
-
const migratedLegacy = migrateDeprecatedPresetId(legacy);
|
|
5566
|
-
if (migratedLegacy) {
|
|
5567
|
-
if (options.migrateLegacy && hasStorageMutation(storage)) {
|
|
5568
|
-
storage.setItem(THEME_PRESET_STORAGE_KEY, migratedLegacy);
|
|
5569
|
-
storage.removeItem(LEGACY_THEME_STORAGE_KEY);
|
|
5570
|
-
}
|
|
5571
|
-
preset = migratedLegacy;
|
|
5572
|
-
}
|
|
5573
|
-
} else if (typeof storedPreset === "string") {
|
|
5574
|
-
const migrated = migrateDeprecatedPresetId(storedPreset);
|
|
5575
|
-
if (migrated) {
|
|
5576
|
-
preset = migrated;
|
|
5577
|
-
if (hasStorageMutation(storage) && migrated !== storedPreset && storedPreset in DEPRECATED_PRESET_MIGRATIONS) storage.setItem(THEME_PRESET_STORAGE_KEY, migrated);
|
|
5578
|
-
}
|
|
5579
|
-
}
|
|
5580
|
-
const mode = isThemeMode(storedMode) ? storedMode : defaultMode;
|
|
5581
|
-
return {
|
|
5582
|
-
preset,
|
|
5583
|
-
mode
|
|
5584
|
-
};
|
|
5585
|
-
}
|
|
5586
|
-
/** Normalize a mode against an optional allowed-mode list. */
|
|
5587
|
-
function coerceThemeMode(mode, allowedModes, fallback = "system") {
|
|
5588
|
-
var _allowedModes$;
|
|
5589
|
-
if (!allowedModes || allowedModes.length === 0) return mode;
|
|
5590
|
-
if (allowedModes.includes(mode)) return mode;
|
|
5591
|
-
if (allowedModes.includes(fallback)) return fallback;
|
|
5592
|
-
return (_allowedModes$ = allowedModes[0]) !== null && _allowedModes$ !== void 0 ? _allowedModes$ : fallback;
|
|
5593
|
-
}
|
|
5594
|
-
/**
|
|
5595
|
-
* Build the inline `<head>` boot script that paints the correct theme before
|
|
5596
|
-
* React mounts. Two paths:
|
|
5597
|
-
*
|
|
5598
|
-
* 1. **Generated** — when both `opt-theme-spec` (kind: "generated") and
|
|
5599
|
-
* `opt-theme-tokens` are present and well-formed, a `<style id="…">` tag
|
|
5600
|
-
* is inserted with the cached tokens and `<html data-theme>` is set to the
|
|
5601
|
-
* generated id (with optional `-dark` suffix). This bypasses opt-palette
|
|
5602
|
-
* at startup so first paint is instant.
|
|
5603
|
-
* 2. **Preset (legacy)** — falls through to the existing preset selector,
|
|
5604
|
-
* including legacy `opt-theme` → `opt-preset` migration.
|
|
5605
|
-
*
|
|
5606
|
-
* Returned as a single minified line; intended for `dangerouslySetInnerHTML`.
|
|
5607
|
-
*/
|
|
5608
|
-
function createThemeBootScript(defaultPreset = "default", defaultMode = "system", options = {}) {
|
|
5609
|
-
var _options$allowedModes, _allowedModes$2;
|
|
5610
|
-
const presetValues = JSON.stringify(THEME_PRESET_VALUES);
|
|
5611
|
-
const modeValues = JSON.stringify(THEME_MODE_VALUES);
|
|
5612
|
-
const allowedModes = ((_options$allowedModes = options.allowedModes) === null || _options$allowedModes === void 0 ? void 0 : _options$allowedModes.length) ? options.allowedModes : THEME_MODE_VALUES;
|
|
5613
|
-
const allowedModeValues = JSON.stringify(allowedModes);
|
|
5614
|
-
const forceLightPresets = JSON.stringify(Array.from(FORCE_LIGHT_PRESETS));
|
|
5615
|
-
const deprecatedMap = JSON.stringify(DEPRECATED_PRESET_MIGRATIONS);
|
|
5616
|
-
const lockedPreset = options.lockedPreset;
|
|
5617
|
-
const defaultPresetLiteral = JSON.stringify(lockedPreset !== null && lockedPreset !== void 0 ? lockedPreset : defaultPreset);
|
|
5618
|
-
const defaultModeLiteral = JSON.stringify(coerceThemeMode(defaultMode, allowedModes, (_allowedModes$2 = allowedModes[0]) !== null && _allowedModes$2 !== void 0 ? _allowedModes$2 : "system"));
|
|
5619
|
-
const lockedPresetLiteral = JSON.stringify(lockedPreset !== null && lockedPreset !== void 0 ? lockedPreset : null);
|
|
5620
|
-
const styleId = JSON.stringify(GLOBAL_THEME_STYLE_ID);
|
|
5621
|
-
const specKey = JSON.stringify(THEME_SPEC_STORAGE_KEY);
|
|
5622
|
-
const tokensKey = JSON.stringify(THEME_TOKENS_STORAGE_KEY);
|
|
5623
|
-
const presetKey = JSON.stringify(THEME_PRESET_STORAGE_KEY);
|
|
5624
|
-
const modeKey = JSON.stringify(THEME_MODE_STORAGE_KEY);
|
|
5625
|
-
const legacyKey = JSON.stringify(LEGACY_THEME_STORAGE_KEY);
|
|
5626
|
-
const darkMq = JSON.stringify(DARK_MQ);
|
|
5627
|
-
return `
|
|
5628
|
-
try {
|
|
5629
|
-
var pv=${presetValues},mv=${modeValues},am=${allowedModeValues},fp=${forceLightPresets},dm=${deprecatedMap},lk=${lockedPresetLiteral};
|
|
5630
|
-
function mp(v){if(typeof v!=="string")return null;if(pv.indexOf(v)>=0)return v;return Object.prototype.hasOwnProperty.call(dm,v)?dm[v]:null;}
|
|
5631
|
-
var p=${defaultPresetLiteral};
|
|
5632
|
-
if(!lk){
|
|
5633
|
-
var lp=localStorage.getItem(${legacyKey}),sp=localStorage.getItem(${presetKey});
|
|
5634
|
-
var lpm=mp(lp),spm=mp(sp);
|
|
5635
|
-
p=lpm||spm||${defaultPresetLiteral};
|
|
5636
|
-
if(lpm){localStorage.setItem(${presetKey},lpm);localStorage.removeItem(${legacyKey});}
|
|
5637
|
-
else if(sp&&spm&&sp!==spm){localStorage.setItem(${presetKey},spm);}
|
|
5638
|
-
}
|
|
5639
|
-
var sm=localStorage.getItem(${modeKey});
|
|
5640
|
-
var m=(typeof sm==="string"&&mv.indexOf(sm)>=0&&am.indexOf(sm)>=0)?sm:${defaultModeLiteral};
|
|
5641
|
-
var spec=null,tk=null;
|
|
5642
|
-
if(!lk){try{var sj=localStorage.getItem(${specKey});if(sj)spec=JSON.parse(sj);}catch(e){}}
|
|
5643
|
-
if(!lk){try{var tj=localStorage.getItem(${tokensKey});if(tj)tk=JSON.parse(tj);}catch(e){}}
|
|
5644
|
-
if(!lk&&spec&&spec.kind==="generated"&&tk&&typeof tk.id==="string"&&tk.light&&typeof tk.light==="object"){
|
|
5645
|
-
var fld=spec.forceLightOnly===true;
|
|
5646
|
-
var dk=!fld&&(m==="dark"||(m==="system"&&matchMedia(${darkMq}).matches));
|
|
5647
|
-
var tt=(dk&&tk.dark)?tk.dark:tk.light;
|
|
5648
|
-
var cid=(dk&&tk.dark)?(tk.id+"-dark"):tk.id;
|
|
5649
|
-
var css="";
|
|
5650
|
-
for(var k in tt){if(Object.prototype.hasOwnProperty.call(tt,k))css+=k+":"+tt[k]+";"}
|
|
5651
|
-
var st=document.getElementById(${styleId});
|
|
5652
|
-
if(!st){st=document.createElement("style");st.id=${styleId};document.head.appendChild(st);}
|
|
5653
|
-
st.textContent='[data-theme="'+cid+'"]{'+css+'}';
|
|
5654
|
-
document.documentElement.setAttribute("data-theme",cid);
|
|
5655
|
-
} else {
|
|
5656
|
-
var d=fp.indexOf(p)<0&&(m==="dark"||(m==="system"&&matchMedia(${darkMq}).matches));
|
|
5657
|
-
document.documentElement.setAttribute("data-theme",d?p+"-dark":p);
|
|
5658
|
-
}
|
|
5659
|
-
} catch(e){}`.replace(/\n\s*/g, "");
|
|
5660
|
-
}
|
|
5661
|
-
//#endregion
|
|
5662
|
-
//#region src/lib/theme/theme-controller-context.tsx
|
|
5663
|
-
const OptThemeControllerContext = (0, react.createContext)(null);
|
|
5664
|
-
/**
|
|
5665
|
-
* Reads the controller exposed by the nearest `OptThemeProvider`. Returns
|
|
5666
|
-
* `null` when used outside a provider — callers should treat that as "no
|
|
5667
|
-
* promotion available" and behave as if scope === "override".
|
|
5668
|
-
*/
|
|
5669
|
-
function useOptThemeController() {
|
|
5670
|
-
return (0, react.useContext)(OptThemeControllerContext);
|
|
5671
|
-
}
|
|
5672
|
-
//#endregion
|
|
5673
|
-
//#region src/lib/theme/theme-provider.tsx
|
|
5674
|
-
const THEME_STORAGE_KEYS = /* @__PURE__ */ new Set([
|
|
5675
|
-
LEGACY_THEME_STORAGE_KEY,
|
|
5676
|
-
THEME_PRESET_STORAGE_KEY,
|
|
5677
|
-
THEME_MODE_STORAGE_KEY,
|
|
5678
|
-
THEME_SPEC_STORAGE_KEY,
|
|
5679
|
-
THEME_TOKENS_STORAGE_KEY
|
|
5680
|
-
]);
|
|
5681
|
-
function getSystemDark() {
|
|
5682
|
-
if (typeof window === "undefined") return false;
|
|
5683
|
-
return window.matchMedia(DARK_MQ).matches;
|
|
5684
|
-
}
|
|
5685
|
-
function subscribeSystemDark(cb) {
|
|
5686
|
-
if (typeof window === "undefined") return () => {};
|
|
5687
|
-
const mql = window.matchMedia(DARK_MQ);
|
|
5688
|
-
mql.addEventListener("change", cb);
|
|
5689
|
-
return () => mql.removeEventListener("change", cb);
|
|
5690
|
-
}
|
|
5691
|
-
/**
|
|
5692
|
-
* Read the persisted ThemeSpec, preferring a generated spec when present.
|
|
5693
|
-
* Falls back to the legacy preset path otherwise. Does not touch localStorage
|
|
5694
|
-
* apart from the legacy migration handled by `readStoredTheme`.
|
|
5695
|
-
*/
|
|
5696
|
-
function readStoredSpec(defaultPreset, defaultMode, options = {}) {
|
|
5697
|
-
const generated = safeParseStoredSpec(window.localStorage.getItem(THEME_SPEC_STORAGE_KEY));
|
|
5698
|
-
const { preset, mode } = readStoredTheme(window.localStorage, defaultPreset, defaultMode, options);
|
|
5699
|
-
if (generated && generated.kind === "generated") return {
|
|
5700
|
-
spec: generated,
|
|
5701
|
-
mode,
|
|
5702
|
-
presetShadow: preset
|
|
5703
|
-
};
|
|
5704
|
-
return {
|
|
5705
|
-
spec: presetTheme(preset),
|
|
5706
|
-
mode,
|
|
5707
|
-
presetShadow: preset
|
|
5708
|
-
};
|
|
5709
|
-
}
|
|
5710
|
-
function persistSpec(spec) {
|
|
5711
|
-
if (isPresetSpec(spec)) {
|
|
5712
|
-
window.localStorage.setItem(THEME_PRESET_STORAGE_KEY, spec.preset);
|
|
5713
|
-
window.localStorage.removeItem(THEME_SPEC_STORAGE_KEY);
|
|
5714
|
-
window.localStorage.removeItem(THEME_TOKENS_STORAGE_KEY);
|
|
5715
|
-
return;
|
|
5716
|
-
}
|
|
5717
|
-
if (isGeneratedSpec(spec)) {
|
|
5718
|
-
const tokens = computeGeneratedTokens(spec);
|
|
5719
|
-
window.localStorage.setItem(THEME_SPEC_STORAGE_KEY, JSON.stringify(spec));
|
|
5720
|
-
if (tokens) window.localStorage.setItem(THEME_TOKENS_STORAGE_KEY, JSON.stringify(buildTokenCache(tokens)));
|
|
5721
|
-
else window.localStorage.removeItem(THEME_TOKENS_STORAGE_KEY);
|
|
5722
|
-
return;
|
|
5723
|
-
}
|
|
5724
|
-
const descriptor = spec.descriptor;
|
|
5725
|
-
if (isThemePresetId(descriptor.id) && !descriptor.palette) {
|
|
5726
|
-
window.localStorage.setItem(THEME_PRESET_STORAGE_KEY, descriptor.id);
|
|
5727
|
-
window.localStorage.removeItem(THEME_SPEC_STORAGE_KEY);
|
|
5728
|
-
window.localStorage.removeItem(THEME_TOKENS_STORAGE_KEY);
|
|
5729
|
-
return;
|
|
5730
|
-
}
|
|
5731
|
-
if (descriptor.palette) persistSpec({
|
|
5732
|
-
kind: "generated",
|
|
5733
|
-
id: descriptor.id,
|
|
5734
|
-
label: descriptor.label,
|
|
5735
|
-
palette: descriptor.palette,
|
|
5736
|
-
forceLightOnly: descriptor.forceLightOnly
|
|
5737
|
-
});
|
|
5738
|
-
}
|
|
5739
|
-
function upsertGlobalStyle(css) {
|
|
5740
|
-
if (typeof document === "undefined") return;
|
|
5741
|
-
let node = document.getElementById(GLOBAL_THEME_STYLE_ID);
|
|
5742
|
-
if (!node) {
|
|
5743
|
-
node = document.createElement("style");
|
|
5744
|
-
node.id = GLOBAL_THEME_STYLE_ID;
|
|
5745
|
-
document.head.appendChild(node);
|
|
5746
|
-
}
|
|
5747
|
-
if (node.textContent !== css) node.textContent = css;
|
|
5748
|
-
}
|
|
5749
|
-
function removeGlobalStyle() {
|
|
5750
|
-
var _document$getElementB;
|
|
5751
|
-
if (typeof document === "undefined") return;
|
|
5752
|
-
(_document$getElementB = document.getElementById("opt-global-theme")) === null || _document$getElementB === void 0 || _document$getElementB.remove();
|
|
5753
|
-
}
|
|
5754
|
-
const ThemeContext = (0, react.createContext)(void 0);
|
|
5755
|
-
/** Renders the opt theme provider component. */
|
|
5756
|
-
function OptThemeProvider({ children, defaultTheme, controlledTheme, defaultPreset = "default", defaultMode = "system", lockedPreset, allowedModes, allowThemePromotion = true }) {
|
|
5757
|
-
var _allowedModes$, _ref, _effectiveStackTop$sp;
|
|
5758
|
-
const normalizedDefaultMode = coerceThemeMode(defaultMode, allowedModes, (_allowedModes$ = allowedModes === null || allowedModes === void 0 ? void 0 : allowedModes[0]) !== null && _allowedModes$ !== void 0 ? _allowedModes$ : "system");
|
|
5759
|
-
const initialSpec = (_ref = controlledTheme !== null && controlledTheme !== void 0 ? controlledTheme : lockedPreset ? presetTheme(lockedPreset) : defaultTheme) !== null && _ref !== void 0 ? _ref : presetTheme(defaultPreset);
|
|
5760
|
-
const initialPresetShadow = isPresetSpec(initialSpec) ? initialSpec.preset : lockedPreset !== null && lockedPreset !== void 0 ? lockedPreset : defaultPreset;
|
|
5761
|
-
const [theme, setThemeState] = (0, react.useState)(initialSpec);
|
|
5762
|
-
const [presetShadow, setPresetShadow] = (0, react.useState)(initialPresetShadow);
|
|
5763
|
-
const [mode, setModeState] = (0, react.useState)(normalizedDefaultMode);
|
|
5764
|
-
/**
|
|
5765
|
-
* Transient theme override stack — descendants (typically harnesses in
|
|
5766
|
-
* promote-global mode) push specs that take priority over `controlledTheme`
|
|
5767
|
-
* and persisted state. The stack is intentionally kept out of localStorage.
|
|
5768
|
-
*/
|
|
5769
|
-
const [stack, setStack] = (0, react.useState)([]);
|
|
5770
|
-
const isControlled = controlledTheme !== void 0;
|
|
5771
|
-
const isLocked = !isControlled && lockedPreset !== void 0;
|
|
5772
|
-
(0, react.useEffect)(() => {
|
|
5773
|
-
if (!isControlled) return;
|
|
5774
|
-
setThemeState(controlledTheme);
|
|
5775
|
-
if (isPresetSpec(controlledTheme)) setPresetShadow(controlledTheme.preset);
|
|
5776
|
-
}, [controlledTheme, isControlled]);
|
|
5777
|
-
(0, react.useEffect)(() => {
|
|
5778
|
-
if (isControlled) return;
|
|
5779
|
-
if (isLocked) {
|
|
5780
|
-
const locked = lockedPreset !== null && lockedPreset !== void 0 ? lockedPreset : defaultPreset;
|
|
5781
|
-
const { mode: storedMode } = readStoredTheme(window.localStorage, locked, normalizedDefaultMode);
|
|
5782
|
-
const nextMode = coerceThemeMode(storedMode, allowedModes, normalizedDefaultMode);
|
|
5783
|
-
const nextSpec = presetTheme(locked);
|
|
5784
|
-
setThemeState((prev) => themeEqual(prev, nextSpec) ? prev : nextSpec);
|
|
5785
|
-
setPresetShadow((prev) => prev === locked ? prev : locked);
|
|
5786
|
-
setModeState((prev) => prev === nextMode ? prev : nextMode);
|
|
5787
|
-
return;
|
|
5788
|
-
}
|
|
5789
|
-
const next = readStoredSpec(defaultPreset, defaultMode, { migrateLegacy: true });
|
|
5790
|
-
const nextMode = coerceThemeMode(next.mode, allowedModes, normalizedDefaultMode);
|
|
5791
|
-
setThemeState((prev) => themeEqual(prev, next.spec) ? prev : next.spec);
|
|
5792
|
-
setPresetShadow((prev) => prev === next.presetShadow ? prev : next.presetShadow);
|
|
5793
|
-
setModeState((prev) => prev === nextMode ? prev : nextMode);
|
|
5794
|
-
}, [
|
|
5795
|
-
allowedModes,
|
|
5796
|
-
isControlled,
|
|
5797
|
-
isLocked,
|
|
5798
|
-
lockedPreset,
|
|
5799
|
-
normalizedDefaultMode
|
|
5800
|
-
]);
|
|
5801
|
-
(0, react.useEffect)(() => {
|
|
5802
|
-
if (isControlled) return;
|
|
5803
|
-
function handleStorage(event) {
|
|
5804
|
-
if (event.storageArea && event.storageArea !== window.localStorage) return;
|
|
5805
|
-
if (event.key != null && !THEME_STORAGE_KEYS.has(event.key)) return;
|
|
5806
|
-
if (isLocked) {
|
|
5807
|
-
const locked = lockedPreset !== null && lockedPreset !== void 0 ? lockedPreset : defaultPreset;
|
|
5808
|
-
const { mode: storedMode } = readStoredTheme(window.localStorage, locked, normalizedDefaultMode);
|
|
5809
|
-
const nextMode = coerceThemeMode(storedMode, allowedModes, normalizedDefaultMode);
|
|
5810
|
-
const nextSpec = presetTheme(locked);
|
|
5811
|
-
setThemeState((prev) => themeEqual(prev, nextSpec) ? prev : nextSpec);
|
|
5812
|
-
setPresetShadow((prev) => prev === locked ? prev : locked);
|
|
5813
|
-
setModeState((prev) => prev === nextMode ? prev : nextMode);
|
|
5814
|
-
return;
|
|
5815
|
-
}
|
|
5816
|
-
const next = readStoredSpec(defaultPreset, defaultMode, { migrateLegacy: event.key === LEGACY_THEME_STORAGE_KEY });
|
|
5817
|
-
const nextMode = coerceThemeMode(next.mode, allowedModes, normalizedDefaultMode);
|
|
5818
|
-
setThemeState((prev) => themeEqual(prev, next.spec) ? prev : next.spec);
|
|
5819
|
-
setPresetShadow((prev) => prev === next.presetShadow ? prev : next.presetShadow);
|
|
5820
|
-
setModeState((prev) => prev === nextMode ? prev : nextMode);
|
|
5821
|
-
}
|
|
5822
|
-
window.addEventListener("storage", handleStorage);
|
|
5823
|
-
return () => window.removeEventListener("storage", handleStorage);
|
|
5824
|
-
}, [
|
|
5825
|
-
allowedModes,
|
|
5826
|
-
isControlled,
|
|
5827
|
-
isLocked,
|
|
5828
|
-
defaultMode,
|
|
5829
|
-
defaultPreset,
|
|
5830
|
-
lockedPreset,
|
|
5831
|
-
normalizedDefaultMode
|
|
5832
|
-
]);
|
|
5833
|
-
const systemDark = (0, react.useSyncExternalStore)(subscribeSystemDark, getSystemDark, () => false);
|
|
5834
|
-
const stackTop = stack.length > 0 ? stack[stack.length - 1] : null;
|
|
5835
|
-
const effectiveStackTop = allowThemePromotion ? stackTop : null;
|
|
5836
|
-
const isPromoted = effectiveStackTop !== null;
|
|
5837
|
-
const effectiveSpec = (_effectiveStackTop$sp = effectiveStackTop === null || effectiveStackTop === void 0 ? void 0 : effectiveStackTop.spec) !== null && _effectiveStackTop$sp !== void 0 ? _effectiveStackTop$sp : theme;
|
|
5838
|
-
const forceLight = isForceLightSpec(effectiveSpec);
|
|
5839
|
-
const resolvedMode = computeResolvedMode(forceLight, mode, systemDark);
|
|
5840
|
-
const compoundId = getCompoundIdForSpec(effectiveSpec, resolvedMode, forceLight);
|
|
5841
|
-
const [hydrated, setHydrated] = (0, react.useState)(false);
|
|
5842
|
-
(0, react.useEffect)(() => {
|
|
5843
|
-
setHydrated(true);
|
|
5844
|
-
}, []);
|
|
5845
|
-
(0, react.useEffect)(() => {
|
|
5846
|
-
if (!hydrated) return;
|
|
5847
|
-
if (document.documentElement.getAttribute("data-theme") !== compoundId) document.documentElement.setAttribute("data-theme", compoundId);
|
|
5848
|
-
}, [compoundId, hydrated]);
|
|
5849
|
-
(0, react.useEffect)(() => {
|
|
5850
|
-
if (isPresetSpec(effectiveSpec)) {
|
|
5851
|
-
removeGlobalStyle();
|
|
5852
|
-
return;
|
|
5853
|
-
}
|
|
5854
|
-
const tokens = computeGeneratedTokens(effectiveSpec);
|
|
5855
|
-
if (!tokens) {
|
|
5856
|
-
removeGlobalStyle();
|
|
5857
|
-
return;
|
|
5858
|
-
}
|
|
5859
|
-
upsertGlobalStyle(serializeGeneratedTheme(tokens));
|
|
5860
|
-
if (!isControlled && !isPromoted && effectiveSpec === theme) try {
|
|
5861
|
-
window.localStorage.setItem(THEME_TOKENS_STORAGE_KEY, JSON.stringify(buildTokenCache(tokens)));
|
|
5862
|
-
} catch (_unused) {}
|
|
5863
|
-
}, [
|
|
5864
|
-
effectiveSpec,
|
|
5865
|
-
theme,
|
|
5866
|
-
isControlled,
|
|
5867
|
-
isPromoted
|
|
5868
|
-
]);
|
|
5869
|
-
const setTheme = (0, react.useCallback)((next) => {
|
|
5870
|
-
if (isLocked) {
|
|
5871
|
-
if (process.env.NODE_ENV !== "production") console.warn("[OptThemeProvider] setTheme called while lockedPreset is set — ignoring.");
|
|
5872
|
-
return;
|
|
5873
|
-
}
|
|
5874
|
-
if (isControlled) {
|
|
5875
|
-
if (process.env.NODE_ENV !== "production") console.warn("[OptThemeProvider] setTheme called while controlledTheme is set — ignoring.");
|
|
5876
|
-
return;
|
|
5877
|
-
}
|
|
5878
|
-
setThemeState(next);
|
|
5879
|
-
if (isPresetSpec(next)) setPresetShadow(next.preset);
|
|
5880
|
-
try {
|
|
5881
|
-
persistSpec(next);
|
|
5882
|
-
} catch (_unused2) {}
|
|
5883
|
-
}, [isControlled, isLocked]);
|
|
5884
|
-
const setPreset = (0, react.useCallback)((p) => {
|
|
5885
|
-
setTheme(presetTheme(p));
|
|
5886
|
-
}, [setTheme]);
|
|
5887
|
-
const setMode = (0, react.useCallback)((m) => {
|
|
5888
|
-
const nextMode = coerceThemeMode(m, allowedModes, normalizedDefaultMode);
|
|
5889
|
-
setModeState(nextMode);
|
|
5890
|
-
if (!isControlled) try {
|
|
5891
|
-
window.localStorage.setItem(THEME_MODE_STORAGE_KEY, nextMode);
|
|
5892
|
-
} catch (_unused3) {}
|
|
5893
|
-
}, [
|
|
5894
|
-
allowedModes,
|
|
5895
|
-
isControlled,
|
|
5896
|
-
normalizedDefaultMode
|
|
5897
|
-
]);
|
|
5898
|
-
const controller = (0, react.useMemo)(() => ({
|
|
5899
|
-
pushTheme(id, spec) {
|
|
5900
|
-
if (!allowThemePromotion) return;
|
|
5901
|
-
setStack((prev) => {
|
|
5902
|
-
return [...prev.filter((entry) => entry.id !== id), {
|
|
5903
|
-
id,
|
|
5904
|
-
spec
|
|
5905
|
-
}];
|
|
5906
|
-
});
|
|
5907
|
-
},
|
|
5908
|
-
popTheme(id) {
|
|
5909
|
-
if (!allowThemePromotion) return;
|
|
5910
|
-
setStack((prev) => prev.filter((entry) => entry.id !== id));
|
|
5911
|
-
}
|
|
5912
|
-
}), [allowThemePromotion]);
|
|
5913
|
-
const value = (0, react.useMemo)(() => ({
|
|
5914
|
-
theme: effectiveSpec,
|
|
5915
|
-
setTheme,
|
|
5916
|
-
preset: presetShadow,
|
|
5917
|
-
setPreset,
|
|
5918
|
-
mode,
|
|
5919
|
-
setMode,
|
|
5920
|
-
resolvedMode,
|
|
5921
|
-
isControlled,
|
|
5922
|
-
isGenerated: !isPresetSpec(effectiveSpec),
|
|
5923
|
-
isPromoted
|
|
5924
|
-
}), [
|
|
5925
|
-
effectiveSpec,
|
|
5926
|
-
setTheme,
|
|
5927
|
-
presetShadow,
|
|
5928
|
-
setPreset,
|
|
5929
|
-
mode,
|
|
5930
|
-
setMode,
|
|
5931
|
-
resolvedMode,
|
|
5932
|
-
isControlled,
|
|
5933
|
-
isPromoted
|
|
5934
|
-
]);
|
|
5935
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThemeContext.Provider, {
|
|
5936
|
-
value,
|
|
5937
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OptThemeControllerContext.Provider, {
|
|
5938
|
-
value: controller,
|
|
5939
|
-
children
|
|
5940
|
-
})
|
|
5941
|
-
});
|
|
5942
|
-
}
|
|
5943
|
-
/** Provides opt theme. */
|
|
5944
|
-
function useOptTheme() {
|
|
5945
|
-
const ctx = (0, react.useContext)(ThemeContext);
|
|
5946
|
-
if (!ctx) throw new Error("useOptTheme must be used within OptThemeProvider");
|
|
5947
|
-
return ctx;
|
|
5948
|
-
}
|
|
5949
|
-
/** Reads opt theme context when present without requiring a provider. */
|
|
5950
|
-
function useOptionalOptTheme() {
|
|
5951
|
-
return (0, react.useContext)(ThemeContext);
|
|
5952
|
-
}
|
|
5953
|
-
function computeResolvedMode(forceLight, mode, systemDark) {
|
|
5954
|
-
if (forceLight) return "light";
|
|
5955
|
-
if (mode === "system") return systemDark ? "dark" : "light";
|
|
5956
|
-
return mode;
|
|
5957
|
-
}
|
|
5958
|
-
function themeEqual(a, b) {
|
|
5959
|
-
if (a === b) return true;
|
|
5960
|
-
if (a.kind !== b.kind) return false;
|
|
5961
|
-
if (a.kind === "preset" && b.kind === "preset") return a.preset === b.preset && overridesEqual(a.overrides, b.overrides);
|
|
5962
|
-
if (a.kind === "generated" && b.kind === "generated") return a.id === b.id && a.label === b.label && a.forceLightOnly === b.forceLightOnly && JSON.stringify(a.palette) === JSON.stringify(b.palette) && overridesEqual(a.overrides, b.overrides);
|
|
5963
|
-
if (a.kind === "descriptor" && b.kind === "descriptor") return a.descriptor === b.descriptor && overridesEqual(a.overrides, b.overrides);
|
|
5964
|
-
return false;
|
|
5965
|
-
}
|
|
5966
|
-
function overridesEqual(a, b) {
|
|
5967
|
-
if (a === b) return true;
|
|
5968
|
-
if (!a && !b) return true;
|
|
5969
|
-
if (!a || !b) return false;
|
|
5970
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
5971
|
-
}
|
|
5972
5562
|
//#endregion
|
|
5973
5563
|
//#region src/shells/theme-switcher.tsx
|
|
5974
5564
|
const FALLBACK_SWATCHES = [
|
|
@@ -5977,9 +5567,9 @@ const FALLBACK_SWATCHES = [
|
|
|
5977
5567
|
"var(--opt-text)"
|
|
5978
5568
|
];
|
|
5979
5569
|
function buildThemeOptions() {
|
|
5980
|
-
return THEME_PRESET_IDS.map((id) => {
|
|
5570
|
+
return require_field_sidebar.THEME_PRESET_IDS.map((id) => {
|
|
5981
5571
|
var _descriptor$switcherS;
|
|
5982
|
-
const descriptor = THEME_REGISTRY[id];
|
|
5572
|
+
const descriptor = require_field_sidebar.THEME_REGISTRY[id];
|
|
5983
5573
|
return {
|
|
5984
5574
|
value: id,
|
|
5985
5575
|
label: descriptor.label,
|
|
@@ -6060,7 +5650,7 @@ function resolveLabels(user) {
|
|
|
6060
5650
|
/** Renders the theme switcher component. */
|
|
6061
5651
|
function ThemeSwitcher({ className, labels: userLabels, variant = "default", customPresetEditor, preset: controlledPreset, onPresetChange, mode: controlledMode, onModeChange }) {
|
|
6062
5652
|
var _ref;
|
|
6063
|
-
const themeContext = useOptionalOptTheme();
|
|
5653
|
+
const themeContext = require_field_sidebar.useOptionalOptTheme();
|
|
6064
5654
|
const preset = controlledPreset !== null && controlledPreset !== void 0 ? controlledPreset : themeContext === null || themeContext === void 0 ? void 0 : themeContext.preset;
|
|
6065
5655
|
const mode = (_ref = controlledMode !== null && controlledMode !== void 0 ? controlledMode : themeContext === null || themeContext === void 0 ? void 0 : themeContext.mode) !== null && _ref !== void 0 ? _ref : "light";
|
|
6066
5656
|
const setPreset = onPresetChange !== null && onPresetChange !== void 0 ? onPresetChange : themeContext === null || themeContext === void 0 ? void 0 : themeContext.setPreset;
|
|
@@ -6069,7 +5659,7 @@ function ThemeSwitcher({ className, labels: userLabels, variant = "default", cus
|
|
|
6069
5659
|
const labels = resolveLabels(userLabels);
|
|
6070
5660
|
const options = buildThemeOptions();
|
|
6071
5661
|
const activePreset = preset;
|
|
6072
|
-
const forcedMode = FORCE_LIGHT_PRESET_IDS.has(activePreset);
|
|
5662
|
+
const forcedMode = require_field_sidebar.FORCE_LIGHT_PRESET_IDS.has(activePreset);
|
|
6073
5663
|
const showCustomBadge = controlledPreset === void 0 && ((themeContext === null || themeContext === void 0 ? void 0 : themeContext.isGenerated) === true || (themeContext === null || themeContext === void 0 ? void 0 : themeContext.isPromoted) === true);
|
|
6074
5664
|
if (options.length === 0) return null;
|
|
6075
5665
|
if (variant === "compact") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -6762,10 +6352,10 @@ function BulkActions({ selectedCount, actions, onAction, onClear, labels: custom
|
|
|
6762
6352
|
labels.selected
|
|
6763
6353
|
]
|
|
6764
6354
|
}),
|
|
6765
|
-
hasActions ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
6355
|
+
hasActions ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownMenu, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownTrigger, {
|
|
6766
6356
|
className: "border-border bg-surface text-text-primary hover:bg-bg-subtle inline-flex h-8 items-center rounded-md border px-3 text-sm font-medium",
|
|
6767
6357
|
children: labels.actions
|
|
6768
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6358
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownContent, { children: actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownItem, {
|
|
6769
6359
|
onClick: () => onAction(action.id),
|
|
6770
6360
|
className: action.variant === "danger" ? "text-danger" : void 0,
|
|
6771
6361
|
children: action.label
|
|
@@ -7800,7 +7390,7 @@ function FeatureFlagPanel({ flags, onToggle, onRolloutChange, environments, clas
|
|
|
7800
7390
|
className: "text-text-tertiary text-xs",
|
|
7801
7391
|
children: flag.description
|
|
7802
7392
|
})]
|
|
7803
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
7393
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Switch, {
|
|
7804
7394
|
checked: flag.enabled,
|
|
7805
7395
|
onChange: (checked) => onToggle(flag.id, checked),
|
|
7806
7396
|
label: flag.enabled ? labels.enabled : labels.disabled
|
|
@@ -9284,7 +8874,7 @@ const enStarRatingLabels = {
|
|
|
9284
8874
|
};
|
|
9285
8875
|
const enBreadcrumbLabels = { navAriaLabel: "Go to {label}" };
|
|
9286
8876
|
//#endregion
|
|
9287
|
-
exports.ALL_COMPOUND_THEMES = ALL_COMPOUND_THEMES;
|
|
8877
|
+
exports.ALL_COMPOUND_THEMES = require_field_sidebar.ALL_COMPOUND_THEMES;
|
|
9288
8878
|
exports.AccordionContent = require_key_pad_menu.AccordionContent;
|
|
9289
8879
|
exports.AccordionItem = require_key_pad_menu.AccordionItem;
|
|
9290
8880
|
exports.AccordionRoot = require_key_pad_menu.AccordionRoot;
|
|
@@ -9308,7 +8898,7 @@ exports.Breadcrumb = require_key_pad_menu.Breadcrumb;
|
|
|
9308
8898
|
exports.BulkActions = BulkActions;
|
|
9309
8899
|
exports.Button = require_text_truncate.Button;
|
|
9310
8900
|
exports.COLOR_PRESETS = COLOR_PRESETS;
|
|
9311
|
-
exports.Callout = Callout;
|
|
8901
|
+
exports.Callout = require_field_sidebar.Callout;
|
|
9312
8902
|
exports.Card = require_key_pad_menu.Card;
|
|
9313
8903
|
exports.CardContent = require_key_pad_menu.CardContent;
|
|
9314
8904
|
exports.CardDescription = require_key_pad_menu.CardDescription;
|
|
@@ -9360,6 +8950,7 @@ exports.ConnectionIndicator = ConnectionIndicator;
|
|
|
9360
8950
|
exports.Container = require_key_pad_menu.Container;
|
|
9361
8951
|
exports.ContentTabs = require_field_sidebar.ContentTabs;
|
|
9362
8952
|
exports.CopyButton = CopyButton;
|
|
8953
|
+
exports.CriteriaBuilder = CriteriaBuilder;
|
|
9363
8954
|
exports.DEFAULT_PRESETS = require_text_truncate.DEFAULT_PRESETS;
|
|
9364
8955
|
exports.DEFAULT_TIME_PRESETS = require_field_sidebar.DEFAULT_TIME_PRESETS;
|
|
9365
8956
|
exports.DashboardGrid = require_field_sidebar.DashboardGrid;
|
|
@@ -9367,7 +8958,7 @@ exports.DataImportWizard = DataImportWizard;
|
|
|
9367
8958
|
exports.DataTable = require_field_sidebar.DataTable;
|
|
9368
8959
|
exports.DateRangePicker = require_text_truncate.DateRangePicker;
|
|
9369
8960
|
exports.DeploymentTimeline = require_field_sidebar.DeploymentTimeline;
|
|
9370
|
-
exports.DescriptionList =
|
|
8961
|
+
exports.DescriptionList = require_text_truncate.DescriptionList;
|
|
9371
8962
|
exports.DesignGuidePanel = DesignGuidePanel;
|
|
9372
8963
|
exports.DialogBody = require_text_truncate.DialogBody;
|
|
9373
8964
|
exports.DialogDescription = require_text_truncate.DialogDescription;
|
|
@@ -9385,13 +8976,14 @@ exports.DomainTable = require_field_sidebar.DomainTable;
|
|
|
9385
8976
|
exports.DrawerClose = require_key_pad_menu.DrawerClose;
|
|
9386
8977
|
exports.DrawerPanel = require_key_pad_menu.DrawerPanel;
|
|
9387
8978
|
exports.DrawerRoot = require_key_pad_menu.DrawerRoot;
|
|
9388
|
-
exports.DropdownContent =
|
|
9389
|
-
exports.DropdownItem =
|
|
9390
|
-
exports.DropdownMenu =
|
|
9391
|
-
exports.DropdownSeparator =
|
|
9392
|
-
exports.DropdownTrigger =
|
|
8979
|
+
exports.DropdownContent = require_text_truncate.DropdownContent;
|
|
8980
|
+
exports.DropdownItem = require_text_truncate.DropdownItem;
|
|
8981
|
+
exports.DropdownMenu = require_text_truncate.DropdownMenu;
|
|
8982
|
+
exports.DropdownSeparator = require_text_truncate.DropdownSeparator;
|
|
8983
|
+
exports.DropdownTrigger = require_text_truncate.DropdownTrigger;
|
|
9393
8984
|
exports.DynamicFieldForm = DynamicFieldForm;
|
|
9394
8985
|
exports.EMPTY_QUERY = require_field_sidebar.EMPTY_QUERY;
|
|
8986
|
+
exports.EMPTY_QUERY_FILTERS = require_field_sidebar.EMPTY_QUERY_FILTERS;
|
|
9395
8987
|
exports.EditorToolbar = require_field_sidebar.EditorToolbar;
|
|
9396
8988
|
exports.EmptyState = require_text_truncate.EmptyState;
|
|
9397
8989
|
exports.EnvPanel = require_field_sidebar.EnvPanel;
|
|
@@ -9409,8 +9001,8 @@ exports.ExportButton = ExportButton;
|
|
|
9409
9001
|
exports.Expression = require_key_pad_menu.Expression;
|
|
9410
9002
|
exports.ExpressionGroup = require_key_pad_menu.ExpressionGroup;
|
|
9411
9003
|
exports.FIELD_TYPE_TOKENS = require_text_truncate.FIELD_TYPE_TOKENS;
|
|
9412
|
-
exports.FORCE_LIGHT_PRESETS = FORCE_LIGHT_PRESETS;
|
|
9413
|
-
exports.FORCE_LIGHT_PRESET_IDS = FORCE_LIGHT_PRESET_IDS;
|
|
9004
|
+
exports.FORCE_LIGHT_PRESETS = require_field_sidebar.FORCE_LIGHT_PRESETS;
|
|
9005
|
+
exports.FORCE_LIGHT_PRESET_IDS = require_field_sidebar.FORCE_LIGHT_PRESET_IDS;
|
|
9414
9006
|
exports.Facet = require_key_pad_menu.Facet;
|
|
9415
9007
|
exports.FacetGroup = require_key_pad_menu.FacetGroup;
|
|
9416
9008
|
exports.FailureList = require_field_sidebar.FailureList;
|
|
@@ -9452,8 +9044,8 @@ exports.FormSubmit = require_text_truncate.FormSubmit;
|
|
|
9452
9044
|
exports.FormSwitch = require_text_truncate.FormSwitch;
|
|
9453
9045
|
exports.FormTagInput = require_text_truncate.FormTagInput;
|
|
9454
9046
|
exports.FormTextarea = require_text_truncate.FormTextarea;
|
|
9455
|
-
exports.GENERATED_THEME_ID_DEFAULT = GENERATED_THEME_ID_DEFAULT;
|
|
9456
|
-
exports.GLOBAL_THEME_STYLE_ID = GLOBAL_THEME_STYLE_ID;
|
|
9047
|
+
exports.GENERATED_THEME_ID_DEFAULT = require_field_sidebar.GENERATED_THEME_ID_DEFAULT;
|
|
9048
|
+
exports.GLOBAL_THEME_STYLE_ID = require_field_sidebar.GLOBAL_THEME_STYLE_ID;
|
|
9457
9049
|
exports.Heading = require_key_pad_menu.Heading;
|
|
9458
9050
|
exports.Highlight = require_text_truncate.Highlight;
|
|
9459
9051
|
exports.IconPicker = require_text_truncate.IconPicker;
|
|
@@ -9494,8 +9086,8 @@ exports.NotificationToast = require_field_sidebar.NotificationToast;
|
|
|
9494
9086
|
exports.NumberInput = require_text_truncate.NumberInput;
|
|
9495
9087
|
exports.OPT_TEXT_PRIMARY = require_text_truncate.OPT_TEXT_PRIMARY;
|
|
9496
9088
|
exports.OPT_TEXT_SECONDARY = require_text_truncate.OPT_TEXT_SECONDARY;
|
|
9497
|
-
exports.OptThemeControllerContext = OptThemeControllerContext;
|
|
9498
|
-
exports.OptThemeProvider = OptThemeProvider;
|
|
9089
|
+
exports.OptThemeControllerContext = require_field_sidebar.OptThemeControllerContext;
|
|
9090
|
+
exports.OptThemeProvider = require_field_sidebar.OptThemeProvider;
|
|
9499
9091
|
exports.OtpField = require_key_pad_menu.OtpField;
|
|
9500
9092
|
exports.POPULAR_ICONS = POPULAR_ICONS;
|
|
9501
9093
|
exports.PageAside = PageAside;
|
|
@@ -9511,7 +9103,14 @@ exports.PromptTemplate = PromptTemplate;
|
|
|
9511
9103
|
exports.PropertyExplorer = PropertyExplorer;
|
|
9512
9104
|
exports.QueryBar = require_field_sidebar.QueryBar;
|
|
9513
9105
|
exports.QueryFilterBar = QueryFilterBar;
|
|
9514
|
-
exports.
|
|
9106
|
+
exports.QueryFiltersMenu = require_field_sidebar.QueryFiltersMenu;
|
|
9107
|
+
exports.QueryHistoryList = require_field_sidebar.QueryHistoryList;
|
|
9108
|
+
exports.QueryOutputPane = require_field_sidebar.QueryOutputPane;
|
|
9109
|
+
exports.QueryResultChart = require_field_sidebar.QueryResultChart;
|
|
9110
|
+
exports.QueryResultsTable = require_field_sidebar.QueryResultsTable;
|
|
9111
|
+
exports.QueryToolbar = require_field_sidebar.QueryToolbar;
|
|
9112
|
+
exports.QueryVariablesMenu = require_field_sidebar.QueryVariablesMenu;
|
|
9113
|
+
exports.QueryWorkspace = require_field_sidebar.QueryWorkspace;
|
|
9515
9114
|
exports.QuickActions = QuickActions;
|
|
9516
9115
|
exports.Radio = require_key_pad_menu.Radio;
|
|
9517
9116
|
exports.RadioGroup = require_key_pad_menu.RadioGroup;
|
|
@@ -9522,9 +9121,9 @@ Object.defineProperty(exports, "ReportWidget", {
|
|
|
9522
9121
|
return _reopt_ai_opt_charts.ReportWidget;
|
|
9523
9122
|
}
|
|
9524
9123
|
});
|
|
9525
|
-
exports.ResizableHandle =
|
|
9526
|
-
exports.ResizablePanel =
|
|
9527
|
-
exports.ResizablePanelGroup =
|
|
9124
|
+
exports.ResizableHandle = require_text_truncate.ResizableHandle;
|
|
9125
|
+
exports.ResizablePanel = require_text_truncate.ResizablePanel;
|
|
9126
|
+
exports.ResizablePanelGroup = require_text_truncate.ResizablePanelGroup;
|
|
9528
9127
|
exports.RichTextEditor = RichTextEditor;
|
|
9529
9128
|
exports.RouteFocusManager = RouteFocusManager;
|
|
9530
9129
|
exports.SHADER_OVERLAY_PARAM_KEYS = require_key_pad_menu.SHADER_OVERLAY_PARAM_KEYS;
|
|
@@ -9532,13 +9131,15 @@ exports.SHADER_PARAM_FALLBACK = require_key_pad_menu.SHADER_PARAM_FALLBACK;
|
|
|
9532
9131
|
exports.SHADER_PARAM_KEYS = require_key_pad_menu.SHADER_PARAM_KEYS;
|
|
9533
9132
|
exports.SHADER_PRESETS = require_key_pad_menu.SHADER_PRESETS;
|
|
9534
9133
|
exports.SHADER_PRESET_IDS = require_key_pad_menu.SHADER_PRESET_IDS;
|
|
9134
|
+
exports.SaveQueryDialog = require_field_sidebar.SaveQueryDialog;
|
|
9535
9135
|
exports.SavedFilters = SavedFilters;
|
|
9136
|
+
exports.SchemaTree = require_field_sidebar.SchemaTree;
|
|
9536
9137
|
exports.ScoreBreakdown = require_field_sidebar.ScoreBreakdown;
|
|
9537
9138
|
exports.ScrollArea = require_key_pad_menu.ScrollArea;
|
|
9538
9139
|
exports.SearchCombobox = require_field_sidebar.SearchCombobox;
|
|
9539
9140
|
exports.Section = require_key_pad_menu.Section;
|
|
9540
9141
|
exports.SegmentBuilder = SegmentBuilder;
|
|
9541
|
-
exports.SegmentedControl = SegmentedControl;
|
|
9142
|
+
exports.SegmentedControl = require_field_sidebar.SegmentedControl;
|
|
9542
9143
|
exports.SelectItem = require_text_truncate.SelectItem;
|
|
9543
9144
|
exports.SelectLabel = require_text_truncate.SelectLabel;
|
|
9544
9145
|
exports.SelectPopover = require_text_truncate.SelectPopover;
|
|
@@ -9557,7 +9158,7 @@ exports.SkeletonText = require_text_truncate.SkeletonText;
|
|
|
9557
9158
|
exports.Slider = require_text_truncate.Slider;
|
|
9558
9159
|
exports.SpatialNavProvider = SpatialNavProvider;
|
|
9559
9160
|
exports.Spinner = require_text_truncate.Spinner;
|
|
9560
|
-
exports.SqlEditor = SqlEditor;
|
|
9161
|
+
exports.SqlEditor = require_field_sidebar.SqlEditor;
|
|
9561
9162
|
exports.StarRating = require_text_truncate.StarRating;
|
|
9562
9163
|
exports.StatCard = require_text_truncate.StatCard;
|
|
9563
9164
|
exports.StatusDot = StatusDot;
|
|
@@ -9565,12 +9166,12 @@ exports.StatusSelect = require_field_sidebar.StatusSelect;
|
|
|
9565
9166
|
exports.StepBuilder = require_key_pad_menu.StepBuilder;
|
|
9566
9167
|
exports.SummaryRow = SummaryRow;
|
|
9567
9168
|
exports.SurfaceLayout = require_key_pad_menu.BlockLayout;
|
|
9568
|
-
exports.Switch =
|
|
9169
|
+
exports.Switch = require_text_truncate.Switch;
|
|
9569
9170
|
exports.THEME_PALETTES = require_key_pad_menu.THEME_PALETTES;
|
|
9570
|
-
exports.THEME_PRESET_IDS = THEME_PRESET_IDS;
|
|
9571
|
-
exports.THEME_REGISTRY = THEME_REGISTRY;
|
|
9572
|
-
exports.THEME_SPEC_STORAGE_KEY = THEME_SPEC_STORAGE_KEY;
|
|
9573
|
-
exports.THEME_TOKENS_STORAGE_KEY = THEME_TOKENS_STORAGE_KEY;
|
|
9171
|
+
exports.THEME_PRESET_IDS = require_field_sidebar.THEME_PRESET_IDS;
|
|
9172
|
+
exports.THEME_REGISTRY = require_field_sidebar.THEME_REGISTRY;
|
|
9173
|
+
exports.THEME_SPEC_STORAGE_KEY = require_field_sidebar.THEME_SPEC_STORAGE_KEY;
|
|
9174
|
+
exports.THEME_TOKENS_STORAGE_KEY = require_field_sidebar.THEME_TOKENS_STORAGE_KEY;
|
|
9574
9175
|
exports.Tab = require_text_truncate.Tab;
|
|
9575
9176
|
exports.TabList = require_text_truncate.TabList;
|
|
9576
9177
|
exports.TabPanel = require_text_truncate.TabPanel;
|
|
@@ -9581,7 +9182,7 @@ exports.TeamMemberList = TeamMemberList;
|
|
|
9581
9182
|
exports.TemplatePicker = TemplatePicker;
|
|
9582
9183
|
exports.Text = require_key_pad_menu.Text;
|
|
9583
9184
|
exports.TextTruncate = require_text_truncate.TextTruncate;
|
|
9584
|
-
exports.Textarea =
|
|
9185
|
+
exports.Textarea = require_text_truncate.Textarea;
|
|
9585
9186
|
exports.ThemeSwitcher = ThemeSwitcher;
|
|
9586
9187
|
exports.TimeRangeControl = require_field_sidebar.TimeRangeControl;
|
|
9587
9188
|
exports.TimeRangeSelector = TimeRangeSelector;
|
|
@@ -9603,6 +9204,7 @@ Object.defineProperty(exports, "TrendChart", {
|
|
|
9603
9204
|
return _reopt_ai_opt_charts.TrendChart;
|
|
9604
9205
|
}
|
|
9605
9206
|
});
|
|
9207
|
+
exports.VALUELESS_OPERATORS = require_field_sidebar.VALUELESS_OPERATORS;
|
|
9606
9208
|
exports.VerticalTabs = VerticalTabs;
|
|
9607
9209
|
exports.VirtualList = require_key_pad_menu.VirtualList;
|
|
9608
9210
|
exports.WebhookConfig = WebhookConfig;
|
|
@@ -9611,15 +9213,24 @@ exports.WizardForm = WizardForm;
|
|
|
9611
9213
|
exports.WorkflowCanvas = require_field_sidebar.WorkflowCanvas;
|
|
9612
9214
|
exports.addClause = require_field_sidebar.addClause;
|
|
9613
9215
|
exports.applyCellAction = require_field_sidebar.applyCellAction;
|
|
9614
|
-
exports.buildTokenCache = buildTokenCache;
|
|
9216
|
+
exports.buildTokenCache = require_field_sidebar.buildTokenCache;
|
|
9615
9217
|
exports.cn = require_text_truncate.cn;
|
|
9616
|
-
exports.coerceThemeMode = coerceThemeMode;
|
|
9617
|
-
exports.computeGeneratedTokens = computeGeneratedTokens;
|
|
9218
|
+
exports.coerceThemeMode = require_field_sidebar.coerceThemeMode;
|
|
9219
|
+
exports.computeGeneratedTokens = require_field_sidebar.computeGeneratedTokens;
|
|
9618
9220
|
exports.computeSpatialTargets = computeSpatialTargets;
|
|
9221
|
+
exports.countActiveQueryFilters = require_field_sidebar.countActiveQueryFilters;
|
|
9619
9222
|
exports.createBlock = require_key_pad_menu.createBlock;
|
|
9620
9223
|
exports.createSurface = require_key_pad_menu.createBlock;
|
|
9621
|
-
exports.createThemeBootScript = createThemeBootScript;
|
|
9622
|
-
exports.
|
|
9224
|
+
exports.createThemeBootScript = require_field_sidebar.createThemeBootScript;
|
|
9225
|
+
exports.criteriaBuilderDuplicate = criteriaBuilderDuplicate;
|
|
9226
|
+
exports.criteriaBuilderDuplicateGroup = criteriaBuilderDuplicateGroup;
|
|
9227
|
+
exports.criteriaBuilderInsert = criteriaBuilderInsert;
|
|
9228
|
+
exports.criteriaBuilderMove = criteriaBuilderMove;
|
|
9229
|
+
exports.criteriaBuilderRemove = criteriaBuilderRemove;
|
|
9230
|
+
exports.criteriaBuilderRemoveGroup = criteriaBuilderRemoveGroup;
|
|
9231
|
+
exports.criteriaGroupLetter = criteriaGroupLetter;
|
|
9232
|
+
exports.defaultQueryChartConfig = require_field_sidebar.defaultQueryChartConfig;
|
|
9233
|
+
exports.defineThemeOverrides = require_field_sidebar.defineThemeOverrides;
|
|
9623
9234
|
exports.describeClause = require_field_sidebar.describeClause;
|
|
9624
9235
|
exports.enBreadcrumbLabels = enBreadcrumbLabels;
|
|
9625
9236
|
exports.enComboboxLabels = enComboboxLabels;
|
|
@@ -9631,42 +9242,51 @@ exports.formatOptNumber = require_text_truncate.formatOptNumber;
|
|
|
9631
9242
|
exports.formatOptShortDate = require_text_truncate.formatOptShortDate;
|
|
9632
9243
|
exports.formatOptTime = require_text_truncate.formatOptTime;
|
|
9633
9244
|
exports.formatQuery = require_field_sidebar.formatQuery;
|
|
9634
|
-
exports.
|
|
9635
|
-
exports.
|
|
9636
|
-
exports.
|
|
9245
|
+
exports.formatQueryCell = require_field_sidebar.formatQueryCell;
|
|
9246
|
+
exports.generatedTheme = require_field_sidebar.generatedTheme;
|
|
9247
|
+
exports.getCompoundIdForSpec = require_field_sidebar.getCompoundIdForSpec;
|
|
9248
|
+
exports.getCompoundTheme = require_field_sidebar.getCompoundTheme;
|
|
9637
9249
|
exports.getShaderFragment = require_key_pad_menu.getShaderFragment;
|
|
9638
9250
|
exports.getShaderPreset = require_key_pad_menu.getShaderPreset;
|
|
9639
|
-
exports.getThemeDescriptor = getThemeDescriptor;
|
|
9251
|
+
exports.getThemeDescriptor = require_field_sidebar.getThemeDescriptor;
|
|
9640
9252
|
exports.getTrappedContextRole = getTrappedContextRole;
|
|
9641
9253
|
exports.hasActiveQuery = hasActiveQuery;
|
|
9642
|
-
exports.
|
|
9254
|
+
exports.hasActiveQueryFilters = require_field_sidebar.hasActiveQueryFilters;
|
|
9255
|
+
exports.isDescriptorSpec = require_field_sidebar.isDescriptorSpec;
|
|
9643
9256
|
exports.isEmptyQuery = require_field_sidebar.isEmptyQuery;
|
|
9644
|
-
exports.isForceLightSpec = isForceLightSpec;
|
|
9645
|
-
exports.isGeneratedSpec = isGeneratedSpec;
|
|
9646
|
-
exports.isPresetSpec = isPresetSpec;
|
|
9647
|
-
exports.isThemePresetId = isThemePresetId;
|
|
9257
|
+
exports.isForceLightSpec = require_field_sidebar.isForceLightSpec;
|
|
9258
|
+
exports.isGeneratedSpec = require_field_sidebar.isGeneratedSpec;
|
|
9259
|
+
exports.isPresetSpec = require_field_sidebar.isPresetSpec;
|
|
9260
|
+
exports.isThemePresetId = require_field_sidebar.isThemePresetId;
|
|
9261
|
+
exports.isValidQueryVariableName = require_field_sidebar.isValidQueryVariableName;
|
|
9648
9262
|
exports.koBreadcrumbLabels = require_text_truncate.koBreadcrumbLabels;
|
|
9649
9263
|
exports.koComboboxLabels = require_text_truncate.koComboboxLabels;
|
|
9650
9264
|
exports.koStarRatingLabels = require_text_truncate.koStarRatingLabels;
|
|
9651
9265
|
exports.matchesQuery = matchesQuery;
|
|
9652
9266
|
exports.matchesQueryObject = matchesQueryObject;
|
|
9267
|
+
exports.numericResultColumns = require_field_sidebar.numericResultColumns;
|
|
9653
9268
|
exports.parseQuery = require_field_sidebar.parseQuery;
|
|
9654
9269
|
exports.parseQueryWithDiagnostics = require_field_sidebar.parseQueryWithDiagnostics;
|
|
9655
|
-
exports.presetTheme = presetTheme;
|
|
9270
|
+
exports.presetTheme = require_field_sidebar.presetTheme;
|
|
9656
9271
|
exports.queryFields = require_field_sidebar.queryFields;
|
|
9657
9272
|
exports.quoteValue = require_field_sidebar.quoteValue;
|
|
9658
|
-
exports.readStoredTheme = readStoredTheme;
|
|
9273
|
+
exports.readStoredTheme = require_field_sidebar.readStoredTheme;
|
|
9659
9274
|
exports.removeClause = require_field_sidebar.removeClause;
|
|
9660
|
-
exports.
|
|
9275
|
+
exports.replaceSqlPlaceholder = replaceSqlPlaceholder;
|
|
9276
|
+
exports.resolveDescriptor = require_field_sidebar.resolveDescriptor;
|
|
9661
9277
|
exports.resolveFieldType = require_text_truncate.resolveFieldType;
|
|
9662
|
-
exports.resolveThemeMode = resolveThemeMode;
|
|
9663
|
-
exports.safeParseStoredSpec = safeParseStoredSpec;
|
|
9664
|
-
exports.safeParseStoredTokens = safeParseStoredTokens;
|
|
9278
|
+
exports.resolveThemeMode = require_field_sidebar.resolveThemeMode;
|
|
9279
|
+
exports.safeParseStoredSpec = require_field_sidebar.safeParseStoredSpec;
|
|
9280
|
+
exports.safeParseStoredTokens = require_field_sidebar.safeParseStoredTokens;
|
|
9665
9281
|
exports.schemaValidator = schemaValidator;
|
|
9666
|
-
exports.serializeGeneratedTheme = serializeGeneratedTheme;
|
|
9667
|
-
exports.serializeThemeRule = serializeThemeRule;
|
|
9668
|
-
exports.serializeTokenBody = serializeTokenBody;
|
|
9282
|
+
exports.serializeGeneratedTheme = require_field_sidebar.serializeGeneratedTheme;
|
|
9283
|
+
exports.serializeThemeRule = require_field_sidebar.serializeThemeRule;
|
|
9284
|
+
exports.serializeTokenBody = require_field_sidebar.serializeTokenBody;
|
|
9669
9285
|
exports.shouldSkipArrow = shouldSkipArrow;
|
|
9286
|
+
exports.splitSqlStatements = splitSqlStatements;
|
|
9287
|
+
exports.sqlPlaceholderNames = sqlPlaceholderNames;
|
|
9288
|
+
exports.sqlStatementAtOffset = sqlStatementAtOffset;
|
|
9289
|
+
exports.sqlUsesPlaceholder = sqlUsesPlaceholder;
|
|
9670
9290
|
exports.toast = require_field_sidebar.toast;
|
|
9671
9291
|
exports.useAutoRefresh = require_field_sidebar.useAutoRefresh;
|
|
9672
9292
|
exports.useControlledState = require_text_truncate.useControlledState;
|
|
@@ -9674,9 +9294,9 @@ exports.useFieldValue = _reopt_ai_opt_ui_primitives.useFieldValue;
|
|
|
9674
9294
|
exports.useFormContext = _reopt_ai_opt_ui_primitives.useFormContext;
|
|
9675
9295
|
exports.useFormStore = _reopt_ai_opt_ui_primitives.useFormStore;
|
|
9676
9296
|
exports.useInputId = require_text_truncate.useInputId;
|
|
9677
|
-
exports.useOptTheme = useOptTheme;
|
|
9678
|
-
exports.useOptThemeController = useOptThemeController;
|
|
9679
|
-
exports.useOptionalOptTheme = useOptionalOptTheme;
|
|
9297
|
+
exports.useOptTheme = require_field_sidebar.useOptTheme;
|
|
9298
|
+
exports.useOptThemeController = require_field_sidebar.useOptThemeController;
|
|
9299
|
+
exports.useOptionalOptTheme = require_field_sidebar.useOptionalOptTheme;
|
|
9680
9300
|
exports.useSidebar = useSidebar;
|
|
9681
9301
|
exports.useToast = require_field_sidebar.useToast;
|
|
9682
9302
|
exports.withFieldValue = require_field_sidebar.withFieldValue;
|