@enerjisaformlibrary/formbuilder-react 1.0.8 → 1.0.22

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/index.js CHANGED
@@ -8104,6 +8104,25 @@ const AlignLeft = createLucideIcon("AlignLeft", [
8104
8104
  */
8105
8105
 
8106
8106
 
8107
+ const BookOpen = createLucideIcon("BookOpen", [
8108
+ ["path", { d: "M12 7v14", key: "1akyts" }],
8109
+ [
8110
+ "path",
8111
+ {
8112
+ d: "M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",
8113
+ key: "ruj8y"
8114
+ }
8115
+ ]
8116
+ ]);
8117
+
8118
+ /**
8119
+ * @license lucide-react v0.453.0 - ISC
8120
+ *
8121
+ * This source code is licensed under the ISC license.
8122
+ * See the LICENSE file in the root directory of this source tree.
8123
+ */
8124
+
8125
+
8107
8126
  const Box = createLucideIcon("Box", [
8108
8127
  [
8109
8128
  "path",
@@ -9414,16 +9433,26 @@ const createEmptyForm = () => ({
9414
9433
  createdAt: new Date().toISOString(),
9415
9434
  updatedAt: new Date().toISOString(),
9416
9435
  });
9436
+ const MAX_HISTORY = 50;
9437
+ const pushToHistory = (state) => {
9438
+ const newHistory = state.history.slice(0, state.historyIndex + 1);
9439
+ newHistory.push(JSON.parse(JSON.stringify(state.form)));
9440
+ if (newHistory.length > MAX_HISTORY) {
9441
+ newHistory.shift();
9442
+ }
9443
+ return { history: newHistory, historyIndex: newHistory.length - 1 };
9444
+ };
9445
+ const initialForm = createDemoForm();
9417
9446
  const useFormStore = create((set, get) => ({
9418
- form: createDemoForm(),
9447
+ form: initialForm,
9419
9448
  selection: { type: null },
9420
9449
  isPreviewMode: false,
9421
9450
  currentStepIndex: 0,
9422
9451
  currentLanguage: 'en',
9423
9452
  formValues: {},
9424
9453
  canvasWidth: 'full',
9425
- history: [],
9426
- historyIndex: -1,
9454
+ history: [JSON.parse(JSON.stringify(initialForm))],
9455
+ historyIndex: 0,
9427
9456
  setCanvasWidth: (width) => set({ canvasWidth: width }),
9428
9457
  undo: () => {
9429
9458
  const state = get();
@@ -9460,75 +9489,87 @@ const useFormStore = create((set, get) => ({
9460
9489
  selection: { type: null },
9461
9490
  formValues: {},
9462
9491
  })),
9463
- clearForm: () => set({
9464
- form: createEmptyForm(),
9465
- selection: { type: null },
9466
- currentStepIndex: 0,
9467
- formValues: {},
9468
- }),
9492
+ clearForm: () => {
9493
+ const newForm = createEmptyForm();
9494
+ return set({
9495
+ form: newForm,
9496
+ selection: { type: null },
9497
+ currentStepIndex: 0,
9498
+ formValues: {},
9499
+ history: [JSON.parse(JSON.stringify(newForm))],
9500
+ historyIndex: 0,
9501
+ });
9502
+ },
9469
9503
  loadForm: (form) => set({
9470
9504
  form,
9471
9505
  selection: { type: null },
9472
9506
  currentStepIndex: 0,
9473
9507
  formValues: {},
9508
+ history: [JSON.parse(JSON.stringify(form))],
9509
+ historyIndex: 0,
9474
9510
  }),
9475
9511
  addRow: (columns = 1, stepId) => set((state) => {
9476
9512
  const newRow = createEmptyRow(columns);
9513
+ let newForm;
9477
9514
  if (state.form.isMultiStep && state.form.steps?.length) {
9478
9515
  const targetStepId = stepId || state.form.steps[state.currentStepIndex]?.id;
9479
- return {
9480
- form: {
9481
- ...state.form,
9482
- steps: state.form.steps.map(s => s.id === targetStepId ? { ...s, rows: [...s.rows, newRow] } : s),
9483
- updatedAt: new Date().toISOString(),
9484
- },
9516
+ newForm = {
9517
+ ...state.form,
9518
+ steps: state.form.steps.map(s => s.id === targetStepId ? { ...s, rows: [...s.rows, newRow] } : s),
9519
+ updatedAt: new Date().toISOString(),
9485
9520
  };
9486
9521
  }
9487
- return {
9488
- form: {
9522
+ else {
9523
+ newForm = {
9489
9524
  ...state.form,
9490
9525
  rows: [...state.form.rows, newRow],
9491
9526
  updatedAt: new Date().toISOString(),
9492
- },
9493
- };
9527
+ };
9528
+ }
9529
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9530
+ return { form: newForm, ...historyUpdate };
9494
9531
  }),
9495
9532
  updateRow: (rowId, updates) => set((state) => {
9496
9533
  const updateRows = (rows) => rows.map((row) => (row.id === rowId ? { ...row, ...updates } : row));
9534
+ let newForm;
9497
9535
  if (state.form.isMultiStep && state.form.steps?.length) {
9498
- return {
9499
- form: {
9500
- ...state.form,
9501
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9502
- updatedAt: new Date().toISOString(),
9503
- },
9536
+ newForm = {
9537
+ ...state.form,
9538
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9539
+ updatedAt: new Date().toISOString(),
9504
9540
  };
9505
9541
  }
9506
- return {
9507
- form: {
9542
+ else {
9543
+ newForm = {
9508
9544
  ...state.form,
9509
9545
  rows: updateRows(state.form.rows),
9510
9546
  updatedAt: new Date().toISOString(),
9511
- },
9512
- };
9547
+ };
9548
+ }
9549
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9550
+ return { form: newForm, ...historyUpdate };
9513
9551
  }),
9514
9552
  deleteRow: (rowId) => set((state) => {
9515
9553
  const filterRows = (rows) => rows.filter((row) => row.id !== rowId);
9554
+ let newForm;
9516
9555
  if (state.form.isMultiStep && state.form.steps?.length) {
9517
- return {
9518
- form: {
9519
- ...state.form,
9520
- steps: state.form.steps.map(s => ({ ...s, rows: filterRows(s.rows) })),
9521
- updatedAt: new Date().toISOString(),
9522
- },
9523
- selection: state.selection.rowId === rowId ? { type: null } : state.selection,
9556
+ newForm = {
9557
+ ...state.form,
9558
+ steps: state.form.steps.map(s => ({ ...s, rows: filterRows(s.rows) })),
9559
+ updatedAt: new Date().toISOString(),
9524
9560
  };
9525
9561
  }
9526
- return {
9527
- form: {
9562
+ else {
9563
+ newForm = {
9528
9564
  ...state.form,
9529
9565
  rows: filterRows(state.form.rows),
9530
9566
  updatedAt: new Date().toISOString(),
9531
- },
9567
+ };
9568
+ }
9569
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9570
+ return {
9571
+ form: newForm,
9572
+ ...historyUpdate,
9532
9573
  selection: state.selection.rowId === rowId ? { type: null } : state.selection,
9533
9574
  };
9534
9575
  }),
@@ -9539,18 +9580,19 @@ const useFormStore = create((set, get) => ({
9539
9580
  newRows.splice(toIndex, 0, removed);
9540
9581
  return newRows;
9541
9582
  };
9583
+ let newForm;
9542
9584
  if (state.form.isMultiStep && stepId) {
9543
- return {
9544
- form: {
9545
- ...state.form,
9546
- steps: state.form.steps?.map(s => s.id === stepId ? { ...s, rows: moveInRows(s.rows) } : s),
9547
- updatedAt: new Date().toISOString(),
9548
- },
9585
+ newForm = {
9586
+ ...state.form,
9587
+ steps: state.form.steps?.map(s => s.id === stepId ? { ...s, rows: moveInRows(s.rows) } : s),
9588
+ updatedAt: new Date().toISOString(),
9549
9589
  };
9550
9590
  }
9551
- return {
9552
- form: { ...state.form, rows: moveInRows(state.form.rows) },
9553
- };
9591
+ else {
9592
+ newForm = { ...state.form, rows: moveInRows(state.form.rows), updatedAt: new Date().toISOString() };
9593
+ }
9594
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9595
+ return { form: newForm, ...historyUpdate };
9554
9596
  }),
9555
9597
  addColumn: (rowId) => set((state) => {
9556
9598
  const updateRows = (rows) => rows.map((row) => {
@@ -9566,22 +9608,23 @@ const useFormStore = create((set, get) => ({
9566
9608
  ],
9567
9609
  };
9568
9610
  });
9611
+ let newForm;
9569
9612
  if (state.form.isMultiStep && state.form.steps?.length) {
9570
- return {
9571
- form: {
9572
- ...state.form,
9573
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9574
- updatedAt: new Date().toISOString(),
9575
- },
9613
+ newForm = {
9614
+ ...state.form,
9615
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9616
+ updatedAt: new Date().toISOString(),
9576
9617
  };
9577
9618
  }
9578
- return {
9579
- form: {
9619
+ else {
9620
+ newForm = {
9580
9621
  ...state.form,
9581
9622
  rows: updateRows(state.form.rows),
9582
9623
  updatedAt: new Date().toISOString(),
9583
- },
9584
- };
9624
+ };
9625
+ }
9626
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9627
+ return { form: newForm, ...historyUpdate };
9585
9628
  }),
9586
9629
  updateColumn: (rowId, columnId, updates) => set((state) => {
9587
9630
  const updateRows = (rows) => rows.map((row) => row.id === rowId
@@ -9590,22 +9633,23 @@ const useFormStore = create((set, get) => ({
9590
9633
  columns: row.columns.map((col) => col.id === columnId ? { ...col, ...updates } : col),
9591
9634
  }
9592
9635
  : row);
9636
+ let newForm;
9593
9637
  if (state.form.isMultiStep && state.form.steps?.length) {
9594
- return {
9595
- form: {
9596
- ...state.form,
9597
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9598
- updatedAt: new Date().toISOString(),
9599
- },
9638
+ newForm = {
9639
+ ...state.form,
9640
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9641
+ updatedAt: new Date().toISOString(),
9600
9642
  };
9601
9643
  }
9602
- return {
9603
- form: {
9644
+ else {
9645
+ newForm = {
9604
9646
  ...state.form,
9605
9647
  rows: updateRows(state.form.rows),
9606
9648
  updatedAt: new Date().toISOString(),
9607
- },
9608
- };
9649
+ };
9650
+ }
9651
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9652
+ return { form: newForm, ...historyUpdate };
9609
9653
  }),
9610
9654
  deleteColumn: (rowId, columnId) => set((state) => {
9611
9655
  const updateRows = (rows) => rows.map((row) => {
@@ -9620,22 +9664,25 @@ const useFormStore = create((set, get) => ({
9620
9664
  columns: newColumns.map((col) => ({ ...col, width })),
9621
9665
  };
9622
9666
  });
9667
+ let newForm;
9623
9668
  if (state.form.isMultiStep && state.form.steps?.length) {
9624
- return {
9625
- form: {
9626
- ...state.form,
9627
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9628
- updatedAt: new Date().toISOString(),
9629
- },
9630
- selection: state.selection.columnId === columnId ? { type: null } : state.selection,
9669
+ newForm = {
9670
+ ...state.form,
9671
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9672
+ updatedAt: new Date().toISOString(),
9631
9673
  };
9632
9674
  }
9633
- return {
9634
- form: {
9675
+ else {
9676
+ newForm = {
9635
9677
  ...state.form,
9636
9678
  rows: updateRows(state.form.rows),
9637
9679
  updatedAt: new Date().toISOString(),
9638
- },
9680
+ };
9681
+ }
9682
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9683
+ return {
9684
+ form: newForm,
9685
+ ...historyUpdate,
9639
9686
  selection: state.selection.columnId === columnId ? { type: null } : state.selection,
9640
9687
  };
9641
9688
  }),
@@ -9664,22 +9711,23 @@ const useFormStore = create((set, get) => ({
9664
9711
  columns: newColumns.map((col) => ({ ...col, width })),
9665
9712
  };
9666
9713
  });
9714
+ let newForm;
9667
9715
  if (state.form.isMultiStep && state.form.steps?.length) {
9668
- return {
9669
- form: {
9670
- ...state.form,
9671
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9672
- updatedAt: new Date().toISOString(),
9673
- },
9716
+ newForm = {
9717
+ ...state.form,
9718
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9719
+ updatedAt: new Date().toISOString(),
9674
9720
  };
9675
9721
  }
9676
- return {
9677
- form: {
9722
+ else {
9723
+ newForm = {
9678
9724
  ...state.form,
9679
9725
  rows: updateRows(state.form.rows),
9680
9726
  updatedAt: new Date().toISOString(),
9681
- },
9682
- };
9727
+ };
9728
+ }
9729
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9730
+ return { form: newForm, ...historyUpdate };
9683
9731
  }),
9684
9732
  addField: (rowId, columnId, field) => set((state) => {
9685
9733
  const updateRows = (rows) => rows.map((row) => row.id === rowId
@@ -9693,22 +9741,23 @@ const useFormStore = create((set, get) => ({
9693
9741
  : col),
9694
9742
  }
9695
9743
  : row);
9744
+ let newForm;
9696
9745
  if (state.form.isMultiStep && state.form.steps?.length) {
9697
- return {
9698
- form: {
9699
- ...state.form,
9700
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9701
- updatedAt: new Date().toISOString(),
9702
- },
9746
+ newForm = {
9747
+ ...state.form,
9748
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9749
+ updatedAt: new Date().toISOString(),
9703
9750
  };
9704
9751
  }
9705
- return {
9706
- form: {
9752
+ else {
9753
+ newForm = {
9707
9754
  ...state.form,
9708
9755
  rows: updateRows(state.form.rows),
9709
9756
  updatedAt: new Date().toISOString(),
9710
- },
9711
- };
9757
+ };
9758
+ }
9759
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9760
+ return { form: newForm, ...historyUpdate };
9712
9761
  }),
9713
9762
  addRowWithField: (field) => set((state) => {
9714
9763
  const newRow = {
@@ -9719,25 +9768,26 @@ const useFormStore = create((set, get) => ({
9719
9768
  fields: [{ ...field, id: nanoid() }],
9720
9769
  }],
9721
9770
  };
9771
+ let newForm;
9722
9772
  if (state.form.isMultiStep && state.form.steps?.length) {
9723
9773
  const currentStep = state.form.steps[state.currentStepIndex];
9724
- return {
9725
- form: {
9726
- ...state.form,
9727
- steps: state.form.steps.map(s => s.id === currentStep.id
9728
- ? { ...s, rows: [...s.rows, newRow] }
9729
- : s),
9730
- updatedAt: new Date().toISOString(),
9731
- },
9774
+ newForm = {
9775
+ ...state.form,
9776
+ steps: state.form.steps.map(s => s.id === currentStep.id
9777
+ ? { ...s, rows: [...s.rows, newRow] }
9778
+ : s),
9779
+ updatedAt: new Date().toISOString(),
9732
9780
  };
9733
9781
  }
9734
- return {
9735
- form: {
9782
+ else {
9783
+ newForm = {
9736
9784
  ...state.form,
9737
9785
  rows: [...state.form.rows, newRow],
9738
9786
  updatedAt: new Date().toISOString(),
9739
- },
9740
- };
9787
+ };
9788
+ }
9789
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9790
+ return { form: newForm, ...historyUpdate };
9741
9791
  }),
9742
9792
  addFieldToContainerDirect: (rowId, columnId, containerFieldId, field) => set((state) => {
9743
9793
  const newField = { ...field, id: nanoid() };
@@ -9763,22 +9813,23 @@ const useFormStore = create((set, get) => ({
9763
9813
  : col),
9764
9814
  }
9765
9815
  : row);
9816
+ let newForm;
9766
9817
  if (state.form.isMultiStep && state.form.steps?.length) {
9767
- return {
9768
- form: {
9769
- ...state.form,
9770
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9771
- updatedAt: new Date().toISOString(),
9772
- },
9818
+ newForm = {
9819
+ ...state.form,
9820
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9821
+ updatedAt: new Date().toISOString(),
9773
9822
  };
9774
9823
  }
9775
- return {
9776
- form: {
9824
+ else {
9825
+ newForm = {
9777
9826
  ...state.form,
9778
9827
  rows: updateRows(state.form.rows),
9779
9828
  updatedAt: new Date().toISOString(),
9780
- },
9781
- };
9829
+ };
9830
+ }
9831
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9832
+ return { form: newForm, ...historyUpdate };
9782
9833
  }),
9783
9834
  addFieldToContainer: (rowId, columnId, containerFieldId, containerRowId, containerColumnId, field) => set((state) => {
9784
9835
  const newField = { ...field, id: nanoid() };
@@ -9814,22 +9865,23 @@ const useFormStore = create((set, get) => ({
9814
9865
  : col),
9815
9866
  }
9816
9867
  : row);
9868
+ let newForm;
9817
9869
  if (state.form.isMultiStep && state.form.steps?.length) {
9818
- return {
9819
- form: {
9820
- ...state.form,
9821
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9822
- updatedAt: new Date().toISOString(),
9823
- },
9870
+ newForm = {
9871
+ ...state.form,
9872
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9873
+ updatedAt: new Date().toISOString(),
9824
9874
  };
9825
9875
  }
9826
- return {
9827
- form: {
9876
+ else {
9877
+ newForm = {
9828
9878
  ...state.form,
9829
9879
  rows: updateRows(state.form.rows),
9830
9880
  updatedAt: new Date().toISOString(),
9831
- },
9832
- };
9881
+ };
9882
+ }
9883
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9884
+ return { form: newForm, ...historyUpdate };
9833
9885
  }),
9834
9886
  updateField: (rowId, columnId, fieldId, updates) => set((state) => {
9835
9887
  const updateFieldInContainer = (field) => {
@@ -9894,22 +9946,23 @@ const useFormStore = create((set, get) => ({
9894
9946
  : col),
9895
9947
  }
9896
9948
  : row);
9949
+ let newForm;
9897
9950
  if (state.form.isMultiStep && state.form.steps?.length) {
9898
- return {
9899
- form: {
9900
- ...state.form,
9901
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9902
- updatedAt: new Date().toISOString(),
9903
- },
9951
+ newForm = {
9952
+ ...state.form,
9953
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9954
+ updatedAt: new Date().toISOString(),
9904
9955
  };
9905
9956
  }
9906
- return {
9907
- form: {
9957
+ else {
9958
+ newForm = {
9908
9959
  ...state.form,
9909
9960
  rows: updateRows(state.form.rows),
9910
9961
  updatedAt: new Date().toISOString(),
9911
- },
9912
- };
9962
+ };
9963
+ }
9964
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
9965
+ return { form: newForm, ...historyUpdate };
9913
9966
  }),
9914
9967
  deleteField: (rowId, columnId, fieldId) => set((state) => {
9915
9968
  const updateRows = (rows) => rows.map((row) => row.id === rowId
@@ -9940,22 +9993,25 @@ const useFormStore = create((set, get) => ({
9940
9993
  : col),
9941
9994
  }
9942
9995
  : row);
9996
+ let newForm;
9943
9997
  if (state.form.isMultiStep && state.form.steps?.length) {
9944
- return {
9945
- form: {
9946
- ...state.form,
9947
- steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
9948
- updatedAt: new Date().toISOString(),
9949
- },
9950
- selection: state.selection.fieldId === fieldId ? { type: null } : state.selection,
9998
+ newForm = {
9999
+ ...state.form,
10000
+ steps: state.form.steps.map(s => ({ ...s, rows: updateRows(s.rows) })),
10001
+ updatedAt: new Date().toISOString(),
9951
10002
  };
9952
10003
  }
9953
- return {
9954
- form: {
10004
+ else {
10005
+ newForm = {
9955
10006
  ...state.form,
9956
10007
  rows: updateRows(state.form.rows),
9957
10008
  updatedAt: new Date().toISOString(),
9958
- },
10009
+ };
10010
+ }
10011
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
10012
+ return {
10013
+ form: newForm,
10014
+ ...historyUpdate,
9959
10015
  selection: state.selection.fieldId === fieldId ? { type: null } : state.selection,
9960
10016
  };
9961
10017
  }),
@@ -9993,22 +10049,23 @@ const useFormStore = create((set, get) => ({
9993
10049
  }
9994
10050
  return row;
9995
10051
  });
10052
+ let newForm;
9996
10053
  if (state.form.isMultiStep && state.form.steps?.length) {
9997
10054
  let newSteps = state.form.steps.map(s => ({ ...s, rows: extractField(s.rows) }));
9998
10055
  if (!movedField)
9999
10056
  return state;
10000
10057
  newSteps = newSteps.map(s => ({ ...s, rows: insertField(s.rows) }));
10001
- return {
10002
- form: { ...state.form, steps: newSteps, updatedAt: new Date().toISOString() },
10003
- };
10058
+ newForm = { ...state.form, steps: newSteps, updatedAt: new Date().toISOString() };
10004
10059
  }
10005
- const rows = extractField(state.form.rows);
10006
- if (!movedField)
10007
- return state;
10008
- const finalRows = insertField(rows);
10009
- return {
10010
- form: { ...state.form, rows: finalRows, updatedAt: new Date().toISOString() },
10011
- };
10060
+ else {
10061
+ const rows = extractField(state.form.rows);
10062
+ if (!movedField)
10063
+ return state;
10064
+ const finalRows = insertField(rows);
10065
+ newForm = { ...state.form, rows: finalRows, updatedAt: new Date().toISOString() };
10066
+ }
10067
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
10068
+ return { form: newForm, ...historyUpdate };
10012
10069
  }),
10013
10070
  addStep: () => set((state) => {
10014
10071
  const newStep = createEmptyStep(state.form.steps?.length || 0);
@@ -10021,22 +10078,27 @@ const useFormStore = create((set, get) => ({
10021
10078
  },
10022
10079
  };
10023
10080
  }),
10024
- updateStep: (stepId, updates) => set((state) => ({
10025
- form: {
10081
+ updateStep: (stepId, updates) => set((state) => {
10082
+ const newForm = {
10026
10083
  ...state.form,
10027
10084
  steps: state.form.steps?.map(s => s.id === stepId ? { ...s, ...updates } : s),
10028
10085
  updatedAt: new Date().toISOString(),
10029
- },
10030
- })),
10086
+ };
10087
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
10088
+ return { form: newForm, ...historyUpdate };
10089
+ }),
10031
10090
  deleteStep: (stepId) => set((state) => {
10032
10091
  const newSteps = state.form.steps?.filter(s => s.id !== stepId) || [];
10092
+ const newForm = {
10093
+ ...state.form,
10094
+ steps: newSteps,
10095
+ isMultiStep: newSteps.length > 0,
10096
+ updatedAt: new Date().toISOString(),
10097
+ };
10098
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
10033
10099
  return {
10034
- form: {
10035
- ...state.form,
10036
- steps: newSteps,
10037
- isMultiStep: newSteps.length > 0,
10038
- updatedAt: new Date().toISOString(),
10039
- },
10100
+ form: newForm,
10101
+ ...historyUpdate,
10040
10102
  currentStepIndex: Math.min(state.currentStepIndex, Math.max(0, newSteps.length - 1)),
10041
10103
  selection: state.selection.stepId === stepId ? { type: null } : state.selection,
10042
10104
  };
@@ -10045,9 +10107,9 @@ const useFormStore = create((set, get) => ({
10045
10107
  const steps = [...(state.form.steps || [])];
10046
10108
  const [removed] = steps.splice(fromIndex, 1);
10047
10109
  steps.splice(toIndex, 0, removed);
10048
- return {
10049
- form: { ...state.form, steps, updatedAt: new Date().toISOString() },
10050
- };
10110
+ const newForm = { ...state.form, steps, updatedAt: new Date().toISOString() };
10111
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
10112
+ return { form: newForm, ...historyUpdate };
10051
10113
  }),
10052
10114
  setCurrentStep: (index) => set((state) => ({
10053
10115
  currentStepIndex: Math.max(0, Math.min(index, (state.form.steps?.length || 1) - 1)),
@@ -10059,33 +10121,30 @@ const useFormStore = create((set, get) => ({
10059
10121
  currentStepIndex: Math.max(0, state.currentStepIndex - 1),
10060
10122
  })),
10061
10123
  toggleMultiStep: () => set((state) => {
10124
+ let newForm;
10062
10125
  if (state.form.isMultiStep) {
10063
10126
  const allRows = state.form.steps?.flatMap(s => s.rows) || [];
10064
- return {
10065
- form: {
10066
- ...state.form,
10067
- isMultiStep: false,
10068
- rows: [...state.form.rows, ...allRows],
10069
- steps: [],
10070
- updatedAt: new Date().toISOString(),
10071
- },
10072
- currentStepIndex: 0,
10127
+ newForm = {
10128
+ ...state.form,
10129
+ isMultiStep: false,
10130
+ rows: [...state.form.rows, ...allRows],
10131
+ steps: [],
10132
+ updatedAt: new Date().toISOString(),
10073
10133
  };
10074
10134
  }
10075
10135
  else {
10076
10136
  const step = createEmptyStep(0);
10077
10137
  step.rows = [...state.form.rows];
10078
- return {
10079
- form: {
10080
- ...state.form,
10081
- isMultiStep: true,
10082
- rows: [],
10083
- steps: [step],
10084
- updatedAt: new Date().toISOString(),
10085
- },
10086
- currentStepIndex: 0,
10138
+ newForm = {
10139
+ ...state.form,
10140
+ isMultiStep: true,
10141
+ rows: [],
10142
+ steps: [step],
10143
+ updatedAt: new Date().toISOString(),
10087
10144
  };
10088
10145
  }
10146
+ const historyUpdate = pushToHistory({ form: newForm, history: state.history, historyIndex: state.historyIndex });
10147
+ return { form: newForm, ...historyUpdate, currentStepIndex: 0 };
10089
10148
  }),
10090
10149
  updateSubmissionConfig: (config) => set((state) => ({
10091
10150
  form: {
@@ -18584,7 +18643,7 @@ function MultiSelectField({ value, onChange, options, disabled, maxItems, classN
18584
18643
  }
18585
18644
  function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMode, getFieldValue: externalGetFieldValue, setFieldValue: externalSetFieldValue, isInsideContainer = false, fieldSize = 'normal' }) {
18586
18645
  const store = useFormStore();
18587
- const { selection, setSelection, deleteField, evaluateCondition, clearFormValues } = store;
18646
+ const { selection, setSelection, deleteField, evaluateCondition, clearFormValues, formValues } = store;
18588
18647
  const isPreviewMode = externalPreviewMode ?? store.isPreviewMode;
18589
18648
  const getFieldValue = externalGetFieldValue ?? store.getFieldValue;
18590
18649
  const setFieldValue = externalSetFieldValue ?? store.setFieldValue;
@@ -18608,6 +18667,15 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18608
18667
  // Reset rating, slider values
18609
18668
  setRatingValue(field.props.defaultValue ? parseInt(field.props.defaultValue) || 0 : 0);
18610
18669
  setSliderValue([field.props.defaultValue ? parseInt(field.props.defaultValue) || 50 : 50]);
18670
+ // Auto focus when entering preview mode
18671
+ if (field.props.autoFocus) {
18672
+ setTimeout(() => {
18673
+ const input = document.querySelector(`[data-testid^="field-"][data-testid$="-${field.id}"]`);
18674
+ if (input && input.focus) {
18675
+ input.focus();
18676
+ }
18677
+ }, 100);
18678
+ }
18611
18679
  }
18612
18680
  }, [isPreviewMode]);
18613
18681
  const isSelected = selection.type === 'field' &&
@@ -18640,8 +18708,59 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18640
18708
  break;
18641
18709
  }
18642
18710
  return { visible, enabled, required };
18643
- }, [field.conditionalLogic, field.validation?.required, evaluateCondition]);
18644
- if (isPreviewMode && !conditionalState.visible) {
18711
+ }, [field.conditionalLogic, field.validation?.required, evaluateCondition, formValues]);
18712
+ const handleChange = useCallback((newValue) => {
18713
+ setLocalValue(newValue);
18714
+ setFieldValue(field.props.key, newValue);
18715
+ if (touched) {
18716
+ setError(validateField(newValue, field.validation, field.type));
18717
+ }
18718
+ }, [touched, field.validation, field.type, field.props.key, setFieldValue]);
18719
+ const handleBlur = useCallback(() => {
18720
+ setTouched(true);
18721
+ setError(validateField(localValue, field.validation, field.type));
18722
+ }, [localValue, field.validation, field.type]);
18723
+ // Execute field actions (onClick, onChange, onFocus, onBlur events)
18724
+ const executeActions = useCallback((eventType) => {
18725
+ if (!isPreviewMode || !field.events)
18726
+ return;
18727
+ const actions = field.events[eventType];
18728
+ if (!actions || actions.length === 0)
18729
+ return;
18730
+ actions.forEach((action) => {
18731
+ if (action.type === 'common') {
18732
+ switch (action.name) {
18733
+ case 'focusField':
18734
+ if (action.args?.targetFieldKey) {
18735
+ setTimeout(() => {
18736
+ const allInputs = document.querySelectorAll('[data-field-key]');
18737
+ allInputs.forEach((el) => {
18738
+ if (el.getAttribute('data-field-key') === action.args?.targetFieldKey) {
18739
+ el.focus();
18740
+ }
18741
+ });
18742
+ }, 50);
18743
+ }
18744
+ break;
18745
+ case 'clearField':
18746
+ setLocalValue('');
18747
+ setFieldValue(field.props.key, '');
18748
+ break;
18749
+ case 'showMessage':
18750
+ if (action.args?.message) {
18751
+ alert(action.args.message);
18752
+ }
18753
+ break;
18754
+ case 'reset':
18755
+ clearFormValues();
18756
+ break;
18757
+ }
18758
+ }
18759
+ });
18760
+ }, [isPreviewMode, field.events, field.props.key, setFieldValue, clearFormValues]);
18761
+ // Early return for hidden fields - MUST be after all hooks
18762
+ // Check both conditional visibility AND explicit hidden property
18763
+ if (isPreviewMode && (!conditionalState.visible || field.props.hidden)) {
18645
18764
  return null;
18646
18765
  }
18647
18766
  const isFieldDisabled = field.props.disabled || !isPreviewMode || !conditionalState.enabled;
@@ -18656,18 +18775,10 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18656
18775
  fieldId: field.id,
18657
18776
  });
18658
18777
  }
18659
- };
18660
- const handleChange = useCallback((newValue) => {
18661
- setLocalValue(newValue);
18662
- setFieldValue(field.props.key, newValue);
18663
- if (touched) {
18664
- setError(validateField(newValue, field.validation, field.type));
18778
+ else {
18779
+ executeActions('onClick');
18665
18780
  }
18666
- }, [touched, field.validation, field.type, field.props.key, setFieldValue]);
18667
- const handleBlur = useCallback(() => {
18668
- setTouched(true);
18669
- setError(validateField(localValue, field.validation, field.type));
18670
- }, [localValue, field.validation, field.type]);
18781
+ };
18671
18782
  const sizeClasses = {
18672
18783
  small: 'h-8 text-sm',
18673
18784
  medium: 'h-9',
@@ -18690,51 +18801,51 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18690
18801
  const errorClass = hasError ? 'border-destructive focus-visible:ring-destructive' : '';
18691
18802
  switch (field.type) {
18692
18803
  case 'input':
18693
- return (jsx(Input, { placeholder: field.props.placeholder, disabled: isFieldDisabled, readOnly: field.props.readOnly, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18804
+ return (jsx(Input, { placeholder: field.props.placeholder, disabled: isFieldDisabled, readOnly: field.props.readOnly, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18694
18805
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18695
18806
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18696
- }, "data-testid": `field-input-${field.id}` }));
18807
+ }, "data-testid": `field-input-${field.id}`, "data-field-key": field.props.key }));
18697
18808
  case 'password':
18698
- return (jsx(Input, { type: "password", placeholder: field.props.placeholder, disabled: isFieldDisabled, value: isPreviewMode ? localValue : '', onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18809
+ return (jsx(Input, { type: "password", placeholder: field.props.placeholder, disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : '', onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18699
18810
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18700
18811
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18701
- }, "data-testid": `field-password-${field.id}` }));
18812
+ }, "data-testid": `field-password-${field.id}`, "data-field-key": field.props.key }));
18702
18813
  case 'phone':
18703
- return (jsx(Input, { type: "tel", placeholder: field.props.placeholder || '+1 (555) 000-0000', disabled: isFieldDisabled, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18814
+ return (jsx(Input, { type: "tel", placeholder: field.props.placeholder || '+1 (555) 000-0000', disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, "data-field-key": field.props.key, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18704
18815
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18705
18816
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18706
18817
  }, "data-testid": `field-phone-${field.id}` }));
18707
18818
  case 'url':
18708
- return (jsx(Input, { type: "url", placeholder: field.props.placeholder || 'https://example.com', disabled: isFieldDisabled, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18819
+ return (jsx(Input, { type: "url", placeholder: field.props.placeholder || 'https://example.com', disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18709
18820
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18710
18821
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18711
- }, "data-testid": `field-url-${field.id}` }));
18822
+ }, "data-testid": `field-url-${field.id}`, "data-field-key": field.props.key }));
18712
18823
  case 'textarea':
18713
- return (jsx(Textarea, { placeholder: field.props.placeholder, disabled: isFieldDisabled, readOnly: field.props.readOnly, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `min-h-[80px] ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18824
+ return (jsx(Textarea, { placeholder: field.props.placeholder, disabled: isFieldDisabled, readOnly: field.props.readOnly, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `min-h-[80px] ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18714
18825
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18715
18826
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18716
- }, "data-testid": `field-textarea-${field.id}` }));
18827
+ }, "data-testid": `field-textarea-${field.id}`, "data-field-key": field.props.key }));
18717
18828
  case 'dropdown':
18718
18829
  const dropdownOptions = typeof field.props.optionsString === 'string'
18719
18830
  ? field.props.optionsString.split('\n').filter((o) => o.trim())
18720
18831
  : (field.props.optionsString || []);
18721
- return (jsxs(Select, { disabled: isFieldDisabled, value: isPreviewMode ? localValue : undefined, onValueChange: (v) => isPreviewMode && handleChange(v), children: [jsx(SelectTrigger, { className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18832
+ return (jsxs(Select, { disabled: isFieldDisabled, value: isPreviewMode ? localValue : undefined, onValueChange: (v) => isPreviewMode && handleChange(v), children: [jsx(SelectTrigger, { className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, tabIndex: tabIndexValue, style: {
18722
18833
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18723
18834
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18724
18835
  }, "data-testid": `field-dropdown-${field.id}`, children: jsx(SelectValue, { placeholder: field.props.placeholder || 'Select...' }) }), jsx(SelectContent, { children: dropdownOptions.map((option, i) => (jsx(SelectItem, { value: option, children: option }, i))) })] }));
18725
18836
  case 'checkbox':
18726
- return (jsxs("div", { className: `flex items-center gap-2 ${field.customStyle?.inputClassName || ''}`, children: [jsx(Checkbox, { disabled: isFieldDisabled, "data-testid": `field-checkbox-${field.id}` }), jsx("span", { className: "text-sm text-foreground", style: {
18837
+ return (jsxs("div", { className: `flex items-center gap-2 ${field.customStyle?.inputClassName || ''}`, children: [jsx(Checkbox, { disabled: isFieldDisabled, tabIndex: tabIndexValue, "data-testid": `field-checkbox-${field.id}` }), jsx("span", { className: "text-sm text-foreground", style: {
18727
18838
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18728
18839
  }, children: field.props.label })] }));
18729
18840
  case 'radio':
18730
18841
  const radioOptions = typeof field.props.optionsString === 'string'
18731
18842
  ? field.props.optionsString.split('\n').filter((o) => o.trim())
18732
18843
  : (field.props.optionsString || []);
18733
- return (jsx(RadioGroup$1, { disabled: isFieldDisabled, className: field.customStyle?.inputClassName || '', children: radioOptions.map((option, i) => (jsxs("div", { className: "flex items-center gap-2", children: [jsx(RadioGroupItem, { value: option, id: `${field.id}-${i}`, "data-testid": `field-radio-${field.id}-${i}` }), jsx(Label$2, { htmlFor: `${field.id}-${i}`, className: "text-sm", style: {
18844
+ return (jsx(RadioGroup$1, { disabled: isFieldDisabled, className: field.customStyle?.inputClassName || '', children: radioOptions.map((option, i) => (jsxs("div", { className: "flex items-center gap-2", children: [jsx(RadioGroupItem, { value: option, id: `${field.id}-${i}`, tabIndex: tabIndexValue, "data-testid": `field-radio-${field.id}-${i}` }), jsx(Label$2, { htmlFor: `${field.id}-${i}`, className: "text-sm", style: {
18734
18845
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18735
18846
  }, children: option })] }, i))) }));
18736
18847
  case 'toggle':
18737
- return (jsxs("div", { className: `flex items-center gap-2 ${field.customStyle?.inputClassName || ''}`, children: [jsx(Switch, { disabled: isFieldDisabled, "data-testid": `field-toggle-${field.id}` }), jsx("span", { className: "text-sm text-foreground", style: {
18848
+ return (jsxs("div", { className: `flex items-center gap-2 ${field.customStyle?.inputClassName || ''}`, children: [jsx(Switch, { disabled: isFieldDisabled, tabIndex: tabIndexValue, "data-testid": `field-toggle-${field.id}` }), jsx("span", { className: "text-sm text-foreground", style: {
18738
18849
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18739
18850
  }, children: field.props.label })] }));
18740
18851
  case 'multiselect':
@@ -18743,30 +18854,30 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18743
18854
  setFieldValue(field.props.key, v);
18744
18855
  }, options: field.props.optionsString || [], disabled: isFieldDisabled, maxItems: field.props.multiSelectConfig?.maxItems, className: field.customStyle?.inputClassName }));
18745
18856
  case 'date':
18746
- return (jsx(Input, { type: "date", disabled: isFieldDisabled, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18857
+ return (jsx(Input, { type: "date", disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18747
18858
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18748
18859
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18749
- }, "data-testid": `field-date-${field.id}` }));
18860
+ }, "data-testid": `field-date-${field.id}`, "data-field-key": field.props.key }));
18750
18861
  case 'time':
18751
- return (jsx(Input, { type: "time", disabled: isFieldDisabled, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18862
+ return (jsx(Input, { type: "time", disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18752
18863
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18753
18864
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18754
- }, "data-testid": `field-time-${field.id}` }));
18865
+ }, "data-testid": `field-time-${field.id}`, "data-field-key": field.props.key }));
18755
18866
  case 'daterange':
18756
- return (jsxs("div", { className: `flex gap-2 items-center ${field.customStyle?.inputClassName || ''}`, children: [jsx(Input, { type: "date", disabled: isFieldDisabled, className: inputSize, style: {
18867
+ return (jsxs("div", { className: `flex gap-2 items-center ${field.customStyle?.inputClassName || ''}`, children: [jsx(Input, { type: "date", disabled: isFieldDisabled, tabIndex: tabIndexValue, className: inputSize, style: {
18757
18868
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18758
18869
  }, "data-testid": `field-daterange-start-${field.id}` }), jsx("span", { className: "text-muted-foreground", style: {
18759
18870
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18760
- }, children: "to" }), jsx(Input, { type: "date", disabled: isFieldDisabled, className: inputSize, style: {
18871
+ }, children: "to" }), jsx(Input, { type: "date", disabled: isFieldDisabled, tabIndex: tabIndexValue !== undefined ? tabIndexValue + 1 : undefined, className: inputSize, style: {
18761
18872
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18762
18873
  }, "data-testid": `field-daterange-end-${field.id}` })] }));
18763
18874
  case 'number':
18764
- return (jsx(Input, { type: "number", placeholder: field.props.placeholder, disabled: isFieldDisabled, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18875
+ return (jsx(Input, { type: "number", placeholder: field.props.placeholder, disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18765
18876
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18766
18877
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18767
- }, "data-testid": `field-number-${field.id}` }));
18878
+ }, "data-testid": `field-number-${field.id}`, "data-field-key": field.props.key }));
18768
18879
  case 'email':
18769
- return (jsx(Input, { type: "email", placeholder: field.props.placeholder, disabled: isFieldDisabled, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, style: {
18880
+ return (jsx(Input, { type: "email", placeholder: field.props.placeholder, disabled: isFieldDisabled, autoFocus: isPreviewMode && field.props.autoFocus, value: isPreviewMode ? localValue : (field.props.defaultValue || ''), onChange: (e) => isPreviewMode && handleChange(e.target.value), onBlur: handleBlur, tabIndex: tabIndexValue, className: `${inputSize} ${errorClass} ${field.customStyle?.inputClassName || ''}`, "data-field-key": field.props.key, style: {
18770
18881
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18771
18882
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18772
18883
  }, "data-testid": `field-email-${field.id}` }));
@@ -18792,7 +18903,7 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18792
18903
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18793
18904
  }, "data-testid": `field-richtext-${field.id}` }));
18794
18905
  case 'autocomplete':
18795
- return (jsx("div", { className: `relative ${field.customStyle?.inputClassName || ''}`, children: jsx(Input, { placeholder: field.props.placeholder || 'Start typing...', disabled: isFieldDisabled, value: isPreviewMode ? localValue : '', onChange: (e) => isPreviewMode && handleChange(e.target.value), className: `${inputSize} ${errorClass}`, style: {
18906
+ return (jsx("div", { className: `relative ${field.customStyle?.inputClassName || ''}`, children: jsx(Input, { placeholder: field.props.placeholder || 'Start typing...', disabled: isFieldDisabled, value: isPreviewMode ? localValue : '', onChange: (e) => isPreviewMode && handleChange(e.target.value), tabIndex: tabIndexValue, className: `${inputSize} ${errorClass}`, style: {
18796
18907
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18797
18908
  ...(field.customStyle?.backgroundColor ? { backgroundColor: field.customStyle.backgroundColor } : {}),
18798
18909
  }, "data-testid": `field-autocomplete-${field.id}` }) }));
@@ -18800,7 +18911,7 @@ function CanvasField({ field, rowId, columnId, isPreviewMode: externalPreviewMod
18800
18911
  return (jsxs("div", { className: `space-y-2 ${field.customStyle?.inputClassName || ''}`, children: [jsx(Slider, { value: sliderValue, onValueChange: (v) => {
18801
18912
  setSliderValue(v);
18802
18913
  setFieldValue(field.props.key, v[0]);
18803
- }, min: field.validation?.min || 0, max: field.validation?.max || 100, step: 1, disabled: isFieldDisabled, "data-testid": `field-slider-${field.id}` }), jsxs("div", { className: "flex justify-between text-xs text-muted-foreground", children: [jsx("span", { children: field.validation?.min || 0 }), jsx("span", { className: "font-medium text-foreground", style: {
18914
+ }, min: field.validation?.min || 0, max: field.validation?.max || 100, step: 1, disabled: isFieldDisabled, tabIndex: tabIndexValue, "data-testid": `field-slider-${field.id}` }), jsxs("div", { className: "flex justify-between text-xs text-muted-foreground", children: [jsx("span", { children: field.validation?.min || 0 }), jsx("span", { className: "font-medium text-foreground", style: {
18804
18915
  ...(field.customStyle?.color ? { color: field.customStyle.color } : {}),
18805
18916
  }, children: sliderValue[0] }), jsx("span", { children: field.validation?.max || 100 })] })] }));
18806
18917
  case 'header':
@@ -19795,15 +19906,30 @@ function FieldProperties() {
19795
19906
  });
19796
19907
  }, className: "w-full gap-2", children: [jsx(Plus, { className: "h-4 w-4" }), "Add Attribute"] })] })] }), jsx(Separator$1, {}), hasOptions && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Options" }), jsxs("div", { className: "space-y-2", children: [getOptionsArray().map((option, i) => (jsxs("div", { className: "flex gap-2", children: [jsx(Input, { value: option, onChange: (e) => handleUpdateOption(i, e.target.value), className: "flex-1", "data-testid": `input-option-${i}` }), jsx(Button, { variant: "outline", size: "icon", onClick: () => handleRemoveOption(i), "data-testid": `button-remove-option-${i}`, children: jsx(Trash2, { className: "h-4 w-4" }) })] }, i))), jsxs(Button, { variant: "outline", size: "sm", onClick: handleAddOption, className: "w-full gap-2", "data-testid": "button-add-option", children: [jsx(Plus, { className: "h-4 w-4" }), "Add Option"] })] })] })), field.type === 'button' && (jsxs("div", { className: "space-y-4", children: [jsx(Separator$1, {}), jsx("h4", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Button Settings" }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Action" }), jsxs(Select, { value: field.props.buttonConfig?.action || 'submit', onValueChange: (value) => handleUpdateProp('buttonConfig', { ...field.props.buttonConfig, action: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "submit", children: "Submit Form" }), jsx(SelectItem, { value: "reset", children: "Reset Form" }), jsx(SelectItem, { value: "custom", children: "Custom Action" })] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Variant" }), jsxs(Select, { value: field.props.buttonConfig?.variant || 'default', onValueChange: (value) => handleUpdateProp('buttonConfig', { ...field.props.buttonConfig, variant: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "default", children: "Default" }), jsx(SelectItem, { value: "outline", children: "Outline" }), jsx(SelectItem, { value: "secondary", children: "Secondary" }), jsx(SelectItem, { value: "destructive", children: "Destructive" }), jsx(SelectItem, { value: "ghost", children: "Ghost" })] })] })] })] })), field.type === 'pattern' && (jsxs("div", { className: "space-y-4", children: [jsx(Separator$1, {}), jsx("h4", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Pattern Format" }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Format Pattern" }), jsx(Input, { value: field.props.patternConfig?.format || '(###) ###-####', onChange: (e) => handleUpdateProp('patternConfig', { ...field.props.patternConfig, format: e.target.value }), placeholder: "(###) ###-####" }), jsx("p", { className: "text-xs text-muted-foreground", children: "Use # for digit placeholders" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Mask Character" }), jsx(Input, { value: field.props.patternConfig?.mask || '_', onChange: (e) => handleUpdateProp('patternConfig', { ...field.props.patternConfig, mask: e.target.value }), maxLength: 1 })] })] })), field.type === 'qrcode' && (jsxs("div", { className: "space-y-4", children: [jsx(Separator$1, {}), jsx("h4", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "QR Code Settings" }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "QR Value" }), jsx(Input, { value: field.props.qrCodeConfig?.value || 'https://example.com', onChange: (e) => handleUpdateProp('qrCodeConfig', { ...field.props.qrCodeConfig, value: e.target.value }), placeholder: "https://example.com" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Size (px)" }), jsx(Input, { type: "number", value: field.props.qrCodeConfig?.size || 128, onChange: (e) => handleUpdateProp('qrCodeConfig', { ...field.props.qrCodeConfig, size: parseInt(e.target.value) }), min: 64, max: 512 })] })] })), field.type === 'container' && (jsxs("div", { className: "space-y-4", children: [jsx(Separator$1, {}), jsx("h4", { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Container Settings" }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Direction" }), jsxs(Select, { value: field.props.containerConfig?.direction || 'row', onValueChange: (value) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, direction: value }), children: [jsx(SelectTrigger, { "data-testid": "select-container-direction", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "row", children: "Row (Horizontal)" }), jsx(SelectItem, { value: "column", children: "Column (Vertical)" })] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Inner Field Size (Density)" }), jsxs(Select, { value: field.props.containerConfig?.fieldSize || 'normal', onValueChange: (value) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, fieldSize: value }), children: [jsx(SelectTrigger, { "data-testid": "container-field-size", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "compact", "data-testid": "field-size-compact", children: "Compact (Minimal)" }), jsx(SelectItem, { value: "normal", "data-testid": "field-size-normal", children: "Normal" }), jsx(SelectItem, { value: "comfortable", "data-testid": "field-size-comfortable", children: "Comfortable (Spacious)" })] })] }), jsx("p", { className: "text-xs text-muted-foreground", children: "Controls padding and font sizes for fields inside this container" })] }), jsx(Separator$1, {}), jsx("h5", { className: "text-xs font-medium text-muted-foreground", children: "Spacing & Layout" }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Gap (between items)" }), jsx(Input, { type: "number", value: field.props.containerConfig?.gap ?? 4, onChange: (e) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, gap: parseInt(e.target.value) }), min: 0, max: 16 }), jsx("p", { className: "text-xs text-muted-foreground", children: "Space between child elements (0-16)" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Padding (inner space)" }), jsx(Input, { type: "number", value: field.props.containerConfig?.padding ?? 4, onChange: (e) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, padding: parseInt(e.target.value) }), min: 0, max: 16 }), jsx("p", { className: "text-xs text-muted-foreground", children: "Inner spacing around content (0-16)" })] }), jsx(Separator$1, {}), jsx("h5", { className: "text-xs font-medium text-muted-foreground", children: "Flex Properties" }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Justify Content" }), jsxs(Select, { value: field.props.containerConfig?.justifyContent || 'flex-start', onValueChange: (value) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, justifyContent: value }), children: [jsx(SelectTrigger, { "data-testid": "select-justify-content", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "flex-start", children: "Start" }), jsx(SelectItem, { value: "flex-end", children: "End" }), jsx(SelectItem, { value: "center", children: "Center" }), jsx(SelectItem, { value: "space-between", children: "Space Between" }), jsx(SelectItem, { value: "space-around", children: "Space Around" }), jsx(SelectItem, { value: "space-evenly", children: "Space Evenly" })] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Align Items" }), jsxs(Select, { value: field.props.containerConfig?.alignItems || 'stretch', onValueChange: (value) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, alignItems: value }), children: [jsx(SelectTrigger, { "data-testid": "select-align-items", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "flex-start", children: "Start" }), jsx(SelectItem, { value: "flex-end", children: "End" }), jsx(SelectItem, { value: "center", children: "Center" }), jsx(SelectItem, { value: "stretch", children: "Stretch" }), jsx(SelectItem, { value: "baseline", children: "Baseline" })] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Flex Wrap" }), jsxs(Select, { value: field.props.containerConfig?.flexWrap || 'wrap', onValueChange: (value) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, flexWrap: value }), children: [jsx(SelectTrigger, { "data-testid": "select-flex-wrap", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "wrap", children: "Wrap" }), jsx(SelectItem, { value: "nowrap", children: "No Wrap" })] })] })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Show Border" }), jsx(Switch, { checked: field.props.containerConfig?.border || false, onCheckedChange: (checked) => handleUpdateProp('containerConfig', { ...field.props.containerConfig, border: checked }) })] }), jsx(Separator$1, {}), jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("h5", { className: "text-sm font-medium", children: "Container Fields" }), jsxs("span", { className: "text-xs text-muted-foreground", children: [(field.props.containerConfig?.fields || []).length, " field(s)"] })] }), jsx("p", { className: "text-xs text-muted-foreground", children: "Drag fields onto the container. Set each field's width in its properties." })] })] })), field.type === 'table' && (jsxs("div", { className: "space-y-4 p-3 bg-muted/30 rounded-md", children: [jsx("h4", { className: "text-sm font-medium", children: "Table Configuration" }), jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Show Row Numbers" }), jsx(Switch, { checked: field.props.tableConfig?.showRowNumbers ?? true, onCheckedChange: (checked) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, showRowNumbers: checked }) })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Allow Add Rows" }), jsx(Switch, { checked: field.props.tableConfig?.allowAddRows ?? true, onCheckedChange: (checked) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, allowAddRows: checked }) })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Allow Delete Rows" }), jsx(Switch, { checked: field.props.tableConfig?.allowDeleteRows ?? false, onCheckedChange: (checked) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, allowDeleteRows: checked }) })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Striped Rows" }), jsx(Switch, { checked: field.props.tableConfig?.striped ?? false, onCheckedChange: (checked) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, striped: checked }) })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Bordered" }), jsx(Switch, { checked: field.props.tableConfig?.bordered ?? true, onCheckedChange: (checked) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, bordered: checked }) })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Compact" }), jsx(Switch, { checked: field.props.tableConfig?.compact ?? false, onCheckedChange: (checked) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, compact: checked }) })] })] }), jsx(Separator$1, {}), jsxs("div", { className: "grid grid-cols-2 gap-3", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Min Rows" }), jsx(Input, { type: "number", value: field.props.tableConfig?.minRows ?? 1, onChange: (e) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, minRows: parseInt(e.target.value) || 1 }), min: 1, max: 100 })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Max Rows" }), jsx(Input, { type: "number", value: field.props.tableConfig?.maxRows ?? 100, onChange: (e) => handleUpdateProp('tableConfig', { ...field.props.tableConfig, maxRows: parseInt(e.target.value) || 100 }), min: 1, max: 1000 })] })] }), jsx(Separator$1, {}), jsxs("div", { className: "space-y-3", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx("h5", { className: "text-sm font-medium", children: "Columns" }), jsxs(Button, { variant: "outline", size: "sm", onClick: () => {
19797
19908
  const currentColumns = field.props.tableConfig?.columns || [];
19909
+ const totalColumns = currentColumns.length + 1;
19910
+ const widthPerColumn = Math.floor(100 / totalColumns);
19911
+ const extraWidth = 100 % totalColumns;
19912
+ const updatedColumns = currentColumns.map((c, idx) => ({
19913
+ ...c,
19914
+ width: `${widthPerColumn + (idx < extraWidth ? 1 : 0)}%`
19915
+ }));
19798
19916
  const newColumn = {
19799
19917
  key: `col_${Date.now()}`,
19800
- label: `Column ${currentColumns.length + 1}`,
19918
+ label: `Column ${totalColumns}`,
19801
19919
  type: 'text',
19920
+ width: `${widthPerColumn}%`,
19802
19921
  };
19803
- handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: [...currentColumns, newColumn] });
19922
+ handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: [...updatedColumns, newColumn] });
19804
19923
  }, children: [jsx(Plus, { className: "h-4 w-4 mr-1" }), "Add Column"] })] }), (field.props.tableConfig?.columns || []).map((col, colIndex) => (jsxs("div", { className: "p-3 bg-background rounded-md border border-border space-y-3", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("span", { className: "text-xs font-medium text-muted-foreground", children: ["Column ", colIndex + 1] }), jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6", onClick: () => {
19805
19924
  const currentColumns = [...(field.props.tableConfig?.columns || [])];
19806
19925
  currentColumns.splice(colIndex, 1);
19926
+ if (currentColumns.length > 0) {
19927
+ const widthPerColumn = Math.floor(100 / currentColumns.length);
19928
+ const extraWidth = 100 % currentColumns.length;
19929
+ currentColumns.forEach((c, idx) => {
19930
+ currentColumns[idx] = { ...c, width: `${widthPerColumn + (idx < extraWidth ? 1 : 0)}%` };
19931
+ });
19932
+ }
19807
19933
  handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: currentColumns });
19808
19934
  }, children: jsx(Trash2, { className: "h-3 w-3 text-destructive" }) })] }), jsxs("div", { className: "grid grid-cols-2 gap-2", children: [jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "Key" }), jsx(Input, { value: col.key, onChange: (e) => {
19809
19935
  const currentColumns = [...(field.props.tableConfig?.columns || [])];
@@ -19817,11 +19943,12 @@ function FieldProperties() {
19817
19943
  const currentColumns = [...(field.props.tableConfig?.columns || [])];
19818
19944
  currentColumns[colIndex] = { ...col, type: value };
19819
19945
  handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: currentColumns });
19820
- }, children: [jsx(SelectTrigger, { className: "h-8 text-xs", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "text", children: "Text" }), jsx(SelectItem, { value: "number", children: "Number" }), jsx(SelectItem, { value: "email", children: "Email" }), jsx(SelectItem, { value: "date", children: "Date" }), jsx(SelectItem, { value: "select", children: "Select" }), jsx(SelectItem, { value: "checkbox", children: "Checkbox" })] })] })] }), jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "Width" }), jsx(Input, { value: col.width || '', onChange: (e) => {
19946
+ }, children: [jsx(SelectTrigger, { className: "h-8 text-xs", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "text", children: "Text" }), jsx(SelectItem, { value: "number", children: "Number" }), jsx(SelectItem, { value: "email", children: "Email" }), jsx(SelectItem, { value: "date", children: "Date" }), jsx(SelectItem, { value: "select", children: "Select" }), jsx(SelectItem, { value: "checkbox", children: "Checkbox" })] })] })] }), jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "%Width" }), jsx(Input, { type: "number", value: col.width ? parseInt(col.width) || '' : '', onChange: (e) => {
19821
19947
  const currentColumns = [...(field.props.tableConfig?.columns || [])];
19822
- currentColumns[colIndex] = { ...col, width: e.target.value };
19948
+ const newWidth = parseInt(e.target.value) || 0;
19949
+ currentColumns[colIndex] = { ...col, width: newWidth > 0 ? `${newWidth}%` : '' };
19823
19950
  handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: currentColumns });
19824
- }, placeholder: "auto", className: "text-xs h-8" })] }), jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "Required" }), jsx("div", { className: "flex items-center h-8", children: jsx(Switch, { checked: col.required || false, onCheckedChange: (checked) => {
19951
+ }, placeholder: "25", min: 1, max: 100, className: "text-xs h-8" })] }), jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "Required" }), jsx("div", { className: "flex items-center h-8", children: jsx(Switch, { checked: col.required || false, onCheckedChange: (checked) => {
19825
19952
  const currentColumns = [...(field.props.tableConfig?.columns || [])];
19826
19953
  currentColumns[colIndex] = { ...col, required: checked };
19827
19954
  handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: currentColumns });
@@ -19849,7 +19976,12 @@ function FieldProperties() {
19849
19976
  currentOptions.splice(optIndex, 1);
19850
19977
  currentColumns[colIndex] = { ...col, options: currentOptions };
19851
19978
  handleUpdateProp('tableConfig', { ...field.props.tableConfig, columns: currentColumns });
19852
- }, children: jsx(Trash2, { className: "h-3 w-3 text-destructive" }) })] }, optIndex))), (!col.options || col.options.length === 0) && (jsx("p", { className: "text-xs text-muted-foreground italic", children: "Hen\u00FCz se\u00E7enek eklenmedi" }))] }))] }, col.key)))] })] })), (() => {
19979
+ }, children: jsx(Trash2, { className: "h-3 w-3 text-destructive" }) })] }, optIndex))), (!col.options || col.options.length === 0) && (jsx("p", { className: "text-xs text-muted-foreground italic", children: "Hen\u00FCz se\u00E7enek eklenmedi" }))] }))] }, `col-${colIndex}`))), (field.props.tableConfig?.columns || []).length > 0 && (() => {
19980
+ const columns = field.props.tableConfig?.columns || [];
19981
+ const totalWidth = columns.reduce((sum, c) => sum + (parseInt(c.width || '0') || 0), 0);
19982
+ const isValid = totalWidth === 100;
19983
+ return (jsxs("div", { className: `flex items-center justify-between p-2 rounded-md text-xs ${isValid ? 'bg-green-500/10 text-green-600 dark:text-green-400' : 'bg-destructive/10 text-destructive'}`, children: [jsxs("span", { className: "font-medium", children: ["Total Width: ", totalWidth, "%"] }), !isValid && (jsx("span", { children: "Must equal 100%" })), isValid && (jsx("span", { children: "\u2713" }))] }));
19984
+ })()] })] })), (() => {
19853
19985
  const staticDisplayTypes = ['spacer', 'divider', 'header', 'subheader', 'label', 'paragraph', 'alert', 'image', 'qrcode', 'button'];
19854
19986
  if (staticDisplayTypes.includes(field.type))
19855
19987
  return null;
@@ -19860,7 +19992,7 @@ function FieldProperties() {
19860
19992
  return (jsx("div", { className: "text-center py-8 text-muted-foreground", children: jsx("p", { className: "text-sm", children: "Bu bile\u015Fen i\u00E7in do\u011Frulama kurallar\u0131 gerekli de\u011Fil." }) }));
19861
19993
  }
19862
19994
  return (jsxs(Fragment, { children: [jsxs("div", { className: "flex items-center gap-2 mb-4", children: [jsx(Settings2, { className: "h-4 w-4 text-muted-foreground" }), jsx("span", { className: "text-sm font-medium", children: "Validation Rules" })] }), jsxs("div", { className: "space-y-3 pb-4", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Auto Validate" }), jsx(Switch, { checked: field.validation?.autoValidate || false, onCheckedChange: (checked) => handleUpdateValidation('autoValidate', checked) })] }), jsx("p", { className: "text-xs text-muted-foreground", children: "Validate while typing" }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Validate on Blur" }), jsx(Switch, { checked: field.validation?.validateOnBlur ?? true, onCheckedChange: (checked) => handleUpdateValidation('validateOnBlur', checked) })] }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { className: "text-sm", children: "Validate on Change" }), jsx(Switch, { checked: field.validation?.validateOnChange || false, onCheckedChange: (checked) => handleUpdateValidation('validateOnChange', checked) })] })] }), jsx(Separator$1, {}), jsxs("div", { className: "space-y-2 pt-4", children: [jsx(Label$2, { className: "text-sm", children: "Validation Type" }), jsxs(Select, { value: field.validation?.validationType || '', onValueChange: (value) => handleUpdateValidation('validationType', value || undefined), children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: "None" }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "email", children: "Email" }), jsx(SelectItem, { value: "url", children: "URL" }), jsx(SelectItem, { value: "phone", children: "Phone" }), jsx(SelectItem, { value: "custom", children: "Custom" })] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Min Length" }), jsx(Input, { type: "number", min: 0, value: field.validation?.minLength || '', onChange: (e) => handleUpdateValidation('minLength', e.target.value ? parseInt(e.target.value) : undefined), "data-testid": "input-min-length" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Max Length" }), jsx(Input, { type: "number", min: 0, value: field.validation?.maxLength || '', onChange: (e) => handleUpdateValidation('maxLength', e.target.value ? parseInt(e.target.value) : undefined), "data-testid": "input-max-length" })] }), ['number', 'slider'].includes(field.type) && (jsxs(Fragment, { children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Min Value" }), jsx(Input, { type: "number", value: field.validation?.min ?? '', onChange: (e) => handleUpdateValidation('min', e.target.value ? parseFloat(e.target.value) : undefined), "data-testid": "input-min-value" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Max Value" }), jsx(Input, { type: "number", value: field.validation?.max ?? '', onChange: (e) => handleUpdateValidation('max', e.target.value ? parseFloat(e.target.value) : undefined), "data-testid": "input-max-value" })] })] })), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Pattern (Regex)" }), jsx(Input, { value: field.validation?.pattern || '', onChange: (e) => handleUpdateValidation('pattern', e.target.value || undefined), placeholder: "^[a-zA-Z]+$", className: "font-mono text-sm", "data-testid": "input-pattern" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Custom Error Message" }), jsx(Input, { value: field.validation?.errorMessage || '', onChange: (e) => handleUpdateValidation('errorMessage', e.target.value || undefined), placeholder: "Please enter a valid value", "data-testid": "input-error-message" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Custom Validation (JS)" }), jsx(Textarea, { value: field.validation?.customValidation || '', onChange: (e) => handleUpdateValidation('customValidation', e.target.value || undefined), placeholder: "return value.length > 5;", className: "font-mono text-sm min-h-[80px]" }), jsx("p", { className: "text-xs text-muted-foreground", children: "Write JavaScript that returns true for valid values" })] }), jsx(Separator$1, {}), jsxs("div", { className: "flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Zap, { className: "h-4 w-4 text-muted-foreground" }), jsx(Label$2, { className: "text-sm font-medium", children: "Conditional Logic" })] }), jsx(Switch, { checked: field.conditionalLogic?.enabled || false, onCheckedChange: (checked) => handleUpdateConditionalLogic({ enabled: checked }) })] }), field.conditionalLogic?.enabled && (jsxs(Fragment, { children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "Action" }), jsxs(Select, { value: field.conditionalLogic?.action || 'show', onValueChange: (value) => handleUpdateConditionalLogic({ action: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "show", children: "Show this field" }), jsx(SelectItem, { value: "hide", children: "Hide this field" }), jsx(SelectItem, { value: "enable", children: "Enable this field" }), jsx(SelectItem, { value: "disable", children: "Disable this field" }), jsx(SelectItem, { value: "require", children: "Make required" })] })] })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-sm", children: "When" }), jsxs(Select, { value: field.conditionalLogic?.logicType || 'all', onValueChange: (value) => handleUpdateConditionalLogic({ logicType: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "all", children: "All conditions are met" }), jsx(SelectItem, { value: "any", children: "Any condition is met" })] })] })] }), jsx(Separator$1, {}), jsxs("div", { className: "space-y-3", children: [jsx(Label$2, { className: "text-sm font-medium", children: "Conditions" }), (field.conditionalLogic?.conditions || []).map((condition, index) => (jsxs("div", { className: "p-3 border border-border rounded-md space-y-3", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs(Badge, { variant: "secondary", children: ["Condition ", index + 1] }), jsx(Button, { variant: "ghost", size: "icon", onClick: () => removeCondition(index), children: jsx(Trash2, { className: "h-4 w-4" }) })] }), jsxs(Select, { value: condition.fieldKey, onValueChange: (value) => updateCondition(index, { fieldKey: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: "Select field..." }) }), jsx(SelectContent, { children: allFields.map((f) => (jsxs(SelectItem, { value: f.props.key, children: [f.props.label, " (", f.props.key, ")"] }, f.id))) })] }), jsxs(Select, { value: condition.operator, onValueChange: (value) => updateCondition(index, { operator: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "equals", children: "Equals" }), jsx(SelectItem, { value: "notEquals", children: "Not equals" }), jsx(SelectItem, { value: "contains", children: "Contains" }), jsx(SelectItem, { value: "notContains", children: "Does not contain" }), jsx(SelectItem, { value: "greaterThan", children: "Greater than" }), jsx(SelectItem, { value: "lessThan", children: "Less than" }), jsx(SelectItem, { value: "isEmpty", children: "Is empty" }), jsx(SelectItem, { value: "isNotEmpty", children: "Is not empty" }), jsx(SelectItem, { value: "startsWith", children: "Starts with" }), jsx(SelectItem, { value: "endsWith", children: "Ends with" })] })] }), !['isEmpty', 'isNotEmpty'].includes(condition.operator) && (jsx(Input, { value: condition.value || '', onChange: (e) => updateCondition(index, { value: e.target.value }), placeholder: "Value..." }))] }, index))), jsxs(Button, { variant: "outline", size: "sm", onClick: addCondition, className: "w-full gap-2", children: [jsx(Plus, { className: "h-4 w-4" }), "Add Condition"] })] })] }))] }));
