@squaredr/fieldcraft-pro 1.7.0 → 1.8.0

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/dist/index.mjs CHANGED
@@ -1,28 +1,116 @@
1
- export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from './chunk-J5V6OVZO.mjs';
2
- export { ResponseViewer } from './chunk-GZIV2XAD.mjs';
1
+ export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from './chunk-GXKQCXIB.mjs';
2
+ export { ResponseViewer } from './chunk-MLP5EDWP.mjs';
3
3
  export { cn } from './chunk-QQ4JZGTD.mjs';
4
- export { consultationBooking, consultationBookingMeta, consultationBookingSchema, ecommerceCheckout, ecommerceCheckoutMeta, ecommerceCheckoutSchema, proTemplates } from './chunk-VEP3DOCQ.mjs';
5
- export { PRESET_FAMILIES, PREVIEW_SCHEMA, ThemeEditor, ThemeEditorThemeProvider, resolveThemeFromDOM, themeEditorDarkPreset, themeEditorLightPreset, useEditorTheme } from './chunk-4TN6YJDF.mjs';
4
+ export { consultationBooking, consultationBookingMeta, consultationBookingSchema, ecommerceCheckout, ecommerceCheckoutMeta, ecommerceCheckoutSchema, proTemplates } from './chunk-IW654Z3M.mjs';
5
+ export { PRESET_FAMILIES, PREVIEW_SCHEMA, ThemeEditor, ThemeEditorThemeProvider, resolveThemeFromDOM, themeEditorDarkPreset, themeEditorLightPreset, useEditorTheme } from './chunk-CYXJGOQH.mjs';
6
6
  export { FieldCraftProProvider, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense } from './chunk-4MMKB2EW.mjs';
7
- import { useState, useEffect, Suspense } from 'react';
7
+ import { useState, useEffect, useMemo } from 'react';
8
8
  import { FieldWrapper } from '@squaredr/fieldcraft-react';
9
+ import { PayKitProvider, CheckoutForm } from '@squaredr/paykit-react';
10
+ import { StripeClientAdapter } from '@squaredr/paykit/stripe/client';
11
+ import { formatAmount } from '@squaredr/paykit';
9
12
  import { jsx, jsxs } from 'react/jsx-runtime';
10
13
 
11
14
  // package.json
