@wipco/sdui 0.18.2 → 0.19.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.
@@ -1,4 +1,5 @@
1
- import { SegmentedControl, Select, Input } from './chunk-WIDDHR7L.js';
1
+ import { DateRangePicker } from './chunk-HPZUPYPK.js';
2
+ import { SegmentedControl, Select } from './chunk-WIDDHR7L.js';
2
3
  import { boxed } from './chunk-SAN4IX6N.js';
3
4
  import { useState, useMemo } from 'react';
4
5
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -142,15 +143,11 @@ function PeriodFilterImpl({ value, onChange, years, modes }) {
142
143
  if (period.year !== void 0 && !base.includes(period.year)) base.push(period.year);
143
144
  return base.sort((a, b) => b - a).map((y) => ({ value: String(y), label: `${y}\uB144` }));
144
145
  }, [years, period.year]);
145
- const handleFromChange = (from) => {
146
- if (!isIsoDate(from)) return;
147
- const to = period.to !== void 0 && period.to >= from ? period.to : from;
148
- emit({ mode: "custom", from, to });
149
- };
150
- const handleToChange = (to) => {
151
- if (!isIsoDate(to)) return;
152
- const from = period.from !== void 0 && period.from <= to ? period.from : to;
153
- emit({ mode: "custom", from, to });
146
+ const handleRangeChange = (next) => {
147
+ const from = next.from ?? next.to;
148
+ const to = next.to ?? next.from;
149
+ if (!isIsoDate(from) || !isIsoDate(to)) return;
150
+ emit({ mode: "custom", from, to: to >= from ? to : from });
154
151
  };
155
152
  return /* @__PURE__ */ jsxs(
156
153
  "div",
@@ -210,7 +207,7 @@ function PeriodFilterImpl({ value, onChange, years, modes }) {
210
207
  onChange: (e) => emit(normalizePeriod({ ...period, month: Number(e.target.value) }))
211
208
  }
212
209
  ) }) : null,
213
- period.mode === "custom" ? /* @__PURE__ */ jsxs(
210
+ period.mode === "custom" ? /* @__PURE__ */ jsx(
214
211
  "span",
215
212
  {
216
213
  style: {
@@ -219,29 +216,13 @@ function PeriodFilterImpl({ value, onChange, years, modes }) {
219
216
  gap: "var(--wp-space-1)",
220
217
  flex: "none"
221
218
  },
222
- children: [
223
- /* @__PURE__ */ jsx("span", { style: { width: 148, flex: "none" }, children: /* @__PURE__ */ jsx(
224
- Input,
225
- {
226
- type: "date",
227
- "aria-label": "\uC2DC\uC791\uC77C",
228
- value: period.from ?? "",
229
- max: period.to,
230
- onChange: (e) => handleFromChange(e.target.value)
231
- }
232
- ) }),
233
- /* @__PURE__ */ jsx("span", { style: { color: "var(--wp-text-subtle)" }, "aria-hidden": true, children: "~" }),
234
- /* @__PURE__ */ jsx("span", { style: { width: 148, flex: "none" }, children: /* @__PURE__ */ jsx(
235
- Input,
236
- {
237
- type: "date",
238
- "aria-label": "\uC885\uB8CC\uC77C",
239
- value: period.to ?? "",
240
- min: period.from,
241
- onChange: (e) => handleToChange(e.target.value)
242
- }
243
- ) })
244
- ]
219
+ children: /* @__PURE__ */ jsx("span", { style: { width: 320, flex: "none" }, children: /* @__PURE__ */ jsx(
220
+ DateRangePicker,
221
+ {
222
+ value: { from: period.from, to: period.to },
223
+ onChange: handleRangeChange
224
+ }
225
+ ) })
245
226
  }
246
227
  ) : null
247
228
  ]
@@ -1,5 +1,5 @@
1
- import { OverlayLayer } from './chunk-XQPTSEJC.js';
2
- import { includesLooseSearch } from './chunk-GZB6YLUI.js';
1
+ import { includesLooseSearch } from './chunk-SUJCS7SU.js';
2
+ import { OverlayLayer } from './chunk-HPZUPYPK.js';
3
3
  import { Button, Dialog, Input, Tag, Checkbox } from './chunk-WIDDHR7L.js';
4
4
  import { boxed } from './chunk-SAN4IX6N.js';
5
5
  import React, { useMemo, useState, useEffect } from 'react';
@@ -1,3 +1,4 @@
1
+ import { useOverlayLayer, DateRangePicker } from './chunk-HPZUPYPK.js';
1
2
  import { Input, Button, IconButton, Tag, Field, Checkbox } from './chunk-WIDDHR7L.js';
2
3
  import { useRef, useEffect, useState, useMemo } from 'react';
3
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -20,16 +21,12 @@ function Popover({
20
21
  if (event.target instanceof Node && hostRef.current?.contains(event.target)) return;
21
22
  closeRef.current();
22
23
  };
23
- const closeOnEscape = (event) => {
24
- if (event.key === "Escape") closeRef.current();
25
- };
26
24
  document.addEventListener("pointerdown", closeOnOutside);
27
- document.addEventListener("keydown", closeOnEscape);
28
25
  return () => {
29
26
  document.removeEventListener("pointerdown", closeOnOutside);
30
- document.removeEventListener("keydown", closeOnEscape);
31
27
  };
32
28
  }, [open]);
