@wipco/sdui 0.5.0 → 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.
@@ -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
@@ -2,6 +2,8 @@ import * as React from 'react';
2
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를 그대로 출력 */
@@ -1551,4 +1571,4 @@ declare class NodeErrorBoundary extends React__default.Component<Props, State> {
1551
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;
1552
1572
  }
1553
1573
 
1554
- 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, 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 };
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 };
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { DEV, DateRangePicker, DatePicker, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, HoistedStyle, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-FGRR3ROJ.js';
2
2
  export { DatePicker, DateRangePicker, defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-FGRR3ROJ.js';
3
+ import { containerLayoutStyle, columnsClass, typographyStyle, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-QBIVW7E6.js';
4
+ export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, childLayoutFrom, columnsClass, containerLayoutStyle, typographyStyle } from './chunk-QBIVW7E6.js';
3
5
  import { searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-KADFN76X.js';
4
6
  export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-KADFN76X.js';
5
7
  import { Toast, Textarea, Tag, Tabs, Table, Switch, StatCard, Spinner, Select, ProgressBar, Pagination, Input, IconButton, Icon, Field, EmptyState, Checkbox, Card, Button, Badge, Alert, SegmentedControl, Dialog } from './chunk-ZUCI34QY.js';
@@ -189,51 +191,76 @@ function Can({ entity, action = "read", scope, fallback = null, children }) {
189
191
  function cx(...parts) {
190
192
  return parts.filter(Boolean).join(" ");
191
193
  }
192
- function Grid({ columns = 3, template, className, style, children }) {
194
+ function mergeStyle(own, given) {
195
+ if (!own) return given;
196
+ if (!given) return own;
197
+ return { ...own, ...given };
198
+ }
199
+ function Grid({ columns = 3, template, gap, align, justify, wrap, className, style, children }) {
193
200
  return /* @__PURE__ */ jsx(
194
201
  "div",
195
202
  {
196
- className: cx("wp-grid", !template && `wp-grid--${columns}`, className),
197
- style: template ? { gridTemplateColumns: template, ...style } : style,
203
+ className: cx("wp-grid", !template && columnsClass(columns), className),
204
+ style: mergeStyle(
205
+ template ? { gridTemplateColumns: template, ...containerLayoutStyle({ gap, align, justify, wrap }) } : containerLayoutStyle({ gap, align, justify, wrap }),
206
+ style
207
+ ),
198
208
  children
199
209
  }
200
210
  );
201
211
  }
202
- var JUSTIFY_CSS = {
203
- start: "flex-start",
204
- center: "center",
205
- end: "flex-end",
206
- between: "space-between"
207
- };
208
- function Row({ justify, className, style, children }) {
212
+ function Row({ justify, gap, align, wrap, className, style, children }) {
209
213
  return /* @__PURE__ */ jsx(
210
214
  "div",
211
215
  {
212
216
  className: cx("wp-row", justify === "between" && "wp-row--between", className),
213
- style: justify && justify !== "between" ? { justifyContent: JUSTIFY_CSS[justify], ...style } : style,
217
+ style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style),
214
218
  children
215
219
  }
216
220
  );
217
221
  }
218
- function Actions({ justify = "end", className, style, children }) {
219
- return /* @__PURE__ */ jsx("div", { className: cx("wp-row", className), style: { flex: 1, justifyContent: JUSTIFY_CSS[justify], ...style }, children });
222
+ function Actions({ justify = "end", gap, align, wrap, className, style, children }) {
223
+ return /* @__PURE__ */ jsx(
224
+ "div",
225
+ {
226
+ className: cx("wp-row", className),
227
+ style: mergeStyle({ flex: 1, ...containerLayoutStyle({ gap, align, justify, wrap }) }, style),
228
+ children
229
+ }
230
+ );
220
231
  }
221
- function Col({ className, style, children }) {
222
- return /* @__PURE__ */ jsx("div", { className: cx("wp-col", className), style, children });
232
+ function Col({ gap, align, justify, wrap, className, style, children }) {
233
+ return /* @__PURE__ */ jsx("div", { className: cx("wp-col", className), style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style), children });
223
234
  }
224
235
  var SPACER_STEPS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 6, 8]);
225
236
  function Spacer({ size }) {
226
237
  const step = size !== void 0 && SPACER_STEPS.has(Number(size)) ? Number(size) : void 0;
227
238
  return /* @__PURE__ */ jsx("div", { className: cx("wp-spacer", step !== void 0 && `wp-spacer--${step}`) });
228
239
  }
229
- function Section({ title, className, style, children }) {
230
- return /* @__PURE__ */ jsxs("section", { className: cx("wp-col", className), style, children: [
231
- title ? /* @__PURE__ */ jsx("h2", { className: "wp-h4", children: title }) : null,
232
- children
233
- ] });
240
+ function Section({ title, gap, align, justify, wrap, className, style, children }) {
241
+ return /* @__PURE__ */ jsxs(
242
+ "section",
243
+ {
244
+ className: cx("wp-col", className),
245
+ style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style),
246
+ children: [
247
+ title ? /* @__PURE__ */ jsx("h2", { className: "wp-h4", children: title }) : null,
248
+ children
249
+ ]
250
+ }
251
+ );
234
252
  }
235
- function Text({ preset = "body", as: Tag2 = "p", className, style, value, children }) {
236
- return /* @__PURE__ */ jsx(Tag2, { className: cx(`wp-${preset}`, className), style, children: value ?? children });
253
+ function Text({
254
+ preset = "body",
255
+ as: Tag2 = "p",
256
+ weight,
257
+ textAlign,
258
+ className,
259
+ style,
260
+ value,
261
+ children
262
+ }) {
263
+ return /* @__PURE__ */ jsx(Tag2, { className: cx(`wp-${preset}`, className), style: mergeStyle(typographyStyle({ weight, textAlign }), style), children: value ?? children });
237
264
  }
238
265
  function KeyValueList({ source, items, className, style }) {
239
266
  return /* @__PURE__ */ jsx("div", { className: cx("wp-kv", className), style, children: (items ?? []).map((item, index) => {
@@ -2043,6 +2070,16 @@ function SduiNodeRenderer({
2043
2070
  props[name] = resolved;
2044
2071
  }
2045
2072
  }
2073
+ const childLayout = childLayoutFrom(props);
2074
+ if (childLayout) {
2075
+ for (const name of CHILD_LAYOUT_PROPS) delete props[name];
2076
+ if (childLayout.style) {
2077
+ props.style = isPlainObject2(props.style) ? { ...childLayout.style, ...props.style } : childLayout.style;
2078
+ }
2079
+ if (childLayout.className) {
2080
+ props.className = typeof props.className === "string" && props.className ? `${childLayout.className} ${props.className}` : childLayout.className;
2081
+ }
2082
+ }
2046
2083
  for (const [name, slotChildren] of Object.entries(slots ?? {})) {
2047
2084
  if (!Array.isArray(slotChildren)) {
2048
2085
  warnOnce2(
@@ -2448,6 +2485,7 @@ function SduiRenderer({
2448
2485
  // 해석된 어댑터를 트리에 흘려보낸다 — dispatch를 거치지 않고 스스로 요청을 내는
2449
2486
  // 컴포넌트(목록 조회 등)도 호스트가 건 잠금 안에서 움직이게 하기 위해서다(adapter.ts 주석).
2450
2487
  /* @__PURE__ */ jsx(SduiAdapterContext.Provider, { value: host, children: /* @__PURE__ */ jsx(SduiDispatchContext.Provider, { value: dispatch, children: /* @__PURE__ */ jsx(SduiRuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ jsx(SduiPermissionProvider, { can, children: /* @__PURE__ */ jsxs("div", { className: "sdui-root", children: [
2488
+ /* @__PURE__ */ jsx(HoistedStyle, { id: "wp-sdui-layout", css: LAYOUT_CSS }),
2451
2489
  page.title || page.subtitle ? /* @__PURE__ */ jsx("div", { className: "wp-page-head", children: /* @__PURE__ */ jsxs("div", { className: "wp-page-head__text", children: [
2452
2490
  page.title ? /* @__PURE__ */ jsx("h1", { className: "wp-page-head__title", children: page.title }) : null,
2453
2491
  page.subtitle ? /* @__PURE__ */ jsx("div", { className: "wp-page-head__sub", children: page.subtitle }) : null
@@ -0,0 +1,150 @@
1
+ import React__default from 'react';
2
+
3
+ /**
4
+ * 레이아웃 어휘 — 공통 프롭의 값 척도와, 그 값을 CSS로 바꾸는 자리.
5
+ *
6
+ * ── 왜 이 모듈이 생겼나
7
+ * 스펙 85개에서 `style` 우회가 187선언 있었고, 그중 73선언(39%)이 "프롭이 없어서"
8
+ * 손으로 쓴 CSS였다(`gap` 33 · `align` 17 · `wrap` 7 · `weight` 7 · `justify` 4 ·
9
+ * `textAlign` 3 · `grow` 1 · `selfAlign` 1). `Col`에는 레이아웃 프롭이 0개였고,
10
+ * v2 원본 88화면이 368회 쓰던 `items-center`에 대응하는 프롭이 어휘 어디에도 없었다.
11
+ *
12
+ * ── 축을 네 갈래로 가른다 (이 갈래가 구현 방식을 결정한다)
13
+ * 1. 컨테이너 전용 `gap` `wrap` `columns` — 자식에 그 개념이 없다
14
+ * 2. 컨테이너+자식 `align` ↔ `selfAlign` — CSS의 align-items/align-self 짝
15
+ * 3. 자식 전용 `grow` `shrink` `span` `truncate`
16
+ * 4. CSS가 상속함 `weight` `textAlign` — **JS는 아무것도 하지 않는다**
17
+ *
18
+ * 4번이 핵심이다. `font-weight`·`text-align`은 브라우저가 이미 자손에게 상속시킨다.
19
+ * 렌더러가 부모를 훑어 값을 내려보내면 중복이고, 게다가 **반드시 틀린다** —
20
+ * `Show`·`Can`·`ForEach`는 `dom.element: 'fragment'`라 자기 DOM 박스가 없어서
21
+ * 스펙 트리의 부모와 실제 DOM 부모가 다르고(`Row > Show > Text`의 DOM 부모는 Row다),
22
+ * `Alert`·`Card`는 자식이 `__body`/`__text` 안으로 들어가 한 겹 더 어긋난다.
23
+ * 그래서 `weight`/`textAlign`은 **자기 요소에만 값을 붙이고 끝낸다.** 부모를 보지 않는다.
24
+ */
25
+ /**
26
+ * 간격 척도 — **px 숫자 문자열**이다. 토큰 단계 번호(`1..8`)도 t-shirt(`sm/md/lg`)도 쓰지 않는다.
27
+ *
28
+ * 단계 번호를 버린 이유: DS 토큰 번호와 v2가 쓰던 Tailwind 번호가 위에서 어긋난다.
29
+ * `--wp-space-7`=32px인데 `gap-7`=28px, `--wp-space-8`=40px인데 `gap-8`=32px이다.
30
+ * 88화면을 옮기는 사람이 `gap-4`를 보고 `gap="4"`를 쓰면 4px이 아니라 16px을 원한 것이다.
31
+ *
32
+ * t-shirt를 버린 이유: `size` 프롭이 이미 12종에서 `sm/md/lg`를 **컨트롤 높이**로 쓴다
33
+ * (`Button.size` 131회, `Dialog.size` 87회). 한 속성 패널에 `size:"md"`(높이 32px)와
34
+ * `gap:"md"`(간격 12px)가 나란히 놓이면 같은 낱말이 두 척도를 가리키게 된다.
35
+ *
36
+ * 6px은 뺐다 — v2가 `gap-1.5`로 38회 쓰지만 DS 척도에 없는 값이라, 여기 넣으면
37
+ * "편집기가 DS 척도를 강제한다"는 이 작업의 목적 자체가 무너진다. `--wp-space-1half`를
38
+ * DS에 더할지는 DS 쪽 결정이고, 그때까지 그 자리는 8px로 붙거나 `style`에 남는다.
39
+ */
40
+ type SduiGapScale = '2' | '4' | '8' | '12' | '16' | '20' | '24' | '32';
41
+ /** `align-items` / `align-self`의 DS 낱말. 값 이름을 CSS 낱말(`flex-start`)로 두지 않는 것은 기존 `Justify`와 짝을 맞추기 위해서다. */
42
+ type SduiAlignScale = 'start' | 'center' | 'end' | 'baseline' | 'stretch';
43
+ /** 그리드 자식이 먹는 트랙 수(`grid-column: span N`). */
44
+ type SduiSpanScale = 1 | 2 | 3 | 4 | 5 | 6;
45
+ /** `Grid`의 트랙 수. 기존 2·3·4에 1·5·6을 더했다 — v2가 22회 쓴다(1열 11 · 5열 5 · 6열 3). */
46
+ type SduiColumnsScale = 1 | 2 | 3 | 4 | 5 | 6;
47
+ /**
48
+ * 글자 굵기. `Text.preset` 19종이 크기·굵기·정렬을 한 덩어리로 묶어 놔서
49
+ * "본문 크기인데 굵게"(v2 `font-medium` 282회)를 만들 수단이 없었다.
50
+ */
51
+ type SduiWeightScale = 'regular' | 'medium' | 'semibold' | 'bold';
52
+ type SduiTextAlignScale = 'left' | 'center' | 'right';
53
+ /**
54
+ * 자기 루트가 flex/grid인 컴포넌트만 받는 축.
55
+ *
56
+ * 이 프롭들을 렌더러가 아무 노드에나 꽂지 않고 **컴포넌트가 직접 받게** 한 이유:
57
+ * 렌더러는 컴포넌트의 루트가 flex인지 알 수 없어서, `Timeline`에 `gap`을 준 스펙이
58
+ * 아무 일도 일어나지 않은 채 조용히 넘어간다. 프롭으로 두면 타입이 그 자리에서 막는다.
59
+ */
60
+ interface SduiContainerLayoutProps {
61
+ /** 자식 사이 간격(px 척도). 생략하면 컴포넌트의 CSS 기본값. */
62
+ gap?: SduiGapScale;
63
+ /** 교차축 정렬(`align-items`). 자식이 `selfAlign`으로 자기 몫만 뒤집을 수 있다. */
64
+ align?: SduiAlignScale;
65
+ /** 주축 정렬(`justify-content`). */
66
+ justify?: 'start' | 'center' | 'end' | 'between';
67
+ /** 넘치면 다음 줄로(`flex-wrap`). */
68
+ wrap?: boolean;
69
+ }
70
+ /**
71
+ * 컨테이너 축 → 인라인 style.
72
+ *
73
+ * ── 유틸 클래스(`wp-gap--8` 등)를 만들지 않고 인라인 style로 가는 이유
74
+ * 실측: 같은 클래스의 기본값이 두 시트에서 다르다(`.wp-col` gap 라이브러리 16px / ERP 8px,
75
+ * `.wp-grid` 16px / 20px). 유틸 클래스는 `.wp-col`과 **명시도가 같아서**(둘 다 클래스 1개)
76
+ * 어느 쪽이 이길지 소스 순서로 결정되는데, 이 시트는 React가 런타임에 꽂는 hoisted
77
+ * `<style>`이고 저쪽은 번들러가 낸 `<link>`라 순서를 보장할 수 없다. 인라인 style은
78
+ * 명시도에서 항상 이기므로 `gap="16"`이 두 소비자에서 똑같이 16px이 된다.
79
+ *
80
+ * 캐스케이드를 잃는 대가는 없다. 4단 해소에서 인라인이 맡는 것은 1단(자식 지정)뿐이고,
81
+ * 2단(타입별 기본)은 컴포넌트 기본 인자가, 3·4단(상속·전역)은 `.wp-row`/`.wp-col` 같은
82
+ * 기존 클래스가 그대로 맡는다. 프롭을 안 주면 인라인 선언 자체가 없어 아래 단이 그대로 보인다.
83
+ */
84
+ declare function containerLayoutStyle(props: SduiContainerLayoutProps): React__default.CSSProperties | undefined;
85
+ /** `Grid.columns` → `wp-grid--N`. 표에 없는 값은 undefined로 떨어뜨려 클래스 주입을 막는다. */
86
+ declare function columnsClass(columns: unknown): string | undefined;
87
+ /**
88
+ * 부모가 아니라 **자기 박스**에 거는 축. 부모 쪽 형태가 없다.
89
+ *
90
+ * 컨테이너 축과 달리 이쪽은 렌더러가 가로채 아무 노드에나 붙인다. 어떤 컴포넌트든
91
+ * flex/grid 부모의 자식이 될 수 있어서 대상을 좁힐 근거가 없기 때문이다.
92
+ */
93
+ interface SduiChildLayoutProps {
94
+ /** 남는 공간을 먹는다(`flex-grow`). */
95
+ grow?: boolean;
96
+ /** 좁아질 때 줄어든다(`flex-shrink`). `false`면 원래 크기를 지킨다. */
97
+ shrink?: boolean;
98
+ /** 그리드에서 먹는 트랙 수(`grid-column: span N`). */
99
+ span?: SduiSpanScale;
100
+ /** 부모의 `align`을 이 노드에서만 뒤집는다(`align-self`). */
101
+ selfAlign?: SduiAlignScale;
102
+ /** 한 줄로 잘라 말줄임(`.wp-truncate`). */
103
+ truncate?: boolean;
104
+ }
105
+ /** 렌더러가 가로채는 자식 축 프롭 이름. */
106
+ declare const CHILD_LAYOUT_PROPS: ReadonlySet<string>;
107
+ interface ChildLayoutResult {
108
+ style?: React__default.CSSProperties;
109
+ className?: string;
110
+ }
111
+ /**
112
+ * 자식 축 → style/className.
113
+ *
114
+ * `truncate`만 클래스인 이유: 선언이 넷이고(`overflow`·`text-overflow`·`white-space`·
115
+ * `min-width`) 그중 `min-width:0`이 flex 자식의 축소 하한을 푸는 필수 조건인데,
116
+ * ERP 시트의 `.wp-row`/`.wp-col`/`.wp-grid`에는 `min-width:0`이 아예 없다(라이브러리에는 있다).
117
+ * 그래서 조상을 고치는 대신 **잘리는 요소 자신에게** `min-width:0`을 건다 — flex 자식의
118
+ * 하한을 푸는 표준 처방이고, 조상 시트를 건드리지 않으니 기존 화면이 움직이지 않는다.
119
+ */
120
+ declare function childLayoutFrom(props: SduiChildLayoutProps): ChildLayoutResult | undefined;
121
+ /**
122
+ * `weight`/`textAlign` → 자기 요소의 style.
123
+ *
124
+ * **부모를 훑지 않는다.** 이 둘은 CSS가 이미 자손에게 상속시키는 속성이라, 값을 자기
125
+ * 요소에 한 번 붙이면 3단(부모 상속)이 공짜로 성립한다. 인라인으로 붙여도 상속은
126
+ * 똑같이 일어난다 — 상속은 명시도가 아니라 계산값을 따라가기 때문이다.
127
+ */
128
+ declare function typographyStyle(props: {
129
+ weight?: SduiWeightScale;
130
+ textAlign?: SduiTextAlignScale;
131
+ }): React__default.CSSProperties | undefined;
132
+ /**
133
+ * 새 어휘가 필요로 하는 **최소한의** CSS.
134
+ *
135
+ * 여기 들어온 것은 인라인 style로 표현할 수 없는 둘뿐이다:
136
+ * · `.wp-truncate` — 선언이 여럿이라 묶는 편이 낫다
137
+ * · `.wp-grid--1/5/6` — 미디어 쿼리가 필요하다. 인라인 `grid-template-columns`로 내면
138
+ * 좁은 화면에서 열이 접히는 기존 동작(`.wp-grid--3/4` → 2열 → 1열)을 잃는다.
139
+ *
140
+ * 나머지(gap·align·justify·wrap·grow·shrink·span·selfAlign·weight·textAlign)는 전부
141
+ * 인라인이라 CSS가 없다. 규칙을 적게 낼수록 두 시트와 충돌할 자리도 줄어든다 —
142
+ * 실제로 이 세 선택자는 라이브러리 시트에도 ERP 시트에도 없어서 겹칠 상대가 없다.
143
+ *
144
+ * `styles.css`가 아니라 `HoistedStyle`로 내보내는 이유: ERP는 `@wipco/sdui/styles.css`를
145
+ * **한 번도 로드하지 않는다**(`main.tsx`가 자기 `styles/index.css`만 import한다).
146
+ * 시트에 넣으면 ERP에서 규칙이 도달하지 못해 `truncate`·5열/6열이 죽는다.
147
+ */
148
+ declare const LAYOUT_CSS = "\n.wp-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}\n.wp-grid--1{grid-template-columns:minmax(0,1fr)}\n.wp-grid--5{grid-template-columns:repeat(5,minmax(0,1fr))}\n.wp-grid--6{grid-template-columns:repeat(6,minmax(0,1fr))}\n@media (max-width:900px){.wp-grid--5,.wp-grid--6{grid-template-columns:repeat(2,minmax(0,1fr))}}\n@media (max-width:600px){.wp-grid--5,.wp-grid--6{grid-template-columns:minmax(0,1fr)}}\n";
149
+
150
+ export { CHILD_LAYOUT_PROPS as C, LAYOUT_CSS as L, type SduiContainerLayoutProps as S, type SduiColumnsScale as a, type SduiWeightScale as b, type SduiTextAlignScale as c, type SduiAlignScale as d, type SduiChildLayoutProps as e, type SduiGapScale as f, type SduiSpanScale as g, childLayoutFrom as h, columnsClass as i, containerLayoutStyle as j, typographyStyle as t };
package/dist/meta.js CHANGED
@@ -62,6 +62,149 @@ var classNameProp = {
62
62
  group: "layout",
63
63
  advanced: true
64
64
  };
65
+ var gapProp = {
66
+ name: "gap",
67
+ kind: "enum",
68
+ label: "\uC774 \uC548\uC758 \uAC04\uACA9",
69
+ default: "8",
70
+ description: "DS \uAC04\uACA9 \uCC99\uB3C4(px). \uCC99\uB3C4 \uBC16 \uAC12\uC740 style\uC5D0 \uB0A8\uAE34\uB2E4.",
71
+ options: [
72
+ { value: "2", label: "2px" },
73
+ { value: "4", label: "4px" },
74
+ { value: "8", label: "8px" },
75
+ { value: "12", label: "12px" },
76
+ { value: "16", label: "16px" },
77
+ { value: "20", label: "20px" },
78
+ { value: "24", label: "24px" },
79
+ { value: "32", label: "32px" }
80
+ ],
81
+ group: "layout"
82
+ };
83
+ var gridGapProp = {
84
+ name: "gap",
85
+ kind: "enum",
86
+ label: "\uC774 \uC548\uC758 \uAC04\uACA9",
87
+ default: "20",
88
+ description: "DS \uAC04\uACA9 \uCC99\uB3C4(px). \uADF8\uB9AC\uB4DC \uAE30\uBCF8\uC740 20px(--wp-gutter)\uC774\uB2E4.",
89
+ options: [
90
+ { value: "2", label: "2px" },
91
+ { value: "4", label: "4px" },
92
+ { value: "8", label: "8px" },
93
+ { value: "12", label: "12px" },
94
+ { value: "16", label: "16px" },
95
+ { value: "20", label: "20px" },
96
+ { value: "24", label: "24px" },
97
+ { value: "32", label: "32px" }
98
+ ],
99
+ group: "layout"
100
+ };
101
+ var rowAlignProp = {
102
+ name: "align",
103
+ kind: "enum",
104
+ label: "\uC774 \uC548\uC758 \uAD50\uCC28\uCD95 \uC815\uB82C",
105
+ default: "center",
106
+ description: "\uC790\uC2DD\uB4E4\uC744 \uC138\uB85C\uB85C \uC5B4\uB514\uC5D0 \uB9DE\uCD9C\uC9C0(align-items). \uC790\uC2DD\uC774 selfAlign\uC73C\uB85C \uC790\uAE30 \uAC83\uB9CC \uB4A4\uC9D1\uC744 \uC218 \uC788\uB2E4.",
107
+ options: [
108
+ { value: "start", label: "\uC704" },
109
+ { value: "center", label: "\uAC00\uC6B4\uB370" },
110
+ { value: "end", label: "\uC544\uB798" },
111
+ { value: "baseline", label: "\uAE00\uC790 \uAE30\uC900\uC120" },
112
+ { value: "stretch", label: "\uB298\uB9AC\uAE30" }
113
+ ],
114
+ group: "layout"
115
+ };
116
+ var stretchAlignProp = {
117
+ name: "align",
118
+ kind: "enum",
119
+ label: "\uC774 \uC548\uC758 \uAD50\uCC28\uCD95 \uC815\uB82C",
120
+ default: "stretch",
121
+ description: "\uC790\uC2DD\uB4E4\uC744 \uAC00\uB85C\uB85C \uC5B4\uB514\uC5D0 \uB9DE\uCD9C\uC9C0(align-items). \uC790\uC2DD\uC774 selfAlign\uC73C\uB85C \uC790\uAE30 \uAC83\uB9CC \uB4A4\uC9D1\uC744 \uC218 \uC788\uB2E4.",
122
+ options: [
123
+ { value: "start", label: "\uC67C\uCABD" },
124
+ { value: "center", label: "\uAC00\uC6B4\uB370" },
125
+ { value: "end", label: "\uC624\uB978\uCABD" },
126
+ { value: "baseline", label: "\uAE00\uC790 \uAE30\uC900\uC120" },
127
+ { value: "stretch", label: "\uB298\uB9AC\uAE30" }
128
+ ],
129
+ group: "layout"
130
+ };
131
+ var wrapProp = {
132
+ name: "wrap",
133
+ kind: "boolean",
134
+ label: "\uB118\uCE58\uBA74 \uC904\uBC14\uAFC8",
135
+ default: false,
136
+ description: "flex-wrap. \uB044\uBA74 \uD55C \uC904\uC5D0 \uBC00\uC5B4 \uB123\uB294\uB2E4.",
137
+ group: "layout"
138
+ };
139
+ var columnJustifyProp = {
140
+ name: "justify",
141
+ kind: "enum",
142
+ label: "\uC774 \uC548\uC758 \uC8FC\uCD95 \uC815\uB82C",
143
+ description: "justify-content. \uC138\uB85C \uBB36\uC74C\uC774\uB77C \uC138\uB85C \uBC29\uD5A5\uC774\uACE0, \uB192\uC774\uAC00 \uC815\uD574\uC9C4 \uC790\uB9AC\uC5D0\uC11C\uB9CC \uD45C\uAC00 \uB09C\uB2E4.",
144
+ options: [
145
+ { value: "start", label: "\uC704" },
146
+ { value: "center", label: "\uAC00\uC6B4\uB370" },
147
+ { value: "end", label: "\uC544\uB798" },
148
+ { value: "between", label: "\uC591\uB05D" }
149
+ ],
150
+ group: "layout",
151
+ advanced: true
152
+ };
153
+ var growProp = {
154
+ name: "grow",
155
+ kind: "boolean",
156
+ label: "\uC790\uAE30: \uB0A8\uB294 \uACF5\uAC04 \uCC28\uC9C0",
157
+ description: "flex-grow. \uBD80\uBAA8\uC758 \uB0A8\uB294 \uD3ED(\uC138\uB85C \uBB36\uC74C\uC774\uBA74 \uB192\uC774)\uC744 \uC774 \uB178\uB4DC\uAC00 \uBA39\uB294\uB2E4.",
158
+ group: "layout",
159
+ advanced: true
160
+ };
161
+ var shrinkProp = {
162
+ name: "shrink",
163
+ kind: "boolean",
164
+ label: "\uC790\uAE30: \uC881\uC544\uC9C0\uBA74 \uC904\uC5B4\uB4E6",
165
+ description: "flex-shrink. \uB044\uBA74 \uC881\uC544\uC838\uB3C4 \uC6D0\uB798 \uD06C\uAE30\uB97C \uC9C0\uD0A8\uB2E4(\uBC84\uD2BC\xB7\uBC30\uC9C0\uCC98\uB7FC \uCC0C\uADF8\uB7EC\uC9C0\uBA74 \uC548 \uB418\uB294 \uAC83).",
166
+ group: "layout",
167
+ advanced: true
168
+ };
169
+ var spanProp = {
170
+ name: "span",
171
+ kind: "enum",
172
+ label: "\uC790\uAE30: \uC5F4 \uBCD1\uD569",
173
+ description: "grid-column: span N. \uBD80\uBAA8\uAC00 Grid\uC77C \uB54C\uB9CC \uB73B\uC774 \uC788\uB2E4.",
174
+ options: [
175
+ { value: 1, label: "1\uCE78" },
176
+ { value: 2, label: "2\uCE78" },
177
+ { value: 3, label: "3\uCE78" },
178
+ { value: 4, label: "4\uCE78" },
179
+ { value: 5, label: "5\uCE78" },
180
+ { value: 6, label: "6\uCE78" }
181
+ ],
182
+ group: "layout",
183
+ advanced: true
184
+ };
185
+ var selfAlignProp = {
186
+ name: "selfAlign",
187
+ kind: "enum",
188
+ label: "\uC790\uAE30: \uAD50\uCC28\uCD95 \uC815\uB82C",
189
+ description: "align-self. \uBD80\uBAA8\uC758 align\uC744 \uC774 \uB178\uB4DC\uC5D0\uC11C\uB9CC \uB4A4\uC9D1\uB294\uB2E4.",
190
+ options: [
191
+ { value: "start", label: "\uC2DC\uC791" },
192
+ { value: "center", label: "\uAC00\uC6B4\uB370" },
193
+ { value: "end", label: "\uB05D" },
194
+ { value: "baseline", label: "\uAE00\uC790 \uAE30\uC900\uC120" },
195
+ { value: "stretch", label: "\uB298\uB9AC\uAE30" }
196
+ ],
197
+ group: "layout",
198
+ advanced: true
199
+ };
200
+ var truncateProp = {
201
+ name: "truncate",
202
+ kind: "boolean",
203
+ label: "\uC790\uAE30: \uD55C \uC904 \uB9D0\uC904\uC784",
204
+ description: "\uB118\uCE58\uB294 \uAE00\uC790\uB97C \u2026\uB85C \uC790\uB978\uB2E4. \uC790\uAE30 min-width\uB97C 0\uC73C\uB85C \uD480\uC5B4 \uBB36\uC74C \uC548\uC5D0\uC11C\uB3C4 \uB3D9\uC791\uD55C\uB2E4.",
205
+ group: "layout",
206
+ advanced: true
207
+ };
65
208
  var ActionsMeta = {
66
209
  name: "Actions",
67
210
  label: "\uC561\uC158 \uBB36\uC74C",
@@ -83,8 +226,15 @@ var ActionsMeta = {
83
226
  ],
84
227
  group: "layout"
85
228
  },
229
+ gapProp,
230
+ rowAlignProp,
231
+ wrapProp,
86
232
  styleProp,
87
- classNameProp
233
+ classNameProp,
234
+ growProp,
235
+ shrinkProp,
236
+ spanProp,
237
+ selfAlignProp
88
238
  ],
89
239
  children: { accepts: true, text: false, label: "\uC815\uB82C\uD560 \uBC84\uD2BC\uB4E4" },
90
240
  dom: { element: "div" },
@@ -137,7 +287,12 @@ var CardMeta = {
137
287
  { name: "selected", kind: "boolean", label: "\uC120\uD0DD\uB428", default: false, bindable: true, group: "appearance" },
138
288
  { name: "onClick", kind: "action", label: "\uD074\uB9AD", group: "behavior" },
139
289
  styleProp,
140
- classNameProp
290
+ classNameProp,
291
+ growProp,
292
+ shrinkProp,
293
+ spanProp,
294
+ selfAlignProp,
295
+ truncateProp
141
296
  ],
142
297
  slots: [
143
298
  { name: "actions", label: "\uD5E4\uB354 \uC6B0\uCE21 \uC561\uC158", description: "\uBC84\uD2BC\xB7Select \uB4F1", allow: ["Actions", "Button", "IconButton", "Select", "Badge", "Tag", "Row", "Show", "Can"] },
@@ -158,12 +313,28 @@ var ColMeta = {
158
313
  category: "layout",
159
314
  icon: "chevrons-up-down",
160
315
  description: "\uC790\uC2DD\uC744 \uC138\uB85C\uB85C \uC313\uB294\uB2E4(.wp-col).",
161
- props: [styleProp, classNameProp],
316
+ props: [
317
+ gapProp,
318
+ stretchAlignProp,
319
+ columnJustifyProp,
320
+ wrapProp,
321
+ styleProp,
322
+ classNameProp,
323
+ growProp,
324
+ shrinkProp,
325
+ spanProp,
326
+ selfAlignProp
327
+ ],
162
328
  children: { accepts: true, text: true },
163
329
  dom: { element: "div" },
330
+ // 자식이 둘이다 — gap·align은 자식이 하나면 값을 바꿔도 화면이 그대로라
331
+ // 사용자가 프롭이 고장 났다고 판단한다. 레이아웃 컨테이너 preset의 규칙으로 잡는다.
164
332
  preset: {
165
333
  component: "Col",
166
- children: [{ component: "Text", props: { preset: "body" }, children: ["\uCCAB \uC904"] }]
334
+ children: [
335
+ { component: "Text", props: { preset: "body" }, children: ["\uCCAB \uC904"] },
336
+ { component: "Text", props: { preset: "body" }, children: ["\uB458\uC9F8 \uC904"] }
337
+ ]
167
338
  },
168
339
  resize: { kind: "style", axis: "both" }
169
340
  };
@@ -192,10 +363,15 @@ var GridMeta = {
192
363
  label: "\uC5F4 \uC218",
193
364
  default: 3,
194
365
  description: "wp-grid--N \uD504\uB9AC\uC14B. \uC2A4\uD399\uC5D0\uB294 \uBB38\uC790\uC5F4\uC774 \uC544\uB2C8\uB77C \uC22B\uC790\uB85C \uB4E4\uC5B4\uAC04\uB2E4.",
366
+ // 1·5·6은 새로 열었다 — v2 원본 88화면이 22회 쓴다(1열 11 · 5열 5 · 6열 3).
367
+ // 규칙은 어휘가 들고 다니는 시트(LAYOUT_CSS)에 있다. 2·3·4는 기존 시트 그대로.
195
368
  options: [
369
+ { value: 1, label: "1\uC5F4" },
196
370
  { value: 2, label: "2\uC5F4" },
197
371
  { value: 3, label: "3\uC5F4" },
198
- { value: 4, label: "4\uC5F4" }
372
+ { value: 4, label: "4\uC5F4" },
373
+ { value: 5, label: "5\uC5F4" },
374
+ { value: 6, label: "6\uC5F4" }
199
375
  ],
200
376
  group: "layout"
201
377
  },
@@ -206,8 +382,15 @@ var GridMeta = {
206
382
  description: 'grid-template-columns \uAC12. \uC608: "minmax(0,1.6fr) minmax(0,1fr)". columns\uB97C \uBB34\uC2DC\uD55C\uB2E4.',
207
383
  group: "layout"
208
384
  },
385
+ gridGapProp,
386
+ stretchAlignProp,
387
+ wrapProp,
209
388
  styleProp,
210
- classNameProp
389
+ classNameProp,
390
+ growProp,
391
+ shrinkProp,
392
+ spanProp,
393
+ selfAlignProp
211
394
  ],
212
395
  children: { accepts: true, text: false, label: "\uADF8\uB9AC\uB4DC \uCE78" },
213
396
  dom: { element: "div" },
@@ -219,7 +402,7 @@ var GridMeta = {
219
402
  { component: "Card", props: { title: "\uC624\uB978\uCABD" }, children: [] }
220
403
  ]
221
404
  },
222
- resize: { kind: "enum", prop: "columns", values: ["2", "3", "4"], axis: "x" }
405
+ resize: { kind: "enum", prop: "columns", values: ["1", "2", "3", "4", "5", "6"], axis: "x" }
223
406
  };
224
407
  var PageHeadMeta = {
225
408
  name: "PageHead",
@@ -260,8 +443,15 @@ var RowMeta = {
260
443
  ],
261
444
  group: "layout"
262
445
  },
446
+ gapProp,
447
+ rowAlignProp,
448
+ wrapProp,
263
449
  styleProp,
264
- classNameProp
450
+ classNameProp,
451
+ growProp,
452
+ shrinkProp,
453
+ spanProp,
454
+ selfAlignProp
265
455
  ],
266
456
  children: { accepts: true, text: true },
267
457
  dom: { element: "div" },
@@ -283,15 +473,26 @@ var SectionMeta = {
283
473
  description: "\uC81C\uBAA9(h4)\uC774 \uBD99\uC740 \uC138\uB85C \uAD6C\uD68D.",
284
474
  props: [
285
475
  { name: "title", kind: "node", label: "\uC81C\uBAA9", slot: true, group: "content" },
476
+ gapProp,
477
+ stretchAlignProp,
478
+ columnJustifyProp,
479
+ wrapProp,
286
480
  styleProp,
287
- classNameProp
481
+ classNameProp,
482
+ growProp,
483
+ shrinkProp,
484
+ spanProp,
485
+ selfAlignProp
288
486
  ],
289
487
  children: { accepts: true, text: true },
290
488
  dom: { element: "section", slotElement: { title: "h2" } },
291
489
  preset: {
292
490
  component: "Section",
293
491
  props: { title: "\uC139\uC158 \uC81C\uBAA9" },
294
- children: [{ component: "Text", props: { preset: "body" }, children: ["\uB0B4\uC6A9"] }]
492
+ children: [
493
+ { component: "Text", props: { preset: "body" }, children: ["\uB0B4\uC6A9"] },
494
+ { component: "Text", props: { preset: "body" }, children: ["\uB458\uC9F8 \uC904"] }
495
+ ]
295
496
  },
296
497
  resize: { kind: "style", axis: "both" }
297
498
  };
@@ -478,7 +679,12 @@ var ButtonMeta = {
478
679
  },
479
680
  { name: "onClick", kind: "action", label: "\uD074\uB9AD", group: "behavior" },
480
681
  styleProp,
481
- classNameProp
682
+ classNameProp,
683
+ growProp,
684
+ shrinkProp,
685
+ spanProp,
686
+ selfAlignProp,
687
+ truncateProp
482
688
  ],
483
689
  children: { accepts: true, text: true, label: "\uBC84\uD2BC \uB77C\uBCA8" },
484
690
  dom: { element: "button", elementProp: "as" },
@@ -877,7 +1083,12 @@ var InputMeta = {
877
1083
  group: "content"
878
1084
  },
879
1085
  styleProp,
880
- classNameProp
1086
+ classNameProp,
1087
+ growProp,
1088
+ shrinkProp,
1089
+ spanProp,
1090
+ selfAlignProp,
1091
+ truncateProp
881
1092
  ],
882
1093
  children: { accepts: false },
883
1094
  dom: { element: "input" },
@@ -930,7 +1141,12 @@ var SelectMeta = {
930
1141
  { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" },
931
1142
  { name: "aria-label", kind: "string", label: "\uC811\uADFC\uC131 \uB77C\uBCA8", description: "Field \uB77C\uBCA8\uC774 \uC5C6\uC744 \uB54C \uC4F4\uB2E4.", group: "content", advanced: true },
932
1143
  styleProp,
933
- classNameProp
1144
+ classNameProp,
1145
+ growProp,
1146
+ shrinkProp,
1147
+ spanProp,
1148
+ selfAlignProp,
1149
+ truncateProp
934
1150
  ],
935
1151
  children: { accepts: false },
936
1152
  dom: { element: "div" },
@@ -1242,6 +1458,39 @@ var TextMeta = {
1242
1458
  ],
1243
1459
  group: "appearance"
1244
1460
  },
1461
+ /*
1462
+ * weight·textAlign은 `preset`이 묶어 놓은 축을 푸는 자리다.
1463
+ * 프리셋 19종이 크기·굵기·정렬을 한 덩어리로 갖고 있어서 "본문 크기인데 굵게"
1464
+ * (v2 원본의 font-medium 282회)를 만들 수단이 없었다.
1465
+ *
1466
+ * `default`를 적지 않은 것은 의도다 — 기본 굵기가 preset마다 다르다(.wp-body 400,
1467
+ * .wp-label 600, .wp-h1 700). 하나를 적으면 편집기가 다른 preset에서 값을 잘못 지운다.
1468
+ */
1469
+ {
1470
+ name: "weight",
1471
+ kind: "enum",
1472
+ label: "\uAE00\uC790 \uAD75\uAE30",
1473
+ description: "preset\uC774 \uC815\uD55C \uAD75\uAE30\uB97C \uC774 \uC790\uB9AC\uC5D0\uC11C\uB9CC \uB4A4\uC9D1\uB294\uB2E4. \uC0DD\uB7B5\uD558\uBA74 preset\uC758 \uAD75\uAE30.",
1474
+ options: [
1475
+ { value: "regular", label: "\uBCF4\uD1B5(400)" },
1476
+ { value: "medium", label: "\uC911\uAC04(500)" },
1477
+ { value: "semibold", label: "\uC57D\uAC04 \uAD75\uAC8C(600)" },
1478
+ { value: "bold", label: "\uAD75\uAC8C(700)" }
1479
+ ],
1480
+ group: "appearance"
1481
+ },
1482
+ {
1483
+ name: "textAlign",
1484
+ kind: "enum",
1485
+ label: "\uAE00\uC790 \uC815\uB82C",
1486
+ description: "\uC0DD\uB7B5\uD558\uBA74 \uC0C1\uC18D\uBC1B\uC740 \uC815\uB82C\uC744 \uADF8\uB300\uB85C \uC4F4\uB2E4.",
1487
+ options: [
1488
+ { value: "left", label: "\uC67C\uCABD" },
1489
+ { value: "center", label: "\uAC00\uC6B4\uB370" },
1490
+ { value: "right", label: "\uC624\uB978\uCABD" }
1491
+ ],
1492
+ group: "appearance"
1493
+ },
1245
1494
  {
1246
1495
  name: "value",
1247
1496
  kind: "node",
@@ -1251,7 +1500,14 @@ var TextMeta = {
1251
1500
  group: "content"
1252
1501
  },
1253
1502
  styleProp,
1254
- classNameProp
1503
+ classNameProp,
1504
+ growProp,
1505
+ shrinkProp,
1506
+ spanProp,
1507
+ selfAlignProp,
1508
+ // Text는 truncate의 주 대상이다 — v2 원본이 truncate 45회 + whitespace-nowrap 15회를
1509
+ // 거의 전부 글자에 걸었다. 폭이 좁아지는 자리(표 셀·목록 행)에서 줄바꿈 대신 …로 자른다.
1510
+ truncateProp
1255
1511
  ],
1256
1512
  children: { accepts: true, text: true, label: "\uD14D\uC2A4\uD2B8" },
1257
1513
  dom: { element: "p", elementProp: "as" },
@@ -3899,12 +4155,33 @@ var StripMeta = {
3899
4155
  icon: "arrow-right",
3900
4156
  description: "\uC790\uC2DD\uC744 \uC904\uBC14\uAFC8 \uC5C6\uC774 \uD55C \uC904\uB85C \uB298\uC5B4\uB193\uACE0 \uAC00\uB85C\uB85C \uC2A4\uD06C\uB864\uD55C\uB2E4. \uCE74\uB4DC \uCE90\uB7EC\uC140 \uAC19\uC740 \uC790\uB9AC\uC5D0 \uC4F4\uB2E4.",
3901
4157
  props: [
4158
+ /*
4159
+ * 자유 CSS 길이에서 DS 간격 척도로 좁혔다.
4160
+ *
4161
+ * `gap`이 공통 어휘로 올라오면서 한 이름이 두 타입을 갖게 됐다 — 다른 컨테이너는
4162
+ * px 척도 문자열("12")인데 여기만 자유 길이("var(--wp-space-3)")라, 속성 패널에서
4163
+ * 같은 이름이 자리마다 다른 입력을 그리게 된다.
4164
+ *
4165
+ * 실사용 4건이 전부 `"var(--wp-space-3)"`(=12px)이고 새 기본값도 12px이라
4166
+ * 값이 무시돼도 화면이 그대로다. 그래도 편집기가 옛 값을 지우지 않도록 legacy 후보로 남긴다.
4167
+ */
3902
4168
  {
3903
4169
  name: "gap",
3904
- kind: "string",
4170
+ kind: "enum",
3905
4171
  label: "\uD56D\uBAA9 \uAC04\uACA9",
3906
- default: "var(--wp-space-3)",
3907
- description: "CSS \uAE38\uC774. \uAC04\uACA9 \uD1A0\uD070(var(--wp-space-N))\uC744 \uC4F0\uB294 \uD3B8\uC774 \uB0AB\uB2E4.",
4172
+ default: "12",
4173
+ description: "DS \uAC04\uACA9 \uCC99\uB3C4(px).",
4174
+ options: [
4175
+ { value: "2", label: "2px" },
4176
+ { value: "4", label: "4px" },
4177
+ { value: "8", label: "8px" },
4178
+ { value: "12", label: "12px" },
4179
+ { value: "16", label: "16px" },
4180
+ { value: "20", label: "20px" },
4181
+ { value: "24", label: "24px" },
4182
+ { value: "32", label: "32px" },
4183
+ { value: "var(--wp-space-3)", label: "12px (\uC61B \uD45C\uAE30)", legacy: true }
4184
+ ],
3908
4185
  group: "layout"
3909
4186
  },
3910
4187
  {
@@ -3920,7 +4197,7 @@ var StripMeta = {
3920
4197
  dom: { element: "div" },
3921
4198
  preset: {
3922
4199
  component: "Strip",
3923
- props: { gap: "var(--wp-space-3)" },
4200
+ props: { gap: "12" },
3924
4201
  children: [
3925
4202
  { component: "Card", props: { title: "\uCE74\uB4DC 1" } },
3926
4203
  { component: "Card", props: { title: "\uCE74\uB4DC 2" } },
package/dist/styles.css CHANGED
@@ -306,10 +306,20 @@
306
306
  .wp-num { font-variant-numeric: tabular-nums; font-size: 12px; color: var(--wp-text-muted); }
307
307
 
308
308
  /* ---------- 레이아웃 프리미티브 ---------- */
309
- .wp-col { display: flex; flex-direction: column; gap: var(--wp-space-4); min-width: 0; }
309
+ /*
310
+ * gap 기본값은 **ERP의 styles/css/layout.css를 정본으로 삼아** 맞춘 값이다.
311
+ * 실측상 두 시트가 같은 클래스에 다른 값을 갖고 있었다 — .wp-col은 여기 16px / ERP 8px,
312
+ * .wp-grid는 여기 16px / ERP 20px(--wp-gutter). ERP가 이 시트를 로드하지 않아서
313
+ * (main.tsx가 자기 styles/index.css만 import한다) 지금까지 사고가 나지 않았을 뿐이다.
314
+ *
315
+ * 어긋난 채로는 메타데이터의 `default`를 적을 수가 없다. 편집기는 프롭 값이 default와
316
+ * 같으면 스펙에서 지우는데, 두 소비자의 실제 기본이 다르면 지운 순간 한쪽 화면이 바뀐다.
317
+ * 화면 85개가 이미 ERP 값으로 그려져 있으므로 그쪽을 정본으로 잡고 이 시트를 옮겼다.
318
+ */
319
+ .wp-col { display: flex; flex-direction: column; gap: var(--wp-space-2); min-width: 0; }
310
320
  .wp-row { display: flex; align-items: center; gap: var(--wp-space-2); min-width: 0; }
311
321
  .wp-row--between { justify-content: space-between; }
312
- .wp-grid { display: grid; gap: var(--wp-space-4); min-width: 0; }
322
+ .wp-grid { display: grid; gap: var(--wp-space-5); min-width: 0; }
313
323
  .wp-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
314
324
  .wp-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
315
325
  .wp-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@@ -1,4 +1,5 @@
1
1
  import React__default from 'react';
2
+ import { f as SduiGapScale } from '../layout-BnYUuWC2.js';
2
3
 
3
4
  /**
4
5
  * Strip — 가로 스크롤 스트립.
@@ -10,8 +11,14 @@ import React__default from 'react';
10
11
 
11
12
  interface StripProps {
12
13
  children: React__default.ReactNode;
13
- /** 항목 간격(CSS 길이). 기본 var(--wp-space-3) */
14
- gap?: string;
14
+ /**
15
+ * 항목 간격 — 간격 척도(px 문자열). 기본 12px.
16
+ *
17
+ * 예전에는 자유 CSS 길이(`'var(--wp-space-3)'`)를 받았다. `gap`이 공통 어휘로 올라오면서
18
+ * 한 이름이 두 타입을 갖게 되어 좁혔다 — 실사용 4건이 전부 `"var(--wp-space-3)"`라
19
+ * `"12"`로 무손실 이관된다. 척도 밖 값은 무시되고 기본값이 남는다.
20
+ */
21
+ gap?: SduiGapScale;
15
22
  /** 항목 시작점에 스크롤 스냅 */
16
23
  snap?: boolean;
17
24
  }
@@ -1 +1,2 @@
1
- export { Strip } from '../chunk-IL2KS4WS.js';
1
+ export { Strip } from '../chunk-PJRXPMI3.js';
2
+ import '../chunk-QBIVW7E6.js';
@@ -40,6 +40,7 @@ export { TreePickerProps } from './TreePicker.js';
40
40
  import { TreeView } from './TreeView.js';
41
41
  export { TreeNode, TreeViewProps } from './TreeView.js';
42
42
  export { AutocompleteField, AutocompleteFieldProps, AutocompleteOption, AutocompleteSearchFn, AutocompleteSearchResult, toAutocompleteOptions } from './AutocompleteField.js';
43
+ import '../layout-BnYUuWC2.js';
43
44
 
44
45
  /**
45
46
  * `createRegistry(widgetComponents)`로 어휘에 얹는 묶음.
@@ -4,8 +4,8 @@ import { SecureScreen } from '../chunk-APCXOCAO.js';
4
4
  export { SecureScreen } from '../chunk-APCXOCAO.js';
5
5
  import { StackedMeter } from '../chunk-7Y4J7EOK.js';
6
6
  export { StackedMeter } from '../chunk-7Y4J7EOK.js';
7
- import { Strip } from '../chunk-IL2KS4WS.js';
8
- export { Strip } from '../chunk-IL2KS4WS.js';
7
+ import { Strip } from '../chunk-PJRXPMI3.js';
8
+ export { Strip } from '../chunk-PJRXPMI3.js';
9
9
  import { SummaryTable } from '../chunk-USKRM22W.js';
10
10
  export { SummaryTable } from '../chunk-USKRM22W.js';
11
11
  import { TagMultiSelect } from '../chunk-4SU2KYPU.js';
@@ -32,6 +32,7 @@ import { PeriodFilter } from '../chunk-DGPRX4MU.js';
32
32
  export { PeriodFilter } from '../chunk-DGPRX4MU.js';
33
33
  import { PrintSheet } from '../chunk-KBHI3IUR.js';
34
34
  export { PrintSheet } from '../chunk-KBHI3IUR.js';
35
+ import '../chunk-QBIVW7E6.js';
35
36
  export { AutocompleteField, toAutocompleteOptions } from '../chunk-MOIU7MUA.js';
36
37
  import '../chunk-KADFN76X.js';
37
38
  import { ColumnBoard } from '../chunk-Q6SBH63R.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipco/sdui",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",
@@ -144,6 +144,7 @@
144
144
  "dev": "tsup --watch",
145
145
  "typecheck": "tsc --noEmit",
146
146
  "check:meta": "node scripts/check-meta.mjs",
147
+ "test": "tsx --test test/*.test.ts",
147
148
  "prepack": "pnpm run build"
148
149
  },
149
150
  "peerDependencies": {
@@ -164,6 +165,7 @@
164
165
  "@types/react": "^19.0.0",
165
166
  "@types/react-dom": "^19.0.0",
166
167
  "tsup": "^8.5.0",
168
+ "tsx": "^4.20.0",
167
169
  "typescript": "^5.7.0"
168
170
  }
169
171
  }