@octanejs/aria 0.0.5 → 0.0.6

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 (120) hide show
  1. package/package.json +3 -3
  2. package/src/components/Table.ts +2618 -0
  3. package/src/components/Tree.ts +1450 -0
  4. package/src/components/TreeDropTargetDelegate.ts +363 -0
  5. package/src/components/index.ts +57 -0
  6. package/src/grid/GridKeyboardDelegate.ts +514 -0
  7. package/src/grid/useGrid.ts +263 -0
  8. package/src/grid/useGridCell.ts +346 -0
  9. package/src/grid/useGridRow.ts +108 -0
  10. package/src/grid/useGridRowGroup.ts +29 -0
  11. package/src/grid/utils.ts +24 -0
  12. package/src/index.ts +38 -0
  13. package/src/intl/autocomplete/index.ts +9 -2
  14. package/src/intl/breadcrumbs/index.ts +9 -2
  15. package/src/intl/combobox/index.ts +9 -2
  16. package/src/intl/compileMessages.ts +356 -0
  17. package/src/intl/grid/index.ts +9 -2
  18. package/src/intl/gridlist/index.ts +9 -2
  19. package/src/intl/menu/index.ts +9 -2
  20. package/src/intl/numberfield/index.ts +9 -2
  21. package/src/intl/overlays/index.ts +9 -2
  22. package/src/intl/searchfield/index.ts +9 -2
  23. package/src/intl/spinbutton/index.ts +9 -2
  24. package/src/intl/table/ar-AE.json +13 -0
  25. package/src/intl/table/bg-BG.json +13 -0
  26. package/src/intl/table/cs-CZ.json +13 -0
  27. package/src/intl/table/da-DK.json +13 -0
  28. package/src/intl/table/de-DE.json +13 -0
  29. package/src/intl/table/el-GR.json +13 -0
  30. package/src/intl/table/en-US.json +13 -0
  31. package/src/intl/table/es-ES.json +13 -0
  32. package/src/intl/table/et-EE.json +13 -0
  33. package/src/intl/table/fi-FI.json +13 -0
  34. package/src/intl/table/fr-FR.json +13 -0
  35. package/src/intl/table/he-IL.json +13 -0
  36. package/src/intl/table/hr-HR.json +13 -0
  37. package/src/intl/table/hu-HU.json +13 -0
  38. package/src/intl/table/index.ts +82 -0
  39. package/src/intl/table/it-IT.json +13 -0
  40. package/src/intl/table/ja-JP.json +13 -0
  41. package/src/intl/table/ko-KR.json +13 -0
  42. package/src/intl/table/lt-LT.json +13 -0
  43. package/src/intl/table/lv-LV.json +13 -0
  44. package/src/intl/table/nb-NO.json +13 -0
  45. package/src/intl/table/nl-NL.json +13 -0
  46. package/src/intl/table/pl-PL.json +13 -0
  47. package/src/intl/table/pt-BR.json +13 -0
  48. package/src/intl/table/pt-PT.json +13 -0
  49. package/src/intl/table/ro-RO.json +13 -0
  50. package/src/intl/table/ru-RU.json +13 -0
  51. package/src/intl/table/sk-SK.json +13 -0
  52. package/src/intl/table/sl-SI.json +13 -0
  53. package/src/intl/table/sr-SP.json +13 -0
  54. package/src/intl/table/sv-SE.json +13 -0
  55. package/src/intl/table/tr-TR.json +13 -0
  56. package/src/intl/table/uk-UA.json +13 -0
  57. package/src/intl/table/zh-CN.json +13 -0
  58. package/src/intl/table/zh-TW.json +13 -0
  59. package/src/intl/tag/index.ts +9 -2
  60. package/src/intl/tree/ar-AE.json +4 -0
  61. package/src/intl/tree/bg-BG.json +4 -0
  62. package/src/intl/tree/cs-CZ.json +4 -0
  63. package/src/intl/tree/da-DK.json +4 -0
  64. package/src/intl/tree/de-DE.json +4 -0
  65. package/src/intl/tree/el-GR.json +4 -0
  66. package/src/intl/tree/en-US.json +4 -0
  67. package/src/intl/tree/es-ES.json +4 -0
  68. package/src/intl/tree/et-EE.json +4 -0
  69. package/src/intl/tree/fi-FI.json +4 -0
  70. package/src/intl/tree/fr-FR.json +4 -0
  71. package/src/intl/tree/he-IL.json +4 -0
  72. package/src/intl/tree/hr-HR.json +4 -0
  73. package/src/intl/tree/hu-HU.json +4 -0
  74. package/src/intl/tree/index.ts +82 -0
  75. package/src/intl/tree/it-IT.json +4 -0
  76. package/src/intl/tree/ja-JP.json +4 -0
  77. package/src/intl/tree/ko-KR.json +4 -0
  78. package/src/intl/tree/lt-LT.json +4 -0
  79. package/src/intl/tree/lv-LV.json +4 -0
  80. package/src/intl/tree/nb-NO.json +4 -0
  81. package/src/intl/tree/nl-NL.json +4 -0
  82. package/src/intl/tree/pl-PL.json +4 -0
  83. package/src/intl/tree/pt-BR.json +4 -0
  84. package/src/intl/tree/pt-PT.json +4 -0
  85. package/src/intl/tree/ro-RO.json +4 -0
  86. package/src/intl/tree/ru-RU.json +4 -0
  87. package/src/intl/tree/sk-SK.json +4 -0
  88. package/src/intl/tree/sl-SI.json +4 -0
  89. package/src/intl/tree/sr-SP.json +4 -0
  90. package/src/intl/tree/sv-SE.json +4 -0
  91. package/src/intl/tree/tr-TR.json +4 -0
  92. package/src/intl/tree/uk-UA.json +4 -0
  93. package/src/intl/tree/zh-CN.json +4 -0
  94. package/src/intl/tree/zh-TW.json +4 -0
  95. package/src/stately/grid/GridCollection.ts +200 -0
  96. package/src/stately/grid/useGridState.ts +160 -0
  97. package/src/stately/index.ts +43 -0
  98. package/src/stately/table/Cell.ts +49 -0
  99. package/src/stately/table/Column.ts +121 -0
  100. package/src/stately/table/Row.ts +145 -0
  101. package/src/stately/table/TableBody.ts +66 -0
  102. package/src/stately/table/TableCollection.ts +390 -0
  103. package/src/stately/table/TableColumnLayout.ts +148 -0
  104. package/src/stately/table/TableHeader.ts +65 -0
  105. package/src/stately/table/TableUtils.ts +269 -0
  106. package/src/stately/table/useTableColumnResizeState.ts +202 -0
  107. package/src/stately/table/useTableState.ts +235 -0
  108. package/src/stately/table/useTreeGridState.ts +248 -0
  109. package/src/table/TableKeyboardDelegate.ts +205 -0
  110. package/src/table/useTable.ts +175 -0
  111. package/src/table/useTableCell.ts +81 -0
  112. package/src/table/useTableColumnHeader.ts +155 -0
  113. package/src/table/useTableColumnResize.ts +374 -0
  114. package/src/table/useTableHeaderRow.ts +57 -0
  115. package/src/table/useTableRow.ts +198 -0
  116. package/src/table/useTableRowGroup.ts +13 -0
  117. package/src/table/useTableSelectionCheckbox.ts +105 -0
  118. package/src/table/utils.ts +42 -0
  119. package/src/tree/useTree.ts +76 -0
  120. package/src/tree/useTreeItem.ts +109 -0
