form-builder-pro 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1114 @@
1
+ import React, { useState } from 'react';
2
+ import ReactDOM from 'react-dom/client';
3
+ import { defaultDropAnimationSideEffects, useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, closestCorners, DragOverlay, useDroppable, useDraggable } from '@dnd-kit/core';
4
+ import { sortableKeyboardCoordinates, useSortable, SortableContext, rectSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
5
+ import { create } from 'zustand';
6
+ import * as Icons from 'lucide-react';
7
+ import { Undo, Redo, Trash2, Eye, Save, GripVertical, Plus, X } from 'lucide-react';
8
+ import { clsx } from 'clsx';
9
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
+ import { CSS } from '@dnd-kit/utilities';
11
+ import { createPortal } from 'react-dom';
12
+
13
+ var __defProp = Object.defineProperty;
14
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
15
+ var __publicField = (obj, key, value) => {
16
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
17
+ return value;
18
+ };
19
+
20
+ // src/core/constants.ts
21
+ var generateId = () => Math.random().toString(36).substring(2, 9);
22
+ var FIELD_TYPES = [
23
+ { type: "text", label: "Text Input", icon: "Type" },
24
+ { type: "textarea", label: "Text Area", icon: "AlignLeft" },
25
+ { type: "number", label: "Number", icon: "Hash" },
26
+ { type: "email", label: "Email", icon: "Mail" },
27
+ { type: "phone", label: "Phone", icon: "Phone" },
28
+ { type: "date", label: "Date Picker", icon: "Calendar" },
29
+ { type: "select", label: "Dropdown", icon: "ChevronDown" },
30
+ { type: "checkbox", label: "Checkbox", icon: "CheckSquare" },
31
+ { type: "radio", label: "Radio Group", icon: "CircleDot" },
32
+ { type: "toggle", label: "Toggle", icon: "ToggleLeft" },
33
+ // Lucide icon names, will be mapped later
34
+ { type: "file", label: "File Upload", icon: "Upload" }
35
+ ];
36
+ var DEFAULT_FIELD_CONFIG = {
37
+ text: { label: "Text Input", placeholder: "Enter text...", width: "100%" },
38
+ textarea: { label: "Text Area", placeholder: "Enter description...", width: "100%" },
39
+ number: { label: "Number", placeholder: "0", width: "50%" },
40
+ email: { label: "Email", placeholder: "example@email.com", width: "100%", validation: [{ type: "email", message: "Invalid email" }] },
41
+ phone: { label: "Phone", placeholder: "+1 234 567 8900", width: "100%" },
42
+ date: { label: "Date", width: "50%" },
43
+ select: { label: "Dropdown", options: [{ label: "Option 1", value: "opt1" }, { label: "Option 2", value: "opt2" }], width: "100%" },
44
+ checkbox: { label: "Checkbox", width: "100%" },
45
+ radio: { label: "Radio Group", options: [{ label: "Option 1", value: "opt1" }, { label: "Option 2", value: "opt2" }], width: "100%" },
46
+ toggle: { label: "Toggle", width: "50%" },
47
+ file: { label: "File Upload", width: "100%" }
48
+ };
49
+
50
+ // src/core/useFormStore.ts
51
+ var INITIAL_SCHEMA = {
52
+ id: "form_1",
53
+ title: "My New Form",
54
+ sections: [
55
+ {
56
+ id: generateId(),
57
+ title: "Section 1",
58
+ fields: []
59
+ }
60
+ ]
61
+ };
62
+ var useFormStore = create((set, get) => ({
63
+ schema: INITIAL_SCHEMA,
64
+ selectedFieldId: null,
65
+ history: [INITIAL_SCHEMA],
66
+ historyIndex: 0,
67
+ isPreviewMode: false,
68
+ setSchema: (schema) => set({ schema }),
69
+ togglePreview: () => set((state) => ({ isPreviewMode: !state.isPreviewMode })),
70
+ addSection: () => {
71
+ const { schema, history, historyIndex } = get();
72
+ const newSection = {
73
+ id: generateId(),
74
+ title: `Section ${schema.sections.length + 1}`,
75
+ fields: []
76
+ };
77
+ const newSchema = { ...schema, sections: [...schema.sections, newSection] };
78
+ set({
79
+ schema: newSchema,
80
+ history: [...history.slice(0, historyIndex + 1), newSchema],
81
+ historyIndex: historyIndex + 1
82
+ });
83
+ },
84
+ removeSection: (sectionId) => {
85
+ const { schema, history, historyIndex } = get();
86
+ const newSchema = {
87
+ ...schema,
88
+ sections: schema.sections.filter((s) => s.id !== sectionId)
89
+ };
90
+ set({
91
+ schema: newSchema,
92
+ history: [...history.slice(0, historyIndex + 1), newSchema],
93
+ historyIndex: historyIndex + 1
94
+ });
95
+ },
96
+ updateSection: (sectionId, updates) => {
97
+ const { schema, history, historyIndex } = get();
98
+ const newSchema = {
99
+ ...schema,
100
+ sections: schema.sections.map(
101
+ (s) => s.id === sectionId ? { ...s, ...updates } : s
102
+ )
103
+ };
104
+ set({
105
+ schema: newSchema,
106
+ history: [...history.slice(0, historyIndex + 1), newSchema],
107
+ historyIndex: historyIndex + 1
108
+ });
109
+ },
110
+ moveSection: (activeId, overId) => {
111
+ const { schema, history, historyIndex } = get();
112
+ const oldIndex = schema.sections.findIndex((s) => s.id === activeId);
113
+ const newIndex = schema.sections.findIndex((s) => s.id === overId);
114
+ if (oldIndex === -1 || newIndex === -1 || oldIndex === newIndex)
115
+ return;
116
+ const newSections = [...schema.sections];
117
+ const [movedSection] = newSections.splice(oldIndex, 1);
118
+ newSections.splice(newIndex, 0, movedSection);
119
+ const newSchema = { ...schema, sections: newSections };
120
+ set({
121
+ schema: newSchema,
122
+ history: [...history.slice(0, historyIndex + 1), newSchema],
123
+ historyIndex: historyIndex + 1
124
+ });
125
+ },
126
+ addField: (sectionId, type, index) => {
127
+ const { schema, history, historyIndex } = get();
128
+ const newField = {
129
+ id: generateId(),
130
+ type,
131
+ ...DEFAULT_FIELD_CONFIG[type]
132
+ };
133
+ const newSchema = {
134
+ ...schema,
135
+ sections: schema.sections.map((s) => {
136
+ if (s.id === sectionId) {
137
+ const newFields = [...s.fields];
138
+ if (typeof index === "number") {
139
+ newFields.splice(index, 0, newField);
140
+ } else {
141
+ newFields.push(newField);
142
+ }
143
+ return { ...s, fields: newFields };
144
+ }
145
+ return s;
146
+ })
147
+ };
148
+ set({
149
+ schema: newSchema,
150
+ selectedFieldId: newField.id,
151
+ history: [...history.slice(0, historyIndex + 1), newSchema],
152
+ historyIndex: historyIndex + 1
153
+ });
154
+ },
155
+ removeField: (fieldId) => {
156
+ const { schema, history, historyIndex } = get();
157
+ const newSchema = {
158
+ ...schema,
159
+ sections: schema.sections.map((s) => ({
160
+ ...s,
161
+ fields: s.fields.filter((f) => f.id !== fieldId)
162
+ }))
163
+ };
164
+ set({
165
+ schema: newSchema,
166
+ selectedFieldId: null,
167
+ history: [...history.slice(0, historyIndex + 1), newSchema],
168
+ historyIndex: historyIndex + 1
169
+ });
170
+ },
171
+ updateField: (fieldId, updates) => {
172
+ const { schema, history, historyIndex } = get();
173
+ const newSchema = {
174
+ ...schema,
175
+ sections: schema.sections.map((s) => ({
176
+ ...s,
177
+ fields: s.fields.map((f) => f.id === fieldId ? { ...f, ...updates } : f)
178
+ }))
179
+ };
180
+ set({
181
+ schema: newSchema,
182
+ history: [...history.slice(0, historyIndex + 1), newSchema],
183
+ historyIndex: historyIndex + 1
184
+ });
185
+ },
186
+ selectField: (fieldId) => set({ selectedFieldId: fieldId }),
187
+ moveField: (activeId, overId, activeSectionId, overSectionId) => {
188
+ const { schema, history, historyIndex } = get();
189
+ const newSections = schema.sections.map((s) => ({
190
+ ...s,
191
+ fields: [...s.fields]
192
+ }));
193
+ const activeSectionIndex = newSections.findIndex((s) => s.id === activeSectionId);
194
+ const overSectionIndex = newSections.findIndex((s) => s.id === overSectionId);
195
+ if (activeSectionIndex === -1 || overSectionIndex === -1)
196
+ return;
197
+ const activeSection = newSections[activeSectionIndex];
198
+ const overSection = newSections[overSectionIndex];
199
+ const activeFieldIndex = activeSection.fields.findIndex((f) => f.id === activeId);
200
+ const overFieldIndex = overSection.fields.findIndex((f) => f.id === overId);
201
+ if (activeFieldIndex === -1)
202
+ return;
203
+ if (activeSectionId === overSectionId) {
204
+ if (activeFieldIndex === overFieldIndex)
205
+ return;
206
+ const [movedField] = activeSection.fields.splice(activeFieldIndex, 1);
207
+ activeSection.fields.splice(overFieldIndex, 0, movedField);
208
+ } else {
209
+ const [movedField] = activeSection.fields.splice(activeFieldIndex, 1);
210
+ if (overId === overSectionId) {
211
+ overSection.fields.push(movedField);
212
+ } else {
213
+ const insertIndex = overFieldIndex >= 0 ? overFieldIndex : overSection.fields.length;
214
+ overSection.fields.splice(insertIndex, 0, movedField);
215
+ }
216
+ }
217
+ const newSchema = { ...schema, sections: newSections };
218
+ set({
219
+ schema: newSchema,
220
+ history: [...history.slice(0, historyIndex + 1), newSchema],
221
+ historyIndex: historyIndex + 1
222
+ });
223
+ },
224
+ undo: () => {
225
+ const { history, historyIndex } = get();
226
+ if (historyIndex > 0) {
227
+ set({
228
+ schema: history[historyIndex - 1],
229
+ historyIndex: historyIndex - 1
230
+ });
231
+ }
232
+ },
233
+ redo: () => {
234
+ const { history, historyIndex } = get();
235
+ if (historyIndex < history.length - 1) {
236
+ set({
237
+ schema: history[historyIndex + 1],
238
+ historyIndex: historyIndex + 1
239
+ });
240
+ }
241
+ },
242
+ canUndo: () => get().historyIndex > 0,
243
+ canRedo: () => get().historyIndex < get().history.length - 1
244
+ }));
245
+ var Toolbar = () => {
246
+ const { undo, redo, canUndo, canRedo, setSchema, togglePreview, isPreviewMode } = useFormStore();
247
+ const handleSave = () => {
248
+ const schema = useFormStore.getState().schema;
249
+ console.log("Saved Schema:", JSON.stringify(schema, null, 2));
250
+ alert("Schema saved to console!");
251
+ };
252
+ const handleClear = () => {
253
+ if (confirm("Are you sure you want to clear the form?")) {
254
+ setSchema({
255
+ id: "form_" + Date.now(),
256
+ title: "New Form",
257
+ sections: []
258
+ });
259
+ }
260
+ };
261
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b bg-white dark:bg-gray-900 border-gray-200 dark:border-gray-800", children: [
262
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
263
+ /* @__PURE__ */ jsx("h1", { className: "text-xl font-bold bg-gradient-to-r from-blue-600 to-indigo-600 bg-clip-text text-transparent mr-4", children: "FormBuilder Pro" }),
264
+ /* @__PURE__ */ jsx(
265
+ "button",
266
+ {
267
+ onClick: undo,
268
+ disabled: !canUndo(),
269
+ className: "p-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
270
+ title: "Undo",
271
+ children: /* @__PURE__ */ jsx(Undo, { size: 18 })
272
+ }
273
+ ),
274
+ /* @__PURE__ */ jsx(
275
+ "button",
276
+ {
277
+ onClick: redo,
278
+ disabled: !canRedo(),
279
+ className: "p-2 rounded hover:bg-gray-100 dark:hover:bg-gray-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
280
+ title: "Redo",
281
+ children: /* @__PURE__ */ jsx(Redo, { size: 18 })
282
+ }
283
+ )
284
+ ] }),
285
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
286
+ /* @__PURE__ */ jsxs(
287
+ "button",
288
+ {
289
+ onClick: handleClear,
290
+ className: "flex items-center px-3 py-2 text-sm font-medium text-red-600 hover:bg-red-50 rounded-md transition-colors",
291
+ children: [
292
+ /* @__PURE__ */ jsx(Trash2, { size: 16, className: "mr-2" }),
293
+ "Clear"
294
+ ]
295
+ }
296
+ ),
297
+ /* @__PURE__ */ jsxs(
298
+ "button",
299
+ {
300
+ onClick: togglePreview,
301
+ className: clsx(
302
+ "flex items-center px-3 py-2 text-sm font-medium rounded-md transition-colors",
303
+ isPreviewMode ? "bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200" : "text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800"
304
+ ),
305
+ children: [
306
+ /* @__PURE__ */ jsx(Eye, { size: 16, className: "mr-2" }),
307
+ isPreviewMode ? "Edit" : "Preview"
308
+ ]
309
+ }
310
+ ),
311
+ /* @__PURE__ */ jsxs(
312
+ "button",
313
+ {
314
+ onClick: handleSave,
315
+ className: "flex items-center px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-md shadow-sm transition-colors",
316
+ children: [
317
+ /* @__PURE__ */ jsx(Save, { size: 16, className: "mr-2" }),
318
+ "Save"
319
+ ]
320
+ }
321
+ )
322
+ ] })
323
+ ] });
324
+ };
325
+ var getIcon = (name) => {
326
+ const Icon = Icons[name];
327
+ return Icon ? /* @__PURE__ */ jsx(Icon, { size: 16 }) : null;
328
+ };
329
+ var ToolboxItem = ({ type, label, icon }) => {
330
+ const { attributes, listeners, setNodeRef, transform } = useDraggable({
331
+ id: `toolbox-${type}`,
332
+ data: {
333
+ type: "toolbox-item",
334
+ fieldType: type
335
+ }
336
+ });
337
+ const style = transform ? {
338
+ transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`
339
+ } : void 0;
340
+ return /* @__PURE__ */ jsxs(
341
+ "div",
342
+ {
343
+ ref: setNodeRef,
344
+ ...listeners,
345
+ ...attributes,
346
+ style,
347
+ className: "flex items-center p-3 mb-2 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-md cursor-move hover:border-blue-500 hover:shadow-sm transition-all",
348
+ children: [
349
+ /* @__PURE__ */ jsx("span", { className: "mr-3 text-gray-500 dark:text-gray-400", children: getIcon(icon) }),
350
+ /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-200", children: label })
351
+ ]
352
+ }
353
+ );
354
+ };
355
+ var FieldToolbox = () => {
356
+ return /* @__PURE__ */ jsxs("div", { className: "w-64 bg-gray-50 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-800 p-4 overflow-y-auto h-full", children: [
357
+ /* @__PURE__ */ jsx("h2", { className: "text-xs font-semibold text-gray-500 uppercase tracking-wider mb-4", children: "Form Fields" }),
358
+ /* @__PURE__ */ jsx("div", { className: "space-y-1", children: FIELD_TYPES.map((field) => /* @__PURE__ */ jsx(
359
+ ToolboxItem,
360
+ {
361
+ type: field.type,
362
+ label: field.label,
363
+ icon: field.icon
364
+ },
365
+ field.type
366
+ )) })
367
+ ] });
368
+ };
369
+ var FieldRenderer = ({ field, value, onChange, readOnly, error }) => {
370
+ const baseInputClass = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm 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";
371
+ const renderInput = () => {
372
+ switch (field.type) {
373
+ case "text":
374
+ case "email":
375
+ case "phone":
376
+ case "number":
377
+ case "date":
378
+ case "file":
379
+ return /* @__PURE__ */ jsx(
380
+ "input",
381
+ {
382
+ type: field.type === "phone" ? "tel" : field.type,
383
+ id: field.id,
384
+ placeholder: field.placeholder,
385
+ className: baseInputClass,
386
+ value: value || "",
387
+ onChange: (e) => onChange?.(e.target.value),
388
+ disabled: readOnly
389
+ }
390
+ );
391
+ case "textarea":
392
+ return /* @__PURE__ */ jsx(
393
+ "textarea",
394
+ {
395
+ id: field.id,
396
+ placeholder: field.placeholder,
397
+ className: clsx(baseInputClass, "min-h-[80px]"),
398
+ value: value || "",
399
+ onChange: (e) => onChange?.(e.target.value),
400
+ disabled: readOnly
401
+ }
402
+ );
403
+ case "select":
404
+ return /* @__PURE__ */ jsxs(
405
+ "select",
406
+ {
407
+ id: field.id,
408
+ className: baseInputClass,
409
+ value: value || "",
410
+ onChange: (e) => onChange?.(e.target.value),
411
+ disabled: readOnly,
412
+ children: [
413
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Select an option" }),
414
+ field.options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
415
+ ]
416
+ }
417
+ );
418
+ case "checkbox":
419
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center h-10", children: /* @__PURE__ */ jsx(
420
+ "input",
421
+ {
422
+ type: "checkbox",
423
+ id: field.id,
424
+ className: "h-5 w-5 rounded border-gray-300 text-primary focus:ring-primary cursor-pointer",
425
+ checked: !!value,
426
+ onChange: (e) => onChange?.(e.target.checked),
427
+ disabled: readOnly
428
+ }
429
+ ) });
430
+ case "radio":
431
+ return /* @__PURE__ */ jsx("div", { className: "space-y-2", children: field.options?.map((opt) => /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
432
+ /* @__PURE__ */ jsx(
433
+ "input",
434
+ {
435
+ type: "radio",
436
+ id: `${field.id}-${opt.value}`,
437
+ name: field.id,
438
+ value: opt.value,
439
+ checked: value === opt.value,
440
+ onChange: (e) => onChange?.(e.target.value),
441
+ disabled: readOnly,
442
+ className: "aspect-square h-4 w-4 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"
443
+ }
444
+ ),
445
+ /* @__PURE__ */ jsx("label", { htmlFor: `${field.id}-${opt.value}`, className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", children: opt.label })
446
+ ] }, opt.value)) });
447
+ case "toggle":
448
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center space-x-2", children: /* @__PURE__ */ jsx(
449
+ "button",
450
+ {
451
+ type: "button",
452
+ role: "switch",
453
+ "aria-checked": !!value,
454
+ onClick: () => !readOnly && onChange?.(!value),
455
+ className: clsx(
456
+ "peer inline-flex h-[24px] w-[44px] shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
457
+ value ? "bg-primary" : "bg-input"
458
+ ),
459
+ disabled: readOnly,
460
+ children: /* @__PURE__ */ jsx(
461
+ "span",
462
+ {
463
+ className: clsx(
464
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform",
465
+ value ? "translate-x-5" : "translate-x-0"
466
+ )
467
+ }
468
+ )
469
+ }
470
+ ) });
471
+ default:
472
+ return /* @__PURE__ */ jsxs("div", { className: "text-red-500", children: [
473
+ "Unknown field type: ",
474
+ field.type
475
+ ] });
476
+ }
477
+ };
478
+ return /* @__PURE__ */ jsxs("div", { className: "w-full", children: [
479
+ /* @__PURE__ */ jsxs("label", { htmlFor: field.id, className: "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 mb-2 block text-gray-900 dark:text-gray-100", children: [
480
+ field.label,
481
+ field.required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", children: "*" })
482
+ ] }),
483
+ renderInput(),
484
+ field.description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground mt-1", children: field.description }),
485
+ error && /* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-destructive mt-1", children: error })
486
+ ] });
487
+ };
488
+ var SortableField = ({ field }) => {
489
+ const {
490
+ attributes,
491
+ listeners,
492
+ setNodeRef,
493
+ transform,
494
+ transition,
495
+ isDragging
496
+ } = useSortable({
497
+ id: field.id,
498
+ data: {
499
+ type: "field",
500
+ field
501
+ }
502
+ });
503
+ const { selectField, selectedFieldId, removeField } = useFormStore();
504
+ const isSelected = selectedFieldId === field.id;
505
+ const style = {
506
+ transform: CSS.Transform.toString(transform),
507
+ transition,
508
+ gridColumn: field.width === "100%" ? "span 4" : field.width === "50%" ? "span 2" : "span 1"
509
+ };
510
+ return /* @__PURE__ */ jsxs(
511
+ "div",
512
+ {
513
+ ref: setNodeRef,
514
+ style,
515
+ className: clsx(
516
+ "relative group rounded-lg border-2 transition-all bg-white dark:bg-gray-800",
517
+ isSelected ? "border-blue-500 ring-2 ring-blue-200" : "border-transparent hover:border-gray-300 dark:hover:border-gray-600",
518
+ isDragging && "opacity-50 z-50"
519
+ ),
520
+ onClick: (e) => {
521
+ e.stopPropagation();
522
+ selectField(field.id);
523
+ },
524
+ children: [
525
+ /* @__PURE__ */ jsx(
526
+ "div",
527
+ {
528
+ ...attributes,
529
+ ...listeners,
530
+ className: clsx(
531
+ "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",
532
+ isSelected && "opacity-100"
533
+ ),
534
+ children: /* @__PURE__ */ jsx(GripVertical, { size: 16 })
535
+ }
536
+ ),
537
+ /* @__PURE__ */ jsx(
538
+ "button",
539
+ {
540
+ onClick: (e) => {
541
+ e.stopPropagation();
542
+ removeField(field.id);
543
+ },
544
+ className: clsx(
545
+ "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",
546
+ isSelected && "opacity-100"
547
+ ),
548
+ children: /* @__PURE__ */ jsx(Trash2, { size: 16 })
549
+ }
550
+ ),
551
+ /* @__PURE__ */ jsx("div", { className: "p-4 pointer-events-none", children: /* @__PURE__ */ jsx(FieldRenderer, { field, readOnly: true }) })
552
+ ]
553
+ }
554
+ );
555
+ };
556
+ var SortableSection = ({ section }) => {
557
+ const {
558
+ attributes,
559
+ listeners,
560
+ setNodeRef,
561
+ transform,
562
+ transition,
563
+ isDragging
564
+ } = useSortable({
565
+ id: section.id,
566
+ data: {
567
+ type: "section",
568
+ section
569
+ }
570
+ });
571
+ const { removeSection, updateSection } = useFormStore();
572
+ const { setNodeRef: setDroppableNodeRef } = useDroppable({
573
+ id: section.id,
574
+ data: {
575
+ type: "section",
576
+ section
577
+ }
578
+ });
579
+ const style = {
580
+ transform: CSS.Transform.toString(transform),
581
+ transition
582
+ };
583
+ return /* @__PURE__ */ jsxs(
584
+ "div",
585
+ {
586
+ ref: setNodeRef,
587
+ style,
588
+ className: clsx(
589
+ "mb-6 rounded-lg border bg-white dark:bg-gray-900 shadow-sm transition-all",
590
+ isDragging ? "opacity-50 z-50 border-blue-500" : "border-gray-200 dark:border-gray-800"
591
+ ),
592
+ children: [
593
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b border-gray-100 dark:border-gray-800 bg-gray-50 dark:bg-gray-800/50 rounded-t-lg", children: [
594
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center flex-1", children: [
595
+ /* @__PURE__ */ jsx(
596
+ "div",
597
+ {
598
+ ...attributes,
599
+ ...listeners,
600
+ className: "cursor-move mr-3 text-gray-400 hover:text-gray-600",
601
+ children: /* @__PURE__ */ jsx(GripVertical, { size: 20 })
602
+ }
603
+ ),
604
+ /* @__PURE__ */ jsx(
605
+ "input",
606
+ {
607
+ value: section.title,
608
+ onChange: (e) => updateSection(section.id, { title: e.target.value }),
609
+ className: "bg-transparent font-semibold text-gray-700 dark:text-gray-200 focus:outline-none focus:border-b border-blue-500",
610
+ placeholder: "Section Title"
611
+ }
612
+ )
613
+ ] }),
614
+ /* @__PURE__ */ jsx(
615
+ "button",
616
+ {
617
+ onClick: () => removeSection(section.id),
618
+ className: "text-gray-400 hover:text-red-500 transition-colors p-1",
619
+ children: /* @__PURE__ */ jsx(Trash2, { size: 18 })
620
+ }
621
+ )
622
+ ] }),
623
+ /* @__PURE__ */ jsxs(
624
+ "div",
625
+ {
626
+ ref: setDroppableNodeRef,
627
+ className: "p-4 min-h-[100px] grid grid-cols-4 gap-4",
628
+ children: [
629
+ /* @__PURE__ */ jsx(
630
+ SortableContext,
631
+ {
632
+ items: section.fields.map((f) => f.id),
633
+ strategy: rectSortingStrategy,
634
+ children: section.fields.map((field) => /* @__PURE__ */ jsx(SortableField, { field }, field.id))
635
+ }
636
+ ),
637
+ section.fields.length === 0 && /* @__PURE__ */ jsx("div", { className: "col-span-4 flex flex-col items-center justify-center py-8 border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-lg text-gray-400", children: /* @__PURE__ */ jsx("p", { className: "text-sm", children: "Drop fields here" }) })
638
+ ]
639
+ }
640
+ )
641
+ ]
642
+ }
643
+ );
644
+ };
645
+ var Canvas = () => {
646
+ const { schema, addSection, selectField } = useFormStore();
647
+ const { setNodeRef } = useDroppable({
648
+ id: "canvas",
649
+ data: {
650
+ type: "canvas"
651
+ }
652
+ });
653
+ return /* @__PURE__ */ jsx(
654
+ "div",
655
+ {
656
+ className: "flex-1 bg-gray-100 dark:bg-gray-950 p-8 overflow-y-auto h-full",
657
+ onClick: () => selectField(null),
658
+ children: /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto", children: [
659
+ /* @__PURE__ */ jsx("div", { className: "mb-8 text-center", children: /* @__PURE__ */ jsx(
660
+ "input",
661
+ {
662
+ value: schema.title,
663
+ onChange: (e) => useFormStore.getState().setSchema({ ...schema, title: e.target.value }),
664
+ className: "text-3xl font-bold text-center bg-transparent border-none focus:outline-none focus:ring-0 w-full text-gray-900 dark:text-white",
665
+ placeholder: "Form Title"
666
+ }
667
+ ) }),
668
+ /* @__PURE__ */ jsx("div", { ref: setNodeRef, className: "space-y-6 min-h-[200px]", children: /* @__PURE__ */ jsx(
669
+ SortableContext,
670
+ {
671
+ items: schema.sections.map((s) => s.id),
672
+ strategy: verticalListSortingStrategy,
673
+ children: schema.sections.map((section) => /* @__PURE__ */ jsx(SortableSection, { section }, section.id))
674
+ }
675
+ ) }),
676
+ /* @__PURE__ */ jsxs(
677
+ "button",
678
+ {
679
+ onClick: addSection,
680
+ 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",
681
+ children: [
682
+ /* @__PURE__ */ jsx(Plus, { size: 20, className: "mr-2" }),
683
+ "Add Section"
684
+ ]
685
+ }
686
+ )
687
+ ] })
688
+ }
689
+ );
690
+ };
691
+ var FieldConfigPanel = () => {
692
+ const { schema, selectedFieldId, updateField, selectField } = useFormStore();
693
+ const selectedField = React.useMemo(() => {
694
+ if (!selectedFieldId)
695
+ return null;
696
+ for (const section of schema.sections) {
697
+ const field = section.fields.find((f) => f.id === selectedFieldId);
698
+ if (field)
699
+ return field;
700
+ }
701
+ return null;
702
+ }, [schema, selectedFieldId]);
703
+ if (!selectedField) {
704
+ return /* @__PURE__ */ jsx("div", { className: "w-80 bg-white dark:bg-gray-900 border-l border-gray-200 dark:border-gray-800 p-6 flex flex-col items-center justify-center text-center text-gray-500", children: /* @__PURE__ */ jsx("p", { children: "Select a field to configure its properties" }) });
705
+ }
706
+ return /* @__PURE__ */ jsxs("div", { className: "w-80 bg-white dark:bg-gray-900 border-l border-gray-200 dark:border-gray-800 flex flex-col h-full", children: [
707
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-800", children: [
708
+ /* @__PURE__ */ jsx("h2", { className: "font-semibold text-gray-900 dark:text-white", children: "Field Settings" }),
709
+ /* @__PURE__ */ jsx("button", { onClick: () => selectField(null), className: "text-gray-500 hover:text-gray-700", children: /* @__PURE__ */ jsx(X, { size: 20 }) })
710
+ ] }),
711
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 overflow-y-auto p-4 space-y-6", children: [
712
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
713
+ /* @__PURE__ */ jsxs("div", { children: [
714
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Label" }),
715
+ /* @__PURE__ */ jsx(
716
+ "input",
717
+ {
718
+ type: "text",
719
+ value: selectedField.label,
720
+ onChange: (e) => updateField(selectedField.id, { label: e.target.value }),
721
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-transparent"
722
+ }
723
+ )
724
+ ] }),
725
+ /* @__PURE__ */ jsxs("div", { children: [
726
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Placeholder" }),
727
+ /* @__PURE__ */ jsx(
728
+ "input",
729
+ {
730
+ type: "text",
731
+ value: selectedField.placeholder || "",
732
+ onChange: (e) => updateField(selectedField.id, { placeholder: e.target.value }),
733
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-transparent"
734
+ }
735
+ )
736
+ ] }),
737
+ /* @__PURE__ */ jsxs("div", { children: [
738
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Description" }),
739
+ /* @__PURE__ */ jsx(
740
+ "textarea",
741
+ {
742
+ value: selectedField.description || "",
743
+ onChange: (e) => updateField(selectedField.id, { description: e.target.value }),
744
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-transparent",
745
+ rows: 2
746
+ }
747
+ )
748
+ ] })
749
+ ] }),
750
+ /* @__PURE__ */ jsx("hr", { className: "border-gray-200 dark:border-gray-800" }),
751
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
752
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Layout" }),
753
+ /* @__PURE__ */ jsxs("div", { children: [
754
+ /* @__PURE__ */ jsx("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1", children: "Width" }),
755
+ /* @__PURE__ */ jsxs(
756
+ "select",
757
+ {
758
+ value: selectedField.width,
759
+ onChange: (e) => updateField(selectedField.id, { width: e.target.value }),
760
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md bg-transparent",
761
+ children: [
762
+ /* @__PURE__ */ jsx("option", { value: "25%", children: "25% (1/4)" }),
763
+ /* @__PURE__ */ jsx("option", { value: "50%", children: "50% (1/2)" }),
764
+ /* @__PURE__ */ jsx("option", { value: "100%", children: "100% (Full)" })
765
+ ]
766
+ }
767
+ )
768
+ ] })
769
+ ] }),
770
+ /* @__PURE__ */ jsx("hr", { className: "border-gray-200 dark:border-gray-800" }),
771
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
772
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Validation" }),
773
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
774
+ /* @__PURE__ */ jsx("label", { className: "text-sm text-gray-700 dark:text-gray-300", children: "Required" }),
775
+ /* @__PURE__ */ jsx(
776
+ "input",
777
+ {
778
+ type: "checkbox",
779
+ checked: selectedField.required || false,
780
+ onChange: (e) => updateField(selectedField.id, { required: e.target.checked }),
781
+ className: "h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
782
+ }
783
+ )
784
+ ] })
785
+ ] }),
786
+ (selectedField.type === "select" || selectedField.type === "radio") && /* @__PURE__ */ jsxs(Fragment, { children: [
787
+ /* @__PURE__ */ jsx("hr", { className: "border-gray-200 dark:border-gray-800" }),
788
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
789
+ /* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900 dark:text-white", children: "Options" }),
790
+ selectedField.options?.map((option, index) => /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
791
+ /* @__PURE__ */ jsx(
792
+ "input",
793
+ {
794
+ placeholder: "Label",
795
+ value: option.label,
796
+ onChange: (e) => {
797
+ const newOptions = [...selectedField.options || []];
798
+ newOptions[index].label = e.target.value;
799
+ updateField(selectedField.id, { options: newOptions });
800
+ },
801
+ className: "flex-1 px-2 py-1 border border-gray-300 dark:border-gray-700 rounded text-sm"
802
+ }
803
+ ),
804
+ /* @__PURE__ */ jsx(
805
+ "input",
806
+ {
807
+ placeholder: "Value",
808
+ value: option.value,
809
+ onChange: (e) => {
810
+ const newOptions = [...selectedField.options || []];
811
+ newOptions[index].value = e.target.value;
812
+ updateField(selectedField.id, { options: newOptions });
813
+ },
814
+ className: "flex-1 px-2 py-1 border border-gray-300 dark:border-gray-700 rounded text-sm"
815
+ }
816
+ ),
817
+ /* @__PURE__ */ jsx(
818
+ "button",
819
+ {
820
+ onClick: () => {
821
+ const newOptions = selectedField.options?.filter((_, i) => i !== index);
822
+ updateField(selectedField.id, { options: newOptions });
823
+ },
824
+ className: "text-red-500 hover:text-red-700",
825
+ children: /* @__PURE__ */ jsx(X, { size: 16 })
826
+ }
827
+ )
828
+ ] }, index)),
829
+ /* @__PURE__ */ jsx(
830
+ "button",
831
+ {
832
+ onClick: () => {
833
+ const newOptions = [...selectedField.options || [], { label: "New Option", value: "new_option" }];
834
+ updateField(selectedField.id, { options: newOptions });
835
+ },
836
+ className: "text-sm text-blue-600 hover:text-blue-700 font-medium",
837
+ children: "+ Add Option"
838
+ }
839
+ )
840
+ ] })
841
+ ] })
842
+ ] })
843
+ ] });
844
+ };
845
+ var FormRenderer = ({ schema, onSubmit, className }) => {
846
+ const [formData, setFormData] = useState({});
847
+ const [errors, setErrors] = useState({});
848
+ const handleChange = (fieldId, value) => {
849
+ setFormData((prev) => ({ ...prev, [fieldId]: value }));
850
+ if (errors[fieldId]) {
851
+ setErrors((prev) => {
852
+ const newErrors = { ...prev };
853
+ delete newErrors[fieldId];
854
+ return newErrors;
855
+ });
856
+ }
857
+ };
858
+ const validate = () => {
859
+ const newErrors = {};
860
+ let isValid = true;
861
+ schema.sections.forEach((section) => {
862
+ section.fields.forEach((field) => {
863
+ const value = formData[field.id];
864
+ if (field.required && !value) {
865
+ newErrors[field.id] = "This field is required";
866
+ isValid = false;
867
+ }
868
+ if (field.validation) {
869
+ field.validation.forEach((rule) => {
870
+ if (rule.type === "email" && value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
871
+ newErrors[field.id] = rule.message || "Invalid email address";
872
+ isValid = false;
873
+ }
874
+ if (rule.type === "min" && typeof value === "number" && value < rule.value) {
875
+ newErrors[field.id] = rule.message || `Minimum value is ${rule.value}`;
876
+ isValid = false;
877
+ }
878
+ });
879
+ }
880
+ });
881
+ });
882
+ setErrors(newErrors);
883
+ return isValid;
884
+ };
885
+ const handleSubmit = (e) => {
886
+ e.preventDefault();
887
+ if (validate()) {
888
+ onSubmit?.(formData);
889
+ }
890
+ };
891
+ return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: clsx("space-y-8", className), children: [
892
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: /* @__PURE__ */ jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: schema.title }) }),
893
+ schema.sections.map((section) => /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
894
+ /* @__PURE__ */ jsx("h2", { className: "text-xl font-semibold text-gray-800 dark:text-gray-200 border-b pb-2", children: section.title }),
895
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-4 gap-4", children: section.fields.map((field) => /* @__PURE__ */ jsx(
896
+ "div",
897
+ {
898
+ style: {
899
+ gridColumn: field.width === "100%" ? "span 4" : field.width === "50%" ? "span 2" : "span 1"
900
+ },
901
+ children: /* @__PURE__ */ jsx(
902
+ FieldRenderer,
903
+ {
904
+ field,
905
+ value: formData[field.id],
906
+ onChange: (val) => handleChange(field.id, val),
907
+ error: errors[field.id]
908
+ }
909
+ )
910
+ },
911
+ field.id
912
+ )) })
913
+ ] }, section.id)),
914
+ /* @__PURE__ */ jsx("div", { className: "pt-4", children: /* @__PURE__ */ jsx(
915
+ "button",
916
+ {
917
+ type: "submit",
918
+ className: "px-6 py-2 bg-blue-600 text-white font-medium rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors",
919
+ children: "Submit"
920
+ }
921
+ ) })
922
+ ] });
923
+ };
924
+ var dropAnimation = {
925
+ sideEffects: defaultDropAnimationSideEffects({
926
+ styles: {
927
+ active: {
928
+ opacity: "0.5"
929
+ }
930
+ }
931
+ })
932
+ };
933
+ var FormBuilder = () => {
934
+ const {
935
+ schema,
936
+ addField,
937
+ moveField,
938
+ moveSection,
939
+ isPreviewMode
940
+ } = useFormStore();
941
+ const [activeId, setActiveId] = useState(null);
942
+ const [activeData, setActiveData] = useState(null);
943
+ const sensors = useSensors(
944
+ useSensor(PointerSensor, {
945
+ activationConstraint: {
946
+ distance: 5
947
+ }
948
+ }),
949
+ useSensor(KeyboardSensor, {
950
+ coordinateGetter: sortableKeyboardCoordinates
951
+ })
952
+ );
953
+ const handleDragStart = (event) => {
954
+ setActiveId(event.active.id);
955
+ setActiveData(event.active.data.current);
956
+ };
957
+ const handleDragOver = (event) => {
958
+ const { active, over } = event;
959
+ if (!over)
960
+ return;
961
+ const activeType = active.data.current?.type;
962
+ const overType = over.data.current?.type;
963
+ if (activeType === "toolbox-item" && overType === "section") {
964
+ return;
965
+ }
966
+ };
967
+ const handleDragEnd = (event) => {
968
+ const { active, over } = event;
969
+ setActiveId(null);
970
+ setActiveData(null);
971
+ if (!over)
972
+ return;
973
+ const activeType = active.data.current?.type;
974
+ const overType = over.data.current?.type;
975
+ if (activeType === "toolbox-item") {
976
+ const fieldType = active.data.current?.fieldType;
977
+ if (overType === "section") {
978
+ addField(over.id, fieldType);
979
+ } else if (overType === "field") {
980
+ const section = schema.sections.find((s) => s.fields.some((f) => f.id === over.id));
981
+ if (section) {
982
+ const index = section.fields.findIndex((f) => f.id === over.id);
983
+ addField(section.id, fieldType, index + 1);
984
+ }
985
+ }
986
+ return;
987
+ }
988
+ if (activeType === "section" && overType === "section") {
989
+ if (active.id !== over.id) {
990
+ moveSection(active.id, over.id);
991
+ }
992
+ return;
993
+ }
994
+ if (activeType === "field") {
995
+ const activeFieldId = active.id;
996
+ const overId = over.id;
997
+ const activeSection = schema.sections.find((s) => s.fields.some((f) => f.id === activeFieldId));
998
+ let overSection;
999
+ if (overType === "section") {
1000
+ overSection = schema.sections.find((s) => s.id === overId);
1001
+ } else if (overType === "field") {
1002
+ overSection = schema.sections.find((s) => s.fields.some((f) => f.id === overId));
1003
+ }
1004
+ if (activeSection && overSection) {
1005
+ moveField(activeFieldId, overId, activeSection.id, overSection.id);
1006
+ }
1007
+ }
1008
+ };
1009
+ return /* @__PURE__ */ jsxs(
1010
+ DndContext,
1011
+ {
1012
+ sensors,
1013
+ collisionDetection: closestCorners,
1014
+ onDragStart: handleDragStart,
1015
+ onDragOver: handleDragOver,
1016
+ onDragEnd: handleDragEnd,
1017
+ children: [
1018
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-screen bg-gray-100 dark:bg-gray-950", children: [
1019
+ /* @__PURE__ */ jsx(Toolbar, {}),
1020
+ /* @__PURE__ */ jsx("div", { className: "flex flex-1 overflow-hidden", children: isPreviewMode ? /* @__PURE__ */ jsx("div", { className: "flex-1 p-8 overflow-y-auto bg-white dark:bg-gray-900 flex justify-center", children: /* @__PURE__ */ jsx("div", { className: "w-full max-w-3xl", children: /* @__PURE__ */ jsx(FormRenderer, { schema, onSubmit: (data) => alert(JSON.stringify(data, null, 2)) }) }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1021
+ /* @__PURE__ */ jsx(FieldToolbox, {}),
1022
+ /* @__PURE__ */ jsx(Canvas, {}),
1023
+ /* @__PURE__ */ jsx(FieldConfigPanel, {})
1024
+ ] }) })
1025
+ ] }),
1026
+ createPortal(
1027
+ /* @__PURE__ */ jsxs(DragOverlay, { dropAnimation, children: [
1028
+ activeId && activeData?.type === "toolbox-item" && /* @__PURE__ */ jsx("div", { className: "p-3 bg-white border border-blue-500 rounded shadow-lg w-48", children: activeData.fieldType }),
1029
+ activeId && activeData?.type === "field" && /* @__PURE__ */ jsx("div", { className: "opacity-80", children: /* @__PURE__ */ jsx(SortableField, { field: activeData.field }) }),
1030
+ activeId && activeData?.type === "section" && /* @__PURE__ */ jsx("div", { className: "opacity-80", children: /* @__PURE__ */ jsx(SortableSection, { section: activeData.section }) })
1031
+ ] }),
1032
+ document.body
1033
+ )
1034
+ ]
1035
+ }
1036
+ );
1037
+ };
1038
+ var ReactCustomElement = class extends HTMLElement {
1039
+ constructor(Component) {
1040
+ super();
1041
+ __publicField(this, "root", null);
1042
+ __publicField(this, "props", {});
1043
+ __publicField(this, "Component");
1044
+ this.Component = Component;
1045
+ }
1046
+ connectedCallback() {
1047
+ if (!this.root) {
1048
+ this.root = ReactDOM.createRoot(this);
1049
+ this.render();
1050
+ }
1051
+ }
1052
+ disconnectedCallback() {
1053
+ if (this.root) {
1054
+ this.root.unmount();
1055
+ this.root = null;
1056
+ }
1057
+ }
1058
+ attributeChangedCallback(name, oldValue, newValue) {
1059
+ if (oldValue !== newValue) {
1060
+ this.props[name] = newValue;
1061
+ this.render();
1062
+ }
1063
+ }
1064
+ // Allow setting complex props via JS properties
1065
+ setProp(name, value) {
1066
+ this.props[name] = value;
1067
+ this.render();
1068
+ }
1069
+ render() {
1070
+ if (this.root) {
1071
+ const Component = this.Component;
1072
+ this.root.render(
1073
+ /* @__PURE__ */ jsx(React.StrictMode, { children: /* @__PURE__ */ jsx(Component, { ...this.props }) })
1074
+ );
1075
+ }
1076
+ }
1077
+ };
1078
+ var FormBuilderElement = class extends ReactCustomElement {
1079
+ constructor() {
1080
+ super(FormBuilder);
1081
+ }
1082
+ // Expose methods or specific props if needed
1083
+ };
1084
+ var FormRendererElement = class extends ReactCustomElement {
1085
+ constructor() {
1086
+ super(FormRenderer);
1087
+ }
1088
+ // Define setters for complex properties
1089
+ set schema(value) {
1090
+ this.setProp("schema", value);
1091
+ }
1092
+ set onSubmit(value) {
1093
+ this.setProp("onSubmit", value);
1094
+ }
1095
+ };
1096
+ function registerWebComponents() {
1097
+ if (typeof window !== "undefined") {
1098
+ if (!customElements.get("form-builder-pro")) {
1099
+ customElements.define("form-builder-pro", FormBuilderElement);
1100
+ }
1101
+ if (!customElements.get("form-renderer-pro")) {
1102
+ customElements.define("form-renderer-pro", FormRendererElement);
1103
+ }
1104
+ }
1105
+ }
1106
+ if (typeof window !== "undefined") {
1107
+ window.FormBuilderPro = {
1108
+ register: registerWebComponents
1109
+ };
1110
+ }
1111
+
1112
+ export { registerWebComponents };
1113
+ //# sourceMappingURL=out.js.map
1114
+ //# sourceMappingURL=web-components.mjs.map