@nextlyhq/plugin-form-builder 0.0.2-alpha.34 → 0.0.2-alpha.37
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/README.md +4 -5
- package/dist/admin/index.d.ts +122 -315
- package/dist/admin/index.js +3836 -3421
- package/dist/admin/index.js.map +1 -1
- package/dist/chunk-WVI7N3QO.js +559 -0
- package/dist/chunk-WVI7N3QO.js.map +1 -0
- package/dist/index.d.ts +8 -8
- package/dist/index.js +440 -611
- package/dist/index.js.map +1 -1
- package/dist/{index-BRumOEsE.d.ts → types-r8uBeB0u.d.ts} +97 -96
- package/package.json +23 -31
- package/dist/CheckboxFieldEditor-K4T6QX52.js +0 -121
- package/dist/CheckboxFieldEditor-K4T6QX52.js.map +0 -1
- package/dist/DateFieldEditor-JFJFAVOH.js +0 -187
- package/dist/DateFieldEditor-JFJFAVOH.js.map +0 -1
- package/dist/EmailFieldEditor-ZZ4VSKKB.js +0 -138
- package/dist/EmailFieldEditor-ZZ4VSKKB.js.map +0 -1
- package/dist/NumberFieldEditor-UISAYR6Z.js +0 -175
- package/dist/NumberFieldEditor-UISAYR6Z.js.map +0 -1
- package/dist/RadioFieldEditor-6UQFH4WT.js +0 -165
- package/dist/RadioFieldEditor-6UQFH4WT.js.map +0 -1
- package/dist/SelectFieldEditor-PSO4KHV4.js +0 -213
- package/dist/SelectFieldEditor-PSO4KHV4.js.map +0 -1
- package/dist/TextFieldEditor-5EU64EA5.js +0 -187
- package/dist/TextFieldEditor-5EU64EA5.js.map +0 -1
- package/dist/TextareaFieldEditor-773G3LNM.js +0 -190
- package/dist/TextareaFieldEditor-773G3LNM.js.map +0 -1
- package/dist/admin/index.css +0 -91
- package/dist/admin/index.css.map +0 -1
- package/dist/chunk-2LLUO3TV.js +0 -547
- package/dist/chunk-2LLUO3TV.js.map +0 -1
- package/dist/chunk-XTCEPJ7B.js +0 -256
- package/dist/chunk-XTCEPJ7B.js.map +0 -1
- package/dist/components/index.d.ts +0 -3
- package/dist/components/index.js +0 -9
- package/dist/components/index.js.map +0 -1
- package/dist/styles/form-builder.css +0 -128
- package/dist/styles/submissions-filter.css +0 -74
package/dist/chunk-XTCEPJ7B.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
// src/admin/fields/OptionsEditor.tsx
|
|
2
|
-
import {
|
|
3
|
-
DndContext,
|
|
4
|
-
closestCenter,
|
|
5
|
-
KeyboardSensor,
|
|
6
|
-
PointerSensor,
|
|
7
|
-
useSensor,
|
|
8
|
-
useSensors
|
|
9
|
-
} from "@dnd-kit/core";
|
|
10
|
-
import {
|
|
11
|
-
arrayMove,
|
|
12
|
-
SortableContext,
|
|
13
|
-
sortableKeyboardCoordinates,
|
|
14
|
-
useSortable,
|
|
15
|
-
verticalListSortingStrategy
|
|
16
|
-
} from "@dnd-kit/sortable";
|
|
17
|
-
import { CSS } from "@dnd-kit/utilities";
|
|
18
|
-
import { Input } from "@nextlyhq/ui";
|
|
19
|
-
import { GripVertical, Plus, Trash2 } from "lucide-react";
|
|
20
|
-
import { useCallback } from "react";
|
|
21
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
-
function generateValueFromLabel(label) {
|
|
23
|
-
return label.toLowerCase().trim().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
|
|
24
|
-
}
|
|
25
|
-
function addIdsToOptions(options) {
|
|
26
|
-
return options.map((opt, index) => ({
|
|
27
|
-
...opt,
|
|
28
|
-
id: `opt_${index}_${opt.value}`
|
|
29
|
-
}));
|
|
30
|
-
}
|
|
31
|
-
function removeIdsFromOptions(options) {
|
|
32
|
-
return options.map(({ label, value }) => ({ label, value }));
|
|
33
|
-
}
|
|
34
|
-
function SortableOption({
|
|
35
|
-
option,
|
|
36
|
-
index,
|
|
37
|
-
onLabelChange,
|
|
38
|
-
onValueChange,
|
|
39
|
-
onDelete,
|
|
40
|
-
disabled
|
|
41
|
-
}) {
|
|
42
|
-
const {
|
|
43
|
-
attributes,
|
|
44
|
-
listeners,
|
|
45
|
-
setNodeRef,
|
|
46
|
-
transform,
|
|
47
|
-
transition,
|
|
48
|
-
isDragging
|
|
49
|
-
} = useSortable({ id: option.id });
|
|
50
|
-
const style = {
|
|
51
|
-
transform: CSS.Transform.toString(transform),
|
|
52
|
-
transition,
|
|
53
|
-
opacity: isDragging ? 0.5 : 1
|
|
54
|
-
};
|
|
55
|
-
return /* @__PURE__ */ jsxs(
|
|
56
|
-
"div",
|
|
57
|
-
{
|
|
58
|
-
ref: setNodeRef,
|
|
59
|
-
style,
|
|
60
|
-
className: `options-editor__option ${isDragging ? "options-editor__option--dragging" : ""}`,
|
|
61
|
-
children: [
|
|
62
|
-
/* @__PURE__ */ jsx(
|
|
63
|
-
"button",
|
|
64
|
-
{
|
|
65
|
-
type: "button",
|
|
66
|
-
className: "options-editor__drag-handle",
|
|
67
|
-
disabled,
|
|
68
|
-
"aria-label": `Drag to reorder option ${index + 1}`,
|
|
69
|
-
...attributes,
|
|
70
|
-
...listeners,
|
|
71
|
-
children: /* @__PURE__ */ jsx(GripVertical, { className: "options-editor__drag-icon" })
|
|
72
|
-
}
|
|
73
|
-
),
|
|
74
|
-
/* @__PURE__ */ jsx("div", { className: "options-editor__input-group", children: /* @__PURE__ */ jsx(
|
|
75
|
-
Input,
|
|
76
|
-
{
|
|
77
|
-
type: "text",
|
|
78
|
-
value: option.label,
|
|
79
|
-
onChange: (e) => onLabelChange(option.id, e.target.value),
|
|
80
|
-
placeholder: "Label",
|
|
81
|
-
disabled,
|
|
82
|
-
className: "options-editor__input"
|
|
83
|
-
}
|
|
84
|
-
) }),
|
|
85
|
-
/* @__PURE__ */ jsx("div", { className: "options-editor__input-group", children: /* @__PURE__ */ jsx(
|
|
86
|
-
Input,
|
|
87
|
-
{
|
|
88
|
-
type: "text",
|
|
89
|
-
value: option.value,
|
|
90
|
-
onChange: (e) => onValueChange(option.id, e.target.value),
|
|
91
|
-
placeholder: "value",
|
|
92
|
-
disabled,
|
|
93
|
-
className: "options-editor__input options-editor__input--mono"
|
|
94
|
-
}
|
|
95
|
-
) }),
|
|
96
|
-
/* @__PURE__ */ jsx(
|
|
97
|
-
"button",
|
|
98
|
-
{
|
|
99
|
-
type: "button",
|
|
100
|
-
className: "options-editor__delete-btn",
|
|
101
|
-
onClick: () => onDelete(option.id),
|
|
102
|
-
disabled,
|
|
103
|
-
"aria-label": `Delete option ${option.label || index + 1}`,
|
|
104
|
-
children: /* @__PURE__ */ jsx(Trash2, { className: "options-editor__delete-icon" })
|
|
105
|
-
}
|
|
106
|
-
)
|
|
107
|
-
]
|
|
108
|
-
}
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
function OptionsEditor({
|
|
112
|
-
options,
|
|
113
|
-
onOptionsChange,
|
|
114
|
-
disabled = false
|
|
115
|
-
}) {
|
|
116
|
-
const optionsWithIds = addIdsToOptions(options);
|
|
117
|
-
const sensors = useSensors(
|
|
118
|
-
useSensor(PointerSensor, {
|
|
119
|
-
activationConstraint: {
|
|
120
|
-
distance: 8
|
|
121
|
-
}
|
|
122
|
-
}),
|
|
123
|
-
useSensor(KeyboardSensor, {
|
|
124
|
-
coordinateGetter: sortableKeyboardCoordinates
|
|
125
|
-
})
|
|
126
|
-
);
|
|
127
|
-
const handleAddOption = useCallback(() => {
|
|
128
|
-
const newIndex = options.length + 1;
|
|
129
|
-
const newOption = {
|
|
130
|
-
label: `Option ${newIndex}`,
|
|
131
|
-
value: `option_${newIndex}`
|
|
132
|
-
};
|
|
133
|
-
onOptionsChange([...options, newOption]);
|
|
134
|
-
}, [options, onOptionsChange]);
|
|
135
|
-
const handleLabelChange = useCallback(
|
|
136
|
-
(id, newLabel) => {
|
|
137
|
-
const updatedOptions = optionsWithIds.map((opt) => {
|
|
138
|
-
if (opt.id !== id) return opt;
|
|
139
|
-
const previousAutoValue = generateValueFromLabel(opt.label);
|
|
140
|
-
const shouldAutoGenerate = !opt.value || opt.value === previousAutoValue;
|
|
141
|
-
return {
|
|
142
|
-
...opt,
|
|
143
|
-
label: newLabel,
|
|
144
|
-
value: shouldAutoGenerate ? generateValueFromLabel(newLabel) : opt.value
|
|
145
|
-
};
|
|
146
|
-
});
|
|
147
|
-
onOptionsChange(removeIdsFromOptions(updatedOptions));
|
|
148
|
-
},
|
|
149
|
-
[optionsWithIds, onOptionsChange]
|
|
150
|
-
);
|
|
151
|
-
const handleValueChange = useCallback(
|
|
152
|
-
(id, newValue) => {
|
|
153
|
-
const updatedOptions = optionsWithIds.map(
|
|
154
|
-
(opt) => opt.id === id ? { ...opt, value: newValue } : opt
|
|
155
|
-
);
|
|
156
|
-
onOptionsChange(removeIdsFromOptions(updatedOptions));
|
|
157
|
-
},
|
|
158
|
-
[optionsWithIds, onOptionsChange]
|
|
159
|
-
);
|
|
160
|
-
const handleDeleteOption = useCallback(
|
|
161
|
-
(id) => {
|
|
162
|
-
const updatedOptions = optionsWithIds.filter((opt) => opt.id !== id);
|
|
163
|
-
onOptionsChange(removeIdsFromOptions(updatedOptions));
|
|
164
|
-
},
|
|
165
|
-
[optionsWithIds, onOptionsChange]
|
|
166
|
-
);
|
|
167
|
-
const handleDragEnd = useCallback(
|
|
168
|
-
(event) => {
|
|
169
|
-
const { active, over } = event;
|
|
170
|
-
if (over && active.id !== over.id) {
|
|
171
|
-
const oldIndex = optionsWithIds.findIndex((opt) => opt.id === active.id);
|
|
172
|
-
const newIndex = optionsWithIds.findIndex((opt) => opt.id === over.id);
|
|
173
|
-
const reorderedOptions = arrayMove(optionsWithIds, oldIndex, newIndex);
|
|
174
|
-
onOptionsChange(removeIdsFromOptions(reorderedOptions));
|
|
175
|
-
}
|
|
176
|
-
},
|
|
177
|
-
[optionsWithIds, onOptionsChange]
|
|
178
|
-
);
|
|
179
|
-
return /* @__PURE__ */ jsxs("div", { className: "options-editor", children: [
|
|
180
|
-
/* @__PURE__ */ jsxs("div", { className: "options-editor__header", children: [
|
|
181
|
-
/* @__PURE__ */ jsx("label", { className: "options-editor__label", children: "Options" }),
|
|
182
|
-
/* @__PURE__ */ jsxs(
|
|
183
|
-
"button",
|
|
184
|
-
{
|
|
185
|
-
type: "button",
|
|
186
|
-
className: "options-editor__add-btn",
|
|
187
|
-
onClick: handleAddOption,
|
|
188
|
-
disabled,
|
|
189
|
-
children: [
|
|
190
|
-
/* @__PURE__ */ jsx(Plus, { className: "options-editor__add-icon" }),
|
|
191
|
-
"Add Option"
|
|
192
|
-
]
|
|
193
|
-
}
|
|
194
|
-
)
|
|
195
|
-
] }),
|
|
196
|
-
options.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
197
|
-
/* @__PURE__ */ jsxs("div", { className: "options-editor__column-headers", children: [
|
|
198
|
-
/* @__PURE__ */ jsx("div", { className: "options-editor__column-spacer" }),
|
|
199
|
-
/* @__PURE__ */ jsx("div", { className: "options-editor__column-label", children: "Label (displayed)" }),
|
|
200
|
-
/* @__PURE__ */ jsx("div", { className: "options-editor__column-label", children: "Value (stored)" }),
|
|
201
|
-
/* @__PURE__ */ jsx("div", { className: "options-editor__column-spacer" })
|
|
202
|
-
] }),
|
|
203
|
-
/* @__PURE__ */ jsx(
|
|
204
|
-
DndContext,
|
|
205
|
-
{
|
|
206
|
-
sensors,
|
|
207
|
-
collisionDetection: closestCenter,
|
|
208
|
-
onDragEnd: handleDragEnd,
|
|
209
|
-
children: /* @__PURE__ */ jsx(
|
|
210
|
-
SortableContext,
|
|
211
|
-
{
|
|
212
|
-
items: optionsWithIds.map((opt) => opt.id),
|
|
213
|
-
strategy: verticalListSortingStrategy,
|
|
214
|
-
children: /* @__PURE__ */ jsx("div", { className: "options-editor__list", children: optionsWithIds.map((option, index) => /* @__PURE__ */ jsx(
|
|
215
|
-
SortableOption,
|
|
216
|
-
{
|
|
217
|
-
option,
|
|
218
|
-
index,
|
|
219
|
-
onLabelChange: handleLabelChange,
|
|
220
|
-
onValueChange: handleValueChange,
|
|
221
|
-
onDelete: handleDeleteOption,
|
|
222
|
-
disabled
|
|
223
|
-
},
|
|
224
|
-
option.id
|
|
225
|
-
)) })
|
|
226
|
-
}
|
|
227
|
-
)
|
|
228
|
-
}
|
|
229
|
-
)
|
|
230
|
-
] }) : (
|
|
231
|
-
/* Empty State */
|
|
232
|
-
/* @__PURE__ */ jsxs("div", { className: "options-editor__empty", children: [
|
|
233
|
-
/* @__PURE__ */ jsx("p", { className: "options-editor__empty-text", children: "No options defined" }),
|
|
234
|
-
/* @__PURE__ */ jsxs(
|
|
235
|
-
"button",
|
|
236
|
-
{
|
|
237
|
-
type: "button",
|
|
238
|
-
className: "options-editor__add-first-btn",
|
|
239
|
-
onClick: handleAddOption,
|
|
240
|
-
disabled,
|
|
241
|
-
children: [
|
|
242
|
-
/* @__PURE__ */ jsx(Plus, { className: "options-editor__add-icon" }),
|
|
243
|
-
"Add first option"
|
|
244
|
-
]
|
|
245
|
-
}
|
|
246
|
-
)
|
|
247
|
-
] })
|
|
248
|
-
),
|
|
249
|
-
/* @__PURE__ */ jsx("p", { className: "options-editor__hint", children: "Drag options to reorder. Value is auto-generated from label." })
|
|
250
|
-
] });
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export {
|
|
254
|
-
OptionsEditor
|
|
255
|
-
};
|
|
256
|
-
//# sourceMappingURL=chunk-XTCEPJ7B.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/admin/fields/OptionsEditor.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * Options Editor Component\n *\n * Shared component for editing options arrays in Select and Radio fields.\n * Features:\n * - Add/edit/remove options\n * - Drag-and-drop reordering with @dnd-kit\n * - Auto-generate value from label\n *\n * @module admin/fields/OptionsEditor\n * @since 0.1.0\n */\n\n\"use client\";\n\nimport {\n DndContext,\n closestCenter,\n KeyboardSensor,\n PointerSensor,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from \"@dnd-kit/core\";\nimport {\n arrayMove,\n SortableContext,\n sortableKeyboardCoordinates,\n useSortable,\n verticalListSortingStrategy,\n} from \"@dnd-kit/sortable\";\nimport { CSS } from \"@dnd-kit/utilities\";\nimport { Input } from \"@nextlyhq/ui\";\nimport { GripVertical, Plus, Trash2 } from \"lucide-react\";\nimport { useCallback } from \"react\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** Option interface for Select/Radio fields */\nexport interface FieldOption {\n label: string;\n value: string;\n}\n\n/** Internal option with ID for drag-and-drop */\ninterface OptionWithId extends FieldOption {\n id: string;\n}\n\nexport interface OptionsEditorProps {\n /** Current options array */\n options: FieldOption[];\n /** Callback when options change */\n onOptionsChange: (options: FieldOption[]) => void;\n /** Disable editing */\n disabled?: boolean;\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Generate a value from a label (snake_case format)\n */\nfunction generateValueFromLabel(label: string): string {\n return label\n .toLowerCase()\n .trim()\n .replace(/\\s+/g, \"_\")\n .replace(/[^a-z0-9_]/g, \"\");\n}\n\n/**\n * Add IDs to options for DnD tracking\n */\nfunction addIdsToOptions(options: FieldOption[]): OptionWithId[] {\n return options.map((opt, index) => ({\n ...opt,\n id: `opt_${index}_${opt.value}`,\n }));\n}\n\n/**\n * Remove IDs from options when saving\n */\nfunction removeIdsFromOptions(options: OptionWithId[]): FieldOption[] {\n return options.map(({ label, value }) => ({ label, value }));\n}\n\n// ============================================================================\n// SortableOption Component\n// ============================================================================\n\ninterface SortableOptionProps {\n option: OptionWithId;\n index: number;\n onLabelChange: (id: string, label: string) => void;\n onValueChange: (id: string, value: string) => void;\n onDelete: (id: string) => void;\n disabled?: boolean;\n}\n\nfunction SortableOption({\n option,\n index,\n onLabelChange,\n onValueChange,\n onDelete,\n disabled,\n}: SortableOptionProps) {\n const {\n attributes,\n listeners,\n setNodeRef,\n transform,\n transition,\n isDragging,\n } = useSortable({ id: option.id });\n\n const style = {\n transform: CSS.Transform.toString(transform),\n transition,\n opacity: isDragging ? 0.5 : 1,\n };\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n className={`options-editor__option ${isDragging ? \"options-editor__option--dragging\" : \"\"}`}\n >\n {/* Drag Handle */}\n <button\n type=\"button\"\n className=\"options-editor__drag-handle\"\n disabled={disabled}\n aria-label={`Drag to reorder option ${index + 1}`}\n {...attributes}\n {...listeners}\n >\n <GripVertical className=\"options-editor__drag-icon\" />\n </button>\n\n {/* Label Input */}\n <div className=\"options-editor__input-group\">\n <Input\n type=\"text\"\n value={option.label}\n onChange={e => onLabelChange(option.id, e.target.value)}\n placeholder=\"Label\"\n disabled={disabled}\n className=\"options-editor__input\"\n />\n </div>\n\n {/* Value Input */}\n <div className=\"options-editor__input-group\">\n <Input\n type=\"text\"\n value={option.value}\n onChange={e => onValueChange(option.id, e.target.value)}\n placeholder=\"value\"\n disabled={disabled}\n className=\"options-editor__input options-editor__input--mono\"\n />\n </div>\n\n {/* Delete Button */}\n <button\n type=\"button\"\n className=\"options-editor__delete-btn\"\n onClick={() => onDelete(option.id)}\n disabled={disabled}\n aria-label={`Delete option ${option.label || index + 1}`}\n >\n <Trash2 className=\"options-editor__delete-icon\" />\n </button>\n </div>\n );\n}\n\n// ============================================================================\n// Main Component\n// ============================================================================\n\n/**\n * OptionsEditor - Manage options for Select/Radio fields\n *\n * Provides a list of editable options with:\n * - Drag-and-drop reordering\n * - Add/remove options\n * - Auto-generate value from label\n *\n * @example\n * ```tsx\n * <OptionsEditor\n * options={field.options}\n * onOptionsChange={(options) => onUpdate({ options })}\n * />\n * ```\n */\nexport function OptionsEditor({\n options,\n onOptionsChange,\n disabled = false,\n}: OptionsEditorProps) {\n // Convert options to internal format with IDs for DnD\n const optionsWithIds = addIdsToOptions(options);\n\n // DnD sensors with activation distance to prevent accidental drags\n const sensors = useSensors(\n useSensor(PointerSensor, {\n activationConstraint: {\n distance: 8,\n },\n }),\n useSensor(KeyboardSensor, {\n coordinateGetter: sortableKeyboardCoordinates,\n })\n );\n\n // Add a new option\n const handleAddOption = useCallback(() => {\n const newIndex = options.length + 1;\n const newOption: FieldOption = {\n label: `Option ${newIndex}`,\n value: `option_${newIndex}`,\n };\n onOptionsChange([...options, newOption]);\n }, [options, onOptionsChange]);\n\n // Handle label change with auto-generate value\n const handleLabelChange = useCallback(\n (id: string, newLabel: string) => {\n const updatedOptions = optionsWithIds.map(opt => {\n if (opt.id !== id) return opt;\n\n // Auto-generate value if it matches the old auto-generated value or is empty\n const previousAutoValue = generateValueFromLabel(opt.label);\n const shouldAutoGenerate =\n !opt.value || opt.value === previousAutoValue;\n\n return {\n ...opt,\n label: newLabel,\n value: shouldAutoGenerate\n ? generateValueFromLabel(newLabel)\n : opt.value,\n };\n });\n\n onOptionsChange(removeIdsFromOptions(updatedOptions));\n },\n [optionsWithIds, onOptionsChange]\n );\n\n // Handle value change (manual override)\n const handleValueChange = useCallback(\n (id: string, newValue: string) => {\n const updatedOptions = optionsWithIds.map(opt =>\n opt.id === id ? { ...opt, value: newValue } : opt\n );\n onOptionsChange(removeIdsFromOptions(updatedOptions));\n },\n [optionsWithIds, onOptionsChange]\n );\n\n // Delete an option\n const handleDeleteOption = useCallback(\n (id: string) => {\n const updatedOptions = optionsWithIds.filter(opt => opt.id !== id);\n onOptionsChange(removeIdsFromOptions(updatedOptions));\n },\n [optionsWithIds, onOptionsChange]\n );\n\n // Handle drag end for reordering\n const handleDragEnd = useCallback(\n (event: DragEndEvent) => {\n const { active, over } = event;\n\n if (over && active.id !== over.id) {\n const oldIndex = optionsWithIds.findIndex(opt => opt.id === active.id);\n const newIndex = optionsWithIds.findIndex(opt => opt.id === over.id);\n const reorderedOptions = arrayMove(optionsWithIds, oldIndex, newIndex);\n onOptionsChange(removeIdsFromOptions(reorderedOptions));\n }\n },\n [optionsWithIds, onOptionsChange]\n );\n\n return (\n <div className=\"options-editor\">\n {/* Header */}\n <div className=\"options-editor__header\">\n <label className=\"options-editor__label\">Options</label>\n <button\n type=\"button\"\n className=\"options-editor__add-btn\"\n onClick={handleAddOption}\n disabled={disabled}\n >\n <Plus className=\"options-editor__add-icon\" />\n Add Option\n </button>\n </div>\n\n {/* Options List */}\n {options.length > 0 ? (\n <>\n {/* Column Headers */}\n <div className=\"options-editor__column-headers\">\n <div className=\"options-editor__column-spacer\" />\n <div className=\"options-editor__column-label\">\n Label (displayed)\n </div>\n <div className=\"options-editor__column-label\">Value (stored)</div>\n <div className=\"options-editor__column-spacer\" />\n </div>\n\n {/* Sortable List */}\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragEnd={handleDragEnd}\n >\n <SortableContext\n items={optionsWithIds.map(opt => opt.id)}\n strategy={verticalListSortingStrategy}\n >\n <div className=\"options-editor__list\">\n {optionsWithIds.map((option, index) => (\n <SortableOption\n key={option.id}\n option={option}\n index={index}\n onLabelChange={handleLabelChange}\n onValueChange={handleValueChange}\n onDelete={handleDeleteOption}\n disabled={disabled}\n />\n ))}\n </div>\n </SortableContext>\n </DndContext>\n </>\n ) : (\n /* Empty State */\n <div className=\"options-editor__empty\">\n <p className=\"options-editor__empty-text\">No options defined</p>\n <button\n type=\"button\"\n className=\"options-editor__add-first-btn\"\n onClick={handleAddOption}\n disabled={disabled}\n >\n <Plus className=\"options-editor__add-icon\" />\n Add first option\n </button>\n </div>\n )}\n\n {/* Help Text */}\n <p className=\"options-editor__hint\">\n Drag options to reorder. Value is auto-generated from label.\n </p>\n </div>\n );\n}\n\nexport default OptionsEditor;\n"],"mappings":"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","names":[]}
|
package/dist/components/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Form Builder styles
|
|
3
|
-
*
|
|
4
|
-
* The builder UI is driven by Tailwind utilities and @nextlyhq/ui components in its
|
|
5
|
-
* React components. This file holds only the few bespoke rules those can't express:
|
|
6
|
-
* 1. The two-pane builder shell (fixed inspector panel; stacks in a narrow panel)
|
|
7
|
-
* 2. Notifications tab: email-integration card list (hover/variant states)
|
|
8
|
-
*
|
|
9
|
-
* Colors read the admin design tokens directly (`var(--token)`), so the UI looks native
|
|
10
|
-
* and inherits dark mode automatically (the admin flips the tokens under `.adminapp.dark`).
|
|
11
|
-
*
|
|
12
|
-
* @module styles/form-builder
|
|
13
|
-
* @since 0.1.0
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/* ---------------------------------------------------------- builder shell */
|
|
17
|
-
|
|
18
|
-
/* Fixed-width inspector panel beside the fluid canvas. */
|
|
19
|
-
.fb-builder-panel {
|
|
20
|
-
width: 360px;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/* Stack the canvas and inspector when the content panel itself gets narrow
|
|
24
|
-
(`content` is the admin content-area container). */
|
|
25
|
-
@container content (max-width: 800px) {
|
|
26
|
-
.fb-builder-shell {
|
|
27
|
-
flex-direction: column;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.fb-builder-panel {
|
|
31
|
-
width: 100%;
|
|
32
|
-
border-left: 0;
|
|
33
|
-
border-top: 1px solid var(--border);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/* ------------------------------------------------------- notifications tab */
|
|
38
|
-
|
|
39
|
-
.form-notifications-tab {
|
|
40
|
-
max-width: 800px;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.form-notifications-list {
|
|
44
|
-
display: flex;
|
|
45
|
-
flex-direction: column;
|
|
46
|
-
gap: 16px;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/* --------------------------------------------------- email integration cards */
|
|
50
|
-
|
|
51
|
-
.form-integration-card {
|
|
52
|
-
display: flex;
|
|
53
|
-
align-items: center;
|
|
54
|
-
justify-content: space-between;
|
|
55
|
-
gap: 16px;
|
|
56
|
-
padding: 14px 16px;
|
|
57
|
-
background: var(--card);
|
|
58
|
-
border: 1px solid var(--border);
|
|
59
|
-
border-radius: var(--radius);
|
|
60
|
-
transition: border-color 0.15s ease;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
.form-integration-card:hover {
|
|
64
|
-
border-color: var(--border-strong);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.form-integration-card--disabled {
|
|
68
|
-
opacity: 0.55;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.form-integration-card-left {
|
|
72
|
-
display: flex;
|
|
73
|
-
align-items: center;
|
|
74
|
-
gap: 12px;
|
|
75
|
-
flex: 1;
|
|
76
|
-
min-width: 0;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
.form-integration-card-info {
|
|
80
|
-
display: flex;
|
|
81
|
-
flex-direction: column;
|
|
82
|
-
gap: 4px;
|
|
83
|
-
min-width: 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
.form-integration-card-name {
|
|
87
|
-
font-size: 0.9375rem;
|
|
88
|
-
font-weight: 600;
|
|
89
|
-
color: var(--foreground);
|
|
90
|
-
white-space: nowrap;
|
|
91
|
-
overflow: hidden;
|
|
92
|
-
text-overflow: ellipsis;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.form-integration-provider-badge {
|
|
96
|
-
font-size: 0.75rem;
|
|
97
|
-
color: var(--muted-foreground);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
.form-integration-card-actions {
|
|
101
|
-
display: flex;
|
|
102
|
-
gap: 8px;
|
|
103
|
-
flex-shrink: 0;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.form-integration-btn {
|
|
107
|
-
padding: 6px 12px;
|
|
108
|
-
font-size: 0.75rem;
|
|
109
|
-
font-weight: 500;
|
|
110
|
-
color: var(--muted-foreground);
|
|
111
|
-
background: transparent;
|
|
112
|
-
border: 1px solid var(--border);
|
|
113
|
-
border-radius: var(--radius);
|
|
114
|
-
cursor: pointer;
|
|
115
|
-
transition: all 0.15s ease;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.form-integration-btn--edit:hover {
|
|
119
|
-
color: var(--primary);
|
|
120
|
-
border-color: var(--primary);
|
|
121
|
-
background: color-mix(in srgb, var(--primary) 10%, transparent);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.form-integration-btn--delete:hover {
|
|
125
|
-
color: var(--destructive);
|
|
126
|
-
border-color: var(--destructive);
|
|
127
|
-
background: color-mix(in srgb, var(--destructive) 10%, transparent);
|
|
128
|
-
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Submissions Filter Styles
|
|
3
|
-
*
|
|
4
|
-
* Styles for the SubmissionsFilter component shown above the
|
|
5
|
-
* form-submissions list table. Colors/borders/radius use the admin tokens.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
.submissions-filter {
|
|
9
|
-
margin-bottom: 1rem;
|
|
10
|
-
padding: 1rem;
|
|
11
|
-
background: var(--muted);
|
|
12
|
-
border: 1px solid var(--border);
|
|
13
|
-
border-radius: var(--radius);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.submissions-filter-container {
|
|
17
|
-
display: flex;
|
|
18
|
-
align-items: center;
|
|
19
|
-
gap: 0.75rem;
|
|
20
|
-
flex-wrap: wrap;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
.submissions-filter-label {
|
|
24
|
-
font-size: 0.875rem;
|
|
25
|
-
font-weight: 500;
|
|
26
|
-
color: var(--muted-foreground);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.submissions-filter-select {
|
|
30
|
-
padding: 0.5rem 2rem 0.5rem 0.75rem;
|
|
31
|
-
font-size: 0.875rem;
|
|
32
|
-
border: 1px solid var(--input);
|
|
33
|
-
border-radius: var(--radius);
|
|
34
|
-
background-color: var(--background);
|
|
35
|
-
color: var(--foreground);
|
|
36
|
-
min-width: 200px;
|
|
37
|
-
cursor: pointer;
|
|
38
|
-
appearance: none;
|
|
39
|
-
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
|
|
40
|
-
background-position: right 0.5rem center;
|
|
41
|
-
background-repeat: no-repeat;
|
|
42
|
-
background-size: 1.5em 1.5em;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
.submissions-filter-select:hover {
|
|
46
|
-
border-color: var(--border-strong);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.submissions-filter-select:focus {
|
|
50
|
-
outline: none;
|
|
51
|
-
border-color: var(--ring);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.submissions-filter-select:disabled {
|
|
55
|
-
opacity: 0.6;
|
|
56
|
-
cursor: not-allowed;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
.submissions-filter-clear {
|
|
60
|
-
padding: 0.5rem 0.75rem;
|
|
61
|
-
font-size: 0.75rem;
|
|
62
|
-
font-weight: 500;
|
|
63
|
-
color: var(--muted-foreground);
|
|
64
|
-
background: var(--background);
|
|
65
|
-
border: 1px solid var(--input);
|
|
66
|
-
border-radius: var(--radius);
|
|
67
|
-
cursor: pointer;
|
|
68
|
-
transition: all 0.15s ease;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.submissions-filter-clear:hover {
|
|
72
|
-
background: var(--muted);
|
|
73
|
-
color: var(--foreground);
|
|
74
|
-
}
|