form-page-builder 0.1.0 → 2.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,17 @@ 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
+ DARK_THEME: () => DARK_THEME,
25
+ DEFAULT_THEME: () => DEFAULT_THEME,
26
+ FormBuilder: () => FormBuilder_default,
27
+ default: () => FormBuilder_default,
26
28
  localStorageAdapter: () => localStorageAdapter
27
29
  });
28
30
  module.exports = __toCommonJS(index_exports);
29
31
 
30
32
  // src/FormBuilder.tsx
31
33
  var import_react8 = require("react");
32
- var import_lucide_react19 = require("lucide-react");
34
+ var import_lucide_react18 = require("lucide-react");
33
35
 
34
36
  // src/i18n/languages.ts
35
37
  var DEFAULT_LANGUAGES = [
@@ -77,6 +79,8 @@ var CHROME = {
77
79
  contentBlocks: "Content",
78
80
  formFields: "Form Fields",
79
81
  addingTo: "Adding to",
82
+ paletteTabBlocks: "Blocks",
83
+ paletteTabDesign: "Design",
80
84
  properties: "Properties",
81
85
  selectFieldHint: "Select a field to edit its properties.",
82
86
  label: "Label",
@@ -122,15 +126,15 @@ var CHROME = {
122
126
  build: "Build",
123
127
  preview: "Preview",
124
128
  newForm: "New",
125
- myForms: "My forms",
129
+ templates: "Templates",
126
130
  save: "Save",
127
131
  viewJson: "View JSON",
128
132
  saving: "Saving...",
129
133
  saved: "Saved",
130
134
  saveFailed: "Save failed",
131
135
  startNewForm: "Start a new form",
132
- openSavedForm: "Open a saved form",
133
- saveToLibraryTitle: "Save this form to your library",
136
+ openTemplatesTitle: "Open a saved template",
137
+ saveToLibraryTitle: "Save this form as a template",
134
138
  sectionTitlePlaceholder: (n) => `Section ${n} title (optional)`,
135
139
  noFieldsInSection: "No fields in this section yet \u2014 pick a field type on the left.",
136
140
  addSection: "Add section",
@@ -143,22 +147,17 @@ var CHROME = {
143
147
  formJson: "Form JSON",
144
148
  copy: "Copy",
145
149
  copied: "Copied",
146
- nothingSaved: 'Nothing saved yet. Click "Save" in the toolbar to store this form here.',
150
+ noTemplates: 'No templates saved yet. Click "Save" in the toolbar to store this form here.',
147
151
  updated: "Updated",
148
152
  open: "Open",
149
- saveForm: "Save form",
150
- formName: "Form name",
151
- saveToLibrary: "Save to library",
153
+ saveForm: "Save as template",
154
+ formName: "Template name",
155
+ saveToLibrary: "Save template",
152
156
  loadingDraft: "Loading your draft...",
157
+ templatesLimitReached: "You can save up to 5 templates. Delete one to save another.",
153
158
  current: "current",
154
159
  customColor: "Custom color",
155
160
  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
161
  fieldTypeInput: "Input",
163
162
  fieldTypeTextarea: "Textarea",
164
163
  fieldTypeSelect: "Select",
@@ -168,6 +167,7 @@ var CHROME = {
168
167
  fieldTypeToggle: "Toggle",
169
168
  fieldTypeParagraph: "Paragraph",
170
169
  fieldTypeImage: "Image",
170
+ fieldTypeButton: "Button",
171
171
  subtypeText: "Text",
172
172
  subtypeEmail: "Email",
173
173
  subtypePhone: "Phone",
@@ -180,8 +180,17 @@ var CHROME = {
180
180
  shapeBanner: "Banner",
181
181
  tagBody: "Body",
182
182
  tagCaption: "Caption",
183
- submitSectionTitle: "Submit",
184
- submitStyle: "Submit button style",
183
+ buttonText: "Button text",
184
+ buttonActionTitle: "Action",
185
+ buttonAction: "When clicked",
186
+ actionLink: "Open link",
187
+ actionSubmit: "Submit",
188
+ openIn: "Open in",
189
+ sameTab: "Same tab",
190
+ newTab: "New tab",
191
+ submitScope: "Submits",
192
+ thisSection: "This section",
193
+ wholeForm: "Whole form",
185
194
  buttonSize: "Size",
186
195
  theme: "Theme",
187
196
  primaryColor: "Primary color",
@@ -206,6 +215,8 @@ var CHROME = {
206
215
  contentBlocks: "\u30B3\u30F3\u30C6\u30F3\u30C4",
207
216
  formFields: "\u30D5\u30A9\u30FC\u30E0\u9805\u76EE",
208
217
  addingTo: "\u8FFD\u52A0\u5148",
218
+ paletteTabBlocks: "\u30D6\u30ED\u30C3\u30AF",
219
+ paletteTabDesign: "\u30C7\u30B6\u30A4\u30F3",
209
220
  properties: "\u30D7\u30ED\u30D1\u30C6\u30A3",
210
221
  selectFieldHint: "\u7DE8\u96C6\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u3092\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
211
222
  label: "\u30E9\u30D9\u30EB",
@@ -251,15 +262,15 @@ var CHROME = {
251
262
  build: "\u4F5C\u6210",
252
263
  preview: "\u30D7\u30EC\u30D3\u30E5\u30FC",
253
264
  newForm: "\u65B0\u898F",
254
- myForms: "\u30DE\u30A4\u30D5\u30A9\u30FC\u30E0",
265
+ templates: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8",
255
266
  save: "\u4FDD\u5B58",
256
267
  viewJson: "JSON\u3092\u8868\u793A",
257
268
  saving: "\u4FDD\u5B58\u4E2D...",
258
269
  saved: "\u4FDD\u5B58\u6E08\u307F",
259
270
  saveFailed: "\u4FDD\u5B58\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
260
271
  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",
272
+ openTemplatesTitle: "\u4FDD\u5B58\u6E08\u307F\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u958B\u304F",
273
+ saveToLibraryTitle: "\u3053\u306E\u30D5\u30A9\u30FC\u30E0\u3092\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3068\u3057\u3066\u4FDD\u5B58",
263
274
  sectionTitlePlaceholder: (n) => `\u30BB\u30AF\u30B7\u30E7\u30F3${n}\u306E\u30BF\u30A4\u30C8\u30EB\uFF08\u4EFB\u610F\uFF09`,
264
275
  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
276
  addSection: "\u30BB\u30AF\u30B7\u30E7\u30F3\u3092\u8FFD\u52A0",
@@ -272,22 +283,17 @@ var CHROME = {
272
283
  formJson: "\u30D5\u30A9\u30FC\u30E0JSON",
273
284
  copy: "\u30B3\u30D4\u30FC",
274
285
  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",
286
+ 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
287
  updated: "\u66F4\u65B0\u65E5\u6642",
277
288
  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",
289
+ saveForm: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3068\u3057\u3066\u4FDD\u5B58",
290
+ formName: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u540D",
291
+ saveToLibrary: "\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u3092\u4FDD\u5B58",
281
292
  loadingDraft: "\u4E0B\u66F8\u304D\u3092\u8AAD\u307F\u8FBC\u3093\u3067\u3044\u307E\u3059...",
293
+ 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
294
  current: "\u73FE\u5728\u7DE8\u96C6\u4E2D",
283
295
  customColor: "\u30AB\u30B9\u30BF\u30E0\u30AB\u30E9\u30FC",
284
296
  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
297
  fieldTypeInput: "\u5165\u529B",
292
298
  fieldTypeTextarea: "\u30C6\u30AD\u30B9\u30C8\u30A8\u30EA\u30A2",
293
299
  fieldTypeSelect: "\u30BB\u30EC\u30AF\u30C8",
@@ -297,6 +303,7 @@ var CHROME = {
297
303
  fieldTypeToggle: "\u30C8\u30B0\u30EB",
298
304
  fieldTypeParagraph: "\u6BB5\u843D",
299
305
  fieldTypeImage: "\u753B\u50CF",
306
+ fieldTypeButton: "\u30DC\u30BF\u30F3",
300
307
  subtypeText: "\u30C6\u30AD\u30B9\u30C8",
301
308
  subtypeEmail: "\u30E1\u30FC\u30EB",
302
309
  subtypePhone: "\u96FB\u8A71\u756A\u53F7",
@@ -309,8 +316,17 @@ var CHROME = {
309
316
  shapeBanner: "\u30D0\u30CA\u30FC",
310
317
  tagBody: "\u672C\u6587",
311
318
  tagCaption: "\u30AD\u30E3\u30D7\u30B7\u30E7\u30F3",
312
- submitSectionTitle: "\u9001\u4FE1",
313
- submitStyle: "\u9001\u4FE1\u30DC\u30BF\u30F3\u306E\u30B9\u30BF\u30A4\u30EB",
319
+ buttonText: "\u30DC\u30BF\u30F3\u306E\u30C6\u30AD\u30B9\u30C8",
320
+ buttonActionTitle: "\u30A2\u30AF\u30B7\u30E7\u30F3",
321
+ buttonAction: "\u30AF\u30EA\u30C3\u30AF\u6642\u306E\u52D5\u4F5C",
322
+ actionLink: "\u30EA\u30F3\u30AF\u3092\u958B\u304F",
323
+ actionSubmit: "\u9001\u4FE1",
324
+ openIn: "\u958B\u304D\u65B9",
325
+ sameTab: "\u540C\u3058\u30BF\u30D6",
326
+ newTab: "\u65B0\u3057\u3044\u30BF\u30D6",
327
+ submitScope: "\u9001\u4FE1\u7BC4\u56F2",
328
+ thisSection: "\u3053\u306E\u30BB\u30AF\u30B7\u30E7\u30F3",
329
+ wholeForm: "\u30D5\u30A9\u30FC\u30E0\u5168\u4F53",
314
330
  buttonSize: "\u30B5\u30A4\u30BA",
315
331
  theme: "\u30C6\u30FC\u30DE",
316
332
  primaryColor: "\u30E1\u30A4\u30F3\u30AB\u30E9\u30FC",
@@ -346,6 +362,35 @@ function withLang(val, lang, value) {
346
362
  return { ...base, [lang]: value };
347
363
  }
348
364
 
365
+ // src/lib/color.ts
366
+ function mixHex(a, b, t2) {
367
+ const pa = parseHex(a);
368
+ const pb = parseHex(b);
369
+ if (!pa || !pb) return a;
370
+ const mix = (x, y) => Math.round(x + (y - x) * t2);
371
+ const toHex = (n) => n.toString(16).padStart(2, "0");
372
+ return `#${toHex(mix(pa[0], pb[0]))}${toHex(mix(pa[1], pb[1]))}${toHex(mix(pa[2], pb[2]))}`;
373
+ }
374
+ function parseHex(hex) {
375
+ const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
376
+ if (!m) return null;
377
+ const n = parseInt(m[1], 16);
378
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
379
+ }
380
+
381
+ // src/lib/storage/compress.ts
382
+ var import_lz_string = require("lz-string");
383
+ function compress(raw) {
384
+ return (0, import_lz_string.compressToUTF16)(raw);
385
+ }
386
+ function decompress(value) {
387
+ try {
388
+ return (0, import_lz_string.decompressFromUTF16)(value);
389
+ } catch {
390
+ return null;
391
+ }
392
+ }
393
+
349
394
  // src/lib/storage/localStorageAdapter.ts
350
395
  function hasLocalStorage() {
351
396
  return typeof window !== "undefined" && !!window.localStorage;
@@ -353,11 +398,21 @@ function hasLocalStorage() {
353
398
  var localStorageAdapter = {
354
399
  async get(key) {
355
400
  if (!hasLocalStorage()) return null;
356
- return window.localStorage.getItem(key);
401
+ const raw = window.localStorage.getItem(key);
402
+ if (raw == null) return null;
403
+ const decompressed = decompress(raw);
404
+ if (decompressed != null) {
405
+ try {
406
+ JSON.parse(decompressed);
407
+ return decompressed;
408
+ } catch {
409
+ }
410
+ }
411
+ return raw;
357
412
  },
358
413
  async set(key, value) {
359
414
  if (!hasLocalStorage()) return;
360
- window.localStorage.setItem(key, value);
415
+ window.localStorage.setItem(key, compress(value));
361
416
  },
362
417
  async delete(key) {
363
418
  if (!hasLocalStorage()) return;
@@ -365,60 +420,12 @@ var localStorageAdapter = {
365
420
  }
366
421
  };
367
422
 
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
423
  // src/constants/fieldTypes.ts
418
424
  var import_lucide_react = require("lucide-react");
419
425
  var FIELD_TYPES = [
420
426
  { type: "paragraph", icon: import_lucide_react.FileText, isContent: true, defaultIcon: "FileText" },
421
427
  { type: "image", icon: import_lucide_react.Image, isContent: true, isImage: true, defaultIcon: "Type" },
428
+ { type: "button", icon: import_lucide_react.MousePointerClick, isContent: true, defaultIcon: "Type" },
422
429
  { type: "input", icon: import_lucide_react.Type, placeholder: true, hasSubtype: true, defaultIcon: "Type" },
423
430
  { type: "textarea", icon: import_lucide_react.AlignLeft, placeholder: true, defaultIcon: "AlignLeft" },
424
431
  { type: "select", icon: import_lucide_react.ChevronDown, options: true, defaultIcon: "ChevronDown" },
@@ -439,6 +446,7 @@ var IMAGE_SHAPES = ["square", "circle", "banner"];
439
446
  var FIELD_TYPE_CHROME_KEY = {
440
447
  paragraph: "fieldTypeParagraph",
441
448
  image: "fieldTypeImage",
449
+ button: "fieldTypeButton",
442
450
  input: "fieldTypeInput",
443
451
  textarea: "fieldTypeTextarea",
444
452
  select: "fieldTypeSelect",
@@ -517,21 +525,195 @@ function defaultFieldFor(type, language, chrome) {
517
525
  base.fontStyle = "normal";
518
526
  base.textAlign = "left";
519
527
  base.color = "";
528
+ } else if (type === "button") {
529
+ base.action = "submit";
530
+ base.submitScope = "form";
531
+ base.buttonStyle = { color: "", size: "md" };
532
+ base.href = "";
533
+ base.target = "_self";
520
534
  } else {
521
535
  base.defaultValue = "";
522
536
  }
523
537
  return base;
524
538
  }
525
539
  function defaultSection(titleEn = "") {
526
- return { id: genSectionId(), title: bi(titleEn, ""), background: "", collapsed: false, submitStyle: null, fields: [] };
540
+ return { id: genSectionId(), title: bi(titleEn, ""), background: "", collapsed: false, fields: [] };
541
+ }
542
+
543
+ // src/lib/submittable.ts
544
+ function sectionHasFormFields(section) {
545
+ return section.fields.some((f) => !getMeta(f.type).isContent);
546
+ }
547
+
548
+ // src/lib/migrate.ts
549
+ function migrateField(field) {
550
+ let f = { ...field };
551
+ if (LEGACY_INPUT_TYPES.includes(f.type)) f = { ...f, type: "input", inputType: f.type };
552
+ f.label = typeof f.label === "string" ? bi(f.label) : f.label || bi();
553
+ f.hideLabel = !!f.hideLabel;
554
+ if ("placeholder" in f) f.placeholder = typeof f.placeholder === "string" ? bi(f.placeholder) : f.placeholder || bi();
555
+ if ("content" in f) f.content = typeof f.content === "string" ? bi(f.content) : f.content || bi();
556
+ if ("alt" in f) f.alt = typeof f.alt === "string" ? bi(f.alt) : f.alt || bi();
557
+ if (f.options) f.options = f.options.map((o) => ({ ...o, label: typeof o.label === "string" ? bi(o.label) : o.label || bi() }));
558
+ if (f.type === "paragraph") {
559
+ f.tag = f.tag || "p";
560
+ f.fontSize = f.fontSize || "md";
561
+ f.fontWeight = f.fontWeight || "normal";
562
+ f.fontStyle = f.fontStyle || "normal";
563
+ f.textAlign = f.textAlign || "left";
564
+ f.color = f.color || "";
565
+ }
566
+ if (f.type === "button") {
567
+ f.action = f.action === "link" ? "link" : "submit";
568
+ f.buttonStyle = f.buttonStyle || { color: "", size: "md" };
569
+ f.href = f.href || "";
570
+ f.target = f.target === "_blank" ? "_blank" : "_self";
571
+ f.submitScope = f.submitScope === "section" ? "section" : "form";
572
+ }
573
+ f.verticalAlign = f.verticalAlign || "top";
574
+ return f;
575
+ }
576
+ function migrateFields(fields) {
577
+ return (fields || []).map(migrateField);
578
+ }
579
+ function synthesizeButtonField(label, style, scope) {
580
+ const resolvedLabel = typeof label === "string" && label ? bi(label) : label && typeof label === "object" && (label.en || label.ja) ? label : bi("Submit", "");
581
+ return {
582
+ id: nextId(),
583
+ type: "button",
584
+ label: resolvedLabel,
585
+ hideLabel: false,
586
+ width: "1/1",
587
+ verticalAlign: "top",
588
+ labelPosition: "top",
589
+ showIcon: false,
590
+ displayIcon: "Type",
591
+ action: "submit",
592
+ submitScope: scope,
593
+ buttonStyle: style || { color: "", size: "md" },
594
+ href: "",
595
+ target: "_self"
596
+ };
597
+ }
598
+ function migrateDocument(raw) {
599
+ if (!raw) return null;
600
+ const title = typeof raw.title === "string" ? bi(raw.title) : raw.title || bi();
601
+ const themeOverrides = raw.themeOverrides || {};
602
+ let sections;
603
+ if (raw.sections) {
604
+ sections = raw.sections.map((s) => ({
605
+ id: s.id || genSectionId(),
606
+ title: typeof s.title === "string" ? bi(s.title) : s.title || bi(),
607
+ background: s.background || "",
608
+ collapsed: !!s.collapsed,
609
+ fields: migrateFields(s.fields || [])
610
+ }));
611
+ } else {
612
+ sections = [{ ...defaultSection(), fields: migrateFields(raw.fields || []) }];
613
+ }
614
+ const legacy = raw.version === void 0 || raw.version < 5;
615
+ if (legacy) {
616
+ resyncIdCounter(sections.flatMap((s) => s.fields));
617
+ const submitMode = raw.submitMode === "perSection" ? "perSection" : "combined";
618
+ const submitLabel = raw.submitLabel;
619
+ const submitStyle = raw.submitStyle || { color: "", size: "md" };
620
+ if (submitMode === "perSection" && raw.sections) {
621
+ sections = sections.map((s, i) => {
622
+ if (!sectionHasFormFields(s)) return s;
623
+ const rawSection = raw.sections[i] || {};
624
+ const label = rawSection.submitLabel || submitLabel;
625
+ const style = rawSection.submitStyle || submitStyle;
626
+ return { ...s, fields: [...s.fields, synthesizeButtonField(label, style, "section")] };
627
+ });
628
+ } else if (sections.some(sectionHasFormFields)) {
629
+ const lastIdx = sections.length - 1;
630
+ sections = sections.map((s, i) => i === lastIdx ? { ...s, fields: [...s.fields, synthesizeButtonField(submitLabel, submitStyle, "form")] } : s);
631
+ }
632
+ }
633
+ return { title, themeOverrides, sections };
634
+ }
635
+
636
+ // src/lib/features.ts
637
+ var DEFAULT_FEATURES = {
638
+ naming: true,
639
+ templates: true,
640
+ newForm: true,
641
+ autosave: true,
642
+ jsonView: true,
643
+ previewMode: true,
644
+ languageSwitcher: true,
645
+ design: false,
646
+ blockStyling: true,
647
+ contentBlocks: true,
648
+ fieldTypes: true,
649
+ sections: true,
650
+ dragReorder: true
651
+ };
652
+ function resolveFeatures(features) {
653
+ return {
654
+ ...DEFAULT_FEATURES,
655
+ ...features,
656
+ contentBlocks: Array.isArray(features?.contentBlocks) ? new Set(features.contentBlocks) : features?.contentBlocks ?? DEFAULT_FEATURES.contentBlocks,
657
+ fieldTypes: Array.isArray(features?.fieldTypes) ? new Set(features.fieldTypes) : features?.fieldTypes ?? DEFAULT_FEATURES.fieldTypes
658
+ };
659
+ }
660
+ function isContentBlockEnabled(features, type) {
661
+ return features.contentBlocks === true || features.contentBlocks instanceof Set && features.contentBlocks.has(type);
662
+ }
663
+ function isFieldTypeEnabled(features, type) {
664
+ return features.fieldTypes === true || features.fieldTypes instanceof Set && features.fieldTypes.has(type);
665
+ }
666
+
667
+ // src/hooks/useTheme.ts
668
+ var import_react = require("react");
669
+
670
+ // src/theme/defaultTheme.ts
671
+ var DEFAULT_THEME = {
672
+ primary: "#5B5FEF",
673
+ primarySoft: "#EEF0FF",
674
+ danger: "#C4432E",
675
+ dangerSoft: "#FDECE4",
676
+ ink: "#1B1E24",
677
+ muted: "#9296A3",
678
+ border: "#E2E4E9",
679
+ surface: "#FFFFFF",
680
+ canvas: "#F5F6F8",
681
+ pageBackground: "#FFFFFF",
682
+ layout: { maxWidth: 1200, pagePadding: 28, canvasPadding: 20, sectionGap: 20, fieldGap: 16, toolbarPadding: 10, panelPadding: 14, ticketPadding: 14 }
683
+ };
684
+
685
+ // src/hooks/useTheme.ts
686
+ function useTheme(themeOverrideProp) {
687
+ const baseTheme = {
688
+ ...DEFAULT_THEME,
689
+ ...themeOverrideProp || {},
690
+ layout: { ...DEFAULT_THEME.layout, ...themeOverrideProp && themeOverrideProp.layout || {} }
691
+ };
692
+ const [themeOverrides, setThemeOverrides] = (0, import_react.useState)({});
693
+ const theme = {
694
+ ...baseTheme,
695
+ ...themeOverrides,
696
+ layout: { ...baseTheme.layout, ...themeOverrides.layout || {} }
697
+ };
698
+ function updateThemeColor(key, value) {
699
+ setThemeOverrides((prev) => ({ ...prev, [key]: value }));
700
+ }
701
+ function updateThemeLayout(key, value) {
702
+ setThemeOverrides((prev) => ({ ...prev, layout: { ...prev.layout, [key]: value } }));
703
+ }
704
+ function resetTheme() {
705
+ setThemeOverrides({});
706
+ }
707
+ function replaceThemeOverrides(overrides) {
708
+ setThemeOverrides(overrides);
709
+ }
710
+ return { theme, themeOverrides, updateThemeColor, updateThemeLayout, resetTheme, replaceThemeOverrides };
527
711
  }
528
712
 
529
713
  // src/hooks/useFormDocument.ts
714
+ var import_react2 = require("react");
530
715
  function useFormDocument({ language, chrome }) {
531
716
  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
717
  const [sections, setSections] = (0, import_react2.useState)([defaultSection()]);
536
718
  const [activeSectionId, setActiveSectionId] = (0, import_react2.useState)(null);
537
719
  const [selectedId, setSelectedId] = (0, import_react2.useState)(null);
@@ -541,12 +723,6 @@ function useFormDocument({ language, chrome }) {
541
723
  function updateTitle(value) {
542
724
  setTitle((prev) => withLang(prev, language, value));
543
725
  }
544
- function updateSubmitLabel(value) {
545
- setSubmitLabelState((prev) => withLang(prev, language, value));
546
- }
547
- function updateSubmitStyle(patch) {
548
- setSubmitStyleState((prev) => ({ ...prev, ...patch }));
549
- }
550
726
  function addSection() {
551
727
  const s = defaultSection();
552
728
  setSections((prev) => [...prev, s]);
@@ -591,12 +767,6 @@ function useFormDocument({ language, chrome }) {
591
767
  function toggleSectionCollapse(sectionId) {
592
768
  setSections((prev) => prev.map((s) => s.id === sectionId ? { ...s, collapsed: !s.collapsed } : s));
593
769
  }
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
770
  function addField(type) {
601
771
  const field = defaultFieldFor(type, language, chrome);
602
772
  const targetId = activeSectionId || sections[0]?.id;
@@ -674,9 +844,6 @@ function useFormDocument({ language, chrome }) {
674
844
  setSections(doc.sections);
675
845
  setActiveSectionId(doc.sections[0]?.id || null);
676
846
  setTitle(doc.title);
677
- setSubmitLabelState(doc.submitLabel);
678
- setSubmitMode(doc.submitMode);
679
- setSubmitStyleState(doc.submitStyle);
680
847
  setSelectedId(null);
681
848
  }
682
849
  function resetToBlank() {
@@ -684,16 +851,10 @@ function useFormDocument({ language, chrome }) {
684
851
  setSections([s]);
685
852
  setActiveSectionId(s.id);
686
853
  setTitle(bi("Untitled form", ""));
687
- setSubmitLabelState(bi());
688
- setSubmitMode("combined");
689
- setSubmitStyleState({ color: "", size: "md" });
690
854
  setSelectedId(null);
691
855
  }
692
856
  return {
693
857
  title,
694
- submitLabel,
695
- submitMode,
696
- submitStyle,
697
858
  sections,
698
859
  activeSectionId,
699
860
  selectedId,
@@ -702,11 +863,8 @@ function useFormDocument({ language, chrome }) {
702
863
  activeSection,
703
864
  setActiveSectionId,
704
865
  setSelectedId,
705
- setSubmitMode,
706
866
  setTitle,
707
867
  updateTitle,
708
- updateSubmitLabel,
709
- updateSubmitStyle,
710
868
  addSection,
711
869
  duplicateSection,
712
870
  deleteSection,
@@ -714,8 +872,6 @@ function useFormDocument({ language, chrome }) {
714
872
  updateSectionTitle,
715
873
  updateSectionBackground,
716
874
  toggleSectionCollapse,
717
- updateSectionSubmitStyle,
718
- clearSectionSubmitStyle,
719
875
  addField,
720
876
  updateField,
721
877
  deleteField,
@@ -738,62 +894,15 @@ var DRAFT_KEY = "form-page-builder:draft";
738
894
  var INDEX_KEY = "form-page-builder:index";
739
895
  var formKey = (id) => `form-page-builder:saved:${id}`;
740
896
 
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
897
  // src/hooks/usePersistence.ts
898
+ var MAX_TEMPLATES = 5;
793
899
  function usePersistence({
794
900
  storage,
901
+ autosave,
795
902
  language,
903
+ chrome,
796
904
  document,
905
+ initialDocument,
797
906
  onLoadDocument,
798
907
  onLoadThemeOverrides,
799
908
  onTitleChange,
@@ -819,17 +928,27 @@ function usePersistence({
819
928
  (0, import_react3.useEffect)(() => {
820
929
  (async () => {
821
930
  try {
822
- const raw = await storage.get(DRAFT_KEY);
823
- if (raw) {
824
- const parsed = JSON.parse(raw);
825
- const doc = migrateDocument(parsed);
931
+ if (initialDocument) {
932
+ const doc = migrateDocument(initialDocument);
826
933
  if (doc) {
827
934
  onLoadDocument(doc);
828
935
  onLoadThemeOverrides(doc.themeOverrides);
936
+ } else {
937
+ ensureActiveSection();
829
938
  }
830
- if (parsed.currentFormId) setCurrentFormId(parsed.currentFormId);
831
939
  } else {
832
- ensureActiveSection();
940
+ const raw = await storage.get(DRAFT_KEY);
941
+ if (raw) {
942
+ const parsed = JSON.parse(raw);
943
+ const doc = migrateDocument(parsed);
944
+ if (doc) {
945
+ onLoadDocument(doc);
946
+ onLoadThemeOverrides(doc.themeOverrides);
947
+ }
948
+ if (parsed.currentFormId) setCurrentFormId(parsed.currentFormId);
949
+ } else {
950
+ ensureActiveSection();
951
+ }
833
952
  }
834
953
  } catch (err) {
835
954
  ensureActiveSection();
@@ -841,7 +960,7 @@ function usePersistence({
841
960
  refreshLibrary();
842
961
  }, []);
843
962
  (0, import_react3.useEffect)(() => {
844
- if (!hasLoadedOnce.current) return;
963
+ if (!hasLoadedOnce.current || !autosave) return;
845
964
  setSaveState("saving");
846
965
  if (autosaveTimer.current) clearTimeout(autosaveTimer.current);
847
966
  autosaveTimer.current = setTimeout(async () => {
@@ -855,8 +974,12 @@ function usePersistence({
855
974
  return () => {
856
975
  if (autosaveTimer.current) clearTimeout(autosaveTimer.current);
857
976
  };
858
- }, [document.title, document.submitLabel, document.submitMode, document.submitStyle, document.themeOverrides, document.sections, currentFormId]);
977
+ }, [document.title, document.themeOverrides, document.sections, currentFormId]);
859
978
  async function saveAs(name) {
979
+ if (savedForms.length >= MAX_TEMPLATES) {
980
+ alert(chrome.templatesLimitReached);
981
+ return;
982
+ }
860
983
  const id = genFormId();
861
984
  const now = Date.now();
862
985
  try {
@@ -965,26 +1088,26 @@ function useDragReorder(reorderWithinSection) {
965
1088
  }
966
1089
 
967
1090
  // src/components/Toolbar.tsx
968
- var import_lucide_react4 = require("lucide-react");
1091
+ var import_lucide_react2 = require("lucide-react");
969
1092
 
970
1093
  // src/styles/styles.ts
971
1094
  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" },
1095
+ 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
1096
  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
1097
  toolbarLeft: { display: "flex", alignItems: "center", gap: 10 },
975
1098
  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" },
976
1099
  titleInput: { border: "none", outline: "none", fontSize: 14, fontWeight: 600, background: "transparent", color: "var(--fb-ink)", padding: "4px 6px", borderRadius: 6, minWidth: 160 },
977
1100
  toolbarRight: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" },
978
1101
  toolbarDivider: { width: 1, height: 20, background: "var(--fb-border)", margin: "0 4px" },
979
- tabBtn: { display: "flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 7, border: "1px solid transparent", background: "transparent", color: "#6B6E79", fontSize: 13, fontWeight: 500 },
1102
+ tabBtn: { display: "flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 7, border: "1px solid transparent", background: "transparent", color: "var(--fb-muted)", fontSize: 13, fontWeight: 500 },
980
1103
  tabBtnActive: { display: "flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 7, border: "1px solid var(--fb-border)", background: "var(--fb-primary-soft)", color: "var(--fb-primary)", fontSize: 13, fontWeight: 600 },
981
- ghostBtn: { display: "flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 7, border: "1px solid var(--fb-border)", background: "var(--fb-surface)", color: "#4A4D57", fontSize: 13, fontWeight: 500 },
1104
+ ghostBtn: { display: "flex", alignItems: "center", gap: 6, padding: "6px 12px", borderRadius: 7, border: "1px solid var(--fb-border)", background: "var(--fb-surface)", color: "var(--fb-ink)", fontSize: 13, fontWeight: 500 },
982
1105
  primaryBtn: { display: "flex", alignItems: "center", gap: 6, padding: "6px 13px", borderRadius: 7, border: "1px solid var(--fb-primary)", background: "var(--fb-primary)", color: "#fff", fontSize: 13, fontWeight: 600 },
983
1106
  saveStatus: { display: "flex", alignItems: "center", gap: 5, fontSize: 12, color: "var(--fb-muted)", minWidth: 60 },
984
1107
  countBadge: { fontSize: 10.5, fontWeight: 700, background: "var(--fb-primary-soft)", color: "var(--fb-primary)", borderRadius: 9, padding: "1px 6px", marginLeft: 2 },
985
1108
  loadingScreen: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", color: "var(--fb-muted)" },
986
1109
  libraryBody: { padding: "var(--fb-space-panel)", overflowY: "auto", display: "flex", flexDirection: "column", gap: 4 },
987
- libraryRow: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, padding: "10px 8px", borderRadius: 8, border: "1px solid #F0F1F4" },
1110
+ libraryRow: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 10, padding: "10px 8px", borderRadius: 8, border: "1px solid var(--fb-border)" },
988
1111
  libraryRowTitle: { fontSize: 13.5, fontWeight: 600, color: "var(--fb-ink)", display: "flex", alignItems: "center", gap: 8, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
989
1112
  libraryRowMeta: { fontSize: 11.5, color: "var(--fb-muted)", marginTop: 2 },
990
1113
  currentBadge: { fontSize: 10, fontWeight: 700, color: "var(--fb-primary)", background: "var(--fb-primary-soft)", padding: "2px 6px", borderRadius: 5, flexShrink: 0 },
@@ -993,7 +1116,7 @@ var styles = {
993
1116
  panelHeading: { fontSize: 11, fontWeight: 700, letterSpacing: "0.06em", textTransform: "uppercase", color: "var(--fb-muted)", marginBottom: 10 },
994
1117
  activeSectionHint: { fontSize: 11.5, color: "var(--fb-muted)", marginBottom: 14, lineHeight: 1.4 },
995
1118
  paletteList: { display: "flex", flexDirection: "column", gap: 4 },
996
- paletteItem: { display: "flex", alignItems: "center", gap: 9, padding: "8px 9px", borderRadius: 8, border: "1px solid transparent", background: "transparent", fontSize: 13, color: "#33353E", textAlign: "left" },
1119
+ paletteItem: { display: "flex", alignItems: "center", gap: 9, padding: "8px 9px", borderRadius: 8, border: "1px solid transparent", background: "transparent", fontSize: 13, color: "var(--fb-ink)", textAlign: "left" },
997
1120
  canvas: { flex: 1, padding: "var(--fb-space-canvas)", overflowY: "auto", background: "var(--fb-canvas)" },
998
1121
  sectionBlock: { borderRadius: 12, padding: "var(--fb-space-panel)", marginBottom: "var(--fb-space-section)", transition: "border-color 0.12s" },
999
1122
  sectionHeader: { display: "flex", alignItems: "center", gap: 8, marginBottom: 12, flexWrap: "wrap" },
@@ -1002,10 +1125,8 @@ var styles = {
1002
1125
  sectionTitleInput: { border: "none", outline: "none", background: "transparent", fontSize: 14, fontWeight: 700, color: "var(--fb-ink)", padding: "2px 0", minWidth: 120, flex: 1 },
1003
1126
  sectionHeaderActions: { display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap", marginLeft: "auto" },
1004
1127
  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
1128
  resetLinkBtn: { display: "flex", alignItems: "center", gap: 3, fontSize: 11, color: "var(--fb-muted)", background: "transparent", border: "none", padding: "2px 4px" },
1008
- 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 },
1129
+ addSectionBtn: { display: "flex", alignItems: "center", justifyContent: "center", gap: 6, width: "100%", padding: "10px", borderRadius: 10, border: "1px dashed var(--fb-border)", background: "transparent", color: "var(--fb-primary)", fontSize: 13, fontWeight: 600 },
1009
1130
  swatchRow: { display: "flex", alignItems: "center", gap: 5, flexWrap: "wrap" },
1010
1131
  swatchBtn: { width: 20, height: 20, borderRadius: "50%", border: "1px solid var(--fb-border)", padding: 0 },
1011
1132
  swatchBtnActive: { border: "2px solid var(--fb-primary)" },
@@ -1014,52 +1135,56 @@ var styles = {
1014
1135
  ticket: { display: "flex", alignItems: "stretch", background: "var(--fb-surface)", border: "1px solid var(--fb-border)", borderRadius: 10, position: "relative", transition: "border-color 0.12s, box-shadow 0.12s" },
1015
1136
  ticketSelected: { borderColor: "var(--fb-primary)", boxShadow: "0 0 0 3px var(--fb-primary-soft)" },
1016
1137
  ticketDragOver: { borderColor: "var(--fb-muted)" },
1017
- ticketIndex: { fontFamily: "'JetBrains Mono', monospace", fontSize: 13, fontWeight: 700, color: "#C7C9D6", width: 34, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 },
1138
+ ticketIndex: { fontFamily: "'JetBrains Mono', monospace", fontSize: 13, fontWeight: 700, color: "var(--fb-border)", width: 34, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 },
1018
1139
  ticketPerforation: { width: 0, borderLeft: "1px dashed var(--fb-border)" },
1019
1140
  ticketBody: { flex: 1, padding: "10px var(--fb-space-ticket)", minWidth: 0 },
1020
1141
  ticketTop: { display: "flex", alignItems: "center", gap: 7, marginBottom: 4 },
1021
1142
  typeBadge: { fontSize: 10.5, fontFamily: "'JetBrains Mono', monospace", color: "var(--fb-muted)" },
1022
- requiredBadge: { fontSize: 10, fontWeight: 700, color: "#B4522F", background: "var(--fb-danger-soft)", padding: "2px 6px", borderRadius: 5, letterSpacing: "0.02em", marginLeft: "auto" },
1143
+ requiredBadge: { fontSize: 10, fontWeight: 700, color: "var(--fb-danger)", background: "var(--fb-danger-soft)", padding: "2px 6px", borderRadius: 5, letterSpacing: "0.02em", marginLeft: "auto" },
1023
1144
  chipRow: { display: "flex", gap: 5, marginBottom: 7, flexWrap: "wrap" },
1024
1145
  miniBadge: { fontSize: 10, fontWeight: 600, color: "var(--fb-primary)", background: "var(--fb-primary-soft)", padding: "2px 6px", borderRadius: 5, letterSpacing: "0.02em" },
1025
- segmented: { display: "flex", gap: 3, background: "#F0F1F4", padding: 3, borderRadius: 8, marginBottom: 4 },
1026
- 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
- 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)" },
1146
+ langToggleTrack: { position: "relative", display: "flex", gap: 3, background: "var(--fb-surface-2)", padding: 3, borderRadius: 20 },
1147
+ langToggleThumb: { position: "absolute", top: 3, left: 3, bottom: 3, background: "var(--fb-primary)", borderRadius: 17, transition: "transform 0.18s ease" },
1148
+ langToggleBtn: { position: "relative", zIndex: 1, padding: "5px 12px", borderRadius: 17, border: "none", background: "transparent", color: "var(--fb-muted)", fontSize: 12.5, fontWeight: 600, whiteSpace: "nowrap" },
1149
+ langToggleBtnActive: { position: "relative", zIndex: 1, padding: "5px 12px", borderRadius: 17, border: "none", background: "transparent", color: "#fff", fontSize: 12.5, fontWeight: 600, whiteSpace: "nowrap" },
1150
+ segmented: { display: "flex", gap: 3, background: "var(--fb-surface-2)", padding: 3, borderRadius: 8, marginBottom: 4 },
1151
+ segmentedBtn: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "6px 8px", borderRadius: 6, border: "none", background: "transparent", color: "var(--fb-muted)", fontSize: 12.5, fontWeight: 500 },
1152
+ segmentedBtnActive: { flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "6px 8px", borderRadius: 6, border: "none", background: "var(--fb-surface)", color: "var(--fb-ink)", fontSize: 12.5, fontWeight: 600, boxShadow: "0 1px 2px rgba(0,0,0,0.08)" },
1028
1153
  iconGrid: { display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 5, marginTop: 6 },
1029
- iconGridBtn: { width: 30, height: 30, borderRadius: 7, border: "1px solid var(--fb-border)", background: "#fff", display: "flex", alignItems: "center", justifyContent: "center", color: "#6B6E79" },
1154
+ iconGridBtn: { width: 30, height: 30, borderRadius: 7, border: "1px solid var(--fb-border)", background: "var(--fb-surface)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fb-muted)" },
1030
1155
  iconGridBtnActive: { width: 30, height: 30, borderRadius: 7, border: "1px solid var(--fb-primary)", background: "var(--fb-primary-soft)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fb-primary)" },
1031
1156
  styleToggleRow: { display: "flex", gap: 5, marginBottom: 4 },
1032
- styleToggle: { width: 30, height: 30, borderRadius: 7, border: "1px solid var(--fb-border)", background: "#fff", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fb-muted)" },
1157
+ styleToggle: { width: 30, height: 30, borderRadius: 7, border: "1px solid var(--fb-border)", background: "var(--fb-surface)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fb-muted)" },
1033
1158
  styleToggleActive: { width: 30, height: 30, borderRadius: 7, border: "1px solid var(--fb-primary)", background: "var(--fb-primary-soft)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fb-primary)" },
1034
- previewInput: { border: "1px solid #E9EAEE", borderRadius: 7, padding: "7px 10px", fontSize: 13, color: "var(--fb-muted)", background: "#FBFBFD", display: "flex", alignItems: "center", justifyContent: "space-between" },
1035
- previewRadio: { display: "flex", alignItems: "center", gap: 6, fontSize: 13, color: "#4A4D57" },
1036
- ticketActions: { display: "flex", flexDirection: "column", gap: 3, padding: 8, borderLeft: "1px solid #F0F1F4" },
1037
- iconBtn: { width: 24, height: 24, borderRadius: 6, border: "1px solid #E9EAEE", background: "#fff", display: "flex", alignItems: "center", justifyContent: "center", color: "#6B6E79" },
1159
+ previewInput: { border: "1px solid var(--fb-border)", borderRadius: 7, padding: "7px 10px", fontSize: 13, color: "var(--fb-muted)", background: "var(--fb-surface-2)", display: "flex", alignItems: "center", justifyContent: "space-between" },
1160
+ previewRadio: { display: "flex", alignItems: "center", gap: 6, fontSize: 13, color: "var(--fb-ink)" },
1161
+ ticketActions: { display: "flex", flexDirection: "column", gap: 3, padding: 8, borderLeft: "1px solid var(--fb-border)" },
1162
+ iconBtn: { width: 24, height: 24, borderRadius: 6, border: "1px solid var(--fb-border)", background: "var(--fb-surface)", display: "flex", alignItems: "center", justifyContent: "center", color: "var(--fb-muted)" },
1038
1163
  iconBtnDanger: { color: "var(--fb-danger)" },
1039
1164
  inspector: { width: 270, borderLeft: "1px solid var(--fb-border)", background: "var(--fb-surface)", padding: "var(--fb-space-panel)", overflowY: "auto" },
1040
1165
  inspectorEmpty: { fontSize: 13, color: "var(--fb-muted)", lineHeight: 1.5, marginTop: 6 },
1041
1166
  inspectorBody: { display: "flex", flexDirection: "column", gap: 4 },
1042
1167
  helperText: { fontSize: 11, color: "var(--fb-muted)", lineHeight: 1.4, margin: "2px 0 4px" },
1043
- propLabel: { fontSize: 11.5, fontWeight: 600, color: "#6B6E79", marginTop: 12, marginBottom: 5 },
1044
- propInput: { border: "1px solid var(--fb-border)", borderRadius: 7, padding: "7px 9px", fontSize: 13, color: "var(--fb-ink)", outline: "none", width: "100%", boxSizing: "border-box" },
1168
+ propLabel: { fontSize: 11.5, fontWeight: 600, color: "var(--fb-muted)", marginTop: 12, marginBottom: 5 },
1169
+ propInput: { border: "1px solid var(--fb-border)", borderRadius: 7, padding: "7px 9px", fontSize: 13, color: "var(--fb-ink)", background: "var(--fb-surface)", outline: "none", width: "100%", boxSizing: "border-box" },
1045
1170
  optionList: { display: "flex", flexDirection: "column", gap: 6 },
1046
1171
  optionRow: { display: "flex", gap: 6, alignItems: "center" },
1047
- optionInput: { flex: 1, border: "1px solid var(--fb-border)", borderRadius: 6, padding: "6px 8px", fontSize: 12.5, outline: "none", minWidth: 0, boxSizing: "border-box" },
1048
- addOptionBtn: { display: "flex", alignItems: "center", gap: 5, fontSize: 12.5, color: "var(--fb-primary)", background: "transparent", border: "1px dashed #C7C9D6", borderRadius: 7, padding: "6px 8px", justifyContent: "center", marginTop: 2 },
1172
+ optionInput: { flex: 1, border: "1px solid var(--fb-border)", borderRadius: 6, padding: "6px 8px", fontSize: 12.5, color: "var(--fb-ink)", background: "var(--fb-surface)", outline: "none", minWidth: 0, boxSizing: "border-box" },
1173
+ addOptionBtn: { display: "flex", alignItems: "center", gap: 5, fontSize: 12.5, color: "var(--fb-primary)", background: "transparent", border: "1px dashed var(--fb-border)", borderRadius: 7, padding: "6px 8px", justifyContent: "center", marginTop: 2 },
1049
1174
  toggleRow: { display: "flex", alignItems: "center", gap: 8, background: "transparent", border: "none", padding: "8px 0" },
1050
1175
  toggleTrack: { width: 30, height: 17, borderRadius: 20, position: "relative", transition: "background 0.15s", display: "inline-block" },
1051
1176
  toggleThumb: { position: "absolute", top: 2, left: 2, width: 13, height: 13, borderRadius: "50%", background: "#fff", transition: "transform 0.15s", boxShadow: "0 1px 2px rgba(0,0,0,0.2)" },
1052
1177
  inspectorDivider: { height: 1, background: "var(--fb-border)", margin: "14px 0 10px" },
1053
1178
  deleteFieldBtn: { display: "flex", alignItems: "center", gap: 6, fontSize: 12.5, color: "var(--fb-danger)", background: "var(--fb-danger-soft)", border: "none", borderRadius: 7, padding: "8px 10px", justifyContent: "center" },
1054
- modalOverlay: { position: "fixed", inset: 0, background: "rgba(20,22,28,0.45)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 50 },
1055
- modal: { background: "#fff", borderRadius: 12, width: 520, maxHeight: "70vh", display: "flex", flexDirection: "column", overflow: "hidden", boxShadow: "0 20px 60px rgba(0,0,0,0.25)" },
1179
+ modalOverlay: { position: "fixed", inset: 0, background: "rgba(20,22,28,0.45)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 50, padding: 16, boxSizing: "border-box" },
1180
+ modal: { background: "var(--fb-surface)", borderRadius: 12, width: "100%", maxWidth: 520, maxHeight: "70vh", display: "flex", flexDirection: "column", overflow: "hidden", boxShadow: "0 20px 60px rgba(0,0,0,0.25)", boxSizing: "border-box" },
1056
1181
  modalHeader: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "12px 16px", borderBottom: "1px solid var(--fb-border)" },
1057
1182
  jsonPre: { margin: 0, padding: 16, fontSize: 12, lineHeight: 1.6, overflow: "auto", background: "#14171C", color: "#D6D8E0", fontFamily: "'JetBrains Mono', monospace" },
1058
1183
  previewWrap: { flex: 1, display: "flex", justifyContent: "center", padding: "var(--fb-space-page) 20px", overflowY: "auto", background: "var(--fb-canvas)" },
1059
1184
  previewToolbar: { width: "100%", display: "flex", gap: 10, marginBottom: 16, justifyContent: "center" },
1060
1185
  previewCard: { width: "100%", maxWidth: 480, background: "var(--fb-page-bg)", border: "1px solid var(--fb-border)", borderRadius: 12, padding: "var(--fb-space-page)" },
1061
1186
  previewTitle: { fontSize: 19, fontWeight: 700, margin: "0 0 20px" },
1062
- previewLabel: { display: "block", fontSize: 13, fontWeight: 600, color: "#33353E", marginBottom: 6 },
1187
+ previewLabel: { display: "block", fontSize: 13, fontWeight: 600, color: "var(--fb-ink)", marginBottom: 6 },
1063
1188
  previewGrid: { display: "flex", flexWrap: "wrap", gap: "var(--fb-space-field)" },
1064
1189
  sectionRuntimeTitle: { fontSize: 15, fontWeight: 700, margin: "0 0 12px", color: "var(--fb-ink)" },
1065
1190
  imagePlaceholder: { display: "flex", alignItems: "center", justifyContent: "center", border: "1px dashed var(--fb-border)" },
@@ -1069,32 +1194,146 @@ var styles = {
1069
1194
  submittedRow: { display: "flex", justifyContent: "space-between", gap: 12, fontSize: 13, padding: "6px 0", borderBottom: "1px solid var(--fb-border)" },
1070
1195
  submittedLabel: { color: "var(--fb-muted)", flexShrink: 0 },
1071
1196
  submittedValue: { color: "var(--fb-ink)", fontWeight: 600, textAlign: "right" },
1072
- 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" },
1197
+ realInput: { width: "100%", border: "1px solid var(--fb-border)", borderRadius: 8, padding: "9px 11px", fontSize: 13.5, outline: "none", color: "var(--fb-ink)", background: "var(--fb-surface)", boxSizing: "border-box" },
1073
1198
  realInputError: { borderColor: "var(--fb-danger)" },
1074
1199
  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
1200
  layoutPanelHeader: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 4 },
1077
1201
  spacingRow: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, padding: "4px 0" },
1078
- spacingLabel: { fontSize: 12, color: "#4A4D57" },
1079
- spacingInput: { width: 60, border: "1px solid var(--fb-border)", borderRadius: 6, padding: "4px 6px", fontSize: 12, textAlign: "right", outline: "none" }
1202
+ spacingLabel: { fontSize: 12, color: "var(--fb-ink)" },
1203
+ spacingInput: { width: 60, border: "1px solid var(--fb-border)", borderRadius: 6, padding: "4px 6px", fontSize: 12, textAlign: "right", color: "var(--fb-ink)", background: "var(--fb-surface)", outline: "none" }
1080
1204
  };
1081
1205
 
1082
- // src/components/Segmented.tsx
1206
+ // src/components/LanguageToggle.tsx
1083
1207
  var import_jsx_runtime = require("react/jsx-runtime");
1208
+ function LanguageToggle({ languages, value, onChange }) {
1209
+ const activeIdx = Math.max(0, languages.findIndex((l) => l.code === value));
1210
+ const n = languages.length || 1;
1211
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: styles.langToggleTrack, children: [
1212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1213
+ "div",
1214
+ {
1215
+ style: {
1216
+ ...styles.langToggleThumb,
1217
+ width: `calc(${100 / n}% - 3px)`,
1218
+ transform: `translateX(calc(${activeIdx * 100}% + ${activeIdx * 3}px))`
1219
+ }
1220
+ }
1221
+ ),
1222
+ languages.map((l) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1223
+ "button",
1224
+ {
1225
+ type: "button",
1226
+ style: l.code === value ? styles.langToggleBtnActive : styles.langToggleBtn,
1227
+ onClick: () => onChange(l.code),
1228
+ children: l.label
1229
+ },
1230
+ l.code
1231
+ ))
1232
+ ] });
1233
+ }
1234
+
1235
+ // src/components/Toolbar.tsx
1236
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1237
+ function Toolbar({
1238
+ title,
1239
+ language,
1240
+ languages,
1241
+ mode,
1242
+ saveState,
1243
+ chrome,
1244
+ features,
1245
+ savedFormsCount,
1246
+ onTitleChange,
1247
+ onLanguageChange,
1248
+ onModeChange,
1249
+ onNewForm,
1250
+ onOpenLibrary,
1251
+ onSaveExisting,
1252
+ onOpenJson
1253
+ }) {
1254
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.toolbar, children: [
1255
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.toolbarLeft, children: [
1256
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.logoMark, children: "FB" }),
1257
+ features.naming ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { value: t(title, language), onChange: (e) => onTitleChange(e.target.value), style: styles.titleInput, "aria-label": "Form title" }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.titleInput, children: t(title, language) })
1258
+ ] }),
1259
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: styles.toolbarRight, children: [
1260
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: styles.saveStatus, children: [
1261
+ saveState === "saving" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1262
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Loader2, { size: 12, className: "spin" }),
1263
+ " ",
1264
+ chrome.saving
1265
+ ] }),
1266
+ saveState === "saved" && chrome.saved,
1267
+ saveState === "error" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: "var(--fb-danger)", display: "flex", alignItems: "center", gap: 4 }, children: [
1268
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.AlertCircle, { size: 12 }),
1269
+ " ",
1270
+ chrome.saveFailed
1271
+ ] })
1272
+ ] }),
1273
+ features.languageSwitcher && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1274
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.toolbarDivider }),
1275
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LanguageToggle, { languages, value: language, onChange: onLanguageChange })
1276
+ ] }),
1277
+ features.previewMode && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1278
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.toolbarDivider }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: mode === "build" ? styles.tabBtnActive : styles.tabBtn, onClick: () => onModeChange("build"), children: [
1280
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Pencil, { size: 14 }),
1281
+ " ",
1282
+ chrome.build
1283
+ ] }),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: mode === "preview" ? styles.tabBtnActive : styles.tabBtn, onClick: () => onModeChange("preview"), children: [
1285
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Eye, { size: 14 }),
1286
+ " ",
1287
+ chrome.preview
1288
+ ] })
1289
+ ] }),
1290
+ (features.newForm || features.templates) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: styles.toolbarDivider }),
1291
+ features.newForm && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: styles.ghostBtn, onClick: onNewForm, title: chrome.startNewForm, children: [
1292
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.FilePlus2, { size: 14 }),
1293
+ " ",
1294
+ chrome.newForm
1295
+ ] }),
1296
+ features.templates && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1297
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: styles.ghostBtn, onClick: onOpenLibrary, title: chrome.openTemplatesTitle, children: [
1298
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.FolderOpen, { size: 14 }),
1299
+ " ",
1300
+ chrome.templates,
1301
+ savedFormsCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: styles.countBadge, children: savedFormsCount })
1302
+ ] }),
1303
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: styles.primaryBtn, onClick: onSaveExisting, title: chrome.saveToLibraryTitle, children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Save, { size: 14 }),
1305
+ " ",
1306
+ chrome.save
1307
+ ] })
1308
+ ] }),
1309
+ features.jsonView && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { style: styles.ghostBtn, onClick: onOpenJson, children: [
1310
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_lucide_react2.Code2, { size: 14 }),
1311
+ " ",
1312
+ chrome.viewJson
1313
+ ] })
1314
+ ] })
1315
+ ] });
1316
+ }
1317
+
1318
+ // src/components/Palette.tsx
1319
+ var import_react5 = require("react");
1320
+ var import_lucide_react5 = require("lucide-react");
1321
+
1322
+ // src/components/Segmented.tsx
1323
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1084
1324
  function Segmented({ options, value, onChange }) {
1085
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: styles.segmented, children: options.map((opt) => {
1325
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: styles.segmented, children: options.map((opt) => {
1086
1326
  const Icon = opt.icon;
1087
1327
  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 }),
1328
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", style: active ? styles.segmentedBtnActive : styles.segmentedBtn, onClick: () => onChange(opt.value), children: [
1329
+ Icon && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Icon, { size: 13 }),
1090
1330
  opt.label
1091
1331
  ] }, opt.value);
