@reopt-ai/opt-ui 1.13.0 → 1.15.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/COMPONENT_CATALOG.md +644 -123
  3. package/README.md +35 -7
  4. package/dist/core/index.cjs +4 -4
  5. package/dist/core/index.d.cts +2 -2
  6. package/dist/core/index.d.ts +2 -2
  7. package/dist/core/index.js +2 -2
  8. package/dist/docs/02-components/01-core.md +261 -58
  9. package/dist/docs/02-components/02-visuals.md +1 -1
  10. package/dist/docs/02-components/03-shells.md +391 -65
  11. package/dist/docs/02-components/04-surfaces.md +1 -1
  12. package/dist/docs/02-components/index.md +4 -4
  13. package/dist/id-registry.cjs +32 -0
  14. package/dist/id-registry.js +32 -0
  15. package/dist/id-registry.json +68 -0
  16. package/dist/index.cjs +1196 -427
  17. package/dist/index.d.cts +208 -19
  18. package/dist/index.d.ts +208 -19
  19. package/dist/index.js +1050 -295
  20. package/dist/{key-pad-menu-DMmbQ1jF.js → key-pad-menu-BCOeYvsH.js} +59 -67
  21. package/dist/{key-pad-menu-BOVu97bj.d.cts → key-pad-menu-CaIsTHB2.d.cts} +22 -9
  22. package/dist/{key-pad-menu-0KWOnELe.cjs → key-pad-menu-Jaqxhx9P.cjs} +57 -77
  23. package/dist/{key-pad-menu-NlZ9zNF8.d.ts → key-pad-menu-odAEycIX.d.ts} +22 -9
  24. package/dist/meta.cjs +877 -26
  25. package/dist/meta.js +877 -26
  26. package/dist/{field-sidebar-CRdToHRO.js → replay-player-layout-BVUNsUS1.js} +904 -203
  27. package/dist/{field-sidebar-CxxSK4JO.cjs → replay-player-layout-Cmzptq89.cjs} +944 -201
  28. package/dist/{field-sidebar-D-rwuN_w.d.cts → replay-player-layout-DpqdfdQ6.d.ts} +246 -3
  29. package/dist/{field-sidebar-Dz7J4ett.d.ts → replay-player-layout-DuZW-gFF.d.cts} +246 -3
  30. package/dist/shells/index.cjs +58 -52
  31. package/dist/shells/index.d.cts +2 -2
  32. package/dist/shells/index.d.ts +2 -2
  33. package/dist/shells/index.js +2 -2
  34. package/dist/{text-truncate-Bd-0WkSP.js → text-truncate-B-8nJgnu.js} +200 -101
  35. package/dist/{text-truncate-eMzvU_7k.d.cts → text-truncate-DOxUijpB.d.cts} +3 -30
  36. package/dist/{text-truncate-eMzvU_7k.d.ts → text-truncate-DOxUijpB.d.ts} +3 -30
  37. package/dist/{text-truncate-BeYW6XZu.cjs → text-truncate-gQhpMy-Z.cjs} +214 -97
  38. package/dist/theme/server.d.cts +2 -2
  39. package/dist/theme/server.d.ts +2 -2
  40. package/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use client";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_text_truncate = require("./text-truncate-BeYW6XZu.cjs");
4
- const require_key_pad_menu = require("./key-pad-menu-0KWOnELe.cjs");
5
- const require_field_sidebar = require("./field-sidebar-CxxSK4JO.cjs");
3
+ const require_text_truncate = require("./text-truncate-gQhpMy-Z.cjs");
4
+ const require_key_pad_menu = require("./key-pad-menu-Jaqxhx9P.cjs");
5
+ const require_replay_player_layout = require("./replay-player-layout-Cmzptq89.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);
@@ -93,7 +93,7 @@ const _excluded = [
93
93
  "disabled",
94
94
  "onClick"
95
95
  ];
96
- const defaultLabels$33 = {
96
+ const defaultLabels$34 = {
97
97
  copy: "복사",
98
98
  copied: "복사됨",
99
99
  failed: "복사할 수 없습니다"
@@ -140,7 +140,7 @@ const stateTone = {
140
140
  */
141
141
  function CopyButton(_ref) {
142
142
  let { value, variant = "icon", size = "md", feedbackDuration = 1500, onCopy, labels: customLabels, className, disabled, onClick } = _ref, props = require_text_truncate._objectWithoutProperties(_ref, _excluded);
143
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$33), customLabels);
143
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$34), customLabels);
144
144
  const [state, setState] = (0, react.useState)("idle");
145
145
  const timer = (0, react.useRef)(null);
146
146
  (0, react.useEffect)(() => () => {
@@ -265,7 +265,7 @@ function PageAside({ header, children, footer, widthClassName = "w-60", label, h
265
265
  PageAside.displayName = "PageAside";
266
266
  //#endregion
267
267
  //#region src/shells/task-list.tsx
268
- const defaultLabels$32 = {
268
+ const defaultLabels$33 = {
269
269
  title: "작업 목록",
270
270
  emptyMessage: "작업이 없습니다",
271
271
  completedOf: "{completed}/{total} 완료",
@@ -285,9 +285,9 @@ const defaultLabels$32 = {
285
285
  };
286
286
  /** Renders the task list component. */
287
287
  function TaskList({ tasks, title, onTaskClick, onTaskStatusChange, emptyMessage, showSubtasks = false, maxItems, labels: customLabels, className }) {
288
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$32), customLabels), {}, {
289
- priority: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$32.priority), customLabels === null || customLabels === void 0 ? void 0 : customLabels.priority),
290
- status: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$32.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status)
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)
291
291
  });
292
292
  const displayTitle = title !== null && title !== void 0 ? title : labels.title;
293
293
  const displayEmptyMessage = emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : labels.emptyMessage;
@@ -445,7 +445,7 @@ function TaskList({ tasks, title, onTaskClick, onTaskStatusChange, emptyMessage,
445
445
  }
446
446
  //#endregion
447
447
  //#region src/shells/activity-feed.tsx
448
- const defaultLabels$31 = {
448
+ const defaultLabels$32 = {
449
449
  title: "활동 피드",
450
450
  emptyMessage: "활동이 없습니다",
451
451
  moreItems: "{count}개 더 보기",
@@ -495,24 +495,24 @@ const variantBorder = {
495
495
  function ActivityFeed({ activities, title, maxItems, onActivityClick, onShowMore, emptyMessage, labels: customLabels, locale = "ko-KR", loading = false, layout = "list", renderActions, className }) {
496
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;
497
497
  const mergedTimeAgo = {
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$31.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$31.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$31.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$31.timeAgo.daysAgo
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
502
502
  };
503
503
  const mergedActivityVerbs = {
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$31.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$31.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$31.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$31.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$31.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$31.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$31.activityVerbs.merged
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
511
511
  };
512
512
  const labels = {
513
- title: (_customLabels$title = customLabels === null || customLabels === void 0 ? void 0 : customLabels.title) !== null && _customLabels$title !== void 0 ? _customLabels$title : defaultLabels$31.title,
514
- emptyMessage: (_customLabels$emptyMe = customLabels === null || customLabels === void 0 ? void 0 : customLabels.emptyMessage) !== null && _customLabels$emptyMe !== void 0 ? _customLabels$emptyMe : defaultLabels$31.emptyMessage,
515
- moreItems: (_customLabels$moreIte = customLabels === null || customLabels === void 0 ? void 0 : customLabels.moreItems) !== null && _customLabels$moreIte !== void 0 ? _customLabels$moreIte : defaultLabels$31.moreItems,
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,
516
516
  timeAgo: mergedTimeAgo,
517
517
  activityVerbs: mergedActivityVerbs
518
518
  };
@@ -640,13 +640,13 @@ function ActivityFeed({ activities, title, maxItems, onActivityClick, onShowMore
640
640
  ActivityFeed.displayName = "ActivityFeed";
641
641
  //#endregion
642
642
  //#region src/shells/filter-bar.tsx
643
- const defaultLabels$30 = {
643
+ const defaultLabels$31 = {
644
644
  clearAll: "필터 초기화",
645
645
  searchPlaceholder: "검색..."
646
646
  };
647
647
  /** Renders the filter bar component. */
648
648
  function FilterBar({ filters, onFilterChange, onDateRangeChange, onClearAll, labels: customLabels, presetActions, className }) {
649
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$30), customLabels);
649
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$31), customLabels);
650
650
  const [searchValues, setSearchValues] = (0, react.useState)({});
651
651
  const [tagInputValues, setTagInputValues] = (0, react.useState)({});
652
652
  const [multiSelectOpen, setMultiSelectOpen] = (0, react.useState)({});
@@ -872,10 +872,10 @@ function matchesShortcut(event, shortcut) {
872
872
  if (requiresMeta && !event.metaKey) return false;
873
873
  return event.key.toLowerCase() === key;
874
874
  }
875
- const defaultLabels$29 = { title: "빠른 작업" };
875
+ const defaultLabels$30 = { title: "빠른 작업" };
876
876
  /** Renders the quick actions component. */
877
877
  function QuickActions({ actions, title, layout = "grid", columns = 3, showDescriptionInGrid = false, bindShortcuts = false, labels: customLabels, className }) {
878
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$29), customLabels);
878
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$30), customLabels);
879
879
  const displayTitle = title !== null && title !== void 0 ? title : labels.title;
880
880
  const titleId = (0, react.useId)();
881
881
  (0, react.useEffect)(() => {
@@ -953,7 +953,7 @@ function QuickActions({ actions, title, layout = "grid", columns = 3, showDescri
953
953
  QuickActions.displayName = "QuickActions";
954
954
  //#endregion
955
955
  //#region src/shells/team-member-list.tsx
956
- const defaultLabels$28 = {
956
+ const defaultLabels$29 = {
957
957
  title: "팀원",
958
958
  emptyMessage: "팀원이 없습니다",
959
959
  onlineCount: "{online}/{total} 온라인",
@@ -974,7 +974,7 @@ const statusDot = {
974
974
  };
975
975
  /** Renders the team member list component. */
976
976
  function TeamMemberList({ members, title, layout = "list", maxDisplay, onMemberClick, onShowMore, emptyMessage, labels: customLabels, className }) {
977
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$28), customLabels), {}, { status: require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$28.status), customLabels === null || customLabels === void 0 ? void 0 : customLabels.status) });
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) });
978
978
  const displayTitle = title !== null && title !== void 0 ? title : labels.title;
979
979
  const displayEmptyMessage = emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : labels.emptyMessage;
980
980
  const titleId = (0, react.useId)();
@@ -1127,9 +1127,14 @@ function TeamMemberList({ members, title, layout = "list", maxDisplay, onMemberC
1127
1127
  //#region src/shells/auth-form.tsx
1128
1128
  /** Renders the auth form component. */
1129
1129
  function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, showRememberMe = true, minPasswordLength = 8, onSubmit, renderExtraFields, labels = {}, ariaLabel }) {
1130
- var _labels$loginTitle, _labels$signupTitle, _labels$emailLabel, _labels$passwordLabel, _labels$confirmPasswo, _labels$rememberMeLab, _labels$loginButton, _labels$signupButton;
1130
+ var _labels$loginTitle, _labels$signupTitle, _labels$emailLabel, _labels$passwordLabel, _labels$confirmPasswo, _labels$rememberMeLab, _labels$loginButton, _labels$signupButton, _labels$submitError;
1131
1131
  const [uncontrolledMode, setUncontrolledMode] = (0, react.useState)(defaultMode);
1132
1132
  const [submitted, setSubmitted] = (0, react.useState)(false);
1133
+ (0, react.useEffect)(() => {
1134
+ if (!submitted) return;
1135
+ const timer = setTimeout(() => setSubmitted(false), 3e3);
1136
+ return () => clearTimeout(timer);
1137
+ }, [submitted]);
1133
1138
  const mode = controlledMode !== null && controlledMode !== void 0 ? controlledMode : uncontrolledMode;
1134
1139
  const handleModeChange = (newMode) => {
1135
1140
  if (controlledMode === void 0) setUncontrolledMode(newMode);
@@ -1168,13 +1173,13 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1168
1173
  }
1169
1174
  return errors;
1170
1175
  },
1171
- onSubmit: (values) => {
1172
- setSubmitted(true);
1173
- setTimeout(() => setSubmitted(false), 3e3);
1174
- if (onSubmit) onSubmit(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({
1176
+ onSubmit: async (values) => {
1177
+ setSubmitted(false);
1178
+ if (onSubmit) await onSubmit(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({
1175
1179
  email: values.email,
1176
1180
  password: values.password
1177
1181
  }, mode === "signup" ? { confirmPassword: values.confirmPassword } : {}), mode === "login" ? { rememberMe: values.rememberMe } : {}), {}, { mode }));
1182
+ setSubmitted(true);
1178
1183
  }
1179
1184
  });
1180
1185
  const loginTitle = (_labels$loginTitle = labels.loginTitle) !== null && _labels$loginTitle !== void 0 ? _labels$loginTitle : "로그인";
@@ -1189,11 +1194,13 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1189
1194
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1190
1195
  type: "button",
1191
1196
  className: `flex-1 rounded-l-lg px-4 py-2 text-sm font-medium transition-colors ${mode === "login" ? "bg-accent text-accent-fg" : "text-text-secondary hover:bg-bg-subtle"}`,
1197
+ disabled: form.isSubmitting(),
1192
1198
  onClick: () => handleModeChange("login"),
1193
1199
  children: loginTitle
1194
1200
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1195
1201
  type: "button",
1196
1202
  className: `flex-1 rounded-r-lg px-4 py-2 text-sm font-medium transition-colors ${mode === "signup" ? "bg-accent text-accent-fg" : "text-text-secondary hover:bg-bg-subtle"}`,
1203
+ disabled: form.isSubmitting(),
1197
1204
  onClick: () => handleModeChange("signup"),
1198
1205
  children: signupTitle
1199
1206
  })]
@@ -1202,8 +1209,8 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1202
1209
  store: form,
1203
1210
  "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : mode === "login" ? "로그인 폼" : "회원가입 폼",
1204
1211
  children: [
1205
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1206
- className: "gap-element flex flex-col",
1212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1213
+ name: "email",
1207
1214
  children: [
1208
1215
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1209
1216
  name: "email",
@@ -1218,8 +1225,8 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1218
1225
  ]
1219
1226
  }),
1220
1227
  renderExtraFields === null || renderExtraFields === void 0 ? void 0 : renderExtraFields(mode),
1221
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1222
- className: "gap-element flex flex-col",
1228
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1229
+ name: "password",
1223
1230
  children: [
1224
1231
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1225
1232
  name: "password",
@@ -1233,8 +1240,8 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1233
1240
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, { name: "password" })
1234
1241
  ]
1235
1242
  }),
1236
- mode === "signup" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1237
- className: "gap-element flex flex-col",
1243
+ mode === "signup" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1244
+ name: "confirmPassword",
1238
1245
  children: [
1239
1246
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1240
1247
  name: "confirmPassword",
@@ -1264,7 +1271,13 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1264
1271
  })
1265
1272
  ]
1266
1273
  }),
1274
+ form.getSubmitError() !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1275
+ role: "alert",
1276
+ className: "border-danger bg-danger-subtle text-danger-fg rounded-lg border p-3 text-sm",
1277
+ children: (_labels$submitError = labels.submitError) !== null && _labels$submitError !== void 0 ? _labels$submitError : "처리에 실패했습니다. 다시 시도해주세요."
1278
+ }),
1267
1279
  submitted && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1280
+ role: "status",
1268
1281
  className: "border-success bg-success-subtle text-success-fg rounded-lg border p-3 text-sm",
1269
1282
  children: mode === "login" ? "로그인 성공!" : "회원가입 완료!"
1270
1283
  })
