@wipco/sdui 0.13.1 → 0.14.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 (49) hide show
  1. package/dist/{chunk-WJEGCCPY.js → chunk-4NPTFNAL.js} +1 -1
  2. package/dist/{chunk-4CZJF5PR.js → chunk-5C4SIRSW.js} +1 -1
  3. package/dist/{chunk-JWYBFODH.js → chunk-5YVXVGQ2.js} +1 -1
  4. package/dist/{chunk-PBGYAVQZ.js → chunk-6NAJ2D4A.js} +2 -2
  5. package/dist/{chunk-7AHNAX6T.js → chunk-BOSSWJTN.js} +1 -1
  6. package/dist/{chunk-X3DGYP4W.js → chunk-BS4LGGQV.js} +30 -6
  7. package/dist/{chunk-WMPSOKNI.js → chunk-CXZYC7IN.js} +1 -1
  8. package/dist/{chunk-BT4HC3WR.js → chunk-F2MKI3W5.js} +1 -1
  9. package/dist/{chunk-QIDMPWZH.js → chunk-FC2F37QH.js} +2 -2
  10. package/dist/{chunk-VK6KWB65.js → chunk-G4QIJHEP.js} +1 -1
  11. package/dist/{chunk-5A7BWIGN.js → chunk-HINKJD6C.js} +1 -1
  12. package/dist/{chunk-VV73LOAE.js → chunk-JND5NXUT.js} +9 -6
  13. package/dist/{chunk-TMAVD3WL.js → chunk-K55ODWRY.js} +16 -3
  14. package/dist/{chunk-UA5CT24N.js → chunk-K5ZJTLFP.js} +2 -2
  15. package/dist/{chunk-B5JTXYDB.js → chunk-LMHIRQZ6.js} +1 -0
  16. package/dist/{chunk-4IRLQWQC.js → chunk-LN6IOMCK.js} +1 -1
  17. package/dist/{chunk-3PYMVHL3.js → chunk-R3IK6EPA.js} +1 -1
  18. package/dist/{chunk-YFUQUWWH.js → chunk-VBCUIM7N.js} +2 -2
  19. package/dist/{chunk-FDVI3PWQ.js → chunk-X5X3FKCQ.js} +1 -1
  20. package/dist/{chunk-WLWWN5LW.js → chunk-YGSU34B3.js} +1 -1
  21. package/dist/index.d.ts +10 -2
  22. package/dist/index.js +63 -10
  23. package/dist/meta.d.ts +1 -1
  24. package/dist/meta.js +70 -3
  25. package/dist/rich.js +3 -3
  26. package/dist/{types-DO8_hC6A.d.ts → types-CeUhMB9Q.d.ts} +18 -0
  27. package/dist/widgets/AutocompleteField.js +3 -3
  28. package/dist/widgets/ColumnBoard.js +2 -2
  29. package/dist/widgets/DiffView.js +2 -2
  30. package/dist/widgets/Disclosure.js +2 -2
  31. package/dist/widgets/EventCalendar.js +2 -2
  32. package/dist/widgets/ImageLightbox.js +2 -2
  33. package/dist/widgets/InlineEdit.js +2 -2
  34. package/dist/widgets/JsonField.js +2 -2
  35. package/dist/widgets/OrgChart.js +2 -2
  36. package/dist/widgets/PeriodFilter.js +2 -2
  37. package/dist/widgets/PrintSheet.js +2 -2
  38. package/dist/widgets/SearchableMultiPicker.js +3 -3
  39. package/dist/widgets/SecureScreen.js +2 -2
  40. package/dist/widgets/TagMultiSelect.d.ts +9 -1
  41. package/dist/widgets/TagMultiSelect.js +2 -2
  42. package/dist/widgets/Timeline.js +3 -3
  43. package/dist/widgets/TreePicker.d.ts +7 -2
  44. package/dist/widgets/TreePicker.js +4 -3
  45. package/dist/widgets/TreeView.d.ts +27 -2
  46. package/dist/widgets/TreeView.js +3 -2
  47. package/dist/widgets/index.d.ts +1 -1
  48. package/dist/widgets/index.js +35 -35
  49. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { SegmentedControl, Select, Input } from './chunk-B5JTXYDB.js';
1
+ import { SegmentedControl, Select, Input } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useMemo } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Icon } from './chunk-B5JTXYDB.js';
1
+ import { Icon } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useRef, useState, useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Button } from './chunk-B5JTXYDB.js';
1
+ import { Button } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
- import { includesLooseSearch } from './chunk-QIDMPWZH.js';
2
- import { Icon, Button, Input, Spinner } from './chunk-B5JTXYDB.js';
1
+ import { includesLooseSearch } from './chunk-FC2F37QH.js';
2
+ import { Icon, Button, Input, Spinner } from './chunk-LMHIRQZ6.js';
3
3
  import { boxed } from './chunk-SAN4IX6N.js';
4
4
  import { useId, useRef, useState, useEffect, useMemo } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { IconButton, Input } from './chunk-B5JTXYDB.js';
1
+ import { IconButton, Input } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useRef, useEffect, useCallback } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,6 +1,7 @@
1
- import { Input, IconButton, EmptyState, Icon, Badge } from './chunk-B5JTXYDB.js';
1
+ import { buildCascadingTree } from './chunk-FC2F37QH.js';
2
+ import { Input, IconButton, EmptyState, Icon, Badge } from './chunk-LMHIRQZ6.js';
2
3
  import { boxed } from './chunk-SAN4IX6N.js';
3
- import React, { useState, useMemo } from 'react';
4
+ import React, { useMemo, useState, useRef, useEffect } from 'react';
4
5
  import { jsxs, jsx } from 'react/jsx-runtime';
5
6
 
6
7
  var INDENT = 24;
@@ -12,6 +13,20 @@ var TREE_CSS = `
12
13
  .erp-treeview__row[aria-current='true'],
13
14
  .erp-treeview__row[aria-current='true']:hover{background:var(--wp-surface-selected);}
14
15
  `;
