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/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
- myForms: "My forms",
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
- openSavedForm: "Open a saved form",
106
- saveToLibraryTitle: "Save this form to your library",
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
- nothingSaved: 'Nothing saved yet. Click "Save" in the toolbar to store this form here.',
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 form",
123
- formName: "Form name",
124
- saveToLibrary: "Save to library",
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
- submitSectionTitle: "Submit",
157
- submitStyle: "Submit button style",
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
- myForms: "\u30DE\u30A4\u30D5\u30A9\u30FC\u30E0",
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
- openSavedForm: "\u4FDD\u5B58\u6E08\u307F\u30D5\u30A9\u30FC\u30E0\u3092\u958B\u304F",
235
- saveToLibraryTitle: "\u3053\u306E\u30D5\u30A9\u30FC\u30E0\u3092\u30E9\u30A4\u30D6\u30E9\u30EA\u306B\u4FDD\u5B58",
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
- nothingSaved: "\u307E\u3060\u4FDD\u5B58\u3055\u308C\u3066\u3044\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",
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: "\u30D5\u30A9\u30FC\u30E0\u3092\u4FDD\u5B58",
252
- formName: "\u30D5\u30A9\u30FC\u30E0\u540D",
253
- saveToLibrary: "\u30E9\u30A4\u30D6\u30E9\u30EA\u306B\u4FDD\u5B58",
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
- submitSectionTitle: "\u9001\u4FE1",
286
- submitStyle: "\u9001\u4FE1\u30DC\u30BF\u30F3\u306E\u30B9\u30BF\u30A4\u30EB",
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
- return window.localStorage.getItem(key);
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, submitStyle: null, fields: [] };
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
- const raw = await storage.get(DRAFT_KEY);
806
- if (raw) {
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
- ensureActiveSection();
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.submitLabel, document.submitMode, document.submitStyle, document.themeOverrides, document.sections, currentFormId]);
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, Languages, Pencil, Eye, Settings, FilePlus2, FolderOpen, Save, Code2 } from "lucide-react";
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)", minHeight: 640, maxHeight: "100vh", display: "flex", flexDirection: "column" },
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/Segmented.tsx
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__ */ jsx("div", { style: styles.segmented, children: options.map((opt) => {
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__ */ jsxs("button", { type: "button", style: active ? styles.segmentedBtnActive : styles.segmentedBtn, onClick: () => onChange(opt.value), children: [
1072
- Icon && /* @__PURE__ */ jsx(Icon, { size: 13 }),
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/LayoutPopover.tsx
1079
- import { useState as useState5 } from "react";
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/LayoutPopover.tsx
1120
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1121
- function LayoutPopover({ chrome, theme, updateThemeColor, updateThemeLayout, resetTheme }) {
1122
- const [open, setOpen] = useState5(false);
1123
- return /* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
1124
- /* @__PURE__ */ jsx2("button", { style: styles.iconBtn, title: chrome.spacing, onClick: () => setOpen((v) => !v), children: /* @__PURE__ */ jsx2(Ruler, { size: 14 }) }),
1125
- open && /* @__PURE__ */ jsxs2("div", { style: styles.layoutPanel, children: [
1126
- /* @__PURE__ */ jsxs2("div", { style: styles.layoutPanelHeader, children: [
1127
- /* @__PURE__ */ jsxs2("span", { style: { fontWeight: 600, fontSize: 13 }, children: [
1128
- chrome.theme,
1129
- " / ",
1130
- chrome.spacing
1131
- ] }),
1132
- /* @__PURE__ */ jsxs2("button", { type: "button", style: styles.resetLinkBtn, onClick: resetTheme, children: [
1133
- /* @__PURE__ */ jsx2(RotateCcw, { size: 11 }),
1134
- " ",
1135
- chrome.reset
1136
- ] })
1137
- ] }),
1138
- /* @__PURE__ */ jsx2("label", { style: styles.propLabel, children: chrome.primaryColor }),
1139
- /* @__PURE__ */ jsxs2("div", { style: styles.swatchRow, children: [
1140
- BUTTON_COLOR_SWATCHES.slice(1).map((c) => /* @__PURE__ */ jsx2("button", { type: "button", title: c, style: { ...styles.swatchBtn, background: c, ...theme.primary === c ? styles.swatchBtnActive : {} }, onClick: () => updateThemeColor("primary", c) }, c)),
1141
- /* @__PURE__ */ jsx2("input", { type: "color", value: theme.primary, onChange: (e) => updateThemeColor("primary", e.target.value), style: styles.colorPickerInput })
1142
- ] }),
1143
- /* @__PURE__ */ jsx2("label", { style: styles.propLabel, children: chrome.pageBackground }),
1144
- /* @__PURE__ */ jsxs2("div", { style: styles.swatchRow, children: [
1145
- SECTION_BG_SWATCHES.filter(Boolean).map((c) => /* @__PURE__ */ jsx2("button", { type: "button", title: c, style: { ...styles.swatchBtn, background: c, ...theme.pageBackground === c ? styles.swatchBtnActive : {} }, onClick: () => updateThemeColor("pageBackground", c) }, c)),
1146
- /* @__PURE__ */ jsx2("input", { type: "color", value: theme.pageBackground, onChange: (e) => updateThemeColor("pageBackground", e.target.value), style: styles.colorPickerInput })
1147
- ] }),
1148
- /* @__PURE__ */ jsx2("label", { style: styles.propLabel, children: chrome.maxWidthPx }),
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/Toolbar.tsx
1161
- import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
1162
- function Toolbar({
1163
- title,
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
- return /* @__PURE__ */ jsxs3("div", { style: styles.toolbar, children: [
1185
- /* @__PURE__ */ jsxs3("div", { style: styles.toolbarLeft, children: [
1186
- /* @__PURE__ */ jsx3("div", { style: styles.logoMark, children: "FB" }),
1187
- /* @__PURE__ */ jsx3("input", { value: t(title, language), onChange: (e) => onTitleChange(e.target.value), style: styles.titleInput, "aria-label": "Form title" })
1188
- ] }),
1189
- /* @__PURE__ */ jsxs3("div", { style: styles.toolbarRight, children: [
1190
- /* @__PURE__ */ jsxs3("span", { style: styles.saveStatus, children: [
1191
- saveState === "saving" && /* @__PURE__ */ jsxs3(Fragment, { children: [
1192
- /* @__PURE__ */ jsx3(Loader2, { size: 12, className: "spin" }),
1193
- " ",
1194
- chrome.saving
1195
- ] }),
1196
- saveState === "saved" && chrome.saved,
1197
- saveState === "error" && /* @__PURE__ */ jsxs3("span", { style: { color: "var(--fb-danger)", display: "flex", alignItems: "center", gap: 4 }, children: [
1198
- /* @__PURE__ */ jsx3(AlertCircle, { size: 12 }),
1199
- " ",
1200
- chrome.saveFailed
1201
- ] })
1202
- ] }),
1203
- /* @__PURE__ */ jsx3("div", { style: styles.toolbarDivider }),
1204
- /* @__PURE__ */ jsx3(Languages, { size: 14, color: "var(--fb-muted)" }),
1205
- /* @__PURE__ */ jsx3(Segmented, { options: languages.map((l) => ({ value: l.code, label: l.label })), value: language, onChange: onLanguageChange }),
1206
- /* @__PURE__ */ jsx3("div", { style: styles.toolbarDivider }),
1207
- /* @__PURE__ */ jsxs3("button", { style: mode === "build" ? styles.tabBtnActive : styles.tabBtn, onClick: () => onModeChange("build"), children: [
1208
- /* @__PURE__ */ jsx3(Pencil, { size: 14 }),
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
- chrome.save
1369
+ /* @__PURE__ */ jsx5("strong", { children: activeSectionLabel })
1235
1370
  ] }),
1236
- /* @__PURE__ */ jsxs3("button", { style: styles.ghostBtn, onClick: onOpenJson, children: [
1237
- /* @__PURE__ */ jsx3(Code2, { size: 14 }),
1238
- " ",
1239
- chrome.viewJson
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, RotateCcw as RotateCcw2 } from "lucide-react";
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 jsx5 } from "react/jsx-runtime";
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__ */ jsx5("img", { src: field.src, alt: t(field.alt, lang || "en"), style: shapeStyle }) : /* @__PURE__ */ jsx5("div", { style: { ...shapeStyle, ...styles.imagePlaceholder }, children: /* @__PURE__ */ jsx5(ImageIcon2, { size: 20, color: "var(--fb-muted)" }) });
1397
- return field.link ? /* @__PURE__ */ jsx5("a", { href: field.link, target: "_blank", rel: "noreferrer", style: { display: "block" }, children: img }) : img;
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 jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1402
- function FieldBlock({ field, lang, onFieldChange, strings, chrome, error, isBuild }) {
1403
- if (field.type === "image") return /* @__PURE__ */ jsx6(ImageBlock, { field, lang });
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__ */ jsx6(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) || "..." });
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__ */ jsxs5("div", { children: [
1415
- /* @__PURE__ */ jsxs5("div", { style: { display: "flex", flexDirection: isInline ? "row" : "column", alignItems: isInline ? "center" : "stretch", gap: isInline ? 10 : 6 }, children: [
1416
- showLabel && /* @__PURE__ */ jsxs5("label", { style: { ...styles.previewLabel, marginBottom: isInline ? 0 : 6, flexShrink: 0, width: isInline ? 120 : "auto", display: "flex", alignItems: "center", gap: 6 }, children: [
1417
- IconComp && /* @__PURE__ */ jsx6(IconComp, { size: 14, color: "#6B6E79" }),
1418
- labelText || (isBuild ? /* @__PURE__ */ jsx6("span", { style: { fontStyle: "italic", color: "var(--fb-muted)" }, children: chrome?.untitledField || "Untitled field" }) : ""),
1419
- field.required && /* @__PURE__ */ jsx6("span", { style: { color: "var(--fb-danger)" }, children: " *" })
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__ */ jsx6("div", { style: { flex: 1, minWidth: 0 }, children: renderInteractive(field, lang, onFieldChange, IconComp, !!error, strings) })
1545
+ /* @__PURE__ */ jsx8("div", { style: { flex: 1, minWidth: 0 }, children: renderInteractive(field, lang, onFieldChange, IconComp, !!error, strings) })
1422
1546
  ] }),
1423
- error && /* @__PURE__ */ jsxs5("div", { style: styles.fieldError, children: [
1424
- /* @__PURE__ */ jsx6(CircleAlert, { size: 12 }),
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__ */ jsx6("input", { type: "number", ...common, min: field.min ?? void 0, max: field.max ?? void 0 });
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__ */ jsx6("input", { type: "email", ...common });
1564
+ return /* @__PURE__ */ jsx8("input", { type: "email", ...common });
1441
1565
  case "password":
1442
- return /* @__PURE__ */ jsx6("input", { type: "password", ...common, maxLength: field.maxLength || void 0 });
1566
+ return /* @__PURE__ */ jsx8("input", { type: "password", ...common, maxLength: field.maxLength || void 0 });
1443
1567
  case "phone":
1444
- return /* @__PURE__ */ jsx6("input", { type: "tel", ...common });
1568
+ return /* @__PURE__ */ jsx8("input", { type: "tel", ...common });
1445
1569
  case "date":
1446
- return /* @__PURE__ */ jsx6("input", { type: "date", ...common });
1570
+ return /* @__PURE__ */ jsx8("input", { type: "date", ...common });
1447
1571
  case "time":
1448
- return /* @__PURE__ */ jsx6("input", { type: "time", ...common });
1572
+ return /* @__PURE__ */ jsx8("input", { type: "time", ...common });
1449
1573
  default:
1450
- return /* @__PURE__ */ jsx6("input", { type: "text", ...common, maxLength: field.maxLength || void 0 });
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__ */ jsx6("textarea", { ...common, rows: 3, maxLength: field.maxLength || void 0 });
1579
+ return /* @__PURE__ */ jsx8("textarea", { ...common, rows: 3, maxLength: field.maxLength || void 0 });
1456
1580
  case "select":
1457
- return /* @__PURE__ */ jsxs5("select", { style: inputStyle, value: value || "", onChange: (e) => set(e.target.value), children: [
1458
- /* @__PURE__ */ jsx6("option", { value: "", children: strings.selectPlaceholder }),
1459
- (field.options || []).map((o) => /* @__PURE__ */ jsx6("option", { value: o.value, children: t(o.label, lang) }, o.value))
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__ */ jsx6("div", { style: { display: "flex", gap: 16, flexWrap: "wrap", marginTop: 4 }, children: (field.options || []).map((o) => /* @__PURE__ */ jsxs5("label", { style: styles.previewRadio, children: [
1463
- /* @__PURE__ */ jsx6("input", { type: "radio", name: field.id, value: o.value, checked: value === o.value, onChange: (e) => set(e.target.value) }),
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__ */ jsx6("div", { style: { display: "flex", gap: 16, flexWrap: "wrap", marginTop: 4 }, children: (field.options || []).map((o) => {
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__ */ jsxs5("label", { style: styles.previewRadio, children: [
1471
- /* @__PURE__ */ jsx6("input", { type: "checkbox", checked, onChange: (e) => {
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__ */ jsxs5("label", { style: styles.previewRadio, children: [
1481
- /* @__PURE__ */ jsx6("input", { type: "checkbox", checked: !!value, onChange: (e) => set(e.target.checked), style: { accentColor: "var(--fb-primary)" } }),
1482
- IconComp && /* @__PURE__ */ jsx6(IconComp, { size: 14, color: "#6B6E79" }),
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__ */ jsx6("span", { style: { color: "var(--fb-danger)" }, children: " *" })
1608
+ field.required && /* @__PURE__ */ jsx8("span", { style: { color: "var(--fb-danger)" }, children: " *" })
1485
1609
  ] });
1486
1610
  case "toggle":
1487
- return /* @__PURE__ */ jsxs5("label", { style: styles.previewRadio, children: [
1488
- /* @__PURE__ */ jsx6("input", { type: "checkbox", checked: !!value, onChange: (e) => set(e.target.checked), style: { accentColor: "var(--fb-primary)" } }),
1489
- IconComp && /* @__PURE__ */ jsx6(IconComp, { size: 14, color: "#6B6E79" }),
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__ */ jsx6("input", { type: "text", ...common });
1617
+ return /* @__PURE__ */ jsx8("input", { type: "text", ...common });
1494
1618
  }
1495
1619
  }
1496
1620
 
1497
1621
  // src/components/FieldTicket.tsx
1498
- import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
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__ */ jsxs6(
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__ */ jsx7("div", { style: styles.ticketIndex, children: String(idx + 1).padStart(2, "0") }),
1533
- /* @__PURE__ */ jsx7("div", { style: styles.ticketPerforation }),
1534
- /* @__PURE__ */ jsxs6("div", { style: styles.ticketBody, children: [
1535
- /* @__PURE__ */ jsxs6("div", { style: styles.ticketTop, children: [
1536
- /* @__PURE__ */ jsx7("span", { ...dragHandleProps, style: { cursor: "grab", display: "flex" }, children: /* @__PURE__ */ jsx7(GripVertical, { size: 14, color: "#C4C6D0" }) }),
1537
- /* @__PURE__ */ jsx7(Icon, { size: 13, color: "var(--fb-primary)" }),
1538
- /* @__PURE__ */ jsxs6("span", { style: styles.typeBadge, children: [
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__ */ jsx7("span", { style: styles.requiredBadge, children: chrome.required })
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__ */ jsxs6("div", { style: styles.chipRow, children: [
1545
- field.width && field.width !== "1/1" && /* @__PURE__ */ jsxs6("span", { style: styles.miniBadge, children: [
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__ */ jsx7("span", { style: styles.miniBadge, children: chrome.inline }),
1551
- field.verticalAlign !== "top" && /* @__PURE__ */ jsx7("span", { style: styles.miniBadge, children: chrome[field.verticalAlign] }),
1552
- field.hideLabel && /* @__PURE__ */ jsx7("span", { style: styles.miniBadge, children: chrome.hideLabel })
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__ */ jsx7("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx7(FieldBlock, { field, lang: language, onFieldChange, strings, chrome, isBuild: true }) })
1678
+ /* @__PURE__ */ jsx9("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx9(FieldBlock, { field, lang: language, onFieldChange, strings, chrome, isBuild: true }) })
1555
1679
  ] }),
1556
- /* @__PURE__ */ jsxs6("div", { style: styles.ticketActions, onClick: (e) => e.stopPropagation(), children: [
1557
- /* @__PURE__ */ jsx7("button", { style: styles.iconBtn, title: chrome.moveUp, onClick: () => onMoveField(field.id, -1), children: /* @__PURE__ */ jsx7(ArrowUp, { size: 13 }) }),
1558
- /* @__PURE__ */ jsx7("button", { style: styles.iconBtn, title: chrome.moveDown, onClick: () => onMoveField(field.id, 1), children: /* @__PURE__ */ jsx7(ArrowDown, { size: 13 }) }),
1559
- /* @__PURE__ */ jsx7("button", { style: styles.iconBtn, title: chrome.duplicate, onClick: () => onDuplicateField(field.id), children: /* @__PURE__ */ jsx7(Copy, { size: 13 }) }),
1560
- /* @__PURE__ */ jsx7("button", { style: { ...styles.iconBtn, ...styles.iconBtnDanger }, title: chrome.delete, onClick: () => onDeleteField(field.id), children: /* @__PURE__ */ jsx7(Trash2, { size: 13 }) })
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 jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
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__ */ jsxs7(
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__ */ jsxs7("div", { style: styles.sectionHeader, children: [
1605
- /* @__PURE__ */ jsx8("button", { style: styles.chevronBtn, onClick: (e) => {
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__ */ jsx8(ChevronRight, { size: 15 }) : /* @__PURE__ */ jsx8(ChevronDown3, { size: 15 }) }),
1609
- /* @__PURE__ */ jsx8("span", { style: { ...styles.colorDot, background: section.background || "var(--fb-canvas)" } }),
1610
- /* @__PURE__ */ jsx8(
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__ */ jsx8("span", { style: styles.miniBadge, children: chrome.fieldsCount(section.fields.length) }),
1621
- /* @__PURE__ */ jsxs7("div", { style: styles.sectionHeaderActions, onClick: (e) => e.stopPropagation(), children: [
1622
- !section.collapsed && /* @__PURE__ */ jsxs7("div", { style: styles.swatchRow, children: [
1623
- SECTION_BG_SWATCHES.map((c) => /* @__PURE__ */ jsx8("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")),
1624
- /* @__PURE__ */ jsx8("input", { type: "color", title: chrome.customColor, value: /^#/.test(section.background) ? section.background : "#ffffff", onChange: (e) => onUpdateBackground(e.target.value), style: styles.colorPickerInput })
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__ */ jsx8("button", { style: styles.iconBtn, title: chrome.duplicate, onClick: onDuplicateSection, children: /* @__PURE__ */ jsx8(Copy2, { size: 13 }) }),
1627
- /* @__PURE__ */ jsx8("button", { style: styles.iconBtn, title: chrome.moveUp, disabled: sIdx === 0, onClick: () => onMoveSection(-1), children: /* @__PURE__ */ jsx8(ArrowUp2, { size: 13 }) }),
1628
- /* @__PURE__ */ jsx8("button", { style: styles.iconBtn, title: chrome.moveDown, disabled: sIdx === sectionsLength - 1, onClick: () => onMoveSection(1), children: /* @__PURE__ */ jsx8(ArrowDown2, { size: 13 }) }),
1629
- /* @__PURE__ */ jsx8("button", { style: { ...styles.iconBtn, ...styles.iconBtnDanger }, title: chrome.deleteSection, disabled: sectionsLength <= 1, onClick: onDeleteSection, children: /* @__PURE__ */ jsx8(Trash22, { size: 13 }) })
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 && submitMode === "perSection" && /* @__PURE__ */ jsxs7("div", { style: styles.submitStyleRow, onClick: (e) => e.stopPropagation(), children: [
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 jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
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__ */ jsxs8("div", { style: styles.canvas, children: [
1699
- sections.map((section, sIdx) => /* @__PURE__ */ jsx9(
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__ */ jsxs8("button", { style: styles.addSectionBtn, onClick: onAddSection, children: [
1733
- /* @__PURE__ */ jsx9(Layers, { size: 14 }),
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 Fragment2, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
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__ */ jsxs9(Fragment2, { children: [
1750
- /* @__PURE__ */ jsx10("label", { style: styles.propLabel, children: chrome.defaultValue }),
1751
- /* @__PURE__ */ jsxs9("button", { style: styles.toggleRow, onClick: () => onChange({ defaultValue: !f.defaultValue }), children: [
1752
- /* @__PURE__ */ jsx10("span", { style: { ...styles.toggleTrack, background: f.defaultValue ? "var(--fb-primary)" : "var(--fb-border)" }, children: /* @__PURE__ */ jsx10("span", { style: { ...styles.toggleThumb, transform: f.defaultValue ? "translateX(16px)" : "translateX(0)" } }) }),
1753
- /* @__PURE__ */ jsx10("span", { style: { fontSize: 13, color: "#4A4D57" }, children: f.defaultValue ? chrome.checked : chrome.unchecked })
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__ */ jsxs9(Fragment2, { children: [
1760
- /* @__PURE__ */ jsx10("label", { style: styles.propLabel, children: chrome.defaultChecked }),
1761
- /* @__PURE__ */ jsx10("div", { style: styles.optionList, children: (f.options || []).map((o) => {
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__ */ jsxs9("label", { style: { ...styles.previewRadio, cursor: "pointer" }, children: [
1764
- /* @__PURE__ */ jsx10("input", { type: "checkbox", checked, onChange: (e) => {
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__ */ jsxs9(Fragment2, { children: [
1775
- /* @__PURE__ */ jsx10("label", { style: styles.propLabel, children: chrome.defaultValue }),
1776
- /* @__PURE__ */ jsxs9("select", { style: styles.propInput, value: f.defaultValue || "", onChange: (e) => onChange({ defaultValue: e.target.value }), children: [
1777
- /* @__PURE__ */ jsx10("option", { value: "", children: chrome.none }),
1778
- (f.options || []).map((o) => /* @__PURE__ */ jsx10("option", { value: o.value, children: t(o.label, lang) }, o.value))
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__ */ jsxs9(Fragment2, { children: [
1784
- /* @__PURE__ */ jsx10("label", { style: styles.propLabel, children: chrome.defaultValue }),
1785
- /* @__PURE__ */ jsx10("input", { type: htmlType, style: styles.propInput, value: f.defaultValue || "", onChange: (e) => onChange({ defaultValue: e.target.value }) })
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 Fragment3, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
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__ */ jsxs10("div", { style: styles.inspector, children: [
1793
- /* @__PURE__ */ jsx11("div", { style: styles.panelHeading, children: chrome.properties }),
1794
- !selected ? /* @__PURE__ */ jsx11("div", { style: styles.inspectorEmpty, children: chrome.selectFieldHint }) : /* @__PURE__ */ jsx11(
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__ */ jsxs10("div", { style: styles.inspectorBody, children: [
1813
- !meta.isContent && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1814
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.label }),
1815
- /* @__PURE__ */ jsx11("input", { style: styles.propInput, value: t(selected.label, language), onChange: (e) => onUpdateField({ label: withLang(selected.label, language, e.target.value) }) }),
1816
- /* @__PURE__ */ jsxs10("label", { style: styles.toggleRow, children: [
1817
- /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: !!selected.hideLabel, onChange: (e) => onUpdateField({ hideLabel: e.target.checked }), style: { width: 15, height: 15, accentColor: "var(--fb-primary)" } }),
1818
- /* @__PURE__ */ jsx11("span", { style: { fontSize: 13, color: "#4A4D57" }, children: chrome.hideLabel })
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__ */ jsxs10(Fragment3, { children: [
1822
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.inputType }),
1823
- /* @__PURE__ */ jsx11("select", { style: styles.propInput, value: f.inputType || "text", onChange: (e) => onUpdateField({ inputType: e.target.value }), children: INPUT_SUBTYPES.map((s) => /* @__PURE__ */ jsx11("option", { value: s, children: chrome[INPUT_SUBTYPE_CHROME_KEY[s]] }, s)) })
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__ */ jsxs10(Fragment3, { children: [
1826
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.content }),
1827
- /* @__PURE__ */ jsx11("textarea", { style: { ...styles.propInput, minHeight: 70, resize: "vertical" }, value: t(selected.content, language), onChange: (e) => onUpdateField({ content: withLang(selected.content, language, e.target.value) }) }),
1828
- /* @__PURE__ */ jsx11("div", { style: styles.inspectorDivider }),
1829
- /* @__PURE__ */ jsx11("div", { style: styles.panelHeading, children: chrome.typography }),
1830
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.headingStyle }),
1831
- /* @__PURE__ */ jsx11(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] }) }),
1832
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.width }),
1833
- /* @__PURE__ */ jsx11(Segmented, { options: FONT_SIZE_OPTIONS, value: selected.fontSize || "md", onChange: (v) => onUpdateField({ fontSize: v }) }),
1834
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.style }),
1835
- /* @__PURE__ */ jsxs10("div", { style: styles.styleToggleRow, children: [
1836
- /* @__PURE__ */ jsx11("button", { type: "button", style: selected.fontWeight === "bold" ? styles.styleToggleActive : styles.styleToggle, onClick: () => onUpdateField({ fontWeight: selected.fontWeight === "bold" ? "normal" : "bold" }), children: /* @__PURE__ */ jsx11(Bold, { size: 14 }) }),
1837
- /* @__PURE__ */ jsx11("button", { type: "button", style: selected.fontStyle === "italic" ? styles.styleToggleActive : styles.styleToggle, onClick: () => onUpdateField({ fontStyle: selected.fontStyle === "italic" ? "normal" : "italic" }), children: /* @__PURE__ */ jsx11(Italic, { size: 14 }) })
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__ */ jsx11("label", { style: styles.propLabel, children: chrome.align }),
1840
- /* @__PURE__ */ jsx11(Segmented, { options: TEXT_ALIGN_OPTIONS, value: selected.textAlign || "left", onChange: (v) => onUpdateField({ textAlign: v }) }),
1841
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.color }),
1842
- /* @__PURE__ */ jsxs10("div", { style: styles.swatchRow, children: [
1843
- COLOR_SWATCHES.map((c) => /* @__PURE__ */ jsx11("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")),
1844
- /* @__PURE__ */ jsx11("input", { type: "color", value: selected.color || "#1B1E24", onChange: (e) => onUpdateField({ color: e.target.value }), style: styles.colorPickerInput })
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__ */ jsxs10(Fragment3, { children: [
1848
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.imageUrl }),
1849
- /* @__PURE__ */ jsx11("input", { style: styles.propInput, placeholder: "https://...", value: selected.src || "", onChange: (e) => onUpdateField({ src: e.target.value }) }),
1850
- /* @__PURE__ */ jsx11("p", { style: styles.helperText, children: chrome.imageUrlHelper }),
1851
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.altText }),
1852
- /* @__PURE__ */ jsx11("input", { style: styles.propInput, value: t(selected.alt, language), onChange: (e) => onUpdateField({ alt: withLang(selected.alt, language, e.target.value) }) }),
1853
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.linkOptional }),
1854
- /* @__PURE__ */ jsx11("input", { style: styles.propInput, placeholder: "https://...", value: selected.link || "", onChange: (e) => onUpdateField({ link: e.target.value }) }),
1855
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.shape }),
1856
- /* @__PURE__ */ jsx11(Segmented, { options: IMAGE_SHAPES.map((v) => ({ value: v, label: chrome[IMAGE_SHAPE_CHROME_KEY[v]] })), value: selected.shape || "square", onChange: (v) => onUpdateField({ shape: v }) }),
1857
- /* @__PURE__ */ jsx11("p", { style: styles.helperText, children: "Fills the field's own width (set below under Layout) and scales height automatically \u2014 always responsive, never overflows." })
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
- meta.placeholder && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1860
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.placeholder }),
1861
- /* @__PURE__ */ jsx11("input", { style: styles.propInput, value: t(f.placeholder, language), onChange: (e) => onUpdateField({ placeholder: withLang(f.placeholder, language, e.target.value) }) })
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
- selected.type === "input" && (selected.inputType === "text" || selected.inputType === "password" || !selected.inputType) && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1864
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.maxLength }),
1865
- /* @__PURE__ */ jsx11("input", { type: "number", style: styles.propInput, placeholder: chrome.noLimit, value: selected.maxLength || "", onChange: (e) => onUpdateField({ maxLength: e.target.value ? Number(e.target.value) : null }) })
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 === "number" && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1868
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.minValue }),
1869
- /* @__PURE__ */ jsx11("input", { type: "number", style: styles.propInput, value: selected.min ?? "", onChange: (e) => onUpdateField({ min: e.target.value === "" ? null : Number(e.target.value) }) }),
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 === "textarea" && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1874
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.maxLength }),
1875
- /* @__PURE__ */ jsx11("input", { type: "number", style: styles.propInput, placeholder: chrome.noLimit, value: selected.maxLength || "", onChange: (e) => onUpdateField({ maxLength: e.target.value ? Number(e.target.value) : null }) })
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
- meta.options && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1878
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.options }),
1879
- /* @__PURE__ */ jsxs10("div", { style: styles.optionList, children: [
1880
- (f.options || []).map((opt, i) => /* @__PURE__ */ jsxs10("div", { style: styles.optionRow, children: [
1881
- /* @__PURE__ */ jsx11("input", { style: styles.optionInput, value: t(opt.label, language), onChange: (e) => onUpdateOption(i, { label: withLang(opt.label, language, e.target.value) }) }),
1882
- /* @__PURE__ */ jsx11("button", { style: styles.iconBtn, onClick: () => onRemoveOption(i), disabled: (f.options || []).length <= 1, children: /* @__PURE__ */ jsx11(X, { size: 13 }) })
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__ */ jsxs10("button", { style: styles.addOptionBtn, onClick: onAddOption, children: [
1885
- /* @__PURE__ */ jsx11(Plus2, { size: 13 }),
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__ */ jsx11(DefaultValueEditor, { field: selected, meta, lang: language, chrome, onChange: onUpdateField }),
1892
- !meta.isContent && /* @__PURE__ */ jsxs10("label", { style: styles.toggleRow, children: [
1893
- /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: !!selected.required, onChange: (e) => onUpdateField({ required: e.target.checked }), style: { width: 15, height: 15, accentColor: "var(--fb-primary)" } }),
1894
- /* @__PURE__ */ jsx11("span", { style: { fontSize: 13, color: "#4A4D57" }, children: chrome.requiredField })
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__ */ jsx11("div", { style: styles.inspectorDivider }),
1897
- /* @__PURE__ */ jsx11("div", { style: styles.panelHeading, children: chrome.layout }),
1898
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.width }),
1899
- /* @__PURE__ */ jsx11(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 }) }),
1900
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.verticalAlign }),
1901
- /* @__PURE__ */ jsx11(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 }) }),
1902
- !meta.boolean && !meta.isContent && /* @__PURE__ */ jsxs10(Fragment3, { children: [
1903
- /* @__PURE__ */ jsx11("label", { style: styles.propLabel, children: chrome.labelPosition }),
1904
- /* @__PURE__ */ jsx11(Segmented, { options: [{ value: "top", label: chrome.above }, { value: "inline", label: chrome.inline }], value: selected.labelPosition || "top", onChange: (v) => onUpdateField({ labelPosition: v }) })
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__ */ jsxs10(Fragment3, { children: [
1907
- /* @__PURE__ */ jsx11("div", { style: styles.inspectorDivider }),
1908
- /* @__PURE__ */ jsx11("div", { style: styles.panelHeading, children: chrome.icon }),
1909
- /* @__PURE__ */ jsxs10("label", { style: styles.toggleRow, children: [
1910
- /* @__PURE__ */ jsx11("input", { type: "checkbox", checked: !!selected.showIcon, onChange: (e) => onUpdateField({ showIcon: e.target.checked }), style: { width: 15, height: 15, accentColor: "var(--fb-primary)" } }),
1911
- /* @__PURE__ */ jsx11("span", { style: { fontSize: 13, color: "#4A4D57" }, children: chrome.showIcon })
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__ */ jsx11("div", { style: styles.iconGrid, children: Object.keys(ICON_LIBRARY).map((key) => {
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__ */ jsx11("button", { type: "button", title: key, style: active ? styles.iconGridBtnActive : styles.iconGridBtn, onClick: () => onUpdateField({ displayIcon: key }), children: /* @__PURE__ */ jsx11(IconComp, { size: 15 }) }, key);
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__ */ jsx11("div", { style: styles.inspectorDivider }),
1920
- /* @__PURE__ */ jsxs10("button", { style: styles.deleteFieldBtn, onClick: onDeleteField, children: [
1921
- /* @__PURE__ */ jsx11(Trash23, { size: 13 }),
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 { Fragment as Fragment4, jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
1967
- function PreviewPane({ title, sections, onFieldChange, language, strings, chrome, baseMaxWidth, submitLabel, submitMode, submitStyle }) {
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 handleSubmitAll() {
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__ */ jsxs11("div", { style: styles.previewWrap, children: [
2007
- /* @__PURE__ */ jsxs11("div", { style: { width: "100%", maxWidth, display: "flex", flexDirection: "column", alignItems: "center" }, children: [
2008
- /* @__PURE__ */ jsx12("div", { style: styles.previewToolbar, children: /* @__PURE__ */ jsx12(Segmented, { options: deviceOptions, value: device, onChange: setDevice }) }),
2009
- /* @__PURE__ */ jsxs11("div", { style: { ...styles.previewCard, maxWidth, width: "100%" }, children: [
2010
- /* @__PURE__ */ jsx12("h2", { style: styles.previewTitle, children: t(title, language) }),
2011
- allFields.length === 0 && /* @__PURE__ */ jsx12("p", { style: { color: "var(--fb-muted)", fontSize: 14 }, children: strings.addFieldsHint }),
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
- const sectionHasFormFields = section.fields.some((f) => !getMeta(f.type).isContent);
2014
- const sectionHasErrors = section.fields.some((f) => errors[f.id]);
2015
- return /* @__PURE__ */ jsxs11("div", { style: { background: section.background || "transparent", padding: section.background ? 16 : 0, borderRadius: section.background ? 10 : 0, marginBottom: "var(--fb-space-section)" }, children: [
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__ */ jsx12("div", { style: { flex: flexBasis, minWidth: 0, alignSelf: ALIGN_MAP[field.verticalAlign || "top"] }, children: /* @__PURE__ */ jsx12(FieldBlock, { field, lang: language, onFieldChange, strings, chrome, error: errors[field.id] }) }, field.id);
2021
- }) }),
2022
- submitMode === "perSection" && sectionHasFormFields && /* @__PURE__ */ jsxs11(Fragment4, { children: [
2023
- /* @__PURE__ */ jsx12("button", { style: { ...styles.submitBtn, ...resolveSubmitStyle(section.submitStyle || submitStyle) }, onClick: () => handleSubmitSection(section), children: submitText }),
2024
- sectionHasErrors && /* @__PURE__ */ jsxs11("p", { style: styles.formErrorNote, children: [
2025
- /* @__PURE__ */ jsx12(CircleAlert2, { size: 13 }),
2026
- " ",
2027
- strings.fixErrors
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__ */ jsx12("div", { style: styles.modalOverlay, onClick: () => setSubmitted(null), children: /* @__PURE__ */ jsxs11("div", { style: { ...styles.modal, width: 420 }, onClick: (e) => e.stopPropagation(), children: [
2041
- /* @__PURE__ */ jsxs11("div", { style: styles.modalHeader, children: [
2042
- /* @__PURE__ */ jsxs11("span", { style: { fontWeight: 600, fontSize: 14, display: "flex", alignItems: "center", gap: 7 }, children: [
2043
- /* @__PURE__ */ jsx12(PartyPopper, { size: 15, color: "var(--fb-primary)" }),
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__ */ jsx12("button", { style: styles.iconBtn, onClick: () => setSubmitted(null), children: /* @__PURE__ */ jsx12(X2, { size: 16 }) })
2194
+ /* @__PURE__ */ jsx14("button", { style: styles.iconBtn, onClick: () => setSubmitted(null), children: /* @__PURE__ */ jsx14(X2, { size: 16 }) })
2048
2195
  ] }),
2049
- /* @__PURE__ */ jsxs11("div", { style: { padding: 16 }, children: [
2050
- /* @__PURE__ */ jsx12("p", { style: { fontSize: 12.5, color: "var(--fb-muted)", marginTop: 0 }, children: strings.submittedBody }),
2051
- /* @__PURE__ */ jsx12("div", { style: styles.submittedList, children: submitted.map((row, i) => /* @__PURE__ */ jsxs11("div", { style: styles.submittedRow, children: [
2052
- /* @__PURE__ */ jsx12("span", { style: styles.submittedLabel, children: row.label }),
2053
- /* @__PURE__ */ jsx12("span", { style: styles.submittedValue, children: row.value })
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__ */ jsx12("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, onClick: () => setSubmitted(null), children: strings.close })
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 jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2210
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2064
2211
  function JsonModal({ chrome, jsonString, copied, onCopy, onClose }) {
2065
- return /* @__PURE__ */ jsx13("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs12("div", { style: styles.modal, onClick: (e) => e.stopPropagation(), children: [
2066
- /* @__PURE__ */ jsxs12("div", { style: styles.modalHeader, children: [
2067
- /* @__PURE__ */ jsx13("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.formJson }),
2068
- /* @__PURE__ */ jsxs12("div", { style: { display: "flex", gap: 8 }, children: [
2069
- /* @__PURE__ */ jsxs12("button", { style: styles.ghostBtn, onClick: onCopy, children: [
2070
- copied ? /* @__PURE__ */ jsx13(Check, { size: 14 }) : /* @__PURE__ */ jsx13(ClipboardCopy, { size: 14 }),
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__ */ jsx13("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx13(X3, { size: 16 }) })
2220
+ /* @__PURE__ */ jsx15("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx15(X3, { size: 16 }) })
2074
2221
  ] })
2075
2222
  ] }),
2076
- /* @__PURE__ */ jsx13("pre", { style: styles.jsonPre, children: jsonString })
2223
+ /* @__PURE__ */ jsx15("pre", { style: styles.jsonPre, children: jsonString })
2077
2224
  ] }) });
2078
2225
  }
2079
2226
 
2080
- // src/components/modals/LibraryModal.tsx
2227
+ // src/components/modals/TemplatesModal.tsx
2081
2228
  import { Trash2 as Trash24, X as X4 } from "lucide-react";
2082
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
2083
- function LibraryModal({ chrome, savedForms, currentFormId, onOpen, onDelete, onClose }) {
2084
- return /* @__PURE__ */ jsx14("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs13("div", { style: styles.modal, onClick: (e) => e.stopPropagation(), children: [
2085
- /* @__PURE__ */ jsxs13("div", { style: styles.modalHeader, children: [
2086
- /* @__PURE__ */ jsx14("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.myForms }),
2087
- /* @__PURE__ */ jsx14("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx14(X4, { size: 16 }) })
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__ */ jsx14("div", { style: styles.libraryBody, children: savedForms.length === 0 ? /* @__PURE__ */ jsx14("div", { style: styles.inspectorEmpty, children: chrome.nothingSaved }) : savedForms.map((f) => /* @__PURE__ */ jsxs13("div", { style: styles.libraryRow, children: [
2090
- /* @__PURE__ */ jsxs13("div", { style: { minWidth: 0 }, children: [
2091
- /* @__PURE__ */ jsxs13("div", { style: styles.libraryRowTitle, children: [
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__ */ jsx14("span", { style: styles.currentBadge, children: chrome.current })
2240
+ f.id === currentFormId && /* @__PURE__ */ jsx16("span", { style: styles.currentBadge, children: chrome.current })
2094
2241
  ] }),
2095
- /* @__PURE__ */ jsxs13("div", { style: styles.libraryRowMeta, children: [
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__ */ jsxs13("div", { style: { display: "flex", gap: 6, flexShrink: 0 }, children: [
2102
- /* @__PURE__ */ jsx14("button", { style: styles.ghostBtn, onClick: () => onOpen(f.id), children: chrome.open }),
2103
- /* @__PURE__ */ jsx14("button", { style: { ...styles.iconBtn, ...styles.iconBtnDanger }, title: chrome.delete, onClick: () => onDelete(f.id), children: /* @__PURE__ */ jsx14(Trash24, { size: 13 }) })
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 jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
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__ */ jsx15("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ jsxs14("div", { style: { ...styles.modal, width: 380 }, onClick: (e) => e.stopPropagation(), children: [
2116
- /* @__PURE__ */ jsxs14("div", { style: styles.modalHeader, children: [
2117
- /* @__PURE__ */ jsx15("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.saveForm }),
2118
- /* @__PURE__ */ jsx15("button", { style: styles.iconBtn, onClick: onClose, children: /* @__PURE__ */ jsx15(X5, { size: 16 }) })
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__ */ jsxs14("div", { style: { padding: 16 }, children: [
2121
- /* @__PURE__ */ jsx15("label", { style: styles.propLabel, children: chrome.formName }),
2122
- /* @__PURE__ */ jsx15("input", { autoFocus: true, style: styles.propInput, value: name, onChange: (e) => setName(e.target.value), onKeyDown: (e) => e.key === "Enter" && name.trim() && onSave(name.trim()) }),
2123
- /* @__PURE__ */ jsxs14("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, disabled: !name.trim(), onClick: () => onSave(name.trim()), children: [
2124
- /* @__PURE__ */ jsx15(Save2, { size: 14 }),
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 jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
2182
- function FormBuilder({
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
- document: {
2207
- title: doc.title,
2208
- submitLabel: doc.submitLabel,
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: 4,
2334
+ version: 5,
2225
2335
  title: doc.title,
2226
- submitLabel: doc.submitLabel,
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, submitStyle: s.submitStyle, fields: s.fields }))
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__ */ jsx17("style", { children: css }),
2264
- /* @__PURE__ */ jsx17(
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__ */ jsx17(Loader22, { size: 20, className: "spin" }),
2291
- /* @__PURE__ */ jsx17("span", { style: { marginTop: 8, fontSize: 13, color: "var(--fb-muted)" }, children: chrome.loadingDraft })
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__ */ jsx17(Palette, { activeSectionLabel, chrome, onAddField: doc.addField }),
2294
- /* @__PURE__ */ jsx17(
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__ */ jsx17(
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__ */ jsx17(
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
- submitLabel: doc.submitLabel,
2352
- submitMode: doc.submitMode,
2353
- submitStyle: doc.submitStyle
2472
+ onSubmit
2354
2473
  }
2355
2474
  ),
2356
- showJson && /* @__PURE__ */ jsx17(JsonModal, { chrome, jsonString, copied, onCopy: copyJson, onClose: () => setShowJson(false) }),
2357
- showLibrary && /* @__PURE__ */ jsx17(
2358
- LibraryModal,
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__ */ jsx17(
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
- FormBuilder as default,
2503
+ FormBuilder_default as FormBuilder,
2504
+ FormBuilder_default as default,
2400
2505
  localStorageAdapter
2401
2506
  };
2402
2507
  //# sourceMappingURL=index.js.map