@@ -1275,11 +1288,16 @@ function AuthForm({ defaultMode = "login", mode: controlledMode, onModeChange, s
1275
1288
  //#region src/shells/dynamic-field-form.tsx
1276
1289
  /** Renders the dynamic field form component. */
1277
1290
  function DynamicFieldForm({ initialCount = 1, minFields = 1, maxFields, fieldType = "text", validateField, onSubmit, onFieldsChange, labels = {}, ariaLabel }) {
1278
- var _labels$itemLabel, _labels$itemPlacehold, _labels$removeAriaLab, _labels$addButton, _labels$submitButton;
1291
+ var _labels$itemLabel, _labels$itemPlacehold, _labels$removeAriaLab, _labels$addButton, _labels$submitButton, _labels$submitError;
1279
1292
  const initialFields = Array.from({ length: initialCount }, (_, i) => ({ id: i + 1 }));
1280
1293
  const [fields, setFields] = (0, react.useState)(initialFields);
1281
1294
  const [nextId, setNextId] = (0, react.useState)(initialCount + 1);
1282
1295
  const [submitted, setSubmitted] = (0, react.useState)(false);
1296
+ (0, react.useEffect)(() => {
1297
+ if (!submitted) return;
1298
+ const timer = setTimeout(() => setSubmitted(false), 3e3);
1299
+ return () => clearTimeout(timer);
1300
+ }, [submitted]);
1283
1301
  const [submittedValues, setSubmittedValues] = (0, react.useState)([]);
1284
1302
  const form = (0, _reopt_ai_opt_ui_primitives.useFormStore)({
1285
1303
  defaultValues: { items: Array.from({ length: initialCount }, () => "") },
@@ -1303,12 +1321,12 @@ function DynamicFieldForm({ initialCount = 1, minFields = 1, maxFields, fieldTyp
1303
1321
  }
1304
1322
  return errors;
1305
1323
  },
1306
- onSubmit: (values) => {
1324
+ onSubmit: async (values) => {
1325
+ setSubmitted(false);
1307
1326
  const items = [...values.items];
1327
+ await (onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(items));
1308
1328
  setSubmittedValues(items);
1309
1329
  setSubmitted(true);
1310
- setTimeout(() => setSubmitted(false), 3e3);
1311
- onSubmit === null || onSubmit === void 0 || onSubmit(items);
1312
1330
  }
1313
1331
  });
1314
1332
  const addField = () => {
@@ -1339,70 +1357,79 @@ function DynamicFieldForm({ initialCount = 1, minFields = 1, maxFields, fieldTyp
1339
1357
  className: "gap-group flex flex-col",
1340
1358
  "data-opt-id": "8RYG7",
1341
1359
  "data-opt-slug": "form-dynamic.DynamicFieldForm",
1342
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormRoot, {
1343
- store: form,
1344
- "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "동적 필드 폼",
1345
- children: [
1346
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1347
- className: "gap-group flex flex-col",
1348
- children: fields.map((field, displayIndex) => {
1349
- const fieldName = `items.${displayIndex}`;
1350
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1351
- className: "gap-element flex flex-col",
1352
- children: [
1353
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1354
- name: fieldName,
1355
- children: formatTemplate(itemLabel, displayIndex + 1)
1356
- }),
1357
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1358
- className: "gap-element flex",
1359
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1360
- className: "flex-1",
1361
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormInput, {
1362
- name: fieldName,
1363
- type: fieldType,
1364
- placeholder: formatTemplate(itemPlaceholder, displayIndex + 1)
1365
- })
1366
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1367
- type: "button",
1368
- onClick: () => removeField(field.id),
1369
- disabled: fields.length <= minFields,
1370
- className: "border-border text-text-tertiary hover:border-danger hover:bg-danger-subtle hover:text-danger-fg inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border transition-colors disabled:cursor-not-allowed disabled:opacity-30",
1371
- "aria-label": formatTemplate(removeAriaLabel, displayIndex + 1),
1372
- children: "✕"
1373
- })]
1374
- }),
1375
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, { name: fieldName })
1376
- ]
1377
- }, field.id);
1360
+ children: [
1361
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormRoot, {
1362
+ store: form,
1363
+ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "동적 필드 폼",
1364
+ children: [
1365
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1366
+ className: "gap-group flex flex-col",
1367
+ children: fields.map((field, displayIndex) => {
1368
+ const fieldName = `items.${displayIndex}`;
1369
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1370
+ name: fieldName,
1371
+ children: [
1372
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1373
+ name: fieldName,
1374
+ children: formatTemplate(itemLabel, displayIndex + 1)
1375
+ }),
1376
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1377
+ className: "gap-element flex",
1378
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1379
+ className: "flex-1",
1380
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormInput, {
1381
+ name: fieldName,
1382
+ type: fieldType,
1383
+ placeholder: formatTemplate(itemPlaceholder, displayIndex + 1)
1384
+ })
1385
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1386
+ type: "button",
1387
+ onClick: () => removeField(field.id),
1388
+ disabled: form.isSubmitting() || fields.length <= minFields,
1389
+ className: "border-border text-text-tertiary hover:border-danger hover:bg-danger-subtle hover:text-danger-fg inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-lg border transition-colors disabled:cursor-not-allowed disabled:opacity-30",
1390
+ "aria-label": formatTemplate(removeAriaLabel, displayIndex + 1),
1391
+ children: "✕"
1392
+ })]
1393
+ }),
1394
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, { name: fieldName })
1395
+ ]
1396
+ }, field.id);
1397
+ })
1398
+ }),
1399
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1400
+ type: "button",
1401
+ onClick: addField,
1402
+ disabled: form.isSubmitting() || maxFields !== void 0 && fields.length >= maxFields,
1403
+ className: "border-border text-text-secondary hover:border-accent hover:bg-accent-subtle hover:text-accent w-full rounded-lg border border-dashed px-4 py-2.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-30",
1404
+ children: (_labels$addButton = labels.addButton) !== null && _labels$addButton !== void 0 ? _labels$addButton : "+ 항목 추가"
1405
+ }),
1406
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSubmit, {
1407
+ disabled: form.isSubmitting(),
1408
+ children: (_labels$submitButton = labels.submitButton) !== null && _labels$submitButton !== void 0 ? _labels$submitButton : "제출"
1378
1409
  })
1379
- }),
1380
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1381
- type: "button",
1382
- onClick: addField,
1383
- disabled: maxFields !== void 0 && fields.length >= maxFields,
1384
- className: "border-border text-text-secondary hover:border-accent hover:bg-accent-subtle hover:text-accent w-full rounded-lg border border-dashed px-4 py-2.5 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-30",
1385
- children: (_labels$addButton = labels.addButton) !== null && _labels$addButton !== void 0 ? _labels$addButton : "+ 항목 추가"
1386
- }),
1387
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSubmit, {
1388
- disabled: form.isSubmitting(),
1389
- children: (_labels$submitButton = labels.submitButton) !== null && _labels$submitButton !== void 0 ? _labels$submitButton : "제출"
1390
- })
1391
- ]
1392
- }), submitted && submittedValues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1393
- className: "border-success bg-success-subtle rounded-lg border p-3",
1394
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1395
- className: "text-success-fg mb-2 text-sm font-medium",
1396
- children: "제출된 값:"
1397
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1398
- className: "text-success-fg gap-element flex flex-col text-sm",
1399
- children: submittedValues.map((val, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
1400
- formatTemplate(itemLabel, i + 1),
1401
- ": ",
1402
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: val })
1403
- ] }, i))
1404
- })]
1405
- })]
1410
+ ]
1411
+ }),
1412
+ form.getSubmitError() !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1413
+ role: "alert",
1414
+ className: "border-danger bg-danger-subtle text-danger-fg rounded-lg border p-3 text-sm",
1415
+ children: (_labels$submitError = labels.submitError) !== null && _labels$submitError !== void 0 ? _labels$submitError : "처리에 실패했습니다. 다시 시도해주세요."
1416
+ }),
1417
+ submitted && submittedValues.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1418
+ role: "status",
1419
+ className: "border-success bg-success-subtle rounded-lg border p-3",
1420
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1421
+ className: "text-success-fg mb-2 text-sm font-medium",
1422
+ children: "제출된 값:"
1423
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1424
+ className: "text-success-fg gap-element flex flex-col text-sm",
1425
+ children: submittedValues.map((val, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
1426
+ formatTemplate(itemLabel, i + 1),
1427
+ ": ",
1428
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: val })
1429
+ ] }, i))
1430
+ })]
1431
+ })
1432
+ ]
1406
1433
  });
1407
1434
  }
1408
1435
  //#endregion
@@ -1414,10 +1441,16 @@ function formatFileSize(bytes) {
1414
1441
  }
1415
1442
  /** Renders the file upload form component. */
1416
1443
  function FileUploadForm({ accept = "image/*,.pdf,.doc,.docx", showPreview = true, showFileInfo = true, showDescription = true, descriptionRows = 3, titleRequired = true, maxFileSize, onSubmit, onFileChange, onPreview, columnMapping, labels = {}, ariaLabel }) {
1417
- var _labels$titleLabel, _labels$titlePlacehol, _labels$descriptionLa, _labels$descriptionPl, _labels$fileLabel, _labels$columnMapping, _labels$submitButton, _labels$successMessag;
1444
+ var _labels$titleLabel, _labels$titlePlacehol, _labels$descriptionLa, _labels$descriptionPl, _labels$fileLabel, _labels$columnMapping, _labels$submitButton, _labels$submitError, _labels$successMessag;
1445
+ const fileId = (0, react.useId)();
1418
1446
  const [selectedFile, setSelectedFile] = (0, react.useState)(null);
1419
1447
  const [preview, setPreview] = (0, react.useState)(null);
1420
1448
  const [submitted, setSubmitted] = (0, react.useState)(false);
1449
+ (0, react.useEffect)(() => {
1450
+ if (!submitted) return;
1451
+ const timer = setTimeout(() => setSubmitted(false), 3e3);
1452
+ return () => clearTimeout(timer);
1453
+ }, [submitted]);
1421
1454
  const [fileSizeError, setFileSizeError] = (0, react.useState)(null);
1422
1455
  const form = (0, _reopt_ai_opt_ui_primitives.useFormStore)({
1423
1456
  defaultValues: {
@@ -1435,14 +1468,14 @@ function FileUploadForm({ accept = "image/*,.pdf,.doc,.docx", showPreview = true
1435
1468
  }
1436
1469
  return errors;
1437
1470
  },
1438
- onSubmit: (values) => {
1439
- setSubmitted(true);
1440
- setTimeout(() => setSubmitted(false), 3e3);
1441
- if (onSubmit) onSubmit({
1471
+ onSubmit: async (values) => {
1472
+ setSubmitted(false);
1473
+ if (onSubmit) await onSubmit({
1442
1474
  title: values.title,
1443
1475
  description: values.description,
1444
1476
  file: selectedFile
1445
1477
  });
1478
+ setSubmitted(true);
1446
1479
  }
1447
1480
  });
1448
1481
  const handleFileChange = (e) => {
@@ -1474,111 +1507,128 @@ function FileUploadForm({ accept = "image/*,.pdf,.doc,.docx", showPreview = true
1474
1507
  className: "gap-group flex flex-col",
1475
1508
  "data-opt-id": "4E3MD",
1476
1509
  "data-opt-slug": "form-upload.FileUploadForm",
1477
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormRoot, {
1478
- store: form,
1479
- "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "파일 업로드 폼",
1480
- children: [
1481
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1482
- className: "gap-element flex flex-col",
1483
- children: [
1484
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1485
- name: "title",
1486
- children: (_labels$titleLabel = labels.titleLabel) !== null && _labels$titleLabel !== void 0 ? _labels$titleLabel : "제목"
1487
- }),
1488
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormInput, {
1489
- name: "title",
1490
- placeholder: (_labels$titlePlacehol = labels.titlePlaceholder) !== null && _labels$titlePlacehol !== void 0 ? _labels$titlePlacehol : "파일 제목을 입력하세요"
1491
- }),
1492
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, { name: "title" })
1493
- ]
1494
- }),
1495
- showDescription && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1496
- className: "gap-element flex flex-col",
1497
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1498
- name: "description",
1499
- children: (_labels$descriptionLa = labels.descriptionLabel) !== null && _labels$descriptionLa !== void 0 ? _labels$descriptionLa : "설명"
1500
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormTextarea, {
1501
- name: "description",
1502
- placeholder: (_labels$descriptionPl = labels.descriptionPlaceholder) !== null && _labels$descriptionPl !== void 0 ? _labels$descriptionPl : "파일에 대한 설명을 입력하세요",
1503
- rows: descriptionRows,
1504
- resize: "none"
1505
- })]
1506
- }),
1507
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1508
- className: "gap-element flex flex-col",
1509
- children: [
1510
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1511
- className: "text-text-primary text-sm font-medium",
1512
- children: (_labels$fileLabel = labels.fileLabel) !== null && _labels$fileLabel !== void 0 ? _labels$fileLabel : "파일 선택"
1513
- }),
1514
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1515
- className: "relative",
1516
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1517
- type: "file",
1518
- onChange: handleFileChange,
1519
- accept,
1520
- className: "border-border bg-surface text-text-primary file:bg-accent-subtle file:text-accent hover:file:bg-accent-subtle block w-full cursor-pointer rounded-lg border px-4 py-2.5 text-sm file:mr-4 file:cursor-pointer file:rounded-md file:border-0 file:px-3 file:py-1 file:text-sm file:font-medium"
1521
- })
1522
- }),
1523
- fileSizeError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1524
- className: "text-danger-fg text-xs",
1525
- children: fileSizeError
1526
- })
1527
- ]
1528
- }),
1529
- selectedFile && showFileInfo && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1530
- className: "border-border-subtle rounded-lg border p-4",
1531
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1532
- className: "gap-element flex flex-col",
1510
+ children: [
1511
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormRoot, {
1512
+ store: form,
1513
+ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "파일 업로드 폼",
1514
+ children: [
1515
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1516
+ name: "title",
1533
1517
  children: [
1534
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1535
- className: "flex items-center justify-between text-sm",
1536
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1537
- className: "text-text-primary font-medium",
1538
- children: selectedFile.name
1539
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1540
- className: "text-text-tertiary",
1541
- children: formatFileSize(selectedFile.size)
1542
- })]
1518
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1519
+ name: "title",
1520
+ children: (_labels$titleLabel = labels.titleLabel) !== null && _labels$titleLabel !== void 0 ? _labels$titleLabel : "제목"
1543
1521
  }),
1544
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1545
- className: "text-text-tertiary text-xs",
1546
- children: ["타입: ", selectedFile.type || " 없음"]
1522
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormInput, {
1523
+ name: "title",
1524
+ placeholder: (_labels$titlePlacehol = labels.titlePlaceholder) !== null && _labels$titlePlacehol !== void 0 ? _labels$titlePlacehol : "파일 제목을 입력하세요"
1525
+ }),
1526
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, { name: "title" })
1527
+ ]
1528
+ }),
1529
+ showDescription && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1530
+ name: "description",
1531
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1532
+ name: "description",
1533
+ children: (_labels$descriptionLa = labels.descriptionLabel) !== null && _labels$descriptionLa !== void 0 ? _labels$descriptionLa : "설명"
1534
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormTextarea, {
1535
+ name: "description",
1536
+ placeholder: (_labels$descriptionPl = labels.descriptionPlaceholder) !== null && _labels$descriptionPl !== void 0 ? _labels$descriptionPl : "파일에 대한 설명을 입력하세요",
1537
+ rows: descriptionRows,
1538
+ resize: "none"
1539
+ })]
1540
+ }),
1541
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1542
+ name: "file",
1543
+ children: [
1544
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
1545
+ htmlFor: fileId,
1546
+ className: "text-text-primary text-sm font-medium",
1547
+ children: (_labels$fileLabel = labels.fileLabel) !== null && _labels$fileLabel !== void 0 ? _labels$fileLabel : "파일 선택"
1547
1548
  }),
1548
- showPreview && preview && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1549
- className: "border-border-subtle overflow-hidden rounded-lg border",
1550
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1551
- src: preview,
1552
- alt: "미리보기",
1553
- className: "max-h-48 w-full object-contain"
1549
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1550
+ className: "relative",
1551
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1552
+ id: fileId,
1553
+ type: "file",
1554
+ disabled: form.isSubmitting(),
1555
+ "aria-invalid": Boolean(fileSizeError),
1556
+ "aria-describedby": fileSizeError ? `${fileId}-error` : void 0,
1557
+ onChange: handleFileChange,
1558
+ accept,
1559
+ className: "border-border bg-surface text-text-primary file:bg-accent-subtle file:text-accent hover:file:bg-accent-subtle block w-full cursor-pointer rounded-lg border px-4 py-2.5 text-sm file:mr-4 file:cursor-pointer file:rounded-md file:border-0 file:px-3 file:py-1 file:text-sm file:font-medium"
1554
1560
  })
1561
+ }),
1562
+ fileSizeError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1563
+ id: `${fileId}-error`,
1564
+ role: "alert",
1565
+ className: "text-danger-fg text-xs",
1566
+ children: fileSizeError
1555
1567
  })
1556
1568
  ]
1569
+ }),
1570
+ selectedFile && showFileInfo && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1571
+ className: "border-border-subtle rounded-lg border p-4",
1572
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1573
+ className: "gap-element flex flex-col",
1574
+ children: [
1575
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1576
+ className: "flex items-center justify-between text-sm",
1577
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1578
+ className: "text-text-primary font-medium",
1579
+ children: selectedFile.name
1580
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1581
+ className: "text-text-tertiary",
1582
+ children: formatFileSize(selectedFile.size)
1583
+ })]
1584
+ }),
1585
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1586
+ className: "text-text-tertiary text-xs",
1587
+ children: ["타입: ", selectedFile.type || "알 수 없음"]
1588
+ }),
1589
+ showPreview && preview && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1590
+ className: "border-border-subtle overflow-hidden rounded-lg border",
1591
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
1592
+ src: preview,
1593
+ alt: "미리보기",
1594
+ className: "max-h-48 w-full object-contain"
1595
+ })
1596
+ })
1597
+ ]
1598
+ })
1599
+ }),
1600
+ columnMapping && selectedFile && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1601
+ className: "gap-element flex flex-col",
1602
+ "aria-label": (_labels$columnMapping = labels.columnMappingLabel) !== null && _labels$columnMapping !== void 0 ? _labels$columnMapping : "Column mapping",
1603
+ children: columnMapping
1604
+ }),
1605
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSubmit, {
1606
+ disabled: form.isSubmitting(),
1607
+ children: (_labels$submitButton = labels.submitButton) !== null && _labels$submitButton !== void 0 ? _labels$submitButton : "업로드"
1557
1608
  })