16
+ function toTreeNodes(options) {
17
+ return options.map((option) => ({
18
+ id: option.value,
19
+ label: option.label,
20
+ ...option.children ? { children: toTreeNodes(option.children) } : null
21
+ }));
22
+ }
23
+ function buildTreeNodes(rows, tree) {
24
+ return toTreeNodes(buildCascadingTree(rows, tree));
25
+ }
26
+ function resolveTreeNodes(nodes, rows, tree) {
27
+ if (Array.isArray(rows) && rows.length > 0 && tree) return buildTreeNodes(rows, tree);
28
+ return nodes ?? [];
29
+ }
15
30
  function pruneExcluded(nodes, excluded) {
16
31
  if (excluded.size === 0) return nodes;
17
32
  const out = [];
@@ -59,6 +74,8 @@ function toggled(prev, id) {
59
74
  }
60
75
  function TreeViewImpl({
61
76
  nodes,
77
+ rows,
78
+ tree,
62
79
  selectedId,
63
80
  onSelect,
64
81
  searchable = false,
@@ -66,18 +83,25 @@ function TreeViewImpl({
66
83
  excludeIds,
67
84
  maxHeight
68
85
  }) {
69
- const [expanded, setExpanded] = useState(() => collectExpandedIds(nodes, defaultExpandedDepth));
86
+ const sourceNodes = useMemo(() => resolveTreeNodes(nodes, rows, tree), [nodes, rows, tree]);
87
+ const [expanded, setExpanded] = useState(() => collectExpandedIds(sourceNodes, defaultExpandedDepth));
70
88
  const [searchCollapsed, setSearchCollapsed] = useState(() => /* @__PURE__ */ new Set());
71
89
  const [query, setQuery] = useState("");
72
90
  const [innerSelected, setInnerSelected] = useState(null);
91
+ const hadRows = useRef(Array.isArray(rows) && rows.length > 0);
92
+ useEffect(() => {
93
+ const hasRows = Array.isArray(rows) && rows.length > 0;
94
+ if (hasRows && !hadRows.current) setExpanded(collectExpandedIds(sourceNodes, defaultExpandedDepth));
95
+ hadRows.current = hasRows;
96
+ }, [rows, sourceNodes, defaultExpandedDepth]);
73
97
  const isControlled = selectedId !== void 0;
74
98
  const currentSelected = isControlled ? selectedId : innerSelected;
75
99
  const trimmedQuery = query.trim().toLowerCase();
76
100
  const searching = trimmedQuery.length > 0;
77
101
  const visibleNodes = useMemo(() => {
78
- const pruned = pruneExcluded(nodes, new Set(excludeIds ?? []));
102
+ const pruned = pruneExcluded(sourceNodes, new Set(excludeIds ?? []));
79
103
  return searching ? filterTree(pruned, trimmedQuery) : pruned;
80
- }, [nodes, excludeIds, searching, trimmedQuery]);
104
+ }, [sourceNodes, excludeIds, searching, trimmedQuery]);
81
105
  const isOpen = (id) => searching ? !searchCollapsed.has(id) : expanded.has(id);
82
106
  const toggleNode = (id) => {
83
107
  if (searching) setSearchCollapsed((prev) => toggled(prev, id));
@@ -259,4 +283,4 @@ function TreeViewImpl({
259
283
  }
260
284
  var TreeView = boxed(TreeViewImpl, "TreeView");
261
285
 
262
- export { TreeView };
286
+ export { TreeView, buildTreeNodes, pruneExcluded, resolveTreeNodes };
@@ -1,4 +1,4 @@
1
- import { SegmentedControl, IconButton, Button, Tag, EmptyState, Icon, Badge } from './chunk-B5JTXYDB.js';
1
+ import { SegmentedControl, IconButton, Button, Tag, EmptyState, Icon, Badge } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useMemo } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { IconButton, Badge } from './chunk-B5JTXYDB.js';
1
+ import { IconButton, Badge } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useRef, useState, useMemo, useCallback, useEffect } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Input, Button, IconButton, Tag, Field, Checkbox } from './chunk-B5JTXYDB.js';
1
+ import { Input, Button, IconButton, Tag, Field, Checkbox } from './chunk-LMHIRQZ6.js';
2
2
  import { useRef, useEffect, useState, useMemo } from 'react';
3
3
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
4
4
 
@@ -623,4 +623,4 @@ function CascadingLevelSelect({
623
623
  );
624
624
  }
625
625
 
626
- export { Popover, SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchFields, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue };
626
+ export { Popover, SearchToolbar, buildCascadingTree, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchFields, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue };
@@ -1,4 +1,4 @@
1
- import { Badge, Checkbox, IconButton, Icon } from './chunk-B5JTXYDB.js';
1
+ import { Badge, Checkbox, IconButton, Icon } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useEffect } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Icon } from './chunk-B5JTXYDB.js';
1
+ import { Icon } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { createContext, useState, useRef, useMemo, useCallback, useEffect, useLayoutEffect, useContext } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
- import { TreeView } from './chunk-X3DGYP4W.js';
2
- import { Field, Dialog, Icon, Button, Input } from './chunk-B5JTXYDB.js';
1
+ import { resolveTreeNodes, TreeView } from './chunk-BS4LGGQV.js';
2
+ import { Field, Dialog, Icon, Button, Input } from './chunk-LMHIRQZ6.js';
3
3
  import { boxed } from './chunk-SAN4IX6N.js';
4
- import { useState, useEffect } from 'react';
4
+ import { useState, useMemo, useEffect } from 'react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
 
