@wipco/sdui 0.21.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HPZTFZZN.js → chunk-36MXPCJP.js} +64 -96
- package/dist/chunk-DVOPZFQS.js +100 -0
- package/dist/{chunk-SRGXODY2.js → chunk-OG62LSFH.js} +30 -5
- package/dist/chunk-ZTQEP3TR.js +211 -0
- package/dist/index.d.ts +44 -5
- package/dist/index.js +369 -123
- package/dist/meta.d.ts +7 -5
- package/dist/meta.js +111 -4
- package/dist/rich.js +3 -51
- package/dist/styles.css +3 -0
- package/dist/{types-opTPYysN.d.ts → types-DmHC7HCN.d.ts} +93 -3
- package/dist/widgets/ApprovalStepper.d.ts +41 -0
- package/dist/widgets/ApprovalStepper.js +3 -0
- package/dist/widgets/AutocompleteField.d.ts +29 -2
- package/dist/widgets/AutocompleteField.js +2 -1
- package/dist/widgets/index.d.ts +6 -3
- package/dist/widgets/index.js +11 -7
- package/package.json +10 -2
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { TimePicker,
|
|
1
|
+
import { TimePicker } from './chunk-36MXPCJP.js';
|
|
2
|
+
export { TimePicker, loadOptionalModule } from './chunk-36MXPCJP.js';
|
|
3
3
|
import { ImageViewer } from './chunk-THEP3VWY.js';
|
|
4
4
|
export { ImageViewer } from './chunk-THEP3VWY.js';
|
|
5
5
|
import { normalizeSearchFields, searchValuesFromParams, splitMultiValue, includesLooseSearch, cascadingValuePaths, SearchToolbar, searchFieldKeys, Popover } from './chunk-U7ZK7WYH.js';
|
|
6
6
|
export { SearchToolbar, cascadingValuePaths, cleanSearchValues, includesLooseSearch, joinMultiValue, normalizeSearchText, searchFieldKeys, searchValuesFromParams, splitMultiValue } from './chunk-U7ZK7WYH.js';
|
|
7
|
+
import { DEV, isSafeNavigationTarget, useSduiAdapter, hostFetchOf, useSduiSandbox, resolveAdapter, assetResolverOf, SduiAdapterContext } from './chunk-DVOPZFQS.js';
|
|
8
|
+
export { defaultAdapter, useSduiAssetResolver, useSduiSandbox } from './chunk-DVOPZFQS.js';
|
|
7
9
|
import { HoistedStyle, DateRangePicker, DatePicker, OverlayLayer } from './chunk-XKLUCUVA.js';
|
|
8
10
|
export { DatePicker, DateRangePicker, OverlayContainerContext, OverlayLayer, getOverlayRoot, useOverlayLayer } from './chunk-XKLUCUVA.js';
|
|
9
11
|
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';
|
|
@@ -1783,6 +1785,310 @@ function createRegistry(extensions) {
|
|
|
1783
1785
|
return { ...defaultRegistry, ...extensions };
|
|
1784
1786
|
}
|
|
1785
1787
|
|
|
1788
|
+
// src/calc.ts
|
|
1789
|
+
function isPlainObject(v) {
|
|
1790
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1791
|
+
}
|
|
1792
|
+
function toNumber2(v) {
|
|
1793
|
+
if (typeof v === "number") return v;
|
|
1794
|
+
if (typeof v === "string") {
|
|
1795
|
+
const n = Number(v.replace(/,/g, ""));
|
|
1796
|
+
return Number.isFinite(n) ? n : 0;
|
|
1797
|
+
}
|
|
1798
|
+
return 0;
|
|
1799
|
+
}
|
|
1800
|
+
function isNumericText(v) {
|
|
1801
|
+
if (typeof v === "number") return true;
|
|
1802
|
+
if (typeof v !== "string" || v === "") return false;
|
|
1803
|
+
return Number.isFinite(Number(v.replace(/,/g, "")));
|
|
1804
|
+
}
|
|
1805
|
+
function orderingCompare(a, b) {
|
|
1806
|
+
if (typeof a === "string" && typeof b === "string" && !isNumericText(a) && !isNumericText(b)) {
|
|
1807
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
1808
|
+
}
|
|
1809
|
+
const x = toNumber2(a);
|
|
1810
|
+
const y = toNumber2(b);
|
|
1811
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
1812
|
+
}
|
|
1813
|
+
function looseEquals(a, b) {
|
|
1814
|
+
return String(a ?? "") === String(b ?? "");
|
|
1815
|
+
}
|
|
1816
|
+
function isBlank(v) {
|
|
1817
|
+
return v === null || v === void 0 || v === "";
|
|
1818
|
+
}
|
|
1819
|
+
function fieldOf(row, field) {
|
|
1820
|
+
if (!field) return row;
|
|
1821
|
+
if (!isPlainObject(row)) return void 0;
|
|
1822
|
+
return Object.hasOwn(row, field) ? row[field] : void 0;
|
|
1823
|
+
}
|
|
1824
|
+
var FIELD_OPS = /* @__PURE__ */ new Set([
|
|
1825
|
+
"eq",
|
|
1826
|
+
"ne",
|
|
1827
|
+
"gt",
|
|
1828
|
+
"gte",
|
|
1829
|
+
"lt",
|
|
1830
|
+
"lte",
|
|
1831
|
+
"in",
|
|
1832
|
+
"notIn",
|
|
1833
|
+
"contains",
|
|
1834
|
+
"startsWith",
|
|
1835
|
+
"endsWith",
|
|
1836
|
+
"isNull"
|
|
1837
|
+
]);
|
|
1838
|
+
function isFieldOpObject(v) {
|
|
1839
|
+
return isPlainObject(v) && Object.keys(v).some((key) => FIELD_OPS.has(key));
|
|
1840
|
+
}
|
|
1841
|
+
function matchesFieldOps(actual, ops, resolve) {
|
|
1842
|
+
return Object.entries(ops).every(([op, rawExpected]) => {
|
|
1843
|
+
if (!FIELD_OPS.has(op)) return true;
|
|
1844
|
+
const expected = resolve(rawExpected);
|
|
1845
|
+
switch (op) {
|
|
1846
|
+
case "eq":
|
|
1847
|
+
return looseEquals(actual, expected);
|
|
1848
|
+
case "ne":
|
|
1849
|
+
return !looseEquals(actual, expected);
|
|
1850
|
+
case "gt":
|
|
1851
|
+
return orderingCompare(actual, expected) > 0;
|
|
1852
|
+
case "gte":
|
|
1853
|
+
return orderingCompare(actual, expected) >= 0;
|
|
1854
|
+
case "lt":
|
|
1855
|
+
return orderingCompare(actual, expected) < 0;
|
|
1856
|
+
case "lte":
|
|
1857
|
+
return orderingCompare(actual, expected) <= 0;
|
|
1858
|
+
case "in":
|
|
1859
|
+
return Array.isArray(expected) && expected.some((item) => looseEquals(actual, item));
|
|
1860
|
+
case "notIn":
|
|
1861
|
+
return !Array.isArray(expected) || !expected.some((item) => looseEquals(actual, item));
|
|
1862
|
+
case "contains":
|
|
1863
|
+
return String(actual ?? "").includes(String(expected ?? ""));
|
|
1864
|
+
case "startsWith":
|
|
1865
|
+
return String(actual ?? "").startsWith(String(expected ?? ""));
|
|
1866
|
+
case "endsWith":
|
|
1867
|
+
return String(actual ?? "").endsWith(String(expected ?? ""));
|
|
1868
|
+
case "isNull":
|
|
1869
|
+
return isBlank(actual) === Boolean(expected);
|
|
1870
|
+
default:
|
|
1871
|
+
return true;
|
|
1872
|
+
}
|
|
1873
|
+
});
|
|
1874
|
+
}
|
|
1875
|
+
function matchesWhere(row, where, resolve) {
|
|
1876
|
+
if (!isPlainObject(where)) return true;
|
|
1877
|
+
return Object.entries(where).every(([key, condition]) => {
|
|
1878
|
+
if (key === "AND") {
|
|
1879
|
+
return Array.isArray(condition) && condition.every((sub) => matchesWhere(row, sub, resolve));
|
|
1880
|
+
}
|
|
1881
|
+
if (key === "OR") {
|
|
1882
|
+
return Array.isArray(condition) && condition.some((sub) => matchesWhere(row, sub, resolve));
|
|
1883
|
+
}
|
|
1884
|
+
if (key === "NOT") {
|
|
1885
|
+
return !matchesWhere(row, condition, resolve);
|
|
1886
|
+
}
|
|
1887
|
+
const actual = fieldOf(row, key);
|
|
1888
|
+
if (isFieldOpObject(condition)) return matchesFieldOps(actual, condition, resolve);
|
|
1889
|
+
return looseEquals(actual, resolve(condition));
|
|
1890
|
+
});
|
|
1891
|
+
}
|
|
1892
|
+
var CALC_OPS = /* @__PURE__ */ new Set([
|
|
1893
|
+
// 산술 (기존)
|
|
1894
|
+
"sum",
|
|
1895
|
+
"sub",
|
|
1896
|
+
"mul",
|
|
1897
|
+
"div",
|
|
1898
|
+
"percent",
|
|
1899
|
+
"count",
|
|
1900
|
+
// 문자 (기존)
|
|
1901
|
+
"concat",
|
|
1902
|
+
"encode",
|
|
1903
|
+
// 비교·논리 (기존)
|
|
1904
|
+
"eq",
|
|
1905
|
+
"gt",
|
|
1906
|
+
"gte",
|
|
1907
|
+
"lt",
|
|
1908
|
+
"lte",
|
|
1909
|
+
"not",
|
|
1910
|
+
// 논리 (신규) — 예전에는 스펙이 eq(concat(eq(a),eq(b)),"falsefalse")로 우회했다
|
|
1911
|
+
"and",
|
|
1912
|
+
"or",
|
|
1913
|
+
// 값 고르기 (신규)
|
|
1914
|
+
"if",
|
|
1915
|
+
"match",
|
|
1916
|
+
"coalesce",
|
|
1917
|
+
// 목록·객체 (신규)
|
|
1918
|
+
"get",
|
|
1919
|
+
"pluck",
|
|
1920
|
+
"filter",
|
|
1921
|
+
"some",
|
|
1922
|
+
"every",
|
|
1923
|
+
"includes",
|
|
1924
|
+
"distinct",
|
|
1925
|
+
"except",
|
|
1926
|
+
"entries",
|
|
1927
|
+
"length",
|
|
1928
|
+
"join",
|
|
1929
|
+
"split",
|
|
1930
|
+
"sortBy"
|
|
1931
|
+
]);
|
|
1932
|
+
function evaluateCalc(calc, resolved, resolve) {
|
|
1933
|
+
const op = typeof calc.op === "string" ? calc.op : "";
|
|
1934
|
+
const field = typeof calc.field === "string" ? calc.field : void 0;
|
|
1935
|
+
const first = resolved[0];
|
|
1936
|
+
const list = Array.isArray(first) ? first : void 0;
|
|
1937
|
+
const listOrEmpty = () => {
|
|
1938
|
+
if (list) return list;
|
|
1939
|
+
if (first !== void 0 && first !== null) {
|
|
1940
|
+
warnOnce(
|
|
1941
|
+
`calc:${op}:list`,
|
|
1942
|
+
`[sdui] $calc(${op}): \uCCAB \uC778\uC790\uAC00 \uBC30\uC5F4\uC774 \uC544\uB2D9\uB2C8\uB2E4 \u2014 \uBE48 \uBAA9\uB85D\uC73C\uB85C \uCC98\uB9AC\uD569\uB2C8\uB2E4`
|
|
1943
|
+
);
|
|
1944
|
+
}
|
|
1945
|
+
return [];
|
|
1946
|
+
};
|
|
1947
|
+
const nums = (v) => {
|
|
1948
|
+
if (Array.isArray(v))
|
|
1949
|
+
return v.map((row) => field && isPlainObject(row) ? toNumber2(row[field]) : toNumber2(row));
|
|
1950
|
+
return [toNumber2(v)];
|
|
1951
|
+
};
|
|
1952
|
+
switch (op) {
|
|
1953
|
+
/* ── 산술 ── */
|
|
1954
|
+
case "sum":
|
|
1955
|
+
return resolved.flatMap(nums).reduce((a, b) => a + b, 0);
|
|
1956
|
+
case "count":
|
|
1957
|
+
return resolved.reduce(
|
|
1958
|
+
(a, v) => a + (Array.isArray(v) ? v.length : v == null ? 0 : 1),
|
|
1959
|
+
0
|
|
1960
|
+
);
|
|
1961
|
+
case "sub": {
|
|
1962
|
+
const items = resolved.map((v) => toNumber2(v));
|
|
1963
|
+
return items.length === 0 ? 0 : items.reduce((a, b) => a - b);
|
|
1964
|
+
}
|
|
1965
|
+
case "mul":
|
|
1966
|
+
return resolved.map((v) => toNumber2(v)).reduce((a, b) => a * b, 1);
|
|
1967
|
+
case "div": {
|
|
1968
|
+
const [a, b] = resolved.map((v) => toNumber2(v));
|
|
1969
|
+
return b === 0 ? 0 : a / b;
|
|
1970
|
+
}
|
|
1971
|
+
case "percent": {
|
|
1972
|
+
const [a, b] = resolved.map((v) => toNumber2(v));
|
|
1973
|
+
return b === 0 ? 0 : Math.round(a / b * 1e3) / 10;
|
|
1974
|
+
}
|
|
1975
|
+
/* ── 문자 ── */
|
|
1976
|
+
case "concat":
|
|
1977
|
+
return resolved.map((v) => v == null ? "" : String(v)).join("");
|
|
1978
|
+
case "encode":
|
|
1979
|
+
return encodeURIComponent(resolved.map((v) => v == null ? "" : String(v)).join(""));
|
|
1980
|
+
/* ── 비교·논리 ── */
|
|
1981
|
+
case "eq":
|
|
1982
|
+
return looseEquals(resolved[0], resolved[1]);
|
|
1983
|
+
case "gt":
|
|
1984
|
+
return orderingCompare(resolved[0], resolved[1]) > 0;
|
|
1985
|
+
case "gte":
|
|
1986
|
+
return orderingCompare(resolved[0], resolved[1]) >= 0;
|
|
1987
|
+
case "lt":
|
|
1988
|
+
return orderingCompare(resolved[0], resolved[1]) < 0;
|
|
1989
|
+
case "lte":
|
|
1990
|
+
return orderingCompare(resolved[0], resolved[1]) <= 0;
|
|
1991
|
+
case "not":
|
|
1992
|
+
return !resolved[0];
|
|
1993
|
+
case "and":
|
|
1994
|
+
return resolved.every(Boolean);
|
|
1995
|
+
case "or":
|
|
1996
|
+
return resolved.some(Boolean);
|
|
1997
|
+
/* ── 값 고르기 ── */
|
|
1998
|
+
case "if":
|
|
1999
|
+
return resolved[0] ? resolve(calc.then ?? null) : resolve(calc.else ?? null);
|
|
2000
|
+
case "match": {
|
|
2001
|
+
const key = String(resolved[0] ?? "");
|
|
2002
|
+
const cases = isPlainObject(calc.cases) ? calc.cases : {};
|
|
2003
|
+
if (Object.hasOwn(cases, key)) return resolve(cases[key]);
|
|
2004
|
+
return resolve(calc.default ?? null);
|
|
2005
|
+
}
|
|
2006
|
+
case "coalesce":
|
|
2007
|
+
return resolved.find((v) => !isBlank(v)) ?? null;
|
|
2008
|
+
/* ── 목록·객체 ── */
|
|
2009
|
+
case "get": {
|
|
2010
|
+
const [container, rawKey] = resolved;
|
|
2011
|
+
const key = rawKey == null ? "" : String(rawKey);
|
|
2012
|
+
if (Array.isArray(container)) {
|
|
2013
|
+
const index = Number(key);
|
|
2014
|
+
if (!Number.isInteger(index) || index < 0 || index >= container.length) return null;
|
|
2015
|
+
return container[index] ?? null;
|
|
2016
|
+
}
|
|
2017
|
+
if (isPlainObject(container)) {
|
|
2018
|
+
return Object.hasOwn(container, key) ? container[key] ?? null : null;
|
|
2019
|
+
}
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
2022
|
+
case "pluck":
|
|
2023
|
+
return listOrEmpty().map((row) => fieldOf(row, field)).filter((v) => v !== null && v !== void 0);
|
|
2024
|
+
case "filter":
|
|
2025
|
+
return listOrEmpty().filter((row) => matchesWhere(row, calc.where, resolve));
|
|
2026
|
+
case "some":
|
|
2027
|
+
return listOrEmpty().some((row) => matchesWhere(row, calc.where, resolve));
|
|
2028
|
+
case "every":
|
|
2029
|
+
return listOrEmpty().every((row) => matchesWhere(row, calc.where, resolve));
|
|
2030
|
+
case "includes": {
|
|
2031
|
+
const needle = resolved[1];
|
|
2032
|
+
if (typeof first === "string") return first.includes(String(needle ?? ""));
|
|
2033
|
+
return listOrEmpty().some((row) => looseEquals(fieldOf(row, field), needle));
|
|
2034
|
+
}
|
|
2035
|
+
case "distinct": {
|
|
2036
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2037
|
+
return listOrEmpty().filter((row) => {
|
|
2038
|
+
const key = String(fieldOf(row, field) ?? "");
|
|
2039
|
+
if (seen.has(key)) return false;
|
|
2040
|
+
seen.add(key);
|
|
2041
|
+
return true;
|
|
2042
|
+
});
|
|
2043
|
+
}
|
|
2044
|
+
case "except": {
|
|
2045
|
+
const remove = new Set(
|
|
2046
|
+
(Array.isArray(resolved[1]) ? resolved[1] : []).map(
|
|
2047
|
+
(row) => String(fieldOf(row, field) ?? "")
|
|
2048
|
+
)
|
|
2049
|
+
);
|
|
2050
|
+
return listOrEmpty().filter(
|
|
2051
|
+
(row) => !remove.has(String(fieldOf(row, field) ?? ""))
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
case "entries": {
|
|
2055
|
+
if (!isPlainObject(first)) return [];
|
|
2056
|
+
return Object.entries(first).map(([key, value]) => ({
|
|
2057
|
+
key,
|
|
2058
|
+
value
|
|
2059
|
+
}));
|
|
2060
|
+
}
|
|
2061
|
+
case "length":
|
|
2062
|
+
if (Array.isArray(first)) return first.length;
|
|
2063
|
+
if (typeof first === "string") return first.length;
|
|
2064
|
+
return 0;
|
|
2065
|
+
case "join": {
|
|
2066
|
+
const sep = typeof calc.sep === "string" ? calc.sep : ",";
|
|
2067
|
+
return listOrEmpty().map((row) => {
|
|
2068
|
+
const value = fieldOf(row, field);
|
|
2069
|
+
return value == null ? "" : String(value);
|
|
2070
|
+
}).join(sep);
|
|
2071
|
+
}
|
|
2072
|
+
case "split": {
|
|
2073
|
+
const sep = typeof calc.sep === "string" ? calc.sep : ",";
|
|
2074
|
+
const parts = String(first ?? "").split(sep);
|
|
2075
|
+
if (calc.take === void 0) return parts;
|
|
2076
|
+
const index = toNumber2(calc.take);
|
|
2077
|
+
const at = index < 0 ? parts.length + index : index;
|
|
2078
|
+
return parts[at] ?? null;
|
|
2079
|
+
}
|
|
2080
|
+
case "sortBy": {
|
|
2081
|
+
const desc = Boolean(calc.desc);
|
|
2082
|
+
return [...listOrEmpty()].sort((a, b) => {
|
|
2083
|
+
const order = orderingCompare(fieldOf(a, field), fieldOf(b, field));
|
|
2084
|
+
return desc ? -order : order;
|
|
2085
|
+
});
|
|
2086
|
+
}
|
|
2087
|
+
default:
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
|
|
1786
2092
|
// src/request-action.ts
|
|
1787
2093
|
function deferChainEntry(container, key) {
|
|
1788
2094
|
return typeof container.action === "string" && (key === "onSuccess" || key === "onError");
|
|
@@ -1802,6 +2108,17 @@ async function runRequestAction(action, deps) {
|
|
|
1802
2108
|
(action.onSuccess ?? []).forEach((a) => deps.dispatch(a, response));
|
|
1803
2109
|
} catch (error) {
|
|
1804
2110
|
const message = error instanceof Error ? error.message : "\uC694\uCCAD\uC774 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4";
|
|
2111
|
+
if (typeof action.errorKey === "string" && action.errorKey !== "") {
|
|
2112
|
+
const detail = error;
|
|
2113
|
+
const value = { message };
|
|
2114
|
+
if (typeof detail?.status === "number") value.status = detail.status;
|
|
2115
|
+
if (detail?.body !== void 0) value.body = detail.body;
|
|
2116
|
+
deps.dispatch({
|
|
2117
|
+
action: "setState",
|
|
2118
|
+
key: action.errorKey,
|
|
2119
|
+
value
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
1805
2122
|
if (action.onError?.length) {
|
|
1806
2123
|
action.onError.forEach((a) => deps.dispatch(a, message));
|
|
1807
2124
|
} else {
|
|
@@ -1829,22 +2146,6 @@ var ACTION_NAMES = /* @__PURE__ */ new Set([
|
|
|
1829
2146
|
"arrayUpdate",
|
|
1830
2147
|
"custom"
|
|
1831
2148
|
]);
|
|
1832
|
-
var CALC_OPS = /* @__PURE__ */ new Set([
|
|
1833
|
-
"sum",
|
|
1834
|
-
"sub",
|
|
1835
|
-
"mul",
|
|
1836
|
-
"div",
|
|
1837
|
-
"percent",
|
|
1838
|
-
"count",
|
|
1839
|
-
"concat",
|
|
1840
|
-
"encode",
|
|
1841
|
-
"eq",
|
|
1842
|
-
"gt",
|
|
1843
|
-
"gte",
|
|
1844
|
-
"lt",
|
|
1845
|
-
"lte",
|
|
1846
|
-
"not"
|
|
1847
|
-
]);
|
|
1848
2149
|
var RULE_NAMES = /* @__PURE__ */ new Set([
|
|
1849
2150
|
"required",
|
|
1850
2151
|
"min",
|
|
@@ -1864,7 +2165,7 @@ var DENIED_PROPS = /* @__PURE__ */ new Set([
|
|
|
1864
2165
|
"constructor",
|
|
1865
2166
|
"prototype"
|
|
1866
2167
|
]);
|
|
1867
|
-
function
|
|
2168
|
+
function isPlainObject2(v) {
|
|
1868
2169
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1869
2170
|
}
|
|
1870
2171
|
function checkUrlValue(key, value, path, issues) {
|
|
@@ -1874,7 +2175,7 @@ function checkUrlValue(key, value, path, issues) {
|
|
|
1874
2175
|
}
|
|
1875
2176
|
function validateSpec(page, knownComponents) {
|
|
1876
2177
|
const issues = [];
|
|
1877
|
-
if (!
|
|
2178
|
+
if (!isPlainObject2(page)) return [{ path: "$", message: "\uC2A4\uD399\uC774 \uAC1D\uCCB4\uAC00 \uC544\uB2D9\uB2C8\uB2E4" }];
|
|
1878
2179
|
if (page.version !== 1) issues.push({ path: "$.version", message: "version\uC740 1\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" });
|
|
1879
2180
|
validatePageData(page.data, issues);
|
|
1880
2181
|
if (!Array.isArray(page.body)) {
|
|
@@ -1888,7 +2189,7 @@ function validateSpec(page, knownComponents) {
|
|
|
1888
2189
|
}
|
|
1889
2190
|
function validatePageData(data, issues) {
|
|
1890
2191
|
if (data === void 0) return;
|
|
1891
|
-
if (!
|
|
2192
|
+
if (!isPlainObject2(data)) {
|
|
1892
2193
|
issues.push({ path: "$.data", message: "data\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1893
2194
|
return;
|
|
1894
2195
|
}
|
|
@@ -1898,7 +2199,7 @@ function validatePageData(data, issues) {
|
|
|
1898
2199
|
issues.push({ path, message: "\uC0C1\uD0DC \uD0A4\uB294 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC544\uC57C \uD558\uACE0 $\uB85C \uC2DC\uC791\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4" });
|
|
1899
2200
|
continue;
|
|
1900
2201
|
}
|
|
1901
|
-
if (!
|
|
2202
|
+
if (!isPlainObject2(raw)) {
|
|
1902
2203
|
issues.push({ path, message: "\uC870\uD68C\uB294 { endpoint, select?, when?, fallback? } \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1903
2204
|
continue;
|
|
1904
2205
|
}
|
|
@@ -1910,7 +2211,7 @@ function validatePageData(data, issues) {
|
|
|
1910
2211
|
} else if (!raw.endpoint.startsWith("/")) {
|
|
1911
2212
|
issues.push({ path: `${path}.endpoint`, message: "endpoint\uB294 /\uB85C \uC2DC\uC791\uD558\uB294 \uACBD\uB85C\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1912
2213
|
}
|
|
1913
|
-
} else if (!
|
|
2214
|
+
} else if (!isPlainObject2(raw.endpoint)) {
|
|
1914
2215
|
issues.push({ path: `${path}.endpoint`, message: "endpoint\uB294 \uBB38\uC790\uC5F4\uC774\uAC70\uB098 \uAC12 \uCC38\uC870\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1915
2216
|
} else {
|
|
1916
2217
|
walkValue(raw.endpoint, `${path}.endpoint`, issues, false);
|
|
@@ -1933,7 +2234,7 @@ function validatePageData(data, issues) {
|
|
|
1933
2234
|
}
|
|
1934
2235
|
function walkChild(child, path, issues, known) {
|
|
1935
2236
|
if (typeof child === "string") return;
|
|
1936
|
-
if (!
|
|
2237
|
+
if (!isPlainObject2(child)) {
|
|
1937
2238
|
issues.push({ path, message: "children \uD56D\uBAA9\uC740 \uBB38\uC790\uC5F4 \uB610\uB294 \uB178\uB4DC \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1938
2239
|
return;
|
|
1939
2240
|
}
|
|
@@ -1945,7 +2246,7 @@ function walkChild(child, path, issues, known) {
|
|
|
1945
2246
|
if (known && !RENDERER_BUILTINS.has(node.component) && !known.has(node.component)) {
|
|
1946
2247
|
issues.push({ path, message: `\uB4F1\uB85D\uB418\uC9C0 \uC54A\uC740 \uCEF4\uD3EC\uB10C\uD2B8: ${node.component}` });
|
|
1947
2248
|
}
|
|
1948
|
-
if (node.props !== void 0 && !
|
|
2249
|
+
if (node.props !== void 0 && !isPlainObject2(node.props)) {
|
|
1949
2250
|
issues.push({ path: `${path}.props`, message: "props\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1950
2251
|
}
|
|
1951
2252
|
for (const [name, value] of Object.entries(node.props ?? {})) {
|
|
@@ -1959,9 +2260,9 @@ function walkChild(child, path, issues, known) {
|
|
|
1959
2260
|
checkUrlValue(name, value, `${path}.props.${name}`, issues);
|
|
1960
2261
|
walkValue(value, `${path}.props.${name}`, issues, name.startsWith("on") || name === "rowClick");
|
|
1961
2262
|
}
|
|
1962
|
-
if (node.component === "Form" &&
|
|
2263
|
+
if (node.component === "Form" && isPlainObject2(node.props) && node.props.rules !== void 0) {
|
|
1963
2264
|
const rules = node.props.rules;
|
|
1964
|
-
if (!
|
|
2265
|
+
if (!isPlainObject2(rules)) {
|
|
1965
2266
|
issues.push({ path: `${path}.props.rules`, message: "rules\uB294 { \uD544\uB4DC: \uADDC\uCE59\uBC30\uC5F4 } \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1966
2267
|
} else {
|
|
1967
2268
|
for (const [field, list] of Object.entries(rules)) {
|
|
@@ -1972,15 +2273,15 @@ function walkChild(child, path, issues, known) {
|
|
|
1972
2273
|
}
|
|
1973
2274
|
}
|
|
1974
2275
|
if (node.component === "Fragment") {
|
|
1975
|
-
const id =
|
|
1976
|
-
if ((typeof id !== "string" || id === "") && !
|
|
2276
|
+
const id = isPlainObject2(node.props) ? node.props.id : void 0;
|
|
2277
|
+
if ((typeof id !== "string" || id === "") && !isPlainObject2(id)) {
|
|
1977
2278
|
issues.push({
|
|
1978
2279
|
path: `${path}.props.id`,
|
|
1979
2280
|
message: "Fragment.id\uB294 \uBE44\uC5B4 \uC788\uC9C0 \uC54A\uC740 \uBB38\uC790\uC5F4(\uB610\uB294 \uAC12 \uCC38\uC870)\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4"
|
|
1980
2281
|
});
|
|
1981
2282
|
}
|
|
1982
|
-
const args =
|
|
1983
|
-
if (args !== void 0 && !
|
|
2283
|
+
const args = isPlainObject2(node.props) ? node.props.args : void 0;
|
|
2284
|
+
if (args !== void 0 && !isPlainObject2(args)) {
|
|
1984
2285
|
issues.push({
|
|
1985
2286
|
path: `${path}.props.args`,
|
|
1986
2287
|
message: "Fragment.args\uB294 { \uC774\uB984: \uAC12 } \uD3C9\uBA74 \uC624\uBE0C\uC81D\uD2B8\uC5EC\uC57C \uD569\uB2C8\uB2E4"
|
|
@@ -1994,7 +2295,7 @@ function walkChild(child, path, issues, known) {
|
|
|
1994
2295
|
}
|
|
1995
2296
|
}
|
|
1996
2297
|
if (node.slots !== void 0) {
|
|
1997
|
-
if (!
|
|
2298
|
+
if (!isPlainObject2(node.slots)) {
|
|
1998
2299
|
issues.push({ path: `${path}.slots`, message: "slots\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" });
|
|
1999
2300
|
} else {
|
|
2000
2301
|
for (const [slot, children] of Object.entries(node.slots)) {
|
|
@@ -2019,7 +2320,7 @@ function walkValue(value, path, issues, actionEligible) {
|
|
|
2019
2320
|
value.forEach((v, i) => walkValue(v, `${path}[${i}]`, issues, actionEligible));
|
|
2020
2321
|
return;
|
|
2021
2322
|
}
|
|
2022
|
-
if (!
|
|
2323
|
+
if (!isPlainObject2(value)) return;
|
|
2023
2324
|
if (typeof value.action === "string" && (actionEligible || ACTION_NAMES.has(value.action))) {
|
|
2024
2325
|
if (actionEligible && !ACTION_NAMES.has(value.action)) {
|
|
2025
2326
|
issues.push({ path, message: `\uC54C \uC218 \uC5C6\uB294 \uC561\uC158: ${value.action}` });
|
|
@@ -2046,7 +2347,7 @@ function walkValue(value, path, issues, actionEligible) {
|
|
|
2046
2347
|
}
|
|
2047
2348
|
if ("$calc" in value) {
|
|
2048
2349
|
const calc = value.$calc;
|
|
2049
|
-
if (!
|
|
2350
|
+
if (!isPlainObject2(calc) || typeof calc.op !== "string" || !CALC_OPS.has(calc.op)) {
|
|
2050
2351
|
issues.push({ path, message: "$calc.op\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4" });
|
|
2051
2352
|
} else if (!Array.isArray(calc.args)) {
|
|
2052
2353
|
issues.push({ path: `${path}.$calc.args`, message: "args\uB294 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4" });
|
|
@@ -2075,12 +2376,12 @@ function walkValue(value, path, issues, actionEligible) {
|
|
|
2075
2376
|
}
|
|
2076
2377
|
|
|
2077
2378
|
// src/page-data.ts
|
|
2078
|
-
function
|
|
2379
|
+
function isPlainObject3(value) {
|
|
2079
2380
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2080
2381
|
}
|
|
2081
2382
|
function planPageData(data, resolve) {
|
|
2082
2383
|
if (data === void 0) return [];
|
|
2083
|
-
if (!
|
|
2384
|
+
if (!isPlainObject3(data)) {
|
|
2084
2385
|
warnOnce("page-data:root", "[sdui] page.data\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uBB34\uC2DC\uD569\uB2C8\uB2E4");
|
|
2085
2386
|
return [];
|
|
2086
2387
|
}
|
|
@@ -2090,7 +2391,7 @@ function planPageData(data, resolve) {
|
|
|
2090
2391
|
warnOnce(`page-data:${key}`, `[sdui] page.data\uC758 \uC0C1\uD0DC \uD0A4 "${key}"\uB294 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uAC74\uB108\uB701\uB2C8\uB2E4`);
|
|
2091
2392
|
continue;
|
|
2092
2393
|
}
|
|
2093
|
-
if (!
|
|
2394
|
+
if (!isPlainObject3(raw)) {
|
|
2094
2395
|
warnOnce(`page-data:${key}`, `[sdui] page.data.${key}\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uAC74\uB108\uB701\uB2C8\uB2E4`);
|
|
2095
2396
|
continue;
|
|
2096
2397
|
}
|
|
@@ -2125,7 +2426,7 @@ function pickPath(source, path) {
|
|
|
2125
2426
|
if (path === void 0 || path === "") return source;
|
|
2126
2427
|
let value = source;
|
|
2127
2428
|
for (const segment of path.split(".")) {
|
|
2128
|
-
if (!
|
|
2429
|
+
if (!isPlainObject3(value)) return void 0;
|
|
2129
2430
|
value = value[segment];
|
|
2130
2431
|
}
|
|
2131
2432
|
return value;
|
|
@@ -2156,26 +2457,26 @@ function nearestArgsFrame(scope) {
|
|
|
2156
2457
|
}
|
|
2157
2458
|
return void 0;
|
|
2158
2459
|
}
|
|
2159
|
-
function
|
|
2460
|
+
function isPlainObject4(v) {
|
|
2160
2461
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2161
2462
|
}
|
|
2162
2463
|
function isStateRef(v) {
|
|
2163
|
-
return
|
|
2464
|
+
return isPlainObject4(v) && typeof v.$state === "string";
|
|
2164
2465
|
}
|
|
2165
2466
|
function isItemRef(v) {
|
|
2166
|
-
return
|
|
2467
|
+
return isPlainObject4(v) && "$item" in v;
|
|
2167
2468
|
}
|
|
2168
2469
|
function isIndexRef(v) {
|
|
2169
|
-
return
|
|
2470
|
+
return isPlainObject4(v) && "$index" in v;
|
|
2170
2471
|
}
|
|
2171
2472
|
function isCalcRef(v) {
|
|
2172
|
-
return
|
|
2473
|
+
return isPlainObject4(v) && isPlainObject4(v.$calc);
|
|
2173
2474
|
}
|
|
2174
2475
|
function isArgRef(v) {
|
|
2175
|
-
return
|
|
2476
|
+
return isPlainObject4(v) && typeof v.$arg === "string";
|
|
2176
2477
|
}
|
|
2177
2478
|
function isAction(v) {
|
|
2178
|
-
return
|
|
2479
|
+
return isPlainObject4(v) && typeof v.action === "string";
|
|
2179
2480
|
}
|
|
2180
2481
|
function isActionList(v) {
|
|
2181
2482
|
return Array.isArray(v) && v.length > 0 && v.every(isAction);
|
|
@@ -2199,7 +2500,7 @@ function expandActionEntries(raw, scope) {
|
|
|
2199
2500
|
return [];
|
|
2200
2501
|
}
|
|
2201
2502
|
function eventValue(arg) {
|
|
2202
|
-
if (
|
|
2503
|
+
if (isPlainObject4(arg) && "target" in arg && typeof arg.preventDefault === "function") {
|
|
2203
2504
|
const target = arg.target;
|
|
2204
2505
|
if (target.type === "checkbox") return target.checked;
|
|
2205
2506
|
if (target.type === "number" || target.type === "range") {
|
|
@@ -2211,14 +2512,6 @@ function eventValue(arg) {
|
|
|
2211
2512
|
}
|
|
2212
2513
|
return arg;
|
|
2213
2514
|
}
|
|
2214
|
-
function toNumber2(v) {
|
|
2215
|
-
if (typeof v === "number") return v;
|
|
2216
|
-
if (typeof v === "string") {
|
|
2217
|
-
const n = Number(v.replace(/,/g, ""));
|
|
2218
|
-
return Number.isFinite(n) ? n : 0;
|
|
2219
|
-
}
|
|
2220
|
-
return 0;
|
|
2221
|
-
}
|
|
2222
2515
|
function toIndex(v) {
|
|
2223
2516
|
if (typeof v === "number") return Number.isInteger(v) ? v : null;
|
|
2224
2517
|
if (typeof v === "string" && /^-?\d+$/.test(v.trim())) return Number(v.trim());
|
|
@@ -2317,7 +2610,7 @@ function childrenOf(node) {
|
|
|
2317
2610
|
}
|
|
2318
2611
|
function renderChild(child, index, scope, engine) {
|
|
2319
2612
|
if (typeof child === "string") return child;
|
|
2320
|
-
if (!
|
|
2613
|
+
if (!isPlainObject4(child)) {
|
|
2321
2614
|
warnOnce2(`child:${String(child)}`, `[sdui] \uC798\uBABB\uB41C \uB178\uB4DC(\uBB38\uC790\uC5F4 \uB610\uB294 \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4): ${String(child)}`);
|
|
2322
2615
|
return /* @__PURE__ */ jsx(SpecErrorCard, { children: "[sdui] \uC798\uBABB\uB41C \uB178\uB4DC \u2014 \uBB38\uC790\uC5F4 \uB610\uB294 \uB178\uB4DC \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4" }, index);
|
|
2323
2616
|
}
|
|
@@ -2332,11 +2625,11 @@ function SduiNodeRenderer({
|
|
|
2332
2625
|
engine
|
|
2333
2626
|
}) {
|
|
2334
2627
|
const { registry, resolveValue, dispatch, resolveAsset } = engine;
|
|
2335
|
-
const slots =
|
|
2628
|
+
const slots = isPlainObject4(node.slots) ? node.slots : void 0;
|
|
2336
2629
|
const childList = childrenOf(node);
|
|
2337
2630
|
if (node.component === "ForEach") {
|
|
2338
2631
|
const source = resolveValue(
|
|
2339
|
-
|
|
2632
|
+
isPlainObject4(node.props) ? node.props.source ?? null : null,
|
|
2340
2633
|
scope
|
|
2341
2634
|
);
|
|
2342
2635
|
const rows = Array.isArray(source) ? source : [];
|
|
@@ -2346,7 +2639,7 @@ function SduiNodeRenderer({
|
|
|
2346
2639
|
}
|
|
2347
2640
|
return /* @__PURE__ */ jsx(Fragment, { children: rows.map((item, rowIndex) => {
|
|
2348
2641
|
const rowScope = [...scope, { item, index: rowIndex }];
|
|
2349
|
-
const rowKey =
|
|
2642
|
+
const rowKey = isPlainObject4(item) && typeof item.id === "string" ? item.id : rowIndex;
|
|
2350
2643
|
return /* @__PURE__ */ jsx(React11.Fragment, { children: childList?.map((child, i) => renderChild(child, i, rowScope, engine)) }, rowKey);
|
|
2351
2644
|
}) });
|
|
2352
2645
|
}
|
|
@@ -2365,7 +2658,7 @@ function SduiNodeRenderer({
|
|
|
2365
2658
|
] });
|
|
2366
2659
|
}
|
|
2367
2660
|
const props = {};
|
|
2368
|
-
for (const [name, raw] of Object.entries(
|
|
2661
|
+
for (const [name, raw] of Object.entries(isPlainObject4(node.props) ? node.props : {})) {
|
|
2369
2662
|
if (DENIED_PROPS2.has(name)) {
|
|
2370
2663
|
warnOnce2(`prop:${name}`, `[sdui] \uC2A4\uD399\uC5D0\uC11C \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 \uD504\uB86D: ${name} \u2014 \uBB34\uC2DC\uD569\uB2C8\uB2E4`);
|
|
2371
2664
|
continue;
|
|
@@ -2404,7 +2697,7 @@ function SduiNodeRenderer({
|
|
|
2404
2697
|
if (childLayout) {
|
|
2405
2698
|
for (const name of CHILD_LAYOUT_PROPS) delete props[name];
|
|
2406
2699
|
if (childLayout.style) {
|
|
2407
|
-
props.style =
|
|
2700
|
+
props.style = isPlainObject4(props.style) ? { ...childLayout.style, ...props.style } : childLayout.style;
|
|
2408
2701
|
}
|
|
2409
2702
|
if (childLayout.className) {
|
|
2410
2703
|
props.className = typeof props.className === "string" && props.className ? `${childLayout.className} ${props.className}` : childLayout.className;
|
|
@@ -2428,7 +2721,7 @@ var FRAGMENT_MAX_DEPTH = 4;
|
|
|
2428
2721
|
function SduiFragment({ node, scope, engine }) {
|
|
2429
2722
|
const adapter = useSduiAdapter();
|
|
2430
2723
|
const chain = React11.useContext(SduiFragmentChainContext);
|
|
2431
|
-
const raw =
|
|
2724
|
+
const raw = isPlainObject4(node.props) ? node.props.id : void 0;
|
|
2432
2725
|
const id = engine.resolveValue(raw, scope);
|
|
2433
2726
|
if (typeof id !== "string" || id === "") {
|
|
2434
2727
|
warnOnce2("fragment:id", "[sdui] <Fragment>\uC5D0 \uBB38\uC790\uC5F4 id\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
@@ -2448,8 +2741,8 @@ function SduiFragment({ node, scope, engine }) {
|
|
|
2448
2741
|
);
|
|
2449
2742
|
return null;
|
|
2450
2743
|
}
|
|
2451
|
-
const rawArgs =
|
|
2452
|
-
if (rawArgs !== void 0 && !
|
|
2744
|
+
const rawArgs = isPlainObject4(node.props) ? node.props.args : void 0;
|
|
2745
|
+
if (rawArgs !== void 0 && !isPlainObject4(rawArgs)) {
|
|
2453
2746
|
warnOnce2(`fragment:args:${id}`, `[sdui] <Fragment ${id}>\uC758 args\uB294 \uD3C9\uBA74 \uC624\uBE0C\uC81D\uD2B8\uC5EC\uC57C \uD569\uB2C8\uB2E4 \u2014 \uBB34\uC2DC\uD569\uB2C8\uB2E4`);
|
|
2454
2747
|
}
|
|
2455
2748
|
const useSpec = adapter?.useSpec;
|
|
@@ -2464,7 +2757,7 @@ function SduiFragment({ node, scope, engine }) {
|
|
|
2464
2757
|
SduiFragmentBody,
|
|
2465
2758
|
{
|
|
2466
2759
|
id,
|
|
2467
|
-
args:
|
|
2760
|
+
args: isPlainObject4(rawArgs) ? rawArgs : void 0,
|
|
2468
2761
|
useSpec,
|
|
2469
2762
|
chain,
|
|
2470
2763
|
scope,
|
|
@@ -2485,13 +2778,13 @@ function SduiFragmentBody({
|
|
|
2485
2778
|
const nextChain = React11.useMemo(() => [...chain, id], [chain, id]);
|
|
2486
2779
|
const bodyScope = React11.useMemo(() => [...scope, { args, callSiteScope: scope }], [scope, args]);
|
|
2487
2780
|
React11.useEffect(() => {
|
|
2488
|
-
if (!DEV || !
|
|
2781
|
+
if (!DEV || !isPlainObject4(spec) || !Array.isArray(spec.body)) return;
|
|
2489
2782
|
validateSpec(spec, new Set(Object.keys(engine.registry))).forEach(
|
|
2490
2783
|
(issue) => console.warn(`[sdui:spec:${id}] ${issue.path} \u2014 ${issue.message}`)
|
|
2491
2784
|
);
|
|
2492
2785
|
}, [spec, engine.registry, id]);
|
|
2493
2786
|
if (spec === void 0) return null;
|
|
2494
|
-
if (spec === null || !
|
|
2787
|
+
if (spec === null || !isPlainObject4(spec) || !Array.isArray(spec.body)) {
|
|
2495
2788
|
warnOnce2(`fragment:missing:${id}`, `[sdui] Fragment \uC2A4\uD399\uC744 \uD574\uC11D\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${id} \u2014 \uB80C\uB354\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
|
|
2496
2789
|
return null;
|
|
2497
2790
|
}
|
|
@@ -2621,7 +2914,7 @@ function SduiRenderer({
|
|
|
2621
2914
|
if (head in current) {
|
|
2622
2915
|
let value = current[head];
|
|
2623
2916
|
for (const segment of segments.slice(cut)) {
|
|
2624
|
-
if (!
|
|
2917
|
+
if (!isPlainObject4(value)) return void 0;
|
|
2625
2918
|
value = value[segment];
|
|
2626
2919
|
}
|
|
2627
2920
|
return value;
|
|
@@ -2639,7 +2932,7 @@ function SduiRenderer({
|
|
|
2639
2932
|
const frame = nearestItemFrame(scope);
|
|
2640
2933
|
if (!frame) return null;
|
|
2641
2934
|
if (value.$item === true) return frame.item;
|
|
2642
|
-
return
|
|
2935
|
+
return isPlainObject4(frame.item) ? frame.item[value.$item] ?? null : null;
|
|
2643
2936
|
}
|
|
2644
2937
|
if (isIndexRef(value)) {
|
|
2645
2938
|
return nearestItemFrame(scope)?.index ?? null;
|
|
@@ -2653,64 +2946,17 @@ function SduiRenderer({
|
|
|
2653
2946
|
return void 0;
|
|
2654
2947
|
}
|
|
2655
2948
|
if (isCalcRef(value)) {
|
|
2656
|
-
const
|
|
2657
|
-
const op = typeof
|
|
2658
|
-
if (!Array.isArray(args)) {
|
|
2949
|
+
const calc = value.$calc;
|
|
2950
|
+
const op = typeof calc.op === "string" ? calc.op : "";
|
|
2951
|
+
if (!Array.isArray(calc.args)) {
|
|
2659
2952
|
warnOnce2(`calc:${op}`, `[sdui] $calc(${op || "?"}): args\uB294 \uBC30\uC5F4\uC774\uC5B4\uC57C \uD569\uB2C8\uB2E4 \u2014 \uAC12 \uC5C6\uC74C\uC73C\uB85C \uCC98\uB9AC\uD569\uB2C8\uB2E4`);
|
|
2660
2953
|
return null;
|
|
2661
2954
|
}
|
|
2662
|
-
const
|
|
2663
|
-
|
|
2664
|
-
const nums = (v) => {
|
|
2665
|
-
if (Array.isArray(v))
|
|
2666
|
-
return v.map((row) => field && isPlainObject3(row) ? toNumber2(row[field]) : toNumber2(row));
|
|
2667
|
-
return [toNumber2(v)];
|
|
2668
|
-
};
|
|
2669
|
-
switch (op) {
|
|
2670
|
-
case "sum":
|
|
2671
|
-
return resolved.flatMap(nums).reduce((a, b) => a + b, 0);
|
|
2672
|
-
case "count":
|
|
2673
|
-
return resolved.reduce((a, v) => a + (Array.isArray(v) ? v.length : v == null ? 0 : 1), 0);
|
|
2674
|
-
case "sub": {
|
|
2675
|
-
const list = resolved.map((v) => toNumber2(v));
|
|
2676
|
-
return list.length === 0 ? 0 : list.reduce((a, b) => a - b);
|
|
2677
|
-
}
|
|
2678
|
-
case "mul":
|
|
2679
|
-
return resolved.map((v) => toNumber2(v)).reduce((a, b) => a * b, 1);
|
|
2680
|
-
case "div": {
|
|
2681
|
-
const [a, b] = resolved.map((v) => toNumber2(v));
|
|
2682
|
-
return b === 0 ? 0 : a / b;
|
|
2683
|
-
}
|
|
2684
|
-
case "percent": {
|
|
2685
|
-
const [a, b] = resolved.map((v) => toNumber2(v));
|
|
2686
|
-
return b === 0 ? 0 : Math.round(a / b * 1e3) / 10;
|
|
2687
|
-
}
|
|
2688
|
-
case "concat":
|
|
2689
|
-
return resolved.map((v) => v == null ? "" : String(v)).join("");
|
|
2690
|
-
case "encode":
|
|
2691
|
-
return encodeURIComponent(resolved.map((v) => v == null ? "" : String(v)).join(""));
|
|
2692
|
-
case "eq": {
|
|
2693
|
-
const [a, b] = resolved;
|
|
2694
|
-
return String(a ?? "") === String(b ?? "");
|
|
2695
|
-
}
|
|
2696
|
-
// 수량 비교 — 정원 초과 차단(Button.disabled), 임계값 경고(Show.when) 등
|
|
2697
|
-
case "gt":
|
|
2698
|
-
return toNumber2(resolved[0]) > toNumber2(resolved[1]);
|
|
2699
|
-
case "gte":
|
|
2700
|
-
return toNumber2(resolved[0]) >= toNumber2(resolved[1]);
|
|
2701
|
-
case "lt":
|
|
2702
|
-
return toNumber2(resolved[0]) < toNumber2(resolved[1]);
|
|
2703
|
-
case "lte":
|
|
2704
|
-
return toNumber2(resolved[0]) <= toNumber2(resolved[1]);
|
|
2705
|
-
/** 부정 — 조건을 뒤집어 "없을 때만" 렌더링하는 데 쓴다 */
|
|
2706
|
-
case "not":
|
|
2707
|
-
return !resolved[0];
|
|
2708
|
-
default:
|
|
2709
|
-
return null;
|
|
2710
|
-
}
|
|
2955
|
+
const resolved = calc.args.map((arg) => resolveValue(arg, scope));
|
|
2956
|
+
return evaluateCalc(calc, resolved, (late) => resolveValue(late, scope));
|
|
2711
2957
|
}
|
|
2712
2958
|
if (Array.isArray(value)) return value.map((v) => resolveValue(v, scope));
|
|
2713
|
-
if (
|
|
2959
|
+
if (isPlainObject4(value)) {
|
|
2714
2960
|
const out = {};
|
|
2715
2961
|
for (const [k, v] of Object.entries(value)) {
|
|
2716
2962
|
out[k] = deferChainEntry(value, k) ? v : resolveValue(v, scope);
|
|
@@ -2879,7 +3125,7 @@ function SduiRenderer({
|
|
|
2879
3125
|
break;
|
|
2880
3126
|
}
|
|
2881
3127
|
const row = current[index];
|
|
2882
|
-
if (!
|
|
3128
|
+
if (!isPlainObject4(row)) break;
|
|
2883
3129
|
const nextValue = (action.fromEvent ? eventValue(arg) : action.value) ?? null;
|
|
2884
3130
|
const next = [...current];
|
|
2885
3131
|
next[index] = { ...row, [action.field]: nextValue };
|
|
@@ -3022,4 +3268,4 @@ function SduiRenderer({
|
|
|
3022
3268
|
);
|
|
3023
3269
|
}
|
|
3024
3270
|
|
|
3025
|
-
export { Actions, Can, Col, Divider, Grid, KeyValueList, NodeErrorBoundary, PageHead, RemoteSearchResults, ResultTable, Row, SduiDialog, SduiForm, SduiPermissionProvider, SduiRenderer, SduiSearchDataProvider, SduiSearchResults, SearchResults, Section, Show, SortHandle, SortableList, Spacer, Text, cellRenderer, createRegistry, defaultRegistry, imageRenderer, normalizePageSizes, sortableDropIndex, sortableMove, useRemoteSearchPage, useSduiCan, useSduiDispatch, useSduiRuntime, useSearchFetcher, validateSpec };
|
|
3271
|
+
export { Actions, CALC_OPS, Can, Col, Divider, Grid, KeyValueList, NodeErrorBoundary, PageHead, RemoteSearchResults, ResultTable, Row, SduiDialog, SduiForm, SduiPermissionProvider, SduiRenderer, SduiSearchDataProvider, SduiSearchResults, SearchResults, Section, Show, SortHandle, SortableList, Spacer, Text, cellRenderer, createRegistry, defaultRegistry, imageRenderer, normalizePageSizes, sortableDropIndex, sortableMove, useRemoteSearchPage, useSduiCan, useSduiDispatch, useSduiRuntime, useSearchFetcher, validateSpec };
|