12
- var version = "1.6.4";
13
- function formatCurrency(amount, currency) {
14
- if (amount == null) return "";
15
- try {
16
- return new Intl.NumberFormat(void 0, {
17
- style: "currency",
18
- currency: currency ?? "USD"
19
- }).format(amount);
20
- } catch {
21
- return `${currency ?? "USD"} ${amount.toFixed(2)}`;
15
+ var version = "1.8.0";
16
+ function resolvePath(obj, path) {
17
+ let current = obj;
18
+ for (const key of path.split(".")) {
19
+ if (current == null || typeof current !== "object") return void 0;
20
+ current = current[key];
22
21
  }
22
+ return current;
23
+ }
24
+ function isDarkTheme(theme) {
25
+ const bg = theme.colors?.background ?? "#FFFFFF";
26
+ let hex = bg.replace("#", "");
27
+ if (hex.length === 3) {
28
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
29
+ }
30
+ if (hex.length < 6) return false;
31
+ const r = parseInt(hex.slice(0, 2), 16);
32
+ const g = parseInt(hex.slice(2, 4), 16);
33
+ const b = parseInt(hex.slice(4, 6), 16);
34
+ return 0.299 * r + 0.587 * g + 0.114 * b < 128;
35
+ }
36
+ function resolveAppearance(theme) {
37
+ const c = theme.colors;
38
+ const isDark = isDarkTheme(theme);
39
+ return {
40
+ theme: isDark ? "night" : "default",
41
+ variables: {
42
+ colorPrimary: c?.primary,
43
+ colorBackground: c?.surface || c?.background,
44
+ colorText: c?.text,
45
+ colorDanger: c?.error,
46
+ colorSuccess: c?.success || "#22c55e",
47
+ borderRadius: theme.shape?.inputRadius || "6px",
48
+ fontFamily: theme.typography?.fontFamily
49
+ }
50
+ };
51
+ }
52
+ var PAYKIT_STYLES = `
53
+ [data-paykit-form] {
54
+ display: flex;
55
+ flex-direction: column;
56
+ gap: 16px;
57
+ }
58
+ [data-paykit-submit] {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ width: 100%;
63
+ padding: 10px 20px;
64
+ font-size: 0.9375rem;
65
+ font-weight: 600;
66
+ font-family: var(--paykit-font-family, inherit);
67
+ line-height: 1.5;
68
+ color: #fff;
69
+ background: var(--paykit-color-primary, #635BFF);
70
+ border: none;
71
+ border-radius: var(--paykit-border-radius, 6px);
72
+ cursor: pointer;
73
+ transition: opacity 150ms ease, box-shadow 150ms ease, filter 150ms ease;
74
+ }
75
+ [data-paykit-submit]:hover:not(:disabled) {
76
+ filter: brightness(1.1);
77
+ box-shadow: 0 2px 8px color-mix(in srgb, var(--paykit-color-primary, #635BFF) 35%, transparent);
78
+ }
79
+ [data-paykit-submit]:active:not(:disabled) {
80
+ filter: brightness(0.95);
81
+ }
82
+ [data-paykit-submit]:disabled {
83
+ opacity: 0.5;
84
+ cursor: not-allowed;
85
+ }
86
+ `;
87
+ var paykitStylesInjected = false;
88
+ function injectPayKitStyles() {
89
+ if (paykitStylesInjected || typeof document === "undefined") return;
90
+ const style = document.createElement("style");
91
+ style.setAttribute("data-paykit-pro", "");
92
+ style.textContent = PAYKIT_STYLES;
93
+ document.head.appendChild(style);
94
+ paykitStylesInjected = true;
95
+ }
96
+ function formatCurrency(amountCents, currency) {
97
+ if (amountCents == null) return "";
98
+ return formatAmount(amountCents, currency ?? "USD");
23
99
  }
24
100
  function ProPaymentField(props) {
25
- const { field, value, error, touched, disabled, readonly, onChange, onBlur, customProps } = props;
101
+ injectPayKitStyles();
102
+ const {
103
+ field,
104
+ value,
105
+ error,
106
+ touched,
107
+ disabled,
108
+ readonly,
109
+ onChange,
110
+ onBlur,
111
+ customProps,
112
+ theme: formTheme
113
+ } = props;
26
114
  const config = field.config;
27
115
  const current = value ?? { status: "pending" };
28
116
  const provider = config?.provider ?? "stripe";
@@ -44,31 +132,77 @@ function ProPaymentField(props) {
44
132
  }
45
133
  if (mode === "setup" || !amount || !publicKey) return;
46
134
  if (clientSecret) return;
135
+ let cancelled = false;
136
+ const controller = mode === "url" ? new AbortController() : void 0;
47
137
  const fetchIntent = async () => {
48
138
  setIntentLoading(true);
49
139
  setIntentError(null);
50
140
  try {
51
141
  if (mode === "callback" && onCreateIntent) {
52
- const result = await onCreateIntent({ amount, currency, provider, metadata: { fieldId: field.id } });
53
- setClientSecret(result.clientSecret);
142
+ const result = await onCreateIntent({
143
+ amount,
144
+ currency,
145
+ provider,
146
+ metadata: { fieldId: field.id }
147
+ });
148
+ if (!cancelled) setClientSecret(result.clientSecret);
54
149
  } else if (mode === "url" && serverUrl) {
55
150
  const res = await fetch(serverUrl, {
56
151
  method: "POST",
57
152
  headers: { "Content-Type": "application/json" },
58
- body: JSON.stringify({ amount, currency, provider, metadata: { fieldId: field.id } })
153
+ body: JSON.stringify({ amount, currency, provider, metadata: { fieldId: field.id } }),
154
+ signal: controller?.signal
59
155
  });
60
156
  if (!res.ok) throw new Error(`Server error (${res.status})`);
61
157
  const data = await res.json();
62
- setClientSecret(data.clientSecret);
158
+ const secretPath = config?.responseMapping?.clientSecretPath;
159
+ const secret = secretPath ? resolvePath(data, secretPath) : data.clientSecret;
160
+ if (!secret)
161
+ throw new Error(
162
+ "No clientSecret in response" + (secretPath ? ` at path "${secretPath}"` : "")
163
+ );
164
+ if (!cancelled) setClientSecret(secret);
63
165
  }
64
166
  } catch (err) {
167
+ if (cancelled) return;
65
168
  setIntentError(err instanceof Error ? err.message : "Failed to create payment intent");
66
169
  } finally {
67
- setIntentLoading(false);
170
+ if (!cancelled) setIntentLoading(false);
68
171
  }
69
172
  };
70
173
  fetchIntent();
71
- }, [mode, amount, currency, provider, publicKey, directSecret, clientSecret, onCreateIntent, serverUrl, field.id]);
174
+ return () => {
175
+ cancelled = true;
176
+ controller?.abort();
177
+ };
178
+ }, [
179
+ mode,
180
+ amount,
181
+ currency,
182
+ provider,
183
+ publicKey,
184
+ directSecret,
185
+ clientSecret,
186
+ onCreateIntent,
187
+ serverUrl,
188
+ field.id
189
+ ]);
190
+ const c = formTheme.colors;
191
+ const cardStyle = {
192
+ borderRadius: formTheme.shape?.inputRadius || "8px",
193
+ border: `1px solid ${c?.border || "#e2e8f0"}`,
194
+ padding: "16px",
195
+ background: c?.surface || c?.background,
196
+ color: c?.text
197
+ };
198
+ const mutedTextStyle = { color: c?.textMuted, fontSize: "0.875rem" };
199
+ const badgeStyle = {
200
+ fontSize: "0.75rem",
201
+ padding: "2px 8px",
202
+ borderRadius: formTheme.shape?.inputRadius || "4px",
203
+ background: c?.secondary || c?.surface,
204
+ color: c?.secondaryForeground || c?.textMuted
205
+ };
72
206
  const handleSuccess = (chargeId) => {
73
207
  const result = { status: "succeeded", chargeId };
74
208
  onChange(result);
@@ -83,7 +217,8 @@ function ProPaymentField(props) {
83
217
  };
84
218
  if (!publicKey) {
85
219
  return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsx("div", { className: "rounded-lg border-2 border-dashed border-input p-4 text-center", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
86
- "Payment field \u2014 configure a ",
220
+ "Payment field \u2014 configure a",
221
+ " ",
87
222
  /* @__PURE__ */ jsx("code", { className: "bg-muted px-1 rounded text-xs", children: "publicKey" }),
88
223
  " in the field properties panel."
89
224
  ] }) }) });