1092
1332
  }) });
1093
1333
  }
1094
1334
 
1095
- // src/components/LayoutPopover.tsx
1096
- var import_react5 = require("react");
1097
- var import_lucide_react3 = require("lucide-react");
1335
+ // src/components/DesignPanel.tsx
1336
+ var import_lucide_react4 = require("lucide-react");
1098
1337
 
1099
1338
  // src/constants/colors.ts
1100
1339
  var COLOR_SWATCHES = ["", "#1B1E24", "#5B5FEF", "#C4432E", "#0EA5A4", "#D97706"];
@@ -1102,7 +1341,7 @@ var SECTION_BG_SWATCHES = ["", "#FFFFFF", "#F5F6F8", "#EEF0FF", "#FDF4E7", "#E9F
1102
1341
  var BUTTON_COLOR_SWATCHES = ["", "#5B5FEF", "#0EA5A4", "#D97706", "#C4432E", "#1B1E24"];
1103
1342
 
1104
1343
  // src/constants/layout.ts
1105
- var import_lucide_react2 = require("lucide-react");
1344
+ var import_lucide_react3 = require("lucide-react");
1106
1345
  var WIDTH_OPTIONS = [
1107
1346
  { value: "1/3", label: "1/3" },
1108
1347
  { value: "1/2", label: "1/2" },
@@ -1117,201 +1356,125 @@ function effectiveWidth(width, device) {
1117
1356
  }
1118
1357
  var SPACING_FIELDS = [
1119
1358
  { key: "pagePadding", labelKey: "spacingPagePadding" },
1120
- { key: "canvasPadding", labelKey: "spacingCanvasPadding" },
1121
1359
  { key: "sectionGap", labelKey: "spacingSectionGap" },
1122
- { key: "fieldGap", labelKey: "spacingFieldGap" },
1123
- { key: "toolbarPadding", labelKey: "spacingToolbarPadding" },
1124
- { key: "panelPadding", labelKey: "spacingPanelPadding" },
1125
- { key: "ticketPadding", labelKey: "spacingTicketPadding" }
1360
+ { key: "fieldGap", labelKey: "spacingFieldGap" }
1126
1361
  ];
1127
1362
  function buildDeviceOptions(baseMaxWidth, chrome) {
1128
1363
  const mw = Number(baseMaxWidth) > 0 ? baseMaxWidth : DEFAULT_THEME.layout.maxWidth;
1129
1364
  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) }
1365
+ { value: "laptop", label: chrome.deviceLaptop, icon: import_lucide_react3.Monitor, maxWidth: mw },
1366
+ { value: "tablet", label: chrome.deviceTablet, icon: import_lucide_react3.Tablet, maxWidth: Math.min(mw, 480) },
1367
+ { value: "mobile", label: chrome.deviceMobile, icon: import_lucide_react3.Smartphone, maxWidth: Math.min(mw, 340) }
1133
1368
  ];
