@wipco/sdui 0.50.6 → 1.0.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 (111) hide show
  1. package/dist/{DatePicker-BK_jsV7i.d.ts → DatePicker-C_TT_SOw.d.ts} +25 -0
  2. package/dist/{chunk-OEWTVLPZ.js → chunk-2HLXCKK7.js} +2 -2
  3. package/dist/{chunk-PWVHAUJC.js → chunk-2YP5N4VV.js} +6 -4
  4. package/dist/{chunk-QTHYLNJW.js → chunk-37SFFW37.js} +2 -13
  5. package/dist/{chunk-YQOMSWW5.js → chunk-5WW4MBRO.js} +1 -1
  6. package/dist/{chunk-LIOS3PF2.js → chunk-5XPZ3RSA.js} +3 -4
  7. package/dist/{chunk-ZD3VNVRF.js → chunk-7BGDSSAN.js} +5 -13
  8. package/dist/{chunk-Y2LIEWQX.js → chunk-7FZTUI6U.js} +6 -5
  9. package/dist/{chunk-HJ5VSXR4.js → chunk-7P7N43JV.js} +2 -2
  10. package/dist/{chunk-55VB6SDU.js → chunk-A5XQOEVH.js} +23 -20
  11. package/dist/{chunk-77LKJCMM.js → chunk-A6LAIGUS.js} +20 -108
  12. package/dist/{chunk-YXS5FXVS.js → chunk-AC5TI3BE.js} +7 -16
  13. package/dist/{chunk-AIOJYVJ2.js → chunk-AXGF4M57.js} +1 -1
  14. package/dist/{chunk-5MPK3NZK.js → chunk-B6WMC2AN.js} +3 -3
  15. package/dist/{chunk-C6ZV4VBN.js → chunk-C37U3GCC.js} +4 -4
  16. package/dist/{chunk-265YPW4W.js → chunk-DMLDKW7K.js} +1 -1
  17. package/dist/{chunk-FZ72IDVF.js → chunk-E6ISNQK3.js} +2 -2
  18. package/dist/{chunk-STX2AX6Y.js → chunk-FLAN7CV3.js} +7 -39
  19. package/dist/{chunk-IV5YTVHR.js → chunk-GE6BYNQJ.js} +18 -33
  20. package/dist/{chunk-ZX36LKJ7.js → chunk-GTGS2QRL.js} +7 -6
  21. package/dist/{chunk-NL3I6F2I.js → chunk-HBBTENSV.js} +3 -3
  22. package/dist/{chunk-RUU7WBGR.js → chunk-I45EUZC6.js} +19 -9
  23. package/dist/{chunk-JBKNIALK.js → chunk-I5SD7XRA.js} +9 -6
  24. package/dist/{chunk-X7GHY2RI.js → chunk-IFKYGJXP.js} +14 -42
  25. package/dist/{chunk-J3YMUR6R.js → chunk-IZ3JA2BR.js} +3 -3
  26. package/dist/{chunk-AUW5RP24.js → chunk-JIV4YHCZ.js} +7 -6
  27. package/dist/{chunk-M6KM3FJS.js → chunk-JYAR7D5U.js} +2 -2
  28. package/dist/{chunk-DKPNFEVU.js → chunk-KO6OEY3G.js} +19 -6
  29. package/dist/{chunk-JHHMFL5D.js → chunk-LFEJLOFN.js} +28 -16
  30. package/dist/chunk-MMIGOPO5.js +111 -0
  31. package/dist/{chunk-YSSNP6JM.js → chunk-N25YP7ID.js} +6 -21
  32. package/dist/{chunk-F2W2FWOT.js → chunk-N5RKM6IC.js} +7 -7
  33. package/dist/{chunk-C4HYWZML.js → chunk-O4IISNE7.js} +1 -1
  34. package/dist/chunk-Q4SWUINA.js +51 -0
  35. package/dist/{chunk-TUOG7EEI.js → chunk-RNOUXUBO.js} +418 -22
  36. package/dist/{chunk-4VZI3PLI.js → chunk-RYHEV5E3.js} +15 -39
  37. package/dist/{chunk-AVRNQOB5.js → chunk-SAPBDJJQ.js} +14 -13
  38. package/dist/{chunk-OPJ4DYNI.js → chunk-SJ3737RA.js} +156 -158
  39. package/dist/{chunk-UMANGYRD.js → chunk-TFGNKFL2.js} +1 -1
  40. package/dist/{chunk-KYGSMUUU.js → chunk-VY7MVBSE.js} +2 -2
  41. package/dist/{chunk-VDBUXYEB.js → chunk-WOYMEEPH.js} +8 -8
  42. package/dist/{chunk-I5Z2RVDF.js → chunk-WSLT32Q4.js} +278 -30
  43. package/dist/{chunk-NYUHSMUU.js → chunk-XGFDY43I.js} +2 -2
  44. package/dist/{chunk-ODKZF4IT.js → chunk-YOZN35HD.js} +17 -9
  45. package/dist/{chunk-EKP6Z3G6.js → chunk-YVTV4ZV6.js} +1 -1
  46. package/dist/{chunk-6BCWFPNJ.js → chunk-YWUDBLO6.js} +2 -2
  47. package/dist/chunk-Z4PYMTTS.js +41 -0
  48. package/dist/{chunk-WXIQLWIX.js → chunk-ZFNFPXPR.js} +2 -2
  49. package/dist/{chunk-7GOWOSX6.js → chunk-ZORQPB6B.js} +11 -5
  50. package/dist/index.d.ts +1096 -941
  51. package/dist/index.js +369 -610
  52. package/dist/meta.d.ts +13 -12
  53. package/dist/meta.js +84 -16
  54. package/dist/rich/ExcelUploadCard.d.ts +7 -0
  55. package/dist/rich/ExcelUploadCard.js +17 -13
  56. package/dist/rich.d.ts +1 -1
  57. package/dist/rich.js +25 -12
  58. package/dist/styles.css +10 -2
  59. package/dist/{types-D14eqLpf.d.ts → types-C7y9CpgF.d.ts} +7 -5
  60. package/dist/widgets/ApprovalLineEditor.js +7 -6
  61. package/dist/widgets/ApprovalOverridesEditor.d.ts +11 -1
  62. package/dist/widgets/ApprovalOverridesEditor.js +9 -8
  63. package/dist/widgets/ApprovalStepper.js +3 -3
  64. package/dist/widgets/AutocompleteField.d.ts +1 -0
  65. package/dist/widgets/AutocompleteField.js +7 -6
  66. package/dist/widgets/ColumnBoard.js +3 -3
  67. package/dist/widgets/DiffView.js +3 -3
  68. package/dist/widgets/Disclosure.js +3 -3
  69. package/dist/widgets/EventCalendar.d.ts +16 -1
  70. package/dist/widgets/EventCalendar.js +3 -3
  71. package/dist/widgets/FileDropzone.js +7 -6
  72. package/dist/widgets/ImageLightbox.js +5 -4
  73. package/dist/widgets/InlineEdit.js +3 -3
  74. package/dist/widgets/JsonField.js +3 -3
  75. package/dist/widgets/LiveClock.js +2 -2
  76. package/dist/widgets/OptionSchemaEditor.js +4 -4
  77. package/dist/widgets/OptionValueFields.d.ts +5 -0
  78. package/dist/widgets/OptionValueFields.js +4 -4
  79. package/dist/widgets/OrgChart.js +4 -3
  80. package/dist/widgets/OrgChartBoard.d.ts +93 -4
  81. package/dist/widgets/OrgChartBoard.js +9 -6
  82. package/dist/widgets/PeriodFilter.js +4 -4
  83. package/dist/widgets/PermissionMatrixEditor.d.ts +16 -0
  84. package/dist/widgets/PermissionMatrixEditor.js +4 -4
  85. package/dist/widgets/PositionSelect.d.ts +6 -1
  86. package/dist/widgets/PositionSelect.js +5 -4
  87. package/dist/widgets/PrintSheet.js +3 -3
  88. package/dist/widgets/ProfileEditDiffCard.d.ts +6 -0
  89. package/dist/widgets/ProfileEditDiffCard.js +4 -4
  90. package/dist/widgets/QRDisplay.js +4 -4
  91. package/dist/widgets/RankBoard.d.ts +6 -0
  92. package/dist/widgets/RankBoard.js +6 -5
  93. package/dist/widgets/RecordSheet.js +2 -2
  94. package/dist/widgets/RoleMemberPicker.d.ts +11 -5
  95. package/dist/widgets/RoleMemberPicker.js +5 -4
  96. package/dist/widgets/SearchableMultiPicker.js +5 -5
  97. package/dist/widgets/SecureScreen.d.ts +12 -0
  98. package/dist/widgets/SecureScreen.js +3 -3
  99. package/dist/widgets/StackedMeter.js +2 -2
  100. package/dist/widgets/StagePeriodEditor.js +4 -5
  101. package/dist/widgets/Strip.js +2 -2
  102. package/dist/widgets/SummaryTable.js +2 -2
  103. package/dist/widgets/TagMultiSelect.d.ts +0 -1
  104. package/dist/widgets/TagMultiSelect.js +4 -4
  105. package/dist/widgets/Timeline.js +4 -4
  106. package/dist/widgets/TreePicker.js +6 -6
  107. package/dist/widgets/TreeView.js +5 -5
  108. package/dist/widgets/index.d.ts +3 -3
  109. package/dist/widgets/index.js +81 -79
  110. package/package.json +1 -1
  111. package/dist/chunk-EKVA7T7P.js +0 -198
