@wipco/sdui 0.31.0 → 0.32.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.
@@ -0,0 +1,122 @@
1
+ import { Text } from './chunk-QO6UJAQN.js';
2
+ import { Switch, Field, Select, Input } from './chunk-WIDDHR7L.js';
3
+ import { boxed } from './chunk-SAN4IX6N.js';
4
+ import React, { useMemo } from 'react';
5
+ import { jsx, jsxs } from 'react/jsx-runtime';
6
+
7
+ function normalizeSchema(schema) {
8
+ if (!Array.isArray(schema)) return [];
9
+ return schema.filter((item) => Boolean(item) && typeof item === "object").filter((item) => typeof item.key === "string" && item.key.trim() !== "");
10
+ }
11
+ function OptionValueFieldsImpl({
12
+ schema,
13
+ value,
14
+ onChange,
15
+ disabled = false,
16
+ readOnly = false
17
+ }) {
18
+ const fields = useMemo(() => normalizeSchema(schema), [schema]);
19
+ const current = useMemo(
20
+ () => value && typeof value === "object" && !Array.isArray(value) ? value : {},
21
+ [value]
22
+ );
23
+ const strays = useMemo(() => {
24
+ const known = new Set(fields.map((field) => field.key));
25
+ return Object.entries(current).filter(([key]) => !known.has(key));
26
+ }, [fields, current]);
27
+ const set = (key, next) => {
28
+ const draft = { ...current };
29
+ if (next === "" || next === void 0 || next === null) delete draft[key];
30
+ else draft[key] = next;
31
+ onChange?.(draft);
32
+ };
33
+ if (readOnly) {
34
+ const filled = fields.filter((field) => {
35
+ const raw = current[field.key];
36
+ return raw !== void 0 && raw !== null && raw !== "";
37
+ });
38
+ if (fields.length === 0 || filled.length === 0) {
39
+ return /* @__PURE__ */ jsx(Text, { preset: "body-sm", style: { color: "var(--wp-text-muted)" }, value: "\u2014" });
40
+ }
41
+ return /* @__PURE__ */ jsx("div", { className: "wp-kv", children: filled.map((field) => {
42
+ const raw = current[field.key];
43
+ const shown = field.type === "boolean" ? raw === true ? "\uC608" : "\uC544\uB2C8\uC624" : `${String(raw)}${field.unit ? ` ${field.unit}` : ""}`;
44
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
45
+ /* @__PURE__ */ jsx("span", { className: "wp-kv__k", children: field.label?.trim() || field.key }),
46
+ /* @__PURE__ */ jsx("span", { className: "wp-kv__v", children: shown })
47
+ ] }, field.key);
48
+ }) });
49
+ }
50
+ if (fields.length === 0) {
51
+ return /* @__PURE__ */ jsx(Text, { preset: "body-sm", style: { color: "var(--wp-text-muted)" }, children: "\uC774 \uC7A5\uBE44\uC5D0 \uC815\uD574 \uB454 \uC635\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC7A5\uBE44 \uC0C1\uC138\uC758 \uC218\uC815 \u2192 \uC635\uC158 \uD0ED\uC5D0\uC11C \uBA3C\uC800 \uC11C\uC2DD\uC744 \uC815\uD558\uC138\uC694." });
52
+ }
53
+ return /* @__PURE__ */ jsxs("div", { className: "wp-col", style: { gap: "var(--wp-space-3)" }, children: [
54
+ fields.map((field) => {
55
+ const label = field.label?.trim() || field.key;
56
+ const raw = current[field.key];
57
+ if (field.type === "boolean") {
58
+ return /* @__PURE__ */ jsxs("div", { className: "wp-row", style: { alignItems: "center", gap: "var(--wp-space-3)" }, children: [
59
+ /* @__PURE__ */ jsx(Text, { preset: "body-sm", style: { flex: 1 }, value: label }),
60
+ /* @__PURE__ */ jsx(
61
+ Switch,
62
+ {
63
+ checked: raw === true,
64
+ disabled,
65
+ onChange: (event) => set(field.key, event.target.checked ? true : void 0)
66
+ }
67
+ )
68
+ ] }, field.key);
69
+ }
70
+ if (field.type === "select") {
71
+ return /* @__PURE__ */ jsx(Field, { label, children: /* @__PURE__ */ jsx(
72
+ Select,
73
+ {
74
+ value: raw === void 0 || raw === null ? "" : String(raw),
75
+ disabled,
76
+ placeholder: "\uC120\uD0DD \uC548 \uD568",
77
+ options: (field.options ?? []).map((option) => ({ value: option, label: option })),
78
+ onChange: (event) => set(field.key, event.target.value)
79
+ }
80
+ ) }, field.key);
81
+ }
82
+ if (field.type === "number") {
83
+ return /* @__PURE__ */ jsx(Field, { label: field.unit ? `${label} (${field.unit})` : label, children: /* @__PURE__ */ jsx(
84
+ Input,
85
+ {
86
+ type: "number",
87
+ value: raw === void 0 || raw === null ? "" : String(raw),
88
+ disabled,
89
+ onChange: (event) => {
90
+ const text = event.target.value;
91
+ if (text === "") return set(field.key, void 0);
92
+ const parsed = Number(text);
93
+ set(field.key, Number.isFinite(parsed) ? parsed : text);
94
+ }
95
+ }
96
+ ) }, field.key);
97
+ }
98
+ return /* @__PURE__ */ jsx(Field, { label, children: /* @__PURE__ */ jsx(
99
+ Input,
100
+ {
101
+ value: raw === void 0 || raw === null ? "" : String(raw),
102
+ disabled,
103
+ onChange: (event) => set(field.key, event.target.value)
104
+ }
105
+ ) }, field.key);
106
+ }),
107
+ strays.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "wp-col", style: { gap: "var(--wp-space-1)" }, children: [
108
+ /* @__PURE__ */ jsx(
109
+ Text,
110
+ {
111
+ preset: "caption",
112
+ value: `\uC11C\uC2DD \uBC16 \uAC12 ${strays.length}\uAC1C \u2014 \uADF8\uB300\uB85C \uBCF4\uAD00\uB429\uB2C8\uB2E4`,
113
+ style: { color: "var(--wp-text-muted)" }
114
+ }
115
+ ),
116
+ strays.map(([key, strayValue]) => /* @__PURE__ */ jsx(Text, { preset: "caption", value: `${key}: ${JSON.stringify(strayValue)}` }, key))
117
+ ] }) : null
118
+ ] });
119
+ }
120
+ var OptionValueFields = boxed(OptionValueFieldsImpl, "OptionValueFields");
121
+
122
+ export { OptionValueFields };
@@ -0,0 +1,124 @@
1
+ import { TimePicker } from './chunk-SNRKPEWT.js';
2
+ import { DatePicker } from './chunk-EFMKWPZ3.js';
3
+ import { Field } from './chunk-WIDDHR7L.js';
4
+ import { boxed } from './chunk-SAN4IX6N.js';
5
+ import { useState, useRef, useEffect, useMemo } from 'react';
6
+ import { jsxs, jsx } from 'react/jsx-runtime';
7
+
8
+ function toHm(value) {
9
+ if (typeof value !== "string") return "";
10
+ const trimmed = value.trim();
11
+ return /^\d{2}:\d{2}/.test(trimmed) ? trimmed.slice(0, 5) : trimmed;
12
+ }
13
+ function toYmd(value) {
14
+ if (typeof value !== "string") return "";
15
+ const trimmed = value.trim();
16
+ return /^\d{4}-\d{2}-\d{2}/.test(trimmed) ? trimmed.slice(0, 10) : trimmed;
17
+ }
18
+ function formFromValue(value) {
19
+ const record = value && typeof value === "object" ? value : {};
20
+ const startDate = toYmd(record.startDate);
21
+ const endDate = toYmd(record.endDate);
22
+ return {
23
+ startDate,
24
+ endDate,
25
+ // 시간은 날짜가 있어야 의미가 있다 — 저장분이 어긋나 있어도 폼에서 정합화.
26
+ startTime: startDate ? toHm(record.startTime) : "",
27
+ endTime: endDate ? toHm(record.endTime) : ""
28
+ };
29
+ }
30
+ function periodError(form) {
31
+ if (form.startDate && form.endDate && form.endDate < form.startDate) {
32
+ return "\uD3C9\uAC00 \uC885\uB8CC\uC77C\uC740 \uC2DC\uC791\uC77C\uBCF4\uB2E4 \uBE60\uB97C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.";
33
+ }
34
+ if (form.startDate && form.endDate && form.startDate === form.endDate && form.startTime && form.endTime && form.endTime <= form.startTime) {
35
+ return "\uC885\uB8CC \uC2DC\uAC04\uC740 \uC2DC\uC791 \uC2DC\uAC04\uBCF4\uB2E4 \uB2A6\uC5B4\uC57C \uD569\uB2C8\uB2E4.";
36
+ }
37
+ return null;
38
+ }
39
+ function envelopeFrom(form) {
40
+ return {
41
+ startDate: form.startDate || null,
42
+ endDate: form.endDate || null,
43
+ startTime: form.startDate && form.startTime || null,
44
+ endTime: form.endDate && form.endTime || null,
45
+ error: periodError(form)
46
+ };
47
+ }
48
+ function StagePeriodEditorImpl({ value, onChange, resetKey, disabled = false }) {
49
+ const [form, setForm] = useState(() => formFromValue(value));
50
+ const seededFor = useRef(resetKey);
51
+ useEffect(() => {
52
+ if (seededFor.current === resetKey) return;
53
+ seededFor.current = resetKey;
54
+ setForm(formFromValue(value));
55
+ }, [resetKey, value]);
56
+ const onChangeRef = useRef(onChange);
57
+ onChangeRef.current = onChange;
58
+ useEffect(() => {
59
+ onChangeRef.current?.(envelopeFrom(form));
60
+ }, [form]);
61
+ const error = useMemo(() => periodError(form), [form]);
62
+ const patch = (partial) => setForm((previous) => ({ ...previous, ...partial }));
63
+ return /* @__PURE__ */ jsxs("div", { className: "wp-col", style: { gap: "var(--wp-space-3)" }, children: [
64
+ /* @__PURE__ */ jsxs(
65
+ "div",
66
+ {
67
+ style: {
68
+ display: "grid",
69
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
70
+ gap: "var(--wp-space-3)"
71
+ },
72
+ children: [
73
+ /* @__PURE__ */ jsx(Field, { label: "\uC2DC\uC791\uC77C", children: /* @__PURE__ */ jsx(
74
+ DatePicker,
75
+ {
76
+ value: form.startDate,
77
+ disabled,
78
+ max: form.endDate || void 0,
79
+ onChange: (next) => patch({
80
+ startDate: next,
81
+ // 시간은 날짜가 있어야 의미가 있으므로 날짜를 지우면 함께 비운다.
82
+ startTime: next ? form.startTime : ""
83
+ })
84
+ }
85
+ ) }),
86
+ /* @__PURE__ */ jsx(Field, { label: "\uC2DC\uC791 \uC2DC\uAC04 (\uC120\uD0DD)", children: /* @__PURE__ */ jsx(
87
+ TimePicker,
88
+ {
89
+ value: form.startTime,
90
+ disabled: disabled || !form.startDate,
91
+ onChange: (next) => patch({ startTime: next })
92
+ }
93
+ ) }),
94
+ /* @__PURE__ */ jsx(Field, { label: "\uC885\uB8CC\uC77C", children: /* @__PURE__ */ jsx(
95
+ DatePicker,
96
+ {
97
+ value: form.endDate,
98
+ disabled,
99
+ min: form.startDate || void 0,
100
+ onChange: (next) => patch({
101
+ endDate: next,
102
+ endTime: next ? form.endTime : ""
103
+ })
104
+ }
105
+ ) }),
106
+ /* @__PURE__ */ jsx(Field, { label: "\uC885\uB8CC \uC2DC\uAC04 (\uC120\uD0DD)", children: /* @__PURE__ */ jsx(
107
+ TimePicker,
108
+ {
109
+ min: form.endDate && form.endDate === form.startDate ? form.startTime || void 0 : void 0,
110
+ value: form.endTime,
111
+ disabled: disabled || !form.endDate,
112
+ onChange: (next) => patch({ endTime: next })
113
+ }
114
+ ) })
115
+ ]
116
+ }
117
+ ),
118
+ error ? /* @__PURE__ */ jsx("span", { className: "wp-caption", style: { color: "var(--wp-text-danger)" }, children: error }) : null,
119
+ /* @__PURE__ */ jsx("span", { className: "wp-caption", style: { color: "var(--wp-text-muted)" }, children: "\uB2E8\uACC4 \uAE30\uAC04\uC744 \uB530\uB85C \uC815\uD558\uC9C0 \uC54A\uC73C\uBA74 \uD68C\uCC28 \uAE30\uAC04\uC744 \uB530\uB985\uB2C8\uB2E4. \uD68C\uCC28 \uAE30\uAC04\uC744 \uBC14\uAFB8\uBA74 \uD68C\uCC28 \uAE30\uAC04\uC744 \uB530\uB974\uB358 \uB2E8\uACC4\uB9CC \uD568\uAED8 \uBC14\uB01D\uB2C8\uB2E4." })
120
+ ] });
121
+ }
122
+ var StagePeriodEditor = boxed(StagePeriodEditorImpl, "StagePeriodEditor");
123
+
124
+ export { StagePeriodEditor };
@@ -0,0 +1,145 @@
1
+ import { mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle } from './chunk-SAN4IX6N.js';
2
+ import React from 'react';
3
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
+
5
+ function paddingStyle(padding) {
6
+ const value = padding === void 0 ? void 0 : PADDING_CSS[padding];
7
+ return value === void 0 ? {} : { padding: value };
8
+ }
9
+ var PADDING_CSS = {
10
+ "2": "2px",
11
+ "4": "4px",
12
+ "8": "8px",
13
+ "12": "12px",
14
+ "16": "16px",
15
+ "20": "20px",
16
+ "24": "24px",
17
+ "32": "32px"
18
+ };
19
+ function Grid({
20
+ columns = 3,
21
+ template,
22
+ gap,
23
+ align,
24
+ justify,
25
+ wrap,
26
+ padding,
27
+ className,
28
+ style,
29
+ children
30
+ }) {
31
+ return /* @__PURE__ */ jsx(
32
+ "div",
33
+ {
34
+ className: joinClass("wp-grid", !template && columnsClass(columns), className),
35
+ style: mergeStyle(
36
+ {
37
+ ...template ? { gridTemplateColumns: template } : null,
38
+ ...containerLayoutStyle({ gap, align, justify, wrap }),
39
+ ...paddingStyle(padding)
40
+ },
41
+ style
42
+ ),
43
+ children
44
+ }
45
+ );
46
+ }
47
+ function Row({ justify, gap, align, wrap, className, style, children }) {
48
+ return /* @__PURE__ */ jsx(
49
+ "div",
50
+ {
51
+ className: joinClass("wp-row", justify === "between" && "wp-row--between", className),
52
+ style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style),
53
+ children
54
+ }
55
+ );
56
+ }
57
+ function Actions({ justify = "end", gap, align, wrap, className, style, children }) {
58
+ return /* @__PURE__ */ jsx(
59
+ "div",
60
+ {
61
+ className: joinClass("wp-row", className),
62
+ style: mergeStyle({ flex: 1, ...containerLayoutStyle({ gap, align, justify, wrap }) }, style),
63
+ children
64
+ }
65
+ );
66
+ }
67
+ function Col({ gap, align, justify, wrap, className, style, children }) {
68
+ return /* @__PURE__ */ jsx("div", { className: joinClass("wp-col", className), style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style), children });
69
+ }
70
+ var SPACER_STEPS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 6, 8]);
71
+ function Spacer({ size, className, style }) {
72
+ const step = size !== void 0 && SPACER_STEPS.has(Number(size)) ? Number(size) : void 0;
73
+ return /* @__PURE__ */ jsx(
74
+ "div",
75
+ {
76
+ className: joinClass("wp-spacer", step !== void 0 && `wp-spacer--${step}`, className),
77
+ style
78
+ }
79
+ );
80
+ }
81
+ function Section({ title, gap, align, justify, wrap, className, style, children }) {
82
+ return /* @__PURE__ */ jsxs(
83
+ "section",
84
+ {
85
+ className: joinClass("wp-col", className),
86
+ style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style),
87
+ children: [
88
+ title ? /* @__PURE__ */ jsx("h2", { className: "wp-h4", children: title }) : null,
89
+ children
90
+ ]
91
+ }
92
+ );
93
+ }
94
+ var TEXT_WRAP_CSS = {
95
+ normal: {},
96
+ preserve: { whiteSpace: "pre-wrap" },
97
+ anywhere: { whiteSpace: "pre-wrap", wordBreak: "break-all" }
98
+ };
99
+ function Text({
100
+ preset = "body",
101
+ as: Tag = "p",
102
+ weight,
103
+ textAlign,
104
+ wrap,
105
+ className,
106
+ style,
107
+ value,
108
+ children
109
+ }) {
110
+ return /* @__PURE__ */ jsx(
111
+ Tag,
112
+ {
113
+ className: joinClass(`wp-${preset}`, className),
114
+ style: mergeStyle({ ...typographyStyle({ weight, textAlign }), ...TEXT_WRAP_CSS[wrap ?? "normal"] }, style),
115
+ children: value ?? children
116
+ }
117
+ );
118
+ }
119
+ function KeyValueList({ source, items, className, style }) {
120
+ return /* @__PURE__ */ jsx("div", { className: joinClass("wp-kv", className), style, children: (items ?? []).map((item, index) => {
121
+ const raw = item.key ? source?.[item.key] : item.value;
122
+ const content = raw === null || raw === void 0 || raw === "" ? "\u2014" : raw;
123
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
124
+ /* @__PURE__ */ jsx("span", { className: "wp-kv__k", children: item.label }),
125
+ /* @__PURE__ */ jsx("span", { className: joinClass("wp-kv__v", item.mono && "wp-mono"), children: content })
126
+ ] }, index);
127
+ }) });
128
+ }
129
+ function PageHead({ title, subtitle, actions, className, style }) {
130
+ return /* @__PURE__ */ jsxs("div", { className: joinClass("wp-page-head", className), style, children: [
131
+ /* @__PURE__ */ jsxs("div", { className: "wp-page-head__text", children: [
132
+ title ? /* @__PURE__ */ jsx("h1", { className: "wp-page-head__title", children: title }) : null,
133
+ subtitle ? /* @__PURE__ */ jsx("div", { className: "wp-page-head__sub", children: subtitle }) : null
134
+ ] }),
135
+ actions ? /* @__PURE__ */ jsx("div", { className: "wp-page-head__actions", children: actions }) : null
136
+ ] });
137
+ }
138
+ function Show({ when, children }) {
139
+ return when ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
140
+ }
141
+ function Divider({ style, className }) {
142
+ return /* @__PURE__ */ jsx("hr", { className: joinClass("wp-divider", className), style });
143
+ }
144
+
145
+ export { Actions, Col, Divider, Grid, KeyValueList, PageHead, Row, Section, Show, Spacer, Text };
@@ -0,0 +1,140 @@
1
+ import { Text } from './chunk-QO6UJAQN.js';
2
+ import { Field, Input, Select, IconButton, Button } from './chunk-WIDDHR7L.js';
3
+ import { boxed } from './chunk-SAN4IX6N.js';
4
+ import { useMemo } from 'react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ var OPTION_TYPES = [
8
+ { value: "text", label: "\uBB38\uC790\uC5F4" },
9
+ { value: "number", label: "\uC22B\uC790" },
10
+ { value: "select", label: "\uC120\uD0DD" },
11
+ { value: "boolean", label: "\uC608/\uC544\uB2C8\uC624" }
12
+ ];
13
+ function normalize(value) {
14
+ if (!Array.isArray(value)) return [];
15
+ return value.filter((item) => Boolean(item) && typeof item === "object").map((item) => ({
16
+ key: typeof item.key === "string" ? item.key : "",
17
+ label: typeof item.label === "string" ? item.label : void 0,
18
+ type: OPTION_TYPES.some((t) => t.value === item.type) ? item.type : "text",
19
+ options: Array.isArray(item.options) ? item.options.map((o) => String(o)) : void 0,
20
+ unit: typeof item.unit === "string" ? item.unit : void 0
21
+ }));
22
+ }
23
+ function OptionSchemaEditorImpl({ value, onChange, disabled = false }) {
24
+ const config = useMemo(
25
+ () => value && typeof value === "object" && !Array.isArray(value) ? value : {},
26
+ [value]
27
+ );
28
+ const fields = useMemo(() => normalize(config.options), [config.options]);
29
+ const duplicates = useMemo(() => {
30
+ const seen = /* @__PURE__ */ new Map();
31
+ for (const field of fields) {
32
+ const key = field.key.trim();
33
+ if (!key) continue;
34
+ seen.set(key, (seen.get(key) ?? 0) + 1);
35
+ }
36
+ return new Set([...seen.entries()].filter(([, count]) => count > 1).map(([key]) => key));
37
+ }, [fields]);
38
+ const emit = (next) => onChange?.({ ...config, options: next });
39
+ const patch = (index, change) => emit(fields.map((field, i) => i === index ? { ...field, ...change } : field));
40
+ return /* @__PURE__ */ jsxs("div", { className: "wp-col", style: { gap: "var(--wp-space-3)" }, children: [
41
+ fields.length === 0 ? /* @__PURE__ */ jsx(Text, { preset: "body-sm", style: { color: "var(--wp-text-muted)" }, children: "\uC544\uC9C1 \uC635\uC158\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC5EC\uAE30\uC5D0 \uC815\uD574 \uB450\uBA74 \uC774 \uC7A5\uBE44\uC758 \uC720\uB2DB\uC744 \uC218\uC815\uD560 \uB54C \uADF8 \uC11C\uC2DD\uB300\uB85C \uCE78\uC774 \uB739\uB2C8\uB2E4." }) : null,
42
+ fields.map((field, index) => {
43
+ const duplicated = Boolean(field.key.trim()) && duplicates.has(field.key.trim());
44
+ return /* @__PURE__ */ jsxs(
45
+ "div",
46
+ {
47
+ className: "wp-row",
48
+ style: { gap: "var(--wp-space-2)", alignItems: "flex-start" },
49
+ children: [
50
+ /* @__PURE__ */ jsx(
51
+ Field,
52
+ {
53
+ label: index === 0 ? "\uC774\uB984(\uD0A4)" : void 0,
54
+ error: !field.key.trim() ? "\uC774\uB984\uC740 \uBE44\uC6B8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" : duplicated ? "\uC774\uB984\uC774 \uACB9\uCE69\uB2C8\uB2E4" : void 0,
55
+ style: { flex: 1.2 },
56
+ children: /* @__PURE__ */ jsx(
57
+ Input,
58
+ {
59
+ value: field.key,
60
+ placeholder: "CPU",
61
+ disabled,
62
+ invalid: !field.key.trim() || duplicated,
63
+ onChange: (event) => patch(index, { key: event.target.value })
64
+ }
65
+ )
66
+ }
67
+ ),
68
+ /* @__PURE__ */ jsx(Field, { label: index === 0 ? "\uD45C\uC2DC \uC774\uB984" : void 0, style: { flex: 1.2 }, children: /* @__PURE__ */ jsx(
69
+ Input,
70
+ {
71
+ value: field.label ?? "",
72
+ placeholder: field.key || "\uBE44\uC6B0\uBA74 \uC774\uB984 \uADF8\uB300\uB85C",
73
+ disabled,
74
+ onChange: (event) => patch(index, { label: event.target.value || void 0 })
75
+ }
76
+ ) }),
77
+ /* @__PURE__ */ jsx(Field, { label: index === 0 ? "\uD615\uC2DD" : void 0, style: { flex: 1 }, children: /* @__PURE__ */ jsx(
78
+ Select,
79
+ {
80
+ value: field.type,
81
+ disabled,
82
+ options: OPTION_TYPES,
83
+ onChange: (event) => patch(index, {
84
+ type: event.target.value,
85
+ // 선택이 아니면 선택지는 의미가 없다 — 남겨 두면 다시 선택으로 바꿨을 때 옛 값이 살아난다
86
+ options: event.target.value === "select" ? field.options ?? [] : void 0
87
+ })
88
+ }
89
+ ) }),
90
+ field.type === "select" ? /* @__PURE__ */ jsx(Field, { label: index === 0 ? "\uC120\uD0DD\uC9C0(\uC27C\uD45C\uB85C \uAD6C\uBD84)" : void 0, style: { flex: 1.6 }, children: /* @__PURE__ */ jsx(
91
+ Input,
92
+ {
93
+ value: (field.options ?? []).join(", "),
94
+ placeholder: "8GB, 16GB, 32GB",
95
+ disabled,
96
+ onChange: (event) => patch(index, {
97
+ options: event.target.value.split(",").map((option) => option.trim()).filter(Boolean)
98
+ })
99
+ }
100
+ ) }) : null,
101
+ field.type === "number" ? /* @__PURE__ */ jsx(Field, { label: index === 0 ? "\uB2E8\uC704" : void 0, style: { flex: 0.7 }, children: /* @__PURE__ */ jsx(
102
+ Input,
103
+ {
104
+ value: field.unit ?? "",
105
+ placeholder: "GB",
106
+ disabled,
107
+ onChange: (event) => patch(index, { unit: event.target.value || void 0 })
108
+ }
109
+ ) }) : null,
110
+ /* @__PURE__ */ jsx("div", { style: { paddingTop: index === 0 ? 22 : 0, flex: "none" }, children: /* @__PURE__ */ jsx(
111
+ IconButton,
112
+ {
113
+ icon: "trash-2",
114
+ label: `${field.label || field.key || index + 1} \uC0AD\uC81C`,
115
+ variant: "ghost",
116
+ disabled,
117
+ onClick: () => emit(fields.filter((_, i) => i !== index))
118
+ }
119
+ ) })
120
+ ]
121
+ },
122
+ index
123
+ );
124
+ }),
125
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
126
+ Button,
127
+ {
128
+ size: "sm",
129
+ variant: "secondary",
130
+ icon: "plus",
131
+ disabled,
132
+ onClick: () => emit([...fields, { key: "", type: "text" }]),
133
+ children: "\uC635\uC158 \uCD94\uAC00"
134
+ }
135
+ ) })
136
+ ] });
137
+ }
138
+ var OptionSchemaEditor = boxed(OptionSchemaEditorImpl, "OptionSchemaEditor");
139
+
140
+ export { OPTION_TYPES, OptionSchemaEditor };
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
- import { TimePicker } from './chunk-SNRKPEWT.js';
2
- export { TimePicker } from './chunk-SNRKPEWT.js';
3
1
  export { loadOptionalModule } from './chunk-RRMKCZYQ.js';
