@usefillo/core 0.24.1 → 0.26.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 +66 -6
- package/dist/index.js +110 -10
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -95,6 +95,11 @@ interface RatingField extends BaseField {
|
|
|
95
95
|
}
|
|
96
96
|
interface DateField extends BaseField {
|
|
97
97
|
kind: "date";
|
|
98
|
+
/**
|
|
99
|
+
* Start on today's date — the respondent's own day, set by their device once
|
|
100
|
+
* the form loads (the server can't know their time zone). They can change it.
|
|
101
|
+
*/
|
|
102
|
+
defaultToday?: boolean;
|
|
98
103
|
}
|
|
99
104
|
interface LinearScaleField extends BaseField {
|
|
100
105
|
kind: "linear_scale";
|
|
@@ -300,8 +305,12 @@ interface ResponseLimit {
|
|
|
300
305
|
* and anonymous embeds can still dedupe.
|
|
301
306
|
* - "identify": the identify() respondent (HMAC-verifiable). The strong
|
|
302
307
|
* path; only embedded surfaces that call identify() are recognized.
|
|
308
|
+
* - "email": a verified email address. On the form's Fillo link the person
|
|
309
|
+
* confirms their email with a 6-digit code before filling in, and the
|
|
310
|
+
* device stays confirmed for 30 days. Embedded forms can't show that
|
|
311
|
+
* step — use "identify" there.
|
|
303
312
|
*/
|
|
304
|
-
by: "browser" | "field" | "identify";
|
|
313
|
+
by: "browser" | "field" | "identify" | "email";
|
|
305
314
|
/** The email/phone field whose answer identifies the person. `by: "field"` only. */
|
|
306
315
|
field?: string;
|
|
307
316
|
/**
|
|
@@ -315,7 +324,8 @@ interface ResponseLimit {
|
|
|
315
324
|
* response (the first answer stands); "update" edits it in place (re-anchored
|
|
316
325
|
* to the current schema, `response.updated` webhook, previous answers
|
|
317
326
|
* prefilled for a verified respondent). "update" applies to `by: "identify"`
|
|
318
|
-
* only — a self-claim/browser must not overwrite another
|
|
327
|
+
* and `by: "email"` only — a self-claim/browser must not overwrite another
|
|
328
|
+
* person's response.
|
|
319
329
|
*/
|
|
320
330
|
onRepeat: "keep" | "update";
|
|
321
331
|
}
|
|
@@ -401,16 +411,31 @@ interface FormSchema {
|
|
|
401
411
|
pages: FormPage[];
|
|
402
412
|
settings: FormSettings;
|
|
403
413
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
colorScheme?: "light" | "dark" | "auto";
|
|
414
|
+
/** The colors (and logo) of one appearance. */
|
|
415
|
+
interface FormThemePalette {
|
|
407
416
|
/** Accent for buttons, focus rings, selection. */
|
|
408
417
|
primary?: string;
|
|
409
418
|
background?: string;
|
|
410
419
|
text?: string;
|
|
420
|
+
/**
|
|
421
|
+
* Logo shown above the form on Fillo-hosted pages: the id of an image
|
|
422
|
+
* uploaded to the workspace. Embedded forms leave branding to the host app.
|
|
423
|
+
*/
|
|
424
|
+
logo?: string;
|
|
425
|
+
}
|
|
426
|
+
interface FormTheme extends FormThemePalette {
|
|
427
|
+
/** Omit to inherit the host page. Use "auto" to follow the visitor's system directly. */
|
|
428
|
+
colorScheme?: "light" | "dark" | "auto";
|
|
411
429
|
/** Border radius scale, e.g. "8px". */
|
|
412
430
|
radius?: string;
|
|
413
431
|
fontFamily?: string;
|
|
432
|
+
/**
|
|
433
|
+
* Dark-mode colors, for a form that follows a light/dark setting
|
|
434
|
+
* (`colorScheme` omitted or "auto"). The top-level colors are then the
|
|
435
|
+
* light palette. An unset dark color uses the default dark token; an unset
|
|
436
|
+
* dark logo reuses the top-level logo. Ignored when `colorScheme` is fixed.
|
|
437
|
+
*/
|
|
438
|
+
dark?: FormThemePalette;
|
|
414
439
|
}
|
|
415
440
|
/** Branding the server tells the SDK to render. Server-owned so the wording /
|
|
416
441
|
* link can change centrally without a new SDK release. */
|
|
@@ -1980,6 +2005,8 @@ declare const FILLO_THEME_VARS: readonly [{
|
|
|
1980
2005
|
readonly var: "--fillo-muted";
|
|
1981
2006
|
}, {
|
|
1982
2007
|
readonly var: "--fillo-border";
|
|
2008
|
+
}, {
|
|
2009
|
+
readonly var: "--fillo-control-border";
|
|
1983
2010
|
}, {
|
|
1984
2011
|
readonly var: "--fillo-control-bg";
|
|
1985
2012
|
}, {
|
|
@@ -2006,6 +2033,30 @@ declare const FILLO_THEME_VARS: readonly [{
|
|
|
2006
2033
|
* `[data-fillo-color-scheme="dark"]` CSS, so no new CSS is needed.
|
|
2007
2034
|
*/
|
|
2008
2035
|
declare function resolveThemeAppearance(theme: FormTheme | null): FormTheme | null;
|
|
2036
|
+
/**
|
|
2037
|
+
* True when the theme switches palettes with the light/dark setting: it has
|
|
2038
|
+
* dark colors and its scheme is not fixed (omitted or "auto"). A dark logo
|
|
2039
|
+
* alone switches nothing.
|
|
2040
|
+
*/
|
|
2041
|
+
declare function themeHasDarkPalette(theme: FormTheme | null | undefined): boolean;
|
|
2042
|
+
interface ThemeDomAttributes {
|
|
2043
|
+
/** Inline custom properties for the form root (`--fillo-primary`, …). */
|
|
2044
|
+
vars: Record<string, string>;
|
|
2045
|
+
/** `data-fillo-*` attributes for the form root. */
|
|
2046
|
+
attrs: Record<string, string>;
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* Turn an untrusted theme into the form root's inline custom properties and
|
|
2050
|
+
* data attributes — one implementation for every renderer.
|
|
2051
|
+
*
|
|
2052
|
+
* A theme with a dark palette (see themeHasDarkPalette) emits each color as
|
|
2053
|
+
* `light-dark(light, dark)`, so it follows the form's own color-scheme: the
|
|
2054
|
+
* host page's when `colorScheme` is omitted, the visitor's device on "auto".
|
|
2055
|
+
* `data-fillo-on-primary` (and `-dark`) name the text tone that reads on a
|
|
2056
|
+
* custom accent; the stylesheet maps them to `--fillo-primary-contrast`, which
|
|
2057
|
+
* stays overridable from consumer CSS.
|
|
2058
|
+
*/
|
|
2059
|
+
declare function resolveThemeDom(theme: FormTheme | null | undefined): ThemeDomAttributes | null;
|
|
2009
2060
|
|
|
2010
2061
|
/** Result of syncing a code-defined form: its canonical id, slug, and branding. */
|
|
2011
2062
|
interface SyncedForm {
|
|
@@ -2208,6 +2259,15 @@ declare function isBuildTimeDevEnv(): boolean;
|
|
|
2208
2259
|
*/
|
|
2209
2260
|
declare function isLikelyDevEnv(): boolean;
|
|
2210
2261
|
|
|
2262
|
+
/** A device's local calendar date as YYYY-MM-DD — the value a date field holds. */
|
|
2263
|
+
declare function localDateString(now?: Date): string;
|
|
2264
|
+
/**
|
|
2265
|
+
* Fill each unanswered date field that starts on today (`defaultToday`). Only
|
|
2266
|
+
* the respondent's device knows their "today" (time zone), so renderers apply
|
|
2267
|
+
* this in the browser after hydration, never on the server. Returns `data`
|
|
2268
|
+
* itself when nothing needed filling.
|
|
2269
|
+
*/
|
|
2270
|
+
declare function applyDateDefaults(form: FormSchema, data: ResponseData, now?: Date): ResponseData;
|
|
2211
2271
|
/**
|
|
2212
2272
|
* Build initial response data from URL query parameters — Tally-style
|
|
2213
2273
|
* prefilling. Hidden fields read their configured paramName; every other
|
|
@@ -2252,4 +2312,4 @@ declare class Sha1 {
|
|
|
2252
2312
|
}
|
|
2253
2313
|
declare const sha1Base64: (bytes: Uint8Array) => string;
|
|
2254
2314
|
|
|
2255
|
-
export { type AutoSubmitContext, BLOCK_KIND_META, type BaseField, type Block, type BlockKind, CONTENT_KINDS, type CalcExpr, type CalculatedField, type ChallengeConfig, type ChallengeTheme, type CheckboxField, type ChoiceField, type CodeForm, type Condition, type ConditionOp, type ContentBlock, type ContentKind, type CreatedDraft, type CustomField, DEFAULT_FIELD_STRINGS, DEFAULT_RESPONDENT_ERROR_STRINGS, DEFAULT_STRINGS, DRAFT_KINDS, type DateField, type DividerBlock, FILLO_CALC_MIN_SDK_VERSION, FILLO_CHALLENGE_MIN_SDK_VERSION, FILLO_DATA_ATTRS, FILLO_GROUP_MIN_SDK_VERSION, FILLO_MIN_SDK_VERSION, FILLO_SCHEMA_VERSION, FILLO_SDK_VERSION, FILLO_SLOTS, FILLO_THEME_VARS, type Field, type FieldKind, type FieldSpec, type FieldValue, type FileUploadField, type FileValue, type FilloAppearance, FilloClient, type FilloClientOptions, FilloError, type FilloFieldStrings, FilloJsxError, type FilloRendererStrings, type FilloRespondent, type FilloSlot, type FilloStrings, type FormBranding, type FormController, type FormControllerOptions, type FormControllerState, type FormDraftSpec, type FormPage, type FormSchema, type FormSettings, type FormStatus, type FormTheme, type GroupInstanceValue, type HeadingBlock, type HiddenField, JSX_BLOCK_COMPONENTS, JSX_BLOCK_SPECS, type JsonValue, type JsxFormMeta, type JumpRule, type LinearScaleField, MAX_FILES_PER_FIELD, type MatrixField, type NextPage, type NumberField, PHONE_COUNTRIES, PHONE_PICKER_COUNTRIES, PHONE_POPOVER_VIEWPORT_GAP, type ParagraphBlock, type ParsePhoneOptions, type ParsedPhone, type PhoneCountry, type PhoneField, type PhonePopoverPlacement, type ProvisionWorkspaceResult, type PublishedForm, REQUIRED_FIELD_MESSAGE, type RankingField, type RatingField, type RepeatingGroupField, type RespondentErrorOverrides, type RespondentErrorStrings, type ResponseData, type ResponseDraft, type ResponseLimit, type SchemaValidationResult, type SelectOption, Sha1, type SignatureField, type SlotClass, type SlotState, type SubmitMeta, type SubmitResult, type SyncFormResult, type SyncedForm, type TextField, type TrustPolicy, type UploadFileOptions, type UploadProgress, type UploadSession, type UploadStatus, type UploadTransport, type ValidationResult, type WhenBuilder, allFields, assembleForm, codeFormFromJsx, computeCalculated, conditionsMet, contentHash, countryByDialCode, countryByIso, countryByTimeZone, createBlock, createClient, createEmptyForm, createFormController, createId, defineForm, digitsOnly, evaluateCalc, flagEmoji, formSchemasEqual, formatAnswer, formatGroupedNumber, formatNational, isAutoSubmitBlock, isBlockVisible, isBuildTimeDevEnv, isCodeForm, isField, isFilloError, isLikelyDevEnv, isPossiblePhone, isTerminalPage, isValidPartialNumberText, localeForNotation, needsExplicitSubmit, normalizeFormSchema, normalizeFormTheme, normalizeSettings, parseGroupedNumber, parsePhone, pipeBlock, positionPhonePopover, prefillFromParams, provisionWorkspace, radioGroupStep, reachableFieldIds, reachableFields, reachablePageIds, reachablePageSequence, requiredFieldMessage, resolveNextPage, resolveSlotClass, resolveStrings, resolveText, resolveThemeAppearance, respondentErrorStringsFor, responseScopeValue, schemaFromJsx, sha1Base64, shouldAutoSubmit, slotClass, syncCodeForm, toE164, validateField, validateFormSchema, validateResponse, visibleBlocks, visibleFields, visibleGroupChildren, visiblePageBlocks, when };
|
|
2315
|
+
export { type AutoSubmitContext, BLOCK_KIND_META, type BaseField, type Block, type BlockKind, CONTENT_KINDS, type CalcExpr, type CalculatedField, type ChallengeConfig, type ChallengeTheme, type CheckboxField, type ChoiceField, type CodeForm, type Condition, type ConditionOp, type ContentBlock, type ContentKind, type CreatedDraft, type CustomField, DEFAULT_FIELD_STRINGS, DEFAULT_RESPONDENT_ERROR_STRINGS, DEFAULT_STRINGS, DRAFT_KINDS, type DateField, type DividerBlock, FILLO_CALC_MIN_SDK_VERSION, FILLO_CHALLENGE_MIN_SDK_VERSION, FILLO_DATA_ATTRS, FILLO_GROUP_MIN_SDK_VERSION, FILLO_MIN_SDK_VERSION, FILLO_SCHEMA_VERSION, FILLO_SDK_VERSION, FILLO_SLOTS, FILLO_THEME_VARS, type Field, type FieldKind, type FieldSpec, type FieldValue, type FileUploadField, type FileValue, type FilloAppearance, FilloClient, type FilloClientOptions, FilloError, type FilloFieldStrings, FilloJsxError, type FilloRendererStrings, type FilloRespondent, type FilloSlot, type FilloStrings, type FormBranding, type FormController, type FormControllerOptions, type FormControllerState, type FormDraftSpec, type FormPage, type FormSchema, type FormSettings, type FormStatus, type FormTheme, type FormThemePalette, type GroupInstanceValue, type HeadingBlock, type HiddenField, JSX_BLOCK_COMPONENTS, JSX_BLOCK_SPECS, type JsonValue, type JsxFormMeta, type JumpRule, type LinearScaleField, MAX_FILES_PER_FIELD, type MatrixField, type NextPage, type NumberField, PHONE_COUNTRIES, PHONE_PICKER_COUNTRIES, PHONE_POPOVER_VIEWPORT_GAP, type ParagraphBlock, type ParsePhoneOptions, type ParsedPhone, type PhoneCountry, type PhoneField, type PhonePopoverPlacement, type ProvisionWorkspaceResult, type PublishedForm, REQUIRED_FIELD_MESSAGE, type RankingField, type RatingField, type RepeatingGroupField, type RespondentErrorOverrides, type RespondentErrorStrings, type ResponseData, type ResponseDraft, type ResponseLimit, type SchemaValidationResult, type SelectOption, Sha1, type SignatureField, type SlotClass, type SlotState, type SubmitMeta, type SubmitResult, type SyncFormResult, type SyncedForm, type TextField, type ThemeDomAttributes, type TrustPolicy, type UploadFileOptions, type UploadProgress, type UploadSession, type UploadStatus, type UploadTransport, type ValidationResult, type WhenBuilder, allFields, applyDateDefaults, assembleForm, codeFormFromJsx, computeCalculated, conditionsMet, contentHash, countryByDialCode, countryByIso, countryByTimeZone, createBlock, createClient, createEmptyForm, createFormController, createId, defineForm, digitsOnly, evaluateCalc, flagEmoji, formSchemasEqual, formatAnswer, formatGroupedNumber, formatNational, isAutoSubmitBlock, isBlockVisible, isBuildTimeDevEnv, isCodeForm, isField, isFilloError, isLikelyDevEnv, isPossiblePhone, isTerminalPage, isValidPartialNumberText, localDateString, localeForNotation, needsExplicitSubmit, normalizeFormSchema, normalizeFormTheme, normalizeSettings, parseGroupedNumber, parsePhone, pipeBlock, positionPhonePopover, prefillFromParams, provisionWorkspace, radioGroupStep, reachableFieldIds, reachableFields, reachablePageIds, reachablePageSequence, requiredFieldMessage, resolveNextPage, resolveSlotClass, resolveStrings, resolveText, resolveThemeAppearance, resolveThemeDom, respondentErrorStringsFor, responseScopeValue, schemaFromJsx, sha1Base64, shouldAutoSubmit, slotClass, syncCodeForm, themeHasDarkPalette, toE164, validateField, validateFormSchema, validateResponse, visibleBlocks, visibleFields, visibleGroupChildren, visiblePageBlocks, when };
|
package/dist/index.js
CHANGED
|
@@ -1114,7 +1114,7 @@ var schemaShape = z2.object({
|
|
|
1114
1114
|
});
|
|
1115
1115
|
var MAX_SCHEMA_VERSION = 1;
|
|
1116
1116
|
var FILLO_SCHEMA_VERSION = 1;
|
|
1117
|
-
var FILLO_SDK_VERSION = true ? "0.
|
|
1117
|
+
var FILLO_SDK_VERSION = true ? "0.26.0" : "0.0.0-dev";
|
|
1118
1118
|
var FILLO_MIN_SDK_VERSION = "0.4.0";
|
|
1119
1119
|
var FILLO_CHALLENGE_MIN_SDK_VERSION = "0.9.0";
|
|
1120
1120
|
var FILLO_CALC_MIN_SDK_VERSION = "0.11.0";
|
|
@@ -1560,12 +1560,12 @@ function normalizeUrl(value) {
|
|
|
1560
1560
|
function normalizeResponseLimit(value) {
|
|
1561
1561
|
if (!value || typeof value !== "object") return void 0;
|
|
1562
1562
|
const rec = value;
|
|
1563
|
-
const by = rec.by === "browser" || rec.by === "field" || rec.by === "identify" ? rec.by : void 0;
|
|
1563
|
+
const by = rec.by === "browser" || rec.by === "field" || rec.by === "identify" || rec.by === "email" ? rec.by : void 0;
|
|
1564
1564
|
if (!by) return void 0;
|
|
1565
1565
|
const field2 = by === "field" ? optionalStr(rec.field, 128) : void 0;
|
|
1566
1566
|
if (by === "field" && !field2) return void 0;
|
|
1567
1567
|
const scopeField = optionalStr(rec.scopeField, 128);
|
|
1568
|
-
const onRepeat = rec.onRepeat === "update" && by === "identify" ? "update" : "keep";
|
|
1568
|
+
const onRepeat = rec.onRepeat === "update" && (by === "identify" || by === "email") ? "update" : "keep";
|
|
1569
1569
|
return {
|
|
1570
1570
|
by,
|
|
1571
1571
|
...field2 ? { field: field2 } : {},
|
|
@@ -1675,8 +1675,12 @@ function normalizeBlock(input) {
|
|
|
1675
1675
|
});
|
|
1676
1676
|
}
|
|
1677
1677
|
case "signature":
|
|
1678
|
-
case "date":
|
|
1679
1678
|
return cleanObject(baseField(rec, kind));
|
|
1679
|
+
case "date":
|
|
1680
|
+
return cleanObject({
|
|
1681
|
+
...baseField(rec, kind),
|
|
1682
|
+
defaultToday: rec.defaultToday === true ? true : void 0
|
|
1683
|
+
});
|
|
1680
1684
|
case "rating": {
|
|
1681
1685
|
const max = int(rec.max, 1, 10, 5);
|
|
1682
1686
|
return cleanObject({
|
|
@@ -1893,17 +1897,30 @@ function safeCssToken(value, max) {
|
|
|
1893
1897
|
if (/[;{}<>]/.test(token) || /url\s*\(/i.test(token)) return void 0;
|
|
1894
1898
|
return token;
|
|
1895
1899
|
}
|
|
1900
|
+
function themeAssetId(value) {
|
|
1901
|
+
return typeof value === "string" && /^[A-Za-z0-9_-]{8,64}$/.test(value) ? value : void 0;
|
|
1902
|
+
}
|
|
1903
|
+
function normalizeThemePalette(input) {
|
|
1904
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return void 0;
|
|
1905
|
+
const rec = input;
|
|
1906
|
+
const palette = cleanObject({
|
|
1907
|
+
primary: safeCssToken(rec.primary, 200),
|
|
1908
|
+
background: safeCssToken(rec.background, 200),
|
|
1909
|
+
text: safeCssToken(rec.text, 200),
|
|
1910
|
+
logo: themeAssetId(rec.logo)
|
|
1911
|
+
});
|
|
1912
|
+
return Object.keys(palette).length > 0 ? palette : void 0;
|
|
1913
|
+
}
|
|
1896
1914
|
function normalizeFormTheme(input) {
|
|
1897
1915
|
if (!input || typeof input !== "object" || Array.isArray(input)) return null;
|
|
1898
1916
|
const rec = input;
|
|
1899
1917
|
const colorScheme = rec.colorScheme === "light" || rec.colorScheme === "dark" || rec.colorScheme === "auto" ? rec.colorScheme : void 0;
|
|
1900
1918
|
const theme = cleanObject({
|
|
1901
1919
|
colorScheme,
|
|
1902
|
-
|
|
1903
|
-
background: safeCssToken(rec.background, 200),
|
|
1904
|
-
text: safeCssToken(rec.text, 200),
|
|
1920
|
+
...normalizeThemePalette(rec),
|
|
1905
1921
|
radius: safeCssToken(rec.radius, 64),
|
|
1906
|
-
fontFamily: safeCssToken(rec.fontFamily, 200)
|
|
1922
|
+
fontFamily: safeCssToken(rec.fontFamily, 200),
|
|
1923
|
+
dark: normalizeThemePalette(rec.dark)
|
|
1907
1924
|
});
|
|
1908
1925
|
return Object.keys(theme).length > 0 ? theme : null;
|
|
1909
1926
|
}
|
|
@@ -3228,6 +3245,20 @@ function parseDecimal(raw) {
|
|
|
3228
3245
|
const n = Number(s);
|
|
3229
3246
|
return Number.isFinite(n) ? n : null;
|
|
3230
3247
|
}
|
|
3248
|
+
function localDateString(now = /* @__PURE__ */ new Date()) {
|
|
3249
|
+
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
3250
|
+
const day = String(now.getDate()).padStart(2, "0");
|
|
3251
|
+
return `${now.getFullYear()}-${month}-${day}`;
|
|
3252
|
+
}
|
|
3253
|
+
function applyDateDefaults(form, data, now = /* @__PURE__ */ new Date()) {
|
|
3254
|
+
let next = null;
|
|
3255
|
+
for (const field2 of allFields(form)) {
|
|
3256
|
+
if (field2.kind !== "date" || !field2.defaultToday || data[field2.id] !== void 0) continue;
|
|
3257
|
+
next = next ?? { ...data };
|
|
3258
|
+
next[field2.id] = localDateString(now);
|
|
3259
|
+
}
|
|
3260
|
+
return next ?? data;
|
|
3261
|
+
}
|
|
3231
3262
|
function prefillFromParams(form, params) {
|
|
3232
3263
|
const data = {};
|
|
3233
3264
|
for (const field2 of allFields(form)) {
|
|
@@ -3505,6 +3536,11 @@ function createFormController(options2) {
|
|
|
3505
3536
|
notify();
|
|
3506
3537
|
}
|
|
3507
3538
|
}
|
|
3539
|
+
const withDates = applyDateDefaults(form, data);
|
|
3540
|
+
if (withDates !== data && status === "idle") {
|
|
3541
|
+
data = computeCalculated(form, withDates);
|
|
3542
|
+
notify();
|
|
3543
|
+
}
|
|
3508
3544
|
if (status === "idle" && hasSubmittedOnce(form, formId, data)) {
|
|
3509
3545
|
status = "submitted";
|
|
3510
3546
|
restoredSubmission = true;
|
|
@@ -4040,6 +4076,7 @@ function createFormController(options2) {
|
|
|
4040
4076
|
if (data[key] === void 0) data[key] = value;
|
|
4041
4077
|
}
|
|
4042
4078
|
}
|
|
4079
|
+
data = applyDateDefaults(form, data);
|
|
4043
4080
|
data = computeCalculated(form, data);
|
|
4044
4081
|
errors = {};
|
|
4045
4082
|
pageIndex = 0;
|
|
@@ -4194,6 +4231,7 @@ var FILLO_THEME_VARS = [
|
|
|
4194
4231
|
{ var: "--fillo-font", themeProp: "fontFamily" },
|
|
4195
4232
|
{ var: "--fillo-muted" },
|
|
4196
4233
|
{ var: "--fillo-border" },
|
|
4234
|
+
{ var: "--fillo-control-border" },
|
|
4197
4235
|
{ var: "--fillo-control-bg" },
|
|
4198
4236
|
{ var: "--fillo-error" },
|
|
4199
4237
|
{ var: "--fillo-primary-contrast" }
|
|
@@ -4222,13 +4260,71 @@ function relativeLuminance(token) {
|
|
|
4222
4260
|
return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
|
|
4223
4261
|
}
|
|
4224
4262
|
function resolveThemeAppearance(theme) {
|
|
4225
|
-
if (!theme || theme.colorScheme === "light" || theme.colorScheme === "dark" || !theme.background
|
|
4263
|
+
if (!theme || theme.colorScheme === "light" || theme.colorScheme === "dark" || !theme.background || // A form with dark colors of its own follows the light/dark setting.
|
|
4264
|
+
themeHasDarkPalette(theme)) {
|
|
4226
4265
|
return theme;
|
|
4227
4266
|
}
|
|
4228
4267
|
const luminance = relativeLuminance(theme.background);
|
|
4229
4268
|
if (luminance == null) return theme;
|
|
4230
4269
|
return { ...theme, colorScheme: luminance > DARK_LUMINANCE_THRESHOLD ? "light" : "dark" };
|
|
4231
4270
|
}
|
|
4271
|
+
function themeHasDarkPalette(theme) {
|
|
4272
|
+
if (!theme || theme.colorScheme === "light" || theme.colorScheme === "dark") return false;
|
|
4273
|
+
const dark = theme.dark;
|
|
4274
|
+
return Boolean(dark && (dark.primary || dark.background || dark.text));
|
|
4275
|
+
}
|
|
4276
|
+
var ON_LIGHT_TEXT = "#18181b";
|
|
4277
|
+
function onColorTone(color) {
|
|
4278
|
+
const luminance = relativeLuminance(color);
|
|
4279
|
+
if (luminance == null) return null;
|
|
4280
|
+
const withWhite = 1.05 / (luminance + 0.05);
|
|
4281
|
+
const withDark = (luminance + 0.05) / ((relativeLuminance(ON_LIGHT_TEXT) ?? 0) + 0.05);
|
|
4282
|
+
return withWhite >= withDark ? "light" : "dark";
|
|
4283
|
+
}
|
|
4284
|
+
var PALETTE_VARS = [
|
|
4285
|
+
["primary", "--fillo-primary"],
|
|
4286
|
+
["background", "--fillo-bg"],
|
|
4287
|
+
["text", "--fillo-text"]
|
|
4288
|
+
];
|
|
4289
|
+
var DEFAULT_PALETTE = {
|
|
4290
|
+
light: { primary: "#18181b", background: "transparent", text: "#18181b" },
|
|
4291
|
+
dark: { primary: "#fafafa", background: "transparent", text: "#f4f4f5" }
|
|
4292
|
+
};
|
|
4293
|
+
function resolveThemeDom(theme) {
|
|
4294
|
+
const safe = resolveThemeAppearance(normalizeFormTheme(theme));
|
|
4295
|
+
if (!safe) return null;
|
|
4296
|
+
const vars = {};
|
|
4297
|
+
const attrs = {};
|
|
4298
|
+
if (safe.colorScheme) attrs["data-fillo-color-scheme"] = safe.colorScheme;
|
|
4299
|
+
const dark = themeHasDarkPalette(safe) ? safe.dark : void 0;
|
|
4300
|
+
for (const [key, name] of PALETTE_VARS) {
|
|
4301
|
+
const light = safe[key];
|
|
4302
|
+
if (!dark) {
|
|
4303
|
+
if (light) vars[name] = light;
|
|
4304
|
+
continue;
|
|
4305
|
+
}
|
|
4306
|
+
const darkValue = dark[key];
|
|
4307
|
+
if (!light && !darkValue) continue;
|
|
4308
|
+
vars[name] = `light-dark(${light ?? DEFAULT_PALETTE.light[key]}, ${darkValue ?? DEFAULT_PALETTE.dark[key]})`;
|
|
4309
|
+
}
|
|
4310
|
+
if (safe.radius) vars["--fillo-radius"] = safe.radius;
|
|
4311
|
+
if (safe.fontFamily) vars["--fillo-font"] = safe.fontFamily;
|
|
4312
|
+
if (dark) {
|
|
4313
|
+
const lightTone = onColorTone(safe.primary ?? DEFAULT_PALETTE.light.primary);
|
|
4314
|
+
const darkTone = onColorTone(dark.primary ?? DEFAULT_PALETTE.dark.primary);
|
|
4315
|
+
if (lightTone && darkTone) {
|
|
4316
|
+
attrs["data-fillo-on-primary"] = lightTone;
|
|
4317
|
+
attrs["data-fillo-on-primary-dark"] = darkTone;
|
|
4318
|
+
}
|
|
4319
|
+
} else if (safe.primary) {
|
|
4320
|
+
const tone = onColorTone(safe.primary);
|
|
4321
|
+
if (tone) attrs["data-fillo-on-primary"] = tone;
|
|
4322
|
+
}
|
|
4323
|
+
if (safe.primary || safe.background || safe.text || dark) {
|
|
4324
|
+
attrs["data-fillo-has-color-theme"] = "";
|
|
4325
|
+
}
|
|
4326
|
+
return { vars, attrs };
|
|
4327
|
+
}
|
|
4232
4328
|
|
|
4233
4329
|
// src/define.ts
|
|
4234
4330
|
function defineForm(def) {
|
|
@@ -4418,7 +4514,7 @@ var JSX_BLOCK_SPECS = [
|
|
|
4418
4514
|
field("Ranking", "ranking", ["options"], { optionChildren: true }),
|
|
4419
4515
|
field("Matrix", "matrix", ["rows", "columns"]),
|
|
4420
4516
|
field("Signature", "signature", []),
|
|
4421
|
-
field("Date", "date", []),
|
|
4517
|
+
field("Date", "date", ["defaultToday"]),
|
|
4422
4518
|
field("FileUpload", "file_upload", ["maxFiles", "maxFileSizeMb", "accept"]),
|
|
4423
4519
|
field("Hidden", "hidden", ["paramName", "defaultValue"]),
|
|
4424
4520
|
field("Calculated", "calculated", ["calc", "decimals", "prefix", "suffix"]),
|
|
@@ -4811,6 +4907,7 @@ export {
|
|
|
4811
4907
|
REQUIRED_FIELD_MESSAGE,
|
|
4812
4908
|
Sha1,
|
|
4813
4909
|
allFields,
|
|
4910
|
+
applyDateDefaults,
|
|
4814
4911
|
assembleForm,
|
|
4815
4912
|
codeFormFromJsx,
|
|
4816
4913
|
computeCalculated,
|
|
@@ -4842,6 +4939,7 @@ export {
|
|
|
4842
4939
|
isPossiblePhone,
|
|
4843
4940
|
isTerminalPage,
|
|
4844
4941
|
isValidPartialNumberText,
|
|
4942
|
+
localDateString,
|
|
4845
4943
|
localeForNotation,
|
|
4846
4944
|
needsExplicitSubmit,
|
|
4847
4945
|
normalizeFormSchema,
|
|
@@ -4864,6 +4962,7 @@ export {
|
|
|
4864
4962
|
resolveStrings,
|
|
4865
4963
|
resolveText,
|
|
4866
4964
|
resolveThemeAppearance,
|
|
4965
|
+
resolveThemeDom,
|
|
4867
4966
|
respondentErrorStringsFor,
|
|
4868
4967
|
responseScopeValue,
|
|
4869
4968
|
schemaFromJsx,
|
|
@@ -4871,6 +4970,7 @@ export {
|
|
|
4871
4970
|
shouldAutoSubmit,
|
|
4872
4971
|
slotClass,
|
|
4873
4972
|
syncCodeForm,
|
|
4973
|
+
themeHasDarkPalette,
|
|
4874
4974
|
toE164,
|
|
4875
4975
|
validateField,
|
|
4876
4976
|
validateFormSchema,
|