@duke333/builder-ui 0.1.0 → 0.1.1

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 CHANGED
@@ -1,12 +1,3 @@
1
- // src/admin/BuilderEditorPage.tsx
2
- import { useEffect } from "react";
3
- import {
4
- FormProvider,
5
- useFieldArray,
6
- useForm,
7
- useWatch
8
- } from "react-hook-form";
9
-
10
1
  // src/admin/editorState.ts
11
2
  var BUILDER_EDITOR_NONE_VALUE = "__none";
12
3
  function builderEditorOptionsToText(options) {
@@ -310,15 +301,976 @@ function builderViewEditorInputFromValues(values, parseTriggers) {
310
301
  };
311
302
  }
312
303
 
304
+ // src/admin/BuilderDefaultEditorBodies.tsx
305
+ import { jsx, jsxs } from "react/jsx-runtime";
306
+ var styles = {
307
+ page: {
308
+ display: "grid",
309
+ gap: "1rem"
310
+ },
311
+ header: {
312
+ display: "flex",
313
+ justifyContent: "space-between",
314
+ gap: "1rem",
315
+ alignItems: "flex-start",
316
+ flexWrap: "wrap"
317
+ },
318
+ title: {
319
+ margin: 0,
320
+ fontSize: "1.5rem",
321
+ fontWeight: 650
322
+ },
323
+ description: {
324
+ margin: "0.25rem 0 0",
325
+ color: "var(--muted-foreground, #64748b)"
326
+ },
327
+ actions: {
328
+ display: "flex",
329
+ gap: "0.5rem",
330
+ flexWrap: "wrap"
331
+ },
332
+ section: {
333
+ border: "1px solid var(--border, #d4d4d8)",
334
+ borderRadius: "0.5rem",
335
+ background: "var(--background, #fff)",
336
+ overflow: "hidden"
337
+ },
338
+ sectionHeader: {
339
+ display: "flex",
340
+ justifyContent: "space-between",
341
+ gap: "1rem",
342
+ alignItems: "center",
343
+ padding: "0.75rem",
344
+ borderBottom: "1px solid var(--border, #d4d4d8)",
345
+ flexWrap: "wrap"
346
+ },
347
+ sectionTitle: {
348
+ margin: 0,
349
+ fontSize: "1rem",
350
+ fontWeight: 650
351
+ },
352
+ grid: {
353
+ display: "grid",
354
+ gap: "0.75rem",
355
+ padding: "0.75rem"
356
+ },
357
+ twoColumn: {
358
+ display: "grid",
359
+ gridTemplateColumns: "repeat(auto-fit, minmax(14rem, 1fr))",
360
+ gap: "0.75rem"
361
+ },
362
+ row: {
363
+ display: "grid",
364
+ gridTemplateColumns: "repeat(auto-fit, minmax(10rem, 1fr))",
365
+ gap: "0.5rem",
366
+ padding: "0.75rem",
367
+ borderBottom: "1px solid var(--border, #d4d4d8)"
368
+ },
369
+ field: {
370
+ display: "grid",
371
+ gap: "0.25rem",
372
+ fontSize: "0.875rem"
373
+ },
374
+ label: {
375
+ color: "var(--muted-foreground, #64748b)",
376
+ fontSize: "0.75rem",
377
+ fontWeight: 600
378
+ },
379
+ input: {
380
+ minWidth: 0,
381
+ border: "1px solid var(--border, #d4d4d8)",
382
+ borderRadius: "0.375rem",
383
+ padding: "0.5rem 0.625rem",
384
+ background: "var(--background, #fff)",
385
+ color: "inherit"
386
+ },
387
+ textarea: {
388
+ minWidth: 0,
389
+ minHeight: "5rem",
390
+ border: "1px solid var(--border, #d4d4d8)",
391
+ borderRadius: "0.375rem",
392
+ padding: "0.5rem 0.625rem",
393
+ background: "var(--background, #fff)",
394
+ color: "inherit",
395
+ resize: "vertical"
396
+ },
397
+ checkboxField: {
398
+ display: "flex",
399
+ alignItems: "center",
400
+ gap: "0.5rem",
401
+ fontSize: "0.875rem",
402
+ minHeight: "2.25rem"
403
+ },
404
+ button: {
405
+ border: "1px solid var(--border, #d4d4d8)",
406
+ borderRadius: "0.375rem",
407
+ background: "var(--background, #fff)",
408
+ color: "inherit",
409
+ cursor: "pointer",
410
+ padding: "0.5rem 0.75rem",
411
+ textDecoration: "none",
412
+ fontSize: "0.875rem"
413
+ },
414
+ primaryButton: {
415
+ border: "1px solid var(--primary, #18181b)",
416
+ borderRadius: "0.375rem",
417
+ background: "var(--primary, #18181b)",
418
+ color: "var(--primary-foreground, #fff)",
419
+ cursor: "pointer",
420
+ padding: "0.5rem 0.75rem",
421
+ textDecoration: "none",
422
+ fontSize: "0.875rem"
423
+ }
424
+ };
425
+ function optionItems(options) {
426
+ return options.map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value));
427
+ }
428
+ function createBuilderDefaultFormEditorBody(options) {
429
+ return function BuilderDefaultFormEditorBody({
430
+ formId,
431
+ form,
432
+ fieldArray,
433
+ subformArray,
434
+ triggerArray,
435
+ fields,
436
+ sourceType,
437
+ sourceTable,
438
+ tables,
439
+ emptyField,
440
+ emptyTrigger,
441
+ isSaving,
442
+ importFieldsFromTable
443
+ }) {
444
+ return /* @__PURE__ */ jsxs("div", { style: styles.page, children: [
445
+ /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
446
+ /* @__PURE__ */ jsxs("div", { children: [
447
+ /* @__PURE__ */ jsx("h1", { style: styles.title, children: formId ? "Edit Dynamic Form" : "New Dynamic Form" }),
448
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Configure fields, source mapping, layout, and triggers." })
449
+ ] }),
450
+ /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
451
+ /* @__PURE__ */ jsx("a", { href: options.backHref, style: styles.button, children: "Cancel" }),
452
+ /* @__PURE__ */ jsx("button", { type: "submit", disabled: isSaving, style: styles.primaryButton, children: isSaving ? "Saving..." : "Save" })
453
+ ] })
454
+ ] }),
455
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
456
+ /* @__PURE__ */ jsx("div", { style: styles.sectionHeader, children: /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Details" }) }),
457
+ /* @__PURE__ */ jsxs("div", { style: { ...styles.grid, ...styles.twoColumn }, children: [
458
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
459
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Title" }),
460
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("title", { required: true }) })
461
+ ] }),
462
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
463
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Description" }),
464
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("description") })
465
+ ] }),
466
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
467
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Datasource" }),
468
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceType"), children: [
469
+ /* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
470
+ /* @__PURE__ */ jsx("option", { value: "dbTable", children: "DB table" }),
471
+ /* @__PURE__ */ jsx("option", { value: "apiEndpoint", children: "API endpoint" })
472
+ ] })
473
+ ] }),
474
+ sourceType === "dbTable" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
475
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Table" }),
476
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceTable"), children: [
477
+ /* @__PURE__ */ jsx("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "Select table" }),
478
+ tables.map((table) => /* @__PURE__ */ jsx("option", { value: table.name, children: table.label ?? table.name }, table.name))
479
+ ] })
480
+ ] }) : null,
481
+ sourceType === "apiEndpoint" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
482
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "API base path" }),
483
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("apiBasePath") })
484
+ ] }) : null,
485
+ sourceType === "dbTable" ? /* @__PURE__ */ jsx("div", { style: { ...styles.field, justifyContent: "end" }, children: /* @__PURE__ */ jsx(
486
+ "button",
487
+ {
488
+ type: "button",
489
+ style: styles.button,
490
+ disabled: sourceTable === BUILDER_EDITOR_NONE_VALUE,
491
+ onClick: importFieldsFromTable,
492
+ children: "Import fields"
493
+ }
494
+ ) }) : null
495
+ ] })
496
+ ] }),
497
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
498
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
499
+ /* @__PURE__ */ jsxs("div", { children: [
500
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Fields" }),
501
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Runtime form inputs." })
502
+ ] }),
503
+ /* @__PURE__ */ jsx(
504
+ "button",
505
+ {
506
+ type: "button",
507
+ style: styles.button,
508
+ onClick: () => {
509
+ const key = `field${fieldArray.fields.length + 1}`;
510
+ fieldArray.append({
511
+ ...emptyField,
512
+ key,
513
+ label: `Field ${fieldArray.fields.length + 1}`,
514
+ type: options.fieldTypeOptions[0]?.value
515
+ });
516
+ },
517
+ children: "Add field"
518
+ }
519
+ )
520
+ ] }),
521
+ fieldArray.fields.map((field, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
522
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
523
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
524
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.key`) })
525
+ ] }),
526
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
527
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
528
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.label`) })
529
+ ] }),
530
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
531
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Type" }),
532
+ /* @__PURE__ */ jsx(
533
+ "select",
534
+ {
535
+ style: styles.input,
536
+ ...form.register(`fields.${index}.type`),
537
+ children: optionItems(options.fieldTypeOptions)
538
+ }
539
+ )
540
+ ] }),
541
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
542
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.required`) }),
543
+ "Required"
544
+ ] }),
545
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
546
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.hidden`) }),
547
+ "Hidden"
548
+ ] }),
549
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
550
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`fields.${index}.disabled`) }),
551
+ "Disabled"
552
+ ] }),
553
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
554
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Placeholder" }),
555
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`fields.${index}.placeholder`) })
556
+ ] }),
557
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
558
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Static options" }),
559
+ /* @__PURE__ */ jsx("textarea", { style: styles.textarea, ...form.register(`fields.${index}.optionsText`) })
560
+ ] }),
561
+ /* @__PURE__ */ jsx("div", { style: styles.actions, children: /* @__PURE__ */ jsx(
562
+ "button",
563
+ {
564
+ type: "button",
565
+ style: styles.button,
566
+ onClick: () => fieldArray.remove(index),
567
+ disabled: fieldArray.fields.length <= 1,
568
+ children: "Remove"
569
+ }
570
+ ) })
571
+ ] }, field.id))
572
+ ] }),
573
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
574
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
575
+ /* @__PURE__ */ jsxs("div", { children: [
576
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Layout" }),
577
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Default layout can be regenerated from current fields." })
578
+ ] }),
579
+ /* @__PURE__ */ jsx(
580
+ "button",
581
+ {
582
+ type: "button",
583
+ style: styles.button,
584
+ onClick: () => form.setValue("layoutGroups", builderFormEditorDefaultLayoutGroups(fields), {
585
+ shouldDirty: true
586
+ }),
587
+ children: "Reset layout"
588
+ }
589
+ )
590
+ ] }),
591
+ form.watch("layoutGroups").map((group, groupIndex) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
592
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
593
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Group title" }),
594
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`layoutGroups.${groupIndex}.title`) })
595
+ ] }),
596
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
597
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Columns" }),
598
+ /* @__PURE__ */ jsxs(
599
+ "select",
600
+ {
601
+ style: styles.input,
602
+ value: group.columns,
603
+ onChange: (event) => form.setValue(
604
+ `layoutGroups.${groupIndex}.columns`,
605
+ Number(event.target.value),
606
+ { shouldDirty: true }
607
+ ),
608
+ children: [
609
+ /* @__PURE__ */ jsx("option", { value: 6, children: "6" }),
610
+ /* @__PURE__ */ jsx("option", { value: 8, children: "8" }),
611
+ /* @__PURE__ */ jsx("option", { value: 12, children: "12" })
612
+ ]
613
+ }
614
+ )
615
+ ] }),
616
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
617
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Fields" }),
618
+ /* @__PURE__ */ jsx(
619
+ "input",
620
+ {
621
+ style: styles.input,
622
+ value: group.fields.map((item) => item.key).join(", "),
623
+ readOnly: true
624
+ }
625
+ )
626
+ ] })
627
+ ] }, group.id))
628
+ ] }),
629
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
630
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
631
+ /* @__PURE__ */ jsxs("div", { children: [
632
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Subforms" }),
633
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional nested runtime view bindings." })
634
+ ] }),
635
+ /* @__PURE__ */ jsx(
636
+ "button",
637
+ {
638
+ type: "button",
639
+ style: styles.button,
640
+ onClick: () => subformArray.append({
641
+ key: `subform${subformArray.fields.length + 1}`,
642
+ label: `Subform ${subformArray.fields.length + 1}`,
643
+ viewId: BUILDER_EDITOR_NONE_VALUE,
644
+ parentField: "id",
645
+ childField: "parentId",
646
+ buttonLabel: "",
647
+ icon: ""
648
+ }),
649
+ children: "Add subform"
650
+ }
651
+ )
652
+ ] }),
653
+ subformArray.fields.map((subform, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
654
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
655
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
656
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.key`) })
657
+ ] }),
658
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
659
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
660
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.label`) })
661
+ ] }),
662
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
663
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "View ID" }),
664
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.viewId`) })
665
+ ] }),
666
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
667
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Parent field" }),
668
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.parentField`) })
669
+ ] }),
670
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
671
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Child field" }),
672
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`subforms.${index}.childField`) })
673
+ ] }),
674
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => subformArray.remove(index), children: "Remove" })
675
+ ] }, subform.id))
676
+ ] }),
677
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
678
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
679
+ /* @__PURE__ */ jsxs("div", { children: [
680
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Form Triggers" }),
681
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional API callbacks for lifecycle events." })
682
+ ] }),
683
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.append(emptyTrigger), children: "Add trigger" })
684
+ ] }),
685
+ triggerArray.fields.map((trigger, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
686
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
687
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Event" }),
688
+ /* @__PURE__ */ jsx(
689
+ "select",
690
+ {
691
+ style: styles.input,
692
+ ...form.register(
693
+ `triggers.${index}.event`
694
+ ),
695
+ children: optionItems(options.formTriggerEventOptions)
696
+ }
697
+ )
698
+ ] }),
699
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
700
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Route" }),
701
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`triggers.${index}.route`) })
702
+ ] }),
703
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
704
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.enabled`) }),
705
+ "Enabled"
706
+ ] }),
707
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
708
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.blocking`) }),
709
+ "Blocking"
710
+ ] }),
711
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.remove(index), children: "Remove" })
712
+ ] }, trigger.id))
713
+ ] })
714
+ ] });
715
+ };
716
+ }
717
+ function createBuilderDefaultListEditorBody(options) {
718
+ return function BuilderDefaultListEditorBody({
719
+ listId,
720
+ form,
721
+ columnArray,
722
+ triggerArray,
723
+ sourceType,
724
+ sourceTable,
725
+ tables,
726
+ emptyColumn,
727
+ emptyTrigger,
728
+ isSaving,
729
+ importColumnsFromTable
730
+ }) {
731
+ return /* @__PURE__ */ jsxs("div", { style: styles.page, children: [
732
+ /* @__PURE__ */ jsxs("div", { style: styles.header, children: [
733
+ /* @__PURE__ */ jsxs("div", { children: [
734
+ /* @__PURE__ */ jsx("h1", { style: styles.title, children: listId ? "Edit Dynamic List" : "New Dynamic List" }),
735
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Configure list columns, source mapping, and triggers." })
736
+ ] }),
737
+ /* @__PURE__ */ jsxs("div", { style: styles.actions, children: [
738
+ /* @__PURE__ */ jsx("a", { href: options.backHref, style: styles.button, children: "Cancel" }),
739
+ /* @__PURE__ */ jsx("button", { type: "submit", disabled: isSaving, style: styles.primaryButton, children: isSaving ? "Saving..." : "Save" })
740
+ ] })
741
+ ] }),
742
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
743
+ /* @__PURE__ */ jsx("div", { style: styles.sectionHeader, children: /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Details" }) }),
744
+ /* @__PURE__ */ jsxs("div", { style: { ...styles.grid, ...styles.twoColumn }, children: [
745
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
746
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Title" }),
747
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("title", { required: true }) })
748
+ ] }),
749
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
750
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Description" }),
751
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("description") })
752
+ ] }),
753
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
754
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Datasource" }),
755
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceType"), children: [
756
+ /* @__PURE__ */ jsx("option", { value: "none", children: "None" }),
757
+ /* @__PURE__ */ jsx("option", { value: "dbTable", children: "DB table" }),
758
+ /* @__PURE__ */ jsx("option", { value: "apiEndpoint", children: "API endpoint" })
759
+ ] })
760
+ ] }),
761
+ sourceType === "dbTable" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
762
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Table" }),
763
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register("sourceTable"), children: [
764
+ /* @__PURE__ */ jsx("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "Select table" }),
765
+ tables.map((table) => /* @__PURE__ */ jsx("option", { value: table.name, children: table.label ?? table.name }, table.name))
766
+ ] })
767
+ ] }) : null,
768
+ sourceType === "apiEndpoint" ? /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
769
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "API base path" }),
770
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register("apiBasePath") })
771
+ ] }) : null,
772
+ sourceType === "dbTable" ? /* @__PURE__ */ jsx("div", { style: { ...styles.field, justifyContent: "end" }, children: /* @__PURE__ */ jsx(
773
+ "button",
774
+ {
775
+ type: "button",
776
+ style: styles.button,
777
+ disabled: sourceTable === BUILDER_EDITOR_NONE_VALUE,
778
+ onClick: importColumnsFromTable,
779
+ children: "Import columns"
780
+ }
781
+ ) }) : null
782
+ ] })
783
+ ] }),
784
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
785
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
786
+ /* @__PURE__ */ jsxs("div", { children: [
787
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "Columns" }),
788
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Runtime list columns." })
789
+ ] }),
790
+ /* @__PURE__ */ jsx(
791
+ "button",
792
+ {
793
+ type: "button",
794
+ style: styles.button,
795
+ onClick: () => columnArray.append({
796
+ ...emptyColumn,
797
+ key: `field${columnArray.fields.length + 1}`,
798
+ label: `Column ${columnArray.fields.length + 1}`
799
+ }),
800
+ children: "Add column"
801
+ }
802
+ )
803
+ ] }),
804
+ columnArray.fields.map((column, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
805
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
806
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Key" }),
807
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`columns.${index}.key`) })
808
+ ] }),
809
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
810
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Label" }),
811
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`columns.${index}.label`) })
812
+ ] }),
813
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
814
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Align" }),
815
+ /* @__PURE__ */ jsxs("select", { style: styles.input, ...form.register(`columns.${index}.align`), children: [
816
+ /* @__PURE__ */ jsx("option", { value: "left", children: "Left" }),
817
+ /* @__PURE__ */ jsx("option", { value: "right", children: "Right" })
818
+ ] })
819
+ ] }),
820
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
821
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`columns.${index}.sortable`) }),
822
+ "Sortable"
823
+ ] }),
824
+ /* @__PURE__ */ jsx(
825
+ "button",
826
+ {
827
+ type: "button",
828
+ style: styles.button,
829
+ onClick: () => columnArray.remove(index),
830
+ disabled: columnArray.fields.length <= 1,
831
+ children: "Remove"
832
+ }
833
+ )
834
+ ] }, column.id))
835
+ ] }),
836
+ /* @__PURE__ */ jsxs("section", { style: styles.section, children: [
837
+ /* @__PURE__ */ jsxs("div", { style: styles.sectionHeader, children: [
838
+ /* @__PURE__ */ jsxs("div", { children: [
839
+ /* @__PURE__ */ jsx("h2", { style: styles.sectionTitle, children: "List Triggers" }),
840
+ /* @__PURE__ */ jsx("p", { style: styles.description, children: "Optional API callbacks for list lifecycle events." })
841
+ ] }),
842
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.append(emptyTrigger), children: "Add trigger" })
843
+ ] }),
844
+ triggerArray.fields.map((trigger, index) => /* @__PURE__ */ jsxs("div", { style: styles.row, children: [
845
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
846
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Event" }),
847
+ /* @__PURE__ */ jsx(
848
+ "select",
849
+ {
850
+ style: styles.input,
851
+ ...form.register(
852
+ `triggers.${index}.event`
853
+ ),
854
+ children: optionItems(options.listTriggerEventOptions)
855
+ }
856
+ )
857
+ ] }),
858
+ /* @__PURE__ */ jsxs("label", { style: styles.field, children: [
859
+ /* @__PURE__ */ jsx("span", { style: styles.label, children: "Route" }),
860
+ /* @__PURE__ */ jsx("input", { style: styles.input, ...form.register(`triggers.${index}.route`) })
861
+ ] }),
862
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
863
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.enabled`) }),
864
+ "Enabled"
865
+ ] }),
866
+ /* @__PURE__ */ jsxs("label", { style: styles.checkboxField, children: [
867
+ /* @__PURE__ */ jsx("input", { type: "checkbox", ...form.register(`triggers.${index}.blocking`) }),
868
+ "Blocking"
869
+ ] }),
870
+ /* @__PURE__ */ jsx("button", { type: "button", style: styles.button, onClick: () => triggerArray.remove(index), children: "Remove" })
871
+ ] }, trigger.id))
872
+ ] })
873
+ ] });
874
+ };
875
+ }
876
+
877
+ // src/admin/BuilderDefaultEntityManager.tsx
878
+ import { useMemo, useState } from "react";
879
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
880
+ var styles2 = {
881
+ page: {
882
+ display: "grid",
883
+ gap: "1rem"
884
+ },
885
+ header: {
886
+ display: "flex",
887
+ justifyContent: "space-between",
888
+ gap: "1rem",
889
+ alignItems: "flex-start",
890
+ flexWrap: "wrap"
891
+ },
892
+ title: {
893
+ margin: 0,
894
+ fontSize: "1.5rem",
895
+ fontWeight: 650
896
+ },
897
+ description: {
898
+ margin: "0.25rem 0 0",
899
+ color: "var(--muted-foreground, #64748b)"
900
+ },
901
+ button: {
902
+ border: "1px solid var(--border, #d4d4d8)",
903
+ borderRadius: "0.375rem",
904
+ background: "var(--background, #fff)",
905
+ color: "inherit",
906
+ cursor: "pointer",
907
+ padding: "0.5rem 0.75rem",
908
+ textDecoration: "none",
909
+ fontSize: "0.875rem"
910
+ },
911
+ primaryButton: {
912
+ border: "1px solid var(--primary, #18181b)",
913
+ borderRadius: "0.375rem",
914
+ background: "var(--primary, #18181b)",
915
+ color: "var(--primary-foreground, #fff)",
916
+ cursor: "pointer",
917
+ padding: "0.5rem 0.75rem",
918
+ textDecoration: "none",
919
+ fontSize: "0.875rem"
920
+ },
921
+ card: {
922
+ border: "1px solid var(--border, #d4d4d8)",
923
+ borderRadius: "0.5rem",
924
+ overflow: "hidden",
925
+ background: "var(--background, #fff)"
926
+ },
927
+ toolbar: {
928
+ padding: "0.75rem",
929
+ borderBottom: "1px solid var(--border, #d4d4d8)"
930
+ },
931
+ input: {
932
+ width: "100%",
933
+ maxWidth: "24rem",
934
+ border: "1px solid var(--border, #d4d4d8)",
935
+ borderRadius: "0.375rem",
936
+ padding: "0.5rem 0.75rem",
937
+ background: "var(--background, #fff)",
938
+ color: "inherit"
939
+ },
940
+ tableWrap: {
941
+ overflowX: "auto"
942
+ },
943
+ table: {
944
+ width: "100%",
945
+ borderCollapse: "collapse",
946
+ fontSize: "0.875rem"
947
+ },
948
+ th: {
949
+ padding: "0.75rem",
950
+ borderBottom: "1px solid var(--border, #d4d4d8)",
951
+ textAlign: "left",
952
+ color: "var(--muted-foreground, #64748b)",
953
+ fontWeight: 600,
954
+ whiteSpace: "nowrap"
955
+ },
956
+ td: {
957
+ padding: "0.75rem",
958
+ borderBottom: "1px solid var(--border, #d4d4d8)",
959
+ verticalAlign: "top"
960
+ },
961
+ actions: {
962
+ display: "flex",
963
+ justifyContent: "flex-end",
964
+ gap: "0.5rem",
965
+ flexWrap: "wrap"
966
+ },
967
+ empty: {
968
+ padding: "2rem",
969
+ textAlign: "center",
970
+ color: "var(--muted-foreground, #64748b)"
971
+ }
972
+ };
973
+ function createBuilderDefaultEntityManagerComponent(deps) {
974
+ return function BuilderDefaultEntityManager() {
975
+ const [state, setState] = useState({
976
+ page: 1,
977
+ pageSize: 20,
978
+ search: ""
979
+ });
980
+ const query = deps.hooks.useEntities(useMemo(() => deps.buildQuery(state), [state]));
981
+ const remove = deps.hooks.useDelete();
982
+ const replicate = deps.hooks.useReplicate();
983
+ const items = query.data?.items ?? [];
984
+ const onReplicate = async (entity) => {
985
+ const title = window.prompt(
986
+ deps.labels.replicatePrompt(entity),
987
+ deps.labels.replicateDefaultTitle(entity)
988
+ );
989
+ if (!title) return;
990
+ await replicate.mutateAsync({ id: entity.id, input: { title } });
991
+ };
992
+ const onDelete = async (entity) => {
993
+ if (!window.confirm(deps.labels.deleteConfirm(entity))) return;
994
+ await remove.mutateAsync(entity.id);
995
+ };
996
+ return /* @__PURE__ */ jsxs2("section", { style: styles2.page, children: [
997
+ /* @__PURE__ */ jsxs2("div", { style: styles2.header, children: [
998
+ /* @__PURE__ */ jsxs2("div", { children: [
999
+ /* @__PURE__ */ jsx2("h1", { style: styles2.title, children: deps.labels.title }),
1000
+ /* @__PURE__ */ jsx2("p", { style: styles2.description, children: deps.labels.description })
1001
+ ] }),
1002
+ deps.createHref ? /* @__PURE__ */ jsx2("a", { href: deps.createHref, style: styles2.primaryButton, children: deps.labels.addLabel }) : null
1003
+ ] }),
1004
+ /* @__PURE__ */ jsxs2("div", { style: styles2.card, children: [
1005
+ /* @__PURE__ */ jsx2("div", { style: styles2.toolbar, children: /* @__PURE__ */ jsx2(
1006
+ "input",
1007
+ {
1008
+ style: styles2.input,
1009
+ placeholder: deps.labels.searchPlaceholder,
1010
+ value: state.search,
1011
+ onChange: (event) => setState((current) => ({ ...current, page: 1, search: event.target.value }))
1012
+ }
1013
+ ) }),
1014
+ /* @__PURE__ */ jsx2("div", { style: styles2.tableWrap, children: /* @__PURE__ */ jsxs2("table", { style: styles2.table, children: [
1015
+ /* @__PURE__ */ jsx2("thead", { children: /* @__PURE__ */ jsxs2("tr", { children: [
1016
+ /* @__PURE__ */ jsx2("th", { style: styles2.th, children: deps.labels.title }),
1017
+ /* @__PURE__ */ jsx2("th", { style: styles2.th, children: "Detail" }),
1018
+ /* @__PURE__ */ jsx2("th", { style: styles2.th, children: "Description" }),
1019
+ /* @__PURE__ */ jsx2("th", { style: { ...styles2.th, textAlign: "right" }, children: "Actions" })
1020
+ ] }) }),
1021
+ /* @__PURE__ */ jsx2("tbody", { children: items.map((entity) => /* @__PURE__ */ jsxs2("tr", { children: [
1022
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: /* @__PURE__ */ jsx2("a", { href: deps.editHref(entity), children: entity.title }) }),
1023
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: deps.getDetail?.(entity) ?? "-" }),
1024
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: entity.description || "-" }),
1025
+ /* @__PURE__ */ jsx2("td", { style: styles2.td, children: /* @__PURE__ */ jsxs2("div", { style: styles2.actions, children: [
1026
+ deps.runtimeHref ? /* @__PURE__ */ jsx2("a", { href: deps.runtimeHref(entity), style: styles2.button, children: deps.labels.runtimeLabel }) : null,
1027
+ /* @__PURE__ */ jsx2("a", { href: deps.editHref(entity), style: styles2.button, children: deps.labels.editLabel }),
1028
+ /* @__PURE__ */ jsx2(
1029
+ "button",
1030
+ {
1031
+ type: "button",
1032
+ style: styles2.button,
1033
+ onClick: () => void onReplicate(entity),
1034
+ children: deps.labels.replicateLabel
1035
+ }
1036
+ ),
1037
+ /* @__PURE__ */ jsx2(
1038
+ "button",
1039
+ {
1040
+ type: "button",
1041
+ style: styles2.button,
1042
+ disabled: remove.isPending,
1043
+ onClick: () => void onDelete(entity),
1044
+ children: deps.labels.deleteLabel
1045
+ }
1046
+ )
1047
+ ] }) })
1048
+ ] }, entity.id)) })
1049
+ ] }) }),
1050
+ query.isPending ? /* @__PURE__ */ jsx2("div", { style: styles2.empty, children: "Loading..." }) : null,
1051
+ query.isError ? /* @__PURE__ */ jsx2("div", { style: styles2.empty, children: "Failed to load." }) : null,
1052
+ !query.isPending && !query.isError && items.length === 0 ? /* @__PURE__ */ jsxs2("div", { style: styles2.empty, children: [
1053
+ /* @__PURE__ */ jsx2("strong", { children: deps.labels.emptyTitle }),
1054
+ /* @__PURE__ */ jsx2("div", { children: deps.labels.emptyDescription })
1055
+ ] }) : null
1056
+ ] })
1057
+ ] });
1058
+ };
1059
+ }
1060
+
1061
+ // src/admin/BuilderDefaultViewEditorPage.tsx
1062
+ import { useEffect } from "react";
1063
+ import { useForm } from "react-hook-form";
1064
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1065
+ var styles3 = {
1066
+ page: {
1067
+ display: "grid",
1068
+ gap: "1rem"
1069
+ },
1070
+ header: {
1071
+ display: "flex",
1072
+ justifyContent: "space-between",
1073
+ gap: "1rem",
1074
+ alignItems: "flex-start",
1075
+ flexWrap: "wrap"
1076
+ },
1077
+ title: {
1078
+ margin: 0,
1079
+ fontSize: "1.5rem",
1080
+ fontWeight: 650
1081
+ },
1082
+ description: {
1083
+ margin: "0.25rem 0 0",
1084
+ color: "var(--muted-foreground, #64748b)"
1085
+ },
1086
+ actions: {
1087
+ display: "flex",
1088
+ gap: "0.5rem",
1089
+ flexWrap: "wrap"
1090
+ },
1091
+ section: {
1092
+ border: "1px solid var(--border, #d4d4d8)",
1093
+ borderRadius: "0.5rem",
1094
+ background: "var(--background, #fff)",
1095
+ overflow: "hidden"
1096
+ },
1097
+ grid: {
1098
+ display: "grid",
1099
+ gridTemplateColumns: "repeat(auto-fit, minmax(14rem, 1fr))",
1100
+ gap: "0.75rem",
1101
+ padding: "0.75rem"
1102
+ },
1103
+ field: {
1104
+ display: "grid",
1105
+ gap: "0.25rem",
1106
+ fontSize: "0.875rem"
1107
+ },
1108
+ label: {
1109
+ color: "var(--muted-foreground, #64748b)",
1110
+ fontSize: "0.75rem",
1111
+ fontWeight: 600
1112
+ },
1113
+ input: {
1114
+ minWidth: 0,
1115
+ border: "1px solid var(--border, #d4d4d8)",
1116
+ borderRadius: "0.375rem",
1117
+ padding: "0.5rem 0.625rem",
1118
+ background: "var(--background, #fff)",
1119
+ color: "inherit"
1120
+ },
1121
+ textarea: {
1122
+ minWidth: 0,
1123
+ minHeight: "8rem",
1124
+ border: "1px solid var(--border, #d4d4d8)",
1125
+ borderRadius: "0.375rem",
1126
+ padding: "0.5rem 0.625rem",
1127
+ background: "var(--background, #fff)",
1128
+ color: "inherit",
1129
+ resize: "vertical"
1130
+ },
1131
+ button: {
1132
+ border: "1px solid var(--border, #d4d4d8)",
1133
+ borderRadius: "0.375rem",
1134
+ background: "var(--background, #fff)",
1135
+ color: "inherit",
1136
+ cursor: "pointer",
1137
+ padding: "0.5rem 0.75rem",
1138
+ textDecoration: "none",
1139
+ fontSize: "0.875rem"
1140
+ },
1141
+ primaryButton: {
1142
+ border: "1px solid var(--primary, #18181b)",
1143
+ borderRadius: "0.375rem",
1144
+ background: "var(--primary, #18181b)",
1145
+ color: "var(--primary-foreground, #fff)",
1146
+ cursor: "pointer",
1147
+ padding: "0.5rem 0.75rem",
1148
+ textDecoration: "none",
1149
+ fontSize: "0.875rem"
1150
+ },
1151
+ state: {
1152
+ color: "var(--muted-foreground, #64748b)",
1153
+ fontSize: "0.875rem"
1154
+ }
1155
+ };
1156
+ var defaultEmptyValues = {
1157
+ title: "",
1158
+ description: "",
1159
+ formId: BUILDER_EDITOR_NONE_VALUE,
1160
+ listId: BUILDER_EDITOR_NONE_VALUE,
1161
+ permissionRead: "org:manage",
1162
+ permissionWrite: "org:manage",
1163
+ triggersText: "[]",
1164
+ version: 0
1165
+ };
1166
+ function createBuilderDefaultViewEditorPage(options) {
1167
+ return function BuilderDefaultViewEditorPage({ viewId }) {
1168
+ const view = options.hooks.useBuilderView(viewId);
1169
+ const forms = options.hooks.useBuilderFormOptions();
1170
+ const lists = options.hooks.useBuilderListOptions();
1171
+ const save = options.hooks.useSaveBuilderView();
1172
+ const form = useForm({
1173
+ defaultValues: { ...defaultEmptyValues, permissionRead: options.defaultPermission, permissionWrite: options.defaultPermission }
1174
+ });
1175
+ useEffect(() => {
1176
+ if (viewId && !view.data) return;
1177
+ form.reset(
1178
+ builderViewEditorValuesFromEntity(
1179
+ view.data ?? null,
1180
+ { ...defaultEmptyValues, permissionRead: options.defaultPermission, permissionWrite: options.defaultPermission },
1181
+ options.defaultPermission
1182
+ )
1183
+ );
1184
+ }, [form, view.data, viewId]);
1185
+ const onSubmit = form.handleSubmit(async (values) => {
1186
+ try {
1187
+ const input = builderViewEditorInputFromValues(values, options.parseTriggers);
1188
+ const saved = await save.mutateAsync({
1189
+ id: viewId,
1190
+ input
1191
+ });
1192
+ options.notifySuccess?.(viewId ? "View saved" : "View created");
1193
+ if (!viewId) {
1194
+ window.location.assign(options.editHref(saved.id));
1195
+ }
1196
+ } catch (error) {
1197
+ if (options.notifyError) options.notifyError(error);
1198
+ else throw error;
1199
+ }
1200
+ });
1201
+ if (viewId && view.isPending) {
1202
+ return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Loading..." });
1203
+ }
1204
+ if (viewId && view.isError) {
1205
+ return /* @__PURE__ */ jsx3("div", { style: styles3.state, children: "Failed to load view." });
1206
+ }
1207
+ return /* @__PURE__ */ jsxs3("form", { onSubmit, noValidate: true, style: styles3.page, children: [
1208
+ /* @__PURE__ */ jsxs3("div", { style: styles3.header, children: [
1209
+ /* @__PURE__ */ jsxs3("div", { children: [
1210
+ /* @__PURE__ */ jsx3("h1", { style: styles3.title, children: viewId ? "Edit Dynamic View" : "New Dynamic View" }),
1211
+ /* @__PURE__ */ jsx3("p", { style: styles3.description, children: "Connect a form and list into a runtime screen." })
1212
+ ] }),
1213
+ /* @__PURE__ */ jsxs3("div", { style: styles3.actions, children: [
1214
+ /* @__PURE__ */ jsx3("a", { href: options.backHref, style: styles3.button, children: "Cancel" }),
1215
+ /* @__PURE__ */ jsx3("button", { type: "submit", disabled: save.isPending, style: styles3.primaryButton, children: save.isPending ? "Saving..." : "Save" })
1216
+ ] })
1217
+ ] }),
1218
+ /* @__PURE__ */ jsx3("section", { style: styles3.section, children: /* @__PURE__ */ jsxs3("div", { style: styles3.grid, children: [
1219
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1220
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Title" }),
1221
+ /* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("title", { required: true }) })
1222
+ ] }),
1223
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1224
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Description" }),
1225
+ /* @__PURE__ */ jsx3("input", { style: styles3.input, ...form.register("description") })
1226
+ ] }),
1227
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1228
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Form" }),
1229
+ /* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("formId"), children: [
1230
+ /* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No form" }),
1231
+ (forms.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
1232
+ ] })
1233
+ ] }),
1234
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1235
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "List" }),
1236
+ /* @__PURE__ */ jsxs3("select", { style: styles3.input, ...form.register("listId"), children: [
1237
+ /* @__PURE__ */ jsx3("option", { value: BUILDER_EDITOR_NONE_VALUE, children: "No list" }),
1238
+ (lists.data ?? []).map((item) => /* @__PURE__ */ jsx3("option", { value: item.id, children: item.title }, item.id))
1239
+ ] })
1240
+ ] }),
1241
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1242
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Read permission" }),
1243
+ /* @__PURE__ */ jsx3("select", { style: styles3.input, ...form.register("permissionRead"), children: options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value)) })
1244
+ ] }),
1245
+ /* @__PURE__ */ jsxs3("label", { style: styles3.field, children: [
1246
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Write permission" }),
1247
+ /* @__PURE__ */ jsx3("select", { style: styles3.input, ...form.register("permissionWrite"), children: options.permissionOptions.map((permission) => /* @__PURE__ */ jsx3("option", { value: permission.value, children: permission.label }, permission.value)) })
1248
+ ] }),
1249
+ /* @__PURE__ */ jsxs3("label", { style: { ...styles3.field, gridColumn: "1 / -1" }, children: [
1250
+ /* @__PURE__ */ jsx3("span", { style: styles3.label, children: "Triggers JSON" }),
1251
+ /* @__PURE__ */ jsx3("textarea", { style: styles3.textarea, ...form.register("triggersText") })
1252
+ ] })
1253
+ ] }) })
1254
+ ] });
1255
+ };
1256
+ }
1257
+
313
1258
  // src/admin/BuilderEditorPage.tsx
314
- import { jsx } from "react/jsx-runtime";
1259
+ import { useEffect as useEffect2 } from "react";
1260
+ import {
1261
+ FormProvider,
1262
+ useFieldArray,
1263
+ useForm as useForm2,
1264
+ useWatch
1265
+ } from "react-hook-form";
1266
+ import { jsx as jsx4 } from "react/jsx-runtime";
315
1267
  function createBuilderFormEditorPageComponent(deps) {
316
1268
  return function BuilderFormEditorPage({ formId }) {
317
1269
  const Body = deps.Body;
318
1270
  const entityQuery = deps.hooks.useEntity(formId);
319
1271
  const tables = deps.hooks.useTables();
320
1272
  const save = deps.hooks.useSave();
321
- const form = useForm({
1273
+ const form = useForm2({
322
1274
  resolver: deps.resolver,
323
1275
  defaultValues: deps.emptyValues
324
1276
  });
@@ -329,7 +1281,7 @@ function createBuilderFormEditorPageComponent(deps) {
329
1281
  const subforms = useWatch({ control: form.control, name: "subforms" }) ?? [];
330
1282
  const sourceType = useWatch({ control: form.control, name: "sourceType" });
331
1283
  const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
332
- useEffect(() => {
1284
+ useEffect2(() => {
333
1285
  if (formId && !entityQuery.data) return;
334
1286
  form.reset(builderFormEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
335
1287
  }, [entityQuery.data, form, formId]);
@@ -352,12 +1304,12 @@ function createBuilderFormEditorPageComponent(deps) {
352
1304
  }
353
1305
  });
354
1306
  if (formId && entityQuery.isPending) {
355
- return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
1307
+ return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
356
1308
  }
357
1309
  if (formId && entityQuery.isError) {
358
- return /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: deps.states.error });
1310
+ return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
359
1311
  }
360
- return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx(
1312
+ return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
361
1313
  Body,
362
1314
  {
363
1315
  formId,
@@ -384,7 +1336,7 @@ function createBuilderListEditorPageComponent(deps) {
384
1336
  const entityQuery = deps.hooks.useEntity(listId);
385
1337
  const tables = deps.hooks.useTables();
386
1338
  const save = deps.hooks.useSave();
387
- const form = useForm({
1339
+ const form = useForm2({
388
1340
  resolver: deps.resolver,
389
1341
  defaultValues: deps.emptyValues
390
1342
  });
@@ -392,7 +1344,7 @@ function createBuilderListEditorPageComponent(deps) {
392
1344
  const triggerArray = useFieldArray({ control: form.control, name: "triggers" });
393
1345
  const sourceType = useWatch({ control: form.control, name: "sourceType" });
394
1346
  const sourceTable = useWatch({ control: form.control, name: "sourceTable" });
395
- useEffect(() => {
1347
+ useEffect2(() => {
396
1348
  if (listId && !entityQuery.data) return;
397
1349
  form.reset(builderListEditorValuesFromEntity(entityQuery.data ?? null, deps.emptyValues));
398
1350
  }, [entityQuery.data, form, listId]);
@@ -411,12 +1363,12 @@ function createBuilderListEditorPageComponent(deps) {
411
1363
  }
412
1364
  });
413
1365
  if (listId && entityQuery.isPending) {
414
- return /* @__PURE__ */ jsx("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
1366
+ return /* @__PURE__ */ jsx4("div", { className: "text-muted-foreground text-sm", children: deps.states.loading });
415
1367
  }
416
1368
  if (listId && entityQuery.isError) {
417
- return /* @__PURE__ */ jsx("div", { className: "text-destructive text-sm", children: deps.states.error });
1369
+ return /* @__PURE__ */ jsx4("div", { className: "text-destructive text-sm", children: deps.states.error });
418
1370
  }
419
- return /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsx("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx(
1371
+ return /* @__PURE__ */ jsx4(FormProvider, { ...form, children: /* @__PURE__ */ jsx4("form", { onSubmit, noValidate: true, className: "space-y-6", children: /* @__PURE__ */ jsx4(
420
1372
  Body,
421
1373
  {
422
1374
  listId,
@@ -435,17 +1387,405 @@ function createBuilderListEditorPageComponent(deps) {
435
1387
  };
436
1388
  }
437
1389
 
1390
+ // src/admin/BuilderAdminPages.tsx
1391
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1392
+ var defaultFieldTypeOptions = [
1393
+ { value: "text", label: "Text" },
1394
+ { value: "textarea", label: "Textarea" },
1395
+ { value: "number", label: "Number" },
1396
+ { value: "money", label: "Money" },
1397
+ { value: "select", label: "Select" },
1398
+ { value: "checkbox", label: "Checkbox" },
1399
+ { value: "date", label: "Date" }
1400
+ ];
1401
+ var defaultFormTriggerEventOptions = [
1402
+ { value: "beforeCreate", label: "Before create" },
1403
+ { value: "afterCreate", label: "After create" },
1404
+ { value: "beforeUpdate", label: "Before update" },
1405
+ { value: "afterUpdate", label: "After update" }
1406
+ ];
1407
+ var defaultListTriggerEventOptions = [
1408
+ { value: "beforeRead", label: "Before read" },
1409
+ { value: "afterRead", label: "After read" },
1410
+ { value: "beforeDelete", label: "Before delete" },
1411
+ { value: "afterDelete", label: "After delete" }
1412
+ ];
1413
+ var defaultFieldTriggerEventOptions = [
1414
+ { value: "onChange", label: "On change" },
1415
+ { value: "onBlur", label: "On blur" }
1416
+ ];
1417
+ var defaultPermissionOptions = [{ value: "org:manage", label: "org:manage" }];
1418
+ function parseJsonArray(value) {
1419
+ const parsed = JSON.parse(value);
1420
+ return Array.isArray(parsed) ? parsed : [];
1421
+ }
1422
+ function joinPath(base, path) {
1423
+ return `${base.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
1424
+ }
1425
+ function defaultQuery(state) {
1426
+ return {
1427
+ page: state.page,
1428
+ pageSize: state.pageSize,
1429
+ search: state.search || void 0
1430
+ };
1431
+ }
1432
+ function detail(entity) {
1433
+ return entity.key ?? entity.id;
1434
+ }
1435
+ var homeStyles = {
1436
+ page: {
1437
+ display: "grid",
1438
+ gap: "1rem"
1439
+ },
1440
+ headerTitle: {
1441
+ margin: 0,
1442
+ fontSize: "1.5rem",
1443
+ fontWeight: 650
1444
+ },
1445
+ description: {
1446
+ margin: "0.25rem 0 0",
1447
+ color: "var(--muted-foreground, #64748b)"
1448
+ },
1449
+ grid: {
1450
+ display: "grid",
1451
+ gridTemplateColumns: "repeat(auto-fit, minmax(13rem, 1fr))",
1452
+ gap: "0.75rem"
1453
+ },
1454
+ card: {
1455
+ border: "1px solid var(--border, #d4d4d8)",
1456
+ borderRadius: "0.5rem",
1457
+ padding: "1rem",
1458
+ background: "var(--background, #fff)",
1459
+ color: "inherit",
1460
+ textDecoration: "none"
1461
+ },
1462
+ cardTitle: {
1463
+ margin: 0,
1464
+ fontSize: "1rem",
1465
+ fontWeight: 650
1466
+ }
1467
+ };
1468
+ function createBuilderAdminPages({
1469
+ hooks,
1470
+ routes = {},
1471
+ fieldTypeOptions = defaultFieldTypeOptions,
1472
+ formTriggerEventOptions = defaultFormTriggerEventOptions,
1473
+ listTriggerEventOptions = defaultListTriggerEventOptions,
1474
+ fieldTriggerEventOptions = defaultFieldTriggerEventOptions,
1475
+ permissionOptions = defaultPermissionOptions,
1476
+ defaultPermission = "org:manage",
1477
+ notifySuccess,
1478
+ notifyError,
1479
+ parseViewTriggers = parseJsonArray
1480
+ }) {
1481
+ const adminBasePath = routes.adminBasePath ?? "/admin/dev/builder";
1482
+ const runtimeBasePath = routes.runtimeBasePath ?? "/admin/winu";
1483
+ const formsPath = routes.formsPath ?? joinPath(adminBasePath, "forms");
1484
+ const newFormPath = routes.newFormPath ?? joinPath(formsPath, "new");
1485
+ const editFormPath = routes.editFormPath ?? ((id) => `${joinPath(formsPath, "edit")}?id=${encodeURIComponent(id)}`);
1486
+ const runtimeFormPath = routes.runtimeFormPath ?? ((id) => `${joinPath(runtimeBasePath, "form")}?id=${encodeURIComponent(id)}`);
1487
+ const listsPath = routes.listsPath ?? joinPath(adminBasePath, "lists");
1488
+ const newListPath = routes.newListPath ?? joinPath(listsPath, "new");
1489
+ const editListPath = routes.editListPath ?? ((id) => `${joinPath(listsPath, "edit")}?id=${encodeURIComponent(id)}`);
1490
+ const runtimeListPath = routes.runtimeListPath ?? ((id) => `${joinPath(runtimeBasePath, "list")}?id=${encodeURIComponent(id)}`);
1491
+ const viewsPath = routes.viewsPath ?? joinPath(adminBasePath, "views");
1492
+ const newViewPath = routes.newViewPath ?? joinPath(viewsPath, "new");
1493
+ const editViewPath = routes.editViewPath ?? ((id) => `${joinPath(viewsPath, "edit")}?id=${encodeURIComponent(id)}`);
1494
+ const runtimeViewPath = routes.runtimeViewPath ?? ((id) => `${joinPath(runtimeBasePath, "view")}?id=${encodeURIComponent(id)}`);
1495
+ const formFieldType = fieldTypeOptions[0]?.value ?? "text";
1496
+ const formTriggerEvent = formTriggerEventOptions[0]?.value ?? "beforeCreate";
1497
+ const listTriggerEvent = listTriggerEventOptions[0]?.value ?? "beforeRead";
1498
+ const emptyField = {
1499
+ key: "name",
1500
+ label: "Name",
1501
+ type: formFieldType,
1502
+ required: true,
1503
+ hidden: false,
1504
+ disabled: false,
1505
+ placeholder: "",
1506
+ optionsText: "",
1507
+ optionsMode: "static",
1508
+ optionsTable: BUILDER_EDITOR_NONE_VALUE,
1509
+ optionsValueField: BUILDER_EDITOR_NONE_VALUE,
1510
+ optionsLabelField: BUILDER_EDITOR_NONE_VALUE,
1511
+ optionsSearchFieldsText: "",
1512
+ optionsDependsOn: "",
1513
+ optionsFilterField: "",
1514
+ triggers: []
1515
+ };
1516
+ const emptyFormValues = {
1517
+ title: "",
1518
+ description: "",
1519
+ sourceType: "none",
1520
+ sourceTable: BUILDER_EDITOR_NONE_VALUE,
1521
+ apiBasePath: "",
1522
+ fields: [emptyField],
1523
+ layoutGroups: builderFormEditorDefaultLayoutGroups([emptyField]),
1524
+ subforms: [],
1525
+ triggers: [],
1526
+ version: 0
1527
+ };
1528
+ const emptyFormTrigger = {
1529
+ event: formTriggerEvent,
1530
+ route: "/api/v1/",
1531
+ enabled: false,
1532
+ blocking: true
1533
+ };
1534
+ const emptyColumn = {
1535
+ key: "name",
1536
+ label: "Name",
1537
+ sortable: true,
1538
+ align: "left"
1539
+ };
1540
+ const emptyListValues = {
1541
+ title: "",
1542
+ description: "",
1543
+ sourceType: "none",
1544
+ sourceTable: BUILDER_EDITOR_NONE_VALUE,
1545
+ apiBasePath: "",
1546
+ columns: [emptyColumn],
1547
+ triggers: [],
1548
+ version: 0
1549
+ };
1550
+ const emptyListTrigger = {
1551
+ event: listTriggerEvent,
1552
+ route: "/api/v1/",
1553
+ enabled: false,
1554
+ blocking: true
1555
+ };
1556
+ const FormEditorPage = createBuilderFormEditorPageComponent({
1557
+ emptyValues: emptyFormValues,
1558
+ emptyField,
1559
+ emptyTrigger: emptyFormTrigger,
1560
+ labels: {
1561
+ created: "Form created",
1562
+ saved: "Form saved"
1563
+ },
1564
+ states: {
1565
+ loading: "Loading...",
1566
+ error: "Failed to load form."
1567
+ },
1568
+ hooks: {
1569
+ useEntity: hooks.useBuilderForm,
1570
+ useTables: hooks.useBuilderDbTables,
1571
+ useSave: hooks.useSaveBuilderForm
1572
+ },
1573
+ buildInput: (values) => builderFormEditorInputFromValues(values),
1574
+ navigateAfterCreate: (entity) => window.location.assign(editFormPath(entity.id)),
1575
+ notifications: {
1576
+ success: (message) => notifySuccess?.(message),
1577
+ error: (error) => {
1578
+ if (notifyError) notifyError(error);
1579
+ else throw error;
1580
+ }
1581
+ },
1582
+ Body: createBuilderDefaultFormEditorBody({
1583
+ backHref: formsPath,
1584
+ fieldTypeOptions,
1585
+ formTriggerEventOptions,
1586
+ fieldTriggerEventOptions
1587
+ })
1588
+ });
1589
+ const ListEditorPage = createBuilderListEditorPageComponent({
1590
+ emptyValues: emptyListValues,
1591
+ emptyColumn,
1592
+ emptyTrigger: emptyListTrigger,
1593
+ labels: {
1594
+ created: "List created",
1595
+ saved: "List saved"
1596
+ },
1597
+ states: {
1598
+ loading: "Loading...",
1599
+ error: "Failed to load list."
1600
+ },
1601
+ hooks: {
1602
+ useEntity: hooks.useBuilderList,
1603
+ useTables: hooks.useBuilderDbTables,
1604
+ useSave: hooks.useSaveBuilderList
1605
+ },
1606
+ buildInput: (values) => builderListEditorInputFromValues(values),
1607
+ navigateAfterCreate: (entity) => window.location.assign(editListPath(entity.id)),
1608
+ notifications: {
1609
+ success: (message) => notifySuccess?.(message),
1610
+ error: (error) => {
1611
+ if (notifyError) notifyError(error);
1612
+ else throw error;
1613
+ }
1614
+ },
1615
+ Body: createBuilderDefaultListEditorBody({
1616
+ backHref: listsPath,
1617
+ listTriggerEventOptions
1618
+ })
1619
+ });
1620
+ const ViewEditorPage = createBuilderDefaultViewEditorPage({
1621
+ hooks,
1622
+ backHref: viewsPath,
1623
+ editHref: editViewPath,
1624
+ permissionOptions,
1625
+ defaultPermission,
1626
+ parseTriggers: parseViewTriggers,
1627
+ notifySuccess,
1628
+ notifyError
1629
+ });
1630
+ const AdminHomePage = function BuilderAdminHomePage() {
1631
+ const items = [
1632
+ {
1633
+ title: "Dynamic Forms",
1634
+ description: "Reusable form schemas.",
1635
+ href: formsPath
1636
+ },
1637
+ {
1638
+ title: "Dynamic Lists",
1639
+ description: "Reusable list and grid schemas.",
1640
+ href: listsPath
1641
+ },
1642
+ {
1643
+ title: "Dynamic Views",
1644
+ description: "Runtime screens composed from form and list schemas.",
1645
+ href: viewsPath
1646
+ }
1647
+ ];
1648
+ return /* @__PURE__ */ jsxs4("section", { style: homeStyles.page, children: [
1649
+ /* @__PURE__ */ jsxs4("div", { children: [
1650
+ /* @__PURE__ */ jsx5("h1", { style: homeStyles.headerTitle, children: "Builder" }),
1651
+ /* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: "Manage dynamic forms, lists, and views." })
1652
+ ] }),
1653
+ /* @__PURE__ */ jsx5("div", { style: homeStyles.grid, children: items.map((item) => /* @__PURE__ */ jsxs4("a", { href: item.href, style: homeStyles.card, children: [
1654
+ /* @__PURE__ */ jsx5("h2", { style: homeStyles.cardTitle, children: item.title }),
1655
+ /* @__PURE__ */ jsx5("p", { style: homeStyles.description, children: item.description })
1656
+ ] }, item.href)) })
1657
+ ] });
1658
+ };
1659
+ const AdminFormsPage = createBuilderDefaultEntityManagerComponent({
1660
+ labels: {
1661
+ title: "Dynamic Forms",
1662
+ description: "Reusable form schemas.",
1663
+ searchPlaceholder: "Search forms...",
1664
+ emptyTitle: "No forms",
1665
+ emptyDescription: "Create your first dynamic form.",
1666
+ addLabel: "Add form",
1667
+ editLabel: "Edit",
1668
+ replicateLabel: "Replicate",
1669
+ deleteLabel: "Delete",
1670
+ runtimeLabel: "Open",
1671
+ deleteConfirm: (entity) => `Delete ${entity.title}?`,
1672
+ replicatePrompt: () => "New form title",
1673
+ replicateDefaultTitle: (entity) => `${entity.title} copy`
1674
+ },
1675
+ createHref: newFormPath,
1676
+ editHref: (entity) => editFormPath(entity.id),
1677
+ runtimeHref: (entity) => runtimeFormPath(entity.id),
1678
+ getDetail: detail,
1679
+ buildQuery: (state) => defaultQuery(state),
1680
+ hooks: {
1681
+ useEntities: (query) => hooks.useBuilderForms(query),
1682
+ useDelete: hooks.useDeleteBuilderForm,
1683
+ useReplicate: hooks.useReplicateBuilderForm
1684
+ }
1685
+ });
1686
+ const AdminListsPage = createBuilderDefaultEntityManagerComponent({
1687
+ labels: {
1688
+ title: "Dynamic Lists",
1689
+ description: "Reusable list and grid schemas.",
1690
+ searchPlaceholder: "Search lists...",
1691
+ emptyTitle: "No lists",
1692
+ emptyDescription: "Create your first dynamic list.",
1693
+ addLabel: "Add list",
1694
+ editLabel: "Edit",
1695
+ replicateLabel: "Replicate",
1696
+ deleteLabel: "Delete",
1697
+ runtimeLabel: "Open",
1698
+ deleteConfirm: (entity) => `Delete ${entity.title}?`,
1699
+ replicatePrompt: () => "New list title",
1700
+ replicateDefaultTitle: (entity) => `${entity.title} copy`
1701
+ },
1702
+ createHref: newListPath,
1703
+ editHref: (entity) => editListPath(entity.id),
1704
+ runtimeHref: (entity) => runtimeListPath(entity.id),
1705
+ getDetail: detail,
1706
+ buildQuery: (state) => defaultQuery(state),
1707
+ hooks: {
1708
+ useEntities: (query) => hooks.useBuilderLists(query),
1709
+ useDelete: hooks.useDeleteBuilderList,
1710
+ useReplicate: hooks.useReplicateBuilderList
1711
+ }
1712
+ });
1713
+ const AdminViewsPage = createBuilderDefaultEntityManagerComponent({
1714
+ labels: {
1715
+ title: "Dynamic Views",
1716
+ description: "Runtime screens composed from form and list schemas.",
1717
+ searchPlaceholder: "Search views...",
1718
+ emptyTitle: "No views",
1719
+ emptyDescription: "Create a dynamic view after preparing a form and list.",
1720
+ addLabel: "Add view",
1721
+ editLabel: "Edit",
1722
+ replicateLabel: "Replicate",
1723
+ deleteLabel: "Delete",
1724
+ runtimeLabel: "Open",
1725
+ deleteConfirm: (entity) => `Delete ${entity.title}?`,
1726
+ replicatePrompt: () => "New view title",
1727
+ replicateDefaultTitle: (entity) => `${entity.title} copy`
1728
+ },
1729
+ createHref: newViewPath,
1730
+ editHref: (entity) => editViewPath(entity.id),
1731
+ runtimeHref: (entity) => runtimeViewPath(entity.id),
1732
+ getDetail: detail,
1733
+ buildQuery: (state) => defaultQuery(state),
1734
+ hooks: {
1735
+ useEntities: (query) => hooks.useBuilderViews(query),
1736
+ useDelete: hooks.useDeleteBuilderView,
1737
+ useReplicate: hooks.useReplicateBuilderView
1738
+ }
1739
+ });
1740
+ return {
1741
+ AdminHomePage,
1742
+ AdminFormsPage,
1743
+ AdminNewFormPage: function BuilderAdminNewFormPage() {
1744
+ return /* @__PURE__ */ jsx5(FormEditorPage, {});
1745
+ },
1746
+ AdminEditFormPage: function BuilderAdminEditFormPage({ formId }) {
1747
+ return /* @__PURE__ */ jsx5(FormEditorPage, { formId });
1748
+ },
1749
+ AdminListsPage,
1750
+ AdminNewListPage: function BuilderAdminNewListPage() {
1751
+ return /* @__PURE__ */ jsx5(ListEditorPage, {});
1752
+ },
1753
+ AdminEditListPage: function BuilderAdminEditListPage({ listId }) {
1754
+ return /* @__PURE__ */ jsx5(ListEditorPage, { listId });
1755
+ },
1756
+ AdminViewsPage,
1757
+ AdminNewViewPage: function BuilderAdminNewViewPage() {
1758
+ return /* @__PURE__ */ jsx5(ViewEditorPage, {});
1759
+ },
1760
+ AdminEditViewPage: function BuilderAdminEditViewPage({ viewId }) {
1761
+ return /* @__PURE__ */ jsx5(ViewEditorPage, { viewId });
1762
+ },
1763
+ routes: {
1764
+ adminBasePath,
1765
+ formsPath,
1766
+ newFormPath,
1767
+ editFormPath,
1768
+ listsPath,
1769
+ newListPath,
1770
+ editListPath,
1771
+ viewsPath,
1772
+ newViewPath,
1773
+ editViewPath
1774
+ }
1775
+ };
1776
+ }
1777
+
438
1778
  // src/admin/BuilderEntityManager.tsx
439
- import { useCallback, useMemo, useState } from "react";
440
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1779
+ import { useCallback, useMemo as useMemo2, useState as useState2 } from "react";
1780
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
441
1781
  function createBuilderEntityManagerComponent(deps) {
442
1782
  return function BuilderEntityManager() {
443
- const [pendingDelete, setPendingDelete] = useState(null);
1783
+ const [pendingDelete, setPendingDelete] = useState2(null);
444
1784
  const state = deps.useDataTableState({ pageSize: 20 });
445
1785
  const query = deps.hooks.useEntities(state.query);
446
1786
  const remove = deps.hooks.useDelete();
447
1787
  const replicate = deps.hooks.useReplicate();
448
- const columns = useMemo(
1788
+ const columns = useMemo2(
449
1789
  () => deps.buildColumns({
450
1790
  onEdit: deps.navigateToEdit,
451
1791
  onReplicate: async (entity) => {
@@ -465,8 +1805,8 @@ function createBuilderEntityManagerComponent(deps) {
465
1805
  state,
466
1806
  getRowId: (row) => row.id
467
1807
  });
468
- return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
469
- /* @__PURE__ */ jsx2(
1808
+ return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
1809
+ /* @__PURE__ */ jsx6(
470
1810
  deps.DataGrid,
471
1811
  {
472
1812
  title: deps.labels.title,
@@ -477,10 +1817,10 @@ function createBuilderEntityManagerComponent(deps) {
477
1817
  emptyTitle: deps.labels.emptyTitle,
478
1818
  emptyDescription: deps.labels.emptyDescription,
479
1819
  onRowClick: deps.navigateToEdit,
480
- toolbarExtra: /* @__PURE__ */ jsx2(deps.AddButton, { href: deps.createHref, label: deps.labels.addLabel })
1820
+ toolbarExtra: /* @__PURE__ */ jsx6(deps.AddButton, { href: deps.createHref, label: deps.labels.addLabel })
481
1821
  }
482
1822
  ),
483
- /* @__PURE__ */ jsx2(
1823
+ /* @__PURE__ */ jsx6(
484
1824
  deps.DeleteDialog,
485
1825
  {
486
1826
  entity: pendingDelete,
@@ -500,9 +1840,9 @@ function createBuilderEntityManagerComponent(deps) {
500
1840
  }
501
1841
  function createBuilderEntityDialogManagerComponent(deps) {
502
1842
  return function BuilderEntityDialogManager() {
503
- const [editing, setEditing] = useState(null);
504
- const [isEditorOpen, setEditorOpen] = useState(false);
505
- const [pendingDelete, setPendingDelete] = useState(null);
1843
+ const [editing, setEditing] = useState2(null);
1844
+ const [isEditorOpen, setEditorOpen] = useState2(false);
1845
+ const [pendingDelete, setPendingDelete] = useState2(null);
506
1846
  const state = deps.useDataTableState({ pageSize: 20 });
507
1847
  const query = deps.hooks.useEntities(state.query);
508
1848
  const remove = deps.hooks.useDelete();
@@ -511,7 +1851,7 @@ function createBuilderEntityDialogManagerComponent(deps) {
511
1851
  setEditing(entity);
512
1852
  setEditorOpen(true);
513
1853
  }, []);
514
- const columns = useMemo(
1854
+ const columns = useMemo2(
515
1855
  () => deps.buildColumns({
516
1856
  onEdit: (entity) => openEditor(entity),
517
1857
  onReplicate: async (entity) => {
@@ -531,8 +1871,8 @@ function createBuilderEntityDialogManagerComponent(deps) {
531
1871
  state,
532
1872
  getRowId: (row) => row.id
533
1873
  });
534
- return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
535
- /* @__PURE__ */ jsx2(
1874
+ return /* @__PURE__ */ jsxs5("div", { className: "space-y-6", children: [
1875
+ /* @__PURE__ */ jsx6(
536
1876
  deps.DataGrid,
537
1877
  {
538
1878
  title: deps.labels.title,
@@ -543,10 +1883,10 @@ function createBuilderEntityDialogManagerComponent(deps) {
543
1883
  emptyTitle: deps.labels.emptyTitle,
544
1884
  emptyDescription: deps.labels.emptyDescription,
545
1885
  onRowClick: openEditor,
546
- toolbarExtra: /* @__PURE__ */ jsx2(deps.AddButton, { label: deps.labels.addLabel, onAdd: () => openEditor(null) })
1886
+ toolbarExtra: /* @__PURE__ */ jsx6(deps.AddButton, { label: deps.labels.addLabel, onAdd: () => openEditor(null) })
547
1887
  }
548
1888
  ),
549
- /* @__PURE__ */ jsx2(
1889
+ /* @__PURE__ */ jsx6(
550
1890
  deps.EditorDialog,
551
1891
  {
552
1892
  open: isEditorOpen,
@@ -554,7 +1894,7 @@ function createBuilderEntityDialogManagerComponent(deps) {
554
1894
  onClose: () => setEditorOpen(false)
555
1895
  }
556
1896
  ),
557
- /* @__PURE__ */ jsx2(
1897
+ /* @__PURE__ */ jsx6(
558
1898
  deps.DeleteDialog,
559
1899
  {
560
1900
  entity: pendingDelete,
@@ -574,9 +1914,9 @@ function createBuilderEntityDialogManagerComponent(deps) {
574
1914
  }
575
1915
 
576
1916
  // src/admin/BuilderViewDialog.tsx
577
- import { useEffect as useEffect2 } from "react";
578
- import { FormProvider as FormProvider2, useForm as useForm2 } from "react-hook-form";
579
- import { jsx as jsx3 } from "react/jsx-runtime";
1917
+ import { useEffect as useEffect3 } from "react";
1918
+ import { FormProvider as FormProvider2, useForm as useForm3 } from "react-hook-form";
1919
+ import { jsx as jsx7 } from "react/jsx-runtime";
580
1920
  function createBuilderViewDialogComponent(deps) {
581
1921
  return function BuilderViewDialog({
582
1922
  open,
@@ -587,11 +1927,11 @@ function createBuilderViewDialogComponent(deps) {
587
1927
  onSave,
588
1928
  isSaving
589
1929
  }) {
590
- const form = useForm2({
1930
+ const form = useForm3({
591
1931
  resolver: deps.resolver,
592
1932
  defaultValues: deps.emptyValues
593
1933
  });
594
- useEffect2(() => {
1934
+ useEffect3(() => {
595
1935
  if (!open) return;
596
1936
  form.reset(
597
1937
  builderViewEditorValuesFromEntity(editing, deps.emptyValues, deps.defaultPermission)
@@ -606,7 +1946,7 @@ function createBuilderViewDialogComponent(deps) {
606
1946
  deps.notifications.error(error);
607
1947
  }
608
1948
  });
609
- return /* @__PURE__ */ jsx3(deps.Shell, { open, editing, onClose, children: /* @__PURE__ */ jsx3(FormProvider2, { ...form, children: /* @__PURE__ */ jsx3("form", { onSubmit, noValidate: true, children: deps.Body({
1949
+ return /* @__PURE__ */ jsx7(deps.Shell, { open, editing, onClose, children: /* @__PURE__ */ jsx7(FormProvider2, { ...form, children: /* @__PURE__ */ jsx7("form", { onSubmit, noValidate: true, children: deps.Body({
610
1950
  form,
611
1951
  editing,
612
1952
  forms,
@@ -619,6 +1959,175 @@ function createBuilderViewDialogComponent(deps) {
619
1959
  };
620
1960
  }
621
1961
 
1962
+ // src/admin/formLayoutEditorState.ts
1963
+ import { useMemo as useMemo3 } from "react";
1964
+ import { useWatch as useWatch2 } from "react-hook-form";
1965
+ var builderFormLayoutDragDataType = "application/x-winu-builder-layout-field";
1966
+ function clampBuilderFormLayoutSpan(span, columns) {
1967
+ return Math.max(1, Math.min(columns, span));
1968
+ }
1969
+ function swapBuilderFormLayoutItems(items, from, to) {
1970
+ if (from < 0 || from >= items.length || to < 0 || to >= items.length) return items;
1971
+ const next = [...items];
1972
+ const item = next[from];
1973
+ next[from] = next[to];
1974
+ next[to] = item;
1975
+ return next;
1976
+ }
1977
+ function nextBuilderFormLayoutGroupId(groups) {
1978
+ let index = groups.length + 1;
1979
+ let id = `group${index}`;
1980
+ const ids = new Set(groups.map((group) => group.id));
1981
+ while (ids.has(id)) {
1982
+ index += 1;
1983
+ id = `group${index}`;
1984
+ }
1985
+ return id;
1986
+ }
1987
+ function serializeBuilderFormLayoutDragPayload(payload) {
1988
+ return JSON.stringify(payload);
1989
+ }
1990
+ function parseBuilderFormLayoutDragPayload(raw) {
1991
+ if (!raw) return null;
1992
+ try {
1993
+ const value = JSON.parse(raw);
1994
+ if (value.type === "palette" && typeof value.key === "string" && value.key) {
1995
+ return { type: value.type, key: value.key };
1996
+ }
1997
+ if (value.type === "layout" && typeof value.key === "string" && value.key && Number.isInteger(value.groupIndex) && Number.isInteger(value.fieldIndex) && (value.groupIndex ?? -1) >= 0 && (value.fieldIndex ?? -1) >= 0) {
1998
+ return {
1999
+ type: value.type,
2000
+ groupIndex: value.groupIndex,
2001
+ fieldIndex: value.fieldIndex,
2002
+ key: value.key
2003
+ };
2004
+ }
2005
+ return null;
2006
+ } catch {
2007
+ return null;
2008
+ }
2009
+ }
2010
+ function useBuilderFormLayoutEditor({ form, fields, subforms = [] }) {
2011
+ const layoutGroups = useWatch2({ control: form.control, name: "layoutGroups" }) ?? [];
2012
+ const layoutItems = useMemo3(
2013
+ () => [
2014
+ ...fields.map((field) => ({
2015
+ key: field.key,
2016
+ kind: "field",
2017
+ meta: field.type,
2018
+ span: builderFormEditorDefaultSpan(field)
2019
+ })),
2020
+ ...subforms.map((subform) => ({
2021
+ key: subform.key,
2022
+ kind: "subform",
2023
+ meta: "subform",
2024
+ span: 12
2025
+ }))
2026
+ ],
2027
+ [fields, subforms]
2028
+ );
2029
+ const assignedKeys = useMemo3(
2030
+ () => new Set(layoutGroups.flatMap((group) => group.fields.map((field) => field.key))),
2031
+ [layoutGroups]
2032
+ );
2033
+ const unassignedItems = useMemo3(
2034
+ () => layoutItems.filter((item) => !assignedKeys.has(item.key)),
2035
+ [assignedKeys, layoutItems]
2036
+ );
2037
+ const setGroups = (groups) => {
2038
+ form.setValue("layoutGroups", groups, { shouldDirty: true, shouldValidate: true });
2039
+ };
2040
+ const updateGroup = (groupIndex, group) => {
2041
+ setGroups(layoutGroups.map((item, index) => index === groupIndex ? group : item));
2042
+ };
2043
+ const updateGroupFields = (groupIndex, updater) => {
2044
+ const group = layoutGroups[groupIndex];
2045
+ if (!group) return;
2046
+ updateGroup(groupIndex, { ...group, fields: updater(group.fields) });
2047
+ };
2048
+ const addGroup = () => {
2049
+ setGroups([
2050
+ ...layoutGroups,
2051
+ {
2052
+ id: nextBuilderFormLayoutGroupId(layoutGroups),
2053
+ title: `Group ${layoutGroups.length + 1}`,
2054
+ columns: 12,
2055
+ fields: []
2056
+ }
2057
+ ]);
2058
+ };
2059
+ const addItemToNewGroup = (itemKey) => {
2060
+ if (assignedKeys.has(itemKey)) return;
2061
+ const item = layoutItems.find((candidate) => candidate.key === itemKey);
2062
+ if (!item) return;
2063
+ setGroups([
2064
+ ...layoutGroups,
2065
+ {
2066
+ id: nextBuilderFormLayoutGroupId(layoutGroups),
2067
+ title: layoutGroups.length === 0 ? "\u04AE\u043D\u0434\u0441\u044D\u043D" : `Group ${layoutGroups.length + 1}`,
2068
+ columns: 12,
2069
+ fields: [{ key: itemKey, span: item.span }]
2070
+ }
2071
+ ]);
2072
+ };
2073
+ const addItemToGroup = (groupIndex, itemKey, insertAt) => {
2074
+ if (assignedKeys.has(itemKey)) return;
2075
+ const item = layoutItems.find((candidate) => candidate.key === itemKey);
2076
+ const group = layoutGroups[groupIndex];
2077
+ if (!item || !group) return;
2078
+ const nextField = {
2079
+ key: itemKey,
2080
+ span: clampBuilderFormLayoutSpan(item.span, group.columns)
2081
+ };
2082
+ updateGroupFields(groupIndex, (groupFields) => {
2083
+ const next = [...groupFields];
2084
+ next.splice(insertAt ?? next.length, 0, nextField);
2085
+ return next;
2086
+ });
2087
+ };
2088
+ const moveLayoutField = (payload, targetGroupIndex, targetFieldIndex) => {
2089
+ const sourceGroup = layoutGroups[payload.groupIndex];
2090
+ const targetGroup = layoutGroups[targetGroupIndex];
2091
+ if (!sourceGroup || !targetGroup) return;
2092
+ const movingField = sourceGroup.fields[payload.fieldIndex];
2093
+ if (!movingField) return;
2094
+ const nextGroups = layoutGroups.map((group) => ({ ...group, fields: [...group.fields] }));
2095
+ nextGroups[payload.groupIndex].fields.splice(payload.fieldIndex, 1);
2096
+ let insertAt = targetFieldIndex ?? nextGroups[targetGroupIndex].fields.length;
2097
+ if (payload.groupIndex === targetGroupIndex && payload.fieldIndex < insertAt) {
2098
+ insertAt -= 1;
2099
+ }
2100
+ nextGroups[targetGroupIndex].fields.splice(insertAt, 0, {
2101
+ ...movingField,
2102
+ span: clampBuilderFormLayoutSpan(movingField.span, targetGroup.columns)
2103
+ });
2104
+ setGroups(nextGroups);
2105
+ };
2106
+ const applyDragPayload = (payload, targetGroupIndex, targetFieldIndex) => {
2107
+ if (!payload) return;
2108
+ if (payload.type === "palette") {
2109
+ addItemToGroup(targetGroupIndex, payload.key, targetFieldIndex);
2110
+ return;
2111
+ }
2112
+ moveLayoutField(payload, targetGroupIndex, targetFieldIndex);
2113
+ };
2114
+ const resetDefaultLayout = () => setGroups(builderFormEditorDefaultLayoutGroups(fields, subforms));
2115
+ return {
2116
+ assignedKeys,
2117
+ layoutGroups,
2118
+ layoutItems,
2119
+ unassignedItems,
2120
+ addGroup,
2121
+ addItemToGroup,
2122
+ addItemToNewGroup,
2123
+ applyDragPayload,
2124
+ resetDefaultLayout,
2125
+ setGroups,
2126
+ updateGroup,
2127
+ updateGroupFields
2128
+ };
2129
+ }
2130
+
622
2131
  // src/api/createBuilderApiClient.ts
623
2132
  function queryParams(query) {
624
2133
  return { ...query };
@@ -709,8 +2218,8 @@ function createBuilderApiClient(transport) {
709
2218
  }
710
2219
 
711
2220
  // src/components/DynamicForm.tsx
712
- import { useMemo as useMemo2 } from "react";
713
- import { FormProvider as FormProvider3, useForm as useForm3 } from "react-hook-form";
2221
+ import { useMemo as useMemo4 } from "react";
2222
+ import { FormProvider as FormProvider3, useForm as useForm4 } from "react-hook-form";
714
2223
 
715
2224
  // src/runtime/runtimeUtils.ts
716
2225
  function emptyFieldValue(field) {
@@ -739,16 +2248,16 @@ function formatBuilderRuntimeValue(value, locale = "mn-MN") {
739
2248
  }
740
2249
 
741
2250
  // src/components/DynamicForm.tsx
742
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
2251
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
743
2252
  function createDynamicFormComponent(deps) {
744
2253
  return function DynamicForm({ formId }) {
745
2254
  const query = deps.hooks.useRuntimeBuilderForm(formId);
746
2255
  const save = deps.hooks.useSaveRuntimeBuilderFormEntry(formId);
747
- const formValues = useMemo2(
2256
+ const formValues = useMemo4(
748
2257
  () => query.data ? createBuilderFormDefaultValues(query.data.schema) : void 0,
749
2258
  [query.data]
750
2259
  );
751
- const form = useForm3({
2260
+ const form = useForm4({
752
2261
  defaultValues: createBuilderFormDefaultValues(query.data?.schema),
753
2262
  values: formValues
754
2263
  });
@@ -762,7 +2271,7 @@ function createDynamicFormComponent(deps) {
762
2271
  }
763
2272
  });
764
2273
  if (query.isError) {
765
- return /* @__PURE__ */ jsx4(
2274
+ return /* @__PURE__ */ jsx8(
766
2275
  deps.ErrorState,
767
2276
  {
768
2277
  title: "Form \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
@@ -771,22 +2280,22 @@ function createDynamicFormComponent(deps) {
771
2280
  );
772
2281
  }
773
2282
  if (!query.data) return null;
774
- return /* @__PURE__ */ jsx4(deps.FormShell, { title: query.data.title, children: /* @__PURE__ */ jsx4(FormProvider3, { ...form, children: /* @__PURE__ */ jsxs2("form", { onSubmit, noValidate: true, className: "space-y-6", children: [
775
- /* @__PURE__ */ jsx4(deps.FormFields, { formId, schema: query.data.schema, namePrefix: "values" }),
776
- /* @__PURE__ */ jsx4(deps.SubmitButton, { isSaving: save.isPending })
2283
+ return /* @__PURE__ */ jsx8(deps.FormShell, { title: query.data.title, children: /* @__PURE__ */ jsx8(FormProvider3, { ...form, children: /* @__PURE__ */ jsxs6("form", { onSubmit, noValidate: true, className: "space-y-6", children: [
2284
+ /* @__PURE__ */ jsx8(deps.FormFields, { formId, schema: query.data.schema, namePrefix: "values" }),
2285
+ /* @__PURE__ */ jsx8(deps.SubmitButton, { isSaving: save.isPending })
777
2286
  ] }) }) });
778
2287
  };
779
2288
  }
780
2289
 
781
2290
  // src/components/DynamicList.tsx
782
- import { useMemo as useMemo3 } from "react";
783
- import { jsx as jsx5 } from "react/jsx-runtime";
2291
+ import { useMemo as useMemo5 } from "react";
2292
+ import { jsx as jsx9 } from "react/jsx-runtime";
784
2293
  function createDynamicListComponent(deps) {
785
2294
  return function DynamicList({ listId }) {
786
2295
  const query = deps.hooks.useRuntimeBuilderList(listId);
787
2296
  const state = deps.useDataTableState({ pageSize: 20 });
788
2297
  const entriesQuery = deps.hooks.useRuntimeBuilderListEntries(listId, state.query);
789
- const columns = useMemo3(() => query.data ? deps.buildColumns(query.data) : [], [query.data]);
2298
+ const columns = useMemo5(() => query.data ? deps.buildColumns(query.data) : [], [query.data]);
790
2299
  const entries = entriesQuery.data?.items ?? [];
791
2300
  const controller = deps.useDataTable({
792
2301
  columns,
@@ -796,7 +2305,7 @@ function createDynamicListComponent(deps) {
796
2305
  getRowId: (row) => row.id
797
2306
  });
798
2307
  if (query.isError) {
799
- return /* @__PURE__ */ jsx5(
2308
+ return /* @__PURE__ */ jsx9(
800
2309
  deps.ErrorState,
801
2310
  {
802
2311
  title: "List \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
@@ -804,7 +2313,7 @@ function createDynamicListComponent(deps) {
804
2313
  }
805
2314
  );
806
2315
  }
807
- return /* @__PURE__ */ jsx5(
2316
+ return /* @__PURE__ */ jsx9(
808
2317
  deps.DataGrid,
809
2318
  {
810
2319
  title: query.data?.title ?? "Dynamic List",
@@ -820,20 +2329,20 @@ function createDynamicListComponent(deps) {
820
2329
  }
821
2330
 
822
2331
  // src/components/DynamicView.tsx
823
- import { useMemo as useMemo4, useState as useState2 } from "react";
824
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
2332
+ import { useMemo as useMemo6, useState as useState3 } from "react";
2333
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
825
2334
  function createDynamicViewComponent(deps) {
826
2335
  return function DynamicView({ viewId }) {
827
- const [editing, setEditing] = useState2(null);
828
- const [isDialogOpen, setDialogOpen] = useState2(false);
829
- const [pendingDelete, setPendingDelete] = useState2(null);
2336
+ const [editing, setEditing] = useState3(null);
2337
+ const [isDialogOpen, setDialogOpen] = useState3(false);
2338
+ const [pendingDelete, setPendingDelete] = useState3(null);
830
2339
  const viewQuery = deps.hooks.useRuntimeBuilderView(viewId);
831
2340
  const state = deps.useDataTableState({ pageSize: 20 });
832
2341
  const entriesQuery = deps.hooks.useBuilderViewEntries(viewId, state.query);
833
2342
  const save = deps.hooks.useSaveBuilderViewEntry(viewId);
834
2343
  const remove = deps.hooks.useDeleteBuilderViewEntry(viewId);
835
2344
  const view = viewQuery.data;
836
- const columns = useMemo4(
2345
+ const columns = useMemo6(
837
2346
  () => view ? deps.buildColumns(view, {
838
2347
  onEdit: (entry) => {
839
2348
  setEditing(entry);
@@ -851,7 +2360,7 @@ function createDynamicViewComponent(deps) {
851
2360
  getRowId: (row) => row.id
852
2361
  });
853
2362
  if (viewQuery.isError) {
854
- return /* @__PURE__ */ jsx6(
2363
+ return /* @__PURE__ */ jsx10(
855
2364
  deps.ErrorState,
856
2365
  {
857
2366
  title: "View \u043D\u044D\u044D\u0433\u0434\u0441\u044D\u043D\u0433\u04AF\u0439",
@@ -859,8 +2368,8 @@ function createDynamicViewComponent(deps) {
859
2368
  }
860
2369
  );
861
2370
  }
862
- return /* @__PURE__ */ jsxs3("div", { className: "space-y-6", children: [
863
- /* @__PURE__ */ jsx6(
2371
+ return /* @__PURE__ */ jsxs7("div", { className: "space-y-6", children: [
2372
+ /* @__PURE__ */ jsx10(
864
2373
  deps.DataGrid,
865
2374
  {
866
2375
  title: view?.title ?? "Dynamic View",
@@ -874,7 +2383,7 @@ function createDynamicViewComponent(deps) {
874
2383
  setEditing(entry);
875
2384
  setDialogOpen(true);
876
2385
  },
877
- toolbarExtra: /* @__PURE__ */ jsx6(
2386
+ toolbarExtra: /* @__PURE__ */ jsx10(
878
2387
  deps.AddButton,
879
2388
  {
880
2389
  disabled: !view?.form,
@@ -886,7 +2395,7 @@ function createDynamicViewComponent(deps) {
886
2395
  )
887
2396
  }
888
2397
  ),
889
- view ? /* @__PURE__ */ jsx6(
2398
+ view ? /* @__PURE__ */ jsx10(
890
2399
  deps.EntryDialog,
891
2400
  {
892
2401
  open: isDialogOpen,
@@ -897,7 +2406,7 @@ function createDynamicViewComponent(deps) {
897
2406
  isSaving: save.isPending
898
2407
  }
899
2408
  ) : null,
900
- /* @__PURE__ */ jsx6(
2409
+ /* @__PURE__ */ jsx10(
901
2410
  deps.DeleteDialog,
902
2411
  {
903
2412
  entry: pendingDelete,
@@ -915,9 +2424,9 @@ function createDynamicViewComponent(deps) {
915
2424
  }
916
2425
 
917
2426
  // src/components/RuntimeEntryDialog.tsx
918
- import { useEffect as useEffect3, useMemo as useMemo5, useState as useState3 } from "react";
919
- import { FormProvider as FormProvider4, useForm as useForm4 } from "react-hook-form";
920
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2427
+ import { useEffect as useEffect4, useMemo as useMemo7, useState as useState4 } from "react";
2428
+ import { FormProvider as FormProvider4, useForm as useForm5 } from "react-hook-form";
2429
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
921
2430
  function isDbTableSource(source) {
922
2431
  return source?.type === "dbTable" && "tableName" in source;
923
2432
  }
@@ -950,19 +2459,19 @@ function createRuntimeEntryDialogComponent(deps) {
950
2459
  onSave,
951
2460
  isSaving
952
2461
  }) {
953
- const [draftSubforms, setDraftSubforms] = useState3({});
2462
+ const [draftSubforms, setDraftSubforms] = useState4({});
954
2463
  const compositeCreate = deps.useCreateCompositeEntry?.(view.id);
955
2464
  const compositeUpdate = deps.useUpdateCompositeEntry?.(view.id);
956
- const form = useForm4({
2465
+ const form = useForm5({
957
2466
  defaultValues: createBuilderEntryDefaultValues(view, editing),
958
2467
  values: open ? createBuilderEntryDefaultValues(view, editing) : void 0
959
2468
  });
960
2469
  const mainTableName = runtimeViewTableName(view);
961
- const hasDraftRows = useMemo5(
2470
+ const hasDraftRows = useMemo7(
962
2471
  () => Object.values(draftSubforms).some((draft) => draft.rows.length > 0),
963
2472
  [draftSubforms]
964
2473
  );
965
- useEffect3(() => {
2474
+ useEffect4(() => {
966
2475
  if (open) setDraftSubforms({});
967
2476
  }, [open]);
968
2477
  const onSubmit = form.handleSubmit(async (values) => {
@@ -1014,7 +2523,7 @@ function createRuntimeEntryDialogComponent(deps) {
1014
2523
  const saving = isSaving || Boolean(compositeCreate?.isPending || compositeUpdate?.isPending);
1015
2524
  const extraItems = deps.SubformField && view.form?.schema.subforms?.length ? view.form.schema.subforms.map((subform) => ({
1016
2525
  key: subform.key,
1017
- render: () => deps.SubformField ? /* @__PURE__ */ jsx7(
2526
+ render: () => deps.SubformField ? /* @__PURE__ */ jsx11(
1018
2527
  deps.SubformField,
1019
2528
  {
1020
2529
  subform,
@@ -1029,15 +2538,15 @@ function createRuntimeEntryDialogComponent(deps) {
1029
2538
  }
1030
2539
  ) : null
1031
2540
  })) : void 0;
1032
- return /* @__PURE__ */ jsx7(
2541
+ return /* @__PURE__ */ jsx11(
1033
2542
  deps.DialogShell,
1034
2543
  {
1035
2544
  open,
1036
2545
  title: editing ? "\u041C\u04E9\u0440 \u0437\u0430\u0441\u0430\u0445" : "\u041C\u04E9\u0440 \u043D\u044D\u043C\u044D\u0445",
1037
2546
  description: view.title,
1038
2547
  onClose,
1039
- children: /* @__PURE__ */ jsx7(FormProvider4, { ...form, children: /* @__PURE__ */ jsxs4("form", { onSubmit, noValidate: true, className: deps.formClassName, children: [
1040
- view.form ? /* @__PURE__ */ jsx7(
2548
+ children: /* @__PURE__ */ jsx11(FormProvider4, { ...form, children: /* @__PURE__ */ jsxs8("form", { onSubmit, noValidate: true, className: deps.formClassName, children: [
2549
+ view.form ? /* @__PURE__ */ jsx11(
1041
2550
  deps.FormFields,
1042
2551
  {
1043
2552
  formId: view.form.id,
@@ -1048,7 +2557,7 @@ function createRuntimeEntryDialogComponent(deps) {
1048
2557
  extraItems
1049
2558
  }
1050
2559
  ) : null,
1051
- /* @__PURE__ */ jsx7(deps.Actions, { isSaving: saving, onClose })
2560
+ /* @__PURE__ */ jsx11(deps.Actions, { isSaving: saving, onClose })
1052
2561
  ] }) })
1053
2562
  }
1054
2563
  );
@@ -1056,9 +2565,9 @@ function createRuntimeEntryDialogComponent(deps) {
1056
2565
  }
1057
2566
 
1058
2567
  // src/components/RuntimeSubformField.tsx
1059
- import { useEffect as useEffect4, useMemo as useMemo6, useRef, useState as useState4 } from "react";
1060
- import { FormProvider as FormProvider5, useForm as useForm5 } from "react-hook-form";
1061
- import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2568
+ import { useEffect as useEffect5, useMemo as useMemo8, useRef, useState as useState5 } from "react";
2569
+ import { FormProvider as FormProvider5, useForm as useForm6 } from "react-hook-form";
2570
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1062
2571
 
1063
2572
  // src/hooks/createBuilderHooks.ts
1064
2573
  import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
@@ -1075,6 +2584,7 @@ function createBuilderKeys() {
1075
2584
  listOptions: () => [...builderKeys.lists, "options"],
1076
2585
  views: ["builder", "views"],
1077
2586
  viewList: (query) => [...builderKeys.views, "list", query],
2587
+ view: (id) => [...builderKeys.views, "detail", id],
1078
2588
  runtimeForm: (id) => ["builder", "runtime", "form", id],
1079
2589
  runtimeFieldOptions: (formId, fieldKey, query) => [...builderKeys.runtimeForm(formId), "fields", fieldKey, "options", query],
1080
2590
  runtimeFormEntries: (id) => [...builderKeys.runtimeForm(id), "entries"],
@@ -1193,6 +2703,13 @@ function createBuilderHooks(client) {
1193
2703
  placeholderData: keepPreviousData
1194
2704
  });
1195
2705
  }
2706
+ function useBuilderView(id) {
2707
+ return useQuery({
2708
+ queryKey: builderKeys.view(id ?? ""),
2709
+ queryFn: () => client.getBuilderView(id ?? ""),
2710
+ enabled: Boolean(id)
2711
+ });
2712
+ }
1196
2713
  function useSaveBuilderView() {
1197
2714
  const queryClient = useQueryClient();
1198
2715
  return useMutation({
@@ -1333,6 +2850,7 @@ function createBuilderHooks(client) {
1333
2850
  useBuilderListOptions,
1334
2851
  useBuilderLists,
1335
2852
  useBuilderViewEntries,
2853
+ useBuilderView,
1336
2854
  useBuilderViews,
1337
2855
  useDeleteBuilderForm,
1338
2856
  useDeleteBuilderList,
@@ -1357,10 +2875,47 @@ function createBuilderHooks(client) {
1357
2875
  };
1358
2876
  }
1359
2877
 
2878
+ // src/integration/createBuilderIntegration.ts
2879
+ function normalizeBasePath(path) {
2880
+ const trimmed = path.trim().replace(/\/+$/g, "");
2881
+ if (!trimmed) return "/builder";
2882
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
2883
+ }
2884
+ function withQuery(path, query) {
2885
+ const params = new URLSearchParams();
2886
+ for (const [key, value] of Object.entries(query)) {
2887
+ if (value) params.set(key, value);
2888
+ }
2889
+ const queryString = params.toString();
2890
+ return queryString ? `${path}?${queryString}` : path;
2891
+ }
2892
+ function createBuilderIntegration(config) {
2893
+ const adminBasePath = normalizeBasePath(config.adminBasePath ?? "/admin/dev/builder");
2894
+ const api = createBuilderApiClient(config.transport);
2895
+ const hooks = createBuilderHooks(api);
2896
+ const formsPath = `${adminBasePath}/forms`;
2897
+ const listsPath = `${adminBasePath}/lists`;
2898
+ return {
2899
+ api,
2900
+ hooks,
2901
+ routes: {
2902
+ adminBasePath,
2903
+ adminHomePath: adminBasePath,
2904
+ formsPath,
2905
+ newFormPath: `${formsPath}/new`,
2906
+ editFormPath: (id) => withQuery(`${formsPath}/edit`, { id }),
2907
+ listsPath,
2908
+ newListPath: `${listsPath}/new`,
2909
+ editListPath: (id) => withQuery(`${listsPath}/edit`, { id }),
2910
+ viewsPath: `${adminBasePath}/views`
2911
+ }
2912
+ };
2913
+ }
2914
+
1360
2915
  // src/index.ts
1361
2916
  var builderUiPackage = {
1362
2917
  name: "@duke333/builder-ui",
1363
- version: "0.1.0"
2918
+ version: "0.1.1"
1364
2919
  };
1365
2920
  export {
1366
2921
  BUILDER_EDITOR_NONE_VALUE,
@@ -1371,19 +2926,27 @@ export {
1371
2926
  builderFormEditorFieldsFromTable,
1372
2927
  builderFormEditorInputFromValues,
1373
2928
  builderFormEditorValuesFromEntity,
2929
+ builderFormLayoutDragDataType,
1374
2930
  builderListEditorColumnsFromTable,
1375
2931
  builderListEditorInputFromValues,
1376
2932
  builderListEditorValuesFromEntity,
1377
2933
  builderUiPackage,
1378
2934
  builderViewEditorInputFromValues,
1379
2935
  builderViewEditorValuesFromEntity,
2936
+ clampBuilderFormLayoutSpan,
2937
+ createBuilderAdminPages,
1380
2938
  createBuilderApiClient,
2939
+ createBuilderDefaultEntityManagerComponent,
2940
+ createBuilderDefaultFormEditorBody,
2941
+ createBuilderDefaultListEditorBody,
2942
+ createBuilderDefaultViewEditorPage,
1381
2943
  createBuilderEntityDialogManagerComponent,
1382
2944
  createBuilderEntityManagerComponent,
1383
2945
  createBuilderEntryDefaultValues,
1384
2946
  createBuilderFormDefaultValues,
1385
2947
  createBuilderFormEditorPageComponent,
1386
2948
  createBuilderHooks,
2949
+ createBuilderIntegration,
1387
2950
  createBuilderKeys,
1388
2951
  createBuilderListEditorPageComponent,
1389
2952
  createBuilderViewDialogComponent,
@@ -1392,6 +2955,11 @@ export {
1392
2955
  createDynamicViewComponent,
1393
2956
  createRuntimeEntryDialogComponent,
1394
2957
  formatBuilderRuntimeValue,
1395
- getBuilderEditorTriggerRoute
2958
+ getBuilderEditorTriggerRoute,
2959
+ nextBuilderFormLayoutGroupId,
2960
+ parseBuilderFormLayoutDragPayload,
2961
+ serializeBuilderFormLayoutDragPayload,
2962
+ swapBuilderFormLayoutItems,
2963
+ useBuilderFormLayoutEditor
1396
2964
  };
1397
2965
  //# sourceMappingURL=index.js.map