29
+ useOverlayLayer(open, () => closeRef.current(), hostRef);
33
30
  return (
34
31
  // 트리거와 패널을 함께 감싸는 기준 상자 — .erp-popover-host의 position:relative가
35
32
  // 패널 absolute의 기준이 된다
@@ -366,27 +363,13 @@ function SearchFieldInput({
366
363
  if (field.type === "dateRange") {
367
364
  const fromKey = field.fromKey ?? `${field.key}From`;
368
365
  const toKey = field.toKey ?? `${field.key}To`;
369
- return /* @__PURE__ */ jsx(Field, { label: field.label, children: /* @__PURE__ */ jsxs("div", { className: "wp-row", children: [
370
- /* @__PURE__ */ jsx(
371
- Input,
372
- {
373
- type: "date",
374
- mono: true,
375
- value: values[fromKey] ?? "",
376
- onChange: (e) => onChange({ [fromKey]: e.target.value })
377
- }
378
- ),
379
- /* @__PURE__ */ jsx("span", { className: "wp-caption", children: "~" }),
380
- /* @__PURE__ */ jsx(
381
- Input,
382
- {
383
- type: "date",
384
- mono: true,
385
- value: values[toKey] ?? "",
386
- onChange: (e) => onChange({ [toKey]: e.target.value })
387
- }
388
- )
389
- ] }) });
366
+ return /* @__PURE__ */ jsx(Field, { label: field.label, children: /* @__PURE__ */ jsx(
367
+ DateRangePicker,
368
+ {
369
+ value: { from: values[fromKey] || void 0, to: values[toKey] || void 0 },
370
+ onChange: (next) => onChange({ [fromKey]: next.from ?? "", [toKey]: next.to ?? "" })
371
+ }
372
+ ) });
390
373
  }
391
374
  if (field.type === "numberRange") {
392
375
  const fromKey = field.fromKey ?? `${field.key}Min`;
@@ -0,0 +1,99 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ // src/adapter.ts
4
+
5
+ // src/env.ts
6
+ var DEV = (() => {
7
+ try {
8
+ const meta = import.meta;
9
+ return Boolean(meta.env?.DEV);
10
+ } catch {
11
+ return false;
12
+ }
13
+ })();
14
+
15
+ // src/adapter.ts
16
+ function isSafeNavigationTarget(to) {
17
+ if (typeof to !== "string") return false;
18
+ const value = to.replace(/[\u0000-\u0020]/g, "");
19
+ if (value === "") return false;
20
+ if (value.startsWith("//")) return false;
21
+ if (value.startsWith("/") || value.startsWith("?") || value.startsWith("#")) return true;
22
+ return /^https?:\/\//i.test(value);
23
+ }
24
+ async function defaultFetch(path, init) {
25
+ const response = await fetch(path, {
26
+ method: init.method,
27
+ headers: { "content-type": "application/json", accept: "application/json" },
28
+ credentials: "include",
29
+ body: init.body === void 0 ? void 0 : JSON.stringify(init.body),
30
+ signal: init.signal
31
+ });
32
+ const text = await response.text();
33
+ let json = null;
34
+ if (text) {
35
+ try {
36
+ json = JSON.parse(text);
37
+ } catch {
38
+ json = null;
39
+ }
40
+ }
41
+ if (!response.ok) {
42
+ const message = json && typeof json === "object" && typeof json.message === "string" ? json.message : `\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4 (${response.status})`;
43
+ throw new Error(message);
44
+ }
45
+ return json;
46
+ }
47
+ var defaultAdapter = {
48
+ navigate: (to) => {
49
+ if (!isSafeNavigationTarget(to)) {
50
+ console.error(`[sdui] \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 navigate \uB300\uC0C1: ${String(to)}`);
51
+ return;
52
+ }
53
+ window.location.assign(to);
54
+ },
55
+ fetch: defaultFetch,
56
+ rawFetch: (path) => fetch(path, { credentials: "include" }),
57
+ // 항등함수. 계약을 문서화하고, 컴포넌트가 `useSduiAssetResolver()`를 조건 없이
58
+ // 부를 수 있게 하는 것이 전부다. **이 함수 참조 자체가 표식**이기도 하다 —
59
+ // `assetResolverOf`가 이것과 같은지 보고 "주입 없음"을 판정한다.
60
+ resolveAsset: (url) => url,
61
+ invalidate: (prefix) => {
62
+ if (DEV) console.warn(`[sdui] invalidate \uC561\uC158\uC774 \uC5B4\uB311\uD130 \uC5C6\uC774 \uD638\uCD9C\uB428 (prefix: ${prefix})`);
63
+ },
64
+ refresh: () => {
65
+ if (DEV) console.warn("[sdui] refresh \uC561\uC158\uC774 \uC5B4\uB311\uD130 \uC5C6\uC774 \uD638\uCD9C\uB428");
66
+ }
67
+ };
68
+ function resolveAdapter(adapter) {
69
+ const merged = { ...defaultAdapter };
70
+ if (adapter) {
71
+ for (const [key, value] of Object.entries(adapter)) {
72
+ if (value !== void 0) merged[key] = value;
73
+ }
74
+ }
75
+ return merged;
76
+ }
77
+ var SduiAdapterContext = createContext(null);
78
+ function useSduiAdapter() {
79
+ return useContext(SduiAdapterContext);
80
+ }
81
+ function assetResolverOf(adapter) {
82
+ const resolve = adapter?.resolveAsset;
83
+ if (!resolve || resolve === defaultAdapter.resolveAsset) return null;
84
+ return resolve;
85
+ }
86
+ function useSduiAssetResolver() {
87
+ const adapter = useContext(SduiAdapterContext);
88
+ return adapter?.resolveAsset ?? defaultAdapter.resolveAsset;
89
+ }
90
+ function useSduiSandbox() {
91
+ return useContext(SduiAdapterContext)?.sandbox === true;
92
+ }
93
+ function hostFetchOf(adapter) {
94
+ const hostFetch = adapter?.fetch;
95
+ if (!hostFetch || hostFetch === defaultAdapter.fetch) return null;
96
+ return hostFetch;
97
+ }
98
+
99
+ export { DEV, SduiAdapterContext, assetResolverOf, defaultAdapter, hostFetchOf, isSafeNavigationTarget, resolveAdapter, useSduiAdapter, useSduiAssetResolver, useSduiSandbox };
@@ -1,5 +1,5 @@
1
- import { resolveTreeNodes, TreeView } from './chunk-PYSTET2C.js';
2
- import { OverlayLayer } from './chunk-XQPTSEJC.js';
1
+ import { resolveTreeNodes, TreeView } from './chunk-BQ5ZGGW7.js';
2
+ import { OverlayLayer } from './chunk-HPZUPYPK.js';
3
3
  import { Field, Dialog, Icon, Button, Input } from './chunk-WIDDHR7L.js';
4
4
  import { boxed } from './chunk-SAN4IX6N.js';
5
5
  import { useState, useMemo, useEffect } from 'react';
@@ -1,4 +1,4 @@
1
- import { includesLooseSearch } from './chunk-GZB6YLUI.js';
1
+ import { includesLooseSearch } from './chunk-SUJCS7SU.js';
2
2
  import { Icon, Button, Input, Spinner } from './chunk-WIDDHR7L.js';
3
3
  import { boxed } from './chunk-SAN4IX6N.js';
4
4
  import { useId, useRef, useState, useEffect, useMemo } from 'react';
package/dist/index.d.ts CHANGED
@@ -4,8 +4,8 @@ import { S as SduiPage, a as SduiAction, b as SduiPropValue, c as SduiRule } fro
4
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
- import { D as DatePickerProps, a as DateRangePickerProps } from './DatePicker-BndreCPl.js';
8
- export { b as DatePicker, c as DateRangePicker, d as DateRangeValue } from './DatePicker-BndreCPl.js';
7
+ import { D as DatePickerProps, a as DateRangePickerProps } from './DatePicker-CPD2cfmG.js';
8
+ export { b as DatePicker, c as DateRangePicker, d as DateRangeValue } from './DatePicker-CPD2cfmG.js';
9
9
 
10
10
  /**
11
11
  * 호스트 앱 연결점 — ERP에서는 라우터·erpFetch·SSE가 하던 일을
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { DEV, HoistedStyle, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, DateRangePicker, DatePicker, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-YJSOC5KM.js';
2
- export { DatePicker, DateRangePicker, defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-YJSOC5KM.js';
1
+ import { DEV, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-WGRB5UL4.js';
2
+ export { defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-WGRB5UL4.js';
3
3
  import { ImageViewer } from './chunk-THEP3VWY.js';
4
4
  export { ImageViewer } from './chunk-THEP3VWY.js';
5
- import { OverlayLayer } from './chunk-XQPTSEJC.js';
6
- export { OverlayContainerContext, OverlayLayer, getOverlayRoot, useOverlayLayer } from './chunk-XQPTSEJC.js';
7
- import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-GZB6YLUI.js';
8
- export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-GZB6YLUI.js';
5
+ import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-SUJCS7SU.js';
6
+ export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-SUJCS7SU.js';
7
+ import { HoistedStyle, DateRangePicker, DatePicker, OverlayLayer } from './chunk-HPZUPYPK.js';
8
+ export { DatePicker, DateRangePicker, OverlayContainerContext, OverlayLayer, getOverlayRoot, useOverlayLayer } from './chunk-HPZUPYPK.js';
9
9
  import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea, Tabs, Table, Switch, StatCard, Input, IconButton, Field, Alert, warnOnce, Dialog } from './chunk-WIDDHR7L.js';
10
10
  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';
11
11
  import { boxed, mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-SAN4IX6N.js';
@@ -403,12 +403,18 @@ function fillTemplate(template, row) {
403
403
  (_match, key) => encodeURIComponent(String(row[key] ?? ""))
404
404
  );
405
405
  }
406
+ var pad2 = (n) => String(n).padStart(2, "0");
407
+ var ymdOf = (date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
408
+ var hmOf = (date) => `${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
409
+ function formatDateCellValue(date) {
410
+ return `${ymdOf(date)} ${hmOf(date)}`;
411
+ }
406
412
  function formatDate(raw, format) {
407
413
  const date = new Date(raw);
408
414
  if (Number.isNaN(date.getTime())) return raw;
409
- if (format === "datetime") return date.toLocaleString("ko-KR");
410
- if (format === "time") return date.toLocaleTimeString("ko-KR");
411
- return date.toLocaleDateString("ko-KR");
415
+ if (format === "datetime") return formatDateCellValue(date);
416
+ if (format === "time") return hmOf(date);
417
+ return ymdOf(date);
412
418
  }
413
419
  function cellRenderer(cell, key, dispatch) {
414
420
  if (!cell || typeof cell !== "object" || typeof cell.type !== "string") return void 0;
@@ -1058,7 +1064,7 @@ function numericValue(value) {
1058
1064
  }
1059
1065
  function formatCell(value) {
1060
1066
  if (value == null) return "";
1061
- if (value instanceof Date) return value.toLocaleString("ko-KR");
1067
+ if (value instanceof Date) return formatDateCellValue(value);
1062
1068
  return value;
1063
1069
  }
1064
1070
  function resolveRowPart(part, item) {
package/dist/meta.js CHANGED
@@ -901,15 +901,23 @@ var DatePickerMeta = {
901
901
  label: "\uB0A0\uC9DC \uC120\uD0DD",
902
902
  category: "input",
903
903
  icon: "calendar",
904
- description: "\uB2E8\uC77C \uB0A0\uC9DC \uC120\uD0DD(YYYY-MM-DD). \uC678\uBD80 \uC758\uC874\uC131 \uC5C6\uB294 \uC790\uCCB4 \uB2EC\uB825\uC774\uB2E4.",
904
+ description: "\uB2E8\uC77C \uB0A0\uC9DC \u2014 \uD0A4\uBCF4\uB4DC\uB85C \uCCD0\uB3C4 \uB418\uACE0 \uB2EC\uB825\uC5D0\uC11C \uACE8\uB77C\uB3C4 \uB41C\uB2E4(YYYY-MM-DD).",
905
905
  props: [
906
906
  { name: "value", kind: "string", label: "\uAC12(YYYY-MM-DD)", bindable: true, group: "data" },
907
907
  { name: "onChange", kind: "action", label: "\uBCC0\uACBD", eventArg: "YYYY-MM-DD \uBB38\uC790\uC5F4", group: "behavior" },
908
908
  { name: "min", kind: "string", label: "\uCD5C\uC18C \uB0A0\uC9DC", description: "YYYY-MM-DD, \uD3EC\uD568", bindable: true, group: "validation" },
909
909
  { name: "max", kind: "string", label: "\uCD5C\uB300 \uB0A0\uC9DC", description: "YYYY-MM-DD, \uD3EC\uD568", bindable: true, group: "validation" },
910
- { name: "placeholder", kind: "string", label: "\uC548\uB0B4 \uBB38\uAD6C", group: "content" },
910
+ { name: "placeholder", kind: "string", label: "\uC548\uB0B4 \uBB38\uAD6C", description: "\uAE30\uBCF8\uAC12\uC740 YYYY-MM-DD", group: "content" },
911
911
  { name: "invalid", kind: "boolean", label: "\uC624\uB958 \uD45C\uC2DC", default: false, bindable: true, group: "validation" },
912
912
  { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" },
913
+ {
914
+ name: "withTime",
915
+ kind: "boolean",
916
+ label: "\uC2DC\uAC01\uAE4C\uC9C0",
917
+ default: false,
918
+ description: "\uAC12\uC774 'YYYY-MM-DDTHH:mm'\uC774 \uB41C\uB2E4 \u2014 \uBE0C\uB77C\uC6B0\uC800 datetime-local\uACFC \uAC19\uC740 \uBAA8\uC591.",
919
+ group: "behavior"
920
+ },
913
921
  {
914
922
  name: "size",
915
923
  kind: "enum",
@@ -928,7 +936,7 @@ var DatePickerMeta = {
928
936
  preset: {
929
937
  component: "DatePicker",
930
938
  props: {
931
- placeholder: "\uB0A0\uC9DC \uC120\uD0DD",
939
+ placeholder: "YYYY-MM-DD",
932
940
  value: { $state: "date", default: "" },
933
941
  onChange: { action: "setState", key: "date", fromEvent: true }
934
942
  }
@@ -940,7 +948,7 @@ var DateRangePickerMeta = {
940
948
  label: "\uAE30\uAC04 \uC120\uD0DD",
941
949
  category: "input",
942
950
  icon: "calendar",
943
- description: "\uC2DC\uC791\xB7\uC885\uB8CC \uB0A0\uC9DC\uB97C \uD55C \uBC88\uC5D0 \uACE0\uB978\uB2E4. \uAC12\uC740 { from, to } \uAC1D\uCCB4\uB2E4.",
951
+ description: "\uC2DC\uC791\xB7\uC885\uB8CC \uB0A0\uC9DC \u2014 \uB450 \uCE78 \uBAA8\uB450 \uD0A4\uBCF4\uB4DC\uB85C \uCE60 \uC218 \uC788\uACE0 \uB2EC\uB825\uC740 \uB450 \uB2EC\uC744 \uD3B8\uB2E4. \uAC12\uC740 { from, to } \uAC1D\uCCB4\uB2E4.",
944
952
  props: [
945
953
  {
946
954
  name: "value",
@@ -950,14 +958,27 @@ var DateRangePickerMeta = {
950
958
  group: "data",
951
959
  fields: [
952
960
  { name: "from", kind: "string", label: "\uC2DC\uC791(YYYY-MM-DD)" },
953
- { name: "to", kind: "string", label: "\uC885\uB8CC(YYYY-MM-DD)" }
961
+ { name: "to", kind: "string", label: "\uC885\uB8CC(YYYY-MM-DD)" },
962
+ { name: "days", kind: "number", label: "\uCD1D \uC77C\uC218(\uC591\uB05D \uD3EC\uD568, \uC704\uC82F\uC774 \uCC44\uC6B4\uB2E4)" }
954
963
  ]
955
964
  },
956
- { name: "onChange", kind: "action", label: "\uBCC0\uACBD", eventArg: "{ from, to } \uAC1D\uCCB4", group: "behavior" },
965
+ { name: "onChange", kind: "action", label: "\uBCC0\uACBD", eventArg: "{ from, to, days } \uAC1D\uCCB4", group: "behavior" },
957
966
  { name: "min", kind: "string", label: "\uCD5C\uC18C \uB0A0\uC9DC", bindable: true, group: "validation" },
958
967
  { name: "max", kind: "string", label: "\uCD5C\uB300 \uB0A0\uC9DC", bindable: true, group: "validation" },
959
968
  { name: "invalid", kind: "boolean", label: "\uC624\uB958 \uD45C\uC2DC", default: false, bindable: true, group: "validation" },
960
- { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" }
969
+ { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" },
970
+ {
971
+ name: "size",
972
+ kind: "enum",
973
+ label: "\uD06C\uAE30",
974
+ default: "md",
975
+ options: [
976
+ { value: "sm", label: "sm 28px" },
977
+ { value: "md", label: "md 32px" },
978
+ { value: "lg", label: "lg 40px" }
979
+ ],
980
+ group: "appearance"
981
+ }
961
982
  ],
962
983
  children: { accepts: false },
963
984
  dom: { element: "div" },
@@ -1199,11 +1220,12 @@ var InputMeta = {
1199
1220
  kind: "enum",
1200
1221
  label: "HTML \uD0C0\uC785",
1201
1222
  default: "text",
1223
+ // 날짜(date·datetime-local)는 일부러 뺐다 — 브라우저가 OS 서식으로 그려서
1224
+ // 같은 화면의 DatePicker와 꼴이 갈린다. 날짜 칸은 DatePicker를 쓴다(0.19.0).
1225
+ description: "\uB0A0\uC9DC\uB294 \uC5EC\uAE30\uAC00 \uC544\uB2C8\uB77C DatePicker\uB85C \u2014 \uBE0C\uB77C\uC6B0\uC800 \uAE30\uBCF8 \uB2EC\uB825\uC740 \uD654\uBA74\uB9C8\uB2E4 \uC11C\uC2DD\uC774 \uAC08\uB9B0\uB2E4.",
1202
1226
  options: [
1203
1227
  { value: "text", label: "\uD14D\uC2A4\uD2B8" },
1204
1228
  { value: "number", label: "\uC22B\uC790" },
1205
- { value: "date", label: "\uB0A0\uC9DC" },
1206
- { value: "datetime-local", label: "\uB0A0\uC9DC+\uC2DC\uAC01" },
1207
1229
  { value: "time", label: "\uC2DC\uAC01" },
1208
1230
  { value: "email", label: "\uC774\uBA54\uC77C" },
1209
1231
  { value: "tel", label: "\uC804\uD654" },
package/dist/rich.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React__default from 'react';
2
- export { b as DatePicker, D as DatePickerProps, c as DateRangePicker, a as DateRangePickerProps, d as DateRangeValue } from './DatePicker-BndreCPl.js';
2
+ export { b as DatePicker, D as DatePickerProps, c as DateRangePicker, a as DateRangePickerProps, d as DateRangeValue } from './DatePicker-CPD2cfmG.js';
3
3
  import './layout-B1QrIBm6.js';
4
4
 
5
5
  /**
package/dist/rich.js CHANGED
@@ -1,6 +1,6 @@
1
- import { useSduiAssetResolver, HoistedStyle } from './chunk-YJSOC5KM.js';
2
- export { DatePicker, DateRangePicker } from './chunk-YJSOC5KM.js';
3
- import './chunk-XQPTSEJC.js';
1
+ import { useSduiAssetResolver } from './chunk-WGRB5UL4.js';
2
+ import { HoistedStyle } from './chunk-HPZUPYPK.js';
3
+ export { DatePicker, DateRangePicker } from './chunk-HPZUPYPK.js';
4
4
  import { Spinner, EmptyState } from './chunk-WIDDHR7L.js';
5
5
  import './chunk-SAN4IX6N.js';
6
6
  import { useRef, useCallback, useMemo, useState, useEffect, useLayoutEffect } from 'react';
@@ -1,4 +1,5 @@
1
- export { AutocompleteField, toAutocompleteOptions } from '../chunk-IXC547V6.js';
2
- import '../chunk-GZB6YLUI.js';
1
+ export { AutocompleteField, toAutocompleteOptions } from '../chunk-ZODL6LE2.js';
2
+ import '../chunk-SUJCS7SU.js';
3
+ import '../chunk-HPZUPYPK.js';
3
4
  import '../chunk-WIDDHR7L.js';
4
5
  import '../chunk-SAN4IX6N.js';
@@ -5,7 +5,7 @@ import { S as SduiBoxProps } from '../layout-B1QrIBm6.js';
5
5
  * PeriodFilter — 복합 기간 선택기.
6
6
  *
7
7
  * - SegmentedControl로 모드(연간/반기/분기/월간/직접)를 고르고,
8
- * 모드에 맞는 Select(연도/반기/분기/월) 또는 날짜 Input(from~to)이 조건부로 나타난다.
8
+ * 모드에 맞는 Select(연도/반기/분기/월) 또는 DateRangePicker(from~to)가 조건부로 나타난다.
9
9
  * - 모드 전환 시 기존 선택을 최대한 보존하며 변환한다
10
10
  * (예: 11월 → 분기 전환 시 4분기, 직접 전환 시 해당 월의 날짜 범위로 프리필).
11
11
  * - 항상 정규화된 Period(해당 모드에 필요한 필드만, 범위 클램프 완료)를 emit한다.
@@ -1,3 +1,4 @@
1
- export { PeriodFilter } from '../chunk-M3TDEPD2.js';
1
+ export { PeriodFilter } from '../chunk-IB4NDAYU.js';
2
+ import '../chunk-HPZUPYPK.js';
2
3
  import '../chunk-WIDDHR7L.js';
3
4
  import '../chunk-SAN4IX6N.js';
@@ -1,5 +1,5 @@
1
- export { SearchableMultiPicker } from '../chunk-WXBOQRD6.js';
2
- import '../chunk-XQPTSEJC.js';
3
- import '../chunk-GZB6YLUI.js';
1
+ export { SearchableMultiPicker } from '../chunk-NXY6QH36.js';
2
+ import '../chunk-SUJCS7SU.js';
3
+ import '../chunk-HPZUPYPK.js';
4
4
  import '../chunk-WIDDHR7L.js';
5
5
  import '../chunk-SAN4IX6N.js';
@@ -1,6 +1,6 @@
1
- export { TreePicker } from '../chunk-J532YYGP.js';
2
- import '../chunk-PYSTET2C.js';
3
- import '../chunk-XQPTSEJC.js';
4
- import '../chunk-GZB6YLUI.js';
1
+ export { TreePicker } from '../chunk-YLYSOOVR.js';
2
+ import '../chunk-BQ5ZGGW7.js';
3
+ import '../chunk-SUJCS7SU.js';
4
+ import '../chunk-HPZUPYPK.js';
5
5
  import '../chunk-WIDDHR7L.js';
6
6
  import '../chunk-SAN4IX6N.js';
@@ -1,4 +1,5 @@
1
- export { TreeView, buildTreeNodes, pruneExcluded, resolveTreeNodes } from '../chunk-PYSTET2C.js';
2
- import '../chunk-GZB6YLUI.js';
1
+ export { TreeView, buildTreeNodes, pruneExcluded, resolveTreeNodes } from '../chunk-BQ5ZGGW7.js';
2
+ import '../chunk-SUJCS7SU.js';
3
+ import '../chunk-HPZUPYPK.js';
3
4
  import '../chunk-WIDDHR7L.js';
4
5
  import '../chunk-SAN4IX6N.js';
@@ -1,5 +1,5 @@
1
- import { SearchableMultiPicker } from '../chunk-WXBOQRD6.js';
2
- export { SearchableMultiPicker } from '../chunk-WXBOQRD6.js';
1
+ import { SearchableMultiPicker } from '../chunk-NXY6QH36.js';
2
+ export { SearchableMultiPicker } from '../chunk-NXY6QH36.js';
3
3
  import { SecureScreen } from '../chunk-IIRENCDS.js';
4
4
  export { SecureScreen } from '../chunk-IIRENCDS.js';
5
5
  import { StackedMeter } from '../chunk-BMZKZGJF.js';
@@ -12,10 +12,10 @@ import { TagMultiSelect } from '../chunk-QDEZXA34.js';
12
12
  export { TagMultiSelect } from '../chunk-QDEZXA34.js';
13
13
  import { Timeline } from '../chunk-EFYEOT47.js';
14
14
  export { Timeline } from '../chunk-EFYEOT47.js';
15
- import { TreePicker } from '../chunk-J532YYGP.js';
16
- export { TreePicker } from '../chunk-J532YYGP.js';
17
- import { TreeView } from '../chunk-PYSTET2C.js';
18
- export { TreeView, buildTreeNodes } from '../chunk-PYSTET2C.js';
15
+ import { TreePicker } from '../chunk-YLYSOOVR.js';
16
+ export { TreePicker } from '../chunk-YLYSOOVR.js';
17
+ import { TreeView } from '../chunk-BQ5ZGGW7.js';
18
+ export { TreeView, buildTreeNodes } from '../chunk-BQ5ZGGW7.js';
19
19
  import { EventCalendar } from '../chunk-C3JY6GA3.js';
20
20
  export { EventCalendar } from '../chunk-C3JY6GA3.js';
21
21
  import { ImageLightbox } from '../chunk-XPBZMECW.js';
@@ -28,14 +28,14 @@ import { LiveClock } from '../chunk-Z3WGIFJP.js';
28
28
  export { LiveClock } from '../chunk-Z3WGIFJP.js';
29
29
  import { OrgChart } from '../chunk-QWJ3OBBL.js';
30
30
  export { OrgChart } from '../chunk-QWJ3OBBL.js';
31
- import { PeriodFilter } from '../chunk-M3TDEPD2.js';
32
- export { PeriodFilter } from '../chunk-M3TDEPD2.js';
31
+ import { PeriodFilter } from '../chunk-IB4NDAYU.js';
32
+ export { PeriodFilter } from '../chunk-IB4NDAYU.js';
33
33
  import { PrintSheet } from '../chunk-MYJ2KEIP.js';
34
34
  export { PrintSheet } from '../chunk-MYJ2KEIP.js';
35
35
  import '../chunk-THEP3VWY.js';
36
- import '../chunk-XQPTSEJC.js';
37
- export { AutocompleteField, toAutocompleteOptions } from '../chunk-IXC547V6.js';
38
- import '../chunk-GZB6YLUI.js';
36
+ export { AutocompleteField, toAutocompleteOptions } from '../chunk-ZODL6LE2.js';
37
+ import '../chunk-SUJCS7SU.js';
38
+ import '../chunk-HPZUPYPK.js';
39
39
  import { ColumnBoard } from '../chunk-C4JRSZGS.js';
40
40
  export { ColumnBoard } from '../chunk-C4JRSZGS.js';
41
41
  import { DiffView } from '../chunk-LDJ2CFFH.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipco/sdui",
3
- "version": "0.18.2",
3
+ "version": "0.19.1",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",