@feugene/granularity 0.42.0 → 0.44.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.
Files changed (193) hide show
  1. package/README.md +2 -2
  2. package/dist/chunks/config-BXRmsn3t.js +172 -0
  3. package/dist/chunks/config-BXRmsn3t.js.map +1 -0
  4. package/dist/chunks/config-BkQ2jvXv.js +49 -0
  5. package/dist/chunks/config-BkQ2jvXv.js.map +1 -0
  6. package/dist/chunks/config-Dg0bSoGw.js +81 -0
  7. package/dist/chunks/config-Dg0bSoGw.js.map +1 -0
  8. package/dist/chunks/config-DmED6aJV.js +237 -0
  9. package/dist/chunks/config-DmED6aJV.js.map +1 -0
  10. package/dist/chunks/{config-DWL81-aM.js → config-hnoZvcIM.js} +2 -20
  11. package/dist/chunks/config-hnoZvcIM.js.map +1 -0
  12. package/dist/chunks/dragSortGeometry-CY-llfrQ.js +87 -0
  13. package/dist/chunks/dragSortGeometry-CY-llfrQ.js.map +1 -0
  14. package/dist/chunks/{en-B9E3jO6m.js → en-DiHzFact.js} +34 -1
  15. package/dist/chunks/en-DiHzFact.js.map +1 -0
  16. package/dist/chunks/{es-QpzdIEut.js → es-1ZL6NtkB.js} +34 -1
  17. package/dist/chunks/es-1ZL6NtkB.js.map +1 -0
  18. package/dist/chunks/{es-DCkqHTlU.js → es-CeKkMxZ_.js} +3 -3
  19. package/dist/chunks/{es-DCkqHTlU.js.map → es-CeKkMxZ_.js.map} +1 -1
  20. package/dist/chunks/{generated-B95IBXs6.js → generated-Hxu_sWPs.js} +238 -0
  21. package/dist/chunks/generated-Hxu_sWPs.js.map +1 -0
  22. package/dist/chunks/{granular-provider-BG_2XqkS.js → granular-provider-CCNbQa5U.js} +9 -1
  23. package/dist/chunks/granular-provider-CCNbQa5U.js.map +1 -0
  24. package/dist/chunks/{ru-D_1Ya489.js → ru-Dr2RYn0P.js} +34 -1
  25. package/dist/chunks/ru-Dr2RYn0P.js.map +1 -0
  26. package/dist/chunks/scrollOverflow-B_kEdcol.js +31 -0
  27. package/dist/chunks/scrollOverflow-B_kEdcol.js.map +1 -0
  28. package/dist/chunks/tones-CRJAaYyg.js +21 -0
  29. package/dist/chunks/tones-CRJAaYyg.js.map +1 -0
  30. package/dist/chunks/useScrollSpy-CIJpw0RI.js +360 -0
  31. package/dist/chunks/useScrollSpy-CIJpw0RI.js.map +1 -0
  32. package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js +272 -0
  33. package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js.map +1 -0
  34. package/dist/components/GrAffix/index.js +3 -0
  35. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js +761 -0
  36. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +1 -0
  37. package/dist/components/GrCarousel/index.js +3 -0
  38. package/dist/components/GrCarousel/styles.css +1 -0
  39. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js → GrColorPicker-9mTR-YZ_.js} +1 -1
  40. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js.map → GrColorPicker-9mTR-YZ_.js.map} +1 -1
  41. package/dist/components/GrColorPicker/index.js +1 -1
  42. package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js → GrDataTable-xNSmO_I-.js} +4 -3
  43. package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js.map → GrDataTable-xNSmO_I-.js.map} +1 -1
  44. package/dist/components/GrDataTable/index.js +1 -1
  45. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js.map → GrImageViewer-DK-iVHHC.js.map} +1 -1
  46. package/dist/components/GrImageViewer/index.js +1 -1
  47. package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js.map → GrInputTag-Ci8AO1ze.js.map} +1 -1
  48. package/dist/components/GrInputTag/index.js +1 -1
  49. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js → GrJsonViewer-CwCBMh4h.js} +2 -2
  50. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js.map → GrJsonViewer-CwCBMh4h.js.map} +1 -1
  51. package/dist/components/GrJsonViewer/index.js +1 -1
  52. package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js.map → GrNumberInput-CL5QhOmx.js.map} +1 -1
  53. package/dist/components/GrNumberInput/index.js +1 -1
  54. package/dist/components/GrProgressBar/index.js +1 -1
  55. package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js +207 -0
  56. package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js.map +1 -0
  57. package/dist/components/GrScrollSpy/index.js +3 -0
  58. package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js.map → GrSlider-CO8N9SF6.js.map} +1 -1
  59. package/dist/components/GrSlider/index.js +1 -1
  60. package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js → GrSortableList-NKriuGm_.js} +2 -1
  61. package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js.map → GrSortableList-NKriuGm_.js.map} +1 -1
  62. package/dist/components/GrSortableList/index.js +1 -1
  63. package/dist/components/GrTabs/chunks/{GrTabs-BArefUFv.js → GrTabs-s9RzC1WX.js} +2 -31
  64. package/dist/components/GrTabs/chunks/GrTabs-s9RzC1WX.js.map +1 -0
  65. package/dist/components/GrTabs/index.js +1 -1
  66. package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js +1368 -0
  67. package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js.map +1 -0
  68. package/dist/components/GrTransfer/index.js +3 -0
  69. package/dist/components/GrTransfer/styles.css +1 -0
  70. package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js → GrTree-CkHzgYg1.js} +3 -3
  71. package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js.map → GrTree-CkHzgYg1.js.map} +1 -1
  72. package/dist/components/GrTree/index.js +1 -1
  73. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js → GrTreeSelect-DUsv3_mF.js} +1 -1
  74. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js.map → GrTreeSelect-DUsv3_mF.js.map} +1 -1
  75. package/dist/components/GrTreeSelect/index.js +1 -1
  76. package/dist/composables/useDragSort.js +179 -1
  77. package/dist/composables/useDragSort.js.map +1 -0
  78. package/dist/composables/useScrollSpy.js +2 -0
  79. package/dist/granular-provider-node.js +1 -1
  80. package/dist/granular-provider.js +1 -1
  81. package/dist/i18n/all.js +1 -1
  82. package/dist/i18n/index.js +1 -1
  83. package/dist/index.js +26 -19
  84. package/dist/theme.js +1 -1
  85. package/dist/tokens.js +1 -1
  86. package/dist/types/components/GrAffix/GrAffix.vue.d.ts +91 -0
  87. package/dist/types/components/GrAffix/affixState.d.ts +81 -0
  88. package/dist/types/components/GrAffix/config.d.ts +1 -0
  89. package/dist/types/components/GrAffix/grAffixStyles.d.ts +46 -0
  90. package/dist/types/components/GrAffix/index.d.ts +9 -0
  91. package/dist/types/components/GrAffix/safelist.d.ts +1 -0
  92. package/dist/types/components/GrAlert/GrAlert.vue.d.ts +1 -1
  93. package/dist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +2 -2
  94. package/dist/types/components/GrButton/GrButton.vue.d.ts +2 -2
  95. package/dist/types/components/GrCard/GrCard.vue.d.ts +1 -1
  96. package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +151 -0
  97. package/dist/types/components/GrCarousel/GrCarouselSlide.vue.d.ts +53 -0
  98. package/dist/types/components/GrCarousel/carouselNavigation.d.ts +57 -0
  99. package/dist/types/components/GrCarousel/composables/useCarouselAutoplay.d.ts +33 -0
  100. package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +20 -0
  101. package/dist/types/components/GrCarousel/config.d.ts +7 -0
  102. package/dist/types/components/GrCarousel/defaults.d.ts +13 -0
  103. package/dist/types/components/GrCarousel/grCarouselContext.d.ts +46 -0
  104. package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +80 -0
  105. package/dist/types/components/GrCarousel/index.d.ts +12 -0
  106. package/dist/types/components/GrCarousel/safelist.d.ts +1 -0
  107. package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +3 -3
  108. package/dist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts +2 -2
  109. package/dist/types/components/GrChip/GrChip.vue.d.ts +2 -2
  110. package/dist/types/components/GrChipGroup/GrChipGroup.vue.d.ts +2 -2
  111. package/dist/types/components/GrCollapse/GrCollapse.vue.d.ts +1 -1
  112. package/dist/types/components/GrCollapse/GrCollapseItem.vue.d.ts +1 -1
  113. package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +3 -3
  114. package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +1 -1
  115. package/dist/types/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +1 -1
  116. package/dist/types/components/GrContextMenu/GrContextMenu.vue.d.ts +2 -2
  117. package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
  118. package/dist/types/components/GrDivider/GrDivider.vue.d.ts +2 -2
  119. package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
  120. package/dist/types/components/GrDropdown/GrDropdown.vue.d.ts +3 -3
  121. package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +3 -3
  122. package/dist/types/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +1 -1
  123. package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +1 -1
  124. package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
  125. package/dist/types/components/GrFormField/GrFormField.vue.d.ts +3 -3
  126. package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
  127. package/dist/types/components/GrFormSection/GrFormSection.vue.d.ts +1 -1
  128. package/dist/types/components/GrIcon/GrIcon.vue.d.ts +1 -1
  129. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +3 -3
  130. package/dist/types/components/GrInput/GrInput.vue.d.ts +4 -4
  131. package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +3 -3
  132. package/dist/types/components/GrKbd/GrKbd.vue.d.ts +1 -1
  133. package/dist/types/components/GrLink/GrLink.vue.d.ts +1 -1
  134. package/dist/types/components/GrList/GrListItem.vue.d.ts +2 -2
  135. package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +2 -2
  136. package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +3 -3
  137. package/dist/types/components/GrPagination/GrPagination.vue.d.ts +1 -1
  138. package/dist/types/components/GrPopover/GrPopover.vue.d.ts +3 -3
  139. package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +3 -3
  140. package/dist/types/components/GrRadio/GrRadio.vue.d.ts +2 -2
  141. package/dist/types/components/GrRadioGroup/GrRadioGroup.vue.d.ts +2 -2
  142. package/dist/types/components/GrRating/GrRating.vue.d.ts +2 -2
  143. package/dist/types/components/GrScrollSpy/GrScrollSpy.vue.d.ts +105 -0
  144. package/dist/types/components/GrScrollSpy/config.d.ts +1 -0
  145. package/dist/types/components/GrScrollSpy/grScrollSpyStyles.d.ts +26 -0
  146. package/dist/types/components/GrScrollSpy/index.d.ts +9 -0
  147. package/dist/types/components/GrScrollSpy/safelist.d.ts +1 -0
  148. package/dist/types/components/GrScrollSpy/scrollSpyItems.d.ts +44 -0
  149. package/dist/types/components/GrSegmented/GrSegmented.vue.d.ts +2 -2
  150. package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +1 -1
  151. package/dist/types/components/GrSkeleton/GrSkeleton.vue.d.ts +1 -1
  152. package/dist/types/components/GrSlider/GrSlider.vue.d.ts +3 -3
  153. package/dist/types/components/GrSplitter/GrSplitter.vue.d.ts +1 -1
  154. package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +2 -2
  155. package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +3 -3
  156. package/dist/types/components/GrTable/GrTable.vue.d.ts +1 -1
  157. package/dist/types/components/GrTabs/GrTabs.vue.d.ts +1 -1
  158. package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
  159. package/dist/types/components/GrTimeline/GrTimelineItem.vue.d.ts +2 -2
  160. package/dist/types/components/GrToaster/GrToaster.vue.d.ts +1 -1
  161. package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +3 -3
  162. package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +103 -0
  163. package/dist/types/components/GrTransfer/config.d.ts +1 -0
  164. package/dist/types/components/GrTransfer/defaults.d.ts +15 -0
  165. package/dist/types/components/GrTransfer/grTransferStyles.d.ts +127 -0
  166. package/dist/types/components/GrTransfer/index.d.ts +11 -0
  167. package/dist/types/components/GrTransfer/safelist.d.ts +1 -0
  168. package/dist/types/components/GrTransfer/transferGeometry.d.ts +44 -0
  169. package/dist/types/components/GrTransfer/transferModel.d.ts +68 -0
  170. package/dist/types/components/GrTransfer/transferSelection.d.ts +36 -0
  171. package/dist/types/components/GrTransfer/useTransferDrag.d.ts +48 -0
  172. package/dist/types/composables/internal/scrollSpyGeometry.d.ts +67 -0
  173. package/dist/types/composables/useScrollSpy.d.ts +59 -0
  174. package/dist/types/granular-provider/shared.d.ts +4 -0
  175. package/dist/types/i18n/messages/en.d.ts +64 -0
  176. package/dist/types/i18n/messages/es.d.ts +64 -0
  177. package/dist/types/i18n/messages/ru.d.ts +64 -0
  178. package/dist/types/index.d.ts +6 -0
  179. package/dist/web-types.json +809 -284
  180. package/package.json +25 -1
  181. package/dist/chunks/config-DWL81-aM.js.map +0 -1
  182. package/dist/chunks/en-B9E3jO6m.js.map +0 -1
  183. package/dist/chunks/es-QpzdIEut.js.map +0 -1
  184. package/dist/chunks/generated-B95IBXs6.js.map +0 -1
  185. package/dist/chunks/granular-provider-BG_2XqkS.js.map +0 -1
  186. package/dist/chunks/ru-D_1Ya489.js.map +0 -1
  187. package/dist/chunks/useDragSort-0l47h4yb.js +0 -265
  188. package/dist/chunks/useDragSort-0l47h4yb.js.map +0 -1
  189. package/dist/components/GrTabs/chunks/GrTabs-BArefUFv.js.map +0 -1
  190. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js → GrImageViewer-DK-iVHHC.js} +3 -3
  191. package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js → GrInputTag-Ci8AO1ze.js} +1 -1
  192. package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js → GrNumberInput-CL5QhOmx.js} +1 -1
  193. package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js → GrSlider-CO8N9SF6.js} +1 -1
