@squaredr/fieldcraft-pro 1.2.0 → 1.4.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.
@@ -1,407 +0,0 @@
1
- import { requireLicense } from './chunk-VECQKSWS.mjs';
2
- import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
3
- import { cleanPreset, playfulPreset, clinicalPreset, highContrastPreset, modernPreset, darkPreset, FormEngineRenderer } from '@squaredr/fieldcraft-react';
4
- import { jsxs, jsx } from 'react/jsx-runtime';
5
-
6
- // src/theme-editor/preview-schema.ts
7
- var PREVIEW_SCHEMA = {
8
- id: "theme-preview",
9
- version: "1.0.0",
10
- title: "Theme Preview",
11
- description: "See how your theme looks on a real form.",
12
- sections: [
13
- {
14
- id: "s1",
15
- title: "Contact Information",
16
- questions: [
17
- {
18
- id: "name",
19
- type: "short_text",
20
- label: "Full Name",
21
- required: true,
22
- placeholder: "Jane Doe"
23
- },
24
- {
25
- id: "email",
26
- type: "email",
27
- label: "Email Address",
28
- required: true,
29
- placeholder: "jane@example.com"
30
- },
31
- {
32
- id: "department",
33
- type: "dropdown",
34
- label: "Department",
35
- options: [
36
- { label: "Engineering", value: "engineering" },
37
- { label: "Design", value: "design" },
38
- { label: "Marketing", value: "marketing" }
39
- ]
40
- },
41
- {
42
- id: "rating",
43
- type: "rating",
44
- label: "How would you rate this experience?",
45
- config: { type: "rating", max: 5 }
46
- },
47
- {
48
- id: "notes",
49
- type: "long_text",
50
- label: "Additional Notes",
51
- placeholder: "Any other feedback..."
52
- }
53
- ]
54
- }
55
- ],
56
- submitAction: { type: "adapter" }
57
- };
58
- var PRESETS = {
59
- clean: cleanPreset,
60
- dark: darkPreset,
61
- modern: modernPreset,
62
- "high-contrast": highContrastPreset,
63
- clinical: clinicalPreset,
64
- playful: playfulPreset
65
- };
66
- var SECTIONS = [
67
- {
68
- id: "colors",
69
- label: "Colors",
70
- themeKey: "colors",
71
- fields: [
72
- { kind: "color", key: "primary", label: "Primary" },
73
- { kind: "color", key: "primaryForeground", label: "Primary Foreground" },
74
- { kind: "color", key: "secondary", label: "Secondary" },
75
- { kind: "color", key: "secondaryForeground", label: "Secondary Foreground" },
76
- { kind: "color", key: "error", label: "Error" },
77
- { kind: "color", key: "errorForeground", label: "Error Foreground" },
78
- { kind: "color", key: "warning", label: "Warning" },
79
- { kind: "color", key: "success", label: "Success" },
80
- { kind: "color", key: "surface", label: "Surface" },
81
- { kind: "color", key: "background", label: "Background" },
82
- { kind: "color", key: "text", label: "Text" },
83
- { kind: "color", key: "textMuted", label: "Text Muted" },
84
- { kind: "color", key: "textDisabled", label: "Text Disabled" },
85
- { kind: "color", key: "border", label: "Border" },
86
- { kind: "color", key: "borderFocus", label: "Border Focus" },
87
- { kind: "color", key: "inputBackground", label: "Input Background" }
88
- ]
89
- },
90
- {
91
- id: "typography",
92
- label: "Typography",
93
- themeKey: "typography",
94
- fields: [
95
- { kind: "text", key: "fontFamily", label: "Font Family", placeholder: "Inter, system-ui, sans-serif" },
96
- {
97
- kind: "select",
98
- key: "scale",
99
- label: "Scale",
100
- options: [
101
- { label: "Compact", value: "compact" },
102
- { label: "Comfortable", value: "comfortable" },
103
- { label: "Spacious", value: "spacious" }
104
- ]
105
- },
106
- { kind: "text", key: "questionSize", label: "Question Size", placeholder: "1.125rem" },
107
- { kind: "text", key: "labelSize", label: "Label Size", placeholder: "0.875rem" },
108
- { kind: "text", key: "helpTextSize", label: "Help Text Size", placeholder: "0.8125rem" },
109
- { kind: "text", key: "bodySize", label: "Body Size", placeholder: "0.9375rem" }
110
- ]
111
- },
112
- {
113
- id: "shape",
114
- label: "Shape",
115
- themeKey: "shape",
116
- fields: [
117
- {
118
- kind: "select",
119
- key: "radius",
120
- label: "Radius",
121
- options: [
122
- { label: "None", value: "none" },
123
- { label: "Small", value: "sm" },
124
- { label: "Medium", value: "md" },
125
- { label: "Large", value: "lg" },
126
- { label: "Full", value: "full" }
127
- ]
128
- },
129
- { kind: "text", key: "inputRadius", label: "Input Radius", placeholder: "8px" },
130
- { kind: "text", key: "buttonRadius", label: "Button Radius", placeholder: "8px" },
131
- { kind: "text", key: "cardRadius", label: "Card Radius", placeholder: "12px" }
132
- ]
133
- },
134
- {
135
- id: "spacing",
136
- label: "Spacing",
137
- themeKey: "spacing",
138
- fields: [
139
- { kind: "number", key: "base", label: "Base", min: 4, max: 32, suffix: "px" },
140
- { kind: "number", key: "sectionGap", label: "Section Gap", min: 0, max: 64, suffix: "px" },
141
- { kind: "number", key: "fieldGap", label: "Field Gap", min: 0, max: 64, suffix: "px" },
142
- { kind: "number", key: "inputPaddingX", label: "Input Padding X", min: 0, max: 32, suffix: "px" },
143
- { kind: "number", key: "inputPaddingY", label: "Input Padding Y", min: 0, max: 32, suffix: "px" }
144
- ]
145
- },
146
- {
147
- id: "layout",
148
- label: "Layout",
149
- themeKey: "layout",
150
- fields: [
151
- { kind: "text", key: "maxWidth", label: "Max Width", placeholder: "640px" },
152
- {
153
- kind: "select",
154
- key: "alignment",
155
- label: "Alignment",
156
- options: [
157
- { label: "Left", value: "left" },
158
- { label: "Center", value: "center" }
159
- ]
160
- },
161
- {
162
- kind: "select",
163
- key: "progressPosition",
164
- label: "Progress Position",
165
- options: [
166
- { label: "Top", value: "top" },
167
- { label: "Bottom", value: "bottom" },
168
- { label: "None", value: "none" }
169
- ]
170
- },
171
- {
172
- kind: "select",
173
- key: "sectionLayout",
174
- label: "Section Layout",
175
- options: [
176
- { label: "Card", value: "card" },
177
- { label: "Flat", value: "flat" },
178
- { label: "Bordered", value: "bordered" }
179
- ]
180
- }
181
- ]
182
- }
183
- ];
184
- function ThemeEditorInner({
185
- initialTheme,
186
- onChange,
187
- onSave,
188
- height,
189
- width,
190
- className,
191
- toolbarExtra,
192
- showPreview = true
193
- }) {
194
- const [theme, setTheme] = useState(initialTheme ?? cleanPreset);
195
- const [activeSection, setActiveSection] = useState("colors");
196
- const [presetKey, setPresetKey] = useState("custom");
197
- const themeRef = useRef(theme);
198
- themeRef.current = theme;
199
- useEffect(() => {
200
- function handleKeyDown(e) {
201
- if ((e.metaKey || e.ctrlKey) && e.key === "s") {
202
- e.preventDefault();
203
- onSave?.(themeRef.current);
204
- }
205
- }
206
- window.addEventListener("keydown", handleKeyDown);
207
- return () => window.removeEventListener("keydown", handleKeyDown);
208
- }, [onSave]);
209
- const updateField = useCallback(
210
- (section, key, value) => {
211
- setTheme((prev) => {
212
- const next = {
213
- ...prev,
214
- [section]: { ...prev[section], [key]: value }
215
- };
216
- onChange?.(next);
217
- return next;
218
- });
219
- setPresetKey("custom");
220
- },
221
- [onChange]
222
- );
223
- const loadPreset = useCallback(
224
- (key) => {
225
- const preset = PRESETS[key];
226
- if (preset) {
227
- setTheme(preset);
228
- setPresetKey(key);
229
- onChange?.(preset);
230
- }
231
- },
232
- [onChange]
233
- );
234
- const exportJson = useCallback(() => {
235
- const blob = new Blob([JSON.stringify(theme, null, 2)], { type: "application/json" });
236
- const url = URL.createObjectURL(blob);
237
- const a = document.createElement("a");
238
- a.href = url;
239
- a.download = "fieldcraft-theme.json";
240
- a.click();
241
- URL.revokeObjectURL(url);
242
- }, [theme]);
243
- const importJson = useCallback(() => {
244
- const input = document.createElement("input");
245
- input.type = "file";
246
- input.accept = ".json";
247
- input.onchange = () => {
248
- const file = input.files?.[0];
249
- if (!file) return;
250
- const reader = new FileReader();
251
- reader.onload = () => {
252
- try {
253
- const parsed = JSON.parse(reader.result);
254
- setTheme(parsed);
255
- setPresetKey("custom");
256
- onChange?.(parsed);
257
- } catch {
258
- }
259
- };
260
- reader.readAsText(file);
261
- };
262
- input.click();
263
- }, [onChange]);
264
- const currentSection = useMemo(
265
- () => SECTIONS.find((s) => s.id === activeSection),
266
- [activeSection]
267
- );
268
- const sectionValues = theme[currentSection.themeKey] ?? {};
269
- return /* @__PURE__ */ jsxs(
270
- "div",
271
- {
272
- className: `fcte-root${className ? ` ${className}` : ""}`,
273
- style: {
274
- height: height ?? "100%",
275
- width: width ?? "100%"
276
- },
277
- children: [
278
- /* @__PURE__ */ jsxs("div", { className: "fcte-toolbar", children: [
279
- /* @__PURE__ */ jsxs("div", { className: "fcte-toolbar__left", children: [
280
- /* @__PURE__ */ jsx("span", { className: "fcte-toolbar__title", children: "Theme Editor" }),
281
- /* @__PURE__ */ jsxs(
282
- "select",
283
- {
284
- value: presetKey,
285
- onChange: (e) => loadPreset(e.target.value),
286
- className: "fcte-toolbar__preset",
287
- children: [
288
- /* @__PURE__ */ jsx("option", { value: "custom", disabled: true, children: "Custom" }),
289
- Object.keys(PRESETS).map((k) => /* @__PURE__ */ jsx("option", { value: k, children: k.charAt(0).toUpperCase() + k.slice(1).replace("-", " ") }, k))
290
- ]
291
- }
292
- )
293
- ] }),
294
- /* @__PURE__ */ jsxs("div", { className: "fcte-toolbar__right", children: [
295
- toolbarExtra,
296
- /* @__PURE__ */ jsx("button", { onClick: importJson, className: "fcte-btn fcte-btn--secondary", children: "Import" }),
297
- /* @__PURE__ */ jsx("button", { onClick: exportJson, className: "fcte-btn fcte-btn--secondary", children: "Export" }),
298
- onSave && /* @__PURE__ */ jsx("button", { onClick: () => onSave(theme), className: "fcte-btn fcte-btn--primary", children: "Save" })
299
- ] })
300
- ] }),
301
- /* @__PURE__ */ jsxs("div", { className: "fcte-body", children: [
302
- /* @__PURE__ */ jsxs("div", { className: "fcte-editor", children: [
303
- /* @__PURE__ */ jsx("div", { className: "fcte-tabs", children: SECTIONS.map((s) => /* @__PURE__ */ jsx(
304
- "button",
305
- {
306
- className: `fcte-tab${activeSection === s.id ? " fcte-tab--active" : ""}`,
307
- onClick: () => setActiveSection(s.id),
308
- children: s.label
309
- },
310
- s.id
311
- )) }),
312
- /* @__PURE__ */ jsx("div", { className: "fcte-fields", children: currentSection.fields.map((field) => {
313
- const val = sectionValues[field.key];
314
- if (field.kind === "color") {
315
- return /* @__PURE__ */ jsxs("div", { className: "fcte-field", children: [
316
- /* @__PURE__ */ jsx("label", { className: "fcte-field__label", children: field.label }),
317
- /* @__PURE__ */ jsxs("div", { className: "fcte-field__color-row", children: [
318
- /* @__PURE__ */ jsx(
319
- "input",
320
- {
321
- type: "color",
322
- value: typeof val === "string" ? val : "#000000",
323
- onChange: (e) => updateField(currentSection.themeKey, field.key, e.target.value),
324
- className: "fcte-field__swatch"
325
- }
326
- ),
327
- /* @__PURE__ */ jsx(
328
- "input",
329
- {
330
- type: "text",
331
- value: typeof val === "string" ? val : "",
332
- onChange: (e) => updateField(currentSection.themeKey, field.key, e.target.value),
333
- className: "fcte-field__text",
334
- spellCheck: false
335
- }
336
- )
337
- ] })
338
- ] }, field.key);
339
- }
340
- if (field.kind === "select") {
341
- return /* @__PURE__ */ jsxs("div", { className: "fcte-field", children: [
342
- /* @__PURE__ */ jsx("label", { className: "fcte-field__label", children: field.label }),
343
- /* @__PURE__ */ jsx(
344
- "select",
345
- {
346
- value: typeof val === "string" ? val : "",
347
- onChange: (e) => updateField(currentSection.themeKey, field.key, e.target.value),
348
- className: "fcte-field__select",
349
- children: field.options.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
350
- }
351
- )
352
- ] }, field.key);
353
- }
354
- if (field.kind === "number") {
355
- return /* @__PURE__ */ jsxs("div", { className: "fcte-field", children: [
356
- /* @__PURE__ */ jsx("label", { className: "fcte-field__label", children: field.label }),
357
- /* @__PURE__ */ jsxs("div", { className: "fcte-field__number-row", children: [
358
- /* @__PURE__ */ jsx(
359
- "input",
360
- {
361
- type: "number",
362
- value: typeof val === "number" ? val : 0,
363
- onChange: (e) => updateField(currentSection.themeKey, field.key, Number(e.target.value)),
364
- min: field.min,
365
- max: field.max,
366
- className: "fcte-field__number"
367
- }
368
- ),
369
- field.suffix && /* @__PURE__ */ jsx("span", { className: "fcte-field__suffix", children: field.suffix })
370
- ] })
371
- ] }, field.key);
372
- }
373
- return /* @__PURE__ */ jsxs("div", { className: "fcte-field", children: [
374
- /* @__PURE__ */ jsx("label", { className: "fcte-field__label", children: field.label }),
375
- /* @__PURE__ */ jsx(
376
- "input",
377
- {
378
- type: "text",
379
- value: typeof val === "string" ? val : "",
380
- onChange: (e) => updateField(currentSection.themeKey, field.key, e.target.value),
381
- placeholder: field.placeholder,
382
- className: "fcte-field__text",
383
- spellCheck: false
384
- }
385
- )
386
- ] }, field.key);
387
- }) })
388
- ] }),
389
- showPreview && /* @__PURE__ */ jsx("div", { className: "fcte-preview", children: /* @__PURE__ */ jsx("div", { className: "fcte-preview__inner", children: /* @__PURE__ */ jsx(
390
- FormEngineRenderer,
391
- {
392
- schema: PREVIEW_SCHEMA,
393
- theme,
394
- onSubmit: () => {
395
- }
396
- }
397
- ) }) })
398
- ] })
399
- ]
400
- }
401
- );
402
- }
403
-
404
- // src/theme-editor/ThemeEditor.tsx
405
- var ThemeEditor = requireLicense(ThemeEditorInner, "ThemeEditor");
406
-
407
- export { PREVIEW_SCHEMA, ThemeEditor, ThemeEditorInner };