@wipco/sdui 0.16.0 → 0.17.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.
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-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';
3
+ import { S as SduiPage, a as SduiAction, b as SduiPropValue, c as SduiRule } from './types-opTPYysN.js';
4
+ export { d as SduiArgRef, e as SduiCalcRef, f as SduiChild, g as SduiIndexRef, h as SduiItemRef, i as SduiNode, j as SduiPageQuery, k as SduiScalar, l as SduiStateRef } from './types-opTPYysN.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';
@@ -40,6 +40,28 @@ interface SduiAdapter {
40
40
  * 반환값은 구독 해제 함수.
41
41
  */
42
42
  subscribe?: (channels: string[], onEvent: () => void) => () => void;
43
+ /**
44
+ * Fragment 노드가 id로 다른 스펙을 가져올 때 부르는 **훅**이다.
45
+ *
46
+ * 반환 계약: `undefined` = 로딩 중(아무것도 그리지 않음), `null` = 없음/실패,
47
+ * 그 외 = 스펙(body만 쓰인다 — data/urlState/subscribe는 무시).
48
+ *
49
+ * 훅인 이유: 요구가 "스펙 캐시 무효화(SSE) → 자동 리렌더"인데, 이는 외부 스토어
50
+ * 구독 문제라 호스트가 이미 가진 조회 훅(TanStack Query 등)이 정답이다.
51
+ * ERP 호스트는 한 줄로 잇는다:
52
+ * useSpec: (id) => { const q = useQuery(specQuery(id)); return q.isPending ? undefined : (q.data ?? null); }
53
+ *
54
+ * 콜백 대안(`loadSpec(id): Promise<…>` + 구독)은 겉모양이 기존 어댑터 관용구에 더
55
+ * 맞지만 버렸다 — 렌더러가 id별 캐시·구독 대장·재조회를 자체 보유해야 해서 ERP의
56
+ * ETag/IndexedDB/SSE 완비 캐시와 **이중 캐시**가 되고, sandbox 주석이 실측으로 경고한
57
+ * "빈 응답이 전역 캐시에 실려 진짜 페이지를 오염" 류의 사고 표면이 그대로 생긴다.
58
+ *
59
+ * 훅 계약(호스트가 지켜야 한다):
60
+ * - 렌더마다 같은 훅을 같은 순서로 부른다(내부 조건부 훅 금지).
61
+ * - 어댑터 객체 정체성을 렌더 중에 갈아 끼우지 않는다(렌더러가 useMemo로 잡고 있지만,
62
+ * useSpec이 있다가 없어지는 교체는 훅 순서 위반이다).
63
+ */
64
+ useSpec?: (id: string) => SduiPage | null | undefined;
43
65
  /**
44
66
  * urlState 반영 시 URL 쿼리 교체를 위임한다 — react-router 호스트라면
45
67
  * setSearchParams(params, { replace: true })를 연결해 라우터 구독자와
@@ -109,6 +131,8 @@ interface SduiAssetContext {
109
131
  cssProperty?: string;
110
132
  }
111
133
  type SduiAssetResolver = (url: string, ctx: SduiAssetContext) => string | null;
134
+ /** {@link SduiAdapter.useSpec} 구현체의 편의 타입 — 호스트가 훅을 따로 정의해 꽂을 때 쓴다. */
135
+ type SduiUseSpec = NonNullable<SduiAdapter['useSpec']>;
112
136
  declare const defaultAdapter: Required<Pick<SduiAdapter, 'navigate' | 'fetch' | 'rawFetch' | 'resolveAsset'>> & SduiAdapter;
113
137
  /**
114
138
  * **스스로 URL을 만드는 컴포넌트**를 위한 자산 관문.
@@ -1771,4 +1795,4 @@ interface ImageViewerProps {
1771
1795
  */
1772
1796
  declare function ImageViewer({ src, alt, open, onClose }: ImageViewerProps): React__default.ReactPortal | null;
1773
1797
 
1774
- export { Actions, type ActionsProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Can, type CanProps, Card, type CardProps, type CascadingSearchOption, Checkbox, type CheckboxProps, Col, type ColProps, type CustomActionHandler, type CustomValidator, DatePickerProps, DateRangePickerProps, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, Icon, IconButton, type IconButtonProps, type IconProps, ImageViewer, type ImageViewerProps, Input, type InputProps, type Justify, type KeyValueItem, KeyValueList, type KeyValueListProps, type MeterTone, NodeErrorBoundary, PageHead, type PageHeadProps, Pagination, type PaginationProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, RemoteSearchResults, type RemoteSearchResultsProps, ResultTable, type ResultTableColumn, type ResultTableProps, Row, type RowProps, SduiAction, type SduiAdapter, type SduiAssetContext, type SduiAssetResolver, type SduiBadgeCell, SduiBoxProps, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, SduiGapScale, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, type SduiImageCell, type SduiLinkCell, type SduiNumberCell, SduiPage, SduiPermissionProvider, type SduiProgressCell, SduiPropValue, type SduiRegistry, SduiRenderer, type SduiRendererProps, type SduiRowCondition, SduiRule, type SduiRuntime, type SduiSearchAction, type SduiSearchColumn, SduiSearchDataProvider, SduiSearchResults, type SduiSearchResultsProps, type SduiTagCell, SduiTextAlignScale, type SduiTextCell, SduiWeightScale, type SearchAction, type SearchColumn, type SearchFetcher, type SearchField, type SearchFilter, type SearchOption, type SearchPage, SearchResults, type SearchResultsProps, type SearchRow, SearchToolbar, type SearchValues, type SearchViewItem, Section, type SectionProps, SegmentedControl, type SegmentedControlProps, type SegmentedItem, Select, type SelectOption, type SelectOptionRecord, type SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, SortHandle, type SortHandleProps, SortableList, type SortableListProps, Spacer, type SpacerProps, type SpecIssue, Spinner, type SpinnerProps, StatCard, type StatCardProps, Switch, type SwitchProps, type TabItem, Table, type TableColumn, type TableProps, Tabs, type TabsProps, Tag, type TagProps, Text, type TextPreset, type TextProps, Textarea, type TextareaProps, Toast, type ToastProps, Tooltip, type TooltipProps, boxed, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, defaultAdapter, defaultRegistry, imageRenderer, includesLooseSearch, joinMultiValue, normalizePageSizes, normalizeSearchText, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec };
1798
+ export { Actions, type ActionsProps, Alert, type AlertProps, Avatar, type AvatarProps, Badge, type BadgeProps, type BadgeTone, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, Can, type CanProps, Card, type CardProps, type CascadingSearchOption, Checkbox, type CheckboxProps, Col, type ColProps, type CustomActionHandler, type CustomValidator, DatePickerProps, DateRangePickerProps, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, Icon, IconButton, type IconButtonProps, type IconProps, ImageViewer, type ImageViewerProps, Input, type InputProps, type Justify, type KeyValueItem, KeyValueList, type KeyValueListProps, type MeterTone, NodeErrorBoundary, PageHead, type PageHeadProps, Pagination, type PaginationProps, ProgressBar, type ProgressBarProps, Radio, type RadioProps, RemoteSearchResults, type RemoteSearchResultsProps, ResultTable, type ResultTableColumn, type ResultTableProps, Row, type RowProps, SduiAction, type SduiAdapter, type SduiAssetContext, type SduiAssetResolver, type SduiBadgeCell, SduiBoxProps, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, SduiGapScale, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, type SduiImageCell, type SduiLinkCell, type SduiNumberCell, SduiPage, SduiPermissionProvider, type SduiProgressCell, SduiPropValue, type SduiRegistry, SduiRenderer, type SduiRendererProps, type SduiRowCondition, SduiRule, type SduiRuntime, type SduiSearchAction, type SduiSearchColumn, SduiSearchDataProvider, SduiSearchResults, type SduiSearchResultsProps, type SduiTagCell, SduiTextAlignScale, type SduiTextCell, type SduiUseSpec, SduiWeightScale, type SearchAction, type SearchColumn, type SearchFetcher, type SearchField, type SearchFilter, type SearchOption, type SearchPage, SearchResults, type SearchResultsProps, type SearchRow, SearchToolbar, type SearchValues, type SearchViewItem, Section, type SectionProps, SegmentedControl, type SegmentedControlProps, type SegmentedItem, Select, type SelectOption, type SelectOptionRecord, type SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, SortHandle, type SortHandleProps, SortableList, type SortableListProps, Spacer, type SpacerProps, type SpecIssue, Spinner, type SpinnerProps, StatCard, type StatCardProps, Switch, type SwitchProps, type TabItem, Table, type TableColumn, type TableProps, Tabs, type TabsProps, Tag, type TagProps, Text, type TextPreset, type TextProps, Textarea, type TextareaProps, Toast, type ToastProps, Tooltip, type TooltipProps, boxed, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, defaultAdapter, defaultRegistry, imageRenderer, includesLooseSearch, joinMultiValue, normalizePageSizes, normalizeSearchText, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec };
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagina
8
8
  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-WIDDHR7L.js';
9
9
  import { boxed, mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-SAN4IX6N.js';
10
10
  export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, boxed, childLayoutFrom, columnsClass, containerLayoutStyle, joinClass, mergeStyle, typographyStyle } from './chunk-SAN4IX6N.js';
11
- import React, { createContext, useState, useMemo, useContext, useRef, useEffect, useCallback } from 'react';
11
+ import React11, { createContext, useState, useMemo, useContext, useRef, useEffect, useCallback } from 'react';
12
12
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
13
 
14
14
  // src/asset-url.ts
@@ -113,7 +113,7 @@ function useSduiDispatch() {
113
113
  }
114
114
  return dispatch;
115
115
  }
