@saastro/forms 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +80 -1
- package/dist/index.js +200 -2
- package/dist/index.js.map +1 -1
- package/package.json +10 -11
package/dist/index.d.ts
CHANGED
|
@@ -3025,6 +3025,69 @@ declare global {
|
|
|
3025
3025
|
*/
|
|
3026
3026
|
declare function recaptchaPlugin(config: RecaptchaPluginConfig): FormPlugin;
|
|
3027
3027
|
|
|
3028
|
+
/**
|
|
3029
|
+
* ============================================
|
|
3030
|
+
* TURNSTILE PLUGIN - Cloudflare Turnstile
|
|
3031
|
+
* ============================================
|
|
3032
|
+
*
|
|
3033
|
+
* Mirrors `recaptchaPlugin` but for Cloudflare Turnstile. Unlike
|
|
3034
|
+
* reCAPTCHA v3 (purely programmatic), Turnstile is widget-based: it must
|
|
3035
|
+
* be rendered into a DOM element. This plugin renders the widget in
|
|
3036
|
+
* explicit + `execution: 'execute'` mode (so it only challenges at submit
|
|
3037
|
+
* time) into a container it manages, captures the token via the success
|
|
3038
|
+
* callback, and attaches it to every submission via `transformValues`.
|
|
3039
|
+
*
|
|
3040
|
+
* The token field defaults to `_captchaToken` — the canonical field the
|
|
3041
|
+
* Hub submit helper (`createHubFormSubmit`) extracts and forwards to the
|
|
3042
|
+
* worker as `captchaToken`.
|
|
3043
|
+
*/
|
|
3044
|
+
interface TurnstilePluginConfig {
|
|
3045
|
+
/** Cloudflare Turnstile site key. */
|
|
3046
|
+
siteKey: string;
|
|
3047
|
+
/** Field name for the token in submitted values (default: '_captchaToken'). */
|
|
3048
|
+
tokenField?: string;
|
|
3049
|
+
/**
|
|
3050
|
+
* Widget appearance. 'interaction-only' (default) keeps it invisible
|
|
3051
|
+
* unless Cloudflare decides a challenge is needed — closest to the
|
|
3052
|
+
* reCAPTCHA v3 UX. 'always' renders a visible widget.
|
|
3053
|
+
*/
|
|
3054
|
+
appearance?: 'always' | 'execute' | 'interaction-only';
|
|
3055
|
+
/**
|
|
3056
|
+
* CSS selector for the element to render the widget into. Defaults to
|
|
3057
|
+
* `[data-saastro-turnstile]` (rendered inline by `HubForm`). If no such
|
|
3058
|
+
* element exists, the plugin creates a fixed, bottom-right container so
|
|
3059
|
+
* an interactive challenge can still surface.
|
|
3060
|
+
*/
|
|
3061
|
+
container?: string;
|
|
3062
|
+
}
|
|
3063
|
+
interface TurnstileApi {
|
|
3064
|
+
render: (el: HTMLElement | string, options: Record<string, unknown>) => string;
|
|
3065
|
+
execute: (widgetId?: string, options?: Record<string, unknown>) => void;
|
|
3066
|
+
reset: (widgetId?: string) => void;
|
|
3067
|
+
remove: (widgetId?: string) => void;
|
|
3068
|
+
getResponse: (widgetId?: string) => string | undefined;
|
|
3069
|
+
}
|
|
3070
|
+
declare global {
|
|
3071
|
+
interface Window {
|
|
3072
|
+
turnstile?: TurnstileApi;
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
/**
|
|
3076
|
+
* Cloudflare Turnstile plugin.
|
|
3077
|
+
*
|
|
3078
|
+
* @example
|
|
3079
|
+
* ```tsx
|
|
3080
|
+
* import { turnstilePlugin, PluginManager, FormBuilder } from '@saastro/forms';
|
|
3081
|
+
*
|
|
3082
|
+
* const pm = new PluginManager();
|
|
3083
|
+
* pm.register(turnstilePlugin({ siteKey: '0x4AAAAAAA...' }));
|
|
3084
|
+
* ```
|
|
3085
|
+
*
|
|
3086
|
+
* With `HubForm`, this is wired automatically when the form schema
|
|
3087
|
+
* declares `meta.captchaProvider === 'turnstile'`.
|
|
3088
|
+
*/
|
|
3089
|
+
declare function turnstilePlugin(config: TurnstilePluginConfig): FormPlugin;
|
|
3090
|
+
|
|
3028
3091
|
/**
|
|
3029
3092
|
* ============================================
|
|
3030
3093
|
* SHADCN/UI PRESET - Component Registry
|
|
@@ -3376,6 +3439,22 @@ declare function useFormLayout(layout?: FormLayout): {
|
|
|
3376
3439
|
gridStyle: React$1.CSSProperties;
|
|
3377
3440
|
};
|
|
3378
3441
|
|
|
3442
|
+
/**
|
|
3443
|
+
* Minimal "value is present" schema for a field that declares
|
|
3444
|
+
* `required: true` at the top level but ships NO explicit `schema`.
|
|
3445
|
+
*
|
|
3446
|
+
* The builder stores `required` at the top level (it drives the asterisk +
|
|
3447
|
+
* the native `required` attribute). Until now `useFormState` only built
|
|
3448
|
+
* validation from `field.schema`, so a `required: true` field without a
|
|
3449
|
+
* schema skipped validation entirely — empty submissions sailed through.
|
|
3450
|
+
*
|
|
3451
|
+
* Kept value-type-agnostic (`z.any()` + refine) on purpose so it never
|
|
3452
|
+
* fights the stored value shape: number inputs hold strings, checkboxes
|
|
3453
|
+
* hold booleans, multi-selects hold arrays. It only enforces presence; rich
|
|
3454
|
+
* per-type rules (email format, min/max, …) still come from an explicit
|
|
3455
|
+
* `schema`/`ValidationRules`.
|
|
3456
|
+
*/
|
|
3457
|
+
declare function buildRequiredOnlySchema(fieldType: string): z.ZodTypeAny;
|
|
3379
3458
|
declare function useFormState({ config: rawConfig, fields: rawFields, steps: rawSteps, }: {
|
|
3380
3459
|
config: FormConfig;
|
|
3381
3460
|
fields: Fields;
|
|
@@ -3870,4 +3949,4 @@ declare function getFieldClass(formLayout?: {
|
|
|
3870
3949
|
*/
|
|
3871
3950
|
declare function getHiddenClasses(hidden?: Partial<Record<Breakpoint, 'visible' | 'hidden'>>): string;
|
|
3872
3951
|
|
|
3873
|
-
export { type AccordionContentProps, type AccordionItemProps, type AccordionProps, type AccordionTriggerProps, BUILD_METHODS, BUILTIN_RESOLVERS, type BaseFieldProps, type Breakpoint$1 as Breakpoint, type BuiltinTransform, type ButtonCardFieldProps, type ButtonCardOption, type ButtonCheckboxFieldProps, type ButtonConfig, type ButtonProps, type ButtonRadioFieldProps, COMMON_CLASSES, COMMON_METHODS, COMMON_STRINGS, type CalendarProps, type CheckboxFieldProps, type CheckboxGroupFieldProps, type CheckboxProps, type ColumnsValue, type ComboboxFieldProps, type CommandEmptyProps, type CommandFieldProps, type CommandGroupProps, type CommandInputProps, type CommandItemProps, type CommandListProps, type CommandProps, type ComponentName, type ComponentOverrides, ComponentProvider, type ComponentProviderProps, type ComponentRegistry, type ComponentRegistryInput, ComponentResolver, type ComponentResolverConfig, type Condition, type ConditionGroup, type ConditionOperator, type CreateHubFormSubmitOptions, type CurrencyFieldProps, type CustomSubmitAction, type CustomSubmitConfig, DEFAULT_HUB_URL, type DatabowlConfig, type DateFieldProps, type DateRangeFieldProps, type DefaultSubmitConfig, type DefinePlugin, type DialogContentProps, type DialogDescriptionProps, type DialogHeaderProps, type DialogProps, type DialogTitleProps, type DialogTriggerProps, type EmailProvider, type EmailSubmitAction, type EndpointConfig, FIELD_DEFAULTS, FieldBuilder, type FieldConfig, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldLayoutConfig, type FieldMapEntry, type FieldMapping, type FieldMappingConfig, type FieldProps, FieldRenderer, type FieldResolver, type FieldTransformFn, type Fields, type FileFieldProps, Form, FormBuilder, type FormButtonProps, type FormButtons, FormComponentsProvider, type FormComponentsProviderProps, type FormConfig, type FormControlProps, type FormFieldProps, type FormLayout, type FormPlugin, type FormProps, type FormRef, type FormStepsInfo, type GapValue, type GlobModules, type HiddenFieldProps, type HtmlFieldProps, type HttpAuthConfig, type HttpBodyConfig, type HttpEndpointConfig, type HttpRetryConfig, type HttpSubmitAction, HubForm, type HubFormProps, type InputGroupFieldProps, type InputOTPGroupProps, type InputOTPProps, type InputOTPSlotProps, type InputProps, type InputSize, type IntegrationSubmitAction, InternalComponentProvider, type InternalComponentProviderProps, type LabelProps, MissingComponentFallback, type MissingComponentFallbackProps, type NativeSelectFieldProps, type NativeSelectProps, OPTION_BASED_TYPES, type Option, type OtpFieldProps, type PartialComponentRegistry, PluginManager, type PopoverContentProps, type PopoverProps, type PopoverTriggerProps, type PropertyMapping, type RadioFieldProps, type RadioGroupItemProps, type RadioGroupProps, type RangeFieldProps, type RecaptchaConfig, type RecaptchaPluginConfig, type RepeaterFieldProps, type ResolvedComponents, SUSPENSE_CONFIG, type SchemaType, type SelectContentProps, type SelectFieldProps, type SelectItemProps, type SelectProps, type SelectTriggerProps, type SelectValueProps, type SeparatorProps, type SerializableFieldResolver, type SerializationHint, type SliderFieldProps, type SliderProps, type Step, type StepCondition, type StepInfo, type StepStatus, type Steps, StepsAccordion, StepsNavigation, StepsProgress, type SubmitAction, type SubmitActionCondition, type SubmitActionNode, type SubmitActionResult, type SubmitActionType, type SubmitActionsResult, type SubmitConfig, type SubmitConfirmationConfig, type SubmitExecutionConfig, type SubmitTrigger, type SubmitTriggerType, type SubmitType, type SwitchFieldProps, type SwitchGroupFieldProps, type SwitchProps, TYPE_SPECIFIC_PROPERTIES, type TestDataLocale, type TestDataOptions, type TextFieldProps, type TextareaFieldProps, type TextareaProps, type TooltipContentProps, type TooltipProps, type TooltipProviderProps, type TooltipTriggerProps, type UseSubmitConfirmationReturn, VALIDATION_METHODS, type ValidateComponentRegistry, type ValidationContext, type ValidationPresetMeta, type ValidationRules, type WebhookSubmitAction, analyticsPlugin, applyBuiltinTransform, applyFieldMapping, applyFieldMappingSync, applyFieldTransforms, applyTransform, autosavePlugin, compileValidationRules, configureComponents, coreComponents, createComponentRegistry, createHubFormSubmit, createMissingComponentPlaceholder, createShadcnRegistry, databowlAction, databowlPlugin, defaultSubmit, definePlugin, detectLocale, executeCustomAction, executeEmailAction, executeHttpAction, executeSubmitAction, executeSubmitActions, executeSubmitActionsByTrigger, executeWebhookAction, fieldTypeComponents, generateFieldValue, generateTestData, getActionsByTrigger, getAllKnownMethods, getAvailablePresets, getComponentResolver, getFieldClass, getFormGridClass, getHiddenClasses, getInstallCommand, getMinDelayMs, getMissingComponents, getRequiredComponents, globalPluginManager, groupMissingByPackage, iconVariants, iconVariantsConfig, inputVariants, inputVariantsConfig, isAdvancedMapping, isValidationRules, isZodSchema, localStoragePlugin, mergeComponentRegistries, parseGlobModules, pxToRem, recaptchaPlugin, registerPreset, resolvePreset, resolveValue, resolveValueSync, textareaVariants, textareaVariantsConfig, useComponentMode, useComponents, useComputedFields, useFormLayout, useFormState, useFormStepsInfo, useHasComponentProvider, useHiddenFieldResolvers, usePartialComponents, useRecaptcha, useSubmitActionTriggers, useSubmitConfirmation, withComponents };
|
|
3952
|
+
export { type AccordionContentProps, type AccordionItemProps, type AccordionProps, type AccordionTriggerProps, BUILD_METHODS, BUILTIN_RESOLVERS, type BaseFieldProps, type Breakpoint$1 as Breakpoint, type BuiltinTransform, type ButtonCardFieldProps, type ButtonCardOption, type ButtonCheckboxFieldProps, type ButtonConfig, type ButtonProps, type ButtonRadioFieldProps, COMMON_CLASSES, COMMON_METHODS, COMMON_STRINGS, type CalendarProps, type CheckboxFieldProps, type CheckboxGroupFieldProps, type CheckboxProps, type ColumnsValue, type ComboboxFieldProps, type CommandEmptyProps, type CommandFieldProps, type CommandGroupProps, type CommandInputProps, type CommandItemProps, type CommandListProps, type CommandProps, type ComponentName, type ComponentOverrides, ComponentProvider, type ComponentProviderProps, type ComponentRegistry, type ComponentRegistryInput, ComponentResolver, type ComponentResolverConfig, type Condition, type ConditionGroup, type ConditionOperator, type CreateHubFormSubmitOptions, type CurrencyFieldProps, type CustomSubmitAction, type CustomSubmitConfig, DEFAULT_HUB_URL, type DatabowlConfig, type DateFieldProps, type DateRangeFieldProps, type DefaultSubmitConfig, type DefinePlugin, type DialogContentProps, type DialogDescriptionProps, type DialogHeaderProps, type DialogProps, type DialogTitleProps, type DialogTriggerProps, type EmailProvider, type EmailSubmitAction, type EndpointConfig, FIELD_DEFAULTS, FieldBuilder, type FieldConfig, type FieldDescriptionProps, type FieldErrorProps, type FieldLabelProps, type FieldLayoutConfig, type FieldMapEntry, type FieldMapping, type FieldMappingConfig, type FieldProps, FieldRenderer, type FieldResolver, type FieldTransformFn, type Fields, type FileFieldProps, Form, FormBuilder, type FormButtonProps, type FormButtons, FormComponentsProvider, type FormComponentsProviderProps, type FormConfig, type FormControlProps, type FormFieldProps, type FormLayout, type FormPlugin, type FormProps, type FormRef, type FormStepsInfo, type GapValue, type GlobModules, type HiddenFieldProps, type HtmlFieldProps, type HttpAuthConfig, type HttpBodyConfig, type HttpEndpointConfig, type HttpRetryConfig, type HttpSubmitAction, HubForm, type HubFormProps, type InputGroupFieldProps, type InputOTPGroupProps, type InputOTPProps, type InputOTPSlotProps, type InputProps, type InputSize, type IntegrationSubmitAction, InternalComponentProvider, type InternalComponentProviderProps, type LabelProps, MissingComponentFallback, type MissingComponentFallbackProps, type NativeSelectFieldProps, type NativeSelectProps, OPTION_BASED_TYPES, type Option, type OtpFieldProps, type PartialComponentRegistry, PluginManager, type PopoverContentProps, type PopoverProps, type PopoverTriggerProps, type PropertyMapping, type RadioFieldProps, type RadioGroupItemProps, type RadioGroupProps, type RangeFieldProps, type RecaptchaConfig, type RecaptchaPluginConfig, type RepeaterFieldProps, type ResolvedComponents, SUSPENSE_CONFIG, type SchemaType, type SelectContentProps, type SelectFieldProps, type SelectItemProps, type SelectProps, type SelectTriggerProps, type SelectValueProps, type SeparatorProps, type SerializableFieldResolver, type SerializationHint, type SliderFieldProps, type SliderProps, type Step, type StepCondition, type StepInfo, type StepStatus, type Steps, StepsAccordion, StepsNavigation, StepsProgress, type SubmitAction, type SubmitActionCondition, type SubmitActionNode, type SubmitActionResult, type SubmitActionType, type SubmitActionsResult, type SubmitConfig, type SubmitConfirmationConfig, type SubmitExecutionConfig, type SubmitTrigger, type SubmitTriggerType, type SubmitType, type SwitchFieldProps, type SwitchGroupFieldProps, type SwitchProps, TYPE_SPECIFIC_PROPERTIES, type TestDataLocale, type TestDataOptions, type TextFieldProps, type TextareaFieldProps, type TextareaProps, type TooltipContentProps, type TooltipProps, type TooltipProviderProps, type TooltipTriggerProps, type TurnstilePluginConfig, type UseSubmitConfirmationReturn, VALIDATION_METHODS, type ValidateComponentRegistry, type ValidationContext, type ValidationPresetMeta, type ValidationRules, type WebhookSubmitAction, analyticsPlugin, applyBuiltinTransform, applyFieldMapping, applyFieldMappingSync, applyFieldTransforms, applyTransform, autosavePlugin, buildRequiredOnlySchema, compileValidationRules, configureComponents, coreComponents, createComponentRegistry, createHubFormSubmit, createMissingComponentPlaceholder, createShadcnRegistry, databowlAction, databowlPlugin, defaultSubmit, definePlugin, detectLocale, executeCustomAction, executeEmailAction, executeHttpAction, executeSubmitAction, executeSubmitActions, executeSubmitActionsByTrigger, executeWebhookAction, fieldTypeComponents, generateFieldValue, generateTestData, getActionsByTrigger, getAllKnownMethods, getAvailablePresets, getComponentResolver, getFieldClass, getFormGridClass, getHiddenClasses, getInstallCommand, getMinDelayMs, getMissingComponents, getRequiredComponents, globalPluginManager, groupMissingByPackage, iconVariants, iconVariantsConfig, inputVariants, inputVariantsConfig, isAdvancedMapping, isValidationRules, isZodSchema, localStoragePlugin, mergeComponentRegistries, parseGlobModules, pxToRem, recaptchaPlugin, registerPreset, resolvePreset, resolveValue, resolveValueSync, textareaVariants, textareaVariantsConfig, turnstilePlugin, useComponentMode, useComponents, useComputedFields, useFormLayout, useFormState, useFormStepsInfo, useHasComponentProvider, useHiddenFieldResolvers, usePartialComponents, useRecaptcha, useSubmitActionTriggers, useSubmitConfirmation, withComponents };
|
package/dist/index.js
CHANGED
|
@@ -2912,6 +2912,27 @@ function useComputedFields(methods, fields) {
|
|
|
2912
2912
|
}
|
|
2913
2913
|
|
|
2914
2914
|
// src/hooks/useFormState.ts
|
|
2915
|
+
function buildRequiredOnlySchema(fieldType) {
|
|
2916
|
+
const message = "This field is required";
|
|
2917
|
+
if (fieldType === "checkbox" || fieldType === "switch") {
|
|
2918
|
+
return z2.any().refine((v) => v === true, {
|
|
2919
|
+
message: "You must accept this"
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
if (fieldType === "checkbox-group" || fieldType === "switch-group" || fieldType === "button-checkbox" || fieldType === "button-card") {
|
|
2923
|
+
return z2.any().refine((v) => Array.isArray(v) && v.length > 0, { message });
|
|
2924
|
+
}
|
|
2925
|
+
if (fieldType === "daterange") {
|
|
2926
|
+
return z2.any().refine(
|
|
2927
|
+
(v) => !!v && typeof v === "object" && !!v.from,
|
|
2928
|
+
{ message }
|
|
2929
|
+
);
|
|
2930
|
+
}
|
|
2931
|
+
return z2.any().refine(
|
|
2932
|
+
(v) => v !== void 0 && v !== null && v !== "" && !(typeof v === "number" && Number.isNaN(v)),
|
|
2933
|
+
{ message }
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2915
2936
|
function useFormState({
|
|
2916
2937
|
config: rawConfig,
|
|
2917
2938
|
fields: rawFields,
|
|
@@ -2967,6 +2988,8 @@ function useFormState({
|
|
|
2967
2988
|
});
|
|
2968
2989
|
}
|
|
2969
2990
|
schema[name] = fieldSchema;
|
|
2991
|
+
} else if (cfg.required) {
|
|
2992
|
+
schema[name] = buildRequiredOnlySchema(cfg.type);
|
|
2970
2993
|
}
|
|
2971
2994
|
defaults[name] = cfg.value ?? (() => {
|
|
2972
2995
|
switch (cfg.type) {
|
|
@@ -6071,6 +6094,156 @@ function recaptchaPlugin(config) {
|
|
|
6071
6094
|
});
|
|
6072
6095
|
}
|
|
6073
6096
|
|
|
6097
|
+
// src/plugins/turnstile.ts
|
|
6098
|
+
var SCRIPT_SRC = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
|
|
6099
|
+
var TOKEN_TIMEOUT_MS = 2e4;
|
|
6100
|
+
function waitForTurnstile(timeoutMs = 1e4) {
|
|
6101
|
+
return new Promise((resolve, reject) => {
|
|
6102
|
+
if (typeof window === "undefined") {
|
|
6103
|
+
reject(new Error("turnstile: no window"));
|
|
6104
|
+
return;
|
|
6105
|
+
}
|
|
6106
|
+
if (window.turnstile) {
|
|
6107
|
+
resolve(window.turnstile);
|
|
6108
|
+
return;
|
|
6109
|
+
}
|
|
6110
|
+
const start = Date.now();
|
|
6111
|
+
const tick = () => {
|
|
6112
|
+
if (window.turnstile) {
|
|
6113
|
+
resolve(window.turnstile);
|
|
6114
|
+
} else if (Date.now() - start > timeoutMs) {
|
|
6115
|
+
reject(new Error("turnstile: script did not load"));
|
|
6116
|
+
} else {
|
|
6117
|
+
setTimeout(tick, 100);
|
|
6118
|
+
}
|
|
6119
|
+
};
|
|
6120
|
+
tick();
|
|
6121
|
+
});
|
|
6122
|
+
}
|
|
6123
|
+
function turnstilePlugin(config) {
|
|
6124
|
+
const {
|
|
6125
|
+
siteKey,
|
|
6126
|
+
tokenField = "_captchaToken",
|
|
6127
|
+
appearance = "interaction-only",
|
|
6128
|
+
container
|
|
6129
|
+
} = config;
|
|
6130
|
+
let scriptElement = null;
|
|
6131
|
+
let createdContainer = null;
|
|
6132
|
+
let widgetId;
|
|
6133
|
+
let lastToken = null;
|
|
6134
|
+
let pending = null;
|
|
6135
|
+
const resolveContainer = () => {
|
|
6136
|
+
if (container) {
|
|
6137
|
+
const found = document.querySelector(container);
|
|
6138
|
+
if (found) return found;
|
|
6139
|
+
}
|
|
6140
|
+
const byData = document.querySelector("[data-saastro-turnstile]");
|
|
6141
|
+
if (byData) return byData;
|
|
6142
|
+
if (!createdContainer) {
|
|
6143
|
+
createdContainer = document.createElement("div");
|
|
6144
|
+
createdContainer.setAttribute("data-saastro-turnstile-fallback", "");
|
|
6145
|
+
createdContainer.style.position = "fixed";
|
|
6146
|
+
createdContainer.style.bottom = "12px";
|
|
6147
|
+
createdContainer.style.right = "12px";
|
|
6148
|
+
createdContainer.style.zIndex = "2147483647";
|
|
6149
|
+
document.body.appendChild(createdContainer);
|
|
6150
|
+
}
|
|
6151
|
+
return createdContainer;
|
|
6152
|
+
};
|
|
6153
|
+
const ensureWidget = async () => {
|
|
6154
|
+
const api = await waitForTurnstile();
|
|
6155
|
+
if (widgetId === void 0) {
|
|
6156
|
+
const el = resolveContainer();
|
|
6157
|
+
widgetId = api.render(el, {
|
|
6158
|
+
sitekey: siteKey,
|
|
6159
|
+
appearance,
|
|
6160
|
+
execution: "execute",
|
|
6161
|
+
callback: (token) => {
|
|
6162
|
+
lastToken = token;
|
|
6163
|
+
pending?.resolve(token);
|
|
6164
|
+
pending = null;
|
|
6165
|
+
},
|
|
6166
|
+
"error-callback": () => {
|
|
6167
|
+
pending?.reject(new Error("turnstile: challenge failed"));
|
|
6168
|
+
pending = null;
|
|
6169
|
+
return true;
|
|
6170
|
+
},
|
|
6171
|
+
"expired-callback": () => {
|
|
6172
|
+
lastToken = null;
|
|
6173
|
+
}
|
|
6174
|
+
});
|
|
6175
|
+
}
|
|
6176
|
+
return api;
|
|
6177
|
+
};
|
|
6178
|
+
return definePlugin({
|
|
6179
|
+
name: "turnstile",
|
|
6180
|
+
version: "1.0.0",
|
|
6181
|
+
description: "Cloudflare Turnstile \u2014 widget render and token generation",
|
|
6182
|
+
onFormInit() {
|
|
6183
|
+
if (typeof window === "undefined") return;
|
|
6184
|
+
if (!window.turnstile && !document.querySelector('script[src*="turnstile/v0/api.js"]')) {
|
|
6185
|
+
scriptElement = document.createElement("script");
|
|
6186
|
+
scriptElement.src = SCRIPT_SRC;
|
|
6187
|
+
scriptElement.async = true;
|
|
6188
|
+
scriptElement.defer = true;
|
|
6189
|
+
document.body.appendChild(scriptElement);
|
|
6190
|
+
}
|
|
6191
|
+
void ensureWidget().catch(() => {
|
|
6192
|
+
});
|
|
6193
|
+
},
|
|
6194
|
+
async transformValues(values) {
|
|
6195
|
+
if (typeof window === "undefined") return values;
|
|
6196
|
+
try {
|
|
6197
|
+
const api = await ensureWidget();
|
|
6198
|
+
const token = await new Promise((resolve, reject) => {
|
|
6199
|
+
pending = { resolve, reject };
|
|
6200
|
+
const timer = setTimeout(() => {
|
|
6201
|
+
if (pending) {
|
|
6202
|
+
pending = null;
|
|
6203
|
+
reject(new Error("turnstile: token timeout"));
|
|
6204
|
+
}
|
|
6205
|
+
}, TOKEN_TIMEOUT_MS);
|
|
6206
|
+
const wrappedResolve = (t) => {
|
|
6207
|
+
clearTimeout(timer);
|
|
6208
|
+
resolve(t);
|
|
6209
|
+
};
|
|
6210
|
+
const wrappedReject = (e) => {
|
|
6211
|
+
clearTimeout(timer);
|
|
6212
|
+
reject(e);
|
|
6213
|
+
};
|
|
6214
|
+
pending = { resolve: wrappedResolve, reject: wrappedReject };
|
|
6215
|
+
lastToken = null;
|
|
6216
|
+
api.reset(widgetId);
|
|
6217
|
+
api.execute(widgetId);
|
|
6218
|
+
});
|
|
6219
|
+
return { ...values, [tokenField]: token };
|
|
6220
|
+
} catch (error) {
|
|
6221
|
+
console.error("turnstilePlugin: failed to get token:", error);
|
|
6222
|
+
return values;
|
|
6223
|
+
}
|
|
6224
|
+
},
|
|
6225
|
+
cleanup() {
|
|
6226
|
+
if (typeof window !== "undefined" && window.turnstile && widgetId !== void 0) {
|
|
6227
|
+
try {
|
|
6228
|
+
window.turnstile.remove(widgetId);
|
|
6229
|
+
} catch {
|
|
6230
|
+
}
|
|
6231
|
+
}
|
|
6232
|
+
widgetId = void 0;
|
|
6233
|
+
lastToken = null;
|
|
6234
|
+
pending = null;
|
|
6235
|
+
if (createdContainer?.parentNode) {
|
|
6236
|
+
createdContainer.parentNode.removeChild(createdContainer);
|
|
6237
|
+
createdContainer = null;
|
|
6238
|
+
}
|
|
6239
|
+
if (scriptElement?.parentNode) {
|
|
6240
|
+
scriptElement.parentNode.removeChild(scriptElement);
|
|
6241
|
+
scriptElement = null;
|
|
6242
|
+
}
|
|
6243
|
+
}
|
|
6244
|
+
});
|
|
6245
|
+
}
|
|
6246
|
+
|
|
6074
6247
|
// src/presets/shadcn.ts
|
|
6075
6248
|
function createComponentRegistry(components) {
|
|
6076
6249
|
return {
|
|
@@ -6901,6 +7074,13 @@ function createHubFormSubmit(opts) {
|
|
|
6901
7074
|
// src/components/HubForm.tsx
|
|
6902
7075
|
import { useEffect as useEffect8, useMemo as useMemo7, useState as useState5 } from "react";
|
|
6903
7076
|
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
7077
|
+
function readCaptchaMeta(schema) {
|
|
7078
|
+
const meta = schema.meta;
|
|
7079
|
+
return {
|
|
7080
|
+
captchaProvider: meta?.captchaProvider,
|
|
7081
|
+
captchaSiteKey: meta?.captchaSiteKey
|
|
7082
|
+
};
|
|
7083
|
+
}
|
|
6904
7084
|
function isRenderableSchema(value) {
|
|
6905
7085
|
if (!value || typeof value !== "object") return false;
|
|
6906
7086
|
const schema = value;
|
|
@@ -6970,6 +7150,18 @@ function HubForm({
|
|
|
6970
7150
|
}
|
|
6971
7151
|
};
|
|
6972
7152
|
}, [hubUrl, siteId, formSlug, onSuccess, onError]);
|
|
7153
|
+
const captcha = useMemo7(() => {
|
|
7154
|
+
if (state.status !== "ready") return void 0;
|
|
7155
|
+
const { captchaProvider, captchaSiteKey } = readCaptchaMeta(state.schema);
|
|
7156
|
+
if (!captchaProvider || !captchaSiteKey) return void 0;
|
|
7157
|
+
const pm = new PluginManager();
|
|
7158
|
+
if (captchaProvider === "turnstile") {
|
|
7159
|
+
pm.register(turnstilePlugin({ siteKey: captchaSiteKey, tokenField: "_captchaToken" }));
|
|
7160
|
+
} else {
|
|
7161
|
+
pm.register(recaptchaPlugin({ siteKey: captchaSiteKey, tokenField: "_captchaToken" }));
|
|
7162
|
+
}
|
|
7163
|
+
return { pm, provider: captchaProvider };
|
|
7164
|
+
}, [state]);
|
|
6973
7165
|
if (state.status === "loading") {
|
|
6974
7166
|
return loadingFallback ?? /* @__PURE__ */ jsx14("div", { "data-saastro-hubform-loading": true, style: loadingStyle, children: "Loading\u2026" });
|
|
6975
7167
|
}
|
|
@@ -6990,9 +7182,13 @@ function HubForm({
|
|
|
6990
7182
|
}
|
|
6991
7183
|
const config = {
|
|
6992
7184
|
...state.schema,
|
|
6993
|
-
submit: wrappedSubmit
|
|
7185
|
+
submit: wrappedSubmit,
|
|
7186
|
+
...captcha ? { pluginManager: captcha.pm } : {}
|
|
6994
7187
|
};
|
|
6995
|
-
return /* @__PURE__ */
|
|
7188
|
+
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
7189
|
+
/* @__PURE__ */ jsx14(Form, { ...formProps, config }),
|
|
7190
|
+
captcha?.provider === "turnstile" ? /* @__PURE__ */ jsx14("div", { "data-saastro-turnstile": true }) : null
|
|
7191
|
+
] });
|
|
6996
7192
|
}
|
|
6997
7193
|
var loadingStyle = {
|
|
6998
7194
|
padding: "2rem 1rem",
|
|
@@ -7279,6 +7475,7 @@ export {
|
|
|
7279
7475
|
applyFieldTransforms,
|
|
7280
7476
|
applyTransform,
|
|
7281
7477
|
autosavePlugin,
|
|
7478
|
+
buildRequiredOnlySchema,
|
|
7282
7479
|
compileValidationRules,
|
|
7283
7480
|
configureComponents,
|
|
7284
7481
|
coreComponents,
|
|
@@ -7332,6 +7529,7 @@ export {
|
|
|
7332
7529
|
resolveValueSync,
|
|
7333
7530
|
textareaVariants,
|
|
7334
7531
|
textareaVariantsConfig,
|
|
7532
|
+
turnstilePlugin,
|
|
7335
7533
|
useComponentMode,
|
|
7336
7534
|
useComponents,
|
|
7337
7535
|
useComputedFields,
|