@kotao/storefront 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/dist/chunk-4OQYNUGM.js +29 -0
  2. package/dist/chunk-4OQYNUGM.js.map +1 -0
  3. package/dist/{chunk-7XYWHWT4.js → chunk-4TEFGD42.js} +331 -38
  4. package/dist/chunk-4TEFGD42.js.map +1 -0
  5. package/dist/chunk-7MTCGXIG.js +144 -0
  6. package/dist/chunk-7MTCGXIG.js.map +1 -0
  7. package/dist/chunk-IIOHENCG.js +239 -0
  8. package/dist/chunk-IIOHENCG.js.map +1 -0
  9. package/dist/chunk-VV653S52.js +246 -0
  10. package/dist/chunk-VV653S52.js.map +1 -0
  11. package/dist/chunk-WG7HYVHJ.js +38 -0
  12. package/dist/chunk-WG7HYVHJ.js.map +1 -0
  13. package/dist/{client-DiPdlvPu.d.ts → client-D51WdvYR.d.ts} +55 -8
  14. package/dist/client-bsiNPHBi.d.ts +159 -0
  15. package/dist/createCartHandler-C4RrPwSG.d.ts +58 -0
  16. package/dist/editor.d.ts +1 -1
  17. package/dist/events-react.d.ts +68 -0
  18. package/dist/events-react.js +557 -0
  19. package/dist/events-react.js.map +1 -0
  20. package/dist/events.d.ts +18 -0
  21. package/dist/events.js +5 -0
  22. package/dist/events.js.map +1 -0
  23. package/dist/{fetch-B6TIc6lI.d.ts → fetch-M3Y-fQrW.d.ts} +1 -1
  24. package/dist/forms.d.ts +58 -0
  25. package/dist/forms.js +3 -0
  26. package/dist/forms.js.map +1 -0
  27. package/dist/http-types-CGh8WGHB.d.ts +11 -0
  28. package/dist/index.d.ts +74 -12
  29. package/dist/index.js +55 -9
  30. package/dist/index.js.map +1 -1
  31. package/dist/offer-token-C-nk_nj8.d.ts +16 -0
  32. package/dist/{pagination-CPgH3fAa.d.ts → pagination-DCrQk02Q.d.ts} +1 -1
  33. package/dist/product.d.ts +1 -1
  34. package/dist/react-router.d.ts +11 -7
  35. package/dist/react-router.js +4 -3
  36. package/dist/react-router.js.map +1 -1
  37. package/dist/react.d.ts +30 -7
  38. package/dist/react.js +4 -2
  39. package/dist/react.js.map +1 -1
  40. package/dist/{routing-BxRlep_-.d.ts → routing-sEonP93J.d.ts} +17 -60
  41. package/dist/seo.d.ts +2 -1
  42. package/dist/settings.d.ts +5 -4
  43. package/dist/{shop-DkQmro-Y.d.ts → shop-BJSvtmnV.d.ts} +2 -2
  44. package/dist/{store-DQK1nhob.d.ts → store-CtCWHI8H.d.ts} +1 -1
  45. package/dist/types-CSNXbGFW.d.ts +108 -0
  46. package/dist/{types-Df3bGbKU.d.ts → types-bcbQzx87.d.ts} +1 -1
  47. package/package.json +14 -2
  48. package/dist/chunk-7XYWHWT4.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http-types.ts","../src/events/client.ts"],"names":[],"mappings":"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","file":"chunk-7MTCGXIG.js","sourcesContent":["/** Structural Headers-compatible value without depending on an ambient `HeadersInit` alias. */\nexport interface StorefrontHeadersLike {\n forEach(callback: (value: string, key: string) => void): void\n}\n\n/**\n * Header input accepted by storefront clients. This preserves the iterable and record shapes\n * accepted by the Web Headers constructor while remaining portable to Node-only declarations.\n */\nexport type StorefrontHeadersInit =\n | StorefrontHeadersLike\n | Iterable<Iterable<string>>\n | Record<string, string>\n\nfunction isHeadersLike(input: StorefrontHeadersInit): input is StorefrontHeadersLike {\n return 'forEach' in input && typeof input.forEach === 'function'\n}\n\nfunction isIterableHeaders(input: StorefrontHeadersInit): input is Iterable<Iterable<string>> {\n return Symbol.iterator in input && typeof input[Symbol.iterator] === 'function'\n}\n\nexport function normalizeStorefrontHeaders(input?: StorefrontHeadersInit): Headers {\n const headers = new Headers()\n if (input === undefined) return headers\n\n if (isIterableHeaders(input)) {\n for (const entry of input) {\n const pair = [...entry]\n if (pair.length !== 2) throw new TypeError('header entry must contain exactly two items')\n headers.append(pair[0]!, pair[1]!)\n }\n return headers\n }\n if (isHeadersLike(input)) {\n input.forEach((value, key) => headers.append(key, value))\n return headers\n }\n for (const [key, value] of Object.entries(input)) headers.append(key, value)\n return headers\n}\n","import type {\n ClaimEventApprovalOffer,\n CreateEventApprovalRequest,\n CreateEventCheckoutSession,\n CreateEventWaitlistEntry,\n EventApprovalOfferResolution,\n EventApprovalRequestReceipt,\n EventCheckoutSession,\n EventRegistrationResult,\n EventRegistrationSubmission,\n EventWaitlistReceipt,\n PublicEvent,\n} from './types'\nimport { normalizeStorefrontHeaders, type StorefrontHeadersInit } from '../http-types'\n\nexport interface EventsClient {\n getEvent(handle: string): Promise<PublicEvent>\n createCheckoutSession(\n handle: string,\n input: CreateEventCheckoutSession,\n idempotencyKey: string,\n ): Promise<EventCheckoutSession>\n submitApplication(\n handle: string,\n input: CreateEventApprovalRequest,\n idempotencyKey: string,\n ): Promise<EventApprovalRequestReceipt>\n joinWaitlist(handle: string, input: CreateEventWaitlistEntry): Promise<EventWaitlistReceipt>\n submitRegistration(input: EventRegistrationSubmission): Promise<EventRegistrationResult>\n resolveOffer(\n offerId: string,\n claimToken: string,\n idempotencyKey?: string,\n ): Promise<EventApprovalOfferResolution>\n claimOffer(\n offerId: string,\n input: ClaimEventApprovalOffer,\n idempotencyKey: string,\n ): Promise<EventCheckoutSession>\n}\n\nexport class StorefrontEventsRequestError extends Error {\n readonly status: number\n\n constructor(status: number) {\n super(`Events request failed with status ${status}`)\n this.name = 'StorefrontEventsRequestError'\n this.status = status\n }\n}\n\ninterface EventApprovalClaimResult {\n readonly checkoutSession: EventCheckoutSession\n}\n\nfunction cleanBaseUrl(baseUrl: string): string {\n const trimmed = baseUrl.trim().replace(/\\/+$/u, '')\n if (trimmed === '' || /[?#]/u.test(trimmed)) {\n throw new Error('Events base URL must not contain a query string or fragment')\n }\n return trimmed\n}\n\nfunction resource(value: string): string {\n return encodeURIComponent(value)\n}\n\nfunction requestHeaders(defaultHeaders: Headers, idempotencyKey?: string): Headers {\n const headers = new Headers(defaultHeaders)\n headers.set('content-type', 'application/json')\n if (idempotencyKey !== undefined) headers.set('idempotency-key', idempotencyKey)\n return headers\n}\n\nfunction resolutionIdempotencyKey(): string {\n return `events-resolve-${Date.now()}-${Math.random().toString(36).slice(2)}`\n}\n\nexport function createEventsClient(input: {\n readonly baseUrl: string\n readonly fetch: typeof globalThis.fetch\n readonly defaultHeaders?: StorefrontHeadersInit\n}): EventsClient {\n const baseUrl = cleanBaseUrl(input.baseUrl)\n const defaultHeaders = normalizeStorefrontHeaders(input.defaultHeaders)\n\n async function get<T>(path: string): Promise<T> {\n const headers = new Headers(defaultHeaders)\n headers.delete('content-type')\n const requestInit = {\n method: 'GET',\n headers,\n credentials: 'include',\n cache: 'no-store',\n referrerPolicy: 'no-referrer',\n } as RequestInit\n const response = await input.fetch(`${baseUrl}${path}`, requestInit)\n if (!response.ok) throw new StorefrontEventsRequestError(response.status)\n return (await response.json()) as T\n }\n\n async function post<T>(path: string, body: unknown, idempotencyKey?: string): Promise<T> {\n const requestInit = {\n method: 'POST',\n headers: requestHeaders(defaultHeaders, idempotencyKey),\n credentials: 'include',\n cache: 'no-store',\n referrerPolicy: 'no-referrer',\n body: JSON.stringify(body),\n } as RequestInit\n const response = await input.fetch(`${baseUrl}${path}`, requestInit)\n if (!response.ok) throw new StorefrontEventsRequestError(response.status)\n return (await response.json()) as T\n }\n\n const client: EventsClient = {\n getEvent: (handle) => get<PublicEvent>(`/events/${resource(handle)}`),\n createCheckoutSession: (handle, body, idempotencyKey) =>\n post<EventCheckoutSession>(\n `/events/${resource(handle)}/checkout-sessions`,\n body,\n idempotencyKey,\n ),\n submitApplication: (handle, body, idempotencyKey) =>\n post<EventApprovalRequestReceipt>(\n `/events/${resource(handle)}/approval-requests`,\n body,\n idempotencyKey,\n ),\n joinWaitlist: (handle, body) =>\n post<EventWaitlistReceipt>(`/events/${resource(handle)}/waitlist`, body),\n async submitRegistration(submission) {\n switch (submission.registrationMode) {\n case 'instant':\n return {\n kind: 'checkout',\n checkoutSession: await client.createCheckoutSession(\n submission.handle,\n submission.input,\n submission.idempotencyKey,\n ),\n }\n case 'approval_then_payment':\n return {\n kind: 'approval',\n receipt: await client.submitApplication(\n submission.handle,\n submission.input,\n submission.idempotencyKey,\n ),\n }\n case 'waitlist_only':\n return {\n kind: 'waitlist',\n receipt: await client.joinWaitlist(submission.handle, submission.input),\n }\n }\n },\n resolveOffer: (offerId, claimToken, idempotencyKey) =>\n post<EventApprovalOfferResolution>(\n `/events/approval-offers/${resource(offerId)}/resolve`,\n { claimToken },\n idempotencyKey ?? resolutionIdempotencyKey(),\n ),\n async claimOffer(offerId, body, idempotencyKey) {\n const claimed = await post<EventApprovalClaimResult>(\n `/events/approval-offers/${resource(offerId)}/claim`,\n body,\n idempotencyKey,\n )\n return claimed.checkoutSession\n },\n }\n return client\n}\n"]}
@@ -0,0 +1,239 @@
1
+ // src/forms/shared.ts
2
+ var FORM_ANSWER_PREFIX = "answers";
3
+ var ADDRESS_PROPERTIES = [
4
+ "line1",
5
+ "line2",
6
+ "city",
7
+ "postalCode",
8
+ "countryCode",
9
+ "provinceCode"
10
+ ];
11
+ function formAnswerName(fieldKey, property) {
12
+ return property === void 0 ? `${FORM_ANSWER_PREFIX}[${fieldKey}]` : `${FORM_ANSWER_PREFIX}[${fieldKey}][${property}]`;
13
+ }
14
+ function resolveFormText(value, locale, fallbackLocale = "en") {
15
+ if (value === void 0) return "";
16
+ return value[locale] ?? value[locale.split("-")[0]] ?? value[fallbackLocale] ?? Object.values(value)[0] ?? "";
17
+ }
18
+ function isEmpty(value) {
19
+ if (value === void 0 || value === "" || value === false) return true;
20
+ if (Array.isArray(value)) return value.length === 0;
21
+ if (typeof value === "object") return Object.values(value).every((item) => item === "");
22
+ return false;
23
+ }
24
+ function evaluateFormRule(rule, answers) {
25
+ const actual = answers[rule.fieldKey];
26
+ switch (rule.operator) {
27
+ case "is_empty":
28
+ return isEmpty(actual);
29
+ case "is_not_empty":
30
+ return !isEmpty(actual);
31
+ case "includes":
32
+ return Array.isArray(actual) && actual.includes(String(rule.value ?? ""));
33
+ case "equals":
34
+ return actual === rule.value;
35
+ case "not_equals":
36
+ return actual !== rule.value;
37
+ }
38
+ }
39
+ function isFormFieldVisible(field, answers) {
40
+ return field.visibleWhen?.all.every((rule) => evaluateFormRule(rule, answers)) ?? true;
41
+ }
42
+ function formFields(schema) {
43
+ return schema.pages.flatMap(
44
+ (page) => page.blocks.flatMap((block) => block.type === "field" ? [block.field] : [])
45
+ );
46
+ }
47
+ function parseFormAnswers(schema, data) {
48
+ const answers = {};
49
+ for (const field of formFields(schema)) {
50
+ const name = formAnswerName(field.key);
51
+ if (field.kind === "address") {
52
+ const address = Object.fromEntries(
53
+ ADDRESS_PROPERTIES.map((property) => [
54
+ property,
55
+ String(data.get(formAnswerName(field.key, property)) ?? "")
56
+ ]).filter(([, value]) => value !== "")
57
+ );
58
+ if (Object.keys(address).length > 0) answers[field.key] = address;
59
+ continue;
60
+ }
61
+ if (field.kind === "multi_select") {
62
+ const values = data.getAll(name).map(String);
63
+ if (values.length > 0) answers[field.key] = values;
64
+ continue;
65
+ }
66
+ if (field.kind === "checkbox" || field.kind === "consent") {
67
+ answers[field.key] = data.has(name);
68
+ continue;
69
+ }
70
+ const raw = data.get(name);
71
+ if (raw === null || raw === "") continue;
72
+ answers[field.key] = field.kind === "number" ? Number(raw) : String(raw);
73
+ }
74
+ return answers;
75
+ }
76
+
77
+ // src/forms/html.ts
78
+ function escapeHtml(value) {
79
+ return String(value).replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
80
+ }
81
+ function attrs(values) {
82
+ return Object.entries(values).filter(([, value]) => value !== void 0 && value !== false).map(([key, value]) => value === true ? key : `${key}="${escapeHtml(value)}"`).join(" ");
83
+ }
84
+ function scalarAnswer(value) {
85
+ return typeof value === "string" || typeof value === "number" ? String(value) : "";
86
+ }
87
+ function renderErrors(field, errors) {
88
+ if (errors.length === 0) return "";
89
+ return `<ul id="form-${escapeHtml(field.key)}-errors" data-kotao-form-errors>${errors.map((error) => `<li>${escapeHtml(error)}</li>`).join("")}</ul>`;
90
+ }
91
+ function renderChoices(field, locale, value) {
92
+ const selected = Array.isArray(value) ? value : [String(value ?? "")];
93
+ if (field.kind === "select" || field.kind === "multi_select") {
94
+ return `<select ${attrs({ id: `form-${field.key}`, name: formAnswerName(field.key), required: field.required, multiple: field.kind === "multi_select" })}>${field.choices?.map((choice) => `<option value="${escapeHtml(choice.value)}"${selected.includes(choice.value) ? " selected" : ""}>${escapeHtml(resolveFormText(choice.label, locale))}</option>`).join("") ?? ""}</select>`;
95
+ }
96
+ return `<div role="radiogroup">${field.choices?.map((choice) => `<label><input ${attrs({ type: "radio", name: formAnswerName(field.key), value: choice.value, required: field.required, checked: selected.includes(choice.value) })}> <span>${escapeHtml(resolveFormText(choice.label, locale))}</span></label>`).join("") ?? ""}</div>`;
97
+ }
98
+ function renderField(field, options) {
99
+ const { locale, answers = {}, errors = {} } = options;
100
+ if (!isFormFieldVisible(field, answers)) return "";
101
+ const value = answers[field.key];
102
+ const fieldErrors = errors[field.key] ?? [];
103
+ const id = `form-${field.key}`;
104
+ const label = resolveFormText(field.label, locale, options.fallbackLocale);
105
+ const describedBy = [field.description ? `${id}-description` : "", fieldErrors.length ? `${id}-errors` : ""].filter(Boolean).join(" ") || void 0;
106
+ let control;
107
+ if (field.kind === "textarea") {
108
+ control = `<textarea ${attrs({ id, name: formAnswerName(field.key), required: field.required, minlength: field.validation?.minLength, maxlength: field.validation?.maxLength, "aria-invalid": fieldErrors.length > 0 ? "true" : void 0, "aria-describedby": describedBy })}>${escapeHtml(scalarAnswer(value))}</textarea>`;
109
+ } else if (field.kind === "address") {
110
+ const address = typeof value === "object" && !Array.isArray(value) ? value : {};
111
+ control = `<fieldset><legend>${escapeHtml(label)}</legend>${ADDRESS_PROPERTIES.map((property) => `<label><span>${escapeHtml(property)}</span><input ${attrs({ name: formAnswerName(field.key, property), value: address[property] ?? "", required: field.required && ["line1", "postalCode", "city", "countryCode"].includes(property) })}></label>`).join("")}</fieldset>`;
112
+ } else if (field.kind === "select" || field.kind === "multi_select" || field.kind === "radio") {
113
+ control = renderChoices(field, locale, value);
114
+ } else if (field.kind === "checkbox" || field.kind === "consent") {
115
+ const text = field.kind === "consent" ? resolveFormText(field.consentText, locale) : label;
116
+ control = `<label><input ${attrs({ id, type: "checkbox", name: formAnswerName(field.key), value: "true", required: field.required, checked: value === true, "aria-invalid": fieldErrors.length > 0 ? "true" : void 0, "aria-describedby": describedBy })}> <span>${escapeHtml(text)}</span></label>`;
117
+ } else {
118
+ const type = field.kind === "phone" ? "tel" : field.kind;
119
+ control = `<input ${attrs({ id, type, name: formAnswerName(field.key), value: scalarAnswer(value), required: field.required, minlength: field.validation?.minLength, maxlength: field.validation?.maxLength, min: field.validation?.min, max: field.validation?.max, "aria-invalid": fieldErrors.length > 0 ? "true" : void 0, "aria-describedby": describedBy })}>`;
120
+ }
121
+ const visibleLabel = field.kind !== "address" && field.kind !== "checkbox" && field.kind !== "consent" ? `<label for="${escapeHtml(id)}">${escapeHtml(label)}${field.required ? ' <span aria-hidden="true">*</span>' : ""}</label>` : "";
122
+ const description = field.description ? `<p id="${escapeHtml(id)}-description">${escapeHtml(resolveFormText(field.description, locale))}</p>` : "";
123
+ return `<div data-kotao-form-field="${escapeHtml(field.key)}">${visibleLabel}${control}${description}${renderErrors(field, fieldErrors)}</div>`;
124
+ }
125
+ function renderFormHtml(form, options) {
126
+ const { schema } = form.version;
127
+ const success = options.submitted ? `<p role="status" data-kotao-form-success>${escapeHtml(resolveFormText(schema.successMessage, options.locale, options.fallbackLocale))}</p>` : "";
128
+ const pages = schema.pages.map(
129
+ (page) => `<section data-kotao-form-page="${escapeHtml(page.key)}">${page.title ? `<h2>${escapeHtml(resolveFormText(page.title, options.locale, options.fallbackLocale))}</h2>` : ""}${page.description ? `<p>${escapeHtml(resolveFormText(page.description, options.locale, options.fallbackLocale))}</p>` : ""}${page.blocks.map((block) => block.type === "field" ? renderField(block.field, options) : block.type === "section" ? `<header><h3>${escapeHtml(resolveFormText(block.title, options.locale, options.fallbackLocale))}</h3>${block.description ? `<p>${escapeHtml(resolveFormText(block.description, options.locale, options.fallbackLocale))}</p>` : ""}</header>` : `<div data-kotao-form-content>${escapeHtml(resolveFormText(block.content, options.locale, options.fallbackLocale))}</div>`).join("")}</section>`
130
+ ).join("");
131
+ const idempotencyInput = options.idempotencyKey ? `<input type="hidden" name="idempotencyKey" value="${escapeHtml(options.idempotencyKey)}">` : "";
132
+ const honeypot = options.honeypotName ? `<div hidden aria-hidden="true"><label>Leave this field empty<input type="text" name="${escapeHtml(options.honeypotName)}" tabindex="-1" autocomplete="off"></label></div>` : "";
133
+ return `<form ${attrs({ method: "post", action: options.action ?? "", class: options.formClass, "data-kotao-form": form.definition.handle })}><input type="hidden" name="versionId" value="${escapeHtml(form.version.id)}"><input type="hidden" name="locale" value="${escapeHtml(options.locale)}">${idempotencyInput}${honeypot}${success}${pages}<button type="submit">${escapeHtml(resolveFormText(schema.submitLabel, options.locale, options.fallbackLocale) || "Submit")}</button></form>`;
134
+ }
135
+
136
+ // src/forms/client.ts
137
+ var StorefrontFormRequestError = class extends Error {
138
+ status;
139
+ fieldErrors;
140
+ constructor(status, message, fieldErrors = {}) {
141
+ super(message);
142
+ this.name = "StorefrontFormRequestError";
143
+ this.status = status;
144
+ this.fieldErrors = fieldErrors;
145
+ }
146
+ };
147
+ function endpoint(baseUrl, handle, suffix = "") {
148
+ const base = (baseUrl ?? "/api/storefront").replace(/\/$/, "");
149
+ return `${base}/forms/${encodeURIComponent(handle)}${suffix}`;
150
+ }
151
+ async function requestError(response) {
152
+ let body = {};
153
+ try {
154
+ body = await response.json();
155
+ } catch {
156
+ }
157
+ return new StorefrontFormRequestError(
158
+ response.status,
159
+ body.error ?? `Form request failed with status ${response.status}`,
160
+ body.fieldErrors
161
+ );
162
+ }
163
+ async function loadPublishedForm(handle, options = {}) {
164
+ const fetcher = options.fetch ?? fetch;
165
+ const response = await fetcher(endpoint(options.apiBaseUrl, handle), {
166
+ method: "GET",
167
+ ...options.headers !== void 0 ? { headers: options.headers } : {},
168
+ ...options.signal !== void 0 ? { signal: options.signal } : {}
169
+ });
170
+ if (!response.ok) throw await requestError(response);
171
+ return await response.json();
172
+ }
173
+ async function submitPublishedForm(handle, input) {
174
+ const fetcher = input.fetch ?? fetch;
175
+ const headers = new Headers(input.headers);
176
+ headers.set("content-type", "application/json");
177
+ headers.set("idempotency-key", input.idempotencyKey ?? crypto.randomUUID());
178
+ const response = await fetcher(endpoint(input.apiBaseUrl, handle, "/submissions"), {
179
+ method: "POST",
180
+ headers,
181
+ ...input.signal !== void 0 ? { signal: input.signal } : {},
182
+ body: JSON.stringify({
183
+ versionId: input.versionId,
184
+ locale: input.locale,
185
+ answers: input.answers
186
+ })
187
+ });
188
+ if (!response.ok) throw await requestError(response);
189
+ return await response.json();
190
+ }
191
+
192
+ // src/forms/shopify-contact.ts
193
+ var STANDARD_FIELD_KINDS = {
194
+ name: ["text"],
195
+ email: ["email", "text"],
196
+ body: ["textarea", "text"],
197
+ phone: ["phone", "text"]
198
+ };
199
+ function inputValue(input, key) {
200
+ switch (key) {
201
+ case "name":
202
+ return input.name;
203
+ case "email":
204
+ return input.email;
205
+ case "body":
206
+ return input.body;
207
+ case "phone":
208
+ return input.phone;
209
+ default:
210
+ return void 0;
211
+ }
212
+ }
213
+ function adaptShopifyContactForm(form, input) {
214
+ if (form.definition.purpose !== "contact") {
215
+ return { compatible: false, reason: "not-contact-purpose" };
216
+ }
217
+ const fields = formFields(form.version.schema);
218
+ for (const field of fields) {
219
+ const supportedKinds = STANDARD_FIELD_KINDS[field.key];
220
+ if (supportedKinds === void 0) {
221
+ if (field.required) return { compatible: false, reason: "unsupported-required-field" };
222
+ continue;
223
+ }
224
+ if (!supportedKinds.includes(field.kind)) {
225
+ return { compatible: false, reason: "incompatible-standard-field" };
226
+ }
227
+ }
228
+ const answers = {};
229
+ for (const field of fields) {
230
+ if (STANDARD_FIELD_KINDS[field.key] === void 0) continue;
231
+ const value = inputValue(input, field.key);
232
+ if (value !== void 0 && value !== null) answers[field.key] = value;
233
+ }
234
+ return { compatible: true, answers };
235
+ }
236
+
237
+ export { ADDRESS_PROPERTIES, FORM_ANSWER_PREFIX, StorefrontFormRequestError, adaptShopifyContactForm, evaluateFormRule, formAnswerName, formFields, isFormFieldVisible, loadPublishedForm, parseFormAnswers, renderFormHtml, resolveFormText, submitPublishedForm };
238
+ //# sourceMappingURL=chunk-IIOHENCG.js.map
239
+ //# sourceMappingURL=chunk-IIOHENCG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/forms/shared.ts","../src/forms/html.ts","../src/forms/client.ts","../src/forms/shopify-contact.ts"],"names":[],"mappings":"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","file":"chunk-IIOHENCG.js","sourcesContent":["import type {\n FormAnswer,\n FormAnswers,\n FormField,\n FormLocalizedText,\n FormVersionSchema,\n FormVisibilityRule,\n} from './types'\n\nexport const FORM_ANSWER_PREFIX = 'answers'\nexport const ADDRESS_PROPERTIES = [\n 'line1',\n 'line2',\n 'city',\n 'postalCode',\n 'countryCode',\n 'provinceCode',\n] as const\n\nexport function formAnswerName(fieldKey: string, property?: string): string {\n return property === undefined\n ? `${FORM_ANSWER_PREFIX}[${fieldKey}]`\n : `${FORM_ANSWER_PREFIX}[${fieldKey}][${property}]`\n}\n\nexport function resolveFormText(\n value: FormLocalizedText | undefined,\n locale: string,\n fallbackLocale = 'en',\n): string {\n if (value === undefined) return ''\n return (\n value[locale] ??\n value[locale.split('-')[0]!] ??\n value[fallbackLocale] ??\n Object.values(value)[0] ??\n ''\n )\n}\n\nfunction isEmpty(value: FormAnswer | undefined): boolean {\n if (value === undefined || value === '' || value === false) return true\n if (Array.isArray(value)) return value.length === 0\n if (typeof value === 'object') return Object.values(value).every((item) => item === '')\n return false\n}\n\nexport function evaluateFormRule(rule: FormVisibilityRule, answers: FormAnswers): boolean {\n const actual = answers[rule.fieldKey]\n switch (rule.operator) {\n case 'is_empty':\n return isEmpty(actual)\n case 'is_not_empty':\n return !isEmpty(actual)\n case 'includes':\n return Array.isArray(actual) && actual.includes(String(rule.value ?? ''))\n case 'equals':\n return actual === rule.value\n case 'not_equals':\n return actual !== rule.value\n }\n}\n\nexport function isFormFieldVisible(field: FormField, answers: FormAnswers): boolean {\n return field.visibleWhen?.all.every((rule) => evaluateFormRule(rule, answers)) ?? true\n}\n\nexport function formFields(schema: FormVersionSchema): FormField[] {\n return schema.pages.flatMap((page) =>\n page.blocks.flatMap((block) => (block.type === 'field' ? [block.field] : [])),\n )\n}\n\nexport function parseFormAnswers(schema: FormVersionSchema, data: FormData): FormAnswers {\n const answers: FormAnswers = {}\n for (const field of formFields(schema)) {\n const name = formAnswerName(field.key)\n if (field.kind === 'address') {\n const address = Object.fromEntries(\n ADDRESS_PROPERTIES.map((property) => [\n property,\n String(data.get(formAnswerName(field.key, property)) ?? ''),\n ]).filter(([, value]) => value !== ''),\n )\n if (Object.keys(address).length > 0) answers[field.key] = address\n continue\n }\n if (field.kind === 'multi_select') {\n const values = data.getAll(name).map(String)\n if (values.length > 0) answers[field.key] = values\n continue\n }\n if (field.kind === 'checkbox' || field.kind === 'consent') {\n answers[field.key] = data.has(name)\n continue\n }\n const raw = data.get(name)\n if (raw === null || raw === '') continue\n answers[field.key] = field.kind === 'number' ? Number(raw) : String(raw)\n }\n return answers\n}\n","import { ADDRESS_PROPERTIES, formAnswerName, isFormFieldVisible, resolveFormText } from './shared'\nimport type { FormAnswer, FormField, FormRenderState, PublicForm } from './types'\n\nexport interface RenderFormHtmlOptions extends FormRenderState {\n locale: string\n action?: string\n formClass?: string\n fallbackLocale?: string\n idempotencyKey?: string\n honeypotName?: string\n}\n\nfunction escapeHtml(value: unknown): string {\n return String(value)\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;')\n}\n\nfunction attrs(values: Record<string, string | number | boolean | undefined>): string {\n return Object.entries(values)\n .filter(([, value]) => value !== undefined && value !== false)\n .map(([key, value]) => (value === true ? key : `${key}=\"${escapeHtml(value)}\"`))\n .join(' ')\n}\n\nfunction scalarAnswer(value: FormAnswer | undefined): string {\n return typeof value === 'string' || typeof value === 'number' ? String(value) : ''\n}\n\nfunction renderErrors(field: FormField, errors: string[]): string {\n if (errors.length === 0) return ''\n return `<ul id=\"form-${escapeHtml(field.key)}-errors\" data-kotao-form-errors>${errors.map((error) => `<li>${escapeHtml(error)}</li>`).join('')}</ul>`\n}\n\nfunction renderChoices(field: FormField, locale: string, value: FormAnswer | undefined): string {\n const selected = Array.isArray(value) ? value : [String(value ?? '')]\n if (field.kind === 'select' || field.kind === 'multi_select') {\n return `<select ${attrs({ id: `form-${field.key}`, name: formAnswerName(field.key), required: field.required, multiple: field.kind === 'multi_select' })}>${field.choices?.map((choice) => `<option value=\"${escapeHtml(choice.value)}\"${selected.includes(choice.value) ? ' selected' : ''}>${escapeHtml(resolveFormText(choice.label, locale))}</option>`).join('') ?? ''}</select>`\n }\n return `<div role=\"radiogroup\">${field.choices?.map((choice) => `<label><input ${attrs({ type: 'radio', name: formAnswerName(field.key), value: choice.value, required: field.required, checked: selected.includes(choice.value) })}> <span>${escapeHtml(resolveFormText(choice.label, locale))}</span></label>`).join('') ?? ''}</div>`\n}\n\nfunction renderField(field: FormField, options: RenderFormHtmlOptions): string {\n const { locale, answers = {}, errors = {} } = options\n if (!isFormFieldVisible(field, answers)) return ''\n const value = answers[field.key]\n const fieldErrors = errors[field.key] ?? []\n const id = `form-${field.key}`\n const label = resolveFormText(field.label, locale, options.fallbackLocale)\n const describedBy =\n [field.description ? `${id}-description` : '', fieldErrors.length ? `${id}-errors` : '']\n .filter(Boolean)\n .join(' ') || undefined\n let control: string\n if (field.kind === 'textarea') {\n control = `<textarea ${attrs({ id, name: formAnswerName(field.key), required: field.required, minlength: field.validation?.minLength, maxlength: field.validation?.maxLength, 'aria-invalid': fieldErrors.length > 0 ? 'true' : undefined, 'aria-describedby': describedBy })}>${escapeHtml(scalarAnswer(value))}</textarea>`\n } else if (field.kind === 'address') {\n const address = typeof value === 'object' && !Array.isArray(value) ? value : {}\n control = `<fieldset><legend>${escapeHtml(label)}</legend>${ADDRESS_PROPERTIES.map((property) => `<label><span>${escapeHtml(property)}</span><input ${attrs({ name: formAnswerName(field.key, property), value: address[property] ?? '', required: field.required && ['line1', 'postalCode', 'city', 'countryCode'].includes(property) })}></label>`).join('')}</fieldset>`\n } else if (field.kind === 'select' || field.kind === 'multi_select' || field.kind === 'radio') {\n control = renderChoices(field, locale, value)\n } else if (field.kind === 'checkbox' || field.kind === 'consent') {\n const text = field.kind === 'consent' ? resolveFormText(field.consentText, locale) : label\n control = `<label><input ${attrs({ id, type: 'checkbox', name: formAnswerName(field.key), value: 'true', required: field.required, checked: value === true, 'aria-invalid': fieldErrors.length > 0 ? 'true' : undefined, 'aria-describedby': describedBy })}> <span>${escapeHtml(text)}</span></label>`\n } else {\n const type = field.kind === 'phone' ? 'tel' : field.kind\n control = `<input ${attrs({ id, type, name: formAnswerName(field.key), value: scalarAnswer(value), required: field.required, minlength: field.validation?.minLength, maxlength: field.validation?.maxLength, min: field.validation?.min, max: field.validation?.max, 'aria-invalid': fieldErrors.length > 0 ? 'true' : undefined, 'aria-describedby': describedBy })}>`\n }\n const visibleLabel =\n field.kind !== 'address' && field.kind !== 'checkbox' && field.kind !== 'consent'\n ? `<label for=\"${escapeHtml(id)}\">${escapeHtml(label)}${field.required ? ' <span aria-hidden=\"true\">*</span>' : ''}</label>`\n : ''\n const description = field.description\n ? `<p id=\"${escapeHtml(id)}-description\">${escapeHtml(resolveFormText(field.description, locale))}</p>`\n : ''\n return `<div data-kotao-form-field=\"${escapeHtml(field.key)}\">${visibleLabel}${control}${description}${renderErrors(field, fieldErrors)}</div>`\n}\n\nexport function renderFormHtml(form: PublicForm, options: RenderFormHtmlOptions): string {\n const { schema } = form.version\n const success = options.submitted\n ? `<p role=\"status\" data-kotao-form-success>${escapeHtml(resolveFormText(schema.successMessage, options.locale, options.fallbackLocale))}</p>`\n : ''\n const pages = schema.pages\n .map(\n (page) =>\n `<section data-kotao-form-page=\"${escapeHtml(page.key)}\">${page.title ? `<h2>${escapeHtml(resolveFormText(page.title, options.locale, options.fallbackLocale))}</h2>` : ''}${page.description ? `<p>${escapeHtml(resolveFormText(page.description, options.locale, options.fallbackLocale))}</p>` : ''}${page.blocks.map((block) => (block.type === 'field' ? renderField(block.field, options) : block.type === 'section' ? `<header><h3>${escapeHtml(resolveFormText(block.title, options.locale, options.fallbackLocale))}</h3>${block.description ? `<p>${escapeHtml(resolveFormText(block.description, options.locale, options.fallbackLocale))}</p>` : ''}</header>` : `<div data-kotao-form-content>${escapeHtml(resolveFormText(block.content, options.locale, options.fallbackLocale))}</div>`)).join('')}</section>`,\n )\n .join('')\n const idempotencyInput = options.idempotencyKey\n ? `<input type=\"hidden\" name=\"idempotencyKey\" value=\"${escapeHtml(options.idempotencyKey)}\">`\n : ''\n const honeypot = options.honeypotName\n ? `<div hidden aria-hidden=\"true\"><label>Leave this field empty<input type=\"text\" name=\"${escapeHtml(options.honeypotName)}\" tabindex=\"-1\" autocomplete=\"off\"></label></div>`\n : ''\n return `<form ${attrs({ method: 'post', action: options.action ?? '', class: options.formClass, 'data-kotao-form': form.definition.handle })}><input type=\"hidden\" name=\"versionId\" value=\"${escapeHtml(form.version.id)}\"><input type=\"hidden\" name=\"locale\" value=\"${escapeHtml(options.locale)}\">${idempotencyInput}${honeypot}${success}${pages}<button type=\"submit\">${escapeHtml(resolveFormText(schema.submitLabel, options.locale, options.fallbackLocale) || 'Submit')}</button></form>`\n}\n","import type { FormAnswers, FormFieldErrors, FormSubmission, PublicForm } from './types'\n\nexport interface FormFetchOptions {\n fetch?: typeof fetch\n apiBaseUrl?: string\n headers?: ConstructorParameters<typeof Headers>[0]\n signal?: AbortSignal\n}\n\nexport interface SubmitFormInput extends FormFetchOptions {\n versionId: string\n locale: string\n answers: FormAnswers\n idempotencyKey?: string\n}\n\nexport class StorefrontFormRequestError extends Error {\n readonly status: number\n readonly fieldErrors: FormFieldErrors\n\n constructor(status: number, message: string, fieldErrors: FormFieldErrors = {}) {\n super(message)\n this.name = 'StorefrontFormRequestError'\n this.status = status\n this.fieldErrors = fieldErrors\n }\n}\n\nfunction endpoint(baseUrl: string | undefined, handle: string, suffix = ''): string {\n const base = (baseUrl ?? '/api/storefront').replace(/\\/$/, '')\n return `${base}/forms/${encodeURIComponent(handle)}${suffix}`\n}\n\nasync function requestError(response: Response): Promise<StorefrontFormRequestError> {\n let body: { error?: string; fieldErrors?: FormFieldErrors } = {}\n try {\n body = (await response.json()) as typeof body\n } catch {\n // A non-JSON proxy error still becomes one stable SDK error.\n }\n return new StorefrontFormRequestError(\n response.status,\n body.error ?? `Form request failed with status ${response.status}`,\n body.fieldErrors,\n )\n}\n\nexport async function loadPublishedForm(\n handle: string,\n options: FormFetchOptions = {},\n): Promise<PublicForm> {\n const fetcher = options.fetch ?? fetch\n const response = await fetcher(endpoint(options.apiBaseUrl, handle), {\n method: 'GET',\n ...(options.headers !== undefined ? { headers: options.headers } : {}),\n ...(options.signal !== undefined ? { signal: options.signal } : {}),\n })\n if (!response.ok) throw await requestError(response)\n return (await response.json()) as PublicForm\n}\n\nexport async function submitPublishedForm(\n handle: string,\n input: SubmitFormInput,\n): Promise<FormSubmission> {\n const fetcher = input.fetch ?? fetch\n const headers = new Headers(input.headers)\n headers.set('content-type', 'application/json')\n headers.set('idempotency-key', input.idempotencyKey ?? crypto.randomUUID())\n const response = await fetcher(endpoint(input.apiBaseUrl, handle, '/submissions'), {\n method: 'POST',\n headers,\n ...(input.signal !== undefined ? { signal: input.signal } : {}),\n body: JSON.stringify({\n versionId: input.versionId,\n locale: input.locale,\n answers: input.answers,\n }),\n })\n if (!response.ok) throw await requestError(response)\n return (await response.json()) as FormSubmission\n}\n","import { formFields } from './shared'\nimport type { FormAnswers, FormField, PublicForm } from './types'\n\nexport interface ShopifyContactInput {\n readonly name?: string | null\n readonly email: string\n readonly body: string\n readonly phone?: string | null\n}\n\nexport type ShopifyContactCompatibility =\n | { readonly compatible: true; readonly answers: FormAnswers }\n | {\n readonly compatible: false\n readonly reason:\n | 'not-contact-purpose'\n | 'unsupported-required-field'\n | 'incompatible-standard-field'\n }\n\nconst STANDARD_FIELD_KINDS: Readonly<Record<string, readonly FormField['kind'][]>> = {\n name: ['text'],\n email: ['email', 'text'],\n body: ['textarea', 'text'],\n phone: ['phone', 'text'],\n}\n\nfunction inputValue(input: ShopifyContactInput, key: string): string | null | undefined {\n switch (key) {\n case 'name':\n return input.name\n case 'email':\n return input.email\n case 'body':\n return input.body\n case 'phone':\n return input.phone\n default:\n return undefined\n }\n}\n\nexport function adaptShopifyContactForm(\n form: PublicForm,\n input: ShopifyContactInput,\n): ShopifyContactCompatibility {\n if (form.definition.purpose !== 'contact') {\n return { compatible: false, reason: 'not-contact-purpose' }\n }\n\n const fields = formFields(form.version.schema)\n for (const field of fields) {\n const supportedKinds = STANDARD_FIELD_KINDS[field.key]\n if (supportedKinds === undefined) {\n if (field.required) return { compatible: false, reason: 'unsupported-required-field' }\n continue\n }\n if (!supportedKinds.includes(field.kind)) {\n return { compatible: false, reason: 'incompatible-standard-field' }\n }\n }\n\n const answers: FormAnswers = {}\n for (const field of fields) {\n if (STANDARD_FIELD_KINDS[field.key] === undefined) continue\n const value = inputValue(input, field.key)\n if (value !== undefined && value !== null) answers[field.key] = value\n }\n return { compatible: true, answers }\n}\n"]}
@@ -0,0 +1,246 @@
1
+ import { resolveFormText, isFormFieldVisible, formAnswerName, ADDRESS_PROPERTIES, formFields } from './chunk-IIOHENCG.js';
2
+ import { useState, useId } from 'react';
3
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
+
5
+ var ADDRESS_LABELS = {
6
+ line1: "Address",
7
+ line2: "Address line 2",
8
+ city: "City",
9
+ postalCode: "Postal code",
10
+ countryCode: "Country code",
11
+ provinceCode: "Province or state code"
12
+ };
13
+ function FieldErrors({ id, errors }) {
14
+ if (errors.length === 0) return null;
15
+ return /* @__PURE__ */ jsx("ul", { id, "data-kotao-form-errors": true, children: errors.map((error, index) => /* @__PURE__ */ jsx("li", { children: error }, `${error}-${index}`)) });
16
+ }
17
+ function StorefrontFormField({
18
+ field,
19
+ locale,
20
+ fallbackLocale,
21
+ value,
22
+ errors,
23
+ onChange,
24
+ idPrefix
25
+ }) {
26
+ const id = `${idPrefix}-form-${field.key}`;
27
+ const label = resolveFormText(field.label, locale, fallbackLocale);
28
+ const description = resolveFormText(field.description, locale, fallbackLocale);
29
+ const errorId = `${id}-errors`;
30
+ const descriptionId = `${id}-description`;
31
+ const describedBy = [description ? descriptionId : "", errors.length ? errorId : ""].filter(Boolean).join(" ");
32
+ const common = {
33
+ id,
34
+ name: formAnswerName(field.key),
35
+ required: field.required,
36
+ "aria-invalid": errors.length > 0 || void 0,
37
+ "aria-describedby": describedBy || void 0
38
+ };
39
+ let control;
40
+ if (field.kind === "textarea") {
41
+ control = /* @__PURE__ */ jsx(
42
+ "textarea",
43
+ {
44
+ ...common,
45
+ value: typeof value === "string" ? value : "",
46
+ minLength: field.validation?.minLength,
47
+ maxLength: field.validation?.maxLength,
48
+ onChange: (event) => onChange(event.currentTarget.value)
49
+ }
50
+ );
51
+ } else if (field.kind === "address") {
52
+ const address = typeof value === "object" && !Array.isArray(value) ? value : {};
53
+ control = /* @__PURE__ */ jsxs("fieldset", { "aria-describedby": describedBy || void 0, children: [
54
+ /* @__PURE__ */ jsxs("legend", { children: [
55
+ label,
56
+ field.required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " *" })
57
+ ] }),
58
+ ADDRESS_PROPERTIES.map((property) => /* @__PURE__ */ jsxs("label", { children: [
59
+ /* @__PURE__ */ jsx("span", { children: ADDRESS_LABELS[property] }),
60
+ /* @__PURE__ */ jsx(
61
+ "input",
62
+ {
63
+ name: formAnswerName(field.key, property),
64
+ value: address[property] ?? "",
65
+ required: field.required && ["line1", "postalCode", "city", "countryCode"].includes(property),
66
+ onChange: (event) => onChange({ ...address, [property]: event.currentTarget.value })
67
+ }
68
+ )
69
+ ] }, property))
70
+ ] });
71
+ } else if (field.kind === "select" || field.kind === "multi_select") {
72
+ const selected = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
73
+ control = /* @__PURE__ */ jsxs(
74
+ "select",
75
+ {
76
+ ...common,
77
+ multiple: field.kind === "multi_select",
78
+ value: field.kind === "multi_select" ? selected : selected[0] ?? "",
79
+ onChange: (event) => onChange(
80
+ field.kind === "multi_select" ? Array.from(event.currentTarget.selectedOptions, (option) => option.value) : event.currentTarget.value
81
+ ),
82
+ children: [
83
+ field.kind === "select" && /* @__PURE__ */ jsx("option", { value: "" }),
84
+ field.choices?.map((choice) => /* @__PURE__ */ jsx("option", { value: choice.value, children: resolveFormText(choice.label, locale, fallbackLocale) }, choice.value))
85
+ ]
86
+ }
87
+ );
88
+ } else if (field.kind === "radio") {
89
+ control = /* @__PURE__ */ jsx("div", { role: "radiogroup", "aria-describedby": describedBy || void 0, children: field.choices?.map((choice) => /* @__PURE__ */ jsxs("label", { children: [
90
+ /* @__PURE__ */ jsx(
91
+ "input",
92
+ {
93
+ type: "radio",
94
+ name: common.name,
95
+ value: choice.value,
96
+ required: field.required,
97
+ checked: value === choice.value,
98
+ onChange: (event) => {
99
+ if (event.currentTarget.checked) onChange(choice.value);
100
+ }
101
+ }
102
+ ),
103
+ /* @__PURE__ */ jsx("span", { children: resolveFormText(choice.label, locale, fallbackLocale) })
104
+ ] }, choice.value)) });
105
+ } else if (field.kind === "checkbox" || field.kind === "consent") {
106
+ control = /* @__PURE__ */ jsxs("label", { children: [
107
+ /* @__PURE__ */ jsx(
108
+ "input",
109
+ {
110
+ ...common,
111
+ type: "checkbox",
112
+ value: "true",
113
+ checked: value === true,
114
+ onChange: (event) => onChange(event.currentTarget.checked)
115
+ }
116
+ ),
117
+ /* @__PURE__ */ jsx("span", { children: field.kind === "consent" ? resolveFormText(field.consentText, locale, fallbackLocale) : label })
118
+ ] });
119
+ } else {
120
+ control = /* @__PURE__ */ jsx(
121
+ "input",
122
+ {
123
+ ...common,
124
+ type: field.kind === "phone" ? "tel" : field.kind,
125
+ value: typeof value === "string" || typeof value === "number" ? value : "",
126
+ minLength: field.validation?.minLength,
127
+ maxLength: field.validation?.maxLength,
128
+ min: field.validation?.min,
129
+ max: field.validation?.max,
130
+ onChange: (event) => onChange(
131
+ field.kind === "number" && event.currentTarget.value !== "" ? event.currentTarget.valueAsNumber : event.currentTarget.value
132
+ )
133
+ }
134
+ );
135
+ }
136
+ const hasSeparateLabel = !["address", "checkbox", "consent"].includes(field.kind);
137
+ return /* @__PURE__ */ jsxs("div", { "data-kotao-form-field": field.key, children: [
138
+ hasSeparateLabel && /* @__PURE__ */ jsxs("label", { htmlFor: id, children: [
139
+ label,
140
+ field.required && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: " *" })
141
+ ] }),
142
+ control,
143
+ description && /* @__PURE__ */ jsx("p", { id: descriptionId, children: description }),
144
+ /* @__PURE__ */ jsx(FieldErrors, { id: errorId, errors })
145
+ ] });
146
+ }
147
+ function StorefrontFormFields({
148
+ form,
149
+ locale,
150
+ fallbackLocale,
151
+ answers: initialAnswers = {},
152
+ errors = {},
153
+ onAnswersChange,
154
+ idPrefix
155
+ }) {
156
+ const [answers, setAnswers] = useState(initialAnswers);
157
+ const generatedId = useId();
158
+ const instanceId = idPrefix ?? `kotao-${generatedId.replaceAll(":", "")}`;
159
+ const schema = form.version.schema;
160
+ function pruneHiddenAnswers(nextAnswers) {
161
+ let pruned = nextAnswers;
162
+ let removed = true;
163
+ while (removed) {
164
+ removed = false;
165
+ for (const field of formFields(schema)) {
166
+ if (Object.hasOwn(pruned, field.key) && !isFormFieldVisible(field, pruned)) {
167
+ if (pruned === nextAnswers) pruned = { ...nextAnswers };
168
+ delete pruned[field.key];
169
+ removed = true;
170
+ }
171
+ }
172
+ }
173
+ return pruned;
174
+ }
175
+ function updateAnswer(key, answer) {
176
+ setAnswers((current) => {
177
+ const next = pruneHiddenAnswers({ ...current, [key]: answer });
178
+ onAnswersChange?.(next);
179
+ return next;
180
+ });
181
+ }
182
+ return /* @__PURE__ */ jsx(Fragment, { children: schema.pages.map((page) => /* @__PURE__ */ jsxs("section", { "data-kotao-form-page": page.key, children: [
183
+ page.title && /* @__PURE__ */ jsx("h2", { children: resolveFormText(page.title, locale, fallbackLocale) }),
184
+ page.description && /* @__PURE__ */ jsx("p", { children: resolveFormText(page.description, locale, fallbackLocale) }),
185
+ page.blocks.map((block) => {
186
+ if (block.type === "section") {
187
+ return /* @__PURE__ */ jsxs("header", { children: [
188
+ /* @__PURE__ */ jsx("h3", { children: resolveFormText(block.title, locale, fallbackLocale) }),
189
+ block.description && /* @__PURE__ */ jsx("p", { children: resolveFormText(block.description, locale, fallbackLocale) })
190
+ ] }, block.key);
191
+ }
192
+ if (block.type === "content") {
193
+ return /* @__PURE__ */ jsx("div", { "data-kotao-form-content": true, children: resolveFormText(block.content, locale, fallbackLocale) }, block.key);
194
+ }
195
+ return isFormFieldVisible(block.field, answers) ? /* @__PURE__ */ jsx(
196
+ StorefrontFormField,
197
+ {
198
+ field: block.field,
199
+ locale,
200
+ fallbackLocale,
201
+ value: answers[block.field.key],
202
+ errors: errors[block.field.key] ?? [],
203
+ onChange: (answer) => updateAnswer(block.field.key, answer),
204
+ idPrefix: instanceId
205
+ },
206
+ block.field.key
207
+ ) : null;
208
+ })
209
+ ] }, page.key)) });
210
+ }
211
+ function StorefrontForm({
212
+ form,
213
+ locale,
214
+ fallbackLocale,
215
+ answers,
216
+ errors,
217
+ submitted = false,
218
+ submitLabel,
219
+ onAnswersChange,
220
+ action = "",
221
+ method = "post",
222
+ ...props
223
+ }) {
224
+ const schema = form.version.schema;
225
+ return /* @__PURE__ */ jsxs("form", { ...props, action, method, "data-kotao-form": form.definition.handle, children: [
226
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: "versionId", value: form.version.id }),
227
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: "locale", value: locale }),
228
+ submitted && /* @__PURE__ */ jsx("p", { role: "status", "data-kotao-form-success": true, children: resolveFormText(schema.successMessage, locale, fallbackLocale) }),
229
+ /* @__PURE__ */ jsx(
230
+ StorefrontFormFields,
231
+ {
232
+ form,
233
+ locale,
234
+ ...fallbackLocale === void 0 ? {} : { fallbackLocale },
235
+ ...answers === void 0 ? {} : { answers },
236
+ ...errors === void 0 ? {} : { errors },
237
+ ...onAnswersChange === void 0 ? {} : { onAnswersChange }
238
+ }
239
+ ),
240
+ /* @__PURE__ */ jsx("button", { type: "submit", children: submitLabel ?? (resolveFormText(schema.submitLabel, locale, fallbackLocale) || "Submit") })
241
+ ] });
242
+ }
243
+
244
+ export { StorefrontForm, StorefrontFormFields };
245
+ //# sourceMappingURL=chunk-VV653S52.js.map
246
+ //# sourceMappingURL=chunk-VV653S52.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/form.tsx"],"names":[],"mappings":"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","file":"chunk-VV653S52.js","sourcesContent":["import React, { useId, useState, type ComponentPropsWithoutRef, type ReactNode } from 'react'\nimport {\n ADDRESS_PROPERTIES,\n formAnswerName,\n formFields,\n isFormFieldVisible,\n resolveFormText,\n type FormAnswer,\n type FormAnswers,\n type FormField,\n type FormFieldErrors,\n type PublicForm,\n} from '../forms'\n\nexport interface StorefrontFormProps extends Omit<\n ComponentPropsWithoutRef<'form'>,\n 'children' | 'defaultValue'\n> {\n form: PublicForm\n locale: string\n fallbackLocale?: string\n answers?: FormAnswers\n errors?: FormFieldErrors\n submitted?: boolean\n submitLabel?: ReactNode\n onAnswersChange?: (answers: FormAnswers) => void\n}\n\nexport interface StorefrontFormFieldsProps {\n readonly form: PublicForm\n readonly locale: string\n readonly fallbackLocale?: string\n readonly answers?: FormAnswers\n readonly errors?: FormFieldErrors\n readonly onAnswersChange?: (answers: FormAnswers) => void\n readonly idPrefix?: string\n}\n\ninterface FieldProps {\n field: FormField\n locale: string\n fallbackLocale?: string | undefined\n value?: FormAnswer | undefined\n errors: string[]\n onChange: (value: FormAnswer) => void\n idPrefix: string\n}\n\nconst ADDRESS_LABELS: Record<(typeof ADDRESS_PROPERTIES)[number], string> = {\n line1: 'Address',\n line2: 'Address line 2',\n city: 'City',\n postalCode: 'Postal code',\n countryCode: 'Country code',\n provinceCode: 'Province or state code',\n}\n\nfunction FieldErrors({ id, errors }: { id: string; errors: string[] }) {\n if (errors.length === 0) return null\n return (\n <ul id={id} data-kotao-form-errors>\n {errors.map((error, index) => (\n <li key={`${error}-${index}`}>{error}</li>\n ))}\n </ul>\n )\n}\n\nfunction StorefrontFormField({\n field,\n locale,\n fallbackLocale,\n value,\n errors,\n onChange,\n idPrefix,\n}: FieldProps) {\n const id = `${idPrefix}-form-${field.key}`\n const label = resolveFormText(field.label, locale, fallbackLocale)\n const description = resolveFormText(field.description, locale, fallbackLocale)\n const errorId = `${id}-errors`\n const descriptionId = `${id}-description`\n const describedBy = [description ? descriptionId : '', errors.length ? errorId : '']\n .filter(Boolean)\n .join(' ')\n const common = {\n id,\n name: formAnswerName(field.key),\n required: field.required,\n 'aria-invalid': errors.length > 0 || undefined,\n 'aria-describedby': describedBy || undefined,\n }\n let control: ReactNode\n\n if (field.kind === 'textarea') {\n control = (\n <textarea\n {...common}\n value={typeof value === 'string' ? value : ''}\n minLength={field.validation?.minLength}\n maxLength={field.validation?.maxLength}\n onChange={(event) => onChange(event.currentTarget.value)}\n />\n )\n } else if (field.kind === 'address') {\n const address = typeof value === 'object' && !Array.isArray(value) ? value : {}\n control = (\n <fieldset aria-describedby={describedBy || undefined}>\n <legend>\n {label}\n {field.required && <span aria-hidden=\"true\"> *</span>}\n </legend>\n {ADDRESS_PROPERTIES.map((property) => (\n <label key={property}>\n <span>{ADDRESS_LABELS[property]}</span>\n <input\n name={formAnswerName(field.key, property)}\n value={address[property] ?? ''}\n required={\n field.required && ['line1', 'postalCode', 'city', 'countryCode'].includes(property)\n }\n onChange={(event) => onChange({ ...address, [property]: event.currentTarget.value })}\n />\n </label>\n ))}\n </fieldset>\n )\n } else if (field.kind === 'select' || field.kind === 'multi_select') {\n const selected = Array.isArray(value) ? value : typeof value === 'string' ? [value] : []\n control = (\n <select\n {...common}\n multiple={field.kind === 'multi_select'}\n value={field.kind === 'multi_select' ? selected : (selected[0] ?? '')}\n onChange={(event) =>\n onChange(\n field.kind === 'multi_select'\n ? Array.from(event.currentTarget.selectedOptions, (option) => option.value)\n : event.currentTarget.value,\n )\n }\n >\n {field.kind === 'select' && <option value=\"\" />}\n {field.choices?.map((choice) => (\n <option key={choice.value} value={choice.value}>\n {resolveFormText(choice.label, locale, fallbackLocale)}\n </option>\n ))}\n </select>\n )\n } else if (field.kind === 'radio') {\n control = (\n <div role=\"radiogroup\" aria-describedby={describedBy || undefined}>\n {field.choices?.map((choice) => (\n <label key={choice.value}>\n <input\n type=\"radio\"\n name={common.name}\n value={choice.value}\n required={field.required}\n checked={value === choice.value}\n onChange={(event) => {\n if (event.currentTarget.checked) onChange(choice.value)\n }}\n />\n <span>{resolveFormText(choice.label, locale, fallbackLocale)}</span>\n </label>\n ))}\n </div>\n )\n } else if (field.kind === 'checkbox' || field.kind === 'consent') {\n control = (\n <label>\n <input\n {...common}\n type=\"checkbox\"\n value=\"true\"\n checked={value === true}\n onChange={(event) => onChange(event.currentTarget.checked)}\n />\n <span>\n {field.kind === 'consent'\n ? resolveFormText(field.consentText, locale, fallbackLocale)\n : label}\n </span>\n </label>\n )\n } else {\n control = (\n <input\n {...common}\n type={field.kind === 'phone' ? 'tel' : field.kind}\n value={typeof value === 'string' || typeof value === 'number' ? value : ''}\n minLength={field.validation?.minLength}\n maxLength={field.validation?.maxLength}\n min={field.validation?.min}\n max={field.validation?.max}\n onChange={(event) =>\n onChange(\n field.kind === 'number' && event.currentTarget.value !== ''\n ? event.currentTarget.valueAsNumber\n : event.currentTarget.value,\n )\n }\n />\n )\n }\n\n const hasSeparateLabel = !['address', 'checkbox', 'consent'].includes(field.kind)\n return (\n <div data-kotao-form-field={field.key}>\n {hasSeparateLabel && (\n <label htmlFor={id}>\n {label}\n {field.required && <span aria-hidden=\"true\"> *</span>}\n </label>\n )}\n {control}\n {description && <p id={descriptionId}>{description}</p>}\n <FieldErrors id={errorId} errors={errors} />\n </div>\n )\n}\n\nexport function StorefrontFormFields({\n form,\n locale,\n fallbackLocale,\n answers: initialAnswers = {},\n errors = {},\n onAnswersChange,\n idPrefix,\n}: StorefrontFormFieldsProps) {\n const [answers, setAnswers] = useState<FormAnswers>(initialAnswers)\n const generatedId = useId()\n const instanceId = idPrefix ?? `kotao-${generatedId.replaceAll(':', '')}`\n const schema = form.version.schema\n\n function pruneHiddenAnswers(nextAnswers: FormAnswers): FormAnswers {\n let pruned = nextAnswers\n let removed = true\n while (removed) {\n removed = false\n for (const field of formFields(schema)) {\n if (Object.hasOwn(pruned, field.key) && !isFormFieldVisible(field, pruned)) {\n if (pruned === nextAnswers) pruned = { ...nextAnswers }\n delete pruned[field.key]\n removed = true\n }\n }\n }\n return pruned\n }\n\n function updateAnswer(key: string, answer: FormAnswer) {\n setAnswers((current) => {\n const next = pruneHiddenAnswers({ ...current, [key]: answer })\n onAnswersChange?.(next)\n return next\n })\n }\n\n return (\n <>\n {schema.pages.map((page) => (\n <section key={page.key} data-kotao-form-page={page.key}>\n {page.title && <h2>{resolveFormText(page.title, locale, fallbackLocale)}</h2>}\n {page.description && <p>{resolveFormText(page.description, locale, fallbackLocale)}</p>}\n {page.blocks.map((block) => {\n if (block.type === 'section') {\n return (\n <header key={block.key}>\n <h3>{resolveFormText(block.title, locale, fallbackLocale)}</h3>\n {block.description && (\n <p>{resolveFormText(block.description, locale, fallbackLocale)}</p>\n )}\n </header>\n )\n }\n if (block.type === 'content') {\n return (\n <div key={block.key} data-kotao-form-content>\n {resolveFormText(block.content, locale, fallbackLocale)}\n </div>\n )\n }\n return isFormFieldVisible(block.field, answers) ? (\n <StorefrontFormField\n key={block.field.key}\n field={block.field}\n locale={locale}\n fallbackLocale={fallbackLocale}\n value={answers[block.field.key]}\n errors={errors[block.field.key] ?? []}\n onChange={(answer) => updateAnswer(block.field.key, answer)}\n idPrefix={instanceId}\n />\n ) : null\n })}\n </section>\n ))}\n </>\n )\n}\n\nexport function StorefrontForm({\n form,\n locale,\n fallbackLocale,\n answers,\n errors,\n submitted = false,\n submitLabel,\n onAnswersChange,\n action = '',\n method = 'post',\n ...props\n}: StorefrontFormProps) {\n const schema = form.version.schema\n\n return (\n <form {...props} action={action} method={method} data-kotao-form={form.definition.handle}>\n <input type=\"hidden\" name=\"versionId\" value={form.version.id} />\n <input type=\"hidden\" name=\"locale\" value={locale} />\n {submitted && (\n <p role=\"status\" data-kotao-form-success>\n {resolveFormText(schema.successMessage, locale, fallbackLocale)}\n </p>\n )}\n <StorefrontFormFields\n form={form}\n locale={locale}\n {...(fallbackLocale === undefined ? {} : { fallbackLocale })}\n {...(answers === undefined ? {} : { answers })}\n {...(errors === undefined ? {} : { errors })}\n {...(onAnswersChange === undefined ? {} : { onAnswersChange })}\n />\n <button type=\"submit\">\n {submitLabel ?? (resolveFormText(schema.submitLabel, locale, fallbackLocale) || 'Submit')}\n </button>\n </form>\n )\n}\n"]}