@qw-ui/core 0.3.0-next.4 → 0.3.0-next.42
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 +21 -37
- package/dist/action-sheet/action-sheet.d.ts +110 -0
- package/dist/action-sheet/index.d.ts +2 -0
- package/dist/action-sheet/index.js +2 -0
- package/dist/action-sheet-Cvcr1S_m.js +183 -0
- package/dist/action-sheet-Cvcr1S_m.js.map +1 -0
- package/dist/area-picker/area-picker.d.ts +113 -0
- package/dist/area-picker/index.d.ts +1 -0
- package/dist/area-picker/index.js +348 -0
- package/dist/area-picker/index.js.map +1 -0
- package/dist/aria-description-CimD2M_C.js +13 -0
- package/dist/aria-description-CimD2M_C.js.map +1 -0
- package/dist/aria-description.d.ts +2 -0
- package/dist/avatar/avatar-load.d.ts +76 -0
- package/dist/avatar/avatar.d.ts +22 -5
- package/dist/avatar/index.d.ts +1 -0
- package/dist/avatar/index.js +57 -18
- package/dist/avatar/index.js.map +1 -1
- package/dist/avatar-load-w9dq05oV.js +139 -0
- package/dist/avatar-load-w9dq05oV.js.map +1 -0
- package/dist/back-top/back-top.d.ts +77 -0
- package/dist/back-top/index.d.ts +1 -0
- package/dist/back-top/index.js +189 -0
- package/dist/back-top/index.js.map +1 -0
- package/dist/badge/badge.d.ts +85 -0
- package/dist/badge/index.d.ts +1 -0
- package/dist/badge/index.js +88 -0
- package/dist/badge/index.js.map +1 -0
- package/dist/button/button.d.ts +13 -0
- package/dist/button/index.js +3 -5
- package/dist/button/index.js.map +1 -1
- package/dist/calendar/calendar.d.ts +100 -0
- package/dist/calendar/index.d.ts +1 -0
- package/dist/calendar/index.js +2 -0
- package/dist/calendar-CmpK3stz.js +363 -0
- package/dist/calendar-CmpK3stz.js.map +1 -0
- package/dist/card/card.d.ts +68 -0
- package/dist/card/index.d.ts +2 -0
- package/dist/card/index.js +2 -0
- package/dist/card-DRtWa6Cr.js +107 -0
- package/dist/card-DRtWa6Cr.js.map +1 -0
- package/dist/cascader/cascader.d.ts +115 -0
- package/dist/cascader/index.d.ts +1 -0
- package/dist/cascader/index.js +2 -0
- package/dist/cascader-D-xMjs7P.js +333 -0
- package/dist/cascader-D-xMjs7P.js.map +1 -0
- package/dist/cell/cell.d.ts +41 -0
- package/dist/cell/index.d.ts +1 -0
- package/dist/cell/index.js +43 -0
- package/dist/cell/index.js.map +1 -0
- package/dist/check-list/check-list.d.ts +78 -0
- package/dist/check-list/index.d.ts +2 -0
- package/dist/check-list/index.js +2 -0
- package/dist/check-list-BvZHQt5w.js +60 -0
- package/dist/check-list-BvZHQt5w.js.map +1 -0
- package/dist/checkbox/checkbox.d.ts +59 -0
- package/dist/checkbox/index.d.ts +2 -0
- package/dist/checkbox/index.js +2 -0
- package/dist/checkbox-BlndJrz5.js +127 -0
- package/dist/checkbox-BlndJrz5.js.map +1 -0
- package/dist/checkbox-group/checkbox-group.d.ts +86 -0
- package/dist/checkbox-group/index.d.ts +3 -0
- package/dist/checkbox-group/index.js +2 -0
- package/dist/checkbox-group-gGfsTv-e.js +223 -0
- package/dist/checkbox-group-gGfsTv-e.js.map +1 -0
- package/dist/choice-group-C4c9m0qe.js +373 -0
- package/dist/choice-group-C4c9m0qe.js.map +1 -0
- package/dist/circle/circle.d.ts +97 -0
- package/dist/circle/index.d.ts +1 -0
- package/dist/circle/index.js +119 -0
- package/dist/circle/index.js.map +1 -0
- package/dist/collapse/collapse.d.ts +98 -0
- package/dist/collapse/index.d.ts +2 -0
- package/dist/collapse/index.js +2 -0
- package/dist/collapse-B969h7-H.js +226 -0
- package/dist/collapse-B969h7-H.js.map +1 -0
- package/dist/countdown/countdown.d.ts +114 -0
- package/dist/countdown/index.d.ts +1 -0
- package/dist/countdown/index.js +309 -0
- package/dist/countdown/index.js.map +1 -0
- package/dist/date-picker/date-picker.d.ts +168 -0
- package/dist/date-picker/index.d.ts +1 -0
- package/dist/date-picker/index.js +401 -0
- package/dist/date-picker/index.js.map +1 -0
- package/dist/descriptions/descriptions.d.ts +69 -0
- package/dist/descriptions/index.d.ts +1 -0
- package/dist/descriptions/index.js +86 -0
- package/dist/descriptions/index.js.map +1 -0
- package/dist/dialog/dialog.d.ts +61 -43
- package/dist/dialog/index.js +73 -19
- package/dist/dialog/index.js.map +1 -1
- package/dist/divider/divider.d.ts +18 -2
- package/dist/divider/index.js +20 -2
- package/dist/divider/index.js.map +1 -1
- package/dist/dropdown/dropdown.d.ts +172 -0
- package/dist/dropdown/index.d.ts +2 -0
- package/dist/dropdown/index.js +467 -0
- package/dist/dropdown/index.js.map +1 -0
- package/dist/ellipsis/ellipsis-layout.d.ts +34 -0
- package/dist/ellipsis/ellipsis.d.ts +88 -0
- package/dist/ellipsis/index.d.ts +2 -0
- package/dist/ellipsis/index.js +320 -0
- package/dist/ellipsis/index.js.map +1 -0
- package/dist/empty/empty-illustration.d.ts +3 -0
- package/dist/empty/empty.d.ts +43 -1
- package/dist/empty/index.js +2 -21
- package/dist/empty-CAgyvhUI.js +166 -0
- package/dist/empty-CAgyvhUI.js.map +1 -0
- package/dist/field/field.d.ts +95 -0
- package/dist/field/index.d.ts +2 -0
- package/dist/field/index.js +2 -0
- package/dist/field-DMHGIMZF.js +241 -0
- package/dist/field-DMHGIMZF.js.map +1 -0
- package/dist/floating-bubble/floating-bubble.d.ts +116 -0
- package/dist/floating-bubble/index.d.ts +1 -0
- package/dist/floating-bubble/index.js +333 -0
- package/dist/floating-bubble/index.js.map +1 -0
- package/dist/floating-panel/floating-panel.d.ts +80 -0
- package/dist/floating-panel/index.d.ts +2 -0
- package/dist/floating-panel/index.js +2 -0
- package/dist/floating-panel-Cbm5njBJ.js +363 -0
- package/dist/floating-panel-Cbm5njBJ.js.map +1 -0
- package/dist/footer/footer.d.ts +94 -0
- package/dist/footer/index.d.ts +1 -0
- package/dist/footer/index.js +154 -0
- package/dist/footer/index.js.map +1 -0
- package/dist/form/connect.d.ts +6 -0
- package/dist/form/form.d.ts +100 -0
- package/dist/form/ids.d.ts +14 -0
- package/dist/form/index.d.ts +13 -0
- package/dist/form/index.js +3 -0
- package/dist/form/methods.d.ts +5 -0
- package/dist/form/model.d.ts +24 -0
- package/dist/form/native.d.ts +25 -0
- package/dist/form/rules.d.ts +40 -0
- package/dist/form/ssr.d.ts +7 -0
- package/dist/form/types.d.ts +150 -0
- package/dist/form-BAGkIEMY.js +1354 -0
- package/dist/form-BAGkIEMY.js.map +1 -0
- package/dist/format-BDUY0C_c.js +89 -0
- package/dist/format-BDUY0C_c.js.map +1 -0
- package/dist/gesture-_SRHIvBm.js +30 -0
- package/dist/gesture-_SRHIvBm.js.map +1 -0
- package/dist/grid/grid-item.d.ts +22 -0
- package/dist/grid/grid.d.ts +42 -0
- package/dist/grid/index.d.ts +2 -0
- package/dist/grid/index.js +73 -0
- package/dist/grid/index.js.map +1 -0
- package/dist/icon/icon.d.ts +37 -1
- package/dist/icon/identity.d.ts +3 -0
- package/dist/icon/index.js +2 -20
- package/dist/icon-Cgdbnk1u.js +77 -0
- package/dist/icon-Cgdbnk1u.js.map +1 -0
- package/dist/image/image-load.d.ts +24 -0
- package/dist/image/image.d.ts +45 -8
- package/dist/image/index.d.ts +1 -0
- package/dist/image/index.js +116 -14
- package/dist/image/index.js.map +1 -1
- package/dist/image-preview/image-preview.d.ts +124 -0
- package/dist/image-preview/index.d.ts +1 -0
- package/dist/image-preview/index.js +450 -0
- package/dist/image-preview/index.js.map +1 -0
- package/dist/index-bar/index-bar.d.ts +121 -0
- package/dist/index-bar/index.d.ts +1 -0
- package/dist/index-bar/index.js +386 -0
- package/dist/index-bar/index.js.map +1 -0
- package/dist/index.d.ts +115 -10
- package/dist/index.js +151 -11
- package/dist/index.js.map +1 -0
- package/dist/infinite-scroll/index.d.ts +1 -0
- package/dist/infinite-scroll/index.js +248 -0
- package/dist/infinite-scroll/index.js.map +1 -0
- package/dist/infinite-scroll/infinite-scroll.d.ts +95 -0
- package/dist/input/index.js +181 -22
- package/dist/input/index.js.map +1 -1
- package/dist/input/input.d.ts +44 -1
- package/dist/layer-IpFrl5--.js +414 -0
- package/dist/layer-IpFrl5--.js.map +1 -0
- package/dist/layout-BRSqi4AQ.js +43 -0
- package/dist/layout-BRSqi4AQ.js.map +1 -0
- package/dist/layout.d.ts +13 -0
- package/dist/list/index.d.ts +2 -0
- package/dist/list/index.js +2 -0
- package/dist/list/list.d.ts +30 -0
- package/dist/list-6-iz-Irh.js +28 -0
- package/dist/list-6-iz-Irh.js.map +1 -0
- package/dist/loading/index.js +45 -2
- package/dist/loading/index.js.map +1 -1
- package/dist/loading/loading.d.ts +45 -2
- package/dist/modal-dialog-machine-CF9_z3Dm.js +487 -0
- package/dist/modal-dialog-machine-CF9_z3Dm.js.map +1 -0
- package/dist/modal-dialog-machine.d.ts +21 -0
- package/dist/modal-dismissable-lifetime.d.ts +21 -0
- package/dist/modal-registry.d.ts +24 -0
- package/dist/modal-render-hydration.d.ts +35 -0
- package/dist/modal-render-runtime.d.ts +19 -0
- package/dist/modal-render-scope.d.ts +63 -0
- package/dist/nav-bar/index.d.ts +1 -0
- package/dist/nav-bar/index.js +115 -0
- package/dist/nav-bar/index.js.map +1 -0
- package/dist/nav-bar/nav-bar.d.ts +76 -0
- package/dist/notice-bar/index.d.ts +2 -0
- package/dist/notice-bar/index.js +2 -0
- package/dist/notice-bar/notice-bar.d.ts +103 -0
- package/dist/notice-bar-DMpwLvRb.js +231 -0
- package/dist/notice-bar-DMpwLvRb.js.map +1 -0
- package/dist/notify/index.d.ts +1 -0
- package/dist/notify/index.js +251 -0
- package/dist/notify/index.js.map +1 -0
- package/dist/notify/notify.d.ts +123 -0
- package/dist/number-keyboard/index.d.ts +1 -0
- package/dist/number-keyboard/index.js +333 -0
- package/dist/number-keyboard/index.js.map +1 -0
- package/dist/number-keyboard/number-keyboard.d.ts +141 -0
- package/dist/overlay-panel/index.d.ts +2 -0
- package/dist/overlay-panel/index.js +2 -0
- package/dist/overlay-panel/overlay-panel.d.ts +20 -0
- package/dist/overlay-panel-Z_qdKeBj.js +26 -0
- package/dist/overlay-panel-Z_qdKeBj.js.map +1 -0
- package/dist/page-indicator/index.d.ts +1 -0
- package/dist/page-indicator/index.js +138 -0
- package/dist/page-indicator/index.js.map +1 -0
- package/dist/page-indicator/page-indicator.d.ts +93 -0
- package/dist/pagination/index.d.ts +1 -0
- package/dist/pagination/index.js +198 -0
- package/dist/pagination/index.js.map +1 -0
- package/dist/pagination/pagination.d.ts +125 -0
- package/dist/password-input/index.d.ts +1 -0
- package/dist/password-input/index.js +317 -0
- package/dist/password-input/index.js.map +1 -0
- package/dist/password-input/password-input.d.ts +144 -0
- package/dist/picker/index.d.ts +8 -0
- package/dist/picker/index.js +2 -0
- package/dist/picker/picker-machine.d.ts +80 -0
- package/dist/picker/picker.d.ts +121 -0
- package/dist/picker/platform.d.ts +84 -0
- package/dist/picker/selection-connect.d.ts +90 -0
- package/dist/picker/selection-model.d.ts +211 -0
- package/dist/picker-BykFntQN.js +1675 -0
- package/dist/picker-BykFntQN.js.map +1 -0
- package/dist/popover/index.d.ts +3 -0
- package/dist/popover/index.js +253 -0
- package/dist/popover/index.js.map +1 -0
- package/dist/popover/layer.d.ts +44 -0
- package/dist/popover/popover.d.ts +104 -0
- package/dist/popover/positioning.d.ts +132 -0
- package/dist/popup/index.d.ts +2 -0
- package/dist/popup/index.js +2 -0
- package/dist/popup/popup.d.ts +60 -0
- package/dist/popup-z5d8IYCt.js +576 -0
- package/dist/popup-z5d8IYCt.js.map +1 -0
- package/dist/portal-BHCNTWhg.js +78 -0
- package/dist/portal-BHCNTWhg.js.map +1 -0
- package/dist/portal.d.ts +61 -0
- package/dist/price/format.d.ts +19 -0
- package/dist/price/index.d.ts +1 -0
- package/dist/price/index.js +154 -0
- package/dist/price/index.js.map +1 -0
- package/dist/price/price.d.ts +88 -0
- package/dist/progress/index.d.ts +1 -0
- package/dist/progress/index.js +2 -0
- package/dist/progress/progress.d.ts +32 -0
- package/dist/progress-f3iYEfdA.js +37 -0
- package/dist/progress-f3iYEfdA.js.map +1 -0
- package/dist/pull-refresh/index.d.ts +1 -0
- package/dist/pull-refresh/index.js +414 -0
- package/dist/pull-refresh/index.js.map +1 -0
- package/dist/pull-refresh/pull-refresh.d.ts +118 -0
- package/dist/radio-group/index.d.ts +3 -0
- package/dist/radio-group/index.js +2 -0
- package/dist/radio-group/radio-group.d.ts +78 -0
- package/dist/radio-group-BOIMuqnS.js +230 -0
- package/dist/radio-group-BOIMuqnS.js.map +1 -0
- package/dist/rate/index.d.ts +1 -0
- package/dist/rate/index.js +2 -0
- package/dist/rate/rate-form.d.ts +28 -0
- package/dist/rate/rate.d.ts +144 -0
- package/dist/rate-5XsU2QkY.js +631 -0
- package/dist/rate-5XsU2QkY.js.map +1 -0
- package/dist/reorder/index.d.ts +1 -0
- package/dist/reorder/index.js +720 -0
- package/dist/reorder/index.js.map +1 -0
- package/dist/reorder/reorder.d.ts +190 -0
- package/dist/result/index.d.ts +1 -0
- package/dist/result/index.js +123 -0
- package/dist/result/index.js.map +1 -0
- package/dist/result/result.d.ts +88 -0
- package/dist/safe-area/index.d.ts +1 -0
- package/dist/safe-area/index.js +42 -0
- package/dist/safe-area/index.js.map +1 -0
- package/dist/safe-area/safe-area.d.ts +28 -0
- package/dist/search-bar/index.js +4 -2
- package/dist/search-bar/index.js.map +1 -1
- package/dist/search-bar/search-bar.d.ts +6 -0
- package/dist/segmented/index.d.ts +2 -0
- package/dist/segmented/index.js +2 -0
- package/dist/segmented/segmented.d.ts +127 -0
- package/dist/segmented-BaU38_L4.js +367 -0
- package/dist/segmented-BaU38_L4.js.map +1 -0
- package/dist/selection-form-BOM_odUk.js +88 -0
- package/dist/selection-form-BOM_odUk.js.map +1 -0
- package/dist/selection-form.d.ts +27 -0
- package/dist/selection-ivXqO1eu.js +55 -0
- package/dist/selection-ivXqO1eu.js.map +1 -0
- package/dist/selection.d.ts +29 -0
- package/dist/selector/choice-group.d.ts +114 -0
- package/dist/selector/index.d.ts +2 -0
- package/dist/selector/index.js +2 -0
- package/dist/selector/selector.d.ts +90 -0
- package/dist/selector-BU2MMJ4N.js +93 -0
- package/dist/selector-BU2MMJ4N.js.map +1 -0
- package/dist/share-sheet/index.d.ts +1 -0
- package/dist/share-sheet/index.js +138 -0
- package/dist/share-sheet/index.js.map +1 -0
- package/dist/share-sheet/share-sheet.d.ts +139 -0
- package/dist/side-nav/index.d.ts +1 -0
- package/dist/side-nav/index.js +99 -0
- package/dist/side-nav/index.js.map +1 -0
- package/dist/side-nav/side-nav.d.ts +94 -0
- package/dist/skeleton/index.js +51 -2
- package/dist/skeleton/index.js.map +1 -1
- package/dist/skeleton/skeleton.d.ts +34 -3
- package/dist/slider/index.d.ts +1 -0
- package/dist/slider/index.js +482 -0
- package/dist/slider/index.js.map +1 -0
- package/dist/slider/slider.d.ts +174 -0
- package/dist/space/index.d.ts +1 -0
- package/dist/space/index.js +52 -0
- package/dist/space/index.js.map +1 -0
- package/dist/space/space.d.ts +46 -0
- package/dist/statistic/index.d.ts +1 -0
- package/dist/statistic/index.js +152 -0
- package/dist/statistic/index.js.map +1 -0
- package/dist/statistic/statistic.d.ts +101 -0
- package/dist/stepper/index.d.ts +1 -0
- package/dist/stepper/index.js +172 -0
- package/dist/stepper/index.js.map +1 -0
- package/dist/stepper/stepper.d.ts +161 -0
- package/dist/steps/index.d.ts +1 -0
- package/dist/steps/index.js +72 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/steps.d.ts +67 -0
- package/dist/sticky/index.d.ts +1 -0
- package/dist/sticky/index.js +145 -0
- package/dist/sticky/index.js.map +1 -0
- package/dist/sticky/sticky.d.ts +70 -0
- package/dist/swipe-action/index.d.ts +1 -0
- package/dist/swipe-action/index.js +417 -0
- package/dist/swipe-action/index.js.map +1 -0
- package/dist/swipe-action/swipe-action.d.ts +148 -0
- package/dist/swiper/gesture.d.ts +32 -0
- package/dist/swiper/index.d.ts +1 -0
- package/dist/swiper/index.js +2 -0
- package/dist/swiper/swiper.d.ts +177 -0
- package/dist/swiper-BKivDkHp.js +550 -0
- package/dist/swiper-BKivDkHp.js.map +1 -0
- package/dist/switch/index.d.ts +1 -0
- package/dist/switch/index.js +168 -0
- package/dist/switch/index.js.map +1 -0
- package/dist/switch/switch.d.ts +142 -0
- package/dist/tabbar/index.d.ts +1 -0
- package/dist/tabbar/index.js +95 -0
- package/dist/tabbar/index.js.map +1 -0
- package/dist/tabbar/tabbar.d.ts +119 -0
- package/dist/tabs/index.js +22 -1
- package/dist/tabs/index.js.map +1 -1
- package/dist/tabs/tabs.d.ts +12 -8
- package/dist/tag/index.js +123 -2
- package/dist/tag/index.js.map +1 -1
- package/dist/tag/tag.d.ts +67 -1
- package/dist/textarea/index.d.ts +2 -0
- package/dist/textarea/index.js +2 -242
- package/dist/textarea/platform.d.ts +22 -0
- package/dist/textarea/textarea.d.ts +169 -46
- package/dist/textarea-qbnruDUG.js +775 -0
- package/dist/textarea-qbnruDUG.js.map +1 -0
- package/dist/time-picker/index.d.ts +1 -0
- package/dist/time-picker/index.js +228 -0
- package/dist/time-picker/index.js.map +1 -0
- package/dist/time-picker/time-picker.d.ts +83 -0
- package/dist/timeline/index.d.ts +1 -0
- package/dist/timeline/index.js +131 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/timeline/timeline.d.ts +79 -0
- package/dist/toast/index.js +47 -4
- package/dist/toast/index.js.map +1 -1
- package/dist/toast/toast.d.ts +26 -3
- package/dist/top-bar/index.js +16 -2
- package/dist/top-bar/index.js.map +1 -1
- package/dist/top-bar/top-bar.d.ts +13 -2
- package/dist/tree-select/index.d.ts +1 -0
- package/dist/tree-select/index.js +512 -0
- package/dist/tree-select/index.js.map +1 -0
- package/dist/tree-select/tree-select.d.ts +215 -0
- package/dist/typography/index.d.ts +1 -0
- package/dist/typography/index.js +82 -0
- package/dist/typography/index.js.map +1 -0
- package/dist/typography/typography.d.ts +54 -0
- package/dist/upload/index.d.ts +1 -0
- package/dist/upload/index.js +458 -0
- package/dist/upload/index.js.map +1 -0
- package/dist/upload/upload.d.ts +172 -0
- package/dist/virtual-list/index.d.ts +1 -0
- package/dist/virtual-list/index.js +445 -0
- package/dist/virtual-list/index.js.map +1 -0
- package/dist/virtual-list/virtual-list.d.ts +160 -0
- package/dist/visual-manifest.d.ts +27 -0
- package/dist/watermark/index.d.ts +1 -0
- package/dist/watermark/index.js +260 -0
- package/dist/watermark/index.js.map +1 -0
- package/dist/watermark/watermark.d.ts +106 -0
- package/package.json +417 -44
- package/dist/empty/index.js.map +0 -1
- package/dist/icon/index.js.map +0 -1
- package/dist/textarea/index.js.map +0 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { type Machine, type Service } from "@zag-js/core";
|
|
2
|
+
import type { NormalizeProps, PropTypes } from "@zag-js/types";
|
|
3
|
+
/** Supported pagination presentations. */
|
|
4
|
+
export declare const PAGINATION_MODES: readonly ["multi", "simple"];
|
|
5
|
+
/** Stable DOM parts shared by all adapters. */
|
|
6
|
+
export declare const PAGINATION_PARTS: readonly ["root", "list", "list-item", "item", "previous", "next", "status"];
|
|
7
|
+
export type PaginationMode = (typeof PAGINATION_MODES)[number];
|
|
8
|
+
/** Navigation request; the owner loads data after receiving it. */
|
|
9
|
+
export interface PaginationPageChangeDetails {
|
|
10
|
+
page: number;
|
|
11
|
+
pageSize: number;
|
|
12
|
+
}
|
|
13
|
+
/** Scalar, SSR-safe paging contract. Labels do not follow lang automatically. */
|
|
14
|
+
export interface QwPaginationProps {
|
|
15
|
+
/** Controlled one-based page. Undefined enables Core-owned state. */
|
|
16
|
+
page?: number;
|
|
17
|
+
/** Initial Core-owned page; defaults to 1. */
|
|
18
|
+
defaultPage?: number;
|
|
19
|
+
/** Total number of records; defaults to 0. */
|
|
20
|
+
count?: number;
|
|
21
|
+
/** Records per page; defaults to 10. */
|
|
22
|
+
pageSize?: number;
|
|
23
|
+
/** Explicit page count overriding count/pageSize. Zero denotes empty. */
|
|
24
|
+
pageCount?: number;
|
|
25
|
+
/** Numbered buttons or compact status; defaults to multi. */
|
|
26
|
+
mode?: PaginationMode;
|
|
27
|
+
/** Pages on each side of the current page; defaults to 1, bounded 0..5. */
|
|
28
|
+
siblingCount?: number;
|
|
29
|
+
/** Pages retained at each boundary; defaults to 1, bounded 0..5. */
|
|
30
|
+
boundaryCount?: number;
|
|
31
|
+
/** Prevent every user and API page request. */
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
/** Standard HTML direction (including auto/empty); previous always decreases the page. */
|
|
34
|
+
dir?: string;
|
|
35
|
+
/** Accessible navigation region name; defaults to 分页导航. */
|
|
36
|
+
navigationLabel?: string;
|
|
37
|
+
/** Previous button label; defaults to 上一页. */
|
|
38
|
+
previousLabel?: string;
|
|
39
|
+
/** Next button label; defaults to 下一页. */
|
|
40
|
+
nextLabel?: string;
|
|
41
|
+
/** Page name with {page}/{count} placeholders; defaults to 第 {page} 页. */
|
|
42
|
+
pageLabelTemplate?: string;
|
|
43
|
+
/** Polite live status template; defaults to 第 {page} / {count} 页. */
|
|
44
|
+
statusLabelTemplate?: string;
|
|
45
|
+
/** Backward page-group jump template; defaults to 向前跳页,目标第 {page} 页. */
|
|
46
|
+
previousJumpLabel?: string;
|
|
47
|
+
/** Forward page-group jump template; defaults to 向后跳页,目标第 {page} 页. */
|
|
48
|
+
nextJumpLabel?: string;
|
|
49
|
+
/** Invoked once for a different enabled page request, including controlled requests. */
|
|
50
|
+
onPageChange?: (details: PaginationPageChangeDetails) => void;
|
|
51
|
+
}
|
|
52
|
+
/** Core-normalized model; empty page count has page 0. */
|
|
53
|
+
export interface ResolvedPaginationState {
|
|
54
|
+
page: number;
|
|
55
|
+
count: number;
|
|
56
|
+
pageSize: number;
|
|
57
|
+
pageCount: number;
|
|
58
|
+
mode: PaginationMode;
|
|
59
|
+
siblingCount: number;
|
|
60
|
+
boundaryCount: number;
|
|
61
|
+
disabled: boolean;
|
|
62
|
+
dir: string | undefined;
|
|
63
|
+
canPrevious: boolean;
|
|
64
|
+
canNext: boolean;
|
|
65
|
+
navigationLabel: string;
|
|
66
|
+
previousLabel: string;
|
|
67
|
+
nextLabel: string;
|
|
68
|
+
pageLabelTemplate: string;
|
|
69
|
+
statusLabelTemplate: string;
|
|
70
|
+
previousJumpLabel: string;
|
|
71
|
+
nextJumpLabel: string;
|
|
72
|
+
}
|
|
73
|
+
/** A numbered button or an executable page-group jump. */
|
|
74
|
+
export interface PaginationItem {
|
|
75
|
+
type: "page" | "ellipsis";
|
|
76
|
+
key: string;
|
|
77
|
+
page: number;
|
|
78
|
+
text: string;
|
|
79
|
+
label: string;
|
|
80
|
+
selected: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** Shared validation: no adapter recomputes boundaries or labels. */
|
|
83
|
+
export declare function resolvePaginationState(props?: QwPaginationProps): ResolvedPaginationState;
|
|
84
|
+
/** Bounded O(window) construction, never allocates a range from the total page count. */
|
|
85
|
+
export declare function getPaginationItems(state: ResolvedPaginationState): PaginationItem[];
|
|
86
|
+
/** Prepare machine props without converting an uncontrolled page into a controlled one. */
|
|
87
|
+
export declare function createPaginationProps(props?: QwPaginationProps): QwPaginationProps;
|
|
88
|
+
export interface QwPaginationSchema {
|
|
89
|
+
props: QwPaginationProps;
|
|
90
|
+
context: {
|
|
91
|
+
page: number;
|
|
92
|
+
};
|
|
93
|
+
state: "ready";
|
|
94
|
+
action: "setPage";
|
|
95
|
+
event: {
|
|
96
|
+
type: "PAGE.SET";
|
|
97
|
+
page: number;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export type QwPaginationMachine = Machine<QwPaginationSchema>;
|
|
101
|
+
export type QwPaginationService = Service<QwPaginationSchema>;
|
|
102
|
+
/** Pure Zag state for both controlled requests and Core-owned paging. */
|
|
103
|
+
export declare const paginationMachine: QwPaginationMachine;
|
|
104
|
+
/** Adapters consume this API without interpreting paging state. */
|
|
105
|
+
export interface QwPaginationApi<T extends PropTypes = PropTypes> {
|
|
106
|
+
page: number;
|
|
107
|
+
pageCount: number;
|
|
108
|
+
pageSize: number;
|
|
109
|
+
items: PaginationItem[];
|
|
110
|
+
statusText: string;
|
|
111
|
+
previousText: string;
|
|
112
|
+
nextText: string;
|
|
113
|
+
setPage(page: number): void;
|
|
114
|
+
previous(): void;
|
|
115
|
+
next(): void;
|
|
116
|
+
getRootProps(): T["element"];
|
|
117
|
+
getListProps(): T["element"];
|
|
118
|
+
getListItemProps(): T["element"];
|
|
119
|
+
getPreviousProps(): T["button"];
|
|
120
|
+
getNextProps(): T["button"];
|
|
121
|
+
getItemProps(item: PaginationItem): T["button"];
|
|
122
|
+
getStatusProps(): T["element"];
|
|
123
|
+
}
|
|
124
|
+
/** Normalize ARIA and native button handlers for all frameworks. */
|
|
125
|
+
export declare function connect<T extends PropTypes>(service: QwPaginationService, normalize: NormalizeProps<T>): QwPaginationApi<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./password-input.js";
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { createMachine } from "@zag-js/core";
|
|
2
|
+
import { addDomEvent, dataAttr, isInputElement } from "@zag-js/dom-query";
|
|
3
|
+
//#region src/password-input/password-input.ts
|
|
4
|
+
/**
|
|
5
|
+
* PasswordInput 密码格 / 验证码:一个真实 `<input>` 承载焦点、选区、粘贴、读屏与表单,
|
|
6
|
+
* 格子只是 `aria-hidden` 的呈现层。
|
|
7
|
+
*
|
|
8
|
+
* Core 持有:长度/字符集归一化、受控提议与拒绝写回、粘贴合并、掩码、选区→高亮格、
|
|
9
|
+
* 一次填满一次 onComplete、表单 reset 恢复默认值。Core 从不提交表单、也不校验验证码。
|
|
10
|
+
*/
|
|
11
|
+
/** Stable DOM parts shared by every adapter. */
|
|
12
|
+
const PASSWORD_INPUT_PARTS = [
|
|
13
|
+
"root",
|
|
14
|
+
"input",
|
|
15
|
+
"cells",
|
|
16
|
+
"cell",
|
|
17
|
+
"hint"
|
|
18
|
+
];
|
|
19
|
+
const PASSWORD_INPUT_DEFAULT_LENGTH = 6;
|
|
20
|
+
/** Inclusive length bounds; out-of-range or non-integer lengths are clamped / rounded down. */
|
|
21
|
+
const PASSWORD_INPUT_MIN_LENGTH = 1;
|
|
22
|
+
const PASSWORD_INPUT_MAX_LENGTH = 12;
|
|
23
|
+
/** Character kept by each charset. Full-width digits/letters are folded to ASCII first. */
|
|
24
|
+
const PASSWORD_INPUT_CHARSETS = ["numeric", "alphanumeric"];
|
|
25
|
+
const PASSWORD_INPUT_MODES = ["password", "otp"];
|
|
26
|
+
/** Decorative glyph drawn in a filled cell while masked. */
|
|
27
|
+
const PASSWORD_INPUT_MASK_GLYPH = "•";
|
|
28
|
+
const DEFAULT_LABEL = {
|
|
29
|
+
password: "密码",
|
|
30
|
+
otp: "验证码"
|
|
31
|
+
};
|
|
32
|
+
const text = (value) => typeof value === "string" ? value.trim() : "";
|
|
33
|
+
/** Clamp to an integer in 1–12; anything unusable falls back to 6. */
|
|
34
|
+
function normalizePasswordInputLength(length) {
|
|
35
|
+
if (typeof length !== "number" || !Number.isFinite(length)) return 6;
|
|
36
|
+
return Math.min(12, Math.max(1, Math.floor(length)));
|
|
37
|
+
}
|
|
38
|
+
/** Fold full-width ASCII (IME digits like "123") to half-width, drop disallowed characters, then truncate. Never throws. */
|
|
39
|
+
function normalizePasswordInputValue(value, length, charset = "numeric") {
|
|
40
|
+
if (typeof value !== "string" && typeof value !== "number") return "";
|
|
41
|
+
const allowed = charset === "alphanumeric" ? /[0-9A-Za-z]/ : /[0-9]/;
|
|
42
|
+
let result = "";
|
|
43
|
+
for (const raw of String(value)) {
|
|
44
|
+
const code = raw.charCodeAt(0), char = code >= 65281 && code <= 65374 ? String.fromCharCode(code - 65248) : raw;
|
|
45
|
+
if (allowed.test(char)) result += char;
|
|
46
|
+
}
|
|
47
|
+
return result.slice(0, normalizePasswordInputLength(length));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Merge pasted text into the current value. A paste that alone fills every cell (after filtering)
|
|
51
|
+
* replaces the whole value — the usual "paste the code from SMS" case; otherwise it replaces the selection.
|
|
52
|
+
* Returns the next value and the caret after the inserted text.
|
|
53
|
+
*/
|
|
54
|
+
function mergePasswordInputPaste(current, pasted, selection, length, charset) {
|
|
55
|
+
const size = normalizePasswordInputLength(length), clean = normalizePasswordInputValue(pasted, 48, charset);
|
|
56
|
+
if (clean.length >= size) return {
|
|
57
|
+
value: clean.slice(0, size),
|
|
58
|
+
caret: size
|
|
59
|
+
};
|
|
60
|
+
const start = Math.max(0, Math.min(selection.start, current.length)), end = Math.max(start, Math.min(selection.end, current.length));
|
|
61
|
+
const value = normalizePasswordInputValue(current.slice(0, start) + clean + current.slice(end), size, charset);
|
|
62
|
+
return {
|
|
63
|
+
value,
|
|
64
|
+
caret: Math.min(value.length, start + clean.length)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function createPasswordInputProps(props = {}) {
|
|
68
|
+
const mode = props.mode === "otp" ? "otp" : "password", charset = props.charset === "alphanumeric" ? "alphanumeric" : "numeric";
|
|
69
|
+
const length = normalizePasswordInputLength(props.length);
|
|
70
|
+
return {
|
|
71
|
+
...props,
|
|
72
|
+
mode,
|
|
73
|
+
charset,
|
|
74
|
+
length,
|
|
75
|
+
mask: typeof props.mask === "boolean" ? props.mask : mode === "password",
|
|
76
|
+
label: text(props.label) || DEFAULT_LABEL[mode],
|
|
77
|
+
hint: text(props.hint) || `${length} 位${charset === "numeric" ? "数字" : "字母或数字"}`,
|
|
78
|
+
autoComplete: props.autoComplete ?? (mode === "otp" ? "one-time-code" : "off"),
|
|
79
|
+
disabled: !!props.disabled,
|
|
80
|
+
readOnly: !!props.readOnly,
|
|
81
|
+
required: !!props.required
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const normalizeWith = (prop, value) => normalizePasswordInputValue(value, prop("length"), prop("charset"));
|
|
85
|
+
const inputId = (id) => `password-input:${id}:input`;
|
|
86
|
+
const hintId = (id) => `password-input:${id}:hint`;
|
|
87
|
+
const passwordInputMachine = createMachine({
|
|
88
|
+
props: ({ props }) => createPasswordInputProps(props),
|
|
89
|
+
initialState: () => "idle",
|
|
90
|
+
context: ({ bindable, prop }) => ({
|
|
91
|
+
value: bindable(() => ({
|
|
92
|
+
defaultValue: normalizeWith(prop, prop("defaultValue") ?? ""),
|
|
93
|
+
value: prop("value") === void 0 ? void 0 : normalizeWith(prop, prop("value")),
|
|
94
|
+
onChange: (value) => prop("onValueChange")?.({ value })
|
|
95
|
+
})),
|
|
96
|
+
selection: bindable(() => ({
|
|
97
|
+
defaultValue: {
|
|
98
|
+
start: 0,
|
|
99
|
+
end: 0
|
|
100
|
+
},
|
|
101
|
+
hash: (value) => `${value.start}:${value.end}`
|
|
102
|
+
})),
|
|
103
|
+
focused: bindable(() => ({ defaultValue: false }))
|
|
104
|
+
}),
|
|
105
|
+
refs: ({ prop }) => ({ completed: normalizeWith(prop, prop("value") ?? prop("defaultValue") ?? "").length === prop("length") }),
|
|
106
|
+
watch({ track, context, prop, action }) {
|
|
107
|
+
track([() => context.get("value"), () => prop("length")], () => action(["notifyComplete"]));
|
|
108
|
+
},
|
|
109
|
+
effects: ["trackForm"],
|
|
110
|
+
on: { "VALUE.SET": { actions: ["setValue"] } },
|
|
111
|
+
states: { idle: {} },
|
|
112
|
+
implementations: {
|
|
113
|
+
actions: {
|
|
114
|
+
setValue({ event, context, prop }) {
|
|
115
|
+
if (prop("disabled") || prop("readOnly")) return;
|
|
116
|
+
context.set("value", normalizeWith(prop, event.value));
|
|
117
|
+
},
|
|
118
|
+
notifyComplete({ context, prop, refs }) {
|
|
119
|
+
const value = context.get("value"), full = value.length === prop("length");
|
|
120
|
+
if (full && !refs.get("completed")) {
|
|
121
|
+
refs.set("completed", true);
|
|
122
|
+
prop("onComplete")?.({ value });
|
|
123
|
+
} else if (!full) refs.set("completed", false);
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
effects: {
|
|
127
|
+
/**
|
|
128
|
+
* Form reset. Reset does not bubble, so listen in the document capture phase and match the input's current form owner:
|
|
129
|
+
* re-parenting, the form attribute and re-rendered inputs need no rebinding. Native reset runs after listeners, so the
|
|
130
|
+
* default is restored on the next task.
|
|
131
|
+
*/
|
|
132
|
+
trackForm({ scope, context, prop }) {
|
|
133
|
+
const doc = scope.getDoc();
|
|
134
|
+
let stopped = false;
|
|
135
|
+
const timers = /* @__PURE__ */ new Set();
|
|
136
|
+
const release = addDomEvent(doc, "reset", (event) => {
|
|
137
|
+
const input = scope.getById(inputId(scope.id ?? ""));
|
|
138
|
+
if (!isInputElement(input) || !input.form || event.target !== input.form) return;
|
|
139
|
+
const timer = setTimeout(() => {
|
|
140
|
+
timers.delete(timer);
|
|
141
|
+
if (stopped || event.defaultPrevented) return;
|
|
142
|
+
context.set("value", normalizeWith(prop, prop("defaultValue") ?? ""));
|
|
143
|
+
if (input.isConnected) input.value = context.get("value");
|
|
144
|
+
}, 0);
|
|
145
|
+
timers.add(timer);
|
|
146
|
+
}, true);
|
|
147
|
+
return () => {
|
|
148
|
+
stopped = true;
|
|
149
|
+
release();
|
|
150
|
+
timers.forEach(clearTimeout);
|
|
151
|
+
timers.clear();
|
|
152
|
+
};
|
|
153
|
+
} }
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
const field = (event) => event.currentTarget ?? event.target;
|
|
157
|
+
const place = (target, caret) => {
|
|
158
|
+
try {
|
|
159
|
+
target.setSelectionRange?.(caret, caret);
|
|
160
|
+
} catch {}
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Caret semantics: the real input owns caret and selection; arrows, Home/End, Backspace/Delete and shift-selection are native.
|
|
164
|
+
* The visual caret cell follows selectionStart (clamped to the last cell when full); a non-collapsed selection marks its cells.
|
|
165
|
+
* A plain tap/click collapses the caret to the end of the value, because input text geometry does not line up with the cells.
|
|
166
|
+
*/
|
|
167
|
+
function connectPasswordInput(service, normalize) {
|
|
168
|
+
const { context, prop, send, scope } = service;
|
|
169
|
+
const value = context.get("value"), length = prop("length") ?? 6, masked = !!prop("mask"), focused = context.get("focused");
|
|
170
|
+
const disabled = !!prop("disabled"), readOnly = !!prop("readOnly"), locked = disabled || readOnly, selection = context.get("selection");
|
|
171
|
+
const label = prop("label") || DEFAULT_LABEL[prop("mode") ?? "password"], hint = prop("hint") ?? "";
|
|
172
|
+
const id = scope.id ?? "";
|
|
173
|
+
const part = (name) => ({
|
|
174
|
+
"data-scope": "password-input",
|
|
175
|
+
"data-part": name
|
|
176
|
+
});
|
|
177
|
+
const ranged = selection.end > selection.start, caretIndex = Math.min(selection.start, length - 1);
|
|
178
|
+
const cells = Array.from({ length }, (_, index) => {
|
|
179
|
+
const char = value[index] ?? "";
|
|
180
|
+
return {
|
|
181
|
+
index,
|
|
182
|
+
char,
|
|
183
|
+
display: char ? masked ? "•" : char : "",
|
|
184
|
+
filled: !!char,
|
|
185
|
+
caret: focused && !disabled && !ranged && index === caretIndex,
|
|
186
|
+
selected: focused && ranged && index >= selection.start && index < selection.end
|
|
187
|
+
};
|
|
188
|
+
});
|
|
189
|
+
const select = (start, end) => {
|
|
190
|
+
const from = Math.max(0, start), current = context.get("selection"), to = Math.max(from, end);
|
|
191
|
+
if (current.start !== from || current.end !== to) context.set("selection", {
|
|
192
|
+
start: from,
|
|
193
|
+
end: to
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
const track = (event) => {
|
|
197
|
+
const target = field(event), start = target.selectionStart ?? target.value.length;
|
|
198
|
+
select(start, target.selectionEnd ?? start);
|
|
199
|
+
};
|
|
200
|
+
/** Propose, then write the effective value back so a rejected or filtered edit never lingers in the DOM. */
|
|
201
|
+
const commit = (target, proposed, caret) => {
|
|
202
|
+
if (!locked) context.set("value", proposed);
|
|
203
|
+
const accepted = context.get("value");
|
|
204
|
+
if (target.value !== accepted) {
|
|
205
|
+
target.value = accepted;
|
|
206
|
+
place(target, Math.min(caret, accepted.length));
|
|
207
|
+
}
|
|
208
|
+
select(target.selectionStart ?? accepted.length, target.selectionEnd ?? accepted.length);
|
|
209
|
+
queueMicrotask(() => {
|
|
210
|
+
if (target.isConnected !== false && target.value !== context.get("value")) {
|
|
211
|
+
target.value = context.get("value");
|
|
212
|
+
place(target, context.get("value").length);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
return {
|
|
217
|
+
value,
|
|
218
|
+
length,
|
|
219
|
+
masked,
|
|
220
|
+
focused,
|
|
221
|
+
complete: value.length === length,
|
|
222
|
+
disabled,
|
|
223
|
+
readOnly,
|
|
224
|
+
label,
|
|
225
|
+
hint,
|
|
226
|
+
cells,
|
|
227
|
+
setValue: (next) => send({
|
|
228
|
+
type: "VALUE.SET",
|
|
229
|
+
value: next
|
|
230
|
+
}),
|
|
231
|
+
clear: () => send({
|
|
232
|
+
type: "VALUE.SET",
|
|
233
|
+
value: ""
|
|
234
|
+
}),
|
|
235
|
+
getRootProps: () => normalize.element({
|
|
236
|
+
...part("root"),
|
|
237
|
+
"data-disabled": dataAttr(disabled),
|
|
238
|
+
"data-readonly": dataAttr(readOnly),
|
|
239
|
+
"data-focused": dataAttr(focused),
|
|
240
|
+
"data-complete": dataAttr(value.length === length),
|
|
241
|
+
"data-masked": dataAttr(masked)
|
|
242
|
+
}),
|
|
243
|
+
getInputProps: () => normalize.input({
|
|
244
|
+
...part("input"),
|
|
245
|
+
id: inputId(id),
|
|
246
|
+
type: masked ? "password" : "text",
|
|
247
|
+
value,
|
|
248
|
+
name: prop("name"),
|
|
249
|
+
form: prop("form"),
|
|
250
|
+
disabled,
|
|
251
|
+
readOnly,
|
|
252
|
+
required: prop("required"),
|
|
253
|
+
maxLength: length,
|
|
254
|
+
pattern: `${prop("charset") === "alphanumeric" ? "[0-9A-Za-z]" : "[0-9]"}{${length}}`,
|
|
255
|
+
inputMode: prop("charset") === "numeric" ? "numeric" : "text",
|
|
256
|
+
autoComplete: prop("autoComplete"),
|
|
257
|
+
enterKeyHint: prop("enterKeyHint"),
|
|
258
|
+
autoCapitalize: "off",
|
|
259
|
+
autoCorrect: "off",
|
|
260
|
+
spellCheck: "false",
|
|
261
|
+
"aria-label": label,
|
|
262
|
+
"aria-describedby": hintId(id),
|
|
263
|
+
onChange(event) {
|
|
264
|
+
const target = field(event), caret = target.selectionStart ?? target.value.length;
|
|
265
|
+
if (locked) {
|
|
266
|
+
commit(target, context.get("value"), caret);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
commit(target, normalizeWith(prop, target.value), normalizeWith(prop, target.value.slice(0, caret)).length);
|
|
270
|
+
},
|
|
271
|
+
onPaste(event) {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
if (locked) return;
|
|
274
|
+
const target = field(event), start = target.selectionStart ?? value.length;
|
|
275
|
+
const merged = mergePasswordInputPaste(context.get("value"), event.clipboardData?.getData("text") ?? "", {
|
|
276
|
+
start,
|
|
277
|
+
end: target.selectionEnd ?? start
|
|
278
|
+
}, length, prop("charset"));
|
|
279
|
+
commit(target, merged.value, merged.caret);
|
|
280
|
+
},
|
|
281
|
+
onClick(event) {
|
|
282
|
+
const target = field(event);
|
|
283
|
+
if (target.selectionStart === target.selectionEnd) place(target, target.value.length);
|
|
284
|
+
track(event);
|
|
285
|
+
},
|
|
286
|
+
onKeyUp: track,
|
|
287
|
+
onSelect: track,
|
|
288
|
+
onFocus(event) {
|
|
289
|
+
context.set("focused", true);
|
|
290
|
+
track(event);
|
|
291
|
+
},
|
|
292
|
+
onBlur() {
|
|
293
|
+
context.set("focused", false);
|
|
294
|
+
}
|
|
295
|
+
}),
|
|
296
|
+
getCellsProps: () => normalize.element({
|
|
297
|
+
...part("cells"),
|
|
298
|
+
"aria-hidden": "true"
|
|
299
|
+
}),
|
|
300
|
+
getCellProps: (cell) => normalize.element({
|
|
301
|
+
...part("cell"),
|
|
302
|
+
"data-index": cell.index,
|
|
303
|
+
"data-filled": dataAttr(cell.filled),
|
|
304
|
+
"data-caret": dataAttr(cell.caret),
|
|
305
|
+
"data-selected": dataAttr(cell.selected),
|
|
306
|
+
"data-disabled": dataAttr(disabled)
|
|
307
|
+
}),
|
|
308
|
+
getHintProps: () => normalize.element({
|
|
309
|
+
...part("hint"),
|
|
310
|
+
id: hintId(id)
|
|
311
|
+
})
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
export { PASSWORD_INPUT_CHARSETS, PASSWORD_INPUT_DEFAULT_LENGTH, PASSWORD_INPUT_MASK_GLYPH, PASSWORD_INPUT_MAX_LENGTH, PASSWORD_INPUT_MIN_LENGTH, PASSWORD_INPUT_MODES, PASSWORD_INPUT_PARTS, connectPasswordInput, createPasswordInputProps, mergePasswordInputPaste, normalizePasswordInputLength, normalizePasswordInputValue, passwordInputMachine };
|
|
316
|
+
|
|
317
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/password-input/password-input.ts"],"sourcesContent":["import { createMachine, type Machine, type Service } from \"@zag-js/core\";\nimport { addDomEvent, dataAttr, isInputElement } from \"@zag-js/dom-query\";\nimport type { NormalizeProps, PropTypes } from \"@zag-js/types\";\n\n/**\n * PasswordInput 密码格 / 验证码:一个真实 `<input>` 承载焦点、选区、粘贴、读屏与表单,\n * 格子只是 `aria-hidden` 的呈现层。\n *\n * Core 持有:长度/字符集归一化、受控提议与拒绝写回、粘贴合并、掩码、选区→高亮格、\n * 一次填满一次 onComplete、表单 reset 恢复默认值。Core 从不提交表单、也不校验验证码。\n */\n\n/** Stable DOM parts shared by every adapter. */\nexport const PASSWORD_INPUT_PARTS = [\"root\", \"input\", \"cells\", \"cell\", \"hint\"] as const;\nexport const PASSWORD_INPUT_DEFAULT_LENGTH = 6;\n/** Inclusive length bounds; out-of-range or non-integer lengths are clamped / rounded down. */\nexport const PASSWORD_INPUT_MIN_LENGTH = 1;\nexport const PASSWORD_INPUT_MAX_LENGTH = 12;\n/** Character kept by each charset. Full-width digits/letters are folded to ASCII first. */\nexport const PASSWORD_INPUT_CHARSETS = [\"numeric\", \"alphanumeric\"] as const;\nexport const PASSWORD_INPUT_MODES = [\"password\", \"otp\"] as const;\n/** Decorative glyph drawn in a filled cell while masked. */\nexport const PASSWORD_INPUT_MASK_GLYPH = \"•\";\n\nexport type PasswordInputPart = (typeof PASSWORD_INPUT_PARTS)[number];\nexport type PasswordInputCharset = (typeof PASSWORD_INPUT_CHARSETS)[number];\nexport type PasswordInputMode = (typeof PASSWORD_INPUT_MODES)[number];\nexport type PasswordInputAutoComplete = \"off\" | \"one-time-code\" | \"current-password\" | \"new-password\";\nexport interface PasswordInputValueChangeDetails { value: string }\nexport interface PasswordInputCompleteDetails { value: string }\n/** One presentational cell. `char` is the real character; adapters render `display`. */\nexport interface PasswordInputCell { index: number; char: string; display: string; filled: boolean; caret: boolean; selected: boolean }\n\nexport interface QwPasswordInputProps {\n /** Instance identity; adapters generate one when omitted. */\n id?: string;\n /** Number of cells; integer 1–12, default 6. */\n length?: number;\n /** Controlled value. Edits are proposed through onValueChange; the shown value only changes when the owner accepts. */\n value?: string;\n /** Uncontrolled initial value, also the value a form reset restores. Default \"\". */\n defaultValue?: string;\n /** Proposed value after an edit, paste or reset (already filtered and truncated). */\n onValueChange?: (details: PasswordInputValueChangeDetails) => void;\n /** The effective value just became full. Fires once per fill; never submits or verifies anything. */\n onComplete?: (details: PasswordInputCompleteDetails) => void;\n /** Allowed characters: numeric (default) keeps 0–9, alphanumeric keeps A–Z/a–z/0–9. */\n charset?: PasswordInputCharset;\n /** password (default) masks by default and turns autofill off; otp shows plain text and asks for one-time-code autofill. */\n mode?: PasswordInputMode;\n /** Draw dots instead of characters; the real input becomes type=\"password\". Default: true for password, false for otp. */\n mask?: boolean;\n /** Overrides the autocomplete token chosen by mode. */\n autoComplete?: PasswordInputAutoComplete;\n /** Accessible name of the real input; defaults to 密码 / 验证码 by mode. */\n label?: string;\n /** Spoken length description; defaults to \"6 位数字\" / \"6 位字母或数字\". */\n hint?: string;\n disabled?: boolean;\n readOnly?: boolean;\n required?: boolean;\n /** Form field name; the real input submits the value under it. */\n name?: string;\n /** Owner form id, as the native form attribute. */\n form?: string;\n enterKeyHint?: \"done\" | \"go\" | \"next\" | \"send\" | \"enter\";\n}\n\nconst DEFAULT_LABEL: Record<PasswordInputMode, string> = { password: \"密码\", otp: \"验证码\" };\nconst text = (value: unknown): string => (typeof value === \"string\" ? value.trim() : \"\");\n\n/** Clamp to an integer in 1–12; anything unusable falls back to 6. */\nexport function normalizePasswordInputLength(length?: number): number {\n if (typeof length !== \"number\" || !Number.isFinite(length)) return PASSWORD_INPUT_DEFAULT_LENGTH;\n return Math.min(PASSWORD_INPUT_MAX_LENGTH, Math.max(PASSWORD_INPUT_MIN_LENGTH, Math.floor(length)));\n}\n\n/** Fold full-width ASCII (IME digits like \"123\") to half-width, drop disallowed characters, then truncate. Never throws. */\nexport function normalizePasswordInputValue(value: unknown, length?: number, charset: PasswordInputCharset = \"numeric\"): string {\n if (typeof value !== \"string\" && typeof value !== \"number\") return \"\";\n const allowed = charset === \"alphanumeric\" ? /[0-9A-Za-z]/ : /[0-9]/;\n let result = \"\";\n for (const raw of String(value)) {\n const code = raw.charCodeAt(0), char = code >= 0xff01 && code <= 0xff5e ? String.fromCharCode(code - 0xfee0) : raw;\n if (allowed.test(char)) result += char;\n }\n return result.slice(0, normalizePasswordInputLength(length));\n}\n\n/**\n * Merge pasted text into the current value. A paste that alone fills every cell (after filtering)\n * replaces the whole value — the usual \"paste the code from SMS\" case; otherwise it replaces the selection.\n * Returns the next value and the caret after the inserted text.\n */\nexport function mergePasswordInputPaste(current: string, pasted: string, selection: { start: number; end: number }, length?: number, charset?: PasswordInputCharset): { value: string; caret: number } {\n const size = normalizePasswordInputLength(length), clean = normalizePasswordInputValue(pasted, PASSWORD_INPUT_MAX_LENGTH * 4, charset);\n if (clean.length >= size) return { value: clean.slice(0, size), caret: size };\n const start = Math.max(0, Math.min(selection.start, current.length)), end = Math.max(start, Math.min(selection.end, current.length));\n const value = normalizePasswordInputValue(current.slice(0, start) + clean + current.slice(end), size, charset);\n return { value, caret: Math.min(value.length, start + clean.length) };\n}\n\nexport function createPasswordInputProps(props: QwPasswordInputProps = {}): QwPasswordInputProps {\n const mode: PasswordInputMode = props.mode === \"otp\" ? \"otp\" : \"password\", charset: PasswordInputCharset = props.charset === \"alphanumeric\" ? \"alphanumeric\" : \"numeric\";\n const length = normalizePasswordInputLength(props.length);\n return {\n ...props, mode, charset, length,\n mask: typeof props.mask === \"boolean\" ? props.mask : mode === \"password\",\n label: text(props.label) || DEFAULT_LABEL[mode],\n hint: text(props.hint) || `${length} 位${charset === \"numeric\" ? \"数字\" : \"字母或数字\"}`,\n autoComplete: props.autoComplete ?? (mode === \"otp\" ? \"one-time-code\" : \"off\"),\n disabled: !!props.disabled, readOnly: !!props.readOnly, required: !!props.required,\n };\n}\n\ninterface Selection { start: number; end: number }\nexport interface QwPasswordInputSchema {\n props: QwPasswordInputProps;\n context: { value: string; selection: Selection; focused: boolean };\n refs: { completed: boolean };\n state: \"idle\";\n action: \"setValue\" | \"notifyComplete\";\n effect: \"trackForm\";\n /** Programmatic proposal (api.setValue / clear). DOM handlers write context synchronously instead. */\n event: { type: \"VALUE.SET\"; value: string };\n}\nexport type QwPasswordInputMachine = Machine<QwPasswordInputSchema>;\nexport type QwPasswordInputService = Service<QwPasswordInputSchema>;\n\nconst normalizeWith = (prop: QwPasswordInputService[\"prop\"], value: unknown) => normalizePasswordInputValue(value, prop(\"length\"), prop(\"charset\"));\nconst inputId = (id: string) => `password-input:${id}:input`;\nconst hintId = (id: string) => `password-input:${id}:hint`;\n\nexport const passwordInputMachine: QwPasswordInputMachine = createMachine<QwPasswordInputSchema>({\n props: ({ props }) => createPasswordInputProps(props),\n initialState: () => \"idle\",\n context: ({ bindable, prop }) => ({\n value: bindable(() => ({\n defaultValue: normalizeWith(prop, prop(\"defaultValue\") ?? \"\"),\n value: prop(\"value\") === undefined ? undefined : normalizeWith(prop, prop(\"value\")),\n onChange: (value) => prop(\"onValueChange\")?.({ value }),\n })),\n selection: bindable<Selection>(() => ({ defaultValue: { start: 0, end: 0 }, hash: (value) => `${value.start}:${value.end}` })),\n focused: bindable(() => ({ defaultValue: false })),\n }),\n // A value that is already full on mount is not a fresh completion.\n refs: ({ prop }) => ({ completed: normalizeWith(prop, prop(\"value\") ?? prop(\"defaultValue\") ?? \"\").length === prop(\"length\") }),\n watch({ track, context, prop, action }) {\n track([() => context.get(\"value\"), () => prop(\"length\")], () => action([\"notifyComplete\"]));\n },\n effects: [\"trackForm\"],\n on: { \"VALUE.SET\": { actions: [\"setValue\"] } },\n states: { idle: {} },\n implementations: {\n actions: {\n setValue({ event, context, prop }) {\n if (prop(\"disabled\") || prop(\"readOnly\")) return;\n context.set(\"value\", normalizeWith(prop, event.value));\n },\n notifyComplete({ context, prop, refs }) {\n const value = context.get(\"value\"), full = value.length === prop(\"length\");\n if (full && !refs.get(\"completed\")) { refs.set(\"completed\", true); prop(\"onComplete\")?.({ value }); } else if (!full) refs.set(\"completed\", false);\n },\n },\n effects: {\n /**\n * Form reset. Reset does not bubble, so listen in the document capture phase and match the input's current form owner:\n * re-parenting, the form attribute and re-rendered inputs need no rebinding. Native reset runs after listeners, so the\n * default is restored on the next task.\n */\n trackForm({ scope, context, prop }) {\n const doc = scope.getDoc();\n let stopped = false;\n const timers = new Set<ReturnType<typeof setTimeout>>();\n const release = addDomEvent(doc, \"reset\", (event) => {\n const input = scope.getById<HTMLInputElement>(inputId(scope.id ?? \"\"));\n if (!isInputElement(input) || !input.form || event.target !== input.form) return;\n const timer = setTimeout(() => {\n timers.delete(timer);\n if (stopped || event.defaultPrevented) return;\n // Reset is a form operation, not a user edit: like native reset it restores the default even when disabled or readOnly.\n context.set(\"value\", normalizeWith(prop, prop(\"defaultValue\") ?? \"\"));\n // Write the effective value back: a rejected controlled reset or an unchanged default must not keep the browser's reset text.\n if (input.isConnected) input.value = context.get(\"value\");\n }, 0);\n timers.add(timer);\n }, true);\n return () => { stopped = true; release(); timers.forEach(clearTimeout); timers.clear(); };\n },\n },\n },\n});\n\nexport interface QwPasswordInputApi<T extends PropTypes = PropTypes> {\n value: string;\n length: number;\n masked: boolean;\n focused: boolean;\n complete: boolean;\n disabled: boolean;\n readOnly: boolean;\n label: string;\n hint: string;\n cells: PasswordInputCell[];\n /** Propose a value programmatically (normalized; ignored when disabled or readOnly). */\n setValue(value: string): void;\n /** Propose \"\" (ignored when disabled or readOnly). */\n clear(): void;\n getRootProps(): T[\"element\"];\n getInputProps(): T[\"input\"];\n getCellsProps(): T[\"element\"];\n getCellProps(cell: PasswordInputCell): T[\"element\"];\n getHintProps(): T[\"element\"];\n}\n\ninterface FieldTarget { value: string; selectionStart: number | null; selectionEnd: number | null; isConnected?: boolean; setSelectionRange?(start: number, end: number): void }\ninterface FieldEvent { currentTarget?: unknown; target?: unknown }\ninterface PasteEvent extends FieldEvent { clipboardData?: { getData(type: string): string } | null; preventDefault(): void }\nconst field = (event: FieldEvent): FieldTarget => (event.currentTarget ?? event.target) as FieldTarget;\nconst place = (target: FieldTarget, caret: number) => { try { target.setSelectionRange?.(caret, caret); } catch { /* Detached or non-text input. */ } };\n\n/**\n * Caret semantics: the real input owns caret and selection; arrows, Home/End, Backspace/Delete and shift-selection are native.\n * The visual caret cell follows selectionStart (clamped to the last cell when full); a non-collapsed selection marks its cells.\n * A plain tap/click collapses the caret to the end of the value, because input text geometry does not line up with the cells.\n */\nexport function connectPasswordInput<T extends PropTypes>(service: QwPasswordInputService, normalize: NormalizeProps<T>): QwPasswordInputApi<T> {\n const { context, prop, send, scope } = service;\n const value = context.get(\"value\"), length = prop(\"length\") ?? PASSWORD_INPUT_DEFAULT_LENGTH, masked = !!prop(\"mask\"), focused = context.get(\"focused\");\n const disabled = !!prop(\"disabled\"), readOnly = !!prop(\"readOnly\"), locked = disabled || readOnly, selection = context.get(\"selection\");\n const label = prop(\"label\") || DEFAULT_LABEL[prop(\"mode\") ?? \"password\"], hint = prop(\"hint\") ?? \"\";\n const id = scope.id ?? \"\";\n const part = (name: PasswordInputPart) => ({ \"data-scope\": \"password-input\", \"data-part\": name });\n const ranged = selection.end > selection.start, caretIndex = Math.min(selection.start, length - 1);\n const cells = Array.from({ length }, (_, index): PasswordInputCell => {\n const char = value[index] ?? \"\";\n return { index, char, display: char ? (masked ? PASSWORD_INPUT_MASK_GLYPH : char) : \"\", filled: !!char, caret: focused && !disabled && !ranged && index === caretIndex, selected: focused && ranged && index >= selection.start && index < selection.end };\n });\n // Handlers write context synchronously (as Input does): adapter sends are deferred, but write-back must see the accepted value now.\n const select = (start: number, end: number) => { const from = Math.max(0, start), current = context.get(\"selection\"), to = Math.max(from, end); if (current.start !== from || current.end !== to) context.set(\"selection\", { start: from, end: to }); };\n const track = (event: FieldEvent) => { const target = field(event), start = target.selectionStart ?? target.value.length; select(start, target.selectionEnd ?? start); };\n /** Propose, then write the effective value back so a rejected or filtered edit never lingers in the DOM. */\n const commit = (target: FieldTarget, proposed: string, caret: number) => {\n if (!locked) context.set(\"value\", proposed);\n const accepted = context.get(\"value\");\n if (target.value !== accepted) { target.value = accepted; place(target, Math.min(caret, accepted.length)); }\n select(target.selectionStart ?? accepted.length, target.selectionEnd ?? accepted.length);\n queueMicrotask(() => { if (target.isConnected !== false && target.value !== context.get(\"value\")) { target.value = context.get(\"value\"); place(target, context.get(\"value\").length); } });\n };\n return {\n value, length, masked, focused, complete: value.length === length, disabled, readOnly, label, hint, cells,\n setValue: (next) => send({ type: \"VALUE.SET\", value: next }),\n clear: () => send({ type: \"VALUE.SET\", value: \"\" }),\n getRootProps: () => normalize.element({ ...part(\"root\"), \"data-disabled\": dataAttr(disabled), \"data-readonly\": dataAttr(readOnly), \"data-focused\": dataAttr(focused), \"data-complete\": dataAttr(value.length === length), \"data-masked\": dataAttr(masked) }),\n getInputProps: () => normalize.input({\n ...part(\"input\"), id: inputId(id), type: masked ? \"password\" : \"text\", value, name: prop(\"name\"), form: prop(\"form\"),\n disabled, readOnly, required: prop(\"required\"), maxLength: length, pattern: `${prop(\"charset\") === \"alphanumeric\" ? \"[0-9A-Za-z]\" : \"[0-9]\"}{${length}}`,\n inputMode: prop(\"charset\") === \"numeric\" ? \"numeric\" : \"text\", autoComplete: prop(\"autoComplete\"), enterKeyHint: prop(\"enterKeyHint\"),\n autoCapitalize: \"off\", autoCorrect: \"off\", spellCheck: \"false\", \"aria-label\": label, \"aria-describedby\": hintId(id),\n onChange(event: FieldEvent) {\n const target = field(event), caret = target.selectionStart ?? target.value.length;\n if (locked) { commit(target, context.get(\"value\"), caret); return; }\n commit(target, normalizeWith(prop, target.value), normalizeWith(prop, target.value.slice(0, caret)).length);\n },\n onPaste(event: PasteEvent) {\n event.preventDefault();\n if (locked) return;\n const target = field(event), start = target.selectionStart ?? value.length;\n const merged = mergePasswordInputPaste(context.get(\"value\"), event.clipboardData?.getData(\"text\") ?? \"\", { start, end: target.selectionEnd ?? start }, length, prop(\"charset\"));\n commit(target, merged.value, merged.caret);\n },\n onClick(event: FieldEvent) {\n const target = field(event);\n if (target.selectionStart === target.selectionEnd) place(target, target.value.length);\n track(event);\n },\n onKeyUp: track, onSelect: track,\n onFocus(event: FieldEvent) { context.set(\"focused\", true); track(event); },\n onBlur() { context.set(\"focused\", false); },\n }),\n getCellsProps: () => normalize.element({ ...part(\"cells\"), \"aria-hidden\": \"true\" }),\n getCellProps: (cell) => normalize.element({ ...part(\"cell\"), \"data-index\": cell.index, \"data-filled\": dataAttr(cell.filled), \"data-caret\": dataAttr(cell.caret), \"data-selected\": dataAttr(cell.selected), \"data-disabled\": dataAttr(disabled) }),\n getHintProps: () => normalize.element({ ...part(\"hint\"), id: hintId(id) }),\n };\n}\n"],"mappings":";;;;;;;;;;;AAaA,MAAa,uBAAuB;CAAC;CAAQ;CAAS;CAAS;CAAQ;AAAM;AAC7E,MAAa,gCAAgC;;AAE7C,MAAa,4BAA4B;AACzC,MAAa,4BAA4B;;AAEzC,MAAa,0BAA0B,CAAC,WAAW,cAAc;AACjE,MAAa,uBAAuB,CAAC,YAAY,KAAK;;AAEtD,MAAa,4BAA4B;AA8CzC,MAAM,gBAAmD;CAAE,UAAU;CAAM,KAAK;AAAM;AACtF,MAAM,QAAQ,UAA4B,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;;AAGrF,SAAgB,6BAA6B,QAAyB;CACpE,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,GAAG,OAAA;CAC5D,OAAO,KAAK,IAAA,IAA+B,KAAK,IAAA,GAA+B,KAAK,MAAM,MAAM,CAAC,CAAC;AACpG;;AAGA,SAAgB,4BAA4B,OAAgB,QAAiB,UAAgC,WAAmB;CAC9H,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU,OAAO;CACnE,MAAM,UAAU,YAAY,iBAAiB,gBAAgB;CAC7D,IAAI,SAAS;CACb,KAAK,MAAM,OAAO,OAAO,KAAK,GAAG;EAC/B,MAAM,OAAO,IAAI,WAAW,CAAC,GAAG,OAAO,QAAQ,SAAU,QAAQ,QAAS,OAAO,aAAa,OAAO,KAAM,IAAI;EAC/G,IAAI,QAAQ,KAAK,IAAI,GAAG,UAAU;CACpC;CACA,OAAO,OAAO,MAAM,GAAG,6BAA6B,MAAM,CAAC;AAC7D;;;;;;AAOA,SAAgB,wBAAwB,SAAiB,QAAgB,WAA2C,QAAiB,SAAkE;CACrM,MAAM,OAAO,6BAA6B,MAAM,GAAG,QAAQ,4BAA4B,QAAA,IAAuC,OAAO;CACrI,IAAI,MAAM,UAAU,MAAM,OAAO;EAAE,OAAO,MAAM,MAAM,GAAG,IAAI;EAAG,OAAO;CAAK;CAC5E,MAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,OAAO,QAAQ,MAAM,CAAC,GAAG,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI,UAAU,KAAK,QAAQ,MAAM,CAAC;CACnI,MAAM,QAAQ,4BAA4B,QAAQ,MAAM,GAAG,KAAK,IAAI,QAAQ,QAAQ,MAAM,GAAG,GAAG,MAAM,OAAO;CAC7G,OAAO;EAAE;EAAO,OAAO,KAAK,IAAI,MAAM,QAAQ,QAAQ,MAAM,MAAM;CAAE;AACtE;AAEA,SAAgB,yBAAyB,QAA8B,CAAC,GAAyB;CAC/F,MAAM,OAA0B,MAAM,SAAS,QAAQ,QAAQ,YAAY,UAAgC,MAAM,YAAY,iBAAiB,iBAAiB;CAC/J,MAAM,SAAS,6BAA6B,MAAM,MAAM;CACxD,OAAO;EACL,GAAG;EAAO;EAAM;EAAS;EACzB,MAAM,OAAO,MAAM,SAAS,YAAY,MAAM,OAAO,SAAS;EAC9D,OAAO,KAAK,MAAM,KAAK,KAAK,cAAc;EAC1C,MAAM,KAAK,MAAM,IAAI,KAAK,GAAG,OAAO,IAAI,YAAY,YAAY,OAAO;EACvE,cAAc,MAAM,iBAAiB,SAAS,QAAQ,kBAAkB;EACxE,UAAU,CAAC,CAAC,MAAM;EAAU,UAAU,CAAC,CAAC,MAAM;EAAU,UAAU,CAAC,CAAC,MAAM;CAC5E;AACF;AAgBA,MAAM,iBAAiB,MAAsC,UAAmB,4BAA4B,OAAO,KAAK,QAAQ,GAAG,KAAK,SAAS,CAAC;AAClJ,MAAM,WAAW,OAAe,kBAAkB,GAAG;AACrD,MAAM,UAAU,OAAe,kBAAkB,GAAG;AAEpD,MAAa,uBAA+C,cAAqC;CAC/F,QAAQ,EAAE,YAAY,yBAAyB,KAAK;CACpD,oBAAoB;CACpB,UAAU,EAAE,UAAU,YAAY;EAChC,OAAO,gBAAgB;GACrB,cAAc,cAAc,MAAM,KAAK,cAAc,KAAK,EAAE;GAC5D,OAAO,KAAK,OAAO,MAAM,KAAA,IAAY,KAAA,IAAY,cAAc,MAAM,KAAK,OAAO,CAAC;GAClF,WAAW,UAAU,KAAK,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC;EACxD,EAAE;EACF,WAAW,gBAA2B;GAAE,cAAc;IAAE,OAAO;IAAG,KAAK;GAAE;GAAG,OAAO,UAAU,GAAG,MAAM,MAAM,GAAG,MAAM;EAAM,EAAE;EAC7H,SAAS,gBAAgB,EAAE,cAAc,MAAM,EAAE;CACnD;CAEA,OAAO,EAAE,YAAY,EAAE,WAAW,cAAc,MAAM,KAAK,OAAO,KAAK,KAAK,cAAc,KAAK,EAAE,CAAC,CAAC,WAAW,KAAK,QAAQ,EAAE;CAC7H,MAAM,EAAE,OAAO,SAAS,MAAM,UAAU;EACtC,MAAM,OAAO,QAAQ,IAAI,OAAO,SAAS,KAAK,QAAQ,CAAC,SAAS,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC5F;CACA,SAAS,CAAC,WAAW;CACrB,IAAI,EAAE,aAAa,EAAE,SAAS,CAAC,UAAU,EAAE,EAAE;CAC7C,QAAQ,EAAE,MAAM,CAAC,EAAE;CACnB,iBAAiB;EACf,SAAS;GACP,SAAS,EAAE,OAAO,SAAS,QAAQ;IACjC,IAAI,KAAK,UAAU,KAAK,KAAK,UAAU,GAAG;IAC1C,QAAQ,IAAI,SAAS,cAAc,MAAM,MAAM,KAAK,CAAC;GACvD;GACA,eAAe,EAAE,SAAS,MAAM,QAAQ;IACtC,MAAM,QAAQ,QAAQ,IAAI,OAAO,GAAG,OAAO,MAAM,WAAW,KAAK,QAAQ;IACzE,IAAI,QAAQ,CAAC,KAAK,IAAI,WAAW,GAAG;KAAE,KAAK,IAAI,aAAa,IAAI;KAAG,KAAK,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC;IAAG,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,aAAa,KAAK;GACnJ;EACF;EACA,SAAS;;;;;;AAMP,UAAU,EAAE,OAAO,SAAS,QAAQ;GAClC,MAAM,MAAM,MAAM,OAAO;GACzB,IAAI,UAAU;GACd,MAAM,yBAAS,IAAI,IAAmC;GACtD,MAAM,UAAU,YAAY,KAAK,UAAU,UAAU;IACnD,MAAM,QAAQ,MAAM,QAA0B,QAAQ,MAAM,MAAM,EAAE,CAAC;IACrE,IAAI,CAAC,eAAe,KAAK,KAAK,CAAC,MAAM,QAAQ,MAAM,WAAW,MAAM,MAAM;IAC1E,MAAM,QAAQ,iBAAiB;KAC7B,OAAO,OAAO,KAAK;KACnB,IAAI,WAAW,MAAM,kBAAkB;KAEvC,QAAQ,IAAI,SAAS,cAAc,MAAM,KAAK,cAAc,KAAK,EAAE,CAAC;KAEpE,IAAI,MAAM,aAAa,MAAM,QAAQ,QAAQ,IAAI,OAAO;IAC1D,GAAG,CAAC;IACJ,OAAO,IAAI,KAAK;GAClB,GAAG,IAAI;GACP,aAAa;IAAE,UAAU;IAAM,QAAQ;IAAG,OAAO,QAAQ,YAAY;IAAG,OAAO,MAAM;GAAG;EAC1F,EACF;CACF;AACF,CAAC;AA2BD,MAAM,SAAS,UAAoC,MAAM,iBAAiB,MAAM;AAChF,MAAM,SAAS,QAAqB,UAAkB;CAAE,IAAI;EAAE,OAAO,oBAAoB,OAAO,KAAK;CAAG,QAAQ,CAAoC;AAAE;;;;;;AAOtJ,SAAgB,qBAA0C,SAAiC,WAAqD;CAC9I,MAAM,EAAE,SAAS,MAAM,MAAM,UAAU;CACvC,MAAM,QAAQ,QAAQ,IAAI,OAAO,GAAG,SAAS,KAAK,QAAQ,KAAA,GAAoC,SAAS,CAAC,CAAC,KAAK,MAAM,GAAG,UAAU,QAAQ,IAAI,SAAS;CACtJ,MAAM,WAAW,CAAC,CAAC,KAAK,UAAU,GAAG,WAAW,CAAC,CAAC,KAAK,UAAU,GAAG,SAAS,YAAY,UAAU,YAAY,QAAQ,IAAI,WAAW;CACtI,MAAM,QAAQ,KAAK,OAAO,KAAK,cAAc,KAAK,MAAM,KAAK,aAAa,OAAO,KAAK,MAAM,KAAK;CACjG,MAAM,KAAK,MAAM,MAAM;CACvB,MAAM,QAAQ,UAA6B;EAAE,cAAc;EAAkB,aAAa;CAAK;CAC/F,MAAM,SAAS,UAAU,MAAM,UAAU,OAAO,aAAa,KAAK,IAAI,UAAU,OAAO,SAAS,CAAC;CACjG,MAAM,QAAQ,MAAM,KAAK,EAAE,OAAO,IAAI,GAAG,UAA6B;EACpE,MAAM,OAAO,MAAM,UAAU;EAC7B,OAAO;GAAE;GAAO;GAAM,SAAS,OAAQ,SAAA,MAAqC,OAAQ;GAAI,QAAQ,CAAC,CAAC;GAAM,OAAO,WAAW,CAAC,YAAY,CAAC,UAAU,UAAU;GAAY,UAAU,WAAW,UAAU,SAAS,UAAU,SAAS,QAAQ,UAAU;EAAI;CAC3P,CAAC;CAED,MAAM,UAAU,OAAe,QAAgB;EAAE,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,GAAG,UAAU,QAAQ,IAAI,WAAW,GAAG,KAAK,KAAK,IAAI,MAAM,GAAG;EAAG,IAAI,QAAQ,UAAU,QAAQ,QAAQ,QAAQ,IAAI,QAAQ,IAAI,aAAa;GAAE,OAAO;GAAM,KAAK;EAAG,CAAC;CAAG;CACtP,MAAM,SAAS,UAAsB;EAAE,MAAM,SAAS,MAAM,KAAK,GAAG,QAAQ,OAAO,kBAAkB,OAAO,MAAM;EAAQ,OAAO,OAAO,OAAO,gBAAgB,KAAK;CAAG;;CAEvK,MAAM,UAAU,QAAqB,UAAkB,UAAkB;EACvE,IAAI,CAAC,QAAQ,QAAQ,IAAI,SAAS,QAAQ;EAC1C,MAAM,WAAW,QAAQ,IAAI,OAAO;EACpC,IAAI,OAAO,UAAU,UAAU;GAAE,OAAO,QAAQ;GAAU,MAAM,QAAQ,KAAK,IAAI,OAAO,SAAS,MAAM,CAAC;EAAG;EAC3G,OAAO,OAAO,kBAAkB,SAAS,QAAQ,OAAO,gBAAgB,SAAS,MAAM;EACvF,qBAAqB;GAAE,IAAI,OAAO,gBAAgB,SAAS,OAAO,UAAU,QAAQ,IAAI,OAAO,GAAG;IAAE,OAAO,QAAQ,QAAQ,IAAI,OAAO;IAAG,MAAM,QAAQ,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM;GAAG;EAAE,CAAC;CAC1L;CACA,OAAO;EACL;EAAO;EAAQ;EAAQ;EAAS,UAAU,MAAM,WAAW;EAAQ;EAAU;EAAU;EAAO;EAAM;EACpG,WAAW,SAAS,KAAK;GAAE,MAAM;GAAa,OAAO;EAAK,CAAC;EAC3D,aAAa,KAAK;GAAE,MAAM;GAAa,OAAO;EAAG,CAAC;EAClD,oBAAoB,UAAU,QAAQ;GAAE,GAAG,KAAK,MAAM;GAAG,iBAAiB,SAAS,QAAQ;GAAG,iBAAiB,SAAS,QAAQ;GAAG,gBAAgB,SAAS,OAAO;GAAG,iBAAiB,SAAS,MAAM,WAAW,MAAM;GAAG,eAAe,SAAS,MAAM;EAAE,CAAC;EAC3P,qBAAqB,UAAU,MAAM;GACnC,GAAG,KAAK,OAAO;GAAG,IAAI,QAAQ,EAAE;GAAG,MAAM,SAAS,aAAa;GAAQ;GAAO,MAAM,KAAK,MAAM;GAAG,MAAM,KAAK,MAAM;GACnH;GAAU;GAAU,UAAU,KAAK,UAAU;GAAG,WAAW;GAAQ,SAAS,GAAG,KAAK,SAAS,MAAM,iBAAiB,gBAAgB,QAAQ,GAAG,OAAO;GACtJ,WAAW,KAAK,SAAS,MAAM,YAAY,YAAY;GAAQ,cAAc,KAAK,cAAc;GAAG,cAAc,KAAK,cAAc;GACpI,gBAAgB;GAAO,aAAa;GAAO,YAAY;GAAS,cAAc;GAAO,oBAAoB,OAAO,EAAE;GAClH,SAAS,OAAmB;IAC1B,MAAM,SAAS,MAAM,KAAK,GAAG,QAAQ,OAAO,kBAAkB,OAAO,MAAM;IAC3E,IAAI,QAAQ;KAAE,OAAO,QAAQ,QAAQ,IAAI,OAAO,GAAG,KAAK;KAAG;IAAQ;IACnE,OAAO,QAAQ,cAAc,MAAM,OAAO,KAAK,GAAG,cAAc,MAAM,OAAO,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM;GAC5G;GACA,QAAQ,OAAmB;IACzB,MAAM,eAAe;IACrB,IAAI,QAAQ;IACZ,MAAM,SAAS,MAAM,KAAK,GAAG,QAAQ,OAAO,kBAAkB,MAAM;IACpE,MAAM,SAAS,wBAAwB,QAAQ,IAAI,OAAO,GAAG,MAAM,eAAe,QAAQ,MAAM,KAAK,IAAI;KAAE;KAAO,KAAK,OAAO,gBAAgB;IAAM,GAAG,QAAQ,KAAK,SAAS,CAAC;IAC9K,OAAO,QAAQ,OAAO,OAAO,OAAO,KAAK;GAC3C;GACA,QAAQ,OAAmB;IACzB,MAAM,SAAS,MAAM,KAAK;IAC1B,IAAI,OAAO,mBAAmB,OAAO,cAAc,MAAM,QAAQ,OAAO,MAAM,MAAM;IACpF,MAAM,KAAK;GACb;GACA,SAAS;GAAO,UAAU;GAC1B,QAAQ,OAAmB;IAAE,QAAQ,IAAI,WAAW,IAAI;IAAG,MAAM,KAAK;GAAG;GACzE,SAAS;IAAE,QAAQ,IAAI,WAAW,KAAK;GAAG;EAC5C,CAAC;EACD,qBAAqB,UAAU,QAAQ;GAAE,GAAG,KAAK,OAAO;GAAG,eAAe;EAAO,CAAC;EAClF,eAAe,SAAS,UAAU,QAAQ;GAAE,GAAG,KAAK,MAAM;GAAG,cAAc,KAAK;GAAO,eAAe,SAAS,KAAK,MAAM;GAAG,cAAc,SAAS,KAAK,KAAK;GAAG,iBAAiB,SAAS,KAAK,QAAQ;GAAG,iBAAiB,SAAS,QAAQ;EAAE,CAAC;EAChP,oBAAoB,UAAU,QAAQ;GAAE,GAAG,KAAK,MAAM;GAAG,IAAI,OAAO,EAAE;EAAE,CAAC;CAC3E;AACF"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { type Machine, type Service } from "@zag-js/core";
|
|
2
|
+
import type { NormalizeProps, PropTypes } from "@zag-js/types";
|
|
3
|
+
/**
|
|
4
|
+
* PasswordInput 密码格 / 验证码:一个真实 `<input>` 承载焦点、选区、粘贴、读屏与表单,
|
|
5
|
+
* 格子只是 `aria-hidden` 的呈现层。
|
|
6
|
+
*
|
|
7
|
+
* Core 持有:长度/字符集归一化、受控提议与拒绝写回、粘贴合并、掩码、选区→高亮格、
|
|
8
|
+
* 一次填满一次 onComplete、表单 reset 恢复默认值。Core 从不提交表单、也不校验验证码。
|
|
9
|
+
*/
|
|
10
|
+
/** Stable DOM parts shared by every adapter. */
|
|
11
|
+
export declare const PASSWORD_INPUT_PARTS: readonly ["root", "input", "cells", "cell", "hint"];
|
|
12
|
+
export declare const PASSWORD_INPUT_DEFAULT_LENGTH = 6;
|
|
13
|
+
/** Inclusive length bounds; out-of-range or non-integer lengths are clamped / rounded down. */
|
|
14
|
+
export declare const PASSWORD_INPUT_MIN_LENGTH = 1;
|
|
15
|
+
export declare const PASSWORD_INPUT_MAX_LENGTH = 12;
|
|
16
|
+
/** Character kept by each charset. Full-width digits/letters are folded to ASCII first. */
|
|
17
|
+
export declare const PASSWORD_INPUT_CHARSETS: readonly ["numeric", "alphanumeric"];
|
|
18
|
+
export declare const PASSWORD_INPUT_MODES: readonly ["password", "otp"];
|
|
19
|
+
/** Decorative glyph drawn in a filled cell while masked. */
|
|
20
|
+
export declare const PASSWORD_INPUT_MASK_GLYPH = "\u2022";
|
|
21
|
+
export type PasswordInputPart = (typeof PASSWORD_INPUT_PARTS)[number];
|
|
22
|
+
export type PasswordInputCharset = (typeof PASSWORD_INPUT_CHARSETS)[number];
|
|
23
|
+
export type PasswordInputMode = (typeof PASSWORD_INPUT_MODES)[number];
|
|
24
|
+
export type PasswordInputAutoComplete = "off" | "one-time-code" | "current-password" | "new-password";
|
|
25
|
+
export interface PasswordInputValueChangeDetails {
|
|
26
|
+
value: string;
|
|
27
|
+
}
|
|
28
|
+
export interface PasswordInputCompleteDetails {
|
|
29
|
+
value: string;
|
|
30
|
+
}
|
|
31
|
+
/** One presentational cell. `char` is the real character; adapters render `display`. */
|
|
32
|
+
export interface PasswordInputCell {
|
|
33
|
+
index: number;
|
|
34
|
+
char: string;
|
|
35
|
+
display: string;
|
|
36
|
+
filled: boolean;
|
|
37
|
+
caret: boolean;
|
|
38
|
+
selected: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface QwPasswordInputProps {
|
|
41
|
+
/** Instance identity; adapters generate one when omitted. */
|
|
42
|
+
id?: string;
|
|
43
|
+
/** Number of cells; integer 1–12, default 6. */
|
|
44
|
+
length?: number;
|
|
45
|
+
/** Controlled value. Edits are proposed through onValueChange; the shown value only changes when the owner accepts. */
|
|
46
|
+
value?: string;
|
|
47
|
+
/** Uncontrolled initial value, also the value a form reset restores. Default "". */
|
|
48
|
+
defaultValue?: string;
|
|
49
|
+
/** Proposed value after an edit, paste or reset (already filtered and truncated). */
|
|
50
|
+
onValueChange?: (details: PasswordInputValueChangeDetails) => void;
|
|
51
|
+
/** The effective value just became full. Fires once per fill; never submits or verifies anything. */
|
|
52
|
+
onComplete?: (details: PasswordInputCompleteDetails) => void;
|
|
53
|
+
/** Allowed characters: numeric (default) keeps 0–9, alphanumeric keeps A–Z/a–z/0–9. */
|
|
54
|
+
charset?: PasswordInputCharset;
|
|
55
|
+
/** password (default) masks by default and turns autofill off; otp shows plain text and asks for one-time-code autofill. */
|
|
56
|
+
mode?: PasswordInputMode;
|
|
57
|
+
/** Draw dots instead of characters; the real input becomes type="password". Default: true for password, false for otp. */
|
|
58
|
+
mask?: boolean;
|
|
59
|
+
/** Overrides the autocomplete token chosen by mode. */
|
|
60
|
+
autoComplete?: PasswordInputAutoComplete;
|
|
61
|
+
/** Accessible name of the real input; defaults to 密码 / 验证码 by mode. */
|
|
62
|
+
label?: string;
|
|
63
|
+
/** Spoken length description; defaults to "6 位数字" / "6 位字母或数字". */
|
|
64
|
+
hint?: string;
|
|
65
|
+
disabled?: boolean;
|
|
66
|
+
readOnly?: boolean;
|
|
67
|
+
required?: boolean;
|
|
68
|
+
/** Form field name; the real input submits the value under it. */
|
|
69
|
+
name?: string;
|
|
70
|
+
/** Owner form id, as the native form attribute. */
|
|
71
|
+
form?: string;
|
|
72
|
+
enterKeyHint?: "done" | "go" | "next" | "send" | "enter";
|
|
73
|
+
}
|
|
74
|
+
/** Clamp to an integer in 1–12; anything unusable falls back to 6. */
|
|
75
|
+
export declare function normalizePasswordInputLength(length?: number): number;
|
|
76
|
+
/** Fold full-width ASCII (IME digits like "123") to half-width, drop disallowed characters, then truncate. Never throws. */
|
|
77
|
+
export declare function normalizePasswordInputValue(value: unknown, length?: number, charset?: PasswordInputCharset): string;
|
|
78
|
+
/**
|
|
79
|
+
* Merge pasted text into the current value. A paste that alone fills every cell (after filtering)
|
|
80
|
+
* replaces the whole value — the usual "paste the code from SMS" case; otherwise it replaces the selection.
|
|
81
|
+
* Returns the next value and the caret after the inserted text.
|
|
82
|
+
*/
|
|
83
|
+
export declare function mergePasswordInputPaste(current: string, pasted: string, selection: {
|
|
84
|
+
start: number;
|
|
85
|
+
end: number;
|
|
86
|
+
}, length?: number, charset?: PasswordInputCharset): {
|
|
87
|
+
value: string;
|
|
88
|
+
caret: number;
|
|
89
|
+
};
|
|
90
|
+
export declare function createPasswordInputProps(props?: QwPasswordInputProps): QwPasswordInputProps;
|
|
91
|
+
interface Selection {
|
|
92
|
+
start: number;
|
|
93
|
+
end: number;
|
|
94
|
+
}
|
|
95
|
+
export interface QwPasswordInputSchema {
|
|
96
|
+
props: QwPasswordInputProps;
|
|
97
|
+
context: {
|
|
98
|
+
value: string;
|
|
99
|
+
selection: Selection;
|
|
100
|
+
focused: boolean;
|
|
101
|
+
};
|
|
102
|
+
refs: {
|
|
103
|
+
completed: boolean;
|
|
104
|
+
};
|
|
105
|
+
state: "idle";
|
|
106
|
+
action: "setValue" | "notifyComplete";
|
|
107
|
+
effect: "trackForm";
|
|
108
|
+
/** Programmatic proposal (api.setValue / clear). DOM handlers write context synchronously instead. */
|
|
109
|
+
event: {
|
|
110
|
+
type: "VALUE.SET";
|
|
111
|
+
value: string;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export type QwPasswordInputMachine = Machine<QwPasswordInputSchema>;
|
|
115
|
+
export type QwPasswordInputService = Service<QwPasswordInputSchema>;
|
|
116
|
+
export declare const passwordInputMachine: QwPasswordInputMachine;
|
|
117
|
+
export interface QwPasswordInputApi<T extends PropTypes = PropTypes> {
|
|
118
|
+
value: string;
|
|
119
|
+
length: number;
|
|
120
|
+
masked: boolean;
|
|
121
|
+
focused: boolean;
|
|
122
|
+
complete: boolean;
|
|
123
|
+
disabled: boolean;
|
|
124
|
+
readOnly: boolean;
|
|
125
|
+
label: string;
|
|
126
|
+
hint: string;
|
|
127
|
+
cells: PasswordInputCell[];
|
|
128
|
+
/** Propose a value programmatically (normalized; ignored when disabled or readOnly). */
|
|
129
|
+
setValue(value: string): void;
|
|
130
|
+
/** Propose "" (ignored when disabled or readOnly). */
|
|
131
|
+
clear(): void;
|
|
132
|
+
getRootProps(): T["element"];
|
|
133
|
+
getInputProps(): T["input"];
|
|
134
|
+
getCellsProps(): T["element"];
|
|
135
|
+
getCellProps(cell: PasswordInputCell): T["element"];
|
|
136
|
+
getHintProps(): T["element"];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Caret semantics: the real input owns caret and selection; arrows, Home/End, Backspace/Delete and shift-selection are native.
|
|
140
|
+
* The visual caret cell follows selectionStart (clamped to the last cell when full); a non-collapsed selection marks its cells.
|
|
141
|
+
* A plain tap/click collapses the caret to the end of the value, because input text geometry does not line up with the cells.
|
|
142
|
+
*/
|
|
143
|
+
export declare function connectPasswordInput<T extends PropTypes>(service: QwPasswordInputService, normalize: NormalizeProps<T>): QwPasswordInputApi<T>;
|
|
144
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { pickerMachine } from "./picker-machine.js";
|
|
2
|
+
export type { QwPickerSchema, QwPickerService, QwPickerMachine } from "./picker-machine.js";
|
|
3
|
+
export { createPickerProps, connectPicker, getPickerAccessibleName, getPickerDataAttrs, isPickerColumns, isPickerValue, resolvePickerColumns, resolvePickerMode, } from "./picker.js";
|
|
4
|
+
export type { QwPickerProps, QwPickerApi, QwPickerMachineProps, QwResolvedPickerColumn, QwResolvedPickerOption } from "./picker.js";
|
|
5
|
+
export { PickerSelectionModel, getPickerDiagnostics, getPickerFirstValue, getPickerKeyboardTarget, getPickerOptionIndex, isPickerOptionSelectable, } from "./selection-model.js";
|
|
6
|
+
export type { PickerChangeDetails, PickerColumn, PickerColumnSignal, PickerColumnToken, PickerDiagnostic, PickerGeometry, PickerKeyboardMove, PickerMode, PickerOption, PickerScrollCommand, PickerSelectionNotice, PickerSelectionProps, PickerSelectionSnapshot, PickerValue, } from "./selection-model.js";
|
|
7
|
+
export { attachPickerColumn, connectPickerColumn } from "./platform.js";
|
|
8
|
+
export type { PickerBridgeCommand, PickerBridgeNotice, PickerColumnBinding, PickerColumnController, PickerColumnHost, PickerColumnSurface, PickerRawEventFacts, } from "./platform.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { _ as isPickerOptionSelectable, a as getPickerAccessibleName, c as isPickerValue, d as pickerMachine, f as PickerSelectionModel, g as getPickerOptionIndex, h as getPickerKeyboardTarget, i as createPickerProps, l as resolvePickerColumns, m as getPickerFirstValue, n as connectPickerColumn, o as getPickerDataAttrs, p as getPickerDiagnostics, r as connectPicker, s as isPickerColumns, t as attachPickerColumn, u as resolvePickerMode } from "../picker-BykFntQN.js";
|
|
2
|
+
export { PickerSelectionModel, attachPickerColumn, connectPicker, connectPickerColumn, createPickerProps, getPickerAccessibleName, getPickerDataAttrs, getPickerDiagnostics, getPickerFirstValue, getPickerKeyboardTarget, getPickerOptionIndex, isPickerColumns, isPickerOptionSelectable, isPickerValue, pickerMachine, resolvePickerColumns, resolvePickerMode };
|