@businessdash/sdk 0.9.80 → 0.9.90
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/README.md +133 -949
- package/assets/{biab-sw.js → bd-sw.js} +2 -2
- package/dist/account-core/index.d.ts +1 -1
- package/dist/account-core/index.d.ts.map +1 -1
- package/dist/adapters-revalidate.d.ts +2 -2
- package/dist/adapters-revalidate.js +2 -2
- package/dist/adapters-revalidate.js.map +1 -1
- package/dist/analytics-core.d.ts +6 -6
- package/dist/analytics-core.d.ts.map +1 -1
- package/dist/analytics-core.js +4 -4
- package/dist/analytics-core.js.map +1 -1
- package/dist/analytics-server.d.ts +6 -6
- package/dist/analytics-server.d.ts.map +1 -1
- package/dist/analytics-server.js +5 -5
- package/dist/auth-handler.d.ts +14 -14
- package/dist/auth-handler.d.ts.map +1 -1
- package/dist/auth-handler.js +16 -16
- package/dist/auth-handler.js.map +1 -1
- package/dist/auth-links.d.ts +2 -2
- package/dist/auth-links.d.ts.map +1 -1
- package/dist/auth-links.js +2 -2
- package/dist/auth-links.js.map +1 -1
- package/dist/{biab-forms.css → bd-forms.css} +158 -158
- package/dist/cli.d.ts +4 -4
- package/dist/cli.js +78 -78
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +158 -147
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +156 -137
- package/dist/client.js.map +1 -1
- package/dist/consent-core/index.cjs +2 -2
- package/dist/consent-core/index.d.ts +2 -2
- package/dist/consent-core/index.d.ts.map +1 -1
- package/dist/consent-core/index.js +10 -8
- package/dist/consent-core/index.js.map +1 -1
- package/dist/contracts.d.ts +411 -52
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +89 -15
- package/dist/contracts.js.map +1 -1
- package/dist/data-model-schema.d.ts +15 -15
- package/dist/data-model-schema.d.ts.map +1 -1
- package/dist/data-model-schema.js +19 -17
- package/dist/data-model-schema.js.map +1 -1
- package/dist/distribution.d.ts +5 -5
- package/dist/distribution.d.ts.map +1 -1
- package/dist/distribution.js +4 -4
- package/dist/element.d.ts +36 -36
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +43 -43
- package/dist/element.js.map +1 -1
- package/dist/embed-protocol.d.ts +11 -11
- package/dist/embed-protocol.d.ts.map +1 -1
- package/dist/embed-protocol.js +1 -1
- package/dist/embed-protocol.js.map +1 -1
- package/dist/errors.d.ts +15 -15
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -18
- package/dist/errors.js.map +1 -1
- package/dist/forms-core/autocomplete.d.ts +3 -3
- package/dist/forms-core/autocomplete.d.ts.map +1 -1
- package/dist/forms-core/autocomplete.js +2 -2
- package/dist/forms-core/controller.d.ts +10 -10
- package/dist/forms-core/controller.d.ts.map +1 -1
- package/dist/forms-core/controller.js +4 -4
- package/dist/forms-core/controller.js.map +1 -1
- package/dist/forms-core/elements.d.ts +4 -4
- package/dist/forms-core/elements.d.ts.map +1 -1
- package/dist/forms-core/elements.js +7 -7
- package/dist/forms-core/elements.js.map +1 -1
- package/dist/forms-core/formula.d.ts +1 -1
- package/dist/forms-core/formula.js +1 -1
- package/dist/forms-core/index.d.ts +6 -6
- package/dist/forms-core/index.d.ts.map +1 -1
- package/dist/forms-core/index.js +5 -5
- package/dist/forms-core/index.js.map +1 -1
- package/dist/forms-core/units.d.ts +1 -1
- package/dist/forms-core/units.js +1 -1
- package/dist/forms-core/us-states.d.ts +1 -1
- package/dist/forms-core/us-states.js +1 -1
- package/dist/forms-core/validation.d.ts +12 -3
- package/dist/forms-core/validation.d.ts.map +1 -1
- package/dist/forms-core/validation.js +152 -17
- package/dist/forms-core/validation.js.map +1 -1
- package/dist/forms.d.ts +2 -2
- package/dist/forms.d.ts.map +1 -1
- package/dist/forms.js +2 -2
- package/dist/forms.js.map +1 -1
- package/dist/framework-support.js +1 -1
- package/dist/framework-support.js.map +1 -1
- package/dist/gallery-types.d.ts +1 -1
- package/dist/graphql.d.ts +3 -3
- package/dist/graphql.d.ts.map +1 -1
- package/dist/graphql.js +3 -3
- package/dist/graphql.js.map +1 -1
- package/dist/index.cjs +351 -272
- package/dist/index.d.cts +5 -5
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/legal-core/index.cjs +8 -8
- package/dist/legal-core/index.d.ts +3 -3
- package/dist/legal-core/index.d.ts.map +1 -1
- package/dist/legal-core/index.js +11 -11
- package/dist/legal-core/index.js.map +1 -1
- package/dist/marketing-core/index.d.ts +51 -1
- package/dist/marketing-core/index.d.ts.map +1 -1
- package/dist/marketing-core/index.js +35 -0
- package/dist/marketing-core/index.js.map +1 -1
- package/dist/marketing-schema.d.ts +9 -9
- package/dist/marketing-schema.d.ts.map +1 -1
- package/dist/marketing-schema.js +1 -1
- package/dist/mcp.d.ts +4 -4
- package/dist/mcp.js +4 -4
- package/dist/native.d.ts +6 -6
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +4 -4
- package/dist/native.js.map +1 -1
- package/dist/next-revalidate.d.ts +8 -8
- package/dist/next-revalidate.d.ts.map +1 -1
- package/dist/next-revalidate.js +7 -7
- package/dist/next-revalidate.js.map +1 -1
- package/dist/notifications-core/index.d.ts +1 -1
- package/dist/notifications-core/index.js +1 -1
- package/dist/parallel-pages.d.ts +4 -4
- package/dist/parallel-pages.d.ts.map +1 -1
- package/dist/parallel-pages.js +5 -5
- package/dist/parallel-pages.js.map +1 -1
- package/dist/portal-core/index.d.ts +1 -1
- package/dist/portal-core/index.js +1 -1
- package/dist/proxy.d.ts +18 -18
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +10 -10
- package/dist/proxy.js.map +1 -1
- package/dist/push-core/index.cjs +6 -2
- package/dist/push-core/index.d.ts +1 -1
- package/dist/push-core/index.d.ts.map +1 -1
- package/dist/push-core/index.js +6 -2
- package/dist/push-core/index.js.map +1 -1
- package/dist/react-analytics.d.ts +14 -14
- package/dist/react-analytics.d.ts.map +1 -1
- package/dist/react-analytics.js +15 -15
- package/dist/react-analytics.js.map +1 -1
- package/dist/react-attribution.d.ts +2 -2
- package/dist/react-attribution.d.ts.map +1 -1
- package/dist/react-attribution.js +1 -1
- package/dist/react-marketing.js +5 -5
- package/dist/react-marketing.js.map +1 -1
- package/dist/react.d.ts +38 -61
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +247 -261
- package/dist/react.js.map +1 -1
- package/dist/reserved-paths.d.ts +2 -2
- package/dist/reserved-paths.js +3 -3
- package/dist/reserved-paths.js.map +1 -1
- package/dist/revalidate-verify.d.ts +3 -3
- package/dist/revalidate-verify.d.ts.map +1 -1
- package/dist/revalidate-verify.js +1 -1
- package/dist/revalidate-verify.js.map +1 -1
- package/dist/sdk.d.ts +51 -45
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +48 -50
- package/dist/sdk.js.map +1 -1
- package/dist/seed-core/index.js +8 -8
- package/dist/seed-core/index.js.map +1 -1
- package/dist/seo-core/blog.d.ts +1 -1
- package/dist/seo-core/blog.js +1 -1
- package/dist/seo-core/blog.js.map +1 -1
- package/dist/seo-core/index.cjs +2 -2
- package/dist/seo-core/index.js +1 -1
- package/dist/seo-core/index.js.map +1 -1
- package/dist/seo.d.ts +1 -1
- package/dist/seo.d.ts.map +1 -1
- package/dist/seo.js +1 -1
- package/dist/seo.js.map +1 -1
- package/dist/sitemap-core/index.cjs +5 -5
- package/dist/sitemap-core/index.d.ts +13 -5
- package/dist/sitemap-core/index.d.ts.map +1 -1
- package/dist/sitemap-core/index.js +4 -4
- package/dist/sitemap-core/index.js.map +1 -1
- package/dist/socials.d.ts +6 -6
- package/dist/socials.d.ts.map +1 -1
- package/dist/socials.js +5 -5
- package/dist/socials.js.map +1 -1
- package/dist/solid-compat.d.ts +1 -1
- package/dist/solid-compat.js +4 -4
- package/dist/solid-compat.js.map +1 -1
- package/dist/store-core/index.d.ts +1 -1
- package/dist/vanilla.d.ts +12 -12
- package/dist/vanilla.d.ts.map +1 -1
- package/dist/vanilla.js +192 -145
- package/dist/vanilla.js.map +1 -1
- package/openapi.json +264 -1
- package/package.json +8 -8
- package/src/account-core/index.ts +1 -1
- package/src/adapters-revalidate.ts +3 -3
- package/src/analytics-core.ts +8 -8
- package/src/analytics-server.ts +6 -6
- package/src/angular/{biab-form.component.ts → bd-form.component.ts} +269 -161
- package/src/angular/headless.ts +12 -12
- package/src/angular/index.ts +9 -9
- package/src/auth-handler.ts +22 -22
- package/src/auth-links.ts +2 -2
- package/src/cli.ts +81 -81
- package/src/client.ts +218 -193
- package/src/consent-core/index.ts +10 -8
- package/src/contracts.ts +99 -15
- package/src/data-model-schema.ts +29 -26
- package/src/distribution.ts +5 -5
- package/src/element.ts +54 -54
- package/src/embed-protocol.ts +14 -14
- package/src/errors.ts +27 -27
- package/src/forms-core/autocomplete.ts +3 -3
- package/src/forms-core/controller.ts +12 -12
- package/src/forms-core/elements.ts +7 -7
- package/src/forms-core/formula.ts +1 -1
- package/src/forms-core/index.ts +8 -8
- package/src/forms-core/units.ts +1 -1
- package/src/forms-core/us-states.ts +1 -1
- package/src/forms-core/validation.ts +158 -14
- package/src/forms.ts +2 -2
- package/src/framework-support.ts +1 -1
- package/src/gallery-types.ts +1 -1
- package/src/graphql.ts +4 -4
- package/src/index.ts +38 -38
- package/src/legal-core/index.ts +12 -12
- package/src/marketing-core/index.ts +62 -0
- package/src/marketing-schema.ts +9 -9
- package/src/mcp.ts +4 -4
- package/src/native.ts +14 -14
- package/src/next-revalidate.ts +10 -10
- package/src/notifications-core/index.ts +1 -1
- package/src/parallel-pages.ts +6 -6
- package/src/portal-core/index.ts +1 -1
- package/src/proxy.ts +28 -28
- package/src/push-core/index.ts +11 -5
- package/src/qwik.tsx +262 -166
- package/src/react-analytics.tsx +17 -17
- package/src/react-attribution.tsx +2 -2
- package/src/react-marketing.tsx +5 -5
- package/src/react.tsx +541 -500
- package/src/reserved-paths.ts +3 -3
- package/src/revalidate-verify.ts +5 -5
- package/src/sdk.ts +131 -101
- package/src/seed-core/index.ts +8 -8
- package/src/seo-core/blog.ts +2 -2
- package/src/seo-core/index.ts +1 -1
- package/src/seo.ts +1 -1
- package/src/sitemap-core/index.ts +17 -9
- package/src/socials.ts +6 -6
- package/src/solid-compat.tsx +5 -5
- package/src/solid-surfaces.tsx +28 -28
- package/src/solid.tsx +264 -175
- package/src/store-core/index.ts +1 -1
- package/src/styles/{biab-forms.css → bd-forms.css} +158 -158
- package/src/svelte/{BiabForm.svelte → BdForm.svelte} +240 -173
- package/src/svelte/context.ts +16 -16
- package/src/svelte/headless.ts +10 -10
- package/src/svelte/index.ts +16 -16
- package/src/vanilla.ts +250 -169
- package/src/vue/{BiabForm.vue → BdForm.vue} +270 -157
- package/src/vue/headless.ts +11 -11
- package/src/vue/index.ts +26 -26
package/src/solid.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@businessdash/sdk/solid` — the `<
|
|
2
|
+
* `@businessdash/sdk/solid` — the `<BdForm>` drop-in for SolidJS.
|
|
3
3
|
*
|
|
4
4
|
* Ship mode: SOURCE (.tsx). This file is published as-is and compiled by the
|
|
5
5
|
* consumer's Solid/JSX toolchain (vite-plugin-solid / babel-preset-solid). It is
|
|
6
|
-
* NOT tsc-compiled inside
|
|
6
|
+
* NOT tsc-compiled inside bd, so it has zero build artifact here.
|
|
7
7
|
*
|
|
8
8
|
* It is a thin, idiomatic Solid view over the framework-agnostic headless core
|
|
9
9
|
* (`createFormController`, exported from `@businessdash/sdk/forms`). All runtime
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* 1. Bridges the controller's subscribe/snapshot observable into Solid
|
|
15
15
|
* reactivity with `from()` (the canonical "external store → Signal" adapter).
|
|
16
|
-
* 2. Renders the snapshot's nested field tree by `type` using the `
|
|
16
|
+
* 2. Renders the snapshot's nested field tree by `type` using the `bd-*`
|
|
17
17
|
* light-DOM class convention (no shadow root) so the consumer's own CSS
|
|
18
18
|
* cascades onto every field.
|
|
19
19
|
* 3. Applies the published `schema.settings` (animation, multi-step + progress
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
} from "./solid-compat.js";
|
|
56
56
|
|
|
57
57
|
import type {
|
|
58
|
-
|
|
58
|
+
BdClient,
|
|
59
59
|
FormFileValue,
|
|
60
60
|
FormSchema,
|
|
61
61
|
FormSubmitResult,
|
|
@@ -77,39 +77,39 @@ import {
|
|
|
77
77
|
} from "./forms-core/autocomplete.js";
|
|
78
78
|
|
|
79
79
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
80
|
-
// Client context — optional Provider-based DI so a tree of `<
|
|
80
|
+
// Client context — optional Provider-based DI so a tree of `<BdForm>`s can
|
|
81
81
|
// share one client instead of threading `client` through every prop.
|
|
82
82
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
83
83
|
|
|
84
|
-
const
|
|
84
|
+
const BdClientContext = createContext<Accessor<BdClient | undefined>>();
|
|
85
85
|
/** Solid 1 exposes `.Provider`; Solid 2 makes the context its own provider. */
|
|
86
|
-
const
|
|
87
|
-
|
|
86
|
+
const BdClientProvider = providerFor<Accessor<BdClient | undefined>>(
|
|
87
|
+
BdClientContext,
|
|
88
88
|
);
|
|
89
89
|
|
|
90
|
-
export interface
|
|
91
|
-
/** The SDK client shared with descendant `<
|
|
92
|
-
client:
|
|
90
|
+
export interface BdProviderProps {
|
|
91
|
+
/** The SDK client shared with descendant `<BdForm>`s. */
|
|
92
|
+
client: BdClient;
|
|
93
93
|
children?: SolidNode;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Provide a single `
|
|
97
|
+
* Provide a single `BdClient` to a subtree. Any descendant `<BdForm>` that
|
|
98
98
|
* doesn't get its own `client` prop falls back to this one. Optional — passing
|
|
99
|
-
* `client` directly to `<
|
|
99
|
+
* `client` directly to `<BdForm>` works without a provider.
|
|
100
100
|
*/
|
|
101
|
-
export function
|
|
101
|
+
export function BdProvider(props: BdProviderProps) {
|
|
102
102
|
const value = createMemo(() => props.client);
|
|
103
103
|
return (
|
|
104
|
-
<
|
|
104
|
+
<BdClientProvider value={value}>
|
|
105
105
|
{renderNode(props.children)}
|
|
106
|
-
</
|
|
106
|
+
</BdClientProvider>
|
|
107
107
|
);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
/** Read the client supplied by the nearest `<
|
|
111
|
-
export function
|
|
112
|
-
const ctx = useContext(
|
|
110
|
+
/** Read the client supplied by the nearest `<BdProvider>` (or `undefined`). */
|
|
111
|
+
export function useBdClient(): BdClient | undefined {
|
|
112
|
+
const ctx = useContext(BdClientContext);
|
|
113
113
|
return ctx?.();
|
|
114
114
|
}
|
|
115
115
|
|
|
@@ -122,7 +122,7 @@ export function useBiabClient(): BiabClient | undefined {
|
|
|
122
122
|
// every notify. Disposes the controller on cleanup.
|
|
123
123
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
124
124
|
|
|
125
|
-
export interface
|
|
125
|
+
export interface BdFormStore {
|
|
126
126
|
/** Reactive snapshot accessor — read it inside JSX / memos to track changes. */
|
|
127
127
|
snapshot: Accessor<FormSnapshot>;
|
|
128
128
|
/** The underlying controller (imperative escape hatch). */
|
|
@@ -133,11 +133,11 @@ export interface BiabFormStore {
|
|
|
133
133
|
* Create a controller-backed reactive store. Kicks off `load()` on mount (so
|
|
134
134
|
* SSR-adopted schemas stay synchronous and client loads fire once), and tears
|
|
135
135
|
* the controller down on cleanup. Use this when you want the headless behaviour
|
|
136
|
-
* but your own markup; `<
|
|
136
|
+
* but your own markup; `<BdForm>` uses it internally.
|
|
137
137
|
*/
|
|
138
138
|
export function createFormStore(
|
|
139
139
|
options: CreateFormControllerOptions,
|
|
140
|
-
):
|
|
140
|
+
): BdFormStore {
|
|
141
141
|
const controller = createFormController(options);
|
|
142
142
|
|
|
143
143
|
// `fromStore` bridges the controller's snapshot/subscribe contract into a
|
|
@@ -156,7 +156,7 @@ export function createFormStore(
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
159
|
-
// CSS-hook helpers — mirror the dashboard renderer's `data-
|
|
159
|
+
// CSS-hook helpers — mirror the dashboard renderer's `data-bd-*` attributes so
|
|
160
160
|
// org overrides written against the dashboard preview also target this drop-in.
|
|
161
161
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
162
162
|
|
|
@@ -179,7 +179,7 @@ function slugifyLabel(raw: string): string {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
|
-
* The `data-
|
|
182
|
+
* The `data-bd-field` value: a published `key`, else an explicit `outputKey`,
|
|
183
183
|
* else a camelCase slug of the label, else the id. Lets orgs target one field.
|
|
184
184
|
*/
|
|
185
185
|
function fieldCssKey(field: FormCoreField): string {
|
|
@@ -218,7 +218,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
218
218
|
const t = () => props.field.type;
|
|
219
219
|
const field = () => props.field;
|
|
220
220
|
// Resolved HTML autofill token for this field (or undefined to omit the
|
|
221
|
-
// attribute). Honors the global `<
|
|
221
|
+
// attribute). Honors the global `<BdForm autoComplete>` switch and per-field
|
|
222
222
|
// overrides; see forms-core/autocomplete.ts.
|
|
223
223
|
const ac = () => props.autocomplete?.(props.field);
|
|
224
224
|
|
|
@@ -226,7 +226,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
226
226
|
<Switch
|
|
227
227
|
fallback={
|
|
228
228
|
<input
|
|
229
|
-
class="
|
|
229
|
+
class="bd-input"
|
|
230
230
|
type="text"
|
|
231
231
|
placeholder={field().placeholder ?? ""}
|
|
232
232
|
value={asString(props.value())}
|
|
@@ -236,25 +236,25 @@ function FieldInput(props: FieldInputProps) {
|
|
|
236
236
|
}
|
|
237
237
|
>
|
|
238
238
|
<Match when={t() === "title"}>
|
|
239
|
-
<h2 class="
|
|
239
|
+
<h2 class="bd-field__title">{field().label || "Untitled"}</h2>
|
|
240
240
|
</Match>
|
|
241
241
|
<Match when={t() === "subtitle"}>
|
|
242
|
-
<h3 class="
|
|
242
|
+
<h3 class="bd-field__subtitle">{field().label || ""}</h3>
|
|
243
243
|
</Match>
|
|
244
244
|
<Match when={t() === "separator"}>
|
|
245
|
-
<hr class="
|
|
245
|
+
<hr class="bd-field__separator" />
|
|
246
246
|
</Match>
|
|
247
247
|
<Match when={t() === "richtext"}>
|
|
248
248
|
{/* The published content is org-authored; render it as plain text to
|
|
249
249
|
keep the binding free of an HTML-sanitizer dependency. Consumers
|
|
250
250
|
needing rich HTML can override this field via the `field` slot. */}
|
|
251
|
-
<div class="
|
|
251
|
+
<div class="bd-field__richtext">{field().content ?? ""}</div>
|
|
252
252
|
</Match>
|
|
253
253
|
<Match when={t() === "image"}>
|
|
254
254
|
<Show when={(field().imageConfig as { src?: string })?.src}>
|
|
255
255
|
{(src) => (
|
|
256
256
|
<img
|
|
257
|
-
class="
|
|
257
|
+
class="bd-field__image"
|
|
258
258
|
src={src()}
|
|
259
259
|
alt={(field().imageConfig as { alt?: string })?.alt ?? ""}
|
|
260
260
|
/>
|
|
@@ -264,7 +264,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
264
264
|
|
|
265
265
|
<Match when={t() === "textarea"}>
|
|
266
266
|
<textarea
|
|
267
|
-
class="
|
|
267
|
+
class="bd-textarea"
|
|
268
268
|
placeholder={field().placeholder ?? ""}
|
|
269
269
|
rows={(field().textareaConfig as { rows?: number })?.rows ?? 4}
|
|
270
270
|
value={asString(props.value())}
|
|
@@ -275,7 +275,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
275
275
|
|
|
276
276
|
<Match when={t() === "select"}>
|
|
277
277
|
<select
|
|
278
|
-
class="
|
|
278
|
+
class="bd-input bd-select"
|
|
279
279
|
value={asString(props.value())}
|
|
280
280
|
onChange={(e) => props.set(e.currentTarget.value)}
|
|
281
281
|
>
|
|
@@ -289,12 +289,12 @@ function FieldInput(props: FieldInputProps) {
|
|
|
289
289
|
</Match>
|
|
290
290
|
|
|
291
291
|
<Match when={t() === "radio"}>
|
|
292
|
-
<div class="
|
|
292
|
+
<div class="bd-radio-group">
|
|
293
293
|
<For each={field().options ?? []}>
|
|
294
294
|
{(opt) => {
|
|
295
295
|
const id = `${field().id}-${opt}`;
|
|
296
296
|
return (
|
|
297
|
-
<label class="
|
|
297
|
+
<label class="bd-radio" for={id}>
|
|
298
298
|
<input
|
|
299
299
|
type="radio"
|
|
300
300
|
id={id}
|
|
@@ -303,7 +303,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
303
303
|
checked={asString(props.value()) === opt}
|
|
304
304
|
onChange={() => props.set(opt)}
|
|
305
305
|
/>
|
|
306
|
-
<span class="
|
|
306
|
+
<span class="bd-radio__label">{opt}</span>
|
|
307
307
|
</label>
|
|
308
308
|
);
|
|
309
309
|
}}
|
|
@@ -312,7 +312,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
312
312
|
</Match>
|
|
313
313
|
|
|
314
314
|
<Match when={t() === "checkbox"}>
|
|
315
|
-
<div class="
|
|
315
|
+
<div class="bd-checkbox-group">
|
|
316
316
|
<For each={field().options ?? []}>
|
|
317
317
|
{(opt) => {
|
|
318
318
|
const arr = () =>
|
|
@@ -320,7 +320,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
320
320
|
? (props.value() as string[])
|
|
321
321
|
: [];
|
|
322
322
|
return (
|
|
323
|
-
<label class="
|
|
323
|
+
<label class="bd-checkbox">
|
|
324
324
|
<input
|
|
325
325
|
type="checkbox"
|
|
326
326
|
value={opt}
|
|
@@ -334,7 +334,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
334
334
|
);
|
|
335
335
|
}}
|
|
336
336
|
/>
|
|
337
|
-
<span class="
|
|
337
|
+
<span class="bd-checkbox__label">{opt}</span>
|
|
338
338
|
</label>
|
|
339
339
|
);
|
|
340
340
|
}}
|
|
@@ -343,13 +343,13 @@ function FieldInput(props: FieldInputProps) {
|
|
|
343
343
|
</Match>
|
|
344
344
|
|
|
345
345
|
<Match when={t() === "boolean"}>
|
|
346
|
-
<label class="
|
|
346
|
+
<label class="bd-switch">
|
|
347
347
|
<input
|
|
348
348
|
type="checkbox"
|
|
349
349
|
checked={props.value() === true}
|
|
350
350
|
onChange={(e) => props.set(e.currentTarget.checked)}
|
|
351
351
|
/>
|
|
352
|
-
<span class="
|
|
352
|
+
<span class="bd-switch__label">
|
|
353
353
|
{field().placeholder || "Yes / No"}
|
|
354
354
|
</span>
|
|
355
355
|
</label>
|
|
@@ -357,7 +357,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
357
357
|
|
|
358
358
|
<Match when={t() === "date"}>
|
|
359
359
|
<input
|
|
360
|
-
class="
|
|
360
|
+
class="bd-input"
|
|
361
361
|
type="date"
|
|
362
362
|
value={asString(props.value())}
|
|
363
363
|
onInput={(e) => props.set(e.currentTarget.value)}
|
|
@@ -366,7 +366,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
366
366
|
|
|
367
367
|
<Match when={t() === "email"}>
|
|
368
368
|
<input
|
|
369
|
-
class="
|
|
369
|
+
class="bd-input"
|
|
370
370
|
type="email"
|
|
371
371
|
placeholder={field().placeholder || "you@example.com"}
|
|
372
372
|
value={asString(props.value())}
|
|
@@ -376,14 +376,14 @@ function FieldInput(props: FieldInputProps) {
|
|
|
376
376
|
</Match>
|
|
377
377
|
|
|
378
378
|
<Match when={t() === "phone"}>
|
|
379
|
-
<div class="
|
|
379
|
+
<div class="bd-phone">
|
|
380
380
|
<Show when={(field().phoneConfig as { showFlags?: boolean })?.showFlags}>
|
|
381
|
-
<span class="
|
|
381
|
+
<span class="bd-phone__flag" aria-hidden="true">
|
|
382
382
|
🇺🇸
|
|
383
383
|
</span>
|
|
384
384
|
</Show>
|
|
385
385
|
<input
|
|
386
|
-
class="
|
|
386
|
+
class="bd-input"
|
|
387
387
|
type="tel"
|
|
388
388
|
placeholder={
|
|
389
389
|
field().placeholder ||
|
|
@@ -400,7 +400,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
400
400
|
|
|
401
401
|
<Match when={t() === "number"}>
|
|
402
402
|
<input
|
|
403
|
-
class="
|
|
403
|
+
class="bd-input"
|
|
404
404
|
type="number"
|
|
405
405
|
placeholder={field().placeholder ?? ""}
|
|
406
406
|
value={
|
|
@@ -419,13 +419,13 @@ function FieldInput(props: FieldInputProps) {
|
|
|
419
419
|
</Match>
|
|
420
420
|
|
|
421
421
|
<Match when={t() === "color_picker"}>
|
|
422
|
-
<div class="
|
|
422
|
+
<div class="bd-color-group">
|
|
423
423
|
<For each={field().options ?? []}>
|
|
424
424
|
{(color) => (
|
|
425
425
|
<button
|
|
426
426
|
type="button"
|
|
427
|
-
class={cx("
|
|
428
|
-
"
|
|
427
|
+
class={cx("bd-color-swatch", {
|
|
428
|
+
"bd-color-swatch--selected":
|
|
429
429
|
asString(props.value()) === color,
|
|
430
430
|
})}
|
|
431
431
|
style={{ "background-color": color }}
|
|
@@ -459,10 +459,10 @@ function FieldInput(props: FieldInputProps) {
|
|
|
459
459
|
? `${n}%`
|
|
460
460
|
: `${n}`;
|
|
461
461
|
return (
|
|
462
|
-
<div class="
|
|
463
|
-
<div class="
|
|
462
|
+
<div class="bd-slider">
|
|
463
|
+
<div class="bd-slider__scale">
|
|
464
464
|
<span>{fmt(min())}</span>
|
|
465
|
-
<span class="
|
|
465
|
+
<span class="bd-slider__value">{fmt(cur())}</span>
|
|
466
466
|
<span>{fmt(max())}</span>
|
|
467
467
|
</div>
|
|
468
468
|
<input
|
|
@@ -483,18 +483,18 @@ function FieldInput(props: FieldInputProps) {
|
|
|
483
483
|
const cur = () =>
|
|
484
484
|
typeof props.value() === "number" ? (props.value() as number) : 0;
|
|
485
485
|
return (
|
|
486
|
-
<div class="
|
|
486
|
+
<div class="bd-stepper">
|
|
487
487
|
<button
|
|
488
488
|
type="button"
|
|
489
|
-
class="
|
|
489
|
+
class="bd-stepper__btn"
|
|
490
490
|
onClick={() => props.set(cur() - 1)}
|
|
491
491
|
>
|
|
492
492
|
−
|
|
493
493
|
</button>
|
|
494
|
-
<span class="
|
|
494
|
+
<span class="bd-stepper__value">{cur()}</span>
|
|
495
495
|
<button
|
|
496
496
|
type="button"
|
|
497
|
-
class="
|
|
497
|
+
class="bd-stepper__btn"
|
|
498
498
|
onClick={() => props.set(cur() + 1)}
|
|
499
499
|
>
|
|
500
500
|
+
|
|
@@ -511,12 +511,12 @@ function FieldInput(props: FieldInputProps) {
|
|
|
511
511
|
const cur = () =>
|
|
512
512
|
typeof props.value() === "number" ? (props.value() as number) : 0;
|
|
513
513
|
return (
|
|
514
|
-
<div class="
|
|
514
|
+
<div class="bd-stars">
|
|
515
515
|
<For each={Array.from({ length: maxStars() })}>
|
|
516
516
|
{(_, i) => (
|
|
517
517
|
<button
|
|
518
518
|
type="button"
|
|
519
|
-
class={cx("
|
|
519
|
+
class={cx("bd-stars__star", { "bd-stars__star--on": i() < cur() })}
|
|
520
520
|
aria-label={`${i() + 1} star`}
|
|
521
521
|
onClick={() => props.set(i() + 1)}
|
|
522
522
|
>
|
|
@@ -535,12 +535,12 @@ function FieldInput(props: FieldInputProps) {
|
|
|
535
535
|
typeof props.value() === "number" ? (props.value() as number) : -1;
|
|
536
536
|
const emojis = ["😞", "😕", "😐", "🙂", "😄"];
|
|
537
537
|
return (
|
|
538
|
-
<div class="
|
|
538
|
+
<div class="bd-happiness">
|
|
539
539
|
<For each={emojis}>
|
|
540
540
|
{(emoji, i) => (
|
|
541
541
|
<button
|
|
542
542
|
type="button"
|
|
543
|
-
class={cx("
|
|
543
|
+
class={cx("bd-happiness__face", { "bd-happiness__face--on": i() === cur() })}
|
|
544
544
|
onClick={() => props.set(i())}
|
|
545
545
|
>
|
|
546
546
|
{emoji}
|
|
@@ -587,7 +587,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
587
587
|
};
|
|
588
588
|
return (
|
|
589
589
|
<select
|
|
590
|
-
class="
|
|
590
|
+
class="bd-input bd-select"
|
|
591
591
|
value={asString(props.value())}
|
|
592
592
|
onChange={(e) => props.set(e.currentTarget.value)}
|
|
593
593
|
>
|
|
@@ -609,11 +609,11 @@ function FieldInput(props: FieldInputProps) {
|
|
|
609
609
|
? (props.value() as { start?: string; end?: string })
|
|
610
610
|
: { start: "", end: "" });
|
|
611
611
|
return (
|
|
612
|
-
<div class="
|
|
613
|
-
<label class="
|
|
614
|
-
<span class="
|
|
612
|
+
<div class="bd-time-block">
|
|
613
|
+
<label class="bd-subfield">
|
|
614
|
+
<span class="bd-subfield__label">Start</span>
|
|
615
615
|
<input
|
|
616
|
-
class="
|
|
616
|
+
class="bd-input"
|
|
617
617
|
type="time"
|
|
618
618
|
value={v().start ?? ""}
|
|
619
619
|
onInput={(e) =>
|
|
@@ -621,10 +621,10 @@ function FieldInput(props: FieldInputProps) {
|
|
|
621
621
|
}
|
|
622
622
|
/>
|
|
623
623
|
</label>
|
|
624
|
-
<label class="
|
|
625
|
-
<span class="
|
|
624
|
+
<label class="bd-subfield">
|
|
625
|
+
<span class="bd-subfield__label">End</span>
|
|
626
626
|
<input
|
|
627
|
-
class="
|
|
627
|
+
class="bd-input"
|
|
628
628
|
type="time"
|
|
629
629
|
value={v().end ?? ""}
|
|
630
630
|
onInput={(e) =>
|
|
@@ -644,11 +644,11 @@ function FieldInput(props: FieldInputProps) {
|
|
|
644
644
|
? (props.value() as { date?: string; time?: string })
|
|
645
645
|
: { date: "", time: "" });
|
|
646
646
|
return (
|
|
647
|
-
<div class="
|
|
648
|
-
<label class="
|
|
649
|
-
<span class="
|
|
647
|
+
<div class="bd-appointment">
|
|
648
|
+
<label class="bd-subfield">
|
|
649
|
+
<span class="bd-subfield__label">Date</span>
|
|
650
650
|
<input
|
|
651
|
-
class="
|
|
651
|
+
class="bd-input"
|
|
652
652
|
type="date"
|
|
653
653
|
value={v().date ?? ""}
|
|
654
654
|
onInput={(e) =>
|
|
@@ -656,10 +656,10 @@ function FieldInput(props: FieldInputProps) {
|
|
|
656
656
|
}
|
|
657
657
|
/>
|
|
658
658
|
</label>
|
|
659
|
-
<label class="
|
|
660
|
-
<span class="
|
|
659
|
+
<label class="bd-subfield">
|
|
660
|
+
<span class="bd-subfield__label">Time</span>
|
|
661
661
|
<input
|
|
662
|
-
class="
|
|
662
|
+
class="bd-input"
|
|
663
663
|
type="time"
|
|
664
664
|
value={v().time ?? ""}
|
|
665
665
|
onInput={(e) =>
|
|
@@ -683,11 +683,11 @@ function FieldInput(props: FieldInputProps) {
|
|
|
683
683
|
? (props.value() as { start?: string; end?: string })
|
|
684
684
|
: { start: "", end: "" });
|
|
685
685
|
return (
|
|
686
|
-
<div class="
|
|
687
|
-
<label class="
|
|
688
|
-
<span class="
|
|
686
|
+
<div class="bd-date-range">
|
|
687
|
+
<label class="bd-subfield">
|
|
688
|
+
<span class="bd-subfield__label">Start</span>
|
|
689
689
|
<input
|
|
690
|
-
class="
|
|
690
|
+
class="bd-input"
|
|
691
691
|
type="date"
|
|
692
692
|
value={v().start ?? ""}
|
|
693
693
|
onInput={(e) =>
|
|
@@ -695,10 +695,10 @@ function FieldInput(props: FieldInputProps) {
|
|
|
695
695
|
}
|
|
696
696
|
/>
|
|
697
697
|
</label>
|
|
698
|
-
<label class="
|
|
699
|
-
<span class="
|
|
698
|
+
<label class="bd-subfield">
|
|
699
|
+
<span class="bd-subfield__label">End</span>
|
|
700
700
|
<input
|
|
701
|
-
class="
|
|
701
|
+
class="bd-input"
|
|
702
702
|
type="date"
|
|
703
703
|
value={v().end ?? ""}
|
|
704
704
|
onInput={(e) =>
|
|
@@ -711,6 +711,95 @@ function FieldInput(props: FieldInputProps) {
|
|
|
711
711
|
})()}
|
|
712
712
|
</Match>
|
|
713
713
|
|
|
714
|
+
<Match when={t() === "name"}>
|
|
715
|
+
{(() => {
|
|
716
|
+
const v = () =>
|
|
717
|
+
(props.value() && typeof props.value() === "object"
|
|
718
|
+
? props.value()
|
|
719
|
+
: {}) as {
|
|
720
|
+
prefix?: string;
|
|
721
|
+
first?: string;
|
|
722
|
+
middle?: string;
|
|
723
|
+
last?: string;
|
|
724
|
+
suffix?: string;
|
|
725
|
+
nicknames?: string[] | string;
|
|
726
|
+
};
|
|
727
|
+
const cfg = () => field().nameConfig ?? {};
|
|
728
|
+
// Fixed per-subfield autofill tokens, suppressed to "off" when the
|
|
729
|
+
// field's resolved token is "off" (global switch or per-field override).
|
|
730
|
+
const acOff = () => ac() === "off";
|
|
731
|
+
const subAc = (token: string) => (acOff() ? "off" : token);
|
|
732
|
+
const part = (
|
|
733
|
+
k: "prefix" | "first" | "middle" | "last" | "suffix",
|
|
734
|
+
label: string,
|
|
735
|
+
token: string,
|
|
736
|
+
placeholder: string,
|
|
737
|
+
full = false,
|
|
738
|
+
) => (
|
|
739
|
+
<label class={cx("bd-subfield", { "bd-subfield--full": full })}>
|
|
740
|
+
<span class="bd-subfield__label">{label}</span>
|
|
741
|
+
<input
|
|
742
|
+
class="bd-input"
|
|
743
|
+
value={v()[k] ?? ""}
|
|
744
|
+
placeholder={placeholder}
|
|
745
|
+
onInput={(e) =>
|
|
746
|
+
props.set({ ...v(), [k]: e.currentTarget.value })
|
|
747
|
+
}
|
|
748
|
+
autocomplete={subAc(token)}
|
|
749
|
+
/>
|
|
750
|
+
</label>
|
|
751
|
+
);
|
|
752
|
+
// The nicknames input keeps the raw comma-separated string while the
|
|
753
|
+
// visitor types; submit normalizes it into a string[] (and the
|
|
754
|
+
// server re-normalizes authoritatively).
|
|
755
|
+
const nicknamesText = () => {
|
|
756
|
+
const nn = v().nicknames;
|
|
757
|
+
if (Array.isArray(nn)) return nn.join(", ");
|
|
758
|
+
return typeof nn === "string" ? nn : "";
|
|
759
|
+
};
|
|
760
|
+
return (
|
|
761
|
+
<div class="bd-name">
|
|
762
|
+
<Show when={cfg().prefix}>
|
|
763
|
+
{part("prefix", "Title", "honorific-prefix", "Dr.", true)}
|
|
764
|
+
</Show>
|
|
765
|
+
{part("first", "First name", "given-name", "Jane")}
|
|
766
|
+
<Show when={cfg().middle}>
|
|
767
|
+
{part("middle", "Middle name", "additional-name", "Quinn")}
|
|
768
|
+
</Show>
|
|
769
|
+
{part(
|
|
770
|
+
"last",
|
|
771
|
+
"Last name",
|
|
772
|
+
"family-name",
|
|
773
|
+
"Doe",
|
|
774
|
+
cfg().middle === true && cfg().suffix !== true,
|
|
775
|
+
)}
|
|
776
|
+
<Show when={cfg().suffix}>
|
|
777
|
+
{part(
|
|
778
|
+
"suffix",
|
|
779
|
+
"Suffix",
|
|
780
|
+
"honorific-suffix",
|
|
781
|
+
"Jr.",
|
|
782
|
+
cfg().middle !== true,
|
|
783
|
+
)}
|
|
784
|
+
</Show>
|
|
785
|
+
<Show when={cfg().nicknames}>
|
|
786
|
+
<label class="bd-subfield bd-subfield--full">
|
|
787
|
+
<span class="bd-subfield__label">Nicknames</span>
|
|
788
|
+
<input
|
|
789
|
+
class="bd-input"
|
|
790
|
+
value={nicknamesText()}
|
|
791
|
+
placeholder="Johnny, JM — separate with commas"
|
|
792
|
+
onInput={(e) =>
|
|
793
|
+
props.set({ ...v(), nicknames: e.currentTarget.value })
|
|
794
|
+
}
|
|
795
|
+
/>
|
|
796
|
+
</label>
|
|
797
|
+
</Show>
|
|
798
|
+
</div>
|
|
799
|
+
);
|
|
800
|
+
})()}
|
|
801
|
+
</Match>
|
|
802
|
+
|
|
714
803
|
<Match when={t() === "address"}>
|
|
715
804
|
{(() => {
|
|
716
805
|
const v = () =>
|
|
@@ -722,10 +811,10 @@ function FieldInput(props: FieldInputProps) {
|
|
|
722
811
|
const acOff = () => ac() === "off";
|
|
723
812
|
const subAc = (token: string) => (acOff() ? "off" : token);
|
|
724
813
|
const part = (k: string, label: string, token: string) => (
|
|
725
|
-
<label class="
|
|
726
|
-
<span class="
|
|
814
|
+
<label class="bd-subfield">
|
|
815
|
+
<span class="bd-subfield__label">{label}</span>
|
|
727
816
|
<input
|
|
728
|
-
class="
|
|
817
|
+
class="bd-input"
|
|
729
818
|
value={v()[k] ?? ""}
|
|
730
819
|
onInput={(e) =>
|
|
731
820
|
props.set({ ...v(), [k]: e.currentTarget.value })
|
|
@@ -735,7 +824,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
735
824
|
</label>
|
|
736
825
|
);
|
|
737
826
|
return (
|
|
738
|
-
<div class="
|
|
827
|
+
<div class="bd-address">
|
|
739
828
|
{part("line1", "Address Line 1", "street-address")}
|
|
740
829
|
{part("line2", "Address Line 2", "address-line2")}
|
|
741
830
|
{part("city", "City", "address-level2")}
|
|
@@ -813,11 +902,11 @@ function FieldInput(props: FieldInputProps) {
|
|
|
813
902
|
};
|
|
814
903
|
|
|
815
904
|
return (
|
|
816
|
-
<div class="
|
|
905
|
+
<div class="bd-file">
|
|
817
906
|
<input
|
|
818
907
|
ref={inputRef}
|
|
819
908
|
type="file"
|
|
820
|
-
class="
|
|
909
|
+
class="bd-file__input"
|
|
821
910
|
multiple={maxFiles() > 1}
|
|
822
911
|
accept={accept()}
|
|
823
912
|
style={{ display: "none" }}
|
|
@@ -825,7 +914,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
825
914
|
/>
|
|
826
915
|
<button
|
|
827
916
|
type="button"
|
|
828
|
-
class="
|
|
917
|
+
class="bd-file__trigger"
|
|
829
918
|
disabled={props.uploading() || remaining() === 0 || !props.uploadFile}
|
|
830
919
|
onClick={() => inputRef?.click()}
|
|
831
920
|
>
|
|
@@ -847,20 +936,20 @@ function FieldInput(props: FieldInputProps) {
|
|
|
847
936
|
</Show>
|
|
848
937
|
</button>
|
|
849
938
|
<Show when={localError()}>
|
|
850
|
-
<p class="
|
|
939
|
+
<p class="bd-file__error">{localError()}</p>
|
|
851
940
|
</Show>
|
|
852
941
|
<Show when={files().length > 0}>
|
|
853
|
-
<ul class="
|
|
942
|
+
<ul class="bd-file__list">
|
|
854
943
|
<For each={files()}>
|
|
855
944
|
{(f, i) => (
|
|
856
|
-
<li class="
|
|
857
|
-
<span class="
|
|
858
|
-
<span class="
|
|
945
|
+
<li class="bd-file__item">
|
|
946
|
+
<span class="bd-file__name">{f.name}</span>
|
|
947
|
+
<span class="bd-file__size">
|
|
859
948
|
{Math.round(f.size / 1024)} KB
|
|
860
949
|
</span>
|
|
861
950
|
<button
|
|
862
951
|
type="button"
|
|
863
|
-
class="
|
|
952
|
+
class="bd-file__remove"
|
|
864
953
|
aria-label="Remove file"
|
|
865
954
|
onClick={() =>
|
|
866
955
|
props.set(
|
|
@@ -885,7 +974,7 @@ function FieldInput(props: FieldInputProps) {
|
|
|
885
974
|
|
|
886
975
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
887
976
|
// FieldRow — a value-bearing field plus its label / required marker / error /
|
|
888
|
-
// help text. Mirrors FormPreview's `FieldRow` + its `data-
|
|
977
|
+
// help text. Mirrors FormPreview's `FieldRow` + its `data-bd-*` hooks.
|
|
889
978
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
890
979
|
|
|
891
980
|
interface RenderCtx {
|
|
@@ -923,19 +1012,19 @@ function FieldRow(props: { field: FormCoreField; ctx: RenderCtx }) {
|
|
|
923
1012
|
>
|
|
924
1013
|
<div
|
|
925
1014
|
data-field-id={field().id}
|
|
926
|
-
data-
|
|
927
|
-
data-
|
|
928
|
-
class={cx("
|
|
929
|
-
[`
|
|
930
|
-
"
|
|
931
|
-
"
|
|
1015
|
+
data-bd-field={fieldCssKey(field())}
|
|
1016
|
+
data-bd-type={field().type}
|
|
1017
|
+
class={cx("bd-field", {
|
|
1018
|
+
[`bd-field--${field().type}`]: true,
|
|
1019
|
+
"bd-field--required": field().required === true,
|
|
1020
|
+
"bd-field--error": Boolean(error()),
|
|
932
1021
|
})}
|
|
933
1022
|
>
|
|
934
1023
|
<Show when={showLabel() && (field().label || field().required)}>
|
|
935
|
-
<label class="
|
|
1024
|
+
<label class="bd-field__label">
|
|
936
1025
|
{field().label || ""}
|
|
937
1026
|
<Show when={field().required}>
|
|
938
|
-
<span class="
|
|
1027
|
+
<span class="bd-field__required"> *</span>
|
|
939
1028
|
</Show>
|
|
940
1029
|
</label>
|
|
941
1030
|
</Show>
|
|
@@ -950,10 +1039,10 @@ function FieldRow(props: { field: FormCoreField; ctx: RenderCtx }) {
|
|
|
950
1039
|
autocomplete={props.ctx.autocomplete}
|
|
951
1040
|
/>
|
|
952
1041
|
<Show when={error()}>
|
|
953
|
-
{(e) => <p class="
|
|
1042
|
+
{(e) => <p class="bd-field__error">{e().message}</p>}
|
|
954
1043
|
</Show>
|
|
955
1044
|
<Show when={field().helpText}>
|
|
956
|
-
<p class="
|
|
1045
|
+
<p class="bd-field__help">{field().helpText}</p>
|
|
957
1046
|
</Show>
|
|
958
1047
|
</div>
|
|
959
1048
|
</Show>
|
|
@@ -963,7 +1052,7 @@ function FieldRow(props: { field: FormCoreField; ctx: RenderCtx }) {
|
|
|
963
1052
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
964
1053
|
// RenderTree — the recursive layout walk: input_group (+ concurrent reveal),
|
|
965
1054
|
// condition_block, or_condition, flex_row, leaf fields. Mirrors FormPreview's
|
|
966
|
-
// `RenderTree` and uses the SAME `
|
|
1055
|
+
// `RenderTree` and uses the SAME `bd-*` hooks. `flat` drops the group border
|
|
967
1056
|
// in consecutive mode (each step IS already a group).
|
|
968
1057
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
969
1058
|
|
|
@@ -973,7 +1062,7 @@ function RenderTree(props: {
|
|
|
973
1062
|
flat?: boolean;
|
|
974
1063
|
}) {
|
|
975
1064
|
return (
|
|
976
|
-
<div class="
|
|
1065
|
+
<div class="bd-tree">
|
|
977
1066
|
<For each={props.fields}>
|
|
978
1067
|
{(node) => (
|
|
979
1068
|
<Switch fallback={<FieldRow field={node} ctx={props.ctx} />}>
|
|
@@ -990,13 +1079,13 @@ function RenderTree(props: {
|
|
|
990
1079
|
: children().length;
|
|
991
1080
|
return (
|
|
992
1081
|
<div
|
|
993
|
-
data-
|
|
994
|
-
class={cx("
|
|
1082
|
+
data-bd-group={fieldCssKey(node)}
|
|
1083
|
+
class={cx("bd-group", { "bd-group--bordered": !props.flat })}
|
|
995
1084
|
>
|
|
996
1085
|
<Show
|
|
997
1086
|
when={node.label && node.showGroupLabel === true}
|
|
998
1087
|
>
|
|
999
|
-
<div class="
|
|
1088
|
+
<div class="bd-group__label">{node.label}</div>
|
|
1000
1089
|
</Show>
|
|
1001
1090
|
<Show
|
|
1002
1091
|
when={concurrent()}
|
|
@@ -1006,7 +1095,7 @@ function RenderTree(props: {
|
|
|
1006
1095
|
>
|
|
1007
1096
|
<For each={children().slice(0, revealCount())}>
|
|
1008
1097
|
{(child) => (
|
|
1009
|
-
<div class="
|
|
1098
|
+
<div class="bd-group__reveal">
|
|
1010
1099
|
<RenderTree
|
|
1011
1100
|
fields={[child]}
|
|
1012
1101
|
ctx={props.ctx}
|
|
@@ -1044,17 +1133,17 @@ function RenderTree(props: {
|
|
|
1044
1133
|
};
|
|
1045
1134
|
return (
|
|
1046
1135
|
<div
|
|
1047
|
-
class={cx("
|
|
1136
|
+
class={cx("bd-or", { "bd-or--error": errored() })}
|
|
1048
1137
|
>
|
|
1049
1138
|
<Show when={node.label}>
|
|
1050
|
-
<div class="
|
|
1139
|
+
<div class="bd-or__label">
|
|
1051
1140
|
{node.label}
|
|
1052
|
-
<span class="
|
|
1141
|
+
<span class="bd-or__hint">Fill at least one side</span>
|
|
1053
1142
|
</div>
|
|
1054
1143
|
</Show>
|
|
1055
|
-
<div class="
|
|
1056
|
-
<div class="
|
|
1057
|
-
<div class="
|
|
1144
|
+
<div class="bd-or__grid">
|
|
1145
|
+
<div class="bd-or__side">
|
|
1146
|
+
<div class="bd-or__side-label">
|
|
1058
1147
|
{cfg().leftLabel || "Option A"}
|
|
1059
1148
|
</div>
|
|
1060
1149
|
<Show when={left()}>
|
|
@@ -1063,11 +1152,11 @@ function RenderTree(props: {
|
|
|
1063
1152
|
)}
|
|
1064
1153
|
</Show>
|
|
1065
1154
|
</div>
|
|
1066
|
-
<div class="
|
|
1067
|
-
<span class="
|
|
1155
|
+
<div class="bd-or__divider">
|
|
1156
|
+
<span class="bd-or__badge">OR</span>
|
|
1068
1157
|
</div>
|
|
1069
|
-
<div class="
|
|
1070
|
-
<div class="
|
|
1158
|
+
<div class="bd-or__side">
|
|
1159
|
+
<div class="bd-or__side-label">
|
|
1071
1160
|
{cfg().rightLabel || "Option B"}
|
|
1072
1161
|
</div>
|
|
1073
1162
|
<Show when={right()}>
|
|
@@ -1078,7 +1167,7 @@ function RenderTree(props: {
|
|
|
1078
1167
|
</div>
|
|
1079
1168
|
</div>
|
|
1080
1169
|
<Show when={errored()}>
|
|
1081
|
-
<p class="
|
|
1170
|
+
<p class="bd-or__error">
|
|
1082
1171
|
Fill in at least one side to continue.
|
|
1083
1172
|
</p>
|
|
1084
1173
|
</Show>
|
|
@@ -1088,10 +1177,10 @@ function RenderTree(props: {
|
|
|
1088
1177
|
</Match>
|
|
1089
1178
|
|
|
1090
1179
|
<Match when={node.type === "flex_row"}>
|
|
1091
|
-
<div class="
|
|
1180
|
+
<div class="bd-flex-row">
|
|
1092
1181
|
<For each={node.children ?? []}>
|
|
1093
1182
|
{(child) => (
|
|
1094
|
-
<div class="
|
|
1183
|
+
<div class="bd-flex-row__cell">
|
|
1095
1184
|
<FieldRow field={child} ctx={props.ctx} />
|
|
1096
1185
|
</div>
|
|
1097
1186
|
)}
|
|
@@ -1113,9 +1202,9 @@ function StepProgress(props: { snapshot: Accessor<FormSnapshot> }) {
|
|
|
1113
1202
|
const steps = () => props.snapshot().steps;
|
|
1114
1203
|
const current = () => props.snapshot().step;
|
|
1115
1204
|
return (
|
|
1116
|
-
<div class="
|
|
1117
|
-
<div class="
|
|
1118
|
-
<div class="
|
|
1205
|
+
<div class="bd-progress bd-progress--steps">
|
|
1206
|
+
<div class="bd-progress__title">Form Progress</div>
|
|
1207
|
+
<div class="bd-progress__track">
|
|
1119
1208
|
<For each={steps()}>
|
|
1120
1209
|
{(s, i) => {
|
|
1121
1210
|
const head = () => s[0];
|
|
@@ -1127,23 +1216,23 @@ function StepProgress(props: { snapshot: Accessor<FormSnapshot> }) {
|
|
|
1127
1216
|
<>
|
|
1128
1217
|
<Show when={i() > 0}>
|
|
1129
1218
|
<div
|
|
1130
|
-
class={cx("
|
|
1131
|
-
"
|
|
1219
|
+
class={cx("bd-progress__line", {
|
|
1220
|
+
"bd-progress__line--filled": i() <= current(),
|
|
1132
1221
|
})}
|
|
1133
1222
|
/>
|
|
1134
1223
|
</Show>
|
|
1135
|
-
<div class="
|
|
1224
|
+
<div class="bd-progress__node">
|
|
1136
1225
|
<span
|
|
1137
|
-
class={cx("
|
|
1138
|
-
"
|
|
1139
|
-
"
|
|
1226
|
+
class={cx("bd-progress__dot", {
|
|
1227
|
+
"bd-progress__dot--current": isCurrent(),
|
|
1228
|
+
"bd-progress__dot--done": done(),
|
|
1140
1229
|
})}
|
|
1141
1230
|
>
|
|
1142
1231
|
{done() ? "✓" : i() + 1}
|
|
1143
1232
|
</span>
|
|
1144
1233
|
<span
|
|
1145
|
-
class={cx("
|
|
1146
|
-
"
|
|
1234
|
+
class={cx("bd-progress__step-label", {
|
|
1235
|
+
"bd-progress__step-label--current": isCurrent(),
|
|
1147
1236
|
})}
|
|
1148
1237
|
>
|
|
1149
1238
|
{title()}
|
|
@@ -1160,13 +1249,13 @@ function StepProgress(props: { snapshot: Accessor<FormSnapshot> }) {
|
|
|
1160
1249
|
|
|
1161
1250
|
function BarProgress(props: { snapshot: Accessor<FormSnapshot> }) {
|
|
1162
1251
|
return (
|
|
1163
|
-
<div class="
|
|
1164
|
-
<span class="
|
|
1252
|
+
<div class="bd-progress bd-progress--bar">
|
|
1253
|
+
<span class="bd-progress__count">
|
|
1165
1254
|
{props.snapshot().step + 1} / {props.snapshot().stepCount}
|
|
1166
1255
|
</span>
|
|
1167
|
-
<div class="
|
|
1256
|
+
<div class="bd-progress__bar-track">
|
|
1168
1257
|
<div
|
|
1169
|
-
class="
|
|
1258
|
+
class="bd-progress__bar-fill"
|
|
1170
1259
|
style={{ width: `${props.snapshot().progressPercent}%` }}
|
|
1171
1260
|
/>
|
|
1172
1261
|
</div>
|
|
@@ -1175,17 +1264,17 @@ function BarProgress(props: { snapshot: Accessor<FormSnapshot> }) {
|
|
|
1175
1264
|
}
|
|
1176
1265
|
|
|
1177
1266
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
1178
|
-
// <
|
|
1267
|
+
// <BdForm> — the drop-in component.
|
|
1179
1268
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
1180
1269
|
|
|
1181
|
-
export interface
|
|
1270
|
+
export interface BdFormProps {
|
|
1182
1271
|
/** Form slug — required unless a pre-fetched `schema` is supplied. */
|
|
1183
1272
|
slug?: string;
|
|
1184
1273
|
/** Pre-fetched schema (SSR / RSC). Adopted synchronously by the controller. */
|
|
1185
1274
|
schema?: FormSchema;
|
|
1186
|
-
/** SDK client. Optional when a `<
|
|
1275
|
+
/** SDK client. Optional when a `<BdProvider>` supplies one, or when only
|
|
1187
1276
|
* rendering a pre-fetched `schema` without submitting. */
|
|
1188
|
-
client?:
|
|
1277
|
+
client?: BdClient;
|
|
1189
1278
|
/** Submit-button text on the final step. */
|
|
1190
1279
|
submitLabel?: string;
|
|
1191
1280
|
/** Validate on the server but store nothing (no side effects). */
|
|
@@ -1217,16 +1306,16 @@ export interface BiabFormProps {
|
|
|
1217
1306
|
}
|
|
1218
1307
|
|
|
1219
1308
|
/**
|
|
1220
|
-
* `<
|
|
1221
|
-
* a published
|
|
1309
|
+
* `<BdForm slug="contact" client={client} />` — a complete, themeable form for
|
|
1310
|
+
* a published BD form. Loads the schema, renders the field tree, validates
|
|
1222
1311
|
* locally (mirroring the server), handles multi-step nav + progress + concurrent
|
|
1223
1312
|
* reveal + file uploads, and submits through the SDK.
|
|
1224
1313
|
*
|
|
1225
|
-
* All visual classes are `
|
|
1314
|
+
* All visual classes are `bd-*` on light DOM, so consumer CSS cascades. The
|
|
1226
1315
|
* component ships no styles of its own.
|
|
1227
1316
|
*/
|
|
1228
|
-
export function
|
|
1229
|
-
const providerClient =
|
|
1317
|
+
export function BdForm(props: BdFormProps) {
|
|
1318
|
+
const providerClient = useBdClient();
|
|
1230
1319
|
const resolvedClient = () => props.client ?? providerClient;
|
|
1231
1320
|
const formId = createUniqueId();
|
|
1232
1321
|
|
|
@@ -1282,7 +1371,7 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1282
1371
|
};
|
|
1283
1372
|
|
|
1284
1373
|
const rootClass = () =>
|
|
1285
|
-
["
|
|
1374
|
+
["bd-form", props.class, props.className].filter(Boolean).join(" ");
|
|
1286
1375
|
|
|
1287
1376
|
// Entrance-animation class for the active step (slide is directional).
|
|
1288
1377
|
const animClass = () => {
|
|
@@ -1290,15 +1379,15 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1290
1379
|
const forward = snap().forward;
|
|
1291
1380
|
switch (a) {
|
|
1292
1381
|
case "fade":
|
|
1293
|
-
return "
|
|
1382
|
+
return "bd-anim bd-anim--fade";
|
|
1294
1383
|
case "scale":
|
|
1295
|
-
return "
|
|
1384
|
+
return "bd-anim bd-anim--scale";
|
|
1296
1385
|
case "slide":
|
|
1297
1386
|
return forward
|
|
1298
|
-
? "
|
|
1299
|
-
: "
|
|
1387
|
+
? "bd-anim bd-anim--slide-forward"
|
|
1388
|
+
: "bd-anim bd-anim--slide-back";
|
|
1300
1389
|
case "scroll":
|
|
1301
|
-
return "
|
|
1390
|
+
return "bd-anim bd-anim--scroll";
|
|
1302
1391
|
default:
|
|
1303
1392
|
return "";
|
|
1304
1393
|
}
|
|
@@ -1308,12 +1397,12 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1308
1397
|
<Switch>
|
|
1309
1398
|
{/* Loading / error / empty guards mirror the controller's status. */}
|
|
1310
1399
|
<Match when={snap().status === "loading"}>
|
|
1311
|
-
<div class="
|
|
1400
|
+
<div class="bd-form bd-form--loading" aria-busy="true">
|
|
1312
1401
|
Loading…
|
|
1313
1402
|
</div>
|
|
1314
1403
|
</Match>
|
|
1315
1404
|
<Match when={snap().status === "error"}>
|
|
1316
|
-
<div class="
|
|
1405
|
+
<div class="bd-form bd-form--error" role="alert">
|
|
1317
1406
|
{snap().loadError ?? "Failed to load the form."}
|
|
1318
1407
|
</div>
|
|
1319
1408
|
</Match>
|
|
@@ -1328,18 +1417,18 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1328
1417
|
{/* Org icon (showOrgIcon) — top-right corner mark. */}
|
|
1329
1418
|
<Show when={snap().orgIcon}>
|
|
1330
1419
|
{(icon) => (
|
|
1331
|
-
<img class="
|
|
1420
|
+
<img class="bd-form__org-icon" src={icon()} alt="" />
|
|
1332
1421
|
)}
|
|
1333
1422
|
</Show>
|
|
1334
1423
|
|
|
1335
1424
|
{/* Title / description from the schema. */}
|
|
1336
1425
|
<Show when={snap().title || snap().description}>
|
|
1337
|
-
<div class="
|
|
1426
|
+
<div class="bd-form__header">
|
|
1338
1427
|
<Show when={snap().title}>
|
|
1339
|
-
<h2 class="
|
|
1428
|
+
<h2 class="bd-form__title">{snap().title}</h2>
|
|
1340
1429
|
</Show>
|
|
1341
1430
|
<Show when={snap().description}>
|
|
1342
|
-
<p class="
|
|
1431
|
+
<p class="bd-form__description">{snap().description}</p>
|
|
1343
1432
|
</Show>
|
|
1344
1433
|
</div>
|
|
1345
1434
|
</Show>
|
|
@@ -1356,12 +1445,12 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1356
1445
|
|
|
1357
1446
|
{/* Form-level error summary. */}
|
|
1358
1447
|
<Show when={snap().errorList.length > 0}>
|
|
1359
|
-
<div class="
|
|
1360
|
-
<div class="
|
|
1448
|
+
<div class="bd-form__errors" role="alert">
|
|
1449
|
+
<div class="bd-form__errors-title">
|
|
1361
1450
|
Please complete the highlighted required field
|
|
1362
1451
|
{snap().errorList.length === 1 ? "" : "s"}.
|
|
1363
1452
|
</div>
|
|
1364
|
-
<div class="
|
|
1453
|
+
<div class="bd-form__errors-list">
|
|
1365
1454
|
{snap()
|
|
1366
1455
|
.errorList.map((er) => er.label)
|
|
1367
1456
|
.join(", ")}
|
|
@@ -1383,10 +1472,10 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1383
1472
|
</div>
|
|
1384
1473
|
}
|
|
1385
1474
|
>
|
|
1386
|
-
<div class="
|
|
1475
|
+
<div class="bd-form__scroll">
|
|
1387
1476
|
<For each={snap().visibleFields}>
|
|
1388
1477
|
{(vf) => (
|
|
1389
|
-
<div class="
|
|
1478
|
+
<div class="bd-anim bd-anim--scroll">
|
|
1390
1479
|
<RenderTree
|
|
1391
1480
|
fields={[vf]}
|
|
1392
1481
|
ctx={ctx}
|
|
@@ -1402,10 +1491,10 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1402
1491
|
<Show
|
|
1403
1492
|
when={multiStep()}
|
|
1404
1493
|
fallback={
|
|
1405
|
-
<div class="
|
|
1494
|
+
<div class="bd-nav">
|
|
1406
1495
|
<button
|
|
1407
1496
|
type="submit"
|
|
1408
|
-
class="
|
|
1497
|
+
class="bd-btn bd-btn--submit"
|
|
1409
1498
|
disabled={snap().submitting}
|
|
1410
1499
|
>
|
|
1411
1500
|
{snap().submitting
|
|
@@ -1415,10 +1504,10 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1415
1504
|
</div>
|
|
1416
1505
|
}
|
|
1417
1506
|
>
|
|
1418
|
-
<div class="
|
|
1507
|
+
<div class="bd-nav bd-nav--steps">
|
|
1419
1508
|
<button
|
|
1420
1509
|
type="button"
|
|
1421
|
-
class="
|
|
1510
|
+
class="bd-btn bd-btn--back"
|
|
1422
1511
|
disabled={snap().isFirstStep}
|
|
1423
1512
|
onClick={() => store.controller.back()}
|
|
1424
1513
|
>
|
|
@@ -1429,7 +1518,7 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1429
1518
|
fallback={
|
|
1430
1519
|
<button
|
|
1431
1520
|
type="button"
|
|
1432
|
-
class="
|
|
1521
|
+
class="bd-btn bd-btn--next"
|
|
1433
1522
|
disabled={!snap().canAdvance}
|
|
1434
1523
|
onClick={() => store.controller.next()}
|
|
1435
1524
|
>
|
|
@@ -1439,7 +1528,7 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1439
1528
|
>
|
|
1440
1529
|
<button
|
|
1441
1530
|
type="submit"
|
|
1442
|
-
class="
|
|
1531
|
+
class="bd-btn bd-btn--submit"
|
|
1443
1532
|
disabled={snap().submitting}
|
|
1444
1533
|
>
|
|
1445
1534
|
{snap().submitting
|
|
@@ -1452,7 +1541,7 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1452
1541
|
|
|
1453
1542
|
{/* Success state. */}
|
|
1454
1543
|
<Show when={snap().submitted}>
|
|
1455
|
-
<div class="
|
|
1544
|
+
<div class="bd-form__success" role="status">
|
|
1456
1545
|
Thanks — your response was received.
|
|
1457
1546
|
</div>
|
|
1458
1547
|
</Show>
|
|
@@ -1465,7 +1554,7 @@ export function BiabForm(props: BiabFormProps) {
|
|
|
1465
1554
|
// Re-export the core types a consumer commonly annotates against, so they can
|
|
1466
1555
|
// import everything they need from `@businessdash/sdk/solid` alone.
|
|
1467
1556
|
export type {
|
|
1468
|
-
|
|
1557
|
+
BdClient,
|
|
1469
1558
|
FormSchema,
|
|
1470
1559
|
FormSubmitResult,
|
|
1471
1560
|
FormFileValue,
|