1558
- }),
1559
- columnMapping && selectedFile && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1560
- className: "gap-element flex flex-col",
1561
- "aria-label": (_labels$columnMapping = labels.columnMappingLabel) !== null && _labels$columnMapping !== void 0 ? _labels$columnMapping : "Column mapping",
1562
- children: columnMapping
1563
- }),
1564
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSubmit, {
1565
- disabled: form.isSubmitting(),
1566
- children: (_labels$submitButton = labels.submitButton) !== null && _labels$submitButton !== void 0 ? _labels$submitButton : "업로드"
1567
- })
1568
- ]
1569
- }), submitted && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1570
- className: "border-success bg-success-subtle text-success-fg rounded-lg border p-3 text-sm",
1571
- children: (_labels$successMessag = labels.successMessage) !== null && _labels$successMessag !== void 0 ? _labels$successMessag : "업로드가 완료되었습니다!"
1572
- })]
1609
+ ]
1610
+ }),
1611
+ form.getSubmitError() !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1612
+ role: "alert",
1613
+ className: "border-danger bg-danger-subtle text-danger-fg rounded-lg border p-3 text-sm",
1614
+ children: (_labels$submitError = labels.submitError) !== null && _labels$submitError !== void 0 ? _labels$submitError : "처리에 실패했습니다. 다시 시도해주세요."
1615
+ }),
1616
+ submitted && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1617
+ role: "status",
1618
+ className: "border-success bg-success-subtle text-success-fg rounded-lg border p-3 text-sm",
1619
+ children: (_labels$successMessag = labels.successMessage) !== null && _labels$successMessag !== void 0 ? _labels$successMessag : "업로드가 완료되었습니다!"
1620
+ })
1621
+ ]
1573
1622
  });
1574
1623
  }
1575
1624
  //#endregion
1576
1625
  //#region src/shells/wizard-form.tsx
1577
1626
  /** Renders the wizard form component. */
1578
1627
  function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange, resetOnSuccess = false, labels = {}, ariaLabel }) {
1579
- var _labels$reviewTitle, _labels$stepsLabel, _labels$reviewTitle2, _labels$backButton, _labels$submitButton, _labels$nextButton, _labels$successMessag, _labels$resetLink;
1628
+ var _labels$reviewTitle, _labels$stepsLabel, _labels$reviewTitle2, _labels$backButton, _labels$submitButton, _labels$nextButton, _labels$submitError, _labels$successMessag, _labels$resetLink;
1580
1629
  const [currentStep, setCurrentStep] = (0, react.useState)(0);
1581
1630
  const [submitted, setSubmitted] = (0, react.useState)(false);
1631
+ const formId = (0, react.useId)();
1582
1632
  const totalSteps = showReview ? steps.length + 1 : steps.length;
1583
1633
  const isReviewStep = showReview && currentStep === steps.length;
1584
1634
  const isLastStep = currentStep === totalSteps - 1;
@@ -1612,22 +1662,31 @@ function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange,
1612
1662
  }
1613
1663
  return errors;
1614
1664
  },
1615
- onSubmit: (values) => {
1665
+ onSubmit: async (values) => {
1616
1666
  if (!isLastStep) {
1617
1667
  const next = currentStep + 1;
1618
1668
  setCurrentStep(next);
1619
1669
  onStepChange === null || onStepChange === void 0 || onStepChange(next);
1620
1670
  } else {
1671
+ setSubmitted(false);
1672
+ await (onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(values));
1621
1673
  setSubmitted(true);
1622
- onSubmit === null || onSubmit === void 0 || onSubmit(values);
1623
- if (resetOnSuccess) setTimeout(() => {
1624
- setCurrentStep(0);
1625
- setSubmitted(false);
1626
- form.reset();
1627
- }, 3e3);
1628
1674
  }
1629
1675
  }
1630
1676
  });
1677
+ (0, react.useEffect)(() => {
1678
+ if (!submitted || !resetOnSuccess) return;
1679
+ const timer = setTimeout(() => {
1680
+ setCurrentStep(0);
1681
+ setSubmitted(false);
1682
+ form.reset();
1683
+ }, 3e3);
1684
+ return () => clearTimeout(timer);
1685
+ }, [
1686
+ submitted,
1687
+ resetOnSuccess,
1688
+ form
1689
+ ]);
1631
1690
  const handleBack = () => {
1632
1691
  if (currentStep > 0) {
1633
1692
  const prev = currentStep - 1;
@@ -1665,8 +1724,8 @@ function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange,
1665
1724
  ]
1666
1725
  }, field.name);
1667
1726
  }
1668
- if (field.type === "checkbox") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1669
- className: "gap-element flex flex-col",
1727
+ if (field.type === "checkbox") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1728
+ name: field.name,
1670
1729
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1671
1730
  className: "text-text-primary gap-element flex items-center text-sm",
1672
1731
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormCheckbox, { name: field.name }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: field.label })]
@@ -1674,13 +1733,10 @@ function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange,
1674
1733
  }, field.name);
1675
1734
  if (field.type === "textarea") {
1676
1735
  var _field$rows, _field$resize;
1677
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1678
- className: "gap-element flex flex-col",
1736
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1737
+ name: field.name,
1679
1738
  children: [
1680
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1681
- name: field.name,
1682
- children: field.label
1683
- }),
1739
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, { children: field.label }),
1684
1740
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormTextarea, {
1685
1741
  name: field.name,
1686
1742
  placeholder: field.placeholder,
@@ -1693,22 +1749,28 @@ function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange,
1693
1749
  }
1694
1750
  if (field.type === "select") {
1695
1751
  var _field$options2;
1696
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1697
- className: "gap-element flex flex-col",
1752
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1753
+ name: field.name,
1698
1754
  children: [
1699
1755
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1700
- name: field.name,
1756
+ htmlFor: `${formId}-${field.name}`,
1701
1757
  children: field.label
1702
1758
  }),
1703
1759
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSelect, {
1704
1760
  name: field.name,
1761
+ id: `${formId}-${field.name}`,
1762
+ "aria-label": field.label,
1763
+ "aria-describedby": form.getError(field.name) && form.getFieldTouched(field.name) ? `${formId}-${field.name}-error` : void 0,
1705
1764
  placeholder: field.placeholder,
1706
1765
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSelectPopover, { children: (_field$options2 = field.options) === null || _field$options2 === void 0 ? void 0 : _field$options2.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSelectItem, {
1707
1766
  value: option.value,
1708
1767
  children: option.label
1709
1768
  }, option.value)) })
1710
1769
  }),
1711
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, { name: field.name })
1770
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormError, {
1771
+ name: field.name,
1772
+ id: `${formId}-${field.name}-error`
1773
+ })
1712
1774
  ]
1713
1775
  }, field.name);
1714
1776
  }
@@ -1725,13 +1787,10 @@ function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange,
1725
1787
  })]
1726
1788
  })]
1727
1789
  }, field.name);
1728
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1729
- className: "gap-element flex flex-col",
1790
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.FormField, {
1791
+ name: field.name,
1730
1792
  children: [
1731
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, {
1732
- name: field.name,
1733
- children: field.label
1734
- }),
1793
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormLabel, { children: field.label }),
1735
1794
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormInput, {
1736
1795
  name: field.name,
1737
1796
  type: (_field$type = field.type) !== null && _field$type !== void 0 ? _field$type : "text",
@@ -1815,13 +1874,20 @@ function WizardForm({ fields, steps, showReview = true, onSubmit, onStepChange,
1815
1874
  children: [currentStep > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1816
1875
  type: "button",
1817
1876
  onClick: handleBack,
1877
+ disabled: form.isSubmitting(),
1818
1878
  className: "border-border text-text-primary hover:bg-bg-subtle rounded-lg border px-4 py-2 text-sm font-medium",
1819
1879
  children: (_labels$backButton = labels.backButton) !== null && _labels$backButton !== void 0 ? _labels$backButton : "이전"
1820
1880
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.FormSubmit, { children: isLastStep ? (_labels$submitButton = labels.submitButton) !== null && _labels$submitButton !== void 0 ? _labels$submitButton : "제출" : (_labels$nextButton = labels.nextButton) !== null && _labels$nextButton !== void 0 ? _labels$nextButton : "다음" })]
1821
1881
  })
1822
1882
  ]
1823
1883
  }),
1884
+ form.getSubmitError() !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1885
+ role: "alert",
1886
+ className: "border-danger bg-danger-subtle text-danger-fg rounded-lg border p-3 text-sm",
1887
+ children: (_labels$submitError = labels.submitError) !== null && _labels$submitError !== void 0 ? _labels$submitError : "처리에 실패했습니다. 다시 시도해주세요."
1888
+ }),
1824
1889
  submitted && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1890
+ role: "status",
1825
1891
  className: "border-success bg-success-subtle rounded-lg border p-4 text-center",
1826
1892
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
1827
1893
  className: "text-success-fg text-sm font-medium",
@@ -1874,7 +1940,7 @@ const COLOR_PRESETS = [
1874
1940
  "#f97316",
1875
1941
  "#14b8a6"
1876
1942
  ];
1877
- const defaultLabels$27 = {
1943
+ const defaultLabels$28 = {
1878
1944
  eventLabelPrefix: "Event",
1879
1945
  defaultAriaLabel: "Event icon"
1880
1946
  };
@@ -1905,7 +1971,7 @@ function getEventIconStyle(color) {
1905
1971
  /** Renders the event icon component. */
1906
1972
  function EventIcon({ icon, color, size = "md", className, labels: customLabels }) {
1907
1973
  var _iconEntry$label;
1908
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$27), customLabels);
1974
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$28), customLabels);
1909
1975
  const sizes = SIZE_MAP[size];
1910
1976
  const resolvedColor = (color === null || color === void 0 ? void 0 : color.trim()) ? color : void 0;
1911
1977
  const iconEntry = typeof icon === "string" ? require_text_truncate.getIconRegistryEntry(icon) : void 0;
@@ -1997,14 +2063,14 @@ function ConnectionIndicator({ status, tone, label, showLabel = true, pulse, cla
1997
2063
  ConnectionIndicator.displayName = "ConnectionIndicator";
1998
2064
  //#endregion
1999
2065
  //#region src/shells/floating-action-bar.tsx
2000
- const defaultLabels$26 = {
2066
+ const defaultLabels$27 = {
2001
2067
  toolbarAriaLabel: "Actions",
2002
2068
  selectedLabel: (count) => `${count} selected`,
2003
2069
  dismissAriaLabel: "Dismiss"
2004
2070
  };
2005
2071
  /** Renders the floating action bar component. */
2006
2072
  function FloatingActionBar({ actions, selectedCount, onAction, onDismiss, className, labels: customLabels }) {
2007
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$26), customLabels);
2073
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$27), customLabels);
2008
2074
  if (actions.length === 0) return null;
2009
2075
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2010
2076
  role: "toolbar",
