@octanejs/aria 0.0.4 → 0.0.5

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 (93) hide show
  1. package/package.json +7 -5
  2. package/src/autocomplete/useAutocomplete.ts +656 -0
  3. package/src/collections/BaseCollection.ts +374 -0
  4. package/src/collections/CollectionBuilder.ts +343 -0
  5. package/src/collections/Document.ts +451 -0
  6. package/src/collections/Hidden.ts +84 -0
  7. package/src/collections/useCachedChildren.ts +103 -0
  8. package/src/components/Autocomplete.ts +124 -0
  9. package/src/components/Breadcrumbs.ts +170 -0
  10. package/src/components/Button.ts +209 -0
  11. package/src/components/Checkbox.ts +593 -0
  12. package/src/components/Collection.ts +301 -0
  13. package/src/components/ComboBox.ts +477 -0
  14. package/src/components/Dialog.ts +195 -0
  15. package/src/components/Disclosure.ts +322 -0
  16. package/src/components/DragAndDrop.ts +177 -0
  17. package/src/components/FieldError.ts +79 -0
  18. package/src/components/Form.ts +65 -0
  19. package/src/components/GridList.ts +1099 -0
  20. package/src/components/Group.ts +146 -0
  21. package/src/components/Header.ts +32 -0
  22. package/src/components/Heading.ts +45 -0
  23. package/src/components/Input.ts +139 -0
  24. package/src/components/Keyboard.ts +23 -0
  25. package/src/components/Label.ts +30 -0
  26. package/src/components/Link.ts +137 -0
  27. package/src/components/ListBox.ts +886 -0
  28. package/src/components/Menu.ts +685 -0
  29. package/src/components/Meter.ts +100 -0
  30. package/src/components/Modal.ts +352 -0
  31. package/src/components/NumberField.ts +221 -0
  32. package/src/components/OverlayArrow.ts +117 -0
  33. package/src/components/Popover.ts +385 -0
  34. package/src/components/ProgressBar.ts +112 -0
  35. package/src/components/RadioGroup.ts +542 -0
  36. package/src/components/SearchField.ts +208 -0
  37. package/src/components/Select.ts +505 -0
  38. package/src/components/SelectionIndicator.ts +52 -0
  39. package/src/components/Separator.ts +97 -0
  40. package/src/components/SharedElementTransition.ts +209 -0
  41. package/src/components/Slider.ts +472 -0
  42. package/src/components/Switch.ts +449 -0
  43. package/src/components/Tabs.ts +675 -0
  44. package/src/components/TagGroup.ts +443 -0
  45. package/src/components/Text.ts +27 -0
  46. package/src/components/TextArea.ts +92 -0
  47. package/src/components/TextField.ts +200 -0
  48. package/src/components/ToggleButton.ts +147 -0
  49. package/src/components/ToggleButtonGroup.ts +106 -0
  50. package/src/components/Toolbar.ts +74 -0
  51. package/src/components/Tooltip.ts +249 -0
  52. package/src/components/index.ts +302 -0
  53. package/src/components/useDragAndDrop.ts +164 -0
  54. package/src/components/utils.ts +521 -0
  55. package/src/intl/autocomplete/ar-AE.json +3 -0
  56. package/src/intl/autocomplete/bg-BG.json +3 -0
  57. package/src/intl/autocomplete/cs-CZ.json +3 -0
  58. package/src/intl/autocomplete/da-DK.json +3 -0
  59. package/src/intl/autocomplete/de-DE.json +3 -0
  60. package/src/intl/autocomplete/el-GR.json +3 -0
  61. package/src/intl/autocomplete/en-US.json +3 -0
  62. package/src/intl/autocomplete/es-ES.json +3 -0
  63. package/src/intl/autocomplete/et-EE.json +3 -0
  64. package/src/intl/autocomplete/fi-FI.json +3 -0
  65. package/src/intl/autocomplete/fr-FR.json +3 -0
  66. package/src/intl/autocomplete/he-IL.json +3 -0
  67. package/src/intl/autocomplete/hr-HR.json +3 -0
  68. package/src/intl/autocomplete/hu-HU.json +3 -0
  69. package/src/intl/autocomplete/index.ts +75 -0
  70. package/src/intl/autocomplete/it-IT.json +3 -0
  71. package/src/intl/autocomplete/ja-JP.json +3 -0
  72. package/src/intl/autocomplete/ko-KR.json +3 -0
  73. package/src/intl/autocomplete/lt-LT.json +3 -0
  74. package/src/intl/autocomplete/lv-LV.json +3 -0
  75. package/src/intl/autocomplete/nb-NO.json +3 -0
  76. package/src/intl/autocomplete/nl-NL.json +3 -0
  77. package/src/intl/autocomplete/pl-PL.json +3 -0
  78. package/src/intl/autocomplete/pt-BR.json +3 -0
  79. package/src/intl/autocomplete/pt-PT.json +3 -0
  80. package/src/intl/autocomplete/ro-RO.json +3 -0
  81. package/src/intl/autocomplete/ru-RU.json +3 -0
  82. package/src/intl/autocomplete/sk-SK.json +3 -0
  83. package/src/intl/autocomplete/sl-SI.json +3 -0
  84. package/src/intl/autocomplete/sr-SP.json +3 -0
  85. package/src/intl/autocomplete/sv-SE.json +3 -0
  86. package/src/intl/autocomplete/tr-TR.json +3 -0
  87. package/src/intl/autocomplete/uk-UA.json +3 -0
  88. package/src/intl/autocomplete/zh-CN.json +3 -0
  89. package/src/intl/autocomplete/zh-TW.json +3 -0
  90. package/src/stately/autocomplete/useAutocompleteState.ts +85 -0
  91. package/src/utils/animation.ts +149 -0
  92. package/src/utils/useLoadMoreSentinel.ts +78 -0
  93. package/src/utils/useViewportSize.ts +123 -0
