@wipco/sdui 1.9.0 → 1.9.2

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 (84) hide show
  1. package/dist/{chunk-SMVPMDWO.js → chunk-35GI6LM5.js} +2 -2
  2. package/dist/{chunk-J2SPMIMO.js → chunk-3L4EXK3X.js} +2 -2
  3. package/dist/{chunk-VSCAW4LS.js → chunk-3XUHKSJM.js} +1 -1
  4. package/dist/{chunk-NKRZVRGH.js → chunk-45GIMFRP.js} +4 -2
  5. package/dist/{chunk-3M64LBYZ.js → chunk-5DLUGN5M.js} +2 -2
  6. package/dist/{chunk-55524GIB.js → chunk-5N4ESLPX.js} +2 -2
  7. package/dist/{chunk-RT2I2U45.js → chunk-77OM6OQG.js} +1 -1
  8. package/dist/{chunk-UYOQ3SEG.js → chunk-BBA7KKG4.js} +1 -1
  9. package/dist/{chunk-NHKQZDBX.js → chunk-BOL536MN.js} +2 -2
  10. package/dist/{chunk-TYPNHH3I.js → chunk-BT5P3DW6.js} +1 -1
  11. package/dist/{chunk-ZHWBTWHS.js → chunk-CBY6ACMR.js} +2 -2
  12. package/dist/{chunk-IOQNDAWT.js → chunk-CKZ66V5Q.js} +13 -156
  13. package/dist/{chunk-LK7MHTJO.js → chunk-CRSNVEUE.js} +2 -2
  14. package/dist/{chunk-RMYGRGKS.js → chunk-DE7FPWVJ.js} +1 -1
  15. package/dist/{chunk-SANCYRIQ.js → chunk-EH5QJJQE.js} +1 -1
  16. package/dist/{chunk-3LPLTD66.js → chunk-EKNEBGNW.js} +245 -8
  17. package/dist/chunk-FLBU7AVR.js +130 -0
  18. package/dist/{chunk-I45MRYCE.js → chunk-FVONSLW3.js} +2 -2
  19. package/dist/{chunk-Z2SOMUZF.js → chunk-GAABHPGR.js} +1 -1
  20. package/dist/{chunk-33LRJ25P.js → chunk-GLAG6ZT3.js} +152 -123
  21. package/dist/{chunk-FR7S52ZL.js → chunk-HNMBEUBO.js} +1 -1
  22. package/dist/{chunk-A2PG44CM.js → chunk-HR2U2QGN.js} +1 -1
  23. package/dist/{chunk-LDIEWJNP.js → chunk-KMNC3Q4J.js} +2 -2
  24. package/dist/{chunk-GHKRT7EA.js → chunk-LRDGT4T4.js} +1 -1
  25. package/dist/{chunk-LEYVJAXU.js → chunk-M4CZZMZJ.js} +3 -3
  26. package/dist/{chunk-4FQB6O4T.js → chunk-MBROAHA6.js} +5 -5
  27. package/dist/{chunk-GW2LSUA4.js → chunk-MLWNI4HI.js} +1 -1
  28. package/dist/{chunk-HKYLKLF6.js → chunk-MY7VBYHI.js} +2 -2
  29. package/dist/{chunk-CZMSQ3B3.js → chunk-PPOQY3V5.js} +1 -1
  30. package/dist/{chunk-VGNLXT3A.js → chunk-Q6V7E2H5.js} +1 -1
  31. package/dist/{chunk-MIFCOTLQ.js → chunk-QDCP6P3K.js} +2 -2
  32. package/dist/{chunk-UX37MB4P.js → chunk-QM2YJS7J.js} +3 -3
  33. package/dist/{chunk-Z5Q44VXX.js → chunk-QZMMW3JC.js} +1 -1
  34. package/dist/{chunk-GUXKGL76.js → chunk-T5ZHEXGK.js} +1 -1
  35. package/dist/{chunk-DELAII7K.js → chunk-TVJS5JAK.js} +2 -2
  36. package/dist/{chunk-LNEFMVHL.js → chunk-VGWOOPHH.js} +3 -3
  37. package/dist/{chunk-F2ICWCV3.js → chunk-WIQIJDEC.js} +1 -1
  38. package/dist/{chunk-MRCTYYBS.js → chunk-WS3QZIYN.js} +2 -2
  39. package/dist/{chunk-YMJUK3V4.js → chunk-WZS7KYOS.js} +2 -2
  40. package/dist/{chunk-JHWJSVZH.js → chunk-YSRJPBMO.js} +2 -2
  41. package/dist/{chunk-DE3HYL4K.js → chunk-ZAESY6NX.js} +2 -2
  42. package/dist/{chunk-NTMFLJEE.js → chunk-ZSKQUIYR.js} +4 -4
  43. package/dist/index.d.ts +8 -0
  44. package/dist/index.js +17 -17
  45. package/dist/meta.js +57 -3
  46. package/dist/rich/ExcelUploadCard.js +3 -3
  47. package/dist/rich.js +5 -5
  48. package/dist/widgets/ApprovalLineEditor.js +7 -7
  49. package/dist/widgets/ApprovalOverridesEditor.js +9 -9
  50. package/dist/widgets/ApprovalStepper.js +2 -2
  51. package/dist/widgets/AutocompleteField.js +7 -7
  52. package/dist/widgets/ColumnBoard.js +2 -2
  53. package/dist/widgets/DiffView.js +2 -2
  54. package/dist/widgets/Disclosure.js +2 -2
  55. package/dist/widgets/EventCalendar.js +3 -3
  56. package/dist/widgets/FileDropzone.d.ts +1 -0
  57. package/dist/widgets/FileDropzone.js +5 -5
  58. package/dist/widgets/ImageLightbox.d.ts +5 -0
  59. package/dist/widgets/ImageLightbox.js +4 -3
  60. package/dist/widgets/InlineEdit.js +2 -2
  61. package/dist/widgets/JsonField.js +2 -2
  62. package/dist/widgets/OptionSchemaEditor.js +3 -3
  63. package/dist/widgets/OptionValueFields.js +3 -3
  64. package/dist/widgets/OrgChart.js +2 -2
  65. package/dist/widgets/OrgChartBoard.js +5 -5
  66. package/dist/widgets/PeriodFilter.js +4 -4
  67. package/dist/widgets/PermissionMatrixEditor.js +3 -3
  68. package/dist/widgets/PositionSelect.js +3 -3
  69. package/dist/widgets/PrintSheet.js +2 -2
  70. package/dist/widgets/ProfileEditDiffCard.js +3 -3
  71. package/dist/widgets/QRDisplay.js +3 -3
  72. package/dist/widgets/RankBoard.js +4 -4
  73. package/dist/widgets/RoleMemberPicker.js +4 -4
  74. package/dist/widgets/SearchableMultiPicker.js +5 -5
  75. package/dist/widgets/SecureScreen.js +2 -2
  76. package/dist/widgets/StagePeriodEditor.js +4 -4
  77. package/dist/widgets/TagInput.js +2 -2
  78. package/dist/widgets/TagMultiSelect.js +3 -3
  79. package/dist/widgets/Timeline.js +3 -3
  80. package/dist/widgets/TreePicker.js +6 -6
  81. package/dist/widgets/TreeView.js +5 -5
  82. package/dist/widgets/index.js +71 -71
  83. package/package.json +1 -1
  84. package/dist/chunk-5NDYDUMJ.js +0 -73