@@ -0,0 +1,363 @@
1
+ // Ported from react-aria-components (source: .react-spectrum/packages/react-aria-components/src/TreeDropTargetDelegate.ts).
2
+ // The geometry/target-resolution logic is verbatim. All referenced types
3
+ // (Direction/DropTarget/DropTargetDelegate/ItemDropTarget/RootDropTarget) are the
4
+ // real @react-types/shared types, exactly as upstream. PHASE-7: this delegate is
5
+ // only exercised through consumer-provided `dragAndDropHooks` (the dnd engine),
6
+ // which cannot be constructed until `useDragAndDrop` is ported — Tree wires it up
7
+ // in its inert dnd branch.
8
+ import type {
9
+ Direction,
10
+ DropTarget,
11
+ DropTargetDelegate,
12
+ ItemDropTarget,
13
+ Key,
14
+ Node,
15
+ RootDropTarget,
16
+ } from '@react-types/shared';
17
+
18
+ interface TreeCollection<T> extends Iterable<Node<T>> {
19
+ getItem(key: Key): Node<T> | null;
20
+ getChildren?(key: Key): Iterable<Node<T>>;
21
+ getKeyAfter(key: Key): Key | null;
22
+ getKeyBefore(key: Key): Key | null;
23
+ }
24
+
25
+ interface TreeState<T> {
26
+ collection: TreeCollection<T>;
27
+ expandedKeys: Set<Key>;
28
+ }
29
+
30
+ interface PointerTracking {
31
+ lastY: number;
32
+ lastX: number;
33
+ yDirection: 'up' | 'down' | null;
34
+ xDirection: 'left' | 'right' | null;
35
+ boundaryContext: {
36
+ parentKey: Key;
37
+ lastSwitchY: number;
38
+ lastSwitchX: number;
39
+ preferredTargetIndex?: number;
40
+ } | null;
41
+ }
42
+
43
+ const X_SWITCH_THRESHOLD = 10;
44
+ const Y_SWITCH_THRESHOLD = 5;
45
+ export class TreeDropTargetDelegate<T> {
46
+ private delegate: DropTargetDelegate | null = null;
47
+ private state: TreeState<T> | null = null;
48
+ private direction: Direction = 'ltr';
49
+ private pointerTracking: PointerTracking = {
50
+ lastY: 0,
51
+ lastX: 0,
52
+ yDirection: null,
53
+ xDirection: null,
54
+ boundaryContext: null,
55
+ };
56
+
57
+ setup(delegate: DropTargetDelegate, state: TreeState<T>, direction: Direction): void {
58
+ this.delegate = delegate;
59
+ this.state = state;
60
+ this.direction = direction;
61
+ }
62
+
63
+ getDropTargetFromPoint(
64
+ x: number,
65
+ y: number,
66
+ isValidDropTarget: (target: DropTarget) => boolean,
67
+ ): DropTarget | null {
68
+ let baseTarget = this.delegate!.getDropTargetFromPoint(x, y, isValidDropTarget);
69
+ if (!baseTarget || baseTarget.type === 'root') {
70
+ return baseTarget;
71
+ }
72
+
73
+ return this.resolveDropTarget(baseTarget, x, y, isValidDropTarget);
74
+ }
75
+
76
+ private resolveDropTarget(
77
+ target: ItemDropTarget,
78
+ x: number,
79
+ y: number,
80
+ isValidDropTarget: (target: DropTarget) => boolean,
81
+ ): RootDropTarget | ItemDropTarget | null {
82
+ let tracking = this.pointerTracking;
83
+
84
+ // Calculate movement directions
85
+ let deltaY = y - tracking.lastY;
86
+ let deltaX = x - tracking.lastX;
87
+ let currentYMovement: 'up' | 'down' | null = tracking.yDirection;
88
+ let currentXMovement: 'left' | 'right' | null = tracking.xDirection;
89
+
90
+ if (Math.abs(deltaY) > Y_SWITCH_THRESHOLD) {
91
+ currentYMovement = deltaY > 0 ? 'down' : 'up';
92
+ tracking.yDirection = currentYMovement;
93
+ tracking.lastY = y;
94
+ }
95
+
96
+ if (Math.abs(deltaX) > X_SWITCH_THRESHOLD) {
97
+ currentXMovement = deltaX > 0 ? 'right' : 'left';
98
+ tracking.xDirection = currentXMovement;
99
+ tracking.lastX = x;
100
+ }
101
+
102
+ // Normalize to 'after'
103
+ if (target.dropPosition === 'before') {
104
+ let keyBefore = this.state!.collection.getKeyBefore(target.key);
105
+
106
+ while (keyBefore != null) {
107
+ let node = this.state!.collection.getItem(keyBefore);
108
+ if (node?.type === 'item') {
109
+ break;
110
+ }
111
+ keyBefore = node?.parentKey ?? null;
112
+ }
113
+ if (keyBefore != null) {
114
+ let convertedTarget = {
115
+ type: 'item',
116
+ key: keyBefore,
117
+ dropPosition: 'after',
118
+ } as const;
119
+
120
+ if (isValidDropTarget(convertedTarget)) {
121
+ target = convertedTarget;
122
+ }
123
+ }
124
+ }
125
+
126
+ let potentialTargets = this.getPotentialTargets(target, isValidDropTarget);
127
+
128
+ if (potentialTargets.length === 0) {
129
+ return { type: 'root' };
130
+ }
131
+
132
+ let resolvedItemTarget: ItemDropTarget;
133
+ if (potentialTargets.length > 1) {
134
+ resolvedItemTarget = this.selectTarget(
135
+ potentialTargets,
136
+ target,
137
+ x,
138
+ y,
139
+ currentYMovement,
140
+ currentXMovement,
141
+ );
142
+ } else {
143
+ resolvedItemTarget = potentialTargets[0];
144
+ // Reset boundary context since we're not in a boundary case
145
+ tracking.boundaryContext = null;
146
+ }
147
+
148
+ return resolvedItemTarget;
149
+ }
150
+
151
+ // Returns potential targets for an ambiguous drop position (e.g. after the last child of a parent, or after the parent itself)
152
+ // Ordered by level, from innermost to outermost.
153
+ private getPotentialTargets(
154
+ originalTarget: ItemDropTarget,
155
+ isValidDropTarget: (target: DropTarget) => boolean,
156
+ ): ItemDropTarget[] {
157
+ if (originalTarget.dropPosition === 'on') {
158
+ return [originalTarget];
159
+ }
160
+
161
+ let target = originalTarget;
162
+ let collection = this.state!.collection;
163
+
164
+ let currentItem = collection.getItem(target.key);
165
+ while (currentItem && currentItem?.type !== 'item' && currentItem.nextKey != null) {
166
+ target.key = currentItem.nextKey;
167
+ currentItem = collection.getItem(currentItem.nextKey);
168
+ }
169
+
170
+ let potentialTargets = [target];
171
+
172
+ // If target has children and is expanded, use "before first child"
173
+ if (
174
+ currentItem &&
175
+ currentItem.hasChildNodes &&
176
+ this.state!.expandedKeys.has(currentItem.key) &&
177
+ collection.getChildren &&
178
+ target.dropPosition === 'after'
179
+ ) {
180
+ // Find the first item child (traverse keys directly instead of using collection.getChildren, which may only include cells).
181
+ let firstChildItemNode =
182
+ currentItem.firstChildKey != null ? collection.getItem(currentItem.firstChildKey) : null;
183
+ while (firstChildItemNode && firstChildItemNode.type !== 'item') {
184
+ firstChildItemNode =
185
+ firstChildItemNode.nextKey != null
186
+ ? collection.getItem(firstChildItemNode.nextKey)
187
+ : null;
188
+ }
189
+
190
+ if (firstChildItemNode?.type === 'item') {
191
+ const beforeFirstChildTarget = {
192
+ type: 'item',
193
+ key: firstChildItemNode.key,
194
+ dropPosition: 'before',
195
+ } as const;
196
+
197
+ if (isValidDropTarget(beforeFirstChildTarget)) {
198
+ return [beforeFirstChildTarget];
199
+ } else {
200
+ return [];
201
+ }
202
+ }
203
+ }
204
+
205
+ if (currentItem?.nextKey != null) {
206
+ return [originalTarget];
207
+ }
208
+
209
+ // Walk up the parent chain to find ancestors that are the last child at their level
210
+ let parentKey = currentItem?.parentKey;
211
+ let ancestorTargets: ItemDropTarget[] = [];
212
+
213
+ while (parentKey != null) {
214
+ let parentItem = collection.getItem(parentKey);
215
+ let nextItem = parentItem?.nextKey != null ? collection.getItem(parentItem.nextKey) : null;
216
+ let isLastChildAtLevel = !nextItem || nextItem.parentKey !== parentKey;
217
+
218
+ if (isLastChildAtLevel) {
219
+ let afterParentTarget = {
220
+ type: 'item',
221
+ key: parentKey,
222
+ dropPosition: 'after',
223
+ } as const;
224
+
225
+ if (isValidDropTarget(afterParentTarget)) {
226
+ ancestorTargets.push(afterParentTarget);
227
+ }
228
+ if (nextItem) {
229
+ break;
230
+ }
231
+ }
232
+
233
+ parentKey = parentItem?.parentKey;
234
+ }
235
+
236
+ if (ancestorTargets.length > 0) {
237
+ potentialTargets.push(...ancestorTargets);
238
+ }
239
+
240
+ // Handle converting "after" to "before next" for non-ambiguous cases
241
+ if (potentialTargets.length === 1) {
242
+ let nextKey = collection.getKeyAfter(target.key);
243
+ let nextNode = nextKey != null ? collection.getItem(nextKey) : null;
244
+ if (
245
+ nextKey != null &&
246
+ nextNode &&
247
+ currentItem &&
248
+ nextNode.level != null &&
249
+ currentItem.level != null &&
250
+ nextNode.level > currentItem.level
251
+ ) {
252
+ let beforeTarget = {
253
+ type: 'item',
254
+ key: nextKey,
255
+ dropPosition: 'before',
256
+ } as const;
257
+ if (isValidDropTarget(beforeTarget)) {
258
+ return [beforeTarget];
259
+ }
260
+ }
261
+ }
262
+
263
+ return potentialTargets.filter(isValidDropTarget);
264
+ }
265
+
266
+ private selectTarget(
267
+ potentialTargets: ItemDropTarget[],
268
+ originalTarget: ItemDropTarget,
269
+ x: number,
270
+ y: number,
271
+ currentYMovement: 'up' | 'down' | null,
272
+ currentXMovement: 'left' | 'right' | null,
273
+ ): ItemDropTarget {
274
+ if (potentialTargets.length < 2) {
275
+ return potentialTargets[0];
276
+ }
277
+
278
+ let tracking = this.pointerTracking;
279
+ let currentItem = this.state!.collection.getItem(originalTarget.key);
280
+ let parentKey = currentItem?.parentKey;
281
+
282
+ if (parentKey == null) {
283
+ return potentialTargets[0];
284
+ }
285
+
286
+ // More than 1 potential target - use Y for initial target, then X for switching levels
287
+ // Initialize boundary context if needed
288
+ if (!tracking.boundaryContext || tracking.boundaryContext.parentKey !== parentKey) {
289
+ // If entering from below, start with outer-most
290
+ let initialTargetIndex = tracking.yDirection === 'up' ? potentialTargets.length - 1 : 0;
291
+ tracking.boundaryContext = {
292
+ parentKey,
293
+ preferredTargetIndex: initialTargetIndex,
294
+ lastSwitchY: y,
295
+ lastSwitchX: x,
296
+ };
297
+ }
298
+
299
+ let boundaryContext = tracking.boundaryContext;
300
+ let distanceFromLastXSwitch = Math.abs(x - boundaryContext.lastSwitchX);
301
+ let distanceFromLastYSwitch = Math.abs(y - boundaryContext.lastSwitchY);
302
+
303
+ // Switch between targets based on Y movement
304
+ if (distanceFromLastYSwitch > Y_SWITCH_THRESHOLD && currentYMovement) {
305
+ let currentIndex = boundaryContext.preferredTargetIndex || 0;
306
+
307
+ if (currentYMovement === 'down' && currentIndex === 0) {
308
+ // Moving down from inner-most, switch to outer-most
309
+ boundaryContext.preferredTargetIndex = potentialTargets.length - 1;
310
+ } else if (currentYMovement === 'up' && currentIndex === potentialTargets.length - 1) {
311
+ // Moving up from outer-most, switch to inner-most
312
+ boundaryContext.preferredTargetIndex = 0;
313
+ }
314
+
315
+ // Reset x tracking so that moving diagonally doesn't cause flickering.
316
+ tracking.xDirection = null;
317
+ }
318
+
319
+ // X movement controls level selection
320
+ if (distanceFromLastXSwitch > X_SWITCH_THRESHOLD && currentXMovement) {
321
+ let currentTargetIndex = boundaryContext.preferredTargetIndex || 0;
322
+
323
+ if (currentXMovement === 'left') {
324
+ if (this.direction === 'ltr') {
325
+ // LTR: left = move to higher level in tree (increase index)
326
+ if (currentTargetIndex < potentialTargets.length - 1) {
327
+ boundaryContext.preferredTargetIndex = currentTargetIndex + 1;
328
+ boundaryContext.lastSwitchX = x;
329
+ }
330
+ } else {
331
+ // RTL: left = move to lower level in tree (decrease index)
332
+ if (currentTargetIndex > 0) {
333
+ boundaryContext.preferredTargetIndex = currentTargetIndex - 1;
334
+ boundaryContext.lastSwitchX = x;
335
+ }
336
+ }
337
+ } else if (currentXMovement === 'right') {
338
+ if (this.direction === 'ltr') {
339
+ // LTR: right = move to lower level in tree (decrease index)
340
+ if (currentTargetIndex > 0) {
341
+ boundaryContext.preferredTargetIndex = currentTargetIndex - 1;
342
+ boundaryContext.lastSwitchX = x;
343
+ }
344
+ } else {
345
+ // RTL: right = move to higher level in tree (increase index)
346
+ if (currentTargetIndex < potentialTargets.length - 1) {
347
+ boundaryContext.preferredTargetIndex = currentTargetIndex + 1;
348
+ boundaryContext.lastSwitchX = x;
349
+ }
350
+ }
351
+ }
352
+
353
+ // Reset y tracking so that moving diagonally doesn't cause flickering.
354
+ tracking.yDirection = null;
355
+ }
356
+
357
+ let targetIndex = Math.max(
358
+ 0,
359
+ Math.min(boundaryContext.preferredTargetIndex || 0, potentialTargets.length - 1),
360
+ );
361
+ return potentialTargets[targetIndex];
362
+ }
363
+ }
@@ -300,3 +300,60 @@ export type { VisuallyHiddenProps } from '../visually-hidden/VisuallyHidden';
300
300
  export type { Placement } from '../overlays/useOverlayPosition';
