@duffcloudservices/site-forms 0.1.1 → 0.1.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.
Files changed (41) hide show
  1. package/README.md +274 -260
  2. package/dist/composables/useFormSubmission.d.ts +1 -1
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.js +554 -398
  5. package/dist/index.js.map +1 -1
  6. package/dist/presets.d.ts +13 -0
  7. package/dist/site-forms.css +1 -0
  8. package/dist/types.d.ts +12 -2
  9. package/package.json +72 -73
  10. package/src/DcsForm.vue +295 -303
  11. package/src/__tests__/fields.test.ts +81 -82
  12. package/src/__tests__/multi-step.test.ts +45 -46
  13. package/src/__tests__/presets.test.ts +64 -0
  14. package/src/__tests__/schema.test.ts +41 -42
  15. package/src/__tests__/style-import.test.ts +9 -0
  16. package/src/__tests__/submission.test.ts +115 -77
  17. package/src/__tests__/validation.test.ts +29 -0
  18. package/src/__tests__/visible-if.test.ts +110 -111
  19. package/src/composables/useDcsForm.ts +201 -201
  20. package/src/composables/useFormSubmission.ts +113 -113
  21. package/src/composables/useFormValidation.ts +128 -127
  22. package/src/fields/DcsFormCheckbox.vue +35 -35
  23. package/src/fields/DcsFormCheckboxGroup.vue +52 -52
  24. package/src/fields/DcsFormDate.vue +34 -34
  25. package/src/fields/DcsFormFieldWrapper.vue +39 -39
  26. package/src/fields/DcsFormFile.vue +38 -38
  27. package/src/fields/DcsFormHidden.vue +17 -17
  28. package/src/fields/DcsFormHtmlBlock.vue +19 -19
  29. package/src/fields/DcsFormRadio.vue +45 -45
  30. package/src/fields/DcsFormSection.vue +19 -19
  31. package/src/fields/DcsFormSelect.vue +62 -62
  32. package/src/fields/DcsFormText.vue +54 -54
  33. package/src/fields/DcsFormTextarea.vue +43 -43
  34. package/src/index.ts +64 -51
  35. package/src/loaders/yaml.ts +51 -51
  36. package/src/presets.ts +192 -0
  37. package/src/schema/form-definition.schema.json +410 -45
  38. package/src/schema/validate.ts +58 -58
  39. package/src/shims.d.ts +10 -10
  40. package/src/style.css +256 -0
  41. package/src/types.ts +164 -140
