ropav 0.4.0 → 0.6.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 (266) 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/drop-zone/drop-zone-root.d.ts +23 -0
  29. package/dist/components/drop-zone/drop-zone-root.js +153 -0
  30. package/dist/components/drop-zone/drop-zone-trigger.d.ts +21 -0
  31. package/dist/components/drop-zone/drop-zone-trigger.js +20 -0
  32. package/dist/components/drop-zone/drop-zone.accept.d.ts +19 -0
  33. package/dist/components/drop-zone/drop-zone.accept.js +28 -0
  34. package/dist/components/drop-zone/drop-zone.context.d.ts +6 -0
  35. package/dist/components/drop-zone/drop-zone.context.js +5 -0
  36. package/dist/components/drop-zone/drop-zone.types.d.ts +30 -0
  37. package/dist/components/drop-zone/index.d.ts +86 -0
  38. package/dist/components/drop-zone/index.js +11 -0
  39. package/dist/components/dropdown/dropdown-menu.js +1 -0
  40. package/dist/components/dropdown/dropdown-submenu-trigger.js +1 -1
  41. package/dist/components/dropdown/index.d.ts +4 -2
  42. package/dist/{composables → components/dropdown}/use-safely-mouse-to-submenu.js +1 -1
  43. package/dist/components/icons/icon-overlay-arrow.js +1 -1
  44. package/dist/components/index.d.ts +5 -0
  45. package/dist/components/input/index.d.ts +2 -0
  46. package/dist/components/input/input-root.js +3 -0
  47. package/dist/components/input/input.types.d.ts +5 -0
  48. package/dist/components/input-group/index.d.ts +2 -0
  49. package/dist/components/input-group/input-group-root.js +3 -0
  50. package/dist/components/input-group/input-group.types.d.ts +5 -0
  51. package/dist/components/input-otp/index.d.ts +6 -4
  52. package/dist/components/link/index.d.ts +2 -0
  53. package/dist/components/link/link-root.js +22 -5
  54. package/dist/components/link/link.types.d.ts +14 -3
  55. package/dist/{composables → components/list-box}/drag-collection.d.ts +2 -2
  56. package/dist/{composables → components/list-box}/drag-collection.js +1 -1
  57. package/dist/components/list-box/index.d.ts +4 -0
  58. package/dist/components/list-box/list-box-root.js +53 -32
  59. package/dist/components/list-box/list-box.types.d.ts +2 -0
  60. package/dist/components/menu/index.d.ts +2 -0
  61. package/dist/components/menu/menu-root.js +5 -1
  62. package/dist/components/menu/menu.types.d.ts +3 -0
  63. package/dist/components/number-field/index.d.ts +3 -0
  64. package/dist/components/number-field/number-field-root.js +2 -0
  65. package/dist/components/number-field/number-field.types.d.ts +2 -0
  66. package/dist/components/overlay/overlay-arrow.js +64 -11
  67. package/dist/components/progress-bar/index.d.ts +4 -0
  68. package/dist/components/progress-bar/progress-bar-root.js +4 -0
  69. package/dist/components/progress-bar/progress-bar.types.d.ts +7 -0
  70. package/dist/components/radio/radio-content.js +1 -1
  71. package/dist/components/range-calendar/index.d.ts +18 -15
  72. package/dist/components/router-provider/index.d.ts +5 -0
  73. package/dist/components/router-provider/index.js +3 -0
  74. package/dist/components/router-provider/router-provider.context.d.ts +40 -0
  75. package/dist/components/router-provider/router-provider.context.js +16 -0
  76. package/dist/components/router-provider/router-provider.d.ts +21 -0
  77. package/dist/components/router-provider/router-provider.js +22 -0
  78. package/dist/components/router-provider/router-provider.types.d.ts +23 -0
  79. package/dist/components/scroll-shadow/use-scroll-shadow.js +25 -1
  80. package/dist/components/search-field/index.d.ts +2 -0
  81. package/dist/components/search-field/search-field-root.js +3 -1
  82. package/dist/components/search-field/search-field.types.d.ts +2 -0
  83. package/dist/{composables → components/search-field}/use-search-field.d.ts +2 -2
  84. package/dist/{composables → components/search-field}/use-search-field.js +3 -3
  85. package/dist/components/segmented-control/index.d.ts +134 -0
  86. package/dist/components/segmented-control/index.js +15 -0
  87. package/dist/components/segmented-control/segmented-control-indicator.d.ts +19 -0
  88. package/dist/components/segmented-control/segmented-control-indicator.js +36 -0
  89. package/dist/components/segmented-control/segmented-control-item.d.ts +21 -0
  90. package/dist/components/segmented-control/segmented-control-item.js +96 -0
  91. package/dist/components/segmented-control/segmented-control-root.d.ts +25 -0
  92. package/dist/components/segmented-control/segmented-control-root.js +112 -0
  93. package/dist/components/segmented-control/segmented-control-separator.d.ts +19 -0
  94. package/dist/components/segmented-control/segmented-control-separator.js +18 -0
  95. package/dist/components/segmented-control/segmented-control.context.d.ts +17 -0
  96. package/dist/components/segmented-control/segmented-control.context.js +12 -0
  97. package/dist/components/segmented-control/segmented-control.types.d.ts +67 -0
  98. package/dist/components/select/index.d.ts +3 -0
  99. package/dist/components/select/select-hidden-select.js +1 -1
  100. package/dist/components/select/select-root.js +2 -0
  101. package/dist/components/select/select.types.d.ts +2 -0
  102. package/dist/components/sidebar/index.d.ts +546 -0
  103. package/dist/components/sidebar/index.js +47 -0
  104. package/dist/components/sidebar/sidebar-collapsible-trigger.d.ts +21 -0
  105. package/dist/components/sidebar/sidebar-collapsible-trigger.js +70 -0
  106. package/dist/components/sidebar/sidebar-collapsible.d.ts +24 -0
  107. package/dist/components/sidebar/sidebar-collapsible.js +78 -0
  108. package/dist/components/sidebar/sidebar-content.d.ts +21 -0
  109. package/dist/components/sidebar/sidebar-content.js +37 -0
  110. package/dist/components/sidebar/sidebar-footer.d.ts +21 -0
  111. package/dist/components/sidebar/sidebar-footer.js +24 -0
  112. package/dist/components/sidebar/sidebar-group-label.d.ts +21 -0
  113. package/dist/components/sidebar/sidebar-group-label.js +32 -0
  114. package/dist/components/sidebar/sidebar-group.d.ts +21 -0
  115. package/dist/components/sidebar/sidebar-group.js +48 -0
  116. package/dist/components/sidebar/sidebar-header.d.ts +21 -0
  117. package/dist/components/sidebar/sidebar-header.js +24 -0
  118. package/dist/components/sidebar/sidebar-inset.d.ts +21 -0
  119. package/dist/components/sidebar/sidebar-inset.js +24 -0
  120. package/dist/components/sidebar/sidebar-item-icon.d.ts +21 -0
  121. package/dist/components/sidebar/sidebar-item-icon.js +20 -0
  122. package/dist/components/sidebar/sidebar-item-indicator.d.ts +21 -0
  123. package/dist/components/sidebar/sidebar-item-indicator.js +48 -0
  124. package/dist/components/sidebar/sidebar-item-label.d.ts +21 -0
  125. package/dist/components/sidebar/sidebar-item-label.js +28 -0
  126. package/dist/components/sidebar/sidebar-item-tooltip.d.ts +21 -0
  127. package/dist/components/sidebar/sidebar-item-tooltip.js +38 -0
  128. package/dist/components/sidebar/sidebar-item-trailing.d.ts +21 -0
  129. package/dist/components/sidebar/sidebar-item-trailing.js +28 -0
  130. package/dist/components/sidebar/sidebar-item.d.ts +23 -0
  131. package/dist/components/sidebar/sidebar-item.js +160 -0
  132. package/dist/components/sidebar/sidebar-panel.d.ts +21 -0
  133. package/dist/components/sidebar/sidebar-panel.js +88 -0
  134. package/dist/components/sidebar/sidebar-rail.d.ts +21 -0
  135. package/dist/components/sidebar/sidebar-rail.js +210 -0
  136. package/dist/components/sidebar/sidebar-root.d.ts +31 -0
  137. package/dist/components/sidebar/sidebar-root.js +140 -0
  138. package/dist/components/sidebar/sidebar-separator.d.ts +19 -0
  139. package/dist/components/sidebar/sidebar-separator.js +16 -0
  140. package/dist/components/sidebar/sidebar-sub-menu.d.ts +23 -0
  141. package/dist/components/sidebar/sidebar-sub-menu.js +40 -0
  142. package/dist/components/sidebar/sidebar-trigger.d.ts +21 -0
  143. package/dist/components/sidebar/sidebar-trigger.js +69 -0
  144. package/dist/components/sidebar/sidebar.context.d.ts +75 -0
  145. package/dist/components/sidebar/sidebar.context.js +30 -0
  146. package/dist/components/sidebar/sidebar.state.d.ts +73 -0
  147. package/dist/components/sidebar/sidebar.state.js +76 -0
  148. package/dist/components/sidebar/sidebar.storage.d.ts +8 -0
  149. package/dist/components/sidebar/sidebar.storage.js +45 -0
  150. package/dist/components/sidebar/sidebar.types.d.ts +273 -0
  151. package/dist/components/splitter/index.d.ts +143 -0
  152. package/dist/components/splitter/index.js +13 -0
  153. package/dist/components/splitter/splitter-handle.d.ts +21 -0
  154. package/dist/components/splitter/splitter-handle.js +209 -0
  155. package/dist/components/splitter/splitter-panel.d.ts +21 -0
  156. package/dist/components/splitter/splitter-panel.js +70 -0
  157. package/dist/components/splitter/splitter-root.d.ts +31 -0
  158. package/dist/components/splitter/splitter-root.js +152 -0
  159. package/dist/components/splitter/splitter.context.d.ts +15 -0
  160. package/dist/components/splitter/splitter.context.js +5 -0
  161. package/dist/components/splitter/splitter.state.d.ts +87 -0
  162. package/dist/components/splitter/splitter.state.js +322 -0
  163. package/dist/components/splitter/splitter.storage.d.ts +15 -0
  164. package/dist/components/splitter/splitter.storage.js +56 -0
  165. package/dist/components/splitter/splitter.types.d.ts +98 -0
  166. package/dist/components/switch/switch-content.js +1 -1
  167. package/dist/components/table/index.d.ts +10 -9
  168. package/dist/components/table/table-body.js +13 -13
  169. package/dist/components/table/table-cell.js +49 -46
  170. package/dist/components/table/table-column-resizer.js +1 -1
  171. package/dist/components/table/table-column.js +1 -1
  172. package/dist/components/table/table-content.js +37 -18
  173. package/dist/{composables → components/table}/table-drag-collection.d.ts +1 -1
  174. package/dist/{composables → components/table}/table-drag-collection.js +1 -1
  175. package/dist/components/table/table-drop-indicator.js +3 -1
  176. package/dist/components/table/table-resizable-container.d.ts +4 -5
  177. package/dist/components/table/table-row.js +45 -14
  178. package/dist/components/table/table-virtualizer-item.d.ts +2 -7
  179. package/dist/components/table/table-virtualizer-item.js +20 -9
  180. package/dist/components/table/table.context.d.ts +11 -3
  181. package/dist/components/table/table.types.d.ts +1 -1
  182. package/dist/{composables → components/table}/use-grid-keyboard.d.ts +3 -3
  183. package/dist/{composables → components/table}/use-grid-keyboard.js +57 -55
  184. package/dist/{composables → components/table}/use-grid-selection-announcement.d.ts +2 -2
  185. package/dist/{composables → components/table}/use-grid-selection-announcement.js +2 -2
  186. package/dist/{composables → components/table}/use-table-collection.d.ts +2 -2
  187. package/dist/{composables → components/table}/use-table-collection.js +4 -4
  188. package/dist/{composables → components/table}/use-table-column-layout.d.ts +13 -20
  189. package/dist/components/table/use-table-column-layout.js +115 -0
  190. package/dist/components/textarea/index.d.ts +2 -0
  191. package/dist/components/textarea/textarea-root.js +3 -0
  192. package/dist/components/textarea/textarea.types.d.ts +5 -0
  193. package/dist/components/textfield/index.d.ts +2 -0
  194. package/dist/components/textfield/textfield-root.js +5 -1
  195. package/dist/components/textfield/textfield.context.d.ts +2 -0
  196. package/dist/components/textfield/textfield.types.d.ts +5 -0
  197. package/dist/components/time-field/index.d.ts +1 -0
  198. package/dist/components/toast/index.d.ts +1 -0
  199. package/dist/components/toast/toast-default-content.js +1 -1
  200. package/dist/components/toolbar/index.d.ts +3 -2
  201. package/dist/components/tooltip/index.js +1 -1
  202. package/dist/components/tooltip/tooltip-root.js +1 -1
  203. package/dist/components/virtualizer/index.d.ts +3 -1
  204. package/dist/components/virtualizer/index.js +2 -1
  205. package/dist/components/virtualizer/use-virtualizer-item.d.ts +23 -0
  206. package/dist/components/virtualizer/use-virtualizer-item.js +45 -0
  207. package/dist/components/virtualizer/virtualizer-item.js +7 -41
  208. package/dist/components/virtualizer/virtualizer-scrollbar-track.d.ts +20 -0
  209. package/dist/components/virtualizer/virtualizer-scrollbar-track.js +141 -0
  210. package/dist/components/virtualizer/virtualizer-scrollbar.d.ts +18 -0
  211. package/dist/components/virtualizer/virtualizer-scrollbar.js +55 -0
  212. package/dist/components/virtualizer/virtualizer.context.d.ts +17 -1
  213. package/dist/composables/drag-manager.js +1 -13
  214. package/dist/composables/index.d.ts +3 -70
  215. package/dist/composables/use-collection.d.ts +22 -3
  216. package/dist/composables/use-collection.js +67 -14
  217. package/dist/composables/use-color-area.js +2 -2
  218. package/dist/composables/use-color-field.js +1 -1
  219. package/dist/composables/use-combo-box.js +1 -1
  220. package/dist/composables/use-date-field.js +1 -1
  221. package/dist/composables/use-drag.d.ts +6 -5
  222. package/dist/composables/use-draggable-item.d.ts +2 -2
  223. package/dist/composables/use-droppable-collection.js +3 -3
  224. package/dist/composables/use-droppable-item.js +1 -1
  225. package/dist/composables/use-form-reset.d.ts +6 -2
  226. package/dist/composables/use-form-reset.js +9 -5
  227. package/dist/composables/use-list-keyboard.js +64 -62
  228. package/dist/composables/use-number-field.js +1 -1
  229. package/dist/composables/use-select.js +2 -2
  230. package/dist/composables/use-selection-manager.js +4 -4
  231. package/dist/composables/use-single-select-list-state.d.ts +37 -0
  232. package/dist/composables/use-single-select-list-state.js +110 -0
  233. package/dist/composables/use-slider-thumb.js +2 -2
  234. package/dist/composables/use-slider.js +1 -1
  235. package/dist/composables/use-tab-list-state.d.ts +10 -29
  236. package/dist/composables/use-tab-list-state.js +10 -99
  237. package/dist/composables/use-text-field.js +1 -1
  238. package/dist/composables/use-virtualizer-scroll.d.ts +52 -2
  239. package/dist/composables/use-virtualizer-scroll.js +79 -13
  240. package/dist/composables/use-virtualizer.d.ts +24 -4
  241. package/dist/composables/use-virtualizer.js +40 -6
  242. package/dist/index.js +60 -83
  243. package/dist/utils/document-order.d.ts +14 -0
  244. package/dist/utils/document-order.js +17 -0
  245. package/dist/utils/flex-sizing.d.ts +41 -0
  246. package/dist/utils/flex-sizing.js +140 -0
  247. package/dist/utils/index.d.ts +2 -0
  248. package/dist/utils/open-link.d.ts +31 -0
  249. package/dist/utils/open-link.js +32 -0
  250. package/dist/utils/story-truncation.d.ts +20 -0
  251. package/dist/utils/story-users.d.ts +11 -0
  252. package/dist/utils/virtualizer-collection.d.ts +14 -4
  253. package/dist/utils/virtualizer-collection.js +9 -14
  254. package/dist/utils/virtualizer-layout-info.js +3 -2
  255. package/dist/utils/virtualizer-list-layout.d.ts +75 -29
  256. package/dist/utils/virtualizer-list-layout.js +182 -99
  257. package/dist/utils/virtualizer-offsets.d.ts +111 -0
  258. package/dist/utils/virtualizer-offsets.js +159 -0
  259. package/dist/utils/virtualizer-overscan.d.ts +9 -15
  260. package/dist/utils/virtualizer-overscan.js +14 -33
  261. package/dist/utils/virtualizer-table-layout.d.ts +50 -21
  262. package/dist/utils/virtualizer-table-layout.js +130 -89
  263. package/dist/version.js +1 -1
  264. package/package.json +25 -5
  265. package/dist/composables/use-table-column-layout.js +0 -214
  266. /package/dist/{composables → components/dropdown}/use-safely-mouse-to-submenu.d.ts +0 -0
