@feugene/granularity 0.49.0 → 0.50.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/README.md +3 -3
- package/dist/chunks/chevron-up-BhW6hi8L.js +23 -0
- package/dist/chunks/chevron-up-BhW6hi8L.js.map +1 -0
- package/dist/chunks/{config-E1cTyRVV.js → config-8n1VR0ju.js} +1 -1
- package/dist/chunks/{config-E1cTyRVV.js.map → config-8n1VR0ju.js.map} +1 -1
- package/dist/chunks/{config-DIDz_E5m.js → config-B34mkd53.js} +66 -1
- package/dist/chunks/config-B34mkd53.js.map +1 -0
- package/dist/chunks/{config-B5SBUa6u.js → config-B7qZqiUB.js} +28 -1
- package/dist/chunks/config-B7qZqiUB.js.map +1 -0
- package/dist/chunks/config-BBrPUEye.js +8 -0
- package/dist/chunks/config-BBrPUEye.js.map +1 -0
- package/dist/chunks/{config-CT4lP6S4.js → config-BOCzHqWh.js} +2 -2
- package/dist/chunks/{config-CT4lP6S4.js.map → config-BOCzHqWh.js.map} +1 -1
- package/dist/chunks/{config-iemgzS4x.js → config-BP1ktzwh.js} +2 -24
- package/dist/chunks/config-BP1ktzwh.js.map +1 -0
- package/dist/chunks/config-BTxmdRzT.js +28 -0
- package/dist/chunks/config-BTxmdRzT.js.map +1 -0
- package/dist/chunks/{config-CjWOTgLL.js → config-Bk52xd5l.js} +12 -5
- package/dist/chunks/config-Bk52xd5l.js.map +1 -0
- package/dist/chunks/{config-D3HOuHDe.js → config-C3SqBqSQ.js} +3 -1
- package/dist/chunks/config-C3SqBqSQ.js.map +1 -0
- package/dist/chunks/{config-2ZHRsdOc.js → config-C3uqd-sW.js} +1 -1
- package/dist/chunks/config-C3uqd-sW.js.map +1 -0
- package/dist/chunks/{config-BXRmsn3t.js → config-CPhcZzHi.js} +72 -10
- package/dist/chunks/config-CPhcZzHi.js.map +1 -0
- package/dist/chunks/config-CWtfxkM9.js.map +1 -1
- package/dist/chunks/{config--t2dxj0t.js → config-CmLTCmY9.js} +2 -2
- package/dist/chunks/{config--t2dxj0t.js.map → config-CmLTCmY9.js.map} +1 -1
- package/dist/chunks/{config-BAse0laT.js → config-CvtqB4ki.js} +8 -3
- package/dist/chunks/config-CvtqB4ki.js.map +1 -0
- package/dist/chunks/{config-BcXX7S7B.js → config-D-JgqV0J.js} +5 -1
- package/dist/chunks/{config-BcXX7S7B.js.map → config-D-JgqV0J.js.map} +1 -1
- package/dist/chunks/{config-BHLMTJaR.js → config-D1oVht-E.js} +8 -3
- package/dist/chunks/config-D1oVht-E.js.map +1 -0
- package/dist/chunks/{config-B42iJ48O.js → config-DG41PD9i.js} +13 -1
- package/dist/chunks/config-DG41PD9i.js.map +1 -0
- package/dist/chunks/{config-Bs1HwUcx.js → config-DPJ3jtiB.js} +12 -2
- package/dist/chunks/config-DPJ3jtiB.js.map +1 -0
- package/dist/chunks/{config-tNqtapcT.js → config-DpqjlCfB.js} +2 -2
- package/dist/chunks/{config-tNqtapcT.js.map → config-DpqjlCfB.js.map} +1 -1
- package/dist/chunks/{config-DNDgp9bB.js → config-DpzFoSIh.js} +64 -2
- package/dist/chunks/config-DpzFoSIh.js.map +1 -0
- package/dist/chunks/config-SPugeaHT.js +37 -0
- package/dist/chunks/config-SPugeaHT.js.map +1 -0
- package/dist/chunks/{en-CsQUoBS2.js → en-mIFywnV2.js} +22 -6
- package/dist/chunks/en-mIFywnV2.js.map +1 -0
- package/dist/chunks/{es-9nbkPvdA.js → es-CvthYwtB.js} +22 -6
- package/dist/chunks/es-CvthYwtB.js.map +1 -0
- package/dist/chunks/{es-DrUz5J6I.js → es-DlGd6Mrj.js} +3 -3
- package/dist/chunks/{es-DrUz5J6I.js.map → es-DlGd6Mrj.js.map} +1 -1
- package/dist/chunks/{generated-CxvC5O0V.js → generated-Cx4C7GRN.js} +84 -0
- package/dist/chunks/{generated-CxvC5O0V.js.map → generated-Cx4C7GRN.js.map} +1 -1
- package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js → grPopoverStyles-CncEkiPu.js} +1 -1
- package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js.map → grPopoverStyles-CncEkiPu.js.map} +1 -1
- package/dist/chunks/{grSelectStyles-D9EQ-pgK.js → grSelectStyles-Cam-IG9s.js} +3 -2
- package/dist/chunks/grSelectStyles-Cam-IG9s.js.map +1 -0
- package/dist/chunks/{grSliderStyles-kaz6VXZ3.js → grSliderStyles-CqzV0hll.js} +1 -1
- package/dist/chunks/grSliderStyles-CqzV0hll.js.map +1 -0
- package/dist/chunks/{config-CbEbLyDE.js → grSortableListStyles-CxieDmpe.js} +1 -27
- package/dist/chunks/grSortableListStyles-CxieDmpe.js.map +1 -0
- package/dist/chunks/grTableStyles-CPSxDTOW.js +66 -0
- package/dist/chunks/grTableStyles-CPSxDTOW.js.map +1 -0
- package/dist/chunks/{config-CMNfZO7S.js → grTabsStyles-DIz2VdIm.js} +1 -36
- package/dist/chunks/grTabsStyles-DIz2VdIm.js.map +1 -0
- package/dist/chunks/grTooltipStyles-CtbGEEGV.js +24 -0
- package/dist/chunks/grTooltipStyles-CtbGEEGV.js.map +1 -0
- package/dist/chunks/{granular-provider-B6xomapW.js → granular-provider-cv5vaM1a.js} +21 -19
- package/dist/chunks/granular-provider-cv5vaM1a.js.map +1 -0
- package/dist/chunks/hotkeySequence-BTHIM_5A.js +46 -0
- package/dist/chunks/hotkeySequence-BTHIM_5A.js.map +1 -0
- package/dist/chunks/{keyboard-DE2yhz_b.js → keyboard-BiFSgWLt.js} +70 -1
- package/dist/chunks/keyboard-BiFSgWLt.js.map +1 -0
- package/dist/chunks/optionPanel-DvY7Tv_4.js +182 -0
- package/dist/chunks/optionPanel-DvY7Tv_4.js.map +1 -0
- package/dist/chunks/overlayListPanel-D91jBCHU.js +21 -0
- package/dist/chunks/overlayListPanel-D91jBCHU.js.map +1 -0
- package/dist/chunks/{overlayStack-DH4Z7am1.js → overlayStack-DCkCgXZP.js} +1 -1
- package/dist/chunks/{overlayStack-DH4Z7am1.js.map → overlayStack-DCkCgXZP.js.map} +1 -1
- package/dist/chunks/{overlayPanelSurface-BKeMhRx4.js → overlayTransition-C0FDMx7Q.js} +24 -24
- package/dist/chunks/overlayTransition-C0FDMx7Q.js.map +1 -0
- package/dist/chunks/{ru-88i1WG0b.js → ru-CQKDR-kD.js} +22 -6
- package/dist/chunks/ru-CQKDR-kD.js.map +1 -0
- package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js → useMenuItemsFocus-C031blYS.js} +1 -1
- package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js.map → useMenuItemsFocus-C031blYS.js.map} +1 -1
- package/dist/chunks/{useModalOverlay-ACRkflzx.js → useModalOverlay-CKCQkGdB.js} +1 -1
- package/dist/chunks/{useModalOverlay-ACRkflzx.js.map → useModalOverlay-CKCQkGdB.js.map} +1 -1
- package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-Chhw65pI.js → GrAutocomplete-Cyr1-ENw.js} +181 -123
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-Cyr1-ENw.js.map +1 -0
- package/dist/components/GrAutocomplete/index.js +2 -2
- package/dist/components/GrAutocomplete/styles.css +1 -1
- package/dist/components/GrCarousel/chunks/{GrCarousel-ByuughtI.js → GrCarousel-CBj-PEPB.js} +186 -37
- package/dist/components/GrCarousel/chunks/GrCarousel-CBj-PEPB.js.map +1 -0
- package/dist/components/GrCarousel/index.js +2 -2
- package/dist/components/GrCarousel/styles.css +1 -1
- package/dist/components/GrCheckbox/chunks/{GrCheckbox-Dp201frb.js → GrCheckbox-B4NJc7Ur.js} +2 -1
- package/dist/components/GrCheckbox/chunks/GrCheckbox-B4NJc7Ur.js.map +1 -0
- package/dist/components/GrCheckbox/index.js +1 -1
- package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js → GrCheckboxGroup-qZHpNFCX.js} +1 -1
- package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js.map → GrCheckboxGroup-qZHpNFCX.js.map} +1 -1
- package/dist/components/GrCheckboxGroup/index.js +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BRM_4lyI.js → GrColorPicker-vGSgpUV9.js} +353 -38
- package/dist/components/GrColorPicker/chunks/GrColorPicker-vGSgpUV9.js.map +1 -0
- package/dist/components/GrColorPicker/index.js +2 -2
- package/dist/components/GrColorPicker/styles.css +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BJHmkDQv.js → GrCommandPalette-CAHgj0Aa.js} +23 -7
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-CAHgj0Aa.js.map +1 -0
- package/dist/components/GrCommandPalette/index.js +1 -1
- package/dist/components/GrCommandPalette/styles.css +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js → GrConfirmDialog-dg021BMd.js} +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js.map → GrConfirmDialog-dg021BMd.js.map} +1 -1
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js → GrContextMenu-bQ1Vvy2c.js} +3 -3
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js.map → GrContextMenu-bQ1Vvy2c.js.map} +1 -1
- package/dist/components/GrContextMenu/index.js +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-DQxYYgQk.js → GrDataTable-Bb2jWnRG.js} +576 -136
- package/dist/components/GrDataTable/chunks/GrDataTable-Bb2jWnRG.js.map +1 -0
- package/dist/components/GrDataTable/index.js +2 -2
- package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js → GrDelta-BSv1KdMy.js} +0 -0
- package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js.map → GrDelta-BSv1KdMy.js.map} +1 -1
- package/dist/components/GrDelta/index.js +2 -2
- package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js → GrDialog-C9Zu72jB.js} +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js.map → GrDialog-C9Zu72jB.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js → GrDialogService-DLBifO61.js} +2 -2
- package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js.map → GrDialogService-DLBifO61.js.map} +1 -1
- package/dist/components/GrDialogService/index.js +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js → GrDrawer-DOcRTE8G.js} +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js.map → GrDrawer-DOcRTE8G.js.map} +1 -1
- package/dist/components/GrDrawer/index.js +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js → GrDropdown-kxwmgfSe.js} +2 -2
- package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js.map → GrDropdown-kxwmgfSe.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-Dxkz_ry4.js → GrDropdownMenu--VoK3VY0.js} +3 -34
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu--VoK3VY0.js.map +1 -0
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js +34 -0
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js.map +1 -0
- package/dist/components/GrDropdownMenu/index.js +2 -1
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-BbvwE-E0.js → GrEmptyState-Bz6-_ED4.js} +42 -6
- package/dist/components/GrEmptyState/chunks/GrEmptyState-Bz6-_ED4.js.map +1 -0
- package/dist/components/GrEmptyState/index.js +1 -1
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-BwMR71zN.js → GrFileUpload-Bgdfnkd8.js} +5 -2
- package/dist/components/GrFileUpload/chunks/GrFileUpload-Bgdfnkd8.js.map +1 -0
- package/dist/components/GrFileUpload/index.js +1 -1
- package/dist/components/GrFormFile/chunks/{GrFormFile-Dlxx-9zi.js → GrFormFile-Ctq1isz-.js} +78 -11
- package/dist/components/GrFormFile/chunks/GrFormFile-Ctq1isz-.js.map +1 -0
- package/dist/components/GrFormFile/index.js +2 -2
- package/dist/components/GrFormFile/styles.css +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js → GrImageViewer-Bnql_dNP.js} +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js.map → GrImageViewer-Bnql_dNP.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInput/chunks/{GrInput-DV4gMWPR.js → GrInput-CoaFLpaU.js} +43 -22
- package/dist/components/GrInput/chunks/GrInput-CoaFLpaU.js.map +1 -0
- package/dist/components/GrInput/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-qnRdAZnn.js → GrInputTag-BzzNRBe3.js} +245 -18
- package/dist/components/GrInputTag/chunks/GrInputTag-BzzNRBe3.js.map +1 -0
- package/dist/components/GrInputTag/index.js +2 -2
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js → GrJsonViewer-B6ZJ3GFH.js} +2 -2
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js.map → GrJsonViewer-B6ZJ3GFH.js.map} +1 -1
- package/dist/components/GrJsonViewer/index.js +1 -1
- package/dist/components/GrKbd/chunks/{GrKbd-BNMeoaLV.js → GrKbd-D2rHDkQv.js} +42 -37
- package/dist/components/GrKbd/chunks/GrKbd-D2rHDkQv.js.map +1 -0
- package/dist/components/GrKbd/index.js +1 -1
- package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js → GrModal-SHb1U2qx.js} +1 -1
- package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js.map → GrModal-SHb1U2qx.js.map} +1 -1
- package/dist/components/GrModal/index.js +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-BRGuksiy.js → GrNavbar-IEIHC5Vt.js} +10 -4
- package/dist/components/GrNavbar/chunks/GrNavbar-IEIHC5Vt.js.map +1 -0
- package/dist/components/GrNavbar/index.js +2 -2
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js → GrNumberInput-CmnUDaKi.js} +2 -22
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js.map → GrNumberInput-CmnUDaKi.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +1 -1
- package/dist/components/GrPagination/chunks/{GrPagination-CMrLPzvL.js → GrPagination-AMbn5D8I.js} +1 -1
- package/dist/components/GrPagination/chunks/{GrPagination-CMrLPzvL.js.map → GrPagination-AMbn5D8I.js.map} +1 -1
- package/dist/components/GrPagination/index.js +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js → GrPopover-DjVxt8bf.js} +3 -3
- package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js.map → GrPopover-DjVxt8bf.js.map} +1 -1
- package/dist/components/GrPopover/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js → GrPromptDialog-BhbIZP1f.js} +3 -3
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js.map → GrPromptDialog-BhbIZP1f.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +1 -1
- package/dist/components/GrSelect/chunks/{GrSelect-DvSq-nV-.js → GrSelect-B-ykrHpL.js} +24 -180
- package/dist/components/GrSelect/chunks/GrSelect-B-ykrHpL.js.map +1 -0
- package/dist/components/GrSelect/index.js +2 -2
- package/dist/components/GrSelect/styles.css +1 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js +543 -0
- package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js.map +1 -0
- package/dist/components/GrSidebar/index.js +2 -2
- package/dist/components/GrSlider/chunks/{GrSlider-CO8N9SF6.js → GrSlider-DF2Cq0rV.js} +29 -4
- package/dist/components/GrSlider/chunks/GrSlider-DF2Cq0rV.js.map +1 -0
- package/dist/components/GrSlider/index.js +2 -2
- package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js → GrSortableList-ChH9nQBv.js} +1 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js.map → GrSortableList-ChH9nQBv.js.map} +1 -1
- package/dist/components/GrSortableList/index.js +2 -2
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js +30 -0
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js.map +1 -0
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js +83 -0
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js.map +1 -0
- package/dist/components/GrTabPanels/index.js +2 -1
- package/dist/components/GrTable/chunks/{GrTable-CKJ-HrsN.js → GrTable-BQitSDep.js} +52 -16
- package/dist/components/GrTable/chunks/GrTable-BQitSDep.js.map +1 -0
- package/dist/components/GrTable/index.js +2 -2
- package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js → GrTabs-DVC6nfWB.js} +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js.map → GrTabs-DVC6nfWB.js.map} +1 -1
- package/dist/components/GrTabs/index.js +2 -2
- package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js +98 -0
- package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js.map +1 -0
- package/dist/components/GrTabsWithPanels/index.js +3 -0
- package/dist/components/GrTextarea/chunks/{GrTextarea-Bfgc0DD2.js → GrTextarea-BFwyqcHB.js} +22 -5
- package/dist/components/GrTextarea/chunks/GrTextarea-BFwyqcHB.js.map +1 -0
- package/dist/components/GrTextarea/index.js +1 -1
- package/dist/components/GrToaster/chunks/{GrToaster-CZixNk0l.js → GrToaster-OzT1VKcp.js} +163 -32
- package/dist/components/GrToaster/chunks/GrToaster-OzT1VKcp.js.map +1 -0
- package/dist/components/GrToaster/index.js +2 -2
- package/dist/components/GrToaster/styles.css +1 -1
- package/dist/components/GrTooltip/chunks/{GrTooltip-DkMMM0uq.js → GrTooltip-BDcFycvW.js} +26 -13
- package/dist/components/GrTooltip/chunks/GrTooltip-BDcFycvW.js.map +1 -0
- package/dist/components/GrTooltip/index.js +2 -2
- package/dist/components/GrTransfer/chunks/{GrTransfer-DdfBUf35.js → GrTransfer-CV7BL5UK.js} +114 -12
- package/dist/components/GrTransfer/chunks/GrTransfer-CV7BL5UK.js.map +1 -0
- package/dist/components/GrTransfer/index.js +1 -1
- package/dist/components/GrTransfer/styles.css +1 -1
- package/dist/components/GrTree/chunks/{GrTree-6yZrncJE.js → GrTree-DpgaP8hk.js} +39 -1
- package/dist/components/GrTree/chunks/GrTree-DpgaP8hk.js.map +1 -0
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTree/styles.css +1 -1
- package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js → GrTreeSections-BeOj__44.js} +1 -1
- package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js.map → GrTreeSections-BeOj__44.js.map} +1 -1
- package/dist/components/GrTreeSections/index.js +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-B6KoDYiZ.js → GrTreeSelect-BHq-T8wH.js} +113 -14
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHq-T8wH.js.map +1 -0
- package/dist/components/GrTreeSelect/index.js +2 -2
- package/dist/composables/useFloating.js +1 -1
- package/dist/composables/useHotkeys.js +89 -0
- package/dist/composables/useHotkeys.js.map +1 -0
- package/dist/composables/useOverlayLayer.js +1 -1
- package/dist/directives/hotkey.js +19 -46
- package/dist/directives/hotkey.js.map +1 -1
- package/dist/granular-provider-node.js +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/i18n/all.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.js +71 -63
- package/dist/theme.js +1 -1
- package/dist/tokens.js +1 -1
- package/dist/types/components/GrAutocomplete/GrAutocomplete.vue.d.ts +4 -4
- package/dist/types/components/GrAutocomplete/composables/useAutocompleteNavigation.d.ts +12 -3
- package/dist/types/components/GrAutocomplete/composables/useAutocompletePanel.d.ts +12 -2
- package/dist/types/components/GrAutocomplete/composables/useAutocompleteValues.d.ts +7 -4
- package/dist/types/components/GrAutocomplete/composables/useRemoteOptions.d.ts +4 -4
- package/dist/types/components/GrAutocomplete/grAutocompleteStyles.d.ts +15 -1
- package/dist/types/components/GrAutocomplete/index.d.ts +1 -1
- package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +29 -1
- package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +5 -0
- package/dist/types/components/GrCarousel/grCarouselContext.d.ts +21 -0
- package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +39 -9
- package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +13 -0
- package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +18 -2
- package/dist/types/components/GrColorPicker/color.d.ts +13 -1
- package/dist/types/components/GrColorPicker/colorArea.d.ts +59 -0
- package/dist/types/components/GrColorPicker/defaults.d.ts +3 -1
- package/dist/types/components/GrColorPicker/eyeDropper.d.ts +21 -0
- package/dist/types/components/GrColorPicker/grColorPickerStyles.d.ts +42 -0
- package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +10 -1
- package/dist/types/components/GrDataTable/GrDataTable.vue.d.ts +41 -1
- package/dist/types/components/GrDataTable/composables/useDataTableGridNavigation.d.ts +53 -0
- package/dist/types/components/GrDataTable/grDataTableStyles.d.ts +8 -0
- package/dist/types/components/GrDataTable/index.d.ts +1 -1
- package/dist/types/components/GrDelta/grDeltaStyles.d.ts +10 -3
- package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +11 -2
- package/dist/types/components/GrEmptyState/grEmptyStateStyles.d.ts +10 -0
- package/dist/types/components/GrEmptyState/index.d.ts +1 -1
- package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +2 -1
- package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +10 -0
- package/dist/types/components/GrInput/GrInput.vue.d.ts +15 -0
- package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +16 -0
- package/dist/types/components/GrInputTag/grInputTagStyles.d.ts +11 -0
- package/dist/types/components/GrKbd/GrKbd.vue.d.ts +14 -0
- package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +18 -0
- package/dist/types/components/GrNavbar/grNavbarStyles.d.ts +10 -1
- package/dist/types/components/GrNavbar/index.d.ts +1 -0
- package/dist/types/components/GrSelect/composables/useSelectPanelItems.d.ts +8 -34
- package/dist/types/components/GrSelect/composables/useSelectVirtualization.d.ts +7 -0
- package/dist/types/components/GrSelect/grSelectStyles.d.ts +1 -1
- package/dist/types/components/GrSidebar/GrSidebar.vue.d.ts +20 -0
- package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +39 -5
- package/dist/types/components/GrSidebar/grSidebarStyles.d.ts +32 -0
- package/dist/types/components/GrSidebar/index.d.ts +1 -1
- package/dist/types/components/GrSidebar/sidebarContext.d.ts +23 -1
- package/dist/types/components/GrSlider/GrSlider.vue.d.ts +39 -1
- package/dist/types/components/GrSlider/grSliderStyles.d.ts +1 -1
- package/dist/types/components/GrTabPanels/context.d.ts +6 -0
- package/dist/types/components/GrTable/GrTable.vue.d.ts +37 -0
- package/dist/types/components/GrTable/grTableStyles.d.ts +16 -7
- package/dist/types/components/GrTabsWithPanels/GrTabsWithPanels.vue.d.ts +77 -0
- package/dist/types/components/GrTabsWithPanels/config.d.ts +1 -0
- package/dist/types/components/GrTabsWithPanels/index.d.ts +4 -0
- package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +19 -1
- package/dist/types/components/GrToaster/GrToaster.vue.d.ts +12 -0
- package/dist/types/components/GrToaster/grToasterStyles.d.ts +26 -0
- package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +22 -0
- package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +23 -0
- package/dist/types/components/GrTreeSelect/grTreeSelectStyles.d.ts +1 -1
- package/dist/types/components/GrTreeSelect/grTreeSelectTypes.d.ts +20 -0
- package/dist/types/components/shared/hotkey.d.ts +8 -9
- package/dist/types/components/shared/optionPanel.d.ts +100 -0
- package/dist/types/components/shared/overlayListPanel.d.ts +18 -0
- package/dist/types/composables/useHotkeys.d.ts +43 -0
- package/dist/types/granular-provider/shared.d.ts +1 -0
- package/dist/types/i18n/messages/en.d.ts +28 -0
- package/dist/types/i18n/messages/es.d.ts +28 -0
- package/dist/types/i18n/messages/ru.d.ts +28 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/internal/hotkeySequence.d.ts +22 -0
- package/dist/types/internal/keyboard.d.ts +45 -0
- package/dist/web-types.json +463 -26
- package/package.json +9 -1
- package/dist/chunks/config-2ZHRsdOc.js.map +0 -1
- package/dist/chunks/config-B42iJ48O.js.map +0 -1
- package/dist/chunks/config-B5SBUa6u.js.map +0 -1
- package/dist/chunks/config-BAse0laT.js.map +0 -1
- package/dist/chunks/config-BHLMTJaR.js.map +0 -1
- package/dist/chunks/config-BXRmsn3t.js.map +0 -1
- package/dist/chunks/config-Bs1HwUcx.js.map +0 -1
- package/dist/chunks/config-CMNfZO7S.js.map +0 -1
- package/dist/chunks/config-CbEbLyDE.js.map +0 -1
- package/dist/chunks/config-CjWOTgLL.js.map +0 -1
- package/dist/chunks/config-D3HOuHDe.js.map +0 -1
- package/dist/chunks/config-DIDz_E5m.js.map +0 -1
- package/dist/chunks/config-DNDgp9bB.js.map +0 -1
- package/dist/chunks/config-iemgzS4x.js.map +0 -1
- package/dist/chunks/en-CsQUoBS2.js.map +0 -1
- package/dist/chunks/es-9nbkPvdA.js.map +0 -1
- package/dist/chunks/grSelectStyles-D9EQ-pgK.js.map +0 -1
- package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +0 -1
- package/dist/chunks/grTableStyles-DkQPMfx9.js +0 -39
- package/dist/chunks/grTableStyles-DkQPMfx9.js.map +0 -1
- package/dist/chunks/granular-provider-B6xomapW.js.map +0 -1
- package/dist/chunks/keyboard-DE2yhz_b.js.map +0 -1
- package/dist/chunks/overlayPanelSurface-BKeMhRx4.js.map +0 -1
- package/dist/chunks/ru-88i1WG0b.js.map +0 -1
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-Chhw65pI.js.map +0 -1
- package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +0 -1
- package/dist/components/GrCheckbox/chunks/GrCheckbox-Dp201frb.js.map +0 -1
- package/dist/components/GrColorPicker/chunks/GrColorPicker-BRM_4lyI.js.map +0 -1
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BJHmkDQv.js.map +0 -1
- package/dist/components/GrDataTable/chunks/GrDataTable-DQxYYgQk.js.map +0 -1
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-Dxkz_ry4.js.map +0 -1
- package/dist/components/GrEmptyState/chunks/GrEmptyState-BbvwE-E0.js.map +0 -1
- package/dist/components/GrFileUpload/chunks/GrFileUpload-BwMR71zN.js.map +0 -1
- package/dist/components/GrFormFile/chunks/GrFormFile-Dlxx-9zi.js.map +0 -1
- package/dist/components/GrInput/chunks/GrInput-DV4gMWPR.js.map +0 -1
- package/dist/components/GrInputTag/chunks/GrInputTag-qnRdAZnn.js.map +0 -1
- package/dist/components/GrKbd/chunks/GrKbd-BNMeoaLV.js.map +0 -1
- package/dist/components/GrNavbar/chunks/GrNavbar-BRGuksiy.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-DvSq-nV-.js.map +0 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js +0 -264
- package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js.map +0 -1
- package/dist/components/GrSlider/chunks/GrSlider-CO8N9SF6.js.map +0 -1
- package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js +0 -92
- package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js.map +0 -1
- package/dist/components/GrTable/chunks/GrTable-CKJ-HrsN.js.map +0 -1
- package/dist/components/GrTextarea/chunks/GrTextarea-Bfgc0DD2.js.map +0 -1
- package/dist/components/GrToaster/chunks/GrToaster-CZixNk0l.js.map +0 -1
- package/dist/components/GrTooltip/chunks/GrTooltip-DkMMM0uq.js.map +0 -1
- package/dist/components/GrTransfer/chunks/GrTransfer-DdfBUf35.js.map +0 -1
- package/dist/components/GrTree/chunks/GrTree-6yZrncJE.js.map +0 -1
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-B6KoDYiZ.js.map +0 -1
- package/dist/types/components/GrAutocomplete/composables/useAutocompleteVirtual.d.ts +0 -33
|
@@ -2,8 +2,9 @@ import { n as alert_triangle_default, t as check_circle_default } from "../../..
|
|
|
2
2
|
import { t as x_default } from "../../../chunks/x-2KXnqxiD.js";
|
|
3
3
|
import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunks/context-CPMRfwVr.js";
|
|
4
4
|
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
|
|
5
|
-
import {
|
|
5
|
+
import { n as isComposingEvent } from "../../../chunks/keyboard-BiFSgWLt.js";
|
|
6
6
|
import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-DTZIgmje.js";
|
|
7
|
+
import { useDismissible } from "../../../composables/useDismissible.js";
|
|
7
8
|
import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js";
|
|
8
9
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
9
10
|
import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
|
|
@@ -14,8 +15,8 @@ import { t as GrChip_default } from "../../GrChip/chunks/GrChip-DoyS1Dr4.js";
|
|
|
14
15
|
import { useAnnouncer } from "../../../composables/useAnnouncer.js";
|
|
15
16
|
import { a as controlStateTextKey, i as controlStateIconColors, n as controlStateFallbackText, r as controlStateIconClass, t as controlSignalState } from "../../../chunks/controlState-DoImKciE.js";
|
|
16
17
|
import { t as loader_2_default } from "../../../chunks/loader-2-B1fdsdWW.js";
|
|
17
|
-
import { a as grInputTagWrapperClass, i as grInputTagInputClass, o as spinnerClass, r as clearButtonClass } from "../../../chunks/config-
|
|
18
|
-
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useId, watchEffect, withCtx, withModifiers } from "vue";
|
|
18
|
+
import { a as grInputTagWrapperClass, i as grInputTagInputClass, o as spinnerClass, r as clearButtonClass, s as tagEditInputClass } from "../../../chunks/config-DG41PD9i.js";
|
|
19
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useId, vModelText, watch, watchEffect, withCtx, withDirectives, withModifiers } from "vue";
|
|
19
20
|
//#region src/components/GrInputTag/GrInputTag.vue?vue&type=script&setup=true&lang.ts
|
|
20
21
|
var _hoisted_1 = ["name", "value"];
|
|
21
22
|
var _hoisted_2 = {
|
|
@@ -23,8 +24,14 @@ var _hoisted_2 = {
|
|
|
23
24
|
role: "list",
|
|
24
25
|
class: "contents"
|
|
25
26
|
};
|
|
26
|
-
var _hoisted_3 =
|
|
27
|
-
|
|
27
|
+
var _hoisted_3 = [
|
|
28
|
+
"size",
|
|
29
|
+
"aria-label",
|
|
30
|
+
"onKeydown",
|
|
31
|
+
"onBlur"
|
|
32
|
+
];
|
|
33
|
+
var _hoisted_4 = { class: "truncate max-w-[18rem]" };
|
|
34
|
+
var _hoisted_5 = [
|
|
28
35
|
"id",
|
|
29
36
|
"value",
|
|
30
37
|
"disabled",
|
|
@@ -37,8 +44,8 @@ var _hoisted_4 = [
|
|
|
37
44
|
"aria-invalid",
|
|
38
45
|
"aria-busy"
|
|
39
46
|
];
|
|
40
|
-
var
|
|
41
|
-
var
|
|
47
|
+
var _hoisted_6 = ["id"];
|
|
48
|
+
var _hoisted_7 = ["aria-label"];
|
|
42
49
|
//#endregion
|
|
43
50
|
//#region src/components/GrInputTag/GrInputTag.vue
|
|
44
51
|
var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
@@ -86,6 +93,10 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
86
93
|
type: Function,
|
|
87
94
|
default: void 0
|
|
88
95
|
},
|
|
96
|
+
editable: {
|
|
97
|
+
type: Boolean,
|
|
98
|
+
default: false
|
|
99
|
+
},
|
|
89
100
|
clearable: {
|
|
90
101
|
type: Boolean,
|
|
91
102
|
default: void 0
|
|
@@ -120,6 +131,7 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
120
131
|
"update:modelValue",
|
|
121
132
|
"add",
|
|
122
133
|
"remove",
|
|
134
|
+
"edit",
|
|
123
135
|
"reject",
|
|
124
136
|
"clear",
|
|
125
137
|
"change",
|
|
@@ -309,6 +321,197 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
309
321
|
emit("remove", removed, index);
|
|
310
322
|
announce(t("gr.inputTag.removed", "Tag removed: {tag}", { tag: removed }));
|
|
311
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Правка тега на месте.
|
|
326
|
+
*
|
|
327
|
+
* Индекс правимого чипа и черновик его значения. Черновик отдельно от модели:
|
|
328
|
+
* пока пользователь печатает, набор не трогается — иначе `Escape` было бы
|
|
329
|
+
* нечем отменять.
|
|
330
|
+
*/
|
|
331
|
+
const editingIndex = ref(null);
|
|
332
|
+
const editDraft = ref("");
|
|
333
|
+
/** Значение на момент входа в правку: по нему видно, что набор сменили снаружи. */
|
|
334
|
+
const editOriginal = ref("");
|
|
335
|
+
/**
|
|
336
|
+
* Свой счётчик гонок, отдельный от `validationRun`.
|
|
337
|
+
*
|
|
338
|
+
* Общий отменял бы проверку правки при добавлении тега — а к тому моменту
|
|
339
|
+
* редактор уже закрыт, и набранное восстановить нечем.
|
|
340
|
+
*/
|
|
341
|
+
let editValidationRun = 0;
|
|
342
|
+
/**
|
|
343
|
+
* Сессия закрывается.
|
|
344
|
+
*
|
|
345
|
+
* `closeEdit` возвращает фокус **до** размонтирования поля, то есть ждёт тик —
|
|
346
|
+
* и в это окно приходит `blur` от переезда фокуса. Без флага он успевал
|
|
347
|
+
* закоммитить то, что пользователь только что отменил.
|
|
348
|
+
*/
|
|
349
|
+
let editClosing = false;
|
|
350
|
+
/**
|
|
351
|
+
* Узел поля правки. Функцией, а не строковым `ref`: поле стоит внутри `v-for`,
|
|
352
|
+
* и там Vue складывает совпадающие `ref` в массив — `focus()` у массива нет.
|
|
353
|
+
*/
|
|
354
|
+
const editInputEl = ref(null);
|
|
355
|
+
function setEditInputRef(el) {
|
|
356
|
+
editInputEl.value = el instanceof HTMLInputElement ? el : null;
|
|
357
|
+
}
|
|
358
|
+
const canEditTag = computed(() => props.editable && canEdit.value);
|
|
359
|
+
if (process.env.NODE_ENV !== "production") watchEffect(() => {
|
|
360
|
+
if (props.editable && !props.tagClosable) console.warn("[granularity] GrInputTag: `editable` без `tagClosable` недостижим с клавиатуры — `F2` нажимают на кнопке снятия, а она единственный фокусируемый узел чипа.");
|
|
361
|
+
});
|
|
362
|
+
/**
|
|
363
|
+
* Правка — немодальный слой общего стека, и `Escape` приходит оттуда, а не из
|
|
364
|
+
* локального обработчика. `overlayStack` слушает `keydown` в capture-фазе на
|
|
365
|
+
* `window` и гасит событие, когда стек непуст: внутри `GrModal` локальный
|
|
366
|
+
* обработчик не сработал бы вовсе, а модалка закрылась бы вместе с правкой.
|
|
367
|
+
*/
|
|
368
|
+
const isEditingAny = computed({
|
|
369
|
+
get: () => editingIndex.value !== null,
|
|
370
|
+
set: (value) => {
|
|
371
|
+
if (!value && editingIndex.value !== null) cancelEdit(editingIndex.value);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
useDismissible(isEditingAny, () => {
|
|
375
|
+
if (editingIndex.value !== null) cancelEdit(editingIndex.value);
|
|
376
|
+
});
|
|
377
|
+
function isEditing(index) {
|
|
378
|
+
return editingIndex.value === index;
|
|
379
|
+
}
|
|
380
|
+
async function startEdit(index) {
|
|
381
|
+
if (!canEditTag.value) return;
|
|
382
|
+
const current = props.modelValue[index];
|
|
383
|
+
if (current === void 0) return;
|
|
384
|
+
editingIndex.value = index;
|
|
385
|
+
editDraft.value = current;
|
|
386
|
+
editOriginal.value = current;
|
|
387
|
+
await nextTick();
|
|
388
|
+
editInputEl.value?.focus();
|
|
389
|
+
editInputEl.value?.select();
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Закрыть правку и вернуть фокус на крестик того же чипа.
|
|
393
|
+
*
|
|
394
|
+
* Через тик обязательно: ключ чипа зависит от значения тега, поэтому после
|
|
395
|
+
* коммита Vue пересоздаёт узел — `removeEl` к этому моменту уже другой.
|
|
396
|
+
*/
|
|
397
|
+
async function closeEdit(index, restoreFocus) {
|
|
398
|
+
editClosing = true;
|
|
399
|
+
if (restoreFocus) await roving.focusKey(index);
|
|
400
|
+
editingIndex.value = null;
|
|
401
|
+
editDraft.value = "";
|
|
402
|
+
editOriginal.value = "";
|
|
403
|
+
editClosing = false;
|
|
404
|
+
}
|
|
405
|
+
/** Фокус ещё в поле правки — значит его и возвращаем. Ушёл сам — не трогаем. */
|
|
406
|
+
function editorHoldsFocus() {
|
|
407
|
+
return document.activeElement === editInputEl.value;
|
|
408
|
+
}
|
|
409
|
+
function cancelEdit(index) {
|
|
410
|
+
closeEdit(index, editorHoldsFocus());
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Подтверждение правки.
|
|
414
|
+
*
|
|
415
|
+
* Проверка дубликатов исключает сам правимый индекс: иначе тег нельзя было бы
|
|
416
|
+
* подтвердить самим собой. `beforeAdd` назван про добавление, но правило у
|
|
417
|
+
* тега одно, и второго пропа ради этого не заводится — отказ возвращает
|
|
418
|
+
* прежнее значение и закрывает правку.
|
|
419
|
+
*/
|
|
420
|
+
async function commitEdit(index, options = {}) {
|
|
421
|
+
if (editClosing || !canEditTag.value || editingIndex.value !== index) return;
|
|
422
|
+
const previous = props.modelValue[index];
|
|
423
|
+
if (previous === void 0) return;
|
|
424
|
+
const restore = editorHoldsFocus();
|
|
425
|
+
const value = normalizeTag(editDraft.value);
|
|
426
|
+
if (!value) {
|
|
427
|
+
await closeEdit(index, restore);
|
|
428
|
+
if (!options.fromBlur) removeAt(index);
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (value === previous) {
|
|
432
|
+
await closeEdit(index, restore);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (!props.allowDuplicates && props.modelValue.some((tag, i) => i !== index && tag === value)) {
|
|
436
|
+
await closeEdit(index, restore);
|
|
437
|
+
announce(t("gr.inputTag.editRejected", "Tag {tag} was not applied", { tag: value }));
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const run = ++editValidationRun;
|
|
441
|
+
const check = props.beforeAdd;
|
|
442
|
+
validating.value = Boolean(check);
|
|
443
|
+
const ok = check ? await check(value) : true;
|
|
444
|
+
if (run === editValidationRun) validating.value = false;
|
|
445
|
+
if (run !== editValidationRun || editingIndex.value !== index) return;
|
|
446
|
+
if (!ok) {
|
|
447
|
+
emit("reject", value);
|
|
448
|
+
await closeEdit(index, restore);
|
|
449
|
+
announce(t("gr.inputTag.editRejected", "Tag {tag} was not applied", { tag: value }));
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
const next = props.modelValue.slice();
|
|
453
|
+
next[index] = value;
|
|
454
|
+
emit("update:modelValue", next);
|
|
455
|
+
emit("change", next);
|
|
456
|
+
emit("edit", value, index, previous);
|
|
457
|
+
announce(t("gr.inputTag.edited", "Tag changed: {tag}", { tag: value }));
|
|
458
|
+
await closeEdit(index, restore);
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Клик внутри правящегося чипа принадлежит редактору.
|
|
462
|
+
*
|
|
463
|
+
* На корне висит `@click="focus"`, и без этого клик, которым ставят каретку в
|
|
464
|
+
* поле правки, уводил бы фокус в главный ввод — то есть попасть мышью в поле
|
|
465
|
+
* было бы нельзя.
|
|
466
|
+
*/
|
|
467
|
+
function onTagClick(e, index) {
|
|
468
|
+
if (editingIndex.value === index) e.stopPropagation();
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Двойной клик по крестику не открывает правку: первый клик уже снял тег, и на
|
|
472
|
+
* этой позиции стоит другой — правка открылась бы не тому.
|
|
473
|
+
*/
|
|
474
|
+
function onTagDblclick(e, index) {
|
|
475
|
+
if (!canEditTag.value) return;
|
|
476
|
+
if (e.target instanceof Element && e.target.closest("[data-gr-chip-close]")) return;
|
|
477
|
+
e.preventDefault();
|
|
478
|
+
startEdit(index);
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Набор или доступность сменились снаружи — правка закрывается без коммита.
|
|
482
|
+
*
|
|
483
|
+
* Индекс правки к чужому набору не относится: теги могли прийти с сервера,
|
|
484
|
+
* форму могли сбросить, поле — заблокировать. Дописать туда своё значение
|
|
485
|
+
* значит переписать не тот тег.
|
|
486
|
+
*/
|
|
487
|
+
watch([() => props.modelValue, canEditTag], ([tags, allowed]) => {
|
|
488
|
+
const index = editingIndex.value;
|
|
489
|
+
if (index === null) return;
|
|
490
|
+
if (!allowed || tags[index] !== editOriginal.value) closeEdit(index, false);
|
|
491
|
+
});
|
|
492
|
+
function onEditKeydown(e, index) {
|
|
493
|
+
if (isComposingEvent(e)) return;
|
|
494
|
+
if (e.key === "Enter") {
|
|
495
|
+
e.preventDefault();
|
|
496
|
+
commitEdit(index);
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
if (e.key === "Escape") {
|
|
500
|
+
e.preventDefault();
|
|
501
|
+
cancelEdit(index);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Уход фокуса подтверждает, а не отменяет, — и это осознанное расхождение с
|
|
506
|
+
* `addOnBlur`. Тот решает, становится ли **недонабранное новое** тегом, и там
|
|
507
|
+
* отбросить безопасно: до этого не было ничего. Правка же начинается с
|
|
508
|
+
* существующего значения, которое пользователь решил изменить, и тихо вернуть
|
|
509
|
+
* его набранное — как раз тот исход, который удивит. Отказаться есть чем:
|
|
510
|
+
* `Escape`.
|
|
511
|
+
*/
|
|
512
|
+
function onEditBlur(index) {
|
|
513
|
+
if (!editClosing && editingIndex.value === index) commitEdit(index, { fromBlur: true });
|
|
514
|
+
}
|
|
312
515
|
/** Удаление с клавиатуры: фокус переезжает на соседний чип, а не пропадает. */
|
|
313
516
|
async function removeAtFromKeyboard(index) {
|
|
314
517
|
removeAt(index);
|
|
@@ -356,7 +559,13 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
356
559
|
}
|
|
357
560
|
}
|
|
358
561
|
function onTagKeydown(e, index) {
|
|
562
|
+
if (editingIndex.value === index) return;
|
|
359
563
|
if (roving.handleNavigationKeys(e)) return;
|
|
564
|
+
if (e.key === "F2" && canEditTag.value) {
|
|
565
|
+
e.preventDefault();
|
|
566
|
+
startEdit(index);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
360
569
|
if (e.key === "Delete" || e.key === "Backspace") {
|
|
361
570
|
e.preventDefault();
|
|
362
571
|
removeAtFromKeyboard(index);
|
|
@@ -406,8 +615,8 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
406
615
|
"data-testid": "gr-input-tag",
|
|
407
616
|
class: normalizeClass(wrapperClassName.value),
|
|
408
617
|
onClick: focus,
|
|
409
|
-
onFocusin: _cache[
|
|
410
|
-
onFocusout: _cache[
|
|
618
|
+
onFocusin: _cache[2] || (_cache[2] = (...args) => unref(onFocusIn) && unref(onFocusIn)(...args)),
|
|
619
|
+
onFocusout: _cache[3] || (_cache[3] = (...args) => unref(onFocusOut) && unref(onFocusOut)(...args))
|
|
411
620
|
}, [
|
|
412
621
|
unref(hasPrefix) ? (openBlock(), createElementBlock("span", {
|
|
413
622
|
key: 0,
|
|
@@ -427,7 +636,7 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
427
636
|
}), 128)) : createCommentVNode("", true),
|
|
428
637
|
__props.modelValue.length ? (openBlock(), createElementBlock("span", _hoisted_2, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.modelValue, (tag, i) => {
|
|
429
638
|
return openBlock(), createBlock(GrChip_default, {
|
|
430
|
-
key:
|
|
639
|
+
key: i,
|
|
431
640
|
ref_for: true,
|
|
432
641
|
ref: setChipRef(i),
|
|
433
642
|
role: "listitem",
|
|
@@ -440,16 +649,31 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
440
649
|
"remove-tabindex": unref(roving).tabindexFor(i),
|
|
441
650
|
"data-gr-input-tag-item": "",
|
|
442
651
|
"data-testid": "gr-input-tag-item",
|
|
652
|
+
"aria-keyshortcuts": canEditTag.value ? "F2" : void 0,
|
|
443
653
|
"data-index": i,
|
|
444
654
|
onRemove: ($event) => removeAt(i),
|
|
445
655
|
onFocusin: ($event) => unref(roving).setActive(i),
|
|
446
|
-
onKeydown: ($event) => onTagKeydown($event, i)
|
|
656
|
+
onKeydown: ($event) => onTagKeydown($event, i),
|
|
657
|
+
onClick: ($event) => onTagClick($event, i),
|
|
658
|
+
onDblclick: ($event) => onTagDblclick($event, i)
|
|
447
659
|
}, {
|
|
448
|
-
default: withCtx(() => [
|
|
660
|
+
default: withCtx(() => [isEditing(i) ? withDirectives((openBlock(), createElementBlock("input", {
|
|
661
|
+
key: 0,
|
|
662
|
+
ref_for: true,
|
|
663
|
+
ref: setEditInputRef,
|
|
664
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => editDraft.value = $event),
|
|
665
|
+
"data-gr-input-tag-edit": "",
|
|
666
|
+
"data-testid": "gr-input-tag-edit",
|
|
667
|
+
class: normalizeClass(unref(tagEditInputClass)),
|
|
668
|
+
size: Math.max(editDraft.value.length, 2),
|
|
669
|
+
"aria-label": unref(t)("gr.inputTag.editTag", "Edit tag {tag}", { tag }),
|
|
670
|
+
onKeydown: withModifiers(($event) => onEditKeydown($event, i), ["stop"]),
|
|
671
|
+
onBlur: ($event) => onEditBlur(i)
|
|
672
|
+
}, null, 42, _hoisted_3)), [[vModelText, editDraft.value]]) : renderSlot(_ctx.$slots, "tag", {
|
|
449
673
|
tag,
|
|
450
674
|
index: i,
|
|
451
675
|
remove: () => removeAt(i)
|
|
452
|
-
}, () => [createElementVNode("span",
|
|
676
|
+
}, () => [createElementVNode("span", _hoisted_4, toDisplayString(tag), 1)], void 0, 1)]),
|
|
453
677
|
_: 2
|
|
454
678
|
}, 1032, [
|
|
455
679
|
"tone",
|
|
@@ -459,10 +683,13 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
459
683
|
"closable",
|
|
460
684
|
"remove-label",
|
|
461
685
|
"remove-tabindex",
|
|
686
|
+
"aria-keyshortcuts",
|
|
462
687
|
"data-index",
|
|
463
688
|
"onRemove",
|
|
464
689
|
"onFocusin",
|
|
465
|
-
"onKeydown"
|
|
690
|
+
"onKeydown",
|
|
691
|
+
"onClick",
|
|
692
|
+
"onDblclick"
|
|
466
693
|
]);
|
|
467
694
|
}), 128))])) : createCommentVNode("", true),
|
|
468
695
|
createElementVNode("input", {
|
|
@@ -486,7 +713,7 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
486
713
|
onKeydown,
|
|
487
714
|
onBlur,
|
|
488
715
|
onPaste
|
|
489
|
-
}, null, 42,
|
|
716
|
+
}, null, 42, _hoisted_5),
|
|
490
717
|
unref(hasSuffix) ? (openBlock(), createElementBlock("span", {
|
|
491
718
|
key: 3,
|
|
492
719
|
ref_key: "suffixEl",
|
|
@@ -515,19 +742,19 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
515
742
|
id: unref(stateTextId),
|
|
516
743
|
"data-gr-input-tag-state-text": "",
|
|
517
744
|
class: "sr-only"
|
|
518
|
-
}, toDisplayString(stateText.value), 9,
|
|
745
|
+
}, toDisplayString(stateText.value), 9, _hoisted_6)) : createCommentVNode("", true),
|
|
519
746
|
showClearAll.value ? (openBlock(), createElementBlock("button", {
|
|
520
747
|
key: 7,
|
|
521
748
|
type: "button",
|
|
522
749
|
"data-gr-input-tag-clear": "",
|
|
523
750
|
class: normalizeClass(unref(clearButtonClass)),
|
|
524
751
|
"aria-label": resolvedClearAllLabel.value,
|
|
525
|
-
onMousedown: _cache[
|
|
752
|
+
onMousedown: _cache[1] || (_cache[1] = withModifiers(() => {}, ["prevent", "stop"])),
|
|
526
753
|
onClick: withModifiers(clearAll, ["stop"])
|
|
527
754
|
}, [createVNode(GrIcon_default, { size: "sm" }, {
|
|
528
755
|
default: withCtx(() => [createVNode(unref(x_default))]),
|
|
529
756
|
_: 1
|
|
530
|
-
})], 42,
|
|
757
|
+
})], 42, _hoisted_7)) : createCommentVNode("", true)
|
|
531
758
|
], 34);
|
|
532
759
|
};
|
|
533
760
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrInputTag-BzzNRBe3.js","names":[],"sources":["../../../../src/components/GrInputTag/GrInputTag.vue","../../../../src/components/GrInputTag/GrInputTag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useId, watch, watchEffect } from 'vue'\n\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrChip from '../GrChip/GrChip.vue'\nimport { chipSizeForBadgeScale } from '../GrChip/grChipStyles'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\nimport IconCheckCircle from '~icons/lucide/check-circle'\nimport IconAlertTriangle from '~icons/lucide/alert-triangle'\nimport IconLoader from '~icons/lucide/loader-2'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useDismissible } from '../../composables/useDismissible'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport {\n controlSignalState,\n controlStateFallbackText,\n controlStateIconClass,\n controlStateIconColors,\n controlStateTextKey,\n} from '../shared/controlState'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nimport {\n clearButtonClass,\n grInputTagInputClass,\n grInputTagWrapperClass,\n spinnerClass,\n tagEditInputClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n /** Обязательное поле (`aria-required`). Складывается с `required` у `GrFormField`. */\n required?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n /**\n * Проверка тега перед добавлением. Может быть асинхронной (проверка на\n * сервере). Отклонённый тег не добавляется и уходит в событие `reject`.\n */\n beforeAdd?: (tag: string) => boolean | Promise<boolean>\n /**\n * Правка тега на месте: `F2` на чипе или двойной клик по нему открывают\n * поле, `Enter` подтверждает, `Escape` отменяет.\n *\n * Проп, а не поведение по умолчанию: двойной клик по чипу сегодня ничего не\n * делает, и превращать его во вход в правку у всех потребителей — тихая\n * смена поведения.\n */\n editable?: boolean\n /** Кнопка «снести все теги». Настраивается через `GrConfigProvider`. */\n clearable?: boolean\n /** Фоновая работа: спиннер + `aria-busy`. Асинхронный `beforeAdd` поднимает его сам. */\n loading?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n /** i18n aria-label кнопки «снести все». */\n clearAllLabel?: string\n /**\n * Имя контрола, когда он используется вне `GrFormField`. Внутри поля имя даёт\n * связка с его `<label for>` — там проп не нужен. Без того и другого у инпута\n * нет доступного имени вовсе: placeholder именем не считается.\n */\n ariaLabel?: string\n /** Имя для нативной формы: hidden input на каждый тег. */\n name?: string\n /**\n * Ширины аддонов `prefix`/`suffix` — общий контракт контролов пакета\n * (`docs/form-controls.md`).\n */\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n prefixFixed?: boolean\n suffixFixed?: boolean\n}\n\nexport interface GrInputTagEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n /** Тег изменён на месте: новое значение, его позиция и то, что стояло раньше. */\n (e: 'edit', value: string, index: number, previous: string): void\n /** Тег не прошёл `beforeAdd`. */\n (e: 'reject', value: string): void\n /** Набор снесён кнопкой «очистить». */\n (e: 'clear'): void\n /** Набор тегов изменился. */\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n state: 'default',\n // Настраивается через `GrConfigProvider`; дефолт — в резолвере ниже.\n size: undefined,\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n editable: false,\n beforeAdd: undefined,\n clearable: undefined,\n loading: false,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: undefined,\n clearAllLabel: undefined,\n ariaLabel: undefined,\n name: undefined,\n },\n)\n\nconst emit = defineEmits<GrInputTagEmits>()\ndefineSlots<{\n /** Аддон слева от чипов: иконка, метка. */\n prefix?: () => any\n /** Аддон справа, перед кнопкой очистки. */\n suffix?: () => any\n /** Свой чип: `remove` снимает значение. */\n tag?: (props: { tag: string, index: number, remove: () => void }) => any\n}>()\n\n// Fallback из контекста `GrFormField` (id/aria-describedby/invalid/required) —\n// как у GrInput и GrSelect: контрол не знает про форму, знает только про поле.\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\n// Эффективные значения: локальный проп → `GrConfigProvider` → дефолт компонента.\n/** Ширина аддона по умолчанию — та же лестница, что у `GrInput`. */\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrInputTagSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrInputTag' })\n\n/**\n * Аддоны — флекс-соседи поля: оболочка тегового поля и так флекс-строка с\n * бейджами, поэтому места паддингом резервировать не нужно.\n */\nconst { hasPrefix, hasSuffix, prefixEl, suffixEl, prefixStyle, suffixStyle } = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => '0px',\n})\nconst resolvedClearable = useGrComponentProp('GrInputTag', 'clearable', () => props.clearable, false)\n\nconst { t } = useGranularityTranslations()\n\n/**\n * Небуквенный признак состояния: иконка для глаз, скрытая подпись для\n * скринридера. Разбор — `shared/controlState`.\n */\nconst stateTextId = useId()\nconst signalState = computed(() => controlSignalState(props.state, isInvalid.value))\nconst stateIcon = computed(() => (signalState.value === 'success' ? IconCheckCircle : IconAlertTriangle))\nconst stateIconClass = computed(() => (signalState.value\n ? `${controlStateIconClass} ${controlStateIconColors[signalState.value]}`\n : ''))\nconst stateText = computed(() => (signalState.value\n ? t(controlStateTextKey[signalState.value], controlStateFallbackText[signalState.value])\n : ''))\n\nconst describedBy = computed(() =>\n [field?.describedById.value, signalState.value ? stateTextId : undefined]\n .filter(Boolean)\n .join(' ') || undefined,\n)\nconst resolvedClearAllLabel = computed(() => props.clearAllLabel ?? t('gr.inputTag.clearAll', 'Clear all tags'))\n\nfunction removeTagLabelFor(tag: string): string {\n // Безликое «Remove tag» на двадцати кнопках подряд не даёт выбрать нужную:\n // имя обязано называть сам тег.\n return props.removeTagLabel ?? t('gr.inputTag.removeTagNamed', 'Remove tag {tag}', { tag })\n}\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\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/**\n * Инстансы чипов: у кольца цель — кнопка снятия внутри чипа, и достаётся она\n * через `defineExpose` (`removeEl`), а не селектором по DOM.\n */\nconst chipRefs = ref<Array<{ removeEl: HTMLButtonElement | null } | null>>([])\n\nfunction setChipRef(index: number) {\n return (el: unknown): void => {\n chipRefs.value[index] = el as { removeEl: HTMLButtonElement | null } | null\n }\n}\n\n/**\n * Проп `tagSize` объявлен по шкале бейджа и остаётся публичным контрактом:\n * `md` обязан означать для потребителя тот же кегль, что и раньше.\n */\nconst chipSize = computed(() => chipSizeForBadgeScale(props.tagSize))\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\nfunction blur(): void {\n inputEl.value?.blur()\n}\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !isDisabled.value && !isReadonly.value)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\n// Добавление, удаление и достигнутый предел — события, а не состояние виджета:\n// показывать их негде, объявить нужно. Это работа общего живого региона.\nconst { announce } = useAnnouncer()\n\n/**\n * Roving tabindex по крестикам: двадцать тегов давали двадцать одну остановку\n * `Tab`. В таб-порядке ровно один крестик, между ними ходят стрелками.\n *\n * Адресация индексом, а не значением тега: теги допускают повторы, и по\n * значению два одинаковых чипа было бы не различить.\n */\nconst tagIndexes = computed(() => props.modelValue.map((_, index) => index))\n\nconst roving = useRovingFocus<number>({\n items: () => tagIndexes.value,\n elementFor: index => chipRefs.value[index]?.removeEl,\n orientation: () => 'horizontal',\n // Ряд чипов — не кольцо: у него есть край, и за краем стоит поле ввода.\n wrap: () => false,\n onOverflow: (edge) => {\n // За последним чипом — поле ввода: продолжение того же ряда. Слева от\n // первого — начало строки, фокус остаётся на месте.\n if (edge === 'end')\n focus()\n return true\n },\n // Удаление чипа перерисовывает ряд: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\n\nasync function focusTag(index: number): Promise<void> {\n const last = props.modelValue.length - 1\n if (last < 0) {\n focus()\n return\n }\n\n await roving.focusKey(Math.min(Math.max(index, 0), last))\n}\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n const added: string[] = []\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n added.push(tag)\n emit('add', tag)\n }\n\n if (!added.length)\n return false\n\n emit('update:modelValue', next)\n emit('change', next)\n announce(added.length === 1\n ? t('gr.inputTag.added', 'Tag added: {tag}', { tag: added[0]! })\n : t('gr.inputTag.addedMany', '{count} tags added', { count: added.length }))\n\n return true\n}\n\n// Счётчик запуска: пока идёт асинхронная проверка, пользователь успевает нажать\n// Enter второй раз — результат устаревшей проверки дописывать нельзя.\nlet validationRun = 0\nconst validating = ref(false)\nconst isBusy = computed(() => props.loading || validating.value)\n\nasync function filterAllowed(tags: string[], run: number): Promise<string[] | null> {\n const check = props.beforeAdd\n if (!check)\n return tags\n\n const allowed: string[] = []\n\n for (const tag of tags) {\n const ok = await check(tag)\n if (run !== validationRun)\n return null\n\n if (ok)\n allowed.push(tag)\n else\n emit('reject', tag)\n }\n\n return allowed\n}\n\nasync function commitInput(): Promise<void> {\n if (!canEdit.value || !inputValue.value)\n return\n\n if (isMaxed.value) {\n announce(t('gr.inputTag.limitReached', 'Tag limit reached'))\n return\n }\n\n const raw = inputValue.value\n const tags = splitToTags(raw)\n if (!tags.length)\n return\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n const allowed = await filterAllowed(tags, run)\n\n if (run === validationRun)\n validating.value = false\n\n if (allowed === null || !allowed.length)\n return\n\n const changed = addMany(allowed)\n // Значение могло измениться, пока шла проверка: стирать чужой ввод нельзя.\n if (changed && props.clearInputOnAdd && inputValue.value === raw)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('change', next)\n emit('remove', removed, index)\n announce(t('gr.inputTag.removed', 'Tag removed: {tag}', { tag: removed }))\n}\n\n/**\n * Правка тега на месте.\n *\n * Индекс правимого чипа и черновик его значения. Черновик отдельно от модели:\n * пока пользователь печатает, набор не трогается — иначе `Escape` было бы\n * нечем отменять.\n */\nconst editingIndex = ref<number | null>(null)\nconst editDraft = ref('')\n/** Значение на момент входа в правку: по нему видно, что набор сменили снаружи. */\nconst editOriginal = ref('')\n/**\n * Свой счётчик гонок, отдельный от `validationRun`.\n *\n * Общий отменял бы проверку правки при добавлении тега — а к тому моменту\n * редактор уже закрыт, и набранное восстановить нечем.\n */\nlet editValidationRun = 0\n/**\n * Сессия закрывается.\n *\n * `closeEdit` возвращает фокус **до** размонтирования поля, то есть ждёт тик —\n * и в это окно приходит `blur` от переезда фокуса. Без флага он успевал\n * закоммитить то, что пользователь только что отменил.\n */\nlet editClosing = false\n/**\n * Узел поля правки. Функцией, а не строковым `ref`: поле стоит внутри `v-for`,\n * и там Vue складывает совпадающие `ref` в массив — `focus()` у массива нет.\n */\nconst editInputEl = ref<HTMLInputElement | null>(null)\n\nfunction setEditInputRef(el: unknown): void {\n editInputEl.value = el instanceof HTMLInputElement ? el : null\n}\n\nconst canEditTag = computed(() => props.editable && canEdit.value)\n\n/*\n * Фокусируемый узел у чипа один — кнопка снятия, и `F2` нажимают на ней. Без\n * `tagClosable` в правку можно попасть только двойным кликом, то есть с\n * клавиатуры — никак.\n */\nif (__GR_DEV__) {\n watchEffect(() => {\n if (props.editable && !props.tagClosable) {\n console.warn(\n '[granularity] GrInputTag: `editable` без `tagClosable` недостижим с клавиатуры — '\n + '`F2` нажимают на кнопке снятия, а она единственный фокусируемый узел чипа.',\n )\n }\n })\n}\n\n/**\n * Правка — немодальный слой общего стека, и `Escape` приходит оттуда, а не из\n * локального обработчика. `overlayStack` слушает `keydown` в capture-фазе на\n * `window` и гасит событие, когда стек непуст: внутри `GrModal` локальный\n * обработчик не сработал бы вовсе, а модалка закрылась бы вместе с правкой.\n */\nconst isEditingAny = computed({\n get: () => editingIndex.value !== null,\n set: (value) => {\n if (!value && editingIndex.value !== null)\n cancelEdit(editingIndex.value)\n },\n})\n\nuseDismissible(isEditingAny, () => {\n if (editingIndex.value !== null)\n cancelEdit(editingIndex.value)\n})\n\nfunction isEditing(index: number): boolean {\n return editingIndex.value === index\n}\n\nasync function startEdit(index: number): Promise<void> {\n if (!canEditTag.value)\n return\n\n const current = props.modelValue[index]\n if (current === undefined)\n return\n\n editingIndex.value = index\n editDraft.value = current\n editOriginal.value = current\n\n await nextTick()\n editInputEl.value?.focus()\n editInputEl.value?.select()\n}\n\n/**\n * Закрыть правку и вернуть фокус на крестик того же чипа.\n *\n * Через тик обязательно: ключ чипа зависит от значения тега, поэтому после\n * коммита Vue пересоздаёт узел — `removeEl` к этому моменту уже другой.\n */\nasync function closeEdit(index: number, restoreFocus: boolean): Promise<void> {\n editClosing = true\n\n // Фокус возвращаем **до** размонтирования редактора: иначе `focusout` уйдёт\n // с `relatedTarget: null`, а `GrFormField` считает это уходом из поля и\n // гоняет валидацию на каждую правку.\n if (restoreFocus)\n await roving.focusKey(index)\n\n editingIndex.value = null\n editDraft.value = ''\n editOriginal.value = ''\n editClosing = false\n}\n\n/** Фокус ещё в поле правки — значит его и возвращаем. Ушёл сам — не трогаем. */\nfunction editorHoldsFocus(): boolean {\n return document.activeElement === editInputEl.value\n}\n\nfunction cancelEdit(index: number): void {\n void closeEdit(index, editorHoldsFocus())\n}\n\n/**\n * Подтверждение правки.\n *\n * Проверка дубликатов исключает сам правимый индекс: иначе тег нельзя было бы\n * подтвердить самим собой. `beforeAdd` назван про добавление, но правило у\n * тега одно, и второго пропа ради этого не заводится — отказ возвращает\n * прежнее значение и закрывает правку.\n */\nasync function commitEdit(index: number, options: { fromBlur?: boolean } = {}): Promise<void> {\n if (editClosing || !canEditTag.value || editingIndex.value !== index)\n return\n\n const previous = props.modelValue[index]\n if (previous === undefined)\n return\n\n const restore = editorHoldsFocus()\n const value = normalizeTag(editDraft.value)\n\n if (!value) {\n // Пустое по `Enter` — снятие тега: пустой ввод и в поле не создаёт тега.\n // Пустое по уходу фокуса — ничего: удаление обязано остаться явным\n // действием, иначе «стёр текст и отвлёкся» стоит тега.\n await closeEdit(index, restore)\n if (!options.fromBlur)\n removeAt(index)\n return\n }\n\n if (value === previous) {\n await closeEdit(index, restore)\n return\n }\n\n const duplicate = !props.allowDuplicates\n && props.modelValue.some((tag, i) => i !== index && tag === value)\n\n if (duplicate) {\n await closeEdit(index, restore)\n announce(t('gr.inputTag.editRejected', 'Tag {tag} was not applied', { tag: value }))\n return\n }\n\n /*\n * Проверка зовётся напрямую, а не через `filterAllowed`: тот сверяется с\n * `validationRun`, то есть со счётчиком добавления. Правка ведёт свой —\n * иначе добавление тега отменяло бы идущую проверку правки, а к тому моменту\n * редактор закрыт и набранное восстановить нечем.\n */\n const run = ++editValidationRun\n const check = props.beforeAdd\n validating.value = Boolean(check)\n\n const ok = check ? await check(value) : true\n\n if (run === editValidationRun)\n validating.value = false\n\n // Сессию сменили, пока шла проверка: своё значение она не дописывает.\n if (run !== editValidationRun || editingIndex.value !== index)\n return\n\n if (!ok) {\n emit('reject', value)\n await closeEdit(index, restore)\n announce(t('gr.inputTag.editRejected', 'Tag {tag} was not applied', { tag: value }))\n return\n }\n\n const next = props.modelValue.slice()\n next[index] = value\n\n emit('update:modelValue', next)\n emit('change', next)\n emit('edit', value, index, previous)\n announce(t('gr.inputTag.edited', 'Tag changed: {tag}', { tag: value }))\n\n await closeEdit(index, restore)\n}\n\n/**\n * Клик внутри правящегося чипа принадлежит редактору.\n *\n * На корне висит `@click=\"focus\"`, и без этого клик, которым ставят каретку в\n * поле правки, уводил бы фокус в главный ввод — то есть попасть мышью в поле\n * было бы нельзя.\n */\nfunction onTagClick(e: MouseEvent, index: number): void {\n if (editingIndex.value === index)\n e.stopPropagation()\n}\n\n/**\n * Двойной клик по крестику не открывает правку: первый клик уже снял тег, и на\n * этой позиции стоит другой — правка открылась бы не тому.\n */\nfunction onTagDblclick(e: MouseEvent, index: number): void {\n if (!canEditTag.value)\n return\n\n if (e.target instanceof Element && e.target.closest('[data-gr-chip-close]'))\n return\n\n e.preventDefault()\n void startEdit(index)\n}\n\n/**\n * Набор или доступность сменились снаружи — правка закрывается без коммита.\n *\n * Индекс правки к чужому набору не относится: теги могли прийти с сервера,\n * форму могли сбросить, поле — заблокировать. Дописать туда своё значение\n * значит переписать не тот тег.\n */\nwatch(\n [() => props.modelValue, canEditTag],\n ([tags, allowed]) => {\n const index = editingIndex.value\n if (index === null)\n return\n\n if (!allowed || tags[index] !== editOriginal.value)\n void closeEdit(index, false)\n },\n)\n\nfunction onEditKeydown(e: KeyboardEvent, index: number): void {\n if (isComposingEvent(e))\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitEdit(index)\n return\n }\n\n if (e.key === 'Escape') {\n e.preventDefault()\n cancelEdit(index)\n }\n}\n\n/**\n * Уход фокуса подтверждает, а не отменяет, — и это осознанное расхождение с\n * `addOnBlur`. Тот решает, становится ли **недонабранное новое** тегом, и там\n * отбросить безопасно: до этого не было ничего. Правка же начинается с\n * существующего значения, которое пользователь решил изменить, и тихо вернуть\n * его набранное — как раз тот исход, который удивит. Отказаться есть чем:\n * `Escape`.\n */\nfunction onEditBlur(index: number): void {\n if (!editClosing && editingIndex.value === index)\n void commitEdit(index, { fromBlur: true })\n}\n\n/** Удаление с клавиатуры: фокус переезжает на соседний чип, а не пропадает. */\nasync function removeAtFromKeyboard(index: number): Promise<void> {\n removeAt(index)\n await nextTick()\n\n if (props.modelValue.length === 0) {\n focus()\n return\n }\n\n await focusTag(Math.min(index, props.modelValue.length - 1))\n}\n\nfunction clearAll(): void {\n if (!canEdit.value || props.modelValue.length === 0)\n return\n\n emit('update:modelValue', [])\n emit('change', [])\n emit('clear')\n announce(t('gr.inputTag.cleared', 'All tags removed'))\n focus()\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n // Enter/сепаратор во время IME-композиции коммитят её, а не тег.\n if (isComposingEvent(e))\n return\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if (inputValue.value.length === 0 && props.modelValue.length > 0) {\n if (e.key === 'Backspace') {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n return\n }\n\n // Из пустого поля стрелка влево уводит на последний чип — дальше по чипам\n // работают те же стрелки, `Tab` для этого не нужен.\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n void focusTag(props.modelValue.length - 1)\n }\n }\n}\n\nfunction onTagKeydown(e: KeyboardEvent, index: number): void {\n // Пока чип правится, клавиши принадлежат полю: иначе `Backspace` снёс бы\n // правящийся тег, а стрелки увезли бы фокус на соседа прямо во время набора.\n if (editingIndex.value === index)\n return\n\n if (roving.handleNavigationKeys(e)) {\n return\n }\n\n // `F2`, а не `Enter`: цель кольца — настоящая кнопка снятия, и `Enter` на\n // ней уже означает «удалить» нативной активацией.\n if (e.key === 'F2' && canEditTag.value) {\n e.preventDefault()\n void startEdit(index)\n return\n }\n\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault()\n void removeAtFromKeyboard(index)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n void commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n void filterAllowed(tags, run).then((allowed) => {\n if (run === validationRun)\n validating.value = false\n\n if (allowed?.length)\n addMany(allowed)\n })\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: resolvedSize.value,\n state: props.state,\n invalid: isInvalid.value,\n disabled: isDisabled.value,\n })\n})\n\nconst inputClassName = computed(() => grInputTagInputClass(resolvedSize.value))\n\nconst showClearAll = computed(() => resolvedClearable.value && canEdit.value && props.modelValue.length > 0)\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n\ndefineExpose({ focus, blur, clear: clearAll })\n\nif (__GR_DEV__) {\n watchEffect(() => {\n if (!Array.isArray(props.modelValue)) {\n console.warn(\n `[granularity] GrInputTag: обязательный проп \\`modelValue\\` должен быть массивом — получено ${String(props.modelValue)}.`,\n )\n }\n })\n}\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-input-tag\n data-testid=\"gr-input-tag\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <span\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-input-tag-prefix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"prefixStyle\"\n >\n <slot name=\"prefix\" />\n </span>\n\n <!-- Нативная форма: hidden на каждый тег — стандартная сериализация набора. -->\n <template v-if=\"name\">\n <input\n v-for=\"(tag, tagIndex) in modelValue\"\n :key=\"`hidden-${tagIndex}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"tag\"\n >\n </template>\n <!--\n `display: contents` — список нужен ради роли, а не ради раскладки: чипы\n обязаны переноситься в одном потоке с полем ввода.\n -->\n <span v-if=\"modelValue.length\" role=\"list\" class=\"contents\">\n <GrChip\n v-for=\"(tag, i) in modelValue\"\n :key=\"i\"\n :ref=\"setChipRef(i)\"\n role=\"listitem\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"chipSize\"\n :radius=\"tagRadius\"\n :closable=\"showRemove\"\n :remove-label=\"removeTagLabelFor(tag)\"\n :remove-tabindex=\"roving.tabindexFor(i)\"\n data-gr-input-tag-item\n data-testid=\"gr-input-tag-item\"\n :aria-keyshortcuts=\"canEditTag ? 'F2' : undefined\"\n :data-index=\"i\"\n @remove=\"removeAt(i)\"\n @focusin=\"roving.setActive(i)\"\n @keydown=\"onTagKeydown($event, i)\"\n @click=\"onTagClick($event, i)\"\n @dblclick=\"onTagDblclick($event, i)\"\n >\n <!--\n В режиме правки поле встаёт вместо содержимого — в том числе вместо\n пользовательского `#tag`: слот описывает показ тега, а правка это\n режим самого компонента.\n -->\n <input\n v-if=\"isEditing(i)\"\n :ref=\"setEditInputRef\"\n v-model=\"editDraft\"\n data-gr-input-tag-edit\n data-testid=\"gr-input-tag-edit\"\n :class=\"tagEditInputClass\"\n :size=\"Math.max(editDraft.length, 2)\"\n :aria-label=\"t('gr.inputTag.editTag', 'Edit tag {tag}', { tag })\"\n @keydown.stop=\"onEditKeydown($event, i)\"\n @blur=\"onEditBlur(i)\"\n >\n\n <slot v-else name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n </GrChip>\n </span>\n\n <input\n :id=\"resolvedId\"\n ref=\"inputEl\"\n data-gr-input-tag-input\n data-testid=\"gr-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :placeholder=\"placeholderText\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-busy=\"isBusy ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--gr-muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n\n <span\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-input-tag-suffix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"suffixStyle\"\n >\n <slot name=\"suffix\" />\n </span>\n\n <span\n v-if=\"isBusy\"\n data-gr-input-tag-spinner\n :class=\"spinnerClass\"\n aria-hidden=\"true\"\n >\n <GrIcon size=\"sm\">\n <IconLoader class=\"animate-spin\" />\n </GrIcon>\n </span>\n\n <span\n v-if=\"signalState\"\n data-gr-input-tag-state\n :class=\"stateIconClass\"\n aria-hidden=\"true\"\n >\n <component :is=\"stateIcon\" class=\"h-4 w-4\" />\n </span>\n\n <span v-if=\"signalState\" :id=\"stateTextId\" data-gr-input-tag-state-text class=\"sr-only\">{{ stateText }}</span>\n\n <button\n v-if=\"showClearAll\"\n type=\"button\"\n data-gr-input-tag-clear\n :class=\"clearButtonClass\"\n :aria-label=\"resolvedClearAllLabel\"\n @mousedown.prevent.stop\n @click.stop=\"clearAll\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useId, watch, watchEffect } from 'vue'\n\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrChip from '../GrChip/GrChip.vue'\nimport { chipSizeForBadgeScale } from '../GrChip/grChipStyles'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\nimport IconCheckCircle from '~icons/lucide/check-circle'\nimport IconAlertTriangle from '~icons/lucide/alert-triangle'\nimport IconLoader from '~icons/lucide/loader-2'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useDismissible } from '../../composables/useDismissible'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport {\n controlSignalState,\n controlStateFallbackText,\n controlStateIconClass,\n controlStateIconColors,\n controlStateTextKey,\n} from '../shared/controlState'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nimport {\n clearButtonClass,\n grInputTagInputClass,\n grInputTagWrapperClass,\n spinnerClass,\n tagEditInputClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n /** Обязательное поле (`aria-required`). Складывается с `required` у `GrFormField`. */\n required?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n /**\n * Проверка тега перед добавлением. Может быть асинхронной (проверка на\n * сервере). Отклонённый тег не добавляется и уходит в событие `reject`.\n */\n beforeAdd?: (tag: string) => boolean | Promise<boolean>\n /**\n * Правка тега на месте: `F2` на чипе или двойной клик по нему открывают\n * поле, `Enter` подтверждает, `Escape` отменяет.\n *\n * Проп, а не поведение по умолчанию: двойной клик по чипу сегодня ничего не\n * делает, и превращать его во вход в правку у всех потребителей — тихая\n * смена поведения.\n */\n editable?: boolean\n /** Кнопка «снести все теги». Настраивается через `GrConfigProvider`. */\n clearable?: boolean\n /** Фоновая работа: спиннер + `aria-busy`. Асинхронный `beforeAdd` поднимает его сам. */\n loading?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n /** i18n aria-label кнопки «снести все». */\n clearAllLabel?: string\n /**\n * Имя контрола, когда он используется вне `GrFormField`. Внутри поля имя даёт\n * связка с его `<label for>` — там проп не нужен. Без того и другого у инпута\n * нет доступного имени вовсе: placeholder именем не считается.\n */\n ariaLabel?: string\n /** Имя для нативной формы: hidden input на каждый тег. */\n name?: string\n /**\n * Ширины аддонов `prefix`/`suffix` — общий контракт контролов пакета\n * (`docs/form-controls.md`).\n */\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n prefixFixed?: boolean\n suffixFixed?: boolean\n}\n\nexport interface GrInputTagEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n /** Тег изменён на месте: новое значение, его позиция и то, что стояло раньше. */\n (e: 'edit', value: string, index: number, previous: string): void\n /** Тег не прошёл `beforeAdd`. */\n (e: 'reject', value: string): void\n /** Набор снесён кнопкой «очистить». */\n (e: 'clear'): void\n /** Набор тегов изменился. */\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n state: 'default',\n // Настраивается через `GrConfigProvider`; дефолт — в резолвере ниже.\n size: undefined,\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n editable: false,\n beforeAdd: undefined,\n clearable: undefined,\n loading: false,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: undefined,\n clearAllLabel: undefined,\n ariaLabel: undefined,\n name: undefined,\n },\n)\n\nconst emit = defineEmits<GrInputTagEmits>()\ndefineSlots<{\n /** Аддон слева от чипов: иконка, метка. */\n prefix?: () => any\n /** Аддон справа, перед кнопкой очистки. */\n suffix?: () => any\n /** Свой чип: `remove` снимает значение. */\n tag?: (props: { tag: string, index: number, remove: () => void }) => any\n}>()\n\n// Fallback из контекста `GrFormField` (id/aria-describedby/invalid/required) —\n// как у GrInput и GrSelect: контрол не знает про форму, знает только про поле.\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\n// Эффективные значения: локальный проп → `GrConfigProvider` → дефолт компонента.\n/** Ширина аддона по умолчанию — та же лестница, что у `GrInput`. */\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrInputTagSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrInputTag' })\n\n/**\n * Аддоны — флекс-соседи поля: оболочка тегового поля и так флекс-строка с\n * бейджами, поэтому места паддингом резервировать не нужно.\n */\nconst { hasPrefix, hasSuffix, prefixEl, suffixEl, prefixStyle, suffixStyle } = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => '0px',\n})\nconst resolvedClearable = useGrComponentProp('GrInputTag', 'clearable', () => props.clearable, false)\n\nconst { t } = useGranularityTranslations()\n\n/**\n * Небуквенный признак состояния: иконка для глаз, скрытая подпись для\n * скринридера. Разбор — `shared/controlState`.\n */\nconst stateTextId = useId()\nconst signalState = computed(() => controlSignalState(props.state, isInvalid.value))\nconst stateIcon = computed(() => (signalState.value === 'success' ? IconCheckCircle : IconAlertTriangle))\nconst stateIconClass = computed(() => (signalState.value\n ? `${controlStateIconClass} ${controlStateIconColors[signalState.value]}`\n : ''))\nconst stateText = computed(() => (signalState.value\n ? t(controlStateTextKey[signalState.value], controlStateFallbackText[signalState.value])\n : ''))\n\nconst describedBy = computed(() =>\n [field?.describedById.value, signalState.value ? stateTextId : undefined]\n .filter(Boolean)\n .join(' ') || undefined,\n)\nconst resolvedClearAllLabel = computed(() => props.clearAllLabel ?? t('gr.inputTag.clearAll', 'Clear all tags'))\n\nfunction removeTagLabelFor(tag: string): string {\n // Безликое «Remove tag» на двадцати кнопках подряд не даёт выбрать нужную:\n // имя обязано называть сам тег.\n return props.removeTagLabel ?? t('gr.inputTag.removeTagNamed', 'Remove tag {tag}', { tag })\n}\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\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/**\n * Инстансы чипов: у кольца цель — кнопка снятия внутри чипа, и достаётся она\n * через `defineExpose` (`removeEl`), а не селектором по DOM.\n */\nconst chipRefs = ref<Array<{ removeEl: HTMLButtonElement | null } | null>>([])\n\nfunction setChipRef(index: number) {\n return (el: unknown): void => {\n chipRefs.value[index] = el as { removeEl: HTMLButtonElement | null } | null\n }\n}\n\n/**\n * Проп `tagSize` объявлен по шкале бейджа и остаётся публичным контрактом:\n * `md` обязан означать для потребителя тот же кегль, что и раньше.\n */\nconst chipSize = computed(() => chipSizeForBadgeScale(props.tagSize))\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\nfunction blur(): void {\n inputEl.value?.blur()\n}\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !isDisabled.value && !isReadonly.value)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\n// Добавление, удаление и достигнутый предел — события, а не состояние виджета:\n// показывать их негде, объявить нужно. Это работа общего живого региона.\nconst { announce } = useAnnouncer()\n\n/**\n * Roving tabindex по крестикам: двадцать тегов давали двадцать одну остановку\n * `Tab`. В таб-порядке ровно один крестик, между ними ходят стрелками.\n *\n * Адресация индексом, а не значением тега: теги допускают повторы, и по\n * значению два одинаковых чипа было бы не различить.\n */\nconst tagIndexes = computed(() => props.modelValue.map((_, index) => index))\n\nconst roving = useRovingFocus<number>({\n items: () => tagIndexes.value,\n elementFor: index => chipRefs.value[index]?.removeEl,\n orientation: () => 'horizontal',\n // Ряд чипов — не кольцо: у него есть край, и за краем стоит поле ввода.\n wrap: () => false,\n onOverflow: (edge) => {\n // За последним чипом — поле ввода: продолжение того же ряда. Слева от\n // первого — начало строки, фокус остаётся на месте.\n if (edge === 'end')\n focus()\n return true\n },\n // Удаление чипа перерисовывает ряд: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\n\nasync function focusTag(index: number): Promise<void> {\n const last = props.modelValue.length - 1\n if (last < 0) {\n focus()\n return\n }\n\n await roving.focusKey(Math.min(Math.max(index, 0), last))\n}\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n const added: string[] = []\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n added.push(tag)\n emit('add', tag)\n }\n\n if (!added.length)\n return false\n\n emit('update:modelValue', next)\n emit('change', next)\n announce(added.length === 1\n ? t('gr.inputTag.added', 'Tag added: {tag}', { tag: added[0]! })\n : t('gr.inputTag.addedMany', '{count} tags added', { count: added.length }))\n\n return true\n}\n\n// Счётчик запуска: пока идёт асинхронная проверка, пользователь успевает нажать\n// Enter второй раз — результат устаревшей проверки дописывать нельзя.\nlet validationRun = 0\nconst validating = ref(false)\nconst isBusy = computed(() => props.loading || validating.value)\n\nasync function filterAllowed(tags: string[], run: number): Promise<string[] | null> {\n const check = props.beforeAdd\n if (!check)\n return tags\n\n const allowed: string[] = []\n\n for (const tag of tags) {\n const ok = await check(tag)\n if (run !== validationRun)\n return null\n\n if (ok)\n allowed.push(tag)\n else\n emit('reject', tag)\n }\n\n return allowed\n}\n\nasync function commitInput(): Promise<void> {\n if (!canEdit.value || !inputValue.value)\n return\n\n if (isMaxed.value) {\n announce(t('gr.inputTag.limitReached', 'Tag limit reached'))\n return\n }\n\n const raw = inputValue.value\n const tags = splitToTags(raw)\n if (!tags.length)\n return\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n const allowed = await filterAllowed(tags, run)\n\n if (run === validationRun)\n validating.value = false\n\n if (allowed === null || !allowed.length)\n return\n\n const changed = addMany(allowed)\n // Значение могло измениться, пока шла проверка: стирать чужой ввод нельзя.\n if (changed && props.clearInputOnAdd && inputValue.value === raw)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('change', next)\n emit('remove', removed, index)\n announce(t('gr.inputTag.removed', 'Tag removed: {tag}', { tag: removed }))\n}\n\n/**\n * Правка тега на месте.\n *\n * Индекс правимого чипа и черновик его значения. Черновик отдельно от модели:\n * пока пользователь печатает, набор не трогается — иначе `Escape` было бы\n * нечем отменять.\n */\nconst editingIndex = ref<number | null>(null)\nconst editDraft = ref('')\n/** Значение на момент входа в правку: по нему видно, что набор сменили снаружи. */\nconst editOriginal = ref('')\n/**\n * Свой счётчик гонок, отдельный от `validationRun`.\n *\n * Общий отменял бы проверку правки при добавлении тега — а к тому моменту\n * редактор уже закрыт, и набранное восстановить нечем.\n */\nlet editValidationRun = 0\n/**\n * Сессия закрывается.\n *\n * `closeEdit` возвращает фокус **до** размонтирования поля, то есть ждёт тик —\n * и в это окно приходит `blur` от переезда фокуса. Без флага он успевал\n * закоммитить то, что пользователь только что отменил.\n */\nlet editClosing = false\n/**\n * Узел поля правки. Функцией, а не строковым `ref`: поле стоит внутри `v-for`,\n * и там Vue складывает совпадающие `ref` в массив — `focus()` у массива нет.\n */\nconst editInputEl = ref<HTMLInputElement | null>(null)\n\nfunction setEditInputRef(el: unknown): void {\n editInputEl.value = el instanceof HTMLInputElement ? el : null\n}\n\nconst canEditTag = computed(() => props.editable && canEdit.value)\n\n/*\n * Фокусируемый узел у чипа один — кнопка снятия, и `F2` нажимают на ней. Без\n * `tagClosable` в правку можно попасть только двойным кликом, то есть с\n * клавиатуры — никак.\n */\nif (__GR_DEV__) {\n watchEffect(() => {\n if (props.editable && !props.tagClosable) {\n console.warn(\n '[granularity] GrInputTag: `editable` без `tagClosable` недостижим с клавиатуры — '\n + '`F2` нажимают на кнопке снятия, а она единственный фокусируемый узел чипа.',\n )\n }\n })\n}\n\n/**\n * Правка — немодальный слой общего стека, и `Escape` приходит оттуда, а не из\n * локального обработчика. `overlayStack` слушает `keydown` в capture-фазе на\n * `window` и гасит событие, когда стек непуст: внутри `GrModal` локальный\n * обработчик не сработал бы вовсе, а модалка закрылась бы вместе с правкой.\n */\nconst isEditingAny = computed({\n get: () => editingIndex.value !== null,\n set: (value) => {\n if (!value && editingIndex.value !== null)\n cancelEdit(editingIndex.value)\n },\n})\n\nuseDismissible(isEditingAny, () => {\n if (editingIndex.value !== null)\n cancelEdit(editingIndex.value)\n})\n\nfunction isEditing(index: number): boolean {\n return editingIndex.value === index\n}\n\nasync function startEdit(index: number): Promise<void> {\n if (!canEditTag.value)\n return\n\n const current = props.modelValue[index]\n if (current === undefined)\n return\n\n editingIndex.value = index\n editDraft.value = current\n editOriginal.value = current\n\n await nextTick()\n editInputEl.value?.focus()\n editInputEl.value?.select()\n}\n\n/**\n * Закрыть правку и вернуть фокус на крестик того же чипа.\n *\n * Через тик обязательно: ключ чипа зависит от значения тега, поэтому после\n * коммита Vue пересоздаёт узел — `removeEl` к этому моменту уже другой.\n */\nasync function closeEdit(index: number, restoreFocus: boolean): Promise<void> {\n editClosing = true\n\n // Фокус возвращаем **до** размонтирования редактора: иначе `focusout` уйдёт\n // с `relatedTarget: null`, а `GrFormField` считает это уходом из поля и\n // гоняет валидацию на каждую правку.\n if (restoreFocus)\n await roving.focusKey(index)\n\n editingIndex.value = null\n editDraft.value = ''\n editOriginal.value = ''\n editClosing = false\n}\n\n/** Фокус ещё в поле правки — значит его и возвращаем. Ушёл сам — не трогаем. */\nfunction editorHoldsFocus(): boolean {\n return document.activeElement === editInputEl.value\n}\n\nfunction cancelEdit(index: number): void {\n void closeEdit(index, editorHoldsFocus())\n}\n\n/**\n * Подтверждение правки.\n *\n * Проверка дубликатов исключает сам правимый индекс: иначе тег нельзя было бы\n * подтвердить самим собой. `beforeAdd` назван про добавление, но правило у\n * тега одно, и второго пропа ради этого не заводится — отказ возвращает\n * прежнее значение и закрывает правку.\n */\nasync function commitEdit(index: number, options: { fromBlur?: boolean } = {}): Promise<void> {\n if (editClosing || !canEditTag.value || editingIndex.value !== index)\n return\n\n const previous = props.modelValue[index]\n if (previous === undefined)\n return\n\n const restore = editorHoldsFocus()\n const value = normalizeTag(editDraft.value)\n\n if (!value) {\n // Пустое по `Enter` — снятие тега: пустой ввод и в поле не создаёт тега.\n // Пустое по уходу фокуса — ничего: удаление обязано остаться явным\n // действием, иначе «стёр текст и отвлёкся» стоит тега.\n await closeEdit(index, restore)\n if (!options.fromBlur)\n removeAt(index)\n return\n }\n\n if (value === previous) {\n await closeEdit(index, restore)\n return\n }\n\n const duplicate = !props.allowDuplicates\n && props.modelValue.some((tag, i) => i !== index && tag === value)\n\n if (duplicate) {\n await closeEdit(index, restore)\n announce(t('gr.inputTag.editRejected', 'Tag {tag} was not applied', { tag: value }))\n return\n }\n\n /*\n * Проверка зовётся напрямую, а не через `filterAllowed`: тот сверяется с\n * `validationRun`, то есть со счётчиком добавления. Правка ведёт свой —\n * иначе добавление тега отменяло бы идущую проверку правки, а к тому моменту\n * редактор закрыт и набранное восстановить нечем.\n */\n const run = ++editValidationRun\n const check = props.beforeAdd\n validating.value = Boolean(check)\n\n const ok = check ? await check(value) : true\n\n if (run === editValidationRun)\n validating.value = false\n\n // Сессию сменили, пока шла проверка: своё значение она не дописывает.\n if (run !== editValidationRun || editingIndex.value !== index)\n return\n\n if (!ok) {\n emit('reject', value)\n await closeEdit(index, restore)\n announce(t('gr.inputTag.editRejected', 'Tag {tag} was not applied', { tag: value }))\n return\n }\n\n const next = props.modelValue.slice()\n next[index] = value\n\n emit('update:modelValue', next)\n emit('change', next)\n emit('edit', value, index, previous)\n announce(t('gr.inputTag.edited', 'Tag changed: {tag}', { tag: value }))\n\n await closeEdit(index, restore)\n}\n\n/**\n * Клик внутри правящегося чипа принадлежит редактору.\n *\n * На корне висит `@click=\"focus\"`, и без этого клик, которым ставят каретку в\n * поле правки, уводил бы фокус в главный ввод — то есть попасть мышью в поле\n * было бы нельзя.\n */\nfunction onTagClick(e: MouseEvent, index: number): void {\n if (editingIndex.value === index)\n e.stopPropagation()\n}\n\n/**\n * Двойной клик по крестику не открывает правку: первый клик уже снял тег, и на\n * этой позиции стоит другой — правка открылась бы не тому.\n */\nfunction onTagDblclick(e: MouseEvent, index: number): void {\n if (!canEditTag.value)\n return\n\n if (e.target instanceof Element && e.target.closest('[data-gr-chip-close]'))\n return\n\n e.preventDefault()\n void startEdit(index)\n}\n\n/**\n * Набор или доступность сменились снаружи — правка закрывается без коммита.\n *\n * Индекс правки к чужому набору не относится: теги могли прийти с сервера,\n * форму могли сбросить, поле — заблокировать. Дописать туда своё значение\n * значит переписать не тот тег.\n */\nwatch(\n [() => props.modelValue, canEditTag],\n ([tags, allowed]) => {\n const index = editingIndex.value\n if (index === null)\n return\n\n if (!allowed || tags[index] !== editOriginal.value)\n void closeEdit(index, false)\n },\n)\n\nfunction onEditKeydown(e: KeyboardEvent, index: number): void {\n if (isComposingEvent(e))\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitEdit(index)\n return\n }\n\n if (e.key === 'Escape') {\n e.preventDefault()\n cancelEdit(index)\n }\n}\n\n/**\n * Уход фокуса подтверждает, а не отменяет, — и это осознанное расхождение с\n * `addOnBlur`. Тот решает, становится ли **недонабранное новое** тегом, и там\n * отбросить безопасно: до этого не было ничего. Правка же начинается с\n * существующего значения, которое пользователь решил изменить, и тихо вернуть\n * его набранное — как раз тот исход, который удивит. Отказаться есть чем:\n * `Escape`.\n */\nfunction onEditBlur(index: number): void {\n if (!editClosing && editingIndex.value === index)\n void commitEdit(index, { fromBlur: true })\n}\n\n/** Удаление с клавиатуры: фокус переезжает на соседний чип, а не пропадает. */\nasync function removeAtFromKeyboard(index: number): Promise<void> {\n removeAt(index)\n await nextTick()\n\n if (props.modelValue.length === 0) {\n focus()\n return\n }\n\n await focusTag(Math.min(index, props.modelValue.length - 1))\n}\n\nfunction clearAll(): void {\n if (!canEdit.value || props.modelValue.length === 0)\n return\n\n emit('update:modelValue', [])\n emit('change', [])\n emit('clear')\n announce(t('gr.inputTag.cleared', 'All tags removed'))\n focus()\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n // Enter/сепаратор во время IME-композиции коммитят её, а не тег.\n if (isComposingEvent(e))\n return\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if (inputValue.value.length === 0 && props.modelValue.length > 0) {\n if (e.key === 'Backspace') {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n return\n }\n\n // Из пустого поля стрелка влево уводит на последний чип — дальше по чипам\n // работают те же стрелки, `Tab` для этого не нужен.\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n void focusTag(props.modelValue.length - 1)\n }\n }\n}\n\nfunction onTagKeydown(e: KeyboardEvent, index: number): void {\n // Пока чип правится, клавиши принадлежат полю: иначе `Backspace` снёс бы\n // правящийся тег, а стрелки увезли бы фокус на соседа прямо во время набора.\n if (editingIndex.value === index)\n return\n\n if (roving.handleNavigationKeys(e)) {\n return\n }\n\n // `F2`, а не `Enter`: цель кольца — настоящая кнопка снятия, и `Enter` на\n // ней уже означает «удалить» нативной активацией.\n if (e.key === 'F2' && canEditTag.value) {\n e.preventDefault()\n void startEdit(index)\n return\n }\n\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault()\n void removeAtFromKeyboard(index)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n void commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n void filterAllowed(tags, run).then((allowed) => {\n if (run === validationRun)\n validating.value = false\n\n if (allowed?.length)\n addMany(allowed)\n })\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: resolvedSize.value,\n state: props.state,\n invalid: isInvalid.value,\n disabled: isDisabled.value,\n })\n})\n\nconst inputClassName = computed(() => grInputTagInputClass(resolvedSize.value))\n\nconst showClearAll = computed(() => resolvedClearable.value && canEdit.value && props.modelValue.length > 0)\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n\ndefineExpose({ focus, blur, clear: clearAll })\n\nif (__GR_DEV__) {\n watchEffect(() => {\n if (!Array.isArray(props.modelValue)) {\n console.warn(\n `[granularity] GrInputTag: обязательный проп \\`modelValue\\` должен быть массивом — получено ${String(props.modelValue)}.`,\n )\n }\n })\n}\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-input-tag\n data-testid=\"gr-input-tag\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <span\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-input-tag-prefix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"prefixStyle\"\n >\n <slot name=\"prefix\" />\n </span>\n\n <!-- Нативная форма: hidden на каждый тег — стандартная сериализация набора. -->\n <template v-if=\"name\">\n <input\n v-for=\"(tag, tagIndex) in modelValue\"\n :key=\"`hidden-${tagIndex}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"tag\"\n >\n </template>\n <!--\n `display: contents` — список нужен ради роли, а не ради раскладки: чипы\n обязаны переноситься в одном потоке с полем ввода.\n -->\n <span v-if=\"modelValue.length\" role=\"list\" class=\"contents\">\n <GrChip\n v-for=\"(tag, i) in modelValue\"\n :key=\"i\"\n :ref=\"setChipRef(i)\"\n role=\"listitem\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"chipSize\"\n :radius=\"tagRadius\"\n :closable=\"showRemove\"\n :remove-label=\"removeTagLabelFor(tag)\"\n :remove-tabindex=\"roving.tabindexFor(i)\"\n data-gr-input-tag-item\n data-testid=\"gr-input-tag-item\"\n :aria-keyshortcuts=\"canEditTag ? 'F2' : undefined\"\n :data-index=\"i\"\n @remove=\"removeAt(i)\"\n @focusin=\"roving.setActive(i)\"\n @keydown=\"onTagKeydown($event, i)\"\n @click=\"onTagClick($event, i)\"\n @dblclick=\"onTagDblclick($event, i)\"\n >\n <!--\n В режиме правки поле встаёт вместо содержимого — в том числе вместо\n пользовательского `#tag`: слот описывает показ тега, а правка это\n режим самого компонента.\n -->\n <input\n v-if=\"isEditing(i)\"\n :ref=\"setEditInputRef\"\n v-model=\"editDraft\"\n data-gr-input-tag-edit\n data-testid=\"gr-input-tag-edit\"\n :class=\"tagEditInputClass\"\n :size=\"Math.max(editDraft.length, 2)\"\n :aria-label=\"t('gr.inputTag.editTag', 'Edit tag {tag}', { tag })\"\n @keydown.stop=\"onEditKeydown($event, i)\"\n @blur=\"onEditBlur(i)\"\n >\n\n <slot v-else name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n </GrChip>\n </span>\n\n <input\n :id=\"resolvedId\"\n ref=\"inputEl\"\n data-gr-input-tag-input\n data-testid=\"gr-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :placeholder=\"placeholderText\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-busy=\"isBusy ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--gr-muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n\n <span\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-input-tag-suffix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"suffixStyle\"\n >\n <slot name=\"suffix\" />\n </span>\n\n <span\n v-if=\"isBusy\"\n data-gr-input-tag-spinner\n :class=\"spinnerClass\"\n aria-hidden=\"true\"\n >\n <GrIcon size=\"sm\">\n <IconLoader class=\"animate-spin\" />\n </GrIcon>\n </span>\n\n <span\n v-if=\"signalState\"\n data-gr-input-tag-state\n :class=\"stateIconClass\"\n aria-hidden=\"true\"\n >\n <component :is=\"stateIcon\" class=\"h-4 w-4\" />\n </span>\n\n <span v-if=\"signalState\" :id=\"stateTextId\" data-gr-input-tag-state-text class=\"sr-only\">{{ stateText }}</span>\n\n <button\n v-if=\"showClearAll\"\n type=\"button\"\n data-gr-input-tag-clear\n :class=\"clearButtonClass\"\n :aria-label=\"resolvedClearAllLabel\"\n @mousedown.prevent.stop\n @click.stop=\"clearAll\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </button>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as grInputTagSafelist, t as grInputTagConfig } from "../../chunks/config-
|
|
2
|
-
import { t as GrInputTag_default } from "./chunks/GrInputTag-
|
|
1
|
+
import { n as grInputTagSafelist, t as grInputTagConfig } from "../../chunks/config-DG41PD9i.js";
|
|
2
|
+
import { t as GrInputTag_default } from "./chunks/GrInputTag-BzzNRBe3.js";
|
|
3
3
|
export { GrInputTag_default as GrInputTag, GrInputTag_default as default, grInputTagConfig, grInputTagSafelist };
|
package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js → GrJsonViewer-B6ZJ3GFH.js}
RENAMED
|
@@ -3,8 +3,8 @@ import { n as useGranularityTranslations } from "../../../chunks/granularityI18n
|
|
|
3
3
|
import { t as check_default } from "../../../chunks/check-BZI24Qs4.js";
|
|
4
4
|
import { t as GrButton_default } from "../../GrButton/chunks/GrButton-CS4TqMtG.js";
|
|
5
5
|
import { useAnnouncer } from "../../../composables/useAnnouncer.js";
|
|
6
|
-
import { t as GrInput_default } from "../../GrInput/chunks/GrInput-
|
|
7
|
-
import { t as GrTree_default } from "../../GrTree/chunks/GrTree-
|
|
6
|
+
import { t as GrInput_default } from "../../GrInput/chunks/GrInput-CoaFLpaU.js";
|
|
7
|
+
import { t as GrTree_default } from "../../GrTree/chunks/GrTree-DpgaP8hk.js";
|
|
8
8
|
import { a as jsonViewerCopyClass, c as jsonViewerMutedClass, d as jsonViewerRowClass, f as jsonViewerSearchClass, i as jsonViewerContentClass, l as jsonViewerPunctuationClass, m as jsonViewerValueClass, o as jsonViewerGroupClass, p as jsonViewerToolbarClass, r as jsonValueClass, s as jsonViewerKeyClass, u as jsonViewerRootClass } from "../../../chunks/config-DpAYidyY.js";
|
|
9
9
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, markRaw, normalizeClass, onBeforeUnmount, onMounted, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, unref, watch, withCtx, withModifiers } from "vue";
|
|
10
10
|
//#region ~icons/lucide/copy
|