@reopt-ai/opt-ui 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/COMPONENT_CATALOG.md +3000 -0
  3. package/LICENSE +21 -0
  4. package/README.md +244 -0
  5. package/dist/chunk-3GWWZKX7.js +38 -0
  6. package/dist/chunk-AFF2HPE5.cjs +5008 -0
  7. package/dist/chunk-ELWICXYY.js +4745 -0
  8. package/dist/chunk-N4NDU5ET.cjs +4745 -0
  9. package/dist/chunk-ONE3C5RV.cjs +38 -0
  10. package/dist/chunk-QWBHD54V.js +3218 -0
  11. package/dist/chunk-RBM2RNC2.js +5008 -0
  12. package/dist/chunk-X5WCXJAF.cjs +3218 -0
  13. package/dist/core/index.cjs +324 -0
  14. package/dist/core/index.d.cts +5 -0
  15. package/dist/core/index.d.ts +5 -0
  16. package/dist/core/index.js +324 -0
  17. package/dist/docs/01-getting-started.md +129 -0
  18. package/dist/docs/02-components/01-core.md +1841 -0
  19. package/dist/docs/02-components/02-visuals.md +11 -0
  20. package/dist/docs/02-components/03-shells.md +1361 -0
  21. package/dist/docs/02-components/04-surfaces.md +11 -0
  22. package/dist/docs/02-components/index.md +106 -0
  23. package/dist/docs/03-recipes/01-forms.md +471 -0
  24. package/dist/docs/03-recipes/02-dashboards.md +397 -0
  25. package/dist/docs/03-recipes/03-layouts.md +424 -0
  26. package/dist/docs/04-theming.md +232 -0
  27. package/dist/docs/05-migration/01-breaking-changes.md +117 -0
  28. package/dist/docs/05-migration/02-formstore.md +336 -0
  29. package/dist/docs/06-troubleshooting.md +119 -0
  30. package/dist/docs/index.md +71 -0
  31. package/dist/id-registry.cjs +1875 -0
  32. package/dist/id-registry.d.cts +27 -0
  33. package/dist/id-registry.d.ts +27 -0
  34. package/dist/id-registry.js +1875 -0
  35. package/dist/id-registry.json +3799 -0
  36. package/dist/index-BZ_lBlO1.d.ts +474 -0
  37. package/dist/index-BuvxoWHf.d.cts +474 -0
  38. package/dist/index-DlAcuvQp.d.cts +1686 -0
  39. package/dist/index-Slu5hOj1.d.ts +1686 -0
  40. package/dist/index.cjs +9959 -0
  41. package/dist/index.d.cts +2351 -0
  42. package/dist/index.d.ts +2351 -0
  43. package/dist/index.js +9959 -0
  44. package/dist/meta.cjs +6898 -0
  45. package/dist/meta.d.cts +36 -0
  46. package/dist/meta.d.ts +36 -0
  47. package/dist/meta.js +6869 -0
  48. package/dist/shells/index.cjs +65 -0
  49. package/dist/shells/index.d.cts +5 -0
  50. package/dist/shells/index.d.ts +5 -0
  51. package/dist/shells/index.js +65 -0
  52. package/dist/tailwind.css +401 -0
  53. package/dist/theme/presets/default.css +355 -0
  54. package/dist/theme/presets/minimal.css +354 -0
  55. package/dist/theme/presets/mono-dark.css +354 -0
  56. package/dist/theme/presets/natural.css +181 -0
  57. package/dist/theme/presets/pro.css +354 -0
  58. package/dist/types-D4-0lwaE.d.cts +298 -0
  59. package/dist/types-D4-0lwaE.d.ts +298 -0
  60. package/dist/visuals/index.cjs +4 -0
  61. package/dist/visuals/index.d.cts +1 -0
  62. package/dist/visuals/index.d.ts +1 -0
  63. package/dist/visuals/index.js +4 -0
  64. package/package.json +165 -0