@@ -0,0 +1,130 @@
1
+ import { looksLikeImage, safeFileHref, fileDisplayNameOf, FileTile, fileBadgeOf, ImageViewer } from './chunk-EKNEBGNW.js';
2
+ import { useSduiSandbox } from './chunk-DE7FPWVJ.js';
3
+ import { boxed } from './chunk-3JTBOABA.js';
4
+ import { useState } from 'react';
5
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
+
7
+ var BOX_KEYS = [
8
+ "width",
9
+ "height",
10
+ "minWidth",
11
+ "minHeight",
12
+ "maxWidth",
13
+ "maxHeight",
14
+ "borderRadius",
15
+ "margin",
16
+ "marginTop",
17
+ "marginRight",
18
+ "marginBottom",
19
+ "marginLeft",
20
+ "flex",
21
+ "flexGrow",
22
+ "flexShrink",
23
+ "flexBasis",
24
+ "alignSelf"
25
+ ];
26
+ function tileBoxOf(thumbStyle) {
27
+ if (!thumbStyle || thumbStyle.width === void 0 && thumbStyle.height === void 0) return null;
28
+ const box = {};
29
+ for (const key of BOX_KEYS) {
30
+ if (thumbStyle[key] !== void 0) box[key] = thumbStyle[key];
31
+ }
32
+ if (box.width === void 0) box.minWidth ??= 72;
33
+ if (box.height === void 0) box.minHeight ??= 72;
34
+ return box;
35
+ }
36
+ function ImageLightboxImpl({
37
+ src,
38
+ alt,
39
+ mimeType,
40
+ thumbClassName,
41
+ thumbStyle,
42
+ children
43
+ }) {
44
+ const [open, setOpen] = useState(false);
45
+ const [failedSrc, setFailedSrc] = useState(null);
46
+ const sandbox = useSduiSandbox();
47
+ const source = typeof src === "string" ? src : "";
48
+ const item = { url: source, mimeType };
49
+ const asImage = looksLikeImage(item) && failedSrc !== source;
50
+ const href = sandbox ? null : safeFileHref(source);
51
+ const openViewer = (event) => {
52
+ event.stopPropagation();
53
+ if (asImage) {
54
+ setOpen(true);
55
+ return;
56
+ }
57
+ if (href && typeof window !== "undefined") window.open(href, "_blank", "noopener");
58
+ };
59
+ const overlay = asImage ? /* @__PURE__ */ jsx(
60
+ ImageViewer,
61
+ {
62
+ src,
63
+ alt,
64
+ open,
65
+ onClose: () => setOpen(false)
66
+ }
67
+ ) : null;
68
+ if (children) {
69
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
70
+ /* @__PURE__ */ jsx(
71
+ "span",
72
+ {
73
+ style: { display: "contents" },
74
+ onClick: openViewer,
75
+ onKeyDown: (event) => {
76
+ if (event.key === "Enter" || event.key === " ") {
77
+ event.preventDefault();
78
+ openViewer(event);
79
+ }
80
+ },
81
+ children
82
+ }
83
+ ),
84
+ overlay
85
+ ] });
86
+ }
87
+ if (!asImage) {
88
+ const box = tileBoxOf(thumbStyle);
89
+ const name = alt && alt.trim() !== "" ? alt : fileDisplayNameOf(item);
90
+ return /* @__PURE__ */ jsx(
91
+ FileTile,
92
+ {
93
+ href,
94
+ name,
95
+ badge: fileBadgeOf(item),
96
+ layout: box ? "tile" : "row",
97
+ style: box ?? void 0,
98
+ className: thumbClassName
99
+ }
100
+ );
101
+ }
102
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
103
+ /* @__PURE__ */ jsx(
104
+ "img",
105
+ {
106
+ src,
107
+ alt: alt ?? "",
108
+ role: "button",
109
+ tabIndex: 0,
110
+ className: thumbClassName,
111
+ style: { cursor: "zoom-in", ...thumbStyle },
112
+ onClick: openViewer,
113
+ onKeyDown: (event) => {
114
+ if (event.key === "Enter" || event.key === " ") {
115
+ event.preventDefault();
116
+ openViewer(event);
117
+ }
118
+ },
119
+ onError: () => setFailedSrc(source)
120
+ }
121
+ ),
122
+ overlay
123
+ ] });
124
+ }
125
+ var ImageLightbox = boxed(
126
+ ImageLightboxImpl,
127
+ "ImageLightbox"
128
+ );
129
+
130
+ export { ImageLightbox };
@@ -1,5 +1,5 @@
1
- import { DateRangePicker } from './chunk-LDIEWJNP.js';
2
- import { SegmentedControl, Select } from './chunk-NKRZVRGH.js';
1
+ import { DateRangePicker } from './chunk-KMNC3Q4J.js';
2
+ import { SegmentedControl, Select } from './chunk-45GIMFRP.js';
3
3
  import { boxed } from './chunk-3JTBOABA.js';
