@feugene/granularity 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{config-Zc_bUvZY2.js → config-BDfTXHo12.js} +1 -1
- package/dist/chunks/{config-Zc_bUvZY2.js.map → config-BDfTXHo12.js.map} +1 -1
- package/dist/chunks/config-BE6n20np2.js.map +1 -0
- package/dist/chunks/{config-CpwwkFBO.js → config-Baj7Wvx-.js} +1 -1
- package/dist/chunks/{config-CpwwkFBO.js.map → config-Baj7Wvx-.js.map} +1 -1
- package/dist/chunks/config-BoNR7_PD2.js.map +1 -0
- package/dist/chunks/{config-DxCTVBfx.js → config-BsPDQ0dS.js} +2 -2
- package/dist/chunks/config-BsPDQ0dS.js.map +1 -0
- package/dist/chunks/config-CN2ULSQL.js.map +1 -0
- package/dist/chunks/{config-Cw6TDzWv2.js → config-COpuWGr_.js} +1 -1
- package/dist/chunks/config-COpuWGr_.js.map +1 -0
- package/dist/chunks/config-D2aNP7Es.js +70 -0
- package/dist/chunks/config-D2aNP7Es.js.map +1 -0
- package/dist/chunks/config-D94Z9po5.js.map +1 -0
- package/dist/chunks/{config-B-g6lT19.js → config-DA6SnEoy.js} +5 -2
- package/dist/chunks/config-DA6SnEoy.js.map +1 -0
- package/dist/chunks/config-DCFvmHEv2.js.map +1 -0
- package/dist/chunks/config-DEvsMTQE.js +150 -0
- package/dist/chunks/config-DEvsMTQE.js.map +1 -0
- package/dist/chunks/{config-CvC0sX8p.js → config-MRvhUl-O.js} +1 -1
- package/dist/chunks/{config-CvC0sX8p.js.map → config-MRvhUl-O.js.map} +1 -1
- package/dist/chunks/config-ScuvHw6k2.js +42 -0
- package/dist/chunks/config-ScuvHw6k2.js.map +1 -0
- package/dist/chunks/config-T3qdQBgU2.js.map +1 -0
- package/dist/chunks/config-eXB87DOi.js.map +1 -0
- package/dist/chunks/{config-D8tSR2uS.js → config-gvq_hWNM.js} +1 -1
- package/dist/chunks/{config-D8tSR2uS.js.map → config-gvq_hWNM.js.map} +1 -1
- package/dist/chunks/context-BSYR7RZs.js.map +1 -1
- package/dist/chunks/{en-B3xMeswz.js → en-COdzxgAX.js} +30 -5
- package/dist/chunks/en-COdzxgAX.js.map +1 -0
- package/dist/chunks/{es-CA-mkU--.js → es-ClqJ-4hr.js} +30 -5
- package/dist/chunks/es-ClqJ-4hr.js.map +1 -0
- package/dist/chunks/{es-Bv8vvqdT.js → es-DGMHwknJ.js} +3 -3
- package/dist/chunks/{es-Bv8vvqdT.js.map → es-DGMHwknJ.js.map} +1 -1
- package/dist/chunks/grKbdStyles-CeZhGQHr.js +43 -0
- package/dist/chunks/grKbdStyles-CeZhGQHr.js.map +1 -0
- package/dist/chunks/{grTextareaStyles-CWI2SqC8.js → grTextareaStyles-iOcHuVMM.js} +2 -2
- package/dist/chunks/{grTextareaStyles-CWI2SqC8.js.map → grTextareaStyles-iOcHuVMM.js.map} +1 -1
- package/dist/chunks/{granular-provider-CtrXGa7c.js → granular-provider-B9nXQCMu.js} +18 -16
- package/dist/chunks/granular-provider-B9nXQCMu.js.map +1 -0
- package/dist/chunks/{keyboard-zYvvyHd4.js → keyboard-DE2yhz_b.js} +10 -1
- package/dist/chunks/keyboard-DE2yhz_b.js.map +1 -0
- package/dist/chunks/{optionFilter-BVY988pC.js → optionFilter-DYw9XPPx.js} +1 -71
- package/dist/chunks/optionFilter-DYw9XPPx.js.map +1 -0
- package/dist/chunks/{useOverlayLayer-BupuP_hs.js → overlayStack-C8cfsqXa.js} +11 -61
- package/dist/chunks/overlayStack-C8cfsqXa.js.map +1 -0
- package/dist/chunks/{ru-COWxgh2A.js → ru-9z8ix45c.js} +30 -5
- package/dist/chunks/ru-9z8ix45c.js.map +1 -0
- package/dist/chunks/useDragSort-0l47h4yb.js +265 -0
- package/dist/chunks/useDragSort-0l47h4yb.js.map +1 -0
- package/dist/chunks/{useModalOverlay-DCM4d3yA.js → useModalOverlay-BTq-0ImG.js} +1 -1
- package/dist/chunks/{useModalOverlay-DCM4d3yA.js.map → useModalOverlay-BTq-0ImG.js.map} +1 -1
- package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-CQ9T7Lly.js → GrAutocomplete-CPEQxmLZ.js} +4 -3
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-CPEQxmLZ.js.map +1 -0
- package/dist/components/GrAutocomplete/index.js +1 -1
- package/dist/components/GrAutocomplete/styles.css +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-bnYBRGk8.js → GrColorPicker-DAdQ-Gc3.js} +4 -4
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-bnYBRGk8.js.map → GrColorPicker-DAdQ-Gc3.js.map} +1 -1
- package/dist/components/GrColorPicker/index.js +2 -2
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-MWDYDPNC.js → GrCommandPalette-DMeSqkEv.js} +6 -7
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-DMeSqkEv.js.map +1 -0
- package/dist/components/GrCommandPalette/index.js +1 -1
- package/dist/components/GrCommandPalette/styles.css +1 -1
- package/dist/components/GrConfigProvider/index.js +2 -2
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-DaQmlp1_.js → GrConfirmDialog-hUTi-GdJ.js} +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-DaQmlp1_.js.map → GrConfirmDialog-hUTi-GdJ.js.map} +1 -1
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-DVFho9Cj.js → GrDataTable-DzaGLG3A.js} +495 -47
- package/dist/components/GrDataTable/chunks/GrDataTable-DzaGLG3A.js.map +1 -0
- package/dist/components/GrDataTable/index.js +2 -2
- package/dist/components/GrDialog/chunks/{GrDialog-AE1gIZuz.js → GrDialog-MD9Fzy9C.js} +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-AE1gIZuz.js.map → GrDialog-MD9Fzy9C.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-B4DYWDkA.js → GrDialogService-DtgUijMj.js} +2 -2
- package/dist/components/GrDialogService/chunks/{GrDialogService-B4DYWDkA.js.map → GrDialogService-DtgUijMj.js.map} +1 -1
- package/dist/components/GrDialogService/index.js +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-DQwi6aRw.js → GrDrawer-DWHdZZzW.js} +2 -2
- package/dist/components/GrDrawer/chunks/{GrDrawer-DQwi6aRw.js.map → GrDrawer-DWHdZZzW.js.map} +1 -1
- package/dist/components/GrDrawer/index.js +2 -2
- package/dist/components/GrDropdown/chunks/{GrDropdown-BLng6V1m.js → GrDropdown-0tJK01Kq.js} +2 -2
- package/dist/components/GrDropdown/chunks/{GrDropdown-BLng6V1m.js.map → GrDropdown-0tJK01Kq.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BImk2Vs7.js → GrDropdownMenu-VPPrpCoA.js} +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BImk2Vs7.js.map → GrDropdownMenu-VPPrpCoA.js.map} +1 -1
- package/dist/components/GrDropdownMenu/index.js +1 -1
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-D0B-BEsd.js → GrFileUpload-DuDzC43S.js} +2 -2
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-D0B-BEsd.js.map → GrFileUpload-DuDzC43S.js.map} +1 -1
- package/dist/components/GrFileUpload/index.js +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-BeCnE8XQ.js → GrImageViewer-DE7MBbF8.js} +46 -22
- package/dist/components/GrImageViewer/chunks/GrImageViewer-DE7MBbF8.js.map +1 -0
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInput/chunks/{GrInput-DD2gYdqS.js → GrInput-2wd7Crs0.js} +1 -1
- package/dist/components/GrInput/chunks/GrInput-2wd7Crs0.js.map +1 -0
- package/dist/components/GrInput/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-DmNunixz.js → GrInputTag-CyV2eY7Z.js} +20 -33
- package/dist/components/GrInputTag/chunks/GrInputTag-CyV2eY7Z.js.map +1 -0
- package/dist/components/GrInputTag/index.js +1 -1
- package/dist/components/GrKbd/chunks/{GrKbd-DRFPvW3G.js → GrKbd-DU2lBkRV.js} +218 -52
- package/dist/components/GrKbd/chunks/GrKbd-DU2lBkRV.js.map +1 -0
- package/dist/components/GrKbd/index.js +3 -3
- package/dist/components/GrModal/chunks/{GrModal-B8I78T0N.js → GrModal-BbhcsDQ8.js} +1 -1
- package/dist/components/GrModal/chunks/{GrModal-B8I78T0N.js.map → GrModal-BbhcsDQ8.js.map} +1 -1
- package/dist/components/GrModal/index.js +1 -1
- package/dist/components/GrPagination/chunks/{GrPagination-B6N0QZBf.js → GrPagination-waKhxBP7.js} +4 -4
- package/dist/components/GrPagination/chunks/GrPagination-waKhxBP7.js.map +1 -0
- package/dist/components/GrPagination/index.js +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-B1eRCOoO.js → GrPopover-DuqeoFaI.js} +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-B1eRCOoO.js.map → GrPopover-DuqeoFaI.js.map} +1 -1
- package/dist/components/GrPopover/index.js +1 -1
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-BiHnaitu.js → GrProgressBar-xwbNM9QB.js} +1 -1
- package/dist/components/GrProgressBar/chunks/GrProgressBar-xwbNM9QB.js.map +1 -0
- package/dist/components/GrProgressBar/index.js +1 -1
- package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-CTogjcHz.js → GrProgressCircle-B8olXRo5.js} +1 -1
- package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-CTogjcHz.js.map → GrProgressCircle-B8olXRo5.js.map} +1 -1
- package/dist/components/GrProgressCircle/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-Ct174NVD.js → GrPromptDialog-JVVqBsPY.js} +3 -3
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-Ct174NVD.js.map → GrPromptDialog-JVVqBsPY.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +1 -1
- package/dist/components/GrRadio/chunks/{GrRadio-DksDro_U.js → GrRadio-DWiRaMzt.js} +8 -32
- package/dist/components/GrRadio/chunks/GrRadio-DWiRaMzt.js.map +1 -0
- package/dist/components/GrRadio/index.js +1 -1
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-BOIhejE6.js → GrRadioGroup-DIuBw0wk.js} +34 -27
- package/dist/components/GrRadioGroup/chunks/GrRadioGroup-DIuBw0wk.js.map +1 -0
- package/dist/components/GrRadioGroup/index.js +1 -1
- package/dist/components/GrRating/chunks/{GrRating-JrHXz0Rv.js → GrRating-LarIiwJL.js} +2 -2
- package/dist/components/GrRating/chunks/GrRating-LarIiwJL.js.map +1 -0
- package/dist/components/GrRating/index.js +2 -2
- package/dist/components/GrSegmented/chunks/{GrSegmented-BQIlH5KI.js → GrSegmented-CQw3ijqa.js} +47 -65
- package/dist/components/GrSegmented/chunks/GrSegmented-CQw3ijqa.js.map +1 -0
- package/dist/components/GrSegmented/index.js +1 -1
- package/dist/components/GrSelect/chunks/{GrSelect-aqkPCqjd.js → GrSelect-DAdu044K.js} +4 -3
- package/dist/components/GrSelect/chunks/GrSelect-DAdu044K.js.map +1 -0
- package/dist/components/GrSelect/index.js +1 -1
- package/dist/components/GrSlider/chunks/{GrSlider-DkU9IQSX.js → GrSlider-CyhVsNKn.js} +21 -34
- package/dist/components/GrSlider/chunks/GrSlider-CyhVsNKn.js.map +1 -0
- package/dist/components/GrSlider/index.js +2 -2
- package/dist/components/GrSortableList/chunks/GrSortableList-BefVfWKh.js +276 -0
- package/dist/components/GrSortableList/chunks/GrSortableList-BefVfWKh.js.map +1 -0
- package/dist/components/GrSortableList/index.js +3 -0
- package/dist/components/GrSplitter/chunks/{GrSplitter-7To8jbJ8.js → GrSplitter-BzxVQwbY.js} +17 -37
- package/dist/components/GrSplitter/chunks/GrSplitter-BzxVQwbY.js.map +1 -0
- package/dist/components/GrSplitter/index.js +2 -2
- package/dist/components/GrStatistic/chunks/{GrStatistic-CttyoYPT.js → GrStatistic-J4qLs3TH.js} +1 -1
- package/dist/components/GrStatistic/chunks/{GrStatistic-CttyoYPT.js.map → GrStatistic-J4qLs3TH.js.map} +1 -1
- package/dist/components/GrStatistic/index.js +2 -2
- package/dist/components/GrSwitch/chunks/{GrSwitch-B9TYbiih.js → GrSwitch-DpyvVrZG.js} +1 -1
- package/dist/components/GrSwitch/chunks/{GrSwitch-B9TYbiih.js.map → GrSwitch-DpyvVrZG.js.map} +1 -1
- package/dist/components/GrSwitch/index.js +2 -2
- package/dist/components/GrTabPanels/index.js +1 -1
- package/dist/components/GrTable/chunks/{GrTable-BB-mI_NM.js → GrTable-BfqgwETQ.js} +7 -1
- package/dist/components/GrTable/chunks/GrTable-BfqgwETQ.js.map +1 -0
- package/dist/components/GrTable/index.js +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-B8CDq2D9.js → GrTabs-TeXaU5Uh.js} +50 -61
- package/dist/components/GrTabs/chunks/GrTabs-TeXaU5Uh.js.map +1 -0
- package/dist/components/GrTabs/index.js +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-DUh5Tlo4.js → GrTextarea-DSvd1nSy.js} +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-DUh5Tlo4.js.map → GrTextarea-DSvd1nSy.js.map} +1 -1
- package/dist/components/GrTextarea/index.js +2 -2
- package/dist/components/GrTimeline/chunks/{GrTimeline-CE9b3s18.js → GrTimeline-B-h2Yanw.js} +1 -1
- package/dist/components/GrTimeline/chunks/{GrTimeline-CE9b3s18.js.map → GrTimeline-B-h2Yanw.js.map} +1 -1
- package/dist/components/GrTimeline/index.js +2 -2
- package/dist/components/GrToaster/chunks/{GrToaster-BKQy3Srm.js → GrToaster-Ct-39hga.js} +113 -12
- package/dist/components/GrToaster/chunks/GrToaster-Ct-39hga.js.map +1 -0
- package/dist/components/GrToaster/index.js +2 -2
- package/dist/components/GrToaster/styles.css +1 -1
- package/dist/components/GrTooltip/chunks/{GrTooltip-DEbejfhA.js → GrTooltip-xAcqs0bP.js} +1 -1
- package/dist/components/GrTooltip/chunks/{GrTooltip-DEbejfhA.js.map → GrTooltip-xAcqs0bP.js.map} +1 -1
- package/dist/components/GrTooltip/index.js +2 -2
- package/dist/components/GrTree/chunks/{GrTree-wfdbvygw.js → GrTree-CaYK8dGZ.js} +124 -92
- package/dist/components/GrTree/chunks/GrTree-CaYK8dGZ.js.map +1 -0
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTree/styles.css +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-lLWmAMtI.js → GrTreeSelect-DZp7CqqW.js} +4 -4
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-lLWmAMtI.js.map → GrTreeSelect-DZp7CqqW.js.map} +1 -1
- package/dist/components/GrTreeSelect/index.js +2 -2
- package/dist/composables/useComboboxNavigation.js +71 -0
- package/dist/composables/useComboboxNavigation.js.map +1 -0
- package/dist/composables/useDismissible.js +1 -1
- package/dist/composables/useDragGesture.js +55 -0
- package/dist/composables/useDragGesture.js.map +1 -0
- package/dist/composables/useDragSort.js +2 -0
- package/dist/composables/useFloating.js +22 -1
- package/dist/composables/useFloating.js.map +1 -1
- package/dist/composables/useGrComponentConfig.js +2 -0
- package/dist/composables/useGranularityTranslations.js +2 -0
- package/dist/composables/useOverlayLayer.js +64 -1
- package/dist/composables/useOverlayLayer.js.map +1 -0
- package/dist/composables/useRovingFocus.js +150 -0
- package/dist/composables/useRovingFocus.js.map +1 -0
- package/dist/directives/hotkey.js +13 -7
- package/dist/directives/hotkey.js.map +1 -1
- package/dist/granular-provider-node.js +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/i18n/all.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.js +67 -58
- package/dist/tokens.js +84 -0
- package/dist/tokens.js.map +1 -1
- package/dist/types/src/components/GrAlert/defaults.d.ts +1 -1
- package/dist/types/src/components/GrAutocomplete/defaults.d.ts +1 -1
- package/dist/types/src/components/GrAvatar/defaults.d.ts +1 -1
- package/dist/types/src/components/GrBadge/defaults.d.ts +1 -1
- package/dist/types/src/components/GrBottomNav/defaults.d.ts +1 -1
- package/dist/types/src/components/GrBreadcrumbs/defaults.d.ts +1 -1
- package/dist/types/src/components/GrButton/defaults.d.ts +1 -1
- package/dist/types/src/components/GrCard/defaults.d.ts +1 -1
- package/dist/types/src/components/GrCheckbox/defaults.d.ts +1 -1
- package/dist/types/src/components/GrCheckboxGroup/defaults.d.ts +1 -1
- package/dist/types/src/components/GrCollapse/defaults.d.ts +1 -1
- package/dist/types/src/components/GrColorPicker/defaults.d.ts +1 -1
- package/dist/types/src/components/GrColorPicker/grColorPickerStyles.d.ts +2 -2
- package/dist/types/src/components/GrCommandPalette/defaults.d.ts +1 -1
- package/dist/types/src/components/GrConfigProvider/context.d.ts +6 -22
- package/dist/types/src/components/GrConfigProvider/index.d.ts +1 -1
- package/dist/types/src/components/GrConfirmDialog/defaults.d.ts +1 -1
- package/dist/types/src/components/GrDataTable/GrDataTable.vue.d.ts +53 -0
- package/dist/types/src/components/GrDataTable/defaults.d.ts +1 -1
- package/dist/types/src/components/GrDataTable/grDataTableStyles.d.ts +39 -0
- package/dist/types/src/components/GrDialog/defaults.d.ts +1 -1
- package/dist/types/src/components/GrDivider/defaults.d.ts +1 -1
- package/dist/types/src/components/GrDrawer/defaults.d.ts +1 -1
- package/dist/types/src/components/GrEmptyState/defaults.d.ts +1 -1
- package/dist/types/src/components/GrFileUpload/defaults.d.ts +1 -1
- package/dist/types/src/components/GrFormField/defaults.d.ts +1 -1
- package/dist/types/src/components/GrFormFile/defaults.d.ts +1 -1
- package/dist/types/src/components/GrFormSection/defaults.d.ts +1 -1
- package/dist/types/src/components/GrIcon/defaults.d.ts +1 -1
- package/dist/types/src/components/GrImageViewer/composables/usePointerGestures.d.ts +1 -0
- package/dist/types/src/components/GrImageViewer/composables/useZoomPan.d.ts +1 -2
- package/dist/types/src/components/GrInput/defaults.d.ts +1 -1
- package/dist/types/src/components/GrInputTag/defaults.d.ts +1 -1
- package/dist/types/src/components/GrKbd/GrKbd.vue.d.ts +18 -3
- package/dist/types/src/components/GrKbd/defaults.d.ts +1 -1
- package/dist/types/src/components/GrKbd/grKbdStyles.d.ts +20 -3
- package/dist/types/src/components/GrKbd/index.d.ts +6 -0
- package/dist/types/src/components/GrLink/defaults.d.ts +1 -1
- package/dist/types/src/components/GrModal/defaults.d.ts +1 -1
- package/dist/types/src/components/GrNumberInput/defaults.d.ts +1 -1
- package/dist/types/src/components/GrPagination/defaults.d.ts +1 -1
- package/dist/types/src/components/GrPopover/GrPopover.vue.d.ts +1 -1
- package/dist/types/src/components/GrPopover/defaults.d.ts +1 -1
- package/dist/types/src/components/GrProgressBar/defaults.d.ts +1 -1
- package/dist/types/src/components/GrProgressCircle/defaults.d.ts +1 -1
- package/dist/types/src/components/GrProgressCircle/grProgressCircleStyles.d.ts +1 -1
- package/dist/types/src/components/GrPromptDialog/defaults.d.ts +1 -1
- package/dist/types/src/components/GrRadio/defaults.d.ts +1 -1
- package/dist/types/src/components/GrRadio/grRadioGroupContext.d.ts +12 -4
- package/dist/types/src/components/GrRadioGroup/defaults.d.ts +1 -1
- package/dist/types/src/components/GrRating/defaults.d.ts +1 -1
- package/dist/types/src/components/GrSegmented/defaults.d.ts +1 -1
- package/dist/types/src/components/GrSelect/defaults.d.ts +1 -1
- package/dist/types/src/components/GrSlider/defaults.d.ts +1 -1
- package/dist/types/src/components/GrSortableList/GrSortableList.vue.d.ts +68 -0
- package/dist/types/src/components/GrSortableList/config.d.ts +1 -0
- package/dist/types/src/components/GrSortableList/grSortableListStyles.d.ts +38 -0
- package/dist/types/src/components/GrSortableList/index.d.ts +9 -0
- package/dist/types/src/components/GrSortableList/safelist.d.ts +1 -0
- package/dist/types/src/components/GrSplitter/defaults.d.ts +1 -1
- package/dist/types/src/components/GrStatistic/defaults.d.ts +1 -1
- package/dist/types/src/components/GrStatistic/grStatisticStyles.d.ts +1 -1
- package/dist/types/src/components/GrSwitch/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTable/GrTable.vue.d.ts +13 -0
- package/dist/types/src/components/GrTable/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTabs/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTextarea/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTextarea/grTextareaStyles.d.ts +2 -2
- package/dist/types/src/components/GrTimeline/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTimeline/grTimelineStyles.d.ts +1 -1
- package/dist/types/src/components/GrToaster/GrToaster.vue.d.ts +8 -0
- package/dist/types/src/components/GrToaster/grToasterStyles.d.ts +27 -0
- package/dist/types/src/components/GrTooltip/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTree/defaults.d.ts +1 -1
- package/dist/types/src/components/GrTree/grTreeInteractionContext.d.ts +0 -1
- package/dist/types/src/components/GrTreeSelect/defaults.d.ts +1 -1
- package/dist/types/src/components/shared/hotkey.d.ts +7 -15
- package/dist/types/src/components/shared/hotkeyTokens.d.ts +37 -0
- package/dist/types/src/composables/internal/dragSortGeometry.d.ts +59 -0
- package/dist/types/src/composables/internal/overlayStack.d.ts +11 -0
- package/dist/types/src/composables/useDragGesture.d.ts +63 -0
- package/dist/types/src/composables/useDragSort.d.ts +80 -0
- package/dist/types/src/composables/useFloating.d.ts +5 -1
- package/dist/types/src/composables/useGrComponentConfig.d.ts +41 -0
- package/dist/types/src/composables/useGranularityTranslations.d.ts +13 -0
- package/dist/types/src/composables/useRovingFocus.d.ts +108 -0
- package/dist/types/src/granular-provider/shared.d.ts +1 -0
- package/dist/types/src/i18n/messages/en.d.ts +48 -0
- package/dist/types/src/i18n/messages/es.d.ts +48 -0
- package/dist/types/src/i18n/messages/ru.d.ts +48 -0
- package/dist/types/src/index.d.ts +12 -0
- package/dist/types/src/internal/keyboard.d.ts +6 -0
- package/dist/web-types.json +201 -3
- package/package.json +31 -3
- package/dist/chunks/config-B-g6lT19.js.map +0 -1
- package/dist/chunks/config-BE6n20np.js.map +0 -1
- package/dist/chunks/config-BNfQwyL4.js +0 -97
- package/dist/chunks/config-BNfQwyL4.js.map +0 -1
- package/dist/chunks/config-BoNR7_PD.js.map +0 -1
- package/dist/chunks/config-CN2ULSQL2.js.map +0 -1
- package/dist/chunks/config-Cw6TDzWv2.js.map +0 -1
- package/dist/chunks/config-D94Z9po52.js.map +0 -1
- package/dist/chunks/config-DCFvmHEv.js.map +0 -1
- package/dist/chunks/config-DxCTVBfx.js.map +0 -1
- package/dist/chunks/config-LGrZIdaZ.js +0 -21
- package/dist/chunks/config-LGrZIdaZ.js.map +0 -1
- package/dist/chunks/config-T3qdQBgU.js.map +0 -1
- package/dist/chunks/config-eXB87DOi2.js.map +0 -1
- package/dist/chunks/en-B3xMeswz.js.map +0 -1
- package/dist/chunks/es-CA-mkU--.js.map +0 -1
- package/dist/chunks/grKbdStyles-DAoxiytu.js +0 -31
- package/dist/chunks/grKbdStyles-DAoxiytu.js.map +0 -1
- package/dist/chunks/granular-provider-CtrXGa7c.js.map +0 -1
- package/dist/chunks/keyboard-zYvvyHd4.js.map +0 -1
- package/dist/chunks/optionFilter-BVY988pC.js.map +0 -1
- package/dist/chunks/ru-COWxgh2A.js.map +0 -1
- package/dist/chunks/useOverlayLayer-BupuP_hs.js.map +0 -1
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-CQ9T7Lly.js.map +0 -1
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-MWDYDPNC.js.map +0 -1
- package/dist/components/GrDataTable/chunks/GrDataTable-DVFho9Cj.js.map +0 -1
- package/dist/components/GrImageViewer/chunks/GrImageViewer-BeCnE8XQ.js.map +0 -1
- package/dist/components/GrInput/chunks/GrInput-DD2gYdqS.js.map +0 -1
- package/dist/components/GrInputTag/chunks/GrInputTag-DmNunixz.js.map +0 -1
- package/dist/components/GrKbd/chunks/GrKbd-DRFPvW3G.js.map +0 -1
- package/dist/components/GrPagination/chunks/GrPagination-B6N0QZBf.js.map +0 -1
- package/dist/components/GrProgressBar/chunks/GrProgressBar-BiHnaitu.js.map +0 -1
- package/dist/components/GrRadio/chunks/GrRadio-DksDro_U.js.map +0 -1
- package/dist/components/GrRadioGroup/chunks/GrRadioGroup-BOIhejE6.js.map +0 -1
- package/dist/components/GrRating/chunks/GrRating-JrHXz0Rv.js.map +0 -1
- package/dist/components/GrSegmented/chunks/GrSegmented-BQIlH5KI.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-aqkPCqjd.js.map +0 -1
- package/dist/components/GrSlider/chunks/GrSlider-DkU9IQSX.js.map +0 -1
- package/dist/components/GrSplitter/chunks/GrSplitter-7To8jbJ8.js.map +0 -1
- package/dist/components/GrTable/chunks/GrTable-BB-mI_NM.js.map +0 -1
- package/dist/components/GrTabs/chunks/GrTabs-B8CDq2D9.js.map +0 -1
- package/dist/components/GrToaster/chunks/GrToaster-BKQy3Srm.js.map +0 -1
- package/dist/components/GrTree/chunks/GrTree-wfdbvygw.js.map +0 -1
- /package/dist/chunks/{config-BE6n20np.js → config-BE6n20np2.js} +0 -0
- /package/dist/chunks/{config-BoNR7_PD.js → config-BoNR7_PD2.js} +0 -0
- /package/dist/chunks/{config-CN2ULSQL2.js → config-CN2ULSQL.js} +0 -0
- /package/dist/chunks/{config-D94Z9po52.js → config-D94Z9po5.js} +0 -0
- /package/dist/chunks/{config-DCFvmHEv.js → config-DCFvmHEv2.js} +0 -0
- /package/dist/chunks/{config-T3qdQBgU.js → config-T3qdQBgU2.js} +0 -0
- /package/dist/chunks/{config-eXB87DOi2.js → config-eXB87DOi.js} +0 -0
- /package/dist/types/src/composables/{internal/useComboboxNavigation.d.ts → useComboboxNavigation.d.ts} +0 -0
package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-BOIhejE6.js → GrRadioGroup-DIuBw0wk.js}
RENAMED
|
@@ -3,8 +3,9 @@ import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js"
|
|
|
3
3
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
4
4
|
import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
|
|
5
5
|
import { t as GrButtonGroup_default } from "../../GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { useRovingFocus } from "../../../composables/useRovingFocus.js";
|
|
7
|
+
import { n as GR_RADIO_GROUP_CONTEXT, t as GrRadio_default } from "../../GrRadio/chunks/GrRadio-DWiRaMzt.js";
|
|
8
|
+
import { Fragment, computed, createBlock, createElementBlock, createSlots, createTextVNode, defineComponent, nextTick, normalizeClass, openBlock, provide, ref, renderList, renderSlot, toDisplayString, unref, withCtx } from "vue";
|
|
8
9
|
//#region src/components/GrRadioGroup/GrRadioGroup.vue?vue&type=script&setup=true&lang.ts
|
|
9
10
|
var _hoisted_1 = [
|
|
10
11
|
"id",
|
|
@@ -75,12 +76,6 @@ var GrRadioGroup_default = /* @__PURE__ */ defineComponent({
|
|
|
75
76
|
enter: (event) => emit("focus", event),
|
|
76
77
|
leave: (event) => emit("blur", event)
|
|
77
78
|
});
|
|
78
|
-
function focus() {
|
|
79
|
-
rootEl.value?.querySelector("[role=\"radio\"][tabindex=\"0\"]")?.focus();
|
|
80
|
-
}
|
|
81
|
-
function blur() {
|
|
82
|
-
rootEl.value?.querySelector("[role=\"radio\"][tabindex=\"0\"]")?.blur();
|
|
83
|
-
}
|
|
84
79
|
__expose({
|
|
85
80
|
focus,
|
|
86
81
|
blur
|
|
@@ -93,24 +88,37 @@ var GrRadioGroup_default = /* @__PURE__ */ defineComponent({
|
|
|
93
88
|
if (index >= 0) entries.value.splice(index, 1);
|
|
94
89
|
};
|
|
95
90
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
function entryOf(value) {
|
|
92
|
+
return entries.value.find((entry) => entry.value() === value);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Кольцо roving-фокуса. Живёт в группе, а не в переключателе: состав знает
|
|
96
|
+
* только она. Обе оси работают всегда — требование паттерна `radiogroup`,
|
|
97
|
+
* стрелки зациклены, выключенные перешагиваются.
|
|
98
|
+
*/
|
|
99
|
+
const roving = useRovingFocus({
|
|
100
|
+
items: () => entries.value.map((entry) => entry.value()),
|
|
101
|
+
elementFor: (value) => entryOf(value)?.el() ?? null,
|
|
102
|
+
isDisabled: (value) => entryOf(value)?.disabled() ?? true,
|
|
103
|
+
orientation: () => "both",
|
|
104
|
+
skipDisabled: () => true,
|
|
105
|
+
initialKey: () => {
|
|
106
|
+
const entry = entryOf(props.modelValue);
|
|
107
|
+
return entry && !entry.disabled() ? props.modelValue : void 0;
|
|
108
|
+
},
|
|
109
|
+
onMove: (value) => setValue(value),
|
|
110
|
+
beforeFocus: () => nextTick()
|
|
100
111
|
});
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый элемент. */
|
|
113
|
+
function rovingElement() {
|
|
114
|
+
const value = roving.rovingKey.value;
|
|
115
|
+
return value === void 0 ? null : entryOf(value)?.el() ?? null;
|
|
116
|
+
}
|
|
117
|
+
function focus() {
|
|
118
|
+
rovingElement()?.focus();
|
|
107
119
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const values = enabledValues.value;
|
|
111
|
-
const next = edge === "first" ? values[0] : values.at(-1);
|
|
112
|
-
if (next !== void 0) setValue(next);
|
|
113
|
-
return next;
|
|
120
|
+
function blur() {
|
|
121
|
+
rovingElement()?.blur();
|
|
114
122
|
}
|
|
115
123
|
provide(GR_RADIO_GROUP_CONTEXT, {
|
|
116
124
|
modelValue: computed(() => props.modelValue),
|
|
@@ -121,9 +129,8 @@ var GrRadioGroup_default = /* @__PURE__ */ defineComponent({
|
|
|
121
129
|
size: resolvedSize,
|
|
122
130
|
setValue,
|
|
123
131
|
register,
|
|
124
|
-
rovingValue,
|
|
125
|
-
|
|
126
|
-
selectEdge
|
|
132
|
+
rovingValue: roving.rovingKey,
|
|
133
|
+
handleNavigationKeys: roving.handleNavigationKeys
|
|
127
134
|
});
|
|
128
135
|
return (_ctx, _cache) => {
|
|
129
136
|
return openBlock(), createElementBlock("div", {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrRadioGroup-DIuBw0wk.js","names":["$slots"],"sources":["../../../../src/components/GrRadioGroup/GrRadioGroup.vue","../../../../src/components/GrRadioGroup/GrRadioGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport type { GrButtonSize } from '../GrButton'\nimport GrButtonGroup from '../GrButtonGroup/GrButtonGroup.vue'\nimport GrRadio from '../GrRadio/GrRadio.vue'\nimport { GR_RADIO_GROUP_CONTEXT } from '../GrRadio'\nimport type { GrRadioEntry, GrRadioValue } from '../GrRadio/grRadioGroupContext'\n\nexport type GrRadioGroupVariant = 'radiobox' | 'button'\nexport type GrRadioGroupOrientation = 'vertical' | 'horizontal'\nexport interface GrRadioGroupOption {\n value: GrRadioValue\n label: string\n /** Отключить одну опцию, не переходя на слот. */\n disabled?: boolean\n /** Пояснение под подписью. Рисуется только в варианте `radiobox`. */\n description?: string\n}\n\n/**\n * GrRadioGroup — контейнер группы `GrRadio`.\n *\n * Может работать как через слот (ручной рендер `GrRadio`), так и через проп `options`.\n * Предоставляет дочерним `GrRadio` общий `modelValue`/`disabled`/`size`/`name` через `inject`.\n */\nexport interface GrRadioGroupProps {\n modelValue: GrRadioValue\n options?: GrRadioGroupOption[]\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n variant?: GrRadioGroupVariant\n /**\n * Раскладка варианта `radiobox`. Кнопочный вариант всегда горизонтальный —\n * его собирает `GrButtonGroup`.\n */\n orientation?: GrRadioGroupOrientation\n size?: GrButtonSize\n ariaLabel?: string\n}\n\nexport interface GrRadioGroupEmits {\n (e: 'update:modelValue', value: GrRadioValue): void\n (e: 'change', value: GrRadioValue): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrRadioGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n variant: 'radiobox',\n orientation: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние `GrRadio` получают уже разрешённое значение через контекст, поэтому\n// провайдер работает и для них — без второго чтения конфига.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrRadioGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid, required: isRequired, readonly: isReadonly } = useGrFormControl(() => props)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\n\nconst emit = defineEmits<GrRadioGroupEmits>()\ndefineSlots<{\n /** Собственная разметка переключателей вместо генерации из `options`. */\n default?: () => any\n}>()\n\n\nfunction setValue(next: GrRadioValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nconst listClass = computed(() => (props.orientation === 'horizontal'\n ? 'flex flex-wrap items-start gap-x-6 gap-y-2'\n : 'grid gap-2'))\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Фокус ходит между радиокнопками: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\n\nconst entries = ref<GrRadioEntry[]>([])\n\nfunction register(entry: GrRadioEntry): () => void {\n entries.value.push(entry)\n return () => {\n const index = entries.value.indexOf(entry)\n if (index >= 0) entries.value.splice(index, 1)\n }\n}\n\nfunction entryOf(value: GrRadioValue): GrRadioEntry | undefined {\n return entries.value.find(entry => entry.value() === value)\n}\n\n/**\n * Кольцо roving-фокуса. Живёт в группе, а не в переключателе: состав знает\n * только она. Обе оси работают всегда — требование паттерна `radiogroup`,\n * стрелки зациклены, выключенные перешагиваются.\n */\nconst roving = useRovingFocus<GrRadioValue>({\n items: () => entries.value.map(entry => entry.value()),\n elementFor: value => entryOf(value)?.el() ?? null,\n isDisabled: value => entryOf(value)?.disabled() ?? true,\n orientation: () => 'both',\n skipDisabled: () => true,\n // Выбранное значение держит остановку `Tab` — но только пока переключатель\n // доступен: на выключенном `GrRadio` ставит `tabindex=\"-1\"` сам, и остановка\n // на нём означала бы, что `Tab` не приводит никуда.\n initialKey: () => {\n const entry = entryOf(props.modelValue)\n return entry && !entry.disabled() ? props.modelValue : undefined\n },\n // В `radiogroup` стрелка переносит выбор, а не только фокус.\n onMove: value => setValue(value),\n // Выбор меняет разметку: фокус ставим по перерисовке, иначе следующая\n // стрелка отсчитывалась бы от прежнего элемента.\n beforeFocus: () => nextTick(),\n})\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый элемент. */\nfunction rovingElement(): HTMLElement | null {\n const value = roving.rovingKey.value\n return value === undefined ? null : entryOf(value)?.el() ?? null\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nprovide(GR_RADIO_GROUP_CONTEXT, {\n modelValue: computed(() => props.modelValue),\n name: computed(() => props.name),\n disabled: computed(() => isDisabled.value),\n readonly: isReadonly,\n invalid: isInvalid,\n size: resolvedSize,\n setValue,\n register,\n rovingValue: roving.rovingKey,\n handleNavigationKeys: roving.handleNavigationKeys,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-radio-group\n role=\"radiogroup\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <template v-if=\"$slots.default\">\n <GrButtonGroup v-if=\"variant === 'button'\">\n <slot />\n </GrButtonGroup>\n <div v-else :class=\"listClass\">\n <slot />\n </div>\n </template>\n <template v-else>\n <GrButtonGroup v-if=\"variant === 'button'\">\n <GrRadio\n v-for=\"opt in options ?? []\"\n :key=\"String(opt.value)\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled\"\n variant=\"button\"\n :size=\"resolvedSize\"\n >\n {{ opt.label }}\n </GrRadio>\n </GrButtonGroup>\n <div v-else :class=\"listClass\">\n <GrRadio\n v-for=\"opt in options ?? []\"\n :key=\"String(opt.value)\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled\"\n >\n {{ opt.label }}\n\n <template v-if=\"opt.description\" #description>\n {{ opt.description }}\n </template>\n </GrRadio>\n </div>\n </template>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport type { GrButtonSize } from '../GrButton'\nimport GrButtonGroup from '../GrButtonGroup/GrButtonGroup.vue'\nimport GrRadio from '../GrRadio/GrRadio.vue'\nimport { GR_RADIO_GROUP_CONTEXT } from '../GrRadio'\nimport type { GrRadioEntry, GrRadioValue } from '../GrRadio/grRadioGroupContext'\n\nexport type GrRadioGroupVariant = 'radiobox' | 'button'\nexport type GrRadioGroupOrientation = 'vertical' | 'horizontal'\nexport interface GrRadioGroupOption {\n value: GrRadioValue\n label: string\n /** Отключить одну опцию, не переходя на слот. */\n disabled?: boolean\n /** Пояснение под подписью. Рисуется только в варианте `radiobox`. */\n description?: string\n}\n\n/**\n * GrRadioGroup — контейнер группы `GrRadio`.\n *\n * Может работать как через слот (ручной рендер `GrRadio`), так и через проп `options`.\n * Предоставляет дочерним `GrRadio` общий `modelValue`/`disabled`/`size`/`name` через `inject`.\n */\nexport interface GrRadioGroupProps {\n modelValue: GrRadioValue\n options?: GrRadioGroupOption[]\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n variant?: GrRadioGroupVariant\n /**\n * Раскладка варианта `radiobox`. Кнопочный вариант всегда горизонтальный —\n * его собирает `GrButtonGroup`.\n */\n orientation?: GrRadioGroupOrientation\n size?: GrButtonSize\n ariaLabel?: string\n}\n\nexport interface GrRadioGroupEmits {\n (e: 'update:modelValue', value: GrRadioValue): void\n (e: 'change', value: GrRadioValue): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrRadioGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n variant: 'radiobox',\n orientation: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние `GrRadio` получают уже разрешённое значение через контекст, поэтому\n// провайдер работает и для них — без второго чтения конфига.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrRadioGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid, required: isRequired, readonly: isReadonly } = useGrFormControl(() => props)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\n\nconst emit = defineEmits<GrRadioGroupEmits>()\ndefineSlots<{\n /** Собственная разметка переключателей вместо генерации из `options`. */\n default?: () => any\n}>()\n\n\nfunction setValue(next: GrRadioValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nconst listClass = computed(() => (props.orientation === 'horizontal'\n ? 'flex flex-wrap items-start gap-x-6 gap-y-2'\n : 'grid gap-2'))\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Фокус ходит между радиокнопками: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\n\nconst entries = ref<GrRadioEntry[]>([])\n\nfunction register(entry: GrRadioEntry): () => void {\n entries.value.push(entry)\n return () => {\n const index = entries.value.indexOf(entry)\n if (index >= 0) entries.value.splice(index, 1)\n }\n}\n\nfunction entryOf(value: GrRadioValue): GrRadioEntry | undefined {\n return entries.value.find(entry => entry.value() === value)\n}\n\n/**\n * Кольцо roving-фокуса. Живёт в группе, а не в переключателе: состав знает\n * только она. Обе оси работают всегда — требование паттерна `radiogroup`,\n * стрелки зациклены, выключенные перешагиваются.\n */\nconst roving = useRovingFocus<GrRadioValue>({\n items: () => entries.value.map(entry => entry.value()),\n elementFor: value => entryOf(value)?.el() ?? null,\n isDisabled: value => entryOf(value)?.disabled() ?? true,\n orientation: () => 'both',\n skipDisabled: () => true,\n // Выбранное значение держит остановку `Tab` — но только пока переключатель\n // доступен: на выключенном `GrRadio` ставит `tabindex=\"-1\"` сам, и остановка\n // на нём означала бы, что `Tab` не приводит никуда.\n initialKey: () => {\n const entry = entryOf(props.modelValue)\n return entry && !entry.disabled() ? props.modelValue : undefined\n },\n // В `radiogroup` стрелка переносит выбор, а не только фокус.\n onMove: value => setValue(value),\n // Выбор меняет разметку: фокус ставим по перерисовке, иначе следующая\n // стрелка отсчитывалась бы от прежнего элемента.\n beforeFocus: () => nextTick(),\n})\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый элемент. */\nfunction rovingElement(): HTMLElement | null {\n const value = roving.rovingKey.value\n return value === undefined ? null : entryOf(value)?.el() ?? null\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nprovide(GR_RADIO_GROUP_CONTEXT, {\n modelValue: computed(() => props.modelValue),\n name: computed(() => props.name),\n disabled: computed(() => isDisabled.value),\n readonly: isReadonly,\n invalid: isInvalid,\n size: resolvedSize,\n setValue,\n register,\n rovingValue: roving.rovingKey,\n handleNavigationKeys: roving.handleNavigationKeys,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-radio-group\n role=\"radiogroup\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <template v-if=\"$slots.default\">\n <GrButtonGroup v-if=\"variant === 'button'\">\n <slot />\n </GrButtonGroup>\n <div v-else :class=\"listClass\">\n <slot />\n </div>\n </template>\n <template v-else>\n <GrButtonGroup v-if=\"variant === 'button'\">\n <GrRadio\n v-for=\"opt in options ?? []\"\n :key=\"String(opt.value)\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled\"\n variant=\"button\"\n :size=\"resolvedSize\"\n >\n {{ opt.label }}\n </GrRadio>\n </GrButtonGroup>\n <div v-else :class=\"listClass\">\n <GrRadio\n v-for=\"opt in options ?? []\"\n :key=\"String(opt.value)\"\n :value=\"opt.value\"\n :disabled=\"opt.disabled\"\n >\n {{ opt.label }}\n\n <template v-if=\"opt.description\" #description>\n {{ opt.description }}\n </template>\n </GrRadio>\n </div>\n </template>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrRadioGroup_default } from "./chunks/GrRadioGroup-
|
|
1
|
+
import { t as GrRadioGroup_default } from "./chunks/GrRadioGroup-DIuBw0wk.js";
|
|
2
2
|
import { t as grRadioGroupConfig } from "../../chunks/config-QaIc_gRa.js";
|
|
3
3
|
export { GrRadioGroup_default as GrRadioGroup, GrRadioGroup_default as default, grRadioGroupConfig };
|
|
@@ -2,7 +2,7 @@ import { o as useGrComponentSize } from "../../../chunks/context-BSYR7RZs.js";
|
|
|
2
2
|
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
|
|
3
3
|
import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js";
|
|
4
4
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
5
|
-
import { a as ratingSymbolClass, i as ratingRootClass, o as ratingTextSizeBySize, r as ratingFillClassByTone, s as ratingVoidClass } from "../../../chunks/config-
|
|
5
|
+
import { a as ratingSymbolClass, i as ratingRootClass, o as ratingTextSizeBySize, r as ratingFillClassByTone, s as ratingVoidClass } from "../../../chunks/config-Baj7Wvx-.js";
|
|
6
6
|
import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, toDisplayString, unref } from "vue";
|
|
7
7
|
//#region src/components/GrRating/GrRating.vue?vue&type=script&setup=true&lang.ts
|
|
8
8
|
var _hoisted_1 = ["name", "value"];
|
|
@@ -305,7 +305,7 @@ var GrRating_default = /* @__PURE__ */ defineComponent({
|
|
|
305
305
|
__props.showText || _ctx.$slots.text ? (openBlock(), createElementBlock("span", {
|
|
306
306
|
key: 1,
|
|
307
307
|
"data-gr-rating-text": "",
|
|
308
|
-
class: normalizeClass(["text-[var(--gr-muted-fg)]
|
|
308
|
+
class: normalizeClass(["text-[var(--gr-muted-fg)] tabular-nums", unref(ratingTextSizeBySize)[unref(resolvedSize)]])
|
|
309
309
|
}, [renderSlot(_ctx.$slots, "text", { value: displayValue.value }, () => [createTextVNode(toDisplayString(text.value), 1)])], 2)) : createCommentVNode("", true)
|
|
310
310
|
], 512);
|
|
311
311
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrRating-LarIiwJL.js","names":["$slots"],"sources":["../../../../src/components/GrRating/GrRating.vue","../../../../src/components/GrRating/GrRating.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport {\n ratingFillClassByTone,\n ratingRootClass,\n ratingSymbolClass,\n ratingTextSizeBySize,\n ratingVoidClass,\n type GrRatingSize,\n type GrRatingTone,\n} from './grRatingStyles'\n\nexport type {\n GrRatingSize,\n GrRatingTone,\n} from './grRatingStyles'\n\n/**\n * Публичный GR-примитив «Rating» — шкала оценки символами (по умолчанию звёзды).\n *\n * Интерактивный режим реализует WAI-ARIA slider pattern (`role=\"slider\"`,\n * `aria-valuemin/max/now/valuetext`, стрелки / Home / End), режим только для\n * чтения — `role=\"img\"` с текстовой подписью, чтобы скринридер озвучил оценку\n * одной фразой, а не набором элементов.\n *\n * Символ по умолчанию рисуется инлайновым SVG (звезда с `fill=\"currentColor\"`) —\n * иконочные шрифты-маски `i-lucide-star` дают только контур. Свой символ\n * задаётся пропом `icon` (UnoCSS-класс иконки) или слотом `#symbol`.\n */\nexport interface GrRatingProps {\n /** Текущая оценка. Дробная (`3.5`) поддерживается при `allowHalf`. */\n modelValue: number\n /** Количество символов шкалы. */\n max?: number\n size?: GrRatingSize\n /** Тон заливки; точечно перекрывается переменной `--gr-rating-color`. */\n tone?: GrRatingTone\n /** Половинчатые оценки: клик по левой половине символа даёт `.5`. */\n allowHalf?: boolean\n /** Только показ: без ввода и фокуса. */\n readonly?: boolean\n disabled?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Повторный клик по текущей оценке сбрасывает её в `0`. */\n clearable?: boolean\n /** UnoCSS-класс иконки вместо встроенной звезды (например `i-lucide-heart`). */\n icon?: string\n /** Показывать числовую подпись справа от шкалы. */\n showText?: boolean\n /** Формат подписи. По умолчанию — само значение. Сильнее `texts`. */\n formatText?: (value: number) => string\n /**\n * Подписи по делениям: «3 из 5, нормально» вместо «3 из 5». Уходят и в\n * видимый текст, и в `aria-valuetext` — ради этого рейтинг и существует.\n * Массив короче `max` оставляет верхние деления без подписи.\n */\n texts?: string[]\n /**\n * Компактный вид: рисуются только заполненные символы. Осмысленно вместе с\n * `readonly` — в списках и таблицах пять звёзд в каждой строке съедают ширину.\n */\n compact?: boolean\n ariaLabel?: string\n /** Имя для нативной формы: hidden input со значением; `0` — «не выбрано», input не рендерится. */\n name?: string\n}\n\nexport interface GrRatingEmits {\n (e: 'update:modelValue', value: number): void\n /** Оценка зафиксирована (клик / клавиша). */\n (e: 'change', value: number): void\n /** Значение под курсором; `null` — курсор ушёл со шкалы. */\n (e: 'hoverChange', value: number | null): void\n /** Оценка снята повторным кликом; только при `clearable`. */\n (e: 'clear'): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrRatingProps>(),\n {\n max: 5,\n size: undefined,\n tone: 'warning',\n allowHalf: false,\n readonly: false,\n disabled: false,\n invalid: false,\n required: false,\n clearable: false,\n icon: undefined,\n showText: false,\n formatText: undefined,\n texts: undefined,\n compact: false,\n ariaLabel: undefined,\n name: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, {\n component: 'GrRating',\n supported: ['xs', 'sm', 'md', 'lg'],\n})\n\nconst emit = defineEmits<GrRatingEmits>()\ndefineSlots<{\n /** Свой символ вместо звезды. `filled` — закрашенная половина символа. */\n symbol?: (props: { index: number, filled: boolean }) => any\n /** Подпись рядом с оценкой. */\n text?: (props: { value: number }) => any\n}>()\n\n\nconst { t } = useGranularityTranslations()\n\n// Контекст `GrFormField`: id/aria-describedby/invalid/required как fallback.\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid, required: isRequired, readonly: isReadonly } = useGrFormControl(() => props)\nconst describedBy = computed(() => field?.describedById.value)\n\nconst rootEl = ref<HTMLElement | null>(null)\n\nfunction focus(): void {\n rootEl.value?.querySelector<HTMLElement>('[data-gr-rating-scale]')?.focus()\n}\n\nfunction blur(): void {\n rootEl.value?.querySelector<HTMLElement>('[data-gr-rating-scale]')?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n/** Ввод возможен: не readonly и не disabled. */\nconst interactive = computed(() => !isReadonly.value && !isDisabled.value)\n\n/**\n * `aria-readonly`, `aria-invalid` и `aria-required` вешаются только в\n * slider-режиме: на `role=\"img\"` они не разрешены и дают critical в axe.\n *\n * Роль контрола (`slider`) сохраняется и в `disabled` — отключённый слайдер это\n * штатный ARIA-паттерн. А вот `readonly` — это уже не контрол, а картинка с\n * подписью: на `role=\"img\"` атрибуты `aria-value*`/`aria-disabled` запрещены\n * (axe: `aria-allowed-attr`), поэтому там их не выводим вовсе.\n */\nconst asSlider = computed(() => !props.readonly)\nconst step = computed(() => (props.allowHalf ? 0.5 : 1))\n\n// Значение под курсором имеет приоритет над моделью — это «предпросмотр» оценки.\nconst hoverValue = ref<number | null>(null)\nconst displayValue = computed(() => hoverValue.value ?? clamp(props.modelValue))\n\nfunction clamp(value: number): number {\n if (!Number.isFinite(value)) return 0\n return Math.min(props.max, Math.max(0, value))\n}\n\n/** Доля заливки символа с индексом `index` (0..1). */\nfunction fillRatio(index: number): number {\n return Math.min(1, Math.max(0, displayValue.value - index))\n}\n\nconst symbols = computed(() => {\n // Компактный вид показывает только заполненную часть шкалы; половинка\n // считается символом — иначе «2.5» потеряло бы половину звезды.\n const length = props.compact ? Math.ceil(clamp(props.modelValue)) : props.max\n return Array.from({ length }, (_, index) => index)\n})\n\n/** Подпись деления под текущим значением: половинки округляются вверх. */\nconst currentLabel = computed(() => {\n if (!props.texts?.length || displayValue.value <= 0) return undefined\n return props.texts[Math.ceil(displayValue.value) - 1]\n})\n\nconst valueText = computed(() => {\n const params = { value: displayValue.value, max: props.max }\n\n // Порядок слов задаёт локаль, а не конкатенация в коде.\n return currentLabel.value\n ? t('gr.rating.valueTextWithLabel', '{value} of {max}, {label}', { ...params, label: currentLabel.value })\n : t('gr.rating.valueText', '{value} of {max}', params)\n})\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.rating.label', 'Rating'))\n\nconst text = computed(() => {\n if (props.formatText) return props.formatText(displayValue.value)\n return currentLabel.value ?? String(displayValue.value)\n})\n\n/** Значение, соответствующее позиции курсора внутри символа `index`. */\nfunction valueAt(index: number, event: MouseEvent): number {\n if (!props.allowHalf) return index + 1\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n return rect.width > 0 && event.clientX - rect.left < rect.width / 2 ? index + 0.5 : index + 1\n}\n\nfunction onScaleBlur(event: FocusEvent): void {\n resetHover()\n emit('blur', event)\n}\n\nfunction commit(value: number): void {\n const next = clamp(value)\n if (next !== props.modelValue) emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction onSymbolClick(index: number, event: MouseEvent): void {\n if (!interactive.value) return\n const next = valueAt(index, event)\n const cleared = props.clearable && next === props.modelValue\n\n commit(cleared ? 0 : next)\n if (cleared) emit('clear')\n}\n\nfunction onSymbolMouseMove(index: number, event: MouseEvent): void {\n if (!interactive.value) {\n // Режим сменился под курсором — оставлять подсветку от прошлого состояния нельзя.\n resetHover()\n return\n }\n const next = valueAt(index, event)\n if (next === hoverValue.value) return\n hoverValue.value = next\n emit('hoverChange', next)\n}\n\nfunction resetHover(): void {\n if (hoverValue.value === null) return\n hoverValue.value = null\n emit('hoverChange', null)\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (!interactive.value) return\n const current = clamp(props.modelValue)\n let next: number | null = null\n\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowUp':\n next = current + step.value\n break\n case 'ArrowLeft':\n case 'ArrowDown':\n next = current - step.value\n break\n case 'Home':\n next = 0\n break\n case 'End':\n next = props.max\n break\n default:\n return\n }\n\n event.preventDefault()\n commit(next)\n}\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-rating\n class=\"inline-flex items-center gap-2\"\n >\n <!-- Нативная форма: роль-виджет не labelable и в submit не попадает. -->\n <input\n v-if=\"name && modelValue > 0\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(modelValue)\"\n >\n <div\n :id=\"resolvedId\"\n data-gr-rating-scale\n data-testid=\"gr-rating-scale\"\n :class=\"ratingRootClass({ size: resolvedSize, disabled, interactive })\"\n :role=\"asSlider ? 'slider' : 'img'\"\n :tabindex=\"asSlider ? (disabled ? -1 : 0) : undefined\"\n :aria-label=\"asSlider ? resolvedAriaLabel : `${resolvedAriaLabel}: ${valueText}`\"\n :aria-valuemin=\"asSlider ? 0 : undefined\"\n :aria-valuemax=\"asSlider ? max : undefined\"\n :aria-valuenow=\"asSlider ? displayValue : undefined\"\n :aria-valuetext=\"asSlider ? valueText : undefined\"\n :aria-orientation=\"asSlider ? 'horizontal' : undefined\"\n :aria-disabled=\"asSlider && disabled ? 'true' : undefined\"\n :aria-invalid=\"asSlider && isInvalid ? 'true' : undefined\"\n :aria-describedby=\"asSlider ? describedBy : undefined\"\n :aria-required=\"asSlider && isRequired ? 'true' : undefined\"\n :aria-readonly=\"asSlider && isReadonly ? 'true' : undefined\"\n @keydown=\"onKeydown\"\n @mouseleave=\"resetHover\"\n @focus=\"emit('focus', $event)\"\n @blur=\"onScaleBlur\"\n >\n <span\n v-for=\"index in symbols\"\n :key=\"index\"\n data-gr-rating-symbol\n :data-testid=\"`gr-rating-symbol-${index}`\"\n :class=\"ratingSymbolClass(resolvedSize)\"\n @click=\"onSymbolClick(index, $event)\"\n @mousemove=\"onSymbolMouseMove(index, $event)\"\n >\n <!-- Нижний слой — «пустой» символ, поверх него обрезанный по ширине «залитый». -->\n <span class=\"block h-full w-full\" :class=\"ratingVoidClass\" aria-hidden=\"true\">\n <slot name=\"symbol\" :index=\"index\" :filled=\"false\">\n <span v-if=\"icon\" class=\"block h-full w-full\" :class=\"icon\" />\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\" class=\"block h-full w-full\">\n <path d=\"M12 2.5l2.9 6.1 6.6.9-4.8 4.7 1.2 6.6L12 17.7 6.1 20.8l1.2-6.6L2.5 9.5l6.6-.9z\" />\n </svg>\n </slot>\n </span>\n\n <span\n data-gr-rating-fill\n class=\"pointer-events-none absolute inset-y-0 left-0 overflow-hidden\"\n :class=\"ratingFillClassByTone[tone]\"\n :style=\"{ width: `${fillRatio(index) * 100}%` }\"\n aria-hidden=\"true\"\n >\n <span :class=\"ratingSymbolClass(resolvedSize)\">\n <slot name=\"symbol\" :index=\"index\" :filled=\"true\">\n <span v-if=\"icon\" class=\"block h-full w-full\" :class=\"icon\" />\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\" class=\"block h-full w-full\">\n <path d=\"M12 2.5l2.9 6.1 6.6.9-4.8 4.7 1.2 6.6L12 17.7 6.1 20.8l1.2-6.6L2.5 9.5l6.6-.9z\" />\n </svg>\n </slot>\n </span>\n </span>\n </span>\n </div>\n\n <span\n v-if=\"showText || $slots.text\"\n data-gr-rating-text\n class=\"text-[var(--gr-muted-fg)] tabular-nums\"\n :class=\"ratingTextSizeBySize[resolvedSize]\"\n >\n <slot name=\"text\" :value=\"displayValue\">{{ text }}</slot>\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport {\n ratingFillClassByTone,\n ratingRootClass,\n ratingSymbolClass,\n ratingTextSizeBySize,\n ratingVoidClass,\n type GrRatingSize,\n type GrRatingTone,\n} from './grRatingStyles'\n\nexport type {\n GrRatingSize,\n GrRatingTone,\n} from './grRatingStyles'\n\n/**\n * Публичный GR-примитив «Rating» — шкала оценки символами (по умолчанию звёзды).\n *\n * Интерактивный режим реализует WAI-ARIA slider pattern (`role=\"slider\"`,\n * `aria-valuemin/max/now/valuetext`, стрелки / Home / End), режим только для\n * чтения — `role=\"img\"` с текстовой подписью, чтобы скринридер озвучил оценку\n * одной фразой, а не набором элементов.\n *\n * Символ по умолчанию рисуется инлайновым SVG (звезда с `fill=\"currentColor\"`) —\n * иконочные шрифты-маски `i-lucide-star` дают только контур. Свой символ\n * задаётся пропом `icon` (UnoCSS-класс иконки) или слотом `#symbol`.\n */\nexport interface GrRatingProps {\n /** Текущая оценка. Дробная (`3.5`) поддерживается при `allowHalf`. */\n modelValue: number\n /** Количество символов шкалы. */\n max?: number\n size?: GrRatingSize\n /** Тон заливки; точечно перекрывается переменной `--gr-rating-color`. */\n tone?: GrRatingTone\n /** Половинчатые оценки: клик по левой половине символа даёт `.5`. */\n allowHalf?: boolean\n /** Только показ: без ввода и фокуса. */\n readonly?: boolean\n disabled?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Повторный клик по текущей оценке сбрасывает её в `0`. */\n clearable?: boolean\n /** UnoCSS-класс иконки вместо встроенной звезды (например `i-lucide-heart`). */\n icon?: string\n /** Показывать числовую подпись справа от шкалы. */\n showText?: boolean\n /** Формат подписи. По умолчанию — само значение. Сильнее `texts`. */\n formatText?: (value: number) => string\n /**\n * Подписи по делениям: «3 из 5, нормально» вместо «3 из 5». Уходят и в\n * видимый текст, и в `aria-valuetext` — ради этого рейтинг и существует.\n * Массив короче `max` оставляет верхние деления без подписи.\n */\n texts?: string[]\n /**\n * Компактный вид: рисуются только заполненные символы. Осмысленно вместе с\n * `readonly` — в списках и таблицах пять звёзд в каждой строке съедают ширину.\n */\n compact?: boolean\n ariaLabel?: string\n /** Имя для нативной формы: hidden input со значением; `0` — «не выбрано», input не рендерится. */\n name?: string\n}\n\nexport interface GrRatingEmits {\n (e: 'update:modelValue', value: number): void\n /** Оценка зафиксирована (клик / клавиша). */\n (e: 'change', value: number): void\n /** Значение под курсором; `null` — курсор ушёл со шкалы. */\n (e: 'hoverChange', value: number | null): void\n /** Оценка снята повторным кликом; только при `clearable`. */\n (e: 'clear'): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrRatingProps>(),\n {\n max: 5,\n size: undefined,\n tone: 'warning',\n allowHalf: false,\n readonly: false,\n disabled: false,\n invalid: false,\n required: false,\n clearable: false,\n icon: undefined,\n showText: false,\n formatText: undefined,\n texts: undefined,\n compact: false,\n ariaLabel: undefined,\n name: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, {\n component: 'GrRating',\n supported: ['xs', 'sm', 'md', 'lg'],\n})\n\nconst emit = defineEmits<GrRatingEmits>()\ndefineSlots<{\n /** Свой символ вместо звезды. `filled` — закрашенная половина символа. */\n symbol?: (props: { index: number, filled: boolean }) => any\n /** Подпись рядом с оценкой. */\n text?: (props: { value: number }) => any\n}>()\n\n\nconst { t } = useGranularityTranslations()\n\n// Контекст `GrFormField`: id/aria-describedby/invalid/required как fallback.\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid, required: isRequired, readonly: isReadonly } = useGrFormControl(() => props)\nconst describedBy = computed(() => field?.describedById.value)\n\nconst rootEl = ref<HTMLElement | null>(null)\n\nfunction focus(): void {\n rootEl.value?.querySelector<HTMLElement>('[data-gr-rating-scale]')?.focus()\n}\n\nfunction blur(): void {\n rootEl.value?.querySelector<HTMLElement>('[data-gr-rating-scale]')?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n/** Ввод возможен: не readonly и не disabled. */\nconst interactive = computed(() => !isReadonly.value && !isDisabled.value)\n\n/**\n * `aria-readonly`, `aria-invalid` и `aria-required` вешаются только в\n * slider-режиме: на `role=\"img\"` они не разрешены и дают critical в axe.\n *\n * Роль контрола (`slider`) сохраняется и в `disabled` — отключённый слайдер это\n * штатный ARIA-паттерн. А вот `readonly` — это уже не контрол, а картинка с\n * подписью: на `role=\"img\"` атрибуты `aria-value*`/`aria-disabled` запрещены\n * (axe: `aria-allowed-attr`), поэтому там их не выводим вовсе.\n */\nconst asSlider = computed(() => !props.readonly)\nconst step = computed(() => (props.allowHalf ? 0.5 : 1))\n\n// Значение под курсором имеет приоритет над моделью — это «предпросмотр» оценки.\nconst hoverValue = ref<number | null>(null)\nconst displayValue = computed(() => hoverValue.value ?? clamp(props.modelValue))\n\nfunction clamp(value: number): number {\n if (!Number.isFinite(value)) return 0\n return Math.min(props.max, Math.max(0, value))\n}\n\n/** Доля заливки символа с индексом `index` (0..1). */\nfunction fillRatio(index: number): number {\n return Math.min(1, Math.max(0, displayValue.value - index))\n}\n\nconst symbols = computed(() => {\n // Компактный вид показывает только заполненную часть шкалы; половинка\n // считается символом — иначе «2.5» потеряло бы половину звезды.\n const length = props.compact ? Math.ceil(clamp(props.modelValue)) : props.max\n return Array.from({ length }, (_, index) => index)\n})\n\n/** Подпись деления под текущим значением: половинки округляются вверх. */\nconst currentLabel = computed(() => {\n if (!props.texts?.length || displayValue.value <= 0) return undefined\n return props.texts[Math.ceil(displayValue.value) - 1]\n})\n\nconst valueText = computed(() => {\n const params = { value: displayValue.value, max: props.max }\n\n // Порядок слов задаёт локаль, а не конкатенация в коде.\n return currentLabel.value\n ? t('gr.rating.valueTextWithLabel', '{value} of {max}, {label}', { ...params, label: currentLabel.value })\n : t('gr.rating.valueText', '{value} of {max}', params)\n})\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.rating.label', 'Rating'))\n\nconst text = computed(() => {\n if (props.formatText) return props.formatText(displayValue.value)\n return currentLabel.value ?? String(displayValue.value)\n})\n\n/** Значение, соответствующее позиции курсора внутри символа `index`. */\nfunction valueAt(index: number, event: MouseEvent): number {\n if (!props.allowHalf) return index + 1\n const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()\n return rect.width > 0 && event.clientX - rect.left < rect.width / 2 ? index + 0.5 : index + 1\n}\n\nfunction onScaleBlur(event: FocusEvent): void {\n resetHover()\n emit('blur', event)\n}\n\nfunction commit(value: number): void {\n const next = clamp(value)\n if (next !== props.modelValue) emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction onSymbolClick(index: number, event: MouseEvent): void {\n if (!interactive.value) return\n const next = valueAt(index, event)\n const cleared = props.clearable && next === props.modelValue\n\n commit(cleared ? 0 : next)\n if (cleared) emit('clear')\n}\n\nfunction onSymbolMouseMove(index: number, event: MouseEvent): void {\n if (!interactive.value) {\n // Режим сменился под курсором — оставлять подсветку от прошлого состояния нельзя.\n resetHover()\n return\n }\n const next = valueAt(index, event)\n if (next === hoverValue.value) return\n hoverValue.value = next\n emit('hoverChange', next)\n}\n\nfunction resetHover(): void {\n if (hoverValue.value === null) return\n hoverValue.value = null\n emit('hoverChange', null)\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (!interactive.value) return\n const current = clamp(props.modelValue)\n let next: number | null = null\n\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowUp':\n next = current + step.value\n break\n case 'ArrowLeft':\n case 'ArrowDown':\n next = current - step.value\n break\n case 'Home':\n next = 0\n break\n case 'End':\n next = props.max\n break\n default:\n return\n }\n\n event.preventDefault()\n commit(next)\n}\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-rating\n class=\"inline-flex items-center gap-2\"\n >\n <!-- Нативная форма: роль-виджет не labelable и в submit не попадает. -->\n <input\n v-if=\"name && modelValue > 0\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(modelValue)\"\n >\n <div\n :id=\"resolvedId\"\n data-gr-rating-scale\n data-testid=\"gr-rating-scale\"\n :class=\"ratingRootClass({ size: resolvedSize, disabled, interactive })\"\n :role=\"asSlider ? 'slider' : 'img'\"\n :tabindex=\"asSlider ? (disabled ? -1 : 0) : undefined\"\n :aria-label=\"asSlider ? resolvedAriaLabel : `${resolvedAriaLabel}: ${valueText}`\"\n :aria-valuemin=\"asSlider ? 0 : undefined\"\n :aria-valuemax=\"asSlider ? max : undefined\"\n :aria-valuenow=\"asSlider ? displayValue : undefined\"\n :aria-valuetext=\"asSlider ? valueText : undefined\"\n :aria-orientation=\"asSlider ? 'horizontal' : undefined\"\n :aria-disabled=\"asSlider && disabled ? 'true' : undefined\"\n :aria-invalid=\"asSlider && isInvalid ? 'true' : undefined\"\n :aria-describedby=\"asSlider ? describedBy : undefined\"\n :aria-required=\"asSlider && isRequired ? 'true' : undefined\"\n :aria-readonly=\"asSlider && isReadonly ? 'true' : undefined\"\n @keydown=\"onKeydown\"\n @mouseleave=\"resetHover\"\n @focus=\"emit('focus', $event)\"\n @blur=\"onScaleBlur\"\n >\n <span\n v-for=\"index in symbols\"\n :key=\"index\"\n data-gr-rating-symbol\n :data-testid=\"`gr-rating-symbol-${index}`\"\n :class=\"ratingSymbolClass(resolvedSize)\"\n @click=\"onSymbolClick(index, $event)\"\n @mousemove=\"onSymbolMouseMove(index, $event)\"\n >\n <!-- Нижний слой — «пустой» символ, поверх него обрезанный по ширине «залитый». -->\n <span class=\"block h-full w-full\" :class=\"ratingVoidClass\" aria-hidden=\"true\">\n <slot name=\"symbol\" :index=\"index\" :filled=\"false\">\n <span v-if=\"icon\" class=\"block h-full w-full\" :class=\"icon\" />\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\" class=\"block h-full w-full\">\n <path d=\"M12 2.5l2.9 6.1 6.6.9-4.8 4.7 1.2 6.6L12 17.7 6.1 20.8l1.2-6.6L2.5 9.5l6.6-.9z\" />\n </svg>\n </slot>\n </span>\n\n <span\n data-gr-rating-fill\n class=\"pointer-events-none absolute inset-y-0 left-0 overflow-hidden\"\n :class=\"ratingFillClassByTone[tone]\"\n :style=\"{ width: `${fillRatio(index) * 100}%` }\"\n aria-hidden=\"true\"\n >\n <span :class=\"ratingSymbolClass(resolvedSize)\">\n <slot name=\"symbol\" :index=\"index\" :filled=\"true\">\n <span v-if=\"icon\" class=\"block h-full w-full\" :class=\"icon\" />\n <svg v-else viewBox=\"0 0 24 24\" fill=\"currentColor\" class=\"block h-full w-full\">\n <path d=\"M12 2.5l2.9 6.1 6.6.9-4.8 4.7 1.2 6.6L12 17.7 6.1 20.8l1.2-6.6L2.5 9.5l6.6-.9z\" />\n </svg>\n </slot>\n </span>\n </span>\n </span>\n </div>\n\n <span\n v-if=\"showText || $slots.text\"\n data-gr-rating-text\n class=\"text-[var(--gr-muted-fg)] tabular-nums\"\n :class=\"ratingTextSizeBySize[resolvedSize]\"\n >\n <slot name=\"text\" :value=\"displayValue\">{{ text }}</slot>\n </span>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as grRatingSafelist, t as grRatingConfig } from "../../chunks/config-
|
|
2
|
-
import { t as GrRating_default } from "./chunks/GrRating-
|
|
1
|
+
import { n as grRatingSafelist, t as grRatingConfig } from "../../chunks/config-Baj7Wvx-.js";
|
|
2
|
+
import { t as GrRating_default } from "./chunks/GrRating-LarIiwJL.js";
|
|
3
3
|
export { GrRating_default as GrRating, GrRating_default as default, grRatingConfig, grRatingSafelist };
|
package/dist/components/GrSegmented/chunks/{GrSegmented-BQIlH5KI.js → GrSegmented-CQw3ijqa.js}
RENAMED
|
@@ -3,6 +3,7 @@ import { t as loader_circle_default } from "../../../chunks/loader-circle-CfVLz7
|
|
|
3
3
|
import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js";
|
|
4
4
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
5
5
|
import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
|
|
6
|
+
import { useRovingFocus } from "../../../composables/useRovingFocus.js";
|
|
6
7
|
import { a as grSegmentedItemClass, c as grSegmentedItemSpinnerClass, i as grSegmentedIndicatorClass, l as grSegmentedRootClass, o as grSegmentedItemIconClass, s as grSegmentedItemLabelClass, u as grSegmentedRootStyle } from "../../../chunks/config-B-iNaGdw.js";
|
|
7
8
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useId, watch } from "vue";
|
|
8
9
|
//#region src/components/GrSegmented/GrSegmented.vue?vue&type=script&setup=true&lang.ts
|
|
@@ -86,12 +87,6 @@ var GrSegmented_default = /* @__PURE__ */ defineComponent({
|
|
|
86
87
|
enter: (event) => emit("focus", event),
|
|
87
88
|
leave: (event) => emit("blur", event)
|
|
88
89
|
});
|
|
89
|
-
function focus() {
|
|
90
|
-
rootRef.value?.querySelector("[data-gr-segmented-item][tabindex=\"0\"]")?.focus();
|
|
91
|
-
}
|
|
92
|
-
function blur() {
|
|
93
|
-
rootRef.value?.querySelector("[data-gr-segmented-item][tabindex=\"0\"]")?.blur();
|
|
94
|
-
}
|
|
95
90
|
__expose({
|
|
96
91
|
focus,
|
|
97
92
|
blur
|
|
@@ -105,7 +100,6 @@ var GrSegmented_default = /* @__PURE__ */ defineComponent({
|
|
|
105
100
|
let scheduled = false;
|
|
106
101
|
const selectedIndex = computed(() => props.options.findIndex((option) => option.value === props.modelValue));
|
|
107
102
|
const selectedOption = computed(() => props.options[selectedIndex.value] ?? null);
|
|
108
|
-
const enabledOptions = computed(() => props.options.filter((option) => !resolveOptionDisabled(option)));
|
|
109
103
|
const indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)));
|
|
110
104
|
const isVertical = computed(() => props.orientation === "vertical");
|
|
111
105
|
const rootClassName = computed(() => grSegmentedRootClass({
|
|
@@ -175,12 +169,6 @@ var GrSegmented_default = /* @__PURE__ */ defineComponent({
|
|
|
175
169
|
function isIconOnlyOption(option) {
|
|
176
170
|
return Boolean(option.icon) && !option.label;
|
|
177
171
|
}
|
|
178
|
-
function isFocusableOption(option, index) {
|
|
179
|
-
if (resolveOptionDisabled(option)) return false;
|
|
180
|
-
if (isOptionSelected(option)) return true;
|
|
181
|
-
if (selectedIndex.value !== -1) return false;
|
|
182
|
-
return enabledOptions.value[0]?.value === props.options[index]?.value;
|
|
183
|
-
}
|
|
184
172
|
function setItemRef(value, element) {
|
|
185
173
|
const key = getOptionKey(value);
|
|
186
174
|
if (!(element instanceof HTMLElement)) {
|
|
@@ -249,61 +237,55 @@ var GrSegmented_default = /* @__PURE__ */ defineComponent({
|
|
|
249
237
|
emit("update:modelValue", option.value);
|
|
250
238
|
emit("change", option.value, option);
|
|
251
239
|
}
|
|
252
|
-
function
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
240
|
+
function optionOf(value) {
|
|
241
|
+
return props.options.find((option) => option.value === value);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента
|
|
245
|
+
* описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —
|
|
246
|
+
* вертикальный набор листается и стрелками влево/вправо.
|
|
247
|
+
*/
|
|
248
|
+
const roving = useRovingFocus({
|
|
249
|
+
items: () => props.options.map((option) => option.value),
|
|
250
|
+
elementFor: (value) => itemRefs.value.get(getOptionKey(value)),
|
|
251
|
+
isDisabled: (value) => {
|
|
252
|
+
const option = optionOf(value);
|
|
253
|
+
return option ? isOptionBlocked(option) : true;
|
|
254
|
+
},
|
|
255
|
+
orientation: () => "both",
|
|
256
|
+
skipDisabled: () => true,
|
|
257
|
+
/**
|
|
258
|
+
* Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём
|
|
259
|
+
* стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся
|
|
260
|
+
* остановку сохраняет: он не «недоступен», а занят.
|
|
261
|
+
*/
|
|
262
|
+
initialKey: () => {
|
|
263
|
+
const selected = selectedOption.value;
|
|
264
|
+
return selected && !resolveOptionDisabled(selected) ? selected.value : void 0;
|
|
265
|
+
},
|
|
266
|
+
onMove: (value) => {
|
|
267
|
+
const option = optionOf(value);
|
|
268
|
+
if (option) emitValue(option);
|
|
259
269
|
}
|
|
260
|
-
|
|
270
|
+
});
|
|
271
|
+
function onItemClick(option) {
|
|
272
|
+
emitValue(option);
|
|
273
|
+
if (!isOptionBlocked(option)) roving.setActive(option.value);
|
|
274
|
+
}
|
|
275
|
+
/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */
|
|
276
|
+
function rovingElement() {
|
|
277
|
+
const key = roving.rovingKey.value;
|
|
278
|
+
return key === void 0 ? void 0 : itemRefs.value.get(getOptionKey(key));
|
|
279
|
+
}
|
|
280
|
+
function focus() {
|
|
281
|
+
rovingElement()?.focus();
|
|
261
282
|
}
|
|
262
|
-
function
|
|
263
|
-
|
|
264
|
-
if (!option) return;
|
|
265
|
-
itemRefs.value.get(getOptionKey(option.value))?.focus();
|
|
283
|
+
function blur() {
|
|
284
|
+
rovingElement()?.blur();
|
|
266
285
|
}
|
|
267
286
|
function onKeydown(event, index) {
|
|
268
287
|
if (isDisabled.value || isReadonly.value) return;
|
|
269
|
-
if (
|
|
270
|
-
event.preventDefault();
|
|
271
|
-
const nextIndex = getNextEnabledIndex(index, 1);
|
|
272
|
-
if (nextIndex === -1) return;
|
|
273
|
-
const option = props.options[nextIndex];
|
|
274
|
-
if (option) {
|
|
275
|
-
emitValue(option);
|
|
276
|
-
focusIndex(nextIndex);
|
|
277
|
-
}
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
|
|
281
|
-
event.preventDefault();
|
|
282
|
-
const nextIndex = getNextEnabledIndex(index, -1);
|
|
283
|
-
if (nextIndex === -1) return;
|
|
284
|
-
const option = props.options[nextIndex];
|
|
285
|
-
if (option) {
|
|
286
|
-
emitValue(option);
|
|
287
|
-
focusIndex(nextIndex);
|
|
288
|
-
}
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (event.key === "Home") {
|
|
292
|
-
event.preventDefault();
|
|
293
|
-
const firstOption = enabledOptions.value[0];
|
|
294
|
-
if (!firstOption) return;
|
|
295
|
-
emitValue(firstOption);
|
|
296
|
-
focusIndex(props.options.findIndex((option) => option.value === firstOption.value));
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
|
-
if (event.key === "End") {
|
|
300
|
-
event.preventDefault();
|
|
301
|
-
const lastOption = enabledOptions.value.at(-1);
|
|
302
|
-
if (!lastOption) return;
|
|
303
|
-
emitValue(lastOption);
|
|
304
|
-
focusIndex(props.options.findIndex((option) => option.value === lastOption.value));
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
288
|
+
if (roving.handleNavigationKeys(event)) return;
|
|
307
289
|
if (event.key === " " || event.key === "Enter") {
|
|
308
290
|
event.preventDefault();
|
|
309
291
|
const option = props.options[index];
|
|
@@ -370,14 +352,14 @@ var GrSegmented_default = /* @__PURE__ */ defineComponent({
|
|
|
370
352
|
"aria-disabled": resolveOptionDisabled(option) ? "true" : void 0,
|
|
371
353
|
"aria-busy": isOptionBusy(option) ? "true" : void 0,
|
|
372
354
|
disabled: resolveOptionDisabled(option),
|
|
373
|
-
tabindex:
|
|
355
|
+
tabindex: unref(roving).tabindexFor(option.value),
|
|
374
356
|
class: normalizeClass(unref(grSegmentedItemClass)({
|
|
375
357
|
variant: unref(resolvedVariant),
|
|
376
358
|
selected: isOptionSelected(option),
|
|
377
359
|
disabled: resolveOptionDisabled(option),
|
|
378
360
|
iconOnly: isIconOnlyOption(option)
|
|
379
361
|
})),
|
|
380
|
-
onClick: ($event) =>
|
|
362
|
+
onClick: ($event) => onItemClick(option),
|
|
381
363
|
onKeydown: ($event) => onKeydown($event, index)
|
|
382
364
|
}, [renderSlot(_ctx.$slots, "default", {
|
|
383
365
|
option,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrSegmented-CQw3ijqa.js","names":[],"sources":["../../../../src/components/GrSegmented/GrSegmented.vue","../../../../src/components/GrSegmented/GrSegmented.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport type { ComponentPublicInstance } from 'vue'\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport {\n grSegmentedIndicatorClass,\n grSegmentedItemClass,\n grSegmentedItemIconClass,\n grSegmentedItemLabelClass,\n grSegmentedItemSpinnerClass,\n grSegmentedRootClass,\n grSegmentedRootStyle,\n type GrSegmentedOption,\n type GrSegmentedOrientation,\n type GrSegmentedSize,\n type GrSegmentedValue,\n type GrSegmentedVariant,\n} from './grSegmentedStyles'\n\ntype IndicatorGeometry = {\n width: number\n height: number\n x: number\n y: number\n}\n\n/**\n * Пропсы публичного GR-примитива «Segmented».\n */\nexport interface GrSegmentedProps {\n modelValue: GrSegmentedValue\n options: GrSegmentedOption[]\n variant?: GrSegmentedVariant\n size?: GrSegmentedSize\n /**\n * Направление ряда. Вертикаль — боковые фильтры; индикатор к ней готов по\n * построению, он двумерный.\n */\n orientation?: GrSegmentedOrientation\n /** Длительность анимации индикатора в мс. */\n indicatorDuration?: number\n /** Растягивать сегмент на всю ширину контейнера. */\n block?: boolean\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Имя скрытых radio-inputs для интеграции с нативной формой. */\n name?: string\n ariaLabel?: string\n}\n\nexport interface GrSegmentedEmits {\n (e: 'update:modelValue', value: GrSegmentedValue): void\n (e: 'change', value: GrSegmentedValue, option: GrSegmentedOption): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrSegmentedProps>(),\n {\n variant: undefined,\n size: undefined,\n orientation: 'horizontal',\n indicatorDuration: 300,\n block: false,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n name: undefined,\n ariaLabel: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrSegmented' })\nconst resolvedVariant = useGrComponentProp('GrSegmented', 'variant', () => props.variant, 'pills')\n\nconst emit = defineEmits<GrSegmentedEmits>()\ndefineSlots<{\n /** Содержимое сегмента вместо подписи из `options`. */\n default?: (props: {\n option: GrSegmentedOption\n selected: boolean\n disabled: boolean\n loading: boolean\n }) => any\n}>()\n\n\n// `useId()` стабилен между сервером и клиентом, в отличие от `instance.uid`.\nconst fallbackName = `gr-segmented-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\nconst {\n disabled: isDisabled,\n invalid: isInvalid, required: isRequired, readonly: isReadonly } = useGrFormControl(() => props)\n\nconst rootRef = ref<HTMLElement | null>(null)\n\n// Фокус ходит между сегментами: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootRef, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\nconst itemRefs = ref(new Map<string, HTMLElement>())\nconst indicatorGeometry = ref<IndicatorGeometry | null>(null)\nconst indicatorReady = ref(false)\n\nlet resizeObserver: ResizeObserver | null = null\nlet observedRoot: HTMLElement | null = null\nlet observedItem: HTMLElement | null = null\nlet scheduled = false\n\nconst selectedIndex = computed(() => props.options.findIndex(option => option.value === props.modelValue))\nconst selectedOption = computed(() => props.options[selectedIndex.value] ?? null)\nconst indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)))\nconst isVertical = computed(() => props.orientation === 'vertical')\nconst rootClassName = computed(() => grSegmentedRootClass({\n variant: resolvedVariant.value,\n orientation: props.orientation,\n block: props.block,\n disabled: isDisabled.value,\n}))\n\n/**\n * Раскладка задаётся треками, а не классами: число сегментов известно только в\n * рантайме. По вертикали колонка одна — сегменты одинаковой ширины по\n * построению, и `block` решает лишь, занимать ли ширину контейнера.\n */\nconst rootStyle = computed<Record<string, string>>(() => {\n const empty = props.options.length === 0\n const track = () => props.block && !isVertical.value ? 'minmax(0,1fr)' : 'minmax(0,max-content)'\n\n return {\n ...grSegmentedRootStyle({\n variant: resolvedVariant.value,\n size: resolvedSize.value,\n orientation: props.orientation,\n }),\n gridTemplateColumns: isVertical.value\n ? 'minmax(0,1fr)'\n : empty ? 'none' : props.options.map(track).join(' '),\n ...(isVertical.value\n ? { gridTemplateRows: empty ? 'none' : props.options.map(track).join(' ') }\n : {}),\n }\n})\nconst indicatorClassName = computed(() => grSegmentedIndicatorClass(resolvedVariant.value))\nconst resolvedName = computed(() => props.name ?? fallbackName)\nconst hasIndicator = computed(() => selectedIndex.value !== -1 && indicatorGeometry.value !== null)\n\nconst indicatorStyle = computed<Record<string, string>>(() => {\n const geometry = indicatorGeometry.value\n if (!geometry) {\n return {\n opacity: '0',\n width: '0px',\n height: '0px',\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: 'translate3d(0px, 0px, 0px)',\n }\n }\n\n return {\n opacity: indicatorReady.value ? '1' : '0',\n width: `${geometry.width}px`,\n height: `${geometry.height}px`,\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`,\n }\n})\n\nfunction getOptionKey(value: GrSegmentedValue): string {\n return String(value)\n}\n\nfunction resolveOptionDisabled(option: GrSegmentedOption): boolean {\n return isDisabled.value || Boolean(option.disabled)\n}\n\n/**\n * Занятый сегмент не «недоступен», а работает: нативный `disabled` и\n * `aria-disabled` ему не ставим — состояние несёт `aria-busy`. Но выбор он не\n * принимает, поэтому блокировка считается отдельно от `disabled`.\n */\nfunction isOptionBusy(option: GrSegmentedOption): boolean {\n return Boolean(option.loading)\n}\n\nfunction isOptionBlocked(option: GrSegmentedOption): boolean {\n return resolveOptionDisabled(option) || isOptionBusy(option)\n}\n\nfunction isOptionSelected(option: GrSegmentedOption): boolean {\n return option.value === props.modelValue\n}\n\nfunction isIconOnlyOption(option: GrSegmentedOption): boolean {\n return Boolean(option.icon) && !option.label\n}\n\nfunction setItemRef(value: GrSegmentedValue, element: Element | ComponentPublicInstance | null): void {\n const key = getOptionKey(value)\n\n if (!(element instanceof HTMLElement)) {\n itemRefs.value.delete(key)\n return\n }\n\n itemRefs.value.set(key, element)\n}\n\nfunction isSameGeometry(left: IndicatorGeometry | null, right: IndicatorGeometry | null): boolean {\n if (left === right) {\n return true\n }\n\n if (!left || !right) {\n return false\n }\n\n return left.width === right.width\n && left.height === right.height\n && left.x === right.x\n && left.y === right.y\n}\n\nfunction measureIndicator(): void {\n const root = rootRef.value\n const option = selectedOption.value\n if (!root || !option) {\n if (indicatorGeometry.value !== null)\n indicatorGeometry.value = null\n\n if (indicatorReady.value)\n indicatorReady.value = false\n\n return\n }\n\n const selectedItem = itemRefs.value.get(getOptionKey(option.value))\n if (!selectedItem) {\n return\n }\n\n const rootRect = root.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const nextGeometry = {\n width: Math.max(Math.round(itemRect.width), 0),\n height: Math.max(Math.round(itemRect.height), 0),\n x: Math.round(itemRect.left - rootRect.left),\n y: Math.max(Math.round(itemRect.top - rootRect.top) - 1, 0),\n } satisfies IndicatorGeometry\n\n if (!isSameGeometry(indicatorGeometry.value, nextGeometry)) {\n indicatorGeometry.value = nextGeometry\n }\n\n const nextReady = nextGeometry.width > 0 && nextGeometry.height > 0\n if (indicatorReady.value !== nextReady) {\n indicatorReady.value = nextReady\n }\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n const root = rootRef.value\n const option = selectedOption.value\n const selectedItem = option\n ? itemRefs.value.get(getOptionKey(option.value)) ?? null\n : null\n\n if (!resizeObserver) {\n resizeObserver = new ResizeObserver(() => scheduleMeasure())\n }\n\n if (!root) {\n resizeObserver.disconnect()\n observedRoot = null\n observedItem = null\n return\n }\n\n if (observedRoot === root && observedItem === selectedItem) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver.observe(root)\n\n if (selectedItem) {\n resizeObserver.observe(selectedItem)\n }\n\n observedRoot = root\n observedItem = selectedItem\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) {\n return\n }\n\n scheduled = true\n void nextTick(() => {\n scheduled = false\n measureIndicator()\n refreshObserver()\n })\n}\n\nfunction emitValue(option: GrSegmentedOption): void {\n // Один guard на все пути: проверяй `readonly` только клавиатура, и клик по\n // сегменту менял бы значение вопреки заявленному контракту.\n if (isReadonly.value || isOptionBlocked(option) || option.value === props.modelValue) {\n return\n }\n\n emit('update:modelValue', option.value)\n emit('change', option.value, option)\n}\n\nfunction optionOf(value: GrSegmentedValue): GrSegmentedOption | undefined {\n return props.options.find(option => option.value === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента\n * описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —\n * вертикальный набор листается и стрелками влево/вправо.\n */\nconst roving = useRovingFocus<GrSegmentedValue>({\n items: () => props.options.map(option => option.value),\n elementFor: value => itemRefs.value.get(getOptionKey(value)),\n isDisabled: (value) => {\n const option = optionOf(value)\n return option ? isOptionBlocked(option) : true\n },\n orientation: () => 'both',\n skipDisabled: () => true,\n /**\n * Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём\n * стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся\n * остановку сохраняет: он не «недоступен», а занят.\n */\n initialKey: () => {\n const selected = selectedOption.value\n return selected && !resolveOptionDisabled(selected) ? selected.value : undefined\n },\n // Стрелка в `radiogroup` переносит и выбор, а не только фокус.\n onMove: (value) => {\n const option = optionOf(value)\n if (option) emitValue(option)\n },\n})\n\nfunction onItemClick(option: GrSegmentedOption): void {\n emitValue(option)\n // Клик тоже переносит остановку `Tab`: иначе она осталась бы там, куда её\n // увела последняя стрелка.\n if (!isOptionBlocked(option)) roving.setActive(option.value)\n}\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */\nfunction rovingElement(): HTMLElement | undefined {\n const key = roving.rovingKey.value\n return key === undefined ? undefined : itemRefs.value.get(getOptionKey(key))\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number): void {\n if (isDisabled.value || isReadonly.value) {\n return\n }\n\n if (roving.handleNavigationKeys(event)) {\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n const option = props.options[index]\n if (option) {\n emitValue(option)\n }\n }\n}\n\nwatch(() => props.modelValue, () => scheduleMeasure())\nwatch(() => props.options, () => scheduleMeasure(), { deep: true })\nwatch(resolvedVariant, () => scheduleMeasure())\nwatch(resolvedSize, () => scheduleMeasure())\nwatch(() => props.block, () => scheduleMeasure())\n// Смена ориентации переставляет сегменты: без пересчёта индикатор остался бы в\n// координатах прежней раскладки.\nwatch(() => props.orientation, () => scheduleMeasure())\n\nonMounted(() => scheduleMeasure())\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n observedRoot = null\n observedItem = null\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootRef\"\n data-gr-segmented\n :data-variant=\"resolvedVariant\"\n role=\"radiogroup\"\n :aria-orientation=\"orientation\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :class=\"rootClassName\"\n :style=\"rootStyle\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Значение для нативной формы уходит одним скрытым полем рядом с\n сегментами, а не вложенным в каждый `role=\"radio\"`: роль объявляет своих\n потомков презентационными, и вложенный интерактивный контрол ломает\n виджет для скринридеров (axe: `nested-interactive`). Скрытое поле не\n фокусируется и интерактивным не считается. -->\n <input\n v-if=\"selectedOption && !resolveOptionDisabled(selectedOption)\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"String(selectedOption.value)\"\n >\n\n <span\n v-if=\"hasIndicator\"\n data-gr-segmented-indicator\n aria-hidden=\"true\"\n :class=\"indicatorClassName\"\n :style=\"indicatorStyle\"\n />\n\n <button\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :ref=\"element => setItemRef(option.value, element)\"\n data-gr-segmented-item\n :data-value=\"String(option.value)\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"option.ariaLabel\"\n :aria-checked=\"isOptionSelected(option) ? 'true' : 'false'\"\n :aria-disabled=\"resolveOptionDisabled(option) ? 'true' : undefined\"\n :aria-busy=\"isOptionBusy(option) ? 'true' : undefined\"\n :disabled=\"resolveOptionDisabled(option)\"\n :tabindex=\"roving.tabindexFor(option.value)\"\n :class=\"grSegmentedItemClass({\n variant: resolvedVariant,\n selected: isOptionSelected(option),\n disabled: resolveOptionDisabled(option),\n iconOnly: isIconOnlyOption(option),\n })\"\n @click=\"onItemClick(option)\"\n @keydown=\"onKeydown($event, index)\"\n >\n <slot\n :option=\"option\"\n :selected=\"isOptionSelected(option)\"\n :disabled=\"resolveOptionDisabled(option)\"\n :loading=\"isOptionBusy(option)\"\n >\n <!-- Спиннер занимает место иконки: две крутилки рядом читались бы как ошибка. -->\n <IconLoader\n v-if=\"isOptionBusy(option)\"\n data-gr-segmented-spinner\n aria-hidden=\"true\"\n :class=\"grSegmentedItemSpinnerClass\"\n />\n <component\n :is=\"option.icon\"\n v-else-if=\"option.icon\"\n aria-hidden=\"true\"\n :class=\"grSegmentedItemIconClass\"\n />\n <span v-if=\"option.label\" :class=\"grSegmentedItemLabelClass\">\n {{ option.label }}\n </span>\n </slot>\n </button>\n </div>\n</template>","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport type { ComponentPublicInstance } from 'vue'\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport {\n grSegmentedIndicatorClass,\n grSegmentedItemClass,\n grSegmentedItemIconClass,\n grSegmentedItemLabelClass,\n grSegmentedItemSpinnerClass,\n grSegmentedRootClass,\n grSegmentedRootStyle,\n type GrSegmentedOption,\n type GrSegmentedOrientation,\n type GrSegmentedSize,\n type GrSegmentedValue,\n type GrSegmentedVariant,\n} from './grSegmentedStyles'\n\ntype IndicatorGeometry = {\n width: number\n height: number\n x: number\n y: number\n}\n\n/**\n * Пропсы публичного GR-примитива «Segmented».\n */\nexport interface GrSegmentedProps {\n modelValue: GrSegmentedValue\n options: GrSegmentedOption[]\n variant?: GrSegmentedVariant\n size?: GrSegmentedSize\n /**\n * Направление ряда. Вертикаль — боковые фильтры; индикатор к ней готов по\n * построению, он двумерный.\n */\n orientation?: GrSegmentedOrientation\n /** Длительность анимации индикатора в мс. */\n indicatorDuration?: number\n /** Растягивать сегмент на всю ширину контейнера. */\n block?: boolean\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Имя скрытых radio-inputs для интеграции с нативной формой. */\n name?: string\n ariaLabel?: string\n}\n\nexport interface GrSegmentedEmits {\n (e: 'update:modelValue', value: GrSegmentedValue): void\n (e: 'change', value: GrSegmentedValue, option: GrSegmentedOption): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrSegmentedProps>(),\n {\n variant: undefined,\n size: undefined,\n orientation: 'horizontal',\n indicatorDuration: 300,\n block: false,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n name: undefined,\n ariaLabel: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrSegmented' })\nconst resolvedVariant = useGrComponentProp('GrSegmented', 'variant', () => props.variant, 'pills')\n\nconst emit = defineEmits<GrSegmentedEmits>()\ndefineSlots<{\n /** Содержимое сегмента вместо подписи из `options`. */\n default?: (props: {\n option: GrSegmentedOption\n selected: boolean\n disabled: boolean\n loading: boolean\n }) => any\n}>()\n\n\n// `useId()` стабилен между сервером и клиентом, в отличие от `instance.uid`.\nconst fallbackName = `gr-segmented-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\nconst {\n disabled: isDisabled,\n invalid: isInvalid, required: isRequired, readonly: isReadonly } = useGrFormControl(() => props)\n\nconst rootRef = ref<HTMLElement | null>(null)\n\n// Фокус ходит между сегментами: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootRef, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\nconst itemRefs = ref(new Map<string, HTMLElement>())\nconst indicatorGeometry = ref<IndicatorGeometry | null>(null)\nconst indicatorReady = ref(false)\n\nlet resizeObserver: ResizeObserver | null = null\nlet observedRoot: HTMLElement | null = null\nlet observedItem: HTMLElement | null = null\nlet scheduled = false\n\nconst selectedIndex = computed(() => props.options.findIndex(option => option.value === props.modelValue))\nconst selectedOption = computed(() => props.options[selectedIndex.value] ?? null)\nconst indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)))\nconst isVertical = computed(() => props.orientation === 'vertical')\nconst rootClassName = computed(() => grSegmentedRootClass({\n variant: resolvedVariant.value,\n orientation: props.orientation,\n block: props.block,\n disabled: isDisabled.value,\n}))\n\n/**\n * Раскладка задаётся треками, а не классами: число сегментов известно только в\n * рантайме. По вертикали колонка одна — сегменты одинаковой ширины по\n * построению, и `block` решает лишь, занимать ли ширину контейнера.\n */\nconst rootStyle = computed<Record<string, string>>(() => {\n const empty = props.options.length === 0\n const track = () => props.block && !isVertical.value ? 'minmax(0,1fr)' : 'minmax(0,max-content)'\n\n return {\n ...grSegmentedRootStyle({\n variant: resolvedVariant.value,\n size: resolvedSize.value,\n orientation: props.orientation,\n }),\n gridTemplateColumns: isVertical.value\n ? 'minmax(0,1fr)'\n : empty ? 'none' : props.options.map(track).join(' '),\n ...(isVertical.value\n ? { gridTemplateRows: empty ? 'none' : props.options.map(track).join(' ') }\n : {}),\n }\n})\nconst indicatorClassName = computed(() => grSegmentedIndicatorClass(resolvedVariant.value))\nconst resolvedName = computed(() => props.name ?? fallbackName)\nconst hasIndicator = computed(() => selectedIndex.value !== -1 && indicatorGeometry.value !== null)\n\nconst indicatorStyle = computed<Record<string, string>>(() => {\n const geometry = indicatorGeometry.value\n if (!geometry) {\n return {\n opacity: '0',\n width: '0px',\n height: '0px',\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: 'translate3d(0px, 0px, 0px)',\n }\n }\n\n return {\n opacity: indicatorReady.value ? '1' : '0',\n width: `${geometry.width}px`,\n height: `${geometry.height}px`,\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`,\n }\n})\n\nfunction getOptionKey(value: GrSegmentedValue): string {\n return String(value)\n}\n\nfunction resolveOptionDisabled(option: GrSegmentedOption): boolean {\n return isDisabled.value || Boolean(option.disabled)\n}\n\n/**\n * Занятый сегмент не «недоступен», а работает: нативный `disabled` и\n * `aria-disabled` ему не ставим — состояние несёт `aria-busy`. Но выбор он не\n * принимает, поэтому блокировка считается отдельно от `disabled`.\n */\nfunction isOptionBusy(option: GrSegmentedOption): boolean {\n return Boolean(option.loading)\n}\n\nfunction isOptionBlocked(option: GrSegmentedOption): boolean {\n return resolveOptionDisabled(option) || isOptionBusy(option)\n}\n\nfunction isOptionSelected(option: GrSegmentedOption): boolean {\n return option.value === props.modelValue\n}\n\nfunction isIconOnlyOption(option: GrSegmentedOption): boolean {\n return Boolean(option.icon) && !option.label\n}\n\nfunction setItemRef(value: GrSegmentedValue, element: Element | ComponentPublicInstance | null): void {\n const key = getOptionKey(value)\n\n if (!(element instanceof HTMLElement)) {\n itemRefs.value.delete(key)\n return\n }\n\n itemRefs.value.set(key, element)\n}\n\nfunction isSameGeometry(left: IndicatorGeometry | null, right: IndicatorGeometry | null): boolean {\n if (left === right) {\n return true\n }\n\n if (!left || !right) {\n return false\n }\n\n return left.width === right.width\n && left.height === right.height\n && left.x === right.x\n && left.y === right.y\n}\n\nfunction measureIndicator(): void {\n const root = rootRef.value\n const option = selectedOption.value\n if (!root || !option) {\n if (indicatorGeometry.value !== null)\n indicatorGeometry.value = null\n\n if (indicatorReady.value)\n indicatorReady.value = false\n\n return\n }\n\n const selectedItem = itemRefs.value.get(getOptionKey(option.value))\n if (!selectedItem) {\n return\n }\n\n const rootRect = root.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const nextGeometry = {\n width: Math.max(Math.round(itemRect.width), 0),\n height: Math.max(Math.round(itemRect.height), 0),\n x: Math.round(itemRect.left - rootRect.left),\n y: Math.max(Math.round(itemRect.top - rootRect.top) - 1, 0),\n } satisfies IndicatorGeometry\n\n if (!isSameGeometry(indicatorGeometry.value, nextGeometry)) {\n indicatorGeometry.value = nextGeometry\n }\n\n const nextReady = nextGeometry.width > 0 && nextGeometry.height > 0\n if (indicatorReady.value !== nextReady) {\n indicatorReady.value = nextReady\n }\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n const root = rootRef.value\n const option = selectedOption.value\n const selectedItem = option\n ? itemRefs.value.get(getOptionKey(option.value)) ?? null\n : null\n\n if (!resizeObserver) {\n resizeObserver = new ResizeObserver(() => scheduleMeasure())\n }\n\n if (!root) {\n resizeObserver.disconnect()\n observedRoot = null\n observedItem = null\n return\n }\n\n if (observedRoot === root && observedItem === selectedItem) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver.observe(root)\n\n if (selectedItem) {\n resizeObserver.observe(selectedItem)\n }\n\n observedRoot = root\n observedItem = selectedItem\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) {\n return\n }\n\n scheduled = true\n void nextTick(() => {\n scheduled = false\n measureIndicator()\n refreshObserver()\n })\n}\n\nfunction emitValue(option: GrSegmentedOption): void {\n // Один guard на все пути: проверяй `readonly` только клавиатура, и клик по\n // сегменту менял бы значение вопреки заявленному контракту.\n if (isReadonly.value || isOptionBlocked(option) || option.value === props.modelValue) {\n return\n }\n\n emit('update:modelValue', option.value)\n emit('change', option.value, option)\n}\n\nfunction optionOf(value: GrSegmentedValue): GrSegmentedOption | undefined {\n return props.options.find(option => option.value === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента\n * описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —\n * вертикальный набор листается и стрелками влево/вправо.\n */\nconst roving = useRovingFocus<GrSegmentedValue>({\n items: () => props.options.map(option => option.value),\n elementFor: value => itemRefs.value.get(getOptionKey(value)),\n isDisabled: (value) => {\n const option = optionOf(value)\n return option ? isOptionBlocked(option) : true\n },\n orientation: () => 'both',\n skipDisabled: () => true,\n /**\n * Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём\n * стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся\n * остановку сохраняет: он не «недоступен», а занят.\n */\n initialKey: () => {\n const selected = selectedOption.value\n return selected && !resolveOptionDisabled(selected) ? selected.value : undefined\n },\n // Стрелка в `radiogroup` переносит и выбор, а не только фокус.\n onMove: (value) => {\n const option = optionOf(value)\n if (option) emitValue(option)\n },\n})\n\nfunction onItemClick(option: GrSegmentedOption): void {\n emitValue(option)\n // Клик тоже переносит остановку `Tab`: иначе она осталась бы там, куда её\n // увела последняя стрелка.\n if (!isOptionBlocked(option)) roving.setActive(option.value)\n}\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */\nfunction rovingElement(): HTMLElement | undefined {\n const key = roving.rovingKey.value\n return key === undefined ? undefined : itemRefs.value.get(getOptionKey(key))\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number): void {\n if (isDisabled.value || isReadonly.value) {\n return\n }\n\n if (roving.handleNavigationKeys(event)) {\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n const option = props.options[index]\n if (option) {\n emitValue(option)\n }\n }\n}\n\nwatch(() => props.modelValue, () => scheduleMeasure())\nwatch(() => props.options, () => scheduleMeasure(), { deep: true })\nwatch(resolvedVariant, () => scheduleMeasure())\nwatch(resolvedSize, () => scheduleMeasure())\nwatch(() => props.block, () => scheduleMeasure())\n// Смена ориентации переставляет сегменты: без пересчёта индикатор остался бы в\n// координатах прежней раскладки.\nwatch(() => props.orientation, () => scheduleMeasure())\n\nonMounted(() => scheduleMeasure())\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n observedRoot = null\n observedItem = null\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootRef\"\n data-gr-segmented\n :data-variant=\"resolvedVariant\"\n role=\"radiogroup\"\n :aria-orientation=\"orientation\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :class=\"rootClassName\"\n :style=\"rootStyle\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Значение для нативной формы уходит одним скрытым полем рядом с\n сегментами, а не вложенным в каждый `role=\"radio\"`: роль объявляет своих\n потомков презентационными, и вложенный интерактивный контрол ломает\n виджет для скринридеров (axe: `nested-interactive`). Скрытое поле не\n фокусируется и интерактивным не считается. -->\n <input\n v-if=\"selectedOption && !resolveOptionDisabled(selectedOption)\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"String(selectedOption.value)\"\n >\n\n <span\n v-if=\"hasIndicator\"\n data-gr-segmented-indicator\n aria-hidden=\"true\"\n :class=\"indicatorClassName\"\n :style=\"indicatorStyle\"\n />\n\n <button\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :ref=\"element => setItemRef(option.value, element)\"\n data-gr-segmented-item\n :data-value=\"String(option.value)\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"option.ariaLabel\"\n :aria-checked=\"isOptionSelected(option) ? 'true' : 'false'\"\n :aria-disabled=\"resolveOptionDisabled(option) ? 'true' : undefined\"\n :aria-busy=\"isOptionBusy(option) ? 'true' : undefined\"\n :disabled=\"resolveOptionDisabled(option)\"\n :tabindex=\"roving.tabindexFor(option.value)\"\n :class=\"grSegmentedItemClass({\n variant: resolvedVariant,\n selected: isOptionSelected(option),\n disabled: resolveOptionDisabled(option),\n iconOnly: isIconOnlyOption(option),\n })\"\n @click=\"onItemClick(option)\"\n @keydown=\"onKeydown($event, index)\"\n >\n <slot\n :option=\"option\"\n :selected=\"isOptionSelected(option)\"\n :disabled=\"resolveOptionDisabled(option)\"\n :loading=\"isOptionBusy(option)\"\n >\n <!-- Спиннер занимает место иконки: две крутилки рядом читались бы как ошибка. -->\n <IconLoader\n v-if=\"isOptionBusy(option)\"\n data-gr-segmented-spinner\n aria-hidden=\"true\"\n :class=\"grSegmentedItemSpinnerClass\"\n />\n <component\n :is=\"option.icon\"\n v-else-if=\"option.icon\"\n aria-hidden=\"true\"\n :class=\"grSegmentedItemIconClass\"\n />\n <span v-if=\"option.label\" :class=\"grSegmentedItemLabelClass\">\n {{ option.label }}\n </span>\n </slot>\n </button>\n </div>\n</template>"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as grSegmentedSafelist, r as GR_SEGMENTED_ORIENTATIONS, t as grSegmentedConfig } from "../../chunks/config-B-iNaGdw.js";
|
|
2
|
-
import { t as GrSegmented_default } from "./chunks/GrSegmented-
|
|
2
|
+
import { t as GrSegmented_default } from "./chunks/GrSegmented-CQw3ijqa.js";
|
|
3
3
|
export { GR_SEGMENTED_ORIENTATIONS, GrSegmented_default as GrSegmented, GrSegmented_default as default, grSegmentedConfig, grSegmentedSafelist };
|
|
@@ -2,7 +2,7 @@ import { a as useGrComponentProp, c as useGrThemeAttrs, o as useGrComponentSize
|
|
|
2
2
|
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
|
|
3
3
|
import { t as usePortalTarget } from "../../../chunks/usePortalTarget-RyzEgNTb.js";
|
|
4
4
|
import { vClickOutside } from "../../../directives/clickOutside.js";
|
|
5
|
-
import {
|
|
5
|
+
import { r as isComposingEvent } from "../../../chunks/keyboard-DE2yhz_b.js";
|
|
6
6
|
import { useFloating } from "../../../composables/useFloating.js";
|
|
7
7
|
import { useDismissible } from "../../../composables/useDismissible.js";
|
|
8
8
|
import { useVirtualList } from "../../../composables/useVirtualList.js";
|
|
@@ -10,11 +10,12 @@ import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js"
|
|
|
10
10
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
11
11
|
import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
|
|
12
12
|
import { t as useControlledOpen } from "../../../chunks/useControlledOpen-DV3SqLTP.js";
|
|
13
|
-
import {
|
|
13
|
+
import { useComboboxNavigation } from "../../../composables/useComboboxNavigation.js";
|
|
14
|
+
import { a as resolveSelectedOptions, i as normalizeOptionQuery, n as matchesOptionQuery } from "../../../chunks/optionFilter-DYw9XPPx.js";
|
|
14
15
|
import { t as useControlAddons } from "../../../chunks/useControlAddons-asUr10Pf.js";
|
|
15
16
|
import { t as GrBadge_default } from "../../GrBadge/chunks/GrBadge-B1tgqfGQ.js";
|
|
16
17
|
import { t as _plugin_vue_export_helper_default } from "../../../chunks/_plugin-vue_export-helper-BOaGB7Aw.js";
|
|
17
|
-
import { t as GrInput_default } from "../../GrInput/chunks/GrInput-
|
|
18
|
+
import { t as GrInput_default } from "../../GrInput/chunks/GrInput-2wd7Crs0.js";
|
|
18
19
|
import { c as grSelectNativeClass, d as grSelectTriggerClass, i as grSelectLinkNativeLabelClass, l as grSelectOptionClass, n as defaultBaseClass, p as linkBaseClass, s as grSelectLinkNativeOverlayClass, u as grSelectPanelClasses } from "../../../chunks/grSelectStyles-eTz4uPMP.js";
|
|
19
20
|
import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, renderSlot, toDisplayString, unref, useId, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
|
|
20
21
|
import '../styles.css';//#region src/components/GrSelect/composables/useSelectPanelItems.ts
|