@feugene/granularity 0.35.0 → 0.37.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-2ZHRsdOc.js.map +1 -1
- package/dist/chunks/config-2vrOFn2f.js.map +1 -1
- package/dist/chunks/config-3bQeQvqd.js.map +1 -1
- package/dist/chunks/config-87fszqnD.js.map +1 -1
- package/dist/chunks/config-8Pcutu1j.js.map +1 -1
- package/dist/chunks/config-A-bBiotF.js.map +1 -1
- package/dist/chunks/config-B0uvcTPH.js.map +1 -1
- package/dist/chunks/config-B3J0alyY.js.map +1 -1
- package/dist/chunks/config-B5SBUa6u.js.map +1 -1
- package/dist/chunks/config-B7W9VlZ7.js.map +1 -1
- package/dist/chunks/config-BDSaD-5p.js.map +1 -1
- package/dist/chunks/config-BEO7brpO.js.map +1 -1
- package/dist/chunks/config-BNu8lFQB.js.map +1 -1
- package/dist/chunks/config-BRESvs9g.js.map +1 -1
- package/dist/chunks/config-BTmfQFwi.js.map +1 -1
- package/dist/chunks/{config-CuQmUkMw2.js → config-BUNxHnEz.js} +1 -1
- package/dist/chunks/config-BUNxHnEz.js.map +1 -0
- package/dist/chunks/config-BaWANzzB.js.map +1 -1
- package/dist/chunks/config-BcXX7S7B.js.map +1 -1
- package/dist/chunks/config-Bd7QfiGj.js.map +1 -1
- package/dist/chunks/config-BhfNgyWL.js.map +1 -1
- package/dist/chunks/config-Bjn30smH.js.map +1 -1
- package/dist/chunks/config-BlJa1Mj9.js.map +1 -1
- package/dist/chunks/config-BoUI0t-t.js.map +1 -1
- package/dist/chunks/config-BqT6PMzO.js.map +1 -1
- package/dist/chunks/config-BscVxZR3.js.map +1 -1
- package/dist/chunks/config-BuGlNPE9.js.map +1 -1
- package/dist/chunks/config-C0Ea9ePP.js.map +1 -1
- package/dist/chunks/config-C0Eu8jpG.js.map +1 -1
- package/dist/chunks/config-CDat1wXf.js.map +1 -1
- package/dist/chunks/config-CIkdsWUk.js.map +1 -1
- package/dist/chunks/config-CJzmDHfI.js.map +1 -1
- package/dist/chunks/config-CLjjjPZj.js.map +1 -1
- package/dist/chunks/config-CMNfZO7S.js.map +1 -1
- package/dist/chunks/config-CQLNjc9X.js.map +1 -0
- package/dist/chunks/config-CT4lP6S4.js.map +1 -1
- package/dist/chunks/config-CWtfxkM9.js.map +1 -1
- package/dist/chunks/config-CYthTVK2.js.map +1 -1
- package/dist/chunks/config-CZPDPJlg.js.map +1 -1
- package/dist/chunks/config-CbEbLyDE.js.map +1 -1
- package/dist/chunks/config-ChPg-BQv.js.map +1 -1
- package/dist/chunks/config-CjKpUcmy.js.map +1 -1
- package/dist/chunks/config-CjWOTgLL.js.map +1 -1
- package/dist/chunks/config-CjXjhphs.js.map +1 -1
- package/dist/chunks/config-CnYdE3HZ.js.map +1 -0
- package/dist/chunks/config-CsCUuukB.js.map +1 -1
- package/dist/chunks/config-CvbVM4ep.js.map +1 -1
- package/dist/chunks/config-D0NzGYaE.js.map +1 -1
- package/dist/chunks/config-D0W8mGFD.js.map +1 -1
- package/dist/chunks/config-D82r782v.js.map +1 -1
- package/dist/chunks/{config-mlheIMtV.js → config-DBi0GVce.js} +2 -2
- package/dist/chunks/config-DBi0GVce.js.map +1 -0
- package/dist/chunks/config-DBmdgoVf.js.map +1 -0
- package/dist/chunks/config-DCq4JySZ.js.map +1 -1
- package/dist/chunks/config-DGC00bTp.js.map +1 -1
- package/dist/chunks/config-DIDz_E5m.js.map +1 -1
- package/dist/chunks/config-DM0lsduD.js.map +1 -1
- package/dist/chunks/config-DNDgp9bB.js.map +1 -1
- package/dist/chunks/config-DOYz_SVK.js.map +1 -1
- package/dist/chunks/config-DRbojEzO.js.map +1 -1
- package/dist/chunks/config-DUNH02Fg.js.map +1 -1
- package/dist/chunks/config-DUbbGcfw.js.map +1 -1
- package/dist/chunks/config-DVCNvhIG.js.map +1 -0
- package/dist/chunks/config-DWL81-aM.js.map +1 -1
- package/dist/chunks/config-DZCUPHPU.js.map +1 -1
- package/dist/chunks/config-DeyT9dJl.js.map +1 -1
- package/dist/chunks/config-DolULhjJ.js.map +1 -1
- package/dist/chunks/config-DpAYidyY.js.map +1 -0
- package/dist/chunks/config-Droqn55j.js.map +1 -1
- package/dist/chunks/config-DwABJHEo.js.map +1 -1
- package/dist/chunks/config-E1cTyRVV.js.map +1 -1
- package/dist/chunks/config-MmPym-Z7.js.map +1 -0
- package/dist/chunks/config-QaIc_gRa.js.map +1 -1
- package/dist/chunks/config-Yy67uWHY.js.map +1 -1
- package/dist/chunks/config-Z5LeUXys.js.map +1 -1
- package/dist/chunks/config-_jbgsFpw.js.map +1 -1
- package/dist/chunks/config-eXB87DOi.js.map +1 -1
- package/dist/chunks/config-rLkc9Zn2.js.map +1 -1
- package/dist/chunks/{context-CTbuwcYs.js → context-CPMRfwVr.js} +1 -1
- package/dist/chunks/{context-CTbuwcYs.js.map → context-CPMRfwVr.js.map} +1 -1
- package/dist/chunks/{grModalStyles-EZfuEiw_.js → grModalStyles-BEkiFal_.js} +10 -1
- package/dist/chunks/grModalStyles-BEkiFal_.js.map +1 -0
- package/dist/chunks/{grRadioStyles-DGL2QLy6.js → grRadioStyles-BwRyCjQQ.js} +4 -2
- package/dist/chunks/{grRadioStyles-DGL2QLy6.js.map → grRadioStyles-BwRyCjQQ.js.map} +1 -1
- package/dist/chunks/{granular-provider-DCn6fgEs.js → granular-provider-DP2gk0oa.js} +10 -9
- package/dist/chunks/{granular-provider-DCn6fgEs.js.map → granular-provider-DP2gk0oa.js.map} +1 -1
- package/dist/chunks/{overlayStack-0CZS99Da.js → overlayStack-B_UFaFzk.js} +65 -24
- package/dist/chunks/overlayStack-B_UFaFzk.js.map +1 -0
- package/dist/chunks/{renamedProp-BwcN-SJg.js → renamedProp-Dy96tT-F.js} +1 -1
- package/dist/chunks/{renamedProp-BwcN-SJg.js.map → renamedProp-Dy96tT-F.js.map} +1 -1
- package/dist/chunks/{useModalOverlay-BnAGZpcI.js → useModalOverlay-BwX8WEcI.js} +3 -3
- package/dist/chunks/{useModalOverlay-BnAGZpcI.js.map → useModalOverlay-BwX8WEcI.js.map} +1 -1
- package/dist/chunks/{usePortalTarget-C0p-mhaM.js → usePortalTarget-BhrRgdqW.js} +1 -1
- package/dist/chunks/{usePortalTarget-C0p-mhaM.js.map → usePortalTarget-BhrRgdqW.js.map} +1 -1
- package/dist/chunks/{validation-5HhpanPP.js → validation-BDjqsuGB.js} +1 -1
- package/dist/chunks/{validation-5HhpanPP.js.map → validation-BDjqsuGB.js.map} +1 -1
- package/dist/components/GrAlert/chunks/{GrAlert-FAVf-ksH.js → GrAlert-D72y1IEh.js} +1 -1
- package/dist/components/GrAlert/chunks/{GrAlert-FAVf-ksH.js.map → GrAlert-D72y1IEh.js.map} +1 -1
- package/dist/components/GrAlert/index.js +1 -1
- package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-BQsSE7sj.js → GrAutocomplete-BpmFmpKs.js} +4 -6
- package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-BQsSE7sj.js.map → GrAutocomplete-BpmFmpKs.js.map} +1 -1
- package/dist/components/GrAutocomplete/index.js +1 -1
- package/dist/components/GrAvatar/chunks/{GrAvatar-CNmLmgcr.js → GrAvatar-dWEXiCJG.js} +1 -1
- package/dist/components/GrAvatar/chunks/{GrAvatar-CNmLmgcr.js.map → GrAvatar-dWEXiCJG.js.map} +1 -1
- package/dist/components/GrAvatar/index.js +1 -1
- package/dist/components/GrBadge/chunks/{GrBadge-DpUDXKbq.js → GrBadge-DBeQXEir.js} +2 -2
- package/dist/components/GrBadge/chunks/{GrBadge-DpUDXKbq.js.map → GrBadge-DBeQXEir.js.map} +1 -1
- package/dist/components/GrBadge/index.js +1 -1
- package/dist/components/GrBadgeWrap/chunks/{GrBadgeWrap-B-A3PRkE.js → GrBadgeWrap-wdfxaXiu.js} +3 -1
- package/dist/components/GrBadgeWrap/chunks/{GrBadgeWrap-B-A3PRkE.js.map → GrBadgeWrap-wdfxaXiu.js.map} +1 -1
- package/dist/components/GrBadgeWrap/index.js +1 -1
- package/dist/components/GrBottomNav/chunks/{GrBottomNav-wtFatLjB.js → GrBottomNav-nE08pVUJ.js} +1 -1
- package/dist/components/GrBottomNav/chunks/{GrBottomNav-wtFatLjB.js.map → GrBottomNav-nE08pVUJ.js.map} +1 -1
- package/dist/components/GrBottomNav/index.js +1 -1
- package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-DRDNan_n.js → GrBreadcrumbs-DOpwY2EF.js} +3 -3
- package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-DRDNan_n.js.map → GrBreadcrumbs-DOpwY2EF.js.map} +1 -1
- package/dist/components/GrBreadcrumbs/index.js +1 -1
- package/dist/components/GrButton/chunks/{GrButton-7GP0zObj.js → GrButton-CS4TqMtG.js} +1 -1
- package/dist/components/GrButton/chunks/{GrButton-7GP0zObj.js.map → GrButton-CS4TqMtG.js.map} +1 -1
- package/dist/components/GrButton/index.js +1 -1
- package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -1
- package/dist/components/GrButtonGroup/index.js +1 -1
- package/dist/components/GrCard/chunks/{GrCard-BttXz1pQ.js → GrCard-Ck5--lMF.js} +2 -2
- package/dist/components/GrCard/chunks/{GrCard-BttXz1pQ.js.map → GrCard-Ck5--lMF.js.map} +1 -1
- package/dist/components/GrCard/index.js +1 -1
- package/dist/components/GrCheckbox/chunks/{GrCheckbox-CEcHIsXM.js → GrCheckbox-Dp201frb.js} +1 -1
- package/dist/components/GrCheckbox/chunks/{GrCheckbox-CEcHIsXM.js.map → GrCheckbox-Dp201frb.js.map} +1 -1
- package/dist/components/GrCheckbox/index.js +1 -1
- package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-BOwrVcFr.js → GrCheckboxGroup-IpqG5qwm.js} +2 -2
- package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-BOwrVcFr.js.map → GrCheckboxGroup-IpqG5qwm.js.map} +1 -1
- package/dist/components/GrCheckboxGroup/index.js +1 -1
- package/dist/components/GrChip/chunks/{GrChip-BTivtwff.js → GrChip-CKqyzYcv.js} +10 -7
- package/dist/components/GrChip/chunks/{GrChip-BTivtwff.js.map → GrChip-CKqyzYcv.js.map} +1 -1
- package/dist/components/GrChip/index.js +1 -1
- package/dist/components/GrChipGroup/chunks/{GrChipGroup-C78Vcwos.js → GrChipGroup-dDGwnC04.js} +1 -1
- package/dist/components/GrChipGroup/chunks/{GrChipGroup-C78Vcwos.js.map → GrChipGroup-dDGwnC04.js.map} +1 -1
- package/dist/components/GrChipGroup/index.js +1 -1
- package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dp0eEBTZ.js → GrCodeBlock-BUOwKwQE.js} +2 -2
- package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dp0eEBTZ.js.map → GrCodeBlock-BUOwKwQE.js.map} +1 -1
- package/dist/components/GrCodeBlock/index.js +1 -1
- package/dist/components/GrCollapse/chunks/{GrCollapse-BlW6ybdL.js → GrCollapse-DWH3QAnU.js} +6 -5
- package/dist/components/GrCollapse/chunks/{GrCollapse-BlW6ybdL.js.map → GrCollapse-DWH3QAnU.js.map} +1 -1
- package/dist/components/GrCollapse/index.js +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-CIgdPXHn.js → GrColorPicker-BNtpj_P6.js} +4 -4
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-CIgdPXHn.js.map → GrColorPicker-BNtpj_P6.js.map} +1 -1
- package/dist/components/GrColorPicker/index.js +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BZHUKlux.js → GrCommandPalette-BVZEd4yy.js} +7 -7
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BZHUKlux.js.map → GrCommandPalette-BVZEd4yy.js.map} +1 -1
- package/dist/components/GrCommandPalette/index.js +1 -1
- package/dist/components/GrConfigProvider/chunks/{GrConfigProvider-BF7R3hgg.js → GrConfigProvider-t9x2UToH.js} +13 -12
- package/dist/components/GrConfigProvider/chunks/{GrConfigProvider-BF7R3hgg.js.map → GrConfigProvider-t9x2UToH.js.map} +1 -1
- package/dist/components/GrConfigProvider/index.js +2 -2
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-jRDs_E6C.js → GrConfirmDialog-K5ht2cYq.js} +4 -4
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-jRDs_E6C.js.map → GrConfirmDialog-K5ht2cYq.js.map} +1 -1
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-DlFWm0eW.js → GrContextMenu-Dd2tgMoL.js} +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-DlFWm0eW.js.map → GrContextMenu-Dd2tgMoL.js.map} +1 -1
- package/dist/components/GrContextMenu/index.js +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-4JAgOQ-7.js → GrDataTable-BYYG_XZA.js} +5 -5
- package/dist/components/GrDataTable/chunks/{GrDataTable-4JAgOQ-7.js.map → GrDataTable-BYYG_XZA.js.map} +1 -1
- package/dist/components/GrDataTable/index.js +1 -1
- package/dist/components/GrDelta/chunks/{GrDelta-BZwkgQW-.js → GrDelta-BpfqebEV.js} +0 -0
- package/dist/components/GrDelta/chunks/{GrDelta-BZwkgQW-.js.map → GrDelta-BpfqebEV.js.map} +1 -1
- package/dist/components/GrDelta/index.js +1 -1
- package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-BMeCgFV3.js → GrDescriptionList-D8ANFpn_.js} +2 -2
- package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-BMeCgFV3.js.map → GrDescriptionList-D8ANFpn_.js.map} +1 -1
- package/dist/components/GrDescriptionList/index.js +2 -2
- package/dist/components/GrDialog/chunks/{GrDialog-C01Hhk6G.js → GrDialog-CeJubnKJ.js} +3 -3
- package/dist/components/GrDialog/chunks/{GrDialog-C01Hhk6G.js.map → GrDialog-CeJubnKJ.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-CmsJNUmM.js → GrDialogService-BArvw1DV.js} +9 -8
- package/dist/components/GrDialogService/chunks/{GrDialogService-CmsJNUmM.js.map → GrDialogService-BArvw1DV.js.map} +1 -1
- package/dist/components/GrDialogService/index.js +1 -1
- package/dist/components/GrDivider/chunks/{GrDivider-BXavGcMX.js → GrDivider-DxA-zV25.js} +1 -1
- package/dist/components/GrDivider/chunks/{GrDivider-BXavGcMX.js.map → GrDivider-DxA-zV25.js.map} +1 -1
- package/dist/components/GrDivider/index.js +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-xfoy-MCj.js → GrDrawer-BBHNgeH0.js} +5 -5
- package/dist/components/GrDrawer/chunks/{GrDrawer-xfoy-MCj.js.map → GrDrawer-BBHNgeH0.js.map} +1 -1
- package/dist/components/GrDrawer/index.js +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-7r772-Cq.js → GrDropdown-CUlviqMi.js} +6 -8
- package/dist/components/GrDropdown/chunks/{GrDropdown-7r772-Cq.js.map → GrDropdown-CUlviqMi.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-DNurbsWc.js → GrDropdownMenu-COOR1LCs.js} +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-DNurbsWc.js.map → GrDropdownMenu-COOR1LCs.js.map} +1 -1
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js.map +1 -1
- package/dist/components/GrDropdownMenu/index.js +1 -1
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-RqsWvgI9.js → GrEmptyState-BbvwE-E0.js} +2 -2
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-RqsWvgI9.js.map → GrEmptyState-BbvwE-E0.js.map} +1 -1
- package/dist/components/GrEmptyState/index.js +1 -1
- package/dist/components/GrFilePreview/chunks/{GrFilePreview-C9Z7hMK8.js → GrFilePreview-PabkLgYX.js} +1 -1
- package/dist/components/GrFilePreview/chunks/{GrFilePreview-C9Z7hMK8.js.map → GrFilePreview-PabkLgYX.js.map} +1 -1
- package/dist/components/GrFilePreview/index.js +1 -1
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-LL8RZvC0.js → GrFileUpload-BwMR71zN.js} +4 -4
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-LL8RZvC0.js.map → GrFileUpload-BwMR71zN.js.map} +1 -1
- package/dist/components/GrFileUpload/index.js +1 -1
- package/dist/components/GrForm/chunks/{GrForm-CrnfCsgj.js → GrForm-xTtavR-K.js} +1 -1
- package/dist/components/GrForm/chunks/{GrForm-CrnfCsgj.js.map → GrForm-xTtavR-K.js.map} +1 -1
- package/dist/components/GrForm/index.js +2 -2
- package/dist/components/GrFormField/chunks/{GrFormField-DSylU7IU.js → GrFormField-DO61vxpS.js} +2 -2
- package/dist/components/GrFormField/chunks/{GrFormField-DSylU7IU.js.map → GrFormField-DO61vxpS.js.map} +1 -1
- package/dist/components/GrFormField/index.js +1 -1
- package/dist/components/GrFormFile/chunks/{GrFormFile-B1jGZyIj.js → GrFormFile-Dlxx-9zi.js} +3 -3
- package/dist/components/GrFormFile/chunks/{GrFormFile-B1jGZyIj.js.map → GrFormFile-Dlxx-9zi.js.map} +1 -1
- package/dist/components/GrFormFile/index.js +1 -1
- package/dist/components/GrFormSection/chunks/{GrFormSection-ejieOg9H.js → GrFormSection-DV1S6R_N.js} +1 -1
- package/dist/components/GrFormSection/chunks/{GrFormSection-ejieOg9H.js.map → GrFormSection-DV1S6R_N.js.map} +1 -1
- package/dist/components/GrFormSection/index.js +1 -1
- package/dist/components/GrIcon/chunks/{GrIcon-Dmf0c9ba.js → GrIcon-DTZIgmje.js} +1 -1
- package/dist/components/GrIcon/chunks/{GrIcon-Dmf0c9ba.js.map → GrIcon-DTZIgmje.js.map} +1 -1
- package/dist/components/GrIcon/index.js +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer--BU8yrfx.js → GrImageViewer-BjYw-uTF.js} +2 -4
- package/dist/components/GrImageViewer/chunks/{GrImageViewer--BU8yrfx.js.map → GrImageViewer-BjYw-uTF.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInput/chunks/{GrInput-BLywRZUN.js → GrInput-TFeBm3gQ.js} +2 -1
- package/dist/components/GrInput/chunks/{GrInput-BLywRZUN.js.map → GrInput-TFeBm3gQ.js.map} +1 -1
- package/dist/components/GrInput/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-ByD9NugQ.js → GrInputTag-DhfUNOA5.js} +3 -3
- package/dist/components/GrInputTag/chunks/{GrInputTag-ByD9NugQ.js.map → GrInputTag-DhfUNOA5.js.map} +1 -1
- package/dist/components/GrInputTag/index.js +1 -1
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BCZ7lE2k.js → GrJsonViewer-CdtmUpZ3.js} +6 -6
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BCZ7lE2k.js.map → GrJsonViewer-CdtmUpZ3.js.map} +1 -1
- package/dist/components/GrJsonViewer/index.js +2 -2
- package/dist/components/GrKbd/chunks/{GrKbd-D2ga1H9i.js → GrKbd-D_a1mPLe.js} +1 -1
- package/dist/components/GrKbd/chunks/{GrKbd-D2ga1H9i.js.map → GrKbd-D_a1mPLe.js.map} +1 -1
- package/dist/components/GrKbd/index.js +1 -1
- package/dist/components/GrLink/chunks/{GrLink-DYXw3W9w.js → GrLink-DwWErumU.js} +2 -2
- package/dist/components/GrLink/chunks/{GrLink-DYXw3W9w.js.map → GrLink-DwWErumU.js.map} +1 -1
- package/dist/components/GrLink/index.js +2 -2
- package/dist/components/GrList/chunks/{GrList-B_CRJB4c.js → GrList-Unya-LXb.js} +3 -3
- package/dist/components/GrList/chunks/{GrList-B_CRJB4c.js.map → GrList-Unya-LXb.js.map} +1 -1
- package/dist/components/GrList/index.js +1 -1
- package/dist/components/GrLoading/chunks/{GrLoading-CMD3Ri9P.js → GrLoading-BDrlrup_.js} +1 -1
- package/dist/components/GrLoading/chunks/{GrLoading-CMD3Ri9P.js.map → GrLoading-BDrlrup_.js.map} +1 -1
- package/dist/components/GrLoading/index.js +1 -1
- package/dist/components/GrModal/chunks/{GrModal-_JrDhon-.js → GrModal-xIWaJozo.js} +7 -6
- package/dist/components/GrModal/chunks/GrModal-xIWaJozo.js.map +1 -0
- package/dist/components/GrModal/index.js +2 -2
- package/dist/components/GrNavbar/chunks/{GrNavbar-Dr8e5kW-.js → GrNavbar-BRGuksiy.js} +3 -3
- package/dist/components/GrNavbar/chunks/{GrNavbar-Dr8e5kW-.js.map → GrNavbar-BRGuksiy.js.map} +1 -1
- package/dist/components/GrNavbar/index.js +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-DQ59YICu.js → GrNumberInput-BqPydXpK.js} +7 -9
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-DQ59YICu.js.map → GrNumberInput-BqPydXpK.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-gBoWVHk6.js → GrPagination-DhbNZHEF.js} +26 -11
- package/dist/components/GrPagination/chunks/GrPagination-DhbNZHEF.js.map +1 -0
- package/dist/components/GrPagination/index.js +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-DEFxDffj.js → GrPopover-BakLcWkX.js} +3 -3
- package/dist/components/GrPopover/chunks/{GrPopover-DEFxDffj.js.map → GrPopover-BakLcWkX.js.map} +1 -1
- package/dist/components/GrPopover/index.js +2 -2
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-hszUOC8f.js → GrProgressBar-C3NRBqIP.js} +6 -3
- package/dist/components/GrProgressBar/chunks/GrProgressBar-C3NRBqIP.js.map +1 -0
- package/dist/components/GrProgressBar/index.js +1 -1
- package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-D3yWXYDa.js → GrProgressCircle-CdvbINQc.js} +2 -2
- package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-D3yWXYDa.js.map → GrProgressCircle-CdvbINQc.js.map} +1 -1
- package/dist/components/GrProgressCircle/index.js +1 -1
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-CailXSqW.js → GrPromptDialog-C9Y1ifE_.js} +8 -8
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-CailXSqW.js.map → GrPromptDialog-C9Y1ifE_.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +1 -1
- package/dist/components/GrRadio/chunks/{GrRadio-Aq3v8XgG.js → GrRadio-B1776V9D.js} +2 -2
- package/dist/components/GrRadio/chunks/{GrRadio-Aq3v8XgG.js.map → GrRadio-B1776V9D.js.map} +1 -1
- package/dist/components/GrRadio/index.js +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-y9LVdTWh.js → GrRadioGroup-UgitrBFl.js} +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-y9LVdTWh.js.map → GrRadioGroup-UgitrBFl.js.map} +1 -1
- package/dist/components/GrRadioGroup/index.js +1 -1
- package/dist/components/GrRating/chunks/{GrRating-IEiTOdnF.js → GrRating-DTriyyqG.js} +1 -1
- package/dist/components/GrRating/chunks/{GrRating-IEiTOdnF.js.map → GrRating-DTriyyqG.js.map} +1 -1
- package/dist/components/GrRating/index.js +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DMeOWlzj.js → GrResponseErrorBanner-NEEJZ8zi.js} +2 -2
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DMeOWlzj.js.map → GrResponseErrorBanner-NEEJZ8zi.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CBVRpgIG.js → GrResponseErrorBanner-ZvBvEQDZ.js} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CBVRpgIG.js.map → GrResponseErrorBanner-ZvBvEQDZ.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/index.js +2 -2
- package/dist/components/GrSegmented/chunks/{GrSegmented-CB-VR-yL.js → GrSegmented-NKTi9bMG.js} +1 -1
- package/dist/components/GrSegmented/chunks/{GrSegmented-CB-VR-yL.js.map → GrSegmented-NKTi9bMG.js.map} +1 -1
- package/dist/components/GrSegmented/index.js +1 -1
- package/dist/components/GrSelect/chunks/{GrSelect-CZqV1Eg4.js → GrSelect-Do1iAyp1.js} +8 -12
- package/dist/components/GrSelect/chunks/GrSelect-Do1iAyp1.js.map +1 -0
- package/dist/components/GrSelect/index.js +1 -1
- package/dist/components/GrSelect/styles.css +1 -1
- package/dist/components/GrSidebar/chunks/{GrSidebar-alkwBUzL.js → GrSidebar-DoKLlHSw.js} +2 -2
- package/dist/components/GrSidebar/chunks/{GrSidebar-alkwBUzL.js.map → GrSidebar-DoKLlHSw.js.map} +1 -1
- package/dist/components/GrSidebar/index.js +1 -1
- package/dist/components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js.map +1 -1
- package/dist/components/GrSlider/chunks/{GrSlider-DTTrZTHK.js → GrSlider-Db-jACXz.js} +14 -6
- package/dist/components/GrSlider/chunks/GrSlider-Db-jACXz.js.map +1 -0
- package/dist/components/GrSlider/index.js +1 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-HyKX--rO.js → GrSortableList-CQCaWivn.js} +1 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-HyKX--rO.js.map → GrSortableList-CQCaWivn.js.map} +1 -1
- package/dist/components/GrSortableList/index.js +1 -1
- package/dist/components/GrSplitter/chunks/{GrSplitter-MltjaADn.js → GrSplitter-C-XQzq7q.js} +1 -1
- package/dist/components/GrSplitter/chunks/{GrSplitter-MltjaADn.js.map → GrSplitter-C-XQzq7q.js.map} +1 -1
- package/dist/components/GrSplitter/index.js +1 -1
- package/dist/components/GrStatistic/chunks/{GrStatistic-qHVasK37.js → GrStatistic-C1_nY4Gc.js} +8 -4
- package/dist/components/GrStatistic/chunks/GrStatistic-C1_nY4Gc.js.map +1 -0
- package/dist/components/GrStatistic/index.js +1 -1
- package/dist/components/GrSteps/chunks/{GrSteps-C2jxpZoN.js → GrSteps-DXj7m-WO.js} +2 -2
- package/dist/components/GrSteps/chunks/{GrSteps-C2jxpZoN.js.map → GrSteps-DXj7m-WO.js.map} +1 -1
- package/dist/components/GrSteps/index.js +1 -1
- package/dist/components/GrSwitch/chunks/{GrSwitch-7Oe5QfQZ.js → GrSwitch-CriHWT2A.js} +1 -1
- package/dist/components/GrSwitch/chunks/{GrSwitch-7Oe5QfQZ.js.map → GrSwitch-CriHWT2A.js.map} +1 -1
- package/dist/components/GrSwitch/index.js +1 -1
- package/dist/components/GrTabPanels/chunks/{GrTabPanels-BZQS8-JM.js → GrTabPanels-5zsbqS1v.js} +1 -1
- package/dist/components/GrTabPanels/chunks/{GrTabPanels-BZQS8-JM.js.map → GrTabPanels-5zsbqS1v.js.map} +1 -1
- package/dist/components/GrTabPanels/index.js +1 -1
- package/dist/components/GrTable/chunks/{GrTable-jhUTczjv.js → GrTable-iwzHvlMC.js} +1 -1
- package/dist/components/GrTable/chunks/{GrTable-jhUTczjv.js.map → GrTable-iwzHvlMC.js.map} +1 -1
- package/dist/components/GrTable/index.js +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-CT2nk_HV.js → GrTabs-DHfv67cp.js} +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-CT2nk_HV.js.map → GrTabs-DHfv67cp.js.map} +1 -1
- package/dist/components/GrTabs/index.js +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-DinXG12-.js → GrTextarea-BII3w61K.js} +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-DinXG12-.js.map → GrTextarea-BII3w61K.js.map} +1 -1
- package/dist/components/GrTextarea/index.js +1 -1
- package/dist/components/GrTimeline/chunks/{GrTimeline-BiHpArsg.js → GrTimeline-Bs60huw0.js} +2 -2
- package/dist/components/GrTimeline/chunks/{GrTimeline-BiHpArsg.js.map → GrTimeline-Bs60huw0.js.map} +1 -1
- package/dist/components/GrTimeline/index.js +1 -1
- package/dist/components/GrToaster/chunks/{GrToaster-COXIBKzq.js → GrToaster-D-sV-9of.js} +4 -4
- package/dist/components/GrToaster/chunks/{GrToaster-COXIBKzq.js.map → GrToaster-D-sV-9of.js.map} +1 -1
- package/dist/components/GrToaster/index.js +1 -1
- package/dist/components/GrTooltip/chunks/{GrTooltip-uYETdbCD.js → GrTooltip-BUiTbROv.js} +3 -3
- package/dist/components/GrTooltip/chunks/{GrTooltip-uYETdbCD.js.map → GrTooltip-BUiTbROv.js.map} +1 -1
- package/dist/components/GrTooltip/index.js +1 -1
- package/dist/components/GrTree/chunks/{GrTree-Ci6CZfKR.js → GrTree-CkELQwR8.js} +1 -2
- package/dist/components/GrTree/chunks/{GrTree-Ci6CZfKR.js.map → GrTree-CkELQwR8.js.map} +1 -1
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DOXcpWq2.js → GrTreeSelect-DurwZ7Cz.js} +4 -4
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DOXcpWq2.js.map → GrTreeSelect-DurwZ7Cz.js.map} +1 -1
- package/dist/components/GrTreeSelect/index.js +1 -1
- package/dist/components/GrValue/chunks/GrValue-ezkQM05Q.js.map +1 -1
- package/dist/composables/useFloating.js +1 -1
- package/dist/composables/useGrComponentConfig.js +1 -1
- package/dist/composables/useOverlayLayer.js +1 -1
- package/dist/composables/usePortalTarget.js +1 -1
- package/dist/composables/useTheme.js +1 -1
- package/dist/composables/useTheme.js.map +1 -1
- package/dist/composables/useToast.js +1 -1
- package/dist/composables/useToast.js.map +1 -1
- package/dist/composables/useVirtualList.js +3 -5
- package/dist/composables/useVirtualList.js.map +1 -1
- package/dist/directives/loading.js +1 -1
- package/dist/granular-provider-node.js +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/index.js +87 -87
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
- package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
- package/dist/types/components/GrModal/GrModal.vue.d.ts +1 -1
- package/dist/types/components/GrModal/grModalStyles.d.ts +9 -0
- package/dist/types/components/GrProgressBar/GrProgressBar.vue.d.ts +1 -1
- package/dist/types/internal/devHook.d.ts +53 -0
- package/dist/vue/index.js +2 -2
- package/dist/vue/index.js.map +1 -1
- package/dist/web-types.json +2 -2
- package/package.json +17 -17
- package/dist/chunks/config-CQLNjc9X2.js.map +0 -1
- package/dist/chunks/config-CnYdE3HZ2.js.map +0 -1
- package/dist/chunks/config-CuQmUkMw2.js.map +0 -1
- package/dist/chunks/config-DBmdgoVf2.js.map +0 -1
- package/dist/chunks/config-DVCNvhIG2.js.map +0 -1
- package/dist/chunks/config-DpAYidyY2.js.map +0 -1
- package/dist/chunks/config-MmPym-Z72.js.map +0 -1
- package/dist/chunks/config-mlheIMtV.js.map +0 -1
- package/dist/chunks/grModalStyles-EZfuEiw_.js.map +0 -1
- package/dist/chunks/overlayStack-0CZS99Da.js.map +0 -1
- package/dist/components/GrModal/chunks/GrModal-_JrDhon-.js.map +0 -1
- package/dist/components/GrPagination/chunks/GrPagination-gBoWVHk6.js.map +0 -1
- package/dist/components/GrProgressBar/chunks/GrProgressBar-hszUOC8f.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-CZqV1Eg4.js.map +0 -1
- package/dist/components/GrSlider/chunks/GrSlider-DTTrZTHK.js.map +0 -1
- package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +0 -1
- /package/dist/chunks/{config-CQLNjc9X2.js → config-CQLNjc9X.js} +0 -0
- /package/dist/chunks/{config-CnYdE3HZ2.js → config-CnYdE3HZ.js} +0 -0
- /package/dist/chunks/{config-DBmdgoVf2.js → config-DBmdgoVf.js} +0 -0
- /package/dist/chunks/{config-DVCNvhIG2.js → config-DVCNvhIG.js} +0 -0
- /package/dist/chunks/{config-DpAYidyY2.js → config-DpAYidyY.js} +0 -0
- /package/dist/chunks/{config-MmPym-Z72.js → config-MmPym-Z7.js} +0 -0
package/dist/components/GrCheckbox/chunks/{GrCheckbox-CEcHIsXM.js.map → GrCheckbox-Dp201frb.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrCheckbox-CEcHIsXM.js","names":[],"sources":["../../../../src/components/GrCheckbox/grCheckboxGroupContext.ts","../../../../src/components/GrCheckbox/GrCheckbox.vue","../../../../src/components/GrCheckbox/GrCheckbox.vue"],"sourcesContent":["import type { ComputedRef, InjectionKey } from 'vue'\n\nimport type { GrCheckboxSize } from './grCheckboxStyles'\n\nexport type GrCheckboxGroupContext = {\n /** Выбранные значения группы. Чекбокс сравнивает с ними свой `value`. */\n modelValue: ComputedRef<string[]>\n name: ComputedRef<string | undefined>\n disabled: ComputedRef<boolean>\n readonly: ComputedRef<boolean>\n invalid: ComputedRef<boolean>\n /**\n * Обязательность группы объявляют её чекбоксы: `role=\"group\"` не поддерживает\n * `aria-required` (axe: `aria-allowed-attr`), а `role=\"checkbox\"` — да.\n */\n required: ComputedRef<boolean>\n size: ComputedRef<GrCheckboxSize>\n /** Добавляет или убирает значение из выбранных. */\n toggle: (value: string, checked: boolean) => void\n}\n\nexport const GR_CHECKBOX_GROUP_CONTEXT: InjectionKey<GrCheckboxGroupContext> = Symbol('GR_CHECKBOX_GROUP_CONTEXT')\n","<script setup lang=\"ts\">\n/**\n * GrCheckbox — GR-примитив чекбокса с нативным скрытым `<input type=\"checkbox\">`\n * для интеграции с HTML-формами (`FormData`, `form`).\n *\n * Источник истины — нативный input: клик по нему (в т.ч. по внешнему\n * `<label for=\"...\">`) слушается через `@change` и эмитит модель. Клик по видимой\n * части компонента переключает через корневой обработчик.\n *\n * Клавиатура: `Space` переключает значение (Enter — намеренно нет, это нестандартно\n * для чекбоксов). Фокус — на самом контроле (квадратике), как у нативного чекбокса.\n *\n * A11y: `role=\"checkbox\"` + `aria-checked` (`true`/`false`/`mixed`) + `aria-disabled`.\n * Роль висит **только на контроле**, а не на всей строке с подписью — по двум причинам:\n * - роль объявляет своих потомков презентационными, поэтому ни нативный input, ни\n * интерактивная подпись (ссылка на политику, кнопка «показать изменения») не могут\n * жить внутри: скринридер теряет их, axe падает на `nested-interactive`;\n * - имя виджета берётся из подписи через `aria-labelledby`, что и позволяет держать\n * её снаружи вместе со всем её интерактивным содержимым.\n *\n * `required` объявляется только через `aria-required`, на скрытый input он не уходит.\n * Нативная проверка потребовала бы фокуса на невалидном контроле, а он невидим и\n * `aria-hidden` — Chrome в таком случае молча отменяет сабмит всей формы\n * («An invalid form control … is not focusable»). Обязательность проверяет\n * `GrForm` правилом `required` — см. `docs/components/GrCheckbox.md`.\n *\n * Внутри `GrCheckboxGroup` значение приходит из группы: свой `modelValue` не\n * задаётся, а `value` сравнивается с массивом выбранных.\n */\nimport { computed, inject, onMounted, ref, useId, useSlots, watch } from 'vue'\nimport IconCheck from '~icons/lucide/check'\nimport IconMinus from '~icons/lucide/minus'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport { GR_CHECKBOX_GROUP_CONTEXT } from './grCheckboxGroupContext'\nimport {\n grCheckboxCheckIconClass,\n grCheckboxControlClass,\n grCheckboxIndeterminateIconClass,\n grCheckboxLabelClass,\n grCheckboxRootClass,\n type GrCheckboxLabelPosition,\n type GrCheckboxSize,\n} from './grCheckboxStyles'\n\nexport type { GrCheckboxLabelPosition, GrCheckboxSize } from './grCheckboxStyles'\n\nexport interface GrCheckboxProps {\n /** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */\n modelValue?: boolean\n disabled?: boolean\n name?: string\n value?: string\n /** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */\n required?: boolean\n /** Только для чтения: состояние видно, но не переключается. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n form?: string\n /** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for=\"...\">`. */\n id?: string\n /** Промежуточное («смешанное») состояние: `aria-checked=\"mixed\"`, индикатор — тире. */\n indeterminate?: boolean\n /** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */\n ariaLabel?: string\n /** Сторона подписи относительно контрола. */\n labelPosition?: GrCheckboxLabelPosition\n /** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */\n size?: GrCheckboxSize\n}\n\nexport interface GrCheckboxEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'change', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst hiddenInputStyle = {\n position: 'absolute',\n opacity: '0',\n width: '0',\n height: '0',\n pointerEvents: 'none',\n} as const\n\nconst props = withDefaults(defineProps<GrCheckboxProps>(), {\n modelValue: undefined,\n disabled: undefined,\n name: undefined,\n value: 'on',\n required: false,\n readonly: false,\n invalid: false,\n form: undefined,\n id: undefined,\n indeterminate: false,\n ariaLabel: undefined,\n labelPosition: 'end',\n size: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxEmits>()\ndefineSlots<{\n /** Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. */\n default?: () => any\n}>()\n\nconst slots = useSlots()\n\nconst labelId = useId()\nconst hasLabel = computed(() => Boolean(slots.default))\n\nconst group = inject(GR_CHECKBOX_GROUP_CONTEXT, null)\n\nconst checked = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n if (group)\n return group.modelValue.value.includes(props.value)\n\n return false\n})\n\nconst resolvedName = computed(() => props.name ?? group?.name.value)\n\n// Контекст `GrFormField`. Id поля вешается на `span[role=\"checkbox\"]` — именно он\n// виджет и держит фокус; на скрытом `aria-hidden`-инпуте он был бы бесполезен\n// (клик по подписи уводил бы фокус в невидимый элемент). Роль-виджет не является\n// labelable-элементом, поэтому имя от подписи поля приходит через `aria-labelledby`.\nconst {\n disabled: isDisabled,\n id: fieldControlId,\n labelId: fieldLabelId,\n describedBy,\n invalid: fieldInvalid,\n required: fieldRequired,\n readonly: fieldReadonly,\n} = useGrFormControl(() => props)\n\n// «Или», а не `??`: `isDisabled` уже сведён к булеву (свой проп + контекст\n// поля и формы), и `??` до группы просто не дошёл бы.\nconst resolvedDisabled = computed(() => isDisabled.value || Boolean(group?.disabled.value))\n\n// `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` — объявлять\n// обязательность и режим чтения группы обязаны сами чекбоксы.\nconst isRequired = computed(() => fieldRequired.value || Boolean(group?.required.value))\n\nconst isReadonly = computed(() => fieldReadonly.value || Boolean(group?.readonly.value))\n\n// Ошибка группы красит чекбоксы, но не объявляется на каждом из них: `aria-invalid`\n// уже висит на самой группе, и дублировать его на всех пунктах — значит заставить\n// диктор повторить «неверное значение» столько раз, сколько в группе чекбоксов.\nconst isInvalid = computed(() => fieldInvalid.value)\nconst showsInvalid = computed(() => isInvalid.value || Boolean(group?.invalid.value))\n\nconst labelledBy = computed(() => {\n if (props.ariaLabel)\n return undefined\n if (hasLabel.value)\n return labelId\n return fieldLabelId.value\n})\n\n// Эффективный размер: локальный проп → группа → `GrConfigProvider` → `md`.\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrCheckbox' },\n)\n\nconst rootClassName = computed(() => grCheckboxRootClass({\n size: resolvedSize.value,\n disabled: resolvedDisabled.value,\n labelPosition: props.labelPosition,\n}))\n\nconst controlClassName = computed(() => grCheckboxControlClass({\n size: resolvedSize.value,\n active: checked.value || props.indeterminate,\n disabled: resolvedDisabled.value,\n invalid: showsInvalid.value,\n}))\n\nconst indeterminateIconClassName = computed(() => grCheckboxIndeterminateIconClass(resolvedSize.value))\n\nconst checkIconClassName = computed(() => grCheckboxCheckIconClass({\n size: resolvedSize.value,\n checked: checked.value,\n}))\n\nconst labelClassName = computed(() => grCheckboxLabelClass(resolvedSize.value))\n\n// Держим `.checked` на нативном input синхронно с состоянием — `:checked`-биндинг\n// на скрытом элементе иногда отстаёт при программных обновлениях.\nconst nativeInput = ref<HTMLInputElement | null>(null)\nconst control = ref<HTMLElement | null>(null)\nwatch(\n checked,\n (value) => {\n if (nativeInput.value && nativeInput.value.checked !== value)\n nativeInput.value.checked = value\n },\n)\n\n// `indeterminate` можно выставить только через JS-свойство (не атрибут).\nfunction syncIndeterminate(): void {\n if (nativeInput.value)\n nativeInput.value.indeterminate = props.indeterminate\n}\nwatch(() => props.indeterminate, syncIndeterminate)\nonMounted(syncIndeterminate)\n\nfunction setChecked(next: boolean): void {\n if (resolvedDisabled.value || isReadonly.value) {\n // Нативный input мог уже переключиться от клика по внешнему `<label for>` —\n // возвращаем его к состоянию модели, иначе форма отправит непринятое значение.\n if (nativeInput.value)\n nativeInput.value.checked = checked.value\n return\n }\n\n if (props.modelValue !== undefined || !group) {\n emit('update:modelValue', next)\n emit('change', next)\n return\n }\n\n group.toggle(props.value, next)\n emit('change', next)\n}\n\nfunction toggle(): void {\n // Из промежуточного состояния переключаемся во «включено» (стандартное поведение).\n setChecked(props.indeterminate ? true : !checked.value)\n}\n\n// Клик по нативному input (в т.ч. по внешнему `<label for=\"...\">`) уже переключил его\n// `.checked` — берём значение как источник истины и эмитим модель.\nfunction onNativeChange(e: Event): void {\n setChecked((e.target as HTMLInputElement).checked)\n}\n\n// `<label for>` уводит фокус на скрытый input — визуально фокус пропадает. Возвращаем\n// его на контрол, который этот фокус и показывает.\nfunction onNativeFocus(): void {\n control.value?.focus()\n}\n\nfunction focus(): void {\n control.value?.focus()\n}\n\nfunction blur(): void {\n control.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n// Подпись держится снаружи роли-виджета именно для того, чтобы могла содержать\n// ссылки и кнопки, — поэтому клик по её интерактивному содержимому чекбокс не\n// переключает. Вложенный `<label>` считается интерактивным: он адресует\n// собственный контрол, и переключение чекбокса «заодно» было бы сюрпризом.\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el)\n return false\n return !!el.closest('a,button,input,select,textarea,label,[role=\"button\"],[role=\"link\"]')\n}\n\nfunction onClick(e: MouseEvent): void {\n if (isInteractiveTarget(e.target))\n return\n toggle()\n}\n</script>\n\n<template>\n <div\n data-gr-checkbox\n :class=\"rootClassName\"\n @click=\"onClick\"\n >\n <input\n :id=\"id\"\n ref=\"nativeInput\"\n type=\"checkbox\"\n :checked=\"checked\"\n :disabled=\"resolvedDisabled\"\n :name=\"resolvedName\"\n :value=\"value\"\n :form=\"form\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :style=\"hiddenInputStyle\"\n @change=\"onNativeChange\"\n @focus=\"onNativeFocus\"\n >\n <span\n :id=\"fieldControlId\"\n ref=\"control\"\n data-gr-checkbox-indicator\n role=\"checkbox\"\n :aria-checked=\"indeterminate ? 'mixed' : (checked ? 'true' : 'false')\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :tabindex=\"resolvedDisabled ? -1 : 0\"\n :class=\"controlClassName\"\n @keydown.space.prevent=\"toggle\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <IconMinus\n v-if=\"indeterminate\"\n :class=\"indeterminateIconClassName\"\n />\n <IconCheck\n v-else\n :class=\"checkIconClassName\"\n />\n </span>\n <span\n v-if=\"hasLabel\"\n :id=\"labelId\"\n :class=\"labelClassName\"\n >\n <slot />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckbox — GR-примитив чекбокса с нативным скрытым `<input type=\"checkbox\">`\n * для интеграции с HTML-формами (`FormData`, `form`).\n *\n * Источник истины — нативный input: клик по нему (в т.ч. по внешнему\n * `<label for=\"...\">`) слушается через `@change` и эмитит модель. Клик по видимой\n * части компонента переключает через корневой обработчик.\n *\n * Клавиатура: `Space` переключает значение (Enter — намеренно нет, это нестандартно\n * для чекбоксов). Фокус — на самом контроле (квадратике), как у нативного чекбокса.\n *\n * A11y: `role=\"checkbox\"` + `aria-checked` (`true`/`false`/`mixed`) + `aria-disabled`.\n * Роль висит **только на контроле**, а не на всей строке с подписью — по двум причинам:\n * - роль объявляет своих потомков презентационными, поэтому ни нативный input, ни\n * интерактивная подпись (ссылка на политику, кнопка «показать изменения») не могут\n * жить внутри: скринридер теряет их, axe падает на `nested-interactive`;\n * - имя виджета берётся из подписи через `aria-labelledby`, что и позволяет держать\n * её снаружи вместе со всем её интерактивным содержимым.\n *\n * `required` объявляется только через `aria-required`, на скрытый input он не уходит.\n * Нативная проверка потребовала бы фокуса на невалидном контроле, а он невидим и\n * `aria-hidden` — Chrome в таком случае молча отменяет сабмит всей формы\n * («An invalid form control … is not focusable»). Обязательность проверяет\n * `GrForm` правилом `required` — см. `docs/components/GrCheckbox.md`.\n *\n * Внутри `GrCheckboxGroup` значение приходит из группы: свой `modelValue` не\n * задаётся, а `value` сравнивается с массивом выбранных.\n */\nimport { computed, inject, onMounted, ref, useId, useSlots, watch } from 'vue'\nimport IconCheck from '~icons/lucide/check'\nimport IconMinus from '~icons/lucide/minus'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport { GR_CHECKBOX_GROUP_CONTEXT } from './grCheckboxGroupContext'\nimport {\n grCheckboxCheckIconClass,\n grCheckboxControlClass,\n grCheckboxIndeterminateIconClass,\n grCheckboxLabelClass,\n grCheckboxRootClass,\n type GrCheckboxLabelPosition,\n type GrCheckboxSize,\n} from './grCheckboxStyles'\n\nexport type { GrCheckboxLabelPosition, GrCheckboxSize } from './grCheckboxStyles'\n\nexport interface GrCheckboxProps {\n /** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */\n modelValue?: boolean\n disabled?: boolean\n name?: string\n value?: string\n /** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */\n required?: boolean\n /** Только для чтения: состояние видно, но не переключается. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n form?: string\n /** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for=\"...\">`. */\n id?: string\n /** Промежуточное («смешанное») состояние: `aria-checked=\"mixed\"`, индикатор — тире. */\n indeterminate?: boolean\n /** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */\n ariaLabel?: string\n /** Сторона подписи относительно контрола. */\n labelPosition?: GrCheckboxLabelPosition\n /** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */\n size?: GrCheckboxSize\n}\n\nexport interface GrCheckboxEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'change', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst hiddenInputStyle = {\n position: 'absolute',\n opacity: '0',\n width: '0',\n height: '0',\n pointerEvents: 'none',\n} as const\n\nconst props = withDefaults(defineProps<GrCheckboxProps>(), {\n modelValue: undefined,\n disabled: undefined,\n name: undefined,\n value: 'on',\n required: false,\n readonly: false,\n invalid: false,\n form: undefined,\n id: undefined,\n indeterminate: false,\n ariaLabel: undefined,\n labelPosition: 'end',\n size: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxEmits>()\ndefineSlots<{\n /** Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. */\n default?: () => any\n}>()\n\nconst slots = useSlots()\n\nconst labelId = useId()\nconst hasLabel = computed(() => Boolean(slots.default))\n\nconst group = inject(GR_CHECKBOX_GROUP_CONTEXT, null)\n\nconst checked = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n if (group)\n return group.modelValue.value.includes(props.value)\n\n return false\n})\n\nconst resolvedName = computed(() => props.name ?? group?.name.value)\n\n// Контекст `GrFormField`. Id поля вешается на `span[role=\"checkbox\"]` — именно он\n// виджет и держит фокус; на скрытом `aria-hidden`-инпуте он был бы бесполезен\n// (клик по подписи уводил бы фокус в невидимый элемент). Роль-виджет не является\n// labelable-элементом, поэтому имя от подписи поля приходит через `aria-labelledby`.\nconst {\n disabled: isDisabled,\n id: fieldControlId,\n labelId: fieldLabelId,\n describedBy,\n invalid: fieldInvalid,\n required: fieldRequired,\n readonly: fieldReadonly,\n} = useGrFormControl(() => props)\n\n// «Или», а не `??`: `isDisabled` уже сведён к булеву (свой проп + контекст\n// поля и формы), и `??` до группы просто не дошёл бы.\nconst resolvedDisabled = computed(() => isDisabled.value || Boolean(group?.disabled.value))\n\n// `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` — объявлять\n// обязательность и режим чтения группы обязаны сами чекбоксы.\nconst isRequired = computed(() => fieldRequired.value || Boolean(group?.required.value))\n\nconst isReadonly = computed(() => fieldReadonly.value || Boolean(group?.readonly.value))\n\n// Ошибка группы красит чекбоксы, но не объявляется на каждом из них: `aria-invalid`\n// уже висит на самой группе, и дублировать его на всех пунктах — значит заставить\n// диктор повторить «неверное значение» столько раз, сколько в группе чекбоксов.\nconst isInvalid = computed(() => fieldInvalid.value)\nconst showsInvalid = computed(() => isInvalid.value || Boolean(group?.invalid.value))\n\nconst labelledBy = computed(() => {\n if (props.ariaLabel)\n return undefined\n if (hasLabel.value)\n return labelId\n return fieldLabelId.value\n})\n\n// Эффективный размер: локальный проп → группа → `GrConfigProvider` → `md`.\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrCheckbox' },\n)\n\nconst rootClassName = computed(() => grCheckboxRootClass({\n size: resolvedSize.value,\n disabled: resolvedDisabled.value,\n labelPosition: props.labelPosition,\n}))\n\nconst controlClassName = computed(() => grCheckboxControlClass({\n size: resolvedSize.value,\n active: checked.value || props.indeterminate,\n disabled: resolvedDisabled.value,\n invalid: showsInvalid.value,\n}))\n\nconst indeterminateIconClassName = computed(() => grCheckboxIndeterminateIconClass(resolvedSize.value))\n\nconst checkIconClassName = computed(() => grCheckboxCheckIconClass({\n size: resolvedSize.value,\n checked: checked.value,\n}))\n\nconst labelClassName = computed(() => grCheckboxLabelClass(resolvedSize.value))\n\n// Держим `.checked` на нативном input синхронно с состоянием — `:checked`-биндинг\n// на скрытом элементе иногда отстаёт при программных обновлениях.\nconst nativeInput = ref<HTMLInputElement | null>(null)\nconst control = ref<HTMLElement | null>(null)\nwatch(\n checked,\n (value) => {\n if (nativeInput.value && nativeInput.value.checked !== value)\n nativeInput.value.checked = value\n },\n)\n\n// `indeterminate` можно выставить только через JS-свойство (не атрибут).\nfunction syncIndeterminate(): void {\n if (nativeInput.value)\n nativeInput.value.indeterminate = props.indeterminate\n}\nwatch(() => props.indeterminate, syncIndeterminate)\nonMounted(syncIndeterminate)\n\nfunction setChecked(next: boolean): void {\n if (resolvedDisabled.value || isReadonly.value) {\n // Нативный input мог уже переключиться от клика по внешнему `<label for>` —\n // возвращаем его к состоянию модели, иначе форма отправит непринятое значение.\n if (nativeInput.value)\n nativeInput.value.checked = checked.value\n return\n }\n\n if (props.modelValue !== undefined || !group) {\n emit('update:modelValue', next)\n emit('change', next)\n return\n }\n\n group.toggle(props.value, next)\n emit('change', next)\n}\n\nfunction toggle(): void {\n // Из промежуточного состояния переключаемся во «включено» (стандартное поведение).\n setChecked(props.indeterminate ? true : !checked.value)\n}\n\n// Клик по нативному input (в т.ч. по внешнему `<label for=\"...\">`) уже переключил его\n// `.checked` — берём значение как источник истины и эмитим модель.\nfunction onNativeChange(e: Event): void {\n setChecked((e.target as HTMLInputElement).checked)\n}\n\n// `<label for>` уводит фокус на скрытый input — визуально фокус пропадает. Возвращаем\n// его на контрол, который этот фокус и показывает.\nfunction onNativeFocus(): void {\n control.value?.focus()\n}\n\nfunction focus(): void {\n control.value?.focus()\n}\n\nfunction blur(): void {\n control.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n// Подпись держится снаружи роли-виджета именно для того, чтобы могла содержать\n// ссылки и кнопки, — поэтому клик по её интерактивному содержимому чекбокс не\n// переключает. Вложенный `<label>` считается интерактивным: он адресует\n// собственный контрол, и переключение чекбокса «заодно» было бы сюрпризом.\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el)\n return false\n return !!el.closest('a,button,input,select,textarea,label,[role=\"button\"],[role=\"link\"]')\n}\n\nfunction onClick(e: MouseEvent): void {\n if (isInteractiveTarget(e.target))\n return\n toggle()\n}\n</script>\n\n<template>\n <div\n data-gr-checkbox\n :class=\"rootClassName\"\n @click=\"onClick\"\n >\n <input\n :id=\"id\"\n ref=\"nativeInput\"\n type=\"checkbox\"\n :checked=\"checked\"\n :disabled=\"resolvedDisabled\"\n :name=\"resolvedName\"\n :value=\"value\"\n :form=\"form\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :style=\"hiddenInputStyle\"\n @change=\"onNativeChange\"\n @focus=\"onNativeFocus\"\n >\n <span\n :id=\"fieldControlId\"\n ref=\"control\"\n data-gr-checkbox-indicator\n role=\"checkbox\"\n :aria-checked=\"indeterminate ? 'mixed' : (checked ? 'true' : 'false')\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :tabindex=\"resolvedDisabled ? -1 : 0\"\n :class=\"controlClassName\"\n @keydown.space.prevent=\"toggle\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <IconMinus\n v-if=\"indeterminate\"\n :class=\"indeterminateIconClassName\"\n />\n <IconCheck\n v-else\n :class=\"checkIconClassName\"\n />\n </span>\n <span\n v-if=\"hasLabel\"\n :id=\"labelId\"\n :class=\"labelClassName\"\n >\n <slot />\n </span>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrCheckbox-Dp201frb.js","names":[],"sources":["../../../../src/components/GrCheckbox/grCheckboxGroupContext.ts","../../../../src/components/GrCheckbox/GrCheckbox.vue","../../../../src/components/GrCheckbox/GrCheckbox.vue"],"sourcesContent":["import type { ComputedRef, InjectionKey } from 'vue'\n\nimport type { GrCheckboxSize } from './grCheckboxStyles'\n\nexport type GrCheckboxGroupContext = {\n /** Выбранные значения группы. Чекбокс сравнивает с ними свой `value`. */\n modelValue: ComputedRef<string[]>\n name: ComputedRef<string | undefined>\n disabled: ComputedRef<boolean>\n readonly: ComputedRef<boolean>\n invalid: ComputedRef<boolean>\n /**\n * Обязательность группы объявляют её чекбоксы: `role=\"group\"` не поддерживает\n * `aria-required` (axe: `aria-allowed-attr`), а `role=\"checkbox\"` — да.\n */\n required: ComputedRef<boolean>\n size: ComputedRef<GrCheckboxSize>\n /** Добавляет или убирает значение из выбранных. */\n toggle: (value: string, checked: boolean) => void\n}\n\nexport const GR_CHECKBOX_GROUP_CONTEXT: InjectionKey<GrCheckboxGroupContext> = Symbol('GR_CHECKBOX_GROUP_CONTEXT')\n","<script setup lang=\"ts\">\n/**\n * GrCheckbox — GR-примитив чекбокса с нативным скрытым `<input type=\"checkbox\">`\n * для интеграции с HTML-формами (`FormData`, `form`).\n *\n * Источник истины — нативный input: клик по нему (в т.ч. по внешнему\n * `<label for=\"...\">`) слушается через `@change` и эмитит модель. Клик по видимой\n * части компонента переключает через корневой обработчик.\n *\n * Клавиатура: `Space` переключает значение (Enter — намеренно нет, это нестандартно\n * для чекбоксов). Фокус — на самом контроле (квадратике), как у нативного чекбокса.\n *\n * A11y: `role=\"checkbox\"` + `aria-checked` (`true`/`false`/`mixed`) + `aria-disabled`.\n * Роль висит **только на контроле**, а не на всей строке с подписью — по двум причинам:\n * - роль объявляет своих потомков презентационными, поэтому ни нативный input, ни\n * интерактивная подпись (ссылка на политику, кнопка «показать изменения») не могут\n * жить внутри: скринридер теряет их, axe падает на `nested-interactive`;\n * - имя виджета берётся из подписи через `aria-labelledby`, что и позволяет держать\n * её снаружи вместе со всем её интерактивным содержимым.\n *\n * `required` объявляется только через `aria-required`, на скрытый input он не уходит.\n * Нативная проверка потребовала бы фокуса на невалидном контроле, а он невидим и\n * `aria-hidden` — Chrome в таком случае молча отменяет сабмит всей формы\n * («An invalid form control … is not focusable»). Обязательность проверяет\n * `GrForm` правилом `required` — см. `docs/components/GrCheckbox.md`.\n *\n * Внутри `GrCheckboxGroup` значение приходит из группы: свой `modelValue` не\n * задаётся, а `value` сравнивается с массивом выбранных.\n */\nimport { computed, inject, onMounted, ref, useId, useSlots, watch } from 'vue'\nimport IconCheck from '~icons/lucide/check'\nimport IconMinus from '~icons/lucide/minus'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport { GR_CHECKBOX_GROUP_CONTEXT } from './grCheckboxGroupContext'\nimport {\n grCheckboxCheckIconClass,\n grCheckboxControlClass,\n grCheckboxIndeterminateIconClass,\n grCheckboxLabelClass,\n grCheckboxRootClass,\n type GrCheckboxLabelPosition,\n type GrCheckboxSize,\n} from './grCheckboxStyles'\n\nexport type { GrCheckboxLabelPosition, GrCheckboxSize } from './grCheckboxStyles'\n\nexport interface GrCheckboxProps {\n /** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */\n modelValue?: boolean\n disabled?: boolean\n name?: string\n value?: string\n /** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */\n required?: boolean\n /** Только для чтения: состояние видно, но не переключается. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n form?: string\n /** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for=\"...\">`. */\n id?: string\n /** Промежуточное («смешанное») состояние: `aria-checked=\"mixed\"`, индикатор — тире. */\n indeterminate?: boolean\n /** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */\n ariaLabel?: string\n /** Сторона подписи относительно контрола. */\n labelPosition?: GrCheckboxLabelPosition\n /** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */\n size?: GrCheckboxSize\n}\n\nexport interface GrCheckboxEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'change', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst hiddenInputStyle = {\n position: 'absolute',\n opacity: '0',\n width: '0',\n height: '0',\n pointerEvents: 'none',\n} as const\n\nconst props = withDefaults(defineProps<GrCheckboxProps>(), {\n modelValue: undefined,\n disabled: undefined,\n name: undefined,\n value: 'on',\n required: false,\n readonly: false,\n invalid: false,\n form: undefined,\n id: undefined,\n indeterminate: false,\n ariaLabel: undefined,\n labelPosition: 'end',\n size: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxEmits>()\ndefineSlots<{\n /** Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. */\n default?: () => any\n}>()\n\nconst slots = useSlots()\n\nconst labelId = useId()\nconst hasLabel = computed(() => Boolean(slots.default))\n\nconst group = inject(GR_CHECKBOX_GROUP_CONTEXT, null)\n\nconst checked = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n if (group)\n return group.modelValue.value.includes(props.value)\n\n return false\n})\n\nconst resolvedName = computed(() => props.name ?? group?.name.value)\n\n// Контекст `GrFormField`. Id поля вешается на `span[role=\"checkbox\"]` — именно он\n// виджет и держит фокус; на скрытом `aria-hidden`-инпуте он был бы бесполезен\n// (клик по подписи уводил бы фокус в невидимый элемент). Роль-виджет не является\n// labelable-элементом, поэтому имя от подписи поля приходит через `aria-labelledby`.\nconst {\n disabled: isDisabled,\n id: fieldControlId,\n labelId: fieldLabelId,\n describedBy,\n invalid: fieldInvalid,\n required: fieldRequired,\n readonly: fieldReadonly,\n} = useGrFormControl(() => props)\n\n// «Или», а не `??`: `isDisabled` уже сведён к булеву (свой проп + контекст\n// поля и формы), и `??` до группы просто не дошёл бы.\nconst resolvedDisabled = computed(() => isDisabled.value || Boolean(group?.disabled.value))\n\n// `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` — объявлять\n// обязательность и режим чтения группы обязаны сами чекбоксы.\nconst isRequired = computed(() => fieldRequired.value || Boolean(group?.required.value))\n\nconst isReadonly = computed(() => fieldReadonly.value || Boolean(group?.readonly.value))\n\n// Ошибка группы красит чекбоксы, но не объявляется на каждом из них: `aria-invalid`\n// уже висит на самой группе, и дублировать его на всех пунктах — значит заставить\n// диктор повторить «неверное значение» столько раз, сколько в группе чекбоксов.\nconst isInvalid = computed(() => fieldInvalid.value)\nconst showsInvalid = computed(() => isInvalid.value || Boolean(group?.invalid.value))\n\nconst labelledBy = computed(() => {\n if (props.ariaLabel)\n return undefined\n if (hasLabel.value)\n return labelId\n return fieldLabelId.value\n})\n\n// Эффективный размер: локальный проп → группа → `GrConfigProvider` → `md`.\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrCheckbox' },\n)\n\nconst rootClassName = computed(() => grCheckboxRootClass({\n size: resolvedSize.value,\n disabled: resolvedDisabled.value,\n labelPosition: props.labelPosition,\n}))\n\nconst controlClassName = computed(() => grCheckboxControlClass({\n size: resolvedSize.value,\n active: checked.value || props.indeterminate,\n disabled: resolvedDisabled.value,\n invalid: showsInvalid.value,\n}))\n\nconst indeterminateIconClassName = computed(() => grCheckboxIndeterminateIconClass(resolvedSize.value))\n\nconst checkIconClassName = computed(() => grCheckboxCheckIconClass({\n size: resolvedSize.value,\n checked: checked.value,\n}))\n\nconst labelClassName = computed(() => grCheckboxLabelClass(resolvedSize.value))\n\n// Держим `.checked` на нативном input синхронно с состоянием — `:checked`-биндинг\n// на скрытом элементе иногда отстаёт при программных обновлениях.\nconst nativeInput = ref<HTMLInputElement | null>(null)\nconst control = ref<HTMLElement | null>(null)\nwatch(\n checked,\n (value) => {\n if (nativeInput.value && nativeInput.value.checked !== value)\n nativeInput.value.checked = value\n },\n)\n\n// `indeterminate` можно выставить только через JS-свойство (не атрибут).\nfunction syncIndeterminate(): void {\n if (nativeInput.value)\n nativeInput.value.indeterminate = props.indeterminate\n}\nwatch(() => props.indeterminate, syncIndeterminate)\nonMounted(syncIndeterminate)\n\nfunction setChecked(next: boolean): void {\n if (resolvedDisabled.value || isReadonly.value) {\n // Нативный input мог уже переключиться от клика по внешнему `<label for>` —\n // возвращаем его к состоянию модели, иначе форма отправит непринятое значение.\n if (nativeInput.value)\n nativeInput.value.checked = checked.value\n return\n }\n\n if (props.modelValue !== undefined || !group) {\n emit('update:modelValue', next)\n emit('change', next)\n return\n }\n\n group.toggle(props.value, next)\n emit('change', next)\n}\n\nfunction toggle(): void {\n // Из промежуточного состояния переключаемся во «включено» (стандартное поведение).\n setChecked(props.indeterminate ? true : !checked.value)\n}\n\n// Клик по нативному input (в т.ч. по внешнему `<label for=\"...\">`) уже переключил его\n// `.checked` — берём значение как источник истины и эмитим модель.\nfunction onNativeChange(e: Event): void {\n setChecked((e.target as HTMLInputElement).checked)\n}\n\n// `<label for>` уводит фокус на скрытый input — визуально фокус пропадает. Возвращаем\n// его на контрол, который этот фокус и показывает.\nfunction onNativeFocus(): void {\n control.value?.focus()\n}\n\nfunction focus(): void {\n control.value?.focus()\n}\n\nfunction blur(): void {\n control.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n// Подпись держится снаружи роли-виджета именно для того, чтобы могла содержать\n// ссылки и кнопки, — поэтому клик по её интерактивному содержимому чекбокс не\n// переключает. Вложенный `<label>` считается интерактивным: он адресует\n// собственный контрол, и переключение чекбокса «заодно» было бы сюрпризом.\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el)\n return false\n return !!el.closest('a,button,input,select,textarea,label,[role=\"button\"],[role=\"link\"]')\n}\n\nfunction onClick(e: MouseEvent): void {\n if (isInteractiveTarget(e.target))\n return\n toggle()\n}\n</script>\n\n<template>\n <div\n data-gr-checkbox\n :class=\"rootClassName\"\n @click=\"onClick\"\n >\n <input\n :id=\"id\"\n ref=\"nativeInput\"\n type=\"checkbox\"\n :checked=\"checked\"\n :disabled=\"resolvedDisabled\"\n :name=\"resolvedName\"\n :value=\"value\"\n :form=\"form\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :style=\"hiddenInputStyle\"\n @change=\"onNativeChange\"\n @focus=\"onNativeFocus\"\n >\n <span\n :id=\"fieldControlId\"\n ref=\"control\"\n data-gr-checkbox-indicator\n role=\"checkbox\"\n :aria-checked=\"indeterminate ? 'mixed' : (checked ? 'true' : 'false')\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :tabindex=\"resolvedDisabled ? -1 : 0\"\n :class=\"controlClassName\"\n @keydown.space.prevent=\"toggle\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <IconMinus\n v-if=\"indeterminate\"\n :class=\"indeterminateIconClassName\"\n />\n <IconCheck\n v-else\n :class=\"checkIconClassName\"\n />\n </span>\n <span\n v-if=\"hasLabel\"\n :id=\"labelId\"\n :class=\"labelClassName\"\n >\n <slot />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckbox — GR-примитив чекбокса с нативным скрытым `<input type=\"checkbox\">`\n * для интеграции с HTML-формами (`FormData`, `form`).\n *\n * Источник истины — нативный input: клик по нему (в т.ч. по внешнему\n * `<label for=\"...\">`) слушается через `@change` и эмитит модель. Клик по видимой\n * части компонента переключает через корневой обработчик.\n *\n * Клавиатура: `Space` переключает значение (Enter — намеренно нет, это нестандартно\n * для чекбоксов). Фокус — на самом контроле (квадратике), как у нативного чекбокса.\n *\n * A11y: `role=\"checkbox\"` + `aria-checked` (`true`/`false`/`mixed`) + `aria-disabled`.\n * Роль висит **только на контроле**, а не на всей строке с подписью — по двум причинам:\n * - роль объявляет своих потомков презентационными, поэтому ни нативный input, ни\n * интерактивная подпись (ссылка на политику, кнопка «показать изменения») не могут\n * жить внутри: скринридер теряет их, axe падает на `nested-interactive`;\n * - имя виджета берётся из подписи через `aria-labelledby`, что и позволяет держать\n * её снаружи вместе со всем её интерактивным содержимым.\n *\n * `required` объявляется только через `aria-required`, на скрытый input он не уходит.\n * Нативная проверка потребовала бы фокуса на невалидном контроле, а он невидим и\n * `aria-hidden` — Chrome в таком случае молча отменяет сабмит всей формы\n * («An invalid form control … is not focusable»). Обязательность проверяет\n * `GrForm` правилом `required` — см. `docs/components/GrCheckbox.md`.\n *\n * Внутри `GrCheckboxGroup` значение приходит из группы: свой `modelValue` не\n * задаётся, а `value` сравнивается с массивом выбранных.\n */\nimport { computed, inject, onMounted, ref, useId, useSlots, watch } from 'vue'\nimport IconCheck from '~icons/lucide/check'\nimport IconMinus from '~icons/lucide/minus'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport { GR_CHECKBOX_GROUP_CONTEXT } from './grCheckboxGroupContext'\nimport {\n grCheckboxCheckIconClass,\n grCheckboxControlClass,\n grCheckboxIndeterminateIconClass,\n grCheckboxLabelClass,\n grCheckboxRootClass,\n type GrCheckboxLabelPosition,\n type GrCheckboxSize,\n} from './grCheckboxStyles'\n\nexport type { GrCheckboxLabelPosition, GrCheckboxSize } from './grCheckboxStyles'\n\nexport interface GrCheckboxProps {\n /** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */\n modelValue?: boolean\n disabled?: boolean\n name?: string\n value?: string\n /** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */\n required?: boolean\n /** Только для чтения: состояние видно, но не переключается. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n form?: string\n /** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for=\"...\">`. */\n id?: string\n /** Промежуточное («смешанное») состояние: `aria-checked=\"mixed\"`, индикатор — тире. */\n indeterminate?: boolean\n /** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */\n ariaLabel?: string\n /** Сторона подписи относительно контрола. */\n labelPosition?: GrCheckboxLabelPosition\n /** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */\n size?: GrCheckboxSize\n}\n\nexport interface GrCheckboxEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'change', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst hiddenInputStyle = {\n position: 'absolute',\n opacity: '0',\n width: '0',\n height: '0',\n pointerEvents: 'none',\n} as const\n\nconst props = withDefaults(defineProps<GrCheckboxProps>(), {\n modelValue: undefined,\n disabled: undefined,\n name: undefined,\n value: 'on',\n required: false,\n readonly: false,\n invalid: false,\n form: undefined,\n id: undefined,\n indeterminate: false,\n ariaLabel: undefined,\n labelPosition: 'end',\n size: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxEmits>()\ndefineSlots<{\n /** Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. */\n default?: () => any\n}>()\n\nconst slots = useSlots()\n\nconst labelId = useId()\nconst hasLabel = computed(() => Boolean(slots.default))\n\nconst group = inject(GR_CHECKBOX_GROUP_CONTEXT, null)\n\nconst checked = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n if (group)\n return group.modelValue.value.includes(props.value)\n\n return false\n})\n\nconst resolvedName = computed(() => props.name ?? group?.name.value)\n\n// Контекст `GrFormField`. Id поля вешается на `span[role=\"checkbox\"]` — именно он\n// виджет и держит фокус; на скрытом `aria-hidden`-инпуте он был бы бесполезен\n// (клик по подписи уводил бы фокус в невидимый элемент). Роль-виджет не является\n// labelable-элементом, поэтому имя от подписи поля приходит через `aria-labelledby`.\nconst {\n disabled: isDisabled,\n id: fieldControlId,\n labelId: fieldLabelId,\n describedBy,\n invalid: fieldInvalid,\n required: fieldRequired,\n readonly: fieldReadonly,\n} = useGrFormControl(() => props)\n\n// «Или», а не `??`: `isDisabled` уже сведён к булеву (свой проп + контекст\n// поля и формы), и `??` до группы просто не дошёл бы.\nconst resolvedDisabled = computed(() => isDisabled.value || Boolean(group?.disabled.value))\n\n// `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` — объявлять\n// обязательность и режим чтения группы обязаны сами чекбоксы.\nconst isRequired = computed(() => fieldRequired.value || Boolean(group?.required.value))\n\nconst isReadonly = computed(() => fieldReadonly.value || Boolean(group?.readonly.value))\n\n// Ошибка группы красит чекбоксы, но не объявляется на каждом из них: `aria-invalid`\n// уже висит на самой группе, и дублировать его на всех пунктах — значит заставить\n// диктор повторить «неверное значение» столько раз, сколько в группе чекбоксов.\nconst isInvalid = computed(() => fieldInvalid.value)\nconst showsInvalid = computed(() => isInvalid.value || Boolean(group?.invalid.value))\n\nconst labelledBy = computed(() => {\n if (props.ariaLabel)\n return undefined\n if (hasLabel.value)\n return labelId\n return fieldLabelId.value\n})\n\n// Эффективный размер: локальный проп → группа → `GrConfigProvider` → `md`.\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrCheckbox' },\n)\n\nconst rootClassName = computed(() => grCheckboxRootClass({\n size: resolvedSize.value,\n disabled: resolvedDisabled.value,\n labelPosition: props.labelPosition,\n}))\n\nconst controlClassName = computed(() => grCheckboxControlClass({\n size: resolvedSize.value,\n active: checked.value || props.indeterminate,\n disabled: resolvedDisabled.value,\n invalid: showsInvalid.value,\n}))\n\nconst indeterminateIconClassName = computed(() => grCheckboxIndeterminateIconClass(resolvedSize.value))\n\nconst checkIconClassName = computed(() => grCheckboxCheckIconClass({\n size: resolvedSize.value,\n checked: checked.value,\n}))\n\nconst labelClassName = computed(() => grCheckboxLabelClass(resolvedSize.value))\n\n// Держим `.checked` на нативном input синхронно с состоянием — `:checked`-биндинг\n// на скрытом элементе иногда отстаёт при программных обновлениях.\nconst nativeInput = ref<HTMLInputElement | null>(null)\nconst control = ref<HTMLElement | null>(null)\nwatch(\n checked,\n (value) => {\n if (nativeInput.value && nativeInput.value.checked !== value)\n nativeInput.value.checked = value\n },\n)\n\n// `indeterminate` можно выставить только через JS-свойство (не атрибут).\nfunction syncIndeterminate(): void {\n if (nativeInput.value)\n nativeInput.value.indeterminate = props.indeterminate\n}\nwatch(() => props.indeterminate, syncIndeterminate)\nonMounted(syncIndeterminate)\n\nfunction setChecked(next: boolean): void {\n if (resolvedDisabled.value || isReadonly.value) {\n // Нативный input мог уже переключиться от клика по внешнему `<label for>` —\n // возвращаем его к состоянию модели, иначе форма отправит непринятое значение.\n if (nativeInput.value)\n nativeInput.value.checked = checked.value\n return\n }\n\n if (props.modelValue !== undefined || !group) {\n emit('update:modelValue', next)\n emit('change', next)\n return\n }\n\n group.toggle(props.value, next)\n emit('change', next)\n}\n\nfunction toggle(): void {\n // Из промежуточного состояния переключаемся во «включено» (стандартное поведение).\n setChecked(props.indeterminate ? true : !checked.value)\n}\n\n// Клик по нативному input (в т.ч. по внешнему `<label for=\"...\">`) уже переключил его\n// `.checked` — берём значение как источник истины и эмитим модель.\nfunction onNativeChange(e: Event): void {\n setChecked((e.target as HTMLInputElement).checked)\n}\n\n// `<label for>` уводит фокус на скрытый input — визуально фокус пропадает. Возвращаем\n// его на контрол, который этот фокус и показывает.\nfunction onNativeFocus(): void {\n control.value?.focus()\n}\n\nfunction focus(): void {\n control.value?.focus()\n}\n\nfunction blur(): void {\n control.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n// Подпись держится снаружи роли-виджета именно для того, чтобы могла содержать\n// ссылки и кнопки, — поэтому клик по её интерактивному содержимому чекбокс не\n// переключает. Вложенный `<label>` считается интерактивным: он адресует\n// собственный контрол, и переключение чекбокса «заодно» было бы сюрпризом.\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el)\n return false\n return !!el.closest('a,button,input,select,textarea,label,[role=\"button\"],[role=\"link\"]')\n}\n\nfunction onClick(e: MouseEvent): void {\n if (isInteractiveTarget(e.target))\n return\n toggle()\n}\n</script>\n\n<template>\n <div\n data-gr-checkbox\n :class=\"rootClassName\"\n @click=\"onClick\"\n >\n <input\n :id=\"id\"\n ref=\"nativeInput\"\n type=\"checkbox\"\n :checked=\"checked\"\n :disabled=\"resolvedDisabled\"\n :name=\"resolvedName\"\n :value=\"value\"\n :form=\"form\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :style=\"hiddenInputStyle\"\n @change=\"onNativeChange\"\n @focus=\"onNativeFocus\"\n >\n <span\n :id=\"fieldControlId\"\n ref=\"control\"\n data-gr-checkbox-indicator\n role=\"checkbox\"\n :aria-checked=\"indeterminate ? 'mixed' : (checked ? 'true' : 'false')\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :tabindex=\"resolvedDisabled ? -1 : 0\"\n :class=\"controlClassName\"\n @keydown.space.prevent=\"toggle\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <IconMinus\n v-if=\"indeterminate\"\n :class=\"indeterminateIconClassName\"\n />\n <IconCheck\n v-else\n :class=\"checkIconClassName\"\n />\n </span>\n <span\n v-if=\"hasLabel\"\n :id=\"labelId\"\n :class=\"labelClassName\"\n >\n <slot />\n </span>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrCheckbox_default } from "./chunks/GrCheckbox-
|
|
1
|
+
import { t as GrCheckbox_default } from "./chunks/GrCheckbox-Dp201frb.js";
|
|
2
2
|
import { n as grCheckboxSafelist, t as grCheckboxConfig } from "../../chunks/config-DZCUPHPU.js";
|
|
3
3
|
export { GrCheckbox_default as GrCheckbox, GrCheckbox_default as default, grCheckboxConfig, grCheckboxSafelist };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as useGrComponentSize } from "../../../chunks/context-
|
|
1
|
+
import { a as useGrComponentSize } from "../../../chunks/context-CPMRfwVr.js";
|
|
2
2
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
3
3
|
import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
|
|
4
|
-
import { n as GR_CHECKBOX_GROUP_CONTEXT, t as GrCheckbox_default } from "../../GrCheckbox/chunks/GrCheckbox-
|
|
4
|
+
import { n as GR_CHECKBOX_GROUP_CONTEXT, t as GrCheckbox_default } from "../../GrCheckbox/chunks/GrCheckbox-Dp201frb.js";
|
|
5
5
|
import { Fragment, computed, createBlock, createElementBlock, createTextVNode, defineComponent, normalizeClass, openBlock, provide, ref, renderList, renderSlot, toDisplayString, unref, withCtx } from "vue";
|
|
6
6
|
//#region src/components/GrCheckboxGroup/GrCheckboxGroup.vue?vue&type=script&setup=true&lang.ts
|
|
7
7
|
var _hoisted_1 = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrCheckboxGroup-BOwrVcFr.js","names":[],"sources":["../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue","../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\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\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_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 required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\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\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_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 required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDA,MAAM,QAAQ;EAYd,MAAM,OAAO;EAQb,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,kBAAkB,CAAC;EAI1F,MAAM,EACJ,UAAU,YACV,IAAI,SACJ,SAAS,cACT,aACA,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;EAEhC,MAAM,aAAa,eAAgB,MAAM,YAAY,KAAA,IAAY,aAAa,KAAM;EAEpF,MAAM,cAAc,eAClB,MAAM,cAAc,eAAe,sCAAsC,YAC3E;EAEA,SAAS,OAAO,OAAe,SAAwB;GACrD,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,IAAI,SAAS;IACX,IAAI,MAAM,WAAW,SAAS,KAAK,GACjC;IACF,OAAO,CAAC,GAAG,MAAM,YAAY,KAAK,CAAC;IACnC;GACF;GAEA,OAAO,MAAM,WAAW,QAAO,SAAQ,SAAS,KAAK,CAAC;EACxD;EAEA,SAAS,OAAO,MAAsB;GACpC,KAAK,qBAAqB,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;EAEA,MAAM,SAAS,IAAwB,IAAI;EAI3C,MAAM,EAAE,WAAW,eAAe,eAAe,QAAQ;GACvD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;EACpC,CAAC;EAED,SAAS,gBAAgD;GACvD,OAAO,OAAO,OAAO,cAA2B,mDAA+C;EACjG;EAEA,SAAS,QAAc;GACrB,cAAc,CAAC,EAAE,MAAM;EACzB;EAEA,SAAS,OAAa;GACpB,cAAc,CAAC,EAAE,KAAK;EACxB;EAEA,SAAa;GAAE;GAAO;EAAK,CAAC;EAE5B,QAAQ,2BAA2B;GACjC,YAAY,eAAe,MAAM,UAAU;GAC3C,MAAM,eAAe,MAAM,IAAI;GAC/B,UAAU,eAAe,WAAW,KAAK;GACzC,UAAU;GACV,SAAS;GACT,MAAM;GACN,UAAU;GACV;EACF,CAAC;;uBAIC,mBAwBM,OAAA;IAvBH,IAAI,MAAA,OAAA;aACD;IAAJ,KAAI;IACJ,0BAAA;IACA,MAAK;IACJ,OAAK,eAAE,YAAA,KAAW;IAClB,cAAY,QAAA;IACZ,mBAAiB,WAAA;IACjB,oBAAkB,MAAA,WAAA;IAClB,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;IACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,WAAO,OAAA,OAAA,OAAA,MAAA,GAAA,SAAE,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACT,YAAQ,OAAA,OAAA,OAAA,MAAA,GAAA,SAAE,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;OAEX,WASO,KAAA,QAAA,WAAA,CAAA,SAAA,EAAA,UAAA,IAAA,GARL,mBAOa,UAAA,MAAA,WANM,QAAA,WAAO,CAAA,IAAjB,WAAM;wBADf,YAOa,oBAAA;KALV,KAAK,OAAO;KACZ,OAAO,OAAO;KACd,UAAU,OAAO;;4BAEA,CAAA,gBAAA,gBAAf,OAAO,KAAK,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"GrCheckboxGroup-IpqG5qwm.js","names":[],"sources":["../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue","../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\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\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_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 required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\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\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_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 required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDA,MAAM,QAAQ;EAYd,MAAM,OAAO;EAQb,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,kBAAkB,CAAC;EAI1F,MAAM,EACJ,UAAU,YACV,IAAI,SACJ,SAAS,cACT,aACA,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;EAEhC,MAAM,aAAa,eAAgB,MAAM,YAAY,KAAA,IAAY,aAAa,KAAM;EAEpF,MAAM,cAAc,eAClB,MAAM,cAAc,eAAe,sCAAsC,YAC3E;EAEA,SAAS,OAAO,OAAe,SAAwB;GACrD,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,IAAI,SAAS;IACX,IAAI,MAAM,WAAW,SAAS,KAAK,GACjC;IACF,OAAO,CAAC,GAAG,MAAM,YAAY,KAAK,CAAC;IACnC;GACF;GAEA,OAAO,MAAM,WAAW,QAAO,SAAQ,SAAS,KAAK,CAAC;EACxD;EAEA,SAAS,OAAO,MAAsB;GACpC,KAAK,qBAAqB,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;EAEA,MAAM,SAAS,IAAwB,IAAI;EAI3C,MAAM,EAAE,WAAW,eAAe,eAAe,QAAQ;GACvD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;EACpC,CAAC;EAED,SAAS,gBAAgD;GACvD,OAAO,OAAO,OAAO,cAA2B,mDAA+C;EACjG;EAEA,SAAS,QAAc;GACrB,cAAc,CAAC,EAAE,MAAM;EACzB;EAEA,SAAS,OAAa;GACpB,cAAc,CAAC,EAAE,KAAK;EACxB;EAEA,SAAa;GAAE;GAAO;EAAK,CAAC;EAE5B,QAAQ,2BAA2B;GACjC,YAAY,eAAe,MAAM,UAAU;GAC3C,MAAM,eAAe,MAAM,IAAI;GAC/B,UAAU,eAAe,WAAW,KAAK;GACzC,UAAU;GACV,SAAS;GACT,MAAM;GACN,UAAU;GACV;EACF,CAAC;;GAIC,OAAA,UAAA,GAAA,mBAwBM,OAAA;IAvBH,IAAI,MAAA,OAAA;IACD,SAAA;IAAJ,KAAI;IACJ,0BAAA;IACA,MAAK;IACJ,OAAK,eAAE,YAAA,KAAW;IAClB,cAAY,QAAA;IACZ,mBAAiB,WAAA;IACjB,oBAAkB,MAAA,WAAA;IAClB,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;IACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,WAAO,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACT,YAAQ,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;GAEX,GAAA,CAAA,WASO,KAAA,QAAA,WAAA,CAAA,SAAA,EARL,UAAA,IAAA,GAAA,mBAOa,UAAA,MAAA,WANM,QAAA,WAAO,CAAA,IAAjB,WAAM;IADf,OAAA,UAAA,GAAA,YAOa,oBAAA;KALV,KAAK,OAAO;KACZ,OAAO,OAAO;KACd,UAAU,OAAO;;KAElB,SAAA,cAAkB,CAAf,gBAAA,gBAAA,OAAO,KAAK,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrCheckboxGroup_default } from "./chunks/GrCheckboxGroup-
|
|
1
|
+
import { t as GrCheckboxGroup_default } from "./chunks/GrCheckboxGroup-IpqG5qwm.js";
|
|
2
2
|
import { t as grCheckboxGroupConfig } from "../../chunks/config-BuGlNPE9.js";
|
|
3
3
|
export { GrCheckboxGroup_default as GrCheckboxGroup, GrCheckboxGroup_default as default, grCheckboxGroupConfig };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as x_default } from "../../../chunks/x-2KXnqxiD.js";
|
|
2
|
-
import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunks/context-
|
|
2
|
+
import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunks/context-CPMRfwVr.js";
|
|
3
3
|
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
|
|
4
|
-
import { t as warnRenamedProp } from "../../../chunks/renamedProp-
|
|
4
|
+
import { t as warnRenamedProp } from "../../../chunks/renamedProp-Dy96tT-F.js";
|
|
5
5
|
import { t as GR_CHIP_GROUP_CONTEXT } from "../../../chunks/grChipGroupContext-DZXkACap.js";
|
|
6
6
|
import { a as chipIconSizeClassBySize, f as grChipClass, i as chipIconClass, n as chipCloseClass, s as chipLabelClass, t as chipCloseButtonClass } from "../../../chunks/grChipStyles-DcDyxAL0.js";
|
|
7
7
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, normalizeClass, onBeforeUnmount, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, unref, useAttrs, withCtx, withModifiers } from "vue";
|
|
@@ -148,11 +148,14 @@ var GrChip_default = /* @__PURE__ */ defineComponent({
|
|
|
148
148
|
requestRemove();
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
-
if (group)
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
if (group) {
|
|
152
|
+
const unregister = group.register({
|
|
153
|
+
value: () => props.value,
|
|
154
|
+
disabled: () => isDisabled.value,
|
|
155
|
+
el: () => rootEl.value
|
|
156
|
+
});
|
|
157
|
+
onBeforeUnmount(unregister);
|
|
158
|
+
}
|
|
156
159
|
const removeEl = ref(null);
|
|
157
160
|
__expose({
|
|
158
161
|
focus: () => rootEl.value?.focus(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrChip-BTivtwff.js","names":["$slots"],"sources":["../../../../src/components/GrChip/GrChip.vue","../../../../src/components/GrChip/GrChip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject, onBeforeUnmount, ref, useAttrs } from 'vue'\n\nimport IconClose from '~icons/lucide/x'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport type { GrChipValue } from './grChipGroupContext'\n\nimport { warnRenamedProp } from '../shared/renamedProp'\nimport { GR_CHIP_GROUP_CONTEXT } from './grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from './grChipStyles'\nimport {\n chipCloseButtonClass,\n chipCloseClass,\n chipIconClass,\n chipIconSizeClassBySize,\n chipLabelClass,\n grChipClass,\n} from './grChipStyles'\n\n/**\n * Интерактивный тег: снимаемый, выбираемый, с иконкой.\n *\n * От `GrBadge` отличается не видом, а природой: бейдж — метка, чип — виджет.\n * Поэтому цвета и радиусы взяты у бейджа как есть (в одном ряду они обязаны\n * совпадать), а роль, клавиатура и размеры — свои.\n */\nexport interface GrChipProps {\n /** Значение чипа в группе. Вне `GrChipGroup` не используется. */\n value?: GrChipValue\n /**\n * Подпись. Нужна отдельно от слота: из неё собирается имя кнопки снятия —\n * «Убрать» на двадцати кнопках подряд не даёт выбрать нужную.\n */\n label?: string\n tone?: GrChipTone\n dark?: boolean\n size?: GrChipSize\n radius?: GrChipRadius\n /** Чип становится переключателем: `aria-pressed`, `Enter`/`Space`. */\n selectable?: boolean\n /** Состояние переключателя вне группы. Внутри группы значение ведёт группа. */\n selected?: boolean\n /** Крестик. Внутри виджета он не кнопка — см. блок про роли ниже. */\n closable?: boolean\n disabled?: boolean\n /** Доступное имя, когда подпись не объясняет назначения. */\n ariaLabel?: string\n /** Имя кнопки снятия целиком. Перебивает собранное из `label`. */\n removeLabel?: string\n /**\n * `tabindex` кнопки снятия — для чипа внутри поля ввода.\n *\n * Там таб-стоп принадлежит `<input>`, а ряд чипов ходит стрелками: у\n * `GrInputTag` кольцо оставляет ровно один `0`, у `GrAutocomplete` их нет\n * вовсе. Проп нужен потому, что кольцом управляет родитель — он знает и\n * порядок чипов, и что стоит за краем ряда.\n */\n removeTabindex?: number\n}\n\nexport interface GrChipEmits {\n (e: 'update:selected', value: boolean): void\n (e: 'remove'): void\n}\n\nconst props = withDefaults(defineProps<GrChipProps>(), {\n value: undefined,\n label: undefined,\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n tone: undefined,\n dark: undefined,\n size: undefined,\n radius: undefined,\n selectable: false,\n selected: false,\n closable: false,\n disabled: false,\n ariaLabel: undefined,\n removeLabel: undefined,\n removeTabindex: undefined,\n})\n\nconst emit = defineEmits<GrChipEmits>()\n\n// `variant` переименован в `tone`: незнакомый атрибут Vue сажает на корневой\n// узел, поэтому старое имя не роняет ни типы, ни рантайм — компонент молча\n// рисуется дефолтным тоном.\nwarnRenamedProp('GrChip', useAttrs(), { variant: 'tone' })\n\ndefineSlots<{\n /** Подпись чипа. Внутри выбираемого чипа — только фразовое содержимое. */\n default?: () => unknown\n /** Иконка перед подписью. */\n icon?: () => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst group = inject(GR_CHIP_GROUP_CONTEXT, null)\nconst rootEl = ref<HTMLElement | null>(null)\n\nconst inGroup = computed(() => group !== null && props.value !== undefined)\n\nconst isDisabled = computed(() => props.disabled || (group?.disabled.value ?? false))\nconst isReadonly = computed(() => group?.readonly.value ?? false)\n\n/**\n * Чип — виджет ровно тогда, когда по нему кликают.\n *\n * От этого зависит вся разметка: у виджета роль, `tabindex` и клавиатура, а\n * крестик внутри него перестаёт быть кнопкой.\n */\nconst isInteractive = computed(() => inGroup.value || props.selectable)\n\nconst isSelected = computed(() => {\n if (inGroup.value && props.value !== undefined)\n return group!.isSelected(props.value)\n return props.selected\n})\n\nconst isClosable = computed(() => {\n if (isReadonly.value || isDisabled.value)\n return false\n return props.closable || (inGroup.value ? group!.closable.value : false)\n})\n\n// Приоритет: локальный проп → значение группы → `GrConfigProvider` → дефолт.\n// Группа специфичнее конфига, поэтому её значение подаётся как «локальное».\nconst resolvedSize = useGrComponentSize<GrChipSize>(\n () => props.size ?? (inGroup.value ? group!.size.value : undefined),\n { component: 'GrChip' },\n)\nconst resolvedTone = useGrComponentProp(\n 'GrChip',\n 'tone',\n () => props.tone ?? (inGroup.value ? group!.tone.value : undefined),\n 'neutral',\n)\nconst resolvedRadius = useGrComponentProp(\n 'GrChip',\n 'radius',\n () => props.radius ?? (inGroup.value ? group!.radius.value : undefined),\n 'round',\n)\nconst resolvedDark = useGrComponentProp(\n 'GrChip',\n 'dark',\n () => props.dark ?? (inGroup.value ? group!.dark.value : undefined),\n false,\n)\n\nconst rootClass = computed(() => grChipClass({\n tone: resolvedTone.value,\n dark: resolvedDark.value,\n size: resolvedSize.value,\n radius: resolvedRadius.value,\n interactive: isInteractive.value && !isReadonly.value,\n selected: isSelected.value,\n disabled: isDisabled.value,\n}))\n\nconst iconSizeClass = computed(() => chipIconSizeClassBySize[resolvedSize.value])\n\nconst removeTitle = computed(() => {\n if (props.removeLabel)\n return props.removeLabel\n if (props.label)\n return t('gr.chip.removeNamed', 'Remove {label}', { label: props.label })\n return t('gr.chip.remove', 'Remove')\n})\n\n/**\n * Роль чипа задаёт группа, а не потребитель.\n *\n * Одиночный переключатель — кнопка с `aria-pressed`; в группе роль зависит от\n * множественности выбора: `radio` в одиночной (образец — `GrSegmented`),\n * `option` во множественной, где контейнер объявлен `listbox` c\n * `aria-multiselectable`.\n */\nconst chipRole = computed(() => {\n if (!inGroup.value)\n return undefined\n return group!.selection.value === 'single' ? 'radio' : 'option'\n})\n\nconst tabindex = computed(() => {\n if (!isInteractive.value)\n return undefined\n if (isDisabled.value)\n return -1\n if (!inGroup.value || props.value === undefined)\n return 0\n return group!.rovingValue.value === props.value ? 0 : -1\n})\n\nfunction toggle(): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (inGroup.value && props.value !== undefined) {\n group!.toggle(props.value)\n return\n }\n\n if (props.selectable)\n emit('update:selected', !props.selected)\n}\n\nfunction requestRemove(): void {\n if (!isClosable.value)\n return\n\n emit('remove')\n if (inGroup.value && props.value !== undefined)\n group!.requestRemove(props.value)\n}\n\n/**\n * Крестик внутри виджета — не кнопка, поэтому его клик приходит сюда же и\n * разбирается по цели. Тот же приём у `GrTabs`: внутрь роли-виджета вложенная\n * кнопка запрещена (axe: `nested-interactive`), а `<button>` внутри `<button>`\n * невалиден и по контент-модели HTML.\n */\nfunction onRootClick(event: MouseEvent): void {\n if (isDisabled.value)\n return\n\n if (event.target instanceof Element && event.target.closest('[data-gr-chip-close]')) {\n requestRemove()\n return\n }\n\n toggle()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (isDisabled.value)\n return\n\n // Навигация принадлежит группе: состав знает только она.\n if (inGroup.value && group!.handleNavigationKeys(event))\n return\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n if (!isClosable.value)\n return\n event.preventDefault()\n requestRemove()\n }\n}\n\nif (group) {\n const unregister = group.register({\n value: () => props.value as GrChipValue,\n disabled: () => isDisabled.value,\n el: () => rootEl.value,\n })\n onBeforeUnmount(unregister)\n}\n\nconst removeEl = ref<HTMLButtonElement | null>(null)\n\ndefineExpose({\n focus: () => rootEl.value?.focus(),\n blur: () => rootEl.value?.blur(),\n /**\n * Кнопка снятия — цель roving-фокуса у родителя. Отдаётся элементом, а не\n * методом `focusRemove`: кольцу нужен сам узел, оно само решает, когда и\n * куда переносить фокус.\n */\n removeEl,\n})\n</script>\n\n<template>\n <component\n :is=\"isInteractive ? 'button' : 'span'\"\n ref=\"rootEl\"\n data-gr-chip\n :type=\"isInteractive ? 'button' : undefined\"\n :class=\"rootClass\"\n :role=\"chipRole\"\n :data-value=\"value\"\n :aria-label=\"ariaLabel\"\n :aria-checked=\"chipRole === 'radio' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-selected=\"chipRole === 'option' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-pressed=\"isInteractive && !chipRole ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :disabled=\"isInteractive && isDisabled ? true : undefined\"\n :aria-keyshortcuts=\"isInteractive && isClosable ? 'Delete' : undefined\"\n :tabindex=\"tabindex\"\n @click=\"isInteractive ? onRootClick($event) : undefined\"\n @keydown=\"isInteractive ? onRootKeydown($event) : undefined\"\n >\n <span v-if=\"$slots.icon\" data-gr-chip-icon :class=\"[chipIconClass, iconSizeClass]\">\n <slot name=\"icon\" />\n </span>\n\n <span data-gr-chip-label :class=\"chipLabelClass\">\n <slot>{{ label }}</slot>\n </span>\n\n <!--\n Крестик существует в двух видах, и различитель — роль самого чипа.\n Виджет: `<span aria-hidden>` вне таб-порядка, снятие идёт `Delete`/`Backspace`.\n Не виджет: настоящая кнопка со своей остановкой `Tab` и своим именем.\n -->\n <span\n v-if=\"isClosable && isInteractive\"\n data-gr-chip-close\n :class=\"[chipCloseClass, iconSizeClass]\"\n :title=\"removeTitle\"\n aria-hidden=\"true\"\n >\n <IconClose class=\"h-full w-full\" />\n </span>\n\n <button\n v-else-if=\"isClosable\"\n ref=\"removeEl\"\n data-gr-chip-close\n type=\"button\"\n :class=\"[chipCloseButtonClass, iconSizeClass]\"\n :aria-label=\"removeTitle\"\n :tabindex=\"removeTabindex\"\n @mousedown.prevent.stop\n @click.stop=\"requestRemove()\"\n >\n <IconClose class=\"h-full w-full\" />\n </button>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, onBeforeUnmount, ref, useAttrs } from 'vue'\n\nimport IconClose from '~icons/lucide/x'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport type { GrChipValue } from './grChipGroupContext'\n\nimport { warnRenamedProp } from '../shared/renamedProp'\nimport { GR_CHIP_GROUP_CONTEXT } from './grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from './grChipStyles'\nimport {\n chipCloseButtonClass,\n chipCloseClass,\n chipIconClass,\n chipIconSizeClassBySize,\n chipLabelClass,\n grChipClass,\n} from './grChipStyles'\n\n/**\n * Интерактивный тег: снимаемый, выбираемый, с иконкой.\n *\n * От `GrBadge` отличается не видом, а природой: бейдж — метка, чип — виджет.\n * Поэтому цвета и радиусы взяты у бейджа как есть (в одном ряду они обязаны\n * совпадать), а роль, клавиатура и размеры — свои.\n */\nexport interface GrChipProps {\n /** Значение чипа в группе. Вне `GrChipGroup` не используется. */\n value?: GrChipValue\n /**\n * Подпись. Нужна отдельно от слота: из неё собирается имя кнопки снятия —\n * «Убрать» на двадцати кнопках подряд не даёт выбрать нужную.\n */\n label?: string\n tone?: GrChipTone\n dark?: boolean\n size?: GrChipSize\n radius?: GrChipRadius\n /** Чип становится переключателем: `aria-pressed`, `Enter`/`Space`. */\n selectable?: boolean\n /** Состояние переключателя вне группы. Внутри группы значение ведёт группа. */\n selected?: boolean\n /** Крестик. Внутри виджета он не кнопка — см. блок про роли ниже. */\n closable?: boolean\n disabled?: boolean\n /** Доступное имя, когда подпись не объясняет назначения. */\n ariaLabel?: string\n /** Имя кнопки снятия целиком. Перебивает собранное из `label`. */\n removeLabel?: string\n /**\n * `tabindex` кнопки снятия — для чипа внутри поля ввода.\n *\n * Там таб-стоп принадлежит `<input>`, а ряд чипов ходит стрелками: у\n * `GrInputTag` кольцо оставляет ровно один `0`, у `GrAutocomplete` их нет\n * вовсе. Проп нужен потому, что кольцом управляет родитель — он знает и\n * порядок чипов, и что стоит за краем ряда.\n */\n removeTabindex?: number\n}\n\nexport interface GrChipEmits {\n (e: 'update:selected', value: boolean): void\n (e: 'remove'): void\n}\n\nconst props = withDefaults(defineProps<GrChipProps>(), {\n value: undefined,\n label: undefined,\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n tone: undefined,\n dark: undefined,\n size: undefined,\n radius: undefined,\n selectable: false,\n selected: false,\n closable: false,\n disabled: false,\n ariaLabel: undefined,\n removeLabel: undefined,\n removeTabindex: undefined,\n})\n\nconst emit = defineEmits<GrChipEmits>()\n\n// `variant` переименован в `tone`: незнакомый атрибут Vue сажает на корневой\n// узел, поэтому старое имя не роняет ни типы, ни рантайм — компонент молча\n// рисуется дефолтным тоном.\nwarnRenamedProp('GrChip', useAttrs(), { variant: 'tone' })\n\ndefineSlots<{\n /** Подпись чипа. Внутри выбираемого чипа — только фразовое содержимое. */\n default?: () => unknown\n /** Иконка перед подписью. */\n icon?: () => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst group = inject(GR_CHIP_GROUP_CONTEXT, null)\nconst rootEl = ref<HTMLElement | null>(null)\n\nconst inGroup = computed(() => group !== null && props.value !== undefined)\n\nconst isDisabled = computed(() => props.disabled || (group?.disabled.value ?? false))\nconst isReadonly = computed(() => group?.readonly.value ?? false)\n\n/**\n * Чип — виджет ровно тогда, когда по нему кликают.\n *\n * От этого зависит вся разметка: у виджета роль, `tabindex` и клавиатура, а\n * крестик внутри него перестаёт быть кнопкой.\n */\nconst isInteractive = computed(() => inGroup.value || props.selectable)\n\nconst isSelected = computed(() => {\n if (inGroup.value && props.value !== undefined)\n return group!.isSelected(props.value)\n return props.selected\n})\n\nconst isClosable = computed(() => {\n if (isReadonly.value || isDisabled.value)\n return false\n return props.closable || (inGroup.value ? group!.closable.value : false)\n})\n\n// Приоритет: локальный проп → значение группы → `GrConfigProvider` → дефолт.\n// Группа специфичнее конфига, поэтому её значение подаётся как «локальное».\nconst resolvedSize = useGrComponentSize<GrChipSize>(\n () => props.size ?? (inGroup.value ? group!.size.value : undefined),\n { component: 'GrChip' },\n)\nconst resolvedTone = useGrComponentProp(\n 'GrChip',\n 'tone',\n () => props.tone ?? (inGroup.value ? group!.tone.value : undefined),\n 'neutral',\n)\nconst resolvedRadius = useGrComponentProp(\n 'GrChip',\n 'radius',\n () => props.radius ?? (inGroup.value ? group!.radius.value : undefined),\n 'round',\n)\nconst resolvedDark = useGrComponentProp(\n 'GrChip',\n 'dark',\n () => props.dark ?? (inGroup.value ? group!.dark.value : undefined),\n false,\n)\n\nconst rootClass = computed(() => grChipClass({\n tone: resolvedTone.value,\n dark: resolvedDark.value,\n size: resolvedSize.value,\n radius: resolvedRadius.value,\n interactive: isInteractive.value && !isReadonly.value,\n selected: isSelected.value,\n disabled: isDisabled.value,\n}))\n\nconst iconSizeClass = computed(() => chipIconSizeClassBySize[resolvedSize.value])\n\nconst removeTitle = computed(() => {\n if (props.removeLabel)\n return props.removeLabel\n if (props.label)\n return t('gr.chip.removeNamed', 'Remove {label}', { label: props.label })\n return t('gr.chip.remove', 'Remove')\n})\n\n/**\n * Роль чипа задаёт группа, а не потребитель.\n *\n * Одиночный переключатель — кнопка с `aria-pressed`; в группе роль зависит от\n * множественности выбора: `radio` в одиночной (образец — `GrSegmented`),\n * `option` во множественной, где контейнер объявлен `listbox` c\n * `aria-multiselectable`.\n */\nconst chipRole = computed(() => {\n if (!inGroup.value)\n return undefined\n return group!.selection.value === 'single' ? 'radio' : 'option'\n})\n\nconst tabindex = computed(() => {\n if (!isInteractive.value)\n return undefined\n if (isDisabled.value)\n return -1\n if (!inGroup.value || props.value === undefined)\n return 0\n return group!.rovingValue.value === props.value ? 0 : -1\n})\n\nfunction toggle(): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (inGroup.value && props.value !== undefined) {\n group!.toggle(props.value)\n return\n }\n\n if (props.selectable)\n emit('update:selected', !props.selected)\n}\n\nfunction requestRemove(): void {\n if (!isClosable.value)\n return\n\n emit('remove')\n if (inGroup.value && props.value !== undefined)\n group!.requestRemove(props.value)\n}\n\n/**\n * Крестик внутри виджета — не кнопка, поэтому его клик приходит сюда же и\n * разбирается по цели. Тот же приём у `GrTabs`: внутрь роли-виджета вложенная\n * кнопка запрещена (axe: `nested-interactive`), а `<button>` внутри `<button>`\n * невалиден и по контент-модели HTML.\n */\nfunction onRootClick(event: MouseEvent): void {\n if (isDisabled.value)\n return\n\n if (event.target instanceof Element && event.target.closest('[data-gr-chip-close]')) {\n requestRemove()\n return\n }\n\n toggle()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (isDisabled.value)\n return\n\n // Навигация принадлежит группе: состав знает только она.\n if (inGroup.value && group!.handleNavigationKeys(event))\n return\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n if (!isClosable.value)\n return\n event.preventDefault()\n requestRemove()\n }\n}\n\nif (group) {\n const unregister = group.register({\n value: () => props.value as GrChipValue,\n disabled: () => isDisabled.value,\n el: () => rootEl.value,\n })\n onBeforeUnmount(unregister)\n}\n\nconst removeEl = ref<HTMLButtonElement | null>(null)\n\ndefineExpose({\n focus: () => rootEl.value?.focus(),\n blur: () => rootEl.value?.blur(),\n /**\n * Кнопка снятия — цель roving-фокуса у родителя. Отдаётся элементом, а не\n * методом `focusRemove`: кольцу нужен сам узел, оно само решает, когда и\n * куда переносить фокус.\n */\n removeEl,\n})\n</script>\n\n<template>\n <component\n :is=\"isInteractive ? 'button' : 'span'\"\n ref=\"rootEl\"\n data-gr-chip\n :type=\"isInteractive ? 'button' : undefined\"\n :class=\"rootClass\"\n :role=\"chipRole\"\n :data-value=\"value\"\n :aria-label=\"ariaLabel\"\n :aria-checked=\"chipRole === 'radio' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-selected=\"chipRole === 'option' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-pressed=\"isInteractive && !chipRole ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :disabled=\"isInteractive && isDisabled ? true : undefined\"\n :aria-keyshortcuts=\"isInteractive && isClosable ? 'Delete' : undefined\"\n :tabindex=\"tabindex\"\n @click=\"isInteractive ? onRootClick($event) : undefined\"\n @keydown=\"isInteractive ? onRootKeydown($event) : undefined\"\n >\n <span v-if=\"$slots.icon\" data-gr-chip-icon :class=\"[chipIconClass, iconSizeClass]\">\n <slot name=\"icon\" />\n </span>\n\n <span data-gr-chip-label :class=\"chipLabelClass\">\n <slot>{{ label }}</slot>\n </span>\n\n <!--\n Крестик существует в двух видах, и различитель — роль самого чипа.\n Виджет: `<span aria-hidden>` вне таб-порядка, снятие идёт `Delete`/`Backspace`.\n Не виджет: настоящая кнопка со своей остановкой `Tab` и своим именем.\n -->\n <span\n v-if=\"isClosable && isInteractive\"\n data-gr-chip-close\n :class=\"[chipCloseClass, iconSizeClass]\"\n :title=\"removeTitle\"\n aria-hidden=\"true\"\n >\n <IconClose class=\"h-full w-full\" />\n </span>\n\n <button\n v-else-if=\"isClosable\"\n ref=\"removeEl\"\n data-gr-chip-close\n type=\"button\"\n :class=\"[chipCloseButtonClass, iconSizeClass]\"\n :aria-label=\"removeTitle\"\n :tabindex=\"removeTabindex\"\n @mousedown.prevent.stop\n @click.stop=\"requestRemove()\"\n >\n <IconClose class=\"h-full w-full\" />\n </button>\n </component>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrChip-CKqyzYcv.js","names":["$slots"],"sources":["../../../../src/components/GrChip/GrChip.vue","../../../../src/components/GrChip/GrChip.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, inject, onBeforeUnmount, ref, useAttrs } from 'vue'\n\nimport IconClose from '~icons/lucide/x'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport type { GrChipValue } from './grChipGroupContext'\n\nimport { warnRenamedProp } from '../shared/renamedProp'\nimport { GR_CHIP_GROUP_CONTEXT } from './grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from './grChipStyles'\nimport {\n chipCloseButtonClass,\n chipCloseClass,\n chipIconClass,\n chipIconSizeClassBySize,\n chipLabelClass,\n grChipClass,\n} from './grChipStyles'\n\n/**\n * Интерактивный тег: снимаемый, выбираемый, с иконкой.\n *\n * От `GrBadge` отличается не видом, а природой: бейдж — метка, чип — виджет.\n * Поэтому цвета и радиусы взяты у бейджа как есть (в одном ряду они обязаны\n * совпадать), а роль, клавиатура и размеры — свои.\n */\nexport interface GrChipProps {\n /** Значение чипа в группе. Вне `GrChipGroup` не используется. */\n value?: GrChipValue\n /**\n * Подпись. Нужна отдельно от слота: из неё собирается имя кнопки снятия —\n * «Убрать» на двадцати кнопках подряд не даёт выбрать нужную.\n */\n label?: string\n tone?: GrChipTone\n dark?: boolean\n size?: GrChipSize\n radius?: GrChipRadius\n /** Чип становится переключателем: `aria-pressed`, `Enter`/`Space`. */\n selectable?: boolean\n /** Состояние переключателя вне группы. Внутри группы значение ведёт группа. */\n selected?: boolean\n /** Крестик. Внутри виджета он не кнопка — см. блок про роли ниже. */\n closable?: boolean\n disabled?: boolean\n /** Доступное имя, когда подпись не объясняет назначения. */\n ariaLabel?: string\n /** Имя кнопки снятия целиком. Перебивает собранное из `label`. */\n removeLabel?: string\n /**\n * `tabindex` кнопки снятия — для чипа внутри поля ввода.\n *\n * Там таб-стоп принадлежит `<input>`, а ряд чипов ходит стрелками: у\n * `GrInputTag` кольцо оставляет ровно один `0`, у `GrAutocomplete` их нет\n * вовсе. Проп нужен потому, что кольцом управляет родитель — он знает и\n * порядок чипов, и что стоит за краем ряда.\n */\n removeTabindex?: number\n}\n\nexport interface GrChipEmits {\n (e: 'update:selected', value: boolean): void\n (e: 'remove'): void\n}\n\nconst props = withDefaults(defineProps<GrChipProps>(), {\n value: undefined,\n label: undefined,\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n tone: undefined,\n dark: undefined,\n size: undefined,\n radius: undefined,\n selectable: false,\n selected: false,\n closable: false,\n disabled: false,\n ariaLabel: undefined,\n removeLabel: undefined,\n removeTabindex: undefined,\n})\n\nconst emit = defineEmits<GrChipEmits>()\n\n// `variant` переименован в `tone`: незнакомый атрибут Vue сажает на корневой\n// узел, поэтому старое имя не роняет ни типы, ни рантайм — компонент молча\n// рисуется дефолтным тоном.\nwarnRenamedProp('GrChip', useAttrs(), { variant: 'tone' })\n\ndefineSlots<{\n /** Подпись чипа. Внутри выбираемого чипа — только фразовое содержимое. */\n default?: () => unknown\n /** Иконка перед подписью. */\n icon?: () => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst group = inject(GR_CHIP_GROUP_CONTEXT, null)\nconst rootEl = ref<HTMLElement | null>(null)\n\nconst inGroup = computed(() => group !== null && props.value !== undefined)\n\nconst isDisabled = computed(() => props.disabled || (group?.disabled.value ?? false))\nconst isReadonly = computed(() => group?.readonly.value ?? false)\n\n/**\n * Чип — виджет ровно тогда, когда по нему кликают.\n *\n * От этого зависит вся разметка: у виджета роль, `tabindex` и клавиатура, а\n * крестик внутри него перестаёт быть кнопкой.\n */\nconst isInteractive = computed(() => inGroup.value || props.selectable)\n\nconst isSelected = computed(() => {\n if (inGroup.value && props.value !== undefined)\n return group!.isSelected(props.value)\n return props.selected\n})\n\nconst isClosable = computed(() => {\n if (isReadonly.value || isDisabled.value)\n return false\n return props.closable || (inGroup.value ? group!.closable.value : false)\n})\n\n// Приоритет: локальный проп → значение группы → `GrConfigProvider` → дефолт.\n// Группа специфичнее конфига, поэтому её значение подаётся как «локальное».\nconst resolvedSize = useGrComponentSize<GrChipSize>(\n () => props.size ?? (inGroup.value ? group!.size.value : undefined),\n { component: 'GrChip' },\n)\nconst resolvedTone = useGrComponentProp(\n 'GrChip',\n 'tone',\n () => props.tone ?? (inGroup.value ? group!.tone.value : undefined),\n 'neutral',\n)\nconst resolvedRadius = useGrComponentProp(\n 'GrChip',\n 'radius',\n () => props.radius ?? (inGroup.value ? group!.radius.value : undefined),\n 'round',\n)\nconst resolvedDark = useGrComponentProp(\n 'GrChip',\n 'dark',\n () => props.dark ?? (inGroup.value ? group!.dark.value : undefined),\n false,\n)\n\nconst rootClass = computed(() => grChipClass({\n tone: resolvedTone.value,\n dark: resolvedDark.value,\n size: resolvedSize.value,\n radius: resolvedRadius.value,\n interactive: isInteractive.value && !isReadonly.value,\n selected: isSelected.value,\n disabled: isDisabled.value,\n}))\n\nconst iconSizeClass = computed(() => chipIconSizeClassBySize[resolvedSize.value])\n\nconst removeTitle = computed(() => {\n if (props.removeLabel)\n return props.removeLabel\n if (props.label)\n return t('gr.chip.removeNamed', 'Remove {label}', { label: props.label })\n return t('gr.chip.remove', 'Remove')\n})\n\n/**\n * Роль чипа задаёт группа, а не потребитель.\n *\n * Одиночный переключатель — кнопка с `aria-pressed`; в группе роль зависит от\n * множественности выбора: `radio` в одиночной (образец — `GrSegmented`),\n * `option` во множественной, где контейнер объявлен `listbox` c\n * `aria-multiselectable`.\n */\nconst chipRole = computed(() => {\n if (!inGroup.value)\n return undefined\n return group!.selection.value === 'single' ? 'radio' : 'option'\n})\n\nconst tabindex = computed(() => {\n if (!isInteractive.value)\n return undefined\n if (isDisabled.value)\n return -1\n if (!inGroup.value || props.value === undefined)\n return 0\n return group!.rovingValue.value === props.value ? 0 : -1\n})\n\nfunction toggle(): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (inGroup.value && props.value !== undefined) {\n group!.toggle(props.value)\n return\n }\n\n if (props.selectable)\n emit('update:selected', !props.selected)\n}\n\nfunction requestRemove(): void {\n if (!isClosable.value)\n return\n\n emit('remove')\n if (inGroup.value && props.value !== undefined)\n group!.requestRemove(props.value)\n}\n\n/**\n * Крестик внутри виджета — не кнопка, поэтому его клик приходит сюда же и\n * разбирается по цели. Тот же приём у `GrTabs`: внутрь роли-виджета вложенная\n * кнопка запрещена (axe: `nested-interactive`), а `<button>` внутри `<button>`\n * невалиден и по контент-модели HTML.\n */\nfunction onRootClick(event: MouseEvent): void {\n if (isDisabled.value)\n return\n\n if (event.target instanceof Element && event.target.closest('[data-gr-chip-close]')) {\n requestRemove()\n return\n }\n\n toggle()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (isDisabled.value)\n return\n\n // Навигация принадлежит группе: состав знает только она.\n if (inGroup.value && group!.handleNavigationKeys(event))\n return\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n if (!isClosable.value)\n return\n event.preventDefault()\n requestRemove()\n }\n}\n\nif (group) {\n const unregister = group.register({\n value: () => props.value as GrChipValue,\n disabled: () => isDisabled.value,\n el: () => rootEl.value,\n })\n onBeforeUnmount(unregister)\n}\n\nconst removeEl = ref<HTMLButtonElement | null>(null)\n\ndefineExpose({\n focus: () => rootEl.value?.focus(),\n blur: () => rootEl.value?.blur(),\n /**\n * Кнопка снятия — цель roving-фокуса у родителя. Отдаётся элементом, а не\n * методом `focusRemove`: кольцу нужен сам узел, оно само решает, когда и\n * куда переносить фокус.\n */\n removeEl,\n})\n</script>\n\n<template>\n <component\n :is=\"isInteractive ? 'button' : 'span'\"\n ref=\"rootEl\"\n data-gr-chip\n :type=\"isInteractive ? 'button' : undefined\"\n :class=\"rootClass\"\n :role=\"chipRole\"\n :data-value=\"value\"\n :aria-label=\"ariaLabel\"\n :aria-checked=\"chipRole === 'radio' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-selected=\"chipRole === 'option' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-pressed=\"isInteractive && !chipRole ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :disabled=\"isInteractive && isDisabled ? true : undefined\"\n :aria-keyshortcuts=\"isInteractive && isClosable ? 'Delete' : undefined\"\n :tabindex=\"tabindex\"\n @click=\"isInteractive ? onRootClick($event) : undefined\"\n @keydown=\"isInteractive ? onRootKeydown($event) : undefined\"\n >\n <span v-if=\"$slots.icon\" data-gr-chip-icon :class=\"[chipIconClass, iconSizeClass]\">\n <slot name=\"icon\" />\n </span>\n\n <span data-gr-chip-label :class=\"chipLabelClass\">\n <slot>{{ label }}</slot>\n </span>\n\n <!--\n Крестик существует в двух видах, и различитель — роль самого чипа.\n Виджет: `<span aria-hidden>` вне таб-порядка, снятие идёт `Delete`/`Backspace`.\n Не виджет: настоящая кнопка со своей остановкой `Tab` и своим именем.\n -->\n <span\n v-if=\"isClosable && isInteractive\"\n data-gr-chip-close\n :class=\"[chipCloseClass, iconSizeClass]\"\n :title=\"removeTitle\"\n aria-hidden=\"true\"\n >\n <IconClose class=\"h-full w-full\" />\n </span>\n\n <button\n v-else-if=\"isClosable\"\n ref=\"removeEl\"\n data-gr-chip-close\n type=\"button\"\n :class=\"[chipCloseButtonClass, iconSizeClass]\"\n :aria-label=\"removeTitle\"\n :tabindex=\"removeTabindex\"\n @mousedown.prevent.stop\n @click.stop=\"requestRemove()\"\n >\n <IconClose class=\"h-full w-full\" />\n </button>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, onBeforeUnmount, ref, useAttrs } from 'vue'\n\nimport IconClose from '~icons/lucide/x'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport type { GrChipValue } from './grChipGroupContext'\n\nimport { warnRenamedProp } from '../shared/renamedProp'\nimport { GR_CHIP_GROUP_CONTEXT } from './grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from './grChipStyles'\nimport {\n chipCloseButtonClass,\n chipCloseClass,\n chipIconClass,\n chipIconSizeClassBySize,\n chipLabelClass,\n grChipClass,\n} from './grChipStyles'\n\n/**\n * Интерактивный тег: снимаемый, выбираемый, с иконкой.\n *\n * От `GrBadge` отличается не видом, а природой: бейдж — метка, чип — виджет.\n * Поэтому цвета и радиусы взяты у бейджа как есть (в одном ряду они обязаны\n * совпадать), а роль, клавиатура и размеры — свои.\n */\nexport interface GrChipProps {\n /** Значение чипа в группе. Вне `GrChipGroup` не используется. */\n value?: GrChipValue\n /**\n * Подпись. Нужна отдельно от слота: из неё собирается имя кнопки снятия —\n * «Убрать» на двадцати кнопках подряд не даёт выбрать нужную.\n */\n label?: string\n tone?: GrChipTone\n dark?: boolean\n size?: GrChipSize\n radius?: GrChipRadius\n /** Чип становится переключателем: `aria-pressed`, `Enter`/`Space`. */\n selectable?: boolean\n /** Состояние переключателя вне группы. Внутри группы значение ведёт группа. */\n selected?: boolean\n /** Крестик. Внутри виджета он не кнопка — см. блок про роли ниже. */\n closable?: boolean\n disabled?: boolean\n /** Доступное имя, когда подпись не объясняет назначения. */\n ariaLabel?: string\n /** Имя кнопки снятия целиком. Перебивает собранное из `label`. */\n removeLabel?: string\n /**\n * `tabindex` кнопки снятия — для чипа внутри поля ввода.\n *\n * Там таб-стоп принадлежит `<input>`, а ряд чипов ходит стрелками: у\n * `GrInputTag` кольцо оставляет ровно один `0`, у `GrAutocomplete` их нет\n * вовсе. Проп нужен потому, что кольцом управляет родитель — он знает и\n * порядок чипов, и что стоит за краем ряда.\n */\n removeTabindex?: number\n}\n\nexport interface GrChipEmits {\n (e: 'update:selected', value: boolean): void\n (e: 'remove'): void\n}\n\nconst props = withDefaults(defineProps<GrChipProps>(), {\n value: undefined,\n label: undefined,\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем\n // компонент заглянет в `GrConfigProvider`.\n tone: undefined,\n dark: undefined,\n size: undefined,\n radius: undefined,\n selectable: false,\n selected: false,\n closable: false,\n disabled: false,\n ariaLabel: undefined,\n removeLabel: undefined,\n removeTabindex: undefined,\n})\n\nconst emit = defineEmits<GrChipEmits>()\n\n// `variant` переименован в `tone`: незнакомый атрибут Vue сажает на корневой\n// узел, поэтому старое имя не роняет ни типы, ни рантайм — компонент молча\n// рисуется дефолтным тоном.\nwarnRenamedProp('GrChip', useAttrs(), { variant: 'tone' })\n\ndefineSlots<{\n /** Подпись чипа. Внутри выбираемого чипа — только фразовое содержимое. */\n default?: () => unknown\n /** Иконка перед подписью. */\n icon?: () => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst group = inject(GR_CHIP_GROUP_CONTEXT, null)\nconst rootEl = ref<HTMLElement | null>(null)\n\nconst inGroup = computed(() => group !== null && props.value !== undefined)\n\nconst isDisabled = computed(() => props.disabled || (group?.disabled.value ?? false))\nconst isReadonly = computed(() => group?.readonly.value ?? false)\n\n/**\n * Чип — виджет ровно тогда, когда по нему кликают.\n *\n * От этого зависит вся разметка: у виджета роль, `tabindex` и клавиатура, а\n * крестик внутри него перестаёт быть кнопкой.\n */\nconst isInteractive = computed(() => inGroup.value || props.selectable)\n\nconst isSelected = computed(() => {\n if (inGroup.value && props.value !== undefined)\n return group!.isSelected(props.value)\n return props.selected\n})\n\nconst isClosable = computed(() => {\n if (isReadonly.value || isDisabled.value)\n return false\n return props.closable || (inGroup.value ? group!.closable.value : false)\n})\n\n// Приоритет: локальный проп → значение группы → `GrConfigProvider` → дефолт.\n// Группа специфичнее конфига, поэтому её значение подаётся как «локальное».\nconst resolvedSize = useGrComponentSize<GrChipSize>(\n () => props.size ?? (inGroup.value ? group!.size.value : undefined),\n { component: 'GrChip' },\n)\nconst resolvedTone = useGrComponentProp(\n 'GrChip',\n 'tone',\n () => props.tone ?? (inGroup.value ? group!.tone.value : undefined),\n 'neutral',\n)\nconst resolvedRadius = useGrComponentProp(\n 'GrChip',\n 'radius',\n () => props.radius ?? (inGroup.value ? group!.radius.value : undefined),\n 'round',\n)\nconst resolvedDark = useGrComponentProp(\n 'GrChip',\n 'dark',\n () => props.dark ?? (inGroup.value ? group!.dark.value : undefined),\n false,\n)\n\nconst rootClass = computed(() => grChipClass({\n tone: resolvedTone.value,\n dark: resolvedDark.value,\n size: resolvedSize.value,\n radius: resolvedRadius.value,\n interactive: isInteractive.value && !isReadonly.value,\n selected: isSelected.value,\n disabled: isDisabled.value,\n}))\n\nconst iconSizeClass = computed(() => chipIconSizeClassBySize[resolvedSize.value])\n\nconst removeTitle = computed(() => {\n if (props.removeLabel)\n return props.removeLabel\n if (props.label)\n return t('gr.chip.removeNamed', 'Remove {label}', { label: props.label })\n return t('gr.chip.remove', 'Remove')\n})\n\n/**\n * Роль чипа задаёт группа, а не потребитель.\n *\n * Одиночный переключатель — кнопка с `aria-pressed`; в группе роль зависит от\n * множественности выбора: `radio` в одиночной (образец — `GrSegmented`),\n * `option` во множественной, где контейнер объявлен `listbox` c\n * `aria-multiselectable`.\n */\nconst chipRole = computed(() => {\n if (!inGroup.value)\n return undefined\n return group!.selection.value === 'single' ? 'radio' : 'option'\n})\n\nconst tabindex = computed(() => {\n if (!isInteractive.value)\n return undefined\n if (isDisabled.value)\n return -1\n if (!inGroup.value || props.value === undefined)\n return 0\n return group!.rovingValue.value === props.value ? 0 : -1\n})\n\nfunction toggle(): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (inGroup.value && props.value !== undefined) {\n group!.toggle(props.value)\n return\n }\n\n if (props.selectable)\n emit('update:selected', !props.selected)\n}\n\nfunction requestRemove(): void {\n if (!isClosable.value)\n return\n\n emit('remove')\n if (inGroup.value && props.value !== undefined)\n group!.requestRemove(props.value)\n}\n\n/**\n * Крестик внутри виджета — не кнопка, поэтому его клик приходит сюда же и\n * разбирается по цели. Тот же приём у `GrTabs`: внутрь роли-виджета вложенная\n * кнопка запрещена (axe: `nested-interactive`), а `<button>` внутри `<button>`\n * невалиден и по контент-модели HTML.\n */\nfunction onRootClick(event: MouseEvent): void {\n if (isDisabled.value)\n return\n\n if (event.target instanceof Element && event.target.closest('[data-gr-chip-close]')) {\n requestRemove()\n return\n }\n\n toggle()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (isDisabled.value)\n return\n\n // Навигация принадлежит группе: состав знает только она.\n if (inGroup.value && group!.handleNavigationKeys(event))\n return\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n if (!isClosable.value)\n return\n event.preventDefault()\n requestRemove()\n }\n}\n\nif (group) {\n const unregister = group.register({\n value: () => props.value as GrChipValue,\n disabled: () => isDisabled.value,\n el: () => rootEl.value,\n })\n onBeforeUnmount(unregister)\n}\n\nconst removeEl = ref<HTMLButtonElement | null>(null)\n\ndefineExpose({\n focus: () => rootEl.value?.focus(),\n blur: () => rootEl.value?.blur(),\n /**\n * Кнопка снятия — цель roving-фокуса у родителя. Отдаётся элементом, а не\n * методом `focusRemove`: кольцу нужен сам узел, оно само решает, когда и\n * куда переносить фокус.\n */\n removeEl,\n})\n</script>\n\n<template>\n <component\n :is=\"isInteractive ? 'button' : 'span'\"\n ref=\"rootEl\"\n data-gr-chip\n :type=\"isInteractive ? 'button' : undefined\"\n :class=\"rootClass\"\n :role=\"chipRole\"\n :data-value=\"value\"\n :aria-label=\"ariaLabel\"\n :aria-checked=\"chipRole === 'radio' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-selected=\"chipRole === 'option' ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-pressed=\"isInteractive && !chipRole ? (isSelected ? 'true' : 'false') : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :disabled=\"isInteractive && isDisabled ? true : undefined\"\n :aria-keyshortcuts=\"isInteractive && isClosable ? 'Delete' : undefined\"\n :tabindex=\"tabindex\"\n @click=\"isInteractive ? onRootClick($event) : undefined\"\n @keydown=\"isInteractive ? onRootKeydown($event) : undefined\"\n >\n <span v-if=\"$slots.icon\" data-gr-chip-icon :class=\"[chipIconClass, iconSizeClass]\">\n <slot name=\"icon\" />\n </span>\n\n <span data-gr-chip-label :class=\"chipLabelClass\">\n <slot>{{ label }}</slot>\n </span>\n\n <!--\n Крестик существует в двух видах, и различитель — роль самого чипа.\n Виджет: `<span aria-hidden>` вне таб-порядка, снятие идёт `Delete`/`Backspace`.\n Не виджет: настоящая кнопка со своей остановкой `Tab` и своим именем.\n -->\n <span\n v-if=\"isClosable && isInteractive\"\n data-gr-chip-close\n :class=\"[chipCloseClass, iconSizeClass]\"\n :title=\"removeTitle\"\n aria-hidden=\"true\"\n >\n <IconClose class=\"h-full w-full\" />\n </span>\n\n <button\n v-else-if=\"isClosable\"\n ref=\"removeEl\"\n data-gr-chip-close\n type=\"button\"\n :class=\"[chipCloseButtonClass, iconSizeClass]\"\n :aria-label=\"removeTitle\"\n :tabindex=\"removeTabindex\"\n @mousedown.prevent.stop\n @click.stop=\"requestRemove()\"\n >\n <IconClose class=\"h-full w-full\" />\n </button>\n </component>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrChip_default } from "./chunks/GrChip-
|
|
1
|
+
import { t as GrChip_default } from "./chunks/GrChip-CKqyzYcv.js";
|
|
2
2
|
import { n as grChipSafelist, t as grChipConfig } from "../../chunks/config-2vrOFn2f.js";
|
|
3
3
|
export { GrChip_default as GrChip, GrChip_default as default, grChipConfig, grChipSafelist };
|
package/dist/components/GrChipGroup/chunks/{GrChipGroup-C78Vcwos.js → GrChipGroup-dDGwnC04.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as useGrComponentSize } from "../../../chunks/context-
|
|
1
|
+
import { a as useGrComponentSize } from "../../../chunks/context-CPMRfwVr.js";
|
|
2
2
|
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";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrChipGroup-C78Vcwos.js","names":[],"sources":["../../../../src/components/GrChipGroup/GrChipGroup.vue","../../../../src/components/GrChipGroup/GrChipGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, provide, ref } from 'vue'\n\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\n\nimport type { GrChipEntry, GrChipSelection, GrChipValue } from '../GrChip/grChipGroupContext'\nimport { GR_CHIP_GROUP_CONTEXT } from '../GrChip/grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from '../GrChip/grChipStyles'\n\nimport { chipGroupRootClass } from './grChipGroupStyles'\n\n/**\n * GrChipGroup — набор выбираемых чипов: фильтры, теги записи, быстрый выбор.\n *\n * Составной виджет: одна остановка `Tab`, внутрь попадают стрелками\n * (roving tabindex). Роль зависит от множественности выбора — `radiogroup`\n * в одиночном, `listbox` с `aria-multiselectable` во множественном; чипы\n * получают парную роль через контекст и сами её не выбирают.\n *\n * Состав группа не рисует: чипы приходят слотом, потому что у каждого своя\n * подпись и иконка. Отсюда же и `remove` — группа его ретранслирует, а снимает\n * чип потребитель, у которого лежит массив.\n */\nexport interface GrChipGroupProps {\n /** Одиночный выбор — значение, множественный — массив. */\n modelValue?: GrChipValue | GrChipValue[] | null\n selection?: GrChipSelection\n /** Имя для нативной формы. Множественный выбор отдаёт по полю на значение. */\n name?: string\n disabled?: boolean\n /** Выбор видно, но он не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n /** Крестик у всех чипов набора. Точечно перебивается пропом самого чипа. */\n closable?: boolean\n size?: GrChipSize\n tone?: GrChipTone\n radius?: GrChipRadius\n dark?: boolean\n ariaLabel?: string\n}\n\nexport interface GrChipGroupEmits {\n (e: 'update:modelValue', value: GrChipValue | GrChipValue[] | null): void\n (e: 'change', value: GrChipValue | GrChipValue[] | null): void\n (e: 'remove', value: GrChipValue): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrChipGroupProps>(), {\n modelValue: undefined,\n selection: 'multiple',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n closable: false,\n // Оформление разрешается в самих чипах: группа отдаёт им своё значение как\n // «локальное», и там же оно спорит с `GrConfigProvider`.\n size: undefined,\n tone: undefined,\n radius: undefined,\n dark: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrChipGroupEmits>()\n\ndefineSlots<{\n /** Чипы набора. */\n default?: () => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize<GrChipSize>(() => props.size, { component: 'GrChipGroup' })\n\n// Группа — не labelable-элемент, поэтому имя приходит через `aria-labelledby`\n// на подпись поля, а не через `<label for>`.\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,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst isMultiple = computed(() => props.selection === 'multiple')\n\nconst selectedValues = computed<GrChipValue[]>(() => {\n if (props.modelValue === undefined || props.modelValue === null)\n return []\n return Array.isArray(props.modelValue) ? [...props.modelValue] : [props.modelValue]\n})\n\nfunction isSelected(value: GrChipValue): boolean {\n return selectedValues.value.includes(value)\n}\n\nfunction commit(next: GrChipValue | GrChipValue[] | null): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\n/**\n * В одиночном режиме повторный выбор снимает отметку.\n *\n * Так ведут себя фильтры: набор без выбранного значения осмыслен («любой»), и\n * отменить выбор иначе было бы нечем — в отличие от `radiogroup` формы, где\n * пустое значение обычно запрещено.\n */\nfunction toggle(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (!isMultiple.value) {\n commit(isSelected(value) ? null : value)\n return\n }\n\n const next = selectedValues.value.filter(item => item !== value)\n if (next.length === selectedValues.value.length)\n next.push(value)\n commit(next)\n}\n\nfunction requestRemove(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n emit('remove', value)\n}\n\nconst entries = ref<GrChipEntry[]>([])\n\nfunction register(entry: GrChipEntry): () => void {\n entries.value.push(entry)\n return () => {\n const index = entries.value.indexOf(entry)\n if (index >= 0)\n entries.value.splice(index, 1)\n }\n}\n\nfunction entryOf(value: GrChipValue): GrChipEntry | undefined {\n return entries.value.find(entry => entry.value() === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси — чипы переносятся на новую строку, и «вниз»\n * означает следующий чип так же, как «вправо».\n *\n * Стрелка двигает только фокус, даже в одиночном режиме: у чипов есть второе\n * действие (снятие по `Delete`), и переносить выбор вместе с фокусом значило бы\n * менять модель при попытке дойти до нужного чипа. Тем же рассуждением живёт\n * `GrTabs` с `activationMode=\"manual\"`.\n */\nconst roving = useRovingFocus<GrChipValue>({\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 initialKey: () => {\n const first = selectedValues.value.find(value => entryOf(value) && !entryOf(value)!.disabled())\n return first\n },\n // Снятие чипа перерисовывает набор: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\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\nfunction rovingElement(): HTMLElement | null {\n const value = roving.rovingKey.value\n return value === undefined ? null : entryOf(value)?.el() ?? null\n}\n\nprovide(GR_CHIP_GROUP_CONTEXT, {\n selection: computed(() => props.selection),\n isSelected,\n toggle,\n requestRemove,\n disabled: isDisabled,\n readonly: isReadonly,\n invalid: isInvalid,\n closable: computed(() => props.closable),\n size: resolvedSize,\n tone: computed(() => props.tone),\n radius: computed(() => props.radius),\n dark: computed(() => props.dark),\n register,\n rovingValue: roving.rovingKey,\n handleNavigationKeys: roving.handleNavigationKeys,\n})\n\ndefineExpose({\n focus: () => rovingElement()?.focus(),\n blur: () => rovingElement()?.blur(),\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-chip-group\n :class=\"chipGroupRootClass\"\n :role=\"isMultiple ? 'listbox' : 'radiogroup'\"\n :aria-multiselectable=\"isMultiple ? 'true' : undefined\"\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 <!--\n Значение уходит в форму скрытыми полями рядом с чипами, а не внутри них:\n внутрь роли-виджета нельзя вкладывать интерактивное, и скрытый `<input>`\n исключением не является.\n -->\n <input\n v-for=\"value in (name ? selectedValues : [])\"\n :key=\"`hidden-${String(value)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(value)\"\n >\n\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, provide, ref } from 'vue'\n\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\n\nimport type { GrChipEntry, GrChipSelection, GrChipValue } from '../GrChip/grChipGroupContext'\nimport { GR_CHIP_GROUP_CONTEXT } from '../GrChip/grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from '../GrChip/grChipStyles'\n\nimport { chipGroupRootClass } from './grChipGroupStyles'\n\n/**\n * GrChipGroup — набор выбираемых чипов: фильтры, теги записи, быстрый выбор.\n *\n * Составной виджет: одна остановка `Tab`, внутрь попадают стрелками\n * (roving tabindex). Роль зависит от множественности выбора — `radiogroup`\n * в одиночном, `listbox` с `aria-multiselectable` во множественном; чипы\n * получают парную роль через контекст и сами её не выбирают.\n *\n * Состав группа не рисует: чипы приходят слотом, потому что у каждого своя\n * подпись и иконка. Отсюда же и `remove` — группа его ретранслирует, а снимает\n * чип потребитель, у которого лежит массив.\n */\nexport interface GrChipGroupProps {\n /** Одиночный выбор — значение, множественный — массив. */\n modelValue?: GrChipValue | GrChipValue[] | null\n selection?: GrChipSelection\n /** Имя для нативной формы. Множественный выбор отдаёт по полю на значение. */\n name?: string\n disabled?: boolean\n /** Выбор видно, но он не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n /** Крестик у всех чипов набора. Точечно перебивается пропом самого чипа. */\n closable?: boolean\n size?: GrChipSize\n tone?: GrChipTone\n radius?: GrChipRadius\n dark?: boolean\n ariaLabel?: string\n}\n\nexport interface GrChipGroupEmits {\n (e: 'update:modelValue', value: GrChipValue | GrChipValue[] | null): void\n (e: 'change', value: GrChipValue | GrChipValue[] | null): void\n (e: 'remove', value: GrChipValue): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrChipGroupProps>(), {\n modelValue: undefined,\n selection: 'multiple',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n closable: false,\n // Оформление разрешается в самих чипах: группа отдаёт им своё значение как\n // «локальное», и там же оно спорит с `GrConfigProvider`.\n size: undefined,\n tone: undefined,\n radius: undefined,\n dark: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrChipGroupEmits>()\n\ndefineSlots<{\n /** Чипы набора. */\n default?: () => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize<GrChipSize>(() => props.size, { component: 'GrChipGroup' })\n\n// Группа — не labelable-элемент, поэтому имя приходит через `aria-labelledby`\n// на подпись поля, а не через `<label for>`.\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,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst isMultiple = computed(() => props.selection === 'multiple')\n\nconst selectedValues = computed<GrChipValue[]>(() => {\n if (props.modelValue === undefined || props.modelValue === null)\n return []\n return Array.isArray(props.modelValue) ? [...props.modelValue] : [props.modelValue]\n})\n\nfunction isSelected(value: GrChipValue): boolean {\n return selectedValues.value.includes(value)\n}\n\nfunction commit(next: GrChipValue | GrChipValue[] | null): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\n/**\n * В одиночном режиме повторный выбор снимает отметку.\n *\n * Так ведут себя фильтры: набор без выбранного значения осмыслен («любой»), и\n * отменить выбор иначе было бы нечем — в отличие от `radiogroup` формы, где\n * пустое значение обычно запрещено.\n */\nfunction toggle(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (!isMultiple.value) {\n commit(isSelected(value) ? null : value)\n return\n }\n\n const next = selectedValues.value.filter(item => item !== value)\n if (next.length === selectedValues.value.length)\n next.push(value)\n commit(next)\n}\n\nfunction requestRemove(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n emit('remove', value)\n}\n\nconst entries = ref<GrChipEntry[]>([])\n\nfunction register(entry: GrChipEntry): () => void {\n entries.value.push(entry)\n return () => {\n const index = entries.value.indexOf(entry)\n if (index >= 0)\n entries.value.splice(index, 1)\n }\n}\n\nfunction entryOf(value: GrChipValue): GrChipEntry | undefined {\n return entries.value.find(entry => entry.value() === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси — чипы переносятся на новую строку, и «вниз»\n * означает следующий чип так же, как «вправо».\n *\n * Стрелка двигает только фокус, даже в одиночном режиме: у чипов есть второе\n * действие (снятие по `Delete`), и переносить выбор вместе с фокусом значило бы\n * менять модель при попытке дойти до нужного чипа. Тем же рассуждением живёт\n * `GrTabs` с `activationMode=\"manual\"`.\n */\nconst roving = useRovingFocus<GrChipValue>({\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 initialKey: () => {\n const first = selectedValues.value.find(value => entryOf(value) && !entryOf(value)!.disabled())\n return first\n },\n // Снятие чипа перерисовывает набор: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\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\nfunction rovingElement(): HTMLElement | null {\n const value = roving.rovingKey.value\n return value === undefined ? null : entryOf(value)?.el() ?? null\n}\n\nprovide(GR_CHIP_GROUP_CONTEXT, {\n selection: computed(() => props.selection),\n isSelected,\n toggle,\n requestRemove,\n disabled: isDisabled,\n readonly: isReadonly,\n invalid: isInvalid,\n closable: computed(() => props.closable),\n size: resolvedSize,\n tone: computed(() => props.tone),\n radius: computed(() => props.radius),\n dark: computed(() => props.dark),\n register,\n rovingValue: roving.rovingKey,\n handleNavigationKeys: roving.handleNavigationKeys,\n})\n\ndefineExpose({\n focus: () => rovingElement()?.focus(),\n blur: () => rovingElement()?.blur(),\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-chip-group\n :class=\"chipGroupRootClass\"\n :role=\"isMultiple ? 'listbox' : 'radiogroup'\"\n :aria-multiselectable=\"isMultiple ? 'true' : undefined\"\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 <!--\n Значение уходит в форму скрытыми полями рядом с чипами, а не внутри них:\n внутрь роли-виджета нельзя вкладывать интерактивное, и скрытый `<input>`\n исключением не является.\n -->\n <input\n v-for=\"value in (name ? selectedValues : [])\"\n :key=\"`hidden-${String(value)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(value)\"\n >\n\n <slot />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuDA,MAAM,QAAQ;EAkBd,MAAM,OAAO;EAOb,MAAM,eAAe,yBAAqC,MAAM,MAAM,EAAE,WAAW,cAAc,CAAC;EAIlG,MAAM,QAAQ,sBAAsB;EACpC,MAAM,UAAU,eAAe,OAAO,GAAG,KAAK;EAC9C,MAAM,cAAc,eAAe,OAAO,cAAc,KAAK;EAC7D,MAAM,aAAa,eAAgB,MAAM,YAAY,KAAA,IAAY,OAAO,QAAQ,KAAM;EACtF,MAAM,EACJ,UAAU,YACV,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;EAEhC,MAAM,aAAa,eAAe,MAAM,cAAc,UAAU;EAEhE,MAAM,iBAAiB,eAA8B;GACnD,IAAI,MAAM,eAAe,KAAA,KAAa,MAAM,eAAe,MACzD,OAAO,CAAC;GACV,OAAO,MAAM,QAAQ,MAAM,UAAU,IAAI,CAAC,GAAG,MAAM,UAAU,IAAI,CAAC,MAAM,UAAU;EACpF,CAAC;EAED,SAAS,WAAW,OAA6B;GAC/C,OAAO,eAAe,MAAM,SAAS,KAAK;EAC5C;EAEA,SAAS,OAAO,MAAgD;GAC9D,KAAK,qBAAqB,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;;;;;;;;EASA,SAAS,OAAO,OAA0B;GACxC,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,IAAI,CAAC,WAAW,OAAO;IACrB,OAAO,WAAW,KAAK,IAAI,OAAO,KAAK;IACvC;GACF;GAEA,MAAM,OAAO,eAAe,MAAM,QAAO,SAAQ,SAAS,KAAK;GAC/D,IAAI,KAAK,WAAW,eAAe,MAAM,QACvC,KAAK,KAAK,KAAK;GACjB,OAAO,IAAI;EACb;EAEA,SAAS,cAAc,OAA0B;GAC/C,IAAI,WAAW,SAAS,WAAW,OACjC;GACF,KAAK,UAAU,KAAK;EACtB;EAEA,MAAM,UAAU,IAAmB,CAAC,CAAC;EAErC,SAAS,SAAS,OAAgC;GAChD,QAAQ,MAAM,KAAK,KAAK;GACxB,aAAa;IACX,MAAM,QAAQ,QAAQ,MAAM,QAAQ,KAAK;IACzC,IAAI,SAAS,GACX,QAAQ,MAAM,OAAO,OAAO,CAAC;GACjC;EACF;EAEA,SAAS,QAAQ,OAA6C;GAC5D,OAAO,QAAQ,MAAM,MAAK,UAAS,MAAM,MAAM,MAAM,KAAK;EAC5D;;;;;;;;;;EAWA,MAAM,SAAS,eAA4B;GACzC,aAAa,QAAQ,MAAM,KAAI,UAAS,MAAM,MAAM,CAAC;GACrD,aAAY,UAAS,QAAQ,KAAK,CAAC,EAAE,GAAG,KAAK;GAC7C,aAAY,UAAS,QAAQ,KAAK,CAAC,EAAE,SAAS,KAAK;GACnD,mBAAmB;GACnB,oBAAoB;GACpB,kBAAkB;IAEhB,OADc,eAAe,MAAM,MAAK,UAAS,QAAQ,KAAK,KAAK,CAAC,QAAQ,KAAK,CAAC,CAAE,SAAS,CACtF;GACT;GAGA,mBAAmB,SAAS;EAC9B,CAAC;EAED,MAAM,SAAS,IAAwB,IAAI;EAI3C,MAAM,EAAE,WAAW,eAAe,eAAe,QAAQ;GACvD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;EACpC,CAAC;EAED,SAAS,gBAAoC;GAC3C,MAAM,QAAQ,OAAO,UAAU;GAC/B,OAAO,UAAU,KAAA,IAAY,OAAO,QAAQ,KAAK,CAAC,EAAE,GAAG,KAAK;EAC9D;EAEA,QAAQ,uBAAuB;GAC7B,WAAW,eAAe,MAAM,SAAS;GACzC;GACA;GACA;GACA,UAAU;GACV,UAAU;GACV,SAAS;GACT,UAAU,eAAe,MAAM,QAAQ;GACvC,MAAM;GACN,MAAM,eAAe,MAAM,IAAI;GAC/B,QAAQ,eAAe,MAAM,MAAM;GACnC,MAAM,eAAe,MAAM,IAAI;GAC/B;GACA,aAAa,OAAO;GACpB,sBAAsB,OAAO;EAC/B,CAAC;EAED,SAAa;GACX,aAAa,cAAc,CAAC,EAAE,MAAM;GACpC,YAAY,cAAc,CAAC,EAAE,KAAK;EACpC,CAAC;;uBAIC,mBA+BM,OAAA;IA9BH,IAAI,QAAA;aACD;IAAJ,KAAI;IACJ,sBAAA;IACC,OAAK,eAAE,MAAA,kBAAA,CAAkB;IACzB,MAAM,WAAA,QAAU,YAAA;IAChB,wBAAsB,WAAA,QAAU,SAAY,KAAA;IAC5C,cAAY,QAAA;IACZ,mBAAiB,WAAA;IACjB,oBAAkB,YAAA;IAClB,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;IACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,WAAO,OAAA,OAAA,OAAA,MAAA,GAAA,SAAE,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACT,YAAQ,OAAA,OAAA,OAAA,MAAA,GAAA,SAAE,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;yBAOX,mBAMC,UAAA,MAAA,WALkB,QAAA,OAAO,eAAA,QAAc,CAAA,IAA/B,UAAK;wBADd,mBAMC,SAAA;KAJE,KAAG,UAAY,OAAO,KAAK;KAC5B,MAAK;KACJ,MAAM,QAAA;KACN,OAAO,OAAO,KAAK;;cAGtB,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA"}
|
|
1
|
+
{"version":3,"file":"GrChipGroup-dDGwnC04.js","names":[],"sources":["../../../../src/components/GrChipGroup/GrChipGroup.vue","../../../../src/components/GrChipGroup/GrChipGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, provide, ref } from 'vue'\n\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\n\nimport type { GrChipEntry, GrChipSelection, GrChipValue } from '../GrChip/grChipGroupContext'\nimport { GR_CHIP_GROUP_CONTEXT } from '../GrChip/grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from '../GrChip/grChipStyles'\n\nimport { chipGroupRootClass } from './grChipGroupStyles'\n\n/**\n * GrChipGroup — набор выбираемых чипов: фильтры, теги записи, быстрый выбор.\n *\n * Составной виджет: одна остановка `Tab`, внутрь попадают стрелками\n * (roving tabindex). Роль зависит от множественности выбора — `radiogroup`\n * в одиночном, `listbox` с `aria-multiselectable` во множественном; чипы\n * получают парную роль через контекст и сами её не выбирают.\n *\n * Состав группа не рисует: чипы приходят слотом, потому что у каждого своя\n * подпись и иконка. Отсюда же и `remove` — группа его ретранслирует, а снимает\n * чип потребитель, у которого лежит массив.\n */\nexport interface GrChipGroupProps {\n /** Одиночный выбор — значение, множественный — массив. */\n modelValue?: GrChipValue | GrChipValue[] | null\n selection?: GrChipSelection\n /** Имя для нативной формы. Множественный выбор отдаёт по полю на значение. */\n name?: string\n disabled?: boolean\n /** Выбор видно, но он не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n /** Крестик у всех чипов набора. Точечно перебивается пропом самого чипа. */\n closable?: boolean\n size?: GrChipSize\n tone?: GrChipTone\n radius?: GrChipRadius\n dark?: boolean\n ariaLabel?: string\n}\n\nexport interface GrChipGroupEmits {\n (e: 'update:modelValue', value: GrChipValue | GrChipValue[] | null): void\n (e: 'change', value: GrChipValue | GrChipValue[] | null): void\n (e: 'remove', value: GrChipValue): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrChipGroupProps>(), {\n modelValue: undefined,\n selection: 'multiple',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n closable: false,\n // Оформление разрешается в самих чипах: группа отдаёт им своё значение как\n // «локальное», и там же оно спорит с `GrConfigProvider`.\n size: undefined,\n tone: undefined,\n radius: undefined,\n dark: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrChipGroupEmits>()\n\ndefineSlots<{\n /** Чипы набора. */\n default?: () => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize<GrChipSize>(() => props.size, { component: 'GrChipGroup' })\n\n// Группа — не labelable-элемент, поэтому имя приходит через `aria-labelledby`\n// на подпись поля, а не через `<label for>`.\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,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst isMultiple = computed(() => props.selection === 'multiple')\n\nconst selectedValues = computed<GrChipValue[]>(() => {\n if (props.modelValue === undefined || props.modelValue === null)\n return []\n return Array.isArray(props.modelValue) ? [...props.modelValue] : [props.modelValue]\n})\n\nfunction isSelected(value: GrChipValue): boolean {\n return selectedValues.value.includes(value)\n}\n\nfunction commit(next: GrChipValue | GrChipValue[] | null): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\n/**\n * В одиночном режиме повторный выбор снимает отметку.\n *\n * Так ведут себя фильтры: набор без выбранного значения осмыслен («любой»), и\n * отменить выбор иначе было бы нечем — в отличие от `radiogroup` формы, где\n * пустое значение обычно запрещено.\n */\nfunction toggle(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (!isMultiple.value) {\n commit(isSelected(value) ? null : value)\n return\n }\n\n const next = selectedValues.value.filter(item => item !== value)\n if (next.length === selectedValues.value.length)\n next.push(value)\n commit(next)\n}\n\nfunction requestRemove(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n emit('remove', value)\n}\n\nconst entries = ref<GrChipEntry[]>([])\n\nfunction register(entry: GrChipEntry): () => void {\n entries.value.push(entry)\n return () => {\n const index = entries.value.indexOf(entry)\n if (index >= 0)\n entries.value.splice(index, 1)\n }\n}\n\nfunction entryOf(value: GrChipValue): GrChipEntry | undefined {\n return entries.value.find(entry => entry.value() === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси — чипы переносятся на новую строку, и «вниз»\n * означает следующий чип так же, как «вправо».\n *\n * Стрелка двигает только фокус, даже в одиночном режиме: у чипов есть второе\n * действие (снятие по `Delete`), и переносить выбор вместе с фокусом значило бы\n * менять модель при попытке дойти до нужного чипа. Тем же рассуждением живёт\n * `GrTabs` с `activationMode=\"manual\"`.\n */\nconst roving = useRovingFocus<GrChipValue>({\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 initialKey: () => {\n const first = selectedValues.value.find(value => entryOf(value) && !entryOf(value)!.disabled())\n return first\n },\n // Снятие чипа перерисовывает набор: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\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\nfunction rovingElement(): HTMLElement | null {\n const value = roving.rovingKey.value\n return value === undefined ? null : entryOf(value)?.el() ?? null\n}\n\nprovide(GR_CHIP_GROUP_CONTEXT, {\n selection: computed(() => props.selection),\n isSelected,\n toggle,\n requestRemove,\n disabled: isDisabled,\n readonly: isReadonly,\n invalid: isInvalid,\n closable: computed(() => props.closable),\n size: resolvedSize,\n tone: computed(() => props.tone),\n radius: computed(() => props.radius),\n dark: computed(() => props.dark),\n register,\n rovingValue: roving.rovingKey,\n handleNavigationKeys: roving.handleNavigationKeys,\n})\n\ndefineExpose({\n focus: () => rovingElement()?.focus(),\n blur: () => rovingElement()?.blur(),\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-chip-group\n :class=\"chipGroupRootClass\"\n :role=\"isMultiple ? 'listbox' : 'radiogroup'\"\n :aria-multiselectable=\"isMultiple ? 'true' : undefined\"\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 <!--\n Значение уходит в форму скрытыми полями рядом с чипами, а не внутри них:\n внутрь роли-виджета нельзя вкладывать интерактивное, и скрытый `<input>`\n исключением не является.\n -->\n <input\n v-for=\"value in (name ? selectedValues : [])\"\n :key=\"`hidden-${String(value)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(value)\"\n >\n\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, provide, ref } from 'vue'\n\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\n\nimport type { GrChipEntry, GrChipSelection, GrChipValue } from '../GrChip/grChipGroupContext'\nimport { GR_CHIP_GROUP_CONTEXT } from '../GrChip/grChipGroupContext'\nimport type { GrChipRadius, GrChipSize, GrChipTone } from '../GrChip/grChipStyles'\n\nimport { chipGroupRootClass } from './grChipGroupStyles'\n\n/**\n * GrChipGroup — набор выбираемых чипов: фильтры, теги записи, быстрый выбор.\n *\n * Составной виджет: одна остановка `Tab`, внутрь попадают стрелками\n * (roving tabindex). Роль зависит от множественности выбора — `radiogroup`\n * в одиночном, `listbox` с `aria-multiselectable` во множественном; чипы\n * получают парную роль через контекст и сами её не выбирают.\n *\n * Состав группа не рисует: чипы приходят слотом, потому что у каждого своя\n * подпись и иконка. Отсюда же и `remove` — группа его ретранслирует, а снимает\n * чип потребитель, у которого лежит массив.\n */\nexport interface GrChipGroupProps {\n /** Одиночный выбор — значение, множественный — массив. */\n modelValue?: GrChipValue | GrChipValue[] | null\n selection?: GrChipSelection\n /** Имя для нативной формы. Множественный выбор отдаёт по полю на значение. */\n name?: string\n disabled?: boolean\n /** Выбор видно, но он не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n /** Крестик у всех чипов набора. Точечно перебивается пропом самого чипа. */\n closable?: boolean\n size?: GrChipSize\n tone?: GrChipTone\n radius?: GrChipRadius\n dark?: boolean\n ariaLabel?: string\n}\n\nexport interface GrChipGroupEmits {\n (e: 'update:modelValue', value: GrChipValue | GrChipValue[] | null): void\n (e: 'change', value: GrChipValue | GrChipValue[] | null): void\n (e: 'remove', value: GrChipValue): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrChipGroupProps>(), {\n modelValue: undefined,\n selection: 'multiple',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n closable: false,\n // Оформление разрешается в самих чипах: группа отдаёт им своё значение как\n // «локальное», и там же оно спорит с `GrConfigProvider`.\n size: undefined,\n tone: undefined,\n radius: undefined,\n dark: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrChipGroupEmits>()\n\ndefineSlots<{\n /** Чипы набора. */\n default?: () => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize<GrChipSize>(() => props.size, { component: 'GrChipGroup' })\n\n// Группа — не labelable-элемент, поэтому имя приходит через `aria-labelledby`\n// на подпись поля, а не через `<label for>`.\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,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst isMultiple = computed(() => props.selection === 'multiple')\n\nconst selectedValues = computed<GrChipValue[]>(() => {\n if (props.modelValue === undefined || props.modelValue === null)\n return []\n return Array.isArray(props.modelValue) ? [...props.modelValue] : [props.modelValue]\n})\n\nfunction isSelected(value: GrChipValue): boolean {\n return selectedValues.value.includes(value)\n}\n\nfunction commit(next: GrChipValue | GrChipValue[] | null): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\n/**\n * В одиночном режиме повторный выбор снимает отметку.\n *\n * Так ведут себя фильтры: набор без выбранного значения осмыслен («любой»), и\n * отменить выбор иначе было бы нечем — в отличие от `radiogroup` формы, где\n * пустое значение обычно запрещено.\n */\nfunction toggle(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (!isMultiple.value) {\n commit(isSelected(value) ? null : value)\n return\n }\n\n const next = selectedValues.value.filter(item => item !== value)\n if (next.length === selectedValues.value.length)\n next.push(value)\n commit(next)\n}\n\nfunction requestRemove(value: GrChipValue): void {\n if (isDisabled.value || isReadonly.value)\n return\n emit('remove', value)\n}\n\nconst entries = ref<GrChipEntry[]>([])\n\nfunction register(entry: GrChipEntry): () => void {\n entries.value.push(entry)\n return () => {\n const index = entries.value.indexOf(entry)\n if (index >= 0)\n entries.value.splice(index, 1)\n }\n}\n\nfunction entryOf(value: GrChipValue): GrChipEntry | undefined {\n return entries.value.find(entry => entry.value() === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси — чипы переносятся на новую строку, и «вниз»\n * означает следующий чип так же, как «вправо».\n *\n * Стрелка двигает только фокус, даже в одиночном режиме: у чипов есть второе\n * действие (снятие по `Delete`), и переносить выбор вместе с фокусом значило бы\n * менять модель при попытке дойти до нужного чипа. Тем же рассуждением живёт\n * `GrTabs` с `activationMode=\"manual\"`.\n */\nconst roving = useRovingFocus<GrChipValue>({\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 initialKey: () => {\n const first = selectedValues.value.find(value => entryOf(value) && !entryOf(value)!.disabled())\n return first\n },\n // Снятие чипа перерисовывает набор: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\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\nfunction rovingElement(): HTMLElement | null {\n const value = roving.rovingKey.value\n return value === undefined ? null : entryOf(value)?.el() ?? null\n}\n\nprovide(GR_CHIP_GROUP_CONTEXT, {\n selection: computed(() => props.selection),\n isSelected,\n toggle,\n requestRemove,\n disabled: isDisabled,\n readonly: isReadonly,\n invalid: isInvalid,\n closable: computed(() => props.closable),\n size: resolvedSize,\n tone: computed(() => props.tone),\n radius: computed(() => props.radius),\n dark: computed(() => props.dark),\n register,\n rovingValue: roving.rovingKey,\n handleNavigationKeys: roving.handleNavigationKeys,\n})\n\ndefineExpose({\n focus: () => rovingElement()?.focus(),\n blur: () => rovingElement()?.blur(),\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-chip-group\n :class=\"chipGroupRootClass\"\n :role=\"isMultiple ? 'listbox' : 'radiogroup'\"\n :aria-multiselectable=\"isMultiple ? 'true' : undefined\"\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 <!--\n Значение уходит в форму скрытыми полями рядом с чипами, а не внутри них:\n внутрь роли-виджета нельзя вкладывать интерактивное, и скрытый `<input>`\n исключением не является.\n -->\n <input\n v-for=\"value in (name ? selectedValues : [])\"\n :key=\"`hidden-${String(value)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(value)\"\n >\n\n <slot />\n </div>\n</template>\n"],"mappings":"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"}
|