4
4
  import { useState, useMemo } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { IconButton, Input } from './chunk-NKRZVRGH.js';
1
+ import { IconButton, Input } from './chunk-45GIMFRP.js';
2
2
  import { boxed } from './chunk-3JTBOABA.js';
3
3
  import { useState, useRef, useEffect, useCallback } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,9 +1,10 @@
1
- import { ellipsisStyle, unwrapRows } from './chunk-A2PG44CM.js';
2
- import { includesLooseSearch } from './chunk-MIFCOTLQ.js';
3
- import { useSduiAdapter, hostFetchOf } from './chunk-RMYGRGKS.js';
4
- import { Icon, Input, Spinner, Button } from './chunk-NKRZVRGH.js';
1
+ import { ellipsisStyle, unwrapRows } from './chunk-HR2U2QGN.js';
2
+ import { includesLooseSearch } from './chunk-QDCP6P3K.js';
3
+ import { useDismiss, usePopoverAnchor, usePortalTo, usePanelPointer, AnchoredPopoverStyles, focusStaysInside, anchorStyle } from './chunk-HNMBEUBO.js';
4
+ import { useSduiAdapter, hostFetchOf } from './chunk-DE7FPWVJ.js';
5
+ import { Icon, Input, Spinner, Button } from './chunk-45GIMFRP.js';
5
6
  import { boxed } from './chunk-3JTBOABA.js';
6
- import { useId, useRef, useMemo, useState, useEffect } from 'react';
7
+ import { useId, useRef, useMemo, useState, useEffect, useCallback } from 'react';
7
8
  import { jsxs, jsx } from 'react/jsx-runtime';
8
9
 
