@octanejs/aria 0.0.47 → 0.0.49

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 (54) hide show
  1. package/package.json +4 -4
  2. package/src/collections/CollectionBuilder.ts +7 -7
  3. package/src/collections/Hidden.ts +1 -1
  4. package/src/combobox/useComboBox.tsx +5 -0
  5. package/src/components/Breadcrumbs.ts +2 -2
  6. package/src/components/Button.ts +1 -1
  7. package/src/components/Calendar.tsx +2 -4
  8. package/src/components/Checkbox.ts +1 -1
  9. package/src/components/ColorSwatchPicker.tsx +2 -2
  10. package/src/components/ComboBox.ts +1 -1
  11. package/src/components/Disclosure.ts +1 -1
  12. package/src/components/Form.ts +2 -2
  13. package/src/components/ListBox.ts +1 -1
  14. package/src/components/Meter.ts +1 -1
  15. package/src/components/Popover.ts +3 -3
  16. package/src/components/ProgressBar.ts +1 -1
  17. package/src/components/RadioGroup.ts +1 -1
  18. package/src/components/Select.ts +1 -1
  19. package/src/components/SharedElementTransition.ts +1 -1
  20. package/src/components/Table.ts +3 -3
  21. package/src/components/Tabs.ts +2 -2
  22. package/src/components/TagGroup.ts +1 -1
  23. package/src/components/Toast.tsx +2 -2
  24. package/src/components/ToggleButton.ts +1 -1
  25. package/src/components/ToggleButtonGroup.ts +1 -1
  26. package/src/components/Tooltip.ts +1 -1
  27. package/src/components/Tree.ts +2 -2
  28. package/src/components/Virtualizer.tsx +6 -6
  29. package/src/components/utils.ts +2 -2
  30. package/src/dialog/useDialog.ts +1 -1
  31. package/src/focus/FocusScope.ts +1 -1
  32. package/src/grid/useGridCell.tsx +5 -0
  33. package/src/gridlist/useGridListItem.tsx +8 -7
  34. package/src/i18n/I18nProvider.ts +2 -2
  35. package/src/interactions/PressResponder.ts +2 -2
  36. package/src/interactions/context.ts +1 -1
  37. package/src/interactions/useFocusable.ts +1 -1
  38. package/src/interactions/useKeyboard.ts +5 -5
  39. package/src/menu/useMenuTrigger.tsx +5 -0
  40. package/src/menu/useSubmenuTrigger.tsx +5 -0
  41. package/src/numberfield/useNumberField.tsx +5 -1
  42. package/src/overlays/Overlay.ts +2 -2
  43. package/src/overlays/PortalProvider.ts +1 -1
  44. package/src/overlays/useModal.ts +1 -1
  45. package/src/overlays/useOverlay.tsx +5 -0
  46. package/src/radio/useRadioGroup.tsx +5 -0
  47. package/src/searchfield/useSearchField.tsx +5 -0
  48. package/src/selection/useSelectableCollection.tsx +5 -1
  49. package/src/slider/useSliderThumb.tsx +5 -0
  50. package/src/spinbutton/useSpinButton.tsx +5 -0
  51. package/src/table/useTableColumnResize.tsx +5 -0
  52. package/src/tokenfield/useTokenField.tsx +1 -1
  53. package/src/utils/openLink.ts +1 -1
  54. package/src/virtualizer/VirtualizerItem.tsx +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@octanejs/aria",
3
- "version": "0.0.47",
3
+ "version": "0.0.49",
4
4
  "license": "MIT AND Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -53,10 +53,10 @@
53
53
  "clsx": "^2.1.1"
54
54
  },
55
55
  "peerDependencies": {
56
- "octane": "^0.1.51 || ^0.2.0"
56
+ "octane": "^0.1.51 || ^0.2.0 || ^0.3.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@tsrx/react": "^0.2.69",
59
+ "@tsrx/react": "^0.3.0",
60
60
  "esbuild": "^0.28.1",
61
61
  "react": "19.2.7",
62
62
  "react-aria": "3.51.0",
@@ -65,7 +65,7 @@
65
65
  "react-stately": "3.49.0",
66
66
  "typescript": "^5.9.3",
67
67
  "vitest": "^4.1.10",
68
- "octane": "0.2.7"
68
+ "octane": "0.3.0"
69
69
  },