7
7
  var PICKER_CSS = `
@@ -23,6 +23,8 @@ function findNode(nodes, id) {
23
23
  }
24
24
  function TreePickerImpl({
25
25
  nodes,
26
+ rows,
27
+ tree,
26
28
  value,
27
29
  valueLabel,
28
30
  onChange,
@@ -35,9 +37,10 @@ function TreePickerImpl({
35
37
  const [open, setOpen] = useState(false);
36
38
  const [pendingId, setPendingId] = useState(null);
37
39
  const [innerValue, setInnerValue] = useState(null);
40
+ const sourceNodes = useMemo(() => resolveTreeNodes(nodes, rows, tree), [nodes, rows, tree]);
38
41
  const isControlled = value !== void 0;
39
42
  const current = isControlled ? value : innerValue;
40
- const currentNode = current != null ? findNode(nodes, current) : void 0;
43
+ const currentNode = current != null ? findNode(sourceNodes, current) : void 0;
41
44
  const displayLabel = current == null ? "" : currentNode?.label ?? valueLabel ?? current;
42
45
  const openDialog = () => {
43
46
  if (disabled) return;
@@ -46,7 +49,7 @@ function TreePickerImpl({
46
49
  };
47
50
  const closeDialog = () => setOpen(false);
48
51
  const commit = () => {
49
- const node = pendingId != null ? findNode(nodes, pendingId) : void 0;
52
+ const node = pendingId != null ? findNode(sourceNodes, pendingId) : void 0;
50
53
  if (!isControlled) setInnerValue(pendingId);
51
54
  onChange?.(pendingId, node);
52
55
  setOpen(false);
@@ -175,7 +178,7 @@ function TreePickerImpl({
175
178
  /* @__PURE__ */ jsx(
176
179
  TreeView,
177
180
  {
178
- nodes,
181
+ nodes: sourceNodes,
179
182
  selectedId: pendingId,
180
183
  onSelect: (id) => setPendingId(id),
181
184
  searchable: true,
@@ -1,16 +1,29 @@
1
- import { Badge, Tag } from './chunk-B5JTXYDB.js';
1
+ import { Badge, Tag } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
- import { useState, useMemo } from 'react';
3
+ import { useMemo, useState } from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
6
+ function foldOptions(options, valueKey, labelKey) {
7
+ if (!Array.isArray(options)) return [];
8
+ return options.flatMap((raw) => {
9
+ if (raw === null || typeof raw !== "object") return [];
10
+ const row = raw;
11
+ const value = (valueKey ? row[valueKey] : void 0) ?? row.value;
12
+ if (value === void 0 || value === null) return [];
13
+ const label = (labelKey ? row[labelKey] : void 0) ?? row.label ?? value;
14
+ return [{ value: String(value), label: String(label) }];
15
+ });
16
+ }
6
17
  function TagMultiSelectImpl({
7
18
  options,
19
+ valueKey,
20
+ labelKey,
8
21
  values,
9
22
  onChange,
10
23
  disabled = false,
11
24
  emptyText = "\uC120\uD0DD\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4"
12
25
  }) {
13
- const safeOptions = options ?? [];
26
+ const safeOptions = useMemo(() => foldOptions(options, valueKey, labelKey), [options, valueKey, labelKey]);
14
27
  const isControlled = values !== void 0 && typeof onChange === "function";
15
28
  const [internalValues, setInternalValues] = useState(values ?? []);
16
29
  const current = isControlled ? values : internalValues;
@@ -1,5 +1,5 @@
1
- import { includesLooseSearch } from './chunk-QIDMPWZH.js';
2
- import { Button, Dialog, Input, Tag, Checkbox } from './chunk-B5JTXYDB.js';
1
+ import { includesLooseSearch } from './chunk-FC2F37QH.js';
2
+ import { Button, Dialog, Input, Tag, Checkbox } from './chunk-LMHIRQZ6.js';
3
3
  import { boxed } from './chunk-SAN4IX6N.js';
4
4
  import React, { useMemo, useState, useEffect } from 'react';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -750,6 +750,7 @@ function Button({
750
750
  style: mergeStyle(containerLayoutStyle({ justify }), style),
751
751
  disabled: Tag2 === "button" ? disabled || loading : void 0,
752
752
  "aria-disabled": disabled || void 0,
753
+ type: Tag2 === "button" ? "button" : void 0,
753
754
  ...rest,
754
755
  children: [
755
756
  icon ? /* @__PURE__ */ jsx(Icon, { name: icon, size: iconSize }) : null,
@@ -1,4 +1,4 @@
1
- import { Icon, Badge } from './chunk-B5JTXYDB.js';
1
+ import { Icon, Badge } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import React from 'react';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { IconButton } from './chunk-B5JTXYDB.js';
1
+ import { IconButton } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useRef, useCallback, useEffect } from 'react';
4
4
  import { createPortal } from 'react-dom';
@@ -1,5 +1,5 @@
1
- import { Disclosure } from './chunk-WLWWN5LW.js';
2
- import { Icon } from './chunk-B5JTXYDB.js';
1
+ import { Disclosure } from './chunk-YGSU34B3.js';
2
+ import { Icon } from './chunk-LMHIRQZ6.js';
3
3
  import { boxed } from './chunk-SAN4IX6N.js';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
5
 
@@ -1,4 +1,4 @@
1
- import { Textarea, Icon } from './chunk-B5JTXYDB.js';
1
+ import { Textarea, Icon } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useRef, useId, useEffect, useCallback } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { Icon } from './chunk-B5JTXYDB.js';
1
+ import { Icon } from './chunk-LMHIRQZ6.js';
2
2
  import { boxed } from './chunk-SAN4IX6N.js';
3
3
  import { useState, useId, useCallback } from 'react';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { CSSProperties, ReactNode, ComponentType } from 'react';
3
- import { S as SduiAction, a as SduiPropValue, b as SduiRule, c as SduiPage } from './types-DO8_hC6A.js';
4
- export { d as SduiCalcRef, e as SduiChild, f as SduiIndexRef, g as SduiItemRef, h as SduiNode, i as SduiPageQuery, j as SduiScalar, k as SduiStateRef } from './types-DO8_hC6A.js';
3
+ import { S as SduiAction, a as SduiPropValue, b as SduiRule, c as SduiPage } from './types-CeUhMB9Q.js';
4
+ export { d as SduiCalcRef, e as SduiChild, f as SduiIndexRef, g as SduiItemRef, h as SduiNode, i as SduiPageQuery, j as SduiScalar, k as SduiStateRef } from './types-CeUhMB9Q.js';
5
5
  import { S as SduiBoxProps, a as SduiContainerLayoutProps, b as SduiColumnsScale, c as SduiGapScale, d as SduiWeightScale, e as SduiTextAlignScale } from './layout-B1QrIBm6.js';
6
6
  export { C as CHILD_LAYOUT_PROPS, L as LAYOUT_CSS, f as SduiAlignScale, g as SduiChildLayoutProps, h as SduiSizeScale, i as SduiSpanScale, j as childLayoutFrom, k as columnsClass, l as containerLayoutStyle, m as joinClass, n as mergeStyle, t as typographyStyle } from './layout-B1QrIBm6.js';
7
7
  import { D as DatePickerProps, a as DateRangePickerProps } from './DatePicker-BndreCPl.js';
@@ -448,6 +448,12 @@ interface SduiTextCell {
448
448
  interface SduiBadgeCell {
449
449
  type: 'badge';
450
450
  toneMap?: Record<string, BadgeTone>;
451
+ /**
452
+ * 값 → 표시 텍스트(생략 시 값 그대로) — Table 컬럼 badge와 같은 의미론.
453
+ * 톤 조회 키는 여전히 **원래 값**이다. labelMap이 조회 키까지 바꾸면 기존 스펙의
454
+ * toneMap(enum 키)이 전부 neutral로 떨어진다.
455
+ */
456
+ labelMap?: Record<string, string>;
451
457
  }
452
458
  /** 값을 태그로. 선행 점 색은 값별 매핑(CSS 색상 문자열). */
453
459
  interface SduiTagCell {
@@ -550,9 +556,11 @@ interface SduiGridCardAction {
550
556
  interface SduiGridCard {
551
557
  titleKey: string;
552
558
  subtitleKey?: string;
559
+ /** 카드 우상단 배지 — labelMap은 표시 텍스트만 바꾸고 톤 조회 키는 원래 값이다(셀 badge와 같은 규칙) */
553
560
  badge?: {
554
561
  key: string;
555
562
  toneMap?: Record<string, BadgeTone>;
563
+ labelMap?: Record<string, string>;
556
564
  };
557
565
  /** 한 열로 쌓는 행 */
558
566
  rows?: SduiGridCardRow[];
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import { DEV, HoistedStyle, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, DateRangePicker, DatePicker, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-5A7BWIGN.js';
2
- export { DatePicker, DateRangePicker, defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-5A7BWIGN.js';
3
- import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-QIDMPWZH.js';
4
- export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-QIDMPWZH.js';
5
- import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea, Tabs, Table, Switch, StatCard, Input, IconButton, Field, Alert, warnOnce, Dialog } from './chunk-B5JTXYDB.js';
6
- export { Alert, Avatar, Badge, Breadcrumb, Button, Card, Checkbox, Dialog, EmptyState, Field, Icon, IconButton, Input, Pagination, ProgressBar, Radio, SegmentedControl, Select, SidebarNav, Spinner, StatCard, Switch, Table, Tabs, Tag, Textarea, Toast, Tooltip } from './chunk-B5JTXYDB.js';
1
+ import { DEV, HoistedStyle, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, DateRangePicker, DatePicker, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-HINKJD6C.js';
2
+ export { DatePicker, DateRangePicker, defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-HINKJD6C.js';
3
+ import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-FC2F37QH.js';
4
+ export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-FC2F37QH.js';
5
+ import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea, Tabs, Table, Switch, StatCard, Input, IconButton, Field, Alert, warnOnce, Dialog } from './chunk-LMHIRQZ6.js';
6
+ export { Alert, Avatar, Badge, Breadcrumb, Button, Card, Checkbox, Dialog, EmptyState, Field, Icon, IconButton, Input, Pagination, ProgressBar, Radio, SegmentedControl, Select, SidebarNav, Spinner, StatCard, Switch, Table, Tabs, Tag, Textarea, Toast, Tooltip } from './chunk-LMHIRQZ6.js';
7
7
  import { boxed, mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-SAN4IX6N.js';
8
8
  export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, boxed, childLayoutFrom, columnsClass, containerLayoutStyle, joinClass, mergeStyle, typographyStyle } from './chunk-SAN4IX6N.js';
9
9
  import React, { createContext, useState, useMemo, useContext, useRef, useEffect, useCallback } from 'react';
@@ -347,7 +347,7 @@ function cellRenderer(cell, key, dispatch) {
347
347
  return (row) => {
348
348
  const value = String(row[key] ?? "");
349
349
  if (!value) return null;
350
- return /* @__PURE__ */ jsx(Badge, { tone: cell.toneMap?.[value] ?? "neutral", children: value });
350
+ return /* @__PURE__ */ jsx(Badge, { tone: cell.toneMap?.[value] ?? "neutral", children: cell.labelMap?.[value] ?? value });
351
351
  };
352
352
  case "tag":
353
353
  return (row) => {
@@ -1111,7 +1111,10 @@ function mapGridCard(gridCard, dispatch) {
1111
1111
  badge: gridCard.badge ? (row) => {
1112
1112
  const value = String(row[gridCard.badge.key] ?? "");
1113
1113
  if (!value) return null;
1114
- return { text: value, variant: gridCard.badge.toneMap?.[value] ?? "neutral" };
1114
+ return {
1115
+ text: gridCard.badge.labelMap?.[value] ?? value,
1116
+ variant: gridCard.badge.toneMap?.[value] ?? "neutral"
1117
+ };
1115
1118
  } : void 0,
1116
1119
  rows: mapCardRows(gridCard.rows, dispatch),
1117
1120
  leftRows: mapCardRows(gridCard.leftRows, dispatch),
@@ -1711,6 +1714,33 @@ function createRegistry(extensions) {
1711
1714
  return { ...defaultRegistry, ...extensions };
1712
1715
  }
1713
1716
 
1717
+ // src/request-action.ts
1718
+ function deferChainEntry(container, key) {
1719
+ return typeof container.action === "string" && (key === "onSuccess" || key === "onError");
1720
+ }
1721
+ async function runRequestAction(action, deps) {
1722
+ try {
1723
+ if (typeof action.endpoint !== "string" || action.endpoint === "") {
1724
+ throw new Error("request \uC561\uC158\uC758 endpoint\uAC00 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 \u2014 $state \uCC38\uC870\uC5D0 \uC544\uC9C1 \uAC12\uC774 \uC5C6\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694");
1725
+ }
1726
+ const response = await deps.fetch(action.endpoint, {
1727
+ method: action.method ?? "POST",
1728
+ ...action.body === void 0 ? {} : { body: action.body }
1729
+ });
1730
+ if (typeof action.invalidate === "string" && action.invalidate !== "") {
1731
+ deps.dispatch({ action: "invalidate", prefix: action.invalidate });
1732
+ }
1733
+ (action.onSuccess ?? []).forEach((a) => deps.dispatch(a, response));
1734
+ } catch (error) {
1735
+ const message = error instanceof Error ? error.message : "\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4";
1736
+ if (action.onError?.length) {
1737
+ action.onError.forEach((a) => deps.dispatch(a, message));
1738
+ } else {
1739
+ deps.toast({ tone: "danger", title: "\uC694\uCCAD \uC2E4\uD328", message });
1740
+ }
1741
+ }
1742
+ }
1743
+
1714
1744
  // src/validate.ts
1715
1745
  var ACTION_NAMES = /* @__PURE__ */ new Set([
1716
1746
  "navigate",
@@ -1719,6 +1749,7 @@ var ACTION_NAMES = /* @__PURE__ */ new Set([
1719
1749
  "close",
1720
1750
  "toast",
1721
1751
  "submitForm",
1752
+ "request",
1722
1753
  "invalidate",
1723
1754
  "refresh",
1724
1755
  "download",
@@ -2004,6 +2035,15 @@ function pickPath(source, path) {
2004
2035
  }
2005
2036
  return value;
2006
2037
  }
2038
+ function planStamp(plan, epochs) {
2039
+ return `${plan.endpoint}#${epochs[plan.key] ?? 0}`;
2040
+ }
2041
+ function revertUnsettledStamps(fetched, runnable, epochs, settled) {
2042
+ for (const plan of runnable) {
2043
+ if (settled.has(plan.key)) continue;
2044
+ if (fetched.get(plan.key) === planStamp(plan, epochs)) fetched.delete(plan.key);
2045
+ }
2046
+ }
2007
2047
  function isPlainObject3(v) {
2008
2048
  return typeof v === "object" && v !== null && !Array.isArray(v);
2009
2049
  }