@@ -96,40 +231,97 @@ function ProPaymentField(props) {
96
231
  ] }) }) });
97
232
  }
98
233
  if (current.status === "succeeded") {
99
- return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
100
- amount != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mb-2", children: [
234
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
235
+ amount != null && /* @__PURE__ */ jsxs("p", { style: { ...mutedTextStyle, marginBottom: "8px" }, children: [
101
236
  formatCurrency(amount, currency),
102
237
  config?.description && /* @__PURE__ */ jsxs("span", { children: [
103
238
  " \u2014 ",
104
239
  config.description
105
240
  ] })
106
241
  ] }),
107
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-medium", style: { color: "var(--success, #22c55e)" }, children: [
108
- /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, width: 16, height: 16, children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" }) }),
109
- /* @__PURE__ */ jsxs("span", { children: [
110
- "Payment successful",
111
- current.chargeId ? ` (${current.chargeId})` : ""
112
- ] })
113
- ] })
242
+ /* @__PURE__ */ jsxs(
243
+ "div",
244
+ {
245
+ style: {
246
+ display: "flex",
247
+ alignItems: "center",
248
+ gap: "8px",
249
+ fontSize: "0.875rem",
250
+ fontWeight: 500,
251
+ color: c?.success || "#22c55e"
252
+ },
253
+ children: [
254
+ /* @__PURE__ */ jsx(
255
+ "svg",
256
+ {
257
+ viewBox: "0 0 24 24",
258
+ fill: "none",
259
+ stroke: "currentColor",
260
+ strokeWidth: 2,
261
+ width: 16,
262
+ height: 16,
263
+ children: /* @__PURE__ */ jsx("polyline", { points: "20 6 9 17 4 12" })
264
+ }
265
+ ),
266
+ /* @__PURE__ */ jsxs("span", { children: [
267
+ "Payment successful",
268
+ current.chargeId ? ` (${current.chargeId})` : ""
269
+ ] })
270
+ ]
271
+ }
272
+ )
114
273
  ] }) });