19863
- })() }), jsxs(TabsContent, { value: "actions", className: "space-y-4 mt-0", children: [jsxs("div", { className: "flex items-center gap-2 mb-4", children: [jsx(MousePointerClick, { className: "h-4 w-4 text-muted-foreground" }), jsx("span", { className: "text-sm font-medium", children: "Event Handlers" })] }), jsx("p", { className: "text-xs text-muted-foreground mb-4", children: "Add actions that trigger on specific events like click, change, focus, or blur." }), ['onClick', 'onChange', 'onFocus', 'onBlur'].map((eventType) => (jsxs(Collapsible, { className: "border border-border rounded-md", children: [jsxs(CollapsibleTrigger, { className: "flex items-center justify-between w-full p-3 hover:bg-muted/50", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Play, { className: "h-3 w-3 text-muted-foreground" }), jsx("span", { className: "text-sm font-medium", children: eventType }), (field.events?.[eventType]?.length || 0) > 0 && (jsx(Badge, { variant: "secondary", className: "text-xs", children: field.events?.[eventType]?.length }))] }), jsx(ChevronDown, { className: "h-4 w-4 text-muted-foreground" })] }), jsxs(CollapsibleContent, { className: "p-3 pt-0 space-y-3", children: [(field.events?.[eventType] || []).map((action, index) => (jsxs("div", { className: "p-3 border border-border rounded-md space-y-3 bg-muted/30", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs(Badge, { variant: "outline", children: ["Action ", index + 1] }), jsx(Button, { variant: "ghost", size: "icon", onClick: () => removeEventAction(eventType, index), children: jsx(Trash2, { className: "h-4 w-4" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "Type" }), jsxs(Select, { value: action.type, onValueChange: (value) => updateEventAction(eventType, index, { type: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "common", children: "Common Action" }), jsx(SelectItem, { value: "code", children: "Code Action" }), jsx(SelectItem, { value: "custom", children: "Custom Action" })] })] })] }), action.type === 'common' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "Action" }), jsxs(Select, { value: action.name, onValueChange: (value) => updateEventAction(eventType, index, { name: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: "Select action..." }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "validate", children: "Validate Form" }), jsx(SelectItem, { value: "reset", children: "Reset Form" }), jsx(SelectItem, { value: "submit", children: "Submit Form" }), jsx(SelectItem, { value: "clearField", children: "Clear This Field" }), jsx(SelectItem, { value: "focusField", children: "Focus Field" }), jsx(SelectItem, { value: "showMessage", children: "Show Message" })] })] })] })), action.type === 'code' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "JavaScript Code" }), jsx(Textarea, { value: action.code || '', onChange: (e) => updateEventAction(eventType, index, { code: e.target.value }), placeholder: "console.log('Action triggered');", className: "font-mono text-xs min-h-[60px]" })] })), action.type === 'custom' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "Custom Action Name" }), jsx(Input, { value: action.name, onChange: (e) => updateEventAction(eventType, index, { name: e.target.value }), placeholder: "myCustomAction", className: "font-mono text-sm" }), jsx("p", { className: "text-xs text-muted-foreground", children: "This will call the custom action passed to FormViewer" })] }))] }, index))), jsxs(Button, { variant: "outline", size: "sm", onClick: () => addEventAction(eventType), className: "w-full gap-2", children: [jsx(Plus, { className: "h-4 w-4" }), "Add Action"] })] })] }, eventType)))] }), jsxs(TabsContent, { value: "style", className: "space-y-4 mt-0", children: [jsxs("div", { className: "flex items-center justify-between mb-4", children: [jsx("span", { className: "text-sm font-medium", children: "For device" }), jsxs(Select, { value: field.customStyle?.deviceTarget || 'any', onValueChange: (value) => handleUpdateCustomStyle('deviceTarget', value), children: [jsx(SelectTrigger, { className: "w-32", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "any", children: "Any" }), jsx(SelectItem, { value: "mobile", children: "Mobile" }), jsx(SelectItem, { value: "tablet", children: "Tablet" }), jsx(SelectItem, { value: "desktop", children: "Desktop" })] })] })] }), jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "text-sm font-semibold", children: "Component" }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Paintbrush, { className: "h-4 w-4 text-muted-foreground" }), jsx(Label$2, { className: "text-sm w-24", children: "Class Name" }), jsx(Input, { value: field.customStyle?.inputClassName || '', onChange: (e) => handleUpdateCustomStyle('inputClassName', e.target.value), placeholder: "", className: "font-mono text-sm flex-1" }), field.customStyle?.inputClassName && (jsx(Button, { variant: "ghost", size: "icon", onClick: () => handleUpdateCustomStyle('inputClassName', ''), children: jsx(Trash2, { className: "h-4 w-4" }) }))] })] }), jsx(Separator$1, {}), jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "text-sm font-semibold", children: "Wrapper" }), jsxs("div", { className: "grid grid-cols-2 gap-3", children: [jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "Width" }), jsxs("div", { className: "flex gap-1", children: [jsx(Input, { type: "number", value: field.customStyle?.width?.value ?? 100, onChange: (e) => handleUpdateCustomStyle('width', {
19995
+ })() }), jsxs(TabsContent, { value: "actions", className: "space-y-4 mt-0", children: [jsxs("div", { className: "flex items-center gap-2 mb-4", children: [jsx(MousePointerClick, { className: "h-4 w-4 text-muted-foreground" }), jsx("span", { className: "text-sm font-medium", children: "Event Handlers" })] }), jsx("p", { className: "text-xs text-muted-foreground mb-4", children: "Add actions that trigger on specific events like click, change, focus, or blur." }), ['onClick', 'onChange', 'onFocus', 'onBlur'].map((eventType) => (jsxs(Collapsible, { className: "border border-border rounded-md", children: [jsxs(CollapsibleTrigger, { className: "flex items-center justify-between w-full p-3 hover:bg-muted/50", children: [jsxs("div", { className: "flex items-center gap-2", children: [jsx(Play, { className: "h-3 w-3 text-muted-foreground" }), jsx("span", { className: "text-sm font-medium", children: eventType }), (field.events?.[eventType]?.length || 0) > 0 && (jsx(Badge, { variant: "secondary", className: "text-xs", children: field.events?.[eventType]?.length }))] }), jsx(ChevronDown, { className: "h-4 w-4 text-muted-foreground" })] }), jsxs(CollapsibleContent, { className: "p-3 pt-0 space-y-3", children: [(field.events?.[eventType] || []).map((action, index) => (jsxs("div", { className: "p-3 border border-border rounded-md space-y-3 bg-muted/30", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs(Badge, { variant: "outline", children: ["Action ", index + 1] }), jsx(Button, { variant: "ghost", size: "icon", onClick: () => removeEventAction(eventType, index), children: jsx(Trash2, { className: "h-4 w-4" }) })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "Type" }), jsxs(Select, { value: action.type, onValueChange: (value) => updateEventAction(eventType, index, { type: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "common", children: "Common Action" }), jsx(SelectItem, { value: "code", children: "Code Action" }), jsx(SelectItem, { value: "custom", children: "Custom Action" })] })] })] }), action.type === 'common' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "Action" }), jsxs(Select, { value: action.name, onValueChange: (value) => updateEventAction(eventType, index, { name: value }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: "Select action..." }) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "validate", children: "Validate Form" }), jsx(SelectItem, { value: "reset", children: "Reset Form" }), jsx(SelectItem, { value: "submit", children: "Submit Form" }), jsx(SelectItem, { value: "clearField", children: "Clear This Field" }), jsx(SelectItem, { value: "focusField", children: "Focus Field" }), jsx(SelectItem, { value: "showMessage", children: "Show Message" })] })] }), action.name === 'focusField' && (jsxs("div", { className: "space-y-2 mt-2", children: [jsx(Label$2, { className: "text-xs", children: "Target Field" }), jsxs(Select, { value: action.args?.targetFieldKey || '', onValueChange: (value) => updateEventAction(eventType, index, { args: { ...action.args, targetFieldKey: value } }), children: [jsx(SelectTrigger, { children: jsx(SelectValue, { placeholder: "Select field to focus..." }) }), jsx(SelectContent, { children: allFields.map((f) => (jsx(SelectItem, { value: f.props.key, children: f.props.label || f.props.key }, f.id))) })] })] })), action.name === 'showMessage' && (jsxs("div", { className: "space-y-2 mt-2", children: [jsx(Label$2, { className: "text-xs", children: "Message" }), jsx(Input, { value: action.args?.message || '', onChange: (e) => updateEventAction(eventType, index, { args: { ...action.args, message: e.target.value } }), placeholder: "Enter message to show..." })] }))] })), action.type === 'code' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "JavaScript Code" }), jsx(Textarea, { value: action.code || '', onChange: (e) => updateEventAction(eventType, index, { code: e.target.value }), placeholder: "console.log('Action triggered');", className: "font-mono text-xs min-h-[60px]" })] })), action.type === 'custom' && (jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { className: "text-xs", children: "Custom Action Name" }), jsx(Input, { value: action.name, onChange: (e) => updateEventAction(eventType, index, { name: e.target.value }), placeholder: "myCustomAction", className: "font-mono text-sm" }), jsx("p", { className: "text-xs text-muted-foreground", children: "This will call the custom action passed to FormViewer" })] }))] }, index))), jsxs(Button, { variant: "outline", size: "sm", onClick: () => addEventAction(eventType), className: "w-full gap-2", children: [jsx(Plus, { className: "h-4 w-4" }), "Add Action"] })] })] }, eventType)))] }), jsxs(TabsContent, { value: "style", className: "space-y-4 mt-0", children: [jsxs("div", { className: "flex items-center justify-between mb-4", children: [jsx("span", { className: "text-sm font-medium", children: "For device" }), jsxs(Select, { value: field.customStyle?.deviceTarget || 'any', onValueChange: (value) => handleUpdateCustomStyle('deviceTarget', value), children: [jsx(SelectTrigger, { className: "w-32", children: jsx(SelectValue, {}) }), jsxs(SelectContent, { children: [jsx(SelectItem, { value: "any", children: "Any" }), jsx(SelectItem, { value: "mobile", children: "Mobile" }), jsx(SelectItem, { value: "tablet", children: "Tablet" }), jsx(SelectItem, { value: "desktop", children: "Desktop" })] })] })] }), jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "text-sm font-semibold", children: "Component" }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Paintbrush, { className: "h-4 w-4 text-muted-foreground" }), jsx(Label$2, { className: "text-sm w-24", children: "Class Name" }), jsx(Input, { value: field.customStyle?.inputClassName || '', onChange: (e) => handleUpdateCustomStyle('inputClassName', e.target.value), placeholder: "", className: "font-mono text-sm flex-1" }), field.customStyle?.inputClassName && (jsx(Button, { variant: "ghost", size: "icon", onClick: () => handleUpdateCustomStyle('inputClassName', ''), children: jsx(Trash2, { className: "h-4 w-4" }) }))] })] }), jsx(Separator$1, {}), jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "text-sm font-semibold", children: "Wrapper" }), jsxs("div", { className: "grid grid-cols-2 gap-3", children: [jsxs("div", { className: "space-y-1", children: [jsx(Label$2, { className: "text-xs", children: "Width" }), jsxs("div", { className: "flex gap-1", children: [jsx(Input, { type: "number", value: field.customStyle?.width?.value ?? 100, onChange: (e) => handleUpdateCustomStyle('width', {
19864
19996
  ...field.customStyle?.width,
19865
19997
  value: parseInt(e.target.value) || 100
19866
19998
  }), className: "w-16" }), jsxs(Select, { value: field.customStyle?.width?.unit || '%', onValueChange: (value) => handleUpdateCustomStyle('width', {
@@ -25034,12 +25166,12 @@ function DraggableComponent({ type, label, icon, isCollapsed }) {
25034
25166
  }
25035
25167
  const fieldCategories = {
25036
25168
  basic: { label: 'Basic Fields', types: FIELD_TYPES.filter(f => f.category === 'basic') },
25037
- selection: { label: 'Selection Fields', types: FIELD_TYPES.filter(f => f.category === 'selection') },
25038
25169
  advanced: { label: 'Advanced Fields', types: FIELD_TYPES.filter(f => f.category === 'advanced') },
25170
+ selection: { label: 'Selection Fields', types: FIELD_TYPES.filter(f => f.category === 'selection') },
25039
25171
  };
25040
25172
  function ComponentLibrary({ isCollapsed = false, onToggleCollapse }) {
25041
25173
  if (isCollapsed) {
25042
- return (jsxs("aside", { className: "w-[60px] border-r border-border bg-card shrink-0 flex flex-col", children: [jsx("div", { className: "p-2 border-b border-border", children: jsx(Button, { variant: "ghost", size: "icon", onClick: onToggleCollapse, "data-testid": "button-expand-sidebar", children: jsx(PanelLeft, { className: "h-4 w-4" }) }) }), jsx(ScrollArea, { className: "flex-1", children: jsxs("div", { className: "p-2 space-y-4", children: [jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "LY" }) }), jsx(TooltipContent, { side: "right", children: "Layout" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: STRUCTURE_TYPES.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "BF" }) }), jsx(TooltipContent, { side: "right", children: "Basic Fields" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: fieldCategories.basic.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "SF" }) }), jsx(TooltipContent, { side: "right", children: "Selection Fields" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: fieldCategories.selection.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "AD" }) }), jsx(TooltipContent, { side: "right", children: "Advanced Fields" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: fieldCategories.advanced.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "EL" }) }), jsx(TooltipContent, { side: "right", children: "Static Elements" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: STATIC_TYPES.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] })] }) })] }));
25174
+ return (jsxs("aside", { className: "w-[60px] border-r border-border bg-card shrink-0 flex flex-col", children: [jsx("div", { className: "p-2 border-b border-border", children: jsx(Button, { variant: "ghost", size: "icon", onClick: onToggleCollapse, "data-testid": "button-expand-sidebar", children: jsx(PanelLeft, { className: "h-4 w-4" }) }) }), jsx(ScrollArea, { className: "flex-1", children: jsxs("div", { className: "p-2 space-y-4", children: [jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "LY" }) }), jsx(TooltipContent, { side: "right", children: "Layout" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: STRUCTURE_TYPES.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "BF" }) }), jsx(TooltipContent, { side: "right", children: "Basic Fields" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: fieldCategories.basic.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "AD" }) }), jsx(TooltipContent, { side: "right", children: "Advanced Fields" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: fieldCategories.advanced.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "SF" }) }), jsx(TooltipContent, { side: "right", children: "Selection Fields" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: fieldCategories.selection.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] }), jsxs("div", { className: "space-y-1", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx("p", { className: "text-[10px] font-semibold uppercase text-muted-foreground text-center cursor-default", children: "EL" }) }), jsx(TooltipContent, { side: "right", children: "Static Elements" })] }), jsx("div", { className: "grid grid-cols-1 gap-1", children: STATIC_TYPES.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon, isCollapsed: true }, item.type))) })] })] }) })] }));
25043
25175
  }
