@businessdash/sdk 0.9.81 → 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 +115 -902
- 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 +350 -273
- 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 +1 -1
- package/dist/push-core/index.d.ts +1 -1
- package/dist/push-core/index.js +1 -1
- 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 +49 -49
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +47 -51
- 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 +3 -3
- package/dist/sitemap-core/index.js +2 -2
- 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 +2 -2
- 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 +106 -110
- 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 +2 -2
- 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/dist/vanilla.js
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
|
import { resolveFieldAutocomplete, } from "./forms-core/autocomplete.js";
|
|
25
25
|
import { concurrentRevealCount, createFormController, evalCondition, } from "./forms-core/index.js";
|
|
@@ -65,17 +65,17 @@ function fieldCssKey(field) {
|
|
|
65
65
|
}
|
|
66
66
|
const NO_LABEL_TYPES = new Set(["title", "subtitle", "separator", "richtext"]);
|
|
67
67
|
/** tw-style entrance class hook for the active step (consumer CSS animates these).
|
|
68
|
-
* Matches the `
|
|
68
|
+
* Matches the `bd-anim--*` convention so orgs can target each animation. */
|
|
69
69
|
function animClass(animation, forward) {
|
|
70
70
|
switch (animation) {
|
|
71
71
|
case "fade":
|
|
72
|
-
return "
|
|
72
|
+
return "bd-anim bd-anim--fade";
|
|
73
73
|
case "scale":
|
|
74
|
-
return "
|
|
74
|
+
return "bd-anim bd-anim--scale";
|
|
75
75
|
case "slide":
|
|
76
76
|
return forward
|
|
77
|
-
? "
|
|
78
|
-
: "
|
|
77
|
+
? "bd-anim bd-anim--slide bd-anim--slide-forward"
|
|
78
|
+
: "bd-anim bd-anim--slide bd-anim--slide-back";
|
|
79
79
|
default:
|
|
80
80
|
return "";
|
|
81
81
|
}
|
|
@@ -93,22 +93,22 @@ function setAutocomplete(el, token) {
|
|
|
93
93
|
function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
94
94
|
const value = snapshot.values[field.id];
|
|
95
95
|
const str = typeof value === "string" ? value : "";
|
|
96
|
-
// Address
|
|
97
|
-
// field's resolved token is "off" (global switch or per-field override).
|
|
96
|
+
// Address/name composites suppress their fixed sub-field tokens to "off" when
|
|
97
|
+
// the field's resolved token is "off" (global switch or per-field override).
|
|
98
98
|
const acOff = autoComplete === "off";
|
|
99
99
|
switch (field.type) {
|
|
100
100
|
case "title":
|
|
101
|
-
return el("h2", { class: "
|
|
101
|
+
return el("h2", { class: "bd-field__title" }, [
|
|
102
102
|
field.label || "Untitled",
|
|
103
103
|
]);
|
|
104
104
|
case "subtitle":
|
|
105
|
-
return el("h3", { class: "
|
|
105
|
+
return el("h3", { class: "bd-field__subtitle" }, [field.label || ""]);
|
|
106
106
|
case "separator":
|
|
107
|
-
return el("hr", { class: "
|
|
107
|
+
return el("hr", { class: "bd-field__separator" });
|
|
108
108
|
case "richtext": {
|
|
109
109
|
if (!field.content)
|
|
110
110
|
return null;
|
|
111
|
-
const div = el("div", { class: "
|
|
111
|
+
const div = el("div", { class: "bd-field__richtext bd-prose" });
|
|
112
112
|
// The published `content` is server-sanitized HTML.
|
|
113
113
|
div.innerHTML = field.content;
|
|
114
114
|
return div;
|
|
@@ -118,7 +118,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
118
118
|
if (!cfg.src)
|
|
119
119
|
return null;
|
|
120
120
|
return el("img", {
|
|
121
|
-
class: "
|
|
121
|
+
class: "bd-field__image",
|
|
122
122
|
src: cfg.src,
|
|
123
123
|
alt: cfg.alt || "",
|
|
124
124
|
...(cfg.width ? { width: cfg.width } : {}),
|
|
@@ -128,7 +128,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
128
128
|
case "textarea": {
|
|
129
129
|
const cfg = (field["textareaConfig"] ?? {});
|
|
130
130
|
const node = el("textarea", {
|
|
131
|
-
class: classNames("
|
|
131
|
+
class: classNames("bd-textarea", cfg.resizable === false && "bd-textarea--fixed"),
|
|
132
132
|
rows: cfg.rows ?? 4,
|
|
133
133
|
placeholder: field.placeholder || "",
|
|
134
134
|
});
|
|
@@ -138,7 +138,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
138
138
|
return node;
|
|
139
139
|
}
|
|
140
140
|
case "select": {
|
|
141
|
-
const node = el("select", { class: "
|
|
141
|
+
const node = el("select", { class: "bd-select" });
|
|
142
142
|
node.append(el("option", { value: "" }, [field.placeholder || "Select..."]));
|
|
143
143
|
for (const opt of field.options ?? []) {
|
|
144
144
|
node.append(el("option", { value: opt }, [opt]));
|
|
@@ -148,11 +148,11 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
148
148
|
return node;
|
|
149
149
|
}
|
|
150
150
|
case "radio": {
|
|
151
|
-
const wrap = el("div", { class: "
|
|
151
|
+
const wrap = el("div", { class: "bd-radio-group" });
|
|
152
152
|
for (const opt of field.options ?? []) {
|
|
153
153
|
const id = `${field.id}-${opt}`;
|
|
154
154
|
const input = el("input", {
|
|
155
|
-
class: "
|
|
155
|
+
class: "bd-radio",
|
|
156
156
|
type: "radio",
|
|
157
157
|
name: field.id,
|
|
158
158
|
id,
|
|
@@ -160,7 +160,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
160
160
|
});
|
|
161
161
|
input.checked = str === opt;
|
|
162
162
|
input.addEventListener("change", () => set(opt));
|
|
163
|
-
wrap.append(el("label", { class: "
|
|
163
|
+
wrap.append(el("label", { class: "bd-radio-option", for: id }, [
|
|
164
164
|
input,
|
|
165
165
|
el("span", {}, [opt]),
|
|
166
166
|
]));
|
|
@@ -169,10 +169,10 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
169
169
|
}
|
|
170
170
|
case "checkbox": {
|
|
171
171
|
const arr = Array.isArray(value) ? value : [];
|
|
172
|
-
const wrap = el("div", { class: "
|
|
172
|
+
const wrap = el("div", { class: "bd-checkbox-group" });
|
|
173
173
|
for (const opt of field.options ?? []) {
|
|
174
174
|
const input = el("input", {
|
|
175
|
-
class: "
|
|
175
|
+
class: "bd-checkbox",
|
|
176
176
|
type: "checkbox",
|
|
177
177
|
value: opt,
|
|
178
178
|
});
|
|
@@ -183,7 +183,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
183
183
|
: arr.filter((x) => x !== opt);
|
|
184
184
|
set(next);
|
|
185
185
|
});
|
|
186
|
-
wrap.append(el("label", { class: "
|
|
186
|
+
wrap.append(el("label", { class: "bd-checkbox-option" }, [
|
|
187
187
|
input,
|
|
188
188
|
el("span", {}, [opt]),
|
|
189
189
|
]));
|
|
@@ -192,21 +192,21 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
192
192
|
}
|
|
193
193
|
case "boolean": {
|
|
194
194
|
const input = el("input", {
|
|
195
|
-
class: "
|
|
195
|
+
class: "bd-switch",
|
|
196
196
|
type: "checkbox",
|
|
197
197
|
});
|
|
198
198
|
input.checked = value === true;
|
|
199
199
|
input.addEventListener("change", () => set(input.checked));
|
|
200
|
-
return el("label", { class: "
|
|
200
|
+
return el("label", { class: "bd-boolean" }, [
|
|
201
201
|
input,
|
|
202
|
-
el("span", { class: "
|
|
202
|
+
el("span", { class: "bd-boolean__label" }, [
|
|
203
203
|
field.placeholder || "Yes / No",
|
|
204
204
|
]),
|
|
205
205
|
]);
|
|
206
206
|
}
|
|
207
207
|
case "date": {
|
|
208
208
|
const node = el("input", {
|
|
209
|
-
class: "
|
|
209
|
+
class: "bd-input",
|
|
210
210
|
type: "date",
|
|
211
211
|
});
|
|
212
212
|
node.value = str;
|
|
@@ -215,7 +215,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
215
215
|
}
|
|
216
216
|
case "email": {
|
|
217
217
|
const node = el("input", {
|
|
218
|
-
class: "
|
|
218
|
+
class: "bd-input",
|
|
219
219
|
type: "email",
|
|
220
220
|
placeholder: field.placeholder || "you@example.com",
|
|
221
221
|
});
|
|
@@ -225,14 +225,14 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
225
225
|
return node;
|
|
226
226
|
}
|
|
227
227
|
case "phone": {
|
|
228
|
-
const wrap = el("div", { class: "
|
|
228
|
+
const wrap = el("div", { class: "bd-phone" });
|
|
229
229
|
if (field.phoneConfig?.showFlags) {
|
|
230
|
-
wrap.append(el("span", { class: "
|
|
230
|
+
wrap.append(el("span", { class: "bd-phone__flag", "aria-hidden": "true" }, [
|
|
231
231
|
"\u{1F1FA}\u{1F1F8}",
|
|
232
232
|
]));
|
|
233
233
|
}
|
|
234
234
|
const node = el("input", {
|
|
235
|
-
class: "
|
|
235
|
+
class: "bd-input",
|
|
236
236
|
type: "tel",
|
|
237
237
|
placeholder: field.placeholder ||
|
|
238
238
|
(field.phoneConfig?.international
|
|
@@ -247,7 +247,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
247
247
|
}
|
|
248
248
|
case "number": {
|
|
249
249
|
const node = el("input", {
|
|
250
|
-
class: "
|
|
250
|
+
class: "bd-input",
|
|
251
251
|
type: "number",
|
|
252
252
|
placeholder: field.placeholder || "",
|
|
253
253
|
});
|
|
@@ -259,12 +259,12 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
259
259
|
}
|
|
260
260
|
case "stepper": {
|
|
261
261
|
const v = typeof value === "number" ? value : 0;
|
|
262
|
-
const out = el("span", { class: "
|
|
263
|
-
const minus = el("button", { class: "
|
|
264
|
-
const plus = el("button", { class: "
|
|
262
|
+
const out = el("span", { class: "bd-stepper__value" }, [String(v)]);
|
|
263
|
+
const minus = el("button", { class: "bd-btn bd-btn--ghost bd-stepper__btn", type: "button" }, ["−"]);
|
|
264
|
+
const plus = el("button", { class: "bd-btn bd-btn--ghost bd-stepper__btn", type: "button" }, ["+"]);
|
|
265
265
|
minus.addEventListener("click", () => set(v - 1));
|
|
266
266
|
plus.addEventListener("click", () => set(v + 1));
|
|
267
|
-
return el("div", { class: "
|
|
267
|
+
return el("div", { class: "bd-stepper" }, [minus, out, plus]);
|
|
268
268
|
}
|
|
269
269
|
case "slider": {
|
|
270
270
|
const min = field.sliderConfig?.min ?? 0;
|
|
@@ -273,9 +273,9 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
273
273
|
const unit = field.sliderConfig?.unit;
|
|
274
274
|
const fmt = (n) => unit === "currency" ? `$${n}` : unit === "percent" ? `${n}%` : `${n}`;
|
|
275
275
|
const v = typeof value === "number" ? value : min;
|
|
276
|
-
const readout = el("span", { class: "
|
|
276
|
+
const readout = el("span", { class: "bd-slider__value" }, [fmt(v)]);
|
|
277
277
|
const input = el("input", {
|
|
278
|
-
class: "
|
|
278
|
+
class: "bd-slider",
|
|
279
279
|
type: "range",
|
|
280
280
|
min,
|
|
281
281
|
max,
|
|
@@ -287,8 +287,8 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
287
287
|
readout.textContent = fmt(n);
|
|
288
288
|
set(n);
|
|
289
289
|
});
|
|
290
|
-
return el("div", { class: "
|
|
291
|
-
el("div", { class: "
|
|
290
|
+
return el("div", { class: "bd-slider-wrap" }, [
|
|
291
|
+
el("div", { class: "bd-slider__scale" }, [
|
|
292
292
|
el("span", {}, [fmt(min)]),
|
|
293
293
|
readout,
|
|
294
294
|
el("span", {}, [fmt(max)]),
|
|
@@ -299,10 +299,10 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
299
299
|
case "star_rating": {
|
|
300
300
|
const max = field.starRatingConfig?.maxStars ?? 5;
|
|
301
301
|
const v = typeof value === "number" ? value : 0;
|
|
302
|
-
const wrap = el("div", { class: "
|
|
302
|
+
const wrap = el("div", { class: "bd-stars" });
|
|
303
303
|
for (let i = 0; i < max; i++) {
|
|
304
304
|
const btn = el("button", {
|
|
305
|
-
class: classNames("
|
|
305
|
+
class: classNames("bd-star", i < v && "bd-star--filled"),
|
|
306
306
|
type: "button",
|
|
307
307
|
"aria-label": `${i + 1} star${i === 0 ? "" : "s"}`,
|
|
308
308
|
}, ["★"]);
|
|
@@ -313,10 +313,10 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
313
313
|
}
|
|
314
314
|
case "happiness_rating": {
|
|
315
315
|
const v = typeof value === "number" ? value : -1;
|
|
316
|
-
const wrap = el("div", { class: "
|
|
316
|
+
const wrap = el("div", { class: "bd-happiness" });
|
|
317
317
|
["\u{1F61E}", "\u{1F615}", "\u{1F610}", "\u{1F642}", "\u{1F604}"].forEach((emoji, i) => {
|
|
318
318
|
const btn = el("button", {
|
|
319
|
-
class: classNames("
|
|
319
|
+
class: classNames("bd-happiness__face", i === v && "bd-happiness__face--active"),
|
|
320
320
|
type: "button",
|
|
321
321
|
}, [emoji]);
|
|
322
322
|
btn.addEventListener("click", () => set(i));
|
|
@@ -326,10 +326,10 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
326
326
|
}
|
|
327
327
|
case "color_picker": {
|
|
328
328
|
const v = str;
|
|
329
|
-
const wrap = el("div", { class: "
|
|
329
|
+
const wrap = el("div", { class: "bd-colors" });
|
|
330
330
|
for (const color of field.options ?? []) {
|
|
331
331
|
const btn = el("button", {
|
|
332
|
-
class: classNames("
|
|
332
|
+
class: classNames("bd-color", v === color && "bd-color--selected"),
|
|
333
333
|
type: "button",
|
|
334
334
|
title: color,
|
|
335
335
|
style: `background-color:${color}`,
|
|
@@ -351,7 +351,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
351
351
|
const format = field.timeConfig?.format ?? "12h";
|
|
352
352
|
const step = Math.max(field.timeConfig?.stepMinutes ?? 30, 1);
|
|
353
353
|
const node = el("select", {
|
|
354
|
-
class: "
|
|
354
|
+
class: "bd-select",
|
|
355
355
|
});
|
|
356
356
|
node.append(el("option", { value: "" }, [field.placeholder || "Select time"]));
|
|
357
357
|
for (let h = 0; h < 24; h++) {
|
|
@@ -380,19 +380,68 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
380
380
|
: { date: "", time: "" };
|
|
381
381
|
return twoField("Date", v.date ?? "", "Time", v.time ?? "", ["date", "time"], (date, time) => set({ ...v, date, time }));
|
|
382
382
|
}
|
|
383
|
+
case "name": {
|
|
384
|
+
const v = (value && typeof value === "object" ? value : {});
|
|
385
|
+
const cfg = field.nameConfig ?? {};
|
|
386
|
+
const grid = el("div", { class: "bd-name" });
|
|
387
|
+
// Fixed per-sub-field autofill tokens, suppressed to "off" when the
|
|
388
|
+
// composite's resolved token is "off". Mirrors the React renderer.
|
|
389
|
+
const part = (key, label, token, placeholder, full = false) => {
|
|
390
|
+
const input = el("input", {
|
|
391
|
+
class: "bd-input",
|
|
392
|
+
placeholder,
|
|
393
|
+
});
|
|
394
|
+
setAutocomplete(input, acOff ? "off" : token);
|
|
395
|
+
input.value = v[key] ?? "";
|
|
396
|
+
input.addEventListener("input", () => set({ ...v, [key]: input.value }));
|
|
397
|
+
return el("label", {
|
|
398
|
+
class: classNames("bd-name__field", full && "bd-name__field--full"),
|
|
399
|
+
}, [el("span", { class: "bd-name__label" }, [label]), input]);
|
|
400
|
+
};
|
|
401
|
+
if (cfg.prefix) {
|
|
402
|
+
grid.append(part("prefix", "Title", "honorific-prefix", "Dr.", true));
|
|
403
|
+
}
|
|
404
|
+
grid.append(part("first", "First name", "given-name", "Jane"));
|
|
405
|
+
if (cfg.middle) {
|
|
406
|
+
grid.append(part("middle", "Middle name", "additional-name", "Quinn"));
|
|
407
|
+
}
|
|
408
|
+
grid.append(part("last", "Last name", "family-name", "Doe", cfg.middle === true && cfg.suffix !== true));
|
|
409
|
+
if (cfg.suffix) {
|
|
410
|
+
grid.append(part("suffix", "Suffix", "honorific-suffix", "Jr.", cfg.middle !== true));
|
|
411
|
+
}
|
|
412
|
+
if (cfg.nicknames) {
|
|
413
|
+
// The nicknames input keeps the raw comma-separated string while the
|
|
414
|
+
// visitor types; submit normalizes it into a string[].
|
|
415
|
+
const input = el("input", {
|
|
416
|
+
class: "bd-input",
|
|
417
|
+
placeholder: "Johnny, JM — separate with commas",
|
|
418
|
+
});
|
|
419
|
+
input.value = Array.isArray(v.nicknames)
|
|
420
|
+
? v.nicknames.join(", ")
|
|
421
|
+
: typeof v.nicknames === "string"
|
|
422
|
+
? v.nicknames
|
|
423
|
+
: "";
|
|
424
|
+
input.addEventListener("input", () => set({ ...v, nicknames: input.value }));
|
|
425
|
+
grid.append(el("label", { class: "bd-name__field bd-name__field--full" }, [
|
|
426
|
+
el("span", { class: "bd-name__label" }, ["Nicknames"]),
|
|
427
|
+
input,
|
|
428
|
+
]));
|
|
429
|
+
}
|
|
430
|
+
return grid;
|
|
431
|
+
}
|
|
383
432
|
case "address": {
|
|
384
433
|
const v = (value && typeof value === "object" ? value : {});
|
|
385
|
-
const grid = el("div", { class: "
|
|
434
|
+
const grid = el("div", { class: "bd-address" });
|
|
386
435
|
// Fixed per-sub-field autofill tokens, suppressed to "off" when the
|
|
387
436
|
// composite's resolved token is "off". Mirrors the React renderer.
|
|
388
437
|
const part = (key, label, token, full = false) => {
|
|
389
|
-
const input = el("input", { class: "
|
|
438
|
+
const input = el("input", { class: "bd-input" });
|
|
390
439
|
setAutocomplete(input, acOff ? "off" : token);
|
|
391
440
|
input.value = v[key] ?? "";
|
|
392
441
|
input.addEventListener("input", () => set({ ...v, [key]: input.value }));
|
|
393
442
|
return el("label", {
|
|
394
|
-
class: classNames("
|
|
395
|
-
}, [el("span", { class: "
|
|
443
|
+
class: classNames("bd-address__field", full && "bd-address__field--full"),
|
|
444
|
+
}, [el("span", { class: "bd-address__label" }, [label]), input]);
|
|
396
445
|
};
|
|
397
446
|
grid.append(part("line1", "Address Line 1", "street-address", true), part("line2", "Address Line 2", "address-line2", true), part("city", "City", "address-level2"), part("state", "State", "address-level1"), part("zip", "Zip", "postal-code", true));
|
|
398
447
|
return grid;
|
|
@@ -402,9 +451,9 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
402
451
|
const maxFiles = field.fileConfig?.maxFiles ?? 1;
|
|
403
452
|
const allowed = field.fileConfig?.allowedTypes;
|
|
404
453
|
const remaining = Math.max(maxFiles - files.length, 0);
|
|
405
|
-
const wrap = el("div", { class: "
|
|
454
|
+
const wrap = el("div", { class: "bd-file" });
|
|
406
455
|
const input = el("input", {
|
|
407
|
-
class: "
|
|
456
|
+
class: "bd-file__input",
|
|
408
457
|
type: "file",
|
|
409
458
|
...(maxFiles > 1 ? { multiple: true } : {}),
|
|
410
459
|
...(allowed && allowed.length > 0 ? { accept: allowed.join(",") } : {}),
|
|
@@ -419,7 +468,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
419
468
|
input.value = "";
|
|
420
469
|
});
|
|
421
470
|
const trigger = el("button", {
|
|
422
|
-
class: "
|
|
471
|
+
class: "bd-file__trigger",
|
|
423
472
|
type: "button",
|
|
424
473
|
...(snapshot.uploading || remaining === 0 ? { disabled: true } : {}),
|
|
425
474
|
}, [
|
|
@@ -432,17 +481,17 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
432
481
|
trigger.addEventListener("click", () => input.click());
|
|
433
482
|
wrap.append(input, trigger);
|
|
434
483
|
if (files.length > 0) {
|
|
435
|
-
const list = el("ul", { class: "
|
|
484
|
+
const list = el("ul", { class: "bd-file__list" });
|
|
436
485
|
files.forEach((f, idx) => {
|
|
437
486
|
const remove = el("button", {
|
|
438
|
-
class: "
|
|
487
|
+
class: "bd-file__remove",
|
|
439
488
|
type: "button",
|
|
440
489
|
"aria-label": "Remove file",
|
|
441
490
|
}, ["✕"]);
|
|
442
491
|
remove.addEventListener("click", () => set(files.filter((_, i) => i !== idx)));
|
|
443
|
-
list.append(el("li", { class: "
|
|
444
|
-
el("span", { class: "
|
|
445
|
-
el("span", { class: "
|
|
492
|
+
list.append(el("li", { class: "bd-file__item" }, [
|
|
493
|
+
el("span", { class: "bd-file__name" }, [f.name]),
|
|
494
|
+
el("span", { class: "bd-file__size" }, [
|
|
446
495
|
`${Math.round(f.size / 1024)} KB`,
|
|
447
496
|
]),
|
|
448
497
|
remove,
|
|
@@ -454,7 +503,7 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
454
503
|
}
|
|
455
504
|
default: {
|
|
456
505
|
const node = el("input", {
|
|
457
|
-
class: "
|
|
506
|
+
class: "bd-input",
|
|
458
507
|
type: "text",
|
|
459
508
|
placeholder: field.placeholder || "",
|
|
460
509
|
});
|
|
@@ -469,24 +518,24 @@ function renderFieldInput(field, snapshot, set, upload, autoComplete) {
|
|
|
469
518
|
function twoField(leftLabel, leftValue, rightLabel, rightValue, type, onChange) {
|
|
470
519
|
const [lt, rt] = Array.isArray(type) ? type : [type, type];
|
|
471
520
|
const left = el("input", {
|
|
472
|
-
class: "
|
|
521
|
+
class: "bd-input",
|
|
473
522
|
type: lt,
|
|
474
523
|
});
|
|
475
524
|
const right = el("input", {
|
|
476
|
-
class: "
|
|
525
|
+
class: "bd-input",
|
|
477
526
|
type: rt,
|
|
478
527
|
});
|
|
479
528
|
left.value = leftValue;
|
|
480
529
|
right.value = rightValue;
|
|
481
530
|
left.addEventListener("input", () => onChange(left.value, right.value));
|
|
482
531
|
right.addEventListener("input", () => onChange(left.value, right.value));
|
|
483
|
-
return el("div", { class: "
|
|
484
|
-
el("label", { class: "
|
|
485
|
-
el("span", { class: "
|
|
532
|
+
return el("div", { class: "bd-grid bd-grid--2" }, [
|
|
533
|
+
el("label", { class: "bd-grid__cell" }, [
|
|
534
|
+
el("span", { class: "bd-grid__label" }, [leftLabel]),
|
|
486
535
|
left,
|
|
487
536
|
]),
|
|
488
|
-
el("label", { class: "
|
|
489
|
-
el("span", { class: "
|
|
537
|
+
el("label", { class: "bd-grid__cell" }, [
|
|
538
|
+
el("span", { class: "bd-grid__label" }, [rightLabel]),
|
|
490
539
|
right,
|
|
491
540
|
]),
|
|
492
541
|
]);
|
|
@@ -496,10 +545,10 @@ function renderFieldRow(field, ctx, flat) {
|
|
|
496
545
|
const showLabel = !NO_LABEL_TYPES.has(field.type);
|
|
497
546
|
const children = [];
|
|
498
547
|
if (showLabel && field.label) {
|
|
499
|
-
children.push(el("label", { class: "
|
|
548
|
+
children.push(el("label", { class: "bd-field__label" }, [
|
|
500
549
|
field.label,
|
|
501
550
|
field.required
|
|
502
|
-
? el("span", { class: "
|
|
551
|
+
? el("span", { class: "bd-field__required" }, [" *"])
|
|
503
552
|
: null,
|
|
504
553
|
]));
|
|
505
554
|
}
|
|
@@ -507,26 +556,26 @@ function renderFieldRow(field, ctx, flat) {
|
|
|
507
556
|
if (input)
|
|
508
557
|
children.push(input);
|
|
509
558
|
if (errored) {
|
|
510
|
-
children.push(el("p", { class: "
|
|
559
|
+
children.push(el("p", { class: "bd-field__error" }, [
|
|
511
560
|
ctx.snapshot.errors[field.id]?.message ?? "This field is required.",
|
|
512
561
|
]));
|
|
513
562
|
}
|
|
514
563
|
if (field.helpText) {
|
|
515
|
-
children.push(el("p", { class: "
|
|
564
|
+
children.push(el("p", { class: "bd-field__help" }, [field.helpText]));
|
|
516
565
|
}
|
|
517
566
|
// `flat` is accepted for signature parity with the group renderer; rows look
|
|
518
567
|
// the same flat or nested.
|
|
519
568
|
void flat;
|
|
520
569
|
return el("div", {
|
|
521
|
-
class: classNames("
|
|
570
|
+
class: classNames("bd-field", `bd-field--${field.type}`, field.required && "bd-field--required", errored && "bd-field--error"),
|
|
522
571
|
"data-field-id": field.id,
|
|
523
|
-
"data-
|
|
524
|
-
"data-
|
|
572
|
+
"data-bd-field": fieldCssKey(field),
|
|
573
|
+
"data-bd-type": field.type,
|
|
525
574
|
}, children);
|
|
526
575
|
}
|
|
527
576
|
/** Recursively render a list of fields, handling every layout/condition node. */
|
|
528
577
|
function renderTree(fields, ctx, flat) {
|
|
529
|
-
const container = el("div", { class: "
|
|
578
|
+
const container = el("div", { class: "bd-tree" });
|
|
530
579
|
for (const field of fields) {
|
|
531
580
|
if (field.type === "input_group") {
|
|
532
581
|
const groupChildren = (field.children ?? []);
|
|
@@ -538,11 +587,11 @@ function renderTree(fields, ctx, flat) {
|
|
|
538
587
|
? groupChildren.slice(0, revealCount)
|
|
539
588
|
: groupChildren;
|
|
540
589
|
const groupNode = el("div", {
|
|
541
|
-
class: classNames("
|
|
542
|
-
"data-
|
|
590
|
+
class: classNames("bd-group", flat ? "bd-group--flat" : "bd-group--card"),
|
|
591
|
+
"data-bd-group": fieldCssKey(field),
|
|
543
592
|
}, []);
|
|
544
593
|
if (field.label && field.showGroupLabel === true) {
|
|
545
|
-
groupNode.append(el("div", { class: "
|
|
594
|
+
groupNode.append(el("div", { class: "bd-group__label" }, [field.label]));
|
|
546
595
|
}
|
|
547
596
|
groupNode.append(renderTree(visible, ctx, flat));
|
|
548
597
|
container.append(groupNode);
|
|
@@ -558,25 +607,25 @@ function renderTree(fields, ctx, flat) {
|
|
|
558
607
|
const errored = Boolean(ctx.snapshot.errors[field.id]);
|
|
559
608
|
const left = field.children?.[0];
|
|
560
609
|
const right = field.children?.[1];
|
|
561
|
-
const box = el("div", { class: classNames("
|
|
610
|
+
const box = el("div", { class: classNames("bd-or", errored && "bd-or--error") }, []);
|
|
562
611
|
if (field.label) {
|
|
563
|
-
box.append(el("div", { class: "
|
|
612
|
+
box.append(el("div", { class: "bd-or__label" }, [
|
|
564
613
|
field.label,
|
|
565
|
-
el("span", { class: "
|
|
614
|
+
el("span", { class: "bd-or__hint" }, [" Fill at least one side"]),
|
|
566
615
|
]));
|
|
567
616
|
}
|
|
568
|
-
const grid = el("div", { class: "
|
|
569
|
-
el("div", { class: "
|
|
570
|
-
el("div", { class: "
|
|
617
|
+
const grid = el("div", { class: "bd-or__grid" }, [
|
|
618
|
+
el("div", { class: "bd-or__side" }, [
|
|
619
|
+
el("div", { class: "bd-or__side-label" }, [
|
|
571
620
|
field.orConditionConfig?.leftLabel || "Option A",
|
|
572
621
|
]),
|
|
573
622
|
left ? renderTree([left], ctx, flat) : null,
|
|
574
623
|
]),
|
|
575
|
-
el("div", { class: "
|
|
576
|
-
el("span", { class: "
|
|
624
|
+
el("div", { class: "bd-or__divider" }, [
|
|
625
|
+
el("span", { class: "bd-or__badge" }, ["OR"]),
|
|
577
626
|
]),
|
|
578
|
-
el("div", { class: "
|
|
579
|
-
el("div", { class: "
|
|
627
|
+
el("div", { class: "bd-or__side" }, [
|
|
628
|
+
el("div", { class: "bd-or__side-label" }, [
|
|
580
629
|
field.orConditionConfig?.rightLabel || "Option B",
|
|
581
630
|
]),
|
|
582
631
|
right ? renderTree([right], ctx, flat) : null,
|
|
@@ -584,7 +633,7 @@ function renderTree(fields, ctx, flat) {
|
|
|
584
633
|
]);
|
|
585
634
|
box.append(grid);
|
|
586
635
|
if (errored) {
|
|
587
|
-
box.append(el("p", { class: "
|
|
636
|
+
box.append(el("p", { class: "bd-or__error" }, [
|
|
588
637
|
"Fill in at least one side to continue.",
|
|
589
638
|
]));
|
|
590
639
|
}
|
|
@@ -592,9 +641,9 @@ function renderTree(fields, ctx, flat) {
|
|
|
592
641
|
continue;
|
|
593
642
|
}
|
|
594
643
|
if (field.type === "flex_row") {
|
|
595
|
-
const row = el("div", { class: "
|
|
644
|
+
const row = el("div", { class: "bd-flex-row" }, []);
|
|
596
645
|
for (const child of (field.children ?? [])) {
|
|
597
|
-
row.append(el("div", { class: "
|
|
646
|
+
row.append(el("div", { class: "bd-flex-row__cell" }, [
|
|
598
647
|
renderFieldRow(child, ctx, flat),
|
|
599
648
|
]));
|
|
600
649
|
}
|
|
@@ -613,16 +662,16 @@ function renderProgress(snapshot, onJump) {
|
|
|
613
662
|
if (!settings.isConsecutive || !settings.showProgress || stepCount <= 1)
|
|
614
663
|
return null;
|
|
615
664
|
if (settings.progressStyle === "bar") {
|
|
616
|
-
const fill = el("div", { class: "
|
|
665
|
+
const fill = el("div", { class: "bd-progress__fill" });
|
|
617
666
|
fill.style.width = `${((step + 1) / stepCount) * 100}%`;
|
|
618
|
-
return el("div", { class: "
|
|
619
|
-
el("span", { class: "
|
|
667
|
+
return el("div", { class: "bd-progress bd-progress--bar" }, [
|
|
668
|
+
el("span", { class: "bd-progress__count" }, [
|
|
620
669
|
`${step + 1} / ${stepCount}`,
|
|
621
670
|
]),
|
|
622
|
-
el("div", { class: "
|
|
671
|
+
el("div", { class: "bd-progress__track" }, [fill]),
|
|
623
672
|
]);
|
|
624
673
|
}
|
|
625
|
-
const track = el("div", { class: "
|
|
674
|
+
const track = el("div", { class: "bd-progress__steps" });
|
|
626
675
|
steps.forEach((s, i) => {
|
|
627
676
|
const f = s[0];
|
|
628
677
|
const title = (typeof f?.stepTitle === "string" && f.stepTitle) ||
|
|
@@ -632,37 +681,37 @@ function renderProgress(snapshot, onJump) {
|
|
|
632
681
|
const current = i === step;
|
|
633
682
|
if (i > 0) {
|
|
634
683
|
track.append(el("div", {
|
|
635
|
-
class: classNames("
|
|
684
|
+
class: classNames("bd-progress__line", i <= step && "bd-progress__line--done"),
|
|
636
685
|
}));
|
|
637
686
|
}
|
|
638
687
|
const dot = el("span", {
|
|
639
|
-
class: classNames("
|
|
688
|
+
class: classNames("bd-progress__dot", current && "bd-progress__dot--current", done && "bd-progress__dot--done"),
|
|
640
689
|
}, [done ? "✓" : String(i + 1)]);
|
|
641
690
|
const stepNode = el("button", {
|
|
642
|
-
class: classNames("
|
|
691
|
+
class: classNames("bd-progress__step", current && "bd-progress__step--current"),
|
|
643
692
|
type: "button",
|
|
644
|
-
}, [dot, el("span", { class: "
|
|
693
|
+
}, [dot, el("span", { class: "bd-progress__title" }, [title])]);
|
|
645
694
|
stepNode.addEventListener("click", () => onJump(i));
|
|
646
695
|
track.append(stepNode);
|
|
647
696
|
});
|
|
648
|
-
return el("div", { class: "
|
|
649
|
-
el("div", { class: "
|
|
697
|
+
return el("div", { class: "bd-progress bd-progress--steps" }, [
|
|
698
|
+
el("div", { class: "bd-progress__heading" }, ["Form Progress"]),
|
|
650
699
|
track,
|
|
651
700
|
]);
|
|
652
701
|
}
|
|
653
702
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
654
|
-
//
|
|
703
|
+
// mountBdForm — wire a controller to a host element and render reactively.
|
|
655
704
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
656
705
|
function resolveHost(elOrSelector) {
|
|
657
706
|
const host = typeof elOrSelector === "string"
|
|
658
707
|
? document.querySelector(elOrSelector)
|
|
659
708
|
: elOrSelector;
|
|
660
709
|
if (!host) {
|
|
661
|
-
throw new Error(`
|
|
710
|
+
throw new Error(`mountBdForm: no element found for ${typeof elOrSelector === "string" ? `selector "${elOrSelector}"` : "the provided node"}.`);
|
|
662
711
|
}
|
|
663
712
|
return host;
|
|
664
713
|
}
|
|
665
|
-
export function
|
|
714
|
+
export function mountBdForm(elOrSelector, opts) {
|
|
666
715
|
const host = resolveHost(elOrSelector);
|
|
667
716
|
const extraClass = opts.class ?? opts.className;
|
|
668
717
|
// HTML autofill config built from the mount options, threaded to every field.
|
|
@@ -739,25 +788,25 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
739
788
|
}
|
|
740
789
|
function render(snapshot) {
|
|
741
790
|
const root = el("div", {
|
|
742
|
-
class: classNames("
|
|
743
|
-
"data-
|
|
791
|
+
class: classNames("bd-form", extraClass),
|
|
792
|
+
"data-bd-status": snapshot.status,
|
|
744
793
|
});
|
|
745
794
|
// Org icon (when the form opted into showOrgIcon).
|
|
746
795
|
if (snapshot.orgIcon) {
|
|
747
796
|
root.append(el("img", {
|
|
748
|
-
class: "
|
|
797
|
+
class: "bd-form__org-icon",
|
|
749
798
|
src: snapshot.orgIcon,
|
|
750
799
|
alt: "",
|
|
751
800
|
}));
|
|
752
801
|
}
|
|
753
802
|
// Loading / error states.
|
|
754
803
|
if (snapshot.status === "loading" || snapshot.status === "idle") {
|
|
755
|
-
root.append(el("div", { class: "
|
|
804
|
+
root.append(el("div", { class: "bd-form__loading" }, ["Loading…"]));
|
|
756
805
|
swap(root);
|
|
757
806
|
return;
|
|
758
807
|
}
|
|
759
808
|
if (snapshot.status === "error") {
|
|
760
|
-
root.append(el("div", { class: "
|
|
809
|
+
root.append(el("div", { class: "bd-form__error" }, [
|
|
761
810
|
snapshot.loadError || "Could not load this form.",
|
|
762
811
|
]));
|
|
763
812
|
swap(root);
|
|
@@ -765,21 +814,19 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
765
814
|
}
|
|
766
815
|
// Submitted confirmation.
|
|
767
816
|
if (snapshot.submitted) {
|
|
768
|
-
root.append(el("div", { class: "
|
|
769
|
-
el("p", { class: "
|
|
770
|
-
"Thanks — we got it.",
|
|
771
|
-
]),
|
|
817
|
+
root.append(el("div", { class: "bd-form__success" }, [
|
|
818
|
+
el("p", { class: "bd-form__success-title" }, ["Thanks — we got it."]),
|
|
772
819
|
]));
|
|
773
820
|
swap(root);
|
|
774
821
|
return;
|
|
775
822
|
}
|
|
776
823
|
// Header (title / description).
|
|
777
824
|
if (snapshot.title || snapshot.description) {
|
|
778
|
-
const header = el("div", { class: "
|
|
825
|
+
const header = el("div", { class: "bd-form__header" }, []);
|
|
779
826
|
if (snapshot.title)
|
|
780
|
-
header.append(el("h2", { class: "
|
|
827
|
+
header.append(el("h2", { class: "bd-form__title" }, [snapshot.title]));
|
|
781
828
|
if (snapshot.description) {
|
|
782
|
-
header.append(el("p", { class: "
|
|
829
|
+
header.append(el("p", { class: "bd-form__description" }, [snapshot.description]));
|
|
783
830
|
}
|
|
784
831
|
root.append(header);
|
|
785
832
|
}
|
|
@@ -789,11 +836,11 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
789
836
|
root.append(progress);
|
|
790
837
|
// Error summary banner.
|
|
791
838
|
if (snapshot.errorList.length > 0) {
|
|
792
|
-
root.append(el("div", { class: "
|
|
793
|
-
el("div", { class: "
|
|
839
|
+
root.append(el("div", { class: "bd-form__error-summary" }, [
|
|
840
|
+
el("div", { class: "bd-form__error-summary-title" }, [
|
|
794
841
|
`Please complete the highlighted required field${snapshot.errorList.length === 1 ? "" : "s"}.`,
|
|
795
842
|
]),
|
|
796
|
-
el("div", { class: "
|
|
843
|
+
el("div", { class: "bd-form__error-summary-list" }, [
|
|
797
844
|
snapshot.errorList.map((e) => e.label).join(", "),
|
|
798
845
|
]),
|
|
799
846
|
]));
|
|
@@ -810,13 +857,13 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
810
857
|
const flat = snapshot.settings.isConsecutive;
|
|
811
858
|
const stepWrap = el("div", {
|
|
812
859
|
class: animClass(snapshot.settings.animation, snapshot.forward),
|
|
813
|
-
"data-
|
|
860
|
+
"data-bd-step": String(snapshot.step),
|
|
814
861
|
});
|
|
815
862
|
if (snapshot.settings.animation === "scroll") {
|
|
816
863
|
// Reveal each top-level field on scroll. Class is the hook; CSS owns the
|
|
817
864
|
// transition. We add the visible state once it intersects.
|
|
818
865
|
for (const vf of snapshot.visibleFields) {
|
|
819
|
-
const reveal = el("div", { class: "
|
|
866
|
+
const reveal = el("div", { class: "bd-reveal" }, [
|
|
820
867
|
renderTree([vf], ctx, flat),
|
|
821
868
|
]);
|
|
822
869
|
stepWrap.append(reveal);
|
|
@@ -835,7 +882,7 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
835
882
|
const submitLabel = opts.submitLabel ?? "Submit";
|
|
836
883
|
if (snapshot.settings.isConsecutive && snapshot.stepCount > 1) {
|
|
837
884
|
const back = el("button", {
|
|
838
|
-
class: "
|
|
885
|
+
class: "bd-btn bd-btn--ghost bd-btn--back",
|
|
839
886
|
type: "button",
|
|
840
887
|
...(snapshot.isFirstStep ? { disabled: true } : {}),
|
|
841
888
|
}, ["Back"]);
|
|
@@ -843,7 +890,7 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
843
890
|
let advance;
|
|
844
891
|
if (!snapshot.isLastStep) {
|
|
845
892
|
advance = el("button", {
|
|
846
|
-
class: "
|
|
893
|
+
class: "bd-btn bd-btn--next",
|
|
847
894
|
type: "button",
|
|
848
895
|
...(snapshot.canAdvance ? {} : { disabled: true }),
|
|
849
896
|
}, ["Next"]);
|
|
@@ -851,21 +898,21 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
851
898
|
}
|
|
852
899
|
else {
|
|
853
900
|
advance = el("button", {
|
|
854
|
-
class: "
|
|
901
|
+
class: "bd-btn bd-btn--submit",
|
|
855
902
|
type: "button",
|
|
856
903
|
...(snapshot.submitting ? { disabled: true } : {}),
|
|
857
904
|
}, [snapshot.submitting ? "Sending…" : submitLabel]);
|
|
858
905
|
advance.addEventListener("click", () => void doSubmit());
|
|
859
906
|
}
|
|
860
|
-
return el("div", { class: "
|
|
907
|
+
return el("div", { class: "bd-nav" }, [back, advance]);
|
|
861
908
|
}
|
|
862
909
|
const submit = el("button", {
|
|
863
|
-
class: "
|
|
910
|
+
class: "bd-btn bd-btn--submit",
|
|
864
911
|
type: "button",
|
|
865
912
|
...(snapshot.submitting ? { disabled: true } : {}),
|
|
866
913
|
}, [snapshot.submitting ? "Sending…" : submitLabel]);
|
|
867
914
|
submit.addEventListener("click", () => void doSubmit());
|
|
868
|
-
return el("div", { class: "
|
|
915
|
+
return el("div", { class: "bd-nav" }, [submit]);
|
|
869
916
|
}
|
|
870
917
|
const unsubscribe = controller.subscribe(render);
|
|
871
918
|
// Initial paint + load (load() notifies, which re-renders).
|
|
@@ -883,16 +930,16 @@ export function mountBiabForm(elOrSelector, opts) {
|
|
|
883
930
|
},
|
|
884
931
|
};
|
|
885
932
|
}
|
|
886
|
-
/** Add the `
|
|
933
|
+
/** Add the `bd-reveal--shown` hook once an element scrolls into view (scroll anim). */
|
|
887
934
|
function observeReveal(node) {
|
|
888
935
|
if (typeof IntersectionObserver === "undefined") {
|
|
889
|
-
node.classList.add("
|
|
936
|
+
node.classList.add("bd-reveal--shown");
|
|
890
937
|
return;
|
|
891
938
|
}
|
|
892
939
|
const obs = new IntersectionObserver((entries) => {
|
|
893
940
|
for (const entry of entries) {
|
|
894
941
|
if (entry.isIntersecting) {
|
|
895
|
-
node.classList.add("
|
|
942
|
+
node.classList.add("bd-reveal--shown");
|
|
896
943
|
obs.disconnect();
|
|
897
944
|
break;
|
|
898
945
|
}
|
|
@@ -915,12 +962,12 @@ function observeReveal(node) {
|
|
|
915
962
|
// Remember to `destroy()` when the surface goes away.
|
|
916
963
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
917
964
|
import { createChatController, } from "./chat-core/index.js";
|
|
918
|
-
import {
|
|
965
|
+
import { BdApiClient as BdClientForSurfaces } from "./client.js";
|
|
919
966
|
import { createStoreController, } from "./store-core/index.js";
|
|
920
967
|
/** Headless storefront + cart. Call `load()` to populate it. */
|
|
921
968
|
export function createStorefront(options) {
|
|
922
969
|
return createStoreController({
|
|
923
|
-
client: new
|
|
970
|
+
client: new BdClientForSurfaces({
|
|
924
971
|
apiKey: options.apiKey,
|
|
925
972
|
baseUrl: options.baseUrl,
|
|
926
973
|
}),
|
|
@@ -932,7 +979,7 @@ export function createStorefront(options) {
|
|
|
932
979
|
/** Headless Front Desk chat — the native alternative to the iframe widget. */
|
|
933
980
|
export function createChat(options) {
|
|
934
981
|
return createChatController({
|
|
935
|
-
client: new
|
|
982
|
+
client: new BdClientForSurfaces({
|
|
936
983
|
apiKey: options.apiKey,
|
|
937
984
|
baseUrl: options.baseUrl,
|
|
938
985
|
}),
|
|
@@ -943,7 +990,7 @@ import { createBlogController, } from "./blog-core/index.js";
|
|
|
943
990
|
/** Headless blog — posts, taxonomy, a single post, comments and likes. */
|
|
944
991
|
export function createBlog(options) {
|
|
945
992
|
return createBlogController({
|
|
946
|
-
client: new
|
|
993
|
+
client: new BdClientForSurfaces({
|
|
947
994
|
apiKey: options.apiKey,
|
|
948
995
|
baseUrl: options.baseUrl,
|
|
949
996
|
}),
|
|
@@ -957,11 +1004,11 @@ export function createBlog(options) {
|
|
|
957
1004
|
}
|
|
958
1005
|
import { createFollowersController, createUserController, } from "./account-core/index.js";
|
|
959
1006
|
import { createCheckoutController, } from "./checkout-core/index.js";
|
|
960
|
-
import {
|
|
1007
|
+
import { createBdClient as createBdClientForFollowers } from "./sdk.js";
|
|
961
1008
|
/** Headless checkout — mint a Stripe session, then `redirect()` or render it. */
|
|
962
1009
|
export function createCheckout(options) {
|
|
963
1010
|
return createCheckoutController({
|
|
964
|
-
client: new
|
|
1011
|
+
client: new BdClientForSurfaces({
|
|
965
1012
|
apiKey: options.apiKey,
|
|
966
1013
|
baseUrl: options.baseUrl,
|
|
967
1014
|
}),
|
|
@@ -974,11 +1021,11 @@ export function createUser(options = {}) {
|
|
|
974
1021
|
}
|
|
975
1022
|
/** Newsletter / follower subscribe, bound to a publishable token. */
|
|
976
1023
|
export function createFollowers(options) {
|
|
977
|
-
// Followers hang off the PUBLISHABLE client (`
|
|
978
|
-
// `
|
|
1024
|
+
// Followers hang off the PUBLISHABLE client (`createBdClient`), not
|
|
1025
|
+
// `BdApiClient`: they are the one surface a browser calls directly with an
|
|
979
1026
|
// origin-locked `pk_…` token and no backend.
|
|
980
1027
|
return createFollowersController({
|
|
981
|
-
client:
|
|
1028
|
+
client: createBdClientForFollowers({
|
|
982
1029
|
apiKey: options.token,
|
|
983
1030
|
siteId: options.siteId,
|
|
984
1031
|
baseUrl: options.baseUrl ?? DEFAULT_PACKAGE_BASE_URL_FOR_SURFACES,
|
|
@@ -1001,7 +1048,7 @@ import { createVerifyController, } from "./verify-core/index.js";
|
|
|
1001
1048
|
*/
|
|
1002
1049
|
export function createMarketing(options) {
|
|
1003
1050
|
return createMarketingController({
|
|
1004
|
-
client:
|
|
1051
|
+
client: createBdClientForFollowers({
|
|
1005
1052
|
apiKey: options.token,
|
|
1006
1053
|
siteId: options.siteId,
|
|
1007
1054
|
baseUrl: options.baseUrl ?? DEFAULT_PACKAGE_BASE_URL_FOR_SURFACES,
|
|
@@ -1013,7 +1060,7 @@ export function createMarketing(options) {
|
|
|
1013
1060
|
export function createVerify(options) {
|
|
1014
1061
|
const { apiKey, baseUrl, ...rest } = options;
|
|
1015
1062
|
return createVerifyController({
|
|
1016
|
-
client: new
|
|
1063
|
+
client: new BdClientForSurfaces({ apiKey, baseUrl }),
|
|
1017
1064
|
...rest,
|
|
1018
1065
|
});
|
|
1019
1066
|
}
|
|
@@ -1025,7 +1072,7 @@ import { createPortalController, } from "./portal-core/index.js";
|
|
|
1025
1072
|
*/
|
|
1026
1073
|
export function createPortal(options) {
|
|
1027
1074
|
return createPortalController({
|
|
1028
|
-
client: new
|
|
1075
|
+
client: new BdClientForSurfaces({
|
|
1029
1076
|
apiKey: options.apiKey,
|
|
1030
1077
|
baseUrl: options.baseUrl,
|
|
1031
1078
|
}),
|