@@ -0,0 +1,3218 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }"use client";
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
76
+
77
+
78
+
79
+
80
+
81
+
82
+
83
+
84
+
85
+
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+ var _chunkAFF2HPE5cjs = require('./chunk-AFF2HPE5.cjs');
97
+
98
+
99
+
100
+
101
+ var _chunkONE3C5RVcjs = require('./chunk-ONE3C5RV.cjs');
102
+
103
+ // src/core/command.tsx
104
+ var _lucidereact = require('lucide-react');
105
+
106
+
107
+
108
+
109
+
110
+
111
+
112
+
113
+ var _optuiprimitives = require('@reopt-ai/opt-ui-primitives');
114
+ var _jsxruntime = require('react/jsx-runtime');
115
+ function Command(_a) {
116
+ var _b = _a, { className } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, ["className"]);
117
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
118
+ _optuiprimitives.CommandRoot,
119
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
120
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
121
+ "bg-surface text-text-primary flex w-full flex-col overflow-hidden rounded-xl",
122
+ className
123
+ )
124
+ }, props), {
125
+ "data-opt-id": "4FYBW",
126
+ "data-opt-slug": "command.Command"
127
+ })
128
+ );
129
+ }
130
+ function CommandDialog({
131
+ open,
132
+ onOpenChange,
133
+ title = "Command Palette",
134
+ description = "\uAC80\uC0C9 \uD6C4 Enter \uB610\uB294 \uD074\uB9AD\uC73C\uB85C \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694.",
135
+ className,
136
+ commandClassName,
137
+ shouldFilter,
138
+ filter,
139
+ children
140
+ }) {
141
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
142
+ _chunkAFF2HPE5cjs.DialogRoot,
143
+ {
144
+ open,
145
+ onOpenChange,
146
+ "data-opt-id": "DVRSX",
147
+ "data-opt-slug": "command.CommandDialog",
148
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
149
+ _chunkAFF2HPE5cjs.DialogPanel,
150
+ {
151
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
152
+ "top-[20%] left-1/2 -translate-x-1/2",
153
+ "w-full max-w-lg overflow-hidden p-0 shadow-2xl",
154
+ className
155
+ ),
156
+ children: [
157
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.DialogHeading, { className: "sr-only", children: title }),
158
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.DialogDescription, { className: "sr-only", children: description }),
159
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
160
+ Command,
161
+ {
162
+ shouldFilter,
163
+ filter,
164
+ className: commandClassName,
165
+ children
166
+ }
167
+ )
168
+ ]
169
+ }
170
+ )
171
+ }
172
+ );
173
+ }
174
+ function CommandInput(_a) {
175
+ var _b = _a, {
176
+ className,
177
+ trailing,
178
+ wrapperClassName,
179
+ placeholder,
180
+ "aria-label": ariaLabel
181
+ } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, [
182
+ "className",
183
+ "trailing",
184
+ "wrapperClassName",
185
+ "placeholder",
186
+ "aria-label"
187
+ ]);
188
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
189
+ "div",
190
+ {
191
+ "data-slot": "command-input-wrapper",
192
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
193
+ "border-border-subtle gap-element flex h-12 items-center border-b px-3",
194
+ wrapperClassName
195
+ ),
196
+ "data-opt-id": "HB1K3",
197
+ "data-opt-slug": "command.CommandInput",
198
+ children: [
199
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.SearchIcon, { "aria-hidden": true, className: "text-text-tertiary size-4 shrink-0" }),
200
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
201
+ _optuiprimitives.CommandInput,
202
+ _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
203
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
204
+ // cmdk 컨벤션 — input 자체는 ring 없이 자연스러운 검색 경험.
205
+ // 포커스 표시는 wrapper(border-b)가 시각적 컨텍스트로 제공.
206
+ "text-text-primary placeholder:text-text-tertiary flex h-full w-full bg-transparent text-sm outline-none focus-visible:ring-0 focus-visible:outline-none",
207
+ "disabled:cursor-not-allowed disabled:opacity-50",
208
+ className
209
+ ),
210
+ placeholder,
211
+ "aria-label": ariaLabel != null ? ariaLabel : typeof placeholder === "string" ? placeholder : "Command search"
212
+ }, props)
213
+ ),
214
+ trailing
215
+ ]
216
+ }
217
+ );
218
+ }
219
+ function CommandList(_a) {
220
+ var _b = _a, {
221
+ className,
222
+ "aria-label": ariaLabel
223
+ } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, [
224
+ "className",
225
+ "aria-label"
226
+ ]);
227
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
228
+ _optuiprimitives.CommandList,
229
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
230
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
231
+ "max-h-80 scroll-py-1 overflow-x-hidden overflow-y-auto p-1",
232
+ className
233
+ ),
234
+ "aria-label": ariaLabel != null ? ariaLabel : "Commands"
235
+ }, props), {
236
+ "data-opt-id": "NPXC5",
237
+ "data-opt-slug": "command.CommandList"
238
+ })
239
+ );
240
+ }
241
+ function CommandEmpty(_a) {
242
+ var _b = _a, { className } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, ["className"]);
243
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
244
+ _optuiprimitives.CommandEmpty,
245
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
246
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "text-text-tertiary py-6 text-center text-sm", className)
247
+ }, props), {
248
+ "data-opt-id": "A8BZM",
249
+ "data-opt-slug": "command.CommandEmpty"
250
+ })
251
+ );
252
+ }
253
+ function CommandGroup(_a) {
254
+ var _b = _a, {
255
+ className,
256
+ heading
257
+ } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, [
258
+ "className",
259
+ "heading"
260
+ ]);
261
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
262
+ _optuiprimitives.CommandGroup,
263
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
264
+ heading: heading != null ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "text-text-tertiary px-2 py-1.5 text-xs font-medium", children: heading }) : void 0,
265
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "py-1", className)
266
+ }, props), {
267
+ "data-opt-id": "JPK1Y",
268
+ "data-opt-slug": "command.CommandGroup"
269
+ })
270
+ );
271
+ }
272
+ function CommandSeparator(_a) {
273
+ var _b = _a, {
274
+ className
275
+ } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, [
276
+ "className"
277
+ ]);
278
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
279
+ _optuiprimitives.CommandSeparator,
280
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
281
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "bg-border-subtle -mx-1 my-1 h-px", className)
282
+ }, props), {
283
+ "data-opt-id": "10P0E",
284
+ "data-opt-slug": "command.CommandSeparator"
285
+ })
286
+ );
287
+ }
288
+ function CommandItem(_a) {
289
+ var _b = _a, { className } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, ["className"]);
290
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
291
+ _optuiprimitives.CommandItem,
292
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
293
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
294
+ "text-text-primary flex cursor-pointer items-center gap-2 rounded-md px-2 py-2 text-sm select-none",
295
+ "data-[active-item]:bg-accent data-[active-item]:text-accent-fg",
296
+ "data-[disabled]:pointer-events-none data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
297
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
298
+ className
299
+ )
300
+ }, props), {
301
+ "data-opt-id": "K674W",
302
+ "data-opt-slug": "command.CommandItem"
303
+ })
304
+ );
305
+ }
306
+ function CommandShortcut(_a) {
307
+ var _b = _a, {
308
+ className
309
+ } = _b, props = _chunkONE3C5RVcjs.__objRest.call(void 0, _b, [
310
+ "className"
311
+ ]);
312
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
313
+ "span",
314
+ _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
315
+ "data-slot": "command-shortcut",
316
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
317
+ "text-text-tertiary ml-auto text-xs tracking-widest",
318
+ "data-[active-item]:text-accent-fg/80",
319
+ className
320
+ )
321
+ }, props), {
322
+ "data-opt-id": "75CQK",
323
+ "data-opt-slug": "command.CommandShortcut"
324
+ })
325
+ );
326
+ }
327
+
328
+ // src/shells/command-palette.tsx
329
+ var _react = require('react'); var React = _interopRequireWildcard(_react);
330
+
331
+ var DEFAULT_LABELS = {
332
+ title: "Command Palette",
333
+ description: "\uAC80\uC0C9 \uD6C4 Enter \uB610\uB294 \uD074\uB9AD\uC73C\uB85C \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uC138\uC694.",
334
+ input: "\uBA85\uB839\uC5B4 \uAC80\uC0C9",
335
+ placeholder: "\uBA85\uB839\uC5B4\uB97C \uAC80\uC0C9\uD558\uC138\uC694...",
336
+ list: "\uBA85\uB839\uC5B4 \uBAA9\uB85D",
337
+ empty: "\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
338
+ escape: "ESC"
339
+ };
340
+ function CommandPalette({
341
+ commands,
342
+ open,
343
+ onOpenChange,
344
+ onSelect,
345
+ inline = false,
346
+ labels,
347
+ footer,
348
+ empty,
349
+ inputTrailing,
350
+ className
351
+ }) {
352
+ const resolvedLabels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, DEFAULT_LABELS), labels);
353
+ const hasCommands = commands.length > 0;
354
+ const grouped = _react.useMemo.call(void 0, () => {
355
+ var _a;
356
+ const map = /* @__PURE__ */ new Map();
357
+ for (const cmd of commands) {
358
+ const list = (_a = map.get(cmd.group)) != null ? _a : [];
359
+ list.push(cmd);
360
+ map.set(cmd.group, list);
361
+ }
362
+ return map;
363
+ }, [commands]);
364
+ const handleSelect = (cmdId) => {
365
+ const cmd = commands.find((c) => c.id === cmdId);
366
+ if (!cmd) return;
367
+ onSelect == null ? void 0 : onSelect(cmd);
368
+ onOpenChange(false);
369
+ };
370
+ const handleInputKeyDown = (e) => {
371
+ if (e.key === "Escape" && !inline) {
372
+ e.preventDefault();
373
+ onOpenChange(false);
374
+ }
375
+ };
376
+ const body = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
377
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
378
+ CommandInput,
379
+ {
380
+ "aria-label": resolvedLabels.input,
381
+ placeholder: resolvedLabels.placeholder,
382
+ onKeyDown: handleInputKeyDown,
383
+ trailing: inputTrailing != null ? inputTrailing : !inline ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Kbd, { children: resolvedLabels.escape }) : void 0
384
+ }
385
+ ),
386
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, CommandList, { "aria-label": resolvedLabels.list, children: [
387
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommandEmpty, { children: empty != null ? empty : resolvedLabels.empty }),
388
+ hasCommands ? Array.from(grouped.entries()).map(([group, items]) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommandGroup, { heading: group, children: items.map((cmd) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
389
+ CommandItem,
390
+ {
391
+ value: cmd.id,
392
+ keywords: [
393
+ cmd.label,
394
+ cmd.group,
395
+ ...cmd.shortcut ? [cmd.shortcut] : []
396
+ ],
397
+ onSelect: handleSelect,
398
+ children: [
399
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: cmd.label }),
400
+ cmd.shortcut && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommandShortcut, { children: cmd.shortcut })
401
+ ]
402
+ },
403
+ cmd.id
404
+ )) }, group)) : null
405
+ ] }),
406
+ footer
407
+ ] });
408
+ if (inline) {
409
+ if (!open) return null;
410
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
411
+ Command,
412
+ {
413
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
414
+ "border-border bg-surface w-full max-w-lg border shadow-lg",
415
+ className
416
+ ),
417
+ "data-opt-id": "ATTF5",
418
+ "data-opt-slug": "command-palette.CommandPalette",
419
+ children: body
420
+ }
421
+ );
422
+ }
423
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
424
+ CommandDialog,
425
+ {
426
+ open,
427
+ onOpenChange,
428
+ title: resolvedLabels.title,
429
+ description: resolvedLabels.description,
430
+ className,
431
+ "data-opt-id": "ATTF5",
432
+ "data-opt-slug": "command-palette.CommandPalette",
433
+ children: body
434
+ }
435
+ );
436
+ }
437
+
438
+ // src/shells/command-palette-trigger.tsx
439
+
440
+
441
+ function CommandPaletteTrigger({
442
+ commands,
443
+ onSelect,
444
+ labels
445
+ }) {
446
+ if (commands.length === 0) return null;
447
+ const [open, setOpen] = _react.useState.call(void 0, false);
448
+ const handleKeyDown = _react.useCallback.call(void 0, (e) => {
449
+ if ((e.metaKey || e.ctrlKey) && e.key === "k") {
450
+ e.preventDefault();
451
+ setOpen(true);
452
+ }
453
+ }, []);
454
+ _react.useEffect.call(void 0, () => {
455
+ document.addEventListener("keydown", handleKeyDown);
456
+ return () => document.removeEventListener("keydown", handleKeyDown);
457
+ }, [handleKeyDown]);
458
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
459
+ CommandPalette,
460
+ {
461
+ commands,
462
+ open,
463
+ onOpenChange: setOpen,
464
+ onSelect,
465
+ labels,
466
+ "data-opt-id": "4FCDB",
467
+ "data-opt-slug": "command-palette-trigger.CommandPaletteTrigger"
468
+ }
469
+ );
470
+ }
471
+
472
+ // src/shells/dashboard-grid.tsx
473
+
474
+ var defaultLabels = {
475
+ ariaLabel: "\uB300\uC2DC\uBCF4\uB4DC \uD1B5\uACC4"
476
+ };
477
+ var MIN_DASHBOARD_COLUMNS = 1;
478
+ var MAX_DASHBOARD_COLUMNS = 12;
479
+ function normalizeDashboardColumns(columns) {
480
+ if (!Number.isFinite(columns)) return MIN_DASHBOARD_COLUMNS;
481
+ return Math.min(
482
+ MAX_DASHBOARD_COLUMNS,
483
+ Math.max(MIN_DASHBOARD_COLUMNS, Math.floor(columns))
484
+ );
485
+ }
486
+ function DashboardGrid({
487
+ stats,
488
+ columns = 3,
489
+ labels: customLabels
490
+ }) {
491
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels), customLabels);
492
+ const columnCount = normalizeDashboardColumns(columns);
493
+ const rowStyle = {
494
+ "--opt-dashboard-grid-columns": `repeat(${columnCount}, minmax(0, 1fr))`
495
+ };
496
+ const rows = [];
497
+ for (let i = 0; i < stats.length; i += columnCount) {
498
+ rows.push(stats.slice(i, i + columnCount));
499
+ }
500
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
501
+ _chunkAFF2HPE5cjs.CompositeProvider,
502
+ {
503
+ focusLoop: true,
504
+ focusWrap: true,
505
+ "data-opt-id": "BM7NA",
506
+ "data-opt-slug": "dashboard-grid.DashboardGrid",
507
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
508
+ _chunkAFF2HPE5cjs.Composite,
509
+ {
510
+ role: "grid",
511
+ "aria-label": labels.ariaLabel,
512
+ className: "gap-group flex flex-col",
513
+ children: rows.map((row, ri) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
514
+ _chunkAFF2HPE5cjs.CompositeRow,
515
+ {
516
+ className: "gap-group grid grid-cols-1 sm:[grid-template-columns:var(--opt-dashboard-grid-columns)]",
517
+ style: rowStyle,
518
+ children: row.map((stat) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
519
+ _chunkAFF2HPE5cjs.CompositeItem,
520
+ {
521
+ className: "data-[active-item]:ring-ring data-[active-item]:ring-offset-ring-offset data-[focus-visible]:ring-ring data-[focus-visible]:ring-offset-ring-offset rounded-xl outline-none data-[active-item]:ring-2 data-[active-item]:ring-offset-2 data-[focus-visible]:ring-2 data-[focus-visible]:ring-offset-2",
522
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { role: "gridcell" }),
523
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.StatCard, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, stat))
524
+ },
525
+ stat.id
526
+ ))
527
+ },
528
+ ri
529
+ ))
530
+ }
531
+ )
532
+ }
533
+ );
534
+ }
535
+
536
+ // src/shells/search-combobox.tsx
537
+ var _matchsorter = require('match-sorter');
538
+
539
+
540
+ var defaultLabels2 = {
541
+ noResults: "\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
542
+ loading: "Loading\u2026"
543
+ };
544
+ function SearchCombobox({
545
+ items,
546
+ placeholder = "\uAC80\uC0C9...",
547
+ label = "\uAC80\uC0C9",
548
+ onSelect,
549
+ labels: customLabels,
550
+ async: isAsync = false,
551
+ onSearch,
552
+ debounceMs = 300
553
+ }) {
554
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels2), customLabels);
555
+ const inputId = _react.useId.call(void 0, );
556
+ const [query, setQuery] = _react.useState.call(void 0, "");
557
+ const [asyncResults, setAsyncResults] = _react.useState.call(void 0, []);
558
+ const [loading, setLoading] = _react.useState.call(void 0, false);
559
+ const timerRef = _react.useRef.call(void 0, void 0);
560
+ const searchGenerationRef = _react.useRef.call(void 0, 0);
561
+ const syncMatches = _react.useMemo.call(void 0, () => {
562
+ if (isAsync) return [];
563
+ if (!query) return items;
564
+ return _matchsorter.matchSorter.call(void 0, items, query);
565
+ }, [query, items, isAsync]);
566
+ const handleInput = (event) => {
567
+ searchGenerationRef.current += 1;
568
+ setQuery(event.currentTarget.value);
569
+ };
570
+ const handleValueChange = (item) => {
571
+ searchGenerationRef.current += 1;
572
+ setQuery(item);
573
+ onSelect == null ? void 0 : onSelect(item);
574
+ };
575
+ _react.useEffect.call(void 0, () => {
576
+ const generation = ++searchGenerationRef.current;
577
+ if (timerRef.current) clearTimeout(timerRef.current);
578
+ if (!isAsync || !onSearch) {
579
+ setLoading(false);
580
+ return;
581
+ }
582
+ if (!query) {
583
+ setAsyncResults([]);
584
+ setLoading(false);
585
+ return;
586
+ }
587
+ setLoading(true);
588
+ timerRef.current = setTimeout(async () => {
589
+ try {
590
+ const results = await onSearch(query);
591
+ if (searchGenerationRef.current !== generation) {
592
+ return;
593
+ }
594
+ setAsyncResults(results);
595
+ } finally {
596
+ if (searchGenerationRef.current === generation) {
597
+ setLoading(false);
598
+ }
599
+ }
600
+ }, debounceMs);
601
+ return () => {
602
+ if (timerRef.current) clearTimeout(timerRef.current);
603
+ };
604
+ }, [query, isAsync, onSearch, debounceMs]);
605
+ const matches = isAsync ? asyncResults : syncMatches;
606
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
607
+ "div",
608
+ {
609
+ className: "gap-element flex flex-col",
610
+ "data-opt-id": "KH4TQ",
611
+ "data-opt-slug": "search-combobox.SearchCombobox",
612
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.ComboboxRoot, { onValueChange: handleValueChange, children: [
613
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { htmlFor: inputId, className: _chunkAFF2HPE5cjs.OPT_TEXT_LABEL, children: label }),
614
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
615
+ _chunkAFF2HPE5cjs.ComboboxInput,
616
+ {
617
+ id: inputId,
618
+ placeholder,
619
+ className: "max-w-xs",
620
+ "aria-busy": loading || void 0,
621
+ onInput: handleInput
622
+ }
623
+ ),
624
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.ComboboxPopover, { className: "max-w-xs", children: isAsync && loading ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
625
+ "div",
626
+ {
627
+ className: "text-text-secondary gap-element flex items-center px-3 py-2 text-sm",
628
+ role: "status",
629
+ "aria-live": "polite",
630
+ "aria-busy": "true",
631
+ children: [
632
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Spinner, { size: "sm", "aria-hidden": "true" }),
633
+ labels.loading
634
+ ]
635
+ }
636
+ ) : matches.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.ComboboxEmpty, { children: labels.noResults }) : matches.map((item) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.ComboboxItem, { value: item, children: item }, item)) })
637
+ ] })
638
+ }
639
+ );
640
+ }
641
+
642
+ // src/shells/status-select.tsx
643
+
644
+
645
+ var defaultLabels3 = {
646
+ selectLabel: "\uC0C1\uD0DC",
647
+ emptyMessage: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uC0C1\uD0DC \uC635\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."
648
+ };
649
+ function StatusSelect({
650
+ options,
651
+ value: controlledValue,
652
+ onChange,
653
+ label,
654
+ labels: customLabels
655
+ }) {
656
+ var _a, _b;
657
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels3), customLabels);
658
+ const resolvedLabel = label != null ? label : labels.selectLabel;
659
+ const [internalValue, setInternalValue] = _react.useState.call(void 0, (_b = (_a = options[0]) == null ? void 0 : _a.value) != null ? _b : "");
660
+ const value = controlledValue != null ? controlledValue : internalValue;
661
+ const selected = options.find((s) => s.value === value);
662
+ if (options.length === 0) {
663
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
664
+ "div",
665
+ {
666
+ className: "gap-element flex flex-col",
667
+ "data-opt-id": "R46E6",
668
+ "data-opt-slug": "status-select.StatusSelect",
669
+ children: [
670
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: _chunkAFF2HPE5cjs.OPT_TEXT_LABEL, children: resolvedLabel }),
671
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-text-tertiary text-sm", children: labels.emptyMessage })
672
+ ]
673
+ }
674
+ );
675
+ }
676
+ const handleChange = (v) => {
677
+ var _a2;
678
+ const next = Array.isArray(v) ? (_a2 = v[0]) != null ? _a2 : "" : v;
679
+ if (onChange) onChange(next);
680
+ else setInternalValue(next);
681
+ };
682
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
683
+ "div",
684
+ {
685
+ className: "gap-element flex flex-col",
686
+ "data-opt-id": "R46E6",
687
+ "data-opt-slug": "status-select.StatusSelect",
688
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.SelectRoot, { value, onValueChange: handleChange, children: [
689
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.SelectLabel, { className: _chunkAFF2HPE5cjs.OPT_TEXT_LABEL, children: resolvedLabel }),
690
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
691
+ _chunkAFF2HPE5cjs.SelectTrigger,
692
+ {
693
+ className: `${_chunkAFF2HPE5cjs.OPT_INPUT} max-w-xs items-center justify-between ${_chunkAFF2HPE5cjs.OPT_FOCUS}`,
694
+ children: [
695
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "gap-element flex items-center", children: [
696
+ (selected == null ? void 0 : selected.color) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `h-2 w-2 rounded-full ${selected.color}` }),
697
+ selected == null ? void 0 : selected.label
698
+ ] }),
699
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
700
+ "svg",
701
+ {
702
+ className: "text-text-tertiary h-4 w-4",
703
+ fill: "none",
704
+ viewBox: "0 0 24 24",
705
+ stroke: "currentColor",
706
+ strokeWidth: 2,
707
+ "aria-hidden": "true",
708
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
709
+ "path",
710
+ {
711
+ strokeLinecap: "round",
712
+ strokeLinejoin: "round",
713
+ d: "m19.5 8.25-7.5 7.5-7.5-7.5"
714
+ }
715
+ )
716
+ }
717
+ )
718
+ ]
719
+ }
720
+ ),
721
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
722
+ _chunkAFF2HPE5cjs.SelectPopover,
723
+ {
724
+ className: `${_chunkAFF2HPE5cjs.OPT_SURFACE_POPOVER} ${_chunkAFF2HPE5cjs.OPT_ANIMATE_ENTER_EXIT} max-w-xs`,
725
+ children: options.map((option) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.SelectItem, { value: option.value, children: [
726
+ option.color && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `h-2 w-2 rounded-full ${option.color}` }),
727
+ option.label
728
+ ] }, option.value))
729
+ }
730
+ )
731
+ ] })
732
+ }
733
+ );
734
+ }
735
+
736
+ // src/shells/app-menubar.tsx
737
+
738
+ var defaultLabels4 = {
739
+ ariaLabel: "Application menu"
740
+ };
741
+ function MenuSection({ menu }) {
742
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.MenuRoot, { children: [
743
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.MenuTrigger, { children: [
744
+ menu.label,
745
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.MenuButtonArrow, {})
746
+ ] }),
747
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.MenuPopover, { children: menu.items.map((item, i) => {
748
+ var _a, _b, _c, _d;
749
+ if (item.type === "separator") {
750
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.MenuSeparator, {}, `sep-${i}`);
751
+ }
752
+ if (item.type === "checkbox") {
753
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
754
+ _chunkAFF2HPE5cjs.MenuItemCheckbox,
755
+ {
756
+ name: (_a = item.name) != null ? _a : item.id,
757
+ value: (_b = item.value) != null ? _b : item.id,
758
+ checked: item.checked,
759
+ onChange: item.onChange,
760
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "gap-element flex items-center", children: [
761
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-4 text-center", children: item.checked ? "\u2713" : "" }),
762
+ item.label
763
+ ] })
764
+ },
765
+ item.id
766
+ );
767
+ }
768
+ if (item.type === "radio") {
769
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
770
+ _chunkAFF2HPE5cjs.MenuItemRadio,
771
+ {
772
+ name: (_c = item.name) != null ? _c : "",
773
+ value: (_d = item.value) != null ? _d : "",
774
+ checked: item.checked,
775
+ onChange: item.onChange,
776
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "gap-element flex items-center", children: [
777
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "w-4 text-center", children: item.checked ? "\u25CF" : "" }),
778
+ item.label
779
+ ] })
780
+ },
781
+ item.id
782
+ );
783
+ }
784
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.MenuItem, { onClick: item.onClick, children: [
785
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: item.label }),
786
+ item.shortcut && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Kbd, { children: item.shortcut })
787
+ ] }, item.id);
788
+ }) })
789
+ ] });
790
+ }
791
+ function AppMenubar({ menus, labels: customLabels }) {
792
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels4), customLabels);
793
+ if (menus.length === 0) return null;
794
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.MenubarRoot, { "data-opt-id": "BGKHW", "data-opt-slug": "app-menubar.AppMenubar", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.MenubarContainer, { "aria-label": labels.ariaLabel, children: menus.map((menu) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, MenuSection, { menu }, menu.id)) }) });
795
+ }
796
+ AppMenubar.displayName = "AppMenubar";
797
+
798
+ // src/shells/sidebar-nav.tsx
799
+ var _link = require('next/link'); var _link2 = _interopRequireDefault(_link);
800
+ var _navigation = require('next/navigation');
801
+
802
+
803
+ var NAV_ID_PREFIX = "sidebar-nav-";
804
+ function domId(id) {
805
+ return `${NAV_ID_PREFIX}${id}`;
806
+ }
807
+ var sectionStyles = {
808
+ // 한글 키
809
+ \uC2DC\uC791\uD558\uAE30: "text-accent",
810
+ "\uD575\uC2EC \uAC1C\uB150": "text-info-fg",
811
+ "\uAD6C\uCD95\xB7\uC6B4\uC601": "text-success-fg",
812
+ \uB3C4\uAD6C: "text-warning-fg",
813
+ DataGrid: "text-accent",
814
+ "\uCEF4\uD3EC\uB10C\uD2B8 \xB7 Core": "text-accent",
815
+ "\uCEF4\uD3EC\uB10C\uD2B8 \xB7 Visuals": "text-success-fg",
816
+ "\uCEF4\uD3EC\uB10C\uD2B8 \xB7 Shells": "text-warning-fg",
817
+ "\uCEF4\uD3EC\uB10C\uD2B8 \xB7 Surfaces": "text-info-fg",
818
+ "\uAE30\uBCF8 \uCEF4\uD3EC\uB10C\uD2B8": "text-accent",
819
+ "\uBE14\uB85D \uCEF4\uD3EC\uB10C\uD2B8": "text-info-fg",
820
+ "\uC870\uD569 \uCEF4\uD3EC\uB10C\uD2B8": "text-warning-fg",
821
+ \uD15C\uD50C\uB9BF: "text-text-tertiary",
822
+ \uB9B4\uB9AC\uC988: "text-text-tertiary",
823
+ // 영문 키 (하위 호환)
824
+ Primitives: "text-accent",
825
+ Blocks: "text-info-fg",
826
+ Compositions: "text-warning-fg",
827
+ Templates: "text-text-tertiary"
828
+ };
829
+ var defaultSectionStyle = "text-text-secondary";
830
+ var defaultLabels5 = {
831
+ ariaLabel: "\uBB38\uC11C \uB124\uBE44\uAC8C\uC774\uC158"
832
+ };
833
+ function SidebarNav({ items, labels: customLabels }) {
834
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels5), customLabels);
835
+ if (items.length === 0) {
836
+ return null;
837
+ }
838
+ const pathname = _navigation.usePathname.call(void 0, );
839
+ const activeItem = items.find((item) => item.href === pathname);
840
+ const [activeId, setActiveId] = _react.useState.call(void 0,
841
+ activeItem ? domId(activeItem.id) : void 0
842
+ );
843
+ _react.useEffect.call(void 0, () => {
844
+ const match = items.find((item) => item.href === pathname);
845
+ if (match) {
846
+ setActiveId(domId(match.id));
847
+ }
848
+ }, [pathname, items]);
849
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
850
+ _chunkAFF2HPE5cjs.CompositeProvider,
851
+ {
852
+ focusLoop: true,
853
+ orientation: "vertical",
854
+ activeId,
855
+ onActiveIdChange: setActiveId,
856
+ "data-opt-id": "1FZNH",
857
+ "data-opt-slug": "sidebar-nav.SidebarNav",
858
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
859
+ _chunkAFF2HPE5cjs.Composite,
860
+ {
861
+ role: "navigation",
862
+ "aria-label": labels.ariaLabel,
863
+ className: "flex flex-col",
864
+ children: items.map((item, index) => {
865
+ var _a, _b;
866
+ const isSelected = pathname === item.href;
867
+ const isFirstItem = index === 0;
868
+ const sectionTextStyle = item.sectionLabel ? (_a = sectionStyles[item.sectionLabel]) != null ? _a : defaultSectionStyle : defaultSectionStyle;
869
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
870
+ item.separator && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: _chunkAFF2HPE5cjs.cn.call(void 0, "mb-2 pt-2", !isFirstItem && "mt-7"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
871
+ "span",
872
+ {
873
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
874
+ "px-2 text-[11px] font-semibold tracking-wider uppercase",
875
+ sectionTextStyle
876
+ ),
877
+ children: (_b = item.sectionLabel) != null ? _b : ""
878
+ }
879
+ ) }),
880
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
881
+ _chunkAFF2HPE5cjs.CompositeItem,
882
+ {
883
+ id: domId(item.id),
884
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
885
+ _link2.default,
886
+ {
887
+ href: item.href,
888
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
889
+ // Base styles
890
+ "group relative block rounded-md px-2 py-1.5 text-[13px] leading-snug outline-none",
891
+ "transition-all duration-150",
892
+ // Default state
893
+ !isSelected && [
894
+ "text-text-secondary",
895
+ // Hover
896
+ "hover:bg-bg-subtle hover:text-text-primary"
897
+ ],
898
+ // Selected (current page)
899
+ isSelected && [
900
+ "bg-bg-subtle text-text-primary font-medium"
901
+ ],
902
+ // Keyboard navigation focus (roving tabindex active)
903
+ "data-[active-item]:bg-accent-subtle data-[active-item]:text-accent",
904
+ // Focus visible (actual keyboard focus indicator)
905
+ "data-[focus-visible]:ring-ring data-[focus-visible]:ring-2",
906
+ "data-[focus-visible]:ring-offset-ring-offset data-[focus-visible]:ring-offset-2",
907
+ // Combined: selected + keyboard active
908
+ isSelected && [
909
+ "data-[active-item]:bg-accent-subtle data-[active-item]:text-accent"
910
+ ]
911
+ )
912
+ }
913
+ ),
914
+ children: [
915
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
916
+ "span",
917
+ {
918
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
919
+ "absolute top-1/2 left-0 h-4 w-0.5 -translate-y-1/2 rounded-full transition-all duration-150",
920
+ // Selected: solid accent bar
921
+ isSelected && "bg-accent",
922
+ // Keyboard active (not selected): lighter bar
923
+ !isSelected && "group-data-[active-item]:bg-accent bg-transparent",
924
+ // Focus visible: ensure bar is visible
925
+ "group-data-[focus-visible]:bg-accent"
926
+ )
927
+ }
928
+ ),
929
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "pl-2", children: item.label })
930
+ ]
931
+ }
932
+ )
933
+ ] }, item.id);
934
+ })
935
+ }
936
+ )
937
+ }
938
+ );
939
+ }
940
+
941
+ // src/shells/editor-toolbar.tsx
942
+
943
+ var defaultLabels6 = {
944
+ ariaLabel: "\uD14D\uC2A4\uD2B8 \uD3B8\uC9D1\uAE30 \uD234\uBC14"
945
+ };
946
+ function ToolbarButtonWithTooltip({
947
+ button,
948
+ active,
949
+ onAction
950
+ }) {
951
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.TooltipProvider, { children: [
952
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.TooltipAnchor, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
953
+ _chunkAFF2HPE5cjs.ToolbarButton,
954
+ {
955
+ className: `text-text-primary data-[active-item]:bg-bg-subtle data-[focus-visible]:ring-ring rounded-md p-2 transition-colors outline-none data-[focus-visible]:ring-2 ${active ? "bg-bg-muted" : "hover:bg-bg-subtle"}`,
956
+ onClick: () => onAction == null ? void 0 : onAction(button.id),
957
+ children: button.icon
958
+ }
959
+ ) }),
960
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Tooltip, { children: button.label })
961
+ ] });
962
+ }
963
+ function EditorToolbar({
964
+ buttons,
965
+ onAction,
966
+ activeButtons = [],
967
+ labels: customLabels
968
+ }) {
969
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels6), customLabels);
970
+ const groups = [];
971
+ let current = [];
972
+ for (const btn of buttons) {
973
+ if (btn.separator) {
974
+ groups.push(current);
975
+ current = [];
976
+ }
977
+ current.push(btn);
978
+ }
979
+ if (current.length) groups.push(current);
980
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
981
+ _chunkAFF2HPE5cjs.ToolbarRoot,
982
+ {
983
+ "data-opt-id": "Z73K6",
984
+ "data-opt-slug": "editor-toolbar.EditorToolbar",
985
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.ToolbarContainer, { "aria-label": labels.ariaLabel, children: groups.map((group, gi) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "contents", children: [
986
+ gi > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.ToolbarSeparator, {}),
987
+ group.map((item) => {
988
+ if (item === "separator") return null;
989
+ const btn = item;
990
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
991
+ ToolbarButtonWithTooltip,
992
+ {
993
+ button: btn,
994
+ active: activeButtons.includes(btn.id),
995
+ onAction
996
+ },
997
+ btn.id
998
+ );
999
+ })
1000
+ ] }, gi)) })
1001
+ }
1002
+ );
1003
+ }
1004
+
1005
+ // src/shells/content-tabs.tsx
1006
+
1007
+
1008
+ var defaultLabels7 = {
1009
+ ariaLabel: "\uCF58\uD150\uCE20 \uD0ED",
1010
+ emptyMessage: "\uD45C\uC2DC\uD560 \uD0ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."
1011
+ };
1012
+ function ContentTabs({
1013
+ tabs,
1014
+ defaultTabId,
1015
+ labels: customLabels
1016
+ }) {
1017
+ var _a, _b;
1018
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels7), customLabels);
1019
+ if (tabs.length === 0) {
1020
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1021
+ "div",
1022
+ {
1023
+ className: "text-text-secondary text-sm",
1024
+ "data-opt-id": "9W97K",
1025
+ "data-opt-slug": "content-tabs.ContentTabs",
1026
+ children: labels.emptyMessage
1027
+ }
1028
+ );
1029
+ }
1030
+ const [selectedTabId, setSelectedTabId] = _react.useState.call(void 0,
1031
+ defaultTabId != null ? defaultTabId : (_a = tabs[0]) == null ? void 0 : _a.id
1032
+ );
1033
+ const handleSelectedTabId = (nextId) => {
1034
+ var _a2;
1035
+ setSelectedTabId(nextId != null ? nextId : (_a2 = tabs[0]) == null ? void 0 : _a2.id);
1036
+ };
1037
+ const activeTab = (_b = tabs.find((tab) => tab.id === selectedTabId)) != null ? _b : tabs[0];
1038
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1039
+ _chunkAFF2HPE5cjs.TabsRoot,
1040
+ {
1041
+ selectedId: selectedTabId,
1042
+ onSelectedIdChange: handleSelectedTabId,
1043
+ "data-opt-id": "9W97K",
1044
+ "data-opt-slug": "content-tabs.ContentTabs",
1045
+ children: [
1046
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.TabList, { "aria-label": labels.ariaLabel, children: tabs.map((tab) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Tab, { id: tab.id, children: tab.label }, tab.id)) }),
1047
+ activeTab && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.TabPanel, { tabId: activeTab.id, children: activeTab.content })
1048
+ ]
1049
+ }
1050
+ );
1051
+ }
1052
+
1053
+ // src/shells/faq-accordion.tsx
1054
+
1055
+ var defaultLabels8 = {
1056
+ ariaLabel: "\uC790\uC8FC \uBB3B\uB294 \uC9C8\uBB38",
1057
+ emptyMessage: "\uB4F1\uB85D\uB41C FAQ\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
1058
+ };
1059
+ function FaqAccordion({
1060
+ items,
1061
+ labels: customLabels
1062
+ }) {
1063
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels8), customLabels);
1064
+ if (items.length === 0) {
1065
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1066
+ "div",
1067
+ {
1068
+ className: "text-text-secondary text-sm",
1069
+ "data-opt-id": "QRBHV",
1070
+ "data-opt-slug": "faq-accordion.FaqAccordion",
1071
+ children: labels.emptyMessage
1072
+ }
1073
+ );
1074
+ }
1075
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1076
+ _chunkAFF2HPE5cjs.CompositeProvider,
1077
+ {
1078
+ focusLoop: true,
1079
+ orientation: "vertical",
1080
+ "data-opt-id": "QRBHV",
1081
+ "data-opt-slug": "faq-accordion.FaqAccordion",
1082
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1083
+ _chunkAFF2HPE5cjs.Composite,
1084
+ {
1085
+ role: "region",
1086
+ "aria-label": labels.ariaLabel,
1087
+ className: "divide-border-subtle border-border divide-y rounded-lg border",
1088
+ children: items.map((faq) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.DisclosureRoot, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1089
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.CompositeItem, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.DisclosureTrigger, {}), children: [
1090
+ faq.question,
1091
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1092
+ "svg",
1093
+ {
1094
+ className: "text-text-tertiary h-4 w-4 shrink-0 transition-transform [[data-open]>&]:rotate-180",
1095
+ fill: "none",
1096
+ viewBox: "0 0 24 24",
1097
+ stroke: "currentColor",
1098
+ strokeWidth: 2,
1099
+ "aria-hidden": "true",
1100
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1101
+ "path",
1102
+ {
1103
+ strokeLinecap: "round",
1104
+ strokeLinejoin: "round",
1105
+ d: "m19.5 8.25-7.5 7.5-7.5-7.5"
1106
+ }
1107
+ )
1108
+ }
1109
+ )
1110
+ ] }),
1111
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.DisclosureContent, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-text-secondary px-4 pt-2 pb-4 text-sm", children: faq.answer }) })
1112
+ ] }) }, faq.id))
1113
+ }
1114
+ )
1115
+ }
1116
+ );
1117
+ }
1118
+
1119
+ // src/shells/settings-form.tsx
1120
+
1121
+
1122
+ var defaultLabels9 = {
1123
+ formAriaLabel: "\uC124\uC815 \uD3FC",
1124
+ submitButton: "\uC800\uC7A5",
1125
+ successMessage: "\uC124\uC815\uC774 \uC800\uC7A5\uB418\uC5C8\uC2B5\uB2C8\uB2E4."
1126
+ };
1127
+ function SettingsForm({
1128
+ fields,
1129
+ onSubmit,
1130
+ labels: customLabels
1131
+ }) {
1132
+ var _a;
1133
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels9), customLabels);
1134
+ const [submitted, setSubmitted] = _react.useState.call(void 0, false);
1135
+ if (fields.length === 0) {
1136
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1137
+ _chunkAFF2HPE5cjs.EmptyState,
1138
+ {
1139
+ title: "\uC124\uC815 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
1140
+ description: "\uD45C\uC2DC\uD560 \uC124\uC815 \uD544\uB4DC\uB97C \uCD94\uAC00\uD558\uBA74 \uC774 \uD3FC\uC774 \uB80C\uB354\uB9C1\uB429\uB2C8\uB2E4.",
1141
+ "data-opt-id": "9TEEJ",
1142
+ "data-opt-slug": "settings-form.SettingsForm"
1143
+ }
1144
+ );
1145
+ }
1146
+ const defaultValues = {};
1147
+ for (const field of fields) {
1148
+ defaultValues[field.name] = (_a = field.defaultValue) != null ? _a : field.type === "switch" || field.type === "checkbox" ? false : field.type === "tags" ? [] : "";
1149
+ }
1150
+ const form = _chunkAFF2HPE5cjs.useFormStore.call(void 0, {
1151
+ defaultValues,
1152
+ validate: (values) => {
1153
+ var _a2;
1154
+ const errors = {};
1155
+ for (const field of fields) {
1156
+ if (field.required) {
1157
+ const value = values[field.name];
1158
+ if (!value || typeof value === "string" && !value.trim()) {
1159
+ errors[field.name] = (_a2 = field.requiredMessage) != null ? _a2 : `${field.label}\uC744(\uB97C) \uC785\uB825\uD574\uC8FC\uC138\uC694.`;
1160
+ }
1161
+ }
1162
+ if (field.validate) {
1163
+ const value = values[field.name];
1164
+ const error = field.validate(value);
1165
+ if (error) {
1166
+ errors[field.name] = error;
1167
+ }
1168
+ }
1169
+ }
1170
+ return errors;
1171
+ },
1172
+ onSubmit: (values) => {
1173
+ setSubmitted(true);
1174
+ onSubmit == null ? void 0 : onSubmit(values);
1175
+ }
1176
+ });
1177
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1178
+ "div",
1179
+ {
1180
+ className: "gap-group flex flex-col",
1181
+ "data-opt-id": "9TEEJ",
1182
+ "data-opt-slug": "settings-form.SettingsForm",
1183
+ children: [
1184
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.FormRoot, { store: form, "aria-label": labels.formAriaLabel, children: [
1185
+ fields.map((field) => {
1186
+ var _a2, _b, _c, _d, _e;
1187
+ if (field.visible !== void 0) {
1188
+ const currentValues = form.getValues();
1189
+ const isVisible = typeof field.visible === "function" ? field.visible(currentValues) : field.visible;
1190
+ if (!isVisible) return null;
1191
+ }
1192
+ if (field.type === "tags") {
1193
+ const rawValue = form.getValue(field.name);
1194
+ const tags = Array.isArray(rawValue) ? rawValue : [];
1195
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex flex-col", children: [
1196
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormLabel, { name: field.name, children: field.label }),
1197
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1198
+ _chunkAFF2HPE5cjs.TagInput,
1199
+ {
1200
+ value: tags,
1201
+ onChange: (next) => form.setValue(field.name, next),
1202
+ placeholder: field.placeholder
1203
+ }
1204
+ ),
1205
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormError, { name: field.name })
1206
+ ] }, field.name);
1207
+ }
1208
+ if (field.type === "radio") {
1209
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "fieldset", { className: "gap-element flex flex-col", children: [
1210
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "legend", { className: "text-text-primary text-sm font-medium", children: field.label }),
1211
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormRadioGroup, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "gap-group flex", children: (_a2 = field.options) == null ? void 0 : _a2.map((option) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1212
+ "label",
1213
+ {
1214
+ className: "text-text-primary gap-element flex items-center text-sm",
1215
+ children: [
1216
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormRadio, { name: field.name, value: option.value }),
1217
+ option.label
1218
+ ]
1219
+ },
1220
+ option.value
1221
+ )) }) }),
1222
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormError, { name: field.name })
1223
+ ] }, field.name);
1224
+ }
1225
+ if (field.type === "checkbox") {
1226
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex flex-col", children: [
1227
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "text-text-primary gap-element flex items-center text-sm", children: [
1228
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormCheckbox, { name: field.name }),
1229
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: field.label })
1230
+ ] }),
1231
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormError, { name: field.name })
1232
+ ] }, field.name);
1233
+ }
1234
+ if (field.type === "textarea") {
1235
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex flex-col", children: [
1236
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormLabel, { name: field.name, children: field.label }),
1237
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1238
+ _chunkAFF2HPE5cjs.FormTextarea,
1239
+ {
1240
+ name: field.name,
1241
+ placeholder: field.placeholder,
1242
+ rows: (_b = field.rows) != null ? _b : 4,
1243
+ resize: (_c = field.resize) != null ? _c : "vertical",
1244
+ className: field.font === "mono" ? "font-mono text-sm" : void 0
1245
+ }
1246
+ ),
1247
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormError, { name: field.name })
1248
+ ] }, field.name);
1249
+ }
1250
+ if (field.type === "select") {
1251
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex flex-col", children: [
1252
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormLabel, { name: field.name, children: field.label }),
1253
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormSelect, { name: field.name, placeholder: field.placeholder, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormSelectPopover, { children: (_d = field.options) == null ? void 0 : _d.map((option) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormSelectItem, { value: option.value, children: option.label }, option.value)) }) }),
1254
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormError, { name: field.name })
1255
+ ] }, field.name);
1256
+ }
1257
+ if (field.type === "switch") {
1258
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "label", { className: "gap-group flex items-center", children: [
1259
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormSwitch, { name: field.name }),
1260
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col", children: [
1261
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-text-primary text-sm font-medium", children: field.label }),
1262
+ field.description && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-text-secondary text-sm", children: field.description })
1263
+ ] })
1264
+ ] }, field.name);
1265
+ }
1266
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex flex-col", children: [
1267
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormLabel, { name: field.name, children: field.label }),
1268
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1269
+ _chunkAFF2HPE5cjs.FormInput,
1270
+ {
1271
+ name: field.name,
1272
+ type: (_e = field.type) != null ? _e : "text",
1273
+ placeholder: field.placeholder
1274
+ }
1275
+ ),
1276
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormError, { name: field.name })
1277
+ ] }, field.name);
1278
+ }),
1279
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.FormSubmit, { children: labels.submitButton })
1280
+ ] }),
1281
+ submitted && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "border-success bg-success-subtle text-success-fg rounded-lg border p-3 text-sm", children: labels.successMessage })
1282
+ ]
1283
+ }
1284
+ );
1285
+ }
1286
+
1287
+ // src/shells/deployment-timeline.tsx
1288
+
1289
+ var statusIcon = {
1290
+ success: "\u25CF",
1291
+ pending: "\u25CC",
1292
+ running: "\u27F3",
1293
+ error: "\u2717",
1294
+ skipped: "\u25CB"
1295
+ };
1296
+ var statusColor = {
1297
+ success: "text-success-fg",
1298
+ pending: _chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY,
1299
+ running: "text-accent",
1300
+ error: "text-danger-fg",
1301
+ skipped: "text-text-tertiary"
1302
+ };
1303
+ var statusBadge = {
1304
+ success: _chunkAFF2HPE5cjs.OPT_BADGE_GREEN,
1305
+ pending: _chunkAFF2HPE5cjs.OPT_BADGE_NEUTRAL,
1306
+ running: "inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium bg-info-subtle text-info-fg",
1307
+ error: _chunkAFF2HPE5cjs.OPT_BADGE_RED,
1308
+ skipped: _chunkAFF2HPE5cjs.OPT_BADGE_NEUTRAL
1309
+ };
1310
+ var statusLabel = {
1311
+ success: "\uC131\uACF5",
1312
+ pending: "\uB300\uAE30",
1313
+ running: "\uC2E4\uD589 \uC911",
1314
+ error: "\uC5D0\uB7EC",
1315
+ skipped: "\uAC74\uB108\uB700"
1316
+ };
1317
+ function DeploymentTimeline({
1318
+ steps,
1319
+ title = "\uBC30\uD3EC \uD0C0\uC784\uB77C\uC778"
1320
+ }) {
1321
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1322
+ "div",
1323
+ {
1324
+ className: "gap-group flex flex-col",
1325
+ "data-opt-id": "XXVQ2",
1326
+ "data-opt-slug": "deployment-timeline.DeploymentTimeline",
1327
+ children: [
1328
+ title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: `text-sm font-semibold ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY}`, children: title }),
1329
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.CompositeProvider, { focusLoop: true, orientation: "vertical", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Composite, { role: "list", "aria-label": title, className: "relative", children: steps.map((step, i) => {
1330
+ const isLast = i === steps.length - 1;
1331
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1332
+ _chunkAFF2HPE5cjs.CompositeItem,
1333
+ {
1334
+ className: `group gap-group relative flex w-full scroll-m-2 rounded-lg px-3 py-2 ${_chunkAFF2HPE5cjs.OPT_FOCUS} data-[active-item]:bg-accent-subtle`,
1335
+ role: "listitem",
1336
+ children: [
1337
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex flex-col items-center", children: [
1338
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1339
+ "span",
1340
+ {
1341
+ className: `text-lg leading-none ${statusColor[step.status]}`,
1342
+ "aria-label": statusLabel[step.status],
1343
+ children: statusIcon[step.status]
1344
+ }
1345
+ ),
1346
+ !isLast && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "bg-border-subtle mt-1 w-px flex-1" })
1347
+ ] }),
1348
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex-1 pb-3", children: [
1349
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex items-center", children: [
1350
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `text-sm font-medium ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY}`, children: step.name }),
1351
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: statusBadge[step.status], children: statusLabel[step.status] }),
1352
+ step.duration && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY}`, children: step.duration })
1353
+ ] }),
1354
+ step.detail && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: `mt-0.5 text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY}`, children: step.detail })
1355
+ ] })
1356
+ ]
1357
+ },
1358
+ step.id
1359
+ );
1360
+ }) }) })
1361
+ ]
1362
+ }
1363
+ );
1364
+ }
1365
+
1366
+ // src/shells/project-switcher.tsx
1367
+
1368
+
1369
+
1370
+ var statusDot = {
1371
+ active: _chunkAFF2HPE5cjs.OPT_DOT_GREEN,
1372
+ paused: _chunkAFF2HPE5cjs.OPT_DOT_YELLOW,
1373
+ error: _chunkAFF2HPE5cjs.OPT_DOT_RED
1374
+ };
1375
+ function ProjectSwitcher({
1376
+ projects,
1377
+ value,
1378
+ onChange,
1379
+ placeholder = "\uD504\uB85C\uC81D\uD2B8 \uAC80\uC0C9..."
1380
+ }) {
1381
+ const [search, setSearch] = _react.useState.call(void 0, "");
1382
+ const matches = _react.useMemo.call(void 0, () => {
1383
+ if (!search) return projects;
1384
+ return _matchsorter.matchSorter.call(void 0, projects, search, { keys: ["name", "framework"] });
1385
+ }, [search, projects]);
1386
+ const selected = projects.find((p) => p.id === value);
1387
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1388
+ "div",
1389
+ {
1390
+ className: "gap-element flex flex-col",
1391
+ "data-opt-id": "5R3AG",
1392
+ "data-opt-slug": "project-switcher.ProjectSwitcher",
1393
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.ComboboxRoot, { onValueChange: setSearch, children: [
1394
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "label", { className: _chunkAFF2HPE5cjs.OPT_TEXT_LABEL, children: "\uD504\uB85C\uC81D\uD2B8" }),
1395
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1396
+ _chunkAFF2HPE5cjs.ComboboxInput,
1397
+ {
1398
+ placeholder: selected ? selected.name : placeholder,
1399
+ className: _chunkAFF2HPE5cjs.OPT_INPUT
1400
+ }
1401
+ ),
1402
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.ComboboxPopover, { className: "max-h-72 overflow-y-auto", children: [
1403
+ matches.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: `py-6 text-center text-sm ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY}`, children: "\uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." }),
1404
+ matches.map((project) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1405
+ _chunkAFF2HPE5cjs.ComboboxItem,
1406
+ {
1407
+ value: project.name,
1408
+ onClick: () => onChange == null ? void 0 : onChange(project.id),
1409
+ className: `gap-element flex scroll-m-2 items-center ${_chunkAFF2HPE5cjs.OPT_ITEM_BASE} ${_chunkAFF2HPE5cjs.OPT_ACTIVE_ITEM}`,
1410
+ children: [
1411
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `shrink-0 ${statusDot[project.status]}` }),
1412
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "flex-1 truncate font-medium", children: project.name }),
1413
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: _chunkAFF2HPE5cjs.OPT_BADGE_NEUTRAL, children: project.framework }),
1414
+ project.domain && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1415
+ "span",
1416
+ {
1417
+ className: `truncate text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY} data-[active-item]:text-accent-fg/70`,
1418
+ children: project.domain
1419
+ }
1420
+ )
1421
+ ]
1422
+ },
1423
+ project.id
1424
+ ))
1425
+ ] })
1426
+ ] })
1427
+ }
1428
+ );
1429
+ }
1430
+ ProjectSwitcher.displayName = "ProjectSwitcher";
1431
+
1432
+ // src/shells/env-panel.tsx
1433
+
1434
+ var defaultLabels10 = {
1435
+ varCount: (count) => `${count}\uAC1C \uBCC0\uC218`,
1436
+ envVarsLabel: (env) => `${env} \uD658\uACBD \uBCC0\uC218`,
1437
+ secretBadge: "secret"
1438
+ };
1439
+ var envDot = {
1440
+ Production: _chunkAFF2HPE5cjs.OPT_DOT_RED,
1441
+ Preview: _chunkAFF2HPE5cjs.OPT_DOT_YELLOW,
1442
+ Development: _chunkAFF2HPE5cjs.OPT_DOT_GREEN
1443
+ };
1444
+ function EnvPanel({ groups, labels: customLabels }) {
1445
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels10), customLabels);
1446
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1447
+ "div",
1448
+ {
1449
+ className: `rounded-lg ${_chunkAFF2HPE5cjs.OPT_BORDER} divide-y ${_chunkAFF2HPE5cjs.OPT_DIVIDER} bg-surface`,
1450
+ "data-opt-id": "ZBDWK",
1451
+ "data-opt-slug": "env-panel.EnvPanel",
1452
+ children: groups.map((group) => {
1453
+ var _a;
1454
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1455
+ _chunkAFF2HPE5cjs.DisclosureRoot,
1456
+ {
1457
+ defaultOpen: group.env === "Production",
1458
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
1459
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.DisclosureTrigger, { className: _chunkAFF2HPE5cjs.OPT_DISCLOSURE_TRIGGER, children: [
1460
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "gap-element flex items-center", children: [
1461
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1462
+ "span",
1463
+ {
1464
+ className: (_a = envDot[group.env]) != null ? _a : "bg-bg-muted h-2 w-2 rounded-full"
1465
+ }
1466
+ ),
1467
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "font-medium", children: group.env }),
1468
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY}`, children: labels.varCount(group.vars.length) })
1469
+ ] }),
1470
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1471
+ "svg",
1472
+ {
1473
+ className: "text-text-tertiary h-4 w-4 shrink-0 transition-transform [[data-open]>&]:rotate-180",
1474
+ fill: "none",
1475
+ viewBox: "0 0 24 24",
1476
+ stroke: "currentColor",
1477
+ strokeWidth: 2,
1478
+ "aria-hidden": "true",
1479
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1480
+ "path",
1481
+ {
1482
+ strokeLinecap: "round",
1483
+ strokeLinejoin: "round",
1484
+ d: "m19.5 8.25-7.5 7.5-7.5-7.5"
1485
+ }
1486
+ )
1487
+ }
1488
+ )
1489
+ ] }),
1490
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.DisclosureContent, { className: _chunkAFF2HPE5cjs.OPT_DISCLOSURE_CONTENT, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.CompositeProvider, { focusLoop: true, orientation: "vertical", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1491
+ _chunkAFF2HPE5cjs.Composite,
1492
+ {
1493
+ role: "list",
1494
+ "aria-label": labels.envVarsLabel(group.env),
1495
+ className: "px-4 pb-3",
1496
+ children: group.vars.map((v) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1497
+ _chunkAFF2HPE5cjs.CompositeItem,
1498
+ {
1499
+ role: "listitem",
1500
+ className: `gap-group flex scroll-m-2 items-center rounded px-2 py-1.5 text-sm ${_chunkAFF2HPE5cjs.OPT_FOCUS} data-[active-item]:bg-accent-subtle`,
1501
+ children: [
1502
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1503
+ "span",
1504
+ {
1505
+ className: `w-44 shrink-0 truncate font-mono text-xs font-medium ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY}`,
1506
+ children: v.key
1507
+ }
1508
+ ),
1509
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1510
+ "span",
1511
+ {
1512
+ className: `flex-1 truncate font-mono text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY}`,
1513
+ children: v.isSecret ? "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" : v.value
1514
+ }
1515
+ ),
1516
+ v.isSecret && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: _chunkAFF2HPE5cjs.OPT_BADGE_NEUTRAL, children: labels.secretBadge })
1517
+ ]
1518
+ },
1519
+ v.key
1520
+ ))
1521
+ }
1522
+ ) }) })
1523
+ ] })
1524
+ },
1525
+ group.env
1526
+ );
1527
+ })
1528
+ }
1529
+ );
1530
+ }
1531
+
1532
+ // src/shells/branch-select.tsx
1533
+
1534
+
1535
+ var defaultLabels11 = {
1536
+ selectLabel: "\uBE0C\uB79C\uCE58",
1537
+ emptySelectionLabel: "\uC120\uD0DD...",
1538
+ emptyMessage: "\uC0AC\uC6A9 \uAC00\uB2A5\uD55C \uBE0C\uB79C\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
1539
+ defaultBadge: "default"
1540
+ };
1541
+ function BranchSelect({
1542
+ branches,
1543
+ value: controlledValue,
1544
+ onChange,
1545
+ label,
1546
+ labels: customLabels
1547
+ }) {
1548
+ var _a, _b, _c, _d;
1549
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels11), customLabels);
1550
+ const resolvedLabel = label != null ? label : labels.selectLabel;
1551
+ const defaultBranch = branches.find((b) => b.isDefault);
1552
+ const [internalValue, setInternalValue] = _react.useState.call(void 0,
1553
+ (_c = (_b = defaultBranch == null ? void 0 : defaultBranch.name) != null ? _b : (_a = branches[0]) == null ? void 0 : _a.name) != null ? _c : ""
1554
+ );
1555
+ const value = controlledValue != null ? controlledValue : internalValue;
1556
+ const selected = branches.find((b) => b.name === value);
1557
+ if (branches.length === 0) {
1558
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1559
+ "div",
1560
+ {
1561
+ className: "gap-element flex flex-col",
1562
+ "data-opt-id": "7EDEP",
1563
+ "data-opt-slug": "branch-select.BranchSelect",
1564
+ children: [
1565
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: _chunkAFF2HPE5cjs.OPT_TEXT_LABEL, children: resolvedLabel }),
1566
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: _chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY, children: labels.emptyMessage })
1567
+ ]
1568
+ }
1569
+ );
1570
+ }
1571
+ const handleChange = (v) => {
1572
+ var _a2;
1573
+ const next = Array.isArray(v) ? (_a2 = v[0]) != null ? _a2 : "" : v;
1574
+ if (onChange) onChange(next);
1575
+ else setInternalValue(next);
1576
+ };
1577
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1578
+ "div",
1579
+ {
1580
+ className: "gap-element flex flex-col",
1581
+ "data-opt-id": "7EDEP",
1582
+ "data-opt-slug": "branch-select.BranchSelect",
1583
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.SelectRoot, { value, onValueChange: handleChange, children: [
1584
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.SelectLabel, { className: _chunkAFF2HPE5cjs.OPT_TEXT_LABEL, children: resolvedLabel }),
1585
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1586
+ _chunkAFF2HPE5cjs.SelectTrigger,
1587
+ {
1588
+ className: `${_chunkAFF2HPE5cjs.OPT_INPUT} max-w-xs items-center justify-between gap-1`,
1589
+ children: [
1590
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "gap-element flex items-center truncate", children: [
1591
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1592
+ "svg",
1593
+ {
1594
+ className: "text-text-tertiary h-4 w-4 shrink-0",
1595
+ fill: "none",
1596
+ viewBox: "0 0 24 24",
1597
+ stroke: "currentColor",
1598
+ strokeWidth: 2,
1599
+ "aria-hidden": "true",
1600
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1601
+ "path",
1602
+ {
1603
+ strokeLinecap: "round",
1604
+ strokeLinejoin: "round",
1605
+ d: "M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"
1606
+ }
1607
+ )
1608
+ }
1609
+ ),
1610
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "truncate", children: (_d = selected == null ? void 0 : selected.name) != null ? _d : labels.emptySelectionLabel }),
1611
+ (selected == null ? void 0 : selected.isDefault) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: _chunkAFF2HPE5cjs.OPT_BADGE_BLUE, children: labels.defaultBadge })
1612
+ ] }),
1613
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1614
+ "svg",
1615
+ {
1616
+ className: "text-text-tertiary h-4 w-4 shrink-0",
1617
+ fill: "none",
1618
+ viewBox: "0 0 24 24",
1619
+ stroke: "currentColor",
1620
+ strokeWidth: 2,
1621
+ "aria-hidden": "true",
1622
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1623
+ "path",
1624
+ {
1625
+ strokeLinecap: "round",
1626
+ strokeLinejoin: "round",
1627
+ d: "m19.5 8.25-7.5 7.5-7.5-7.5"
1628
+ }
1629
+ )
1630
+ }
1631
+ )
1632
+ ]
1633
+ }
1634
+ ),
1635
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.SelectPopover, { className: "max-w-xs", children: branches.map((branch) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1636
+ _chunkAFF2HPE5cjs.SelectItem,
1637
+ {
1638
+ value: branch.name,
1639
+ className: `gap-element flex scroll-m-2 items-center ${_chunkAFF2HPE5cjs.OPT_ITEM_BASE} ${_chunkAFF2HPE5cjs.OPT_ACTIVE_ITEM}`,
1640
+ children: [
1641
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "flex-1 truncate", children: branch.name }),
1642
+ branch.isDefault && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "bg-accent-subtle text-accent data-[active-item]:bg-accent-fg/20 data-[active-item]:text-accent-fg rounded-full px-2 py-0.5 text-[11px] font-medium", children: labels.defaultBadge }),
1643
+ branch.lastCommit && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1644
+ "span",
1645
+ {
1646
+ className: `font-mono text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY} data-[active-item]:text-accent-fg/60`,
1647
+ children: branch.lastCommit
1648
+ }
1649
+ ),
1650
+ branch.author && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1651
+ "span",
1652
+ {
1653
+ className: `text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY} data-[active-item]:text-accent-fg/60`,
1654
+ children: branch.author
1655
+ }
1656
+ )
1657
+ ]
1658
+ },
1659
+ branch.name
1660
+ )) })
1661
+ ] })
1662
+ }
1663
+ );
1664
+ }
1665
+ BranchSelect.displayName = "BranchSelect";
1666
+
1667
+ // src/shells/domain-table.tsx
1668
+
1669
+ var defaultLabels12 = {
1670
+ domain: "Domain",
1671
+ status: "Status",
1672
+ ssl: "SSL",
1673
+ redirect: "Redirect",
1674
+ added: "Added",
1675
+ emptyMessage: "No domains configured"
1676
+ };
1677
+ var statusBadge2 = {
1678
+ active: _chunkAFF2HPE5cjs.OPT_BADGE_GREEN,
1679
+ pending: _chunkAFF2HPE5cjs.OPT_BADGE_YELLOW,
1680
+ error: _chunkAFF2HPE5cjs.OPT_BADGE_RED
1681
+ };
1682
+ var sslBadge = {
1683
+ valid: _chunkAFF2HPE5cjs.OPT_BADGE_GREEN,
1684
+ pending: _chunkAFF2HPE5cjs.OPT_BADGE_YELLOW,
1685
+ expired: _chunkAFF2HPE5cjs.OPT_BADGE_RED
1686
+ };
1687
+ var statusLabel2 = {
1688
+ active: "Active",
1689
+ pending: "Pending",
1690
+ error: "Error"
1691
+ };
1692
+ var sslLabel = {
1693
+ valid: "Valid",
1694
+ pending: "Pending",
1695
+ expired: "Expired"
1696
+ };
1697
+ function DomainTable({
1698
+ domains,
1699
+ title = "\uB3C4\uBA54\uC778",
1700
+ labels: customLabels
1701
+ }) {
1702
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels12), customLabels);
1703
+ if (domains.length === 0) {
1704
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1705
+ "div",
1706
+ {
1707
+ className: "gap-group flex flex-col",
1708
+ "data-opt-id": "A7SRM",
1709
+ "data-opt-slug": "domain-table.DomainTable",
1710
+ children: [
1711
+ title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: `text-sm font-semibold ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY}`, children: title }),
1712
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1713
+ "div",
1714
+ {
1715
+ className: `rounded-lg px-4 py-6 text-sm ${_chunkAFF2HPE5cjs.OPT_BORDER} ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY} bg-surface`,
1716
+ children: labels.emptyMessage
1717
+ }
1718
+ )
1719
+ ]
1720
+ }
1721
+ );
1722
+ }
1723
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1724
+ "div",
1725
+ {
1726
+ className: "gap-group flex flex-col",
1727
+ "data-opt-id": "A7SRM",
1728
+ "data-opt-slug": "domain-table.DomainTable",
1729
+ children: [
1730
+ title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: `text-sm font-semibold ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY}`, children: title }),
1731
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: `overflow-x-auto rounded-lg ${_chunkAFF2HPE5cjs.OPT_BORDER} bg-surface`, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.CompositeProvider, { focusLoop: true, focusWrap: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1732
+ _chunkAFF2HPE5cjs.Composite,
1733
+ {
1734
+ role: "grid",
1735
+ "aria-label": title,
1736
+ className: "w-full",
1737
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "table", {}),
1738
+ children: [
1739
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "thead", { className: "border-border-subtle bg-surface-inset border-b", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
1740
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.OPT_TH, children: labels.domain }),
1741
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.OPT_TH, children: labels.status }),
1742
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.OPT_TH, children: labels.ssl }),
1743
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.OPT_TH, children: labels.redirect }),
1744
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.OPT_TH, children: labels.added })
1745
+ ] }) }),
1746
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { className: `divide-y ${_chunkAFF2HPE5cjs.OPT_DIVIDER}`, children: domains.map((d) => {
1747
+ var _a, _b;
1748
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAFF2HPE5cjs.CompositeRow, { render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tr", {}), children: [
1749
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1750
+ _chunkAFF2HPE5cjs.CompositeItem,
1751
+ {
1752
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1753
+ "td",
1754
+ {
1755
+ className: `${_chunkAFF2HPE5cjs.OPT_TD} font-mono font-medium`,
1756
+ role: "gridcell"
1757
+ }
1758
+ ),
1759
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
1760
+ children: d.domain
1761
+ }
1762
+ ),
1763
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1764
+ _chunkAFF2HPE5cjs.CompositeItem,
1765
+ {
1766
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { className: _chunkAFF2HPE5cjs.OPT_TD, role: "gridcell" }),
1767
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
1768
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: statusBadge2[d.status], children: statusLabel2[d.status] })
1769
+ }
1770
+ ),
1771
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1772
+ _chunkAFF2HPE5cjs.CompositeItem,
1773
+ {
1774
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { className: _chunkAFF2HPE5cjs.OPT_TD, role: "gridcell" }),
1775
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
1776
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: sslBadge[d.ssl], children: sslLabel[d.ssl] })
1777
+ }
1778
+ ),
1779
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1780
+ _chunkAFF2HPE5cjs.CompositeItem,
1781
+ {
1782
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { className: _chunkAFF2HPE5cjs.OPT_TD, role: "gridcell" }),
1783
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
1784
+ children: (_a = d.redirect) != null ? _a : "\u2014"
1785
+ }
1786
+ ),
1787
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1788
+ _chunkAFF2HPE5cjs.CompositeItem,
1789
+ {
1790
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "td", { className: _chunkAFF2HPE5cjs.OPT_TD_MUTED, role: "gridcell" }),
1791
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
1792
+ children: (_b = d.addedAt) != null ? _b : "\u2014"
1793
+ }
1794
+ )
1795
+ ] }, d.domain);
1796
+ }) })
1797
+ ]
1798
+ }
1799
+ ) }) })
1800
+ ]
1801
+ }
1802
+ );
1803
+ }
1804
+
1805
+ // src/shells/data-table.tsx
1806
+
1807
+
1808
+
1809
+
1810
+
1811
+
1812
+
1813
+ var MIN_COLUMN_WIDTH = 40;
1814
+ var DEFAULT_COLUMN_RESIZE_MAX = 1200;
1815
+ var alignmentClass = {
1816
+ left: "text-left",
1817
+ center: "text-center",
1818
+ right: "text-right"
1819
+ };
1820
+ function getCellValue(row, accessor) {
1821
+ if (typeof accessor === "function") {
1822
+ try {
1823
+ return accessor(row);
1824
+ } catch (e) {
1825
+ return "\u2014";
1826
+ }
1827
+ }
1828
+ const value = row[accessor];
1829
+ if (value === null || value === void 0 || typeof value === "number" && !Number.isFinite(value)) {
1830
+ return "\u2014";
1831
+ }
1832
+ return String(value);
1833
+ }
1834
+ function getRawValue(row, accessor) {
1835
+ if (typeof accessor === "function") {
1836
+ return accessor(row);
1837
+ }
1838
+ return row[accessor];
1839
+ }
1840
+ function isMissingSortValue(value) {
1841
+ return value == null || typeof value === "number" && !Number.isFinite(value);
1842
+ }
1843
+ function compareSortValues(aVal, bVal, dir) {
1844
+ const aMissing = isMissingSortValue(aVal);
1845
+ const bMissing = isMissingSortValue(bVal);
1846
+ if (aMissing && bMissing) return 0;
1847
+ if (aMissing) return 1;
1848
+ if (bMissing) return -1;
1849
+ const cmp = typeof aVal === "number" && typeof bVal === "number" ? aVal - bVal : String(aVal).localeCompare(String(bVal));
1850
+ return dir === "desc" ? -cmp : cmp;
1851
+ }
1852
+ function clampPercent(ratio) {
1853
+ if (!Number.isFinite(ratio)) return 0;
1854
+ return Math.min(100, Math.max(0, Math.round(ratio * 100)));
1855
+ }
1856
+ function getResizeHandleValue(currentWidth, configuredWidth) {
1857
+ if (typeof currentWidth === "number" && Number.isFinite(currentWidth)) {
1858
+ return Math.max(MIN_COLUMN_WIDTH, Math.round(currentWidth));
1859
+ }
1860
+ const pxWidth = configuredWidth == null ? void 0 : configuredWidth.trim().match(/^(\d+(?:\.\d+)?)px$/);
1861
+ if (pxWidth) {
1862
+ return Math.max(MIN_COLUMN_WIDTH, Math.round(Number(pxWidth[1])));
1863
+ }
1864
+ return MIN_COLUMN_WIDTH;
1865
+ }
1866
+ function DataTableProgressBar({
1867
+ value,
1868
+ barColor,
1869
+ label
1870
+ }) {
1871
+ const percent = clampPercent(value);
1872
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1873
+ "div",
1874
+ {
1875
+ className: "bg-bg-subtle mt-1 h-1.5 w-full overflow-hidden rounded-full",
1876
+ role: "progressbar",
1877
+ "aria-valuenow": percent,
1878
+ "aria-valuemin": 0,
1879
+ "aria-valuemax": 100,
1880
+ "aria-valuetext": `${percent}%`,
1881
+ "aria-label": label,
1882
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1883
+ "div",
1884
+ {
1885
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "h-full rounded-full transition-all", barColor),
1886
+ style: { width: `${percent}%` }
1887
+ }
1888
+ )
1889
+ }
1890
+ );
1891
+ }
1892
+ function DataTable({
1893
+ data,
1894
+ columns,
1895
+ keyExtractor,
1896
+ title = "Data Table",
1897
+ onRowClick,
1898
+ emptyMessage = "No data available",
1899
+ activeRowId,
1900
+ sortable = false,
1901
+ selectable = false,
1902
+ selectedKeys,
1903
+ onSelectionChange,
1904
+ expandable = false,
1905
+ renderExpanded,
1906
+ pageSize,
1907
+ stickyHeader = false,
1908
+ resizableColumns = false,
1909
+ onSort: onSortExternal,
1910
+ className
1911
+ }) {
1912
+ const [sortCol, setSortCol] = _react.useState.call(void 0, null);
1913
+ const [sortDir, setSortDir] = _react.useState.call(void 0, null);
1914
+ const [expandedKeys, setExpandedKeys] = _react.useState.call(void 0, /* @__PURE__ */ new Set());
1915
+ const [page, setPage] = _react.useState.call(void 0, 0);
1916
+ const [colWidths, setColWidths] = _react.useState.call(void 0, {});
1917
+ const sortedData = _react.useMemo.call(void 0, () => {
1918
+ if (!sortable || !sortCol || !sortDir) return data;
1919
+ const col = columns.find((c) => c.id === sortCol);
1920
+ if (!col) return data;
1921
+ return [...data].sort((a, b) => {
1922
+ const aVal = getRawValue(a, col.accessor);
1923
+ const bVal = getRawValue(b, col.accessor);
1924
+ return compareSortValues(aVal, bVal, sortDir);
1925
+ });
1926
+ }, [data, sortable, sortCol, sortDir, columns]);
1927
+ const totalPages = pageSize ? Math.ceil(sortedData.length / pageSize) : 1;
1928
+ const pagedData = pageSize ? sortedData.slice(page * pageSize, (page + 1) * pageSize) : sortedData;
1929
+ const handleSort = _react.useCallback.call(void 0,
1930
+ (colId) => {
1931
+ if (!sortable) return;
1932
+ let nextDir;
1933
+ if (sortCol === colId) {
1934
+ nextDir = sortDir === "asc" ? "desc" : sortDir === "desc" ? null : "asc";
1935
+ setSortDir(nextDir);
1936
+ if (nextDir === null) setSortCol(null);
1937
+ } else {
1938
+ setSortCol(colId);
1939
+ setSortDir("asc");
1940
+ nextDir = "asc";
1941
+ }
1942
+ setPage(0);
1943
+ if (onSortExternal) {
1944
+ onSortExternal(colId, nextDir);
1945
+ }
1946
+ },
1947
+ [sortable, sortCol, sortDir, onSortExternal]
1948
+ );
1949
+ const toggleExpand = _react.useCallback.call(void 0, (key) => {
1950
+ setExpandedKeys((prev) => {
1951
+ const next = new Set(prev);
1952
+ if (next.has(key)) next.delete(key);
1953
+ else next.add(key);
1954
+ return next;
1955
+ });
1956
+ }, []);
1957
+ const selected = selectedKeys != null ? selectedKeys : [];
1958
+ const selectedSet = _react.useMemo.call(void 0,
1959
+ () => new Set(selectedKeys != null ? selectedKeys : []),
1960
+ [selectedKeys]
1961
+ );
1962
+ const allKeys = data.map(keyExtractor);
1963
+ const allSelected = allKeys.length > 0 && allKeys.every((k) => selectedSet.has(k));
1964
+ const toggleSelectAll = _react.useCallback.call(void 0, () => {
1965
+ if (!onSelectionChange) return;
1966
+ onSelectionChange(allSelected ? [] : allKeys);
1967
+ }, [allSelected, allKeys, onSelectionChange]);
1968
+ const toggleSelectRow = _react.useCallback.call(void 0,
1969
+ (key) => {
1970
+ if (!onSelectionChange) return;
1971
+ onSelectionChange(
1972
+ selectedSet.has(key) ? selected.filter((k) => k !== key) : [...selected, key]
1973
+ );
1974
+ },
1975
+ [selected, selectedSet, onSelectionChange]
1976
+ );
1977
+ const sortIndicator = (colId) => {
1978
+ if (sortCol !== colId) return null;
1979
+ return sortDir === "asc" ? " \u25B2" : sortDir === "desc" ? " \u25BC" : null;
1980
+ };
1981
+ const colCount = columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0);
1982
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
1983
+ "div",
1984
+ {
1985
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "gap-group flex flex-col", className),
1986
+ "data-opt-id": "J1KN4",
1987
+ "data-opt-slug": "data-table.DataTable",
1988
+ children: [
1989
+ title && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: _chunkAFF2HPE5cjs.cn.call(void 0, "text-sm font-semibold", _chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY), children: title }),
1990
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1991
+ "div",
1992
+ {
1993
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "overflow-x-auto rounded-lg", _chunkAFF2HPE5cjs.OPT_BORDER, "bg-surface"),
1994
+ children: data.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1995
+ "div",
1996
+ {
1997
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "px-4 py-8 text-center text-sm", _chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY),
1998
+ children: emptyMessage
1999
+ }
2000
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.CompositeProvider, { focusLoop: true, focusWrap: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2001
+ _chunkAFF2HPE5cjs.Composite,
2002
+ {
2003
+ role: "grid",
2004
+ "aria-label": title,
2005
+ className: "w-full",
2006
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "table", {}),
2007
+ children: [
2008
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2009
+ "thead",
2010
+ {
2011
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2012
+ "border-border-subtle bg-surface-inset border-b",
2013
+ stickyHeader && "sticky top-0 z-10"
2014
+ ),
2015
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "tr", { children: [
2016
+ selectable && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.cn.call(void 0, _chunkAFF2HPE5cjs.OPT_TH, "w-10"), children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2017
+ _chunkAFF2HPE5cjs.Checkbox,
2018
+ {
2019
+ checked: allSelected,
2020
+ onChange: toggleSelectAll,
2021
+ "aria-label": "Select all"
2022
+ }
2023
+ ) }),
2024
+ expandable && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "th", { className: _chunkAFF2HPE5cjs.cn.call(void 0, _chunkAFF2HPE5cjs.OPT_TH, "w-10") }),
2025
+ columns.map((col) => {
2026
+ var _a;
2027
+ const isSortable = sortable && col.sortable !== false;
2028
+ const resizeValue = getResizeHandleValue(
2029
+ colWidths[col.id],
2030
+ col.width
2031
+ );
2032
+ const resizeMax = Math.max(
2033
+ DEFAULT_COLUMN_RESIZE_MAX,
2034
+ resizeValue
2035
+ );
2036
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2037
+ "th",
2038
+ {
2039
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2040
+ _chunkAFF2HPE5cjs.OPT_TH,
2041
+ "relative",
2042
+ alignmentClass[(_a = col.align) != null ? _a : "left"],
2043
+ isSortable && "hover:text-text-primary cursor-pointer select-none"
2044
+ ),
2045
+ style: {
2046
+ width: colWidths[col.id] || col.width || void 0
2047
+ },
2048
+ onClick: isSortable ? () => handleSort(col.id) : void 0,
2049
+ "aria-sort": sortCol === col.id && sortDir ? sortDir === "asc" ? "ascending" : "descending" : void 0,
2050
+ children: [
2051
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "flex items-center", children: [
2052
+ col.header,
2053
+ sortIndicator(col.id)
2054
+ ] }),
2055
+ resizableColumns && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2056
+ "span",
2057
+ {
2058
+ role: "separator",
2059
+ "aria-orientation": "vertical",
2060
+ "aria-label": `Resize ${col.header}`,
2061
+ "aria-valuemin": MIN_COLUMN_WIDTH,
2062
+ "aria-valuemax": resizeMax,
2063
+ "aria-valuenow": resizeValue,
2064
+ tabIndex: 0,
2065
+ className: "bg-border absolute top-0 right-0 bottom-0 w-1 cursor-col-resize opacity-0 hover:opacity-100",
2066
+ onKeyDown: (e) => {
2067
+ if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") {
2068
+ return;
2069
+ }
2070
+ e.preventDefault();
2071
+ e.stopPropagation();
2072
+ const delta = e.shiftKey ? 40 : 10;
2073
+ const direction = e.key === "ArrowRight" ? 1 : -1;
2074
+ setColWidths((prev) => {
2075
+ const current = getResizeHandleValue(
2076
+ prev[col.id],
2077
+ col.width
2078
+ );
2079
+ return _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, prev), {
2080
+ [col.id]: Math.max(
2081
+ MIN_COLUMN_WIDTH,
2082
+ current + direction * delta
2083
+ )
2084
+ });
2085
+ });
2086
+ },
2087
+ onMouseDown: (e) => {
2088
+ e.preventDefault();
2089
+ e.stopPropagation();
2090
+ const startX = e.clientX;
2091
+ const th = e.target.parentElement;
2092
+ const startW = th.offsetWidth;
2093
+ const onMove = (ev) => {
2094
+ const newW = Math.max(
2095
+ MIN_COLUMN_WIDTH,
2096
+ startW + ev.clientX - startX
2097
+ );
2098
+ setColWidths((prev) => _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, prev), {
2099
+ [col.id]: newW
2100
+ }));
2101
+ };
2102
+ const onUp = () => {
2103
+ document.removeEventListener(
2104
+ "mousemove",
2105
+ onMove
2106
+ );
2107
+ document.removeEventListener("mouseup", onUp);
2108
+ };
2109
+ document.addEventListener("mousemove", onMove);
2110
+ document.addEventListener("mouseup", onUp);
2111
+ }
2112
+ }
2113
+ )
2114
+ ]
2115
+ },
2116
+ col.id
2117
+ );
2118
+ })
2119
+ ] })
2120
+ }
2121
+ ),
2122
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tbody", { className: _chunkAFF2HPE5cjs.cn.call(void 0, "divide-y", _chunkAFF2HPE5cjs.OPT_DIVIDER), children: pagedData.map((row) => {
2123
+ const key = keyExtractor(row);
2124
+ const isExpanded = expandedKeys.has(key);
2125
+ const isSelected = selectedSet.has(key);
2126
+ const isActive = activeRowId === key;
2127
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _react.Fragment, { children: [
2128
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2129
+ _chunkAFF2HPE5cjs.CompositeRow,
2130
+ {
2131
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2132
+ "tr",
2133
+ {
2134
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2135
+ onRowClick ? "cursor-pointer" : void 0,
2136
+ (isSelected || isActive) && "bg-accent-subtle"
2137
+ ),
2138
+ onClick: onRowClick ? () => onRowClick(row) : void 0
2139
+ }
2140
+ ),
2141
+ children: [
2142
+ selectable && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2143
+ _chunkAFF2HPE5cjs.CompositeItem,
2144
+ {
2145
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2146
+ "td",
2147
+ {
2148
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, _chunkAFF2HPE5cjs.OPT_TD, "w-10"),
2149
+ role: "gridcell"
2150
+ }
2151
+ ),
2152
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
2153
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2154
+ _chunkAFF2HPE5cjs.Checkbox,
2155
+ {
2156
+ checked: isSelected,
2157
+ onChange: () => toggleSelectRow(key),
2158
+ "aria-label": `Select row ${key}`
2159
+ }
2160
+ )
2161
+ }
2162
+ ),
2163
+ expandable && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2164
+ _chunkAFF2HPE5cjs.CompositeItem,
2165
+ {
2166
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2167
+ "td",
2168
+ {
2169
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, _chunkAFF2HPE5cjs.OPT_TD, "w-10"),
2170
+ role: "gridcell"
2171
+ }
2172
+ ),
2173
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
2174
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2175
+ "button",
2176
+ {
2177
+ type: "button",
2178
+ onClick: (e) => {
2179
+ e.stopPropagation();
2180
+ toggleExpand(key);
2181
+ },
2182
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2183
+ "rounded p-0.5 text-sm transition-transform",
2184
+ _chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY,
2185
+ _chunkAFF2HPE5cjs.OPT_FOCUS_VISIBLE,
2186
+ isExpanded && "rotate-90"
2187
+ ),
2188
+ "aria-expanded": isExpanded,
2189
+ "aria-label": "Expand row",
2190
+ children: "\u25B6"
2191
+ }
2192
+ )
2193
+ }
2194
+ ),
2195
+ columns.map((col, colIndex) => {
2196
+ var _a, _b;
2197
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2198
+ _chunkAFF2HPE5cjs.CompositeItem,
2199
+ {
2200
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2201
+ "td",
2202
+ {
2203
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2204
+ _chunkAFF2HPE5cjs.OPT_TD,
2205
+ alignmentClass[(_a = col.align) != null ? _a : "left"],
2206
+ colIndex === 0 ? "font-medium" : ""
2207
+ ),
2208
+ role: "gridcell"
2209
+ }
2210
+ ),
2211
+ className: _chunkAFF2HPE5cjs.OPT_TABLE_ROW_ACTIVE,
2212
+ children: [
2213
+ getCellValue(row, col.accessor),
2214
+ col.bar && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2215
+ DataTableProgressBar,
2216
+ {
2217
+ value: col.bar(row),
2218
+ barColor: (_b = col.barColor) != null ? _b : "bg-accent",
2219
+ label: col.header
2220
+ }
2221
+ )
2222
+ ]
2223
+ },
2224
+ col.id
2225
+ );
2226
+ })
2227
+ ]
2228
+ }
2229
+ ),
2230
+ expandable && isExpanded && renderExpanded && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "tr", { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2231
+ "td",
2232
+ {
2233
+ colSpan: colCount,
2234
+ className: "border-border-subtle bg-surface-inset border-t px-4 py-3",
2235
+ children: renderExpanded(row)
2236
+ }
2237
+ ) })
2238
+ ] }, key);
2239
+ }) })
2240
+ ]
2241
+ }
2242
+ ) })
2243
+ }
2244
+ ),
2245
+ pageSize && totalPages > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2246
+ _chunkAFF2HPE5cjs.Pagination,
2247
+ {
2248
+ totalItems: sortedData.length,
2249
+ pageSize,
2250
+ currentPage: page + 1,
2251
+ onPageChange: (p) => setPage(p - 1)
2252
+ }
2253
+ )
2254
+ ]
2255
+ }
2256
+ );
2257
+ }
2258
+
2259
+ // src/shells/notification-toast.tsx
2260
+
2261
+
2262
+
2263
+
2264
+
2265
+
2266
+
2267
+
2268
+
2269
+
2270
+ var toastCounter = 0;
2271
+ var toasts = [];
2272
+ var listeners = /* @__PURE__ */ new Set();
2273
+ function emitChange() {
2274
+ for (const l of listeners) l();
2275
+ }
2276
+ var toastStore = {
2277
+ subscribe(listener) {
2278
+ listeners.add(listener);
2279
+ return () => {
2280
+ listeners.delete(listener);
2281
+ };
2282
+ },
2283
+ getSnapshot() {
2284
+ return toasts;
2285
+ },
2286
+ add(input) {
2287
+ var _a;
2288
+ const id = `toast-${++toastCounter}`;
2289
+ toasts = [...toasts, _chunkONE3C5RVcjs.__spreadValues.call(void 0, { id, variant: (_a = input.variant) != null ? _a : "info" }, input)];
2290
+ emitChange();
2291
+ return id;
2292
+ },
2293
+ dismiss(id) {
2294
+ const next = toasts.filter((t) => t.id !== id);
2295
+ if (next.length !== toasts.length) {
2296
+ toasts = next;
2297
+ emitChange();
2298
+ }
2299
+ },
2300
+ clear() {
2301
+ if (toasts.length) {
2302
+ toasts = [];
2303
+ emitChange();
2304
+ }
2305
+ }
2306
+ };
2307
+ function makeVariant(variant) {
2308
+ return (message, options) => toastStore.add(_chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, options), { message, variant }));
2309
+ }
2310
+ var toast = Object.assign(
2311
+ (options) => toastStore.add(options),
2312
+ {
2313
+ info: makeVariant("info"),
2314
+ success: makeVariant("success"),
2315
+ warning: makeVariant("warning"),
2316
+ error: makeVariant("error"),
2317
+ dismiss: (id) => toastStore.dismiss(id),
2318
+ clear: () => toastStore.clear()
2319
+ }
2320
+ );
2321
+ var ToastContext = _react.createContext.call(void 0, null);
2322
+ var positionStyles = {
2323
+ "top-right": "top-4 right-4",
2324
+ "top-left": "top-4 left-4",
2325
+ "bottom-right": "bottom-4 right-4",
2326
+ "bottom-left": "bottom-4 left-4"
2327
+ };
2328
+ function ToastProvider({
2329
+ children,
2330
+ position = "top-right",
2331
+ defaultDuration = 5e3,
2332
+ stackLimit = 5
2333
+ }) {
2334
+ const allToasts = _react.useSyncExternalStore.call(void 0,
2335
+ toastStore.subscribe,
2336
+ toastStore.getSnapshot,
2337
+ toastStore.getSnapshot
2338
+ );
2339
+ const visibleToasts = allToasts.length > stackLimit ? allToasts.slice(-stackLimit) : allToasts;
2340
+ const addToast = _react.useCallback.call(void 0,
2341
+ (t) => toastStore.add(t),
2342
+ []
2343
+ );
2344
+ const removeToast = _react.useCallback.call(void 0, (id) => toastStore.dismiss(id), []);
2345
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2346
+ ToastContext.Provider,
2347
+ {
2348
+ value: { toasts: visibleToasts, addToast, removeToast },
2349
+ children: [
2350
+ children,
2351
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2352
+ "div",
2353
+ {
2354
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2355
+ "gap-element fixed z-50 flex flex-col",
2356
+ positionStyles[position]
2357
+ ),
2358
+ role: "region",
2359
+ "aria-label": "Notifications",
2360
+ "data-opt-id": "M0KTS",
2361
+ "data-opt-slug": "notification-toast.ToastProvider",
2362
+ children: visibleToasts.map((t) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2363
+ NotificationToast,
2364
+ {
2365
+ toast: t,
2366
+ defaultDuration,
2367
+ onDismiss: () => toastStore.dismiss(t.id)
2368
+ },
2369
+ t.id
2370
+ ))
2371
+ }
2372
+ )
2373
+ ]
2374
+ }
2375
+ );
2376
+ }
2377
+ function useToast() {
2378
+ const context = _react.useContext.call(void 0, ToastContext);
2379
+ if (!context) {
2380
+ throw new Error("useToast must be used within a ToastProvider");
2381
+ }
2382
+ return context;
2383
+ }
2384
+ function NotificationToast({
2385
+ toast: toast2,
2386
+ onDismiss,
2387
+ defaultDuration = 5e3
2388
+ }) {
2389
+ var _a;
2390
+ const duration = (_a = toast2.duration) != null ? _a : defaultDuration;
2391
+ const isUrgent = toast2.variant === "error" || toast2.variant === "warning";
2392
+ const onDismissRef = _react.useRef.call(void 0, onDismiss);
2393
+ const dismissedRef = _react.useRef.call(void 0, false);
2394
+ const timerStartedAtRef = _react.useRef.call(void 0, null);
2395
+ const remainingDurationRef = _react.useRef.call(void 0, duration);
2396
+ const [paused, setPaused] = _react.useState.call(void 0, false);
2397
+ _react.useEffect.call(void 0, () => {
2398
+ onDismissRef.current = onDismiss;
2399
+ }, [onDismiss]);
2400
+ const dismissOnce = _react.useCallback.call(void 0, () => {
2401
+ if (dismissedRef.current) return;
2402
+ dismissedRef.current = true;
2403
+ onDismissRef.current();
2404
+ }, []);
2405
+ _react.useEffect.call(void 0, () => {
2406
+ dismissedRef.current = false;
2407
+ remainingDurationRef.current = duration;
2408
+ }, [toast2.id, duration]);
2409
+ _react.useEffect.call(void 0, () => {
2410
+ if (!duration || duration <= 0 || paused || dismissedRef.current) {
2411
+ return;
2412
+ }
2413
+ timerStartedAtRef.current = Date.now();
2414
+ const timer = setTimeout(() => {
2415
+ dismissOnce();
2416
+ }, remainingDurationRef.current);
2417
+ return () => {
2418
+ clearTimeout(timer);
2419
+ if (timerStartedAtRef.current !== null) {
2420
+ const elapsed = Date.now() - timerStartedAtRef.current;
2421
+ remainingDurationRef.current = Math.max(
2422
+ 0,
2423
+ remainingDurationRef.current - elapsed
2424
+ );
2425
+ timerStartedAtRef.current = null;
2426
+ }
2427
+ };
2428
+ }, [dismissOnce, duration, paused]);
2429
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2430
+ "div",
2431
+ {
2432
+ className: "animate-in slide-in-from-right-full fade-in w-80 duration-200",
2433
+ role: isUrgent ? "alert" : "status",
2434
+ "aria-live": isUrgent ? "assertive" : "polite",
2435
+ "aria-atomic": "true",
2436
+ onMouseEnter: () => setPaused(true),
2437
+ onMouseLeave: () => setPaused(false),
2438
+ onFocus: () => setPaused(true),
2439
+ onBlur: (event) => {
2440
+ if (!event.currentTarget.contains(event.relatedTarget)) {
2441
+ setPaused(false);
2442
+ }
2443
+ },
2444
+ "data-opt-id": "26YVM",
2445
+ "data-opt-slug": "notification-toast.NotificationToast",
2446
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2447
+ _chunkAFF2HPE5cjs.Alert,
2448
+ {
2449
+ variant: toast2.variant,
2450
+ title: toast2.title,
2451
+ dismissible: true,
2452
+ onDismiss: dismissOnce,
2453
+ children: [
2454
+ toast2.message,
2455
+ toast2.actions && toast2.actions.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "gap-element mt-2 flex", children: toast2.actions.map((action) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2456
+ "button",
2457
+ {
2458
+ type: "button",
2459
+ onClick: action.onClick,
2460
+ className: "text-xs font-medium underline hover:no-underline",
2461
+ children: action.label
2462
+ },
2463
+ action.label
2464
+ )) })
2465
+ ]
2466
+ }
2467
+ )
2468
+ }
2469
+ );
2470
+ }
2471
+
2472
+ // src/shells/failure-list.tsx
2473
+
2474
+ var defaultLabels13 = {
2475
+ title: "\uCD5C\uADFC \uC2E4\uD328",
2476
+ emptyMessage: "\uC2E4\uD328 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
2477
+ moreItems: "{count}\uAC1C \uB354 \uBCF4\uAE30",
2478
+ severityLabels: {
2479
+ critical: "\uC2EC\uAC01",
2480
+ error: "\uC624\uB958",
2481
+ warning: "\uACBD\uACE0"
2482
+ },
2483
+ timeAgo: {
2484
+ justNow: "\uBC29\uAE08 \uC804",
2485
+ minutesAgo: "{minutes}\uBD84 \uC804",
2486
+ hoursAgo: "{hours}\uC2DC\uAC04 \uC804",
2487
+ daysAgo: "{days}\uC77C \uC804"
2488
+ }
2489
+ };
2490
+ var severityVariant = {
2491
+ critical: "error",
2492
+ error: "error",
2493
+ warning: "warning"
2494
+ };
2495
+ var severityBorder = {
2496
+ critical: "border-l-2 border-l-danger",
2497
+ error: "border-l-2 border-l-danger",
2498
+ warning: "border-l-2 border-l-warning"
2499
+ };
2500
+ function formatRelativeTime(timestamp, timeLabels, locale) {
2501
+ const now = /* @__PURE__ */ new Date();
2502
+ const date = new Date(timestamp);
2503
+ const diffMs = now.getTime() - date.getTime();
2504
+ const diffMins = Math.floor(diffMs / 6e4);
2505
+ const diffHours = Math.floor(diffMs / 36e5);
2506
+ const diffDays = Math.floor(diffMs / 864e5);
2507
+ if (diffMins < 1) return timeLabels.justNow;
2508
+ if (diffMins < 60)
2509
+ return timeLabels.minutesAgo.replace("{minutes}", String(diffMins));
2510
+ if (diffHours < 24)
2511
+ return timeLabels.hoursAgo.replace("{hours}", String(diffHours));
2512
+ if (diffDays < 7)
2513
+ return timeLabels.daysAgo.replace("{days}", String(diffDays));
2514
+ return date.toLocaleDateString(locale);
2515
+ }
2516
+ function groupBy(items, key) {
2517
+ const map = /* @__PURE__ */ new Map();
2518
+ for (const item of items) {
2519
+ const k = key(item);
2520
+ const existing = map.get(k);
2521
+ if (existing) {
2522
+ existing.push(item);
2523
+ } else {
2524
+ map.set(k, [item]);
2525
+ }
2526
+ }
2527
+ return map;
2528
+ }
2529
+ function FailureItemRow({
2530
+ failure,
2531
+ isLast,
2532
+ onFailureClick,
2533
+ renderActions,
2534
+ mergedSeverityLabels,
2535
+ mergedTimeAgo,
2536
+ locale
2537
+ }) {
2538
+ const itemId = `failure-${failure.id}`;
2539
+ const handleKeyDown = (event) => {
2540
+ if (!onFailureClick) return;
2541
+ if (event.key !== "Enter" && event.key !== " ") return;
2542
+ event.preventDefault();
2543
+ onFailureClick(failure);
2544
+ };
2545
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2546
+ _chunkAFF2HPE5cjs.CompositeItem,
2547
+ {
2548
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "article", {}),
2549
+ role: "article",
2550
+ "aria-labelledby": itemId,
2551
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2552
+ "group gap-group relative flex w-full items-start p-3",
2553
+ _chunkAFF2HPE5cjs.OPT_FOCUS_VISIBLE,
2554
+ "data-[active-item]:bg-accent-subtle",
2555
+ onFailureClick && "cursor-pointer",
2556
+ !isLast && "border-border-subtle border-b",
2557
+ severityBorder[failure.severity]
2558
+ ),
2559
+ onClick: () => onFailureClick == null ? void 0 : onFailureClick(failure),
2560
+ onKeyDown: handleKeyDown,
2561
+ children: [
2562
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 flex-1", children: [
2563
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-element flex items-center", children: [
2564
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.Badge, { variant: severityVariant[failure.severity], size: "sm", children: mergedSeverityLabels[failure.severity] }),
2565
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2566
+ "span",
2567
+ {
2568
+ id: itemId,
2569
+ className: `text-sm font-medium ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY} truncate`,
2570
+ children: failure.title
2571
+ }
2572
+ )
2573
+ ] }),
2574
+ failure.message && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: `mt-1 text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY} line-clamp-2`, children: failure.message }),
2575
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2576
+ "time",
2577
+ {
2578
+ dateTime: failure.timestamp,
2579
+ className: `mt-1 block text-xs ${_chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY}`,
2580
+ children: formatRelativeTime(failure.timestamp, mergedTimeAgo, locale)
2581
+ }
2582
+ )
2583
+ ] }),
2584
+ renderActions && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex shrink-0 items-center gap-1", children: renderActions(failure) })
2585
+ ]
2586
+ },
2587
+ failure.id
2588
+ );
2589
+ }
2590
+ function FailureList({
2591
+ failures,
2592
+ title,
2593
+ maxItems,
2594
+ grouped = false,
2595
+ onFailureClick,
2596
+ onShowMore,
2597
+ labels: customLabels,
2598
+ locale = "ko-KR",
2599
+ loading = false,
2600
+ renderActions,
2601
+ className
2602
+ }) {
2603
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
2604
+ const mergedTimeAgo = {
2605
+ justNow: (_b = (_a = customLabels == null ? void 0 : customLabels.timeAgo) == null ? void 0 : _a.justNow) != null ? _b : defaultLabels13.timeAgo.justNow,
2606
+ minutesAgo: (_d = (_c = customLabels == null ? void 0 : customLabels.timeAgo) == null ? void 0 : _c.minutesAgo) != null ? _d : defaultLabels13.timeAgo.minutesAgo,
2607
+ hoursAgo: (_f = (_e = customLabels == null ? void 0 : customLabels.timeAgo) == null ? void 0 : _e.hoursAgo) != null ? _f : defaultLabels13.timeAgo.hoursAgo,
2608
+ daysAgo: (_h = (_g = customLabels == null ? void 0 : customLabels.timeAgo) == null ? void 0 : _g.daysAgo) != null ? _h : defaultLabels13.timeAgo.daysAgo
2609
+ };
2610
+ const mergedSeverityLabels = {
2611
+ critical: (_j = (_i = customLabels == null ? void 0 : customLabels.severityLabels) == null ? void 0 : _i.critical) != null ? _j : defaultLabels13.severityLabels.critical,
2612
+ error: (_l = (_k = customLabels == null ? void 0 : customLabels.severityLabels) == null ? void 0 : _k.error) != null ? _l : defaultLabels13.severityLabels.error,
2613
+ warning: (_n = (_m = customLabels == null ? void 0 : customLabels.severityLabels) == null ? void 0 : _m.warning) != null ? _n : defaultLabels13.severityLabels.warning
2614
+ };
2615
+ const labels = {
2616
+ title: (_o = customLabels == null ? void 0 : customLabels.title) != null ? _o : defaultLabels13.title,
2617
+ emptyMessage: (_p = customLabels == null ? void 0 : customLabels.emptyMessage) != null ? _p : defaultLabels13.emptyMessage,
2618
+ moreItems: (_q = customLabels == null ? void 0 : customLabels.moreItems) != null ? _q : defaultLabels13.moreItems
2619
+ };
2620
+ const displayTitle = title != null ? title : labels.title;
2621
+ const allItems = maxItems ? failures.slice(0, maxItems) : failures;
2622
+ const remainingCount = maxItems ? Math.max(0, failures.length - maxItems) : 0;
2623
+ const rowProps = {
2624
+ onFailureClick,
2625
+ renderActions,
2626
+ mergedSeverityLabels,
2627
+ mergedTimeAgo,
2628
+ locale
2629
+ };
2630
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2631
+ "div",
2632
+ {
2633
+ className,
2634
+ "data-opt-id": "ZAM3R",
2635
+ "data-opt-slug": "failure-list.FailureList",
2636
+ children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "gap-group flex flex-col", children: [
2637
+ displayTitle && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: `text-sm font-semibold ${_chunkAFF2HPE5cjs.OPT_TEXT_PRIMARY}`, children: displayTitle }),
2638
+ failures.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2639
+ "div",
2640
+ {
2641
+ role: "status",
2642
+ className: `py-8 text-center text-sm ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY}`,
2643
+ children: labels.emptyMessage
2644
+ }
2645
+ ) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAFF2HPE5cjs.CompositeProvider, { focusLoop: true, orientation: "vertical", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2646
+ _chunkAFF2HPE5cjs.Composite,
2647
+ {
2648
+ role: "feed",
2649
+ "aria-label": displayTitle,
2650
+ "aria-busy": loading,
2651
+ className: `rounded-lg ${_chunkAFF2HPE5cjs.OPT_BORDER} bg-surface`,
2652
+ children: grouped ? renderGrouped(
2653
+ allItems,
2654
+ remainingCount,
2655
+ rowProps,
2656
+ labels,
2657
+ onShowMore
2658
+ ) : renderFlat(
2659
+ allItems,
2660
+ remainingCount,
2661
+ rowProps,
2662
+ labels,
2663
+ onShowMore
2664
+ )
2665
+ }
2666
+ ) })
2667
+ ] })
2668
+ }
2669
+ );
2670
+ }
2671
+ function renderFlat(items, remainingCount, rowProps, labels, onShowMore) {
2672
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2673
+ items.map((failure, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2674
+ FailureItemRow,
2675
+ _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
2676
+ failure,
2677
+ isLast: index === items.length - 1 && remainingCount === 0
2678
+ }, rowProps),
2679
+ failure.id
2680
+ )),
2681
+ remainingCount > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2682
+ _chunkAFF2HPE5cjs.CompositeItem,
2683
+ {
2684
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button" }),
2685
+ onClick: onShowMore,
2686
+ className: `border-border-subtle w-full border-t p-3 text-center text-xs font-medium ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY} ${_chunkAFF2HPE5cjs.OPT_FOCUS} hover:text-accent data-[active-item]:bg-accent-subtle transition-colors`,
2687
+ "aria-label": `${remainingCount}\uAC1C\uC758 \uC2E4\uD328 \uB354 \uBCF4\uAE30`,
2688
+ children: labels.moreItems.replace("{count}", String(remainingCount))
2689
+ }
2690
+ )
2691
+ ] });
2692
+ }
2693
+ function renderGrouped(items, remainingCount, rowProps, labels, onShowMore) {
2694
+ const groups = groupBy(items, (f) => {
2695
+ var _a;
2696
+ return (_a = f.group) != null ? _a : "";
2697
+ });
2698
+ const groupEntries = Array.from(groups.entries());
2699
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
2700
+ groupEntries.map(([groupName, groupItems], groupIndex) => {
2701
+ const isLastGroup = groupIndex === groupEntries.length - 1 && remainingCount === 0;
2702
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { children: [
2703
+ groupName && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2704
+ "div",
2705
+ {
2706
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2707
+ `px-3 py-2 text-xs font-semibold ${_chunkAFF2HPE5cjs.OPT_TEXT_TERTIARY} tracking-wider uppercase`,
2708
+ groupIndex > 0 && "border-border-subtle border-t"
2709
+ ),
2710
+ children: groupName
2711
+ }
2712
+ ),
2713
+ groupItems.map((failure, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2714
+ FailureItemRow,
2715
+ _chunkONE3C5RVcjs.__spreadValues.call(void 0, {
2716
+ failure,
2717
+ isLast: isLastGroup && index === groupItems.length - 1
2718
+ }, rowProps),
2719
+ failure.id
2720
+ ))
2721
+ ] }, groupName || "__ungrouped__");
2722
+ }),
2723
+ remainingCount > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2724
+ _chunkAFF2HPE5cjs.CompositeItem,
2725
+ {
2726
+ render: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "button", { type: "button" }),
2727
+ onClick: onShowMore,
2728
+ className: `border-border-subtle w-full border-t p-3 text-center text-xs font-medium ${_chunkAFF2HPE5cjs.OPT_TEXT_SECONDARY} ${_chunkAFF2HPE5cjs.OPT_FOCUS} hover:text-accent data-[active-item]:bg-accent-subtle transition-colors`,
2729
+ "aria-label": `${remainingCount}\uAC1C\uC758 \uC2E4\uD328 \uB354 \uBCF4\uAE30`,
2730
+ children: labels.moreItems.replace("{count}", String(remainingCount))
2731
+ }
2732
+ )
2733
+ ] });
2734
+ }
2735
+
2736
+ // src/shells/key-value-editor.tsx
2737
+
2738
+
2739
+ var defaultLabels14 = {
2740
+ keyPlaceholder: "\uD0A4",
2741
+ valuePlaceholder: "\uAC12",
2742
+ addButton: "\uCD94\uAC00",
2743
+ removeAriaLabel: "\uD56D\uBAA9 \uC0AD\uC81C",
2744
+ toggleSecretAriaLabel: "\uBE44\uBC00\uAC12 \uD1A0\uAE00",
2745
+ emptyMessage: "\uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uCD94\uAC00 \uBC84\uD2BC\uC744 \uB20C\uB7EC\uC8FC\uC138\uC694."
2746
+ };
2747
+ var idCounter = 0;
2748
+ function generateId() {
2749
+ return `kv-${++idCounter}`;
2750
+ }
2751
+ function KeyValueEditor({
2752
+ value: controlledValue,
2753
+ defaultValue,
2754
+ onChange,
2755
+ showSecretToggle = false,
2756
+ maxEntries,
2757
+ readOnly = false,
2758
+ labels: customLabels,
2759
+ renderActions,
2760
+ validateKey,
2761
+ className
2762
+ }) {
2763
+ const labels = _chunkONE3C5RVcjs.__spreadValues.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, defaultLabels14), customLabels);
2764
+ const [internalEntries, setInternalEntries] = _react.useState.call(void 0,
2765
+ () => defaultValue != null ? defaultValue : []
2766
+ );
2767
+ const entries = controlledValue != null ? controlledValue : internalEntries;
2768
+ const keyInputRef = _react.useRef.call(void 0, null);
2769
+ const updateEntries = _react.useCallback.call(void 0,
2770
+ (next) => {
2771
+ if (!controlledValue) {
2772
+ setInternalEntries(next);
2773
+ }
2774
+ onChange == null ? void 0 : onChange(next);
2775
+ },
2776
+ [controlledValue, onChange]
2777
+ );
2778
+ const addEntry = _react.useCallback.call(void 0, () => {
2779
+ if (maxEntries && entries.length >= maxEntries) return;
2780
+ const newEntry = {
2781
+ id: generateId(),
2782
+ key: "",
2783
+ value: "",
2784
+ isSecret: false
2785
+ };
2786
+ updateEntries([...entries, newEntry]);
2787
+ requestAnimationFrame(() => {
2788
+ var _a, _b, _c;
2789
+ (_c = (_b = (_a = keyInputRef.current) == null ? void 0 : _a.closest("[data-kv-list]")) == null ? void 0 : _b.querySelector(
2790
+ `[data-kv-id="${newEntry.id}"] [data-kv-key]`
2791
+ )) == null ? void 0 : _c.focus();
2792
+ });
2793
+ }, [entries, maxEntries, updateEntries]);
2794
+ const removeEntry = _react.useCallback.call(void 0,
2795
+ (id) => {
2796
+ updateEntries(entries.filter((e) => e.id !== id));
2797
+ },
2798
+ [entries, updateEntries]
2799
+ );
2800
+ const updateEntry = _react.useCallback.call(void 0,
2801
+ (id, field, val) => {
2802
+ updateEntries(
2803
+ entries.map((e) => e.id === id ? _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, e), { [field]: val }) : e)
2804
+ );
2805
+ },
2806
+ [entries, updateEntries]
2807
+ );
2808
+ const toggleSecret = _react.useCallback.call(void 0,
2809
+ (id) => {
2810
+ updateEntries(
2811
+ entries.map((e) => e.id === id ? _chunkONE3C5RVcjs.__spreadProps.call(void 0, _chunkONE3C5RVcjs.__spreadValues.call(void 0, {}, e), { isSecret: !e.isSecret }) : e)
2812
+ );
2813
+ },
2814
+ [entries, updateEntries]
2815
+ );
2816
+ const canAdd = !readOnly && (!maxEntries || entries.length < maxEntries);
2817
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2818
+ "div",
2819
+ {
2820
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "gap-group flex flex-col", className),
2821
+ "data-opt-id": "NCBWA",
2822
+ "data-opt-slug": "key-value-editor.KeyValueEditor",
2823
+ children: [
2824
+ entries.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { className: "text-text-tertiary py-4 text-center text-sm", children: labels.emptyMessage }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "gap-element flex flex-col", "data-kv-list": true, children: entries.map((entry, index) => {
2825
+ const keyError = validateKey == null ? void 0 : validateKey(entry.key, entries);
2826
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2827
+ "div",
2828
+ {
2829
+ "data-kv-id": entry.id,
2830
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2831
+ "gap-element flex items-start",
2832
+ "border-border rounded-lg border p-3",
2833
+ "bg-surface"
2834
+ ),
2835
+ children: [
2836
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [
2837
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2838
+ "input",
2839
+ {
2840
+ "data-kv-key": true,
2841
+ ref: index === entries.length - 1 ? keyInputRef : void 0,
2842
+ type: "text",
2843
+ value: entry.key,
2844
+ onChange: (e) => updateEntry(entry.id, "key", e.target.value),
2845
+ placeholder: labels.keyPlaceholder,
2846
+ readOnly,
2847
+ "aria-label": `${labels.keyPlaceholder} ${index + 1}`,
2848
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2849
+ "border-border bg-bg-subtle text-text-primary placeholder:text-text-tertiary w-full rounded-md border px-3 py-1.5 font-mono text-sm",
2850
+ "focus:border-accent focus-visible:ring-ring focus-visible:ring-offset-ring-offset focus-visible:ring-2 focus-visible:ring-offset-1",
2851
+ readOnly && "cursor-default opacity-70",
2852
+ keyError && "border-error"
2853
+ )
2854
+ }
2855
+ ),
2856
+ keyError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-error text-xs", children: keyError })
2857
+ ] }),
2858
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-text-tertiary px-1 py-1.5", children: "=" }),
2859
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2860
+ "input",
2861
+ {
2862
+ type: entry.isSecret ? "password" : "text",
2863
+ value: entry.value,
2864
+ onChange: (e) => updateEntry(entry.id, "value", e.target.value),
2865
+ placeholder: labels.valuePlaceholder,
2866
+ readOnly,
2867
+ "aria-label": `${labels.valuePlaceholder} ${index + 1}`,
2868
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2869
+ "border-border bg-bg-subtle text-text-primary placeholder:text-text-tertiary w-full rounded-md border px-3 py-1.5 font-mono text-sm",
2870
+ "focus:border-accent focus-visible:ring-ring focus-visible:ring-offset-ring-offset focus-visible:ring-2 focus-visible:ring-offset-1",
2871
+ readOnly && "cursor-default opacity-70"
2872
+ )
2873
+ }
2874
+ ) }),
2875
+ showSecretToggle && !readOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2876
+ "button",
2877
+ {
2878
+ type: "button",
2879
+ onClick: () => toggleSecret(entry.id),
2880
+ "aria-label": labels.toggleSecretAriaLabel,
2881
+ "aria-pressed": entry.isSecret,
2882
+ className: "text-text-tertiary hover:text-text-primary shrink-0 rounded p-1.5 transition-colors",
2883
+ children: entry.isSecret ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2884
+ "svg",
2885
+ {
2886
+ className: "size-4",
2887
+ fill: "none",
2888
+ viewBox: "0 0 24 24",
2889
+ stroke: "currentColor",
2890
+ strokeWidth: 2,
2891
+ "aria-hidden": "true",
2892
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2893
+ "path",
2894
+ {
2895
+ strokeLinecap: "round",
2896
+ strokeLinejoin: "round",
2897
+ d: "M3.98 8.223A10.477 10.477 0 001.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.45 10.45 0 0112 4.5c4.756 0 8.773 3.162 10.065 7.498a10.523 10.523 0 01-4.293 5.774M6.228 6.228L3 3m3.228 3.228l3.65 3.65m7.894 7.894L21 21m-3.228-3.228l-3.65-3.65m0 0a3 3 0 10-4.243-4.243m4.242 4.242L9.88 9.88"
2898
+ }
2899
+ )
2900
+ }
2901
+ ) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
2902
+ "svg",
2903
+ {
2904
+ className: "size-4",
2905
+ fill: "none",
2906
+ viewBox: "0 0 24 24",
2907
+ stroke: "currentColor",
2908
+ strokeWidth: 2,
2909
+ "aria-hidden": "true",
2910
+ children: [
2911
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2912
+ "path",
2913
+ {
2914
+ strokeLinecap: "round",
2915
+ strokeLinejoin: "round",
2916
+ d: "M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"
2917
+ }
2918
+ ),
2919
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2920
+ "path",
2921
+ {
2922
+ strokeLinecap: "round",
2923
+ strokeLinejoin: "round",
2924
+ d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z"
2925
+ }
2926
+ )
2927
+ ]
2928
+ }
2929
+ )
2930
+ }
2931
+ ),
2932
+ renderActions == null ? void 0 : renderActions(entry, index),
2933
+ !readOnly && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2934
+ "button",
2935
+ {
2936
+ type: "button",
2937
+ onClick: () => removeEntry(entry.id),
2938
+ "aria-label": labels.removeAriaLabel,
2939
+ className: "text-text-tertiary hover:text-error shrink-0 rounded p-1.5 transition-colors",
2940
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2941
+ "svg",
2942
+ {
2943
+ className: "size-4",
2944
+ fill: "none",
2945
+ viewBox: "0 0 24 24",
2946
+ stroke: "currentColor",
2947
+ strokeWidth: 2,
2948
+ "aria-hidden": "true",
2949
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2950
+ "path",
2951
+ {
2952
+ strokeLinecap: "round",
2953
+ strokeLinejoin: "round",
2954
+ d: "M6 18L18 6M6 6l12 12"
2955
+ }
2956
+ )
2957
+ }
2958
+ )
2959
+ }
2960
+ )
2961
+ ]
2962
+ },
2963
+ entry.id
2964
+ );
2965
+ }) }),
2966
+ canAdd && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
2967
+ "button",
2968
+ {
2969
+ type: "button",
2970
+ onClick: addEntry,
2971
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
2972
+ "border-border text-text-secondary rounded-lg border border-dashed px-4 py-2 text-sm transition-colors",
2973
+ "hover:border-accent hover:text-accent"
2974
+ ),
2975
+ children: labels.addButton
2976
+ }
2977
+ )
2978
+ ]
2979
+ }
2980
+ );
2981
+ }
2982
+
2983
+ // src/shells/workflow-canvas.tsx
2984
+
2985
+
2986
+ var statusVariant = {
2987
+ idle: "default",
2988
+ running: "info",
2989
+ success: "success",
2990
+ error: "error"
2991
+ };
2992
+ function clamp(value, min, max) {
2993
+ return Math.max(min, Math.min(max, value));
2994
+ }
2995
+ function WorkflowCanvas({
2996
+ steps,
2997
+ connections = [],
2998
+ rows = 9,
2999
+ cols = 9,
3000
+ cellSize = 72,
3001
+ gap = 12,
3002
+ title = "Workflow Canvas",
3003
+ emptyMessage = "No workflow steps",
3004
+ selectedStepId,
3005
+ onSelectStep,
3006
+ onStepMove,
3007
+ renderStep,
3008
+ className
3009
+ }) {
3010
+ const stepMap = React.useMemo(
3011
+ () => new Map(steps.map((step) => [step.id, step])),
3012
+ [steps]
3013
+ );
3014
+ const width = cols * cellSize + (cols - 1) * gap;
3015
+ const height = rows * cellSize + (rows - 1) * gap;
3016
+ const renderDefaultStep = React.useCallback(
3017
+ (step, selected) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3018
+ "button",
3019
+ {
3020
+ type: "button",
3021
+ onClick: () => onSelectStep == null ? void 0 : onSelectStep(step),
3022
+ className: _chunkAFF2HPE5cjs.cn.call(void 0,
3023
+ "group absolute flex h-full w-full flex-col justify-between rounded-lg border p-2 text-left transition-colors",
3024
+ selected ? "border-accent bg-accent-subtle" : "border-border bg-surface hover:bg-bg-subtle"
3025
+ ),
3026
+ children: [
3027
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "text-text-primary truncate text-xs font-medium", children: step.title }),
3028
+ step.status && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3029
+ _chunkAFF2HPE5cjs.Badge,
3030
+ {
3031
+ variant: statusVariant[step.status],
3032
+ size: "sm",
3033
+ className: "w-fit",
3034
+ children: step.status
3035
+ }
3036
+ )
3037
+ ]
3038
+ }
3039
+ ),
3040
+ [onSelectStep]
3041
+ );
3042
+ const handleStepKeyDown = React.useCallback(
3043
+ (event, step) => {
3044
+ if (!onStepMove) {
3045
+ return;
3046
+ }
3047
+ let nextRow = step.row;
3048
+ let nextCol = step.col;
3049
+ switch (event.key) {
3050
+ case "ArrowUp":
3051
+ nextRow -= 1;
3052
+ break;
3053
+ case "ArrowDown":
3054
+ nextRow += 1;
3055
+ break;
3056
+ case "ArrowLeft":
3057
+ nextCol -= 1;
3058
+ break;
3059
+ case "ArrowRight":
3060
+ nextCol += 1;
3061
+ break;
3062
+ default:
3063
+ return;
3064
+ }
3065
+ event.preventDefault();
3066
+ onStepMove(
3067
+ step.id,
3068
+ clamp(nextRow, 0, rows - 1),
3069
+ clamp(nextCol, 0, cols - 1)
3070
+ );
3071
+ },
3072
+ [onStepMove, rows, cols]
3073
+ );
3074
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3075
+ "div",
3076
+ {
3077
+ className: _chunkAFF2HPE5cjs.cn.call(void 0, "gap-group flex flex-col", className),
3078
+ "data-opt-id": "4TX11",
3079
+ "data-opt-slug": "workflow-canvas.WorkflowCanvas",
3080
+ children: [
3081
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h3", { className: "text-text-primary text-sm font-semibold", children: title }),
3082
+ steps.length === 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "text-text-secondary border-border rounded-lg border border-dashed p-8 text-center text-sm", children: emptyMessage }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "border-border bg-bg-subtle relative overflow-auto rounded-lg border p-3", children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
3083
+ "div",
3084
+ {
3085
+ role: "grid",
3086
+ "aria-label": title,
3087
+ className: "relative",
3088
+ style: { width, height },
3089
+ children: [
3090
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3091
+ "div",
3092
+ {
3093
+ className: "grid",
3094
+ style: {
3095
+ gridTemplateColumns: `repeat(${cols}, ${cellSize}px)`,
3096
+ gridTemplateRows: `repeat(${rows}, ${cellSize}px)`,
3097
+ gap
3098
+ },
3099
+ children: Array.from({ length: rows * cols }, (_, i) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3100
+ "div",
3101
+ {
3102
+ "aria-hidden": "true",
3103
+ className: "border-border-subtle bg-surface/30 rounded-md border border-dashed"
3104
+ },
3105
+ i
3106
+ ))
3107
+ }
3108
+ ),
3109
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3110
+ "svg",
3111
+ {
3112
+ className: "pointer-events-none absolute inset-0",
3113
+ width,
3114
+ height,
3115
+ "aria-hidden": "true",
3116
+ children: connections.map((connection) => {
3117
+ const from = stepMap.get(connection.from);
3118
+ const to = stepMap.get(connection.to);
3119
+ if (!from || !to) {
3120
+ return null;
3121
+ }
3122
+ const x1 = from.col * (cellSize + gap) + cellSize / 2;
3123
+ const y1 = from.row * (cellSize + gap) + cellSize / 2;
3124
+ const x2 = to.col * (cellSize + gap) + cellSize / 2;
3125
+ const y2 = to.row * (cellSize + gap) + cellSize / 2;
3126
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "g", { children: [
3127
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3128
+ "line",
3129
+ {
3130
+ x1,
3131
+ y1,
3132
+ x2,
3133
+ y2,
3134
+ stroke: "currentColor",
3135
+ strokeOpacity: "0.35",
3136
+ strokeWidth: "2"
3137
+ }
3138
+ ),
3139
+ connection.label && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3140
+ "text",
3141
+ {
3142
+ x: (x1 + x2) / 2,
3143
+ y: (y1 + y2) / 2 - 4,
3144
+ textAnchor: "middle",
3145
+ className: "fill-text-secondary text-[10px]",
3146
+ children: connection.label
3147
+ }
3148
+ )
3149
+ ] }, `${connection.from}-${connection.to}`);
3150
+ })
3151
+ }
3152
+ ),
3153
+ steps.map((step) => {
3154
+ const selected = selectedStepId === step.id;
3155
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
3156
+ "div",
3157
+ {
3158
+ role: "gridcell",
3159
+ tabIndex: 0,
3160
+ "aria-selected": selected,
3161
+ "aria-label": `${step.title} (${step.row + 1}, ${step.col + 1})`,
3162
+ onKeyDown: (event) => handleStepKeyDown(event, step),
3163
+ className: "focus-visible:ring-ring absolute focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-white focus-visible:outline-none",
3164
+ style: {
3165
+ width: cellSize,
3166
+ height: cellSize,
3167
+ left: step.col * (cellSize + gap),
3168
+ top: step.row * (cellSize + gap)
3169
+ },
3170
+ children: renderStep ? renderStep(step, selected) : renderDefaultStep(step, selected)
3171
+ },
3172
+ step.id
3173
+ );
3174
+ })
3175
+ ]
3176
+ }
3177
+ ) })
3178
+ ]
3179
+ }
3180
+ );
3181
+ }
3182
+ WorkflowCanvas.displayName = "WorkflowCanvas";
3183
+
3184
+
3185
+
3186
+
3187
+
3188
+
3189
+
3190
+
3191
+
3192
+
3193
+
3194
+
3195
+
3196
+
3197
+
3198
+
3199
+
3200
+
3201
+
3202
+
3203
+
3204
+
3205
+
3206
+
3207
+
3208
+
3209
+
3210
+
3211
+
3212
+
3213
+
3214
+
3215
+
3216
+
3217
+
3218
+ exports.Command = Command; exports.CommandDialog = CommandDialog; exports.CommandInput = CommandInput; exports.CommandList = CommandList; exports.CommandEmpty = CommandEmpty; exports.CommandGroup = CommandGroup; exports.CommandSeparator = CommandSeparator; exports.CommandItem = CommandItem; exports.CommandShortcut = CommandShortcut; exports.CommandPalette = CommandPalette; exports.CommandPaletteTrigger = CommandPaletteTrigger; exports.DashboardGrid = DashboardGrid; exports.SearchCombobox = SearchCombobox; exports.StatusSelect = StatusSelect; exports.AppMenubar = AppMenubar; exports.SidebarNav = SidebarNav; exports.EditorToolbar = EditorToolbar; exports.ContentTabs = ContentTabs; exports.FaqAccordion = FaqAccordion; exports.SettingsForm = SettingsForm; exports.DeploymentTimeline = DeploymentTimeline; exports.ProjectSwitcher = ProjectSwitcher; exports.EnvPanel = EnvPanel; exports.BranchSelect = BranchSelect; exports.DomainTable = DomainTable; exports.DataTable = DataTable; exports.toast = toast; exports.ToastProvider = ToastProvider; exports.useToast = useToast; exports.NotificationToast = NotificationToast; exports.FailureList = FailureList; exports.KeyValueEditor = KeyValueEditor; exports.WorkflowCanvas = WorkflowCanvas;