301
301
  export { useFilter } from '../i18n/useFilter';
302
302
  export type { Filter } from '../i18n/useFilter';
303
+
304
+ // tree + table (Tree/Table phase)
305
+ export {
306
+ TreeLoadMoreItem,
307
+ Tree,
308
+ TreeItem,
309
+ TreeContext,
310
+ TreeItemContent,
311
+ TreeHeader,
312
+ TreeSection,
313
+ TreeStateContext,
314
+ } from './Tree';
315
+ export type {
316
+ TreeProps,
317
+ TreeRenderProps,
318
+ TreeEmptyStateRenderProps,
319
+ TreeItemProps,
320
+ TreeItemRenderProps,
321
+ TreeItemContentProps,
322
+ TreeItemContentRenderProps,
323
+ TreeLoadMoreItemProps,
324
+ TreeLoadMoreItemRenderProps,
325
+ } from './Tree';
326
+ export {
327
+ TableLoadMoreItem,
328
+ Table,
329
+ Row,
330
+ Cell,
331
+ Column,
332
+ ColumnResizer,
333
+ TableHeader,
334
+ TableBody,
335
+ TableContext,
336
+ ResizableTableContainer,
337
+ useTableOptions,
338
+ TableStateContext,
339
+ TableColumnResizeStateContext,
340
+ TableFooter,
341
+ } from './Table';
342
+ export type {
343
+ TableProps,
344
+ TableRenderProps,
345
+ TableHeaderProps,
346
+ TableBodyProps,
347
+ TableBodyRenderProps,
348
+ ResizableTableContainerProps,
349
+ ColumnProps,
350
+ ColumnRenderProps,
351
+ ColumnResizerProps,
352
+ ColumnResizerRenderProps,
353
+ RowProps,
354
+ RowRenderProps,
355
+ CellProps,
356
+ CellRenderProps,
357
+ TableLoadMoreItemProps,
358
+ TableFooterProps,
359
+ } from './Table';