@qw-ui/core 0.3.0-next.40 → 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 +9 -0
- package/dist/badge/index.js +14 -1
- package/dist/badge/index.js.map +1 -1
- 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 +32 -3
- package/dist/dialog/index.js +58 -3
- 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 +107 -14
- package/dist/index.js +148 -14
- 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/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 +3 -1
- package/dist/search-bar/index.js.map +1 -1
- package/dist/search-bar/search-bar.d.ts +4 -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/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.js +62 -3
- package/dist/stepper/index.js.map +1 -1
- package/dist/stepper/stepper.d.ts +44 -4
- 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.js +135 -10
- package/dist/switch/index.js.map +1 -1
- package/dist/switch/switch.d.ts +93 -6
- package/dist/tabbar/index.js +46 -1
- package/dist/tabbar/index.js.map +1 -1
- package/dist/tabbar/tabbar.d.ts +50 -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 +165 -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 +6 -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 +399 -50
- package/dist/empty/index.js.map +0 -1
- package/dist/icon/index.js.map +0 -1
- package/dist/textarea/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/stepper/stepper.ts"],"sourcesContent":["/**\n * Stepper 加减(数量步进器)的跨框架行为契约。\n *\n * Stepper 是原型 A(无状态 Core 状态机):交互由原生 `<button>` 承担,\n * core 只负责数值归一化、边界 clamp、按钮可用性计算与 prop-getter 生成。\n */\n\n/** 尺寸全集:s = 15×15px,m = 18×18px。 */\nexport const STEPPER_SIZES = [\"s\", \"m\"] as const;\n\n/** 形态变体全集:default = 裸按钮组合,bordered = 带边框卡片形态。 */\nexport const STEPPER_VARIANTS = [\"default\", \"bordered\"] as const;\n\n/** 渲染部位全集(data-part 取值)。 */\nexport const STEPPER_PARTS = [\"root\", \"decrement\", \"value\", \"increment\"] as const;\n\nexport type StepperSize = (typeof STEPPER_SIZES)[number];\nexport type StepperVariant = (typeof STEPPER_VARIANTS)[number];\nexport type StepperPart = (typeof STEPPER_PARTS)[number];\n\n/**\n * QwStepperProps — 双栈共享的行为契约(全字段可选)。\n * `value` 未传时走非受控模式,由适配层管理内部数值。\n */\nexport interface QwStepperProps {\n /** 受控值。未传时走非受控模式。 */\n value?: number;\n /** 非受控初始值,默认 `0`(若 `min > 0` 则取 `min`)。仅在 `value` 未传时生效。 */\n defaultValue?: number;\n /** 数值变化回调,参数为新的 value。 */\n onChange?: (value: number) => void;\n /** 最小值。 */\n min?: number;\n /** 最大值。 */\n max?: number;\n /** 步长,默认 1;非法值(非正数)回退到 1。 */\n step?: number;\n /** 禁用状态。 */\n disabled?: boolean;\n /** 按钮尺寸,默认 m。 */\n size?: StepperSize;\n /** 形态变体,默认 default;bordered 为带边框卡片形态。 */\n variant?: StepperVariant;\n /** 减量按钮 aria-label,默认「减少」(适配层可注入语言包取值)。 */\n decrementLabel?: string;\n /** 增量按钮 aria-label,默认「增加」(适配层可注入语言包取值)。 */\n incrementLabel?: string;\n}\n\n/** 适配器唯一可消费的归一化结果。 */\nexport interface ResolvedStepperState {\n /** 当前数值(已按 min/max clamp)。 */\n value: number;\n /** 最小值。 */\n min: number | undefined;\n /** 最大值。 */\n max: number | undefined;\n /** 实际生效的步长。 */\n step: number;\n /** 是否整体禁用。 */\n disabled: boolean;\n /** 按钮尺寸。 */\n size: StepperSize;\n /** 形态变体。 */\n variant: StepperVariant;\n /** 选中态:value > min 派生,仅影响 bordered 视觉。 */\n selected: boolean;\n /** 减量按钮是否可用。 */\n canDecrement: boolean;\n /** 增量按钮是否可用。 */\n canIncrement: boolean;\n /** 减量按钮 aria-label(per-prop > 适配层注入 > 内置「减少」)。 */\n decrementLabel: string;\n /** 增量按钮 aria-label(per-prop > 适配层注入 > 内置「增加」)。 */\n incrementLabel: string;\n}\n\n/** 将数值约束在 [min, max] 范围内;边界未定义时跳过对应侧。 */\nexport function clampStepperValue(\n value: number,\n min: number | undefined,\n max: number | undefined,\n): number {\n let result = value;\n if (typeof min === \"number\" && !Number.isNaN(min)) {\n result = Math.max(result, min);\n }\n if (typeof max === \"number\" && !Number.isNaN(max)) {\n result = Math.min(result, max);\n }\n return result;\n}\n\n/** 规范化 step:仅接受正数,否则回退到 1。 */\nfunction normalizeStepperStep(step: number | undefined): number {\n return typeof step === \"number\" && step > 0 && !Number.isNaN(step) ? step : 1;\n}\n\n/** 规范化 min:未指定时按规格默认 0(不做负数默认值)。 */\nfunction normalizeStepperMin(min: number | undefined): number {\n return typeof min === \"number\" && !Number.isNaN(min) ? min : 0;\n}\n\n/** 将公开输入归一化为唯一的跨框架状态。 */\nexport function resolveStepperState(props: QwStepperProps = {}): ResolvedStepperState {\n const min = normalizeStepperMin(props.min);\n const max = props.max;\n const step = normalizeStepperStep(props.step);\n const disabled = props.disabled ?? false;\n const variant = props.variant ?? \"default\";\n\n const isControlled = props.value !== undefined;\n const rawValue = isControlled\n ? props.value!\n : (props.defaultValue ?? min);\n\n const value = clampStepperValue(rawValue, min, max);\n\n const size = props.size ?? \"m\";\n\n const selected = value > min;\n\n const canDecrement = !disabled && value > min;\n const canIncrement = !disabled && (typeof max !== \"number\" || value < max);\n\n return {\n value,\n min,\n max,\n step,\n disabled,\n size,\n variant,\n selected,\n canDecrement,\n canIncrement,\n decrementLabel: props.decrementLabel ?? \"减少\",\n incrementLabel: props.incrementLabel ?? \"增加\",\n };\n}\n\n/** 计算减量后的目标值(已 clamp)。 */\nexport function getStepperDecrementValue(state: ResolvedStepperState): number {\n return clampStepperValue(state.value - state.step, state.min, state.max);\n}\n\n/** 计算增量后的目标值(已 clamp)。 */\nexport function getStepperIncrementValue(state: ResolvedStepperState): number {\n return clampStepperValue(state.value + state.step, state.min, state.max);\n}\n\n/** Core 生成、由适配器最后覆盖到根元素的属性。 */\nexport interface StepperRootProps {\n role: \"group\";\n \"data-scope\": \"stepper\";\n \"data-part\": \"root\";\n \"data-size\": StepperSize;\n \"data-variant\": StepperVariant;\n \"data-selected\"?: \"true\";\n \"data-disabled\"?: \"true\";\n}\n\n/** 生成根容器属性。 */\nexport function getStepperRootProps(state: ResolvedStepperState): StepperRootProps {\n return {\n role: \"group\",\n \"data-scope\": \"stepper\",\n \"data-part\": \"root\",\n \"data-size\": state.size,\n \"data-variant\": state.variant,\n ...(state.selected ? { \"data-selected\": \"true\" as const } : {}),\n ...(state.disabled ? { \"data-disabled\": \"true\" as const } : {}),\n };\n}\n\n/** 减量按钮属性。 */\nexport interface StepperDecrementProps {\n type: \"button\";\n disabled: boolean;\n \"data-scope\": \"stepper\";\n \"data-part\": \"decrement\";\n \"aria-label\": string;\n \"data-disabled\"?: \"true\";\n}\n\n/** 生成减量按钮属性。 */\nexport function getStepperDecrementProps(state: ResolvedStepperState): StepperDecrementProps {\n const disabled = !state.canDecrement;\n return {\n type: \"button\",\n disabled,\n \"data-scope\": \"stepper\",\n \"data-part\": \"decrement\",\n \"aria-label\": state.decrementLabel,\n ...(disabled ? { \"data-disabled\": \"true\" as const } : {}),\n };\n}\n\n/** 增量按钮属性。 */\nexport interface StepperIncrementProps {\n type: \"button\";\n disabled: boolean;\n \"data-scope\": \"stepper\";\n \"data-part\": \"increment\";\n \"aria-label\": string;\n \"data-disabled\"?: \"true\";\n}\n\n/** 生成增量按钮属性。 */\nexport function getStepperIncrementProps(state: ResolvedStepperState): StepperIncrementProps {\n const disabled = !state.canIncrement;\n return {\n type: \"button\",\n disabled,\n \"data-scope\": \"stepper\",\n \"data-part\": \"increment\",\n \"aria-label\": state.incrementLabel,\n ...(disabled ? { \"data-disabled\": \"true\" as const } : {}),\n };\n}\n\n/** 数值展示属性。 */\nexport interface StepperValueProps {\n \"data-scope\": \"stepper\";\n \"data-part\": \"value\";\n \"aria-live\": \"polite\";\n \"aria-atomic\": \"true\";\n}\n\n/** 生成数值展示属性。 */\nexport function getStepperValueProps(): StepperValueProps {\n return {\n \"data-scope\": \"stepper\",\n \"data-part\": \"value\",\n \"aria-live\": \"polite\",\n \"aria-atomic\": \"true\",\n };\n}\n"],"mappings":";;;;;;;;AAQA,MAAa,gBAAgB,CAAC,KAAK,GAAG;;AAGtC,MAAa,mBAAmB,CAAC,WAAW,UAAU;;AAGtD,MAAa,gBAAgB;CAAC;CAAQ;CAAa;CAAS;AAAW;;AAgEvE,SAAgB,kBACd,OACA,KACA,KACQ;CACR,IAAI,SAAS;CACb,IAAI,OAAO,QAAQ,YAAY,CAAC,OAAO,MAAM,GAAG,GAC9C,SAAS,KAAK,IAAI,QAAQ,GAAG;CAE/B,IAAI,OAAO,QAAQ,YAAY,CAAC,OAAO,MAAM,GAAG,GAC9C,SAAS,KAAK,IAAI,QAAQ,GAAG;CAE/B,OAAO;AACT;;AAGA,SAAS,qBAAqB,MAAkC;CAC9D,OAAO,OAAO,SAAS,YAAY,OAAO,KAAK,CAAC,OAAO,MAAM,IAAI,IAAI,OAAO;AAC9E;;AAGA,SAAS,oBAAoB,KAAiC;CAC5D,OAAO,OAAO,QAAQ,YAAY,CAAC,OAAO,MAAM,GAAG,IAAI,MAAM;AAC/D;;AAGA,SAAgB,oBAAoB,QAAwB,CAAC,GAAyB;CACpF,MAAM,MAAM,oBAAoB,MAAM,GAAG;CACzC,MAAM,MAAM,MAAM;CAClB,MAAM,OAAO,qBAAqB,MAAM,IAAI;CAC5C,MAAM,WAAW,MAAM,YAAY;CACnC,MAAM,UAAU,MAAM,WAAW;CAOjC,MAAM,QAAQ,kBALO,MAAM,UAAU,KAAA,IAEjC,MAAM,QACL,MAAM,gBAAgB,KAEe,KAAK,GAAG;CASlD,OAAO;EACL;EACA;EACA;EACA;EACA;EACA,MAbW,MAAM,QAAQ;EAczB;EACA,UAbe,QAAQ;EAcvB,cAZmB,CAAC,YAAY,QAAQ;EAaxC,cAZmB,CAAC,aAAa,OAAO,QAAQ,YAAY,QAAQ;EAapE,gBAAgB,MAAM,kBAAkB;EACxC,gBAAgB,MAAM,kBAAkB;CAC1C;AACF;;AAGA,SAAgB,yBAAyB,OAAqC;CAC5E,OAAO,kBAAkB,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAK,MAAM,GAAG;AACzE;;AAGA,SAAgB,yBAAyB,OAAqC;CAC5E,OAAO,kBAAkB,MAAM,QAAQ,MAAM,MAAM,MAAM,KAAK,MAAM,GAAG;AACzE;;AAcA,SAAgB,oBAAoB,OAA+C;CACjF,OAAO;EACL,MAAM;EACN,cAAc;EACd,aAAa;EACb,aAAa,MAAM;EACnB,gBAAgB,MAAM;EACtB,GAAI,MAAM,WAAW,EAAE,iBAAiB,OAAgB,IAAI,CAAC;EAC7D,GAAI,MAAM,WAAW,EAAE,iBAAiB,OAAgB,IAAI,CAAC;CAC/D;AACF;;AAaA,SAAgB,yBAAyB,OAAoD;CAC3F,MAAM,WAAW,CAAC,MAAM;CACxB,OAAO;EACL,MAAM;EACN;EACA,cAAc;EACd,aAAa;EACb,cAAc,MAAM;EACpB,GAAI,WAAW,EAAE,iBAAiB,OAAgB,IAAI,CAAC;CACzD;AACF;;AAaA,SAAgB,yBAAyB,OAAoD;CAC3F,MAAM,WAAW,CAAC,MAAM;CACxB,OAAO;EACL,MAAM;EACN;EACA,cAAc;EACd,aAAa;EACb,cAAc,MAAM;EACpB,GAAI,WAAW,EAAE,iBAAiB,OAAgB,IAAI,CAAC;CACzD;AACF;;AAWA,SAAgB,uBAA0C;CACxD,OAAO;EACL,cAAc;EACd,aAAa;EACb,aAAa;EACb,eAAe;CACjB;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/stepper/stepper.ts"],"sourcesContent":["/**\n * Stepper 加减(数量步进器)的跨框架行为契约。\n *\n * 交互由原生 `<button>` 承担。数值归一化、边界、按钮可用性、非受控模型、\n * 受控判断和取消都在 Core;适配层只运输点击并重绘。\n */\n\n/** 尺寸全集:s = 15×15px,m = 18×18px。 */\nexport const STEPPER_SIZES = [\"s\", \"m\"] as const;\n\n/** 形态变体全集:default = 裸按钮组合,bordered = 带边框卡片形态。 */\nexport const STEPPER_VARIANTS = [\"default\", \"bordered\"] as const;\n\n/** 渲染部位全集(data-part 取值)。 */\nexport const STEPPER_PARTS = [\"root\", \"decrement\", \"value\", \"increment\"] as const;\n\nexport type StepperSize = (typeof STEPPER_SIZES)[number];\nexport type StepperVariant = (typeof STEPPER_VARIANTS)[number];\nexport type StepperPart = (typeof STEPPER_PARTS)[number];\n\n/**\n * QwStepperProps — 跨框架行为契约(全字段可选)。\n * `value` 未传时走非受控模式,由 `createStepperModel` 持有内部数值。\n */\nexport interface QwStepperProps {\n /** 受控值。未传时走非受控模式。 */\n value?: number;\n /** 非受控初始值,默认 `0`(若 `min > 0` 则取 `min`)。仅在 `value` 未传时生效。 */\n defaultValue?: number;\n /** 数值变化回调,参数为新的 value。 */\n onChange?: (value: number) => void;\n /** 最小值。 */\n min?: number;\n /** 最大值。 */\n max?: number;\n /** 步长,默认 1;非法值(非正数)回退到 1。 */\n step?: number;\n /** 禁用状态。 */\n disabled?: boolean;\n /** 按钮尺寸,默认 m。 */\n size?: StepperSize;\n /** 形态变体,默认 default;bordered 为带边框卡片形态。 */\n variant?: StepperVariant;\n /** 减量按钮 aria-label,默认「减少」(适配层可注入语言包取值)。 */\n decrementLabel?: string;\n /** 增量按钮 aria-label,默认「增加」(适配层可注入语言包取值)。 */\n incrementLabel?: string;\n}\n\n/** 适配器唯一可消费的归一化结果。 */\nexport interface ResolvedStepperState {\n /** 当前数值(已按 min/max clamp)。 */\n value: number;\n /** 最小值。 */\n min: number | undefined;\n /** 最大值。 */\n max: number | undefined;\n /** 实际生效的步长。 */\n step: number;\n /** 是否整体禁用。 */\n disabled: boolean;\n /** 按钮尺寸。 */\n size: StepperSize;\n /** 形态变体。 */\n variant: StepperVariant;\n /** 选中态:value > min 派生,仅影响 bordered 视觉。 */\n selected: boolean;\n /** 减量按钮是否可用。 */\n canDecrement: boolean;\n /** 增量按钮是否可用。 */\n canIncrement: boolean;\n /** 减量按钮 aria-label(per-prop > 适配层注入 > 内置「减少」)。 */\n decrementLabel: string;\n /** 增量按钮 aria-label(per-prop > 适配层注入 > 内置「增加」)。 */\n incrementLabel: string;\n}\n\n/** 将数值约束在 [min, max] 范围内;边界未定义时跳过对应侧。 */\nexport function clampStepperValue(\n value: number,\n min: number | undefined,\n max: number | undefined,\n): number {\n let result = value;\n if (typeof min === \"number\" && !Number.isNaN(min)) {\n result = Math.max(result, min);\n }\n if (typeof max === \"number\" && !Number.isNaN(max)) {\n result = Math.min(result, max);\n }\n return result;\n}\n\n/** 规范化 step:仅接受正数,否则回退到 1。 */\nfunction normalizeStepperStep(step: number | undefined): number {\n return typeof step === \"number\" && step > 0 && !Number.isNaN(step) ? step : 1;\n}\n\n/** 规范化 min:未指定时按规格默认 0(不做负数默认值)。 */\nfunction normalizeStepperMin(min: number | undefined): number {\n return typeof min === \"number\" && !Number.isNaN(min) ? min : 0;\n}\n\n/** 将公开输入归一化为唯一的跨框架状态。 */\nexport function resolveStepperState(props: QwStepperProps = {}): ResolvedStepperState {\n const min = normalizeStepperMin(props.min);\n const max = props.max;\n const step = normalizeStepperStep(props.step);\n const disabled = props.disabled ?? false;\n const variant = props.variant ?? \"default\";\n\n const isControlled = props.value !== undefined;\n const rawValue = isControlled\n ? props.value!\n : (props.defaultValue ?? min);\n\n const value = clampStepperValue(rawValue, min, max);\n\n const size = props.size ?? \"m\";\n\n const selected = value > min;\n\n const canDecrement = !disabled && value > min;\n const canIncrement = !disabled && (typeof max !== \"number\" || value < max);\n\n return {\n value,\n min,\n max,\n step,\n disabled,\n size,\n variant,\n selected,\n canDecrement,\n canIncrement,\n decrementLabel: props.decrementLabel ?? \"减少\",\n incrementLabel: props.incrementLabel ?? \"增加\",\n };\n}\n\n/** 计算减量后的目标值(已 clamp)。 */\nexport function getStepperDecrementValue(state: ResolvedStepperState): number {\n return clampStepperValue(state.value - state.step, state.min, state.max);\n}\n\n/** 计算增量后的目标值(已 clamp)。 */\nexport function getStepperIncrementValue(state: ResolvedStepperState): number {\n return clampStepperValue(state.value + state.step, state.min, state.max);\n}\n\n/** Core 生成、由适配器最后覆盖到根元素的属性。 */\nexport interface StepperRootProps {\n role: \"group\";\n \"data-scope\": \"stepper\";\n \"data-part\": \"root\";\n \"data-size\": StepperSize;\n \"data-variant\": StepperVariant;\n \"data-selected\"?: \"true\";\n \"data-disabled\"?: \"true\";\n}\n\n/** 生成根容器属性。 */\nexport function getStepperRootProps(state: ResolvedStepperState): StepperRootProps {\n return {\n role: \"group\",\n \"data-scope\": \"stepper\",\n \"data-part\": \"root\",\n \"data-size\": state.size,\n \"data-variant\": state.variant,\n ...(state.selected ? { \"data-selected\": \"true\" as const } : {}),\n ...(state.disabled ? { \"data-disabled\": \"true\" as const } : {}),\n };\n}\n\n/** 减量按钮属性。 */\nexport interface StepperDecrementProps {\n type: \"button\";\n disabled: boolean;\n \"data-scope\": \"stepper\";\n \"data-part\": \"decrement\";\n \"aria-label\": string;\n \"data-disabled\"?: \"true\";\n}\n\n/** 生成减量按钮属性。 */\nexport function getStepperDecrementProps(state: ResolvedStepperState): StepperDecrementProps {\n const disabled = !state.canDecrement;\n return {\n type: \"button\",\n disabled,\n \"data-scope\": \"stepper\",\n \"data-part\": \"decrement\",\n \"aria-label\": state.decrementLabel,\n ...(disabled ? { \"data-disabled\": \"true\" as const } : {}),\n };\n}\n\n/** 增量按钮属性。 */\nexport interface StepperIncrementProps {\n type: \"button\";\n disabled: boolean;\n \"data-scope\": \"stepper\";\n \"data-part\": \"increment\";\n \"aria-label\": string;\n \"data-disabled\"?: \"true\";\n}\n\n/** 生成增量按钮属性。 */\nexport function getStepperIncrementProps(state: ResolvedStepperState): StepperIncrementProps {\n const disabled = !state.canIncrement;\n return {\n type: \"button\",\n disabled,\n \"data-scope\": \"stepper\",\n \"data-part\": \"increment\",\n \"aria-label\": state.incrementLabel,\n ...(disabled ? { \"data-disabled\": \"true\" as const } : {}),\n };\n}\n\n/** 数值展示属性。 */\nexport interface StepperValueProps {\n \"data-scope\": \"stepper\";\n \"data-part\": \"value\";\n \"aria-live\": \"polite\";\n \"aria-atomic\": \"true\";\n}\n\n/** 生成数值展示属性。 */\nexport function getStepperValueProps(): StepperValueProps {\n return {\n \"data-scope\": \"stepper\",\n \"data-part\": \"value\",\n \"aria-live\": \"polite\",\n \"aria-atomic\": \"true\",\n };\n}\n\n/** 一次步进方向。适配层只运输激活,不预算下一个数值。 */\nexport type StepperDirection = \"increment\" | \"decrement\";\n\n/**\n * 取消标记。Core 在微任务里读 `defaultPrevented`,宿主冒泡阶段的 preventDefault 能赶上。\n * 传入点击事件本身即可。\n */\nexport interface StepperStepNotice {\n readonly defaultPrevented: boolean;\n}\n\n/** 受控时是调用方原值,非受控时是内部模型。 */\nexport interface StepperModelSnapshot {\n value: number;\n}\n\nexport interface StepperModelOptions {\n /** 未被取消的步进提交后调用,供适配层重绘。提交时读取当前属性。 */\n onCommit?: () => void;\n /** 非受控重连快照。仅当创建时未传 `value`,且 `value` 为 number 时覆盖初始模型。 */\n snapshot?: { value?: unknown };\n}\n\nexport interface StepperModel {\n /** 当前画面状态(数值已 clamp)。 */\n readonly state: ResolvedStepperState;\n /** 受控:调用方原值(可以未经 clamp)。非受控:内部模型。 */\n readonly modelValue: number;\n readonly controlled: boolean;\n update(props: QwStepperProps): void;\n request(direction: StepperDirection, notice: StepperStepNotice): void;\n /** 恢复接收步进。stop 之前已经排队的请求仍然作废。 */\n start(): void;\n /** 作废尚未提交的步进。 */\n stop(): void;\n snapshot(): StepperModelSnapshot;\n}\n\nfunction seedStepperModel(props: QwStepperProps, snapshot: StepperModelOptions[\"snapshot\"]): number {\n if (props.value === undefined && typeof snapshot?.value === \"number\") return snapshot.value;\n if (typeof props.defaultValue === \"number\") return props.defaultValue;\n if (typeof props.min === \"number\") return props.min;\n return 0;\n}\n\n/**\n * 步进器的行为源。下一步在提交时按当时的模型计算:同一次任务里连续激活会依次累计,\n * 而不是共用渲染当时预算的同一个 next。取消只看提交时的 defaultPrevented、禁用和 stop。\n */\nexport function createStepperModel(props: QwStepperProps = {}, options: StepperModelOptions = {}): StepperModel {\n let current = props;\n let internal = seedStepperModel(props, options.snapshot);\n let generation = 0;\n let stopped = false;\n const controlledNow = () => current.value !== undefined;\n const view = (): ResolvedStepperState => resolveStepperState({\n ...current,\n value: controlledNow() ? current.value : internal,\n });\n const readModel = () => (controlledNow() ? current.value ?? internal : internal);\n\n return {\n get state() { return view(); },\n get modelValue() { return readModel(); },\n get controlled() { return controlledNow(); },\n update(next) { current = next; },\n request(direction, notice) {\n if (stopped || view().disabled) return;\n const seen = generation;\n queueMicrotask(() => {\n if (stopped || seen !== generation || notice.defaultPrevented) return;\n const resolved = view();\n if (resolved.disabled) return;\n const next = direction === \"increment\" ? getStepperIncrementValue(resolved) : getStepperDecrementValue(resolved);\n if (!controlledNow()) internal = next;\n current.onChange?.(next);\n options.onCommit?.();\n });\n },\n start() { stopped = false; },\n stop() { stopped = true; generation += 1; },\n snapshot() { return { value: readModel() }; },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Stepper 加减(数量步进器)的跨框架行为契约。
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* 交互由原生 `<button>` 承担。数值归一化、边界、按钮可用性、非受控模型、
|
|
5
|
+
* 受控判断和取消都在 Core;适配层只运输点击并重绘。
|
|
6
6
|
*/
|
|
7
7
|
/** 尺寸全集:s = 15×15px,m = 18×18px。 */
|
|
8
8
|
export declare const STEPPER_SIZES: readonly ["s", "m"];
|
|
@@ -14,8 +14,8 @@ export type StepperSize = (typeof STEPPER_SIZES)[number];
|
|
|
14
14
|
export type StepperVariant = (typeof STEPPER_VARIANTS)[number];
|
|
15
15
|
export type StepperPart = (typeof STEPPER_PARTS)[number];
|
|
16
16
|
/**
|
|
17
|
-
* QwStepperProps —
|
|
18
|
-
* `value`
|
|
17
|
+
* QwStepperProps — 跨框架行为契约(全字段可选)。
|
|
18
|
+
* `value` 未传时走非受控模式,由 `createStepperModel` 持有内部数值。
|
|
19
19
|
*/
|
|
20
20
|
export interface QwStepperProps {
|
|
21
21
|
/** 受控值。未传时走非受控模式。 */
|
|
@@ -119,3 +119,43 @@ export interface StepperValueProps {
|
|
|
119
119
|
}
|
|
120
120
|
/** 生成数值展示属性。 */
|
|
121
121
|
export declare function getStepperValueProps(): StepperValueProps;
|
|
122
|
+
/** 一次步进方向。适配层只运输激活,不预算下一个数值。 */
|
|
123
|
+
export type StepperDirection = "increment" | "decrement";
|
|
124
|
+
/**
|
|
125
|
+
* 取消标记。Core 在微任务里读 `defaultPrevented`,宿主冒泡阶段的 preventDefault 能赶上。
|
|
126
|
+
* 传入点击事件本身即可。
|
|
127
|
+
*/
|
|
128
|
+
export interface StepperStepNotice {
|
|
129
|
+
readonly defaultPrevented: boolean;
|
|
130
|
+
}
|
|
131
|
+
/** 受控时是调用方原值,非受控时是内部模型。 */
|
|
132
|
+
export interface StepperModelSnapshot {
|
|
133
|
+
value: number;
|
|
134
|
+
}
|
|
135
|
+
export interface StepperModelOptions {
|
|
136
|
+
/** 未被取消的步进提交后调用,供适配层重绘。提交时读取当前属性。 */
|
|
137
|
+
onCommit?: () => void;
|
|
138
|
+
/** 非受控重连快照。仅当创建时未传 `value`,且 `value` 为 number 时覆盖初始模型。 */
|
|
139
|
+
snapshot?: {
|
|
140
|
+
value?: unknown;
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
export interface StepperModel {
|
|
144
|
+
/** 当前画面状态(数值已 clamp)。 */
|
|
145
|
+
readonly state: ResolvedStepperState;
|
|
146
|
+
/** 受控:调用方原值(可以未经 clamp)。非受控:内部模型。 */
|
|
147
|
+
readonly modelValue: number;
|
|
148
|
+
readonly controlled: boolean;
|
|
149
|
+
update(props: QwStepperProps): void;
|
|
150
|
+
request(direction: StepperDirection, notice: StepperStepNotice): void;
|
|
151
|
+
/** 恢复接收步进。stop 之前已经排队的请求仍然作废。 */
|
|
152
|
+
start(): void;
|
|
153
|
+
/** 作废尚未提交的步进。 */
|
|
154
|
+
stop(): void;
|
|
155
|
+
snapshot(): StepperModelSnapshot;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 步进器的行为源。下一步在提交时按当时的模型计算:同一次任务里连续激活会依次累计,
|
|
159
|
+
* 而不是共用渲染当时预算的同一个 next。取消只看提交时的 defaultPrevented、禁用和 stop。
|
|
160
|
+
*/
|
|
161
|
+
export declare function createStepperModel(props?: QwStepperProps, options?: StepperModelOptions): StepperModel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./steps.js";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/steps/steps.ts
|
|
2
|
+
/** Ordered sequence contract; business navigation stays with the caller. */
|
|
3
|
+
const STEP_STATUSES = [
|
|
4
|
+
"wait",
|
|
5
|
+
"process",
|
|
6
|
+
"finish",
|
|
7
|
+
"error"
|
|
8
|
+
];
|
|
9
|
+
const STEPS_ORIENTATIONS = ["horizontal", "vertical"];
|
|
10
|
+
function resolveStepsState(props) {
|
|
11
|
+
const input = props.current ?? 0;
|
|
12
|
+
const current = Number.isFinite(input) ? Math.floor(input) : 0;
|
|
13
|
+
return {
|
|
14
|
+
current,
|
|
15
|
+
orientation: props.orientation ?? "horizontal",
|
|
16
|
+
items: props.items.map((item, index) => ({
|
|
17
|
+
...item,
|
|
18
|
+
index,
|
|
19
|
+
current: index === current,
|
|
20
|
+
status: item.status ?? (index < current ? "finish" : index === current ? "process" : "wait")
|
|
21
|
+
}))
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function getStepProps(item) {
|
|
25
|
+
return {
|
|
26
|
+
"data-scope": "steps",
|
|
27
|
+
"data-part": "item",
|
|
28
|
+
"data-value": item.id,
|
|
29
|
+
"data-status": item.status,
|
|
30
|
+
...item.current ? { "aria-current": "step" } : {}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Native semantics are chosen in Core so all integrations render the same controls. */
|
|
34
|
+
function getStepControlTag(props, item) {
|
|
35
|
+
return props.interactive ? item.href ? "a" : "button" : "span";
|
|
36
|
+
}
|
|
37
|
+
function getStepControlProps(props, item) {
|
|
38
|
+
return {
|
|
39
|
+
"data-scope": "steps",
|
|
40
|
+
"data-part": "control",
|
|
41
|
+
...item.current ? { "aria-current": "step" } : {},
|
|
42
|
+
...item.href ? item.disabled ? {
|
|
43
|
+
role: "link",
|
|
44
|
+
"aria-disabled": true,
|
|
45
|
+
tabIndex: -1
|
|
46
|
+
} : { href: item.href } : {
|
|
47
|
+
type: "button",
|
|
48
|
+
disabled: item.disabled ?? false
|
|
49
|
+
},
|
|
50
|
+
onClick(event) {
|
|
51
|
+
if (!props.interactive || item.disabled) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
props.onStepChange?.({
|
|
56
|
+
id: item.id,
|
|
57
|
+
index: item.index,
|
|
58
|
+
current: resolveStepsState(props).current
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Optional interaction moves current semantics to the native control without changing legacy getStepProps. */
|
|
64
|
+
function getStepsItemProps(props, item) {
|
|
65
|
+
const result = getStepProps(item);
|
|
66
|
+
if (props.interactive) delete result["aria-current"];
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
export { STEPS_ORIENTATIONS, STEP_STATUSES, getStepControlProps, getStepControlTag, getStepProps, getStepsItemProps, resolveStepsState };
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/steps/steps.ts"],"sourcesContent":["/** Ordered sequence contract; business navigation stays with the caller. */\nexport const STEP_STATUSES = [\"wait\", \"process\", \"finish\", \"error\"] as const;\nexport const STEPS_ORIENTATIONS = [\"horizontal\", \"vertical\"] as const;\nexport type StepStatus = (typeof STEP_STATUSES)[number];\nexport type StepsOrientation = (typeof STEPS_ORIENTATIONS)[number];\nexport interface StepItem {\n id: string;\n title: string;\n description?: string;\n status?: StepStatus;\n /** Beta: native link destination in interactive mode. */\n href?: string;\n disabled?: boolean;\n}\nexport interface QwStepsProps {\n items: readonly StepItem[];\n /** Zero-based active index; negative means not started. */\n current?: number;\n orientation?: StepsOrientation;\n /** Beta: opt into native controls; current remains caller-owned. */\n interactive?: boolean;\n onStepChange?: (details: StepChangeDetails) => void;\n}\nexport interface ResolvedStepItem extends StepItem {\n index: number;\n status: StepStatus;\n current: boolean;\n}\nexport interface ResolvedStepsState {\n current: number;\n orientation: StepsOrientation;\n items: ResolvedStepItem[];\n}\nexport interface StepProps {\n \"data-scope\": \"steps\";\n \"data-part\": \"item\";\n \"data-value\": string;\n \"data-status\": StepStatus;\n \"aria-current\"?: \"step\";\n}\nexport function resolveStepsState(props: QwStepsProps): ResolvedStepsState {\n const input = props.current ?? 0;\n const current = Number.isFinite(input) ? Math.floor(input) : 0;\n return { current, orientation: props.orientation ?? \"horizontal\", items: props.items.map((item, index) => ({\n ...item, index, current: index === current,\n status: item.status ?? (index < current ? \"finish\" : index === current ? \"process\" : \"wait\"),\n })) };\n}\nexport function getStepProps(item: ResolvedStepItem): StepProps {\n return { \"data-scope\": \"steps\", \"data-part\": \"item\", \"data-value\": item.id, \"data-status\": item.status,\n ...(item.current ? { \"aria-current\": \"step\" as const } : {}) };\n}\n\n/** An activation request; accepting or refusing it belongs to the caller. */\nexport interface StepChangeDetails { id: string; index: number; current: number }\nexport interface StepControlProps {\n \"data-scope\": \"steps\";\n \"data-part\": \"control\";\n \"aria-current\"?: \"step\";\n \"aria-disabled\"?: true;\n disabled?: boolean;\n href?: string;\n role?: \"link\";\n tabIndex?: number;\n type?: \"button\";\n onClick: (event: { preventDefault(): void }) => void;\n}\n/** Native semantics are chosen in Core so all integrations render the same controls. */\nexport function getStepControlTag(props: QwStepsProps, item: StepItem): \"a\" | \"button\" | \"span\" {\n return props.interactive ? item.href ? \"a\" : \"button\" : \"span\";\n}\nexport function getStepControlProps(props: QwStepsProps, item: ResolvedStepItem): StepControlProps {\n return {\n \"data-scope\": \"steps\", \"data-part\": \"control\",\n ...(item.current ? { \"aria-current\": \"step\" as const } : {}),\n ...(item.href ? item.disabled ? { role: \"link\" as const, \"aria-disabled\": true as const, tabIndex: -1 } : { href: item.href }\n : { type: \"button\" as const, disabled: item.disabled ?? false }),\n onClick(event) {\n if (!props.interactive || item.disabled) { event.preventDefault(); return; }\n props.onStepChange?.({ id: item.id, index: item.index, current: resolveStepsState(props).current });\n },\n };\n}\n\n/** Optional interaction moves current semantics to the native control without changing legacy getStepProps. */\nexport function getStepsItemProps(props: QwStepsProps, item: ResolvedStepItem): StepProps {\n const result = getStepProps(item);\n if (props.interactive) delete result[\"aria-current\"];\n return result;\n}\n"],"mappings":";;AACA,MAAa,gBAAgB;CAAC;CAAQ;CAAW;CAAU;AAAO;AAClE,MAAa,qBAAqB,CAAC,cAAc,UAAU;AAsC3D,SAAgB,kBAAkB,OAAyC;CACzE,MAAM,QAAQ,MAAM,WAAW;CAC/B,MAAM,UAAU,OAAO,SAAS,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI;CAC7D,OAAO;EAAE;EAAS,aAAa,MAAM,eAAe;EAAc,OAAO,MAAM,MAAM,KAAK,MAAM,WAAW;GACzG,GAAG;GAAM;GAAO,SAAS,UAAU;GACnC,QAAQ,KAAK,WAAW,QAAQ,UAAU,WAAW,UAAU,UAAU,YAAY;EACvF,EAAE;CAAE;AACN;AACA,SAAgB,aAAa,MAAmC;CAC9D,OAAO;EAAE,cAAc;EAAS,aAAa;EAAQ,cAAc,KAAK;EAAI,eAAe,KAAK;EAC9F,GAAI,KAAK,UAAU,EAAE,gBAAgB,OAAgB,IAAI,CAAC;CAAG;AACjE;;AAiBA,SAAgB,kBAAkB,OAAqB,MAAyC;CAC9F,OAAO,MAAM,cAAc,KAAK,OAAO,MAAM,WAAW;AAC1D;AACA,SAAgB,oBAAoB,OAAqB,MAA0C;CACjG,OAAO;EACL,cAAc;EAAS,aAAa;EACpC,GAAI,KAAK,UAAU,EAAE,gBAAgB,OAAgB,IAAI,CAAC;EAC1D,GAAI,KAAK,OAAO,KAAK,WAAW;GAAE,MAAM;GAAiB,iBAAiB;GAAe,UAAU;EAAG,IAAI,EAAE,MAAM,KAAK,KAAK,IACxH;GAAE,MAAM;GAAmB,UAAU,KAAK,YAAY;EAAM;EAChE,QAAQ,OAAO;GACb,IAAI,CAAC,MAAM,eAAe,KAAK,UAAU;IAAE,MAAM,eAAe;IAAG;GAAQ;GAC3E,MAAM,eAAe;IAAE,IAAI,KAAK;IAAI,OAAO,KAAK;IAAO,SAAS,kBAAkB,KAAK,CAAC,CAAC;GAAQ,CAAC;EACpG;CACF;AACF;;AAGA,SAAgB,kBAAkB,OAAqB,MAAmC;CACxF,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,MAAM,aAAa,OAAO,OAAO;CACrC,OAAO;AACT"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Ordered sequence contract; business navigation stays with the caller. */
|
|
2
|
+
export declare const STEP_STATUSES: readonly ["wait", "process", "finish", "error"];
|
|
3
|
+
export declare const STEPS_ORIENTATIONS: readonly ["horizontal", "vertical"];
|
|
4
|
+
export type StepStatus = (typeof STEP_STATUSES)[number];
|
|
5
|
+
export type StepsOrientation = (typeof STEPS_ORIENTATIONS)[number];
|
|
6
|
+
export interface StepItem {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
status?: StepStatus;
|
|
11
|
+
/** Beta: native link destination in interactive mode. */
|
|
12
|
+
href?: string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface QwStepsProps {
|
|
16
|
+
items: readonly StepItem[];
|
|
17
|
+
/** Zero-based active index; negative means not started. */
|
|
18
|
+
current?: number;
|
|
19
|
+
orientation?: StepsOrientation;
|
|
20
|
+
/** Beta: opt into native controls; current remains caller-owned. */
|
|
21
|
+
interactive?: boolean;
|
|
22
|
+
onStepChange?: (details: StepChangeDetails) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface ResolvedStepItem extends StepItem {
|
|
25
|
+
index: number;
|
|
26
|
+
status: StepStatus;
|
|
27
|
+
current: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface ResolvedStepsState {
|
|
30
|
+
current: number;
|
|
31
|
+
orientation: StepsOrientation;
|
|
32
|
+
items: ResolvedStepItem[];
|
|
33
|
+
}
|
|
34
|
+
export interface StepProps {
|
|
35
|
+
"data-scope": "steps";
|
|
36
|
+
"data-part": "item";
|
|
37
|
+
"data-value": string;
|
|
38
|
+
"data-status": StepStatus;
|
|
39
|
+
"aria-current"?: "step";
|
|
40
|
+
}
|
|
41
|
+
export declare function resolveStepsState(props: QwStepsProps): ResolvedStepsState;
|
|
42
|
+
export declare function getStepProps(item: ResolvedStepItem): StepProps;
|
|
43
|
+
/** An activation request; accepting or refusing it belongs to the caller. */
|
|
44
|
+
export interface StepChangeDetails {
|
|
45
|
+
id: string;
|
|
46
|
+
index: number;
|
|
47
|
+
current: number;
|
|
48
|
+
}
|
|
49
|
+
export interface StepControlProps {
|
|
50
|
+
"data-scope": "steps";
|
|
51
|
+
"data-part": "control";
|
|
52
|
+
"aria-current"?: "step";
|
|
53
|
+
"aria-disabled"?: true;
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
href?: string;
|
|
56
|
+
role?: "link";
|
|
57
|
+
tabIndex?: number;
|
|
58
|
+
type?: "button";
|
|
59
|
+
onClick: (event: {
|
|
60
|
+
preventDefault(): void;
|
|
61
|
+
}) => void;
|
|
62
|
+
}
|
|
63
|
+
/** Native semantics are chosen in Core so all integrations render the same controls. */
|
|
64
|
+
export declare function getStepControlTag(props: QwStepsProps, item: StepItem): "a" | "button" | "span";
|
|
65
|
+
export declare function getStepControlProps(props: QwStepsProps, item: ResolvedStepItem): StepControlProps;
|
|
66
|
+
/** Optional interaction moves current semantics to the native control without changing legacy getStepProps. */
|
|
67
|
+
export declare function getStepsItemProps(props: QwStepsProps, item: ResolvedStepItem): StepProps;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sticky.js";
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { createMachine } from "@zag-js/core";
|
|
2
|
+
//#region src/sticky/sticky.ts
|
|
3
|
+
/** Edge of the scrollport the element sticks to. */
|
|
4
|
+
const STICKY_POSITIONS = ["top", "bottom"];
|
|
5
|
+
/** Stable DOM parts shared by every adapter. */
|
|
6
|
+
const STICKY_PARTS = ["root"];
|
|
7
|
+
function resolveStickyState(props = {}) {
|
|
8
|
+
return {
|
|
9
|
+
offset: typeof props.offset === "number" && Number.isFinite(props.offset) && props.offset > 0 ? props.offset : 0,
|
|
10
|
+
position: STICKY_POSITIONS.includes(props.position) ? props.position : "top",
|
|
11
|
+
scrollContainer: typeof props.scrollContainer === "string" && props.scrollContainer.trim() ? props.scrollContainer : void 0
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A native sticky box that has scrolled is stuck exactly when it sits on its offset line;
|
|
16
|
+
* an unstuck box moves with the content, so the coincidence tolerance is sub-pixel.
|
|
17
|
+
*/
|
|
18
|
+
function computeStickyStuck(state, m) {
|
|
19
|
+
return state.position === "top" ? m.scrolledBefore > 0 && Math.abs(m.rootStart - (m.portStart + state.offset)) < 1 : m.scrolledAfter > 0 && Math.abs(m.rootEnd - (m.portEnd - state.offset)) < 1;
|
|
20
|
+
}
|
|
21
|
+
function createStickyProps(props = {}) {
|
|
22
|
+
if (props.id !== void 0 && (typeof props.id !== "string" || !props.id.trim())) throw new TypeError("Sticky requires a nonempty instance id when provided");
|
|
23
|
+
return { ...props };
|
|
24
|
+
}
|
|
25
|
+
const rootId = (scope) => `sticky:${scope.id}`;
|
|
26
|
+
const live = (service) => resolveStickyState({
|
|
27
|
+
offset: service.prop("offset"),
|
|
28
|
+
position: service.prop("position"),
|
|
29
|
+
scrollContainer: service.prop("scrollContainer")
|
|
30
|
+
});
|
|
31
|
+
/** Platform boundary: resolve the scrollport and measure. Only called from the client effect. */
|
|
32
|
+
function measure(root, state) {
|
|
33
|
+
const win = root.ownerDocument.defaultView;
|
|
34
|
+
const port = state.scrollContainer ? root.parentElement?.closest(state.scrollContainer) ?? null : null;
|
|
35
|
+
const rect = root.getBoundingClientRect();
|
|
36
|
+
if (port) {
|
|
37
|
+
const box = port.getBoundingClientRect();
|
|
38
|
+
return computeStickyStuck(state, {
|
|
39
|
+
rootStart: rect.top,
|
|
40
|
+
rootEnd: rect.bottom,
|
|
41
|
+
portStart: box.top + port.clientTop,
|
|
42
|
+
portEnd: box.top + port.clientTop + port.clientHeight,
|
|
43
|
+
scrolledBefore: port.scrollTop,
|
|
44
|
+
scrolledAfter: port.scrollHeight - port.clientHeight - port.scrollTop
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const doc = root.ownerDocument.documentElement, y = win?.scrollY ?? doc.scrollTop, height = win?.innerHeight ?? doc.clientHeight;
|
|
48
|
+
return computeStickyStuck(state, {
|
|
49
|
+
rootStart: rect.top,
|
|
50
|
+
rootEnd: rect.bottom,
|
|
51
|
+
portStart: 0,
|
|
52
|
+
portEnd: height,
|
|
53
|
+
scrolledBefore: y,
|
|
54
|
+
scrolledAfter: doc.scrollHeight - height - y
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Core owns listening, rAF throttling, transition-only notification and cleanup. */
|
|
58
|
+
const stickyMachine = createMachine({
|
|
59
|
+
props: ({ props }) => createStickyProps(props),
|
|
60
|
+
initialState: () => "ready",
|
|
61
|
+
states: { ready: {} },
|
|
62
|
+
context: ({ bindable, prop }) => ({ stuck: bindable(() => ({
|
|
63
|
+
defaultValue: false,
|
|
64
|
+
onChange(stuck) {
|
|
65
|
+
prop("onStuckChange")?.({ stuck });
|
|
66
|
+
}
|
|
67
|
+
})) }),
|
|
68
|
+
refs: () => ({ schedule: null }),
|
|
69
|
+
watch({ track, prop, action }) {
|
|
70
|
+
track([
|
|
71
|
+
() => prop("offset"),
|
|
72
|
+
() => prop("position"),
|
|
73
|
+
() => prop("scrollContainer")
|
|
74
|
+
], () => action(["remeasure"]));
|
|
75
|
+
},
|
|
76
|
+
on: { "STUCK.SET": { actions: ["setStuck"] } },
|
|
77
|
+
effects: ["trackStuck"],
|
|
78
|
+
implementations: {
|
|
79
|
+
actions: {
|
|
80
|
+
setStuck(params) {
|
|
81
|
+
if (params.event.type === "STUCK.SET") params.context.set("stuck", params.event.stuck);
|
|
82
|
+
},
|
|
83
|
+
remeasure(params) {
|
|
84
|
+
params.refs.get("schedule")?.();
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
effects: { trackStuck({ scope, prop, send, context, refs }) {
|
|
88
|
+
const root = scope.getById(rootId(scope)), win = root?.ownerDocument.defaultView;
|
|
89
|
+
if (!root || !win) return;
|
|
90
|
+
let frame = 0, port = null, disposed = false;
|
|
91
|
+
const attach = () => {
|
|
92
|
+
const state = live({ prop });
|
|
93
|
+
const next = state.scrollContainer ? root.parentElement?.closest(state.scrollContainer) ?? win : win;
|
|
94
|
+
if (next === port) return;
|
|
95
|
+
port?.removeEventListener("scroll", schedule);
|
|
96
|
+
port = next;
|
|
97
|
+
port.addEventListener("scroll", schedule, { passive: true });
|
|
98
|
+
};
|
|
99
|
+
const run = () => {
|
|
100
|
+
frame = 0;
|
|
101
|
+
if (disposed || !root.isConnected) return;
|
|
102
|
+
attach();
|
|
103
|
+
const stuck = measure(root, live({ prop }));
|
|
104
|
+
if (stuck !== context.get("stuck")) send({
|
|
105
|
+
type: "STUCK.SET",
|
|
106
|
+
stuck
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
function schedule() {
|
|
110
|
+
if (!frame && !disposed) frame = win.requestAnimationFrame(run);
|
|
111
|
+
}
|
|
112
|
+
attach();
|
|
113
|
+
win.addEventListener("resize", schedule, { passive: true });
|
|
114
|
+
schedule();
|
|
115
|
+
refs.set("schedule", schedule);
|
|
116
|
+
return () => {
|
|
117
|
+
disposed = true;
|
|
118
|
+
refs.set("schedule", null);
|
|
119
|
+
if (frame) win.cancelAnimationFrame(frame);
|
|
120
|
+
port?.removeEventListener("scroll", schedule);
|
|
121
|
+
win.removeEventListener("resize", schedule);
|
|
122
|
+
};
|
|
123
|
+
} }
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
function connectSticky(service, normalize) {
|
|
127
|
+
const state = live(service), stuck = service.context.get("stuck");
|
|
128
|
+
return {
|
|
129
|
+
stuck,
|
|
130
|
+
position: state.position,
|
|
131
|
+
offset: state.offset,
|
|
132
|
+
getRootProps: () => normalize.element({
|
|
133
|
+
"data-scope": "sticky",
|
|
134
|
+
"data-part": "root",
|
|
135
|
+
id: rootId(service.scope),
|
|
136
|
+
"data-position": state.position,
|
|
137
|
+
"data-stuck": stuck ? "true" : void 0,
|
|
138
|
+
style: { "--qw-sticky-offset": `${state.offset}px` }
|
|
139
|
+
})
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
export { STICKY_PARTS, STICKY_POSITIONS, computeStickyStuck, connectSticky, createStickyProps, resolveStickyState, stickyMachine };
|
|
144
|
+
|
|
145
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/sticky/sticky.ts"],"sourcesContent":["import { createMachine, type Machine, type Service } from \"@zag-js/core\";\nimport type { NormalizeProps, PropTypes } from \"@zag-js/types\";\n\n/** Edge of the scrollport the element sticks to. */\nexport const STICKY_POSITIONS = [\"top\", \"bottom\"] as const;\n/** Stable DOM parts shared by every adapter. */\nexport const STICKY_PARTS = [\"root\"] as const;\nexport type StickyPosition = (typeof STICKY_POSITIONS)[number];\nexport interface StickyStuckChangeDetails { stuck: boolean }\n/** SSR-safe input shared by all adapters. Positioning is native `position: sticky`. */\nexport interface QwStickyProps {\n /** Page-unique instance identity; adapters generate one when omitted. */\n id?: string;\n /** Distance in CSS pixels from the chosen scrollport edge; nonfinite/negative is 0. */\n offset?: number;\n position?: StickyPosition;\n /** CSS selector of the scrolling ancestor, matched with `closest()`; omitted means the viewport. */\n scrollContainer?: string;\n /** Called only when the measured stuck state changes. */\n onStuckChange?: (details: StickyStuckChangeDetails) => void;\n}\nexport interface ResolvedStickyState { offset: number; position: StickyPosition; scrollContainer: string | undefined }\nexport function resolveStickyState(props: QwStickyProps = {}): ResolvedStickyState {\n const offset = typeof props.offset === \"number\" && Number.isFinite(props.offset) && props.offset > 0 ? props.offset : 0;\n return { offset, position: STICKY_POSITIONS.includes(props.position!) ? props.position! : \"top\",\n scrollContainer: typeof props.scrollContainer === \"string\" && props.scrollContainer.trim() ? props.scrollContainer : undefined };\n}\n/** Geometry snapshot read by the platform effect. `before`/`after` are remaining scroll distances. */\nexport interface StickyMeasurement {\n rootStart: number; rootEnd: number; portStart: number; portEnd: number; scrolledBefore: number; scrolledAfter: number;\n}\n/**\n * A native sticky box that has scrolled is stuck exactly when it sits on its offset line;\n * an unstuck box moves with the content, so the coincidence tolerance is sub-pixel.\n */\nexport function computeStickyStuck(state: ResolvedStickyState, m: StickyMeasurement): boolean {\n return state.position === \"top\"\n ? m.scrolledBefore > 0 && Math.abs(m.rootStart - (m.portStart + state.offset)) < 1\n : m.scrolledAfter > 0 && Math.abs(m.rootEnd - (m.portEnd - state.offset)) < 1;\n}\nexport function createStickyProps(props: QwStickyProps = {}): QwStickyProps {\n if (props.id !== undefined && (typeof props.id !== \"string\" || !props.id.trim())) throw new TypeError(\"Sticky requires a nonempty instance id when provided\");\n return { ...props };\n}\n\nexport interface QwStickySchema {\n props: QwStickyProps;\n context: { stuck: boolean };\n refs: { schedule: (() => void) | null };\n state: \"ready\";\n action: \"setStuck\" | \"remeasure\";\n effect: \"trackStuck\";\n event: { type: \"STUCK.SET\"; stuck: boolean };\n}\nexport type QwStickyMachine = Machine<QwStickySchema>;\nexport type QwStickyService = Service<QwStickySchema>;\nconst rootId = (scope: QwStickyService[\"scope\"]) => `sticky:${scope.id}`;\nconst live = (service: Pick<QwStickyService, \"prop\">) => resolveStickyState({ offset: service.prop(\"offset\"), position: service.prop(\"position\"), scrollContainer: service.prop(\"scrollContainer\") });\n\n/** Platform boundary: resolve the scrollport and measure. Only called from the client effect. */\nfunction measure(root: HTMLElement, state: ResolvedStickyState): boolean {\n const win = root.ownerDocument.defaultView;\n const port = state.scrollContainer ? root.parentElement?.closest<HTMLElement>(state.scrollContainer) ?? null : null;\n const rect = root.getBoundingClientRect();\n if (port) {\n const box = port.getBoundingClientRect();\n return computeStickyStuck(state, { rootStart: rect.top, rootEnd: rect.bottom, portStart: box.top + port.clientTop, portEnd: box.top + port.clientTop + port.clientHeight,\n scrolledBefore: port.scrollTop, scrolledAfter: port.scrollHeight - port.clientHeight - port.scrollTop });\n }\n const doc = root.ownerDocument.documentElement, y = win?.scrollY ?? doc.scrollTop, height = win?.innerHeight ?? doc.clientHeight;\n return computeStickyStuck(state, { rootStart: rect.top, rootEnd: rect.bottom, portStart: 0, portEnd: height, scrolledBefore: y, scrolledAfter: doc.scrollHeight - height - y });\n}\n\n/** Core owns listening, rAF throttling, transition-only notification and cleanup. */\nexport const stickyMachine: QwStickyMachine = createMachine<QwStickySchema>({\n props: ({ props }) => createStickyProps(props), initialState: () => \"ready\", states: { ready: {} },\n context: ({ bindable, prop }) => ({\n stuck: bindable(() => ({ defaultValue: false, onChange(stuck) { prop(\"onStuckChange\")?.({ stuck }); } })),\n }),\n refs: () => ({ schedule: null }),\n watch({ track, prop, action }) { track([() => prop(\"offset\"), () => prop(\"position\"), () => prop(\"scrollContainer\")], () => action([\"remeasure\"])); },\n on: { \"STUCK.SET\": { actions: [\"setStuck\"] } },\n effects: [\"trackStuck\"],\n implementations: {\n actions: {\n setStuck(params) { if (params.event.type === \"STUCK.SET\") params.context.set(\"stuck\", params.event.stuck); },\n remeasure(params) { params.refs.get(\"schedule\")?.(); },\n },\n effects: { trackStuck({ scope, prop, send, context, refs }) {\n const root = scope.getById<HTMLElement>(rootId(scope)), win = root?.ownerDocument.defaultView;\n if (!root || !win) return;\n let frame = 0, port: EventTarget | null = null, disposed = false;\n const attach = () => {\n const state = live({ prop });\n const next: EventTarget = state.scrollContainer ? root.parentElement?.closest(state.scrollContainer) ?? win : win;\n if (next === port) return;\n port?.removeEventListener(\"scroll\", schedule); port = next; port.addEventListener(\"scroll\", schedule, { passive: true });\n };\n const run = () => { frame = 0; if (disposed || !root.isConnected) return; attach(); const stuck = measure(root, live({ prop })); if (stuck !== context.get(\"stuck\")) send({ type: \"STUCK.SET\", stuck }); };\n function schedule() { if (!frame && !disposed) frame = win!.requestAnimationFrame(run); }\n attach(); win.addEventListener(\"resize\", schedule, { passive: true }); schedule();\n refs.set(\"schedule\", schedule);\n return () => { disposed = true; refs.set(\"schedule\", null); if (frame) win.cancelAnimationFrame(frame); port?.removeEventListener(\"scroll\", schedule); win.removeEventListener(\"resize\", schedule); };\n } },\n },\n});\n\nexport interface QwStickyApi<T extends PropTypes = PropTypes> {\n stuck: boolean; position: StickyPosition; offset: number;\n getRootProps(): T[\"element\"];\n}\nexport function connectSticky<T extends PropTypes>(service: QwStickyService, normalize: NormalizeProps<T>): QwStickyApi<T> {\n const state = live(service), stuck = service.context.get(\"stuck\");\n return { stuck, position: state.position, offset: state.offset,\n getRootProps: () => normalize.element({ \"data-scope\": \"sticky\", \"data-part\": \"root\", id: rootId(service.scope), \"data-position\": state.position, \"data-stuck\": stuck ? \"true\" : undefined,\n style: { \"--qw-sticky-offset\": `${state.offset}px` } }) };\n}\n"],"mappings":";;;AAIA,MAAa,mBAAmB,CAAC,OAAO,QAAQ;;AAEhD,MAAa,eAAe,CAAC,MAAM;AAgBnC,SAAgB,mBAAmB,QAAuB,CAAC,GAAwB;CAEjF,OAAO;EAAE,QADM,OAAO,MAAM,WAAW,YAAY,OAAO,SAAS,MAAM,MAAM,KAAK,MAAM,SAAS,IAAI,MAAM,SAAS;EACrG,UAAU,iBAAiB,SAAS,MAAM,QAAS,IAAI,MAAM,WAAY;EACxF,iBAAiB,OAAO,MAAM,oBAAoB,YAAY,MAAM,gBAAgB,KAAK,IAAI,MAAM,kBAAkB,KAAA;CAAU;AACnI;;;;;AASA,SAAgB,mBAAmB,OAA4B,GAA+B;CAC5F,OAAO,MAAM,aAAa,QACtB,EAAE,iBAAiB,KAAK,KAAK,IAAI,EAAE,aAAa,EAAE,YAAY,MAAM,OAAO,IAAI,IAC/E,EAAE,gBAAgB,KAAK,KAAK,IAAI,EAAE,WAAW,EAAE,UAAU,MAAM,OAAO,IAAI;AAChF;AACA,SAAgB,kBAAkB,QAAuB,CAAC,GAAkB;CAC1E,IAAI,MAAM,OAAO,KAAA,MAAc,OAAO,MAAM,OAAO,YAAY,CAAC,MAAM,GAAG,KAAK,IAAI,MAAM,IAAI,UAAU,sDAAsD;CAC5J,OAAO,EAAE,GAAG,MAAM;AACpB;AAaA,MAAM,UAAU,UAAoC,UAAU,MAAM;AACpE,MAAM,QAAQ,YAA2C,mBAAmB;CAAE,QAAQ,QAAQ,KAAK,QAAQ;CAAG,UAAU,QAAQ,KAAK,UAAU;CAAG,iBAAiB,QAAQ,KAAK,iBAAiB;AAAE,CAAC;;AAGpM,SAAS,QAAQ,MAAmB,OAAqC;CACvE,MAAM,MAAM,KAAK,cAAc;CAC/B,MAAM,OAAO,MAAM,kBAAkB,KAAK,eAAe,QAAqB,MAAM,eAAe,KAAK,OAAO;CAC/G,MAAM,OAAO,KAAK,sBAAsB;CACxC,IAAI,MAAM;EACR,MAAM,MAAM,KAAK,sBAAsB;EACvC,OAAO,mBAAmB,OAAO;GAAE,WAAW,KAAK;GAAK,SAAS,KAAK;GAAQ,WAAW,IAAI,MAAM,KAAK;GAAW,SAAS,IAAI,MAAM,KAAK,YAAY,KAAK;GAC1J,gBAAgB,KAAK;GAAW,eAAe,KAAK,eAAe,KAAK,eAAe,KAAK;EAAU,CAAC;CAC3G;CACA,MAAM,MAAM,KAAK,cAAc,iBAAiB,IAAI,KAAK,WAAW,IAAI,WAAW,SAAS,KAAK,eAAe,IAAI;CACpH,OAAO,mBAAmB,OAAO;EAAE,WAAW,KAAK;EAAK,SAAS,KAAK;EAAQ,WAAW;EAAG,SAAS;EAAQ,gBAAgB;EAAG,eAAe,IAAI,eAAe,SAAS;CAAE,CAAC;AAChL;;AAGA,MAAa,gBAAiC,cAA8B;CAC1E,QAAQ,EAAE,YAAY,kBAAkB,KAAK;CAAG,oBAAoB;CAAS,QAAQ,EAAE,OAAO,CAAC,EAAE;CACjG,UAAU,EAAE,UAAU,YAAY,EAChC,OAAO,gBAAgB;EAAE,cAAc;EAAO,SAAS,OAAO;GAAE,KAAK,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC;EAAG;CAAE,EAAE,EAC1G;CACA,aAAa,EAAE,UAAU,KAAK;CAC9B,MAAM,EAAE,OAAO,MAAM,UAAU;EAAE,MAAM;SAAO,KAAK,QAAQ;SAAS,KAAK,UAAU;SAAS,KAAK,iBAAiB;EAAC,SAAS,OAAO,CAAC,WAAW,CAAC,CAAC;CAAG;CACpJ,IAAI,EAAE,aAAa,EAAE,SAAS,CAAC,UAAU,EAAE,EAAE;CAC7C,SAAS,CAAC,YAAY;CACtB,iBAAiB;EACf,SAAS;GACP,SAAS,QAAQ;IAAE,IAAI,OAAO,MAAM,SAAS,aAAa,OAAO,QAAQ,IAAI,SAAS,OAAO,MAAM,KAAK;GAAG;GAC3G,UAAU,QAAQ;IAAE,OAAO,KAAK,IAAI,UAAU,CAAC,GAAG;GAAG;EACvD;EACA,SAAS,EAAE,WAAW,EAAE,OAAO,MAAM,MAAM,SAAS,QAAQ;GAC1D,MAAM,OAAO,MAAM,QAAqB,OAAO,KAAK,CAAC,GAAG,MAAM,MAAM,cAAc;GAClF,IAAI,CAAC,QAAQ,CAAC,KAAK;GACnB,IAAI,QAAQ,GAAG,OAA2B,MAAM,WAAW;GAC3D,MAAM,eAAe;IACnB,MAAM,QAAQ,KAAK,EAAE,KAAK,CAAC;IAC3B,MAAM,OAAoB,MAAM,kBAAkB,KAAK,eAAe,QAAQ,MAAM,eAAe,KAAK,MAAM;IAC9G,IAAI,SAAS,MAAM;IACnB,MAAM,oBAAoB,UAAU,QAAQ;IAAG,OAAO;IAAM,KAAK,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;GACzH;GACA,MAAM,YAAY;IAAE,QAAQ;IAAG,IAAI,YAAY,CAAC,KAAK,aAAa;IAAQ,OAAO;IAAG,MAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE,KAAK,CAAC,CAAC;IAAG,IAAI,UAAU,QAAQ,IAAI,OAAO,GAAG,KAAK;KAAE,MAAM;KAAa;IAAM,CAAC;GAAG;GACzM,SAAS,WAAW;IAAE,IAAI,CAAC,SAAS,CAAC,UAAU,QAAQ,IAAK,sBAAsB,GAAG;GAAG;GACxF,OAAO;GAAG,IAAI,iBAAiB,UAAU,UAAU,EAAE,SAAS,KAAK,CAAC;GAAG,SAAS;GAChF,KAAK,IAAI,YAAY,QAAQ;GAC7B,aAAa;IAAE,WAAW;IAAM,KAAK,IAAI,YAAY,IAAI;IAAG,IAAI,OAAO,IAAI,qBAAqB,KAAK;IAAG,MAAM,oBAAoB,UAAU,QAAQ;IAAG,IAAI,oBAAoB,UAAU,QAAQ;GAAG;EACtM,EAAE;CACJ;AACF,CAAC;AAMD,SAAgB,cAAmC,SAA0B,WAA8C;CACzH,MAAM,QAAQ,KAAK,OAAO,GAAG,QAAQ,QAAQ,QAAQ,IAAI,OAAO;CAChE,OAAO;EAAE;EAAO,UAAU,MAAM;EAAU,QAAQ,MAAM;EACtD,oBAAoB,UAAU,QAAQ;GAAE,cAAc;GAAU,aAAa;GAAQ,IAAI,OAAO,QAAQ,KAAK;GAAG,iBAAiB,MAAM;GAAU,cAAc,QAAQ,SAAS,KAAA;GAC9K,OAAO,EAAE,sBAAsB,GAAG,MAAM,OAAO,IAAI;EAAE,CAAC;CAAE;AAC9D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type Machine, type Service } from "@zag-js/core";
|
|
2
|
+
import type { NormalizeProps, PropTypes } from "@zag-js/types";
|
|
3
|
+
/** Edge of the scrollport the element sticks to. */
|
|
4
|
+
export declare const STICKY_POSITIONS: readonly ["top", "bottom"];
|
|
5
|
+
/** Stable DOM parts shared by every adapter. */
|
|
6
|
+
export declare const STICKY_PARTS: readonly ["root"];
|
|
7
|
+
export type StickyPosition = (typeof STICKY_POSITIONS)[number];
|
|
8
|
+
export interface StickyStuckChangeDetails {
|
|
9
|
+
stuck: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** SSR-safe input shared by all adapters. Positioning is native `position: sticky`. */
|
|
12
|
+
export interface QwStickyProps {
|
|
13
|
+
/** Page-unique instance identity; adapters generate one when omitted. */
|
|
14
|
+
id?: string;
|
|
15
|
+
/** Distance in CSS pixels from the chosen scrollport edge; nonfinite/negative is 0. */
|
|
16
|
+
offset?: number;
|
|
17
|
+
position?: StickyPosition;
|
|
18
|
+
/** CSS selector of the scrolling ancestor, matched with `closest()`; omitted means the viewport. */
|
|
19
|
+
scrollContainer?: string;
|
|
20
|
+
/** Called only when the measured stuck state changes. */
|
|
21
|
+
onStuckChange?: (details: StickyStuckChangeDetails) => void;
|
|
22
|
+
}
|
|
23
|
+
export interface ResolvedStickyState {
|
|
24
|
+
offset: number;
|
|
25
|
+
position: StickyPosition;
|
|
26
|
+
scrollContainer: string | undefined;
|
|
27
|
+
}
|
|
28
|
+
export declare function resolveStickyState(props?: QwStickyProps): ResolvedStickyState;
|
|
29
|
+
/** Geometry snapshot read by the platform effect. `before`/`after` are remaining scroll distances. */
|
|
30
|
+
export interface StickyMeasurement {
|
|
31
|
+
rootStart: number;
|
|
32
|
+
rootEnd: number;
|
|
33
|
+
portStart: number;
|
|
34
|
+
portEnd: number;
|
|
35
|
+
scrolledBefore: number;
|
|
36
|
+
scrolledAfter: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A native sticky box that has scrolled is stuck exactly when it sits on its offset line;
|
|
40
|
+
* an unstuck box moves with the content, so the coincidence tolerance is sub-pixel.
|
|
41
|
+
*/
|
|
42
|
+
export declare function computeStickyStuck(state: ResolvedStickyState, m: StickyMeasurement): boolean;
|
|
43
|
+
export declare function createStickyProps(props?: QwStickyProps): QwStickyProps;
|
|
44
|
+
export interface QwStickySchema {
|
|
45
|
+
props: QwStickyProps;
|
|
46
|
+
context: {
|
|
47
|
+
stuck: boolean;
|
|
48
|
+
};
|
|
49
|
+
refs: {
|
|
50
|
+
schedule: (() => void) | null;
|
|
51
|
+
};
|
|
52
|
+
state: "ready";
|
|
53
|
+
action: "setStuck" | "remeasure";
|
|
54
|
+
effect: "trackStuck";
|
|
55
|
+
event: {
|
|
56
|
+
type: "STUCK.SET";
|
|
57
|
+
stuck: boolean;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export type QwStickyMachine = Machine<QwStickySchema>;
|
|
61
|
+
export type QwStickyService = Service<QwStickySchema>;
|
|
62
|
+
/** Core owns listening, rAF throttling, transition-only notification and cleanup. */
|
|
63
|
+
export declare const stickyMachine: QwStickyMachine;
|
|
64
|
+
export interface QwStickyApi<T extends PropTypes = PropTypes> {
|
|
65
|
+
stuck: boolean;
|
|
66
|
+
position: StickyPosition;
|
|
67
|
+
offset: number;
|
|
68
|
+
getRootProps(): T["element"];
|
|
69
|
+
}
|
|
70
|
+
export declare function connectSticky<T extends PropTypes>(service: QwStickyService, normalize: NormalizeProps<T>): QwStickyApi<T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./swipe-action.js";
|