@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,35 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { fieldDescribedBy, fieldIds } from "../ids.js";
|
|
5
|
+
import { PICKER_BASE_CSS } from "../picker.js";
|
|
6
|
+
import { EffectSheets } from "./choiceParts.js";
|
|
7
|
+
import { checkPicker } from "./pickerChecks.js";
|
|
8
|
+
import { effectList, filled, withUid } from "./shared.js";
|
|
9
|
+
/**
|
|
10
|
+
* The browser's own `<select>`, wearing effects. Where the browser lets a page style its picker (Chrome 135+, Safari 27:
|
|
11
|
+
* `appearance: base-select`), the picker effects reach the list that opens; elsewhere (Firefox) the browser's own list
|
|
12
|
+
* opens, and the box, the arrow and the error still look the part. The keyboard, the screen reader, autofill and a
|
|
13
|
+
* phone's own picker all keep working, because it is the real one.
|
|
14
|
+
*
|
|
15
|
+
* ```tsx
|
|
16
|
+
* <Select label="Country" options={countries} placeholder="Choose…" effect={[pickerArrow(), pickerOpen()]} {...register("country")} />
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function Select(props) {
|
|
20
|
+
const { label, description, error, invalid, options, children, placeholder, effect, inline, unstyled, className, rootClassName, labelClassName, style, id: ownId, ...rest } = props;
|
|
21
|
+
const effects = effectList(effect);
|
|
22
|
+
const auto = useId().replace(/[^\w-]/g, "");
|
|
23
|
+
const id = ownId ?? `sx-select${auto}`;
|
|
24
|
+
const ids = fieldIds(id);
|
|
25
|
+
const hasError = filled(error);
|
|
26
|
+
const isInvalid = hasError || invalid === true || rest["aria-invalid"] === true || rest["aria-invalid"] === "true";
|
|
27
|
+
const describedBy = fieldDescribedBy(ids, { error: hasError, description: filled(description), own: rest["aria-describedby"] });
|
|
28
|
+
if (process.env.NODE_ENV !== "production") {
|
|
29
|
+
checkPicker({ control: "Select", effects, labelled: filled(label) || !!rest["aria-label"] || !!rest["aria-labelledby"], count: options?.length ?? 0 });
|
|
30
|
+
}
|
|
31
|
+
// nothing chosen yet: the placeholder shows, as the first option, until a real one is picked
|
|
32
|
+
const start = rest.value === undefined && rest.defaultValue === undefined && placeholder !== undefined ? { defaultValue: "" } : {};
|
|
33
|
+
const vars = { ...withUid(Object.assign({}, ...effects.map((e) => e.vars)), `sx${auto}`), ...style };
|
|
34
|
+
return (_jsxs(_Fragment, { children: [_jsx(EffectSheets, { name: "form-picker", base: PICKER_BASE_CSS, effects: effects }), _jsxs("div", { "data-sx-picker": effects.map((e) => e.id).join(" "), "data-sx-kind": "select", "data-sx-styled": unstyled ? undefined : "", "data-sx-inline": inline ? "" : undefined, className: rootClassName, style: vars, children: [filled(label) ? (_jsx("label", { "data-sx-picker-label": "", id: ids.label, htmlFor: id, className: labelClassName, children: label })) : null, _jsxs("div", { "data-sx-picker-box": "", className: className, children: [_jsxs("select", { ...start, ...rest, id: id, "data-sx-picker-control": "", "aria-invalid": isInvalid || undefined, "aria-describedby": describedBy, children: [placeholder !== undefined ? (_jsx("option", { value: "", disabled: true, hidden: true, children: placeholder })) : null, options?.map((o) => (_jsx("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))), children] }), _jsx("span", { "data-sx-picker-arrow": "", "aria-hidden": true, children: _jsx("svg", { viewBox: "0 0 24 24", focusable: "false", children: _jsx("path", { d: "m6 9 6 6 6-6" }) }) })] }), filled(description) ? (_jsx("p", { "data-sx-picker-description": "", id: ids.description, children: description })) : null, _jsx("div", { "data-sx-picker-message": "", children: _jsx("p", { "data-sx-picker-error": "", id: ids.error, role: "alert", children: hasError ? (_jsx("span", { "data-sx-picker-says": "", children: error }, typeof error === "string" ? error : undefined)) : null }) })] })] }));
|
|
35
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type CSSProperties, type ReactNode } from "react";
|
|
2
|
+
import type { FormEffect } from "../types.js";
|
|
3
|
+
interface SwitchOwnProps {
|
|
4
|
+
/** The words beside the switch. The whole row is the label: a click on the words flips it too. */
|
|
5
|
+
readonly label?: ReactNode;
|
|
6
|
+
/** Help under the words, read as the switch's description. */
|
|
7
|
+
readonly description?: ReactNode;
|
|
8
|
+
/** The error message, with `aria-invalid` and a `role="alert"` region. */
|
|
9
|
+
readonly error?: ReactNode;
|
|
10
|
+
readonly invalid?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Waiting for the server: a spinner in the thumb, `aria-busy`, clicks ignored. Flip `checked` back yourself if the
|
|
13
|
+
* save fails (the switch holds no opinion about the result).
|
|
14
|
+
*/
|
|
15
|
+
readonly pending?: boolean;
|
|
16
|
+
/** The thumb can be dragged; let go past halfway and it flips. A tap still flips it. */
|
|
17
|
+
readonly drag?: boolean;
|
|
18
|
+
/** A tick you can feel: Safari's own switch haptics on an iPhone, a short vibration on Android. Nothing elsewhere. */
|
|
19
|
+
readonly haptics?: boolean;
|
|
20
|
+
/** The words first, the switch at the end of the row (a settings list). */
|
|
21
|
+
readonly labelFirst?: boolean;
|
|
22
|
+
/** One effect or a list; they stack. */
|
|
23
|
+
readonly effect?: FormEffect | readonly FormEffect[];
|
|
24
|
+
/** The browser's own control: Safari's switch (`switch` attribute), a checkbox elsewhere. Effects don't apply. */
|
|
25
|
+
readonly native?: boolean;
|
|
26
|
+
/** Drop the default look. */
|
|
27
|
+
readonly unstyled?: boolean;
|
|
28
|
+
/** The words, for your language. */
|
|
29
|
+
readonly labels?: {
|
|
30
|
+
readonly pending?: string;
|
|
31
|
+
};
|
|
32
|
+
/** Goes on the track. */
|
|
33
|
+
readonly className?: string;
|
|
34
|
+
/** Goes on the outer element. */
|
|
35
|
+
readonly rootClassName?: string;
|
|
36
|
+
/** Goes on the words. */
|
|
37
|
+
readonly labelClassName?: string;
|
|
38
|
+
readonly style?: CSSProperties;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Every other prop goes on the real checkbox (`role="switch"`), `ref` included: `name`, `checked` / `defaultChecked`,
|
|
42
|
+
* `onChange`, `disabled`, so `{...register("news")}` spreads onto it.
|
|
43
|
+
*/
|
|
44
|
+
export type SwitchProps = SwitchOwnProps & Omit<ComponentPropsWithRef<"input">, keyof SwitchOwnProps | "type" | "role">;
|
|
45
|
+
/**
|
|
46
|
+
* A switch that wears any number of effects: a real checkbox with `role="switch"` on top of the drawn track, at opacity
|
|
47
|
+
* 0, the same size. It takes the click, Space and the focus; screen readers hear "switch, on".
|
|
48
|
+
*
|
|
49
|
+
* ```tsx
|
|
50
|
+
* <Switch label="Email me" effect={[switchSlide(), switchIcon()]} pending={saving} {...register("news")} />
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function Switch(props: SwitchProps): import("react").JSX.Element;
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useId, useRef } from "react";
|
|
4
|
+
import { styleHref } from "../../backgrounds/hosts/CssHost.js";
|
|
5
|
+
import { pickEffect } from "../../buttons/pick.js";
|
|
6
|
+
import { useButtonTier } from "../../buttons/runtime/useButtonTier.js";
|
|
7
|
+
import { CHOICE_BASE_CSS } from "../choice.js";
|
|
8
|
+
import { fieldDescribedBy, fieldIds } from "../ids.js";
|
|
9
|
+
import { useSwitchDrag } from "../runtime/useSwitchDrag.js";
|
|
10
|
+
import { SWITCH_BASE_CSS } from "../switch.js";
|
|
11
|
+
import { checkChoice } from "./choiceChecks.js";
|
|
12
|
+
import { ChoiceItem, EffectSheets, usePrograms } from "./choiceParts.js";
|
|
13
|
+
import { effectList, filled, withUid } from "./shared.js";
|
|
14
|
+
/**
|
|
15
|
+
* A switch that wears any number of effects: a real checkbox with `role="switch"` on top of the drawn track, at opacity
|
|
16
|
+
* 0, the same size. It takes the click, Space and the focus; screen readers hear "switch, on".
|
|
17
|
+
*
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <Switch label="Email me" effect={[switchSlide(), switchIcon()]} pending={saving} {...register("news")} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function Switch(props) {
|
|
23
|
+
const { label, description, error, invalid, pending, drag, haptics, labelFirst, effect, native, unstyled, labels, className, rootClassName, labelClassName, style, id: ownId, ...rest } = props;
|
|
24
|
+
const wanted = native ? [] : effectList(effect);
|
|
25
|
+
// a heavy effect starts on its fallback and moves up once the device is known (no hydration mismatch)
|
|
26
|
+
const device = useButtonTier(wanted.some((e) => e.tier !== "all"));
|
|
27
|
+
const effects = wanted.map((e) => pickEffect(e, device));
|
|
28
|
+
const auto = useId();
|
|
29
|
+
const id = ownId ?? `sx-switch${auto.replace(/[^\w-]/g, "")}`;
|
|
30
|
+
const uid = `sx${auto.replace(/[^\w-]/g, "")}`;
|
|
31
|
+
const ids = fieldIds(id);
|
|
32
|
+
const hasError = filled(error);
|
|
33
|
+
const ownInvalid = rest["aria-invalid"];
|
|
34
|
+
const isInvalid = hasError || invalid === true || ownInvalid === true || ownInvalid === "true";
|
|
35
|
+
const describedBy = fieldDescribedBy(ids, { error: hasError, description: filled(description), own: rest["aria-describedby"] });
|
|
36
|
+
if (process.env.NODE_ENV !== "production") {
|
|
37
|
+
checkChoice({
|
|
38
|
+
control: "switch",
|
|
39
|
+
effects,
|
|
40
|
+
labelled: filled(label) || !!rest["aria-label"] || !!rest["aria-labelledby"],
|
|
41
|
+
nativeWithEffects: !!native && !!effect && effectList(effect).length > 0,
|
|
42
|
+
invalidWithoutWords: invalid === true && !hasError,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const root = useRef(null);
|
|
46
|
+
usePrograms(root, effects);
|
|
47
|
+
useSwitchDrag(root, !!drag && !native);
|
|
48
|
+
// While it saves, a click must change nothing, and React must not hear one: it reports a checkbox's change from the
|
|
49
|
+
// click itself, so stopping the default in onClick still let onChange through. Stopped at the input, before React.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const input = root.current?.querySelector("[data-sx-choice-control]");
|
|
52
|
+
if (!pending || !input)
|
|
53
|
+
return;
|
|
54
|
+
const hold = (e) => {
|
|
55
|
+
e.preventDefault();
|
|
56
|
+
e.stopPropagation();
|
|
57
|
+
};
|
|
58
|
+
input.addEventListener("click", hold);
|
|
59
|
+
return () => input.removeEventListener("click", hold);
|
|
60
|
+
}, [pending]);
|
|
61
|
+
const ownChange = rest.onChange;
|
|
62
|
+
const vars = { ...withUid(Object.assign({}, ...effects.map((e) => e.vars)), uid), ...style };
|
|
63
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { href: styleHref("form-choice", CHOICE_BASE_CSS), precedence: "sx", children: CHOICE_BASE_CSS }), _jsx(EffectSheets, { name: "form-switch", base: SWITCH_BASE_CSS, effects: effects }), _jsxs(ChoiceItem, { kind: "switch", effects: effects, uid: uid, label: label, description: description, descriptionId: ids.description, boxClassName: className, labelClassName: labelClassName, thumb: pending ? _jsx("span", { "data-sx-switch-spinner": "" }) : null, root: {
|
|
64
|
+
ref: root,
|
|
65
|
+
"data-sx-choice": "",
|
|
66
|
+
"data-sx-switch": effects.map((e) => e.id).join(" "),
|
|
67
|
+
"data-sx-kind": "switch",
|
|
68
|
+
"data-sx-styled": unstyled ? undefined : "",
|
|
69
|
+
"data-sx-native": native ? "" : undefined,
|
|
70
|
+
"data-sx-pending": pending ? "" : undefined,
|
|
71
|
+
"data-sx-drag": drag && !native ? "" : undefined,
|
|
72
|
+
"data-sx-label-first": labelFirst ? "" : undefined,
|
|
73
|
+
className: rootClassName,
|
|
74
|
+
style: vars,
|
|
75
|
+
}, control: {
|
|
76
|
+
...rest,
|
|
77
|
+
id,
|
|
78
|
+
type: "checkbox",
|
|
79
|
+
role: "switch",
|
|
80
|
+
// Safari draws its own switch with this, and on an iPhone gives the haptic tick when it flips
|
|
81
|
+
...(native || haptics ? { switch: "" } : {}),
|
|
82
|
+
"aria-invalid": isInvalid || undefined,
|
|
83
|
+
"aria-describedby": describedBy,
|
|
84
|
+
"aria-busy": pending || undefined,
|
|
85
|
+
onChange: (e) => {
|
|
86
|
+
if (haptics && typeof navigator !== "undefined")
|
|
87
|
+
navigator.vibrate?.(8);
|
|
88
|
+
ownChange?.(e);
|
|
89
|
+
},
|
|
90
|
+
}, children: [pending === undefined ? null : (_jsx("span", { "data-sx-choice-sr": "", role: "status", children: pending ? (labels?.pending ?? "Saving…") : "" })), _jsx("div", { "data-sx-choice-message": "", children: _jsx("p", { "data-sx-choice-error": "", id: ids.error, role: "alert", children: hasError ? (_jsx("span", { "data-sx-choice-says": "", children: error }, typeof error === "string" ? error : undefined)) : null }) })] })] }));
|
|
91
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type CSSProperties, type FocusEvent, type ReactNode, type Ref } from "react";
|
|
2
|
+
import type { FormEffect } from "../types.js";
|
|
3
|
+
/** The words a TagsField says, for your language. `{label}` is a tag, `{n}` a number. */
|
|
4
|
+
export interface TagsFieldLabels {
|
|
5
|
+
readonly remove?: string;
|
|
6
|
+
readonly added?: string;
|
|
7
|
+
readonly removed?: string;
|
|
8
|
+
readonly again?: string;
|
|
9
|
+
readonly full?: string;
|
|
10
|
+
readonly refused?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface TagsFieldProps {
|
|
13
|
+
/** The visible label: a real `<label for>` on the text box. */
|
|
14
|
+
readonly label?: ReactNode;
|
|
15
|
+
readonly description?: ReactNode;
|
|
16
|
+
/** The error message. While set, the text box is `aria-invalid` and points at it. */
|
|
17
|
+
readonly error?: ReactNode;
|
|
18
|
+
readonly invalid?: boolean;
|
|
19
|
+
/** The tags, when you hold them (React Hook Form's `Controller` passes `field.value`). */
|
|
20
|
+
readonly value?: readonly string[];
|
|
21
|
+
readonly defaultValue?: readonly string[];
|
|
22
|
+
/** Called with every tag after a change: `field.onChange` fits. */
|
|
23
|
+
readonly onChange?: (tags: string[]) => void;
|
|
24
|
+
readonly onBlur?: (e: FocusEvent<HTMLInputElement>) => void;
|
|
25
|
+
/** Called with the words typed so far (to suggest, or to count). */
|
|
26
|
+
readonly onInputChange?: (text: string) => void;
|
|
27
|
+
/** Submitted with a plain form: one hidden input per tag. */
|
|
28
|
+
readonly name?: string;
|
|
29
|
+
/** The most tags; past it, a new one is refused and the field says so. */
|
|
30
|
+
readonly max?: number;
|
|
31
|
+
/** Keys besides Enter that end a tag. Default `[","]`. A paste is cut at each of these, and at new lines. */
|
|
32
|
+
readonly separators?: readonly string[];
|
|
33
|
+
/** Whether a tag may be added (a format, a length). A refused one stays in the box to be fixed. */
|
|
34
|
+
readonly allow?: (tag: string, tags: readonly string[]) => boolean;
|
|
35
|
+
/** The same words twice, ignoring case: refused, and the tag already there flashes. Default `false`. */
|
|
36
|
+
readonly duplicates?: boolean;
|
|
37
|
+
/** Typed words become a tag when the box loses the focus. Default `true`. */
|
|
38
|
+
readonly addOnBlur?: boolean;
|
|
39
|
+
readonly placeholder?: string;
|
|
40
|
+
readonly disabled?: boolean;
|
|
41
|
+
readonly required?: boolean;
|
|
42
|
+
readonly autoFocus?: boolean;
|
|
43
|
+
/** Goes on the text box (React Hook Form focuses it on an error). */
|
|
44
|
+
readonly ref?: Ref<HTMLInputElement>;
|
|
45
|
+
readonly id?: string;
|
|
46
|
+
/** `chipPop`: tags pop in and shrink away, the others glide into place. */
|
|
47
|
+
readonly effect?: FormEffect | readonly FormEffect[];
|
|
48
|
+
readonly labels?: TagsFieldLabels;
|
|
49
|
+
readonly unstyled?: boolean;
|
|
50
|
+
/** Goes on the box (border, background). */
|
|
51
|
+
readonly className?: string;
|
|
52
|
+
readonly rootClassName?: string;
|
|
53
|
+
readonly labelClassName?: string;
|
|
54
|
+
readonly style?: CSSProperties;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Free-text tags in one box: type and press Enter (or a comma) to add a tag, Backspace in the empty box removes the last,
|
|
58
|
+
* and a paste of "red, green, blue" adds three. Each tag has a named remove button. The tags are the value: hold them
|
|
59
|
+
* with `value` / `onChange` (React Hook Form's `Controller`), and `name` submits them with a plain form, one hidden
|
|
60
|
+
* input each. Suggestions to pick from are a `Combobox` with `multiple` and `creatable`.
|
|
61
|
+
*
|
|
62
|
+
* ```tsx
|
|
63
|
+
* <Controller name="skills" control={control} render={({ field }) => (
|
|
64
|
+
* <TagsField label="Skills" max={8} effect={chipPop()} {...field} />
|
|
65
|
+
* )} />
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function TagsField(props: TagsFieldProps): import("react").JSX.Element;
|
|
Binary file
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FormControl, FormEffect } from "../types.js";
|
|
2
|
+
export interface ChoiceCheck {
|
|
3
|
+
readonly control: Extract<FormControl, "checkbox" | "radio" | "switch">;
|
|
4
|
+
readonly effects: readonly FormEffect[];
|
|
5
|
+
/** It has words, or an `aria-label`. */
|
|
6
|
+
readonly labelled: boolean;
|
|
7
|
+
/** `native` with effects: they have nothing to paint on. */
|
|
8
|
+
readonly nativeWithEffects: boolean;
|
|
9
|
+
readonly invalidWithoutWords: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function checkChoice(c: ChoiceCheck): void;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Warnings for the developer about checkboxes and radio groups. The controls call this only outside production,
|
|
2
|
+
// behind a check bundlers turn into `if (false)`, so a production build drops this module and its messages.
|
|
3
|
+
import { claimConflicts } from "../../buttons/claims.js";
|
|
4
|
+
import { warnOnce } from "../../buttons/runtime/dev.js";
|
|
5
|
+
export function checkChoice(c) {
|
|
6
|
+
const what = c.control === "radio" ? "radio group" : c.control;
|
|
7
|
+
for (const { claim, ids } of claimConflicts(c.effects)) {
|
|
8
|
+
warnOnce(`${what} effects ${ids.join(" and ")} both write the "${claim}" channel: the last one wins. Keep one of them.`);
|
|
9
|
+
}
|
|
10
|
+
for (const e of c.effects)
|
|
11
|
+
if (!e.fits.includes(c.control))
|
|
12
|
+
warnOnce(`the effect ${e.id} is not made for a ${what}: it fits ${e.fits.join(", ")}.`);
|
|
13
|
+
if (!c.labelled)
|
|
14
|
+
warnOnce(`a ${what} has no label: give it \`label\`, or an \`aria-label\`.`);
|
|
15
|
+
if (c.nativeWithEffects)
|
|
16
|
+
warnOnce(`a native ${what} shows the browser's own control: its effects have nothing to paint on.`);
|
|
17
|
+
if (c.invalidWithoutWords)
|
|
18
|
+
warnOnce(`a ${what} marked invalid needs an \`error\` that says why.`);
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type CSSProperties, type ReactNode, type Ref, type RefObject } from "react";
|
|
2
|
+
import type { FormEffect, FormSlot } from "../types.js";
|
|
3
|
+
/** The base sheet first, then each effect's motion (dropped under reduced motion) and its states. */
|
|
4
|
+
export declare function EffectSheets({ name, base, effects }: {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly base: string;
|
|
7
|
+
readonly effects: readonly FormEffect[];
|
|
8
|
+
}): import("react").JSX.Element;
|
|
9
|
+
/** Starts the effects' programs (confetti) on the control's root; restarts them only when their options change. */
|
|
10
|
+
export declare function usePrograms(root: RefObject<HTMLElement | null>, effects: readonly FormEffect[]): void;
|
|
11
|
+
/** Every layer of these effects in one slot, in the effects' order. */
|
|
12
|
+
export declare function choiceLayers(effects: readonly FormEffect[], slot: FormSlot, uid: string): ReactNode[];
|
|
13
|
+
export interface ChoiceItemProps {
|
|
14
|
+
readonly kind: "checkbox" | "radio" | "switch";
|
|
15
|
+
/** The effects whose option layers this option wears (a checkbox's own, or its radio group's). */
|
|
16
|
+
readonly effects: readonly FormEffect[];
|
|
17
|
+
readonly uid: string;
|
|
18
|
+
readonly label: ReactNode;
|
|
19
|
+
readonly description?: ReactNode;
|
|
20
|
+
readonly descriptionId?: string;
|
|
21
|
+
/** Everything the real input gets: its type, the developer's props, the ids it points at. */
|
|
22
|
+
readonly control: Record<string, unknown>;
|
|
23
|
+
/** The option's root: data attributes, the class, the style. */
|
|
24
|
+
readonly root: Record<string, unknown> & {
|
|
25
|
+
readonly ref?: Ref<HTMLDivElement>;
|
|
26
|
+
readonly style?: CSSProperties;
|
|
27
|
+
};
|
|
28
|
+
readonly boxClassName?: string;
|
|
29
|
+
readonly labelClassName?: string;
|
|
30
|
+
/** After the option: its error row. */
|
|
31
|
+
readonly children?: ReactNode;
|
|
32
|
+
/** A switch's thumb, drawn over the track's layers. */
|
|
33
|
+
readonly thumb?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* One option. The whole row is a real `<label>` around the real input, so a click anywhere on it, the words included,
|
|
37
|
+
* toggles it, and its name is the words. The help sits inside too, for a card to hold it, so it is hidden from the name
|
|
38
|
+
* and read as the description instead.
|
|
39
|
+
*/
|
|
40
|
+
export declare function ChoiceItem({ kind, effects, uid, label, description, descriptionId, control, root, boxClassName, labelClassName, children, thumb }: ChoiceItemProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
// What a checkbox and a radio share: one option's markup (the drawn box under the real input, the mark, the words and
|
|
4
|
+
// the help, all inside a real label), the effects' layers by slot, the stylesheets, and the effects' programs.
|
|
5
|
+
import { useEffect } from "react";
|
|
6
|
+
import { styleHref } from "../../backgrounds/hosts/CssHost.js";
|
|
7
|
+
import { renderSvgElement } from "../../backgrounds/hosts/svgElement.js";
|
|
8
|
+
import { motionOnly } from "../../transitions/progress.js";
|
|
9
|
+
/** The base sheet first, then each effect's motion (dropped under reduced motion) and its states. */
|
|
10
|
+
export function EffectSheets({ name, base, effects }) {
|
|
11
|
+
return (_jsxs(_Fragment, { children: [_jsx("style", { href: styleHref(name, base), precedence: "sx", children: base }), effects.filter((e) => e.css).map((e) => {
|
|
12
|
+
const css = motionOnly(e.css);
|
|
13
|
+
return (_jsx("style", { href: styleHref(`form-${e.id}`, css), precedence: "sx", children: css }, e.id));
|
|
14
|
+
}), effects.filter((e) => e.stateCss).map((e) => (_jsx("style", { href: styleHref(`form-${e.id}-state`, e.stateCss), precedence: "sx", children: e.stateCss }, e.id)))] }));
|
|
15
|
+
}
|
|
16
|
+
/** Starts the effects' programs (confetti) on the control's root; restarts them only when their options change. */
|
|
17
|
+
export function usePrograms(root, effects) {
|
|
18
|
+
const programs = effects.filter((e) => e.program);
|
|
19
|
+
const key = programs.map((e) => `${e.id}:${e.program.signature}`).join(" ");
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
const el = root.current;
|
|
22
|
+
if (!el || programs.length === 0)
|
|
23
|
+
return;
|
|
24
|
+
const stops = programs.map((e) => e.program.attach(el));
|
|
25
|
+
return () => stops.forEach((stop) => stop());
|
|
26
|
+
// a factory called during render makes a new program every time: only its options restart it
|
|
27
|
+
}, [key]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
28
|
+
}
|
|
29
|
+
function ChoiceLayer({ effect, layer, uid }) {
|
|
30
|
+
return (_jsxs("span", { "data-sx-choice-layer": effect.id, "data-sx-choice-part": layer.part, "data-sx-choice-slot": layer.slot, "data-sx-choice-keep": layer.keep ? "" : undefined, "aria-hidden": true, children: [layer.svg ? (_jsx("svg", { viewBox: layer.svg.viewBox, preserveAspectRatio: layer.svg.preserveAspectRatio, focusable: "false", children: layer.svg.children.map((el, i) => renderSvgElement(el, uid, i, "data-sx-choice-svg")) })) : null, layer.children?.map((part) => _jsx("span", { "data-sx-choice-part": part }, part)), layer.text] }));
|
|
31
|
+
}
|
|
32
|
+
/** Every layer of these effects in one slot, in the effects' order. */
|
|
33
|
+
export function choiceLayers(effects, slot, uid) {
|
|
34
|
+
return effects.flatMap((effect) => effect.layers.filter((l) => l.slot === slot).map((layer, i) => _jsx(ChoiceLayer, { effect: effect, layer: layer, uid: uid }, `${effect.id}-${i}`)));
|
|
35
|
+
}
|
|
36
|
+
/** The mark a checked option shows: a tick and a dash for a checkbox (one drawn at a time), a dot for a radio. */
|
|
37
|
+
function Mark({ kind }) {
|
|
38
|
+
if (kind === "radio")
|
|
39
|
+
return _jsx("span", { "data-sx-mark": "dot" });
|
|
40
|
+
return (_jsxs("svg", { "data-sx-choice-mark": "", viewBox: "0 0 24 24", focusable: "false", children: [_jsx("path", { "data-sx-mark": "tick", d: "m5.5 12.5 4.25 4.25L18.5 7.5", pathLength: 1 }), _jsx("path", { "data-sx-mark": "dash", d: "M6.5 12h11", pathLength: 1 })] }));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* One option. The whole row is a real `<label>` around the real input, so a click anywhere on it, the words included,
|
|
44
|
+
* toggles it, and its name is the words. The help sits inside too, for a card to hold it, so it is hidden from the name
|
|
45
|
+
* and read as the description instead.
|
|
46
|
+
*/
|
|
47
|
+
export function ChoiceItem({ kind, effects, uid, label, description, descriptionId, control, root, boxClassName, labelClassName, children, thumb }) {
|
|
48
|
+
return (_jsxs("div", { ...root, children: [_jsxs("label", { "data-sx-choice-row": "", children: [choiceLayers(effects, "row", uid), choiceLayers(effects, "halo", uid), _jsx("span", { "data-sx-choice-box": "", "aria-hidden": true, className: boxClassName, children: kind === "switch" ? (_jsxs(_Fragment, { children: [choiceLayers(effects, "box", uid), _jsxs("span", { "data-sx-switch-thumb": "", children: [thumb, choiceLayers(effects, "thumb", uid)] })] })) : (_jsxs(_Fragment, { children: [_jsx(Mark, { kind: kind }), choiceLayers(effects, "box", uid)] })) }), _jsx("input", { "data-sx-choice-control": "", ...control }), _jsxs("span", { "data-sx-choice-text": "", className: labelClassName, children: [label, choiceLayers(effects, "text", uid)] }), description === undefined || description === null || description === false || description === "" ? null : (_jsx("span", { "data-sx-choice-description": "", id: descriptionId, "aria-hidden": true, children: description }))] }), children] }));
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { FormEffect, FormLabelPlan } from "../types.js";
|
|
2
|
+
export interface FieldCheck {
|
|
3
|
+
readonly effects: readonly FormEffect[];
|
|
4
|
+
readonly labelled: boolean;
|
|
5
|
+
readonly labelIsText: boolean;
|
|
6
|
+
readonly plan: FormLabelPlan | undefined;
|
|
7
|
+
readonly as: string | undefined;
|
|
8
|
+
readonly type: string | undefined;
|
|
9
|
+
readonly hasError: boolean;
|
|
10
|
+
readonly status: string | undefined;
|
|
11
|
+
readonly reveal: boolean | undefined;
|
|
12
|
+
readonly counter: boolean | number | undefined;
|
|
13
|
+
readonly limit: number | undefined;
|
|
14
|
+
readonly grow: boolean | number | undefined;
|
|
15
|
+
readonly focusRing: "auto" | "always" | "none" | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare function checkField(c: FieldCheck): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// The field's warnings for the developer. `Field` calls this only outside production, behind a check bundlers turn into
|
|
2
|
+
// `if (false)`, so a production build drops this module and every message in it.
|
|
3
|
+
import { claimConflicts } from "../../buttons/claims.js";
|
|
4
|
+
import { warnOnce } from "../../buttons/runtime/dev.js";
|
|
5
|
+
export function checkField(c) {
|
|
6
|
+
for (const { claim, ids } of claimConflicts(c.effects)) {
|
|
7
|
+
warnOnce(`field effects ${ids.join(" and ")} both write the "${claim}" channel: the last one wins. Keep one of them.`);
|
|
8
|
+
}
|
|
9
|
+
for (const e of c.effects) {
|
|
10
|
+
if (!e.fits.includes("field"))
|
|
11
|
+
warnOnce(`the effect ${e.id} is not made for a text field: it fits ${e.fits.join(", ")}.`);
|
|
12
|
+
if (e.needs.tool === "counter" && !c.counter)
|
|
13
|
+
warnOnce(`${e.id} draws the character counter: turn it on with \`counter\`.`);
|
|
14
|
+
if (e.needs.tool === "reveal" && !c.reveal)
|
|
15
|
+
warnOnce(`${e.id} styles the show-password button: turn it on with \`reveal\`.`);
|
|
16
|
+
}
|
|
17
|
+
if (!c.labelled)
|
|
18
|
+
warnOnce("a field has no label: give it `label`, or an `aria-label`. A placeholder is not a label: it goes away as you type.");
|
|
19
|
+
if (c.plan?.split && !c.labelIsText)
|
|
20
|
+
warnOnce("a field effect that moves the label's letters needs a plain text label: with anything else, the letters stay still.");
|
|
21
|
+
if (c.effects.some((e) => e.layers.some((l) => l.legend)) && !c.labelled)
|
|
22
|
+
warnOnce("inputNotch cuts its gap to fit the label: it needs one.");
|
|
23
|
+
if (c.status === "invalid" && !c.hasError)
|
|
24
|
+
warnOnce('a field with status="invalid" needs an `error` that says why: a red mark alone is not enough.');
|
|
25
|
+
if (c.reveal && c.type !== "password")
|
|
26
|
+
warnOnce('`reveal` shows a password: the field needs type="password".');
|
|
27
|
+
if (c.grow && c.as !== "textarea")
|
|
28
|
+
warnOnce('`grow` makes a textarea grow with its text: give the field as="textarea".');
|
|
29
|
+
if (c.focusRing === "none" && !c.effects.some((e) => e.marksFocus)) {
|
|
30
|
+
warnOnce('focusRing="none" leaves no sign of the focus: give the field an effect that marks it (inputUnderline, inputRing …) or style :focus-within yourself.');
|
|
31
|
+
}
|
|
32
|
+
if (c.counter === true && c.limit === undefined)
|
|
33
|
+
warnOnce("`counter` counts against `maxLength`: give the field one, or pass the limit as `counter={280}`.");
|
|
34
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/** The words a field's own buttons and notes use. Pass yours for another language; anything left out stays English. */
|
|
3
|
+
export interface FieldLabels {
|
|
4
|
+
/** The clear button's name. */
|
|
5
|
+
readonly clear?: string;
|
|
6
|
+
/** The show-password button's name (it is a toggle: pressed while the password shows). */
|
|
7
|
+
readonly show?: string;
|
|
8
|
+
/** Shown under a password field while Caps Lock is on. */
|
|
9
|
+
readonly capsLock?: string;
|
|
10
|
+
/** Read out near the counter's limit. `{n}` is the number. */
|
|
11
|
+
readonly left?: string;
|
|
12
|
+
/** Read out past a soft limit. `{n}` is the number. */
|
|
13
|
+
readonly over?: string;
|
|
14
|
+
/** Beside the strength meter. `{level}` is one of `levels`. */
|
|
15
|
+
readonly strength?: string;
|
|
16
|
+
/** The strength levels, 0 to 4. */
|
|
17
|
+
readonly levels?: readonly [string, string, string, string, string];
|
|
18
|
+
/** Read out while an async check runs (`status="checking"`). */
|
|
19
|
+
readonly checking?: string;
|
|
20
|
+
/** Read out when it passes (`status="valid"`). */
|
|
21
|
+
readonly valid?: string;
|
|
22
|
+
/** The hint button's name. */
|
|
23
|
+
readonly hint?: string;
|
|
24
|
+
}
|
|
25
|
+
export declare const FIELD_LABELS: Required<FieldLabels>;
|
|
26
|
+
/**
|
|
27
|
+
* Sets a value the way typing does: through the element's own setter, which React's change tracking doesn't see, then an
|
|
28
|
+
* `input` event, so a controlled field's `onChange` and React Hook Form both hear it.
|
|
29
|
+
*/
|
|
30
|
+
export declare function setNativeValue(el: HTMLInputElement | HTMLTextAreaElement, value: string): void;
|
|
31
|
+
interface ToolProps {
|
|
32
|
+
readonly label: string;
|
|
33
|
+
/** The input's id. */
|
|
34
|
+
readonly controls: string;
|
|
35
|
+
readonly onClick: () => void;
|
|
36
|
+
}
|
|
37
|
+
export declare function ClearButton({ label, controls, onClick }: ToolProps): import("react").JSX.Element;
|
|
38
|
+
/** Shows the action: an open eye while the password is hidden, a crossed-out one while it shows. */
|
|
39
|
+
export declare function RevealButton({ label, controls, onClick, pressed }: ToolProps & {
|
|
40
|
+
readonly pressed: boolean;
|
|
41
|
+
}): import("react").JSX.Element;
|
|
42
|
+
/** Opens the hint popover. Anchor positioning places it; the field moves it by hand where that is missing. */
|
|
43
|
+
export declare function HintButton({ label, target, anchor }: {
|
|
44
|
+
readonly label: string;
|
|
45
|
+
readonly target: string;
|
|
46
|
+
readonly anchor: string;
|
|
47
|
+
}): import("react").JSX.Element;
|
|
48
|
+
/** The async check's mark: a ring that spins, then a check or a cross. */
|
|
49
|
+
export declare function StatusMark(): import("react").JSX.Element;
|
|
50
|
+
/** "12/280", or "12" with no limit. `inputCounter` draws its ring in `children` and shows what is left near the end. */
|
|
51
|
+
export declare function Counter({ used, limit, children }: {
|
|
52
|
+
readonly used: number;
|
|
53
|
+
readonly limit: number | undefined;
|
|
54
|
+
readonly children: ReactNode;
|
|
55
|
+
}): import("react").JSX.Element;
|
|
56
|
+
/** Four bars and a word. The word is a live region: a new level is read out. */
|
|
57
|
+
export declare function Strength({ level, text }: {
|
|
58
|
+
readonly level: number;
|
|
59
|
+
readonly text: string;
|
|
60
|
+
}): import("react").JSX.Element;
|
|
61
|
+
export declare function CapsIcon(): import("react").JSX.Element;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export const FIELD_LABELS = {
|
|
3
|
+
clear: "Clear",
|
|
4
|
+
show: "Show password",
|
|
5
|
+
capsLock: "Caps Lock is on",
|
|
6
|
+
left: "{n} characters left",
|
|
7
|
+
over: "{n} characters too many",
|
|
8
|
+
strength: "Strength: {level}",
|
|
9
|
+
levels: ["Very weak", "Weak", "Fair", "Good", "Strong"],
|
|
10
|
+
checking: "Checking…",
|
|
11
|
+
valid: "Looks good",
|
|
12
|
+
hint: "More about this field",
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Sets a value the way typing does: through the element's own setter, which React's change tracking doesn't see, then an
|
|
16
|
+
* `input` event, so a controlled field's `onChange` and React Hook Form both hear it.
|
|
17
|
+
*/
|
|
18
|
+
export function setNativeValue(el, value) {
|
|
19
|
+
const set = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), "value")?.set;
|
|
20
|
+
if (set)
|
|
21
|
+
set.call(el, value);
|
|
22
|
+
else
|
|
23
|
+
el.value = value;
|
|
24
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
25
|
+
}
|
|
26
|
+
const Icon = ({ children }) => (_jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": true, focusable: "false", children: children }));
|
|
27
|
+
export function ClearButton({ label, controls, onClick }) {
|
|
28
|
+
return (_jsx("button", { type: "button", "data-sx-field-tool": "", "data-sx-field-clear": "", "aria-label": label, "aria-controls": controls, onClick: onClick, children: _jsx(Icon, { children: _jsx("path", { d: "m7 7 10 10M17 7 7 17" }) }) }));
|
|
29
|
+
}
|
|
30
|
+
/** Shows the action: an open eye while the password is hidden, a crossed-out one while it shows. */
|
|
31
|
+
export function RevealButton({ label, controls, onClick, pressed }) {
|
|
32
|
+
return (_jsx("button", { type: "button", "data-sx-field-tool": "", "data-sx-field-reveal": "", "aria-label": label, "aria-pressed": pressed, "aria-controls": controls,
|
|
33
|
+
// a press keeps the focus (and a phone's keyboard) in the field: Safari would otherwise drop it on the page
|
|
34
|
+
onPointerDown: (e) => e.preventDefault(), onClick: onClick, children: _jsxs(Icon, { children: [_jsx("path", { "data-sx-tool-eye": "lid", d: "M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12Z" }), _jsx("circle", { "data-sx-tool-eye": "pupil", cx: "12", cy: "12", r: "3" }), _jsx("path", { "data-sx-tool-part": "slash", d: "m4 4 16 16", pathLength: 1 })] }) }));
|
|
35
|
+
}
|
|
36
|
+
/** Opens the hint popover. Anchor positioning places it; the field moves it by hand where that is missing. */
|
|
37
|
+
export function HintButton({ label, target, anchor }) {
|
|
38
|
+
return (_jsx("button", { type: "button", "data-sx-field-tool": "", "data-sx-field-hint-button": "", "aria-label": label, popoverTarget: target, style: { anchorName: anchor }, children: _jsxs(Icon, { children: [_jsx("circle", { cx: "12", cy: "12", r: "9" }), _jsx("path", { d: "M12 11v5M12 8h.01" })] }) }));
|
|
39
|
+
}
|
|
40
|
+
/** The async check's mark: a ring that spins, then a check or a cross. */
|
|
41
|
+
export function StatusMark() {
|
|
42
|
+
return (_jsx("span", { "data-sx-field-status": "", "aria-hidden": true, children: _jsxs(Icon, { children: [_jsx("circle", { "data-sx-tool-part": "ring", cx: "12", cy: "12", r: "9", pathLength: 1 }), _jsx("path", { "data-sx-tool-part": "check", d: "m8 12.5 2.75 2.75L16 9.5", pathLength: 1 }), _jsx("path", { "data-sx-tool-part": "cross", d: "m9 9 6 6m0-6-6 6", pathLength: 1 })] }) }));
|
|
43
|
+
}
|
|
44
|
+
/** "12/280", or "12" with no limit. `inputCounter` draws its ring in `children` and shows what is left near the end. */
|
|
45
|
+
export function Counter({ used, limit, children }) {
|
|
46
|
+
return (_jsxs("span", { "data-sx-field-counter": "", "aria-hidden": true, children: [children, _jsx("span", { "data-sx-field-used": "", children: limit === undefined ? used : `${used}/${limit}` }), limit === undefined ? null : _jsx("span", { "data-sx-field-left": "", children: limit - used })] }));
|
|
47
|
+
}
|
|
48
|
+
/** Four bars and a word. The word is a live region: a new level is read out. */
|
|
49
|
+
export function Strength({ level, text }) {
|
|
50
|
+
return (_jsxs("div", { "data-sx-field-strength": "", children: [_jsx("span", { "data-sx-field-bars": "", "aria-hidden": true, children: [0, 1, 2, 3].map((i) => (_jsx("span", { "data-sx-field-bar": "", style: { "--sx-field-i": i }, children: _jsx("span", {}) }, i))) }), _jsx("span", { "data-sx-field-level": "", role: "status", children: _jsx("span", { children: text }, level) })] }));
|
|
51
|
+
}
|
|
52
|
+
export function CapsIcon() {
|
|
53
|
+
return (_jsxs(Icon, { children: [_jsx("path", { d: "M12 4 5 11h4v5h6v-5h4Z" }), _jsx("path", { d: "M9 20h6" })] }));
|
|
54
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FormEffect } from "../types.js";
|
|
2
|
+
export interface PickerCheck {
|
|
3
|
+
readonly control: "Select" | "Combobox" | "TagsField";
|
|
4
|
+
readonly effects: readonly FormEffect[];
|
|
5
|
+
readonly labelled: boolean;
|
|
6
|
+
readonly count: number;
|
|
7
|
+
/** Options whose label is not plain text and that have no `text` to filter and show by. */
|
|
8
|
+
readonly wordless?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function checkPicker(c: PickerCheck): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Warnings for the developer about Select and Combobox. Called only outside production, behind a check bundlers turn
|
|
2
|
+
// into `if (false)`, so a production build drops this module and its messages.
|
|
3
|
+
import { claimConflicts } from "../../buttons/claims.js";
|
|
4
|
+
import { warnOnce } from "../../buttons/runtime/dev.js";
|
|
5
|
+
/** Effects that need the Combobox's own markup: a highlight layer, marked words, chips. */
|
|
6
|
+
const COMBOBOX_ONLY = ["listHighlight", "listMatch", "chipPop"];
|
|
7
|
+
/** Past this many options a list without virtual scrolling gets slow to filter and to read. */
|
|
8
|
+
const MANY = 500;
|
|
9
|
+
export function checkPicker(c) {
|
|
10
|
+
for (const { claim, ids } of claimConflicts(c.effects)) {
|
|
11
|
+
warnOnce(`${c.control} effects ${ids.join(" and ")} both write the "${claim}" channel: the last one wins. Keep one of them.`);
|
|
12
|
+
}
|
|
13
|
+
for (const e of c.effects) {
|
|
14
|
+
if (!e.fits.includes("picker"))
|
|
15
|
+
warnOnce(`the effect ${e.id} is not made for a ${c.control}: it fits ${e.fits.join(", ")}.`);
|
|
16
|
+
else if (c.control === "TagsField" && e.id !== "chipPop")
|
|
17
|
+
warnOnce(`the effect ${e.id} reaches only a Select or a Combobox: a TagsField has no list.`);
|
|
18
|
+
else if (c.control === "Select" && COMBOBOX_ONLY.includes(e.id))
|
|
19
|
+
warnOnce(`the effect ${e.id} reaches only a Combobox: a <select> has no ${e.id === "chipPop" ? "chips" : "room for it in its list"}.`);
|
|
20
|
+
}
|
|
21
|
+
if (!c.labelled)
|
|
22
|
+
warnOnce(`a ${c.control} has no label: give it \`label\`, or an \`aria-label\`.`);
|
|
23
|
+
if (c.count > MANY)
|
|
24
|
+
warnOnce(`a ${c.control} with ${c.count} options: past ${MANY}, filter on the server and pass the matches.`);
|
|
25
|
+
if (c.wordless)
|
|
26
|
+
warnOnce(`${c.wordless} Combobox options have a label that is not plain text and no \`text\`: give them \`text\` to filter and show by.`);
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { FormEffect } from "../types.js";
|
|
2
|
+
export interface RangeCheck {
|
|
3
|
+
readonly effects: readonly FormEffect[];
|
|
4
|
+
readonly labelled: boolean;
|
|
5
|
+
readonly min: number;
|
|
6
|
+
readonly max: number;
|
|
7
|
+
readonly step: number;
|
|
8
|
+
readonly vertical: boolean;
|
|
9
|
+
readonly dual: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function checkRange(c: RangeCheck): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Warnings for the developer about Range. Called only outside production, behind a check bundlers turn into
|
|
2
|
+
// `if (false)`, so a production build drops this module and its messages.
|
|
3
|
+
import { claimConflicts } from "../../buttons/claims.js";
|
|
4
|
+
import { warnOnce } from "../../buttons/runtime/dev.js";
|
|
5
|
+
/** Effects drawn along a rail that lies across: they don't stand a Range upright. */
|
|
6
|
+
const ACROSS_ONLY = ["rangeHistogram"];
|
|
7
|
+
export function checkRange(c) {
|
|
8
|
+
for (const { claim, ids } of claimConflicts(c.effects)) {
|
|
9
|
+
warnOnce(`Range effects ${ids.join(" and ")} both write the "${claim}" channel: the last one wins. Keep one of them.`);
|
|
10
|
+
}
|
|
11
|
+
for (const e of c.effects) {
|
|
12
|
+
if (!e.fits.includes("range"))
|
|
13
|
+
warnOnce(`the effect ${e.id} is not made for a Range: it fits ${e.fits.join(", ")}.`);
|
|
14
|
+
else if (c.vertical && ACROSS_ONLY.includes(e.id))
|
|
15
|
+
warnOnce(`the effect ${e.id} draws along a rail that lies across: an upright Range doesn't show it.`);
|
|
16
|
+
}
|
|
17
|
+
if (!c.labelled)
|
|
18
|
+
warnOnce("a Range has no label: give it `label`, or an `aria-label`.");
|
|
19
|
+
if (!(c.max > c.min))
|
|
20
|
+
warnOnce(`a Range's max (${c.max}) must be above its min (${c.min}).`);
|
|
21
|
+
if (!(c.step > 0))
|
|
22
|
+
warnOnce(`a Range's step must be above 0 (it is ${c.step}).`);
|
|
23
|
+
}
|