@@ -0,0 +1,41 @@
1
+ /** A size: pixels as a number or a `px` string, a percentage of the container, or a fraction of what is left. */
2
+ export type FlexSize = number | string;
3
+ export interface FlexSizeDefinition {
4
+ /** A size the caller controls. Set, it outranks everything below it. */
5
+ size?: FlexSize | null;
6
+ /** The size the item starts at, when the caller is not controlling it. */
7
+ defaultSize?: FlexSize | null;
8
+ minSize?: FlexSize | null;
9
+ maxSize?: FlexSize | null;
10
+ }
11
+ /**
12
+ * Pixels and percentages are fixed; `fr` units and anything unrecognised flex.
13
+ *
14
+ * A bare number, a `px` string and a numeric string all count as pixels. Accepting the string
15
+ * forms is not cosmetic: a template attribute is always a string, so `size="240px"` is the only
16
+ * way most callers can express a pixel size at all.
17
+ */
18
+ export declare const isStaticSize: (size?: FlexSize | null) => boolean;
19
+ /** The number in front of `fr`. Anything else counts as `1fr`, as React Aria has it. */
20
+ export declare const parseFractionalUnit: (size?: FlexSize | null) => number;
21
+ export declare const parseStaticSize: (size: FlexSize, availableSize: number) => number;
22
+ export declare const getMaxSize: (maxSize: FlexSize | null | undefined, availableSize: number) => number;
23
+ /**
24
+ * A minimum cannot be given in `fr`: knowing what a fraction comes to would need every other
25
+ * item's size, which is the very thing being solved for.
26
+ */
27
+ export declare const getMinSize: (minSize: FlexSize | null | undefined, availableSize: number) => number;
28
+ /**
29
+ * Sizes for one container size, ported from react-stately's `calculateColumnSizes`.
30
+ *
31
+ * This is the CSS flexbox layout algorithm, cut down to the shape a single track needs: one line,
32
+ * a flex basis of zero unless the item asked for a static size, and grow and shrink both equal to
33
+ * the item's `fr`. It is deliberately **not** plain pixel sizing — `1fr` items have to share what
34
+ * the static and percentage items leave over, and a minimum or maximum on any one of them
35
+ * redistributes the rest.
36
+ *
37
+ * Keyless on purpose: a caller with overriding sizes of its own resolves them into `size` before
38
+ * calling, which is the same precedence a lookup here would have given and leaves the solver with
39
+ * nothing to know about how the caller identifies its items.
40
+ */
41
+ export declare const calculateFlexSizes: (availableSize: number, definitions: FlexSizeDefinition[], getDefaultSize?: (index: number) => FlexSize | null | undefined, getDefaultMinSize?: (index: number) => FlexSize | null | undefined) => number[];
@@ -0,0 +1,140 @@
1
+ //#region src/utils/flex-sizing.ts
2
+ var PIXELS = /^(-?\d*\.?\d+)px$/;
3
+ var PERCENT = /^(-?\d*\.?\d+)%$/;
4
+ var NUMBER = /^-?\d*\.?\d+$/;
5
+ var FRACTION = /^(-?\d*\.?\d+)fr$/;
6
+ /**
7
+ * Pixels and percentages are fixed; `fr` units and anything unrecognised flex.
8
+ *
9
+ * A bare number, a `px` string and a numeric string all count as pixels. Accepting the string
10
+ * forms is not cosmetic: a template attribute is always a string, so `size="240px"` is the only
11
+ * way most callers can express a pixel size at all.
12
+ */
13
+ var isStaticSize = (size) => {
14
+ if (size == null) return false;
15
+ if (typeof size === "number") return !isNaN(size);
16
+ return PIXELS.test(size) || PERCENT.test(size) || NUMBER.test(size);
17
+ };
18
+ /** The number in front of `fr`. Anything else counts as `1fr`, as React Aria has it. */
19
+ var parseFractionalUnit = (size) => {
20
+ if (!size || typeof size === "number") return 1;
21
+ const match = FRACTION.exec(size);
22
+ return match ? parseFloat(match[1]) : 1;
23
+ };
24
+ var parseStaticSize = (size, availableSize) => {
25
+ if (typeof size === "number") return size;
26
+ const percent = PERCENT.exec(size);
27
+ if (percent) return availableSize * (parseFloat(percent[1]) / 100);
28
+ const pixels = PIXELS.exec(size);
29
+ if (pixels) return parseFloat(pixels[1]);
30
+ if (NUMBER.test(size)) return parseFloat(size);
31
+ throw new Error("Only percentages or numbers are supported for static sizes");
32
+ };
33
+ var getMaxSize = (maxSize, availableSize) => maxSize != null ? parseStaticSize(maxSize, availableSize) : Number.MAX_SAFE_INTEGER;
34
+ /**
35
+ * A minimum cannot be given in `fr`: knowing what a fraction comes to would need every other
36
+ * item's size, which is the very thing being solved for.
37
+ */
38
+ var getMinSize = (minSize, availableSize) => minSize != null ? parseStaticSize(minSize, availableSize) : 0;
39
+ /**
40
+ * Round an array of floats that sums to an integer, keeping the sum.
41
+ *
42
+ * Each item has to come out a whole number of pixels, and rounding them one by one would drift:
43
+ * the remainder is carried forward instead, so the total is preserved.
44
+ */
45
+ var cascadeRounding = (items) => {
46
+ let floatTotal = 0;
47
+ let intTotal = 0;
48
+ return items.map((item) => {
49
+ const rounded = Math.round(item.targetMainSize + floatTotal) - intTotal;
50
+ floatTotal += item.targetMainSize;
51
+ intTotal += rounded;
52
+ return rounded;
53
+ });
54
+ };
55
+ /**
56
+ * Sizes for one container size, ported from react-stately's `calculateColumnSizes`.
57
+ *
58
+ * This is the CSS flexbox layout algorithm, cut down to the shape a single track needs: one line,
59
+ * a flex basis of zero unless the item asked for a static size, and grow and shrink both equal to
60
+ * the item's `fr`. It is deliberately **not** plain pixel sizing — `1fr` items have to share what
61
+ * the static and percentage items leave over, and a minimum or maximum on any one of them
62
+ * redistributes the rest.
63
+ *
64
+ * Keyless on purpose: a caller with overriding sizes of its own resolves them into `size` before
65
+ * calling, which is the same precedence a lookup here would have given and leaves the solver with
66
+ * nothing to know about how the caller identifies its items.
67
+ */
68
+ var calculateFlexSizes = (availableSize, definitions, getDefaultSize, getDefaultMinSize) => {
69
+ const originalSize = availableSize;
70
+ const flooredSize = Math.floor(availableSize);
71
+ const hasFractionalSize = availableSize - flooredSize > 0;
72
+ availableSize = flooredSize;
73
+ let hasNonFrozenItems = false;
74
+ const items = definitions.map((definition, index) => {
75
+ const size = definition.size ?? definition.defaultSize ?? getDefaultSize?.(index) ?? "1fr";
76
+ let frozen = false;
77
+ let baseSize = 0;
78
+ let flex = 0;
79
+ let targetMainSize = 0;
80
+ if (isStaticSize(size)) {
81
+ baseSize = parseStaticSize(size, availableSize);
82
+ frozen = true;
83
+ } else {
84
+ flex = parseFractionalUnit(size);
85
+ if (flex <= 0) frozen = true;
86
+ }
87
+ const min = getMinSize(definition.minSize ?? getDefaultMinSize?.(index) ?? 0, availableSize);
88
+ const max = getMaxSize(definition.maxSize, availableSize);
89
+ const hypotheticalMainSize = Math.max(min, Math.min(baseSize, max));
90
+ if (frozen) targetMainSize = hypotheticalMainSize;
91
+ else if (baseSize > hypotheticalMainSize) {
92
+ frozen = true;
93
+ targetMainSize = hypotheticalMainSize;
94
+ }
95
+ if (!frozen) hasNonFrozenItems = true;
96
+ return {
97
+ baseSize,
98
+ flex,
99
+ frozen,
100
+ hypotheticalMainSize,
101
+ max,
102
+ min,
103
+ targetMainSize,
104
+ violation: 0
105
+ };
106
+ });
107
+ while (hasNonFrozenItems) {
108
+ let usedSize = 0;
109
+ let flexFactors = 0;
110
+ for (const item of items) if (item.frozen) usedSize += item.targetMainSize;
111
+ else {
112
+ usedSize += item.baseSize;
113
+ flexFactors += item.flex;
114
+ }
115
+ const remainingFreeSpace = availableSize - usedSize;
116
+ if (remainingFreeSpace > 0) {
117
+ for (const item of items) if (!item.frozen) item.targetMainSize = item.baseSize + item.flex / flexFactors * remainingFreeSpace;
118
+ }
119
+ let totalViolation = 0;
120
+ for (const item of items) {
121
+ item.violation = 0;
122
+ if (item.frozen) continue;
123
+ const unclamped = item.targetMainSize;
124
+ item.targetMainSize = Math.max(item.min, Math.min(unclamped, item.max));
125
+ item.violation = item.targetMainSize - unclamped;
126
+ totalViolation += item.violation;
127
+ }
128
+ hasNonFrozenItems = false;
129
+ for (const item of items) if (totalViolation === 0 || Math.sign(totalViolation) === Math.sign(item.violation)) item.frozen = true;
130
+ else if (!item.frozen) hasNonFrozenItems = true;
131
+ }
132
+ const sizes = cascadeRounding(items);
133
+ if (hasFractionalSize && sizes.length > 0) {
134
+ const fraction = originalSize.toString().split(".")[1];
135
+ sizes[sizes.length - 1] = Number(`${sizes.at(-1)}.${fraction}`);
136
+ }
137
+ return sizes;
138
+ };
139
+ //#endregion
140
+ export { calculateFlexSizes, getMaxSize, getMinSize, isStaticSize, parseFractionalUnit, parseStaticSize };
@@ -22,6 +22,7 @@ export * from "./form-value.js";
22
22
  export * from "./incomplete-date.js";
