form-builder-pro 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4112,17 +4112,17 @@ var FIELD_TYPES = [
4112
4112
  { type: "file", label: "File Upload", icon: "Upload" }
4113
4113
  ];
4114
4114
  var DEFAULT_FIELD_CONFIG = {
4115
- text: { label: "Text Input", placeholder: "Enter text...", width: "100%" },
4116
- textarea: { label: "Text Area", placeholder: "Enter description...", width: "100%" },
4117
- number: { label: "Number", placeholder: "0", width: "50%" },
4118
- email: { label: "Email", placeholder: "example@email.com", width: "100%", validation: [{ type: "email", message: "Invalid email" }] },
4119
- phone: { label: "Phone", placeholder: "+1 234 567 8900", width: "100%" },
4120
- date: { label: "Date", width: "50%" },
4121
- select: { label: "Dropdown", options: [{ label: "Option 1", value: "opt1" }, { label: "Option 2", value: "opt2" }], width: "100%" },
4122
- checkbox: { label: "Checkbox", width: "100%" },
4123
- radio: { label: "Radio Group", options: [{ label: "Option 1", value: "opt1" }, { label: "Option 2", value: "opt2" }], width: "100%" },
4124
- toggle: { label: "Toggle", width: "50%" },
4125
- file: { label: "File Upload", width: "100%" }
4115
+ text: { label: "Text Input", placeholder: "Enter text...", width: "100%", enabled: true, visible: true },
4116
+ textarea: { label: "Text Area", placeholder: "Enter description...", width: "100%", enabled: true, visible: true },
4117
+ number: { label: "Number", placeholder: "0", width: "50%", enabled: true, visible: true },
4118
+ email: { label: "Email", placeholder: "example@email.com", width: "100%", validation: [{ type: "email", message: "Invalid email" }], enabled: true, visible: true },
4119
+ phone: { label: "Phone", placeholder: "+1 234 567 8900", width: "100%", enabled: true, visible: true },
4120
+ date: { label: "Date", width: "50%", enabled: true, visible: true },
4121
+ select: { label: "Dropdown", options: [{ label: "Option 1", value: "opt1" }, { label: "Option 2", value: "opt2" }], width: "100%", enabled: true, visible: true },
4122
+ checkbox: { label: "Checkbox", width: "100%", enabled: true, visible: true },
4123
+ radio: { label: "Radio Group", options: [{ label: "Option 1", value: "opt1" }, { label: "Option 2", value: "opt2" }], width: "100%", enabled: true, visible: true },
4124
+ toggle: { label: "Toggle", width: "50%", enabled: true, visible: true },
4125
+ file: { label: "File Upload", width: "100%", enabled: true, visible: true }
4126
4126
  };
4127
4127
 
4128
4128
  // src/utils/clone.ts
@@ -4157,13 +4157,7 @@ var INITIAL_SCHEMA = {
4157
4157
  id: "form_1",
4158
4158
  title: "My New Form",
4159
4159
  formName: "myNewForm",
4160
- sections: [
4161
- {
4162
- id: generateId(),
4163
- title: "Section 1",
4164
- fields: []
4165
- }
4166
- ]
4160
+ sections: []
4167
4161
  };
