ropav 0.4.0 → 0.5.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 (253) hide show
  1. package/dist/components/autocomplete/autocomplete-root.js +3 -1
  2. package/dist/components/autocomplete/index.d.ts +3 -0
  3. package/dist/components/breadcrumbs/breadcrumbs-item.js +1 -0
  4. package/dist/components/breadcrumbs/index.d.ts +1 -0
  5. package/dist/components/calendar/index.d.ts +5 -3
  6. package/dist/components/calendar-year-picker/index.d.ts +4 -2
  7. package/dist/components/checkbox/checkbox-content.js +1 -1
  8. package/dist/components/color-field/index.d.ts +1 -0
  9. package/dist/components/color-input-group/color-input-group-root.js +2 -0
  10. package/dist/components/color-input-group/color-input-group.types.d.ts +2 -0
  11. package/dist/components/color-input-group/index.d.ts +2 -0
  12. package/dist/components/combo-box/combo-box-root.js +9 -2
  13. package/dist/components/combo-box/combo-box.types.d.ts +3 -0
  14. package/dist/components/combo-box/index.d.ts +3 -0
  15. package/dist/components/date-field/index.d.ts +1 -0
  16. package/dist/components/date-input-group/date-input-group-root.js +2 -0
  17. package/dist/components/date-input-group/date-input-group-segment.js +1 -1
  18. package/dist/components/date-input-group/date-input-group.types.d.ts +2 -0
  19. package/dist/{composables → components/date-input-group}/use-date-segment.d.ts +2 -2
  20. package/dist/{composables → components/date-input-group}/use-date-segment.js +9 -9
  21. package/dist/components/date-range-picker/date-range-picker-root.js +1 -1
  22. package/dist/components/date-range-picker/index.d.ts +15 -14
  23. package/dist/{composables → components/date-range-picker}/use-date-range-picker.d.ts +7 -7
  24. package/dist/{composables → components/date-range-picker}/use-date-range-picker.js +10 -10
  25. package/dist/components/drawer/drawer-dialog.js +1 -1
  26. package/dist/{composables → components/drawer}/use-drawer-drag.d.ts +1 -1
  27. package/dist/{composables → components/drawer}/use-drawer-drag.js +1 -1
  28. package/dist/components/dropdown/dropdown-menu.js +1 -0
  29. package/dist/components/dropdown/dropdown-submenu-trigger.js +1 -1
  30. package/dist/components/dropdown/index.d.ts +4 -2
  31. package/dist/{composables → components/dropdown}/use-safely-mouse-to-submenu.js +1 -1
  32. package/dist/components/icons/icon-overlay-arrow.js +1 -1
  33. package/dist/components/index.d.ts +4 -0
  34. package/dist/components/input/index.d.ts +2 -0
  35. package/dist/components/input/input-root.js +3 -0
  36. package/dist/components/input/input.types.d.ts +5 -0
  37. package/dist/components/input-group/index.d.ts +2 -0
  38. package/dist/components/input-group/input-group-root.js +3 -0
  39. package/dist/components/input-group/input-group.types.d.ts +5 -0
  40. package/dist/components/input-otp/index.d.ts +6 -4
  41. package/dist/components/link/index.d.ts +2 -0
  42. package/dist/components/link/link-root.js +22 -5
  43. package/dist/components/link/link.types.d.ts +14 -3
  44. package/dist/{composables → components/list-box}/drag-collection.d.ts +2 -2
  45. package/dist/{composables → components/list-box}/drag-collection.js +1 -1
  46. package/dist/components/list-box/index.d.ts +4 -0
  47. package/dist/components/list-box/list-box-root.js +53 -32
  48. package/dist/components/list-box/list-box.types.d.ts +2 -0
  49. package/dist/components/menu/index.d.ts +2 -0
  50. package/dist/components/menu/menu-root.js +5 -1
  51. package/dist/components/menu/menu.types.d.ts +3 -0
  52. package/dist/components/number-field/index.d.ts +3 -0
  53. package/dist/components/number-field/number-field-root.js +2 -0
  54. package/dist/components/number-field/number-field.types.d.ts +2 -0
  55. package/dist/components/overlay/overlay-arrow.js +64 -11
  56. package/dist/components/radio/radio-content.js +1 -1
  57. package/dist/components/range-calendar/index.d.ts +18 -15
  58. package/dist/components/router-provider/index.d.ts +5 -0
  59. package/dist/components/router-provider/index.js +3 -0
  60. package/dist/components/router-provider/router-provider.context.d.ts +40 -0
  61. package/dist/components/router-provider/router-provider.context.js +16 -0
  62. package/dist/components/router-provider/router-provider.d.ts +21 -0
  63. package/dist/components/router-provider/router-provider.js +22 -0
  64. package/dist/components/router-provider/router-provider.types.d.ts +23 -0
  65. package/dist/components/scroll-shadow/use-scroll-shadow.js +25 -1
  66. package/dist/components/search-field/index.d.ts +2 -0
  67. package/dist/components/search-field/search-field-root.js +3 -1
  68. package/dist/components/search-field/search-field.types.d.ts +2 -0
  69. package/dist/{composables → components/search-field}/use-search-field.d.ts +2 -2
  70. package/dist/{composables → components/search-field}/use-search-field.js +3 -3
  71. package/dist/components/segmented-control/index.d.ts +134 -0
  72. package/dist/components/segmented-control/index.js +15 -0
  73. package/dist/components/segmented-control/segmented-control-indicator.d.ts +19 -0
  74. package/dist/components/segmented-control/segmented-control-indicator.js +36 -0
  75. package/dist/components/segmented-control/segmented-control-item.d.ts +21 -0
  76. package/dist/components/segmented-control/segmented-control-item.js +96 -0
  77. package/dist/components/segmented-control/segmented-control-root.d.ts +25 -0
  78. package/dist/components/segmented-control/segmented-control-root.js +112 -0
  79. package/dist/components/segmented-control/segmented-control-separator.d.ts +19 -0
  80. package/dist/components/segmented-control/segmented-control-separator.js +18 -0
  81. package/dist/components/segmented-control/segmented-control.context.d.ts +17 -0
  82. package/dist/components/segmented-control/segmented-control.context.js +12 -0
  83. package/dist/components/segmented-control/segmented-control.types.d.ts +67 -0
  84. package/dist/components/select/index.d.ts +3 -0
  85. package/dist/components/select/select-hidden-select.js +1 -1
  86. package/dist/components/select/select-root.js +2 -0
  87. package/dist/components/select/select.types.d.ts +2 -0
  88. package/dist/components/sidebar/index.d.ts +544 -0
  89. package/dist/components/sidebar/index.js +47 -0
  90. package/dist/components/sidebar/sidebar-collapsible-trigger.d.ts +21 -0
  91. package/dist/components/sidebar/sidebar-collapsible-trigger.js +70 -0
  92. package/dist/components/sidebar/sidebar-collapsible.d.ts +24 -0
  93. package/dist/components/sidebar/sidebar-collapsible.js +78 -0
  94. package/dist/components/sidebar/sidebar-content.d.ts +21 -0
  95. package/dist/components/sidebar/sidebar-content.js +37 -0
  96. package/dist/components/sidebar/sidebar-footer.d.ts +21 -0
  97. package/dist/components/sidebar/sidebar-footer.js +24 -0
  98. package/dist/components/sidebar/sidebar-group-label.d.ts +21 -0
  99. package/dist/components/sidebar/sidebar-group-label.js +32 -0
  100. package/dist/components/sidebar/sidebar-group.d.ts +21 -0
  101. package/dist/components/sidebar/sidebar-group.js +48 -0
  102. package/dist/components/sidebar/sidebar-header.d.ts +21 -0
  103. package/dist/components/sidebar/sidebar-header.js +24 -0
  104. package/dist/components/sidebar/sidebar-inset.d.ts +21 -0
  105. package/dist/components/sidebar/sidebar-inset.js +24 -0
  106. package/dist/components/sidebar/sidebar-item-icon.d.ts +21 -0
  107. package/dist/components/sidebar/sidebar-item-icon.js +20 -0
  108. package/dist/components/sidebar/sidebar-item-indicator.d.ts +21 -0
  109. package/dist/components/sidebar/sidebar-item-indicator.js +48 -0
  110. package/dist/components/sidebar/sidebar-item-label.d.ts +21 -0
  111. package/dist/components/sidebar/sidebar-item-label.js +28 -0
  112. package/dist/components/sidebar/sidebar-item-tooltip.d.ts +21 -0
  113. package/dist/components/sidebar/sidebar-item-tooltip.js +38 -0
  114. package/dist/components/sidebar/sidebar-item-trailing.d.ts +21 -0
  115. package/dist/components/sidebar/sidebar-item-trailing.js +28 -0
  116. package/dist/components/sidebar/sidebar-item.d.ts +23 -0
  117. package/dist/components/sidebar/sidebar-item.js +160 -0
  118. package/dist/components/sidebar/sidebar-panel.d.ts +21 -0
  119. package/dist/components/sidebar/sidebar-panel.js +88 -0
  120. package/dist/components/sidebar/sidebar-rail.d.ts +21 -0
  121. package/dist/components/sidebar/sidebar-rail.js +210 -0
  122. package/dist/components/sidebar/sidebar-root.d.ts +31 -0
  123. package/dist/components/sidebar/sidebar-root.js +138 -0
  124. package/dist/components/sidebar/sidebar-separator.d.ts +19 -0
  125. package/dist/components/sidebar/sidebar-separator.js +16 -0
  126. package/dist/components/sidebar/sidebar-sub-menu.d.ts +23 -0
  127. package/dist/components/sidebar/sidebar-sub-menu.js +40 -0
  128. package/dist/components/sidebar/sidebar-trigger.d.ts +21 -0
  129. package/dist/components/sidebar/sidebar-trigger.js +69 -0
  130. package/dist/components/sidebar/sidebar.context.d.ts +75 -0
  131. package/dist/components/sidebar/sidebar.context.js +30 -0
  132. package/dist/components/sidebar/sidebar.state.d.ts +73 -0
  133. package/dist/components/sidebar/sidebar.state.js +76 -0
  134. package/dist/components/sidebar/sidebar.storage.d.ts +8 -0
  135. package/dist/components/sidebar/sidebar.storage.js +45 -0
  136. package/dist/components/sidebar/sidebar.types.d.ts +259 -0
  137. package/dist/components/splitter/index.d.ts +143 -0
  138. package/dist/components/splitter/index.js +13 -0
  139. package/dist/components/splitter/splitter-handle.d.ts +21 -0
  140. package/dist/components/splitter/splitter-handle.js +209 -0
  141. package/dist/components/splitter/splitter-panel.d.ts +21 -0
  142. package/dist/components/splitter/splitter-panel.js +70 -0
  143. package/dist/components/splitter/splitter-root.d.ts +31 -0
  144. package/dist/components/splitter/splitter-root.js +152 -0
  145. package/dist/components/splitter/splitter.context.d.ts +15 -0
  146. package/dist/components/splitter/splitter.context.js +5 -0
  147. package/dist/components/splitter/splitter.state.d.ts +87 -0
  148. package/dist/components/splitter/splitter.state.js +322 -0
  149. package/dist/components/splitter/splitter.storage.d.ts +15 -0
  150. package/dist/components/splitter/splitter.storage.js +56 -0
  151. package/dist/components/splitter/splitter.types.d.ts +98 -0
  152. package/dist/components/switch/switch-content.js +1 -1
  153. package/dist/components/table/index.d.ts +10 -9
  154. package/dist/components/table/table-body.js +13 -13
  155. package/dist/components/table/table-cell.js +49 -46
  156. package/dist/components/table/table-column-resizer.js +1 -1
  157. package/dist/components/table/table-column.js +1 -1
  158. package/dist/components/table/table-content.js +37 -18
  159. package/dist/{composables → components/table}/table-drag-collection.d.ts +1 -1
  160. package/dist/{composables → components/table}/table-drag-collection.js +1 -1
  161. package/dist/components/table/table-drop-indicator.js +3 -1
  162. package/dist/components/table/table-resizable-container.d.ts +4 -5
  163. package/dist/components/table/table-row.js +45 -14
  164. package/dist/components/table/table-virtualizer-item.d.ts +2 -7
  165. package/dist/components/table/table-virtualizer-item.js +20 -9
  166. package/dist/components/table/table.context.d.ts +11 -3
  167. package/dist/components/table/table.types.d.ts +1 -1
  168. package/dist/{composables → components/table}/use-grid-keyboard.d.ts +3 -3
  169. package/dist/{composables → components/table}/use-grid-keyboard.js +57 -55
  170. package/dist/{composables → components/table}/use-grid-selection-announcement.d.ts +2 -2
  171. package/dist/{composables → components/table}/use-grid-selection-announcement.js +2 -2
  172. package/dist/{composables → components/table}/use-table-collection.d.ts +2 -2
  173. package/dist/{composables → components/table}/use-table-collection.js +4 -4
  174. package/dist/{composables → components/table}/use-table-column-layout.d.ts +13 -20
  175. package/dist/components/table/use-table-column-layout.js +115 -0
  176. package/dist/components/textarea/index.d.ts +2 -0
  177. package/dist/components/textarea/textarea-root.js +3 -0
  178. package/dist/components/textarea/textarea.types.d.ts +5 -0
  179. package/dist/components/textfield/index.d.ts +2 -0
  180. package/dist/components/textfield/textfield-root.js +5 -1
  181. package/dist/components/textfield/textfield.context.d.ts +2 -0
  182. package/dist/components/textfield/textfield.types.d.ts +5 -0
  183. package/dist/components/time-field/index.d.ts +1 -0
  184. package/dist/components/toast/index.d.ts +1 -0
  185. package/dist/components/toast/toast-default-content.js +1 -1
  186. package/dist/components/toolbar/index.d.ts +3 -2
  187. package/dist/components/tooltip/index.js +1 -1
  188. package/dist/components/tooltip/tooltip-root.js +1 -1
  189. package/dist/components/virtualizer/index.d.ts +3 -1
  190. package/dist/components/virtualizer/index.js +2 -1
  191. package/dist/components/virtualizer/use-virtualizer-item.d.ts +23 -0
  192. package/dist/components/virtualizer/use-virtualizer-item.js +45 -0
  193. package/dist/components/virtualizer/virtualizer-item.js +7 -41
  194. package/dist/components/virtualizer/virtualizer-scrollbar-track.d.ts +20 -0
  195. package/dist/components/virtualizer/virtualizer-scrollbar-track.js +141 -0
  196. package/dist/components/virtualizer/virtualizer-scrollbar.d.ts +18 -0
  197. package/dist/components/virtualizer/virtualizer-scrollbar.js +55 -0
  198. package/dist/components/virtualizer/virtualizer.context.d.ts +17 -1
  199. package/dist/composables/drag-manager.js +1 -13
  200. package/dist/composables/index.d.ts +3 -71
  201. package/dist/composables/use-collection.d.ts +22 -3
  202. package/dist/composables/use-collection.js +67 -14
  203. package/dist/composables/use-color-area.js +2 -2
  204. package/dist/composables/use-color-field.js +1 -1
  205. package/dist/composables/use-combo-box.js +1 -1
  206. package/dist/composables/use-date-field.js +1 -1
  207. package/dist/composables/use-drag-and-drop.js +1 -1
  208. package/dist/composables/use-drag.d.ts +6 -5
  209. package/dist/composables/use-draggable-item.d.ts +2 -2
  210. package/dist/composables/use-droppable-collection.js +2 -2
  211. package/dist/composables/use-droppable-item.js +1 -1
  212. package/dist/composables/use-form-reset.d.ts +6 -2
  213. package/dist/composables/use-form-reset.js +9 -5
  214. package/dist/composables/use-list-keyboard.js +64 -62
  215. package/dist/composables/use-number-field.js +1 -1
  216. package/dist/composables/use-select.js +2 -2
  217. package/dist/composables/use-selection-manager.js +4 -4
  218. package/dist/composables/use-single-select-list-state.d.ts +37 -0
  219. package/dist/composables/use-single-select-list-state.js +110 -0
  220. package/dist/composables/use-slider-thumb.js +2 -2
  221. package/dist/composables/use-slider.js +1 -1
  222. package/dist/composables/use-tab-list-state.d.ts +10 -29
  223. package/dist/composables/use-tab-list-state.js +10 -99
  224. package/dist/composables/use-text-field.js +1 -1
  225. package/dist/composables/use-virtualizer-scroll.d.ts +52 -2
  226. package/dist/composables/use-virtualizer-scroll.js +79 -13
  227. package/dist/composables/use-virtualizer.d.ts +24 -4
  228. package/dist/composables/use-virtualizer.js +40 -6
  229. package/dist/index.js +52 -80
  230. package/dist/utils/document-order.d.ts +14 -0
  231. package/dist/utils/document-order.js +17 -0
  232. package/dist/utils/flex-sizing.d.ts +41 -0
  233. package/dist/utils/flex-sizing.js +140 -0
  234. package/dist/utils/index.d.ts +2 -0
  235. package/dist/utils/open-link.d.ts +31 -0
  236. package/dist/utils/open-link.js +32 -0
  237. package/dist/utils/story-truncation.d.ts +20 -0
  238. package/dist/utils/story-users.d.ts +11 -0
  239. package/dist/utils/virtualizer-collection.d.ts +14 -4
  240. package/dist/utils/virtualizer-collection.js +9 -14
  241. package/dist/utils/virtualizer-layout-info.js +3 -2
  242. package/dist/utils/virtualizer-list-layout.d.ts +75 -29
  243. package/dist/utils/virtualizer-list-layout.js +182 -99
  244. package/dist/utils/virtualizer-offsets.d.ts +111 -0
  245. package/dist/utils/virtualizer-offsets.js +159 -0
  246. package/dist/utils/virtualizer-overscan.d.ts +9 -15
  247. package/dist/utils/virtualizer-overscan.js +14 -33
  248. package/dist/utils/virtualizer-table-layout.d.ts +50 -21
  249. package/dist/utils/virtualizer-table-layout.js +130 -89
  250. package/dist/version.js +1 -1
  251. package/package.json +19 -3
  252. package/dist/composables/use-table-column-layout.js +0 -214
  253. /package/dist/{composables → components/dropdown}/use-safely-mouse-to-submenu.d.ts +0 -0
