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