@usefillo/react 0.16.1 → 0.19.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/README.md +2 -0
- package/dist/index.d.ts +16 -2
- package/dist/index.js +238 -49
- package/dist/styles.css +67 -40
- package/dist/styles.unlayered.css +67 -40
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ npm i @usefillo/react
|
|
|
24
24
|
|
|
25
25
|
`react` and `react-dom` (18 or 19) are peer dependencies.
|
|
26
26
|
|
|
27
|
+
The default stylesheet inherits the host page's CSS `color-scheme` and font. If your theme provider only toggles a class or data attribute, pass its resolved mode as `theme={{ colorScheme: "light" | "dark" }}`. Use `"auto"` only for a deliberately system-driven page. A fixed hex `background` automatically selects a readable palette unless you explicitly choose one.
|
|
28
|
+
|
|
27
29
|
## Write forms as components
|
|
28
30
|
|
|
29
31
|
```tsx
|
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, ChallengeConfig, FilloError, CodeForm, FormSettings, Condition, TextField, PhoneField, NumberField, ChoiceField, SelectOption, CheckboxField, RatingField, LinearScaleField, RankingField, SignatureField, DateField, FileUploadField as FileUploadField$1, HiddenField, CalculatedField } from '@usefillo/core';
|
|
4
|
+
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloAppearance, FilloRendererStrings, FilloRespondent, ChallengeConfig, ChallengeTheme, FilloError, CodeForm, FormSettings, Condition, TextField, PhoneField, NumberField, ChoiceField, SelectOption, CheckboxField, RatingField, LinearScaleField, RankingField, SignatureField, DateField, FileUploadField as FileUploadField$1, HiddenField, CalculatedField, RespondentErrorStrings } 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
|
/**
|
|
@@ -143,6 +143,18 @@ interface FilloFormBaseProps {
|
|
|
143
143
|
* hosted page does this). The SECRET key stays server-side — never passed here.
|
|
144
144
|
*/
|
|
145
145
|
challenge?: ChallengeConfig;
|
|
146
|
+
/**
|
|
147
|
+
* Theme for the human-verification widget. Defaults to "auto" (the
|
|
148
|
+
* visitor's OS preference); apps with their own theme switch should pass
|
|
149
|
+
* "light"/"dark" so the widget matches the surrounding form.
|
|
150
|
+
*/
|
|
151
|
+
challengeTheme?: ChallengeTheme;
|
|
152
|
+
/**
|
|
153
|
+
* Bridge-mode visibility for the human check. "interaction-only" (default)
|
|
154
|
+
* keeps it invisible unless Cloudflare needs the visitor to act; "always"
|
|
155
|
+
* shows the classic widget box the whole time.
|
|
156
|
+
*/
|
|
157
|
+
challengeAppearance?: "always" | "interaction-only";
|
|
146
158
|
/**
|
|
147
159
|
* Server-owned per-file ceiling when an inline schema skips the normal form
|
|
148
160
|
* fetch. Fillo's hosted page uses this to preserve its server-rendered fast
|
|
@@ -258,7 +270,7 @@ type ContentProps = {
|
|
|
258
270
|
/** Inert: rendering one throws; they exist to be read by the compiler. */
|
|
259
271
|
type Inert<P> = (props: P) => never;
|
|
260
272
|
interface FilloJsxFormBaseProps extends Omit<FilloFormProps, "form" | "formId" | "client" | "renderOnly" | "skipValidation"> {
|
|
261
|
-
/**
|
|
273
|
+
/** Project handle — the form's identity across syncs. */
|
|
262
274
|
id: string;
|
|
263
275
|
title?: string;
|
|
264
276
|
description?: string;
|
|
@@ -354,6 +366,8 @@ interface ControllerOptions {
|
|
|
354
366
|
* environment) so integration details never reach production visitors.
|
|
355
367
|
*/
|
|
356
368
|
verboseResolutionErrors?: boolean;
|
|
369
|
+
/** Resolved renderer fallbacks for localized respondent-safe failures. */
|
|
370
|
+
respondentErrorStrings?: Partial<RespondentErrorStrings>;
|
|
357
371
|
/**
|
|
358
372
|
* Host-app account context (identify()): who is filling this form, by your
|
|
359
373
|
* own user id. Recorded with the response as an unverified claim so the
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useId as useId2,
|
|
8
8
|
useMemo as useMemo6,
|
|
9
9
|
useRef as useRef9,
|
|
10
|
-
useState as
|
|
10
|
+
useState as useState7,
|
|
11
11
|
useSyncExternalStore as useSyncExternalStore2
|
|
12
12
|
} from "react";
|
|
13
13
|
import {
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
normalizeFormTheme,
|
|
23
23
|
reachableFields,
|
|
24
24
|
reachablePageSequence,
|
|
25
|
+
respondentErrorStringsFor,
|
|
25
26
|
resolveThemeAppearance
|
|
26
27
|
} from "@usefillo/core";
|
|
27
28
|
import { resolveStrings, slotClass as slotClass3 } from "@usefillo/core";
|
|
@@ -104,26 +105,35 @@ function DevNoClientNotice() {
|
|
|
104
105
|
" to collect them in Fillo, or forward them with webhooks. (This notice only appears in development and preview.)"
|
|
105
106
|
] });
|
|
106
107
|
}
|
|
107
|
-
function DevDraftNotice({ warningUrl }) {
|
|
108
|
-
const
|
|
108
|
+
function DevDraftNotice({ warningUrl, formUrl }) {
|
|
109
|
+
const storageUrl = safeHttpUrl(warningUrl);
|
|
110
|
+
const publishUrl = safeHttpUrl(formUrl);
|
|
109
111
|
return /* @__PURE__ */ jsxs("div", { className: "fillo-devwarning", role: "alert", children: [
|
|
110
|
-
/* @__PURE__ */ jsx("strong", { children: "Draft form." }),
|
|
111
|
-
"
|
|
112
|
+
/* @__PURE__ */ jsx("strong", { children: "Draft form preview." }),
|
|
113
|
+
" The form renders for local testing, but Fillo will reject the submission and save no response until you publish it.",
|
|
112
114
|
" ",
|
|
113
|
-
|
|
114
|
-
"Connect storage to publish
|
|
115
|
-
" ",
|
|
116
|
-
/* @__PURE__ */ jsx("a", { href: safeUrl, target: "_blank", rel: "noopener noreferrer", children: safeUrl }),
|
|
115
|
+
storageUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
116
|
+
/* @__PURE__ */ jsx("a", { href: storageUrl, target: "_blank", rel: "noopener noreferrer", children: "Connect storage to publish" }),
|
|
117
117
|
".",
|
|
118
118
|
" "
|
|
119
|
-
] }),
|
|
119
|
+
] }) : publishUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
120
|
+
/* @__PURE__ */ jsx("a", { href: publishUrl, target: "_blank", rel: "noopener noreferrer", children: "Open in Fillo to publish" }),
|
|
121
|
+
".",
|
|
122
|
+
" "
|
|
123
|
+
] }) : null,
|
|
120
124
|
"(This notice only appears in development and preview.)"
|
|
121
125
|
] });
|
|
122
126
|
}
|
|
123
|
-
function DevStagedNotice() {
|
|
127
|
+
function DevStagedNotice({ formUrl }) {
|
|
128
|
+
const publishUrl = safeHttpUrl(formUrl);
|
|
124
129
|
return /* @__PURE__ */ jsxs("div", { className: "fillo-devwarning", role: "alert", children: [
|
|
125
|
-
/* @__PURE__ */ jsx("strong", { children: "Code changes are staged." }),
|
|
126
|
-
" This
|
|
130
|
+
/* @__PURE__ */ jsx("strong", { children: "Code changes are staged, not live." }),
|
|
131
|
+
" This page shows your draft, while respondents still get the live version.",
|
|
132
|
+
" ",
|
|
133
|
+
publishUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
134
|
+
/* @__PURE__ */ jsx("a", { href: publishUrl, target: "_blank", rel: "noopener noreferrer", children: "Review and publish in Fillo" }),
|
|
135
|
+
"."
|
|
136
|
+
] }) : /* @__PURE__ */ jsx(Fragment, { children: "Review and publish the changes in Fillo." })
|
|
127
137
|
] });
|
|
128
138
|
}
|
|
129
139
|
function DevSyncErrorNotice({ error }) {
|
|
@@ -139,7 +149,7 @@ function DevSyncErrorNotice({ error }) {
|
|
|
139
149
|
] });
|
|
140
150
|
}
|
|
141
151
|
function DevChrome(props) {
|
|
142
|
-
const notice = props.devNotices === false ? null : props.syncError ? /* @__PURE__ */ jsx(DevSyncErrorNotice, { error: props.syncError }) : props.staged ? /* @__PURE__ */ jsx(DevStagedNotice, {}) : props.draft ? /* @__PURE__ */ jsx(DevDraftNotice, { warningUrl: props.warningUrl }) : props.noClient ? /* @__PURE__ */ jsx(DevNoClientNotice, {}) : null;
|
|
152
|
+
const notice = props.devNotices === false ? null : props.syncError ? /* @__PURE__ */ jsx(DevSyncErrorNotice, { error: props.syncError }) : props.staged ? /* @__PURE__ */ jsx(DevStagedNotice, { formUrl: props.formUrl }) : props.draft ? /* @__PURE__ */ jsx(DevDraftNotice, { warningUrl: props.warningUrl, formUrl: props.formUrl }) : props.noClient ? /* @__PURE__ */ jsx(DevNoClientNotice, {}) : null;
|
|
143
153
|
if (!props.preview && !notice) return null;
|
|
144
154
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
145
155
|
props.preview && /* @__PURE__ */ jsx(PreviewBadge, {}),
|
|
@@ -210,6 +220,24 @@ import {
|
|
|
210
220
|
function useFilloController(options) {
|
|
211
221
|
const optsRef = useRef(options);
|
|
212
222
|
optsRef.current = options;
|
|
223
|
+
const errorCopy = options.respondentErrorStrings;
|
|
224
|
+
const respondentErrorStrings = useMemo2(
|
|
225
|
+
() => ({ ...errorCopy }),
|
|
226
|
+
[
|
|
227
|
+
errorCopy?.submitFailed,
|
|
228
|
+
errorCopy?.loadFailedNotFound,
|
|
229
|
+
errorCopy?.loadFailedNetwork,
|
|
230
|
+
errorCopy?.formUnavailable,
|
|
231
|
+
errorCopy?.formClosed,
|
|
232
|
+
errorCopy?.submitRateLimited,
|
|
233
|
+
errorCopy?.respondentUnrecognized,
|
|
234
|
+
errorCopy?.fileUnavailable,
|
|
235
|
+
errorCopy?.scopeMissing,
|
|
236
|
+
errorCopy?.challengeIncomplete,
|
|
237
|
+
errorCopy?.challengeRetry,
|
|
238
|
+
errorCopy?.reviewAnswers
|
|
239
|
+
]
|
|
240
|
+
);
|
|
213
241
|
const storeRef = useRef(null);
|
|
214
242
|
if (storeRef.current === null) {
|
|
215
243
|
storeRef.current = createFormController({
|
|
@@ -230,6 +258,7 @@ function useFilloController(options) {
|
|
|
230
258
|
get verboseResolutionErrors() {
|
|
231
259
|
return optsRef.current.verboseResolutionErrors;
|
|
232
260
|
},
|
|
261
|
+
respondentErrorStrings,
|
|
233
262
|
respondent: options.respondent,
|
|
234
263
|
// Challenge wiring read through optsRef so the engine (created once) sees
|
|
235
264
|
// the latest token/reset each submit — the widget solves after mount.
|
|
@@ -244,9 +273,17 @@ function useFilloController(options) {
|
|
|
244
273
|
form: options.form,
|
|
245
274
|
formId: options.formId,
|
|
246
275
|
client: options.client,
|
|
247
|
-
respondent: options.respondent
|
|
276
|
+
respondent: options.respondent,
|
|
277
|
+
respondentErrorStrings
|
|
248
278
|
});
|
|
249
|
-
}, [
|
|
279
|
+
}, [
|
|
280
|
+
store,
|
|
281
|
+
options.form,
|
|
282
|
+
options.formId,
|
|
283
|
+
options.client,
|
|
284
|
+
options.respondent,
|
|
285
|
+
respondentErrorStrings
|
|
286
|
+
]);
|
|
250
287
|
useEffect(() => () => store.destroy(), [store]);
|
|
251
288
|
const state = useSyncExternalStore(store.subscribe, store.getState, store.getState);
|
|
252
289
|
return useMemo2(
|
|
@@ -329,6 +366,7 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
329
366
|
settled: false,
|
|
330
367
|
formId: null,
|
|
331
368
|
status: null,
|
|
369
|
+
manageUrl: void 0,
|
|
332
370
|
error: null,
|
|
333
371
|
noticeError: null,
|
|
334
372
|
staged: false,
|
|
@@ -390,6 +428,7 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
390
428
|
settled: true,
|
|
391
429
|
formId: r.formId,
|
|
392
430
|
status: r.status ?? null,
|
|
431
|
+
manageUrl: r.manageUrl,
|
|
393
432
|
branding: r.branding,
|
|
394
433
|
challenge: r.challenge,
|
|
395
434
|
error: null,
|
|
@@ -405,7 +444,7 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
405
444
|
warningCode: r.warningCode,
|
|
406
445
|
warningUrl: r.warningUrl
|
|
407
446
|
});
|
|
408
|
-
const dashboardUrl =
|
|
447
|
+
const dashboardUrl = r.manageUrl;
|
|
409
448
|
if (r.warning) {
|
|
410
449
|
console.warn(
|
|
411
450
|
`[fillo] ${r.warning}${r.warningUrl ? ` Connect storage to publish: ${r.warningUrl}` : ""}`
|
|
@@ -421,10 +460,14 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
421
460
|
noticeSync(
|
|
422
461
|
codeForm.id,
|
|
423
462
|
"staged",
|
|
424
|
-
`[fillo] "${codeForm.id}": changes staged as a draft \u2014 the live version remains rendered until you publish them at ${dashboardUrl}`
|
|
463
|
+
`[fillo] "${codeForm.id}": changes staged as a draft \u2014 the live version remains rendered until you publish them${dashboardUrl ? ` at ${dashboardUrl}` : " in Fillo"}`
|
|
425
464
|
);
|
|
426
465
|
} else if (r.status === "draft") {
|
|
427
|
-
noticeSync(
|
|
466
|
+
noticeSync(
|
|
467
|
+
codeForm.id,
|
|
468
|
+
"draft",
|
|
469
|
+
`[fillo] "${codeForm.id}" is a draft \u2014 it renders here but won't accept responses until published${dashboardUrl ? `: ${dashboardUrl}` : " in Fillo"}`
|
|
470
|
+
);
|
|
428
471
|
}
|
|
429
472
|
}).catch((err) => {
|
|
430
473
|
if (cancelled) return;
|
|
@@ -451,6 +494,7 @@ function useCodeFormSync(form, client, onError, options) {
|
|
|
451
494
|
return synced.key === syncKey && synced.client === client ? {
|
|
452
495
|
formId: synced.formId,
|
|
453
496
|
status: synced.status,
|
|
497
|
+
manageUrl: synced.manageUrl,
|
|
454
498
|
branding: synced.branding,
|
|
455
499
|
challenge: synced.challenge,
|
|
456
500
|
error: synced.error,
|
|
@@ -1167,8 +1211,9 @@ function formatBytes(bytes) {
|
|
|
1167
1211
|
function uploadFailureMessage(error, strings) {
|
|
1168
1212
|
if (error instanceof Error && error.name === "FilloError") {
|
|
1169
1213
|
const status = error.status;
|
|
1170
|
-
if (status !== void 0 && status >= 500)
|
|
1171
|
-
|
|
1214
|
+
if (status === 0 || status !== void 0 && status >= 500) {
|
|
1215
|
+
return strings.uploadUnavailable;
|
|
1216
|
+
}
|
|
1172
1217
|
}
|
|
1173
1218
|
return strings.uploadFailed;
|
|
1174
1219
|
}
|
|
@@ -1323,7 +1368,10 @@ function FileUploadField({
|
|
|
1323
1368
|
filesRef.current = next;
|
|
1324
1369
|
setValue(next);
|
|
1325
1370
|
} catch (err) {
|
|
1326
|
-
if (mountedRef.current) {
|
|
1371
|
+
if (mountedRef.current && !controller.signal.aborted) {
|
|
1372
|
+
if (err instanceof Error && err.name === "FilloError") {
|
|
1373
|
+
chrome?.onError?.(err);
|
|
1374
|
+
}
|
|
1327
1375
|
const message = uploadFailureMessage(err, strings);
|
|
1328
1376
|
setInFlight((prev) => prev.map((f) => f.key === key ? { ...f, error: message } : f));
|
|
1329
1377
|
}
|
|
@@ -2500,10 +2548,12 @@ function FormField({
|
|
|
2500
2548
|
}
|
|
2501
2549
|
|
|
2502
2550
|
// src/turnstile.tsx
|
|
2503
|
-
import { useEffect as useEffect8, useRef as useRef8 } from "react";
|
|
2551
|
+
import { useEffect as useEffect8, useRef as useRef8, useState as useState6 } from "react";
|
|
2504
2552
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
2505
2553
|
var SCRIPT_SRC = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
|
|
2506
2554
|
var SCRIPT_ID = "fillo-turnstile-script";
|
|
2555
|
+
var BRIDGE_READY_TIMEOUT_MS = 2e4;
|
|
2556
|
+
var CDATA_RE = /^[A-Za-z0-9_-]{1,255}$/;
|
|
2507
2557
|
var scriptPromise = null;
|
|
2508
2558
|
function turnstileGlobal() {
|
|
2509
2559
|
return globalThis.turnstile;
|
|
@@ -2552,8 +2602,133 @@ function loadTurnstileScript() {
|
|
|
2552
2602
|
});
|
|
2553
2603
|
return scriptPromise;
|
|
2554
2604
|
}
|
|
2555
|
-
function TurnstileWidget({
|
|
2605
|
+
function TurnstileWidget(props) {
|
|
2606
|
+
return props.bridgeUrl ? /* @__PURE__ */ jsx7(BridgeChallenge, { ...props, bridgeUrl: props.bridgeUrl }) : /* @__PURE__ */ jsx7(DirectChallenge, { ...props });
|
|
2607
|
+
}
|
|
2608
|
+
function BridgeChallenge({
|
|
2609
|
+
bridgeUrl,
|
|
2610
|
+
formId,
|
|
2611
|
+
theme,
|
|
2612
|
+
appearance,
|
|
2613
|
+
onToken,
|
|
2614
|
+
onError,
|
|
2615
|
+
registerReset,
|
|
2616
|
+
className
|
|
2617
|
+
}) {
|
|
2618
|
+
const iframeRef = useRef8(null);
|
|
2619
|
+
const interactionOnly = (appearance ?? "interaction-only") === "interaction-only";
|
|
2620
|
+
const [frame, setFrame] = useState6(null);
|
|
2621
|
+
const [expanded, setExpanded] = useState6(!interactionOnly);
|
|
2622
|
+
const onTokenRef = useRef8(onToken);
|
|
2623
|
+
onTokenRef.current = onToken;
|
|
2624
|
+
const onErrorRef = useRef8(onError);
|
|
2625
|
+
onErrorRef.current = onError;
|
|
2626
|
+
const registerResetRef = useRef8(registerReset);
|
|
2627
|
+
registerResetRef.current = registerReset;
|
|
2628
|
+
useEffect8(() => {
|
|
2629
|
+
if (typeof window === "undefined") return;
|
|
2630
|
+
let url;
|
|
2631
|
+
try {
|
|
2632
|
+
url = new URL(bridgeUrl);
|
|
2633
|
+
} catch {
|
|
2634
|
+
onErrorRef.current?.();
|
|
2635
|
+
return;
|
|
2636
|
+
}
|
|
2637
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
2638
|
+
onErrorRef.current?.();
|
|
2639
|
+
return;
|
|
2640
|
+
}
|
|
2641
|
+
url.searchParams.set("origin", window.location.origin);
|
|
2642
|
+
url.searchParams.set("theme", theme ?? "auto");
|
|
2643
|
+
url.searchParams.set("appearance", interactionOnly ? "interaction-only" : "always");
|
|
2644
|
+
if (formId && CDATA_RE.test(formId)) url.searchParams.set("cdata", formId);
|
|
2645
|
+
setFrame({ src: url.toString(), origin: url.origin });
|
|
2646
|
+
}, [bridgeUrl, formId, theme, interactionOnly]);
|
|
2647
|
+
useEffect8(() => {
|
|
2648
|
+
if (!frame || typeof window === "undefined") return;
|
|
2649
|
+
let settled = false;
|
|
2650
|
+
const watchdog = window.setTimeout(() => {
|
|
2651
|
+
if (!settled) {
|
|
2652
|
+
onTokenRef.current(void 0);
|
|
2653
|
+
onErrorRef.current?.();
|
|
2654
|
+
}
|
|
2655
|
+
}, BRIDGE_READY_TIMEOUT_MS);
|
|
2656
|
+
const settle = () => {
|
|
2657
|
+
settled = true;
|
|
2658
|
+
window.clearTimeout(watchdog);
|
|
2659
|
+
};
|
|
2660
|
+
const onMessage = (event) => {
|
|
2661
|
+
if (event.origin !== frame.origin) return;
|
|
2662
|
+
const target = iframeRef.current;
|
|
2663
|
+
if (!target || event.source !== target.contentWindow) return;
|
|
2664
|
+
const data = event.data;
|
|
2665
|
+
switch (data?.type) {
|
|
2666
|
+
case "fillo:challenge:ready":
|
|
2667
|
+
settle();
|
|
2668
|
+
break;
|
|
2669
|
+
case "fillo:challenge:token":
|
|
2670
|
+
settle();
|
|
2671
|
+
if (typeof data.token === "string" && data.token.length > 0) {
|
|
2672
|
+
onTokenRef.current(data.token);
|
|
2673
|
+
}
|
|
2674
|
+
if (interactionOnly) setExpanded(false);
|
|
2675
|
+
break;
|
|
2676
|
+
case "fillo:challenge:interactive":
|
|
2677
|
+
if (interactionOnly) setExpanded(true);
|
|
2678
|
+
break;
|
|
2679
|
+
case "fillo:challenge:interactive-done":
|
|
2680
|
+
if (interactionOnly) setExpanded(false);
|
|
2681
|
+
break;
|
|
2682
|
+
case "fillo:challenge:expired":
|
|
2683
|
+
onTokenRef.current(void 0);
|
|
2684
|
+
break;
|
|
2685
|
+
case "fillo:challenge:error":
|
|
2686
|
+
settle();
|
|
2687
|
+
onTokenRef.current(void 0);
|
|
2688
|
+
onErrorRef.current?.();
|
|
2689
|
+
break;
|
|
2690
|
+
}
|
|
2691
|
+
};
|
|
2692
|
+
window.addEventListener("message", onMessage);
|
|
2693
|
+
registerResetRef.current?.(() => {
|
|
2694
|
+
onTokenRef.current(void 0);
|
|
2695
|
+
iframeRef.current?.contentWindow?.postMessage(
|
|
2696
|
+
{ type: "fillo:challenge:reset" },
|
|
2697
|
+
frame.origin
|
|
2698
|
+
);
|
|
2699
|
+
});
|
|
2700
|
+
return () => {
|
|
2701
|
+
window.clearTimeout(watchdog);
|
|
2702
|
+
window.removeEventListener("message", onMessage);
|
|
2703
|
+
onTokenRef.current(void 0);
|
|
2704
|
+
};
|
|
2705
|
+
}, [frame, interactionOnly]);
|
|
2706
|
+
return /* @__PURE__ */ jsx7(
|
|
2707
|
+
"div",
|
|
2708
|
+
{
|
|
2709
|
+
className,
|
|
2710
|
+
"data-fillo": "turnstile",
|
|
2711
|
+
"data-fillo-challenge-visible": expanded ? "true" : "false",
|
|
2712
|
+
children: frame && /* @__PURE__ */ jsx7(
|
|
2713
|
+
"iframe",
|
|
2714
|
+
{
|
|
2715
|
+
ref: iframeRef,
|
|
2716
|
+
src: frame.src,
|
|
2717
|
+
title: "Human verification",
|
|
2718
|
+
width: 300,
|
|
2719
|
+
height: expanded ? 65 : 0,
|
|
2720
|
+
className: "fillo-turnstile-frame",
|
|
2721
|
+
referrerPolicy: "no-referrer",
|
|
2722
|
+
"aria-hidden": expanded ? void 0 : true,
|
|
2723
|
+
tabIndex: expanded ? void 0 : -1
|
|
2724
|
+
}
|
|
2725
|
+
)
|
|
2726
|
+
}
|
|
2727
|
+
);
|
|
2728
|
+
}
|
|
2729
|
+
function DirectChallenge({
|
|
2556
2730
|
siteKey,
|
|
2731
|
+
theme,
|
|
2557
2732
|
onToken,
|
|
2558
2733
|
onError,
|
|
2559
2734
|
registerReset,
|
|
@@ -2582,7 +2757,7 @@ function TurnstileWidget({
|
|
|
2582
2757
|
};
|
|
2583
2758
|
widgetIdRef.current = api.render(containerRef.current, {
|
|
2584
2759
|
sitekey: siteKey,
|
|
2585
|
-
theme: "auto",
|
|
2760
|
+
theme: theme ?? "auto",
|
|
2586
2761
|
callback: (token) => onTokenRef.current(token),
|
|
2587
2762
|
"error-callback": () => {
|
|
2588
2763
|
onTokenRef.current(void 0);
|
|
@@ -2607,15 +2782,8 @@ function TurnstileWidget({
|
|
|
2607
2782
|
widgetIdRef.current = null;
|
|
2608
2783
|
onTokenRef.current(void 0);
|
|
2609
2784
|
};
|
|
2610
|
-
}, [siteKey]);
|
|
2611
|
-
return /* @__PURE__ */ jsx7(
|
|
2612
|
-
"div",
|
|
2613
|
-
{
|
|
2614
|
-
ref: containerRef,
|
|
2615
|
-
className,
|
|
2616
|
-
"data-fillo": "turnstile"
|
|
2617
|
-
}
|
|
2618
|
-
);
|
|
2785
|
+
}, [siteKey, theme]);
|
|
2786
|
+
return /* @__PURE__ */ jsx7("div", { ref: containerRef, className, "data-fillo": "turnstile" });
|
|
2619
2787
|
}
|
|
2620
2788
|
|
|
2621
2789
|
// src/FilloForm.tsx
|
|
@@ -2680,8 +2848,8 @@ function FilloForm(props) {
|
|
|
2680
2848
|
() => renderOnly ? void 0 : props.client ?? (formId ? createClient() : void 0),
|
|
2681
2849
|
[renderOnly, props.client, formId]
|
|
2682
2850
|
);
|
|
2683
|
-
const [loaded, setLoaded] =
|
|
2684
|
-
const [loadFailure, setLoadFailure] =
|
|
2851
|
+
const [loaded, setLoaded] = useState7(null);
|
|
2852
|
+
const [loadFailure, setLoadFailure] = useState7(
|
|
2685
2853
|
null
|
|
2686
2854
|
);
|
|
2687
2855
|
const devEnv = useIsDevEnv();
|
|
@@ -2705,7 +2873,8 @@ function FilloForm(props) {
|
|
|
2705
2873
|
resolvedSchema,
|
|
2706
2874
|
resolvedTheme,
|
|
2707
2875
|
warningCode: syncedWarningCode,
|
|
2708
|
-
warningUrl: syncedWarningUrl
|
|
2876
|
+
warningUrl: syncedWarningUrl,
|
|
2877
|
+
manageUrl: syncedManageUrl
|
|
2709
2878
|
} = useCodeFormSync(form, client, onError, {
|
|
2710
2879
|
// An absent client is intentional render-only use. Builder previews and an
|
|
2711
2880
|
// explicit canonical id also do not need publishable-key resolution.
|
|
@@ -2922,6 +3091,7 @@ function FilloForm(props) {
|
|
|
2922
3091
|
draftNotice: notPublished,
|
|
2923
3092
|
stagedNotice: codeChangesStaged,
|
|
2924
3093
|
syncErrorNotice: syncError ?? syncNoticeError ?? void 0,
|
|
3094
|
+
syncFormUrl: syncedManageUrl,
|
|
2925
3095
|
uploadsAvailable: codeForm ? syncedUploadsAvailable : currentLoaded?.uploadsAvailable,
|
|
2926
3096
|
uploadFileSizeLimitMb: codeForm ? syncedUploadFileSizeLimitMb : currentLoaded?.uploadFileSizeLimitMb ?? props.uploadFileSizeLimitMb,
|
|
2927
3097
|
syncWarningCode: codeForm ? syncedWarningCode : void 0,
|
|
@@ -2996,10 +3166,10 @@ function ResolvedForm(props) {
|
|
|
2996
3166
|
const challenge = renderOnly ? void 0 : props.challenge;
|
|
2997
3167
|
const challengeRequired = Boolean(challenge);
|
|
2998
3168
|
const challengeTokenRef = useRef9(void 0);
|
|
2999
|
-
const [resyncWarning, setResyncWarning] =
|
|
3000
|
-
const [resolutionFailureCode, setResolutionFailureCode] =
|
|
3001
|
-
const [challengeToken, setChallengeToken] =
|
|
3002
|
-
const [challengeError, setChallengeError] =
|
|
3169
|
+
const [resyncWarning, setResyncWarning] = useState7(null);
|
|
3170
|
+
const [resolutionFailureCode, setResolutionFailureCode] = useState7(null);
|
|
3171
|
+
const [challengeToken, setChallengeToken] = useState7(void 0);
|
|
3172
|
+
const [challengeError, setChallengeError] = useState7(false);
|
|
3003
3173
|
const resetChallengeRef = useRef9(void 0);
|
|
3004
3174
|
const handleChallengeToken = useCallback2((token) => {
|
|
3005
3175
|
challengeTokenRef.current = token;
|
|
@@ -3081,6 +3251,7 @@ function ResolvedForm(props) {
|
|
|
3081
3251
|
) : void 0,
|
|
3082
3252
|
[codeForm, client, props.onError, schema]
|
|
3083
3253
|
);
|
|
3254
|
+
const strings = resolveStrings(props.strings);
|
|
3084
3255
|
const api = useFilloController({
|
|
3085
3256
|
form: schema,
|
|
3086
3257
|
formId: props.formId,
|
|
@@ -3097,6 +3268,7 @@ function ResolvedForm(props) {
|
|
|
3097
3268
|
// Dev chrome gets the developer-grade resolution failure (message + code)
|
|
3098
3269
|
// instead of the respondent-safe "unavailable" fallback.
|
|
3099
3270
|
verboseResolutionErrors: devChrome,
|
|
3271
|
+
respondentErrorStrings: respondentErrorStringsFor(strings),
|
|
3100
3272
|
respondent: props.respondent,
|
|
3101
3273
|
challengeRequired,
|
|
3102
3274
|
getChallengeToken: () => challengeTokenRef.current,
|
|
@@ -3106,7 +3278,6 @@ function ResolvedForm(props) {
|
|
|
3106
3278
|
}
|
|
3107
3279
|
});
|
|
3108
3280
|
useDraftFlush(api, !displayOnly && !renderOnly);
|
|
3109
|
-
const strings = resolveStrings(props.strings);
|
|
3110
3281
|
const announceRef = useRef9(null);
|
|
3111
3282
|
const announce = useCallback2((text) => {
|
|
3112
3283
|
const el = announceRef.current;
|
|
@@ -3140,9 +3311,18 @@ function ResolvedForm(props) {
|
|
|
3140
3311
|
uploadsAvailable,
|
|
3141
3312
|
uploadFileSizeLimitMb,
|
|
3142
3313
|
warningCode,
|
|
3143
|
-
warningUrl
|
|
3314
|
+
warningUrl,
|
|
3315
|
+
onError: props.onError
|
|
3144
3316
|
}),
|
|
3145
|
-
[
|
|
3317
|
+
[
|
|
3318
|
+
devChrome,
|
|
3319
|
+
renderOnly,
|
|
3320
|
+
uploadsAvailable,
|
|
3321
|
+
uploadFileSizeLimitMb,
|
|
3322
|
+
warningCode,
|
|
3323
|
+
warningUrl,
|
|
3324
|
+
props.onError
|
|
3325
|
+
]
|
|
3146
3326
|
);
|
|
3147
3327
|
const settings = schema.settings;
|
|
3148
3328
|
const submitted = api.status === "submitted";
|
|
@@ -3243,6 +3423,7 @@ function ResolvedForm(props) {
|
|
|
3243
3423
|
staged: props.stagedNotice,
|
|
3244
3424
|
draft: props.draftNotice,
|
|
3245
3425
|
warningUrl: props.syncWarningUrl,
|
|
3426
|
+
formUrl: props.syncFormUrl,
|
|
3246
3427
|
noClient: !props.client && !props.skipValidation && !renderOnly
|
|
3247
3428
|
}
|
|
3248
3429
|
),
|
|
@@ -3364,6 +3545,10 @@ function ResolvedForm(props) {
|
|
|
3364
3545
|
TurnstileWidget,
|
|
3365
3546
|
{
|
|
3366
3547
|
siteKey: challenge.siteKey,
|
|
3548
|
+
bridgeUrl: challenge.bridgeUrl,
|
|
3549
|
+
formId: props.formId,
|
|
3550
|
+
theme: props.challengeTheme,
|
|
3551
|
+
appearance: props.challengeAppearance,
|
|
3367
3552
|
className: slotClass3("fillo-turnstile", appearance, { slot: "turnstile" }),
|
|
3368
3553
|
onToken: handleChallengeToken,
|
|
3369
3554
|
onError: () => setChallengeError(true),
|
|
@@ -3531,13 +3716,14 @@ var Fillo = {
|
|
|
3531
3716
|
};
|
|
3532
3717
|
|
|
3533
3718
|
// src/provider.tsx
|
|
3534
|
-
import { useEffect as useEffect10, useId as useId3, useMemo as useMemo7, useState as
|
|
3719
|
+
import { useEffect as useEffect10, useId as useId3, useMemo as useMemo7, useState as useState8 } from "react";
|
|
3535
3720
|
import {
|
|
3536
3721
|
FilloError as FilloError3,
|
|
3537
3722
|
createClient as createClient2,
|
|
3538
3723
|
formSchemasEqual as formSchemasEqual2,
|
|
3539
3724
|
isFilloError as isFilloError3,
|
|
3540
3725
|
normalizeFormSchema as normalizeFormSchema2,
|
|
3726
|
+
respondentErrorStringsFor as respondentErrorStringsFor2,
|
|
3541
3727
|
resolveStrings as resolveStrings2,
|
|
3542
3728
|
syncCodeForm as syncCodeForm3
|
|
3543
3729
|
} from "@usefillo/core";
|
|
@@ -3594,7 +3780,7 @@ function FilloProvider({
|
|
|
3594
3780
|
} = useCodeFormSync(form, activeClient, onError, {
|
|
3595
3781
|
allowUnsynced: Boolean(!activeClient || activeFormId || localPreview)
|
|
3596
3782
|
});
|
|
3597
|
-
const [resyncWarning, setResyncWarning] =
|
|
3783
|
+
const [resyncWarning, setResyncWarning] = useState8(null);
|
|
3598
3784
|
const rawSchema = codeForm ? resolvedSchema && !devChrome ? resolvedSchema : codeForm.schema : form;
|
|
3599
3785
|
const normalized = useMemo7(() => normalizeFormSchema2(rawSchema), [rawSchema]);
|
|
3600
3786
|
if (!normalized.ok) {
|
|
@@ -3668,6 +3854,7 @@ function FilloProvider({
|
|
|
3668
3854
|
} : void 0,
|
|
3669
3855
|
[activeClient, codeForm, onError, schema]
|
|
3670
3856
|
);
|
|
3857
|
+
const resolvedStrings = resolveStrings2(strings);
|
|
3671
3858
|
const api = useFilloController({
|
|
3672
3859
|
...options,
|
|
3673
3860
|
client: activeClient,
|
|
@@ -3678,6 +3865,7 @@ function FilloProvider({
|
|
|
3678
3865
|
// Dev chrome (preview or dev env) surfaces the developer-grade resolution
|
|
3679
3866
|
// failure (message + code); an explicit option wins.
|
|
3680
3867
|
verboseResolutionErrors: options.verboseResolutionErrors ?? devChrome,
|
|
3868
|
+
respondentErrorStrings: respondentErrorStringsFor2(resolvedStrings),
|
|
3681
3869
|
// Headless = your markup, no Fillo-rendered layout. Free like every embed
|
|
3682
3870
|
// method; recorded per response so usage stays measurable.
|
|
3683
3871
|
surface: "headless"
|
|
@@ -3694,7 +3882,8 @@ function FilloProvider({
|
|
|
3694
3882
|
uploadsAvailable: freshUploadsAvailable,
|
|
3695
3883
|
uploadFileSizeLimitMb: freshUploadFileSizeLimitMb,
|
|
3696
3884
|
warningCode: freshWarningCode,
|
|
3697
|
-
warningUrl: freshWarningUrl
|
|
3885
|
+
warningUrl: freshWarningUrl,
|
|
3886
|
+
onError
|
|
3698
3887
|
}),
|
|
3699
3888
|
[
|
|
3700
3889
|
devChrome,
|
|
@@ -3702,10 +3891,10 @@ function FilloProvider({
|
|
|
3702
3891
|
freshUploadsAvailable,
|
|
3703
3892
|
freshUploadFileSizeLimitMb,
|
|
3704
3893
|
freshWarningCode,
|
|
3705
|
-
freshWarningUrl
|
|
3894
|
+
freshWarningUrl,
|
|
3895
|
+
onError
|
|
3706
3896
|
]
|
|
3707
3897
|
);
|
|
3708
|
-
const resolvedStrings = resolveStrings2(strings);
|
|
3709
3898
|
if (targetError) {
|
|
3710
3899
|
if (renderError) return /* @__PURE__ */ jsx10(Fragment4, { children: renderError(targetError) });
|
|
3711
3900
|
throw targetError;
|
package/dist/styles.css
CHANGED
|
@@ -20,20 +20,36 @@
|
|
|
20
20
|
|
|
21
21
|
@layer components {
|
|
22
22
|
.fillo-form {
|
|
23
|
-
color-scheme: light;
|
|
24
23
|
--fillo-primary: #18181b;
|
|
24
|
+
--fillo-primary: light-dark(#18181b, #fafafa);
|
|
25
25
|
--fillo-primary-contrast: #ffffff;
|
|
26
|
+
--fillo-primary-contrast: light-dark(#ffffff, #18181b);
|
|
26
27
|
--fillo-bg: transparent;
|
|
27
28
|
--fillo-text: #18181b;
|
|
29
|
+
--fillo-text: light-dark(#18181b, #f4f4f5);
|
|
28
30
|
--fillo-muted: #71717a;
|
|
31
|
+
--fillo-muted: light-dark(#71717a, #a1a1aa);
|
|
29
32
|
--fillo-border: #e4e4e7;
|
|
33
|
+
--fillo-border: light-dark(#e4e4e7, #3f3f46);
|
|
30
34
|
--fillo-error: #dc2626;
|
|
35
|
+
--fillo-error: light-dark(#dc2626, #f87171);
|
|
31
36
|
--fillo-radius: 10px;
|
|
32
37
|
--fillo-font: inherit;
|
|
38
|
+
/* The form's local type root. Default = inherit the host's font, so the
|
|
39
|
+
form blends in; set it once to pin or scale the WHOLE form — every
|
|
40
|
+
internal size is em-based and proportional to this. Prefer an ABSOLUTE
|
|
41
|
+
value (px): the not-open state nests a preview .fillo-form inside the
|
|
42
|
+
root .fillo-form, and a relative value would compound there. */
|
|
43
|
+
--fillo-font-size: 1em;
|
|
33
44
|
--fillo-control-bg: #ffffff;
|
|
45
|
+
--fillo-control-bg: light-dark(#ffffff, #18181b);
|
|
34
46
|
|
|
35
|
-
color-scheme
|
|
47
|
+
/* Unthemed forms follow the host's CSS color-scheme. The first value for
|
|
48
|
+
each token above is a safe light fallback for browsers without
|
|
49
|
+
light-dark(); explicit light/dark and auto remain available below. */
|
|
50
|
+
color-scheme: inherit;
|
|
36
51
|
font-family: var(--fillo-font);
|
|
52
|
+
font-size: var(--fillo-font-size);
|
|
37
53
|
color: var(--fillo-text);
|
|
38
54
|
background: var(--fillo-bg);
|
|
39
55
|
display: flex;
|
|
@@ -46,8 +62,11 @@
|
|
|
46
62
|
color-scheme: light;
|
|
47
63
|
}
|
|
48
64
|
|
|
65
|
+
.fillo-form[data-fillo-color-scheme="auto"] {
|
|
66
|
+
color-scheme: light dark;
|
|
67
|
+
}
|
|
68
|
+
|
|
49
69
|
.fillo-form[data-fillo-color-scheme="dark"] {
|
|
50
|
-
color-scheme: dark;
|
|
51
70
|
--fillo-primary: #fafafa;
|
|
52
71
|
--fillo-primary-contrast: #18181b;
|
|
53
72
|
--fillo-text: #f4f4f5;
|
|
@@ -60,9 +79,8 @@
|
|
|
60
79
|
}
|
|
61
80
|
|
|
62
81
|
@media (prefers-color-scheme: dark) {
|
|
63
|
-
.fillo-form
|
|
64
|
-
|
|
65
|
-
--fillo-primary: #fafafa;
|
|
82
|
+
.fillo-form[data-fillo-color-scheme="auto"] {
|
|
83
|
+
--fillo-primary: #fafafa;
|
|
66
84
|
--fillo-primary-contrast: #18181b;
|
|
67
85
|
--fillo-text: #f4f4f5;
|
|
68
86
|
--fillo-muted: #a1a1aa;
|
|
@@ -75,22 +93,22 @@
|
|
|
75
93
|
}
|
|
76
94
|
|
|
77
95
|
.fillo-header { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
78
|
-
.fillo-title { font-size: 1.
|
|
96
|
+
.fillo-title { font-size: 1.6em; font-weight: 650; letter-spacing: 0; margin: 0; }
|
|
79
97
|
.fillo-form-description { color: var(--fillo-muted); margin: 0; line-height: 1.55; }
|
|
80
|
-
.fillo-page-title { font-size: 1.
|
|
98
|
+
.fillo-page-title { font-size: 1.2em; font-weight: 600; margin: 0; }
|
|
81
99
|
|
|
82
100
|
.fillo-blocks { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
83
101
|
|
|
84
102
|
/* ---------- Field chrome ---------- */
|
|
85
103
|
.fillo-field { display: flex; flex-direction: column; gap: 0.45rem; }
|
|
86
|
-
.fillo-label { font-weight: 550; font-size: 0.
|
|
104
|
+
.fillo-label { font-weight: 550; font-size: 0.95em; }
|
|
87
105
|
:where(.fillo-field--error) .fillo-label { color: var(--fillo-error); }
|
|
88
106
|
/* Fillo marks the few optional fields rather than starring the many required
|
|
89
107
|
ones — so a clean label reads as required by default. */
|
|
90
108
|
.fillo-optional { color: var(--fillo-muted); font-weight: 400; font-size: 0.85em; }
|
|
91
|
-
.fillo-description { color: var(--fillo-muted); font-size: 0.
|
|
92
|
-
.fillo-error { color: var(--fillo-error); font-size: 0.
|
|
93
|
-
.fillo-submit-error { color: var(--fillo-error); font-size: 0.
|
|
109
|
+
.fillo-description { color: var(--fillo-muted); font-size: 0.85em; margin: 0; line-height: 1.5; }
|
|
110
|
+
.fillo-error { color: var(--fillo-error); font-size: 0.85em; font-weight: 500; line-height: 1.4; margin: 0; }
|
|
111
|
+
.fillo-submit-error { color: var(--fillo-error); font-size: 0.85em; font-weight: 500; margin: 0; }
|
|
94
112
|
|
|
95
113
|
/* ---------- Inputs ---------- */
|
|
96
114
|
.fillo-input {
|
|
@@ -294,7 +312,7 @@
|
|
|
294
312
|
/* Selected marker for icon-mode options — the non-color signal (the native
|
|
295
313
|
input is visually hidden there, so forced-colors has nothing else). */
|
|
296
314
|
.fillo-option-check { flex: 0 0 auto; margin-inline-start: auto; color: var(--fillo-primary); }
|
|
297
|
-
.fillo-option-label { font-size:
|
|
315
|
+
.fillo-option-label { font-size: 1em; }
|
|
298
316
|
|
|
299
317
|
.fillo-option-main {
|
|
300
318
|
display: flex;
|
|
@@ -396,7 +414,7 @@
|
|
|
396
414
|
min-width: 0;
|
|
397
415
|
margin-left: 0;
|
|
398
416
|
padding: 0.5rem 0.7rem;
|
|
399
|
-
font-size:
|
|
417
|
+
font-size: 1em;
|
|
400
418
|
background: color-mix(in srgb, var(--fillo-primary) 3%, var(--fillo-control-bg));
|
|
401
419
|
}
|
|
402
420
|
.fillo-other-input--block {
|
|
@@ -407,7 +425,7 @@
|
|
|
407
425
|
/* ---------- Rating ---------- */
|
|
408
426
|
.fillo-rating { display: flex; gap: 0.25rem; }
|
|
409
427
|
.fillo-star {
|
|
410
|
-
font-size: 1.
|
|
428
|
+
font-size: 1.75em;
|
|
411
429
|
line-height: 1;
|
|
412
430
|
background: none;
|
|
413
431
|
border: none;
|
|
@@ -458,7 +476,7 @@
|
|
|
458
476
|
display: flex;
|
|
459
477
|
justify-content: space-between;
|
|
460
478
|
color: var(--fillo-muted);
|
|
461
|
-
font-size: 0.
|
|
479
|
+
font-size: 0.78em;
|
|
462
480
|
margin-top: 0.35rem;
|
|
463
481
|
}
|
|
464
482
|
|
|
@@ -481,11 +499,11 @@
|
|
|
481
499
|
border-radius: 999px;
|
|
482
500
|
background: color-mix(in srgb, var(--fillo-primary) 10%, transparent);
|
|
483
501
|
color: var(--fillo-primary);
|
|
484
|
-
font-size: 0.
|
|
502
|
+
font-size: 0.78em;
|
|
485
503
|
font-weight: 650;
|
|
486
504
|
font-variant-numeric: tabular-nums;
|
|
487
505
|
}
|
|
488
|
-
.fillo-ranking-label { flex: 1; font-size:
|
|
506
|
+
.fillo-ranking-label { flex: 1; font-size: 1em; }
|
|
489
507
|
.fillo-ranking-controls { display: flex; gap: 0.2rem; }
|
|
490
508
|
.fillo-ranking-move {
|
|
491
509
|
font: inherit;
|
|
@@ -504,13 +522,13 @@
|
|
|
504
522
|
|
|
505
523
|
/* ---------- Matrix ---------- */
|
|
506
524
|
.fillo-matrix-wrap { overflow-x: auto; }
|
|
507
|
-
.fillo-matrix { border-collapse: collapse; width: 100%; font-size: 0.
|
|
525
|
+
.fillo-matrix { border-collapse: collapse; width: 100%; font-size: 0.9em; }
|
|
508
526
|
:where(.fillo-matrix) th, :where(.fillo-matrix) td {
|
|
509
527
|
padding: 0.55rem 0.7rem;
|
|
510
528
|
text-align: center;
|
|
511
529
|
border-bottom: 1px solid var(--fillo-border);
|
|
512
530
|
}
|
|
513
|
-
.fillo-matrix thead th { color: var(--fillo-muted); font-weight: 500; font-size: 0.
|
|
531
|
+
.fillo-matrix thead th { color: var(--fillo-muted); font-weight: 500; font-size: 0.89em; }
|
|
514
532
|
.fillo-matrix tbody th { text-align: start; font-weight: 500; }
|
|
515
533
|
.fillo-matrix tbody tr:last-child th, .fillo-matrix tbody tr:last-child td { border-bottom: none; }
|
|
516
534
|
.fillo-matrix-cell:focus-within {
|
|
@@ -524,7 +542,7 @@
|
|
|
524
542
|
/* A quiet computed-value line, not a control: no border or input chrome —
|
|
525
543
|
the slightly heavier tabular number is the only emphasis. */
|
|
526
544
|
.fillo-calculated-value {
|
|
527
|
-
font-size: 1.
|
|
545
|
+
font-size: 1.05em;
|
|
528
546
|
font-weight: 600;
|
|
529
547
|
font-variant-numeric: tabular-nums;
|
|
530
548
|
color: var(--fillo-text);
|
|
@@ -553,7 +571,7 @@
|
|
|
553
571
|
display: grid;
|
|
554
572
|
place-items: center;
|
|
555
573
|
color: var(--fillo-muted);
|
|
556
|
-
font-size: 0.
|
|
574
|
+
font-size: 0.85em;
|
|
557
575
|
pointer-events: none;
|
|
558
576
|
}
|
|
559
577
|
.fillo-signature-clear {
|
|
@@ -561,7 +579,7 @@
|
|
|
561
579
|
top: 0.4rem;
|
|
562
580
|
inset-inline-end: 0.4rem;
|
|
563
581
|
font: inherit;
|
|
564
|
-
font-size: 0.
|
|
582
|
+
font-size: 0.75em;
|
|
565
583
|
border: 1px solid var(--fillo-border);
|
|
566
584
|
border-radius: calc(var(--fillo-radius) * 0.6);
|
|
567
585
|
background: var(--fillo-control-bg);
|
|
@@ -580,7 +598,7 @@
|
|
|
580
598
|
}
|
|
581
599
|
.fillo-signature-type-label {
|
|
582
600
|
color: var(--fillo-muted);
|
|
583
|
-
font-size: 0.
|
|
601
|
+
font-size: 0.8em;
|
|
584
602
|
}
|
|
585
603
|
.fillo-signature-type-input {
|
|
586
604
|
margin-top: 0;
|
|
@@ -620,8 +638,8 @@
|
|
|
620
638
|
outline: none;
|
|
621
639
|
}
|
|
622
640
|
.fillo-dropzone--disabled { cursor: not-allowed; opacity: 0.6; }
|
|
623
|
-
.fillo-dropzone-title { font-weight: 550; font-size: 0.
|
|
624
|
-
.fillo-dropzone-hint { color: var(--fillo-muted); font-size: 0.
|
|
641
|
+
.fillo-dropzone-title { font-weight: 550; font-size: 0.95em; }
|
|
642
|
+
.fillo-dropzone-hint { color: var(--fillo-muted); font-size: 0.82em; }
|
|
625
643
|
|
|
626
644
|
.fillo-files { list-style: none; display: flex; flex-direction: column; gap: 0.45rem; margin: 0; padding: 0; }
|
|
627
645
|
.fillo-file {
|
|
@@ -632,7 +650,7 @@
|
|
|
632
650
|
border: 1px solid var(--fillo-border);
|
|
633
651
|
border-radius: var(--fillo-radius);
|
|
634
652
|
padding: 0.625rem 0.75rem;
|
|
635
|
-
font-size: 0.
|
|
653
|
+
font-size: 0.88em;
|
|
636
654
|
background: var(--fillo-control-bg);
|
|
637
655
|
box-sizing: border-box;
|
|
638
656
|
min-width: 0;
|
|
@@ -692,7 +710,7 @@
|
|
|
692
710
|
}
|
|
693
711
|
.fillo-file-error {
|
|
694
712
|
color: var(--fillo-error);
|
|
695
|
-
font-size: 0.
|
|
713
|
+
font-size: 0.93em;
|
|
696
714
|
line-height: 1.35;
|
|
697
715
|
overflow-wrap: anywhere;
|
|
698
716
|
}
|
|
@@ -747,7 +765,7 @@
|
|
|
747
765
|
}
|
|
748
766
|
|
|
749
767
|
/* ---------- Content blocks ---------- */
|
|
750
|
-
.fillo-heading { font-size: 1.
|
|
768
|
+
.fillo-heading { font-size: 1.15em; font-weight: 600; margin: 0.5rem 0 0; }
|
|
751
769
|
.fillo-paragraph { color: var(--fillo-muted); line-height: 1.6; margin: 0; }
|
|
752
770
|
.fillo-divider { border: none; border-top: 1px solid var(--fillo-border); margin: 0.25rem 0; }
|
|
753
771
|
|
|
@@ -821,11 +839,11 @@
|
|
|
821
839
|
padding: 2rem 1rem;
|
|
822
840
|
text-align: center;
|
|
823
841
|
}
|
|
824
|
-
.fillo-not-open-title { margin: 0; font-size: 1.
|
|
842
|
+
.fillo-not-open-title { margin: 0; font-size: 1.05em; font-weight: 650; letter-spacing: 0; }
|
|
825
843
|
.fillo-not-open-body {
|
|
826
844
|
max-width: 26rem;
|
|
827
845
|
margin: 0;
|
|
828
|
-
font-size: 0.
|
|
846
|
+
font-size: 0.875em;
|
|
829
847
|
color: var(--fillo-muted);
|
|
830
848
|
line-height: 1.5;
|
|
831
849
|
}
|
|
@@ -849,8 +867,8 @@
|
|
|
849
867
|
border-bottom: 2.5px solid var(--fillo-primary-contrast);
|
|
850
868
|
transform: translateY(-0.09rem) rotate(-45deg);
|
|
851
869
|
}
|
|
852
|
-
.fillo-success-title { margin: 0; font-size: 1.
|
|
853
|
-
.fillo-success-message { margin: 0; font-size: 0.
|
|
870
|
+
.fillo-success-title { margin: 0; font-size: 1.05em; letter-spacing: 0; }
|
|
871
|
+
.fillo-success-message { margin: 0; font-size: 0.875em; color: var(--fillo-muted); }
|
|
854
872
|
|
|
855
873
|
/* Honeypot — off-screen, never display:none (bots check that) */
|
|
856
874
|
.fillo-hp {
|
|
@@ -911,7 +929,7 @@
|
|
|
911
929
|
display: block;
|
|
912
930
|
margin-top: 1.25rem;
|
|
913
931
|
text-align: center;
|
|
914
|
-
font-size: 0.
|
|
932
|
+
font-size: 0.75em;
|
|
915
933
|
font-weight: 500;
|
|
916
934
|
letter-spacing: 0;
|
|
917
935
|
color: var(--fillo-muted);
|
|
@@ -929,7 +947,7 @@
|
|
|
929
947
|
border-radius: var(--fillo-radius);
|
|
930
948
|
background: #fffbeb;
|
|
931
949
|
color: #92400e;
|
|
932
|
-
font-size: 0.
|
|
950
|
+
font-size: 0.82em;
|
|
933
951
|
line-height: 1.45;
|
|
934
952
|
}
|
|
935
953
|
.fillo-devwarning code {
|
|
@@ -948,7 +966,7 @@
|
|
|
948
966
|
border-radius: 999px;
|
|
949
967
|
background: #fef3c7;
|
|
950
968
|
color: #92400e;
|
|
951
|
-
font-size: 0.
|
|
969
|
+
font-size: 0.7em;
|
|
952
970
|
font-weight: 600;
|
|
953
971
|
letter-spacing: 0.06em;
|
|
954
972
|
text-transform: uppercase;
|
|
@@ -966,7 +984,7 @@
|
|
|
966
984
|
border-radius: var(--fillo-radius);
|
|
967
985
|
background: var(--fillo-control-bg);
|
|
968
986
|
color: var(--fillo-muted);
|
|
969
|
-
font-size: 0.
|
|
987
|
+
font-size: 0.82em;
|
|
970
988
|
line-height: 1.45;
|
|
971
989
|
}
|
|
972
990
|
.fillo-resume-clear {
|
|
@@ -994,10 +1012,19 @@
|
|
|
994
1012
|
.fillo-turnstile {
|
|
995
1013
|
min-height: 65px;
|
|
996
1014
|
}
|
|
1015
|
+
/* Bridge mode: the widget lives in Fillo's iframe — keep it flush. */
|
|
1016
|
+
.fillo-turnstile-frame {
|
|
1017
|
+
display: block;
|
|
1018
|
+
border: 0;
|
|
1019
|
+
}
|
|
1020
|
+
/* interaction-only: while the check runs invisibly, reserve no space. */
|
|
1021
|
+
.fillo-turnstile[data-fillo-challenge-visible="false"] {
|
|
1022
|
+
min-height: 0;
|
|
1023
|
+
}
|
|
997
1024
|
.fillo-turnstile-error {
|
|
998
1025
|
margin: 0;
|
|
999
1026
|
color: var(--fillo-error);
|
|
1000
|
-
font-size: 0.
|
|
1027
|
+
font-size: 0.82em;
|
|
1001
1028
|
line-height: 1.45;
|
|
1002
1029
|
}
|
|
1003
1030
|
|
|
@@ -1018,7 +1045,7 @@
|
|
|
1018
1045
|
justify-content: space-between;
|
|
1019
1046
|
gap: 0.5rem;
|
|
1020
1047
|
}
|
|
1021
|
-
.fillo-group-instance-title { margin: 0; font-size: 0.
|
|
1048
|
+
.fillo-group-instance-title { margin: 0; font-size: 0.95em; font-weight: 600; }
|
|
1022
1049
|
.fillo-group-add {
|
|
1023
1050
|
align-self: flex-start;
|
|
1024
1051
|
font: inherit;
|
|
@@ -1031,7 +1058,7 @@
|
|
|
1031
1058
|
}
|
|
1032
1059
|
.fillo-group-add:disabled { opacity: 0.5; cursor: default; }
|
|
1033
1060
|
.fillo-group-remove {
|
|
1034
|
-
font-size: 1.
|
|
1061
|
+
font-size: 1.1em;
|
|
1035
1062
|
line-height: 1;
|
|
1036
1063
|
padding: 0 0.2rem;
|
|
1037
1064
|
border: none;
|
|
@@ -20,20 +20,36 @@
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
.fillo-form {
|
|
23
|
-
color-scheme: light;
|
|
24
23
|
--fillo-primary: #18181b;
|
|
24
|
+
--fillo-primary: light-dark(#18181b, #fafafa);
|
|
25
25
|
--fillo-primary-contrast: #ffffff;
|
|
26
|
+
--fillo-primary-contrast: light-dark(#ffffff, #18181b);
|
|
26
27
|
--fillo-bg: transparent;
|
|
27
28
|
--fillo-text: #18181b;
|
|
29
|
+
--fillo-text: light-dark(#18181b, #f4f4f5);
|
|
28
30
|
--fillo-muted: #71717a;
|
|
31
|
+
--fillo-muted: light-dark(#71717a, #a1a1aa);
|
|
29
32
|
--fillo-border: #e4e4e7;
|
|
33
|
+
--fillo-border: light-dark(#e4e4e7, #3f3f46);
|
|
30
34
|
--fillo-error: #dc2626;
|
|
35
|
+
--fillo-error: light-dark(#dc2626, #f87171);
|
|
31
36
|
--fillo-radius: 10px;
|
|
32
37
|
--fillo-font: inherit;
|
|
38
|
+
/* The form's local type root. Default = inherit the host's font, so the
|
|
39
|
+
form blends in; set it once to pin or scale the WHOLE form — every
|
|
40
|
+
internal size is em-based and proportional to this. Prefer an ABSOLUTE
|
|
41
|
+
value (px): the not-open state nests a preview .fillo-form inside the
|
|
42
|
+
root .fillo-form, and a relative value would compound there. */
|
|
43
|
+
--fillo-font-size: 1em;
|
|
33
44
|
--fillo-control-bg: #ffffff;
|
|
45
|
+
--fillo-control-bg: light-dark(#ffffff, #18181b);
|
|
34
46
|
|
|
35
|
-
color-scheme
|
|
47
|
+
/* Unthemed forms follow the host's CSS color-scheme. The first value for
|
|
48
|
+
each token above is a safe light fallback for browsers without
|
|
49
|
+
light-dark(); explicit light/dark and auto remain available below. */
|
|
50
|
+
color-scheme: inherit;
|
|
36
51
|
font-family: var(--fillo-font);
|
|
52
|
+
font-size: var(--fillo-font-size);
|
|
37
53
|
color: var(--fillo-text);
|
|
38
54
|
background: var(--fillo-bg);
|
|
39
55
|
display: flex;
|
|
@@ -46,8 +62,11 @@
|
|
|
46
62
|
color-scheme: light;
|
|
47
63
|
}
|
|
48
64
|
|
|
65
|
+
.fillo-form[data-fillo-color-scheme="auto"] {
|
|
66
|
+
color-scheme: light dark;
|
|
67
|
+
}
|
|
68
|
+
|
|
49
69
|
.fillo-form[data-fillo-color-scheme="dark"] {
|
|
50
|
-
color-scheme: dark;
|
|
51
70
|
--fillo-primary: #fafafa;
|
|
52
71
|
--fillo-primary-contrast: #18181b;
|
|
53
72
|
--fillo-text: #f4f4f5;
|
|
@@ -60,9 +79,8 @@
|
|
|
60
79
|
}
|
|
61
80
|
|
|
62
81
|
@media (prefers-color-scheme: dark) {
|
|
63
|
-
.fillo-form
|
|
64
|
-
|
|
65
|
-
--fillo-primary: #fafafa;
|
|
82
|
+
.fillo-form[data-fillo-color-scheme="auto"] {
|
|
83
|
+
--fillo-primary: #fafafa;
|
|
66
84
|
--fillo-primary-contrast: #18181b;
|
|
67
85
|
--fillo-text: #f4f4f5;
|
|
68
86
|
--fillo-muted: #a1a1aa;
|
|
@@ -75,22 +93,22 @@
|
|
|
75
93
|
}
|
|
76
94
|
|
|
77
95
|
.fillo-header { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
78
|
-
.fillo-title { font-size: 1.
|
|
96
|
+
.fillo-title { font-size: 1.6em; font-weight: 650; letter-spacing: 0; margin: 0; }
|
|
79
97
|
.fillo-form-description { color: var(--fillo-muted); margin: 0; line-height: 1.55; }
|
|
80
|
-
.fillo-page-title { font-size: 1.
|
|
98
|
+
.fillo-page-title { font-size: 1.2em; font-weight: 600; margin: 0; }
|
|
81
99
|
|
|
82
100
|
.fillo-blocks { display: flex; flex-direction: column; gap: 1.5rem; }
|
|
83
101
|
|
|
84
102
|
/* ---------- Field chrome ---------- */
|
|
85
103
|
.fillo-field { display: flex; flex-direction: column; gap: 0.45rem; }
|
|
86
|
-
.fillo-label { font-weight: 550; font-size: 0.
|
|
104
|
+
.fillo-label { font-weight: 550; font-size: 0.95em; }
|
|
87
105
|
:where(.fillo-field--error) .fillo-label { color: var(--fillo-error); }
|
|
88
106
|
/* Fillo marks the few optional fields rather than starring the many required
|
|
89
107
|
ones — so a clean label reads as required by default. */
|
|
90
108
|
.fillo-optional { color: var(--fillo-muted); font-weight: 400; font-size: 0.85em; }
|
|
91
|
-
.fillo-description { color: var(--fillo-muted); font-size: 0.
|
|
92
|
-
.fillo-error { color: var(--fillo-error); font-size: 0.
|
|
93
|
-
.fillo-submit-error { color: var(--fillo-error); font-size: 0.
|
|
109
|
+
.fillo-description { color: var(--fillo-muted); font-size: 0.85em; margin: 0; line-height: 1.5; }
|
|
110
|
+
.fillo-error { color: var(--fillo-error); font-size: 0.85em; font-weight: 500; line-height: 1.4; margin: 0; }
|
|
111
|
+
.fillo-submit-error { color: var(--fillo-error); font-size: 0.85em; font-weight: 500; margin: 0; }
|
|
94
112
|
|
|
95
113
|
/* ---------- Inputs ---------- */
|
|
96
114
|
.fillo-input {
|
|
@@ -294,7 +312,7 @@
|
|
|
294
312
|
/* Selected marker for icon-mode options — the non-color signal (the native
|
|
295
313
|
input is visually hidden there, so forced-colors has nothing else). */
|
|
296
314
|
.fillo-option-check { flex: 0 0 auto; margin-inline-start: auto; color: var(--fillo-primary); }
|
|
297
|
-
.fillo-option-label { font-size:
|
|
315
|
+
.fillo-option-label { font-size: 1em; }
|
|
298
316
|
|
|
299
317
|
.fillo-option-main {
|
|
300
318
|
display: flex;
|
|
@@ -396,7 +414,7 @@
|
|
|
396
414
|
min-width: 0;
|
|
397
415
|
margin-left: 0;
|
|
398
416
|
padding: 0.5rem 0.7rem;
|
|
399
|
-
font-size:
|
|
417
|
+
font-size: 1em;
|
|
400
418
|
background: color-mix(in srgb, var(--fillo-primary) 3%, var(--fillo-control-bg));
|
|
401
419
|
}
|
|
402
420
|
.fillo-other-input--block {
|
|
@@ -407,7 +425,7 @@
|
|
|
407
425
|
/* ---------- Rating ---------- */
|
|
408
426
|
.fillo-rating { display: flex; gap: 0.25rem; }
|
|
409
427
|
.fillo-star {
|
|
410
|
-
font-size: 1.
|
|
428
|
+
font-size: 1.75em;
|
|
411
429
|
line-height: 1;
|
|
412
430
|
background: none;
|
|
413
431
|
border: none;
|
|
@@ -458,7 +476,7 @@
|
|
|
458
476
|
display: flex;
|
|
459
477
|
justify-content: space-between;
|
|
460
478
|
color: var(--fillo-muted);
|
|
461
|
-
font-size: 0.
|
|
479
|
+
font-size: 0.78em;
|
|
462
480
|
margin-top: 0.35rem;
|
|
463
481
|
}
|
|
464
482
|
|
|
@@ -481,11 +499,11 @@
|
|
|
481
499
|
border-radius: 999px;
|
|
482
500
|
background: color-mix(in srgb, var(--fillo-primary) 10%, transparent);
|
|
483
501
|
color: var(--fillo-primary);
|
|
484
|
-
font-size: 0.
|
|
502
|
+
font-size: 0.78em;
|
|
485
503
|
font-weight: 650;
|
|
486
504
|
font-variant-numeric: tabular-nums;
|
|
487
505
|
}
|
|
488
|
-
.fillo-ranking-label { flex: 1; font-size:
|
|
506
|
+
.fillo-ranking-label { flex: 1; font-size: 1em; }
|
|
489
507
|
.fillo-ranking-controls { display: flex; gap: 0.2rem; }
|
|
490
508
|
.fillo-ranking-move {
|
|
491
509
|
font: inherit;
|
|
@@ -504,13 +522,13 @@
|
|
|
504
522
|
|
|
505
523
|
/* ---------- Matrix ---------- */
|
|
506
524
|
.fillo-matrix-wrap { overflow-x: auto; }
|
|
507
|
-
.fillo-matrix { border-collapse: collapse; width: 100%; font-size: 0.
|
|
525
|
+
.fillo-matrix { border-collapse: collapse; width: 100%; font-size: 0.9em; }
|
|
508
526
|
:where(.fillo-matrix) th, :where(.fillo-matrix) td {
|
|
509
527
|
padding: 0.55rem 0.7rem;
|
|
510
528
|
text-align: center;
|
|
511
529
|
border-bottom: 1px solid var(--fillo-border);
|
|
512
530
|
}
|
|
513
|
-
.fillo-matrix thead th { color: var(--fillo-muted); font-weight: 500; font-size: 0.
|
|
531
|
+
.fillo-matrix thead th { color: var(--fillo-muted); font-weight: 500; font-size: 0.89em; }
|
|
514
532
|
.fillo-matrix tbody th { text-align: start; font-weight: 500; }
|
|
515
533
|
.fillo-matrix tbody tr:last-child th, .fillo-matrix tbody tr:last-child td { border-bottom: none; }
|
|
516
534
|
.fillo-matrix-cell:focus-within {
|
|
@@ -524,7 +542,7 @@
|
|
|
524
542
|
/* A quiet computed-value line, not a control: no border or input chrome —
|
|
525
543
|
the slightly heavier tabular number is the only emphasis. */
|
|
526
544
|
.fillo-calculated-value {
|
|
527
|
-
font-size: 1.
|
|
545
|
+
font-size: 1.05em;
|
|
528
546
|
font-weight: 600;
|
|
529
547
|
font-variant-numeric: tabular-nums;
|
|
530
548
|
color: var(--fillo-text);
|
|
@@ -553,7 +571,7 @@
|
|
|
553
571
|
display: grid;
|
|
554
572
|
place-items: center;
|
|
555
573
|
color: var(--fillo-muted);
|
|
556
|
-
font-size: 0.
|
|
574
|
+
font-size: 0.85em;
|
|
557
575
|
pointer-events: none;
|
|
558
576
|
}
|
|
559
577
|
.fillo-signature-clear {
|
|
@@ -561,7 +579,7 @@
|
|
|
561
579
|
top: 0.4rem;
|
|
562
580
|
inset-inline-end: 0.4rem;
|
|
563
581
|
font: inherit;
|
|
564
|
-
font-size: 0.
|
|
582
|
+
font-size: 0.75em;
|
|
565
583
|
border: 1px solid var(--fillo-border);
|
|
566
584
|
border-radius: calc(var(--fillo-radius) * 0.6);
|
|
567
585
|
background: var(--fillo-control-bg);
|
|
@@ -580,7 +598,7 @@
|
|
|
580
598
|
}
|
|
581
599
|
.fillo-signature-type-label {
|
|
582
600
|
color: var(--fillo-muted);
|
|
583
|
-
font-size: 0.
|
|
601
|
+
font-size: 0.8em;
|
|
584
602
|
}
|
|
585
603
|
.fillo-signature-type-input {
|
|
586
604
|
margin-top: 0;
|
|
@@ -620,8 +638,8 @@
|
|
|
620
638
|
outline: none;
|
|
621
639
|
}
|
|
622
640
|
.fillo-dropzone--disabled { cursor: not-allowed; opacity: 0.6; }
|
|
623
|
-
.fillo-dropzone-title { font-weight: 550; font-size: 0.
|
|
624
|
-
.fillo-dropzone-hint { color: var(--fillo-muted); font-size: 0.
|
|
641
|
+
.fillo-dropzone-title { font-weight: 550; font-size: 0.95em; }
|
|
642
|
+
.fillo-dropzone-hint { color: var(--fillo-muted); font-size: 0.82em; }
|
|
625
643
|
|
|
626
644
|
.fillo-files { list-style: none; display: flex; flex-direction: column; gap: 0.45rem; margin: 0; padding: 0; }
|
|
627
645
|
.fillo-file {
|
|
@@ -632,7 +650,7 @@
|
|
|
632
650
|
border: 1px solid var(--fillo-border);
|
|
633
651
|
border-radius: var(--fillo-radius);
|
|
634
652
|
padding: 0.625rem 0.75rem;
|
|
635
|
-
font-size: 0.
|
|
653
|
+
font-size: 0.88em;
|
|
636
654
|
background: var(--fillo-control-bg);
|
|
637
655
|
box-sizing: border-box;
|
|
638
656
|
min-width: 0;
|
|
@@ -692,7 +710,7 @@
|
|
|
692
710
|
}
|
|
693
711
|
.fillo-file-error {
|
|
694
712
|
color: var(--fillo-error);
|
|
695
|
-
font-size: 0.
|
|
713
|
+
font-size: 0.93em;
|
|
696
714
|
line-height: 1.35;
|
|
697
715
|
overflow-wrap: anywhere;
|
|
698
716
|
}
|
|
@@ -747,7 +765,7 @@
|
|
|
747
765
|
}
|
|
748
766
|
|
|
749
767
|
/* ---------- Content blocks ---------- */
|
|
750
|
-
.fillo-heading { font-size: 1.
|
|
768
|
+
.fillo-heading { font-size: 1.15em; font-weight: 600; margin: 0.5rem 0 0; }
|
|
751
769
|
.fillo-paragraph { color: var(--fillo-muted); line-height: 1.6; margin: 0; }
|
|
752
770
|
.fillo-divider { border: none; border-top: 1px solid var(--fillo-border); margin: 0.25rem 0; }
|
|
753
771
|
|
|
@@ -821,11 +839,11 @@
|
|
|
821
839
|
padding: 2rem 1rem;
|
|
822
840
|
text-align: center;
|
|
823
841
|
}
|
|
824
|
-
.fillo-not-open-title { margin: 0; font-size: 1.
|
|
842
|
+
.fillo-not-open-title { margin: 0; font-size: 1.05em; font-weight: 650; letter-spacing: 0; }
|
|
825
843
|
.fillo-not-open-body {
|
|
826
844
|
max-width: 26rem;
|
|
827
845
|
margin: 0;
|
|
828
|
-
font-size: 0.
|
|
846
|
+
font-size: 0.875em;
|
|
829
847
|
color: var(--fillo-muted);
|
|
830
848
|
line-height: 1.5;
|
|
831
849
|
}
|
|
@@ -849,8 +867,8 @@
|
|
|
849
867
|
border-bottom: 2.5px solid var(--fillo-primary-contrast);
|
|
850
868
|
transform: translateY(-0.09rem) rotate(-45deg);
|
|
851
869
|
}
|
|
852
|
-
.fillo-success-title { margin: 0; font-size: 1.
|
|
853
|
-
.fillo-success-message { margin: 0; font-size: 0.
|
|
870
|
+
.fillo-success-title { margin: 0; font-size: 1.05em; letter-spacing: 0; }
|
|
871
|
+
.fillo-success-message { margin: 0; font-size: 0.875em; color: var(--fillo-muted); }
|
|
854
872
|
|
|
855
873
|
/* Honeypot — off-screen, never display:none (bots check that) */
|
|
856
874
|
.fillo-hp {
|
|
@@ -911,7 +929,7 @@
|
|
|
911
929
|
display: block;
|
|
912
930
|
margin-top: 1.25rem;
|
|
913
931
|
text-align: center;
|
|
914
|
-
font-size: 0.
|
|
932
|
+
font-size: 0.75em;
|
|
915
933
|
font-weight: 500;
|
|
916
934
|
letter-spacing: 0;
|
|
917
935
|
color: var(--fillo-muted);
|
|
@@ -929,7 +947,7 @@
|
|
|
929
947
|
border-radius: var(--fillo-radius);
|
|
930
948
|
background: #fffbeb;
|
|
931
949
|
color: #92400e;
|
|
932
|
-
font-size: 0.
|
|
950
|
+
font-size: 0.82em;
|
|
933
951
|
line-height: 1.45;
|
|
934
952
|
}
|
|
935
953
|
.fillo-devwarning code {
|
|
@@ -948,7 +966,7 @@
|
|
|
948
966
|
border-radius: 999px;
|
|
949
967
|
background: #fef3c7;
|
|
950
968
|
color: #92400e;
|
|
951
|
-
font-size: 0.
|
|
969
|
+
font-size: 0.7em;
|
|
952
970
|
font-weight: 600;
|
|
953
971
|
letter-spacing: 0.06em;
|
|
954
972
|
text-transform: uppercase;
|
|
@@ -966,7 +984,7 @@
|
|
|
966
984
|
border-radius: var(--fillo-radius);
|
|
967
985
|
background: var(--fillo-control-bg);
|
|
968
986
|
color: var(--fillo-muted);
|
|
969
|
-
font-size: 0.
|
|
987
|
+
font-size: 0.82em;
|
|
970
988
|
line-height: 1.45;
|
|
971
989
|
}
|
|
972
990
|
.fillo-resume-clear {
|
|
@@ -994,10 +1012,19 @@
|
|
|
994
1012
|
.fillo-turnstile {
|
|
995
1013
|
min-height: 65px;
|
|
996
1014
|
}
|
|
1015
|
+
/* Bridge mode: the widget lives in Fillo's iframe — keep it flush. */
|
|
1016
|
+
.fillo-turnstile-frame {
|
|
1017
|
+
display: block;
|
|
1018
|
+
border: 0;
|
|
1019
|
+
}
|
|
1020
|
+
/* interaction-only: while the check runs invisibly, reserve no space. */
|
|
1021
|
+
.fillo-turnstile[data-fillo-challenge-visible="false"] {
|
|
1022
|
+
min-height: 0;
|
|
1023
|
+
}
|
|
997
1024
|
.fillo-turnstile-error {
|
|
998
1025
|
margin: 0;
|
|
999
1026
|
color: var(--fillo-error);
|
|
1000
|
-
font-size: 0.
|
|
1027
|
+
font-size: 0.82em;
|
|
1001
1028
|
line-height: 1.45;
|
|
1002
1029
|
}
|
|
1003
1030
|
|
|
@@ -1018,7 +1045,7 @@
|
|
|
1018
1045
|
justify-content: space-between;
|
|
1019
1046
|
gap: 0.5rem;
|
|
1020
1047
|
}
|
|
1021
|
-
.fillo-group-instance-title { margin: 0; font-size: 0.
|
|
1048
|
+
.fillo-group-instance-title { margin: 0; font-size: 0.95em; font-weight: 600; }
|
|
1022
1049
|
.fillo-group-add {
|
|
1023
1050
|
align-self: flex-start;
|
|
1024
1051
|
font: inherit;
|
|
@@ -1031,7 +1058,7 @@
|
|
|
1031
1058
|
}
|
|
1032
1059
|
.fillo-group-add:disabled { opacity: 0.5; cursor: default; }
|
|
1033
1060
|
.fillo-group-remove {
|
|
1034
|
-
font-size: 1.
|
|
1061
|
+
font-size: 1.1em;
|
|
1035
1062
|
line-height: 1;
|
|
1036
1063
|
padding: 0 0.2rem;
|
|
1037
1064
|
border: none;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usefillo/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Headless React components for embedding Fillo forms natively in your product.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@usefillo/core": "^0.
|
|
46
|
+
"@usefillo/core": "^0.19.0"
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
49
|
"react": "^18.0.0 || ^19.0.0",
|