@@ -1,7 +1,7 @@
1
+ import { useMove } from "./use-move.js";
1
2
  import { useFormReset } from "./use-form-reset.js";
2
3
  import { setFormValue } from "../utils/form-value.js";
3
4
  import { clamp } from "../utils/number.js";
4
- import { useMove } from "./use-move.js";
5
5
  import { computed, nextTick, onScopeDispose, toValue, watch, watchEffect } from "vue";
6
6
  //#region src/composables/use-slider-thumb.ts
7
7
  /**
@@ -110,7 +110,7 @@ var useSliderThumb = (options) => {
110
110
  nextTick(() => {
111
111
  setFormValue(inputEl.value, String(state.getThumbValue(index.value)));
112
112
  });
113
- });
113
+ }, options.form);
114
114
  watch([inputEl, () => state.getThumbValue(index.value)], ([input, value]) => setFormValue(input, String(value)), {
115
115
  flush: "post",
116
116
  immediate: true
@@ -1,6 +1,6 @@
1
1
  import { setInteractionModality } from "./use-interaction-states.js";
2
- import { clamp } from "../utils/number.js";
3
2
  import { useMove } from "./use-move.js";
3
+ import { clamp } from "../utils/number.js";
4
4
  import { computed, onScopeDispose, toValue } from "vue";
5
5
  //#region src/composables/use-slider.ts
6
6
  /**
@@ -1,25 +1,11 @@
1
- import type { CollectionKey, UseCollectionReturn } from "./use-collection.js";
2
- import type { UseSelectionManagerReturn } from "./use-selection-manager.js";
1
+ import type { CollectionKey } from "./use-collection.js";
2
+ import type { UseSingleSelectListStateOptions, UseSingleSelectListStateReturn } from "./use-single-select-list-state.js";
3
3
  import type { ComputedRef, MaybeRefOrGetter } from "vue";
4
- export interface UseTabListStateOptions {
5
- /** The selected tab, when the caller drives it. */
6
- selectedKey?: MaybeRefOrGetter<CollectionKey | undefined>;
7
- /** The initially selected tab. Falls back to the first tab that is not disabled. */
8
- defaultSelectedKey?: CollectionKey;
9
- onSelectionChange?: (key: CollectionKey) => void;
10
- disabledKeys?: MaybeRefOrGetter<Iterable<CollectionKey> | undefined>;
11
- /** Whether the whole tab list is disabled: a selection that exists but cannot be changed. */
12
- isDisabled?: MaybeRefOrGetter<boolean | undefined>;
4
+ export interface UseTabListStateOptions extends UseSingleSelectListStateOptions {
13
5
  /** A base the tab and panel ids are derived from. Generated when absent. */
14
6
  id?: MaybeRefOrGetter<string | undefined>;
15
7
  }
