@wipco/sdui 0.4.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ export function Page({ spec }: { spec: unknown }) {
18
18
 
19
19
  | 진입점 | 내용 | 추가 peer |
20
20
  | --- | --- | --- |
21
- | `@wipco/sdui` | 렌더러 · 기본 어휘 39종 · 검증 · 권한 게이트 | 없음 |
21
+ | `@wipco/sdui` | 렌더러 · 기본 어휘 41종 · 검증 · 권한 게이트 | 없음 |
22
22
  | `@wipco/sdui/rich` | `Chart` · `MapPreview` — `createRegistry(richComponents)`로 얹는다 | `recharts` · `ol` (선택) |
23
23
  | `@wipco/sdui/meta` | 컴포넌트 메타데이터 — 빌더 UI의 팔레트·속성 패널용 | 없음 |
24
24
  | `@wipco/sdui/styles.css` | 공용 시트 (`.wp-*`) | — |
@@ -1,7 +1,7 @@
1
+ import { containerLayoutStyle } from './chunk-QBIVW7E6.js';
1
2
  import React from 'react';
2
3
  import { jsxs, jsx } from 'react/jsx-runtime';
3
4
 
4
- // src/widgets/Strip.tsx
5
5
  var STRIP_CSS = `
6
6
  .erp-strip{display:flex;align-items:stretch;overflow-x:auto;min-width:0;padding-bottom:var(--wp-space-1);scrollbar-width:thin;scrollbar-color:var(--wp-border-default) transparent}
7
7
  .erp-strip::-webkit-scrollbar{height:6px}
@@ -14,12 +14,19 @@ var STRIP_CSS = `
14
14
  function StripStyles() {
15
15
  return /* @__PURE__ */ jsx("style", { href: "erp-strip", precedence: "medium", children: STRIP_CSS });
16
16
  }
17
- function Strip({ children, gap = "var(--wp-space-3)", snap = false }) {
17
+ function Strip({ children, gap = "12", snap = false }) {
18
18
  const items = React.Children.toArray(children);
19
- return /* @__PURE__ */ jsxs("div", { className: snap ? "erp-strip erp-strip--snap" : "erp-strip", style: { gap }, children: [
20
- /* @__PURE__ */ jsx(StripStyles, {}),
21
- items.map((child, index) => /* @__PURE__ */ jsx("div", { className: "erp-strip__item", children: child }, index))
22
- ] });
19
+ return /* @__PURE__ */ jsxs(
20
+ "div",
21
+ {
22
+ className: snap ? "erp-strip erp-strip--snap" : "erp-strip",
23
+ style: containerLayoutStyle({ gap }) ?? { gap: "12px" },
24
+ children: [
25
+ /* @__PURE__ */ jsx(StripStyles, {}),
26
+ items.map((child, index) => /* @__PURE__ */ jsx("div", { className: "erp-strip__item", children: child }, index))
27
+ ]
28
+ }
29
+ );
23
30
  }
24
31
 
25
32
  export { Strip };
@@ -0,0 +1,90 @@
1
+ // src/layout.ts
2
+ var GAP_CSS = {
3
+ "2": "2px",
4
+ "4": "4px",
5
+ "8": "8px",
6
+ "12": "12px",
7
+ "16": "16px",
8
+ "20": "20px",
9
+ "24": "24px",
10
+ "32": "32px"
11
+ };
12
+ var ALIGN_CSS = {
13
+ start: "flex-start",
14
+ center: "center",
15
+ end: "flex-end",
16
+ baseline: "baseline",
17
+ stretch: "stretch"
18
+ };
19
+ var JUSTIFY_CSS = {
20
+ start: "flex-start",
21
+ center: "center",
22
+ end: "flex-end",
23
+ between: "space-between"
24
+ };
25
+ var WEIGHT_CSS = {
26
+ regular: "var(--wp-weight-regular, 400)",
27
+ medium: "var(--wp-weight-medium, 500)",
28
+ semibold: "var(--wp-weight-semibold, 600)",
29
+ bold: "var(--wp-weight-bold, 700)"
30
+ };
31
+ var TEXT_ALIGN_CSS = {
32
+ left: "left",
33
+ center: "center",
34
+ right: "right"
35
+ };
36
+ var COLUMNS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 6]);
37
+ function lookup(table, value) {
38
+ if (value === void 0 || value === null) return void 0;
39
+ return table[String(value)];
40
+ }
41
+ function containerLayoutStyle(props) {
42
+ const gap = lookup(GAP_CSS, props.gap);
43
+ const alignItems = lookup(ALIGN_CSS, props.align);
44
+ const justifyContent = lookup(JUSTIFY_CSS, props.justify);
45
+ const flexWrap = props.wrap === void 0 ? void 0 : props.wrap ? "wrap" : "nowrap";
46
+ if (gap === void 0 && alignItems === void 0 && justifyContent === void 0 && flexWrap === void 0) {
47
+ return void 0;
48
+ }
49
+ return { gap, alignItems, justifyContent, flexWrap };
50
+ }
51
+ function columnsClass(columns) {
52
+ const n = Number(columns);
53
+ return Number.isInteger(n) && COLUMNS.has(n) ? `wp-grid--${n}` : void 0;
54
+ }
55
+ var CHILD_LAYOUT_PROPS = /* @__PURE__ */ new Set([
56
+ "grow",
57
+ "shrink",
58
+ "span",
59
+ "selfAlign",
60
+ "truncate"
61
+ ]);
62
+ function childLayoutFrom(props) {
63
+ const style = {};
64
+ if (props.grow !== void 0) style.flexGrow = props.grow ? 1 : 0;
65
+ if (props.shrink !== void 0) style.flexShrink = props.shrink ? 1 : 0;
66
+ const span = Number(props.span);
67
+ if (Number.isInteger(span) && COLUMNS.has(span)) style.gridColumn = `span ${span}`;
68
+ const alignSelf = lookup(ALIGN_CSS, props.selfAlign);
69
+ if (alignSelf !== void 0) style.alignSelf = alignSelf;
70
+ const className = props.truncate ? "wp-truncate" : void 0;
71
+ const hasStyle = Object.keys(style).length > 0;
72
+ if (!hasStyle && className === void 0) return void 0;
73
+ return { style: hasStyle ? style : void 0, className };
74
+ }
75
+ function typographyStyle(props) {
76
+ const fontWeight = lookup(WEIGHT_CSS, props.weight);
77
+ const textAlign = lookup(TEXT_ALIGN_CSS, props.textAlign);
78
+ if (fontWeight === void 0 && textAlign === void 0) return void 0;
79
+ return { fontWeight, textAlign };
80
+ }
81
+ var LAYOUT_CSS = `
82
+ .wp-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
83
+ .wp-grid--1{grid-template-columns:minmax(0,1fr)}
84
+ .wp-grid--5{grid-template-columns:repeat(5,minmax(0,1fr))}
85
+ .wp-grid--6{grid-template-columns:repeat(6,minmax(0,1fr))}
86
+ @media (max-width:900px){.wp-grid--5,.wp-grid--6{grid-template-columns:repeat(2,minmax(0,1fr))}}
87
+ @media (max-width:600px){.wp-grid--5,.wp-grid--6{grid-template-columns:minmax(0,1fr)}}
88
+ `;
89
+
90
+ export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, childLayoutFrom, columnsClass, containerLayoutStyle, typographyStyle };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as React from 'react';
2
- import React__default, { ComponentType } from 'react';
2
+ import React__default, { CSSProperties, ReactNode, ComponentType } from 'react';
3
3
  import { D as DatePicker, a as DateRangePicker } from './DatePicker-CTDcFR7V.js';