115
274
  }
116
275
  if (current.status === "failed") {
117
- return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-destructive/50 p-4", children: [
118
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-destructive font-medium", children: [
119
- /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, width: 16, height: 16, children: [
120
- /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
121
- /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
122
- ] }),
123
- /* @__PURE__ */ jsxs("span", { children: [
124
- "Payment failed",
125
- current.error ? `: ${current.error}` : ""
126
- ] })
127
- ] }),
276
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { style: { ...cardStyle, borderColor: c?.error || "#dc2626" }, children: [
277
+ /* @__PURE__ */ jsxs(
278
+ "div",
279
+ {
280
+ style: {
281
+ display: "flex",
282
+ alignItems: "center",
283
+ gap: "8px",
284
+ fontSize: "0.875rem",
285
+ fontWeight: 500,
286
+ color: c?.error || "#dc2626"
287
+ },
288
+ children: [
289
+ /* @__PURE__ */ jsxs(
290
+ "svg",
291
+ {
292
+ viewBox: "0 0 24 24",
293
+ fill: "none",
294
+ stroke: "currentColor",
295
+ strokeWidth: 2,
296
+ width: 16,
297
+ height: 16,
298
+ children: [
299
+ /* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
300
+ /* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
301
+ ]
302
+ }
303
+ ),
304
+ /* @__PURE__ */ jsxs("span", { children: [
305
+ "Payment failed",
306
+ current.error ? `: ${current.error}` : ""
307
+ ] })
308
+ ]
309
+ }
310
+ ),
128
311
  /* @__PURE__ */ jsx(
129
312
  "button",
130
313
  {
131
314
  type: "button",
132
- className: "mt-2 text-xs text-primary hover:underline",
315
+ style: {
316
+ marginTop: "8px",
317
+ fontSize: "0.75rem",
318
+ color: c?.primary,
319
+ background: "none",
320
+ border: "none",
321
+ cursor: "pointer",
322
+ textDecoration: "underline",
323
+ padding: 0
324
+ },
133
325
  onClick: () => {
134
326
  onChange({ status: "pending" });
135
327
  setClientSecret(void 0);
@@ -140,26 +332,46 @@ function ProPaymentField(props) {
140
332
  ] }) });
141
333
  }
142
334
  if (intentLoading || mode !== "setup" && mode !== "direct" && !clientSecret) {
143
- return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
144
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
145
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Payment" }),
146
- /* @__PURE__ */ jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
147
- ] }),
148
- amount != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: [
335
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
336
+ /* @__PURE__ */ jsxs(
337
+ "div",
338
+ {
339
+ style: {
340
+ display: "flex",
341
+ alignItems: "center",
342
+ justifyContent: "space-between",
343
+ marginBottom: "12px"
344
+ },
345
+ children: [
346
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", fontWeight: 500 }, children: "Payment" }),
347
+ /* @__PURE__ */ jsx("span", { style: badgeStyle, children: provider })
348
+ ]
349
+ }
350
+ ),
351
+ amount != null && /* @__PURE__ */ jsxs("p", { style: { ...mutedTextStyle, marginBottom: "12px" }, children: [
149
352
  "Amount: ",
150
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatCurrency(amount, currency) }),
353
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: formatCurrency(amount, currency) }),
151
354
  config?.description && /* @__PURE__ */ jsxs("span", { children: [
152
355
  " \u2014 ",
153
356
  config.description
154
357
  ] })
155
358
  ] }),
