rn-inputforge 0.4.0 → 0.5.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 +723 -39
- package/lib/commonjs/adapters/index.js +25 -0
- package/lib/commonjs/adapters/index.js.map +1 -0
- package/lib/commonjs/adapters/reactHookForm.js +107 -0
- package/lib/commonjs/adapters/reactHookForm.js.map +1 -0
- package/lib/commonjs/components/FieldFlowAffordance/FieldFlowAffordance.js +104 -0
- package/lib/commonjs/components/FieldFlowAffordance/FieldFlowAffordance.js.map +1 -0
- package/lib/commonjs/components/FieldFlowAffordance/index.js +13 -0
- package/lib/commonjs/components/FieldFlowAffordance/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowCreditCard/FieldFlowCreditCard.js +146 -0
- package/lib/commonjs/components/FieldFlowCreditCard/FieldFlowCreditCard.js.map +1 -0
- package/lib/commonjs/components/FieldFlowCreditCard/index.js +13 -0
- package/lib/commonjs/components/FieldFlowCreditCard/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowDraftBanner/FieldFlowDraftBanner.js +156 -0
- package/lib/commonjs/components/FieldFlowDraftBanner/FieldFlowDraftBanner.js.map +1 -0
- package/lib/commonjs/components/FieldFlowDraftBanner/index.js +13 -0
- package/lib/commonjs/components/FieldFlowDraftBanner/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowInput/FieldFlowInput.js +143 -43
- package/lib/commonjs/components/FieldFlowInput/FieldFlowInput.js.map +1 -1
- package/lib/commonjs/components/FieldFlowInput/styles.js +16 -0
- package/lib/commonjs/components/FieldFlowInput/styles.js.map +1 -1
- package/lib/commonjs/components/FieldFlowNumberStepper/FieldFlowNumberStepper.js +136 -0
- package/lib/commonjs/components/FieldFlowNumberStepper/FieldFlowNumberStepper.js.map +1 -0
- package/lib/commonjs/components/FieldFlowNumberStepper/index.js +13 -0
- package/lib/commonjs/components/FieldFlowNumberStepper/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.js +122 -0
- package/lib/commonjs/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.js.map +1 -0
- package/lib/commonjs/components/FieldFlowPasswordStrength/index.js +13 -0
- package/lib/commonjs/components/FieldFlowPasswordStrength/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowPhone/FieldFlowPhone.js +263 -0
- package/lib/commonjs/components/FieldFlowPhone/FieldFlowPhone.js.map +1 -0
- package/lib/commonjs/components/FieldFlowPhone/index.js +13 -0
- package/lib/commonjs/components/FieldFlowPhone/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowRating/FieldFlowRating.js +106 -0
- package/lib/commonjs/components/FieldFlowRating/FieldFlowRating.js.map +1 -0
- package/lib/commonjs/components/FieldFlowRating/index.js +13 -0
- package/lib/commonjs/components/FieldFlowRating/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSection/FieldFlowSection.js +141 -0
- package/lib/commonjs/components/FieldFlowSection/FieldFlowSection.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSection/index.js +13 -0
- package/lib/commonjs/components/FieldFlowSection/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSegmented/FieldFlowSegmented.js +195 -0
- package/lib/commonjs/components/FieldFlowSegmented/FieldFlowSegmented.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSegmented/index.js +13 -0
- package/lib/commonjs/components/FieldFlowSegmented/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSignature/FieldFlowSignature.js +200 -0
- package/lib/commonjs/components/FieldFlowSignature/FieldFlowSignature.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSignature/index.js +13 -0
- package/lib/commonjs/components/FieldFlowSignature/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSlider/FieldFlowSlider.js +178 -0
- package/lib/commonjs/components/FieldFlowSlider/FieldFlowSlider.js.map +1 -0
- package/lib/commonjs/components/FieldFlowSlider/index.js +13 -0
- package/lib/commonjs/components/FieldFlowSlider/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowStepper/FieldFlowStepper.js +166 -0
- package/lib/commonjs/components/FieldFlowStepper/FieldFlowStepper.js.map +1 -0
- package/lib/commonjs/components/FieldFlowStepper/index.js +13 -0
- package/lib/commonjs/components/FieldFlowStepper/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowTags/FieldFlowTags.js +240 -0
- package/lib/commonjs/components/FieldFlowTags/FieldFlowTags.js.map +1 -0
- package/lib/commonjs/components/FieldFlowTags/index.js +13 -0
- package/lib/commonjs/components/FieldFlowTags/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowTypeahead/FieldFlowTypeahead.js +227 -0
- package/lib/commonjs/components/FieldFlowTypeahead/FieldFlowTypeahead.js.map +1 -0
- package/lib/commonjs/components/FieldFlowTypeahead/index.js +13 -0
- package/lib/commonjs/components/FieldFlowTypeahead/index.js.map +1 -0
- package/lib/commonjs/components/FieldFlowUpload/FieldFlowUpload.js +191 -0
- package/lib/commonjs/components/FieldFlowUpload/FieldFlowUpload.js.map +1 -0
- package/lib/commonjs/components/FieldFlowUpload/index.js +13 -0
- package/lib/commonjs/components/FieldFlowUpload/index.js.map +1 -0
- package/lib/commonjs/hooks/index.js +35 -0
- package/lib/commonjs/hooks/index.js.map +1 -1
- package/lib/commonjs/hooks/useFieldFlowArray.js +110 -0
- package/lib/commonjs/hooks/useFieldFlowArray.js.map +1 -0
- package/lib/commonjs/hooks/useFieldFlowDirtyGuard.js +53 -0
- package/lib/commonjs/hooks/useFieldFlowDirtyGuard.js.map +1 -0
- package/lib/commonjs/hooks/useFieldFlowDraft.js +168 -0
- package/lib/commonjs/hooks/useFieldFlowDraft.js.map +1 -0
- package/lib/commonjs/hooks/useFieldFlowForm.js +224 -30
- package/lib/commonjs/hooks/useFieldFlowForm.js.map +1 -1
- package/lib/commonjs/hooks/useFieldFlowSteps.js +77 -0
- package/lib/commonjs/hooks/useFieldFlowSteps.js.map +1 -0
- package/lib/commonjs/hooks/useFormIntelligence.js +130 -0
- package/lib/commonjs/hooks/useFormIntelligence.js.map +1 -0
- package/lib/commonjs/i18n/index.js +25 -0
- package/lib/commonjs/i18n/index.js.map +1 -0
- package/lib/commonjs/i18n/messages.js +88 -0
- package/lib/commonjs/i18n/messages.js.map +1 -0
- package/lib/commonjs/index.js +322 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/intelligence/formAccessibility.js +79 -0
- package/lib/commonjs/intelligence/formAccessibility.js.map +1 -0
- package/lib/commonjs/intelligence/index.js +31 -0
- package/lib/commonjs/intelligence/index.js.map +1 -0
- package/lib/commonjs/intelligence/types.js +2 -0
- package/lib/commonjs/intelligence/types.js.map +1 -0
- package/lib/commonjs/motion/index.js +20 -0
- package/lib/commonjs/motion/index.js.map +1 -0
- package/lib/commonjs/motion/useFieldMotion.js +111 -0
- package/lib/commonjs/motion/useFieldMotion.js.map +1 -0
- package/lib/commonjs/motion/useReducedMotion.js +32 -0
- package/lib/commonjs/motion/useReducedMotion.js.map +1 -0
- package/lib/commonjs/theme/index.js +13 -0
- package/lib/commonjs/theme/index.js.map +1 -1
- package/lib/commonjs/theme/presets.js +142 -0
- package/lib/commonjs/theme/presets.js.map +1 -0
- package/lib/commonjs/utils/affordance.js +151 -0
- package/lib/commonjs/utils/affordance.js.map +1 -0
- package/lib/commonjs/utils/passwordStrength.js +79 -0
- package/lib/commonjs/utils/passwordStrength.js.map +1 -0
- package/lib/commonjs/utils/phoneCountries.js +119 -0
- package/lib/commonjs/utils/phoneCountries.js.map +1 -0
- package/lib/commonjs/validation/validators.js +10 -7
- package/lib/commonjs/validation/validators.js.map +1 -1
- package/lib/module/adapters/index.js +4 -0
- package/lib/module/adapters/index.js.map +1 -0
- package/lib/module/adapters/reactHookForm.js +100 -0
- package/lib/module/adapters/reactHookForm.js.map +1 -0
- package/lib/module/components/FieldFlowAffordance/FieldFlowAffordance.js +99 -0
- package/lib/module/components/FieldFlowAffordance/FieldFlowAffordance.js.map +1 -0
- package/lib/module/components/FieldFlowAffordance/index.js +4 -0
- package/lib/module/components/FieldFlowAffordance/index.js.map +1 -0
- package/lib/module/components/FieldFlowCreditCard/FieldFlowCreditCard.js +141 -0
- package/lib/module/components/FieldFlowCreditCard/FieldFlowCreditCard.js.map +1 -0
- package/lib/module/components/FieldFlowCreditCard/index.js +4 -0
- package/lib/module/components/FieldFlowCreditCard/index.js.map +1 -0
- package/lib/module/components/FieldFlowDraftBanner/FieldFlowDraftBanner.js +151 -0
- package/lib/module/components/FieldFlowDraftBanner/FieldFlowDraftBanner.js.map +1 -0
- package/lib/module/components/FieldFlowDraftBanner/index.js +4 -0
- package/lib/module/components/FieldFlowDraftBanner/index.js.map +1 -0
- package/lib/module/components/FieldFlowInput/FieldFlowInput.js +144 -44
- package/lib/module/components/FieldFlowInput/FieldFlowInput.js.map +1 -1
- package/lib/module/components/FieldFlowInput/styles.js +16 -0
- package/lib/module/components/FieldFlowInput/styles.js.map +1 -1
- package/lib/module/components/FieldFlowNumberStepper/FieldFlowNumberStepper.js +131 -0
- package/lib/module/components/FieldFlowNumberStepper/FieldFlowNumberStepper.js.map +1 -0
- package/lib/module/components/FieldFlowNumberStepper/index.js +4 -0
- package/lib/module/components/FieldFlowNumberStepper/index.js.map +1 -0
- package/lib/module/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.js +117 -0
- package/lib/module/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.js.map +1 -0
- package/lib/module/components/FieldFlowPasswordStrength/index.js +4 -0
- package/lib/module/components/FieldFlowPasswordStrength/index.js.map +1 -0
- package/lib/module/components/FieldFlowPhone/FieldFlowPhone.js +258 -0
- package/lib/module/components/FieldFlowPhone/FieldFlowPhone.js.map +1 -0
- package/lib/module/components/FieldFlowPhone/index.js +4 -0
- package/lib/module/components/FieldFlowPhone/index.js.map +1 -0
- package/lib/module/components/FieldFlowRating/FieldFlowRating.js +101 -0
- package/lib/module/components/FieldFlowRating/FieldFlowRating.js.map +1 -0
- package/lib/module/components/FieldFlowRating/index.js +4 -0
- package/lib/module/components/FieldFlowRating/index.js.map +1 -0
- package/lib/module/components/FieldFlowSection/FieldFlowSection.js +136 -0
- package/lib/module/components/FieldFlowSection/FieldFlowSection.js.map +1 -0
- package/lib/module/components/FieldFlowSection/index.js +4 -0
- package/lib/module/components/FieldFlowSection/index.js.map +1 -0
- package/lib/module/components/FieldFlowSegmented/FieldFlowSegmented.js +190 -0
- package/lib/module/components/FieldFlowSegmented/FieldFlowSegmented.js.map +1 -0
- package/lib/module/components/FieldFlowSegmented/index.js +4 -0
- package/lib/module/components/FieldFlowSegmented/index.js.map +1 -0
- package/lib/module/components/FieldFlowSignature/FieldFlowSignature.js +195 -0
- package/lib/module/components/FieldFlowSignature/FieldFlowSignature.js.map +1 -0
- package/lib/module/components/FieldFlowSignature/index.js +4 -0
- package/lib/module/components/FieldFlowSignature/index.js.map +1 -0
- package/lib/module/components/FieldFlowSlider/FieldFlowSlider.js +173 -0
- package/lib/module/components/FieldFlowSlider/FieldFlowSlider.js.map +1 -0
- package/lib/module/components/FieldFlowSlider/index.js +4 -0
- package/lib/module/components/FieldFlowSlider/index.js.map +1 -0
- package/lib/module/components/FieldFlowStepper/FieldFlowStepper.js +161 -0
- package/lib/module/components/FieldFlowStepper/FieldFlowStepper.js.map +1 -0
- package/lib/module/components/FieldFlowStepper/index.js +4 -0
- package/lib/module/components/FieldFlowStepper/index.js.map +1 -0
- package/lib/module/components/FieldFlowTags/FieldFlowTags.js +235 -0
- package/lib/module/components/FieldFlowTags/FieldFlowTags.js.map +1 -0
- package/lib/module/components/FieldFlowTags/index.js +4 -0
- package/lib/module/components/FieldFlowTags/index.js.map +1 -0
- package/lib/module/components/FieldFlowTypeahead/FieldFlowTypeahead.js +222 -0
- package/lib/module/components/FieldFlowTypeahead/FieldFlowTypeahead.js.map +1 -0
- package/lib/module/components/FieldFlowTypeahead/index.js +4 -0
- package/lib/module/components/FieldFlowTypeahead/index.js.map +1 -0
- package/lib/module/components/FieldFlowUpload/FieldFlowUpload.js +186 -0
- package/lib/module/components/FieldFlowUpload/FieldFlowUpload.js.map +1 -0
- package/lib/module/components/FieldFlowUpload/index.js +4 -0
- package/lib/module/components/FieldFlowUpload/index.js.map +1 -0
- package/lib/module/hooks/index.js +5 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/useFieldFlowArray.js +106 -0
- package/lib/module/hooks/useFieldFlowArray.js.map +1 -0
- package/lib/module/hooks/useFieldFlowDirtyGuard.js +49 -0
- package/lib/module/hooks/useFieldFlowDirtyGuard.js.map +1 -0
- package/lib/module/hooks/useFieldFlowDraft.js +165 -0
- package/lib/module/hooks/useFieldFlowDraft.js.map +1 -0
- package/lib/module/hooks/useFieldFlowForm.js +224 -30
- package/lib/module/hooks/useFieldFlowForm.js.map +1 -1
- package/lib/module/hooks/useFieldFlowSteps.js +73 -0
- package/lib/module/hooks/useFieldFlowSteps.js.map +1 -0
- package/lib/module/hooks/useFormIntelligence.js +126 -0
- package/lib/module/hooks/useFormIntelligence.js.map +1 -0
- package/lib/module/i18n/index.js +4 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/i18n/messages.js +82 -0
- package/lib/module/i18n/messages.js.map +1 -0
- package/lib/module/index.js +31 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/intelligence/formAccessibility.js +72 -0
- package/lib/module/intelligence/formAccessibility.js.map +1 -0
- package/lib/module/intelligence/index.js +4 -0
- package/lib/module/intelligence/index.js.map +1 -0
- package/lib/module/intelligence/types.js +2 -0
- package/lib/module/intelligence/types.js.map +1 -0
- package/lib/module/motion/index.js +5 -0
- package/lib/module/motion/index.js.map +1 -0
- package/lib/module/motion/useFieldMotion.js +107 -0
- package/lib/module/motion/useFieldMotion.js.map +1 -0
- package/lib/module/motion/useReducedMotion.js +29 -0
- package/lib/module/motion/useReducedMotion.js.map +1 -0
- package/lib/module/theme/index.js +1 -0
- package/lib/module/theme/index.js.map +1 -1
- package/lib/module/theme/presets.js +138 -0
- package/lib/module/theme/presets.js.map +1 -0
- package/lib/module/utils/affordance.js +140 -0
- package/lib/module/utils/affordance.js.map +1 -0
- package/lib/module/utils/passwordStrength.js +74 -0
- package/lib/module/utils/passwordStrength.js.map +1 -0
- package/lib/module/utils/phoneCountries.js +113 -0
- package/lib/module/utils/phoneCountries.js.map +1 -0
- package/lib/module/validation/validators.js +10 -7
- package/lib/module/validation/validators.js.map +1 -1
- package/lib/typescript/adapters/index.d.ts +3 -0
- package/lib/typescript/adapters/index.d.ts.map +1 -0
- package/lib/typescript/adapters/reactHookForm.d.ts +56 -0
- package/lib/typescript/adapters/reactHookForm.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowAffordance/FieldFlowAffordance.d.ts +29 -0
- package/lib/typescript/components/FieldFlowAffordance/FieldFlowAffordance.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowAffordance/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowAffordance/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowCreditCard/FieldFlowCreditCard.d.ts +27 -0
- package/lib/typescript/components/FieldFlowCreditCard/FieldFlowCreditCard.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowCreditCard/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowCreditCard/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowDraftBanner/FieldFlowDraftBanner.d.ts +24 -0
- package/lib/typescript/components/FieldFlowDraftBanner/FieldFlowDraftBanner.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowDraftBanner/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowDraftBanner/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowInput/FieldFlowInput.d.ts.map +1 -1
- package/lib/typescript/components/FieldFlowInput/styles.d.ts +16 -0
- package/lib/typescript/components/FieldFlowInput/styles.d.ts.map +1 -1
- package/lib/typescript/components/FieldFlowInput/types.d.ts +32 -0
- package/lib/typescript/components/FieldFlowInput/types.d.ts.map +1 -1
- package/lib/typescript/components/FieldFlowNumberStepper/FieldFlowNumberStepper.d.ts +34 -0
- package/lib/typescript/components/FieldFlowNumberStepper/FieldFlowNumberStepper.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowNumberStepper/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowNumberStepper/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.d.ts +26 -0
- package/lib/typescript/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowPasswordStrength/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowPasswordStrength/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowPhone/FieldFlowPhone.d.ts +40 -0
- package/lib/typescript/components/FieldFlowPhone/FieldFlowPhone.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowPhone/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowPhone/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowRating/FieldFlowRating.d.ts +30 -0
- package/lib/typescript/components/FieldFlowRating/FieldFlowRating.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowRating/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowRating/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSection/FieldFlowSection.d.ts +35 -0
- package/lib/typescript/components/FieldFlowSection/FieldFlowSection.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSection/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowSection/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSegmented/FieldFlowSegmented.d.ts +28 -0
- package/lib/typescript/components/FieldFlowSegmented/FieldFlowSegmented.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSegmented/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowSegmented/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSignature/FieldFlowSignature.d.ts +41 -0
- package/lib/typescript/components/FieldFlowSignature/FieldFlowSignature.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSignature/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowSignature/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSlider/FieldFlowSlider.d.ts +30 -0
- package/lib/typescript/components/FieldFlowSlider/FieldFlowSlider.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowSlider/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowSlider/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowStepper/FieldFlowStepper.d.ts +31 -0
- package/lib/typescript/components/FieldFlowStepper/FieldFlowStepper.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowStepper/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowStepper/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowTags/FieldFlowTags.d.ts +41 -0
- package/lib/typescript/components/FieldFlowTags/FieldFlowTags.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowTags/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowTags/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowTypeahead/FieldFlowTypeahead.d.ts +43 -0
- package/lib/typescript/components/FieldFlowTypeahead/FieldFlowTypeahead.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowTypeahead/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowTypeahead/index.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowUpload/FieldFlowUpload.d.ts +52 -0
- package/lib/typescript/components/FieldFlowUpload/FieldFlowUpload.d.ts.map +1 -0
- package/lib/typescript/components/FieldFlowUpload/index.d.ts +3 -0
- package/lib/typescript/components/FieldFlowUpload/index.d.ts.map +1 -0
- package/lib/typescript/hooks/index.d.ts +11 -1
- package/lib/typescript/hooks/index.d.ts.map +1 -1
- package/lib/typescript/hooks/useFieldFlowArray.d.ts +54 -0
- package/lib/typescript/hooks/useFieldFlowArray.d.ts.map +1 -0
- package/lib/typescript/hooks/useFieldFlowDirtyGuard.d.ts +26 -0
- package/lib/typescript/hooks/useFieldFlowDirtyGuard.d.ts.map +1 -0
- package/lib/typescript/hooks/useFieldFlowDraft.d.ts +64 -0
- package/lib/typescript/hooks/useFieldFlowDraft.d.ts.map +1 -0
- package/lib/typescript/hooks/useFieldFlowForm.d.ts +80 -2
- package/lib/typescript/hooks/useFieldFlowForm.d.ts.map +1 -1
- package/lib/typescript/hooks/useFieldFlowSteps.d.ts +42 -0
- package/lib/typescript/hooks/useFieldFlowSteps.d.ts.map +1 -0
- package/lib/typescript/hooks/useFormIntelligence.d.ts +23 -0
- package/lib/typescript/hooks/useFormIntelligence.d.ts.map +1 -0
- package/lib/typescript/i18n/index.d.ts +3 -0
- package/lib/typescript/i18n/index.d.ts.map +1 -0
- package/lib/typescript/i18n/messages.d.ts +16 -0
- package/lib/typescript/i18n/messages.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +48 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/intelligence/formAccessibility.d.ts +21 -0
- package/lib/typescript/intelligence/formAccessibility.d.ts.map +1 -0
- package/lib/typescript/intelligence/index.d.ts +4 -0
- package/lib/typescript/intelligence/index.d.ts.map +1 -0
- package/lib/typescript/intelligence/types.d.ts +36 -0
- package/lib/typescript/intelligence/types.d.ts.map +1 -0
- package/lib/typescript/motion/index.d.ts +4 -0
- package/lib/typescript/motion/index.d.ts.map +1 -0
- package/lib/typescript/motion/useFieldMotion.d.ts +31 -0
- package/lib/typescript/motion/useFieldMotion.d.ts.map +1 -0
- package/lib/typescript/motion/useReducedMotion.d.ts +5 -0
- package/lib/typescript/motion/useReducedMotion.d.ts.map +1 -0
- package/lib/typescript/theme/index.d.ts +2 -0
- package/lib/typescript/theme/index.d.ts.map +1 -1
- package/lib/typescript/theme/presets.d.ts +134 -0
- package/lib/typescript/theme/presets.d.ts.map +1 -0
- package/lib/typescript/utils/affordance.d.ts +36 -0
- package/lib/typescript/utils/affordance.d.ts.map +1 -0
- package/lib/typescript/utils/passwordStrength.d.ts +26 -0
- package/lib/typescript/utils/passwordStrength.d.ts.map +1 -0
- package/lib/typescript/utils/phoneCountries.d.ts +12 -0
- package/lib/typescript/utils/phoneCountries.d.ts.map +1 -0
- package/lib/typescript/validation/validators.d.ts +3 -1
- package/lib/typescript/validation/validators.d.ts.map +1 -1
- package/package.json +19 -2
- package/src/adapters/index.ts +9 -0
- package/src/adapters/reactHookForm.tsx +152 -0
- package/src/components/FieldFlowAffordance/FieldFlowAffordance.tsx +143 -0
- package/src/components/FieldFlowAffordance/index.ts +2 -0
- package/src/components/FieldFlowCreditCard/FieldFlowCreditCard.tsx +152 -0
- package/src/components/FieldFlowCreditCard/index.ts +2 -0
- package/src/components/FieldFlowDraftBanner/FieldFlowDraftBanner.tsx +169 -0
- package/src/components/FieldFlowDraftBanner/index.ts +2 -0
- package/src/components/FieldFlowInput/FieldFlowInput.tsx +174 -53
- package/src/components/FieldFlowInput/styles.ts +16 -0
- package/src/components/FieldFlowInput/types.ts +33 -0
- package/src/components/FieldFlowNumberStepper/FieldFlowNumberStepper.tsx +156 -0
- package/src/components/FieldFlowNumberStepper/index.ts +2 -0
- package/src/components/FieldFlowPasswordStrength/FieldFlowPasswordStrength.tsx +148 -0
- package/src/components/FieldFlowPasswordStrength/index.ts +2 -0
- package/src/components/FieldFlowPhone/FieldFlowPhone.tsx +298 -0
- package/src/components/FieldFlowPhone/index.ts +2 -0
- package/src/components/FieldFlowRating/FieldFlowRating.tsx +121 -0
- package/src/components/FieldFlowRating/index.ts +2 -0
- package/src/components/FieldFlowSection/FieldFlowSection.tsx +176 -0
- package/src/components/FieldFlowSection/index.ts +2 -0
- package/src/components/FieldFlowSegmented/FieldFlowSegmented.tsx +248 -0
- package/src/components/FieldFlowSegmented/index.ts +2 -0
- package/src/components/FieldFlowSignature/FieldFlowSignature.tsx +241 -0
- package/src/components/FieldFlowSignature/index.ts +7 -0
- package/src/components/FieldFlowSlider/FieldFlowSlider.tsx +190 -0
- package/src/components/FieldFlowSlider/index.ts +2 -0
- package/src/components/FieldFlowStepper/FieldFlowStepper.tsx +190 -0
- package/src/components/FieldFlowStepper/index.ts +2 -0
- package/src/components/FieldFlowTags/FieldFlowTags.tsx +319 -0
- package/src/components/FieldFlowTags/index.ts +2 -0
- package/src/components/FieldFlowTypeahead/FieldFlowTypeahead.tsx +261 -0
- package/src/components/FieldFlowTypeahead/index.ts +2 -0
- package/src/components/FieldFlowUpload/FieldFlowUpload.tsx +226 -0
- package/src/components/FieldFlowUpload/index.ts +6 -0
- package/src/hooks/index.ts +31 -0
- package/src/hooks/useFieldFlowArray.ts +153 -0
- package/src/hooks/useFieldFlowDirtyGuard.ts +70 -0
- package/src/hooks/useFieldFlowDraft.ts +221 -0
- package/src/hooks/useFieldFlowForm.ts +357 -28
- package/src/hooks/useFieldFlowSteps.ts +130 -0
- package/src/hooks/useFormIntelligence.ts +207 -0
- package/src/i18n/index.ts +6 -0
- package/src/i18n/messages.ts +101 -0
- package/src/index.ts +161 -3
- package/src/intelligence/formAccessibility.ts +87 -0
- package/src/intelligence/index.ts +12 -0
- package/src/intelligence/types.ts +34 -0
- package/src/motion/index.ts +3 -0
- package/src/motion/useFieldMotion.ts +120 -0
- package/src/motion/useReducedMotion.ts +31 -0
- package/src/theme/index.ts +2 -0
- package/src/theme/presets.ts +120 -0
- package/src/utils/affordance.ts +138 -0
- package/src/utils/passwordStrength.ts +109 -0
- package/src/utils/phoneCountries.ts +44 -0
- package/src/validation/validators.ts +17 -7
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { AccessibilityInfo, findNodeHandle, type TextInput } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export type FieldRefMap<T extends string = string> = Partial<
|
|
4
|
+
Record<T, { current: TextInput | null } | TextInput | null>
|
|
5
|
+
>;
|
|
6
|
+
|
|
7
|
+
function resolveNode(ref: FieldRefMap[string]): TextInput | null {
|
|
8
|
+
if (!ref) return null;
|
|
9
|
+
if (typeof ref === 'object' && 'current' in ref) return ref.current ?? null;
|
|
10
|
+
return ref;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Focus the first field (in `order` or object key order) that has an error.
|
|
15
|
+
* Returns the field key that was focused, or `undefined` if none.
|
|
16
|
+
*/
|
|
17
|
+
export function focusFirstError<T extends string>(
|
|
18
|
+
errors: Partial<Record<T, string | undefined>>,
|
|
19
|
+
refs: FieldRefMap<T>,
|
|
20
|
+
order?: T[],
|
|
21
|
+
): T | undefined {
|
|
22
|
+
const keys = order ?? (Object.keys(errors) as T[]);
|
|
23
|
+
for (const key of keys) {
|
|
24
|
+
if (!errors[key]) continue;
|
|
25
|
+
const node = resolveNode(refs[key]);
|
|
26
|
+
if (node && typeof node.focus === 'function') {
|
|
27
|
+
node.focus();
|
|
28
|
+
return key;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Fallback: any field with an error that has a ref, even if not in order
|
|
32
|
+
for (const key of Object.keys(errors) as T[]) {
|
|
33
|
+
if (!errors[key]) continue;
|
|
34
|
+
const node = resolveNode(refs[key]);
|
|
35
|
+
if (node && typeof node.focus === 'function') {
|
|
36
|
+
node.focus();
|
|
37
|
+
return key;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Announce a short message to VoiceOver / TalkBack when available. */
|
|
44
|
+
export function announceForAccessibility(message: string): void {
|
|
45
|
+
if (!message) return;
|
|
46
|
+
try {
|
|
47
|
+
AccessibilityInfo.announceForAccessibility(message);
|
|
48
|
+
} catch {
|
|
49
|
+
// Older RN / platforms without announce support — silently ignore.
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Build a concise announcement for failed validation, e.g.
|
|
55
|
+
* "Form has 2 errors. Email is required."
|
|
56
|
+
*/
|
|
57
|
+
export function buildValidationAnnouncement(
|
|
58
|
+
errors: Partial<Record<string, string | undefined>>,
|
|
59
|
+
): string {
|
|
60
|
+
const entries = Object.entries(errors).filter(([, msg]) => Boolean(msg)) as Array<
|
|
61
|
+
[string, string]
|
|
62
|
+
>;
|
|
63
|
+
if (entries.length === 0) return '';
|
|
64
|
+
const [firstField, firstMessage] = entries[0];
|
|
65
|
+
if (entries.length === 1) {
|
|
66
|
+
return `${formatFieldName(firstField)}: ${firstMessage}`;
|
|
67
|
+
}
|
|
68
|
+
return `Form has ${entries.length} errors. ${formatFieldName(firstField)}: ${firstMessage}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function formatFieldName(field: string): string {
|
|
72
|
+
return field
|
|
73
|
+
.replace(/([A-Z])/g, ' $1')
|
|
74
|
+
.replace(/[_-]/g, ' ')
|
|
75
|
+
.replace(/^\w/, c => c.toUpperCase())
|
|
76
|
+
.trim();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Best-effort: mark a native view as accessibility-focused (Android). */
|
|
80
|
+
export function setAccessibilityFocus(ref: { current: TextInput | null } | TextInput | null): void {
|
|
81
|
+
const node = resolveNode(ref);
|
|
82
|
+
if (!node) return;
|
|
83
|
+
const handle = findNodeHandle(node);
|
|
84
|
+
if (handle != null) {
|
|
85
|
+
AccessibilityInfo.setAccessibilityFocus?.(handle);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export {
|
|
2
|
+
focusFirstError,
|
|
3
|
+
announceForAccessibility,
|
|
4
|
+
buildValidationAnnouncement,
|
|
5
|
+
setAccessibilityFocus,
|
|
6
|
+
} from './formAccessibility';
|
|
7
|
+
export type { FieldRefMap } from './formAccessibility';
|
|
8
|
+
export type {
|
|
9
|
+
FieldFrictionStats,
|
|
10
|
+
FormHealthReport,
|
|
11
|
+
FormIntelligenceOptions,
|
|
12
|
+
} from './types';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface FieldFrictionStats {
|
|
2
|
+
focusCount: number;
|
|
3
|
+
/** Cumulative milliseconds the field was focused. */
|
|
4
|
+
totalFocusMs: number;
|
|
5
|
+
errorCount: number;
|
|
6
|
+
changeCount: number;
|
|
7
|
+
blurCount: number;
|
|
8
|
+
lastFocusedAt?: number;
|
|
9
|
+
/** Running focus session start (ms since epoch); cleared on blur. */
|
|
10
|
+
focusStartedAt?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface FormHealthReport {
|
|
14
|
+
/** Wall-clock ms from first interaction to this report. */
|
|
15
|
+
sessionMs: number;
|
|
16
|
+
submitAttempts: number;
|
|
17
|
+
successfulSubmits: number;
|
|
18
|
+
fields: Record<string, FieldFrictionStats>;
|
|
19
|
+
/**
|
|
20
|
+
* Fields sorted by estimated friction (errors × 3 + focusCount + changeCount / 10).
|
|
21
|
+
* Useful for product analytics / debugging onboarding drop-off.
|
|
22
|
+
*/
|
|
23
|
+
mostFriction: Array<{ field: string; score: number }>;
|
|
24
|
+
generatedAt: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface FormIntelligenceOptions {
|
|
28
|
+
/** Called whenever a new report is produced (submit attempt, or `flush()`). */
|
|
29
|
+
onReport?: (report: FormHealthReport) => void;
|
|
30
|
+
/** When true (default), failed submit focuses & announces the first invalid field. */
|
|
31
|
+
focusFirstError?: boolean;
|
|
32
|
+
/** Announce errors via `AccessibilityInfo.announceForAccessibility`. Default: true. */
|
|
33
|
+
announceErrors?: boolean;
|
|
34
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { Animated, Easing } from 'react-native';
|
|
3
|
+
import { useReducedMotion } from './useReducedMotion';
|
|
4
|
+
|
|
5
|
+
export interface UseFieldMotionOptions {
|
|
6
|
+
/** Master switch. Default: true. */
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
isFocused: boolean;
|
|
9
|
+
hasError: boolean;
|
|
10
|
+
isSuccess?: boolean;
|
|
11
|
+
/** Base duration from theme. */
|
|
12
|
+
duration?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface UseFieldMotionResult {
|
|
16
|
+
/** Apply to the field chrome (input container). */
|
|
17
|
+
containerStyle: {
|
|
18
|
+
transform: Array<{ translateX: Animated.AnimatedInterpolation<string | number> }>;
|
|
19
|
+
};
|
|
20
|
+
/** Soft focus glow overlay opacity (0–1). */
|
|
21
|
+
glowOpacity: Animated.Value;
|
|
22
|
+
/** Footer message fade. */
|
|
23
|
+
messageOpacity: Animated.Value;
|
|
24
|
+
/** Success check scale pop. */
|
|
25
|
+
successScale: Animated.Value;
|
|
26
|
+
reducedMotion: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Field micro-interactions: error shake, focus glow, message cross-fade, success pop.
|
|
31
|
+
* Uses RN Animated only (no Reanimated) and respects Reduce Motion.
|
|
32
|
+
*/
|
|
33
|
+
export function useFieldMotion({
|
|
34
|
+
enabled = true,
|
|
35
|
+
isFocused,
|
|
36
|
+
hasError,
|
|
37
|
+
isSuccess,
|
|
38
|
+
duration = 180,
|
|
39
|
+
}: UseFieldMotionOptions): UseFieldMotionResult {
|
|
40
|
+
const reducedMotion = useReducedMotion();
|
|
41
|
+
const active = enabled && !reducedMotion;
|
|
42
|
+
|
|
43
|
+
const shake = useRef(new Animated.Value(0)).current;
|
|
44
|
+
const glowOpacity = useRef(new Animated.Value(0)).current;
|
|
45
|
+
const messageOpacity = useRef(new Animated.Value(1)).current;
|
|
46
|
+
const successScale = useRef(new Animated.Value(1)).current;
|
|
47
|
+
const prevError = useRef(hasError);
|
|
48
|
+
|
|
49
|
+
// Focus glow
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
if (!active) {
|
|
52
|
+
glowOpacity.setValue(isFocused ? 0.35 : 0);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
Animated.timing(glowOpacity, {
|
|
56
|
+
toValue: isFocused ? 1 : 0,
|
|
57
|
+
duration,
|
|
58
|
+
easing: Easing.out(Easing.cubic),
|
|
59
|
+
useNativeDriver: true,
|
|
60
|
+
}).start();
|
|
61
|
+
}, [active, isFocused, glowOpacity, duration]);
|
|
62
|
+
|
|
63
|
+
// Error shake when error turns on
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
const justErrored = hasError && !prevError.current;
|
|
66
|
+
prevError.current = hasError;
|
|
67
|
+
if (!justErrored) return;
|
|
68
|
+
|
|
69
|
+
if (!active) return;
|
|
70
|
+
|
|
71
|
+
shake.setValue(0);
|
|
72
|
+
Animated.sequence([
|
|
73
|
+
Animated.timing(shake, { toValue: 1, duration: 40, useNativeDriver: true }),
|
|
74
|
+
Animated.timing(shake, { toValue: -1, duration: 40, useNativeDriver: true }),
|
|
75
|
+
Animated.timing(shake, { toValue: 1, duration: 40, useNativeDriver: true }),
|
|
76
|
+
Animated.timing(shake, { toValue: -1, duration: 40, useNativeDriver: true }),
|
|
77
|
+
Animated.timing(shake, { toValue: 0, duration: 40, useNativeDriver: true }),
|
|
78
|
+
]).start();
|
|
79
|
+
|
|
80
|
+
messageOpacity.setValue(0);
|
|
81
|
+
Animated.timing(messageOpacity, {
|
|
82
|
+
toValue: 1,
|
|
83
|
+
duration: duration + 40,
|
|
84
|
+
easing: Easing.out(Easing.cubic),
|
|
85
|
+
useNativeDriver: true,
|
|
86
|
+
}).start();
|
|
87
|
+
}, [hasError, active, shake, messageOpacity, duration]);
|
|
88
|
+
|
|
89
|
+
// Success pop
|
|
90
|
+
useEffect(() => {
|
|
91
|
+
if (!isSuccess) {
|
|
92
|
+
successScale.setValue(1);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (!active) return;
|
|
96
|
+
successScale.setValue(0.6);
|
|
97
|
+
Animated.spring(successScale, {
|
|
98
|
+
toValue: 1,
|
|
99
|
+
friction: 5,
|
|
100
|
+
tension: 140,
|
|
101
|
+
useNativeDriver: true,
|
|
102
|
+
}).start();
|
|
103
|
+
}, [isSuccess, active, successScale]);
|
|
104
|
+
|
|
105
|
+
const translateX = shake.interpolate({
|
|
106
|
+
inputRange: [-1, 0, 1],
|
|
107
|
+
outputRange: [-6, 0, 6],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return useMemo(
|
|
111
|
+
() => ({
|
|
112
|
+
containerStyle: { transform: [{ translateX }] },
|
|
113
|
+
glowOpacity,
|
|
114
|
+
messageOpacity,
|
|
115
|
+
successScale,
|
|
116
|
+
reducedMotion,
|
|
117
|
+
}),
|
|
118
|
+
[translateX, glowOpacity, messageOpacity, successScale, reducedMotion],
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { AccessibilityInfo } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tracks the OS “Reduce Motion” preference so FieldFlow can skip decorative animation.
|
|
6
|
+
*/
|
|
7
|
+
export function useReducedMotion(): boolean {
|
|
8
|
+
const [reduced, setReduced] = useState(false);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
let mounted = true;
|
|
12
|
+
AccessibilityInfo.isReduceMotionEnabled?.()
|
|
13
|
+
.then(value => {
|
|
14
|
+
if (mounted) setReduced(Boolean(value));
|
|
15
|
+
})
|
|
16
|
+
.catch(() => {
|
|
17
|
+
/* older RN */
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const sub = AccessibilityInfo.addEventListener?.('reduceMotionChanged', setReduced);
|
|
21
|
+
return () => {
|
|
22
|
+
mounted = false;
|
|
23
|
+
// RN versions differ: subscription may be `{ remove }` or a legacy remover fn
|
|
24
|
+
if (sub && typeof (sub as { remove?: () => void }).remove === 'function') {
|
|
25
|
+
(sub as { remove: () => void }).remove();
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
return reduced;
|
|
31
|
+
}
|
package/src/theme/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { defaultTheme, darkTheme } from './defaultTheme';
|
|
2
2
|
export { FieldFlowThemeProvider, useFieldFlowTheme, mergeDeep } from './ThemeProvider';
|
|
3
3
|
export type { FieldFlowThemeProviderProps } from './ThemeProvider';
|
|
4
|
+
export { themePresets, getThemePreset } from './presets';
|
|
5
|
+
export type { FieldFlowThemePresetName } from './presets';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { DeepPartial, FieldFlowTheme } from '../types';
|
|
2
|
+
import { defaultTheme, darkTheme } from './defaultTheme';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Curated one-liner themes for demos and brand starts.
|
|
6
|
+
* Pass into `FieldFlowThemeProvider theme={themePresets.soft}`.
|
|
7
|
+
*/
|
|
8
|
+
export const themePresets = {
|
|
9
|
+
/** Default FieldFlow blue. */
|
|
10
|
+
default: defaultTheme as DeepPartial<FieldFlowTheme>,
|
|
11
|
+
/** Bundled dark palette. */
|
|
12
|
+
dark: darkTheme as DeepPartial<FieldFlowTheme>,
|
|
13
|
+
/** Soft rounded surfaces, indigo accent. */
|
|
14
|
+
soft: {
|
|
15
|
+
colors: {
|
|
16
|
+
background: '#F8FAFC',
|
|
17
|
+
backgroundDisabled: '#EEF2F7',
|
|
18
|
+
border: '#E2E8F0',
|
|
19
|
+
borderFocused: '#6366F1',
|
|
20
|
+
borderError: '#F43F5E',
|
|
21
|
+
borderSuccess: '#10B981',
|
|
22
|
+
text: '#0F172A',
|
|
23
|
+
placeholder: '#94A3B8',
|
|
24
|
+
label: '#475569',
|
|
25
|
+
labelFocused: '#6366F1',
|
|
26
|
+
error: '#F43F5E',
|
|
27
|
+
success: '#10B981',
|
|
28
|
+
icon: '#64748B',
|
|
29
|
+
iconFocused: '#6366F1',
|
|
30
|
+
},
|
|
31
|
+
spacing: { borderRadius: 16, paddingHorizontal: 16, paddingVertical: 14 },
|
|
32
|
+
typography: { fontSize: 16, labelFontSize: 13, helperFontSize: 12 },
|
|
33
|
+
} satisfies DeepPartial<FieldFlowTheme>,
|
|
34
|
+
/** High-contrast ink on white — docs / legal forms. */
|
|
35
|
+
contrast: {
|
|
36
|
+
colors: {
|
|
37
|
+
background: '#FFFFFF',
|
|
38
|
+
backgroundDisabled: '#F3F4F6',
|
|
39
|
+
border: '#111827',
|
|
40
|
+
borderFocused: '#111827',
|
|
41
|
+
borderError: '#B91C1C',
|
|
42
|
+
borderSuccess: '#047857',
|
|
43
|
+
text: '#111827',
|
|
44
|
+
placeholder: '#6B7280',
|
|
45
|
+
label: '#111827',
|
|
46
|
+
labelFocused: '#111827',
|
|
47
|
+
error: '#B91C1C',
|
|
48
|
+
success: '#047857',
|
|
49
|
+
icon: '#374151',
|
|
50
|
+
iconFocused: '#111827',
|
|
51
|
+
},
|
|
52
|
+
spacing: { borderRadius: 4, borderWidth: 1.5, borderWidthFocused: 2 },
|
|
53
|
+
} satisfies DeepPartial<FieldFlowTheme>,
|
|
54
|
+
/** Warm coral accent, cream surfaces. */
|
|
55
|
+
warm: {
|
|
56
|
+
colors: {
|
|
57
|
+
background: '#FFFBF7',
|
|
58
|
+
backgroundDisabled: '#F5EDE4',
|
|
59
|
+
border: '#E8D5C4',
|
|
60
|
+
borderFocused: '#E11D48',
|
|
61
|
+
borderError: '#DC2626',
|
|
62
|
+
borderSuccess: '#059669',
|
|
63
|
+
text: '#1C1917',
|
|
64
|
+
placeholder: '#A8A29E',
|
|
65
|
+
label: '#57534E',
|
|
66
|
+
labelFocused: '#E11D48',
|
|
67
|
+
error: '#DC2626',
|
|
68
|
+
success: '#059669',
|
|
69
|
+
icon: '#78716C',
|
|
70
|
+
iconFocused: '#E11D48',
|
|
71
|
+
},
|
|
72
|
+
spacing: { borderRadius: 12 },
|
|
73
|
+
} satisfies DeepPartial<FieldFlowTheme>,
|
|
74
|
+
/** Cool teal — fintech / health. */
|
|
75
|
+
teal: {
|
|
76
|
+
colors: {
|
|
77
|
+
background: '#FFFFFF',
|
|
78
|
+
backgroundDisabled: '#F0FDFA',
|
|
79
|
+
border: '#CCFBF1',
|
|
80
|
+
borderFocused: '#0D9488',
|
|
81
|
+
borderError: '#E11D48',
|
|
82
|
+
borderSuccess: '#059669',
|
|
83
|
+
text: '#134E4A',
|
|
84
|
+
placeholder: '#5EEAD4',
|
|
85
|
+
label: '#0F766E',
|
|
86
|
+
labelFocused: '#0D9488',
|
|
87
|
+
error: '#E11D48',
|
|
88
|
+
success: '#059669',
|
|
89
|
+
icon: '#14B8A6',
|
|
90
|
+
iconFocused: '#0D9488',
|
|
91
|
+
},
|
|
92
|
+
spacing: { borderRadius: 14, paddingHorizontal: 16 },
|
|
93
|
+
} satisfies DeepPartial<FieldFlowTheme>,
|
|
94
|
+
/** Midnight elevated cards. */
|
|
95
|
+
midnight: {
|
|
96
|
+
colors: {
|
|
97
|
+
background: '#0B1220',
|
|
98
|
+
backgroundDisabled: '#111827',
|
|
99
|
+
border: '#1F2937',
|
|
100
|
+
borderFocused: '#818CF8',
|
|
101
|
+
borderError: '#FB7185',
|
|
102
|
+
borderSuccess: '#34D399',
|
|
103
|
+
text: '#F9FAFB',
|
|
104
|
+
placeholder: '#6B7280',
|
|
105
|
+
label: '#9CA3AF',
|
|
106
|
+
labelFocused: '#A5B4FC',
|
|
107
|
+
error: '#FB7185',
|
|
108
|
+
success: '#34D399',
|
|
109
|
+
icon: '#9CA3AF',
|
|
110
|
+
iconFocused: '#A5B4FC',
|
|
111
|
+
},
|
|
112
|
+
spacing: { borderRadius: 14 },
|
|
113
|
+
} satisfies DeepPartial<FieldFlowTheme>,
|
|
114
|
+
} as const;
|
|
115
|
+
|
|
116
|
+
export type FieldFlowThemePresetName = keyof typeof themePresets;
|
|
117
|
+
|
|
118
|
+
export function getThemePreset(name: FieldFlowThemePresetName): DeepPartial<FieldFlowTheme> {
|
|
119
|
+
return themePresets[name];
|
|
120
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
export type FieldFlowAffordanceKind = 'email' | 'phone' | 'currency' | 'custom';
|
|
2
|
+
|
|
3
|
+
export interface FieldFlowAffordanceChip {
|
|
4
|
+
/** Visible chip label, e.g. "@gmail.com" or "+1". */
|
|
5
|
+
label: string;
|
|
6
|
+
/** Value applied when the chip is pressed. Defaults to `label`. */
|
|
7
|
+
value?: string;
|
|
8
|
+
/** Optional accessibility label. */
|
|
9
|
+
accessibilityLabel?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Popular consumer email domains for quick completion. */
|
|
13
|
+
export const DEFAULT_EMAIL_DOMAINS: string[] = [
|
|
14
|
+
'gmail.com',
|
|
15
|
+
'outlook.com',
|
|
16
|
+
'hotmail.com',
|
|
17
|
+
'yahoo.com',
|
|
18
|
+
'icloud.com',
|
|
19
|
+
'proton.me',
|
|
20
|
+
'aol.com',
|
|
21
|
+
'mail.com',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
/** Common dial-code chips (label shown to the user). */
|
|
25
|
+
export const DEFAULT_PHONE_DIAL_CODES: FieldFlowAffordanceChip[] = [
|
|
26
|
+
{ label: '+1', accessibilityLabel: 'United States / Canada +1' },
|
|
27
|
+
{ label: '+44', accessibilityLabel: 'United Kingdom +44' },
|
|
28
|
+
{ label: '+92', accessibilityLabel: 'Pakistan +92' },
|
|
29
|
+
{ label: '+91', accessibilityLabel: 'India +91' },
|
|
30
|
+
{ label: '+61', accessibilityLabel: 'Australia +61' },
|
|
31
|
+
{ label: '+49', accessibilityLabel: 'Germany +49' },
|
|
32
|
+
{ label: '+971', accessibilityLabel: 'UAE +971' },
|
|
33
|
+
{ label: '+966', accessibilityLabel: 'Saudi Arabia +966' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
/** Currency symbol chips. */
|
|
37
|
+
export const DEFAULT_CURRENCY_SYMBOLS: FieldFlowAffordanceChip[] = [
|
|
38
|
+
{ label: '$', value: '$', accessibilityLabel: 'US Dollar' },
|
|
39
|
+
{ label: '€', value: '€', accessibilityLabel: 'Euro' },
|
|
40
|
+
{ label: '£', value: '£', accessibilityLabel: 'British Pound' },
|
|
41
|
+
{ label: '₹', value: '₹', accessibilityLabel: 'Indian Rupee' },
|
|
42
|
+
{ label: 'Rs', value: 'Rs ', accessibilityLabel: 'Rupee' },
|
|
43
|
+
{ label: 'AED', value: 'AED ', accessibilityLabel: 'UAE Dirham' },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
export function emailDomainsToChips(domains: string[]): FieldFlowAffordanceChip[] {
|
|
47
|
+
return domains.map(domain => ({
|
|
48
|
+
label: `@${domain}`,
|
|
49
|
+
value: domain,
|
|
50
|
+
accessibilityLabel: `Complete with ${domain}`,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Apply an email-domain suggestion to the current value.
|
|
56
|
+
* - `jane` + `gmail.com` → `jane@gmail.com`
|
|
57
|
+
* - `jane@hot` + `gmail.com` → `jane@gmail.com`
|
|
58
|
+
* - `jane@gmail.com` + `outlook.com` → `jane@outlook.com`
|
|
59
|
+
*/
|
|
60
|
+
export function applyEmailDomainSuggestion(current: string, domain: string): string {
|
|
61
|
+
const cleanedDomain = domain.replace(/^@/, '');
|
|
62
|
+
const at = current.indexOf('@');
|
|
63
|
+
if (at === -1) {
|
|
64
|
+
const local = current.trim();
|
|
65
|
+
return local ? `${local}@${cleanedDomain}` : `@${cleanedDomain}`;
|
|
66
|
+
}
|
|
67
|
+
return `${current.slice(0, at)}@${cleanedDomain}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Apply a dial-code chip. Replaces an existing leading `+digits` prefix when present.
|
|
72
|
+
*/
|
|
73
|
+
export function applyPhoneDialSuggestion(current: string, dialCode: string): string {
|
|
74
|
+
const code = dialCode.startsWith('+') ? dialCode : `+${dialCode}`;
|
|
75
|
+
const rest = current.replace(/^\s*\+?\d{0,4}\s*/, '');
|
|
76
|
+
return rest ? `${code} ${rest.trimStart()}` : code;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Ensure the value starts with the currency symbol (does not duplicate if already present).
|
|
81
|
+
*/
|
|
82
|
+
export function applyCurrencySymbolSuggestion(current: string, symbol: string): string {
|
|
83
|
+
const trimmed = current.trimStart();
|
|
84
|
+
if (trimmed.startsWith(symbol.trim())) return current;
|
|
85
|
+
const digits = trimmed.replace(/^[^\d.-]+/, '');
|
|
86
|
+
return `${symbol}${digits}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function resolveAffordanceChips(
|
|
90
|
+
kind: FieldFlowAffordanceKind,
|
|
91
|
+
custom?: FieldFlowAffordanceChip[] | string[],
|
|
92
|
+
): FieldFlowAffordanceChip[] {
|
|
93
|
+
if (custom && custom.length > 0) {
|
|
94
|
+
return custom.map(item =>
|
|
95
|
+
typeof item === 'string'
|
|
96
|
+
? { label: item.startsWith('@') || item.startsWith('+') ? item : item, value: item }
|
|
97
|
+
: item,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
switch (kind) {
|
|
101
|
+
case 'email':
|
|
102
|
+
return emailDomainsToChips(DEFAULT_EMAIL_DOMAINS);
|
|
103
|
+
case 'phone':
|
|
104
|
+
return DEFAULT_PHONE_DIAL_CODES;
|
|
105
|
+
case 'currency':
|
|
106
|
+
return DEFAULT_CURRENCY_SYMBOLS;
|
|
107
|
+
default:
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function applyAffordanceSuggestion(
|
|
113
|
+
kind: FieldFlowAffordanceKind,
|
|
114
|
+
current: string,
|
|
115
|
+
chip: FieldFlowAffordanceChip,
|
|
116
|
+
): string {
|
|
117
|
+
const value = chip.value ?? chip.label;
|
|
118
|
+
switch (kind) {
|
|
119
|
+
case 'email':
|
|
120
|
+
return applyEmailDomainSuggestion(current, value);
|
|
121
|
+
case 'phone':
|
|
122
|
+
return applyPhoneDialSuggestion(current, value);
|
|
123
|
+
case 'currency':
|
|
124
|
+
return applyCurrencySymbolSuggestion(current, value);
|
|
125
|
+
default:
|
|
126
|
+
return value;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Infer affordance kind from FieldFlow input `type`. */
|
|
131
|
+
export function affordanceKindFromFieldType(
|
|
132
|
+
type?: string,
|
|
133
|
+
): FieldFlowAffordanceKind | undefined {
|
|
134
|
+
if (type === 'email') return 'email';
|
|
135
|
+
if (type === 'phone') return 'phone';
|
|
136
|
+
if (type === 'decimal' || type === 'number') return 'currency';
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
export type PasswordStrengthLevel = 'empty' | 'weak' | 'fair' | 'good' | 'strong';
|
|
2
|
+
|
|
3
|
+
export interface PasswordStrengthRule {
|
|
4
|
+
id: string;
|
|
5
|
+
label: string;
|
|
6
|
+
test: (password: string) => boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface PasswordStrengthResult {
|
|
10
|
+
score: number;
|
|
11
|
+
/** 0–4 mapped level (empty when score is 0 and password is empty). */
|
|
12
|
+
level: PasswordStrengthLevel;
|
|
13
|
+
/** Fraction 0–1 for progress bars. */
|
|
14
|
+
progress: number;
|
|
15
|
+
passed: PasswordStrengthRule[];
|
|
16
|
+
failed: PasswordStrengthRule[];
|
|
17
|
+
/** Short human label, e.g. "Strong". */
|
|
18
|
+
label: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_PASSWORD_RULES: PasswordStrengthRule[] = [
|
|
22
|
+
{
|
|
23
|
+
id: 'length',
|
|
24
|
+
label: 'At least 8 characters',
|
|
25
|
+
test: p => p.length >= 8,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 'lowercase',
|
|
29
|
+
label: 'A lowercase letter',
|
|
30
|
+
test: p => /[a-z]/.test(p),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'uppercase',
|
|
34
|
+
label: 'An uppercase letter',
|
|
35
|
+
test: p => /[A-Z]/.test(p),
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'number',
|
|
39
|
+
label: 'A number',
|
|
40
|
+
test: p => /\d/.test(p),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'symbol',
|
|
44
|
+
label: 'A symbol',
|
|
45
|
+
test: p => /[^A-Za-z0-9]/.test(p),
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const LEVEL_LABELS: Record<PasswordStrengthLevel, string> = {
|
|
50
|
+
empty: '',
|
|
51
|
+
weak: 'Weak',
|
|
52
|
+
fair: 'Fair',
|
|
53
|
+
good: 'Good',
|
|
54
|
+
strong: 'Strong',
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Score a password against declarative rules (default NIST-ish checklist).
|
|
59
|
+
* Pure function — safe to unit test and reuse outside React.
|
|
60
|
+
*/
|
|
61
|
+
export function evaluatePasswordStrength(
|
|
62
|
+
password: string,
|
|
63
|
+
rules: PasswordStrengthRule[] = DEFAULT_PASSWORD_RULES,
|
|
64
|
+
): PasswordStrengthResult {
|
|
65
|
+
if (!password) {
|
|
66
|
+
return {
|
|
67
|
+
score: 0,
|
|
68
|
+
level: 'empty',
|
|
69
|
+
progress: 0,
|
|
70
|
+
passed: [],
|
|
71
|
+
failed: [...rules],
|
|
72
|
+
label: LEVEL_LABELS.empty,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const passed: PasswordStrengthRule[] = [];
|
|
77
|
+
const failed: PasswordStrengthRule[] = [];
|
|
78
|
+
for (const rule of rules) {
|
|
79
|
+
if (rule.test(password)) passed.push(rule);
|
|
80
|
+
else failed.push(rule);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const score = passed.length;
|
|
84
|
+
const max = Math.max(rules.length, 1);
|
|
85
|
+
const ratio = score / max;
|
|
86
|
+
|
|
87
|
+
let level: PasswordStrengthLevel;
|
|
88
|
+
if (ratio < 0.4) level = 'weak';
|
|
89
|
+
else if (ratio < 0.6) level = 'fair';
|
|
90
|
+
else if (ratio < 0.85) level = 'good';
|
|
91
|
+
else level = 'strong';
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
score,
|
|
95
|
+
level,
|
|
96
|
+
progress: ratio,
|
|
97
|
+
passed,
|
|
98
|
+
failed,
|
|
99
|
+
label: LEVEL_LABELS[level],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Suggested bar colors for each level (consumers can override). */
|
|
104
|
+
export const PASSWORD_STRENGTH_COLORS: Record<Exclude<PasswordStrengthLevel, 'empty'>, string> = {
|
|
105
|
+
weak: '#EF4444',
|
|
106
|
+
fair: '#F59E0B',
|
|
107
|
+
good: '#3B82F6',
|
|
108
|
+
strong: '#22C55E',
|
|
109
|
+
};
|