@wipco/sdui 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +27 -0
  3. package/dist/chunk-4SU2KYPU.js +59 -0
  4. package/dist/chunk-56KKWLNI.js +186 -0
  5. package/dist/chunk-7Y4J7EOK.js +115 -0
  6. package/dist/chunk-APCXOCAO.js +110 -0
  7. package/dist/chunk-AROOQ5W6.js +119 -0
  8. package/dist/chunk-DGPRX4MU.js +251 -0
  9. package/dist/chunk-IL2KS4WS.js +25 -0
  10. package/dist/chunk-KADFN76X.js +541 -0
  11. package/dist/chunk-KBHI3IUR.js +40 -0
  12. package/dist/chunk-LZJTKVMO.js +767 -0
  13. package/dist/chunk-MOIU7MUA.js +282 -0
  14. package/dist/chunk-MSAV4J4I.js +77 -0
  15. package/dist/chunk-OOHHW4K4.js +159 -0
  16. package/dist/chunk-Q6SBH63R.js +190 -0
  17. package/dist/chunk-QZQDHSMD.js +78 -0
  18. package/dist/chunk-RH7ESUE6.js +309 -0
  19. package/dist/chunk-SEBPBUZR.js +260 -0
  20. package/dist/chunk-USKRM22W.js +39 -0
  21. package/dist/chunk-WNYWTFGW.js +61 -0
  22. package/dist/chunk-WVRCIVAD.js +72 -0
  23. package/dist/chunk-YJMD6MOE.js +404 -0
  24. package/dist/chunk-ZNITJ4KK.js +433 -0
  25. package/dist/chunk-ZQR3ULVH.js +193 -0
  26. package/dist/{chunk-QJHD6HVQ.js → chunk-ZUCI34QY.js} +106 -390
  27. package/dist/index.d.ts +306 -53
  28. package/dist/index.js +276 -720
  29. package/dist/meta.d.ts +8 -0
  30. package/dist/meta.js +147 -8
  31. package/dist/rich.js +3 -2
  32. package/dist/styles.css +246 -0
  33. package/dist/widgets/AutocompleteField.d.ts +96 -0
  34. package/dist/widgets/AutocompleteField.js +3 -0
  35. package/dist/widgets/ColumnBoard.d.ts +47 -0
  36. package/dist/widgets/ColumnBoard.js +2 -0
  37. package/dist/widgets/DiffView.d.ts +30 -0
  38. package/dist/widgets/DiffView.js +2 -0
  39. package/dist/widgets/Disclosure.d.ts +20 -0
  40. package/dist/widgets/Disclosure.js +2 -0
  41. package/dist/widgets/EventCalendar.d.ts +59 -0
  42. package/dist/widgets/EventCalendar.js +2 -0
  43. package/dist/widgets/ImageLightbox.d.ts +25 -0
  44. package/dist/widgets/ImageLightbox.js +2 -0
  45. package/dist/widgets/InlineEdit.d.ts +23 -0
  46. package/dist/widgets/InlineEdit.js +2 -0
  47. package/dist/widgets/JsonField.d.ts +24 -0
  48. package/dist/widgets/JsonField.js +2 -0
  49. package/dist/widgets/LiveClock.d.ts +21 -0
  50. package/dist/widgets/LiveClock.js +1 -0
  51. package/dist/widgets/OrgChart.d.ts +32 -0
  52. package/dist/widgets/OrgChart.js +2 -0
  53. package/dist/widgets/PeriodFilter.d.ts +48 -0
  54. package/dist/widgets/PeriodFilter.js +2 -0
  55. package/dist/widgets/PrintSheet.d.ts +23 -0
  56. package/dist/widgets/PrintSheet.js +2 -0
  57. package/dist/widgets/SearchableMultiPicker.d.ts +29 -0
  58. package/dist/widgets/SearchableMultiPicker.js +3 -0
  59. package/dist/widgets/SecureScreen.d.ts +25 -0
  60. package/dist/widgets/SecureScreen.js +2 -0
  61. package/dist/widgets/StackedMeter.d.ts +26 -0
  62. package/dist/widgets/StackedMeter.js +1 -0
  63. package/dist/widgets/Strip.d.ts +20 -0
  64. package/dist/widgets/Strip.js +1 -0
  65. package/dist/widgets/SummaryTable.d.ts +31 -0
  66. package/dist/widgets/SummaryTable.js +1 -0
  67. package/dist/widgets/TagMultiSelect.d.ts +25 -0
  68. package/dist/widgets/TagMultiSelect.js +2 -0
  69. package/dist/widgets/Timeline.d.ts +30 -0
  70. package/dist/widgets/Timeline.js +3 -0
  71. package/dist/widgets/TreePicker.d.ts +21 -0
  72. package/dist/widgets/TreePicker.js +3 -0
  73. package/dist/widgets/TreeView.d.ts +26 -0
  74. package/dist/widgets/TreeView.js +2 -0
  75. package/dist/widgets/index.d.ts +76 -0
  76. package/dist/widgets/index.js +69 -0
  77. package/package.json +93 -3
