@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 @@
|
|
|
1
|
+
{"version":3,"file":"popup-z5d8IYCt.js","names":[],"sources":["../src/modal-render-scope.ts","../src/modal-render-runtime.ts","../src/popup/popup.ts"],"sourcesContent":["/** A request-local declaration scope. It never accesses DOM or the client registry. */\nexport type ModalRenderKind = \"dialog\" | \"popup\";\n/** A finite logical WC host identity; the physical modal remains Popup. */\nexport type ModalRenderOwner = \"wc:action-sheet\" | \"wc:picker\";\n\n/** JSON bootstrap data. A rejected initial request has a non-null foreign owner. */\nexport interface ModalRenderTicket {\n id: string;\n kind: ModalRenderKind;\n owner?: ModalRenderOwner;\n pageSeed: string;\n ordinal: number;\n initialAdmitted: boolean;\n initialOwnerId: string | null;\n /** Native framework render identity, scoped to one root bootstrap list. */\n declarationKey?: string;\n /** False for SSR markup stored in an inert platform template. */\n initialActive?: boolean;\n}\n\nexport interface ModalRenderScopeOptions { pageSeed?: string }\nexport type ModalRenderPhase = \"server\" | \"client\";\n/** A mount session; ordinal guards identity reuse, session guards effect replay. */\nexport interface ModalRenderLease { id: string; ordinal: number; session: number; admitted: boolean }\n\nexport interface ModalRenderScope {\n readonly pageSeed: string;\n readonly tickets: readonly ModalRenderTicket[];\n allocate(kind: ModalRenderKind, explicitId?: string, wantsOpen?: boolean, phase?: ModalRenderPhase, declarationKey?: string, initialActive?: boolean, owner?: ModalRenderOwner): ModalRenderTicket;\n acquire(ticket: ModalRenderTicket, wantsOpen: boolean, claimant?: object): ModalRenderLease;\n syncLease(lease: ModalRenderLease, open: boolean): boolean;\n releaseLease(lease: ModalRenderLease): boolean;\n adopt(ticket: ModalRenderTicket): ModalRenderTicket;\n /** Called on the first client admission after the complete page bootstrap. */\n completeBootstrap(): void;\n hasOther(id: string, ignored?: readonly string[]): boolean;\n isServerTicket(ticket: ModalRenderTicket): boolean;\n sync(id: string, kind: ModalRenderKind, open: boolean, ordinal?: number): void;\n release(id: string, ordinal?: number): void;\n notifyInitialRejection(id: string, notify?: (open: false) => void): void;\n}\n\nlet nextSeed = 0;\nfunction nonempty(value: unknown): value is string { return typeof value === \"string\" && value.trim().length > 0; }\nfunction kindValid(value: unknown): value is ModalRenderKind { return value === \"dialog\" || value === \"popup\"; }\nfunction ownerValid(kind: ModalRenderKind, owner: unknown): boolean { return owner === undefined || (kind === \"popup\" && (owner === \"wc:action-sheet\" || owner === \"wc:picker\")); }\nfunction validateTicket(ticket: ModalRenderTicket): void {\n if (!ticket || !ownerValid(ticket.kind, ticket.owner) || !nonempty(ticket.id) || !nonempty(ticket.pageSeed) || !kindValid(ticket.kind) ||\n !Number.isSafeInteger(ticket.ordinal) || ticket.ordinal < 1 || typeof ticket.initialAdmitted !== \"boolean\" ||\n !(ticket.initialOwnerId === null || nonempty(ticket.initialOwnerId)) ||\n (ticket.declarationKey !== undefined && !nonempty(ticket.declarationKey)) ||\n (ticket.initialActive !== undefined && typeof ticket.initialActive !== \"boolean\")) throw new TypeError(\"Invalid modal render ticket\");\n if (ticket.initialAdmitted && ticket.initialOwnerId === null) throw new TypeError(\"Admitted modal requires an initial owner\");\n if (!ticket.initialAdmitted && ticket.initialOwnerId === ticket.id) throw new TypeError(\"Rejected modal cannot own its initial reservation\");\n}\n\n/**\n * Create once per page/request and share across its render roots. Bootstrap\n * tickets before hydrating any root, including roots hydrated in reverse order.\n * Default seeds are non-random identities, never global modal declarations.\n */\nexport function createModalRenderScope(options: ModalRenderScopeOptions = {}): ModalRenderScope {\n if (options.pageSeed !== undefined && !nonempty(options.pageSeed)) throw new TypeError(\"pageSeed must be nonempty\");\n let pageSeed = options.pageSeed ?? `r${++nextSeed}`;\n const explicitSeed = options.pageSeed !== undefined;\n let ordinal = 0;\n let bootstrapComplete = false;\n const records = new Map<string, ModalRenderTicket>();\n const identities = new Map<string, ModalRenderTicket>();\n const speculative = new WeakMap<ModalRenderTicket, ModalRenderTicket>();\n const reservations = new Map<string, ModalRenderKind | null>();\n const retired = new Set<string>();\n const released = new Set<string>();\n const notified = new Set<string>();\n const incarnations = new Map<string, number>();\n const sessions = new Map<string, number>();\n const serverDeclarations = new Map<string, number>();\n const consumedDeclarations = new Map<string, number>();\n const active = new Map<string, ModalRenderLease>();\n const claimants = new Map<string, object>();\n const owns = (lease: ModalRenderLease) => active.get(lease.id)?.session === lease.session && incarnations.get(lease.id) === lease.ordinal;\n const current = (id: string, expected?: number) => expected === undefined || records.get(id)?.ordinal === expected;\n const copy = (ticket: ModalRenderTicket): ModalRenderTicket => ({\n id: ticket.id, kind: ticket.kind, pageSeed: ticket.pageSeed, ordinal: ticket.ordinal,\n initialAdmitted: ticket.initialAdmitted, initialOwnerId: ticket.initialOwnerId,\n ...(ticket.declarationKey !== undefined ? { declarationKey: ticket.declarationKey } : {}),\n ...(ticket.initialActive === false ? { initialActive: false } : {}),\n ...(ticket.owner !== undefined ? { owner: ticket.owner } : {}),\n });\n const reserve = (ticket: ModalRenderTicket) => {\n if (ticket.initialActive === false) return;\n const owner = ticket.initialOwnerId;\n if (owner && !retired.has(owner) && !released.has(owner) && (!bootstrapComplete || reservations.has(owner))) reservations.set(owner, reservations.get(owner) ?? null);\n if (ticket.initialAdmitted && !retired.has(ticket.id) && !released.has(ticket.id)) reservations.set(ticket.id, ticket.kind);\n };\n const completeBootstrap = () => {\n if (bootstrapComplete) return;\n bootstrapComplete = true;\n // Unknown foreign owners temporarily protect out-of-order bootstrap. At\n // client admission all actual page markers must already be adopted. A\n // discarded server subtree has no owner marker and cannot stay reserved.\n for (const [id, kind] of reservations) if (kind === null) reservations.delete(id);\n };\n return {\n get pageSeed() { return pageSeed; },\n get tickets() { return [...records.values()].map(copy); },\n allocate(kind, explicitId, wantsOpen = false, phase = \"server\", declarationKey, initialActive = true, owner) {\n if (!ownerValid(kind, owner) || typeof initialActive !== \"boolean\" || (declarationKey !== undefined && !nonempty(declarationKey)) || (phase !== \"server\" && phase !== \"client\") || !kindValid(kind) || (explicitId !== undefined && !nonempty(explicitId))) throw new TypeError(\"Invalid modal identity\");\n const next = ordinal + 1;\n const id = explicitId ?? `qw-${kind}-${encodeURIComponent(pageSeed)}-${next}`;\n if (records.has(id)) throw new TypeError(`Duplicate modal identity: ${id}`);\n ordinal = next;\n const firstOwner = initialActive ? reservations.keys().next().value ?? null : null;\n const admitted = wantsOpen && (!initialActive || kind === \"dialog\" || firstOwner === null);\n const ticket: ModalRenderTicket = {\n id, kind, pageSeed, ordinal,\n initialAdmitted: admitted,\n initialOwnerId: wantsOpen ? (firstOwner ?? (admitted ? id : null)) : null,\n ...(declarationKey !== undefined ? { declarationKey } : {}),\n ...(!initialActive ? { initialActive: false } : {}),\n ...(owner !== undefined ? { owner } : {}),\n };\n if (phase === \"server\") {\n records.set(id, ticket); identities.set(id, ticket); incarnations.set(id, next);\n retired.delete(id); released.delete(id); notified.delete(id);\n serverDeclarations.set(id, next); reserve(ticket);\n return copy(ticket);\n }\n const result = copy(ticket);\n speculative.set(result, ticket);\n return result;\n },\n adopt(input) {\n validateTicket(input);\n if (pageSeed !== input.pageSeed) {\n if (explicitSeed || ordinal !== 0 || records.size !== 0) throw new TypeError(\"Modal pageSeed mismatch\");\n pageSeed = input.pageSeed;\n }\n const existing = identities.get(input.id);\n const ticket = copy(input);\n if (existing && JSON.stringify(existing) !== JSON.stringify(ticket)) throw new TypeError(\"Conflicting modal ticket\");\n if ([...records.values()].some(record => record.ordinal === ticket.ordinal && record.id !== ticket.id)) throw new TypeError(\"Conflicting modal ordinal\");\n ordinal = Math.max(ordinal, ticket.ordinal);\n if (!released.has(ticket.id)) serverDeclarations.set(ticket.id, ticket.ordinal);\n if (!released.has(ticket.id)) { records.set(ticket.id, ticket); identities.set(ticket.id, ticket); incarnations.set(ticket.id, ticket.ordinal); }\n reserve(ticket);\n return copy(ticket);\n },\n acquire(ticket, wantsOpen, claimant = ticket) {\n validateTicket(ticket);\n if (active.has(ticket.id) && claimants.get(ticket.id) !== claimant) throw new TypeError(`Duplicate modal identity: ${ticket.id}`);\n const previousOrdinal = incarnations.get(ticket.id);\n if (ticket.pageSeed !== pageSeed || (previousOrdinal !== undefined && ticket.ordinal < previousOrdinal)) throw new TypeError(\"Stale modal render ticket\");\n const existing = previousOrdinal === ticket.ordinal ? identities.get(ticket.id) : speculative.get(ticket);\n if (!existing) throw new TypeError(\"Unknown speculative modal ticket\");\n if (JSON.stringify(existing) !== JSON.stringify(copy(ticket))) throw new TypeError(\"Conflicting modal ticket\");\n completeBootstrap();\n if (previousOrdinal !== ticket.ordinal) { notified.delete(ticket.id); consumedDeclarations.delete(ticket.id); }\n records.set(ticket.id, copy(ticket)); identities.set(ticket.id, copy(ticket)); incarnations.set(ticket.id, ticket.ordinal);\n released.delete(ticket.id);\n consumedDeclarations.set(ticket.id, ticket.ordinal);\n const admitted = wantsOpen && (ticket.kind === \"dialog\" || reservations.has(ticket.id) || ![...reservations.keys()].some(id => id !== ticket.id));\n const session = (sessions.get(ticket.id) ?? 0) + 1;\n sessions.set(ticket.id, session);\n const lease = { id: ticket.id, ordinal: ticket.ordinal, session, admitted };\n active.set(ticket.id, lease); claimants.set(ticket.id, claimant);\n if (admitted) { retired.delete(ticket.id); reservations.set(ticket.id, ticket.kind); }\n else { retired.add(ticket.id); reservations.delete(ticket.id); }\n return { ...lease };\n },\n syncLease(lease, open) {\n if (!owns(lease)) return false;\n const ticket = records.get(lease.id)!;\n if (open) { retired.delete(lease.id); reservations.set(lease.id, ticket.kind); }\n else { retired.add(lease.id); reservations.delete(lease.id); }\n return true;\n },\n releaseLease(lease) {\n if (!owns(lease)) return false;\n active.delete(lease.id); claimants.delete(lease.id);\n reservations.delete(lease.id); retired.add(lease.id); released.add(lease.id);\n records.delete(lease.id);\n return true;\n },\n isServerTicket(ticket) { return ticket.initialActive !== false && serverDeclarations.get(ticket.id) === ticket.ordinal && consumedDeclarations.get(ticket.id) !== ticket.ordinal && !retired.has(ticket.id) && !released.has(ticket.id); },\n completeBootstrap,\n hasOther(id, ignored = []) { return [...reservations.keys()].some(owner => owner !== id && !ignored.includes(owner)); },\n sync(id, kind, open, expected) {\n if (!current(id, expected) || released.has(id)) return;\n if (open) { retired.delete(id); reservations.set(id, kind); }\n else { retired.add(id); reservations.delete(id); }\n },\n release(id, expected) {\n if (!current(id, expected)) return;\n reservations.delete(id); retired.add(id); released.add(id);\n records.delete(id); notified.delete(id); active.delete(id); claimants.delete(id);\n },\n notifyInitialRejection(id, notify) {\n const ticket = records.get(id);\n if (!notify || !ticket || notified.has(id) || ticket.kind !== \"popup\" || ticket.initialAdmitted || ticket.initialOwnerId === null) return;\n notified.add(id);\n notify(false);\n },\n };\n}\n\n\n/** Consume one root's declaration tickets in framework render order. */\nexport interface ModalRenderInputs { id?: string; open?: boolean; defaultOpen?: boolean }\nexport function wantsModalOpen(props: ModalRenderInputs): boolean { return props.open === true || (props.open === undefined && props.defaultOpen === true); }\nexport interface ModalTicketCursor {\n takeProps(kind: ModalRenderKind, props: ModalRenderInputs, phase?: ModalRenderPhase, declarationKey?: string, initialActive?: boolean, owner?: ModalRenderOwner): ModalRenderTicket;\n take(kind: ModalRenderKind, explicitId?: string, wantsOpen?: boolean, phase?: ModalRenderPhase, declarationKey?: string, initialActive?: boolean, owner?: ModalRenderOwner): ModalRenderTicket;\n}\nexport function createModalTicketCursor(scope: ModalRenderScope, tickets?: readonly ModalRenderTicket[]): ModalTicketCursor {\n let position = 0;\n const bootstrap = tickets?.map(ticket => scope.adopt(ticket));\n const cache = new Map<string, ModalRenderTicket>();\n const bound = new Set<number>();\n const keyed = bootstrap?.some(ticket => ticket.declarationKey !== undefined) ?? false;\n for (const ticket of bootstrap ?? []) {\n if (ticket.declarationKey === undefined) continue;\n if (cache.has(ticket.declarationKey)) throw new TypeError(\"Duplicate modal root declaration key\");\n cache.set(ticket.declarationKey, ticket);\n }\n function checked(ticket: ModalRenderTicket, kind: ModalRenderKind, explicitId?: string, owner?: ModalRenderOwner): ModalRenderTicket {\n if (ticket.owner !== owner || ticket.kind !== kind || (explicitId !== undefined && ticket.id !== explicitId)) throw new TypeError(\"Modal root ticket order or identity mismatch\");\n bound.add(ticket.ordinal);\n return { ...ticket };\n }\n function take(kind: ModalRenderKind, explicitId?: string, wantsOpen = false, phase: ModalRenderPhase = \"server\", declarationKey?: string, initialActive = true, owner?: ModalRenderOwner): ModalRenderTicket {\n const key = declarationKey ?? explicitId;\n // CSR claims are weak until mounted. Do not retain abandoned component keys.\n if (!bootstrap && phase === \"client\") return scope.allocate(kind, explicitId, wantsOpen, phase, declarationKey, initialActive, owner);\n const previous = key === undefined ? undefined : cache.get(key);\n if (previous) return checked(previous, kind, explicitId, owner);\n if (!bootstrap) {\n const ticket = scope.allocate(kind, explicitId, wantsOpen, phase, declarationKey, initialActive, owner);\n if (key !== undefined) cache.set(key, ticket);\n return ticket;\n }\n const named = explicitId === undefined ? undefined : bootstrap.find(ticket => ticket.id === explicitId);\n if (named) return checked(named, kind, explicitId, owner);\n // Keyed manifests follow native render identity, never hydration visitation\n // order: React can hydrate a sibling before a dehydrated Suspense subtree.\n if (keyed && declarationKey !== undefined) {\n if (phase === \"client\") return scope.allocate(kind, explicitId, wantsOpen, phase, declarationKey, initialActive, owner);\n throw new TypeError(\"Modal root declaration key mismatch\");\n }\n while (bootstrap[position] && bound.has(bootstrap[position]!.ordinal)) position++;\n const ticket = bootstrap[position];\n if (!ticket && phase === \"client\") return scope.allocate(kind, explicitId, wantsOpen, phase, declarationKey, initialActive, owner);\n if (!ticket) throw new TypeError(\"Modal root ticket order or identity mismatch\");\n const result = checked(ticket, kind, explicitId, owner);\n position++;\n if (key !== undefined) cache.set(key, ticket);\n return result;\n }\n return { take, takeProps: (kind, props, phase, declarationKey, initialActive, owner) => take(kind, props.id, wantsModalOpen(props), phase, declarationKey, initialActive, owner) };\n}\n","import { disposeModalSession, hasOtherModal, hasOtherModalExcept, syncModalRegistration } from \"./modal-registry.js\";\nimport { wantsModalOpen, type ModalRenderInputs, type ModalRenderLease, type ModalRenderPhase, type ModalRenderScope, type ModalRenderTicket } from \"./modal-render-scope.js\";\n\n/** Stable per-component transport object. Frameworks mechanically supply phase. */\nexport interface ModalRenderRuntime {\n scope: ModalRenderScope;\n ticket: ModalRenderTicket;\n phase: ModalRenderPhase;\n}\ninterface RuntimeState { lease?: ModalRenderLease; mounted: boolean; notified: boolean; initialPending: boolean; suppressedClose: boolean; open: boolean; initialSynced: boolean; initialRejected: boolean; pendingRejected: boolean; identityInitialized: boolean; explicitId?: string; retiring: { ticket: ModalRenderTicket; lease: ModalRenderLease }[] }\nconst states = new WeakMap<ModalRenderRuntime, RuntimeState>();\nconst registrations = new Map<string, ModalRenderLease>();\nfunction unregisterLease(id: string, lease: ModalRenderLease): void {\n if (registrations.get(id) !== lease) return;\n registrations.delete(id); disposeModalSession(id);\n}\nfunction stateFor(runtime: ModalRenderRuntime): RuntimeState {\n let state = states.get(runtime);\n if (!state) { state = { mounted: false, notified: false, initialPending: true, suppressedClose: false, open: false, initialSynced: false, initialRejected: false, pendingRejected: false, identityInitialized: false, retiring: [] }; states.set(runtime, state); }\n return state;\n}\n\n/** Resolve explicit identity changes without render-time global registration. */\nexport function updateModalRenderIdentity(runtime: ModalRenderRuntime, props: ModalRenderInputs): string {\n const state = stateFor(runtime);\n if (!state.identityInitialized) { state.identityInitialized = true; state.explicitId = props.id; return runtime.ticket.id; }\n if (state.explicitId === props.id) return runtime.ticket.id;\n const previous = runtime.ticket;\n const next = runtime.scope.allocate(previous.kind, props.id, wantsModalOpen(props), runtime.phase, undefined, undefined, previous.owner);\n if (state.lease) state.retiring.push({ ticket: previous, lease: state.lease });\n else runtime.scope.release(previous.id, previous.ordinal);\n runtime.ticket = next;\n state.lease = undefined; state.explicitId = props.id; state.initialPending = false;\n return next.id;\n}\n\nfunction releaseRetiring(runtime: ModalRenderRuntime, state: RuntimeState): void {\n for (const previous of state.retiring) {\n runtime.scope.releaseLease(previous.lease);\n unregisterLease(previous.ticket.id, previous.lease);\n }\n state.retiring = [];\n}\n\n/** Pure server projection; a hydrated first tree follows its declaration ticket. */\nexport function modalRenderBlocked(runtime: ModalRenderRuntime, wantsOpen: boolean): boolean {\n if (runtime.phase === \"client\") runtime.scope.completeBootstrap();\n if (runtime.ticket.kind === \"dialog\") return false;\n if (!wantsOpen) { if (runtime.phase === \"client\") stateFor(runtime).pendingRejected = false; return false; }\n if (runtime.phase === \"server\") return !runtime.ticket.initialAdmitted;\n const state = stateFor(runtime);\n if (state.open || (!state.initialSynced && runtime.scope.isServerTicket(runtime.ticket) && runtime.ticket.initialAdmitted)) return false;\n const blocked = (!state.initialSynced && runtime.scope.isServerTicket(runtime.ticket) && !runtime.ticket.initialAdmitted && runtime.ticket.initialOwnerId !== null) ||\n runtime.scope.hasOther(runtime.ticket.id, state.retiring.map(previous => previous.ticket.id)) || hasOtherModalExcept(runtime.ticket.id, state.retiring.map(previous => previous.ticket.id));\n state.pendingRejected = blocked;\n return blocked;\n}\n\n/** Notify a mounted client request once until a close or successful admission. */\nexport function notifyModalRenderRejection(runtime: ModalRenderRuntime, notify?: (open: false) => void): void {\n if (runtime.phase !== \"client\" || !notify) return;\n const state = stateFor(runtime);\n if (!state.mounted || state.notified) return;\n state.notified = true;\n notify(false);\n}\n\n/** The machine's close projection must not duplicate a rejection already notified. */\nexport function notifyModalRenderOpenChange(runtime: ModalRenderRuntime, open: boolean, notify: (open: boolean) => void): void {\n const state = stateFor(runtime);\n if (!open && state.suppressedClose) { state.suppressedClose = false; return; }\n if (open) state.notified = false;\n notify(open);\n}\n\n/** Mounted/layout transport: acquire atomically, sync both registries, return actual open. */\nexport function syncModalRender(runtime: ModalRenderRuntime, open: boolean, notify?: (open: false) => void): boolean {\n if (runtime.phase === \"server\") return runtime.ticket.initialAdmitted && open;\n const state = stateFor(runtime);\n const { scope, ticket } = runtime;\n scope.completeBootstrap();\n releaseRetiring(runtime, state);\n if (!state.initialSynced) state.initialRejected = scope.isServerTicket(ticket) && !ticket.initialAdmitted && ticket.initialOwnerId !== null;\n const retainAdmission = state.open || (!state.initialSynced && scope.isServerTicket(ticket) && ticket.initialAdmitted);\n if (!state.lease) state.lease = scope.acquire(ticket, open, runtime);\n state.mounted = true;\n const initiallyRejected = state.initialRejected;\n const blocked = ticket.kind === \"popup\" && open && !retainAdmission && (scope.hasOther(ticket.id) || hasOtherModal(ticket.id));\n const actual = open && !blocked;\n if (!scope.syncLease(state.lease, actual)) return false;\n if (actual) { registrations.set(ticket.id, state.lease); syncModalRegistration(ticket.id, ticket.kind, true); }\n else unregisterLease(ticket.id, state.lease);\n state.open = actual; state.initialSynced = true;\n if (blocked) {\n state.suppressedClose = true;\n notifyModalRenderRejection(runtime, notify);\n } else if (state.pendingRejected || (initiallyRejected && state.initialPending)) {\n notifyModalRenderRejection(runtime, notify);\n } else if (actual || !open) state.notified = false;\n if (notify || actual || !initiallyRejected) state.initialPending = false;\n return actual;\n}\n\n/** Session ownership prevents obsolete cleanup from clearing a reacquired ticket. */\nexport function disposeModalRender(runtime: ModalRenderRuntime): void {\n if (runtime.phase === \"server\") return;\n const state = stateFor(runtime);\n releaseRetiring(runtime, state);\n if (state.lease) { runtime.scope.releaseLease(state.lease); unregisterLease(runtime.ticket.id, state.lease); }\n state.lease = undefined;\n state.mounted = false;\n}\n","import {\n connect,\n type Api,\n type OpenChangeDetails,\n type Props as ZagDialogProps,\n type Service,\n type machine,\n} from \"@zag-js/dialog\";\nimport {\n claimRejectedOpenNotice,\n hasOtherModal,\n releaseRejectedOpenNotice,\n rejectedOpenNoticeToken,\n} from \"../modal-registry.js\";\n\nimport { modalOriginAttrs, createModalDialogMachine, modalRequestService, cancelModalClose } from \"../modal-dialog-machine.js\";\nimport { trackModalDismissableElement } from \"../modal-dismissable-lifetime.js\";\nimport { modalRenderBlocked, notifyModalRenderRejection, notifyModalRenderOpenChange, type ModalRenderRuntime } from \"../modal-render-runtime.js\";\n\n/** Popup 的 Core machine;共享声明归属与焦点策略,按物理节点准入关闭监听。 */\nexport const popupMachine: typeof machine = createModalDialogMachine(trackModalDismissableElement);\n\nexport type PopupPlacement = \"bottom\" | \"top\";\n\n/**\n * QwPopupProps — 贴边弹出层的跨框架行为输入。\n * modal / role / Esc 是内部无障碍政策,不作为业务开关。\n */\nexport interface QwPopupProps {\n /** 唯一 id;也是 modal-registry 的键。不传时由适配层提供。 */\n id?: string;\n /** 受控开关。传入即受控。 */\n open?: boolean;\n /** 非受控初值,默认 false。 */\n defaultOpen?: boolean;\n /** 贴底或贴顶,默认 bottom。未知值回退 bottom。 */\n placement?: PopupPlacement;\n /** 点击遮罩关闭,默认 true。 */\n closeOnMaskClick?: boolean;\n /** 打开时禁止 body 滚动,默认 true。 */\n disableBodyScroll?: boolean;\n /** 为 false 时不加安全区留白,默认 true。 */\n safeArea?: boolean;\n /** 可访问名称的首选。trim 后为空视为缺省。 */\n title?: string;\n /** 无标题时的可访问名称。trim 后为空视为缺省。 */\n ariaLabel?: string;\n /** 关闭按钮的可访问名称,默认「关闭」。组件不按语言翻译。 */\n closeLabel?: string;\n /** 关闭后的焦点目标。只透传给 zag finalFocusEl,不解析 selector。 */\n returnFocus?: () => HTMLElement | null;\n /** 每次开合请求通知一次。被拒的打开通知一次 false。 */\n onOpenChange?: (open: boolean) => void;\n}\n\n/** 同 Zag dialog Api。setOpen 与 getTriggerProps 已包装单层模态拒绝。 */\nexport type QwPopupApi = Api;\n\ntype PopupNormalize = Parameters<typeof connect>[1];\n\nconst FALLBACK_NAME = \"弹出层\";\n\nfunction popupId(props: QwPopupProps): string {\n return props.id ?? \"\";\n}\n\n/**\n * 已有其它模态时拒绝打开。同一 id 在撤回或阻塞消失前只通知一次。\n * 返回 true 表示这次请求被拒。\n * deferNotice:调用发生在适配层渲染期间时为 true,通知改到微任务,避免在渲染中更新调用方状态。\n */\nfunction rejectIfOtherModal(\n id: string,\n onOpenChange?: (open: boolean) => void,\n deferNotice = false,\n): boolean {\n if (!hasOtherModal(id)) {\n releaseRejectedOpenNotice(id);\n return false;\n }\n if (onOpenChange && claimRejectedOpenNotice(id)) {\n if (deferNotice) {\n const token = rejectedOpenNoticeToken(id);\n queueMicrotask(() => { if (rejectedOpenNoticeToken(id) === token) onOpenChange(false); });\n }\n else onOpenChange(false);\n }\n return true;\n}\n\n/** 未知 placement 回退 bottom。 */\nexport function resolvePopupPlacement(value: unknown): PopupPlacement {\n return value === \"top\" ? \"top\" : \"bottom\";\n}\n\n/** 可访问名称:title → ariaLabel → 「弹出层」。空白视为缺省。 */\nexport function getPopupAccessibleName(props: Pick<QwPopupProps, \"title\" | \"ariaLabel\">): string {\n const title = props.title?.trim();\n if (title) return title;\n const label = props.ariaLabel?.trim();\n if (label) return label;\n return FALLBACK_NAME;\n}\n\n/** positioner 与 content 共用的 data 属性。safeArea 缺省为开启。 */\nexport function getPopupDataAttrs(\n props: Pick<QwPopupProps, \"placement\" | \"safeArea\">,\n): Record<string, string | undefined> {\n return {\n \"data-placement\": resolvePopupPlacement(props.placement),\n \"data-safe-area\": props.safeArea === false ? undefined : \"\",\n };\n}\n\n/** header / body / footer 没有 Zag part,scope 与 part 由 Core 输出。 */\nexport function getPopupPartProps(part: \"header\" | \"body\" | \"footer\"): {\n \"data-scope\": \"popup\";\n \"data-part\": \"header\" | \"body\" | \"footer\";\n} {\n return { \"data-scope\": \"popup\", \"data-part\": part };\n}\n\n/** 把公开 props 转成 zag dialog context。受控 open:true 被拒时映射为关闭。 */\nexport function createPopupProps(props: QwPopupProps = {}, runtime?: ModalRenderRuntime): Partial<ZagDialogProps> {\n const id = popupId(props);\n if (!runtime && props.open === false) releaseRejectedOpenNotice(id);\n const wantsInitialOpen = props.open === true || (props.open === undefined && props.defaultOpen === true);\n const blocked = runtime ? modalRenderBlocked(runtime, wantsInitialOpen) : wantsInitialOpen && rejectIfOtherModal(id, props.onOpenChange, true);\n const ctx: Partial<ZagDialogProps> = {\n id: props.id,\n open: blocked && props.open === true ? false : props.open,\n // Zag uses open || defaultOpen for its initial state; controlled input must not inherit the uncontrolled seed.\n defaultOpen: blocked || typeof props.open === \"boolean\" ? false : props.defaultOpen,\n role: \"dialog\",\n modal: true,\n closeOnEscape: true,\n closeOnInteractOutside: props.closeOnMaskClick !== false,\n preventScroll: props.disableBodyScroll !== false,\n finalFocusEl: props.returnFocus,\n };\n // 有标题时留给 Zag 写 aria-labelledby;无标题才用可访问名称。\n if (!props.title?.trim()) ctx[\"aria-label\"] = getPopupAccessibleName(props);\n if (props.onOpenChange) {\n const cb = props.onOpenChange;\n ctx.onOpenChange = (details: OpenChangeDetails) => {\n if (runtime) notifyModalRenderOpenChange(runtime, details.open, cb);\n else cb(details.open);\n };\n }\n return ctx;\n}\n\nfunction withPopupScope<T extends { \"data-scope\"?: string }>(props: T): T {\n return { ...props, \"data-scope\": \"popup\" };\n}\n\n/**\n * Popup 的 anatomy 没有 description part(见 docs/accessibility.md),\n * 但 zag dialog 的 rendered.description 初值是 true,只有 open entry 的 raf DOM 扫描才纠正它。\n * SSR 首树与 raf 之前的首帧因此会在 content 上发出指向不存在节点的 aria-describedby。\n *\n * 这里在 normalize **之前**从 content 的 raw 属性里摘掉这个键:normalize 之后再删会被\n * 任何做键映射的 normalizer 绕过。只改写 element,其余成员转发给调用方的 normalize。\n * 需要描述的 headless 调用者照常渲染 getDescriptionProps(),并自行写 aria-describedby。\n *\n * 代理的目标是一个空壳而不是 normalize 本身,否则两类合法输入会崩:\n * 冻结对象的 element 是不可配置不可写自有属性,get 返回替代函数违反 Proxy 不变量;\n * 带私有字段的 class normalizer 若以代理为 receiver 调用方法,私有字段归属会出错。\n * 空壳没有自有属性,不受不变量约束;成员统一绑回原 normalize,保住它的 receiver。\n * 不能改用展开复制——createNormalizer 返回的是对 {} 的 Proxy,自有键为空,展开会丢光虚拟成员。\n */\nfunction withoutContentDescriptionRef(normalize: PopupNormalize): PopupNormalize {\n const element: PopupNormalize[\"element\"] = (props) => {\n if (props[\"data-scope\"] !== \"dialog\" || props[\"data-part\"] !== \"content\") return normalize.element(props);\n const { \"aria-describedby\": _absent, ...rest } = props;\n void _absent;\n return normalize.element(rest);\n };\n return new Proxy({} as PopupNormalize, {\n get(_shell, key) {\n if (key === \"element\") return element;\n const member: unknown = Reflect.get(normalize, key);\n return typeof member === \"function\" ? member.bind(normalize) : member;\n },\n has: (_shell, key) => Reflect.has(normalize, key),\n });\n}\n\n/**\n * 包装 zag connect。触发器 onClick 与 setOpen(true) 先查登记;\n * 被拒时 onClick 调 preventDefault,让 zag 看到 defaultPrevented 后不发 TOGGLE。\n * setOpen(true) 被拒则直接返回,不向 zag 发事件。\n */\nexport function connectPopup(\n service: Service,\n normalize: PopupNormalize,\n props: QwPopupProps = {},\n runtime?: ModalRenderRuntime,\n): QwPopupApi & { getOriginProps(): ReturnType<PopupNormalize[\"element\"]> } {\n const api = connect(modalRequestService(service), withoutContentDescriptionRef(normalize));\n const id = popupId(props);\n const isOpen = () => service.state.matches(\"open\");\n const reject = () => {\n if (!runtime) return rejectIfOtherModal(id, props.onOpenChange);\n if (!modalRenderBlocked(runtime, true)) return false;\n notifyModalRenderRejection(runtime, props.onOpenChange);\n return true;\n };\n return {\n ...api,\n getOriginProps: () => normalize.element(modalOriginAttrs(service.scope.id, \"popup\")),\n setOpen(nextOpen) {\n if (nextOpen) cancelModalClose(service);\n if (nextOpen && !isOpen() && reject()) return;\n api.setOpen(nextOpen);\n },\n getTriggerProps(triggerProps) {\n const trigger = api.getTriggerProps(triggerProps);\n // React 保留 onClick;vanilla / WC 归一化成 onclick。只替换实际存在的那个。\n const key = typeof trigger.onClick === \"function\" ? \"onClick\" : \"onclick\";\n const previous = trigger[key] as\n | ((event: { defaultPrevented: boolean; preventDefault(): void }) => void)\n | undefined;\n return withPopupScope({\n ...trigger,\n [key](event: { defaultPrevented: boolean; preventDefault(): void }) {\n if (!isOpen() && !event.defaultPrevented && reject()) {\n event.preventDefault();\n }\n previous?.(event);\n },\n });\n },\n getBackdropProps() {\n return withPopupScope(api.getBackdropProps());\n },\n getPositionerProps() {\n return withPopupScope(api.getPositionerProps());\n },\n getContentProps() {\n return withPopupScope(api.getContentProps());\n },\n getTitleProps() {\n return withPopupScope(api.getTitleProps());\n },\n getDescriptionProps() {\n return withPopupScope(api.getDescriptionProps());\n },\n getCloseTriggerProps() {\n return withPopupScope(api.getCloseTriggerProps());\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
//#region src/portal.ts
|
|
2
|
+
const PORTAL_COPY_ATTRIBUTES = [
|
|
3
|
+
"lang",
|
|
4
|
+
"dir",
|
|
5
|
+
"data-qw-theme",
|
|
6
|
+
"data-qw-mode"
|
|
7
|
+
];
|
|
8
|
+
const QW_INLINE_PREFIX = "--qw-";
|
|
9
|
+
function partsFor(kind) {
|
|
10
|
+
switch (kind) {
|
|
11
|
+
case "dialog":
|
|
12
|
+
case "popup": return ["backdrop", "positioner"];
|
|
13
|
+
case "toast": return ["toast-mask"];
|
|
14
|
+
default: throw new TypeError(`Unknown portal kind: ${String(kind)}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/** 按 kind 给出挂载计划。未知 kind 在类型上不可传入;运行时抛 TypeError。 */
|
|
18
|
+
function createPortalPlan(kind) {
|
|
19
|
+
return {
|
|
20
|
+
kind,
|
|
21
|
+
target: "owner-body",
|
|
22
|
+
parts: partsFor(kind),
|
|
23
|
+
copy: {
|
|
24
|
+
attributes: [...PORTAL_COPY_ATTRIBUTES],
|
|
25
|
+
variables: {
|
|
26
|
+
scope: "scope-inline",
|
|
27
|
+
root: "inherit-root"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function assignString(target, key, value) {
|
|
33
|
+
if (typeof value === "string") target[key] = value;
|
|
34
|
+
}
|
|
35
|
+
function inlineQwVariables(source) {
|
|
36
|
+
const variables = {};
|
|
37
|
+
if (!source) return variables;
|
|
38
|
+
for (const [key, value] of Object.entries(source)) if (key.startsWith(QW_INLINE_PREFIX)) variables[key] = value;
|
|
39
|
+
return variables;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 宿主位置上的 lang / dir:读锚点(触发器,或无触发器时的宿主探针)的父节点。
|
|
43
|
+
* 没有锚点,或父节点是 documentElement 时,两个值都是 null。
|
|
44
|
+
* 这是"portal 根从哪里继承语言方向"的策略,各栈适配层不各自实现一份。
|
|
45
|
+
*/
|
|
46
|
+
function readPortalHostLocale(anchor) {
|
|
47
|
+
const parent = anchor?.parentElement ?? null;
|
|
48
|
+
if (!anchor || !parent || parent === anchor.ownerDocument.documentElement) return {
|
|
49
|
+
lang: null,
|
|
50
|
+
dir: null
|
|
51
|
+
};
|
|
52
|
+
return {
|
|
53
|
+
lang: parent.getAttribute("lang"),
|
|
54
|
+
dir: parent.getAttribute("dir")
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** 按快照决定 portal 根要写的属性与变量。不读取宿主文档。 */
|
|
58
|
+
function resolvePortalCopy(snapshot) {
|
|
59
|
+
const attributes = {};
|
|
60
|
+
assignString(attributes, "lang", snapshot.lang);
|
|
61
|
+
assignString(attributes, "dir", snapshot.dir);
|
|
62
|
+
if (snapshot.root === true) return {
|
|
63
|
+
variableMode: "inherit-root",
|
|
64
|
+
attributes,
|
|
65
|
+
variables: {}
|
|
66
|
+
};
|
|
67
|
+
assignString(attributes, "data-qw-theme", snapshot.theme);
|
|
68
|
+
assignString(attributes, "data-qw-mode", snapshot.mode);
|
|
69
|
+
return {
|
|
70
|
+
variableMode: "scope-inline",
|
|
71
|
+
attributes,
|
|
72
|
+
variables: inlineQwVariables(snapshot.variables)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { readPortalHostLocale as n, resolvePortalCopy as r, createPortalPlan as t };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=portal-BHCNTWhg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal-BHCNTWhg.js","names":["unexpected"],"sources":["../src/portal.ts"],"sourcesContent":["/**\n * 共享 portal 计划(RFC 0008;popup 见 specs/053)。\n * 纯数据:不读取宿主文档,不调用 focus。\n *\n * plan.copy.attributes 是候选属性名。\n * plan.copy.variables 按边界给出模式:scope 为 \"scope-inline\",root 为 \"inherit-root\"。\n * resolvePortalCopy 把已读快照收成要写到 portal 根的属性与变量。\n * root 不含主题属性和变量;非 --qw- 前缀丢弃;没有的 lang/dir 不写。\n */\n\nexport const PORTAL_KINDS = [\"dialog\", \"toast\", \"popup\"] as const;\n\n/** dialog、toast,以及 popup(053 的新消费者)。 */\nexport type PortalKind = (typeof PORTAL_KINDS)[number];\n\nexport type PortalTarget = \"owner-body\";\n\nexport type PortalPart = \"backdrop\" | \"positioner\" | \"toast-mask\";\n\nexport const PORTAL_COPY_ATTRIBUTES = [\n \"lang\",\n \"dir\",\n \"data-qw-theme\",\n \"data-qw-mode\",\n] as const;\n\nexport type PortalCopyAttribute = (typeof PORTAL_COPY_ATTRIBUTES)[number];\n\n/** scope 复制内联 --qw-*;root 不复制,浮层继承 html。 */\nexport type PortalVariableMode = \"scope-inline\" | \"inherit-root\";\n\nexport interface PortalCopy {\n readonly attributes: readonly PortalCopyAttribute[];\n /** scope 用 scope-inline,root 用 inherit-root。计划本身不选边。 */\n readonly variables: {\n readonly scope: \"scope-inline\";\n readonly root: \"inherit-root\";\n };\n}\n\nexport interface PortalPlan {\n readonly kind: PortalKind;\n readonly target: PortalTarget;\n readonly parts: readonly PortalPart[];\n readonly copy: PortalCopy;\n}\n\n/** 适配层已经读好的边界。Core 不再访问节点。 */\nexport interface PortalSnapshot {\n readonly root: boolean;\n readonly theme?: string | null;\n readonly mode?: string | null;\n readonly variables?: Readonly<Record<string, string>> | null;\n readonly lang?: string | null;\n readonly dir?: string | null;\n}\n\n/** 要写到每个 portal 根的属性与内联变量。 */\nexport interface PortalResolvedCopy {\n /** root 为 inherit-root,否则 scope-inline。 */\n readonly variableMode: PortalVariableMode;\n readonly attributes: Readonly<Partial<Record<PortalCopyAttribute, string>>>;\n readonly variables: Readonly<Record<string, string>>;\n}\n\nconst QW_INLINE_PREFIX = \"--qw-\";\n\nfunction partsFor(kind: PortalKind): readonly PortalPart[] {\n switch (kind) {\n case \"dialog\":\n case \"popup\":\n return [\"backdrop\", \"positioner\"];\n case \"toast\":\n return [\"toast-mask\"];\n default: {\n const unexpected: never = kind;\n throw new TypeError(`Unknown portal kind: ${String(unexpected)}`);\n }\n }\n}\n\n/** 按 kind 给出挂载计划。未知 kind 在类型上不可传入;运行时抛 TypeError。 */\nexport function createPortalPlan(kind: PortalKind): PortalPlan {\n return {\n kind,\n target: \"owner-body\",\n parts: partsFor(kind),\n copy: {\n attributes: [...PORTAL_COPY_ATTRIBUTES],\n variables: { scope: \"scope-inline\", root: \"inherit-root\" },\n },\n };\n}\n\nfunction assignString(\n target: Partial<Record<PortalCopyAttribute, string>>,\n key: PortalCopyAttribute,\n value: string | null | undefined,\n): void {\n if (typeof value === \"string\") target[key] = value;\n}\n\nfunction inlineQwVariables(\n source: Readonly<Record<string, string>> | null | undefined,\n): Record<string, string> {\n const variables: Record<string, string> = {};\n if (!source) return variables;\n for (const [key, value] of Object.entries(source)) {\n if (key.startsWith(QW_INLINE_PREFIX)) variables[key] = value;\n }\n return variables;\n}\n\n/**\n * 宿主位置上的 lang / dir:读锚点(触发器,或无触发器时的宿主探针)的父节点。\n * 没有锚点,或父节点是 documentElement 时,两个值都是 null。\n * 这是\"portal 根从哪里继承语言方向\"的策略,各栈适配层不各自实现一份。\n */\nexport function readPortalHostLocale(anchor: Element | null | undefined): { lang: string | null; dir: string | null } {\n const parent = anchor?.parentElement ?? null;\n if (!anchor || !parent || parent === anchor.ownerDocument.documentElement) return { lang: null, dir: null };\n return { lang: parent.getAttribute(\"lang\"), dir: parent.getAttribute(\"dir\") };\n}\n\n/** 按快照决定 portal 根要写的属性与变量。不读取宿主文档。 */\nexport function resolvePortalCopy(snapshot: PortalSnapshot): PortalResolvedCopy {\n const attributes: Partial<Record<PortalCopyAttribute, string>> = {};\n assignString(attributes, \"lang\", snapshot.lang);\n assignString(attributes, \"dir\", snapshot.dir);\n if (snapshot.root === true) {\n return { variableMode: \"inherit-root\", attributes, variables: {} };\n }\n assignString(attributes, \"data-qw-theme\", snapshot.theme);\n assignString(attributes, \"data-qw-mode\", snapshot.mode);\n return {\n variableMode: \"scope-inline\",\n attributes,\n variables: inlineQwVariables(snapshot.variables),\n };\n}\n"],"mappings":";AAmBA,MAAa,yBAAyB;CACpC;CACA;CACA;CACA;AACF;AAyCA,MAAM,mBAAmB;AAEzB,SAAS,SAAS,MAAyC;CACzD,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,SACH,OAAO,CAAC,YAAY,YAAY;EAClC,KAAK,SACH,OAAO,CAAC,YAAY;EACtB,SAEE,MAAM,IAAI,UAAU,wBAAwB,OAAOA,IAAU,GAAG;CAEpE;AACF;;AAGA,SAAgB,iBAAiB,MAA8B;CAC7D,OAAO;EACL;EACA,QAAQ;EACR,OAAO,SAAS,IAAI;EACpB,MAAM;GACJ,YAAY,CAAC,GAAG,sBAAsB;GACtC,WAAW;IAAE,OAAO;IAAgB,MAAM;GAAe;EAC3D;CACF;AACF;AAEA,SAAS,aACP,QACA,KACA,OACM;CACN,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO;AAC/C;AAEA,SAAS,kBACP,QACwB;CACxB,MAAM,YAAoC,CAAC;CAC3C,IAAI,CAAC,QAAQ,OAAO;CACpB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,IAAI,IAAI,WAAW,gBAAgB,GAAG,UAAU,OAAO;CAEzD,OAAO;AACT;;;;;;AAOA,SAAgB,qBAAqB,QAAiF;CACpH,MAAM,SAAS,QAAQ,iBAAiB;CACxC,IAAI,CAAC,UAAU,CAAC,UAAU,WAAW,OAAO,cAAc,iBAAiB,OAAO;EAAE,MAAM;EAAM,KAAK;CAAK;CAC1G,OAAO;EAAE,MAAM,OAAO,aAAa,MAAM;EAAG,KAAK,OAAO,aAAa,KAAK;CAAE;AAC9E;;AAGA,SAAgB,kBAAkB,UAA8C;CAC9E,MAAM,aAA2D,CAAC;CAClE,aAAa,YAAY,QAAQ,SAAS,IAAI;CAC9C,aAAa,YAAY,OAAO,SAAS,GAAG;CAC5C,IAAI,SAAS,SAAS,MACpB,OAAO;EAAE,cAAc;EAAgB;EAAY,WAAW,CAAC;CAAE;CAEnE,aAAa,YAAY,iBAAiB,SAAS,KAAK;CACxD,aAAa,YAAY,gBAAgB,SAAS,IAAI;CACtD,OAAO;EACL,cAAc;EACd;EACA,WAAW,kBAAkB,SAAS,SAAS;CACjD;AACF"}
|
package/dist/portal.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 共享 portal 计划(RFC 0008;popup 见 specs/053)。
|
|
3
|
+
* 纯数据:不读取宿主文档,不调用 focus。
|
|
4
|
+
*
|
|
5
|
+
* plan.copy.attributes 是候选属性名。
|
|
6
|
+
* plan.copy.variables 按边界给出模式:scope 为 "scope-inline",root 为 "inherit-root"。
|
|
7
|
+
* resolvePortalCopy 把已读快照收成要写到 portal 根的属性与变量。
|
|
8
|
+
* root 不含主题属性和变量;非 --qw- 前缀丢弃;没有的 lang/dir 不写。
|
|
9
|
+
*/
|
|
10
|
+
export declare const PORTAL_KINDS: readonly ["dialog", "toast", "popup"];
|
|
11
|
+
/** dialog、toast,以及 popup(053 的新消费者)。 */
|
|
12
|
+
export type PortalKind = (typeof PORTAL_KINDS)[number];
|
|
13
|
+
export type PortalTarget = "owner-body";
|
|
14
|
+
export type PortalPart = "backdrop" | "positioner" | "toast-mask";
|
|
15
|
+
export declare const PORTAL_COPY_ATTRIBUTES: readonly ["lang", "dir", "data-qw-theme", "data-qw-mode"];
|
|
16
|
+
export type PortalCopyAttribute = (typeof PORTAL_COPY_ATTRIBUTES)[number];
|
|
17
|
+
/** scope 复制内联 --qw-*;root 不复制,浮层继承 html。 */
|
|
18
|
+
export type PortalVariableMode = "scope-inline" | "inherit-root";
|
|
19
|
+
export interface PortalCopy {
|
|
20
|
+
readonly attributes: readonly PortalCopyAttribute[];
|
|
21
|
+
/** scope 用 scope-inline,root 用 inherit-root。计划本身不选边。 */
|
|
22
|
+
readonly variables: {
|
|
23
|
+
readonly scope: "scope-inline";
|
|
24
|
+
readonly root: "inherit-root";
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export interface PortalPlan {
|
|
28
|
+
readonly kind: PortalKind;
|
|
29
|
+
readonly target: PortalTarget;
|
|
30
|
+
readonly parts: readonly PortalPart[];
|
|
31
|
+
readonly copy: PortalCopy;
|
|
32
|
+
}
|
|
33
|
+
/** 适配层已经读好的边界。Core 不再访问节点。 */
|
|
34
|
+
export interface PortalSnapshot {
|
|
35
|
+
readonly root: boolean;
|
|
36
|
+
readonly theme?: string | null;
|
|
37
|
+
readonly mode?: string | null;
|
|
38
|
+
readonly variables?: Readonly<Record<string, string>> | null;
|
|
39
|
+
readonly lang?: string | null;
|
|
40
|
+
readonly dir?: string | null;
|
|
41
|
+
}
|
|
42
|
+
/** 要写到每个 portal 根的属性与内联变量。 */
|
|
43
|
+
export interface PortalResolvedCopy {
|
|
44
|
+
/** root 为 inherit-root,否则 scope-inline。 */
|
|
45
|
+
readonly variableMode: PortalVariableMode;
|
|
46
|
+
readonly attributes: Readonly<Partial<Record<PortalCopyAttribute, string>>>;
|
|
47
|
+
readonly variables: Readonly<Record<string, string>>;
|
|
48
|
+
}
|
|
49
|
+
/** 按 kind 给出挂载计划。未知 kind 在类型上不可传入;运行时抛 TypeError。 */
|
|
50
|
+
export declare function createPortalPlan(kind: PortalKind): PortalPlan;
|
|
51
|
+
/**
|
|
52
|
+
* 宿主位置上的 lang / dir:读锚点(触发器,或无触发器时的宿主探针)的父节点。
|
|
53
|
+
* 没有锚点,或父节点是 documentElement 时,两个值都是 null。
|
|
54
|
+
* 这是"portal 根从哪里继承语言方向"的策略,各栈适配层不各自实现一份。
|
|
55
|
+
*/
|
|
56
|
+
export declare function readPortalHostLocale(anchor: Element | null | undefined): {
|
|
57
|
+
lang: string | null;
|
|
58
|
+
dir: string | null;
|
|
59
|
+
};
|
|
60
|
+
/** 按快照决定 portal 根要写的属性与变量。不读取宿主文档。 */
|
|
61
|
+
export declare function resolvePortalCopy(snapshot: PortalSnapshot): PortalResolvedCopy;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal decimal formatting shared by Price and Statistic.
|
|
3
|
+
* Not re-exported from any public index: names stay module-private to the two families.
|
|
4
|
+
* All arithmetic is done on decimal strings, so binary floating-point noise never reaches the UI.
|
|
5
|
+
*/
|
|
6
|
+
/** Signed decimal split into digit strings without separators. */
|
|
7
|
+
export interface DecimalParts {
|
|
8
|
+
negative: boolean;
|
|
9
|
+
integer: string;
|
|
10
|
+
fraction: string;
|
|
11
|
+
}
|
|
12
|
+
/** Parse a finite number or decimal string; returns null for anything else. */
|
|
13
|
+
export declare function parseDecimal(value: unknown): DecimalParts | null;
|
|
14
|
+
/** Round half away from zero to a fixed number of fraction digits (string arithmetic). */
|
|
15
|
+
export declare function roundDecimal(parts: DecimalParts, precision: number): DecimalParts;
|
|
16
|
+
/** Insert a group separator every three integer digits. Empty separator disables grouping. */
|
|
17
|
+
export declare function groupDecimalInteger(integer: string, separator: string): string;
|
|
18
|
+
/** Validate a precision option: integer in [0, 10], otherwise the fallback. */
|
|
19
|
+
export declare function resolveDecimalPrecision(precision: unknown, fallback: number | undefined): number | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./price.js";
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { i as roundDecimal, n as parseDecimal, r as resolveDecimalPrecision, t as groupDecimalInteger } from "../format-BDUY0C_c.js";
|
|
2
|
+
import { visuallyHiddenStyle } from "@zag-js/dom-query";
|
|
3
|
+
//#region src/price/price.ts
|
|
4
|
+
/** Typography scale for the integer digits; fraction/symbol/unit derive from it in styles-core. */
|
|
5
|
+
const PRICE_SIZES = [
|
|
6
|
+
"sm",
|
|
7
|
+
"md",
|
|
8
|
+
"lg"
|
|
9
|
+
];
|
|
10
|
+
/** Existing T3 content roles; there is no dedicated price color role. */
|
|
11
|
+
const PRICE_TONES = [
|
|
12
|
+
"default",
|
|
13
|
+
"danger",
|
|
14
|
+
"secondary"
|
|
15
|
+
];
|
|
16
|
+
const PRICE_SYMBOL_POSITIONS = ["before", "after"];
|
|
17
|
+
const PRICE_FRACTION_SIZES = ["reduced", "same"];
|
|
18
|
+
/** Stable DOM parts shared by every adapter. */
|
|
19
|
+
const PRICE_PARTS = [
|
|
20
|
+
"root",
|
|
21
|
+
"sr-text",
|
|
22
|
+
"visual",
|
|
23
|
+
"sign",
|
|
24
|
+
"symbol",
|
|
25
|
+
"integer",
|
|
26
|
+
"decimal",
|
|
27
|
+
"fraction",
|
|
28
|
+
"unit"
|
|
29
|
+
];
|
|
30
|
+
const PRICE_DEFAULT_PRECISION = 2;
|
|
31
|
+
const PRICE_DEFAULT_SYMBOL = "¥";
|
|
32
|
+
const PRICE_DEFAULT_PLACEHOLDER = "--";
|
|
33
|
+
const PRICE_DEFAULT_ORIGINAL_LABEL = "原价";
|
|
34
|
+
const pick = (list, value, fallback) => list.includes(value) ? value : fallback;
|
|
35
|
+
/** Normalize props into display digits and complete accessible text. Pure and SSR-safe. */
|
|
36
|
+
function resolvePriceState(props) {
|
|
37
|
+
const precision = resolveDecimalPrecision(props.precision, 2);
|
|
38
|
+
const symbol = typeof props.symbol === "string" ? props.symbol : "¥";
|
|
39
|
+
const symbolPosition = pick(PRICE_SYMBOL_POSITIONS, props.symbolPosition, "before");
|
|
40
|
+
const unit = props.unit ?? "";
|
|
41
|
+
const strikethrough = !!props.strikethrough;
|
|
42
|
+
const placeholder = props.placeholder ?? "--";
|
|
43
|
+
const label = (props.label ?? (strikethrough ? "原价" : "")).trim();
|
|
44
|
+
const parsed = parseDecimal(props.value);
|
|
45
|
+
const base = {
|
|
46
|
+
symbolPosition,
|
|
47
|
+
unit,
|
|
48
|
+
strikethrough,
|
|
49
|
+
placeholder,
|
|
50
|
+
rootTag: strikethrough ? "del" : "span",
|
|
51
|
+
size: pick(PRICE_SIZES, props.size, "md"),
|
|
52
|
+
tone: pick(PRICE_TONES, props.tone, "default"),
|
|
53
|
+
fractionSize: pick(PRICE_FRACTION_SIZES, props.fractionSize, "reduced")
|
|
54
|
+
};
|
|
55
|
+
if (!parsed) return {
|
|
56
|
+
...base,
|
|
57
|
+
valid: false,
|
|
58
|
+
negative: false,
|
|
59
|
+
sign: "",
|
|
60
|
+
symbol: "",
|
|
61
|
+
integer: "",
|
|
62
|
+
decimal: "",
|
|
63
|
+
fraction: "",
|
|
64
|
+
unit: "",
|
|
65
|
+
text: placeholder,
|
|
66
|
+
accessibleText: [label, placeholder].filter(Boolean).join(" ")
|
|
67
|
+
};
|
|
68
|
+
const rounded = roundDecimal(parsed, precision);
|
|
69
|
+
const integer = groupDecimalInteger(rounded.integer, props.thousands === false ? "" : ",");
|
|
70
|
+
const decimal = precision > 0 ? "." : "";
|
|
71
|
+
const sign = rounded.negative ? "-" : "";
|
|
72
|
+
const amount = `${integer}${decimal}${rounded.fraction}`;
|
|
73
|
+
const text = symbolPosition === "before" ? `${sign}${symbol}${amount}${unit}` : `${sign}${amount}${symbol}${unit}`;
|
|
74
|
+
return {
|
|
75
|
+
...base,
|
|
76
|
+
valid: true,
|
|
77
|
+
negative: rounded.negative,
|
|
78
|
+
sign,
|
|
79
|
+
symbol,
|
|
80
|
+
integer,
|
|
81
|
+
decimal,
|
|
82
|
+
fraction: rounded.fraction,
|
|
83
|
+
text,
|
|
84
|
+
accessibleText: [label, text].filter(Boolean).join(" ")
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function getPriceRootProps(state) {
|
|
88
|
+
return {
|
|
89
|
+
"data-scope": "price",
|
|
90
|
+
"data-part": "root",
|
|
91
|
+
"data-size": state.size,
|
|
92
|
+
"data-tone": state.tone,
|
|
93
|
+
"data-fraction-size": state.fractionSize,
|
|
94
|
+
"data-symbol-position": state.symbolPosition,
|
|
95
|
+
...state.strikethrough ? { "data-strikethrough": "" } : {},
|
|
96
|
+
...state.negative ? { "data-negative": "" } : {},
|
|
97
|
+
...!state.valid ? { "data-invalid": "" } : {}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** Visually hidden complete text; the visual layer is hidden from assistive technology. */
|
|
101
|
+
function getPricePartProps(part) {
|
|
102
|
+
if (part === "sr-text") return {
|
|
103
|
+
"data-scope": "price",
|
|
104
|
+
"data-part": part,
|
|
105
|
+
style: { ...visuallyHiddenStyle }
|
|
106
|
+
};
|
|
107
|
+
if (part === "visual") return {
|
|
108
|
+
"data-scope": "price",
|
|
109
|
+
"data-part": part,
|
|
110
|
+
"aria-hidden": "true"
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
"data-scope": "price",
|
|
114
|
+
"data-part": part
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function getPriceSegments(state) {
|
|
118
|
+
if (!state.valid) return [{
|
|
119
|
+
part: "integer",
|
|
120
|
+
text: state.placeholder
|
|
121
|
+
}];
|
|
122
|
+
const symbol = {
|
|
123
|
+
part: "symbol",
|
|
124
|
+
text: state.symbol
|
|
125
|
+
};
|
|
126
|
+
return [
|
|
127
|
+
{
|
|
128
|
+
part: "sign",
|
|
129
|
+
text: state.sign
|
|
130
|
+
},
|
|
131
|
+
...state.symbolPosition === "before" ? [symbol] : [],
|
|
132
|
+
{
|
|
133
|
+
part: "integer",
|
|
134
|
+
text: state.integer
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
part: "decimal",
|
|
138
|
+
text: state.decimal
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
part: "fraction",
|
|
142
|
+
text: state.fraction
|
|
143
|
+
},
|
|
144
|
+
...state.symbolPosition === "after" ? [symbol] : [],
|
|
145
|
+
{
|
|
146
|
+
part: "unit",
|
|
147
|
+
text: state.unit
|
|
148
|
+
}
|
|
149
|
+
].filter((segment) => segment.text !== "");
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
export { PRICE_DEFAULT_ORIGINAL_LABEL, PRICE_DEFAULT_PLACEHOLDER, PRICE_DEFAULT_PRECISION, PRICE_DEFAULT_SYMBOL, PRICE_FRACTION_SIZES, PRICE_PARTS, PRICE_SIZES, PRICE_SYMBOL_POSITIONS, PRICE_TONES, getPricePartProps, getPriceRootProps, getPriceSegments, resolvePriceState };
|
|
153
|
+
|
|
154
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/price/price.ts"],"sourcesContent":["import { visuallyHiddenStyle } from \"@zag-js/dom-query\";\nimport { groupDecimalInteger, parseDecimal, resolveDecimalPrecision, roundDecimal } from \"./format.js\";\n\n/** Typography scale for the integer digits; fraction/symbol/unit derive from it in styles-core. */\nexport const PRICE_SIZES = [\"sm\", \"md\", \"lg\"] as const;\n/** Existing T3 content roles; there is no dedicated price color role. */\nexport const PRICE_TONES = [\"default\", \"danger\", \"secondary\"] as const;\nexport const PRICE_SYMBOL_POSITIONS = [\"before\", \"after\"] as const;\nexport const PRICE_FRACTION_SIZES = [\"reduced\", \"same\"] as const;\n/** Stable DOM parts shared by every adapter. */\nexport const PRICE_PARTS = [\"root\", \"sr-text\", \"visual\", \"sign\", \"symbol\", \"integer\", \"decimal\", \"fraction\", \"unit\"] as const;\nexport const PRICE_DEFAULT_PRECISION = 2;\nexport const PRICE_DEFAULT_SYMBOL = \"¥\";\nexport const PRICE_DEFAULT_PLACEHOLDER = \"--\";\nexport const PRICE_DEFAULT_ORIGINAL_LABEL = \"原价\";\n\nexport type PriceSize = (typeof PRICE_SIZES)[number];\nexport type PriceTone = (typeof PRICE_TONES)[number];\nexport type PriceSymbolPosition = (typeof PRICE_SYMBOL_POSITIONS)[number];\nexport type PriceFractionSize = (typeof PRICE_FRACTION_SIZES)[number];\nexport type PricePart = (typeof PRICE_PARTS)[number];\n\nexport interface QwPriceProps {\n /** Amount. Decimal strings keep exact digits; numbers use their shortest round-trip form. */\n value: number | string;\n /** Fraction digits, integer 0–10; defaults to 2. */\n precision?: number;\n /** Currency symbol; empty string renders none. Defaults to ¥. */\n symbol?: string;\n symbolPosition?: PriceSymbolPosition;\n /** Group integer digits with \",\"; defaults true. */\n thousands?: boolean;\n /** Visible unit suffix such as \"/件\". */\n unit?: string;\n /** Original (crossed-out) price rendered as <del>. */\n strikethrough?: boolean;\n /** Accessible prefix; strikethrough defaults to \"原价\". */\n label?: string;\n size?: PriceSize;\n tone?: PriceTone;\n fractionSize?: PriceFractionSize;\n /** Text for invalid values; defaults to \"--\". */\n placeholder?: string;\n}\n\nexport interface ResolvedPriceState {\n valid: boolean;\n negative: boolean;\n sign: string;\n symbol: string;\n symbolPosition: PriceSymbolPosition;\n integer: string;\n decimal: string;\n fraction: string;\n unit: string;\n /** Visible text without label, e.g. \"-¥1,299.00/件\". */\n text: string;\n /** Complete screen-reader text including label. */\n accessibleText: string;\n rootTag: \"span\" | \"del\";\n size: PriceSize;\n tone: PriceTone;\n fractionSize: PriceFractionSize;\n strikethrough: boolean;\n placeholder: string;\n}\n\nconst pick = <T extends string>(list: readonly T[], value: unknown, fallback: T): T => (list as readonly unknown[]).includes(value) ? value as T : fallback;\n\n/** Normalize props into display digits and complete accessible text. Pure and SSR-safe. */\nexport function resolvePriceState(props: QwPriceProps): ResolvedPriceState {\n const precision = resolveDecimalPrecision(props.precision, PRICE_DEFAULT_PRECISION)!;\n const symbol = typeof props.symbol === \"string\" ? props.symbol : PRICE_DEFAULT_SYMBOL;\n const symbolPosition = pick(PRICE_SYMBOL_POSITIONS, props.symbolPosition, \"before\");\n const unit = props.unit ?? \"\";\n const strikethrough = !!props.strikethrough;\n const placeholder = props.placeholder ?? PRICE_DEFAULT_PLACEHOLDER;\n const label = (props.label ?? (strikethrough ? PRICE_DEFAULT_ORIGINAL_LABEL : \"\")).trim();\n const parsed = parseDecimal(props.value);\n const base = { symbolPosition, unit, strikethrough, placeholder, rootTag: strikethrough ? \"del\" as const : \"span\" as const,\n size: pick(PRICE_SIZES, props.size, \"md\"), tone: pick(PRICE_TONES, props.tone, \"default\"), fractionSize: pick(PRICE_FRACTION_SIZES, props.fractionSize, \"reduced\") };\n if (!parsed) {\n return { ...base, valid: false, negative: false, sign: \"\", symbol: \"\", integer: \"\", decimal: \"\", fraction: \"\", unit: \"\", text: placeholder,\n accessibleText: [label, placeholder].filter(Boolean).join(\" \") };\n }\n const rounded = roundDecimal(parsed, precision);\n const integer = groupDecimalInteger(rounded.integer, props.thousands === false ? \"\" : \",\");\n const decimal = precision > 0 ? \".\" : \"\";\n const sign = rounded.negative ? \"-\" : \"\";\n const amount = `${integer}${decimal}${rounded.fraction}`;\n const text = symbolPosition === \"before\" ? `${sign}${symbol}${amount}${unit}` : `${sign}${amount}${symbol}${unit}`;\n return { ...base, valid: true, negative: rounded.negative, sign, symbol, integer, decimal, fraction: rounded.fraction, text,\n accessibleText: [label, text].filter(Boolean).join(\" \") };\n}\n\nexport interface PriceRootProps {\n \"data-scope\": \"price\";\n \"data-part\": \"root\";\n \"data-size\": PriceSize;\n \"data-tone\": PriceTone;\n \"data-fraction-size\": PriceFractionSize;\n \"data-symbol-position\": PriceSymbolPosition;\n \"data-strikethrough\"?: \"\";\n \"data-negative\"?: \"\";\n \"data-invalid\"?: \"\";\n}\n\nexport function getPriceRootProps(state: ResolvedPriceState): PriceRootProps {\n return {\n \"data-scope\": \"price\", \"data-part\": \"root\", \"data-size\": state.size, \"data-tone\": state.tone,\n \"data-fraction-size\": state.fractionSize, \"data-symbol-position\": state.symbolPosition,\n ...(state.strikethrough ? { \"data-strikethrough\": \"\" as const } : {}),\n ...(state.negative ? { \"data-negative\": \"\" as const } : {}),\n ...(!state.valid ? { \"data-invalid\": \"\" as const } : {}),\n };\n}\n\nexport interface PricePartProps {\n \"data-scope\": \"price\";\n \"data-part\": PricePart;\n \"aria-hidden\"?: \"true\";\n style?: Record<string, string>;\n}\n\n/** Visually hidden complete text; the visual layer is hidden from assistive technology. */\nexport function getPricePartProps(part: Exclude<PricePart, \"root\">): PricePartProps {\n if (part === \"sr-text\") return { \"data-scope\": \"price\", \"data-part\": part, style: { ...visuallyHiddenStyle } as Record<string, string> };\n if (part === \"visual\") return { \"data-scope\": \"price\", \"data-part\": part, \"aria-hidden\": \"true\" };\n return { \"data-scope\": \"price\", \"data-part\": part };\n}\n\n/** Ordered visible segments; empty segments are omitted so adapters render a flat list. */\nexport interface PriceSegment { part: Exclude<PricePart, \"root\" | \"sr-text\" | \"visual\">; text: string }\nexport function getPriceSegments(state: ResolvedPriceState): PriceSegment[] {\n if (!state.valid) return [{ part: \"integer\", text: state.placeholder }];\n const symbol: PriceSegment = { part: \"symbol\", text: state.symbol };\n const list: PriceSegment[] = [\n { part: \"sign\", text: state.sign },\n ...(state.symbolPosition === \"before\" ? [symbol] : []),\n { part: \"integer\", text: state.integer },\n { part: \"decimal\", text: state.decimal },\n { part: \"fraction\", text: state.fraction },\n ...(state.symbolPosition === \"after\" ? [symbol] : []),\n { part: \"unit\", text: state.unit },\n ];\n return list.filter((segment) => segment.text !== \"\");\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** Typography scale for the integer digits; fraction/symbol/unit derive from it in styles-core. */
|
|
2
|
+
export declare const PRICE_SIZES: readonly ["sm", "md", "lg"];
|
|
3
|
+
/** Existing T3 content roles; there is no dedicated price color role. */
|
|
4
|
+
export declare const PRICE_TONES: readonly ["default", "danger", "secondary"];
|
|
5
|
+
export declare const PRICE_SYMBOL_POSITIONS: readonly ["before", "after"];
|
|
6
|
+
export declare const PRICE_FRACTION_SIZES: readonly ["reduced", "same"];
|
|
7
|
+
/** Stable DOM parts shared by every adapter. */
|
|
8
|
+
export declare const PRICE_PARTS: readonly ["root", "sr-text", "visual", "sign", "symbol", "integer", "decimal", "fraction", "unit"];
|
|
9
|
+
export declare const PRICE_DEFAULT_PRECISION = 2;
|
|
10
|
+
export declare const PRICE_DEFAULT_SYMBOL = "\u00A5";
|
|
11
|
+
export declare const PRICE_DEFAULT_PLACEHOLDER = "--";
|
|
12
|
+
export declare const PRICE_DEFAULT_ORIGINAL_LABEL = "\u539F\u4EF7";
|
|
13
|
+
export type PriceSize = (typeof PRICE_SIZES)[number];
|
|
14
|
+
export type PriceTone = (typeof PRICE_TONES)[number];
|
|
15
|
+
export type PriceSymbolPosition = (typeof PRICE_SYMBOL_POSITIONS)[number];
|
|
16
|
+
export type PriceFractionSize = (typeof PRICE_FRACTION_SIZES)[number];
|
|
17
|
+
export type PricePart = (typeof PRICE_PARTS)[number];
|
|
18
|
+
export interface QwPriceProps {
|
|
19
|
+
/** Amount. Decimal strings keep exact digits; numbers use their shortest round-trip form. */
|
|
20
|
+
value: number | string;
|
|
21
|
+
/** Fraction digits, integer 0–10; defaults to 2. */
|
|
22
|
+
precision?: number;
|
|
23
|
+
/** Currency symbol; empty string renders none. Defaults to ¥. */
|
|
24
|
+
symbol?: string;
|
|
25
|
+
symbolPosition?: PriceSymbolPosition;
|
|
26
|
+
/** Group integer digits with ","; defaults true. */
|
|
27
|
+
thousands?: boolean;
|
|
28
|
+
/** Visible unit suffix such as "/件". */
|
|
29
|
+
unit?: string;
|
|
30
|
+
/** Original (crossed-out) price rendered as <del>. */
|
|
31
|
+
strikethrough?: boolean;
|
|
32
|
+
/** Accessible prefix; strikethrough defaults to "原价". */
|
|
33
|
+
label?: string;
|
|
34
|
+
size?: PriceSize;
|
|
35
|
+
tone?: PriceTone;
|
|
36
|
+
fractionSize?: PriceFractionSize;
|
|
37
|
+
/** Text for invalid values; defaults to "--". */
|
|
38
|
+
placeholder?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ResolvedPriceState {
|
|
41
|
+
valid: boolean;
|
|
42
|
+
negative: boolean;
|
|
43
|
+
sign: string;
|
|
44
|
+
symbol: string;
|
|
45
|
+
symbolPosition: PriceSymbolPosition;
|
|
46
|
+
integer: string;
|
|
47
|
+
decimal: string;
|
|
48
|
+
fraction: string;
|
|
49
|
+
unit: string;
|
|
50
|
+
/** Visible text without label, e.g. "-¥1,299.00/件". */
|
|
51
|
+
text: string;
|
|
52
|
+
/** Complete screen-reader text including label. */
|
|
53
|
+
accessibleText: string;
|
|
54
|
+
rootTag: "span" | "del";
|
|
55
|
+
size: PriceSize;
|
|
56
|
+
tone: PriceTone;
|
|
57
|
+
fractionSize: PriceFractionSize;
|
|
58
|
+
strikethrough: boolean;
|
|
59
|
+
placeholder: string;
|
|
60
|
+
}
|
|
61
|
+
/** Normalize props into display digits and complete accessible text. Pure and SSR-safe. */
|
|
62
|
+
export declare function resolvePriceState(props: QwPriceProps): ResolvedPriceState;
|
|
63
|
+
export interface PriceRootProps {
|
|
64
|
+
"data-scope": "price";
|
|
65
|
+
"data-part": "root";
|
|
66
|
+
"data-size": PriceSize;
|
|
67
|
+
"data-tone": PriceTone;
|
|
68
|
+
"data-fraction-size": PriceFractionSize;
|
|
69
|
+
"data-symbol-position": PriceSymbolPosition;
|
|
70
|
+
"data-strikethrough"?: "";
|
|
71
|
+
"data-negative"?: "";
|
|
72
|
+
"data-invalid"?: "";
|
|
73
|
+
}
|
|
74
|
+
export declare function getPriceRootProps(state: ResolvedPriceState): PriceRootProps;
|
|
75
|
+
export interface PricePartProps {
|
|
76
|
+
"data-scope": "price";
|
|
77
|
+
"data-part": PricePart;
|
|
78
|
+
"aria-hidden"?: "true";
|
|
79
|
+
style?: Record<string, string>;
|
|
80
|
+
}
|
|
81
|
+
/** Visually hidden complete text; the visual layer is hidden from assistive technology. */
|
|
82
|
+
export declare function getPricePartProps(part: Exclude<PricePart, "root">): PricePartProps;
|
|
83
|
+
/** Ordered visible segments; empty segments are omitted so adapters render a flat list. */
|
|
84
|
+
export interface PriceSegment {
|
|
85
|
+
part: Exclude<PricePart, "root" | "sr-text" | "visual">;
|
|
86
|
+
text: string;
|
|
87
|
+
}
|
|
88
|
+
export declare function getPriceSegments(state: ResolvedPriceState): PriceSegment[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./progress.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Finite range and accessible progress contract. */
|
|
2
|
+
export declare const PROGRESS_TONES: readonly ["brand", "success", "danger"];
|
|
3
|
+
export type ProgressTone = (typeof PROGRESS_TONES)[number];
|
|
4
|
+
export interface QwProgressProps {
|
|
5
|
+
/** Accessible name, supplied by the caller. */
|
|
6
|
+
label: string;
|
|
7
|
+
value?: number;
|
|
8
|
+
max?: number;
|
|
9
|
+
indeterminate?: boolean;
|
|
10
|
+
tone?: ProgressTone;
|
|
11
|
+
}
|
|
12
|
+
export interface ResolvedProgressState {
|
|
13
|
+
label: string;
|
|
14
|
+
value: number;
|
|
15
|
+
max: number;
|
|
16
|
+
percent: number;
|
|
17
|
+
indeterminate: boolean;
|
|
18
|
+
tone: ProgressTone;
|
|
19
|
+
}
|
|
20
|
+
export interface ProgressRootProps {
|
|
21
|
+
role: "progressbar";
|
|
22
|
+
"aria-label": string;
|
|
23
|
+
"aria-valuemin": 0;
|
|
24
|
+
"aria-valuemax": number;
|
|
25
|
+
"aria-valuenow"?: number;
|
|
26
|
+
"data-scope": "progress";
|
|
27
|
+
"data-part": "root";
|
|
28
|
+
"data-tone": ProgressTone;
|
|
29
|
+
"data-indeterminate"?: "true";
|
|
30
|
+
}
|
|
31
|
+
export declare function resolveProgressState(props: QwProgressProps): ResolvedProgressState;
|
|
32
|
+
export declare function getProgressRootProps(state: ResolvedProgressState): ProgressRootProps;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/progress/progress.ts
|
|
2
|
+
/** Finite range and accessible progress contract. */
|
|
3
|
+
const PROGRESS_TONES = [
|
|
4
|
+
"brand",
|
|
5
|
+
"success",
|
|
6
|
+
"danger"
|
|
7
|
+
];
|
|
8
|
+
function resolveProgressState(props) {
|
|
9
|
+
const max = props.max != null && Number.isFinite(props.max) && props.max > 0 ? props.max : 100;
|
|
10
|
+
const input = props.value ?? 0;
|
|
11
|
+
const value = Number.isFinite(input) ? Math.min(max, Math.max(0, input)) : 0;
|
|
12
|
+
return {
|
|
13
|
+
label: props.label,
|
|
14
|
+
max,
|
|
15
|
+
value,
|
|
16
|
+
percent: value / max * 100,
|
|
17
|
+
indeterminate: props.indeterminate ?? false,
|
|
18
|
+
tone: props.tone ?? "brand"
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function getProgressRootProps(state) {
|
|
22
|
+
return {
|
|
23
|
+
role: "progressbar",
|
|
24
|
+
"aria-label": state.label,
|
|
25
|
+
"aria-valuemin": 0,
|
|
26
|
+
"aria-valuemax": state.max,
|
|
27
|
+
...!state.indeterminate ? { "aria-valuenow": state.value } : {},
|
|
28
|
+
"data-scope": "progress",
|
|
29
|
+
"data-part": "root",
|
|
30
|
+
"data-tone": state.tone,
|
|
31
|
+
...state.indeterminate ? { "data-indeterminate": "true" } : {}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { getProgressRootProps as n, resolveProgressState as r, PROGRESS_TONES as t };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=progress-f3iYEfdA.js.map
|