@@ -2041,7 +2107,7 @@ function FloatingActionBar({ actions, selectedCount, onAction, onDismiss, classN
2041
2107
  FloatingActionBar.displayName = "FloatingActionBar";
2042
2108
  //#endregion
2043
2109
  //#region src/shells/template-picker.tsx
2044
- const defaultLabels$25 = {
2110
+ const defaultLabels$26 = {
2045
2111
  ariaLabel: "Templates",
2046
2112
  defaultCategory: "General",
2047
2113
  searchPlaceholder: "Search templates...",
@@ -2049,7 +2115,7 @@ const defaultLabels$25 = {
2049
2115
  };
2050
2116
  /** Renders the template picker component. */
2051
2117
  function TemplatePicker({ templates, selected, onSelect, labels: customLabels, showSearch = false, className }) {
2052
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$25), customLabels);
2118
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$26), customLabels);
2053
2119
  const [search, setSearch] = react.useState("");
2054
2120
  const filtered = react.useMemo(() => {
2055
2121
  if (!showSearch || !search) return templates;
@@ -2135,7 +2201,7 @@ function TemplatePicker({ templates, selected, onSelect, labels: customLabels, s
2135
2201
  TemplatePicker.displayName = "TemplatePicker";
2136
2202
  //#endregion
2137
2203
  //#region src/shells/code-snippet-viewer.tsx
2138
- const defaultLabels$24 = {
2204
+ const defaultLabels$25 = {
2139
2205
  copy: "Copy",
2140
2206
  copied: "Copied!",
2141
2207
  codeRegion: "Code snippet"
@@ -2173,7 +2239,7 @@ const syntaxThemeClasses = {
2173
2239
  /** Renders the code snippet viewer component. */
2174
2240
  function CodeSnippetViewer({ code, language = "text", title, showLineNumbers = true, showCopyButton = true, maxHeight = 400, syntaxTheme = "default", className, labels: customLabels }) {
2175
2241
  var _syntaxThemeClasses$s;
2176
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$24), customLabels);
2242
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$25), customLabels);
2177
2243
  const [copied, setCopied] = react.useState(false);
2178
2244
  const lines = code.split("\n");
2179
2245
  const theme = (_syntaxThemeClasses$s = syntaxThemeClasses[syntaxTheme]) !== null && _syntaxThemeClasses$s !== void 0 ? _syntaxThemeClasses$s : syntaxThemeClasses.default;
@@ -2225,7 +2291,7 @@ function CodeSnippetViewer({ code, language = "text", title, showLineNumbers = t
2225
2291
  CodeSnippetViewer.displayName = "CodeSnippetViewer";
2226
2292
  //#endregion
2227
2293
  //#region src/shells/property-explorer.tsx
2228
- const defaultLabels$23 = {
2294
+ const defaultLabels$24 = {
2229
2295
  searchPlaceholder: "Search properties...",
2230
2296
  noPropertiesFound: "No properties found",
2231
2297
  edit: (property) => `${property} 편집`,
@@ -2233,7 +2299,7 @@ const defaultLabels$23 = {
2233
2299
  };
2234
2300
  /** Renders the property explorer component. */
2235
2301
  function PropertyExplorer({ groups, onSelect, onEdit, className, labels: customLabels }) {
2236
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$23), customLabels);
2302
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$24), customLabels);
2237
2303
  const [search, setSearch] = react.useState("");
2238
2304
  const filtered = react.useMemo(() => {
2239
2305
  if (!search) return groups;
@@ -2519,7 +2585,7 @@ function skipBlockComment(text, from) {
2519
2585
  }
2520
2586
  //#endregion
2521
2587
  //#region src/shells/alert-builder.tsx
2522
- const defaultLabels$22 = {
2588
+ const defaultLabels$23 = {
2523
2589
  alertNameLabel: "Alert name",
2524
2590
  conditionsLabel: "Conditions",
2525
2591
  metricLabel: "Metric",
@@ -2590,7 +2656,7 @@ function AlertBuilder({ value, onChange, metrics = [
2590
2656
  ], labels: customLabels, className }) {
2591
2657
  const resolvedMetrics = eventOptions ? eventOptions.map((e) => e.id) : metrics;
2592
2658
  const metricLabelMap = eventOptions ? Object.fromEntries(eventOptions.map((e) => [e.id, e.name])) : null;
2593
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$22), customLabels);
2659
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$23), customLabels);
2594
2660
  const alertNameId = react.useId();
2595
2661
  const conditionsId = react.useId();
2596
2662
  const checkFrequencyId = react.useId();
@@ -2745,7 +2811,7 @@ function AlertBuilder({ value, onChange, metrics = [
2745
2811
  AlertBuilder.displayName = "AlertBuilder";
2746
2812
  //#endregion
2747
2813
  //#region src/shells/event-meta-editor.tsx
2748
- const defaultLabels$21 = {
2814
+ const defaultLabels$22 = {
2749
2815
  icon: "Icon",
2750
2816
  color: "Color",
2751
2817
  name: "Event name",
@@ -2763,7 +2829,7 @@ const defaultLabels$21 = {
2763
2829
  };
2764
2830
  /** Renders the event meta editor component. */
2765
2831
  function EventMetaEditor({ value, onChange, icons, sections, footer, className, labels: customLabels }) {
2766
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$21), customLabels);
2832
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$22), customLabels);
2767
2833
  const hasTags = value.tags.length > 0;
2768
2834
  const nameId = react.useId();
2769
2835
  const displayNameId = react.useId();
@@ -2886,10 +2952,10 @@ function EventMetaEditor({ value, onChange, icons, sections, footer, className,
2886
2952
  EventMetaEditor.displayName = "EventMetaEditor";
2887
2953
  //#endregion
2888
2954
  //#region src/shells/widget-grid.tsx
2889
- const defaultLabels$20 = { emptyMessage: "No widgets to display" };
2955
+ const defaultLabels$21 = { emptyMessage: "No widgets to display" };
2890
2956
  /** Renders the widget grid component. */
2891
2957
  function WidgetGrid({ widgets, cols = 12, rowHeight = 80, gap = 16, editable = false, onReorder, labels: customLabels, className }) {
2892
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$20), customLabels);
2958
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$21), customLabels);
2893
2959
  const [dragIdx, setDragIdx] = react.useState(null);
2894
2960
  const [overIdx, setOverIdx] = react.useState(null);
2895
2961
  if (widgets.length === 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -2934,7 +3000,7 @@ function WidgetGrid({ widgets, cols = 12, rowHeight = 80, gap = 16, editable = f
2934
3000
  WidgetGrid.displayName = "WidgetGrid";
2935
3001
  //#endregion
2936
3002
  //#region src/shells/report-builder.tsx
2937
- const defaultLabels$19 = {
3003
+ const defaultLabels$20 = {
2938
3004
  stepsLabel: "Report steps",
2939
3005
  stepType: "Chart Type",
2940
3006
  stepConfig: "Data Config",
@@ -3010,7 +3076,7 @@ const STEPS = [
3010
3076
  ];
3011
3077
  /** Renders the report builder component. */
3012
3078
  function ReportBuilder({ chartTypes = DEFAULT_CHART_TYPES, dataSources = [], onSave, onCancel, configForm, styleForm, preview, onChartTypeChange, onDataSourceChange, onStepChange, selectedChartType: controlledChartType, selectedDataSource: controlledDataSource, labels: customLabels, className }) {
3013
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$19), customLabels);
3079
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$20), customLabels);
3014
3080
  const [stepIndex, setStepIndex] = react.useState(0);
3015
3081
  const [internalChartType, setInternalChartType] = react.useState(null);
3016
3082
  const [internalDataSource, setInternalDataSource] = react.useState("");
@@ -3230,7 +3296,7 @@ function ReportBuilder({ chartTypes = DEFAULT_CHART_TYPES, dataSources = [], onS
3230
3296
  ReportBuilder.displayName = "ReportBuilder";
3231
3297
  //#endregion
3232
3298
  //#region src/shells/audit-timeline.tsx
3233
- const defaultLabels$18 = {
3299
+ const defaultLabels$19 = {
3234
3300
  title: "변경 이력",
3235
3301
  empty: "변경 이력이 없습니다",
3236
3302
  expand: "상세 보기",
@@ -3309,7 +3375,7 @@ function DiffTable({ changes, labels }) {
3309
3375
  }
3310
3376
  /** Renders the audit timeline component. */
3311
3377
  function AuditTimeline({ entries, labels: customLabels, className, onEntryClick }) {
3312
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$18), customLabels);
3378
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$19), customLabels);
3313
3379
  const [expandedIds, setExpandedIds] = react.useState(/* @__PURE__ */ new Set());
3314
3380
  const toggleExpanded = react.useCallback((id) => {
3315
3381
  setExpandedIds((prev) => {
@@ -3432,7 +3498,7 @@ function AuditTimeline({ entries, labels: customLabels, className, onEntryClick
3432
3498
  AuditTimeline.displayName = "AuditTimeline";
3433
3499
  //#endregion
3434
3500
  //#region src/shells/segment-builder.tsx
3435
- const defaultLabels$17 = {
3501
+ const defaultLabels$18 = {
3436
3502
  match: "Match",
3437
3503
  ofTheFollowing: "of the following",
3438
3504
  groupLabel: "Segment group",
@@ -3553,7 +3619,7 @@ function SegmentBuilder({ groups, onChange, eventOptions = [
3553
3619
  "New Users",
3554
3620
  "Power Users"
3555
3621
  ], className, labels: customLabels }) {
3556
- const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$17), customLabels);
3622
+ const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$18), customLabels);
3557
3623
  const builderId = react.useId().replace(/:/g, "");
3558
3624
  const nextIdRef = react.useRef(1);
3559
3625
  const createId = react.useCallback(() => {
@@ -3765,6 +3831,703 @@ function SegmentBuilder({ groups, onChange, eventOptions = [
3765
3831
  }
3766
3832
  SegmentBuilder.displayName = "SegmentBuilder";
3767
3833
  //#endregion
3834
+ //#region src/shells/criteria-builder.tsx
3835
+ const defaultLabels$17 = {
3836
+ builder: "조건 빌더",
3837
+ rootLogicLegend: "그룹 결합 방식",
3838
+ matchAllGroups: "모든 그룹 일치",
3839
+ matchAnyGroup: "하나 이상 일치",
3840
+ groupLogicLegend: (letter) => `그룹 ${letter} 조건 결합 방식`,
3841
+ matchAllCriteria: "모두 충족",
3842
+ matchAnyCriteria: "하나 이상 충족",
3843
+ and: "그리고",
3844
+ or: "또는",
3845
+ groupLabel: (letter) => `그룹 ${letter}`,
3846
+ criterionLabel: (letter, index) => `조건 ${letter}.${index}`,
3847
+ actionLabel: (action, target) => `${action}: ${target}`,
3848
+ addCriterion: "조건 추가",
3849
+ addGroup: "그룹 추가",
3850
+ kindMenuTitle: "조건 유형",
3851
+ duplicateCriterion: "조건 복제",
3852
+ removeCriterion: "조건 제거",
3853
+ moveUp: "위로 이동",
3854
+ moveDown: "아래로 이동",
3855
+ negate: "제외",
3856
+ duplicateGroup: "그룹 복제",
3857
+ removeGroup: "그룹 제거",
3858
+ emptyGroup: "이 그룹에는 아직 조건이 없습니다.",
3859
+ unknownKind: (kind) => `알 수 없는 조건 유형 "${kind}"`,
3860
+ unknownKindDescription: "이 조건은 표시할 수 없습니다. 유형을 바꾸거나 제거하세요.",
3861
+ replaceKind: "유형 바꾸기",
3862
+ emptyTitle: "조건이 없습니다",
3863
+ emptyDescription: "첫 그룹을 추가해 누가 포함되는지 정의하세요.",
3864
+ emptyAction: "첫 조건 추가",
3865
+ keyboardHint: "조건 추가 · 그룹 추가",
3866
+ maxGroupsReached: (max) => `그룹은 최대 ${max}개까지 추가할 수 있습니다.`,
3867
+ maxCriteriaReached: (max) => `한 그룹에는 조건을 최대 ${max}개까지 추가할 수 있습니다.`
3868
+ };
3869
+ /** `A`, `B`, … `Z`, `AA`, `AB` — the badge a group wears. */
3870
+ function criteriaGroupLetter(index) {
3871
+ let n = Math.max(0, Math.floor(index));
3872
+ let out = "";
3873
+ do {
3874
+ out = String.fromCharCode(65 + n % 26) + out;
3875
+ n = Math.floor(n / 26) - 1;
3876
+ } while (n >= 0);
3877
+ return out;
3878
+ }
3879
+ function collectIds(value) {
3880
+ const ids = /* @__PURE__ */ new Set();
3881
+ for (const group of value.groups) {
3882
+ ids.add(group.id);
3883
+ for (const criterion of group.criteria) ids.add(criterion.id);
3884
+ }
3885
+ return ids;
3886
+ }
3887
+ function uniqueId(base, taken) {
3888
+ if (!taken.has(base)) return base;
3889
+ let n = 2;
3890
+ while (taken.has(`${base}-${n}`)) n += 1;
3891
+ return `${base}-${n}`;
3892
+ }
3893
+ function replaceGroup(value, groupIndex, next) {
3894
+ return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: value.groups.map((group, i) => i === groupIndex ? next : group) });
3895
+ }
3896
+ /**
3897
+ * Moves one criterion a step up or down inside its group. Returns the same
3898
+ * value when the move is impossible, so a caller can `===` to know nothing
3899
+ * changed.
3900
+ */
3901
+ function criteriaBuilderMove(value, groupIndex, index, direction) {
3902
+ const group = value.groups[groupIndex];
3903
+ if (!group) return value;
3904
+ const target = direction === "up" ? index - 1 : index + 1;
3905
+ if (index < 0 || target < 0 || target >= group.criteria.length) return value;
3906
+ const criteria = [...group.criteria];
3907
+ const [moved] = criteria.splice(index, 1);
3908
+ criteria.splice(target, 0, moved);
3909
+ return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria }));
3910
+ }
3911
+ /**
3912
+ * Inserts a copy of one criterion *before* the original, so the copy takes the
3913
+ * original's place in the reading order and the original follows as the thing
3914
+ * to edit.
3915
+ */
3916
+ function criteriaBuilderDuplicate(value, groupIndex, index, clone) {
3917
+ const group = value.groups[groupIndex];
3918
+ const original = group === null || group === void 0 ? void 0 : group.criteria[index];
3919
+ if (!group || !original) return value;
3920
+ const criteria = [...group.criteria];
3921
+ criteria.splice(index, 0, clone(original));
3922
+ return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria }));
3923
+ }
3924
+ /** Removes one criterion. The group stays, even when it empties. */
3925
+ function criteriaBuilderRemove(value, groupIndex, index) {
3926
+ const group = value.groups[groupIndex];
3927
+ if (!group || index < 0 || index >= group.criteria.length) return value;
3928
+ return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria: group.criteria.filter((_, i) => i !== index) }));
3929
+ }
3930
+ /** Appends a criterion to a group, or inserts it at `at`. */
3931
+ function criteriaBuilderInsert(value, groupIndex, criterion, at) {
3932
+ const group = value.groups[groupIndex];
3933
+ if (!group) return value;
3934
+ const criteria = [...group.criteria];
3935
+ const position = at === void 0 ? criteria.length : Math.max(0, Math.min(at, criteria.length));
3936
+ criteria.splice(position, 0, criterion);
3937
+ return replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria }));
3938
+ }
3939
+ /** Removes one group. */
3940
+ function criteriaBuilderRemoveGroup(value, groupIndex) {
3941
+ if (groupIndex < 0 || groupIndex >= value.groups.length) return value;
3942
+ return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: value.groups.filter((_, i) => i !== groupIndex) });
3943
+ }
3944
+ /** Inserts a copy of one group — every criterion cloned — before the original. */
3945
+ function criteriaBuilderDuplicateGroup(value, groupIndex, groupId, clone) {
3946
+ const group = value.groups[groupIndex];
3947
+ if (!group) return value;
3948
+ const copy = {
3949
+ id: groupId,
3950
+ logic: group.logic,
3951
+ criteria: group.criteria.map(clone)
3952
+ };
3953
+ const groups = [...value.groups];
3954
+ groups.splice(groupIndex, 0, copy);
3955
+ return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups });
3956
+ }
3957
+ const EDITABLE_TARGET = "input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"], [role=\"combobox\"], [role=\"textbox\"], [role=\"menu\"], [role=\"menuitem\"], [role=\"listbox\"], [role=\"option\"]";
3958
+ function isEditableTarget(target) {
3959
+ return target instanceof Element && target.closest(EDITABLE_TARGET) !== null;
3960
+ }
3961
+ function sectionKinds(kinds) {
3962
+ const sections = [];
3963
+ const byHeading = /* @__PURE__ */ new Map();
3964
+ for (const option of kinds) {
3965
+ let section = byHeading.get(option.group);
3966
+ if (!section) {
3967
+ section = {
3968
+ heading: option.group,
3969
+ entries: []
3970
+ };
3971
+ byHeading.set(option.group, section);
3972
+ sections.push(section);
3973
+ }
3974
+ section.entries.push({
3975
+ key: option.kind,
3976
+ kind: option.kind,
3977
+ negate: false,
3978
+ option
3979
+ });
3980
+ if (option.negatedLabel) section.entries.push({
3981
+ key: `${option.kind}:not`,
3982
+ kind: option.kind,
3983
+ negate: true,
3984
+ option
3985
+ });
3986
+ }
3987
+ return [...sections.filter((s) => s.heading === void 0), ...sections.filter((s) => s.heading !== void 0)];
3988
+ }
3989
+ function KindMenu({ kinds, menuLabel, triggerLabel, triggerAriaLabel, triggerIcon, disabled = false, disabledReason, variant = "ghost", onPick, addTarget }) {
3990
+ const sections = react.useMemo(() => sectionKinds(kinds), [kinds]);
3991
+ const trigger = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownTrigger, {
3992
+ disabled,
3993
+ "aria-label": triggerAriaLabel,
3994
+ title: disabled ? disabledReason : void 0,
3995
+ "data-criteria-add": addTarget,
3996
+ 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),
3997
+ children: [triggerIcon, triggerLabel]
3998
+ });
3999
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownMenu, {
4000
+ animated: false,
4001
+ children: [trigger, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownContent, {
4002
+ "aria-label": menuLabel,
4003
+ "aria-labelledby": void 0,
4004
+ className: "min-w-56",
4005
+ children: sections.map((section, si) => {
4006
+ var _section$heading;
4007
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [
4008
+ si > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.DropdownSeparator, {}),
4009
+ section.heading !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4010
+ role: "presentation",
4011
+ className: "text-text-tertiary px-2 pt-1.5 pb-1 text-[11px] font-semibold tracking-wide uppercase",
4012
+ children: section.heading
4013
+ }),
4014
+ section.entries.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.DropdownItem, {
4015
+ onClick: () => onPick(entry.kind, entry.negate),
4016
+ className: "flex items-start gap-2",
4017
+ children: [entry.option.icon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4018
+ className: "text-text-tertiary mt-0.5 shrink-0 [&_svg]:size-3.5",
4019
+ children: entry.option.icon
4020
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4021
+ className: "flex min-w-0 flex-col",
4022
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4023
+ className: require_text_truncate.cn("text-sm", entry.negate && "text-danger-fg"),
4024
+ children: entry.negate ? entry.option.negatedLabel : entry.option.label
4025
+ }), !entry.negate && entry.option.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4026
+ className: "text-text-tertiary text-xs",
4027
+ children: entry.option.description
4028
+ })]
4029
+ })]
4030
+ }, entry.key))
4031
+ ] }, (_section$heading = section.heading) !== null && _section$heading !== void 0 ? _section$heading : "__none");
4032
+ })
4033
+ })]
4034
+ });
4035
+ }
4036
+ function IconAction({ icon, label, onClick, disabled = false, danger = false }) {
4037
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4038
+ type: "button",
4039
+ onClick,
4040
+ disabled,
4041
+ "aria-label": label,
4042
+ title: label,
4043
+ 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),
4044
+ children: icon
4045
+ });
4046
+ }
4047
+ function LogicDivider({ label, emphasis }) {
4048
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4049
+ role: "separator",
4050
+ "aria-label": label,
4051
+ className: require_text_truncate.cn("flex items-center", emphasis === "root" ? "gap-group" : "gap-element"),
4052
+ children: [
4053
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: require_text_truncate.cn("h-px flex-1", emphasis === "root" ? "bg-border" : "bg-border-subtle") }),
4054
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4055
+ 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"),
4056
+ children: label
4057
+ }),
4058
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: require_text_truncate.cn("h-px flex-1", emphasis === "root" ? "bg-border" : "bg-border-subtle") })
4059
+ ]
4060
+ });
4061
+ }
4062
+ function Lettermark({ letter }) {
4063
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4064
+ "aria-hidden": "true",
4065
+ className: "bg-accent-subtle text-accent inline-flex size-6 shrink-0 items-center justify-center rounded-md text-xs font-semibold tabular-nums",
4066
+ children: letter
4067
+ });
4068
+ }
4069
+ /**
4070
+ * CriteriaBuilder — a two-level tree of criteria, edited as sentences.
4071
+ *
4072
+ * The builder owns what every criteria editor needs and nothing a particular
4073
+ * product does: groups and their AND/OR, the order of criteria, negation,
4074
+ * inline errors, the "add" menu, and the keyboard. The consumer owns the
4075
+ * criterion type and renders each one — usually as `Expression` chips whose
4076
+ * values open an editor — so the same shell serves a cohort of users, an
4077
+ * alert condition, or a feature-flag rollout without knowing which.
4078
+ *
4079
+ * Kinds the builder does not know render as an invalid row with a warning and
4080
+ * a replace/remove pair, never as some other kind's fields: a criterion saved
4081
+ * by a newer client should look broken, not silently different.
4082
+ *
4083
+ * @example
4084
+ * ```tsx
4085
+ * <CriteriaBuilder
4086
+ * value={value}
4087
+ * onChange={setValue}
4088
+ * kinds={[
4089
+ * { kind: "performed", label: "이벤트를 수행함", negatedLabel: "이벤트를 수행하지 않음" },
4090
+ * { kind: "property", label: "속성이 일치함" },
4091
+ * ]}
4092
+ * createCriterion={(kind, negate) => ({ id: nextId(), kind, negate, event: "" })}
4093
+ * renderCriterion={(c, api) => (
4094
+ * <ExpressionGroup>
4095
+ * <Expression description="이벤트" value={c.event} onClick={() => open(c.id)} />
4096
+ * </ExpressionGroup>
4097
+ * )}
4098
+ * />
4099
+ * ```
4100
+ */
4101
+ 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 }) {
4102
+ const labels = react.useMemo(() => require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$17), customLabels), [customLabels]);
4103
+ const baseId = react.useId().replace(/:/g, "");
4104
+ const nextGroupRef = react.useRef(1);
4105
+ const rootRef = react.useRef(null);
4106
+ const [pendingOpen, setPendingOpen] = react.useState(null);
4107
+ const knownKinds = react.useMemo(() => new Set(kinds.map((k) => k.kind)), [kinds]);
4108
+ const groupsFull = value.groups.length >= maxGroups;
4109
+ const newGroupId = react.useCallback(() => {
4110
+ const taken = collectIds(value);
4111
+ if (createGroupId) return uniqueId(createGroupId(), taken);
4112
+ let id = "";
4113
+ do
4114
+ id = `group-${nextGroupRef.current++}`;
4115
+ while (taken.has(id));
4116
+ return id;
4117
+ }, [createGroupId, value]);
4118
+ const clone = react.useCallback((criterion, taken) => {
4119
+ if (cloneCriterion) return cloneCriterion(criterion);
4120
+ const id = uniqueId(`${criterion.id}-copy`, taken);
4121
+ taken.add(id);
4122
+ return require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, criterion), {}, { id });
4123
+ }, [cloneCriterion]);
4124
+ const addGroup = react.useCallback(() => {
4125
+ if (disabled || groupsFull) return null;
4126
+ const id = newGroupId();
4127
+ onChange(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: [...value.groups, {
4128
+ id,
4129
+ logic: "and",
4130
+ criteria: []
4131
+ }] }));
4132
+ return id;
4133
+ }, [
4134
+ disabled,
4135
+ groupsFull,
4136
+ newGroupId,
4137
+ onChange,
4138
+ value
4139
+ ]);
4140
+ const addCriterion = react.useCallback((groupIndex, kind, negate) => {
4141
+ const group = value.groups[groupIndex];
4142
+ if (!group || group.criteria.length >= maxCriteriaPerGroup) return;
4143
+ onChange(criteriaBuilderInsert(value, groupIndex, createCriterion(kind, negate)));
4144
+ }, [
4145
+ createCriterion,
4146
+ maxCriteriaPerGroup,
4147
+ onChange,
4148
+ value
4149
+ ]);
4150
+ const addFirst = react.useCallback((kind, negate) => {
4151
+ if (disabled) return;
4152
+ onChange(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { groups: [{
4153
+ id: newGroupId(),
4154
+ logic: "and",
4155
+ criteria: [createCriterion(kind, negate)]
4156
+ }] }));
4157
+ }, [
4158
+ createCriterion,
4159
+ disabled,
4160
+ newGroupId,
4161
+ onChange,
4162
+ value
4163
+ ]);
4164
+ const replaceCriterion = react.useCallback((groupIndex, index, kind, negate) => {
4165
+ const group = value.groups[groupIndex];
4166
+ const current = group === null || group === void 0 ? void 0 : group.criteria[index];
4167
+ if (!group || !current) return;
4168
+ const replacement = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, createCriterion(kind, negate)), {}, { id: current.id });
4169
+ onChange(replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { criteria: group.criteria.map((c, i) => i === index ? replacement : c) })));
4170
+ }, [
4171
+ createCriterion,
4172
+ onChange,
4173
+ value
4174
+ ]);
4175
+ const updateCriterion = react.useCallback((groupIndex, index, patch) => {
4176
+ const group = value.groups[groupIndex];
4177
+ if (!group) return;
4178
+ 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) })));
4179
+ }, [onChange, value]);
4180
+ const findAddTrigger = react.useCallback((groupId) => {
4181
+ var _rootRef$current$quer, _rootRef$current;
4182
+ 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;
4183
+ }, []);
4184
+ react.useEffect(() => {
4185
+ if (!pendingOpen) return;
4186
+ const trigger = findAddTrigger(pendingOpen);
4187
+ if (!trigger) return;
4188
+ setPendingOpen(null);
4189
+ trigger.focus();
4190
+ trigger.click();
4191
+ }, [
4192
+ findAddTrigger,
4193
+ pendingOpen,
4194
+ value
4195
+ ]);
4196
+ const handleKeyDown = react.useCallback((event) => {
4197
+ if (disabled || event.defaultPrevented) return;
4198
+ if (event.altKey || event.ctrlKey || event.metaKey) return;
4199
+ if (isEditableTarget(event.target)) return;
4200
+ const key = event.key.toLowerCase();
4201
+ if (key === "g") {
4202
+ const id = addGroup();
4203
+ if (id) {
4204
+ event.preventDefault();
4205
+ setPendingOpen(id);
4206
+ }
4207
+ return;
4208
+ }
4209
+ if (key === "a") {
4210
+ const host = event.target instanceof Element ? event.target.closest("[data-criteria-group]") : null;
4211
+ const groupId = host === null || host === void 0 ? void 0 : host.dataset.criteriaGroup;
4212
+ const trigger = groupId ? findAddTrigger(groupId) : null;
4213
+ if (trigger && !trigger.disabled) {
4214
+ event.preventDefault();
4215
+ trigger.focus();
4216
+ trigger.click();
4217
+ }
4218
+ }
4219
+ }, [
4220
+ addGroup,
4221
+ disabled,
4222
+ findAddTrigger
4223
+ ]);
4224
+ const rootLogicOptions = react.useMemo(() => [{
4225
+ value: "and",
4226
+ label: labels.matchAllGroups
4227
+ }, {
4228
+ value: "or",
4229
+ label: labels.matchAnyGroup
4230
+ }], [labels]);
4231
+ const groupLogicOptions = react.useMemo(() => [{
4232
+ value: "and",
4233
+ label: labels.matchAllCriteria
4234
+ }, {
4235
+ value: "or",
4236
+ label: labels.matchAnyCriteria
4237
+ }], [labels]);
4238
+ const isEmpty = value.groups.length === 0;
4239
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4240
+ ref: rootRef,
4241
+ role: "group",
4242
+ "aria-label": ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : labels.builder,
4243
+ className: require_text_truncate.cn("gap-section flex flex-col lg:flex-row", className),
4244
+ onKeyDown: handleKeyDown,
4245
+ "data-opt-id": "6F4JG",
4246
+ "data-opt-slug": "criteria-builder.CriteriaBuilder",
4247
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4248
+ className: "gap-group flex min-w-0 flex-1 flex-col",
4249
+ children: isEmpty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.EmptyState, {
4250
+ title: labels.emptyTitle,
4251
+ description: labels.emptyDescription,
4252
+ hasBorder: true,
4253
+ tone: "subdued",
4254
+ actions: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindMenu, {
4255
+ kinds,
4256
+ menuLabel: labels.kindMenuTitle,
4257
+ triggerLabel: labels.emptyAction,
4258
+ triggerAriaLabel: labels.emptyAction,
4259
+ triggerIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { "aria-hidden": "true" }),
4260
+ variant: "secondary",
4261
+ disabled,
4262
+ onPick: addFirst
4263
+ }),
4264
+ footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4265
+ className: "gap-element inline-flex items-center",
4266
+ children: [
4267
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
4268
+ hint: true,
4269
+ children: "A"
4270
+ }),
4271
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
4272
+ hint: true,
4273
+ children: "G"
4274
+ }),
4275
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels.keyboardHint })
4276
+ ]
4277
+ })
4278
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
4279
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
4280
+ className: "gap-group m-0 flex min-w-0 flex-wrap items-center border-0 p-0",
4281
+ children: [
4282
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
4283
+ className: "sr-only",
4284
+ children: labels.rootLogicLegend
4285
+ }),
4286
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_replay_player_layout.SegmentedControl, {
4287
+ "aria-label": labels.rootLogicLegend,
4288
+ size: "sm",
4289
+ options: rootLogicOptions,
4290
+ value: value.logic,
4291
+ onChange: (logic) => onChange(require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, value), {}, { logic })),
4292
+ disabled
4293
+ }),
4294
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4295
+ className: "text-text-tertiary gap-element hidden items-center text-xs sm:inline-flex",
4296
+ children: [
4297
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
4298
+ hint: true,
4299
+ children: "A"
4300
+ }),
4301
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Kbd, {
4302
+ hint: true,
4303
+ children: "G"
4304
+ }),
4305
+ labels.keyboardHint
4306
+ ]
4307
+ })
4308
+ ]
4309
+ }),
4310
+ value.groups.map((group, groupIndex) => {
4311
+ const letter = criteriaGroupLetter(groupIndex);
4312
+ const groupName = labels.groupLabel(letter);
4313
+ const groupLabelId = `${baseId}-${group.id}-label`;
4314
+ const groupError = errors === null || errors === void 0 ? void 0 : errors[group.id];
4315
+ const groupErrorId = `${baseId}-${group.id}-error`;
4316
+ const criteriaFull = group.criteria.length >= maxCriteriaPerGroup;
4317
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [groupIndex > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LogicDivider, {
4318
+ emphasis: "root",
4319
+ label: value.logic === "and" ? labels.and : labels.or
4320
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4321
+ role: "group",
4322
+ "aria-labelledby": groupLabelId,
4323
+ "aria-describedby": groupError ? groupErrorId : void 0,
4324
+ "data-criteria-group": group.id,
4325
+ "data-invalid": groupError ? true : void 0,
4326
+ className: require_text_truncate.cn("bg-bg-subtle gap-element flex flex-col rounded-lg border p-3", groupError ? "border-danger/40" : "border-border"),
4327
+ children: [
4328
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4329
+ id: groupLabelId,
4330
+ className: "sr-only",
4331
+ children: groupName
4332
+ }),
4333
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4334
+ className: "gap-element flex flex-wrap items-center justify-between",
4335
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4336
+ className: "gap-element flex items-center",
4337
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Lettermark, { letter }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
4338
+ className: "m-0 border-0 p-0",
4339
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
4340
+ className: "sr-only",
4341
+ children: labels.groupLogicLegend(letter)
4342
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_replay_player_layout.SegmentedControl, {
4343
+ "aria-label": labels.groupLogicLegend(letter),
4344
+ size: "sm",
4345
+ options: groupLogicOptions,
4346
+ value: group.logic,
4347
+ onChange: (logic) => onChange(replaceGroup(value, groupIndex, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, group), {}, { logic }))),
4348
+ disabled
4349
+ })]
4350
+ })]
4351
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4352
+ className: "flex items-center gap-0.5",
4353
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
4354
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Copy, { "aria-hidden": "true" }),
4355
+ label: labels.actionLabel(labels.duplicateGroup, groupName),
4356
+ disabled: disabled || groupsFull,
4357
+ onClick: () => {
4358
+ const taken = collectIds(value);
4359
+ const id = newGroupId();
4360
+ taken.add(id);
4361
+ onChange(criteriaBuilderDuplicateGroup(value, groupIndex, id, (c) => clone(c, taken)));
4362
+ }
4363
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
4364
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, { "aria-hidden": "true" }),
4365
+ label: labels.actionLabel(labels.removeGroup, groupName),
4366
+ disabled,
4367
+ danger: true,
4368
+ onClick: () => onChange(criteriaBuilderRemoveGroup(value, groupIndex))
4369
+ })]
4370
+ })]
4371
+ }),
4372
+ group.criteria.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4373
+ className: "text-text-tertiary text-xs",
4374
+ children: labels.emptyGroup
4375
+ }),
4376
+ group.criteria.map((criterion, index) => {
4377
+ const criterionName = labels.criterionLabel(letter, index + 1);
4378
+ const rowLabelId = `${baseId}-${criterion.id}-label`;
4379
+ const error = errors === null || errors === void 0 ? void 0 : errors[criterion.id];
4380
+ const errorId = `${baseId}-${criterion.id}-error`;
4381
+ const known = knownKinds.has(criterion.kind);
4382
+ const negated = criterion.negate === true;
4383
+ const api = {
4384
+ update: (patch) => updateCriterion(groupIndex, index, patch),
4385
+ invalid: Boolean(error) || !known,
4386
+ error,
4387
+ disabled,
4388
+ groupIndex,
4389
+ index
4390
+ };
4391
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [index > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LogicDivider, {
4392
+ emphasis: "group",
4393
+ label: group.logic === "and" ? labels.and : labels.or
4394
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4395
+ role: "group",
4396
+ "aria-labelledby": rowLabelId,
4397
+ "aria-describedby": error ? errorId : void 0,
4398
+ "data-criterion-kind": criterion.kind,
4399
+ "data-negated": negated || void 0,
4400
+ "data-invalid": error || !known ? true : void 0,
4401
+ 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"),
4402
+ children: [
4403
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4404
+ id: rowLabelId,
4405
+ className: "sr-only",
4406
+ children: criterionName
4407
+ }),
4408
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4409
+ className: "gap-element flex flex-wrap items-start",
4410
+ children: [
4411
+ allowNegation && known && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4412
+ type: "button",
4413
+ "aria-pressed": negated,
4414
+ "aria-label": labels.actionLabel(labels.negate, criterionName),
4415
+ disabled,
4416
+ onClick: () => updateCriterion(groupIndex, index, { negate: !negated }),
4417
+ 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"),
4418
+ children: labels.negate
4419
+ }),
4420
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4421
+ className: "min-w-0 flex-1",
4422
+ children: known ? renderCriterion(criterion, api) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_replay_player_layout.Callout, {
4423
+ tone: "warning",
4424
+ size: "sm",
4425
+ title: labels.unknownKind(criterion.kind),
4426
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.TriangleAlert, { "aria-hidden": "true" }),
4427
+ action: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindMenu, {
4428
+ kinds,
4429
+ menuLabel: labels.kindMenuTitle,
4430
+ triggerLabel: labels.replaceKind,
4431
+ triggerAriaLabel: labels.actionLabel(labels.replaceKind, criterionName),
4432
+ variant: "secondary",
4433
+ disabled,
4434
+ onPick: (kind, negate) => replaceCriterion(groupIndex, index, kind, negate)
4435
+ }),
4436
+ children: labels.unknownKindDescription
4437
+ })
4438
+ }),
4439
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4440
+ className: "flex items-center gap-0.5",
4441
+ children: [
4442
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
4443
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowUp, { "aria-hidden": "true" }),
4444
+ label: labels.actionLabel(labels.moveUp, criterionName),
4445
+ disabled: disabled || index === 0,
4446
+ onClick: () => onChange(criteriaBuilderMove(value, groupIndex, index, "up"))
4447
+ }),
4448
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
4449
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ArrowDown, { "aria-hidden": "true" }),
4450
+ label: labels.actionLabel(labels.moveDown, criterionName),
4451
+ disabled: disabled || index === group.criteria.length - 1,
4452
+ onClick: () => onChange(criteriaBuilderMove(value, groupIndex, index, "down"))
4453
+ }),
4454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
4455
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Copy, { "aria-hidden": "true" }),
4456
+ label: labels.actionLabel(labels.duplicateCriterion, criterionName),
4457
+ disabled: disabled || criteriaFull,
4458
+ onClick: () => onChange(criteriaBuilderDuplicate(value, groupIndex, index, (c) => clone(c, collectIds(value))))
4459
+ }),
4460
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconAction, {
4461
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Trash2, { "aria-hidden": "true" }),
4462
+ label: labels.actionLabel(labels.removeCriterion, criterionName),
4463
+ disabled,
4464
+ danger: true,
4465
+ onClick: () => onChange(criteriaBuilderRemove(value, groupIndex, index))
4466
+ })
4467
+ ]
4468
+ })
4469
+ ]
4470
+ }),
4471
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4472
+ id: errorId,
4473
+ className: "text-danger-fg text-xs",
4474
+ children: error
4475
+ })
4476
+ ]
4477
+ })] }, criterion.id);
4478
+ }),
4479
+ groupError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4480
+ id: groupErrorId,
4481
+ className: "text-danger-fg text-xs",
4482
+ children: groupError
4483
+ }),
4484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4485
+ className: "gap-element flex flex-wrap items-center",
4486
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(KindMenu, {
4487
+ kinds,
4488
+ menuLabel: labels.kindMenuTitle,
4489
+ triggerLabel: labels.addCriterion,
4490
+ triggerAriaLabel: labels.actionLabel(labels.addCriterion, groupName),
4491
+ triggerIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { "aria-hidden": "true" }),
4492
+ disabled: disabled || criteriaFull,
4493
+ disabledReason: labels.maxCriteriaReached(maxCriteriaPerGroup),
4494
+ onPick: (kind, negate) => addCriterion(groupIndex, kind, negate),
4495
+ addTarget: group.id
4496
+ }), criteriaFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4497
+ className: "text-text-tertiary text-xs",
4498
+ children: labels.maxCriteriaReached(maxCriteriaPerGroup)
4499
+ })]
4500
+ })
4501
+ ]
4502
+ })] }, group.id);
4503
+ }),
4504
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4505
+ className: "gap-element flex flex-wrap items-center",
4506
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Button, {
4507
+ variant: "secondary",
4508
+ size: "sm",
4509
+ leftIcon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Plus, { "aria-hidden": "true" }),
4510
+ disabled: disabled || groupsFull,
4511
+ title: groupsFull ? labels.maxGroupsReached(maxGroups) : void 0,
4512
+ onClick: () => {
4513
+ const id = addGroup();
4514
+ if (id) setPendingOpen(id);
4515
+ },
4516
+ children: labels.addGroup
4517
+ }), groupsFull && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4518
+ className: "text-text-tertiary text-xs",
4519
+ children: labels.maxGroupsReached(maxGroups)
4520
+ })]
4521
+ })
4522
+ ] })
4523
+ }), aside !== void 0 && aside !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
4524
+ className: "min-w-0 lg:w-72 lg:shrink-0",
4525
+ children: aside
4526
+ })]
4527
+ });
4528
+ }
4529
+ CriteriaBuilder.displayName = "CriteriaBuilder";
4530
+ //#endregion
3768
4531
  //#region src/shells/insights-panel.tsx