70
70
  "scripts": {
71
71
  "exports:check": "node scripts/check-react-aria-components-exports.mjs",
@@ -80,7 +80,7 @@ export function CollectionBuilder<C extends BaseCollection<any>>(
80
80
  null,
81
81
  createElement(Hidden, {
82
82
  target: document.getRootElement(),
83
- children: createElement(CollectionDocumentContext.Provider, {
83
+ children: createElement(CollectionDocumentContext, {
84
84
  value: document,
85
85
  children: props.content,
86
86
  }),
@@ -207,7 +207,7 @@ function useSSRCollectionNode<T extends Element>(
207
207
  parentNode.ownerDocument.nodesByProps.set(props, element);
208
208
  }
209
209
 
210
- return children ? createElement(SSRContext.Provider, { value: element, children }) : null;
210
+ return children ? createElement(SSRContext, { value: element, children }) : null;
211
211
  }
212
212
 
213
213
  // The placeholder tag is the node type (`<item>`/`<section>`-style) — a valid
@@ -240,7 +240,7 @@ export function createLeafComponent<T, P extends object, E extends Element>(
240
240
  null,
241
241
  (node) =>
242
242
  // Forward FocusableContext to real DOM tree so tooltips work.
243
- createElement(FocusableContext.Provider, {
243
+ createElement(FocusableContext, {
244
244
  value: focusableProps,
245
245
  children: createElement(Component, { node }),
246
246
  }),
@@ -312,7 +312,7 @@ export function Collection<T>(props: CollectionProps<T>): any {
312
312
  subSlot(slot, 'ctx'),
313
313
  );
314
314
 
315
- return createElement(CollectionContext.Provider, { value: ctx, children });
315
+ return createElement(CollectionContext, { value: ctx, children });
316
316
  }
317
317
 
318
318
  function CollectionRoot(props: { children: any }): any {
@@ -320,9 +320,9 @@ function CollectionRoot(props: { children: any }): any {
320
320
  let doc = useContext(CollectionDocumentContext);
321
321
  let wrappedChildren = useMemo(
322
322
  () =>
323
- createElement(CollectionDocumentContext.Provider, {
323
+ createElement(CollectionDocumentContext, {
324
324
  value: null,
325
- children: createElement(ShallowRenderContext.Provider, {
325
+ children: createElement(ShallowRenderContext, {
326
326
  value: doc,
327
327
  children: props.children,
328
328
  }),
@@ -338,6 +338,6 @@ function CollectionRoot(props: { children: any }): any {
338
338
  // container, so the placeholders land in the walked tree directly.
339
339
  let isSSR = useIsSSR(subSlot(slot, 'ssr'));
340
340
  return isSSR
341
- ? createElement(SSRContext.Provider, { value: doc, children: wrappedChildren })
341
+ ? createElement(SSRContext, { value: doc, children: wrappedChildren })
342
342
  : wrappedChildren;
343
343
  }
@@ -35,7 +35,7 @@ export function Hidden(props: { children: any; target?: Element | null }): any {
35
35
  return props.children;
36
36
  }
37
37
 
38
- let children = createElement(HiddenContext.Provider, {
38
+ let children = createElement(HiddenContext, {
39
39
  value: true,
40
40
  children: props.children,
41
41
  });
@@ -47,6 +47,7 @@ import {
47
47
  import { getActiveElement, getEventTarget, nodeContains } from '../utils/shadowdom/DOMFunctions';
48
48
  import { getChildNodes } from '../upstream-exports/react-stately/private/collections/getChildNodes';
49
49
  import { getItemCount } from '../upstream-exports/react-stately/private/collections/getItemCount';
50
+ import { withSlot } from 'octane';
50
51
  import { getItemId, listData } from '../listbox/utils';
51
52
  import { getOwnerDocument } from '../utils/domHelpers';
52
53
  import intlMessages from '../intl/combobox/index';
@@ -131,6 +132,10 @@ export function useComboBox<T, M extends SelectionMode = 'single'>(
131
132
  state: ComboBoxState<T, M>,
132
133
  _slot?: symbol,
133
134
  ): ComboBoxAria<T> {
135
+ if (_slot !== undefined) {
136
+ return withSlot(_slot, useComboBox<T, M>, props, state);
137
+ }
138
+
134
139
  let {
135
140
  buttonRef,
136
141
  popoverRef,
@@ -80,7 +80,7 @@ export function Breadcrumbs<T extends object>(props: BreadcrumbsProps<T>): any {
80
80
  slot: props.slot || undefined,
81
81
  style: props.style,
82
82
  className: props.className ?? 'react-aria-Breadcrumbs',
83
- children: createElement(BreadcrumbsContext.Provider, {
83
+ children: createElement(BreadcrumbsContext, {
84
84
  value: props,
85
85
  children: createElement(CollectionRoot, { collection }),
86
86
  }),
@@ -161,7 +161,7 @@ export const Breadcrumb: (props: BreadcrumbProps & { ref?: any }) => any = creat
161
161
  ref,
162
162
  'data-disabled': isDisabled || isCurrent || undefined,
163
163
  'data-current': isCurrent || undefined,
164
- children: createElement(LinkContext.Provider, {
164
+ children: createElement(LinkContext, {
165
165
  value: linkProps as any,
166
166
  children: renderProps.children,
167
167
  }),
@@ -183,7 +183,7 @@ export const Button = /*#__PURE__*/ createHideableComponent(function Button(
183
183
  'data-focused': isFocused || undefined,
184
184
  'data-pending': isPending || undefined,
185
185
  'data-focus-visible': isFocusVisible || undefined,
186
- children: createElement(ProgressBarContext.Provider, {
186
+ children: createElement(ProgressBarContext, {
187
187
  value: { id: progressId },
188
188
  children: renderProps.children,
189
189
  }),
@@ -523,9 +523,7 @@ export const CalendarGrid = /*#__PURE__*/ (forwardRef as any)(function CalendarG
523
523
  let DOMProps = filterDOMProps(props, { global: true });
524
524
 
525
525
  return (
526
- <InternalCalendarGridContext.Provider
527
- value={{ headerProps, weekDays, startDate, weeksInMonth }}
528
- >
526
+ <InternalCalendarGridContext value={{ headerProps, weekDays, startDate, weeksInMonth }}>
529
527
  <dom.table
530
528
  render={props.render}
531
529
  {...mergeProps(DOMProps, gridProps)}
@@ -545,7 +543,7 @@ export const CalendarGrid = /*#__PURE__*/ (forwardRef as any)(function CalendarG
545
543
  </>
546
544
  )}
547
545
  </dom.table>
548
- </InternalCalendarGridContext.Provider>
546
+ </InternalCalendarGridContext>
549
547
  );
550
548
  });
551
549
 
@@ -496,7 +496,7 @@ export function Checkbox(props: CheckboxProps): any {
496
496
  );
497
497
  let [aria, inputRef] = useCheckboxAria(props, userProvidedInputRef, subSlot(slot, 'aria'));
498
498
 
499
- return createElement(InternalCheckboxContext.Provider, {
499
+ return createElement(InternalCheckboxContext, {
500
500
  value: {
501
501
  ...aria,
502
502
  inputRef,
@@ -96,7 +96,7 @@ export const ColorSwatchPicker = forwardRef(function ColorSwatchPicker(
96
96
  }}
97
97
  disallowEmptySelection
98
98
  >
99
- <ColorMapContext.Provider value={colorMap}>{props.children}</ColorMapContext.Provider>
99
+ <ColorMapContext value={colorMap}>{props.children}</ColorMapContext>
100
100
  </ListBox>
101
101
  );
102
102
  });
@@ -169,7 +169,7 @@ export const ColorSwatchPickerItem = forwardRef(function ColorSwatchPickerItem(
169
169
  style={wrap(props.style)}
170
170
  >
171
171
  {composeRenderProps(wrap(props.children), (children) => (
172
- <ColorSwatchContext.Provider value={{ color }}>{children}</ColorSwatchContext.Provider>
172
+ <ColorSwatchContext value={{ color }}>{children}</ColorSwatchContext>
173
173
  ))}
174
174
  </ListBoxItem>
175
175
  );
@@ -162,7 +162,7 @@ export const ComboBox: <T, M extends SelectionMode = 'single'>(
162
162
  } = props;
163
163
  let content = useMemo(
164
164
  () =>
165
- createElement(ListBoxContext.Provider, {
165
+ createElement(ListBoxContext, {
166
166
  value: { items: props.items ?? props.defaultItems },
167
167
  children:
168
168
  typeof children === 'function' && !isChildrenBlock(children)
@@ -99,7 +99,7 @@ export function DisclosureGroup(props: DisclosureGroupProps): any {
99
99
  ...renderProps,
100
100
  ref,
101
101
  'data-disabled': props.isDisabled || undefined,
102
- children: createElement(DisclosureGroupStateContext.Provider, {
102
+ children: createElement(DisclosureGroupStateContext, {
103
103
  value: state,
104
104
  children: renderProps.children,
105
105
  }),
@@ -54,9 +54,9 @@ export function Form(props: FormProps): any {
54
54
  ...domProps,
55
55
  ref,
56
56
  className: className || 'react-aria-Form',
57
- children: createElement(FormContext.Provider, {
57
+ children: createElement(FormContext, {
58
58
  value: { ...props, validationBehavior },
59
- children: createElement(FormValidationContext.Provider, {
59
+ children: createElement(FormValidationContext, {
60
60
  value: validationErrors ?? {},
61
61
  children,
62
62
  }),
@@ -530,7 +530,7 @@ function ListBoxSectionInner<T>(
530
530
  return createElement(dom.section, {
531
531
  ...mergeProps(DOMProps, renderProps, groupProps),
532
532
  ref,
533
- children: createElement(HeaderContext.Provider, {
533
+ children: createElement(HeaderContext, {
534
534
  value: { ...headingProps, ref: headingRef },
535
535
  children: createElement(CollectionBranch, {
536
536
  collection: state.collection,
@@ -94,7 +94,7 @@ export function Meter(props: MeterProps): any {
94
94
  ...mergeProps(DOMProps, renderProps, meterProps),
95
95
  ref,
96
96
  slot: props.slot || undefined,
97
- children: createElement(LabelContext.Provider, {
97
+ children: createElement(LabelContext, {
98
98
  value: { ...labelProps, ref: labelRef, elementType: 'span' },
99
99
  children: renderProps.children,
100
100
  }),
@@ -292,7 +292,7 @@ function PopoverInner(allProps: PopoverInnerProps): any {
292
292
  let children = renderProps.children;
293
293
  if (clearContexts) {
294
294
  for (let Context of clearContexts) {
295
- children = createElement((Context as any).Provider, { value: null, children });
295
+ children = createElement(Context as any, { value: null, children });
296
296
  }
297
297
  }
298
298
  return children;
@@ -353,7 +353,7 @@ function PopoverInner(allProps: PopoverInnerProps): any {
353
353
  'data-exiting': isExiting || undefined,
354
354
  },
355
355
  !props.isNonModal ? createElement(DismissButton, { onDismiss: state.close }) : null,
356
- createElement(OverlayArrowContext.Provider, {
356
+ createElement(OverlayArrowContext, {
357
357
  value: { ...arrowProps, placement, ref: arrowRef } as any,
358
358
  children,
359
359
  }),
@@ -381,7 +381,7 @@ function PopoverInner(allProps: PopoverInnerProps): any {
381
381
  createElement('div', {
382
382
  ref: containerRef,
383
383
  style: { display: 'contents' },
384
- children: createElement(PopoverGroupContext.Provider, {
384
+ children: createElement(PopoverGroupContext, {
385
385
  value: containerRef,
386
386
  children: overlay,
387
387
  }),
@@ -112,7 +112,7 @@ export function ProgressBar(props: ProgressBarProps): any {
112
112
  ...mergeProps(DOMProps, renderProps, progressBarProps),
113
113
  ref,
114
114
  slot: props.slot || undefined,
115
- children: createElement(LabelContext.Provider, {
115
+ children: createElement(LabelContext, {
116
116
  value: { ...labelProps, ref: labelRef, elementType: 'span' },
117
117
  children: renderProps.children,
118
118
  }),
@@ -370,7 +370,7 @@ export function Radio(props: RadioProps): any {
370
370
  subSlot(slot, 'radio'),
371
371
  );
372
372
 
373
- return createElement(InternalRadioContext.Provider, {
373
+ return createElement(InternalRadioContext, {
374
374
  value: { ...aria, inputRef, defaultClassName: 'react-aria-Radio' },
375
375
  children: createElement(RadioButton, { ...props, ref } as any),
376
376
  });
@@ -505,7 +505,7 @@ export const SelectValue: <T>(props: SelectValueProps<T> & { ref?: any }) => any
505
505
  ...renderProps,
506
506
  'data-placeholder': state.selectedItems.length === 0 || undefined,
507
507
  // clear description and error message slots
508
- children: createElement(TextContext.Provider, {
508
+ children: createElement(TextContext, {
509
509
  value: undefined,
510
510
  children: renderProps.children,
511
511
  }),
@@ -35,7 +35,7 @@ export interface SharedElementTransitionProps {
35
35
  export function SharedElementTransition(props: SharedElementTransitionProps): any {
36
36
  const slot = S('SharedElementTransition');
37
37
  let ref = useRef<{ [name: string]: Snapshot }>({}, subSlot(slot, 'scope'));
38
- return createElement(SharedElementContext.Provider, { value: ref, children: props.children });
38
+ return createElement(SharedElementContext, { value: ref, children: props.children });
39
39
  }
40
40
 
41
41
  export interface SharedElementRenderProps {
@@ -615,7 +615,7 @@ export function ResizableTableContainer(props: ResizableTableContainerProps & {
615
615
  className: props.className || 'react-aria-ResizableTableContainer',
616
616
  style: props.style,
617
617
  onScroll: (props as any).onScroll,
618
- children: createElement(ResizableTableContainerContext.Provider, {
618
+ children: createElement(ResizableTableContainerContext, {
619
619
  value: ctx,
620
620
  children: props.children,
621
621
  }),
@@ -715,7 +715,7 @@ export function Table(props: TableProps): any {
715
715
  subSlot(slot, 'options'),
716
716
  );
717
717
 
718
- let content = createElement(TableOptionsContext.Provider, {
718
+ let content = createElement(TableOptionsContext, {
719
719
  value: ctx,
720
720
  children: createElement(Collection, props as any),
721
721
  });
@@ -2361,7 +2361,7 @@ export const Cell: (props: CellProps & { ref?: any }) => any = /*#__PURE__*/ cre
2361
2361
  'data-level': row.level + 1,
2362
2362
  'data-tree-column': cell.column!.key === state.treeColumn || undefined,
2363
2363
  'data-disabled': isDisabled || undefined,
2364
- children: createElement(CollectionRendererContext.Provider, {
2364
+ children: createElement(CollectionRendererContext, {
2365
2365
  value: DefaultCollectionRenderer,
2366
2366
  children: renderProps.children,
2367
2367
  }),
@@ -471,7 +471,7 @@ export const Tab: (props: TabProps & { ref?: any }) => any = createLeafComponent
471
471
  'data-focus-visible': isFocusVisible || undefined,
472
472
  'data-pressed': isPressed || undefined,
473
473
  'data-hovered': isHovered || undefined,
474
- children: createElement(SelectionIndicatorContext.Provider, {
474
+ children: createElement(SelectionIndicatorContext, {
475
475
  value: { isSelected },
476
476
  children: renderProps.children,
477
477
  }),
@@ -679,7 +679,7 @@ function TabPanelInner(
679
679
  [TabsContext, null],
680
680
  [TabListStateContext, null],
681
681
  ] as any,
682
- children: createElement(CollectionRendererContext.Provider, {
682
+ children: createElement(CollectionRendererContext, {
683
683
  value: DefaultCollectionRenderer,
684
684
  children: renderProps.children,
685
685
  }),
@@ -134,7 +134,7 @@ export function TagGroup(props: TagGroupProps): any {
134
134
  const slot = S('TagGroup');
135
135
  let ref: any;
136
136
  [props, ref] = useContextProps(props, (props as any).ref, TagGroupContext, subSlot(slot, 'ctx'));
137
- return createElement(ListStateContext.Provider, {
137
+ return createElement(ListStateContext, {
138
138
  value: null,
139
139
  children: createElement(CollectionBuilder, {
140
140
  content: props.children,
@@ -142,7 +142,7 @@ const ToastRegion = /*#__PURE__*/ (forwardRef as any)(function ToastRegion<T>(
142
142
  let DOMProps = filterDOMProps(props, { global: true });
143
143
 
144
144
  let region = (
145
- <ToastStateContext.Provider value={state}>
145
+ <ToastStateContext value={state}>
146
146
  <dom.div
147
147
  {...mergeProps(DOMProps, renderProps, regionProps, focusProps, hoverProps)}
148
148
  dir={direction}
@@ -164,7 +164,7 @@ const ToastRegion = /*#__PURE__*/ (forwardRef as any)(function ToastRegion<T>(
164
164
  props.children
165
165
  )}
166
166
  </dom.div>
167
- </ToastStateContext.Provider>
167
+ </ToastStateContext>
168
168
  );
169
169
 
170
170
  return state.visibleToasts.length > 0 && portalContainer
@@ -139,7 +139,7 @@ export function ToggleButton(props: ToggleButtonProps): any {
139
139
  'data-selected': isSelected || undefined,
140
140
  'data-hovered': isHovered || undefined,
141
141
  'data-focus-visible': isFocusVisible || undefined,
142
- children: createElement(SelectionIndicatorContext.Provider, {
142
+ children: createElement(SelectionIndicatorContext, {
143
143
  value: { isSelected },
144
144
  children: renderProps.children,
145
145
  }),
@@ -98,7 +98,7 @@ export function ToggleButtonGroup(props: ToggleButtonGroupProps): any {
98
98
  slot: props.slot || undefined,
99
99
  'data-orientation': props.orientation || 'horizontal',
100
100
  'data-disabled': props.isDisabled || undefined,
101
- children: createElement(ToggleGroupStateContext.Provider, {
101
+ children: createElement(ToggleGroupStateContext, {
102
102
  value: state,
103
103
  children: createElement(SharedElementTransition, { children: renderProps.children }),
104
104
  }),
@@ -239,7 +239,7 @@ function TooltipInner(
239
239
  'data-placement': placement ?? undefined,
240
240
  'data-entering': isEntering || undefined,
241
241
  'data-exiting': props.isExiting || undefined,
242
- children: createElement(OverlayArrowContext.Provider, {
242
+ children: createElement(OverlayArrowContext, {
243
243
  value: { ...arrowProps, placement, ref: arrowRef } as any,
244
244
  children: renderProps.children,
245
245
  }),
@@ -765,7 +765,7 @@ export const TreeItemContent: (props: TreeItemContentProps) => any =
765
765
  } as any,
766
766
  subSlot(slot, 'render'),
767
767
  );
768
- return createElement(CollectionRendererContext.Provider, {
768
+ return createElement(CollectionRendererContext, {
769
769
  value: DefaultCollectionRenderer,
770
770
  children: renderProps.children,
771
771
  });
@@ -1386,7 +1386,7 @@ export interface TreeSectionProps<T> extends SectionProps<T>, DOMRenderProps<'di
1386
1386
  * A TreeSection represents a section within a Tree.
1387
1387
  */
1388
1388
  export const TreeSection: <T extends object = object>(
1389
- props: GridListHeaderProps & { ref?: any },
1389
+ props: TreeSectionProps<T> & { ref?: any },
1390
1390
  ) => any = /*#__PURE__*/ createBranchComponent(SectionNode, function TreeSection<
1391
1391
  T,
1392
1392
  >(props: TreeSectionProps<T>, forwardedRef: any, item?: Node<T>): any {
@@ -87,11 +87,11 @@ export function Virtualizer<O>(props: VirtualizerProps<O>): JSX.Element {
87
87
  );
88
88
 
89
89
  return (
90
- <CollectionRendererContext.Provider value={renderer}>
91
- <VirtualizerOptionsContext.Provider value={{ layout, layoutOptions, shouldObserveItemSize }}>
90
+ <CollectionRendererContext value={renderer}>
91
+ <VirtualizerOptionsContext value={{ layout, layoutOptions, shouldObserveItemSize }}>
92
92
  {children}
93
- </VirtualizerOptionsContext.Provider>
94
- </CollectionRendererContext.Provider>
93
+ </VirtualizerOptionsContext>
94
+ </CollectionRendererContext>
95
95
  );
96
96
  }
97
97
 
@@ -141,9 +141,9 @@ function CollectionRoot({
141
141
 
142
142
  return (
143
143
  <div {...contentProps}>
144
- <VirtualizerContext.Provider value={state}>
144
+ <VirtualizerContext value={state}>
145
145
  {renderChildren(null, state.visibleViews, renderDropIndicator, shouldObserveItemSize)}
146
- </VirtualizerContext.Provider>
146
+ </VirtualizerContext>
147
147
  </div>
148
148
  );
149
149
  }
@@ -50,7 +50,7 @@ interface ProviderProps<Contexts extends readonly Context<any>[]> {
50
50
  children: ReactNode;
51
51
  }
52
52
 
53
- // No hooks (Provider nests plain Context.Provider descriptors), so no slot threading. The
53
+ // No hooks (Provider nests plain Context descriptors), so no slot threading. The
54
54
  // descriptor `{ value, children }` shape stays stable per values entry (see aria memory
55
55
  // octane-provider-children-shape-flip).
56
56
  export function Provider<const Contexts extends readonly Context<any>[]>(
@@ -58,7 +58,7 @@ export function Provider<const Contexts extends readonly Context<any>[]>(
58
58
  ): any {
59
59
  let { values, children } = props;
60
60
  for (let [Context, value] of values) {
61
- children = createElement((Context as any).Provider, { value, children });
61
+ children = createElement(Context, { value, children });
62
62
  }
63
63
 
64
64
  return children;
@@ -61,7 +61,7 @@ export function useDialog(...args: any[]): DialogAria {
61
61
  let titleId: string | undefined = useSlotId(undefined, subSlot(slot, 'title'));
62
62
  titleId = props['aria-label'] ? undefined : titleId;
63
63
 
64
- let contentId: string | undefined = useSlotId();
64
+ let contentId: string | undefined = useSlotId(undefined, subSlot(slot, 'content'));
65
65
  contentId = role === 'alertdialog' && !props['aria-describedby'] ? contentId : undefined;
66
66
 
67
67
  let isRefocusing = useRef(false, subSlot(slot, 'refocusing'));
@@ -238,7 +238,7 @@ export function FocusScope(props: FocusScopeProps): any {
238
238
  );
239
239
 
240
240
  return createElement(
241
- FocusContext.Provider,
241
+ FocusContext,
242
242
  { value },
243
243
  createElement('span', { 'data-focus-scope-start': true, hidden: true, ref: startRef }),
244
244
  children,
@@ -14,6 +14,7 @@ type DOMAttributes = Record<string, any>;
14
14
  */
15
15
 
16
16
  import { FocusableElement, Key, RefObject } from '@react-types/shared';
17
+ import { withSlot } from 'octane';
17
18
  import { focusSafely } from '../interactions/focusSafely';
18
19
  import {
19
20
  getActiveElement,
@@ -89,6 +90,10 @@ export function useGridCell<T, C extends GridCollection<T>>(
89
90
  ref: RefObject<FocusableElement | null>,
90
91
  _slot?: symbol,
91
92
  ): GridCellAria {
93
+ if (_slot !== undefined) {
94
+ return withSlot(_slot, useGridCell<T, C>, props, state, ref);
95
+ }
96
+
92
97
  let {
93
98
  node,
94
99
  isVirtualized,
@@ -27,6 +27,7 @@ import { getOwnerDocument } from '../utils/domHelpers';
27
27
  import { getRowId, listMap } from './utils';
28
28
  import { getScrollParent } from '../utils/getScrollParent';
29
29
  import { HTMLAttributes, KeyboardEvent as ReactKeyboardEvent, useRef } from '../compat/react';
30
+ import { withSlot } from 'octane';
30
31
  import { isFocusVisible } from '../interactions/useFocusVisible';
31
32
  import type { ListState } from '../upstream-exports/react-stately/useListState';
32
33
  import { mergeProps } from '../utils/mergeProps';
@@ -97,6 +98,10 @@ export function useGridListItem<T>(
97
98
  ref: RefObject<FocusableElement | null>,
98
99
  _slot?: symbol,
99
100
  ): GridListItemAria {
101
+ if (_slot !== undefined) {
102
+ return withSlot(_slot, useGridListItem<T>, props, state, ref);
103
+ }
104
+
100
105
  // Copied from useGridCell + some modifications to make it not so grid specific
101
106
  let { node, isVirtualized, focusMode = 'row', allowsArrowNavigation } = props;
102
107
 
@@ -438,16 +443,12 @@ export function useGridListItem<T>(
438
443
  rowProps.tabIndex = -1;
439
444
  }
440
445
 
441
- // we need to guard against space/enter triggering selection/row link via usePress (from itemProps) so check if propagation
442
- // is stopped. this also fixes space not working in a textfield in a tree parent row
446
+ // Keep Space/Enter on a child control from reaching the row's usePress handler. With native
447
+ // events, stopPropagation() marks cancelBubble rather than exposing isPropagationStopped().
443
448
  let baseOnKeyDown = rowProps.onKeyDown;
444
449
  rowProps.onKeyDown = (e: ReactKeyboardEvent<FocusableElement>) => {
445
450
  onKeyDown(e as ReactKeyboardEvent);
446
- if (!(
447
- 'isPropagationStopped' in e &&
448
- typeof e.isPropagationStopped === 'function' &&
449
- e.isPropagationStopped()
450
- )) {
451
+ if (!e.cancelBubble) {
451
452
  baseOnKeyDown?.(e);
452
453
  }
453
454
  };
@@ -48,7 +48,7 @@ function I18nProviderWithLocale(props: I18nProviderWithLocaleProps): any {
48
48
  subSlot(slot, 'value'),
49
49
  );
50
50
 
51
- return createElement(I18nContext.Provider, { value, children });
51
+ return createElement(I18nContext, { value, children });
52
52
  }
53
53
 
54
54
  interface I18nProviderWithDefaultLocaleProps {
@@ -63,7 +63,7 @@ function I18nProviderWithDefaultLocale(props: I18nProviderWithDefaultLocaleProps
63
63
  let { children } = props;
64
64
  let defaultLocale = useDefaultLocale(subSlot(slot, 'default'));
65
65
 
66
- return createElement(I18nContext.Provider, { value: defaultLocale, children });
66
+ return createElement(I18nContext, { value: defaultLocale, children });
67
67
  }
68
68
 
69
69
  /**
@@ -44,11 +44,11 @@ export function PressResponder(allProps: PressResponderProps): any {
44
44
  context.ref = useObjectRef(ref || prevContext?.ref, subSlot(slot, 'ref'));
45
45
  useSyncRef(prevContext, context.ref, subSlot(slot, 'sync'));
46
46
 
47
- return createElement(PressResponderContext.Provider, { value: context, children });
47
+ return createElement(PressResponderContext, { value: context, children });
48
48
  }
49
49
 
50
50
  export function ClearPressResponder({ children }: { children: any }): any {
51
51
  const slot = S('ClearPressResponder');
52
52
  let context = useMemo(() => ({ register: () => {} }), [], subSlot(slot, 'context'));
53
- return createElement(PressResponderContext.Provider, { value: context as any, children });
53
+ return createElement(PressResponderContext, { value: context as any, children });
54
54
  }
@@ -1,6 +1,6 @@
1
1
  // Ported from react-aria (source: .react-spectrum/packages/react-aria/src/interactions/context.ts).
2
2
  // octane adaptations: React.createContext → octane createContext (octane's Context is
3
- // callable-as-Provider, `.Provider` stays as an identity alias, so consumers are unchanged);
3
+ // is itself the provider component);
4
4
  // React's MutableRefObject type → a local structural alias; `displayName` is stamped through
5
5
  // a cast (octane's Context type doesn't declare it, but the runtime reads it for diagnostics).
6
6
  import type { FocusableElement } from '@react-types/shared';
@@ -90,7 +90,7 @@ export function FocusableProvider(
90
90
  ref: objRef,
91
91
  };
92
92
 
93
- return createElement(FocusableContext.Provider, { value: context, children });
93
+ return createElement(FocusableContext, { value: context, children });
94
94
  }
95
95
 
96
96
  export interface FocusableAria {
@@ -1,4 +1,3 @@
1
- import { chain } from '../utils/chain';
2
1
  import {
3
2
  createKeyboardShortcutHandler,
4
3
  type KeyboardShortcutBindings,
@@ -8,6 +7,7 @@ import { getEventTarget, nodeContains } from '../utils/shadowdom/DOMFunctions';
8
7
  // octane adaptations:
9
8
  // - `KeyboardEvents` / `DOMAttributes` from '@react-types/shared' are typed over React's
10
9
  // synthetic events; local structural aliases over native KeyboardEvent replace them.
10
+ // - Shortcut and user callbacks share the BaseEvent wrapper so both have propagation controls.
11
11
  // - Public-hook slot threading (splitSlot) per the binding convention; no octane base hooks
12
12
  // are composed here, so the slot is absorbed and unused.
13
13
  import type { BaseEvent } from './createEventHandler';
@@ -53,7 +53,8 @@ export function useKeyboard(...args: any[]): KeyboardResult {
53
53
  let onKeyUp;
54
54
  if (shortcuts) {
55
55
  let shortcutHandler = createKeyboardShortcutHandler(shortcuts);
56
- let shortcutOnKeyDown = createEventHandler<KeyboardEvent>((e) => {
56
+ onKeyDown = createEventHandler<KeyboardEvent>((e) => {
57
+ props.onKeyDown?.(e);
57
58
  // If keyboard event didn't originate from a child of the current target,
58
59
  // then it's a React event coming through a portal. We should ignore it.
59
60
  if (!nodeContains(e.currentTarget as Node, getEventTarget(e) as Element)) {
@@ -67,7 +68,8 @@ export function useKeyboard(...args: any[]): KeyboardResult {
67
68
 
68
69
  shortcutHandler(e);
69
70
  });
70
- let shortcutOnKeyUp = createEventHandler<KeyboardEvent>((e) => {
71
+ onKeyUp = createEventHandler<KeyboardEvent>((e) => {
72
+ props.onKeyUp?.(e);
71
73
  // If keyboard event didn't originate from a child of the current target,
72
74
  // then it's a React event coming through a portal. We should ignore it.
73
75
  if (!nodeContains(e.currentTarget as Node, getEventTarget(e) as Element)) {
@@ -81,8 +83,6 @@ export function useKeyboard(...args: any[]): KeyboardResult {
81
83
  // implement shortcut handler on keyup, what should the map be called? or should it be another syntax on shortcuts?
82
84
  e.continuePropagation();
83
85
  });
84
- onKeyDown = props.onKeyDown ? chain(props.onKeyDown, shortcutOnKeyDown) : shortcutOnKeyDown;
85
- onKeyUp = props.onKeyUp ? chain(props.onKeyUp, shortcutOnKeyUp) : shortcutOnKeyUp;
86
86
  } else {
87
87
  onKeyDown = createEventHandler(props.onKeyDown);
88
88
  onKeyUp = createEventHandler(props.onKeyUp);
@@ -15,6 +15,7 @@ type KeyboardEvent = BaseEvent<globalThis.KeyboardEvent>;
15
15
  */
16
16
 
17
17
  import { AriaButtonProps } from '../button/useButton';
18
+ import { withSlot } from 'octane';
18
19
  import { AriaMenuOptions } from './useMenu';
19
20
  import { FocusableElement, FocusStrategy, RefObject } from '@react-types/shared';
20
21
  import { focusWithoutScrolling } from '../utils/focusWithoutScrolling';
@@ -63,6 +64,10 @@ export function useMenuTrigger<T>(
63
64
  ref: RefObject<Element | null>,
64
65
  _slot?: symbol,
65
66
  ): MenuTriggerAria<T> {
67
+ if (_slot !== undefined) {
68
+ return withSlot(_slot, useMenuTrigger<T>, props, state, ref);
69
+ }
70
+
66
71
  let { type = 'menu', isDisabled, trigger = 'press' } = props;
67
72
 
68
73
  let menuTriggerId = useId();
@@ -13,6 +13,7 @@
13
13
  */
14
14
 
15
15
  import { AriaMenuItemProps } from './useMenuItem';
16
+ import { withSlot } from 'octane';
16
17
  import { AriaMenuOptions } from './useMenu';
17
18
  import type { AriaPopoverProps } from '../overlays/usePopover';
18
19
  import { FocusableElement, FocusStrategy, Node, PressEvent, RefObject } from '@react-types/shared';
@@ -93,6 +94,10 @@ export function useSubmenuTrigger<T>(
93
94
  ref: RefObject<FocusableElement | null>,
94
95
  _slot?: symbol,
95
96
  ): SubmenuTriggerAria<T> {
97
+ if (_slot !== undefined) {
98
+ return withSlot(_slot, useSubmenuTrigger<T>, props, state, ref);
99
+ }
100
+
96
101
  let {
97
102
  parentMenuRef,
98
103
  submenuRef,
@@ -42,7 +42,7 @@ import {
42
42
  useState,
43
43
  } from '../compat/react';
44
44
  import { filterDOMProps } from '../utils/filterDOMProps';
45
- import { flushSync } from 'octane';
45
+ import { flushSync, withSlot } from 'octane';
46
46
  import { getActiveElement, getEventTarget } from '../utils/shadowdom/DOMFunctions';
47
47
  import intlMessages from '../intl/numberfield/index';
48
48
  import { isAndroid, isIOS, isIPhone } from '../utils/platform';
@@ -110,6 +110,10 @@ export function useNumberField(
110
110
  inputRef: RefObject<HTMLInputElement | null>,
111
111
  _slot?: symbol,
112
112
  ): NumberFieldAria {
113
+ if (_slot !== undefined) {
114
+ return withSlot(_slot, useNumberField, props, state, inputRef);
115
+ }
116
+
113
117
  let {
114
118
  id,
115
119
  decrementAriaLabel,
@@ -80,9 +80,9 @@ export function Overlay(props: OverlayProps): any {
80
80
  });
81
81
  }
82
82
 
83
- contents = createElement(OverlayContext.Provider, {
83
+ contents = createElement(OverlayContext, {
84
84
  value: contextValue as OverlayContextValue,
85
- children: createElement(FocusableContext.Provider, {
85
+ children: createElement(FocusableContext, {
86
86
  value: null,
87
87
  children: createElement(ClearPressResponder, { children: contents }),
88
88
  }),
@@ -24,7 +24,7 @@ export const PortalContext = createContext<PortalProviderContextValue>({});
24
24
  export function UNSAFE_PortalProvider(props: PortalProviderProps): any {
25
25
  let { getContainer } = props;
26
26
  let { getContainer: ctxGetContainer } = useUNSAFE_PortalContext();
27
- return createElement(PortalContext.Provider, {
27
+ return createElement(PortalContext, {
28
28
  value: {
29
29
  getContainer: getContainer === null ? undefined : (getContainer ?? ctxGetContainer),
30
30
  },
@@ -71,7 +71,7 @@ export function ModalProvider(props: ModalProviderProps): any {
71
71
  subSlot(slot, 'context'),
72
72
  );
73
73
 
74
- return createElement(Context.Provider, { value: context, children });
74
+ return createElement(Context, { value: context, children });
75
75
  }
76
76
 
77
77
  export interface ModalProviderAria {
@@ -14,6 +14,7 @@ type DOMAttributes = Record<string, any>;
14
14
  */
15
15
 
16
16
  import { RefObject } from '@react-types/shared';
17
+ import { withSlot } from 'octane';
17
18
  import { getEventTarget } from '../utils/shadowdom/DOMFunctions';
18
19
  import { isElementInChildOfActiveScope } from '../focus/FocusScope';
19
20
  import { useEffect, useRef } from '../compat/react';
@@ -73,6 +74,10 @@ export function useOverlay(
73
74
  ref: RefObject<Element | null>,
74
75
  _slot?: symbol,
75
76
  ): OverlayAria {
77
+ if (_slot !== undefined) {
78
+ return withSlot(_slot, useOverlay, props, ref);
79
+ }
80
+
76
81
  let {
77
82
  onClose,
78
83
  shouldCloseOnBlur,
@@ -20,6 +20,7 @@ import {
20
20
  InputDOMProps,
21
21
  ValidationResult,
22
22
  } from '@react-types/shared';
23
+ import { withSlot } from 'octane';
23
24
  import { filterDOMProps } from '../utils/filterDOMProps';
24
25
  import { getEventTarget } from '../utils/shadowdom/DOMFunctions';
25
26
  import { getFocusableTreeWalker } from '../focus/FocusScope';
@@ -62,6 +63,10 @@ export function useRadioGroup(
62
63
  state: RadioGroupState,
63
64
  _slot?: symbol,
64
65
  ): RadioGroupAria {
66
+ if (_slot !== undefined) {
67
+ return withSlot(_slot, useRadioGroup, props, state);
68
+ }
69
+
65
70
  let {
66
71
  name,
67
72
  form,
@@ -14,6 +14,7 @@ type DOMAttributes = Record<string, any>;
14
14
  */
15
15
 
16
16
  import { AriaButtonProps } from '../button/useButton';
17
+ import { withSlot } from 'octane';
17
18
  import { AriaTextFieldProps, useTextField } from '../textfield/useTextField';
18
19
  import { RefObject, ValidationResult } from '@react-types/shared';
19
20
  import { InputHTMLAttributes, LabelHTMLAttributes } from '../compat/react';
@@ -69,6 +70,10 @@ export function useSearchField(
69
70
  inputRef: RefObject<HTMLInputElement | null>,
70
71
  _slot?: symbol,
71
72
  ): SearchFieldAria {
73
+ if (_slot !== undefined) {
74
+ return withSlot(_slot, useSearchField, props, state, inputRef);
75
+ }
76
+
72
77
  let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/searchfield');
73
78
  let { isDisabled, isReadOnly, onSubmit, onClear, type = 'search' } = props;
74
79
 
@@ -25,7 +25,7 @@ import {
25
25
  KeyboardDelegate,
26
26
  RefObject,
27
27
  } from '@react-types/shared';
28
- import { flushSync } from 'octane';
28
+ import { flushSync, withSlot } from 'octane';
29
29
  import { FocusEvent, useEffect, useRef } from '../compat/react';
30
30
  import { focusSafely } from '../interactions/focusSafely';
31
31
  import { focusWithoutScrolling } from '../utils/focusWithoutScrolling';
@@ -153,6 +153,10 @@ export function useSelectableCollection(
153
153
  options: AriaSelectableCollectionOptions,
154
154
  _slot?: symbol,
155
155
  ): SelectableCollectionAria {
156
+ if (_slot !== undefined) {
157
+ return withSlot(_slot, useSelectableCollection, options);
158
+ }
159
+
156
160
  let {
157
161
  selectionManager: manager,
158
162
  keyboardDelegate: delegate,
@@ -18,6 +18,7 @@ import { focusWithoutScrolling } from '../utils/focusWithoutScrolling';
18
18
  import { getEventTarget } from '../utils/shadowdom/DOMFunctions';
19
19
  import { getSliderThumbId, sliderData } from './utils';
20
20
  import { mergeProps } from '../utils/mergeProps';
21
+ import { withSlot } from 'octane';
21
22
  import React, {
22
23
  ChangeEvent,
23
24
  InputHTMLAttributes,
@@ -104,6 +105,10 @@ export function useSliderThumb(
104
105
  state: SliderState,
105
106
  _slot?: symbol,
106
107
  ): SliderThumbAria {
108
+ if (_slot !== undefined) {
109
+ return withSlot(_slot, useSliderThumb, opts, state);
110
+ }
111
+
107
112
  let {
108
113
  index = 0,
109
114
  isRequired,
@@ -14,6 +14,7 @@ type DOMAttributes = Record<string, any>;
14
14
  */
15
15
 
16
16
  import { announce, clearAnnouncer } from '../live-announcer/LiveAnnouncer';
17
+ import { withSlot } from 'octane';
17
18
 
18
19
  import { AriaButtonProps } from '../button/useButton';
19
20
  import { InputBase, RangeInputBase, Validation, ValueBase } from '@react-types/shared';
@@ -44,6 +45,10 @@ export interface SpinbuttonAria {
44
45
  }
45
46
 
46
47
  export function useSpinButton(props: SpinButtonProps, _slot?: symbol): SpinbuttonAria {
48
+ if (_slot !== undefined) {
49
+ return withSlot(_slot, useSpinButton, props);
50
+ }
51
+
47
52
  const _async = useRef<number | undefined>(undefined);
48
53
  let {
49
54
  value,
@@ -23,6 +23,7 @@ import { GridNode } from '../upstream-exports/react-stately/private/grid/GridCol
23
23
  import intlMessages from '../intl/table/index';
24
24
  import { mergeProps } from '../utils/mergeProps';
25
25
  import { TableColumnResizeState } from '../upstream-exports/react-stately/useTableState';
26
+ import { withSlot } from 'octane';
26
27
  import { useDescription } from '../utils/useDescription';
27
28
  import { useEffectEvent } from '../utils/useEffectEvent';
28
29
  import { useId } from '../utils/useId';
@@ -87,6 +88,10 @@ export function useTableColumnResize<T>(
87
88
  ref: RefObject<HTMLInputElement | null>,
88
89
  _slot?: symbol,
89
90
  ): TableColumnResizeAria {
91
+ if (_slot !== undefined) {
92
+ return withSlot(_slot, useTableColumnResize<T>, props, state, ref);
93
+ }
94
+
90
95
  let {
91
96
  column: item,
92
97
  triggerRef,
@@ -43,7 +43,7 @@ import { useLayoutEffect } from '../utils/useLayoutEffect';
43
43
  import { useLocale } from '../i18n/I18nProvider';
44
44
 
45
45
  export interface AriaTokenFieldProps<T extends TokenFieldValue = TokenFieldValue>
46
- extends TokenFieldProps<T>, AriaLabelingProps {
46
+ extends TokenFieldProps<T>, AriaLabelingProps, FocusableProps {
47
47
  /**
48
48
  * The accessibility role of the token field.
49
49
  *
@@ -65,7 +65,7 @@ export function RouterProvider(props: RouterProviderProps): any {
65
65
  S('RouterProvider:ctx'),
66
66
  );
67
67
 
68
- return createElement(RouterContext.Provider, { value: ctx, children });
68
+ return createElement(RouterContext, { value: ctx, children });
69
69
  }
70
70
 
71
71
  export function useRouter(): Router {
@@ -36,6 +36,7 @@ export function VirtualizerItem(props: VirtualizerItemProps): JSX.Element {
36
36
  layoutInfo,
37
37
  virtualizer,
38
38
  ref,
39
+ shouldObserveItemSize,
39
40
  });
40
41
 
41
42
  return (