25044
25176
  return (jsxs("aside", { className: "w-[200px] border-r border-border bg-card shrink-0 flex flex-col", children: [jsxs("div", { className: "p-2 border-b border-border flex items-center justify-between gap-2", children: [jsx("span", { className: "text-sm font-medium text-foreground pl-1", children: "Components" }), jsx(Button, { variant: "ghost", size: "icon", className: "h-6 w-6 shrink-0", onClick: onToggleCollapse, "data-testid": "button-collapse-sidebar", children: jsx(PanelLeftClose, { className: "h-3.5 w-3.5" }) })] }), jsx(ScrollArea, { className: "flex-1", children: jsx("div", { className: "p-2", children: jsxs(Accordion, { type: "multiple", defaultValue: ['structure', 'basic', 'selection', 'advanced', 'static'], className: "w-full", children: [jsxs(AccordionItem, { value: "structure", className: "border-b-0 bg-muted/50 rounded-md mb-1 px-2", children: [jsxs(AccordionTrigger, { className: "py-1.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground hover:no-underline", children: ["Layout (", STRUCTURE_TYPES.length, ")"] }), jsx(AccordionContent, { children: jsx("div", { className: "grid grid-cols-2 gap-1 pb-2", children: STRUCTURE_TYPES.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon }, item.type))) }) })] }), Object.entries(fieldCategories).map(([key, category]) => (jsxs(AccordionItem, { value: key, className: "border-b-0 bg-background dark:bg-card rounded-md mb-1 px-2", children: [jsxs(AccordionTrigger, { className: "py-1.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground hover:no-underline", children: [category.label.split(' ')[0], " (", category.types.length, ")"] }), jsx(AccordionContent, { children: jsx("div", { className: "grid grid-cols-2 gap-1 pb-2", children: category.types.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon }, item.type))) }) })] }, key))), jsxs(AccordionItem, { value: "static", className: "border-b-0 bg-background dark:bg-card rounded-md mb-1 px-2", children: [jsxs(AccordionTrigger, { className: "py-1.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground hover:no-underline", children: ["Attributes (", STATIC_TYPES.length, ")"] }), jsx(AccordionContent, { children: jsx("div", { className: "grid grid-cols-2 gap-1 pb-2", children: STATIC_TYPES.map((item) => (jsx(DraggableComponent, { type: item.type, label: item.label, icon: item.icon }, item.type))) }) })] })] }) }) })] }));