23
23
  export * from "./locale.js";
24
24
  export * from "./number.js";
25
+ export * from "./open-link.js";
25
26
  export * from "./platform.js";
26
27
  export * from "./position.js";
27
28
  export * from "./text-value.js";
@@ -30,6 +31,7 @@ export * from "./virtualizer-geometry.js";
30
31
  export * from "./virtualizer-layout.js";
31
32
  export * from "./virtualizer-layout-info.js";
32
33
  export * from "./virtualizer-list-layout.js";
34
+ export * from "./virtualizer-offsets.js";
33
35
  export * from "./virtualizer-overscan.js";
34
36
  export * from "./virtualizer-table-layout.js";
35
37
  export * from "./visually-hidden.js";
@@ -0,0 +1,31 @@
1
+ import type { RouterContext } from "../components/router-provider/router-provider.context.js";
2
+ /** The modifier keys a click carries, which is all `shouldClientNavigate` reads off the event. */
3
+ export interface OpenLinkModifiers {
4
+ altKey: boolean;
5
+ ctrlKey: boolean;
6
+ metaKey: boolean;
7
+ shiftKey: boolean;
8
+ }
9
+ export interface OpenLinkOptions {
10
+ /** The href as the link declared it, before `resolveHref` rewrote it for the DOM. */
11
+ href?: string;
12
+ router: RouterContext | null;
13
+ /** Passed straight through to `navigate`, for whatever the application's router accepts. */
14
+ routerOptions?: unknown;
15
+ }
16
+ /**
17
+ * Whether the application's router should take this activation rather than the browser.
18
+ *
19
+ * Ported from React Aria's `shouldClientNavigate`. Every case below asks the browser for
20
+ * something a client-side router cannot do, so letting the event through is the whole point.
21
+ */
22
+ export declare const shouldClientNavigate: (link: HTMLAnchorElement, modifiers: OpenLinkModifiers) => boolean;
23
+ /**
24
+ * Give a click on an anchor to the application's router, when it is a click the router can serve.
25
+ *
26
+ * Called after the press machinery, from a link's own click handler. Every activation path
27
+ * converges there: a pointer press completes on the click, Enter on an anchor produces a native
28
+ * click because `usePress` carves anchors out of its keyboard default handling, and a screen
29
+ * reader arrives as a virtual click.
30
+ */
31
+ export declare const openLink: (event: MouseEvent, options: OpenLinkOptions) => void;
@@ -0,0 +1,32 @@
1
+ //#region src/utils/open-link.ts
2
+ /**
3
+ * Whether the application's router should take this activation rather than the browser.
4
+ *
5
+ * Ported from React Aria's `shouldClientNavigate`. Every case below asks the browser for
6
+ * something a client-side router cannot do, so letting the event through is the whole point.
7
+ */
8
+ var shouldClientNavigate = (link, modifiers) => {
9
+ const target = link.getAttribute("target");
10
+ return (!target || target === "_self") && link.origin === window.location.origin && !link.hasAttribute("download") && !modifiers.metaKey && !modifiers.ctrlKey && !modifiers.altKey && !modifiers.shiftKey;
11
+ };
12
+ /**
13
+ * Give a click on an anchor to the application's router, when it is a click the router can serve.
14
+ *
15
+ * Called after the press machinery, from a link's own click handler. Every activation path
16
+ * converges there: a pointer press completes on the click, Enter on an anchor produces a native
17
+ * click because `usePress` carves anchors out of its keyboard default handling, and a screen
18
+ * reader arrives as a virtual click.
19
+ */
20
+ var openLink = (event, options) => {
21
+ const { href, router, routerOptions } = options;
22
+ if (!router || !href) return;
23
+ if (event.defaultPrevented) return;
24
+ if (event.button !== 0) return;
25
+ const link = event.currentTarget;
26
+ if (!(link instanceof HTMLAnchorElement)) return;
27
+ if (!shouldClientNavigate(link, event)) return;
28
+ event.preventDefault();
29
+ router.navigate(href, routerOptions);
30
+ };
31
+ //#endregion
32
+ export { openLink, shouldClientNavigate };
@@ -0,0 +1,20 @@
1
+ import type { CollectionKey } from "../composables/use-collection.js";
2
+ /**
3
+ * Which of a collection's labels are clipped, for the stories that pair truncation with a tooltip.
4
+ *
5
+ * A tooltip on every option is noise: the ones that fit already say everything they have to say, and
6
+ * a tooltip repeating a label the user can read is one more thing moving under the pointer. So the
7
+ * label reports whether it is actually clipped, and only those get one.
8
+ *
9
+ * `scrollWidth > clientWidth` is the only reliable read of that — CSS truncates without telling
10
+ * anyone, and the width a label wants depends on the font, the container and the text at once, none
11
+ * of which a story can know in advance. A `ResizeObserver` keeps the answer current: the popover is
12
+ * measured the moment it opens, and again whenever it is resized under a label that then fits, or
13
+ * stops fitting.
14
+ *
15
+ * Story-only, so it is deliberately not re-exported from `utils/index.ts`.
16
+ */
17
+ export declare const useClippedLabels: () => {
18
+ clipped: import("vue").ShallowRef<ReadonlySet<CollectionKey>, ReadonlySet<CollectionKey>>;
19
+ measure: (key: CollectionKey, element: unknown) => void;
20
+ };
@@ -0,0 +1,11 @@
1
+ /** Story-only, like the rest of the `story-*` helpers, so deliberately not re-exported. */
2
+ export interface User {
3
+ id: number;
4
+ image_url: string;
5
+ name: string;
6
+ role: string;
7
+ status: "Active" | "Inactive" | "On Leave";
8
+ email: string;
9
+ }
10
+ /** The same rows in the same order as the React story, so the two can be compared row by row. */
11
+ export declare const generateUsers: (count: number) => User[];
@@ -34,7 +34,12 @@ export interface VirtualizerTableCollection extends VirtualizerCollection {
34
34
  loaderKey: VirtualizerKey | null;
35
35
  /** The columns, in order. A cell's position among them is what pairs it with a width. */
36
36
  columnKeys: VirtualizerKey[];
37
- /** The key of the cell where a row and a column meet. */
37
+ /**
38
+ * The key of the cell where a row and a column meet.
39
+ *
40
+ * A cell is not a node of this collection — this is what stands in for one, so the layout can
41
+ * name a cell it is about to place and a rendered cell can look its own geometry back up.
42
+ */
38
43
  cellKey: (rowKey: VirtualizerKey, columnKey: VirtualizerKey) => VirtualizerKey;
39
44
  /**
40
45
  * The same nodes seen as a flat list of rows.
@@ -65,12 +70,17 @@ export interface CreateTableCollectionOptions<T> {
65
70
  }
66
71
  /**
67
72
  * The two-dimensional collection a table layout walks: a header holding one row of columns, and a
68
- * body holding a row per item with a cell per column.
73
+ * body holding a row per item.
69
74
  *
70
75
  * React Aria gets this shape from its hidden render pass, where every cell a row rendered is a
71
76
  * node of the collection. There is no such pass here, so the cells are **derived**: a virtualized
72
- * table renders one cell per column, so the cell where row `r` meets column `c` is known without
73
- * anyone having rendered it. That is what lets the layout place a row that is nowhere in the DOM.
77
+ * table renders one cell per column, so the cell where row `r` meets column `c` is known from
78
+ * {@link VirtualizerTableCollection.cellKey} without anyone having rendered it. That is what lets
79
+ * the layout place a row that is nowhere in the DOM.
80
+ *
81
+ * Nothing here holds a cell, and deliberately: a cell per column per row is the one count that
82
+ * grows with the data rather than with the window, and it would be paid in full before the first
83
+ * paint. The layout builds the cells of the rows it places, and drops them with those rows.
74
84
  *
75
85
  * Consequently a `colSpan` is not expressible — every cell is exactly one column wide.
76
86
  */
@@ -36,12 +36,17 @@ var createListCollection = (options) => {
36
36
  };
37
37
  /**
38
38
  * The two-dimensional collection a table layout walks: a header holding one row of columns, and a
39
- * body holding a row per item with a cell per column.
39
+ * body holding a row per item.
40
40
  *
41
41
  * React Aria gets this shape from its hidden render pass, where every cell a row rendered is a
42
42
  * node of the collection. There is no such pass here, so the cells are **derived**: a virtualized
43
- * table renders one cell per column, so the cell where row `r` meets column `c` is known without
44
- * anyone having rendered it. That is what lets the layout place a row that is nowhere in the DOM.
43
+ * table renders one cell per column, so the cell where row `r` meets column `c` is known from
44
+ * {@link VirtualizerTableCollection.cellKey} without anyone having rendered it. That is what lets
45
+ * the layout place a row that is nowhere in the DOM.
46
+ *
47
+ * Nothing here holds a cell, and deliberately: a cell per column per row is the one count that
48
+ * grows with the data rather than with the window, and it would be paid in full before the first
49
+ * paint. The layout builds the cells of the rows it places, and drops them with those rows.
45
50
  *
46
51
  * Consequently a `colSpan` is not expressible — every cell is exactly one column wide.
47
52
  */
@@ -93,11 +98,10 @@ var createTableCollection = (options) => {
93
98
  });
