@sharedex/ui 0.9.0 → 0.10.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 +37 -2
- package/dist/backgrounds/hosts/CssHost.d.ts +2 -6
- package/dist/backgrounds/hosts/CssHost.js +3 -17
- package/dist/backgrounds/hosts/styleHref.d.ts +6 -0
- package/dist/backgrounds/hosts/styleHref.js +20 -0
- package/dist/buttons/pick.d.ts +9 -3
- package/dist/buttons/pick.js +4 -1
- package/dist/forms/base.d.ts +1 -0
- package/dist/forms/base.js +224 -0
- package/dist/forms/buddy.d.ts +6 -0
- package/dist/forms/buddy.js +150 -0
- package/dist/forms/chips.d.ts +1 -0
- package/dist/forms/chips.js +140 -0
- package/dist/forms/choice.d.ts +1 -0
- package/dist/forms/choice.js +208 -0
- package/dist/forms/controls/CheckGroup.d.ts +65 -0
- package/dist/forms/controls/CheckGroup.js +99 -0
- package/dist/forms/controls/Checkbox.d.ts +43 -0
- package/dist/forms/controls/Checkbox.js +67 -0
- package/dist/forms/controls/ChipGroup.d.ts +50 -0
- package/dist/forms/controls/ChipGroup.js +56 -0
- package/dist/forms/controls/Combobox.d.ts +75 -0
- package/dist/forms/controls/Combobox.js +249 -0
- package/dist/forms/controls/ErrorSummary.d.ts +29 -0
- package/dist/forms/controls/ErrorSummary.js +79 -0
- package/dist/forms/controls/Field.d.ts +92 -0
- package/dist/forms/controls/Field.js +219 -0
- package/dist/forms/controls/FileDrop.d.ts +81 -0
- package/dist/forms/controls/FileDrop.js +328 -0
- package/dist/forms/controls/FormBuddy.d.ts +22 -0
- package/dist/forms/controls/FormBuddy.js +143 -0
- package/dist/forms/controls/FormReveal.d.ts +21 -0
- package/dist/forms/controls/FormReveal.js +19 -0
- package/dist/forms/controls/FormSteps.d.ts +75 -0
- package/dist/forms/controls/FormSteps.js +205 -0
- package/dist/forms/controls/FormSwap.d.ts +27 -0
- package/dist/forms/controls/FormSwap.js +38 -0
- package/dist/forms/controls/InlineEdit.d.ts +50 -0
- package/dist/forms/controls/InlineEdit.js +136 -0
- package/dist/forms/controls/NumberField.d.ts +43 -0
- package/dist/forms/controls/NumberField.js +205 -0
- package/dist/forms/controls/OtpField.d.ts +46 -0
- package/dist/forms/controls/OtpField.js +195 -0
- package/dist/forms/controls/PasswordRules.d.ts +31 -0
- package/dist/forms/controls/PasswordRules.js +85 -0
- package/dist/forms/controls/RadioGroup.d.ts +69 -0
- package/dist/forms/controls/RadioGroup.js +95 -0
- package/dist/forms/controls/Range.d.ts +60 -0
- package/dist/forms/controls/Range.js +169 -0
- package/dist/forms/controls/SaveStatus.d.ts +25 -0
- package/dist/forms/controls/SaveStatus.js +88 -0
- package/dist/forms/controls/Select.d.ts +46 -0
- package/dist/forms/controls/Select.js +35 -0
- package/dist/forms/controls/Switch.d.ts +54 -0
- package/dist/forms/controls/Switch.js +91 -0
- package/dist/forms/controls/TagsField.d.ts +68 -0
- package/dist/forms/controls/TagsField.js +0 -0
- package/dist/forms/controls/choiceChecks.d.ts +11 -0
- package/dist/forms/controls/choiceChecks.js +19 -0
- package/dist/forms/controls/choiceParts.d.ts +40 -0
- package/dist/forms/controls/choiceParts.js +49 -0
- package/dist/forms/controls/fieldChecks.d.ts +17 -0
- package/dist/forms/controls/fieldChecks.js +34 -0
- package/dist/forms/controls/fieldTools.d.ts +62 -0
- package/dist/forms/controls/fieldTools.js +54 -0
- package/dist/forms/controls/pickerChecks.d.ts +10 -0
- package/dist/forms/controls/pickerChecks.js +27 -0
- package/dist/forms/controls/rangeChecks.d.ts +11 -0
- package/dist/forms/controls/rangeChecks.js +23 -0
- package/dist/forms/controls/shared.d.ts +8 -0
- package/dist/forms/controls/shared.js +18 -0
- package/dist/forms/effects/cards.d.ts +11 -0
- package/dist/forms/effects/cards.js +52 -0
- package/dist/forms/effects/check/checkCard.d.ts +10 -0
- package/dist/forms/effects/check/checkCard.js +15 -0
- package/dist/forms/effects/check/checkCard.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkCard.schema.js +9 -0
- package/dist/forms/effects/check/checkConfetti.d.ts +18 -0
- package/dist/forms/effects/check/checkConfetti.js +38 -0
- package/dist/forms/effects/check/checkConfetti.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkConfetti.schema.js +13 -0
- package/dist/forms/effects/check/checkDraw.d.ts +7 -0
- package/dist/forms/effects/check/checkDraw.js +12 -0
- package/dist/forms/effects/check/checkDraw.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkDraw.schema.js +9 -0
- package/dist/forms/effects/check/checkHeart.d.ts +9 -0
- package/dist/forms/effects/check/checkHeart.js +84 -0
- package/dist/forms/effects/check/checkHeart.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkHeart.schema.js +10 -0
- package/dist/forms/effects/check/checkJelly.d.ts +9 -0
- package/dist/forms/effects/check/checkJelly.js +23 -0
- package/dist/forms/effects/check/checkJelly.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkJelly.schema.js +10 -0
- package/dist/forms/effects/check/checkMerge.d.ts +9 -0
- package/dist/forms/effects/check/checkMerge.js +37 -0
- package/dist/forms/effects/check/checkMerge.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkMerge.schema.js +10 -0
- package/dist/forms/effects/check/checkMixed.d.ts +7 -0
- package/dist/forms/effects/check/checkMixed.js +25 -0
- package/dist/forms/effects/check/checkMixed.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkMixed.schema.js +9 -0
- package/dist/forms/effects/check/checkMorph.d.ts +9 -0
- package/dist/forms/effects/check/checkMorph.js +53 -0
- package/dist/forms/effects/check/checkMorph.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkMorph.schema.js +10 -0
- package/dist/forms/effects/check/checkPop.d.ts +9 -0
- package/dist/forms/effects/check/checkPop.js +27 -0
- package/dist/forms/effects/check/checkPop.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkPop.schema.js +10 -0
- package/dist/forms/effects/check/checkRipple.d.ts +7 -0
- package/dist/forms/effects/check/checkRipple.js +33 -0
- package/dist/forms/effects/check/checkRipple.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkRipple.schema.js +9 -0
- package/dist/forms/effects/check/checkScribble.d.ts +11 -0
- package/dist/forms/effects/check/checkScribble.js +42 -0
- package/dist/forms/effects/check/checkScribble.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkScribble.schema.js +11 -0
- package/dist/forms/effects/check/checkStrike.d.ts +9 -0
- package/dist/forms/effects/check/checkStrike.js +54 -0
- package/dist/forms/effects/check/checkStrike.schema.d.ts +1 -0
- package/dist/forms/effects/check/checkStrike.schema.js +10 -0
- package/dist/forms/effects/chip/chipCheck.d.ts +7 -0
- package/dist/forms/effects/chip/chipCheck.js +26 -0
- package/dist/forms/effects/chip/chipCheck.schema.d.ts +1 -0
- package/dist/forms/effects/chip/chipCheck.schema.js +9 -0
- package/dist/forms/effects/chip/chipMerge.d.ts +9 -0
- package/dist/forms/effects/chip/chipMerge.js +63 -0
- package/dist/forms/effects/chip/chipMerge.schema.d.ts +1 -0
- package/dist/forms/effects/chip/chipMerge.schema.js +10 -0
- package/dist/forms/effects/file/fileButton.d.ts +7 -0
- package/dist/forms/effects/file/fileButton.js +28 -0
- package/dist/forms/effects/file/fileButton.schema.d.ts +1 -0
- package/dist/forms/effects/file/fileButton.schema.js +9 -0
- package/dist/forms/effects/file/fileCards.d.ts +7 -0
- package/dist/forms/effects/file/fileCards.js +38 -0
- package/dist/forms/effects/file/fileCards.schema.d.ts +1 -0
- package/dist/forms/effects/file/fileCards.schema.js +9 -0
- package/dist/forms/effects/file/fileDrag.d.ts +9 -0
- package/dist/forms/effects/file/fileDrag.js +45 -0
- package/dist/forms/effects/file/fileDrag.schema.d.ts +1 -0
- package/dist/forms/effects/file/fileDrag.schema.js +10 -0
- package/dist/forms/effects/file/filePage.d.ts +7 -0
- package/dist/forms/effects/file/filePage.js +46 -0
- package/dist/forms/effects/file/filePage.schema.d.ts +1 -0
- package/dist/forms/effects/file/filePage.schema.js +9 -0
- package/dist/forms/effects/file/filePreview.d.ts +7 -0
- package/dist/forms/effects/file/filePreview.js +17 -0
- package/dist/forms/effects/file/filePreview.schema.d.ts +1 -0
- package/dist/forms/effects/file/filePreview.schema.js +9 -0
- package/dist/forms/effects/file/fileProgress.d.ts +9 -0
- package/dist/forms/effects/file/fileProgress.js +92 -0
- package/dist/forms/effects/file/fileProgress.schema.d.ts +1 -0
- package/dist/forms/effects/file/fileProgress.schema.js +10 -0
- package/dist/forms/effects/file/fileReject.d.ts +7 -0
- package/dist/forms/effects/file/fileReject.js +24 -0
- package/dist/forms/effects/file/fileReject.schema.d.ts +1 -0
- package/dist/forms/effects/file/fileReject.schema.js +9 -0
- package/dist/forms/effects/input/inputAside.d.ts +11 -0
- package/dist/forms/effects/input/inputAside.js +42 -0
- package/dist/forms/effects/input/inputAside.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputAside.schema.js +11 -0
- package/dist/forms/effects/input/inputBeam.d.ts +14 -0
- package/dist/forms/effects/input/inputBeam.js +51 -0
- package/dist/forms/effects/input/inputBeam.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputBeam.schema.js +18 -0
- package/dist/forms/effects/input/inputCaret.d.ts +13 -0
- package/dist/forms/effects/input/inputCaret.js +33 -0
- package/dist/forms/effects/input/inputCaret.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputCaret.schema.js +26 -0
- package/dist/forms/effects/input/inputCounter.d.ts +16 -0
- package/dist/forms/effects/input/inputCounter.js +84 -0
- package/dist/forms/effects/input/inputCounter.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputCounter.schema.js +12 -0
- package/dist/forms/effects/input/inputCycle.d.ts +19 -0
- package/dist/forms/effects/input/inputCycle.js +93 -0
- package/dist/forms/effects/input/inputCycle.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputCycle.schema.js +11 -0
- package/dist/forms/effects/input/inputDepth.d.ts +11 -0
- package/dist/forms/effects/input/inputDepth.js +31 -0
- package/dist/forms/effects/input/inputDepth.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputDepth.schema.js +11 -0
- package/dist/forms/effects/input/inputDraw.d.ts +13 -0
- package/dist/forms/effects/input/inputDraw.js +27 -0
- package/dist/forms/effects/input/inputDraw.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputDraw.schema.js +12 -0
- package/dist/forms/effects/input/inputFlap.d.ts +9 -0
- package/dist/forms/effects/input/inputFlap.js +24 -0
- package/dist/forms/effects/input/inputFlap.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputFlap.schema.js +10 -0
- package/dist/forms/effects/input/inputFloat.d.ts +12 -0
- package/dist/forms/effects/input/inputFloat.js +46 -0
- package/dist/forms/effects/input/inputFloat.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputFloat.schema.js +10 -0
- package/dist/forms/effects/input/inputFlood.d.ts +11 -0
- package/dist/forms/effects/input/inputFlood.js +30 -0
- package/dist/forms/effects/input/inputFlood.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputFlood.schema.js +11 -0
- package/dist/forms/effects/input/inputFrame.d.ts +18 -0
- package/dist/forms/effects/input/inputFrame.js +77 -0
- package/dist/forms/effects/input/inputFrame.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputFrame.schema.js +13 -0
- package/dist/forms/effects/input/inputIcon.d.ts +11 -0
- package/dist/forms/effects/input/inputIcon.js +18 -0
- package/dist/forms/effects/input/inputIcon.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputIcon.schema.js +11 -0
- package/dist/forms/effects/input/inputNotch.d.ts +9 -0
- package/dist/forms/effects/input/inputNotch.js +70 -0
- package/dist/forms/effects/input/inputNotch.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputNotch.schema.js +10 -0
- package/dist/forms/effects/input/inputReveal.d.ts +15 -0
- package/dist/forms/effects/input/inputReveal.js +56 -0
- package/dist/forms/effects/input/inputReveal.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputReveal.schema.js +16 -0
- package/dist/forms/effects/input/inputRing.d.ts +13 -0
- package/dist/forms/effects/input/inputRing.js +27 -0
- package/dist/forms/effects/input/inputRing.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputRing.schema.js +12 -0
- package/dist/forms/effects/input/inputRise.d.ts +9 -0
- package/dist/forms/effects/input/inputRise.js +22 -0
- package/dist/forms/effects/input/inputRise.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputRise.schema.js +10 -0
- package/dist/forms/effects/input/inputSearch.d.ts +9 -0
- package/dist/forms/effects/input/inputSearch.js +37 -0
- package/dist/forms/effects/input/inputSearch.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputSearch.schema.js +10 -0
- package/dist/forms/effects/input/inputSkeleton.d.ts +7 -0
- package/dist/forms/effects/input/inputSkeleton.js +41 -0
- package/dist/forms/effects/input/inputSkeleton.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputSkeleton.schema.js +9 -0
- package/dist/forms/effects/input/inputSpotlight.d.ts +9 -0
- package/dist/forms/effects/input/inputSpotlight.js +20 -0
- package/dist/forms/effects/input/inputSpotlight.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputSpotlight.schema.js +10 -0
- package/dist/forms/effects/input/inputStrength.d.ts +9 -0
- package/dist/forms/effects/input/inputStrength.js +29 -0
- package/dist/forms/effects/input/inputStrength.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputStrength.schema.js +10 -0
- package/dist/forms/effects/input/inputSwap.d.ts +11 -0
- package/dist/forms/effects/input/inputSwap.js +39 -0
- package/dist/forms/effects/input/inputSwap.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputSwap.schema.js +11 -0
- package/dist/forms/effects/input/inputUnderline.d.ts +13 -0
- package/dist/forms/effects/input/inputUnderline.js +36 -0
- package/dist/forms/effects/input/inputUnderline.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputUnderline.schema.js +18 -0
- package/dist/forms/effects/input/inputWave.d.ts +11 -0
- package/dist/forms/effects/input/inputWave.js +23 -0
- package/dist/forms/effects/input/inputWave.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputWave.schema.js +11 -0
- package/dist/forms/effects/input/inputWavy.d.ts +11 -0
- package/dist/forms/effects/input/inputWavy.js +53 -0
- package/dist/forms/effects/input/inputWavy.schema.d.ts +1 -0
- package/dist/forms/effects/input/inputWavy.schema.js +11 -0
- package/dist/forms/effects/kit.d.ts +213 -0
- package/dist/forms/effects/kit.js +226 -0
- package/dist/forms/effects/picker/chipPop.d.ts +7 -0
- package/dist/forms/effects/picker/chipPop.js +28 -0
- package/dist/forms/effects/picker/chipPop.schema.d.ts +1 -0
- package/dist/forms/effects/picker/chipPop.schema.js +9 -0
- package/dist/forms/effects/picker/listHighlight.d.ts +9 -0
- package/dist/forms/effects/picker/listHighlight.js +42 -0
- package/dist/forms/effects/picker/listHighlight.schema.d.ts +1 -0
- package/dist/forms/effects/picker/listHighlight.schema.js +10 -0
- package/dist/forms/effects/picker/listMatch.d.ts +7 -0
- package/dist/forms/effects/picker/listMatch.js +21 -0
- package/dist/forms/effects/picker/listMatch.schema.d.ts +1 -0
- package/dist/forms/effects/picker/listMatch.schema.js +9 -0
- package/dist/forms/effects/picker/pickerArrow.d.ts +9 -0
- package/dist/forms/effects/picker/pickerArrow.js +17 -0
- package/dist/forms/effects/picker/pickerArrow.schema.d.ts +1 -0
- package/dist/forms/effects/picker/pickerArrow.schema.js +10 -0
- package/dist/forms/effects/picker/pickerCheck.d.ts +7 -0
- package/dist/forms/effects/picker/pickerCheck.js +31 -0
- package/dist/forms/effects/picker/pickerCheck.schema.d.ts +1 -0
- package/dist/forms/effects/picker/pickerCheck.schema.js +9 -0
- package/dist/forms/effects/picker/pickerOpen.d.ts +12 -0
- package/dist/forms/effects/picker/pickerOpen.js +34 -0
- package/dist/forms/effects/picker/pickerOpen.schema.d.ts +1 -0
- package/dist/forms/effects/picker/pickerOpen.schema.js +16 -0
- package/dist/forms/effects/picker/pickerSheet.d.ts +9 -0
- package/dist/forms/effects/picker/pickerSheet.js +47 -0
- package/dist/forms/effects/picker/pickerSheet.schema.d.ts +1 -0
- package/dist/forms/effects/picker/pickerSheet.schema.js +10 -0
- package/dist/forms/effects/picker/pickerStagger.d.ts +9 -0
- package/dist/forms/effects/picker/pickerStagger.js +31 -0
- package/dist/forms/effects/picker/pickerStagger.schema.d.ts +1 -0
- package/dist/forms/effects/picker/pickerStagger.schema.js +10 -0
- package/dist/forms/effects/radio/radioCard.d.ts +10 -0
- package/dist/forms/effects/radio/radioCard.js +15 -0
- package/dist/forms/effects/radio/radioCard.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioCard.schema.js +9 -0
- package/dist/forms/effects/radio/radioCircle.d.ts +9 -0
- package/dist/forms/effects/radio/radioCircle.js +49 -0
- package/dist/forms/effects/radio/radioCircle.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioCircle.schema.js +10 -0
- package/dist/forms/effects/radio/radioDot.d.ts +7 -0
- package/dist/forms/effects/radio/radioDot.js +10 -0
- package/dist/forms/effects/radio/radioDot.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioDot.schema.js +9 -0
- package/dist/forms/effects/radio/radioEmoji.d.ts +9 -0
- package/dist/forms/effects/radio/radioEmoji.js +94 -0
- package/dist/forms/effects/radio/radioEmoji.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioEmoji.schema.js +10 -0
- package/dist/forms/effects/radio/radioPulse.d.ts +9 -0
- package/dist/forms/effects/radio/radioPulse.js +24 -0
- package/dist/forms/effects/radio/radioPulse.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioPulse.schema.js +10 -0
- package/dist/forms/effects/radio/radioScale.d.ts +9 -0
- package/dist/forms/effects/radio/radioScale.js +73 -0
- package/dist/forms/effects/radio/radioScale.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioScale.schema.js +10 -0
- package/dist/forms/effects/radio/radioSegment.d.ts +7 -0
- package/dist/forms/effects/radio/radioSegment.js +52 -0
- package/dist/forms/effects/radio/radioSegment.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioSegment.schema.js +9 -0
- package/dist/forms/effects/radio/radioStars.d.ts +15 -0
- package/dist/forms/effects/radio/radioStars.js +125 -0
- package/dist/forms/effects/radio/radioStars.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioStars.schema.js +13 -0
- package/dist/forms/effects/radio/radioTravel.d.ts +9 -0
- package/dist/forms/effects/radio/radioTravel.js +49 -0
- package/dist/forms/effects/radio/radioTravel.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioTravel.schema.js +10 -0
- package/dist/forms/effects/radio/radioUnderline.d.ts +9 -0
- package/dist/forms/effects/radio/radioUnderline.js +61 -0
- package/dist/forms/effects/radio/radioUnderline.schema.d.ts +1 -0
- package/dist/forms/effects/radio/radioUnderline.schema.js +10 -0
- package/dist/forms/effects/radio/shape.d.ts +13 -0
- package/dist/forms/effects/radio/shape.js +61 -0
- package/dist/forms/effects/range/rangeBubble.d.ts +9 -0
- package/dist/forms/effects/range/rangeBubble.js +54 -0
- package/dist/forms/effects/range/rangeBubble.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeBubble.schema.js +10 -0
- package/dist/forms/effects/range/rangeElastic.d.ts +9 -0
- package/dist/forms/effects/range/rangeElastic.js +101 -0
- package/dist/forms/effects/range/rangeElastic.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeElastic.schema.js +10 -0
- package/dist/forms/effects/range/rangeFace.d.ts +11 -0
- package/dist/forms/effects/range/rangeFace.js +68 -0
- package/dist/forms/effects/range/rangeFace.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeFace.schema.js +11 -0
- package/dist/forms/effects/range/rangeFill.d.ts +7 -0
- package/dist/forms/effects/range/rangeFill.js +29 -0
- package/dist/forms/effects/range/rangeFill.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeFill.schema.js +9 -0
- package/dist/forms/effects/range/rangeHistogram.d.ts +14 -0
- package/dist/forms/effects/range/rangeHistogram.js +65 -0
- package/dist/forms/effects/range/rangeHistogram.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeHistogram.schema.js +11 -0
- package/dist/forms/effects/range/rangeThumb.d.ts +9 -0
- package/dist/forms/effects/range/rangeThumb.js +39 -0
- package/dist/forms/effects/range/rangeThumb.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeThumb.schema.js +10 -0
- package/dist/forms/effects/range/rangeTicks.d.ts +9 -0
- package/dist/forms/effects/range/rangeTicks.js +44 -0
- package/dist/forms/effects/range/rangeTicks.schema.d.ts +1 -0
- package/dist/forms/effects/range/rangeTicks.schema.js +18 -0
- package/dist/forms/effects/ring.d.ts +5 -0
- package/dist/forms/effects/ring.js +12 -0
- package/dist/forms/effects/step/stepProgress.d.ts +9 -0
- package/dist/forms/effects/step/stepProgress.js +35 -0
- package/dist/forms/effects/step/stepProgress.schema.d.ts +1 -0
- package/dist/forms/effects/step/stepProgress.schema.js +10 -0
- package/dist/forms/effects/step/stepSlide.d.ts +9 -0
- package/dist/forms/effects/step/stepSlide.js +50 -0
- package/dist/forms/effects/step/stepSlide.schema.d.ts +1 -0
- package/dist/forms/effects/step/stepSlide.schema.js +10 -0
- package/dist/forms/effects/switch/switchBulb.d.ts +9 -0
- package/dist/forms/effects/switch/switchBulb.js +70 -0
- package/dist/forms/effects/switch/switchBulb.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchBulb.schema.js +10 -0
- package/dist/forms/effects/switch/switchDayNight.d.ts +15 -0
- package/dist/forms/effects/switch/switchDayNight.js +96 -0
- package/dist/forms/effects/switch/switchDayNight.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchDayNight.schema.js +13 -0
- package/dist/forms/effects/switch/switchFace.d.ts +7 -0
- package/dist/forms/effects/switch/switchFace.js +75 -0
- package/dist/forms/effects/switch/switchFace.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchFace.schema.js +9 -0
- package/dist/forms/effects/switch/switchFlip.d.ts +7 -0
- package/dist/forms/effects/switch/switchFlip.js +45 -0
- package/dist/forms/effects/switch/switchFlip.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchFlip.schema.js +9 -0
- package/dist/forms/effects/switch/switchGoo.d.ts +7 -0
- package/dist/forms/effects/switch/switchGoo.js +95 -0
- package/dist/forms/effects/switch/switchGoo.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchGoo.schema.js +9 -0
- package/dist/forms/effects/switch/switchIcon.d.ts +9 -0
- package/dist/forms/effects/switch/switchIcon.js +63 -0
- package/dist/forms/effects/switch/switchIcon.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchIcon.schema.js +10 -0
- package/dist/forms/effects/switch/switchLabels.d.ts +11 -0
- package/dist/forms/effects/switch/switchLabels.js +55 -0
- package/dist/forms/effects/switch/switchLabels.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchLabels.schema.js +11 -0
- package/dist/forms/effects/switch/switchMorph.d.ts +9 -0
- package/dist/forms/effects/switch/switchMorph.js +22 -0
- package/dist/forms/effects/switch/switchMorph.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchMorph.schema.js +10 -0
- package/dist/forms/effects/switch/switchNeon.d.ts +11 -0
- package/dist/forms/effects/switch/switchNeon.js +53 -0
- package/dist/forms/effects/switch/switchNeon.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchNeon.schema.js +11 -0
- package/dist/forms/effects/switch/switchSlide.d.ts +7 -0
- package/dist/forms/effects/switch/switchSlide.js +11 -0
- package/dist/forms/effects/switch/switchSlide.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchSlide.schema.js +9 -0
- package/dist/forms/effects/switch/switchStretch.d.ts +9 -0
- package/dist/forms/effects/switch/switchStretch.js +21 -0
- package/dist/forms/effects/switch/switchStretch.schema.d.ts +1 -0
- package/dist/forms/effects/switch/switchStretch.schema.js +10 -0
- package/dist/forms/effects/valid/validAsync.d.ts +7 -0
- package/dist/forms/effects/valid/validAsync.js +36 -0
- package/dist/forms/effects/valid/validAsync.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validAsync.schema.js +9 -0
- package/dist/forms/effects/valid/validBubble.d.ts +7 -0
- package/dist/forms/effects/valid/validBubble.js +61 -0
- package/dist/forms/effects/valid/validBubble.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validBubble.schema.js +9 -0
- package/dist/forms/effects/valid/validCheck.d.ts +9 -0
- package/dist/forms/effects/valid/validCheck.js +50 -0
- package/dist/forms/effects/valid/validCheck.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validCheck.schema.js +10 -0
- package/dist/forms/effects/valid/validColor.d.ts +11 -0
- package/dist/forms/effects/valid/validColor.js +28 -0
- package/dist/forms/effects/valid/validColor.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validColor.schema.js +11 -0
- package/dist/forms/effects/valid/validFlash.d.ts +9 -0
- package/dist/forms/effects/valid/validFlash.js +36 -0
- package/dist/forms/effects/valid/validFlash.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validFlash.schema.js +10 -0
- package/dist/forms/effects/valid/validMessage.d.ts +7 -0
- package/dist/forms/effects/valid/validMessage.js +24 -0
- package/dist/forms/effects/valid/validMessage.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validMessage.schema.js +9 -0
- package/dist/forms/effects/valid/validShake.d.ts +9 -0
- package/dist/forms/effects/valid/validShake.js +37 -0
- package/dist/forms/effects/valid/validShake.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validShake.schema.js +10 -0
- package/dist/forms/effects/valid/validSwap.d.ts +7 -0
- package/dist/forms/effects/valid/validSwap.js +33 -0
- package/dist/forms/effects/valid/validSwap.schema.d.ts +1 -0
- package/dist/forms/effects/valid/validSwap.schema.js +9 -0
- package/dist/forms/errors.d.ts +12 -0
- package/dist/forms/errors.js +20 -0
- package/dist/forms/file.d.ts +1 -0
- package/dist/forms/file.js +268 -0
- package/dist/forms/files.d.ts +7 -0
- package/dist/forms/files.js +29 -0
- package/dist/forms/formSteps.d.ts +9 -0
- package/dist/forms/formSteps.js +6 -0
- package/dist/forms/ids.d.ts +17 -0
- package/dist/forms/ids.js +13 -0
- package/dist/forms/inline.d.ts +3 -0
- package/dist/forms/inline.js +128 -0
- package/dist/forms/number.d.ts +1 -0
- package/dist/forms/number.js +67 -0
- package/dist/forms/otp.d.ts +4 -0
- package/dist/forms/otp.js +171 -0
- package/dist/forms/picker.d.ts +1 -0
- package/dist/forms/picker.js +303 -0
- package/dist/forms/range.d.ts +3 -0
- package/dist/forms/range.js +223 -0
- package/dist/forms/registry.d.ts +4 -0
- package/dist/forms/registry.js +133 -0
- package/dist/forms/reveal.d.ts +6 -0
- package/dist/forms/reveal.js +51 -0
- package/dist/forms/runtime/focus.d.ts +16 -0
- package/dist/forms/runtime/focus.js +55 -0
- package/dist/forms/runtime/listMatch.d.ts +2 -0
- package/dist/forms/runtime/listMatch.js +33 -0
- package/dist/forms/runtime/origin.d.ts +10 -0
- package/dist/forms/runtime/origin.js +25 -0
- package/dist/forms/runtime/placePopup.d.ts +10 -0
- package/dist/forms/runtime/placePopup.js +55 -0
- package/dist/forms/runtime/useFlip.d.ts +7 -0
- package/dist/forms/runtime/useFlip.js +38 -0
- package/dist/forms/runtime/useMorph.d.ts +8 -0
- package/dist/forms/runtime/useMorph.js +56 -0
- package/dist/forms/runtime/useOffScreen.d.ts +3 -0
- package/dist/forms/runtime/useOffScreen.js +16 -0
- package/dist/forms/runtime/useSwitchDrag.d.ts +8 -0
- package/dist/forms/runtime/useSwitchDrag.js +83 -0
- package/dist/forms/runtime/vanish.d.ts +6 -0
- package/dist/forms/runtime/vanish.js +185 -0
- package/dist/forms/steps.d.ts +1 -0
- package/dist/forms/steps.js +149 -0
- package/dist/forms/swap.d.ts +7 -0
- package/dist/forms/swap.js +149 -0
- package/dist/forms/switch.d.ts +1 -0
- package/dist/forms/switch.js +99 -0
- package/dist/forms/tools.d.ts +3 -0
- package/dist/forms/tools.js +248 -0
- package/dist/forms/types.d.ts +161 -0
- package/dist/forms/types.js +5 -0
- package/dist/index.d.ts +234 -0
- package/dist/index.js +119 -0
- package/dist/schema/forms.d.ts +3 -0
- package/dist/schema/forms.js +194 -0
- package/dist/schema/index.d.ts +2 -1
- package/dist/schema/index.js +3 -1
- package/dist/schema/types.d.ts +2 -2
- package/dist/schema/types.js +1 -0
- package/guides/README.md +62 -61
- package/guides/contact.md +100 -77
- package/guides/forms.md +105 -0
- package/package.json +1 -1
- package/styles/form.css +594 -0
- package/theme.css +6 -1
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState, } from "react";
|
|
4
|
+
import { styleHref } from "../../backgrounds/hosts/CssHost.js";
|
|
5
|
+
import { motionOnly } from "../../transitions/progress.js";
|
|
6
|
+
import { INLINE_CSS, INLINE_MOTION } from "../inline.js";
|
|
7
|
+
import { setNativeValue } from "./fieldTools.js";
|
|
8
|
+
const WORDS = { edit: "Edit {label}", saved: "Saved", failed: "Couldn't save: the change was undone" };
|
|
9
|
+
/**
|
|
10
|
+
* Text that turns into a field and back: a click (or Enter on it) opens the field with the text selected, Enter or
|
|
11
|
+
* leaving it keeps the edit, Esc throws it away and gives the text back. The real input is always in the page, so a
|
|
12
|
+
* form submits it; at rest it is inert and unseen.
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <InlineEdit label="Title" defaultValue={page.title} onSave={(title) => save({ title })} />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function InlineEdit(props) {
|
|
19
|
+
const { label, as = "input", value, defaultValue, onSave, onCancel, placeholder, saveOnBlur = true, labels, unstyled, className, textClassName, rootClassName, style, disabled, id: ownId, ...rest } = props;
|
|
20
|
+
const words = { ...WORDS, ...labels };
|
|
21
|
+
const auto = useId().replace(/[^\w-]/g, "");
|
|
22
|
+
const id = ownId ?? `sx-inline${auto}`;
|
|
23
|
+
const textId = `${id}-text`;
|
|
24
|
+
const input = useRef(null);
|
|
25
|
+
const view = useRef(null);
|
|
26
|
+
const [editing, setEditing] = useState(false);
|
|
27
|
+
const live = useRef(false);
|
|
28
|
+
live.current = editing;
|
|
29
|
+
const [text, setText] = useState(() => String(value ?? defaultValue ?? ""));
|
|
30
|
+
const [status, setStatus] = useState("idle");
|
|
31
|
+
const [said, setSaid] = useState("");
|
|
32
|
+
const kept = useRef("");
|
|
33
|
+
const shown = value ?? text;
|
|
34
|
+
const start = () => {
|
|
35
|
+
const el = input.current;
|
|
36
|
+
if (!el || disabled)
|
|
37
|
+
return;
|
|
38
|
+
kept.current = el.value;
|
|
39
|
+
setEditing(true);
|
|
40
|
+
};
|
|
41
|
+
useLayoutEffect(() => {
|
|
42
|
+
const el = input.current;
|
|
43
|
+
if (!editing || !el)
|
|
44
|
+
return;
|
|
45
|
+
el.focus();
|
|
46
|
+
el.select();
|
|
47
|
+
}, [editing]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (status !== "saved")
|
|
50
|
+
return;
|
|
51
|
+
const t = setTimeout(() => setStatus("idle"), 1600);
|
|
52
|
+
return () => clearTimeout(t);
|
|
53
|
+
}, [status]);
|
|
54
|
+
// a form reset puts the input back: show its text again
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
const el = input.current;
|
|
57
|
+
const form = el?.form;
|
|
58
|
+
if (!el || !form)
|
|
59
|
+
return;
|
|
60
|
+
const later = () => setTimeout(() => setText(el.value));
|
|
61
|
+
form.addEventListener("reset", later);
|
|
62
|
+
return () => form.removeEventListener("reset", later);
|
|
63
|
+
}, []);
|
|
64
|
+
const finish = (keep, refocus) => {
|
|
65
|
+
const el = input.current;
|
|
66
|
+
if (!el || !live.current)
|
|
67
|
+
return;
|
|
68
|
+
const before = kept.current;
|
|
69
|
+
// a kept edit the field's own checks refuse (required, a pattern): Enter stays to fix it, leaving undoes it
|
|
70
|
+
if (keep && !el.checkValidity()) {
|
|
71
|
+
if (refocus)
|
|
72
|
+
return;
|
|
73
|
+
keep = false;
|
|
74
|
+
}
|
|
75
|
+
live.current = false;
|
|
76
|
+
setEditing(false);
|
|
77
|
+
if (refocus)
|
|
78
|
+
requestAnimationFrame(() => view.current?.focus());
|
|
79
|
+
const next = el.value;
|
|
80
|
+
if (!keep) {
|
|
81
|
+
if (next !== before)
|
|
82
|
+
setNativeValue(el, before);
|
|
83
|
+
onCancel?.();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (next === before)
|
|
87
|
+
return;
|
|
88
|
+
const result = onSave?.(next);
|
|
89
|
+
const say = (s) => setSaid((now) => (now === s ? `${s} ` : s));
|
|
90
|
+
if (result && typeof result.then === "function") {
|
|
91
|
+
setStatus("saving");
|
|
92
|
+
result.then(() => {
|
|
93
|
+
setStatus("saved");
|
|
94
|
+
say(words.saved);
|
|
95
|
+
}, () => {
|
|
96
|
+
setNativeValue(el, before);
|
|
97
|
+
setStatus("failed");
|
|
98
|
+
say(words.failed);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
setStatus("saved");
|
|
103
|
+
say(words.saved);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const keys = (e) => {
|
|
107
|
+
rest.onKeyDown?.(e);
|
|
108
|
+
if (e.defaultPrevented || e.nativeEvent.isComposing)
|
|
109
|
+
return;
|
|
110
|
+
if (e.key === "Escape") {
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
finish(false, true);
|
|
113
|
+
}
|
|
114
|
+
else if (e.key === "Enter" && (as === "input" || e.ctrlKey || e.metaKey)) {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
finish(true, true);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const ownRef = rest.ref;
|
|
120
|
+
const setRef = (el) => {
|
|
121
|
+
input.current = el;
|
|
122
|
+
if (typeof ownRef === "function")
|
|
123
|
+
ownRef(el);
|
|
124
|
+
else if (ownRef)
|
|
125
|
+
ownRef.current = el;
|
|
126
|
+
};
|
|
127
|
+
const { ref: _ref, onKeyDown: _keys, onChange, onBlur, ...own } = rest;
|
|
128
|
+
const Control = as;
|
|
129
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { href: styleHref("form-inline", INLINE_CSS), precedence: "sx", children: INLINE_CSS }), _jsx("style", { href: styleHref("form-inline-motion", INLINE_MOTION), precedence: "sx", children: motionOnly(INLINE_MOTION) }), _jsxs("span", { "data-sx-inline": "", "data-sx-styled": unstyled ? undefined : "", "data-sx-editing": editing ? "" : undefined, "data-sx-saving": status === "saving" ? "" : undefined, "data-sx-saved": status === "saved" ? "" : undefined, "data-sx-empty": shown === "" ? "" : undefined, className: rootClassName, style: style, children: [_jsxs("button", { ref: view, type: "button", "data-sx-inline-view": "", "aria-label": words.edit.replace("{label}", label), "aria-describedby": textId, "aria-busy": status === "saving" || undefined, disabled: disabled, inert: editing, className: textClassName, onClick: start, children: [_jsx("span", { "data-sx-inline-text": "", id: textId, children: shown === "" ? placeholder : shown }), _jsx("svg", { "data-sx-inline-icon": "", viewBox: "0 0 24 24", "aria-hidden": true, focusable: "false", children: _jsx("path", { d: "M4 20h4L19 9l-4-4L4 16v4ZM13.5 6.5l4 4" }) }), _jsx("svg", { "data-sx-inline-done": "", viewBox: "0 0 24 24", "aria-hidden": true, focusable: "false", children: _jsx("path", { d: "m5 12.5 4.5 4.5L19 7.5", pathLength: 1 }) })] }), _jsx(Control, { "aria-label": rest["aria-labelledby"] ? undefined : label, ...own, ...(value !== undefined ? { value } : defaultValue !== undefined ? { defaultValue } : {}), ...(as === "input" ? { size: 1 } : { cols: 1, rows: own.rows ?? 2 }), ref: setRef, id: id, "data-sx-inline-control": "", placeholder: placeholder, disabled: disabled, inert: !editing, className: className, onChange: (e) => {
|
|
130
|
+
setText(e.target.value);
|
|
131
|
+
onChange?.(e);
|
|
132
|
+
}, onKeyDown: keys, onBlur: (e) => {
|
|
133
|
+
finish(saveOnBlur, false);
|
|
134
|
+
onBlur?.(e);
|
|
135
|
+
} }), _jsx("span", { "data-sx-inline-sr": "", role: "status", children: said })] })] }));
|
|
136
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type FieldProps } from "./Field.js";
|
|
3
|
+
import { type FieldLabels } from "./fieldTools.js";
|
|
4
|
+
/** The words a NumberField says, for your language, besides Field's own. */
|
|
5
|
+
export interface NumberFieldLabels extends FieldLabels {
|
|
6
|
+
readonly increment?: string;
|
|
7
|
+
readonly decrement?: string;
|
|
8
|
+
}
|
|
9
|
+
interface NumberOwnProps {
|
|
10
|
+
/** The number, when you hold it. `null` or `""`: empty. */
|
|
11
|
+
readonly value?: number | string | null;
|
|
12
|
+
readonly defaultValue?: number | string;
|
|
13
|
+
/** Numbers, or number strings as React Hook Form's `register()` passes them. */
|
|
14
|
+
readonly min?: number | string;
|
|
15
|
+
readonly max?: number | string;
|
|
16
|
+
/** How far one press of − / + or one arrow key goes. Page Up / Page Down go ten. Default `1`. */
|
|
17
|
+
readonly step?: number | string;
|
|
18
|
+
/** How the number reads while the field doesn't have the focus: `Intl.NumberFormat` options (currency, percent …). */
|
|
19
|
+
readonly format?: Intl.NumberFormatOptions;
|
|
20
|
+
/** The locale for the digits and separators. Default the visitor's. */
|
|
21
|
+
readonly locale?: string;
|
|
22
|
+
/** Drag across the label to change the number: `true`, or the pixels per step (default 6). A click still types. */
|
|
23
|
+
readonly scrub?: boolean | number;
|
|
24
|
+
/** `false`: the number changes at once, without rolling. */
|
|
25
|
+
readonly roll?: boolean;
|
|
26
|
+
readonly labels?: NumberFieldLabels;
|
|
27
|
+
/** Your own content at the end, before − / +. */
|
|
28
|
+
readonly end?: ReactNode;
|
|
29
|
+
}
|
|
30
|
+
/** Every other prop is Field's, and goes on the real `<input type="number">`: `name`, `onChange`, `ref` … */
|
|
31
|
+
export type NumberFieldProps = NumberOwnProps & Omit<FieldProps<"input">, keyof NumberOwnProps | "as" | "type">;
|
|
32
|
+
/**
|
|
33
|
+
* A number field on the browser's own `<input type="number">` (so its checks, `min` / `max` / `step`, a phone's number
|
|
34
|
+
* keyboard and a plain form submit all work), built on `Field`: its look and its effects apply. − and + step the number
|
|
35
|
+
* (↑ / ↓ too, Page Up / Page Down by ten); the digits roll to each new value; pushing past `min` or `max` shakes the
|
|
36
|
+
* field instead. With `scrub`, a drag across the label changes the number.
|
|
37
|
+
*
|
|
38
|
+
* ```tsx
|
|
39
|
+
* <NumberField label="Guests" min={1} max={12} defaultValue={2} scrub {...register("guests", { valueAsNumber: true })} />
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function NumberField(props: NumberFieldProps): import("react").JSX.Element;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
4
|
+
import { styleHref } from "../../backgrounds/hosts/CssHost.js";
|
|
5
|
+
import { NumberRoll } from "../../text/number/NumberRoll.js";
|
|
6
|
+
import { NUMBER_CSS } from "../number.js";
|
|
7
|
+
import { Field } from "./Field.js";
|
|
8
|
+
import { setNativeValue } from "./fieldTools.js";
|
|
9
|
+
const WORDS = { increment: "Increase", decrement: "Decrease" };
|
|
10
|
+
const PLAIN = { useGrouping: false, maximumFractionDigits: 20 };
|
|
11
|
+
const toNum = (v) => {
|
|
12
|
+
if (v === null || v === undefined || v === "")
|
|
13
|
+
return null;
|
|
14
|
+
const n = Number(v);
|
|
15
|
+
return Number.isFinite(n) ? n : null;
|
|
16
|
+
};
|
|
17
|
+
const decimals = (n) => (String(n).split(".")[1] ?? "").length;
|
|
18
|
+
const Sign = ({ plus }) => (_jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": true, focusable: "false", children: _jsx("path", { d: plus ? "M6 12h12M12 6v12" : "M6 12h12" }) }));
|
|
19
|
+
/**
|
|
20
|
+
* A number field on the browser's own `<input type="number">` (so its checks, `min` / `max` / `step`, a phone's number
|
|
21
|
+
* keyboard and a plain form submit all work), built on `Field`: its look and its effects apply. − and + step the number
|
|
22
|
+
* (↑ / ↓ too, Page Up / Page Down by ten); the digits roll to each new value; pushing past `min` or `max` shakes the
|
|
23
|
+
* field instead. With `scrub`, a drag across the label changes the number.
|
|
24
|
+
*
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <NumberField label="Guests" min={1} max={12} defaultValue={2} scrub {...register("guests", { valueAsNumber: true })} />
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function NumberField(props) {
|
|
30
|
+
const { value, defaultValue, min: rawMin, max: rawMax, step: rawStep = 1, format, locale, scrub, roll = true, labels, end, onKeyDown, onFocus, onBlur, ...rest } = props;
|
|
31
|
+
const words = { ...WORDS, ...labels };
|
|
32
|
+
const min = toNum(rawMin) ?? undefined;
|
|
33
|
+
const max = toNum(rawMax) ?? undefined;
|
|
34
|
+
const step = toNum(rawStep) ?? 1;
|
|
35
|
+
const wrap = useRef(null);
|
|
36
|
+
const over = useRef(null);
|
|
37
|
+
const input = () => wrap.current?.querySelector("[data-sx-field-control]") ?? null;
|
|
38
|
+
const [num, setNum] = useState(() => toNum(value ?? defaultValue));
|
|
39
|
+
const [typing, setTyping] = useState(false);
|
|
40
|
+
const [focused, setFocused] = useState(false);
|
|
41
|
+
const [limit, setLimit] = useState(null);
|
|
42
|
+
const [scrubbing, setScrubbing] = useState(false);
|
|
43
|
+
const shake = useRef(undefined);
|
|
44
|
+
const places = Math.max(decimals(step), min === undefined ? 0 : decimals(min));
|
|
45
|
+
const hit = (side) => {
|
|
46
|
+
clearTimeout(shake.current);
|
|
47
|
+
setLimit(null);
|
|
48
|
+
// a frame without the mark, so a second push shakes again
|
|
49
|
+
requestAnimationFrame(() => {
|
|
50
|
+
setLimit(side);
|
|
51
|
+
shake.current = setTimeout(() => setLimit(null), 400);
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
/** Sets `next`, or shakes when it lies past a limit the number already sits on. Returns whether it moved. */
|
|
55
|
+
const place = (next) => {
|
|
56
|
+
const el = input();
|
|
57
|
+
if (!el || el.disabled || el.readOnly)
|
|
58
|
+
return false;
|
|
59
|
+
const cur = toNum(el.value);
|
|
60
|
+
let n = Number(next.toFixed(places));
|
|
61
|
+
if (max !== undefined && n > max) {
|
|
62
|
+
if (cur !== null && cur >= max)
|
|
63
|
+
return hit("max"), false;
|
|
64
|
+
n = max;
|
|
65
|
+
}
|
|
66
|
+
if (min !== undefined && n < min) {
|
|
67
|
+
if (cur !== null && cur <= min)
|
|
68
|
+
return hit("min"), false;
|
|
69
|
+
n = min;
|
|
70
|
+
}
|
|
71
|
+
if (n === cur)
|
|
72
|
+
return false;
|
|
73
|
+
setTyping(false);
|
|
74
|
+
setNativeValue(el, String(n));
|
|
75
|
+
return true;
|
|
76
|
+
};
|
|
77
|
+
const stepBy = (k) => {
|
|
78
|
+
const cur = toNum(input()?.value);
|
|
79
|
+
place(cur === null ? (min ?? 0) : cur + k * step);
|
|
80
|
+
};
|
|
81
|
+
// follow the input: typed (an input event with a type), stepped, reset, or set by the app
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
const el = input();
|
|
84
|
+
if (!el)
|
|
85
|
+
return;
|
|
86
|
+
const read = (e) => {
|
|
87
|
+
setNum(toNum(el.value));
|
|
88
|
+
if (e.inputType)
|
|
89
|
+
setTyping(true);
|
|
90
|
+
};
|
|
91
|
+
const reset = () => setTimeout(() => setNum(toNum(el.value)));
|
|
92
|
+
el.addEventListener("input", read);
|
|
93
|
+
el.form?.addEventListener("reset", reset);
|
|
94
|
+
return () => {
|
|
95
|
+
el.removeEventListener("input", read);
|
|
96
|
+
el.form?.removeEventListener("reset", reset);
|
|
97
|
+
};
|
|
98
|
+
}, []);
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
const n = toNum(input()?.value);
|
|
101
|
+
if (n !== num)
|
|
102
|
+
setNum(n);
|
|
103
|
+
});
|
|
104
|
+
// the rolling digits lie exactly over the input's text: its box, padding and font, measured
|
|
105
|
+
const rolling = roll && num !== null;
|
|
106
|
+
useLayoutEffect(() => {
|
|
107
|
+
const el = input();
|
|
108
|
+
const o = over.current;
|
|
109
|
+
if (!el || !o)
|
|
110
|
+
return;
|
|
111
|
+
const fit = () => {
|
|
112
|
+
const s = getComputedStyle(el);
|
|
113
|
+
Object.assign(o.style, {
|
|
114
|
+
left: `${el.offsetLeft}px`,
|
|
115
|
+
top: `${el.offsetTop}px`,
|
|
116
|
+
width: `${el.offsetWidth}px`,
|
|
117
|
+
height: `${el.offsetHeight}px`,
|
|
118
|
+
padding: s.padding,
|
|
119
|
+
font: s.font,
|
|
120
|
+
lineHeight: s.lineHeight,
|
|
121
|
+
letterSpacing: s.letterSpacing,
|
|
122
|
+
justifyContent: s.textAlign === "center" ? "center" : s.textAlign === "right" || s.textAlign === "end" ? "flex-end" : "flex-start",
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
fit();
|
|
126
|
+
const watch = new ResizeObserver(fit);
|
|
127
|
+
watch.observe(el);
|
|
128
|
+
el.addEventListener("transitionend", fit);
|
|
129
|
+
return () => {
|
|
130
|
+
watch.disconnect();
|
|
131
|
+
el.removeEventListener("transitionend", fit);
|
|
132
|
+
};
|
|
133
|
+
}, [rolling, focused]);
|
|
134
|
+
// scrub: a drag across the label changes the number; a plain click still focuses the field
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
const label = wrap.current?.querySelector("[data-sx-field-label]");
|
|
137
|
+
const el = input();
|
|
138
|
+
if (!scrub || !label || !el)
|
|
139
|
+
return;
|
|
140
|
+
const per = typeof scrub === "number" ? scrub : 6;
|
|
141
|
+
let start = null;
|
|
142
|
+
let moved = false;
|
|
143
|
+
const down = (e) => {
|
|
144
|
+
if (e.button !== 0 || el.disabled || el.readOnly)
|
|
145
|
+
return;
|
|
146
|
+
start = { x: e.clientX, from: toNum(el.value) ?? min ?? 0, id: e.pointerId };
|
|
147
|
+
moved = false;
|
|
148
|
+
};
|
|
149
|
+
const move = (e) => {
|
|
150
|
+
if (!start || e.pointerId !== start.id)
|
|
151
|
+
return;
|
|
152
|
+
const dx = (e.clientX - start.x) * (getComputedStyle(label).direction === "rtl" ? -1 : 1);
|
|
153
|
+
if (!moved && Math.abs(dx) < 4)
|
|
154
|
+
return;
|
|
155
|
+
if (!moved) {
|
|
156
|
+
moved = true;
|
|
157
|
+
label.setPointerCapture(e.pointerId);
|
|
158
|
+
setScrubbing(true);
|
|
159
|
+
}
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
place(start.from + Math.trunc(dx / per) * step);
|
|
162
|
+
};
|
|
163
|
+
const up = () => {
|
|
164
|
+
if (!start)
|
|
165
|
+
return;
|
|
166
|
+
start = null;
|
|
167
|
+
if (!moved)
|
|
168
|
+
return;
|
|
169
|
+
setScrubbing(false);
|
|
170
|
+
// the click that ends a scrub doesn't also put the caret in the field
|
|
171
|
+
label.addEventListener("click", (e) => e.preventDefault(), { once: true, capture: true });
|
|
172
|
+
};
|
|
173
|
+
label.addEventListener("pointerdown", down);
|
|
174
|
+
label.addEventListener("pointermove", move);
|
|
175
|
+
label.addEventListener("pointerup", up);
|
|
176
|
+
label.addEventListener("pointercancel", up);
|
|
177
|
+
return () => {
|
|
178
|
+
label.removeEventListener("pointerdown", down);
|
|
179
|
+
label.removeEventListener("pointermove", move);
|
|
180
|
+
label.removeEventListener("pointerup", up);
|
|
181
|
+
label.removeEventListener("pointercancel", up);
|
|
182
|
+
};
|
|
183
|
+
}, [scrub, min, max, step]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
184
|
+
const keys = (e) => {
|
|
185
|
+
onKeyDown?.(e);
|
|
186
|
+
if (e.defaultPrevented)
|
|
187
|
+
return;
|
|
188
|
+
const k = { ArrowUp: 1, ArrowDown: -1, PageUp: 10, PageDown: -10 }[e.key];
|
|
189
|
+
if (k === undefined)
|
|
190
|
+
return;
|
|
191
|
+
e.preventDefault();
|
|
192
|
+
stepBy(k);
|
|
193
|
+
};
|
|
194
|
+
const atMax = max !== undefined && num !== null && num >= max;
|
|
195
|
+
const atMin = min !== undefined && num !== null && num <= min;
|
|
196
|
+
const button = (plus) => (_jsx("button", { type: "button", tabIndex: -1, "data-sx-field-tool": "", "data-sx-number-step": plus ? "up" : "down", "aria-label": plus ? words.increment : words.decrement, "aria-controls": rest.id, "aria-disabled": (plus ? atMax : atMin) || undefined, disabled: rest.disabled, onPointerDown: (e) => e.preventDefault(), onClick: () => stepBy(plus ? 1 : -1), children: _jsx(Sign, { plus: plus }) }));
|
|
197
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { href: styleHref("form-number", NUMBER_CSS), precedence: "sx", children: NUMBER_CSS }), _jsx("div", { ref: wrap, "data-sx-number": "", "data-sx-typing": typing || !rolling ? "" : undefined, "data-sx-limit": limit ?? undefined, "data-sx-scrub": scrub ? "" : undefined, "data-sx-scrubbing": scrubbing ? "" : undefined, children: _jsx(Field, { ...rest, ...(value !== undefined ? { value: value ?? "" } : defaultValue !== undefined ? { defaultValue } : {}), labels: labels, type: "number", inputMode: step % 1 === 0 && (min === undefined || min >= 0) ? "numeric" : "decimal", min: min, max: max, step: step, onKeyDown: keys, onFocus: (e) => {
|
|
198
|
+
setFocused(true);
|
|
199
|
+
onFocus?.(e);
|
|
200
|
+
}, onBlur: (e) => {
|
|
201
|
+
setFocused(false);
|
|
202
|
+
setTyping(false);
|
|
203
|
+
onBlur?.(e);
|
|
204
|
+
}, end: _jsxs(_Fragment, { children: [rolling ? (_jsx("span", { ref: over, "data-sx-number-roll": "", "aria-hidden": true, children: _jsx(NumberRoll, { value: num, look: "spin", start: "change", duration: 0.45, format: focused ? PLAIN : format, locale: focused ? "en-US" : locale }) })) : null, end, button(false), button(true)] }) }) })] }));
|
|
205
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
interface OtpOwnProps {
|
|
3
|
+
/** The visible label: a real `<label for>`. Leave it out only with an `aria-label`. */
|
|
4
|
+
readonly label?: ReactNode;
|
|
5
|
+
readonly description?: ReactNode;
|
|
6
|
+
/** The error message. While set, the input is `aria-invalid` and points at it. */
|
|
7
|
+
readonly error?: ReactNode;
|
|
8
|
+
readonly invalid?: boolean;
|
|
9
|
+
/** How many characters. Default `6`. */
|
|
10
|
+
readonly length?: number;
|
|
11
|
+
/** Which characters it takes; others are dropped as they are typed or pasted. Default `"digits"`. */
|
|
12
|
+
readonly chars?: "digits" | "alphanumeric";
|
|
13
|
+
/** Slots per group, with a gap between groups: `[3, 3]`. Default: one group. */
|
|
14
|
+
readonly groups?: readonly number[];
|
|
15
|
+
/** Dots instead of the characters (a PIN): the input becomes a password input. */
|
|
16
|
+
readonly mask?: boolean;
|
|
17
|
+
/** Called once the last slot is filled (typed, pasted or filled in from a text message). */
|
|
18
|
+
readonly onComplete?: (code: string) => void;
|
|
19
|
+
/** The code, when you hold it. */
|
|
20
|
+
readonly value?: string;
|
|
21
|
+
readonly defaultValue?: string;
|
|
22
|
+
readonly unstyled?: boolean;
|
|
23
|
+
/** Goes on the slots' row. */
|
|
24
|
+
readonly className?: string;
|
|
25
|
+
/** Goes on the outer element. */
|
|
26
|
+
readonly rootClassName?: string;
|
|
27
|
+
readonly labelClassName?: string;
|
|
28
|
+
readonly style?: CSSProperties;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Every other prop goes on the one real input, `ref` included: `name`, `onChange`, `onBlur`, `required`, `autoFocus`,
|
|
32
|
+
* `disabled`, so `{...register("code")}` spreads straight onto it.
|
|
33
|
+
*/
|
|
34
|
+
export type OtpFieldProps = OtpOwnProps & Omit<ComponentPropsWithRef<"input">, keyof OtpOwnProps | "type" | "maxLength">;
|
|
35
|
+
/**
|
|
36
|
+
* A one-time code field: one real input, `autocomplete="one-time-code"`, laid over drawn slots. Typing, a paste of the
|
|
37
|
+
* whole code ("123 456" or "123-456" too) and a phone's code from a text message all land in that input, and a screen
|
|
38
|
+
* reader hears one text box. A click on a filled slot selects its character, so the next key replaces it; ← → move
|
|
39
|
+
* between slots and Backspace steps back.
|
|
40
|
+
*
|
|
41
|
+
* ```tsx
|
|
42
|
+
* <OtpField label="Code from the text" onComplete={verify} {...register("code")} />
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function OtpField(props: OtpFieldProps): import("react").JSX.Element;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
4
|
+
import { styleHref } from "../../backgrounds/hosts/CssHost.js";
|
|
5
|
+
import { warnOnce } from "../../buttons/runtime/dev.js";
|
|
6
|
+
import { motionOnly } from "../../transitions/progress.js";
|
|
7
|
+
import { fieldDescribedBy, fieldIds } from "../ids.js";
|
|
8
|
+
import { OTP_CSS, OTP_MOTION } from "../otp.js";
|
|
9
|
+
import { setNativeValue } from "./fieldTools.js";
|
|
10
|
+
import { filled } from "./shared.js";
|
|
11
|
+
const CLEAN = { digits: /\D/g, alphanumeric: /[^\da-z]/gi };
|
|
12
|
+
/**
|
|
13
|
+
* A one-time code field: one real input, `autocomplete="one-time-code"`, laid over drawn slots. Typing, a paste of the
|
|
14
|
+
* whole code ("123 456" or "123-456" too) and a phone's code from a text message all land in that input, and a screen
|
|
15
|
+
* reader hears one text box. A click on a filled slot selects its character, so the next key replaces it; ← → move
|
|
16
|
+
* between slots and Backspace steps back.
|
|
17
|
+
*
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <OtpField label="Code from the text" onComplete={verify} {...register("code")} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function OtpField(props) {
|
|
23
|
+
const { label, description, error, invalid, length: rawLength = 6, chars = "digits", groups, mask, onComplete, value, defaultValue, unstyled, className, rootClassName, labelClassName, style, id: ownId, ...rest } = props;
|
|
24
|
+
const length = Math.max(1, Math.round(rawLength));
|
|
25
|
+
const clean = (s) => s.replace(CLEAN[chars], "").slice(0, length);
|
|
26
|
+
const auto = useId().replace(/[^\w-]/g, "");
|
|
27
|
+
const id = ownId ?? `sx-otp${auto}`;
|
|
28
|
+
const ids = fieldIds(id);
|
|
29
|
+
const hasError = filled(error);
|
|
30
|
+
const ownInvalid = rest["aria-invalid"];
|
|
31
|
+
const isInvalid = hasError || invalid === true || ownInvalid === true || ownInvalid === "true";
|
|
32
|
+
const describedBy = fieldDescribedBy(ids, { error: hasError, description: filled(description), own: rest["aria-describedby"] });
|
|
33
|
+
if (process.env.NODE_ENV !== "production") {
|
|
34
|
+
if (!filled(label) && !rest["aria-label"] && !rest["aria-labelledby"])
|
|
35
|
+
warnOnce("an OtpField has no label: give it `label`, or an `aria-label`.");
|
|
36
|
+
if (groups && groups.reduce((a, b) => a + b, 0) !== length)
|
|
37
|
+
warnOnce(`an OtpField's groups add up to ${groups.reduce((a, b) => a + b, 0)}, not its length ${length}.`);
|
|
38
|
+
}
|
|
39
|
+
const input = useRef(null);
|
|
40
|
+
const slots = useRef(null);
|
|
41
|
+
const [code, setCode] = useState(() => clean(String(value ?? defaultValue ?? "")));
|
|
42
|
+
const [sel, setSel] = useState([0, 0]);
|
|
43
|
+
const done = useRef(onComplete);
|
|
44
|
+
done.current = onComplete;
|
|
45
|
+
// the input is the one truth: read it on each change, and keep its selection one character wide inside the code, so
|
|
46
|
+
// the slot you are on is the one the next key replaces
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
const el = input.current;
|
|
49
|
+
if (!el)
|
|
50
|
+
return;
|
|
51
|
+
let prev = el.value.length;
|
|
52
|
+
const select = (from) => {
|
|
53
|
+
const n = el.value.length;
|
|
54
|
+
const at = Math.max(0, Math.min(from, n === length ? n - 1 : n));
|
|
55
|
+
if (document.activeElement !== el)
|
|
56
|
+
return;
|
|
57
|
+
el.setSelectionRange(at, at < n ? at + 1 : at);
|
|
58
|
+
};
|
|
59
|
+
const sync = () => {
|
|
60
|
+
if (document.activeElement !== el)
|
|
61
|
+
return;
|
|
62
|
+
const s = el.selectionStart ?? 0;
|
|
63
|
+
const e = el.selectionEnd ?? s;
|
|
64
|
+
const n = el.value.length;
|
|
65
|
+
if (s === e && (s < n || (n === length && n > 0)))
|
|
66
|
+
return select(s);
|
|
67
|
+
setSel([s, e]);
|
|
68
|
+
};
|
|
69
|
+
const read = () => {
|
|
70
|
+
const v = el.value;
|
|
71
|
+
const ok = clean(v);
|
|
72
|
+
// autofill or a script can put in what typing can't: drop the rest, as a change of its own
|
|
73
|
+
if (ok !== v)
|
|
74
|
+
return setNativeValue(el, ok);
|
|
75
|
+
setCode(v);
|
|
76
|
+
if (v.length === length && prev < length)
|
|
77
|
+
done.current?.(v);
|
|
78
|
+
prev = v.length;
|
|
79
|
+
sync();
|
|
80
|
+
};
|
|
81
|
+
const before = (e) => {
|
|
82
|
+
if (e.isComposing)
|
|
83
|
+
return;
|
|
84
|
+
if (e.inputType === "insertText" && e.data && clean(e.data) !== e.data)
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
};
|
|
87
|
+
const paste = (e) => {
|
|
88
|
+
e.preventDefault();
|
|
89
|
+
const text = clean(e.clipboardData?.getData("text") ?? "");
|
|
90
|
+
if (!text || el.readOnly || el.disabled)
|
|
91
|
+
return;
|
|
92
|
+
const s = el.selectionStart ?? el.value.length;
|
|
93
|
+
const e2 = el.selectionEnd ?? s;
|
|
94
|
+
// the whole code replaces everything; a part goes where the caret is
|
|
95
|
+
const next = text.length >= length ? text : clean(el.value.slice(0, s) + text + el.value.slice(e2));
|
|
96
|
+
setNativeValue(el, next);
|
|
97
|
+
select(text.length >= length ? length : s + text.length);
|
|
98
|
+
};
|
|
99
|
+
const keys = (e) => {
|
|
100
|
+
if (e.altKey || e.ctrlKey || e.metaKey || e.isComposing)
|
|
101
|
+
return;
|
|
102
|
+
const s = el.selectionStart ?? 0;
|
|
103
|
+
const e2 = el.selectionEnd ?? s;
|
|
104
|
+
const n = el.value.length;
|
|
105
|
+
const one = e2 - s === 1;
|
|
106
|
+
if (e.key === "ArrowLeft" || e.key === "ArrowRight") {
|
|
107
|
+
// the slots always run left to right (a code reads that way in every script): ← is back
|
|
108
|
+
e.preventDefault();
|
|
109
|
+
select(e.key === "ArrowLeft" ? s - 1 : one ? s + 1 : e2);
|
|
110
|
+
}
|
|
111
|
+
else if (e.key === "Home" || e.key === "End") {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
select(e.key === "Home" ? 0 : n);
|
|
114
|
+
}
|
|
115
|
+
else if (e.key === "Backspace" && one && !el.readOnly) {
|
|
116
|
+
// on a slot, Backspace clears it and steps back one, as it would in a row of boxes
|
|
117
|
+
e.preventDefault();
|
|
118
|
+
setNativeValue(el, el.value.slice(0, s) + el.value.slice(e2));
|
|
119
|
+
select(Math.max(0, s === n - 1 ? s : s - 1));
|
|
120
|
+
}
|
|
121
|
+
else if (e.key === "Delete" && one && !el.readOnly) {
|
|
122
|
+
e.preventDefault();
|
|
123
|
+
setNativeValue(el, el.value.slice(0, s) + el.value.slice(e2));
|
|
124
|
+
select(s);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
// a click lands on the input, whose own caret means nothing here: put it on the slot under the pointer
|
|
128
|
+
const click = (e) => {
|
|
129
|
+
const boxes = [...(slots.current?.querySelectorAll("[data-sx-otp-slot]") ?? [])];
|
|
130
|
+
let at = boxes.findIndex((b) => {
|
|
131
|
+
const r = b.getBoundingClientRect();
|
|
132
|
+
return e.clientX >= r.left - 4 && e.clientX <= r.right + 4;
|
|
133
|
+
});
|
|
134
|
+
if (at === -1)
|
|
135
|
+
at = el.value.length;
|
|
136
|
+
// after the browser has put its own caret down (WebKit does so once the click's handlers have run)
|
|
137
|
+
setTimeout(() => select(Math.min(at, el.value.length)));
|
|
138
|
+
};
|
|
139
|
+
const focus = () => requestAnimationFrame(sync);
|
|
140
|
+
const reset = () => setTimeout(() => setCode(el.value));
|
|
141
|
+
el.addEventListener("input", read);
|
|
142
|
+
el.addEventListener("beforeinput", before);
|
|
143
|
+
el.addEventListener("paste", paste);
|
|
144
|
+
el.addEventListener("keydown", keys);
|
|
145
|
+
el.addEventListener("click", click);
|
|
146
|
+
el.addEventListener("focus", focus);
|
|
147
|
+
document.addEventListener("selectionchange", sync);
|
|
148
|
+
el.form?.addEventListener("reset", reset);
|
|
149
|
+
return () => {
|
|
150
|
+
el.removeEventListener("input", read);
|
|
151
|
+
el.removeEventListener("beforeinput", before);
|
|
152
|
+
el.removeEventListener("paste", paste);
|
|
153
|
+
el.removeEventListener("keydown", keys);
|
|
154
|
+
el.removeEventListener("click", click);
|
|
155
|
+
el.removeEventListener("focus", focus);
|
|
156
|
+
document.removeEventListener("selectionchange", sync);
|
|
157
|
+
el.form?.removeEventListener("reset", reset);
|
|
158
|
+
};
|
|
159
|
+
}, [length, chars]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
160
|
+
// a value set by the app (or React Hook Form's reset) shows in the slots too
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
const v = input.current?.value ?? "";
|
|
163
|
+
if (v !== code)
|
|
164
|
+
setCode(v);
|
|
165
|
+
});
|
|
166
|
+
const ownRef = rest.ref;
|
|
167
|
+
const setRef = (el) => {
|
|
168
|
+
input.current = el;
|
|
169
|
+
if (typeof ownRef === "function")
|
|
170
|
+
ownRef(el);
|
|
171
|
+
else if (ownRef)
|
|
172
|
+
ownRef.current = el;
|
|
173
|
+
};
|
|
174
|
+
const [s, e] = sel;
|
|
175
|
+
const slotsOf = (from, count) => Array.from({ length: count }, (_, k) => {
|
|
176
|
+
const i = from + k;
|
|
177
|
+
const char = code[i];
|
|
178
|
+
const active = s === e ? i === Math.min(s, length - 1) : e - s === 1 && i === s;
|
|
179
|
+
return (_jsxs("span", { "data-sx-otp-slot": "", "data-filled": char !== undefined ? "" : undefined, "data-active": active ? "" : undefined, "data-selected": e - s > 1 && i >= s && i < e ? "" : undefined, children: [char !== undefined ? (_jsx("span", { "data-sx-otp-char": "", children: mask ? "•" : char }, `${i}-${char}`)) : null, _jsx("span", { "data-sx-otp-caret": "" })] }, i));
|
|
180
|
+
});
|
|
181
|
+
const sizes = groups && groups.length > 0 ? groups : [length];
|
|
182
|
+
let from = 0;
|
|
183
|
+
const row = [];
|
|
184
|
+
sizes.forEach((size, g) => {
|
|
185
|
+
if (g > 0) {
|
|
186
|
+
row.push(_jsx("span", { "data-sx-otp-gap": "", children: _jsx("span", {}) }, `gap-${g}`));
|
|
187
|
+
}
|
|
188
|
+
row.push(...slotsOf(from, Math.min(size, length - from)));
|
|
189
|
+
from += size;
|
|
190
|
+
});
|
|
191
|
+
if (from < length)
|
|
192
|
+
row.push(...slotsOf(from, length - from));
|
|
193
|
+
const { ref: _ref, "aria-describedby": _d, "aria-invalid": _i, ...own } = rest;
|
|
194
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { href: styleHref("form-otp", OTP_CSS), precedence: "sx", children: OTP_CSS }), _jsx("style", { href: styleHref("form-otp-motion", OTP_MOTION), precedence: "sx", children: motionOnly(OTP_MOTION) }), _jsxs("div", { "data-sx-otp": "", "data-sx-styled": unstyled ? undefined : "", className: rootClassName, style: style, children: [filled(label) ? (_jsx("label", { "data-sx-otp-label": "", id: ids.label, htmlFor: id, className: labelClassName, children: label })) : null, _jsxs("div", { "data-sx-otp-box": "", dir: "ltr", children: [_jsx("div", { ref: slots, "data-sx-otp-slots": "", "aria-hidden": true, className: className, children: row }), _jsx("input", { autoComplete: "one-time-code", inputMode: chars === "digits" ? "numeric" : "text", pattern: chars === "digits" ? `\\d{${length}}` : `[\\da-zA-Z]{${length}}`, spellCheck: false, autoCapitalize: "off", autoCorrect: "off", ...own, ...(value !== undefined ? { value: clean(value) } : defaultValue !== undefined ? { defaultValue: clean(defaultValue) } : {}), ref: setRef, id: id, type: mask ? "password" : "text", maxLength: length, "data-sx-otp-control": "", "aria-invalid": isInvalid || undefined, "aria-required": own.required || undefined, "aria-describedby": describedBy })] }), filled(description) ? (_jsx("p", { "data-sx-otp-description": "", id: ids.description, children: description })) : null, _jsx("div", { "data-sx-otp-message": "", children: _jsx("p", { "data-sx-otp-error": "", id: ids.error, role: "alert", children: hasError ? (_jsx("span", { "data-sx-otp-says": "", children: error }, typeof error === "string" ? error : undefined)) : null }) })] })] }));
|
|
195
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/** One requirement and whether the password meets it (your app checks). */
|
|
3
|
+
export interface PasswordRule {
|
|
4
|
+
readonly label: ReactNode;
|
|
5
|
+
readonly met: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface PasswordRulesProps {
|
|
8
|
+
readonly rules: readonly PasswordRule[];
|
|
9
|
+
/** Give it one and pass it to the password field's `aria-describedby`, so the rules are read with the field. */
|
|
10
|
+
readonly id?: string;
|
|
11
|
+
/** The words for screen readers, for your language. `{met}` and `{total}` are numbers. */
|
|
12
|
+
readonly labels?: {
|
|
13
|
+
readonly met?: string;
|
|
14
|
+
readonly unmet?: string;
|
|
15
|
+
readonly progress?: string;
|
|
16
|
+
};
|
|
17
|
+
/** Goes on the list's box. */
|
|
18
|
+
readonly className?: string;
|
|
19
|
+
/** Drop the default look. */
|
|
20
|
+
readonly unstyled?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The rules a new password must meet, each ticking off as it is met: a dot turns into a check that draws in. Screen
|
|
24
|
+
* readers hear "done" or "not yet" on each rule, and a count when it changes. Your app checks the rules.
|
|
25
|
+
*
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <PasswordRules id="pw-rules" rules={[{ label: "8 characters or more", met: pw.length >= 8 }]} />
|
|
28
|
+
* <Field type="password" aria-describedby="pw-rules" … />
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function PasswordRules({ rules, id, labels, className, unstyled }: PasswordRulesProps): import("react").JSX.Element;
|