@@ -0,0 +1,433 @@
1
+ import { IconButton, Badge } from './chunk-ZUCI34QY.js';
2
+ import { useRef, useState, useMemo, useCallback, useEffect } from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ var NODE_W = 176;
6
+ var NODE_H = 64;
7
+ var SIBLING_GAP = 24;
8
+ var LEVEL_GAP = 48;
9
+ var CANVAS_PADDING = 48;
10
+ var MIN_ZOOM = 0.35;
11
+ var MAX_ZOOM = 1.8;
12
+ var ZOOM_STEP = 1.2;
13
+ var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
14
+ function buildBlock(node) {
15
+ const childBlocks = (node.children ?? []).map(buildBlock);
16
+ const childAreaWidth = childBlocks.reduce(
17
+ (total, block, index) => total + block.width + (index > 0 ? SIBLING_GAP : 0),
18
+ 0
19
+ );
20
+ const width = Math.max(NODE_W, childAreaWidth);
21
+ const nodeX = (width - NODE_W) / 2;
22
+ const nodes = [{ node, x: nodeX, y: 0 }];
23
+ const connectors = [];
24
+ let height = NODE_H;
25
+ if (childBlocks.length > 0) {
26
+ const childY = NODE_H + LEVEL_GAP;
27
+ let cursorX = (width - childAreaWidth) / 2;
28
+ let maxChildHeight = 0;
29
+ for (const block of childBlocks) {
30
+ nodes.push(
31
+ ...block.nodes.map((item) => ({
32
+ ...item,
33
+ x: item.x + cursorX,
34
+ y: item.y + childY
35
+ }))
36
+ );
37
+ connectors.push(
38
+ ...block.connectors.map((item) => ({
39
+ fromX: item.fromX + cursorX,
40
+ fromY: item.fromY + childY,
41
+ toX: item.toX + cursorX,
42
+ toY: item.toY + childY
43
+ }))
44
+ );
45
+ connectors.push({
46
+ fromX: width / 2,
47
+ fromY: NODE_H,
48
+ toX: block.topAnchor.x + cursorX,
49
+ toY: block.topAnchor.y + childY
50
+ });
51
+ maxChildHeight = Math.max(maxChildHeight, block.height);
52
+ cursorX += block.width + SIBLING_GAP;
53
+ }
54
+ height = childY + maxChildHeight;
55
+ }
56
+ return {
57
+ width,
58
+ height,
59
+ nodes,
60
+ connectors,
61
+ topAnchor: { x: width / 2, y: 0 }
62
+ };
63
+ }
64
+ function buildLayout(root) {
65
+ const block = buildBlock(root);
66
+ return {
67
+ width: block.width + CANVAS_PADDING * 2,
68
+ height: block.height + CANVAS_PADDING * 2,
69
+ nodes: block.nodes.map((item) => ({
70
+ ...item,
71
+ x: item.x + CANVAS_PADDING,
72
+ y: item.y + CANVAS_PADDING
73
+ })),
74
+ connectors: block.connectors.map((item) => ({
75
+ fromX: item.fromX + CANVAS_PADDING,
76
+ fromY: item.fromY + CANVAS_PADDING,
77
+ toX: item.toX + CANVAS_PADDING,
78
+ toY: item.toY + CANVAS_PADDING
79
+ }))
80
+ };
81
+ }
82
+ function connectorPath(connector) {
83
+ const midY = connector.fromY + (connector.toY - connector.fromY) / 2;
84
+ return `M ${connector.fromX} ${connector.fromY} V ${midY} H ${connector.toX} V ${connector.toY}`;
85
+ }
86
+ var nodeCardStyle = (selected) => ({
87
+ position: "absolute",
88
+ width: NODE_W,
89
+ height: NODE_H,
90
+ display: "flex",
91
+ flexDirection: "column",
92
+ justifyContent: "center",
93
+ gap: 2,
94
+ padding: "0 var(--wp-space-3)",
95
+ textAlign: "left",
96
+ background: "var(--wp-surface-card)",
97
+ border: "1px solid",
98
+ borderColor: selected ? "var(--wp-border-brand)" : "var(--wp-border-subtle)",
99
+ borderRadius: "var(--wp-radius-md)",
100
+ boxShadow: selected ? "var(--wp-ring-selected)" : "var(--wp-shadow-xs)",
101
+ cursor: "pointer",
102
+ transition: "box-shadow var(--wp-duration-fast), border-color var(--wp-duration-fast)"
103
+ });
104
+ function OrgChart({
105
+ root,
106
+ onNodeClick,
107
+ selectedId,
108
+ height = 520
109
+ }) {
110
+ const viewportRef = useRef(null);
111
+ const dragRef = useRef(null);
112
+ const [view, setView] = useState({ scale: 1, x: 0, y: 0 });
113
+ const [dragging, setDragging] = useState(false);
114
+ const [isFullscreen, setIsFullscreen] = useState(false);
115
+ const [internalSelected, setInternalSelected] = useState(
116
+ void 0
117
+ );
118
+ const effectiveSelected = selectedId ?? internalSelected;
119
+ const layout = useMemo(() => buildLayout(root), [root]);
120
+ const centerView = useCallback(
121
+ (scale = 1) => {
122
+ const rect = viewportRef.current?.getBoundingClientRect();
123
+ const viewportWidth = rect?.width ?? 0;
124
+ setView({
125
+ scale,
126
+ x: Math.max(0, (viewportWidth - layout.width * scale) / 2),
127
+ y: 0
128
+ });
129
+ },
130
+ [layout.width]
131
+ );
132
+ useEffect(() => {
133
+ centerView(1);
134
+ }, [centerView]);
135
+ useEffect(() => {
136
+ const handleChange = () => {
137
+ setIsFullscreen(document.fullscreenElement === viewportRef.current);
138
+ };
139
+ document.addEventListener("fullscreenchange", handleChange);
140
+ return () => document.removeEventListener("fullscreenchange", handleChange);
141
+ }, []);
142
+ const zoomAt = useCallback(
143
+ (nextScale, focal) => {
144
+ setView((current) => {
145
+ const scale = clamp(nextScale, MIN_ZOOM, MAX_ZOOM);
146
+ return {
147
+ scale,
148
+ x: focal.x - (focal.x - current.x) / current.scale * scale,
149
+ y: focal.y - (focal.y - current.y) / current.scale * scale
150
+ };
151
+ });
152
+ },
153
+ []
154
+ );
155
+ useEffect(() => {
156
+ const el = viewportRef.current;
157
+ if (!el) return;
158
+ const handleWheel = (event) => {
159
+ event.preventDefault();
160
+ const rect = el.getBoundingClientRect();
161
+ const focal = {
162
+ x: event.clientX - rect.left,
163
+ y: event.clientY - rect.top
164
+ };
165
+ setView((current) => {
166
+ const scale = clamp(
167
+ current.scale * (event.deltaY > 0 ? 0.9 : 1.1),
168
+ MIN_ZOOM,
169
+ MAX_ZOOM
170
+ );
171
+ return {
172
+ scale,
173
+ x: focal.x - (focal.x - current.x) / current.scale * scale,
174
+ y: focal.y - (focal.y - current.y) / current.scale * scale
175
+ };
176
+ });
177
+ };
178
+ el.addEventListener("wheel", handleWheel, { passive: false });
179
+ return () => el.removeEventListener("wheel", handleWheel);
180
+ }, []);
181
+ const viewportCenter = useCallback(() => {
182
+ const rect = viewportRef.current?.getBoundingClientRect();
183
+ if (!rect) return { x: 0, y: 0 };
184
+ return { x: rect.width / 2, y: rect.height / 2 };
185
+ }, []);
186
+ const handlePointerDown = (event) => {
187
+ if (event.target.closest("[data-orgchart-stop]")) return;
188
+ dragRef.current = {
189
+ pointerId: event.pointerId,
190
+ startX: event.clientX,
191
+ startY: event.clientY,
192
+ originX: view.x,
193
+ originY: view.y
194
+ };
195
+ setDragging(true);
196
+ event.currentTarget.setPointerCapture(event.pointerId);
197
+ };
198
+ const handlePointerMove = (event) => {
199
+ const drag = dragRef.current;
200
+ if (!drag || drag.pointerId !== event.pointerId) return;
201
+ setView((current) => ({
202
+ ...current,
203
+ x: drag.originX + event.clientX - drag.startX,
204
+ y: drag.originY + event.clientY - drag.startY
205
+ }));
206
+ };
207
+ const handlePointerUp = (event) => {
208
+ if (dragRef.current?.pointerId !== event.pointerId) return;
209
+ dragRef.current = null;
210
+ setDragging(false);
211
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) {
212
+ event.currentTarget.releasePointerCapture(event.pointerId);
213
+ }
214
+ };
215
+ const toggleFullscreen = async () => {
216
+ const viewport = viewportRef.current;
217
+ if (!viewport) return;
218
+ try {
219
+ if (document.fullscreenElement === viewport) {
220
+ await document.exitFullscreen();
221
+ } else {
222
+ await viewport.requestFullscreen();
223
+ }
224
+ } catch {
225
+ }
226
+ };
227
+ const handleNodeClick = (node) => {
228
+ if (selectedId === void 0) setInternalSelected(node.id);
229
+ onNodeClick?.(node);
230
+ };
231
+ return /* @__PURE__ */ jsxs(
232
+ "div",
233
+ {
234
+ ref: viewportRef,
235
+ role: "application",
236
+ "aria-label": "\uC870\uC9C1\uB3C4 \uCE94\uBC84\uC2A4",
237
+ onPointerDown: handlePointerDown,
238
+ onPointerMove: handlePointerMove,
239
+ onPointerUp: handlePointerUp,
240
+ onPointerCancel: handlePointerUp,
241
+ style: {
242
+ position: "relative",
243
+ height: isFullscreen ? "100vh" : height,
244
+ overflow: "hidden",
245
+ background: "var(--wp-surface-sunken)",
246
+ border: "1px solid var(--wp-border-subtle)",
247
+ borderRadius: "var(--wp-radius-md)",
248
+ cursor: dragging ? "grabbing" : "grab",
249
+ touchAction: "none",
250
+ overscrollBehavior: "contain",
251
+ userSelect: "none"
252
+ },
253
+ children: [
254
+ /* @__PURE__ */ jsxs(
255
+ "div",
256
+ {
257
+ "data-orgchart-stop": true,
258
+ style: {
259
+ position: "absolute",
260
+ top: "var(--wp-space-3)",
261
+ right: "var(--wp-space-3)",
262
+ zIndex: 2,
263
+ display: "flex",
264
+ alignItems: "center",
265
+ gap: "var(--wp-space-1)",
266
+ padding: "var(--wp-space-1)",
267
+ background: "var(--wp-surface-card)",
268
+ border: "1px solid var(--wp-border-subtle)",
269
+ borderRadius: "var(--wp-radius-md)",
270
+ boxShadow: "var(--wp-shadow-sm)",
271
+ cursor: "default"
272
+ },
273
+ children: [
274
+ /* @__PURE__ */ jsx(
275
+ IconButton,
276
+ {
277
+ icon: "zoom-out",
278
+ label: "\uCD95\uC18C",
279
+ size: "sm",
280
+ onClick: () => zoomAt(view.scale / ZOOM_STEP, viewportCenter()),
281
+ disabled: view.scale <= MIN_ZOOM
282
+ }
283
+ ),
284
+ /* @__PURE__ */ jsxs(
285
+ "span",
286
+ {
287
+ className: "wp-caption",
288
+ style: {
289
+ minWidth: 40,
290
+ textAlign: "center",
291
+ fontVariantNumeric: "tabular-nums",
292
+ color: "var(--wp-text-muted)"
293
+ },
294
+ children: [
295
+ Math.round(view.scale * 100),
296
+ "%"
297
+ ]
298
+ }
299
+ ),
300
+ /* @__PURE__ */ jsx(
301
+ IconButton,
302
+ {
303
+ icon: "zoom-in",
304
+ label: "\uD655\uB300",
305
+ size: "sm",
306
+ onClick: () => zoomAt(view.scale * ZOOM_STEP, viewportCenter()),
307
+ disabled: view.scale >= MAX_ZOOM
308
+ }
309
+ ),
310
+ /* @__PURE__ */ jsx(
311
+ IconButton,
312
+ {
313
+ icon: "rotate-ccw",
314
+ label: "\uBCF4\uAE30 \uCD08\uAE30\uD654",
315
+ size: "sm",
316
+ onClick: () => centerView(1)
317
+ }
318
+ ),
319
+ /* @__PURE__ */ jsx(
320
+ IconButton,
321
+ {
322
+ icon: isFullscreen ? "minimize" : "maximize",
323
+ label: isFullscreen ? "\uC804\uCCB4\uD654\uBA74 \uD574\uC81C" : "\uC804\uCCB4\uD654\uBA74",
324
+ size: "sm",
325
+ onClick: () => void toggleFullscreen()
326
+ }
327
+ )
328
+ ]
329
+ }
330
+ ),
331
+ /* @__PURE__ */ jsxs(
332
+ "div",
333
+ {
334
+ style: {
335
+ position: "absolute",
336
+ left: 0,
337
+ top: 0,
338
+ width: layout.width,
339
+ height: layout.height,
340
+ transform: `translate(${view.x}px, ${view.y}px) scale(${view.scale})`,
341
+ transformOrigin: "0 0"
342
+ },
343
+ children: [
344
+ /* @__PURE__ */ jsx(
345
+ "svg",
346
+ {
347
+ width: layout.width,
348
+ height: layout.height,
349
+ "aria-hidden": true,
350
+ style: {
351
+ position: "absolute",
352
+ left: 0,
353
+ top: 0,
354
+ pointerEvents: "none"
355
+ },
356
+ children: layout.connectors.map((connector, index) => /* @__PURE__ */ jsx(
357
+ "path",
358
+ {
359
+ d: connectorPath(connector),
360
+ fill: "none",
361
+ stroke: "var(--wp-border-strong)",
362
+ strokeWidth: 1.5
363
+ },
364
+ index
365
+ ))
366
+ }
367
+ ),
368
+ layout.nodes.map(({ node, x, y }) => {
369
+ const selected = node.id === effectiveSelected;
370
+ return /* @__PURE__ */ jsxs(
371
+ "button",
372
+ {
373
+ type: "button",
374
+ "data-orgchart-stop": true,
375
+ onClick: () => handleNodeClick(node),
376
+ "aria-pressed": selected,
377
+ style: { ...nodeCardStyle(selected), left: x, top: y },
378
+ children: [
379
+ /* @__PURE__ */ jsxs(
380
+ "span",
381
+ {
382
+ style: {
383
+ display: "flex",
384
+ alignItems: "center",
385
+ gap: "var(--wp-space-2)",
386
+ minWidth: 0
387
+ },
388
+ children: [
389
+ /* @__PURE__ */ jsx(
390
+ "span",
391
+ {
392
+ className: "wp-body-sm",
393
+ style: {
394
+ fontWeight: 600,
395
+ color: "var(--wp-text-strong)",
396
+ whiteSpace: "nowrap",
397
+ overflow: "hidden",
398
+ textOverflow: "ellipsis"
399
+ },
400
+ children: node.label
401
+ }
402
+ ),
403
+ node.badge && /* @__PURE__ */ jsx(Badge, { tone: selected ? "brand" : "neutral", children: node.badge })
404
+ ]
405
+ }
406
+ ),
407
+ node.sub && /* @__PURE__ */ jsx(
408
+ "span",
409
+ {
410
+ className: "wp-caption",
411
+ style: {
412
+ color: "var(--wp-text-muted)",
413
+ whiteSpace: "nowrap",
414
+ overflow: "hidden",
415
+ textOverflow: "ellipsis"
416
+ },
417
+ children: node.sub
418
+ }
419
+ )
420
+ ]
421
+ },
422
+ node.id
423
+ );
424
+ })
425
+ ]
426
+ }
427
+ )
428
+ ]
429
+ }
430
+ );
431
+ }
432
+
433
+ export { OrgChart };
@@ -0,0 +1,193 @@
1
+ import { TreeView } from './chunk-SEBPBUZR.js';
2
+ import { Field, Dialog, Icon, Button, Input } from './chunk-ZUCI34QY.js';
3
+ import { useState, useEffect } from 'react';
4
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
+
6
+ var PICKER_CSS = `
7
+ .erp-treepicker__none{transition:background var(--wp-duration-fast) var(--wp-ease-out);}
8
+ .erp-treepicker__none:hover{background:var(--wp-surface-hover);}
9
+ .erp-treepicker__none:focus-visible{outline:none;box-shadow:var(--wp-ring-focus);}
10
+ .erp-treepicker__none[aria-current='true'],
11
+ .erp-treepicker__none[aria-current='true']:hover{background:var(--wp-surface-selected);}
12
+ `;
13
+ function findNode(nodes, id) {
14
+ for (const node of nodes) {
15
+ if (node.id === id) return node;
16
+ if (node.children) {
17
+ const found = findNode(node.children, id);
18
+ if (found) return found;
19
+ }
20
+ }
21
+ return void 0;
22
+ }
23
+ function TreePicker({
24
+ nodes,
25
+ value,
26
+ valueLabel,
27
+ onChange,
28
+ label,
29
+ placeholder = "\uC120\uD0DD \uC548 \uD568",
30
+ excludeIds,
31
+ allowEmpty = true,
32
+ disabled = false
33
+ }) {
34
+ const [open, setOpen] = useState(false);
35
+ const [pendingId, setPendingId] = useState(null);
36
+ const [innerValue, setInnerValue] = useState(null);
37
+ const isControlled = value !== void 0;
38
+ const current = isControlled ? value : innerValue;
39
+ const currentNode = current != null ? findNode(nodes, current) : void 0;
40
+ const displayLabel = current == null ? "" : currentNode?.label ?? valueLabel ?? current;
41
+ const openDialog = () => {
42
+ if (disabled) return;
43
+ setPendingId(current ?? null);
44
+ setOpen(true);
45
+ };
46
+ const closeDialog = () => setOpen(false);
47
+ const commit = () => {
48
+ const node = pendingId != null ? findNode(nodes, pendingId) : void 0;
49
+ if (!isControlled) setInnerValue(pendingId);
50
+ onChange?.(pendingId, node);
51
+ setOpen(false);
52
+ };
53
+ useEffect(() => {
54
+ if (!open) return;
55
+ const onKeyDown = (event) => {
56
+ if (event.key === "Escape") setOpen(false);
57
+ };
58
+ document.addEventListener("keydown", onKeyDown);
59
+ return () => document.removeEventListener("keydown", onKeyDown);
60
+ }, [open]);
61
+ const commitDisabled = !allowEmpty && pendingId == null;
62
+ const noneSelected = pendingId == null;
63
+ const trigger = /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "var(--wp-space-2)", minWidth: 0 }, children: [
64
+ /* @__PURE__ */ jsx("div", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ jsx(
65
+ Input,
66
+ {
67
+ readOnly: true,
68
+ value: displayLabel,
69
+ placeholder,
70
+ icon: "git-branch",
71
+ disabled,
72
+ "aria-label": label ?? "\uD56D\uBAA9 \uC120\uD0DD",
73
+ style: { cursor: disabled ? void 0 : "pointer" },
74
+ onClick: openDialog,
75
+ onKeyDown: (event) => {
76
+ if (!disabled && (event.key === "Enter" || event.key === " ")) {
77
+ event.preventDefault();
78
+ openDialog();
79
+ }
80
+ }
81
+ }
82
+ ) }),
83
+ /* @__PURE__ */ jsx(
84
+ Button,
85
+ {
86
+ variant: "secondary",
87
+ onClick: openDialog,
88
+ disabled,
89
+ title: disabled ? "\uC9C0\uAE08\uC740 \uC120\uD0DD\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" : void 0,
90
+ style: { flexShrink: 0 },
91
+ children: "\uC120\uD0DD"
92
+ }
93
+ )
94
+ ] });
95
+ return /* @__PURE__ */ jsxs("div", { className: "erp-treepicker", style: { minWidth: 0 }, children: [
96
+ /* @__PURE__ */ jsx("style", { children: PICKER_CSS }),
97
+ label ? /* @__PURE__ */ jsx(Field, { label, children: trigger }) : trigger,
98
+ open ? /* @__PURE__ */ jsx(
99
+ "div",
100
+ {
101
+ style: { position: "fixed", inset: 0, zIndex: "var(--wp-z-dialog)" },
102
+ onClick: (event) => {
103
+ if (event.target instanceof HTMLElement && event.target.classList.contains("wp-overlay")) {
104
+ closeDialog();
105
+ }
106
+ },
107
+ children: /* @__PURE__ */ jsx(
108
+ Dialog,
109
+ {
110
+ title: label ?? "\uD56D\uBAA9 \uC120\uD0DD",
111
+ subtitle: "\uD2B8\uB9AC\uC5D0\uC11C \uD56D\uBAA9\uC744 \uC120\uD0DD\uD55C \uB4A4 [\uC120\uD0DD]\uC744 \uB204\uB974\uC138\uC694.",
112
+ icon: "git-branch",
113
+ size: "md",
114
+ onClose: closeDialog,
115
+ footer: /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: closeDialog, children: "\uCDE8\uC18C" }),
117
+ /* @__PURE__ */ jsx(
118
+ Button,
119
+ {
120
+ variant: "primary",
121
+ onClick: commit,
122
+ disabled: commitDisabled,
123
+ title: commitDisabled ? "\uC120\uD0DD\uD560 \uD56D\uBAA9\uC744 \uC9C0\uC815\uD558\uC138\uC694" : void 0,
124
+ children: "\uC120\uD0DD"
125
+ }
126
+ )
127
+ ] }),
128
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "var(--wp-space-2)", minWidth: 0 }, children: [
129
+ allowEmpty ? /* @__PURE__ */ jsxs(
130
+ "div",
131
+ {
132
+ role: "radio",
133
+ "aria-checked": noneSelected,
134
+ "aria-current": noneSelected ? "true" : void 0,
135
+ tabIndex: 0,
136
+ className: "erp-treepicker__none",
137
+ style: {
138
+ display: "flex",
139
+ alignItems: "center",
140
+ gap: "var(--wp-space-2)",
141
+ minHeight: "var(--wp-row-h-dense)",
142
+ padding: "0 var(--wp-space-2)",
143
+ borderRadius: "var(--wp-radius-sm)",
144
+ cursor: "pointer",
145
+ userSelect: "none"
146
+ },
147
+ onClick: () => setPendingId(null),
148
+ onKeyDown: (event) => {
149
+ if (event.key === "Enter" || event.key === " ") {
150
+ event.preventDefault();
151
+ setPendingId(null);
152
+ }
153
+ },
154
+ children: [
155
+ /* @__PURE__ */ jsx(
156
+ Icon,
157
+ {
158
+ name: noneSelected ? "circle-dot" : "circle-x",
159
+ size: 16,
160
+ style: { flexShrink: 0, color: noneSelected ? "var(--wp-text-brand)" : "var(--wp-text-muted)" }
161
+ }
162
+ ),
163
+ /* @__PURE__ */ jsx(
164
+ "span",
165
+ {
166
+ className: "wp-body-sm",
167
+ style: { color: noneSelected ? "var(--wp-text-strong)" : "var(--wp-text-muted)" },
168
+ children: "(\uC5C6\uC74C)"
169
+ }
170
+ )
171
+ ]
172
+ }
173
+ ) : null,
174
+ /* @__PURE__ */ jsx(
175
+ TreeView,
176
+ {
177
+ nodes,
178
+ selectedId: pendingId,
179
+ onSelect: (id) => setPendingId(id),
180
+ searchable: true,
181
+ excludeIds,
182
+ maxHeight: "320px"
183
+ }
184
+ )
185
+ ] })
186
+ }
187
+ )
188
+ }
189
+ ) : null
190
+ ] });
191
+ }
192
+
193
+ export { TreePicker };