@@ -0,0 +1,200 @@
1
+ // Ported from react-aria-components (source: .react-spectrum/packages/react-aria-components/src/TextField.tsx).
2
+ // octane adaptations: `.tsx` → `.ts`, JSX → `createElement`; NO forwardRef — the forwarded ref
3
+ // arrives positionally from `createHideableComponent` (which forwards `props.ref`); the
4
+ // plain-`.ts` component uses the S()/subSlot component-slot convention. NATIVE EVENTS: the
5
+ // per-keystroke wiring rides octane's native `onInput` (produced inside useTextField); no
6
+ // synthetic `onChange` is added here. `DOMProps` comes from './utils' (RAC's own bag), NOT
7
+ // `@react-types/shared`; upstream's `GlobalDOMAttributes` → a structural record.
8
+ import { createContext, createElement, useCallback, useRef, useState } from 'octane';
9
+
10
+ import { createHideableComponent } from '../collections/Hidden';
11
+ import { S, subSlot } from '../internal';
12
+ import { type AriaTextFieldProps, useTextField } from '../textfield/useTextField';
13
+ import { filterDOMProps } from '../utils/filterDOMProps';
14
+ import { FieldInputContext } from './Autocomplete';
15
+ import { FieldErrorContext } from './FieldError';
16
+ import { FormContext } from './Form';
17
+ import { GroupContext } from './Group';
18
+ import { InputContext } from './Input';
19
+ import { LabelContext } from './Label';
20
+ import { TextAreaContext } from './TextArea';
21
+ import { TextContext } from './Text';
22
+ import {
23
+ type ClassNameOrFunction,
24
+ type ContextValue,
25
+ dom,
26
+ type DOMProps,
27
+ Provider,
28
+ type RACValidation,
29
+ removeDataAttributes,
30
+ type RenderProps,
31
+ type SlotProps,
32
+ useContextProps,
33
+ useRenderProps,
34
+ useSlot,
35
+ useSlottedContext,
36
+ } from './utils';
37
+
38
+ // octane adaptation: structural bag (upstream's `GlobalDOMAttributes` drags React handler types).
39
+ type GlobalDOMAttributes = Record<string, any>;
40
+
41
+ export interface TextFieldRenderProps {
42
+ /**
43
+ * Whether the text field is disabled.
44
+ *
45
+ * @selector [data-disabled]
46
+ */
47
+ isDisabled: boolean;
48
+ /**
49
+ * Whether the value is invalid.
50
+ *
51
+ * @selector [data-invalid]
52
+ */
53
+ isInvalid: boolean;
54
+ /**
55
+ * Whether the text field is read only.
56
+ *
57
+ * @selector [data-readonly]
58
+ */
59
+ isReadOnly: boolean;
60
+ /**
61
+ * Whether the text field is required.
62
+ *
63
+ * @selector [data-required]
64
+ */
65
+ isRequired: boolean;
66
+ }
67
+
68
+ export interface TextFieldProps
69
+ extends
70
+ Omit<
71
+ AriaTextFieldProps,
72
+ | 'label'
73
+ | 'placeholder'
74
+ | 'description'
75
+ | 'errorMessage'
76
+ | 'validationState'
77
+ | 'validationBehavior'
78
+ >,
79
+ RACValidation,
80
+ Omit<DOMProps, 'style' | 'className' | 'children'>,
81
+ SlotProps,
82
+ RenderProps<TextFieldRenderProps>,
83
+ GlobalDOMAttributes {
84
+ /**
85
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
86
+ * element. A function may be provided to compute the class based on component state.
87
+ *
88
+ * @default 'react-aria-TextField'
89
+ */
90
+ className?: ClassNameOrFunction<TextFieldRenderProps>;
91
+ /** Whether the value is invalid. */
92
+ isInvalid?: boolean;
93
+ }
94
+
95
+ export const TextFieldContext = createContext<ContextValue<TextFieldProps, HTMLDivElement>>(null);
96
+
97
+ /**
98
+ * A text field allows a user to enter a plain text value with a keyboard.
99
+ */
100
+ export const TextField = /*#__PURE__*/ createHideableComponent(function TextField(
101
+ props: TextFieldProps,
102
+ ref: any,
103
+ ) {
104
+ const slot = S('TextField');
105
+ [props, ref] = useContextProps(props, ref, TextFieldContext, subSlot(slot, 'ctx'));
106
+ let { validationBehavior: formValidationBehavior } = useSlottedContext(FormContext) || {};
107
+ let validationBehavior = props.validationBehavior ?? formValidationBehavior ?? 'native';
108
+ let inputRef: any = useRef<HTMLInputElement | null>(null, subSlot(slot, 'input'));
109
+ // octane adaptation: destructuring assignment instead of upstream's `inputRef as unknown`
110
+ // lvalue cast — the merged object ref replaces the local ref exactly like upstream.
111
+ [props, inputRef] = useContextProps(
112
+ props,
113
+ inputRef,
114
+ FieldInputContext as any,
115
+ subSlot(slot, 'fieldInput'),
116
+ );
117
+ let [labelRef, label] = useSlot(
118
+ !props['aria-label'] && !props['aria-labelledby'],
119
+ subSlot(slot, 'labelSlot'),
120
+ );
121
+ let [inputElementType, setInputElementType] = useState('input', subSlot(slot, 'elementType'));
122
+ let { labelProps, inputProps, descriptionProps, errorMessageProps, ...validation } =
123
+ useTextField<any>(
124
+ {
125
+ ...removeDataAttributes(props),
126
+ inputElementType,
127
+ label,
128
+ validationBehavior,
129
+ },
130
+ inputRef,
131
+ subSlot(slot, 'textField'),
132
+ );
133
+
134
+ // Intercept setting the input ref so we can determine what kind of element we have.
135
+ // useTextField uses this to determine what props to include.
136
+ let inputOrTextAreaRef = useCallback(
137
+ (el: any) => {
138
+ inputRef.current = el;
139
+ if (el) {
140
+ setInputElementType(el instanceof HTMLTextAreaElement ? 'textarea' : 'input');
141
+ }
142
+ },
143
+ [inputRef],
144
+ subSlot(slot, 'inputOrTextAreaRef'),
145
+ );
146
+
147
+ let renderProps = useRenderProps(
148
+ {
149
+ ...props,
150
+ values: {
151
+ isDisabled: props.isDisabled || false,
152
+ isInvalid: validation.isInvalid,
153
+ isReadOnly: props.isReadOnly || false,
154
+ isRequired: props.isRequired || false,
155
+ },
156
+ defaultClassName: 'react-aria-TextField',
157
+ },
158
+ subSlot(slot, 'render'),
159
+ );
160
+
161
+ let DOMProps = filterDOMProps(props, { global: true });
162
+ delete DOMProps.id;
163
+
164
+ return createElement(dom.div, {
165
+ ...DOMProps,
166
+ ...renderProps,
167
+ ref,
168
+ slot: props.slot || undefined,
169
+ 'data-disabled': props.isDisabled || undefined,
170
+ 'data-invalid': validation.isInvalid || undefined,
171
+ 'data-readonly': props.isReadOnly || undefined,
172
+ 'data-required': props.isRequired || undefined,
173
+ children: createElement(Provider, {
174
+ values: [
175
+ [LabelContext, { ...labelProps, ref: labelRef }],
176
+ [InputContext, { ...inputProps, ref: inputOrTextAreaRef }],
177
+ [TextAreaContext, { ...inputProps, ref: inputOrTextAreaRef }],
178
+ [
179
+ GroupContext,
180
+ {
181
+ role: 'presentation',
182
+ isInvalid: validation.isInvalid,
183
+ isDisabled: props.isDisabled || false,
184
+ },
185
+ ],
186
+ [
187
+ TextContext,
188
+ {
189
+ slots: {
190
+ description: descriptionProps,
191
+ errorMessage: errorMessageProps,
192
+ },
193
+ },
194
+ ],
195
+ [FieldErrorContext, validation],
196
+ ] as any,
197
+ children: renderProps.children,
198
+ }),
199
+ });
200
+ });
@@ -0,0 +1,147 @@
1
+ // Ported from react-aria-components (source: .react-spectrum/packages/react-aria-components/src/ToggleButton.tsx).
2
+ // octane adaptations: `.tsx` → `.ts`, JSX → `createElement`; NO forwardRef — the forwarded ref
3
+ // is `props.ref`, passed into `useContextProps` explicitly and re-applied as the merged object
4
+ // ref; the plain-`.ts` component uses the S()/subSlot component-slot convention. Upstream's
5
+ // conditional group-item/standalone hook calls (eslint-disabled there) are safe here because
6
+ // binding hooks are keyed by their explicit slot symbols, not call order.
7
+ import type { HoverEvents, Key } from '@react-types/shared';
8
+ import { createContext, createElement, useContext } from 'octane';
9
+
10
+ import { type AriaToggleButtonProps, useToggleButton } from '../button/useToggleButton';
11
+ import { useToggleButtonGroupItem } from '../button/useToggleButtonGroup';
12
+ import { useFocusRing } from '../focus/useFocusRing';
13
+ import { useHover } from '../interactions/useHover';
14
+ import { S, subSlot } from '../internal';
15
+ import { type ToggleState, useToggleState } from '../stately/toggle/useToggleState';
16
+ import { filterDOMProps } from '../utils/filterDOMProps';
17
+ import { mergeProps } from '../utils/mergeProps';
18
+ import type { ButtonRenderProps } from './Button';
19
+ import { SelectionIndicatorContext } from './SelectionIndicator';
20
+ import { ToggleGroupStateContext } from './ToggleButtonGroup';
21
+ import {
22
+ type ClassNameOrFunction,
23
+ type ContextValue,
24
+ dom,
25
+ type RenderProps,
26
+ type SlotProps,
27
+ useContextProps,
28
+ useRenderProps,
29
+ } from './utils';
30
+
31
+ // octane adaptation: structural bag (upstream's `GlobalDOMAttributes` drags React handler types).
32
+ type GlobalDOMAttributes = Record<string, any>;
33
+
34
+ export interface ToggleButtonRenderProps extends Omit<ButtonRenderProps, 'isPending'> {
35
+ /**
36
+ * Whether the button is currently selected.
37
+ *
38
+ * @selector [data-selected]
39
+ */
40
+ isSelected: boolean;
41
+ /**
42
+ * State of the toggle button.
43
+ */
44
+ state: ToggleState;
45
+ }
46
+
47
+ export interface ToggleButtonProps
48
+ extends
49
+ Omit<AriaToggleButtonProps, 'children' | 'elementType' | 'id'>,
50
+ HoverEvents,
51
+ SlotProps,
52
+ RenderProps<ToggleButtonRenderProps, 'button'>,
53
+ Omit<GlobalDOMAttributes, 'onClick'> {
54
+ /**
55
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
56
+ * element. A function may be provided to compute the class based on component state.
57
+ *
58
+ * @default 'react-aria-ToggleButton'
59
+ */
60
+ className?: ClassNameOrFunction<ToggleButtonRenderProps>;
61
+ /**
62
+ * When used in a ToggleButtonGroup, an identifier for the item in `selectedKeys`. When used
63
+ * standalone, a DOM id.
64
+ */
65
+ id?: Key;
66
+ }
67
+
68
+ export const ToggleButtonContext = createContext<
69
+ ContextValue<ToggleButtonProps, HTMLButtonElement>
70
+ >({});
71
+
72
+ /**
73
+ * A toggle button allows a user to toggle a selection on or off, for example switching between two
74
+ * states or modes.
75
+ */
76
+ export function ToggleButton(props: ToggleButtonProps): any {
77
+ const slot = S('ToggleButton');
78
+ let ref: any;
79
+ [props, ref] = useContextProps(props, props.ref, ToggleButtonContext, subSlot(slot, 'ctx'));
80
+ let groupState = useContext(ToggleGroupStateContext);
81
+ let state = useToggleState(
82
+ groupState && props.id != null
83
+ ? {
84
+ isSelected: groupState.selectedKeys.has(props.id),
85
+ onChange(isSelected: boolean) {
86
+ groupState.setSelected(props.id!, isSelected);
87
+ },
88
+ }
89
+ : (props as any),
90
+ subSlot(slot, 'toggle'),
91
+ );
92
+
93
+ let { buttonProps, isPressed, isSelected, isDisabled } =
94
+ groupState && props.id != null
95
+ ? useToggleButtonGroupItem(
96
+ { ...props, id: props.id } as any,
97
+ groupState,
98
+ ref,
99
+ subSlot(slot, 'groupItem'),
100
+ )
101
+ : useToggleButton(
102
+ { ...props, id: props.id != null ? String(props.id) : undefined } as any,
103
+ state,
104
+ ref,
105
+ subSlot(slot, 'toggleButton'),
106
+ );
107
+
108
+ let { focusProps, isFocused, isFocusVisible } = useFocusRing(props, subSlot(slot, 'focusRing'));
109
+ let { hoverProps, isHovered } = useHover({ ...props, isDisabled }, subSlot(slot, 'hover'));
110
+ let renderProps = useRenderProps(
111
+ {
112
+ ...props,
113
+ id: undefined,
114
+ values: {
115
+ isHovered,
116
+ isPressed,
117
+ isFocused,
118
+ isSelected: state.isSelected,
119
+ isFocusVisible,
120
+ isDisabled,
121
+ state,
122
+ },
123
+ defaultClassName: 'react-aria-ToggleButton',
124
+ },
125
+ subSlot(slot, 'render'),
126
+ );
127
+
128
+ let DOMProps = filterDOMProps(props as any, { global: true });
129
+ delete DOMProps.id;
130
+ delete DOMProps.onClick;
131
+
132
+ return createElement(dom.button, {
133
+ ...mergeProps(DOMProps, renderProps, buttonProps, focusProps, hoverProps),
134
+ ref,
135
+ slot: props.slot || undefined,
136
+ 'data-focused': isFocused || undefined,
137
+ 'data-disabled': isDisabled || undefined,
138
+ 'data-pressed': isPressed || undefined,
139
+ 'data-selected': isSelected || undefined,
140
+ 'data-hovered': isHovered || undefined,
141
+ 'data-focus-visible': isFocusVisible || undefined,
142
+ children: createElement(SelectionIndicatorContext.Provider, {
143
+ value: { isSelected },
144
+ children: renderProps.children,
145
+ }),
146
+ });
147
+ }
@@ -0,0 +1,106 @@
1
+ // Ported from react-aria-components (source: .react-spectrum/packages/react-aria-components/src/ToggleButtonGroup.tsx).
2
+ // octane adaptations: `.tsx` → `.ts`, JSX → `createElement`; NO forwardRef — the forwarded ref
3
+ // is `props.ref`, passed into `useContextProps` explicitly and re-applied as the merged object
4
+ // ref; the plain-`.ts` component uses the S()/subSlot component-slot convention.
5
+ import type { Orientation } from '@react-types/shared';
6
+ import { createContext, createElement } from 'octane';
7
+
8
+ import {
9
+ type AriaToggleButtonGroupProps,
10
+ useToggleButtonGroup,
11
+ } from '../button/useToggleButtonGroup';
12
+ import { S, subSlot } from '../internal';
13
+ import { type ToggleGroupState, useToggleGroupState } from '../stately/toggle/useToggleGroupState';
14
+ import { filterDOMProps } from '../utils/filterDOMProps';
15
+ import { mergeProps } from '../utils/mergeProps';
16
+ import { SharedElementTransition } from './SharedElementTransition';
17
+ import {
18
+ type ClassNameOrFunction,
19
+ type ContextValue,
20
+ dom,
21
+ type RenderProps,
22
+ type SlotProps,
23
+ useContextProps,
24
+ useRenderProps,
25
+ } from './utils';
26
+
27
+ // octane adaptation: structural bag (upstream's `GlobalDOMAttributes` drags React handler types).
28
+ type GlobalDOMAttributes = Record<string, any>;
29
+
30
+ export interface ToggleButtonGroupRenderProps {
31
+ /**
32
+ * The orientation of the toggle button group.
33
+ *
34
+ * @selector [data-orientation="horizontal | vertical"]
35
+ */
36
+ orientation: Orientation;
37
+ /**
38
+ * Whether the toggle button group is disabled.
39
+ *
40
+ * @selector [data-disabled]
41
+ */
42
+ isDisabled: boolean;
43
+ /**
44
+ * State of the toggle button group.
45
+ */
46
+ state: ToggleGroupState;
47
+ }
48
+
49
+ export interface ToggleButtonGroupProps
50
+ extends
51
+ AriaToggleButtonGroupProps,
52
+ RenderProps<ToggleButtonGroupRenderProps>,
53
+ SlotProps,
54
+ GlobalDOMAttributes {
55
+ /**
56
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
57
+ * element. A function may be provided to compute the class based on component state.
58
+ *
59
+ * @default 'react-aria-ToggleButtonGroup'
60
+ */
61
+ className?: ClassNameOrFunction<ToggleButtonGroupRenderProps>;
62
+ }
63
+
64
+ export const ToggleButtonGroupContext = createContext<
65
+ ContextValue<ToggleButtonGroupProps, HTMLDivElement>
66
+ >({});
67
+ export const ToggleGroupStateContext = createContext<ToggleGroupState | null>(null);
68
+
69
+ /**
70
+ * A toggle button group allows a user to toggle multiple options, with single or multiple
71
+ * selection.
72
+ */
73
+ export function ToggleButtonGroup(props: ToggleButtonGroupProps): any {
74
+ const slot = S('ToggleButtonGroup');
75
+ let ref: any;
76
+ [props, ref] = useContextProps(props, props.ref, ToggleButtonGroupContext, subSlot(slot, 'ctx'));
77
+ let state = useToggleGroupState(props, subSlot(slot, 'state'));
78
+ let { groupProps } = useToggleButtonGroup(props, state, ref, subSlot(slot, 'group'));
79
+
80
+ let renderProps = useRenderProps(
81
+ {
82
+ ...props,
83
+ values: {
84
+ orientation: props.orientation || 'horizontal',
85
+ isDisabled: state.isDisabled,
86
+ state,
87
+ },
88
+ defaultClassName: 'react-aria-ToggleButtonGroup',
89
+ },
90
+ subSlot(slot, 'render'),
91
+ );
92
+
93
+ let DOMProps = filterDOMProps(props, { global: true });
94
+
95
+ return createElement(dom.div, {
96
+ ...mergeProps(DOMProps, renderProps, groupProps),
97
+ ref,
98
+ slot: props.slot || undefined,
99
+ 'data-orientation': props.orientation || 'horizontal',
100
+ 'data-disabled': props.isDisabled || undefined,
101
+ children: createElement(ToggleGroupStateContext.Provider, {
102
+ value: state,
103
+ children: createElement(SharedElementTransition, { children: renderProps.children }),
104
+ }),
105
+ });
106
+ }
@@ -0,0 +1,74 @@
1
+ // Ported from react-aria-components (source: .react-spectrum/packages/react-aria-components/src/Toolbar.tsx).
2
+ // octane adaptations: `.tsx` → `.ts`, JSX → `createElement`; NO forwardRef — the forwarded ref
3
+ // is `props.ref`, passed into `useContextProps` explicitly and re-applied as the merged object
4
+ // ref; the plain-`.ts` component uses the S()/subSlot component-slot convention.
5
+ import type { Orientation } from '@react-types/shared';
6
+ import { createContext, createElement } from 'octane';
7
+
8
+ import { S, subSlot } from '../internal';
9
+ import { type AriaToolbarProps, useToolbar } from '../toolbar/useToolbar';
10
+ import { filterDOMProps } from '../utils/filterDOMProps';
11
+ import { mergeProps } from '../utils/mergeProps';
12
+ import {
13
+ type ClassNameOrFunction,
14
+ type ContextValue,
15
+ dom,
16
+ type RenderProps,
17
+ type SlotProps,
18
+ useContextProps,
19
+ useRenderProps,
20
+ } from './utils';
21
+
22
+ // octane adaptation: structural bag (upstream's `GlobalDOMAttributes` drags React handler types).
23
+ type GlobalDOMAttributes = Record<string, any>;
24
+
25
+ export interface ToolbarRenderProps {
26
+ /**
27
+ * The current orientation of the toolbar.
28
+ *
29
+ * @selector [data-orientation]
30
+ */
31
+ orientation: Orientation;
32
+ }
33
+
34
+ export interface ToolbarProps
35
+ extends AriaToolbarProps, SlotProps, RenderProps<ToolbarRenderProps>, GlobalDOMAttributes {
36
+ /**
37
+ * The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the
38
+ * element. A function may be provided to compute the class based on component state.
39
+ *
40
+ * @default 'react-aria-Toolbar'
41
+ */
42
+ className?: ClassNameOrFunction<ToolbarRenderProps>;
43
+ }
44
+
45
+ export const ToolbarContext = createContext<ContextValue<ToolbarProps, HTMLDivElement>>({});
46
+
47
+ /**
48
+ * A toolbar is a container for a set of interactive controls, such as buttons, dropdown menus, or
49
+ * checkboxes, with arrow key navigation.
50
+ */
51
+ export function Toolbar(props: ToolbarProps): any {
52
+ const slot = S('Toolbar');
53
+ let ref: any;
54
+ [props, ref] = useContextProps(props, props.ref, ToolbarContext, subSlot(slot, 'ctx'));
55
+ let { toolbarProps } = useToolbar(props, ref, subSlot(slot, 'toolbar'));
56
+ let renderProps = useRenderProps(
57
+ {
58
+ ...props,
59
+ values: { orientation: props.orientation || 'horizontal' },
60
+ defaultClassName: 'react-aria-Toolbar',
61
+ },
62
+ subSlot(slot, 'render'),
63
+ );
64
+ let DOMProps = filterDOMProps(props, { global: true });
65
+ delete DOMProps.id;
66
+
67
+ return createElement(dom.div, {
68
+ ...mergeProps(DOMProps, renderProps, toolbarProps),
69
+ ref,
70
+ slot: props.slot || undefined,
71
+ 'data-orientation': props.orientation || 'horizontal',
72
+ children: renderProps.children,
73
+ });
74
+ }