form-page-builder 0.1.0 → 1.0.0
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/LICENSE +0 -0
- package/README.md +100 -8
- package/dist/index.cjs +846 -742
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -31
- package/dist/index.d.ts +92 -31
- package/dist/index.js +846 -741
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/FormBuilder.tsx
|
|
4
|
-
import { useState as useState8 } from "react";
|
|
4
|
+
import { forwardRef, useImperativeHandle, useState as useState8 } from "react";
|
|
5
5
|
import { Loader2 as Loader22 } from "lucide-react";
|
|
6
6
|
|
|
7
7
|
// src/i18n/languages.ts
|
|
@@ -50,6 +50,8 @@ var CHROME = {
|
|
|
50
50
|
contentBlocks: "Content",
|
|
51
51
|
formFields: "Form Fields",
|
|
52
52
|
addingTo: "Adding to",
|
|
53
|
+
paletteTabBlocks: "Blocks",
|
|
54
|
+
paletteTabDesign: "Design",
|
|
53
55
|
properties: "Properties",
|
|
54
56
|
selectFieldHint: "Select a field to edit its properties.",
|
|
55
57
|
label: "Label",
|
|
@@ -95,15 +97,15 @@ var CHROME = {
|
|
|
95
97
|
build: "Build",
|
|
96
98
|
preview: "Preview",
|
|
97
99
|
newForm: "New",
|
|
98
|
-
|
|
100
|
+
templates: "Templates",
|
|
99
101
|
save: "Save",
|
|
100
102
|
viewJson: "View JSON",
|
|
101
103
|
saving: "Saving...",
|
|
102
104
|
saved: "Saved",
|
|
103
105
|
saveFailed: "Save failed",
|
|
104
106
|
startNewForm: "Start a new form",
|
|
105
|
-
|
|
106
|
-
saveToLibraryTitle: "Save this form
|
|
107
|
+
openTemplatesTitle: "Open a saved template",
|
|
108
|
+
saveToLibraryTitle: "Save this form as a template",
|
|
107
109
|
sectionTitlePlaceholder: (n) => `Section ${n} title (optional)`,
|
|
108
110
|
noFieldsInSection: "No fields in this section yet \u2014 pick a field type on the left.",
|
|
109
111
|
addSection: "Add section",
|
|
@@ -116,22 +118,17 @@ var CHROME = {
|
|
|
116
118
|
formJson: "Form JSON",
|
|
117
119
|
copy: "Copy",
|
|
118
120
|
copied: "Copied",
|
|
119
|
-
|
|
121
|
+
noTemplates: 'No templates saved yet. Click "Save" in the toolbar to store this form here.',
|
|
120
122
|
updated: "Updated",
|
|
121
123
|
open: "Open",
|
|
122
|
-
saveForm: "Save
|
|
123
|
-
formName: "
|
|
124
|
-
saveToLibrary: "Save
|
|
124
|
+
saveForm: "Save as template",
|
|
125
|
+
formName: "Template name",
|
|
126
|
+
saveToLibrary: "Save template",
|
|
125
127
|
loadingDraft: "Loading your draft...",
|
|
128
|
+
templatesLimitReached: "You can save up to 5 templates. Delete one to save another.",
|
|
126
129
|
current: "current",
|
|
127
130
|
customColor: "Custom color",
|
|
128
131
|
fieldsCount: (n) => `${n} field${n === 1 ? "" : "s"}`,
|
|
129
|
-
formSettings: "Form settings",
|
|
130
|
-
submitLabel: "Submit button text",
|
|
131
|
-
submitMode: "Submit button",
|
|
132
|
-
combined: "Combined (one button)",
|
|
133
|
-
perSection: "Per section",
|
|
134
|
-
settings: "Form settings",
|
|
135
132
|
fieldTypeInput: "Input",
|
|
136
133
|
fieldTypeTextarea: "Textarea",
|
|
137
134
|
fieldTypeSelect: "Select",
|
|
@@ -141,6 +138,7 @@ var CHROME = {
|
|
|
141
138
|
fieldTypeToggle: "Toggle",
|
|
142
139
|
fieldTypeParagraph: "Paragraph",
|
|
143
140
|
fieldTypeImage: "Image",
|
|
141
|
+
fieldTypeButton: "Button",
|
|
144
142
|
subtypeText: "Text",
|
|
145
143
|
subtypeEmail: "Email",
|
|
146
144
|
subtypePhone: "Phone",
|
|
@@ -153,8 +151,17 @@ var CHROME = {
|
|
|
153
151
|
shapeBanner: "Banner",
|
|
154
152
|
tagBody: "Body",
|
|
155
153
|
tagCaption: "Caption",
|
|
156
|
-
|
|
157
|
-
|
|
154
|
+
buttonText: "Button text",
|
|
155
|
+
buttonActionTitle: "Action",
|
|
156
|
+
buttonAction: "When clicked",
|
|
157
|
+
actionLink: "Open link",
|
|
158
|
+
actionSubmit: "Submit",
|
|
159
|
+
openIn: "Open in",
|
|
160
|
+
sameTab: "Same tab",
|
|
161
|
+
newTab: "New tab",
|
|
162
|
+
submitScope: "Submits",
|
|
163
|
+
thisSection: "This section",
|
|
164
|
+
wholeForm: "Whole form",
|
|
158
165
|
buttonSize: "Size",
|
|
159
166
|
theme: "Theme",
|
|
160
167
|
primaryColor: "Primary color",
|
|
@@ -179,6 +186,8 @@ var CHROME = {
|
|
|
179
186
|
contentBlocks: "\u30B3\u30F3\u30C6\u30F3\u30C4",
|
|
180
187
|
formFields: "\u30D5\u30A9\u30FC\u30E0\u9805\u76EE",
|
|
181
188
|
addingTo: "\u8FFD\u52A0\u5148",
|
|
189
|
+
paletteTabBlocks: "\u30D6\u30ED\u30C3\u30AF",
|
|
190
|
+
paletteTabDesign: "\u30C7\u30B6\u30A4\u30F3",
|
|
182
191
|
properties: "\u30D7\u30ED\u30D1\u30C6\u30A3",
|
|
183
192
|
selectFieldHint: "\u7DE8\u96C6\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
184
193
|
label: "\u30E9\u30D9\u30EB",
|
|
@@ -224,15 +233,15 @@ var CHROME = {
|
|
|
224
233
|
build: "\u4F5C\u6210",
|
|
225
234
|
preview: "\u30D7\u30EC\u30D3\u30E5\u30FC",
|
|
226
235
|
newForm: "\u65B0\u898F",
|
|
227
|
-
|
|
236
|
+
templates: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8",
|
|
228
237
|
save: "\u4FDD\u5B58",
|
|
229
238
|
viewJson: "JSON\u3092\u8868\u793A",
|
|
230
239
|
saving: "\u4FDD\u5B58\u4E2D...",
|
|
231
240
|
saved: "\u4FDD\u5B58\u6E08\u307F",
|
|
232
241
|
saveFailed: "\u4FDD\u5B58\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
|
|
233
242
|
startNewForm: "\u65B0\u3057\u3044\u30D5\u30A9\u30FC\u30E0\u3092\u4F5C\u6210",
|
|
234
|
-
|
|
235
|
-
saveToLibraryTitle: "\u3053\u306E\u30D5\u30A9\u30FC\u30E0\u3092\
|
|
243
|
+
openTemplatesTitle: "\u4FDD\u5B58\u6E08\u307F\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u958B\u304F",
|
|
244
|
+
saveToLibraryTitle: "\u3053\u306E\u30D5\u30A9\u30FC\u30E0\u3092\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3068\u3057\u3066\u4FDD\u5B58",
|
|
236
245
|
sectionTitlePlaceholder: (n) => `\u30BB\u30AF\u30B7\u30E7\u30F3${n}\u306E\u30BF\u30A4\u30C8\u30EB\uFF08\u4EFB\u610F\uFF09`,
|
|
237
246
|
noFieldsInSection: "\u3053\u306E\u30BB\u30AF\u30B7\u30E7\u30F3\u306B\u306F\u307E\u3060\u30D5\u30A3\u30FC\u30EB\u30C9\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u5DE6\u306E\u30D1\u30CD\u30EB\u304B\u3089\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
238
247
|
addSection: "\u30BB\u30AF\u30B7\u30E7\u30F3\u3092\u8FFD\u52A0",
|
|
@@ -245,22 +254,17 @@ var CHROME = {
|
|
|
245
254
|
formJson: "\u30D5\u30A9\u30FC\u30E0JSON",
|
|
246
255
|
copy: "\u30B3\u30D4\u30FC",
|
|
247
256
|
copied: "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F",
|
|
248
|
-
|
|
257
|
+
noTemplates: "\u307E\u3060\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u304C\u3042\u308A\u307E\u305B\u3093\u3002\u30C4\u30FC\u30EB\u30D0\u30FC\u306E\u300C\u4FDD\u5B58\u300D\u3092\u30AF\u30EA\u30C3\u30AF\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
249
258
|
updated: "\u66F4\u65B0\u65E5\u6642",
|
|
250
259
|
open: "\u958B\u304F",
|
|
251
|
-
saveForm: "\
|
|
252
|
-
formName: "\
|
|
253
|
-
saveToLibrary: "\
|
|
260
|
+
saveForm: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3068\u3057\u3066\u4FDD\u5B58",
|
|
261
|
+
formName: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u540D",
|
|
262
|
+
saveToLibrary: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4FDD\u5B58",
|
|
254
263
|
loadingDraft: "\u4E0B\u66F8\u304D\u3092\u8AAD\u307F\u8FBC\u3093\u3067\u3044\u307E\u3059...",
|
|
264
|
+
templatesLimitReached: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u306F5\u4EF6\u307E\u3067\u4FDD\u5B58\u3067\u304D\u307E\u3059\u30021\u4EF6\u524A\u9664\u3057\u3066\u304B\u3089\u4FDD\u5B58\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
255
265
|
current: "\u73FE\u5728\u7DE8\u96C6\u4E2D",
|
|
256
266
|
customColor: "\u30AB\u30B9\u30BF\u30E0\u30AB\u30E9\u30FC",
|
|
257
267
|
fieldsCount: (n) => `${n}\u4EF6\u306E\u30D5\u30A3\u30FC\u30EB\u30C9`,
|
|
258
|
-
formSettings: "\u30D5\u30A9\u30FC\u30E0\u8A2D\u5B9A",
|
|
259
|
-
submitLabel: "\u9001\u4FE1\u30DC\u30BF\u30F3\u306E\u30C6\u30AD\u30B9\u30C8",
|
|
260
|
-
submitMode: "\u9001\u4FE1\u30DC\u30BF\u30F3\u306E\u8868\u793A",
|
|
261
|
-
combined: "\u307E\u3068\u3081\u30661\u3064",
|
|
262
|
-
perSection: "\u30BB\u30AF\u30B7\u30E7\u30F3\u3054\u3068",
|
|
263
|
-
settings: "\u30D5\u30A9\u30FC\u30E0\u8A2D\u5B9A",
|
|
264
268
|
fieldTypeInput: "\u5165\u529B",
|
|
265
269
|
fieldTypeTextarea: "\u30C6\u30AD\u30B9\u30C8\u30A8\u30EA\u30A2",
|
|
266
270
|
fieldTypeSelect: "\u30BB\u30EC\u30AF\u30C8",
|
|
@@ -270,6 +274,7 @@ var CHROME = {
|
|
|
270
274
|
fieldTypeToggle: "\u30C8\u30B0\u30EB",
|
|
271
275
|
fieldTypeParagraph: "\u6BB5\u843D",
|
|
272
276
|
fieldTypeImage: "\u753B\u50CF",
|
|
277
|
+
fieldTypeButton: "\u30DC\u30BF\u30F3",
|
|
273
278
|
subtypeText: "\u30C6\u30AD\u30B9\u30C8",
|
|
274
279
|
subtypeEmail: "\u30E1\u30FC\u30EB",
|
|
275
280
|
subtypePhone: "\u96FB\u8A71\u756A\u53F7",
|
|
@@ -282,8 +287,17 @@ var CHROME = {
|
|
|
282
287
|
shapeBanner: "\u30D0\u30CA\u30FC",
|
|
283
288
|
tagBody: "\u672C\u6587",
|
|
284
289
|
tagCaption: "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3",
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
buttonText: "\u30DC\u30BF\u30F3\u306E\u30C6\u30AD\u30B9\u30C8",
|
|
291
|
+
buttonActionTitle: "\u30A2\u30AF\u30B7\u30E7\u30F3",
|
|
292
|
+
buttonAction: "\u30AF\u30EA\u30C3\u30AF\u6642\u306E\u52D5\u4F5C",
|
|
293
|
+
actionLink: "\u30EA\u30F3\u30AF\u3092\u958B\u304F",
|
|
294
|
+
actionSubmit: "\u9001\u4FE1",
|
|
295
|
+
openIn: "\u958B\u304D\u65B9",
|
|
296
|
+
sameTab: "\u540C\u3058\u30BF\u30D6",
|
|
297
|
+
newTab: "\u65B0\u3057\u3044\u30BF\u30D6",
|
|
298
|
+
submitScope: "\u9001\u4FE1\u7BC4\u56F2",
|
|
299
|
+
thisSection: "\u3053\u306E\u30BB\u30AF\u30B7\u30E7\u30F3",
|
|
300
|
+
wholeForm: "\u30D5\u30A9\u30FC\u30E0\u5168\u4F53",
|
|
287
301
|
buttonSize: "\u30B5\u30A4\u30BA",
|
|
288
302
|
theme: "\u30C6\u30FC\u30DE",
|
|
289
303
|
primaryColor: "\u30E1\u30A4\u30F3\u30AB\u30E9\u30FC",
|
|
@@ -319,6 +333,19 @@ function withLang(val, lang, value) {
|
|
|
319
333
|
return { ...base, [lang]: value };
|
|
320
334
|
}
|
|
321
335
|
|
|
336
|
+
// src/lib/storage/compress.ts
|
|
337
|
+
import { compressToUTF16, decompressFromUTF16 } from "lz-string";
|
|
338
|
+
function compress(raw) {
|
|
339
|
+
return compressToUTF16(raw);
|
|
340
|
+
}
|
|
341
|
+
function decompress(value) {
|
|
342
|
+
try {
|
|
343
|
+
return decompressFromUTF16(value);
|
|
344
|
+
} catch {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
322
349
|
// src/lib/storage/localStorageAdapter.ts
|
|
323
350
|
function hasLocalStorage() {
|
|
324
351
|
return typeof window !== "undefined" && !!window.localStorage;
|
|
@@ -326,11 +353,21 @@ function hasLocalStorage() {
|
|
|
326
353
|
var localStorageAdapter = {
|
|
327
354
|
async get(key) {
|
|
328
355
|
if (!hasLocalStorage()) return null;
|
|
329
|
-
|
|
356
|
+
const raw = window.localStorage.getItem(key);
|
|
357
|
+
if (raw == null) return null;
|
|
358
|
+
const decompressed = decompress(raw);
|
|
359
|
+
if (decompressed != null) {
|
|
360
|
+
try {
|
|
361
|
+
JSON.parse(decompressed);
|
|
362
|
+
return decompressed;
|
|
363
|
+
} catch {
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return raw;
|
|
330
367
|
},
|
|
331
368
|
async set(key, value) {
|
|
332
369
|
if (!hasLocalStorage()) return;
|
|
333
|
-
window.localStorage.setItem(key, value);
|
|
370
|
+
window.localStorage.setItem(key, compress(value));
|
|
334
371
|
},
|
|
335
372
|
async delete(key) {
|
|
336
373
|
if (!hasLocalStorage()) return;
|
|
@@ -338,55 +375,6 @@ var localStorageAdapter = {
|
|
|
338
375
|
}
|
|
339
376
|
};
|
|
340
377
|
|
|
341
|
-
// src/hooks/useTheme.ts
|
|
342
|
-
import { useState } from "react";
|
|
343
|
-
|
|
344
|
-
// src/theme/defaultTheme.ts
|
|
345
|
-
var DEFAULT_THEME = {
|
|
346
|
-
primary: "#5B5FEF",
|
|
347
|
-
primarySoft: "#EEF0FF",
|
|
348
|
-
danger: "#C4432E",
|
|
349
|
-
dangerSoft: "#FDECE4",
|
|
350
|
-
ink: "#1B1E24",
|
|
351
|
-
muted: "#9296A3",
|
|
352
|
-
border: "#E2E4E9",
|
|
353
|
-
surface: "#FFFFFF",
|
|
354
|
-
canvas: "#F5F6F8",
|
|
355
|
-
pageBackground: "#FFFFFF",
|
|
356
|
-
layout: { maxWidth: 640, pagePadding: 28, canvasPadding: 20, sectionGap: 20, fieldGap: 16, toolbarPadding: 10, panelPadding: 14, ticketPadding: 14 }
|
|
357
|
-
};
|
|
358
|
-
|
|
359
|
-
// src/hooks/useTheme.ts
|
|
360
|
-
function useTheme(themeOverrideProp) {
|
|
361
|
-
const baseTheme = {
|
|
362
|
-
...DEFAULT_THEME,
|
|
363
|
-
...themeOverrideProp || {},
|
|
364
|
-
layout: { ...DEFAULT_THEME.layout, ...themeOverrideProp && themeOverrideProp.layout || {} }
|
|
365
|
-
};
|
|
366
|
-
const [themeOverrides, setThemeOverrides] = useState({});
|
|
367
|
-
const theme = {
|
|
368
|
-
...baseTheme,
|
|
369
|
-
...themeOverrides,
|
|
370
|
-
layout: { ...baseTheme.layout, ...themeOverrides.layout || {} }
|
|
371
|
-
};
|
|
372
|
-
function updateThemeColor(key, value) {
|
|
373
|
-
setThemeOverrides((prev) => ({ ...prev, [key]: value }));
|
|
374
|
-
}
|
|
375
|
-
function updateThemeLayout(key, value) {
|
|
376
|
-
setThemeOverrides((prev) => ({ ...prev, layout: { ...prev.layout, [key]: value } }));
|
|
377
|
-
}
|
|
378
|
-
function resetTheme() {
|
|
379
|
-
setThemeOverrides({});
|
|
380
|
-
}
|
|
381
|
-
function replaceThemeOverrides(overrides) {
|
|
382
|
-
setThemeOverrides(overrides);
|
|
383
|
-
}
|
|
384
|
-
return { theme, themeOverrides, updateThemeColor, updateThemeLayout, resetTheme, replaceThemeOverrides };
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// src/hooks/useFormDocument.ts
|
|
388
|
-
import { useState as useState2 } from "react";
|
|
389
|
-
|
|
390
378
|
// src/constants/fieldTypes.ts
|
|
391
379
|
import {
|
|
392
380
|
Type,
|
|
@@ -397,11 +385,13 @@ import {
|
|
|
397
385
|
CheckSquare,
|
|
398
386
|
ToggleLeft,
|
|
399
387
|
FileText,
|
|
400
|
-
Image as ImageIcon
|
|
388
|
+
Image as ImageIcon,
|
|
389
|
+
MousePointerClick
|
|
401
390
|
} from "lucide-react";
|
|
402
391
|
var FIELD_TYPES = [
|
|
403
392
|
{ type: "paragraph", icon: FileText, isContent: true, defaultIcon: "FileText" },
|
|
404
393
|
{ type: "image", icon: ImageIcon, isContent: true, isImage: true, defaultIcon: "Type" },
|
|
394
|
+
{ type: "button", icon: MousePointerClick, isContent: true, defaultIcon: "Type" },
|
|
405
395
|
{ type: "input", icon: Type, placeholder: true, hasSubtype: true, defaultIcon: "Type" },
|
|
406
396
|
{ type: "textarea", icon: AlignLeft, placeholder: true, defaultIcon: "AlignLeft" },
|
|
407
397
|
{ type: "select", icon: ChevronDown, options: true, defaultIcon: "ChevronDown" },
|
|
@@ -422,6 +412,7 @@ var IMAGE_SHAPES = ["square", "circle", "banner"];
|
|
|
422
412
|
var FIELD_TYPE_CHROME_KEY = {
|
|
423
413
|
paragraph: "fieldTypeParagraph",
|
|
424
414
|
image: "fieldTypeImage",
|
|
415
|
+
button: "fieldTypeButton",
|
|
425
416
|
input: "fieldTypeInput",
|
|
426
417
|
textarea: "fieldTypeTextarea",
|
|
427
418
|
select: "fieldTypeSelect",
|
|
@@ -500,21 +491,164 @@ function defaultFieldFor(type, language, chrome) {
|
|
|
500
491
|
base.fontStyle = "normal";
|
|
501
492
|
base.textAlign = "left";
|
|
502
493
|
base.color = "";
|
|
494
|
+
} else if (type === "button") {
|
|
495
|
+
base.action = "submit";
|
|
496
|
+
base.submitScope = "form";
|
|
497
|
+
base.buttonStyle = { color: "", size: "md" };
|
|
498
|
+
base.href = "";
|
|
499
|
+
base.target = "_self";
|
|
503
500
|
} else {
|
|
504
501
|
base.defaultValue = "";
|
|
505
502
|
}
|
|
506
503
|
return base;
|
|
507
504
|
}
|
|
508
505
|
function defaultSection(titleEn = "") {
|
|
509
|
-
return { id: genSectionId(), title: bi(titleEn, ""), background: "", collapsed: false,
|
|
506
|
+
return { id: genSectionId(), title: bi(titleEn, ""), background: "", collapsed: false, fields: [] };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/lib/submittable.ts
|
|
510
|
+
function sectionHasFormFields(section) {
|
|
511
|
+
return section.fields.some((f) => !getMeta(f.type).isContent);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// src/lib/migrate.ts
|
|
515
|
+
function migrateField(field) {
|
|
516
|
+
let f = { ...field };
|
|
517
|
+
if (LEGACY_INPUT_TYPES.includes(f.type)) f = { ...f, type: "input", inputType: f.type };
|
|
518
|
+
f.label = typeof f.label === "string" ? bi(f.label) : f.label || bi();
|
|
519
|
+
f.hideLabel = !!f.hideLabel;
|
|
520
|
+
if ("placeholder" in f) f.placeholder = typeof f.placeholder === "string" ? bi(f.placeholder) : f.placeholder || bi();
|
|
521
|
+
if ("content" in f) f.content = typeof f.content === "string" ? bi(f.content) : f.content || bi();
|
|
522
|
+
if ("alt" in f) f.alt = typeof f.alt === "string" ? bi(f.alt) : f.alt || bi();
|
|
523
|
+
if (f.options) f.options = f.options.map((o) => ({ ...o, label: typeof o.label === "string" ? bi(o.label) : o.label || bi() }));
|
|
524
|
+
if (f.type === "paragraph") {
|
|
525
|
+
f.tag = f.tag || "p";
|
|
526
|
+
f.fontSize = f.fontSize || "md";
|
|
527
|
+
f.fontWeight = f.fontWeight || "normal";
|
|
528
|
+
f.fontStyle = f.fontStyle || "normal";
|
|
529
|
+
f.textAlign = f.textAlign || "left";
|
|
530
|
+
f.color = f.color || "";
|
|
531
|
+
}
|
|
532
|
+
if (f.type === "button") {
|
|
533
|
+
f.action = f.action === "link" ? "link" : "submit";
|
|
534
|
+
f.buttonStyle = f.buttonStyle || { color: "", size: "md" };
|
|
535
|
+
f.href = f.href || "";
|
|
536
|
+
f.target = f.target === "_blank" ? "_blank" : "_self";
|
|
537
|
+
f.submitScope = f.submitScope === "section" ? "section" : "form";
|
|
538
|
+
}
|
|
539
|
+
f.verticalAlign = f.verticalAlign || "top";
|
|
540
|
+
return f;
|
|
541
|
+
}
|
|
542
|
+
function migrateFields(fields) {
|
|
543
|
+
return (fields || []).map(migrateField);
|
|
544
|
+
}
|
|
545
|
+
function synthesizeButtonField(label, style, scope) {
|
|
546
|
+
const resolvedLabel = typeof label === "string" && label ? bi(label) : label && typeof label === "object" && (label.en || label.ja) ? label : bi("Submit", "");
|
|
547
|
+
return {
|
|
548
|
+
id: nextId(),
|
|
549
|
+
type: "button",
|
|
550
|
+
label: resolvedLabel,
|
|
551
|
+
hideLabel: false,
|
|
552
|
+
width: "1/1",
|
|
553
|
+
verticalAlign: "top",
|
|
554
|
+
labelPosition: "top",
|
|
555
|
+
showIcon: false,
|
|
556
|
+
displayIcon: "Type",
|
|
557
|
+
action: "submit",
|
|
558
|
+
submitScope: scope,
|
|
559
|
+
buttonStyle: style || { color: "", size: "md" },
|
|
560
|
+
href: "",
|
|
561
|
+
target: "_self"
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function migrateDocument(raw) {
|
|
565
|
+
if (!raw) return null;
|
|
566
|
+
const title = typeof raw.title === "string" ? bi(raw.title) : raw.title || bi();
|
|
567
|
+
const themeOverrides = raw.themeOverrides || {};
|
|
568
|
+
let sections;
|
|
569
|
+
if (raw.sections) {
|
|
570
|
+
sections = raw.sections.map((s) => ({
|
|
571
|
+
id: s.id || genSectionId(),
|
|
572
|
+
title: typeof s.title === "string" ? bi(s.title) : s.title || bi(),
|
|
573
|
+
background: s.background || "",
|
|
574
|
+
collapsed: !!s.collapsed,
|
|
575
|
+
fields: migrateFields(s.fields || [])
|
|
576
|
+
}));
|
|
577
|
+
} else {
|
|
578
|
+
sections = [{ ...defaultSection(), fields: migrateFields(raw.fields || []) }];
|
|
579
|
+
}
|
|
580
|
+
const legacy = raw.version === void 0 || raw.version < 5;
|
|
581
|
+
if (legacy) {
|
|
582
|
+
resyncIdCounter(sections.flatMap((s) => s.fields));
|
|
583
|
+
const submitMode = raw.submitMode === "perSection" ? "perSection" : "combined";
|
|
584
|
+
const submitLabel = raw.submitLabel;
|
|
585
|
+
const submitStyle = raw.submitStyle || { color: "", size: "md" };
|
|
586
|
+
if (submitMode === "perSection" && raw.sections) {
|
|
587
|
+
sections = sections.map((s, i) => {
|
|
588
|
+
if (!sectionHasFormFields(s)) return s;
|
|
589
|
+
const rawSection = raw.sections[i] || {};
|
|
590
|
+
const label = rawSection.submitLabel || submitLabel;
|
|
591
|
+
const style = rawSection.submitStyle || submitStyle;
|
|
592
|
+
return { ...s, fields: [...s.fields, synthesizeButtonField(label, style, "section")] };
|
|
593
|
+
});
|
|
594
|
+
} else if (sections.some(sectionHasFormFields)) {
|
|
595
|
+
const lastIdx = sections.length - 1;
|
|
596
|
+
sections = sections.map((s, i) => i === lastIdx ? { ...s, fields: [...s.fields, synthesizeButtonField(submitLabel, submitStyle, "form")] } : s);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return { title, themeOverrides, sections };
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// src/hooks/useTheme.ts
|
|
603
|
+
import { useState } from "react";
|
|
604
|
+
|
|
605
|
+
// src/theme/defaultTheme.ts
|
|
606
|
+
var DEFAULT_THEME = {
|
|
607
|
+
primary: "#5B5FEF",
|
|
608
|
+
primarySoft: "#EEF0FF",
|
|
609
|
+
danger: "#C4432E",
|
|
610
|
+
dangerSoft: "#FDECE4",
|
|
611
|
+
ink: "#1B1E24",
|
|
612
|
+
muted: "#9296A3",
|
|
613
|
+
border: "#E2E4E9",
|
|
614
|
+
surface: "#FFFFFF",
|
|
615
|
+
canvas: "#F5F6F8",
|
|
616
|
+
pageBackground: "#FFFFFF",
|
|
617
|
+
layout: { maxWidth: 1200, pagePadding: 28, canvasPadding: 20, sectionGap: 20, fieldGap: 16, toolbarPadding: 10, panelPadding: 14, ticketPadding: 14 }
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
// src/hooks/useTheme.ts
|
|
621
|
+
function useTheme(themeOverrideProp) {
|
|
622
|
+
const baseTheme = {
|
|
623
|
+
...DEFAULT_THEME,
|
|
624
|
+
...themeOverrideProp || {},
|
|
625
|
+
layout: { ...DEFAULT_THEME.layout, ...themeOverrideProp && themeOverrideProp.layout || {} }
|
|
626
|
+
};
|
|
627
|
+
const [themeOverrides, setThemeOverrides] = useState({});
|
|
628
|
+
const theme = {
|
|
629
|
+
...baseTheme,
|
|
630
|
+
...themeOverrides,
|
|
631
|
+
layout: { ...baseTheme.layout, ...themeOverrides.layout || {} }
|
|
632
|
+
};
|
|
633
|
+
function updateThemeColor(key, value) {
|
|
634
|
+
setThemeOverrides((prev) => ({ ...prev, [key]: value }));
|
|
635
|
+
}
|
|
636
|
+
function updateThemeLayout(key, value) {
|
|
637
|
+
setThemeOverrides((prev) => ({ ...prev, layout: { ...prev.layout, [key]: value } }));
|
|
638
|
+
}
|
|
639
|
+
function resetTheme() {
|
|
640
|
+
setThemeOverrides({});
|
|
641
|
+
}
|
|
642
|
+
function replaceThemeOverrides(overrides) {
|
|
643
|
+
setThemeOverrides(overrides);
|
|
644
|
+
}
|
|
645
|
+
return { theme, themeOverrides, updateThemeColor, updateThemeLayout, resetTheme, replaceThemeOverrides };
|
|
510
646
|
}
|
|
511
647
|
|
|
512
648
|
// src/hooks/useFormDocument.ts
|
|
649
|
+
import { useState as useState2 } from "react";
|
|
513
650
|
function useFormDocument({ language, chrome }) {
|
|
514
651
|
const [title, setTitle] = useState2(bi("Untitled form", ""));
|
|
515
|
-
const [submitLabel, setSubmitLabelState] = useState2(bi());
|
|
516
|
-
const [submitMode, setSubmitMode] = useState2("combined");
|
|
517
|
-
const [submitStyle, setSubmitStyleState] = useState2({ color: "", size: "md" });
|
|
518
652
|
const [sections, setSections] = useState2([defaultSection()]);
|
|
519
653
|
const [activeSectionId, setActiveSectionId] = useState2(null);
|
|
520
654
|
const [selectedId, setSelectedId] = useState2(null);
|
|
@@ -524,12 +658,6 @@ function useFormDocument({ language, chrome }) {
|
|
|
524
658
|
function updateTitle(value) {
|
|
525
659
|
setTitle((prev) => withLang(prev, language, value));
|
|
526
660
|
}
|
|
527
|
-
function updateSubmitLabel(value) {
|
|
528
|
-
setSubmitLabelState((prev) => withLang(prev, language, value));
|
|
529
|
-
}
|
|
530
|
-
function updateSubmitStyle(patch) {
|
|
531
|
-
setSubmitStyleState((prev) => ({ ...prev, ...patch }));
|
|
532
|
-
}
|
|
533
661
|
function addSection() {
|
|
534
662
|
const s = defaultSection();
|
|
535
663
|
setSections((prev) => [...prev, s]);
|
|
@@ -574,12 +702,6 @@ function useFormDocument({ language, chrome }) {
|
|
|
574
702
|
function toggleSectionCollapse(sectionId) {
|
|
575
703
|
setSections((prev) => prev.map((s) => s.id === sectionId ? { ...s, collapsed: !s.collapsed } : s));
|
|
576
704
|
}
|
|
577
|
-
function updateSectionSubmitStyle(sectionId, patch) {
|
|
578
|
-
setSections((prev) => prev.map((s) => s.id === sectionId ? { ...s, submitStyle: { ...s.submitStyle || submitStyle, ...patch } } : s));
|
|
579
|
-
}
|
|
580
|
-
function clearSectionSubmitStyle(sectionId) {
|
|
581
|
-
setSections((prev) => prev.map((s) => s.id === sectionId ? { ...s, submitStyle: null } : s));
|
|
582
|
-
}
|
|
583
705
|
function addField(type) {
|
|
584
706
|
const field = defaultFieldFor(type, language, chrome);
|
|
585
707
|
const targetId = activeSectionId || sections[0]?.id;
|
|
@@ -657,9 +779,6 @@ function useFormDocument({ language, chrome }) {
|
|
|
657
779
|
setSections(doc.sections);
|
|
658
780
|
setActiveSectionId(doc.sections[0]?.id || null);
|
|
659
781
|
setTitle(doc.title);
|
|
660
|
-
setSubmitLabelState(doc.submitLabel);
|
|
661
|
-
setSubmitMode(doc.submitMode);
|
|
662
|
-
setSubmitStyleState(doc.submitStyle);
|
|
663
782
|
setSelectedId(null);
|
|
664
783
|
}
|
|
665
784
|
function resetToBlank() {
|
|
@@ -667,16 +786,10 @@ function useFormDocument({ language, chrome }) {
|
|
|
667
786
|
setSections([s]);
|
|
668
787
|
setActiveSectionId(s.id);
|
|
669
788
|
setTitle(bi("Untitled form", ""));
|
|
670
|
-
setSubmitLabelState(bi());
|
|
671
|
-
setSubmitMode("combined");
|
|
672
|
-
setSubmitStyleState({ color: "", size: "md" });
|
|
673
789
|
setSelectedId(null);
|
|
674
790
|
}
|
|
675
791
|
return {
|
|
676
792
|
title,
|
|
677
|
-
submitLabel,
|
|
678
|
-
submitMode,
|
|
679
|
-
submitStyle,
|
|
680
793
|
sections,
|
|
681
794
|
activeSectionId,
|
|
682
795
|
selectedId,
|
|
@@ -685,11 +798,8 @@ function useFormDocument({ language, chrome }) {
|
|
|
685
798
|
activeSection,
|
|
686
799
|
setActiveSectionId,
|
|
687
800
|
setSelectedId,
|
|
688
|
-
setSubmitMode,
|
|
689
801
|
setTitle,
|
|
690
802
|
updateTitle,
|
|
691
|
-
updateSubmitLabel,
|
|
692
|
-
updateSubmitStyle,
|
|
693
803
|
addSection,
|
|
694
804
|
duplicateSection,
|
|
695
805
|
deleteSection,
|
|
@@ -697,8 +807,6 @@ function useFormDocument({ language, chrome }) {
|
|
|
697
807
|
updateSectionTitle,
|
|
698
808
|
updateSectionBackground,
|
|
699
809
|
toggleSectionCollapse,
|
|
700
|
-
updateSectionSubmitStyle,
|
|
701
|
-
clearSectionSubmitStyle,
|
|
702
810
|
addField,
|
|
703
811
|
updateField,
|
|
704
812
|
deleteField,
|
|
@@ -721,62 +829,14 @@ var DRAFT_KEY = "form-page-builder:draft";
|
|
|
721
829
|
var INDEX_KEY = "form-page-builder:index";
|
|
722
830
|
var formKey = (id) => `form-page-builder:saved:${id}`;
|
|
723
831
|
|
|
724
|
-
// src/lib/migrate.ts
|
|
725
|
-
function migrateField(field) {
|
|
726
|
-
let f = { ...field };
|
|
727
|
-
if (LEGACY_INPUT_TYPES.includes(f.type)) f = { ...f, type: "input", inputType: f.type };
|
|
728
|
-
f.label = typeof f.label === "string" ? bi(f.label) : f.label || bi();
|
|
729
|
-
f.hideLabel = !!f.hideLabel;
|
|
730
|
-
if ("placeholder" in f) f.placeholder = typeof f.placeholder === "string" ? bi(f.placeholder) : f.placeholder || bi();
|
|
731
|
-
if ("content" in f) f.content = typeof f.content === "string" ? bi(f.content) : f.content || bi();
|
|
732
|
-
if ("alt" in f) f.alt = typeof f.alt === "string" ? bi(f.alt) : f.alt || bi();
|
|
733
|
-
if (f.options) f.options = f.options.map((o) => ({ ...o, label: typeof o.label === "string" ? bi(o.label) : o.label || bi() }));
|
|
734
|
-
if (f.type === "paragraph") {
|
|
735
|
-
f.tag = f.tag || "p";
|
|
736
|
-
f.fontSize = f.fontSize || "md";
|
|
737
|
-
f.fontWeight = f.fontWeight || "normal";
|
|
738
|
-
f.fontStyle = f.fontStyle || "normal";
|
|
739
|
-
f.textAlign = f.textAlign || "left";
|
|
740
|
-
f.color = f.color || "";
|
|
741
|
-
}
|
|
742
|
-
f.verticalAlign = f.verticalAlign || "top";
|
|
743
|
-
return f;
|
|
744
|
-
}
|
|
745
|
-
function migrateFields(fields) {
|
|
746
|
-
return (fields || []).map(migrateField);
|
|
747
|
-
}
|
|
748
|
-
function migrateDocument(raw) {
|
|
749
|
-
if (!raw) return null;
|
|
750
|
-
const title = typeof raw.title === "string" ? bi(raw.title) : raw.title || bi();
|
|
751
|
-
const submitLabel = typeof raw.submitLabel === "string" ? bi(raw.submitLabel) : raw.submitLabel || bi();
|
|
752
|
-
const submitMode = raw.submitMode === "perSection" ? "perSection" : "combined";
|
|
753
|
-
const submitStyle = raw.submitStyle || { color: "", size: "md" };
|
|
754
|
-
const themeOverrides = raw.themeOverrides || {};
|
|
755
|
-
if (raw.sections) {
|
|
756
|
-
return {
|
|
757
|
-
title,
|
|
758
|
-
submitLabel,
|
|
759
|
-
submitMode,
|
|
760
|
-
submitStyle,
|
|
761
|
-
themeOverrides,
|
|
762
|
-
sections: raw.sections.map((s) => ({
|
|
763
|
-
id: s.id || genSectionId(),
|
|
764
|
-
title: typeof s.title === "string" ? bi(s.title) : s.title || bi(),
|
|
765
|
-
background: s.background || "",
|
|
766
|
-
collapsed: !!s.collapsed,
|
|
767
|
-
submitStyle: s.submitStyle || null,
|
|
768
|
-
fields: migrateFields(s.fields || [])
|
|
769
|
-
}))
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
return { title, submitLabel, submitMode, submitStyle, themeOverrides, sections: [{ ...defaultSection(), fields: migrateFields(raw.fields || []) }] };
|
|
773
|
-
}
|
|
774
|
-
|
|
775
832
|
// src/hooks/usePersistence.ts
|
|
833
|
+
var MAX_TEMPLATES = 5;
|
|
776
834
|
function usePersistence({
|
|
777
835
|
storage,
|
|
778
836
|
language,
|
|
837
|
+
chrome,
|
|
779
838
|
document,
|
|
839
|
+
initialDocument,
|
|
780
840
|
onLoadDocument,
|
|
781
841
|
onLoadThemeOverrides,
|
|
782
842
|
onTitleChange,
|
|
@@ -802,17 +862,27 @@ function usePersistence({
|
|
|
802
862
|
useEffect(() => {
|
|
803
863
|
(async () => {
|
|
804
864
|
try {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
const parsed = JSON.parse(raw);
|
|
808
|
-
const doc = migrateDocument(parsed);
|
|
865
|
+
if (initialDocument) {
|
|
866
|
+
const doc = migrateDocument(initialDocument);
|
|
809
867
|
if (doc) {
|
|
810
868
|
onLoadDocument(doc);
|
|
811
869
|
onLoadThemeOverrides(doc.themeOverrides);
|
|
870
|
+
} else {
|
|
871
|
+
ensureActiveSection();
|
|
812
872
|
}
|
|
813
|
-
if (parsed.currentFormId) setCurrentFormId(parsed.currentFormId);
|
|
814
873
|
} else {
|
|
815
|
-
|
|
874
|
+
const raw = await storage.get(DRAFT_KEY);
|
|
875
|
+
if (raw) {
|
|
876
|
+
const parsed = JSON.parse(raw);
|
|
877
|
+
const doc = migrateDocument(parsed);
|
|
878
|
+
if (doc) {
|
|
879
|
+
onLoadDocument(doc);
|
|
880
|
+
onLoadThemeOverrides(doc.themeOverrides);
|
|
881
|
+
}
|
|
882
|
+
if (parsed.currentFormId) setCurrentFormId(parsed.currentFormId);
|
|
883
|
+
} else {
|
|
884
|
+
ensureActiveSection();
|
|
885
|
+
}
|
|
816
886
|
}
|
|
817
887
|
} catch (err) {
|
|
818
888
|
ensureActiveSection();
|
|
@@ -838,8 +908,12 @@ function usePersistence({
|
|
|
838
908
|
return () => {
|
|
839
909
|
if (autosaveTimer.current) clearTimeout(autosaveTimer.current);
|
|
840
910
|
};
|
|
841
|
-
}, [document.title, document.
|
|
911
|
+
}, [document.title, document.themeOverrides, document.sections, currentFormId]);
|
|
842
912
|
async function saveAs(name) {
|
|
913
|
+
if (savedForms.length >= MAX_TEMPLATES) {
|
|
914
|
+
alert(chrome.templatesLimitReached);
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
843
917
|
const id = genFormId();
|
|
844
918
|
const now = Date.now();
|
|
845
919
|
try {
|
|
@@ -948,11 +1022,11 @@ function useDragReorder(reorderWithinSection) {
|
|
|
948
1022
|
}
|
|
949
1023
|
|
|
950
1024
|
// src/components/Toolbar.tsx
|
|
951
|
-
import { Loader2, AlertCircle,
|
|
1025
|
+
import { Loader2, AlertCircle, Pencil, Eye, FilePlus2, FolderOpen, Save, Code2 } from "lucide-react";
|
|
952
1026
|
|
|
953
1027
|
// src/styles/styles.ts
|
|
954
1028
|
var styles = {
|
|
955
|
-
app: { fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif", background: "var(--fb-canvas)", borderRadius: 12, overflow: "hidden", border: "1px solid var(--fb-border)", color: "var(--fb-ink)",
|
|
1029
|
+
app: { fontFamily: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif", background: "var(--fb-canvas)", borderRadius: 12, overflow: "hidden", border: "1px solid var(--fb-border)", color: "var(--fb-ink)", display: "flex", flexDirection: "column" },
|
|
956
1030
|
toolbar: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "var(--fb-space-toolbar) 16px", borderBottom: "1px solid var(--fb-border)", background: "var(--fb-surface)", flexWrap: "wrap", gap: 8, position: "relative" },
|
|
957
1031
|
toolbarLeft: { display: "flex", alignItems: "center", gap: 10 },
|
|
958
1032
|
logoMark: { width: 26, height: 26, borderRadius: 7, background: "var(--fb-primary)", color: "#fff", fontSize: 11, fontWeight: 700, display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "'JetBrains Mono', monospace", letterSpacing: "-0.5px" },
|
|
@@ -985,8 +1059,6 @@ var styles = {
|
|
|
985
1059
|
sectionTitleInput: { border: "none", outline: "none", background: "transparent", fontSize: 14, fontWeight: 700, color: "var(--fb-ink)", padding: "2px 0", minWidth: 120, flex: 1 },
|
|
986
1060
|
sectionHeaderActions: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", marginLeft: "auto" },
|
|
987
1061
|
sectionEmpty: { fontSize: 12.5, color: "var(--fb-muted)", padding: "18px 4px", textAlign: "center", border: "1px dashed var(--fb-border)", borderRadius: 8 },
|
|
988
|
-
submitStyleRow: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", background: "#F7F8FA", border: "1px solid #F0F1F4", borderRadius: 8, padding: "6px 10px", marginBottom: 12 },
|
|
989
|
-
miniLabel: { fontSize: 11, fontWeight: 600, color: "var(--fb-muted)" },
|
|
990
1062
|
resetLinkBtn: { display: "flex", alignItems: "center", gap: 3, fontSize: 11, color: "var(--fb-muted)", background: "transparent", border: "none", padding: "2px 4px" },
|
|
991
1063
|
addSectionBtn: { display: "flex", alignItems: "center", justifyContent: "center", gap: 6, width: "100%", padding: "10px", borderRadius: 10, border: "1px dashed #C7C9D6", background: "transparent", color: "var(--fb-primary)", fontSize: 13, fontWeight: 600 },
|
|
992
1064
|
swatchRow: { display: "flex", alignItems: "center", gap: 5, flexWrap: "wrap" },
|
|
@@ -1005,6 +1077,10 @@ var styles = {
|
|
|
1005
1077
|
requiredBadge: { fontSize: 10, fontWeight: 700, color: "#B4522F", background: "var(--fb-danger-soft)", padding: "2px 6px", borderRadius: 5, letterSpacing: "0.02em", marginLeft: "auto" },
|
|
1006
1078
|
chipRow: { display: "flex", gap: 5, marginBottom: 7, flexWrap: "wrap" },
|
|
1007
1079
|
miniBadge: { fontSize: 10, fontWeight: 600, color: "var(--fb-primary)", background: "var(--fb-primary-soft)", padding: "2px 6px", borderRadius: 5, letterSpacing: "0.02em" },
|
|
1080
|
+
langToggleTrack: { position: "relative", display: "flex", gap: 3, background: "#F0F1F4", padding: 3, borderRadius: 20 },
|
|
1081
|
+
langToggleThumb: { position: "absolute", top: 3, left: 3, bottom: 3, background: "var(--fb-primary)", borderRadius: 17, transition: "transform 0.18s ease" },
|
|
1082
|
+
langToggleBtn: { position: "relative", zIndex: 1, padding: "5px 12px", borderRadius: 17, border: "none", background: "transparent", color: "#6B6E79", fontSize: 12.5, fontWeight: 600, whiteSpace: "nowrap" },
|
|
1083
|
+
langToggleBtnActive: { position: "relative", zIndex: 1, padding: "5px 12px", borderRadius: 17, border: "none", background: "transparent", color: "#fff", fontSize: 12.5, fontWeight: 600, whiteSpace: "nowrap" },
|
|
1008
1084
|
segmented: { display: "flex", gap: 3, background: "#F0F1F4", padding: 3, borderRadius: 8, marginBottom: 4 },
|
|
1009
1085
|
segmentedBtn: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "6px 8px", borderRadius: 6, border: "none", background: "transparent", color: "#6B6E79", fontSize: 12.5, fontWeight: 500 },
|
|
1010
1086
|
segmentedBtnActive: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "6px 8px", borderRadius: 6, border: "none", background: "#fff", color: "var(--fb-ink)", fontSize: 12.5, fontWeight: 600, boxShadow: "0 1px 2px rgba(0,0,0,0.08)" },
|
|
@@ -1055,29 +1131,136 @@ var styles = {
|
|
|
1055
1131
|
realInput: { width: "100%", border: "1px solid var(--fb-border)", borderRadius: 8, padding: "9px 11px", fontSize: 13.5, outline: "none", color: "var(--fb-ink)", boxSizing: "border-box" },
|
|
1056
1132
|
realInputError: { borderColor: "var(--fb-danger)" },
|
|
1057
1133
|
submitBtn: { marginTop: 8, color: "#fff", border: "none", borderRadius: 8, fontWeight: 600, width: "100%" },
|
|
1058
|
-
layoutPanel: { position: "absolute", top: "calc(100% + 6px)", right: 0, width: 260, background: "#fff", border: "1px solid var(--fb-border)", borderRadius: 10, boxShadow: "0 12px 32px rgba(0,0,0,0.18)", padding: 14, zIndex: 60, maxHeight: "70vh", overflowY: "auto" },
|
|
1059
1134
|
layoutPanelHeader: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 },
|
|
1060
1135
|
spacingRow: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, padding: "4px 0" },
|
|
1061
1136
|
spacingLabel: { fontSize: 12, color: "#4A4D57" },
|
|
1062
1137
|
spacingInput: { width: 60, border: "1px solid var(--fb-border)", borderRadius: 6, padding: "4px 6px", fontSize: 12, textAlign: "right", outline: "none" }
|
|
1063
1138
|
};
|
|
1064
1139
|
|
|
1065
|
-
// src/components/
|
|
1140
|
+
// src/components/LanguageToggle.tsx
|
|
1066
1141
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1142
|
+
function LanguageToggle({ languages, value, onChange }) {
|
|
1143
|
+
const activeIdx = Math.max(0, languages.findIndex((l) => l.code === value));
|
|
1144
|
+
const n = languages.length || 1;
|
|
1145
|
+
return /* @__PURE__ */ jsxs("div", { style: styles.langToggleTrack, children: [
|
|
1146
|
+
/* @__PURE__ */ jsx(
|
|
1147
|
+
"div",
|
|
1148
|
+
{
|
|
1149
|
+
style: {
|
|
1150
|
+
...styles.langToggleThumb,
|
|
1151
|
+
width: `calc(${100 / n}% - 3px)`,
|
|
1152
|
+
transform: `translateX(calc(${activeIdx * 100}% + ${activeIdx * 3}px))`
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
),
|
|
1156
|
+
languages.map((l) => /* @__PURE__ */ jsx(
|
|
1157
|
+
"button",
|
|
1158
|
+
{
|
|
1159
|
+
type: "button",
|
|
1160
|
+
style: l.code === value ? styles.langToggleBtnActive : styles.langToggleBtn,
|
|
1161
|
+
onClick: () => onChange(l.code),
|
|
1162
|
+
children: l.label
|
|
1163
|
+
},
|
|
1164
|
+
l.code
|
|
1165
|
+
))
|
|
1166
|
+
] });
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// src/components/Toolbar.tsx
|
|
1170
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1171
|
+
function Toolbar({
|
|
1172
|
+
title,
|
|
1173
|
+
language,
|
|
1174
|
+
languages,
|
|
1175
|
+
mode,
|
|
1176
|
+
saveState,
|
|
1177
|
+
chrome,
|
|
1178
|
+
savedFormsCount,
|
|
1179
|
+
onTitleChange,
|
|
1180
|
+
onLanguageChange,
|
|
1181
|
+
onModeChange,
|
|
1182
|
+
onNewForm,
|
|
1183
|
+
onOpenLibrary,
|
|
1184
|
+
onSaveExisting,
|
|
1185
|
+
onOpenJson
|
|
1186
|
+
}) {
|
|
1187
|
+
return /* @__PURE__ */ jsxs2("div", { style: styles.toolbar, children: [
|
|
1188
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.toolbarLeft, children: [
|
|
1189
|
+
/* @__PURE__ */ jsx2("div", { style: styles.logoMark, children: "FB" }),
|
|
1190
|
+
/* @__PURE__ */ jsx2("input", { value: t(title, language), onChange: (e) => onTitleChange(e.target.value), style: styles.titleInput, "aria-label": "Form title" })
|
|
1191
|
+
] }),
|
|
1192
|
+
/* @__PURE__ */ jsxs2("div", { style: styles.toolbarRight, children: [
|
|
1193
|
+
/* @__PURE__ */ jsxs2("span", { style: styles.saveStatus, children: [
|
|
1194
|
+
saveState === "saving" && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
1195
|
+
/* @__PURE__ */ jsx2(Loader2, { size: 12, className: "spin" }),
|
|
1196
|
+
" ",
|
|
1197
|
+
chrome.saving
|
|
1198
|
+
] }),
|
|
1199
|
+
saveState === "saved" && chrome.saved,
|
|
1200
|
+
saveState === "error" && /* @__PURE__ */ jsxs2("span", { style: { color: "var(--fb-danger)", display: "flex", alignItems: "center", gap: 4 }, children: [
|
|
1201
|
+
/* @__PURE__ */ jsx2(AlertCircle, { size: 12 }),
|
|
1202
|
+
" ",
|
|
1203
|
+
chrome.saveFailed
|
|
1204
|
+
] })
|
|
1205
|
+
] }),
|
|
1206
|
+
/* @__PURE__ */ jsx2("div", { style: styles.toolbarDivider }),
|
|
1207
|
+
/* @__PURE__ */ jsx2(LanguageToggle, { languages, value: language, onChange: onLanguageChange }),
|
|
1208
|
+
/* @__PURE__ */ jsx2("div", { style: styles.toolbarDivider }),
|
|
1209
|
+
/* @__PURE__ */ jsxs2("button", { style: mode === "build" ? styles.tabBtnActive : styles.tabBtn, onClick: () => onModeChange("build"), children: [
|
|
1210
|
+
/* @__PURE__ */ jsx2(Pencil, { size: 14 }),
|
|
1211
|
+
" ",
|
|
1212
|
+
chrome.build
|
|
1213
|
+
] }),
|
|
1214
|
+
/* @__PURE__ */ jsxs2("button", { style: mode === "preview" ? styles.tabBtnActive : styles.tabBtn, onClick: () => onModeChange("preview"), children: [
|
|
1215
|
+
/* @__PURE__ */ jsx2(Eye, { size: 14 }),
|
|
1216
|
+
" ",
|
|
1217
|
+
chrome.preview
|
|
1218
|
+
] }),
|
|
1219
|
+
/* @__PURE__ */ jsx2("div", { style: styles.toolbarDivider }),
|
|
1220
|
+
/* @__PURE__ */ jsxs2("button", { style: styles.ghostBtn, onClick: onNewForm, title: chrome.startNewForm, children: [
|
|
1221
|
+
/* @__PURE__ */ jsx2(FilePlus2, { size: 14 }),
|
|
1222
|
+
" ",
|
|
1223
|
+
chrome.newForm
|
|
1224
|
+
] }),
|
|
1225
|
+
/* @__PURE__ */ jsxs2("button", { style: styles.ghostBtn, onClick: onOpenLibrary, title: chrome.openTemplatesTitle, children: [
|
|
1226
|
+
/* @__PURE__ */ jsx2(FolderOpen, { size: 14 }),
|
|
1227
|
+
" ",
|
|
1228
|
+
chrome.templates,
|
|
1229
|
+
savedFormsCount > 0 && /* @__PURE__ */ jsx2("span", { style: styles.countBadge, children: savedFormsCount })
|
|
1230
|
+
] }),
|
|
1231
|
+
/* @__PURE__ */ jsxs2("button", { style: styles.primaryBtn, onClick: onSaveExisting, title: chrome.saveToLibraryTitle, children: [
|
|
1232
|
+
/* @__PURE__ */ jsx2(Save, { size: 14 }),
|
|
1233
|
+
" ",
|
|
1234
|
+
chrome.save
|
|
1235
|
+
] }),
|
|
1236
|
+
/* @__PURE__ */ jsxs2("button", { style: styles.ghostBtn, onClick: onOpenJson, children: [
|
|
1237
|
+
/* @__PURE__ */ jsx2(Code2, { size: 14 }),
|
|
1238
|
+
" ",
|
|
1239
|
+
chrome.viewJson
|
|
1240
|
+
] })
|
|
1241
|
+
] })
|
|
1242
|
+
] });
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// src/components/Palette.tsx
|
|
1246
|
+
import { useState as useState5 } from "react";
|
|
1247
|
+
import { Plus } from "lucide-react";
|
|
1248
|
+
|
|
1249
|
+
// src/components/Segmented.tsx
|
|
1250
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1067
1251
|
function Segmented({ options, value, onChange }) {
|
|
1068
|
-
return /* @__PURE__ */
|
|
1252
|
+
return /* @__PURE__ */ jsx3("div", { style: styles.segmented, children: options.map((opt) => {
|
|
1069
1253
|
const Icon = opt.icon;
|
|
1070
1254
|
const active = value === opt.value;
|
|
1071
|
-
return /* @__PURE__ */
|
|
1072
|
-
Icon && /* @__PURE__ */
|
|
1255
|
+
return /* @__PURE__ */ jsxs3("button", { type: "button", style: active ? styles.segmentedBtnActive : styles.segmentedBtn, onClick: () => onChange(opt.value), children: [
|
|
1256
|
+
Icon && /* @__PURE__ */ jsx3(Icon, { size: 13 }),
|
|
1073
1257
|
opt.label
|
|
1074
1258
|
] }, opt.value);
|
|
1075
1259
|
}) });
|
|
1076
1260
|
}
|
|
1077
1261
|
|
|
1078
|
-
// src/components/
|
|
1079
|
-
import {
|
|
1080
|
-
import { Ruler, RotateCcw } from "lucide-react";
|
|
1262
|
+
// src/components/DesignPanel.tsx
|
|
1263
|
+
import { RotateCcw } from "lucide-react";
|
|
1081
1264
|
|
|
1082
1265
|
// src/constants/colors.ts
|
|
1083
1266
|
var COLOR_SWATCHES = ["", "#1B1E24", "#5B5FEF", "#C4432E", "#0EA5A4", "#D97706"];
|
|
@@ -1100,12 +1283,8 @@ function effectiveWidth(width, device) {
|
|
|
1100
1283
|
}
|
|
1101
1284
|
var SPACING_FIELDS = [
|
|
1102
1285
|
{ key: "pagePadding", labelKey: "spacingPagePadding" },
|
|
1103
|
-
{ key: "canvasPadding", labelKey: "spacingCanvasPadding" },
|
|
1104
1286
|
{ key: "sectionGap", labelKey: "spacingSectionGap" },
|
|
1105
|
-
{ key: "fieldGap", labelKey: "spacingFieldGap" }
|
|
1106
|
-
{ key: "toolbarPadding", labelKey: "spacingToolbarPadding" },
|
|
1107
|
-
{ key: "panelPadding", labelKey: "spacingPanelPadding" },
|
|
1108
|
-
{ key: "ticketPadding", labelKey: "spacingTicketPadding" }
|
|
1287
|
+
{ key: "fieldGap", labelKey: "spacingFieldGap" }
|
|
1109
1288
|
];
|
|
1110
1289
|
function buildDeviceOptions(baseMaxWidth, chrome) {
|
|
1111
1290
|
const mw = Number(baseMaxWidth) > 0 ? baseMaxWidth : DEFAULT_THEME.layout.maxWidth;
|
|
@@ -1116,184 +1295,106 @@ function buildDeviceOptions(baseMaxWidth, chrome) {
|
|
|
1116
1295
|
];
|
|
1117
1296
|
}
|
|
1118
1297
|
|
|
1119
|
-
// src/components/
|
|
1120
|
-
import { jsx as
|
|
1121
|
-
function
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
/* @__PURE__ */
|
|
1139
|
-
/* @__PURE__ */
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
] })
|
|
1148
|
-
|
|
1149
|
-
/* @__PURE__ */ jsx2("input", { type: "number", style: styles.propInput, value: theme.layout.maxWidth, onChange: (e) => updateThemeLayout("maxWidth", Number(e.target.value) || DEFAULT_THEME.layout.maxWidth) }),
|
|
1150
|
-
/* @__PURE__ */ jsx2("div", { style: styles.inspectorDivider }),
|
|
1151
|
-
/* @__PURE__ */ jsx2("div", { style: styles.panelHeading, children: chrome.spacing }),
|
|
1152
|
-
SPACING_FIELDS.map(({ key, labelKey }) => /* @__PURE__ */ jsxs2("div", { style: styles.spacingRow, children: [
|
|
1153
|
-
/* @__PURE__ */ jsx2("span", { style: styles.spacingLabel, children: chrome[labelKey] }),
|
|
1154
|
-
/* @__PURE__ */ jsx2("input", { type: "number", style: styles.spacingInput, value: theme.layout[key], onChange: (e) => updateThemeLayout(key, Number(e.target.value) || 0) })
|
|
1155
|
-
] }, key))
|
|
1156
|
-
] })
|
|
1298
|
+
// src/components/DesignPanel.tsx
|
|
1299
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1300
|
+
function DesignPanel({ chrome, theme, updateThemeColor, updateThemeLayout, resetTheme }) {
|
|
1301
|
+
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
1302
|
+
/* @__PURE__ */ jsxs4("div", { style: styles.layoutPanelHeader, children: [
|
|
1303
|
+
/* @__PURE__ */ jsx4("span", { style: { fontWeight: 600, fontSize: 13 }, children: chrome.theme }),
|
|
1304
|
+
/* @__PURE__ */ jsxs4("button", { type: "button", style: styles.resetLinkBtn, onClick: resetTheme, children: [
|
|
1305
|
+
/* @__PURE__ */ jsx4(RotateCcw, { size: 11 }),
|
|
1306
|
+
" ",
|
|
1307
|
+
chrome.reset
|
|
1308
|
+
] })
|
|
1309
|
+
] }),
|
|
1310
|
+
/* @__PURE__ */ jsx4("label", { style: styles.propLabel, children: chrome.primaryColor }),
|
|
1311
|
+
/* @__PURE__ */ jsxs4("div", { style: styles.swatchRow, children: [
|
|
1312
|
+
BUTTON_COLOR_SWATCHES.slice(1).map((c) => /* @__PURE__ */ jsx4("button", { type: "button", title: c, style: { ...styles.swatchBtn, background: c, ...theme.primary === c ? styles.swatchBtnActive : {} }, onClick: () => updateThemeColor("primary", c) }, c)),
|
|
1313
|
+
/* @__PURE__ */ jsx4("input", { type: "color", value: theme.primary, onChange: (e) => updateThemeColor("primary", e.target.value), style: styles.colorPickerInput })
|
|
1314
|
+
] }),
|
|
1315
|
+
/* @__PURE__ */ jsx4("label", { style: styles.propLabel, children: chrome.pageBackground }),
|
|
1316
|
+
/* @__PURE__ */ jsxs4("div", { style: styles.swatchRow, children: [
|
|
1317
|
+
SECTION_BG_SWATCHES.filter(Boolean).map((c) => /* @__PURE__ */ jsx4("button", { type: "button", title: c, style: { ...styles.swatchBtn, background: c, ...theme.pageBackground === c ? styles.swatchBtnActive : {} }, onClick: () => updateThemeColor("pageBackground", c) }, c)),
|
|
1318
|
+
/* @__PURE__ */ jsx4("input", { type: "color", value: theme.pageBackground, onChange: (e) => updateThemeColor("pageBackground", e.target.value), style: styles.colorPickerInput })
|
|
1319
|
+
] }),
|
|
1320
|
+
/* @__PURE__ */ jsx4("label", { style: styles.propLabel, children: chrome.maxWidthPx }),
|
|
1321
|
+
/* @__PURE__ */ jsx4("input", { type: "number", style: styles.propInput, value: theme.layout.maxWidth, onChange: (e) => updateThemeLayout("maxWidth", Number(e.target.value) || DEFAULT_THEME.layout.maxWidth) }),
|
|
1322
|
+
/* @__PURE__ */ jsx4("div", { style: styles.inspectorDivider }),
|
|
1323
|
+
/* @__PURE__ */ jsx4("div", { style: styles.panelHeading, children: chrome.spacing }),
|
|
1324
|
+
SPACING_FIELDS.map(({ key, labelKey }) => /* @__PURE__ */ jsxs4("div", { style: styles.spacingRow, children: [
|
|
1325
|
+
/* @__PURE__ */ jsx4("span", { style: styles.spacingLabel, children: chrome[labelKey] }),
|
|
1326
|
+
/* @__PURE__ */ jsx4("input", { type: "number", style: styles.spacingInput, value: theme.layout[key], onChange: (e) => updateThemeLayout(key, Number(e.target.value) || 0) })
|
|
1327
|
+
] }, key))
|
|
1157
1328
|
] });
|
|
1158
1329
|
}
|
|
1159
1330
|
|
|
1160
|
-
// src/components/
|
|
1161
|
-
import { Fragment, jsx as
|
|
1162
|
-
function
|
|
1163
|
-
|
|
1164
|
-
language,
|
|
1165
|
-
languages,
|
|
1166
|
-
mode,
|
|
1167
|
-
saveState,
|
|
1331
|
+
// src/components/Palette.tsx
|
|
1332
|
+
import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1333
|
+
function Palette({
|
|
1334
|
+
activeSectionLabel,
|
|
1168
1335
|
chrome,
|
|
1336
|
+
onAddField,
|
|
1169
1337
|
themeEditable,
|
|
1170
1338
|
theme,
|
|
1171
|
-
savedFormsCount,
|
|
1172
|
-
onTitleChange,
|
|
1173
|
-
onLanguageChange,
|
|
1174
|
-
onModeChange,
|
|
1175
|
-
onOpenSettings,
|
|
1176
|
-
onNewForm,
|
|
1177
|
-
onOpenLibrary,
|
|
1178
|
-
onSaveExisting,
|
|
1179
|
-
onOpenJson,
|
|
1180
1339
|
updateThemeColor,
|
|
1181
1340
|
updateThemeLayout,
|
|
1182
1341
|
resetTheme
|
|
1183
1342
|
}) {
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
/* @__PURE__ */
|
|
1208
|
-
|
|
1209
|
-
" ",
|
|
1210
|
-
chrome.build
|
|
1211
|
-
] }),
|
|
1212
|
-
/* @__PURE__ */ jsxs3("button", { style: mode === "preview" ? styles.tabBtnActive : styles.tabBtn, onClick: () => onModeChange("preview"), children: [
|
|
1213
|
-
/* @__PURE__ */ jsx3(Eye, { size: 14 }),
|
|
1214
|
-
" ",
|
|
1215
|
-
chrome.preview
|
|
1216
|
-
] }),
|
|
1217
|
-
/* @__PURE__ */ jsx3("div", { style: styles.toolbarDivider }),
|
|
1218
|
-
themeEditable && /* @__PURE__ */ jsx3(LayoutPopover, { chrome, theme, updateThemeColor, updateThemeLayout, resetTheme }),
|
|
1219
|
-
/* @__PURE__ */ jsx3("button", { style: styles.iconBtn, title: chrome.settings, onClick: onOpenSettings, children: /* @__PURE__ */ jsx3(Settings, { size: 14 }) }),
|
|
1220
|
-
/* @__PURE__ */ jsxs3("button", { style: styles.ghostBtn, onClick: onNewForm, title: chrome.startNewForm, children: [
|
|
1221
|
-
/* @__PURE__ */ jsx3(FilePlus2, { size: 14 }),
|
|
1222
|
-
" ",
|
|
1223
|
-
chrome.newForm
|
|
1224
|
-
] }),
|
|
1225
|
-
/* @__PURE__ */ jsxs3("button", { style: styles.ghostBtn, onClick: onOpenLibrary, title: chrome.openSavedForm, children: [
|
|
1226
|
-
/* @__PURE__ */ jsx3(FolderOpen, { size: 14 }),
|
|
1227
|
-
" ",
|
|
1228
|
-
chrome.myForms,
|
|
1229
|
-
savedFormsCount > 0 && /* @__PURE__ */ jsx3("span", { style: styles.countBadge, children: savedFormsCount })
|
|
1230
|
-
] }),
|
|
1231
|
-
/* @__PURE__ */ jsxs3("button", { style: styles.primaryBtn, onClick: onSaveExisting, title: chrome.saveToLibraryTitle, children: [
|
|
1232
|
-
/* @__PURE__ */ jsx3(Save, { size: 14 }),
|
|
1343
|
+
const [tab, setTab] = useState5("blocks");
|
|
1344
|
+
return /* @__PURE__ */ jsxs5("div", { style: styles.palette, children: [
|
|
1345
|
+
themeEditable && /* @__PURE__ */ jsx5("div", { style: { marginBottom: 14 }, children: /* @__PURE__ */ jsx5(
|
|
1346
|
+
Segmented,
|
|
1347
|
+
{
|
|
1348
|
+
options: [
|
|
1349
|
+
{ value: "blocks", label: chrome.paletteTabBlocks },
|
|
1350
|
+
{ value: "design", label: chrome.paletteTabDesign }
|
|
1351
|
+
],
|
|
1352
|
+
value: tab,
|
|
1353
|
+
onChange: setTab
|
|
1354
|
+
}
|
|
1355
|
+
) }),
|
|
1356
|
+
tab === "design" && themeEditable ? /* @__PURE__ */ jsx5(
|
|
1357
|
+
DesignPanel,
|
|
1358
|
+
{
|
|
1359
|
+
chrome,
|
|
1360
|
+
theme,
|
|
1361
|
+
updateThemeColor,
|
|
1362
|
+
updateThemeLayout,
|
|
1363
|
+
resetTheme
|
|
1364
|
+
}
|
|
1365
|
+
) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1366
|
+
/* @__PURE__ */ jsxs5("div", { style: styles.activeSectionHint, children: [
|
|
1367
|
+
chrome.addingTo,
|
|
1233
1368
|
" ",
|
|
1234
|
-
|
|
1369
|
+
/* @__PURE__ */ jsx5("strong", { children: activeSectionLabel })
|
|
1235
1370
|
] }),
|
|
1236
|
-
/* @__PURE__ */
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1371
|
+
/* @__PURE__ */ jsx5("div", { style: styles.panelHeading, children: chrome.contentBlocks }),
|
|
1372
|
+
/* @__PURE__ */ jsx5("div", { style: styles.paletteList, children: CONTENT_TYPES.map((f) => {
|
|
1373
|
+
const Icon = f.icon;
|
|
1374
|
+
return /* @__PURE__ */ jsxs5("button", { style: styles.paletteItem, onClick: () => onAddField(f.type), children: [
|
|
1375
|
+
/* @__PURE__ */ jsx5(Icon, { size: 16, color: "var(--fb-primary)" }),
|
|
1376
|
+
/* @__PURE__ */ jsx5("span", { children: chrome[FIELD_TYPE_CHROME_KEY[f.type]] }),
|
|
1377
|
+
/* @__PURE__ */ jsx5(Plus, { size: 13, color: "#A6A8B3", style: { marginLeft: "auto" } })
|
|
1378
|
+
] }, f.type);
|
|
1379
|
+
}) }),
|
|
1380
|
+
/* @__PURE__ */ jsx5("div", { style: { ...styles.panelHeading, marginTop: 16 }, children: chrome.formFields }),
|
|
1381
|
+
/* @__PURE__ */ jsx5("div", { style: styles.paletteList, children: FORM_TYPES.map((f) => {
|
|
1382
|
+
const Icon = f.icon;
|
|
1383
|
+
return /* @__PURE__ */ jsxs5("button", { style: styles.paletteItem, onClick: () => onAddField(f.type), children: [
|
|
1384
|
+
/* @__PURE__ */ jsx5(Icon, { size: 16, color: "var(--fb-primary)" }),
|
|
1385
|
+
/* @__PURE__ */ jsx5("span", { children: chrome[FIELD_TYPE_CHROME_KEY[f.type]] }),
|
|
1386
|
+
/* @__PURE__ */ jsx5(Plus, { size: 13, color: "#A6A8B3", style: { marginLeft: "auto" } })
|
|
1387
|
+
] }, f.type);
|
|
1388
|
+
}) })
|
|
1241
1389
|
] })
|
|
1242
1390
|
] });
|
|
1243
1391
|
}
|
|
1244
1392
|
|
|
1245
|
-
// src/components/Palette.tsx
|
|
1246
|
-
import { Plus } from "lucide-react";
|
|
1247
|
-
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1248
|
-
function Palette({ activeSectionLabel, chrome, onAddField }) {
|
|
1249
|
-
return /* @__PURE__ */ jsxs4("div", { style: styles.palette, children: [
|
|
1250
|
-
/* @__PURE__ */ jsxs4("div", { style: styles.activeSectionHint, children: [
|
|
1251
|
-
chrome.addingTo,
|
|
1252
|
-
" ",
|
|
1253
|
-
/* @__PURE__ */ jsx4("strong", { children: activeSectionLabel })
|
|
1254
|
-
] }),
|
|
1255
|
-
/* @__PURE__ */ jsx4("div", { style: styles.panelHeading, children: chrome.contentBlocks }),
|
|
1256
|
-
/* @__PURE__ */ jsx4("div", { style: styles.paletteList, children: CONTENT_TYPES.map((f) => {
|
|
1257
|
-
const Icon = f.icon;
|
|
1258
|
-
return /* @__PURE__ */ jsxs4("button", { style: styles.paletteItem, onClick: () => onAddField(f.type), children: [
|
|
1259
|
-
/* @__PURE__ */ jsx4(Icon, { size: 16, color: "var(--fb-primary)" }),
|
|
1260
|
-
/* @__PURE__ */ jsx4("span", { children: chrome[FIELD_TYPE_CHROME_KEY[f.type]] }),
|
|
1261
|
-
/* @__PURE__ */ jsx4(Plus, { size: 13, color: "#A6A8B3", style: { marginLeft: "auto" } })
|
|
1262
|
-
] }, f.type);
|
|
1263
|
-
}) }),
|
|
1264
|
-
/* @__PURE__ */ jsx4("div", { style: { ...styles.panelHeading, marginTop: 16 }, children: chrome.formFields }),
|
|
1265
|
-
/* @__PURE__ */ jsx4("div", { style: styles.paletteList, children: FORM_TYPES.map((f) => {
|
|
1266
|
-
const Icon = f.icon;
|
|
1267
|
-
return /* @__PURE__ */ jsxs4("button", { style: styles.paletteItem, onClick: () => onAddField(f.type), children: [
|
|
1268
|
-
/* @__PURE__ */ jsx4(Icon, { size: 16, color: "var(--fb-primary)" }),
|
|
1269
|
-
/* @__PURE__ */ jsx4("span", { children: chrome[FIELD_TYPE_CHROME_KEY[f.type]] }),
|
|
1270
|
-
/* @__PURE__ */ jsx4(Plus, { size: 13, color: "#A6A8B3", style: { marginLeft: "auto" } })
|
|
1271
|
-
] }, f.type);
|
|
1272
|
-
}) })
|
|
1273
|
-
] });
|
|
1274
|
-
}
|
|
1275
|
-
|
|
1276
1393
|
// src/components/Canvas.tsx
|
|
1277
1394
|
import { Layers } from "lucide-react";
|
|
1278
1395
|
|
|
1279
1396
|
// src/components/SectionCard.tsx
|
|
1280
|
-
import { ChevronDown as ChevronDown3, ChevronRight, Copy as Copy2, ArrowUp as ArrowUp2, ArrowDown as ArrowDown2, Trash2 as Trash22
|
|
1281
|
-
|
|
1282
|
-
// src/constants/submitStyle.ts
|
|
1283
|
-
var SUBMIT_SIZE_OPTIONS = [
|
|
1284
|
-
{ value: "sm", label: "S" },
|
|
1285
|
-
{ value: "md", label: "M" },
|
|
1286
|
-
{ value: "lg", label: "L" }
|
|
1287
|
-
];
|
|
1288
|
-
var SUBMIT_SIZE_STYLES = {
|
|
1289
|
-
sm: { padding: "7px 12px", fontSize: 12.5 },
|
|
1290
|
-
md: { padding: "10px 16px", fontSize: 13.5 },
|
|
1291
|
-
lg: { padding: "13px 22px", fontSize: 15 }
|
|
1292
|
-
};
|
|
1293
|
-
function resolveSubmitStyle(style) {
|
|
1294
|
-
const sizeStyle = SUBMIT_SIZE_STYLES[style?.size || "md"] || SUBMIT_SIZE_STYLES.md;
|
|
1295
|
-
return { ...sizeStyle, background: style?.color || "var(--fb-primary)" };
|
|
1296
|
-
}
|
|
1397
|
+
import { ChevronDown as ChevronDown3, ChevronRight, Copy as Copy2, ArrowUp as ArrowUp2, ArrowDown as ArrowDown2, Trash2 as Trash22 } from "lucide-react";
|
|
1297
1398
|
|
|
1298
1399
|
// src/components/FieldTicket.tsx
|
|
1299
1400
|
import { ArrowUp, ArrowDown, Copy, Trash2, GripVertical } from "lucide-react";
|
|
@@ -1379,7 +1480,7 @@ var ICON_LIBRARY = {
|
|
|
1379
1480
|
|
|
1380
1481
|
// src/components/fields/ImageBlock.tsx
|
|
1381
1482
|
import { Image as ImageIcon2 } from "lucide-react";
|
|
1382
|
-
import { jsx as
|
|
1483
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1383
1484
|
function buildImageStyle(field) {
|
|
1384
1485
|
const aspectRatio = field.shape === "banner" ? "16 / 5" : "1 / 1";
|
|
1385
1486
|
return {
|
|
@@ -1393,35 +1494,58 @@ function buildImageStyle(field) {
|
|
|
1393
1494
|
}
|
|
1394
1495
|
function ImageBlock({ field, lang }) {
|
|
1395
1496
|
const shapeStyle = buildImageStyle(field);
|
|
1396
|
-
const img = field.src ? /* @__PURE__ */
|
|
1397
|
-
return field.link ? /* @__PURE__ */
|
|
1497
|
+
const img = field.src ? /* @__PURE__ */ jsx6("img", { src: field.src, alt: t(field.alt, lang || "en"), style: shapeStyle }) : /* @__PURE__ */ jsx6("div", { style: { ...shapeStyle, ...styles.imagePlaceholder }, children: /* @__PURE__ */ jsx6(ImageIcon2, { size: 20, color: "var(--fb-muted)" }) });
|
|
1498
|
+
return field.link ? /* @__PURE__ */ jsx6("a", { href: field.link, target: "_blank", rel: "noreferrer", style: { display: "block" }, children: img }) : img;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// src/constants/submitStyle.ts
|
|
1502
|
+
var SUBMIT_SIZE_OPTIONS = [
|
|
1503
|
+
{ value: "sm", label: "S" },
|
|
1504
|
+
{ value: "md", label: "M" },
|
|
1505
|
+
{ value: "lg", label: "L" }
|
|
1506
|
+
];
|
|
1507
|
+
var SUBMIT_SIZE_STYLES = {
|
|
1508
|
+
sm: { padding: "7px 12px", fontSize: 12.5 },
|
|
1509
|
+
md: { padding: "10px 16px", fontSize: 13.5 },
|
|
1510
|
+
lg: { padding: "13px 22px", fontSize: 15 }
|
|
1511
|
+
};
|
|
1512
|
+
function resolveSubmitStyle(style) {
|
|
1513
|
+
const sizeStyle = SUBMIT_SIZE_STYLES[style?.size || "md"] || SUBMIT_SIZE_STYLES.md;
|
|
1514
|
+
return { ...sizeStyle, background: style?.color || "var(--fb-primary)" };
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
// src/components/fields/ButtonBlock.tsx
|
|
1518
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1519
|
+
function ButtonBlock({ field, lang, onAction }) {
|
|
1520
|
+
return /* @__PURE__ */ jsx7("button", { type: "button", style: { ...styles.submitBtn, ...resolveSubmitStyle(field.buttonStyle) }, onClick: () => onAction?.(field), children: t(field.label, lang) || "..." });
|
|
1398
1521
|
}
|
|
1399
1522
|
|
|
1400
1523
|
// src/components/fields/FieldBlock.tsx
|
|
1401
|
-
import { jsx as
|
|
1402
|
-
function FieldBlock({ field, lang, onFieldChange, strings, chrome, error, isBuild }) {
|
|
1403
|
-
if (field.type === "image") return /* @__PURE__ */
|
|
1524
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1525
|
+
function FieldBlock({ field, lang, onFieldChange, strings, chrome, error, isBuild, onButtonAction }) {
|
|
1526
|
+
if (field.type === "image") return /* @__PURE__ */ jsx8(ImageBlock, { field, lang });
|
|
1527
|
+
if (field.type === "button") return /* @__PURE__ */ jsx8(ButtonBlock, { field, lang, onAction: onButtonAction });
|
|
1404
1528
|
if (field.type === "paragraph") {
|
|
1405
1529
|
const fontPx = FONT_SIZE_OPTIONS.find((f) => f.value === field.fontSize)?.px || 14;
|
|
1406
1530
|
const Tag = TAG_TO_ELEMENT[field.tag] || "p";
|
|
1407
|
-
return /* @__PURE__ */
|
|
1531
|
+
return /* @__PURE__ */ jsx8(Tag, { style: { margin: 0, whiteSpace: "pre-wrap", fontSize: fontPx, fontWeight: field.fontWeight === "bold" ? 700 : 400, fontStyle: field.fontStyle === "italic" ? "italic" : "normal", textAlign: field.textAlign || "left", color: field.color || "var(--fb-ink)", lineHeight: 1.6 }, children: t(field.content, lang) || "..." });
|
|
1408
1532
|
}
|
|
1409
1533
|
const meta = getMeta(field.type);
|
|
1410
1534
|
const IconComp = field.showIcon && field.displayIcon ? ICON_LIBRARY[field.displayIcon] : null;
|
|
1411
1535
|
const isInline = field.labelPosition === "inline" && !meta.boolean;
|
|
1412
1536
|
const labelText = t(field.label, lang);
|
|
1413
1537
|
const showLabel = !meta.boolean && !field.hideLabel;
|
|
1414
|
-
return /* @__PURE__ */
|
|
1415
|
-
/* @__PURE__ */
|
|
1416
|
-
showLabel && /* @__PURE__ */
|
|
1417
|
-
IconComp && /* @__PURE__ */
|
|
1418
|
-
labelText || (isBuild ? /* @__PURE__ */
|
|
1419
|
-
field.required && /* @__PURE__ */
|
|
1538
|
+
return /* @__PURE__ */ jsxs6("div", { children: [
|
|
1539
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", flexDirection: isInline ? "row" : "column", alignItems: isInline ? "center" : "stretch", gap: isInline ? 10 : 6 }, children: [
|
|
1540
|
+
showLabel && /* @__PURE__ */ jsxs6("label", { style: { ...styles.previewLabel, marginBottom: isInline ? 0 : 6, flexShrink: 0, width: isInline ? 120 : "auto", display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
1541
|
+
IconComp && /* @__PURE__ */ jsx8(IconComp, { size: 14, color: "#6B6E79" }),
|
|
1542
|
+
labelText || (isBuild ? /* @__PURE__ */ jsx8("span", { style: { fontStyle: "italic", color: "var(--fb-muted)" }, children: chrome?.untitledField || "Untitled field" }) : ""),
|
|
1543
|
+
field.required && /* @__PURE__ */ jsx8("span", { style: { color: "var(--fb-danger)" }, children: " *" })
|
|
1420
1544
|
] }),
|
|
1421
|
-
/* @__PURE__ */
|
|
1545
|
+
/* @__PURE__ */ jsx8("div", { style: { flex: 1, minWidth: 0 }, children: renderInteractive(field, lang, onFieldChange, IconComp, !!error, strings) })
|
|
1422
1546
|
] }),
|
|
1423
|
-
error && /* @__PURE__ */
|
|
1424
|
-
/* @__PURE__ */
|
|
1547
|
+
error && /* @__PURE__ */ jsxs6("div", { style: styles.fieldError, children: [
|
|
1548
|
+
/* @__PURE__ */ jsx8(CircleAlert, { size: 12 }),
|
|
1425
1549
|
" ",
|
|
1426
1550
|
error
|
|
1427
1551
|
] })
|
|
@@ -1435,40 +1559,40 @@ function renderInteractive(field, lang, onFieldChange, IconComp, hasError, strin
|
|
|
1435
1559
|
if (field.type === "input") {
|
|
1436
1560
|
switch (field.inputType) {
|
|
1437
1561
|
case "number":
|
|
1438
|
-
return /* @__PURE__ */
|
|
1562
|
+
return /* @__PURE__ */ jsx8("input", { type: "number", ...common, min: field.min ?? void 0, max: field.max ?? void 0 });
|
|
1439
1563
|
case "email":
|
|
1440
|
-
return /* @__PURE__ */
|
|
1564
|
+
return /* @__PURE__ */ jsx8("input", { type: "email", ...common });
|
|
1441
1565
|
case "password":
|
|
1442
|
-
return /* @__PURE__ */
|
|
1566
|
+
return /* @__PURE__ */ jsx8("input", { type: "password", ...common, maxLength: field.maxLength || void 0 });
|
|
1443
1567
|
case "phone":
|
|
1444
|
-
return /* @__PURE__ */
|
|
1568
|
+
return /* @__PURE__ */ jsx8("input", { type: "tel", ...common });
|
|
1445
1569
|
case "date":
|
|
1446
|
-
return /* @__PURE__ */
|
|
1570
|
+
return /* @__PURE__ */ jsx8("input", { type: "date", ...common });
|
|
1447
1571
|
case "time":
|
|
1448
|
-
return /* @__PURE__ */
|
|
1572
|
+
return /* @__PURE__ */ jsx8("input", { type: "time", ...common });
|
|
1449
1573
|
default:
|
|
1450
|
-
return /* @__PURE__ */
|
|
1574
|
+
return /* @__PURE__ */ jsx8("input", { type: "text", ...common, maxLength: field.maxLength || void 0 });
|
|
1451
1575
|
}
|
|
1452
1576
|
}
|
|
1453
1577
|
switch (field.type) {
|
|
1454
1578
|
case "textarea":
|
|
1455
|
-
return /* @__PURE__ */
|
|
1579
|
+
return /* @__PURE__ */ jsx8("textarea", { ...common, rows: 3, maxLength: field.maxLength || void 0 });
|
|
1456
1580
|
case "select":
|
|
1457
|
-
return /* @__PURE__ */
|
|
1458
|
-
/* @__PURE__ */
|
|
1459
|
-
(field.options || []).map((o) => /* @__PURE__ */
|
|
1581
|
+
return /* @__PURE__ */ jsxs6("select", { style: inputStyle, value: value || "", onChange: (e) => set(e.target.value), children: [
|
|
1582
|
+
/* @__PURE__ */ jsx8("option", { value: "", children: strings.selectPlaceholder }),
|
|
1583
|
+
(field.options || []).map((o) => /* @__PURE__ */ jsx8("option", { value: o.value, children: t(o.label, lang) }, o.value))
|
|
1460
1584
|
] });
|
|
1461
1585
|
case "radio":
|
|
1462
|
-
return /* @__PURE__ */
|
|
1463
|
-
/* @__PURE__ */
|
|
1586
|
+
return /* @__PURE__ */ jsx8("div", { style: { display: "flex", gap: 16, flexWrap: "wrap", marginTop: 4 }, children: (field.options || []).map((o) => /* @__PURE__ */ jsxs6("label", { style: styles.previewRadio, children: [
|
|
1587
|
+
/* @__PURE__ */ jsx8("input", { type: "radio", name: field.id, value: o.value, checked: value === o.value, onChange: (e) => set(e.target.value) }),
|
|
1464
1588
|
t(o.label, lang)
|
|
1465
1589
|
] }, o.value)) });
|
|
1466
1590
|
case "checkboxGroup": {
|
|
1467
1591
|
const vals = Array.isArray(value) ? value : [];
|
|
1468
|
-
return /* @__PURE__ */
|
|
1592
|
+
return /* @__PURE__ */ jsx8("div", { style: { display: "flex", gap: 16, flexWrap: "wrap", marginTop: 4 }, children: (field.options || []).map((o) => {
|
|
1469
1593
|
const checked = vals.includes(o.value);
|
|
1470
|
-
return /* @__PURE__ */
|
|
1471
|
-
/* @__PURE__ */
|
|
1594
|
+
return /* @__PURE__ */ jsxs6("label", { style: styles.previewRadio, children: [
|
|
1595
|
+
/* @__PURE__ */ jsx8("input", { type: "checkbox", checked, onChange: (e) => {
|
|
1472
1596
|
const next = e.target.checked ? [...vals, o.value] : vals.filter((v) => v !== o.value);
|
|
1473
1597
|
set(next);
|
|
1474
1598
|
}, style: { accentColor: "var(--fb-primary)" } }),
|
|
@@ -1477,25 +1601,25 @@ function renderInteractive(field, lang, onFieldChange, IconComp, hasError, strin
|
|
|
1477
1601
|
}) });
|
|
1478
1602
|
}
|
|
1479
1603
|
case "checkbox":
|
|
1480
|
-
return /* @__PURE__ */
|
|
1481
|
-
/* @__PURE__ */
|
|
1482
|
-
IconComp && /* @__PURE__ */
|
|
1604
|
+
return /* @__PURE__ */ jsxs6("label", { style: styles.previewRadio, children: [
|
|
1605
|
+
/* @__PURE__ */ jsx8("input", { type: "checkbox", checked: !!value, onChange: (e) => set(e.target.checked), style: { accentColor: "var(--fb-primary)" } }),
|
|
1606
|
+
IconComp && /* @__PURE__ */ jsx8(IconComp, { size: 14, color: "#6B6E79" }),
|
|
1483
1607
|
t(field.label, lang),
|
|
1484
|
-
field.required && /* @__PURE__ */
|
|
1608
|
+
field.required && /* @__PURE__ */ jsx8("span", { style: { color: "var(--fb-danger)" }, children: " *" })
|
|
1485
1609
|
] });
|
|
1486
1610
|
case "toggle":
|
|
1487
|
-
return /* @__PURE__ */
|
|
1488
|
-
/* @__PURE__ */
|
|
1489
|
-
IconComp && /* @__PURE__ */
|
|
1611
|
+
return /* @__PURE__ */ jsxs6("label", { style: styles.previewRadio, children: [
|
|
1612
|
+
/* @__PURE__ */ jsx8("input", { type: "checkbox", checked: !!value, onChange: (e) => set(e.target.checked), style: { accentColor: "var(--fb-primary)" } }),
|
|
1613
|
+
IconComp && /* @__PURE__ */ jsx8(IconComp, { size: 14, color: "#6B6E79" }),
|
|
1490
1614
|
t(field.label, lang)
|
|
1491
1615
|
] });
|
|
1492
1616
|
default:
|
|
1493
|
-
return /* @__PURE__ */
|
|
1617
|
+
return /* @__PURE__ */ jsx8("input", { type: "text", ...common });
|
|
1494
1618
|
}
|
|
1495
1619
|
}
|
|
1496
1620
|
|
|
1497
1621
|
// src/components/FieldTicket.tsx
|
|
1498
|
-
import { jsx as
|
|
1622
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1499
1623
|
function FieldTicket({
|
|
1500
1624
|
field,
|
|
1501
1625
|
idx,
|
|
@@ -1515,7 +1639,7 @@ function FieldTicket({
|
|
|
1515
1639
|
const meta = getMeta(field.type);
|
|
1516
1640
|
const Icon = meta.icon;
|
|
1517
1641
|
const widthPct = WIDTH_PERCENT[field.width || "1/1"];
|
|
1518
|
-
return /* @__PURE__ */
|
|
1642
|
+
return /* @__PURE__ */ jsxs7(
|
|
1519
1643
|
"div",
|
|
1520
1644
|
{
|
|
1521
1645
|
...dropZoneHandlers,
|
|
@@ -1529,35 +1653,35 @@ function FieldTicket({
|
|
|
1529
1653
|
...isDragOver ? styles.ticketDragOver : {}
|
|
1530
1654
|
},
|
|
1531
1655
|
children: [
|
|
1532
|
-
/* @__PURE__ */
|
|
1533
|
-
/* @__PURE__ */
|
|
1534
|
-
/* @__PURE__ */
|
|
1535
|
-
/* @__PURE__ */
|
|
1536
|
-
/* @__PURE__ */
|
|
1537
|
-
/* @__PURE__ */
|
|
1538
|
-
/* @__PURE__ */
|
|
1656
|
+
/* @__PURE__ */ jsx9("div", { style: styles.ticketIndex, children: String(idx + 1).padStart(2, "0") }),
|
|
1657
|
+
/* @__PURE__ */ jsx9("div", { style: styles.ticketPerforation }),
|
|
1658
|
+
/* @__PURE__ */ jsxs7("div", { style: styles.ticketBody, children: [
|
|
1659
|
+
/* @__PURE__ */ jsxs7("div", { style: styles.ticketTop, children: [
|
|
1660
|
+
/* @__PURE__ */ jsx9("span", { ...dragHandleProps, style: { cursor: "grab", display: "flex" }, children: /* @__PURE__ */ jsx9(GripVertical, { size: 14, color: "#C4C6D0" }) }),
|
|
1661
|
+
/* @__PURE__ */ jsx9(Icon, { size: 13, color: "var(--fb-primary)" }),
|
|
1662
|
+
/* @__PURE__ */ jsxs7("span", { style: styles.typeBadge, children: [
|
|
1539
1663
|
chrome[FIELD_TYPE_CHROME_KEY[field.type]] || field.type,
|
|
1540
1664
|
field.type === "input" && field.inputType && field.inputType !== "text" ? ` \xB7 ${chrome[INPUT_SUBTYPE_CHROME_KEY[field.inputType]]}` : ""
|
|
1541
1665
|
] }),
|
|
1542
|
-
field.required && /* @__PURE__ */
|
|
1666
|
+
field.required && /* @__PURE__ */ jsx9("span", { style: styles.requiredBadge, children: chrome.required })
|
|
1543
1667
|
] }),
|
|
1544
|
-
field.width && field.width !== "1/1" || field.labelPosition === "inline" || field.verticalAlign !== "top" || field.hideLabel ? /* @__PURE__ */
|
|
1545
|
-
field.width && field.width !== "1/1" && /* @__PURE__ */
|
|
1668
|
+
field.width && field.width !== "1/1" || field.labelPosition === "inline" || field.verticalAlign !== "top" || field.hideLabel ? /* @__PURE__ */ jsxs7("div", { style: styles.chipRow, children: [
|
|
1669
|
+
field.width && field.width !== "1/1" && /* @__PURE__ */ jsxs7("span", { style: styles.miniBadge, children: [
|
|
1546
1670
|
chrome.width,
|
|
1547
1671
|
" ",
|
|
1548
1672
|
field.width
|
|
1549
1673
|
] }),
|
|
1550
|
-
field.labelPosition === "inline" && /* @__PURE__ */
|
|
1551
|
-
field.verticalAlign !== "top" && /* @__PURE__ */
|
|
1552
|
-
field.hideLabel && /* @__PURE__ */
|
|
1674
|
+
field.labelPosition === "inline" && /* @__PURE__ */ jsx9("span", { style: styles.miniBadge, children: chrome.inline }),
|
|
1675
|
+
field.verticalAlign !== "top" && /* @__PURE__ */ jsx9("span", { style: styles.miniBadge, children: chrome[field.verticalAlign] }),
|
|
1676
|
+
field.hideLabel && /* @__PURE__ */ jsx9("span", { style: styles.miniBadge, children: chrome.hideLabel })
|
|
1553
1677
|
] }) : null,
|
|
1554
|
-
/* @__PURE__ */
|
|
1678
|
+
/* @__PURE__ */ jsx9("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx9(FieldBlock, { field, lang: language, onFieldChange, strings, chrome, isBuild: true }) })
|
|
1555
1679
|
] }),
|
|
1556
|
-
/* @__PURE__ */
|
|
1557
|
-
/* @__PURE__ */
|
|
1558
|
-
/* @__PURE__ */
|
|
1559
|
-
/* @__PURE__ */
|
|
1560
|
-
/* @__PURE__ */
|
|
1680
|
+
/* @__PURE__ */ jsxs7("div", { style: styles.ticketActions, onClick: (e) => e.stopPropagation(), children: [
|
|
1681
|
+
/* @__PURE__ */ jsx9("button", { style: styles.iconBtn, title: chrome.moveUp, onClick: () => onMoveField(field.id, -1), children: /* @__PURE__ */ jsx9(ArrowUp, { size: 13 }) }),
|
|
1682
|
+
/* @__PURE__ */ jsx9("button", { style: styles.iconBtn, title: chrome.moveDown, onClick: () => onMoveField(field.id, 1), children: /* @__PURE__ */ jsx9(ArrowDown, { size: 13 }) }),
|
|
1683
|
+
/* @__PURE__ */ jsx9("button", { style: styles.iconBtn, title: chrome.duplicate, onClick: () => onDuplicateField(field.id), children: /* @__PURE__ */ jsx9(Copy, { size: 13 }) }),
|
|
1684
|
+
/* @__PURE__ */ jsx9("button", { style: { ...styles.iconBtn, ...styles.iconBtnDanger }, title: chrome.delete, onClick: () => onDeleteField(field.id), children: /* @__PURE__ */ jsx9(Trash2, { size: 13 }) })
|
|
1561
1685
|
] })
|
|
1562
1686
|
]
|
|
1563
1687
|
}
|
|
@@ -1565,14 +1689,12 @@ function FieldTicket({
|
|
|
1565
1689
|
}
|
|
1566
1690
|
|
|
1567
1691
|
// src/components/SectionCard.tsx
|
|
1568
|
-
import { jsx as
|
|
1692
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1569
1693
|
function SectionCard({
|
|
1570
1694
|
section,
|
|
1571
1695
|
sIdx,
|
|
1572
1696
|
sectionsLength,
|
|
1573
1697
|
isActive,
|
|
1574
|
-
submitMode,
|
|
1575
|
-
submitStyle,
|
|
1576
1698
|
selectedId,
|
|
1577
1699
|
dragOverKey,
|
|
1578
1700
|
chrome,
|
|
@@ -1585,8 +1707,6 @@ function SectionCard({
|
|
|
1585
1707
|
onDuplicateSection,
|
|
1586
1708
|
onMoveSection,
|
|
1587
1709
|
onDeleteSection,
|
|
1588
|
-
onUpdateSectionSubmitStyle,
|
|
1589
|
-
onClearSectionSubmitStyle,
|
|
1590
1710
|
onSelectField,
|
|
1591
1711
|
onFieldChange,
|
|
1592
1712
|
onMoveField,
|
|
@@ -1595,19 +1715,19 @@ function SectionCard({
|
|
|
1595
1715
|
getDropZoneHandlers,
|
|
1596
1716
|
getDragHandleProps
|
|
1597
1717
|
}) {
|
|
1598
|
-
return /* @__PURE__ */
|
|
1718
|
+
return /* @__PURE__ */ jsxs8(
|
|
1599
1719
|
"div",
|
|
1600
1720
|
{
|
|
1601
1721
|
style: { ...styles.sectionBlock, background: section.background || "transparent", border: isActive ? "1px solid var(--fb-primary)" : "1px dashed var(--fb-border)" },
|
|
1602
1722
|
onClick: onActivate,
|
|
1603
1723
|
children: [
|
|
1604
|
-
/* @__PURE__ */
|
|
1605
|
-
/* @__PURE__ */
|
|
1724
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.sectionHeader, children: [
|
|
1725
|
+
/* @__PURE__ */ jsx10("button", { style: styles.chevronBtn, onClick: (e) => {
|
|
1606
1726
|
e.stopPropagation();
|
|
1607
1727
|
onToggleCollapse();
|
|
1608
|
-
}, children: section.collapsed ? /* @__PURE__ */
|
|
1609
|
-
/* @__PURE__ */
|
|
1610
|
-
/* @__PURE__ */
|
|
1728
|
+
}, children: section.collapsed ? /* @__PURE__ */ jsx10(ChevronRight, { size: 15 }) : /* @__PURE__ */ jsx10(ChevronDown3, { size: 15 }) }),
|
|
1729
|
+
/* @__PURE__ */ jsx10("span", { style: { ...styles.colorDot, background: section.background || "var(--fb-canvas)" } }),
|
|
1730
|
+
/* @__PURE__ */ jsx10(
|
|
1611
1731
|
"input",
|
|
1612
1732
|
{
|
|
1613
1733
|
style: styles.sectionTitleInput,
|
|
@@ -1617,29 +1737,19 @@ function SectionCard({
|
|
|
1617
1737
|
onClick: (e) => e.stopPropagation()
|
|
1618
1738
|
}
|
|
1619
1739
|
),
|
|
1620
|
-
section.collapsed && /* @__PURE__ */
|
|
1621
|
-
/* @__PURE__ */
|
|
1622
|
-
!section.collapsed && /* @__PURE__ */
|
|
1623
|
-
SECTION_BG_SWATCHES.map((c) => /* @__PURE__ */
|
|
1624
|
-
/* @__PURE__ */
|
|
1740
|
+
section.collapsed && /* @__PURE__ */ jsx10("span", { style: styles.miniBadge, children: chrome.fieldsCount(section.fields.length) }),
|
|
1741
|
+
/* @__PURE__ */ jsxs8("div", { style: styles.sectionHeaderActions, onClick: (e) => e.stopPropagation(), children: [
|
|
1742
|
+
!section.collapsed && /* @__PURE__ */ jsxs8("div", { style: styles.swatchRow, children: [
|
|
1743
|
+
SECTION_BG_SWATCHES.map((c) => /* @__PURE__ */ jsx10("button", { type: "button", title: c || chrome.none, style: { ...styles.swatchBtn, background: c || "var(--fb-canvas)", ...section.background === c ? styles.swatchBtnActive : {} }, onClick: () => onUpdateBackground(c) }, c || "none")),
|
|
1744
|
+
/* @__PURE__ */ jsx10("input", { type: "color", title: chrome.customColor, value: /^#/.test(section.background) ? section.background : "#ffffff", onChange: (e) => onUpdateBackground(e.target.value), style: styles.colorPickerInput })
|
|
1625
1745
|
] }),
|
|
1626
|
-
/* @__PURE__ */
|
|
1627
|
-
/* @__PURE__ */
|
|
1628
|
-
/* @__PURE__ */
|
|
1629
|
-
/* @__PURE__ */
|
|
1746
|
+
/* @__PURE__ */ jsx10("button", { style: styles.iconBtn, title: chrome.duplicate, onClick: onDuplicateSection, children: /* @__PURE__ */ jsx10(Copy2, { size: 13 }) }),
|
|
1747
|
+
/* @__PURE__ */ jsx10("button", { style: styles.iconBtn, title: chrome.moveUp, disabled: sIdx === 0, onClick: () => onMoveSection(-1), children: /* @__PURE__ */ jsx10(ArrowUp2, { size: 13 }) }),
|
|
1748
|
+
/* @__PURE__ */ jsx10("button", { style: styles.iconBtn, title: chrome.moveDown, disabled: sIdx === sectionsLength - 1, onClick: () => onMoveSection(1), children: /* @__PURE__ */ jsx10(ArrowDown2, { size: 13 }) }),
|
|
1749
|
+
/* @__PURE__ */ jsx10("button", { style: { ...styles.iconBtn, ...styles.iconBtnDanger }, title: chrome.deleteSection, disabled: sectionsLength <= 1, onClick: onDeleteSection, children: /* @__PURE__ */ jsx10(Trash22, { size: 13 }) })
|
|
1630
1750
|
] })
|
|
1631
1751
|
] }),
|
|
1632
|
-
!section.collapsed &&
|
|
1633
|
-
/* @__PURE__ */ jsx8("span", { style: styles.miniLabel, children: chrome.submitStyle }),
|
|
1634
|
-
/* @__PURE__ */ jsx8("div", { style: styles.swatchRow, children: BUTTON_COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx8("button", { type: "button", title: c || chrome.none, style: { ...styles.swatchBtn, background: c || "var(--fb-primary)", ...(section.submitStyle?.color || "") === c ? styles.swatchBtnActive : {} }, onClick: () => onUpdateSectionSubmitStyle({ color: c }) }, c || "inherit")) }),
|
|
1635
|
-
/* @__PURE__ */ jsx8(Segmented, { options: SUBMIT_SIZE_OPTIONS, value: section.submitStyle?.size || submitStyle.size, onChange: (v) => onUpdateSectionSubmitStyle({ size: v }) }),
|
|
1636
|
-
section.submitStyle && /* @__PURE__ */ jsxs7("button", { type: "button", style: styles.resetLinkBtn, onClick: onClearSectionSubmitStyle, children: [
|
|
1637
|
-
/* @__PURE__ */ jsx8(RotateCcw2, { size: 11 }),
|
|
1638
|
-
" ",
|
|
1639
|
-
chrome.reset
|
|
1640
|
-
] })
|
|
1641
|
-
] }),
|
|
1642
|
-
!section.collapsed && (section.fields.length === 0 ? /* @__PURE__ */ jsx8("div", { style: styles.sectionEmpty, children: chrome.noFieldsInSection }) : /* @__PURE__ */ jsx8("div", { style: styles.fieldList, children: section.fields.map((field, idx) => /* @__PURE__ */ jsx8(
|
|
1752
|
+
!section.collapsed && (section.fields.length === 0 ? /* @__PURE__ */ jsx10("div", { style: styles.sectionEmpty, children: chrome.noFieldsInSection }) : /* @__PURE__ */ jsx10("div", { style: styles.fieldList, children: section.fields.map((field, idx) => /* @__PURE__ */ jsx10(
|
|
1643
1753
|
FieldTicket,
|
|
1644
1754
|
{
|
|
1645
1755
|
field,
|
|
@@ -1666,12 +1776,10 @@ function SectionCard({
|
|
|
1666
1776
|
}
|
|
1667
1777
|
|
|
1668
1778
|
// src/components/Canvas.tsx
|
|
1669
|
-
import { jsx as
|
|
1779
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1670
1780
|
function Canvas({
|
|
1671
1781
|
sections,
|
|
1672
1782
|
activeSectionId,
|
|
1673
|
-
submitMode,
|
|
1674
|
-
submitStyle,
|
|
1675
1783
|
selectedId,
|
|
1676
1784
|
dragOverKey,
|
|
1677
1785
|
chrome,
|
|
@@ -1684,8 +1792,6 @@ function Canvas({
|
|
|
1684
1792
|
onDuplicateSection,
|
|
1685
1793
|
onMoveSection,
|
|
1686
1794
|
onDeleteSection,
|
|
1687
|
-
onUpdateSectionSubmitStyle,
|
|
1688
|
-
onClearSectionSubmitStyle,
|
|
1689
1795
|
onAddSection,
|
|
1690
1796
|
onSelectField,
|
|
1691
1797
|
onFieldChange,
|
|
@@ -1695,16 +1801,14 @@ function Canvas({
|
|
|
1695
1801
|
getDropZoneHandlers,
|
|
1696
1802
|
getDragHandleProps
|
|
1697
1803
|
}) {
|
|
1698
|
-
return /* @__PURE__ */
|
|
1699
|
-
sections.map((section, sIdx) => /* @__PURE__ */
|
|
1804
|
+
return /* @__PURE__ */ jsxs9("div", { style: styles.canvas, children: [
|
|
1805
|
+
sections.map((section, sIdx) => /* @__PURE__ */ jsx11(
|
|
1700
1806
|
SectionCard,
|
|
1701
1807
|
{
|
|
1702
1808
|
section,
|
|
1703
1809
|
sIdx,
|
|
1704
1810
|
sectionsLength: sections.length,
|
|
1705
1811
|
isActive: activeSectionId === section.id,
|
|
1706
|
-
submitMode,
|
|
1707
|
-
submitStyle,
|
|
1708
1812
|
selectedId,
|
|
1709
1813
|
dragOverKey,
|
|
1710
1814
|
chrome,
|
|
@@ -1717,8 +1821,6 @@ function Canvas({
|
|
|
1717
1821
|
onDuplicateSection: () => onDuplicateSection(section.id),
|
|
1718
1822
|
onMoveSection: (dir) => onMoveSection(section.id, dir),
|
|
1719
1823
|
onDeleteSection: () => onDeleteSection(section.id),
|
|
1720
|
-
onUpdateSectionSubmitStyle: (patch) => onUpdateSectionSubmitStyle(section.id, patch),
|
|
1721
|
-
onClearSectionSubmitStyle: () => onClearSectionSubmitStyle(section.id),
|
|
1722
1824
|
onSelectField: (fieldId) => onSelectField(section.id, fieldId),
|
|
1723
1825
|
onFieldChange,
|
|
1724
1826
|
onMoveField,
|
|
@@ -1729,8 +1831,8 @@ function Canvas({
|
|
|
1729
1831
|
},
|
|
1730
1832
|
section.id
|
|
1731
1833
|
)),
|
|
1732
|
-
/* @__PURE__ */
|
|
1733
|
-
/* @__PURE__ */
|
|
1834
|
+
/* @__PURE__ */ jsxs9("button", { style: styles.addSectionBtn, onClick: onAddSection, children: [
|
|
1835
|
+
/* @__PURE__ */ jsx11(Layers, { size: 14 }),
|
|
1734
1836
|
" ",
|
|
1735
1837
|
chrome.addSection
|
|
1736
1838
|
] })
|
|
@@ -1741,27 +1843,27 @@ function Canvas({
|
|
|
1741
1843
|
import { Bold, Italic, X, Plus as Plus2, Trash2 as Trash23 } from "lucide-react";
|
|
1742
1844
|
|
|
1743
1845
|
// src/components/fields/DefaultValueEditor.tsx
|
|
1744
|
-
import { Fragment as
|
|
1846
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1745
1847
|
function DefaultValueEditor({ field, meta, lang, chrome, onChange }) {
|
|
1746
1848
|
if (meta.isContent) return null;
|
|
1747
1849
|
const f = field;
|
|
1748
1850
|
if (meta.boolean) {
|
|
1749
|
-
return /* @__PURE__ */
|
|
1750
|
-
/* @__PURE__ */
|
|
1751
|
-
/* @__PURE__ */
|
|
1752
|
-
/* @__PURE__ */
|
|
1753
|
-
/* @__PURE__ */
|
|
1851
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1852
|
+
/* @__PURE__ */ jsx12("label", { style: styles.propLabel, children: chrome.defaultValue }),
|
|
1853
|
+
/* @__PURE__ */ jsxs10("button", { style: styles.toggleRow, onClick: () => onChange({ defaultValue: !f.defaultValue }), children: [
|
|
1854
|
+
/* @__PURE__ */ jsx12("span", { style: { ...styles.toggleTrack, background: f.defaultValue ? "var(--fb-primary)" : "var(--fb-border)" }, children: /* @__PURE__ */ jsx12("span", { style: { ...styles.toggleThumb, transform: f.defaultValue ? "translateX(16px)" : "translateX(0)" } }) }),
|
|
1855
|
+
/* @__PURE__ */ jsx12("span", { style: { fontSize: 13, color: "#4A4D57" }, children: f.defaultValue ? chrome.checked : chrome.unchecked })
|
|
1754
1856
|
] })
|
|
1755
1857
|
] });
|
|
1756
1858
|
}
|
|
1757
1859
|
if (meta.multiValue) {
|
|
1758
1860
|
const selectedVals = f.defaultValue || [];
|
|
1759
|
-
return /* @__PURE__ */
|
|
1760
|
-
/* @__PURE__ */
|
|
1761
|
-
/* @__PURE__ */
|
|
1861
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1862
|
+
/* @__PURE__ */ jsx12("label", { style: styles.propLabel, children: chrome.defaultChecked }),
|
|
1863
|
+
/* @__PURE__ */ jsx12("div", { style: styles.optionList, children: (f.options || []).map((o) => {
|
|
1762
1864
|
const checked = selectedVals.includes(o.value);
|
|
1763
|
-
return /* @__PURE__ */
|
|
1764
|
-
/* @__PURE__ */
|
|
1865
|
+
return /* @__PURE__ */ jsxs10("label", { style: { ...styles.previewRadio, cursor: "pointer" }, children: [
|
|
1866
|
+
/* @__PURE__ */ jsx12("input", { type: "checkbox", checked, onChange: (e) => {
|
|
1765
1867
|
const next = e.target.checked ? [...selectedVals, o.value] : selectedVals.filter((v) => v !== o.value);
|
|
1766
1868
|
onChange({ defaultValue: next });
|
|
1767
1869
|
}, style: { accentColor: "var(--fb-primary)" } }),
|
|
@@ -1771,27 +1873,27 @@ function DefaultValueEditor({ field, meta, lang, chrome, onChange }) {
|
|
|
1771
1873
|
] });
|
|
1772
1874
|
}
|
|
1773
1875
|
if (meta.options) {
|
|
1774
|
-
return /* @__PURE__ */
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1777
|
-
/* @__PURE__ */
|
|
1778
|
-
(f.options || []).map((o) => /* @__PURE__ */
|
|
1876
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1877
|
+
/* @__PURE__ */ jsx12("label", { style: styles.propLabel, children: chrome.defaultValue }),
|
|
1878
|
+
/* @__PURE__ */ jsxs10("select", { style: styles.propInput, value: f.defaultValue || "", onChange: (e) => onChange({ defaultValue: e.target.value }), children: [
|
|
1879
|
+
/* @__PURE__ */ jsx12("option", { value: "", children: chrome.none }),
|
|
1880
|
+
(f.options || []).map((o) => /* @__PURE__ */ jsx12("option", { value: o.value, children: t(o.label, lang) }, o.value))
|
|
1779
1881
|
] })
|
|
1780
1882
|
] });
|
|
1781
1883
|
}
|
|
1782
1884
|
const htmlType = field.type === "input" && field.inputType === "number" ? "number" : field.type === "input" && field.inputType === "date" ? "date" : field.type === "input" && field.inputType === "time" ? "time" : "text";
|
|
1783
|
-
return /* @__PURE__ */
|
|
1784
|
-
/* @__PURE__ */
|
|
1785
|
-
/* @__PURE__ */
|
|
1885
|
+
return /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
1886
|
+
/* @__PURE__ */ jsx12("label", { style: styles.propLabel, children: chrome.defaultValue }),
|
|
1887
|
+
/* @__PURE__ */ jsx12("input", { type: htmlType, style: styles.propInput, value: f.defaultValue || "", onChange: (e) => onChange({ defaultValue: e.target.value }) })
|
|
1786
1888
|
] });
|
|
1787
1889
|
}
|
|
1788
1890
|
|
|
1789
1891
|
// src/components/Inspector.tsx
|
|
1790
|
-
import { Fragment as
|
|
1892
|
+
import { Fragment as Fragment4, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1791
1893
|
function Inspector({ selected, language, chrome, onUpdateField, onDeleteField, onUpdateOption, onAddOption, onRemoveOption }) {
|
|
1792
|
-
return /* @__PURE__ */
|
|
1793
|
-
/* @__PURE__ */
|
|
1794
|
-
!selected ? /* @__PURE__ */
|
|
1894
|
+
return /* @__PURE__ */ jsxs11("div", { style: styles.inspector, children: [
|
|
1895
|
+
/* @__PURE__ */ jsx13("div", { style: styles.panelHeading, children: chrome.properties }),
|
|
1896
|
+
!selected ? /* @__PURE__ */ jsx13("div", { style: styles.inspectorEmpty, children: chrome.selectFieldHint }) : /* @__PURE__ */ jsx13(
|
|
1795
1897
|
InspectorBody,
|
|
1796
1898
|
{
|
|
1797
1899
|
selected,
|
|
@@ -1809,116 +1911,138 @@ function Inspector({ selected, language, chrome, onUpdateField, onDeleteField, o
|
|
|
1809
1911
|
function InspectorBody({ selected, language, chrome, onUpdateField, onDeleteField, onUpdateOption, onAddOption, onRemoveOption }) {
|
|
1810
1912
|
const meta = getMeta(selected.type);
|
|
1811
1913
|
const f = selected;
|
|
1812
|
-
return /* @__PURE__ */
|
|
1813
|
-
!meta.isContent && /* @__PURE__ */
|
|
1814
|
-
/* @__PURE__ */
|
|
1815
|
-
/* @__PURE__ */
|
|
1816
|
-
/* @__PURE__ */
|
|
1817
|
-
/* @__PURE__ */
|
|
1818
|
-
/* @__PURE__ */
|
|
1914
|
+
return /* @__PURE__ */ jsxs11("div", { style: styles.inspectorBody, children: [
|
|
1915
|
+
(!meta.isContent || selected.type === "button") && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1916
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: selected.type === "button" ? chrome.buttonText : chrome.label }),
|
|
1917
|
+
/* @__PURE__ */ jsx13("input", { style: styles.propInput, value: t(selected.label, language), onChange: (e) => onUpdateField({ label: withLang(selected.label, language, e.target.value) }) }),
|
|
1918
|
+
!meta.isContent && /* @__PURE__ */ jsxs11("label", { style: styles.toggleRow, children: [
|
|
1919
|
+
/* @__PURE__ */ jsx13("input", { type: "checkbox", checked: !!selected.hideLabel, onChange: (e) => onUpdateField({ hideLabel: e.target.checked }), style: { width: 15, height: 15, accentColor: "var(--fb-primary)" } }),
|
|
1920
|
+
/* @__PURE__ */ jsx13("span", { style: { fontSize: 13, color: "#4A4D57" }, children: chrome.hideLabel })
|
|
1819
1921
|
] })
|
|
1820
1922
|
] }),
|
|
1821
|
-
meta.hasSubtype && /* @__PURE__ */
|
|
1822
|
-
/* @__PURE__ */
|
|
1823
|
-
/* @__PURE__ */
|
|
1923
|
+
meta.hasSubtype && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1924
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.inputType }),
|
|
1925
|
+
/* @__PURE__ */ jsx13("select", { style: styles.propInput, value: f.inputType || "text", onChange: (e) => onUpdateField({ inputType: e.target.value }), children: INPUT_SUBTYPES.map((s) => /* @__PURE__ */ jsx13("option", { value: s, children: chrome[INPUT_SUBTYPE_CHROME_KEY[s]] }, s)) })
|
|
1824
1926
|
] }),
|
|
1825
|
-
selected.type === "paragraph" && /* @__PURE__ */
|
|
1826
|
-
/* @__PURE__ */
|
|
1827
|
-
/* @__PURE__ */
|
|
1828
|
-
/* @__PURE__ */
|
|
1829
|
-
/* @__PURE__ */
|
|
1830
|
-
/* @__PURE__ */
|
|
1831
|
-
/* @__PURE__ */
|
|
1832
|
-
/* @__PURE__ */
|
|
1833
|
-
/* @__PURE__ */
|
|
1834
|
-
/* @__PURE__ */
|
|
1835
|
-
/* @__PURE__ */
|
|
1836
|
-
/* @__PURE__ */
|
|
1837
|
-
/* @__PURE__ */
|
|
1927
|
+
selected.type === "paragraph" && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1928
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.content }),
|
|
1929
|
+
/* @__PURE__ */ jsx13("textarea", { style: { ...styles.propInput, minHeight: 70, resize: "vertical" }, value: t(selected.content, language), onChange: (e) => onUpdateField({ content: withLang(selected.content, language, e.target.value) }) }),
|
|
1930
|
+
/* @__PURE__ */ jsx13("div", { style: styles.inspectorDivider }),
|
|
1931
|
+
/* @__PURE__ */ jsx13("div", { style: styles.panelHeading, children: chrome.typography }),
|
|
1932
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.headingStyle }),
|
|
1933
|
+
/* @__PURE__ */ jsx13(Segmented, { options: PARAGRAPH_TAG_OPTIONS.map((v) => ({ value: v, label: TAG_CHROME_KEY[v] ? chrome[TAG_CHROME_KEY[v]] : v.toUpperCase() })), value: selected.tag || "p", onChange: (v) => onUpdateField({ tag: v, ...TAG_PRESETS[v] }) }),
|
|
1934
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.width }),
|
|
1935
|
+
/* @__PURE__ */ jsx13(Segmented, { options: FONT_SIZE_OPTIONS, value: selected.fontSize || "md", onChange: (v) => onUpdateField({ fontSize: v }) }),
|
|
1936
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.style }),
|
|
1937
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.styleToggleRow, children: [
|
|
1938
|
+
/* @__PURE__ */ jsx13("button", { type: "button", style: selected.fontWeight === "bold" ? styles.styleToggleActive : styles.styleToggle, onClick: () => onUpdateField({ fontWeight: selected.fontWeight === "bold" ? "normal" : "bold" }), children: /* @__PURE__ */ jsx13(Bold, { size: 14 }) }),
|
|
1939
|
+
/* @__PURE__ */ jsx13("button", { type: "button", style: selected.fontStyle === "italic" ? styles.styleToggleActive : styles.styleToggle, onClick: () => onUpdateField({ fontStyle: selected.fontStyle === "italic" ? "normal" : "italic" }), children: /* @__PURE__ */ jsx13(Italic, { size: 14 }) })
|
|
1838
1940
|
] }),
|
|
1839
|
-
/* @__PURE__ */
|
|
1840
|
-
/* @__PURE__ */
|
|
1841
|
-
/* @__PURE__ */
|
|
1842
|
-
/* @__PURE__ */
|
|
1843
|
-
COLOR_SWATCHES.map((c) => /* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1941
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.align }),
|
|
1942
|
+
/* @__PURE__ */ jsx13(Segmented, { options: TEXT_ALIGN_OPTIONS, value: selected.textAlign || "left", onChange: (v) => onUpdateField({ textAlign: v }) }),
|
|
1943
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.color }),
|
|
1944
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.swatchRow, children: [
|
|
1945
|
+
COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx13("button", { type: "button", title: c || chrome.none, style: { ...styles.swatchBtn, background: c || "var(--fb-ink)", ...selected.color === c ? styles.swatchBtnActive : {} }, onClick: () => onUpdateField({ color: c }) }, c || "default")),
|
|
1946
|
+
/* @__PURE__ */ jsx13("input", { type: "color", value: selected.color || "#1B1E24", onChange: (e) => onUpdateField({ color: e.target.value }), style: styles.colorPickerInput })
|
|
1845
1947
|
] })
|
|
1846
1948
|
] }),
|
|
1847
|
-
selected.type === "image" && /* @__PURE__ */
|
|
1848
|
-
/* @__PURE__ */
|
|
1849
|
-
/* @__PURE__ */
|
|
1850
|
-
/* @__PURE__ */
|
|
1851
|
-
/* @__PURE__ */
|
|
1852
|
-
/* @__PURE__ */
|
|
1853
|
-
/* @__PURE__ */
|
|
1854
|
-
/* @__PURE__ */
|
|
1855
|
-
/* @__PURE__ */
|
|
1856
|
-
/* @__PURE__ */
|
|
1857
|
-
/* @__PURE__ */
|
|
1949
|
+
selected.type === "image" && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1950
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.imageUrl }),
|
|
1951
|
+
/* @__PURE__ */ jsx13("input", { style: styles.propInput, placeholder: "https://...", value: selected.src || "", onChange: (e) => onUpdateField({ src: e.target.value }) }),
|
|
1952
|
+
/* @__PURE__ */ jsx13("p", { style: styles.helperText, children: chrome.imageUrlHelper }),
|
|
1953
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.altText }),
|
|
1954
|
+
/* @__PURE__ */ jsx13("input", { style: styles.propInput, value: t(selected.alt, language), onChange: (e) => onUpdateField({ alt: withLang(selected.alt, language, e.target.value) }) }),
|
|
1955
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.linkOptional }),
|
|
1956
|
+
/* @__PURE__ */ jsx13("input", { style: styles.propInput, placeholder: "https://...", value: selected.link || "", onChange: (e) => onUpdateField({ link: e.target.value }) }),
|
|
1957
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.shape }),
|
|
1958
|
+
/* @__PURE__ */ jsx13(Segmented, { options: IMAGE_SHAPES.map((v) => ({ value: v, label: chrome[IMAGE_SHAPE_CHROME_KEY[v]] })), value: selected.shape || "square", onChange: (v) => onUpdateField({ shape: v }) }),
|
|
1959
|
+
/* @__PURE__ */ jsx13("p", { style: styles.helperText, children: "Fills the field's own width (set below under Layout) and scales height automatically \u2014 always responsive, never overflows." })
|
|
1858
1960
|
] }),
|
|
1859
|
-
|
|
1860
|
-
/* @__PURE__ */
|
|
1861
|
-
/* @__PURE__ */
|
|
1961
|
+
selected.type === "button" && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1962
|
+
/* @__PURE__ */ jsx13("div", { style: styles.inspectorDivider }),
|
|
1963
|
+
/* @__PURE__ */ jsx13("div", { style: styles.panelHeading, children: chrome.buttonActionTitle }),
|
|
1964
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.buttonAction }),
|
|
1965
|
+
/* @__PURE__ */ jsx13(Segmented, { options: [{ value: "link", label: chrome.actionLink }, { value: "submit", label: chrome.actionSubmit }], value: selected.action || "submit", onChange: (v) => onUpdateField({ action: v }) }),
|
|
1966
|
+
selected.action === "link" ? /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1967
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.linkOptional }),
|
|
1968
|
+
/* @__PURE__ */ jsx13("input", { style: styles.propInput, placeholder: "https://...", value: selected.href || "", onChange: (e) => onUpdateField({ href: e.target.value }) }),
|
|
1969
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.openIn }),
|
|
1970
|
+
/* @__PURE__ */ jsx13(Segmented, { options: [{ value: "_self", label: chrome.sameTab }, { value: "_blank", label: chrome.newTab }], value: selected.target || "_self", onChange: (v) => onUpdateField({ target: v }) })
|
|
1971
|
+
] }) : /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1972
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.submitScope }),
|
|
1973
|
+
/* @__PURE__ */ jsx13(Segmented, { options: [{ value: "section", label: chrome.thisSection }, { value: "form", label: chrome.wholeForm }], value: selected.submitScope || "form", onChange: (v) => onUpdateField({ submitScope: v }) })
|
|
1974
|
+
] }),
|
|
1975
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.color }),
|
|
1976
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.swatchRow, children: [
|
|
1977
|
+
BUTTON_COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx13("button", { type: "button", title: c || chrome.none, style: { ...styles.swatchBtn, background: c || "var(--fb-primary)", ...(selected.buttonStyle?.color || "") === c ? styles.swatchBtnActive : {} }, onClick: () => onUpdateField({ buttonStyle: { ...selected.buttonStyle, color: c } }) }, c || "default")),
|
|
1978
|
+
/* @__PURE__ */ jsx13("input", { type: "color", value: selected.buttonStyle?.color || "#5B5FEF", onChange: (e) => onUpdateField({ buttonStyle: { ...selected.buttonStyle, color: e.target.value } }), style: styles.colorPickerInput })
|
|
1979
|
+
] }),
|
|
1980
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.buttonSize }),
|
|
1981
|
+
/* @__PURE__ */ jsx13(Segmented, { options: SUBMIT_SIZE_OPTIONS, value: selected.buttonStyle?.size || "md", onChange: (v) => onUpdateField({ buttonStyle: { ...selected.buttonStyle, size: v } }) })
|
|
1862
1982
|
] }),
|
|
1863
|
-
|
|
1864
|
-
/* @__PURE__ */
|
|
1865
|
-
/* @__PURE__ */
|
|
1983
|
+
meta.placeholder && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1984
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.placeholder }),
|
|
1985
|
+
/* @__PURE__ */ jsx13("input", { style: styles.propInput, value: t(f.placeholder, language), onChange: (e) => onUpdateField({ placeholder: withLang(f.placeholder, language, e.target.value) }) })
|
|
1866
1986
|
] }),
|
|
1867
|
-
selected.type === "input" && selected.inputType === "
|
|
1868
|
-
/* @__PURE__ */
|
|
1869
|
-
/* @__PURE__ */
|
|
1870
|
-
/* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.maxValue }),
|
|
1871
|
-
/* @__PURE__ */ jsx11("input", { type: "number", style: styles.propInput, value: selected.max ?? "", onChange: (e) => onUpdateField({ max: e.target.value === "" ? null : Number(e.target.value) }) })
|
|
1987
|
+
selected.type === "input" && (selected.inputType === "text" || selected.inputType === "password" || !selected.inputType) && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1988
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.maxLength }),
|
|
1989
|
+
/* @__PURE__ */ jsx13("input", { type: "number", style: styles.propInput, placeholder: chrome.noLimit, value: selected.maxLength || "", onChange: (e) => onUpdateField({ maxLength: e.target.value ? Number(e.target.value) : null }) })
|
|
1872
1990
|
] }),
|
|
1873
|
-
selected.type === "
|
|
1874
|
-
/* @__PURE__ */
|
|
1875
|
-
/* @__PURE__ */
|
|
1991
|
+
selected.type === "input" && selected.inputType === "number" && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1992
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.minValue }),
|
|
1993
|
+
/* @__PURE__ */ jsx13("input", { type: "number", style: styles.propInput, value: selected.min ?? "", onChange: (e) => onUpdateField({ min: e.target.value === "" ? null : Number(e.target.value) }) }),
|
|
1994
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.maxValue }),
|
|
1995
|
+
/* @__PURE__ */ jsx13("input", { type: "number", style: styles.propInput, value: selected.max ?? "", onChange: (e) => onUpdateField({ max: e.target.value === "" ? null : Number(e.target.value) }) })
|
|
1876
1996
|
] }),
|
|
1877
|
-
|
|
1878
|
-
/* @__PURE__ */
|
|
1879
|
-
/* @__PURE__ */
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1997
|
+
selected.type === "textarea" && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
1998
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.maxLength }),
|
|
1999
|
+
/* @__PURE__ */ jsx13("input", { type: "number", style: styles.propInput, placeholder: chrome.noLimit, value: selected.maxLength || "", onChange: (e) => onUpdateField({ maxLength: e.target.value ? Number(e.target.value) : null }) })
|
|
2000
|
+
] }),
|
|
2001
|
+
meta.options && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2002
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.options }),
|
|
2003
|
+
/* @__PURE__ */ jsxs11("div", { style: styles.optionList, children: [
|
|
2004
|
+
(f.options || []).map((opt, i) => /* @__PURE__ */ jsxs11("div", { style: styles.optionRow, children: [
|
|
2005
|
+
/* @__PURE__ */ jsx13("input", { style: styles.optionInput, value: t(opt.label, language), onChange: (e) => onUpdateOption(i, { label: withLang(opt.label, language, e.target.value) }) }),
|
|
2006
|
+
/* @__PURE__ */ jsx13("button", { style: styles.iconBtn, onClick: () => onRemoveOption(i), disabled: (f.options || []).length <= 1, children: /* @__PURE__ */ jsx13(X, { size: 13 }) })
|
|
1883
2007
|
] }, i)),
|
|
1884
|
-
/* @__PURE__ */
|
|
1885
|
-
/* @__PURE__ */
|
|
2008
|
+
/* @__PURE__ */ jsxs11("button", { style: styles.addOptionBtn, onClick: onAddOption, children: [
|
|
2009
|
+
/* @__PURE__ */ jsx13(Plus2, { size: 13 }),
|
|
1886
2010
|
" ",
|
|
1887
2011
|
chrome.addOption
|
|
1888
2012
|
] })
|
|
1889
2013
|
] })
|
|
1890
2014
|
] }),
|
|
1891
|
-
/* @__PURE__ */
|
|
1892
|
-
!meta.isContent && /* @__PURE__ */
|
|
1893
|
-
/* @__PURE__ */
|
|
1894
|
-
/* @__PURE__ */
|
|
2015
|
+
/* @__PURE__ */ jsx13(DefaultValueEditor, { field: selected, meta, lang: language, chrome, onChange: onUpdateField }),
|
|
2016
|
+
!meta.isContent && /* @__PURE__ */ jsxs11("label", { style: styles.toggleRow, children: [
|
|
2017
|
+
/* @__PURE__ */ jsx13("input", { type: "checkbox", checked: !!selected.required, onChange: (e) => onUpdateField({ required: e.target.checked }), style: { width: 15, height: 15, accentColor: "var(--fb-primary)" } }),
|
|
2018
|
+
/* @__PURE__ */ jsx13("span", { style: { fontSize: 13, color: "#4A4D57" }, children: chrome.requiredField })
|
|
1895
2019
|
] }),
|
|
1896
|
-
/* @__PURE__ */
|
|
1897
|
-
/* @__PURE__ */
|
|
1898
|
-
/* @__PURE__ */
|
|
1899
|
-
/* @__PURE__ */
|
|
1900
|
-
/* @__PURE__ */
|
|
1901
|
-
/* @__PURE__ */
|
|
1902
|
-
!meta.boolean && !meta.isContent && /* @__PURE__ */
|
|
1903
|
-
/* @__PURE__ */
|
|
1904
|
-
/* @__PURE__ */
|
|
2020
|
+
/* @__PURE__ */ jsx13("div", { style: styles.inspectorDivider }),
|
|
2021
|
+
/* @__PURE__ */ jsx13("div", { style: styles.panelHeading, children: chrome.layout }),
|
|
2022
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.width }),
|
|
2023
|
+
/* @__PURE__ */ jsx13(Segmented, { options: WIDTH_OPTIONS.map((o) => ({ ...o, label: o.labelKey ? chrome[o.labelKey] : o.label || "" })), value: selected.width || "1/1", onChange: (v) => onUpdateField({ width: v }) }),
|
|
2024
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.verticalAlign }),
|
|
2025
|
+
/* @__PURE__ */ jsx13(Segmented, { options: [{ value: "top", label: chrome.top }, { value: "middle", label: chrome.middle }, { value: "bottom", label: chrome.bottom }], value: selected.verticalAlign || "top", onChange: (v) => onUpdateField({ verticalAlign: v }) }),
|
|
2026
|
+
!meta.boolean && !meta.isContent && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2027
|
+
/* @__PURE__ */ jsx13("label", { style: styles.propLabel, children: chrome.labelPosition }),
|
|
2028
|
+
/* @__PURE__ */ jsx13(Segmented, { options: [{ value: "top", label: chrome.above }, { value: "inline", label: chrome.inline }], value: selected.labelPosition || "top", onChange: (v) => onUpdateField({ labelPosition: v }) })
|
|
1905
2029
|
] }),
|
|
1906
|
-
!meta.isContent && /* @__PURE__ */
|
|
1907
|
-
/* @__PURE__ */
|
|
1908
|
-
/* @__PURE__ */
|
|
1909
|
-
/* @__PURE__ */
|
|
1910
|
-
/* @__PURE__ */
|
|
1911
|
-
/* @__PURE__ */
|
|
2030
|
+
!meta.isContent && /* @__PURE__ */ jsxs11(Fragment4, { children: [
|
|
2031
|
+
/* @__PURE__ */ jsx13("div", { style: styles.inspectorDivider }),
|
|
2032
|
+
/* @__PURE__ */ jsx13("div", { style: styles.panelHeading, children: chrome.icon }),
|
|
2033
|
+
/* @__PURE__ */ jsxs11("label", { style: styles.toggleRow, children: [
|
|
2034
|
+
/* @__PURE__ */ jsx13("input", { type: "checkbox", checked: !!selected.showIcon, onChange: (e) => onUpdateField({ showIcon: e.target.checked }), style: { width: 15, height: 15, accentColor: "var(--fb-primary)" } }),
|
|
2035
|
+
/* @__PURE__ */ jsx13("span", { style: { fontSize: 13, color: "#4A4D57" }, children: chrome.showIcon })
|
|
1912
2036
|
] }),
|
|
1913
|
-
selected.showIcon && /* @__PURE__ */
|
|
2037
|
+
selected.showIcon && /* @__PURE__ */ jsx13("div", { style: styles.iconGrid, children: Object.keys(ICON_LIBRARY).map((key) => {
|
|
1914
2038
|
const IconComp = ICON_LIBRARY[key];
|
|
1915
2039
|
const active = selected.displayIcon === key;
|
|
1916
|
-
return /* @__PURE__ */
|
|
2040
|
+
return /* @__PURE__ */ jsx13("button", { type: "button", title: key, style: active ? styles.iconGridBtnActive : styles.iconGridBtn, onClick: () => onUpdateField({ displayIcon: key }), children: /* @__PURE__ */ jsx13(IconComp, { size: 15 }) }, key);
|
|
1917
2041
|
}) })
|
|
1918
2042
|
] }),
|
|
1919
|
-
/* @__PURE__ */
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
2043
|
+
/* @__PURE__ */ jsx13("div", { style: styles.inspectorDivider }),
|
|
2044
|
+
/* @__PURE__ */ jsxs11("button", { style: styles.deleteFieldBtn, onClick: onDeleteField, children: [
|
|
2045
|
+
/* @__PURE__ */ jsx13(Trash23, { size: 13 }),
|
|
1922
2046
|
" ",
|
|
1923
2047
|
chrome.deleteField
|
|
1924
2048
|
] })
|
|
@@ -1962,17 +2086,26 @@ function formatValue(field, lang) {
|
|
|
1962
2086
|
return String(v);
|
|
1963
2087
|
}
|
|
1964
2088
|
|
|
2089
|
+
// src/lib/collectSubmission.ts
|
|
2090
|
+
function collectFieldValues(fields) {
|
|
2091
|
+
const values = {};
|
|
2092
|
+
fields.forEach((f) => {
|
|
2093
|
+
if (getMeta(f.type).isContent) return;
|
|
2094
|
+
values[f.id] = f.defaultValue;
|
|
2095
|
+
});
|
|
2096
|
+
return values;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
1965
2099
|
// src/components/PreviewPane.tsx
|
|
1966
|
-
import {
|
|
1967
|
-
function PreviewPane({ title, sections, onFieldChange, language, strings, chrome, baseMaxWidth,
|
|
2100
|
+
import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2101
|
+
function PreviewPane({ title, sections, onFieldChange, language, strings, chrome, baseMaxWidth, onSubmit }) {
|
|
1968
2102
|
const [device, setDevice] = useState6("laptop");
|
|
1969
2103
|
const [errors, setErrors] = useState6({});
|
|
1970
2104
|
const [submitted, setSubmitted] = useState6(null);
|
|
2105
|
+
const [attemptedButtonId, setAttemptedButtonId] = useState6(null);
|
|
1971
2106
|
const deviceOptions = buildDeviceOptions(baseMaxWidth, chrome);
|
|
1972
2107
|
const maxWidth = (deviceOptions.find((d) => d.value === device) || deviceOptions[0]).maxWidth;
|
|
1973
2108
|
const allFields = sections.flatMap((s) => s.fields);
|
|
1974
|
-
const submitText = t(submitLabel, language) || strings.submit;
|
|
1975
|
-
const overallHasFormFields = allFields.some((f) => !getMeta(f.type).isContent);
|
|
1976
2109
|
function runValidation(fields) {
|
|
1977
2110
|
const errs = {};
|
|
1978
2111
|
fields.forEach((f) => {
|
|
@@ -1981,78 +2114,92 @@ function PreviewPane({ title, sections, onFieldChange, language, strings, chrome
|
|
|
1981
2114
|
});
|
|
1982
2115
|
return errs;
|
|
1983
2116
|
}
|
|
1984
|
-
function
|
|
2117
|
+
function buildSectionsBreakdown() {
|
|
2118
|
+
return sections.map((s) => ({ sectionId: s.id, values: collectFieldValues(s.fields) }));
|
|
2119
|
+
}
|
|
2120
|
+
function handleSubmitAll(buttonId) {
|
|
1985
2121
|
const errs = runValidation(allFields);
|
|
1986
2122
|
setErrors(errs);
|
|
2123
|
+
setAttemptedButtonId(buttonId);
|
|
1987
2124
|
if (Object.keys(errs).length > 0) {
|
|
1988
2125
|
setSubmitted(null);
|
|
1989
2126
|
return;
|
|
1990
2127
|
}
|
|
1991
2128
|
setSubmitted(allFields.filter((f) => !getMeta(f.type).isContent).map((f) => ({ label: t(f.label, language), value: formatValue(f, language) })));
|
|
2129
|
+
const sectionsBreakdown = buildSectionsBreakdown();
|
|
2130
|
+
const all = collectFieldValues(allFields);
|
|
2131
|
+
onSubmit?.({ buttonId, scope: "form", values: all, sections: sectionsBreakdown, all });
|
|
1992
2132
|
}
|
|
1993
|
-
function handleSubmitSection(section) {
|
|
2133
|
+
function handleSubmitSection(section, buttonId) {
|
|
1994
2134
|
const errs = runValidation(section.fields);
|
|
1995
2135
|
setErrors((prev) => {
|
|
1996
2136
|
const next = { ...prev };
|
|
1997
2137
|
section.fields.forEach((f) => delete next[f.id]);
|
|
1998
2138
|
return { ...next, ...errs };
|
|
1999
2139
|
});
|
|
2140
|
+
setAttemptedButtonId(buttonId);
|
|
2000
2141
|
if (Object.keys(errs).length > 0) {
|
|
2001
2142
|
setSubmitted(null);
|
|
2002
2143
|
return;
|
|
2003
2144
|
}
|
|
2004
2145
|
setSubmitted(section.fields.filter((f) => !getMeta(f.type).isContent).map((f) => ({ label: t(f.label, language), value: formatValue(f, language) })));
|
|
2146
|
+
const sectionsBreakdown = buildSectionsBreakdown();
|
|
2147
|
+
const all = collectFieldValues(allFields);
|
|
2148
|
+
onSubmit?.({ buttonId, scope: "section", sectionId: section.id, values: collectFieldValues(section.fields), sections: sectionsBreakdown, all });
|
|
2149
|
+
}
|
|
2150
|
+
function handleButtonAction(field) {
|
|
2151
|
+
if (field.action === "link") {
|
|
2152
|
+
if (field.href) window.open(field.href, field.target === "_blank" ? "_blank" : "_self", field.target === "_blank" ? "noopener,noreferrer" : void 0);
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
if (field.submitScope === "section") {
|
|
2156
|
+
const section = sections.find((s) => s.fields.some((f) => f.id === field.id));
|
|
2157
|
+
if (section) handleSubmitSection(section, field.id);
|
|
2158
|
+
} else {
|
|
2159
|
+
handleSubmitAll(field.id);
|
|
2160
|
+
}
|
|
2005
2161
|
}
|
|
2006
|
-
return /* @__PURE__ */
|
|
2007
|
-
/* @__PURE__ */
|
|
2008
|
-
/* @__PURE__ */
|
|
2009
|
-
/* @__PURE__ */
|
|
2010
|
-
/* @__PURE__ */
|
|
2011
|
-
allFields.length === 0 && /* @__PURE__ */
|
|
2162
|
+
return /* @__PURE__ */ jsxs12("div", { style: styles.previewWrap, children: [
|
|
2163
|
+
/* @__PURE__ */ jsxs12("div", { style: { width: "100%", maxWidth, display: "flex", flexDirection: "column", alignItems: "center" }, children: [
|
|
2164
|
+
/* @__PURE__ */ jsx14("div", { style: styles.previewToolbar, children: /* @__PURE__ */ jsx14(Segmented, { options: deviceOptions, value: device, onChange: setDevice }) }),
|
|
2165
|
+
/* @__PURE__ */ jsxs12("div", { style: { ...styles.previewCard, maxWidth, width: "100%" }, children: [
|
|
2166
|
+
/* @__PURE__ */ jsx14("h2", { style: styles.previewTitle, children: t(title, language) }),
|
|
2167
|
+
allFields.length === 0 && /* @__PURE__ */ jsx14("p", { style: { color: "var(--fb-muted)", fontSize: 14 }, children: strings.addFieldsHint }),
|
|
2012
2168
|
sections.map((section) => {
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
t(section.title, language) && /* @__PURE__ */ jsx12("h3", { style: styles.sectionRuntimeTitle, children: t(section.title, language) }),
|
|
2017
|
-
/* @__PURE__ */ jsx12("div", { style: styles.previewGrid, children: section.fields.map((field) => {
|
|
2169
|
+
return /* @__PURE__ */ jsxs12("div", { style: { background: section.background || "transparent", padding: section.background ? 16 : 0, borderRadius: section.background ? 10 : 0, marginBottom: "var(--fb-space-section)" }, children: [
|
|
2170
|
+
t(section.title, language) && /* @__PURE__ */ jsx14("h3", { style: styles.sectionRuntimeTitle, children: t(section.title, language) }),
|
|
2171
|
+
/* @__PURE__ */ jsx14("div", { style: styles.previewGrid, children: section.fields.map((field) => {
|
|
2018
2172
|
const width = effectiveWidth(field.width, device);
|
|
2019
2173
|
const flexBasis = `1 1 calc(${WIDTH_PERCENT[width]} - 14px)`;
|
|
2020
|
-
return /* @__PURE__ */
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
] })
|
|
2174
|
+
return /* @__PURE__ */ jsxs12("div", { style: { flex: flexBasis, minWidth: 0, alignSelf: ALIGN_MAP[field.verticalAlign || "top"] }, children: [
|
|
2175
|
+
/* @__PURE__ */ jsx14(FieldBlock, { field, lang: language, onFieldChange, strings, chrome, error: errors[field.id], onButtonAction: handleButtonAction }),
|
|
2176
|
+
field.type === "button" && field.id === attemptedButtonId && Object.keys(errors).length > 0 && /* @__PURE__ */ jsxs12("p", { style: styles.formErrorNote, children: [
|
|
2177
|
+
/* @__PURE__ */ jsx14(CircleAlert2, { size: 13 }),
|
|
2178
|
+
" ",
|
|
2179
|
+
strings.fixErrors
|
|
2180
|
+
] })
|
|
2181
|
+
] }, field.id);
|
|
2182
|
+
}) })
|
|
2030
2183
|
] }, section.id);
|
|
2031
|
-
})
|
|
2032
|
-
submitMode === "combined" && overallHasFormFields && /* @__PURE__ */ jsx12("button", { style: { ...styles.submitBtn, ...resolveSubmitStyle(submitStyle) }, onClick: handleSubmitAll, children: submitText }),
|
|
2033
|
-
submitMode === "combined" && Object.keys(errors).length > 0 && /* @__PURE__ */ jsxs11("p", { style: styles.formErrorNote, children: [
|
|
2034
|
-
/* @__PURE__ */ jsx12(CircleAlert2, { size: 13 }),
|
|
2035
|
-
" ",
|
|
2036
|
-
strings.fixErrors
|
|
2037
|
-
] })
|
|
2184
|
+
})
|
|
2038
2185
|
] })
|
|
2039
2186
|
] }),
|
|
2040
|
-
submitted && /* @__PURE__ */
|
|
2041
|
-
/* @__PURE__ */
|
|
2042
|
-
/* @__PURE__ */
|
|
2043
|
-
/* @__PURE__ */
|
|
2187
|
+
submitted && /* @__PURE__ */ jsx14("div", { style: styles.modalOverlay, onClick: () => setSubmitted(null), children: /* @__PURE__ */ jsxs12("div", { style: { ...styles.modal, width: 420 }, onClick: (e) => e.stopPropagation(), children: [
|
|
2188
|
+
/* @__PURE__ */ jsxs12("div", { style: styles.modalHeader, children: [
|
|
2189
|
+
/* @__PURE__ */ jsxs12("span", { style: { fontWeight: 600, fontSize: 14, display: "flex", alignItems: "center", gap: 7 }, children: [
|
|
2190
|
+
/* @__PURE__ */ jsx14(PartyPopper, { size: 15, color: "var(--fb-primary)" }),
|
|
2044
2191
|
" ",
|
|
2045
2192
|
strings.submittedTitle
|
|
2046
2193
|
] }),
|
|
2047
|
-
/* @__PURE__ */
|
|
2194
|
+
/* @__PURE__ */ jsx14("button", { style: styles.iconBtn, onClick: () => setSubmitted(null), children: /* @__PURE__ */ jsx14(X2, { size: 16 }) })
|
|
2048
2195
|
] }),
|
|
2049
|
-
/* @__PURE__ */
|
|
2050
|
-
/* @__PURE__ */
|
|
2051
|
-
/* @__PURE__ */
|
|
2052
|
-
/* @__PURE__ */
|
|
2053
|
-
/* @__PURE__ */
|
|
2196
|
+
/* @__PURE__ */ jsxs12("div", { style: { padding: 16 }, children: [
|
|
2197
|
+
/* @__PURE__ */ jsx14("p", { style: { fontSize: 12.5, color: "var(--fb-muted)", marginTop: 0 }, children: strings.submittedBody }),
|
|
2198
|
+
/* @__PURE__ */ jsx14("div", { style: styles.submittedList, children: submitted.map((row, i) => /* @__PURE__ */ jsxs12("div", { style: styles.submittedRow, children: [
|
|
2199
|
+
/* @__PURE__ */ jsx14("span", { style: styles.submittedLabel, children: row.label }),
|
|
2200
|
+
/* @__PURE__ */ jsx14("span", { style: styles.submittedValue, children: row.value })
|
|
2054
2201
|
] }, i)) }),
|
|
2055
|
-
/* @__PURE__ */
|
|
2202
|
+
/* @__PURE__ */ jsx14("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, onClick: () => setSubmitted(null), children: strings.close })
|
|
2056
2203
|
] })
|
|
2057
2204
|
] }) })
|
|
2058
2205
|
] });
|
|
@@ -2060,47 +2207,47 @@ function PreviewPane({ title, sections, onFieldChange, language, strings, chrome
|
|
|
2060
2207
|
|
|
2061
2208
|
// src/components/modals/JsonModal.tsx
|
|
2062
2209
|
import { Check, ClipboardCopy, X as X3 } from "lucide-react";
|
|
2063
|
-
import { jsx as
|
|
2210
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2064
2211
|
function JsonModal({ chrome, jsonString, copied, onCopy, onClose }) {
|
|
2065
|
-
return /* @__PURE__ */
|
|
2066
|
-
/* @__PURE__ */
|
|
2067
|
-
/* @__PURE__ */
|
|
2068
|
-
/* @__PURE__ */
|
|
2069
|
-
/* @__PURE__ */
|
|
2070
|
-
copied ? /* @__PURE__ */
|
|
2212
|
+
return /* @__PURE__ */ jsx15("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs13("div", { style: styles.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
2213
|
+
/* @__PURE__ */ jsxs13("div", { style: styles.modalHeader, children: [
|
|
2214
|
+
/* @__PURE__ */ jsx15("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.formJson }),
|
|
2215
|
+
/* @__PURE__ */ jsxs13("div", { style: { display: "flex", gap: 8 }, children: [
|
|
2216
|
+
/* @__PURE__ */ jsxs13("button", { style: styles.ghostBtn, onClick: onCopy, children: [
|
|
2217
|
+
copied ? /* @__PURE__ */ jsx15(Check, { size: 14 }) : /* @__PURE__ */ jsx15(ClipboardCopy, { size: 14 }),
|
|
2071
2218
|
copied ? chrome.copied : chrome.copy
|
|
2072
2219
|
] }),
|
|
2073
|
-
/* @__PURE__ */
|
|
2220
|
+
/* @__PURE__ */ jsx15("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx15(X3, { size: 16 }) })
|
|
2074
2221
|
] })
|
|
2075
2222
|
] }),
|
|
2076
|
-
/* @__PURE__ */
|
|
2223
|
+
/* @__PURE__ */ jsx15("pre", { style: styles.jsonPre, children: jsonString })
|
|
2077
2224
|
] }) });
|
|
2078
2225
|
}
|
|
2079
2226
|
|
|
2080
|
-
// src/components/modals/
|
|
2227
|
+
// src/components/modals/TemplatesModal.tsx
|
|
2081
2228
|
import { Trash2 as Trash24, X as X4 } from "lucide-react";
|
|
2082
|
-
import { jsx as
|
|
2083
|
-
function
|
|
2084
|
-
return /* @__PURE__ */
|
|
2085
|
-
/* @__PURE__ */
|
|
2086
|
-
/* @__PURE__ */
|
|
2087
|
-
/* @__PURE__ */
|
|
2229
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2230
|
+
function TemplatesModal({ chrome, savedForms, currentFormId, onOpen, onDelete, onClose }) {
|
|
2231
|
+
return /* @__PURE__ */ jsx16("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs14("div", { style: styles.modal, onClick: (e) => e.stopPropagation(), children: [
|
|
2232
|
+
/* @__PURE__ */ jsxs14("div", { style: styles.modalHeader, children: [
|
|
2233
|
+
/* @__PURE__ */ jsx16("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.templates }),
|
|
2234
|
+
/* @__PURE__ */ jsx16("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx16(X4, { size: 16 }) })
|
|
2088
2235
|
] }),
|
|
2089
|
-
/* @__PURE__ */
|
|
2090
|
-
/* @__PURE__ */
|
|
2091
|
-
/* @__PURE__ */
|
|
2236
|
+
/* @__PURE__ */ jsx16("div", { style: styles.libraryBody, children: savedForms.length === 0 ? /* @__PURE__ */ jsx16("div", { style: styles.inspectorEmpty, children: chrome.noTemplates }) : savedForms.map((f) => /* @__PURE__ */ jsxs14("div", { style: styles.libraryRow, children: [
|
|
2237
|
+
/* @__PURE__ */ jsxs14("div", { style: { minWidth: 0 }, children: [
|
|
2238
|
+
/* @__PURE__ */ jsxs14("div", { style: styles.libraryRowTitle, children: [
|
|
2092
2239
|
f.title,
|
|
2093
|
-
f.id === currentFormId && /* @__PURE__ */
|
|
2240
|
+
f.id === currentFormId && /* @__PURE__ */ jsx16("span", { style: styles.currentBadge, children: chrome.current })
|
|
2094
2241
|
] }),
|
|
2095
|
-
/* @__PURE__ */
|
|
2242
|
+
/* @__PURE__ */ jsxs14("div", { style: styles.libraryRowMeta, children: [
|
|
2096
2243
|
chrome.updated,
|
|
2097
2244
|
" ",
|
|
2098
2245
|
new Date(f.updatedAt).toLocaleString()
|
|
2099
2246
|
] })
|
|
2100
2247
|
] }),
|
|
2101
|
-
/* @__PURE__ */
|
|
2102
|
-
/* @__PURE__ */
|
|
2103
|
-
/* @__PURE__ */
|
|
2248
|
+
/* @__PURE__ */ jsxs14("div", { style: { display: "flex", gap: 6, flexShrink: 0 }, children: [
|
|
2249
|
+
/* @__PURE__ */ jsx16("button", { style: styles.ghostBtn, onClick: () => onOpen(f.id), children: chrome.open }),
|
|
2250
|
+
/* @__PURE__ */ jsx16("button", { style: { ...styles.iconBtn, ...styles.iconBtnDanger }, title: chrome.delete, onClick: () => onDelete(f.id), children: /* @__PURE__ */ jsx16(Trash24, { size: 13 }) })
|
|
2104
2251
|
] })
|
|
2105
2252
|
] }, f.id)) })
|
|
2106
2253
|
] }) });
|
|
@@ -2109,19 +2256,19 @@ function LibraryModal({ chrome, savedForms, currentFormId, onOpen, onDelete, onC
|
|
|
2109
2256
|
// src/components/modals/SaveAsModal.tsx
|
|
2110
2257
|
import { useState as useState7 } from "react";
|
|
2111
2258
|
import { Save as Save2, X as X5 } from "lucide-react";
|
|
2112
|
-
import { jsx as
|
|
2259
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2113
2260
|
function SaveAsModal({ chrome, suggestedName, onSave, onClose }) {
|
|
2114
2261
|
const [name, setName] = useState7(suggestedName);
|
|
2115
|
-
return /* @__PURE__ */
|
|
2116
|
-
/* @__PURE__ */
|
|
2117
|
-
/* @__PURE__ */
|
|
2118
|
-
/* @__PURE__ */
|
|
2262
|
+
return /* @__PURE__ */ jsx17("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs15("div", { style: { ...styles.modal, width: 380 }, onClick: (e) => e.stopPropagation(), children: [
|
|
2263
|
+
/* @__PURE__ */ jsxs15("div", { style: styles.modalHeader, children: [
|
|
2264
|
+
/* @__PURE__ */ jsx17("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.saveForm }),
|
|
2265
|
+
/* @__PURE__ */ jsx17("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx17(X5, { size: 16 }) })
|
|
2119
2266
|
] }),
|
|
2120
|
-
/* @__PURE__ */
|
|
2121
|
-
/* @__PURE__ */
|
|
2122
|
-
/* @__PURE__ */
|
|
2123
|
-
/* @__PURE__ */
|
|
2124
|
-
/* @__PURE__ */
|
|
2267
|
+
/* @__PURE__ */ jsxs15("div", { style: { padding: 16 }, children: [
|
|
2268
|
+
/* @__PURE__ */ jsx17("label", { style: styles.propLabel, children: chrome.formName }),
|
|
2269
|
+
/* @__PURE__ */ jsx17("input", { autoFocus: true, style: styles.propInput, value: name, onChange: (e) => setName(e.target.value), onKeyDown: (e) => e.key === "Enter" && name.trim() && onSave(name.trim()) }),
|
|
2270
|
+
/* @__PURE__ */ jsxs15("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, disabled: !name.trim(), onClick: () => onSave(name.trim()), children: [
|
|
2271
|
+
/* @__PURE__ */ jsx17(Save2, { size: 14 }),
|
|
2125
2272
|
" ",
|
|
2126
2273
|
chrome.saveToLibrary
|
|
2127
2274
|
] })
|
|
@@ -2129,45 +2276,6 @@ function SaveAsModal({ chrome, suggestedName, onSave, onClose }) {
|
|
|
2129
2276
|
] }) });
|
|
2130
2277
|
}
|
|
2131
2278
|
|
|
2132
|
-
// src/components/modals/SettingsModal.tsx
|
|
2133
|
-
import { X as X6 } from "lucide-react";
|
|
2134
|
-
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2135
|
-
function SettingsModal({
|
|
2136
|
-
chrome,
|
|
2137
|
-
strings,
|
|
2138
|
-
submitLabel,
|
|
2139
|
-
language,
|
|
2140
|
-
submitMode,
|
|
2141
|
-
submitStyle,
|
|
2142
|
-
onSubmitLabelChange,
|
|
2143
|
-
onSubmitModeChange,
|
|
2144
|
-
onSubmitStyleChange,
|
|
2145
|
-
onClose
|
|
2146
|
-
}) {
|
|
2147
|
-
return /* @__PURE__ */ jsx16("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs15("div", { style: { ...styles.modal, width: 400 }, onClick: (e) => e.stopPropagation(), children: [
|
|
2148
|
-
/* @__PURE__ */ jsxs15("div", { style: styles.modalHeader, children: [
|
|
2149
|
-
/* @__PURE__ */ jsx16("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.formSettings }),
|
|
2150
|
-
/* @__PURE__ */ jsx16("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx16(X6, { size: 16 }) })
|
|
2151
|
-
] }),
|
|
2152
|
-
/* @__PURE__ */ jsxs15("div", { style: { padding: 16 }, children: [
|
|
2153
|
-
/* @__PURE__ */ jsx16("div", { style: styles.panelHeading, children: chrome.submitSectionTitle }),
|
|
2154
|
-
/* @__PURE__ */ jsx16("label", { style: styles.propLabel, children: chrome.submitLabel }),
|
|
2155
|
-
/* @__PURE__ */ jsx16("input", { style: styles.propInput, placeholder: strings.submit, value: t(submitLabel, language), onChange: (e) => onSubmitLabelChange(e.target.value) }),
|
|
2156
|
-
/* @__PURE__ */ jsx16("label", { style: styles.propLabel, children: chrome.submitMode }),
|
|
2157
|
-
/* @__PURE__ */ jsx16(Segmented, { options: [{ value: "combined", label: chrome.combined }, { value: "perSection", label: chrome.perSection }], value: submitMode, onChange: onSubmitModeChange }),
|
|
2158
|
-
/* @__PURE__ */ jsx16("div", { style: styles.inspectorDivider }),
|
|
2159
|
-
/* @__PURE__ */ jsx16("div", { style: styles.panelHeading, children: chrome.submitStyle }),
|
|
2160
|
-
/* @__PURE__ */ jsx16("label", { style: styles.propLabel, children: chrome.color }),
|
|
2161
|
-
/* @__PURE__ */ jsxs15("div", { style: styles.swatchRow, children: [
|
|
2162
|
-
BUTTON_COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx16("button", { type: "button", title: c || chrome.none, style: { ...styles.swatchBtn, background: c || "var(--fb-primary)", ...(submitStyle.color || "") === c ? styles.swatchBtnActive : {} }, onClick: () => onSubmitStyleChange({ color: c }) }, c || "default")),
|
|
2163
|
-
/* @__PURE__ */ jsx16("input", { type: "color", value: submitStyle.color || "#5B5FEF", onChange: (e) => onSubmitStyleChange({ color: e.target.value }), style: styles.colorPickerInput })
|
|
2164
|
-
] }),
|
|
2165
|
-
/* @__PURE__ */ jsx16("label", { style: styles.propLabel, children: chrome.buttonSize }),
|
|
2166
|
-
/* @__PURE__ */ jsx16(Segmented, { options: SUBMIT_SIZE_OPTIONS, value: submitStyle.size, onChange: (v) => onSubmitStyleChange({ size: v }) })
|
|
2167
|
-
] })
|
|
2168
|
-
] }) });
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2171
2279
|
// src/styles/globalCss.ts
|
|
2172
2280
|
var css = `
|
|
2173
2281
|
* { box-sizing: border-box; }
|
|
@@ -2175,19 +2283,27 @@ var css = `
|
|
|
2175
2283
|
input, textarea, select { font-family: inherit; }
|
|
2176
2284
|
@keyframes fb-spin { to { transform: rotate(360deg); } }
|
|
2177
2285
|
.spin { animation: fb-spin 0.8s linear infinite; }
|
|
2286
|
+
/* Caps the widget at the viewport height so it scrolls internally rather
|
|
2287
|
+
than growing past whatever space its host container gives it; the
|
|
2288
|
+
second declaration upgrades to the dynamic viewport unit on browsers
|
|
2289
|
+
that support it (mobile browser chrome resizing the viewport), and is
|
|
2290
|
+
simply ignored by ones that don't. */
|
|
2291
|
+
.fb-root { max-height: 100vh; max-height: 100dvh; }
|
|
2178
2292
|
`;
|
|
2179
2293
|
|
|
2180
2294
|
// src/FormBuilder.tsx
|
|
2181
|
-
import { jsx as
|
|
2182
|
-
|
|
2295
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2296
|
+
var FormBuilder = forwardRef(function FormBuilder2({
|
|
2183
2297
|
theme: themeOverrideProp,
|
|
2184
2298
|
language: languageOverride,
|
|
2185
2299
|
languages = DEFAULT_LANGUAGES,
|
|
2186
2300
|
strings: stringsOverride,
|
|
2187
2301
|
chrome: chromeOverride,
|
|
2188
2302
|
themeEditable = false,
|
|
2189
|
-
storage: storageProp
|
|
2190
|
-
|
|
2303
|
+
storage: storageProp,
|
|
2304
|
+
onSubmit,
|
|
2305
|
+
initialDocument
|
|
2306
|
+
}, ref) {
|
|
2191
2307
|
const storage = storageProp ?? localStorageAdapter;
|
|
2192
2308
|
const { theme, updateThemeColor, updateThemeLayout, resetTheme, replaceThemeOverrides, themeOverrides } = useTheme(themeOverrideProp);
|
|
2193
2309
|
const [language, setLanguage] = useState8(languageOverride || languages[0]?.code || "en");
|
|
@@ -2197,20 +2313,14 @@ function FormBuilder({
|
|
|
2197
2313
|
const drag = useDragReorder(doc.reorderWithinSection);
|
|
2198
2314
|
const [mode, setMode] = useState8("build");
|
|
2199
2315
|
const [showJson, setShowJson] = useState8(false);
|
|
2200
|
-
const [showSettings, setShowSettings] = useState8(false);
|
|
2201
2316
|
const [showLibrary, setShowLibrary] = useState8(false);
|
|
2202
2317
|
const [copied, setCopied] = useState8(false);
|
|
2203
2318
|
const persistence = usePersistence({
|
|
2204
2319
|
storage,
|
|
2205
2320
|
language,
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
submitMode: doc.submitMode,
|
|
2210
|
-
submitStyle: doc.submitStyle,
|
|
2211
|
-
themeOverrides,
|
|
2212
|
-
sections: doc.sections
|
|
2213
|
-
},
|
|
2321
|
+
chrome,
|
|
2322
|
+
document: { title: doc.title, themeOverrides, sections: doc.sections },
|
|
2323
|
+
initialDocument,
|
|
2214
2324
|
onLoadDocument: doc.loadDocument,
|
|
2215
2325
|
onLoadThemeOverrides: replaceThemeOverrides,
|
|
2216
2326
|
onTitleChange: doc.setTitle,
|
|
@@ -2221,13 +2331,11 @@ function FormBuilder({
|
|
|
2221
2331
|
ensureActiveSection: () => doc.setActiveSectionId((prev) => prev ?? doc.sections[0]?.id ?? null)
|
|
2222
2332
|
});
|
|
2223
2333
|
const jsonDoc = {
|
|
2224
|
-
version:
|
|
2334
|
+
version: 5,
|
|
2225
2335
|
title: doc.title,
|
|
2226
|
-
|
|
2227
|
-
submitMode: doc.submitMode,
|
|
2228
|
-
submitStyle: doc.submitStyle,
|
|
2336
|
+
theme,
|
|
2229
2337
|
themeOverrides,
|
|
2230
|
-
sections: doc.sections.map((s) => ({ id: s.id, title: s.title, background: s.background, collapsed: s.collapsed,
|
|
2338
|
+
sections: doc.sections.map((s) => ({ id: s.id, title: s.title, background: s.background, collapsed: s.collapsed, fields: s.fields }))
|
|
2231
2339
|
};
|
|
2232
2340
|
const jsonString = JSON.stringify(jsonDoc, null, 2);
|
|
2233
2341
|
function copyJson() {
|
|
@@ -2237,6 +2345,17 @@ function FormBuilder({
|
|
|
2237
2345
|
}).catch(() => {
|
|
2238
2346
|
});
|
|
2239
2347
|
}
|
|
2348
|
+
useImperativeHandle(ref, () => ({
|
|
2349
|
+
getDocument: () => jsonDoc,
|
|
2350
|
+
exportJson: () => jsonString,
|
|
2351
|
+
loadDocument: (raw) => {
|
|
2352
|
+
const migrated = migrateDocument(raw);
|
|
2353
|
+
if (!migrated) return;
|
|
2354
|
+
doc.loadDocument(migrated);
|
|
2355
|
+
replaceThemeOverrides(migrated.themeOverrides);
|
|
2356
|
+
}
|
|
2357
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2358
|
+
}), [jsonDoc, jsonString]);
|
|
2240
2359
|
const activeSectionIdx = doc.sections.findIndex((s) => s.id === doc.activeSection?.id);
|
|
2241
2360
|
const activeSectionLabel = t(doc.activeSection?.title, language) || `#${activeSectionIdx + 1}`;
|
|
2242
2361
|
const rootStyle = {
|
|
@@ -2259,9 +2378,9 @@ function FormBuilder({
|
|
|
2259
2378
|
"--fb-space-panel": `${theme.layout.panelPadding}px`,
|
|
2260
2379
|
"--fb-space-ticket": `${theme.layout.ticketPadding}px`
|
|
2261
2380
|
};
|
|
2262
|
-
return /* @__PURE__ */ jsxs16("div", { style: rootStyle, children: [
|
|
2263
|
-
/* @__PURE__ */
|
|
2264
|
-
/* @__PURE__ */
|
|
2381
|
+
return /* @__PURE__ */ jsxs16("div", { className: "fb-root", style: rootStyle, children: [
|
|
2382
|
+
/* @__PURE__ */ jsx18("style", { children: css }),
|
|
2383
|
+
/* @__PURE__ */ jsx18(
|
|
2265
2384
|
Toolbar,
|
|
2266
2385
|
{
|
|
2267
2386
|
title: doc.title,
|
|
@@ -2270,34 +2389,38 @@ function FormBuilder({
|
|
|
2270
2389
|
mode,
|
|
2271
2390
|
saveState: persistence.saveState,
|
|
2272
2391
|
chrome,
|
|
2273
|
-
themeEditable,
|
|
2274
|
-
theme,
|
|
2275
2392
|
savedFormsCount: persistence.savedForms.length,
|
|
2276
2393
|
onTitleChange: doc.updateTitle,
|
|
2277
2394
|
onLanguageChange: setLanguage,
|
|
2278
2395
|
onModeChange: setMode,
|
|
2279
|
-
onOpenSettings: () => setShowSettings(true),
|
|
2280
2396
|
onNewForm: persistence.newForm,
|
|
2281
2397
|
onOpenLibrary: () => setShowLibrary(true),
|
|
2282
2398
|
onSaveExisting: persistence.saveExisting,
|
|
2283
|
-
onOpenJson: () => setShowJson(true)
|
|
2284
|
-
updateThemeColor,
|
|
2285
|
-
updateThemeLayout,
|
|
2286
|
-
resetTheme
|
|
2399
|
+
onOpenJson: () => setShowJson(true)
|
|
2287
2400
|
}
|
|
2288
2401
|
),
|
|
2289
2402
|
persistence.loadingDraft ? /* @__PURE__ */ jsxs16("div", { style: styles.loadingScreen, children: [
|
|
2290
|
-
/* @__PURE__ */
|
|
2291
|
-
/* @__PURE__ */
|
|
2403
|
+
/* @__PURE__ */ jsx18(Loader22, { size: 20, className: "spin" }),
|
|
2404
|
+
/* @__PURE__ */ jsx18("span", { style: { marginTop: 8, fontSize: 13, color: "var(--fb-muted)" }, children: chrome.loadingDraft })
|
|
2292
2405
|
] }) : mode === "build" ? /* @__PURE__ */ jsxs16("div", { style: styles.workArea, children: [
|
|
2293
|
-
/* @__PURE__ */
|
|
2294
|
-
|
|
2406
|
+
/* @__PURE__ */ jsx18(
|
|
2407
|
+
Palette,
|
|
2408
|
+
{
|
|
2409
|
+
activeSectionLabel,
|
|
2410
|
+
chrome,
|
|
2411
|
+
onAddField: doc.addField,
|
|
2412
|
+
themeEditable,
|
|
2413
|
+
theme,
|
|
2414
|
+
updateThemeColor,
|
|
2415
|
+
updateThemeLayout,
|
|
2416
|
+
resetTheme
|
|
2417
|
+
}
|
|
2418
|
+
),
|
|
2419
|
+
/* @__PURE__ */ jsx18(
|
|
2295
2420
|
Canvas,
|
|
2296
2421
|
{
|
|
2297
2422
|
sections: doc.sections,
|
|
2298
2423
|
activeSectionId: doc.activeSectionId,
|
|
2299
|
-
submitMode: doc.submitMode,
|
|
2300
|
-
submitStyle: doc.submitStyle,
|
|
2301
2424
|
selectedId: doc.selectedId,
|
|
2302
2425
|
dragOverKey: drag.dragOverKey,
|
|
2303
2426
|
chrome,
|
|
@@ -2310,8 +2433,6 @@ function FormBuilder({
|
|
|
2310
2433
|
onDuplicateSection: doc.duplicateSection,
|
|
2311
2434
|
onMoveSection: doc.moveSection,
|
|
2312
2435
|
onDeleteSection: doc.deleteSection,
|
|
2313
|
-
onUpdateSectionSubmitStyle: doc.updateSectionSubmitStyle,
|
|
2314
|
-
onClearSectionSubmitStyle: doc.clearSectionSubmitStyle,
|
|
2315
2436
|
onAddSection: doc.addSection,
|
|
2316
2437
|
onSelectField: (sectionId, fieldId) => {
|
|
2317
2438
|
doc.setSelectedId(fieldId);
|
|
@@ -2325,7 +2446,7 @@ function FormBuilder({
|
|
|
2325
2446
|
getDragHandleProps: drag.getDragHandleProps
|
|
2326
2447
|
}
|
|
2327
2448
|
),
|
|
2328
|
-
/* @__PURE__ */
|
|
2449
|
+
/* @__PURE__ */ jsx18(
|
|
2329
2450
|
Inspector,
|
|
2330
2451
|
{
|
|
2331
2452
|
selected: doc.selected,
|
|
@@ -2338,7 +2459,7 @@ function FormBuilder({
|
|
|
2338
2459
|
onRemoveOption: (optIdx) => doc.selected && doc.removeOption(doc.selected.id, optIdx)
|
|
2339
2460
|
}
|
|
2340
2461
|
)
|
|
2341
|
-
] }) : /* @__PURE__ */
|
|
2462
|
+
] }) : /* @__PURE__ */ jsx18(
|
|
2342
2463
|
PreviewPane,
|
|
2343
2464
|
{
|
|
2344
2465
|
title: doc.title,
|
|
@@ -2348,14 +2469,12 @@ function FormBuilder({
|
|
|
2348
2469
|
strings,
|
|
2349
2470
|
chrome,
|
|
2350
2471
|
baseMaxWidth: theme.layout.maxWidth,
|
|
2351
|
-
|
|
2352
|
-
submitMode: doc.submitMode,
|
|
2353
|
-
submitStyle: doc.submitStyle
|
|
2472
|
+
onSubmit
|
|
2354
2473
|
}
|
|
2355
2474
|
),
|
|
2356
|
-
showJson && /* @__PURE__ */
|
|
2357
|
-
showLibrary && /* @__PURE__ */
|
|
2358
|
-
|
|
2475
|
+
showJson && /* @__PURE__ */ jsx18(JsonModal, { chrome, jsonString, copied, onCopy: copyJson, onClose: () => setShowJson(false) }),
|
|
2476
|
+
showLibrary && /* @__PURE__ */ jsx18(
|
|
2477
|
+
TemplatesModal,
|
|
2359
2478
|
{
|
|
2360
2479
|
chrome,
|
|
2361
2480
|
savedForms: persistence.savedForms,
|
|
@@ -2368,7 +2487,7 @@ function FormBuilder({
|
|
|
2368
2487
|
onClose: () => setShowLibrary(false)
|
|
2369
2488
|
}
|
|
2370
2489
|
),
|
|
2371
|
-
persistence.saveAsPrompt && /* @__PURE__ */
|
|
2490
|
+
persistence.saveAsPrompt && /* @__PURE__ */ jsx18(
|
|
2372
2491
|
SaveAsModal,
|
|
2373
2492
|
{
|
|
2374
2493
|
chrome,
|
|
@@ -2376,27 +2495,13 @@ function FormBuilder({
|
|
|
2376
2495
|
onSave: persistence.saveAs,
|
|
2377
2496
|
onClose: persistence.dismissSaveAsPrompt
|
|
2378
2497
|
}
|
|
2379
|
-
),
|
|
2380
|
-
showSettings && /* @__PURE__ */ jsx17(
|
|
2381
|
-
SettingsModal,
|
|
2382
|
-
{
|
|
2383
|
-
chrome,
|
|
2384
|
-
strings,
|
|
2385
|
-
submitLabel: doc.submitLabel,
|
|
2386
|
-
language,
|
|
2387
|
-
submitMode: doc.submitMode,
|
|
2388
|
-
submitStyle: doc.submitStyle,
|
|
2389
|
-
onSubmitLabelChange: doc.updateSubmitLabel,
|
|
2390
|
-
onSubmitModeChange: doc.setSubmitMode,
|
|
2391
|
-
onSubmitStyleChange: doc.updateSubmitStyle,
|
|
2392
|
-
onClose: () => setShowSettings(false)
|
|
2393
|
-
}
|
|
2394
2498
|
)
|
|
2395
2499
|
] });
|
|
2396
|
-
}
|
|
2500
|
+
});
|
|
2501
|
+
var FormBuilder_default = FormBuilder;
|
|
2397
2502
|
export {
|
|
2398
|
-
FormBuilder,
|
|
2399
|
-
|
|
2503
|
+
FormBuilder_default as FormBuilder,
|
|
2504
|
+
FormBuilder_default as default,
|
|
2400
2505
|
localStorageAdapter
|
|
2401
2506
|
};
|
|
2402
2507
|
//# sourceMappingURL=index.js.map
|