@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrTransfer-CV7BL5UK.js","names":[],"sources":["../../../../src/components/GrTransfer/transferModel.ts","../../../../src/components/GrTransfer/transferGeometry.ts","../../../../src/components/GrTransfer/useTransferDrag.ts","../../../../src/components/GrTransfer/transferSelection.ts","../../../../src/components/GrTransfer/GrTransfer.vue","../../../../src/components/GrTransfer/GrTransfer.vue"],"sourcesContent":["/**\n * Порядок и состав панелей: чистая арифметика над ключами, без DOM и Vue.\n *\n * Вынесена отдельно по той же причине, что и `dragSortGeometry`: ошибка здесь\n * проявляется не исключением, а «строка встала не туда» или «выбор исчез после\n * перезагрузки каталога» — поймать это можно только тестом на числах и\n * массивах.\n */\n\nexport type GrTransferKey = string | number\n\nexport type GrTransferSide = 'source' | 'target'\n\nexport type GrTransferDirection = 'toTarget' | 'toSource'\n\nexport interface GrTransferSplit<TItem> {\n /** Каталог минус модель, в порядке `items`. */\n source: TItem[]\n /** Отобранное, в порядке **модели**: порядок правой панели и есть значение. */\n target: TItem[]\n /** Ключи модели, которым в `items` ничего не соответствует. */\n unresolved: GrTransferKey[]\n /** Ключи, встретившиеся в `items` дважды: рисуется первый. */\n duplicated: GrTransferKey[]\n}\n\n/**\n * Ключи без дублей, первый выигрывает.\n *\n * Нормализация идёт **на чтение** и наружу сама по себе не эмитится: эмит из\n * рендера — источник петель обновления. Нормализованный вид уезжает потребителю\n * при первом же коммите.\n */\nexport function normalizeKeys(keys: readonly GrTransferKey[]): GrTransferKey[] {\n const seen = new Set<GrTransferKey>()\n const next: GrTransferKey[] = []\n\n for (const key of keys) {\n if (seen.has(key))\n continue\n\n seen.add(key)\n next.push(key)\n }\n\n return next\n}\n\n/**\n * Раскладка каталога по панелям.\n *\n * `target` строится обходом **модели**, а не `items`: порядок правой панели\n * задаёт пользователь, и он же является значением. `source` — обходом `items`,\n * потому что порядок каталога принадлежит потребителю.\n */\nexport function splitByModel<TItem>(\n items: readonly TItem[],\n keyOf: (item: TItem) => GrTransferKey,\n model: readonly GrTransferKey[],\n): GrTransferSplit<TItem> {\n const byKey = new Map<GrTransferKey, TItem>()\n const duplicated: GrTransferKey[] = []\n\n for (const item of items) {\n const key = keyOf(item)\n if (byKey.has(key)) {\n duplicated.push(key)\n continue\n }\n byKey.set(key, item)\n }\n\n const wanted = normalizeKeys(model)\n const inTarget = new Set(wanted)\n\n const target: TItem[] = []\n const unresolved: GrTransferKey[] = []\n\n for (const key of wanted) {\n const item = byKey.get(key)\n if (item === undefined) {\n unresolved.push(key)\n continue\n }\n target.push(item)\n }\n\n // Дубль рисуется один раз: `byKey` держит именно первое вхождение, поэтому\n // сравнение по ссылке отсеивает повторы за один проход, без вложенного поиска.\n const source = items.filter(item => !inTarget.has(keyOf(item)) && byKey.get(keyOf(item)) === item)\n\n return { source, target, unresolved, duplicated }\n}\n\n/** Ключи в порядке эталонного списка; чего в нём нет — в конец, в порядке входа. */\nexport function orderedBy(\n order: readonly GrTransferKey[],\n keys: Iterable<GrTransferKey>,\n): GrTransferKey[] {\n const wanted = new Set(keys)\n const known = order.filter(key => wanted.has(key))\n const knownSet = new Set(known)\n const rest = [...wanted].filter(key => !knownSet.has(key))\n\n return [...known, ...rest]\n}\n\n/** Изъятие блока. Вход не мутируется. */\nexport function removeKeys(\n order: readonly GrTransferKey[],\n moving: readonly GrTransferKey[],\n): GrTransferKey[] {\n const drop = new Set(moving)\n\n return order.filter(key => !drop.has(key))\n}\n\n/**\n * Вставка блока перед ключом `before`; `null` или ненайденный ключ — в конец.\n *\n * Цель выражена ключом, а не индексом, намеренно: индекс пришлось бы\n * пересчитывать после изъятия блока, и это ровно тот класс off-by-one, из-за\n * которого `insertionIndex` в `dragSortGeometry` носит поправку «элемент\n * временно вынут». Здесь поправка не нужна вовсе.\n */\nexport function insertKeys(\n order: readonly GrTransferKey[],\n moving: readonly GrTransferKey[],\n before: GrTransferKey | null,\n): GrTransferKey[] {\n const block = normalizeKeys(moving)\n if (block.length === 0)\n return order.slice()\n\n const rest = removeKeys(order, block)\n const at = before === null ? -1 : rest.indexOf(before)\n\n if (at < 0)\n return [...rest, ...block]\n\n return [...rest.slice(0, at), ...block, ...rest.slice(at)]\n}\n\n/**\n * Куда встанет блок при сдвиге на шаг; `undefined` — двигаться некуда.\n *\n * Рассыпанное выделение при сдвиге схлопывается в непрерывный блок: это\n * предсказуемо и объяснимо, в отличие от попытки двигать каждый кусок\n * независимо.\n */\nexport function stepTarget(\n order: readonly GrTransferKey[],\n moving: readonly GrTransferKey[],\n delta: 1 | -1,\n): GrTransferKey | null | undefined {\n const block = normalizeKeys(moving).filter(key => order.includes(key))\n if (block.length === 0)\n return undefined\n\n const rest = removeKeys(order, block)\n const first = order.findIndex(key => block.includes(key))\n const before = order.slice(0, first).filter(key => !block.includes(key)).length\n const next = Math.min(rest.length, Math.max(0, before + delta))\n\n if (next === before)\n return undefined\n\n return rest[next] ?? null\n}\n\n/** Крайняя позиция блока: `-1` — в начало, `1` — в конец. */\nexport function edgeTarget(\n order: readonly GrTransferKey[],\n moving: readonly GrTransferKey[],\n edge: 'start' | 'end',\n): GrTransferKey | null | undefined {\n const block = normalizeKeys(moving).filter(key => order.includes(key))\n if (block.length === 0)\n return undefined\n\n const rest = removeKeys(order, block)\n\n if (edge === 'end')\n return rest.length === 0 ? undefined : null\n\n const first = rest[0]\n\n return first === undefined ? undefined : first\n}\n\n/**\n * Какая строка останется под фокусом после изъятия.\n *\n * Без этого фокус после переноса падает на тело документа, и клавиатурный\n * сценарий обрывается на первом же шаге — тот же довод, что у `drop()` в\n * `GrSortableList`.\n */\nexport function keyAfterRemoval(\n visible: readonly GrTransferKey[],\n removed: readonly GrTransferKey[],\n focused: GrTransferKey | undefined,\n): GrTransferKey | undefined {\n const drop = new Set(removed)\n const rest = visible.filter(key => !drop.has(key))\n\n if (rest.length === 0)\n return undefined\n\n if (focused !== undefined && !drop.has(focused))\n return focused\n\n const from = focused === undefined ? 0 : visible.indexOf(focused)\n\n // Ниже по списку — естественнее: взгляд остаётся там, где был список.\n for (let index = from; index < visible.length; index += 1) {\n const key = visible[index]\n if (!drop.has(key))\n return key\n }\n\n for (let index = from - 1; index >= 0; index -= 1) {\n const key = visible[index]\n if (!drop.has(key))\n return key\n }\n\n return rest[0]\n}\n","import type { DragSortSpan } from '../../composables/internal/dragSortGeometry'\nimport { hitTest } from '../../composables/internal/dragSortGeometry'\nimport type { GrTransferKey, GrTransferSide } from './transferModel'\n\n/**\n * Геометрия переноса между двумя панелями: чистая арифметика, без DOM.\n *\n * В jsdom раскладки нет — `getBoundingClientRect` там нули, — поэтому всё, что\n * решает «куда попал указатель», живёт здесь и проверяется числами. Тот же\n * довод, что у `dragSortGeometry` и `scrollOverflow`.\n */\n\n/** Порог начала жеста. То же число, что у `useDragSort` и у переноса дашборда. */\nexport const GR_TRANSFER_DRAG_THRESHOLD = 4\n\nexport interface GrTransferRect {\n left: number\n right: number\n top: number\n bottom: number\n}\n\nexport interface GrTransferPoint {\n x: number\n y: number\n}\n\nexport interface GrTransferPanelRects {\n source: GrTransferRect | null\n target: GrTransferRect | null\n}\n\nfunction contains(rect: GrTransferRect, point: GrTransferPoint): boolean {\n return point.x >= rect.left && point.x <= rect.right\n && point.y >= rect.top && point.y <= rect.bottom\n}\n\n/**\n * Панель под указателем; `null` — указатель в зазоре или за пределами обеих.\n *\n * Считается по прямоугольнику **обёртки панели**, а не по ближайшей строке:\n * `hitTest` при промахе возвращает ближайший элемент, и указатель над пустой\n * правой панелью резолвился бы в строку левой.\n */\nexport function sideAtPoint(\n rects: GrTransferPanelRects,\n point: GrTransferPoint,\n): GrTransferSide | null {\n if (rects.source && contains(rects.source, point))\n return 'source'\n\n if (rects.target && contains(rects.target, point))\n return 'target'\n\n return null\n}\n\n/**\n * Перед какой строкой встанет блок; `null` — в конец панели.\n *\n * Цель — ключ, а не индекс: индекс пришлось бы пересчитывать после изъятия\n * блока, и именно ради этого `insertionIndex` в `dragSortGeometry` носит\n * поправку «элемент временно вынут». Для вставки из чужой панели поправка\n * вредна — там ничего не вынимается, — поэтому та функция здесь не годится.\n */\nexport function dropBefore(\n keys: readonly GrTransferKey[],\n spans: readonly DragSortSpan[],\n position: number,\n): GrTransferKey | null {\n if (keys.length === 0 || spans.length === 0)\n return null\n\n const hit = hitTest(spans, position)\n if (!hit)\n return null\n\n const index = hit.fraction < 0.5 ? hit.index : hit.index + 1\n\n return index >= keys.length ? null : keys[index] ?? null\n}\n\n/** Пройден ли порог начала жеста. */\nexport function passedThreshold(\n from: GrTransferPoint,\n to: GrTransferPoint,\n threshold: number = GR_TRANSFER_DRAG_THRESHOLD,\n): boolean {\n return Math.hypot(to.x - from.x, to.y - from.y) >= threshold\n}\n","import { onScopeDispose, ref, shallowRef } from 'vue'\nimport type { Ref, ShallowRef } from 'vue'\n\nimport { autoScrollDelta } from '../../composables/internal/dragSortGeometry'\nimport { useDragGesture } from '../../composables/useDragGesture'\nimport type { GrTransferPoint, GrTransferRect } from './transferGeometry'\nimport { dropBefore, passedThreshold, sideAtPoint } from './transferGeometry'\nimport type { GrTransferKey, GrTransferSide } from './transferModel'\n\n/** Что тянут: сторона-источник и весь переносимый блок. */\nexport interface GrTransferDragSession {\n side: GrTransferSide\n keys: readonly GrTransferKey[]\n}\n\n/** Куда положат: сторона-приёмник и ключ, перед которым встанет блок. */\nexport interface GrTransferDropSpot {\n side: GrTransferSide\n before: GrTransferKey | null\n}\n\nexport interface UseTransferDragOptions {\n disabled: () => boolean\n /** Ключи панели в порядке показа. */\n visibleKeys: (side: GrTransferSide) => readonly GrTransferKey[]\n rowEl: (side: GrTransferSide, key: GrTransferKey) => HTMLElement | null\n /** Обёртка панели: по её прямоугольнику выбирается приёмник. */\n panelEl: (side: GrTransferSide) => HTMLElement | null\n /** Скроллер панели: по нему считается автопрокрутка. */\n scrollerEl: (side: GrTransferSide) => HTMLElement | null\n /** Что тянуть: всё выделение, если взялись за выделенную строку, иначе одну. */\n blockFor: (side: GrTransferSide, key: GrTransferKey) => readonly GrTransferKey[]\n /** Можно ли ронять обратно в свою панель (перестановка). */\n allowSameSide: (side: GrTransferSide) => boolean\n onDrop: (session: GrTransferDragSession, spot: GrTransferDropSpot) => void\n onCancel?: () => void\n}\n\nexport interface UseTransferDragReturn {\n session: Readonly<ShallowRef<GrTransferDragSession | null>>\n spot: Readonly<ShallowRef<GrTransferDropSpot | null>>\n /** Где указатель прямо сейчас: за ним едет предпросмотр переносимого. */\n pointer: Readonly<ShallowRef<GrTransferPoint>>\n /** Был ли жест — чтобы следующий `click` не схлопнул выделение. */\n consumeClick: () => boolean\n startFrom: (side: GrTransferSide, key: GrTransferKey) => (event: PointerEvent) => void\n cancel: () => void\n}\n\nfunction rectOf(el: HTMLElement | null): GrTransferRect | null {\n if (!el)\n return null\n\n const box = el.getBoundingClientRect()\n\n return { left: box.left, right: box.right, top: box.top, bottom: box.bottom }\n}\n\n/**\n * Перетаскивание между панелями.\n *\n * `useDragSort` здесь не подходит: его `resolveTarget` получает попадание, но не\n * точку указателя, а панель-приёмник определяется прямоугольником под точкой —\n * `hitTest` при промахе отдаёт ближайшую строку, и указатель над пустой правой\n * панелью резолвился бы в строку левой.\n */\nexport function useTransferDrag(options: UseTransferDragOptions): UseTransferDragReturn {\n const session = shallowRef<GrTransferDragSession | null>(null)\n const spot = shallowRef<GrTransferDropSpot | null>(null)\n const moved: Ref<boolean> = ref(false)\n const pointer = shallowRef<GrTransferPoint>({ x: 0, y: 0 })\n\n let origin: GrTransferPoint = { x: 0, y: 0 }\n let pending: GrTransferDragSession | null = null\n /** Последняя непустая сторона: в зазоре между панелями индикатор не мигает. */\n let lastSide: GrTransferSide | null = null\n let frame: number | null = null\n let cursor: GrTransferPoint = { x: 0, y: 0 }\n\n function stopAutoScroll(): void {\n if (frame !== null && typeof cancelAnimationFrame === 'function')\n cancelAnimationFrame(frame)\n frame = null\n }\n\n function tickAutoScroll(): void {\n frame = null\n const side = lastSide\n const scroller = side ? options.scrollerEl(side) : null\n\n if (scroller) {\n const box = scroller.getBoundingClientRect()\n const delta = autoScrollDelta({ start: box.top, end: box.bottom }, cursor.y)\n if (delta !== 0)\n scroller.scrollTop += delta\n }\n\n scheduleAutoScroll()\n }\n\n function scheduleAutoScroll(): void {\n // У края указатель стоит неподвижно, событий нет — а список обязан ехать.\n if (session.value === null || typeof requestAnimationFrame !== 'function')\n return\n\n frame = requestAnimationFrame(tickAutoScroll)\n }\n\n function reset(): void {\n session.value = null\n spot.value = null\n pending = null\n lastSide = null\n stopAutoScroll()\n detachEscape()\n unlockSelection()\n }\n\n function onEscape(event: KeyboardEvent): void {\n if (event.key !== 'Escape' || session.value === null)\n return\n\n event.preventDefault()\n event.stopPropagation()\n abort()\n }\n\n /**\n * Выделение текста на время жеста.\n *\n * `select-none` на самих строках недостаточно: выделение **начинается** внутри\n * компонента, а тянется по всему документу — и пользователь, ведя строку через\n * страницу, подсвечивает попутно чужие заголовки и абзацы. Гасим на теле\n * документа и возвращаем прежнее значение, а не пустую строку: потребитель мог\n * задать своё.\n */\n let selectionLock: { userSelect: string, webkitUserSelect: string } | null = null\n\n function lockSelection(): void {\n if (typeof document === 'undefined' || selectionLock !== null)\n return\n\n const style = document.body.style as CSSStyleDeclaration & { webkitUserSelect?: string }\n selectionLock = { userSelect: style.userSelect, webkitUserSelect: style.webkitUserSelect ?? '' }\n style.userSelect = 'none'\n style.webkitUserSelect = 'none'\n\n // Уже начатое выделение снимаем: иначе оно остаётся подсвеченным весь жест.\n window.getSelection?.()?.removeAllRanges()\n }\n\n function unlockSelection(): void {\n if (typeof document === 'undefined' || selectionLock === null)\n return\n\n const style = document.body.style as CSSStyleDeclaration & { webkitUserSelect?: string }\n style.userSelect = selectionLock.userSelect\n style.webkitUserSelect = selectionLock.webkitUserSelect\n selectionLock = null\n }\n\n let escapeAttached = false\n\n function attachEscape(): void {\n if (escapeAttached || typeof window === 'undefined')\n return\n\n // Браузер `pointercancel` на `Esc` не шлёт, поэтому слушаем сами — в capture,\n // как это делает `useDragSort`.\n window.addEventListener('keydown', onEscape, true)\n escapeAttached = true\n }\n\n function detachEscape(): void {\n if (!escapeAttached || typeof window === 'undefined')\n return\n\n window.removeEventListener('keydown', onEscape, true)\n escapeAttached = false\n }\n\n function resolveSpot(point: GrTransferPoint): void {\n const active = session.value\n if (!active)\n return\n\n const side = sideAtPoint(\n { source: rectOf(options.panelEl('source')), target: rectOf(options.panelEl('target')) },\n point,\n ) ?? lastSide\n\n if (side === null) {\n spot.value = null\n return\n }\n\n lastSide = side\n\n if (side === active.side && !options.allowSameSide(side)) {\n spot.value = null\n return\n }\n\n const keys = options.visibleKeys(side)\n const spans = keys.map((key) => {\n const box = options.rowEl(side, key)?.getBoundingClientRect()\n\n return { start: box?.top ?? 0, end: box?.bottom ?? 0 }\n })\n\n spot.value = { side, before: dropBefore(keys, spans, point.y) }\n }\n\n const drag = useDragGesture({\n disabled: options.disabled,\n onMove: (event) => {\n cursor = { x: event.clientX, y: event.clientY }\n pointer.value = cursor\n\n if (session.value === null) {\n if (pending === null || !passedThreshold(origin, cursor))\n return\n\n session.value = pending\n moved.value = true\n lockSelection()\n attachEscape()\n scheduleAutoScroll()\n }\n\n // Против выделения текста строк во время протяжки.\n event.preventDefault()\n resolveSpot(cursor)\n },\n onEnd: () => {\n const active = session.value\n const target = spot.value\n\n if (active && target)\n options.onDrop(active, target)\n\n reset()\n },\n onCancel: () => {\n if (session.value !== null)\n options.onCancel?.()\n\n reset()\n },\n })\n\n /** Объявлен после `drag`: слушатель `Esc` вешается раньше и зовёт его косвенно. */\n function abort(): void {\n drag.stop(false)\n }\n\n onScopeDispose(reset)\n\n return {\n session,\n spot,\n pointer,\n consumeClick: () => {\n const was = moved.value\n moved.value = false\n\n return was\n },\n startFrom: (side, key) => (event) => {\n // Пальцем панель прокручивают: отбирать вертикальную ось у скроллера ради\n // жеста, у которого есть работающий эквивалент кнопкой, — плохой обмен.\n if (event.pointerType === 'touch' || options.disabled())\n return\n\n const block = options.blockFor(side, key)\n if (block.length === 0)\n return\n\n origin = { x: event.clientX, y: event.clientY }\n pending = { side, keys: block }\n moved.value = false\n drag.start(event)\n },\n cancel: () => drag.stop(false),\n }\n}\n","import type { GrTransferKey } from './transferModel'\n\n/**\n * Алгебра выделения панели: чистая, без DOM и Vue.\n *\n * Мультивыбор со `Shift`-диапазоном в пакете появляется впервые, прецедента API\n * нет — тем важнее, чтобы правила лежали числами в одном месте и проверялись\n * без монтирования.\n */\n\nexport type GrTransferSelectMode = 'replace' | 'toggle' | 'range'\n\nexport interface GrTransferSelectIntent {\n mode: GrTransferSelectMode\n /** Диапазон объединяется с текущим выделением, а не заменяет его. */\n additive: boolean\n}\n\nexport interface GrTransferSelection {\n keys: ReadonlySet<GrTransferKey>\n /** Опора диапазона. `Shift` её не двигает — иначе диапазон нельзя растянуть. */\n anchor: GrTransferKey | undefined\n}\n\nexport const emptySelection: GrTransferSelection = { keys: new Set(), anchor: undefined }\n\n/** `Shift` сильнее `Ctrl`; их сочетание объединяет диапазон с выделением. */\nexport function selectIntentFrom(\n event: Pick<MouseEvent, 'shiftKey' | 'ctrlKey' | 'metaKey'>,\n): GrTransferSelectIntent {\n const additive = event.ctrlKey || event.metaKey\n\n if (event.shiftKey)\n return { mode: 'range', additive }\n\n return { mode: additive ? 'toggle' : 'replace', additive }\n}\n\nfunction rangeBetween(\n visible: readonly GrTransferKey[],\n from: GrTransferKey,\n to: GrTransferKey,\n): GrTransferKey[] {\n const start = visible.indexOf(from)\n const end = visible.indexOf(to)\n\n if (start < 0 || end < 0)\n return []\n\n return visible.slice(Math.min(start, end), Math.max(start, end) + 1)\n}\n\n/**\n * Новое состояние выделения после жеста по строке `key`.\n *\n * Диапазон считается по **видимому** порядку, а не по каталогу: пользователь\n * растягивает то, что видит, и после фильтра «от сих до сих» обязано значить\n * то же самое.\n */\nexport function applySelect(\n state: GrTransferSelection,\n key: GrTransferKey,\n intent: GrTransferSelectIntent,\n visible: readonly GrTransferKey[],\n isSelectable: (key: GrTransferKey) => boolean,\n): GrTransferSelection {\n if (!isSelectable(key))\n return state\n\n if (intent.mode === 'range' && state.anchor !== undefined) {\n const range = rangeBetween(visible, state.anchor, key).filter(isSelectable)\n\n if (range.length > 0) {\n const keys = intent.additive ? new Set(state.keys) : new Set<GrTransferKey>()\n range.forEach(item => keys.add(item))\n\n // Якорь остаётся прежним: повторный `Shift`-клик обязан растягивать\n // диапазон от той же опоры, а не от предыдущего края.\n return { keys, anchor: state.anchor }\n }\n }\n\n if (intent.mode === 'toggle') {\n const keys = new Set(state.keys)\n if (keys.has(key))\n keys.delete(key)\n else keys.add(key)\n\n return { keys, anchor: key }\n }\n\n return { keys: new Set([key]), anchor: key }\n}\n\n/** Всё видимое и выбираемое; уже выбрано всё — снять. */\nexport function toggleAllVisible(\n state: GrTransferSelection,\n visible: readonly GrTransferKey[],\n isSelectable: (key: GrTransferKey) => boolean,\n): GrTransferSelection {\n const selectable = visible.filter(isSelectable)\n\n if (selectable.length === 0)\n return { keys: new Set(state.keys), anchor: undefined }\n\n const allSelected = selectable.every(key => state.keys.has(key))\n\n if (allSelected) {\n const keys = new Set(state.keys)\n selectable.forEach(key => keys.delete(key))\n\n return { keys, anchor: undefined }\n }\n\n const keys = new Set(state.keys)\n selectable.forEach(key => keys.add(key))\n\n return { keys, anchor: undefined }\n}\n\n/** Ключи, которых больше нет в панели. Якорь исчез — забываем и его. */\nexport function pruneSelection(\n state: GrTransferSelection,\n present: readonly GrTransferKey[],\n): GrTransferSelection {\n const alive = new Set(present)\n const keys = new Set<GrTransferKey>()\n\n state.keys.forEach((key) => {\n if (alive.has(key))\n keys.add(key)\n })\n\n const anchor = state.anchor !== undefined && alive.has(state.anchor) ? state.anchor : undefined\n\n if (keys.size === state.keys.size && anchor === state.anchor)\n return state\n\n return { keys, anchor }\n}\n\n/** Состояние отметки «выбрать всё видимое» в шапке панели. */\nexport function allVisibleState(\n state: GrTransferSelection,\n visible: readonly GrTransferKey[],\n isSelectable: (key: GrTransferKey) => boolean,\n): 'checked' | 'indeterminate' | 'unchecked' {\n const selectable = visible.filter(isSelectable)\n if (selectable.length === 0)\n return 'unchecked'\n\n const picked = selectable.filter(key => state.keys.has(key)).length\n\n if (picked === 0)\n return 'unchecked'\n\n return picked === selectable.length ? 'checked' : 'indeterminate'\n}\n","<script setup lang=\"ts\" generic=\"TItem extends Record<string, unknown> = Record<string, unknown>\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, useSlots, watch } from 'vue'\n\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { usePortalTarget } from '../../composables/usePortalTarget'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton'\nimport GrButtonGroup from '../GrButtonGroup'\nimport GrCheckbox from '../GrCheckbox'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport GrInput from '../GrInput'\nimport { matchesQueryParts, normalizeOptionQuery } from '../shared/optionFilter'\nimport type { GrScrollOverflow } from '../shared/scrollOverflow'\nimport { resolveScrollOverflow } from '../shared/scrollOverflow'\nimport type { GrComponentSize } from '../shared/sizes'\nimport {\n grTransferActionsClass,\n grTransferEmptyClass,\n grTransferHeaderClass,\n grTransferMarkClass,\n grTransferOptionClass,\n grTransferPanelClass,\n grTransferReorderClass,\n grTransferSearchClass,\n transferActionIconClass,\n transferActionInertClass,\n transferCounterClass,\n transferGhostClass,\n transferGhostCountClass,\n transferGhostLabelClass,\n transferLabelClass,\n transferListBase,\n transferMarkIconClass,\n transferReorderIconClass,\n transferRootBase,\n transferStatusClass,\n transferTitleClass,\n} from './grTransferStyles'\nimport type { GrTransferDirection, GrTransferKey, GrTransferSide } from './transferModel'\nimport {\n edgeTarget,\n insertKeys,\n keyAfterRemoval,\n normalizeKeys,\n removeKeys,\n splitByModel,\n stepTarget,\n} from './transferModel'\nimport type { GrTransferDragSession, GrTransferDropSpot } from './useTransferDrag'\nimport { useTransferDrag } from './useTransferDrag'\nimport type { GrTransferSelection } from './transferSelection'\nimport {\n allVisibleState,\n applySelect,\n emptySelection,\n pruneSelection,\n selectIntentFrom,\n toggleAllVisible,\n} from './transferSelection'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconArrowLeft from '~icons/lucide/arrow-left'\nimport IconArrowRight from '~icons/lucide/arrow-right'\nimport IconChevronLeft from '~icons/lucide/chevron-left'\nimport IconChevronRight from '~icons/lucide/chevron-right'\n\nexport type GrTransferItemKey<T> = string | ((item: T) => GrTransferKey)\nexport type GrTransferItemLabel<T> = string | ((item: T) => string)\nexport type GrTransferItemFlag<T> = string | ((item: T) => boolean)\n\nexport interface GrTransferProps<T extends Record<string, unknown> = Record<string, unknown>> {\n /** Каталог целиком: обе панели — одна его раскладка. */\n items: T[]\n /** Ключи правой панели **в её порядке**: порядок и есть значение. */\n modelValue: GrTransferKey[]\n itemKey?: GrTransferItemKey<T>\n itemLabel?: GrTransferItemLabel<T>\n itemDisabled?: GrTransferItemFlag<T>\n /** Имя левой панели. Это доступное имя её `listbox`, а не украшение. */\n sourceTitle?: string\n /** Имя правой панели. */\n targetTitle?: string\n /** Поле поиска в каждой панели. */\n searchable?: boolean\n /** Свой матчер: встроенный ищет по `itemLabel`, а строка может показывать больше. */\n filter?: (item: T, query: string) => boolean\n /**\n * Каталог в пути: пустая панель говорит «ищем», а не «ничего не найдено».\n *\n * Проп общий на обе панели, а не свой у каждой: `items` — один каталог, и обе\n * панели его виды, так что пока он едет, пусты обе. Подгрузку запускает\n * потребитель по событию `search`, поэтому и флаг держит он.\n */\n loading?: boolean\n /** Текст индикатора. Не задан — из локали (`gr.transfer.loading`). */\n loadingText?: string\n /** Правую панель можно переставлять. */\n sortable?: boolean\n /** Перетаскивание строк указателем. Усиление поверх кнопок, а не контракт. */\n draggable?: boolean\n /** Высота панелей: обе одинаковы и прокручиваются внутри себя. */\n maxHeight?: number | string\n /**\n * Держать в DOM только окно строк вокруг вьюпорта. Нужен `maxHeight`: без\n * него панель не прокручивается, окна нет и виртуализировать нечего.\n *\n * Перенос от этого не страдает — он идёт по модели, а не по разметке. А вот\n * перетаскивание указателем ограничено отрисованными строками: навести\n * указатель на то, чего нет на экране, всё равно нечем.\n */\n virtual?: boolean\n size?: GrComponentSize\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n ariaLabel?: string\n}\n\nexport interface GrTransferEmits {\n (e: 'update:modelValue', value: GrTransferKey[]): void\n (e: 'change', value: GrTransferKey[]): void\n (e: 'transfer', keys: GrTransferKey[], direction: GrTransferDirection): void\n (e: 'search', query: string, side: GrTransferSide): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrTransferProps<TItem>>(), {\n itemKey: undefined,\n itemLabel: undefined,\n itemDisabled: undefined,\n sourceTitle: undefined,\n targetTitle: undefined,\n searchable: true,\n filter: undefined,\n loading: false,\n loadingText: undefined,\n sortable: true,\n draggable: undefined,\n maxHeight: undefined,\n virtual: false,\n size: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrTransferEmits>()\n\ndefineSlots<{\n /** Своя строка. Слот доменный: у соседей `item` — строка списка, здесь тоже. */\n item?: (props: {\n item: TItem\n side: GrTransferSide\n index: number\n selected: boolean\n disabled: boolean\n }) => unknown\n /** Своя шапка панели: имя, счётчик, отметка «выбрать всё». */\n header?: (props: {\n side: GrTransferSide\n title: string\n selected: number\n total: number\n shown: number\n }) => unknown\n /** Своя колонка кнопок между панелями. */\n actions?: (props: {\n toTarget: () => void\n toSource: () => void\n canToTarget: boolean\n canToSource: boolean\n }) => unknown\n /** Пустая панель. `filtered` — пусто из-за поиска, а не по сути. */\n empty?: (props: { side: GrTransferSide, filtered: boolean }) => unknown\n /** Панель под загрузкой — вместо текста «ищем». */\n loading?: (props: { side: GrTransferSide }) => unknown\n}>()\n\nconst slots = useSlots()\n\n/**\n * Свой `#header` уносит с собой заголовок панели, а вместе с ним и `id`, на\n * который смотрит `aria-labelledby` списка: панель осталась бы без доступного\n * имени, и axe ловит это как `aria-input-field-name`. Имя поэтому не зависит от\n * разметки потребителя — при своей шапке оно приходит из `aria-label`.\n */\nconst hasHeaderSlot = computed(() => Boolean(slots.header))\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTransfer' })\nconst resolvedDraggable = useGrComponentProp('GrTransfer', 'draggable', () => props.draggable, true)\n\nconst {\n disabled: isDisabled,\n readonly: isReadonly,\n invalid: isInvalid,\n required: isRequired,\n locked: isLocked,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n} = useGrFormControl(() => props)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst uid = useId()\nconst sourceTitleId = `${uid}-source-title`\nconst targetTitleId = `${uid}-target-title`\nconst sourceListId = `${uid}-source-list`\nconst targetListId = `${uid}-target-list`\n\nif (__GR_DEV__) {\n if (!Array.isArray(props.items)) {\n console.warn(\n `[granularity] GrTransfer: обязательный проп \\`items\\` должен быть массивом — получено ${typeof props.items}.`,\n )\n }\n if (!Array.isArray(props.modelValue)) {\n console.warn(\n `[granularity] GrTransfer: обязательный проп \\`modelValue\\` должен быть массивом — получено ${typeof props.modelValue}.`,\n )\n }\n}\n\n/**\n * Синтетический ключ для элемента без своего: общий ключ пометил бы выбранными\n * все строки разом. Приём и причина — из `GrDataTable`.\n */\nconst syntheticKeys = new WeakMap<object, string>()\nlet syntheticCount = 0\nlet warnedSynthetic = false\n\nfunction keyOf(item: TItem): GrTransferKey {\n // Фолбэк здесь, а не в `withDefaults`: у дженерик-компонента вывод дефолта\n // не снимает опциональность, и `item[source]` переставал типизироваться.\n const source = props.itemKey ?? 'id'\n const value = typeof source === 'function' ? source(item) : item[source]\n\n if (typeof value === 'string' && value !== '')\n return value\n if (typeof value === 'number')\n return value\n\n const known = syntheticKeys.get(item)\n if (known !== undefined)\n return known\n\n syntheticCount += 1\n const generated = `${uid}-synthetic-${syntheticCount}`\n syntheticKeys.set(item, generated)\n\n if (__GR_DEV__ && !warnedSynthetic) {\n warnedSynthetic = true\n console.warn(\n '[granularity] GrTransfer: у элемента нет значения `itemKey` — выдан временный ключ. '\n + 'Он не переживёт перезагрузку данных, и `modelValue` с ним не сойдётся: задайте `itemKey`.',\n )\n }\n\n return generated\n}\n\nfunction labelOf(item: TItem): string {\n const source = props.itemLabel ?? 'label'\n\n return typeof source === 'function' ? source(item) : String(item[source] ?? '')\n}\n\nfunction disabledOf(item: TItem): boolean {\n const source = props.itemDisabled ?? 'disabled'\n\n return typeof source === 'function' ? source(item) : Boolean(item[source])\n}\n\nconst split = computed(() => splitByModel(props.items ?? [], keyOf, props.modelValue ?? []))\n\nif (__GR_DEV__) {\n watch(split, (value) => {\n if (value.duplicated.length > 0) {\n console.warn(\n `[granularity] GrTransfer: ключи повторяются в \\`items\\` (${value.duplicated.join(', ')}) — `\n + 'рисуется первый элемент с таким ключом.',\n )\n }\n /*\n * Под загрузкой неполный каталог — норма, а не ошибка потребителя. Без этого\n * серверный поиск сужает `items`, выбранные ключи оказываются вне сужения, и\n * предупреждение срабатывает на каждое нажатие клавиши.\n */\n if (!props.loading && value.unresolved.length > 0 && (props.items?.length ?? 0) > 0) {\n console.warn(\n `[granularity] GrTransfer: ключи из \\`modelValue\\` не найдены в \\`items\\` (${value.unresolved.join(', ')}). `\n + 'Они сохранены в значении, но не показаны: каталог мог ещё не приехать.',\n )\n }\n }, { immediate: true })\n}\n\nconst queries = ref<Record<GrTransferSide, string>>({ source: '', target: '' })\nconst selections = ref<Record<GrTransferSide, GrTransferSelection>>({\n source: emptySelection,\n target: emptySelection,\n})\n\nfunction itemsOf(side: GrTransferSide): TItem[] {\n return side === 'source' ? split.value.source : split.value.target\n}\n\nfunction matches(item: TItem, query: string): boolean {\n if (props.filter)\n return props.filter(item, query)\n\n return matchesQueryParts([labelOf(item)], normalizeOptionQuery(query))\n}\n\nfunction visibleOf(side: GrTransferSide): TItem[] {\n const query = queries.value[side]\n if (!props.searchable || normalizeOptionQuery(query) === '')\n return itemsOf(side)\n\n return itemsOf(side).filter(item => matches(item, query))\n}\n\nconst visible = computed<Record<GrTransferSide, TItem[]>>(() => ({\n source: visibleOf('source'),\n target: visibleOf('target'),\n}))\n\nconst visibleKeys = computed<Record<GrTransferSide, GrTransferKey[]>>(() => ({\n source: visible.value.source.map(keyOf),\n target: visible.value.target.map(keyOf),\n}))\n\nfunction selectableOf(side: GrTransferSide): (key: GrTransferKey) => boolean {\n return (key) => {\n const item = itemsOf(side).find(candidate => keyOf(candidate) === key)\n\n return item !== undefined && !disabledOf(item)\n }\n}\n\n// Состав каталога сменился — выделение чистится от исчезнувших ключей.\nwatch(split, () => {\n selections.value = {\n source: pruneSelection(selections.value.source, split.value.source.map(keyOf)),\n target: pruneSelection(selections.value.target, split.value.target.map(keyOf)),\n }\n})\n\nconst titles = computed<Record<GrTransferSide, string>>(() => ({\n source: props.sourceTitle ?? t('gr.transfer.sourceTitle', 'Available'),\n target: props.targetTitle ?? t('gr.transfer.targetTitle', 'Selected'),\n}))\n\nfunction setSelection(side: GrTransferSide, next: GrTransferSelection): void {\n selections.value = { ...selections.value, [side]: next }\n}\n\nfunction toggleAll(side: GrTransferSide): void {\n if (isDisabled.value)\n return\n\n setSelection(side, toggleAllVisible(selections.value[side], visibleKeys.value[side], selectableOf(side)))\n}\n\n/** Что реально уедет: отмеченное минус запрещённое. Скрытое поиском — уезжает. */\nfunction movableOf(side: GrTransferSide): GrTransferKey[] {\n const selectable = selectableOf(side)\n const order = itemsOf(side).map(keyOf)\n\n return order.filter(key => selections.value[side].keys.has(key) && selectable(key))\n}\n\nconst canToTarget = computed(() => !isLocked.value && movableOf('source').length > 0)\nconst canToSource = computed(() => !isLocked.value && movableOf('target').length > 0)\n\nfunction commit(next: GrTransferKey[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nasync function transfer(keys: GrTransferKey[], direction: GrTransferDirection): Promise<void> {\n if (isLocked.value || keys.length === 0)\n return\n\n const from: GrTransferSide = direction === 'toTarget' ? 'source' : 'target'\n const to: GrTransferSide = direction === 'toTarget' ? 'target' : 'source'\n const model = normalizeKeys(props.modelValue ?? [])\n\n const nextFocus = keyAfterRemoval(visibleKeys.value[from], keys, rovingOf(from).rovingKey.value)\n\n commit(direction === 'toTarget' ? insertKeys(model, keys, null) : removeKeys(model, keys))\n\n // Выделение переезжает вместе со строками: `Alt`+стрелка сразу ставит их на\n // место, а возврат — одно нажатие.\n selections.value = {\n ...selections.value,\n [from]: emptySelection,\n [to]: { keys: new Set(keys), anchor: keys[0] },\n }\n\n markArrived(keys)\n emit('transfer', keys, direction)\n announce(t('gr.transfer.moved', '{count} moved to {list}', {\n count: keys.length,\n n: keys.length,\n list: titles.value[to],\n }))\n\n await nextTick()\n if (nextFocus !== undefined)\n void rovingOf(from).focusKey(nextFocus)\n else void rovingOf(to).focusKey(keys[0])\n}\n\nfunction transferSelected(direction: GrTransferDirection): void {\n const side: GrTransferSide = direction === 'toTarget' ? 'source' : 'target'\n const keys = movableOf(side)\n if (keys.length > 0) {\n void transfer(keys, direction)\n return\n }\n\n // Ничего не отмечено — переносится строка под фокусом: так `Enter` работает\n // сразу, без обязательного предварительного `Space`.\n const focused = rovingOf(side).rovingKey.value\n if (focused !== undefined && selectableOf(side)(focused))\n void transfer([focused], direction)\n}\n\n/** Перестановка отключена, пока панель отфильтрована: см. `docs/components/GrTransfer.md`. */\nconst reorderAllowed = computed(() => props.sortable\n && !isLocked.value\n && normalizeOptionQuery(queries.value.target) === '')\n\nfunction reorder(target: GrTransferKey | null | undefined, keys: GrTransferKey[]): void {\n if (target === undefined || keys.length === 0)\n return\n\n const model = normalizeKeys(props.modelValue ?? [])\n commit(insertKeys(model, keys, target))\n\n const position = removeKeys(model, keys).findIndex(key => key === target)\n announce(t('gr.transfer.reordered', 'Position {position} of {count}', {\n position: (position < 0 ? model.length - keys.length : position) + 1,\n count: model.length,\n }))\n}\n\nfunction moveBlock(delta: 1 | -1): void {\n const keys = movableOf('target')\n const moving = keys.length > 0 ? keys : blockUnderFocus('target')\n if (moving.length === 0)\n return\n\n if (!reorderAllowed.value) {\n if (props.sortable && !isLocked.value)\n announce(t('gr.transfer.reorderFiltered', 'Reordering is off while a search is active'))\n return\n }\n\n reorder(stepTarget(normalizeKeys(props.modelValue ?? []), moving, delta), moving)\n}\n\nfunction moveBlockToEdge(edge: 'start' | 'end'): void {\n const keys = movableOf('target')\n const moving = keys.length > 0 ? keys : blockUnderFocus('target')\n if (moving.length === 0 || !reorderAllowed.value)\n return\n\n reorder(edgeTarget(normalizeKeys(props.modelValue ?? []), moving, edge), moving)\n}\n\nfunction blockUnderFocus(side: GrTransferSide): GrTransferKey[] {\n const focused = rovingOf(side).rovingKey.value\n\n return focused !== undefined && selectableOf(side)(focused) ? [focused] : []\n}\n\nconst sourceRows = ref<Map<GrTransferKey, HTMLElement>>(new Map())\nconst targetRows = ref<Map<GrTransferKey, HTMLElement>>(new Map())\nconst searchEls = ref<Record<GrTransferSide, HTMLElement | null>>({ source: null, target: null })\nconst panelEls = ref<Record<GrTransferSide, HTMLElement | null>>({ source: null, target: null })\nconst listEls = ref<Record<GrTransferSide, HTMLElement | null>>({ source: null, target: null })\n\nfunction rowsOf(side: GrTransferSide): Map<GrTransferKey, HTMLElement> {\n return side === 'source' ? sourceRows.value : targetRows.value\n}\n\nlet isUnmounting = false\n\nonBeforeUnmount(() => {\n isUnmounting = true\n})\n\n/**\n * Строка размонтируется — снимаем регистрацию, а если фокус был на ней, уводим\n * его на сам список.\n *\n * При виртуализации это не редкость: колесо мыши уносит сфокусированную строку\n * из окна, и без перевода фокус упал бы на `body`. Обработчик клавиш висит на\n * списке, до `body` он не достаёт, и клавиатура панели умерла бы до клика мышью.\n *\n * Элемент берётся из карты, а не из аргумента: Vue обнуляет function ref ДО\n * удаления узла, то есть в момент вызова фокус ещё на строке.\n */\nfunction registerRow(side: GrTransferSide, key: GrTransferKey, el: Element | null): void {\n const map = rowsOf(side)\n\n if (el instanceof HTMLElement) {\n map.set(key, el)\n return\n }\n\n const previous = map.get(key)\n const active = typeof document === 'undefined' ? null : document.activeElement\n const heldFocus = Boolean(previous && active && (previous === active || previous.contains(active)))\n\n map.delete(key)\n\n if (heldFocus && !isUnmounting)\n listEls.value[side]?.focus({ preventScroll: true })\n}\n\n// ————— Виртуализация панелей.\n\n/**\n * Виртуализатор просит `Ref` на контейнер, а панели хранятся одной картой на обе\n * стороны. Отдельная ссылка на сторону — дешевле, чем разводить карту на два рефа\n * и синхронизировать их вручную.\n */\nconst sourceListEl = computed(() => listEls.value.source)\nconst targetListEl = computed(() => listEls.value.target)\n\n/** Оценка высоты строки до первого замера: считает сам виртуализатор по образцам. */\nconst ROW_ESTIMATE_PX = 36\n\nfunction makeVirtualizer(side: GrTransferSide) {\n return useVirtualList({\n container: side === 'source' ? sourceListEl : targetListEl,\n count: () => (props.virtual ? visible.value[side].length : 0),\n // Поиск и перенос меняют состав панели — замеры прошлого набора невалидны.\n source: () => visible.value[side],\n itemSize: () => ROW_ESTIMATE_PX,\n /*\n * Запасное окно до первого замера — высота панели, а не списка: список\n * тянется флексом и своей высоты в пропах не имеет. Оценка выходит\n * завышенной, то есть в первом кадре строк рисуется с запасом — это\n * безопасная сторона ошибки, и замер её сразу поправляет.\n */\n viewportSize: () => (typeof props.maxHeight === 'number' ? props.maxHeight : undefined),\n })\n}\n\nconst sourceVirtualizer = makeVirtualizer('source')\nconst targetVirtualizer = makeVirtualizer('target')\n\nfunction virtualizerOf(side: GrTransferSide) {\n return side === 'source' ? sourceVirtualizer : targetVirtualizer\n}\n\n/** Строки к отрисовке: при выключенной виртуализации — все. */\nfunction renderedOf(side: GrTransferSide): TItem[] {\n if (!props.virtual)\n return visible.value[side]\n\n const { start, end } = virtualizerOf(side).range.value\n return visible.value[side].slice(start, end)\n}\n\n/** Абсолютный индекс строки: `aria-posinset` обязан считать от всего списка. */\nfunction absoluteIndex(side: GrTransferSide, offsetInWindow: number): number {\n return props.virtual ? virtualizerOf(side).range.value.start + offsetInWindow : offsetInWindow\n}\n\n/**\n * Строки вне окна в DOM нет: `elementFor` вернул бы `null`, и фокус остался бы\n * на месте. Поэтому сперва прокрутка, и только следующим тиком — фокус.\n */\nfunction scrollRowIntoView(side: GrTransferSide, key: GrTransferKey): Promise<void> {\n if (props.virtual) {\n const index = visibleKeys.value[side].indexOf(key)\n if (index >= 0)\n virtualizerOf(side).scrollToIndex(index)\n }\n\n return nextTick()\n}\n\nfunction makeRoving(side: GrTransferSide) {\n return useRovingFocus<GrTransferKey>({\n items: () => visibleKeys.value[side],\n elementFor: key => rowsOf(side).get(key) ?? null,\n beforeFocus: key => scrollRowIntoView(side, key),\n orientation: () => 'vertical',\n // Кольцо не замкнуто: замкнутое делает `Shift`-диапазоны бессмысленными.\n wrap: () => false,\n // Выключенная строка остаётся достижимой — иначе AT не прочтёт, что она есть.\n skipDisabled: () => false,\n onOverflow: (edge) => {\n if (edge !== 'start')\n return false\n\n // Вверх из первой строки — в поле поиска своей панели (приём `GrTreeSelect`).\n const input = searchEls.value[side]?.querySelector('input')\n if (!input)\n return false\n\n input.focus()\n return true\n },\n })\n}\n\nconst sourceRoving = makeRoving('source')\nconst targetRoving = makeRoving('target')\n\nfunction rovingOf(side: GrTransferSide) {\n return side === 'source' ? sourceRoving : targetRoving\n}\n\n/**\n * Признак того, что список продолжается за краем.\n *\n * Полоса прокрутки у панели своя и на macOS невидима, поэтому обрезанная\n * посередине строка читается как дефект отрисовки, а не как «прокрути». Затухание\n * рисует CSS по `data-overflow` — тот же приём, что у ряда вкладок `GrTabs`.\n */\nconst listOverflow = ref<Record<GrTransferSide, GrScrollOverflow>>({ source: 'none', target: 'none' })\nlet overflowObserver: ResizeObserver | null = null\nlet overflowScheduled = false\n\nfunction measureOverflow(): void {\n const next = { source: 'none', target: 'none' } as Record<GrTransferSide, GrScrollOverflow>\n\n for (const side of ['source', 'target'] as GrTransferSide[]) {\n const el = listEls.value[side]\n if (el)\n next[side] = resolveScrollOverflow(el.scrollTop, el.scrollHeight, el.clientHeight)\n }\n\n listOverflow.value = next\n}\n\nfunction scheduleOverflow(): void {\n if (overflowScheduled)\n return\n\n overflowScheduled = true\n void nextTick(() => {\n overflowScheduled = false\n measureOverflow()\n })\n}\n\nonMounted(() => {\n scheduleOverflow()\n\n // На сервере и в jsdom `ResizeObserver` отсутствует — измерять там нечего.\n if (typeof ResizeObserver === 'undefined')\n return\n\n overflowObserver = new ResizeObserver(scheduleOverflow)\n for (const side of ['source', 'target'] as GrTransferSide[]) {\n const el = listEls.value[side]\n if (el)\n overflowObserver.observe(el)\n }\n})\n\nonBeforeUnmount(() => {\n overflowObserver?.disconnect()\n overflowObserver = null\n})\n\nwatch([split, visible], scheduleOverflow)\n\n/** Есть ли что переставлять: иначе кнопки в шапке гасятся, оставаясь в таб-порядке. */\nconst canReorder = computed(() => reorderAllowed.value\n && itemsOf('target').length > 1\n && (movableOf('target').length > 0 || blockUnderFocus('target').length > 0))\n\n/**\n * Ключи, только что приехавшие в панель: подсветка живёт ~1.2 с и снимается сама.\n * Таймер один на компонент — быстрый повторный перенос перезапускает его, а не\n * копит хвосты.\n */\nconst arrived = ref<Set<GrTransferKey>>(new Set())\nlet arrivedTimer: number | null = null\n\nfunction markArrived(keys: readonly GrTransferKey[]): void {\n if (typeof window === 'undefined')\n return\n\n arrived.value = new Set(keys)\n if (arrivedTimer !== null)\n clearTimeout(arrivedTimer)\n\n arrivedTimer = window.setTimeout(() => {\n arrivedTimer = null\n arrived.value = new Set()\n }, 1200)\n}\n\nonBeforeUnmount(() => {\n if (arrivedTimer !== null)\n clearTimeout(arrivedTimer)\n})\n\nconst dragging = useTransferDrag({\n disabled: () => isLocked.value || !resolvedDraggable.value,\n visibleKeys: side => visibleKeys.value[side],\n rowEl: (side, key) => rowsOf(side).get(key) ?? null,\n panelEl: side => panelEls.value[side],\n scrollerEl: side => listEls.value[side],\n // Взялись за отмеченную строку — едет всё выделение; за чужую — только она.\n blockFor: (side, key) => {\n const selectable = selectableOf(side)\n if (!selectable(key))\n return []\n\n const chosen = movableOf(side)\n\n return chosen.includes(key) ? chosen : [key]\n },\n allowSameSide: side => side === 'target' && reorderAllowed.value,\n onDrop: (session, spot) => {\n const model = normalizeKeys(props.modelValue ?? [])\n\n if (spot.side === session.side) {\n reorder(spot.before, [...session.keys])\n return\n }\n\n if (spot.side === 'target') {\n commit(insertKeys(model, [...session.keys], spot.before))\n markArrived(session.keys)\n emit('transfer', [...session.keys], 'toTarget')\n announce(t('gr.transfer.moved', '{count} moved to {list}', {\n count: session.keys.length,\n n: session.keys.length,\n list: titles.value.target,\n }))\n return\n }\n\n commit(removeKeys(model, [...session.keys]))\n markArrived(session.keys)\n emit('transfer', [...session.keys], 'toSource')\n announce(t('gr.transfer.moved', '{count} moved to {list}', {\n count: session.keys.length,\n n: session.keys.length,\n list: titles.value.source,\n }))\n },\n onCancel: () => announce(t('gr.transfer.cancelled', 'Move cancelled')),\n})\n\n/**\n * Вызов через обработчик, а не `@pointerdown=\"dragging.startFrom(...)\"`: Vue\n * считает такое выражение инлайн-инструкцией и возвращённую функцию\n * выбрасывает — жест не начинался бы вовсе. Приём `GrSortableList`.\n */\nfunction onRowPointerDown(side: GrTransferSide, key: GrTransferKey, event: PointerEvent): void {\n dragging.startFrom(side, key)(event)\n}\n\n/**\n * Подпись переносимого. Первая строка блока названа, остальные — числом: список\n * из десяти имён под курсором закрыл бы то самое место, куда человек целится.\n */\nconst ghost = computed(() => {\n const session = dragging.session.value\n if (!session || session.keys.length === 0)\n return null\n\n const first = itemsOf(session.side).find(item => keyOf(item) === session.keys[0])\n\n return {\n label: first ? labelOf(first) : String(session.keys[0]),\n rest: session.keys.length - 1,\n }\n})\n\nconst ghostStyle = computed(() => ({\n // Смещение от курсора: под остриём должно оставаться видно, куда целишься.\n transform: `translate3d(${dragging.pointer.value.x + 12}px, ${dragging.pointer.value.y + 12}px, 0)`,\n}))\n\nfunction indicatorFor(side: GrTransferSide, key: GrTransferKey): 'before' | 'after' | null {\n const spot: GrTransferDropSpot | null = dragging.spot.value\n if (!spot || spot.side !== side)\n return null\n\n if (spot.before === key)\n return 'before'\n\n const keys = visibleKeys.value[side]\n\n return spot.before === null && keys[keys.length - 1] === key ? 'after' : null\n}\n\nfunction isDraggingKey(side: GrTransferSide, key: GrTransferKey): boolean {\n const session: GrTransferDragSession | null = dragging.session.value\n\n return session !== null && session.side === side && session.keys.includes(key)\n}\n\nfunction onOptionClick(side: GrTransferSide, key: GrTransferKey, event: MouseEvent): void {\n // Клик после протяжки выделение не трогает: иначе любое перетаскивание\n // схлопывало бы блок в одну строку ровно в момент отпускания.\n if (isDisabled.value || dragging.consumeClick())\n return\n\n rovingOf(side).setActive(key)\n setSelection(side, applySelect(\n selections.value[side],\n key,\n selectIntentFrom(event),\n visibleKeys.value[side],\n selectableOf(side),\n ))\n}\n\nfunction extendRange(side: GrTransferSide, key: GrTransferKey): void {\n setSelection(side, applySelect(\n selections.value[side],\n key,\n { mode: 'range', additive: false },\n visibleKeys.value[side],\n selectableOf(side),\n ))\n}\n\nfunction onListKeydown(side: GrTransferSide, event: KeyboardEvent): void {\n if (isDisabled.value || visibleKeys.value[side].length === 0)\n return\n\n const roving = rovingOf(side)\n const current = roving.rovingKey.value\n\n if ((event.ctrlKey || event.metaKey) && (event.key === 'a' || event.key === 'A')) {\n event.preventDefault()\n toggleAll(side)\n return\n }\n\n if (event.key === ' ') {\n event.preventDefault()\n if (current === undefined)\n return\n\n if (event.shiftKey) {\n extendRange(side, current)\n }\n else {\n setSelection(side, applySelect(\n selections.value[side],\n current,\n { mode: 'toggle', additive: true },\n visibleKeys.value[side],\n selectableOf(side),\n ))\n }\n return\n }\n\n if (event.key === 'Enter') {\n event.preventDefault()\n transferSelected(side === 'source' ? 'toTarget' : 'toSource')\n return\n }\n\n if (side === 'target' && event.altKey) {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveBlock(event.key === 'ArrowDown' ? 1 : -1)\n return\n }\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault()\n moveBlockToEdge(event.key === 'Home' ? 'start' : 'end')\n return\n }\n }\n\n // Стрелки и `Home`/`End` ведёт примитив; `Shift` растягивает диапазон следом.\n if (!roving.handleNavigationKeys(event))\n return\n\n const next = roving.rovingKey.value\n if (event.shiftKey && next !== undefined)\n extendRange(side, next)\n}\n\nfunction onSearchKeydown(side: GrTransferSide, event: KeyboardEvent): void {\n if (event.key !== 'ArrowDown')\n return\n\n const first = visibleKeys.value[side][0]\n if (first === undefined)\n return\n\n event.preventDefault()\n void rovingOf(side).focusKey(first)\n}\n\nfunction onSearch(side: GrTransferSide, value: string): void {\n queries.value = { ...queries.value, [side]: value }\n emit('search', value, side)\n}\n\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\n/**\n * Скролл-протяжённость виртуализованного списка держат псевдоэлементы\n * контейнера: распорка приезжает переменными в том же патче, что и сами строки,\n * и схлопнуться между кадрами ей нечем.\n */\nfunction listStyle(side: GrTransferSide): Record<string, string> | undefined {\n return props.virtual ? virtualizerOf(side).spacerStyle.value : undefined\n}\n\nconst panelStyle = computed(() => ({\n maxHeight: props.maxHeight === undefined\n ? 'var(--gr-transfer-panel-max-h, 18rem)'\n : typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight,\n}))\n\nfunction counterText(side: GrTransferSide): string {\n return t('gr.transfer.selected', '{count} of {total}', {\n count: selections.value[side].keys.size,\n total: itemsOf(side).length,\n })\n}\n\nfunction shownText(side: GrTransferSide): string {\n return t('gr.transfer.shown', 'Showing {shown} of {total}', {\n shown: visible.value[side].length,\n total: itemsOf(side).length,\n })\n}\n\nfunction emptyText(side: GrTransferSide): string {\n return normalizeOptionQuery(queries.value[side]) === ''\n ? t('gr.transfer.empty', 'Nothing here yet')\n : t('gr.transfer.emptyFiltered', 'Nothing matches the search')\n}\n\nconst resolvedLoadingText = computed(() => props.loadingText ?? t('gr.transfer.loading', 'Loading…'))\n\nfunction isFiltered(side: GrTransferSide): boolean {\n return normalizeOptionQuery(queries.value[side]) !== ''\n}\n\nfunction allState(side: GrTransferSide): 'checked' | 'indeterminate' | 'unchecked' {\n return allVisibleState(selections.value[side], visibleKeys.value[side], selectableOf(side))\n}\n\nfunction focusSide(side: GrTransferSide): void {\n const roving = rovingOf(side)\n const key = roving.rovingKey.value ?? visibleKeys.value[side][0]\n\n if (key !== undefined) {\n void roving.focusKey(key)\n return\n }\n\n searchEls.value[side]?.querySelector('input')?.focus()\n}\n\ndefineExpose({\n focus: () => focusSide('target'),\n blur: () => {\n const active = document.activeElement\n if (active instanceof HTMLElement && rootEl.value?.contains(active))\n active.blur()\n },\n focusSide,\n transfer: (keys: GrTransferKey[], direction: GrTransferDirection) => void transfer(keys, direction),\n selectAll: (side: GrTransferSide) => toggleAll(side),\n clearSelection: (side?: GrTransferSide) => {\n if (side) {\n setSelection(side, emptySelection)\n return\n }\n selections.value = { source: emptySelection, target: emptySelection }\n },\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-transfer\n :data-dragging=\"dragging.session.value ? 'true' : undefined\"\n role=\"group\"\n :class=\"transferRootBase\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <div\n v-for=\"side in (['source', 'target'] as GrTransferSide[])\"\n :key=\"side\"\n :ref=\"el => { panelEls[side] = el as HTMLElement | null }\"\n :data-gr-transfer-panel=\"side\"\n :class=\"grTransferPanelClass(dragging.spot.value?.side === side)\"\n :style=\"panelStyle\"\n >\n <slot\n name=\"header\"\n :side=\"side\"\n :title=\"titles[side]\"\n :selected=\"selections[side].keys.size\"\n :total=\"itemsOf(side).length\"\n :shown=\"visible[side].length\"\n >\n <div :class=\"grTransferHeaderClass(resolvedSize)\">\n <!--\n Над пустой панелью отметка не рисуется вовсе, а не рисуется\n выключенной: выключенный орган управления сообщает, что выбирать\n есть что. Тот же довод, что у стрелок `GrCarousel` на краю.\n -->\n <GrCheckbox\n v-if=\"visible[side].length > 0\"\n :model-value=\"allState(side) === 'checked'\"\n :indeterminate=\"allState(side) === 'indeterminate'\"\n :disabled=\"isDisabled\"\n :size=\"resolvedSize\"\n :aria-label=\"t('gr.transfer.selectAll', 'Select everything shown')\"\n @update:model-value=\"toggleAll(side)\"\n />\n <span\n :id=\"side === 'source' ? sourceTitleId : targetTitleId\"\n :class=\"transferTitleClass\"\n >{{ titles[side] }}</span>\n <span :class=\"transferCounterClass\">{{ counterText(side) }}</span>\n\n <!--\n Перестановка видимым органом управления, а не только сочетанием\n `Alt` + стрелка: аккорд её ускоряет, но сам по себе неоткрываем.\n -->\n <template v-if=\"side === 'target' && sortable && visible[side].length > 1\">\n <button\n type=\"button\"\n data-gr-transfer-move-up\n :class=\"grTransferReorderClass(resolvedSize)\"\n :aria-disabled=\"canReorder ? undefined : 'true'\"\n :aria-label=\"t('gr.transfer.moveUp', 'Move earlier')\"\n @click=\"canReorder && moveBlock(-1)\"\n >\n <IconArrowLeft :class=\"transferReorderIconClass\" aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n data-gr-transfer-move-down\n :class=\"grTransferReorderClass(resolvedSize)\"\n :aria-disabled=\"canReorder ? undefined : 'true'\"\n :aria-label=\"t('gr.transfer.moveDown', 'Move later')\"\n @click=\"canReorder && moveBlock(1)\"\n >\n <IconArrowRight :class=\"transferReorderIconClass\" aria-hidden=\"true\" />\n </button>\n </template>\n </div>\n </slot>\n\n <div\n v-if=\"searchable\"\n :ref=\"el => { searchEls[side] = el as HTMLElement | null }\"\n :class=\"grTransferSearchClass(resolvedSize)\"\n >\n <GrInput\n :model-value=\"queries[side]\"\n type=\"search\"\n clearable\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :loading=\"loading\"\n :placeholder=\"t('gr.transfer.search', 'Search')\"\n :aria-label=\"`${titles[side]} — ${t('gr.transfer.search', 'Search')}`\"\n @update:model-value=\"(value: string) => onSearch(side, value)\"\n @keydown=\"(event: KeyboardEvent) => onSearchKeydown(side, event)\"\n />\n </div>\n\n <!--\n Загрузку объявляет живой регион: смена одного пустого текста на другой\n сама себя не объявляет, и пользователь скринридера получил бы тишину.\n -->\n <p :class=\"transferStatusClass\" role=\"status\" aria-live=\"polite\">\n {{ loading ? resolvedLoadingText : (isFiltered(side) ? shownText(side) : '') }}\n </p>\n\n <!--\n Список рисуется всегда, даже пустым: на нём висят `aria-required`,\n `aria-invalid` и связь с текстом ошибки, и исчезать они обязаны меньше\n всего именно тогда, когда поле пустое.\n -->\n <div\n :id=\"side === 'source' ? sourceListId : (fieldId ?? targetListId)\"\n :ref=\"el => { listEls[side] = el as HTMLElement | null }\"\n :data-gr-transfer-list=\"side\"\n :data-overflow=\"listOverflow[side]\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n tabindex=\"-1\"\n :data-gr-virtual=\"virtual ? '' : undefined\"\n :class=\"transferListBase\"\n :style=\"listStyle(side)\"\n :aria-label=\"hasHeaderSlot ? titles[side] : undefined\"\n :aria-labelledby=\"hasHeaderSlot\n ? (side === 'target' ? fieldLabelId : undefined)\n : (side === 'target' && fieldLabelId\n ? `${fieldLabelId} ${targetTitleId}`\n : (side === 'source' ? sourceTitleId : targetTitleId))\"\n :aria-describedby=\"side === 'target' ? describedBy : undefined\"\n :aria-invalid=\"side === 'target' && isInvalid ? 'true' : undefined\"\n :aria-required=\"side === 'target' && isRequired ? 'true' : undefined\"\n :aria-readonly=\"side === 'target' && isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @keydown=\"(event: KeyboardEvent) => onListKeydown(side, event)\"\n @scroll.passive=\"scheduleOverflow\"\n >\n <div\n v-for=\"(item, index) in renderedOf(side)\"\n :key=\"keyOf(item)\"\n :ref=\"(el) => {\n registerRow(side, keyOf(item), el as Element | null)\n if (virtual) virtualizerOf(side).measure(absoluteIndex(side, index), el as Element | null)\n }\"\n data-gr-transfer-option\n role=\"option\"\n :aria-selected=\"selections[side].keys.has(keyOf(item)) ? 'true' : 'false'\"\n :aria-disabled=\"disabledOf(item) ? 'true' : undefined\"\n :aria-setsize=\"visible[side].length\"\n :aria-posinset=\"absoluteIndex(side, index) + 1\"\n :tabindex=\"rovingOf(side).tabindexFor(keyOf(item))\"\n :class=\"grTransferOptionClass({\n size: resolvedSize,\n selected: selections[side].keys.has(keyOf(item)),\n disabled: disabledOf(item),\n draggable: resolvedDraggable && !isLocked,\n dragging: isDraggingKey(side, keyOf(item)),\n arrived: arrived.has(keyOf(item)),\n indicator: indicatorFor(side, keyOf(item)),\n })\"\n @pointerdown=\"(event: PointerEvent) => onRowPointerDown(side, keyOf(item), event)\"\n @click=\"(event: MouseEvent) => onOptionClick(side, keyOf(item), event)\"\n @focus=\"rovingOf(side).setActive(keyOf(item))\"\n @dblclick=\"!disabledOf(item) && transfer([keyOf(item)], side === 'source' ? 'toTarget' : 'toSource')\"\n >\n <span\n aria-hidden=\"true\"\n :class=\"grTransferMarkClass(resolvedSize, selections[side].keys.has(keyOf(item)))\"\n >\n <IconCheck\n v-if=\"selections[side].keys.has(keyOf(item))\"\n :class=\"transferMarkIconClass\"\n />\n </span>\n <slot\n name=\"item\"\n :item=\"item\"\n :side=\"side\"\n :index=\"absoluteIndex(side, index)\"\n :selected=\"selections[side].keys.has(keyOf(item))\"\n :disabled=\"disabledOf(item)\"\n >\n <span :class=\"transferLabelClass\">{{ labelOf(item) }}</span>\n </slot>\n </div>\n </div>\n\n <!--\n Текст пустоты и текст загрузки — соседи списка, а не его потомки: потомки\n роли презентационны.\n\n Состояния взаимоисключающи: «ничего не найдено» под незакончившимся\n запросом — утверждение, которого никто не проверял.\n -->\n <slot v-if=\"loading && visible[side].length === 0\" name=\"loading\" :side=\"side\">\n <p data-gr-transfer-loading :class=\"grTransferEmptyClass(resolvedSize)\">\n {{ resolvedLoadingText }}\n </p>\n </slot>\n\n <slot v-else-if=\"visible[side].length === 0\" name=\"empty\" :side=\"side\" :filtered=\"isFiltered(side)\">\n <p :class=\"grTransferEmptyClass(resolvedSize)\">\n {{ emptyText(side) }}\n </p>\n </slot>\n </div>\n\n <Teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <div\n v-if=\"ghost\"\n data-gr-transfer-ghost\n aria-hidden=\"true\"\n :class=\"transferGhostClass\"\n :style=\"ghostStyle\"\n >\n <span :class=\"transferGhostLabelClass\">{{ ghost.label }}</span>\n <span v-if=\"ghost.rest > 0\" :class=\"transferGhostCountClass\">+{{ ghost.rest }}</span>\n </div>\n </Teleport>\n\n <div :class=\"grTransferActionsClass(resolvedSize)\" style=\"order: 1\">\n <slot\n name=\"actions\"\n :to-target=\"() => transferSelected('toTarget')\"\n :to-source=\"() => transferSelected('toSource')\"\n :can-to-target=\"canToTarget\"\n :can-to-source=\"canToSource\"\n >\n <GrButtonGroup orientation=\"vertical\" attached :size=\"resolvedSize\">\n <GrButton\n data-gr-transfer-to-target\n variant=\"secondary\"\n :aria-disabled=\"canToTarget ? undefined : 'true'\"\n :class=\"canToTarget ? '' : transferActionInertClass\"\n :aria-label=\"t('gr.transfer.toTarget', 'Move to selected')\"\n @click=\"canToTarget && transferSelected('toTarget')\"\n >\n <IconChevronRight :class=\"transferActionIconClass\" aria-hidden=\"true\" />\n </GrButton>\n <GrButton\n data-gr-transfer-to-source\n variant=\"secondary\"\n :aria-disabled=\"canToSource ? undefined : 'true'\"\n :class=\"canToSource ? '' : transferActionInertClass\"\n :aria-label=\"t('gr.transfer.toSource', 'Move back to available')\"\n @click=\"canToSource && transferSelected('toSource')\"\n >\n <IconChevronLeft :class=\"transferActionIconClass\" aria-hidden=\"true\" />\n </GrButton>\n </GrButtonGroup>\n </slot>\n </div>\n </div>\n</template>\n\n<style>\n/*\n * Распорка виртуализованной панели. Правило повторяется в каждом компоненте с\n * виртуализацией намеренно: единственный глобальный стиль пакета\n * (`styles/base.css`) потребитель вправе не подключать, и уехавшее туда правило\n * молча ломало бы прокрутку. Копии сверяет `src/__tests__/virtualSpacer.test.ts`.\n */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n\n/*\n * Колонка кнопок стоит между панелями, а в DOM идёт после них: так `Tab`\n * проходит левую панель целиком до кнопок, а `order` ставит её на место.\n * Порядок DOM менять нельзя — в RTL он перевернётся сам вместе с флексом.\n */\n[data-gr-transfer] > [data-gr-transfer-panel='source'] { order: 0; }\n[data-gr-transfer] > [data-gr-transfer-panel='target'] { order: 2; }\n\n[data-gr-transfer-list][data-overflow='start'] {\n --gr-transfer-list-mask: linear-gradient(to bottom, transparent 0, #000 var(--gr-transfer-fade, 1.25rem));\n}\n\n[data-gr-transfer-list][data-overflow='end'] {\n --gr-transfer-list-mask: linear-gradient(to bottom, #000 calc(100% - var(--gr-transfer-fade, 1.25rem)), transparent 100%);\n}\n\n[data-gr-transfer-list][data-overflow='both'] {\n --gr-transfer-list-mask: linear-gradient(\n to bottom,\n transparent 0,\n #000 var(--gr-transfer-fade, 1.25rem),\n #000 calc(100% - var(--gr-transfer-fade, 1.25rem)),\n transparent 100%\n );\n}\n\n[data-gr-transfer-list]:is([data-overflow='start'], [data-overflow='end'], [data-overflow='both']) {\n -webkit-mask-image: var(--gr-transfer-list-mask);\n mask-image: var(--gr-transfer-list-mask);\n}\n\n/*\n * Гашение кнопки, которой некуда переносить. Селектор по атрибуту внутри корня\n * сильнее одноклассовой утилиты `GrButton`, поэтому фон не зависит от порядка\n * правил в собранном CSS. Фоном, а не `opacity`: прозрачность разбавляет\n * выверенные на AA токены текста.\n */\n/*\n * Подсветка прибытия. Без `animation-fill-mode`, исходный кадр — обычная строка:\n * глобальный кламп `prefers-reduced-motion` доигрывает её за 0.01ms и оставляет\n * ровно тот вид, что и так был бы.\n */\n@keyframes gr-transfer-arrive {\n from { background: var(--gr-transfer-arrived-bg, color-mix(in srgb, var(--gr-primary) 32%, transparent)); }\n to { background: transparent; }\n}\n\n[data-gr-transfer] .gr-transfer-arrived {\n animation: gr-transfer-arrive var(--gr-duration-slow) var(--gr-ease-out);\n}\n\n/* Пока строка «в руке», курсор обязан это показывать везде, а не только над ней. */\n[data-gr-transfer][data-dragging='true'],\n[data-gr-transfer][data-dragging='true'] * {\n cursor: grabbing !important;\n user-select: none;\n}\n\n/*\n * Пустое место на время жеста: пунктир и приглушённый текст читаются как «строка\n * сейчас в руке», тогда как прежняя бледная подложка оставляла её почти обычной.\n */\n/*\n * Селектор нарочно длиннее одноклассового: строка при нажатии получает фокус, а\n * `focus:outline-none` сбрасывает `outline` утилитой той же специфичности —\n * пунктир проигрывал бы ей по порядку правил.\n */\n[data-gr-transfer] [data-gr-transfer-option].gr-transfer-vacated {\n background: var(--gr-transfer-dragging-bg, var(--gr-muted));\n color: var(--gr-muted-fg);\n outline: 1px dashed var(--gr-brd);\n outline-offset: -3px;\n}\n\n[data-gr-transfer] button[aria-disabled='true'] {\n background: var(--gr-muted);\n color: var(--gr-disabled-fg);\n}\n</style>\n","<script setup lang=\"ts\" generic=\"TItem extends Record<string, unknown> = Record<string, unknown>\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, useSlots, watch } from 'vue'\n\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { usePortalTarget } from '../../composables/usePortalTarget'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton'\nimport GrButtonGroup from '../GrButtonGroup'\nimport GrCheckbox from '../GrCheckbox'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport GrInput from '../GrInput'\nimport { matchesQueryParts, normalizeOptionQuery } from '../shared/optionFilter'\nimport type { GrScrollOverflow } from '../shared/scrollOverflow'\nimport { resolveScrollOverflow } from '../shared/scrollOverflow'\nimport type { GrComponentSize } from '../shared/sizes'\nimport {\n grTransferActionsClass,\n grTransferEmptyClass,\n grTransferHeaderClass,\n grTransferMarkClass,\n grTransferOptionClass,\n grTransferPanelClass,\n grTransferReorderClass,\n grTransferSearchClass,\n transferActionIconClass,\n transferActionInertClass,\n transferCounterClass,\n transferGhostClass,\n transferGhostCountClass,\n transferGhostLabelClass,\n transferLabelClass,\n transferListBase,\n transferMarkIconClass,\n transferReorderIconClass,\n transferRootBase,\n transferStatusClass,\n transferTitleClass,\n} from './grTransferStyles'\nimport type { GrTransferDirection, GrTransferKey, GrTransferSide } from './transferModel'\nimport {\n edgeTarget,\n insertKeys,\n keyAfterRemoval,\n normalizeKeys,\n removeKeys,\n splitByModel,\n stepTarget,\n} from './transferModel'\nimport type { GrTransferDragSession, GrTransferDropSpot } from './useTransferDrag'\nimport { useTransferDrag } from './useTransferDrag'\nimport type { GrTransferSelection } from './transferSelection'\nimport {\n allVisibleState,\n applySelect,\n emptySelection,\n pruneSelection,\n selectIntentFrom,\n toggleAllVisible,\n} from './transferSelection'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconArrowLeft from '~icons/lucide/arrow-left'\nimport IconArrowRight from '~icons/lucide/arrow-right'\nimport IconChevronLeft from '~icons/lucide/chevron-left'\nimport IconChevronRight from '~icons/lucide/chevron-right'\n\nexport type GrTransferItemKey<T> = string | ((item: T) => GrTransferKey)\nexport type GrTransferItemLabel<T> = string | ((item: T) => string)\nexport type GrTransferItemFlag<T> = string | ((item: T) => boolean)\n\nexport interface GrTransferProps<T extends Record<string, unknown> = Record<string, unknown>> {\n /** Каталог целиком: обе панели — одна его раскладка. */\n items: T[]\n /** Ключи правой панели **в её порядке**: порядок и есть значение. */\n modelValue: GrTransferKey[]\n itemKey?: GrTransferItemKey<T>\n itemLabel?: GrTransferItemLabel<T>\n itemDisabled?: GrTransferItemFlag<T>\n /** Имя левой панели. Это доступное имя её `listbox`, а не украшение. */\n sourceTitle?: string\n /** Имя правой панели. */\n targetTitle?: string\n /** Поле поиска в каждой панели. */\n searchable?: boolean\n /** Свой матчер: встроенный ищет по `itemLabel`, а строка может показывать больше. */\n filter?: (item: T, query: string) => boolean\n /**\n * Каталог в пути: пустая панель говорит «ищем», а не «ничего не найдено».\n *\n * Проп общий на обе панели, а не свой у каждой: `items` — один каталог, и обе\n * панели его виды, так что пока он едет, пусты обе. Подгрузку запускает\n * потребитель по событию `search`, поэтому и флаг держит он.\n */\n loading?: boolean\n /** Текст индикатора. Не задан — из локали (`gr.transfer.loading`). */\n loadingText?: string\n /** Правую панель можно переставлять. */\n sortable?: boolean\n /** Перетаскивание строк указателем. Усиление поверх кнопок, а не контракт. */\n draggable?: boolean\n /** Высота панелей: обе одинаковы и прокручиваются внутри себя. */\n maxHeight?: number | string\n /**\n * Держать в DOM только окно строк вокруг вьюпорта. Нужен `maxHeight`: без\n * него панель не прокручивается, окна нет и виртуализировать нечего.\n *\n * Перенос от этого не страдает — он идёт по модели, а не по разметке. А вот\n * перетаскивание указателем ограничено отрисованными строками: навести\n * указатель на то, чего нет на экране, всё равно нечем.\n */\n virtual?: boolean\n size?: GrComponentSize\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n ariaLabel?: string\n}\n\nexport interface GrTransferEmits {\n (e: 'update:modelValue', value: GrTransferKey[]): void\n (e: 'change', value: GrTransferKey[]): void\n (e: 'transfer', keys: GrTransferKey[], direction: GrTransferDirection): void\n (e: 'search', query: string, side: GrTransferSide): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrTransferProps<TItem>>(), {\n itemKey: undefined,\n itemLabel: undefined,\n itemDisabled: undefined,\n sourceTitle: undefined,\n targetTitle: undefined,\n searchable: true,\n filter: undefined,\n loading: false,\n loadingText: undefined,\n sortable: true,\n draggable: undefined,\n maxHeight: undefined,\n virtual: false,\n size: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrTransferEmits>()\n\ndefineSlots<{\n /** Своя строка. Слот доменный: у соседей `item` — строка списка, здесь тоже. */\n item?: (props: {\n item: TItem\n side: GrTransferSide\n index: number\n selected: boolean\n disabled: boolean\n }) => unknown\n /** Своя шапка панели: имя, счётчик, отметка «выбрать всё». */\n header?: (props: {\n side: GrTransferSide\n title: string\n selected: number\n total: number\n shown: number\n }) => unknown\n /** Своя колонка кнопок между панелями. */\n actions?: (props: {\n toTarget: () => void\n toSource: () => void\n canToTarget: boolean\n canToSource: boolean\n }) => unknown\n /** Пустая панель. `filtered` — пусто из-за поиска, а не по сути. */\n empty?: (props: { side: GrTransferSide, filtered: boolean }) => unknown\n /** Панель под загрузкой — вместо текста «ищем». */\n loading?: (props: { side: GrTransferSide }) => unknown\n}>()\n\nconst slots = useSlots()\n\n/**\n * Свой `#header` уносит с собой заголовок панели, а вместе с ним и `id`, на\n * который смотрит `aria-labelledby` списка: панель осталась бы без доступного\n * имени, и axe ловит это как `aria-input-field-name`. Имя поэтому не зависит от\n * разметки потребителя — при своей шапке оно приходит из `aria-label`.\n */\nconst hasHeaderSlot = computed(() => Boolean(slots.header))\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTransfer' })\nconst resolvedDraggable = useGrComponentProp('GrTransfer', 'draggable', () => props.draggable, true)\n\nconst {\n disabled: isDisabled,\n readonly: isReadonly,\n invalid: isInvalid,\n required: isRequired,\n locked: isLocked,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n} = useGrFormControl(() => props)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst uid = useId()\nconst sourceTitleId = `${uid}-source-title`\nconst targetTitleId = `${uid}-target-title`\nconst sourceListId = `${uid}-source-list`\nconst targetListId = `${uid}-target-list`\n\nif (__GR_DEV__) {\n if (!Array.isArray(props.items)) {\n console.warn(\n `[granularity] GrTransfer: обязательный проп \\`items\\` должен быть массивом — получено ${typeof props.items}.`,\n )\n }\n if (!Array.isArray(props.modelValue)) {\n console.warn(\n `[granularity] GrTransfer: обязательный проп \\`modelValue\\` должен быть массивом — получено ${typeof props.modelValue}.`,\n )\n }\n}\n\n/**\n * Синтетический ключ для элемента без своего: общий ключ пометил бы выбранными\n * все строки разом. Приём и причина — из `GrDataTable`.\n */\nconst syntheticKeys = new WeakMap<object, string>()\nlet syntheticCount = 0\nlet warnedSynthetic = false\n\nfunction keyOf(item: TItem): GrTransferKey {\n // Фолбэк здесь, а не в `withDefaults`: у дженерик-компонента вывод дефолта\n // не снимает опциональность, и `item[source]` переставал типизироваться.\n const source = props.itemKey ?? 'id'\n const value = typeof source === 'function' ? source(item) : item[source]\n\n if (typeof value === 'string' && value !== '')\n return value\n if (typeof value === 'number')\n return value\n\n const known = syntheticKeys.get(item)\n if (known !== undefined)\n return known\n\n syntheticCount += 1\n const generated = `${uid}-synthetic-${syntheticCount}`\n syntheticKeys.set(item, generated)\n\n if (__GR_DEV__ && !warnedSynthetic) {\n warnedSynthetic = true\n console.warn(\n '[granularity] GrTransfer: у элемента нет значения `itemKey` — выдан временный ключ. '\n + 'Он не переживёт перезагрузку данных, и `modelValue` с ним не сойдётся: задайте `itemKey`.',\n )\n }\n\n return generated\n}\n\nfunction labelOf(item: TItem): string {\n const source = props.itemLabel ?? 'label'\n\n return typeof source === 'function' ? source(item) : String(item[source] ?? '')\n}\n\nfunction disabledOf(item: TItem): boolean {\n const source = props.itemDisabled ?? 'disabled'\n\n return typeof source === 'function' ? source(item) : Boolean(item[source])\n}\n\nconst split = computed(() => splitByModel(props.items ?? [], keyOf, props.modelValue ?? []))\n\nif (__GR_DEV__) {\n watch(split, (value) => {\n if (value.duplicated.length > 0) {\n console.warn(\n `[granularity] GrTransfer: ключи повторяются в \\`items\\` (${value.duplicated.join(', ')}) — `\n + 'рисуется первый элемент с таким ключом.',\n )\n }\n /*\n * Под загрузкой неполный каталог — норма, а не ошибка потребителя. Без этого\n * серверный поиск сужает `items`, выбранные ключи оказываются вне сужения, и\n * предупреждение срабатывает на каждое нажатие клавиши.\n */\n if (!props.loading && value.unresolved.length > 0 && (props.items?.length ?? 0) > 0) {\n console.warn(\n `[granularity] GrTransfer: ключи из \\`modelValue\\` не найдены в \\`items\\` (${value.unresolved.join(', ')}). `\n + 'Они сохранены в значении, но не показаны: каталог мог ещё не приехать.',\n )\n }\n }, { immediate: true })\n}\n\nconst queries = ref<Record<GrTransferSide, string>>({ source: '', target: '' })\nconst selections = ref<Record<GrTransferSide, GrTransferSelection>>({\n source: emptySelection,\n target: emptySelection,\n})\n\nfunction itemsOf(side: GrTransferSide): TItem[] {\n return side === 'source' ? split.value.source : split.value.target\n}\n\nfunction matches(item: TItem, query: string): boolean {\n if (props.filter)\n return props.filter(item, query)\n\n return matchesQueryParts([labelOf(item)], normalizeOptionQuery(query))\n}\n\nfunction visibleOf(side: GrTransferSide): TItem[] {\n const query = queries.value[side]\n if (!props.searchable || normalizeOptionQuery(query) === '')\n return itemsOf(side)\n\n return itemsOf(side).filter(item => matches(item, query))\n}\n\nconst visible = computed<Record<GrTransferSide, TItem[]>>(() => ({\n source: visibleOf('source'),\n target: visibleOf('target'),\n}))\n\nconst visibleKeys = computed<Record<GrTransferSide, GrTransferKey[]>>(() => ({\n source: visible.value.source.map(keyOf),\n target: visible.value.target.map(keyOf),\n}))\n\nfunction selectableOf(side: GrTransferSide): (key: GrTransferKey) => boolean {\n return (key) => {\n const item = itemsOf(side).find(candidate => keyOf(candidate) === key)\n\n return item !== undefined && !disabledOf(item)\n }\n}\n\n// Состав каталога сменился — выделение чистится от исчезнувших ключей.\nwatch(split, () => {\n selections.value = {\n source: pruneSelection(selections.value.source, split.value.source.map(keyOf)),\n target: pruneSelection(selections.value.target, split.value.target.map(keyOf)),\n }\n})\n\nconst titles = computed<Record<GrTransferSide, string>>(() => ({\n source: props.sourceTitle ?? t('gr.transfer.sourceTitle', 'Available'),\n target: props.targetTitle ?? t('gr.transfer.targetTitle', 'Selected'),\n}))\n\nfunction setSelection(side: GrTransferSide, next: GrTransferSelection): void {\n selections.value = { ...selections.value, [side]: next }\n}\n\nfunction toggleAll(side: GrTransferSide): void {\n if (isDisabled.value)\n return\n\n setSelection(side, toggleAllVisible(selections.value[side], visibleKeys.value[side], selectableOf(side)))\n}\n\n/** Что реально уедет: отмеченное минус запрещённое. Скрытое поиском — уезжает. */\nfunction movableOf(side: GrTransferSide): GrTransferKey[] {\n const selectable = selectableOf(side)\n const order = itemsOf(side).map(keyOf)\n\n return order.filter(key => selections.value[side].keys.has(key) && selectable(key))\n}\n\nconst canToTarget = computed(() => !isLocked.value && movableOf('source').length > 0)\nconst canToSource = computed(() => !isLocked.value && movableOf('target').length > 0)\n\nfunction commit(next: GrTransferKey[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nasync function transfer(keys: GrTransferKey[], direction: GrTransferDirection): Promise<void> {\n if (isLocked.value || keys.length === 0)\n return\n\n const from: GrTransferSide = direction === 'toTarget' ? 'source' : 'target'\n const to: GrTransferSide = direction === 'toTarget' ? 'target' : 'source'\n const model = normalizeKeys(props.modelValue ?? [])\n\n const nextFocus = keyAfterRemoval(visibleKeys.value[from], keys, rovingOf(from).rovingKey.value)\n\n commit(direction === 'toTarget' ? insertKeys(model, keys, null) : removeKeys(model, keys))\n\n // Выделение переезжает вместе со строками: `Alt`+стрелка сразу ставит их на\n // место, а возврат — одно нажатие.\n selections.value = {\n ...selections.value,\n [from]: emptySelection,\n [to]: { keys: new Set(keys), anchor: keys[0] },\n }\n\n markArrived(keys)\n emit('transfer', keys, direction)\n announce(t('gr.transfer.moved', '{count} moved to {list}', {\n count: keys.length,\n n: keys.length,\n list: titles.value[to],\n }))\n\n await nextTick()\n if (nextFocus !== undefined)\n void rovingOf(from).focusKey(nextFocus)\n else void rovingOf(to).focusKey(keys[0])\n}\n\nfunction transferSelected(direction: GrTransferDirection): void {\n const side: GrTransferSide = direction === 'toTarget' ? 'source' : 'target'\n const keys = movableOf(side)\n if (keys.length > 0) {\n void transfer(keys, direction)\n return\n }\n\n // Ничего не отмечено — переносится строка под фокусом: так `Enter` работает\n // сразу, без обязательного предварительного `Space`.\n const focused = rovingOf(side).rovingKey.value\n if (focused !== undefined && selectableOf(side)(focused))\n void transfer([focused], direction)\n}\n\n/** Перестановка отключена, пока панель отфильтрована: см. `docs/components/GrTransfer.md`. */\nconst reorderAllowed = computed(() => props.sortable\n && !isLocked.value\n && normalizeOptionQuery(queries.value.target) === '')\n\nfunction reorder(target: GrTransferKey | null | undefined, keys: GrTransferKey[]): void {\n if (target === undefined || keys.length === 0)\n return\n\n const model = normalizeKeys(props.modelValue ?? [])\n commit(insertKeys(model, keys, target))\n\n const position = removeKeys(model, keys).findIndex(key => key === target)\n announce(t('gr.transfer.reordered', 'Position {position} of {count}', {\n position: (position < 0 ? model.length - keys.length : position) + 1,\n count: model.length,\n }))\n}\n\nfunction moveBlock(delta: 1 | -1): void {\n const keys = movableOf('target')\n const moving = keys.length > 0 ? keys : blockUnderFocus('target')\n if (moving.length === 0)\n return\n\n if (!reorderAllowed.value) {\n if (props.sortable && !isLocked.value)\n announce(t('gr.transfer.reorderFiltered', 'Reordering is off while a search is active'))\n return\n }\n\n reorder(stepTarget(normalizeKeys(props.modelValue ?? []), moving, delta), moving)\n}\n\nfunction moveBlockToEdge(edge: 'start' | 'end'): void {\n const keys = movableOf('target')\n const moving = keys.length > 0 ? keys : blockUnderFocus('target')\n if (moving.length === 0 || !reorderAllowed.value)\n return\n\n reorder(edgeTarget(normalizeKeys(props.modelValue ?? []), moving, edge), moving)\n}\n\nfunction blockUnderFocus(side: GrTransferSide): GrTransferKey[] {\n const focused = rovingOf(side).rovingKey.value\n\n return focused !== undefined && selectableOf(side)(focused) ? [focused] : []\n}\n\nconst sourceRows = ref<Map<GrTransferKey, HTMLElement>>(new Map())\nconst targetRows = ref<Map<GrTransferKey, HTMLElement>>(new Map())\nconst searchEls = ref<Record<GrTransferSide, HTMLElement | null>>({ source: null, target: null })\nconst panelEls = ref<Record<GrTransferSide, HTMLElement | null>>({ source: null, target: null })\nconst listEls = ref<Record<GrTransferSide, HTMLElement | null>>({ source: null, target: null })\n\nfunction rowsOf(side: GrTransferSide): Map<GrTransferKey, HTMLElement> {\n return side === 'source' ? sourceRows.value : targetRows.value\n}\n\nlet isUnmounting = false\n\nonBeforeUnmount(() => {\n isUnmounting = true\n})\n\n/**\n * Строка размонтируется — снимаем регистрацию, а если фокус был на ней, уводим\n * его на сам список.\n *\n * При виртуализации это не редкость: колесо мыши уносит сфокусированную строку\n * из окна, и без перевода фокус упал бы на `body`. Обработчик клавиш висит на\n * списке, до `body` он не достаёт, и клавиатура панели умерла бы до клика мышью.\n *\n * Элемент берётся из карты, а не из аргумента: Vue обнуляет function ref ДО\n * удаления узла, то есть в момент вызова фокус ещё на строке.\n */\nfunction registerRow(side: GrTransferSide, key: GrTransferKey, el: Element | null): void {\n const map = rowsOf(side)\n\n if (el instanceof HTMLElement) {\n map.set(key, el)\n return\n }\n\n const previous = map.get(key)\n const active = typeof document === 'undefined' ? null : document.activeElement\n const heldFocus = Boolean(previous && active && (previous === active || previous.contains(active)))\n\n map.delete(key)\n\n if (heldFocus && !isUnmounting)\n listEls.value[side]?.focus({ preventScroll: true })\n}\n\n// ————— Виртуализация панелей.\n\n/**\n * Виртуализатор просит `Ref` на контейнер, а панели хранятся одной картой на обе\n * стороны. Отдельная ссылка на сторону — дешевле, чем разводить карту на два рефа\n * и синхронизировать их вручную.\n */\nconst sourceListEl = computed(() => listEls.value.source)\nconst targetListEl = computed(() => listEls.value.target)\n\n/** Оценка высоты строки до первого замера: считает сам виртуализатор по образцам. */\nconst ROW_ESTIMATE_PX = 36\n\nfunction makeVirtualizer(side: GrTransferSide) {\n return useVirtualList({\n container: side === 'source' ? sourceListEl : targetListEl,\n count: () => (props.virtual ? visible.value[side].length : 0),\n // Поиск и перенос меняют состав панели — замеры прошлого набора невалидны.\n source: () => visible.value[side],\n itemSize: () => ROW_ESTIMATE_PX,\n /*\n * Запасное окно до первого замера — высота панели, а не списка: список\n * тянется флексом и своей высоты в пропах не имеет. Оценка выходит\n * завышенной, то есть в первом кадре строк рисуется с запасом — это\n * безопасная сторона ошибки, и замер её сразу поправляет.\n */\n viewportSize: () => (typeof props.maxHeight === 'number' ? props.maxHeight : undefined),\n })\n}\n\nconst sourceVirtualizer = makeVirtualizer('source')\nconst targetVirtualizer = makeVirtualizer('target')\n\nfunction virtualizerOf(side: GrTransferSide) {\n return side === 'source' ? sourceVirtualizer : targetVirtualizer\n}\n\n/** Строки к отрисовке: при выключенной виртуализации — все. */\nfunction renderedOf(side: GrTransferSide): TItem[] {\n if (!props.virtual)\n return visible.value[side]\n\n const { start, end } = virtualizerOf(side).range.value\n return visible.value[side].slice(start, end)\n}\n\n/** Абсолютный индекс строки: `aria-posinset` обязан считать от всего списка. */\nfunction absoluteIndex(side: GrTransferSide, offsetInWindow: number): number {\n return props.virtual ? virtualizerOf(side).range.value.start + offsetInWindow : offsetInWindow\n}\n\n/**\n * Строки вне окна в DOM нет: `elementFor` вернул бы `null`, и фокус остался бы\n * на месте. Поэтому сперва прокрутка, и только следующим тиком — фокус.\n */\nfunction scrollRowIntoView(side: GrTransferSide, key: GrTransferKey): Promise<void> {\n if (props.virtual) {\n const index = visibleKeys.value[side].indexOf(key)\n if (index >= 0)\n virtualizerOf(side).scrollToIndex(index)\n }\n\n return nextTick()\n}\n\nfunction makeRoving(side: GrTransferSide) {\n return useRovingFocus<GrTransferKey>({\n items: () => visibleKeys.value[side],\n elementFor: key => rowsOf(side).get(key) ?? null,\n beforeFocus: key => scrollRowIntoView(side, key),\n orientation: () => 'vertical',\n // Кольцо не замкнуто: замкнутое делает `Shift`-диапазоны бессмысленными.\n wrap: () => false,\n // Выключенная строка остаётся достижимой — иначе AT не прочтёт, что она есть.\n skipDisabled: () => false,\n onOverflow: (edge) => {\n if (edge !== 'start')\n return false\n\n // Вверх из первой строки — в поле поиска своей панели (приём `GrTreeSelect`).\n const input = searchEls.value[side]?.querySelector('input')\n if (!input)\n return false\n\n input.focus()\n return true\n },\n })\n}\n\nconst sourceRoving = makeRoving('source')\nconst targetRoving = makeRoving('target')\n\nfunction rovingOf(side: GrTransferSide) {\n return side === 'source' ? sourceRoving : targetRoving\n}\n\n/**\n * Признак того, что список продолжается за краем.\n *\n * Полоса прокрутки у панели своя и на macOS невидима, поэтому обрезанная\n * посередине строка читается как дефект отрисовки, а не как «прокрути». Затухание\n * рисует CSS по `data-overflow` — тот же приём, что у ряда вкладок `GrTabs`.\n */\nconst listOverflow = ref<Record<GrTransferSide, GrScrollOverflow>>({ source: 'none', target: 'none' })\nlet overflowObserver: ResizeObserver | null = null\nlet overflowScheduled = false\n\nfunction measureOverflow(): void {\n const next = { source: 'none', target: 'none' } as Record<GrTransferSide, GrScrollOverflow>\n\n for (const side of ['source', 'target'] as GrTransferSide[]) {\n const el = listEls.value[side]\n if (el)\n next[side] = resolveScrollOverflow(el.scrollTop, el.scrollHeight, el.clientHeight)\n }\n\n listOverflow.value = next\n}\n\nfunction scheduleOverflow(): void {\n if (overflowScheduled)\n return\n\n overflowScheduled = true\n void nextTick(() => {\n overflowScheduled = false\n measureOverflow()\n })\n}\n\nonMounted(() => {\n scheduleOverflow()\n\n // На сервере и в jsdom `ResizeObserver` отсутствует — измерять там нечего.\n if (typeof ResizeObserver === 'undefined')\n return\n\n overflowObserver = new ResizeObserver(scheduleOverflow)\n for (const side of ['source', 'target'] as GrTransferSide[]) {\n const el = listEls.value[side]\n if (el)\n overflowObserver.observe(el)\n }\n})\n\nonBeforeUnmount(() => {\n overflowObserver?.disconnect()\n overflowObserver = null\n})\n\nwatch([split, visible], scheduleOverflow)\n\n/** Есть ли что переставлять: иначе кнопки в шапке гасятся, оставаясь в таб-порядке. */\nconst canReorder = computed(() => reorderAllowed.value\n && itemsOf('target').length > 1\n && (movableOf('target').length > 0 || blockUnderFocus('target').length > 0))\n\n/**\n * Ключи, только что приехавшие в панель: подсветка живёт ~1.2 с и снимается сама.\n * Таймер один на компонент — быстрый повторный перенос перезапускает его, а не\n * копит хвосты.\n */\nconst arrived = ref<Set<GrTransferKey>>(new Set())\nlet arrivedTimer: number | null = null\n\nfunction markArrived(keys: readonly GrTransferKey[]): void {\n if (typeof window === 'undefined')\n return\n\n arrived.value = new Set(keys)\n if (arrivedTimer !== null)\n clearTimeout(arrivedTimer)\n\n arrivedTimer = window.setTimeout(() => {\n arrivedTimer = null\n arrived.value = new Set()\n }, 1200)\n}\n\nonBeforeUnmount(() => {\n if (arrivedTimer !== null)\n clearTimeout(arrivedTimer)\n})\n\nconst dragging = useTransferDrag({\n disabled: () => isLocked.value || !resolvedDraggable.value,\n visibleKeys: side => visibleKeys.value[side],\n rowEl: (side, key) => rowsOf(side).get(key) ?? null,\n panelEl: side => panelEls.value[side],\n scrollerEl: side => listEls.value[side],\n // Взялись за отмеченную строку — едет всё выделение; за чужую — только она.\n blockFor: (side, key) => {\n const selectable = selectableOf(side)\n if (!selectable(key))\n return []\n\n const chosen = movableOf(side)\n\n return chosen.includes(key) ? chosen : [key]\n },\n allowSameSide: side => side === 'target' && reorderAllowed.value,\n onDrop: (session, spot) => {\n const model = normalizeKeys(props.modelValue ?? [])\n\n if (spot.side === session.side) {\n reorder(spot.before, [...session.keys])\n return\n }\n\n if (spot.side === 'target') {\n commit(insertKeys(model, [...session.keys], spot.before))\n markArrived(session.keys)\n emit('transfer', [...session.keys], 'toTarget')\n announce(t('gr.transfer.moved', '{count} moved to {list}', {\n count: session.keys.length,\n n: session.keys.length,\n list: titles.value.target,\n }))\n return\n }\n\n commit(removeKeys(model, [...session.keys]))\n markArrived(session.keys)\n emit('transfer', [...session.keys], 'toSource')\n announce(t('gr.transfer.moved', '{count} moved to {list}', {\n count: session.keys.length,\n n: session.keys.length,\n list: titles.value.source,\n }))\n },\n onCancel: () => announce(t('gr.transfer.cancelled', 'Move cancelled')),\n})\n\n/**\n * Вызов через обработчик, а не `@pointerdown=\"dragging.startFrom(...)\"`: Vue\n * считает такое выражение инлайн-инструкцией и возвращённую функцию\n * выбрасывает — жест не начинался бы вовсе. Приём `GrSortableList`.\n */\nfunction onRowPointerDown(side: GrTransferSide, key: GrTransferKey, event: PointerEvent): void {\n dragging.startFrom(side, key)(event)\n}\n\n/**\n * Подпись переносимого. Первая строка блока названа, остальные — числом: список\n * из десяти имён под курсором закрыл бы то самое место, куда человек целится.\n */\nconst ghost = computed(() => {\n const session = dragging.session.value\n if (!session || session.keys.length === 0)\n return null\n\n const first = itemsOf(session.side).find(item => keyOf(item) === session.keys[0])\n\n return {\n label: first ? labelOf(first) : String(session.keys[0]),\n rest: session.keys.length - 1,\n }\n})\n\nconst ghostStyle = computed(() => ({\n // Смещение от курсора: под остриём должно оставаться видно, куда целишься.\n transform: `translate3d(${dragging.pointer.value.x + 12}px, ${dragging.pointer.value.y + 12}px, 0)`,\n}))\n\nfunction indicatorFor(side: GrTransferSide, key: GrTransferKey): 'before' | 'after' | null {\n const spot: GrTransferDropSpot | null = dragging.spot.value\n if (!spot || spot.side !== side)\n return null\n\n if (spot.before === key)\n return 'before'\n\n const keys = visibleKeys.value[side]\n\n return spot.before === null && keys[keys.length - 1] === key ? 'after' : null\n}\n\nfunction isDraggingKey(side: GrTransferSide, key: GrTransferKey): boolean {\n const session: GrTransferDragSession | null = dragging.session.value\n\n return session !== null && session.side === side && session.keys.includes(key)\n}\n\nfunction onOptionClick(side: GrTransferSide, key: GrTransferKey, event: MouseEvent): void {\n // Клик после протяжки выделение не трогает: иначе любое перетаскивание\n // схлопывало бы блок в одну строку ровно в момент отпускания.\n if (isDisabled.value || dragging.consumeClick())\n return\n\n rovingOf(side).setActive(key)\n setSelection(side, applySelect(\n selections.value[side],\n key,\n selectIntentFrom(event),\n visibleKeys.value[side],\n selectableOf(side),\n ))\n}\n\nfunction extendRange(side: GrTransferSide, key: GrTransferKey): void {\n setSelection(side, applySelect(\n selections.value[side],\n key,\n { mode: 'range', additive: false },\n visibleKeys.value[side],\n selectableOf(side),\n ))\n}\n\nfunction onListKeydown(side: GrTransferSide, event: KeyboardEvent): void {\n if (isDisabled.value || visibleKeys.value[side].length === 0)\n return\n\n const roving = rovingOf(side)\n const current = roving.rovingKey.value\n\n if ((event.ctrlKey || event.metaKey) && (event.key === 'a' || event.key === 'A')) {\n event.preventDefault()\n toggleAll(side)\n return\n }\n\n if (event.key === ' ') {\n event.preventDefault()\n if (current === undefined)\n return\n\n if (event.shiftKey) {\n extendRange(side, current)\n }\n else {\n setSelection(side, applySelect(\n selections.value[side],\n current,\n { mode: 'toggle', additive: true },\n visibleKeys.value[side],\n selectableOf(side),\n ))\n }\n return\n }\n\n if (event.key === 'Enter') {\n event.preventDefault()\n transferSelected(side === 'source' ? 'toTarget' : 'toSource')\n return\n }\n\n if (side === 'target' && event.altKey) {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault()\n moveBlock(event.key === 'ArrowDown' ? 1 : -1)\n return\n }\n if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault()\n moveBlockToEdge(event.key === 'Home' ? 'start' : 'end')\n return\n }\n }\n\n // Стрелки и `Home`/`End` ведёт примитив; `Shift` растягивает диапазон следом.\n if (!roving.handleNavigationKeys(event))\n return\n\n const next = roving.rovingKey.value\n if (event.shiftKey && next !== undefined)\n extendRange(side, next)\n}\n\nfunction onSearchKeydown(side: GrTransferSide, event: KeyboardEvent): void {\n if (event.key !== 'ArrowDown')\n return\n\n const first = visibleKeys.value[side][0]\n if (first === undefined)\n return\n\n event.preventDefault()\n void rovingOf(side).focusKey(first)\n}\n\nfunction onSearch(side: GrTransferSide, value: string): void {\n queries.value = { ...queries.value, [side]: value }\n emit('search', value, side)\n}\n\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\n/**\n * Скролл-протяжённость виртуализованного списка держат псевдоэлементы\n * контейнера: распорка приезжает переменными в том же патче, что и сами строки,\n * и схлопнуться между кадрами ей нечем.\n */\nfunction listStyle(side: GrTransferSide): Record<string, string> | undefined {\n return props.virtual ? virtualizerOf(side).spacerStyle.value : undefined\n}\n\nconst panelStyle = computed(() => ({\n maxHeight: props.maxHeight === undefined\n ? 'var(--gr-transfer-panel-max-h, 18rem)'\n : typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight,\n}))\n\nfunction counterText(side: GrTransferSide): string {\n return t('gr.transfer.selected', '{count} of {total}', {\n count: selections.value[side].keys.size,\n total: itemsOf(side).length,\n })\n}\n\nfunction shownText(side: GrTransferSide): string {\n return t('gr.transfer.shown', 'Showing {shown} of {total}', {\n shown: visible.value[side].length,\n total: itemsOf(side).length,\n })\n}\n\nfunction emptyText(side: GrTransferSide): string {\n return normalizeOptionQuery(queries.value[side]) === ''\n ? t('gr.transfer.empty', 'Nothing here yet')\n : t('gr.transfer.emptyFiltered', 'Nothing matches the search')\n}\n\nconst resolvedLoadingText = computed(() => props.loadingText ?? t('gr.transfer.loading', 'Loading…'))\n\nfunction isFiltered(side: GrTransferSide): boolean {\n return normalizeOptionQuery(queries.value[side]) !== ''\n}\n\nfunction allState(side: GrTransferSide): 'checked' | 'indeterminate' | 'unchecked' {\n return allVisibleState(selections.value[side], visibleKeys.value[side], selectableOf(side))\n}\n\nfunction focusSide(side: GrTransferSide): void {\n const roving = rovingOf(side)\n const key = roving.rovingKey.value ?? visibleKeys.value[side][0]\n\n if (key !== undefined) {\n void roving.focusKey(key)\n return\n }\n\n searchEls.value[side]?.querySelector('input')?.focus()\n}\n\ndefineExpose({\n focus: () => focusSide('target'),\n blur: () => {\n const active = document.activeElement\n if (active instanceof HTMLElement && rootEl.value?.contains(active))\n active.blur()\n },\n focusSide,\n transfer: (keys: GrTransferKey[], direction: GrTransferDirection) => void transfer(keys, direction),\n selectAll: (side: GrTransferSide) => toggleAll(side),\n clearSelection: (side?: GrTransferSide) => {\n if (side) {\n setSelection(side, emptySelection)\n return\n }\n selections.value = { source: emptySelection, target: emptySelection }\n },\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-transfer\n :data-dragging=\"dragging.session.value ? 'true' : undefined\"\n role=\"group\"\n :class=\"transferRootBase\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <div\n v-for=\"side in (['source', 'target'] as GrTransferSide[])\"\n :key=\"side\"\n :ref=\"el => { panelEls[side] = el as HTMLElement | null }\"\n :data-gr-transfer-panel=\"side\"\n :class=\"grTransferPanelClass(dragging.spot.value?.side === side)\"\n :style=\"panelStyle\"\n >\n <slot\n name=\"header\"\n :side=\"side\"\n :title=\"titles[side]\"\n :selected=\"selections[side].keys.size\"\n :total=\"itemsOf(side).length\"\n :shown=\"visible[side].length\"\n >\n <div :class=\"grTransferHeaderClass(resolvedSize)\">\n <!--\n Над пустой панелью отметка не рисуется вовсе, а не рисуется\n выключенной: выключенный орган управления сообщает, что выбирать\n есть что. Тот же довод, что у стрелок `GrCarousel` на краю.\n -->\n <GrCheckbox\n v-if=\"visible[side].length > 0\"\n :model-value=\"allState(side) === 'checked'\"\n :indeterminate=\"allState(side) === 'indeterminate'\"\n :disabled=\"isDisabled\"\n :size=\"resolvedSize\"\n :aria-label=\"t('gr.transfer.selectAll', 'Select everything shown')\"\n @update:model-value=\"toggleAll(side)\"\n />\n <span\n :id=\"side === 'source' ? sourceTitleId : targetTitleId\"\n :class=\"transferTitleClass\"\n >{{ titles[side] }}</span>\n <span :class=\"transferCounterClass\">{{ counterText(side) }}</span>\n\n <!--\n Перестановка видимым органом управления, а не только сочетанием\n `Alt` + стрелка: аккорд её ускоряет, но сам по себе неоткрываем.\n -->\n <template v-if=\"side === 'target' && sortable && visible[side].length > 1\">\n <button\n type=\"button\"\n data-gr-transfer-move-up\n :class=\"grTransferReorderClass(resolvedSize)\"\n :aria-disabled=\"canReorder ? undefined : 'true'\"\n :aria-label=\"t('gr.transfer.moveUp', 'Move earlier')\"\n @click=\"canReorder && moveBlock(-1)\"\n >\n <IconArrowLeft :class=\"transferReorderIconClass\" aria-hidden=\"true\" />\n </button>\n <button\n type=\"button\"\n data-gr-transfer-move-down\n :class=\"grTransferReorderClass(resolvedSize)\"\n :aria-disabled=\"canReorder ? undefined : 'true'\"\n :aria-label=\"t('gr.transfer.moveDown', 'Move later')\"\n @click=\"canReorder && moveBlock(1)\"\n >\n <IconArrowRight :class=\"transferReorderIconClass\" aria-hidden=\"true\" />\n </button>\n </template>\n </div>\n </slot>\n\n <div\n v-if=\"searchable\"\n :ref=\"el => { searchEls[side] = el as HTMLElement | null }\"\n :class=\"grTransferSearchClass(resolvedSize)\"\n >\n <GrInput\n :model-value=\"queries[side]\"\n type=\"search\"\n clearable\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :loading=\"loading\"\n :placeholder=\"t('gr.transfer.search', 'Search')\"\n :aria-label=\"`${titles[side]} — ${t('gr.transfer.search', 'Search')}`\"\n @update:model-value=\"(value: string) => onSearch(side, value)\"\n @keydown=\"(event: KeyboardEvent) => onSearchKeydown(side, event)\"\n />\n </div>\n\n <!--\n Загрузку объявляет живой регион: смена одного пустого текста на другой\n сама себя не объявляет, и пользователь скринридера получил бы тишину.\n -->\n <p :class=\"transferStatusClass\" role=\"status\" aria-live=\"polite\">\n {{ loading ? resolvedLoadingText : (isFiltered(side) ? shownText(side) : '') }}\n </p>\n\n <!--\n Список рисуется всегда, даже пустым: на нём висят `aria-required`,\n `aria-invalid` и связь с текстом ошибки, и исчезать они обязаны меньше\n всего именно тогда, когда поле пустое.\n -->\n <div\n :id=\"side === 'source' ? sourceListId : (fieldId ?? targetListId)\"\n :ref=\"el => { listEls[side] = el as HTMLElement | null }\"\n :data-gr-transfer-list=\"side\"\n :data-overflow=\"listOverflow[side]\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n tabindex=\"-1\"\n :data-gr-virtual=\"virtual ? '' : undefined\"\n :class=\"transferListBase\"\n :style=\"listStyle(side)\"\n :aria-label=\"hasHeaderSlot ? titles[side] : undefined\"\n :aria-labelledby=\"hasHeaderSlot\n ? (side === 'target' ? fieldLabelId : undefined)\n : (side === 'target' && fieldLabelId\n ? `${fieldLabelId} ${targetTitleId}`\n : (side === 'source' ? sourceTitleId : targetTitleId))\"\n :aria-describedby=\"side === 'target' ? describedBy : undefined\"\n :aria-invalid=\"side === 'target' && isInvalid ? 'true' : undefined\"\n :aria-required=\"side === 'target' && isRequired ? 'true' : undefined\"\n :aria-readonly=\"side === 'target' && isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @keydown=\"(event: KeyboardEvent) => onListKeydown(side, event)\"\n @scroll.passive=\"scheduleOverflow\"\n >\n <div\n v-for=\"(item, index) in renderedOf(side)\"\n :key=\"keyOf(item)\"\n :ref=\"(el) => {\n registerRow(side, keyOf(item), el as Element | null)\n if (virtual) virtualizerOf(side).measure(absoluteIndex(side, index), el as Element | null)\n }\"\n data-gr-transfer-option\n role=\"option\"\n :aria-selected=\"selections[side].keys.has(keyOf(item)) ? 'true' : 'false'\"\n :aria-disabled=\"disabledOf(item) ? 'true' : undefined\"\n :aria-setsize=\"visible[side].length\"\n :aria-posinset=\"absoluteIndex(side, index) + 1\"\n :tabindex=\"rovingOf(side).tabindexFor(keyOf(item))\"\n :class=\"grTransferOptionClass({\n size: resolvedSize,\n selected: selections[side].keys.has(keyOf(item)),\n disabled: disabledOf(item),\n draggable: resolvedDraggable && !isLocked,\n dragging: isDraggingKey(side, keyOf(item)),\n arrived: arrived.has(keyOf(item)),\n indicator: indicatorFor(side, keyOf(item)),\n })\"\n @pointerdown=\"(event: PointerEvent) => onRowPointerDown(side, keyOf(item), event)\"\n @click=\"(event: MouseEvent) => onOptionClick(side, keyOf(item), event)\"\n @focus=\"rovingOf(side).setActive(keyOf(item))\"\n @dblclick=\"!disabledOf(item) && transfer([keyOf(item)], side === 'source' ? 'toTarget' : 'toSource')\"\n >\n <span\n aria-hidden=\"true\"\n :class=\"grTransferMarkClass(resolvedSize, selections[side].keys.has(keyOf(item)))\"\n >\n <IconCheck\n v-if=\"selections[side].keys.has(keyOf(item))\"\n :class=\"transferMarkIconClass\"\n />\n </span>\n <slot\n name=\"item\"\n :item=\"item\"\n :side=\"side\"\n :index=\"absoluteIndex(side, index)\"\n :selected=\"selections[side].keys.has(keyOf(item))\"\n :disabled=\"disabledOf(item)\"\n >\n <span :class=\"transferLabelClass\">{{ labelOf(item) }}</span>\n </slot>\n </div>\n </div>\n\n <!--\n Текст пустоты и текст загрузки — соседи списка, а не его потомки: потомки\n роли презентационны.\n\n Состояния взаимоисключающи: «ничего не найдено» под незакончившимся\n запросом — утверждение, которого никто не проверял.\n -->\n <slot v-if=\"loading && visible[side].length === 0\" name=\"loading\" :side=\"side\">\n <p data-gr-transfer-loading :class=\"grTransferEmptyClass(resolvedSize)\">\n {{ resolvedLoadingText }}\n </p>\n </slot>\n\n <slot v-else-if=\"visible[side].length === 0\" name=\"empty\" :side=\"side\" :filtered=\"isFiltered(side)\">\n <p :class=\"grTransferEmptyClass(resolvedSize)\">\n {{ emptyText(side) }}\n </p>\n </slot>\n </div>\n\n <Teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <div\n v-if=\"ghost\"\n data-gr-transfer-ghost\n aria-hidden=\"true\"\n :class=\"transferGhostClass\"\n :style=\"ghostStyle\"\n >\n <span :class=\"transferGhostLabelClass\">{{ ghost.label }}</span>\n <span v-if=\"ghost.rest > 0\" :class=\"transferGhostCountClass\">+{{ ghost.rest }}</span>\n </div>\n </Teleport>\n\n <div :class=\"grTransferActionsClass(resolvedSize)\" style=\"order: 1\">\n <slot\n name=\"actions\"\n :to-target=\"() => transferSelected('toTarget')\"\n :to-source=\"() => transferSelected('toSource')\"\n :can-to-target=\"canToTarget\"\n :can-to-source=\"canToSource\"\n >\n <GrButtonGroup orientation=\"vertical\" attached :size=\"resolvedSize\">\n <GrButton\n data-gr-transfer-to-target\n variant=\"secondary\"\n :aria-disabled=\"canToTarget ? undefined : 'true'\"\n :class=\"canToTarget ? '' : transferActionInertClass\"\n :aria-label=\"t('gr.transfer.toTarget', 'Move to selected')\"\n @click=\"canToTarget && transferSelected('toTarget')\"\n >\n <IconChevronRight :class=\"transferActionIconClass\" aria-hidden=\"true\" />\n </GrButton>\n <GrButton\n data-gr-transfer-to-source\n variant=\"secondary\"\n :aria-disabled=\"canToSource ? undefined : 'true'\"\n :class=\"canToSource ? '' : transferActionInertClass\"\n :aria-label=\"t('gr.transfer.toSource', 'Move back to available')\"\n @click=\"canToSource && transferSelected('toSource')\"\n >\n <IconChevronLeft :class=\"transferActionIconClass\" aria-hidden=\"true\" />\n </GrButton>\n </GrButtonGroup>\n </slot>\n </div>\n </div>\n</template>\n\n<style>\n/*\n * Распорка виртуализованной панели. Правило повторяется в каждом компоненте с\n * виртуализацией намеренно: единственный глобальный стиль пакета\n * (`styles/base.css`) потребитель вправе не подключать, и уехавшее туда правило\n * молча ломало бы прокрутку. Копии сверяет `src/__tests__/virtualSpacer.test.ts`.\n */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n\n/*\n * Колонка кнопок стоит между панелями, а в DOM идёт после них: так `Tab`\n * проходит левую панель целиком до кнопок, а `order` ставит её на место.\n * Порядок DOM менять нельзя — в RTL он перевернётся сам вместе с флексом.\n */\n[data-gr-transfer] > [data-gr-transfer-panel='source'] { order: 0; }\n[data-gr-transfer] > [data-gr-transfer-panel='target'] { order: 2; }\n\n[data-gr-transfer-list][data-overflow='start'] {\n --gr-transfer-list-mask: linear-gradient(to bottom, transparent 0, #000 var(--gr-transfer-fade, 1.25rem));\n}\n\n[data-gr-transfer-list][data-overflow='end'] {\n --gr-transfer-list-mask: linear-gradient(to bottom, #000 calc(100% - var(--gr-transfer-fade, 1.25rem)), transparent 100%);\n}\n\n[data-gr-transfer-list][data-overflow='both'] {\n --gr-transfer-list-mask: linear-gradient(\n to bottom,\n transparent 0,\n #000 var(--gr-transfer-fade, 1.25rem),\n #000 calc(100% - var(--gr-transfer-fade, 1.25rem)),\n transparent 100%\n );\n}\n\n[data-gr-transfer-list]:is([data-overflow='start'], [data-overflow='end'], [data-overflow='both']) {\n -webkit-mask-image: var(--gr-transfer-list-mask);\n mask-image: var(--gr-transfer-list-mask);\n}\n\n/*\n * Гашение кнопки, которой некуда переносить. Селектор по атрибуту внутри корня\n * сильнее одноклассовой утилиты `GrButton`, поэтому фон не зависит от порядка\n * правил в собранном CSS. Фоном, а не `opacity`: прозрачность разбавляет\n * выверенные на AA токены текста.\n */\n/*\n * Подсветка прибытия. Без `animation-fill-mode`, исходный кадр — обычная строка:\n * глобальный кламп `prefers-reduced-motion` доигрывает её за 0.01ms и оставляет\n * ровно тот вид, что и так был бы.\n */\n@keyframes gr-transfer-arrive {\n from { background: var(--gr-transfer-arrived-bg, color-mix(in srgb, var(--gr-primary) 32%, transparent)); }\n to { background: transparent; }\n}\n\n[data-gr-transfer] .gr-transfer-arrived {\n animation: gr-transfer-arrive var(--gr-duration-slow) var(--gr-ease-out);\n}\n\n/* Пока строка «в руке», курсор обязан это показывать везде, а не только над ней. */\n[data-gr-transfer][data-dragging='true'],\n[data-gr-transfer][data-dragging='true'] * {\n cursor: grabbing !important;\n user-select: none;\n}\n\n/*\n * Пустое место на время жеста: пунктир и приглушённый текст читаются как «строка\n * сейчас в руке», тогда как прежняя бледная подложка оставляла её почти обычной.\n */\n/*\n * Селектор нарочно длиннее одноклассового: строка при нажатии получает фокус, а\n * `focus:outline-none` сбрасывает `outline` утилитой той же специфичности —\n * пунктир проигрывал бы ей по порядку правил.\n */\n[data-gr-transfer] [data-gr-transfer-option].gr-transfer-vacated {\n background: var(--gr-transfer-dragging-bg, var(--gr-muted));\n color: var(--gr-muted-fg);\n outline: 1px dashed var(--gr-brd);\n outline-offset: -3px;\n}\n\n[data-gr-transfer] button[aria-disabled='true'] {\n background: var(--gr-muted);\n color: var(--gr-disabled-fg);\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as grTransferSafelist, t as grTransferConfig } from "../../chunks/config-DmED6aJV.js";
|
|
2
|
-
import { t as GrTransfer_default } from "./chunks/GrTransfer-
|
|
2
|
+
import { t as GrTransfer_default } from "./chunks/GrTransfer-CV7BL5UK.js";
|
|
3
3
|
export { GrTransfer_default as GrTransfer, GrTransfer_default as default, grTransferConfig, grTransferSafelist };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[data-gr-transfer]>[data-gr-transfer-panel=source]{order:0}[data-gr-transfer]>[data-gr-transfer-panel=target]{order:2}[data-gr-transfer-list][data-overflow=start]{--gr-transfer-list-mask:linear-gradient(to bottom, transparent 0, #000 var(--gr-transfer-fade,1.25rem))}[data-gr-transfer-list][data-overflow=end]{--gr-transfer-list-mask:linear-gradient(to bottom, #000 calc(100% - var(--gr-transfer-fade,1.25rem)), transparent 100%)}[data-gr-transfer-list][data-overflow=both]{--gr-transfer-list-mask:linear-gradient(to bottom, transparent 0, #000 var(--gr-transfer-fade,1.25rem), #000 calc(100% - var(--gr-transfer-fade,1.25rem)), transparent 100%)}[data-gr-transfer-list]:is([data-overflow=start],[data-overflow=end],[data-overflow=both]){-webkit-mask-image:var(--gr-transfer-list-mask);mask-image:var(--gr-transfer-list-mask)}@keyframes gr-transfer-arrive{0%{background:var(--gr-transfer-arrived-bg,color-mix(in srgb, var(--gr-primary) 32%, transparent))}to{background:0 0}}[data-gr-transfer] .gr-transfer-arrived{animation:gr-transfer-arrive var(--gr-duration-slow) var(--gr-ease-out)}[data-gr-transfer][data-dragging=true],[data-gr-transfer][data-dragging=true] *{user-select:none;cursor:grabbing!important}[data-gr-transfer] [data-gr-transfer-option].gr-transfer-vacated{background:var(--gr-transfer-dragging-bg,var(--gr-muted));color:var(--gr-muted-fg);outline:1px dashed var(--gr-brd);outline-offset:-3px}[data-gr-transfer] button[aria-disabled=true]{background:var(--gr-muted);color:var(--gr-disabled-fg)}
|
|
1
|
+
[data-gr-virtual]:before,[data-gr-virtual]:after{content:"";flex:none;display:block}[data-gr-virtual]:before{height:var(--gr-virtual-before,0px)}[data-gr-virtual]:after{height:var(--gr-virtual-after,0px)}[data-gr-transfer]>[data-gr-transfer-panel=source]{order:0}[data-gr-transfer]>[data-gr-transfer-panel=target]{order:2}[data-gr-transfer-list][data-overflow=start]{--gr-transfer-list-mask:linear-gradient(to bottom, transparent 0, #000 var(--gr-transfer-fade,1.25rem))}[data-gr-transfer-list][data-overflow=end]{--gr-transfer-list-mask:linear-gradient(to bottom, #000 calc(100% - var(--gr-transfer-fade,1.25rem)), transparent 100%)}[data-gr-transfer-list][data-overflow=both]{--gr-transfer-list-mask:linear-gradient(to bottom, transparent 0, #000 var(--gr-transfer-fade,1.25rem), #000 calc(100% - var(--gr-transfer-fade,1.25rem)), transparent 100%)}[data-gr-transfer-list]:is([data-overflow=start],[data-overflow=end],[data-overflow=both]){-webkit-mask-image:var(--gr-transfer-list-mask);mask-image:var(--gr-transfer-list-mask)}@keyframes gr-transfer-arrive{0%{background:var(--gr-transfer-arrived-bg,color-mix(in srgb, var(--gr-primary) 32%, transparent))}to{background:0 0}}[data-gr-transfer] .gr-transfer-arrived{animation:gr-transfer-arrive var(--gr-duration-slow) var(--gr-ease-out)}[data-gr-transfer][data-dragging=true],[data-gr-transfer][data-dragging=true] *{user-select:none;cursor:grabbing!important}[data-gr-transfer] [data-gr-transfer-option].gr-transfer-vacated{background:var(--gr-transfer-dragging-bg,var(--gr-muted));color:var(--gr-muted-fg);outline:1px dashed var(--gr-brd);outline-offset:-3px}[data-gr-transfer] button[aria-disabled=true]{background:var(--gr-muted);color:var(--gr-disabled-fg)}
|
|
@@ -209,6 +209,7 @@ var _hoisted_7 = { class: "gr-tree__label" };
|
|
|
209
209
|
var DEFAULT_BRANCH_LINE_COLOR = "var(--gr-tree-branch-line-default-color, var(--gr-brd))";
|
|
210
210
|
/** Стрелки, которые вместе с `Shift` двигают узел, а не фокус. */
|
|
211
211
|
var TREE_ROW_GAP = 2;
|
|
212
|
+
var DRAG_EXPAND_DELAY_MS = 700;
|
|
212
213
|
//#endregion
|
|
213
214
|
//#region src/components/GrTree/GrTree.vue
|
|
214
215
|
var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
@@ -760,6 +761,42 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
760
761
|
interactionContext.emitNodeDrop(movedNode, dropNode, type);
|
|
761
762
|
return true;
|
|
762
763
|
}
|
|
764
|
+
/**
|
|
765
|
+
* Свёрнутая ветка под перетаскиваемым узлом раскрывается сама.
|
|
766
|
+
*
|
|
767
|
+
* Без этого положить узел внутрь свёрнутой ветки на нужное место было нельзя
|
|
768
|
+
* вовсе: перенос приходилось бросать, раскрывать ветку руками и начинать
|
|
769
|
+
* заново — а бросить его нечем, кроме `Escape`.
|
|
770
|
+
*
|
|
771
|
+
* Только на «внутрь»: целясь в соседа сверху или снизу, пользователь не просил
|
|
772
|
+
* менять раскладку, и раскрытие увело бы строки из-под курсора вместе с точкой,
|
|
773
|
+
* в которую он метил.
|
|
774
|
+
*/
|
|
775
|
+
let dragExpandTimer = null;
|
|
776
|
+
let dragExpandKey = null;
|
|
777
|
+
function cancelDragExpand() {
|
|
778
|
+
if (dragExpandTimer !== null) clearTimeout(dragExpandTimer);
|
|
779
|
+
dragExpandTimer = null;
|
|
780
|
+
dragExpandKey = null;
|
|
781
|
+
}
|
|
782
|
+
function scheduleDragExpand(target) {
|
|
783
|
+
if (!target || target.type !== "inner" || !target.allowed) {
|
|
784
|
+
cancelDragExpand();
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
if (dragExpandKey === target.key) return;
|
|
788
|
+
cancelDragExpand();
|
|
789
|
+
const node = treeStore.getNode(target.key);
|
|
790
|
+
if (!node || treeStore.isLeafNode(node) || treeStore.isExpandedKey(node.key)) return;
|
|
791
|
+
dragExpandKey = target.key;
|
|
792
|
+
dragExpandTimer = setTimeout(() => {
|
|
793
|
+
dragExpandTimer = null;
|
|
794
|
+
dragExpandKey = null;
|
|
795
|
+
const fresh = treeStore.getNode(target.key);
|
|
796
|
+
if (fresh && !treeStore.isExpandedKey(fresh.key)) toggleExpand(fresh);
|
|
797
|
+
}, DRAG_EXPAND_DELAY_MS);
|
|
798
|
+
}
|
|
799
|
+
onBeforeUnmount(cancelDragExpand);
|
|
763
800
|
const dragSort = useDragSort({
|
|
764
801
|
items: () => visibleRows.value.map((row) => row.node.key),
|
|
765
802
|
elementFor: (key) => interactionContext.nodeEls.get(key) ?? null,
|
|
@@ -790,6 +827,7 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
790
827
|
onUpdate: (sourceKey, target) => {
|
|
791
828
|
interactionContext.draggingNode.value = sourceKey === null ? null : treeStore.getNode(sourceKey) ?? null;
|
|
792
829
|
interactionContext.dropTarget.value = target;
|
|
830
|
+
scheduleDragExpand(target);
|
|
793
831
|
}
|
|
794
832
|
});
|
|
795
833
|
function onHandlePointerDown(event, node) {
|
|
@@ -1008,6 +1046,6 @@ var GrTree_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE_
|
|
|
1008
1046
|
}), 128))], 46, _hoisted_1);
|
|
1009
1047
|
};
|
|
1010
1048
|
}
|
|
1011
|
-
}), [["__scopeId", "data-v-
|
|
1049
|
+
}), [["__scopeId", "data-v-15f3d7da"]]);
|
|
1012
1050
|
//#endregion
|
|
1013
1051
|
export { grTreeViewVars as n, GrTree_default as t };
|