1134
1369
  }
1135
1370
 
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
- ] })
1371
+ // src/components/DesignPanel.tsx
1372
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1373
+ function DesignPanel({ chrome, theme, updateThemeColor, updateThemeLayout, resetTheme }) {
1374
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
1375
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.layoutPanelHeader, children: [
1376
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { fontWeight: 600, fontSize: 13 }, children: chrome.theme }),
1377
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", style: styles.resetLinkBtn, onClick: resetTheme, children: [
1378
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react4.RotateCcw, { size: 11 }),
1379
+ " ",
1380
+ chrome.reset
1381
+ ] })
1382
+ ] }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.propLabel, children: chrome.primaryColor }),
1384
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.swatchRow, children: [
1385
+ 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)),
1386
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "color", value: theme.primary, onChange: (e) => updateThemeColor("primary", e.target.value), style: styles.colorPickerInput })
1387
+ ] }),
1388
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.propLabel, children: chrome.pageBackground }),
1389
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.swatchRow, children: [
1390
+ 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)),
1391
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "color", value: theme.pageBackground, onChange: (e) => updateThemeColor("pageBackground", e.target.value), style: styles.colorPickerInput })
1392
+ ] }),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { style: styles.propLabel, children: chrome.maxWidthPx }),
1394
+ /* @__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) }),
1395
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.inspectorDivider }),
1396
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: styles.panelHeading, children: chrome.spacing }),
1397
+ SPACING_FIELDS.map(({ key, labelKey }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: styles.spacingRow, children: [
1398
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: styles.spacingLabel, children: chrome[labelKey] }),
1399
+ /* @__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) })
1400
+ ] }, key))
1174
1401
  ] });
1175
1402
  }
1176
1403
 
1177
- // src/components/Toolbar.tsx
1178
- var import_jsx_runtime3 = require("react/jsx-runtime");
1179
- function Toolbar({
1180
- title,
1181
- language,
1182
- languages,
1183
- mode,
1184
- saveState,
1404
+ // src/components/Palette.tsx
1405
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1406
+ function Palette({
1407
+ activeSectionLabel,
1185
1408
  chrome,
1186
- themeEditable,
1409
+ onAddField,
1410
+ features,
1187
1411
  theme,
1188
- savedFormsCount,
1189
- onTitleChange,
1190
- onLanguageChange,
1191
- onModeChange,
1192
- onOpenSettings,
1193
- onNewForm,
1194
- onOpenLibrary,
1195
- onSaveExisting,
1196
- onOpenJson,
1197
1412
  updateThemeColor,
1198
1413
  updateThemeLayout,
1199
1414
  resetTheme
1200
1415
  }) {
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" })
1205
- ] }),
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" }),
1210
- " ",
1211
- chrome.saving
1212
- ] }),
1213
- 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
- " ",
1217
- chrome.saveFailed
1218
- ] })
1219
- ] }),
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 }),
1226
- " ",
1227
- chrome.build
1228
- ] }),
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 }),
1231
- " ",
1232
- chrome.preview
1233
- ] }),
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 }),
1239
- " ",
1240
- chrome.newForm
1241
- ] }),
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 }),
1416
+ const [tab, setTab] = (0, import_react5.useState)("blocks");
1417
+ const contentTypes = CONTENT_TYPES.filter((f) => isContentBlockEnabled(features, f.type));
1418
+ const formTypes = FORM_TYPES.filter((f) => isFieldTypeEnabled(features, f.type));
1419
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "fb-palette", style: styles.palette, children: [
1420
+ features.design && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { marginBottom: 14 }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1421
+ Segmented,
1422
+ {
1423
+ options: [
1424
+ { value: "blocks", label: chrome.paletteTabBlocks },
1425
+ { value: "design", label: chrome.paletteTabDesign }
1426
+ ],
1427
+ value: tab,
1428
+ onChange: setTab
1429
+ }
1430
+ ) }),
1431
+ tab === "design" && features.design ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1432
+ DesignPanel,
1433
+ {
1434
+ chrome,
1435
+ theme,
1436
+ updateThemeColor,
1437
+ updateThemeLayout,
1438
+ resetTheme
1439
+ }
1440
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1441
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: styles.activeSectionHint, children: [
1442
+ chrome.addingTo,
1244
1443
  " ",
1245
- chrome.myForms,
1246
- savedFormsCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: styles.countBadge, children: savedFormsCount })
1444
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: activeSectionLabel })
1247
1445
  ] }),
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 }),
1250
- " ",
1251
- chrome.save
1446
+ contentTypes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1447
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.panelHeading, children: chrome.contentBlocks }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.paletteList, children: contentTypes.map((f) => {
1449
+ const Icon = f.icon;
1450
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { style: styles.paletteItem, onClick: () => onAddField(f.type), children: [
1451
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { size: 16, color: "var(--fb-primary)" }),
1452
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: chrome[FIELD_TYPE_CHROME_KEY[f.type]] }),
1453
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react5.Plus, { size: 13, color: "var(--fb-muted)", style: { marginLeft: "auto" } })
1454
+ ] }, f.type);
1455
+ }) })
1252
1456
  ] }),
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 }),
1255
- " ",
1256
- chrome.viewJson
1457
+ formTypes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1458
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { ...styles.panelHeading, marginTop: 16 }, children: chrome.formFields }),
1459
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: styles.paletteList, children: formTypes.map((f) => {
1460
+ const Icon = f.icon;
1461
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { style: styles.paletteItem, onClick: () => onAddField(f.type), children: [
1462
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Icon, { size: 16, color: "var(--fb-primary)" }),
1463
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: chrome[FIELD_TYPE_CHROME_KEY[f.type]] }),
1464
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_lucide_react5.Plus, { size: 13, color: "var(--fb-muted)", style: { marginLeft: "auto" } })
1465
+ ] }, f.type);
1466
+ }) })
1257
1467
  ] })
1258
1468
  ] })
1259
1469
  ] });
1260
1470
  }
1261
1471
 
1262
- // src/components/Palette.tsx
1263
- var import_lucide_react5 = require("lucide-react");
1264
- 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 })
1271
- ] }),
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
- }) })
1290
- ] });
1291
- }
1292
-
1293
1472
  // src/components/Canvas.tsx
1294
1473
  var import_lucide_react12 = require("lucide-react");
1295
1474
 
1296
1475
  // src/components/SectionCard.tsx
1297
1476
  var import_lucide_react11 = require("lucide-react");
1298
1477
 
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
1478
  // src/components/FieldTicket.tsx
1316
1479
  var import_lucide_react10 = require("lucide-react");
1317
1480
 
@@ -1372,7 +1535,7 @@ var ICON_LIBRARY = {
1372
1535
 
1373
1536
  // src/components/fields/ImageBlock.tsx
1374
1537
  var import_lucide_react8 = require("lucide-react");
1375
- var import_jsx_runtime5 = require("react/jsx-runtime");
1538
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1376
1539
  function buildImageStyle(field) {
1377
1540
  const aspectRatio = field.shape === "banner" ? "16 / 5" : "1 / 1";
1378
1541
  return {
@@ -1386,35 +1549,58 @@ function buildImageStyle(field) {
1386
1549
  }
1387
1550
  function ImageBlock({ field, lang }) {
1388
1551
  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;
1552
+ 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)" }) });
1553
+ return field.link ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: field.link, target: "_blank", rel: "noreferrer", style: { display: "block" }, children: img }) : img;
1554
+ }
1555
+
1556
+ // src/constants/submitStyle.ts
1557
+ var SUBMIT_SIZE_OPTIONS = [
1558
+ { value: "sm", label: "S" },
1559
+ { value: "md", label: "M" },
1560
+ { value: "lg", label: "L" }
1561
+ ];
1562
+ var SUBMIT_SIZE_STYLES = {
1563
+ sm: { padding: "7px 12px", fontSize: 12.5 },
1564
+ md: { padding: "10px 16px", fontSize: 13.5 },
1565
+ lg: { padding: "13px 22px", fontSize: 15 }
1566
+ };
1567
+ function resolveSubmitStyle(style) {
1568
+ const sizeStyle = SUBMIT_SIZE_STYLES[style?.size || "md"] || SUBMIT_SIZE_STYLES.md;
1569
+ return { ...sizeStyle, background: style?.color || "var(--fb-primary)" };
1570
+ }
1571
+
1572
+ // src/components/fields/ButtonBlock.tsx
1573
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1574
+ function ButtonBlock({ field, lang, onAction }) {
1575
+ 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
1576
  }
1392
1577
 
1393
1578
  // 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 });
1579
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1580
+ function FieldBlock({ field, lang, onFieldChange, strings, chrome, error, isBuild, onButtonAction }) {
1581
+ if (field.type === "image") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ImageBlock, { field, lang });
1582
+ if (field.type === "button") return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ButtonBlock, { field, lang, onAction: onButtonAction });
1397
1583
  if (field.type === "paragraph") {
1398
1584
  const fontPx = FONT_SIZE_OPTIONS.find((f) => f.value === field.fontSize)?.px || 14;
1399
1585
  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) || "..." });
1586
+ 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
1587
  }
1402
1588
  const meta = getMeta(field.type);
1403
1589
  const IconComp = field.showIcon && field.displayIcon ? ICON_LIBRARY[field.displayIcon] : null;
1404
1590
  const isInline = field.labelPosition === "inline" && !meta.boolean;
1405
1591
  const labelText = t(field.label, lang);
1406
1592
  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: " *" })
1593
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { children: [
1594
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { display: "flex", flexDirection: isInline ? "row" : "column", alignItems: isInline ? "center" : "stretch", gap: isInline ? 10 : 6 }, children: [
1595
+ 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: [
1596
+ IconComp && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconComp, { size: 14, color: "var(--fb-muted)" }),
1597
+ labelText || (isBuild ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { fontStyle: "italic", color: "var(--fb-muted)" }, children: chrome?.untitledField || "Untitled field" }) : ""),
1598
+ field.required && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { color: "var(--fb-danger)" }, children: " *" })
1413
1599
  ] }),
1414
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flex: 1, minWidth: 0 }, children: renderInteractive(field, lang, onFieldChange, IconComp, !!error, strings) })
1600
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { flex: 1, minWidth: 0 }, children: renderInteractive(field, lang, onFieldChange, IconComp, !!error, strings) })
1415
1601
  ] }),
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 }),
1602
+ error && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.fieldError, children: [
1603
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_lucide_react9.CircleAlert, { size: 12 }),
1418
1604
  " ",
1419
1605
  error
1420
1606
  ] })
@@ -1428,40 +1614,40 @@ function renderInteractive(field, lang, onFieldChange, IconComp, hasError, strin
1428
1614
  if (field.type === "input") {
1429
1615
  switch (field.inputType) {
1430
1616
  case "number":
1431
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "number", ...common, min: field.min ?? void 0, max: field.max ?? void 0 });
1617
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "number", ...common, min: field.min ?? void 0, max: field.max ?? void 0 });
1432
1618
  case "email":
1433
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "email", ...common });
1619
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "email", ...common });
1434
1620
  case "password":
1435
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "password", ...common, maxLength: field.maxLength || void 0 });
1621
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "password", ...common, maxLength: field.maxLength || void 0 });
1436
1622
  case "phone":
1437
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "tel", ...common });
1623
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "tel", ...common });
1438
1624
  case "date":
1439
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "date", ...common });
1625
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "date", ...common });
1440
1626
  case "time":
1441
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "time", ...common });
1627
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "time", ...common });
1442
1628
  default:
1443
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "text", ...common, maxLength: field.maxLength || void 0 });
1629
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "text", ...common, maxLength: field.maxLength || void 0 });
1444
1630
  }
1445
1631
  }
1446
1632
  switch (field.type) {
1447
1633
  case "textarea":
1448
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("textarea", { ...common, rows: 3, maxLength: field.maxLength || void 0 });
1634
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("textarea", { ...common, rows: 3, maxLength: field.maxLength || void 0 });
1449
1635
  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))
1636
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("select", { style: inputStyle, value: value || "", onChange: (e) => set(e.target.value), children: [
1637
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: "", children: strings.selectPlaceholder }),
1638
+ (field.options || []).map((o) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("option", { value: o.value, children: t(o.label, lang) }, o.value))
1453
1639
  ] });
1454
1640
  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) }),
1641
+ 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: [
1642
+ /* @__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
1643
  t(o.label, lang)
1458
1644
  ] }, o.value)) });
1459
1645
  case "checkboxGroup": {
1460
1646
  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) => {
1647
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { display: "flex", gap: 16, flexWrap: "wrap", marginTop: 4 }, children: (field.options || []).map((o) => {
1462
1648
  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) => {
1649
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: styles.previewRadio, children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked, onChange: (e) => {
1465
1651
  const next = e.target.checked ? [...vals, o.value] : vals.filter((v) => v !== o.value);
1466
1652
  set(next);
1467
1653
  }, style: { accentColor: "var(--fb-primary)" } }),
@@ -1470,25 +1656,25 @@ function renderInteractive(field, lang, onFieldChange, IconComp, hasError, strin
1470
1656
  }) });
1471
1657
  }
1472
1658
  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" }),
1659
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: styles.previewRadio, children: [
1660
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: !!value, onChange: (e) => set(e.target.checked), style: { accentColor: "var(--fb-primary)" } }),
1661
+ IconComp && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconComp, { size: 14, color: "var(--fb-muted)" }),
1476
1662
  t(field.label, lang),
1477
- field.required && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: "var(--fb-danger)" }, children: " *" })
1663
+ field.required && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { color: "var(--fb-danger)" }, children: " *" })
1478
1664
  ] });
1479
1665
  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" }),
1666
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: styles.previewRadio, children: [
1667
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: !!value, onChange: (e) => set(e.target.checked), style: { accentColor: "var(--fb-primary)" } }),
1668
+ IconComp && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(IconComp, { size: 14, color: "var(--fb-muted)" }),
1483
1669
  t(field.label, lang)
1484
1670
  ] });
1485
1671
  default:
1486
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { type: "text", ...common });
1672
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "text", ...common });
1487
1673
  }
1488
1674
  }
1489
1675
 
1490
1676
  // src/components/FieldTicket.tsx
1491
- var import_jsx_runtime7 = require("react/jsx-runtime");
1677
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1492
1678
  function FieldTicket({
1493
1679
  field,
1494
1680
  idx,
@@ -1497,6 +1683,7 @@ function FieldTicket({
1497
1683
  chrome,
1498
1684
  strings,
1499
1685
  language,
1686
+ dragEnabled,
1500
1687
  onSelect,
1501
1688
  onFieldChange,
1502
1689
  onMoveField,
@@ -1508,7 +1695,7 @@ function FieldTicket({
1508
1695
  const meta = getMeta(field.type);
1509
1696
  const Icon = meta.icon;
1510
1697
  const widthPct = WIDTH_PERCENT[field.width || "1/1"];
1511
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1698
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1512
1699
  "div",
1513
1700
  {
1514
1701
  ...dropZoneHandlers,
@@ -1522,35 +1709,35 @@ function FieldTicket({
1522
1709
  ...isDragOver ? styles.ticketDragOver : {}
1523
1710
  },
1524
1711
  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: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.ticketIndex, children: String(idx + 1).padStart(2, "0") }),
1713
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.ticketPerforation }),
1714
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.ticketBody, children: [
1715
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.ticketTop, children: [
1716
+ dragEnabled && /* @__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: "var(--fb-muted)" }) }),
1717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { size: 13, color: "var(--fb-primary)" }),
1718
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: styles.typeBadge, children: [
1532
1719
  chrome[FIELD_TYPE_CHROME_KEY[field.type]] || field.type,
1533
1720
  field.type === "input" && field.inputType && field.inputType !== "text" ? ` \xB7 ${chrome[INPUT_SUBTYPE_CHROME_KEY[field.inputType]]}` : ""
1534
1721
  ] }),
1535
- field.required && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.requiredBadge, children: chrome.required })
1722
+ field.required && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.requiredBadge, children: chrome.required })
1536
1723
  ] }),
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: [
1724
+ 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: [
1725
+ field.width && field.width !== "1/1" && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: styles.miniBadge, children: [
1539
1726
  chrome.width,
1540
1727
  " ",
1541
1728
  field.width
1542
1729
  ] }),
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 })
1730
+ field.labelPosition === "inline" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.miniBadge, children: chrome.inline }),
1731
+ field.verticalAlign !== "top" && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.miniBadge, children: chrome[field.verticalAlign] }),
1732
+ field.hideLabel && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.miniBadge, children: chrome.hideLabel })
1546
1733
  ] }) : 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 }) })
1734
+ /* @__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
1735
  ] }),
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 }) })
1736
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.ticketActions, onClick: (e) => e.stopPropagation(), children: [
1737
+ /* @__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 }) }),
1738
+ /* @__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 }) }),
1739
+ /* @__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 }) }),
1740
+ /* @__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
1741
  ] })
1555
1742
  ]
1556
1743
  }
@@ -1558,19 +1745,18 @@ function FieldTicket({
1558
1745
  }
1559
1746
 
1560
1747
  // src/components/SectionCard.tsx
1561
- var import_jsx_runtime8 = require("react/jsx-runtime");
1748
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1562
1749
  function SectionCard({
1563
1750
  section,
1564
1751
  sIdx,
1565
1752
  sectionsLength,
1566
1753
  isActive,
1567
- submitMode,
1568
- submitStyle,
1569
1754
  selectedId,
1570
1755
  dragOverKey,
1571
1756
  chrome,
1572
1757
  strings,
1573
1758
  language,
1759
+ features,
1574
1760
  onActivate,
1575
1761
  onToggleCollapse,
1576
1762
  onUpdateTitle,
@@ -1578,8 +1764,6 @@ function SectionCard({
1578
1764
  onDuplicateSection,
1579
1765
  onMoveSection,
1580
1766
  onDeleteSection,
1581
- onUpdateSectionSubmitStyle,
1582
- onClearSectionSubmitStyle,
1583
1767
  onSelectField,
1584
1768
  onFieldChange,
1585
1769
  onMoveField,
@@ -1588,19 +1772,19 @@ function SectionCard({
1588
1772
  getDropZoneHandlers,
1589
1773
  getDragHandleProps
1590
1774
  }) {
1591
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1775
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1592
1776
  "div",
1593
1777
  {
1594
1778
  style: { ...styles.sectionBlock, background: section.background || "transparent", border: isActive ? "1px solid var(--fb-primary)" : "1px dashed var(--fb-border)" },
1595
1779
  onClick: onActivate,
1596
1780
  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) => {
1781
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.sectionHeader, children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { style: styles.chevronBtn, onClick: (e) => {
1599
1783
  e.stopPropagation();
1600
1784
  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)(
1785
+ }, 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 }) }),
1786
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { ...styles.colorDot, background: section.background || "var(--fb-canvas)" } }),
1787
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1604
1788
  "input",
1605
1789
  {
1606
1790
  style: styles.sectionTitleInput,
@@ -1610,29 +1794,21 @@ function SectionCard({
1610
1794
  onClick: (e) => e.stopPropagation()
1611
1795
  }
1612
1796
  ),
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 })
1797
+ section.collapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.miniBadge, children: chrome.fieldsCount(section.fields.length) }),
1798
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.sectionHeaderActions, onClick: (e) => e.stopPropagation(), children: [
1799
+ features.sections && !section.collapsed && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.swatchRow, children: [
1800
+ 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")),
1801
+ /* @__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
1802
  ] }),
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
1803
+ features.sections && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1804
+ /* @__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 }) }),
1805
+ /* @__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 }) }),
1806
+ /* @__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 }) }),
1807
+ /* @__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 }) })
1808
+ ] })
1633
1809
  ] })
1634
1810
  ] }),
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)(
1811
+ !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
1812
  FieldTicket,
1637
1813
  {
1638
1814
  field,
@@ -1643,6 +1819,7 @@ function SectionCard({
1643
1819
  chrome,
1644
1820
  strings,
1645
1821
  language,
1822
+ dragEnabled: features.dragReorder,
1646
1823
  onSelect: () => onSelectField(field.id),
1647
1824
  onFieldChange,
1648
1825
  onMoveField,
@@ -1659,17 +1836,16 @@ function SectionCard({
1659
1836
  }
1660
1837
 
1661
1838
  // src/components/Canvas.tsx
1662
- var import_jsx_runtime9 = require("react/jsx-runtime");
1839
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1663
1840
  function Canvas({
1664
1841
  sections,
1665
1842
  activeSectionId,
1666
- submitMode,
1667
- submitStyle,
1668
1843
  selectedId,
1669
1844
  dragOverKey,
1670
1845
  chrome,
1671
1846
  strings,
1672
1847
  language,
1848
+ features,
1673
1849
  onActivateSection,
1674
1850
  onToggleSectionCollapse,
1675
1851
  onUpdateSectionTitle,
@@ -1677,8 +1853,6 @@ function Canvas({
1677
1853
  onDuplicateSection,
1678
1854
  onMoveSection,
1679
1855
  onDeleteSection,
1680
- onUpdateSectionSubmitStyle,
1681
- onClearSectionSubmitStyle,
1682
1856
  onAddSection,
1683
1857
  onSelectField,
1684
1858
  onFieldChange,
@@ -1688,21 +1862,20 @@ function Canvas({
1688
1862
  getDropZoneHandlers,
1689
1863
  getDragHandleProps
1690
1864
  }) {
1691
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.canvas, children: [
1692
- sections.map((section, sIdx) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1865
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "fb-canvas", style: styles.canvas, children: [
1866
+ sections.map((section, sIdx) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1693
1867
  SectionCard,
1694
1868
  {
1695
1869
  section,
1696
1870
  sIdx,
1697
1871
  sectionsLength: sections.length,
1698
1872
  isActive: activeSectionId === section.id,
1699
- submitMode,
1700
- submitStyle,
1701
1873
  selectedId,
1702
1874
  dragOverKey,
1703
1875
  chrome,
1704
1876
  strings,
1705
1877
  language,
1878
+ features,
1706
1879
  onActivate: () => onActivateSection(section.id),
1707
1880
  onToggleCollapse: () => onToggleSectionCollapse(section.id),
1708
1881
  onUpdateTitle: (value) => onUpdateSectionTitle(section.id, value),
@@ -1710,8 +1883,6 @@ function Canvas({
1710
1883
  onDuplicateSection: () => onDuplicateSection(section.id),
1711
1884
  onMoveSection: (dir) => onMoveSection(section.id, dir),
1712
1885
  onDeleteSection: () => onDeleteSection(section.id),
1713
- onUpdateSectionSubmitStyle: (patch) => onUpdateSectionSubmitStyle(section.id, patch),
1714
- onClearSectionSubmitStyle: () => onClearSectionSubmitStyle(section.id),
1715
1886
  onSelectField: (fieldId) => onSelectField(section.id, fieldId),
1716
1887
  onFieldChange,
1717
1888
  onMoveField,
@@ -1722,8 +1893,8 @@ function Canvas({
1722
1893
  },
1723
1894
  section.id
1724
1895
  )),
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 }),
1896
+ features.sections && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { style: styles.addSectionBtn, onClick: onAddSection, children: [
1897
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_lucide_react12.Layers, { size: 14 }),
1727
1898
  " ",
1728
1899
  chrome.addSection
1729
1900
  ] })
@@ -1734,27 +1905,27 @@ function Canvas({
1734
1905
  var import_lucide_react13 = require("lucide-react");
1735
1906
 
1736
1907
  // src/components/fields/DefaultValueEditor.tsx
1737
- var import_jsx_runtime10 = require("react/jsx-runtime");
1908
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1738
1909
  function DefaultValueEditor({ field, meta, lang, chrome, onChange }) {
1739
1910
  if (meta.isContent) return null;
1740
1911
  const f = field;
1741
1912
  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 })
1913
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1914
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { style: styles.propLabel, children: chrome.defaultValue }),
1915
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { style: styles.toggleRow, onClick: () => onChange({ defaultValue: !f.defaultValue }), children: [
1916
+ /* @__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)" } }) }),
1917
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 13, color: "var(--fb-ink)" }, children: f.defaultValue ? chrome.checked : chrome.unchecked })
1747
1918
  ] })
1748
1919
  ] });
1749
1920
  }
1750
1921
  if (meta.multiValue) {
1751
1922
  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) => {
1923
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1924
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { style: styles.propLabel, children: chrome.defaultChecked }),
1925
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: styles.optionList, children: (f.options || []).map((o) => {
1755
1926
  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) => {
1927
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("label", { style: { ...styles.previewRadio, cursor: "pointer" }, children: [
1928
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: "checkbox", checked, onChange: (e) => {
1758
1929
  const next = e.target.checked ? [...selectedVals, o.value] : selectedVals.filter((v) => v !== o.value);
1759
1930
  onChange({ defaultValue: next });
1760
1931
  }, style: { accentColor: "var(--fb-primary)" } }),
@@ -1764,32 +1935,33 @@ function DefaultValueEditor({ field, meta, lang, chrome, onChange }) {
1764
1935
  ] });
1765
1936
  }
1766
1937
  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))
1938
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1939
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { style: styles.propLabel, children: chrome.defaultValue }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("select", { style: styles.propInput, value: f.defaultValue || "", onChange: (e) => onChange({ defaultValue: e.target.value }), children: [
1941
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "", children: chrome.none }),
1942
+ (f.options || []).map((o) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: o.value, children: t(o.label, lang) }, o.value))
1772
1943
  ] })
1773
1944
  ] });
1774
1945
  }
1775
1946
  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 }) })
1947
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1948
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("label", { style: styles.propLabel, children: chrome.defaultValue }),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("input", { type: htmlType, style: styles.propInput, value: f.defaultValue || "", onChange: (e) => onChange({ defaultValue: e.target.value }) })
1779
1950
  ] });
1780
1951
  }
1781
1952
 
1782
1953
  // src/components/Inspector.tsx
1783
- var import_jsx_runtime11 = require("react/jsx-runtime");
1784
- 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)(
1954
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1955
+ function Inspector({ selected, language, chrome, features, onUpdateField, onDeleteField, onUpdateOption, onAddOption, onRemoveOption }) {
1956
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "fb-inspector", style: styles.inspector, children: [
1957
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.panelHeading, children: chrome.properties }),
1958
+ !selected ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.inspectorEmpty, children: chrome.selectFieldHint }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1788
1959
  InspectorBody,
1789
1960
  {
1790
1961
  selected,
1791
1962
  language,
1792
1963
  chrome,
1964
+ features,
1793
1965
  onUpdateField,
1794
1966
  onDeleteField,
1795
1967
  onUpdateOption,
@@ -1799,119 +1971,145 @@ function Inspector({ selected, language, chrome, onUpdateField, onDeleteField, o
1799
1971
  )
1800
1972
  ] });
1801
1973
  }
1802
- function InspectorBody({ selected, language, chrome, onUpdateField, onDeleteField, onUpdateOption, onAddOption, onRemoveOption }) {
1974
+ function InspectorBody({ selected, language, chrome, features, onUpdateField, onDeleteField, onUpdateOption, onAddOption, onRemoveOption }) {
1803
1975
  const meta = getMeta(selected.type);
1804
1976
  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 })
1977
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.inspectorBody, children: [
1978
+ (!meta.isContent || selected.type === "button") && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1979
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: selected.type === "button" ? chrome.buttonText : chrome.label }),
1980
+ /* @__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) }) }),
1981
+ !meta.isContent && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: styles.toggleRow, children: [
1982
+ /* @__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)" } }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 13, color: "var(--fb-ink)" }, children: chrome.hideLabel })
1812
1984
  ] })
1813
1985
  ] }),
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)) })
1986
+ meta.hasSubtype && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1987
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.inputType }),
1988
+ /* @__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
1989
  ] }),
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 }) })
1831
- ] }),
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 })
1990
+ selected.type === "paragraph" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1991
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.content }),
1992
+ /* @__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) }) }),
1993
+ features.blockStyling && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1994
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.inspectorDivider }),
1995
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.panelHeading, children: chrome.typography }),
1996
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.headingStyle }),
1997
+ /* @__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] }) }),
1998
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.width }),
1999
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Segmented, { options: FONT_SIZE_OPTIONS, value: selected.fontSize || "md", onChange: (v) => onUpdateField({ fontSize: v }) }),
2000
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.style }),
2001
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.styleToggleRow, children: [
2002
+ /* @__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 }) }),
2003
+ /* @__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 }) })
2004
+ ] }),
2005
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.align }),
2006
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Segmented, { options: TEXT_ALIGN_OPTIONS, value: selected.textAlign || "left", onChange: (v) => onUpdateField({ textAlign: v }) }),
2007
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.color }),
2008
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.swatchRow, children: [
2009
+ 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")),
2010
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { type: "color", value: selected.color || "#1B1E24", onChange: (e) => onUpdateField({ color: e.target.value }), style: styles.colorPickerInput })
2011
+ ] })
1838
2012
  ] })
1839
2013
  ] }),
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." })
2014
+ selected.type === "image" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2015
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.imageUrl }),
2016
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { style: styles.propInput, placeholder: "https://...", value: selected.src || "", onChange: (e) => onUpdateField({ src: e.target.value }) }),
2017
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.helperText, children: chrome.imageUrlHelper }),
2018
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.altText }),
2019
+ /* @__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) }) }),
2020
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.linkOptional }),
2021
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { style: styles.propInput, placeholder: "https://...", value: selected.link || "", onChange: (e) => onUpdateField({ link: e.target.value }) }),
2022
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.shape }),
2023
+ /* @__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 }) }),
2024
+ /* @__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." })
1851
2025
  ] }),
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) }) })
2026
+ selected.type === "button" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2027
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.inspectorDivider }),
2028
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.panelHeading, children: chrome.buttonActionTitle }),
2029
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.buttonAction }),
2030
+ /* @__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 }) }),
2031
+ selected.action === "link" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2032
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.linkOptional }),
2033
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("input", { style: styles.propInput, placeholder: "https://...", value: selected.href || "", onChange: (e) => onUpdateField({ href: e.target.value }) }),
2034
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.openIn }),
2035
+ /* @__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 }) })
2036
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2037
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.submitScope }),
2038
+ /* @__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 }) })
2039
+ ] }),
2040
+ features.blockStyling && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2041
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.color }),
2042
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.swatchRow, children: [
2043
+ 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")),
2044
+ /* @__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 })
2045
+ ] }),
2046
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.buttonSize }),
2047
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Segmented, { options: SUBMIT_SIZE_OPTIONS, value: selected.buttonStyle?.size || "md", onChange: (v) => onUpdateField({ buttonStyle: { ...selected.buttonStyle, size: v } }) })
2048
+ ] })
2049
+ ] }),
2050
+ meta.placeholder && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2051
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.placeholder }),
2052
+ /* @__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
2053
  ] }),
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 }) })
2054
+ selected.type === "input" && (selected.inputType === "text" || selected.inputType === "password" || !selected.inputType) && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2055
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.maxLength }),
2056
+ /* @__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
2057
  ] }),
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) }) })
2058
+ selected.type === "input" && selected.inputType === "number" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2059
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.minValue }),
2060
+ /* @__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) }) }),
2061
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.maxValue }),
2062
+ /* @__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
2063
  ] }),
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 }) })
2064
+ selected.type === "textarea" && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2065
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.maxLength }),
2066
+ /* @__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
2067
  ] }),
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 }) })
2068
+ meta.options && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2069
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.options }),
2070
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.optionList, children: [
2071
+ (f.options || []).map((opt, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.optionRow, children: [
2072
+ /* @__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) }) }),
2073
+ /* @__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
2074
  ] }, 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 }),
2075
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { style: styles.addOptionBtn, onClick: onAddOption, children: [
2076
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react13.Plus, { size: 13 }),
1879
2077
  " ",
1880
2078
  chrome.addOption
1881
2079
  ] })
1882
2080
  ] })
1883
2081
  ] }),
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 })
2082
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DefaultValueEditor, { field: selected, meta, lang: language, chrome, onChange: onUpdateField }),
2083
+ !meta.isContent && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: styles.toggleRow, children: [
2084
+ /* @__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)" } }),
2085
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 13, color: "var(--fb-ink)" }, children: chrome.requiredField })
1888
2086
  ] }),
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 }) })
2087
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.inspectorDivider }),
2088
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.panelHeading, children: chrome.layout }),
2089
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.width }),
2090
+ /* @__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 }) }),
2091
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.verticalAlign }),
2092
+ /* @__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 }) }),
2093
+ !meta.boolean && !meta.isContent && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2094
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: styles.propLabel, children: chrome.labelPosition }),
2095
+ /* @__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
2096
  ] }),
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 })
2097
+ !meta.isContent && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2098
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.inspectorDivider }),
2099
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.panelHeading, children: chrome.icon }),
2100
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("label", { style: styles.toggleRow, children: [
2101
+ /* @__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)" } }),
2102
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 13, color: "var(--fb-ink)" }, children: chrome.showIcon })
1905
2103
  ] }),
1906
- selected.showIcon && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.iconGrid, children: Object.keys(ICON_LIBRARY).map((key) => {
2104
+ selected.showIcon && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.iconGrid, children: Object.keys(ICON_LIBRARY).map((key) => {
1907
2105
  const IconComp = ICON_LIBRARY[key];
1908
2106
  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);
2107
+ 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
2108
  }) })
1911
2109
  ] }),
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 }),
2110
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.inspectorDivider }),
2111
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { style: styles.deleteFieldBtn, onClick: onDeleteField, children: [
2112
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react13.Trash2, { size: 13 }),
1915
2113
  " ",
1916
2114
  chrome.deleteField
1917
2115
  ] })
@@ -1955,17 +2153,26 @@ function formatValue(field, lang) {
1955
2153
  return String(v);
1956
2154
  }
1957
2155
 
2156
+ // src/lib/collectSubmission.ts
2157
+ function collectFieldValues(fields) {
2158
+ const values = {};
2159
+ fields.forEach((f) => {
2160
+ if (getMeta(f.type).isContent) return;
2161
+ values[f.id] = f.defaultValue;
2162
+ });
2163
+ return values;
2164
+ }
2165
+
1958
2166
  // 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 }) {
2167
+ var import_jsx_runtime14 = require("react/jsx-runtime");
2168
+ function PreviewPane({ title, sections, onFieldChange, language, strings, chrome, baseMaxWidth, onSubmit }) {
1961
2169
  const [device, setDevice] = (0, import_react6.useState)("laptop");
1962
2170
  const [errors, setErrors] = (0, import_react6.useState)({});
1963
2171
  const [submitted, setSubmitted] = (0, import_react6.useState)(null);
2172
+ const [attemptedButtonId, setAttemptedButtonId] = (0, import_react6.useState)(null);
1964
2173
  const deviceOptions = buildDeviceOptions(baseMaxWidth, chrome);
1965
2174
  const maxWidth = (deviceOptions.find((d) => d.value === device) || deviceOptions[0]).maxWidth;
1966
2175
  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
2176
  function runValidation(fields) {
1970
2177
  const errs = {};
1971
2178
  fields.forEach((f) => {
@@ -1974,78 +2181,92 @@ function PreviewPane({ title, sections, onFieldChange, language, strings, chrome
1974
2181
  });
1975
2182
  return errs;
1976
2183
  }
1977
- function handleSubmitAll() {
2184
+ function buildSectionsBreakdown() {
2185
+ return sections.map((s) => ({ sectionId: s.id, values: collectFieldValues(s.fields) }));
2186
+ }
2187
+ function handleSubmitAll(buttonId) {
1978
2188
  const errs = runValidation(allFields);
1979
2189
  setErrors(errs);
2190
+ setAttemptedButtonId(buttonId);
1980
2191
  if (Object.keys(errs).length > 0) {
1981
2192
  setSubmitted(null);
1982
2193
  return;
1983
2194
  }
1984
2195
  setSubmitted(allFields.filter((f) => !getMeta(f.type).isContent).map((f) => ({ label: t(f.label, language), value: formatValue(f, language) })));
2196
+ const sectionsBreakdown = buildSectionsBreakdown();
2197
+ const all = collectFieldValues(allFields);
2198
+ onSubmit?.({ buttonId, scope: "form", values: all, sections: sectionsBreakdown, all });
1985
2199
  }
1986
- function handleSubmitSection(section) {
2200
+ function handleSubmitSection(section, buttonId) {
1987
2201
  const errs = runValidation(section.fields);
1988
2202
  setErrors((prev) => {
1989
2203
  const next = { ...prev };
1990
2204
  section.fields.forEach((f) => delete next[f.id]);
1991
2205
  return { ...next, ...errs };
1992
2206
  });
2207
+ setAttemptedButtonId(buttonId);
1993
2208
  if (Object.keys(errs).length > 0) {
1994
2209
  setSubmitted(null);
1995
2210
  return;
1996
2211
  }
1997
2212
  setSubmitted(section.fields.filter((f) => !getMeta(f.type).isContent).map((f) => ({ label: t(f.label, language), value: formatValue(f, language) })));
2213
+ const sectionsBreakdown = buildSectionsBreakdown();
2214
+ const all = collectFieldValues(allFields);
2215
+ onSubmit?.({ buttonId, scope: "section", sectionId: section.id, values: collectFieldValues(section.fields), sections: sectionsBreakdown, all });
2216
+ }
2217
+ function handleButtonAction(field) {
2218
+ if (field.action === "link") {
2219
+ if (field.href) window.open(field.href, field.target === "_blank" ? "_blank" : "_self", field.target === "_blank" ? "noopener,noreferrer" : void 0);
2220
+ return;
2221
+ }
2222
+ if (field.submitScope === "section") {
2223
+ const section = sections.find((s) => s.fields.some((f) => f.id === field.id));
2224
+ if (section) handleSubmitSection(section, field.id);
2225
+ } else {
2226
+ handleSubmitAll(field.id);
2227
+ }
1998
2228
  }
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 }),
2229
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.previewWrap, children: [
2230
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { width: "100%", maxWidth, display: "flex", flexDirection: "column", alignItems: "center" }, children: [
2231
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.previewToolbar, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Segmented, { options: deviceOptions, value: device, onChange: setDevice }) }),
2232
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { ...styles.previewCard, maxWidth, width: "100%" }, children: [
2233
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h2", { style: styles.previewTitle, children: t(title, language) }),
2234
+ allFields.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { color: "var(--fb-muted)", fontSize: 14 }, children: strings.addFieldsHint }),
2005
2235
  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) => {
2236
+ 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: [
2237
+ t(section.title, language) && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { style: styles.sectionRuntimeTitle, children: t(section.title, language) }),
2238
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.previewGrid, children: section.fields.map((field) => {
2011
2239
  const width = effectiveWidth(field.width, device);
2012
2240
  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
- ] })
2241
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { flex: flexBasis, minWidth: 0, alignSelf: ALIGN_MAP[field.verticalAlign || "top"] }, children: [
2242
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(FieldBlock, { field, lang: language, onFieldChange, strings, chrome, error: errors[field.id], onButtonAction: handleButtonAction }),
2243
+ field.type === "button" && field.id === attemptedButtonId && Object.keys(errors).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { style: styles.formErrorNote, children: [
2244
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react14.CircleAlert, { size: 13 }),
2245
+ " ",
2246
+ strings.fixErrors
2247
+ ] })
2248
+ ] }, field.id);
2249
+ }) })
2023
2250
  ] }, 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
- ] })
2251
+ })
2031
2252
  ] })
2032
2253
  ] }),
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)" }),
2254
+ 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, maxWidth: 420 }, onClick: (e) => e.stopPropagation(), children: [
2255
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.modalHeader, children: [
2256
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { style: { fontWeight: 600, fontSize: 14, display: "flex", alignItems: "center", gap: 7 }, children: [
2257
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react14.PartyPopper, { size: 15, color: "var(--fb-primary)" }),
2037
2258
  " ",
2038
2259
  strings.submittedTitle
2039
2260
  ] }),
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 }) })
2261
+ /* @__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
2262
  ] }),
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 })
2263
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { padding: 16 }, children: [
2264
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { fontSize: 12.5, color: "var(--fb-muted)", marginTop: 0 }, children: strings.submittedBody }),
2265
+ /* @__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: [
2266
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: styles.submittedLabel, children: row.label }),
2267
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: styles.submittedValue, children: row.value })
2047
2268
  ] }, i)) }),
2048
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, onClick: () => setSubmitted(null), children: strings.close })
2269
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, onClick: () => setSubmitted(null), children: strings.close })
2049
2270
  ] })
2050
2271
  ] }) })
2051
2272
  ] });
@@ -2053,47 +2274,47 @@ function PreviewPane({ title, sections, onFieldChange, language, strings, chrome
2053
2274
 
2054
2275
  // src/components/modals/JsonModal.tsx
2055
2276
  var import_lucide_react15 = require("lucide-react");
2056
- var import_jsx_runtime13 = require("react/jsx-runtime");
2277
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2057
2278
  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 }),
2279
+ 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: [
2280
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: styles.modalHeader, children: [
2281
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.formJson }),
2282
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", gap: 8 }, children: [
2283
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { style: styles.ghostBtn, onClick: onCopy, children: [
2284
+ 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
2285
  copied ? chrome.copied : chrome.copy
2065
2286
  ] }),
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 }) })
2287
+ /* @__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
2288
  ] })
2068
2289
  ] }),
2069
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("pre", { style: styles.jsonPre, children: jsonString })
2290
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("pre", { style: styles.jsonPre, children: jsonString })
2070
2291
  ] }) });
2071
2292
  }
2072
2293
 
2073
- // src/components/modals/LibraryModal.tsx
2294
+ // src/components/modals/TemplatesModal.tsx
2074
2295
  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 }) })
2296
+ var import_jsx_runtime16 = require("react/jsx-runtime");
2297
+ function TemplatesModal({ chrome, savedForms, currentFormId, onOpen, onDelete, onClose }) {
2298
+ 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: [
2299
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: styles.modalHeader, children: [
2300
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.templates }),
2301
+ /* @__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
2302
  ] }),
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: [
2303
+ /* @__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: [
2304
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { minWidth: 0 }, children: [
2305
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: styles.libraryRowTitle, children: [
2085
2306
  f.title,
2086
- f.id === currentFormId && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: styles.currentBadge, children: chrome.current })
2307
+ f.id === currentFormId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: styles.currentBadge, children: chrome.current })
2087
2308
  ] }),
2088
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.libraryRowMeta, children: [
2309
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: styles.libraryRowMeta, children: [
2089
2310
  chrome.updated,
2090
2311
  " ",
2091
2312
  new Date(f.updatedAt).toLocaleString()
2092
2313
  ] })
2093
2314
  ] }),
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 }) })
2315
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0 }, children: [
2316
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { style: styles.ghostBtn, onClick: () => onOpen(f.id), children: chrome.open }),
2317
+ /* @__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
2318
  ] })
2098
2319
  ] }, f.id)) })
2099
2320
  ] }) });
@@ -2102,19 +2323,19 @@ function LibraryModal({ chrome, savedForms, currentFormId, onOpen, onDelete, onC
2102
2323
  // src/components/modals/SaveAsModal.tsx
2103
2324
  var import_react7 = require("react");
2104
2325
  var import_lucide_react17 = require("lucide-react");
2105
- var import_jsx_runtime15 = require("react/jsx-runtime");
2326
+ var import_jsx_runtime17 = require("react/jsx-runtime");
2106
2327
  function SaveAsModal({ chrome, suggestedName, onSave, onClose }) {
2107
2328
  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 }) })
2329
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: styles.modalOverlay, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...styles.modal, maxWidth: 380 }, onClick: (e) => e.stopPropagation(), children: [
2330
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: styles.modalHeader, children: [
2331
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { fontWeight: 600, fontSize: 14 }, children: chrome.saveForm }),
2332
+ /* @__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
2333
  ] }),
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 }),
2334
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { padding: 16 }, children: [
2335
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { style: styles.propLabel, children: chrome.formName }),
2336
+ /* @__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()) }),
2337
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { style: { ...styles.primaryBtn, width: "100%", justifyContent: "center", marginTop: 14 }, disabled: !name.trim(), onClick: () => onSave(name.trim()), children: [
2338
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_lucide_react17.Save, { size: 14 }),
2118
2339
  " ",
2119
2340
  chrome.saveToLibrary
2120
2341
  ] })
@@ -2122,45 +2343,6 @@ function SaveAsModal({ chrome, suggestedName, onSave, onClose }) {
2122
2343
  ] }) });
2123
2344
  }
2124
2345
 
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
2346
  // src/styles/globalCss.ts
2165
2347
  var css = `
2166
2348
  * { box-sizing: border-box; }
@@ -2168,19 +2350,58 @@ var css = `
2168
2350
  input, textarea, select { font-family: inherit; }
2169
2351
  @keyframes fb-spin { to { transform: rotate(360deg); } }
2170
2352
  .spin { animation: fb-spin 0.8s linear infinite; }
2353
+ /* Caps the widget at the viewport height so it scrolls internally rather
2354
+ than growing past whatever space its host container gives it; the
2355
+ second declaration upgrades to the dynamic viewport unit on browsers
2356
+ that support it (mobile browser chrome resizing the viewport), and is
2357
+ simply ignored by ones that don't. */
2358
+ .fb-root { max-height: 100vh; max-height: 100dvh; }
2359
+
2360
+ /* Below this width the fixed 200px Palette + 270px Inspector columns
2361
+ don't leave room for a usable Canvas, so instead of stacking all
2362
+ three in flow (which buries Canvas under a tall Palette), Palette
2363
+ and Inspector become narrow drawers over Canvas (which stays
2364
+ partially visible behind them), toggled by .fb-mobile-bar's two
2365
+ buttons, tracked by .fb-work-area's data-mobile-panel attribute,
2366
+ and dismissible via .fb-mobile-backdrop. */
2367
+ .fb-mobile-bar { display: none; align-items: center; gap: 6px; padding: 6px 10px; border-bottom: 1px solid var(--fb-border); background: var(--fb-surface); flex-shrink: 0; }
2368
+ .fb-mobile-btn { display: flex; align-items: center; gap: 6px; padding: 6px 10px; border-radius: 7px; border: 1px solid var(--fb-border); background: var(--fb-surface); color: var(--fb-muted); font-size: 12.5px; font-weight: 600; }
2369
+ .fb-mobile-btn[aria-pressed="true"] { border-color: var(--fb-primary); background: var(--fb-primary-soft); color: var(--fb-primary); }
2370
+ .fb-mobile-backdrop { display: none; }
2371
+ @media (max-width: 720px) {
2372
+ .fb-mobile-bar { display: flex; }
2373
+ .fb-work-area { flex-direction: column !important; min-height: 0; }
2374
+ .fb-canvas-area { position: relative; overflow: hidden; }
2375
+ .fb-canvas { width: 100%; }
2376
+ .fb-mobile-backdrop { display: block; position: absolute; inset: 0; z-index: 6; background: rgba(15,16,20,0.35); }
2377
+ .fb-palette, .fb-inspector {
2378
+ position: absolute; top: 0; bottom: 0; z-index: 7;
2379
+ width: min(260px, 80vw) !important; max-height: none !important;
2380
+ border: none !important;
2381
+ box-shadow: 0 0 24px rgba(0,0,0,0.18);
2382
+ transition: transform 0.18s ease;
2383
+ }
2384
+ .fb-palette { left: 0; transform: translateX(-100%); }
2385
+ .fb-inspector { right: 0; transform: translateX(100%); }
2386
+ .fb-work-area[data-mobile-panel="palette"] .fb-palette,
2387
+ .fb-work-area[data-mobile-panel="inspector"] .fb-inspector { transform: translateX(0); }
2388
+ }
2171
2389
  `;
2172
2390
 
2173
2391
  // src/FormBuilder.tsx
2174
- var import_jsx_runtime17 = require("react/jsx-runtime");
2175
- function FormBuilder({
2392
+ var import_jsx_runtime18 = require("react/jsx-runtime");
2393
+ var FormBuilder = (0, import_react8.forwardRef)(function FormBuilder2({
2176
2394
  theme: themeOverrideProp,
2177
2395
  language: languageOverride,
2178
2396
  languages = DEFAULT_LANGUAGES,
2179
2397
  strings: stringsOverride,
2180
2398
  chrome: chromeOverride,
2181
- themeEditable = false,
2182
- storage: storageProp
2183
- } = {}) {
2399
+ features: featuresProp,
2400
+ storage: storageProp,
2401
+ onSubmit,
2402
+ initialDocument
2403
+ }, ref) {
2404
+ const features = resolveFeatures(featuresProp);
2184
2405
  const storage = storageProp ?? localStorageAdapter;
2185
2406
  const { theme, updateThemeColor, updateThemeLayout, resetTheme, replaceThemeOverrides, themeOverrides } = useTheme(themeOverrideProp);
2186
2407
  const [language, setLanguage] = (0, import_react8.useState)(languageOverride || languages[0]?.code || "en");
@@ -2190,20 +2411,16 @@ function FormBuilder({
2190
2411
  const drag = useDragReorder(doc.reorderWithinSection);
2191
2412
  const [mode, setMode] = (0, import_react8.useState)("build");
2192
2413
  const [showJson, setShowJson] = (0, import_react8.useState)(false);
2193
- const [showSettings, setShowSettings] = (0, import_react8.useState)(false);
2194
2414
  const [showLibrary, setShowLibrary] = (0, import_react8.useState)(false);
2195
2415
  const [copied, setCopied] = (0, import_react8.useState)(false);
2416
+ const [mobilePanel, setMobilePanel] = (0, import_react8.useState)("none");
2196
2417
  const persistence = usePersistence({
2197
2418
  storage,
2419
+ autosave: features.autosave,
2198
2420
  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
- },
2421
+ chrome,
2422
+ document: { title: doc.title, themeOverrides, sections: doc.sections },
2423
+ initialDocument,
2207
2424
  onLoadDocument: doc.loadDocument,
2208
2425
  onLoadThemeOverrides: replaceThemeOverrides,
2209
2426
  onTitleChange: doc.setTitle,
@@ -2214,13 +2431,11 @@ function FormBuilder({
2214
2431
  ensureActiveSection: () => doc.setActiveSectionId((prev) => prev ?? doc.sections[0]?.id ?? null)
2215
2432
  });
2216
2433
  const jsonDoc = {
2217
- version: 4,
2434
+ version: 5,
2218
2435
  title: doc.title,
2219
- submitLabel: doc.submitLabel,
2220
- submitMode: doc.submitMode,
2221
- submitStyle: doc.submitStyle,
2436
+ theme,
2222
2437
  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 }))
2438
+ sections: doc.sections.map((s) => ({ id: s.id, title: s.title, background: s.background, collapsed: s.collapsed, fields: s.fields }))
2224
2439
  };
2225
2440
  const jsonString = JSON.stringify(jsonDoc, null, 2);
2226
2441
  function copyJson() {
@@ -2230,6 +2445,17 @@ function FormBuilder({
2230
2445
  }).catch(() => {
2231
2446
  });
2232
2447
  }
2448
+ (0, import_react8.useImperativeHandle)(ref, () => ({
2449
+ getDocument: () => jsonDoc,
2450
+ exportJson: () => jsonString,
2451
+ loadDocument: (raw) => {
2452
+ const migrated = migrateDocument(raw);
2453
+ if (!migrated) return;
2454
+ doc.loadDocument(migrated);
2455
+ replaceThemeOverrides(migrated.themeOverrides);
2456
+ }
2457
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2458
+ }), [jsonDoc, jsonString]);
2233
2459
  const activeSectionIdx = doc.sections.findIndex((s) => s.id === doc.activeSection?.id);
2234
2460
  const activeSectionLabel = t(doc.activeSection?.title, language) || `#${activeSectionIdx + 1}`;
