@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.
- package/package.json +7 -5
- package/src/autocomplete/useAutocomplete.ts +656 -0
- package/src/collections/BaseCollection.ts +374 -0
- package/src/collections/CollectionBuilder.ts +343 -0
- package/src/collections/Document.ts +451 -0
- package/src/collections/Hidden.ts +84 -0
- package/src/collections/useCachedChildren.ts +103 -0
- package/src/components/Autocomplete.ts +124 -0
- package/src/components/Breadcrumbs.ts +170 -0
- package/src/components/Button.ts +209 -0
- package/src/components/Checkbox.ts +593 -0
- package/src/components/Collection.ts +301 -0
- package/src/components/ComboBox.ts +477 -0
- package/src/components/Dialog.ts +195 -0
- package/src/components/Disclosure.ts +322 -0
- package/src/components/DragAndDrop.ts +177 -0
- package/src/components/FieldError.ts +79 -0
- package/src/components/Form.ts +65 -0
- package/src/components/GridList.ts +1099 -0
- package/src/components/Group.ts +146 -0
- package/src/components/Header.ts +32 -0
- package/src/components/Heading.ts +45 -0
- package/src/components/Input.ts +139 -0
- package/src/components/Keyboard.ts +23 -0
- package/src/components/Label.ts +30 -0
- package/src/components/Link.ts +137 -0
- package/src/components/ListBox.ts +886 -0
- package/src/components/Menu.ts +685 -0
- package/src/components/Meter.ts +100 -0
- package/src/components/Modal.ts +352 -0
- package/src/components/NumberField.ts +221 -0
- package/src/components/OverlayArrow.ts +117 -0
- package/src/components/Popover.ts +385 -0
- package/src/components/ProgressBar.ts +112 -0
- package/src/components/RadioGroup.ts +542 -0
- package/src/components/SearchField.ts +208 -0
- package/src/components/Select.ts +505 -0
- package/src/components/SelectionIndicator.ts +52 -0
- package/src/components/Separator.ts +97 -0
- package/src/components/SharedElementTransition.ts +209 -0
- package/src/components/Slider.ts +472 -0
- package/src/components/Switch.ts +449 -0
- package/src/components/Tabs.ts +675 -0
- package/src/components/TagGroup.ts +443 -0
- package/src/components/Text.ts +27 -0
- package/src/components/TextArea.ts +92 -0
- package/src/components/TextField.ts +200 -0
- package/src/components/ToggleButton.ts +147 -0
- package/src/components/ToggleButtonGroup.ts +106 -0
- package/src/components/Toolbar.ts +74 -0
- package/src/components/Tooltip.ts +249 -0
- package/src/components/index.ts +302 -0
- package/src/components/useDragAndDrop.ts +164 -0
- package/src/components/utils.ts +521 -0
- package/src/intl/autocomplete/ar-AE.json +3 -0
- package/src/intl/autocomplete/bg-BG.json +3 -0
- package/src/intl/autocomplete/cs-CZ.json +3 -0
- package/src/intl/autocomplete/da-DK.json +3 -0
- package/src/intl/autocomplete/de-DE.json +3 -0
- package/src/intl/autocomplete/el-GR.json +3 -0
- package/src/intl/autocomplete/en-US.json +3 -0
- package/src/intl/autocomplete/es-ES.json +3 -0
- package/src/intl/autocomplete/et-EE.json +3 -0
- package/src/intl/autocomplete/fi-FI.json +3 -0
- package/src/intl/autocomplete/fr-FR.json +3 -0
- package/src/intl/autocomplete/he-IL.json +3 -0
- package/src/intl/autocomplete/hr-HR.json +3 -0
- package/src/intl/autocomplete/hu-HU.json +3 -0
- package/src/intl/autocomplete/index.ts +75 -0
- package/src/intl/autocomplete/it-IT.json +3 -0
- package/src/intl/autocomplete/ja-JP.json +3 -0
- package/src/intl/autocomplete/ko-KR.json +3 -0
- package/src/intl/autocomplete/lt-LT.json +3 -0
- package/src/intl/autocomplete/lv-LV.json +3 -0
- package/src/intl/autocomplete/nb-NO.json +3 -0
- package/src/intl/autocomplete/nl-NL.json +3 -0
- package/src/intl/autocomplete/pl-PL.json +3 -0
- package/src/intl/autocomplete/pt-BR.json +3 -0
- package/src/intl/autocomplete/pt-PT.json +3 -0
- package/src/intl/autocomplete/ro-RO.json +3 -0
- package/src/intl/autocomplete/ru-RU.json +3 -0
- package/src/intl/autocomplete/sk-SK.json +3 -0
- package/src/intl/autocomplete/sl-SI.json +3 -0
- package/src/intl/autocomplete/sr-SP.json +3 -0
- package/src/intl/autocomplete/sv-SE.json +3 -0
- package/src/intl/autocomplete/tr-TR.json +3 -0
- package/src/intl/autocomplete/uk-UA.json +3 -0
- package/src/intl/autocomplete/zh-CN.json +3 -0
- package/src/intl/autocomplete/zh-TW.json +3 -0
- package/src/stately/autocomplete/useAutocompleteState.ts +85 -0
- package/src/utils/animation.ts +149 -0
- package/src/utils/useLoadMoreSentinel.ts +78 -0
- 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
|
+
}
|