@@ -0,0 +1,1368 @@
1
+ import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunks/context-CPMRfwVr.js";
2
+ import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
+ import { t as usePortalTarget } from "../../../chunks/usePortalTarget-BhrRgdqW.js";
4
+ import { useGrFormControl } from "../../../composables/useGrFormControl.js";
5
+ import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
6
+ import { useRovingFocus } from "../../../composables/useRovingFocus.js";
7
+ import { i as normalizeOptionQuery, r as matchesQueryParts } from "../../../chunks/optionFilter-DYw9XPPx.js";
8
+ import { t as check_default } from "../../../chunks/check-BZI24Qs4.js";
9
+ import { t as GrButton_default } from "../../GrButton/chunks/GrButton-CS4TqMtG.js";
10
+ import { t as GrButtonGroup_default } from "../../GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js";
11
+ import { useAnnouncer } from "../../../composables/useAnnouncer.js";
12
+ import { t as resolveScrollOverflow } from "../../../chunks/scrollOverflow-B_kEdcol.js";
13
+ import { useDragGesture } from "../../../composables/useDragGesture.js";
14
+ import { t as chevron_left_default } from "../../../chunks/chevron-left-D8AUBAM7.js";
15
+ import { t as chevron_right_default } from "../../../chunks/chevron-right-C6Z01h0X.js";
16
+ import { t as GrCheckbox_default } from "../../GrCheckbox/chunks/GrCheckbox-Dp201frb.js";
17
+ import { t as GrInput_default } from "../../GrInput/chunks/GrInput-TFeBm3gQ.js";
18
+ import { n as hitTest, t as autoScrollDelta } from "../../../chunks/dragSortGeometry-CY-llfrQ.js";
19
+ import { C as transferTitleClass, S as transferStatusClass, _ as transferLabelClass, a as grTransferHeaderClass, b as transferReorderIconClass, c as grTransferPanelClass, d as transferActionIconClass, f as transferActionInertClass, g as transferGhostLabelClass, h as transferGhostCountClass, i as grTransferEmptyClass, l as grTransferReorderClass, m as transferGhostClass, o as grTransferMarkClass, p as transferCounterClass, r as grTransferActionsClass, s as grTransferOptionClass, u as grTransferSearchClass, v as transferListBase, x as transferRootBase, y as transferMarkIconClass } from "../../../chunks/config-DmED6aJV.js";
20
+ import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, markRaw, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onScopeDispose, openBlock, ref, renderList, renderSlot, shallowRef, toDisplayString, unref, useId, useSlots, watch, withCtx } from "vue";
21
+ import '../styles.css';//#region src/components/GrTransfer/transferModel.ts
22
+ /**
23
+ * Ключи без дублей, первый выигрывает.
24
+ *
25
+ * Нормализация идёт **на чтение** и наружу сама по себе не эмитится: эмит из
26
+ * рендера — источник петель обновления. Нормализованный вид уезжает потребителю
27
+ * при первом же коммите.
28
+ */
29
+ function normalizeKeys(keys) {
30
+ const seen = /* @__PURE__ */ new Set();
31
+ const next = [];
32
+ for (const key of keys) {
33
+ if (seen.has(key)) continue;
34
+ seen.add(key);
35
+ next.push(key);
36
+ }
37
+ return next;
38
+ }
39
+ /**
40
+ * Раскладка каталога по панелям.
41
+ *
42
+ * `target` строится обходом **модели**, а не `items`: порядок правой панели
43
+ * задаёт пользователь, и он же является значением. `source` — обходом `items`,
44
+ * потому что порядок каталога принадлежит потребителю.
45
+ */
46
+ function splitByModel(items, keyOf, model) {
47
+ const byKey = /* @__PURE__ */ new Map();
48
+ const duplicated = [];
49
+ for (const item of items) {
50
+ const key = keyOf(item);
51
+ if (byKey.has(key)) {
52
+ duplicated.push(key);
53
+ continue;
54
+ }
55
+ byKey.set(key, item);
56
+ }
57
+ const wanted = normalizeKeys(model);
58
+ const inTarget = new Set(wanted);
59
+ const target = [];
60
+ const unresolved = [];
61
+ for (const key of wanted) {
62
+ const item = byKey.get(key);
63
+ if (item === void 0) {
64
+ unresolved.push(key);
65
+ continue;
66
+ }
67
+ target.push(item);
68
+ }
69
+ return {
70
+ source: items.filter((item) => !inTarget.has(keyOf(item)) && byKey.get(keyOf(item)) === item),
71
+ target,
72
+ unresolved,
73
+ duplicated
74
+ };
75
+ }
76
+ /** Изъятие блока. Вход не мутируется. */
77
+ function removeKeys(order, moving) {
78
+ const drop = new Set(moving);
79
+ return order.filter((key) => !drop.has(key));
80
+ }
81
+ /**
82
+ * Вставка блока перед ключом `before`; `null` или ненайденный ключ — в конец.
83
+ *
84
+ * Цель выражена ключом, а не индексом, намеренно: индекс пришлось бы
85
+ * пересчитывать после изъятия блока, и это ровно тот класс off-by-one, из-за
86
+ * которого `insertionIndex` в `dragSortGeometry` носит поправку «элемент
87
+ * временно вынут». Здесь поправка не нужна вовсе.
88
+ */
89
+ function insertKeys(order, moving, before) {
90
+ const block = normalizeKeys(moving);
91
+ if (block.length === 0) return order.slice();
92
+ const rest = removeKeys(order, block);
93
+ const at = before === null ? -1 : rest.indexOf(before);
94
+ if (at < 0) return [...rest, ...block];
95
+ return [
96
+ ...rest.slice(0, at),
97
+ ...block,
98
+ ...rest.slice(at)
99
+ ];
100
+ }
101
+ /**
102
+ * Куда встанет блок при сдвиге на шаг; `undefined` — двигаться некуда.
103
+ *
104
+ * Рассыпанное выделение при сдвиге схлопывается в непрерывный блок: это
105
+ * предсказуемо и объяснимо, в отличие от попытки двигать каждый кусок
106
+ * независимо.
107
+ */
108
+ function stepTarget(order, moving, delta) {
109
+ const block = normalizeKeys(moving).filter((key) => order.includes(key));
110
+ if (block.length === 0) return void 0;
111
+ const rest = removeKeys(order, block);
112
+ const first = order.findIndex((key) => block.includes(key));
113
+ const before = order.slice(0, first).filter((key) => !block.includes(key)).length;
114
+ const next = Math.min(rest.length, Math.max(0, before + delta));
115
+ if (next === before) return void 0;
116
+ return rest[next] ?? null;
117
+ }
118
+ /** Крайняя позиция блока: `-1` — в начало, `1` — в конец. */
119
+ function edgeTarget(order, moving, edge) {
120
+ const block = normalizeKeys(moving).filter((key) => order.includes(key));
121
+ if (block.length === 0) return void 0;
122
+ const rest = removeKeys(order, block);
123
+ if (edge === "end") return rest.length === 0 ? void 0 : null;
124
+ const first = rest[0];
125
+ return first === void 0 ? void 0 : first;
126
+ }
127
+ /**
128
+ * Какая строка останется под фокусом после изъятия.
129
+ *
130
+ * Без этого фокус после переноса падает на тело документа, и клавиатурный
131
+ * сценарий обрывается на первом же шаге — тот же довод, что у `drop()` в
132
+ * `GrSortableList`.
133
+ */
134
+ function keyAfterRemoval(visible, removed, focused) {
135
+ const drop = new Set(removed);
136
+ const rest = visible.filter((key) => !drop.has(key));
137
+ if (rest.length === 0) return void 0;
138
+ if (focused !== void 0 && !drop.has(focused)) return focused;
139
+ const from = focused === void 0 ? 0 : visible.indexOf(focused);
140
+ for (let index = from; index < visible.length; index += 1) {
141
+ const key = visible[index];
142
+ if (!drop.has(key)) return key;
143
+ }
144
+ for (let index = from - 1; index >= 0; index -= 1) {
145
+ const key = visible[index];
146
+ if (!drop.has(key)) return key;
147
+ }
148
+ return rest[0];
149
+ }
150
+ function contains(rect, point) {
151
+ return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
152
+ }
153
+ /**
154
+ * Панель под указателем; `null` — указатель в зазоре или за пределами обеих.
155
+ *
156
+ * Считается по прямоугольнику **обёртки панели**, а не по ближайшей строке:
157
+ * `hitTest` при промахе возвращает ближайший элемент, и указатель над пустой
158
+ * правой панелью резолвился бы в строку левой.
159
+ */
160
+ function sideAtPoint(rects, point) {
161
+ if (rects.source && contains(rects.source, point)) return "source";
162
+ if (rects.target && contains(rects.target, point)) return "target";
163
+ return null;
164
+ }
165
+ /**
166
+ * Перед какой строкой встанет блок; `null` — в конец панели.
167
+ *
168
+ * Цель — ключ, а не индекс: индекс пришлось бы пересчитывать после изъятия
169
+ * блока, и именно ради этого `insertionIndex` в `dragSortGeometry` носит
170
+ * поправку «элемент временно вынут». Для вставки из чужой панели поправка
171
+ * вредна — там ничего не вынимается, — поэтому та функция здесь не годится.
172
+ */
173
+ function dropBefore(keys, spans, position) {
174
+ if (keys.length === 0 || spans.length === 0) return null;
175
+ const hit = hitTest(spans, position);
176
+ if (!hit) return null;
177
+ const index = hit.fraction < .5 ? hit.index : hit.index + 1;
178
+ return index >= keys.length ? null : keys[index] ?? null;
179
+ }
180
+ /** Пройден ли порог начала жеста. */
181
+ function passedThreshold(from, to, threshold = 4) {
182
+ return Math.hypot(to.x - from.x, to.y - from.y) >= threshold;
183
+ }
184
+ //#endregion
185
+ //#region src/components/GrTransfer/useTransferDrag.ts
186
+ function rectOf(el) {
187
+ if (!el) return null;
188
+ const box = el.getBoundingClientRect();
189
+ return {
190
+ left: box.left,
191
+ right: box.right,
192
+ top: box.top,
193
+ bottom: box.bottom
194
+ };
195
+ }
196
+ /**
197
+ * Перетаскивание между панелями.
198
+ *
199
+ * `useDragSort` здесь не подходит: его `resolveTarget` получает попадание, но не
200
+ * точку указателя, а панель-приёмник определяется прямоугольником под точкой —
201
+ * `hitTest` при промахе отдаёт ближайшую строку, и указатель над пустой правой
202
+ * панелью резолвился бы в строку левой.
203
+ */
204
+ function useTransferDrag(options) {
205
+ const session = shallowRef(null);
206
+ const spot = shallowRef(null);
207
+ const moved = ref(false);
208
+ const pointer = shallowRef({
209
+ x: 0,
210
+ y: 0
211
+ });
212
+ let origin = {
213
+ x: 0,
214
+ y: 0
215
+ };
216
+ let pending = null;
217
+ /** Последняя непустая сторона: в зазоре между панелями индикатор не мигает. */
218
+ let lastSide = null;
219
+ let frame = null;
220
+ let cursor = {
221
+ x: 0,
222
+ y: 0
223
+ };
224
+ function stopAutoScroll() {
225
+ if (frame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
226
+ frame = null;
227
+ }
228
+ function tickAutoScroll() {
229
+ frame = null;
230
+ const side = lastSide;
231
+ const scroller = side ? options.scrollerEl(side) : null;
232
+ if (scroller) {
233
+ const box = scroller.getBoundingClientRect();
234
+ const delta = autoScrollDelta({
235
+ start: box.top,
236
+ end: box.bottom
237
+ }, cursor.y);
238
+ if (delta !== 0) scroller.scrollTop += delta;
239
+ }
240
+ scheduleAutoScroll();
241
+ }
242
+ function scheduleAutoScroll() {
243
+ if (session.value === null || typeof requestAnimationFrame !== "function") return;
244
+ frame = requestAnimationFrame(tickAutoScroll);
245
+ }
246
+ function reset() {
247
+ session.value = null;
248
+ spot.value = null;
249
+ pending = null;
250
+ lastSide = null;
251
+ stopAutoScroll();
252
+ detachEscape();
253
+ unlockSelection();
254
+ }
255
+ function onEscape(event) {
256
+ if (event.key !== "Escape" || session.value === null) return;
257
+ event.preventDefault();
258
+ event.stopPropagation();
259
+ abort();
260
+ }
261
+ /**
262
+ * Выделение текста на время жеста.
263
+ *
264
+ * `select-none` на самих строках недостаточно: выделение **начинается** внутри
265
+ * компонента, а тянется по всему документу — и пользователь, ведя строку через
266
+ * страницу, подсвечивает попутно чужие заголовки и абзацы. Гасим на теле
267
+ * документа и возвращаем прежнее значение, а не пустую строку: потребитель мог
268
+ * задать своё.
269
+ */
270
+ let selectionLock = null;
271
+ function lockSelection() {
272
+ if (typeof document === "undefined" || selectionLock !== null) return;
273
+ const style = document.body.style;
274
+ selectionLock = {
275
+ userSelect: style.userSelect,
276
+ webkitUserSelect: style.webkitUserSelect ?? ""
277
+ };
278
+ style.userSelect = "none";
279
+ style.webkitUserSelect = "none";
280
+ window.getSelection?.()?.removeAllRanges();
281
+ }
282
+ function unlockSelection() {
283
+ if (typeof document === "undefined" || selectionLock === null) return;
284
+ const style = document.body.style;
285
+ style.userSelect = selectionLock.userSelect;
286
+ style.webkitUserSelect = selectionLock.webkitUserSelect;
287
+ selectionLock = null;
288
+ }
289
+ let escapeAttached = false;
290
+ function attachEscape() {
291
+ if (escapeAttached || typeof window === "undefined") return;
292
+ window.addEventListener("keydown", onEscape, true);
293
+ escapeAttached = true;
294
+ }
295
+ function detachEscape() {
296
+ if (!escapeAttached || typeof window === "undefined") return;
297
+ window.removeEventListener("keydown", onEscape, true);
298
+ escapeAttached = false;
299
+ }
300
+ function resolveSpot(point) {
301
+ const active = session.value;
302
+ if (!active) return;
303
+ const side = sideAtPoint({
304
+ source: rectOf(options.panelEl("source")),
305
+ target: rectOf(options.panelEl("target"))
306
+ }, point) ?? lastSide;
307
+ if (side === null) {
308
+ spot.value = null;
309
+ return;
310
+ }
311
+ lastSide = side;
312
+ if (side === active.side && !options.allowSameSide(side)) {
313
+ spot.value = null;
314
+ return;
315
+ }
316
+ const keys = options.visibleKeys(side);
317
+ const spans = keys.map((key) => {
318
+ const box = options.rowEl(side, key)?.getBoundingClientRect();
319
+ return {
320
+ start: box?.top ?? 0,
321
+ end: box?.bottom ?? 0
322
+ };
323
+ });
324
+ spot.value = {
325
+ side,
326
+ before: dropBefore(keys, spans, point.y)
327
+ };
328
+ }
329
+ const drag = useDragGesture({
330
+ disabled: options.disabled,
331
+ onMove: (event) => {
332
+ cursor = {
333
+ x: event.clientX,
334
+ y: event.clientY
335
+ };
336
+ pointer.value = cursor;
337
+ if (session.value === null) {
338
+ if (pending === null || !passedThreshold(origin, cursor)) return;
339
+ session.value = pending;
340
+ moved.value = true;
341
+ lockSelection();
342
+ attachEscape();
343
+ scheduleAutoScroll();
344
+ }
345
+ event.preventDefault();
346
+ resolveSpot(cursor);
347
+ },
348
+ onEnd: () => {
349
+ const active = session.value;
350
+ const target = spot.value;
351
+ if (active && target) options.onDrop(active, target);
352
+ reset();
353
+ },
354
+ onCancel: () => {
355
+ if (session.value !== null) options.onCancel?.();
356
+ reset();
357
+ }
358
+ });
359
+ /** Объявлен после `drag`: слушатель `Esc` вешается раньше и зовёт его косвенно. */
360
+ function abort() {
361
+ drag.stop(false);
362
+ }
363
+ onScopeDispose(reset);
364
+ return {
365
+ session,
366
+ spot,
367
+ pointer,
368
+ consumeClick: () => {
369
+ const was = moved.value;
370
+ moved.value = false;
371
+ return was;
372
+ },
373
+ startFrom: (side, key) => (event) => {
374
+ if (event.pointerType === "touch" || options.disabled()) return;
375
+ const block = options.blockFor(side, key);
376
+ if (block.length === 0) return;
377
+ origin = {
378
+ x: event.clientX,
379
+ y: event.clientY
380
+ };
381
+ pending = {
382
+ side,
383
+ keys: block
384
+ };
385
+ moved.value = false;
386
+ drag.start(event);
387
+ },
388
+ cancel: () => drag.stop(false)
389
+ };
390
+ }
391
+ //#endregion
392
+ //#region src/components/GrTransfer/transferSelection.ts
393
+ var emptySelection = {
394
+ keys: /* @__PURE__ */ new Set(),
395
+ anchor: void 0
396
+ };
397
+ /** `Shift` сильнее `Ctrl`; их сочетание объединяет диапазон с выделением. */
398
+ function selectIntentFrom(event) {
399
+ const additive = event.ctrlKey || event.metaKey;
400
+ if (event.shiftKey) return {
401
+ mode: "range",
402
+ additive
403
+ };
404
+ return {
405
+ mode: additive ? "toggle" : "replace",
406
+ additive
407
+ };
408
+ }
409
+ function rangeBetween(visible, from, to) {
410
+ const start = visible.indexOf(from);
411
+ const end = visible.indexOf(to);
412
+ if (start < 0 || end < 0) return [];
413
+ return visible.slice(Math.min(start, end), Math.max(start, end) + 1);
414
+ }
415
+ /**
416
+ * Новое состояние выделения после жеста по строке `key`.
417
+ *
418
+ * Диапазон считается по **видимому** порядку, а не по каталогу: пользователь
419
+ * растягивает то, что видит, и после фильтра «от сих до сих» обязано значить
420
+ * то же самое.
421
+ */
422
+ function applySelect(state, key, intent, visible, isSelectable) {
423
+ if (!isSelectable(key)) return state;
424
+ if (intent.mode === "range" && state.anchor !== void 0) {
425
+ const range = rangeBetween(visible, state.anchor, key).filter(isSelectable);
426
+ if (range.length > 0) {
427
+ const keys = intent.additive ? new Set(state.keys) : /* @__PURE__ */ new Set();
428
+ range.forEach((item) => keys.add(item));
429
+ return {
430
+ keys,
431
+ anchor: state.anchor
432
+ };
433
+ }
434
+ }
435
+ if (intent.mode === "toggle") {
436
+ const keys = new Set(state.keys);
437
+ if (keys.has(key)) keys.delete(key);
438
+ else keys.add(key);
439
+ return {
440
+ keys,
441
+ anchor: key
442
+ };
443
+ }
444
+ return {
445
+ keys: /* @__PURE__ */ new Set([key]),
446
+ anchor: key
447
+ };
448
+ }
449
+ /** Всё видимое и выбираемое; уже выбрано всё — снять. */
450
+ function toggleAllVisible(state, visible, isSelectable) {
451
+ const selectable = visible.filter(isSelectable);
452
+ if (selectable.length === 0) return {
453
+ keys: new Set(state.keys),
454
+ anchor: void 0
455
+ };
456
+ if (selectable.every((key) => state.keys.has(key))) {
457
+ const keys = new Set(state.keys);
458
+ selectable.forEach((key) => keys.delete(key));
459
+ return {
460
+ keys,
461
+ anchor: void 0
462
+ };
463
+ }
464
+ const keys = new Set(state.keys);
465
+ selectable.forEach((key) => keys.add(key));
466
+ return {
467
+ keys,
468
+ anchor: void 0
469
+ };
470
+ }
471
+ /** Ключи, которых больше нет в панели. Якорь исчез — забываем и его. */
472
+ function pruneSelection(state, present) {
473
+ const alive = new Set(present);
474
+ const keys = /* @__PURE__ */ new Set();
475
+ state.keys.forEach((key) => {
476
+ if (alive.has(key)) keys.add(key);
477
+ });
478
+ const anchor = state.anchor !== void 0 && alive.has(state.anchor) ? state.anchor : void 0;
479
+ if (keys.size === state.keys.size && anchor === state.anchor) return state;
480
+ return {
481
+ keys,
482
+ anchor
483
+ };
484
+ }
485
+ /** Состояние отметки «выбрать всё видимое» в шапке панели. */
486
+ function allVisibleState(state, visible, isSelectable) {
487
+ const selectable = visible.filter(isSelectable);
488
+ if (selectable.length === 0) return "unchecked";
489
+ const picked = selectable.filter((key) => state.keys.has(key)).length;
490
+ if (picked === 0) return "unchecked";
491
+ return picked === selectable.length ? "checked" : "indeterminate";
492
+ }
493
+ //#endregion
494
+ //#region ~icons/lucide/arrow-left
495
+ var _hoisted_1$2 = {
496
+ viewBox: "0 0 24 24",
497
+ width: "1.2em",
498
+ height: "1.2em"
499
+ };
500
+ function render$2(_ctx, _cache) {
501
+ return openBlock(), createElementBlock("svg", _hoisted_1$2, [..._cache[0] || (_cache[0] = [createElementVNode("path", {
502
+ fill: "none",
503
+ stroke: "currentColor",
504
+ "stroke-linecap": "round",
505
+ "stroke-linejoin": "round",
506
+ "stroke-width": "2",
507
+ d: "m12 19l-7-7l7-7m7 7H5"
508
+ }, null, -1)])]);
509
+ }
510
+ var arrow_left_default = markRaw({
511
+ name: "lucide-arrow-left",
512
+ render: render$2
513
+ });
514
+ //#endregion
515
+ //#region ~icons/lucide/arrow-right
516
+ var _hoisted_1$1 = {
517
+ viewBox: "0 0 24 24",
518
+ width: "1.2em",
519
+ height: "1.2em"
520
+ };
521
+ function render$1(_ctx, _cache) {
522
+ return openBlock(), createElementBlock("svg", _hoisted_1$1, [..._cache[0] || (_cache[0] = [createElementVNode("path", {
523
+ fill: "none",
524
+ stroke: "currentColor",
525
+ "stroke-linecap": "round",
526
+ "stroke-linejoin": "round",
527
+ "stroke-width": "2",
528
+ d: "M5 12h14m-7-7l7 7l-7 7"
529
+ }, null, -1)])]);
530
+ }
531
+ var arrow_right_default = markRaw({
532
+ name: "lucide-arrow-right",
533
+ render: render$1
534
+ });
535
+ //#endregion
536
+ //#region src/components/GrTransfer/GrTransfer.vue?vue&type=script&setup=true&lang.ts
537
+ var _hoisted_1 = [
538
+ "data-dragging",
539
+ "aria-label",
540
+ "aria-disabled"
541
+ ];
542
+ var _hoisted_2 = ["data-gr-transfer-panel"];
543
+ var _hoisted_3 = ["id"];
544
+ var _hoisted_4 = ["aria-disabled", "aria-label"];
545
+ var _hoisted_5 = ["aria-disabled", "aria-label"];
546
+ var _hoisted_6 = [
547
+ "id",
548
+ "data-gr-transfer-list",
549
+ "data-overflow",
550
+ "aria-label",
551
+ "aria-labelledby",
552
+ "aria-describedby",
553
+ "aria-invalid",
554
+ "aria-required",
555
+ "aria-readonly",
556
+ "aria-disabled",
557
+ "onKeydown"
558
+ ];
559
+ var _hoisted_7 = [
560
+ "aria-selected",
561
+ "aria-disabled",
562
+ "tabindex",
563
+ "onPointerdown",
564
+ "onClick",
565
+ "onFocus",
566
+ "onDblclick"
567
+ ];
568
+ //#endregion
569
+ //#region src/components/GrTransfer/GrTransfer.vue
570
+ var GrTransfer_default = /* @__PURE__ */ defineComponent({
571
+ __name: "GrTransfer",
572
+ props: {
573
+ items: {},
574
+ modelValue: {},
575
+ itemKey: {
576
+ type: [String, Function],
577
+ default: void 0
578
+ },
579
+ itemLabel: {
580
+ type: [String, Function],
581
+ default: void 0
582
+ },
583
+ itemDisabled: {
584
+ type: [String, Function],
585
+ default: void 0
586
+ },
587
+ sourceTitle: { default: void 0 },
588
+ targetTitle: { default: void 0 },
589
+ searchable: {
590
+ type: Boolean,
591
+ default: true
592
+ },
593
+ filter: {
594
+ type: Function,
595
+ default: void 0
596
+ },
597
+ sortable: {
598
+ type: Boolean,
599
+ default: true
600
+ },
601
+ draggable: {
602
+ type: Boolean,
603
+ default: void 0
604
+ },
605
+ maxHeight: { default: void 0 },
606
+ size: { default: void 0 },
607
+ disabled: {
608
+ type: Boolean,
609
+ default: false
610
+ },
611
+ readonly: {
612
+ type: Boolean,
613
+ default: false
614
+ },
615
+ invalid: {
616
+ type: Boolean,
617
+ default: false
618
+ },
619
+ required: {
620
+ type: Boolean,
621
+ default: false
622
+ },
623
+ ariaLabel: { default: void 0 }
624
+ },
625
+ emits: [
626
+ "update:modelValue",
627
+ "change",
628
+ "transfer",
629
+ "search",
630
+ "focus",
631
+ "blur"
632
+ ],
633
+ setup(__props, { expose: __expose, emit: __emit }) {
634
+ const props = __props;
635
+ const emit = __emit;
636
+ const slots = useSlots();
637
+ /**
638
+ * Свой `#header` уносит с собой заголовок панели, а вместе с ним и `id`, на
639
+ * который смотрит `aria-labelledby` списка: панель осталась бы без доступного
640
+ * имени, и axe ловит это как `aria-input-field-name`. Имя поэтому не зависит от
641
+ * разметки потребителя — при своей шапке оно приходит из `aria-label`.
642
+ */
643
+ const hasHeaderSlot = computed(() => Boolean(slots.header));
644
+ const { t } = useGranularityTranslations();
645
+ const { announce } = useAnnouncer();
646
+ const { target: portalTarget, enabled: teleportEnabled } = usePortalTarget();
647
+ const resolvedSize = useGrComponentSize(() => props.size, { component: "GrTransfer" });
648
+ const resolvedDraggable = useGrComponentProp("GrTransfer", "draggable", () => props.draggable, true);
649
+ const { disabled: isDisabled, readonly: isReadonly, invalid: isInvalid, required: isRequired, locked: isLocked, id: fieldId, labelId: fieldLabelId, describedBy } = useGrFormControl(() => props);
650
+ const rootEl = ref(null);
651
+ const uid = useId();
652
+ const sourceTitleId = `${uid}-source-title`;
653
+ const targetTitleId = `${uid}-target-title`;
654
+ const sourceListId = `${uid}-source-list`;
655
+ const targetListId = `${uid}-target-list`;
656
+ if (process.env.NODE_ENV !== "production") {
657
+ if (!Array.isArray(props.items)) console.warn(`[granularity] GrTransfer: обязательный проп \`items\` должен быть массивом — получено ${typeof props.items}.`);
658
+ if (!Array.isArray(props.modelValue)) console.warn(`[granularity] GrTransfer: обязательный проп \`modelValue\` должен быть массивом — получено ${typeof props.modelValue}.`);
659
+ }
660
+ /**
661
+ * Синтетический ключ для элемента без своего: общий ключ пометил бы выбранными
662
+ * все строки разом. Приём и причина — из `GrDataTable`.
663
+ */
664
+ const syntheticKeys = /* @__PURE__ */ new WeakMap();
665
+ let syntheticCount = 0;
666
+ let warnedSynthetic = false;
667
+ function keyOf(item) {
668
+ const source = props.itemKey ?? "id";
669
+ const value = typeof source === "function" ? source(item) : item[source];
670
+ if (typeof value === "string" && value !== "") return value;
671
+ if (typeof value === "number") return value;
672
+ const known = syntheticKeys.get(item);
673
+ if (known !== void 0) return known;
674
+ syntheticCount += 1;
675
+ const generated = `${uid}-synthetic-${syntheticCount}`;
676
+ syntheticKeys.set(item, generated);
677
+ if (process.env.NODE_ENV !== "production" && !warnedSynthetic) {
678
+ warnedSynthetic = true;
679
+ console.warn("[granularity] GrTransfer: у элемента нет значения `itemKey` — выдан временный ключ. Он не переживёт перезагрузку данных, и `modelValue` с ним не сойдётся: задайте `itemKey`.");
680
+ }
681
+ return generated;
682
+ }
683
+ function labelOf(item) {
684
+ const source = props.itemLabel ?? "label";
685
+ return typeof source === "function" ? source(item) : String(item[source] ?? "");
686
+ }
687
+ function disabledOf(item) {
688
+ const source = props.itemDisabled ?? "disabled";
689
+ return typeof source === "function" ? source(item) : Boolean(item[source]);
690
+ }
691
+ const split = computed(() => splitByModel(props.items ?? [], keyOf, props.modelValue ?? []));
692
+ if (process.env.NODE_ENV !== "production") watch(split, (value) => {
693
+ if (value.duplicated.length > 0) console.warn(`[granularity] GrTransfer: ключи повторяются в \`items\` (${value.duplicated.join(", ")}) — рисуется первый элемент с таким ключом.`);
694
+ if (value.unresolved.length > 0 && (props.items?.length ?? 0) > 0) console.warn(`[granularity] GrTransfer: ключи из \`modelValue\` не найдены в \`items\` (${value.unresolved.join(", ")}). Они сохранены в значении, но не показаны: каталог мог ещё не приехать.`);
695
+ }, { immediate: true });
696
+ const queries = ref({
697
+ source: "",
698
+ target: ""
699
+ });
700
+ const selections = ref({
701
+ source: emptySelection,
702
+ target: emptySelection
703
+ });
704
+ function itemsOf(side) {
705
+ return side === "source" ? split.value.source : split.value.target;
706
+ }
707
+ function matches(item, query) {
708
+ if (props.filter) return props.filter(item, query);
709
+ return matchesQueryParts([labelOf(item)], normalizeOptionQuery(query));
710
+ }
711
+ function visibleOf(side) {
712
+ const query = queries.value[side];
713
+ if (!props.searchable || normalizeOptionQuery(query) === "") return itemsOf(side);
714
+ return itemsOf(side).filter((item) => matches(item, query));
715
+ }
716
+ const visible = computed(() => ({
717
+ source: visibleOf("source"),
718
+ target: visibleOf("target")
719
+ }));
720
+ const visibleKeys = computed(() => ({
721
+ source: visible.value.source.map(keyOf),
722
+ target: visible.value.target.map(keyOf)
723
+ }));
724
+ function selectableOf(side) {
725
+ return (key) => {
726
+ const item = itemsOf(side).find((candidate) => keyOf(candidate) === key);
727
+ return item !== void 0 && !disabledOf(item);
728
+ };
729
+ }
730
+ watch(split, () => {
731
+ selections.value = {
732
+ source: pruneSelection(selections.value.source, split.value.source.map(keyOf)),
733
+ target: pruneSelection(selections.value.target, split.value.target.map(keyOf))
734
+ };
735
+ });
736
+ const titles = computed(() => ({
737
+ source: props.sourceTitle ?? t("gr.transfer.sourceTitle", "Available"),
738
+ target: props.targetTitle ?? t("gr.transfer.targetTitle", "Selected")
739
+ }));
740
+ function setSelection(side, next) {
741
+ selections.value = {
742
+ ...selections.value,
743
+ [side]: next
744
+ };
745
+ }
746
+ function toggleAll(side) {
747
+ if (isDisabled.value) return;
748
+ setSelection(side, toggleAllVisible(selections.value[side], visibleKeys.value[side], selectableOf(side)));
749
+ }
750
+ /** Что реально уедет: отмеченное минус запрещённое. Скрытое поиском — уезжает. */
751
+ function movableOf(side) {
752
+ const selectable = selectableOf(side);
753
+ return itemsOf(side).map(keyOf).filter((key) => selections.value[side].keys.has(key) && selectable(key));
754
+ }
755
+ const canToTarget = computed(() => !isLocked.value && movableOf("source").length > 0);
756
+ const canToSource = computed(() => !isLocked.value && movableOf("target").length > 0);
757
+ function commit(next) {
758
+ emit("update:modelValue", next);
759
+ emit("change", next);
760
+ }
761
+ async function transfer(keys, direction) {
762
+ if (isLocked.value || keys.length === 0) return;
763
+ const from = direction === "toTarget" ? "source" : "target";
764
+ const to = direction === "toTarget" ? "target" : "source";
765
+ const model = normalizeKeys(props.modelValue ?? []);
766
+ const nextFocus = keyAfterRemoval(visibleKeys.value[from], keys, rovingOf(from).rovingKey.value);
767
+ commit(direction === "toTarget" ? insertKeys(model, keys, null) : removeKeys(model, keys));
768
+ selections.value = {
769
+ ...selections.value,
770
+ [from]: emptySelection,
771
+ [to]: {
772
+ keys: new Set(keys),
773
+ anchor: keys[0]
774
+ }
775
+ };
776
+ markArrived(keys);
777
+ emit("transfer", keys, direction);
778
+ announce(t("gr.transfer.moved", "{count} moved to {list}", {
779
+ count: keys.length,
780
+ n: keys.length,
781
+ list: titles.value[to]
782
+ }));
783
+ await nextTick();
784
+ if (nextFocus !== void 0) rovingOf(from).focusKey(nextFocus);
785
+ else rovingOf(to).focusKey(keys[0]);
786
+ }
787
+ function transferSelected(direction) {
788
+ const side = direction === "toTarget" ? "source" : "target";
789
+ const keys = movableOf(side);
790
+ if (keys.length > 0) {
791
+ transfer(keys, direction);
792
+ return;
793
+ }
794
+ const focused = rovingOf(side).rovingKey.value;
795
+ if (focused !== void 0 && selectableOf(side)(focused)) transfer([focused], direction);
796
+ }
797
+ /** Перестановка отключена, пока панель отфильтрована: см. `docs/components/GrTransfer.md`. */
798
+ const reorderAllowed = computed(() => props.sortable && !isLocked.value && normalizeOptionQuery(queries.value.target) === "");
799
+ function reorder(target, keys) {
800
+ if (target === void 0 || keys.length === 0) return;
801
+ const model = normalizeKeys(props.modelValue ?? []);
802
+ commit(insertKeys(model, keys, target));
803
+ const position = removeKeys(model, keys).findIndex((key) => key === target);
804
+ announce(t("gr.transfer.reordered", "Position {position} of {count}", {
805
+ position: (position < 0 ? model.length - keys.length : position) + 1,
806
+ count: model.length
807
+ }));
808
+ }
809
+ function moveBlock(delta) {
810
+ const keys = movableOf("target");
811
+ const moving = keys.length > 0 ? keys : blockUnderFocus("target");
812
+ if (moving.length === 0) return;
813
+ if (!reorderAllowed.value) {
814
+ if (props.sortable && !isLocked.value) announce(t("gr.transfer.reorderFiltered", "Reordering is off while a search is active"));
815
+ return;
816
+ }
817
+ reorder(stepTarget(normalizeKeys(props.modelValue ?? []), moving, delta), moving);
818
+ }
819
+ function moveBlockToEdge(edge) {
820
+ const keys = movableOf("target");
821
+ const moving = keys.length > 0 ? keys : blockUnderFocus("target");
822
+ if (moving.length === 0 || !reorderAllowed.value) return;
823
+ reorder(edgeTarget(normalizeKeys(props.modelValue ?? []), moving, edge), moving);
824
+ }
825
+ function blockUnderFocus(side) {
826
+ const focused = rovingOf(side).rovingKey.value;
827
+ return focused !== void 0 && selectableOf(side)(focused) ? [focused] : [];
828
+ }
829
+ const sourceRows = ref(/* @__PURE__ */ new Map());
830
+ const targetRows = ref(/* @__PURE__ */ new Map());
831
+ const searchEls = ref({
832
+ source: null,
833
+ target: null
834
+ });
835
+ const panelEls = ref({
836
+ source: null,
837
+ target: null
838
+ });
839
+ const listEls = ref({
840
+ source: null,
841
+ target: null
842
+ });
843
+ function rowsOf(side) {
844
+ return side === "source" ? sourceRows.value : targetRows.value;
845
+ }
846
+ function registerRow(side, key, el) {
847
+ const map = rowsOf(side);
848
+ if (el instanceof HTMLElement) map.set(key, el);
849
+ else map.delete(key);
850
+ }
851
+ function makeRoving(side) {
852
+ return useRovingFocus({
853
+ items: () => visibleKeys.value[side],
854
+ elementFor: (key) => rowsOf(side).get(key) ?? null,
855
+ orientation: () => "vertical",
856
+ wrap: () => false,
857
+ skipDisabled: () => false,
858
+ onOverflow: (edge) => {
859
+ if (edge !== "start") return false;
860
+ const input = searchEls.value[side]?.querySelector("input");
861
+ if (!input) return false;
862
+ input.focus();
863
+ return true;
864
+ }
865
+ });
866
+ }
867
+ const sourceRoving = makeRoving("source");
868
+ const targetRoving = makeRoving("target");
869
+ function rovingOf(side) {
870
+ return side === "source" ? sourceRoving : targetRoving;
871
+ }
872
+ /**
873
+ * Признак того, что список продолжается за краем.
874
+ *
875
+ * Полоса прокрутки у панели своя и на macOS невидима, поэтому обрезанная
876
+ * посередине строка читается как дефект отрисовки, а не как «прокрути». Затухание
877
+ * рисует CSS по `data-overflow` — тот же приём, что у ряда вкладок `GrTabs`.
878
+ */
879
+ const listOverflow = ref({
880
+ source: "none",
881
+ target: "none"
882
+ });
883
+ let overflowObserver = null;
884
+ let overflowScheduled = false;
885
+ function measureOverflow() {
886
+ const next = {
887
+ source: "none",
888
+ target: "none"
889
+ };
890
+ for (const side of ["source", "target"]) {
891
+ const el = listEls.value[side];
892
+ if (el) next[side] = resolveScrollOverflow(el.scrollTop, el.scrollHeight, el.clientHeight);
893
+ }
894
+ listOverflow.value = next;
895
+ }
896
+ function scheduleOverflow() {
897
+ if (overflowScheduled) return;
898
+ overflowScheduled = true;
899
+ nextTick(() => {
900
+ overflowScheduled = false;
901
+ measureOverflow();
902
+ });
903
+ }
904
+ onMounted(() => {
905
+ scheduleOverflow();
906
+ if (typeof ResizeObserver === "undefined") return;
907
+ overflowObserver = new ResizeObserver(scheduleOverflow);
908
+ for (const side of ["source", "target"]) {
909
+ const el = listEls.value[side];
910
+ if (el) overflowObserver.observe(el);
911
+ }
912
+ });
913
+ onBeforeUnmount(() => {
914
+ overflowObserver?.disconnect();
915
+ overflowObserver = null;
916
+ });
917
+ watch([split, visible], scheduleOverflow);
918
+ /** Есть ли что переставлять: иначе кнопки в шапке гасятся, оставаясь в таб-порядке. */
919
+ const canReorder = computed(() => reorderAllowed.value && itemsOf("target").length > 1 && (movableOf("target").length > 0 || blockUnderFocus("target").length > 0));
920
+ /**
921
+ * Ключи, только что приехавшие в панель: подсветка живёт ~1.2 с и снимается сама.
922
+ * Таймер один на компонент — быстрый повторный перенос перезапускает его, а не
923
+ * копит хвосты.
924
+ */
925
+ const arrived = ref(/* @__PURE__ */ new Set());
926
+ let arrivedTimer = null;
927
+ function markArrived(keys) {
928
+ if (typeof window === "undefined") return;
929
+ arrived.value = new Set(keys);
930
+ if (arrivedTimer !== null) clearTimeout(arrivedTimer);
931
+ arrivedTimer = window.setTimeout(() => {
932
+ arrivedTimer = null;
933
+ arrived.value = /* @__PURE__ */ new Set();
934
+ }, 1200);
935
+ }
936
+ onBeforeUnmount(() => {
937
+ if (arrivedTimer !== null) clearTimeout(arrivedTimer);
938
+ });
939
+ const dragging = useTransferDrag({
940
+ disabled: () => isLocked.value || !resolvedDraggable.value,
941
+ visibleKeys: (side) => visibleKeys.value[side],
942
+ rowEl: (side, key) => rowsOf(side).get(key) ?? null,
943
+ panelEl: (side) => panelEls.value[side],
944
+ scrollerEl: (side) => listEls.value[side],
945
+ blockFor: (side, key) => {
946
+ if (!selectableOf(side)(key)) return [];
947
+ const chosen = movableOf(side);
948
+ return chosen.includes(key) ? chosen : [key];
949
+ },
950
+ allowSameSide: (side) => side === "target" && reorderAllowed.value,
951
+ onDrop: (session, spot) => {
952
+ const model = normalizeKeys(props.modelValue ?? []);
953
+ if (spot.side === session.side) {
954
+ reorder(spot.before, [...session.keys]);
955
+ return;
956
+ }
957
+ if (spot.side === "target") {
958
+ commit(insertKeys(model, [...session.keys], spot.before));
959
+ markArrived(session.keys);
960
+ emit("transfer", [...session.keys], "toTarget");
961
+ announce(t("gr.transfer.moved", "{count} moved to {list}", {
962
+ count: session.keys.length,
963
+ n: session.keys.length,
964
+ list: titles.value.target
965
+ }));
966
+ return;
967
+ }
968
+ commit(removeKeys(model, [...session.keys]));
969
+ markArrived(session.keys);
970
+ emit("transfer", [...session.keys], "toSource");
971
+ announce(t("gr.transfer.moved", "{count} moved to {list}", {
972
+ count: session.keys.length,
973
+ n: session.keys.length,
974
+ list: titles.value.source
975
+ }));
976
+ },
977
+ onCancel: () => announce(t("gr.transfer.cancelled", "Move cancelled"))
978
+ });
979
+ /**
980
+ * Вызов через обработчик, а не `@pointerdown="dragging.startFrom(...)"`: Vue
981
+ * считает такое выражение инлайн-инструкцией и возвращённую функцию
982
+ * выбрасывает — жест не начинался бы вовсе. Приём `GrSortableList`.
983
+ */
984
+ function onRowPointerDown(side, key, event) {
985
+ dragging.startFrom(side, key)(event);
986
+ }
987
+ /**
988
+ * Подпись переносимого. Первая строка блока названа, остальные — числом: список
989
+ * из десяти имён под курсором закрыл бы то самое место, куда человек целится.
990
+ */
991
+ const ghost = computed(() => {
992
+ const session = dragging.session.value;
993
+ if (!session || session.keys.length === 0) return null;
994
+ const first = itemsOf(session.side).find((item) => keyOf(item) === session.keys[0]);
995
+ return {
996
+ label: first ? labelOf(first) : String(session.keys[0]),
997
+ rest: session.keys.length - 1
998
+ };
999
+ });
1000
+ const ghostStyle = computed(() => ({ transform: `translate3d(${dragging.pointer.value.x + 12}px, ${dragging.pointer.value.y + 12}px, 0)` }));
1001
+ function indicatorFor(side, key) {
1002
+ const spot = dragging.spot.value;
1003
+ if (!spot || spot.side !== side) return null;
1004
+ if (spot.before === key) return "before";
1005
+ const keys = visibleKeys.value[side];
1006
+ return spot.before === null && keys[keys.length - 1] === key ? "after" : null;
1007
+ }
1008
+ function isDraggingKey(side, key) {
1009
+ const session = dragging.session.value;
1010
+ return session !== null && session.side === side && session.keys.includes(key);
1011
+ }
1012
+ function onOptionClick(side, key, event) {
1013
+ if (isDisabled.value || dragging.consumeClick()) return;
1014
+ rovingOf(side).setActive(key);
1015
+ setSelection(side, applySelect(selections.value[side], key, selectIntentFrom(event), visibleKeys.value[side], selectableOf(side)));
1016
+ }
1017
+ function extendRange(side, key) {
1018
+ setSelection(side, applySelect(selections.value[side], key, {
1019
+ mode: "range",
1020
+ additive: false
1021
+ }, visibleKeys.value[side], selectableOf(side)));
1022
+ }
1023
+ function onListKeydown(side, event) {
1024
+ if (isDisabled.value || visibleKeys.value[side].length === 0) return;
1025
+ const roving = rovingOf(side);
1026
+ const current = roving.rovingKey.value;
1027
+ if ((event.ctrlKey || event.metaKey) && (event.key === "a" || event.key === "A")) {
1028
+ event.preventDefault();
1029
+ toggleAll(side);
1030
+ return;
1031
+ }
1032
+ if (event.key === " ") {
1033
+ event.preventDefault();
1034
+ if (current === void 0) return;
1035
+ if (event.shiftKey) extendRange(side, current);
1036
+ else setSelection(side, applySelect(selections.value[side], current, {
1037
+ mode: "toggle",
1038
+ additive: true
1039
+ }, visibleKeys.value[side], selectableOf(side)));
1040
+ return;
1041
+ }
1042
+ if (event.key === "Enter") {
1043
+ event.preventDefault();
1044
+ transferSelected(side === "source" ? "toTarget" : "toSource");
1045
+ return;
1046
+ }
1047
+ if (side === "target" && event.altKey) {
1048
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
1049
+ event.preventDefault();
1050
+ moveBlock(event.key === "ArrowDown" ? 1 : -1);
1051
+ return;
1052
+ }
1053
+ if (event.key === "Home" || event.key === "End") {
1054
+ event.preventDefault();
1055
+ moveBlockToEdge(event.key === "Home" ? "start" : "end");
1056
+ return;
1057
+ }
1058
+ }
1059
+ if (!roving.handleNavigationKeys(event)) return;
1060
+ const next = roving.rovingKey.value;
1061
+ if (event.shiftKey && next !== void 0) extendRange(side, next);
1062
+ }
1063
+ function onSearchKeydown(side, event) {
1064
+ if (event.key !== "ArrowDown") return;
1065
+ const first = visibleKeys.value[side][0];
1066
+ if (first === void 0) return;
1067
+ event.preventDefault();
1068
+ rovingOf(side).focusKey(first);
1069
+ }
1070
+ function onSearch(side, value) {
1071
+ queries.value = {
1072
+ ...queries.value,
1073
+ [side]: value
1074
+ };
1075
+ emit("search", value, side);
1076
+ }
1077
+ const { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {
1078
+ enter: (event) => emit("focus", event),
1079
+ leave: (event) => emit("blur", event)
1080
+ });
1081
+ const panelStyle = computed(() => ({ maxHeight: props.maxHeight === void 0 ? "var(--gr-transfer-panel-max-h, 18rem)" : typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight }));
1082
+ function counterText(side) {
1083
+ return t("gr.transfer.selected", "{count} of {total}", {
1084
+ count: selections.value[side].keys.size,
1085
+ total: itemsOf(side).length
1086
+ });
1087
+ }
1088
+ function shownText(side) {
1089
+ return t("gr.transfer.shown", "Showing {shown} of {total}", {
1090
+ shown: visible.value[side].length,
1091
+ total: itemsOf(side).length
1092
+ });
1093
+ }
1094
+ function emptyText(side) {
1095
+ return normalizeOptionQuery(queries.value[side]) === "" ? t("gr.transfer.empty", "Nothing here yet") : t("gr.transfer.emptyFiltered", "Nothing matches the search");
1096
+ }
1097
+ function isFiltered(side) {
1098
+ return normalizeOptionQuery(queries.value[side]) !== "";
1099
+ }
1100
+ function allState(side) {
1101
+ return allVisibleState(selections.value[side], visibleKeys.value[side], selectableOf(side));
1102
+ }
1103
+ function focusSide(side) {
1104
+ const roving = rovingOf(side);
1105
+ const key = roving.rovingKey.value ?? visibleKeys.value[side][0];
1106
+ if (key !== void 0) {
1107
+ roving.focusKey(key);
1108
+ return;
1109
+ }
1110
+ searchEls.value[side]?.querySelector("input")?.focus();
1111
+ }
1112
+ __expose({
1113
+ focus: () => focusSide("target"),
1114
+ blur: () => {
1115
+ const active = document.activeElement;
1116
+ if (active instanceof HTMLElement && rootEl.value?.contains(active)) active.blur();
1117
+ },
1118
+ focusSide,
1119
+ transfer: (keys, direction) => void transfer(keys, direction),
1120
+ selectAll: (side) => toggleAll(side),
1121
+ clearSelection: (side) => {
1122
+ if (side) {
1123
+ setSelection(side, emptySelection);
1124
+ return;
1125
+ }
1126
+ selections.value = {
1127
+ source: emptySelection,
1128
+ target: emptySelection
1129
+ };
1130
+ }
1131
+ });
1132
+ return (_ctx, _cache) => {
1133
+ return openBlock(), createElementBlock("div", {
1134
+ ref_key: "rootEl",
1135
+ ref: rootEl,
1136
+ "data-gr-transfer": "",
1137
+ "data-dragging": unref(dragging).session.value ? "true" : void 0,
1138
+ role: "group",
1139
+ class: normalizeClass(unref(transferRootBase)),
1140
+ "aria-label": __props.ariaLabel,
1141
+ "aria-disabled": unref(isDisabled) ? "true" : void 0,
1142
+ onFocusin: _cache[4] || (_cache[4] = (...args) => unref(onFocusIn) && unref(onFocusIn)(...args)),
1143
+ onFocusout: _cache[5] || (_cache[5] = (...args) => unref(onFocusOut) && unref(onFocusOut)(...args))
1144
+ }, [
1145
+ (openBlock(), createElementBlock(Fragment, null, renderList(["source", "target"], (side) => {
1146
+ return createElementVNode("div", {
1147
+ key: side,
1148
+ ref_for: true,
1149
+ ref: (el) => {
1150
+ panelEls.value[side] = el;
1151
+ },
1152
+ "data-gr-transfer-panel": side,
1153
+ class: normalizeClass(unref(grTransferPanelClass)(unref(dragging).spot.value?.side === side)),
1154
+ style: normalizeStyle(panelStyle.value)
1155
+ }, [
1156
+ renderSlot(_ctx.$slots, "header", {
1157
+ side,
1158
+ title: titles.value[side],
1159
+ selected: selections.value[side].keys.size,
1160
+ total: itemsOf(side).length,
1161
+ shown: visible.value[side].length
1162
+ }, () => [createElementVNode("div", { class: normalizeClass(unref(grTransferHeaderClass)(unref(resolvedSize))) }, [
1163
+ visible.value[side].length > 0 ? (openBlock(), createBlock(unref(GrCheckbox_default), {
1164
+ key: 0,
1165
+ "model-value": allState(side) === "checked",
1166
+ indeterminate: allState(side) === "indeterminate",
1167
+ disabled: unref(isDisabled),
1168
+ size: unref(resolvedSize),
1169
+ "aria-label": unref(t)("gr.transfer.selectAll", "Select everything shown"),
1170
+ "onUpdate:modelValue": ($event) => toggleAll(side)
1171
+ }, null, 8, [
1172
+ "model-value",
1173
+ "indeterminate",
1174
+ "disabled",
1175
+ "size",
1176
+ "aria-label",
1177
+ "onUpdate:modelValue"
1178
+ ])) : createCommentVNode("", true),
1179
+ createElementVNode("span", {
1180
+ id: side === "source" ? sourceTitleId : targetTitleId,
1181
+ class: normalizeClass(unref(transferTitleClass))
1182
+ }, toDisplayString(titles.value[side]), 11, _hoisted_3),
1183
+ createElementVNode("span", { class: normalizeClass(unref(transferCounterClass)) }, toDisplayString(counterText(side)), 3),
1184
+ side === "target" && __props.sortable && visible.value[side].length > 1 ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("button", {
1185
+ type: "button",
1186
+ "data-gr-transfer-move-up": "",
1187
+ class: normalizeClass(unref(grTransferReorderClass)(unref(resolvedSize))),
1188
+ "aria-disabled": canReorder.value ? void 0 : "true",
1189
+ "aria-label": unref(t)("gr.transfer.moveUp", "Move earlier"),
1190
+ onClick: _cache[0] || (_cache[0] = ($event) => canReorder.value && moveBlock(-1))
1191
+ }, [createVNode(unref(arrow_left_default), {
1192
+ class: normalizeClass(unref(transferReorderIconClass)),
1193
+ "aria-hidden": "true"
1194
+ }, null, 8, ["class"])], 10, _hoisted_4), createElementVNode("button", {
1195
+ type: "button",
1196
+ "data-gr-transfer-move-down": "",
1197
+ class: normalizeClass(unref(grTransferReorderClass)(unref(resolvedSize))),
1198
+ "aria-disabled": canReorder.value ? void 0 : "true",
1199
+ "aria-label": unref(t)("gr.transfer.moveDown", "Move later"),
1200
+ onClick: _cache[1] || (_cache[1] = ($event) => canReorder.value && moveBlock(1))
1201
+ }, [createVNode(unref(arrow_right_default), {
1202
+ class: normalizeClass(unref(transferReorderIconClass)),
1203
+ "aria-hidden": "true"
1204
+ }, null, 8, ["class"])], 10, _hoisted_5)], 64)) : createCommentVNode("", true)
1205
+ ], 2)]),
1206
+ __props.searchable ? (openBlock(), createElementBlock("div", {
1207
+ key: 0,
1208
+ ref_for: true,
1209
+ ref: (el) => {
1210
+ searchEls.value[side] = el;
1211
+ },
1212
+ class: normalizeClass(unref(grTransferSearchClass)(unref(resolvedSize)))
1213
+ }, [createVNode(unref(GrInput_default), {
1214
+ "model-value": queries.value[side],
1215
+ type: "search",
1216
+ clearable: "",
1217
+ size: unref(resolvedSize),
1218
+ disabled: unref(isDisabled),
1219
+ placeholder: unref(t)("gr.transfer.search", "Search"),
1220
+ "aria-label": `${titles.value[side]} — ${unref(t)("gr.transfer.search", "Search")}`,
1221
+ "onUpdate:modelValue": (value) => onSearch(side, value),
1222
+ onKeydown: (event) => onSearchKeydown(side, event)
1223
+ }, null, 8, [
1224
+ "model-value",
1225
+ "size",
1226
+ "disabled",
1227
+ "placeholder",
1228
+ "aria-label",
1229
+ "onUpdate:modelValue",
1230
+ "onKeydown"
1231
+ ])], 2)) : createCommentVNode("", true),
1232
+ createElementVNode("p", {
1233
+ class: normalizeClass(unref(transferStatusClass)),
1234
+ role: "status",
1235
+ "aria-live": "polite"
1236
+ }, toDisplayString(isFiltered(side) ? shownText(side) : ""), 3),
1237
+ createElementVNode("div", {
1238
+ id: side === "source" ? sourceListId : unref(fieldId) ?? targetListId,
1239
+ ref_for: true,
1240
+ ref: (el) => {
1241
+ listEls.value[side] = el;
1242
+ },
1243
+ "data-gr-transfer-list": side,
1244
+ "data-overflow": listOverflow.value[side],
1245
+ role: "listbox",
1246
+ "aria-multiselectable": "true",
1247
+ class: normalizeClass(unref(transferListBase)),
1248
+ "aria-label": hasHeaderSlot.value ? titles.value[side] : void 0,
1249
+ "aria-labelledby": hasHeaderSlot.value ? side === "target" ? unref(fieldLabelId) : void 0 : side === "target" && unref(fieldLabelId) ? `${unref(fieldLabelId)} ${targetTitleId}` : side === "source" ? sourceTitleId : targetTitleId,
1250
+ "aria-describedby": side === "target" ? unref(describedBy) : void 0,
1251
+ "aria-invalid": side === "target" && unref(isInvalid) ? "true" : void 0,
1252
+ "aria-required": side === "target" && unref(isRequired) ? "true" : void 0,
1253
+ "aria-readonly": side === "target" && unref(isReadonly) ? "true" : void 0,
1254
+ "aria-disabled": unref(isDisabled) ? "true" : void 0,
1255
+ onKeydown: (event) => onListKeydown(side, event),
1256
+ onScrollPassive: scheduleOverflow
1257
+ }, [(openBlock(true), createElementBlock(Fragment, null, renderList(visible.value[side], (item, index) => {
1258
+ return openBlock(), createElementBlock("div", {
1259
+ key: keyOf(item),
1260
+ ref_for: true,
1261
+ ref: (el) => registerRow(side, keyOf(item), el),
1262
+ "data-gr-transfer-option": "",
1263
+ role: "option",
1264
+ "aria-selected": selections.value[side].keys.has(keyOf(item)) ? "true" : "false",
1265
+ "aria-disabled": disabledOf(item) ? "true" : void 0,
1266
+ tabindex: rovingOf(side).tabindexFor(keyOf(item)),
1267
+ class: normalizeClass(unref(grTransferOptionClass)({
1268
+ size: unref(resolvedSize),
1269
+ selected: selections.value[side].keys.has(keyOf(item)),
1270
+ disabled: disabledOf(item),
1271
+ draggable: unref(resolvedDraggable) && !unref(isLocked),
1272
+ dragging: isDraggingKey(side, keyOf(item)),
1273
+ arrived: arrived.value.has(keyOf(item)),
1274
+ indicator: indicatorFor(side, keyOf(item))
1275
+ })),
1276
+ onPointerdown: (event) => onRowPointerDown(side, keyOf(item), event),
1277
+ onClick: (event) => onOptionClick(side, keyOf(item), event),
1278
+ onFocus: ($event) => rovingOf(side).setActive(keyOf(item)),
1279
+ onDblclick: ($event) => !disabledOf(item) && transfer([keyOf(item)], side === "source" ? "toTarget" : "toSource")
1280
+ }, [createElementVNode("span", {
1281
+ "aria-hidden": "true",
1282
+ class: normalizeClass(unref(grTransferMarkClass)(unref(resolvedSize), selections.value[side].keys.has(keyOf(item))))
1283
+ }, [selections.value[side].keys.has(keyOf(item)) ? (openBlock(), createBlock(unref(check_default), {
1284
+ key: 0,
1285
+ class: normalizeClass(unref(transferMarkIconClass))
1286
+ }, null, 8, ["class"])) : createCommentVNode("", true)], 2), renderSlot(_ctx.$slots, "item", {
1287
+ item,
1288
+ side,
1289
+ index,
1290
+ selected: selections.value[side].keys.has(keyOf(item)),
1291
+ disabled: disabledOf(item)
1292
+ }, () => [createElementVNode("span", { class: normalizeClass(unref(transferLabelClass)) }, toDisplayString(labelOf(item)), 3)])], 42, _hoisted_7);
1293
+ }), 128))], 42, _hoisted_6),
1294
+ visible.value[side].length === 0 ? renderSlot(_ctx.$slots, "empty", {
1295
+ side,
1296
+ filtered: isFiltered(side)
1297
+ }, () => [createElementVNode("p", { class: normalizeClass(unref(grTransferEmptyClass)(unref(resolvedSize))) }, toDisplayString(emptyText(side)), 3)], void 0, 1) : createCommentVNode("", true)
1298
+ ], 14, _hoisted_2);
1299
+ }), 64)),
1300
+ (openBlock(), createBlock(Teleport, {
1301
+ to: unref(portalTarget),
1302
+ disabled: !unref(teleportEnabled)
1303
+ }, [ghost.value ? (openBlock(), createElementBlock("div", {
1304
+ key: 0,
1305
+ "data-gr-transfer-ghost": "",
1306
+ "aria-hidden": "true",
1307
+ class: normalizeClass(unref(transferGhostClass)),
1308
+ style: normalizeStyle(ghostStyle.value)
1309
+ }, [createElementVNode("span", { class: normalizeClass(unref(transferGhostLabelClass)) }, toDisplayString(ghost.value.label), 3), ghost.value.rest > 0 ? (openBlock(), createElementBlock("span", {
1310
+ key: 0,
1311
+ class: normalizeClass(unref(transferGhostCountClass))
1312
+ }, "+" + toDisplayString(ghost.value.rest), 3)) : createCommentVNode("", true)], 6)) : createCommentVNode("", true)], 8, ["to", "disabled"])),
1313
+ createElementVNode("div", {
1314
+ class: normalizeClass(unref(grTransferActionsClass)(unref(resolvedSize))),
1315
+ style: { "order": "1" }
1316
+ }, [renderSlot(_ctx.$slots, "actions", {
1317
+ toTarget: () => transferSelected("toTarget"),
1318
+ toSource: () => transferSelected("toSource"),
1319
+ canToTarget: canToTarget.value,
1320
+ canToSource: canToSource.value
1321
+ }, () => [createVNode(unref(GrButtonGroup_default), {
1322
+ orientation: "vertical",
1323
+ attached: "",
1324
+ size: unref(resolvedSize)
1325
+ }, {
1326
+ default: withCtx(() => [createVNode(unref(GrButton_default), {
1327
+ "data-gr-transfer-to-target": "",
1328
+ variant: "secondary",
1329
+ "aria-disabled": canToTarget.value ? void 0 : "true",
1330
+ class: normalizeClass(canToTarget.value ? "" : unref(transferActionInertClass)),
1331
+ "aria-label": unref(t)("gr.transfer.toTarget", "Move to selected"),
1332
+ onClick: _cache[2] || (_cache[2] = ($event) => canToTarget.value && transferSelected("toTarget"))
1333
+ }, {
1334
+ default: withCtx(() => [createVNode(unref(chevron_right_default), {
1335
+ class: normalizeClass(unref(transferActionIconClass)),
1336
+ "aria-hidden": "true"
1337
+ }, null, 8, ["class"])]),
1338
+ _: 1
1339
+ }, 8, [
1340
+ "aria-disabled",
1341
+ "class",
1342
+ "aria-label"
1343
+ ]), createVNode(unref(GrButton_default), {
1344
+ "data-gr-transfer-to-source": "",
1345
+ variant: "secondary",
1346
+ "aria-disabled": canToSource.value ? void 0 : "true",
1347
+ class: normalizeClass(canToSource.value ? "" : unref(transferActionInertClass)),
1348
+ "aria-label": unref(t)("gr.transfer.toSource", "Move back to available"),
1349
+ onClick: _cache[3] || (_cache[3] = ($event) => canToSource.value && transferSelected("toSource"))
1350
+ }, {
1351
+ default: withCtx(() => [createVNode(unref(chevron_left_default), {
1352
+ class: normalizeClass(unref(transferActionIconClass)),
1353
+ "aria-hidden": "true"
1354
+ }, null, 8, ["class"])]),
1355
+ _: 1
1356
+ }, 8, [
1357
+ "aria-disabled",
1358
+ "class",
1359
+ "aria-label"
1360
+ ])]),
1361
+ _: 1
1362
+ }, 8, ["size"])])], 2)
1363
+ ], 42, _hoisted_1);
1364
+ };
1365
+ }
1366
+ });
1367
+ //#endregion
1368
+ export { GrTransfer_default as t };