9
10
  function endpointSearchFn(endpoint, searchParam, hostFetch) {
@@ -32,6 +33,20 @@ function pickText(option, key) {
32
33
  var statusRowStyle = {
33
34
  padding: "var(--wp-space-2) var(--wp-space-3)"
34
35
  };
36
+ var LIST_MAX_HEIGHT = 280;
37
+ var LIST_ESTIMATE = LIST_MAX_HEIGHT + 10;
38
+ function listPopStyle(anchor) {
39
+ const base = anchorStyle(anchor);
40
+ if (!base || !anchor) return base;
41
+ return { ...base, width: anchor.minWidth, minWidth: 0, maxWidth: "calc(100vw - 16px)", boxSizing: "border-box" };
42
+ }
43
+ var listBoxStyle = {
44
+ maxHeight: `min(${LIST_MAX_HEIGHT}px, var(--wp-pop-avail, ${LIST_MAX_HEIGHT}px))`,
45
+ overflowY: "auto",
46
+ overscrollBehavior: "contain",
47
+ padding: "var(--wp-space-1)"
48
+ };
49
+ var keepFocusInField = (event) => event.preventDefault();
35
50
  function optionRowStyle(active) {
36
51
  return {
37
52
  display: "block",
@@ -102,6 +117,7 @@ function AutocompleteFieldImpl({
102
117
  const [activeIndex, setActiveIndex] = useState(0);
103
118
  const [focusPending, setFocusPending] = useState(false);
104
119
  const listRef = useRef(null);
120
+ const popRef = useRef(null);
105
121
  const [typedSeq, setTypedSeq] = useState(0);
106
122
  const [ownLinked, setOwnLinked] = useState(false);
107
123
  const linked = freeText && (selected ?? ownLinked);
@@ -109,6 +125,17 @@ function AutocompleteFieldImpl({
109
125
  useEffect(() => {
110
126
  if (linked) unlinkSentRef.current = false;
111
127
  }, [linked]);
128
+ const dismiss = useCallback(() => setOpen(false), []);
129
+ useDismiss(open, hostRef, popRef, dismiss);
130
+ const anchor = usePopoverAnchor(open, hostRef, popRef, LIST_ESTIMATE);
131
+ const portal = usePortalTo();
132
+ const pointer = usePanelPointer(popRef);
133
+ const anchored = anchor !== null;
134
+ const handleHostBlur = (event) => {
135
+ if (!open) return;
136
+ if (focusStaysInside(event.relatedTarget, hostRef, popRef, pointer)) return;
137
+ setOpen(false);
138
+ };
112
139
  useEffect(() => {
113
140
  if (!open) return;
114
141
  const box = listRef.current;
@@ -118,7 +145,7 @@ function AutocompleteFieldImpl({
118
145
  const bottom = top + active.offsetHeight;
119
146
  if (top < box.scrollTop) box.scrollTop = top;
120
147
  else if (bottom > box.scrollTop + box.clientHeight) box.scrollTop = bottom - box.clientHeight;
121
- }, [open, activeIndex, listId, results]);
148
+ }, [open, anchored, activeIndex, listId, results]);
122
149
  useEffect(() => {
123
150
  if (disabled || cardMode) return;
124
151
  const keyword = query.trim();
@@ -162,22 +189,6 @@ function AutocompleteFieldImpl({
162
189
  controller.abort();
163
190
  };
164
191
  }, [query, typedSeq, hasSearch, labelKey, subKey, minChars, debounceMs, disabled, cardMode]);
165
- useEffect(() => {
166
- if (!open) return;
167
- const closeOnOutsideClick = (event) => {
168
- if (event.target instanceof Node && hostRef.current?.contains(event.target)) return;
169
- setOpen(false);
170
- };
171
- const closeOnEscape = (event) => {
172
- if (event.key === "Escape") setOpen(false);
173
- };
174
- document.addEventListener("pointerdown", closeOnOutsideClick);
175
- document.addEventListener("keydown", closeOnEscape);
176
- return () => {
177
- document.removeEventListener("pointerdown", closeOnOutsideClick);
178
- document.removeEventListener("keydown", closeOnEscape);
179
- };
180
- }, [open]);
181
192
  useEffect(() => {
182
193
  if (!focusPending || hasSelection) return;
183
194
  hostRef.current?.querySelector("input")?.focus();
@@ -266,7 +277,6 @@ function AutocompleteFieldImpl({
266
277
  }
267
278
  return;
268
279
  }
269
- if (event.key === "Escape") setOpen(false);
270
280
  };
271
281
  const handleKeyDown = (event) => {
272
282
  if (event.key === "ArrowDown" || event.key === "ArrowUp") {
@@ -285,7 +295,6 @@ function AutocompleteFieldImpl({
285
295
  if (active) selectOption(active);
286
296
  return;
287
297
  }
288
- if (event.key === "Escape") setOpen(false);
289
298
  };
290
299
  const staticMatch = useMemo(() => {
291
300
  if (!hasSelection) return null;
@@ -297,7 +306,8 @@ function AutocompleteFieldImpl({
297
306
  const cardSub = cardOption ? pickText(cardOption, subKey) : "";
298
307
  if (freeText) {
299
308
  const createText = freeTextCreateLabel(createLabel, freeTextValue);
300
- return /* @__PURE__ */ jsxs("div", { ref: hostRef, className: "erp-popover-host", children: [
309
+ return /* @__PURE__ */ jsxs("div", { ref: hostRef, className: "erp-popover-host", onBlur: handleHostBlur, children: [
310
+ /* @__PURE__ */ jsx(AnchoredPopoverStyles, {}),
301
311
  /* @__PURE__ */ jsxs("div", { className: "wp-inputwrap wp-inputwrap--lead", children: [
302
312
  /* @__PURE__ */ jsx(
303
313
  "span",
@@ -325,65 +335,74 @@ function AutocompleteFieldImpl({
325
335
  }
326
336
  )
327
337
  ] }),
328
- open ? /* @__PURE__ */ jsx("div", { className: "erp-popover erp-popover--left", style: { width: "100%" }, children: /* @__PURE__ */ jsxs(
329
- "div",
330
- {
331
- id: listId,
332
- ref: listRef,
333
- role: "listbox",
334
- className: "erp-popover__body",
335
- style: {
336
- maxHeight: 280,
337
- overflowY: "auto",
338
- overscrollBehavior: "contain",
339
- padding: "var(--wp-space-1)"
340
- },
341
- onMouseDown: (event) => event.preventDefault(),
342
- children: [
343
- /* @__PURE__ */ jsx(
344
- "button",
338
+ open ? portal(
339
+ anchor,
340
+ /* @__PURE__ */ jsx(
341
+ "div",
342
+ {
343
+ ref: popRef,
344
+ className: "wp-anchored-pop",
345
+ style: listPopStyle(anchor),
346
+ ...pointer.panelProps,
347
+ onMouseDown: keepFocusInField,
348
+ children: /* @__PURE__ */ jsxs(
349
+ "div",
345
350
  {
346
- id: `${listId}-opt-0`,
347
- type: "button",
348
- role: "option",
349
- "aria-selected": activeIndex === 0,
350
- "data-create-row": "",
351
- onClick: () => chooseFreeRow(0),
352
- onPointerEnter: () => setActiveIndex(0),
353
- style: optionRowStyle(activeIndex === 0),
354
- children: /* @__PURE__ */ jsx("span", { className: "wp-body-sm", style: ellipsisStyle, children: createText })
351
+ id: listId,
352
+ ref: listRef,
353
+ role: "listbox",
354
+ className: "erp-popover__body",
355
+ style: listBoxStyle,
356
+ children: [
357
+ /* @__PURE__ */ jsx(
358
+ "button",
359
+ {
360
+ id: `${listId}-opt-0`,
361
+ type: "button",
362
+ tabIndex: -1,
363
+ role: "option",
364
+ "aria-selected": activeIndex === 0,
365
+ "data-create-row": "",
366
+ onClick: () => chooseFreeRow(0),
367
+ onPointerEnter: () => setActiveIndex(0),
368
+ style: optionRowStyle(activeIndex === 0),
369
+ children: /* @__PURE__ */ jsx("span", { className: "wp-body-sm", style: ellipsisStyle, children: createText })
370
+ }
371
+ ),
372
+ status === "loading" ? /* @__PURE__ */ jsx("div", { className: "wp-row", style: statusRowStyle, children: /* @__PURE__ */ jsx(Spinner, { size: "sm", label: "\uAC80\uC0C9 \uC911\u2026" }) }) : status === "offline" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
373
+ /* @__PURE__ */ jsx(Icon, { name: "unplug", size: 16, style: { color: "var(--wp-text-muted)", flex: "none" } }),
374
+ /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uBC31\uC5D4\uB4DC \uBBF8\uC5F0\uB3D9 \u2014 \uAC80\uC0C9 \uACB0\uACFC\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" })
375
+ ] }) : status === "error" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
376
+ /* @__PURE__ */ jsx(Icon, { name: "circle-alert", size: 16, style: { color: "var(--wp-text-danger)", flex: "none" } }),
377
+ /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uAC80\uC0C9 \uC2E4\uD328 \u2014 \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694" })
378
+ ] }) : status === "ready" && results.length === 0 ? /* @__PURE__ */ jsx("div", { className: "wp-caption", style: { ...statusRowStyle, color: "var(--wp-text-subtle)" }, children: "\uC77C\uCE58\uD558\uB294 \uD56D\uBAA9 \uC5C6\uC74C" }) : status === "ready" ? results.map((option, index) => {
379
+ const row = index + 1;
380
+ const optionSub = pickText(option, subKey);
381
+ return /* @__PURE__ */ jsxs(
382
+ "button",
383
+ {
384
+ id: `${listId}-opt-${row}`,
385
+ type: "button",
386
+ tabIndex: -1,
387
+ role: "option",
388
+ "aria-selected": row === activeIndex,
389
+ onClick: () => chooseFreeRow(row),
390
+ onPointerEnter: () => setActiveIndex(row),
391
+ style: optionRowStyle(row === activeIndex),
392
+ children: [
393
+ /* @__PURE__ */ jsx("span", { className: "wp-body-sm", style: ellipsisStyle, children: pickText(option, labelKey) || pickText(option, valueKey) }),
394
+ optionSub ? /* @__PURE__ */ jsx("span", { className: "wp-caption", style: ellipsisStyle, children: optionSub }) : null
395
+ ]
396
+ },
397
+ `${pickText(option, valueKey)}-${index}`
398
+ );
399
+ }) : null
400
+ ]
355
401
  }
356
- ),
357
- status === "loading" ? /* @__PURE__ */ jsx("div", { className: "wp-row", style: statusRowStyle, children: /* @__PURE__ */ jsx(Spinner, { size: "sm", label: "\uAC80\uC0C9 \uC911\u2026" }) }) : status === "offline" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
358
- /* @__PURE__ */ jsx(Icon, { name: "unplug", size: 16, style: { color: "var(--wp-text-muted)", flex: "none" } }),
359
- /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uBC31\uC5D4\uB4DC \uBBF8\uC5F0\uB3D9 \u2014 \uAC80\uC0C9 \uACB0\uACFC\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" })
360
- ] }) : status === "error" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
361
- /* @__PURE__ */ jsx(Icon, { name: "circle-alert", size: 16, style: { color: "var(--wp-text-danger)", flex: "none" } }),
362
- /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uAC80\uC0C9 \uC2E4\uD328 \u2014 \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694" })
363
- ] }) : status === "ready" && results.length === 0 ? /* @__PURE__ */ jsx("div", { className: "wp-caption", style: { ...statusRowStyle, color: "var(--wp-text-subtle)" }, children: "\uC77C\uCE58\uD558\uB294 \uD56D\uBAA9 \uC5C6\uC74C" }) : status === "ready" ? results.map((option, index) => {
364
- const row = index + 1;
365
- const optionSub = pickText(option, subKey);
366
- return /* @__PURE__ */ jsxs(
367
- "button",
368
- {
369
- id: `${listId}-opt-${row}`,
370
- type: "button",
371
- role: "option",
372
- "aria-selected": row === activeIndex,
373
- onClick: () => chooseFreeRow(row),
374
- onPointerEnter: () => setActiveIndex(row),
375
- style: optionRowStyle(row === activeIndex),
376
- children: [
377
- /* @__PURE__ */ jsx("span", { className: "wp-body-sm", style: ellipsisStyle, children: pickText(option, labelKey) || pickText(option, valueKey) }),
378
- optionSub ? /* @__PURE__ */ jsx("span", { className: "wp-caption", style: ellipsisStyle, children: optionSub }) : null
379
- ]
380
- },
381
- `${pickText(option, valueKey)}-${index}`
382
- );
383
- }) : null
384
- ]
385
- }
386
- ) }) : null
402
+ )
403
+ }
404
+ )
405
+ ) : null
387
406
  ] });
388
407
  }
389
408
  if (cardMode) {
@@ -420,7 +439,8 @@ function AutocompleteFieldImpl({
420
439
  );
421
440
  }
422
441
  const showActiveDescendant = open && status === "ready" && results.length > 0;
423
- return /* @__PURE__ */ jsxs("div", { ref: hostRef, className: "erp-popover-host", children: [
442
+ return /* @__PURE__ */ jsxs("div", { ref: hostRef, className: "erp-popover-host", onBlur: handleHostBlur, children: [
443
+ /* @__PURE__ */ jsx(AnchoredPopoverStyles, {}),
424
444
  /* @__PURE__ */ jsx(
425
445
  Input,
426
446
  {
@@ -441,47 +461,56 @@ function AutocompleteFieldImpl({
441
461
  onKeyDown: handleKeyDown
442
462
  }
443
463
  ),
444
- open ? /* @__PURE__ */ jsx("div", { className: "erp-popover erp-popover--left", style: { width: "100%" }, children: /* @__PURE__ */ jsx(
445
- "div",
446
- {
447
- id: listId,
448
- ref: listRef,
449
- role: "listbox",
450
- className: "erp-popover__body",
451
- style: {
452
- maxHeight: 280,
453
- overflowY: "auto",
454
- overscrollBehavior: "contain",
455
- padding: "var(--wp-space-1)"
456
- },
457
- children: status === "loading" ? /* @__PURE__ */ jsx("div", { className: "wp-row", style: statusRowStyle, children: /* @__PURE__ */ jsx(Spinner, { size: "sm", label: "\uAC80\uC0C9 \uC911\u2026" }) }) : status === "offline" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
458
- /* @__PURE__ */ jsx(Icon, { name: "unplug", size: 16, style: { color: "var(--wp-text-muted)", flex: "none" } }),
459
- /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uBC31\uC5D4\uB4DC \uBBF8\uC5F0\uB3D9 \u2014 \uAC80\uC0C9 \uACB0\uACFC\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" })
460
- ] }) : status === "error" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
461
- /* @__PURE__ */ jsx(Icon, { name: "circle-alert", size: 16, style: { color: "var(--wp-text-danger)", flex: "none" } }),
462
- /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uAC80\uC0C9 \uC2E4\uD328 \u2014 \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694" })
463
- ] }) : results.length === 0 ? /* @__PURE__ */ jsx("div", { className: "wp-caption", style: statusRowStyle, children: "\uACB0\uACFC \uC5C6\uC74C" }) : results.map((option, index) => {
464
- const optionSub = pickText(option, subKey);
465
- return /* @__PURE__ */ jsxs(
466
- "button",
464
+ open ? portal(
465
+ anchor,
466
+ /* @__PURE__ */ jsx(
467
+ "div",
468
+ {
469
+ ref: popRef,
470
+ className: "wp-anchored-pop",
471
+ style: listPopStyle(anchor),
472
+ ...pointer.panelProps,
473
+ onMouseDown: keepFocusInField,
474
+ children: /* @__PURE__ */ jsx(
475
+ "div",
467
476
  {
468
- id: `${listId}-opt-${index}`,
469
- type: "button",
470
- role: "option",
471
- "aria-selected": index === activeIndex,
472
- onClick: () => selectOption(option),
473
- onPointerEnter: () => setActiveIndex(index),
474
- style: optionRowStyle(index === activeIndex),
475
- children: [
476
- /* @__PURE__ */ jsx("span", { className: "wp-body-sm", style: ellipsisStyle, children: pickText(option, labelKey) || pickText(option, valueKey) }),
477
- optionSub ? /* @__PURE__ */ jsx("span", { className: "wp-caption", style: ellipsisStyle, children: optionSub }) : null
478
- ]
479
- },
480
- `${pickText(option, valueKey)}-${index}`
481
- );
482
- })
483
- }
484
- ) }) : null
477
+ id: listId,
478
+ ref: listRef,
479
+ role: "listbox",
480
+ className: "erp-popover__body",
481
+ style: listBoxStyle,
482
+ children: status === "loading" ? /* @__PURE__ */ jsx("div", { className: "wp-row", style: statusRowStyle, children: /* @__PURE__ */ jsx(Spinner, { size: "sm", label: "\uAC80\uC0C9 \uC911\u2026" }) }) : status === "offline" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
483
+ /* @__PURE__ */ jsx(Icon, { name: "unplug", size: 16, style: { color: "var(--wp-text-muted)", flex: "none" } }),
484
+ /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uBC31\uC5D4\uB4DC \uBBF8\uC5F0\uB3D9 \u2014 \uAC80\uC0C9 \uACB0\uACFC\uB97C \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" })
485
+ ] }) : status === "error" ? /* @__PURE__ */ jsxs("div", { className: "wp-row", style: statusRowStyle, children: [
486
+ /* @__PURE__ */ jsx(Icon, { name: "circle-alert", size: 16, style: { color: "var(--wp-text-danger)", flex: "none" } }),
487
+ /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uAC80\uC0C9 \uC2E4\uD328 \u2014 \uC7A0\uC2DC \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD574 \uC8FC\uC138\uC694" })
488
+ ] }) : results.length === 0 ? /* @__PURE__ */ jsx("div", { className: "wp-caption", style: statusRowStyle, children: "\uACB0\uACFC \uC5C6\uC74C" }) : results.map((option, index) => {
489
+ const optionSub = pickText(option, subKey);
490
+ return /* @__PURE__ */ jsxs(
491
+ "button",
492
+ {
493
+ id: `${listId}-opt-${index}`,
494
+ type: "button",
495
+ tabIndex: -1,
496
+ role: "option",
497
+ "aria-selected": index === activeIndex,
498
+ onClick: () => selectOption(option),
499
+ onPointerEnter: () => setActiveIndex(index),
500
+ style: optionRowStyle(index === activeIndex),
501
+ children: [
502
+ /* @__PURE__ */ jsx("span", { className: "wp-body-sm", style: ellipsisStyle, children: pickText(option, labelKey) || pickText(option, valueKey) }),
503
+ optionSub ? /* @__PURE__ */ jsx("span", { className: "wp-caption", style: ellipsisStyle, children: optionSub }) : null
504
+ ]
505
+ },
506
+ `${pickText(option, valueKey)}-${index}`
507
+ );
508
+ })
509
+ }
510
+ )
511
+ }
512
+ )
513
+ ) : null
485
514
  ] });
486
515
  }
487
516
  var AutocompleteField = boxed(AutocompleteFieldImpl, "AutocompleteField");
@@ -1,6 +1,6 @@
1
1
  import { OverlayContainerContext, getOverlayRoot, useOverlayLayer } from './chunk-R2ORCOTG.js';
2
2
  import { HoistedStyle } from './chunk-RIZRM7OO.js';
3
- import { IconButton } from './chunk-NKRZVRGH.js';
3
+ import { IconButton } from './chunk-45GIMFRP.js';
4
4
  import React2, { useState, useRef, useEffect, useLayoutEffect, useCallback } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
  import { createPortal } from 'react-dom';
@@ -1,4 +1,4 @@
1
- import { isPlainObject } from './chunk-NKRZVRGH.js';
1
+ import { isPlainObject } from './chunk-45GIMFRP.js';
2
2
 
3
3
  // src/widgets/shared.ts
4
4
  function unwrapRows(payload) {
@@ -1,7 +1,7 @@
1
- import { KO_CALENDAR_NAV_LOCALE, useDismiss, usePopoverAnchor, usePortalTo, usePanelPointer, AnchoredPopoverStyles, anchorStyle, focusStaysInside, resolveCalendarNavLocale, CalendarZoom, CalendarNav, clampIndex } from './chunk-FR7S52ZL.js';
1
+ import { KO_CALENDAR_NAV_LOCALE, useDismiss, usePopoverAnchor, usePortalTo, usePanelPointer, AnchoredPopoverStyles, anchorStyle, focusStaysInside, resolveCalendarNavLocale, CalendarZoom, CalendarNav, clampIndex } from './chunk-HNMBEUBO.js';
2
2
  import { HoistedStyle } from './chunk-RIZRM7OO.js';
3
3
  import { useIsMobile } from './chunk-TAVKGYH5.js';
4
- import { Icon } from './chunk-NKRZVRGH.js';
4
+ import { Icon } from './chunk-45GIMFRP.js';
5
5
  import { boxed } from './chunk-3JTBOABA.js';
6
6
  import { useState, useRef, useEffect, useMemo, useCallback, useLayoutEffect } from 'react';
7
7
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
1
  import { usePanZoomCanvas, MIN_ZOOM, MAX_ZOOM } from './chunk-XDR6HC4U.js';
2
- import { IconButton, Badge } from './chunk-NKRZVRGH.js';
2
+ import { IconButton, Badge } from './chunk-45GIMFRP.js';
3
3
  import { boxed } from './chunk-3JTBOABA.js';
4
4
  import { useState, useMemo, useCallback, useEffect } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  import { fetchAllJobPositions } from './chunk-XRHR452N.js';
2
- import { useSduiDispatch, useSduiCan, SduiDialog } from './chunk-RT2I2U45.js';
3
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-RMYGRGKS.js';
4
- import { Card, Input, Button, Icon, Badge, IconButton } from './chunk-NKRZVRGH.js';
2
+ import { useSduiDispatch, useSduiCan, SduiDialog } from './chunk-77OM6OQG.js';
3
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DE7FPWVJ.js';
4
+ import { Card, Input, Button, Icon, Badge, IconButton } from './chunk-45GIMFRP.js';
5
5
  import { boxed } from './chunk-3JTBOABA.js';
6
6
  import React, { useState, useEffect, useCallback, useMemo } from 'react';
7
7
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,8 +1,8 @@
1
- import { TagMultiSelect } from './chunk-3M64LBYZ.js';
2
- import { ApprovalLineEditor, stepTypeIcon, stepLabel } from './chunk-NTMFLJEE.js';
3
- import { orderCircleStyle, unwrapRows, uid } from './chunk-A2PG44CM.js';
4
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-RMYGRGKS.js';
5
- import { Card, Icon, Input, IconButton, Field, Button, Badge } from './chunk-NKRZVRGH.js';
1
+ import { TagMultiSelect } from './chunk-5DLUGN5M.js';
2
+ import { ApprovalLineEditor, stepTypeIcon, stepLabel } from './chunk-ZSKQUIYR.js';
3
+ import { orderCircleStyle, unwrapRows, uid } from './chunk-HR2U2QGN.js';
4
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DE7FPWVJ.js';
5
+ import { Card, Icon, Input, IconButton, Field, Button, Badge } from './chunk-45GIMFRP.js';
6
6
  import { boxed } from './chunk-3JTBOABA.js';
7
7
  import React, { useRef, useState, useEffect } from 'react';
8
8
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Icon, Badge, Tooltip } from './chunk-NKRZVRGH.js';
1
+ import { Icon, Badge, Tooltip } from './chunk-45GIMFRP.js';
2
2
  import { boxed } from './chunk-3JTBOABA.js';
3
3
  import React from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,6 +1,6 @@
1
1
  import { fetchAllJobPositions } from './chunk-XRHR452N.js';
2
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-RMYGRGKS.js';
3
- import { Select, Button } from './chunk-NKRZVRGH.js';
2
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DE7FPWVJ.js';
3
+ import { Select, Button } from './chunk-45GIMFRP.js';
4
4
  import { boxed } from './chunk-3JTBOABA.js';
5
5
  import { useRef, useState, useEffect, useMemo } from 'react';
6
6
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { formatDisplayValue } from './chunk-NKRZVRGH.js';
1
+ import { formatDisplayValue } from './chunk-45GIMFRP.js';
2
2
  import { mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle, GAP_CSS } from './chunk-3JTBOABA.js';
3
3
  import React from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Badge, Checkbox, IconButton, Icon } from './chunk-NKRZVRGH.js';
1
+ import { Badge, Checkbox, IconButton, Icon } from './chunk-45GIMFRP.js';
2
2
  import { boxed } from './chunk-3JTBOABA.js';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
- import { DateRangePicker } from './chunk-LDIEWJNP.js';
1
+ import { DateRangePicker } from './chunk-KMNC3Q4J.js';
2
2
  import { useOverlayLayer } from './chunk-R2ORCOTG.js';
3
3
  import { HoistedStyle } from './chunk-RIZRM7OO.js';
4
- import { Input, Button, IconButton, Tag, Field, Checkbox, plainNumberText, formatNumberValue } from './chunk-NKRZVRGH.js';
4
+ import { Input, Button, IconButton, Tag, Field, Checkbox, plainNumberText, formatNumberValue } from './chunk-45GIMFRP.js';
5
5
  import { useRef, useEffect, useState, useMemo } from 'react';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
7
7
 
@@ -1,9 +1,9 @@
1
1
  import { parseJobPositionRow } from './chunk-XRHR452N.js';
2
2
  import { MIN_ZOOM, usePanZoomCanvas } from './chunk-XDR6HC4U.js';
3
- import { ImageLightbox } from './chunk-5NDYDUMJ.js';
4
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-RMYGRGKS.js';
3
+ import { ImageLightbox } from './chunk-FLBU7AVR.js';
4
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DE7FPWVJ.js';
5
5
  import { useIsTabletDown } from './chunk-TAVKGYH5.js';
6
- import { warnOnce, Badge, Button, IconButton, Icon } from './chunk-NKRZVRGH.js';
6
+ import { warnOnce, Badge, Button, IconButton, Icon } from './chunk-45GIMFRP.js';
7
7
  import { boxed } from './chunk-3JTBOABA.js';
8
8
  import { useState, useMemo, useRef, useCallback, useEffect, useLayoutEffect } from 'react';
9
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Icon, Badge } from './chunk-NKRZVRGH.js';
1
+ import { Icon, Badge } from './chunk-45GIMFRP.js';
2
2
  import { boxed } from './chunk-3JTBOABA.js';
3
3
  import React from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Spinner, EmptyState } from './chunk-NKRZVRGH.js';
1
+ import { Spinner, EmptyState } from './chunk-45GIMFRP.js';
2
2
  import { useState, useEffect } from 'react';
3
3
  import { jsx, jsxs } from 'react/jsx-runtime';
4
4