94
99
  items.forEach((item, index) => {
95
100
  const rowKey = getKey(item, index);
96
- const cellKeys = columnKeys.map((columnKey) => cellKey(rowKey, columnKey));
97
101
  rowKeys.push(rowKey);
98
102
  bodyChildKeys.push(rowKey);
99
103
  add({
100
- childKeys: cellKeys,
104
+ childKeys: [],
101
105
  content: item,
102
106
  index,
103
107
  isDisabled: isDisabled?.(item) ?? false,
@@ -106,15 +110,6 @@ var createTableCollection = (options) => {
106
110
  textValue: getTextValue?.(item),
107
111
  type: "row"
108
112
  });
109
- cellKeys.forEach((key, columnIndex) => {
110
- add({
111
- childKeys: [],
112
- index: columnIndex,
113
- key,
114
- parentKey: rowKey,
115
- type: "cell"
116
- });
117
- });
118
113
  });
119
114
  if (loaderKey != null) {
120
115
  bodyChildKeys.push(loaderKey);
@@ -68,10 +68,11 @@ var px = (value) => Number.isFinite(value) ? `${value}px` : void 0;
68
68
  */
69
69
  var layoutInfoToStyle = (layoutInfo, parent) => {
70
70
  const offsetParent = Boolean(parent && !(parent.allowOverflow && layoutInfo.isSticky)) ? parent : null;
71
+ const isEstimated = layoutInfo.estimatedSize;
71
72
  return {
72
- contain: "size layout style",
73
+ contain: isEstimated ? "layout style" : "size layout style",
73
74
  display: layoutInfo.isSticky ? "inline-block" : void 0,
74
- height: px(layoutInfo.rect.height),
75
+ height: isEstimated ? "auto" : px(layoutInfo.rect.height),
75
76
  left: px(layoutInfo.rect.x - (offsetParent?.rect.x ?? 0)),
76
77
  opacity: layoutInfo.opacity,
77
78
  overflow: layoutInfo.allowOverflow ? "visible" : "hidden",
@@ -4,6 +4,7 @@ import type { VirtualizerKey } from "./virtualizer-layout-info.js";
4
4
  import { Rect, Size } from "./virtualizer-geometry.js";
5
5
  import { Layout } from "./virtualizer-layout.js";
6
6
  import { LayoutInfo } from "./virtualizer-layout-info.js";
7
+ import { RowOffsets } from "./virtualizer-offsets.js";
7
8
  export interface ListLayoutOptions {
8
9
  /** The fixed size of a row, in px. */
9
10
  rowSize?: number;
@@ -21,23 +22,11 @@ export interface ListLayoutOptions {
21
22
  padding?: number;
22
23
  /** How thick the line marking a gap between two items is, in px. @default 2 */
23
24
  dropIndicatorThickness?: number;
24
- /** @deprecated Use `rowSize`. Accepted because React Aria still does. */
25
- rowHeight?: number;
26
- /** @deprecated Use `estimatedRowSize`. */
27
- estimatedRowHeight?: number;
28
- /** @deprecated Use `headingSize`. */
29
- headingHeight?: number;
30
- /** @deprecated Use `estimatedHeadingSize`. */
31
- estimatedHeadingHeight?: number;
32
- /** @deprecated Use `loaderSize`. */
33
- loaderHeight?: number;
34
25
  }
35
26
  /** A layout info plus the hierarchy around it, which a table needs and a list does not. */
36
27
  export interface LayoutNode {
37
28
  layoutInfo: LayoutInfo;
38
29
  children: LayoutNode[];
39
- /** The part of the layout info that has been computed against real data. */
40
- validRect: Rect;
41
30
  node?: VirtualizerNode;
42
31
  index?: number;
43
32
  }
@@ -53,21 +42,27 @@ export declare class ListLayout<Options extends ListLayoutOptions = ListLayoutOp
53
42
  protected layoutNodes: Map<VirtualizerKey, LayoutNode>;
54
43
  protected rootNodes: LayoutNode[];
55
44
  protected contentSize: Size;
56
- /** The region rows have been computed for. Everything outside it is only accounted for. */
57
- protected requestedRect: Rect;
58
- /** The part of `requestedRect` whose rows are known-good. */
59
- protected validRect: Rect;
45
+ /** Where every root sits, whether or not it has ever been built. */
46
+ protected offsets: RowOffsets;
47
+ /** The window the rendered set was built for, in content coordinates. */
48
+ protected window: Rect;
60
49
  protected lastCollection: VirtualizerCollection | null;
61
50
  private invalidateEverything;
62
51
  constructor(options?: ListLayoutOptions);
63
52
  getContentSize(): Size;
64
53
  getLayoutInfo(key: VirtualizerKey): LayoutInfo | null;
54
+ /** Where every root sits, for a caller that needs an offset rather than a rendered node. */
55
+ getRowOffsets(): RowOffsets;
65
56
  /**
66
57
  * The rectangle grown to whole rows.
67
58
  *
68
59
  * Without this a one-pixel scroll would change which rows fall inside the rectangle, and the set
69
- * of rendered elements would churn on every frame. A table snaps differently — its own row
70
- * stride ignores the gap — so this is the one part of the walk a subclass replaces.
60
+ * of rendered elements would churn on every frame.
61
+ *
62
+ * The stride has to be the one rows are actually placed at, gap included, and the height has to
63
+ * absorb however far the top edge moved. Upstream's table snaps by the bare row height and lets
64
+ * the bottom edge fall wherever it lands, which costs a gap of coverage per screen — so a window
65
+ * arrived at by scrolling ends one gap short of where it was asked to reach.
71
66
  */
72
67
  protected snapVisibleRect(rect: Rect): Rect;
73
68
  /** Every layout info inside `rect`, snapped to whole rows, parents before children. */
@@ -77,21 +72,72 @@ export declare class ListLayout<Options extends ListLayoutOptions = ListLayoutOp
77
72
  /**
78
73
  * Records a row's measured size.
79
74
  *
80
- * Returns whether anything moved, which is the virtualizer's cue to lay out again. The rows
81
- * below this one are the ones that moved, so the valid region is cut off at this row's offset
82
- * rather than thrown away entirely.
75
+ * Returns whether anything moved, which is the virtualizer's cue to lay out again. The size goes
76
+ * to the index rather than only onto the rendered node, so the rows below it move even though
77
+ * none of them is in the window, and so the row keeps its height when the window comes back.
83
78
  */
84
79
  updateItemSize(key: VirtualizerKey, size: Size): boolean;
80
+ /**
81
+ * Hands a measurement to the index, when it is a root that the index places.
82
+ *
83
+ * A table's cell is measured too, but a cell does not sit among the roots — its row does, and
84
+ * the row is measured by its tallest cell, so the row's own measurement is the one that lands.
85
+ */
86
+ protected recordMeasuredSize(layoutNode: LayoutNode, height: number): void;
85
87
  protected shouldInvalidateEverything(context: InvalidationContext<Options>): boolean;
86
- /** Extends the computed region to cover `rect`, and to cover every persisted key. */
87
- protected layoutIfNeeded(rect: Rect): void;
88
88
  /**
89
- * Computes the whole layout when a key is asked about that the lazy pass never reached.
89
+ * The estimated size of a root, which is what the index places it at until it is measured.
90
+ */
91
+ protected estimatedSizeAt(index: number): number;
92
+ /** How many things the index places. The roots for a list; the body's children for a table. */
93
+ protected get placedCount(): number;
94
+ /** Points the index at the collection as it stands, which is what makes every offset answerable. */
95
+ protected configureOffsets(start?: number): void;
96
+ /**
97
+ * The roots that are rendered wherever the window is.
98
+ *
99
+ * Loaders, because a sentinel that is not in the DOM can never report that it came into view,
100
+ * so the next page would never be asked for. Persisted keys, because the roving tab stop lives
101
+ * on the focused row and losing its element drops focus to the document.
102
+ */
103
+ protected indicesPlacedOutsideTheWindow(): Set<number>;
104
+ /**
105
+ * Where the persisted keys sit among `keys`.
106
+ *
107
+ * A persisted key can be a cell as easily as a row — the roving tab stop lives on whichever
108
+ * element holds focus — and a cell needs its row placed or it has nowhere to live. So a key
109
+ * that is not one of these walks up until it finds the ancestor that is.
110
+ */
111
+ protected persistedIndices(keys: readonly VirtualizerKey[]): Set<number>;
112
+ /** Where the row at `index` sits. A lookup, for a row nobody has rendered as much as for one. */
113
+ protected rowOffset(index: number): number;
114
+ /**
115
+ * The root indices the pass places, in order.
116
+ *
117
+ * The window plus whatever has to exist outside it. There is nothing to walk to and nothing to
118
+ * account for afterwards: a row's offset is a lookup, so the rows above and below the window
119
+ * cost the pass nothing at all.
120
+ */
121
+ protected windowedIndices(rect: Rect): number[];
122
+ /** Builds the rendered set for a window, and drops what that window has left behind. */
123
+ protected layoutFor(rect: Rect): void;
124
+ /**
125
+ * Drops the rows the window has moved away from.
126
+ *
127
+ * Only rows and their cells: a table's header, its columns and its body are placed once and
128
+ * read by everything else, and a row that something still depends on — the one holding the
129
+ * roving tab stop — has to keep its element.
130
+ */
131
+ protected pruneLayoutNodes(): void;
132
+ /**
133
+ * Places a key the windowed pass never reached.
90
134
  *
91
- * Pressing End, or restoring focus to a selected row, asks about a key at an arbitrary offset;
92
- * there is no way to know where it sits without laying out everything above it.
135
+ * Pressing End, or restoring focus to a selected row, asks about a key at an arbitrary offset.
136
+ * That offset is a lookup whatever the rows are, so the one row is placed and nothing else is.
93
137
  */
94
138
  private ensureLayoutInfo;
139
+ /** Where the index puts a node, or `null` for one it does not place. */
140
+ protected indexedOffset(node: VirtualizerNode): number | null;
95
141
  private replaceLayoutInfo;
96
142
  protected buildCollection(offset?: number): LayoutNode[];
97
143
  protected buildChild(node: VirtualizerNode, x: number, y: number, parentKey: VirtualizerKey | null): LayoutNode;
@@ -100,9 +146,9 @@ export declare class ListLayout<Options extends ListLayoutOptions = ListLayoutOp
100
146
  /**
101
147
  * Whether a cached row can be reused as it stands.
102
148
  *
103
- * Everything here has to hold: nothing global was invalidated, the datum is the same object,
104
- * the row is at the same offset, it sits inside the known-good region, and the part of it that
105
- * was computed covers the part now being asked about.
149
+ * Three things: nothing global was invalidated, the datum is the same object, and the row is
150
+ * still at the same offset. There is no region to be inside of any more a row's offset comes
151
+ * from the index, so being at the offset the index gives it *is* the whole of being current.
106
152
  */
107
153
  protected isValid(node: VirtualizerNode, y: number): boolean;
108
154
  protected buildLoader(node: VirtualizerNode, x: number, y: number): LayoutNode;