156
359
  intentError ? /* @__PURE__ */ jsxs("div", { children: [
157
- /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: intentError }),
360
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", color: c?.error || "#dc2626" }, children: intentError }),
158
361
  /* @__PURE__ */ jsx(
159
362
  "button",
160
363
  {
161
364
  type: "button",
162
- className: "mt-2 text-xs text-primary hover:underline",
365
+ style: {
366
+ marginTop: "8px",
367
+ fontSize: "0.75rem",
368
+ color: c?.primary,
369
+ background: "none",
370
+ border: "none",
371
+ cursor: "pointer",
372
+ textDecoration: "underline",
373
+ padding: 0
374
+ },
163
375
  onClick: () => {
164
376
  setIntentError(null);
165
377
  setClientSecret(void 0);
@@ -167,54 +379,78 @@ function ProPaymentField(props) {
167
379
  children: "Retry"
168
380
  }
169
381
  )
170
- ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
171
- /* @__PURE__ */ jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
382
+ ] }) : /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", ...mutedTextStyle }, children: [
383
+ /* @__PURE__ */ jsx(
384
+ "svg",
385
+ {
386
+ style: { width: "16px", height: "16px", animation: "spin 1s linear infinite" },
387
+ viewBox: "0 0 24 24",
388
+ fill: "none",
389
+ stroke: "currentColor",
390
+ strokeWidth: 2,
391
+ children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" })
392
+ }
393
+ ),
172
394
  /* @__PURE__ */ jsx("span", { children: "Preparing payment..." })
173
395
  ] })
174
396
  ] }) });
175
397
  }
176
398
  if (!clientSecret) {
177
399
  const waitingForAmount = config?.amountField && !amount;
178
- return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
179
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
180
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Payment" }),
181
- /* @__PURE__ */ jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
182
- ] }),
183
- /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: waitingForAmount ? "Select an option above to proceed with payment." : "Provide a clientSecret via customProps, an onCreatePaymentIntent callback, or a serverUrl." })
400
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
401
+ /* @__PURE__ */ jsxs(
402
+ "div",
403
+ {
404
+ style: {
405
+ display: "flex",
406
+ alignItems: "center",
407
+ justifyContent: "space-between",
408
+ marginBottom: "12px"
409
+ },
410
+ children: [
411
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", fontWeight: 500 }, children: "Payment" }),
412
+ /* @__PURE__ */ jsx("span", { style: badgeStyle, children: provider })
413
+ ]
414
+ }
415
+ ),
416
+ /* @__PURE__ */ jsx("p", { style: mutedTextStyle, children: waitingForAmount ? "Select an option above to proceed with payment." : "Provide a clientSecret via customProps, an onCreatePaymentIntent callback, or a serverUrl." })
184
417
  ] }) });
185
418
  }
186
- return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-input p-4", children: [
187
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-3", children: [
188
- /* @__PURE__ */ jsx("p", { className: "text-sm font-medium", children: "Payment" }),
189
- /* @__PURE__ */ jsx("span", { className: "text-xs bg-muted px-2 py-0.5 rounded", children: provider })
190
- ] }),
191
- amount != null && /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: [
419
+ return /* @__PURE__ */ jsx(FieldWrapper, { field, error, touched, children: /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
420
+ /* @__PURE__ */ jsxs(
421
+ "div",
422
+ {
423
+ style: {
424
+ display: "flex",
425
+ alignItems: "center",
426
+ justifyContent: "space-between",
427
+ marginBottom: "12px"
428
+ },
429
+ children: [
430
+ /* @__PURE__ */ jsx("p", { style: { fontSize: "0.875rem", fontWeight: 500 }, children: "Payment" }),
431
+ /* @__PURE__ */ jsx("span", { style: badgeStyle, children: provider })
432
+ ]
433
+ }
434
+ ),
435
+ amount != null && /* @__PURE__ */ jsxs("p", { style: { ...mutedTextStyle, marginBottom: "12px" }, children: [
192
436
  "Amount: ",
193
- /* @__PURE__ */ jsx("span", { className: "font-medium", children: formatCurrency(amount, currency) }),
437
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: formatCurrency(amount, currency) }),
194
438
  config?.description && /* @__PURE__ */ jsxs("span", { children: [
195
439
  " \u2014 ",
196
440
  config.description
197
441
  ] })
198
442
  ] }),
199
443
  /* @__PURE__ */ jsx(
200
- Suspense,
444
+ PayKitCheckout,
201
445
  {
202
- fallback: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-4", children: [
203
- /* @__PURE__ */ jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
204
- "Loading payment form..."
205
- ] }),
206
- children: /* @__PURE__ */ jsx(
207
- PayKitCheckout,
208
- {
209
- publicKey,
210
- clientSecret,
211
- amount,
212
- currency,
213
- disabled: disabled || readonly,
214
- onSuccess: handleSuccess,
215
- onError: handleError
216
- }
217
- )
446
+ publicKey,
447
+ clientSecret,
448
+ amount,
449
+ currency,
450
+ appearance: resolveAppearance(formTheme),
451
+ disabled: disabled || readonly,
452
+ onSuccess: handleSuccess,
453
+ onError: handleError
218
454
  }
