@schema-forms-data/create 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 SchemaForms
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # create-schema-form
2
+
3
+ Scaffold a **SchemaForms Studio** — a Vite + React app with a drag-and-drop form builder, live JSON viewer, and form preview — in one command.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx create-schema-form my-app
9
+ cd my-app
10
+ npm install
11
+ npm run dev
12
+ ```
13
+
14
+ Then open **http://localhost:5173**.
15
+
16
+ ## What you get
17
+
18
+ ```
19
+ my-app/
20
+ ├── src/
21
+ │ ├── App.tsx ← Studio shell (builder + JSON + preview)
22
+ │ ├── exampleSchema.ts ← Starter FormSchema — edit or replace
23
+ │ ├── App.css
24
+ │ ├── index.css
25
+ │ └── main.tsx
26
+ ├── index.html
27
+ ├── vite.config.ts
28
+ ├── tsconfig.json
29
+ └── package.json
30
+ ```
31
+
32
+ ### Studio layout
33
+
34
+ ```
35
+ ┌─────────────────────────────────────────────────────────────────────┐
36
+ │ SchemaForms Studio [JSON] [Preview] Save │
37
+ ├──────────────┬───────────────────────┬──────────────┬───────────────┤
38
+ │ Palette │ Canvas │ Config │ JSON / Form │
39
+ │ │ drag fields here │ Panel │ Preview │
40
+ └──────────────┴───────────────────────┴──────────────┴───────────────┘
41
+ ```
42
+
43
+ - **Palette** — drag field types onto the canvas
44
+ - **Canvas** — build multi-step forms visually (Step → Container → Fields)
45
+ - **Config Panel** — configure the selected field
46
+ - **JSON** — see the live `FormSchema` JSON; click **Copy** to grab it
47
+ - **Preview** — actually fill in the form and see the submitted data
48
+
49
+ Click **Save / Export** to convert the current canvas state to a `FormSchema` and update both panels. The schema is also saved to `localStorage` so it survives a page refresh.
50
+
51
+ ## Packages installed
52
+
53
+ | Package | Role |
54
+ | ----------------------------- | ----------------------------------------------------- |
55
+ | `@schema-forms-data/core` | TypeScript types & enums |
56
+ | `@schema-forms-data/builder` | `BuilderProvider`, `Canvas`, `Palette`, `ConfigPanel` |
57
+ | `@schema-forms-data/renderer` | `FormRenderer` |
58
+
59
+ ## Docs
60
+
61
+ https://schemaforms.github.io/schema-forms-data
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env node
2
+ // @ts-check
3
+ import { mkdir, cp, readFile, writeFile } from "node:fs/promises";
4
+ import { existsSync } from "node:fs";
5
+ import { resolve, join, dirname } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+
10
+ const GREEN = "\x1b[32m";
11
+ const CYAN = "\x1b[36m";
12
+ const BOLD = "\x1b[1m";
13
+ const RESET = "\x1b[0m";
14
+
15
+ function log(msg) {
16
+ process.stdout.write(msg + "\n");
17
+ }
18
+
19
+ async function main() {
20
+ const targetName = process.argv[2] || "my-schema-form";
21
+
22
+ if (!/^[a-z0-9_-]+$/i.test(targetName)) {
23
+ log(`\x1b[31mInvalid project name: "${targetName}"\x1b[0m`);
24
+ log('Use only letters, numbers, hyphens and underscores.');
25
+ process.exit(1);
26
+ }
27
+
28
+ const targetDir = resolve(process.cwd(), targetName);
29
+
30
+ if (existsSync(targetDir)) {
31
+ log(`\x1b[31mDirectory "${targetName}" already exists.\x1b[0m`);
32
+ process.exit(1);
33
+ }
34
+
35
+ const templateDir = join(__dirname, "..", "template");
36
+
37
+ log(`\n${BOLD}${CYAN}Creating SchemaForms Studio in ${targetDir}${RESET}\n`);
38
+
39
+ await mkdir(targetDir, { recursive: true });
40
+ await cp(templateDir, targetDir, { recursive: true });
41
+
42
+ // Rename _package.json → package.json (npm strips package.json from tarballs)
43
+ const pkgSrc = join(targetDir, "_package.json");
44
+ const pkgDst = join(targetDir, "package.json");
45
+ if (existsSync(pkgSrc)) {
46
+ const raw = await readFile(pkgSrc, "utf8");
47
+ const pkg = JSON.parse(raw);
48
+ pkg.name = targetName;
49
+ await writeFile(pkgDst, JSON.stringify(pkg, null, 2) + "\n");
50
+ const { unlink } = await import("node:fs/promises");
51
+ await unlink(pkgSrc);
52
+ }
53
+
54
+ // Rename _gitignore → .gitignore
55
+ const gitignoreSrc = join(targetDir, "_gitignore");
56
+ const gitignoreDst = join(targetDir, ".gitignore");
57
+ if (existsSync(gitignoreSrc)) {
58
+ const { rename } = await import("node:fs/promises");
59
+ await rename(gitignoreSrc, gitignoreDst);
60
+ }
61
+
62
+ const pkgManager = detectPackageManager();
63
+
64
+ log(`${GREEN}${BOLD}Done!${RESET} Your project is ready.\n`);
65
+ log(` ${CYAN}cd ${targetName}${RESET}`);
66
+ log(` ${CYAN}${pkgManager} install${RESET}`);
67
+ log(` ${CYAN}${pkgManager === "npm" ? "npm run" : pkgManager} dev${RESET}`);
68
+ log(``);
69
+ log(`Then open ${BOLD}http://localhost:5173${RESET} to see the studio.`);
70
+ log(``);
71
+ }
72
+
73
+ function detectPackageManager() {
74
+ const agent = process.env.npm_config_user_agent || "";
75
+ if (agent.startsWith("pnpm")) return "pnpm";
76
+ if (agent.startsWith("yarn")) return "yarn";
77
+ return "npm";
78
+ }
79
+
80
+ main().catch((err) => {
81
+ process.stderr.write(err.message + "\n");
82
+ process.exit(1);
83
+ });
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@schema-forms-data/create",
3
+ "version": "0.2.3",
4
+ "description": "Scaffold a SchemaForms studio app — builder + JSON viewer + renderer preview",
5
+ "license": "MIT",
6
+ "author": "SchemaForms",
7
+ "homepage": "https://schemaforms.github.io/schema-forms-data",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/SchemaForms/schema-forms-data.git",
11
+ "directory": "packages/create-schema-form"
12
+ },
13
+ "keywords": [
14
+ "create",
15
+ "scaffold",
16
+ "schema-forms",
17
+ "form-builder",
18
+ "schema-forms-data"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "type": "module",
24
+ "bin": {
25
+ "create-schema-form": "./bin/create-schema-form.js"
26
+ },
27
+ "files": [
28
+ "bin",
29
+ "template"
30
+ ],
31
+ "engines": {
32
+ "node": ">=18"
33
+ }
34
+ }
@@ -0,0 +1,3 @@
1
+ node_modules
2
+ dist
3
+ .env
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "my-schema-form",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@schema-forms-data/core": "^0.2.3",
13
+ "@schema-forms-data/builder": "^0.2.3",
14
+ "@schema-forms-data/renderer": "^0.2.3",
15
+ "lucide-react": "^0.400.0",
16
+ "react": "^18.3.1",
17
+ "react-dom": "^18.3.1",
18
+ "react-hook-form": "^7.54.0"
19
+ },
20
+ "devDependencies": {
21
+ "@types/react": "^18.3.3",
22
+ "@types/react-dom": "^18.3.0",
23
+ "@vitejs/plugin-react": "^4.3.1",
24
+ "typescript": "^5.5.3",
25
+ "vite": "^5.4.2"
26
+ }
27
+ }
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>SchemaForms Studio</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,214 @@
1
+ /* ── App shell ─────────────────────────────────────────────────── */
2
+ .sf-app {
3
+ display: flex;
4
+ flex-direction: column;
5
+ height: 100dvh;
6
+ overflow: hidden;
7
+ }
8
+
9
+ /* ── Toolbar ───────────────────────────────────────────────────── */
10
+ .sf-toolbar {
11
+ display: flex;
12
+ align-items: center;
13
+ gap: 12px;
14
+ padding: 0 16px;
15
+ height: 52px;
16
+ background: #1a1a2e;
17
+ color: #fff;
18
+ flex-shrink: 0;
19
+ border-bottom: 1px solid #2a2a4a;
20
+ }
21
+
22
+ .sf-toolbar-title {
23
+ display: flex;
24
+ align-items: center;
25
+ gap: 8px;
26
+ font-weight: 700;
27
+ font-size: 15px;
28
+ letter-spacing: -0.2px;
29
+ flex: 1;
30
+ }
31
+
32
+ .sf-tabs {
33
+ display: flex;
34
+ gap: 4px;
35
+ }
36
+
37
+ .sf-tab {
38
+ padding: 5px 14px;
39
+ border-radius: 6px;
40
+ border: 1px solid rgba(255, 255, 255, 0.2);
41
+ background: transparent;
42
+ color: rgba(255, 255, 255, 0.7);
43
+ cursor: pointer;
44
+ font-size: 13px;
45
+ transition: all 0.15s;
46
+ }
47
+
48
+ .sf-tab:hover {
49
+ background: rgba(255, 255, 255, 0.08);
50
+ color: #fff;
51
+ }
52
+
53
+ .sf-tab--active {
54
+ background: rgba(255, 255, 255, 0.15);
55
+ color: #fff;
56
+ border-color: rgba(255, 255, 255, 0.4);
57
+ }
58
+
59
+ .sf-save-btn {
60
+ padding: 6px 16px;
61
+ border-radius: 7px;
62
+ border: none;
63
+ background: #6366f1;
64
+ color: #fff;
65
+ font-weight: 600;
66
+ font-size: 13px;
67
+ cursor: pointer;
68
+ transition: background 0.15s;
69
+ }
70
+
71
+ .sf-save-btn:hover {
72
+ background: #4f52d3;
73
+ }
74
+
75
+ /* ── Body (4-column layout) ────────────────────────────────────── */
76
+ .sf-body {
77
+ display: grid;
78
+ grid-template-columns: 200px 1fr 260px 380px;
79
+ flex: 1;
80
+ overflow: hidden;
81
+ gap: 0;
82
+ }
83
+
84
+ @media (max-width: 960px) {
85
+ .sf-body {
86
+ grid-template-columns: 160px 1fr 220px;
87
+ }
88
+ .sf-output {
89
+ display: none;
90
+ }
91
+ }
92
+
93
+ /* ── Panel base ────────────────────────────────────────────────── */
94
+ .sf-palette,
95
+ .sf-canvas,
96
+ .sf-config,
97
+ .sf-output {
98
+ overflow-y: auto;
99
+ height: 100%;
100
+ }
101
+
102
+ .sf-palette {
103
+ border-right: 1px solid #e2e4e9;
104
+ background: #ffffff;
105
+ padding: 12px 8px;
106
+ }
107
+
108
+ .sf-canvas {
109
+ background: #f0f2f7;
110
+ padding: 20px;
111
+ }
112
+
113
+ .sf-config {
114
+ border-left: 1px solid #e2e4e9;
115
+ background: #fafafa;
116
+ padding: 12px;
117
+ }
118
+
119
+ .sf-output {
120
+ border-left: 1px solid #e2e4e9;
121
+ background: #fff;
122
+ display: flex;
123
+ flex-direction: column;
124
+ }
125
+
126
+ /* ── JSON panel ────────────────────────────────────────────────── */
127
+ .sf-json-panel {
128
+ display: flex;
129
+ flex-direction: column;
130
+ height: 100%;
131
+ overflow: hidden;
132
+ }
133
+
134
+ .sf-json-header {
135
+ display: flex;
136
+ align-items: center;
137
+ justify-content: space-between;
138
+ padding: 10px 14px;
139
+ border-bottom: 1px solid #e2e4e9;
140
+ font-weight: 600;
141
+ font-size: 12px;
142
+ color: #555;
143
+ text-transform: uppercase;
144
+ letter-spacing: 0.5px;
145
+ background: #fafafa;
146
+ flex-shrink: 0;
147
+ }
148
+
149
+ .sf-copy-btn {
150
+ padding: 3px 10px;
151
+ border-radius: 5px;
152
+ border: 1px solid #d0d3da;
153
+ background: transparent;
154
+ font-size: 11px;
155
+ cursor: pointer;
156
+ color: #555;
157
+ transition: all 0.12s;
158
+ }
159
+
160
+ .sf-copy-btn:hover {
161
+ border-color: #6366f1;
162
+ color: #6366f1;
163
+ }
164
+
165
+ .sf-json-pre {
166
+ flex: 1;
167
+ overflow: auto;
168
+ padding: 14px;
169
+ font-size: 11.5px;
170
+ line-height: 1.6;
171
+ font-family: "Fira Code", "Cascadia Code", "Consolas", monospace;
172
+ color: #2d2d2d;
173
+ white-space: pre;
174
+ word-break: keep-all;
175
+ }
176
+
177
+ /* ── Preview panel ─────────────────────────────────────────────── */
178
+ .sf-preview-wrap {
179
+ padding: 16px;
180
+ overflow-y: auto;
181
+ height: 100%;
182
+ }
183
+
184
+ .sf-preview-empty {
185
+ display: flex;
186
+ align-items: center;
187
+ justify-content: center;
188
+ height: 100%;
189
+ color: #888;
190
+ text-align: center;
191
+ padding: 24px;
192
+ font-size: 13px;
193
+ line-height: 1.6;
194
+ }
195
+
196
+ .sf-submitted {
197
+ padding: 20px;
198
+ }
199
+
200
+ .sf-submitted h3 {
201
+ color: #22c55e;
202
+ margin-bottom: 12px;
203
+ font-size: 16px;
204
+ }
205
+
206
+ .sf-submitted pre {
207
+ background: #f4f5f7;
208
+ padding: 12px;
209
+ border-radius: 8px;
210
+ font-size: 11px;
211
+ overflow-x: auto;
212
+ margin-bottom: 12px;
213
+ font-family: "Fira Code", monospace;
214
+ }
@@ -0,0 +1,215 @@
1
+ import React, { useState, useMemo } from "react";
2
+ import {
3
+ BuilderProvider,
4
+ Canvas,
5
+ Palette,
6
+ ConfigPanel,
7
+ useBuilder,
8
+ formSchemaToBuilder,
9
+ builderToFormSchema,
10
+ } from "@schema-forms-data/builder";
11
+ import type { FormSchema } from "@schema-forms-data/core";
12
+ import { FormSchemaStatus } from "@schema-forms-data/core";
13
+ import { FormRenderer } from "@schema-forms-data/renderer";
14
+ import { exampleSchema } from "./exampleSchema";
15
+ import "./App.css";
16
+
17
+ type Tab = "json" | "preview";
18
+
19
+ // ── JSON Panel ──────────────────────────────────────────────────────────────
20
+ function JsonPanel({ schema }: { schema: FormSchema | null }) {
21
+ const [copied, setCopied] = useState(false);
22
+ const json = JSON.stringify(schema, null, 2);
23
+
24
+ const copy = () => {
25
+ navigator.clipboard.writeText(json).then(() => {
26
+ setCopied(true);
27
+ setTimeout(() => setCopied(false), 1500);
28
+ });
29
+ };
30
+
31
+ return (
32
+ <div className="sf-json-panel">
33
+ <div className="sf-json-header">
34
+ <span>FormSchema JSON</span>
35
+ <button className="sf-copy-btn" onClick={copy}>
36
+ {copied ? "Copied!" : "Copy"}
37
+ </button>
38
+ </div>
39
+ <pre className="sf-json-pre">{json}</pre>
40
+ </div>
41
+ );
42
+ }
43
+
44
+ // ── Preview Panel ────────────────────────────────────────────────────────────
45
+ function PreviewPanel({ schema }: { schema: FormSchema | null }) {
46
+ const [submitted, setSubmitted] = useState<Record<string, unknown> | null>(
47
+ null,
48
+ );
49
+
50
+ if (!schema) {
51
+ return (
52
+ <div className="sf-preview-empty">
53
+ Build a form and click <strong>Save / Export</strong> to preview it
54
+ here.
55
+ </div>
56
+ );
57
+ }
58
+
59
+ if (submitted) {
60
+ return (
61
+ <div className="sf-submitted">
62
+ <h3>✓ Submitted</h3>
63
+ <pre>{JSON.stringify(submitted, null, 2)}</pre>
64
+ <button className="sf-save-btn" onClick={() => setSubmitted(null)}>
65
+ Fill again
66
+ </button>
67
+ </div>
68
+ );
69
+ }
70
+
71
+ return (
72
+ <div className="sf-preview-wrap">
73
+ <FormRenderer
74
+ schema={schema}
75
+ onComplete={(data) => setSubmitted(data as Record<string, unknown>)}
76
+ />
77
+ </div>
78
+ );
79
+ }
80
+
81
+ // ── StudioInner: lives inside BuilderProvider so it can use useBuilder() ───
82
+ function StudioInner({
83
+ formName,
84
+ savedSchema,
85
+ onSchemaSaved,
86
+ }: {
87
+ formName: string;
88
+ savedSchema: FormSchema | null;
89
+ onSchemaSaved: (schema: FormSchema) => void;
90
+ }) {
91
+ const { containers, configs } = useBuilder();
92
+ const [tab, setTab] = useState<Tab>("json");
93
+
94
+ const handleSave = () => {
95
+ const schema = builderToFormSchema({ containers }, configs, {
96
+ nome: formName,
97
+ status: FormSchemaStatus.RASCUNHO,
98
+ }) as FormSchema;
99
+ onSchemaSaved(schema);
100
+ };
101
+
102
+ return (
103
+ <div className="sf-app">
104
+ {/* ── Toolbar ── */}
105
+ <header className="sf-toolbar">
106
+ <span className="sf-toolbar-title">
107
+ <svg
108
+ width="20"
109
+ height="20"
110
+ viewBox="0 0 24 24"
111
+ fill="none"
112
+ stroke="currentColor"
113
+ strokeWidth="2"
114
+ strokeLinecap="round"
115
+ strokeLinejoin="round"
116
+ >
117
+ <rect x="3" y="3" width="18" height="18" rx="2" />
118
+ <path d="M3 9h18M9 21V9" />
119
+ </svg>
120
+ SchemaForms Studio
121
+ </span>
122
+
123
+ <div className="sf-tabs">
124
+ <button
125
+ className={`sf-tab ${tab === "json" ? "sf-tab--active" : ""}`}
126
+ onClick={() => setTab("json")}
127
+ >
128
+ JSON
129
+ </button>
130
+ <button
131
+ className={`sf-tab ${tab === "preview" ? "sf-tab--active" : ""}`}
132
+ onClick={() => setTab("preview")}
133
+ >
134
+ Preview
135
+ </button>
136
+ </div>
137
+
138
+ <button className="sf-save-btn" onClick={handleSave}>
139
+ Save / Export
140
+ </button>
141
+ </header>
142
+
143
+ {/* ── Body ── */}
144
+ <div className="sf-body">
145
+ <aside className="sf-palette">
146
+ <Palette />
147
+ </aside>
148
+
149
+ <main className="sf-canvas">
150
+ <Canvas />
151
+ </main>
152
+
153
+ <aside className="sf-config">
154
+ <ConfigPanel />
155
+ </aside>
156
+
157
+ <aside className="sf-output">
158
+ {tab === "json" ? (
159
+ <JsonPanel schema={savedSchema} />
160
+ ) : (
161
+ <PreviewPanel schema={savedSchema} />
162
+ )}
163
+ </aside>
164
+ </div>
165
+ </div>
166
+ );
167
+ }
168
+
169
+ // ── App ──────────────────────────────────────────────────────────────────────
170
+ export default function App() {
171
+ const [savedSchema, setSavedSchema] = useState<FormSchema | null>(() => {
172
+ try {
173
+ const stored = localStorage.getItem("sf-studio-schema");
174
+ return stored ? (JSON.parse(stored) as FormSchema) : exampleSchema;
175
+ } catch {
176
+ return exampleSchema;
177
+ }
178
+ });
179
+
180
+ const handleSchemaSaved = (schema: FormSchema) => {
181
+ setSavedSchema(schema);
182
+ try {
183
+ localStorage.setItem("sf-studio-schema", JSON.stringify(schema));
184
+ } catch {
185
+ // ignore quota errors
186
+ }
187
+ };
188
+
189
+ // Convert saved schema to builder state only on initial mount
190
+ const { initialContainers, initialConfigs } = useMemo(() => {
191
+ try {
192
+ const result = formSchemaToBuilder(savedSchema ?? exampleSchema);
193
+ return {
194
+ initialContainers: result.dndState.containers,
195
+ initialConfigs: result.configs,
196
+ };
197
+ } catch {
198
+ return { initialContainers: undefined, initialConfigs: undefined };
199
+ }
200
+ // eslint-disable-next-line react-hooks/exhaustive-deps
201
+ }, []); // intentionally runs only on mount
202
+
203
+ return (
204
+ <BuilderProvider
205
+ initialContainers={initialContainers}
206
+ initialConfigs={initialConfigs}
207
+ >
208
+ <StudioInner
209
+ formName={savedSchema?.nome ?? "My Form"}
210
+ savedSchema={savedSchema}
211
+ onSchemaSaved={handleSchemaSaved}
212
+ />
213
+ </BuilderProvider>
214
+ );
215
+ }
@@ -0,0 +1,109 @@
1
+ import type { FormSchema } from "@schema-forms-data/core";
2
+ import { FormSchemaStatus, FieldType } from "@schema-forms-data/core";
3
+
4
+ /**
5
+ * Example FormSchema used as the initial state in the studio.
6
+ * Edit this file or drag fields in the builder to change the form.
7
+ */
8
+ export const exampleSchema: FormSchema = {
9
+ id: "example-schema",
10
+ nome: "Example Form",
11
+ status: FormSchemaStatus.RASCUNHO,
12
+ steps: [
13
+ {
14
+ id: "step-texto",
15
+ titulo: "Personal Info",
16
+ ordem: 0,
17
+ containers: [
18
+ {
19
+ id: "container-details",
20
+ titulo: "Your Details",
21
+ ordem: 0,
22
+ colunas: 2,
23
+ campos: [
24
+ {
25
+ id: "field-texto-firstName",
26
+ nome: "firstName",
27
+ label: "First Name",
28
+ tipo: FieldType.TEXTO,
29
+ obrigatorio: true,
30
+ tamanho: 6,
31
+ ordem: 0,
32
+ placeholder: "John",
33
+ },
34
+ {
35
+ id: "field-texto-lastName",
36
+ nome: "lastName",
37
+ label: "Last Name",
38
+ tipo: FieldType.TEXTO,
39
+ obrigatorio: true,
40
+ tamanho: 6,
41
+ ordem: 1,
42
+ placeholder: "Doe",
43
+ },
44
+ {
45
+ id: "field-email-email",
46
+ nome: "email",
47
+ label: "Email",
48
+ tipo: FieldType.EMAIL,
49
+ obrigatorio: true,
50
+ tamanho: 6,
51
+ ordem: 2,
52
+ placeholder: "john@example.com",
53
+ },
54
+ {
55
+ id: "field-telefone-phone",
56
+ nome: "phone",
57
+ label: "Phone",
58
+ tipo: FieldType.TELEFONE,
59
+ obrigatorio: false,
60
+ tamanho: 6,
61
+ ordem: 3,
62
+ placeholder: "(11) 99999-9999",
63
+ },
64
+ ],
65
+ },
66
+ ],
67
+ },
68
+ {
69
+ id: "step-prefs",
70
+ titulo: "Preferences",
71
+ ordem: 1,
72
+ containers: [
73
+ {
74
+ id: "container-prefs",
75
+ titulo: "Preferences",
76
+ ordem: 0,
77
+ colunas: 1,
78
+ campos: [
79
+ {
80
+ id: "field-select-size",
81
+ nome: "size",
82
+ label: "T-Shirt Size",
83
+ tipo: FieldType.SELECT,
84
+ obrigatorio: true,
85
+ tamanho: 12,
86
+ ordem: 0,
87
+ opcoes: [
88
+ { label: "Small", valor: "S" },
89
+ { label: "Medium", valor: "M" },
90
+ { label: "Large", valor: "L" },
91
+ { label: "X-Large", valor: "XL" },
92
+ ],
93
+ },
94
+ {
95
+ id: "field-textarea-bio",
96
+ nome: "bio",
97
+ label: "Short Bio",
98
+ tipo: FieldType.TEXTAREA,
99
+ obrigatorio: false,
100
+ tamanho: 12,
101
+ ordem: 1,
102
+ placeholder: "Tell us about yourself…",
103
+ },
104
+ ],
105
+ },
106
+ ],
107
+ },
108
+ ],
109
+ };
@@ -0,0 +1,16 @@
1
+ /* ── Global reset ──────────────────────────────────────────────── */
2
+ *,
3
+ *::before,
4
+ *::after {
5
+ box-sizing: border-box;
6
+ margin: 0;
7
+ padding: 0;
8
+ }
9
+
10
+ body {
11
+ font-family:
12
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
13
+ font-size: 14px;
14
+ background: #f4f5f7;
15
+ color: #1a1a2e;
16
+ }
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import App from "./App";
4
+ import "./index.css";
5
+
6
+ ReactDOM.createRoot(document.getElementById("root")!).render(
7
+ <React.StrictMode>
8
+ <App />
9
+ </React.StrictMode>,
10
+ );
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "isolatedModules": true,
11
+ "moduleDetection": "force",
12
+ "noEmit": true,
13
+ "jsx": "react-jsx",
14
+ "strict": true
15
+ },
16
+ "include": ["src"]
17
+ }
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+
4
+ export default defineConfig({
5
+ plugins: [react()],
6
+ })