@@ -2442,7 +2482,9 @@ function SduiRenderer({
2442
2482
  if (Array.isArray(value)) return value.map((v) => resolveValue(v, scope));
2443
2483
  if (isPlainObject3(value)) {
2444
2484
  const out = {};
2445
- for (const [k, v] of Object.entries(value)) out[k] = resolveValue(v, scope);
2485
+ for (const [k, v] of Object.entries(value)) {
2486
+ out[k] = deferChainEntry(value, k) ? v : resolveValue(v, scope);
2487
+ }
2446
2488
  return out;
2447
2489
  }
2448
2490
  return value;
@@ -2465,7 +2507,7 @@ function SduiRenderer({
2465
2507
  useEffect(() => {
2466
2508
  const epochs = dataEpochsRef.current;
2467
2509
  const runnable = runnablePlans(dataPlanRef.current).filter((plan) => {
2468
- const stamp = `${plan.endpoint}#${epochs[plan.key] ?? 0}`;
2510
+ const stamp = planStamp(plan, epochs);
2469
2511
  if (fetchedRef.current.get(plan.key) === stamp) return false;
2470
2512
  fetchedRef.current.set(plan.key, stamp);
2471
2513
  return true;
@@ -2474,6 +2516,7 @@ function SduiRenderer({
2474
2516
  const controller = new AbortController();
2475
2517
  let cancelled = false;
2476
2518
  const timers = [];
2519
+ const settled = /* @__PURE__ */ new Set();
2477
2520
  setEntries(
2478
2521
  Object.fromEntries(runnable.map((plan) => [`${plan.key}.$loading`, true]))
2479
2522
  );
@@ -2497,6 +2540,7 @@ function SduiRenderer({
2497
2540
  `[sdui] page.data.${plan.key}: \uC751\uB2F5\uC5D0 "${plan.select}" \uACBD\uB85C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uAC12 \uC5C6\uC74C\uC73C\uB85C \uB461\uB2C8\uB2E4 (${plan.endpoint})`
2498
2541
  );
2499
2542
  }
2543
+ settled.add(plan.key);
2500
2544
  setEntries({
2501
2545
  [plan.key]: picked,
2502
2546
  [`${plan.key}.$loading`]: false,
@@ -2506,6 +2550,7 @@ function SduiRenderer({
2506
2550
  if (cancelled || controller.signal.aborted) return;
2507
2551
  const message = error instanceof Error ? error.message : "\uC870\uD68C\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4";
2508
2552
  warnOnce2(`data:${plan.key}:${plan.endpoint}`, `[sdui] page.data.${plan.key} \uC870\uD68C \uC2E4\uD328 (${plan.endpoint}): ${message}`);
2553
+ settled.add(plan.key);
2509
2554
  setEntries({
2510
2555
  [plan.key]: plan.fallback ?? void 0,
2511
2556
  [`${plan.key}.$loading`]: false,
@@ -2518,6 +2563,7 @@ function SduiRenderer({
2518
2563
  cancelled = true;
2519
2564
  controller.abort();
2520
2565
  timers.forEach(clearTimeout);
2566
+ revertUnsettledStamps(fetchedRef.current, runnable, epochs, settled);
2521
2567
  };
2522
2568
  }, [dataPlanKey, dataEpochKey, setEntries]);
2523
2569
  const dispatchRef = useRef(() => {
@@ -2646,6 +2692,13 @@ function SduiRenderer({
2646
2692
  })();
2647
2693
  break;
2648
2694
  }
2695
+ case "request":
2696
+ void runRequestAction(action, {
2697
+ fetch: (path, init) => hostRef.current.fetch(path, init),
2698
+ dispatch: (a, value) => dispatchRef.current(a, value),
2699
+ toast: pushToast
2700
+ });
2701
+ break;
2649
2702
  case "invalidate": {
2650
2703
  hostRef.current.invalidate?.(action.prefix, action.exact ?? false);
2651
2704
  const prefix = typeof action.prefix === "string" ? action.prefix : "";
package/dist/meta.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as SduiPropValue, h as SduiNode } from './types-DO8_hC6A.js';
1
+ import { a as SduiPropValue, h as SduiNode } from './types-CeUhMB9Q.js';
2
2
 
3
3
  /**
4
4
  * 시각 빌더용 컴포넌트 메타데이터 스키마.
package/dist/meta.js CHANGED
@@ -1806,6 +1806,12 @@ var searchCellFields = [
1806
1806
  ]
1807
1807
  },
1808
1808
  { name: "toneMap", kind: "object", label: "\uAC12 \u2192 \uD1A4", description: "type=badge (\uC5C6\uB294 \uAC12\uC740 neutral)" },
1809
+ {
1810
+ name: "labelMap",
1811
+ kind: "object",
1812
+ label: "\uAC12 \u2192 \uD45C\uC2DC \uBB38\uAD6C",
1813
+ description: "type=badge (\uC5C6\uB294 \uAC12\uC740 \uC6D0\uBB38 \uADF8\uB300\uB85C, \uD1A4 \uC870\uD68C \uD0A4\uB294 \uC6D0\uB798 \uAC12)"
1814
+ },
1809
1815
  { name: "colorMap", kind: "object", label: "\uAC12 \u2192 \uC810 \uC0C9", description: "type=tag" },
1810
1816
  { name: "filled", kind: "boolean", label: "\uCC44\uC6B4 \uD0DC\uADF8", description: "type=tag" },
1811
1817
  {
@@ -1955,7 +1961,7 @@ var searchCommonProps = [
1955
1961
  fields: [
1956
1962
  { name: "titleKey", kind: "string", label: "\uC81C\uBAA9 \uD544\uB4DC", required: true },
1957
1963
  { name: "subtitleKey", kind: "string", label: "\uBD80\uC81C \uD544\uB4DC" },
1958
- { name: "badge", kind: "object", label: "\uBC30\uC9C0", description: "{ key, toneMap }" },
1964
+ { name: "badge", kind: "object", label: "\uBC30\uC9C0", description: "{ key, toneMap, labelMap } \u2014 labelMap\uC740 \uD45C\uC2DC \uBB38\uAD6C\uB9CC \uBC14\uAFBC\uB2E4" },
1959
1965
  { name: "rows", kind: "array", label: "\uD589", item: searchCardRowFields },
1960
1966
  {
1961
1967
  name: "leftRows",
@@ -3493,12 +3499,29 @@ var TagMultiSelectMeta = {
3493
3499
  label: "\uC635\uC158",
3494
3500
  required: true,
3495
3501
  bindable: true,
3502
+ description: "\uAE30\uBCF8\uC740 \uC544\uB798 \uD589 \uD3B8\uC9D1\uAE30\uC758 {\uAC12, \uD45C\uC2DC} \uBAA8\uC591\uC774\uB2E4. \uB3C4\uBA54\uC778 \uD589 \uBAA9\uB85D\uC744 \uADF8\uB300\uB85C \uBB3C\uB9B4 \uAC70\uBA74(\uC608: /employees\uC758 {id, name}) \uAC12 \uD0A4\xB7\uB77C\uBCA8 \uD0A4\uB85C \uC77D\uC744 \uC790\uB9AC\uB97C \uC54C\uB824 \uC900\uB2E4.",
3496
3503
  group: "data",
3497
3504
  item: [
3498
3505
  { name: "value", kind: "string", label: "\uAC12", required: true },
3499
3506
  { name: "label", kind: "string", label: "\uD45C\uC2DC", required: true }
3500
3507
  ]
3501
3508
  },
3509
+ {
3510
+ name: "valueKey",
3511
+ kind: "string",
3512
+ label: "\uAC12 \uD0A4",
3513
+ default: "value",
3514
+ description: "\uC635\uC158\uC5D0\uC11C \uAC12\uC744 \uC77D\uC744 \uD0A4. Select\uC758 \uAC19\uC740 \uC774\uB984 \uD504\uB86D\uACFC \uB73B\uC774 \uAC19\uB2E4.",
3515
+ group: "data"
3516
+ },
3517
+ {
3518
+ name: "labelKey",
3519
+ kind: "string",
3520
+ label: "\uB77C\uBCA8 \uD0A4",
3521
+ default: "label",
3522
+ description: "\uC635\uC158\uC5D0\uC11C \uD45C\uC2DC \uB77C\uBCA8\uC744 \uC77D\uC744 \uD0A4. \uADF8 \uC790\uB9AC\uAC00 \uBE44\uBA74 \uAC12\uC73C\uB85C \uB300\uC2E0 \uADF8\uB9B0\uB2E4.",
3523
+ group: "data"
3524
+ },
3502
3525
  {
3503
3526
  name: "values",
3504
3527
  kind: "array",
@@ -3541,11 +3564,33 @@ var TreePickerMeta = {
3541
3564
  name: "nodes",
3542
3565
  kind: "array",
3543
3566
  label: "\uD2B8\uB9AC",
3544
- required: true,
3545
3567
  bindable: true,
3568
+ description: "rows\uAC00 \uBE44\uC5B4 \uC788\uC744 \uB54C\uC758 \uD3F4\uBC31 \u2014 \uCE94\uBC84\uC2A4 \uB370\uBAA8\uB294 \uC5EC\uAE30 \uB454\uB2E4.",
3546
3569
  group: "data",
3547
3570
  item: treeNodeItem
3548
3571
  },
3572
+ {
3573
+ name: "rows",
3574
+ kind: "array",
3575
+ label: "\uD3C9\uBA74 \uD589",
3576
+ bindable: true,
3577
+ description: "{id, parent_id, name} \uAC19\uC740 \uD3C9\uBA74 \uBAA9\uB85D. \uBE44\uC5B4\uC788\uC9C0 \uC54A\uC73C\uBA74 tree \uB9E4\uD551\uC73C\uB85C \uACC4\uCE35\uC744 \uC138\uC6B4\uB2E4 \u2014 /categories\uCC98\uB7FC \uD3C9\uBA74\uC73C\uB85C \uC8FC\uB294 API\uB97C \uADF8\uB300\uB85C \uBC14\uC778\uB529\uD55C\uB2E4.",
3578
+ group: "data",
3579
+ item: [],
3580
+ itemKind: "object"
3581
+ },
3582
+ {
3583
+ name: "tree",
3584
+ kind: "object",
3585
+ label: "\uD589 \u2192 \uD2B8\uB9AC \uB9E4\uD551",
3586
+ description: "\uD3C9\uBA74 \uD589\uC5D0\uC11C \uC77D\uC744 \uD0A4 \uC774\uB984. \uC0C1\uC138\uAC80\uC0C9 cascading\uC758 tree\uC640 \uAC19\uC740 \uACC4\uC57D\uC774\uB2E4.",
3587
+ group: "data",
3588
+ fields: [
3589
+ { name: "idKey", kind: "string", label: "id \uD0A4", required: true },
3590
+ { name: "parentIdKey", kind: "string", label: "\uBD80\uBAA8 id \uD0A4", required: true },
3591
+ { name: "labelKey", kind: "string", label: "\uB77C\uBCA8 \uD0A4", required: true }
3592
+ ]
3593
+ },
3549
3594
  {
3550
3595
  name: "value",
3551
3596
  kind: "string",
@@ -4198,11 +4243,33 @@ var TreeViewMeta = {
4198
4243
  name: "nodes",
4199
4244
  kind: "array",
4200
4245
  label: "\uD2B8\uB9AC",
4201
- required: true,
4202
4246
  bindable: true,
4247
+ description: "rows\uAC00 \uBE44\uC5B4 \uC788\uC744 \uB54C\uC758 \uD3F4\uBC31 \u2014 \uCE94\uBC84\uC2A4 \uB370\uBAA8\uB294 \uC5EC\uAE30 \uB454\uB2E4.",
4203
4248
  group: "data",
4204
4249
  item: treeNodeItem
4205
4250
  },
4251
+ {
4252
+ name: "rows",
4253
+ kind: "array",
4254
+ label: "\uD3C9\uBA74 \uD589",
4255
+ bindable: true,
4256
+ description: "{id, parent_id, name} \uAC19\uC740 \uD3C9\uBA74 \uBAA9\uB85D. \uBE44\uC5B4\uC788\uC9C0 \uC54A\uC73C\uBA74 tree \uB9E4\uD551\uC73C\uB85C \uACC4\uCE35\uC744 \uC138\uC6B4\uB2E4 \u2014 /categories\uCC98\uB7FC \uD3C9\uBA74\uC73C\uB85C \uC8FC\uB294 API\uB97C \uADF8\uB300\uB85C \uBC14\uC778\uB529\uD55C\uB2E4.",
4257
+ group: "data",
4258
+ item: [],
4259
+ itemKind: "object"
4260
+ },
4261
+ {
4262
+ name: "tree",
4263
+ kind: "object",
4264
+ label: "\uD589 \u2192 \uD2B8\uB9AC \uB9E4\uD551",
4265
+ description: "\uD3C9\uBA74 \uD589\uC5D0\uC11C \uC77D\uC744 \uD0A4 \uC774\uB984. \uC0C1\uC138\uAC80\uC0C9 cascading\uC758 tree\uC640 \uAC19\uC740 \uACC4\uC57D\uC774\uB2E4.",
4266
+ group: "data",
4267
+ fields: [
4268
+ { name: "idKey", kind: "string", label: "id \uD0A4", required: true },
4269
+ { name: "parentIdKey", kind: "string", label: "\uBD80\uBAA8 id \uD0A4", required: true },
4270
+ { name: "labelKey", kind: "string", label: "\uB77C\uBCA8 \uD0A4", required: true }
4271
+ ]
4272
+ },
4206
4273
  {
4207
4274
  name: "selectedId",
4208
4275
  kind: "string",
package/dist/rich.js CHANGED
@@ -1,6 +1,6 @@
1
- import { useSduiAssetResolver, HoistedStyle } from './chunk-5A7BWIGN.js';
2
- export { DatePicker, DateRangePicker } from './chunk-5A7BWIGN.js';
3
- import { Spinner, EmptyState } from './chunk-B5JTXYDB.js';
1
+ import { useSduiAssetResolver, HoistedStyle } from './chunk-HINKJD6C.js';
2
+ export { DatePicker, DateRangePicker } from './chunk-HINKJD6C.js';
3
+ import { Spinner, EmptyState } from './chunk-LMHIRQZ6.js';
4
4
  import './chunk-SAN4IX6N.js';
5
5
  import { useRef, useCallback, useMemo, useState, useEffect, useLayoutEffect } from 'react';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -134,6 +134,24 @@ type SduiAction = {
134
134
  /** 실패 시 순차 실행 (이벤트 값 = 에러 메시지). 생략하면 danger 토스트 */
135
135
  onError?: SduiAction[];
136
136
  }
137
+ /**
138
+ * 단발 API 호출 — submitForm에서 폼 수집·검증을 뺀 것. 서버의 2단계 커밋 계약
139
+ * (본체 POST 후 `POST /{entity}/{id}/attachments`)을 submitForm의 onSuccess 안에서
140
+ * 잇는 자리다. endpoint·body는 디스패치 시점에 해석되므로 같은 체인의 setState를 본다.
141
+ */
142
+ | {
143
+ action: 'request';
144
+ endpoint: string;
145
+ /** 생략하면 POST. GET은 page.data의 몫이다 — 본문 실린 GET은 브라우저가 막는다. */
146
+ method?: 'POST' | 'PUT' | 'PATCH' | 'DELETE';
147
+ body?: SduiPropValue;
148
+ /** 성공 시 순차 실행 (이벤트 값 = 응답 JSON) */
149
+ onSuccess?: SduiAction[];
150
+ /** 실패 시 순차 실행 (이벤트 값 = 에러 메시지). 생략하면 danger 토스트 */
151
+ onError?: SduiAction[];
152
+ /** 성공 시 무효화할 조회 prefix — onSuccess의 invalidate 액션 단축 */
153
+ invalidate?: string;
154
+ }
137
155
  /** 클라이언트 조회 캐시 무효화 — 어댑터의 invalidate로 위임 */
138
156
  | {
139
157
  action: 'invalidate';
@@ -1,4 +1,4 @@
1
- export { AutocompleteField, toAutocompleteOptions } from '../chunk-PBGYAVQZ.js';
2
- import '../chunk-QIDMPWZH.js';
3
- import '../chunk-B5JTXYDB.js';
1
+ export { AutocompleteField, toAutocompleteOptions } from '../chunk-6NAJ2D4A.js';
2
+ import '../chunk-FC2F37QH.js';
3
+ import '../chunk-LMHIRQZ6.js';
4
4
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { ColumnBoard } from '../chunk-VK6KWB65.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { ColumnBoard } from '../chunk-G4QIJHEP.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { DiffView } from '../chunk-4IRLQWQC.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { DiffView } from '../chunk-LN6IOMCK.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { Disclosure } from '../chunk-WLWWN5LW.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { Disclosure } from '../chunk-YGSU34B3.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { EventCalendar } from '../chunk-WMPSOKNI.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { EventCalendar } from '../chunk-CXZYC7IN.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { ImageLightbox } from '../chunk-3PYMVHL3.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { ImageLightbox } from '../chunk-R3IK6EPA.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { InlineEdit } from '../chunk-7AHNAX6T.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { InlineEdit } from '../chunk-BOSSWJTN.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { JsonField } from '../chunk-FDVI3PWQ.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { JsonField } from '../chunk-X5X3FKCQ.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { OrgChart } from '../chunk-BT4HC3WR.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { OrgChart } from '../chunk-F2MKI3W5.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { PeriodFilter } from '../chunk-WJEGCCPY.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { PeriodFilter } from '../chunk-4NPTFNAL.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { PrintSheet } from '../chunk-JWYBFODH.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { PrintSheet } from '../chunk-5YVXVGQ2.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,4 +1,4 @@
1
- export { SearchableMultiPicker } from '../chunk-UA5CT24N.js';
2
- import '../chunk-QIDMPWZH.js';
3
- import '../chunk-B5JTXYDB.js';
1
+ export { SearchableMultiPicker } from '../chunk-K5ZJTLFP.js';
2
+ import '../chunk-FC2F37QH.js';
3
+ import '../chunk-LMHIRQZ6.js';
4
4
  import '../chunk-SAN4IX6N.js';
@@ -1,3 +1,3 @@
1
- export { SecureScreen } from '../chunk-4CZJF5PR.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { SecureScreen } from '../chunk-5C4SIRSW.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -14,7 +14,15 @@ interface TagMultiSelectOption {
14
14
  label: string;
15
15
  }
16
16
  interface TagMultiSelectProps {
17
- options: TagMultiSelectOption[];
17
+ /**
18
+ * 기본은 `{value, label}`이고, 도메인 행(`{id, name, …}`)을 그대로 넘길 거면
19
+ * `valueKey`/`labelKey`로 읽을 키를 알려 준다 — Select 0.7.0과 같은 계약.
20
+ */
21
+ options: Array<TagMultiSelectOption | Record<string, unknown>>;
22
+ /** 옵션에서 값을 읽을 키. 기본 'value'. */
23
+ valueKey?: string;
24
+ /** 옵션에서 표시 라벨을 읽을 키. 기본 'label'. */
25
+ labelKey?: string;
18
26
  values: string[];
19
27
  onChange: (values: string[]) => void;
20
28
  disabled?: boolean;
@@ -1,3 +1,3 @@
1
- export { TagMultiSelect } from '../chunk-TMAVD3WL.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { TagMultiSelect } from '../chunk-K55ODWRY.js';
2
+ import '../chunk-LMHIRQZ6.js';
3
3
  import '../chunk-SAN4IX6N.js';
@@ -1,4 +1,4 @@
1
- export { Timeline } from '../chunk-YFUQUWWH.js';
2
- import '../chunk-WLWWN5LW.js';
3
- import '../chunk-B5JTXYDB.js';
1
+ export { Timeline } from '../chunk-VBCUIM7N.js';
2
+ import '../chunk-YGSU34B3.js';
3
+ import '../chunk-LMHIRQZ6.js';
4
4
  import '../chunk-SAN4IX6N.js';
@@ -1,9 +1,14 @@
1
1
  import * as React from 'react';
2
2
  import { S as SduiBoxProps } from '../layout-B1QrIBm6.js';
3
- import { TreeNode } from './TreeView.js';
3
+ import { TreeNode, TreeRowsMapping } from './TreeView.js';
4
4
 
5
5
  interface TreePickerProps {
6
- nodes: TreeNode[];
6
+ /** 정적 트리. `rows`가 비어 있을 때의 폴백이기도 하다 — 캔버스 데모는 여기 둔다. */
7
+ nodes?: TreeNode[];
8
+ /** 평면 행. 비어있지 않으면 `tree` 매핑으로 계층을 세운다 — {@link TreeViewProps.rows}와 같은 계약. */
9
+ rows?: unknown[];
10
+ /** 평면 행에서 읽을 키 이름. 없으면 `rows`는 무시된다. */
11
+ tree?: TreeRowsMapping;
7
12
  /** 지정하면 controlled — 내부 커밋 상태를 쓰지 않는다. null = 선택 없음. */
8
13
  value?: string | null;
9
14
  /** 트리에서 노드를 찾지 못할 때 표시할 라벨(controlled 보조). */
@@ -1,4 +1,5 @@
1
- export { TreePicker } from '../chunk-VV73LOAE.js';
2
- import '../chunk-X3DGYP4W.js';
3
- import '../chunk-B5JTXYDB.js';
1
+ export { TreePicker } from '../chunk-JND5NXUT.js';
2
+ import '../chunk-BS4LGGQV.js';
3
+ import '../chunk-FC2F37QH.js';
4
+ import '../chunk-LMHIRQZ6.js';
4
5
  import '../chunk-SAN4IX6N.js';
@@ -8,8 +8,25 @@ interface TreeNode {
8
8
  meta?: string;
9
9
  children?: TreeNode[];
10
10
  }
11
+ /**
12
+ * `rows` → 트리 매핑 계약. 상세검색 cascading의 `tree`(SearchToolbar)와 같은 모양이다 —
13
+ * 스펙 작성자가 한 어휘를 두 자리에서 그대로 쓴다.
14
+ */
15
+ interface TreeRowsMapping {
16
+ idKey: string;
17
+ parentIdKey: string;
18
+ labelKey: string;
19
+ }
11
20
  interface TreeViewProps {
12
- nodes: TreeNode[];
21
+ /** 정적 트리. `rows`가 비어 있을 때의 폴백이기도 하다 — 캔버스 데모는 여기 둔다. */
22
+ nodes?: TreeNode[];
23
+ /**
24
+ * 평면 행(/categories 모양 — {id, parent_id, name}). 비어있지 않으면 `tree` 매핑으로
25
+ * 계층을 세우고, 아니면 `nodes` 폴백 — AutocompleteField의 데모 options 유지와 같은 관례.
26
+ */
27
+ rows?: unknown[];
28
+ /** 평면 행에서 읽을 키 이름. 없으면 `rows`는 무시된다. */
29
+ tree?: TreeRowsMapping;
13
30
  /** 지정하면 controlled — 내부 선택 상태를 쓰지 않는다. */
14
31
  selectedId?: string | null;
15
32
  onSelect?: (id: string, node: TreeNode) => void;
@@ -22,10 +39,18 @@ interface TreeViewProps {
22
39
  /** 스크롤 컨테이너 최대 높이 (예: "320px"). */
23
40
  maxHeight?: string;
24
41
  }
42
+ /**
43
+ * 평면 행을 TreeNode 계층으로 세운다. 고아 행(부모가 목록에 없음)을 루트로 올리는 것까지
44
+ * `buildCascadingTree`와 동작이 같다 — 알고리즘은 그쪽 한 벌뿐이고 여기는 노드 모양만 바꾼다.
45
+ */
46
+ declare function buildTreeNodes(rows: unknown[] | undefined, tree: TreeRowsMapping): TreeNode[];
47
+ /** rows가 비어있지 않고 매핑이 있으면 파생 트리, 아니면 nodes 폴백. TreePicker도 이 판을 쓴다. */
48
+ declare function resolveTreeNodes(nodes: TreeNode[] | undefined, rows: unknown[] | undefined, tree: TreeRowsMapping | undefined): TreeNode[];
49
+ declare function pruneExcluded(nodes: TreeNode[], excluded: ReadonlySet<string>): TreeNode[];
25
50
  /**
26
51
  * 바깥에서 온 `style`·`className`을 뿌리에 얹어 내보낸다 — 자식 축(`grow`·`width` …)이
27
52
  * 이 컴포넌트에서도 동작하게 하는 유일한 통로다. 까닭은 {@link ../boxed.tsx}에 있다.
28
53
  */
29
54
  declare const TreeView: React__default.FC<TreeViewProps & SduiBoxProps>;
30
55
 
31
- export { type TreeNode, TreeView, type TreeViewProps };
56
+ export { type TreeNode, type TreeRowsMapping, TreeView, type TreeViewProps, buildTreeNodes, pruneExcluded, resolveTreeNodes };
@@ -1,3 +1,4 @@
1
- export { TreeView } from '../chunk-X3DGYP4W.js';
2
- import '../chunk-B5JTXYDB.js';
1
+ export { TreeView, buildTreeNodes, pruneExcluded, resolveTreeNodes } from '../chunk-BS4LGGQV.js';
2
+ import '../chunk-FC2F37QH.js';
3
+ import '../chunk-LMHIRQZ6.js';
3
4
  import '../chunk-SAN4IX6N.js';
@@ -1,5 +1,5 @@
1
1
  import { TreeViewProps } from './TreeView.js';
2
- export { TreeNode, TreeView } from './TreeView.js';
2
+ export { TreeNode, TreeRowsMapping, TreeView, buildTreeNodes } from './TreeView.js';
3
3
  import { TreePickerProps } from './TreePicker.js';
4
4
  export { TreePicker } from './TreePicker.js';
5
5
  import { TimelineProps } from './Timeline.js';
@@ -1,46 +1,46 @@
1
- import { SearchableMultiPicker } from '../chunk-UA5CT24N.js';
2
- export { SearchableMultiPicker } from '../chunk-UA5CT24N.js';
3
- import { SecureScreen } from '../chunk-4CZJF5PR.js';
4
- export { SecureScreen } from '../chunk-4CZJF5PR.js';
1
+ import { SearchableMultiPicker } from '../chunk-K5ZJTLFP.js';
2
+ export { SearchableMultiPicker } from '../chunk-K5ZJTLFP.js';
3
+ import { SecureScreen } from '../chunk-5C4SIRSW.js';
4
+ export { SecureScreen } from '../chunk-5C4SIRSW.js';
5
5
  import { StackedMeter } from '../chunk-BMZKZGJF.js';
6
6
  export { StackedMeter } from '../chunk-BMZKZGJF.js';
7
7
  import { Strip } from '../chunk-ZH5MLOZS.js';
8
8
  export { Strip } from '../chunk-ZH5MLOZS.js';
9
9
  import { SummaryTable } from '../chunk-O4U7Y3XL.js';
10
10
  export { SummaryTable } from '../chunk-O4U7Y3XL.js';
11
- import { TagMultiSelect } from '../chunk-TMAVD3WL.js';
12
- export { TagMultiSelect } from '../chunk-TMAVD3WL.js';
13
- import { Timeline } from '../chunk-YFUQUWWH.js';
14
- export { Timeline } from '../chunk-YFUQUWWH.js';
15
- import { TreePicker } from '../chunk-VV73LOAE.js';
16
- export { TreePicker } from '../chunk-VV73LOAE.js';
17
- import { TreeView } from '../chunk-X3DGYP4W.js';
18
- export { TreeView } from '../chunk-X3DGYP4W.js';
19
- import { EventCalendar } from '../chunk-WMPSOKNI.js';
20
- export { EventCalendar } from '../chunk-WMPSOKNI.js';
21
- import { ImageLightbox } from '../chunk-3PYMVHL3.js';
22
- export { ImageLightbox } from '../chunk-3PYMVHL3.js';
23
- import { InlineEdit } from '../chunk-7AHNAX6T.js';
24
- export { InlineEdit } from '../chunk-7AHNAX6T.js';
25
- import { JsonField } from '../chunk-FDVI3PWQ.js';
26
- export { JsonField } from '../chunk-FDVI3PWQ.js';
11
+ import { TagMultiSelect } from '../chunk-K55ODWRY.js';
12
+ export { TagMultiSelect } from '../chunk-K55ODWRY.js';
13
+ import { Timeline } from '../chunk-VBCUIM7N.js';
14
+ export { Timeline } from '../chunk-VBCUIM7N.js';
15
+ import { TreePicker } from '../chunk-JND5NXUT.js';
16
+ export { TreePicker } from '../chunk-JND5NXUT.js';
17
+ import { TreeView } from '../chunk-BS4LGGQV.js';
18
+ export { TreeView, buildTreeNodes } from '../chunk-BS4LGGQV.js';
19
+ import { EventCalendar } from '../chunk-CXZYC7IN.js';
20
+ export { EventCalendar } from '../chunk-CXZYC7IN.js';
21
+ import { ImageLightbox } from '../chunk-R3IK6EPA.js';
22
+ export { ImageLightbox } from '../chunk-R3IK6EPA.js';
23
+ import { InlineEdit } from '../chunk-BOSSWJTN.js';
24
+ export { InlineEdit } from '../chunk-BOSSWJTN.js';
25
+ import { JsonField } from '../chunk-X5X3FKCQ.js';
26
+ export { JsonField } from '../chunk-X5X3FKCQ.js';
27
27
  import { LiveClock } from '../chunk-Z3WGIFJP.js';
28
28
  export { LiveClock } from '../chunk-Z3WGIFJP.js';
29
- import { OrgChart } from '../chunk-BT4HC3WR.js';
30
- export { OrgChart } from '../chunk-BT4HC3WR.js';
31
- import { PeriodFilter } from '../chunk-WJEGCCPY.js';
32
- export { PeriodFilter } from '../chunk-WJEGCCPY.js';
33
- import { PrintSheet } from '../chunk-JWYBFODH.js';
34
- export { PrintSheet } from '../chunk-JWYBFODH.js';
35
- export { AutocompleteField, toAutocompleteOptions } from '../chunk-PBGYAVQZ.js';
36
- import '../chunk-QIDMPWZH.js';
37
- import { ColumnBoard } from '../chunk-VK6KWB65.js';
38
- export { ColumnBoard } from '../chunk-VK6KWB65.js';
39
- import { DiffView } from '../chunk-4IRLQWQC.js';
40
- export { DiffView } from '../chunk-4IRLQWQC.js';
41
- import { Disclosure } from '../chunk-WLWWN5LW.js';
42
- export { Disclosure } from '../chunk-WLWWN5LW.js';
43
- import '../chunk-B5JTXYDB.js';
29
+ import { OrgChart } from '../chunk-F2MKI3W5.js';
30
+ export { OrgChart } from '../chunk-F2MKI3W5.js';
31
+ import { PeriodFilter } from '../chunk-4NPTFNAL.js';
32
+ export { PeriodFilter } from '../chunk-4NPTFNAL.js';
33
+ import { PrintSheet } from '../chunk-5YVXVGQ2.js';
34
+ export { PrintSheet } from '../chunk-5YVXVGQ2.js';
35
+ export { AutocompleteField, toAutocompleteOptions } from '../chunk-6NAJ2D4A.js';
36
+ import '../chunk-FC2F37QH.js';
37
+ import { ColumnBoard } from '../chunk-G4QIJHEP.js';
38
+ export { ColumnBoard } from '../chunk-G4QIJHEP.js';
39
+ import { DiffView } from '../chunk-LN6IOMCK.js';
40
+ export { DiffView } from '../chunk-LN6IOMCK.js';
41
+ import { Disclosure } from '../chunk-YGSU34B3.js';
42
+ export { Disclosure } from '../chunk-YGSU34B3.js';
43
+ import '../chunk-LMHIRQZ6.js';
44
44
  import '../chunk-SAN4IX6N.js';
45
45
 
46
46
  // src/widgets/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipco/sdui",
3
- "version": "0.13.1",
3
+ "version": "0.14.1",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",