3769
4532
  const defaultLabels$16 = {
3770
4533
  title: "Insights",
@@ -4375,7 +5138,7 @@ const flyoutSize = {
4375
5138
  * ```
4376
5139
  */
4377
5140
  function InspectorLayout({ children, inspector, open, onClose, title, description, actions, footer, breakpoint = "xl", width = "md", labels, className }) {
4378
- const canPush = require_field_sidebar.useMediaQuery(breakpointQuery[breakpoint], true);
5141
+ const canPush = require_replay_player_layout.useMediaQuery(breakpointQuery[breakpoint], true);
4379
5142
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4380
5143
  className: require_text_truncate.cn("flex min-w-0 items-stretch gap-group", className),
4381
5144
  "data-opt-id": "MN44T",
@@ -4386,7 +5149,7 @@ function InspectorLayout({ children, inspector, open, onClose, title, descriptio
4386
5149
  children
4387
5150
  }), canPush ? open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("aside", {
4388
5151
  className: require_text_truncate.cn("shrink-0", pushWidth[width]),
4389
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_field_sidebar.Flyout, {
5152
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_replay_player_layout.Flyout, {
4390
5153
  open,
4391
5154
  onClose,
4392
5155
  type: "inline",
@@ -4398,7 +5161,7 @@ function InspectorLayout({ children, inspector, open, onClose, title, descriptio
4398
5161
  className: "h-full",
4399
5162
  children: inspector
4400
5163
  })
4401
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_field_sidebar.Flyout, {
5164
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_replay_player_layout.Flyout, {
4402
5165
  open,
4403
5166
  onClose,
4404
5167
  type: "overlay",
@@ -4424,11 +5187,11 @@ const defaultLabels$14 = {
4424
5187
  };
4425
5188
  function toggleValue(query, field, value, active, multiSelect) {
4426
5189
  if (active) {
4427
- const remaining = require_field_sidebar.fieldValues(query, field).filter((it) => it !== value);
4428
- const cleared = require_field_sidebar.withoutField(query, field);
4429
- return remaining.reduce((next, keep) => require_field_sidebar.withFieldValue(next, field, keep), cleared);
5190
+ const remaining = require_replay_player_layout.fieldValues(query, field).filter((it) => it !== value);
5191
+ const cleared = require_replay_player_layout.withoutField(query, field);
5192
+ return remaining.reduce((next, keep) => require_replay_player_layout.withFieldValue(next, field, keep), cleared);
4430
5193
  }
4431
- return multiSelect ? require_field_sidebar.withFieldValue(query, field, value) : require_field_sidebar.withFieldValue(require_field_sidebar.withoutField(query, field), field, value);
5194
+ return multiSelect ? require_replay_player_layout.withFieldValue(query, field, value) : require_replay_player_layout.withFieldValue(require_replay_player_layout.withoutField(query, field), field, value);
4432
5195
  }
4433
5196
  /**
4434
5197
  * QueryFilterBar — filter buttons and a query string that are the same thing.
@@ -4460,7 +5223,7 @@ function toggleValue(query, field, value, active, multiSelect) {
4460
5223
  function QueryFilterBar({ value, onChange, filters, fields, actions, showClauses = true, live = false, disabled = false, labels: customLabels, queryBarLabels, className }) {
4461
5224
  const labels = require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, defaultLabels$14), customLabels);
4462
5225
  const activeCount = (0, react.useMemo)(() => filters.reduce((count, filter) => {
4463
- const values = require_field_sidebar.fieldValues(value, filter.field);
5226
+ const values = require_replay_player_layout.fieldValues(value, filter.field);
4464
5227
  if (filter.kind === "field_value_selection") return count + values.length;
4465
5228
  return count + (filter.value && values.includes(filter.value) ? 1 : 0);
4466
5229
  }, 0), [filters, value]);
@@ -4468,7 +5231,7 @@ function QueryFilterBar({ value, onChange, filters, fields, actions, showClauses
4468
5231
  className: require_text_truncate.cn("flex flex-col gap-element", className),
4469
5232
  "data-opt-id": "SK31N",
4470
5233
  "data-opt-slug": "query-filter-bar.QueryFilterBar",
4471
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_field_sidebar.QueryBar, {
5234
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_replay_player_layout.QueryBar, {
4472
5235
  value,
4473
5236
  onChange,
4474
5237
  fields,
@@ -4486,7 +5249,7 @@ function QueryFilterBar({ value, onChange, filters, fields, actions, showClauses
4486
5249
  children: [
4487
5250
  filters.map((filter) => {
4488
5251
  var _filter$multiSelect, _filter$value;
4489
- const values = require_field_sidebar.fieldValues(value, filter.field);
5252
+ const values = require_replay_player_layout.fieldValues(value, filter.field);
4490
5253
  const multiSelect = (_filter$multiSelect = filter.multiSelect) !== null && _filter$multiSelect !== void 0 ? _filter$multiSelect : true;
4491
5254
  if (filter.kind === "field_value_selection") {
4492
5255
  var _filter$options, _filter$options2;
@@ -4569,7 +5332,7 @@ function QueryFilterBar({ value, onChange, filters, fields, actions, showClauses
4569
5332
  }
4570
5333
  /** Whether the bar is filtering anything — for an empty state's wording. */
4571
5334
  function hasActiveQuery(query) {
4572
- return !require_field_sidebar.isEmptyQuery(query);
5335
+ return !require_replay_player_layout.isEmptyQuery(query);
4573
5336
  }
4574
5337
  //#endregion
4575
5338
  //#region src/shells/catalog-frame.tsx
@@ -4666,7 +5429,7 @@ function CatalogFrame({ children, isEmpty, query, onQueryChange, filters, stats,
4666
5429
  selectedKeys,
4667
5430
  onSelectionChange
4668
5431
  ]);
4669
- const filtering = !require_field_sidebar.isEmptyQuery(query);
5432
+ const filtering = !require_replay_player_layout.isEmptyQuery(query);
4670
5433
  const body = error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.EmptyState, {
4671
5434
  tone: "error",
4672
5435
  hasBorder: true,
@@ -4870,9 +5633,9 @@ const FALLBACK_SWATCHES = [
4870
5633
  "var(--opt-text)"
4871
5634
  ];
4872
5635
  function buildThemeOptions() {
4873
- return require_field_sidebar.THEME_PRESET_IDS.map((id) => {
5636
+ return require_replay_player_layout.THEME_PRESET_IDS.map((id) => {
4874
5637
  var _descriptor$switcherS;
4875
- const descriptor = require_field_sidebar.THEME_REGISTRY[id];
5638
+ const descriptor = require_replay_player_layout.THEME_REGISTRY[id];
4876
5639
  return {
4877
5640
  value: id,
4878
5641
  label: descriptor.label,
@@ -4953,7 +5716,7 @@ function resolveLabels(user) {
4953
5716
  /** Renders the theme switcher component. */
4954
5717
  function ThemeSwitcher({ className, labels: userLabels, variant = "default", customPresetEditor, preset: controlledPreset, onPresetChange, mode: controlledMode, onModeChange }) {
4955
5718
  var _ref;
4956
- const themeContext = require_field_sidebar.useOptionalOptTheme();
5719
+ const themeContext = require_replay_player_layout.useOptionalOptTheme();
4957
5720
  const preset = controlledPreset !== null && controlledPreset !== void 0 ? controlledPreset : themeContext === null || themeContext === void 0 ? void 0 : themeContext.preset;
4958
5721
  const mode = (_ref = controlledMode !== null && controlledMode !== void 0 ? controlledMode : themeContext === null || themeContext === void 0 ? void 0 : themeContext.mode) !== null && _ref !== void 0 ? _ref : "light";
4959
5722
  const setPreset = onPresetChange !== null && onPresetChange !== void 0 ? onPresetChange : themeContext === null || themeContext === void 0 ? void 0 : themeContext.setPreset;
@@ -4962,7 +5725,7 @@ function ThemeSwitcher({ className, labels: userLabels, variant = "default", cus
4962
5725
  const labels = resolveLabels(userLabels);
4963
5726
  const options = buildThemeOptions();
4964
5727
  const activePreset = preset;
4965
- const forcedMode = require_field_sidebar.FORCE_LIGHT_PRESET_IDS.has(activePreset);
5728
+ const forcedMode = require_replay_player_layout.FORCE_LIGHT_PRESET_IDS.has(activePreset);
4966
5729
  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);
4967
5730
  if (options.length === 0) return null;
4968
5731
  if (variant === "compact") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -5477,64 +6240,56 @@ ConfirmDialog.displayName = "ConfirmDialog";
5477
6240
  function AsyncCombobox({ onSearch, debounceMs = 300, loadingText, minChars = 1, placeholder, onSelect, labels: customLabels, className }) {
5478
6241
  const labels = require_text_truncate._objectSpread2({
5479
6242
  input: placeholder !== null && placeholder !== void 0 ? placeholder : "Search",
6243
+ error: "Search failed. Please try again.",
6244
+ retry: "Retry",
5480
6245
  loading: loadingText !== null && loadingText !== void 0 ? loadingText : "Loading…",
5481
6246
  noResults: "No results",
5482
6247
  placeholder: placeholder !== null && placeholder !== void 0 ? placeholder : "Search…"
5483
6248
  }, customLabels);
5484
6249
  const [query, setQuery] = react.useState("");
5485
- const [results, setResults] = react.useState([]);
5486
- const [loading, setLoading] = react.useState(false);
5487
- const timerRef = react.useRef(void 0);
5488
- const searchGenerationRef = react.useRef(0);
5489
- const handleInput = react.useCallback((event) => {
5490
- searchGenerationRef.current += 1;
6250
+ const inputRef = react.useRef(null);
6251
+ const { results, loading, failed, retry, invalidate } = require_replay_player_layout.useAsyncSearch({
6252
+ query,
6253
+ search: onSearch,
6254
+ enabled: query.length >= minChars,
6255
+ debounceMs
6256
+ });
6257
+ const handleInput = (event) => {
6258
+ inputRef.current = event.currentTarget;
6259
+ invalidate();
5491
6260
  setQuery(event.currentTarget.value);
5492
- }, []);
5493
- const handleValueChange = react.useCallback((value) => {
5494
- searchGenerationRef.current += 1;
5495
- if (timerRef.current) clearTimeout(timerRef.current);
5496
- setLoading(false);
5497
- setResults([]);
6261
+ };
6262
+ const handleValueChange = (value) => {
6263
+ invalidate();
5498
6264
  onSelect === null || onSelect === void 0 || onSelect(value);
5499
- }, [onSelect]);
5500
- react.useEffect(() => {
5501
- const generation = ++searchGenerationRef.current;
5502
- if (timerRef.current) clearTimeout(timerRef.current);
5503
- if (query.length < minChars) {
5504
- setResults([]);
5505
- setLoading(false);
5506
- return;
5507
- }
5508
- setLoading(true);
5509
- timerRef.current = setTimeout(async () => {
5510
- try {
5511
- const items = await onSearch(query);
5512
- if (searchGenerationRef.current !== generation) return;
5513
- setResults(items);
5514
- } finally {
5515
- if (searchGenerationRef.current === generation) setLoading(false);
5516
- }
5517
- }, debounceMs);
5518
- return () => {
5519
- if (timerRef.current) clearTimeout(timerRef.current);
5520
- };
5521
- }, [
5522
- query,
5523
- minChars,
5524
- debounceMs,
5525
- onSearch
5526
- ]);
6265
+ };
5527
6266
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_text_truncate.ComboboxRoot, {
5528
6267
  onValueChange: handleValueChange,
5529
6268
  "data-opt-id": "KAKTV",
5530
6269
  "data-opt-slug": "async-combobox.AsyncCombobox",
5531
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.ComboboxInput, {
6270
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.ComboboxInput, require_text_truncate._objectSpread2({
5532
6271
  className: require_text_truncate.cn(className),
5533
6272
  "aria-label": labels.input,
5534
6273
  "aria-busy": loading || void 0,
5535
6274
  placeholder: labels.placeholder,
5536
6275
  onInput: handleInput
5537
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.ComboboxPopover, { children: loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6276
+ }, failed ? {
6277
+ "aria-expanded": false,
6278
+ "aria-controls": void 0
6279
+ } : {})), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.ComboboxPopover, require_text_truncate._objectSpread2(require_text_truncate._objectSpread2({}, failed ? { role: "presentation" } : {}), {}, { children: failed ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6280
+ role: "alert",
6281
+ className: "gap-element flex flex-col px-3 py-2 text-sm",
6282
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: labels.error }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.Button, {
6283
+ variant: "secondary",
6284
+ size: "sm",
6285
+ onClick: () => {
6286
+ var _inputRef$current;
6287
+ retry();
6288
+ (_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
6289
+ },
6290
+ children: labels.retry
6291
+ })]
6292
+ }) : loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5538
6293
  className: "text-text-secondary gap-element flex items-center px-3 py-2 text-sm",
5539
6294
  role: "status",
5540
6295
  "aria-live": "polite",
@@ -5546,7 +6301,7 @@ function AsyncCombobox({ onSearch, debounceMs = 300, loadingText, minChars = 1,
5546
6301
  }) : results.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.ComboboxEmpty, { children: labels.noResults }) : results.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_text_truncate.ComboboxItem, {
5547
6302
  value: item,
5548
6303
  children: item
5549
- }, item)) })]
6304
+ }, item)) }))]
5550
6305
  });
5551
6306
  }
5552
6307
  //#endregion
@@ -8177,7 +8932,7 @@ const enStarRatingLabels = {
8177
8932
  };
8178
8933
  const enBreadcrumbLabels = { navAriaLabel: "Go to {label}" };
8179
8934
  //#endregion
8180
- exports.ALL_COMPOUND_THEMES = require_field_sidebar.ALL_COMPOUND_THEMES;
8935
+ exports.ALL_COMPOUND_THEMES = require_replay_player_layout.ALL_COMPOUND_THEMES;
8181
8936
  exports.AccordionContent = require_key_pad_menu.AccordionContent;
8182
8937
  exports.AccordionItem = require_key_pad_menu.AccordionItem;
8183
8938
  exports.AccordionRoot = require_key_pad_menu.AccordionRoot;
@@ -8186,7 +8941,7 @@ exports.ActivityFeed = ActivityFeed;
8186
8941
  exports.Alert = require_text_truncate.Alert;
8187
8942
  exports.AlertBuilder = AlertBuilder;
8188
8943
  exports.AlertDialogPanel = require_text_truncate.AlertDialogPanel;
8189
- exports.AppMenubar = require_field_sidebar.AppMenubar;
8944
+ exports.AppMenubar = require_replay_player_layout.AppMenubar;
8190
8945
  exports.AppShell = AppShell;
8191
8946
  exports.AsyncCombobox = AsyncCombobox;
8192
8947
  exports.AuditLog = AuditLog;
@@ -8196,12 +8951,12 @@ exports.Avatar = require_key_pad_menu.Avatar;
8196
8951
  exports.AvatarGroup = require_key_pad_menu.AvatarGroup;
8197
8952
  exports.Badge = require_text_truncate.Badge;
8198
8953
  exports.BlockLayout = require_key_pad_menu.BlockLayout;
8199
- exports.BranchSelect = require_field_sidebar.BranchSelect;
8954
+ exports.BranchSelect = require_replay_player_layout.BranchSelect;
8200
8955
  exports.Breadcrumb = require_key_pad_menu.Breadcrumb;
8201
8956
  exports.BulkActions = BulkActions;
8202
8957
  exports.Button = require_text_truncate.Button;
8203
8958
  exports.COLOR_PRESETS = COLOR_PRESETS;
8204
- exports.Callout = require_field_sidebar.Callout;
8959
+ exports.Callout = require_replay_player_layout.Callout;
8205
8960
  exports.Card = require_key_pad_menu.Card;
8206
8961
  exports.CardContent = require_key_pad_menu.CardContent;
8207
8962
  exports.CardDescription = require_key_pad_menu.CardDescription;
@@ -8230,17 +8985,17 @@ exports.ComboboxInput = require_text_truncate.ComboboxInput;
8230
8985
  exports.ComboboxItem = require_text_truncate.ComboboxItem;
8231
8986
  exports.ComboboxPopover = require_text_truncate.ComboboxPopover;
8232
8987
  exports.ComboboxRoot = require_text_truncate.ComboboxRoot;
8233
- exports.Command = require_field_sidebar.Command;
8234
- exports.CommandDialog = require_field_sidebar.CommandDialog;
8235
- exports.CommandEmpty = require_field_sidebar.CommandEmpty;
8236
- exports.CommandGroup = require_field_sidebar.CommandGroup;
8237
- exports.CommandInput = require_field_sidebar.CommandInput;
8238
- exports.CommandItem = require_field_sidebar.CommandItem;
8239
- exports.CommandList = require_field_sidebar.CommandList;
8240
- exports.CommandPalette = require_field_sidebar.CommandPalette;
8241
- exports.CommandPaletteTrigger = require_field_sidebar.CommandPaletteTrigger;
8242
- exports.CommandSeparator = require_field_sidebar.CommandSeparator;
8243
- exports.CommandShortcut = require_field_sidebar.CommandShortcut;
8988
+ exports.Command = require_replay_player_layout.Command;
8989
+ exports.CommandDialog = require_replay_player_layout.CommandDialog;
8990
+ exports.CommandEmpty = require_replay_player_layout.CommandEmpty;
8991
+ exports.CommandGroup = require_replay_player_layout.CommandGroup;
8992
+ exports.CommandInput = require_replay_player_layout.CommandInput;
8993
+ exports.CommandItem = require_replay_player_layout.CommandItem;
8994
+ exports.CommandList = require_replay_player_layout.CommandList;
8995
+ exports.CommandPalette = require_replay_player_layout.CommandPalette;
8996
+ exports.CommandPaletteTrigger = require_replay_player_layout.CommandPaletteTrigger;
8997
+ exports.CommandSeparator = require_replay_player_layout.CommandSeparator;
8998
+ exports.CommandShortcut = require_replay_player_layout.CommandShortcut;
8244
8999
  exports.ComparisonSelector = ComparisonSelector;
8245
9000
  exports.Composite = _reopt_ai_opt_ui_primitives.Composite;
8246
9001
  exports.CompositeItem = _reopt_ai_opt_ui_primitives.CompositeItem;
@@ -8251,15 +9006,16 @@ exports.ConditionBuilder = require_key_pad_menu.ConditionBuilder;
8251
9006
  exports.ConfirmDialog = ConfirmDialog;
8252
9007
  exports.ConnectionIndicator = ConnectionIndicator;
8253
9008
  exports.Container = require_key_pad_menu.Container;
8254
- exports.ContentTabs = require_field_sidebar.ContentTabs;
9009
+ exports.ContentTabs = require_replay_player_layout.ContentTabs;
8255
9010
  exports.CopyButton = CopyButton;
9011
+ exports.CriteriaBuilder = CriteriaBuilder;
8256
9012
  exports.DEFAULT_PRESETS = require_text_truncate.DEFAULT_PRESETS;
8257
- exports.DEFAULT_TIME_PRESETS = require_field_sidebar.DEFAULT_TIME_PRESETS;
8258
- exports.DashboardGrid = require_field_sidebar.DashboardGrid;
9013
+ exports.DEFAULT_TIME_PRESETS = require_replay_player_layout.DEFAULT_TIME_PRESETS;
9014
+ exports.DashboardGrid = require_replay_player_layout.DashboardGrid;
8259
9015
  exports.DataImportWizard = DataImportWizard;
8260
- exports.DataTable = require_field_sidebar.DataTable;
9016
+ exports.DataTable = require_replay_player_layout.DataTable;
8261
9017
  exports.DateRangePicker = require_text_truncate.DateRangePicker;
8262
- exports.DeploymentTimeline = require_field_sidebar.DeploymentTimeline;
9018
+ exports.DeploymentTimeline = require_replay_player_layout.DeploymentTimeline;
8263
9019
  exports.DescriptionList = require_text_truncate.DescriptionList;
8264
9020
  exports.DesignGuidePanel = DesignGuidePanel;
8265
9021
  exports.DialogBody = require_text_truncate.DialogBody;
@@ -8274,7 +9030,7 @@ exports.DialogRoot = require_text_truncate.DialogRoot;
8274
9030
  exports.DisclosureContent = require_text_truncate.DisclosureContent;
8275
9031
  exports.DisclosureRoot = require_text_truncate.DisclosureRoot;
8276
9032
  exports.DisclosureTrigger = require_text_truncate.DisclosureTrigger;
8277
- exports.DomainTable = require_field_sidebar.DomainTable;
9033
+ exports.DomainTable = require_replay_player_layout.DomainTable;
8278
9034
  exports.DrawerClose = require_key_pad_menu.DrawerClose;
8279
9035
  exports.DrawerPanel = require_key_pad_menu.DrawerPanel;
8280
9036
  exports.DrawerRoot = require_key_pad_menu.DrawerRoot;
@@ -8284,11 +9040,11 @@ exports.DropdownMenu = require_text_truncate.DropdownMenu;
8284
9040
  exports.DropdownSeparator = require_text_truncate.DropdownSeparator;
8285
9041
  exports.DropdownTrigger = require_text_truncate.DropdownTrigger;
8286
9042
  exports.DynamicFieldForm = DynamicFieldForm;
8287
- exports.EMPTY_QUERY = require_field_sidebar.EMPTY_QUERY;
8288
- exports.EMPTY_QUERY_FILTERS = require_field_sidebar.EMPTY_QUERY_FILTERS;
8289
- exports.EditorToolbar = require_field_sidebar.EditorToolbar;
9043
+ exports.EMPTY_QUERY = require_replay_player_layout.EMPTY_QUERY;
9044
+ exports.EMPTY_QUERY_FILTERS = require_replay_player_layout.EMPTY_QUERY_FILTERS;
9045
+ exports.EditorToolbar = require_replay_player_layout.EditorToolbar;
8290
9046
  exports.EmptyState = require_text_truncate.EmptyState;
8291
- exports.EnvPanel = require_field_sidebar.EnvPanel;
9047
+ exports.EnvPanel = require_replay_player_layout.EnvPanel;
8292
9048
  exports.ErrorBoundary = ErrorBoundary;
8293
9049
  exports.EventIcon = EventIcon;
8294
9050
  exports.EventMetaEditor = EventMetaEditor;
@@ -8298,25 +9054,25 @@ Object.defineProperty(exports, "EventSparkline", {
8298
9054
  return _reopt_ai_opt_charts.EventSparkline;
8299
9055
  }
8300
9056
  });
8301
- exports.EventTimeline = require_field_sidebar.EventTimeline;
9057
+ exports.EventTimeline = require_replay_player_layout.EventTimeline;
8302
9058
  exports.ExportButton = ExportButton;
8303
9059
  exports.Expression = require_key_pad_menu.Expression;
8304
9060
  exports.ExpressionGroup = require_key_pad_menu.ExpressionGroup;
8305
9061
  exports.FIELD_TYPE_TOKENS = require_text_truncate.FIELD_TYPE_TOKENS;
8306
- exports.FORCE_LIGHT_PRESETS = require_field_sidebar.FORCE_LIGHT_PRESETS;
8307
- exports.FORCE_LIGHT_PRESET_IDS = require_field_sidebar.FORCE_LIGHT_PRESET_IDS;
9062
+ exports.FORCE_LIGHT_PRESETS = require_replay_player_layout.FORCE_LIGHT_PRESETS;
9063
+ exports.FORCE_LIGHT_PRESET_IDS = require_replay_player_layout.FORCE_LIGHT_PRESET_IDS;
8308
9064
  exports.Facet = require_key_pad_menu.Facet;
8309
9065
  exports.FacetGroup = require_key_pad_menu.FacetGroup;
8310
- exports.FailureList = require_field_sidebar.FailureList;
8311
- exports.FaqAccordion = require_field_sidebar.FaqAccordion;
9066
+ exports.FailureList = require_replay_player_layout.FailureList;
9067
+ exports.FaqAccordion = require_replay_player_layout.FaqAccordion;
8312
9068
  exports.FeatureFlagPanel = FeatureFlagPanel;
8313
- exports.FieldSidebar = require_field_sidebar.FieldSidebar;
9069
+ exports.FieldSidebar = require_replay_player_layout.FieldSidebar;
8314
9070
  exports.FieldToken = require_text_truncate.FieldToken;
8315
9071
  exports.FieldTokenLegend = require_text_truncate.FieldTokenLegend;
8316
9072
  exports.FileUploadForm = FileUploadForm;
8317
9073
  exports.FilterBar = FilterBar;
8318
9074
  exports.FloatingActionBar = FloatingActionBar;
8319
- exports.Flyout = require_field_sidebar.Flyout;
9075
+ exports.Flyout = require_replay_player_layout.Flyout;
8320
9076
  exports.FormCheckbox = require_text_truncate.FormCheckbox;
8321
9077
  exports.FormColorPicker = require_text_truncate.FormColorPicker;
8322
9078
  exports.FormControl = require_text_truncate.FormControl;
@@ -8346,8 +9102,8 @@ exports.FormSubmit = require_text_truncate.FormSubmit;
8346
9102
  exports.FormSwitch = require_text_truncate.FormSwitch;
8347
9103
  exports.FormTagInput = require_text_truncate.FormTagInput;
8348
9104
  exports.FormTextarea = require_text_truncate.FormTextarea;
8349
- exports.GENERATED_THEME_ID_DEFAULT = require_field_sidebar.GENERATED_THEME_ID_DEFAULT;
8350
- exports.GLOBAL_THEME_STYLE_ID = require_field_sidebar.GLOBAL_THEME_STYLE_ID;
9105
+ exports.GENERATED_THEME_ID_DEFAULT = require_replay_player_layout.GENERATED_THEME_ID_DEFAULT;
9106
+ exports.GLOBAL_THEME_STYLE_ID = require_replay_player_layout.GLOBAL_THEME_STYLE_ID;
8351
9107
  exports.Heading = require_key_pad_menu.Heading;
8352
9108
  exports.Highlight = require_text_truncate.Highlight;
8353
9109
  exports.IconPicker = require_text_truncate.IconPicker;
@@ -8360,10 +9116,10 @@ exports.InspectorLayout = InspectorLayout;
8360
9116
  exports.KanbanBoard = KanbanBoard;
8361
9117
  exports.Kbd = require_text_truncate.Kbd;
8362
9118
  exports.KeyPadMenu = require_key_pad_menu.KeyPadMenu;
8363
- exports.KeyValueEditor = require_field_sidebar.KeyValueEditor;
9119
+ exports.KeyValueEditor = require_replay_player_layout.KeyValueEditor;
8364
9120
  exports.LiveRegion = require_key_pad_menu.LiveRegion;
8365
9121
  exports.LoadingOverlay = require_key_pad_menu.LoadingOverlay;
8366
- exports.LogTable = require_field_sidebar.LogTable;
9122
+ exports.LogTable = require_replay_player_layout.LogTable;
8367
9123
  exports.Logo = require_key_pad_menu.Logo;
8368
9124
  exports.MegaMenu = MegaMenu;
8369
9125
  exports.MenuButtonArrow = require_text_truncate.MenuButtonArrow;
@@ -8384,12 +9140,12 @@ Object.defineProperty(exports, "MetricsCard", {
8384
9140
  }
8385
9141
  });
8386
9142
  exports.NotificationCenter = NotificationCenter;
8387
- exports.NotificationToast = require_field_sidebar.NotificationToast;
9143
+ exports.NotificationToast = require_replay_player_layout.NotificationToast;
8388
9144
  exports.NumberInput = require_text_truncate.NumberInput;
8389
9145
  exports.OPT_TEXT_PRIMARY = require_text_truncate.OPT_TEXT_PRIMARY;
8390
9146
  exports.OPT_TEXT_SECONDARY = require_text_truncate.OPT_TEXT_SECONDARY;
8391
- exports.OptThemeControllerContext = require_field_sidebar.OptThemeControllerContext;
8392
- exports.OptThemeProvider = require_field_sidebar.OptThemeProvider;
9147
+ exports.OptThemeControllerContext = require_replay_player_layout.OptThemeControllerContext;
9148
+ exports.OptThemeProvider = require_replay_player_layout.OptThemeProvider;
8393
9149
  exports.OtpField = require_key_pad_menu.OtpField;
8394
9150
  exports.POPULAR_ICONS = POPULAR_ICONS;
8395
9151
  exports.PageAside = PageAside;
@@ -8400,22 +9156,25 @@ exports.PopoverContent = require_text_truncate.PopoverContent;
8400
9156
  exports.PopoverRoot = require_text_truncate.PopoverRoot;
8401
9157
  exports.PopoverTrigger = require_text_truncate.PopoverTrigger;
8402
9158
  exports.Progress = require_key_pad_menu.Progress;
8403
- exports.ProjectSwitcher = require_field_sidebar.ProjectSwitcher;
9159
+ exports.ProjectSwitcher = require_replay_player_layout.ProjectSwitcher;
8404
9160
  exports.PromptTemplate = PromptTemplate;
8405
9161
  exports.PropertyExplorer = PropertyExplorer;
8406
- exports.QueryBar = require_field_sidebar.QueryBar;
9162
+ exports.QueryBar = require_replay_player_layout.QueryBar;
8407
9163
  exports.QueryFilterBar = QueryFilterBar;
8408
- exports.QueryFiltersMenu = require_field_sidebar.QueryFiltersMenu;
8409
- exports.QueryHistoryList = require_field_sidebar.QueryHistoryList;
8410
- exports.QueryOutputPane = require_field_sidebar.QueryOutputPane;
8411
- exports.QueryResultChart = require_field_sidebar.QueryResultChart;
8412
- exports.QueryResultsTable = require_field_sidebar.QueryResultsTable;
8413
- exports.QueryToolbar = require_field_sidebar.QueryToolbar;
8414
- exports.QueryVariablesMenu = require_field_sidebar.QueryVariablesMenu;
8415
- exports.QueryWorkspace = require_field_sidebar.QueryWorkspace;
9164
+ exports.QueryFiltersMenu = require_replay_player_layout.QueryFiltersMenu;
9165
+ exports.QueryHistoryList = require_replay_player_layout.QueryHistoryList;
9166
+ exports.QueryOutputPane = require_replay_player_layout.QueryOutputPane;
9167
+ exports.QueryResultChart = require_replay_player_layout.QueryResultChart;
9168
+ exports.QueryResultsTable = require_replay_player_layout.QueryResultsTable;
9169
+ exports.QueryToolbar = require_replay_player_layout.QueryToolbar;
9170
+ exports.QueryVariablesMenu = require_replay_player_layout.QueryVariablesMenu;
9171
+ exports.QueryWorkspace = require_replay_player_layout.QueryWorkspace;
8416
9172
  exports.QuickActions = QuickActions;
8417
9173
  exports.Radio = require_key_pad_menu.Radio;
8418
9174
  exports.RadioGroup = require_key_pad_menu.RadioGroup;
9175
+ exports.ReplayPlayerLayout = require_replay_player_layout.ReplayPlayerLayout;
9176
+ exports.ReplayScrubber = require_replay_player_layout.ReplayScrubber;
9177
+ exports.ReplayTransport = require_replay_player_layout.ReplayTransport;
8419
9178
  exports.ReportBuilder = ReportBuilder;
8420
9179
  Object.defineProperty(exports, "ReportWidget", {
8421
9180
  enumerable: true,
@@ -8433,25 +9192,25 @@ exports.SHADER_PARAM_FALLBACK = require_key_pad_menu.SHADER_PARAM_FALLBACK;
8433
9192
  exports.SHADER_PARAM_KEYS = require_key_pad_menu.SHADER_PARAM_KEYS;
8434
9193
  exports.SHADER_PRESETS = require_key_pad_menu.SHADER_PRESETS;
8435
9194
  exports.SHADER_PRESET_IDS = require_key_pad_menu.SHADER_PRESET_IDS;
8436
- exports.SaveQueryDialog = require_field_sidebar.SaveQueryDialog;
9195
+ exports.SaveQueryDialog = require_replay_player_layout.SaveQueryDialog;
8437
9196
  exports.SavedFilters = SavedFilters;
8438
- exports.SchemaTree = require_field_sidebar.SchemaTree;
8439
- exports.ScoreBreakdown = require_field_sidebar.ScoreBreakdown;
9197
+ exports.SchemaTree = require_replay_player_layout.SchemaTree;
9198
+ exports.ScoreBreakdown = require_replay_player_layout.ScoreBreakdown;
8440
9199
  exports.ScrollArea = require_key_pad_menu.ScrollArea;
8441
- exports.SearchCombobox = require_field_sidebar.SearchCombobox;
9200
+ exports.SearchCombobox = require_replay_player_layout.SearchCombobox;
8442
9201
  exports.Section = require_key_pad_menu.Section;
8443
9202
  exports.SegmentBuilder = SegmentBuilder;
8444
- exports.SegmentedControl = require_field_sidebar.SegmentedControl;
9203
+ exports.SegmentedControl = require_replay_player_layout.SegmentedControl;
8445
9204
  exports.SelectItem = require_text_truncate.SelectItem;
8446
9205
  exports.SelectLabel = require_text_truncate.SelectLabel;
8447
9206
  exports.SelectPopover = require_text_truncate.SelectPopover;
8448
9207
  exports.SelectRoot = require_text_truncate.SelectRoot;
8449
9208
  exports.SelectTrigger = require_text_truncate.SelectTrigger;
8450
9209
  exports.Separator = require_key_pad_menu.Separator;
8451
- exports.SettingsForm = require_field_sidebar.SettingsForm;
9210
+ exports.SettingsForm = require_replay_player_layout.SettingsForm;
8452
9211
  exports.ShaderSurface = require_key_pad_menu.ShaderSurface;
8453
9212
  exports.Sidebar = Sidebar;
8454
- exports.SidebarNav = require_field_sidebar.SidebarNav;
9213
+ exports.SidebarNav = require_replay_player_layout.SidebarNav;
8455
9214
  exports.Skeleton = require_text_truncate.Skeleton;
8456
9215
  exports.SkeletonAvatar = require_text_truncate.SkeletonAvatar;
8457
9216
  exports.SkeletonCard = require_text_truncate.SkeletonCard;
@@ -8460,20 +9219,20 @@ exports.SkeletonText = require_text_truncate.SkeletonText;
8460
9219
  exports.Slider = require_text_truncate.Slider;
8461
9220
  exports.SpatialNavProvider = SpatialNavProvider;
8462
9221
  exports.Spinner = require_text_truncate.Spinner;
8463
- exports.SqlEditor = require_field_sidebar.SqlEditor;
9222
+ exports.SqlEditor = require_replay_player_layout.SqlEditor;
8464
9223
  exports.StarRating = require_text_truncate.StarRating;
8465
9224
  exports.StatCard = require_text_truncate.StatCard;
8466
9225
  exports.StatusDot = StatusDot;
8467
- exports.StatusSelect = require_field_sidebar.StatusSelect;
9226
+ exports.StatusSelect = require_replay_player_layout.StatusSelect;
8468
9227
  exports.StepBuilder = require_key_pad_menu.StepBuilder;
8469
9228
  exports.SummaryRow = SummaryRow;
8470
9229
  exports.SurfaceLayout = require_key_pad_menu.BlockLayout;
8471
9230
  exports.Switch = require_text_truncate.Switch;
8472
9231
  exports.THEME_PALETTES = require_key_pad_menu.THEME_PALETTES;
8473
- exports.THEME_PRESET_IDS = require_field_sidebar.THEME_PRESET_IDS;
8474
- exports.THEME_REGISTRY = require_field_sidebar.THEME_REGISTRY;
8475
- exports.THEME_SPEC_STORAGE_KEY = require_field_sidebar.THEME_SPEC_STORAGE_KEY;
8476
- exports.THEME_TOKENS_STORAGE_KEY = require_field_sidebar.THEME_TOKENS_STORAGE_KEY;
9232
+ exports.THEME_PRESET_IDS = require_replay_player_layout.THEME_PRESET_IDS;
9233
+ exports.THEME_REGISTRY = require_replay_player_layout.THEME_REGISTRY;
9234
+ exports.THEME_SPEC_STORAGE_KEY = require_replay_player_layout.THEME_SPEC_STORAGE_KEY;
9235
+ exports.THEME_TOKENS_STORAGE_KEY = require_replay_player_layout.THEME_TOKENS_STORAGE_KEY;
8477
9236
  exports.Tab = require_text_truncate.Tab;
8478
9237
  exports.TabList = require_text_truncate.TabList;
8479
9238
  exports.TabPanel = require_text_truncate.TabPanel;
@@ -8486,12 +9245,12 @@ exports.Text = require_key_pad_menu.Text;
8486
9245
  exports.TextTruncate = require_text_truncate.TextTruncate;
8487
9246
  exports.Textarea = require_text_truncate.Textarea;
8488
9247
  exports.ThemeSwitcher = ThemeSwitcher;
8489
- exports.TimeRangeControl = require_field_sidebar.TimeRangeControl;
9248
+ exports.TimeRangeControl = require_replay_player_layout.TimeRangeControl;
8490
9249
  exports.TimeRangeSelector = TimeRangeSelector;
8491
- exports.TimeSeriesPanel = require_field_sidebar.TimeSeriesPanel;
8492
- exports.ToastProvider = require_field_sidebar.ToastProvider;
8493
- exports.Toggle = require_key_pad_menu.Toggle;
8494
- exports.ToggleGroup = require_key_pad_menu.ToggleGroup;
9250
+ exports.TimeSeriesPanel = require_replay_player_layout.TimeSeriesPanel;
9251
+ exports.ToastProvider = require_replay_player_layout.ToastProvider;
9252
+ exports.Toggle = require_text_truncate.Toggle;
9253
+ exports.ToggleGroup = require_text_truncate.ToggleGroup;
8495
9254
  exports.ToolbarButton = require_text_truncate.ToolbarButton;
8496
9255
  exports.ToolbarContainer = require_text_truncate.ToolbarContainer;
8497
9256
  exports.ToolbarRoot = require_text_truncate.ToolbarRoot;
@@ -8506,96 +9265,106 @@ Object.defineProperty(exports, "TrendChart", {
8506
9265
  return _reopt_ai_opt_charts.TrendChart;
8507
9266
  }
8508
9267
  });
8509
- exports.VALUELESS_OPERATORS = require_field_sidebar.VALUELESS_OPERATORS;
9268
+ exports.VALUELESS_OPERATORS = require_replay_player_layout.VALUELESS_OPERATORS;
8510
9269
  exports.VerticalTabs = VerticalTabs;
8511
9270
  exports.VirtualList = require_key_pad_menu.VirtualList;
8512
9271
  exports.WebhookConfig = WebhookConfig;
8513
9272
  exports.WidgetGrid = WidgetGrid;
8514
9273
  exports.WizardForm = WizardForm;
8515
- exports.WorkflowCanvas = require_field_sidebar.WorkflowCanvas;
8516
- exports.addClause = require_field_sidebar.addClause;
8517
- exports.applyCellAction = require_field_sidebar.applyCellAction;
8518
- exports.buildTokenCache = require_field_sidebar.buildTokenCache;
9274
+ exports.WorkflowCanvas = require_replay_player_layout.WorkflowCanvas;
9275
+ exports.addClause = require_replay_player_layout.addClause;
9276
+ exports.applyCellAction = require_replay_player_layout.applyCellAction;
9277
+ exports.buildTokenCache = require_replay_player_layout.buildTokenCache;
8519
9278
  exports.cn = require_text_truncate.cn;
8520
- exports.coerceThemeMode = require_field_sidebar.coerceThemeMode;
8521
- exports.computeGeneratedTokens = require_field_sidebar.computeGeneratedTokens;
9279
+ exports.coerceThemeMode = require_replay_player_layout.coerceThemeMode;
9280
+ exports.computeGeneratedTokens = require_replay_player_layout.computeGeneratedTokens;
8522
9281
  exports.computeSpatialTargets = computeSpatialTargets;
8523
- exports.countActiveQueryFilters = require_field_sidebar.countActiveQueryFilters;
9282
+ exports.countActiveQueryFilters = require_replay_player_layout.countActiveQueryFilters;
8524
9283
  exports.createBlock = require_key_pad_menu.createBlock;
8525
9284
  exports.createSurface = require_key_pad_menu.createBlock;
8526
- exports.createThemeBootScript = require_field_sidebar.createThemeBootScript;
8527
- exports.defaultQueryChartConfig = require_field_sidebar.defaultQueryChartConfig;
8528
- exports.defineThemeOverrides = require_field_sidebar.defineThemeOverrides;
8529
- exports.describeClause = require_field_sidebar.describeClause;
9285
+ exports.createThemeBootScript = require_replay_player_layout.createThemeBootScript;
9286
+ exports.criteriaBuilderDuplicate = criteriaBuilderDuplicate;
9287
+ exports.criteriaBuilderDuplicateGroup = criteriaBuilderDuplicateGroup;
9288
+ exports.criteriaBuilderInsert = criteriaBuilderInsert;
9289
+ exports.criteriaBuilderMove = criteriaBuilderMove;
9290
+ exports.criteriaBuilderRemove = criteriaBuilderRemove;
9291
+ exports.criteriaBuilderRemoveGroup = criteriaBuilderRemoveGroup;
9292
+ exports.criteriaGroupLetter = criteriaGroupLetter;
9293
+ exports.defaultQueryChartConfig = require_replay_player_layout.defaultQueryChartConfig;
9294
+ exports.defineThemeOverrides = require_replay_player_layout.defineThemeOverrides;
9295
+ exports.describeClause = require_replay_player_layout.describeClause;
8530
9296
  exports.enBreadcrumbLabels = enBreadcrumbLabels;
8531
9297
  exports.enComboboxLabels = enComboboxLabels;
8532
9298
  exports.enStarRatingLabels = enStarRatingLabels;
8533
- exports.fieldValues = require_field_sidebar.fieldValues;
8534
- exports.formatClause = require_field_sidebar.formatClause;
9299
+ exports.fieldValues = require_replay_player_layout.fieldValues;
9300
+ exports.formatClause = require_replay_player_layout.formatClause;
8535
9301
  exports.formatOptDateTime = require_text_truncate.formatOptDateTime;
8536
9302
  exports.formatOptNumber = require_text_truncate.formatOptNumber;
8537
9303
  exports.formatOptShortDate = require_text_truncate.formatOptShortDate;
8538
9304
  exports.formatOptTime = require_text_truncate.formatOptTime;
8539
- exports.formatQuery = require_field_sidebar.formatQuery;
8540
- exports.formatQueryCell = require_field_sidebar.formatQueryCell;
8541
- exports.generatedTheme = require_field_sidebar.generatedTheme;
8542
- exports.getCompoundIdForSpec = require_field_sidebar.getCompoundIdForSpec;
8543
- exports.getCompoundTheme = require_field_sidebar.getCompoundTheme;
9305
+ exports.formatQuery = require_replay_player_layout.formatQuery;
9306
+ exports.formatQueryCell = require_replay_player_layout.formatQueryCell;
9307
+ exports.formatReplayElapsed = require_replay_player_layout.formatReplayElapsed;
9308
+ exports.generatedTheme = require_replay_player_layout.generatedTheme;
9309
+ exports.getCompoundIdForSpec = require_replay_player_layout.getCompoundIdForSpec;
9310
+ exports.getCompoundTheme = require_replay_player_layout.getCompoundTheme;
8544
9311
  exports.getShaderFragment = require_key_pad_menu.getShaderFragment;
8545
9312
  exports.getShaderPreset = require_key_pad_menu.getShaderPreset;
8546
- exports.getThemeDescriptor = require_field_sidebar.getThemeDescriptor;
9313
+ exports.getThemeDescriptor = require_replay_player_layout.getThemeDescriptor;
8547
9314
  exports.getTrappedContextRole = getTrappedContextRole;
9315
+ exports.groupReplayMarkers = require_replay_player_layout.groupReplayMarkers;
8548
9316
  exports.hasActiveQuery = hasActiveQuery;
8549
- exports.hasActiveQueryFilters = require_field_sidebar.hasActiveQueryFilters;
8550
- exports.isDescriptorSpec = require_field_sidebar.isDescriptorSpec;
8551
- exports.isEmptyQuery = require_field_sidebar.isEmptyQuery;
8552
- exports.isForceLightSpec = require_field_sidebar.isForceLightSpec;
8553
- exports.isGeneratedSpec = require_field_sidebar.isGeneratedSpec;
8554
- exports.isPresetSpec = require_field_sidebar.isPresetSpec;
8555
- exports.isThemePresetId = require_field_sidebar.isThemePresetId;
8556
- exports.isValidQueryVariableName = require_field_sidebar.isValidQueryVariableName;
9317
+ exports.hasActiveQueryFilters = require_replay_player_layout.hasActiveQueryFilters;
9318
+ exports.isDescriptorSpec = require_replay_player_layout.isDescriptorSpec;
9319
+ exports.isEmptyQuery = require_replay_player_layout.isEmptyQuery;
9320
+ exports.isForceLightSpec = require_replay_player_layout.isForceLightSpec;
9321
+ exports.isGeneratedSpec = require_replay_player_layout.isGeneratedSpec;
9322
+ exports.isPresetSpec = require_replay_player_layout.isPresetSpec;
9323
+ exports.isThemePresetId = require_replay_player_layout.isThemePresetId;
9324
+ exports.isValidQueryVariableName = require_replay_player_layout.isValidQueryVariableName;
8557
9325
  exports.koBreadcrumbLabels = require_text_truncate.koBreadcrumbLabels;
8558
9326
  exports.koComboboxLabels = require_text_truncate.koComboboxLabels;
8559
9327
  exports.koStarRatingLabels = require_text_truncate.koStarRatingLabels;
8560
9328
  exports.matchesQuery = matchesQuery;
8561
9329
  exports.matchesQueryObject = matchesQueryObject;
8562
- exports.numericResultColumns = require_field_sidebar.numericResultColumns;
8563
- exports.parseQuery = require_field_sidebar.parseQuery;
8564
- exports.parseQueryWithDiagnostics = require_field_sidebar.parseQueryWithDiagnostics;
8565
- exports.presetTheme = require_field_sidebar.presetTheme;
8566
- exports.queryFields = require_field_sidebar.queryFields;
8567
- exports.quoteValue = require_field_sidebar.quoteValue;
8568
- exports.readStoredTheme = require_field_sidebar.readStoredTheme;
8569
- exports.removeClause = require_field_sidebar.removeClause;
9330
+ exports.numericResultColumns = require_replay_player_layout.numericResultColumns;
9331
+ exports.parseQuery = require_replay_player_layout.parseQuery;
9332
+ exports.parseQueryWithDiagnostics = require_replay_player_layout.parseQueryWithDiagnostics;
9333
+ exports.presetTheme = require_replay_player_layout.presetTheme;
9334
+ exports.queryFields = require_replay_player_layout.queryFields;
9335
+ exports.quoteValue = require_replay_player_layout.quoteValue;
9336
+ exports.readStoredTheme = require_replay_player_layout.readStoredTheme;
9337
+ exports.removeClause = require_replay_player_layout.removeClause;
8570
9338
  exports.replaceSqlPlaceholder = replaceSqlPlaceholder;
8571
- exports.resolveDescriptor = require_field_sidebar.resolveDescriptor;
9339
+ exports.replayShortcutKey = require_replay_player_layout.replayShortcutKey;
9340
+ exports.resolveDescriptor = require_replay_player_layout.resolveDescriptor;
8572
9341
  exports.resolveFieldType = require_text_truncate.resolveFieldType;
8573
- exports.resolveThemeMode = require_field_sidebar.resolveThemeMode;
8574
- exports.safeParseStoredSpec = require_field_sidebar.safeParseStoredSpec;
8575
- exports.safeParseStoredTokens = require_field_sidebar.safeParseStoredTokens;
9342
+ exports.resolveThemeMode = require_replay_player_layout.resolveThemeMode;
9343
+ exports.safeParseStoredSpec = require_replay_player_layout.safeParseStoredSpec;
9344
+ exports.safeParseStoredTokens = require_replay_player_layout.safeParseStoredTokens;
8576
9345
  exports.schemaValidator = schemaValidator;
8577
- exports.serializeGeneratedTheme = require_field_sidebar.serializeGeneratedTheme;
8578
- exports.serializeThemeRule = require_field_sidebar.serializeThemeRule;
8579
- exports.serializeTokenBody = require_field_sidebar.serializeTokenBody;
9346
+ exports.serializeGeneratedTheme = require_replay_player_layout.serializeGeneratedTheme;
9347
+ exports.serializeThemeRule = require_replay_player_layout.serializeThemeRule;
9348
+ exports.serializeTokenBody = require_replay_player_layout.serializeTokenBody;
8580
9349
  exports.shouldSkipArrow = shouldSkipArrow;
8581
9350
  exports.splitSqlStatements = splitSqlStatements;
8582
9351
  exports.sqlPlaceholderNames = sqlPlaceholderNames;
8583
9352
  exports.sqlStatementAtOffset = sqlStatementAtOffset;
8584
9353
  exports.sqlUsesPlaceholder = sqlUsesPlaceholder;
8585
- exports.toast = require_field_sidebar.toast;
8586
- exports.useAutoRefresh = require_field_sidebar.useAutoRefresh;
9354
+ exports.toast = require_replay_player_layout.toast;
9355
+ exports.useAutoRefresh = require_replay_player_layout.useAutoRefresh;
8587
9356
  exports.useControlledState = require_text_truncate.useControlledState;
8588
9357
  exports.useFieldValue = _reopt_ai_opt_ui_primitives.useFieldValue;
8589
9358
  exports.useFormContext = _reopt_ai_opt_ui_primitives.useFormContext;
8590
9359
  exports.useFormStore = _reopt_ai_opt_ui_primitives.useFormStore;
8591
9360
  exports.useInputId = require_text_truncate.useInputId;
8592
- exports.useOptTheme = require_field_sidebar.useOptTheme;
8593
- exports.useOptThemeController = require_field_sidebar.useOptThemeController;
8594
- exports.useOptionalOptTheme = require_field_sidebar.useOptionalOptTheme;
9361
+ exports.useOptTheme = require_replay_player_layout.useOptTheme;
9362
+ exports.useOptThemeController = require_replay_player_layout.useOptThemeController;
9363
+ exports.useOptionalOptTheme = require_replay_player_layout.useOptionalOptTheme;
8595
9364
  exports.useSidebar = useSidebar;
8596
- exports.useToast = require_field_sidebar.useToast;
8597
- exports.withFieldValue = require_field_sidebar.withFieldValue;
8598
- exports.withoutField = require_field_sidebar.withoutField;
9365
+ exports.useToast = require_replay_player_layout.useToast;
9366
+ exports.withFieldValue = require_replay_player_layout.withFieldValue;
9367
+ exports.withoutField = require_replay_player_layout.withoutField;
8599
9368
  Object.keys(_reopt_ai_opt_charts).forEach(function(k) {
8600
9369
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
8601
9370
  enumerable: true,