4
2
  import { useSduiDispatch, SduiDialog, useSduiCan, SduiDispatchContext, SduiPermissionProvider } from './chunk-QU7YVMFA.js';
5
3
  export { SduiDialog, SduiPermissionProvider, useSduiCan, useSduiDispatch } from './chunk-QU7YVMFA.js';
4
+ import { Text, Spacer, Show, Section, Row, PageHead, KeyValueList, Grid, Divider, Col, Actions } from './chunk-QO6UJAQN.js';
5
+ export { Actions, Col, Divider, Grid, KeyValueList, PageHead, Row, Section, Show, Spacer, Text } from './chunk-QO6UJAQN.js';
6
6
  import { ImageViewer } from './chunk-THEP3VWY.js';
7
7
  export { ImageViewer } from './chunk-THEP3VWY.js';
8
+ import { TimePicker } from './chunk-SNRKPEWT.js';
9
+ export { TimePicker } from './chunk-SNRKPEWT.js';
8
10
  import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-BD75U73S.js';
9
11
  export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-BD75U73S.js';
10
12
  import { HoistedStyle, DateRangePicker, DatePicker } from './chunk-EFMKWPZ3.js';
@@ -14,9 +16,9 @@ import { DEV, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, useSduiSandbo
14
16
  export { defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-DKPNFEVU.js';
15
17
  import { EmptyState, Button, Checkbox, SegmentedControl, Spinner, Select, Pagination, Icon, Card, Badge, ProgressBar, Tag, Toast, Textarea, Tabs, Table, Switch, StatCard, Input, IconButton, Field, Alert, warnOnce } from './chunk-WIDDHR7L.js';
16
18
  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';
17
- import { boxed, mergeStyle, containerLayoutStyle, joinClass, columnsClass, typographyStyle, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-SAN4IX6N.js';
19
+ import { boxed, LAYOUT_CSS, childLayoutFrom, CHILD_LAYOUT_PROPS } from './chunk-SAN4IX6N.js';
18
20
  export { CHILD_LAYOUT_PROPS, LAYOUT_CSS, boxed, childLayoutFrom, columnsClass, containerLayoutStyle, joinClass, mergeStyle, typographyStyle } from './chunk-SAN4IX6N.js';
19
- import React10, { createContext, useState, useMemo, useRef, useEffect, useCallback, useContext } from 'react';
21
+ import React9, { createContext, useState, useMemo, useRef, useEffect, useCallback, useContext } from 'react';
20
22
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
21
23
 
22
24
  // src/asset-url.ts
@@ -113,7 +115,7 @@ function resolveAssetsIn(propName, value, resolve, component) {
113
115
  return out ?? record;
114
116
  }
115
117
  }
116
- var NodeErrorBoundary = class extends React10.Component {
118
+ var NodeErrorBoundary = class extends React9.Component {
117
119
  state = { error: null };
118
120
  static getDerivedStateFromError(error) {
119
121
  return { error };
@@ -161,145 +163,6 @@ function Can({ entity, action = "read", scope, fallback = null, children }) {
161
163
  }
162
164
  return can({ entity, action: typeof action === "string" ? action : "read", scope }) ? /* @__PURE__ */ jsx(Fragment, { children }) : /* @__PURE__ */ jsx(Fragment, { children: fallback });
163
165
  }
164
- function paddingStyle(padding) {
165
- const value = padding === void 0 ? void 0 : PADDING_CSS[padding];
166
- return value === void 0 ? {} : { padding: value };
167
- }
168
- var PADDING_CSS = {
169
- "2": "2px",
170
- "4": "4px",
171
- "8": "8px",
172
- "12": "12px",
173
- "16": "16px",
174
- "20": "20px",
175
- "24": "24px",
176
- "32": "32px"
177
- };
178
- function Grid({
179
- columns = 3,
180
- template,
181
- gap,
182
- align,
183
- justify,
184
- wrap,
185
- padding,
186
- className,
187
- style,
188
- children
189
- }) {
190
- return /* @__PURE__ */ jsx(
191
- "div",
192
- {
193
- className: joinClass("wp-grid", !template && columnsClass(columns), className),
194
- style: mergeStyle(
195
- {
196
- ...template ? { gridTemplateColumns: template } : null,
197
- ...containerLayoutStyle({ gap, align, justify, wrap }),
198
- ...paddingStyle(padding)
199
- },
200
- style
201
- ),
202
- children
203
- }
204
- );
205
- }
206
- function Row({ justify, gap, align, wrap, className, style, children }) {
207
- return /* @__PURE__ */ jsx(
208
- "div",
209
- {
210
- className: joinClass("wp-row", justify === "between" && "wp-row--between", className),
211
- style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style),
212
- children
213
- }
214
- );
215
- }
216
- function Actions({ justify = "end", gap, align, wrap, className, style, children }) {
217
- return /* @__PURE__ */ jsx(
218
- "div",
219
- {
220
- className: joinClass("wp-row", className),
221
- style: mergeStyle({ flex: 1, ...containerLayoutStyle({ gap, align, justify, wrap }) }, style),
222
- children
223
- }
224
- );
225
- }
226
- function Col({ gap, align, justify, wrap, className, style, children }) {
227
- return /* @__PURE__ */ jsx("div", { className: joinClass("wp-col", className), style: mergeStyle(containerLayoutStyle({ gap, align, justify, wrap }), style), children });
228
- }
229
- var SPACER_STEPS = /* @__PURE__ */ new Set([1, 2, 3, 4, 5, 6, 8]);
230
- function Spacer({ size, className, style }) {
231
- const step = size !== void 0 && SPACER_STEPS.has(Number(size)) ? Number(size) : void 0;
232
- return /* @__PURE__ */ jsx(
233
- "div",
234
- {
235
- className: joinClass("wp-spacer", step !== void 0 && `wp-spacer--${step}`, className),
236
- style
237
- }
238
- );
239
- }
240
- function Section({ title, gap, align, justify, wrap, className, style, children }) {
241
- return /* @__PURE__ */ jsxs(
242
- "section",
243
- {
244
- className: joinClass("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
- );
252
- }
253
- var TEXT_WRAP_CSS = {
254
- normal: {},
255
- preserve: { whiteSpace: "pre-wrap" },
256
- anywhere: { whiteSpace: "pre-wrap", wordBreak: "break-all" }
257
- };
258
- function Text({
259
- preset = "body",
260
- as: Tag2 = "p",
261
- weight,
262
- textAlign,
263
- wrap,
264
- className,
265
- style,
266
- value,
267
- children
268
- }) {
269
- return /* @__PURE__ */ jsx(
270
- Tag2,
271
- {
272
- className: joinClass(`wp-${preset}`, className),
273
- style: mergeStyle({ ...typographyStyle({ weight, textAlign }), ...TEXT_WRAP_CSS[wrap ?? "normal"] }, style),
274
- children: value ?? children
275
- }
276
- );
277
- }
278
- function KeyValueList({ source, items, className, style }) {
279
- return /* @__PURE__ */ jsx("div", { className: joinClass("wp-kv", className), style, children: (items ?? []).map((item, index) => {
280
- const raw = item.key ? source?.[item.key] : item.value;
281
- const content = raw === null || raw === void 0 || raw === "" ? "\u2014" : raw;
282
- return /* @__PURE__ */ jsxs(React10.Fragment, { children: [
283
- /* @__PURE__ */ jsx("span", { className: "wp-kv__k", children: item.label }),
284
- /* @__PURE__ */ jsx("span", { className: joinClass("wp-kv__v", item.mono && "wp-mono"), children: content })
285
- ] }, index);
286
- }) });
287
- }
288
- function PageHead({ title, subtitle, actions, className, style }) {
289
- return /* @__PURE__ */ jsxs("div", { className: joinClass("wp-page-head", className), style, children: [
290
- /* @__PURE__ */ jsxs("div", { className: "wp-page-head__text", children: [
291
- title ? /* @__PURE__ */ jsx("h1", { className: "wp-page-head__title", children: title }) : null,
292
- subtitle ? /* @__PURE__ */ jsx("div", { className: "wp-page-head__sub", children: subtitle }) : null
293
- ] }),
294
- actions ? /* @__PURE__ */ jsx("div", { className: "wp-page-head__actions", children: actions }) : null
295
- ] });
296
- }
297
- function Show({ when, children }) {
298
- return when ? /* @__PURE__ */ jsx(Fragment, { children }) : null;
299
- }
300
- function Divider({ style, className }) {
301
- return /* @__PURE__ */ jsx("hr", { className: joinClass("wp-divider", className), style });
302
- }
303
166
  function imageRenderer(cell, key, width = cell.width ?? 72) {
304
167
  const height = cell.height ?? 52;
305
168
  return (row) => /* @__PURE__ */ jsx(
@@ -2640,7 +2503,7 @@ function SduiNodeRenderer({
2640
2503
  return /* @__PURE__ */ jsx(Fragment, { children: rows.map((item, rowIndex) => {
2641
2504
  const rowScope = [...scope, { item, index: rowIndex }];
2642
2505
  const rowKey = isPlainObject4(item) && typeof item.id === "string" ? item.id : rowIndex;
2643
- return /* @__PURE__ */ jsx(React10.Fragment, { children: childList?.map((child, i) => renderChild(child, i, rowScope, engine)) }, rowKey);
2506
+ return /* @__PURE__ */ jsx(React9.Fragment, { children: childList?.map((child, i) => renderChild(child, i, rowScope, engine)) }, rowKey);
2644
2507
  }) });
2645
2508
  }
2646
2509
  if (node.component === "Fragment") {
@@ -2716,11 +2579,11 @@ function SduiNodeRenderer({
2716
2579
  const children = childList?.map((child, i) => renderChild(child, i, scope, engine));
2717
2580
  return /* @__PURE__ */ jsx(Component, { ...props, children });
2718
2581
  }
2719
- var SduiFragmentChainContext = React10.createContext([]);
2582
+ var SduiFragmentChainContext = React9.createContext([]);
2720
2583
  var FRAGMENT_MAX_DEPTH = 4;
2721
2584
  function SduiFragment({ node, scope, engine }) {
2722
2585
  const adapter = useSduiAdapter();
2723
- const chain = React10.useContext(SduiFragmentChainContext);
2586
+ const chain = React9.useContext(SduiFragmentChainContext);
2724
2587
  const raw = isPlainObject4(node.props) ? node.props.id : void 0;
2725
2588
  const id = engine.resolveValue(raw, scope);
2726
2589
  if (typeof id !== "string" || id === "") {
@@ -2775,9 +2638,9 @@ function SduiFragmentBody({
2775
2638
  engine
2776
2639
  }) {
2777
2640
  const spec = useSpec(id);
2778
- const nextChain = React10.useMemo(() => [...chain, id], [chain, id]);
2779
- const bodyScope = React10.useMemo(() => [...scope, { args, callSiteScope: scope }], [scope, args]);
2780
- React10.useEffect(() => {
2641
+ const nextChain = React9.useMemo(() => [...chain, id], [chain, id]);
2642
+ const bodyScope = React9.useMemo(() => [...scope, { args, callSiteScope: scope }], [scope, args]);
2643
+ React9.useEffect(() => {
2781
2644
  if (!DEV || !isPlainObject4(spec) || !Array.isArray(spec.body)) return;
2782
2645
  validateSpec(spec, new Set(Object.keys(engine.registry))).forEach(
2783
2646
  (issue) => console.warn(`[sdui:spec:${id}] ${issue.path} \u2014 ${issue.message}`)
@@ -3268,4 +3131,4 @@ function SduiRenderer({
3268
3131
  );
3269
3132
  }
3270
3133
 
3271
- export { Actions, CALC_OPS, Can, Col, Divider, Grid, KeyValueList, NodeErrorBoundary, PageHead, RemoteSearchResults, ResultTable, Row, SduiForm, SduiRenderer, SduiSearchDataProvider, SduiSearchResults, SearchResults, Section, Show, SortHandle, SortableList, Spacer, Text, cellRenderer, createRegistry, defaultRegistry, imageRenderer, normalizePageSizes, sortableDropIndex, sortableMove, useRemoteSearchPage, useSduiRuntime, useSearchFetcher, validateSpec };
3134
+ export { CALC_OPS, Can, NodeErrorBoundary, RemoteSearchResults, ResultTable, SduiForm, SduiRenderer, SduiSearchDataProvider, SduiSearchResults, SearchResults, SortHandle, SortableList, cellRenderer, createRegistry, defaultRegistry, imageRenderer, normalizePageSizes, sortableDropIndex, sortableMove, useRemoteSearchPage, useSduiRuntime, useSearchFetcher, validateSpec };
package/dist/meta.d.ts CHANGED
@@ -432,6 +432,9 @@ declare const PermissionMatrixEditorMeta: SduiComponentMeta;
432
432
  declare const RoleMemberPickerMeta: SduiComponentMeta;
433
433
  declare const FileDropzoneMeta: SduiComponentMeta;
434
434
  declare const ExcelUploadCardMeta: SduiComponentMeta;
435
+ declare const OptionSchemaEditorMeta: SduiComponentMeta;
436
+ declare const OptionValueFieldsMeta: SduiComponentMeta;
437
+ declare const StagePeriodEditorMeta: SduiComponentMeta;
435
438
  declare const AutocompleteFieldMeta: SduiComponentMeta;
436
439
  declare const InlineEditMeta: SduiComponentMeta;
437
440
  declare const JsonFieldMeta: SduiComponentMeta;
@@ -468,6 +471,9 @@ declare const widgetComponentMeta: {
468
471
  ApprovalLineEditor: SduiComponentMeta;
469
472
  ApprovalOverridesEditor: SduiComponentMeta;
470
473
  ApprovalStepper: SduiComponentMeta;
474
+ OptionSchemaEditor: SduiComponentMeta;
475
+ OptionValueFields: SduiComponentMeta;
476
+ StagePeriodEditor: SduiComponentMeta;
471
477
  ExcelUploadCard: SduiComponentMeta;
472
478
  FileDropzone: SduiComponentMeta;
473
479
  PermissionMatrixEditor: SduiComponentMeta;
@@ -606,4 +612,4 @@ declare function paletteGroups(catalog?: Record<string, SduiComponentMeta>): Arr
606
612
  items: SduiComponentMeta[];
607
613
  }>;
608
614
 
609
- export { ActionsMeta, AlertMeta, ApprovalLineEditorMeta, ApprovalOverridesEditorMeta, ApprovalStepperMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, ExcelUploadCardMeta, FieldMeta, FileDropzoneMeta, ForEachMeta, FormMeta, FragmentMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OrgChartBoardMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PermissionMatrixEditorMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RankBoardMeta, RecordSheetMeta, RemoteSearchResultsMeta, RoleMemberPickerMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, type SduiCategory, type SduiChildrenMeta, type SduiComponentMeta, type SduiDomMeta, type SduiEnumOption, type SduiPropGroup, type SduiPropKind, type SduiPropMeta, type SduiResizeMeta, type SduiSlotMeta, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimePickerMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
615
+ export { ActionsMeta, AlertMeta, ApprovalLineEditorMeta, ApprovalOverridesEditorMeta, ApprovalStepperMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, ExcelUploadCardMeta, FieldMeta, FileDropzoneMeta, ForEachMeta, FormMeta, FragmentMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OptionSchemaEditorMeta, OptionValueFieldsMeta, OrgChartBoardMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PermissionMatrixEditorMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RankBoardMeta, RecordSheetMeta, RemoteSearchResultsMeta, RoleMemberPickerMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, type SduiCategory, type SduiChildrenMeta, type SduiComponentMeta, type SduiDomMeta, type SduiEnumOption, type SduiPropGroup, type SduiPropKind, type SduiPropMeta, type SduiResizeMeta, type SduiSlotMeta, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StagePeriodEditorMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimePickerMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
package/dist/meta.js CHANGED
@@ -4060,6 +4060,123 @@ var ExcelUploadCardMeta = {
4060
4060
  },
4061
4061
  resize: { kind: "none" }
4062
4062
  };
4063
+ var OptionSchemaEditorMeta = {
4064
+ name: "OptionSchemaEditor",
4065
+ label: "\uC635\uC158 \uC11C\uC2DD \uD3B8\uC9D1",
4066
+ category: "input",
4067
+ icon: "sliders-horizontal",
4068
+ description: "\uC7A5\uBE44\uAC00 \uC790\uAE30 \uC720\uB2DB\uC5D0\uAC8C \uBC1B\uC744 \uC635\uC158\uC758 \uC11C\uC2DD(\uC774\uB984\xB7\uD615\uC2DD\xB7\uC120\uD0DD\uC9C0)\uC744 \uC815\uD55C\uB2E4. \uAC12\uC774 \uC544\uB2C8\uB77C \uC11C\uC2DD\uC774\uB2E4 \u2014 \uC720\uB2DB \uC218\uC815\uC740 \uC774 \uC11C\uC2DD\uB300\uB85C \uCE78\uC744 \uADF8\uB9B0\uB2E4(OptionValueFields).",
4069
+ props: [
4070
+ {
4071
+ name: "value",
4072
+ kind: "object",
4073
+ label: "\uC7A5\uBE44 config",
4074
+ bindable: true,
4075
+ description: "\uC11C\uC2DD\uC740 \uC774 \uAC1D\uCCB4\uC758 options\uC5D0 \uB2F4\uAE34\uB2E4 \u2014 { options: [{ key, label?, type, options?, unit? }] }. \uBC30\uC5F4\uC774 \uC544\uB2C8\uB77C config \uD1B5\uC9F8\uB85C \uC8FC\uACE0\uBC1B\uB294 \uC774\uC720\uB294 setState\uAC00 \uC810 \uACBD\uB85C\uB97C \uD3C9\uBA74 \uD0A4\uB85C \uC800\uC7A5\uD558\uAE30 \uB54C\uBB38\uC774\uB2E4.",
4076
+ group: "data"
4077
+ },
4078
+ {
4079
+ name: "onChange",
4080
+ kind: "action",
4081
+ label: "\uBCC0\uACBD",
4082
+ eventArg: "options\uAC00 \uAC31\uC2E0\uB41C config \uAC1D\uCCB4",
4083
+ description: '{ "action": "setState", "key": "assetEditForm.config", "fromEvent": true }',
4084
+ group: "behavior"
4085
+ },
4086
+ { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" }
4087
+ ],
4088
+ children: { accepts: false },
4089
+ dom: { element: "div" },
4090
+ preset: {
4091
+ component: "OptionSchemaEditor",
4092
+ props: {
4093
+ value: { $state: "form.config", default: {} },
4094
+ onChange: { action: "setState", key: "form.config", fromEvent: true }
4095
+ }
4096
+ },
4097
+ resize: { kind: "none" }
4098
+ };
4099
+ var OptionValueFieldsMeta = {
4100
+ name: "OptionValueFields",
4101
+ label: "\uC635\uC158 \uAC12 \uC785\uB825",
4102
+ category: "input",
4103
+ icon: "list-filter",
4104
+ description: "\uC7A5\uBE44\uAC00 \uC815\uD574 \uB454 \uC635\uC158 \uC11C\uC2DD\uB300\uB85C \uC720\uB2DB\uC758 \uAC12 \uCE78\uC744 \uADF8\uB9B0\uB2E4. \uC11C\uC2DD\uC5D0 \uC5C6\uB294 \uD0A4\uB294 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uACE0 \uADF8\uB300\uB85C \uBCF4\uAD00\uD55C\uB2E4.",
4105
+ props: [
4106
+ {
4107
+ name: "schema",
4108
+ kind: "array",
4109
+ label: "\uC635\uC158 \uC11C\uC2DD",
4110
+ bindable: true,
4111
+ description: "\uC7A5\uBE44\uC758 assets.config.options \u2014 OptionSchemaEditor\uAC00 \uB9CC\uB4E0 \uBC30\uC5F4 \uADF8\uB300\uB85C.",
4112
+ group: "data",
4113
+ item: [
4114
+ { name: "key", kind: "string", label: "\uC774\uB984(\uD0A4)", required: true },
4115
+ { name: "label", kind: "string", label: "\uD45C\uC2DC \uC774\uB984" },
4116
+ { name: "type", kind: "string", label: "\uD615\uC2DD", required: true },
4117
+ { name: "options", kind: "array", label: "\uC120\uD0DD\uC9C0", itemKind: "string", item: [] },
4118
+ { name: "unit", kind: "string", label: "\uB2E8\uC704" }
4119
+ ]
4120
+ },
4121
+ {
4122
+ name: "value",
4123
+ kind: "object",
4124
+ label: "\uC635\uC158 \uAC12",
4125
+ bindable: true,
4126
+ description: "{ \uD0A4: \uAC12 } \uD3C9\uBA74 \uAC1D\uCCB4 \u2014 asset_units.config.",
4127
+ group: "data"
4128
+ },
4129
+ {
4130
+ name: "onChange",
4131
+ kind: "action",
4132
+ label: "\uBCC0\uACBD",
4133
+ eventArg: "\uC635\uC158 \uAC12 \uAC1D\uCCB4",
4134
+ description: '{ "action": "setState", "key": "unitForm.config", "fromEvent": true }',
4135
+ group: "behavior"
4136
+ },
4137
+ { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" },
4138
+ {
4139
+ name: "readOnly",
4140
+ kind: "boolean",
4141
+ label: "\uC77D\uAE30 \uD45C\uC2DC",
4142
+ default: false,
4143
+ description: "\uC0C1\uC138 \uD654\uBA74\uC6A9 \u2014 \uC785\uB825\uCE78 \uB300\uC2E0 \uAC12\uC774 \uC788\uB294 \uCE78\uB9CC \uB77C\uBCA8\xB7\uAC12 \uC904\uB85C \uC138\uC6B4\uB2E4.",
4144
+ group: "appearance"
4145
+ }
4146
+ ],
4147
+ children: { accepts: false },
4148
+ dom: { element: "div" },
4149
+ preset: {
4150
+ component: "OptionValueFields",
4151
+ props: {
4152
+ schema: { $state: "rt.assetOptions.config.options", default: [] },
4153
+ value: { $state: "unitForm.config", default: {} },
4154
+ onChange: { action: "setState", key: "unitForm.config", fromEvent: true }
4155
+ }
4156
+ },
4157
+ resize: { kind: "none" }
4158
+ };
4159
+ var StagePeriodEditorMeta = {
4160
+ name: "StagePeriodEditor",
4161
+ label: "\uB2E8\uACC4 \uAE30\uAC04 \uC785\uB825\uAE30",
4162
+ category: "input",
4163
+ icon: "calendar",
4164
+ description: "\uD3C9\uAC00 \uB2E8\uACC4\uC758 \uAE30\uAC04 4\uD544\uB4DC(startDate/endDate/startTime/endTime)\uB97C \uD3B8\uC9D1\uD55C\uB2E4. \uBE48\uAC12\u2192null \uC815\uADDC\uD654\uC640 \uC11C\uBC84 validate_period \uBBF8\uB7EC(\uC885\uB8CC\uC77C<\uC2DC\uC791\uC77C, \uAC19\uC740 \uB0A0 \uC2DC\uAC04 \uC21C\uC11C)\uAC00 \uC874\uC7AC \uC774\uC720 \u2014 onChange \uBD09\uD22C\uC758 error\uAC00 \uC788\uC73C\uBA74 \uC800\uC7A5\uC744 \uC7A0\uADFC\uB2E4. \uC800\uC7A5\uC740 \uC2A4\uD399\uC774 PATCH \uCCB4\uC778\uC73C\uB85C \uD55C\uB2E4.",
4165
+ props: [
4166
+ { name: "value", kind: "object", label: "\uC800\uC7A5\uB41C \uAE30\uAC04", bindable: true, description: "\uB2E8\uACC4 \uD589(stages[]) \uADF8\uB300\uB85C \u2014 \uC2DC\uAC01 HH:MM:SS \uD5C8\uC6A9, HH:MM\uB85C \uC815\uADDC\uD654\uD574 \uC77D\uB294\uB2E4. \uC2DC\uB529 \uC804\uC6A9.", group: "data" },
4167
+ { name: "onChange", kind: "action", label: "\uBCC0\uACBD", description: "{startDate,endDate,startTime,endTime(null|\uC720\uD6A8\uAC12), error} \uBD09\uD22C. \uB9C8\uC6B4\uD2B8 \uC9C1\uD6C4\uC5D0\uB3C4 1\uD68C \uD758\uB9B0\uB2E4.", group: "behavior" },
4168
+ { name: "resetKey", kind: "string", label: "\uC7AC\uC2DC\uB529 \uD0A4", bindable: true, group: "data", advanced: true },
4169
+ { name: "disabled", kind: "boolean", label: "\uBE44\uD65C\uC131", default: false, bindable: true, group: "behavior" }
4170
+ ],
4171
+ children: { accepts: false },
4172
+ dom: { element: "div" },
4173
+ preset: {
4174
+ component: "StagePeriodEditor",
4175
+ // 빈 props 는 저장 왕복에서 사라진다(편집기 계약) — 프리셋은 실제로 채운다.
4176
+ props: { value: { startDate: "", endDate: "", startTime: "09:00", endTime: "18:00" } }
4177
+ },
4178
+ resize: { kind: "none" }
4179
+ };
4063
4180
  var AutocompleteFieldMeta = {
4064
4181
  name: "AutocompleteField",
4065
4182
  label: "\uC790\uB3D9\uC644\uC131",
@@ -5480,6 +5597,9 @@ var widgetComponentMeta = {
5480
5597
  ApprovalLineEditor: ApprovalLineEditorMeta,
5481
5598
  ApprovalOverridesEditor: ApprovalOverridesEditorMeta,
5482
5599
  ApprovalStepper: ApprovalStepperMeta,
5600
+ OptionSchemaEditor: OptionSchemaEditorMeta,
5601
+ OptionValueFields: OptionValueFieldsMeta,
5602
+ StagePeriodEditor: StagePeriodEditorMeta,
5483
5603
  ExcelUploadCard: ExcelUploadCardMeta,
5484
5604
  FileDropzone: FileDropzoneMeta,
5485
5605
  PermissionMatrixEditor: PermissionMatrixEditorMeta,
@@ -5543,4 +5663,4 @@ function paletteGroups(catalog = allComponentMeta) {
5543
5663
  })).filter((group) => group.items.length > 0);
5544
5664
  }
5545
5665
 
5546
- export { ActionsMeta, AlertMeta, ApprovalLineEditorMeta, ApprovalOverridesEditorMeta, ApprovalStepperMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, ExcelUploadCardMeta, FieldMeta, FileDropzoneMeta, ForEachMeta, FormMeta, FragmentMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OrgChartBoardMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PermissionMatrixEditorMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RankBoardMeta, RecordSheetMeta, RemoteSearchResultsMeta, RoleMemberPickerMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimePickerMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
5666
+ export { ActionsMeta, AlertMeta, ApprovalLineEditorMeta, ApprovalOverridesEditorMeta, ApprovalStepperMeta, AutocompleteFieldMeta, AvatarMeta, BadgeMeta, BreadcrumbMeta, ButtonMeta, CanMeta, CardMeta, ChartMeta, CheckboxMeta, ColMeta, ColumnBoardMeta, DatePickerMeta, DateRangePickerMeta, DialogMeta, DiffViewMeta, DisclosureMeta, DividerMeta, EmptyStateMeta, EventCalendarMeta, ExcelUploadCardMeta, FieldMeta, FileDropzoneMeta, ForEachMeta, FormMeta, FragmentMeta, GridMeta, IconButtonMeta, IconMeta, ImageLightboxMeta, InlineEditMeta, InputMeta, JsonFieldMeta, KeyValueListMeta, LiveClockMeta, MapPreviewMeta, OptionSchemaEditorMeta, OptionValueFieldsMeta, OrgChartBoardMeta, OrgChartMeta, PageHeadMeta, PaginationMeta, PeriodFilterMeta, PermissionMatrixEditorMeta, PrintSheetMeta, ProgressBarMeta, RadioMeta, RankBoardMeta, RecordSheetMeta, RemoteSearchResultsMeta, RoleMemberPickerMeta, RowMeta, SDUI_CATEGORIES, SELF_AXIS_PROPS, SearchResultsMeta, SearchableMultiPickerMeta, SectionMeta, SecureScreenMeta, SegmentedControlMeta, SelectMeta, ShowMeta, SidebarNavMeta, SortHandleMeta, SortableListMeta, SpacerMeta, SpinnerMeta, StackedMeterMeta, StagePeriodEditorMeta, StatCardMeta, StripMeta, SummaryTableMeta, SwitchMeta, TableMeta, TabsMeta, TagMeta, TagMultiSelectMeta, TextMeta, TextareaMeta, TimePickerMeta, TimelineMeta, ToastMeta, TooltipMeta, TreePickerMeta, TreeViewMeta, allComponentMeta, builtinComponentMeta, coreComponentMeta, dsComponentMeta, getComponentMeta, paletteGroups, richComponentMeta, slotNamesOf, widgetComponentMeta, withSelfAxis, withSelfAxisAll };
package/dist/rich.js CHANGED
@@ -1,5 +1,5 @@
1
- export { TimePicker } from './chunk-SNRKPEWT.js';
2
1
  import { useOptionalModule, DependencyPlaceholder } from './chunk-RRMKCZYQ.js';
2
+ export { TimePicker } from './chunk-SNRKPEWT.js';
3
3
  import { HoistedStyle } from './chunk-EFMKWPZ3.js';
4
4
  export { DatePicker, DateRangePicker } from './chunk-EFMKWPZ3.js';
5
5
  import './chunk-XQPTSEJC.js';
@@ -0,0 +1,63 @@
1
+ import * as React from 'react';
2
+ import { S as SduiBoxProps } from '../layout-B1QrIBm6.js';
3
+
4
+ /**
5
+ * OptionSchemaEditor — 장비가 자기 유닛에게 받을 **옵션 서식**을 정한다.
6
+ *
7
+ * 유닛의 사양(CPU·RAM·해상도…)은 장비 종류마다 달라서 컬럼으로 세울 수 없다.
8
+ * 그래서 값은 `asset_units.config`(JSON)에 담기는데, 지금까지는 그 JSON을 사람이
9
+ * 직접 쓰고 있었다 — 키 이름이 유닛마다 갈리고(`cpu`/`CPU`/`씨피유`) 숫자여야 할
10
+ * 자리에 문자열이 들어가도 아무도 못 막는다.
11
+ *
12
+ * 여기서 정하는 것은 **값이 아니라 서식**이다. 장비에 한 번 정해 두면
13
+ * (`assets.config.options`) 유닛 수정 화면이 그 서식대로 칸을 그린다
14
+ * ({@link ./OptionValueFields.tsx}). SDUI가 스펙을 화면으로 만드는 것과 같은 결이고,
15
+ * 서식이 스펙이 아니라 **데이터**라는 점만 다르다 — 장비마다 다르니 스펙일 수 없다.
16
+ *
17
+ * 계약: `value`는 장비의 **config 객체 통째**이고 서식은 그 안의 `options`다.
18
+ * { options: [{ key, label?, type: 'text'|'number'|'select'|'boolean', options?, unit? }] }
19
+ *
20
+ * 배열만 주고받지 않는 이유는 SDUI의 `setState`가 **점 경로를 평면 키로 저장**하기
21
+ * 때문이다 — `assetEditForm.config.options`로 쓰면 그 이름의 납작한 키가 하나 생길 뿐
22
+ * `config` 안에 들어가지 않아 폼 본문에 실리지 않는다. 그래서 다른 폼 칸과 똑같이
23
+ * 키 하나(`assetEditForm.config`)를 주고받고, `options` 밖의 값은 그대로 보존한다.
24
+ * - `key`가 유닛 config의 실제 키다. 비었거나 겹치면 저장 못 하게 사유를 띄운다
25
+ * (스펙은 이 위젯 밖이라 검증을 여기서 보여 준다).
26
+ * - `label`은 화면에 쓸 이름 — 비면 key를 그대로 쓴다.
27
+ */
28
+ declare const OPTION_TYPES: readonly [{
29
+ readonly value: "text";
30
+ readonly label: "문자열";
31
+ }, {
32
+ readonly value: "number";
33
+ readonly label: "숫자";
34
+ }, {
35
+ readonly value: "select";
36
+ readonly label: "선택";
37
+ }, {
38
+ readonly value: "boolean";
39
+ readonly label: "예/아니오";
40
+ }];
41
+ type OptionFieldType = (typeof OPTION_TYPES)[number]['value'];
42
+ interface OptionField {
43
+ key: string;
44
+ label?: string;
45
+ type: OptionFieldType;
46
+ /** type=select일 때의 선택지 */
47
+ options?: string[];
48
+ /** 숫자 뒤에 붙는 단위 표시 — GB·인치처럼 값에 섞지 않을 것들 */
49
+ unit?: string;
50
+ }
51
+ /** 장비의 config — 서식은 options에 담고 나머지 키는 손대지 않는다 */
52
+ interface AssetOptionConfig {
53
+ options?: OptionField[];
54
+ [key: string]: unknown;
55
+ }
56
+ interface OptionSchemaEditorProps {
57
+ value?: AssetOptionConfig | null;
58
+ onChange?: (config: AssetOptionConfig) => void;
59
+ disabled?: boolean;
60
+ }
61
+ declare const OptionSchemaEditor: React.FC<OptionSchemaEditorProps & SduiBoxProps>;
62
+
63
+ export { type AssetOptionConfig, OPTION_TYPES, type OptionField, type OptionFieldType, OptionSchemaEditor, type OptionSchemaEditorProps };
@@ -0,0 +1,4 @@
1
+ export { OPTION_TYPES, OptionSchemaEditor } from '../chunk-TIY4A223.js';
2
+ import '../chunk-QO6UJAQN.js';
3
+ import '../chunk-WIDDHR7L.js';
4
+ import '../chunk-SAN4IX6N.js';
@@ -0,0 +1,21 @@
1
+ import { S as SduiBoxProps } from '../layout-B1QrIBm6.js';
2
+ import React__default from 'react';
3
+ import { OptionField } from './OptionSchemaEditor.js';
4
+
5
+ interface OptionValueFieldsProps {
6
+ /** 장비의 옵션 서식 (assets.config.options) */
7
+ schema?: OptionField[];
8
+ /** 유닛의 옵션 값 (asset_units.config) */
9
+ value?: Record<string, unknown> | null;
10
+ onChange?: (value: Record<string, unknown>) => void;
11
+ disabled?: boolean;
12
+ /**
13
+ * 입력 대신 읽기 표시 — 상세 화면용. 값이 있는 칸만 라벨·값 줄로 세운다.
14
+ * 잠긴 입력칸으로 대신하지 않는 이유: 회색 입력칸은 "고칠 수 있는데 지금은 막혔다"로
15
+ * 읽히고, 빈 칸이 줄줄이 서면 값이 없다는 사실만 크게 보인다.
16
+ */
17
+ readOnly?: boolean;
18
+ }
19
+ declare const OptionValueFields: React__default.FC<OptionValueFieldsProps & SduiBoxProps>;
20
+
21
+ export { OptionValueFields, type OptionValueFieldsProps };
@@ -0,0 +1,4 @@
1
+ export { OptionValueFields } from '../chunk-CTSVZTIT.js';
2
+ import '../chunk-QO6UJAQN.js';
3
+ import '../chunk-WIDDHR7L.js';
4
+ import '../chunk-SAN4IX6N.js';
@@ -0,0 +1,45 @@
1
+ import * as React from 'react';
2
+ import { S as SduiBoxProps } from '../layout-B1QrIBm6.js';
3
+
4
+ /**
5
+ * StagePeriodEditor — 평가 단계(회차 소속 세션)의 기간 4필드 편집기.
6
+ *
7
+ * v2 evaluation-campaign-management.tsx의 StagePeriodDialog 본문 이식이다.
8
+ * 스펙만으로는 안 되는 두 가지가 이 계층의 존재 이유다:
9
+ * 1. **빈값 → null 정규화** — 서버 PATCH /evaluation-sessions/{id}는 빈 문자열을
10
+ * 400("YYYY-MM-DD/HH:MM 형식")으로 거부하고 null만 "기간 없음"으로 받는다.
11
+ * 스펙($calc)에는 ""→null 변환 연산이 없다.
12
+ * 2. **서버 validate_period의 클라이언트 미러** — 종료일<시작일, 같은 날
13
+ * 종료시간≤시작시간. 날짜 문자열 비교 연산이 스펙에 없다.
14
+ *
15
+ * 프롭 계약:
16
+ * - value: 저장된 기간(서버 stages[]의 startDate/endDate/startTime/endTime —
17
+ * 시각은 'HH:MM:SS'도 허용, 'HH:MM'으로 정규화해 읽는다). **시딩 전용** —
18
+ * resetKey가 바뀔 때만 다시 읽는다(편집 중 재조회가 입력을 덮지 않게, v2와
19
+ * 같은 마운트 1회 초기화 의미론).
20
+ * - onChange: { startDate, endDate, startTime, endTime, error } 봉투.
21
+ * 4필드는 항상 null 또는 유효값이라 그대로 PATCH body에 바인딩할 수 있고,
22
+ * error가 있으면 스펙은 저장 버튼을 잠근다. 마운트 직후에도 한 번 흘린다.
23
+ * - 저장은 스펙이 한다(PATCH camel 4필드). 시간을 날짜 없이 두는 조합은 입력
24
+ * 단계에서 막는다(날짜를 지우면 시각도 함께 비움 — v2 동일).
25
+ */
26
+ /** onChange 봉투 — 4필드는 null 또는 유효값, error가 있으면 저장 금지. */
27
+ interface StagePeriodValue {
28
+ startDate: string | null;
29
+ endDate: string | null;
30
+ startTime: string | null;
31
+ endTime: string | null;
32
+ error: string | null;
33
+ }
34
+ interface StagePeriodEditorProps {
35
+ /** 저장된 기간(서버 응답 그대로). 시딩 전용 — resetKey가 바뀔 때 다시 읽는다. */
36
+ value?: unknown;
37
+ onChange?: (value: StagePeriodValue) => void;
38
+ /** 단계 id — 바뀌면 value로 폼을 다시 시딩한다(다이얼로그 재사용 대비). */
39
+ resetKey?: string;
40
+ disabled?: boolean;
41
+ }
42
+ /** 바깥 style·className을 뿌리에 얹는다 — 자기 축(폭·여백) 통로. */
43
+ declare const StagePeriodEditor: React.FC<StagePeriodEditorProps & SduiBoxProps>;
44
+
45
+ export { StagePeriodEditor, type StagePeriodEditorProps, type StagePeriodValue };
@@ -0,0 +1,6 @@
1
+ export { StagePeriodEditor } from '../chunk-KVFHPBAY.js';
2
+ import '../chunk-SNRKPEWT.js';
3
+ import '../chunk-EFMKWPZ3.js';
4
+ import '../chunk-XQPTSEJC.js';
5
+ import '../chunk-WIDDHR7L.js';
6
+ import '../chunk-SAN4IX6N.js';
@@ -10,6 +10,8 @@ import { SummaryTableProps } from './SummaryTable.js';
10
10
  export { SummaryTable, SummaryTableColumn } from './SummaryTable.js';
11
11
  import { StripProps } from './Strip.js';
12
12
  export { Strip } from './Strip.js';
13
+ import { StagePeriodEditorProps } from './StagePeriodEditor.js';
14
+ export { StagePeriodEditor } from './StagePeriodEditor.js';
13
15
  import { StackedMeterProps } from './StackedMeter.js';
14
16
  export { StackedMeter, StackedMeterSegment } from './StackedMeter.js';
15
17
  import { SecureScreenProps } from './SecureScreen.js';
@@ -32,6 +34,10 @@ import { OrgChartBoardProps } from './OrgChartBoard.js';
32
34
  export { OrgChartBoard } from './OrgChartBoard.js';
33
35
  import { OrgChartProps } from './OrgChart.js';
34
36
  export { OrgChart, OrgNode } from './OrgChart.js';
37
+ import { OptionValueFieldsProps } from './OptionValueFields.js';
38
+ export { OptionValueFields } from './OptionValueFields.js';
39
+ import { OptionSchemaEditorProps } from './OptionSchemaEditor.js';
40
+ export { OptionSchemaEditor } from './OptionSchemaEditor.js';
35
41
  import { LiveClockProps } from './LiveClock.js';
36
42
  export { LiveClock } from './LiveClock.js';
37
43
  import { JsonFieldProps } from './JsonField.js';
@@ -78,6 +84,8 @@ declare const widgetComponents: {
78
84
  InlineEdit: React.FC<InlineEditProps & SduiBoxProps>;
79
85
  JsonField: React.FC<JsonFieldProps & SduiBoxProps>;
80
86
  LiveClock: React.FC<LiveClockProps & SduiBoxProps>;
87
+ OptionSchemaEditor: React.FC<OptionSchemaEditorProps & SduiBoxProps>;
88
+ OptionValueFields: React.FC<OptionValueFieldsProps & SduiBoxProps>;
81
89
  OrgChart: React.FC<OrgChartProps & SduiBoxProps>;
82
90
  OrgChartBoard: React.FC<OrgChartBoardProps & SduiBoxProps>;
83
91
  PermissionMatrixEditor: React.FC<PermissionMatrixEditorProps & SduiBoxProps>;
@@ -89,6 +97,7 @@ declare const widgetComponents: {
89
97
  SearchableMultiPicker: React.FC<SearchableMultiPickerProps & SduiBoxProps>;
90
98
  SecureScreen: React.FC<SecureScreenProps & SduiBoxProps>;
91
99
  StackedMeter: React.FC<StackedMeterProps & SduiBoxProps>;
100
+ StagePeriodEditor: React.FC<StagePeriodEditorProps & SduiBoxProps>;
92
101
  Strip: React.FC<StripProps & SduiBoxProps>;
93
102
  SummaryTable: React.FC<SummaryTableProps & SduiBoxProps>;
94
103
  TagMultiSelect: React.FC<TagMultiSelectProps & SduiBoxProps>;
@@ -99,4 +108,4 @@ declare const widgetComponents: {
99
108
  /** 위젯 어휘의 컴포넌트 이름 union — 메타데이터 대조에 쓴다(`@wipco/sdui/meta`). */
100
109
  type SduiWidgetComponentName = keyof typeof widgetComponents;
101
110
 
102
- export { ApprovalLineEditorProps, ApprovalOverridesEditorProps, ApprovalStepperProps, ColumnBoardProps, DiffViewProps, DisclosureProps, EventCalendarProps, ImageLightboxProps, InlineEditProps, JsonFieldProps, LiveClockProps, OrgChartBoardProps, OrgChartProps, PeriodFilterProps, PermissionMatrixEditorProps, PrintSheetProps, RankBoardProps, RecordSheetProps, RoleMemberPickerProps, type SduiWidgetComponentName, SearchableMultiPickerProps, SecureScreenProps, StackedMeterProps, StripProps, SummaryTableProps, TagMultiSelectProps, TimelineProps, TreePickerProps, TreeViewProps, widgetComponents };
111
+ export { ApprovalLineEditorProps, ApprovalOverridesEditorProps, ApprovalStepperProps, ColumnBoardProps, DiffViewProps, DisclosureProps, EventCalendarProps, ImageLightboxProps, InlineEditProps, JsonFieldProps, LiveClockProps, OptionSchemaEditorProps, OptionValueFieldsProps, OrgChartBoardProps, OrgChartProps, PeriodFilterProps, PermissionMatrixEditorProps, PrintSheetProps, RankBoardProps, RecordSheetProps, RoleMemberPickerProps, type SduiWidgetComponentName, SearchableMultiPickerProps, SecureScreenProps, StackedMeterProps, StagePeriodEditorProps, StripProps, SummaryTableProps, TagMultiSelectProps, TimelineProps, TreePickerProps, TreeViewProps, widgetComponents };
@@ -1,9 +1,17 @@
1
+ import { Strip } from '../chunk-ZH5MLOZS.js';
2
+ export { Strip } from '../chunk-ZH5MLOZS.js';
3
+ import { SummaryTable } from '../chunk-O4U7Y3XL.js';
4
+ export { SummaryTable } from '../chunk-O4U7Y3XL.js';
1
5
  import { Timeline } from '../chunk-EFYEOT47.js';
2
6
  export { Timeline } from '../chunk-EFYEOT47.js';
3
7
  import { TreePicker } from '../chunk-U3HYQCFA.js';
4
8
  export { TreePicker } from '../chunk-U3HYQCFA.js';
5
9
  import { TreeView } from '../chunk-X5R2HHEN.js';
6
10
  export { TreeView, buildTreeNodes } from '../chunk-X5R2HHEN.js';
11
+ import { PrintSheet } from '../chunk-MYJ2KEIP.js';
12
+ export { PrintSheet } from '../chunk-MYJ2KEIP.js';
13
+ import { RankBoard } from '../chunk-U6H7YN4I.js';
14
+ export { RankBoard } from '../chunk-U6H7YN4I.js';
7
15
  import { RecordSheet } from '../chunk-K3JBSWFI.js';
8
16
  export { RecordSheet } from '../chunk-K3JBSWFI.js';
9
17
  import { RoleMemberPicker } from '../chunk-WXZDYDXG.js';
@@ -14,14 +22,16 @@ import { SecureScreen } from '../chunk-IIRENCDS.js';
14
22
  export { SecureScreen } from '../chunk-IIRENCDS.js';
15
23
  import { StackedMeter } from '../chunk-BMZKZGJF.js';
16
24
  export { StackedMeter } from '../chunk-BMZKZGJF.js';
17
- import { Strip } from '../chunk-ZH5MLOZS.js';
18
- export { Strip } from '../chunk-ZH5MLOZS.js';
19
- import { SummaryTable } from '../chunk-O4U7Y3XL.js';
20
- export { SummaryTable } from '../chunk-O4U7Y3XL.js';
25
+ import { StagePeriodEditor } from '../chunk-KVFHPBAY.js';
26
+ export { StagePeriodEditor } from '../chunk-KVFHPBAY.js';
21
27
  import { JsonField } from '../chunk-JVBZRDC2.js';
22
28
  export { JsonField } from '../chunk-JVBZRDC2.js';
23
29
  import { LiveClock } from '../chunk-Z3WGIFJP.js';
24
30
  export { LiveClock } from '../chunk-Z3WGIFJP.js';
31
+ import { OptionSchemaEditor } from '../chunk-TIY4A223.js';
32
+ export { OptionSchemaEditor } from '../chunk-TIY4A223.js';
33
+ import { OptionValueFields } from '../chunk-CTSVZTIT.js';
34
+ export { OptionValueFields } from '../chunk-CTSVZTIT.js';
25
35
  import { OrgChart } from '../chunk-QWJ3OBBL.js';
26
36
  export { OrgChart } from '../chunk-QWJ3OBBL.js';
27
37
  import { OrgChartBoard } from '../chunk-NGZI4V3O.js';
@@ -30,10 +40,6 @@ import { PermissionMatrixEditor } from '../chunk-N24VF6KI.js';
30
40
  export { PermissionMatrixEditor } from '../chunk-N24VF6KI.js';
31
41
  import { PeriodFilter } from '../chunk-INWASR2G.js';
32
42
  export { PeriodFilter } from '../chunk-INWASR2G.js';
33
- import { PrintSheet } from '../chunk-MYJ2KEIP.js';
34
- export { PrintSheet } from '../chunk-MYJ2KEIP.js';
35
- import { RankBoard } from '../chunk-U6H7YN4I.js';
36
- export { RankBoard } from '../chunk-U6H7YN4I.js';
37
43
  export { AutocompleteField, toAutocompleteOptions } from '../chunk-CVCP52OD.js';
38
44
  import { ColumnBoard } from '../chunk-C4JRSZGS.js';
39
45
  export { ColumnBoard } from '../chunk-C4JRSZGS.js';
@@ -49,7 +55,9 @@ export { ImageLightbox } from '../chunk-XPBZMECW.js';
49
55
  import { InlineEdit } from '../chunk-KT3ZVBLN.js';
50
56
  export { InlineEdit } from '../chunk-KT3ZVBLN.js';
51
57
  import '../chunk-QU7YVMFA.js';
58
+ import '../chunk-QO6UJAQN.js';
52
59
  import '../chunk-THEP3VWY.js';
60
+ import '../chunk-SNRKPEWT.js';
53
61
  import { ApprovalOverridesEditor } from '../chunk-OR27SRKL.js';
54
62
  export { ApprovalOverridesEditor } from '../chunk-OR27SRKL.js';
55
63
  import { TagMultiSelect } from '../chunk-QDEZXA34.js';
@@ -78,6 +86,8 @@ var widgetComponents = {
78
86
  InlineEdit,
79
87
  JsonField,
80
88
  LiveClock,
89
+ OptionSchemaEditor,
90
+ OptionValueFields,
81
91
  OrgChart,
82
92
  OrgChartBoard,
83
93
  PermissionMatrixEditor,
@@ -89,6 +99,7 @@ var widgetComponents = {
89
99
  SearchableMultiPicker,
90
100
  SecureScreen,
91
101
  StackedMeter,
102
+ StagePeriodEditor,
92
103
  Strip,
93
104
  SummaryTable,
94
105
  TagMultiSelect,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipco/sdui",
3
- "version": "0.31.0",
3
+ "version": "0.32.0",
4
4
  "description": "WIPCO 서버 주도 UI(SDUI) 렌더러 — JSON 페이지 스펙을 React 컴포넌트로 렌더링",
5
5
  "keywords": [
6
6
  "sdui",
@@ -92,6 +92,14 @@
92
92
  "types": "./dist/widgets/LiveClock.d.ts",
93
93
  "default": "./dist/widgets/LiveClock.js"
94
94
  },
95
+ "./widgets/OptionSchemaEditor": {
96
+ "types": "./dist/widgets/OptionSchemaEditor.d.ts",
97
+ "default": "./dist/widgets/OptionSchemaEditor.js"
98
+ },
99
+ "./widgets/OptionValueFields": {
100
+ "types": "./dist/widgets/OptionValueFields.d.ts",
101
+ "default": "./dist/widgets/OptionValueFields.js"
102
+ },
95
103
  "./widgets/OrgChart": {
96
104
  "types": "./dist/widgets/OrgChart.d.ts",
97
105
  "default": "./dist/widgets/OrgChart.js"
@@ -136,6 +144,10 @@
136
144
  "types": "./dist/widgets/StackedMeter.d.ts",
137
145
  "default": "./dist/widgets/StackedMeter.js"
138
146
  },
147
+ "./widgets/StagePeriodEditor": {
148
+ "types": "./dist/widgets/StagePeriodEditor.d.ts",
149
+ "default": "./dist/widgets/StagePeriodEditor.js"
150
+ },
139
151
  "./widgets/Strip": {
140
152
  "types": "./dist/widgets/Strip.d.ts",
141
153
  "default": "./dist/widgets/Strip.js"