@@ -1,28 +1,24 @@
1
- import { TagMultiSelect } from './chunk-JBKNIALK.js';
2
- import { ApprovalLineEditor, stepTypeIcon, stepLabel } from './chunk-STX2AX6Y.js';
3
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DKPNFEVU.js';
4
- import { Card, Icon, Input, IconButton, Field, Button, Badge } from './chunk-TUOG7EEI.js';
5
- import { boxed } from './chunk-YQOMSWW5.js';
6
- import React, { useState, useEffect } from 'react';
1
+ import { TagMultiSelect } from './chunk-I5SD7XRA.js';
2
+ import { ApprovalLineEditor, stepTypeIcon, stepLabel } from './chunk-FLAN7CV3.js';
3
+ import { orderCircleStyle, unwrapRows, uid } from './chunk-Q4SWUINA.js';
4
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-KO6OEY3G.js';
5
+ import { Card, Icon, Input, IconButton, Field, Button, Badge } from './chunk-RNOUXUBO.js';
6
+ import { boxed } from './chunk-5WW4MBRO.js';
7
+ import React, { useRef, useState, useEffect } from 'react';
7
8
  import { jsxs, jsx } from 'react/jsx-runtime';
8
9
 
9
- function facetsFrom(rows) {
10
+ function facetsFrom(payload) {
10
11
  const titles = /* @__PURE__ */ new Set();
11
12
  const grades = /* @__PURE__ */ new Set();
12
- if (Array.isArray(rows)) {
13
- for (const row of rows) {
14
- if (typeof row !== "object" || row === null) continue;
15
- const title = row.job_title;
16
- const grade = row.grade;
17
- if (typeof title === "string" && title.trim()) titles.add(title.trim());
18
- if (typeof grade === "string" && grade.trim()) grades.add(grade.trim());
19
- }
13
+ for (const row of unwrapRows(payload)) {
14
+ const title = typeof row.job_title === "string" ? row.job_title : row.jobTitle;
15
+ const grade = row.grade;
16
+ if (typeof title === "string" && title.trim()) titles.add(title.trim());
17
+ if (typeof grade === "string" && grade.trim()) grades.add(grade.trim());
20
18
  }
21
19
  const ko = (a, b) => a.localeCompare(b, "ko");
22
20
  return { titles: [...titles].sort(ko), grades: [...grades].sort(ko) };
23
21
  }
24
- var uidCounter = 0;
25
- var uid = (prefix) => `${prefix}-${Date.now()}-${++uidCounter}`;
26
22
  var describeScope = (override) => {
27
23
  const identityParts = [];
28
24
  if (override.jobTitles.length > 0) identityParts.push(`\uC9C1\uCC45 ${override.jobTitles.join(", ")}`);
@@ -36,17 +32,6 @@ var withSelected = (options, selected) => [...options, ...selected.filter((value
36
32
  value,
37
33
  label: value
38
34
  }));
39
- var orderCircleStyle = {
40
- display: "inline-flex",
41
- alignItems: "center",
42
- justifyContent: "center",
43
- width: 28,
44
- height: 28,
45
- flex: "none",
46
- borderRadius: "var(--wp-radius-pill)",
47
- background: "var(--wp-surface-brand-tint)",
48
- color: "var(--wp-text-brand)"
49
- };
50
35
  function StepSummary({ steps }) {
51
36
  if (steps.length === 0) {
52
37
  return /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "\uACB0\uC7AC \uB2E8\uACC4\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uB9E4\uCE6D \uC2DC \uC790\uB3D9 \uC2B9\uC778\uB429\uB2C8\uB2E4." });
@@ -79,6 +64,8 @@ function ApprovalOverridesEditorImpl({
79
64
  }) {
80
65
  const adapter = useSduiAdapter();
81
66
  const api = hostFetchOf(adapter) ?? defaultAdapter.fetch;
67
+ const apiRef = useRef(api);
68
+ apiRef.current = api;
82
69
  const overrides = value ?? [];
83
70
  const [fetchedFacets, setFetchedFacets] = useState(
84
71
  null
@@ -86,11 +73,9 @@ function ApprovalOverridesEditorImpl({
86
73
  useEffect(() => {
87
74
  if (!facetsEndpoint) return;
88
75
  let alive = true;
89
- api(facetsEndpoint, { method: "GET" }).then((response) => {
76
+ apiRef.current(facetsEndpoint, { method: "GET" }).then((response) => {
90
77
  if (!alive) return;
91
- const body = response;
92
- const rows = Array.isArray(response) ? response : body?.data ?? [];
93
- setFetchedFacets(facetsFrom(rows));
78
+ setFetchedFacets(facetsFrom(response));
94
79
  }).catch(() => {
95
80
  });
96
81
  return () => {
@@ -356,4 +341,4 @@ function ApprovalOverridesEditorImpl({
356
341
  }
357
342
  var ApprovalOverridesEditor = boxed(ApprovalOverridesEditorImpl, "ApprovalOverridesEditor");
358
343
 
359
- export { ApprovalOverridesEditor };
344
+ export { ApprovalOverridesEditor, facetsFrom };
@@ -1,6 +1,6 @@
1
- import { Disclosure } from './chunk-OEWTVLPZ.js';
2
- import { Icon } from './chunk-TUOG7EEI.js';
3
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { Disclosure } from './chunk-2HLXCKK7.js';
2
+ import { Icon } from './chunk-RNOUXUBO.js';
3
+ import { boxed } from './chunk-5WW4MBRO.js';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
5
 
6
6
  var TYPE_META = {
@@ -40,7 +40,8 @@ function formatPayload(payload) {
40
40
  }
41
41
  }
42
42
  function TimelineImpl({ items, maxHeight }) {
43
- if (items.length === 0) {
43
+ const list = Array.isArray(items) ? items : [];
44
+ if (list.length === 0) {
44
45
  return /* @__PURE__ */ jsx("p", { className: "wp-caption", style: { margin: 0, padding: "var(--wp-space-2) 0" }, children: "\uD45C\uC2DC\uD560 \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." });
45
46
  }
46
47
  return /* @__PURE__ */ jsxs(
@@ -50,9 +51,9 @@ function TimelineImpl({ items, maxHeight }) {
50
51
  style: maxHeight !== void 0 ? { maxHeight, overflowY: "auto", paddingRight: "var(--wp-space-1)" } : void 0,
51
52
  children: [
52
53
  /* @__PURE__ */ jsx(TimelineStyles, {}),
53
- items.map((item, index) => {
54
+ list.map((item, index) => {
54
55
  const meta = TYPE_META[item.type ?? "info"];
55
- const isLast = index === items.length - 1;
56
+ const isLast = index === list.length - 1;
56
57
  const hasPayload = item.payload !== void 0 && item.payload !== null;
57
58
  return /* @__PURE__ */ jsxs("li", { className: "erp-timeline__item", children: [
58
59
  /* @__PURE__ */ jsxs("div", { className: "erp-timeline__rail", "aria-hidden": "true", children: [
@@ -1,6 +1,6 @@
1
- import { DateRangePicker } from './chunk-I5Z2RVDF.js';
2
- import { SegmentedControl, Select } from './chunk-TUOG7EEI.js';
3
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { DateRangePicker } from './chunk-WSLT32Q4.js';
2
+ import { SegmentedControl, Select } from './chunk-RNOUXUBO.js';
3
+ import { boxed } from './chunk-5WW4MBRO.js';
4
4
  import { useState, useMemo } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
 
@@ -1,11 +1,11 @@
1
- import { Icon } from './chunk-TUOG7EEI.js';
2
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { Icon } from './chunk-RNOUXUBO.js';
2
+ import { boxed } from './chunk-5WW4MBRO.js';
3
3
  import { useRef, useState, useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
5
5
 
6
6
  var DEFAULT_NOTICE = "\uAC1C\uC778\uC815\uBCF4 \uBCF4\uD638\uB97C \uC704\uD574 \uD654\uBA74\uC744 \uAC00\uB838\uC2B5\uB2C8\uB2E4. \uD654\uBA74\uC744 \uD074\uB9AD\uD558\uBA74 \uB2E4\uC2DC \uD45C\uC2DC\uB429\uB2C8\uB2E4.";
7
7
  var PRINT_NOTICE = "\uAC1C\uC778\uC815\uBCF4 \uBCF4\uD638 \uD654\uBA74\uC740 \uC778\uC1C4\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.";
8
- var CLIPBOARD_WARNING = "[WIPCO ERP] \uAC1C\uC778\uC815\uBCF4 \uBCF4\uD638 \uD654\uBA74\uC785\uB2C8\uB2E4 \u2014 \uD654\uBA74 \uCEA1\uCC98\xB7\uBCF5\uC0AC\uAC00 \uC81C\uD55C\uB418\uBA70, \uC720\uCD9C \uC2DC \uAD00\uB828 \uBC95\uB839\uC5D0 \uB530\uB77C \uCC98\uBC8C\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
8
+ var CLIPBOARD_WARNING = "\uAC1C\uC778\uC815\uBCF4 \uBCF4\uD638 \uD654\uBA74\uC785\uB2C8\uB2E4 \u2014 \uD654\uBA74 \uCEA1\uCC98\xB7\uBCF5\uC0AC\uAC00 \uC81C\uD55C\uB418\uBA70, \uC720\uCD9C \uC2DC \uAD00\uB828 \uBC95\uB839\uC5D0 \uB530\uB77C \uCC98\uBC8C\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4.";
9
9
  var BLOCKED_COMBO_KEYS = /* @__PURE__ */ new Set(["A", "C", "P", "S", "U", "X"]);
10
10
  var SECURE_CSS = `
11
11
  .erp-secure{position:relative}
@@ -22,14 +22,20 @@ var SECURE_CSS = `
22
22
  function SecureStyles() {
23
23
  return /* @__PURE__ */ jsx("style", { href: "erp-secure", precedence: "medium", children: SECURE_CSS });
24
24
  }
25
- function overwriteClipboard() {
25
+ function overwriteClipboard(warning) {
26
26
  try {
27
- const pending = navigator.clipboard?.writeText(CLIPBOARD_WARNING);
27
+ const pending = navigator.clipboard?.writeText(warning);
28
28
  if (pending) pending.catch(() => void 0);
29
29
  } catch {
30
30
  }
31
31
  }
32
- function SecureScreenImpl({ enabled = true, notice, children }) {
32
+ function SecureScreenImpl({
33
+ enabled = true,
34
+ notice,
35
+ clipboardWarning,
36
+ documentWideKeys = true,
37
+ children
38
+ }) {
33
39
  const hostRef = useRef(null);
34
40
  const [cover, setCover] = useState(null);
35
41
  const [prevEnabled, setPrevEnabled] = useState(enabled);
@@ -43,16 +49,20 @@ function SecureScreenImpl({ enabled = true, notice, children }) {
43
49
  const block = (event) => event.preventDefault();
44
50
  const guarded = ["contextmenu", "copy", "cut", "dragstart", "selectstart"];
45
51
  guarded.forEach((name) => host?.addEventListener(name, block));
52
+ const warning = clipboardWarning || CLIPBOARD_WARNING;
46
53
  const onKeyDown = (event) => {
47
54
  if ((event.ctrlKey || event.metaKey) && BLOCKED_COMBO_KEYS.has(event.key.toUpperCase())) {
55
+ if (!documentWideKeys && !(host && event.target instanceof Node && host.contains(event.target))) {
56
+ return;
57
+ }
48
58
  event.preventDefault();
49
59
  event.stopPropagation();
50
60
  return;
51
61
  }
52
- if (event.key === "PrintScreen") overwriteClipboard();
62
+ if (event.key === "PrintScreen") overwriteClipboard(warning);
53
63
  };
54
64
  const onKeyUp = (event) => {
55
- if (event.key === "PrintScreen") overwriteClipboard();
65
+ if (event.key === "PrintScreen") overwriteClipboard(warning);
56
66
  };
57
67
  const raiseVeil = () => setCover((current) => current ?? "veil");
58
68
  const dropVeil = () => setCover((current) => current === "veil" ? null : current);
@@ -79,7 +89,7 @@ function SecureScreenImpl({ enabled = true, notice, children }) {
79
89
  window.removeEventListener("beforeprint", onBeforePrint);
80
90
  window.removeEventListener("afterprint", onAfterPrint);
81
91
  };
82
- }, [enabled]);
92
+ }, [enabled, clipboardWarning, documentWideKeys]);
83
93
  const classes = ["erp-secure"];
84
94
  if (enabled) classes.push("erp-secure--enabled");
85
95
  if (enabled && cover === "print") classes.push("erp-secure--print");
@@ -1,6 +1,6 @@
1
- import { useSduiAdapter, hostFetchOf } from './chunk-DKPNFEVU.js';
2
- import { Badge, Tag } from './chunk-TUOG7EEI.js';
3
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { useSduiAdapter, hostFetchOf } from './chunk-KO6OEY3G.js';
2
+ import { Badge, Tag } from './chunk-RNOUXUBO.js';
3
+ import { boxed } from './chunk-5WW4MBRO.js';
4
4
  import { useRef, useEffect, useMemo, useState } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
 
@@ -15,9 +15,12 @@ function pickSeedValues(payload, valueKey) {
15
15
  }
16
16
  return rows.flatMap((row) => {
17
17
  if (typeof row === "string") return row ? [row] : [];
18
+ if (typeof row === "number") return [String(row)];
18
19
  if (row === null || typeof row !== "object") return [];
19
20
  const value = row[valueKey];
20
- return typeof value === "string" && value ? [value] : [];
21
+ if (typeof value === "string") return value ? [value] : [];
22
+ if (typeof value === "number") return [String(value)];
23
+ return [];
21
24
  });
22
25
  }
23
26
  function foldOptions(options, valueKey, labelKey) {
@@ -67,11 +70,11 @@ function TagMultiSelectImpl({
67
70
  const folded = useMemo(() => foldOptions(options, valueKey, labelKey), [options, valueKey, labelKey]);
68
71
  const isControlled = values !== void 0 && typeof onChange === "function";
69
72
  const [internalValues, setInternalValues] = useState(values ?? []);
70
- const current = isControlled ? values : internalValues;
73
+ const current = (isControlled ? values : internalValues) ?? [];
71
74
  const safeOptions = useMemo(() => {
72
75
  if (!keepUnknownValues) return folded;
73
76
  const known = new Set(folded.map((option) => option.value));
74
- const unknown = (current ?? []).filter((value) => value && !known.has(value)).map((value) => ({ value, label: value }));
77
+ const unknown = current.filter((value) => value && !known.has(value)).map((value) => ({ value, label: value }));
75
78
  return unknown.length > 0 ? [...folded, ...unknown] : folded;
76
79
  }, [folded, current, keepUnknownValues]);
77
80
  const currentSet = useMemo(() => new Set(current), [current]);
@@ -1,50 +1,17 @@
1
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DKPNFEVU.js';
2
- import { Select, Button } from './chunk-TUOG7EEI.js';
3
- import { boxed } from './chunk-YQOMSWW5.js';
4
- import { useState, useEffect, useMemo } from 'react';
1
+ import { fetchAllJobPositions } from './chunk-Z4PYMTTS.js';
2
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-KO6OEY3G.js';
3
+ import { Select, Button } from './chunk-RNOUXUBO.js';
4
+ import { boxed } from './chunk-5WW4MBRO.js';
5
+ import { useRef, useState, useEffect, useMemo } from 'react';
5
6
  import { jsxs, jsx } from 'react/jsx-runtime';
6
7
 
7
8
  var EMPTY_VALUE = "__wipco_position_none__";
8
9
  var LOADING_VALUE = "__wipco_position_loading__";
9
- var toNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
10
- function parseRow(raw) {
11
- if (typeof raw !== "object" || raw === null) return null;
12
- const row = raw;
13
- if (typeof row.name !== "string") return null;
14
- return {
15
- name: row.name,
16
- rankOrder: toNumber(row.rank_order),
17
- sortOrder: toNumber(row.sort_order),
18
- // is_active 결측은 true 폴백 — 파서 사정으로 목록이 전부 사라지는 사고 방지(v2와 동일).
19
- isActive: row.is_active === void 0 || row.is_active === null ? true : row.is_active === true
20
- };
21
- }
22
- async function fetchAllPositions(api, endpoint) {
23
- const LIMIT = 500;
24
- const MAX_PAGES = 10;
25
- const rows = [];
26
- let offset = 0;
27
- for (let page = 0; page < MAX_PAGES; page += 1) {
28
- const sep = endpoint.includes("?") ? "&" : "?";
29
- const res = await api(`${endpoint}${sep}limit=${LIMIT}&offset=${offset}`, {
30
- method: "GET"
31
- });
32
- const data = Array.isArray(res?.data) ? res.data : [];
33
- for (const raw of data) {
34
- const parsed = parseRow(raw);
35
- if (parsed) rows.push(parsed);
36
- }
37
- const total = typeof res?.total === "number" ? res.total : rows.length;
38
- offset += LIMIT;
39
- if (data.length === 0 || rows.length >= total) break;
40
- }
41
- return rows;
42
- }
43
10
  var inflight = /* @__PURE__ */ new Map();
44
11
  function loadPositions(api, endpoint) {
45
12
  const pending = inflight.get(endpoint);
46
13
  if (pending) return pending;
47
- const next = fetchAllPositions(api, endpoint).finally(() => {
14
+ const next = fetchAllJobPositions(api, endpoint).finally(() => {
48
15
  inflight.delete(endpoint);
49
16
  });
50
17
  inflight.set(endpoint, next);
@@ -59,16 +26,21 @@ function PositionSelectImpl({
59
26
  size,
60
27
  invalid,
61
28
  placeholder = "\uC9C1\uC704\uB97C \uC120\uD0DD\uD558\uC138\uC694",
29
+ emptyText = "\uB4F1\uB85D\uB41C \uC9C1\uC704\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
62
30
  id
63
31
  }) {
64
32
  const adapter = useSduiAdapter();
65
33
  const api = hostFetchOf(adapter) ?? defaultAdapter.fetch;
34
+ const apiRef = useRef(api);
35
+ apiRef.current = api;
66
36
  const [positions, setPositions] = useState(null);
67
37
  const [failed, setFailed] = useState(false);
68
38
  const [attempt, setAttempt] = useState(0);
69
39
  useEffect(() => {
70
40
  let alive = true;
71
- loadPositions(api, endpoint).then((rows2) => {
41
+ setPositions(null);
42
+ setFailed(false);
43
+ loadPositions(apiRef.current, endpoint).then((rows2) => {
72
44
  if (!alive) return;
73
45
  setPositions(rows2);
74
46
  setFailed(false);
@@ -80,7 +52,7 @@ function PositionSelectImpl({
80
52
  return () => {
81
53
  alive = false;
82
54
  };
83
- }, [attempt]);
55
+ }, [attempt, endpoint]);
84
56
  const isLoading = positions === null && !failed;
85
57
  const rows = useMemo(() => positions ?? [], [positions]);
86
58
  const activeByName = useMemo(() => {
@@ -151,7 +123,7 @@ function PositionSelectImpl({
151
123
  }
152
124
  )
153
125
  ] }),
154
- !isLoading && !failed && activeNames.length === 0 && !isOffList && /* @__PURE__ */ jsx("span", { className: "wp-caption", style: { color: "var(--wp-text-muted)" }, children: "\uB4F1\uB85D\uB41C \uC9C1\uC704\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uC778\uC0AC > \uC9C1\uC704 \uAD00\uB9AC\uC5D0\uC11C \uB4F1\uB85D\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4." })
126
+ !isLoading && !failed && activeNames.length === 0 && !isOffList && /* @__PURE__ */ jsx("span", { className: "wp-caption", style: { color: "var(--wp-text-muted)" }, children: emptyText })
155
127
  ] });
156
128
  }
157
129
  var PositionSelect = boxed(PositionSelectImpl, "PositionSelect");
@@ -1,6 +1,6 @@
1
- import { useSduiAssetResolver } from './chunk-DKPNFEVU.js';
2
- import { Spinner, Icon } from './chunk-TUOG7EEI.js';
3
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { useSduiAssetResolver } from './chunk-KO6OEY3G.js';
2
+ import { Spinner, Icon } from './chunk-RNOUXUBO.js';
3
+ import { boxed } from './chunk-5WW4MBRO.js';
4
4
  import { useState, useEffect } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
 
@@ -1,4 +1,4 @@
1
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { boxed } from './chunk-5WW4MBRO.js';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
 
4
4
  var resolveColor = (color, index) => {
@@ -20,7 +20,8 @@ function StackedMeterImpl({
20
20
  showLegend = true,
21
21
  height = 10
22
22
  }) {
23
- const positive = segments.filter((s) => s.value > 0);
23
+ const list = Array.isArray(segments) ? segments : [];
24
+ const positive = list.filter((s) => s.value > 0);
24
25
  const total = positive.reduce((sum, s) => sum + s.value, 0);
25
26
  const pctOf = (v) => total > 0 ? v / total * 100 : 0;
26
27
  return /* @__PURE__ */ jsxs("div", { children: [
@@ -28,7 +29,7 @@ function StackedMeterImpl({
28
29
  "div",
29
30
  {
30
31
  role: "img",
31
- "aria-label": total > 0 ? segments.map((s) => `${s.label} ${formatPercent(pctOf(s.value))}`).join(", ") : "\uB370\uC774\uD130 \uC5C6\uC74C",
32
+ "aria-label": total > 0 ? list.map((s) => `${s.label} ${formatPercent(pctOf(s.value))}`).join(", ") : "\uB370\uC774\uD130 \uC5C6\uC74C",
32
33
  style: {
33
34
  display: "flex",
34
35
  gap: "var(--wp-space-half)",
@@ -38,7 +39,7 @@ function StackedMeterImpl({
38
39
  background: "var(--wp-surface-sunken)",
39
40
  overflow: "hidden"
40
41
  },
41
- children: total > 0 && segments.map((s, i) => {
42
+ children: total > 0 && list.map((s, i) => {
42
43
  if (s.value <= 0) return null;
43
44
  const pct = pctOf(s.value);
44
45
  return /* @__PURE__ */ jsx(
@@ -57,7 +58,7 @@ function StackedMeterImpl({
57
58
  })
58
59
  }
59
60
  ),
60
- showLegend && segments.length > 0 && /* @__PURE__ */ jsx(
61
+ showLegend && list.length > 0 && /* @__PURE__ */ jsx(
61
62
  "div",
62
63
  {
63
64
  style: {
@@ -66,7 +67,7 @@ function StackedMeterImpl({
66
67
  gap: "var(--wp-space-1)",
67
68
  marginTop: "var(--wp-space-3)"
68
69
  },
69
- children: segments.map((s, i) => /* @__PURE__ */ jsxs(
70
+ children: list.map((s, i) => /* @__PURE__ */ jsxs(
70
71
  "div",
71
72
  {
72
73
  className: "wp-body-sm",
@@ -1,5 +1,5 @@
1
- import { Icon, Badge } from './chunk-TUOG7EEI.js';
2
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { Icon, Badge } from './chunk-RNOUXUBO.js';
2
+ import { boxed } from './chunk-5WW4MBRO.js';
3
3
  import React from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
5
 
@@ -1,7 +1,6 @@
1
+ import { warnOnce } from './chunk-RNOUXUBO.js';
1
2
  import { createContext, useContext } from 'react';
2
3
 
3
- // src/adapter.ts
4
-
5
4
  // src/env.ts
6
5
  var DEV = (() => {
7
6
  try {
@@ -17,7 +16,7 @@ function isSafeNavigationTarget(to) {
17
16
  if (typeof to !== "string") return false;
18
17
  const value = to.replace(/[\u0000-\u0020]/g, "");
19
18
  if (value === "") return false;
20
- if (value.startsWith("//")) return false;
19
+ if (/^[/\\][/\\]/.test(value)) return false;
21
20
  if (value.startsWith("/") || value.startsWith("?") || value.startsWith("#")) return true;
22
21
  return /^https?:\/\//i.test(value);
23
22
  }
@@ -39,8 +38,12 @@ async function defaultFetch(path, init) {
39
38
  }
40
39
  }
41
40
  if (!response.ok) {
42
- const message = json && typeof json === "object" && typeof json.message === "string" ? json.message : `\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4 (${response.status})`;
43
- throw new Error(message);
41
+ const detail = json;
42
+ const message = detail && typeof detail === "object" ? typeof detail.message === "string" ? detail.message : typeof detail.error === "string" ? detail.error : `\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4 (${response.status})` : `\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4 (${response.status})`;
43
+ const error = new Error(message);
44
+ error.status = response.status;
45
+ error.body = json;
46
+ throw error;
44
47
  }
45
48
  return json;
46
49
  }
@@ -99,7 +102,17 @@ function hostFetchOf(adapter) {
99
102
  function hostRawFetchOf(adapter) {
100
103
  const hostRawFetch = adapter?.rawFetch;
101
104
  if (!hostRawFetch || hostRawFetch === defaultAdapter.rawFetch) return null;
102
- return hostRawFetch;
105
+ if (!DEV) return hostRawFetch;
106
+ return (path, init) => {
107
+ if (init?.body !== void 0 && hostRawFetch.length < 2) {
108
+ warnOnce(
109
+ "adapter:rawFetch:init",
110
+ "[sdui] rawFetch \uAD6C\uD604\uC774 init \uB9E4\uAC1C\uBCC0\uC218\uB97C \uBC1B\uC9C0 \uC54A\uB294 \uAC83\uC73C\uB85C \uBCF4\uC785\uB2C8\uB2E4 \u2014 \uBCF8\uBB38(FormData \uB4F1)\uC774 \uC720\uC2E4\uB418\uBA74 \uC5C5\uB85C\uB4DC\uAC00 \uBCF8\uBB38 \uC5C6\uB294 GET\uC774 \uB429\uB2C8\uB2E4. (path, init) \uB450 \uC778\uC790\uB97C \uD758\uB9AC\uC138\uC694. (init\uC5D0 \uAE30\uBCF8\uAC12\uC744 \uC900 \uAD6C\uD604\uC774\uB77C\uBA74 \uBB34\uC2DC\uD574\uB3C4 \uB429\uB2C8\uB2E4)",
111
+ "warn"
112
+ );
113
+ }
114
+ return hostRawFetch(path, init);
115
+ };
103
116
  }
104
117
 
105
118
  export { DEV, SduiAdapterContext, assetResolverOf, defaultAdapter, hostFetchOf, hostRawFetchOf, isSafeNavigationTarget, resolveAdapter, useSduiAdapter, useSduiAssetResolver, useSduiSandbox };
@@ -1,6 +1,6 @@
1
- import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-DKPNFEVU.js';
2
- import { Icon, Badge, Checkbox, Select, Button } from './chunk-TUOG7EEI.js';
3
- import { boxed } from './chunk-YQOMSWW5.js';
1
+ import { useSduiAdapter, hostFetchOf, defaultAdapter } from './chunk-KO6OEY3G.js';
2
+ import { Icon, Badge, Checkbox, Select, Button } from './chunk-RNOUXUBO.js';
3
+ import { boxed } from './chunk-5WW4MBRO.js';
4
4
  import { useRef, useEffect, useMemo, useState } from 'react';
5
5
  import { jsx, jsxs } from 'react/jsx-runtime';
6
6
 
@@ -32,7 +32,7 @@ var operationOf = (code) => {
32
32
  const op = i > 0 ? code.slice(i + 1) : "";
33
33
  return OPERATIONS.some((o) => o.key === op) ? op : null;
34
34
  };
35
- function groupCatalog(catalog) {
35
+ function groupCatalog(catalog, categoryLabels, categoryOrder) {
36
36
  const categories = /* @__PURE__ */ new Map();
37
37
  for (const entry of catalog) {
38
38
  if (!entry || typeof entry.code !== "string") continue;
@@ -52,12 +52,12 @@ function groupCatalog(catalog) {
52
52
  }
53
53
  }
54
54
  const order = (c) => {
55
- const i = CATEGORY_ORDER.indexOf(c);
56
- return i < 0 ? CATEGORY_ORDER.length : i;
55
+ const i = categoryOrder.indexOf(c);
56
+ return i < 0 ? categoryOrder.length : i;
57
57
  };
58
58
  return [...categories.entries()].sort((a, b) => order(a[0]) - order(b[0]) || a[0].localeCompare(b[0])).map(([category, byEntity]) => ({
59
59
  category,
60
- label: CATEGORY_LABELS[category] ?? category,
60
+ label: categoryLabels[category] ?? category,
61
61
  rows: [...byEntity.values()].sort((a, b) => a.entity.localeCompare(b.entity))
62
62
  }));
63
63
  }
@@ -66,7 +66,12 @@ function PermissionMatrixEditorImpl({
66
66
  value,
67
67
  onChange,
68
68
  sourceEndpoint,
69
- disabled = false
69
+ disabled = false,
70
+ scopeOptions = SCOPE_OPTIONS,
71
+ defaultScope = "all",
72
+ categoryLabels = CATEGORY_LABELS,
73
+ categoryOrder = CATEGORY_ORDER,
74
+ emptyText = "\uAD8C\uD55C \uCE74\uD0C8\uB85C\uADF8\uAC00 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uD398\uC774\uC9C0\uC758 data \uC120\uC5B8(/permissions?limit=1000)\uC744 \uD655\uC778\uD558\uC138\uC694."
70
75
  }) {
71
76
  const adapter = useSduiAdapter();
72
77
  const api = hostFetchOf(adapter) ?? defaultAdapter.fetch;
@@ -85,18 +90,23 @@ function PermissionMatrixEditorImpl({
85
90
  if (typeof row !== "object" || row === null) return [];
86
91
  const { code, scope } = row;
87
92
  if (typeof code !== "string" || !code) return [];
88
- return [{ code, scope: typeof scope === "string" ? scope : "all" }];
93
+ return [{ code, scope: typeof scope === "string" ? scope : defaultScope }];
89
94
  })
90
95
  );
91
96
  }).catch(() => {
92
97
  });
93
- }, [sourceEndpoint]);
98
+ }, [sourceEndpoint, defaultScope]);
94
99
  const grants = useMemo(() => Array.isArray(value) ? value : [], [value]);
95
100
  const catalog = useMemo(
96
101
  () => Array.isArray(permissions) ? permissions : [],
97
102
  [permissions]
98
103
  );
99
- const groups = useMemo(() => groupCatalog(catalog), [catalog]);
104
+ const labelsKey = JSON.stringify(categoryLabels);
105
+ const orderKey = JSON.stringify(categoryOrder);
106
+ const groups = useMemo(
107
+ () => groupCatalog(catalog, categoryLabels, categoryOrder),
108
+ [catalog, labelsKey, orderKey]
109
+ );
100
110
  const granted = useMemo(() => new Set(grants.map((g) => g.code)), [grants]);
101
111
  const scopeOf = useMemo(() => {
102
112
  const map = /* @__PURE__ */ new Map();
@@ -117,7 +127,7 @@ function PermissionMatrixEditorImpl({
117
127
  onChange?.(
118
128
  [...nextGranted].sort().map((code) => ({
119
129
  code,
120
- scope: nextScopes.get(entityOf(code)) ?? "all"
130
+ scope: nextScopes.get(entityOf(code)) ?? defaultScope
121
131
  }))
122
132
  );
123
133
  };
@@ -158,7 +168,7 @@ function PermissionMatrixEditorImpl({
158
168
  textAlign: "center",
159
169
  color: "var(--wp-text-muted)"
160
170
  },
161
- children: "\uAD8C\uD55C \uCE74\uD0C8\uB85C\uADF8\uAC00 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uD398\uC774\uC9C0\uC758 data \uC120\uC5B8(/permissions?limit=1000)\uC744 \uD655\uC778\uD558\uC138\uC694."
171
+ children: emptyText
162
172
  }
163
173
  );
164
174
  }
@@ -168,7 +178,9 @@ function PermissionMatrixEditorImpl({
168
178
  catalog.length,
169
179
  "\uC885 \uC911 ",
170
180
  granted.size,
171
- "\uAC1C \uBD80\uC5EC\uB428 \xB7 \uBC94\uC704\uB294 \uC5D4\uD2F0\uD2F0 \uB2E8\uC704\uB85C \uC801\uC6A9\uB429\uB2C8\uB2E4 (\uD300 < \uBCF8\uBD80 < \uC804\uCCB4)"
181
+ "\uAC1C \uBD80\uC5EC\uB428 \xB7 \uBC94\uC704\uB294 \uC5D4\uD2F0\uD2F0 \uB2E8\uC704\uB85C \uC801\uC6A9\uB429\uB2C8\uB2E4 (",
182
+ scopeOptions.map((option) => option.label).join(" < "),
183
+ ")"
172
184
  ] }),
173
185
  /* @__PURE__ */ jsx(
174
186
  "div",
@@ -303,8 +315,8 @@ function PermissionMatrixEditorImpl({
303
315
  Select,
304
316
  {
305
317
  "aria-label": `${row.label || row.entity} \uBC94\uC704`,
306
- value: scopeOf.get(row.entity) ?? "all",
307
- options: SCOPE_OPTIONS,
318
+ value: scopeOf.get(row.entity) ?? defaultScope,
319
+ options: scopeOptions,
308
320
  disabled: disabled || !anyOn,
309
321
  onChange: (event) => setEntityScope(row.entity, event.target.value)
310
322
  }