4
4
  export { b as DatePickerProps, c as DateRangePickerProps, d as DateRangeValue } from './DatePicker-CTDcFR7V.js';
5
+ import { S as SduiContainerLayoutProps, a as SduiColumnsScale, b as SduiWeightScale, c as SduiTextAlignScale } from './layout-BnYUuWC2.js';
6
+ export { C as CHILD_LAYOUT_PROPS, L as LAYOUT_CSS, d as SduiAlignScale, e as SduiChildLayoutProps, f as SduiGapScale, g as SduiSpanScale, h as childLayoutFrom, i as columnsClass, j as containerLayoutStyle, t as typographyStyle } from './layout-BnYUuWC2.js';
5
7
  import { S as SduiAction, a as SduiPropValue, b as SduiRule, c as SduiPage } from './types-D5Tkrynd.js';
6
8
  export { d as SduiCalcRef, e as SduiChild, f as SduiIndexRef, g as SduiItemRef, h as SduiNode, i as SduiScalar, j as SduiStateRef } from './types-D5Tkrynd.js';
7
9
 
@@ -596,39 +598,45 @@ interface TooltipProps extends React__default.HTMLAttributes<HTMLSpanElement> {
596
598
  /** hover 힌트. 트리거를 감싸며 위치는 CSS가 잡는다 — 포털을 쓰지 않는다. */
597
599
  declare function Tooltip({ label, shortcut, placement, wrap, children, className, ...rest }: TooltipProps): React__default.JSX.Element;
598
600
 
599
- interface GridProps {
600
- /** wp-grid--N 프리셋 */
601
- columns?: 2 | 3 | 4;
601
+ interface GridProps extends SduiContainerLayoutProps {
602
+ /** wp-grid--N 프리셋 (1~6) */
603
+ columns?: SduiColumnsScale;
602
604
  /** 커스텀 트랙 — grid-template-columns 값. columns보다 우선 */
603
605
  template?: string;
604
606
  className?: string;
605
607
  style?: React__default.CSSProperties;
606
608
  children?: React__default.ReactNode;
607
609
  }
608
- declare function Grid({ columns, template, className, style, children }: GridProps): React__default.JSX.Element;
610
+ declare function Grid({ columns, template, gap, align, justify, wrap, className, style, children }: GridProps): React__default.JSX.Element;
609
611
  type Justify = 'start' | 'center' | 'end' | 'between';
610
- interface RowProps {
612
+ interface RowProps extends SduiContainerLayoutProps {
611
613
  /** 가로 정렬 (기본 start) */
612
614
  justify?: Justify;
613
615
  className?: string;
614
616
  style?: React__default.CSSProperties;
615
617
  children?: React__default.ReactNode;
616
618
  }
617
- declare function Row({ justify, className, style, children }: RowProps): React__default.JSX.Element;
618
- interface ActionsProps {
619
+ declare function Row({ justify, gap, align, wrap, className, style, children }: RowProps): React__default.JSX.Element;
620
+ interface ActionsProps extends SduiContainerLayoutProps {
619
621
  /** 가로 정렬 — 기본 end(우측) */
620
622
  justify?: Justify;
621
623
  className?: string;
622
624
  style?: React__default.CSSProperties;
623
625
  children?: React__default.ReactNode;
624
626
  }
625
- /** 액션 버튼 묶음 — 슬롯 안에서 정렬을 제어한다(flex:1로 슬롯 폭 차지). */
626
- declare function Actions({ justify, className, style, children }: ActionsProps): React__default.JSX.Element;
627
- declare function Col({ className, style, children }: {
627
+ /**
628
+ * 액션 버튼 묶음 — 슬롯 안에서 정렬을 제어한다(flex:1로 슬롯 폭 차지).
629
+ *
630
+ * `justify = 'end'`가 **2단(타입별 기본)의 실제 사례**다. 전역 기본은 `.wp-row`의
631
+ * `flex-start`인데 이 타입만 `end`로 시작하고, 스펙이 `justify`를 주면 그것이 이긴다.
632
+ */
633
+ declare function Actions({ justify, gap, align, wrap, className, style, children }: ActionsProps): React__default.JSX.Element;
634
+ interface ColProps extends SduiContainerLayoutProps {
628
635
  className?: string;
629
636
  style?: React__default.CSSProperties;
630
637
  children?: React__default.ReactNode;
631
- }): React__default.JSX.Element;
638
+ }
639
+ declare function Col({ gap, align, justify, wrap, className, style, children }: ColProps): React__default.JSX.Element;
632
640
  interface SpacerProps {
633
641
  /**
634
642
  * 간격 토큰 단계(`--wp-space-N`). 주면 "남는 공간 밀어내기"가 아니라
@@ -639,25 +647,37 @@ interface SpacerProps {
639
647
  size?: 1 | 2 | 3 | 4 | 5 | 6 | 8;
640
648
  }
641
649
  declare function Spacer({ size }: SpacerProps): React__default.JSX.Element;
642
- interface SectionProps {
650
+ interface SectionProps extends SduiContainerLayoutProps {
643
651
  title?: React__default.ReactNode;
644
652
  className?: string;
645
653
  style?: React__default.CSSProperties;
646
654
  children?: React__default.ReactNode;
647
655
  }
648
- declare function Section({ title, className, style, children }: SectionProps): React__default.JSX.Element;
656
+ declare function Section({ title, gap, align, justify, wrap, className, style, children }: SectionProps): React__default.JSX.Element;
649
657
  type TextPreset = 'display-1' | 'display-2' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body-lg' | 'body' | 'body-sm' | 'caption' | 'label' | 'overline' | 'micro' | 'metric' | 'metric-sm' | 'mono' | 'mono-xs';
650
658
  interface TextProps {
651
659
  /** styles.css의 .wp-* 타입 프리셋 이름 */
652
660
  preset?: TextPreset;
653
661
  as?: 'p' | 'span' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
662
+ /**
663
+ * 글자 굵기 — `preset`이 정한 굵기를 이 자리에서만 뒤집는다.
664
+ * 프리셋 19종이 크기·굵기·정렬을 묶어 놔 "본문 크기인데 굵게"를 만들 수 없던 것을 푼다.
665
+ */
666
+ weight?: SduiWeightScale;
667
+ /** 글자 정렬. */
668
+ textAlign?: SduiTextAlignScale;
654
669
  className?: string;
655
670
  style?: React__default.CSSProperties;
656
671
  /** children 대신 쓸 수 있는 내용 — 상태 바인딩({ "$state": ... })에 유용 */
657
672
  value?: React__default.ReactNode;
658
673
  children?: React__default.ReactNode;
659
674
  }
660
- declare function Text({ preset, as: Tag, className, style, value, children }: TextProps): React__default.JSX.Element;
675
+ /**
676
+ * `weight`·`textAlign`은 **이 요소에만** 붙는다. 자손에게 내려보내는 코드는 없다 —
677
+ * 그 일은 CSS 상속이 이미 하고 있고, JS로 다시 하면 `Show`/`Can` 같은 fragment 노드
678
+ * 때문에 스펙 트리의 부모와 실제 DOM 부모가 어긋나 조용히 틀린 값이 내려간다(layout.ts 주석).
679
+ */
680
+ declare function Text({ preset, as: Tag, weight, textAlign, className, style, value, children, }: TextProps): React__default.JSX.Element;
661
681
  interface KeyValueItem {
662
682
  label: React__default.ReactNode;
663
683
  /** source에서 꺼낼 필드 키. 생략하면 value를 그대로 출력 */
@@ -1235,6 +1255,124 @@ interface SduiFormProps {
1235
1255
  }
1236
1256
  declare function SduiForm({ id, initial, initialFromUrl, rules, labels, guard, onSubmit, className, style, children, }: SduiFormProps): React__default.JSX.Element;
1237
1257
 
1258
+ /**
1259
+ * `SortableList` / `SortHandle` — 손잡이를 끌어 **배열 상태의 순서를 바꾸는** 목록.
1260
+ *
1261
+ * 어휘에 이미 `arrayMove` 액션이 있었다. 없던 것은 그 액션을 **드래그로 일으키는
1262
+ * 표현**뿐이라, 여기서 새로 만드는 것도 그 표현 하나다 — 상태 변경은 전부 기존
1263
+ * `arrayMove`로 나간다(새 액션 0개, `types.ts` 무변경).
1264
+ *
1265
+ * ## 왜 컨테이너와 손잡이 둘로 나눴나
1266
+ *
1267
+ * `$item`/`$index` 스코프는 **렌더러 소유**다(`SduiRenderer.tsx`의 ForEach 분기만
1268
+ * `rowScope`를 만든다). 레지스트리 컴포넌트는 배열을 스스로 돌 수 없으므로, 반복은
1269
+ * 그대로 `ForEach`가 하고 이쪽은 **인덱스만** 안다.
1270
+ *
1271
+ * SortableList(stateKey) > ForEach(source) > Card( SortHandle(index:{$index:true}) … )
1272
+ *
1273
+ * 손잡이가 `{"$index": true}`로 **자기 번호를 스펙에서 선언**하는 것이 핵심이다.
1274
+ * 컨테이너가 DOM 자식을 세어 인덱스를 매기는 안(손잡이 없는 단일 컴포넌트)은 버렸다 —
1275
+ * ForEach는 fragment라 보통은 "DOM 자식 하나 = 행 하나"가 맞지만, 행 템플릿이 노드
1276
+ * 둘이 되거나 `Show`가 아무것도 안 그리는 순간 매핑이 **조용히** 어긋난다. 어휘가
1277
+ * "행은 노드 하나여야 함"이라는 암묵 규칙을 갖게 되는 값이 손잡이 하나보다 비싸다.
1278
+ *
1279
+ * 손잡이가 필요한 독립적인 이유도 있다. 이 목록의 행은 `Input`/`Textarea`를 품는다.
1280
+ * 행 전체를 드래그로 잡으면 그 입력칸의 텍스트 선택이 죽는다. 캔버스 자신도 같은
1281
+ * 결론이라 노드 이동을 행이 아니라 그립 뱃지에 붙였다.
1282
+ *
1283
+ * ## 왜 HTML5 DnD가 아니라 포인터 이벤트인가
1284
+ *
1285
+ * 실측(Chromium): 캔버스가 캡처 단계에서 `mousedown`을 삼키면 `dragstart`는 안 뜨지만
1286
+ * `pointerdown`/`pointermove`는 그대로 온다. 그리고 터치에서는 `dragstart`가 아예 안 뜬다.
1287
+ * 포인터 이벤트를 고르면 캔버스의 노드 이동(HTML5 DnD)과 **이벤트 종류부터 달라져**,
1288
+ * `dragover`마다 "이건 행 정렬인가 노드 이동인가"를 되묻는 분기가 아예 생기지 않는다.
1289
+ * 대신 캔버스에서는 이쪽이 완전히 살아 있으므로 **명시적으로 끊어야 한다** — 아래 참고.
1290
+ * 라이브러리 선례도 포인터 쪽이다(`OrgChart`의 `setPointerCapture` + `touchAction:'none'`).
1291
+ *
1292
+ * ## 캔버스에서는 정렬이 노드 이동에 진다
1293
+ *
1294
+ * `useSduiSandbox()`가 true면 포인터·키보드 핸들러를 **아예 붙이지 않는다.** 근거는
1295
+ * 두 가지다. ① 캔버스는 스펙을 고치는 자리이고, 거기서 바꾼 행 순서는 런타임 상태라
1296
+ * **저장되지 않는다** — 사용자가 한 일이 사라지는 것이 가장 나쁜 결과다. ② 캔버스에서
1297
+ * 행을 끄는 동작에는 이미 뜻이 있다(노드 이동). 두 뜻이 겹치면 어느 쪽인지 정해야
1298
+ * 하는데, 저장되지 않는 쪽이 이길 이유가 없다.
1299
+ * 표식은 그린다 — 손잡이는 그립 모양 그대로 나오되 `aria-disabled`와 사유 툴팁이 붙는다.
1300
+ * "막았다"를 화면에 남기는 방식과 문구를 캔버스의 다른 차단과 맞춘 것이다.
1301
+ *
1302
+ * ## 잠기는 자리를 전부 툴팁으로 말한다
1303
+ *
1304
+ * `arrayMove`는 키가 배열이 아니면 **경고 한 줄 없이** 끝난다. 이 화면은 정확히 그
1305
+ * 함정 위에 지어지므로(`{"$state":"rows","default":[…]}`처럼 `default`만 있는 상태는
1306
+ * 화면에 행이 보여도 `arrayMove`가 무동작이다), 손잡이가 스스로 그 사실을 말한다.
1307
+ * 사유는 전부 `title` + `aria-disabled`로 나가고, 스펙 작성 실수(키 없음·손잡이가
1308
+ * 컨테이너 밖)만 콘솔에도 한 번 남긴다.
1309
+ *
1310
+ * ## 접근성 — 세 경로가 같은 액션 하나로 모인다
1311
+ *
1312
+ * 드래그(포인터) ─┐
1313
+ * 키보드(손잡이) ─┼→ dispatch({action:'arrayMove', key, from, to})
1314
+ * 위/아래 버튼 ─┘ (버튼은 스펙이 직접 선언한다 — 라이브러리 개입 0)
1315
+ *
1316
+ * WCAG SC 2.5.7(Dragging Movements)은 드래그에 단일 포인터 대안을 요구하고 SC 2.1.1은
1317
+ * 키보드 대안을 요구한다. 손잡이는 진짜 `<button>`이고 Space로 집어 ↑↓로 옮긴다.
1318
+ * 위/아래 버튼은 오늘 어휘만으로 완성되므로(`arrayMove.to`에 `$calc` sum/sub를 넣으면
1319
+ * 된다 — 실측 확인) 여기서 대신 만들지 않는다. 스펙이 그대로 쓰면 된다.
1320
+ * 그립은 SC 2.5.8(Target Size)을 지켜 24×24 CSS px 이상이다.
1321
+ */
1322
+
1323
+ /**
1324
+ * 손잡이들의 세로 중심 좌표에서 드롭 지점을 인덱스로 바꾼다. 가장 가까운 중심이 답이다.
1325
+ *
1326
+ * 행 높이가 같으면 이 규칙에 히스테리시스가 저절로 생긴다 — 한 칸 옮겨진 직후에는
1327
+ * 포인터 밑에 **옮겨진 행 자신**이 있으므로 가장 가까운 중심이 자기 자리가 되어
1328
+ * 되돌아가지 않는다. 그래서 끄는 동안 곧바로 `arrayMove`를 쏘는(=행이 실제로 움직이는)
1329
+ * 방식이 흔들리지 않고, 자리표시자·유령 행 같은 장치가 필요 없다.
1330
+ *
1331
+ * 빈 자리(`null`/`undefined`)는 건너뛴다. `Show`가 어떤 행의 손잡이를 안 그리면
1332
+ * 그 인덱스는 비는데, 그때 0으로 뭉개면 엉뚱한 행이 목적지가 된다.
1333
+ *
1334
+ * @param centers 인덱스별 손잡이 중심의 clientY. 성기게(sparse) 와도 된다.
1335
+ * @returns 가장 가까운 인덱스. 잴 손잡이가 하나도 없으면 null.
1336
+ */
1337
+ declare function sortableDropIndex(centers: ReadonlyArray<number | null | undefined>, pointerY: number): number | null;
1338
+ /**
1339
+ * 이동을 확정한다 — **`arrayMove`가 실제로 하는 일과 같은 규칙**으로.
1340
+ *
1341
+ * `arrayMove`는 `from`이 범위를 벗어나면 무시하고, `to`는 양끝으로 clamp한 뒤
1342
+ * `from === to`면 아무 것도 하지 않는다(`SduiRenderer.tsx`). 그 판정을 여기서 미리
1343
+ * 해서 **무동작 액션을 아예 쏘지 않는다.** 렌더러에 맡겨도 결과는 같지만, 그러면
1344
+ * "첫 행을 위로"가 상태 갱신 한 번을 헛돌게 하고 낭독도 한 번 헛나간다.
1345
+ *
1346
+ * @returns 옮길 자리. 할 일이 없으면(범위 밖·같은 자리) null.
1347
+ */
1348
+ declare function sortableMove(from: number, to: number | null, length: number): number | null;
1349
+ interface SortableListProps {
1350
+ /**
1351
+ * 순서를 바꿀 배열의 상태 키. `arrayMove.key`로 그대로 나간다.
1352
+ *
1353
+ * **최상위 키여야 한다** — `arrayMove`는 `state[key]`를 직접 조회하므로 `a.0.b` 같은
1354
+ * 중첩 경로는 조용히 무동작이다. 행마다 다른 배열을 다뤄야 하면(분류 안의 항목 등)
1355
+ * 상태를 평면으로 펴고 `{"$calc":{"op":"concat","args":["items.",{"$item":"id"}]}}`로
1356
+ * 키를 만들어 넘긴다 — 렌더러가 프롭을 해석해 주므로 여기에는 문자열로 도착한다.
1357
+ */
1358
+ stateKey?: string;
1359
+ /** 순서 변경 잠금. 손잡이는 그대로 보이고 사유가 툴팁으로 붙는다. */
1360
+ disabled?: boolean;
1361
+ className?: string;
1362
+ style?: CSSProperties;
1363
+ children?: ReactNode;
1364
+ }
1365
+ declare function SortableList({ stateKey, disabled, className, style, children, }: SortableListProps): React__default.JSX.Element;
1366
+ interface SortHandleProps {
1367
+ /** 이 행의 번호. 스펙에서는 거의 항상 `{"$index": true}`이고, 그 값이 곧 `arrayMove.from`이다. */
1368
+ index?: number;
1369
+ /** 보조기술이 읽을 행 이름. 보통 `{"$item":"title"}`. 없으면 "N번째 항목". */
1370
+ label?: string;
1371
+ className?: string;
1372
+ style?: CSSProperties;
1373
+ }
1374
+ declare function SortHandle({ index, label, className, style }: SortHandleProps): React__default.JSX.Element;
1375
+
1238
1376
  /**
1239
1377
  * JSON 스펙의 `component` 이름 → 실제 컴포넌트.
1240
1378
  * 이 키 목록이 곧 스펙에서 사용할 수 있는 컴포넌트 어휘 전체다.
@@ -1292,6 +1430,8 @@ declare const defaultRegistry: {
1292
1430
  Text: typeof Text;
1293
1431
  Form: typeof SduiForm;
1294
1432
  Can: typeof Can;
1433
+ SortableList: typeof SortableList;
1434
+ SortHandle: typeof SortHandle;
1295
1435
  SearchResults: typeof SduiSearchResults;
1296
1436
  RemoteSearchResults: typeof RemoteSearchResults;
1297
1437
  };
@@ -1431,4 +1571,4 @@ declare class NodeErrorBoundary extends React__default.Component<Props, State> {
1431
1571
  render(): string | number | bigint | boolean | Iterable<React__default.ReactNode> | Promise<string | number | bigint | boolean | React__default.ReactPortal | React__default.ReactElement<unknown, string | React__default.JSXElementConstructor<any>> | Iterable<React__default.ReactNode> | null | undefined> | React__default.JSX.Element | null | undefined;
1432
1572
  }
1433
1573
 
1434
- 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 CustomActionHandler, type CustomValidator, DatePicker, DateRangePicker, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, Icon, IconButton, type IconButtonProps, type IconProps, 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, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, 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, type SduiTextCell, 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 SelectProps, Show, type ShowProps, SidebarNav, type SidebarNavItem, type SidebarNavProps, type SidebarNavSection, type SortDir, 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, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, defaultAdapter, defaultRegistry, includesLooseSearch, joinMultiValue, normalizePageSizes, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec };
1574
+ 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, DatePicker, DateRangePicker, Dialog, type DialogProps, Divider, EmptyState, type EmptyStateProps, Field, type FieldProps, Grid, type GridCardConfig, type GridCardRow, type GridProps, Icon, IconButton, type IconButtonProps, type IconProps, 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, type SduiCanFn, type SduiCanQuery, type SduiCanSetting, type SduiCell, SduiColumnsScale, SduiContainerLayoutProps, type SduiDateCell, SduiDialog, type SduiDispatch, SduiForm, type SduiFormConfig, type SduiFormProps, type SduiGridCard, type SduiGridCardAction, type SduiGridCardRow, type SduiIconCell, 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 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, cascadingValuePaths, cellRenderer, cleanSearchValues, createRegistry, defaultAdapter, defaultRegistry, includesLooseSearch, joinMultiValue, normalizePageSizes, normalizeSearchText, searchFieldKeys, searchValuesFromParams, sortableDropIndex, sortableMove, splitMultiValue, useRemoteSearchPage, useSduiAssetResolver, useSduiCan, useSduiDispatch, useSduiRuntime, useSduiSandbox, useSearchFetcher, validateSpec };