package/README.md CHANGED
@@ -1,260 +1,274 @@
1
- # @duffcloudservices/site-forms
2
-
3
- Shared `<DcsForm/>` runtime for DCS customer sites. Renders a managed
4
- form definition (created in the portal Form Manager) from a build-time
5
- `.dcs/forms/<formId>.yaml` snapshot, validates user input, and posts
6
- submissions to the public site-forms API.
7
-
8
- This is the single import surface for managed-form runtime code on
9
- customer sites — do not redefine field components per site.
10
-
11
- > **Inside the `dcs-again` workspace** the package is also reachable
12
- > as `@duffcloudservices/site-forms` via `workspace:*` (the workspace
13
- > name and the published name are the same).
14
- > **In sibling customer-site repos** install the published package
15
- > from public npm — see [`PUBLISHING.md`](./PUBLISHING.md) for the
16
- > consumption story and registry setup.
17
-
18
- ## Install
19
-
20
- ### In a workspace app (inside `dcs-again`)
21
-
22
- ```jsonc
23
- // portal/package.json
24
- {
25
- "dependencies": {
26
- "@duffcloudservices/site-forms": "workspace:*"
27
- }
28
- }
29
- ```
30
-
31
- Then `pnpm install` from the repo root.
32
-
33
- ### In a sibling customer-site repo (e.g. `ktbraunlaw`, `kept`)
34
-
35
- ```powershell
36
- pnpm add @duffcloudservices/site-forms
37
- ```
38
-
39
- See [`PUBLISHING.md`](./PUBLISHING.md) for the registry, version, and
40
- release-workflow details.
41
-
42
- ## Vite setup
43
-
44
- Three pieces are required in the consuming site:
45
-
46
- 1. **`vite-plugin-yaml`** so YAML modules return parsed objects:
47
-
48
- ```ts
49
- // vite.config.ts
50
- import yaml from '@modyfi/vite-plugin-yaml'
51
-
52
- export default defineConfig({
53
- plugins: [vue(), yaml()],
54
- })
55
- ```
56
-
57
- Without it, the loader falls back to parsing raw strings via
58
- `js-yaml`, which works but pays the parse cost at boot.
59
-
60
- 2. **A `formsModules` loader** in your site that does the
61
- `import.meta.glob` from a path Vite can resolve (see below).
62
-
63
- 3. **Env vars** the runtime reads:
64
-
65
- | Variable | Purpose |
66
- | ----------------------- | ---------------------------------------------------- |
67
- | `VITE_DCS_PUBLIC_API` | Base URL of the DCS public API (no trailing slash). |
68
- | `VITE_DCS_SITE_SLUG` | Default site slug used when the prop is omitted. |
69
-
70
- ### Why the `formsModules` prop is required in real sites
71
-
72
- `<DcsForm/>` ships with an internal `import.meta.glob('/.dcs/forms/*.yaml')`
73
- fallback, but Vite resolves the leading `/` against the **consumer's
74
- Vite project root** (the directory containing `vite.config.ts`).
75
- On every customer-site repo today, the `.dcs/forms/` directory lives
76
- at the **repo root**, one or more levels above the Vite root
77
- (typically `site/` or `docs/`). The internal glob therefore matches
78
- nothing and you get:
79
-
80
- ```
81
- [@duffcloudservices/site-forms] No form definition found for "contact".
82
- Expected a YAML at /.dcs/forms/contact.yaml.
83
- ```
84
-
85
- The fix is a one-file loader the rest of your site imports from.
86
-
87
- #### Vue SPA (`vite.config.ts` in `site/`)
88
-
89
- ```ts
90
- // site/src/dcs-forms.ts
91
- const modules = import.meta.glob('../../.dcs/forms/*.yaml', {
92
- eager: true,
93
- import: 'default',
94
- })
95
- export const dcsFormsModules: Record<string, unknown> = modules
96
- ```
97
-
98
- #### VitePress (`vite` block in `docs/.vitepress/config.ts`)
99
-
100
- ```ts
101
- // docs/.vitepress/dcs-forms-loader.ts
102
- const modules = import.meta.glob('../../.dcs/forms/*.yaml', {
103
- eager: true,
104
- import: 'default',
105
- })
106
- export const dcsFormsModules: Record<string, unknown> = modules
107
- ```
108
-
109
- The relative depth (`../../`) depends on where the loader file lives
110
- relative to the repo root. Adjust as needed.
111
-
112
- ## Usage
113
-
114
- Place a YAML file at `<site>/.dcs/forms/contact.yaml`:
115
-
116
- ```yaml
117
- formId: contact
118
- title: Contact Us
119
- submission:
120
- kind: lead
121
- fields:
122
- - id: name
123
- type: text
124
- label: Name
125
- required: true
126
- - id: email
127
- type: email
128
- label: Email
129
- required: true
130
- - id: message
131
- type: textarea
132
- label: Message
133
- required: true
134
- ```
135
-
136
- Then in any page component:
137
-
138
- ```vue
139
- <script setup lang="ts">
140
- import { DcsForm } from '@duffcloudservices/site-forms'
141
- import { dcsFormsModules } from '@/dcs-forms'
142
- </script>
143
-
144
- <template>
145
- <DcsForm
146
- form-id="contact"
147
- :forms-modules="dcsFormsModules"
148
- @submit-success="onSuccess"
149
- @submit-error="onError"
150
- />
151
- </template>
152
- ```
153
-
154
- ## Props
155
-
156
- | Prop | Type | Default | Notes |
157
- | -------------------- | --------------------------------- | -------------------------------------- | ----------------------------------------------------------- |
158
- | `formId` | `string` (required) | | Matches `.dcs/forms/<formId>.yaml`. |
159
- | `siteSlug` | `string` | `import.meta.env.VITE_DCS_SITE_SLUG` | Path segment in the submission URL. |
160
- | `definitionOverride` | `PortalFormDefinition` | | Used by the portal preview iframe to show in-flight edits. |
161
- | `apiBase` | `string` | `import.meta.env.VITE_DCS_PUBLIC_API` | Override for tests / non-prod environments. |
162
- | `captchaToken` | `string` | | Attached to the submission payload when set. |
163
- | `formsModules` | `Record<string, unknown>` | internal fallback glob (rarely matches) | **Required in real sites.** Pass a `Record<string, unknown>` from your own `import.meta.glob('../../.dcs/forms/*.yaml', { eager: true, import: 'default' })` — see Vite setup section. |
164
-
165
- ## Emits
166
-
167
- | Event | Payload | When |
168
- | ------------------ | ---------------------- | ------------------------------------------- |
169
- | `submit-success` | `DcsFormSubmitSuccess` | API responded `2xx`. |
170
- | `submit-error` | `DcsFormSubmitError` | Network or non-2xx response after retries. |
171
- | `validation-error` | `FormErrors` | Submit attempted with invalid required/regex/etc. fields. |
172
-
173
- ## Slots
174
-
175
- Every slot exposes scoped data so consumers (KT Braun, Kept) can swap
176
- shadcn primitives in without forking field components.
177
-
178
- | Slot | Scope | Default |
179
- | ---------- | ------------------------------------------------------------------ | ---------------------------------------------------- |
180
- | `header` | `{ definition }` | `<h2>` + description |
181
- | `progress` | `{ current, total, step }` | `Step N of M — Title` (multi-step only) |
182
- | `actions` | `{ isFirstStep, isLastStep, submitting, prev, next }` | Plain `<button>` elements |
183
- | `success` | `{ definition }` | `definition.successMessage` |
184
- | `missing` | `{ formId }` | Friendly fallback when the YAML can't be found |
185
-
186
- Per-field components (`DcsFormText` etc.) expose `#input` slots so a
187
- shadcn site can replace the underlying primitive while keeping the
188
- wrapper, label, help, and error-message structure.
189
-
190
- ## Composables
191
-
192
- For sites that want a fully custom layout, drop `<DcsForm/>` and use
193
- the underlying composables directly:
194
-
195
- ```ts
196
- import {
197
- useDcsForm,
198
- validateForm,
199
- submitFormValues,
200
- parseFormYaml,
201
- } from '@duffcloudservices/site-forms'
202
- ```
203
-
204
- - `useDcsForm({ definition })` — reactive `values`, `errors`, `steps`,
205
- `next`, `prev`, `validateAll`, `collectSubmissionValues`, etc.
206
- - `validateForm(def, values, fieldIds?)` — pure validator usable in
207
- any setting (server-side, tests, custom adapters).
208
- - `submitFormValues({ apiBase, siteSlug, payload })` one-shot POST
209
- with a single retry on 5xx and `multipart/form-data` when files are
210
- present.
211
-
212
- ## Visual editor integration
213
-
214
- The form root carries `data-form-key="<formId>"` and every field
215
- wrapper carries `data-form-field-key="<fieldId>"`. The portal preview
216
- iframe bridge uses these to highlight and select form regions. Do not
217
- strip them in custom layouts.
218
-
219
- ## Schema validation
220
-
221
- In dev (`import.meta.env.DEV === true`) the runtime validates each
222
- loaded definition against the JSON Schema bundled in
223
- `src/schema/form-definition.schema.json` (snapshot of
224
- `contracts/dist/form-definition.schema.json`) and logs failures via
225
- `console.warn`. Production builds skip the warning to avoid noisy
226
- end-user consoles.
227
-
228
- When the contracts schema is regenerated (`pnpm --filter @dcs/contracts
229
- generate`), refresh the snapshot:
230
-
231
- ```powershell
232
- Copy-Item ../../contracts/dist/form-definition.schema.json ./src/schema/form-definition.schema.json -Force
233
- pnpm --filter @duffcloudservices/site-forms test --run
234
- ```
235
-
236
- ## Scripts
237
-
238
- ```powershell
239
- pnpm --filter @duffcloudservices/site-forms build # vite library build (esm + dts)
240
- pnpm --filter @duffcloudservices/site-forms test # vitest --run
241
- pnpm --filter @duffcloudservices/site-forms type-check # vue-tsc --noEmit
242
- ```
243
-
244
- ## Related docs
245
-
246
- - **Authoring guide** — [`.docs/forms/AUTHORING.md`](../../.docs/forms/AUTHORING.md)
247
- covers the YAML schema, worked examples, validation flow, HIPAA
248
- guardrails, and the hand-coded → `<DcsForm/>` migration recipe.
249
- - **Publishing** [`PUBLISHING.md`](./PUBLISHING.md) covers the
250
- registry, OIDC trusted publishing, version bump policy, and the
251
- exact dep line sibling customer-site repos should add.
252
- - **Validation CLI** — [`cli/forms/README.md`](../../cli/forms/README.md)
253
- documents `dcs forms validate` and `dcs forms doctor`, which lint
254
- the `.dcs/forms/*.yaml` files in a customer-site repo.
255
-
256
- ## Ownership
257
-
258
- Per `packages/README.md`: external/consumer-facing docs live here, not
259
- in repo-root docs. Cross-cutting details (e.g. the public submissions
260
- API contract) belong in `contracts/README.md`.
1
+ # @duffcloudservices/site-forms
2
+
3
+ Shared `<DcsForm/>` runtime for DCS customer sites. Renders a managed
4
+ form definition (created in the portal Form Manager) from a build-time
5
+ `.dcs/forms/<formId>.yaml` snapshot, validates user input, and posts
6
+ submissions to the public site-forms API.
7
+
8
+ This is the single import surface for managed-form runtime code on
9
+ customer sites — do not redefine field components per site.
10
+
11
+ > **Inside the `dcs-again` workspace** the package is also reachable
12
+ > as `@duffcloudservices/site-forms` via `workspace:*` (the workspace
13
+ > name and the published name are the same).
14
+ > **In sibling customer-site repos** install the published package
15
+ > from public npm — see [`PUBLISHING.md`](./PUBLISHING.md) for the
16
+ > consumption story and registry setup.
17
+
18
+ ## Install
19
+
20
+ ### In a workspace app (inside `dcs-again`)
21
+
22
+ ```jsonc
23
+ // portal/package.json
24
+ {
25
+ "dependencies": {
26
+ "@duffcloudservices/site-forms": "workspace:*"
27
+ }
28
+ }
29
+ ```
30
+
31
+ Then `pnpm install` from the repo root.
32
+
33
+ ### In a sibling customer-site repo (e.g. `ktbraunlaw`, `kept`)
34
+
35
+ ```powershell
36
+ pnpm add @duffcloudservices/site-forms
37
+ ```
38
+
39
+ See [`PUBLISHING.md`](./PUBLISHING.md) for the registry, version, and
40
+ release-workflow details.
41
+
42
+ ## Vite setup
43
+
44
+ Three pieces are required in the consuming site:
45
+
46
+ 1. **`vite-plugin-yaml`** so YAML modules return parsed objects:
47
+
48
+ ```ts
49
+ // vite.config.ts
50
+ import yaml from '@modyfi/vite-plugin-yaml'
51
+
52
+ export default defineConfig({
53
+ plugins: [vue(), yaml()],
54
+ })
55
+ ```
56
+
57
+ Without it, the loader falls back to parsing raw strings via
58
+ `js-yaml`, which works but pays the parse cost at boot.
59
+
60
+ 2. **A `formsModules` loader** in your site that does the
61
+ `import.meta.glob` from a path Vite can resolve (see below).
62
+
63
+ 3. **Env vars** the runtime reads:
64
+
65
+ | Variable | Purpose |
66
+ | ----------------------- | ---------------------------------------------------- |
67
+ | `VITE_DCS_PUBLIC_API` | Base URL of the DCS public API (no trailing slash). |
68
+ | `VITE_DCS_SITE_SLUG` | Default site slug used when the prop is omitted. |
69
+
70
+ ### Why the `formsModules` prop is required in real sites
71
+
72
+ `<DcsForm/>` ships with an internal `import.meta.glob('/.dcs/forms/*.yaml')`
73
+ fallback, but Vite resolves the leading `/` against the **consumer's
74
+ Vite project root** (the directory containing `vite.config.ts`).
75
+ On every customer-site repo today, the `.dcs/forms/` directory lives
76
+ at the **repo root**, one or more levels above the Vite root
77
+ (typically `site/` or `docs/`). The internal glob therefore matches
78
+ nothing and you get:
79
+
80
+ ```
81
+ [@duffcloudservices/site-forms] No form definition found for "contact".
82
+ Expected a YAML at /.dcs/forms/contact.yaml.
83
+ ```
84
+
85
+ The fix is a one-file loader the rest of your site imports from.
86
+
87
+ #### Vue SPA (`vite.config.ts` in `site/`)
88
+
89
+ ```ts
90
+ // site/src/dcs-forms.ts
91
+ const modules = import.meta.glob('../../.dcs/forms/*.yaml', {
92
+ eager: true,
93
+ import: 'default',
94
+ })
95
+ export const dcsFormsModules: Record<string, unknown> = modules
96
+ ```
97
+
98
+ #### VitePress (`vite` block in `docs/.vitepress/config.ts`)
99
+
100
+ ```ts
101
+ // docs/.vitepress/dcs-forms-loader.ts
102
+ const modules = import.meta.glob('../../.dcs/forms/*.yaml', {
103
+ eager: true,
104
+ import: 'default',
105
+ })
106
+ export const dcsFormsModules: Record<string, unknown> = modules
107
+ ```
108
+
109
+ The relative depth (`../../`) depends on where the loader file lives
110
+ relative to the repo root. Adjust as needed.
111
+
112
+ ## Usage
113
+
114
+ Place a YAML file at `<site>/.dcs/forms/contact.yaml`:
115
+
116
+ ```yaml
117
+ formId: contact
118
+ submission:
119
+ kind: lead
120
+ fields:
121
+ - id: name
122
+ type: text
123
+ label: Name
124
+ required: true
125
+ - id: email
126
+ type: email
127
+ label: Email
128
+ required: true
129
+ - id: message
130
+ type: textarea
131
+ label: Message
132
+ required: true
133
+ ```
134
+
135
+ Then in any page component:
136
+
137
+ ```vue
138
+ <script setup lang="ts">
139
+ import { DcsForm } from '@duffcloudservices/site-forms'
140
+ import { dcsFormsModules } from '@/dcs-forms'
141
+ </script>
142
+
143
+ <template>
144
+ <DcsForm
145
+ form-id="contact"
146
+ :forms-modules="dcsFormsModules"
147
+ @submit-success="onSuccess"
148
+ @submit-error="onError"
149
+ />
150
+ </template>
151
+ ```
152
+
153
+ ## Props
154
+
155
+ | Prop | Type | Default | Notes |
156
+ | -------------------- | --------------------------------- | -------------------------------------- | ----------------------------------------------------------- |
157
+ | `formId` | `string` (required) | | Matches `.dcs/forms/<formId>.yaml`. |
158
+ | `siteSlug` | `string` | `import.meta.env.VITE_DCS_SITE_SLUG` | Path segment in the submission URL. |
159
+ | `definitionOverride` | `PortalFormDefinition` | | Used by the portal preview iframe to show in-flight edits. |
160
+ | `apiBase` | `string` | `import.meta.env.VITE_DCS_PUBLIC_API` | Override for tests / non-prod environments. |
161
+ | `captchaToken` | `string` | | Attached to the submission payload when set. |
162
+ | `formsModules` | `Record<string, unknown>` | internal fallback glob (rarely matches) | **Required in real sites.** Pass a `Record<string, unknown>` from your own `import.meta.glob('../../.dcs/forms/*.yaml', { eager: true, import: 'default' })` — see Vite setup section. |
163
+
164
+ ## Emits
165
+
166
+ | Event | Payload | When |
167
+ | ------------------ | ---------------------- | ------------------------------------------- |
168
+ | `submit-success` | `DcsFormSubmitSuccess` | API responded `2xx`. |
169
+ | `submit-error` | `DcsFormSubmitError` | Network or non-2xx response after retries. |
170
+ | `validation-error` | `FormErrors` | Submit attempted with invalid required/regex/etc. fields. |
171
+
172
+ ## Slots
173
+
174
+ Every slot exposes scoped data so consumers (KT Braun, Kept) can swap
175
+ shadcn primitives in without forking field components.
176
+
177
+ | Slot | Scope | Default |
178
+ | ---------- | ------------------------------------------------------------------ | ---------------------------------------------------- |
179
+ | `header` | `{ definition }` | Empty; page/section headings live outside the managed form |
180
+ | `progress` | `{ current, total, step }` | `Step N of M — Title` (multi-step only) |
181
+ | `actions` | `{ isFirstStep, isLastStep, submitting, prev, next }` | Plain `<button>` elements |
182
+ | `success` | `{ definition }` | `definition.successMessage` |
183
+ | `missing` | `{ formId }` | Friendly fallback when the YAML can't be found |
184
+
185
+ Per-field components (`DcsFormText` etc.) expose `#input` slots so a
186
+ shadcn site can replace the underlying primitive while keeping the
187
+ wrapper, label, help, and error-message structure.
188
+
189
+ ## Composables
190
+
191
+ For sites that want a fully custom layout, drop `<DcsForm/>` and use
192
+ the underlying composables directly:
193
+
194
+ ```ts
195
+ import {
196
+ useDcsForm,
197
+ validateForm,
198
+ submitFormValues,
199
+ parseFormYaml,
200
+ } from '@duffcloudservices/site-forms'
201
+ ```
202
+
203
+ - `useDcsForm({ definition })` — reactive `values`, `errors`, `steps`,
204
+ `next`, `prev`, `validateAll`, `collectSubmissionValues`, etc.
205
+ - `validateForm(def, values, fieldIds?)` — pure validator usable in
206
+ any setting (server-side, tests, custom adapters).
207
+ - `submitFormValues({ apiBase, siteSlug, payload })` — one-shot POST
208
+ with a single retry on 5xx and `multipart/form-data` when files are
209
+ present.
210
+
211
+ ## Visual editor integration
212
+
213
+ The form root carries `data-form-key="<formId>"` and every field
214
+ wrapper carries `data-form-field-key="<fieldId>"`. The portal preview
215
+ iframe bridge uses these to discover managed forms, show the preview
216
+ affordance, and route preview click / context-menu actions into the same
217
+ portal `FormManagerSheet`. Do not strip these attributes in custom
218
+ layouts.
219
+
220
+ `definitionOverride` is a preview-only draft path for the iframe. The
221
+ durable form truth still lives in the form definition saved by the
222
+ portal and in the committed `.dcs/forms/<formId>.yaml` snapshot consumed
223
+ by the site runtime.
224
+
225
+ For the cross-package first-party component contract (runtime markers,
226
+ bridge discovery, portal entry points, rollout, validation), see
227
+ [`../FIRST-PARTY-COMPONENTS.md`](../FIRST-PARTY-COMPONENTS.md).
228
+
229
+ ## Schema validation
230
+
231
+ In dev (`import.meta.env.DEV === true`) the runtime validates each
232
+ loaded definition against the JSON Schema bundled in
233
+ `src/schema/form-definition.schema.json` (snapshot of
234
+ `contracts/dist/form-definition.schema.json`) and logs failures via
235
+ `console.warn`. Production builds skip the warning to avoid noisy
236
+ end-user consoles.
237
+
238
+ When the contracts schema is regenerated (`pnpm --filter @dcs/contracts
239
+ generate`), refresh the snapshot:
240
+
241
+ ```powershell
242
+ Copy-Item ../../contracts/dist/form-definition.schema.json ./src/schema/form-definition.schema.json -Force
243
+ pnpm --filter @duffcloudservices/site-forms test --run
244
+ ```
245
+
246
+ ## Scripts
247
+
248
+ ```powershell
249
+ pnpm --filter @duffcloudservices/site-forms build # vite library build (esm + dts)
250
+ pnpm --filter @duffcloudservices/site-forms test # vitest --run
251
+ pnpm --filter @duffcloudservices/site-forms type-check # vue-tsc --noEmit
252
+ ```
253
+
254
+ ## Related docs
255
+
256
+ - **Authoring guide** — [`.docs/forms/AUTHORING.md`](../../.docs/forms/AUTHORING.md)
257
+ covers the YAML schema, worked examples, validation flow, HIPAA
258
+ guardrails, and the hand-coded `<DcsForm/>` migration recipe.
259
+ - **Publishing** [`PUBLISHING.md`](./PUBLISHING.md) covers the
260
+ registry, OIDC trusted publishing, version bump policy, and the
261
+ exact dep line sibling customer-site repos should add.
262
+ - **First-party visual-editor contract** —
263
+ [`../FIRST-PARTY-COMPONENTS.md`](../FIRST-PARTY-COMPONENTS.md)
264
+ captures the shared adaptation model used by forms and future
265
+ component families.
266
+ - **Validation CLI** — [`cli/forms/README.md`](../../cli/forms/README.md)
267
+ documents `dcs forms validate` and `dcs forms doctor`, which lint
268
+ the `.dcs/forms/*.yaml` files in a customer-site repo.
269
+
270
+ ## Ownership
271
+
272
+ Per `packages/README.md`: external/consumer-facing docs live here, not
273
+ in repo-root docs. Cross-cutting details (e.g. the public submissions
274
+ API contract) belong in `contracts/README.md`.
@@ -10,7 +10,7 @@ export interface SubmitOptions {
10
10
  }
