@bsm-form/react-renderer 0.39.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.js ADDED
@@ -0,0 +1,4992 @@
1
+ // src/renderer/layout-renderer.tsx
2
+ import { adaptLayout } from "@bsm-form/core";
3
+
4
+ // src/renderer/field-renderer.tsx
5
+ import { adaptField } from "@bsm-form/core";
6
+ import {
7
+ fieldAllowsBlurEvent,
8
+ fieldAllowsChangeEvent,
9
+ fieldAllowsCommitEvent
10
+ } from "@bsm-form/schema";
11
+
12
+ // src/registry/field-registry.ts
13
+ import { Checkbox, Switch } from "bsm-design-system";
14
+
15
+ // src/renderer/radio-group-field.tsx
16
+ import { RadioGroup } from "bsm-design-system";
17
+ import { jsx, jsxs } from "react/jsx-runtime";
18
+ function RadioGroupField({
19
+ "aria-describedby": ariaDescribedBy,
20
+ "aria-labelledby": ariaLabelledBy,
21
+ disabled,
22
+ error,
23
+ helperText,
24
+ id,
25
+ label,
26
+ onChange,
27
+ options,
28
+ value,
29
+ ...groupProps
30
+ }) {
31
+ const normalizedOptions = normalizeRadioOptions(options);
32
+ const selectedOption = normalizedOptions.find(
33
+ (option) => Object.is(option.value, value)
34
+ );
35
+ const labelId = label && id ? `${id}-label` : void 0;
36
+ return /* @__PURE__ */ jsxs(
37
+ "fieldset",
38
+ {
39
+ disabled,
40
+ className: "m-0 flex flex-col items-start border-0 p-0",
41
+ children: [
42
+ label ? /* @__PURE__ */ jsx("legend", { id: labelId, className: "mb-1 text-sm text-fg", children: label }) : null,
43
+ /* @__PURE__ */ jsx(
44
+ RadioGroup,
45
+ {
46
+ ...groupProps,
47
+ id,
48
+ value: selectedOption?.controlValue ?? "",
49
+ disabled,
50
+ "aria-invalid": error || void 0,
51
+ "aria-describedby": ariaDescribedBy,
52
+ "aria-labelledby": ariaLabelledBy ?? labelId,
53
+ onChange: (controlValue) => {
54
+ const optionValue = resolveRadioOptionValue(
55
+ normalizedOptions,
56
+ controlValue
57
+ );
58
+ if (optionValue !== void 0) {
59
+ onChange?.(optionValue);
60
+ }
61
+ },
62
+ children: normalizedOptions.map((option) => /* @__PURE__ */ jsx(
63
+ RadioGroup.Item,
64
+ {
65
+ id: id ? `${id}-${option.controlValue}` : void 0,
66
+ value: option.controlValue,
67
+ children: option.label
68
+ },
69
+ option.controlValue
70
+ ))
71
+ }
72
+ ),
73
+ helperText ? /* @__PURE__ */ jsx(
74
+ "p",
75
+ {
76
+ id: ariaDescribedBy,
77
+ role: error ? "alert" : void 0,
78
+ className: `mt-1 text-xs ${error ? "text-fg-error" : "text-fg-tertiary"}`,
79
+ children: helperText
80
+ }
81
+ ) : null
82
+ ]
83
+ }
84
+ );
85
+ }
86
+ function normalizeRadioOptions(options) {
87
+ if (!Array.isArray(options)) {
88
+ return [];
89
+ }
90
+ const normalizedOptions = [];
91
+ options.forEach((option, index) => {
92
+ if (typeof option !== "object" || option === null) {
93
+ return;
94
+ }
95
+ if (!("label" in option) || !("value" in option)) {
96
+ return;
97
+ }
98
+ if (typeof option.label !== "string" && typeof option.label !== "number" || typeof option.value !== "string" && typeof option.value !== "number") {
99
+ return;
100
+ }
101
+ normalizedOptions.push({
102
+ controlValue: `radio-option-${index}`,
103
+ label: String(option.label),
104
+ value: option.value
105
+ });
106
+ });
107
+ return normalizedOptions;
108
+ }
109
+ function resolveRadioOptionValue(options, controlValue) {
110
+ return options.find((option) => option.controlValue === controlValue)?.value;
111
+ }
112
+
113
+ // src/renderer/slider-field.tsx
114
+ import { Slider } from "bsm-design-system";
115
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
116
+ function SliderField({
117
+ "aria-describedby": ariaDescribedBy,
118
+ "aria-labelledby": ariaLabelledBy,
119
+ disabled,
120
+ error,
121
+ helperText,
122
+ id,
123
+ label,
124
+ max,
125
+ min,
126
+ minStepsBetweenThumbs,
127
+ mode,
128
+ onChange,
129
+ onCommit,
130
+ orientation,
131
+ step,
132
+ value,
133
+ variant,
134
+ ...sliderProps
135
+ }) {
136
+ const bounds = normalizeSliderBounds(min, max);
137
+ const resolvedMode = resolveSliderMode(mode, value);
138
+ const componentValue = normalizeSliderComponentValue(
139
+ value,
140
+ resolvedMode,
141
+ bounds.min,
142
+ bounds.max
143
+ );
144
+ const labelId = label && id ? `${id}-label` : void 0;
145
+ const normalizedStep = normalizeSliderStep(step);
146
+ const normalizedMinSteps = normalizeSliderMinSteps(minStepsBetweenThumbs);
147
+ const toValue = (nextValue) => toEngineSliderValue(nextValue, resolvedMode);
148
+ return /* @__PURE__ */ jsxs2(
149
+ "fieldset",
150
+ {
151
+ disabled,
152
+ className: "m-0 flex flex-col items-start border-0 p-0",
153
+ children: [
154
+ label ? /* @__PURE__ */ jsx2("legend", { id: labelId, className: "mb-1 text-sm text-fg", children: label }) : null,
155
+ /* @__PURE__ */ jsx2(
156
+ Slider,
157
+ {
158
+ ...sliderProps,
159
+ id,
160
+ value: componentValue,
161
+ min: bounds.min,
162
+ max: bounds.max,
163
+ step: normalizedStep,
164
+ minStepsBetweenThumbs: normalizedMinSteps,
165
+ orientation: orientation === "vertical" ? "vertical" : "horizontal",
166
+ variant: variant === "secondary" ? "secondary" : "primary",
167
+ disabled,
168
+ "aria-invalid": error || void 0,
169
+ "aria-describedby": ariaDescribedBy,
170
+ "aria-labelledby": ariaLabelledBy ?? labelId,
171
+ onChange: (nextValue) => {
172
+ const engineValue = toValue(nextValue);
173
+ if (engineValue !== void 0) {
174
+ onChange?.(engineValue);
175
+ }
176
+ },
177
+ onValueCommit: (nextValue) => {
178
+ const engineValue = toValue(nextValue);
179
+ if (engineValue !== void 0) {
180
+ onCommit?.(engineValue);
181
+ }
182
+ }
183
+ }
184
+ ),
185
+ helperText ? /* @__PURE__ */ jsx2(
186
+ "p",
187
+ {
188
+ id: ariaDescribedBy,
189
+ role: error ? "alert" : void 0,
190
+ className: `mt-1 text-xs ${error ? "text-fg-error" : "text-fg-tertiary"}`,
191
+ children: helperText
192
+ }
193
+ ) : null
194
+ ]
195
+ }
196
+ );
197
+ }
198
+ function resolveSliderMode(mode, value) {
199
+ if (mode === "single" || mode === "range") {
200
+ return mode;
201
+ }
202
+ return Array.isArray(value) && value.length >= 2 ? "range" : "single";
203
+ }
204
+ function normalizeSliderBounds(min, max) {
205
+ const normalizedMin = isFiniteNumber(min) ? min : 0;
206
+ const normalizedMax = isFiniteNumber(max) ? max : 100;
207
+ return {
208
+ min: normalizedMin,
209
+ max: normalizedMax > normalizedMin ? normalizedMax : normalizedMin + 1
210
+ };
211
+ }
212
+ function normalizeSliderStep(step) {
213
+ return isPositiveFiniteNumber(step) ? step : 1;
214
+ }
215
+ function normalizeSliderMinSteps(minSteps) {
216
+ return isFiniteNumber(minSteps) ? Math.max(0, minSteps) : 0;
217
+ }
218
+ function normalizeSliderComponentValue(value, mode, min, max) {
219
+ if (mode === "single") {
220
+ return [clamp(isFiniteNumber(value) ? value : min, min, max)];
221
+ }
222
+ if (!isSliderRangeValue(value)) {
223
+ return [min, max];
224
+ }
225
+ const first = clamp(value[0], min, max);
226
+ const second = clamp(value[1], min, max);
227
+ return first <= second ? [first, second] : [second, first];
228
+ }
229
+ function toEngineSliderValue(value, mode) {
230
+ if (mode === "single") {
231
+ return isFiniteNumber(value[0]) ? value[0] : void 0;
232
+ }
233
+ if (!isSliderRangeValue(value)) {
234
+ return void 0;
235
+ }
236
+ return value[0] <= value[1] ? [value[0], value[1]] : [value[1], value[0]];
237
+ }
238
+ function isSliderValue(value) {
239
+ return isFiniteNumber(value) || isSliderRangeValue(value);
240
+ }
241
+ function isSliderRangeValue(value) {
242
+ return Array.isArray(value) && value.length === 2 && isFiniteNumber(value[0]) && isFiniteNumber(value[1]);
243
+ }
244
+ function isFiniteNumber(value) {
245
+ return typeof value === "number" && Number.isFinite(value);
246
+ }
247
+ function isPositiveFiniteNumber(value) {
248
+ return isFiniteNumber(value) && value > 0;
249
+ }
250
+ function clamp(value, min, max) {
251
+ return Math.min(Math.max(value, min), max);
252
+ }
253
+
254
+ // src/renderer/time-picker-field.tsx
255
+ import {
256
+ TimePicker
257
+ } from "bsm-design-system";
258
+ import { jsx as jsx3 } from "react/jsx-runtime";
259
+ function TimePickerField({
260
+ "aria-describedby": ariaDescribedBy,
261
+ disabled,
262
+ disabledHours,
263
+ disabledMinutes,
264
+ error,
265
+ helperText,
266
+ id,
267
+ label,
268
+ maxTime,
269
+ minTime,
270
+ onBlur,
271
+ onChange,
272
+ readOnly,
273
+ size,
274
+ value,
275
+ ...timePickerProps
276
+ }) {
277
+ const bounds = normalizeTimeBounds(minTime, maxTime);
278
+ return /* @__PURE__ */ jsx3(
279
+ "fieldset",
280
+ {
281
+ id,
282
+ disabled,
283
+ "aria-describedby": ariaDescribedBy,
284
+ "aria-invalid": error || void 0,
285
+ "aria-readonly": readOnly || void 0,
286
+ onBlur,
287
+ className: "m-0 border-0 p-0",
288
+ children: /* @__PURE__ */ jsx3(
289
+ TimePicker,
290
+ {
291
+ ...timePickerProps,
292
+ value: normalizeTimeComponentValue(value),
293
+ minTime: bounds.minTime,
294
+ maxTime: bounds.maxTime,
295
+ disabledHours: normalizeDisabledTimeParts(disabledHours, "hour"),
296
+ disabledMinutes: normalizeDisabledTimeParts(
297
+ disabledMinutes,
298
+ "minute"
299
+ ),
300
+ size: isTimePickerSize(size) ? size : void 0,
301
+ disabled,
302
+ readOnly,
303
+ error,
304
+ label,
305
+ helperText,
306
+ onChange: (nextValue) => {
307
+ const engineValue = toEngineTimeValue(nextValue);
308
+ if (engineValue !== void 0) {
309
+ onChange?.(engineValue);
310
+ }
311
+ }
312
+ }
313
+ )
314
+ }
315
+ );
316
+ }
317
+ function normalizeTimeComponentValue(value) {
318
+ return normalizeCompleteTime(value) ?? {};
319
+ }
320
+ function toEngineTimeValue(value) {
321
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
322
+ return void 0;
323
+ }
324
+ const hour = "hour" in value ? value.hour : void 0;
325
+ const minute = "minute" in value ? value.minute : void 0;
326
+ const isEmpty = (hour === void 0 || hour === "") && (minute === void 0 || minute === "");
327
+ if (isEmpty) {
328
+ return "";
329
+ }
330
+ return normalizeCompleteTime(value);
331
+ }
332
+ function normalizeTimeFieldValue(value) {
333
+ return value === "" ? "" : toEngineTimeValue(value);
334
+ }
335
+ function normalizeTimeBounds(minTime, maxTime) {
336
+ const normalizedMin = normalizeCompleteTime(minTime);
337
+ const normalizedMax = normalizeCompleteTime(maxTime);
338
+ if (normalizedMin && normalizedMax && toMinutes(normalizedMin) > toMinutes(normalizedMax)) {
339
+ return { minTime: normalizedMax, maxTime: normalizedMin };
340
+ }
341
+ return { minTime: normalizedMin, maxTime: normalizedMax };
342
+ }
343
+ function normalizeDisabledTimeParts(values, part) {
344
+ if (!Array.isArray(values)) {
345
+ return void 0;
346
+ }
347
+ const max = part === "hour" ? 23 : 59;
348
+ const normalizedValues = values.flatMap((value) => {
349
+ const normalizedValue = normalizeTimePart(value, max);
350
+ return normalizedValue === void 0 ? [] : [normalizedValue];
351
+ });
352
+ return [...new Set(normalizedValues)];
353
+ }
354
+ function normalizeCompleteTime(value) {
355
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
356
+ return void 0;
357
+ }
358
+ if (!("hour" in value) || !("minute" in value)) {
359
+ return void 0;
360
+ }
361
+ const hour = normalizeTimePart(value.hour, 23);
362
+ const minute = normalizeTimePart(value.minute, 59);
363
+ return hour !== void 0 && minute !== void 0 ? { hour, minute } : void 0;
364
+ }
365
+ function normalizeTimePart(value, max) {
366
+ if (typeof value !== "string" || !/^\d{1,2}$/.test(value)) {
367
+ return void 0;
368
+ }
369
+ const numericValue = Number(value);
370
+ if (numericValue > max) {
371
+ return void 0;
372
+ }
373
+ return value.padStart(2, "0");
374
+ }
375
+ function isTimePickerSize(size) {
376
+ return size === "xs" || size === "sm" || size === "md" || size === "lg";
377
+ }
378
+ function toMinutes(value) {
379
+ return Number(value.hour) * 60 + Number(value.minute);
380
+ }
381
+
382
+ // src/renderer/input-otp-field.tsx
383
+ import { InputOTP } from "bsm-design-system";
384
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
385
+ var DEFAULT_OTP_LENGTH = 6;
386
+ var MAX_OTP_LENGTH = 32;
387
+ var DEFAULT_OTP_PATTERN = "^\\d+$";
388
+ var OTP_FORMAT_PATTERN = /^[xX#]+(?:[-/ ][xX#]+)*$/;
389
+ function InputOtpField({
390
+ "aria-describedby": ariaDescribedBy,
391
+ "aria-labelledby": ariaLabelledBy,
392
+ disabled,
393
+ error,
394
+ format,
395
+ group,
396
+ helperText,
397
+ id,
398
+ label,
399
+ maxLength,
400
+ onBlur,
401
+ onChange,
402
+ pattern,
403
+ placeholderChar,
404
+ readOnly,
405
+ value,
406
+ ...otpProps
407
+ }) {
408
+ const configuration = normalizeOtpConfiguration(format, maxLength, group);
409
+ const labelId = label && id ? `${id}-label` : void 0;
410
+ const sharedProps = {
411
+ ...otpProps,
412
+ id,
413
+ value: normalizeOtpValue(value, configuration.maxLength),
414
+ pattern: normalizeOtpPattern(pattern),
415
+ placeholderChar: normalizeOtpPlaceholderChar(placeholderChar),
416
+ disabled,
417
+ readOnly,
418
+ "aria-invalid": error || void 0,
419
+ "aria-describedby": ariaDescribedBy,
420
+ "aria-labelledby": ariaLabelledBy ?? labelId,
421
+ onBlur,
422
+ onChange: (nextValue) => {
423
+ onChange?.(normalizeOtpValue(nextValue, configuration.maxLength));
424
+ }
425
+ };
426
+ return /* @__PURE__ */ jsxs3(
427
+ "fieldset",
428
+ {
429
+ disabled,
430
+ "aria-invalid": error || void 0,
431
+ "aria-readonly": readOnly || void 0,
432
+ className: "m-0 flex flex-col items-start border-0 p-0",
433
+ children: [
434
+ label ? /* @__PURE__ */ jsx4("legend", { id: labelId, className: "mb-1 text-sm text-fg", children: label }) : null,
435
+ configuration.format ? /* @__PURE__ */ jsx4(InputOTP, { ...sharedProps, format: configuration.format }) : /* @__PURE__ */ jsx4(
436
+ InputOTP,
437
+ {
438
+ ...sharedProps,
439
+ maxLength: configuration.maxLength,
440
+ group: configuration.group
441
+ }
442
+ ),
443
+ helperText ? /* @__PURE__ */ jsx4(
444
+ "p",
445
+ {
446
+ id: ariaDescribedBy,
447
+ role: error ? "alert" : void 0,
448
+ className: `mt-1 text-xs ${disabled ? "text-fg-disabled" : error ? "text-fg-error" : "text-fg-tertiary"}`,
449
+ children: helperText
450
+ }
451
+ ) : null
452
+ ]
453
+ }
454
+ );
455
+ }
456
+ function normalizeOtpConfiguration(format, maxLength, group) {
457
+ const normalizedFormat = normalizeOtpFormat(format);
458
+ if (normalizedFormat) {
459
+ return {
460
+ format: normalizedFormat,
461
+ maxLength: countOtpFormatSlots(normalizedFormat)
462
+ };
463
+ }
464
+ const normalizedMaxLength = normalizeOtpMaxLength(maxLength);
465
+ return {
466
+ maxLength: normalizedMaxLength,
467
+ group: normalizeOtpGroup(group, normalizedMaxLength)
468
+ };
469
+ }
470
+ function normalizeOtpValue(value, maxLength) {
471
+ return typeof value === "string" ? value.slice(0, maxLength) : "";
472
+ }
473
+ function normalizeOtpPattern(pattern) {
474
+ if (typeof pattern !== "string" || pattern.length === 0) {
475
+ return DEFAULT_OTP_PATTERN;
476
+ }
477
+ try {
478
+ new RegExp(pattern);
479
+ return pattern;
480
+ } catch {
481
+ return DEFAULT_OTP_PATTERN;
482
+ }
483
+ }
484
+ function normalizeOtpFormat(format) {
485
+ if (typeof format !== "string" || !OTP_FORMAT_PATTERN.test(format)) {
486
+ return void 0;
487
+ }
488
+ const slotCount = countOtpFormatSlots(format);
489
+ return slotCount <= MAX_OTP_LENGTH ? format : void 0;
490
+ }
491
+ function normalizeOtpMaxLength(maxLength) {
492
+ if (typeof maxLength !== "number" || !Number.isFinite(maxLength)) {
493
+ return DEFAULT_OTP_LENGTH;
494
+ }
495
+ return Math.min(
496
+ Math.max(Math.trunc(maxLength), 1),
497
+ MAX_OTP_LENGTH
498
+ );
499
+ }
500
+ function normalizeOtpGroup(group, maxLength) {
501
+ if (!Array.isArray(group) || group.length === 0) {
502
+ return void 0;
503
+ }
504
+ const normalizedGroup = group.filter(
505
+ (size) => typeof size === "number" && Number.isInteger(size) && size > 0
506
+ );
507
+ const totalLength = normalizedGroup.reduce((total, size) => total + size, 0);
508
+ return normalizedGroup.length === group.length && totalLength === maxLength ? normalizedGroup : void 0;
509
+ }
510
+ function normalizeOtpPlaceholderChar(placeholderChar) {
511
+ if (placeholderChar === null) {
512
+ return null;
513
+ }
514
+ if (typeof placeholderChar !== "string" || placeholderChar.length === 0) {
515
+ return void 0;
516
+ }
517
+ return [...placeholderChar][0];
518
+ }
519
+ function countOtpFormatSlots(format) {
520
+ return [...format].filter(
521
+ (character) => character === "x" || character === "X" || character === "#"
522
+ ).length;
523
+ }
524
+
525
+ // src/renderer/select-field.tsx
526
+ import { Select } from "bsm-design-system";
527
+ import { jsx as jsx5 } from "react/jsx-runtime";
528
+ function SelectField({
529
+ "aria-describedby": ariaDescribedBy,
530
+ "aria-labelledby": ariaLabelledBy,
531
+ asyncSearch,
532
+ className,
533
+ clearable,
534
+ contentDirection,
535
+ disabled,
536
+ emptyText,
537
+ error,
538
+ helperText,
539
+ hint,
540
+ id,
541
+ label,
542
+ loading,
543
+ mode,
544
+ onBlur,
545
+ onChange,
546
+ onSearch,
547
+ options,
548
+ placeholder,
549
+ readOnly,
550
+ rounded,
551
+ scrollContent,
552
+ searchable,
553
+ size,
554
+ value
555
+ }) {
556
+ const normalizedOptions = normalizeSelectOptions(options);
557
+ const resolvedMode = normalizeSelectMode(mode);
558
+ const componentOptions = normalizedOptions.map((option) => ({
559
+ label: option.label,
560
+ value: option.controlValue
561
+ }));
562
+ const componentValue = toComponentSelectValue(
563
+ value,
564
+ normalizedOptions,
565
+ resolvedMode
566
+ );
567
+ const normalizedDisabled = disabled === true;
568
+ const normalizedReadOnly = readOnly === true;
569
+ const sharedProps = {
570
+ id,
571
+ asyncSearch: asyncSearch === true,
572
+ className: typeof className === "string" ? className : void 0,
573
+ clearable: typeof clearable === "boolean" ? clearable : void 0,
574
+ contentDirection: contentDirection === "ltr" || contentDirection === "rtl" ? contentDirection : void 0,
575
+ disabled: normalizedDisabled,
576
+ emptyText: typeof emptyText === "string" ? emptyText : void 0,
577
+ error: error === true,
578
+ helperText: typeof helperText === "string" ? helperText : void 0,
579
+ hint: typeof hint === "string" ? hint : void 0,
580
+ label: typeof label === "string" ? label : void 0,
581
+ loading: loading === true,
582
+ onSearch: typeof onSearch === "function" ? onSearch : void 0,
583
+ placeholder: typeof placeholder === "string" ? placeholder : void 0,
584
+ readOnly: normalizedReadOnly,
585
+ rounded: rounded === true,
586
+ scrollContent: scrollContent === true,
587
+ searchable: searchable === true,
588
+ size: isSelectSize(size) ? size : void 0,
589
+ "aria-describedby": ariaDescribedBy,
590
+ "aria-labelledby": ariaLabelledBy,
591
+ "aria-invalid": error === true || void 0,
592
+ "aria-readonly": normalizedReadOnly || void 0,
593
+ onBlur
594
+ };
595
+ const handleChange = (nextValue) => {
596
+ if (normalizedDisabled || normalizedReadOnly) {
597
+ return;
598
+ }
599
+ const engineValue = toEngineSelectValue(
600
+ nextValue,
601
+ normalizedOptions,
602
+ resolvedMode
603
+ );
604
+ if (engineValue !== void 0) {
605
+ onChange?.(engineValue);
606
+ }
607
+ };
608
+ if (resolvedMode === "multi") {
609
+ return /* @__PURE__ */ jsx5(
610
+ Select,
611
+ {
612
+ ...sharedProps,
613
+ mode: "multi",
614
+ options: componentOptions,
615
+ value: componentValue,
616
+ onChange: handleChange
617
+ }
618
+ );
619
+ }
620
+ return /* @__PURE__ */ jsx5(
621
+ Select,
622
+ {
623
+ ...sharedProps,
624
+ mode: "select",
625
+ options: componentOptions,
626
+ value: componentValue,
627
+ onChange: handleChange
628
+ }
629
+ );
630
+ }
631
+ function normalizeSelectMode(mode) {
632
+ return mode === "multi" ? "multi" : "select";
633
+ }
634
+ function normalizeSelectOptions(options) {
635
+ if (!Array.isArray(options)) {
636
+ return [];
637
+ }
638
+ const normalizedOptions = [];
639
+ options.forEach((option, index) => {
640
+ if (typeof option !== "object" || option === null || !("label" in option) || !("value" in option) || typeof option.label !== "string" && typeof option.label !== "number" || !isSelectOptionValue(option.value) || option.value === "") {
641
+ return;
642
+ }
643
+ if (normalizedOptions.some(
644
+ (candidate) => selectValuesEqual(candidate.value, option.value)
645
+ )) {
646
+ return;
647
+ }
648
+ normalizedOptions.push({
649
+ controlValue: `select-option-${index}`,
650
+ label: String(option.label),
651
+ value: option.value
652
+ });
653
+ });
654
+ return normalizedOptions;
655
+ }
656
+ function toComponentSelectValue(value, options, mode) {
657
+ if (mode === "multi") {
658
+ if (!Array.isArray(value)) {
659
+ return [];
660
+ }
661
+ const selectedControlValues = value.flatMap((item) => {
662
+ const option = options.find(
663
+ (candidate) => selectValuesEqual(candidate.value, item)
664
+ );
665
+ return option ? [option.controlValue] : [];
666
+ });
667
+ return [...new Set(selectedControlValues)];
668
+ }
669
+ if (!isSelectOptionValue(value)) {
670
+ return void 0;
671
+ }
672
+ return options.find((option) => selectValuesEqual(option.value, value))?.controlValue;
673
+ }
674
+ function toEngineSelectValue(value, options, mode) {
675
+ if (mode === "multi") {
676
+ if (!Array.isArray(value)) {
677
+ return void 0;
678
+ }
679
+ const engineValues = [];
680
+ for (const controlValue of value) {
681
+ if (typeof controlValue !== "string") {
682
+ return void 0;
683
+ }
684
+ const option = options.find(
685
+ (candidate) => candidate.controlValue === controlValue
686
+ );
687
+ if (!option) {
688
+ return void 0;
689
+ }
690
+ if (!engineValues.some((item) => selectValuesEqual(item, option.value))) {
691
+ engineValues.push(option.value);
692
+ }
693
+ }
694
+ return engineValues;
695
+ }
696
+ if (value === void 0 || value === null || value === "") {
697
+ return "";
698
+ }
699
+ if (typeof value !== "string") {
700
+ return void 0;
701
+ }
702
+ return options.find((option) => option.controlValue === value)?.value;
703
+ }
704
+ function isSelectValue(value) {
705
+ return isSelectOptionValue(value) || Array.isArray(value) && value.every(isSelectOptionValue);
706
+ }
707
+ function isSelectOptionValue(value) {
708
+ return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
709
+ }
710
+ function selectValuesEqual(first, second) {
711
+ return first === second;
712
+ }
713
+ function isSelectSize(value) {
714
+ return value === "xs" || value === "sm" || value === "md" || value === "lg";
715
+ }
716
+
717
+ // src/renderer/text-fields.tsx
718
+ import {
719
+ Input,
720
+ Textarea
721
+ } from "bsm-design-system";
722
+ import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
723
+ function TextInputField(props) {
724
+ return /* @__PURE__ */ jsx6(
725
+ InputFieldControl,
726
+ {
727
+ ...props,
728
+ inputType: typeof props.type === "string" ? props.type : "text"
729
+ }
730
+ );
731
+ }
732
+ function NumberInputField(props) {
733
+ return /* @__PURE__ */ jsx6(InputFieldControl, { ...props, inputType: "number" });
734
+ }
735
+ function TextareaField({
736
+ "aria-describedby": ariaDescribedBy,
737
+ "aria-label": ariaLabel,
738
+ "aria-labelledby": ariaLabelledBy,
739
+ className,
740
+ error,
741
+ helperText,
742
+ id,
743
+ label,
744
+ value,
745
+ ...props
746
+ }) {
747
+ const helperTextId = helperText && id ? `${id}-helper-text` : void 0;
748
+ const descriptionIds = mergeDescriptionIds(
749
+ ariaDescribedBy,
750
+ helperTextId
751
+ );
752
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
753
+ /* @__PURE__ */ jsx6(
754
+ Textarea,
755
+ {
756
+ ...props,
757
+ className: typeof className === "string" ? className : "",
758
+ id,
759
+ value: normalizeTextFieldValue(value),
760
+ label,
761
+ helperText,
762
+ error: error === true,
763
+ "aria-label": ariaLabel ?? (!ariaLabelledBy ? normalizeAccessibleText(label) : void 0),
764
+ "aria-labelledby": ariaLabelledBy,
765
+ "aria-describedby": descriptionIds,
766
+ "aria-invalid": error === true || void 0
767
+ }
768
+ ),
769
+ /* @__PURE__ */ jsx6(
770
+ AssistiveHelperText,
771
+ {
772
+ id: helperTextId,
773
+ error: error === true,
774
+ text: helperText
775
+ }
776
+ )
777
+ ] });
778
+ }
779
+ function normalizeTextFieldValue(value) {
780
+ if (typeof value === "string") {
781
+ return value;
782
+ }
783
+ return typeof value === "number" && Number.isFinite(value) ? value : "";
784
+ }
785
+ function InputFieldControl({
786
+ "aria-describedby": ariaDescribedBy,
787
+ "aria-label": ariaLabel,
788
+ "aria-labelledby": ariaLabelledBy,
789
+ className,
790
+ error,
791
+ helperText,
792
+ hint,
793
+ id,
794
+ inputType,
795
+ label,
796
+ value,
797
+ ...props
798
+ }) {
799
+ const helperTextId = helperText && id ? `${id}-helper-text` : void 0;
800
+ const descriptionIds = mergeDescriptionIds(
801
+ ariaDescribedBy,
802
+ helperTextId
803
+ );
804
+ const accessibleLabel = normalizeAccessibleText(label, hint);
805
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
806
+ /* @__PURE__ */ jsx6(
807
+ Input,
808
+ {
809
+ ...props,
810
+ className: typeof className === "string" ? className : "",
811
+ id,
812
+ type: inputType,
813
+ value: normalizeTextFieldValue(value),
814
+ label,
815
+ hint,
816
+ helperText,
817
+ error: error === true,
818
+ "aria-label": ariaLabel ?? (!ariaLabelledBy ? accessibleLabel : void 0),
819
+ "aria-labelledby": ariaLabelledBy,
820
+ "aria-describedby": descriptionIds,
821
+ "aria-invalid": error === true || void 0
822
+ }
823
+ ),
824
+ /* @__PURE__ */ jsx6(
825
+ AssistiveHelperText,
826
+ {
827
+ id: helperTextId,
828
+ error: error === true,
829
+ text: helperText
830
+ }
831
+ )
832
+ ] });
833
+ }
834
+ function AssistiveHelperText({
835
+ error,
836
+ id,
837
+ text
838
+ }) {
839
+ if (!id || !text) {
840
+ return null;
841
+ }
842
+ return /* @__PURE__ */ jsx6("span", { id, role: error ? "alert" : void 0, className: "sr-only", children: text });
843
+ }
844
+ function mergeDescriptionIds(...ids) {
845
+ const uniqueIds = new Set(
846
+ ids.flatMap((id) => typeof id === "string" ? id.split(/\s+/) : [])
847
+ );
848
+ return uniqueIds.size > 0 ? [...uniqueIds].join(" ") : void 0;
849
+ }
850
+ function normalizeAccessibleText(...parts) {
851
+ const text = parts.filter((part) => Boolean(part)).join(" ").trim();
852
+ return text || void 0;
853
+ }
854
+
855
+ // src/renderer/segment-button-field.tsx
856
+ import { SegmentButton } from "bsm-design-system";
857
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
858
+ function SegmentButtonField({
859
+ "aria-describedby": ariaDescribedBy,
860
+ ariaLabel,
861
+ className,
862
+ disabled,
863
+ error,
864
+ fullWidth,
865
+ helperText,
866
+ hint,
867
+ id,
868
+ label,
869
+ onBlur,
870
+ onChange,
871
+ options,
872
+ readOnly,
873
+ rounded,
874
+ size,
875
+ value
876
+ }) {
877
+ const normalizedOptions = normalizeSegmentButtonOptions(options);
878
+ const normalizedDisabled = disabled === true;
879
+ const normalizedReadOnly = readOnly === true;
880
+ const normalizedLabel = normalizeText(label);
881
+ const normalizedHint = normalizeText(hint);
882
+ const normalizedHelperText = normalizeText(helperText);
883
+ const labelId = normalizedLabel && id ? `${id}-label` : void 0;
884
+ const componentValue = toComponentSegmentButtonValue(
885
+ value,
886
+ normalizedOptions
887
+ );
888
+ return /* @__PURE__ */ jsxs5(
889
+ "fieldset",
890
+ {
891
+ id,
892
+ disabled: normalizedDisabled,
893
+ onBlur,
894
+ className: "m-0 flex flex-col items-start border-0 p-0",
895
+ children: [
896
+ normalizedLabel ? /* @__PURE__ */ jsxs5(
897
+ "legend",
898
+ {
899
+ id: labelId,
900
+ className: "mb-1 flex items-center gap-1 text-sm text-fg",
901
+ children: [
902
+ /* @__PURE__ */ jsx7("span", { children: normalizedLabel }),
903
+ normalizedHint ? /* @__PURE__ */ jsx7("span", { className: "text-fg-tertiary", children: normalizedHint }) : null
904
+ ]
905
+ }
906
+ ) : null,
907
+ /* @__PURE__ */ jsx7(
908
+ SegmentButton,
909
+ {
910
+ value: componentValue ?? "",
911
+ size: normalizeSegmentButtonSize(size),
912
+ disabled: normalizedDisabled,
913
+ rounded: rounded === true,
914
+ fullWidth: fullWidth === true,
915
+ className: normalizeClassName(className),
916
+ "aria-invalid": error === true || void 0,
917
+ "aria-readonly": normalizedReadOnly || void 0,
918
+ "aria-describedby": ariaDescribedBy,
919
+ "aria-labelledby": labelId,
920
+ "aria-label": labelId ? void 0 : normalizeText(ariaLabel),
921
+ onChange: (controlValue) => {
922
+ if (normalizedDisabled || normalizedReadOnly) {
923
+ return;
924
+ }
925
+ const optionValue = toEngineSegmentButtonValue(
926
+ controlValue,
927
+ normalizedOptions
928
+ );
929
+ if (optionValue !== void 0) {
930
+ onChange?.(optionValue);
931
+ }
932
+ },
933
+ children: normalizedOptions.map((option) => {
934
+ const itemDisabled = normalizedDisabled || option.disabled;
935
+ return /* @__PURE__ */ jsx7(
936
+ SegmentButton.Item,
937
+ {
938
+ value: option.controlValue,
939
+ disabled: itemDisabled,
940
+ "aria-disabled": itemDisabled || void 0,
941
+ tabIndex: itemDisabled ? -1 : void 0,
942
+ children: option.label
943
+ },
944
+ option.controlValue
945
+ );
946
+ })
947
+ }
948
+ ),
949
+ normalizedHelperText ? /* @__PURE__ */ jsx7(
950
+ "p",
951
+ {
952
+ id: ariaDescribedBy,
953
+ role: error === true ? "alert" : void 0,
954
+ className: `mt-1 text-xs ${normalizedDisabled ? "text-fg-disabled" : error === true ? "text-fg-error" : "text-fg-tertiary"}`,
955
+ children: normalizedHelperText
956
+ }
957
+ ) : null
958
+ ]
959
+ }
960
+ );
961
+ }
962
+ function normalizeSegmentButtonOptions(options) {
963
+ if (!Array.isArray(options)) {
964
+ return [];
965
+ }
966
+ const normalizedOptions = [];
967
+ options.forEach((option, index) => {
968
+ if (typeof option !== "object" || option === null || !("label" in option) || !("value" in option)) {
969
+ return;
970
+ }
971
+ const label = normalizeOptionLabel(option.label);
972
+ if (!label || !isNonEmptySegmentButtonValue(option.value)) {
973
+ return;
974
+ }
975
+ if (normalizedOptions.some((candidate) => candidate.value === option.value)) {
976
+ return;
977
+ }
978
+ normalizedOptions.push({
979
+ controlValue: `segment-option-${index}`,
980
+ label,
981
+ value: option.value,
982
+ disabled: "disabled" in option && option.disabled === true
983
+ });
984
+ });
985
+ return normalizedOptions;
986
+ }
987
+ function normalizeSegmentButtonSize(value) {
988
+ return value === "xs" || value === "sm" || value === "lg" ? value : "md";
989
+ }
990
+ function toComponentSegmentButtonValue(value, options) {
991
+ return options.find((option) => option.value === value)?.controlValue;
992
+ }
993
+ function toEngineSegmentButtonValue(controlValue, options) {
994
+ if (typeof controlValue !== "string") {
995
+ return void 0;
996
+ }
997
+ const option = options.find(
998
+ (candidate) => candidate.controlValue === controlValue
999
+ );
1000
+ return option && !option.disabled ? option.value : void 0;
1001
+ }
1002
+ function isSegmentButtonValue(value) {
1003
+ return typeof value === "string" || typeof value === "number" && Number.isFinite(value);
1004
+ }
1005
+ function isNonEmptySegmentButtonValue(value) {
1006
+ return isSegmentButtonValue(value) && value !== "";
1007
+ }
1008
+ function normalizeOptionLabel(value) {
1009
+ if (typeof value !== "string" && typeof value !== "number") {
1010
+ return void 0;
1011
+ }
1012
+ const label = String(value).trim();
1013
+ return label || void 0;
1014
+ }
1015
+ function normalizeText(value) {
1016
+ if (typeof value !== "string") {
1017
+ return void 0;
1018
+ }
1019
+ const text = value.trim();
1020
+ return text || void 0;
1021
+ }
1022
+ function normalizeClassName(value) {
1023
+ return typeof value === "string" ? value.trim() || void 0 : void 0;
1024
+ }
1025
+
1026
+ // src/registry/field-registry.ts
1027
+ var FIELD_CHANGE_IGNORED = /* @__PURE__ */ Symbol("FIELD_CHANGE_IGNORED");
1028
+ var eventValueDefinition = (component) => ({
1029
+ component,
1030
+ toEngineValue: readEventValue
1031
+ });
1032
+ var fieldRegistry = {
1033
+ text: eventValueDefinition(TextInputField),
1034
+ number: eventValueDefinition(NumberInputField),
1035
+ textarea: eventValueDefinition(TextareaField),
1036
+ select: {
1037
+ component: SelectField,
1038
+ toEngineValue: (value) => isSelectValue(value) ? value : FIELD_CHANGE_IGNORED
1039
+ },
1040
+ checkbox: {
1041
+ component: Checkbox,
1042
+ toEngineValue: (value) => isCheckboxValue(value) ? value : FIELD_CHANGE_IGNORED,
1043
+ toComponentProps: (props) => {
1044
+ const componentProps = { ...props };
1045
+ const checked = isCheckboxValue(props.value) ? props.value : false;
1046
+ delete componentProps.value;
1047
+ delete componentProps.error;
1048
+ delete componentProps.helperText;
1049
+ return {
1050
+ ...componentProps,
1051
+ checked,
1052
+ "aria-invalid": props.error === true
1053
+ };
1054
+ },
1055
+ rendersHelperText: false
1056
+ },
1057
+ switch: {
1058
+ component: Switch,
1059
+ toEngineValue: (value) => typeof value === "boolean" ? value : FIELD_CHANGE_IGNORED,
1060
+ toComponentProps: (props) => {
1061
+ const componentProps = { ...props };
1062
+ delete componentProps.value;
1063
+ delete componentProps.error;
1064
+ delete componentProps.helperText;
1065
+ delete componentProps.label;
1066
+ return {
1067
+ ...componentProps,
1068
+ checked: typeof props.value === "boolean" ? props.value : false,
1069
+ "aria-invalid": props.error === true
1070
+ };
1071
+ },
1072
+ rendersHelperText: false,
1073
+ rendersLabel: false
1074
+ },
1075
+ radio: {
1076
+ component: RadioGroupField,
1077
+ toEngineValue: (value) => typeof value === "string" || typeof value === "number" ? value : FIELD_CHANGE_IGNORED
1078
+ },
1079
+ "segment-button": {
1080
+ component: SegmentButtonField,
1081
+ toEngineValue: (value) => isSegmentButtonValue(value) ? value : FIELD_CHANGE_IGNORED
1082
+ },
1083
+ slider: {
1084
+ component: SliderField,
1085
+ toEngineValue: (value) => isSliderValue(value) ? value : FIELD_CHANGE_IGNORED
1086
+ },
1087
+ time: {
1088
+ component: TimePickerField,
1089
+ toEngineValue: (value) => {
1090
+ const normalizedValue = normalizeTimeFieldValue(value);
1091
+ return normalizedValue === void 0 ? FIELD_CHANGE_IGNORED : normalizedValue;
1092
+ }
1093
+ },
1094
+ otp: {
1095
+ component: InputOtpField,
1096
+ toEngineValue: (value) => typeof value === "string" ? value : FIELD_CHANGE_IGNORED
1097
+ }
1098
+ };
1099
+ function readEventValue(change) {
1100
+ if (typeof change !== "object" || change === null || !("target" in change)) {
1101
+ return FIELD_CHANGE_IGNORED;
1102
+ }
1103
+ const target = change.target;
1104
+ if (typeof target !== "object" || target === null || !("value" in target)) {
1105
+ return FIELD_CHANGE_IGNORED;
1106
+ }
1107
+ return target.value;
1108
+ }
1109
+ function isCheckboxValue(value) {
1110
+ return typeof value === "boolean" || value === "indeterminate";
1111
+ }
1112
+
1113
+ // src/context/form-config.ts
1114
+ import { createContext, useContext } from "react";
1115
+ var ConfigContext = createContext({
1116
+ designMode: false
1117
+ });
1118
+ function useConfigContext() {
1119
+ const ctx = useContext(ConfigContext);
1120
+ if (!ctx) {
1121
+ throw new Error("Form Engine missing");
1122
+ }
1123
+ return ctx;
1124
+ }
1125
+
1126
+ // src/context/form-context.ts
1127
+ import { createContext as createContext2, useContext as useContext2 } from "react";
1128
+ var FormContext = createContext2(null);
1129
+ function useFormContext() {
1130
+ const ctx = useContext2(FormContext);
1131
+ if (!ctx) {
1132
+ throw new Error("Form Engine missing");
1133
+ }
1134
+ return ctx;
1135
+ }
1136
+ function useOptionalFormContext() {
1137
+ return useContext2(FormContext);
1138
+ }
1139
+
1140
+ // src/renderer/field-renderer.tsx
1141
+ import { useEffect, useState } from "react";
1142
+
1143
+ // src/renderer/design-visibility.ts
1144
+ import { useContext as useContext3 } from "react";
1145
+ function useDesignVisible(runtimeVisible) {
1146
+ const { designMode } = useContext3(ConfigContext);
1147
+ return designMode === true || runtimeVisible;
1148
+ }
1149
+
1150
+ // src/renderer/field-execution.ts
1151
+ function executeRendererFieldEvent(engine, nodeId, event, designMode, options) {
1152
+ if (designMode) {
1153
+ return void 0;
1154
+ }
1155
+ return engine.executeFieldEvent(nodeId, event, options);
1156
+ }
1157
+
1158
+ // src/renderer/repeat-renderer.tsx
1159
+ import { createContext as createContext3, useContext as useContext4 } from "react";
1160
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1161
+ var RepeatItemContext = createContext3(
1162
+ void 0
1163
+ );
1164
+ function useRepeatItem() {
1165
+ return useContext4(RepeatItemContext)?.item;
1166
+ }
1167
+ function useRepeatItemScope() {
1168
+ return useContext4(RepeatItemContext);
1169
+ }
1170
+ function RepeatRenderer({ node }) {
1171
+ if (node.schema.kind !== "layout" || node.schema.type !== "repeat") {
1172
+ return null;
1173
+ }
1174
+ const engine = useFormContext();
1175
+ const { designMode } = useConfigContext();
1176
+ const parentScope = useRepeatItemScope();
1177
+ const props = node.schema.props;
1178
+ const className = normalizeClassName2(props.className);
1179
+ const badge = describeRepeat(props);
1180
+ const parentPrefix = parentScope?.valuePrefix;
1181
+ if (designMode === true) {
1182
+ return /* @__PURE__ */ jsxs6(
1183
+ "div",
1184
+ {
1185
+ className: joinClassNames(
1186
+ "space-y-2 rounded border border-dashed border-gray-300 p-2",
1187
+ className
1188
+ ),
1189
+ "data-repeat": "design",
1190
+ "data-repeat-mode": props.mode,
1191
+ children: [
1192
+ /* @__PURE__ */ jsxs6("div", { className: "text-[10px] font-medium uppercase tracking-wide text-gray-500", children: [
1193
+ "Repeat ",
1194
+ badge
1195
+ ] }),
1196
+ node.children.map((child) => /* @__PURE__ */ jsx8(NodeRenderer, { node: child }, child.id))
1197
+ ]
1198
+ }
1199
+ );
1200
+ }
1201
+ const items = engine.getRepeatItems(node.id, {
1202
+ ...parentPrefix !== void 0 ? { valuePrefix: parentPrefix } : {}
1203
+ });
1204
+ const relativePath = props.mode === "values" && typeof props.path === "string" ? props.path.trim() : void 0;
1205
+ return /* @__PURE__ */ jsx8(
1206
+ "div",
1207
+ {
1208
+ className,
1209
+ "data-repeat": "runtime",
1210
+ "data-repeat-mode": props.mode,
1211
+ "data-repeat-count": items.length,
1212
+ children: items.map((item, index) => {
1213
+ const valuePrefix = relativePath !== void 0 ? joinPrefixes(parentPrefix, relativePath, String(index)) : parentPrefix;
1214
+ return /* @__PURE__ */ jsx8(
1215
+ RepeatItemContext.Provider,
1216
+ {
1217
+ value: {
1218
+ item,
1219
+ index,
1220
+ ...valuePrefix !== void 0 ? { valuePrefix } : {}
1221
+ },
1222
+ children: /* @__PURE__ */ jsx8("div", { "data-repeat-index": index, children: node.children.map((child) => /* @__PURE__ */ jsx8(NodeRenderer, { node: child }, `${child.id}-${index}`)) })
1223
+ },
1224
+ `${node.id}-${index}`
1225
+ );
1226
+ })
1227
+ }
1228
+ );
1229
+ }
1230
+ function describeRepeat(props) {
1231
+ if (props.mode === "count") {
1232
+ return `\xD7${typeof props.count === "number" ? props.count : 0}`;
1233
+ }
1234
+ if (props.mode === "source" && typeof props.source === "string") {
1235
+ return `\u2190 ${props.source.trim()}`;
1236
+ }
1237
+ if (props.mode === "values" && typeof props.path === "string") {
1238
+ return `\u21C4 ${props.path.trim()}`;
1239
+ }
1240
+ return "";
1241
+ }
1242
+ function joinPrefixes(...parts) {
1243
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(".");
1244
+ }
1245
+ function normalizeClassName2(value) {
1246
+ return typeof value === "string" ? value.trim() : "";
1247
+ }
1248
+ function joinClassNames(...parts) {
1249
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
1250
+ }
1251
+
1252
+ // src/renderer/field-renderer.tsx
1253
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1254
+ function FieldRenderer({ node }) {
1255
+ if (node.schema.kind !== "field") return null;
1256
+ const engine = useFormContext();
1257
+ const { designMode } = useConfigContext();
1258
+ const repeatScope = useRepeatItemScope();
1259
+ const name = repeatScope?.valuePrefix !== void 0 ? `${repeatScope.valuePrefix}.${node.schema.name}` : node.schema.name;
1260
+ const [, forceUpdate] = useState(0);
1261
+ useEffect(() => {
1262
+ const unsubscribe = engine.subscribe(() => {
1263
+ forceUpdate((x) => x + 1);
1264
+ });
1265
+ return unsubscribe;
1266
+ }, [engine]);
1267
+ const runtimeVisible = engine.isVisible(name);
1268
+ const show = useDesignVisible(runtimeVisible);
1269
+ const definition = fieldRegistry[node.schema.type];
1270
+ if (!definition) {
1271
+ return null;
1272
+ }
1273
+ const fieldType = node.schema.type;
1274
+ const fireFieldEvent = (event) => {
1275
+ void executeRendererFieldEvent(
1276
+ engine,
1277
+ node.id,
1278
+ event,
1279
+ designMode === true
1280
+ );
1281
+ };
1282
+ const field = {
1283
+ value: engine.getValue(name),
1284
+ error: engine.getError(name),
1285
+ touched: engine.isTouched(name),
1286
+ touch: () => engine.touch(name),
1287
+ disabled: engine.isDisabled(name) || engine.isFormDisabled(),
1288
+ dirty: engine.isDirty(name),
1289
+ visible: runtimeVisible,
1290
+ setValue: (change) => {
1291
+ const value = definition.toEngineValue(change);
1292
+ if (value !== FIELD_CHANGE_IGNORED) {
1293
+ engine.setValue(name, value);
1294
+ if (fieldAllowsChangeEvent(fieldType)) {
1295
+ fireFieldEvent("change");
1296
+ }
1297
+ }
1298
+ }
1299
+ };
1300
+ if (!show) return null;
1301
+ const Component = definition.component;
1302
+ const options = engine.getOptions(name);
1303
+ const optionsLoading = engine.isOptionsSourceLoading(name);
1304
+ const engineState = engine.getState();
1305
+ const schema = node.schema.type === "select" || node.schema.type === "radio" || node.schema.type === "segment-button" ? {
1306
+ ...node.schema,
1307
+ props: {
1308
+ ...node.schema.props,
1309
+ options
1310
+ }
1311
+ } : node.schema;
1312
+ const props = adaptField({
1313
+ schema,
1314
+ field,
1315
+ setValue: field.setValue,
1316
+ state: {
1317
+ isLoading: engineState.isLoading,
1318
+ pendingActionIds: engineState.pendingActionIds,
1319
+ resourceInFlight: engineState.resourceInFlight
1320
+ },
1321
+ loading: optionsLoading
1322
+ });
1323
+ const helperText = typeof props.helperText === "string" ? props.helperText : void 0;
1324
+ const label = typeof schema.props?.label === "string" ? schema.props.label : void 0;
1325
+ const helperTextId = helperText ? `${node.id}-helper-text` : void 0;
1326
+ const inputId = repeatScope?.valuePrefix !== void 0 ? `${node.id}-${repeatScope.index}` : node.id;
1327
+ const baseComponentProps = {
1328
+ ...props,
1329
+ id: inputId,
1330
+ name,
1331
+ "aria-describedby": helperTextId,
1332
+ onBlur: () => {
1333
+ field.touch();
1334
+ if (fieldAllowsBlurEvent(fieldType)) {
1335
+ fireFieldEvent("blur");
1336
+ }
1337
+ },
1338
+ ...fieldAllowsCommitEvent(fieldType) ? {
1339
+ onCommit: (change) => {
1340
+ const value = definition.toEngineValue(change);
1341
+ if (value !== FIELD_CHANGE_IGNORED) {
1342
+ engine.setValue(name, value);
1343
+ field.touch();
1344
+ fireFieldEvent("commit");
1345
+ }
1346
+ }
1347
+ } : {}
1348
+ };
1349
+ const componentProps = definition.toComponentProps?.(baseComponentProps) ?? baseComponentProps;
1350
+ const component = /* @__PURE__ */ jsx9(Component, { ...componentProps });
1351
+ const externalLabel = definition.rendersLabel === false && label;
1352
+ const externalHelperText = definition.rendersHelperText === false && helperText;
1353
+ if (!externalLabel && !externalHelperText) {
1354
+ return component;
1355
+ }
1356
+ return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col items-start", children: [
1357
+ externalLabel ? /* @__PURE__ */ jsx9("label", { htmlFor: inputId, className: "mb-1 text-sm text-fg", children: label }) : null,
1358
+ component,
1359
+ externalHelperText ? /* @__PURE__ */ jsx9(
1360
+ "p",
1361
+ {
1362
+ id: helperTextId,
1363
+ role: props.error ? "alert" : void 0,
1364
+ className: `mt-1 text-xs ${props.error ? "text-fg-error" : "text-fg-tertiary"}`,
1365
+ children: helperText
1366
+ }
1367
+ ) : null
1368
+ ] });
1369
+ }
1370
+
1371
+ // src/renderer/action-renderer.tsx
1372
+ import { adaptAction } from "@bsm-form/core";
1373
+
1374
+ // src/renderer/action-button.tsx
1375
+ import { isValidElement } from "react";
1376
+ import {
1377
+ Button
1378
+ } from "bsm-design-system";
1379
+ import { jsx as jsx10 } from "react/jsx-runtime";
1380
+ function ActionButton({
1381
+ "aria-label": ariaLabel,
1382
+ children,
1383
+ className,
1384
+ color,
1385
+ dangerouslySetInnerHTML: _dangerouslySetInnerHTML,
1386
+ disabled,
1387
+ iconOnly,
1388
+ leadingIcon,
1389
+ loading,
1390
+ rounded,
1391
+ size,
1392
+ traillingIcon,
1393
+ trailingIcon,
1394
+ variant,
1395
+ ...props
1396
+ }) {
1397
+ const content = normalizeActionButtonContent(children);
1398
+ const isLoading = loading === true;
1399
+ const isDisabled = disabled === true;
1400
+ const resolvedTrailingIcon = normalizeActionButtonContent(
1401
+ trailingIcon ?? traillingIcon
1402
+ );
1403
+ return /* @__PURE__ */ jsx10(
1404
+ Button,
1405
+ {
1406
+ ...props,
1407
+ type: "button",
1408
+ className: typeof className === "string" ? className : "",
1409
+ variant: normalizeButtonVariant(variant),
1410
+ color: normalizeButtonColor(color),
1411
+ size: normalizeButtonSize(size),
1412
+ loading: isLoading,
1413
+ disabled: isDisabled,
1414
+ iconOnly: iconOnly === true,
1415
+ leadingIcon: normalizeActionButtonContent(leadingIcon),
1416
+ trailingIcon: resolvedTrailingIcon,
1417
+ rounded: rounded === true,
1418
+ "aria-busy": isLoading || void 0,
1419
+ "aria-label": typeof ariaLabel === "string" && ariaLabel.trim() ? ariaLabel : getButtonAccessibleLabel(content),
1420
+ children: content
1421
+ }
1422
+ );
1423
+ }
1424
+ function normalizeButtonVariant(value) {
1425
+ return value === "ghost" || value === "outlined" || value === "text" ? value : "fill";
1426
+ }
1427
+ function normalizeButtonColor(value) {
1428
+ return value === "secondary" || value === "error" || value === "success" || value === "info" || value === "warning" ? value : "primary";
1429
+ }
1430
+ function normalizeButtonSize(value) {
1431
+ return value === "xs" || value === "sm" || value === "lg" ? value : "md";
1432
+ }
1433
+ function normalizeActionButtonContent(value) {
1434
+ if (typeof value === "string" || typeof value === "number" || isValidElement(value)) {
1435
+ return value;
1436
+ }
1437
+ return Array.isArray(value) ? value.map(normalizeActionButtonContent) : null;
1438
+ }
1439
+ function getButtonAccessibleLabel(content) {
1440
+ return typeof content === "string" || typeof content === "number" ? String(content) : void 0;
1441
+ }
1442
+
1443
+ // src/renderer/action-execution.ts
1444
+ function executeRendererAction(engine, actionId, designMode, options) {
1445
+ if (designMode) {
1446
+ return void 0;
1447
+ }
1448
+ return engine.executeAction(actionId, options);
1449
+ }
1450
+
1451
+ // src/renderer/action-renderer.tsx
1452
+ import { jsx as jsx11 } from "react/jsx-runtime";
1453
+ function ActionRenderer({ node }) {
1454
+ if (node.schema.kind !== "action") {
1455
+ return null;
1456
+ }
1457
+ const engine = useFormContext();
1458
+ const { designMode } = useConfigContext();
1459
+ const repeatScope = useRepeatItemScope();
1460
+ const show = useDesignVisible(node.state.visible);
1461
+ if (!show) {
1462
+ return null;
1463
+ }
1464
+ const schema = node.schema;
1465
+ const engineState = engine.getState();
1466
+ const stepperState = (schema.type === "stepper-next" || schema.type === "stepper-previous") && schema.stepperId ? engine.getStepperState(schema.stepperId) : void 0;
1467
+ const isStepperActionDisabled = schema.type === "stepper-next" ? !stepperState?.canGoNext || engineState.initializationStatus !== "ready" : schema.type === "stepper-previous" ? !stepperState?.canGoPrevious || engineState.initializationStatus !== "ready" : false;
1468
+ const isCustomPending = schema.type === "custom" && engineState.pendingActionIds.includes(node.id);
1469
+ const props = adaptAction({
1470
+ schema,
1471
+ onClick: () => {
1472
+ void executeRendererAction(
1473
+ engine,
1474
+ node.id,
1475
+ designMode === true,
1476
+ repeatScope !== void 0 ? {
1477
+ item: repeatScope.item,
1478
+ itemIndex: repeatScope.index,
1479
+ ...repeatScope.valuePrefix !== void 0 ? {
1480
+ valuePrefix: parentValuePrefix(repeatScope.valuePrefix)
1481
+ } : {}
1482
+ } : void 0
1483
+ );
1484
+ },
1485
+ state: {
1486
+ isLoading: engineState.isLoading,
1487
+ pendingActionIds: engineState.pendingActionIds,
1488
+ resourceInFlight: engineState.resourceInFlight
1489
+ },
1490
+ loading: schema.type === "submit" && engineState.isSubmitting || isCustomPending,
1491
+ disabled: node.state.disabled || engine.isFormDisabled() || isStepperActionDisabled || isCustomPending
1492
+ });
1493
+ return /* @__PURE__ */ jsx11(ActionButton, { ...props, id: node.id });
1494
+ }
1495
+ function parentValuePrefix(itemValuePrefix) {
1496
+ const withoutIndex = itemValuePrefix.replace(/\.\d+$/, "");
1497
+ const lastDot = withoutIndex.lastIndexOf(".");
1498
+ return lastDot === -1 ? "" : withoutIndex.slice(0, lastDot);
1499
+ }
1500
+
1501
+ // src/renderer/display-renderer.tsx
1502
+ import { adaptDisplay } from "@bsm-form/core";
1503
+ import { useEffect as useEffect2, useState as useState2 } from "react";
1504
+
1505
+ // src/renderer/alert-display.tsx
1506
+ import { Alert } from "bsm-design-system";
1507
+ import { jsx as jsx12 } from "react/jsx-runtime";
1508
+ var ALERT_TYPES = [
1509
+ "success",
1510
+ "error",
1511
+ "warning",
1512
+ "info",
1513
+ "default"
1514
+ ];
1515
+ var ALERT_VARIANTS = ["filled", "outline"];
1516
+ function AlertDisplay({
1517
+ type,
1518
+ variant,
1519
+ title,
1520
+ children,
1521
+ className,
1522
+ withIcon,
1523
+ closable,
1524
+ actionText,
1525
+ onClose,
1526
+ onAction
1527
+ }) {
1528
+ const normalizedTitle = normalizeAlertText(title);
1529
+ const normalizedContent = normalizeAlertText(children);
1530
+ const normalizedActionText = normalizeAlertText(actionText);
1531
+ const closeHandler = typeof onClose === "function" ? onClose : void 0;
1532
+ const actionHandler = normalizedActionText && typeof onAction === "function" ? onAction : void 0;
1533
+ if (!normalizedTitle && !normalizedContent) {
1534
+ return null;
1535
+ }
1536
+ return /* @__PURE__ */ jsx12(
1537
+ Alert,
1538
+ {
1539
+ type: normalizeAlertType(type),
1540
+ variant: normalizeAlertVariant(variant),
1541
+ title: normalizedTitle,
1542
+ className: normalizeAlertClassName(className) ?? "",
1543
+ withIcon: withIcon !== false,
1544
+ closable: closable === true,
1545
+ actionText: actionHandler ? normalizedActionText : void 0,
1546
+ onClose: closeHandler,
1547
+ onAction: actionHandler,
1548
+ children: normalizedContent
1549
+ }
1550
+ );
1551
+ }
1552
+ function normalizeAlertType(value) {
1553
+ return normalizeEnum(value, ALERT_TYPES, "default");
1554
+ }
1555
+ function normalizeAlertVariant(value) {
1556
+ return normalizeEnum(value, ALERT_VARIANTS, "filled");
1557
+ }
1558
+ function normalizeAlertText(value) {
1559
+ if (typeof value === "string") {
1560
+ const text = value.trim();
1561
+ return text || void 0;
1562
+ }
1563
+ if (typeof value === "number" && Number.isFinite(value)) {
1564
+ return String(value);
1565
+ }
1566
+ return void 0;
1567
+ }
1568
+ function normalizeAlertClassName(value) {
1569
+ if (typeof value !== "string") {
1570
+ return void 0;
1571
+ }
1572
+ const className = value.trim();
1573
+ return className || void 0;
1574
+ }
1575
+ function normalizeEnum(value, values, fallback) {
1576
+ if (typeof value !== "string") {
1577
+ return fallback;
1578
+ }
1579
+ const normalizedValue = value.trim().toLowerCase();
1580
+ return values.includes(normalizedValue) ? normalizedValue : fallback;
1581
+ }
1582
+
1583
+ // src/renderer/chips-display.tsx
1584
+ import { Chips } from "bsm-design-system";
1585
+ import { jsx as jsx13 } from "react/jsx-runtime";
1586
+ var CHIPS_VARIANTS = ["default", "secondary"];
1587
+ function ChipsDisplay({
1588
+ label,
1589
+ className,
1590
+ variant,
1591
+ rounded,
1592
+ disabled,
1593
+ onClose,
1594
+ onClick
1595
+ }) {
1596
+ const normalizedLabel = normalizeChipsLabel(label);
1597
+ if (normalizedLabel === void 0) {
1598
+ return null;
1599
+ }
1600
+ const closeHandler = typeof onClose === "function" ? () => {
1601
+ onClose();
1602
+ } : void 0;
1603
+ const clickHandler = typeof onClick === "function" ? () => {
1604
+ onClick();
1605
+ } : void 0;
1606
+ return /* @__PURE__ */ jsx13(
1607
+ Chips,
1608
+ {
1609
+ label: normalizedLabel,
1610
+ className: normalizeChipsClassName(className),
1611
+ variant: normalizeChipsVariant(variant),
1612
+ rounded: rounded === true,
1613
+ disabled: disabled === true,
1614
+ onClose: closeHandler,
1615
+ onClick: clickHandler
1616
+ }
1617
+ );
1618
+ }
1619
+ function normalizeChipsLabel(value) {
1620
+ if (typeof value === "string") {
1621
+ const label = value.trim();
1622
+ return label || void 0;
1623
+ }
1624
+ if (typeof value === "number" && Number.isFinite(value)) {
1625
+ return String(value);
1626
+ }
1627
+ return void 0;
1628
+ }
1629
+ function normalizeChipsVariant(value) {
1630
+ if (typeof value !== "string") {
1631
+ return "default";
1632
+ }
1633
+ const normalizedValue = value.trim().toLowerCase();
1634
+ return CHIPS_VARIANTS.includes(normalizedValue) ? normalizedValue : "default";
1635
+ }
1636
+ function normalizeChipsClassName(value) {
1637
+ if (typeof value !== "string") {
1638
+ return void 0;
1639
+ }
1640
+ const className = value.trim();
1641
+ return className || void 0;
1642
+ }
1643
+
1644
+ // src/renderer/tag-display.tsx
1645
+ import { Tag } from "bsm-design-system";
1646
+ import { jsx as jsx14 } from "react/jsx-runtime";
1647
+ var TAG_VARIANTS = [
1648
+ "default",
1649
+ "secondary",
1650
+ "error",
1651
+ "success",
1652
+ "warning",
1653
+ "info",
1654
+ "magenta",
1655
+ "cyan",
1656
+ "blue",
1657
+ "lime",
1658
+ "purple",
1659
+ "volcano"
1660
+ ];
1661
+ var TAG_SIZES = ["md", "lg"];
1662
+ function TagDisplay({
1663
+ label,
1664
+ className,
1665
+ variant,
1666
+ size,
1667
+ rounded,
1668
+ borderLess
1669
+ }) {
1670
+ const normalizedLabel = normalizeTagLabel(label);
1671
+ if (normalizedLabel === void 0) {
1672
+ return null;
1673
+ }
1674
+ return /* @__PURE__ */ jsx14(
1675
+ Tag,
1676
+ {
1677
+ label: normalizedLabel,
1678
+ className: normalizeTagClassName(className),
1679
+ variant: normalizeTagVariant(variant),
1680
+ size: normalizeTagSize(size),
1681
+ rounded: rounded === true,
1682
+ borderLess: borderLess === true
1683
+ }
1684
+ );
1685
+ }
1686
+ function normalizeTagLabel(value) {
1687
+ if (typeof value === "string") {
1688
+ const label = value.trim();
1689
+ return label || void 0;
1690
+ }
1691
+ if (typeof value === "number" && Number.isFinite(value)) {
1692
+ return String(value);
1693
+ }
1694
+ return void 0;
1695
+ }
1696
+ function normalizeTagVariant(value) {
1697
+ return normalizeEnum2(value, TAG_VARIANTS, "default");
1698
+ }
1699
+ function normalizeTagSize(value) {
1700
+ return normalizeEnum2(value, TAG_SIZES, "md");
1701
+ }
1702
+ function normalizeTagClassName(value) {
1703
+ if (typeof value !== "string") {
1704
+ return void 0;
1705
+ }
1706
+ const className = value.trim();
1707
+ return className || void 0;
1708
+ }
1709
+ function normalizeEnum2(value, values, fallback) {
1710
+ if (typeof value !== "string") {
1711
+ return fallback;
1712
+ }
1713
+ const normalizedValue = value.trim().toLowerCase();
1714
+ return values.includes(normalizedValue) ? normalizedValue : fallback;
1715
+ }
1716
+
1717
+ // src/renderer/skeleton-display.tsx
1718
+ import { Skeleton } from "bsm-design-system";
1719
+ import { jsx as jsx15 } from "react/jsx-runtime";
1720
+ function SkeletonDisplay({
1721
+ ariaLabel,
1722
+ className
1723
+ }) {
1724
+ const normalizedAriaLabel = normalizeSkeletonAriaLabel(ariaLabel);
1725
+ return /* @__PURE__ */ jsx15(
1726
+ Skeleton,
1727
+ {
1728
+ className: normalizeSkeletonClassName(className),
1729
+ role: normalizedAriaLabel ? "status" : void 0,
1730
+ "aria-label": normalizedAriaLabel,
1731
+ "aria-busy": normalizedAriaLabel ? true : void 0,
1732
+ "aria-hidden": normalizedAriaLabel ? void 0 : true
1733
+ }
1734
+ );
1735
+ }
1736
+ function normalizeSkeletonAriaLabel(value) {
1737
+ if (typeof value !== "string") {
1738
+ return void 0;
1739
+ }
1740
+ const ariaLabel = value.trim();
1741
+ return ariaLabel || void 0;
1742
+ }
1743
+ function normalizeSkeletonClassName(value) {
1744
+ if (typeof value !== "string") {
1745
+ return void 0;
1746
+ }
1747
+ const className = value.trim();
1748
+ return className || void 0;
1749
+ }
1750
+
1751
+ // src/renderer/table-display.tsx
1752
+ import { Button as Button2, Table, Tag as Tag2 } from "bsm-design-system";
1753
+ import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
1754
+ var TABLE_ALIGNS = ["left", "right", "center"];
1755
+ var ACTION_VARIANTS = ["fill", "outlined", "ghost", "text"];
1756
+ var ACTION_COLORS = [
1757
+ "primary",
1758
+ "secondary",
1759
+ "success",
1760
+ "error",
1761
+ "info",
1762
+ "warning"
1763
+ ];
1764
+ function TableDisplay({
1765
+ align,
1766
+ bordered,
1767
+ caption,
1768
+ className,
1769
+ columns,
1770
+ onActionClick,
1771
+ onRowClick,
1772
+ pendingTableInteractions,
1773
+ rows,
1774
+ separated,
1775
+ tableNodeId
1776
+ }) {
1777
+ const normalizedColumns = normalizeTableColumns(columns);
1778
+ const normalizedRows = Array.isArray(rows) ? rows : [];
1779
+ const normalizedCaption = normalizeTableCaption(caption);
1780
+ const rowInteractive = typeof onRowClick === "function";
1781
+ const pending = Array.isArray(pendingTableInteractions) ? pendingTableInteractions : [];
1782
+ return /* @__PURE__ */ jsx16(Table.Container, { className: normalizeTableClassName(className), children: /* @__PURE__ */ jsxs8(
1783
+ Table,
1784
+ {
1785
+ align: normalizeTableAlign(align),
1786
+ bordered: bordered === true,
1787
+ separated: separated === true,
1788
+ children: [
1789
+ normalizedCaption ? /* @__PURE__ */ jsx16(Table.Caption, { children: normalizedCaption }) : null,
1790
+ /* @__PURE__ */ jsx16(Table.Header, { children: /* @__PURE__ */ jsx16(Table.Row, { children: normalizedColumns.map((column) => /* @__PURE__ */ jsx16(
1791
+ Table.Head,
1792
+ {
1793
+ className: column.kind === "actions" ? "text-end" : void 0,
1794
+ children: column.header
1795
+ },
1796
+ column.id
1797
+ )) }) }),
1798
+ /* @__PURE__ */ jsx16(Table.Body, { children: normalizedRows.map((row, rowIndex) => /* @__PURE__ */ jsx16(
1799
+ Table.Row,
1800
+ {
1801
+ onClick: rowInteractive ? () => {
1802
+ onRowClick(rowIndex);
1803
+ } : void 0,
1804
+ style: rowInteractive ? { cursor: "pointer" } : void 0,
1805
+ children: normalizedColumns.map((column) => /* @__PURE__ */ jsx16(
1806
+ Table.Cell,
1807
+ {
1808
+ className: column.kind === "actions" ? "text-end" : void 0,
1809
+ children: renderTableCell({
1810
+ column,
1811
+ onActionClick,
1812
+ pendingTableInteractions: pending,
1813
+ row,
1814
+ rowIndex,
1815
+ tableNodeId: typeof tableNodeId === "string" ? tableNodeId : void 0
1816
+ })
1817
+ },
1818
+ column.id
1819
+ ))
1820
+ },
1821
+ rowIndex
1822
+ )) })
1823
+ ]
1824
+ }
1825
+ ) });
1826
+ }
1827
+ function renderTableCell({
1828
+ column,
1829
+ onActionClick,
1830
+ pendingTableInteractions,
1831
+ row,
1832
+ rowIndex,
1833
+ tableNodeId
1834
+ }) {
1835
+ if (column.kind === "actions") {
1836
+ return /* @__PURE__ */ jsx16("div", { className: "flex flex-wrap items-center justify-end gap-2", children: column.actions.map((action) => {
1837
+ const iconOnly = action.iconOnly === true;
1838
+ const pendingKey = tableNodeId !== void 0 ? `${tableNodeId}:${column.id}:${action.id}:${rowIndex}` : void 0;
1839
+ const isPending = pendingKey !== void 0 && pendingTableInteractions.includes(pendingKey);
1840
+ return /* @__PURE__ */ jsx16(
1841
+ Button2,
1842
+ {
1843
+ type: "button",
1844
+ size: "xs",
1845
+ variant: normalizeActionVariant(action.variant),
1846
+ color: normalizeActionColor(action.color),
1847
+ iconOnly,
1848
+ "aria-label": action.label,
1849
+ loading: isPending,
1850
+ disabled: isPending,
1851
+ onClick: (event) => {
1852
+ event.stopPropagation();
1853
+ onActionClick?.(column.id, action.id, rowIndex);
1854
+ },
1855
+ children: action.label
1856
+ },
1857
+ action.id
1858
+ );
1859
+ }) });
1860
+ }
1861
+ if (column.kind === "tag") {
1862
+ const rawValue = readTableCellValue(row, column.path);
1863
+ const mapped = resolveTableTagMapping(rawValue, column.map);
1864
+ const label = normalizeTagLabel(mapped?.label ?? rawValue);
1865
+ if (label === void 0) {
1866
+ return null;
1867
+ }
1868
+ const variantFromPath = column.variantPath !== void 0 ? readTableCellValue(row, column.variantPath) : void 0;
1869
+ return /* @__PURE__ */ jsx16(
1870
+ Tag2,
1871
+ {
1872
+ label,
1873
+ variant: normalizeTagVariant(
1874
+ mapped?.variant ?? variantFromPath ?? column.variant
1875
+ )
1876
+ }
1877
+ );
1878
+ }
1879
+ return formatTableCellValue(readTableCellValue(row, column.path));
1880
+ }
1881
+ function normalizeTableColumns(value) {
1882
+ if (!Array.isArray(value)) {
1883
+ return [];
1884
+ }
1885
+ return value.flatMap((column) => {
1886
+ const normalized = normalizeTableColumn(column);
1887
+ return normalized ? [normalized] : [];
1888
+ });
1889
+ }
1890
+ function normalizeTableColumn(value) {
1891
+ if (typeof value !== "object" || value === null || typeof value.id !== "string" || value.id.trim() === "" || typeof value.header !== "string" || value.header.trim() === "") {
1892
+ return void 0;
1893
+ }
1894
+ const column = value;
1895
+ const id = column.id;
1896
+ const header = column.header;
1897
+ const kind = column.kind;
1898
+ if (kind === "actions") {
1899
+ const actions = normalizeTableColumnActions(column.actions);
1900
+ if (actions.length === 0) {
1901
+ return void 0;
1902
+ }
1903
+ return {
1904
+ id,
1905
+ header,
1906
+ kind: "actions",
1907
+ actions
1908
+ };
1909
+ }
1910
+ if (typeof column.path !== "string" || column.path.trim() === "") {
1911
+ return void 0;
1912
+ }
1913
+ if (kind === "tag") {
1914
+ const tagColumn = {
1915
+ id,
1916
+ header,
1917
+ kind: "tag",
1918
+ path: column.path
1919
+ };
1920
+ if (typeof column.variantPath === "string" && column.variantPath.trim() !== "") {
1921
+ tagColumn.variantPath = column.variantPath;
1922
+ }
1923
+ const variant = normalizeOptionalTagVariant(column.variant);
1924
+ if (variant) {
1925
+ tagColumn.variant = variant;
1926
+ }
1927
+ const map = normalizeTableTagMap(column.map);
1928
+ if (map) {
1929
+ tagColumn.map = map;
1930
+ }
1931
+ return tagColumn;
1932
+ }
1933
+ if (kind !== void 0 && kind !== "text") {
1934
+ return void 0;
1935
+ }
1936
+ return {
1937
+ id,
1938
+ header,
1939
+ kind: "text",
1940
+ path: column.path
1941
+ };
1942
+ }
1943
+ function normalizeTableColumnActions(value) {
1944
+ if (!Array.isArray(value)) {
1945
+ return [];
1946
+ }
1947
+ return value.flatMap((action) => {
1948
+ if (typeof action !== "object" || action === null || typeof action.id !== "string" || action.id.trim() === "" || typeof action.label !== "string" || action.label.trim() === "" || !Array.isArray(action.steps)) {
1949
+ return [];
1950
+ }
1951
+ const normalized = {
1952
+ id: action.id,
1953
+ label: action.label,
1954
+ steps: action.steps
1955
+ };
1956
+ if (typeof action.variant === "string" && ACTION_VARIANTS.includes(
1957
+ action.variant
1958
+ )) {
1959
+ normalized.variant = action.variant;
1960
+ }
1961
+ if (typeof action.color === "string" && action.color.trim() !== "") {
1962
+ const color = normalizeActionColor(action.color);
1963
+ if (color) {
1964
+ normalized.color = color;
1965
+ }
1966
+ }
1967
+ if (action.iconOnly === true) {
1968
+ normalized.iconOnly = true;
1969
+ }
1970
+ return [normalized];
1971
+ });
1972
+ }
1973
+ function normalizeTableAlign(value) {
1974
+ return normalizeEnum3(value, TABLE_ALIGNS, "left");
1975
+ }
1976
+ function normalizeTableCaption(value) {
1977
+ if (typeof value !== "string") {
1978
+ return void 0;
1979
+ }
1980
+ const caption = value.trim();
1981
+ return caption || void 0;
1982
+ }
1983
+ function normalizeTableClassName(value) {
1984
+ if (typeof value !== "string") {
1985
+ return void 0;
1986
+ }
1987
+ const className = value.trim();
1988
+ return className || void 0;
1989
+ }
1990
+ function readTableCellValue(row, path) {
1991
+ if (!path) {
1992
+ return void 0;
1993
+ }
1994
+ let current = row;
1995
+ for (const key of path.split(".")) {
1996
+ if (typeof current !== "object" || current === null) {
1997
+ return void 0;
1998
+ }
1999
+ current = current[key];
2000
+ }
2001
+ return current;
2002
+ }
2003
+ function formatTableCellValue(value) {
2004
+ if (value === void 0 || value === null) {
2005
+ return "";
2006
+ }
2007
+ if (typeof value === "string") {
2008
+ return value;
2009
+ }
2010
+ if (typeof value === "number" && Number.isFinite(value)) {
2011
+ return String(value);
2012
+ }
2013
+ if (typeof value === "boolean") {
2014
+ return value ? "true" : "false";
2015
+ }
2016
+ try {
2017
+ return JSON.stringify(value) ?? "";
2018
+ } catch {
2019
+ return "";
2020
+ }
2021
+ }
2022
+ function resolveTableTagMapping(value, map) {
2023
+ if (!map) {
2024
+ return void 0;
2025
+ }
2026
+ const key = tableTagMapKey(value);
2027
+ if (key === void 0) {
2028
+ return void 0;
2029
+ }
2030
+ if (map[key]) {
2031
+ return map[key];
2032
+ }
2033
+ const trimmed = key.trim();
2034
+ if (trimmed !== key && map[trimmed]) {
2035
+ return map[trimmed];
2036
+ }
2037
+ for (const [mapKey, mapping] of Object.entries(map)) {
2038
+ if (mapKey.trim() === trimmed) {
2039
+ return mapping;
2040
+ }
2041
+ }
2042
+ return void 0;
2043
+ }
2044
+ function tableTagMapKey(value) {
2045
+ if (typeof value === "string") {
2046
+ return value;
2047
+ }
2048
+ if (typeof value === "number" && Number.isFinite(value)) {
2049
+ return String(value);
2050
+ }
2051
+ if (typeof value === "boolean") {
2052
+ return value ? "true" : "false";
2053
+ }
2054
+ return void 0;
2055
+ }
2056
+ function normalizeTableTagMap(value) {
2057
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
2058
+ return void 0;
2059
+ }
2060
+ const map = {};
2061
+ for (const [rawKey, entry] of Object.entries(value)) {
2062
+ const key = rawKey.trim();
2063
+ if (key === "" || typeof entry !== "object" || entry === null || Array.isArray(entry)) {
2064
+ continue;
2065
+ }
2066
+ const mapping = {};
2067
+ if (typeof entry.label === "string" && entry.label.trim() !== "") {
2068
+ mapping.label = entry.label.trim();
2069
+ }
2070
+ const variant = normalizeOptionalTagVariant(entry.variant);
2071
+ if (variant) {
2072
+ mapping.variant = variant;
2073
+ }
2074
+ if (mapping.label !== void 0 || mapping.variant !== void 0) {
2075
+ map[key] = mapping;
2076
+ }
2077
+ }
2078
+ return Object.keys(map).length > 0 ? map : void 0;
2079
+ }
2080
+ function normalizeOptionalTagVariant(value) {
2081
+ if (typeof value !== "string") {
2082
+ return void 0;
2083
+ }
2084
+ const normalized = value.trim().toLowerCase();
2085
+ return TAG_VARIANTS.includes(normalized) ? normalized : void 0;
2086
+ }
2087
+ function normalizeActionVariant(value) {
2088
+ return normalizeEnum3(value, ACTION_VARIANTS, "ghost");
2089
+ }
2090
+ function normalizeActionColor(value) {
2091
+ if (typeof value !== "string") {
2092
+ return void 0;
2093
+ }
2094
+ const color = value.trim().toLowerCase();
2095
+ return ACTION_COLORS.includes(color) ? color : void 0;
2096
+ }
2097
+ function normalizeEnum3(value, values, fallback) {
2098
+ if (typeof value !== "string") {
2099
+ return fallback;
2100
+ }
2101
+ const normalizedValue = value.trim().toLowerCase();
2102
+ return values.includes(normalizedValue) ? normalizedValue : fallback;
2103
+ }
2104
+
2105
+ // src/renderer/typography-display.tsx
2106
+ import { createElement } from "react";
2107
+ var TYPOGRAPHY_TAGS = /* @__PURE__ */ new Set([
2108
+ "p",
2109
+ "span",
2110
+ "h1",
2111
+ "h2",
2112
+ "h3",
2113
+ "h4",
2114
+ "h5",
2115
+ "h6",
2116
+ "label",
2117
+ "strong",
2118
+ "em"
2119
+ ]);
2120
+ function TypographyDisplay({
2121
+ as,
2122
+ className,
2123
+ children,
2124
+ designPlaceholder
2125
+ }) {
2126
+ const text = normalizeTypographyChildren(children);
2127
+ const placeholder = normalizeTypographyPlaceholder(designPlaceholder);
2128
+ const Tag3 = normalizeTypographyAs(as);
2129
+ const baseClassName = normalizeTypographyClassName(className);
2130
+ if (text !== "") {
2131
+ return createElement(Tag3, {
2132
+ className: baseClassName,
2133
+ children: text
2134
+ });
2135
+ }
2136
+ if (!placeholder) {
2137
+ return null;
2138
+ }
2139
+ return createElement(Tag3, {
2140
+ className: [baseClassName, "opacity-50 italic text-gray-400"].filter(Boolean).join(" "),
2141
+ "data-typography-placeholder": "",
2142
+ children: placeholder
2143
+ });
2144
+ }
2145
+ function normalizeTypographyAs(value) {
2146
+ return typeof value === "string" && TYPOGRAPHY_TAGS.has(value) ? value : "p";
2147
+ }
2148
+ function normalizeTypographyClassName(value) {
2149
+ if (typeof value !== "string") {
2150
+ return void 0;
2151
+ }
2152
+ const className = value.trim();
2153
+ return className || void 0;
2154
+ }
2155
+ function normalizeTypographyChildren(value) {
2156
+ if (typeof value !== "string") {
2157
+ return "";
2158
+ }
2159
+ return value;
2160
+ }
2161
+ function normalizeTypographyPlaceholder(value) {
2162
+ if (typeof value !== "string") {
2163
+ return void 0;
2164
+ }
2165
+ const placeholder = value.trim();
2166
+ return placeholder || void 0;
2167
+ }
2168
+
2169
+ // src/renderer/slot-display.tsx
2170
+ import { Fragment as Fragment2, jsx as jsx17 } from "react/jsx-runtime";
2171
+ function SlotDisplay({
2172
+ className,
2173
+ children,
2174
+ designPlaceholder
2175
+ }) {
2176
+ if (children == null) {
2177
+ if (designPlaceholder === void 0) {
2178
+ return null;
2179
+ }
2180
+ return /* @__PURE__ */ jsx17(
2181
+ "div",
2182
+ {
2183
+ className: [
2184
+ "rounded border border-dashed border-stroke-secondary px-3 py-2 text-xs text-fg-tertiary",
2185
+ className
2186
+ ].filter(Boolean).join(" "),
2187
+ "data-slot-placeholder": "",
2188
+ children: designPlaceholder
2189
+ }
2190
+ );
2191
+ }
2192
+ if (className) {
2193
+ return /* @__PURE__ */ jsx17("div", { className, children });
2194
+ }
2195
+ return /* @__PURE__ */ jsx17(Fragment2, { children });
2196
+ }
2197
+
2198
+ // src/registry/display-registry.ts
2199
+ var displayRegistry = {
2200
+ alert: AlertDisplay,
2201
+ chips: ChipsDisplay,
2202
+ skeleton: SkeletonDisplay,
2203
+ tag: TagDisplay,
2204
+ table: TableDisplay,
2205
+ typography: TypographyDisplay,
2206
+ slot: SlotDisplay
2207
+ };
2208
+
2209
+ // src/renderer/display-execution.ts
2210
+ function executeRendererDisplayEvent(engine, nodeId, event, designMode, options) {
2211
+ if (designMode) {
2212
+ return void 0;
2213
+ }
2214
+ return engine.executeDisplayEvent(nodeId, event, options);
2215
+ }
2216
+ function executeRendererTableInteraction(engine, nodeId, interaction, designMode) {
2217
+ if (designMode) {
2218
+ return void 0;
2219
+ }
2220
+ return engine.executeTableInteraction(nodeId, interaction);
2221
+ }
2222
+
2223
+ // src/renderer/display-renderer.tsx
2224
+ import { jsx as jsx18 } from "react/jsx-runtime";
2225
+ function DisplayRenderer({ node }) {
2226
+ const schema = node.schema;
2227
+ const engine = useOptionalFormContext();
2228
+ const { designMode, slots } = useConfigContext();
2229
+ const repeatItem = useRepeatItem();
2230
+ const show = useDesignVisible(node.state.visible);
2231
+ const [, forceUpdate] = useState2(0);
2232
+ useEffect2(() => {
2233
+ if (!engine) {
2234
+ return;
2235
+ }
2236
+ return engine.subscribe(() => {
2237
+ forceUpdate((value) => value + 1);
2238
+ });
2239
+ }, [engine]);
2240
+ if (schema.kind !== "display" || !show) {
2241
+ return null;
2242
+ }
2243
+ const Component = displayRegistry[schema.type];
2244
+ if (!Component) {
2245
+ return null;
2246
+ }
2247
+ const executeEvent = (event) => {
2248
+ if (!engine) {
2249
+ return;
2250
+ }
2251
+ void executeRendererDisplayEvent(
2252
+ engine,
2253
+ node.id,
2254
+ event,
2255
+ designMode === true,
2256
+ repeatItem !== void 0 ? { item: repeatItem } : void 0
2257
+ );
2258
+ };
2259
+ const props = adaptDisplay({
2260
+ schema,
2261
+ onClose: () => executeEvent("close"),
2262
+ onAction: () => executeEvent("action"),
2263
+ onClick: () => executeEvent("click"),
2264
+ disabled: node.state.disabled
2265
+ });
2266
+ if (schema.type === "table") {
2267
+ const hasRowClick = Array.isArray(schema.events?.rowClick?.steps) && schema.events.rowClick.steps.length > 0;
2268
+ const engineState = engine?.getState();
2269
+ const rows = engine?.getTableRows(
2270
+ node.id,
2271
+ repeatItem !== void 0 ? { item: repeatItem } : void 0
2272
+ ) ?? [];
2273
+ return /* @__PURE__ */ jsx18(
2274
+ Component,
2275
+ {
2276
+ ...props,
2277
+ columns: schema.columns,
2278
+ rows,
2279
+ tableNodeId: node.id,
2280
+ pendingTableInteractions: engineState?.pendingTableInteractions ?? [],
2281
+ onRowClick: hasRowClick && engine ? (rowIndex) => {
2282
+ void executeRendererTableInteraction(
2283
+ engine,
2284
+ node.id,
2285
+ { kind: "rowClick", rowIndex },
2286
+ designMode === true
2287
+ );
2288
+ } : void 0,
2289
+ onActionClick: engine ? (columnId, actionId, rowIndex) => {
2290
+ void executeRendererTableInteraction(
2291
+ engine,
2292
+ node.id,
2293
+ { kind: "action", columnId, actionId, rowIndex },
2294
+ designMode === true
2295
+ );
2296
+ } : void 0
2297
+ }
2298
+ );
2299
+ }
2300
+ if (schema.type === "typography") {
2301
+ const text = engine?.getTypographyText(
2302
+ node.id,
2303
+ repeatItem !== void 0 ? { item: repeatItem } : void 0
2304
+ ) ?? "";
2305
+ const designPlaceholder = designMode === true && text === "" ? typeof schema.props.from === "string" && schema.props.from.trim() ? schema.props.from.trim() : "Typography" : void 0;
2306
+ return /* @__PURE__ */ jsx18(
2307
+ Component,
2308
+ {
2309
+ ...props,
2310
+ as: schema.props.as,
2311
+ className: schema.props.className,
2312
+ children: text,
2313
+ designPlaceholder
2314
+ }
2315
+ );
2316
+ }
2317
+ if (schema.type === "tag") {
2318
+ const presentation = engine?.getTagPresentation(
2319
+ node.id,
2320
+ repeatItem !== void 0 ? { item: repeatItem } : void 0
2321
+ ) ?? {
2322
+ label: typeof schema.props?.label === "string" || typeof schema.props?.label === "number" ? String(schema.props.label) : ""
2323
+ };
2324
+ const label = presentation.label;
2325
+ const designPlaceholder = designMode === true && label.trim() === "" ? typeof schema.props?.from === "string" && schema.props.from.trim() ? schema.props.from.trim() : void 0 : void 0;
2326
+ const resolvedLabel = label.trim() !== "" ? label : designPlaceholder !== void 0 ? designPlaceholder : label;
2327
+ const className = typeof schema.props?.className === "string" ? schema.props.className : void 0;
2328
+ return /* @__PURE__ */ jsx18(
2329
+ Component,
2330
+ {
2331
+ ...props,
2332
+ from: void 0,
2333
+ map: void 0,
2334
+ label: resolvedLabel,
2335
+ variant: presentation.variant ?? schema.props?.variant,
2336
+ className: designPlaceholder !== void 0 && label.trim() === "" ? [className, "opacity-50"].filter(Boolean).join(" ") : className
2337
+ }
2338
+ );
2339
+ }
2340
+ if (schema.type === "slot") {
2341
+ const slotName = schema.props.name;
2342
+ const className = typeof schema.props.className === "string" ? schema.props.className : void 0;
2343
+ const renderer = slots?.[slotName];
2344
+ const values = engine?.getValues() ?? {};
2345
+ const resources = engine?.getResources() ?? {};
2346
+ const children = renderer?.({ values, resources });
2347
+ const designPlaceholder = designMode === true && children == null ? `Slot \u201C${slotName}\u201D` : void 0;
2348
+ return /* @__PURE__ */ jsx18(
2349
+ Component,
2350
+ {
2351
+ className,
2352
+ designPlaceholder,
2353
+ children
2354
+ }
2355
+ );
2356
+ }
2357
+ return /* @__PURE__ */ jsx18(Component, { ...props });
2358
+ }
2359
+
2360
+ // src/renderer/node-renderer.tsx
2361
+ import { jsx as jsx19 } from "react/jsx-runtime";
2362
+ function NodeRenderer({ node }) {
2363
+ const { renderWrapper } = useConfigContext();
2364
+ const schema = node.schema;
2365
+ const createChildren = ({
2366
+ node: node2,
2367
+ children
2368
+ }) => {
2369
+ if (renderWrapper)
2370
+ return renderWrapper({
2371
+ node: node2,
2372
+ children
2373
+ });
2374
+ return children;
2375
+ };
2376
+ switch (schema.kind) {
2377
+ case "field":
2378
+ return createChildren({ node, children: /* @__PURE__ */ jsx19(FieldRenderer, { node }) });
2379
+ case "layout":
2380
+ return createChildren({
2381
+ node,
2382
+ children: /* @__PURE__ */ jsx19(LayoutRenderer, { node })
2383
+ });
2384
+ case "action":
2385
+ return createChildren({ node, children: /* @__PURE__ */ jsx19(ActionRenderer, { node }) });
2386
+ case "display":
2387
+ return createChildren({ node, children: /* @__PURE__ */ jsx19(DisplayRenderer, { node }) });
2388
+ default:
2389
+ return null;
2390
+ }
2391
+ }
2392
+
2393
+ // src/components/layout-types.ts
2394
+ function normalizeLayoutClassName(value) {
2395
+ if (typeof value !== "string") {
2396
+ return void 0;
2397
+ }
2398
+ const className = value.trim();
2399
+ return className || void 0;
2400
+ }
2401
+ function normalizeLayoutGap(value, fallback) {
2402
+ const numericValue = toFiniteNumber(value);
2403
+ if (numericValue !== void 0) {
2404
+ return numericValue >= 0 ? numericValue : fallback;
2405
+ }
2406
+ if (typeof value === "string") {
2407
+ const cssValue = value.trim();
2408
+ return cssValue || fallback;
2409
+ }
2410
+ return fallback;
2411
+ }
2412
+ function toFiniteNumber(value) {
2413
+ if (typeof value === "number") {
2414
+ return Number.isFinite(value) ? value : void 0;
2415
+ }
2416
+ if (typeof value !== "string" || value.trim() === "") {
2417
+ return void 0;
2418
+ }
2419
+ const numericValue = Number(value);
2420
+ return Number.isFinite(numericValue) ? numericValue : void 0;
2421
+ }
2422
+
2423
+ // src/components/grid.tsx
2424
+ import { jsx as jsx20 } from "react/jsx-runtime";
2425
+ var DEFAULT_COLUMNS = 1;
2426
+ var DEFAULT_ROW_GAP = 48;
2427
+ var DEFAULT_COLUMN_GAP = 32;
2428
+ function Grid({
2429
+ columns,
2430
+ children,
2431
+ className,
2432
+ gap,
2433
+ rowGap,
2434
+ columnGap
2435
+ }) {
2436
+ const customClassName = normalizeLayoutClassName(className);
2437
+ return /* @__PURE__ */ jsx20(
2438
+ "div",
2439
+ {
2440
+ className: customClassName ? `grid ${customClassName}` : "grid",
2441
+ style: {
2442
+ display: "grid",
2443
+ gridTemplateColumns: `repeat(${normalizeGridColumns(columns)}, minmax(0,1fr))`,
2444
+ rowGap: normalizeLayoutGap(
2445
+ rowGap,
2446
+ normalizeLayoutGap(gap, DEFAULT_ROW_GAP)
2447
+ ),
2448
+ columnGap: normalizeLayoutGap(
2449
+ columnGap,
2450
+ normalizeLayoutGap(gap, DEFAULT_COLUMN_GAP)
2451
+ )
2452
+ },
2453
+ children
2454
+ }
2455
+ );
2456
+ }
2457
+ function normalizeGridColumns(value) {
2458
+ const parsedValue = toFiniteNumber2(value);
2459
+ if (parsedValue === void 0 || parsedValue < 1) {
2460
+ return DEFAULT_COLUMNS;
2461
+ }
2462
+ return Math.floor(parsedValue);
2463
+ }
2464
+ function toFiniteNumber2(value) {
2465
+ if (typeof value === "number") {
2466
+ return Number.isFinite(value) ? value : void 0;
2467
+ }
2468
+ if (typeof value !== "string" || value.trim() === "") {
2469
+ return void 0;
2470
+ }
2471
+ const numericValue = Number(value);
2472
+ return Number.isFinite(numericValue) ? numericValue : void 0;
2473
+ }
2474
+
2475
+ // src/components/row.tsx
2476
+ import { jsx as jsx21 } from "react/jsx-runtime";
2477
+ var DEFAULT_GAP = 16;
2478
+ var ALIGN_ITEMS_VALUES = [
2479
+ "flex-start",
2480
+ "center",
2481
+ "flex-end",
2482
+ "stretch",
2483
+ "baseline"
2484
+ ];
2485
+ var JUSTIFY_CONTENT_VALUES = [
2486
+ "flex-start",
2487
+ "center",
2488
+ "flex-end",
2489
+ "space-between",
2490
+ "space-around",
2491
+ "space-evenly"
2492
+ ];
2493
+ var FLEX_WRAP_VALUES = ["nowrap", "wrap", "wrap-reverse"];
2494
+ var ALIGN_ITEMS_ALIASES = {
2495
+ start: "flex-start",
2496
+ end: "flex-end"
2497
+ };
2498
+ var JUSTIFY_CONTENT_ALIASES = {
2499
+ start: "flex-start",
2500
+ end: "flex-end",
2501
+ between: "space-between",
2502
+ around: "space-around",
2503
+ evenly: "space-evenly"
2504
+ };
2505
+ function Row({
2506
+ children,
2507
+ className,
2508
+ gap,
2509
+ rowGap,
2510
+ columnGap,
2511
+ alignItems,
2512
+ justifyContent,
2513
+ flexWrap
2514
+ }) {
2515
+ const customClassName = normalizeLayoutClassName(className);
2516
+ const normalizedGap = normalizeLayoutGap(gap, DEFAULT_GAP);
2517
+ return /* @__PURE__ */ jsx21(
2518
+ "div",
2519
+ {
2520
+ className: customClassName ? `form-row ${customClassName}` : "form-row",
2521
+ style: {
2522
+ display: "flex",
2523
+ flexDirection: "row",
2524
+ rowGap: normalizeLayoutGap(rowGap, normalizedGap),
2525
+ columnGap: normalizeLayoutGap(columnGap, normalizedGap),
2526
+ alignItems: normalizeRowAlignItems(alignItems),
2527
+ justifyContent: normalizeRowJustifyContent(justifyContent),
2528
+ flexWrap: normalizeRowFlexWrap(flexWrap)
2529
+ },
2530
+ children
2531
+ }
2532
+ );
2533
+ }
2534
+ function normalizeRowAlignItems(value) {
2535
+ return normalizeRowValue(
2536
+ value,
2537
+ ALIGN_ITEMS_VALUES,
2538
+ ALIGN_ITEMS_ALIASES,
2539
+ "flex-start"
2540
+ );
2541
+ }
2542
+ function normalizeRowJustifyContent(value) {
2543
+ return normalizeRowValue(
2544
+ value,
2545
+ JUSTIFY_CONTENT_VALUES,
2546
+ JUSTIFY_CONTENT_ALIASES,
2547
+ "flex-start"
2548
+ );
2549
+ }
2550
+ function normalizeRowFlexWrap(value) {
2551
+ if (value === true) {
2552
+ return "wrap";
2553
+ }
2554
+ if (value === false) {
2555
+ return "nowrap";
2556
+ }
2557
+ return normalizeRowValue(value, FLEX_WRAP_VALUES, {}, "wrap");
2558
+ }
2559
+ function normalizeRowValue(value, values, aliases, fallback) {
2560
+ if (typeof value !== "string") {
2561
+ return fallback;
2562
+ }
2563
+ const normalizedValue = value.trim().toLowerCase();
2564
+ const alias = aliases[normalizedValue];
2565
+ if (alias) {
2566
+ return alias;
2567
+ }
2568
+ return values.includes(normalizedValue) ? normalizedValue : fallback;
2569
+ }
2570
+
2571
+ // src/components/section.tsx
2572
+ import { jsx as jsx22 } from "react/jsx-runtime";
2573
+ function Section({ children, className }) {
2574
+ return /* @__PURE__ */ jsx22("section", { className: normalizeLayoutClassName(className), children: /* @__PURE__ */ jsx22("div", { className: "space-y-8", children }) });
2575
+ }
2576
+
2577
+ // src/components/div.tsx
2578
+ import { jsx as jsx23 } from "react/jsx-runtime";
2579
+ function Div({ children, className }) {
2580
+ return /* @__PURE__ */ jsx23("div", { className: normalizeLayoutClassName(className), children });
2581
+ }
2582
+
2583
+ // src/components/scroll-area.tsx
2584
+ import { ScrollArea } from "bsm-design-system";
2585
+ import { jsx as jsx24 } from "react/jsx-runtime";
2586
+ var DEFAULT_SCROLL_HIDE_DELAY = 600;
2587
+ function ScrollAreaLayout({
2588
+ ariaLabel,
2589
+ children,
2590
+ className,
2591
+ dir,
2592
+ scrollAreaType,
2593
+ scrollHideDelay,
2594
+ viewportClassName
2595
+ }) {
2596
+ const normalizedAriaLabel = normalizeScrollAreaAriaLabel(ariaLabel);
2597
+ return /* @__PURE__ */ jsx24(
2598
+ ScrollArea,
2599
+ {
2600
+ className: normalizeLayoutClassName(className),
2601
+ viewportClassName: normalizeLayoutClassName(viewportClassName),
2602
+ type: normalizeScrollAreaType(scrollAreaType),
2603
+ dir: normalizeScrollAreaDirection(dir),
2604
+ scrollHideDelay: normalizeScrollHideDelay(scrollHideDelay),
2605
+ role: normalizedAriaLabel ? "region" : void 0,
2606
+ "aria-label": normalizedAriaLabel,
2607
+ children
2608
+ }
2609
+ );
2610
+ }
2611
+ function normalizeScrollAreaType(value) {
2612
+ return value === "scroll" || value === "auto" || value === "always" ? value : "hover";
2613
+ }
2614
+ function normalizeScrollAreaDirection(value) {
2615
+ return value === "ltr" ? "ltr" : "rtl";
2616
+ }
2617
+ function normalizeScrollHideDelay(value) {
2618
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : DEFAULT_SCROLL_HIDE_DELAY;
2619
+ }
2620
+ function normalizeScrollAreaAriaLabel(value) {
2621
+ if (typeof value !== "string") {
2622
+ return void 0;
2623
+ }
2624
+ const ariaLabel = value.trim();
2625
+ return ariaLabel || void 0;
2626
+ }
2627
+
2628
+ // src/components/badge.tsx
2629
+ import { Badge } from "bsm-design-system";
2630
+ import { jsx as jsx25 } from "react/jsx-runtime";
2631
+ function BadgeLayout({
2632
+ ariaLabel,
2633
+ badgeContent,
2634
+ badgeOffsetX,
2635
+ badgeOffsetY,
2636
+ badgeShow,
2637
+ badgeType,
2638
+ children,
2639
+ className
2640
+ }) {
2641
+ const normalizedAriaLabel = normalizeBadgeAriaLabel(ariaLabel);
2642
+ return /* @__PURE__ */ jsx25(
2643
+ Badge,
2644
+ {
2645
+ content: normalizeBadgeContent(badgeContent),
2646
+ show: normalizeBadgeShow(badgeShow),
2647
+ type: normalizeBadgeType(badgeType),
2648
+ offsetX: normalizeBadgeOffset(badgeOffsetX),
2649
+ offsetY: normalizeBadgeOffset(badgeOffsetY),
2650
+ className: normalizeLayoutClassName(className),
2651
+ role: normalizedAriaLabel ? "group" : void 0,
2652
+ "aria-label": normalizedAriaLabel,
2653
+ children
2654
+ }
2655
+ );
2656
+ }
2657
+ function normalizeBadgeContent(value) {
2658
+ if (typeof value === "string") {
2659
+ const content = value.trim();
2660
+ return content || void 0;
2661
+ }
2662
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : void 0;
2663
+ }
2664
+ function normalizeBadgeShow(value) {
2665
+ return value !== false;
2666
+ }
2667
+ function normalizeBadgeType(value) {
2668
+ if (value === "success" || value === "error" || value === "warning") {
2669
+ return value;
2670
+ }
2671
+ return value === "process" || value === "proccess" ? "proccess" : "default";
2672
+ }
2673
+ function normalizeBadgeOffset(value) {
2674
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
2675
+ }
2676
+ function normalizeBadgeAriaLabel(value) {
2677
+ if (typeof value !== "string") {
2678
+ return void 0;
2679
+ }
2680
+ const ariaLabel = value.trim();
2681
+ return ariaLabel || void 0;
2682
+ }
2683
+
2684
+ // src/components/card.tsx
2685
+ import { Card } from "bsm-design-system";
2686
+ import { jsx as jsx26 } from "react/jsx-runtime";
2687
+ function CardLayout({
2688
+ ariaLabel,
2689
+ children,
2690
+ className
2691
+ }) {
2692
+ const normalizedAriaLabel = normalizeCardAriaLabel(ariaLabel);
2693
+ return /* @__PURE__ */ jsx26(
2694
+ Card,
2695
+ {
2696
+ className: normalizeLayoutClassName(className),
2697
+ role: normalizedAriaLabel ? "group" : void 0,
2698
+ "aria-label": normalizedAriaLabel,
2699
+ children
2700
+ }
2701
+ );
2702
+ }
2703
+ function CardHeaderLayout({
2704
+ cardDivider,
2705
+ children,
2706
+ className
2707
+ }) {
2708
+ return /* @__PURE__ */ jsx26(
2709
+ Card.Header,
2710
+ {
2711
+ className: normalizeCardSlotClassName(
2712
+ className,
2713
+ cardDivider,
2714
+ "border-b"
2715
+ ),
2716
+ children
2717
+ }
2718
+ );
2719
+ }
2720
+ function CardContentLayout({
2721
+ children,
2722
+ className
2723
+ }) {
2724
+ return /* @__PURE__ */ jsx26(Card.Content, { className: normalizeLayoutClassName(className), children });
2725
+ }
2726
+ function CardFooterLayout({
2727
+ cardDivider,
2728
+ children,
2729
+ className
2730
+ }) {
2731
+ return /* @__PURE__ */ jsx26(
2732
+ Card.Footer,
2733
+ {
2734
+ className: normalizeCardSlotClassName(
2735
+ className,
2736
+ cardDivider,
2737
+ "border-t"
2738
+ ),
2739
+ children
2740
+ }
2741
+ );
2742
+ }
2743
+ function normalizeCardAriaLabel(value) {
2744
+ if (typeof value !== "string") {
2745
+ return void 0;
2746
+ }
2747
+ const ariaLabel = value.trim();
2748
+ return ariaLabel || void 0;
2749
+ }
2750
+ function normalizeCardDivider(value) {
2751
+ return value === true;
2752
+ }
2753
+ function normalizeCardSlotClassName(value, divider, dividerClassName) {
2754
+ const className = normalizeLayoutClassName(value);
2755
+ return [className, normalizeCardDivider(divider) && dividerClassName].filter(Boolean).join(" ") || void 0;
2756
+ }
2757
+
2758
+ // src/registry/layout-registry.ts
2759
+ var layoutRegistry = {
2760
+ badge: BadgeLayout,
2761
+ card: CardLayout,
2762
+ "card-header": CardHeaderLayout,
2763
+ "card-content": CardContentLayout,
2764
+ "card-footer": CardFooterLayout,
2765
+ div: Div,
2766
+ grid: Grid,
2767
+ row: Row,
2768
+ "scroll-area": ScrollAreaLayout,
2769
+ section: Section
2770
+ };
2771
+
2772
+ // src/renderer/tabs-renderer.tsx
2773
+ import { useEffect as useEffect3, useState as useState3 } from "react";
2774
+ import { Tabs } from "bsm-design-system";
2775
+
2776
+ // src/renderer/legacy-container-items.ts
2777
+ function normalizeLegacyContainerItems(children, fallbackLabel) {
2778
+ const ids = /* @__PURE__ */ new Set();
2779
+ const items = [];
2780
+ children.forEach((node, index) => {
2781
+ if (typeof node.id !== "string" || node.id.trim() === "" || ids.has(node.id)) {
2782
+ return;
2783
+ }
2784
+ ids.add(node.id);
2785
+ const schema = readRecord(node.schema);
2786
+ const props = readRecord(schema?.props);
2787
+ items.push({
2788
+ disabled: node.state.disabled || schema?.disabled === true || props?.disabled === true,
2789
+ id: node.id,
2790
+ node,
2791
+ title: normalizeContainerTitle(
2792
+ schema?.title ?? props?.title,
2793
+ `${fallbackLabel} ${index + 1}`
2794
+ )
2795
+ });
2796
+ });
2797
+ return items;
2798
+ }
2799
+ function resolveContainerInitialValue(value, fallbackValue, items) {
2800
+ for (const candidate of [value, fallbackValue]) {
2801
+ if (typeof candidate === "string" && items.some((item) => item.id === candidate)) {
2802
+ return candidate;
2803
+ }
2804
+ }
2805
+ return items.find((item) => !item.disabled)?.id ?? items[0]?.id ?? "";
2806
+ }
2807
+ function resolveContainerInitialValues(value, fallbackValue, items) {
2808
+ for (const candidate of [value, fallbackValue]) {
2809
+ if (Array.isArray(candidate)) {
2810
+ const values = candidate.filter(
2811
+ (item, index) => typeof item === "string" && candidate.indexOf(item) === index && items.some((containerItem) => containerItem.id === item)
2812
+ );
2813
+ if (values.length > 0 || candidate.length === 0) {
2814
+ return values;
2815
+ }
2816
+ }
2817
+ }
2818
+ return [];
2819
+ }
2820
+ function normalizeContainerTitle(value, fallback) {
2821
+ if (typeof value === "string" && value.trim() !== "") {
2822
+ return value.trim();
2823
+ }
2824
+ return typeof value === "number" && Number.isFinite(value) ? String(value) : fallback;
2825
+ }
2826
+ function readRecord(value) {
2827
+ return typeof value === "object" && value !== null ? value : void 0;
2828
+ }
2829
+
2830
+ // src/renderer/tabs-execution.ts
2831
+ function executeRendererTabsChange(engine, tabsId, tabId, designMode) {
2832
+ if (designMode) {
2833
+ return;
2834
+ }
2835
+ return engine.changeTabs(tabsId, tabId);
2836
+ }
2837
+
2838
+ // src/renderer/tabs-renderer.tsx
2839
+ import { jsx as jsx27, jsxs as jsxs9 } from "react/jsx-runtime";
2840
+ function TabsRenderer({ node }) {
2841
+ if (node.schema.kind !== "layout" || node.schema.type !== "tabs") {
2842
+ return null;
2843
+ }
2844
+ return /* @__PURE__ */ jsx27(TabsLayout, { node });
2845
+ }
2846
+ function TabsLayout({ node }) {
2847
+ const engine = useOptionalFormContext();
2848
+ const { designMode } = useConfigContext();
2849
+ const props = node.schema.props;
2850
+ const items = normalizeLegacyContainerItems(node.children, "Tab");
2851
+ const initialValue = resolveContainerInitialValue(
2852
+ props?.value,
2853
+ props?.defaultValue,
2854
+ items
2855
+ );
2856
+ const engineActiveTabId = engine?.getTabsState(node.id)?.activeTabId;
2857
+ const [selectedValue, setSelectedValue] = useState3(
2858
+ engineActiveTabId ?? initialValue
2859
+ );
2860
+ useEffect3(() => {
2861
+ if (designMode === true || !engine) {
2862
+ setSelectedValue(initialValue);
2863
+ }
2864
+ }, [designMode, engine, initialValue]);
2865
+ useEffect3(() => {
2866
+ if (designMode === true || !engine || !engineActiveTabId) {
2867
+ return;
2868
+ }
2869
+ setSelectedValue(engineActiveTabId);
2870
+ }, [designMode, engine, engineActiveTabId]);
2871
+ const activeValue = items.some((item) => item.id === selectedValue) ? selectedValue : engineActiveTabId && items.some((item) => item.id === engineActiveTabId) ? engineActiveTabId : initialValue;
2872
+ return /* @__PURE__ */ jsxs9(
2873
+ Tabs,
2874
+ {
2875
+ id: node.id,
2876
+ className: normalizeClassName3(props?.className),
2877
+ value: activeValue,
2878
+ onChange: (nextValue) => {
2879
+ setSelectedValue(nextValue);
2880
+ if (designMode === true || !engine) {
2881
+ return;
2882
+ }
2883
+ void executeRendererTabsChange(engine, node.id, nextValue, false);
2884
+ },
2885
+ variant: normalizeTabsVariant(props?.variant),
2886
+ size: normalizeTabsSize(props?.size),
2887
+ fullWidth: props?.fullWidth === true,
2888
+ dir: normalizeDirection(props?.dir),
2889
+ activationMode: normalizeActivationMode(props?.activationMode),
2890
+ "aria-label": normalizeAriaLabel(props?.["aria-label"]),
2891
+ children: [
2892
+ /* @__PURE__ */ jsx27(
2893
+ Tabs.List,
2894
+ {
2895
+ loop: props?.loop !== false,
2896
+ className: joinClassNames2(
2897
+ props?.fullWidth === true ? "w-full" : void 0,
2898
+ designMode === true ? "pointer-events-auto" : void 0
2899
+ ),
2900
+ children: items.map((item) => /* @__PURE__ */ jsx27(
2901
+ Tabs.Trigger,
2902
+ {
2903
+ value: item.id,
2904
+ disabled: item.disabled,
2905
+ className: props?.fullWidth === true ? "flex-1" : void 0,
2906
+ children: item.title
2907
+ },
2908
+ item.id
2909
+ ))
2910
+ }
2911
+ ),
2912
+ items.map((item) => /* @__PURE__ */ jsx27(Tabs.Content, { value: item.id, children: item.node.children.map((child) => /* @__PURE__ */ jsx27(NodeRenderer, { node: child }, child.id)) }, item.id))
2913
+ ]
2914
+ }
2915
+ );
2916
+ }
2917
+ function normalizeTabsVariant(value) {
2918
+ return value === "filled" ? "filled" : "underline";
2919
+ }
2920
+ function normalizeTabsSize(value) {
2921
+ return value === "sm" || value === "lg" ? value : "md";
2922
+ }
2923
+ function normalizeDirection(value) {
2924
+ return value === "ltr" ? "ltr" : "rtl";
2925
+ }
2926
+ function normalizeActivationMode(value) {
2927
+ return value === "manual" || value === "automatic" ? value : void 0;
2928
+ }
2929
+ function normalizeClassName3(value) {
2930
+ return typeof value === "string" ? value : "";
2931
+ }
2932
+ function joinClassNames2(...parts) {
2933
+ return parts.filter(Boolean).join(" ") || void 0;
2934
+ }
2935
+ function normalizeAriaLabel(value) {
2936
+ return typeof value === "string" && value.trim() ? value : void 0;
2937
+ }
2938
+
2939
+ // src/renderer/accordion-renderer.tsx
2940
+ import { Accordion } from "bsm-design-system";
2941
+
2942
+ // src/renderer/accordion-execution.ts
2943
+ function executeRendererAccordionChange(engine, accordionId, nextValue, designMode) {
2944
+ if (designMode) {
2945
+ return;
2946
+ }
2947
+ return engine.changeAccordion(accordionId, nextValue);
2948
+ }
2949
+
2950
+ // src/renderer/accordion-renderer.tsx
2951
+ import { jsx as jsx28, jsxs as jsxs10 } from "react/jsx-runtime";
2952
+ function AccordionRenderer({ node }) {
2953
+ if (node.schema.kind !== "layout" || node.schema.type !== "accordion") {
2954
+ return null;
2955
+ }
2956
+ const engine = useOptionalFormContext();
2957
+ const { designMode } = useConfigContext();
2958
+ const props = node.schema.props;
2959
+ const items = normalizeLegacyContainerItems(node.children, "Section");
2960
+ const engineState = engine?.getAccordionState(node.id);
2961
+ const sharedProps = {
2962
+ id: node.id,
2963
+ className: typeof props?.className === "string" ? props.className : "",
2964
+ separate: props?.separate !== false,
2965
+ variant: normalizeAccordionVariant(props?.variant),
2966
+ iconPosition: normalizeAccordionIconPosition(props?.iconPosition),
2967
+ dir: props?.dir === "ltr" || props?.dir === "rtl" ? props.dir : void 0,
2968
+ "aria-label": typeof props?.["aria-label"] === "string" && props["aria-label"].trim() ? props["aria-label"] : void 0
2969
+ };
2970
+ const canDriveEngine = engine !== void 0 && engine !== null && designMode !== true;
2971
+ const commitAccordionChange = (nextValue) => {
2972
+ if (!engine || designMode === true) {
2973
+ return;
2974
+ }
2975
+ void executeRendererAccordionChange(engine, node.id, nextValue, false);
2976
+ };
2977
+ if (props?.type === "multiple") {
2978
+ const defaultValue2 = resolveContainerInitialValues(
2979
+ props.value,
2980
+ props.defaultValue,
2981
+ items
2982
+ );
2983
+ const value2 = engineState?.openItemIds ?? defaultValue2;
2984
+ return /* @__PURE__ */ jsx28(
2985
+ Accordion,
2986
+ {
2987
+ ...sharedProps,
2988
+ type: "multiple",
2989
+ ...canDriveEngine ? {
2990
+ value: value2,
2991
+ onChange: commitAccordionChange
2992
+ } : { defaultValue: defaultValue2 },
2993
+ children: /* @__PURE__ */ jsx28(AccordionItems, { items, designMode: designMode === true })
2994
+ }
2995
+ );
2996
+ }
2997
+ const defaultValue = resolveOptionalContainerInitialValue(
2998
+ props?.value,
2999
+ props?.defaultValue,
3000
+ items
3001
+ );
3002
+ const value = engineState !== void 0 ? engineState.openItemIds[0] : defaultValue;
3003
+ return /* @__PURE__ */ jsx28(
3004
+ Accordion,
3005
+ {
3006
+ ...sharedProps,
3007
+ type: "single",
3008
+ collapsible: props?.collapsible !== false,
3009
+ ...canDriveEngine ? {
3010
+ value,
3011
+ onChange: commitAccordionChange
3012
+ } : { defaultValue },
3013
+ children: /* @__PURE__ */ jsx28(AccordionItems, { items, designMode: designMode === true })
3014
+ }
3015
+ );
3016
+ }
3017
+ function normalizeAccordionVariant(value) {
3018
+ return value === "ghost" ? "ghost" : "default";
3019
+ }
3020
+ function normalizeAccordionIconPosition(value) {
3021
+ return value === "start" ? "start" : "end";
3022
+ }
3023
+ function AccordionItems({
3024
+ items,
3025
+ designMode
3026
+ }) {
3027
+ const engine = useOptionalFormContext();
3028
+ const repeatItem = useRepeatItem();
3029
+ return items.map((item) => {
3030
+ const resolvedTitle = engine?.getAccordionItemTitle(
3031
+ item.id,
3032
+ repeatItem !== void 0 ? { item: repeatItem } : void 0
3033
+ ) ?? "";
3034
+ const titleFrom = item.node.schema.kind === "layout" && item.node.schema.type === "accordion-item" && typeof item.node.schema.props?.titleFrom === "string" ? item.node.schema.props.titleFrom : void 0;
3035
+ const title = resolvedTitle.trim() !== "" ? resolvedTitle : designMode === true && titleFrom ? titleFrom : item.title;
3036
+ return /* @__PURE__ */ jsxs10(
3037
+ Accordion.Item,
3038
+ {
3039
+ value: item.id,
3040
+ disabled: item.disabled,
3041
+ children: [
3042
+ /* @__PURE__ */ jsx28(
3043
+ Accordion.Trigger,
3044
+ {
3045
+ className: designMode ? "pointer-events-auto" : void 0,
3046
+ children: title
3047
+ }
3048
+ ),
3049
+ /* @__PURE__ */ jsx28(Accordion.Content, { children: item.node.children.map((child) => /* @__PURE__ */ jsx28(NodeRenderer, { node: child }, child.id)) })
3050
+ ]
3051
+ },
3052
+ item.id
3053
+ );
3054
+ });
3055
+ }
3056
+ function resolveOptionalContainerInitialValue(value, fallbackValue, items) {
3057
+ for (const candidate of [value, fallbackValue]) {
3058
+ if (candidate === "") {
3059
+ return void 0;
3060
+ }
3061
+ if (typeof candidate === "string" && items.some((item) => item.id === candidate)) {
3062
+ return candidate;
3063
+ }
3064
+ }
3065
+ return void 0;
3066
+ }
3067
+
3068
+ // src/renderer/stepper-renderer.tsx
3069
+ import { Stepper } from "bsm-design-system";
3070
+ import { useEffect as useEffect4, useState as useState4 } from "react";
3071
+
3072
+ // src/renderer/step-renderer.tsx
3073
+ import { jsx as jsx29, jsxs as jsxs11 } from "react/jsx-runtime";
3074
+ var DEFAULT_STEP_ACTIONS_CLASSNAME = "flex flex-wrap items-center gap-2";
3075
+ function StepRenderer({ node }) {
3076
+ const show = useDesignVisible(node.state.visible);
3077
+ if (node.schema.kind !== "layout" || node.schema.type !== "step" || !show) {
3078
+ return null;
3079
+ }
3080
+ const contentChildren = [];
3081
+ const actionChildren = [];
3082
+ for (const child of node.children) {
3083
+ if (child.schema.kind === "action") {
3084
+ actionChildren.push(child);
3085
+ } else {
3086
+ contentChildren.push(child);
3087
+ }
3088
+ }
3089
+ return /* @__PURE__ */ jsxs11(
3090
+ "div",
3091
+ {
3092
+ id: `${node.id}-content`,
3093
+ role: "group",
3094
+ "aria-label": normalizeStepLabel(node.schema.props.label),
3095
+ className: normalizeClassName4(node.schema.props.className),
3096
+ "data-step-id": node.id,
3097
+ children: [
3098
+ contentChildren.map((child) => /* @__PURE__ */ jsx29(NodeRenderer, { node: child }, child.id)),
3099
+ actionChildren.length > 0 ? /* @__PURE__ */ jsx29(
3100
+ "div",
3101
+ {
3102
+ className: joinClassNames3(
3103
+ DEFAULT_STEP_ACTIONS_CLASSNAME,
3104
+ normalizeClassName4(node.schema.props.actionsClassName)
3105
+ ),
3106
+ "data-step-actions": "",
3107
+ children: actionChildren.map((child) => /* @__PURE__ */ jsx29(NodeRenderer, { node: child }, child.id))
3108
+ }
3109
+ ) : null
3110
+ ]
3111
+ }
3112
+ );
3113
+ }
3114
+ function normalizeStepLabel(value) {
3115
+ return typeof value === "string" ? value.trim() : "";
3116
+ }
3117
+ function normalizeClassName4(value) {
3118
+ return typeof value === "string" ? value.trim() : "";
3119
+ }
3120
+ function joinClassNames3(...parts) {
3121
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
3122
+ }
3123
+
3124
+ // src/renderer/stepper-execution.ts
3125
+ function executeRendererStepperNavigation(engine, stepperId, stepId, designMode) {
3126
+ if (designMode) {
3127
+ return;
3128
+ }
3129
+ return engine.goToStep(stepperId, stepId);
3130
+ }
3131
+
3132
+ // src/renderer/stepper-renderer.tsx
3133
+ import { jsx as jsx30, jsxs as jsxs12 } from "react/jsx-runtime";
3134
+ function StepperRenderer({ node }) {
3135
+ if (node.schema.kind !== "layout" || node.schema.type !== "stepper") {
3136
+ return null;
3137
+ }
3138
+ const engine = useFormContext();
3139
+ const { designMode } = useConfigContext();
3140
+ const props = node.schema.props;
3141
+ const state = engine.getStepperState(node.id);
3142
+ const visibleSteps = node.children.filter(
3143
+ (child) => child.schema.kind === "layout" && child.schema.type === "step" && (designMode === true || child.state.visible)
3144
+ );
3145
+ const items = visibleSteps.map((step, index) => ({
3146
+ id: index + 1,
3147
+ label: normalizeStepLabel(step.schema.props?.label),
3148
+ caption: normalizeOptionalText(step.schema.props?.caption),
3149
+ disabled: step.state.disabled || step.schema.props?.disabled === true,
3150
+ step
3151
+ }));
3152
+ const engineActiveStepId = state?.activeStepId;
3153
+ const [designActiveStepId, setDesignActiveStepId] = useState4(
3154
+ engineActiveStepId
3155
+ );
3156
+ useEffect4(() => {
3157
+ if (designMode === true) {
3158
+ setDesignActiveStepId(engineActiveStepId);
3159
+ }
3160
+ }, [designMode, engineActiveStepId]);
3161
+ const activeStepId = designMode === true ? designActiveStepId : engineActiveStepId;
3162
+ const activeItem = items.find((item) => item.step.id === activeStepId);
3163
+ const isReady = engine.getState().initializationStatus === "ready";
3164
+ return /* @__PURE__ */ jsxs12(
3165
+ "section",
3166
+ {
3167
+ id: node.id,
3168
+ "aria-label": normalizeAriaLabel2(props?.ariaLabel),
3169
+ children: [
3170
+ /* @__PURE__ */ jsx30("div", { className: designMode === true ? "pointer-events-auto" : void 0, children: /* @__PURE__ */ jsx30(
3171
+ Stepper,
3172
+ {
3173
+ steps: items.map(({ step: _step, ...item }) => item),
3174
+ activeStep: activeItem?.id ?? 0,
3175
+ onChange: (numericId) => {
3176
+ const target = items.find((item) => item.id === numericId);
3177
+ if (!target) return;
3178
+ if (designMode === true) {
3179
+ setDesignActiveStepId(target.step.id);
3180
+ return;
3181
+ }
3182
+ executeRendererStepperNavigation(
3183
+ engine,
3184
+ node.id,
3185
+ target.step.id,
3186
+ false
3187
+ );
3188
+ },
3189
+ orientation: normalizeStepperOrientation(props?.orientation),
3190
+ className: normalizeClassName5(props?.className),
3191
+ clickable: designMode === true || props?.clickable === true && isReady,
3192
+ dotStyle: props?.dotStyle === true,
3193
+ connector: normalizeStepperConnector(props?.connector)
3194
+ }
3195
+ ) }),
3196
+ activeItem ? /* @__PURE__ */ jsx30("div", { className: normalizeClassName5(props?.contentClassName), children: /* @__PURE__ */ jsx30(NodeRenderer, { node: activeItem.step }) }) : null
3197
+ ]
3198
+ }
3199
+ );
3200
+ }
3201
+ function normalizeStepperOrientation(value) {
3202
+ return value === "vertical" ? "vertical" : "horizontal";
3203
+ }
3204
+ function normalizeStepperConnector(value) {
3205
+ return value === "dashed" ? "dashed" : "solid";
3206
+ }
3207
+ function normalizeOptionalText(value) {
3208
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
3209
+ }
3210
+ function normalizeClassName5(value) {
3211
+ return typeof value === "string" ? value.trim() : "";
3212
+ }
3213
+ function normalizeAriaLabel2(value) {
3214
+ return typeof value === "string" && value.trim() ? value.trim() : "Form steps";
3215
+ }
3216
+
3217
+ // src/renderer/dialog-renderer.tsx
3218
+ import { Dialog } from "bsm-design-system";
3219
+
3220
+ // src/renderer/dialog-execution.ts
3221
+ function executeRendererDialogChange(engine, dialogId, open, designMode) {
3222
+ if (designMode) {
3223
+ return;
3224
+ }
3225
+ return open ? engine.openDialog(dialogId) : engine.closeDialog(dialogId);
3226
+ }
3227
+
3228
+ // src/renderer/dialog-renderer.tsx
3229
+ import { jsx as jsx31, jsxs as jsxs13 } from "react/jsx-runtime";
3230
+ function DialogRenderer({ node }) {
3231
+ if (node.schema.kind !== "layout" || node.schema.type !== "dialog") {
3232
+ return null;
3233
+ }
3234
+ const engine = useFormContext();
3235
+ const { designMode } = useConfigContext();
3236
+ if (designMode === true) {
3237
+ return /* @__PURE__ */ jsxs13(
3238
+ "div",
3239
+ {
3240
+ className: "space-y-2 rounded border border-dashed border-gray-300 p-2",
3241
+ "data-design-overlay": "dialog",
3242
+ children: [
3243
+ /* @__PURE__ */ jsx31("div", { className: "text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Dialog" }),
3244
+ node.children.map((child) => /* @__PURE__ */ jsx31(NodeRenderer, { node: child }, child.id))
3245
+ ]
3246
+ }
3247
+ );
3248
+ }
3249
+ const state = engine.getDialogState(node.id);
3250
+ return /* @__PURE__ */ jsx31(
3251
+ Dialog,
3252
+ {
3253
+ open: state?.open === true,
3254
+ onClose: (open) => {
3255
+ void executeRendererDialogChange(
3256
+ engine,
3257
+ node.id,
3258
+ open,
3259
+ false
3260
+ );
3261
+ },
3262
+ size: normalizeDialogSize(node.schema.props?.size),
3263
+ disableCloseOutside: node.schema.props?.disableCloseOutside === true,
3264
+ children: node.children.map((child) => /* @__PURE__ */ jsx31(NodeRenderer, { node: child }, child.id))
3265
+ }
3266
+ );
3267
+ }
3268
+ function normalizeDialogSize(value) {
3269
+ return value === "sm" || value === "lg" || value === "xl" || value === "full" ? value : "md";
3270
+ }
3271
+
3272
+ // src/renderer/dialog-slot-renderer.tsx
3273
+ import { Dialog as Dialog2 } from "bsm-design-system";
3274
+ import { jsx as jsx32, jsxs as jsxs14 } from "react/jsx-runtime";
3275
+ function DialogSlotRenderer({ node }) {
3276
+ const show = useDesignVisible(node.state.visible);
3277
+ const { designMode } = useConfigContext();
3278
+ if (node.schema.kind !== "layout" || !show) {
3279
+ return null;
3280
+ }
3281
+ const children = node.children.map((child) => /* @__PURE__ */ jsx32(NodeRenderer, { node: child }, child.id));
3282
+ if (designMode === true) {
3283
+ return renderDesignModeSlot(node, children);
3284
+ }
3285
+ switch (node.schema.type) {
3286
+ case "dialog-header":
3287
+ return /* @__PURE__ */ jsx32(
3288
+ Dialog2.Header,
3289
+ {
3290
+ title: normalizeDialogTitle(node.schema.props.title),
3291
+ hideClose: node.schema.props.hideClose === true,
3292
+ children
3293
+ }
3294
+ );
3295
+ case "dialog-body":
3296
+ return /* @__PURE__ */ jsx32(
3297
+ "div",
3298
+ {
3299
+ "data-slot": "dialog-body",
3300
+ className: normalizeClassName6(node.schema.props?.className),
3301
+ children
3302
+ }
3303
+ );
3304
+ case "dialog-footer":
3305
+ return /* @__PURE__ */ jsx32(
3306
+ Dialog2.Footer,
3307
+ {
3308
+ className: normalizeClassName6(node.schema.props?.className),
3309
+ children
3310
+ }
3311
+ );
3312
+ default:
3313
+ return null;
3314
+ }
3315
+ }
3316
+ function renderDesignModeSlot(node, children) {
3317
+ const schema = node.schema;
3318
+ if (schema.kind !== "layout") return null;
3319
+ switch (schema.type) {
3320
+ case "dialog-header": {
3321
+ const title = normalizeDialogTitle(schema.props.title) || "Dialog header";
3322
+ return /* @__PURE__ */ jsxs14(
3323
+ "div",
3324
+ {
3325
+ "data-slot": "dialog-header",
3326
+ className: "rounded border border-dashed border-gray-200 p-2",
3327
+ children: [
3328
+ /* @__PURE__ */ jsx32("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Header" }),
3329
+ /* @__PURE__ */ jsx32("div", { className: "text-sm font-medium text-gray-800", children: title }),
3330
+ children
3331
+ ]
3332
+ }
3333
+ );
3334
+ }
3335
+ case "dialog-body":
3336
+ return /* @__PURE__ */ jsxs14(
3337
+ "div",
3338
+ {
3339
+ "data-slot": "dialog-body",
3340
+ className: joinClassNames4(
3341
+ "min-h-16 rounded border border-dashed border-gray-200 p-2",
3342
+ normalizeClassName6(schema.props?.className)
3343
+ ),
3344
+ children: [
3345
+ /* @__PURE__ */ jsx32("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Body" }),
3346
+ children
3347
+ ]
3348
+ }
3349
+ );
3350
+ case "dialog-footer":
3351
+ return /* @__PURE__ */ jsxs14(
3352
+ "div",
3353
+ {
3354
+ "data-slot": "dialog-footer",
3355
+ className: joinClassNames4(
3356
+ "min-h-12 rounded border border-dashed border-gray-200 p-2",
3357
+ normalizeClassName6(schema.props?.className)
3358
+ ),
3359
+ children: [
3360
+ /* @__PURE__ */ jsx32("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Footer" }),
3361
+ children
3362
+ ]
3363
+ }
3364
+ );
3365
+ default:
3366
+ return null;
3367
+ }
3368
+ }
3369
+ function normalizeDialogTitle(value) {
3370
+ return typeof value === "string" ? value.trim() : "";
3371
+ }
3372
+ function normalizeClassName6(value) {
3373
+ return typeof value === "string" ? value.trim() : "";
3374
+ }
3375
+ function joinClassNames4(...parts) {
3376
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
3377
+ }
3378
+
3379
+ // src/renderer/drawer-renderer.tsx
3380
+ import { Drawer } from "bsm-design-system";
3381
+
3382
+ // src/renderer/drawer-execution.ts
3383
+ function executeRendererDrawerChange(engine, drawerId, open, designMode) {
3384
+ if (designMode) {
3385
+ return;
3386
+ }
3387
+ return open ? engine.openDrawer(drawerId) : engine.closeDrawer(drawerId);
3388
+ }
3389
+
3390
+ // src/renderer/drawer-renderer.tsx
3391
+ import { jsx as jsx33, jsxs as jsxs15 } from "react/jsx-runtime";
3392
+ function DrawerRenderer({ node }) {
3393
+ if (node.schema.kind !== "layout" || node.schema.type !== "drawer") {
3394
+ return null;
3395
+ }
3396
+ const engine = useFormContext();
3397
+ const { designMode } = useConfigContext();
3398
+ if (designMode === true) {
3399
+ const side = normalizeDrawerSide(node.schema.props?.side);
3400
+ return /* @__PURE__ */ jsxs15(
3401
+ "div",
3402
+ {
3403
+ className: "space-y-2 rounded border border-dashed border-gray-300 p-2",
3404
+ "data-design-overlay": "drawer",
3405
+ "data-side": side,
3406
+ children: [
3407
+ /* @__PURE__ */ jsxs15("div", { className: "text-[10px] font-medium uppercase tracking-wide text-gray-500", children: [
3408
+ "Drawer (",
3409
+ side,
3410
+ ")"
3411
+ ] }),
3412
+ node.children.map((child) => /* @__PURE__ */ jsx33(NodeRenderer, { node: child }, child.id))
3413
+ ]
3414
+ }
3415
+ );
3416
+ }
3417
+ const state = engine.getDrawerState(node.id);
3418
+ return /* @__PURE__ */ jsx33(
3419
+ Drawer,
3420
+ {
3421
+ open: state?.open === true,
3422
+ onClose: (open) => {
3423
+ void executeRendererDrawerChange(
3424
+ engine,
3425
+ node.id,
3426
+ open,
3427
+ false
3428
+ );
3429
+ },
3430
+ side: normalizeDrawerSide(node.schema.props?.side),
3431
+ disableCloseOutside: node.schema.props?.disableCloseOutside === true,
3432
+ children: node.children.map((child) => /* @__PURE__ */ jsx33(NodeRenderer, { node: child }, child.id))
3433
+ }
3434
+ );
3435
+ }
3436
+ function normalizeDrawerSide(value) {
3437
+ return value === "top" || value === "right" || value === "bottom" ? value : "left";
3438
+ }
3439
+
3440
+ // src/renderer/drawer-slot-renderer.tsx
3441
+ import { Drawer as Drawer2 } from "bsm-design-system";
3442
+ import { jsx as jsx34, jsxs as jsxs16 } from "react/jsx-runtime";
3443
+ function DrawerSlotRenderer({ node }) {
3444
+ const show = useDesignVisible(node.state.visible);
3445
+ const { designMode } = useConfigContext();
3446
+ if (node.schema.kind !== "layout" || !show) {
3447
+ return null;
3448
+ }
3449
+ const children = node.children.map((child) => /* @__PURE__ */ jsx34(NodeRenderer, { node: child }, child.id));
3450
+ if (designMode === true) {
3451
+ return renderDesignModeSlot2(node, children);
3452
+ }
3453
+ switch (node.schema.type) {
3454
+ case "drawer-header":
3455
+ return /* @__PURE__ */ jsx34(
3456
+ Drawer2.Header,
3457
+ {
3458
+ title: normalizeDrawerTitle(node.schema.props.title),
3459
+ hideClose: node.schema.props.hideClose === true,
3460
+ children
3461
+ }
3462
+ );
3463
+ case "drawer-body":
3464
+ return /* @__PURE__ */ jsx34(
3465
+ "div",
3466
+ {
3467
+ "data-slot": "drawer-body",
3468
+ className: normalizeClassName7(node.schema.props?.className),
3469
+ children
3470
+ }
3471
+ );
3472
+ case "drawer-footer":
3473
+ return /* @__PURE__ */ jsx34(
3474
+ Drawer2.Footer,
3475
+ {
3476
+ className: normalizeClassName7(node.schema.props?.className),
3477
+ children
3478
+ }
3479
+ );
3480
+ default:
3481
+ return null;
3482
+ }
3483
+ }
3484
+ function renderDesignModeSlot2(node, children) {
3485
+ const schema = node.schema;
3486
+ if (schema.kind !== "layout") return null;
3487
+ switch (schema.type) {
3488
+ case "drawer-header": {
3489
+ const title = normalizeDrawerTitle(schema.props.title) || "Drawer header";
3490
+ return /* @__PURE__ */ jsxs16(
3491
+ "div",
3492
+ {
3493
+ "data-slot": "drawer-header",
3494
+ className: "rounded border border-dashed border-gray-200 p-2",
3495
+ children: [
3496
+ /* @__PURE__ */ jsx34("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Header" }),
3497
+ /* @__PURE__ */ jsx34("div", { className: "text-sm font-medium text-gray-800", children: title }),
3498
+ children
3499
+ ]
3500
+ }
3501
+ );
3502
+ }
3503
+ case "drawer-body":
3504
+ return /* @__PURE__ */ jsxs16(
3505
+ "div",
3506
+ {
3507
+ "data-slot": "drawer-body",
3508
+ className: joinClassNames5(
3509
+ "min-h-16 rounded border border-dashed border-gray-200 p-2",
3510
+ normalizeClassName7(schema.props?.className)
3511
+ ),
3512
+ children: [
3513
+ /* @__PURE__ */ jsx34("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Body" }),
3514
+ children
3515
+ ]
3516
+ }
3517
+ );
3518
+ case "drawer-footer":
3519
+ return /* @__PURE__ */ jsxs16(
3520
+ "div",
3521
+ {
3522
+ "data-slot": "drawer-footer",
3523
+ className: joinClassNames5(
3524
+ "min-h-12 rounded border border-dashed border-gray-200 p-2",
3525
+ normalizeClassName7(schema.props?.className)
3526
+ ),
3527
+ children: [
3528
+ /* @__PURE__ */ jsx34("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wide text-gray-500", children: "Footer" }),
3529
+ children
3530
+ ]
3531
+ }
3532
+ );
3533
+ default:
3534
+ return null;
3535
+ }
3536
+ }
3537
+ function normalizeDrawerTitle(value) {
3538
+ return typeof value === "string" ? value.trim() : "";
3539
+ }
3540
+ function normalizeClassName7(value) {
3541
+ return typeof value === "string" ? value.trim() : "";
3542
+ }
3543
+ function joinClassNames5(...parts) {
3544
+ return parts.filter((part) => typeof part === "string" && part.length > 0).join(" ");
3545
+ }
3546
+
3547
+ // src/components/tooltip.tsx
3548
+ import { Tooltip } from "bsm-design-system";
3549
+ import { jsx as jsx35, jsxs as jsxs17 } from "react/jsx-runtime";
3550
+ function TooltipLayout({
3551
+ children,
3552
+ content,
3553
+ side,
3554
+ sideOffset,
3555
+ delayDuration,
3556
+ defaultOpen,
3557
+ className
3558
+ }) {
3559
+ return /* @__PURE__ */ jsxs17(
3560
+ Tooltip,
3561
+ {
3562
+ delayDuration: normalizeTooltipDelayDuration(delayDuration),
3563
+ defaultOpen: normalizeTooltipDefaultOpen(defaultOpen),
3564
+ children: [
3565
+ /* @__PURE__ */ jsx35(Tooltip.Trigger, { children }),
3566
+ /* @__PURE__ */ jsx35(
3567
+ Tooltip.Content,
3568
+ {
3569
+ side: normalizeTooltipSide(side),
3570
+ sideOffset: normalizeTooltipSideOffset(sideOffset),
3571
+ className: normalizeTooltipClassName(className),
3572
+ children: normalizeTooltipContent(content)
3573
+ }
3574
+ )
3575
+ ]
3576
+ }
3577
+ );
3578
+ }
3579
+ function normalizeTooltipContent(value) {
3580
+ if (typeof value !== "string") {
3581
+ return "";
3582
+ }
3583
+ return value.trim();
3584
+ }
3585
+ function normalizeTooltipSide(value) {
3586
+ return value === "right" || value === "bottom" || value === "left" ? value : "top";
3587
+ }
3588
+ function normalizeTooltipSideOffset(value) {
3589
+ return normalizeNonNegativeNumber(value, 0);
3590
+ }
3591
+ function normalizeTooltipDelayDuration(value) {
3592
+ return normalizeNonNegativeNumber(value, 0);
3593
+ }
3594
+ function normalizeTooltipDefaultOpen(value) {
3595
+ return value === true;
3596
+ }
3597
+ function normalizeTooltipClassName(value) {
3598
+ if (typeof value !== "string") {
3599
+ return void 0;
3600
+ }
3601
+ const className = value.trim();
3602
+ return className || void 0;
3603
+ }
3604
+ function normalizeNonNegativeNumber(value, fallback) {
3605
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
3606
+ }
3607
+
3608
+ // src/components/trigger-bridge.tsx
3609
+ import {
3610
+ forwardRef,
3611
+ useCallback,
3612
+ useEffect as useEffect5,
3613
+ useState as useState5
3614
+ } from "react";
3615
+ import { jsx as jsx36 } from "react/jsx-runtime";
3616
+ var FOCUSABLE_SELECTOR = [
3617
+ "a[href]",
3618
+ "button:not([disabled])",
3619
+ 'input:not([disabled]):not([type="hidden"])',
3620
+ "select:not([disabled])",
3621
+ "textarea:not([disabled])",
3622
+ '[contenteditable="true"]',
3623
+ '[tabindex]:not([tabindex="-1"])'
3624
+ ].join(",");
3625
+ var MIRRORED_ATTRIBUTES = [
3626
+ "aria-controls",
3627
+ "aria-expanded",
3628
+ "aria-haspopup",
3629
+ "aria-label"
3630
+ ];
3631
+ var TriggerBridge = forwardRef(function TriggerBridge2({
3632
+ activateWhenNonInteractive = false,
3633
+ children,
3634
+ className,
3635
+ disabled = false,
3636
+ onClickCapture,
3637
+ onKeyDown,
3638
+ onKeyDownCapture,
3639
+ onPointerDownCapture,
3640
+ tabIndex,
3641
+ ...props
3642
+ }, forwardedRef) {
3643
+ const [element, setElement] = useState5(null);
3644
+ const [hasFocusableDescendant, setHasFocusableDescendant] = useState5(true);
3645
+ const assignRef = useCallback(
3646
+ (node) => {
3647
+ setElement(node);
3648
+ setForwardedRef(forwardedRef, node);
3649
+ },
3650
+ [forwardedRef]
3651
+ );
3652
+ useEffect5(() => {
3653
+ if (!element) {
3654
+ return;
3655
+ }
3656
+ let describedElement = null;
3657
+ let addedDescriptionIds = [];
3658
+ let attributeMirrors = [];
3659
+ const clearMirroredAttributes = () => {
3660
+ if (describedElement && addedDescriptionIds.length > 0) {
3661
+ const remainingIds = readDescriptionIds(describedElement).filter(
3662
+ (id) => !addedDescriptionIds.includes(id)
3663
+ );
3664
+ writeDescriptionIds(describedElement, remainingIds);
3665
+ }
3666
+ for (const mirror of attributeMirrors) {
3667
+ if (mirror.target.getAttribute(mirror.attribute) !== mirror.appliedValue) {
3668
+ continue;
3669
+ }
3670
+ if (mirror.previousValue === null) {
3671
+ mirror.target.removeAttribute(mirror.attribute);
3672
+ } else {
3673
+ mirror.target.setAttribute(
3674
+ mirror.attribute,
3675
+ mirror.previousValue
3676
+ );
3677
+ }
3678
+ }
3679
+ describedElement = null;
3680
+ addedDescriptionIds = [];
3681
+ attributeMirrors = [];
3682
+ };
3683
+ const synchronize = () => {
3684
+ clearMirroredAttributes();
3685
+ const focusableElement = element.querySelector(FOCUSABLE_SELECTOR);
3686
+ setHasFocusableDescendant(Boolean(focusableElement));
3687
+ if (!focusableElement) {
3688
+ return;
3689
+ }
3690
+ const descriptionIds = readDescriptionIds(element);
3691
+ if (descriptionIds.length > 0) {
3692
+ const existingIds = readDescriptionIds(focusableElement);
3693
+ addedDescriptionIds = descriptionIds.filter(
3694
+ (id) => !existingIds.includes(id)
3695
+ );
3696
+ describedElement = focusableElement;
3697
+ writeDescriptionIds(focusableElement, [
3698
+ ...existingIds,
3699
+ ...addedDescriptionIds
3700
+ ]);
3701
+ }
3702
+ for (const attribute of MIRRORED_ATTRIBUTES) {
3703
+ const value = element.getAttribute(attribute);
3704
+ if (value === null) {
3705
+ continue;
3706
+ }
3707
+ attributeMirrors.push({
3708
+ attribute,
3709
+ target: focusableElement,
3710
+ previousValue: focusableElement.getAttribute(attribute),
3711
+ appliedValue: value
3712
+ });
3713
+ focusableElement.setAttribute(attribute, value);
3714
+ }
3715
+ };
3716
+ synchronize();
3717
+ if (typeof MutationObserver === "undefined") {
3718
+ return clearMirroredAttributes;
3719
+ }
3720
+ const rootObserver = new MutationObserver(synchronize);
3721
+ rootObserver.observe(element, {
3722
+ attributes: true,
3723
+ attributeFilter: ["aria-describedby", ...MIRRORED_ATTRIBUTES]
3724
+ });
3725
+ const descendantsObserver = new MutationObserver(synchronize);
3726
+ descendantsObserver.observe(element, {
3727
+ childList: true,
3728
+ subtree: true,
3729
+ attributes: true,
3730
+ attributeFilter: [
3731
+ "contenteditable",
3732
+ "disabled",
3733
+ "href",
3734
+ "tabindex",
3735
+ "type"
3736
+ ]
3737
+ });
3738
+ return () => {
3739
+ rootObserver.disconnect();
3740
+ descendantsObserver.disconnect();
3741
+ clearMirroredAttributes();
3742
+ };
3743
+ }, [element]);
3744
+ const handleKeyDown = (event) => {
3745
+ onKeyDown?.(event);
3746
+ if (activateWhenNonInteractive && !hasFocusableDescendant && !event.defaultPrevented && event.currentTarget === event.target && (event.key === "Enter" || event.key === " ")) {
3747
+ event.preventDefault();
3748
+ event.currentTarget.click();
3749
+ }
3750
+ };
3751
+ const handleDisabledInteraction = (event) => {
3752
+ if (!disabled) {
3753
+ return;
3754
+ }
3755
+ event.preventDefault();
3756
+ event.stopPropagation();
3757
+ };
3758
+ return /* @__PURE__ */ jsx36(
3759
+ "span",
3760
+ {
3761
+ ...props,
3762
+ ref: assignRef,
3763
+ "aria-disabled": disabled || void 0,
3764
+ className: ["inline-flex max-w-full", className].filter(Boolean).join(" "),
3765
+ inert: disabled ? true : void 0,
3766
+ onClickCapture: (event) => {
3767
+ onClickCapture?.(event);
3768
+ handleDisabledInteraction(event);
3769
+ },
3770
+ onKeyDown: handleKeyDown,
3771
+ onKeyDownCapture: (event) => {
3772
+ onKeyDownCapture?.(event);
3773
+ handleDisabledInteraction(event);
3774
+ },
3775
+ onPointerDownCapture: (event) => {
3776
+ onPointerDownCapture?.(event);
3777
+ handleDisabledInteraction(event);
3778
+ },
3779
+ tabIndex: disabled ? -1 : tabIndex ?? (hasFocusableDescendant ? void 0 : 0),
3780
+ children
3781
+ }
3782
+ );
3783
+ });
3784
+ function readDescriptionIds(element) {
3785
+ return (element.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean);
3786
+ }
3787
+ function writeDescriptionIds(element, ids) {
3788
+ if (ids.length === 0) {
3789
+ element.removeAttribute("aria-describedby");
3790
+ return;
3791
+ }
3792
+ element.setAttribute("aria-describedby", ids.join(" "));
3793
+ }
3794
+ function setForwardedRef(ref, value) {
3795
+ if (typeof ref === "function") {
3796
+ ref(value);
3797
+ return;
3798
+ }
3799
+ if (ref) {
3800
+ ref.current = value;
3801
+ }
3802
+ }
3803
+
3804
+ // src/renderer/tooltip-renderer.tsx
3805
+ import { jsx as jsx37 } from "react/jsx-runtime";
3806
+ function TooltipRenderer({ node }) {
3807
+ const schema = node.schema;
3808
+ const { designMode } = useConfigContext();
3809
+ if (schema.kind !== "layout" || schema.type !== "tooltip") {
3810
+ return null;
3811
+ }
3812
+ const child = node.children[0];
3813
+ if (!child) {
3814
+ return null;
3815
+ }
3816
+ if (designMode === true) {
3817
+ return /* @__PURE__ */ jsx37(NodeRenderer, { node: child });
3818
+ }
3819
+ return /* @__PURE__ */ jsx37(
3820
+ TooltipLayout,
3821
+ {
3822
+ content: schema.props.content,
3823
+ side: schema.props.side,
3824
+ sideOffset: schema.props.sideOffset,
3825
+ delayDuration: schema.props.delayDuration,
3826
+ defaultOpen: schema.props.defaultOpen,
3827
+ className: schema.props.className,
3828
+ children: /* @__PURE__ */ jsx37(TriggerBridge, { children: /* @__PURE__ */ jsx37(NodeRenderer, { node: child }) })
3829
+ }
3830
+ );
3831
+ }
3832
+
3833
+ // src/renderer/popover-renderer.tsx
3834
+ import { Popover } from "bsm-design-system";
3835
+ import { jsx as jsx38 } from "react/jsx-runtime";
3836
+ function PopoverRenderer({ node }) {
3837
+ if (node.schema.kind !== "layout" || node.schema.type !== "popover") {
3838
+ return null;
3839
+ }
3840
+ const { designMode } = useConfigContext();
3841
+ if (designMode === true) {
3842
+ return /* @__PURE__ */ jsx38("div", { className: "space-y-3 rounded border border-dashed border-gray-300 p-2", children: node.children.map((child) => /* @__PURE__ */ jsx38(NodeRenderer, { node: child }, child.id)) });
3843
+ }
3844
+ const rootProps = buildPopoverRootProps(node.schema.props);
3845
+ return /* @__PURE__ */ jsx38(Popover, { ...rootProps, children: node.children.map((child) => /* @__PURE__ */ jsx38(NodeRenderer, { node: child }, child.id)) });
3846
+ }
3847
+ function buildPopoverRootProps(props) {
3848
+ const record = typeof props === "object" && props !== null ? props : void 0;
3849
+ return {
3850
+ defaultOpen: normalizePopoverDefaultOpen(record?.defaultOpen),
3851
+ modal: normalizePopoverModal(record?.modal)
3852
+ };
3853
+ }
3854
+ function normalizePopoverDefaultOpen(value) {
3855
+ return value === true;
3856
+ }
3857
+ function normalizePopoverModal(value) {
3858
+ return value === true;
3859
+ }
3860
+
3861
+ // src/renderer/popover-slot-renderer.tsx
3862
+ import { Popover as Popover2 } from "bsm-design-system";
3863
+ import { jsx as jsx39 } from "react/jsx-runtime";
3864
+ function PopoverSlotRenderer({ node }) {
3865
+ if (node.schema.kind !== "layout" || !node.state.visible) {
3866
+ return null;
3867
+ }
3868
+ const { designMode } = useConfigContext();
3869
+ if (node.schema.type === "popover-trigger") {
3870
+ const child = node.children[0];
3871
+ if (!child) {
3872
+ return null;
3873
+ }
3874
+ if (designMode === true) {
3875
+ return /* @__PURE__ */ jsx39(
3876
+ "div",
3877
+ {
3878
+ "data-slot": "popover-trigger",
3879
+ className: normalizePopoverClassName(node.schema.props?.className),
3880
+ "aria-label": normalizePopoverAriaLabel(node.schema.props?.ariaLabel),
3881
+ children: /* @__PURE__ */ jsx39(NodeRenderer, { node: child })
3882
+ }
3883
+ );
3884
+ }
3885
+ return /* @__PURE__ */ jsx39(Popover2.Trigger, { children: /* @__PURE__ */ jsx39(
3886
+ TriggerBridge,
3887
+ {
3888
+ activateWhenNonInteractive: true,
3889
+ className: normalizePopoverClassName(
3890
+ node.schema.props?.className
3891
+ ),
3892
+ "aria-label": normalizePopoverAriaLabel(
3893
+ node.schema.props?.ariaLabel
3894
+ ),
3895
+ children: /* @__PURE__ */ jsx39(NodeRenderer, { node: child })
3896
+ }
3897
+ ) });
3898
+ }
3899
+ if (node.schema.type === "popover-content") {
3900
+ const contentProps = buildPopoverContentProps(node.schema.props);
3901
+ const children = node.children.map((child) => /* @__PURE__ */ jsx39(NodeRenderer, { node: child }, child.id));
3902
+ if (designMode === true) {
3903
+ return /* @__PURE__ */ jsx39(
3904
+ "div",
3905
+ {
3906
+ "data-slot": "popover-content",
3907
+ className: joinClassNames6(
3908
+ "min-h-12 rounded border border-dashed border-gray-200 p-2",
3909
+ contentProps.className
3910
+ ),
3911
+ "aria-label": contentProps["aria-label"],
3912
+ children
3913
+ }
3914
+ );
3915
+ }
3916
+ return /* @__PURE__ */ jsx39(Popover2.Content, { ...contentProps, children });
3917
+ }
3918
+ return null;
3919
+ }
3920
+ function buildPopoverContentProps(props) {
3921
+ const record = typeof props === "object" && props !== null ? props : void 0;
3922
+ return {
3923
+ align: normalizePopoverAlign(record?.align),
3924
+ side: normalizePopoverSide(record?.side),
3925
+ sideOffset: normalizePopoverSideOffset(record?.sideOffset),
3926
+ alignOffset: normalizePopoverAlignOffset(record?.alignOffset),
3927
+ className: normalizePopoverClassName(record?.className),
3928
+ "aria-label": normalizePopoverAriaLabel(record?.ariaLabel)
3929
+ };
3930
+ }
3931
+ function normalizePopoverAlign(value) {
3932
+ return value === "start" || value === "end" ? value : "center";
3933
+ }
3934
+ function normalizePopoverSide(value) {
3935
+ return value === "top" || value === "right" || value === "left" ? value : "bottom";
3936
+ }
3937
+ function normalizePopoverSideOffset(value) {
3938
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 4;
3939
+ }
3940
+ function normalizePopoverAlignOffset(value) {
3941
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
3942
+ }
3943
+ function normalizePopoverClassName(value) {
3944
+ if (typeof value !== "string") {
3945
+ return void 0;
3946
+ }
3947
+ const className = value.trim();
3948
+ return className || void 0;
3949
+ }
3950
+ function normalizePopoverAriaLabel(value) {
3951
+ if (typeof value !== "string") {
3952
+ return void 0;
3953
+ }
3954
+ const ariaLabel = value.trim();
3955
+ return ariaLabel || void 0;
3956
+ }
3957
+ function joinClassNames6(...parts) {
3958
+ return parts.filter(Boolean).join(" ") || void 0;
3959
+ }
3960
+
3961
+ // src/renderer/dropdown-menu-renderer.tsx
3962
+ import { DropdownMenu } from "bsm-design-system";
3963
+ import { jsx as jsx40 } from "react/jsx-runtime";
3964
+ function DropdownMenuRenderer({ node }) {
3965
+ if (node.schema.kind !== "layout" || node.schema.type !== "dropdown-menu") {
3966
+ return null;
3967
+ }
3968
+ const { designMode } = useConfigContext();
3969
+ if (designMode === true) {
3970
+ return /* @__PURE__ */ jsx40("div", { className: "space-y-3 rounded border border-dashed border-gray-300 p-2", children: node.children.map((child) => /* @__PURE__ */ jsx40(NodeRenderer, { node: child }, child.id)) });
3971
+ }
3972
+ const rootProps = buildDropdownMenuRootProps(node.schema.props);
3973
+ return /* @__PURE__ */ jsx40(DropdownMenu, { ...rootProps, children: node.children.map((child) => /* @__PURE__ */ jsx40(NodeRenderer, { node: child }, child.id)) });
3974
+ }
3975
+ function buildDropdownMenuRootProps(props) {
3976
+ const record = typeof props === "object" && props !== null ? props : void 0;
3977
+ return {
3978
+ defaultOpen: normalizeDropdownMenuDefaultOpen(record?.defaultOpen),
3979
+ modal: normalizeDropdownMenuModal(record?.modal)
3980
+ };
3981
+ }
3982
+ function normalizeDropdownMenuDefaultOpen(value) {
3983
+ return value === true;
3984
+ }
3985
+ function normalizeDropdownMenuModal(value) {
3986
+ return value !== false;
3987
+ }
3988
+
3989
+ // src/renderer/dropdown-menu-slot-renderer.tsx
3990
+ import { DropdownMenu as DropdownMenu2 } from "bsm-design-system";
3991
+ import { jsx as jsx41, jsxs as jsxs18 } from "react/jsx-runtime";
3992
+ function DropdownMenuSlotRenderer({ node }) {
3993
+ if (node.schema.kind !== "layout" || !node.state.visible) {
3994
+ return null;
3995
+ }
3996
+ const { designMode } = useConfigContext();
3997
+ const schema = node.schema;
3998
+ const children = node.children.map((child) => /* @__PURE__ */ jsx41(NodeRenderer, { node: child }, child.id));
3999
+ if (designMode === true) {
4000
+ return renderDesignModeSlot3(node, children);
4001
+ }
4002
+ switch (schema.type) {
4003
+ case "dropdown-menu-trigger": {
4004
+ const child = node.children[0];
4005
+ if (!child) {
4006
+ return null;
4007
+ }
4008
+ const disabled = normalizeDropdownMenuBoolean(schema.props?.disabled) || node.state.disabled;
4009
+ return /* @__PURE__ */ jsx41(DropdownMenu2.Trigger, { disabled, children: /* @__PURE__ */ jsx41(
4010
+ TriggerBridge,
4011
+ {
4012
+ activateWhenNonInteractive: true,
4013
+ disabled,
4014
+ className: normalizeDropdownMenuClassName(
4015
+ schema.props?.className
4016
+ ),
4017
+ "aria-label": normalizeDropdownMenuAriaLabel(
4018
+ schema.props?.ariaLabel
4019
+ ),
4020
+ children: /* @__PURE__ */ jsx41(NodeRenderer, { node: child })
4021
+ }
4022
+ ) });
4023
+ }
4024
+ case "dropdown-menu-content":
4025
+ return /* @__PURE__ */ jsx41(DropdownMenu2.Content, { ...buildDropdownMenuContentProps(schema.props), children });
4026
+ case "dropdown-menu-group":
4027
+ return /* @__PURE__ */ jsx41(
4028
+ DropdownMenu2.Group,
4029
+ {
4030
+ className: normalizeDropdownMenuClassName(
4031
+ schema.props?.className
4032
+ ),
4033
+ children
4034
+ }
4035
+ );
4036
+ case "dropdown-menu-label":
4037
+ return /* @__PURE__ */ jsx41(
4038
+ DropdownMenu2.Label,
4039
+ {
4040
+ id: node.id,
4041
+ inset: normalizeDropdownMenuBoolean(schema.props?.inset),
4042
+ className: normalizeDropdownMenuClassName(
4043
+ schema.props?.className
4044
+ ),
4045
+ children: normalizeDropdownMenuText(schema.props?.label)
4046
+ }
4047
+ );
4048
+ case "dropdown-menu-item":
4049
+ return /* @__PURE__ */ jsx41(DropdownMenuActionItem, { node });
4050
+ case "dropdown-menu-separator":
4051
+ return /* @__PURE__ */ jsx41(
4052
+ DropdownMenu2.Separator,
4053
+ {
4054
+ id: node.id,
4055
+ className: normalizeDropdownMenuClassName(
4056
+ schema.props?.className
4057
+ )
4058
+ }
4059
+ );
4060
+ case "dropdown-menu-sub":
4061
+ return /* @__PURE__ */ jsx41(
4062
+ DropdownMenu2.Sub,
4063
+ {
4064
+ defaultOpen: normalizeDropdownMenuDefaultOpen(
4065
+ schema.props?.defaultOpen
4066
+ ),
4067
+ children
4068
+ }
4069
+ );
4070
+ case "dropdown-menu-sub-trigger":
4071
+ return /* @__PURE__ */ jsx41(
4072
+ DropdownMenu2.SubTrigger,
4073
+ {
4074
+ id: node.id,
4075
+ disabled: normalizeDropdownMenuBoolean(schema.props?.disabled) || node.state.disabled,
4076
+ inset: normalizeDropdownMenuBoolean(schema.props?.inset),
4077
+ className: normalizeDropdownMenuClassName(
4078
+ schema.props?.className
4079
+ ),
4080
+ children: normalizeDropdownMenuText(schema.props?.label)
4081
+ }
4082
+ );
4083
+ case "dropdown-menu-sub-content":
4084
+ return /* @__PURE__ */ jsx41(
4085
+ DropdownMenu2.SubContent,
4086
+ {
4087
+ sideOffset: normalizeDropdownMenuSideOffset(
4088
+ schema.props?.sideOffset
4089
+ ),
4090
+ className: normalizeDropdownMenuClassName(
4091
+ schema.props?.className
4092
+ ),
4093
+ "aria-label": normalizeDropdownMenuAriaLabel(
4094
+ schema.props?.ariaLabel
4095
+ ),
4096
+ children
4097
+ }
4098
+ );
4099
+ default:
4100
+ return null;
4101
+ }
4102
+ }
4103
+ function renderDesignModeSlot3(node, children) {
4104
+ const schema = node.schema;
4105
+ if (schema.kind !== "layout") {
4106
+ return null;
4107
+ }
4108
+ const className = normalizeDropdownMenuClassName(schema.props?.className);
4109
+ const ariaLabel = normalizeDropdownMenuAriaLabel(schema.props?.ariaLabel);
4110
+ const label = normalizeDropdownMenuText(schema.props?.label);
4111
+ switch (schema.type) {
4112
+ case "dropdown-menu-trigger": {
4113
+ const child = node.children[0];
4114
+ if (!child) {
4115
+ return null;
4116
+ }
4117
+ return /* @__PURE__ */ jsx41(
4118
+ "div",
4119
+ {
4120
+ "data-slot": "dropdown-menu-trigger",
4121
+ className,
4122
+ "aria-label": ariaLabel,
4123
+ children: /* @__PURE__ */ jsx41(NodeRenderer, { node: child })
4124
+ }
4125
+ );
4126
+ }
4127
+ case "dropdown-menu-content":
4128
+ return /* @__PURE__ */ jsx41(
4129
+ "div",
4130
+ {
4131
+ "data-slot": "dropdown-menu-content",
4132
+ className: joinClassNames7(
4133
+ "min-h-12 space-y-1 rounded border border-dashed border-gray-200 p-2",
4134
+ className
4135
+ ),
4136
+ "aria-label": ariaLabel,
4137
+ children
4138
+ }
4139
+ );
4140
+ case "dropdown-menu-group":
4141
+ return /* @__PURE__ */ jsx41(
4142
+ "div",
4143
+ {
4144
+ "data-slot": "dropdown-menu-group",
4145
+ className: joinClassNames7(
4146
+ "space-y-1 rounded border border-dashed border-gray-100 p-1",
4147
+ className
4148
+ ),
4149
+ children
4150
+ }
4151
+ );
4152
+ case "dropdown-menu-label":
4153
+ return /* @__PURE__ */ jsx41(
4154
+ "div",
4155
+ {
4156
+ "data-slot": "dropdown-menu-label",
4157
+ id: node.id,
4158
+ className: joinClassNames7(
4159
+ "px-2 py-1 text-xs font-medium text-gray-500",
4160
+ className
4161
+ ),
4162
+ children: label || "Label"
4163
+ }
4164
+ );
4165
+ case "dropdown-menu-item":
4166
+ return /* @__PURE__ */ jsx41(DropdownMenuActionItem, { node, designMode: true });
4167
+ case "dropdown-menu-separator":
4168
+ return /* @__PURE__ */ jsx41(
4169
+ "div",
4170
+ {
4171
+ "data-slot": "dropdown-menu-separator",
4172
+ id: node.id,
4173
+ role: "separator",
4174
+ className: joinClassNames7("my-1 h-px bg-gray-200", className)
4175
+ }
4176
+ );
4177
+ case "dropdown-menu-sub":
4178
+ return /* @__PURE__ */ jsx41(
4179
+ "div",
4180
+ {
4181
+ "data-slot": "dropdown-menu-sub",
4182
+ className: "space-y-1 rounded border border-dashed border-gray-200 p-1",
4183
+ children
4184
+ }
4185
+ );
4186
+ case "dropdown-menu-sub-trigger":
4187
+ return /* @__PURE__ */ jsx41(
4188
+ "div",
4189
+ {
4190
+ "data-slot": "dropdown-menu-sub-trigger",
4191
+ id: node.id,
4192
+ className: joinClassNames7(
4193
+ "rounded px-2 py-1 text-sm text-gray-700",
4194
+ className
4195
+ ),
4196
+ children: label || "Submenu"
4197
+ }
4198
+ );
4199
+ case "dropdown-menu-sub-content":
4200
+ return /* @__PURE__ */ jsx41(
4201
+ "div",
4202
+ {
4203
+ "data-slot": "dropdown-menu-sub-content",
4204
+ className: joinClassNames7(
4205
+ "min-h-10 space-y-1 rounded border border-dashed border-gray-200 p-2",
4206
+ className
4207
+ ),
4208
+ "aria-label": ariaLabel,
4209
+ children
4210
+ }
4211
+ );
4212
+ default:
4213
+ return null;
4214
+ }
4215
+ }
4216
+ function DropdownMenuActionItem({
4217
+ node,
4218
+ designMode: designModeProp
4219
+ }) {
4220
+ const engine = useFormContext();
4221
+ const { designMode: contextDesignMode } = useConfigContext();
4222
+ const designMode = designModeProp ?? contextDesignMode === true;
4223
+ if (node.schema.kind !== "layout" || node.schema.type !== "dropdown-menu-item") {
4224
+ return null;
4225
+ }
4226
+ const actionNode = node.children[0];
4227
+ if (!actionNode || actionNode.schema.kind !== "action") {
4228
+ return null;
4229
+ }
4230
+ const schema = node.schema;
4231
+ const shortcut = normalizeDropdownMenuOptionalText(
4232
+ schema.props?.shortcut
4233
+ );
4234
+ const label = normalizeDropdownMenuText(schema.props?.label);
4235
+ const className = normalizeDropdownMenuClassName(schema.props?.className);
4236
+ const disabled = normalizeDropdownMenuBoolean(schema.props?.disabled) || node.state.disabled || isDropdownMenuActionDisabled(engine, actionNode);
4237
+ if (designMode) {
4238
+ return /* @__PURE__ */ jsxs18(
4239
+ "div",
4240
+ {
4241
+ "data-slot": "dropdown-menu-item",
4242
+ id: node.id,
4243
+ className: joinClassNames7(
4244
+ "flex items-center justify-between gap-2 rounded px-2 py-1 text-sm",
4245
+ disabled ? "opacity-50" : void 0,
4246
+ className
4247
+ ),
4248
+ children: [
4249
+ /* @__PURE__ */ jsx41("span", { children: label || "Menu item" }),
4250
+ shortcut ? /* @__PURE__ */ jsx41("span", { className: "text-xs text-gray-400", children: shortcut }) : null
4251
+ ]
4252
+ }
4253
+ );
4254
+ }
4255
+ return /* @__PURE__ */ jsx41(
4256
+ DropdownMenuItemView,
4257
+ {
4258
+ id: node.id,
4259
+ disabled,
4260
+ inset: normalizeDropdownMenuBoolean(schema.props?.inset),
4261
+ variant: normalizeDropdownMenuItemVariant(schema.props?.variant),
4262
+ className,
4263
+ label,
4264
+ shortcut,
4265
+ onSelect: () => {
4266
+ void executeRendererAction(engine, actionNode.id, false);
4267
+ }
4268
+ }
4269
+ );
4270
+ }
4271
+ function DropdownMenuItemView({
4272
+ id,
4273
+ label,
4274
+ shortcut,
4275
+ disabled,
4276
+ inset,
4277
+ variant,
4278
+ className,
4279
+ onSelect
4280
+ }) {
4281
+ return /* @__PURE__ */ jsxs18(
4282
+ DropdownMenu2.Item,
4283
+ {
4284
+ id,
4285
+ disabled,
4286
+ inset,
4287
+ variant,
4288
+ className,
4289
+ onSelect,
4290
+ children: [
4291
+ /* @__PURE__ */ jsx41("span", { children: label }),
4292
+ shortcut ? /* @__PURE__ */ jsx41(DropdownMenu2.Shortcut, { children: shortcut }) : null
4293
+ ]
4294
+ }
4295
+ );
4296
+ }
4297
+ function buildDropdownMenuContentProps(props) {
4298
+ const record = typeof props === "object" && props !== null ? props : void 0;
4299
+ return {
4300
+ side: normalizeDropdownMenuSide(record?.side),
4301
+ sideOffset: normalizeDropdownMenuSideOffset(record?.sideOffset),
4302
+ align: normalizeDropdownMenuAlign(record?.align),
4303
+ alignOffset: normalizeDropdownMenuAlignOffset(record?.alignOffset),
4304
+ collisionPadding: normalizeDropdownMenuCollisionPadding(
4305
+ record?.collisionPadding
4306
+ ),
4307
+ className: normalizeDropdownMenuClassName(record?.className),
4308
+ "aria-label": normalizeDropdownMenuAriaLabel(record?.ariaLabel)
4309
+ };
4310
+ }
4311
+ function normalizeDropdownMenuSide(value) {
4312
+ return value === "top" || value === "right" || value === "left" ? value : "bottom";
4313
+ }
4314
+ function normalizeDropdownMenuAlign(value) {
4315
+ return value === "start" || value === "end" ? value : "center";
4316
+ }
4317
+ function normalizeDropdownMenuSideOffset(value) {
4318
+ return normalizeNonNegativeNumber2(value, 4);
4319
+ }
4320
+ function normalizeDropdownMenuAlignOffset(value) {
4321
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
4322
+ }
4323
+ function normalizeDropdownMenuCollisionPadding(value) {
4324
+ return normalizeNonNegativeNumber2(value, 0);
4325
+ }
4326
+ function normalizeDropdownMenuItemVariant(value) {
4327
+ return value === "destructive" ? "destructive" : "default";
4328
+ }
4329
+ function normalizeDropdownMenuBoolean(value) {
4330
+ return value === true;
4331
+ }
4332
+ function normalizeDropdownMenuClassName(value) {
4333
+ return normalizeDropdownMenuOptionalText(value);
4334
+ }
4335
+ function normalizeDropdownMenuAriaLabel(value) {
4336
+ return normalizeDropdownMenuOptionalText(value);
4337
+ }
4338
+ function normalizeDropdownMenuText(value) {
4339
+ return typeof value === "string" ? value.trim() : "";
4340
+ }
4341
+ function normalizeDropdownMenuOptionalText(value) {
4342
+ const text = normalizeDropdownMenuText(value);
4343
+ return text || void 0;
4344
+ }
4345
+ function joinClassNames7(...parts) {
4346
+ return parts.filter(Boolean).join(" ") || void 0;
4347
+ }
4348
+ function normalizeNonNegativeNumber2(value, fallback) {
4349
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : fallback;
4350
+ }
4351
+ function isDropdownMenuActionDisabled(engine, node) {
4352
+ if (node.schema.kind !== "action") {
4353
+ return true;
4354
+ }
4355
+ const schema = node.schema;
4356
+ const stepperState = (schema.type === "stepper-next" || schema.type === "stepper-previous") && schema.stepperId ? engine.getStepperState(schema.stepperId) : void 0;
4357
+ const isStepperActionDisabled = schema.type === "stepper-next" ? !stepperState?.canGoNext || engine.getState().initializationStatus !== "ready" : schema.type === "stepper-previous" ? !stepperState?.canGoPrevious || engine.getState().initializationStatus !== "ready" : false;
4358
+ return node.state.disabled || schema.props?.disabled === true || engine.isFormDisabled() || isStepperActionDisabled;
4359
+ }
4360
+
4361
+ // src/renderer/pagination-renderer.tsx
4362
+ import { Pagination } from "bsm-design-system";
4363
+ import { useEffect as useEffect6, useState as useState6 } from "react";
4364
+
4365
+ // src/renderer/pagination-execution.ts
4366
+ function executeRendererPaginationChange(engine, paginationId, page, pageSize, designMode) {
4367
+ if (designMode) {
4368
+ return;
4369
+ }
4370
+ return engine.changePagination(paginationId, page, pageSize);
4371
+ }
4372
+
4373
+ // src/renderer/pagination-renderer.tsx
4374
+ import { jsx as jsx42 } from "react/jsx-runtime";
4375
+ function PaginationRenderer({ node }) {
4376
+ if (node.schema.kind !== "layout" || node.schema.type !== "pagination") {
4377
+ return null;
4378
+ }
4379
+ const engine = useFormContext();
4380
+ const { designMode } = useConfigContext();
4381
+ const props = node.schema.props;
4382
+ const engineState = engine.getPaginationState(node.id) ?? {
4383
+ page: normalizePositiveInteger(props.initialPage, 1),
4384
+ pageSize: normalizePositiveInteger(props.pageSize, 10)
4385
+ };
4386
+ const [synchronized, setSynchronized] = useState6(() => ({
4387
+ revision: 0,
4388
+ page: engineState.page,
4389
+ pageSize: engineState.pageSize
4390
+ }));
4391
+ useEffect6(() => {
4392
+ if (synchronized.page === engineState.page && synchronized.pageSize === engineState.pageSize) {
4393
+ return;
4394
+ }
4395
+ setSynchronized((current) => ({
4396
+ revision: current.revision + 1,
4397
+ page: engineState.page,
4398
+ pageSize: engineState.pageSize
4399
+ }));
4400
+ }, [
4401
+ engineState.page,
4402
+ engineState.pageSize,
4403
+ synchronized.page,
4404
+ synchronized.pageSize
4405
+ ]);
4406
+ return /* @__PURE__ */ jsx42(
4407
+ "section",
4408
+ {
4409
+ id: node.id,
4410
+ "aria-label": normalizeAriaLabel3(props.ariaLabel),
4411
+ children: /* @__PURE__ */ jsx42(
4412
+ Pagination,
4413
+ {
4414
+ totalItems: normalizeNonNegativeInteger(props.totalItems, 0),
4415
+ initialPage: synchronized.page,
4416
+ pageSize: synchronized.pageSize,
4417
+ pageSizeOptions: normalizePageSizeOptions(props.pageSizeOptions),
4418
+ siblings: normalizeNonNegativeInteger(props.siblings, 1),
4419
+ showPageSizeSelector: props.showPageSizeSelector === true,
4420
+ showPageInfo: props.showPageInfo === true,
4421
+ rounded: props.rounded === true,
4422
+ className: normalizeClassName8(props.className),
4423
+ onPageChange: (page, pageSize) => {
4424
+ void (async () => {
4425
+ const result = await executeRendererPaginationChange(
4426
+ engine,
4427
+ node.id,
4428
+ page,
4429
+ pageSize,
4430
+ designMode === true
4431
+ );
4432
+ if (result) {
4433
+ setSynchronized((current) => ({
4434
+ ...current,
4435
+ page: result.page,
4436
+ pageSize: result.pageSize
4437
+ }));
4438
+ }
4439
+ })();
4440
+ }
4441
+ },
4442
+ synchronized.revision
4443
+ )
4444
+ }
4445
+ );
4446
+ }
4447
+ function normalizePageSizeOptions(value) {
4448
+ if (!Array.isArray(value)) {
4449
+ return [5, 10, 20];
4450
+ }
4451
+ const options = value.filter(
4452
+ (option) => Number.isInteger(option) && Number(option) > 0
4453
+ );
4454
+ return options.length > 0 ? [...new Set(options)] : [5, 10, 20];
4455
+ }
4456
+ function normalizePositiveInteger(value, fallback) {
4457
+ return Number.isInteger(value) && Number(value) > 0 ? Number(value) : fallback;
4458
+ }
4459
+ function normalizeNonNegativeInteger(value, fallback) {
4460
+ return Number.isInteger(value) && Number(value) >= 0 ? Number(value) : fallback;
4461
+ }
4462
+ function normalizeClassName8(value) {
4463
+ return typeof value === "string" ? value.trim() : "";
4464
+ }
4465
+ function normalizeAriaLabel3(value) {
4466
+ return typeof value === "string" && value.trim() ? value.trim() : "Pagination";
4467
+ }
4468
+
4469
+ // src/renderer/form-ref-renderer.tsx
4470
+ import {
4471
+ compileSchema,
4472
+ FormEngine
4473
+ } from "@bsm-form/core";
4474
+ import { useEffect as useEffect8, useMemo, useRef as useRef2, useState as useState8 } from "react";
4475
+
4476
+ // src/context/form-provider.tsx
4477
+ import { jsx as jsx43 } from "react/jsx-runtime";
4478
+ function FormProvider({
4479
+ engine,
4480
+ children
4481
+ }) {
4482
+ return /* @__PURE__ */ jsx43(FormContext.Provider, { value: engine, children });
4483
+ }
4484
+
4485
+ // src/context/config-provider.tsx
4486
+ import { useCallback as useCallback2, useEffect as useEffect7, useRef, useState as useState7 } from "react";
4487
+
4488
+ // src/renderer/embedded-form-bag.ts
4489
+ var EMBEDS_RESOURCE_ROOT = "embeds";
4490
+ function aggregateEmbeddedFormValues(parentValues, embeddedBag) {
4491
+ const embeddedValues = {};
4492
+ for (const [key, entry] of Object.entries(embeddedBag)) {
4493
+ embeddedValues[key] = isSnapshot(entry) ? { ...entry.values } : { ...entry };
4494
+ }
4495
+ return {
4496
+ ...parentValues,
4497
+ ...embeddedValues
4498
+ };
4499
+ }
4500
+ function aggregateEmbeddedFormPayload(parentValues, parentResources, embeddedBag) {
4501
+ return {
4502
+ values: aggregateEmbeddedFormValues(parentValues, embeddedBag),
4503
+ resources: parentResources,
4504
+ embeds: cloneBag(embeddedBag)
4505
+ };
4506
+ }
4507
+ function setEmbeddedFormSnapshot(bag, instanceKey, snapshot) {
4508
+ return {
4509
+ ...bag,
4510
+ [instanceKey]: {
4511
+ values: { ...snapshot.values },
4512
+ resources: { ...snapshot.resources }
4513
+ }
4514
+ };
4515
+ }
4516
+ function setEmbeddedFormValues(bag, instanceKey, values) {
4517
+ return {
4518
+ ...bag,
4519
+ [instanceKey]: { ...values }
4520
+ };
4521
+ }
4522
+ function resourcesWithoutEmbeds(resources) {
4523
+ if (!Object.prototype.hasOwnProperty.call(resources, EMBEDS_RESOURCE_ROOT)) {
4524
+ return { ...resources };
4525
+ }
4526
+ const next = { ...resources };
4527
+ delete next[EMBEDS_RESOURCE_ROOT];
4528
+ return next;
4529
+ }
4530
+ function snapshotFromEngine(parts) {
4531
+ return {
4532
+ values: { ...parts.values },
4533
+ resources: resourcesWithoutEmbeds(parts.resources)
4534
+ };
4535
+ }
4536
+ function isSnapshot(value) {
4537
+ return typeof value === "object" && value !== null && !Array.isArray(value) && "values" in value && "resources" in value && typeof value.values === "object" && typeof value.resources === "object";
4538
+ }
4539
+ function cloneBag(bag) {
4540
+ const next = {};
4541
+ for (const [key, snapshot] of Object.entries(bag)) {
4542
+ next[key] = {
4543
+ values: { ...snapshot.values },
4544
+ resources: { ...snapshot.resources }
4545
+ };
4546
+ }
4547
+ return next;
4548
+ }
4549
+
4550
+ // src/context/config-provider.tsx
4551
+ import { jsx as jsx44 } from "react/jsx-runtime";
4552
+ function ConfigProvider({
4553
+ designMode,
4554
+ children,
4555
+ renderWrapper,
4556
+ invokeCatalog,
4557
+ slots,
4558
+ slotCatalog,
4559
+ forms,
4560
+ onEmbeddedValuesChange,
4561
+ onEmbeddedSnapshotChange,
4562
+ environment,
4563
+ parentEngine,
4564
+ embeddedBag: embeddedBagProp,
4565
+ publishEmbeddedSnapshot: publishEmbeddedSnapshotProp
4566
+ }) {
4567
+ const isRootBagOwner = publishEmbeddedSnapshotProp === void 0;
4568
+ const [ownedBag, setOwnedBag] = useState7({});
4569
+ const lastBagSerialized = useRef("");
4570
+ const embeddedBag = embeddedBagProp ?? ownedBag;
4571
+ const publishEmbeddedSnapshot = useCallback2(
4572
+ (instanceKey, snapshot) => {
4573
+ if (publishEmbeddedSnapshotProp) {
4574
+ publishEmbeddedSnapshotProp(instanceKey, snapshot);
4575
+ return;
4576
+ }
4577
+ setOwnedBag((previous) => {
4578
+ const next = setEmbeddedFormSnapshot(previous, instanceKey, snapshot);
4579
+ const serialized = JSON.stringify(next);
4580
+ if (serialized === lastBagSerialized.current) {
4581
+ return previous;
4582
+ }
4583
+ lastBagSerialized.current = serialized;
4584
+ return next;
4585
+ });
4586
+ onEmbeddedSnapshotChange?.(instanceKey, snapshot);
4587
+ onEmbeddedValuesChange?.(instanceKey, snapshot.values);
4588
+ },
4589
+ [
4590
+ publishEmbeddedSnapshotProp,
4591
+ onEmbeddedSnapshotChange,
4592
+ onEmbeddedValuesChange
4593
+ ]
4594
+ );
4595
+ useEffect7(() => {
4596
+ if (!isRootBagOwner || !parentEngine) {
4597
+ return;
4598
+ }
4599
+ parentEngine.setResource(EMBEDS_RESOURCE_ROOT, embeddedBag);
4600
+ }, [isRootBagOwner, parentEngine, embeddedBag]);
4601
+ return /* @__PURE__ */ jsx44(
4602
+ ConfigContext.Provider,
4603
+ {
4604
+ value: {
4605
+ designMode,
4606
+ renderWrapper,
4607
+ invokeCatalog,
4608
+ slots,
4609
+ slotCatalog,
4610
+ forms,
4611
+ onEmbeddedValuesChange,
4612
+ onEmbeddedSnapshotChange,
4613
+ environment,
4614
+ embeddedBag,
4615
+ publishEmbeddedSnapshot
4616
+ },
4617
+ children
4618
+ }
4619
+ );
4620
+ }
4621
+
4622
+ // src/renderer/sonner-notify.ts
4623
+ import { toast } from "sonner";
4624
+ function notifyWithSonner(notification) {
4625
+ const { message, variant, position, duration } = notification;
4626
+ const options = {
4627
+ ...position ? { position } : {},
4628
+ ...duration !== void 0 ? { duration } : {}
4629
+ };
4630
+ switch (variant) {
4631
+ case "success":
4632
+ toast.success(message, options);
4633
+ return;
4634
+ case "error":
4635
+ toast.error(message, options);
4636
+ return;
4637
+ case "info":
4638
+ toast.info(message, options);
4639
+ return;
4640
+ case "warning":
4641
+ toast.warning(message, options);
4642
+ return;
4643
+ default:
4644
+ toast(message, options);
4645
+ }
4646
+ }
4647
+
4648
+ // src/renderer/form-ref-renderer.tsx
4649
+ import { jsx as jsx45 } from "react/jsx-runtime";
4650
+ function FormRefRenderer({ node }) {
4651
+ const schema = node.schema;
4652
+ const {
4653
+ designMode,
4654
+ forms,
4655
+ environment,
4656
+ slots,
4657
+ slotCatalog,
4658
+ invokeCatalog,
4659
+ embeddedBag,
4660
+ publishEmbeddedSnapshot,
4661
+ onEmbeddedValuesChange,
4662
+ onEmbeddedSnapshotChange
4663
+ } = useConfigContext();
4664
+ const show = useDesignVisible(node.state.visible);
4665
+ const lastSerialized = useRef2("");
4666
+ const lastEmbedsSerialized = useRef2("");
4667
+ const [, forceUpdate] = useState8(0);
4668
+ const schemaId = schema.kind === "layout" && schema.type === "form-ref" ? schema.props.schemaId : "";
4669
+ const instanceKey = schema.kind === "layout" && schema.type === "form-ref" ? schema.props.instanceKey : "";
4670
+ const className = schema.kind === "layout" && schema.type === "form-ref" && typeof schema.props.className === "string" ? schema.props.className : void 0;
4671
+ const nestedTree = schemaId ? forms?.[schemaId] : void 0;
4672
+ const engine = useMemo(() => {
4673
+ if (!nestedTree) {
4674
+ return void 0;
4675
+ }
4676
+ return new FormEngine(compileSchema(nestedTree), {
4677
+ ...environment,
4678
+ notify: environment?.notify ?? notifyWithSonner,
4679
+ invoke: environment?.invoke ?? {}
4680
+ });
4681
+ }, [nestedTree, environment, designMode]);
4682
+ useEffect8(() => {
4683
+ if (!engine) {
4684
+ return;
4685
+ }
4686
+ const publish = () => {
4687
+ if (!publishEmbeddedSnapshot || !instanceKey) {
4688
+ return;
4689
+ }
4690
+ const snapshot = snapshotFromEngine({
4691
+ values: engine.getValues(),
4692
+ resources: engine.getResources()
4693
+ });
4694
+ const serialized = JSON.stringify(snapshot);
4695
+ if (serialized === lastSerialized.current) {
4696
+ return;
4697
+ }
4698
+ lastSerialized.current = serialized;
4699
+ publishEmbeddedSnapshot(instanceKey, snapshot);
4700
+ };
4701
+ const unsubscribe = engine.subscribe(() => {
4702
+ forceUpdate((value) => value + 1);
4703
+ publish();
4704
+ });
4705
+ void engine.initialize({ skipLoadSteps: designMode === true }).then(() => {
4706
+ publish();
4707
+ }).catch(() => {
4708
+ });
4709
+ return unsubscribe;
4710
+ }, [engine, designMode, instanceKey, publishEmbeddedSnapshot]);
4711
+ useEffect8(() => {
4712
+ lastSerialized.current = "";
4713
+ }, [schemaId, instanceKey, nestedTree]);
4714
+ useEffect8(() => {
4715
+ if (!engine || embeddedBag === void 0) {
4716
+ return;
4717
+ }
4718
+ const serialized = JSON.stringify(embeddedBag);
4719
+ if (serialized === lastEmbedsSerialized.current) {
4720
+ return;
4721
+ }
4722
+ lastEmbedsSerialized.current = serialized;
4723
+ engine.setResource(EMBEDS_RESOURCE_ROOT, embeddedBag);
4724
+ }, [engine, embeddedBag]);
4725
+ if (schema.kind !== "layout" || schema.type !== "form-ref" || !show) {
4726
+ return null;
4727
+ }
4728
+ if (!nestedTree || !engine) {
4729
+ return /* @__PURE__ */ jsx45(
4730
+ "div",
4731
+ {
4732
+ className: [
4733
+ "rounded border border-dashed border-stroke-secondary px-3 py-4 text-xs text-fg-tertiary",
4734
+ className
4735
+ ].filter(Boolean).join(" "),
4736
+ "data-form-ref-missing": schemaId || void 0,
4737
+ children: designMode ? `Embedded form \u201C${schemaId || "missing schemaId"}\u201D (${instanceKey || "missing key"})` : `Form \u201C${schemaId}\u201D is unavailable`
4738
+ }
4739
+ );
4740
+ }
4741
+ return /* @__PURE__ */ jsx45(
4742
+ "div",
4743
+ {
4744
+ className,
4745
+ "data-form-ref": schemaId,
4746
+ "data-form-ref-instance": instanceKey,
4747
+ children: /* @__PURE__ */ jsx45(FormProvider, { engine, children: /* @__PURE__ */ jsx45(
4748
+ ConfigProvider,
4749
+ {
4750
+ designMode: designMode === true,
4751
+ environment,
4752
+ forms,
4753
+ slots,
4754
+ slotCatalog,
4755
+ invokeCatalog,
4756
+ onEmbeddedValuesChange,
4757
+ onEmbeddedSnapshotChange,
4758
+ embeddedBag,
4759
+ publishEmbeddedSnapshot,
4760
+ children: /* @__PURE__ */ jsx45(NodeRenderer, { node: engine.getTree() })
4761
+ }
4762
+ ) })
4763
+ }
4764
+ );
4765
+ }
4766
+
4767
+ // src/renderer/layout-renderer.tsx
4768
+ import { jsx as jsx46 } from "react/jsx-runtime";
4769
+ function LayoutRenderer({ node }) {
4770
+ const schema = node.schema;
4771
+ if (schema.kind !== "layout") {
4772
+ return null;
4773
+ }
4774
+ if (schema.type === "form-ref") {
4775
+ return /* @__PURE__ */ jsx46(FormRefRenderer, { node });
4776
+ }
4777
+ if (schema.type === "repeat") {
4778
+ return /* @__PURE__ */ jsx46(RepeatRenderer, { node });
4779
+ }
4780
+ if (schema.type === "tabs") {
4781
+ return /* @__PURE__ */ jsx46(TabsRenderer, { node });
4782
+ }
4783
+ if (schema.type === "accordion") {
4784
+ return /* @__PURE__ */ jsx46(AccordionRenderer, { node });
4785
+ }
4786
+ if (schema.type === "tooltip") {
4787
+ return /* @__PURE__ */ jsx46(TooltipRenderer, { node });
4788
+ }
4789
+ if (schema.type === "popover") {
4790
+ return /* @__PURE__ */ jsx46(PopoverRenderer, { node });
4791
+ }
4792
+ if (schema.type === "popover-trigger" || schema.type === "popover-content") {
4793
+ return /* @__PURE__ */ jsx46(PopoverSlotRenderer, { node });
4794
+ }
4795
+ if (schema.type === "dropdown-menu") {
4796
+ return /* @__PURE__ */ jsx46(DropdownMenuRenderer, { node });
4797
+ }
4798
+ if (schema.type === "dropdown-menu-trigger" || schema.type === "dropdown-menu-content" || schema.type === "dropdown-menu-group" || schema.type === "dropdown-menu-label" || schema.type === "dropdown-menu-item" || schema.type === "dropdown-menu-separator" || schema.type === "dropdown-menu-sub" || schema.type === "dropdown-menu-sub-trigger" || schema.type === "dropdown-menu-sub-content") {
4799
+ return /* @__PURE__ */ jsx46(DropdownMenuSlotRenderer, { node });
4800
+ }
4801
+ if (schema.type === "pagination") {
4802
+ return /* @__PURE__ */ jsx46(PaginationRenderer, { node });
4803
+ }
4804
+ if (schema.type === "stepper") {
4805
+ return /* @__PURE__ */ jsx46(StepperRenderer, { node });
4806
+ }
4807
+ if (schema.type === "step") {
4808
+ return /* @__PURE__ */ jsx46(StepRenderer, { node });
4809
+ }
4810
+ if (schema.type === "dialog") {
4811
+ return /* @__PURE__ */ jsx46(DialogRenderer, { node });
4812
+ }
4813
+ if (schema.type === "dialog-header" || schema.type === "dialog-body" || schema.type === "dialog-footer") {
4814
+ return /* @__PURE__ */ jsx46(DialogSlotRenderer, { node });
4815
+ }
4816
+ if (schema.type === "drawer") {
4817
+ return /* @__PURE__ */ jsx46(DrawerRenderer, { node });
4818
+ }
4819
+ if (schema.type === "drawer-header" || schema.type === "drawer-body" || schema.type === "drawer-footer") {
4820
+ return /* @__PURE__ */ jsx46(DrawerSlotRenderer, { node });
4821
+ }
4822
+ const Component = layoutRegistry[schema.type];
4823
+ if (!Component) {
4824
+ return null;
4825
+ }
4826
+ const children = node.children.map((child) => /* @__PURE__ */ jsx46(NodeRenderer, { node: child }, child.id));
4827
+ const props = adaptLayout({ schema, children });
4828
+ return /* @__PURE__ */ jsx46(Component, { ...props });
4829
+ }
4830
+
4831
+ // src/renderer/form-renderer.tsx
4832
+ import {
4833
+ compileSchema as compileSchema2,
4834
+ FormEngine as FormEngine2
4835
+ } from "@bsm-form/core";
4836
+ import { useEffect as useEffect9, useMemo as useMemo2, useRef as useRef3, useState as useState9 } from "react";
4837
+ import { createPortal } from "react-dom";
4838
+ import { Toaster } from "sonner";
4839
+ import { jsx as jsx47, jsxs as jsxs19 } from "react/jsx-runtime";
4840
+ function FormRenderer({
4841
+ tree,
4842
+ renderWrapper,
4843
+ designMode = false,
4844
+ environment,
4845
+ invokeCatalog,
4846
+ slots,
4847
+ slotCatalog,
4848
+ forms,
4849
+ onEmbeddedValuesChange,
4850
+ onEmbeddedSnapshotChange,
4851
+ onValuesChange,
4852
+ suppressToaster = false
4853
+ }) {
4854
+ const [, forceUpdate] = useState9(0);
4855
+ const lastSerialized = useRef3("");
4856
+ const engine = useMemo2(
4857
+ () => new FormEngine2(compileSchema2(tree), {
4858
+ ...environment,
4859
+ notify: environment?.notify ?? notifyWithSonner,
4860
+ invoke: environment?.invoke ?? {}
4861
+ }),
4862
+ [tree, designMode, environment]
4863
+ );
4864
+ useEffect9(() => {
4865
+ const unsubscribe = engine.subscribe(() => {
4866
+ forceUpdate((x) => x + 1);
4867
+ if (!onValuesChange) {
4868
+ return;
4869
+ }
4870
+ const values = engine.getValues();
4871
+ const serialized = JSON.stringify(values);
4872
+ if (serialized === lastSerialized.current) {
4873
+ return;
4874
+ }
4875
+ lastSerialized.current = serialized;
4876
+ onValuesChange(values);
4877
+ });
4878
+ void engine.initialize({ skipLoadSteps: designMode === true }).catch(() => {
4879
+ });
4880
+ return unsubscribe;
4881
+ }, [engine, designMode, onValuesChange]);
4882
+ useEffect9(() => {
4883
+ lastSerialized.current = "";
4884
+ }, [engine]);
4885
+ const toaster = suppressToaster || designMode || typeof document === "undefined" ? null : createPortal(
4886
+ /* @__PURE__ */ jsx47(Toaster, { richColors: true, closeButton: true, position: "top-right" }),
4887
+ document.body
4888
+ );
4889
+ return /* @__PURE__ */ jsx47(FormProvider, { engine, children: /* @__PURE__ */ jsxs19(
4890
+ ConfigProvider,
4891
+ {
4892
+ designMode,
4893
+ renderWrapper,
4894
+ invokeCatalog,
4895
+ slots,
4896
+ slotCatalog,
4897
+ forms,
4898
+ onEmbeddedValuesChange,
4899
+ onEmbeddedSnapshotChange,
4900
+ environment,
4901
+ parentEngine: engine,
4902
+ children: [
4903
+ /* @__PURE__ */ jsx47(NodeRenderer, { node: engine.getTree() }),
4904
+ toaster
4905
+ ]
4906
+ }
4907
+ ) });
4908
+ }
4909
+ export {
4910
+ ActionRenderer,
4911
+ AlertDisplay,
4912
+ ChipsDisplay,
4913
+ DialogRenderer,
4914
+ DialogSlotRenderer,
4915
+ DisplayRenderer,
4916
+ DrawerRenderer,
4917
+ DrawerSlotRenderer,
4918
+ DropdownMenuItemView,
4919
+ DropdownMenuRenderer,
4920
+ DropdownMenuSlotRenderer,
4921
+ EMBEDS_RESOURCE_ROOT,
4922
+ FieldRenderer,
4923
+ FormContext,
4924
+ FormProvider,
4925
+ FormRefRenderer,
4926
+ FormRenderer,
4927
+ LayoutRenderer,
4928
+ NodeRenderer,
4929
+ PaginationRenderer,
4930
+ PopoverRenderer,
4931
+ PopoverSlotRenderer,
4932
+ SkeletonDisplay,
4933
+ SlotDisplay,
4934
+ StepRenderer,
4935
+ StepperRenderer,
4936
+ TooltipRenderer,
4937
+ TriggerBridge as TooltipTriggerBridge,
4938
+ aggregateEmbeddedFormPayload,
4939
+ aggregateEmbeddedFormValues,
4940
+ buildDropdownMenuContentProps,
4941
+ buildDropdownMenuRootProps,
4942
+ buildPopoverContentProps,
4943
+ buildPopoverRootProps,
4944
+ executeRendererDialogChange,
4945
+ executeRendererDrawerChange,
4946
+ executeRendererPaginationChange,
4947
+ executeRendererStepperNavigation,
4948
+ normalizeAlertText,
4949
+ normalizeAlertType,
4950
+ normalizeAlertVariant,
4951
+ normalizeChipsLabel,
4952
+ normalizeChipsVariant,
4953
+ normalizeDialogSize,
4954
+ normalizeDialogTitle,
4955
+ normalizeDrawerSide,
4956
+ normalizeDrawerTitle,
4957
+ normalizeDropdownMenuAlign,
4958
+ normalizeDropdownMenuAlignOffset,
4959
+ normalizeDropdownMenuAriaLabel,
4960
+ normalizeDropdownMenuBoolean,
4961
+ normalizeDropdownMenuClassName,
4962
+ normalizeDropdownMenuCollisionPadding,
4963
+ normalizeDropdownMenuDefaultOpen,
4964
+ normalizeDropdownMenuItemVariant,
4965
+ normalizeDropdownMenuModal,
4966
+ normalizeDropdownMenuOptionalText,
4967
+ normalizeDropdownMenuSide,
4968
+ normalizeDropdownMenuSideOffset,
4969
+ normalizeDropdownMenuText,
4970
+ normalizeNonNegativeInteger,
4971
+ normalizePageSizeOptions,
4972
+ normalizePopoverAlign,
4973
+ normalizePopoverAlignOffset,
4974
+ normalizePopoverAriaLabel,
4975
+ normalizePopoverClassName,
4976
+ normalizePopoverDefaultOpen,
4977
+ normalizePopoverModal,
4978
+ normalizePopoverSide,
4979
+ normalizePopoverSideOffset,
4980
+ normalizePositiveInteger,
4981
+ normalizeSkeletonAriaLabel,
4982
+ normalizeSkeletonClassName,
4983
+ normalizeStepLabel,
4984
+ normalizeStepperConnector,
4985
+ normalizeStepperOrientation,
4986
+ resourcesWithoutEmbeds,
4987
+ setEmbeddedFormSnapshot,
4988
+ setEmbeddedFormValues,
4989
+ snapshotFromEngine,
4990
+ useFormContext,
4991
+ useOptionalFormContext
4992
+ };