@feugene/granularity 0.42.0 → 0.43.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/config-BXRmsn3t.js +172 -0
- package/dist/chunks/config-BXRmsn3t.js.map +1 -0
- package/dist/chunks/config-Dg0bSoGw.js +81 -0
- package/dist/chunks/config-Dg0bSoGw.js.map +1 -0
- package/dist/chunks/config-DmED6aJV.js +237 -0
- package/dist/chunks/config-DmED6aJV.js.map +1 -0
- package/dist/chunks/{config-DWL81-aM.js → config-hnoZvcIM.js} +2 -20
- package/dist/chunks/config-hnoZvcIM.js.map +1 -0
- package/dist/chunks/dragSortGeometry-CY-llfrQ.js +87 -0
- package/dist/chunks/dragSortGeometry-CY-llfrQ.js.map +1 -0
- package/dist/chunks/{en-B9E3jO6m.js → en-C_QkUTRL.js} +32 -1
- package/dist/chunks/en-C_QkUTRL.js.map +1 -0
- package/dist/chunks/{es-DCkqHTlU.js → es-B4t_3Wnh.js} +3 -3
- package/dist/chunks/{es-DCkqHTlU.js.map → es-B4t_3Wnh.js.map} +1 -1
- package/dist/chunks/{es-QpzdIEut.js → es-DemSEhZE.js} +32 -1
- package/dist/chunks/es-DemSEhZE.js.map +1 -0
- package/dist/chunks/{generated-B95IBXs6.js → generated-VcxJTo_q.js} +210 -0
- package/dist/chunks/generated-VcxJTo_q.js.map +1 -0
- package/dist/chunks/{granular-provider-BG_2XqkS.js → granular-provider-BohXQcNt.js} +7 -1
- package/dist/chunks/granular-provider-BohXQcNt.js.map +1 -0
- package/dist/chunks/{ru-D_1Ya489.js → ru-CLUErjhY.js} +32 -1
- package/dist/chunks/ru-CLUErjhY.js.map +1 -0
- package/dist/chunks/scrollOverflow-B_kEdcol.js +31 -0
- package/dist/chunks/scrollOverflow-B_kEdcol.js.map +1 -0
- package/dist/chunks/tones-CRJAaYyg.js +21 -0
- package/dist/chunks/tones-CRJAaYyg.js.map +1 -0
- package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js +272 -0
- package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js.map +1 -0
- package/dist/components/GrAffix/index.js +3 -0
- package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js +761 -0
- package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +1 -0
- package/dist/components/GrCarousel/index.js +3 -0
- package/dist/components/GrCarousel/styles.css +1 -0
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js → GrColorPicker-9mTR-YZ_.js} +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js.map → GrColorPicker-9mTR-YZ_.js.map} +1 -1
- package/dist/components/GrColorPicker/index.js +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js → GrDataTable-xNSmO_I-.js} +4 -3
- package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js.map → GrDataTable-xNSmO_I-.js.map} +1 -1
- package/dist/components/GrDataTable/index.js +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js.map → GrImageViewer-DK-iVHHC.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js.map → GrInputTag-Ci8AO1ze.js.map} +1 -1
- package/dist/components/GrInputTag/index.js +1 -1
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js → GrJsonViewer-CwCBMh4h.js} +2 -2
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js.map → GrJsonViewer-CwCBMh4h.js.map} +1 -1
- package/dist/components/GrJsonViewer/index.js +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js.map → GrNumberInput-CL5QhOmx.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +1 -1
- package/dist/components/GrProgressBar/index.js +1 -1
- package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js.map → GrSlider-CO8N9SF6.js.map} +1 -1
- package/dist/components/GrSlider/index.js +1 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js → GrSortableList-NKriuGm_.js} +2 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js.map → GrSortableList-NKriuGm_.js.map} +1 -1
- package/dist/components/GrSortableList/index.js +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-BArefUFv.js → GrTabs-s9RzC1WX.js} +2 -31
- package/dist/components/GrTabs/chunks/GrTabs-s9RzC1WX.js.map +1 -0
- package/dist/components/GrTabs/index.js +1 -1
- package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js +1368 -0
- package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js.map +1 -0
- package/dist/components/GrTransfer/index.js +3 -0
- package/dist/components/GrTransfer/styles.css +1 -0
- package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js → GrTree-CkHzgYg1.js} +3 -3
- package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js.map → GrTree-CkHzgYg1.js.map} +1 -1
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js → GrTreeSelect-DUsv3_mF.js} +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js.map → GrTreeSelect-DUsv3_mF.js.map} +1 -1
- package/dist/components/GrTreeSelect/index.js +1 -1
- package/dist/composables/useDragSort.js +179 -1
- package/dist/composables/useDragSort.js.map +1 -0
- 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 +23 -19
- package/dist/theme.js +1 -1
- package/dist/tokens.js +1 -1
- package/dist/types/components/GrAffix/GrAffix.vue.d.ts +91 -0
- package/dist/types/components/GrAffix/affixState.d.ts +81 -0
- package/dist/types/components/GrAffix/config.d.ts +1 -0
- package/dist/types/components/GrAffix/grAffixStyles.d.ts +46 -0
- package/dist/types/components/GrAffix/index.d.ts +9 -0
- package/dist/types/components/GrAffix/safelist.d.ts +1 -0
- package/dist/types/components/GrAlert/GrAlert.vue.d.ts +1 -1
- package/dist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +2 -2
- package/dist/types/components/GrButton/GrButton.vue.d.ts +2 -2
- package/dist/types/components/GrCard/GrCard.vue.d.ts +1 -1
- package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +151 -0
- package/dist/types/components/GrCarousel/GrCarouselSlide.vue.d.ts +53 -0
- package/dist/types/components/GrCarousel/carouselNavigation.d.ts +57 -0
- package/dist/types/components/GrCarousel/composables/useCarouselAutoplay.d.ts +33 -0
- package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +20 -0
- package/dist/types/components/GrCarousel/config.d.ts +7 -0
- package/dist/types/components/GrCarousel/defaults.d.ts +13 -0
- package/dist/types/components/GrCarousel/grCarouselContext.d.ts +46 -0
- package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +80 -0
- package/dist/types/components/GrCarousel/index.d.ts +12 -0
- package/dist/types/components/GrCarousel/safelist.d.ts +1 -0
- package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +3 -3
- package/dist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts +2 -2
- package/dist/types/components/GrChip/GrChip.vue.d.ts +2 -2
- package/dist/types/components/GrChipGroup/GrChipGroup.vue.d.ts +2 -2
- package/dist/types/components/GrCollapse/GrCollapse.vue.d.ts +1 -1
- package/dist/types/components/GrCollapse/GrCollapseItem.vue.d.ts +1 -1
- package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +3 -3
- package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +1 -1
- package/dist/types/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +1 -1
- package/dist/types/components/GrContextMenu/GrContextMenu.vue.d.ts +2 -2
- package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
- package/dist/types/components/GrDivider/GrDivider.vue.d.ts +2 -2
- package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
- package/dist/types/components/GrDropdown/GrDropdown.vue.d.ts +3 -3
- package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +3 -3
- package/dist/types/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +1 -1
- package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +1 -1
- package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
- package/dist/types/components/GrFormField/GrFormField.vue.d.ts +3 -3
- package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
- package/dist/types/components/GrFormSection/GrFormSection.vue.d.ts +1 -1
- package/dist/types/components/GrIcon/GrIcon.vue.d.ts +1 -1
- package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +3 -3
- package/dist/types/components/GrInput/GrInput.vue.d.ts +4 -4
- package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +3 -3
- package/dist/types/components/GrKbd/GrKbd.vue.d.ts +1 -1
- package/dist/types/components/GrLink/GrLink.vue.d.ts +1 -1
- package/dist/types/components/GrList/GrListItem.vue.d.ts +2 -2
- package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +2 -2
- package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +3 -3
- package/dist/types/components/GrPagination/GrPagination.vue.d.ts +1 -1
- package/dist/types/components/GrPopover/GrPopover.vue.d.ts +3 -3
- package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +3 -3
- package/dist/types/components/GrRadio/GrRadio.vue.d.ts +2 -2
- package/dist/types/components/GrRadioGroup/GrRadioGroup.vue.d.ts +2 -2
- package/dist/types/components/GrRating/GrRating.vue.d.ts +2 -2
- package/dist/types/components/GrSegmented/GrSegmented.vue.d.ts +2 -2
- package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +1 -1
- package/dist/types/components/GrSkeleton/GrSkeleton.vue.d.ts +1 -1
- package/dist/types/components/GrSlider/GrSlider.vue.d.ts +3 -3
- package/dist/types/components/GrSplitter/GrSplitter.vue.d.ts +1 -1
- package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +2 -2
- package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +3 -3
- package/dist/types/components/GrTable/GrTable.vue.d.ts +1 -1
- package/dist/types/components/GrTabs/GrTabs.vue.d.ts +1 -1
- package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
- package/dist/types/components/GrTimeline/GrTimelineItem.vue.d.ts +2 -2
- package/dist/types/components/GrToaster/GrToaster.vue.d.ts +1 -1
- package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +3 -3
- package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +103 -0
- package/dist/types/components/GrTransfer/config.d.ts +1 -0
- package/dist/types/components/GrTransfer/defaults.d.ts +15 -0
- package/dist/types/components/GrTransfer/grTransferStyles.d.ts +127 -0
- package/dist/types/components/GrTransfer/index.d.ts +11 -0
- package/dist/types/components/GrTransfer/safelist.d.ts +1 -0
- package/dist/types/components/GrTransfer/transferGeometry.d.ts +44 -0
- package/dist/types/components/GrTransfer/transferModel.d.ts +68 -0
- package/dist/types/components/GrTransfer/transferSelection.d.ts +36 -0
- package/dist/types/components/GrTransfer/useTransferDrag.d.ts +48 -0
- package/dist/types/granular-provider/shared.d.ts +3 -0
- package/dist/types/i18n/messages/en.d.ts +58 -0
- package/dist/types/i18n/messages/es.d.ts +58 -0
- package/dist/types/i18n/messages/ru.d.ts +58 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/web-types.json +718 -288
- package/package.json +17 -1
- package/dist/chunks/config-DWL81-aM.js.map +0 -1
- package/dist/chunks/en-B9E3jO6m.js.map +0 -1
- package/dist/chunks/es-QpzdIEut.js.map +0 -1
- package/dist/chunks/generated-B95IBXs6.js.map +0 -1
- package/dist/chunks/granular-provider-BG_2XqkS.js.map +0 -1
- package/dist/chunks/ru-D_1Ya489.js.map +0 -1
- package/dist/chunks/useDragSort-0l47h4yb.js +0 -265
- package/dist/chunks/useDragSort-0l47h4yb.js.map +0 -1
- package/dist/components/GrTabs/chunks/GrTabs-BArefUFv.js.map +0 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js → GrImageViewer-DK-iVHHC.js} +3 -3
- package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js → GrInputTag-Ci8AO1ze.js} +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js → GrNumberInput-CL5QhOmx.js} +1 -1
- package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js → GrSlider-CO8N9SF6.js} +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrTransfer-8FA78ny6.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 { 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 sortable?: boolean\n /** Перетаскивание строк указателем. Усиление поверх кнопок, а не контракт. */\n draggable?: boolean\n /** Высота панелей: обе одинаковы и прокручиваются внутри себя. */\n maxHeight?: number | string\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 sortable: true,\n draggable: undefined,\n maxHeight: undefined,\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\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 if (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\nfunction registerRow(side: GrTransferSide, key: GrTransferKey, el: Element | null): void {\n const map = rowsOf(side)\n if (el instanceof HTMLElement)\n map.set(key, el)\n else map.delete(key)\n}\n\nfunction makeRoving(side: GrTransferSide) {\n return useRovingFocus<GrTransferKey>({\n items: () => visibleKeys.value[side],\n elementFor: key => rowsOf(side).get(key) ?? null,\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\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\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 :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 <p :class=\"transferStatusClass\" role=\"status\" aria-live=\"polite\">\n {{ 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 :class=\"transferListBase\"\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 visible[side]\"\n :key=\"keyOf(item)\"\n :ref=\"el => registerRow(side, keyOf(item), el as Element | null)\"\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 :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=\"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 <slot v-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 * Колонка кнопок стоит между панелями, а в 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 { 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 sortable?: boolean\n /** Перетаскивание строк указателем. Усиление поверх кнопок, а не контракт. */\n draggable?: boolean\n /** Высота панелей: обе одинаковы и прокручиваются внутри себя. */\n maxHeight?: number | string\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 sortable: true,\n draggable: undefined,\n maxHeight: undefined,\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\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 if (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\nfunction registerRow(side: GrTransferSide, key: GrTransferKey, el: Element | null): void {\n const map = rowsOf(side)\n if (el instanceof HTMLElement)\n map.set(key, el)\n else map.delete(key)\n}\n\nfunction makeRoving(side: GrTransferSide) {\n return useRovingFocus<GrTransferKey>({\n items: () => visibleKeys.value[side],\n elementFor: key => rowsOf(side).get(key) ?? null,\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\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\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 :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 <p :class=\"transferStatusClass\" role=\"status\" aria-live=\"polite\">\n {{ 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 :class=\"transferListBase\"\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 visible[side]\"\n :key=\"keyOf(item)\"\n :ref=\"el => registerRow(side, keyOf(item), el as Element | null)\"\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 :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=\"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 <slot v-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 * Колонка кнопок стоит между панелями, а в 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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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { n as grTransferSafelist, t as grTransferConfig } from "../../chunks/config-DmED6aJV.js";
|
|
2
|
+
import { t as GrTransfer_default } from "./chunks/GrTransfer-8FA78ny6.js";
|
|
3
|
+
export { GrTransfer_default as GrTransfer, GrTransfer_default as default, grTransferConfig, grTransferSafelist };
|
|
@@ -0,0 +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)}
|
|
@@ -6,12 +6,12 @@ import { useRovingFocus } from "../../../composables/useRovingFocus.js";
|
|
|
6
6
|
import { t as check_default } from "../../../chunks/check-BZI24Qs4.js";
|
|
7
7
|
import { t as _plugin_vue_export_helper_default } from "../../../chunks/_plugin-vue_export-helper-BOaGB7Aw.js";
|
|
8
8
|
import { n as iconTag, t as iconClass } from "../../../chunks/icon-Dag2tIMs.js";
|
|
9
|
+
import { useAnnouncer } from "../../../composables/useAnnouncer.js";
|
|
10
|
+
import { t as chevron_right_default } from "../../../chunks/chevron-right-C6Z01h0X.js";
|
|
9
11
|
import { t as minus_default } from "../../../chunks/minus-oxdbHF33.js";
|
|
10
12
|
import { t as useTypeahead } from "../../../chunks/useTypeahead-mxPtPBf2.js";
|
|
11
|
-
import {
|
|
12
|
-
import { t as useDragSort } from "../../../chunks/useDragSort-0l47h4yb.js";
|
|
13
|
+
import { useDragSort } from "../../../composables/useDragSort.js";
|
|
13
14
|
import { t as grip_vertical_default } from "../../../chunks/grip-vertical-lRha2S7q.js";
|
|
14
|
-
import { t as chevron_right_default } from "../../../chunks/chevron-right-C6Z01h0X.js";
|
|
15
15
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, toValue, unref, watch, withModifiers } from "vue";
|
|
16
16
|
import '../styles.css';//#region src/components/GrTree/grTreeDataAdapter.ts
|
|
17
17
|
var DEFAULT_CHILDREN_KEY = "children";
|