2235
2461
  const rootStyle = {
@@ -2244,6 +2470,7 @@ function FormBuilder({
2244
2470
  "--fb-surface": theme.surface,
2245
2471
  "--fb-canvas": theme.canvas,
2246
2472
  "--fb-page-bg": theme.pageBackground,
2473
+ "--fb-surface-2": mixHex(theme.surface, theme.ink, 0.06),
2247
2474
  "--fb-space-page": `${theme.layout.pagePadding}px`,
2248
2475
  "--fb-space-canvas": `${theme.layout.canvasPadding}px`,
2249
2476
  "--fb-space-section": `${theme.layout.sectionGap}px`,
@@ -2252,9 +2479,9 @@ function FormBuilder({
2252
2479
  "--fb-space-panel": `${theme.layout.panelPadding}px`,
2253
2480
  "--fb-space-ticket": `${theme.layout.ticketPadding}px`
2254
2481
  };
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)(
2482
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fb-root", style: rootStyle, children: [
2483
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("style", { children: css }),
2484
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2258
2485
  Toolbar,
2259
2486
  {
2260
2487
  title: doc.title,
@@ -2263,75 +2490,117 @@ function FormBuilder({
2263
2490
  mode,
2264
2491
  saveState: persistence.saveState,
2265
2492
  chrome,
2266
- themeEditable,
2267
- theme,
2493
+ features,
2268
2494
  savedFormsCount: persistence.savedForms.length,
2269
2495
  onTitleChange: doc.updateTitle,
2270
2496
  onLanguageChange: setLanguage,
2271
2497
  onModeChange: setMode,
2272
- onOpenSettings: () => setShowSettings(true),
2273
2498
  onNewForm: persistence.newForm,
2274
2499
  onOpenLibrary: () => setShowLibrary(true),
2275
2500
  onSaveExisting: persistence.saveExisting,
2276
- onOpenJson: () => setShowJson(true),
2277
- updateThemeColor,
2278
- updateThemeLayout,
2279
- resetTheme
2501
+ onOpenJson: () => setShowJson(true)
2280
2502
  }
2281
2503
  ),
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)(
2288
- Canvas,
2289
- {
2290
- sections: doc.sections,
2291
- activeSectionId: doc.activeSectionId,
2292
- submitMode: doc.submitMode,
2293
- submitStyle: doc.submitStyle,
2294
- selectedId: doc.selectedId,
2295
- dragOverKey: drag.dragOverKey,
2296
- chrome,
2297
- strings,
2298
- language,
2299
- onActivateSection: doc.setActiveSectionId,
2300
- onToggleSectionCollapse: doc.toggleSectionCollapse,
2301
- onUpdateSectionTitle: doc.updateSectionTitle,
2302
- onUpdateSectionBackground: doc.updateSectionBackground,
2303
- onDuplicateSection: doc.duplicateSection,
2304
- onMoveSection: doc.moveSection,
2305
- onDeleteSection: doc.deleteSection,
2306
- onUpdateSectionSubmitStyle: doc.updateSectionSubmitStyle,
2307
- onClearSectionSubmitStyle: doc.clearSectionSubmitStyle,
2308
- onAddSection: doc.addSection,
2309
- onSelectField: (sectionId, fieldId) => {
2310
- doc.setSelectedId(fieldId);
2311
- doc.setActiveSectionId(sectionId);
2312
- },
2313
- onFieldChange: doc.updateField,
2314
- onMoveField: doc.moveField,
2315
- onDuplicateField: doc.duplicateField,
2316
- onDeleteField: doc.deleteField,
2317
- getDropZoneHandlers: drag.getDropZoneHandlers,
2318
- getDragHandleProps: drag.getDragHandleProps
2319
- }
2320
- ),
2321
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2322
- Inspector,
2323
- {
2324
- selected: doc.selected,
2325
- language,
2326
- chrome,
2327
- onUpdateField: (patch) => doc.selected && doc.updateField(doc.selected.id, patch),
2328
- onDeleteField: () => doc.selected && doc.deleteField(doc.selected.id),
2329
- onUpdateOption: (optIdx, patch) => doc.selected && doc.updateOption(doc.selected.id, optIdx, patch),
2330
- onAddOption: () => doc.selected && doc.addOption(doc.selected.id),
2331
- onRemoveOption: (optIdx) => doc.selected && doc.removeOption(doc.selected.id, optIdx)
2332
- }
2333
- )
2334
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2504
+ persistence.loadingDraft ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: styles.loadingScreen, children: [
2505
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react18.Loader2, { size: 20, className: "spin" }),
2506
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { style: { marginTop: 8, fontSize: 13, color: "var(--fb-muted)" }, children: chrome.loadingDraft })
2507
+ ] }) : mode === "build" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fb-work-area", style: styles.workArea, "data-mobile-panel": mobilePanel, children: [
2508
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fb-mobile-bar", children: [
2509
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2510
+ "button",
2511
+ {
2512
+ type: "button",
2513
+ className: "fb-mobile-btn",
2514
+ "aria-pressed": mobilePanel === "palette",
2515
+ onClick: () => setMobilePanel((p) => p === "palette" ? "none" : "palette"),
2516
+ children: [
2517
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react18.Menu, { size: 14 }),
2518
+ " ",
2519
+ chrome.paletteTabBlocks
2520
+ ]
2521
+ }
2522
+ ),
2523
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
2524
+ "button",
2525
+ {
2526
+ type: "button",
2527
+ className: "fb-mobile-btn",
2528
+ "aria-pressed": mobilePanel === "inspector",
2529
+ onClick: () => setMobilePanel((p) => p === "inspector" ? "none" : "inspector"),
2530
+ children: [
2531
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_lucide_react18.SlidersHorizontal, { size: 14 }),
2532
+ " ",
2533
+ chrome.properties
2534
+ ]
2535
+ }
2536
+ )
2537
+ ] }),
2538
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "fb-canvas-area", style: styles.workArea, children: [
2539
+ mobilePanel !== "none" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "fb-mobile-backdrop", onClick: () => setMobilePanel("none") }),
2540
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2541
+ Palette,
2542
+ {
2543
+ activeSectionLabel,
2544
+ chrome,
2545
+ onAddField: (type) => {
2546
+ doc.addField(type);
2547
+ setMobilePanel("none");
2548
+ },
2549
+ features,
2550
+ theme,
2551
+ updateThemeColor,
2552
+ updateThemeLayout,
2553
+ resetTheme
2554
+ }
2555
+ ),
2556
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2557
+ Canvas,
2558
+ {
2559
+ sections: doc.sections,
2560
+ activeSectionId: doc.activeSectionId,
2561
+ selectedId: doc.selectedId,
2562
+ dragOverKey: drag.dragOverKey,
2563
+ chrome,
2564
+ strings,
2565
+ language,
2566
+ features,
2567
+ onActivateSection: doc.setActiveSectionId,
2568
+ onToggleSectionCollapse: doc.toggleSectionCollapse,
2569
+ onUpdateSectionTitle: doc.updateSectionTitle,
2570
+ onUpdateSectionBackground: doc.updateSectionBackground,
2571
+ onDuplicateSection: doc.duplicateSection,
2572
+ onMoveSection: doc.moveSection,
2573
+ onDeleteSection: doc.deleteSection,
2574
+ onAddSection: doc.addSection,
2575
+ onSelectField: (sectionId, fieldId) => {
2576
+ doc.setSelectedId(fieldId);
2577
+ doc.setActiveSectionId(sectionId);
2578
+ setMobilePanel("inspector");
2579
+ },
2580
+ onFieldChange: doc.updateField,
2581
+ onMoveField: doc.moveField,
2582
+ onDuplicateField: doc.duplicateField,
2583
+ onDeleteField: doc.deleteField,
2584
+ getDropZoneHandlers: drag.getDropZoneHandlers,
2585
+ getDragHandleProps: drag.getDragHandleProps
2586
+ }
2587
+ ),
2588
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2589
+ Inspector,
2590
+ {
2591
+ selected: doc.selected,
2592
+ language,
2593
+ chrome,
2594
+ features,
2595
+ onUpdateField: (patch) => doc.selected && doc.updateField(doc.selected.id, patch),
2596
+ onDeleteField: () => doc.selected && doc.deleteField(doc.selected.id),
2597
+ onUpdateOption: (optIdx, patch) => doc.selected && doc.updateOption(doc.selected.id, optIdx, patch),
2598
+ onAddOption: () => doc.selected && doc.addOption(doc.selected.id),
2599
+ onRemoveOption: (optIdx) => doc.selected && doc.removeOption(doc.selected.id, optIdx)
2600
+ }
2601
+ )
2602
+ ] })
2603
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2335
2604
  PreviewPane,