219
455
  )
220
456
  ] }) });
@@ -224,48 +460,17 @@ function PayKitCheckout({
224
460
  clientSecret,
225
461
  amount,
226
462
  currency,
463
+ appearance,
227
464
  disabled,
228
465
  onSuccess,
229
466
  onError
230
467
  }) {
231
- const [PayKit, setPayKit] = useState(null);
232
- const [loadError, setLoadError] = useState(null);
233
- useEffect(() => {
234
- let cancelled = false;
235
- Promise.all([
236
- import('@squaredr/paykit-react'),
237
- // @ts-expect-error — optional peer dep, types not available at build time
238
- import('@squaredr/paykit/stripe/client')
239
- ]).then(([paykit, stripe]) => {
240
- if (cancelled) return;
241
- setPayKit({
242
- Provider: paykit.PayKitProvider,
243
- Form: paykit.CheckoutForm,
244
- adapter: new stripe.StripeClientAdapter(publicKey)
245
- });
246
- }).catch((err) => {
247
- if (cancelled) return;
248
- setLoadError(
249
- `Failed to load payment SDK. Ensure @squaredr/paykit-react and @squaredr/paykit are installed. (${err.message})`
250
- );
251
- });
252
- return () => {
253
- cancelled = true;
254
- };
255
- }, [publicKey]);
256
- if (loadError) {
257
- return /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: loadError });
258
- }
259
- if (!PayKit) {
260
- return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground py-2", children: [
261
- /* @__PURE__ */ jsx("svg", { className: "animate-spin size-4", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10", strokeDasharray: "60", strokeDashoffset: "20" }) }),
262
- "Loading Stripe..."
263
- ] });
264
- }
265
- return /* @__PURE__ */ jsx(PayKit.Provider, { clientAdapter: PayKit.adapter, children: /* @__PURE__ */ jsx(
266
- PayKit.Form,
468
+ const clientAdapter = useMemo(() => new StripeClientAdapter(publicKey), [publicKey]);
469
+ return /* @__PURE__ */ jsx(PayKitProvider, { clientAdapter, children: /* @__PURE__ */ jsx(
470
+ CheckoutForm,
267
471
  {
268
472
  clientSecret,
473
+ appearance,
269
474
  submitLabel: disabled ? "Payment disabled" : `Pay ${formatCurrency(amount, currency)}`,
270
475
  onSuccess: (result) => onSuccess(result.chargeId),
271
476
  onError: (err) => onError(err.message)
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { FormEngineSchema, FormResponse } from '@squaredr/fieldcraft-core';
2
+ import { FormResponse, FormEngineSchema } from '@squaredr/fieldcraft-core';
3
3
 
4
4
  type FieldRenderer = (field: ResponseField, response: FormResponse) => React.ReactNode;
5
5
  type ResponseViewerProps = {
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { FormEngineSchema, FormResponse } from '@squaredr/fieldcraft-core';
2
+ import { FormResponse, FormEngineSchema } from '@squaredr/fieldcraft-core';
3
3
 
4
4
  type FieldRenderer = (field: ResponseField, response: FormResponse) => React.ReactNode;
5
5
  type ResponseViewerProps = {