@fixture-inc/forms-react 0.1.0-beta.1
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.cjs +503 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +200 -0
- package/dist/index.d.ts +200 -0
- package/dist/index.js +464 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
// src/hooks.ts
|
|
2
|
+
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
|
|
3
|
+
import {
|
|
4
|
+
getDefaultValue,
|
|
5
|
+
validateForm,
|
|
6
|
+
errorsToRecord
|
|
7
|
+
} from "@fixture-inc/forms-core";
|
|
8
|
+
import { FormClient, normalizeError } from "@fixture-inc/forms-browser";
|
|
9
|
+
|
|
10
|
+
// src/context.ts
|
|
11
|
+
import { createContext, useContext } from "react";
|
|
12
|
+
var FixtureFormsContext = createContext(null);
|
|
13
|
+
function useFixtureFormsContext() {
|
|
14
|
+
return useContext(FixtureFormsContext);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/hooks.ts
|
|
18
|
+
function useFixtureForm(formId, options = {}) {
|
|
19
|
+
const {
|
|
20
|
+
apiUrl,
|
|
21
|
+
enabled = true,
|
|
22
|
+
initialData,
|
|
23
|
+
fetcher,
|
|
24
|
+
debug,
|
|
25
|
+
onSuccess,
|
|
26
|
+
onError
|
|
27
|
+
} = options;
|
|
28
|
+
const context = useFixtureFormsContext();
|
|
29
|
+
const clientRef = useRef(null);
|
|
30
|
+
if (!clientRef.current) {
|
|
31
|
+
clientRef.current = context?.client ?? new FormClient({
|
|
32
|
+
apiUrl: apiUrl ?? context?.apiUrl,
|
|
33
|
+
debug: debug ?? context?.debug
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const client = clientRef.current;
|
|
37
|
+
const [status, setStatus] = useState(
|
|
38
|
+
initialData ? "ready" : "idle"
|
|
39
|
+
);
|
|
40
|
+
const [form, setForm] = useState(initialData?.form ?? null);
|
|
41
|
+
const [nonce, setNonce] = useState(initialData?.nonce ?? null);
|
|
42
|
+
const [values, setValuesState] = useState(() => {
|
|
43
|
+
if (initialData?.form) {
|
|
44
|
+
return initializeValues(initialData.form);
|
|
45
|
+
}
|
|
46
|
+
return {};
|
|
47
|
+
});
|
|
48
|
+
const [errors, setErrors] = useState({});
|
|
49
|
+
const [error, setError] = useState(null);
|
|
50
|
+
const [result, setResult] = useState(null);
|
|
51
|
+
function initializeValues(formData) {
|
|
52
|
+
const vals = {};
|
|
53
|
+
for (const field of formData.fields) {
|
|
54
|
+
vals[field.id] = getDefaultValue(field.type);
|
|
55
|
+
}
|
|
56
|
+
return vals;
|
|
57
|
+
}
|
|
58
|
+
const fetchForm = useCallback(async () => {
|
|
59
|
+
if (!formId) return;
|
|
60
|
+
setStatus("loading");
|
|
61
|
+
setError(null);
|
|
62
|
+
try {
|
|
63
|
+
let response;
|
|
64
|
+
if (fetcher) {
|
|
65
|
+
response = await fetcher(formId);
|
|
66
|
+
} else {
|
|
67
|
+
response = await client.fetchForm(formId);
|
|
68
|
+
}
|
|
69
|
+
setForm(response.form);
|
|
70
|
+
setNonce(response.nonce);
|
|
71
|
+
setValuesState(initializeValues(response.form));
|
|
72
|
+
setErrors({});
|
|
73
|
+
setStatus("ready");
|
|
74
|
+
} catch (err) {
|
|
75
|
+
const normalized = normalizeError(err);
|
|
76
|
+
setError(normalized.message);
|
|
77
|
+
setStatus("error");
|
|
78
|
+
if (onError) {
|
|
79
|
+
onError(normalized);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}, [formId, client, fetcher, onError]);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
if (enabled && !initialData) {
|
|
85
|
+
fetchForm();
|
|
86
|
+
}
|
|
87
|
+
}, [enabled, initialData, fetchForm]);
|
|
88
|
+
const setValue = useCallback((fieldId, value) => {
|
|
89
|
+
setValuesState((prev) => ({ ...prev, [fieldId]: value }));
|
|
90
|
+
setErrors((prev) => {
|
|
91
|
+
const next = { ...prev };
|
|
92
|
+
delete next[fieldId];
|
|
93
|
+
return next;
|
|
94
|
+
});
|
|
95
|
+
}, []);
|
|
96
|
+
const setValuesFunc = useCallback((newValues) => {
|
|
97
|
+
setValuesState((prev) => ({ ...prev, ...newValues }));
|
|
98
|
+
}, []);
|
|
99
|
+
const getFieldValue = useCallback(
|
|
100
|
+
(fieldId) => {
|
|
101
|
+
return values[fieldId];
|
|
102
|
+
},
|
|
103
|
+
[values]
|
|
104
|
+
);
|
|
105
|
+
const submit = useCallback(async () => {
|
|
106
|
+
if (!form || !nonce) {
|
|
107
|
+
setError("Form not loaded");
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const validationErrors = validateForm(
|
|
111
|
+
form.fields,
|
|
112
|
+
values
|
|
113
|
+
);
|
|
114
|
+
if (validationErrors.length > 0) {
|
|
115
|
+
setErrors(errorsToRecord(validationErrors));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
setStatus("submitting");
|
|
119
|
+
setError(null);
|
|
120
|
+
try {
|
|
121
|
+
const { result: submitResult, newNonce } = await client.submitWithRetry(
|
|
122
|
+
formId,
|
|
123
|
+
form,
|
|
124
|
+
values,
|
|
125
|
+
{ nonce }
|
|
126
|
+
);
|
|
127
|
+
if (newNonce) {
|
|
128
|
+
setNonce(newNonce);
|
|
129
|
+
}
|
|
130
|
+
if (submitResult.redirectUrl && typeof window !== "undefined") {
|
|
131
|
+
window.location.href = submitResult.redirectUrl;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
setResult(submitResult);
|
|
135
|
+
setStatus("success");
|
|
136
|
+
if (onSuccess) {
|
|
137
|
+
onSuccess(submitResult);
|
|
138
|
+
}
|
|
139
|
+
} catch (err) {
|
|
140
|
+
const normalized = normalizeError(err);
|
|
141
|
+
setError(normalized.message);
|
|
142
|
+
setStatus("ready");
|
|
143
|
+
if (onError) {
|
|
144
|
+
onError(normalized);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}, [form, nonce, values, formId, client, onSuccess, onError]);
|
|
148
|
+
const reset = useCallback(() => {
|
|
149
|
+
if (form) {
|
|
150
|
+
setValuesState(initializeValues(form));
|
|
151
|
+
}
|
|
152
|
+
setErrors({});
|
|
153
|
+
setError(null);
|
|
154
|
+
setResult(null);
|
|
155
|
+
setStatus(form ? "ready" : "idle");
|
|
156
|
+
}, [form]);
|
|
157
|
+
const getFieldProps = useCallback(
|
|
158
|
+
(fieldId) => {
|
|
159
|
+
const field = form?.fields.find((f) => f.id === fieldId);
|
|
160
|
+
const value = values[fieldId];
|
|
161
|
+
const isCheckbox = field?.type === "checkbox";
|
|
162
|
+
return {
|
|
163
|
+
id: `ff-${fieldId}`,
|
|
164
|
+
name: fieldId,
|
|
165
|
+
value: isCheckbox ? "true" : value ?? "",
|
|
166
|
+
checked: isCheckbox ? value : void 0,
|
|
167
|
+
required: field?.required,
|
|
168
|
+
type: field?.type === "email" ? "email" : field?.type === "phone" ? "tel" : void 0,
|
|
169
|
+
onChange: (e) => {
|
|
170
|
+
if (isCheckbox) {
|
|
171
|
+
setValue(fieldId, e.target.checked);
|
|
172
|
+
} else {
|
|
173
|
+
setValue(fieldId, e.target.value);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
},
|
|
178
|
+
[form, values, setValue]
|
|
179
|
+
);
|
|
180
|
+
const fields = useMemo(() => form?.fields ?? [], [form]);
|
|
181
|
+
return {
|
|
182
|
+
form,
|
|
183
|
+
fields,
|
|
184
|
+
status,
|
|
185
|
+
error,
|
|
186
|
+
result,
|
|
187
|
+
values,
|
|
188
|
+
errors,
|
|
189
|
+
getFieldValue,
|
|
190
|
+
setValue,
|
|
191
|
+
setValues: setValuesFunc,
|
|
192
|
+
submit,
|
|
193
|
+
reset,
|
|
194
|
+
refetch: fetchForm,
|
|
195
|
+
getFieldProps
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function useVisitorId() {
|
|
199
|
+
const [visitorId, setVisitorId] = useState(null);
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
import("@fixture-inc/forms-browser").then(({ getVisitorId }) => {
|
|
202
|
+
setVisitorId(getVisitorId());
|
|
203
|
+
});
|
|
204
|
+
}, []);
|
|
205
|
+
return visitorId;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// src/components/Field.tsx
|
|
209
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
210
|
+
function Field({
|
|
211
|
+
field,
|
|
212
|
+
value,
|
|
213
|
+
error,
|
|
214
|
+
onChange
|
|
215
|
+
}) {
|
|
216
|
+
const id = `ff-${field.id}`;
|
|
217
|
+
const required = field.required;
|
|
218
|
+
const baseInputProps = {
|
|
219
|
+
id,
|
|
220
|
+
name: field.id,
|
|
221
|
+
required,
|
|
222
|
+
"aria-invalid": error ? true : void 0,
|
|
223
|
+
"aria-describedby": error ? `${id}-error` : void 0
|
|
224
|
+
};
|
|
225
|
+
let input;
|
|
226
|
+
switch (field.type) {
|
|
227
|
+
case "textarea":
|
|
228
|
+
input = /* @__PURE__ */ jsx(
|
|
229
|
+
"textarea",
|
|
230
|
+
{
|
|
231
|
+
...baseInputProps,
|
|
232
|
+
className: "ff-textarea",
|
|
233
|
+
placeholder: field.placeholder,
|
|
234
|
+
value: value ?? "",
|
|
235
|
+
onChange: (e) => onChange(e.target.value)
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
break;
|
|
239
|
+
case "dropdown":
|
|
240
|
+
input = /* @__PURE__ */ jsxs(
|
|
241
|
+
"select",
|
|
242
|
+
{
|
|
243
|
+
...baseInputProps,
|
|
244
|
+
className: "ff-select",
|
|
245
|
+
value: value ?? "",
|
|
246
|
+
onChange: (e) => onChange(e.target.value),
|
|
247
|
+
children: [
|
|
248
|
+
/* @__PURE__ */ jsx("option", { value: "", children: "Select..." }),
|
|
249
|
+
field.options?.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
|
|
250
|
+
]
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
break;
|
|
254
|
+
case "checkbox":
|
|
255
|
+
return /* @__PURE__ */ jsxs("div", { className: "ff-field", children: [
|
|
256
|
+
/* @__PURE__ */ jsxs("div", { className: "ff-checkbox-wrapper", children: [
|
|
257
|
+
/* @__PURE__ */ jsx(
|
|
258
|
+
"input",
|
|
259
|
+
{
|
|
260
|
+
...baseInputProps,
|
|
261
|
+
type: "checkbox",
|
|
262
|
+
className: "ff-checkbox",
|
|
263
|
+
checked: value ?? false,
|
|
264
|
+
onChange: (e) => onChange(e.target.checked)
|
|
265
|
+
}
|
|
266
|
+
),
|
|
267
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: id, className: "ff-checkbox-label", children: [
|
|
268
|
+
field.label,
|
|
269
|
+
required && /* @__PURE__ */ jsx("span", { className: "ff-required", children: "*" })
|
|
270
|
+
] })
|
|
271
|
+
] }),
|
|
272
|
+
error && /* @__PURE__ */ jsx("div", { id: `${id}-error`, className: "ff-field-error", role: "alert", children: error })
|
|
273
|
+
] });
|
|
274
|
+
case "radio":
|
|
275
|
+
return /* @__PURE__ */ jsxs("div", { className: "ff-field", children: [
|
|
276
|
+
/* @__PURE__ */ jsxs("div", { className: "ff-label", children: [
|
|
277
|
+
field.label,
|
|
278
|
+
required && /* @__PURE__ */ jsx("span", { className: "ff-required", children: "*" })
|
|
279
|
+
] }),
|
|
280
|
+
/* @__PURE__ */ jsx("div", { className: "ff-radio-group", role: "radiogroup", "aria-labelledby": id, children: field.options?.map((opt, i) => /* @__PURE__ */ jsxs("label", { className: "ff-radio-wrapper", children: [
|
|
281
|
+
/* @__PURE__ */ jsx(
|
|
282
|
+
"input",
|
|
283
|
+
{
|
|
284
|
+
type: "radio",
|
|
285
|
+
name: field.id,
|
|
286
|
+
value: opt,
|
|
287
|
+
className: "ff-radio",
|
|
288
|
+
checked: value === opt,
|
|
289
|
+
required: i === 0 && required,
|
|
290
|
+
onChange: () => onChange(opt)
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
/* @__PURE__ */ jsx("span", { className: "ff-radio-label", children: opt })
|
|
294
|
+
] }, opt)) }),
|
|
295
|
+
error && /* @__PURE__ */ jsx("div", { id: `${id}-error`, className: "ff-field-error", role: "alert", children: error })
|
|
296
|
+
] });
|
|
297
|
+
case "email":
|
|
298
|
+
input = /* @__PURE__ */ jsx(
|
|
299
|
+
"input",
|
|
300
|
+
{
|
|
301
|
+
...baseInputProps,
|
|
302
|
+
type: "email",
|
|
303
|
+
className: "ff-input",
|
|
304
|
+
placeholder: field.placeholder,
|
|
305
|
+
value: value ?? "",
|
|
306
|
+
onChange: (e) => onChange(e.target.value)
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
break;
|
|
310
|
+
case "phone":
|
|
311
|
+
input = /* @__PURE__ */ jsx(
|
|
312
|
+
"input",
|
|
313
|
+
{
|
|
314
|
+
...baseInputProps,
|
|
315
|
+
type: "tel",
|
|
316
|
+
className: "ff-input",
|
|
317
|
+
placeholder: field.placeholder,
|
|
318
|
+
value: value ?? "",
|
|
319
|
+
onChange: (e) => onChange(e.target.value)
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
break;
|
|
323
|
+
default:
|
|
324
|
+
input = /* @__PURE__ */ jsx(
|
|
325
|
+
"input",
|
|
326
|
+
{
|
|
327
|
+
...baseInputProps,
|
|
328
|
+
type: "text",
|
|
329
|
+
className: "ff-input",
|
|
330
|
+
placeholder: field.placeholder,
|
|
331
|
+
value: value ?? "",
|
|
332
|
+
onChange: (e) => onChange(e.target.value)
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
return /* @__PURE__ */ jsxs("div", { className: "ff-field", children: [
|
|
337
|
+
/* @__PURE__ */ jsxs("label", { htmlFor: id, className: "ff-label", children: [
|
|
338
|
+
field.label,
|
|
339
|
+
required && /* @__PURE__ */ jsx("span", { className: "ff-required", children: "*" })
|
|
340
|
+
] }),
|
|
341
|
+
input,
|
|
342
|
+
error && /* @__PURE__ */ jsx("div", { id: `${id}-error`, className: "ff-field-error", role: "alert", children: error })
|
|
343
|
+
] });
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/components/Form.tsx
|
|
347
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
348
|
+
function Form({
|
|
349
|
+
formId,
|
|
350
|
+
className = "",
|
|
351
|
+
submitText = "Submit",
|
|
352
|
+
submittingText = "Submitting...",
|
|
353
|
+
successTitle = "Thank you!",
|
|
354
|
+
successMessage,
|
|
355
|
+
loadingMessage = "Loading form...",
|
|
356
|
+
hideBadge = false,
|
|
357
|
+
children,
|
|
358
|
+
...options
|
|
359
|
+
}) {
|
|
360
|
+
const {
|
|
361
|
+
form,
|
|
362
|
+
fields,
|
|
363
|
+
values,
|
|
364
|
+
errors,
|
|
365
|
+
error,
|
|
366
|
+
status,
|
|
367
|
+
result,
|
|
368
|
+
setValue,
|
|
369
|
+
getFieldProps,
|
|
370
|
+
submit
|
|
371
|
+
} = useFixtureForm(formId, options);
|
|
372
|
+
if (status === "loading" || status === "idle") {
|
|
373
|
+
return /* @__PURE__ */ jsx2("div", { className: `ff-form ${className}`, children: /* @__PURE__ */ jsx2("div", { className: "ff-loading", children: loadingMessage }) });
|
|
374
|
+
}
|
|
375
|
+
if (status === "error" && !form) {
|
|
376
|
+
return /* @__PURE__ */ jsx2("div", { className: `ff-form ${className}`, children: /* @__PURE__ */ jsx2("div", { className: "ff-error", children: error }) });
|
|
377
|
+
}
|
|
378
|
+
if (status === "success") {
|
|
379
|
+
const message = successMessage || result?.successMessage || "Thank you for your submission!";
|
|
380
|
+
return /* @__PURE__ */ jsx2("div", { className: `ff-form ${className}`, children: /* @__PURE__ */ jsxs2("div", { className: "ff-success", children: [
|
|
381
|
+
/* @__PURE__ */ jsx2("div", { className: "ff-success-icon", children: /* @__PURE__ */ jsx2("svg", { fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx2(
|
|
382
|
+
"path",
|
|
383
|
+
{
|
|
384
|
+
strokeLinecap: "round",
|
|
385
|
+
strokeLinejoin: "round",
|
|
386
|
+
strokeWidth: 2,
|
|
387
|
+
d: "M5 13l4 4L19 7"
|
|
388
|
+
}
|
|
389
|
+
) }) }),
|
|
390
|
+
/* @__PURE__ */ jsx2("h2", { className: "ff-success-title", children: successTitle }),
|
|
391
|
+
/* @__PURE__ */ jsx2("p", { className: "ff-success-message", children: message })
|
|
392
|
+
] }) });
|
|
393
|
+
}
|
|
394
|
+
if (!form) {
|
|
395
|
+
return /* @__PURE__ */ jsx2("div", { className: `ff-form ${className}`, children: /* @__PURE__ */ jsx2("div", { className: "ff-error", children: "Form not found" }) });
|
|
396
|
+
}
|
|
397
|
+
if (children) {
|
|
398
|
+
return /* @__PURE__ */ jsx2("div", { className: `ff-form ${className}`, "data-form-id": form.id, children: children({
|
|
399
|
+
form,
|
|
400
|
+
fields,
|
|
401
|
+
values,
|
|
402
|
+
errors,
|
|
403
|
+
setValue,
|
|
404
|
+
getFieldProps,
|
|
405
|
+
submit,
|
|
406
|
+
status
|
|
407
|
+
}) });
|
|
408
|
+
}
|
|
409
|
+
const showBadge = !hideBadge && form.settings?.branding?.show_fixture_badge !== false;
|
|
410
|
+
const handleSubmit = (e) => {
|
|
411
|
+
e.preventDefault();
|
|
412
|
+
submit();
|
|
413
|
+
};
|
|
414
|
+
return /* @__PURE__ */ jsxs2("div", { className: `ff-form ${className}`, "data-form-id": form.id, children: [
|
|
415
|
+
(form.name || form.description) && /* @__PURE__ */ jsxs2("div", { className: "ff-form-header", children: [
|
|
416
|
+
form.name && /* @__PURE__ */ jsx2("h2", { className: "ff-form-title", children: form.name }),
|
|
417
|
+
form.description && /* @__PURE__ */ jsx2("p", { className: "ff-form-description", children: form.description })
|
|
418
|
+
] }),
|
|
419
|
+
/* @__PURE__ */ jsxs2("form", { className: "ff-form-element", onSubmit: handleSubmit, children: [
|
|
420
|
+
error && /* @__PURE__ */ jsx2("div", { className: "ff-error", role: "alert", children: error }),
|
|
421
|
+
fields.map((field) => /* @__PURE__ */ jsx2(
|
|
422
|
+
Field,
|
|
423
|
+
{
|
|
424
|
+
field,
|
|
425
|
+
value: values[field.id],
|
|
426
|
+
error: errors[field.id],
|
|
427
|
+
onChange: (value) => setValue(field.id, value)
|
|
428
|
+
},
|
|
429
|
+
field.id
|
|
430
|
+
)),
|
|
431
|
+
/* @__PURE__ */ jsx2(
|
|
432
|
+
"button",
|
|
433
|
+
{
|
|
434
|
+
type: "submit",
|
|
435
|
+
className: "ff-button",
|
|
436
|
+
disabled: status === "submitting",
|
|
437
|
+
children: status === "submitting" ? submittingText : submitText
|
|
438
|
+
}
|
|
439
|
+
)
|
|
440
|
+
] }),
|
|
441
|
+
showBadge && /* @__PURE__ */ jsx2("div", { className: "ff-badge", children: /* @__PURE__ */ jsx2(
|
|
442
|
+
"a",
|
|
443
|
+
{
|
|
444
|
+
href: "https://fixture.app",
|
|
445
|
+
target: "_blank",
|
|
446
|
+
rel: "noopener noreferrer",
|
|
447
|
+
children: "Powered by Fixture"
|
|
448
|
+
}
|
|
449
|
+
) })
|
|
450
|
+
] });
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/index.ts
|
|
454
|
+
import { FormClient as FormClient2 } from "@fixture-inc/forms-browser";
|
|
455
|
+
export {
|
|
456
|
+
Field,
|
|
457
|
+
FixtureFormsContext,
|
|
458
|
+
Form,
|
|
459
|
+
FormClient2 as FormClient,
|
|
460
|
+
useFixtureForm,
|
|
461
|
+
useFixtureFormsContext,
|
|
462
|
+
useVisitorId
|
|
463
|
+
};
|
|
464
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks.ts","../src/context.ts","../src/components/Field.tsx","../src/components/Form.tsx","../src/index.ts"],"sourcesContent":["/**\n * React hooks for Fixture Forms\n */\n\nimport { useState, useEffect, useCallback, useMemo, useRef } from 'react'\nimport {\n type Form,\n type FormField,\n type FormResponse,\n type SubmitResult,\n type FieldType,\n type FormStatus,\n type FieldValueMap,\n getDefaultValue,\n validateForm,\n errorsToRecord,\n} from '@fixture-inc/forms-core'\nimport { FormClient, normalizeError } from '@fixture-inc/forms-browser'\nimport { useFixtureFormsContext } from './context'\n\n/**\n * Options for useFixtureForm hook\n */\nexport interface UseFixtureFormOptions {\n /** API endpoint. Defaults to inferred from context or 'https://api.fixture.app' */\n apiUrl?: string\n\n /** Disable auto-fetching. Useful for SSR or conditional rendering. Default: true */\n enabled?: boolean\n\n /** Pre-populate with server-fetched data (for SSR hydration) */\n initialData?: { form: Form; nonce: string }\n\n /** Custom fetch function (for testing, SSR, or proxying) */\n fetcher?: (formId: string) => Promise<{ form: Form; nonce: string }>\n\n /** Enable debug logging */\n debug?: boolean\n\n /** Called on successful submission */\n onSuccess?: (result: SubmitResult) => void\n\n /** Called on any error */\n onError?: (error: { message: string }) => void\n}\n\n/**\n * Props for binding to form inputs\n */\nexport interface FieldInputProps {\n id: string\n name: string\n value: string | boolean\n onChange: (\n e: React.ChangeEvent<\n HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement\n >\n ) => void\n required?: boolean\n type?: string\n checked?: boolean\n}\n\n/**\n * Return type for useFixtureForm hook\n */\nexport interface UseFixtureFormReturn {\n // Form data\n /** Form definition (null while loading) */\n form: Form | null\n /** Form fields array (empty while loading) */\n fields: FormField[]\n\n // State\n /** Current form status */\n status: FormStatus\n /** Global error message */\n error: string | null\n /** Submission result (available after success) */\n result: SubmitResult | null\n\n // Field values\n /** Current field values. Use getFieldValue() for type-safe access. */\n values: Record<string, unknown>\n /** Field validation errors */\n errors: Record<string, string>\n\n // Type-safe value accessor\n /** Get field value with canonical type */\n getFieldValue: <T extends FieldType>(fieldId: string) => FieldValueMap[T] | undefined\n\n // Actions\n /** Set a single field value */\n setValue: (fieldId: string, value: unknown) => void\n /** Set multiple field values */\n setValues: (values: Record<string, unknown>) => void\n /** Submit the form */\n submit: () => Promise<void>\n /** Reset form to initial values */\n reset: () => void\n /** Refetch form from server */\n refetch: () => Promise<void>\n\n // Helpers\n /** Get props for binding to an input element */\n getFieldProps: (fieldId: string) => FieldInputProps\n}\n\n/**\n * Hook for using Fixture Forms in React\n *\n * @example\n * ```tsx\n * function ContactForm() {\n * const { form, fields, values, setValue, submit, status } = useFixtureForm('contact-form')\n *\n * if (status === 'loading') return <div>Loading...</div>\n * if (status === 'success') return <div>Thanks!</div>\n *\n * return (\n * <form onSubmit={(e) => { e.preventDefault(); submit(); }}>\n * {fields.map(field => (\n * <input\n * key={field.id}\n * {...getFieldProps(field.id)}\n * />\n * ))}\n * <button type=\"submit\" disabled={status === 'submitting'}>\n * Submit\n * </button>\n * </form>\n * )\n * }\n * ```\n */\nexport function useFixtureForm(\n formId: string,\n options: UseFixtureFormOptions = {}\n): UseFixtureFormReturn {\n const {\n apiUrl,\n enabled = true,\n initialData,\n fetcher,\n debug,\n onSuccess,\n onError,\n } = options\n\n // Get context if available\n const context = useFixtureFormsContext()\n\n // Create or reuse client\n const clientRef = useRef<FormClient | null>(null)\n if (!clientRef.current) {\n clientRef.current =\n context?.client ??\n new FormClient({\n apiUrl: apiUrl ?? context?.apiUrl,\n debug: debug ?? context?.debug,\n })\n }\n const client = clientRef.current\n\n // State\n const [status, setStatus] = useState<FormStatus>(\n initialData ? 'ready' : 'idle'\n )\n const [form, setForm] = useState<Form | null>(initialData?.form ?? null)\n const [nonce, setNonce] = useState<string | null>(initialData?.nonce ?? null)\n const [values, setValuesState] = useState<Record<string, unknown>>(() => {\n if (initialData?.form) {\n return initializeValues(initialData.form)\n }\n return {}\n })\n const [errors, setErrors] = useState<Record<string, string>>({})\n const [error, setError] = useState<string | null>(null)\n const [result, setResult] = useState<SubmitResult | null>(null)\n\n // Initialize values from form\n function initializeValues(formData: Form): Record<string, unknown> {\n const vals: Record<string, unknown> = {}\n for (const field of formData.fields) {\n vals[field.id] = getDefaultValue(field.type)\n }\n return vals\n }\n\n // Fetch form\n const fetchForm = useCallback(async () => {\n if (!formId) return\n\n setStatus('loading')\n setError(null)\n\n try {\n let response: FormResponse\n\n if (fetcher) {\n response = await fetcher(formId)\n } else {\n response = await client.fetchForm(formId)\n }\n\n setForm(response.form)\n setNonce(response.nonce)\n setValuesState(initializeValues(response.form))\n setErrors({})\n setStatus('ready')\n } catch (err) {\n const normalized = normalizeError(err)\n setError(normalized.message)\n setStatus('error')\n\n if (onError) {\n onError(normalized)\n }\n }\n }, [formId, client, fetcher, onError])\n\n // Auto-fetch on mount\n useEffect(() => {\n if (enabled && !initialData) {\n fetchForm()\n }\n }, [enabled, initialData, fetchForm])\n\n // Set single value\n const setValue = useCallback((fieldId: string, value: unknown) => {\n setValuesState((prev) => ({ ...prev, [fieldId]: value }))\n // Clear field error when value changes\n setErrors((prev) => {\n const next = { ...prev }\n delete next[fieldId]\n return next\n })\n }, [])\n\n // Set multiple values\n const setValuesFunc = useCallback((newValues: Record<string, unknown>) => {\n setValuesState((prev) => ({ ...prev, ...newValues }))\n }, [])\n\n // Get type-safe field value\n const getFieldValue = useCallback(\n <T extends FieldType>(fieldId: string): FieldValueMap[T] | undefined => {\n return values[fieldId] as FieldValueMap[T] | undefined\n },\n [values]\n )\n\n // Submit form\n const submit = useCallback(async () => {\n if (!form || !nonce) {\n setError('Form not loaded')\n return\n }\n\n // Validate\n const validationErrors = validateForm(\n form.fields,\n values as Record<string, string | boolean>\n )\n if (validationErrors.length > 0) {\n setErrors(errorsToRecord(validationErrors))\n return\n }\n\n setStatus('submitting')\n setError(null)\n\n try {\n const { result: submitResult, newNonce } = await client.submitWithRetry(\n formId,\n form,\n values,\n { nonce }\n )\n\n // Update nonce if refreshed\n if (newNonce) {\n setNonce(newNonce)\n }\n\n // Handle redirect\n if (submitResult.redirectUrl && typeof window !== 'undefined') {\n window.location.href = submitResult.redirectUrl\n return\n }\n\n setResult(submitResult)\n setStatus('success')\n\n if (onSuccess) {\n onSuccess(submitResult)\n }\n } catch (err) {\n const normalized = normalizeError(err)\n setError(normalized.message)\n setStatus('ready')\n\n if (onError) {\n onError(normalized)\n }\n }\n }, [form, nonce, values, formId, client, onSuccess, onError])\n\n // Reset form\n const reset = useCallback(() => {\n if (form) {\n setValuesState(initializeValues(form))\n }\n setErrors({})\n setError(null)\n setResult(null)\n setStatus(form ? 'ready' : 'idle')\n }, [form])\n\n // Get field props for easy binding\n const getFieldProps = useCallback(\n (fieldId: string): FieldInputProps => {\n const field = form?.fields.find((f) => f.id === fieldId)\n const value = values[fieldId]\n const isCheckbox = field?.type === 'checkbox'\n\n return {\n id: `ff-${fieldId}`,\n name: fieldId,\n value: isCheckbox ? 'true' : (value as string) ?? '',\n checked: isCheckbox ? (value as boolean) : undefined,\n required: field?.required,\n type: field?.type === 'email' ? 'email' : field?.type === 'phone' ? 'tel' : undefined,\n onChange: (e) => {\n if (isCheckbox) {\n setValue(fieldId, (e.target as HTMLInputElement).checked)\n } else {\n setValue(fieldId, e.target.value)\n }\n },\n }\n },\n [form, values, setValue]\n )\n\n // Memoize fields array\n const fields = useMemo(() => form?.fields ?? [], [form])\n\n return {\n form,\n fields,\n status,\n error,\n result,\n values,\n errors,\n getFieldValue,\n setValue,\n setValues: setValuesFunc,\n submit,\n reset,\n refetch: fetchForm,\n getFieldProps,\n }\n}\n\n/**\n * Hook to get the visitor ID from the forms tracker\n */\nexport function useVisitorId(): string | null {\n const [visitorId, setVisitorId] = useState<string | null>(null)\n\n useEffect(() => {\n // Import dynamically to avoid SSR issues\n import('@fixture-inc/forms-browser').then(({ getVisitorId }) => {\n setVisitorId(getVisitorId())\n })\n }, [])\n\n return visitorId\n}\n","/**\n * React context for Fixture Forms\n */\n\nimport { createContext, useContext } from 'react'\nimport type { FormClient } from '@fixture-inc/forms-browser'\n\n/**\n * Context value for the forms provider\n */\nexport interface FixtureFormsContextValue {\n /** Shared FormClient instance */\n client: FormClient\n /** Default API URL */\n apiUrl?: string\n /** Debug mode enabled */\n debug?: boolean\n}\n\n/**\n * Context for sharing FormClient across components\n */\nexport const FixtureFormsContext = createContext<FixtureFormsContextValue | null>(null)\n\n/**\n * Hook to access the forms context\n *\n * @returns Context value or null if not in provider\n */\nexport function useFixtureFormsContext(): FixtureFormsContextValue | null {\n return useContext(FixtureFormsContext)\n}\n","/**\n * Pre-built Field component\n *\n * Renders a single form field with appropriate input type and styling.\n */\n\nimport React from 'react'\nimport type { FormField } from '@fixture-inc/forms-core'\n\nexport interface FieldProps {\n /** Field definition */\n field: FormField\n /** Current value */\n value: unknown\n /** Validation error */\n error?: string\n /** Called when value changes */\n onChange: (value: unknown) => void\n}\n\n/**\n * Render a single form field\n */\nexport function Field({\n field,\n value,\n error,\n onChange,\n}: FieldProps): React.ReactElement {\n const id = `ff-${field.id}`\n const required = field.required\n\n // Common props for inputs\n const baseInputProps = {\n id,\n name: field.id,\n required,\n 'aria-invalid': error ? true : undefined,\n 'aria-describedby': error ? `${id}-error` : undefined,\n }\n\n // Render field based on type\n let input: React.ReactNode\n\n switch (field.type) {\n case 'textarea':\n input = (\n <textarea\n {...baseInputProps}\n className=\"ff-textarea\"\n placeholder={field.placeholder}\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n />\n )\n break\n\n case 'dropdown':\n input = (\n <select\n {...baseInputProps}\n className=\"ff-select\"\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n >\n <option value=\"\">Select...</option>\n {field.options?.map((opt) => (\n <option key={opt} value={opt}>\n {opt}\n </option>\n ))}\n </select>\n )\n break\n\n case 'checkbox':\n return (\n <div className=\"ff-field\">\n <div className=\"ff-checkbox-wrapper\">\n <input\n {...baseInputProps}\n type=\"checkbox\"\n className=\"ff-checkbox\"\n checked={(value as boolean) ?? false}\n onChange={(e) => onChange(e.target.checked)}\n />\n <label htmlFor={id} className=\"ff-checkbox-label\">\n {field.label}\n {required && <span className=\"ff-required\">*</span>}\n </label>\n </div>\n {error && (\n <div id={`${id}-error`} className=\"ff-field-error\" role=\"alert\">\n {error}\n </div>\n )}\n </div>\n )\n\n case 'radio':\n return (\n <div className=\"ff-field\">\n <div className=\"ff-label\">\n {field.label}\n {required && <span className=\"ff-required\">*</span>}\n </div>\n <div className=\"ff-radio-group\" role=\"radiogroup\" aria-labelledby={id}>\n {field.options?.map((opt, i) => (\n <label key={opt} className=\"ff-radio-wrapper\">\n <input\n type=\"radio\"\n name={field.id}\n value={opt}\n className=\"ff-radio\"\n checked={(value as string) === opt}\n required={i === 0 && required}\n onChange={() => onChange(opt)}\n />\n <span className=\"ff-radio-label\">{opt}</span>\n </label>\n ))}\n </div>\n {error && (\n <div id={`${id}-error`} className=\"ff-field-error\" role=\"alert\">\n {error}\n </div>\n )}\n </div>\n )\n\n case 'email':\n input = (\n <input\n {...baseInputProps}\n type=\"email\"\n className=\"ff-input\"\n placeholder={field.placeholder}\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n />\n )\n break\n\n case 'phone':\n input = (\n <input\n {...baseInputProps}\n type=\"tel\"\n className=\"ff-input\"\n placeholder={field.placeholder}\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n />\n )\n break\n\n default: // text\n input = (\n <input\n {...baseInputProps}\n type=\"text\"\n className=\"ff-input\"\n placeholder={field.placeholder}\n value={(value as string) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n />\n )\n }\n\n return (\n <div className=\"ff-field\">\n <label htmlFor={id} className=\"ff-label\">\n {field.label}\n {required && <span className=\"ff-required\">*</span>}\n </label>\n {input}\n {error && (\n <div id={`${id}-error`} className=\"ff-field-error\" role=\"alert\">\n {error}\n </div>\n )}\n </div>\n )\n}\n","/**\n * Pre-built Form component\n *\n * A complete, styled form component that handles loading, submission, and success states.\n */\n\nimport React from 'react'\nimport type { SubmitResult, Form as FormType } from '@fixture-inc/forms-core'\nimport { useFixtureForm, type UseFixtureFormOptions, type FieldInputProps } from '../hooks'\nimport { Field } from './Field'\n\nexport interface FormProps extends UseFixtureFormOptions {\n /** Form ID to render */\n formId: string\n /** Custom className for the form container */\n className?: string\n /** Custom submit button text */\n submitText?: string\n /** Custom submitting button text */\n submittingText?: string\n /** Custom success title */\n successTitle?: string\n /** Custom success message (overrides server response) */\n successMessage?: string\n /** Custom loading message */\n loadingMessage?: string\n /** Hide the \"Powered by Fixture\" badge */\n hideBadge?: boolean\n /** Custom render function for the form */\n children?: (props: {\n form: FormType\n fields: FormType['fields']\n values: Record<string, unknown>\n errors: Record<string, string>\n setValue: (fieldId: string, value: unknown) => void\n getFieldProps: (fieldId: string) => FieldInputProps\n submit: () => Promise<void>\n status: string\n }) => React.ReactNode\n}\n\n/**\n * Pre-built form component with default styling\n */\nexport function Form({\n formId,\n className = '',\n submitText = 'Submit',\n submittingText = 'Submitting...',\n successTitle = 'Thank you!',\n successMessage,\n loadingMessage = 'Loading form...',\n hideBadge = false,\n children,\n ...options\n}: FormProps): React.ReactElement {\n const {\n form,\n fields,\n values,\n errors,\n error,\n status,\n result,\n setValue,\n getFieldProps,\n submit,\n } = useFixtureForm(formId, options)\n\n // Loading state\n if (status === 'loading' || status === 'idle') {\n return (\n <div className={`ff-form ${className}`}>\n <div className=\"ff-loading\">{loadingMessage}</div>\n </div>\n )\n }\n\n // Error state (form failed to load)\n if (status === 'error' && !form) {\n return (\n <div className={`ff-form ${className}`}>\n <div className=\"ff-error\">{error}</div>\n </div>\n )\n }\n\n // Success state\n if (status === 'success') {\n const message =\n successMessage || result?.successMessage || 'Thank you for your submission!'\n return (\n <div className={`ff-form ${className}`}>\n <div className=\"ff-success\">\n <div className=\"ff-success-icon\">\n <svg fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n </div>\n <h2 className=\"ff-success-title\">{successTitle}</h2>\n <p className=\"ff-success-message\">{message}</p>\n </div>\n </div>\n )\n }\n\n // Form state\n if (!form) {\n return (\n <div className={`ff-form ${className}`}>\n <div className=\"ff-error\">Form not found</div>\n </div>\n )\n }\n\n // Custom render function\n if (children) {\n return (\n <div className={`ff-form ${className}`} data-form-id={form.id}>\n {children({\n form,\n fields,\n values,\n errors,\n setValue,\n getFieldProps,\n submit,\n status,\n })}\n </div>\n )\n }\n\n // Default render\n const showBadge =\n !hideBadge && form.settings?.branding?.show_fixture_badge !== false\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault()\n submit()\n }\n\n return (\n <div className={`ff-form ${className}`} data-form-id={form.id}>\n {(form.name || form.description) && (\n <div className=\"ff-form-header\">\n {form.name && <h2 className=\"ff-form-title\">{form.name}</h2>}\n {form.description && (\n <p className=\"ff-form-description\">{form.description}</p>\n )}\n </div>\n )}\n\n <form className=\"ff-form-element\" onSubmit={handleSubmit}>\n {error && (\n <div className=\"ff-error\" role=\"alert\">\n {error}\n </div>\n )}\n\n {fields.map((field) => (\n <Field\n key={field.id}\n field={field}\n value={values[field.id]}\n error={errors[field.id]}\n onChange={(value) => setValue(field.id, value)}\n />\n ))}\n\n <button\n type=\"submit\"\n className=\"ff-button\"\n disabled={status === 'submitting'}\n >\n {status === 'submitting' ? submittingText : submitText}\n </button>\n </form>\n\n {showBadge && (\n <div className=\"ff-badge\">\n <a\n href=\"https://fixture.app\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Powered by Fixture\n </a>\n </div>\n )}\n </div>\n )\n}\n","/**\n * @fixture-inc/forms-react\n *\n * React hooks and components for Fixture Forms.\n */\n\n// Hooks\nexport { useFixtureForm, useVisitorId } from './hooks'\nexport type { UseFixtureFormOptions, UseFixtureFormReturn, FieldInputProps } from './hooks'\n\n// Context\nexport { FixtureFormsContext, useFixtureFormsContext } from './context'\nexport type { FixtureFormsContextValue } from './context'\n\n// Components\nexport { Form, Field } from './components'\nexport type { FormProps, FieldProps } from './components'\n\n// Re-export commonly used types from core\nexport type {\n Form as FormType,\n FormField,\n FormResponse,\n SubmitResult,\n FieldType,\n FormStatus,\n NormalizedError,\n} from '@fixture-inc/forms-core'\n\n// Re-export client for advanced usage\nexport { FormClient } from '@fixture-inc/forms-browser'\nexport type { FormClientConfig } from '@fixture-inc/forms-browser'\n"],"mappings":"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","names":["jsx","jsxs","FormClient"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fixture-inc/forms-react",
|
|
3
|
+
"version": "0.1.0-beta.1",
|
|
4
|
+
"description": "React hooks and components for Fixture Forms",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@fixture-inc/forms-core": "0.1.0-beta.1",
|
|
26
|
+
"@fixture-inc/forms-browser": "0.1.0-beta.1"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"react": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@testing-library/react": "^16.0.0",
|
|
33
|
+
"@types/react": "^19.0.0",
|
|
34
|
+
"jsdom": "^26.0.0",
|
|
35
|
+
"react": "^19.0.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"typescript": "^5.0.0",
|
|
38
|
+
"vitest": "^4.0.0"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"license": "MIT",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "git+https://github.com/fixture-inc/web.git",
|
|
47
|
+
"directory": "packages/forms-react"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"dev": "tsup --watch",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"test:watch": "vitest",
|
|
54
|
+
"typecheck": "tsc --noEmit -p tsconfig.typecheck.json"
|
|
55
|
+
}
|
|
56
|
+
}
|