25045
25177
  }
@@ -28323,7 +28455,9 @@ const DropdownMenuSeparator = React.forwardRef(({ className, ...props }, ref) =>
28323
28455
  DropdownMenuSeparator.displayName = Separator2.displayName;
28324
28456
 
28325
28457
  function Toolbar({ onOpenJsonViewer }) {
28326
- const { form, setFormName, isPreviewMode, togglePreviewMode, clearForm, toggleMultiStep, saveVersion, restoreVersion, updateSubmissionConfig, undo, redo, canUndo, canRedo, canvasWidth, setCanvasWidth, } = useFormStore();
28458
+ const { form, setFormName, isPreviewMode, togglePreviewMode, clearForm, toggleMultiStep, saveVersion, restoreVersion, updateSubmissionConfig, undo, redo, canvasWidth, setCanvasWidth, historyIndex, history, } = useFormStore();
28459
+ const canUndo = historyIndex > 0;
28460
+ const canRedo = historyIndex < history.length - 1;
28327
28461
  const widthOptions = [
28328
28462
  { value: 'compact', label: 'Compact', description: '672px' },
28329
28463
  { value: 'medium', label: 'Medium', description: '896px' },
@@ -28336,6 +28470,7 @@ function Toolbar({ onOpenJsonViewer }) {
28336
28470
  const [versionDialogOpen, setVersionDialogOpen] = useState(false);
28337
28471
  const [changelog, setChangelog] = useState('');
28338
28472
  const [settingsDialogOpen, setSettingsDialogOpen] = useState(false);
28473
+ const [docsDialogOpen, setDocsDialogOpen] = useState(false);
28339
28474
  const [isDarkMode, setIsDarkMode] = useState(false);
28340
28475
  const { toast } = useToast();
28341
28476
  const toggleTheme = () => {
@@ -28432,7 +28567,101 @@ function Toolbar({ onOpenJsonViewer }) {
28432
28567
  return (jsxs("header", { className: "h-14 border-b border-border bg-card px-6 flex items-center justify-between gap-4 shrink-0", children: [jsx("div", { className: "flex items-center gap-3", children: isEditing ? (jsxs("div", { className: "flex items-center gap-2", children: [jsx(Input, { value: tempName, onChange: (e) => setTempName(e.target.value), onKeyDown: handleKeyDown, onBlur: handleSaveName, className: "h-8 w-64 text-sm font-medium", autoFocus: true, "data-testid": "input-form-name" }), jsx(Button, { size: "icon", variant: "ghost", onClick: handleSaveName, "data-testid": "button-save-name", children: jsx(Check, { className: "h-4 w-4" }) })] })) : (jsxs("div", { className: "flex items-center gap-2", children: [jsx("h1", { className: "text-lg font-semibold text-foreground", children: form.name }), jsx(Button, { size: "icon", variant: "ghost", onClick: () => {
28433
28568
  setTempName(form.name);
28434
28569
  setIsEditing(true);
28435
- }, "data-testid": "button-edit-name", children: jsx(PenLine, { className: "h-4 w-4" }) }), form.isMultiStep && (jsx(Badge, { variant: "secondary", className: "text-xs", children: "Multi-Step" })), form.currentVersion && (jsxs(Badge, { variant: "outline", className: "text-xs", children: ["v", form.currentVersion] }))] })) }), jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", onClick: undo, disabled: !canUndo(), "data-testid": "button-undo", children: jsx(Undo2, { className: "h-4 w-4" }) }) }), jsx(TooltipContent, { children: "Undo" })] }), jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", onClick: redo, disabled: !canRedo(), "data-testid": "button-redo", children: jsx(Redo2, { className: "h-4 w-4" }) }) }), jsx(TooltipContent, { children: "Redo" })] }), jsxs(DropdownMenu, { children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", "data-testid": "button-canvas-width", children: jsx(Maximize2, { className: "h-4 w-4" }) }) }) }), jsx(TooltipContent, { children: "Canvas Width" })] }), jsxs(DropdownMenuContent, { align: "end", children: [jsx(DropdownMenuLabel, { children: "Canvas Width" }), jsx(DropdownMenuSeparator, {}), widthOptions.map((option) => (jsxs(DropdownMenuItem, { onClick: () => setCanvasWidth(option.value), className: "flex justify-between gap-4", "data-testid": `menu-width-${option.value}`, children: [jsx("span", { children: option.label }), jsx("span", { className: "text-muted-foreground text-xs", children: option.description }), canvasWidth === option.value && jsx(Check, { className: "h-4 w-4 ml-2" })] }, option.value)))] })] }), jsx("div", { className: "w-px h-6 bg-border mx-1" }), jsxs(Button, { variant: "default", size: "sm", onClick: handleSaveForm, disabled: isSaving, className: "gap-2", "data-testid": "button-save-form", children: [isSaving ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : (jsx(Save, { className: "h-4 w-4" })), jsx("span", { children: "Save" })] }), jsx(Button, { variant: isPreviewMode ? 'default' : 'outline', size: "sm", onClick: togglePreviewMode, className: "gap-2", "data-testid": "button-toggle-preview", children: isPreviewMode ? (jsxs(Fragment, { children: [jsx(EyeOff, { className: "h-4 w-4" }), jsx("span", { children: "Edit" })] })) : (jsxs(Fragment, { children: [jsx(Eye, { className: "h-4 w-4" }), jsx("span", { children: "Preview" })] })) }), jsx(Button, { variant: form.isMultiStep ? 'default' : 'outline', size: "sm", onClick: toggleMultiStep, className: "gap-2", title: form.isMultiStep ? 'Switch to single page' : 'Switch to multi-step wizard', "data-testid": "button-toggle-multistep", children: jsx(Layers, { className: "h-4 w-4" }) }), jsxs(Dialog, { open: versionDialogOpen, onOpenChange: setVersionDialogOpen, children: [jsx(DialogTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-version", children: jsx(History, { className: "h-4 w-4" }) }) }), jsxs(DialogContent, { className: "max-w-md", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: "Version History" }), jsx(DialogDescription, { children: "Save snapshots and restore previous versions of your form." })] }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Save New Version" }), jsx(Textarea, { value: changelog, onChange: (e) => setChangelog(e.target.value), placeholder: "What changed in this version?", className: "min-h-[60px]" }), jsxs(Button, { onClick: handleSaveVersion, className: "w-full gap-2", size: "sm", children: [jsx(Save, { className: "h-4 w-4" }), "Save Version ", (form.currentVersion || 0) + 1] })] }), form.versions && form.versions.length > 0 && (jsx(Fragment, { children: jsxs("div", { className: "border-t pt-4", children: [jsx(Label$2, { className: "mb-2 block", children: "Previous Versions" }), jsx(ScrollArea, { className: "h-[200px]", children: jsx("div", { className: "space-y-2", children: [...form.versions].reverse().map((version) => (jsxs("div", { className: "p-3 border rounded-md space-y-2", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("span", { className: "font-medium", children: ["Version ", version.version] }), jsx(Button, { variant: "outline", size: "sm", onClick: () => handleRestoreVersion(version.id, version.version), children: "Restore" })] }), version.changelog && (jsx("p", { className: "text-sm text-muted-foreground", children: version.changelog })), jsx("p", { className: "text-xs text-muted-foreground", children: new Date(version.createdAt).toLocaleString() })] }, version.id))) }) })] }) }))] })] })] }), jsxs(Dialog, { open: settingsDialogOpen, onOpenChange: setSettingsDialogOpen, children: [jsx(DialogTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-settings", children: jsx(Settings, { className: "h-4 w-4" }) }) }), jsxs(DialogContent, { className: "max-w-lg", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: "Form Settings" }), jsx(DialogDescription, { children: "Configure submission, webhooks, and other form settings." })] }), jsx("div", { className: "space-y-6", children: jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "font-medium", children: "Submission Settings" }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { children: "Enable Submission Handler" }), jsx(Switch, { checked: form.submissionConfig?.enabled || false, onCheckedChange: (checked) => updateSubmissionConfig({ enabled: checked }) })] }), form.submissionConfig?.enabled && (jsxs(Fragment, { children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Webhook URL" }), jsx(Input, { value: form.submissionConfig?.webhookUrl || '', onChange: (e) => updateSubmissionConfig({ webhookUrl: e.target.value }), placeholder: "https://your-api.com/webhook" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Success Message" }), jsx(Input, { value: form.submissionConfig?.successMessage || '', onChange: (e) => updateSubmissionConfig({ successMessage: e.target.value }), placeholder: "Thank you for your submission!" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Redirect URL (optional)" }), jsx(Input, { value: form.submissionConfig?.redirectUrl || '', onChange: (e) => updateSubmissionConfig({ redirectUrl: e.target.value }), placeholder: "https://your-site.com/thank-you" })] })] }))] }) }), jsx(DialogFooter, { children: jsx(Button, { onClick: () => setSettingsDialogOpen(false), children: "Done" }) })] })] }), jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-more", children: jsx(FileJson, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsx(DropdownMenuLabel, { children: "Export / Import" }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuItem, { onClick: onOpenJsonViewer, children: [jsx(FileJson, { className: "h-4 w-4 mr-2" }), "View JSON Schema"] }), jsxs(DropdownMenuItem, { onClick: handleExportJson, children: [jsx(Download, { className: "h-4 w-4 mr-2" }), "Download JSON"] }), jsx(DropdownMenuItem, { asChild: true, children: jsxs("label", { className: "cursor-pointer flex items-center", children: [jsx(Upload, { className: "h-4 w-4 mr-2" }), "Import JSON", jsx("input", { type: "file", accept: ".json", onChange: handleImportJson, className: "hidden" })] }) })] })] }), jsx(Button, { variant: "outline", size: "sm", onClick: clearForm, className: "gap-2 text-destructive hover:text-destructive", "data-testid": "button-clear-form", children: jsx(Trash2, { className: "h-4 w-4" }) }), jsx("div", { className: "w-px h-6 bg-border mx-1" }), jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", onClick: toggleTheme, "data-testid": "button-toggle-theme", children: isDarkMode ? jsx(Sun, { className: "h-4 w-4" }) : jsx(Moon, { className: "h-4 w-4" }) }) }), jsx(TooltipContent, { children: isDarkMode ? 'Light Mode' : 'Dark Mode' })] })] })] }));
28570
+ }, "data-testid": "button-edit-name", children: jsx(PenLine, { className: "h-4 w-4" }) }), form.isMultiStep && (jsx(Badge, { variant: "secondary", className: "text-xs", children: "Multi-Step" })), form.currentVersion && (jsxs(Badge, { variant: "outline", className: "text-xs", children: ["v", form.currentVersion] }))] })) }), jsxs("div", { className: "flex items-center gap-2", children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", onClick: undo, disabled: !canUndo, "data-testid": "button-undo", children: jsx(Undo2, { className: "h-4 w-4" }) }) }), jsx(TooltipContent, { children: "Undo" })] }), jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", onClick: redo, disabled: !canRedo, "data-testid": "button-redo", children: jsx(Redo2, { className: "h-4 w-4" }) }) }), jsx(TooltipContent, { children: "Redo" })] }), jsxs(DropdownMenu, { children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", "data-testid": "button-canvas-width", children: jsx(Maximize2, { className: "h-4 w-4" }) }) }) }), jsx(TooltipContent, { children: "Canvas Width" })] }), jsxs(DropdownMenuContent, { align: "end", children: [jsx(DropdownMenuLabel, { children: "Canvas Width" }), jsx(DropdownMenuSeparator, {}), widthOptions.map((option) => (jsxs(DropdownMenuItem, { onClick: () => setCanvasWidth(option.value), className: "flex justify-between gap-4", "data-testid": `menu-width-${option.value}`, children: [jsx("span", { children: option.label }), jsx("span", { className: "text-muted-foreground text-xs", children: option.description }), canvasWidth === option.value && jsx(Check, { className: "h-4 w-4 ml-2" })] }, option.value)))] })] }), jsx("div", { className: "w-px h-6 bg-border mx-1" }), jsxs(Button, { variant: "default", size: "sm", onClick: handleSaveForm, disabled: isSaving, className: "gap-2", "data-testid": "button-save-form", children: [isSaving ? (jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : (jsx(Save, { className: "h-4 w-4" })), jsx("span", { children: "Save" })] }), jsx(Button, { variant: isPreviewMode ? 'default' : 'outline', size: "sm", onClick: togglePreviewMode, className: "gap-2", "data-testid": "button-toggle-preview", children: isPreviewMode ? (jsxs(Fragment, { children: [jsx(EyeOff, { className: "h-4 w-4" }), jsx("span", { children: "Edit" })] })) : (jsxs(Fragment, { children: [jsx(Eye, { className: "h-4 w-4" }), jsx("span", { children: "Preview" })] })) }), jsx(Button, { variant: form.isMultiStep ? 'default' : 'outline', size: "sm", onClick: toggleMultiStep, className: "gap-2", title: form.isMultiStep ? 'Switch to single page' : 'Switch to multi-step wizard', "data-testid": "button-toggle-multistep", children: jsx(Layers, { className: "h-4 w-4" }) }), jsxs(Dialog, { open: versionDialogOpen, onOpenChange: setVersionDialogOpen, children: [jsx(DialogTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-version", children: jsx(History, { className: "h-4 w-4" }) }) }), jsxs(DialogContent, { className: "max-w-md", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: "Version History" }), jsx(DialogDescription, { children: "Save snapshots and restore previous versions of your form." })] }), jsxs("div", { className: "space-y-4", children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Save New Version" }), jsx(Textarea, { value: changelog, onChange: (e) => setChangelog(e.target.value), placeholder: "What changed in this version?", className: "min-h-[60px]" }), jsxs(Button, { onClick: handleSaveVersion, className: "w-full gap-2", size: "sm", children: [jsx(Save, { className: "h-4 w-4" }), "Save Version ", (form.currentVersion || 0) + 1] })] }), form.versions && form.versions.length > 0 && (jsx(Fragment, { children: jsxs("div", { className: "border-t pt-4", children: [jsx(Label$2, { className: "mb-2 block", children: "Previous Versions" }), jsx(ScrollArea, { className: "h-[200px]", children: jsx("div", { className: "space-y-2", children: [...form.versions].reverse().map((version) => (jsxs("div", { className: "p-3 border rounded-md space-y-2", children: [jsxs("div", { className: "flex items-center justify-between", children: [jsxs("span", { className: "font-medium", children: ["Version ", version.version] }), jsx(Button, { variant: "outline", size: "sm", onClick: () => handleRestoreVersion(version.id, version.version), children: "Restore" })] }), version.changelog && (jsx("p", { className: "text-sm text-muted-foreground", children: version.changelog })), jsx("p", { className: "text-xs text-muted-foreground", children: new Date(version.createdAt).toLocaleString() })] }, version.id))) }) })] }) }))] })] })] }), jsxs(Dialog, { open: docsDialogOpen, onOpenChange: setDocsDialogOpen, children: [jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(DialogTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-docs", children: jsx(BookOpen, { className: "h-4 w-4" }) }) }) }), jsx(TooltipContent, { children: "Documentation" })] }), jsxs(DialogContent, { className: "max-w-4xl max-h-[85vh]", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: "FormBuilder Documentation" }), jsx(DialogDescription, { children: "Complete guide for the drag-and-drop form builder component" })] }), jsx(ScrollArea, { className: "h-[60vh] pr-4", children: jsxs("div", { className: "prose prose-sm dark:prose-invert max-w-none space-y-6", children: [jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Quick Start" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `import { FormBuilder } from '@enerjisaformlibrary/formbuilder-react';
28571
+ import '@enerjisaformlibrary/formbuilder-react/styles.css';
28572
+
28573
+ function App() {
28574
+ return (
28575
+ <FormBuilder
28576
+ onSave={(form) => saveToDatabase(JSON.stringify(form))}
28577
+ onChange={(form) => console.log('Updated:', form)}
28578
+ theme="light"
28579
+ />
28580
+ );
28581
+ }` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Field Types (20+)" }), jsxs("div", { className: "grid grid-cols-3 gap-2 text-sm", children: [jsxs("div", { children: [jsx("strong", { children: "Basic:" }), " input, textarea, number, email, password, phone, url"] }), jsxs("div", { children: [jsx("strong", { children: "Selection:" }), " dropdown, checkbox, radio, toggle, multiselect"] }), jsxs("div", { children: [jsx("strong", { children: "Date/Time:" }), " date, time, daterange"] }), jsxs("div", { children: [jsx("strong", { children: "Advanced:" }), " file, signature, rating, richtext, slider, color, autocomplete"] }), jsxs("div", { children: [jsx("strong", { children: "Static:" }), " header, label, paragraph, divider, spacer, alert, image"] }), jsxs("div", { children: [jsx("strong", { children: "Structure:" }), " button, qrcode, pattern, container"] })] })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Form Schema Structure" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `FormSchema {
28582
+ id: string;
28583
+ name: string;
28584
+ rows: FormRow[]; // Single-page mode
28585
+ steps?: FormStep[]; // Multi-step wizard mode
28586
+ isMultiStep?: boolean;
28587
+ submissionConfig?: { webhookUrl, successMessage, redirectUrl };
28588
+ }
28589
+
28590
+ FormRow → columns[] → FormColumn (width: 1-12) → fields[] → FormField` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "FormField Properties" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `FormField {
28591
+ id: string;
28592
+ type: 'input' | 'dropdown' | 'checkbox' | ...;
28593
+ props: {
28594
+ key: string; // Unique identifier for form values
28595
+ label?: string;
28596
+ placeholder?: string;
28597
+ defaultValue?: string;
28598
+ tooltip?: string; // Help text on hover
28599
+ autoFocus?: boolean; // Focus on preview mode
28600
+ hidden?: boolean;
28601
+ disabled?: boolean;
28602
+ readOnly?: boolean;
28603
+ size?: 'small' | 'medium' | 'large';
28604
+ };
28605
+ validation?: { required, minLength, maxLength, pattern, min, max };
28606
+ conditionalLogic?: { enabled, action, conditions[] };
28607
+ customStyle?: { containerClassName, labelClassName, inputClassName };
28608
+ events?: { onClick, onChange, onFocus, onBlur };
28609
+ }` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Conditional Logic" }), jsx("p", { className: "text-sm text-muted-foreground mb-2", children: "Show/hide/enable/disable fields based on other field values" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `conditionalLogic: {
28610
+ enabled: true,
28611
+ action: 'show' | 'hide' | 'enable' | 'disable' | 'require',
28612
+ conditions: [{
28613
+ field: 'country', // Target field's props.key
28614
+ operator: 'equals' | 'notEquals' | 'contains' | 'isEmpty' | ...,
28615
+ value: 'USA'
28616
+ }],
28617
+ conditionLogic: 'and' | 'or' // How to combine multiple conditions
28618
+ }` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Events & Actions" }), jsx("p", { className: "text-sm text-muted-foreground mb-2", children: "Execute actions on field interactions (preview mode only)" }), jsxs("div", { className: "text-sm mb-2", children: [jsx("strong", { children: "Available Actions:" }), jsxs("ul", { className: "list-disc list-inside mt-1", children: [jsxs("li", { children: [jsx("code", { children: "focusField" }), " - Focus another field (args: targetFieldKey)"] }), jsxs("li", { children: [jsx("code", { children: "clearField" }), " - Clear current field value"] }), jsxs("li", { children: [jsx("code", { children: "showMessage" }), " - Display alert (args: message)"] }), jsxs("li", { children: [jsx("code", { children: "reset" }), " - Reset all form values"] })] })] }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `events: {
28619
+ onChange: [{
28620
+ type: 'common',
28621
+ name: 'focusField',
28622
+ args: { targetFieldKey: 'nextField' }
28623
+ }]
28624
+ }` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Zustand Store API" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `import { useFormStore } from '@enerjisaformlibrary/formbuilder-react';
28625
+
28626
+ const {
28627
+ form, // Current FormSchema
28628
+ formValues, // Values in preview mode
28629
+ previewMode, // boolean
28630
+ loadForm, // Load existing form
28631
+ addRow, deleteRow, // Row operations
28632
+ addField, updateField, // Field operations
28633
+ setFieldValue, // Set value in preview
28634
+ getFormValues, // Get all form values
28635
+ } = useFormStore();` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Container Fields" }), jsx("p", { className: "text-sm text-muted-foreground mb-2", children: "Group fields with nested row/column structure" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `{
28636
+ type: 'container',
28637
+ props: {
28638
+ key: 'addressGroup',
28639
+ label: 'Address',
28640
+ containerConfig: {
28641
+ rows: [{
28642
+ id: 'row1',
28643
+ columns: [
28644
+ { id: 'col1', width: 6, fields: [...] },
28645
+ { id: 'col2', width: 6, fields: [...] }
28646
+ ]
28647
+ }]
28648
+ }
28649
+ }
28650
+ }` })] }), jsxs("section", { children: [jsx("h3", { className: "text-lg font-semibold border-b pb-2", children: "Multi-Step Forms" }), jsx("pre", { className: "bg-muted p-3 rounded text-xs overflow-x-auto text-foreground", children: `{
28651
+ isMultiStep: true,
28652
+ steps: [{
28653
+ id: 'step1',
28654
+ title: 'Personal Info',
28655
+ order: 0,
28656
+ rows: [...],
28657
+ validation: { validateOnNext: true }
28658
+ }, {
28659
+ id: 'step2',
28660
+ title: 'Contact',
28661
+ order: 1,
28662
+ rows: [...]
28663
+ }]
28664
+ }` })] })] }) }), jsx(DialogFooter, { children: jsx(Button, { onClick: () => setDocsDialogOpen(false), children: "Close" }) })] })] }), jsxs(Dialog, { open: settingsDialogOpen, onOpenChange: setSettingsDialogOpen, children: [jsx(DialogTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-settings", children: jsx(Settings, { className: "h-4 w-4" }) }) }), jsxs(DialogContent, { className: "max-w-lg", children: [jsxs(DialogHeader, { children: [jsx(DialogTitle, { children: "Form Settings" }), jsx(DialogDescription, { children: "Configure submission, webhooks, and other form settings." })] }), jsx("div", { className: "space-y-6", children: jsxs("div", { className: "space-y-4", children: [jsx("h4", { className: "font-medium", children: "Submission Settings" }), jsxs("div", { className: "flex items-center justify-between", children: [jsx(Label$2, { children: "Enable Submission Handler" }), jsx(Switch, { checked: form.submissionConfig?.enabled || false, onCheckedChange: (checked) => updateSubmissionConfig({ enabled: checked }) })] }), form.submissionConfig?.enabled && (jsxs(Fragment, { children: [jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Webhook URL" }), jsx(Input, { value: form.submissionConfig?.webhookUrl || '', onChange: (e) => updateSubmissionConfig({ webhookUrl: e.target.value }), placeholder: "https://your-api.com/webhook" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Success Message" }), jsx(Input, { value: form.submissionConfig?.successMessage || '', onChange: (e) => updateSubmissionConfig({ successMessage: e.target.value }), placeholder: "Thank you for your submission!" })] }), jsxs("div", { className: "space-y-2", children: [jsx(Label$2, { children: "Redirect URL (optional)" }), jsx(Input, { value: form.submissionConfig?.redirectUrl || '', onChange: (e) => updateSubmissionConfig({ redirectUrl: e.target.value }), placeholder: "https://your-site.com/thank-you" })] })] }))] }) }), jsx(DialogFooter, { children: jsx(Button, { onClick: () => setSettingsDialogOpen(false), children: "Done" }) })] })] }), jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsx(Button, { variant: "outline", size: "sm", className: "gap-2", "data-testid": "button-more", children: jsx(FileJson, { className: "h-4 w-4" }) }) }), jsxs(DropdownMenuContent, { align: "end", children: [jsx(DropdownMenuLabel, { children: "Export / Import" }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuItem, { onClick: onOpenJsonViewer, children: [jsx(FileJson, { className: "h-4 w-4 mr-2" }), "View JSON Schema"] }), jsxs(DropdownMenuItem, { onClick: handleExportJson, children: [jsx(Download, { className: "h-4 w-4 mr-2" }), "Download JSON"] }), jsx(DropdownMenuItem, { asChild: true, children: jsxs("label", { className: "cursor-pointer flex items-center", children: [jsx(Upload, { className: "h-4 w-4 mr-2" }), "Import JSON", jsx("input", { type: "file", accept: ".json", onChange: handleImportJson, className: "hidden" })] }) })] })] }), jsx(Button, { variant: "outline", size: "sm", onClick: clearForm, className: "gap-2 text-destructive hover:text-destructive", "data-testid": "button-clear-form", children: jsx(Trash2, { className: "h-4 w-4" }) }), jsx("div", { className: "w-px h-6 bg-border mx-1" }), jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsx(Button, { variant: "ghost", size: "icon", onClick: toggleTheme, "data-testid": "button-toggle-theme", children: isDarkMode ? jsx(Sun, { className: "h-4 w-4" }) : jsx(Moon, { className: "h-4 w-4" }) }) }), jsx(TooltipContent, { children: isDarkMode ? 'Light Mode' : 'Dark Mode' })] })] })] }));
28436
28665
  }
28437
28666
 
28438
28667
  const iconMap = {