@usefillo/react 0.8.0 → 0.9.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.d.ts +14 -1
- package/dist/index.js +246 -72
- package/dist/styles.css +18 -0
- package/dist/styles.unlayered.css +18 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ReactNode, ReactElement } from 'react';
|
|
3
3
|
import * as _usefillo_core from '@usefillo/core';
|
|
4
|
-
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloAppearance, FilloRendererStrings, FilloRespondent, FilloError, CodeForm, FormSettings, Condition, TextField, PhoneField, NumberField, ChoiceField, SelectOption, CheckboxField, RatingField, LinearScaleField, RankingField, SignatureField, DateField, FileUploadField as FileUploadField$1, HiddenField } from '@usefillo/core';
|
|
4
|
+
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloAppearance, FilloRendererStrings, FilloRespondent, ChallengeConfig, FilloError, CodeForm, FormSettings, Condition, TextField, PhoneField, NumberField, ChoiceField, SelectOption, CheckboxField, RatingField, LinearScaleField, RankingField, SignatureField, DateField, FileUploadField as FileUploadField$1, HiddenField } from '@usefillo/core';
|
|
5
5
|
export { CodeForm, Field, FieldValue, FileValue, FilloAppearance, FilloClient, FilloError, FilloJsxError, FilloRendererStrings, FilloSlot, FilloStrings, FormSchema, FormStatus, FormTheme, ProvisionWorkspaceResult, PublishedForm, ResponseData, SlotState, createClient, defineForm, provisionWorkspace, when } from '@usefillo/core';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -136,6 +136,13 @@ interface FilloFormBaseProps {
|
|
|
136
136
|
* loads).
|
|
137
137
|
*/
|
|
138
138
|
respondent?: FilloRespondent;
|
|
139
|
+
/**
|
|
140
|
+
* Human-verification challenge config (public site key + provider). Normally
|
|
141
|
+
* the SDK reads this from the form fetch automatically; pass it explicitly
|
|
142
|
+
* only when you render an inline `form` schema and still want the widget (the
|
|
143
|
+
* hosted page does this). The SECRET key stays server-side — never passed here.
|
|
144
|
+
*/
|
|
145
|
+
challenge?: ChallengeConfig;
|
|
139
146
|
onChange?: (data: ResponseData) => void;
|
|
140
147
|
onSubmitted?: (responseId: string | undefined, data: ResponseData) => void;
|
|
141
148
|
/** Observe load and code-form sync failures (otherwise only logged). */
|
|
@@ -286,6 +293,12 @@ interface ControllerOptions {
|
|
|
286
293
|
* dashboard, webhooks, and integrations can say who answered.
|
|
287
294
|
*/
|
|
288
295
|
respondent?: FilloRespondent;
|
|
296
|
+
/** True when the form requires a human-verification challenge (Turnstile). */
|
|
297
|
+
challengeRequired?: boolean;
|
|
298
|
+
/** Read the current challenge token from the rendered widget (lazy). */
|
|
299
|
+
getChallengeToken?: () => string | undefined;
|
|
300
|
+
/** The server rejected the challenge — reset the widget for a fresh token. */
|
|
301
|
+
onChallengeFailed?: () => void;
|
|
289
302
|
}
|
|
290
303
|
/**
|
|
291
304
|
* React binding for the framework-agnostic engine in @usefillo/core
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/FilloForm.tsx
|
|
4
|
-
import { useEffect as
|
|
4
|
+
import { useCallback, useEffect as useEffect8, useId as useId2, useMemo as useMemo5, useRef as useRef7, useState as useState6 } from "react";
|
|
5
5
|
import {
|
|
6
6
|
FilloError as FilloError2,
|
|
7
7
|
createClient,
|
|
@@ -10,7 +10,8 @@ import {
|
|
|
10
10
|
needsExplicitSubmit,
|
|
11
11
|
normalizeFormSchema,
|
|
12
12
|
normalizeFormTheme,
|
|
13
|
-
|
|
13
|
+
reachableFields,
|
|
14
|
+
reachablePageSequence
|
|
14
15
|
} from "@usefillo/core";
|
|
15
16
|
import { resolveStrings, slotClass as slotClass3 } from "@usefillo/core";
|
|
16
17
|
|
|
@@ -127,7 +128,12 @@ function useFilloController(options) {
|
|
|
127
128
|
surface: options.surface ?? "headless",
|
|
128
129
|
// Wrapped so the engine (created once) always calls the latest resolver.
|
|
129
130
|
resolveFormId: options.resolveFormId ? () => optsRef.current.resolveFormId() : void 0,
|
|
130
|
-
respondent: options.respondent
|
|
131
|
+
respondent: options.respondent,
|
|
132
|
+
// Challenge wiring read through optsRef so the engine (created once) sees
|
|
133
|
+
// the latest token/reset each submit — the widget solves after mount.
|
|
134
|
+
challengeRequired: options.challengeRequired,
|
|
135
|
+
getChallengeToken: () => optsRef.current.getChallengeToken?.(),
|
|
136
|
+
onChallengeFailed: () => optsRef.current.onChallengeFailed?.()
|
|
131
137
|
});
|
|
132
138
|
}
|
|
133
139
|
const store = storeRef.current;
|
|
@@ -276,6 +282,7 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
276
282
|
formId: r.formId,
|
|
277
283
|
status: r.status ?? null,
|
|
278
284
|
branding: r.branding,
|
|
285
|
+
challenge: r.challenge,
|
|
279
286
|
error: null,
|
|
280
287
|
noticeError,
|
|
281
288
|
staged: Boolean(r.staged),
|
|
@@ -325,6 +332,7 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
325
332
|
formId: synced.formId,
|
|
326
333
|
status: synced.status,
|
|
327
334
|
branding: synced.branding,
|
|
335
|
+
challenge: synced.challenge,
|
|
328
336
|
error: synced.error,
|
|
329
337
|
noticeError: synced.noticeError,
|
|
330
338
|
syncing: Boolean(syncKey) && !synced.settled,
|
|
@@ -1899,8 +1907,127 @@ function FormField({
|
|
|
1899
1907
|
);
|
|
1900
1908
|
}
|
|
1901
1909
|
|
|
1910
|
+
// src/turnstile.tsx
|
|
1911
|
+
import { useEffect as useEffect7, useRef as useRef6 } from "react";
|
|
1912
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1913
|
+
var SCRIPT_SRC = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
|
|
1914
|
+
var SCRIPT_ID = "fillo-turnstile-script";
|
|
1915
|
+
var scriptPromise = null;
|
|
1916
|
+
function turnstileGlobal() {
|
|
1917
|
+
return globalThis.turnstile;
|
|
1918
|
+
}
|
|
1919
|
+
function loadTurnstileScript() {
|
|
1920
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
1921
|
+
return Promise.reject(new Error("Turnstile needs a browser"));
|
|
1922
|
+
}
|
|
1923
|
+
if (turnstileGlobal()) return Promise.resolve();
|
|
1924
|
+
if (scriptPromise) return scriptPromise;
|
|
1925
|
+
scriptPromise = new Promise((resolve, reject) => {
|
|
1926
|
+
const onReady = () => {
|
|
1927
|
+
if (turnstileGlobal()) resolve();
|
|
1928
|
+
else reject(new Error("Turnstile loaded without its global"));
|
|
1929
|
+
};
|
|
1930
|
+
const existing = document.getElementById(SCRIPT_ID);
|
|
1931
|
+
if (existing) {
|
|
1932
|
+
if (turnstileGlobal()) {
|
|
1933
|
+
resolve();
|
|
1934
|
+
return;
|
|
1935
|
+
}
|
|
1936
|
+
existing.addEventListener("load", onReady, { once: true });
|
|
1937
|
+
existing.addEventListener(
|
|
1938
|
+
"error",
|
|
1939
|
+
() => reject(new Error("Turnstile script failed to load")),
|
|
1940
|
+
{ once: true }
|
|
1941
|
+
);
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1944
|
+
const script = document.createElement("script");
|
|
1945
|
+
script.id = SCRIPT_ID;
|
|
1946
|
+
script.src = SCRIPT_SRC;
|
|
1947
|
+
script.async = true;
|
|
1948
|
+
script.defer = true;
|
|
1949
|
+
script.addEventListener("load", onReady, { once: true });
|
|
1950
|
+
script.addEventListener(
|
|
1951
|
+
"error",
|
|
1952
|
+
() => {
|
|
1953
|
+
script.remove();
|
|
1954
|
+
scriptPromise = null;
|
|
1955
|
+
reject(new Error("Turnstile script failed to load"));
|
|
1956
|
+
},
|
|
1957
|
+
{ once: true }
|
|
1958
|
+
);
|
|
1959
|
+
document.head.appendChild(script);
|
|
1960
|
+
});
|
|
1961
|
+
return scriptPromise;
|
|
1962
|
+
}
|
|
1963
|
+
function TurnstileWidget({
|
|
1964
|
+
siteKey,
|
|
1965
|
+
onToken,
|
|
1966
|
+
onError,
|
|
1967
|
+
registerReset,
|
|
1968
|
+
className
|
|
1969
|
+
}) {
|
|
1970
|
+
const containerRef = useRef6(null);
|
|
1971
|
+
const widgetIdRef = useRef6(null);
|
|
1972
|
+
const onTokenRef = useRef6(onToken);
|
|
1973
|
+
onTokenRef.current = onToken;
|
|
1974
|
+
const onErrorRef = useRef6(onError);
|
|
1975
|
+
onErrorRef.current = onError;
|
|
1976
|
+
const registerResetRef = useRef6(registerReset);
|
|
1977
|
+
registerResetRef.current = registerReset;
|
|
1978
|
+
useEffect7(() => {
|
|
1979
|
+
let cancelled = false;
|
|
1980
|
+
loadTurnstileScript().then(() => {
|
|
1981
|
+
if (cancelled || !containerRef.current) return;
|
|
1982
|
+
const api = turnstileGlobal();
|
|
1983
|
+
if (!api) {
|
|
1984
|
+
onErrorRef.current?.();
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
const clearAndReset = () => {
|
|
1988
|
+
onTokenRef.current(void 0);
|
|
1989
|
+
if (widgetIdRef.current) api.reset(widgetIdRef.current);
|
|
1990
|
+
};
|
|
1991
|
+
widgetIdRef.current = api.render(containerRef.current, {
|
|
1992
|
+
sitekey: siteKey,
|
|
1993
|
+
theme: "auto",
|
|
1994
|
+
callback: (token) => onTokenRef.current(token),
|
|
1995
|
+
"error-callback": () => {
|
|
1996
|
+
onTokenRef.current(void 0);
|
|
1997
|
+
onErrorRef.current?.();
|
|
1998
|
+
},
|
|
1999
|
+
"expired-callback": clearAndReset,
|
|
2000
|
+
"timeout-callback": clearAndReset
|
|
2001
|
+
});
|
|
2002
|
+
registerResetRef.current?.(clearAndReset);
|
|
2003
|
+
}).catch(() => {
|
|
2004
|
+
if (!cancelled) onErrorRef.current?.();
|
|
2005
|
+
});
|
|
2006
|
+
return () => {
|
|
2007
|
+
cancelled = true;
|
|
2008
|
+
const api = turnstileGlobal();
|
|
2009
|
+
if (widgetIdRef.current && api) {
|
|
2010
|
+
try {
|
|
2011
|
+
api.remove(widgetIdRef.current);
|
|
2012
|
+
} catch {
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
widgetIdRef.current = null;
|
|
2016
|
+
onTokenRef.current(void 0);
|
|
2017
|
+
};
|
|
2018
|
+
}, [siteKey]);
|
|
2019
|
+
return /* @__PURE__ */ jsx5(
|
|
2020
|
+
"div",
|
|
2021
|
+
{
|
|
2022
|
+
ref: containerRef,
|
|
2023
|
+
className,
|
|
2024
|
+
"data-fillo": "turnstile"
|
|
2025
|
+
}
|
|
2026
|
+
);
|
|
2027
|
+
}
|
|
2028
|
+
|
|
1902
2029
|
// src/FilloForm.tsx
|
|
1903
|
-
import { Fragment as Fragment2, jsx as
|
|
2030
|
+
import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1904
2031
|
function themeProps(theme) {
|
|
1905
2032
|
const safeTheme = normalizeFormTheme(theme);
|
|
1906
2033
|
if (!safeTheme) return {};
|
|
@@ -1973,6 +2100,7 @@ function FilloForm(props) {
|
|
|
1973
2100
|
formId: syncedFormId,
|
|
1974
2101
|
status: syncedStatus,
|
|
1975
2102
|
branding: syncedBranding,
|
|
2103
|
+
challenge: syncedChallenge,
|
|
1976
2104
|
error: syncError,
|
|
1977
2105
|
noticeError: syncNoticeError,
|
|
1978
2106
|
syncing: codeFormSyncing,
|
|
@@ -1986,12 +2114,12 @@ function FilloForm(props) {
|
|
|
1986
2114
|
});
|
|
1987
2115
|
const renderResolvedSnapshot = Boolean(resolvedSchema && !isDevEnv());
|
|
1988
2116
|
const inlineSchema = codeForm ? renderResolvedSnapshot ? resolvedSchema : codeForm.schema : form;
|
|
1989
|
-
const onErrorRef =
|
|
1990
|
-
|
|
2117
|
+
const onErrorRef = useRef7(onError);
|
|
2118
|
+
useEffect8(() => {
|
|
1991
2119
|
onErrorRef.current = onError;
|
|
1992
2120
|
});
|
|
1993
2121
|
const needsFetch = !inlineSchema && Boolean(client && formId);
|
|
1994
|
-
|
|
2122
|
+
useEffect8(() => {
|
|
1995
2123
|
if (!needsFetch || !client || !formId) {
|
|
1996
2124
|
setLoaded(null);
|
|
1997
2125
|
setLoadFailure(null);
|
|
@@ -2007,7 +2135,8 @@ function FilloForm(props) {
|
|
|
2007
2135
|
schema: published.schema,
|
|
2008
2136
|
theme: published.theme,
|
|
2009
2137
|
closed: Boolean(published.closed),
|
|
2010
|
-
branding: published.branding ?? null
|
|
2138
|
+
branding: published.branding ?? null,
|
|
2139
|
+
challenge: published.challenge ?? null
|
|
2011
2140
|
});
|
|
2012
2141
|
}).catch((err) => {
|
|
2013
2142
|
if (cancelled) return;
|
|
@@ -2029,25 +2158,25 @@ function FilloForm(props) {
|
|
|
2029
2158
|
const theme = props.appearance?.theme ?? props.theme ?? resolvedCodeTheme ?? currentLoaded?.theme ?? void 0;
|
|
2030
2159
|
if (normalized && !normalized.ok) {
|
|
2031
2160
|
const error = new FilloError2(`This form could not be rendered: ${normalized.error}`, 422);
|
|
2032
|
-
if (props.renderError) return /* @__PURE__ */
|
|
2033
|
-
return /* @__PURE__ */
|
|
2161
|
+
if (props.renderError) return /* @__PURE__ */ jsx6(Fragment2, { children: props.renderError(error) });
|
|
2162
|
+
return /* @__PURE__ */ jsx6("div", { className: `fillo-form fillo-form--error ${props.className ?? ""}`, children: strings.renderFailed });
|
|
2034
2163
|
}
|
|
2035
2164
|
if (loadError) {
|
|
2036
2165
|
if (props.renderError) {
|
|
2037
|
-
return /* @__PURE__ */
|
|
2166
|
+
return /* @__PURE__ */ jsx6(Fragment2, { children: props.renderError(loadError) });
|
|
2038
2167
|
}
|
|
2039
2168
|
const message = loadError.status === 404 ? strings.loadFailedNotFound : loadError.status === 0 ? strings.loadFailedNetwork : strings.loadFailed;
|
|
2040
|
-
return /* @__PURE__ */
|
|
2169
|
+
return /* @__PURE__ */ jsx6("div", { className: `fillo-form fillo-form--error ${props.className ?? ""}`, children: message });
|
|
2041
2170
|
}
|
|
2042
2171
|
if (currentLoaded?.closed) {
|
|
2043
|
-
return /* @__PURE__ */
|
|
2172
|
+
return /* @__PURE__ */ jsx6("div", { className: `fillo-form fillo-form--closed ${props.className ?? ""}`, ...themeProps(theme), children: /* @__PURE__ */ jsx6("p", { className: "fillo-closed", children: strings.closed }) });
|
|
2044
2173
|
}
|
|
2045
2174
|
const canonicalSyncError = codeForm && syncError && !props.skipValidation ? syncError : null;
|
|
2046
2175
|
if (canonicalSyncError && props.renderError) {
|
|
2047
|
-
return /* @__PURE__ */
|
|
2176
|
+
return /* @__PURE__ */ jsx6(Fragment2, { children: props.renderError(canonicalSyncError) });
|
|
2048
2177
|
}
|
|
2049
2178
|
if (canonicalSyncError && !isDevEnv()) {
|
|
2050
|
-
return /* @__PURE__ */
|
|
2179
|
+
return /* @__PURE__ */ jsx6(
|
|
2051
2180
|
"div",
|
|
2052
2181
|
{
|
|
2053
2182
|
className: `fillo-form fillo-form--error ${props.className ?? ""}`,
|
|
@@ -2062,8 +2191,8 @@ function FilloForm(props) {
|
|
|
2062
2191
|
const notPublished = Boolean(codeForm) && syncedStatus === "draft" && !props.skipValidation;
|
|
2063
2192
|
if (notPublished && !isDevEnv()) {
|
|
2064
2193
|
const error = new FilloError2("This form isn't published yet.", 403);
|
|
2065
|
-
if (props.renderError) return /* @__PURE__ */
|
|
2066
|
-
return /* @__PURE__ */
|
|
2194
|
+
if (props.renderError) return /* @__PURE__ */ jsx6(Fragment2, { children: props.renderError(error) });
|
|
2195
|
+
return /* @__PURE__ */ jsx6("div", { className: `fillo-form fillo-form--closed ${props.className ?? ""}`, ...themeProps(theme), children: /* @__PURE__ */ jsx6("p", { className: "fillo-closed", children: strings.notLive }) });
|
|
2067
2196
|
}
|
|
2068
2197
|
const awaitingCanonical = Boolean(codeForm && codeFormSyncing && !props.skipValidation);
|
|
2069
2198
|
if (!isDevEnv() && awaitingCanonical || !schema) {
|
|
@@ -2074,16 +2203,17 @@ function FilloForm(props) {
|
|
|
2074
2203
|
"aria-busy": "true",
|
|
2075
2204
|
...themeProps(theme),
|
|
2076
2205
|
children: [
|
|
2077
|
-
/* @__PURE__ */
|
|
2078
|
-
/* @__PURE__ */
|
|
2079
|
-
/* @__PURE__ */
|
|
2206
|
+
/* @__PURE__ */ jsx6("div", { className: "fillo-skeleton" }),
|
|
2207
|
+
/* @__PURE__ */ jsx6("div", { className: "fillo-skeleton" }),
|
|
2208
|
+
/* @__PURE__ */ jsx6("div", { className: "fillo-skeleton fillo-skeleton--short" })
|
|
2080
2209
|
]
|
|
2081
2210
|
}
|
|
2082
2211
|
);
|
|
2083
2212
|
}
|
|
2084
2213
|
const branding = codeForm ? syncedBranding : currentLoaded?.branding;
|
|
2085
2214
|
const poweredBy = branding?.poweredBy ?? true;
|
|
2086
|
-
|
|
2215
|
+
const challenge = props.challenge ?? (codeForm ? syncedChallenge : currentLoaded?.challenge) ?? void 0;
|
|
2216
|
+
return /* @__PURE__ */ jsx6(
|
|
2087
2217
|
ResolvedForm,
|
|
2088
2218
|
{
|
|
2089
2219
|
...props,
|
|
@@ -2096,33 +2226,34 @@ function FilloForm(props) {
|
|
|
2096
2226
|
brandHref: branding?.href,
|
|
2097
2227
|
draftNotice: notPublished,
|
|
2098
2228
|
stagedNotice: codeChangesStaged,
|
|
2099
|
-
syncErrorNotice: syncError ?? syncNoticeError ?? void 0
|
|
2229
|
+
syncErrorNotice: syncError ?? syncNoticeError ?? void 0,
|
|
2230
|
+
challenge
|
|
2100
2231
|
}
|
|
2101
2232
|
);
|
|
2102
2233
|
}
|
|
2103
2234
|
function PoweredBy({ label, href }) {
|
|
2104
|
-
return /* @__PURE__ */
|
|
2235
|
+
return /* @__PURE__ */ jsx6("a", { className: "fillo-powered", href: badgeUrl(href), target: "_blank", rel: "noopener noreferrer", children: label ?? "Powered by Fillo" });
|
|
2105
2236
|
}
|
|
2106
2237
|
function isDevEnv() {
|
|
2107
2238
|
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
2108
2239
|
}
|
|
2109
2240
|
function DevNoClientNotice() {
|
|
2110
2241
|
return /* @__PURE__ */ jsxs5("div", { className: "fillo-devwarning", role: "alert", children: [
|
|
2111
|
-
/* @__PURE__ */
|
|
2242
|
+
/* @__PURE__ */ jsx6("strong", { children: "No Fillo client connected." }),
|
|
2112
2243
|
" This form is render-only and won\u2019t save responses. Pass a ",
|
|
2113
|
-
/* @__PURE__ */
|
|
2244
|
+
/* @__PURE__ */ jsx6("code", { children: "client" }),
|
|
2114
2245
|
" to collect them in Fillo, or forward them with webhooks. (This notice only appears in development.)"
|
|
2115
2246
|
] });
|
|
2116
2247
|
}
|
|
2117
2248
|
function DevDraftNotice() {
|
|
2118
2249
|
return /* @__PURE__ */ jsxs5("div", { className: "fillo-devwarning", role: "alert", children: [
|
|
2119
|
-
/* @__PURE__ */
|
|
2250
|
+
/* @__PURE__ */ jsx6("strong", { children: "Draft form." }),
|
|
2120
2251
|
" It renders here, but it won\u2019t accept responses until you publish it in your Fillo dashboard. (This notice only appears in development.)"
|
|
2121
2252
|
] });
|
|
2122
2253
|
}
|
|
2123
2254
|
function DevStagedNotice() {
|
|
2124
2255
|
return /* @__PURE__ */ jsxs5("div", { className: "fillo-devwarning", role: "alert", children: [
|
|
2125
|
-
/* @__PURE__ */
|
|
2256
|
+
/* @__PURE__ */ jsx6("strong", { children: "Code changes are staged." }),
|
|
2126
2257
|
" This local preview is not the live form yet. Publish the changes in Fillo before deploying them for respondents."
|
|
2127
2258
|
] });
|
|
2128
2259
|
}
|
|
@@ -2141,9 +2272,23 @@ function DevSyncErrorNotice({ error }) {
|
|
|
2141
2272
|
function ResolvedForm(props) {
|
|
2142
2273
|
const { schema, theme } = props;
|
|
2143
2274
|
const instanceId = useId2().replace(/:/g, "");
|
|
2144
|
-
const hpRef =
|
|
2275
|
+
const hpRef = useRef7(null);
|
|
2145
2276
|
const codeForm = isCodeForm2(props.form) ? props.form : null;
|
|
2146
2277
|
const client = props.client;
|
|
2278
|
+
const challenge = props.challenge;
|
|
2279
|
+
const challengeRequired = Boolean(challenge);
|
|
2280
|
+
const challengeTokenRef = useRef7(void 0);
|
|
2281
|
+
const [challengeToken, setChallengeToken] = useState6(void 0);
|
|
2282
|
+
const [challengeError, setChallengeError] = useState6(false);
|
|
2283
|
+
const resetChallengeRef = useRef7(void 0);
|
|
2284
|
+
const handleChallengeToken = useCallback((token) => {
|
|
2285
|
+
challengeTokenRef.current = token;
|
|
2286
|
+
setChallengeToken(token);
|
|
2287
|
+
if (token) setChallengeError(false);
|
|
2288
|
+
}, []);
|
|
2289
|
+
const registerChallengeReset = useCallback((reset) => {
|
|
2290
|
+
resetChallengeRef.current = reset;
|
|
2291
|
+
}, []);
|
|
2147
2292
|
const resolveFormId = useMemo5(
|
|
2148
2293
|
() => codeForm && client?.key ? (
|
|
2149
2294
|
// bypassCache: a stale cached formId must not be trusted at submit time.
|
|
@@ -2213,25 +2358,31 @@ function ResolvedForm(props) {
|
|
|
2213
2358
|
// "default", never the bare-engine "headless".
|
|
2214
2359
|
surface: "default",
|
|
2215
2360
|
resolveFormId,
|
|
2216
|
-
respondent: props.respondent
|
|
2361
|
+
respondent: props.respondent,
|
|
2362
|
+
challengeRequired,
|
|
2363
|
+
getChallengeToken: () => challengeTokenRef.current,
|
|
2364
|
+
onChallengeFailed: () => {
|
|
2365
|
+
handleChallengeToken(void 0);
|
|
2366
|
+
resetChallengeRef.current?.();
|
|
2367
|
+
}
|
|
2217
2368
|
});
|
|
2218
2369
|
useDraftFlush(api);
|
|
2219
2370
|
const themed = useMemo5(() => themeProps(theme), [theme]);
|
|
2220
2371
|
const settings = schema.settings;
|
|
2221
2372
|
const submitted = api.status === "submitted";
|
|
2222
2373
|
const liveSubmit = submitted && !api.restoredSubmission;
|
|
2223
|
-
|
|
2374
|
+
useEffect8(() => {
|
|
2224
2375
|
if (!liveSubmit || !settings.redirectUrl || typeof window === "undefined") return;
|
|
2225
2376
|
const url = safeHttpUrl(settings.redirectUrl);
|
|
2226
2377
|
if (url) window.location.assign(url);
|
|
2227
2378
|
}, [liveSubmit, settings.redirectUrl]);
|
|
2228
|
-
const successRef =
|
|
2229
|
-
|
|
2379
|
+
const successRef = useRef7(null);
|
|
2380
|
+
useEffect8(() => {
|
|
2230
2381
|
if (liveSubmit) successRef.current?.focus();
|
|
2231
2382
|
}, [liveSubmit]);
|
|
2232
|
-
const blocksRef =
|
|
2233
|
-
const prevPageIndex =
|
|
2234
|
-
|
|
2383
|
+
const blocksRef = useRef7(null);
|
|
2384
|
+
const prevPageIndex = useRef7(api.pageIndex);
|
|
2385
|
+
useEffect8(() => {
|
|
2235
2386
|
if (prevPageIndex.current === api.pageIndex) return;
|
|
2236
2387
|
prevPageIndex.current = api.pageIndex;
|
|
2237
2388
|
blocksRef.current?.focus();
|
|
@@ -2261,22 +2412,29 @@ function ResolvedForm(props) {
|
|
|
2261
2412
|
className: slotClass3("fillo-success", appearance, { slot: "success", status: "submitted" }),
|
|
2262
2413
|
"data-fillo": "success",
|
|
2263
2414
|
children: [
|
|
2264
|
-
/* @__PURE__ */
|
|
2265
|
-
/* @__PURE__ */
|
|
2266
|
-
/* @__PURE__ */
|
|
2415
|
+
/* @__PURE__ */ jsx6("div", { className: "fillo-success-mark", "aria-hidden": "true", children: "\u2713" }),
|
|
2416
|
+
/* @__PURE__ */ jsx6("h2", { className: "fillo-success-title", children: settings.successTitle ?? strings.successTitle }),
|
|
2417
|
+
/* @__PURE__ */ jsx6("p", { className: "fillo-success-message", children: api.duplicateSubmission ? strings.alreadyAnswered : settings.successMessage ?? strings.successMessage })
|
|
2267
2418
|
]
|
|
2268
2419
|
}
|
|
2269
2420
|
),
|
|
2270
|
-
props.poweredBy && /* @__PURE__ */
|
|
2421
|
+
props.poweredBy && /* @__PURE__ */ jsx6(PoweredBy, { label: props.brandLabel, href: props.brandHref })
|
|
2271
2422
|
]
|
|
2272
2423
|
}
|
|
2273
2424
|
);
|
|
2274
2425
|
}
|
|
2275
2426
|
const multiPage = api.pageCount > 1;
|
|
2276
2427
|
const autoSubmit = settings.submitMode === "auto";
|
|
2277
|
-
const
|
|
2428
|
+
const showChallenge = challengeRequired && api.isLastPage;
|
|
2429
|
+
const showPrimaryButton = !autoSubmit || !api.isLastPage || needsExplicitSubmit(reachableFields(api.form, api.data)) || // A challenge needs an explicit Submit even on an otherwise button-less
|
|
2430
|
+
// auto-submit form — you can't one-tap past a human check.
|
|
2431
|
+
showChallenge;
|
|
2278
2432
|
const showFooter = showPrimaryButton || multiPage && !api.isFirstPage;
|
|
2279
|
-
|
|
2433
|
+
const progressSeq = reachablePageSequence(api.form, api.data);
|
|
2434
|
+
const progressTotal = Math.max(progressSeq.length, 1);
|
|
2435
|
+
const progressPos = progressSeq.indexOf(api.page.id);
|
|
2436
|
+
const progressStep = progressPos >= 0 ? progressPos + 1 : Math.min(api.pageIndex + 1, progressTotal);
|
|
2437
|
+
return /* @__PURE__ */ jsx6(FilloContext.Provider, { value: api, children: /* @__PURE__ */ jsx6(FilloStringsContext.Provider, { value: strings, children: /* @__PURE__ */ jsx6(FilloAppearanceContext.Provider, { value: appearance, children: /* @__PURE__ */ jsx6(FilloInstanceIdContext.Provider, { value: instanceId, children: /* @__PURE__ */ jsxs5(
|
|
2280
2438
|
"form",
|
|
2281
2439
|
{
|
|
2282
2440
|
className: slotClass3(`fillo-form ${props.className ?? ""}`, appearance, {
|
|
@@ -2301,10 +2459,10 @@ function ResolvedForm(props) {
|
|
|
2301
2459
|
}
|
|
2302
2460
|
},
|
|
2303
2461
|
children: [
|
|
2304
|
-
!props.client && !props.skipValidation && isDevEnv() && /* @__PURE__ */
|
|
2305
|
-
props.draftNotice && isDevEnv() && /* @__PURE__ */
|
|
2306
|
-
props.stagedNotice && isDevEnv() && /* @__PURE__ */
|
|
2307
|
-
props.syncErrorNotice && isDevEnv() && /* @__PURE__ */
|
|
2462
|
+
!props.client && !props.skipValidation && isDevEnv() && /* @__PURE__ */ jsx6(DevNoClientNotice, {}),
|
|
2463
|
+
props.draftNotice && isDevEnv() && /* @__PURE__ */ jsx6(DevDraftNotice, {}),
|
|
2464
|
+
props.stagedNotice && isDevEnv() && /* @__PURE__ */ jsx6(DevStagedNotice, {}),
|
|
2465
|
+
props.syncErrorNotice && isDevEnv() && /* @__PURE__ */ jsx6(DevSyncErrorNotice, { error: props.syncErrorNotice }),
|
|
2308
2466
|
(api.resumedDraft || api.editingPrevious) && /* @__PURE__ */ jsxs5(
|
|
2309
2467
|
"div",
|
|
2310
2468
|
{
|
|
@@ -2312,21 +2470,21 @@ function ResolvedForm(props) {
|
|
|
2312
2470
|
"data-fillo": "resume",
|
|
2313
2471
|
role: "status",
|
|
2314
2472
|
children: [
|
|
2315
|
-
/* @__PURE__ */
|
|
2316
|
-
/* @__PURE__ */
|
|
2473
|
+
/* @__PURE__ */ jsx6("span", { className: "fillo-resume-text", children: api.editingPrevious ? strings.editNotice : strings.resumeNotice }),
|
|
2474
|
+
/* @__PURE__ */ jsx6("button", { type: "button", className: "fillo-resume-clear", onClick: api.resetDraft, children: strings.resumeStartOver })
|
|
2317
2475
|
]
|
|
2318
2476
|
}
|
|
2319
2477
|
),
|
|
2320
|
-
api.resumeLinkFailed && !api.resumedDraft && !api.editingPrevious && /* @__PURE__ */
|
|
2478
|
+
api.resumeLinkFailed && !api.resumedDraft && !api.editingPrevious && /* @__PURE__ */ jsx6(
|
|
2321
2479
|
"div",
|
|
2322
2480
|
{
|
|
2323
2481
|
className: slotClass3("fillo-resume fillo-resume--expired", appearance, { slot: "resume" }),
|
|
2324
2482
|
"data-fillo": "resume",
|
|
2325
2483
|
role: "status",
|
|
2326
|
-
children: /* @__PURE__ */
|
|
2484
|
+
children: /* @__PURE__ */ jsx6("span", { className: "fillo-resume-text", children: strings.resumeLinkExpired })
|
|
2327
2485
|
}
|
|
2328
2486
|
),
|
|
2329
|
-
multiPage && settings.showProgress !== false && /* @__PURE__ */
|
|
2487
|
+
multiPage && settings.showProgress !== false && /* @__PURE__ */ jsx6(
|
|
2330
2488
|
"div",
|
|
2331
2489
|
{
|
|
2332
2490
|
className: slotClass3("fillo-progress-track", appearance, { slot: "progress" }),
|
|
@@ -2334,21 +2492,21 @@ function ResolvedForm(props) {
|
|
|
2334
2492
|
role: "progressbar",
|
|
2335
2493
|
"aria-label": schema.title || "Form progress",
|
|
2336
2494
|
"aria-valuemin": 1,
|
|
2337
|
-
"aria-valuemax":
|
|
2338
|
-
"aria-valuenow":
|
|
2339
|
-
children: /* @__PURE__ */
|
|
2495
|
+
"aria-valuemax": progressTotal,
|
|
2496
|
+
"aria-valuenow": progressStep,
|
|
2497
|
+
children: /* @__PURE__ */ jsx6(
|
|
2340
2498
|
"div",
|
|
2341
2499
|
{
|
|
2342
2500
|
className: slotClass3("fillo-progress-fill", appearance, { slot: "progressFill" }),
|
|
2343
2501
|
"data-fillo": "progressFill",
|
|
2344
|
-
style: { "--fillo-progress-value": `${
|
|
2502
|
+
style: { "--fillo-progress-value": `${progressStep / progressTotal * 100}%` }
|
|
2345
2503
|
}
|
|
2346
2504
|
)
|
|
2347
2505
|
}
|
|
2348
2506
|
),
|
|
2349
2507
|
api.pageIndex === 0 && props.showTitle !== false && /* @__PURE__ */ jsxs5("header", { className: slotClass3("fillo-header", appearance, { slot: "header" }), "data-fillo": "header", children: [
|
|
2350
|
-
schema.title && /* @__PURE__ */
|
|
2351
|
-
schema.description && /* @__PURE__ */
|
|
2508
|
+
schema.title && /* @__PURE__ */ jsx6("h1", { className: slotClass3("fillo-title", appearance, { slot: "title" }), "data-fillo": "title", children: schema.title }),
|
|
2509
|
+
schema.description && /* @__PURE__ */ jsx6(
|
|
2352
2510
|
"p",
|
|
2353
2511
|
{
|
|
2354
2512
|
className: slotClass3("fillo-form-description", appearance, { slot: "description" }),
|
|
@@ -2357,8 +2515,8 @@ function ResolvedForm(props) {
|
|
|
2357
2515
|
}
|
|
2358
2516
|
)
|
|
2359
2517
|
] }),
|
|
2360
|
-
multiPage && api.page.title && api.pageIndex > 0 && /* @__PURE__ */
|
|
2361
|
-
/* @__PURE__ */
|
|
2518
|
+
multiPage && api.page.title && api.pageIndex > 0 && /* @__PURE__ */ jsx6("h2", { className: slotClass3("fillo-page-title", appearance, { slot: "pageTitle" }), "data-fillo": "pageTitle", children: api.page.title }),
|
|
2519
|
+
/* @__PURE__ */ jsx6("div", { className: slotClass3("fillo-blocks", appearance, { slot: "blocks" }), "data-fillo": "blocks", ref: blocksRef, tabIndex: -1, children: api.blocks.map((block) => /* @__PURE__ */ jsx6(
|
|
2362
2520
|
BlockRenderer,
|
|
2363
2521
|
{
|
|
2364
2522
|
block,
|
|
@@ -2368,7 +2526,7 @@ function ResolvedForm(props) {
|
|
|
2368
2526
|
},
|
|
2369
2527
|
block.id
|
|
2370
2528
|
)) }),
|
|
2371
|
-
/* @__PURE__ */
|
|
2529
|
+
/* @__PURE__ */ jsx6(
|
|
2372
2530
|
"input",
|
|
2373
2531
|
{
|
|
2374
2532
|
type: "text",
|
|
@@ -2385,9 +2543,22 @@ function ResolvedForm(props) {
|
|
|
2385
2543
|
}
|
|
2386
2544
|
}
|
|
2387
2545
|
),
|
|
2388
|
-
|
|
2546
|
+
challenge && showChallenge && /* @__PURE__ */ jsxs5("div", { className: "fillo-turnstile-slot", "data-fillo": "turnstile-slot", children: [
|
|
2547
|
+
/* @__PURE__ */ jsx6(
|
|
2548
|
+
TurnstileWidget,
|
|
2549
|
+
{
|
|
2550
|
+
siteKey: challenge.siteKey,
|
|
2551
|
+
className: slotClass3("fillo-turnstile", appearance, { slot: "turnstile" }),
|
|
2552
|
+
onToken: handleChallengeToken,
|
|
2553
|
+
onError: () => setChallengeError(true),
|
|
2554
|
+
registerReset: registerChallengeReset
|
|
2555
|
+
}
|
|
2556
|
+
),
|
|
2557
|
+
challengeError && /* @__PURE__ */ jsx6("p", { className: "fillo-turnstile-error", role: "alert", children: strings.challengeUnavailable })
|
|
2558
|
+
] }),
|
|
2559
|
+
(api.status === "error" || api.submitError) && /* @__PURE__ */ jsx6("p", { className: "fillo-submit-error", role: "alert", children: api.submitError ?? strings.submitFailed }),
|
|
2389
2560
|
showFooter && /* @__PURE__ */ jsxs5("footer", { className: slotClass3("fillo-footer", appearance, { slot: "footer" }), "data-fillo": "footer", children: [
|
|
2390
|
-
multiPage && !api.isFirstPage && /* @__PURE__ */
|
|
2561
|
+
multiPage && !api.isFirstPage && /* @__PURE__ */ jsx6(
|
|
2391
2562
|
"button",
|
|
2392
2563
|
{
|
|
2393
2564
|
type: "button",
|
|
@@ -2397,38 +2568,41 @@ function ResolvedForm(props) {
|
|
|
2397
2568
|
children: strings.back
|
|
2398
2569
|
}
|
|
2399
2570
|
),
|
|
2400
|
-
showPrimaryButton && /* @__PURE__ */
|
|
2571
|
+
showPrimaryButton && /* @__PURE__ */ jsx6(
|
|
2401
2572
|
"button",
|
|
2402
2573
|
{
|
|
2403
2574
|
type: "submit",
|
|
2404
2575
|
className: slotClass3("fillo-button fillo-button--primary", appearance, { slot: "button", variant: "primary" }),
|
|
2405
2576
|
"data-fillo": "button",
|
|
2406
|
-
disabled: api.status === "submitting" || api.uploading
|
|
2577
|
+
disabled: api.status === "submitting" || api.uploading || // Wait for the human check before enabling submit (never
|
|
2578
|
+
// "Next"). The server rejects a tokenless submit regardless —
|
|
2579
|
+
// this is UX only.
|
|
2580
|
+
showChallenge && !challengeToken,
|
|
2407
2581
|
children: api.uploading ? strings.uploading : api.status === "submitting" ? strings.submitting : api.isLastPage ? settings.submitLabel ?? strings.submit : strings.next
|
|
2408
2582
|
}
|
|
2409
2583
|
)
|
|
2410
2584
|
] }),
|
|
2411
|
-
props.poweredBy && /* @__PURE__ */
|
|
2585
|
+
props.poweredBy && /* @__PURE__ */ jsx6(PoweredBy, { label: props.brandLabel, href: props.brandHref })
|
|
2412
2586
|
]
|
|
2413
2587
|
}
|
|
2414
2588
|
) }) }) }) });
|
|
2415
2589
|
}
|
|
2416
2590
|
|
|
2417
2591
|
// src/jsx.tsx
|
|
2418
|
-
import { useRef as
|
|
2592
|
+
import { useRef as useRef8 } from "react";
|
|
2419
2593
|
import {
|
|
2420
2594
|
codeFormFromJsx,
|
|
2421
2595
|
FilloJsxError,
|
|
2422
2596
|
JSX_BLOCK_COMPONENTS
|
|
2423
2597
|
} from "@usefillo/core";
|
|
2424
|
-
import { jsx as
|
|
2598
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2425
2599
|
var B = JSX_BLOCK_COMPONENTS;
|
|
2426
2600
|
var isDevEnv2 = () => typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
2427
2601
|
function JsxForm(props) {
|
|
2428
2602
|
const { id, title, description, settings, theme, client, children, ...rest } = props;
|
|
2429
2603
|
const compiled = codeFormFromJsx({ id, title, description, settings, theme }, children);
|
|
2430
2604
|
const json = JSON.stringify(compiled.schema) + JSON.stringify(compiled.theme ?? null);
|
|
2431
|
-
const memo2 =
|
|
2605
|
+
const memo2 = useRef8(null);
|
|
2432
2606
|
if (memo2.current && memo2.current.json !== json && isDevEnv2()) {
|
|
2433
2607
|
console.warn(
|
|
2434
2608
|
`[fillo] "${id}": form structure changed between renders. If you just edited the form, ignore this. Otherwise: conditional questions are visibleIf={when(\u2026)\u2026}, never {cond && <Fillo.\u2026/>} \u2014 a per-visitor schema churns drafts in your workspace.`
|
|
@@ -2437,7 +2611,7 @@ function JsxForm(props) {
|
|
|
2437
2611
|
if (!memo2.current || memo2.current.json !== json) {
|
|
2438
2612
|
memo2.current = { json, form: compiled };
|
|
2439
2613
|
}
|
|
2440
|
-
return /* @__PURE__ */
|
|
2614
|
+
return /* @__PURE__ */ jsx7(FilloForm, { form: memo2.current.form, client, ...rest });
|
|
2441
2615
|
}
|
|
2442
2616
|
function defineFormFromJsx(element) {
|
|
2443
2617
|
if (!element || element.type !== JsxForm) {
|
|
@@ -2490,7 +2664,7 @@ import {
|
|
|
2490
2664
|
resolveStrings as resolveStrings2,
|
|
2491
2665
|
syncCodeForm as syncCodeForm3
|
|
2492
2666
|
} from "@usefillo/core";
|
|
2493
|
-
import { Fragment as Fragment3, jsx as
|
|
2667
|
+
import { Fragment as Fragment3, jsx as jsx8 } from "react/jsx-runtime";
|
|
2494
2668
|
function FilloProvider({
|
|
2495
2669
|
children,
|
|
2496
2670
|
form,
|
|
@@ -2585,15 +2759,15 @@ function FilloProvider({
|
|
|
2585
2759
|
useDraftFlush(api);
|
|
2586
2760
|
const resolvedStrings = resolveStrings2(strings);
|
|
2587
2761
|
const canonicalSyncError = syncError && !options.skipValidation ? syncError : null;
|
|
2588
|
-
if (canonicalSyncError && renderError) return /* @__PURE__ */
|
|
2762
|
+
if (canonicalSyncError && renderError) return /* @__PURE__ */ jsx8(Fragment3, { children: renderError(canonicalSyncError) });
|
|
2589
2763
|
if (canonicalSyncError && !isDevEnv3()) return null;
|
|
2590
2764
|
if (codeFormSyncing && !options.skipValidation && !isDevEnv3()) return null;
|
|
2591
2765
|
const notPublished = Boolean(codeForm) && syncedStatus === "draft" && !options.skipValidation;
|
|
2592
2766
|
if (notPublished && !isDevEnv3()) {
|
|
2593
2767
|
const error = new FilloError3("This form isn't published yet.", 403, void 0, "form_not_published");
|
|
2594
|
-
return renderError ? /* @__PURE__ */
|
|
2768
|
+
return renderError ? /* @__PURE__ */ jsx8(Fragment3, { children: renderError(error) }) : null;
|
|
2595
2769
|
}
|
|
2596
|
-
return /* @__PURE__ */
|
|
2770
|
+
return /* @__PURE__ */ jsx8(FilloContext.Provider, { value: api, children: /* @__PURE__ */ jsx8(FilloStringsContext.Provider, { value: resolvedStrings, children: /* @__PURE__ */ jsx8(FilloAppearanceContext.Provider, { value: appearance, children: /* @__PURE__ */ jsx8(FilloInstanceIdContext.Provider, { value: instanceId, children }) }) }) });
|
|
2597
2771
|
}
|
|
2598
2772
|
function isDevEnv3() {
|
|
2599
2773
|
return typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
package/dist/styles.css
CHANGED
|
@@ -735,4 +735,22 @@
|
|
|
735
735
|
border-radius: 4px;
|
|
736
736
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--fillo-primary) 15%, transparent);
|
|
737
737
|
}
|
|
738
|
+
|
|
739
|
+
/* ---------- Human-verification challenge (Turnstile) ---------- */
|
|
740
|
+
.fillo-turnstile-slot {
|
|
741
|
+
display: flex;
|
|
742
|
+
flex-direction: column;
|
|
743
|
+
gap: 0.5rem;
|
|
744
|
+
margin: 0.25rem 0 1rem;
|
|
745
|
+
}
|
|
746
|
+
/* Cloudflare draws a fixed-size widget inside; just give it room to breathe. */
|
|
747
|
+
.fillo-turnstile {
|
|
748
|
+
min-height: 65px;
|
|
749
|
+
}
|
|
750
|
+
.fillo-turnstile-error {
|
|
751
|
+
margin: 0;
|
|
752
|
+
color: var(--fillo-error);
|
|
753
|
+
font-size: 0.82rem;
|
|
754
|
+
line-height: 1.45;
|
|
755
|
+
}
|
|
738
756
|
}
|
|
@@ -735,3 +735,21 @@
|
|
|
735
735
|
border-radius: 4px;
|
|
736
736
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--fillo-primary) 15%, transparent);
|
|
737
737
|
}
|
|
738
|
+
|
|
739
|
+
/* ---------- Human-verification challenge (Turnstile) ---------- */
|
|
740
|
+
.fillo-turnstile-slot {
|
|
741
|
+
display: flex;
|
|
742
|
+
flex-direction: column;
|
|
743
|
+
gap: 0.5rem;
|
|
744
|
+
margin: 0.25rem 0 1rem;
|
|
745
|
+
}
|
|
746
|
+
/* Cloudflare draws a fixed-size widget inside; just give it room to breathe. */
|
|
747
|
+
.fillo-turnstile {
|
|
748
|
+
min-height: 65px;
|
|
749
|
+
}
|
|
750
|
+
.fillo-turnstile-error {
|
|
751
|
+
margin: 0;
|
|
752
|
+
color: var(--fillo-error);
|
|
753
|
+
font-size: 0.82rem;
|
|
754
|
+
line-height: 1.45;
|
|
755
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usefillo/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Headless React components for embedding Fillo forms natively in your product.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@usefillo/core": "^0.
|
|
37
|
+
"@usefillo/core": "^0.9.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"react": "^18.0.0 || ^19.0.0",
|