116
- var NodeErrorBoundary = class extends React.Component {
116
+ var NodeErrorBoundary = class extends React11.Component {
117
117
  state = { error: null };
118
118
  static getDerivedStateFromError(error) {
119
119
  return { error };
@@ -300,7 +300,7 @@ function KeyValueList({ source, items, className, style }) {
300
300
  return /* @__PURE__ */ jsx("div", { className: joinClass("wp-kv", className), style, children: (items ?? []).map((item, index) => {
301
301
  const raw = item.key ? source?.[item.key] : item.value;
302
302
  const content = raw === null || raw === void 0 || raw === "" ? "\u2014" : raw;
303
- return /* @__PURE__ */ jsxs(React.Fragment, { children: [
303
+ return /* @__PURE__ */ jsxs(React11.Fragment, { children: [
304
304
  /* @__PURE__ */ jsx("span", { className: "wp-kv__k", children: item.label }),
305
305
  /* @__PURE__ */ jsx("span", { className: joinClass("wp-kv__v", item.mono && "wp-mono"), children: content })
306
306
  ] }, index);
@@ -1866,6 +1866,7 @@ var RULE_NAMES = /* @__PURE__ */ new Set([
1866
1866
  "notBeforeField",
1867
1867
  "custom"
1868
1868
  ]);
1869
+ var RENDERER_BUILTINS = /* @__PURE__ */ new Set(["ForEach", "Fragment"]);
1869
1870
  var DENIED_PROPS = /* @__PURE__ */ new Set([
1870
1871
  "dangerouslySetInnerHTML",
1871
1872
  "ref",
@@ -1952,7 +1953,7 @@ function walkChild(child, path, issues, known) {
1952
1953
  issues.push({ path, message: "component\uB294 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 \uBB38\uC790\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" });
1953
1954
  return;
1954
1955
  }
1955
- if (known && node.component !== "ForEach" && !known.has(node.component)) {
1956
+ if (known && !RENDERER_BUILTINS.has(node.component) && !known.has(node.component)) {
1956
1957
  issues.push({ path, message: `\uB4F1\uB85D\uB418\uC9C0 \uC54A\uC740 \uCEF4\uD3EC\uB10C\uD2B8: ${node.component}` });
1957
1958
  }
1958
1959
  if (node.props !== void 0 && !isPlainObject(node.props)) {
@@ -1981,6 +1982,28 @@ function walkChild(child, path, issues, known) {
1981
1982
  }
1982
1983
  }
1983
1984
  }
1985
+ if (node.component === "Fragment") {
1986
+ const id = isPlainObject(node.props) ? node.props.id : void 0;
1987
+ if ((typeof id !== "string" || id === "") && !isPlainObject(id)) {
1988
+ issues.push({
1989
+ path: `${path}.props.id`,
1990
+ message: "Fragment.id\uB294 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 \uBB38\uC790\uC5F4(\uB610\uB294 \uAC12 \uCC38\uC870)\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4"
1991
+ });
1992
+ }
1993
+ const args = isPlainObject(node.props) ? node.props.args : void 0;
1994
+ if (args !== void 0 && !isPlainObject(args)) {
1995
+ issues.push({
1996
+ path: `${path}.props.args`,
1997
+ message: "Fragment.args\uB294 { \uC774\uB984: \uAC12 } \uD3C9\uBA74 \uC624\uBE0C\uC81D\uD2B8\uC5EC\uC57C \uD569\uB2C8\uB2E4"
1998
+ });
1999
+ }
2000
+ if (node.children !== void 0 || node.slots !== void 0) {
2001
+ issues.push({
2002
+ path,
2003
+ message: "Fragment\uB294 children/slots\uB97C \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 \uC870\uAC01 \uC2A4\uD399\uC758 body\uAC00 \uADF8\uB824\uC9D1\uB2C8\uB2E4"
2004
+ });
2005
+ }
2006
+ }
1984
2007
  if (node.slots !== void 0) {
1985
2008
  if (!isPlainObject(node.slots)) {
1986
2009
  issues.push({ path: `${path}.slots`, message: "slots\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
@@ -2029,6 +2052,9 @@ function walkValue(value, path, issues, actionEligible) {
2029
2052
  if ("$state" in value && typeof value.$state !== "string") {
2030
2053
  issues.push({ path, message: "$state\uB294 \uBB38\uC790\uC5F4 \uD0A4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
2031
2054
  }
2055
+ if ("$arg" in value && typeof value.$arg !== "string") {
2056
+ issues.push({ path, message: "$arg\uB294 \uBB38\uC790\uC5F4 \uC774\uB984\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" });
2057
+ }
2032
2058
  if ("$calc" in value) {
2033
2059
  const calc = value.$calc;
2034
2060
  if (!isPlainObject(calc) || typeof calc.op !== "string" || !CALC_OPS.has(calc.op)) {
@@ -2124,6 +2150,23 @@ function revertUnsettledStamps(fetched, runnable, epochs, settled) {
2124
2150
  if (fetched.get(plan.key) === planStamp(plan, epochs)) fetched.delete(plan.key);
2125
2151
  }
2126
2152
  }
2153
+ function isArgsFrame(frame) {
2154
+ return "callSiteScope" in frame;
2155
+ }
2156
+ function nearestItemFrame(scope) {
2157
+ for (let i = scope.length - 1; i >= 0; i--) {
2158
+ const frame = scope[i];
2159
+ if (!isArgsFrame(frame)) return frame;
2160
+ }
2161
+ return void 0;
2162
+ }
2163
+ function nearestArgsFrame(scope) {
2164
+ for (let i = scope.length - 1; i >= 0; i--) {
2165
+ const frame = scope[i];
2166
+ if (isArgsFrame(frame)) return frame;
2167
+ }
2168
+ return void 0;
2169
+ }
2127
2170
  function isPlainObject3(v) {
2128
2171
  return typeof v === "object" && v !== null && !Array.isArray(v);
2129
2172
  }
@@ -2139,12 +2182,33 @@ function isIndexRef(v) {
2139
2182
  function isCalcRef(v) {
2140
2183
  return isPlainObject3(v) && isPlainObject3(v.$calc);
2141
2184
  }
2185
+ function isArgRef(v) {
2186
+ return isPlainObject3(v) && typeof v.$arg === "string";
2187
+ }
2142
2188
  function isAction(v) {
2143
2189
  return isPlainObject3(v) && typeof v.action === "string";
2144
2190
  }
2145
2191
  function isActionList(v) {
2146
2192
  return Array.isArray(v) && v.length > 0 && v.every(isAction);
2147
2193
  }
2194
+ function isActionEntryList(v) {
2195
+ return Array.isArray(v) && v.length > 0 && v.every((x) => isAction(x) || isArgRef(x));
2196
+ }
2197
+ function expandActionEntries(raw, scope) {
2198
+ if (Array.isArray(raw)) return raw.flatMap((v) => expandActionEntries(v, scope));
2199
+ if (isArgRef(raw)) {
2200
+ const frame = nearestArgsFrame(scope);
2201
+ if (frame?.args && Object.hasOwn(frame.args, raw.$arg)) {
2202
+ return expandActionEntries(frame.args[raw.$arg], frame.callSiteScope);
2203
+ }
2204
+ if (raw.default !== void 0) return expandActionEntries(raw.default, scope);
2205
+ return [];
2206
+ }
2207
+ if (isAction(raw)) return [{ action: raw, scope }];
2208
+ if (raw === void 0 || raw === null) return [];
2209
+ warnOnce2(`action-entry:${typeof raw}`, "[sdui] \uC561\uC158 \uC790\uB9AC\uC5D0 \uC561\uC158\uC774 \uC544\uB2CC \uAC12\uC774 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uBB34\uC2DC\uD569\uB2C8\uB2E4");
2210
+ return [];
2211
+ }
2148
2212
  function eventValue(arg) {
2149
2213
  if (isPlainObject3(arg) && "target" in arg && typeof arg.preventDefault === "function") {
2150
2214
  const target = arg.target;
@@ -2294,9 +2358,12 @@ function SduiNodeRenderer({
2294
2358
  return /* @__PURE__ */ jsx(Fragment, { children: rows.map((item, rowIndex) => {
2295
2359
  const rowScope = [...scope, { item, index: rowIndex }];
2296
2360
  const rowKey = isPlainObject3(item) && typeof item.id === "string" ? item.id : rowIndex;
2297
- return /* @__PURE__ */ jsx(React.Fragment, { children: childList?.map((child, i) => renderChild(child, i, rowScope, engine)) }, rowKey);
2361
+ return /* @__PURE__ */ jsx(React11.Fragment, { children: childList?.map((child, i) => renderChild(child, i, rowScope, engine)) }, rowKey);
2298
2362
  }) });
2299
2363
  }
2364
+ if (node.component === "Fragment") {
2365
+ return /* @__PURE__ */ jsx(SduiFragment, { node, scope, engine });
2366
+ }
2300
2367
  const Component = typeof node.component === "string" && Object.hasOwn(registry, node.component) ? registry[node.component] : void 0;
2301
2368
  if (!Component) {
2302
2369
  warnOnce2(
@@ -2314,13 +2381,18 @@ function SduiNodeRenderer({
2314
2381
  warnOnce2(`prop:${name}`, `[sdui] \uC2A4\uD399\uC5D0\uC11C \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 \uD504\uB86D: ${name} \u2014 \uBB34\uC2DC\uD569\uB2C8\uB2E4`);
2315
2382
  continue;
2316
2383
  }
2317
- if (name.startsWith("on") && (isAction(raw) || isActionList(raw))) {
2318
- const actions = isActionList(raw) ? raw : [raw];
2319
- props[name] = (arg) => actions.forEach(
2320
- (a) => dispatch(resolveValue(a, scope), arg)
2384
+ if (name.startsWith("on") && (isAction(raw) || isArgRef(raw) || isActionEntryList(raw))) {
2385
+ props[name] = (arg) => expandActionEntries(raw, scope).forEach(
2386
+ (entry) => dispatch(
2387
+ resolveValue(entry.action, entry.scope),
2388
+ arg,
2389
+ entry.scope
2390
+ )
2321
2391
  );
2322
2392
  } else if (name === "rowClick" && (isAction(raw) || isActionList(raw))) {
2323
2393
  props[name] = raw;
2394
+ } else if (name === "rowClick" && (isArgRef(raw) || isActionEntryList(raw))) {
2395
+ props[name] = expandActionEntries(raw, scope).map((entry) => entry.action);
2324
2396
  } else {
2325
2397
  let resolved = resolveValue(raw, scope);
2326
2398
  if (resolved === null) {
@@ -2362,6 +2434,87 @@ function SduiNodeRenderer({
2362
2434
  const children = childList?.map((child, i) => renderChild(child, i, scope, engine));
2363
2435
  return /* @__PURE__ */ jsx(Component, { ...props, children });
2364
2436
  }
2437
+ var SduiFragmentChainContext = React11.createContext([]);
2438
+ var FRAGMENT_MAX_DEPTH = 4;
2439
+ function SduiFragment({ node, scope, engine }) {
2440
+ const adapter = useSduiAdapter();
2441
+ const chain = React11.useContext(SduiFragmentChainContext);
2442
+ const raw = isPlainObject3(node.props) ? node.props.id : void 0;
2443
+ const id = engine.resolveValue(raw, scope);
2444
+ if (typeof id !== "string" || id === "") {
2445
+ warnOnce2("fragment:id", "[sdui] <Fragment>\uC5D0 \uBB38\uC790\uC5F4 id\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
2446
+ return null;
2447
+ }
2448
+ if (chain.includes(id)) {
2449
+ warnOnce2(
2450
+ `fragment:cycle:${id}`,
2451
+ `[sdui] Fragment \uC21C\uD658 \uCC38\uC870: ${[...chain, id].join(" \u2192 ")} \u2014 \uC7AC\uC9C4\uC785\uC744 \uAC70\uBD80\uD569\uB2C8\uB2E4`
2452
+ );
2453
+ return null;
2454
+ }
2455
+ if (chain.length >= FRAGMENT_MAX_DEPTH) {
2456
+ warnOnce2(
2457
+ `fragment:depth:${id}`,
2458
+ `[sdui] Fragment \uC911\uCCA9\uC774 ${FRAGMENT_MAX_DEPTH}\uB2E8\uC744 \uB118\uC2B5\uB2C8\uB2E4(${[...chain, id].join(" \u2192 ")}) \u2014 \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`
2459
+ );
2460
+ return null;
2461
+ }
2462
+ const rawArgs = isPlainObject3(node.props) ? node.props.args : void 0;
2463
+ if (rawArgs !== void 0 && !isPlainObject3(rawArgs)) {
2464
+ warnOnce2(`fragment:args:${id}`, `[sdui] <Fragment ${id}>\uC758 args\uB294 \uD3C9\uBA74 \uC624\uBE0C\uC81D\uD2B8\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uBB34\uC2DC\uD569\uB2C8\uB2E4`);
2465
+ }
2466
+ const useSpec = adapter?.useSpec;
2467
+ if (!useSpec) {
2468
+ warnOnce2(
2469
+ "fragment:no-useSpec",
2470
+ "[sdui] Fragment\uB97C \uC4F0\uB824\uBA74 \uC5B4\uB311\uD130\uC5D0 useSpec(id)\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4"
2471
+ );
2472
+ return null;
2473
+ }
2474
+ return /* @__PURE__ */ jsx(
2475
+ SduiFragmentBody,
2476
+ {
2477
+ id,
2478
+ args: isPlainObject3(rawArgs) ? rawArgs : void 0,
2479
+ useSpec,
2480
+ chain,
2481
+ scope,
2482
+ engine
2483
+ },
2484
+ id
2485
+ );
2486
+ }
2487
+ function SduiFragmentBody({
2488
+ id,
2489
+ args,
2490
+ useSpec,
2491
+ chain,
2492
+ scope,
2493
+ engine
2494
+ }) {
2495
+ const spec = useSpec(id);
2496
+ const nextChain = React11.useMemo(() => [...chain, id], [chain, id]);
2497
+ const bodyScope = React11.useMemo(() => [...scope, { args, callSiteScope: scope }], [scope, args]);
2498
+ React11.useEffect(() => {
2499
+ if (!DEV || !isPlainObject3(spec) || !Array.isArray(spec.body)) return;
2500
+ validateSpec(spec, new Set(Object.keys(engine.registry))).forEach(
2501
+ (issue) => console.warn(`[sdui:spec:${id}] ${issue.path} \u2014 ${issue.message}`)
2502
+ );
2503
+ }, [spec, engine.registry, id]);
2504
+ if (spec === void 0) return null;
2505
+ if (spec === null || !isPlainObject3(spec) || !Array.isArray(spec.body)) {
2506
+ warnOnce2(`fragment:missing:${id}`, `[sdui] Fragment \uC2A4\uD399\uC744 \uD574\uC11D\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${id} \u2014 \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
2507
+ return null;
2508
+ }
2509
+ const page = spec;
2510
+ if (page.data || page.urlState || page.subscribe) {
2511
+ warnOnce2(
2512
+ `fragment:page-features:${id}`,
2513
+ `[sdui] Fragment \uC2A4\uD399 ${id}\uC758 data/urlState/subscribe\uB294 \uBB34\uC2DC\uB429\uB2C8\uB2E4 \u2014 \uC870\uAC01\uC740 body\uB9CC \uB80C\uB354\uD569\uB2C8\uB2E4`
2514
+ );
2515
+ }
2516
+ return /* @__PURE__ */ jsx(SduiFragmentChainContext.Provider, { value: nextChain, children: page.body.map((child, i) => renderChild(child, i, bodyScope, engine)) });
2517
+ }
2365
2518
  function SduiRenderer({
2366
2519
  page,
2367
2520
  registry = defaultRegistry,
@@ -2494,13 +2647,21 @@ function SduiRenderer({
2494
2647
  return current === void 0 ? value.default ?? null : current;
2495
2648
  }
2496
2649
  if (isItemRef(value)) {
2497
- const frame = scope[scope.length - 1];
2650
+ const frame = nearestItemFrame(scope);
2498
2651
  if (!frame) return null;
2499
2652
  if (value.$item === true) return frame.item;
2500
2653
  return isPlainObject3(frame.item) ? frame.item[value.$item] ?? null : null;
2501
2654
  }
2502
2655
  if (isIndexRef(value)) {
2503
- return scope[scope.length - 1]?.index ?? null;
2656
+ return nearestItemFrame(scope)?.index ?? null;
2657
+ }
2658
+ if (isArgRef(value)) {
2659
+ const frame = nearestArgsFrame(scope);
2660
+ if (frame?.args && Object.hasOwn(frame.args, value.$arg)) {
2661
+ return resolveValue(frame.args[value.$arg], frame.callSiteScope);
2662
+ }
2663
+ if (value.default !== void 0) return resolveValue(value.default, scope);
2664
+ return void 0;
2504
2665
  }
2505
2666
  if (isCalcRef(value)) {
2506
2667
  const { op: rawOp, args, field: rawField } = value.$calc;
@@ -2649,10 +2810,16 @@ function SduiRenderer({
2649
2810
  const dispatchRef = useRef(() => {
2650
2811
  });
2651
2812
  const dispatch = useCallback(
2652
- (rawAction, arg) => {
2813
+ (rawAction, arg, scope = EMPTY_SCOPE) => {
2814
+ if (isArgRef(rawAction)) {
2815
+ for (const entry of expandActionEntries(rawAction, scope)) {
2816
+ dispatchRef.current(entry.action, arg, entry.scope);
2817
+ }
2818
+ return;
2819
+ }
2653
2820
  const action = resolveValue(
2654
2821
  rawAction,
2655
- EMPTY_SCOPE
2822
+ scope
2656
2823
  );
2657
2824
  switch (action.action) {
2658
2825
  case "navigate":
@@ -2756,7 +2923,7 @@ function SduiRenderer({
2756
2923
  body: values
2757
2924
  });
2758
2925
  setEntries({ [`${formId}.$submitting`]: false, [`${formId}.$resetDirty`]: true });
2759
- (action.onSuccess ?? []).forEach((a) => dispatchRef.current(a, response));
2926
+ (action.onSuccess ?? []).forEach((a) => dispatchRef.current(a, response, scope));
2760
2927
  } catch (error) {
2761
2928
  setEntries({ [`${formId}.$submitting`]: false });
2762
2929
  const message = error instanceof Error ? error.message : "\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4";
@@ -2764,7 +2931,7 @@ function SduiRenderer({
2764
2931
  warnOnce2(`validate:${formId}`, `[sdui] ${formId} \uAC80\uC99D \uADDC\uCE59 \uC624\uB958: ${message}`);
2765
2932
  pushToast({ tone: "danger", title: "\uAC80\uC99D \uADDC\uCE59 \uC624\uB958", message });
2766
2933
  } else if (action.onError?.length) {
2767
- action.onError.forEach((a) => dispatchRef.current(a, message));
2934
+ action.onError.forEach((a) => dispatchRef.current(a, message, scope));
2768
2935
  } else {
2769
2936
  pushToast({ tone: "danger", title: "\uC800\uC7A5 \uC2E4\uD328", message });
2770
2937
  }
@@ -2775,7 +2942,9 @@ function SduiRenderer({
2775
2942
  case "request":
2776
2943
  void runRequestAction(action, {
2777
2944
  fetch: (path, init) => hostRef.current.fetch(path, init),
2778
- dispatch: (a, value) => dispatchRef.current(a, value),
2945
+ // scope 를 잇는다 — request 의 onSuccess/onError 도 같은 자리의 텍스트다.
2946
+ // {"$arg"} 체인 항목은 dispatch 진입부가 이 스코프로 펼친다(submitForm과 동일).
2947
+ dispatch: (a, value) => dispatchRef.current(a, value, scope),
2779
2948
  toast: pushToast
2780
2949
  });
2781
2950
  break;
package/dist/meta.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as SduiPropValue, h as SduiNode } from './types-CeUhMB9Q.js';
1
+ import { b as SduiPropValue, i as SduiNode } from './types-opTPYysN.js';
2
2
 
3
3
  /**
4
4
  * 시각 빌더용 컴포넌트 메타데이터 스키마.
@@ -530,9 +530,11 @@ declare const dsComponentMeta: {
530
530
  */
531
531
 
532
532
  declare const ForEachMeta: SduiComponentMeta;
533
+ declare const FragmentMeta: SduiComponentMeta;
533
534
  /** 렌더러 내장 어휘의 메타데이터 묶음. */
534
535
  declare const builtinComponentMeta: {
535
536
  ForEach: SduiComponentMeta;
537
+ Fragment: SduiComponentMeta;
536
538
  };
537
539
 
538
540
  /**
@@ -553,7 +555,7 @@ declare const SDUI_CATEGORIES: ReadonlyArray<{
553
555
  label: string;
554
556
  }>;
555
557
  /**
556
- * 라이브러리가 아는 어휘 전체 — 기본 41 + rich 2 + 위젯 21 + DS 6 + 렌더러 내장 1 = 71종.
558
+ * 라이브러리가 아는 어휘 전체 — 기본 41 + rich 2 + 위젯 21 + DS 6 + 렌더러 내장 2 = 72종.
557
559
  * 편집기처럼 어휘 전부를 다뤄야 하는 쪽에서 쓴다.
558
560
  *
559
561
  * **레지스트리와 일대일이 아니다.** `defaultRegistry`에 없는 것도 들어 있다 —
@@ -582,4 +584,4 @@ declare function paletteGroups(catalog?: Record<string, SduiComponentMeta>): Arr
582
584
  items: SduiComponentMeta[];
583
585
  }>;
584
586
 
585
- export { ActionsMeta, AlertMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, FieldMeta, ForEachMeta, FormMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RemoteSearchResultsMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, type SduiCategory, type SduiChildrenMeta, type SduiComponentMeta, type SduiDomMeta, type SduiEnumOption, type SduiPropGroup, type SduiPropKind, type SduiPropMeta, type SduiResizeMeta, type SduiSlotMeta, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
587
+ export { ActionsMeta, AlertMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, FieldMeta, ForEachMeta, FormMeta, FragmentMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RemoteSearchResultsMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, type SduiCategory, type SduiChildrenMeta, type SduiComponentMeta, type SduiDomMeta, type SduiEnumOption, type SduiPropGroup, type SduiPropKind, type SduiPropMeta, type SduiResizeMeta, type SduiSlotMeta, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
package/dist/meta.js CHANGED
@@ -41,8 +41,39 @@ var ForEachMeta = {
41
41
  },
42
42
  resize: { kind: "none" }
43
43
  };
44
+ var FragmentMeta = {
45
+ name: "Fragment",
46
+ label: "\uC2A4\uD399 \uC870\uAC01",
47
+ category: "logic",
48
+ icon: "component",
49
+ description: '\uB2E4\uB978 \uC2A4\uD399(id)\uC758 body\uB97C \uC774 \uC790\uB9AC\uC5D0 \uC778\uB77C\uC778 \uB80C\uB354\uD55C\uB2E4. \uC0C8 \uC0C1\uD0DC \uC5C6\uC774 \uD604\uC7AC \uD398\uC774\uC9C0\uC758 $state\xB7$item\xB7\uAD8C\uD55C\uC744 \uADF8\uB300\uB85C \uBCF8\uB2E4 \u2014 \uACF5\uC6A9 \uB2E4\uC774\uC5BC\uB85C\uADF8\uB97C \uC870\uAC01\uC73C\uB85C \uBE7C\uB294 \uC790\uB9AC\uB2E4. args\uB85C \uAC12\xB7\uC561\uC158\uC744 \uB118\uAE30\uBA74 \uC870\uAC01 \uC548\uC5D0\uC11C {"$arg":"\uC774\uB984"}\uC73C\uB85C \uC77D\uB294\uB2E4.',
50
+ props: [
51
+ {
52
+ name: "id",
53
+ kind: "string",
54
+ label: "\uC2A4\uD399 ID",
55
+ required: true,
56
+ description: '\uAC00\uC838\uC62C \uC2A4\uD399\uC758 id (\uC608: "dialogs/asset/category/catCreate"). \uC5B4\uB311\uD130\uC758 useSpec\uC73C\uB85C \uD574\uC11D\uB41C\uB2E4.',
57
+ group: "data"
58
+ },
59
+ {
60
+ name: "args",
61
+ kind: "object",
62
+ label: "\uC804\uB2EC \uC778\uC790",
63
+ description: '\uC870\uAC01\uC5D0 \uB118\uAE38 { \uC774\uB984: \uAC12 } \uD3C9\uBA74 \uC624\uBE0C\uC81D\uD2B8. \uAC12\uC740 \uC2A4\uCE7C\uB77C\xB7\uBC14\uC778\uB529($state/$item)\xB7\uC561\uC158(\uB2E8\uC77C/\uBC30\uC5F4) \uBB34\uC5C7\uC774\uB4E0 \uB418\uACE0, \uC870\uAC01 \uC548\uC5D0\uC11C {"$arg":"\uC774\uB984","default"?:\u2026}\uB85C \uC77D\uB294\uB2E4.',
64
+ group: "data"
65
+ }
66
+ ],
67
+ children: { accepts: false },
68
+ // 조각의 body를 그린다 — 작성한 children은 렌더되지 않는다
69
+ dom: { element: "fragment" },
70
+ // ForEach와 같음 — 자기 요소 없이 자식을 흘려보낸다
71
+ preset: { component: "Fragment", props: { id: "dialogs/example" } },
72
+ resize: { kind: "none" }
73
+ };
44
74
  var builtinComponentMeta = {
45
- ForEach: ForEachMeta
75
+ ForEach: ForEachMeta,
76
+ Fragment: FragmentMeta
46
77
  };
47
78
 
48
79
  // src/meta/self-axis.ts
@@ -4526,4 +4557,4 @@ function paletteGroups(catalog = allComponentMeta) {
4526
4557
  })).filter((group) => group.items.length > 0);
4527
4558
  }
4528
4559
 
4529
- export { ActionsMeta, AlertMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, FieldMeta, ForEachMeta, FormMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RemoteSearchResultsMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
4560
+ export { ActionsMeta, AlertMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, FieldMeta, ForEachMeta, FormMeta, FragmentMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RemoteSearchResultsMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
@@ -39,6 +39,19 @@ interface SduiStateRef {
39
39
  interface SduiItemRef {
40
40
  $item: string | true;
41
41
  }
42
+ /**
43
+ * Fragment 조각 안에서 호출부가 넘긴 args 값을 참조한다.
44
+ *
45
+ * 조각 스펙(body)의 값 자리 어디서나 쓴다 — 프롭·Show.when·$calc 인자·액션 필드.
46
+ * 해석 규칙: 가장 가까운 Fragment의 args에서 이름을 찾고, 찾은 **원본 값**을
47
+ * **호출부 스코프**로 다시 해석한다(호출부의 $state/$item이 호출부 의미로 풀린다).
48
+ * 이름이 없으면 default, 그것도 없으면 undefined — 경고 없이 조용히 빈다
49
+ * (Show.when 같은 조건 자리의 정상 폴백을 허용하기 위해서다).
50
+ */
51
+ interface SduiArgRef {
52
+ $arg: string;
53
+ default?: SduiPropValue;
54
+ }
42
55
  /** ForEach 반복 스코프 안에서 현재 인덱스(0부터)를 참조한다. */
43
56
  interface SduiIndexRef {
44
57
  $index: true;
@@ -265,4 +278,4 @@ interface SduiPage {
265
278
  body: SduiChild[];
266
279
  }
267
280
 
268
- export type { SduiAction as S, SduiPropValue as a, SduiRule as b, SduiPage as c, SduiCalcRef as d, SduiChild as e, SduiIndexRef as f, SduiItemRef as g, SduiNode as h, SduiPageQuery as i, SduiScalar as j, SduiStateRef as k };
281
+ export type { SduiPage as S, SduiAction as a, SduiPropValue as b, SduiRule as c, SduiArgRef as d, SduiCalcRef as e, SduiChild as f, SduiIndexRef as g, SduiItemRef as h, SduiNode as i, SduiPageQuery as j, SduiScalar as k, SduiStateRef as l };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipco/sdui",
3
- "version": "0.16.0",
3
+ "version": "0.17.1",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",