@westpac/ui 1.16.0 → 1.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/component-type.json +1 -1
- package/dist/components/button/button.component.d.ts +2 -17
- package/dist/components/button/button.component.js +9 -4
- package/dist/components/button/button.types.d.ts +16 -6
- package/dist/components/button-group/button-group.component.d.ts +2 -1
- package/dist/components/button-group/button-group.component.js +6 -3
- package/dist/components/checkbox-group/checkbox-group.component.d.ts +11 -2
- package/dist/components/checkbox-group/checkbox-group.component.js +10 -3
- package/dist/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.d.ts +1 -1
- package/dist/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.js +5 -6
- package/dist/components/date-picker/components/date-field/components/date-segment/date-segment.component.d.ts +6 -5
- package/dist/components/date-picker/components/date-field/components/date-segment/date-segment.component.js +6 -4
- package/dist/components/date-picker/components/date-field/date-field.component.d.ts +5 -5
- package/dist/components/date-picker/components/date-field/date-field.component.js +7 -3
- package/dist/components/date-picker/date-picker.component.d.ts +19 -2
- package/dist/components/date-picker/date-picker.component.js +10 -5
- package/dist/components/date-picker/date-picker.styles.js +5 -5
- package/dist/components/link/link.component.d.ts +4 -12
- package/dist/components/link/link.component.js +30 -7
- package/dist/components/link/link.types.d.ts +26 -3
- package/dist/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.component.d.ts +1 -1
- package/dist/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.component.js +14 -7
- package/dist/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.types.d.ts +11 -0
- package/dist/components/multi-select/components/multi-select-list-box/components/multi-select-option/multi-select-option.component.js +3 -7
- package/dist/components/multi-select/components/multi-select-list-box/components/multi-select-select-all-option/multi-select-select-all-option.component.js +3 -3
- package/dist/components/multi-select/components/multi-select-popover/multi-select-popover.component.js +5 -2
- package/dist/components/multi-select/components/multi-select-searchbar/multi-select-searchbar.component.js +4 -7
- package/dist/components/multi-select/multi-select.component.d.ts +14 -3
- package/dist/components/multi-select/multi-select.component.js +10 -16
- package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.d.ts +1 -1
- package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.js +5 -6
- package/dist/components/radio-group/radio-group.component.d.ts +10 -2
- package/dist/components/radio-group/radio-group.component.js +10 -3
- package/dist/components/selector/components/selector-button-group/selector-button-group.component.d.ts +9 -2
- package/dist/components/selector/components/selector-button-group/selector-button-group.component.js +8 -3
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.d.ts +6 -2
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.js +8 -3
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.d.ts +6 -2
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.js +8 -3
- package/dist/components/selector/selector.component.d.ts +3 -1
- package/dist/components/selector/selector.component.js +16 -5
- package/dist/components/switch/switch.component.d.ts +8 -2
- package/dist/components/switch/switch.component.js +6 -4
- package/dist/css/westpac-ui.css +12 -12
- package/dist/css/westpac-ui.min.css +12 -12
- package/dist/hook/focus-manager-ref.hook.d.ts +29 -0
- package/dist/hook/focus-manager-ref.hook.js +23 -0
- package/dist/hook/index.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/package.json +5 -3
- package/src/components/button/button.component.tsx +10 -9
- package/src/components/button/button.types.ts +21 -8
- package/src/components/button-group/button-group.component.tsx +26 -16
- package/src/components/checkbox-group/checkbox-group.component.tsx +24 -14
- package/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx +7 -7
- package/src/components/date-picker/components/date-field/components/date-segment/date-segment.component.tsx +10 -4
- package/src/components/date-picker/components/date-field/date-field.component.tsx +17 -3
- package/src/components/date-picker/date-picker.component.tsx +32 -21
- package/src/components/date-picker/date-picker.styles.ts +5 -5
- package/src/components/link/link.component.tsx +60 -12
- package/src/components/link/link.types.ts +31 -4
- package/src/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.component.tsx +16 -2
- package/src/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.types.ts +12 -0
- package/src/components/multi-select/components/multi-select-list-box/components/multi-select-option/multi-select-option.component.tsx +3 -5
- package/src/components/multi-select/components/multi-select-list-box/components/multi-select-select-all-option/multi-select-select-all-option.component.tsx +4 -3
- package/src/components/multi-select/components/multi-select-popover/multi-select-popover.component.tsx +8 -2
- package/src/components/multi-select/components/multi-select-searchbar/multi-select-searchbar.component.tsx +3 -6
- package/src/components/multi-select/multi-select.component.tsx +33 -28
- package/src/components/radio-group/components/radio-group-radio/radio-group-radio.component.tsx +10 -7
- package/src/components/radio-group/radio-group.component.tsx +24 -14
- package/src/components/selector/components/selector-button-group/selector-button-group.component.tsx +23 -14
- package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx +12 -3
- package/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx +21 -11
- package/src/components/selector/selector.component.tsx +16 -5
- package/src/components/switch/switch.component.tsx +10 -12
- package/src/hook/focus-manager-ref.hook.ts +56 -0
- package/src/hook/index.ts +1 -0
- package/src/index.ts +1 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
+
import { focusWithoutScrolling } from '@react-aria/utils';
|
|
2
3
|
import React, { useCallback, useContext, useMemo } from 'react';
|
|
3
4
|
import { useOption, useFocusRing, mergeProps } from 'react-aria';
|
|
4
5
|
import { TickIcon } from '../../../../../icon/index.js';
|
|
@@ -40,12 +41,11 @@ export function MultiSelectSelectAllOption() {
|
|
|
40
41
|
var _listBoxRef_current;
|
|
41
42
|
e.preventDefault();
|
|
42
43
|
const firstItem = (_listBoxRef_current = listBoxRef.current) === null || _listBoxRef_current === void 0 ? void 0 : _listBoxRef_current.querySelector('[data-key]');
|
|
43
|
-
|
|
44
|
+
if (firstItem) focusWithoutScrolling(firstItem);
|
|
44
45
|
}
|
|
45
46
|
if (e.key === 'ArrowUp') {
|
|
46
|
-
var _inputRef_current;
|
|
47
47
|
e.preventDefault();
|
|
48
|
-
(
|
|
48
|
+
if (inputRef.current) focusWithoutScrolling(inputRef.current);
|
|
49
49
|
}
|
|
50
50
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
51
51
|
e.preventDefault();
|
|
@@ -14,6 +14,10 @@ export function MultiSelectPopover({ children, className, ...props }) {
|
|
|
14
14
|
setIsPopoverSmaller(popoverWidth < buttonWidth);
|
|
15
15
|
}
|
|
16
16
|
}, []);
|
|
17
|
+
const positioningState = {
|
|
18
|
+
...overlayState,
|
|
19
|
+
close: ()=>undefined
|
|
20
|
+
};
|
|
17
21
|
const { popoverProps } = usePopover({
|
|
18
22
|
...props,
|
|
19
23
|
placement: placement,
|
|
@@ -23,7 +27,7 @@ export function MultiSelectPopover({ children, className, ...props }) {
|
|
|
23
27
|
shouldFlip: true,
|
|
24
28
|
shouldCloseOnInteractOutside: ()=>false,
|
|
25
29
|
offset: 6
|
|
26
|
-
},
|
|
30
|
+
}, positioningState);
|
|
27
31
|
const brandContainer = useMemo(()=>{
|
|
28
32
|
if (typeof window !== 'undefined') {
|
|
29
33
|
return document.querySelector('[data-brand]') || document.querySelector('[class^="theme-"], [class*=" theme-"]') || document.body;
|
|
@@ -57,7 +61,6 @@ export function MultiSelectPopover({ children, className, ...props }) {
|
|
|
57
61
|
}
|
|
58
62
|
},
|
|
59
63
|
role: "dialog",
|
|
60
|
-
"aria-modal": "true",
|
|
61
64
|
"aria-label": "Options list with filter"
|
|
62
65
|
}, children, React.createElement(DismissButton, {
|
|
63
66
|
onDismiss: ()=>overlayState.close()
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { focusWithoutScrolling } from '@react-aria/utils';
|
|
1
2
|
import React, { useContext, useCallback } from 'react';
|
|
2
3
|
import { Button } from '../../../../components/button/index.js';
|
|
3
4
|
import { ClearIcon, SearchIcon } from '../../../../components/icon/index.js';
|
|
@@ -10,14 +11,10 @@ export function MultiSelectSearchbar({ filterText, setFilterText, closeBtnRef })
|
|
|
10
11
|
const styles = searchbarStyles();
|
|
11
12
|
const handleInputKeyDown = useCallback((e)=>{
|
|
12
13
|
if (e.key === 'ArrowDown') {
|
|
14
|
+
var _listBoxRef_current;
|
|
13
15
|
e.preventDefault();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} else {
|
|
17
|
-
var _listBoxRef_current;
|
|
18
|
-
const firstItem = (_listBoxRef_current = listBoxRef.current) === null || _listBoxRef_current === void 0 ? void 0 : _listBoxRef_current.querySelector('[data-key]');
|
|
19
|
-
firstItem === null || firstItem === void 0 ? void 0 : firstItem.focus();
|
|
20
|
-
}
|
|
16
|
+
const target = selectAllRef.current || ((_listBoxRef_current = listBoxRef.current) === null || _listBoxRef_current === void 0 ? void 0 : _listBoxRef_current.querySelector('[data-key]'));
|
|
17
|
+
if (target) focusWithoutScrolling(target);
|
|
21
18
|
}
|
|
22
19
|
if (e.key === 'Escape' && filterText.length > 0) {
|
|
23
20
|
e.stopPropagation();
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { ForwardedRef } from 'react';
|
|
2
2
|
import type { MultiSelectContextProps, MultiSelectItemProps, MultiSelectProps, MultiSelectValue } from './multi-select.types.js';
|
|
3
3
|
export declare const MultiSelectContext: React.Context<MultiSelectContextProps>;
|
|
4
|
-
export declare function BaseMultiSelect<T extends MultiSelectValue = MultiSelectValue>({ size, listBoxProps, selectionMode, selectedKeys, onSelectionChange, placeholder, showSingleSectionTitle, placement, portalContainer, id, hideFilter, hideSelectAll, width, ...props }: MultiSelectProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
-
export declare const MultiSelect: React.MemoExoticComponent<
|
|
4
|
+
export declare function BaseMultiSelect<T extends MultiSelectValue = MultiSelectValue>({ size, listBoxProps, selectionMode, selectedKeys, onSelectionChange, placeholder, showSingleSectionTitle, placement, portalContainer, id, hideFilter, hideSelectAll, width, ...props }: MultiSelectProps<T>, forwardedRef: ForwardedRef<HTMLButtonElement>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare const MultiSelect: React.MemoExoticComponent<React.ForwardRefExoticComponent<{
|
|
6
|
+
hideFilter?: boolean;
|
|
7
|
+
hideSelectAll?: boolean;
|
|
8
|
+
listBoxProps?: Omit<import("react-aria").AriaListBoxOptions<MultiSelectValue>, "state" | "selectionMode"> | undefined;
|
|
9
|
+
id?: string;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
placement?: import("react-aria").AriaPopoverProps["placement"];
|
|
12
|
+
portalContainer?: Element;
|
|
13
|
+
showSingleSectionTitle?: boolean;
|
|
14
|
+
size?: import("./components/multi-select-list-box-trigger/multi-select-list-box-trigger.types.js").MultiSelectSize;
|
|
15
|
+
width?: import("../../types/responsive-variants.types.js").ResponsiveVariants<2 | 1 | 3 | "full" | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 30 | undefined>;
|
|
16
|
+
} & import("react-stately").ListProps<MultiSelectValue> & React.RefAttributes<HTMLButtonElement>>>;
|
|
6
17
|
export declare const MultiSelectItem: (props: MultiSelectItemProps) => JSX.Element;
|
|
7
18
|
export { Section as MultiSelectSection } from 'react-stately';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import { focusWithoutScrolling } from '@react-aria/utils';
|
|
3
|
+
import React, { forwardRef, useRef, useState, memo, createContext } from 'react';
|
|
4
|
+
import { useFilter, useObjectRef, useOverlayTrigger } from 'react-aria';
|
|
4
5
|
import { Item, useListState, useOverlayTriggerState } from 'react-stately';
|
|
5
6
|
import { MultiSelectDropdown } from './components/multi-select-dropdown/multi-select-dropdown.component.js';
|
|
6
7
|
import { MultiSelectListBoxTrigger } from './components/multi-select-list-box-trigger/multi-select-list-box-trigger.component.js';
|
|
@@ -28,7 +29,7 @@ export const MultiSelectContext = createContext({
|
|
|
28
29
|
overlayProps: {},
|
|
29
30
|
hideSelectAll: false
|
|
30
31
|
});
|
|
31
|
-
export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode = 'multiple', selectedKeys, onSelectionChange, placeholder = 'Select', showSingleSectionTitle = false, placement = 'bottom left', portalContainer, id, hideFilter = false, hideSelectAll = false, width = 'full', ...props }) {
|
|
32
|
+
export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode = 'multiple', selectedKeys, onSelectionChange, placeholder = 'Select', showSingleSectionTitle = false, placement = 'bottom left', portalContainer, id, hideFilter = false, hideSelectAll = false, width = 'full', ...props }, forwardedRef) {
|
|
32
33
|
const [filterText, setFilterText] = useState('');
|
|
33
34
|
const filter = useFilter({
|
|
34
35
|
sensitivity: 'base'
|
|
@@ -41,7 +42,7 @@ export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode =
|
|
|
41
42
|
filter: (nodes)=>filterNodes(nodes, filterText, (value, string)=>filter.contains(value, string))
|
|
42
43
|
});
|
|
43
44
|
const inputRef = useRef(null);
|
|
44
|
-
const buttonRef =
|
|
45
|
+
const buttonRef = useObjectRef(forwardedRef);
|
|
45
46
|
const popoverRef = useRef(null);
|
|
46
47
|
const selectAllRef = useRef(null);
|
|
47
48
|
const listBoxRef = useRef(null);
|
|
@@ -49,17 +50,9 @@ export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode =
|
|
|
49
50
|
onOpenChange: (isOpen)=>{
|
|
50
51
|
if (isOpen) {
|
|
51
52
|
requestAnimationFrame(()=>{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} else if (selectionMode === 'multiple' && !hideSelectAll) {
|
|
56
|
-
var _selectAllRef_current;
|
|
57
|
-
(_selectAllRef_current = selectAllRef.current) === null || _selectAllRef_current === void 0 ? void 0 : _selectAllRef_current.focus();
|
|
58
|
-
} else {
|
|
59
|
-
var _listBoxRef_current;
|
|
60
|
-
const firstItem = (_listBoxRef_current = listBoxRef.current) === null || _listBoxRef_current === void 0 ? void 0 : _listBoxRef_current.querySelector('[data-key]');
|
|
61
|
-
firstItem === null || firstItem === void 0 ? void 0 : firstItem.focus();
|
|
62
|
-
}
|
|
53
|
+
var _listBoxRef_current;
|
|
54
|
+
const target = !hideFilter && inputRef.current || selectionMode === 'multiple' && !hideSelectAll && selectAllRef.current || ((_listBoxRef_current = listBoxRef.current) === null || _listBoxRef_current === void 0 ? void 0 : _listBoxRef_current.querySelector('[data-key]'));
|
|
55
|
+
if (target) focusWithoutScrolling(target);
|
|
63
56
|
});
|
|
64
57
|
}
|
|
65
58
|
if (!isOpen) {
|
|
@@ -103,6 +96,7 @@ export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode =
|
|
|
103
96
|
...listBoxProps
|
|
104
97
|
})));
|
|
105
98
|
}
|
|
106
|
-
export const MultiSelect = memo(BaseMultiSelect);
|
|
99
|
+
export const MultiSelect = memo(forwardRef(BaseMultiSelect));
|
|
100
|
+
MultiSelect.displayName = 'MultiSelect';
|
|
107
101
|
export const MultiSelectItem = Item;
|
|
108
102
|
export { Section as MultiSelectSection } from 'react-stately';
|
package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export declare const RadioGroupRadio: React.ForwardRefExoticComponent<{
|
|
|
3
3
|
className?: string;
|
|
4
4
|
hint?: React.ReactNode;
|
|
5
5
|
label: React.ReactNode;
|
|
6
|
-
} & Omit<import("react-aria").AriaRadioProps, "children"> & React.RefAttributes<
|
|
6
|
+
} & Omit<import("react-aria").AriaRadioProps, "children"> & React.RefAttributes<HTMLInputElement>>;
|
package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { forwardRef, useContext
|
|
3
|
-
import { VisuallyHidden, mergeProps, useFocusRing, useRadio } from 'react-aria';
|
|
2
|
+
import React, { forwardRef, useContext } from 'react';
|
|
3
|
+
import { VisuallyHidden, mergeProps, useFocusRing, useObjectRef, useRadio } from 'react-aria';
|
|
4
4
|
import { RadioGroupContext } from '../../radio-group.component.js';
|
|
5
5
|
import { styles as radioStyles } from './radio-group-radio.styles.js';
|
|
6
6
|
function BaseRadioGroupRadio({ className, hint, label, ...props }, ref) {
|
|
7
7
|
const { state, size, orientation } = useContext(RadioGroupContext);
|
|
8
|
-
const
|
|
8
|
+
const inputRef = useObjectRef(ref);
|
|
9
9
|
const { inputProps, labelProps, isSelected, isDisabled } = useRadio({
|
|
10
10
|
...props,
|
|
11
11
|
children: label
|
|
12
|
-
}, state,
|
|
12
|
+
}, state, inputRef);
|
|
13
13
|
const { isFocusVisible, focusProps } = useFocusRing();
|
|
14
14
|
const styles = radioStyles({
|
|
15
15
|
isDisabled,
|
|
@@ -22,13 +22,12 @@ function BaseRadioGroupRadio({ className, hint, label, ...props }, ref) {
|
|
|
22
22
|
className: styles.base({
|
|
23
23
|
className
|
|
24
24
|
}),
|
|
25
|
-
ref: ref,
|
|
26
25
|
...labelProps
|
|
27
26
|
}, React.createElement(VisuallyHidden, {
|
|
28
27
|
elementType: "span"
|
|
29
28
|
}, React.createElement("input", {
|
|
30
29
|
...mergeProps(inputProps, focusProps),
|
|
31
|
-
ref:
|
|
30
|
+
ref: inputRef
|
|
32
31
|
})), React.createElement("span", {
|
|
33
32
|
className: styles.selector()
|
|
34
33
|
}), React.createElement("span", {
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FocusHandle } from '../../hook/focus-manager-ref.hook.js';
|
|
3
|
+
import { type RadioGroupContextState } from './radio-group.types.js';
|
|
3
4
|
export declare const RadioGroupContext: React.Context<RadioGroupContextState>;
|
|
4
|
-
export declare
|
|
5
|
+
export declare const RadioGroup: React.ForwardRefExoticComponent<{
|
|
6
|
+
className?: string;
|
|
7
|
+
errorMessage?: string | string[];
|
|
8
|
+
hintMessage?: import("../index.js").HintProps["children"];
|
|
9
|
+
radios: import("./components/radio-group-radio/radio-group-radio.types.js").RadioGroupRadioProps[];
|
|
10
|
+
showAmount?: number;
|
|
11
|
+
size?: "medium" | "large";
|
|
12
|
+
} & Omit<import("react-aria").AriaRadioGroupProps, "errorMessage" | "description"> & React.RefAttributes<FocusHandle>>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { createContext, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import React, { createContext, forwardRef, useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { useFocusRing, useRadioGroup } from 'react-aria';
|
|
4
4
|
import { useRadioGroupState } from 'react-stately';
|
|
5
5
|
import { FUNCTION_NOT_IMPLEMENTED } from '../../constants/message.js';
|
|
6
6
|
import { useBreakpoint } from '../../hook/breakpoints.hook.js';
|
|
7
|
+
import { acceptInputs, useFocusManagerRef } from '../../hook/focus-manager-ref.hook.js';
|
|
7
8
|
import { resolveResponsiveVariant } from '../../utils/breakpoint.util.js';
|
|
8
9
|
import { Button } from '../button/index.js';
|
|
9
10
|
import { ExpandMoreIcon } from '../icon/index.js';
|
|
@@ -69,7 +70,10 @@ export const RadioGroupContext = createContext({
|
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
});
|
|
72
|
-
|
|
73
|
+
function BaseRadioGroup({ className, radios, label, orientation = 'vertical', showAmount = 0, size = 'medium', errorMessage, hintMessage, ...props }, ref) {
|
|
74
|
+
const wrapperRef = useFocusManagerRef(ref, {
|
|
75
|
+
accept: acceptInputs
|
|
76
|
+
});
|
|
73
77
|
const breakpoint = useBreakpoint();
|
|
74
78
|
const resolvedOrientation = resolveResponsiveVariant(orientation, breakpoint);
|
|
75
79
|
const resolvedSize = resolveResponsiveVariant(size, breakpoint);
|
|
@@ -123,7 +127,8 @@ export function RadioGroup({ className, radios, label, orientation = 'vertical',
|
|
|
123
127
|
message: errorMessage
|
|
124
128
|
}), React.createElement("div", {
|
|
125
129
|
className: styles.radioWrapper(),
|
|
126
|
-
id: panelId
|
|
130
|
+
id: panelId,
|
|
131
|
+
ref: wrapperRef
|
|
127
132
|
}, React.createElement(RadioGroupContext.Provider, {
|
|
128
133
|
value: {
|
|
129
134
|
state,
|
|
@@ -145,3 +150,5 @@ export function RadioGroup({ className, radios, label, orientation = 'vertical',
|
|
|
145
150
|
className: styles.buttonText()
|
|
146
151
|
}, `Show ${revealAmount} more ${revealAmount === 1 ? 'item' : 'items'}`))));
|
|
147
152
|
}
|
|
153
|
+
export const RadioGroup = forwardRef(BaseRadioGroup);
|
|
154
|
+
RadioGroup.displayName = 'RadioGroup';
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FocusHandle } from '../../../../hook/focus-manager-ref.hook.js';
|
|
3
|
+
import { SelectorButtonGroupContextState } from './selector-button-group.types.js';
|
|
3
4
|
export declare const SelectorButtonContext: React.Context<SelectorButtonGroupContextState>;
|
|
4
|
-
export declare
|
|
5
|
+
export declare const SelectorButtonGroup: React.ForwardRefExoticComponent<{
|
|
6
|
+
isDisabled?: boolean;
|
|
7
|
+
orientation?: import("../../../../types/responsive-variants.types.js").ResponsiveVariants<"horizontal" | "vertical" | undefined>;
|
|
8
|
+
tag?: keyof JSX.IntrinsicElements;
|
|
9
|
+
value?: string;
|
|
10
|
+
onChange?: (value: string) => void;
|
|
11
|
+
} & import("react-aria").AriaFieldProps & Omit<React.HTMLAttributes<Element>, "onChange"> & React.RefAttributes<FocusHandle>>;
|
package/dist/components/selector/components/selector-button-group/selector-button-group.component.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { createContext, useCallback, useMemo, useState } from 'react';
|
|
2
|
+
import React, { createContext, forwardRef, useCallback, useMemo, useState } from 'react';
|
|
3
3
|
import { useField } from 'react-aria';
|
|
4
4
|
import { useBreakpoint } from '../../../../hook/breakpoints.hook.js';
|
|
5
|
+
import { useFocusManagerRef } from '../../../../hook/focus-manager-ref.hook.js';
|
|
5
6
|
import { resolveResponsiveVariant } from '../../../../utils/breakpoint.util.js';
|
|
6
7
|
import { ErrorMessage, Hint, Label } from '../../../index.js';
|
|
7
8
|
import { styles } from './selector-button-group.styles.js';
|
|
@@ -11,7 +12,8 @@ export const SelectorButtonContext = createContext({
|
|
|
11
12
|
validationState: 'valid',
|
|
12
13
|
isDisabled: undefined
|
|
13
14
|
});
|
|
14
|
-
|
|
15
|
+
function BaseSelectorButtonGroup({ className, children, label, orientation = 'vertical', errorMessage, description, value = '', onChange, isDisabled, ...props }, ref) {
|
|
16
|
+
const wrapperRef = useFocusManagerRef(ref);
|
|
15
17
|
const isControlled = onChange !== undefined;
|
|
16
18
|
const onChangeCallback = onChange;
|
|
17
19
|
const [selected, setSelected] = useState(value);
|
|
@@ -55,8 +57,11 @@ export function SelectorButtonGroup({ className, children, label, orientation =
|
|
|
55
57
|
className,
|
|
56
58
|
orientation: resolvedOrientation
|
|
57
59
|
}),
|
|
58
|
-
...fieldProps
|
|
60
|
+
...fieldProps,
|
|
61
|
+
ref: wrapperRef
|
|
59
62
|
}, React.createElement(SelectorButtonContext.Provider, {
|
|
60
63
|
value: state
|
|
61
64
|
}, children)));
|
|
62
65
|
}
|
|
66
|
+
export const SelectorButtonGroup = forwardRef(BaseSelectorButtonGroup);
|
|
67
|
+
SelectorButtonGroup.displayName = 'SelectorButtonGroup';
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FocusHandle } from '../../../../hook/focus-manager-ref.hook.js';
|
|
3
3
|
export declare const SelectorCheckboxGroupContext: React.Context<import("react-stately").CheckboxGroupState>;
|
|
4
|
-
export declare
|
|
4
|
+
export declare const SelectorCheckboxGroup: React.ForwardRefExoticComponent<{
|
|
5
|
+
className?: string;
|
|
6
|
+
orientation?: "horizontal" | "vertical";
|
|
7
|
+
size?: "medium" | "large";
|
|
8
|
+
} & import("react-aria").AriaCheckboxGroupProps & Omit<React.HTMLAttributes<Element>, "onChange"> & React.RefAttributes<FocusHandle>>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { createContext } from 'react';
|
|
2
|
+
import React, { createContext, forwardRef } from 'react';
|
|
3
3
|
import { useCheckboxGroup } from 'react-aria';
|
|
4
4
|
import { useCheckboxGroupState } from 'react-stately';
|
|
5
5
|
import { FUNCTION_NOT_IMPLEMENTED } from '../../../../constants/message.js';
|
|
6
|
+
import { useFocusManagerRef } from '../../../../hook/focus-manager-ref.hook.js';
|
|
6
7
|
import { ErrorMessage, Hint, Label } from '../../../index.js';
|
|
7
8
|
import { styles } from './selector-checkbox-group.styles.js';
|
|
8
9
|
export const SelectorCheckboxGroupContext = createContext({
|
|
@@ -65,8 +66,9 @@ export const SelectorCheckboxGroupContext = createContext({
|
|
|
65
66
|
throw new Error(FUNCTION_NOT_IMPLEMENTED);
|
|
66
67
|
}
|
|
67
68
|
});
|
|
68
|
-
|
|
69
|
+
function BaseSelectorCheckboxGroup(props, ref) {
|
|
69
70
|
const { children, label, description, errorMessage } = props;
|
|
71
|
+
const wrapperRef = useFocusManagerRef(ref);
|
|
70
72
|
const state = useCheckboxGroupState(props);
|
|
71
73
|
const { groupProps, labelProps, descriptionProps, errorMessageProps } = useCheckboxGroup(props, state);
|
|
72
74
|
return React.createElement(React.Fragment, null, label && React.createElement(Label, labelProps, label), description && React.createElement(Hint, descriptionProps, description), errorMessage && state.isInvalid && React.createElement(ErrorMessage, {
|
|
@@ -76,8 +78,11 @@ export function SelectorCheckboxGroup(props) {
|
|
|
76
78
|
...groupProps,
|
|
77
79
|
className: styles({
|
|
78
80
|
className: groupProps.className
|
|
79
|
-
})
|
|
81
|
+
}),
|
|
82
|
+
ref: wrapperRef
|
|
80
83
|
}, React.createElement(SelectorCheckboxGroupContext.Provider, {
|
|
81
84
|
value: state
|
|
82
85
|
}, children)));
|
|
83
86
|
}
|
|
87
|
+
export const SelectorCheckboxGroup = forwardRef(BaseSelectorCheckboxGroup);
|
|
88
|
+
SelectorCheckboxGroup.displayName = 'SelectorCheckboxGroup';
|
package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FocusHandle } from '../../../../hook/focus-manager-ref.hook.js';
|
|
3
|
+
import { type SelectorRadioGroupContextState } from './selector-radio-group.types.js';
|
|
3
4
|
export declare const SelectorRadioGroupContext: React.Context<SelectorRadioGroupContextState>;
|
|
4
|
-
export declare
|
|
5
|
+
export declare const SelectorRadioGroup: React.ForwardRefExoticComponent<{
|
|
6
|
+
orientation?: "horizontal" | "vertical" | undefined;
|
|
7
|
+
tag?: keyof JSX.IntrinsicElements;
|
|
8
|
+
} & import("react-aria").AriaRadioGroupProps & Omit<React.HTMLAttributes<Element>, "onChange"> & React.RefAttributes<FocusHandle>>;
|
package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, { createContext } from 'react';
|
|
2
|
+
import React, { createContext, forwardRef } from 'react';
|
|
3
3
|
import { useRadioGroup } from 'react-aria';
|
|
4
4
|
import { useRadioGroupState } from 'react-stately';
|
|
5
5
|
import { FUNCTION_NOT_IMPLEMENTED } from '../../../../constants/message.js';
|
|
6
6
|
import { useBreakpoint } from '../../../../hook/breakpoints.hook.js';
|
|
7
|
+
import { useFocusManagerRef } from '../../../../hook/focus-manager-ref.hook.js';
|
|
7
8
|
import { resolveResponsiveVariant } from '../../../../utils/breakpoint.util.js';
|
|
8
9
|
import { ErrorMessage, Hint, Label } from '../../../index.js';
|
|
9
10
|
import { styles } from './selector-radio-group.styles.js';
|
|
@@ -66,7 +67,8 @@ export const SelectorRadioGroupContext = createContext({
|
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
});
|
|
69
|
-
|
|
70
|
+
function BaseSelectorRadioGroup({ className, children, label, orientation = 'vertical', errorMessage, description, ...props }, ref) {
|
|
71
|
+
const wrapperRef = useFocusManagerRef(ref);
|
|
70
72
|
const breakpoint = useBreakpoint();
|
|
71
73
|
const resolvedOrientation = resolveResponsiveVariant(orientation, breakpoint);
|
|
72
74
|
const state = useRadioGroupState({
|
|
@@ -88,7 +90,8 @@ export function SelectorRadioGroup({ className, children, label, orientation = '
|
|
|
88
90
|
className,
|
|
89
91
|
orientation: resolvedOrientation
|
|
90
92
|
}),
|
|
91
|
-
...radioGroupProps
|
|
93
|
+
...radioGroupProps,
|
|
94
|
+
ref: wrapperRef
|
|
92
95
|
}, React.createElement(SelectorRadioGroupContext.Provider, {
|
|
93
96
|
value: {
|
|
94
97
|
state,
|
|
@@ -96,3 +99,5 @@ export function SelectorRadioGroup({ className, children, label, orientation = '
|
|
|
96
99
|
}
|
|
97
100
|
}, children)));
|
|
98
101
|
}
|
|
102
|
+
export const SelectorRadioGroup = forwardRef(BaseSelectorRadioGroup);
|
|
103
|
+
SelectorRadioGroup.displayName = 'SelectorRadioGroup';
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { FocusHandle } from '../../hook/focus-manager-ref.hook.js';
|
|
1
3
|
import { type SelectorProps } from './selector.types.js';
|
|
2
|
-
export declare
|
|
4
|
+
export declare const Selector: React.ForwardRefExoticComponent<SelectorProps & React.RefAttributes<FocusHandle>>;
|
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { forwardRef } from 'react';
|
|
3
3
|
import { SelectorButtonGroup, SelectorCheckboxGroup, SelectorLinkGroup, SelectorRadioGroup } from './components/index.js';
|
|
4
|
-
|
|
4
|
+
function BaseSelector(props, ref) {
|
|
5
5
|
if (props.type === 'checkbox') {
|
|
6
|
-
return React.createElement(SelectorCheckboxGroup,
|
|
6
|
+
return React.createElement(SelectorCheckboxGroup, {
|
|
7
|
+
...props,
|
|
8
|
+
ref: ref
|
|
9
|
+
});
|
|
7
10
|
}
|
|
8
11
|
if (props.type === 'radio') {
|
|
9
|
-
return React.createElement(SelectorRadioGroup,
|
|
12
|
+
return React.createElement(SelectorRadioGroup, {
|
|
13
|
+
...props,
|
|
14
|
+
ref: ref
|
|
15
|
+
});
|
|
10
16
|
}
|
|
11
17
|
if (props.type === 'button') {
|
|
12
|
-
return React.createElement(SelectorButtonGroup,
|
|
18
|
+
return React.createElement(SelectorButtonGroup, {
|
|
19
|
+
...props,
|
|
20
|
+
ref: ref
|
|
21
|
+
});
|
|
13
22
|
}
|
|
14
23
|
if (props.type === 'link') {
|
|
15
24
|
return React.createElement(SelectorLinkGroup, props);
|
|
16
25
|
}
|
|
17
26
|
}
|
|
27
|
+
export const Selector = forwardRef(BaseSelector);
|
|
28
|
+
Selector.displayName = 'Selector';
|
|
@@ -1,2 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
export declare
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export declare const Switch: React.ForwardRefExoticComponent<{
|
|
3
|
+
block?: import("../../types/responsive-variants.types.js").ResponsiveVariants<boolean | undefined>;
|
|
4
|
+
checked?: boolean;
|
|
5
|
+
className?: string;
|
|
6
|
+
label: string;
|
|
7
|
+
size?: import("../../types/responsive-variants.types.js").ResponsiveVariants<"small" | "xlarge" | "medium" | "large" | undefined>;
|
|
8
|
+
} & Omit<import("react-aria").AriaCheckboxProps, "children"> & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import React, {
|
|
3
|
-
import { VisuallyHidden, mergeProps, useCheckbox, useFocusRing } from 'react-aria';
|
|
2
|
+
import React, { forwardRef, useId } from 'react';
|
|
3
|
+
import { VisuallyHidden, mergeProps, useCheckbox, useFocusRing, useObjectRef } from 'react-aria';
|
|
4
4
|
import { useToggleState } from 'react-stately';
|
|
5
5
|
import { useBreakpoint } from '../../hook/breakpoints.hook.js';
|
|
6
6
|
import { resolveResponsiveVariant } from '../../utils/breakpoint.util.js';
|
|
7
7
|
import { styles as switchStyles } from './switch.styles.js';
|
|
8
|
-
|
|
8
|
+
function BaseSwitch({ className, label, size = 'medium', block = false, checked = false, isDisabled, ...props }, forwardedRef) {
|
|
9
9
|
const state = useToggleState({
|
|
10
10
|
...props,
|
|
11
11
|
defaultSelected: checked
|
|
12
12
|
});
|
|
13
13
|
const labelId = useId();
|
|
14
|
-
const ref =
|
|
14
|
+
const ref = useObjectRef(forwardedRef);
|
|
15
15
|
const { isSelected } = state;
|
|
16
16
|
const { inputProps, labelProps } = useCheckbox({
|
|
17
17
|
isDisabled,
|
|
@@ -45,3 +45,5 @@ export function Switch({ className, label, size = 'medium', block = false, check
|
|
|
45
45
|
className: styles.switchDiv()
|
|
46
46
|
}));
|
|
47
47
|
}
|
|
48
|
+
export const Switch = forwardRef(BaseSwitch);
|
|
49
|
+
Switch.displayName = 'Switch';
|
package/dist/css/westpac-ui.css
CHANGED
|
@@ -1093,27 +1093,15 @@
|
|
|
1093
1093
|
.w-\[116px\] {
|
|
1094
1094
|
width: 116px;
|
|
1095
1095
|
}
|
|
1096
|
-
.w-\[120px\] {
|
|
1097
|
-
width: 120px;
|
|
1098
|
-
}
|
|
1099
1096
|
.w-\[122px\] {
|
|
1100
1097
|
width: 122px;
|
|
1101
1098
|
}
|
|
1102
1099
|
.w-\[135px\] {
|
|
1103
1100
|
width: 135px;
|
|
1104
1101
|
}
|
|
1105
|
-
.w-\[140px\] {
|
|
1106
|
-
width: 140px;
|
|
1107
|
-
}
|
|
1108
|
-
.w-\[145px\] {
|
|
1109
|
-
width: 145px;
|
|
1110
|
-
}
|
|
1111
1102
|
.w-\[150px\] {
|
|
1112
1103
|
width: 150px;
|
|
1113
1104
|
}
|
|
1114
|
-
.w-\[165px\] {
|
|
1115
|
-
width: 165px;
|
|
1116
|
-
}
|
|
1117
1105
|
.w-\[170px\] {
|
|
1118
1106
|
width: 170px;
|
|
1119
1107
|
}
|
|
@@ -1339,6 +1327,18 @@
|
|
|
1339
1327
|
.min-w-\[100vw\] {
|
|
1340
1328
|
min-width: 100vw;
|
|
1341
1329
|
}
|
|
1330
|
+
.min-w-\[120px\] {
|
|
1331
|
+
min-width: 120px;
|
|
1332
|
+
}
|
|
1333
|
+
.min-w-\[140px\] {
|
|
1334
|
+
min-width: 140px;
|
|
1335
|
+
}
|
|
1336
|
+
.min-w-\[145px\] {
|
|
1337
|
+
min-width: 145px;
|
|
1338
|
+
}
|
|
1339
|
+
.min-w-\[165px\] {
|
|
1340
|
+
min-width: 165px;
|
|
1341
|
+
}
|
|
1342
1342
|
.min-w-\[200px\] {
|
|
1343
1343
|
min-width: 200px;
|
|
1344
1344
|
}
|
|
@@ -1093,27 +1093,15 @@
|
|
|
1093
1093
|
.w-\[116px\] {
|
|
1094
1094
|
width: 116px;
|
|
1095
1095
|
}
|
|
1096
|
-
.w-\[120px\] {
|
|
1097
|
-
width: 120px;
|
|
1098
|
-
}
|
|
1099
1096
|
.w-\[122px\] {
|
|
1100
1097
|
width: 122px;
|
|
1101
1098
|
}
|
|
1102
1099
|
.w-\[135px\] {
|
|
1103
1100
|
width: 135px;
|
|
1104
1101
|
}
|
|
1105
|
-
.w-\[140px\] {
|
|
1106
|
-
width: 140px;
|
|
1107
|
-
}
|
|
1108
|
-
.w-\[145px\] {
|
|
1109
|
-
width: 145px;
|
|
1110
|
-
}
|
|
1111
1102
|
.w-\[150px\] {
|
|
1112
1103
|
width: 150px;
|
|
1113
1104
|
}
|
|
1114
|
-
.w-\[165px\] {
|
|
1115
|
-
width: 165px;
|
|
1116
|
-
}
|
|
1117
1105
|
.w-\[170px\] {
|
|
1118
1106
|
width: 170px;
|
|
1119
1107
|
}
|
|
@@ -1339,6 +1327,18 @@
|
|
|
1339
1327
|
.min-w-\[100vw\] {
|
|
1340
1328
|
min-width: 100vw;
|
|
1341
1329
|
}
|
|
1330
|
+
.min-w-\[120px\] {
|
|
1331
|
+
min-width: 120px;
|
|
1332
|
+
}
|
|
1333
|
+
.min-w-\[140px\] {
|
|
1334
|
+
min-width: 140px;
|
|
1335
|
+
}
|
|
1336
|
+
.min-w-\[145px\] {
|
|
1337
|
+
min-width: 145px;
|
|
1338
|
+
}
|
|
1339
|
+
.min-w-\[165px\] {
|
|
1340
|
+
min-width: 165px;
|
|
1341
|
+
}
|
|
1342
1342
|
.min-w-\[200px\] {
|
|
1343
1343
|
min-width: 200px;
|
|
1344
1344
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ForwardedRef, RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Imperative handle exposed by group fields (`RadioGroup`, `CheckboxGroup`, `Selector`, `ButtonGroup`) whose
|
|
4
|
+
* focusable control is not a single element the group can point a DOM ref at.
|
|
5
|
+
*
|
|
6
|
+
* `focus()` moves focus to the group's first tabbable option at call time, which is what form libraries
|
|
7
|
+
* such as react-hook-form need (`field.ref` → `ref.focus()` on validation error).
|
|
8
|
+
*/
|
|
9
|
+
export type FocusHandle = {
|
|
10
|
+
focus: () => void;
|
|
11
|
+
};
|
|
12
|
+
export type UseFocusManagerRefOptions = {
|
|
13
|
+
/**
|
|
14
|
+
* Restricts which descendants of the wrapper may receive focus, e.g. only `<input>`s when the wrapper also
|
|
15
|
+
* contains other controls (such as a "show more" button).
|
|
16
|
+
*/
|
|
17
|
+
accept?: (node: Element) => boolean;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Bridges a forwarded {@link FocusHandle} ref to a wrapper element. Returns the ref to attach to the
|
|
21
|
+
* wrapper; `focus()` on the forwarded handle focuses the first tabbable descendant via react-aria's
|
|
22
|
+
* focus manager. Resolution happens when `focus()` is called, so options that render, enable or
|
|
23
|
+
* disable after mount are handled, and roving-tabindex groups (radios) focus their tab stop
|
|
24
|
+
* (the selected option) rather than the first option. When no option is tabbable (e.g. a radio
|
|
25
|
+
* group whose `value` matches no radio, such as `''`), the first focusable option is used instead.
|
|
26
|
+
*/
|
|
27
|
+
export declare function useFocusManagerRef<T extends HTMLElement = HTMLDivElement>(forwardedRef: ForwardedRef<FocusHandle>, { accept }?: UseFocusManagerRefOptions): RefObject<T>;
|
|
28
|
+
/** `accept` predicate for groups whose options are `<input>` elements. */
|
|
29
|
+
export declare const acceptInputs: (node: Element) => boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { createFocusManager } from '@react-aria/focus';
|
|
3
|
+
import { useImperativeHandle, useRef } from 'react';
|
|
4
|
+
export function useFocusManagerRef(forwardedRef, { accept } = {}) {
|
|
5
|
+
const wrapperRef = useRef(null);
|
|
6
|
+
useImperativeHandle(forwardedRef, ()=>({
|
|
7
|
+
focus: ()=>{
|
|
8
|
+
const focusManager = createFocusManager(wrapperRef);
|
|
9
|
+
if (!focusManager.focusFirst({
|
|
10
|
+
tabbable: true,
|
|
11
|
+
accept
|
|
12
|
+
})) {
|
|
13
|
+
focusManager.focusFirst({
|
|
14
|
+
accept
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}), [
|
|
19
|
+
accept
|
|
20
|
+
]);
|
|
21
|
+
return wrapperRef;
|
|
22
|
+
}
|
|
23
|
+
export const acceptInputs = (node)=>node.tagName === 'INPUT';
|
package/dist/hook/index.d.ts
CHANGED