11
11
  /**
12
12
  * POSTs a form submission to
13
- * `${apiBase}/public/sites/{siteSlug}/form-submissions`.
13
+ * `${apiBase}/sites/{siteSlug}/forms/{formId}/submissions`.
14
14
  *
15
15
  * Uses JSON for plain values and `multipart/form-data` when any
16
16
  * value is a `File` (file-upload fields).
package/dist/index.d.ts CHANGED
@@ -17,6 +17,8 @@ export { validateField, validateForm, isFieldVisible, hasErrors, } from './compo
17
17
  export { submitFormValues } from './composables/useFormSubmission';
18
18
  export type { SubmitOptions } from './composables/useFormSubmission';
19
19
  export { loadFormDefinitions, parseFormYaml } from './loaders/yaml';
20
+ export { buildStandardFormDefinition, STANDARD_FORM_PRESET_META, } from './presets';
21
+ export type { StandardFormPreset, BuildStandardFormOptions, } from './presets';
20
22
  export { validateFormDefinition, warnIfInvalid, } from './schema/validate';
21
23
  export type { SchemaValidationResult } from './schema/validate';
22
- export type { DcsFormSubmitPayload, DcsFormSubmitSuccess, DcsFormSubmitError, FormErrors, FormValues, PortalFormDefinition, PortalFormField, PortalFormFieldType, PortalFormFieldOption, PortalFormFieldValidation, PortalFormFieldVisibleIf, PortalFormFieldWidth, PortalFormStep, PortalFormSubmissionConfig, PortalFormSubmissionLeadConfig, PortalFormSubmissionEmailConfig, PortalFormSubmissionWebhookConfig, } from './types';
24
+ export type { DcsFormSubmitPayload, DcsFormSubmitSuccess, DcsFormSubmitError, FormErrors, FormValues, PortalFormDefinition, PortalFormField, PortalFormKind, PortalFormFieldRole, PortalFormAttachmentPolicy, PortalFormFieldType, PortalFormFieldOption, PortalFormFieldValidation, PortalFormFieldVisibleIf, PortalFormFieldWidth, PortalFormStep, PortalFormSubmissionConfig, PortalFormSubmissionLeadConfig, PortalFormSubmissionEmailConfig, PortalFormSubmissionWebhookConfig, } from './types';