@wipco/sdui 0.18.1 → 0.19.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,5 +1,5 @@
1
- import { OverlayLayer } from './chunk-XQPTSEJC.js';
2
- import { includesLooseSearch } from './chunk-GZB6YLUI.js';
1
+ import { includesLooseSearch } from './chunk-VAXBRGDZ.js';
2
+ import { OverlayLayer } from './chunk-L6HNC4B5.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 { DateRangePicker } from './chunk-L6HNC4B5.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';
@@ -366,27 +367,13 @@ function SearchFieldInput({
366
367
  if (field.type === "dateRange") {
367
368
  const fromKey = field.fromKey ?? `${field.key}From`;
368
369
  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
- ] }) });
370
+ return /* @__PURE__ */ jsx(Field, { label: field.label, children: /* @__PURE__ */ jsx(
371
+ DateRangePicker,
372
+ {
373
+ value: { from: values[fromKey] || void 0, to: values[toKey] || void 0 },
374
+ onChange: (next) => onChange({ [fromKey]: next.from ?? "", [toKey]: next.to ?? "" })
375
+ }
376
+ ) });
390
377
  }
391
378
  if (field.type === "numberRange") {
392
379
  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 };
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-VAXBRGDZ.js';
6
+ export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-VAXBRGDZ.js';
7
+ import { HoistedStyle, DateRangePicker, DatePicker, OverlayLayer } from './chunk-L6HNC4B5.js';
8
+ export { DatePicker, DateRangePicker, OverlayContainerContext, OverlayLayer, getOverlayRoot, useOverlayLayer } from './chunk-L6HNC4B5.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-L6HNC4B5.js';
3
+ export { DatePicker, DateRangePicker } from './chunk-L6HNC4B5.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-3MS4UWWZ.js';
2
- import '../chunk-GZB6YLUI.js';
1
+ export { AutocompleteField, toAutocompleteOptions } from '../chunk-6KGO2PO4.js';
2
+ import '../chunk-VAXBRGDZ.js';
3
+ import '../chunk-L6HNC4B5.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-ACZHPPGA.js';
2
+ import '../chunk-L6HNC4B5.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-LDVPLJ3S.js';
2
+ import '../chunk-VAXBRGDZ.js';
3
+ import '../chunk-L6HNC4B5.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-4IJGZ2TV.js';
2
+ import '../chunk-5H5DSIQW.js';
3
+ import '../chunk-VAXBRGDZ.js';
4
+ import '../chunk-L6HNC4B5.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-5H5DSIQW.js';
2
+ import '../chunk-VAXBRGDZ.js';
3
+ import '../chunk-L6HNC4B5.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-LDVPLJ3S.js';
2
+ export { SearchableMultiPicker } from '../chunk-LDVPLJ3S.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-4IJGZ2TV.js';
16
+ export { TreePicker } from '../chunk-4IJGZ2TV.js';
17
+ import { TreeView } from '../chunk-5H5DSIQW.js';
18
+ export { TreeView, buildTreeNodes } from '../chunk-5H5DSIQW.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-ACZHPPGA.js';
32
+ export { PeriodFilter } from '../chunk-ACZHPPGA.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-3MS4UWWZ.js';
38
- import '../chunk-GZB6YLUI.js';
36
+ export { AutocompleteField, toAutocompleteOptions } from '../chunk-6KGO2PO4.js';
37
+ import '../chunk-VAXBRGDZ.js';
38
+ import '../chunk-L6HNC4B5.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.1",
3
+ "version": "0.19.0",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",
@@ -1,135 +0,0 @@
1
- import React, { useRef, useEffect, useSyncExternalStore } from 'react';
2
- import { createPortal } from 'react-dom';
3
- import { jsx } from 'react/jsx-runtime';
4
-
5
- // src/overlay.tsx
6
- var OVERLAY_ROOT_ID = "wp-overlay-root";
7
- var DOCUMENT_POSITION_FOLLOWING = 4;
8
- function getOverlayRoot() {
9
- if (typeof document === "undefined") return null;
10
- const existing = document.getElementById(OVERLAY_ROOT_ID);
11
- if (existing) return existing;
12
- const created = document.createElement("div");
13
- created.id = OVERLAY_ROOT_ID;
14
- document.body.appendChild(created);
15
- return created;
16
- }
17
- var layers = [];
18
- var nextId = 0;
19
- var subscribers = /* @__PURE__ */ new Set();
20
- var keyListenerBound = false;
21
- function emit() {
22
- layers = layers.slice();
23
- subscribers.forEach((fn) => fn());
24
- }
25
- function topLayer(list) {
26
- let best;
27
- let bestNode = null;
28
- for (const layer of list) {
29
- const node = layer.node();
30
- if (!best) {
31
- best = layer;
32
- bestNode = node;
33
- continue;
34
- }
35
- if (!node) continue;
36
- if (!bestNode) {
37
- best = layer;
38
- bestNode = node;
39
- continue;
40
- }
41
- if (bestNode.compareDocumentPosition(node) & DOCUMENT_POSITION_FOLLOWING) {
42
- best = layer;
43
- bestNode = node;
44
- }
45
- }
46
- return best;
47
- }
48
- function layerHoldsTop(list, id) {
49
- const top = topLayer(list);
50
- if (!top) return false;
51
- if (top.id === id) return true;
52
- const mine = list.find((l) => l.id === id)?.node();
53
- const topNode = top.node();
54
- return !!mine && !!topNode && mine.contains(topNode);
55
- }
56
- function escapeTopmost() {
57
- topLayer(layers)?.onEscape();
58
- }
59
- function handleKeyDown(event) {
60
- if (event.key !== "Escape") return;
61
- escapeTopmost();
62
- }
63
- function push(layer) {
64
- layers.push(layer);
65
- if (!keyListenerBound && typeof document !== "undefined") {
66
- document.addEventListener("keydown", handleKeyDown);
67
- keyListenerBound = true;
68
- }
69
- emit();
70
- }
71
- function remove(id) {
72
- layers = layers.filter((l) => l.id !== id);
73
- emit();
74
- }
75
- function subscribe(fn) {
76
- subscribers.add(fn);
77
- return () => {
78
- subscribers.delete(fn);
79
- };
80
- }
81
- var snapshot = () => layers;
82
- var serverSnapshot = () => [];
83
- function useOverlayLayer(active, onEscape, nodeRef) {
84
- const idRef = useRef(0);
85
- if (idRef.current === 0) idRef.current = ++nextId;
86
- const escapeRef = useRef(onEscape);
87
- escapeRef.current = onEscape;
88
- const nodeRefRef = useRef(nodeRef);
89
- nodeRefRef.current = nodeRef;
90
- useEffect(() => {
91
- if (!active) return;
92
- const id2 = idRef.current;
93
- push({
94
- id: id2,
95
- onEscape: () => escapeRef.current?.(),
96
- node: () => nodeRefRef.current?.current ?? null
97
- });
98
- return () => remove(id2);
99
- }, [active]);
100
- const current = useSyncExternalStore(subscribe, snapshot, serverSnapshot);
101
- const id = idRef.current;
102
- return {
103
- isTop: active && topLayer(current)?.id === id,
104
- holdsTop: active && layerHoldsTop(current, id)
105
- };
106
- }
107
- var OverlayContainerContext = React.createContext(null);
108
- function OverlayLayer({
109
- onClose,
110
- children
111
- }) {
112
- const ref = useRef(null);
113
- const container = React.useContext(OverlayContainerContext);
114
- const { holdsTop } = useOverlayLayer(true, onClose, ref);
115
- useEffect(() => {
116
- ref.current?.toggleAttribute("inert", !holdsTop);
117
- }, [holdsTop]);
118
- const layer = /* @__PURE__ */ jsx(
119
- "div",
120
- {
121
- ref,
122
- className: "wp-overlay-layer",
123
- onClick: (event) => {
124
- if (onClose && event.target instanceof HTMLElement && event.target.classList.contains("wp-overlay")) {
125
- onClose();
126
- }
127
- },
128
- children
129
- }
130
- );
131
- const root = container ?? getOverlayRoot();
132
- return root ? createPortal(layer, root) : layer;
133
- }
134
-
135
- export { OverlayContainerContext, OverlayLayer, getOverlayRoot, useOverlayLayer };