@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/vanilla.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `@businessdash/sdk/vanilla` — framework-free imperative DOM binding for `<
|
|
2
|
+
* `@businessdash/sdk/vanilla` — framework-free imperative DOM binding for `<BdForm>`.
|
|
3
3
|
*
|
|
4
|
-
* `
|
|
4
|
+
* `mountBdForm(elOrSelector, opts)` mounts a fully-rendered, schema-driven form
|
|
5
5
|
* into any DOM node. It owns nothing of the form's logic — all of that lives in
|
|
6
6
|
* the headless `createFormController` core (`@businessdash/sdk/forms`). This binding
|
|
7
7
|
* is the "render layer": it subscribes to the controller's `snapshot()` and, on
|
|
8
8
|
* every notify, rebuilds the form's DOM by walking `snapshot.visibleFields` and
|
|
9
9
|
* dispatching per field `type`. It is a faithful port of the dashboard renderer
|
|
10
|
-
* (`FormPreview.tsx`) so a drop-in `<
|
|
10
|
+
* (`FormPreview.tsx`) so a drop-in `<bd-form>` reproduces the builder preview.
|
|
11
11
|
*
|
|
12
12
|
* Rendering rules (kept identical to the dashboard):
|
|
13
13
|
* - Light DOM, no shadow root, so the consumer's CSS cascades straight in.
|
|
14
|
-
* - Stable `
|
|
14
|
+
* - Stable `bd-*` class hooks + `data-bd-*` attributes on every node.
|
|
15
15
|
* - Applies `schema.settings`: animation (none/fade/slide/scale/scroll),
|
|
16
16
|
* multi-step ("consecutive") nav, progress bar/steps, concurrent-reveal
|
|
17
17
|
* gating inside groups, plus the org icon when `showOrgIcon` is set.
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* walked exactly as the core's validation helpers expect.
|
|
20
20
|
*
|
|
21
21
|
* Compiled to dist (plain TS, no JSX). The web-component binding
|
|
22
|
-
* (`@businessdash/sdk/element`) wraps this same `
|
|
22
|
+
* (`@businessdash/sdk/element`) wraps this same `mountBdForm`.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import {
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
type FormSubmitOptions,
|
|
39
39
|
} from "./forms-core/index.js";
|
|
40
40
|
import type {
|
|
41
|
-
|
|
41
|
+
BdClient,
|
|
42
42
|
FormFileValue,
|
|
43
43
|
FormSchema,
|
|
44
44
|
FormSubmitResult,
|
|
@@ -51,10 +51,10 @@ export * from "./forms-core/index.js";
|
|
|
51
51
|
// Public mount options — the consistent component API across every binding.
|
|
52
52
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
53
53
|
|
|
54
|
-
export interface
|
|
54
|
+
export interface MountBdFormOptions {
|
|
55
55
|
/** The SDK client. Required unless `schema` is supplied (SSR / pre-fetched).
|
|
56
56
|
* Still used for `submit` / `uploadFile` when both are given. */
|
|
57
|
-
client?:
|
|
57
|
+
client?: BdClient;
|
|
58
58
|
/** Form slug. Required when loading via `client`. */
|
|
59
59
|
slug?: string;
|
|
60
60
|
/** Pre-fetched schema (SSR). `load()` adopts it synchronously. */
|
|
@@ -63,7 +63,7 @@ export interface MountBiabFormOptions {
|
|
|
63
63
|
submitLabel?: string;
|
|
64
64
|
/** Validate on the server but store nothing (no side effects). */
|
|
65
65
|
dryRun?: boolean;
|
|
66
|
-
/** Extra class(es) added to the root `.
|
|
66
|
+
/** Extra class(es) added to the root `.bd-form` element. */
|
|
67
67
|
class?: string;
|
|
68
68
|
/** Alias for `class` — accepted for cross-framework parity. */
|
|
69
69
|
className?: string;
|
|
@@ -84,8 +84,8 @@ export interface MountBiabFormOptions {
|
|
|
84
84
|
onError?: (result: Extract<FormSubmitResult, { ok: false }>) => void;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
/** Handle returned by `
|
|
88
|
-
export interface
|
|
87
|
+
/** Handle returned by `mountBdForm` — drive or tear down the mounted form. */
|
|
88
|
+
export interface BdFormInstance {
|
|
89
89
|
/** The underlying headless controller (advanced use). */
|
|
90
90
|
controller: FormController;
|
|
91
91
|
/** Re-fetch (or re-adopt) the schema and re-render. */
|
|
@@ -154,17 +154,17 @@ function fieldCssKey(field: FormCoreField): string {
|
|
|
154
154
|
const NO_LABEL_TYPES = new Set(["title", "subtitle", "separator", "richtext"]);
|
|
155
155
|
|
|
156
156
|
/** tw-style entrance class hook for the active step (consumer CSS animates these).
|
|
157
|
-
* Matches the `
|
|
157
|
+
* Matches the `bd-anim--*` convention so orgs can target each animation. */
|
|
158
158
|
function animClass(animation: string, forward: boolean): string {
|
|
159
159
|
switch (animation) {
|
|
160
160
|
case "fade":
|
|
161
|
-
return "
|
|
161
|
+
return "bd-anim bd-anim--fade";
|
|
162
162
|
case "scale":
|
|
163
|
-
return "
|
|
163
|
+
return "bd-anim bd-anim--scale";
|
|
164
164
|
case "slide":
|
|
165
165
|
return forward
|
|
166
|
-
? "
|
|
167
|
-
: "
|
|
166
|
+
? "bd-anim bd-anim--slide bd-anim--slide-forward"
|
|
167
|
+
: "bd-anim bd-anim--slide bd-anim--slide-back";
|
|
168
168
|
default:
|
|
169
169
|
return "";
|
|
170
170
|
}
|
|
@@ -190,22 +190,22 @@ function renderFieldInput(
|
|
|
190
190
|
): HTMLElement | null {
|
|
191
191
|
const value = snapshot.values[field.id];
|
|
192
192
|
const str = typeof value === "string" ? value : "";
|
|
193
|
-
// Address
|
|
194
|
-
// field's resolved token is "off" (global switch or per-field override).
|
|
193
|
+
// Address/name composites suppress their fixed sub-field tokens to "off" when
|
|
194
|
+
// the field's resolved token is "off" (global switch or per-field override).
|
|
195
195
|
const acOff = autoComplete === "off";
|
|
196
196
|
|
|
197
197
|
switch (field.type) {
|
|
198
198
|
case "title":
|
|
199
|
-
return el("h2", { class: "
|
|
199
|
+
return el("h2", { class: "bd-field__title" }, [
|
|
200
200
|
field.label || "Untitled",
|
|
201
201
|
]);
|
|
202
202
|
case "subtitle":
|
|
203
|
-
return el("h3", { class: "
|
|
203
|
+
return el("h3", { class: "bd-field__subtitle" }, [field.label || ""]);
|
|
204
204
|
case "separator":
|
|
205
|
-
return el("hr", { class: "
|
|
205
|
+
return el("hr", { class: "bd-field__separator" });
|
|
206
206
|
case "richtext": {
|
|
207
207
|
if (!field.content) return null;
|
|
208
|
-
const div = el("div", { class: "
|
|
208
|
+
const div = el("div", { class: "bd-field__richtext bd-prose" });
|
|
209
209
|
// The published `content` is server-sanitized HTML.
|
|
210
210
|
div.innerHTML = field.content;
|
|
211
211
|
return div;
|
|
@@ -219,7 +219,7 @@ function renderFieldInput(
|
|
|
219
219
|
};
|
|
220
220
|
if (!cfg.src) return null;
|
|
221
221
|
return el("img", {
|
|
222
|
-
class: "
|
|
222
|
+
class: "bd-field__image",
|
|
223
223
|
src: cfg.src,
|
|
224
224
|
alt: cfg.alt || "",
|
|
225
225
|
...(cfg.width ? { width: cfg.width } : {}),
|
|
@@ -233,8 +233,8 @@ function renderFieldInput(
|
|
|
233
233
|
};
|
|
234
234
|
const node = el("textarea", {
|
|
235
235
|
class: classNames(
|
|
236
|
-
"
|
|
237
|
-
cfg.resizable === false && "
|
|
236
|
+
"bd-textarea",
|
|
237
|
+
cfg.resizable === false && "bd-textarea--fixed",
|
|
238
238
|
),
|
|
239
239
|
rows: cfg.rows ?? 4,
|
|
240
240
|
placeholder: field.placeholder || "",
|
|
@@ -245,7 +245,7 @@ function renderFieldInput(
|
|
|
245
245
|
return node;
|
|
246
246
|
}
|
|
247
247
|
case "select": {
|
|
248
|
-
const node = el("select", { class: "
|
|
248
|
+
const node = el("select", { class: "bd-select" }) as HTMLSelectElement;
|
|
249
249
|
node.append(
|
|
250
250
|
el("option", { value: "" }, [field.placeholder || "Select..."]),
|
|
251
251
|
);
|
|
@@ -257,11 +257,11 @@ function renderFieldInput(
|
|
|
257
257
|
return node;
|
|
258
258
|
}
|
|
259
259
|
case "radio": {
|
|
260
|
-
const wrap = el("div", { class: "
|
|
260
|
+
const wrap = el("div", { class: "bd-radio-group" });
|
|
261
261
|
for (const opt of field.options ?? []) {
|
|
262
262
|
const id = `${field.id}-${opt}`;
|
|
263
263
|
const input = el("input", {
|
|
264
|
-
class: "
|
|
264
|
+
class: "bd-radio",
|
|
265
265
|
type: "radio",
|
|
266
266
|
name: field.id,
|
|
267
267
|
id,
|
|
@@ -270,7 +270,7 @@ function renderFieldInput(
|
|
|
270
270
|
input.checked = str === opt;
|
|
271
271
|
input.addEventListener("change", () => set(opt));
|
|
272
272
|
wrap.append(
|
|
273
|
-
el("label", { class: "
|
|
273
|
+
el("label", { class: "bd-radio-option", for: id }, [
|
|
274
274
|
input,
|
|
275
275
|
el("span", {}, [opt]),
|
|
276
276
|
]),
|
|
@@ -280,10 +280,10 @@ function renderFieldInput(
|
|
|
280
280
|
}
|
|
281
281
|
case "checkbox": {
|
|
282
282
|
const arr = Array.isArray(value) ? (value as string[]) : [];
|
|
283
|
-
const wrap = el("div", { class: "
|
|
283
|
+
const wrap = el("div", { class: "bd-checkbox-group" });
|
|
284
284
|
for (const opt of field.options ?? []) {
|
|
285
285
|
const input = el("input", {
|
|
286
|
-
class: "
|
|
286
|
+
class: "bd-checkbox",
|
|
287
287
|
type: "checkbox",
|
|
288
288
|
value: opt,
|
|
289
289
|
}) as HTMLInputElement;
|
|
@@ -295,7 +295,7 @@ function renderFieldInput(
|
|
|
295
295
|
set(next);
|
|
296
296
|
});
|
|
297
297
|
wrap.append(
|
|
298
|
-
el("label", { class: "
|
|
298
|
+
el("label", { class: "bd-checkbox-option" }, [
|
|
299
299
|
input,
|
|
300
300
|
el("span", {}, [opt]),
|
|
301
301
|
]),
|
|
@@ -305,21 +305,21 @@ function renderFieldInput(
|
|
|
305
305
|
}
|
|
306
306
|
case "boolean": {
|
|
307
307
|
const input = el("input", {
|
|
308
|
-
class: "
|
|
308
|
+
class: "bd-switch",
|
|
309
309
|
type: "checkbox",
|
|
310
310
|
}) as HTMLInputElement;
|
|
311
311
|
input.checked = value === true;
|
|
312
312
|
input.addEventListener("change", () => set(input.checked));
|
|
313
|
-
return el("label", { class: "
|
|
313
|
+
return el("label", { class: "bd-boolean" }, [
|
|
314
314
|
input,
|
|
315
|
-
el("span", { class: "
|
|
315
|
+
el("span", { class: "bd-boolean__label" }, [
|
|
316
316
|
field.placeholder || "Yes / No",
|
|
317
317
|
]),
|
|
318
318
|
]);
|
|
319
319
|
}
|
|
320
320
|
case "date": {
|
|
321
321
|
const node = el("input", {
|
|
322
|
-
class: "
|
|
322
|
+
class: "bd-input",
|
|
323
323
|
type: "date",
|
|
324
324
|
}) as HTMLInputElement;
|
|
325
325
|
node.value = str;
|
|
@@ -328,7 +328,7 @@ function renderFieldInput(
|
|
|
328
328
|
}
|
|
329
329
|
case "email": {
|
|
330
330
|
const node = el("input", {
|
|
331
|
-
class: "
|
|
331
|
+
class: "bd-input",
|
|
332
332
|
type: "email",
|
|
333
333
|
placeholder: field.placeholder || "you@example.com",
|
|
334
334
|
}) as HTMLInputElement;
|
|
@@ -338,16 +338,16 @@ function renderFieldInput(
|
|
|
338
338
|
return node;
|
|
339
339
|
}
|
|
340
340
|
case "phone": {
|
|
341
|
-
const wrap = el("div", { class: "
|
|
341
|
+
const wrap = el("div", { class: "bd-phone" });
|
|
342
342
|
if (field.phoneConfig?.showFlags) {
|
|
343
343
|
wrap.append(
|
|
344
|
-
el("span", { class: "
|
|
344
|
+
el("span", { class: "bd-phone__flag", "aria-hidden": "true" }, [
|
|
345
345
|
"\u{1F1FA}\u{1F1F8}",
|
|
346
346
|
]),
|
|
347
347
|
);
|
|
348
348
|
}
|
|
349
349
|
const node = el("input", {
|
|
350
|
-
class: "
|
|
350
|
+
class: "bd-input",
|
|
351
351
|
type: "tel",
|
|
352
352
|
placeholder:
|
|
353
353
|
field.placeholder ||
|
|
@@ -363,7 +363,7 @@ function renderFieldInput(
|
|
|
363
363
|
}
|
|
364
364
|
case "number": {
|
|
365
365
|
const node = el("input", {
|
|
366
|
-
class: "
|
|
366
|
+
class: "bd-input",
|
|
367
367
|
type: "number",
|
|
368
368
|
placeholder: field.placeholder || "",
|
|
369
369
|
}) as HTMLInputElement;
|
|
@@ -375,20 +375,20 @@ function renderFieldInput(
|
|
|
375
375
|
}
|
|
376
376
|
case "stepper": {
|
|
377
377
|
const v = typeof value === "number" ? value : 0;
|
|
378
|
-
const out = el("span", { class: "
|
|
378
|
+
const out = el("span", { class: "bd-stepper__value" }, [String(v)]);
|
|
379
379
|
const minus = el(
|
|
380
380
|
"button",
|
|
381
|
-
{ class: "
|
|
381
|
+
{ class: "bd-btn bd-btn--ghost bd-stepper__btn", type: "button" },
|
|
382
382
|
["−"],
|
|
383
383
|
);
|
|
384
384
|
const plus = el(
|
|
385
385
|
"button",
|
|
386
|
-
{ class: "
|
|
386
|
+
{ class: "bd-btn bd-btn--ghost bd-stepper__btn", type: "button" },
|
|
387
387
|
["+"],
|
|
388
388
|
);
|
|
389
389
|
minus.addEventListener("click", () => set(v - 1));
|
|
390
390
|
plus.addEventListener("click", () => set(v + 1));
|
|
391
|
-
return el("div", { class: "
|
|
391
|
+
return el("div", { class: "bd-stepper" }, [minus, out, plus]);
|
|
392
392
|
}
|
|
393
393
|
case "slider": {
|
|
394
394
|
const min = field.sliderConfig?.min ?? 0;
|
|
@@ -398,9 +398,9 @@ function renderFieldInput(
|
|
|
398
398
|
const fmt = (n: number) =>
|
|
399
399
|
unit === "currency" ? `$${n}` : unit === "percent" ? `${n}%` : `${n}`;
|
|
400
400
|
const v = typeof value === "number" ? value : min;
|
|
401
|
-
const readout = el("span", { class: "
|
|
401
|
+
const readout = el("span", { class: "bd-slider__value" }, [fmt(v)]);
|
|
402
402
|
const input = el("input", {
|
|
403
|
-
class: "
|
|
403
|
+
class: "bd-slider",
|
|
404
404
|
type: "range",
|
|
405
405
|
min,
|
|
406
406
|
max,
|
|
@@ -412,8 +412,8 @@ function renderFieldInput(
|
|
|
412
412
|
readout.textContent = fmt(n);
|
|
413
413
|
set(n);
|
|
414
414
|
});
|
|
415
|
-
return el("div", { class: "
|
|
416
|
-
el("div", { class: "
|
|
415
|
+
return el("div", { class: "bd-slider-wrap" }, [
|
|
416
|
+
el("div", { class: "bd-slider__scale" }, [
|
|
417
417
|
el("span", {}, [fmt(min)]),
|
|
418
418
|
readout,
|
|
419
419
|
el("span", {}, [fmt(max)]),
|
|
@@ -424,12 +424,12 @@ function renderFieldInput(
|
|
|
424
424
|
case "star_rating": {
|
|
425
425
|
const max = field.starRatingConfig?.maxStars ?? 5;
|
|
426
426
|
const v = typeof value === "number" ? value : 0;
|
|
427
|
-
const wrap = el("div", { class: "
|
|
427
|
+
const wrap = el("div", { class: "bd-stars" });
|
|
428
428
|
for (let i = 0; i < max; i++) {
|
|
429
429
|
const btn = el(
|
|
430
430
|
"button",
|
|
431
431
|
{
|
|
432
|
-
class: classNames("
|
|
432
|
+
class: classNames("bd-star", i < v && "bd-star--filled"),
|
|
433
433
|
type: "button",
|
|
434
434
|
"aria-label": `${i + 1} star${i === 0 ? "" : "s"}`,
|
|
435
435
|
},
|
|
@@ -442,15 +442,15 @@ function renderFieldInput(
|
|
|
442
442
|
}
|
|
443
443
|
case "happiness_rating": {
|
|
444
444
|
const v = typeof value === "number" ? value : -1;
|
|
445
|
-
const wrap = el("div", { class: "
|
|
445
|
+
const wrap = el("div", { class: "bd-happiness" });
|
|
446
446
|
["\u{1F61E}", "\u{1F615}", "\u{1F610}", "\u{1F642}", "\u{1F604}"].forEach(
|
|
447
447
|
(emoji, i) => {
|
|
448
448
|
const btn = el(
|
|
449
449
|
"button",
|
|
450
450
|
{
|
|
451
451
|
class: classNames(
|
|
452
|
-
"
|
|
453
|
-
i === v && "
|
|
452
|
+
"bd-happiness__face",
|
|
453
|
+
i === v && "bd-happiness__face--active",
|
|
454
454
|
),
|
|
455
455
|
type: "button",
|
|
456
456
|
},
|
|
@@ -464,13 +464,10 @@ function renderFieldInput(
|
|
|
464
464
|
}
|
|
465
465
|
case "color_picker": {
|
|
466
466
|
const v = str;
|
|
467
|
-
const wrap = el("div", { class: "
|
|
467
|
+
const wrap = el("div", { class: "bd-colors" });
|
|
468
468
|
for (const color of field.options ?? []) {
|
|
469
469
|
const btn = el("button", {
|
|
470
|
-
class: classNames(
|
|
471
|
-
"biab-color",
|
|
472
|
-
v === color && "biab-color--selected",
|
|
473
|
-
),
|
|
470
|
+
class: classNames("bd-color", v === color && "bd-color--selected"),
|
|
474
471
|
type: "button",
|
|
475
472
|
title: color,
|
|
476
473
|
style: `background-color:${color}`,
|
|
@@ -500,7 +497,7 @@ function renderFieldInput(
|
|
|
500
497
|
const format = field.timeConfig?.format ?? "12h";
|
|
501
498
|
const step = Math.max(field.timeConfig?.stepMinutes ?? 30, 1);
|
|
502
499
|
const node = el("select", {
|
|
503
|
-
class: "
|
|
500
|
+
class: "bd-select",
|
|
504
501
|
}) as HTMLSelectElement;
|
|
505
502
|
node.append(
|
|
506
503
|
el("option", { value: "" }, [field.placeholder || "Select time"]),
|
|
@@ -548,12 +545,100 @@ function renderFieldInput(
|
|
|
548
545
|
(date, time) => set({ ...v, date, time }),
|
|
549
546
|
);
|
|
550
547
|
}
|
|
548
|
+
case "name": {
|
|
549
|
+
const v = (value && typeof value === "object" ? value : {}) as {
|
|
550
|
+
prefix?: string;
|
|
551
|
+
first?: string;
|
|
552
|
+
middle?: string;
|
|
553
|
+
last?: string;
|
|
554
|
+
suffix?: string;
|
|
555
|
+
nicknames?: string[] | string;
|
|
556
|
+
};
|
|
557
|
+
const cfg = field.nameConfig ?? {};
|
|
558
|
+
const grid = el("div", { class: "bd-name" });
|
|
559
|
+
// Fixed per-sub-field autofill tokens, suppressed to "off" when the
|
|
560
|
+
// composite's resolved token is "off". Mirrors the React renderer.
|
|
561
|
+
const part = (
|
|
562
|
+
key: "prefix" | "first" | "middle" | "last" | "suffix",
|
|
563
|
+
label: string,
|
|
564
|
+
token: string,
|
|
565
|
+
placeholder: string,
|
|
566
|
+
full = false,
|
|
567
|
+
) => {
|
|
568
|
+
const input = el("input", {
|
|
569
|
+
class: "bd-input",
|
|
570
|
+
placeholder,
|
|
571
|
+
}) as HTMLInputElement;
|
|
572
|
+
setAutocomplete(input, acOff ? "off" : token);
|
|
573
|
+
input.value = v[key] ?? "";
|
|
574
|
+
input.addEventListener("input", () =>
|
|
575
|
+
set({ ...v, [key]: input.value }),
|
|
576
|
+
);
|
|
577
|
+
return el(
|
|
578
|
+
"label",
|
|
579
|
+
{
|
|
580
|
+
class: classNames("bd-name__field", full && "bd-name__field--full"),
|
|
581
|
+
},
|
|
582
|
+
[el("span", { class: "bd-name__label" }, [label]), input],
|
|
583
|
+
);
|
|
584
|
+
};
|
|
585
|
+
if (cfg.prefix) {
|
|
586
|
+
grid.append(part("prefix", "Title", "honorific-prefix", "Dr.", true));
|
|
587
|
+
}
|
|
588
|
+
grid.append(part("first", "First name", "given-name", "Jane"));
|
|
589
|
+
if (cfg.middle) {
|
|
590
|
+
grid.append(part("middle", "Middle name", "additional-name", "Quinn"));
|
|
591
|
+
}
|
|
592
|
+
grid.append(
|
|
593
|
+
part(
|
|
594
|
+
"last",
|
|
595
|
+
"Last name",
|
|
596
|
+
"family-name",
|
|
597
|
+
"Doe",
|
|
598
|
+
cfg.middle === true && cfg.suffix !== true,
|
|
599
|
+
),
|
|
600
|
+
);
|
|
601
|
+
if (cfg.suffix) {
|
|
602
|
+
grid.append(
|
|
603
|
+
part(
|
|
604
|
+
"suffix",
|
|
605
|
+
"Suffix",
|
|
606
|
+
"honorific-suffix",
|
|
607
|
+
"Jr.",
|
|
608
|
+
cfg.middle !== true,
|
|
609
|
+
),
|
|
610
|
+
);
|
|
611
|
+
}
|
|
612
|
+
if (cfg.nicknames) {
|
|
613
|
+
// The nicknames input keeps the raw comma-separated string while the
|
|
614
|
+
// visitor types; submit normalizes it into a string[].
|
|
615
|
+
const input = el("input", {
|
|
616
|
+
class: "bd-input",
|
|
617
|
+
placeholder: "Johnny, JM — separate with commas",
|
|
618
|
+
}) as HTMLInputElement;
|
|
619
|
+
input.value = Array.isArray(v.nicknames)
|
|
620
|
+
? v.nicknames.join(", ")
|
|
621
|
+
: typeof v.nicknames === "string"
|
|
622
|
+
? v.nicknames
|
|
623
|
+
: "";
|
|
624
|
+
input.addEventListener("input", () =>
|
|
625
|
+
set({ ...v, nicknames: input.value }),
|
|
626
|
+
);
|
|
627
|
+
grid.append(
|
|
628
|
+
el("label", { class: "bd-name__field bd-name__field--full" }, [
|
|
629
|
+
el("span", { class: "bd-name__label" }, ["Nicknames"]),
|
|
630
|
+
input,
|
|
631
|
+
]),
|
|
632
|
+
);
|
|
633
|
+
}
|
|
634
|
+
return grid;
|
|
635
|
+
}
|
|
551
636
|
case "address": {
|
|
552
637
|
const v = (value && typeof value === "object" ? value : {}) as Record<
|
|
553
638
|
string,
|
|
554
639
|
string
|
|
555
640
|
>;
|
|
556
|
-
const grid = el("div", { class: "
|
|
641
|
+
const grid = el("div", { class: "bd-address" });
|
|
557
642
|
// Fixed per-sub-field autofill tokens, suppressed to "off" when the
|
|
558
643
|
// composite's resolved token is "off". Mirrors the React renderer.
|
|
559
644
|
const part = (
|
|
@@ -562,7 +647,7 @@ function renderFieldInput(
|
|
|
562
647
|
token: string,
|
|
563
648
|
full = false,
|
|
564
649
|
) => {
|
|
565
|
-
const input = el("input", { class: "
|
|
650
|
+
const input = el("input", { class: "bd-input" }) as HTMLInputElement;
|
|
566
651
|
setAutocomplete(input, acOff ? "off" : token);
|
|
567
652
|
input.value = v[key] ?? "";
|
|
568
653
|
input.addEventListener("input", () =>
|
|
@@ -572,11 +657,11 @@ function renderFieldInput(
|
|
|
572
657
|
"label",
|
|
573
658
|
{
|
|
574
659
|
class: classNames(
|
|
575
|
-
"
|
|
576
|
-
full && "
|
|
660
|
+
"bd-address__field",
|
|
661
|
+
full && "bd-address__field--full",
|
|
577
662
|
),
|
|
578
663
|
},
|
|
579
|
-
[el("span", { class: "
|
|
664
|
+
[el("span", { class: "bd-address__label" }, [label]), input],
|
|
580
665
|
);
|
|
581
666
|
};
|
|
582
667
|
grid.append(
|
|
@@ -593,10 +678,10 @@ function renderFieldInput(
|
|
|
593
678
|
const maxFiles = field.fileConfig?.maxFiles ?? 1;
|
|
594
679
|
const allowed = field.fileConfig?.allowedTypes;
|
|
595
680
|
const remaining = Math.max(maxFiles - files.length, 0);
|
|
596
|
-
const wrap = el("div", { class: "
|
|
681
|
+
const wrap = el("div", { class: "bd-file" });
|
|
597
682
|
|
|
598
683
|
const input = el("input", {
|
|
599
|
-
class: "
|
|
684
|
+
class: "bd-file__input",
|
|
600
685
|
type: "file",
|
|
601
686
|
...(maxFiles > 1 ? { multiple: true } : {}),
|
|
602
687
|
...(allowed && allowed.length > 0 ? { accept: allowed.join(",") } : {}),
|
|
@@ -613,7 +698,7 @@ function renderFieldInput(
|
|
|
613
698
|
const trigger = el(
|
|
614
699
|
"button",
|
|
615
700
|
{
|
|
616
|
-
class: "
|
|
701
|
+
class: "bd-file__trigger",
|
|
617
702
|
type: "button",
|
|
618
703
|
...(snapshot.uploading || remaining === 0 ? { disabled: true } : {}),
|
|
619
704
|
},
|
|
@@ -629,12 +714,12 @@ function renderFieldInput(
|
|
|
629
714
|
wrap.append(input, trigger);
|
|
630
715
|
|
|
631
716
|
if (files.length > 0) {
|
|
632
|
-
const list = el("ul", { class: "
|
|
717
|
+
const list = el("ul", { class: "bd-file__list" });
|
|
633
718
|
files.forEach((f, idx) => {
|
|
634
719
|
const remove = el(
|
|
635
720
|
"button",
|
|
636
721
|
{
|
|
637
|
-
class: "
|
|
722
|
+
class: "bd-file__remove",
|
|
638
723
|
type: "button",
|
|
639
724
|
"aria-label": "Remove file",
|
|
640
725
|
},
|
|
@@ -644,9 +729,9 @@ function renderFieldInput(
|
|
|
644
729
|
set(files.filter((_, i) => i !== idx)),
|
|
645
730
|
);
|
|
646
731
|
list.append(
|
|
647
|
-
el("li", { class: "
|
|
648
|
-
el("span", { class: "
|
|
649
|
-
el("span", { class: "
|
|
732
|
+
el("li", { class: "bd-file__item" }, [
|
|
733
|
+
el("span", { class: "bd-file__name" }, [f.name]),
|
|
734
|
+
el("span", { class: "bd-file__size" }, [
|
|
650
735
|
`${Math.round(f.size / 1024)} KB`,
|
|
651
736
|
]),
|
|
652
737
|
remove,
|
|
@@ -659,7 +744,7 @@ function renderFieldInput(
|
|
|
659
744
|
}
|
|
660
745
|
default: {
|
|
661
746
|
const node = el("input", {
|
|
662
|
-
class: "
|
|
747
|
+
class: "bd-input",
|
|
663
748
|
type: "text",
|
|
664
749
|
placeholder: field.placeholder || "",
|
|
665
750
|
}) as HTMLInputElement;
|
|
@@ -682,24 +767,24 @@ function twoField(
|
|
|
682
767
|
): HTMLElement {
|
|
683
768
|
const [lt, rt] = Array.isArray(type) ? type : [type, type];
|
|
684
769
|
const left = el("input", {
|
|
685
|
-
class: "
|
|
770
|
+
class: "bd-input",
|
|
686
771
|
type: lt,
|
|
687
772
|
}) as HTMLInputElement;
|
|
688
773
|
const right = el("input", {
|
|
689
|
-
class: "
|
|
774
|
+
class: "bd-input",
|
|
690
775
|
type: rt,
|
|
691
776
|
}) as HTMLInputElement;
|
|
692
777
|
left.value = leftValue;
|
|
693
778
|
right.value = rightValue;
|
|
694
779
|
left.addEventListener("input", () => onChange(left.value, right.value));
|
|
695
780
|
right.addEventListener("input", () => onChange(left.value, right.value));
|
|
696
|
-
return el("div", { class: "
|
|
697
|
-
el("label", { class: "
|
|
698
|
-
el("span", { class: "
|
|
781
|
+
return el("div", { class: "bd-grid bd-grid--2" }, [
|
|
782
|
+
el("label", { class: "bd-grid__cell" }, [
|
|
783
|
+
el("span", { class: "bd-grid__label" }, [leftLabel]),
|
|
699
784
|
left,
|
|
700
785
|
]),
|
|
701
|
-
el("label", { class: "
|
|
702
|
-
el("span", { class: "
|
|
786
|
+
el("label", { class: "bd-grid__cell" }, [
|
|
787
|
+
el("span", { class: "bd-grid__label" }, [rightLabel]),
|
|
703
788
|
right,
|
|
704
789
|
]),
|
|
705
790
|
]);
|
|
@@ -728,10 +813,10 @@ function renderFieldRow(
|
|
|
728
813
|
|
|
729
814
|
if (showLabel && field.label) {
|
|
730
815
|
children.push(
|
|
731
|
-
el("label", { class: "
|
|
816
|
+
el("label", { class: "bd-field__label" }, [
|
|
732
817
|
field.label,
|
|
733
818
|
field.required
|
|
734
|
-
? el("span", { class: "
|
|
819
|
+
? el("span", { class: "bd-field__required" }, [" *"])
|
|
735
820
|
: null,
|
|
736
821
|
]),
|
|
737
822
|
);
|
|
@@ -748,13 +833,13 @@ function renderFieldRow(
|
|
|
748
833
|
|
|
749
834
|
if (errored) {
|
|
750
835
|
children.push(
|
|
751
|
-
el("p", { class: "
|
|
836
|
+
el("p", { class: "bd-field__error" }, [
|
|
752
837
|
ctx.snapshot.errors[field.id]?.message ?? "This field is required.",
|
|
753
838
|
]),
|
|
754
839
|
);
|
|
755
840
|
}
|
|
756
841
|
if (field.helpText) {
|
|
757
|
-
children.push(el("p", { class: "
|
|
842
|
+
children.push(el("p", { class: "bd-field__help" }, [field.helpText]));
|
|
758
843
|
}
|
|
759
844
|
|
|
760
845
|
// `flat` is accepted for signature parity with the group renderer; rows look
|
|
@@ -764,14 +849,14 @@ function renderFieldRow(
|
|
|
764
849
|
"div",
|
|
765
850
|
{
|
|
766
851
|
class: classNames(
|
|
767
|
-
"
|
|
768
|
-
`
|
|
769
|
-
field.required && "
|
|
770
|
-
errored && "
|
|
852
|
+
"bd-field",
|
|
853
|
+
`bd-field--${field.type}`,
|
|
854
|
+
field.required && "bd-field--required",
|
|
855
|
+
errored && "bd-field--error",
|
|
771
856
|
),
|
|
772
857
|
"data-field-id": field.id,
|
|
773
|
-
"data-
|
|
774
|
-
"data-
|
|
858
|
+
"data-bd-field": fieldCssKey(field),
|
|
859
|
+
"data-bd-type": field.type,
|
|
775
860
|
},
|
|
776
861
|
children,
|
|
777
862
|
);
|
|
@@ -783,7 +868,7 @@ function renderTree(
|
|
|
783
868
|
ctx: RenderCtx,
|
|
784
869
|
flat: boolean,
|
|
785
870
|
): HTMLElement {
|
|
786
|
-
const container = el("div", { class: "
|
|
871
|
+
const container = el("div", { class: "bd-tree" });
|
|
787
872
|
|
|
788
873
|
for (const field of fields) {
|
|
789
874
|
if (field.type === "input_group") {
|
|
@@ -799,16 +884,16 @@ function renderTree(
|
|
|
799
884
|
"div",
|
|
800
885
|
{
|
|
801
886
|
class: classNames(
|
|
802
|
-
"
|
|
803
|
-
flat ? "
|
|
887
|
+
"bd-group",
|
|
888
|
+
flat ? "bd-group--flat" : "bd-group--card",
|
|
804
889
|
),
|
|
805
|
-
"data-
|
|
890
|
+
"data-bd-group": fieldCssKey(field),
|
|
806
891
|
},
|
|
807
892
|
[],
|
|
808
893
|
);
|
|
809
894
|
if (field.label && field.showGroupLabel === true) {
|
|
810
895
|
groupNode.append(
|
|
811
|
-
el("div", { class: "
|
|
896
|
+
el("div", { class: "bd-group__label" }, [field.label]),
|
|
812
897
|
);
|
|
813
898
|
}
|
|
814
899
|
groupNode.append(renderTree(visible, ctx, flat));
|
|
@@ -830,29 +915,29 @@ function renderTree(
|
|
|
830
915
|
const right = field.children?.[1];
|
|
831
916
|
const box = el(
|
|
832
917
|
"div",
|
|
833
|
-
{ class: classNames("
|
|
918
|
+
{ class: classNames("bd-or", errored && "bd-or--error") },
|
|
834
919
|
[],
|
|
835
920
|
);
|
|
836
921
|
if (field.label) {
|
|
837
922
|
box.append(
|
|
838
|
-
el("div", { class: "
|
|
923
|
+
el("div", { class: "bd-or__label" }, [
|
|
839
924
|
field.label,
|
|
840
|
-
el("span", { class: "
|
|
925
|
+
el("span", { class: "bd-or__hint" }, [" Fill at least one side"]),
|
|
841
926
|
]),
|
|
842
927
|
);
|
|
843
928
|
}
|
|
844
|
-
const grid = el("div", { class: "
|
|
845
|
-
el("div", { class: "
|
|
846
|
-
el("div", { class: "
|
|
929
|
+
const grid = el("div", { class: "bd-or__grid" }, [
|
|
930
|
+
el("div", { class: "bd-or__side" }, [
|
|
931
|
+
el("div", { class: "bd-or__side-label" }, [
|
|
847
932
|
field.orConditionConfig?.leftLabel || "Option A",
|
|
848
933
|
]),
|
|
849
934
|
left ? renderTree([left], ctx, flat) : null,
|
|
850
935
|
]),
|
|
851
|
-
el("div", { class: "
|
|
852
|
-
el("span", { class: "
|
|
936
|
+
el("div", { class: "bd-or__divider" }, [
|
|
937
|
+
el("span", { class: "bd-or__badge" }, ["OR"]),
|
|
853
938
|
]),
|
|
854
|
-
el("div", { class: "
|
|
855
|
-
el("div", { class: "
|
|
939
|
+
el("div", { class: "bd-or__side" }, [
|
|
940
|
+
el("div", { class: "bd-or__side-label" }, [
|
|
856
941
|
field.orConditionConfig?.rightLabel || "Option B",
|
|
857
942
|
]),
|
|
858
943
|
right ? renderTree([right], ctx, flat) : null,
|
|
@@ -861,7 +946,7 @@ function renderTree(
|
|
|
861
946
|
box.append(grid);
|
|
862
947
|
if (errored) {
|
|
863
948
|
box.append(
|
|
864
|
-
el("p", { class: "
|
|
949
|
+
el("p", { class: "bd-or__error" }, [
|
|
865
950
|
"Fill in at least one side to continue.",
|
|
866
951
|
]),
|
|
867
952
|
);
|
|
@@ -871,10 +956,10 @@ function renderTree(
|
|
|
871
956
|
}
|
|
872
957
|
|
|
873
958
|
if (field.type === "flex_row") {
|
|
874
|
-
const row = el("div", { class: "
|
|
959
|
+
const row = el("div", { class: "bd-flex-row" }, []);
|
|
875
960
|
for (const child of (field.children ?? []) as FormCoreField[]) {
|
|
876
961
|
row.append(
|
|
877
|
-
el("div", { class: "
|
|
962
|
+
el("div", { class: "bd-flex-row__cell" }, [
|
|
878
963
|
renderFieldRow(child, ctx, flat),
|
|
879
964
|
]),
|
|
880
965
|
);
|
|
@@ -902,17 +987,17 @@ function renderProgress(
|
|
|
902
987
|
return null;
|
|
903
988
|
|
|
904
989
|
if (settings.progressStyle === "bar") {
|
|
905
|
-
const fill = el("div", { class: "
|
|
990
|
+
const fill = el("div", { class: "bd-progress__fill" });
|
|
906
991
|
fill.style.width = `${((step + 1) / stepCount) * 100}%`;
|
|
907
|
-
return el("div", { class: "
|
|
908
|
-
el("span", { class: "
|
|
992
|
+
return el("div", { class: "bd-progress bd-progress--bar" }, [
|
|
993
|
+
el("span", { class: "bd-progress__count" }, [
|
|
909
994
|
`${step + 1} / ${stepCount}`,
|
|
910
995
|
]),
|
|
911
|
-
el("div", { class: "
|
|
996
|
+
el("div", { class: "bd-progress__track" }, [fill]),
|
|
912
997
|
]);
|
|
913
998
|
}
|
|
914
999
|
|
|
915
|
-
const track = el("div", { class: "
|
|
1000
|
+
const track = el("div", { class: "bd-progress__steps" });
|
|
916
1001
|
steps.forEach((s, i) => {
|
|
917
1002
|
const f = s[0];
|
|
918
1003
|
const title =
|
|
@@ -925,8 +1010,8 @@ function renderProgress(
|
|
|
925
1010
|
track.append(
|
|
926
1011
|
el("div", {
|
|
927
1012
|
class: classNames(
|
|
928
|
-
"
|
|
929
|
-
i <= step && "
|
|
1013
|
+
"bd-progress__line",
|
|
1014
|
+
i <= step && "bd-progress__line--done",
|
|
930
1015
|
),
|
|
931
1016
|
}),
|
|
932
1017
|
);
|
|
@@ -935,9 +1020,9 @@ function renderProgress(
|
|
|
935
1020
|
"span",
|
|
936
1021
|
{
|
|
937
1022
|
class: classNames(
|
|
938
|
-
"
|
|
939
|
-
current && "
|
|
940
|
-
done && "
|
|
1023
|
+
"bd-progress__dot",
|
|
1024
|
+
current && "bd-progress__dot--current",
|
|
1025
|
+
done && "bd-progress__dot--done",
|
|
941
1026
|
),
|
|
942
1027
|
},
|
|
943
1028
|
[done ? "✓" : String(i + 1)],
|
|
@@ -946,25 +1031,25 @@ function renderProgress(
|
|
|
946
1031
|
"button",
|
|
947
1032
|
{
|
|
948
1033
|
class: classNames(
|
|
949
|
-
"
|
|
950
|
-
current && "
|
|
1034
|
+
"bd-progress__step",
|
|
1035
|
+
current && "bd-progress__step--current",
|
|
951
1036
|
),
|
|
952
1037
|
type: "button",
|
|
953
1038
|
},
|
|
954
|
-
[dot, el("span", { class: "
|
|
1039
|
+
[dot, el("span", { class: "bd-progress__title" }, [title])],
|
|
955
1040
|
);
|
|
956
1041
|
stepNode.addEventListener("click", () => onJump(i));
|
|
957
1042
|
track.append(stepNode);
|
|
958
1043
|
});
|
|
959
1044
|
|
|
960
|
-
return el("div", { class: "
|
|
961
|
-
el("div", { class: "
|
|
1045
|
+
return el("div", { class: "bd-progress bd-progress--steps" }, [
|
|
1046
|
+
el("div", { class: "bd-progress__heading" }, ["Form Progress"]),
|
|
962
1047
|
track,
|
|
963
1048
|
]);
|
|
964
1049
|
}
|
|
965
1050
|
|
|
966
1051
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
967
|
-
//
|
|
1052
|
+
// mountBdForm — wire a controller to a host element and render reactively.
|
|
968
1053
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
969
1054
|
|
|
970
1055
|
function resolveHost(elOrSelector: Element | string): HTMLElement {
|
|
@@ -974,16 +1059,16 @@ function resolveHost(elOrSelector: Element | string): HTMLElement {
|
|
|
974
1059
|
: elOrSelector;
|
|
975
1060
|
if (!host) {
|
|
976
1061
|
throw new Error(
|
|
977
|
-
`
|
|
1062
|
+
`mountBdForm: no element found for ${typeof elOrSelector === "string" ? `selector "${elOrSelector}"` : "the provided node"}.`,
|
|
978
1063
|
);
|
|
979
1064
|
}
|
|
980
1065
|
return host as HTMLElement;
|
|
981
1066
|
}
|
|
982
1067
|
|
|
983
|
-
export function
|
|
1068
|
+
export function mountBdForm(
|
|
984
1069
|
elOrSelector: Element | string,
|
|
985
|
-
opts:
|
|
986
|
-
):
|
|
1070
|
+
opts: MountBdFormOptions,
|
|
1071
|
+
): BdFormInstance {
|
|
987
1072
|
const host = resolveHost(elOrSelector);
|
|
988
1073
|
const extraClass = opts.class ?? opts.className;
|
|
989
1074
|
|
|
@@ -1082,15 +1167,15 @@ export function mountBiabForm(
|
|
|
1082
1167
|
|
|
1083
1168
|
function render(snapshot: FormSnapshot): void {
|
|
1084
1169
|
const root = el("div", {
|
|
1085
|
-
class: classNames("
|
|
1086
|
-
"data-
|
|
1170
|
+
class: classNames("bd-form", extraClass),
|
|
1171
|
+
"data-bd-status": snapshot.status,
|
|
1087
1172
|
});
|
|
1088
1173
|
|
|
1089
1174
|
// Org icon (when the form opted into showOrgIcon).
|
|
1090
1175
|
if (snapshot.orgIcon) {
|
|
1091
1176
|
root.append(
|
|
1092
1177
|
el("img", {
|
|
1093
|
-
class: "
|
|
1178
|
+
class: "bd-form__org-icon",
|
|
1094
1179
|
src: snapshot.orgIcon,
|
|
1095
1180
|
alt: "",
|
|
1096
1181
|
}),
|
|
@@ -1099,13 +1184,13 @@ export function mountBiabForm(
|
|
|
1099
1184
|
|
|
1100
1185
|
// Loading / error states.
|
|
1101
1186
|
if (snapshot.status === "loading" || snapshot.status === "idle") {
|
|
1102
|
-
root.append(el("div", { class: "
|
|
1187
|
+
root.append(el("div", { class: "bd-form__loading" }, ["Loading…"]));
|
|
1103
1188
|
swap(root);
|
|
1104
1189
|
return;
|
|
1105
1190
|
}
|
|
1106
1191
|
if (snapshot.status === "error") {
|
|
1107
1192
|
root.append(
|
|
1108
|
-
el("div", { class: "
|
|
1193
|
+
el("div", { class: "bd-form__error" }, [
|
|
1109
1194
|
snapshot.loadError || "Could not load this form.",
|
|
1110
1195
|
]),
|
|
1111
1196
|
);
|
|
@@ -1116,10 +1201,8 @@ export function mountBiabForm(
|
|
|
1116
1201
|
// Submitted confirmation.
|
|
1117
1202
|
if (snapshot.submitted) {
|
|
1118
1203
|
root.append(
|
|
1119
|
-
el("div", { class: "
|
|
1120
|
-
el("p", { class: "
|
|
1121
|
-
"Thanks — we got it.",
|
|
1122
|
-
]),
|
|
1204
|
+
el("div", { class: "bd-form__success" }, [
|
|
1205
|
+
el("p", { class: "bd-form__success-title" }, ["Thanks — we got it."]),
|
|
1123
1206
|
]),
|
|
1124
1207
|
);
|
|
1125
1208
|
swap(root);
|
|
@@ -1128,14 +1211,12 @@ export function mountBiabForm(
|
|
|
1128
1211
|
|
|
1129
1212
|
// Header (title / description).
|
|
1130
1213
|
if (snapshot.title || snapshot.description) {
|
|
1131
|
-
const header = el("div", { class: "
|
|
1214
|
+
const header = el("div", { class: "bd-form__header" }, []);
|
|
1132
1215
|
if (snapshot.title)
|
|
1133
|
-
header.append(
|
|
1134
|
-
el("h2", { class: "biab-form__title" }, [snapshot.title]),
|
|
1135
|
-
);
|
|
1216
|
+
header.append(el("h2", { class: "bd-form__title" }, [snapshot.title]));
|
|
1136
1217
|
if (snapshot.description) {
|
|
1137
1218
|
header.append(
|
|
1138
|
-
el("p", { class: "
|
|
1219
|
+
el("p", { class: "bd-form__description" }, [snapshot.description]),
|
|
1139
1220
|
);
|
|
1140
1221
|
}
|
|
1141
1222
|
root.append(header);
|
|
@@ -1148,11 +1229,11 @@ export function mountBiabForm(
|
|
|
1148
1229
|
// Error summary banner.
|
|
1149
1230
|
if (snapshot.errorList.length > 0) {
|
|
1150
1231
|
root.append(
|
|
1151
|
-
el("div", { class: "
|
|
1152
|
-
el("div", { class: "
|
|
1232
|
+
el("div", { class: "bd-form__error-summary" }, [
|
|
1233
|
+
el("div", { class: "bd-form__error-summary-title" }, [
|
|
1153
1234
|
`Please complete the highlighted required field${snapshot.errorList.length === 1 ? "" : "s"}.`,
|
|
1154
1235
|
]),
|
|
1155
|
-
el("div", { class: "
|
|
1236
|
+
el("div", { class: "bd-form__error-summary-list" }, [
|
|
1156
1237
|
snapshot.errorList.map((e) => e.label).join(", "),
|
|
1157
1238
|
]),
|
|
1158
1239
|
]),
|
|
@@ -1172,13 +1253,13 @@ export function mountBiabForm(
|
|
|
1172
1253
|
const flat = snapshot.settings.isConsecutive;
|
|
1173
1254
|
const stepWrap = el("div", {
|
|
1174
1255
|
class: animClass(snapshot.settings.animation, snapshot.forward),
|
|
1175
|
-
"data-
|
|
1256
|
+
"data-bd-step": String(snapshot.step),
|
|
1176
1257
|
});
|
|
1177
1258
|
if (snapshot.settings.animation === "scroll") {
|
|
1178
1259
|
// Reveal each top-level field on scroll. Class is the hook; CSS owns the
|
|
1179
1260
|
// transition. We add the visible state once it intersects.
|
|
1180
1261
|
for (const vf of snapshot.visibleFields) {
|
|
1181
|
-
const reveal = el("div", { class: "
|
|
1262
|
+
const reveal = el("div", { class: "bd-reveal" }, [
|
|
1182
1263
|
renderTree([vf], ctx, flat),
|
|
1183
1264
|
]);
|
|
1184
1265
|
stepWrap.append(reveal);
|
|
@@ -1202,7 +1283,7 @@ export function mountBiabForm(
|
|
|
1202
1283
|
const back = el(
|
|
1203
1284
|
"button",
|
|
1204
1285
|
{
|
|
1205
|
-
class: "
|
|
1286
|
+
class: "bd-btn bd-btn--ghost bd-btn--back",
|
|
1206
1287
|
type: "button",
|
|
1207
1288
|
...(snapshot.isFirstStep ? { disabled: true } : {}),
|
|
1208
1289
|
},
|
|
@@ -1215,7 +1296,7 @@ export function mountBiabForm(
|
|
|
1215
1296
|
advance = el(
|
|
1216
1297
|
"button",
|
|
1217
1298
|
{
|
|
1218
|
-
class: "
|
|
1299
|
+
class: "bd-btn bd-btn--next",
|
|
1219
1300
|
type: "button",
|
|
1220
1301
|
...(snapshot.canAdvance ? {} : { disabled: true }),
|
|
1221
1302
|
},
|
|
@@ -1226,7 +1307,7 @@ export function mountBiabForm(
|
|
|
1226
1307
|
advance = el(
|
|
1227
1308
|
"button",
|
|
1228
1309
|
{
|
|
1229
|
-
class: "
|
|
1310
|
+
class: "bd-btn bd-btn--submit",
|
|
1230
1311
|
type: "button",
|
|
1231
1312
|
...(snapshot.submitting ? { disabled: true } : {}),
|
|
1232
1313
|
},
|
|
@@ -1234,20 +1315,20 @@ export function mountBiabForm(
|
|
|
1234
1315
|
);
|
|
1235
1316
|
advance.addEventListener("click", () => void doSubmit());
|
|
1236
1317
|
}
|
|
1237
|
-
return el("div", { class: "
|
|
1318
|
+
return el("div", { class: "bd-nav" }, [back, advance]);
|
|
1238
1319
|
}
|
|
1239
1320
|
|
|
1240
1321
|
const submit = el(
|
|
1241
1322
|
"button",
|
|
1242
1323
|
{
|
|
1243
|
-
class: "
|
|
1324
|
+
class: "bd-btn bd-btn--submit",
|
|
1244
1325
|
type: "button",
|
|
1245
1326
|
...(snapshot.submitting ? { disabled: true } : {}),
|
|
1246
1327
|
},
|
|
1247
1328
|
[snapshot.submitting ? "Sending…" : submitLabel],
|
|
1248
1329
|
);
|
|
1249
1330
|
submit.addEventListener("click", () => void doSubmit());
|
|
1250
|
-
return el("div", { class: "
|
|
1331
|
+
return el("div", { class: "bd-nav" }, [submit]);
|
|
1251
1332
|
}
|
|
1252
1333
|
|
|
1253
1334
|
const unsubscribe = controller.subscribe(render);
|
|
@@ -1268,17 +1349,17 @@ export function mountBiabForm(
|
|
|
1268
1349
|
};
|
|
1269
1350
|
}
|
|
1270
1351
|
|
|
1271
|
-
/** Add the `
|
|
1352
|
+
/** Add the `bd-reveal--shown` hook once an element scrolls into view (scroll anim). */
|
|
1272
1353
|
function observeReveal(node: HTMLElement): void {
|
|
1273
1354
|
if (typeof IntersectionObserver === "undefined") {
|
|
1274
|
-
node.classList.add("
|
|
1355
|
+
node.classList.add("bd-reveal--shown");
|
|
1275
1356
|
return;
|
|
1276
1357
|
}
|
|
1277
1358
|
const obs = new IntersectionObserver(
|
|
1278
1359
|
(entries) => {
|
|
1279
1360
|
for (const entry of entries) {
|
|
1280
1361
|
if (entry.isIntersecting) {
|
|
1281
|
-
node.classList.add("
|
|
1362
|
+
node.classList.add("bd-reveal--shown");
|
|
1282
1363
|
obs.disconnect();
|
|
1283
1364
|
break;
|
|
1284
1365
|
}
|
|
@@ -1308,7 +1389,7 @@ import {
|
|
|
1308
1389
|
type ChatController,
|
|
1309
1390
|
createChatController,
|
|
1310
1391
|
} from "./chat-core/index.js";
|
|
1311
|
-
import {
|
|
1392
|
+
import { BdApiClient as BdClientForSurfaces } from "./client.js";
|
|
1312
1393
|
import {
|
|
1313
1394
|
createStoreController,
|
|
1314
1395
|
type StoreController,
|
|
@@ -1327,7 +1408,7 @@ export function createStorefront(
|
|
|
1327
1408
|
options: CreateStorefrontOptions,
|
|
1328
1409
|
): StoreController {
|
|
1329
1410
|
return createStoreController({
|
|
1330
|
-
client: new
|
|
1411
|
+
client: new BdClientForSurfaces({
|
|
1331
1412
|
apiKey: options.apiKey,
|
|
1332
1413
|
baseUrl: options.baseUrl,
|
|
1333
1414
|
}),
|
|
@@ -1346,7 +1427,7 @@ export type CreateChatOptions = {
|
|
|
1346
1427
|
/** Headless Front Desk chat — the native alternative to the iframe widget. */
|
|
1347
1428
|
export function createChat(options: CreateChatOptions): ChatController {
|
|
1348
1429
|
return createChatController({
|
|
1349
|
-
client: new
|
|
1430
|
+
client: new BdClientForSurfaces({
|
|
1350
1431
|
apiKey: options.apiKey,
|
|
1351
1432
|
baseUrl: options.baseUrl,
|
|
1352
1433
|
}),
|
|
@@ -1377,7 +1458,7 @@ export type CreateBlogOptions = {
|
|
|
1377
1458
|
/** Headless blog — posts, taxonomy, a single post, comments and likes. */
|
|
1378
1459
|
export function createBlog(options: CreateBlogOptions): BlogController {
|
|
1379
1460
|
return createBlogController({
|
|
1380
|
-
client: new
|
|
1461
|
+
client: new BdClientForSurfaces({
|
|
1381
1462
|
apiKey: options.apiKey,
|
|
1382
1463
|
baseUrl: options.baseUrl,
|
|
1383
1464
|
}),
|
|
@@ -1402,7 +1483,7 @@ import {
|
|
|
1402
1483
|
type CheckoutController,
|
|
1403
1484
|
createCheckoutController,
|
|
1404
1485
|
} from "./checkout-core/index.js";
|
|
1405
|
-
import {
|
|
1486
|
+
import { createBdClient as createBdClientForFollowers } from "./sdk.js";
|
|
1406
1487
|
|
|
1407
1488
|
/** Headless checkout — mint a Stripe session, then `redirect()` or render it. */
|
|
1408
1489
|
export function createCheckout(options: {
|
|
@@ -1411,7 +1492,7 @@ export function createCheckout(options: {
|
|
|
1411
1492
|
onError?: (error: Error) => void;
|
|
1412
1493
|
}): CheckoutController {
|
|
1413
1494
|
return createCheckoutController({
|
|
1414
|
-
client: new
|
|
1495
|
+
client: new BdClientForSurfaces({
|
|
1415
1496
|
apiKey: options.apiKey,
|
|
1416
1497
|
baseUrl: options.baseUrl,
|
|
1417
1498
|
}),
|
|
@@ -1433,11 +1514,11 @@ export function createFollowers(options: {
|
|
|
1433
1514
|
baseUrl?: string;
|
|
1434
1515
|
onError?: (error: Error) => void;
|
|
1435
1516
|
}): FollowersController {
|
|
1436
|
-
// Followers hang off the PUBLISHABLE client (`
|
|
1437
|
-
// `
|
|
1517
|
+
// Followers hang off the PUBLISHABLE client (`createBdClient`), not
|
|
1518
|
+
// `BdApiClient`: they are the one surface a browser calls directly with an
|
|
1438
1519
|
// origin-locked `pk_…` token and no backend.
|
|
1439
1520
|
return createFollowersController({
|
|
1440
|
-
client:
|
|
1521
|
+
client: createBdClientForFollowers({
|
|
1441
1522
|
apiKey: options.token,
|
|
1442
1523
|
siteId: options.siteId,
|
|
1443
1524
|
baseUrl: options.baseUrl ?? DEFAULT_PACKAGE_BASE_URL_FOR_SURFACES,
|
|
@@ -1494,7 +1575,7 @@ export function createMarketing(options: {
|
|
|
1494
1575
|
onError?: (error: Error) => void;
|
|
1495
1576
|
}): MarketingController {
|
|
1496
1577
|
return createMarketingController({
|
|
1497
|
-
client:
|
|
1578
|
+
client: createBdClientForFollowers({
|
|
1498
1579
|
apiKey: options.token,
|
|
1499
1580
|
siteId: options.siteId,
|
|
1500
1581
|
baseUrl: options.baseUrl ?? DEFAULT_PACKAGE_BASE_URL_FOR_SURFACES,
|
|
@@ -1512,7 +1593,7 @@ export function createVerify(
|
|
|
1512
1593
|
): VerifyController {
|
|
1513
1594
|
const { apiKey, baseUrl, ...rest } = options;
|
|
1514
1595
|
return createVerifyController({
|
|
1515
|
-
client: new
|
|
1596
|
+
client: new BdClientForSurfaces({ apiKey, baseUrl }),
|
|
1516
1597
|
...rest,
|
|
1517
1598
|
});
|
|
1518
1599
|
}
|
|
@@ -1544,7 +1625,7 @@ export function createPortal(options: {
|
|
|
1544
1625
|
onError?: (error: Error) => void;
|
|
1545
1626
|
}): PortalController {
|
|
1546
1627
|
return createPortalController({
|
|
1547
|
-
client: new
|
|
1628
|
+
client: new BdClientForSurfaces({
|
|
1548
1629
|
apiKey: options.apiKey,
|
|
1549
1630
|
baseUrl: options.baseUrl,
|
|
1550
1631
|
}),
|