@usefillo/react 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -4
- package/dist/index.js +124 -19
- package/dist/styles.css +16 -7
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ComponentType, ReactNode } from 'react';
|
|
3
|
-
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, FormTheme, FilloError, CodeForm } from '@usefillo/core';
|
|
3
|
+
import { FormSchema, FilloClient, ResponseData, FieldValue, FormPage, Block, FormStatus, FieldKind, Field, CustomField, FormTheme, FilloError, CodeForm } from '@usefillo/core';
|
|
4
4
|
export { CodeForm, Field, FieldValue, FileValue, FilloClient, FilloError, FormSchema, FormStatus, FormTheme, ProvisionWorkspaceResult, PublishedForm, ResponseData, createClient, defineForm, provisionWorkspace } from '@usefillo/core';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -47,14 +47,25 @@ interface FieldComponentProps<F extends Field = Field> {
|
|
|
47
47
|
api: FilloApi;
|
|
48
48
|
ids?: FilloFieldIds;
|
|
49
49
|
}
|
|
50
|
-
/**
|
|
51
|
-
|
|
50
|
+
/**
|
|
51
|
+
* The Field variant carrying a given kind. Some variants share a union `kind`
|
|
52
|
+
* (ChoiceField is "select" | "multi_select" | "dropdown"), so `Extract` would
|
|
53
|
+
* collapse to `never` — distribute over the union and keep the matching member.
|
|
54
|
+
*/
|
|
55
|
+
type FieldOfKind<K extends FieldKind> = Field extends infer V ? V extends Field ? K extends V["kind"] ? V : never : never : never;
|
|
56
|
+
/**
|
|
57
|
+
* Per-kind component overrides — swap any built-in field for your own. Each
|
|
58
|
+
* kind's `field` is narrowed to its variant, so an override reads it cast-free.
|
|
59
|
+
*/
|
|
60
|
+
type FieldComponents = {
|
|
61
|
+
[K in FieldKind]?: ComponentType<FieldComponentProps<FieldOfKind<K>>>;
|
|
62
|
+
};
|
|
52
63
|
/**
|
|
53
64
|
* Renderers for your own field kinds, keyed by a custom field's `component`.
|
|
54
65
|
* A block `{ kind: "custom", component: "color", config: {...} }` renders
|
|
55
66
|
* `customComponents.color`. The component reads `field.config` for options.
|
|
56
67
|
*/
|
|
57
|
-
type CustomComponents = Record<string, ComponentType<FieldComponentProps
|
|
68
|
+
type CustomComponents = Record<string, ComponentType<FieldComponentProps<CustomField>>>;
|
|
58
69
|
|
|
59
70
|
interface FilloFormBaseProps {
|
|
60
71
|
theme?: FormTheme;
|
package/dist/index.js
CHANGED
|
@@ -138,6 +138,7 @@ import { memo, useEffect as useEffect6, useState as useState5 } from "react";
|
|
|
138
138
|
import {
|
|
139
139
|
PHONE_COUNTRIES,
|
|
140
140
|
countryByIso,
|
|
141
|
+
countryByTimeZone,
|
|
141
142
|
digitsOnly,
|
|
142
143
|
flagEmoji,
|
|
143
144
|
formatNational,
|
|
@@ -152,17 +153,58 @@ function localeCountry() {
|
|
|
152
153
|
const region = tag.split("-")[1];
|
|
153
154
|
return region && /^[A-Za-z]{2}$/.test(region) ? region.toUpperCase() : void 0;
|
|
154
155
|
}
|
|
156
|
+
function browserTimeZone() {
|
|
157
|
+
if (typeof Intl === "undefined") return void 0;
|
|
158
|
+
try {
|
|
159
|
+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
160
|
+
return typeof timeZone === "string" && timeZone ? timeZone : void 0;
|
|
161
|
+
} catch {
|
|
162
|
+
return void 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
155
165
|
function nationalFor(stored, country) {
|
|
156
166
|
const digits = digitsOnly(stored);
|
|
157
167
|
return digits.startsWith(country.dialCode) ? digits.slice(country.dialCode.length) : digits;
|
|
158
168
|
}
|
|
169
|
+
var PHONE_POPOVER_VIEWPORT_GAP = 8;
|
|
170
|
+
function positionPhonePopover(anchor, popover) {
|
|
171
|
+
if (!anchor || !popover || typeof window === "undefined") return "below";
|
|
172
|
+
const gap = PHONE_POPOVER_VIEWPORT_GAP;
|
|
173
|
+
const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
|
|
174
|
+
const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
|
|
175
|
+
const anchorRect = anchor.getBoundingClientRect();
|
|
176
|
+
const spaceBelow = Math.max(0, viewportHeight - anchorRect.bottom - gap);
|
|
177
|
+
const spaceAbove = Math.max(0, anchorRect.top - gap);
|
|
178
|
+
const placement = spaceBelow < popover.scrollHeight && spaceAbove > spaceBelow ? "above" : "below";
|
|
179
|
+
const availableHeight = placement === "above" ? spaceAbove : spaceBelow;
|
|
180
|
+
const maxHeight = Math.max(0, Math.min(availableHeight, viewportHeight - gap * 2));
|
|
181
|
+
const maxWidth = Math.max(0, viewportWidth - gap * 2);
|
|
182
|
+
popover.style.setProperty("--fillo-phone-popover-max-height", `${Math.floor(maxHeight)}px`);
|
|
183
|
+
popover.style.setProperty("--fillo-phone-popover-max-width", `${Math.floor(maxWidth)}px`);
|
|
184
|
+
popover.style.setProperty("--fillo-phone-popover-offset-x", "0px");
|
|
185
|
+
const width = Math.min(popover.offsetWidth, maxWidth);
|
|
186
|
+
let offsetX = 0;
|
|
187
|
+
const rightOverflow = anchorRect.left + width - (viewportWidth - gap);
|
|
188
|
+
if (rightOverflow > 0) offsetX -= rightOverflow;
|
|
189
|
+
const leftOverflow = gap - (anchorRect.left + offsetX);
|
|
190
|
+
if (leftOverflow > 0) offsetX += leftOverflow;
|
|
191
|
+
popover.style.setProperty("--fillo-phone-popover-offset-x", `${Math.round(offsetX)}px`);
|
|
192
|
+
return placement;
|
|
193
|
+
}
|
|
159
194
|
function PhoneField({ field, value, error, setValue, ids: providedIds }) {
|
|
160
195
|
const ids = useFilloFieldIds(field.id, providedIds);
|
|
161
196
|
const schema = field;
|
|
162
197
|
const stored = typeof value === "string" ? value : "";
|
|
163
198
|
const [country, setCountry] = useState2(
|
|
164
|
-
() => parsePhone(stored).country ?? countryByIso(schema.defaultCountry) ??
|
|
199
|
+
() => parsePhone(stored).country ?? countryByIso(schema.defaultCountry) ?? PHONE_COUNTRIES[0]
|
|
165
200
|
);
|
|
201
|
+
const touched = useRef2(false);
|
|
202
|
+
useEffect3(() => {
|
|
203
|
+
if (touched.current) return;
|
|
204
|
+
if (parsePhone(stored).country || countryByIso(schema.defaultCountry)) return;
|
|
205
|
+
const guess = countryByTimeZone(browserTimeZone()) ?? countryByIso(localeCountry());
|
|
206
|
+
if (guess) setCountry(guess);
|
|
207
|
+
}, []);
|
|
166
208
|
const national = nationalFor(stored, country);
|
|
167
209
|
const display = formatNational(country, national);
|
|
168
210
|
const inputRef = useRef2(null);
|
|
@@ -185,6 +227,7 @@ function PhoneField({ field, value, error, setValue, ids: providedIds }) {
|
|
|
185
227
|
});
|
|
186
228
|
const commit = (c, nat) => setValue(nat ? toE164(c, nat) : "");
|
|
187
229
|
function onInput(e) {
|
|
230
|
+
touched.current = true;
|
|
188
231
|
const el = e.target;
|
|
189
232
|
const raw = el.value;
|
|
190
233
|
const caret = el.selectionStart ?? raw.length;
|
|
@@ -198,6 +241,7 @@ function PhoneField({ field, value, error, setValue, ids: providedIds }) {
|
|
|
198
241
|
commit(country, digitsOnly(raw));
|
|
199
242
|
}
|
|
200
243
|
function pickCountry(c) {
|
|
244
|
+
touched.current = true;
|
|
201
245
|
setCountry(c);
|
|
202
246
|
commit(c, national);
|
|
203
247
|
inputRef.current?.focus();
|
|
@@ -240,7 +284,10 @@ function CountrySelect({
|
|
|
240
284
|
const [open, setOpen] = useState2(false);
|
|
241
285
|
const [query, setQuery] = useState2("");
|
|
242
286
|
const [active, setActive] = useState2(0);
|
|
287
|
+
const [placement, setPlacement] = useState2("below");
|
|
243
288
|
const rootRef = useRef2(null);
|
|
289
|
+
const triggerRef = useRef2(null);
|
|
290
|
+
const popoverRef = useRef2(null);
|
|
244
291
|
const searchRef = useRef2(null);
|
|
245
292
|
const listId = `${labelledBy}-countries`;
|
|
246
293
|
const matches = useMemo3(() => {
|
|
@@ -266,6 +313,17 @@ function CountrySelect({
|
|
|
266
313
|
document.addEventListener("mousedown", onDown);
|
|
267
314
|
return () => document.removeEventListener("mousedown", onDown);
|
|
268
315
|
}, [open]);
|
|
316
|
+
useLayoutEffect(() => {
|
|
317
|
+
if (!open) return;
|
|
318
|
+
const update = () => setPlacement(positionPhonePopover(rootRef.current, popoverRef.current));
|
|
319
|
+
update();
|
|
320
|
+
window.addEventListener("resize", update);
|
|
321
|
+
window.addEventListener("scroll", update, true);
|
|
322
|
+
return () => {
|
|
323
|
+
window.removeEventListener("resize", update);
|
|
324
|
+
window.removeEventListener("scroll", update, true);
|
|
325
|
+
};
|
|
326
|
+
}, [open, matches.length]);
|
|
269
327
|
useEffect3(() => {
|
|
270
328
|
if (!open) return;
|
|
271
329
|
document.getElementById(`${listId}-opt-${active}`)?.scrollIntoView({ block: "nearest" });
|
|
@@ -288,12 +346,14 @@ function CountrySelect({
|
|
|
288
346
|
} else if (e.key === "Escape") {
|
|
289
347
|
e.preventDefault();
|
|
290
348
|
setOpen(false);
|
|
349
|
+
triggerRef.current?.focus();
|
|
291
350
|
}
|
|
292
351
|
}
|
|
293
352
|
return /* @__PURE__ */ jsxs("div", { className: "fillo-phone-country", ref: rootRef, children: [
|
|
294
353
|
/* @__PURE__ */ jsxs(
|
|
295
354
|
"button",
|
|
296
355
|
{
|
|
356
|
+
ref: triggerRef,
|
|
297
357
|
type: "button",
|
|
298
358
|
className: "fillo-phone-flag",
|
|
299
359
|
"aria-haspopup": "listbox",
|
|
@@ -310,7 +370,7 @@ function CountrySelect({
|
|
|
310
370
|
]
|
|
311
371
|
}
|
|
312
372
|
),
|
|
313
|
-
open && /* @__PURE__ */ jsxs("div", { className:
|
|
373
|
+
open && /* @__PURE__ */ jsxs("div", { ref: popoverRef, className: `fillo-phone-popover fillo-phone-popover--${placement}`, children: [
|
|
314
374
|
/* @__PURE__ */ jsx(
|
|
315
375
|
"input",
|
|
316
376
|
{
|
|
@@ -603,7 +663,7 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
603
663
|
}
|
|
604
664
|
const describedBy = [field.description ? ids.descriptionId : null, error ? ids.errorId : null].filter(Boolean).join(" ") || void 0;
|
|
605
665
|
return /* @__PURE__ */ jsxs3("div", { className: `fillo-field fillo-field--file_upload${error ? " fillo-field--error" : ""}`, children: [
|
|
606
|
-
/* @__PURE__ */ jsxs3("label", { className: "fillo-label", htmlFor: ids.inputId, children: [
|
|
666
|
+
/* @__PURE__ */ jsxs3("label", { className: "fillo-label", id: ids.labelId, htmlFor: ids.inputId, children: [
|
|
607
667
|
field.label,
|
|
608
668
|
!field.required && /* @__PURE__ */ jsx3("span", { className: "fillo-optional", children: " (optional)" })
|
|
609
669
|
] }),
|
|
@@ -625,6 +685,10 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
625
685
|
onClick: () => canUpload && inputRef.current?.click(),
|
|
626
686
|
role: "button",
|
|
627
687
|
tabIndex: 0,
|
|
688
|
+
"aria-labelledby": ids.labelId,
|
|
689
|
+
"aria-required": field.required ? true : void 0,
|
|
690
|
+
"aria-invalid": error ? true : void 0,
|
|
691
|
+
"aria-describedby": describedBy,
|
|
628
692
|
onKeyDown: (e) => {
|
|
629
693
|
if ((e.key === "Enter" || e.key === " ") && canUpload) inputRef.current?.click();
|
|
630
694
|
},
|
|
@@ -636,9 +700,6 @@ function FileUploadField({ field, value, error, setValue, api, ids: providedIds
|
|
|
636
700
|
id: ids.inputId,
|
|
637
701
|
type: "file",
|
|
638
702
|
hidden: true,
|
|
639
|
-
"aria-invalid": error ? true : void 0,
|
|
640
|
-
"aria-required": field.required ? true : void 0,
|
|
641
|
-
"aria-describedby": describedBy,
|
|
642
703
|
multiple: maxFiles > 1,
|
|
643
704
|
accept: schema.accept?.join(","),
|
|
644
705
|
onChange: (e) => handleFiles(e.target.files)
|
|
@@ -740,6 +801,9 @@ function fieldAria(field, error, ids) {
|
|
|
740
801
|
"aria-describedby": describedBy.length ? describedBy.join(" ") : void 0
|
|
741
802
|
};
|
|
742
803
|
}
|
|
804
|
+
function isNativeControlTarget(target) {
|
|
805
|
+
return target instanceof HTMLElement && Boolean(target.closest("input, textarea, select, button"));
|
|
806
|
+
}
|
|
743
807
|
function FieldShell({
|
|
744
808
|
field,
|
|
745
809
|
error,
|
|
@@ -852,6 +916,12 @@ function SingleChoice({ field, value, error, setValue, ids: providedIds }) {
|
|
|
852
916
|
{
|
|
853
917
|
"data-option": opt.id,
|
|
854
918
|
className: `fillo-option${opt.icon ? " fillo-option--has-icon" : ""}${value === opt.id ? " fillo-option--selected" : ""}`,
|
|
919
|
+
onClick: (event) => {
|
|
920
|
+
if (isNativeControlTarget(event.target)) return;
|
|
921
|
+
event.preventDefault();
|
|
922
|
+
setOtherOn(false);
|
|
923
|
+
setValue(opt.id);
|
|
924
|
+
},
|
|
855
925
|
children: [
|
|
856
926
|
/* @__PURE__ */ jsx4(
|
|
857
927
|
"input",
|
|
@@ -937,6 +1007,11 @@ function MultiChoice({ field, value, error, setValue, ids: providedIds }) {
|
|
|
937
1007
|
{
|
|
938
1008
|
"data-option": opt.id,
|
|
939
1009
|
className: `fillo-option${opt.icon ? " fillo-option--has-icon" : ""}${selected.includes(opt.id) ? " fillo-option--selected" : ""}`,
|
|
1010
|
+
onClick: (event) => {
|
|
1011
|
+
if (isNativeControlTarget(event.target)) return;
|
|
1012
|
+
event.preventDefault();
|
|
1013
|
+
toggle(opt.id);
|
|
1014
|
+
},
|
|
940
1015
|
children: [
|
|
941
1016
|
/* @__PURE__ */ jsx4(
|
|
942
1017
|
"input",
|
|
@@ -1382,8 +1457,12 @@ function blockPropsEqual(prev, next) {
|
|
|
1382
1457
|
const id = next.block.id;
|
|
1383
1458
|
if (prev.api.data[id] !== next.api.data[id]) return false;
|
|
1384
1459
|
if (prev.api.errors[id] !== next.api.errors[id]) return false;
|
|
1385
|
-
|
|
1386
|
-
|
|
1460
|
+
if (next.block.kind === "custom") {
|
|
1461
|
+
return prev.api.data === next.api.data && prev.api.status === next.api.status && prev.api.uploading === next.api.uploading && prev.api.isFirstPage === next.api.isFirstPage && prev.api.isLastPage === next.api.isLastPage && prev.api.pageIndex === next.api.pageIndex;
|
|
1462
|
+
}
|
|
1463
|
+
if ((blockHasPiping(prev.block) || blockHasPiping(next.block)) && prev.api.data !== next.api.data) {
|
|
1464
|
+
return false;
|
|
1465
|
+
}
|
|
1387
1466
|
if (next.api.form.settings.submitMode === "auto") {
|
|
1388
1467
|
if (prev.api.data !== next.api.data || prev.api.status !== next.api.status || prev.api.uploading !== next.api.uploading || prev.api.isLastPage !== next.api.isLastPage) {
|
|
1389
1468
|
return false;
|
|
@@ -1511,6 +1590,10 @@ function FilloForm(props) {
|
|
|
1511
1590
|
const inlineSchema = codeForm ? codeForm.schema : form;
|
|
1512
1591
|
const onError = props.onError;
|
|
1513
1592
|
const syncedFormId = useCodeFormSync(form, client, onError);
|
|
1593
|
+
const onErrorRef = useRef5(onError);
|
|
1594
|
+
useEffect7(() => {
|
|
1595
|
+
onErrorRef.current = onError;
|
|
1596
|
+
});
|
|
1514
1597
|
const needsFetch = !inlineSchema && Boolean(client && formId);
|
|
1515
1598
|
useEffect7(() => {
|
|
1516
1599
|
if (!needsFetch || !client || !formId) return;
|
|
@@ -1527,12 +1610,12 @@ function FilloForm(props) {
|
|
|
1527
1610
|
if (cancelled) return;
|
|
1528
1611
|
const error = err instanceof FilloError2 ? err : new FilloError2("This form could not be loaded.", 0);
|
|
1529
1612
|
setLoadError(error);
|
|
1530
|
-
|
|
1613
|
+
onErrorRef.current?.(error);
|
|
1531
1614
|
});
|
|
1532
1615
|
return () => {
|
|
1533
1616
|
cancelled = true;
|
|
1534
1617
|
};
|
|
1535
|
-
}, [needsFetch, client, formId
|
|
1618
|
+
}, [needsFetch, client, formId]);
|
|
1536
1619
|
const rawSchema = inlineSchema ?? fetched;
|
|
1537
1620
|
const normalized = useMemo4(() => rawSchema ? normalizeFormSchema(rawSchema) : null, [rawSchema]);
|
|
1538
1621
|
const schema = normalized?.ok ? normalized.schema : null;
|
|
@@ -1618,15 +1701,37 @@ function ResolvedForm(props) {
|
|
|
1618
1701
|
const url = safeHttpUrl(settings.redirectUrl);
|
|
1619
1702
|
if (url) window.location.assign(url);
|
|
1620
1703
|
}, [submitted, settings.redirectUrl]);
|
|
1704
|
+
const successRef = useRef5(null);
|
|
1705
|
+
useEffect7(() => {
|
|
1706
|
+
if (submitted) successRef.current?.focus();
|
|
1707
|
+
}, [submitted]);
|
|
1708
|
+
const blocksRef = useRef5(null);
|
|
1709
|
+
const prevPageIndex = useRef5(api.pageIndex);
|
|
1710
|
+
useEffect7(() => {
|
|
1711
|
+
if (prevPageIndex.current === api.pageIndex) return;
|
|
1712
|
+
prevPageIndex.current = api.pageIndex;
|
|
1713
|
+
blocksRef.current?.focus();
|
|
1714
|
+
}, [api.pageIndex]);
|
|
1621
1715
|
if (api.status === "submitted") {
|
|
1622
|
-
return /* @__PURE__ */ jsxs5(
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1716
|
+
return /* @__PURE__ */ jsxs5(
|
|
1717
|
+
"div",
|
|
1718
|
+
{
|
|
1719
|
+
ref: successRef,
|
|
1720
|
+
tabIndex: -1,
|
|
1721
|
+
role: "status",
|
|
1722
|
+
"aria-live": "polite",
|
|
1723
|
+
className: `fillo-form fillo-form--success ${props.className ?? ""}`,
|
|
1724
|
+
...themed,
|
|
1725
|
+
children: [
|
|
1726
|
+
props.renderSuccess ? props.renderSuccess() : /* @__PURE__ */ jsxs5("div", { className: "fillo-success", children: [
|
|
1727
|
+
/* @__PURE__ */ jsx5("div", { className: "fillo-success-mark", "aria-hidden": "true", children: "\u2713" }),
|
|
1728
|
+
/* @__PURE__ */ jsx5("h2", { className: "fillo-success-title", children: settings.successTitle ?? "Thanks!" }),
|
|
1729
|
+
/* @__PURE__ */ jsx5("p", { className: "fillo-success-message", children: settings.successMessage ?? "Your response has been recorded." })
|
|
1730
|
+
] }),
|
|
1731
|
+
props.poweredBy && /* @__PURE__ */ jsx5(PoweredBy, { label: props.brandLabel, href: props.brandHref })
|
|
1732
|
+
]
|
|
1733
|
+
}
|
|
1734
|
+
);
|
|
1630
1735
|
}
|
|
1631
1736
|
const multiPage = api.pageCount > 1;
|
|
1632
1737
|
const autoSubmit = settings.submitMode === "auto";
|
|
@@ -1671,7 +1776,7 @@ function ResolvedForm(props) {
|
|
|
1671
1776
|
schema.description && /* @__PURE__ */ jsx5("p", { className: "fillo-form-description", children: schema.description })
|
|
1672
1777
|
] }),
|
|
1673
1778
|
multiPage && api.page.title && api.pageIndex > 0 && /* @__PURE__ */ jsx5("h2", { className: "fillo-page-title", children: api.page.title }),
|
|
1674
|
-
/* @__PURE__ */ jsx5("div", { className: "fillo-blocks", children: api.blocks.map((block) => /* @__PURE__ */ jsx5(
|
|
1779
|
+
/* @__PURE__ */ jsx5("div", { className: "fillo-blocks", ref: blocksRef, tabIndex: -1, children: api.blocks.map((block) => /* @__PURE__ */ jsx5(
|
|
1675
1780
|
BlockRenderer,
|
|
1676
1781
|
{
|
|
1677
1782
|
block,
|
package/dist/styles.css
CHANGED
|
@@ -126,12 +126,18 @@
|
|
|
126
126
|
.fillo-field--error .fillo-phone-flag { border-color: var(--fillo-error); }
|
|
127
127
|
.fillo-phone-popover {
|
|
128
128
|
position: absolute; z-index: 30; top: calc(100% + 0.3rem); left: 0;
|
|
129
|
-
width: 18rem
|
|
129
|
+
width: min(18rem, calc(100vw - 1rem));
|
|
130
|
+
max-width: var(--fillo-phone-popover-max-width, 84vw);
|
|
131
|
+
max-height: min(var(--fillo-phone-popover-max-height, 20rem), calc(100vh - 1rem));
|
|
132
|
+
padding: 0.4rem;
|
|
133
|
+
box-sizing: border-box; overflow: hidden;
|
|
134
|
+
transform: translateX(var(--fillo-phone-popover-offset-x, 0px));
|
|
130
135
|
display: flex; flex-direction: column; gap: 0.35rem;
|
|
131
136
|
background: var(--fillo-control-bg);
|
|
132
137
|
border: 1px solid var(--fillo-border); border-radius: var(--fillo-radius);
|
|
133
138
|
box-shadow: 0 12px 32px -14px rgba(0, 0, 0, 0.35);
|
|
134
139
|
}
|
|
140
|
+
.fillo-phone-popover--above { top: auto; bottom: calc(100% + 0.3rem); }
|
|
135
141
|
.fillo-phone-search {
|
|
136
142
|
appearance: none; font: inherit; width: 100%; box-sizing: border-box;
|
|
137
143
|
color: var(--fillo-text); background: var(--fillo-bg);
|
|
@@ -139,7 +145,10 @@
|
|
|
139
145
|
border-radius: calc(var(--fillo-radius) - 3px); padding: 0.45rem 0.6rem;
|
|
140
146
|
}
|
|
141
147
|
.fillo-phone-search:focus-visible { outline: none; border-color: var(--fillo-primary); }
|
|
142
|
-
.fillo-phone-list {
|
|
148
|
+
.fillo-phone-list {
|
|
149
|
+
flex: 1 1 auto; min-height: 0;
|
|
150
|
+
list-style: none; margin: 0; padding: 0; max-height: 14rem; overflow-y: auto;
|
|
151
|
+
}
|
|
143
152
|
.fillo-phone-option {
|
|
144
153
|
display: flex; align-items: center; gap: 0.5rem;
|
|
145
154
|
padding: 0.45rem 0.5rem; border-radius: calc(var(--fillo-radius) - 3px);
|
|
@@ -586,17 +595,17 @@
|
|
|
586
595
|
}
|
|
587
596
|
|
|
588
597
|
/* ---------- Success ---------- */
|
|
589
|
-
.fillo-success { display: flex; flex-direction: column; align-items: center; gap: 0.
|
|
598
|
+
.fillo-success { display: flex; flex-direction: column; align-items: center; gap: 0.4rem; text-align: center; padding: 1.4rem 1rem; }
|
|
590
599
|
.fillo-success-mark {
|
|
591
|
-
width:
|
|
600
|
+
width: 2rem; height: 2rem;
|
|
592
601
|
display: grid; place-items: center;
|
|
593
602
|
border-radius: 999px;
|
|
594
603
|
background: color-mix(in srgb, var(--fillo-primary) 10%, transparent);
|
|
595
604
|
color: var(--fillo-primary);
|
|
596
|
-
font-size:
|
|
605
|
+
font-size: 0.95rem; font-weight: 700;
|
|
597
606
|
}
|
|
598
|
-
.fillo-success-title { margin: 0; font-size: 1.
|
|
599
|
-
.fillo-success-message { margin: 0; color: var(--fillo-muted); }
|
|
607
|
+
.fillo-success-title { margin: 0; font-size: 1.05rem; letter-spacing: 0; }
|
|
608
|
+
.fillo-success-message { margin: 0; font-size: 0.875rem; color: var(--fillo-muted); }
|
|
600
609
|
|
|
601
610
|
/* Honeypot — off-screen, never display:none (bots check that) */
|
|
602
611
|
.fillo-hp {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usefillo/react",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
4
4
|
"description": "Headless React components for embedding Fillo forms natively in your product.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@usefillo/core": "^0.5.
|
|
35
|
+
"@usefillo/core": "^0.5.1"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": "^18.0.0 || ^19.0.0",
|