16
- export interface UseTabListStateReturn {
17
- collection: UseCollectionReturn;
18
- selection: UseSelectionManagerReturn;
19
- /** The selected tab, with the default resolved against the collection. */
20
- selectedKey: ComputedRef<CollectionKey | null>;
21
- setSelectedKey: (key: CollectionKey) => void;
22
- isDisabled: ComputedRef<boolean>;
8
+ export interface UseTabListStateReturn extends UseSingleSelectListStateReturn {
23
9
  /** The tab list's own id, which the tab and panel ids hang off. */
24
10
  tabsId: ComputedRef<string>;
25
11
  /** `undefined` for a key that does not exist, so no attribute points at nothing. */
@@ -39,17 +25,12 @@ export interface UseTabListStateReturn {
39
25
  /**
40
26
  * Which tab is selected, and the ids that tie each tab to its panel.
41
27
  *
42
- * Ported from React Stately's `useTabListState` and the `useSingleSelectListState` layer beneath
43
- * it (`react-stately/src/tabs/useTabListState.ts`, react-stately 3.49.0), together with the id
44
- * scheme from `react-aria/src/tabs/utils.ts` (react-aria 3.51.0).
28
+ * Ported from React Stately's `useTabListState` (`react-stately/src/tabs/useTabListState.ts`,
29
+ * react-stately 3.49.0), together with the id scheme from `react-aria/src/tabs/utils.ts`
30
+ * (react-aria 3.51.0).
45
31
  *
46
- * A tab list always has exactly one tab selected, which is `disallowEmptySelection` plus a
47
- * fallback for the case where nothing says which. The selection behaviour is deliberately left at
48
- * toggle: whether the arrow keys choose is a question about how activation works, asked by the
49
- * caller through `selectOnFocus`, not a question about what a press means.
50
- *
51
- * The three pieces have to be built in one order — the collection, then the fallback that reads
52
- * it, then the selection manager the fallback feeds — which is the reason this is a composable
53
- * rather than a few lines in the root component.
32
+ * The selection itself is {@link useSingleSelectListState}, the layer React Stately builds this
33
+ * one on. What is left here is what makes a tab list a tab list rather than any other list with
34
+ * one selection: the ids, and the panels they point at.
54
35
  */
55
36
  export declare const useTabListState: (options?: UseTabListStateOptions) => UseTabListStateReturn;
@@ -1,113 +1,27 @@
1
1
  import { useId as useId$1 } from "./use-id.js";
2
- import { useControllableState } from "./use-controllable-state.js";
3
- import { useCollection } from "./use-collection.js";
4
- import { useSelectionManager } from "./use-selection-manager.js";
5
- import { computed, shallowRef, toValue, watch } from "vue";
2
+ import { useSingleSelectListState } from "./use-single-select-list-state.js";
3
+ import { shallowRef, toValue } from "vue";
6
4
  //#region src/composables/use-tab-list-state.ts
7
5
  /**
8
6
  * Which tab is selected, and the ids that tie each tab to its panel.
9
7
  *
10
- * Ported from React Stately's `useTabListState` and the `useSingleSelectListState` layer beneath
11
- * it (`react-stately/src/tabs/useTabListState.ts`, react-stately 3.49.0), together with the id
12
- * scheme from `react-aria/src/tabs/utils.ts` (react-aria 3.51.0).
8
+ * Ported from React Stately's `useTabListState` (`react-stately/src/tabs/useTabListState.ts`,
9
+ * react-stately 3.49.0), together with the id scheme from `react-aria/src/tabs/utils.ts`
10
+ * (react-aria 3.51.0).
13
11
  *
14
- * A tab list always has exactly one tab selected, which is `disallowEmptySelection` plus a
15
- * fallback for the case where nothing says which. The selection behaviour is deliberately left at
16
- * toggle: whether the arrow keys choose is a question about how activation works, asked by the
17
- * caller through `selectOnFocus`, not a question about what a press means.
18
- *
19
- * The three pieces have to be built in one order — the collection, then the fallback that reads
20
- * it, then the selection manager the fallback feeds — which is the reason this is a composable
21
- * rather than a few lines in the root component.
12
+ * The selection itself is {@link useSingleSelectListState}, the layer React Stately builds this
13
+ * one on. What is left here is what makes a tab list a tab list rather than any other list with
14
+ * one selection: the ids, and the panels they point at.
22
15
  */
23
16
  var useTabListState = (options = {}) => {
24
- const collection = useCollection();
25
- const disabledKeySet = computed(() => new Set(toValue(options.disabledKeys) ?? []));
26
- /**
27
- * Whether a tab can be selected, asked of the collection rather than of the selection manager.
28
- *
29
- * Two reasons, and either alone would be enough: the fallback below runs before the manager
30
- * exists, and React Stately asks the same question the same way — an item's own disabled state
31
- * or the group's disabled keys, with no `disabledBehavior` in it.
32
- */
33
- const isKeyDisabled = (key) => disabledKeySet.value.has(key) || Boolean(collection.getItem(key)?.isDisabled());
34
- /** The first tab that can be selected, or the first tab when none of them can. */
35
- const findDefaultSelectedKey = () => {
36
- let key = collection.getFirstKey();
37
- while (key != null && isKeyDisabled(key) && key !== collection.getLastKey()) key = collection.getKeyAfter(key);
38
- if (key != null && isKeyDisabled(key) && key === collection.getLastKey()) key = collection.getFirstKey();
39
- return key;
40
- };
41
- const stored = useControllableState({
42
- defaultValue: options.defaultSelectedKey ?? null,
43
- onValueChange: (key) => {
44
- if (key != null) options.onSelectionChange?.(key);
45
- },
46
- value: () => toValue(options.selectedKey)
47
- });
48
- /**
49
- * The selected tab, with the fallback resolved as a read rather than written back.
50
- *
51
- * React Stately can resolve it before the first render, because the collection is built by a
52
- * pass that runs before it. Rendering is what creates the collection here, so writing the
53
- * fallback into the selection would report a selection change nobody made, on every mount of
54
- * every uncontrolled tab list.
55
- *
56
- * `collection.size` is read for its own sake: the fallback walks the collection through
57
- * calls that stay outside reactivity on purpose, so without it this would resolve against the
58
- * empty collection of the first render and keep that answer.
59
- */
60
- const selectedKey = computed(() => {
61
- const key = stored.state.value;
62
- if (stored.isControlled.value) return key ?? null;
63
- if (key != null && collection.getItem(key)) return key;
64
- return findDefaultSelectedKey();
65
- });
66
- const selection = useSelectionManager({
67
- collection,
68
- disabledKeys: () => toValue(options.disabledKeys),
69
- disallowEmptySelection: true,
70
- onSelectionChange: (keys) => {
71
- if (keys === "all") return;
72
- const [key] = [...keys];
73
- if (key != null) stored.setState(key);
74
- },
75
- selectedKeys: () => selectedKey.value != null ? [selectedKey.value] : [],
76
- selectionMode: "single"
77
- });
78
- let lastSelectedKey = selectedKey.value;
79
- /**
80
- * The selection places focus, because on a tab list it is the only thing that can.
81
- *
82
- * React Aria's tab list element ends up with no tab index of its own, so the roving index on
83
- * the selected tab is the only way in — and with no focused key nothing inside is tabbable
84
- * either, which would put the whole tab list out of the tab order.
85
- *
86
- * Post-flush and keyed on the collection's size, because setting a focused key the collection
87
- * does not hold is refused: the first attempt runs before the tabs have registered, and the
88
- * registration is what makes the retry land.
89
- */
90
- watch([
91
- selectedKey,
92
- collection.size,
93
- () => selection.focusedKey.value == null
94
- ], () => {
95
- const key = selectedKey.value;
96
- if (key == null) return;
97
- if (selection.focusedKey.value == null || !selection.isFocused.value && key !== lastSelectedKey) selection.setFocusedKey(key);
98
- lastSelectedKey = key;
99
- }, {
100
- flush: "post",
101
- immediate: true
102
- });
17
+ const list = useSingleSelectListState(options);
103
18
  const tabsId = useId$1(() => toValue(options.id));
104
19
  /** React Aria strips whitespace out of a string key so the id stays a single token. */
105
20
  const idFor = (key, role) => key == null ? void 0 : `${tabsId.value}-${role}-${String(key).replace(/\s+/g, "")}`;
106
21
  const panelKeys = shallowRef(/* @__PURE__ */ new Set());
107
22
  return {
108
- collection,
23
+ ...list,
109
24
  hasPanel: (key) => key != null && panelKeys.value.has(key),
110
- isDisabled: computed(() => Boolean(toValue(options.isDisabled))),
111
25
  registerPanel: (key) => {
112
26
  panelKeys.value = new Set(panelKeys.value).add(key);
113
27
  return () => {
@@ -116,9 +30,6 @@ var useTabListState = (options = {}) => {
116
30
  panelKeys.value = next;
117
31
  };
118
32
  },
119
- selectedKey,
120
- selection,
121
- setSelectedKey: (key) => stored.setState(key),
122
33
  tabId: (key) => idFor(key, "tab"),
123
34
  tabPanelId: (key) => idFor(key, "tabpanel"),
124
35
  tabsId
@@ -91,7 +91,7 @@ var useTextField = (options = {}) => {
91
91
  reassert();
92
92
  };
93
93
  const initialValue = value.value;
94
- if (!options.skipFormReset) useFormReset(element, () => toValue(options.defaultValue) ?? initialValue, setState);
94
+ if (!options.skipFormReset) useFormReset(element, () => toValue(options.defaultValue) ?? initialValue, setState, options.form);
95
95
  useFormValidation(element, validation, { commitOnBlur: () => toValue(options.commitOnBlur) });
96
96
  watch(element, (control, previous) => {
97
97
  if (control && !previous && toValue(options.autoFocus)) control.focus();
@@ -1,22 +1,72 @@
1
1
  import type { Size } from "../utils/virtualizer-geometry.js";
2
2
  import type { ComputedRef, MaybeRefOrGetter } from "vue";
3
- import { Rect } from "../utils/virtualizer-geometry.js";
3
+ import { Point, Rect } from "../utils/virtualizer-geometry.js";
4
4
  export interface UseVirtualizerScrollOptions {
5
5
  /** The element that scrolls — the collection itself. */
6
6
  element: MaybeRefOrGetter<HTMLElement | null | undefined>;
7
- /** The size of everything the layout produced, used to clamp an over-scroll. */
7
+ /** The size of everything the layout produced, which is what gives the container its scroll. */
8
8
  contentSize: () => Size;
9
9
  /** Whether the collection is mid-scroll, which the content wrapper turns off pointers for. */
10
10
  isScrolling: () => boolean;
11
11
  onVisibleRectChange: (rect: Rect) => void;
12
12
  onSizeChange: (size: Size) => void;
13
+ /**
14
+ * How far rows measured above the window have pushed the content under it, and a way to say the
15
+ * shift has been applied.
16
+ *
17
+ * Rows of a height nobody declared are placed at an estimate and corrected once they are in the
18
+ * DOM. A correction above the window moves everything below it — so without putting the shift
19
+ * back into the scroll offset, the collection slides under the pointer while it is read.
20
+ */
21
+ scrollAdjustment?: () => number;
22
+ takeScrollAdjustment?: () => number;
13
23
  onScrollStart?: () => void;
14
24
  onScrollEnd?: () => void;
15
25
  }
26
+ /** Where to scroll the container to. An axis left out stays where it is. */
27
+ export interface ScrollToOffset {
28
+ left?: number;
29
+ top?: number;
30
+ }
31
+ /** What the container's own style says about it, as far as a scrollbar drawn for it has to know. */
32
+ export interface ScrollBoxInfo {
33
+ /** Which way the inline axis runs, which decides which edge the content starts at. */
34
+ direction: "ltr" | "rtl";
35
+ /** How far the content sits in from the container's top edge. */
36
+ paddingTop: number;
37
+ /** How far the content sits in from the container's inline start edge. */
38
+ paddingInlineStart: number;
39
+ /** Whether the container scrolls along the inline axis, rather than clipping or letting content out. */
40
+ scrollsX: boolean;
41
+ /** Whether the container scrolls along the block axis. */
42
+ scrollsY: boolean;
43
+ }
16
44
  export interface UseVirtualizerScrollReturn {
17
45
  /** The style for the wrapper that gives the container something to scroll. */
18
46
  contentStyle: ComputedRef<Record<string, string | undefined>>;
19
47
  /** Re-measures the container. Called on mount, on resize, and by tests. */
20
48
  measure: () => void;
49
+ /** The container's padding and which of its axes scroll, read whenever it is measured. */
50
+ scrollBox: ComputedRef<ScrollBoxInfo>;
51
+ /**
52
+ * How far the container is scrolled, as the element reports it.
53
+ *
54
+ * Along the block axis the offset is clamped into the content, as the visible rectangle is.
55
+ * Along the inline axis it keeps its sign: a right-to-left box scrolls into negative offsets,
56
+ * and a scrollbar drawn for it has to know which way the content ran.
57
+ */
58
+ scrollOffset: ComputedRef<Point>;
59
+ /** The container's scrollable overflow, per axis — what the offset runs up to, less the box. */
60
+ scrollSize: ComputedRef<Size>;
61
+ /**
62
+ * Scrolls the container from here, and moves the window in the same task.
63
+ *
64
+ * A scroll the browser makes on its own reaches this composable a frame after the offset moved,
65
+ * and the compositor has already drawn that frame with the rows built for the old offset. A
66
+ * scroll made here is read back at once, so the offset and the rows it calls for are committed
67
+ * by the same frame — which is what lets a scrollbar the collection draws itself never show an
68
+ * empty window.
69
+ */
70
+ scrollTo: (offset: ScrollToOffset) => void;
21
71
  }
22
72
  export declare const useVirtualizerScroll: (options: UseVirtualizerScrollOptions) => UseVirtualizerScrollReturn;
@@ -1,5 +1,5 @@
1
1
  import { Point, Rect, Size } from "../utils/virtualizer-geometry.js";
2
- import { computed, onScopeDispose, toValue, watch } from "vue";
2
+ import { computed, onScopeDispose, shallowRef, toValue, watch } from "vue";
3
3
  //#region src/composables/use-virtualizer-scroll.ts
4
4
  /**
5
5
  * Measuring the scroll container a virtualizer lives in, ported from React Aria's `useScrollView`.
@@ -30,8 +30,44 @@ var useVirtualizerScroll = (options) => {
30
30
  viewportOffset: new Point(),
31
31
  viewportSize: new Size()
32
32
  };
33
+ const scrollOffset = shallowRef(new Point());
34
+ const scrollSize = shallowRef(new Size());
35
+ const scrollBox = shallowRef({
36
+ direction: "ltr",
37
+ paddingInlineStart: 0,
38
+ paddingTop: 0,
39
+ scrollsX: false,
40
+ scrollsY: false
41
+ });
33
42
  let isMeasuring = false;
34
43
  const getElement = () => toValue(options.element) ?? null;
44
+ /** Whether an overflow value is one the browser scrolls, rather than clips or lets out. */
45
+ const scrolls = (overflow) => overflow === "auto" || overflow === "scroll" || overflow === "overlay";
46
+ /** Reads what the container's style says about it, for the scrollbar drawn against it. */
47
+ const readBox = (element) => {
48
+ const style = getComputedStyle(element);
49
+ const next = {
50
+ direction: style.direction === "rtl" ? "rtl" : "ltr",
51
+ paddingInlineStart: Number.parseFloat(style.paddingInlineStart) || 0,
52
+ paddingTop: Number.parseFloat(style.paddingTop) || 0,
53
+ scrollsX: scrolls(style.overflowX),
54
+ scrollsY: scrolls(style.overflowY)
55
+ };
56
+ const current = scrollBox.value;
57
+ if (current.direction !== next.direction || current.paddingInlineStart !== next.paddingInlineStart || current.paddingTop !== next.paddingTop || current.scrollsX !== next.scrollsX || current.scrollsY !== next.scrollsY) scrollBox.value = next;
58
+ };
59
+ /** Reads where the element is scrolled to, and how far it could go. */
60
+ const readScroll = (element) => {
61
+ const scrollWidth = element.scrollWidth;
62
+ const scrollHeight = element.scrollHeight;
63
+ const left = element.scrollLeft;
64
+ const top = element.scrollTop;
65
+ state.scrollPosition = new Point(Math.max(0, Math.min(left, scrollWidth - state.size.width)), Math.max(0, Math.min(top, scrollHeight - state.size.height)));
66
+ if (scrollSize.value.width !== scrollWidth || scrollSize.value.height !== scrollHeight) scrollSize.value = new Size(scrollWidth, scrollHeight);
67
+ const inlineRange = Math.max(0, scrollWidth - state.size.width);
68
+ const offset = new Point(Math.sign(left) * Math.min(Math.abs(left), inlineRange), state.scrollPosition.y);
69
+ if (!scrollOffset.value.equals(offset)) scrollOffset.value = offset;
70
+ };
35
71
  const updateVisibleRect = () => {
36
72
  const visibleRect = new Rect(state.viewportOffset.x + state.scrollPosition.x, state.viewportOffset.y + state.scrollPosition.y, Math.max(0, Math.min(state.size.width - state.viewportOffset.x, state.viewportSize.width)), Math.max(0, Math.min(state.size.height - state.viewportOffset.y, state.viewportSize.height)));
37
73
  if (visibleRect.area > 0 || state.lastVisibleRect.area > 0) {
@@ -51,14 +87,19 @@ var useVirtualizerScroll = (options) => {
51
87
  if (state.scrollTimeout != null) clearTimeout(state.scrollTimeout);
52
88
  state.scrollTimeout = setTimeout(endScrolling, SCROLL_END_DELAY);
53
89
  };
90
+ const markScrolling = () => {
91
+ if (!state.isScrolling) {
92
+ state.isScrolling = true;
93
+ options.onScrollStart?.();
94
+ }
95
+ scheduleScrollEnd();
96
+ };
54
97
  const onScroll = (event) => {
55
98
  const element = getElement();
56
99
  const target = event.target;
57
100
  if (!element || !(target instanceof Node) || !target.contains(element)) return;
58
- if (target === element) {
59
- const contentSize = options.contentSize();
60
- state.scrollPosition = new Point(Math.max(0, Math.min(element.scrollLeft, contentSize.width - state.size.width)), Math.max(0, Math.min(element.scrollTop, contentSize.height - state.size.height)));
61
- } else {
101
+ if (target === element) readScroll(element);
102
+ else {
62
103
  const bounds = element.getBoundingClientRect();
63
104
  const x = bounds.x < 0 ? -bounds.x : 0;
64
105
  const y = bounds.y < 0 ? -bounds.y : 0;
@@ -66,11 +107,16 @@ var useVirtualizerScroll = (options) => {
66
107
  state.viewportOffset = new Point(x, y);
67
108
  }
68
109
  updateVisibleRect();
69
- if (!state.isScrolling) {
70
- state.isScrolling = true;
71
- options.onScrollStart?.();
72
- }
73
- scheduleScrollEnd();
110
+ markScrolling();
111
+ };
112
+ const scrollTo = (offset) => {
113
+ const element = getElement();
114
+ if (!element) return;
115
+ if (offset.left != null) element.scrollLeft = offset.left;
116
+ if (offset.top != null) element.scrollTop = offset.top;
117
+ readScroll(element);
118
+ updateVisibleRect();
119
+ markScrolling();
74
120
  };
75
121
  /**
76
122
  * Re-measures the container.
@@ -87,14 +133,17 @@ var useVirtualizerScroll = (options) => {
87
133
  const viewportHeight = window.innerHeight;
88
134
  const viewportChanged = state.viewportSize.width !== viewportWidth || state.viewportSize.height !== viewportHeight;
89
135
  if (viewportChanged) state.viewportSize = new Size(viewportWidth, viewportHeight);
136
+ readBox(element);
90
137
  const clientWidth = element.clientWidth;
91
138
  const clientHeight = element.clientHeight;
92
139
  if (state.size.width !== clientWidth || state.size.height !== clientHeight || viewportChanged) {
93
140
  state.size = new Size(clientWidth, clientHeight);
141
+ readScroll(element);
94
142
  updateVisibleRect();
95
143
  options.onSizeChange(state.size);
96
144
  if (element.clientWidth !== clientWidth || element.clientHeight !== clientHeight) {
97
145
  state.size = new Size(element.clientWidth, element.clientHeight);
146
+ readScroll(element);
98
147
  updateVisibleRect();
99
148
  options.onSizeChange(state.size);
100
149
  }
@@ -104,13 +153,16 @@ var useVirtualizerScroll = (options) => {
104
153
  watch(() => getElement(), (element, _previous, onCleanup) => {
105
154
  if (!element) return;
106
155
  const document = element.ownerDocument;
107
- document.addEventListener("scroll", onScroll, true);
156
+ document.addEventListener("scroll", onScroll, {
157
+ capture: true,
158
+ passive: true
159
+ });
108
160
  window.addEventListener("resize", measure);
109
161
  const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => measure());
110
162
  observer?.observe(element, { box: "border-box" });
111
163
  measure();
112
164
  onCleanup(() => {
113
- document.removeEventListener("scroll", onScroll, true);
165
+ document.removeEventListener("scroll", onScroll, { capture: true });
114
166
  window.removeEventListener("resize", measure);
115
167
  observer?.disconnect();
116
168
  });
@@ -118,6 +170,16 @@ var useVirtualizerScroll = (options) => {
118
170
  flush: "post",
119
171
  immediate: true
120
172
  });
173
+ watch(() => options.contentSize(), () => {
174
+ const element = getElement();
175
+ if (element) readScroll(element);
176
+ }, { flush: "post" });
177
+ watch(() => options.scrollAdjustment?.() ?? 0, (adjustment) => {
178
+ const element = getElement();
179
+ if (!element || adjustment === 0) return;
180
+ options.takeScrollAdjustment?.();
181
+ element.scrollTop += adjustment;
182
+ }, { flush: "post" });
121
183
  onScopeDispose(() => {
122
184
  if (state.scrollTimeout != null) clearTimeout(state.scrollTimeout);
123
185
  });
@@ -131,7 +193,11 @@ var useVirtualizerScroll = (options) => {
131
193
  width: px(contentSize.width)
132
194
  };
133
195
  }),
134
- measure
196
+ measure,
197
+ scrollBox: computed(() => scrollBox.value),
198
+ scrollOffset: computed(() => scrollOffset.value),
199
+ scrollSize: computed(() => scrollSize.value),
200
+ scrollTo
135
201
  };
136
202
  };
137
203
  //#endregion
@@ -11,10 +11,12 @@ import { Rect, Size } from "../utils/virtualizer-geometry.js";
11
11
  *
12
12
  * Two pieces of upstream are deliberately gone:
13
13
  *
14
- * `ReusableView` and its recycling. React swaps the content of existing elements as they scroll
15
- * out of view, and defers reordering the DOM until scrolling stops because reordering is what
16
- * costs. A keyed `v-for` does the same swapping for free here, and it keeps the DOM in
17
- * collection order at every moment which is what a screen reader walks.
14
+ * `ReusableView` as a class. Its idea is kept see {@link VirtualizerView.slot} because a
15
+ * keyed `v-for` on its own cannot spare a window that moved wholesale: every key in it is new, so
16
+ * every row mounts anew, and a scrollbar dragged across a long collection lands on nothing for as
17
+ * long as the mounting takes. Reordering is not deferred as React defers it: the rendered set is
18
+ * kept in collection order at every moment, which is what a screen reader walks, and moving an
19
+ * element is cheap next to mounting one.
18
20
  *
19
21
  * The scroll anchor. Upstream calls `UNSTABLE_getScrollAnchorInfo` on the layout, but no layout
20
22
  * implements it, so the whole tracker resolves to nothing for every collection in this build.
@@ -22,6 +24,15 @@ import { Rect, Size } from "../utils/virtualizer-geometry.js";
22
24
  /** One rendered element: a layout info, what it was built from, and anything nested inside it. */
23
25
  export interface VirtualizerView {
24
26
  key: VirtualizerKey;
27
+ /**
28
+ * The element this view is rendered into, as a number that outlives the key.
29
+ *
30
+ * A key that leaves the window frees its slot, and the next key to arrive takes it. A collection
31
+ * that keys its rendered items by this rather than by `key` keeps the element and its component
32
+ * when the window moves and changes what they show — which is what makes a window that moved
33
+ * wholesale cost a screenful of updates rather than a screenful of mounts.
34
+ */
35
+ slot: number;
25
36
  layoutInfo: LayoutInfo;
26
37
  parentKey: VirtualizerKey | null;
27
38
  node?: VirtualizerNode;
@@ -48,6 +59,15 @@ export interface UseVirtualizerReturn {
48
59
  endScrolling: () => void;
49
60
  /** Records a measured size, and lays out again when it moved anything. */
50
61
  updateItemSize: (key: VirtualizerKey, size: Size) => void;
62
+ /**
63
+ * How far the content under the window has been pushed by rows measured above it.
64
+ *
65
+ * Adding this to the scroll offset is what holds the collection still while the rows above it
66
+ * settle. Nothing here applies it — only whoever owns the scrolling element can.
67
+ */
68
+ scrollAdjustment: ComputedRef<number>;
69
+ /** Reads the accumulated shift and clears it, so it is applied once. */
70
+ takeScrollAdjustment: () => number;
51
71
  getLayoutInfo: (key: VirtualizerKey) => LayoutInfo | null;
52
72
  isPersistedKey: (key: VirtualizerKey) => boolean;
53
73
  }
@@ -1,5 +1,5 @@
1
1
  import { Rect, Size } from "../utils/virtualizer-geometry.js";
2
- import { OverscanManager } from "../utils/virtualizer-overscan.js";
2
+ import { overscannedRect } from "../utils/virtualizer-overscan.js";
3
3
  import { computed, shallowRef } from "vue";
4
4
  //#region src/composables/use-virtualizer.ts
5
5
  var useVirtualizer = (options) => {
@@ -8,7 +8,7 @@ var useVirtualizer = (options) => {
8
8
  const isScrolling = shallowRef(false);
9
9
  /** Bumped when something outside the reactive inputs invalidates the layout. */
10
10
  const revision = shallowRef(0);
11
- const overscan = new OverscanManager();
11
+ const scrollAdjustment = shallowRef(0);
12
12
  const persistedKeys = () => options.persistedKeys?.() ?? /* @__PURE__ */ new Set();
13
13
  /**
14
14
  * Whether a key, or anything containing it, must stay rendered.
@@ -91,9 +91,33 @@ var useVirtualizer = (options) => {
91
91
  return {
92
92
  contentSize: layout.getContentSize(),
93
93
  layout,
94
- layoutInfos: layout.getVisibleLayoutInfos(overscan.getOverscannedRect())
94
+ layoutInfos: layout.getVisibleLayoutInfos(overscannedRect(rect))
95
95
  };
96
96
  });
97
+ /** Which slot each key of the last pass held. Plain state: it is history, not something derived. */
98
+ let slotByKey = /* @__PURE__ */ new Map();
99
+ let nextSlot = 0;
100
+ /**
101
+ * Hands every key in the pass a slot, keeping the one it had.
102
+ *
103
+ * The slots of the keys that left are handed out in the order their keys were rendered, to the
104
+ * arriving keys in the order they will be: a window that moved wholesale therefore keeps every
105
+ * slot in place, and a window that moved by a row moves one element.
106
+ */
107
+ const assignSlots = (layoutInfos) => {
108
+ const next = /* @__PURE__ */ new Map();
109
+ const arriving = [];
110
+ for (const { key } of layoutInfos) {
111
+ const slot = slotByKey.get(key);
112
+ if (slot == null) arriving.push(key);
113
+ else next.set(key, slot);
114
+ }
115
+ const freed = [];
116
+ for (const [key, slot] of slotByKey) if (!next.has(key)) freed.push(slot);
117
+ for (const key of arriving) next.set(key, freed.length > 0 ? freed.shift() : nextSlot++);
118
+ slotByKey = next;
119
+ return next;
120
+ };
97
121
  /**
98
122
  * The layout infos arrive parents first, so a child always finds its parent already built. One
99
123
  * whose parent is not in the window is treated as a root rather than dropped — losing it would
@@ -104,13 +128,15 @@ var useVirtualizer = (options) => {
104
128
  const collection = options.collection();
105
129
  const views = /* @__PURE__ */ new Map();
106
130
  const roots = [];
131
+ const slots = assignSlots(layoutInfos);
107
132
  for (const layoutInfo of layoutInfos) {
108
133
  const view = {
109
134
  children: [],
110
135
  key: layoutInfo.key,
111
136
  layoutInfo,
112
137
  node: collection.getNode(layoutInfo.key),
113
- parentKey: layoutInfo.parentKey
138
+ parentKey: layoutInfo.parentKey,
139
+ slot: slots.get(layoutInfo.key)
114
140
  };
115
141
  views.set(view.key, view);
116
142
  const parent = layoutInfo.parentKey != null ? views.get(layoutInfo.parentKey) : void 0;
@@ -127,20 +153,28 @@ var useVirtualizer = (options) => {
127
153
  getLayoutInfo: (key) => pass.value.layout.getLayoutInfo(key),
128
154
  isPersistedKey,
129
155
  isScrolling: computed(() => isScrolling.value),
156
+ scrollAdjustment: computed(() => scrollAdjustment.value),
130
157
  setSize: (next) => {
131
158
  if (!size.value.equals(next)) size.value = next;
132
159
  },
133
160
  setVisibleRect: (rect) => {
134
161
  if (visibleRect.value.equals(rect)) return;
135
- overscan.setVisibleRect(rect);
136
162
  visibleRect.value = rect;
137
163
  },
138
164
  size: computed(() => size.value),
139
165
  startScrolling: () => {
140
166
  isScrolling.value = true;
141
167
  },
168
+ takeScrollAdjustment: () => {
169
+ const pending = scrollAdjustment.value;
170
+ scrollAdjustment.value = 0;
171
+ return pending;
172
+ },
142
173
  updateItemSize: (key, measured) => {
143
- if (!pass.value.layout.updateItemSize?.(key, measured)) return;
174
+ const layout = attachedLayout ?? pass.value.layout;
175
+ const placed = layout.getLayoutInfo(key)?.rect;
176
+ if (!layout.updateItemSize?.(key, measured)) return;
177
+ if (placed != null && placed.y < visibleRect.value.y) scrollAdjustment.value += measured.height - placed.height;
144
178
  pendingItemSizeChange = true;
145
179
  revision.value += 1;
146
180
  },