4168
4162
  var formStore = createStore((set, get) => ({
4169
4163
  schema: INITIAL_SCHEMA,
@@ -4173,11 +4167,13 @@ var formStore = createStore((set, get) => ({
4173
4167
  isPreviewMode: false,
4174
4168
  existingForms: [],
4175
4169
  templates: [],
4170
+ masterTypes: [],
4176
4171
  setSchema: (schema) => set({ schema }),
4177
4172
  togglePreview: () => set((state) => ({ isPreviewMode: !state.isPreviewMode })),
4178
4173
  // New Actions
4179
4174
  setExistingForms: (forms) => set({ existingForms: forms }),
4180
4175
  setTemplates: (templates) => set({ templates }),
4176
+ setMasterTypes: (masterTypes) => set({ masterTypes }),
4181
4177
  loadForm: (formId) => {
4182
4178
  const { existingForms, history, historyIndex } = get();
4183
4179
  const found = existingForms.find((f) => f.id === formId);
@@ -4272,20 +4268,39 @@ var formStore = createStore((set, get) => ({
4272
4268
  type,
4273
4269
  ...DEFAULT_FIELD_CONFIG[type]
4274
4270
  };
4271
+ let newSections = [...schema.sections];
4272
+ if (newSections.length === 0 || sectionId === null) {
4273
+ const defaultSection = {
4274
+ id: generateId(),
4275
+ title: "Default Section",
4276
+ fields: [],
4277
+ columns: 1
4278
+ };
4279
+ newSections.push(defaultSection);
4280
+ sectionId = defaultSection.id;
4281
+ }
4282
+ const sectionIndex = newSections.findIndex((s) => s.id === sectionId);
4283
+ if (sectionIndex !== -1) {
4284
+ const section = newSections[sectionIndex];
4285
+ const newFields = [...section.fields];
4286
+ if (typeof index2 === "number") {
4287
+ newFields.splice(index2, 0, newField);
4288
+ } else {
4289
+ newFields.push(newField);
4290
+ }
4291
+ newSections[sectionIndex] = { ...section, fields: newFields };
4292
+ } else {
4293
+ const defaultSection = {
4294
+ id: generateId(),
4295
+ title: "Default Section",
4296
+ fields: [newField],
4297
+ columns: 1
4298
+ };
4299
+ newSections.push(defaultSection);
4300
+ }
4275
4301
  const newSchema = {
4276
4302
  ...schema,
4277
- sections: schema.sections.map((s) => {
4278
- if (s.id === sectionId) {
4279
- const newFields = [...s.fields];
4280
- if (typeof index2 === "number") {
4281
- newFields.splice(index2, 0, newField);
4282
- } else {
4283
- newFields.push(newField);
4284
- }
4285
- return { ...s, fields: newFields };
4286
- }
4287
- return s;
4288
- })
4303
+ sections: newSections
4289
4304
  };
4290
4305
  set({
4291
4306
  schema: newSchema,
@@ -4341,6 +4356,16 @@ var formStore = createStore((set, get) => ({
4341
4356
  });
4342
4357
  if (!field)
4343
4358
  return;
4359
+ if (targetSectionId === null || newSections.length === 0) {
4360
+ const defaultSection = {
4361
+ id: generateId(),
4362
+ title: "Default Section",
4363
+ fields: [],
4364
+ columns: 1
4365
+ };
4366
+ newSections.push(defaultSection);
4367
+ targetSectionId = defaultSection.id;
4368
+ }
4344
4369
  const targetSectionIndex = newSections.findIndex((s) => s.id === targetSectionId);
4345
4370
  if (targetSectionIndex !== -1) {
4346
4371
  const targetSection = newSections[targetSectionIndex];
@@ -4499,6 +4524,7 @@ function getIcon(name, size = 20) {
4499
4524
  var FieldRenderer = class {
4500
4525
  static render(field, value, onChange, readOnly = false) {
4501
4526
  const wrapper = createElement("div", { className: "w-full" });
4527
+ const isEnabled = field.enabled !== false && !readOnly;
4502
4528
  if (field.type !== "checkbox") {
4503
4529
  const label = createElement("label", {
4504
4530
  className: "text-xs sm:text-sm font-medium leading-none mb-2 block text-gray-900 dark:text-gray-100",
@@ -4525,7 +4551,7 @@ var FieldRenderer = class {
4525
4551
  className: "flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm sm:text-base ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
4526
4552
  placeholder: field.placeholder,
4527
4553
  value: value || "",
4528
- disabled: readOnly,
4554
+ disabled: !isEnabled,
4529
4555
  oninput: (e) => onChange?.(e.target.value)
4530
4556
  });
4531
4557
  break;
@@ -4533,7 +4559,7 @@ var FieldRenderer = class {
4533
4559
  input = createElement("select", {
4534
4560
  className: "flex min-h-touch w-full rounded-md border border-input bg-background px-3 py-2 text-sm sm:text-base ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
4535
4561
  value: value || "",
4536
- disabled: readOnly,
4562
+ disabled: !isEnabled,
4537
4563
  onchange: (e) => onChange?.(e.target.value)
4538
4564
  });
4539
4565
  input.appendChild(createElement("option", { value: "", text: "Select an option", disabled: true, selected: !value }));
@@ -4547,7 +4573,7 @@ var FieldRenderer = class {
4547
4573
  type: "checkbox",
4548
4574
  className: "h-5 w-5 sm:h-6 sm:w-6 rounded border-gray-300 text-primary focus:ring-primary cursor-pointer",
4549
4575
  checked: !!value,
4550
- disabled: readOnly,
4576
+ disabled: !isEnabled,
4551
4577
  onchange: (e) => onChange?.(e.target.checked)
4552
4578
  });
4553
4579
  input.appendChild(checkbox);
@@ -4561,7 +4587,7 @@ var FieldRenderer = class {
4561
4587
  name: field.id,
4562
4588
  value: opt.value,
4563
4589
  checked: value === opt.value,
4564
- disabled: readOnly,
4590
+ disabled: !isEnabled,
4565
4591
  className: "aspect-square h-4 w-4 sm:h-5 sm:w-5 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
4566
4592
  onchange: (e) => onChange?.(e.target.value)
4567
4593
  });
@@ -4580,7 +4606,7 @@ var FieldRenderer = class {
4580
4606
  className: "flex min-h-touch w-full rounded-md border border-input bg-background px-3 py-2 text-sm sm:text-base ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
4581
4607
  placeholder: field.placeholder,
4582
4608
  value: value || "",
4583
- disabled: readOnly,
4609
+ disabled: !isEnabled,
4584
4610
  oninput: (e) => onChange?.(e.target.value)
4585
4611
  });
4586
4612
  }
@@ -4617,6 +4643,10 @@ var FormRenderer = class {
4617
4643
  sectionEl.appendChild(createElement("h2", { className: "text-lg md:text-xl font-semibold text-gray-800 dark:text-gray-200 border-b pb-2", text: section.title }));
4618
4644
  const grid = createElement("div", { className: "form-builder-grid" });
4619
4645
  section.fields.forEach((field) => {
4646
+ const isVisible = field.visible !== false;
4647
+ if (!isVisible) {
4648
+ return;
4649
+ }
4620
4650
  const fieldWrapper = createElement("div");
4621
4651
  let spanClass = "col-span-12";
4622
4652
  if (field.width === "50%")
@@ -6902,6 +6932,266 @@ Sortable.mount(new AutoScrollPlugin());
6902
6932
  Sortable.mount(Remove, Revert);
6903
6933
  var sortable_esm_default = Sortable;
6904
6934
 
6935
+ // src/builder/FieldWrapper.ts
6936
+ var FieldWrapper = class {
6937
+ static render(field, isSelected) {
6938
+ const isVisible = field.visible !== false;
6939
+ let spanClass = "col-span-12";
6940
+ if (field.width === "50%")
6941
+ spanClass = "col-span-6";
6942
+ else if (field.width === "33%")
6943
+ spanClass = "col-span-4";
6944
+ else if (field.width === "25%")
6945
+ spanClass = "col-span-3";
6946
+ else if (field.width === "66%")
6947
+ spanClass = "col-span-8";
6948
+ else if (field.width === "75%")
6949
+ spanClass = "col-span-9";
6950
+ const fieldWrapper = createElement("div", {
6951
+ className: `form-builder-field-wrapper ${isSelected ? "selected-field" : ""} ${spanClass} relative group border border-transparent hover:border-blue-200 rounded-md transition-all ${!isVisible ? "hidden" : ""}`,
6952
+ "data-id": field.id,
6953
+ onclick: (e) => {
6954
+ e.stopPropagation();
6955
+ formStore.getState().selectField(field.id);
6956
+ }
6957
+ });
6958
+ if (isSelected) {
6959
+ fieldWrapper.classList.add("ring-2", "ring-blue-500", "bg-blue-50", "dark:bg-blue-900/20");
6960
+ }
6961
+ fieldWrapper.appendChild(createElement("div", {
6962
+ className: `absolute top-2 left-2 cursor-move p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity field-handle z-10 ${isSelected ? "opacity-100" : ""}`
6963
+ }, [getIcon("GripVertical", 16)]));
6964
+ fieldWrapper.appendChild(createElement("button", {
6965
+ className: `absolute top-2 right-2 p-1 rounded hover:bg-red-50 text-red-400 hover:text-red-600 opacity-0 group-hover:opacity-100 transition-opacity z-10 ${isSelected ? "opacity-100" : ""}`,
6966
+ onclick: (e) => {
6967
+ e.stopPropagation();
6968
+ if (confirm("Delete this field?")) {
6969
+ formStore.getState().removeField(field.id);
6970
+ }
6971
+ }
6972
+ }, [getIcon("Trash2", 16)]));
6973
+ const content = createElement("div", { className: "p-4 pointer-events-none" });
6974
+ content.appendChild(FieldRenderer.render(field, null, void 0, true));
6975
+ fieldWrapper.appendChild(content);
6976
+ return fieldWrapper;
6977
+ }
6978
+ };
6979
+
6980
+ // src/builder/Section.ts
6981
+ var Section = class {
6982
+ constructor(section, isSelectedField) {
6983
+ __publicField(this, "container");
6984
+ __publicField(this, "section");
6985
+ __publicField(this, "isSelectedField");
6986
+ this.section = section;
6987
+ this.isSelectedField = isSelectedField;
6988
+ this.container = this.render();
6989
+ }
6990
+ getElement() {
6991
+ return this.container;
6992
+ }
6993
+ render() {
6994
+ const sectionEl = createElement("div", {
6995
+ className: "mb-6 rounded-lg border bg-white dark:bg-gray-900 shadow-sm transition-all border-gray-200 dark:border-gray-800",
6996
+ "data-id": this.section.id
6997
+ });
6998
+ const header = createElement("div", { className: "flex items-center justify-between p-2 border-b border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 rounded-t-lg" });
6999
+ const headerLeft = createElement("div", { className: "flex items-center flex-1" });
7000
+ headerLeft.appendChild(createElement("div", { className: "cursor-move mr-3 text-gray-400 hover:text-gray-600 section-handle" }, [getIcon("GripVertical", 20)]));
7001
+ headerLeft.appendChild(createElement("input", {
7002
+ className: "bg-transparent font-semibold text-gray-700 dark:text-gray-200 focus:outline-none focus:border-b border-blue-500",
7003
+ value: this.section.title,
7004
+ "data-focus-id": `section-title-${this.section.id}`,
7005
+ oninput: (e) => formStore.getState().updateSection(this.section.id, { title: e.target.value })
7006
+ }));
7007
+ header.appendChild(headerLeft);
7008
+ const actions = createElement("div", { className: "flex items-center space-x-1" });
7009
+ const colSelect = createElement("select", {
7010
+ className: "text-xs border rounded bg-transparent mr-2 p-1 text-gray-600",
7011
+ title: "Section Columns",
7012
+ onchange: (e) => {
7013
+ formStore.getState().updateSection(this.section.id, { columns: parseInt(e.target.value) });
7014
+ }
7015
+ });
7016
+ [1, 2, 3].forEach((c) => {
7017
+ colSelect.appendChild(createElement("option", { value: c.toString(), text: `${c} Col`, selected: (this.section.columns || 1) === c }));
7018
+ });
7019
+ actions.appendChild(colSelect);
7020
+ actions.appendChild(createElement("button", {
7021
+ className: "text-gray-600 hover:text-red-500 transition-colors p-1",
7022
+ onclick: () => {
7023
+ if (confirm("Delete this section and all its fields?")) {
7024
+ formStore.getState().removeSection(this.section.id);
7025
+ }
7026
+ }
7027
+ }, [getIcon("Trash2", 18)]));
7028
+ header.appendChild(actions);
7029
+ sectionEl.appendChild(header);
7030
+ const fieldsGrid = createElement("div", {
7031
+ className: "form-builder-grid p-4 min-h-[100px] fields-list",
7032
+ "data-section-id": this.section.id
7033
+ });
7034
+ if (this.section.fields.length === 0) {
7035
+ fieldsGrid.classList.add("flex", "justify-center", "items-center", "border-2", "border-dashed", "border-gray-100", "dark:border-gray-800", "m-4", "rounded");
7036
+ fieldsGrid.appendChild(createElement("div", { className: "text-gray-400 text-sm py-4", text: "Drop fields here" }));
7037
+ }
7038
+ this.section.fields.forEach((field) => {
7039
+ const isSelected = this.isSelectedField(field.id);
7040
+ fieldsGrid.appendChild(FieldWrapper.render(field, isSelected));
7041
+ });
7042
+ sectionEl.appendChild(fieldsGrid);
7043
+ this.initFieldSortable(fieldsGrid);
7044
+ return sectionEl;
7045
+ }
7046
+ initFieldSortable(element) {
7047
+ new sortable_esm_default(element, {
7048
+ group: {
7049
+ name: "shared-fields",
7050
+ put: ["shared-fields", "shared-templates"]
7051
+ // Allow dropping templates to merge fields
7052
+ },
7053
+ handle: ".field-handle",
7054
+ animation: 150,
7055
+ ghostClass: "bg-blue-50",
7056
+ // Class to apply to the drag ghost
7057
+ onAdd: (evt) => {
7058
+ const item = evt.item;
7059
+ const type = item.getAttribute("data-type");
7060
+ evt.from.getAttribute("data-section-id");
7061
+ const toSectionId = this.section.id;
7062
+ if (type && !item.hasAttribute("data-id")) {
7063
+ item.remove();
7064
+ if (type === "template-section") {
7065
+ const templateId = item.getAttribute("data-template-id");
7066
+ const templates = formStore.getState().templates;
7067
+ const template = templates.find((t) => t.id === templateId);
7068
+ if (template) {
7069
+ formStore.getState().addTemplateFields(toSectionId, template, evt.newIndex);
7070
+ }
7071
+ return;
7072
+ }
7073
+ formStore.getState().addField(toSectionId, type, evt.newIndex);
7074
+ } else {
7075
+ const fieldId = item.getAttribute("data-id");
7076
+ if (fieldId) {
7077
+ formStore.getState().moveField(fieldId, toSectionId, evt.newIndex);
7078
+ item.remove();
7079
+ }
7080
+ }
7081
+ },
7082
+ onUpdate: (evt) => {
7083
+ const item = evt.item;
7084
+ const fieldId = item.getAttribute("data-id");
7085
+ if (fieldId && evt.newIndex !== void 0) {
7086
+ formStore.getState().moveField(fieldId, this.section.id, evt.newIndex);
7087
+ }
7088
+ }
7089
+ });
7090
+ }
7091
+ };
7092
+
7093
+ // src/builder/SectionList.ts
7094
+ var SectionList = class {
7095
+ constructor(schema, selectedFieldId) {
7096
+ __publicField(this, "container");
7097
+ __publicField(this, "schema");
7098
+ __publicField(this, "selectedFieldId");
7099
+ this.schema = schema;
7100
+ this.selectedFieldId = selectedFieldId;
7101
+ this.container = this.render();
7102
+ }
7103
+ getElement() {
7104
+ return this.container;
7105
+ }
7106
+ render() {
7107
+ const listContainer = createElement("div", {
7108
+ className: "space-y-6 min-h-[200px] pb-20",
7109
+ // pb-20 for extra scrolling space
7110
+ id: "sections-list",
7111
+ "data-drop-zone": "sections"
7112
+ });
7113
+ const hasNoSections = this.schema.sections.length === 0;
7114
+ if (hasNoSections) {
7115
+ const placeholder = createElement("div", {
7116
+ className: "border-2 border-dashed border-gray-300 dark:border-gray-700 rounded-lg p-8 text-center text-gray-500 flex flex-col items-center justify-center min-h-[200px] bg-gray-50 dark:bg-gray-800/50 empty-fields-dropzone",
7117
+ id: "empty-fields-dropzone"
7118
+ });
7119
+ placeholder.appendChild(createElement("div", { className: "font-medium mb-2", text: "Start Building Your Form" }));
7120
+ placeholder.appendChild(createElement("div", { className: "text-sm text-gray-400", text: 'Drag fields from the sidebar or click "Add Section" below.' }));
7121
+ listContainer.appendChild(placeholder);
7122
+ }
7123
+ this.schema.sections.forEach((section) => {
7124
+ const sectionComponent = new Section(section, (id) => id === this.selectedFieldId);
7125
+ listContainer.appendChild(sectionComponent.getElement());
7126
+ });
7127
+ this.initSectionSortable(listContainer, hasNoSections);
7128
+ return listContainer;
7129
+ }
7130
+ initSectionSortable(element, hasNoSections) {
7131
+ if (hasNoSections) {
7132
+ const emptyDropzone = element.querySelector("#empty-fields-dropzone");
7133
+ if (emptyDropzone) {
7134
+ new sortable_esm_default(emptyDropzone, {
7135
+ group: {
7136
+ name: "shared-fields",
7137
+ put: ["shared-fields", "shared-templates"]
7138
+ },
7139
+ animation: 150,
7140
+ ghostClass: "bg-blue-50",
7141
+ onAdd: (evt) => {
7142
+ const item = evt.item;
7143
+ const type = item.getAttribute("data-type");
7144
+ const templateId = item.getAttribute("data-template-id");
7145
+ item.remove();
7146
+ if (templateId) {
7147
+ const templates = formStore.getState().templates;
7148
+ const template = templates.find((t) => t.id === templateId);
7149
+ if (template) {
7150
+ formStore.getState().importSection(template);
7151
+ }
7152
+ } else if (type && !item.hasAttribute("data-id")) {
7153
+ formStore.getState().addField(null, type, evt.newIndex);
7154
+ } else {
7155
+ const fieldId = item.getAttribute("data-id");
7156
+ if (fieldId) {
7157
+ formStore.getState().moveField(fieldId, null, evt.newIndex || 0);
7158
+ }
7159
+ }
7160
+ }
7161
+ });
7162
+ }
7163
+ } else {
7164
+ new sortable_esm_default(element, {
7165
+ group: {
7166
+ name: "shared-sections",
7167
+ put: ["shared-templates"]
7168
+ // Allow dropping templates here
7169
+ },
7170
+ handle: ".section-handle",
7171
+ animation: 150,
7172
+ ghostClass: "opacity-50",
7173
+ onAdd: (evt) => {
7174
+ const item = evt.item;
7175
+ const templateId = item.getAttribute("data-template-id");
7176
+ if (templateId) {
7177
+ const templates = formStore.getState().templates;
7178
+ const template = templates.find((t) => t.id === templateId);
7179
+ item.remove();
7180
+ if (template) {
7181
+ formStore.getState().importSection(template);
7182
+ }
7183
+ }
7184
+ },
7185
+ onUpdate: (evt) => {
7186
+ if (evt.oldIndex !== void 0 && evt.newIndex !== void 0) {
7187
+ formStore.getState().moveSection(evt.oldIndex, evt.newIndex);
7188
+ }
7189
+ }
7190
+ });
7191
+ }
7192
+ }
7193
+ };
7194
+
6905
7195
  // src/builder/FormBuilder.ts
6906
7196
  var FormBuilder = class {
6907
7197
  constructor(container, options = {}) {
@@ -6935,6 +7225,9 @@ var FormBuilder = class {
6935
7225
  if (options.formJson) {
6936
7226
  formStore.getState().setSchema(options.formJson);
6937
7227
  } else if (options.mode === "create") ;
7228
+ if (options.data?.masterTypes) {
7229
+ formStore.getState().setMasterTypes(options.data.masterTypes);
7230
+ }
6938
7231
  this.render();
6939
7232
  this.setupSubscriptions();
6940
7233
  }
@@ -7039,7 +7332,7 @@ var FormBuilder = class {
7039
7332
  }, 0);
7040
7333
  }
7041
7334
  if (!state.isPreviewMode) {
7042
- this.initSortable();
7335
+ this.initSidebarSortables();
7043
7336
  }
7044
7337
  }
7045
7338
  renderToolbar(state) {
@@ -7236,98 +7529,8 @@ var FormBuilder = class {
7236
7529
  oninput: (e) => formStore.getState().setSchema({ ...state.schema, formName: e.target.value })
7237
7530
  });
7238
7531
  inner.appendChild(formNameInput);
7239
- const sectionsContainer = createElement("div", {
7240
- className: "space-y-6 min-h-[200px]",
7241
- id: "sections-list",
7242
- "data-drop-zone": "sections"
7243
- });
7244
- state.schema.sections.forEach((section) => {
7245
- const sectionEl = createElement("div", {
7246
- className: "mb-6 rounded-lg border bg-white dark:bg-gray-900 shadow-sm transition-all border-gray-200 dark:border-gray-800",
7247
- "data-id": section.id
7248
- });
7249
- const header = createElement("div", { className: "flex items-center justify-between p-2 border-b border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 rounded-t-lg" });
7250
- const headerLeft = createElement("div", { className: "flex items-center flex-1" });
7251
- headerLeft.appendChild(createElement("div", { className: "cursor-move mr-3 text-gray-400 hover:text-gray-600 section-handle" }, [getIcon("GripVertical", 20)]));
7252
- headerLeft.appendChild(createElement("input", {
7253
- className: "bg-transparent font-semibold text-gray-700 dark:text-gray-200 focus:outline-none focus:border-b border-blue-500",
7254
- value: section.title,
7255
- "data-focus-id": `section-title-${section.id}`,
7256
- oninput: (e) => formStore.getState().updateSection(section.id, { title: e.target.value })
7257
- }));
7258
- header.appendChild(headerLeft);
7259
- const actions = createElement("div", { className: "flex items-center space-x-1" });
7260
- const colSelect = createElement("select", {
7261
- className: "text-xs border rounded bg-transparent mr-2 p-1 text-gray-600",
7262
- title: "Section Columns",
7263
- onchange: (e) => {
7264
- formStore.getState().updateSection(section.id, { columns: parseInt(e.target.value) });
7265
- }
7266
- });
7267
- [1, 2, 3].forEach((c) => {
7268
- colSelect.appendChild(createElement("option", { value: c.toString(), text: `${c} Col`, selected: (section.columns || 1) === c }));
7269
- });
7270
- actions.appendChild(colSelect);
7271
- actions.appendChild(createElement("button", {
7272
- className: "text-gray-600 hover:text-blue-500 transition-colors p-1",
7273
- title: "Save as Template",
7274
- onclick: () => {
7275
- const name = prompt("Enter template name:", section.title);
7276
- if (name) {
7277
- this.saveSectionAsTemplate({ ...section, title: name });
7278
- }
7279
- }
7280
- }, [getIcon("Save", 18)]));
7281
- actions.appendChild(createElement("button", {
7282
- className: "text-gray-600 hover:text-red-500 transition-colors p-1",
7283
- onclick: () => formStore.getState().removeSection(section.id)
7284
- }, [getIcon("Trash2", 18)]));
7285
- header.appendChild(actions);
7286
- sectionEl.appendChild(header);
7287
- const fieldsGrid = createElement("div", {
7288
- className: "form-builder-grid p-4 min-h-[100px] fields-list",
7289
- "data-section-id": section.id
7290
- });
7291
- section.fields.forEach((field) => {
7292
- const isSelected = state.selectedFieldId === field.id;
7293
- let spanClass = "col-span-12";
7294
- if (field.width === "50%")
7295
- spanClass = "col-span-6";
7296
- else if (field.width === "33%")
7297
- spanClass = "col-span-4";
7298
- else if (field.width === "25%")
7299
- spanClass = "col-span-3";
7300
- else if (field.width === "66%")
7301
- spanClass = "col-span-8";
7302
- else if (field.width === "75%")
7303
- spanClass = "col-span-9";
7304
- const fieldWrapper = createElement("div", {
7305
- className: `form-builder-field-wrapper ${isSelected ? "selected-field" : ""} ${spanClass}`,
7306
- "data-id": field.id,
7307
- onclick: (e) => {
7308
- e.stopPropagation();
7309
- formStore.getState().selectField(field.id);
7310
- }
7311
- });
7312
- fieldWrapper.appendChild(createElement("div", {
7313
- className: `absolute top-2 left-2 cursor-move p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-400 opacity-0 group-hover:opacity-100 transition-opacity field-handle ${isSelected ? "opacity-100" : ""}`
7314
- }, [getIcon("GripVertical", 16)]));
7315
- fieldWrapper.appendChild(createElement("button", {
7316
- className: `absolute top-2 right-2 p-1 rounded hover:bg-red-50 text-red-400 hover:text-red-600 opacity-0 group-hover:opacity-100 transition-opacity ${isSelected ? "opacity-100" : ""}`,
7317
- onclick: (e) => {
7318
- e.stopPropagation();
7319
- formStore.getState().removeField(field.id);
7320
- }
7321
- }, [getIcon("Trash2", 16)]));
7322
- const content = createElement("div", { className: "p-4 pointer-events-none" });
7323
- content.appendChild(FieldRenderer.render(field, null, void 0, true));
7324
- fieldWrapper.appendChild(content);
7325
- fieldsGrid.appendChild(fieldWrapper);
7326
- });
7327
- sectionEl.appendChild(fieldsGrid);
7328
- sectionsContainer.appendChild(sectionEl);
7329
- });
7330
- inner.appendChild(sectionsContainer);
7532
+ const sectionList = new SectionList(state.schema, state.selectedFieldId);
7533
+ inner.appendChild(sectionList.getElement());
7331
7534
  const addSectionBtn = createElement("button", {
7332
7535
  className: "w-full mt-6 py-4 border-2 border-dashed border-gray-300 dark:border-gray-700 rounded-lg text-gray-500 hover:border-blue-500 hover:text-blue-500 transition-colors flex items-center justify-center font-medium",
7333
7536
  onclick: () => formStore.getState().addSection()
@@ -7389,6 +7592,68 @@ var FormBuilder = class {
7389
7592
  onchange: (e) => formStore.getState().updateField(selectedField.id, { required: e.target.checked })
7390
7593
  }));
7391
7594
  body.appendChild(requiredGroup);
7595
+ const enabledGroup = createElement("div", { className: "flex items-center justify-between mb-4" });
7596
+ enabledGroup.appendChild(createElement("label", { className: "text-sm text-gray-700 dark:text-gray-300", text: "Enabled" }));
7597
+ enabledGroup.appendChild(createElement("input", {
7598
+ type: "checkbox",
7599
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500",
7600
+ checked: selectedField.enabled !== false,
7601
+ // Default to true if not specified
7602
+ onchange: (e) => formStore.getState().updateField(selectedField.id, { enabled: e.target.checked })
7603
+ }));
7604
+ body.appendChild(enabledGroup);
7605
+ const visibleGroup = createElement("div", { className: "flex items-center justify-between mb-4" });
7606
+ visibleGroup.appendChild(createElement("label", { className: "text-sm text-gray-700 dark:text-gray-300", text: "Visible" }));
7607
+ visibleGroup.appendChild(createElement("input", {
7608
+ type: "checkbox",
7609
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500",
7610
+ checked: selectedField.visible !== false,
7611
+ // Default to true if not specified
7612
+ onchange: (e) => formStore.getState().updateField(selectedField.id, { visible: e.target.checked })
7613
+ }));
7614
+ body.appendChild(visibleGroup);
7615
+ if (selectedField.type === "select") {
7616
+ const masterTypes = formStore.getState().masterTypes;
7617
+ const activeMasterTypes = masterTypes.filter((mt) => mt.active === true);
7618
+ if (activeMasterTypes.length > 0) {
7619
+ const groupNameGroup = createElement("div", { className: "mb-4" });
7620
+ groupNameGroup.appendChild(createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", text: "Group Name" }));
7621
+ const groupNameSelect = createElement("select", {
7622
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-transparent",
7623
+ onchange: (e) => {
7624
+ const selectedValue = e.target.value;
7625
+ if (selectedValue) {
7626
+ const selectedMasterType = activeMasterTypes.find((mt) => mt.id === selectedValue || mt.name === selectedValue);
7627
+ if (selectedMasterType) {
7628
+ formStore.getState().updateField(selectedField.id, {
7629
+ groupName: {
7630
+ id: selectedMasterType.id,
7631
+ name: selectedMasterType.name
7632
+ }
7633
+ });
7634
+ }
7635
+ } else {
7636
+ formStore.getState().updateField(selectedField.id, { groupName: void 0 });
7637
+ }
7638
+ }
7639
+ });
7640
+ groupNameSelect.appendChild(createElement("option", {
7641
+ value: "",
7642
+ text: "None",
7643
+ selected: !selectedField.groupName
7644
+ }));
7645
+ activeMasterTypes.forEach((mt) => {
7646
+ const isSelected = selectedField.groupName && (selectedField.groupName.id === mt.id || selectedField.groupName.name === mt.name);
7647
+ groupNameSelect.appendChild(createElement("option", {
7648
+ value: mt.id || mt.name,
7649
+ text: mt.displayName || mt.name,
7650
+ selected: !!isSelected
7651
+ }));
7652
+ });
7653
+ groupNameGroup.appendChild(groupNameSelect);
7654
+ body.appendChild(groupNameGroup);
7655
+ }
7656
+ }
7392
7657
  const validationHeader = createElement("h3", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3 mt-6", text: "Validation Rules" });
7393
7658
  body.appendChild(validationHeader);
7394
7659
  const validations = selectedField.validation || [];
@@ -7515,12 +7780,13 @@ var FormBuilder = class {
7515
7780
  panel.appendChild(body);
7516
7781
  return panel;
7517
7782
  }
7518
- initSortable() {
7783
+ initSidebarSortables() {
7519
7784
  const toolboxList = document.getElementById("toolbox-list");
7520
7785
  if (toolboxList) {
7521
7786
  new sortable_esm_default(toolboxList, {
7522
7787
  group: {
7523
- name: "shared",
7788
+ name: "shared-fields",
7789
+ // Matches the group in Section.ts
7524
7790
  pull: "clone",
7525
7791
  put: false
7526
7792
  },
@@ -7532,7 +7798,7 @@ var FormBuilder = class {
7532
7798
  if (templatesList) {
7533
7799
  new sortable_esm_default(templatesList, {
7534
7800
  group: {
7535
- name: "shared",
7801
+ name: "shared-templates",
7536
7802
  pull: "clone",
7537
7803
  put: false
7538
7804
  },
@@ -7542,85 +7808,6 @@ var FormBuilder = class {
7542
7808
  forceFallback: true
7543
7809
  });
7544
7810
  }
7545
- const sectionsList = document.getElementById("sections-list");
7546
- if (sectionsList) {
7547
- new sortable_esm_default(sectionsList, {
7548
- group: "shared",
7549
- handle: ".section-handle",
7550
- animation: 150,
7551
- onAdd: (evt) => {
7552
- const item = evt.item;
7553
- const templateId = item.getAttribute("data-template-id");
7554
- const isTemplate = item.getAttribute("data-type") === "template-section";
7555
- if (templateId && isTemplate) {
7556
- const templates = formStore.getState().templates;
7557
- const template = templates.find((t) => t.id === templateId);
7558
- if (template) {
7559
- item.remove();
7560
- formStore.getState().importSection(template);
7561
- return;
7562
- }
7563
- }
7564
- },
7565
- onEnd: (evt) => {
7566
- const item = evt.item;
7567
- const templateId = item.getAttribute("data-template-id");
7568
- const isTemplate = item.getAttribute("data-type") === "template-section";
7569
- if (!templateId && !isTemplate && evt.oldIndex !== void 0 && evt.newIndex !== void 0 && evt.oldIndex !== evt.newIndex) {
7570
- formStore.getState().moveSection(evt.oldIndex, evt.newIndex);
7571
- }
7572
- }
7573
- });
7574
- }
7575
- const fieldLists = document.querySelectorAll(".fields-list");
7576
- fieldLists.forEach((list) => {
7577
- new sortable_esm_default(list, {
7578
- group: "shared",
7579
- handle: ".field-handle",
7580
- animation: 150,
7581
- onAdd: (evt) => {
7582
- const item = evt.item;
7583
- const type = item.getAttribute("data-type");
7584
- const sectionId = list.getAttribute("data-section-id");
7585
- if (type && sectionId) {
7586
- if (type === "template-section") {
7587
- const templateId = item.getAttribute("data-template-id");
7588
- const templates = formStore.getState().templates;
7589
- const template = templates.find((t) => t.id === templateId);
7590
- item.remove();
7591
- if (template) {
7592
- formStore.getState().addTemplateFields(sectionId, template, evt.newIndex);
7593
- }
7594
- return;
7595
- }
7596
- item.remove();
7597
- formStore.getState().addField(sectionId, type, evt.newIndex);
7598
- } else if (sectionId) {
7599
- item.getAttribute("data-id");
7600
- }
7601
- },
7602
- onUpdate: (evt) => {
7603
- const item = evt.item;
7604
- const fieldId = item.getAttribute("data-id");
7605
- const sectionId = list.getAttribute("data-section-id");
7606
- if (fieldId && sectionId && evt.newIndex !== void 0) {
7607
- formStore.getState().moveField(fieldId, sectionId, evt.newIndex);
7608
- }
7609
- },
7610
- onEnd: (evt) => {
7611
- const item = evt.item;
7612
- const fromList = evt.from;
7613
- const toList = evt.to;
7614
- if (fromList !== toList && fromList.classList.contains("fields-list") && toList.classList.contains("fields-list")) {
7615
- const fieldId = item.getAttribute("data-id");
7616
- const targetSectionId = toList.getAttribute("data-section-id");
7617
- if (fieldId && targetSectionId && evt.newIndex !== void 0) {
7618
- formStore.getState().moveField(fieldId, targetSectionId, evt.newIndex);
7619
- }
7620
- }
7621
- }
7622
- });
7623
- });
7624
7811
  }
7625
7812
  };
7626
7813