@safe-ugc-ui/react 0.6.0 → 1.1.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/index.d.ts +45 -5
- package/dist/index.js +731 -58
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
// src/UGCRenderer.tsx
|
|
2
|
-
import { useEffect, useMemo as useMemo2, useState as
|
|
2
|
+
import { useEffect as useEffect2, useMemo as useMemo2, useState as useState4 } from "react";
|
|
3
3
|
import { validate, validateRaw } from "@safe-ugc-ui/validator";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
COMPACT_BREAKPOINT_MAX_WIDTH,
|
|
6
|
+
MEDIUM_BREAKPOINT_MAX_WIDTH
|
|
7
|
+
} from "@safe-ugc-ui/types";
|
|
5
8
|
|
|
6
9
|
// src/UGCContainer.tsx
|
|
7
10
|
import { forwardRef } from "react";
|
|
@@ -29,7 +32,9 @@ import {
|
|
|
29
32
|
} from "@safe-ugc-ui/types";
|
|
30
33
|
|
|
31
34
|
// src/state-resolver.ts
|
|
32
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
PROTOTYPE_POLLUTION_SEGMENTS
|
|
37
|
+
} from "@safe-ugc-ui/types";
|
|
33
38
|
function parseRefSegments(path) {
|
|
34
39
|
const segments = [];
|
|
35
40
|
const dotParts = path.split(".");
|
|
@@ -89,6 +94,111 @@ function resolveValue(value, state, locals) {
|
|
|
89
94
|
}
|
|
90
95
|
return value;
|
|
91
96
|
}
|
|
97
|
+
function stringifyTextScalar(value) {
|
|
98
|
+
if (value === void 0) return "";
|
|
99
|
+
if (value === null) return "null";
|
|
100
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
101
|
+
return String(value);
|
|
102
|
+
}
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
function isTemplateObject(value) {
|
|
106
|
+
return typeof value === "object" && value !== null && "$template" in value && Array.isArray(value.$template);
|
|
107
|
+
}
|
|
108
|
+
function resolveTemplate(value, state, locals) {
|
|
109
|
+
if (!isTemplateObject(value)) {
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
return value.$template.map((part) => stringifyTextScalar(resolveValue(part, state, locals))).join("");
|
|
113
|
+
}
|
|
114
|
+
function resolveTextValue(value, state, locals) {
|
|
115
|
+
const template = resolveTemplate(value, state, locals);
|
|
116
|
+
if (template !== void 0) {
|
|
117
|
+
return template;
|
|
118
|
+
}
|
|
119
|
+
return stringifyTextScalar(resolveValue(value, state, locals));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/condition-resolver.ts
|
|
123
|
+
import { MAX_CONDITION_DEPTH, isRef } from "@safe-ugc-ui/types";
|
|
124
|
+
function resolveOperand(operand, state, locals) {
|
|
125
|
+
if (isRef(operand)) {
|
|
126
|
+
const resolved = resolveRef(operand.$ref, state, locals);
|
|
127
|
+
if (resolved === null || typeof resolved === "string" || typeof resolved === "number" || typeof resolved === "boolean") {
|
|
128
|
+
return resolved;
|
|
129
|
+
}
|
|
130
|
+
return void 0;
|
|
131
|
+
}
|
|
132
|
+
return operand;
|
|
133
|
+
}
|
|
134
|
+
function compareValues(op, left, right) {
|
|
135
|
+
if (left === void 0 || right === void 0) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (op === "eq") return left === right;
|
|
139
|
+
if (op === "ne") return left !== right;
|
|
140
|
+
if (left === null || right === null) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (typeof left !== typeof right) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (typeof left !== "number" && typeof left !== "string" || typeof right !== "number" && typeof right !== "string") {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
switch (op) {
|
|
150
|
+
case "gt":
|
|
151
|
+
return left > right;
|
|
152
|
+
case "gte":
|
|
153
|
+
return left >= right;
|
|
154
|
+
case "lt":
|
|
155
|
+
return left < right;
|
|
156
|
+
case "lte":
|
|
157
|
+
return left <= right;
|
|
158
|
+
default:
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function evaluateCondition(condition, state, locals, depth = 1) {
|
|
163
|
+
if (depth > MAX_CONDITION_DEPTH) {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
if (typeof condition === "boolean") {
|
|
167
|
+
return condition;
|
|
168
|
+
}
|
|
169
|
+
if (isRef(condition)) {
|
|
170
|
+
return resolveRef(condition.$ref, state, locals) === true;
|
|
171
|
+
}
|
|
172
|
+
if (typeof condition !== "object" || condition === null || Array.isArray(condition)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const conditionObj = condition;
|
|
176
|
+
switch (conditionObj.op) {
|
|
177
|
+
case "not":
|
|
178
|
+
return !evaluateCondition(conditionObj.value, state, locals, depth + 1);
|
|
179
|
+
case "and":
|
|
180
|
+
return Array.isArray(conditionObj.values) && conditionObj.values.every(
|
|
181
|
+
(value) => evaluateCondition(value, state, locals, depth + 1)
|
|
182
|
+
);
|
|
183
|
+
case "or":
|
|
184
|
+
return Array.isArray(conditionObj.values) && conditionObj.values.some(
|
|
185
|
+
(value) => evaluateCondition(value, state, locals, depth + 1)
|
|
186
|
+
);
|
|
187
|
+
case "eq":
|
|
188
|
+
case "ne":
|
|
189
|
+
case "gt":
|
|
190
|
+
case "gte":
|
|
191
|
+
case "lt":
|
|
192
|
+
case "lte":
|
|
193
|
+
return compareValues(
|
|
194
|
+
conditionObj.op,
|
|
195
|
+
resolveOperand(conditionObj.left, state, locals),
|
|
196
|
+
resolveOperand(conditionObj.right, state, locals)
|
|
197
|
+
);
|
|
198
|
+
default:
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
92
202
|
|
|
93
203
|
// src/style-mapper.ts
|
|
94
204
|
import { ALLOWED_TRANSITION_PROPERTIES } from "@safe-ugc-ui/types";
|
|
@@ -103,6 +213,7 @@ var DIRECT_MAP_PROPS = [
|
|
|
103
213
|
"gap",
|
|
104
214
|
"width",
|
|
105
215
|
"height",
|
|
216
|
+
"aspectRatio",
|
|
106
217
|
"minWidth",
|
|
107
218
|
"maxWidth",
|
|
108
219
|
"minHeight",
|
|
@@ -159,6 +270,19 @@ function containsForbiddenCssFunction(value) {
|
|
|
159
270
|
const lower = value.toLowerCase();
|
|
160
271
|
return FORBIDDEN_CSS_FUNCTIONS_LOWER.some((fn) => lower.includes(fn));
|
|
161
272
|
}
|
|
273
|
+
function isValidAspectRatio(value) {
|
|
274
|
+
if (typeof value === "number") {
|
|
275
|
+
return Number.isFinite(value) && value > 0;
|
|
276
|
+
}
|
|
277
|
+
if (typeof value !== "string" || containsForbiddenCssFunction(value)) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
const match = value.match(/^\s*([0-9]+(?:\.[0-9]+)?)\s*\/\s*([0-9]+(?:\.[0-9]+)?)\s*$/);
|
|
281
|
+
if (!match) {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
return Number(match[1]) > 0 && Number(match[2]) > 0;
|
|
285
|
+
}
|
|
162
286
|
function resolveStyleValue(value, state, locals) {
|
|
163
287
|
return resolveValue(value, state, locals);
|
|
164
288
|
}
|
|
@@ -179,6 +303,19 @@ function resolveStructuredString(value, state, locals) {
|
|
|
179
303
|
}
|
|
180
304
|
return resolved;
|
|
181
305
|
}
|
|
306
|
+
function resolveStructuredLength(value, state, locals) {
|
|
307
|
+
const resolved = resolveStyleValue(value, state, locals);
|
|
308
|
+
if (typeof resolved === "number") {
|
|
309
|
+
return resolved;
|
|
310
|
+
}
|
|
311
|
+
if (typeof resolved === "string" && !containsForbiddenCssFunction(resolved)) {
|
|
312
|
+
return resolved;
|
|
313
|
+
}
|
|
314
|
+
return void 0;
|
|
315
|
+
}
|
|
316
|
+
function toCssLength(value) {
|
|
317
|
+
return typeof value === "number" ? `${value}px` : value;
|
|
318
|
+
}
|
|
182
319
|
function transformToCss(transform) {
|
|
183
320
|
const parts = [];
|
|
184
321
|
if (transform.rotate !== void 0) {
|
|
@@ -347,6 +484,62 @@ function resolveBorderObject(border, state, locals) {
|
|
|
347
484
|
if (color !== void 0) resolved.color = color;
|
|
348
485
|
return resolved;
|
|
349
486
|
}
|
|
487
|
+
function clipPathToCss(clipPath) {
|
|
488
|
+
switch (clipPath.type) {
|
|
489
|
+
case "circle":
|
|
490
|
+
return `circle(${toCssLength(clipPath.radius)})`;
|
|
491
|
+
case "ellipse":
|
|
492
|
+
return `ellipse(${toCssLength(clipPath.rx)} ${toCssLength(clipPath.ry)})`;
|
|
493
|
+
case "inset": {
|
|
494
|
+
const base = [
|
|
495
|
+
toCssLength(clipPath.top),
|
|
496
|
+
toCssLength(clipPath.right),
|
|
497
|
+
toCssLength(clipPath.bottom),
|
|
498
|
+
toCssLength(clipPath.left)
|
|
499
|
+
].join(" ");
|
|
500
|
+
const round = clipPath.round;
|
|
501
|
+
return round !== void 0 ? `inset(${base} round ${toCssLength(round)})` : `inset(${base})`;
|
|
502
|
+
}
|
|
503
|
+
default:
|
|
504
|
+
return "";
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function resolveClipPathObject(clipPath, state, locals) {
|
|
508
|
+
if (!isRecord(clipPath) || typeof clipPath.type !== "string") {
|
|
509
|
+
return void 0;
|
|
510
|
+
}
|
|
511
|
+
switch (clipPath.type) {
|
|
512
|
+
case "circle": {
|
|
513
|
+
const radius = resolveStructuredLength(clipPath.radius, state, locals);
|
|
514
|
+
return radius !== void 0 ? { type: "circle", radius } : void 0;
|
|
515
|
+
}
|
|
516
|
+
case "ellipse": {
|
|
517
|
+
const rx = resolveStructuredLength(clipPath.rx, state, locals);
|
|
518
|
+
const ry = resolveStructuredLength(clipPath.ry, state, locals);
|
|
519
|
+
return rx !== void 0 && ry !== void 0 ? { type: "ellipse", rx, ry } : void 0;
|
|
520
|
+
}
|
|
521
|
+
case "inset": {
|
|
522
|
+
const top = resolveStructuredLength(clipPath.top, state, locals);
|
|
523
|
+
const right = resolveStructuredLength(clipPath.right, state, locals);
|
|
524
|
+
const bottom = resolveStructuredLength(clipPath.bottom, state, locals);
|
|
525
|
+
const left = resolveStructuredLength(clipPath.left, state, locals);
|
|
526
|
+
const round = resolveStructuredLength(clipPath.round, state, locals);
|
|
527
|
+
if (top === void 0 || right === void 0 || bottom === void 0 || left === void 0) {
|
|
528
|
+
return void 0;
|
|
529
|
+
}
|
|
530
|
+
return {
|
|
531
|
+
type: "inset",
|
|
532
|
+
top,
|
|
533
|
+
right,
|
|
534
|
+
bottom,
|
|
535
|
+
left,
|
|
536
|
+
...round !== void 0 ? { round } : {}
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
default:
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
350
543
|
var FLEX_ALIGNMENT_MAP = {
|
|
351
544
|
start: "flex-start",
|
|
352
545
|
end: "flex-end"
|
|
@@ -369,6 +562,9 @@ function mapStyle(style, state, locals) {
|
|
|
369
562
|
if (typeof resolved === "string" && containsForbiddenCssFunction(resolved)) {
|
|
370
563
|
continue;
|
|
371
564
|
}
|
|
565
|
+
if (prop === "aspectRatio" && !isValidAspectRatio(resolved)) {
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
372
568
|
css[prop] = resolved;
|
|
373
569
|
}
|
|
374
570
|
}
|
|
@@ -421,6 +617,17 @@ function mapStyle(style, state, locals) {
|
|
|
421
617
|
css.transition = transitionCss;
|
|
422
618
|
}
|
|
423
619
|
}
|
|
620
|
+
const resolvedBackdropBlur = resolveStructuredNumber(style.backdropBlur, state, locals);
|
|
621
|
+
if (resolvedBackdropBlur !== void 0 && Number.isFinite(resolvedBackdropBlur) && resolvedBackdropBlur >= 0) {
|
|
622
|
+
css.backdropFilter = `blur(${resolvedBackdropBlur}px)`;
|
|
623
|
+
}
|
|
624
|
+
const resolvedClipPath = resolveClipPathObject(style.clipPath, state, locals);
|
|
625
|
+
if (resolvedClipPath) {
|
|
626
|
+
const clipPathCss = clipPathToCss(resolvedClipPath);
|
|
627
|
+
if (clipPathCss) {
|
|
628
|
+
css.clipPath = clipPathCss;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
424
631
|
return css;
|
|
425
632
|
}
|
|
426
633
|
var CSS_PROPERTY_NAME_MAP = {
|
|
@@ -520,9 +727,40 @@ function Column({ style, hoverStyle, children }) {
|
|
|
520
727
|
|
|
521
728
|
// src/components/Text.tsx
|
|
522
729
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
523
|
-
function
|
|
730
|
+
function getClampStyle(maxLines, truncate) {
|
|
731
|
+
if (!maxLines || maxLines < 1) {
|
|
732
|
+
return void 0;
|
|
733
|
+
}
|
|
734
|
+
if (maxLines === 1) {
|
|
735
|
+
return {
|
|
736
|
+
display: "inline-block",
|
|
737
|
+
maxWidth: "100%",
|
|
738
|
+
overflow: "hidden",
|
|
739
|
+
whiteSpace: "nowrap",
|
|
740
|
+
textOverflow: truncate ?? "ellipsis"
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
return {
|
|
744
|
+
display: "-webkit-box",
|
|
745
|
+
maxWidth: "100%",
|
|
746
|
+
overflow: "hidden",
|
|
747
|
+
textOverflow: truncate ?? "ellipsis",
|
|
748
|
+
WebkitBoxOrient: "vertical",
|
|
749
|
+
WebkitLineClamp: maxLines
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function Text({
|
|
753
|
+
content,
|
|
754
|
+
spans,
|
|
755
|
+
maxLines,
|
|
756
|
+
truncate,
|
|
757
|
+
style,
|
|
758
|
+
hoverStyle
|
|
759
|
+
}) {
|
|
524
760
|
const { style: resolvedStyle, onMouseEnter, onMouseLeave } = useHoverStyle(style, hoverStyle);
|
|
525
|
-
|
|
761
|
+
const clampStyle = getClampStyle(maxLines, truncate);
|
|
762
|
+
const mergedStyle = clampStyle ? { ...resolvedStyle, ...clampStyle } : resolvedStyle;
|
|
763
|
+
return /* @__PURE__ */ jsx5("span", { style: mergedStyle, onMouseEnter, onMouseLeave, children: spans?.map((span, index) => /* @__PURE__ */ jsx5("span", { style: span.style, children: span.text }, index)) ?? content ?? "" });
|
|
526
764
|
}
|
|
527
765
|
|
|
528
766
|
// src/components/Image.tsx
|
|
@@ -755,13 +993,279 @@ function Toggle({ value, onToggle, onAction, disabled, style, hoverStyle }) {
|
|
|
755
993
|
);
|
|
756
994
|
}
|
|
757
995
|
|
|
996
|
+
// src/components/Accordion.tsx
|
|
997
|
+
import { useId, useState as useState2 } from "react";
|
|
998
|
+
import { jsx as jsx18, jsxs } from "react/jsx-runtime";
|
|
999
|
+
function getInitialExpandedIds(items, defaultExpanded, allowMultiple) {
|
|
1000
|
+
const enabledIds = new Set(
|
|
1001
|
+
items.filter((item) => item.disabled !== true).map((item) => item.id)
|
|
1002
|
+
);
|
|
1003
|
+
const initial = (defaultExpanded ?? []).filter((id) => enabledIds.has(id));
|
|
1004
|
+
return allowMultiple ? initial : initial.slice(0, 1);
|
|
1005
|
+
}
|
|
1006
|
+
function Accordion({
|
|
1007
|
+
items,
|
|
1008
|
+
allowMultiple = false,
|
|
1009
|
+
defaultExpanded,
|
|
1010
|
+
style,
|
|
1011
|
+
hoverStyle
|
|
1012
|
+
}) {
|
|
1013
|
+
const { style: resolvedStyle, onMouseEnter, onMouseLeave } = useHoverStyle(style, hoverStyle);
|
|
1014
|
+
const [expandedIds, setExpandedIds] = useState2(
|
|
1015
|
+
() => getInitialExpandedIds(items, defaultExpanded, allowMultiple)
|
|
1016
|
+
);
|
|
1017
|
+
const baseId = useId();
|
|
1018
|
+
const expandedSet = new Set(expandedIds);
|
|
1019
|
+
const toggleItem = (itemId, disabled) => {
|
|
1020
|
+
if (disabled) {
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
setExpandedIds((current) => {
|
|
1024
|
+
const currentSet = new Set(current);
|
|
1025
|
+
if (allowMultiple) {
|
|
1026
|
+
if (currentSet.has(itemId)) {
|
|
1027
|
+
currentSet.delete(itemId);
|
|
1028
|
+
} else {
|
|
1029
|
+
currentSet.add(itemId);
|
|
1030
|
+
}
|
|
1031
|
+
return [...currentSet];
|
|
1032
|
+
}
|
|
1033
|
+
return currentSet.has(itemId) ? [] : [itemId];
|
|
1034
|
+
});
|
|
1035
|
+
};
|
|
1036
|
+
return /* @__PURE__ */ jsx18("div", { style: resolvedStyle, onMouseEnter, onMouseLeave, children: items.map((item) => {
|
|
1037
|
+
const expanded = expandedSet.has(item.id);
|
|
1038
|
+
const buttonId = `${baseId}-${item.id}-button`;
|
|
1039
|
+
const panelId = `${baseId}-${item.id}-panel`;
|
|
1040
|
+
return /* @__PURE__ */ jsxs(
|
|
1041
|
+
"div",
|
|
1042
|
+
{
|
|
1043
|
+
style: {
|
|
1044
|
+
borderTop: "1px solid rgba(148, 163, 184, 0.25)"
|
|
1045
|
+
},
|
|
1046
|
+
children: [
|
|
1047
|
+
/* @__PURE__ */ jsxs(
|
|
1048
|
+
"button",
|
|
1049
|
+
{
|
|
1050
|
+
id: buttonId,
|
|
1051
|
+
type: "button",
|
|
1052
|
+
"aria-expanded": expanded,
|
|
1053
|
+
"aria-controls": panelId,
|
|
1054
|
+
disabled: item.disabled,
|
|
1055
|
+
onClick: () => toggleItem(item.id, item.disabled),
|
|
1056
|
+
style: {
|
|
1057
|
+
width: "100%",
|
|
1058
|
+
display: "flex",
|
|
1059
|
+
alignItems: "center",
|
|
1060
|
+
justifyContent: "space-between",
|
|
1061
|
+
padding: "12px 0",
|
|
1062
|
+
background: "transparent",
|
|
1063
|
+
border: "none",
|
|
1064
|
+
color: "inherit",
|
|
1065
|
+
textAlign: "left",
|
|
1066
|
+
cursor: item.disabled ? "default" : "pointer",
|
|
1067
|
+
opacity: item.disabled ? 0.5 : 1
|
|
1068
|
+
},
|
|
1069
|
+
children: [
|
|
1070
|
+
/* @__PURE__ */ jsx18("span", { children: item.label }),
|
|
1071
|
+
/* @__PURE__ */ jsx18("span", { "aria-hidden": "true", children: expanded ? "-" : "+" })
|
|
1072
|
+
]
|
|
1073
|
+
}
|
|
1074
|
+
),
|
|
1075
|
+
expanded ? /* @__PURE__ */ jsx18(
|
|
1076
|
+
"div",
|
|
1077
|
+
{
|
|
1078
|
+
id: panelId,
|
|
1079
|
+
role: "region",
|
|
1080
|
+
"aria-labelledby": buttonId,
|
|
1081
|
+
style: { paddingBottom: 12 },
|
|
1082
|
+
children: item.content
|
|
1083
|
+
}
|
|
1084
|
+
) : null
|
|
1085
|
+
]
|
|
1086
|
+
},
|
|
1087
|
+
item.id
|
|
1088
|
+
);
|
|
1089
|
+
}) });
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// src/components/Tabs.tsx
|
|
1093
|
+
import {
|
|
1094
|
+
useEffect,
|
|
1095
|
+
useId as useId2,
|
|
1096
|
+
useRef,
|
|
1097
|
+
useState as useState3
|
|
1098
|
+
} from "react";
|
|
1099
|
+
import { jsx as jsx19, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1100
|
+
function getEnabledTabIds(tabs) {
|
|
1101
|
+
return tabs.filter((tab) => tab.disabled !== true).map((tab) => tab.id);
|
|
1102
|
+
}
|
|
1103
|
+
function getInitialSelectedTab(tabs, defaultTab) {
|
|
1104
|
+
const enabledIds = getEnabledTabIds(tabs);
|
|
1105
|
+
if (enabledIds.length === 0) {
|
|
1106
|
+
return void 0;
|
|
1107
|
+
}
|
|
1108
|
+
if (defaultTab && enabledIds.includes(defaultTab)) {
|
|
1109
|
+
return defaultTab;
|
|
1110
|
+
}
|
|
1111
|
+
return enabledIds[0];
|
|
1112
|
+
}
|
|
1113
|
+
function getNextEnabledIndex(tabs, startIndex, direction) {
|
|
1114
|
+
for (let offset = 1; offset <= tabs.length; offset++) {
|
|
1115
|
+
const nextIndex = (startIndex + direction * offset + tabs.length) % tabs.length;
|
|
1116
|
+
if (tabs[nextIndex]?.disabled !== true) {
|
|
1117
|
+
return nextIndex;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return startIndex;
|
|
1121
|
+
}
|
|
1122
|
+
function focusTab(buttonRefs, index) {
|
|
1123
|
+
buttonRefs.current[index]?.focus();
|
|
1124
|
+
}
|
|
1125
|
+
function Tabs({
|
|
1126
|
+
tabs,
|
|
1127
|
+
defaultTab,
|
|
1128
|
+
style,
|
|
1129
|
+
hoverStyle
|
|
1130
|
+
}) {
|
|
1131
|
+
const { style: resolvedStyle, onMouseEnter, onMouseLeave } = useHoverStyle(style, hoverStyle);
|
|
1132
|
+
const [selectedTab, setSelectedTab] = useState3(
|
|
1133
|
+
() => getInitialSelectedTab(tabs, defaultTab)
|
|
1134
|
+
);
|
|
1135
|
+
const baseId = useId2();
|
|
1136
|
+
const buttonRefs = useRef([]);
|
|
1137
|
+
useEffect(() => {
|
|
1138
|
+
setSelectedTab((current) => {
|
|
1139
|
+
const enabledIds = getEnabledTabIds(tabs);
|
|
1140
|
+
if (enabledIds.length === 0) {
|
|
1141
|
+
return void 0;
|
|
1142
|
+
}
|
|
1143
|
+
if (current && enabledIds.includes(current)) {
|
|
1144
|
+
return current;
|
|
1145
|
+
}
|
|
1146
|
+
if (defaultTab && enabledIds.includes(defaultTab)) {
|
|
1147
|
+
return defaultTab;
|
|
1148
|
+
}
|
|
1149
|
+
return enabledIds[0];
|
|
1150
|
+
});
|
|
1151
|
+
}, [tabs, defaultTab]);
|
|
1152
|
+
const selectedItem = tabs.find((tab) => tab.id === selectedTab && tab.disabled !== true) ?? tabs.find((tab) => tab.disabled !== true);
|
|
1153
|
+
const activateTab = (index, focus = false) => {
|
|
1154
|
+
const tab = tabs[index];
|
|
1155
|
+
if (!tab || tab.disabled) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
setSelectedTab(tab.id);
|
|
1159
|
+
if (focus) {
|
|
1160
|
+
focusTab(buttonRefs, index);
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
const onTabKeyDown = (event, index) => {
|
|
1164
|
+
switch (event.key) {
|
|
1165
|
+
case "ArrowRight":
|
|
1166
|
+
case "ArrowDown": {
|
|
1167
|
+
event.preventDefault();
|
|
1168
|
+
activateTab(getNextEnabledIndex(tabs, index, 1), true);
|
|
1169
|
+
break;
|
|
1170
|
+
}
|
|
1171
|
+
case "ArrowLeft":
|
|
1172
|
+
case "ArrowUp": {
|
|
1173
|
+
event.preventDefault();
|
|
1174
|
+
activateTab(getNextEnabledIndex(tabs, index, -1), true);
|
|
1175
|
+
break;
|
|
1176
|
+
}
|
|
1177
|
+
case "Home": {
|
|
1178
|
+
event.preventDefault();
|
|
1179
|
+
const firstEnabledIndex = tabs.findIndex((tab) => tab.disabled !== true);
|
|
1180
|
+
if (firstEnabledIndex >= 0) {
|
|
1181
|
+
activateTab(firstEnabledIndex, true);
|
|
1182
|
+
}
|
|
1183
|
+
break;
|
|
1184
|
+
}
|
|
1185
|
+
case "End": {
|
|
1186
|
+
event.preventDefault();
|
|
1187
|
+
const lastEnabledIndex = [...tabs].map((tab, currentIndex) => ({ tab, currentIndex })).reverse().find(({ tab }) => tab.disabled !== true);
|
|
1188
|
+
if (lastEnabledIndex) {
|
|
1189
|
+
activateTab(lastEnabledIndex.currentIndex, true);
|
|
1190
|
+
}
|
|
1191
|
+
break;
|
|
1192
|
+
}
|
|
1193
|
+
default:
|
|
1194
|
+
break;
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
return /* @__PURE__ */ jsxs2("div", { style: resolvedStyle, onMouseEnter, onMouseLeave, children: [
|
|
1198
|
+
/* @__PURE__ */ jsx19(
|
|
1199
|
+
"div",
|
|
1200
|
+
{
|
|
1201
|
+
role: "tablist",
|
|
1202
|
+
"aria-orientation": "horizontal",
|
|
1203
|
+
style: {
|
|
1204
|
+
display: "flex",
|
|
1205
|
+
gap: 8,
|
|
1206
|
+
borderBottom: "1px solid rgba(148, 163, 184, 0.25)",
|
|
1207
|
+
paddingBottom: 8
|
|
1208
|
+
},
|
|
1209
|
+
children: tabs.map((tab, index) => {
|
|
1210
|
+
const selected = selectedItem?.id === tab.id;
|
|
1211
|
+
const tabId = `${baseId}-${tab.id}-tab`;
|
|
1212
|
+
const panelId = `${baseId}-${tab.id}-panel`;
|
|
1213
|
+
return /* @__PURE__ */ jsx19(
|
|
1214
|
+
"button",
|
|
1215
|
+
{
|
|
1216
|
+
ref: (element) => {
|
|
1217
|
+
buttonRefs.current[index] = element;
|
|
1218
|
+
},
|
|
1219
|
+
id: tabId,
|
|
1220
|
+
type: "button",
|
|
1221
|
+
role: "tab",
|
|
1222
|
+
"aria-selected": selected,
|
|
1223
|
+
"aria-controls": panelId,
|
|
1224
|
+
disabled: tab.disabled,
|
|
1225
|
+
tabIndex: selected ? 0 : -1,
|
|
1226
|
+
onClick: () => activateTab(index),
|
|
1227
|
+
onKeyDown: (event) => onTabKeyDown(event, index),
|
|
1228
|
+
style: {
|
|
1229
|
+
padding: "8px 12px",
|
|
1230
|
+
borderRadius: 8,
|
|
1231
|
+
border: "none",
|
|
1232
|
+
background: selected ? "rgba(148, 163, 184, 0.16)" : "transparent",
|
|
1233
|
+
color: "inherit",
|
|
1234
|
+
cursor: tab.disabled ? "default" : "pointer",
|
|
1235
|
+
opacity: tab.disabled ? 0.5 : 1,
|
|
1236
|
+
fontWeight: selected ? 600 : 400
|
|
1237
|
+
},
|
|
1238
|
+
children: tab.label
|
|
1239
|
+
},
|
|
1240
|
+
tab.id
|
|
1241
|
+
);
|
|
1242
|
+
})
|
|
1243
|
+
}
|
|
1244
|
+
),
|
|
1245
|
+
selectedItem ? /* @__PURE__ */ jsx19(
|
|
1246
|
+
"div",
|
|
1247
|
+
{
|
|
1248
|
+
id: `${baseId}-${selectedItem.id}-panel`,
|
|
1249
|
+
role: "tabpanel",
|
|
1250
|
+
"aria-labelledby": `${baseId}-${selectedItem.id}-tab`,
|
|
1251
|
+
style: { paddingTop: 12 },
|
|
1252
|
+
children: selectedItem.content
|
|
1253
|
+
}
|
|
1254
|
+
) : null
|
|
1255
|
+
] });
|
|
1256
|
+
}
|
|
1257
|
+
|
|
758
1258
|
// src/node-renderer.tsx
|
|
759
|
-
import { jsx as
|
|
1259
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
760
1260
|
function isForLoop(obj) {
|
|
761
1261
|
if (obj == null || typeof obj !== "object" || Array.isArray(obj)) return false;
|
|
762
1262
|
const o = obj;
|
|
763
1263
|
return typeof o.for === "string" && typeof o.in === "string" && o.template != null;
|
|
764
1264
|
}
|
|
1265
|
+
function isFragmentUse(obj) {
|
|
1266
|
+
if (obj == null || typeof obj !== "object" || Array.isArray(obj)) return false;
|
|
1267
|
+
return typeof obj.$use === "string";
|
|
1268
|
+
}
|
|
765
1269
|
function utf8ByteLength(str) {
|
|
766
1270
|
let bytes = 0;
|
|
767
1271
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -814,50 +1318,159 @@ function mergeStyleWithCardStyles(nodeStyle, cardStyles) {
|
|
|
814
1318
|
hoverStyle: mergedHoverStyle
|
|
815
1319
|
};
|
|
816
1320
|
}
|
|
817
|
-
function
|
|
1321
|
+
function getResponsiveOverrideStyle(nodeResponsive, mode) {
|
|
818
1322
|
if (!nodeResponsive) return void 0;
|
|
819
|
-
const
|
|
820
|
-
if (
|
|
1323
|
+
const override = nodeResponsive[mode];
|
|
1324
|
+
if (override == null || typeof override !== "object" || Array.isArray(override)) {
|
|
821
1325
|
return void 0;
|
|
822
1326
|
}
|
|
823
|
-
return
|
|
1327
|
+
return override;
|
|
824
1328
|
}
|
|
825
1329
|
function mergeEffectiveNodeStyle(node, ctx) {
|
|
826
1330
|
const baseStyle = mergeStyleWithCardStyles(node.style, ctx.cardStyles);
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
1331
|
+
const mediumOverride = mergeNamedStyle(
|
|
1332
|
+
getResponsiveOverrideStyle(node.responsive, "medium"),
|
|
1333
|
+
ctx.cardStyles
|
|
1334
|
+
);
|
|
830
1335
|
const compactOverride = mergeNamedStyle(
|
|
831
|
-
|
|
1336
|
+
getResponsiveOverrideStyle(node.responsive, "compact"),
|
|
832
1337
|
ctx.cardStyles
|
|
833
1338
|
);
|
|
834
|
-
if (!compactOverride) {
|
|
835
|
-
return baseStyle;
|
|
836
|
-
}
|
|
837
1339
|
const {
|
|
838
|
-
hoverStyle:
|
|
839
|
-
transition:
|
|
1340
|
+
hoverStyle: _mediumHoverStyle,
|
|
1341
|
+
transition: _mediumTransition,
|
|
1342
|
+
...mediumStyleWithoutInteractiveFields
|
|
1343
|
+
} = mediumOverride ?? {};
|
|
1344
|
+
const {
|
|
1345
|
+
hoverStyle: _compactHoverStyle,
|
|
1346
|
+
transition: _compactTransition,
|
|
840
1347
|
...compactStyleWithoutInteractiveFields
|
|
841
|
-
} = compactOverride;
|
|
1348
|
+
} = compactOverride ?? {};
|
|
842
1349
|
return {
|
|
843
1350
|
...baseStyle ?? {},
|
|
844
|
-
...
|
|
1351
|
+
...ctx.responsive.medium ? mediumStyleWithoutInteractiveFields : {},
|
|
1352
|
+
...ctx.responsive.compact ? compactStyleWithoutInteractiveFields : {}
|
|
845
1353
|
};
|
|
846
1354
|
}
|
|
1355
|
+
function resolveTextPayload(node, ctx) {
|
|
1356
|
+
const rawSpans = Array.isArray(node.spans) ? node.spans : void 0;
|
|
1357
|
+
if (rawSpans) {
|
|
1358
|
+
const spans = rawSpans.map((span) => {
|
|
1359
|
+
const rawSpan = span;
|
|
1360
|
+
const spanStyle = rawSpan.style != null && typeof rawSpan.style === "object" && !Array.isArray(rawSpan.style) ? rawSpan.style : void 0;
|
|
1361
|
+
return {
|
|
1362
|
+
text: resolveTextValue(rawSpan.text, ctx.state, ctx.locals),
|
|
1363
|
+
style: spanStyle ? mapStyle(spanStyle, ctx.state, ctx.locals) : void 0,
|
|
1364
|
+
rawStyleBytes: spanStyle ? utf8ByteLength(JSON.stringify(spanStyle)) : 0
|
|
1365
|
+
};
|
|
1366
|
+
});
|
|
1367
|
+
const combinedText = spans.map((span) => span.text).join("");
|
|
1368
|
+
return {
|
|
1369
|
+
spans: spans.map(({ rawStyleBytes: _rawStyleBytes, ...span }) => span),
|
|
1370
|
+
textBytes: utf8ByteLength(combinedText),
|
|
1371
|
+
styleBytes: spans.reduce((sum, span) => sum + span.rawStyleBytes, 0)
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
const content = resolveTextValue(node.content, ctx.state, ctx.locals);
|
|
1375
|
+
return {
|
|
1376
|
+
content,
|
|
1377
|
+
textBytes: utf8ByteLength(content),
|
|
1378
|
+
styleBytes: 0
|
|
1379
|
+
};
|
|
1380
|
+
}
|
|
1381
|
+
function resolveAccordionItems(node, ctx, key) {
|
|
1382
|
+
const rawItems = Array.isArray(node.items) ? node.items : [];
|
|
1383
|
+
return rawItems.flatMap((item, index) => {
|
|
1384
|
+
if (item == null || typeof item !== "object" || Array.isArray(item)) {
|
|
1385
|
+
return [];
|
|
1386
|
+
}
|
|
1387
|
+
const rawItem = item;
|
|
1388
|
+
const id = typeof rawItem.id === "string" ? rawItem.id : `item-${index}`;
|
|
1389
|
+
const label = resolveTextValue(rawItem.label, ctx.state, ctx.locals);
|
|
1390
|
+
const resolvedDisabled = resolveValue(rawItem.disabled, ctx.state, ctx.locals);
|
|
1391
|
+
const disabled = typeof resolvedDisabled === "boolean" ? resolvedDisabled : void 0;
|
|
1392
|
+
const content = renderNode(
|
|
1393
|
+
rawItem.content,
|
|
1394
|
+
ctx,
|
|
1395
|
+
`${String(key)}.items[${index}].content`
|
|
1396
|
+
);
|
|
1397
|
+
return [{ id, label, content, disabled }];
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
function resolveTabsItems(node, ctx, key) {
|
|
1401
|
+
const rawTabs = Array.isArray(node.tabs) ? node.tabs : [];
|
|
1402
|
+
return rawTabs.flatMap((tab, index) => {
|
|
1403
|
+
if (tab == null || typeof tab !== "object" || Array.isArray(tab)) {
|
|
1404
|
+
return [];
|
|
1405
|
+
}
|
|
1406
|
+
const rawTab = tab;
|
|
1407
|
+
const id = typeof rawTab.id === "string" ? rawTab.id : `tab-${index}`;
|
|
1408
|
+
const label = resolveTextValue(rawTab.label, ctx.state, ctx.locals);
|
|
1409
|
+
const resolvedDisabled = resolveValue(rawTab.disabled, ctx.state, ctx.locals);
|
|
1410
|
+
const disabled = typeof resolvedDisabled === "boolean" ? resolvedDisabled : void 0;
|
|
1411
|
+
const content = renderNode(
|
|
1412
|
+
rawTab.content,
|
|
1413
|
+
ctx,
|
|
1414
|
+
`${String(key)}.tabs[${index}].content`
|
|
1415
|
+
);
|
|
1416
|
+
return [{ id, label, content, disabled }];
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
847
1419
|
function renderNode(node, ctx, key) {
|
|
848
1420
|
if (node == null || typeof node !== "object") return null;
|
|
1421
|
+
if (isFragmentUse(node)) {
|
|
1422
|
+
if ("$if" in node && !evaluateCondition(node.$if, ctx.state, ctx.locals)) {
|
|
1423
|
+
return null;
|
|
1424
|
+
}
|
|
1425
|
+
if ((ctx.fragmentStack?.length ?? 0) > 0) {
|
|
1426
|
+
ctx.onError?.([{
|
|
1427
|
+
code: "RUNTIME_FRAGMENT_NESTED_USE",
|
|
1428
|
+
message: 'Fragments may not contain nested "$use" references',
|
|
1429
|
+
path: String(key)
|
|
1430
|
+
}]);
|
|
1431
|
+
return null;
|
|
1432
|
+
}
|
|
1433
|
+
if (ctx.fragmentStack?.includes(node.$use)) {
|
|
1434
|
+
ctx.onError?.([{
|
|
1435
|
+
code: "RUNTIME_FRAGMENT_CYCLE",
|
|
1436
|
+
message: `Fragment "${node.$use}" recursively references itself`,
|
|
1437
|
+
path: String(key)
|
|
1438
|
+
}]);
|
|
1439
|
+
return null;
|
|
1440
|
+
}
|
|
1441
|
+
const fragment = ctx.fragments?.[node.$use];
|
|
1442
|
+
if (fragment == null) {
|
|
1443
|
+
ctx.onError?.([{
|
|
1444
|
+
code: "RUNTIME_FRAGMENT_NOT_FOUND",
|
|
1445
|
+
message: `Fragment "${node.$use}" was not found`,
|
|
1446
|
+
path: String(key)
|
|
1447
|
+
}]);
|
|
1448
|
+
return null;
|
|
1449
|
+
}
|
|
1450
|
+
return renderNode(
|
|
1451
|
+
fragment,
|
|
1452
|
+
{
|
|
1453
|
+
...ctx,
|
|
1454
|
+
fragmentStack: [...ctx.fragmentStack ?? [], node.$use]
|
|
1455
|
+
},
|
|
1456
|
+
key
|
|
1457
|
+
);
|
|
1458
|
+
}
|
|
849
1459
|
const n = node;
|
|
850
1460
|
if (!n.type) return null;
|
|
1461
|
+
if ("$if" in n && !evaluateCondition(n.$if, ctx.state, ctx.locals)) {
|
|
1462
|
+
return null;
|
|
1463
|
+
}
|
|
851
1464
|
const mergedRawStyle = mergeEffectiveNodeStyle(n, ctx);
|
|
852
1465
|
const rv = (val) => resolveValue(val, ctx.state, ctx.locals);
|
|
853
|
-
|
|
1466
|
+
let styleDelta = mergedRawStyle ? utf8ByteLength(JSON.stringify(mergedRawStyle)) : 0;
|
|
854
1467
|
const overflowDelta = mergedRawStyle?.overflow === "auto" ? 1 : 0;
|
|
855
|
-
let
|
|
1468
|
+
let resolvedTextPayload;
|
|
856
1469
|
let textDelta = 0;
|
|
857
1470
|
if (n.type === "Text") {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
1471
|
+
resolvedTextPayload = resolveTextPayload(n, ctx);
|
|
1472
|
+
textDelta = resolvedTextPayload.textBytes;
|
|
1473
|
+
styleDelta += resolvedTextPayload.styleBytes;
|
|
861
1474
|
}
|
|
862
1475
|
if (ctx.limits.nodeCount + 1 > MAX_NODE_COUNT) {
|
|
863
1476
|
ctx.onError?.([{ code: "RUNTIME_NODE_LIMIT", message: `Node count exceeds maximum of ${MAX_NODE_COUNT}`, path: String(key) }]);
|
|
@@ -885,17 +1498,31 @@ function renderNode(node, ctx, key) {
|
|
|
885
1498
|
const childElements = renderChildren(n.children, ctx);
|
|
886
1499
|
switch (n.type) {
|
|
887
1500
|
case "Box":
|
|
888
|
-
return /* @__PURE__ */
|
|
1501
|
+
return /* @__PURE__ */ jsx20(Box, { style: cssStyle, hoverStyle: cssHoverStyle, children: childElements }, key);
|
|
889
1502
|
case "Row":
|
|
890
|
-
return /* @__PURE__ */
|
|
1503
|
+
return /* @__PURE__ */ jsx20(Row, { style: cssStyle, hoverStyle: cssHoverStyle, children: childElements }, key);
|
|
891
1504
|
case "Column":
|
|
892
|
-
return /* @__PURE__ */
|
|
1505
|
+
return /* @__PURE__ */ jsx20(Column, { style: cssStyle, hoverStyle: cssHoverStyle, children: childElements }, key);
|
|
893
1506
|
case "Stack":
|
|
894
|
-
return /* @__PURE__ */
|
|
1507
|
+
return /* @__PURE__ */ jsx20(Stack, { style: cssStyle, hoverStyle: cssHoverStyle, children: childElements }, key);
|
|
895
1508
|
case "Grid":
|
|
896
|
-
return /* @__PURE__ */
|
|
897
|
-
case "Text":
|
|
898
|
-
|
|
1509
|
+
return /* @__PURE__ */ jsx20(Grid, { style: cssStyle, hoverStyle: cssHoverStyle, children: childElements }, key);
|
|
1510
|
+
case "Text": {
|
|
1511
|
+
const maxLines = typeof n.maxLines === "number" ? n.maxLines : void 0;
|
|
1512
|
+
const truncate = n.truncate === "clip" || n.truncate === "ellipsis" ? n.truncate : void 0;
|
|
1513
|
+
return /* @__PURE__ */ jsx20(
|
|
1514
|
+
Text,
|
|
1515
|
+
{
|
|
1516
|
+
content: resolvedTextPayload?.content,
|
|
1517
|
+
spans: resolvedTextPayload?.spans,
|
|
1518
|
+
maxLines,
|
|
1519
|
+
truncate,
|
|
1520
|
+
style: cssStyle,
|
|
1521
|
+
hoverStyle: cssHoverStyle
|
|
1522
|
+
},
|
|
1523
|
+
key
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
899
1526
|
case "Image": {
|
|
900
1527
|
let src = rv(n.src);
|
|
901
1528
|
if (typeof src !== "string" || !src) return null;
|
|
@@ -906,7 +1533,7 @@ function renderNode(node, ctx, key) {
|
|
|
906
1533
|
if (typeof resolved === "string" && resolved.trim().toLowerCase().startsWith("javascript:")) return null;
|
|
907
1534
|
const resolvedAlt = rv(n.alt);
|
|
908
1535
|
const alt = typeof resolvedAlt === "string" ? resolvedAlt : void 0;
|
|
909
|
-
return /* @__PURE__ */
|
|
1536
|
+
return /* @__PURE__ */ jsx20(Image, { src: resolved, alt, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
910
1537
|
}
|
|
911
1538
|
case "Avatar": {
|
|
912
1539
|
let src = rv(n.src);
|
|
@@ -918,7 +1545,7 @@ function renderNode(node, ctx, key) {
|
|
|
918
1545
|
if (typeof resolved === "string" && resolved.trim().toLowerCase().startsWith("javascript:")) return null;
|
|
919
1546
|
const resolvedSize = rv(n.size);
|
|
920
1547
|
const size = typeof resolvedSize === "number" || typeof resolvedSize === "string" ? resolvedSize : void 0;
|
|
921
|
-
return /* @__PURE__ */
|
|
1548
|
+
return /* @__PURE__ */ jsx20(Avatar, { src: resolved, size, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
922
1549
|
}
|
|
923
1550
|
case "Icon": {
|
|
924
1551
|
const resolvedName = rv(n.name);
|
|
@@ -927,7 +1554,7 @@ function renderNode(node, ctx, key) {
|
|
|
927
1554
|
const size = typeof resolvedSize === "number" || typeof resolvedSize === "string" ? resolvedSize : void 0;
|
|
928
1555
|
const resolvedColor = rv(n.color);
|
|
929
1556
|
const color = typeof resolvedColor === "string" ? resolvedColor : void 0;
|
|
930
|
-
return /* @__PURE__ */
|
|
1557
|
+
return /* @__PURE__ */ jsx20(
|
|
931
1558
|
Icon,
|
|
932
1559
|
{
|
|
933
1560
|
name,
|
|
@@ -943,14 +1570,14 @@ function renderNode(node, ctx, key) {
|
|
|
943
1570
|
case "Spacer": {
|
|
944
1571
|
const resolvedSize = rv(n.size);
|
|
945
1572
|
const size = typeof resolvedSize === "number" || typeof resolvedSize === "string" ? resolvedSize : void 0;
|
|
946
|
-
return /* @__PURE__ */
|
|
1573
|
+
return /* @__PURE__ */ jsx20(Spacer, { size, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
947
1574
|
}
|
|
948
1575
|
case "Divider": {
|
|
949
1576
|
const resolvedColor = rv(n.color);
|
|
950
1577
|
const color = typeof resolvedColor === "string" ? resolvedColor : void 0;
|
|
951
1578
|
const resolvedThickness = rv(n.thickness);
|
|
952
1579
|
const thickness = typeof resolvedThickness === "number" || typeof resolvedThickness === "string" ? resolvedThickness : void 0;
|
|
953
|
-
return /* @__PURE__ */
|
|
1580
|
+
return /* @__PURE__ */ jsx20(Divider, { color, thickness, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
954
1581
|
}
|
|
955
1582
|
case "ProgressBar": {
|
|
956
1583
|
const resolvedValue = rv(n.value);
|
|
@@ -959,33 +1586,33 @@ function renderNode(node, ctx, key) {
|
|
|
959
1586
|
const max = typeof resolvedMax === "number" ? resolvedMax : 100;
|
|
960
1587
|
const resolvedColor = rv(n.color);
|
|
961
1588
|
const color = typeof resolvedColor === "string" ? resolvedColor : void 0;
|
|
962
|
-
return /* @__PURE__ */
|
|
1589
|
+
return /* @__PURE__ */ jsx20(ProgressBar, { value, max, color, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
963
1590
|
}
|
|
964
1591
|
case "Badge": {
|
|
965
|
-
const
|
|
966
|
-
const label = typeof resolvedLabel === "string" ? resolvedLabel : "";
|
|
1592
|
+
const label = resolveTextValue(n.label, ctx.state, ctx.locals);
|
|
967
1593
|
const resolvedColor = rv(n.color);
|
|
968
1594
|
const color = typeof resolvedColor === "string" ? resolvedColor : void 0;
|
|
969
|
-
return /* @__PURE__ */
|
|
1595
|
+
return /* @__PURE__ */ jsx20(Badge, { label, color, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
970
1596
|
}
|
|
971
1597
|
case "Chip": {
|
|
972
|
-
const
|
|
973
|
-
const label = typeof resolvedLabel === "string" ? resolvedLabel : "";
|
|
1598
|
+
const label = resolveTextValue(n.label, ctx.state, ctx.locals);
|
|
974
1599
|
const resolvedColor = rv(n.color);
|
|
975
1600
|
const color = typeof resolvedColor === "string" ? resolvedColor : void 0;
|
|
976
|
-
return /* @__PURE__ */
|
|
1601
|
+
return /* @__PURE__ */ jsx20(Chip, { label, color, style: cssStyle, hoverStyle: cssHoverStyle }, key);
|
|
977
1602
|
}
|
|
978
1603
|
case "Button": {
|
|
979
|
-
const
|
|
980
|
-
const label = typeof resolvedLabel === "string" ? resolvedLabel : "";
|
|
1604
|
+
const label = resolveTextValue(n.label, ctx.state, ctx.locals);
|
|
981
1605
|
const actionVal = n.action;
|
|
982
1606
|
const action = typeof actionVal === "string" ? actionVal : "";
|
|
983
|
-
|
|
1607
|
+
const resolvedDisabled = rv(n.disabled);
|
|
1608
|
+
const disabled = typeof resolvedDisabled === "boolean" ? resolvedDisabled : void 0;
|
|
1609
|
+
return /* @__PURE__ */ jsx20(
|
|
984
1610
|
Button,
|
|
985
1611
|
{
|
|
986
1612
|
label,
|
|
987
1613
|
action,
|
|
988
1614
|
onAction: ctx.onAction,
|
|
1615
|
+
disabled,
|
|
989
1616
|
style: cssStyle,
|
|
990
1617
|
hoverStyle: cssHoverStyle
|
|
991
1618
|
},
|
|
@@ -997,12 +1624,47 @@ function renderNode(node, ctx, key) {
|
|
|
997
1624
|
const value = typeof resolvedValue === "boolean" ? resolvedValue : false;
|
|
998
1625
|
const onToggleVal = n.onToggle;
|
|
999
1626
|
const onToggle = typeof onToggleVal === "string" ? onToggleVal : "";
|
|
1000
|
-
|
|
1627
|
+
const resolvedDisabled = rv(n.disabled);
|
|
1628
|
+
const disabled = typeof resolvedDisabled === "boolean" ? resolvedDisabled : void 0;
|
|
1629
|
+
return /* @__PURE__ */ jsx20(
|
|
1001
1630
|
Toggle,
|
|
1002
1631
|
{
|
|
1003
1632
|
value,
|
|
1004
1633
|
onToggle,
|
|
1005
1634
|
onAction: ctx.onAction,
|
|
1635
|
+
disabled,
|
|
1636
|
+
style: cssStyle,
|
|
1637
|
+
hoverStyle: cssHoverStyle
|
|
1638
|
+
},
|
|
1639
|
+
key
|
|
1640
|
+
);
|
|
1641
|
+
}
|
|
1642
|
+
case "Accordion": {
|
|
1643
|
+
const items = resolveAccordionItems(n, ctx, key);
|
|
1644
|
+
const allowMultiple = n.allowMultiple === true;
|
|
1645
|
+
const defaultExpanded = Array.isArray(n.defaultExpanded) ? n.defaultExpanded.filter(
|
|
1646
|
+
(value) => typeof value === "string"
|
|
1647
|
+
) : void 0;
|
|
1648
|
+
return /* @__PURE__ */ jsx20(
|
|
1649
|
+
Accordion,
|
|
1650
|
+
{
|
|
1651
|
+
items,
|
|
1652
|
+
allowMultiple,
|
|
1653
|
+
defaultExpanded,
|
|
1654
|
+
style: cssStyle,
|
|
1655
|
+
hoverStyle: cssHoverStyle
|
|
1656
|
+
},
|
|
1657
|
+
key
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
case "Tabs": {
|
|
1661
|
+
const tabs = resolveTabsItems(n, ctx, key);
|
|
1662
|
+
const defaultTab = typeof n.defaultTab === "string" ? n.defaultTab : void 0;
|
|
1663
|
+
return /* @__PURE__ */ jsx20(
|
|
1664
|
+
Tabs,
|
|
1665
|
+
{
|
|
1666
|
+
tabs,
|
|
1667
|
+
defaultTab,
|
|
1006
1668
|
style: cssStyle,
|
|
1007
1669
|
hoverStyle: cssHoverStyle
|
|
1008
1670
|
},
|
|
@@ -1050,7 +1712,7 @@ function renderForLoop(loop, ctx) {
|
|
|
1050
1712
|
}
|
|
1051
1713
|
return elements;
|
|
1052
1714
|
}
|
|
1053
|
-
function renderTree(rootNode, state, assets, cardStyles, iconResolver, onAction, onError, responsive = { compact: false }) {
|
|
1715
|
+
function renderTree(rootNode, state, assets, cardStyles, iconResolver, onAction, onError, responsive = { compact: false, medium: false }, fragments) {
|
|
1054
1716
|
const limits = {
|
|
1055
1717
|
nodeCount: 0,
|
|
1056
1718
|
textBytes: 0,
|
|
@@ -1061,17 +1723,22 @@ function renderTree(rootNode, state, assets, cardStyles, iconResolver, onAction,
|
|
|
1061
1723
|
state,
|
|
1062
1724
|
assets,
|
|
1063
1725
|
cardStyles,
|
|
1726
|
+
fragments,
|
|
1727
|
+
fragmentStack: [],
|
|
1064
1728
|
iconResolver,
|
|
1065
1729
|
onAction,
|
|
1066
1730
|
onError,
|
|
1067
1731
|
limits,
|
|
1068
|
-
responsive
|
|
1732
|
+
responsive: {
|
|
1733
|
+
compact: responsive.compact,
|
|
1734
|
+
medium: responsive.medium ?? responsive.compact
|
|
1735
|
+
}
|
|
1069
1736
|
};
|
|
1070
1737
|
return renderNode(rootNode, ctx, "root");
|
|
1071
1738
|
}
|
|
1072
1739
|
|
|
1073
1740
|
// src/UGCRenderer.tsx
|
|
1074
|
-
import { jsx as
|
|
1741
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1075
1742
|
function UGCRenderer({
|
|
1076
1743
|
card,
|
|
1077
1744
|
viewName,
|
|
@@ -1082,8 +1749,8 @@ function UGCRenderer({
|
|
|
1082
1749
|
iconResolver,
|
|
1083
1750
|
onAction
|
|
1084
1751
|
}) {
|
|
1085
|
-
const [containerElement, setContainerElement] =
|
|
1086
|
-
const [containerWidth, setContainerWidth] =
|
|
1752
|
+
const [containerElement, setContainerElement] = useState4(null);
|
|
1753
|
+
const [containerWidth, setContainerWidth] = useState4(
|
|
1087
1754
|
typeof window === "undefined" ? null : window.innerWidth
|
|
1088
1755
|
);
|
|
1089
1756
|
const result = useMemo2(() => {
|
|
@@ -1103,14 +1770,16 @@ function UGCRenderer({
|
|
|
1103
1770
|
...stateOverride ?? {}
|
|
1104
1771
|
};
|
|
1105
1772
|
const cardStyles = cardObj.styles;
|
|
1773
|
+
const fragments = cardObj.fragments;
|
|
1106
1774
|
return {
|
|
1107
1775
|
valid: true,
|
|
1108
1776
|
rootNode: views[selectedView],
|
|
1109
1777
|
state: mergedState,
|
|
1110
|
-
cardStyles
|
|
1778
|
+
cardStyles,
|
|
1779
|
+
fragments
|
|
1111
1780
|
};
|
|
1112
1781
|
}, [card, viewName, stateOverride]);
|
|
1113
|
-
|
|
1782
|
+
useEffect2(() => {
|
|
1114
1783
|
if (!containerElement) {
|
|
1115
1784
|
return;
|
|
1116
1785
|
}
|
|
@@ -1136,6 +1805,7 @@ function UGCRenderer({
|
|
|
1136
1805
|
}, [containerElement]);
|
|
1137
1806
|
const responsive = useMemo2(
|
|
1138
1807
|
() => ({
|
|
1808
|
+
medium: containerWidth != null && containerWidth <= MEDIUM_BREAKPOINT_MAX_WIDTH,
|
|
1139
1809
|
compact: containerWidth != null && containerWidth <= COMPACT_BREAKPOINT_MAX_WIDTH
|
|
1140
1810
|
}),
|
|
1141
1811
|
[containerWidth]
|
|
@@ -1146,7 +1816,7 @@ function UGCRenderer({
|
|
|
1146
1816
|
}
|
|
1147
1817
|
return null;
|
|
1148
1818
|
}
|
|
1149
|
-
return /* @__PURE__ */
|
|
1819
|
+
return /* @__PURE__ */ jsx21(UGCContainer, { ref: setContainerElement, style: containerStyle2, children: renderTree(
|
|
1150
1820
|
result.rootNode,
|
|
1151
1821
|
result.state,
|
|
1152
1822
|
assets,
|
|
@@ -1154,10 +1824,12 @@ function UGCRenderer({
|
|
|
1154
1824
|
iconResolver,
|
|
1155
1825
|
onAction,
|
|
1156
1826
|
onError,
|
|
1157
|
-
responsive
|
|
1827
|
+
responsive,
|
|
1828
|
+
result.fragments
|
|
1158
1829
|
) });
|
|
1159
1830
|
}
|
|
1160
1831
|
export {
|
|
1832
|
+
Accordion,
|
|
1161
1833
|
Avatar,
|
|
1162
1834
|
Badge,
|
|
1163
1835
|
Box,
|
|
@@ -1172,6 +1844,7 @@ export {
|
|
|
1172
1844
|
Row,
|
|
1173
1845
|
Spacer,
|
|
1174
1846
|
Stack,
|
|
1847
|
+
Tabs,
|
|
1175
1848
|
Text,
|
|
1176
1849
|
Toggle,
|
|
1177
1850
|
UGCContainer,
|