2336
2605
  {
2337
2606
  title: doc.title,
@@ -2341,14 +2610,12 @@ function FormBuilder({
2341
2610
  strings,
2342
2611
  chrome,
2343
2612
  baseMaxWidth: theme.layout.maxWidth,
2344
- submitLabel: doc.submitLabel,
2345
- submitMode: doc.submitMode,
2346
- submitStyle: doc.submitStyle
2613
+ onSubmit
2347
2614
  }
2348
2615
  ),
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,
2616
+ showJson && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(JsonModal, { chrome, jsonString, copied, onCopy: copyJson, onClose: () => setShowJson(false) }),
2617
+ showLibrary && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2618
+ TemplatesModal,
2352
2619
  {
2353
2620
  chrome,
2354
2621
  savedForms: persistence.savedForms,
@@ -2361,7 +2628,7 @@ function FormBuilder({
2361
2628
  onClose: () => setShowLibrary(false)
2362
2629
  }
2363
2630
  ),
2364
- persistence.saveAsPrompt && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2631
+ persistence.saveAsPrompt && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2365
2632
  SaveAsModal,
2366
2633
  {
2367
2634
  chrome,
@@ -2369,26 +2636,29 @@ function FormBuilder({
2369
2636
  onSave: persistence.saveAs,
2370
2637
  onClose: persistence.dismissSaveAsPrompt
2371
2638
  }
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
2639
  )
2388
2640
  ] });
2389
- }
2641
+ });
2642
+ var FormBuilder_default = FormBuilder;
2643
+
2644
+ // src/theme/darkTheme.ts
2645
+ var DARK_THEME = {
2646
+ primary: "#8B8FF5",
2647
+ primarySoft: "#262A45",
2648
+ danger: "#F0715B",
2649
+ dangerSoft: "#3A2420",
2650
+ ink: "#EDEEF2",
2651
+ muted: "#9096A8",
2652
+ border: "#2E313D",
2653
+ surface: "#1A1B23",
2654
+ canvas: "#121319",
2655
+ pageBackground: "#1A1B23",
2656
+ layout: DEFAULT_THEME.layout
2657
+ };
2390
2658
  // Annotate the CommonJS export names for ESM import in node:
2391
2659
  0 && (module.exports = {
2660
+ DARK_THEME,
2661
+ DEFAULT_THEME,
2392
2662
  FormBuilder,
2393
2663
  localStorageAdapter
2394
2664
  });