@westpac/ui 1.18.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/component-type.json +1 -1
  3. package/dist/components/button-group/button-group.component.d.ts +2 -1
  4. package/dist/components/button-group/button-group.component.js +6 -3
  5. package/dist/components/checkbox-group/checkbox-group.component.d.ts +11 -2
  6. package/dist/components/checkbox-group/checkbox-group.component.js +10 -3
  7. package/dist/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.d.ts +1 -1
  8. package/dist/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.js +5 -6
  9. package/dist/components/date-picker/components/date-field/components/date-segment/date-segment.component.d.ts +6 -5
  10. package/dist/components/date-picker/components/date-field/components/date-segment/date-segment.component.js +6 -4
  11. package/dist/components/date-picker/components/date-field/date-field.component.d.ts +5 -5
  12. package/dist/components/date-picker/components/date-field/date-field.component.js +7 -3
  13. package/dist/components/date-picker/date-picker.component.d.ts +19 -2
  14. package/dist/components/date-picker/date-picker.component.js +10 -5
  15. package/dist/components/date-picker/date-picker.styles.js +5 -5
  16. package/dist/components/multi-select/components/multi-select-list-box/components/multi-select-option/multi-select-option.component.js +3 -7
  17. 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
  18. package/dist/components/multi-select/components/multi-select-popover/multi-select-popover.component.js +5 -2
  19. package/dist/components/multi-select/components/multi-select-searchbar/multi-select-searchbar.component.js +4 -7
  20. package/dist/components/multi-select/multi-select.component.d.ts +14 -3
  21. package/dist/components/multi-select/multi-select.component.js +10 -16
  22. package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.d.ts +1 -1
  23. package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.js +5 -6
  24. package/dist/components/radio-group/radio-group.component.d.ts +10 -2
  25. package/dist/components/radio-group/radio-group.component.js +10 -3
  26. package/dist/components/selector/components/selector-button-group/selector-button-group.component.d.ts +9 -2
  27. package/dist/components/selector/components/selector-button-group/selector-button-group.component.js +8 -3
  28. package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.d.ts +6 -2
  29. package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.js +8 -3
  30. package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.d.ts +6 -2
  31. package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.js +8 -3
  32. package/dist/components/selector/selector.component.d.ts +3 -1
  33. package/dist/components/selector/selector.component.js +16 -5
  34. package/dist/components/switch/switch.component.d.ts +8 -2
  35. package/dist/components/switch/switch.component.js +6 -4
  36. package/dist/css/westpac-ui.css +12 -12
  37. package/dist/css/westpac-ui.min.css +12 -12
  38. package/dist/hook/focus-manager-ref.hook.d.ts +29 -0
  39. package/dist/hook/focus-manager-ref.hook.js +23 -0
  40. package/dist/hook/index.d.ts +1 -0
  41. package/dist/index.d.ts +1 -0
  42. package/package.json +5 -4
  43. package/src/components/button-group/button-group.component.tsx +26 -16
  44. package/src/components/checkbox-group/checkbox-group.component.tsx +24 -14
  45. package/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx +7 -7
  46. package/src/components/date-picker/components/date-field/components/date-segment/date-segment.component.tsx +10 -4
  47. package/src/components/date-picker/components/date-field/date-field.component.tsx +17 -3
  48. package/src/components/date-picker/date-picker.component.tsx +32 -21
  49. package/src/components/date-picker/date-picker.styles.ts +5 -5
  50. package/src/components/multi-select/components/multi-select-list-box/components/multi-select-option/multi-select-option.component.tsx +3 -5
  51. 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
  52. package/src/components/multi-select/components/multi-select-popover/multi-select-popover.component.tsx +8 -2
  53. package/src/components/multi-select/components/multi-select-searchbar/multi-select-searchbar.component.tsx +3 -6
  54. package/src/components/multi-select/multi-select.component.tsx +33 -28
  55. package/src/components/radio-group/components/radio-group-radio/radio-group-radio.component.tsx +10 -7
  56. package/src/components/radio-group/radio-group.component.tsx +24 -14
  57. package/src/components/selector/components/selector-button-group/selector-button-group.component.tsx +23 -14
  58. package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx +12 -3
  59. package/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx +21 -11
  60. package/src/components/selector/selector.component.tsx +16 -5
  61. package/src/components/switch/switch.component.tsx +10 -12
  62. package/src/hook/focus-manager-ref.hook.ts +56 -0
  63. package/src/hook/index.ts +1 -0
  64. package/src/index.ts +1 -0
@@ -1,4 +1,5 @@
1
1
  import React from 'react';
2
+ import { FocusHandle } from '../../hook/focus-manager-ref.hook.js';
2
3
  import type { ButtonGroupProps } from './button-group.types.js';
3
4
  import type { ToggleGroupState } from 'react-stately';
4
5
  export declare const ToggleButtonGroupContext: React.Context<(ToggleGroupState & {
@@ -7,4 +8,4 @@ export declare const ToggleButtonGroupContext: React.Context<(ToggleGroupState &
7
8
  block: ButtonGroupProps["block"];
8
9
  orientation: ButtonGroupProps["orientation"];
9
10
  }) | null>;
10
- export declare function ButtonGroup({ size, look, block, children, onSelect, orientation, selectionMode, selectedKeys, defaultSelectedKeys, onSelectionChange, className, ...props }: ButtonGroupProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare const ButtonGroup: React.ForwardRefExoticComponent<ButtonGroupProps & React.RefAttributes<FocusHandle>>;
@@ -1,10 +1,12 @@
1
1
  'use client';
2
- import React, { useCallback, useMemo } from 'react';
2
+ import React, { forwardRef, useCallback, useMemo } from 'react';
3
3
  import { useToggleButtonGroup } from 'react-aria';
4
4
  import { useToggleGroupState } from 'react-stately';
5
+ import { useFocusManagerRef } from '../../hook/focus-manager-ref.hook.js';
5
6
  import { styles as buttonGroupStyles } from './button-group.styles.js';
6
7
  export const ToggleButtonGroupContext = React.createContext(null);
7
- export function ButtonGroup({ size, look, block, children, onSelect, orientation = 'horizontal', selectionMode, selectedKeys, defaultSelectedKeys, onSelectionChange, className, ...props }) {
8
+ function BaseButtonGroup({ size, look, block, children, onSelect, orientation = 'horizontal', selectionMode, selectedKeys, defaultSelectedKeys, onSelectionChange, className, ...props }, forwardedRef) {
9
+ const ref = useFocusManagerRef(forwardedRef);
8
10
  const normalizeKeys = useCallback((keys)=>{
9
11
  if (keys === undefined) return undefined;
10
12
  if (selectionMode === 'multiple') return new Set(keys);
@@ -42,7 +44,6 @@ export function ButtonGroup({ size, look, block, children, onSelect, orientation
42
44
  defaultSelectedKeys: finalDefaultSelectedKeys,
43
45
  selectedKeys: finalSelectedKeys
44
46
  });
45
- const ref = React.useRef(null);
46
47
  const { groupProps } = useToggleButtonGroup({
47
48
  ...props,
48
49
  orientation,
@@ -71,3 +72,5 @@ export function ButtonGroup({ size, look, block, children, onSelect, orientation
71
72
  }
72
73
  }, children));
73
74
  }
75
+ export const ButtonGroup = forwardRef(BaseButtonGroup);
76
+ ButtonGroup.displayName = 'ButtonGroup';
@@ -1,4 +1,13 @@
1
1
  import React from 'react';
2
- import { type CheckboxGroupContextState, type CheckboxGroupProps } from './checkbox-group.types.js';
2
+ import { FocusHandle } from '../../hook/focus-manager-ref.hook.js';
3
+ import { type CheckboxGroupContextState } from './checkbox-group.types.js';
3
4
  export declare const CheckboxGroupContext: React.Context<CheckboxGroupContextState>;
4
- export declare function CheckboxGroup({ className, checkboxes, label, orientation, showAmount, size, errorMessage, hintMessage, ...props }: CheckboxGroupProps): import("react/jsx-runtime").JSX.Element;
5
+ export declare const CheckboxGroup: React.ForwardRefExoticComponent<{
6
+ checkboxes: import("./components/checkbox-group-checkbox/checkbox-group-checkbox.types.js").CheckboxGroupCheckboxProps[];
7
+ className?: string;
8
+ errorMessage?: string | string[];
9
+ hintMessage?: import("../index.js").HintProps["children"];
10
+ orientation?: import("../../types/responsive-variants.types.js").ResponsiveVariants<"horizontal" | "vertical" | undefined>;
11
+ showAmount?: number;
12
+ size?: import("../../types/responsive-variants.types.js").ResponsiveVariants<"medium" | "large">;
13
+ } & Omit<import("react-aria").AriaCheckboxGroupProps, "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 { useCheckboxGroup, useFocusRing } from 'react-aria';
4
4
  import { useCheckboxGroupState } 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';
@@ -73,7 +74,10 @@ export const CheckboxGroupContext = createContext({
73
74
  }
74
75
  }
75
76
  });
76
- export function CheckboxGroup({ className, checkboxes, label, orientation = 'vertical', showAmount = 0, size = 'medium', errorMessage, hintMessage, ...props }) {
77
+ function BaseCheckboxGroup({ className, checkboxes, label, orientation = 'vertical', showAmount = 0, size = 'medium', errorMessage, hintMessage, ...props }, ref) {
78
+ const wrapperRef = useFocusManagerRef(ref, {
79
+ accept: acceptInputs
80
+ });
77
81
  const state = useCheckboxGroupState({
78
82
  ...props,
79
83
  label
@@ -123,7 +127,8 @@ export function CheckboxGroup({ className, checkboxes, label, orientation = 'ver
123
127
  message: errorMessage
124
128
  }), React.createElement("div", {
125
129
  className: styles.itemWrapper(),
126
- id: panelId
130
+ id: panelId,
131
+ ref: wrapperRef
127
132
  }, React.createElement(CheckboxGroupContext.Provider, {
128
133
  value: {
129
134
  state,
@@ -145,3 +150,5 @@ export function CheckboxGroup({ className, checkboxes, label, orientation = 'ver
145
150
  className: styles.buttonText()
146
151
  }, `Show ${revealAmount} more ${revealAmount === 1 ? 'item' : 'items'}`))));
147
152
  }
153
+ export const CheckboxGroup = forwardRef(BaseCheckboxGroup);
154
+ CheckboxGroup.displayName = 'CheckboxGroup';
@@ -3,4 +3,4 @@ export declare const CheckboxGroupCheckbox: React.ForwardRefExoticComponent<{
3
3
  className?: string;
4
4
  hint?: React.ReactNode;
5
5
  label: React.ReactNode;
6
- } & Omit<import("react-aria").AriaCheckboxGroupItemProps, "children" | "isIndeterminate"> & React.RefAttributes<HTMLLabelElement>>;
6
+ } & Omit<import("react-aria").AriaCheckboxGroupItemProps, "children" | "isIndeterminate"> & React.RefAttributes<HTMLInputElement>>;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
- import React, { forwardRef, useContext, useRef } from 'react';
3
- import { VisuallyHidden, mergeProps, useCheckboxGroupItem, useFocusRing } from 'react-aria';
2
+ import React, { forwardRef, useContext } from 'react';
3
+ import { VisuallyHidden, mergeProps, useCheckboxGroupItem, useFocusRing, useObjectRef } from 'react-aria';
4
4
  import { Icon } from '../../../icon/icon.component.js';
5
5
  import { CheckboxGroupContext } from '../../checkbox-group.component.js';
6
6
  import { styles as checkboxItemStyles } from './checkbox-group-checkbox.styles.js';
@@ -20,12 +20,12 @@ function CheckIcon({ copyrightYear = '2025', size, ...props }) {
20
20
  }
21
21
  function BaseCheckbox({ className, hint, label, value, ...props }, ref) {
22
22
  const { state, size, orientation } = useContext(CheckboxGroupContext);
23
- const localRef = useRef(null);
23
+ const inputRef = useObjectRef(ref);
24
24
  const { inputProps, labelProps, isDisabled, isSelected } = useCheckboxGroupItem({
25
25
  ...props,
26
26
  value,
27
27
  children: label
28
- }, state, localRef);
28
+ }, state, inputRef);
29
29
  const { isFocusVisible, focusProps } = useFocusRing();
30
30
  const styles = checkboxItemStyles({
31
31
  isDisabled,
@@ -37,13 +37,12 @@ function BaseCheckbox({ className, hint, label, value, ...props }, ref) {
37
37
  className: styles.base({
38
38
  className
39
39
  }),
40
- ref: ref,
41
40
  ...labelProps
42
41
  }, React.createElement(VisuallyHidden, {
43
42
  elementType: "span"
44
43
  }, React.createElement("input", {
45
44
  ...mergeProps(inputProps, focusProps),
46
- ref: localRef
45
+ ref: inputRef
47
46
  })), React.createElement("span", {
48
47
  className: styles.checkbox()
49
48
  }, isSelected && React.createElement(CheckIcon, {
@@ -1,5 +1,6 @@
1
- import { DateSegmentProps } from './date-segment.types.js';
2
- /**
3
- * @private
4
- */
5
- export declare function DateSegment({ segment, state, separator, ...props }: DateSegmentProps): import("react/jsx-runtime").JSX.Element;
1
+ import React from 'react';
2
+ export declare const DateSegment: React.ForwardRefExoticComponent<{
3
+ segment: import("react-stately").DateSegment;
4
+ separator?: string;
5
+ state: import("react-stately").DateFieldState;
6
+ } & React.HTMLAttributes<Element> & React.RefAttributes<HTMLSpanElement>>;
@@ -1,9 +1,9 @@
1
1
  'use client';
2
- import React, { useRef } from 'react';
3
- import { mergeProps, useDateSegment, useFocusRing } from 'react-aria';
2
+ import React, { forwardRef } from 'react';
3
+ import { mergeProps, useDateSegment, useFocusRing, useObjectRef } from 'react-aria';
4
4
  import { styles as dateSegmentStyles } from './date-segment.styles.js';
5
- export function DateSegment({ segment, state, separator, ...props }) {
6
- const ref = useRef(null);
5
+ function BaseDateSegment({ segment, state, separator, ...props }, forwardedRef) {
6
+ const ref = useObjectRef(forwardedRef);
7
7
  const { focusProps, isFocusVisible } = useFocusRing();
8
8
  const { segmentProps } = useDateSegment(segment, state, ref);
9
9
  const styles = dateSegmentStyles({
@@ -17,3 +17,5 @@ export function DateSegment({ segment, state, separator, ...props }) {
17
17
  className: styles
18
18
  }, segment.type === 'literal' ? separator || segment.text : segment.text);
19
19
  }
20
+ export const DateSegment = forwardRef(BaseDateSegment);
21
+ DateSegment.displayName = 'DateSegment';
@@ -1,5 +1,5 @@
1
- import { type DateFieldProps } from './date-field.types.js';
2
- /**
3
- * @private
4
- */
5
- export declare function DateField({ separator, className, ...props }: DateFieldProps): import("react/jsx-runtime").JSX.Element;
1
+ import React from 'react';
2
+ export declare const DateField: React.ForwardRefExoticComponent<import("react-aria").AriaDateFieldProps<import("react-aria").DateValue> & {
3
+ separator?: string;
4
+ className?: string;
5
+ } & React.RefAttributes<HTMLSpanElement>>;
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
  import { createCalendar } from '@internationalized/date';
3
- import React, { useRef } from 'react';
3
+ import React, { forwardRef, useRef } from 'react';
4
4
  import { useDateField, useLocale } from 'react-aria';
5
5
  import { useDateFieldState } from 'react-stately';
6
6
  import { DateSegment } from './components/date-segment/date-segment.component.js';
7
- export function DateField({ separator, className, ...props }) {
7
+ function BaseDateField({ separator, className, ...props }, forwardedRef) {
8
8
  const { locale } = useLocale();
9
9
  const state = useDateFieldState({
10
10
  ...props,
@@ -13,6 +13,7 @@ export function DateField({ separator, className, ...props }) {
13
13
  });
14
14
  const ref = useRef(null);
15
15
  const { fieldProps } = useDateField(props, state, ref);
16
+ const firstEditableIndex = state.segments.findIndex((segment)=>segment.isEditable);
16
17
  return React.createElement("div", {
17
18
  ...fieldProps,
18
19
  className: className,
@@ -21,6 +22,9 @@ export function DateField({ separator, className, ...props }) {
21
22
  separator: separator,
22
23
  key: i,
23
24
  segment: segment,
24
- state: state
25
+ state: state,
26
+ ref: i === firstEditableIndex ? forwardedRef : null
25
27
  })));
26
28
  }
29
+ export const DateField = forwardRef(BaseDateField);
30
+ DateField.displayName = 'DateField';
@@ -1,2 +1,19 @@
1
- import { type DatePickerProps } from './date-picker.types.js';
2
- export declare function DatePicker({ size, className, bottomSheetView, block, isDateUnavailable, disableDaysOfWeek, disableWeekends, separator, portalContainer, placement, ...props }: DatePickerProps): import("react/jsx-runtime").JSX.Element;
1
+ import { Breakpoint } from '@westpac/style-config/constants';
2
+ import React from 'react';
3
+ export declare const DatePicker: React.ForwardRefExoticComponent<Omit<import("react-stately").DatePickerStateOptions<import("react-aria").DateValue>, "onBlur"> & Omit<{
4
+ size?: "small" | "xlarge" | "medium" | "large" | undefined;
5
+ block?: boolean | undefined;
6
+ isDisabled?: boolean | undefined;
7
+ isReadOnly?: boolean | undefined;
8
+ isInvalid?: boolean | undefined;
9
+ }, "size" | "block"> & Omit<React.HTMLAttributes<HTMLDivElement>, "onBlur" | "invalid" | "block"> & {
10
+ bottomSheetView?: boolean | Partial<Record<Breakpoint | "initial", boolean>>;
11
+ disableDaysOfWeek?: number[];
12
+ disableWeekends?: boolean;
13
+ separator?: string;
14
+ onBlur?: ((event: React.FocusEvent<Element, Element>, date?: import("react-aria").DateValue | undefined) => void) | undefined;
15
+ placement?: "top left" | "top right" | "bottom left" | "bottom right";
16
+ portalContainer?: Element;
17
+ size?: import("../../types/responsive-variants.types.js").ResponsiveVariants<"small" | "xlarge" | "medium" | "large" | undefined>;
18
+ block?: import("../../types/responsive-variants.types.js").ResponsiveVariants<boolean | undefined>;
19
+ } & React.RefAttributes<HTMLSpanElement>>;
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { getDayOfWeek, isWeekend } from '@internationalized/date';
3
- import React, { useMemo, useRef } from 'react';
3
+ import React, { forwardRef, useMemo, useRef } from 'react';
4
4
  import { useButton, useDatePicker, useLocale } from 'react-aria';
5
5
  import { useDatePickerState } from 'react-stately';
6
6
  import { useBreakpoint } from '../../hook/breakpoints.hook.js';
@@ -20,10 +20,10 @@ const BREAKPOINTS_DECRECENT = [
20
20
  'xsl',
21
21
  'initial'
22
22
  ];
23
- export function DatePicker({ size = 'medium', className, bottomSheetView = {
23
+ function BaseDatePicker({ size = 'medium', className, bottomSheetView = {
24
24
  initial: true,
25
25
  xsl: false
26
- }, block, isDateUnavailable, disableDaysOfWeek, disableWeekends, separator, portalContainer, placement = 'bottom left', ...props }) {
26
+ }, block, isDateUnavailable, disableDaysOfWeek, disableWeekends, separator, portalContainer, placement = 'bottom left', ...props }, forwardedRef) {
27
27
  const { locale } = useLocale();
28
28
  const enhancedIsDateUnavailable = useMemo(()=>{
29
29
  return disableDaysOfWeek || disableWeekends ? (date)=>{
@@ -86,7 +86,9 @@ export function DatePicker({ size = 'medium', className, bottomSheetView = {
86
86
  const buttonRef = useRef(null);
87
87
  const { buttonProps: newButtonProps } = useButton(buttonProps, buttonRef);
88
88
  const brandContainer = useMemo(()=>{
89
- return document.querySelector('[data-brand]') || document.querySelector('[class^="theme-"], [class*=" theme-"]') || undefined;
89
+ if (typeof window !== 'undefined') {
90
+ return document.querySelector('[data-brand]') || document.querySelector('[class^="theme-"], [class*=" theme-"]') || undefined;
91
+ }
90
92
  }, []);
91
93
  return React.createElement(React.Fragment, null, props.label && React.createElement("div", labelProps, props.label), React.createElement("div", {
92
94
  ...props,
@@ -106,7 +108,8 @@ export function DatePicker({ size = 'medium', className, bottomSheetView = {
106
108
  }, React.createElement(DateField, {
107
109
  className: styles.dateField(),
108
110
  separator: separator,
109
- ...fieldProps
111
+ ...fieldProps,
112
+ ref: forwardedRef
110
113
  }), React.createElement(Button, {
111
114
  look: "faint",
112
115
  className: styles.button(),
@@ -126,3 +129,5 @@ export function DatePicker({ size = 'medium', className, bottomSheetView = {
126
129
  firstDayOfWeek: props.firstDayOfWeek
127
130
  }))));
128
131
  }
132
+ export const DatePicker = forwardRef(BaseDatePicker);
133
+ DatePicker.displayName = 'DatePicker';
@@ -2,26 +2,26 @@ import { tv } from 'tailwind-variants';
2
2
  export const styles = tv({
3
3
  slots: {
4
4
  input: 'form-control flex items-center border-0',
5
- dateField: 'rounded rounded-r-none border border-r-0 border-border-muted-strong',
5
+ dateField: 'rounded rounded-r-none border border-r-0 border-border-muted-strong whitespace-nowrap',
6
6
  button: 'flex items-center justify-center rounded-l-none border-border-muted-strong bg-surface-muted-pale'
7
7
  },
8
8
  variants: {
9
9
  size: {
10
10
  small: {
11
11
  input: 'max-h-5',
12
- dateField: 'h-5 w-[120px] form-control-small'
12
+ dateField: 'h-5 min-w-[120px] form-control-small'
13
13
  },
14
14
  medium: {
15
15
  input: 'max-h-6',
16
- dateField: 'h-6 w-[140px] form-control-medium'
16
+ dateField: 'h-6 min-w-[140px] form-control-medium'
17
17
  },
18
18
  large: {
19
19
  input: 'max-h-7',
20
- dateField: 'h-7 w-[145px] form-control-large'
20
+ dateField: 'h-7 min-w-[145px] form-control-large'
21
21
  },
22
22
  xlarge: {
23
23
  input: 'max-h-8',
24
- dateField: 'h-8 w-[165px] form-control-xlarge'
24
+ dateField: 'h-8 min-w-[165px] form-control-xlarge'
25
25
  }
26
26
  },
27
27
  block: {
@@ -1,4 +1,5 @@
1
1
  'use client';
2
+ import { focusWithoutScrolling } from '@react-aria/utils';
2
3
  import React, { useCallback, useContext, useRef } from 'react';
3
4
  import { mergeProps, useFocusRing, useOption } from 'react-aria';
4
5
  import { TickIcon } from '../../../../../icon/index.js';
@@ -21,13 +22,8 @@ export function MultiSelectOption({ item }) {
21
22
  const handleButtonKeyDown = useCallback((e)=>{
22
23
  if (e.key === 'ArrowUp' && item.index === 0) {
23
24
  e.preventDefault();
24
- if (selectAllRef.current) {
25
- var _selectAllRef_current;
26
- (_selectAllRef_current = selectAllRef.current) === null || _selectAllRef_current === void 0 ? void 0 : _selectAllRef_current.focus();
27
- } else {
28
- var _inputRef_current;
29
- (_inputRef_current = inputRef.current) === null || _inputRef_current === void 0 ? void 0 : _inputRef_current.focus();
30
- }
25
+ const target = selectAllRef.current || inputRef.current;
26
+ if (target) focusWithoutScrolling(target);
31
27
  }
32
28
  if (e.key === 'Enter' || e.key === ' ') {
33
29
  e.preventDefault();
@@ -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
- firstItem === null || firstItem === void 0 ? void 0 : firstItem.focus();
44
+ if (firstItem) focusWithoutScrolling(firstItem);
44
45
  }
45
46
  if (e.key === 'ArrowUp') {
46
- var _inputRef_current;
47
47
  e.preventDefault();
48
- (_inputRef_current = inputRef.current) === null || _inputRef_current === void 0 ? void 0 : _inputRef_current.focus();
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
- }, overlayState);
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
- if (selectAllRef.current) {
15
- selectAllRef.current.focus();
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<typeof BaseMultiSelect>;
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 React, { useRef, useState, memo, createContext } from 'react';
3
- import { useFilter, useOverlayTrigger } from 'react-aria';
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 = useRef(null);
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
- if (!hideFilter) {
53
- var _inputRef_current;
54
- (_inputRef_current = inputRef.current) === null || _inputRef_current === void 0 ? void 0 : _inputRef_current.focus();
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';
@@ -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<HTMLLabelElement>>;
6
+ } & Omit<import("react-aria").AriaRadioProps, "children"> & React.RefAttributes<HTMLInputElement>>;
@@ -1,15 +1,15 @@
1
1
  'use client';
2
- import React, { forwardRef, useContext, useRef } from 'react';
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 localRef = useRef(null);
8
+ const inputRef = useObjectRef(ref);
9
9
  const { inputProps, labelProps, isSelected, isDisabled } = useRadio({
10
10
  ...props,
11
11
  children: label
12
- }, state, localRef);
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: localRef
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 { type RadioGroupContextState, type RadioGroupProps } from './radio-group.types.js';
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 function RadioGroup({ className, radios, label, orientation, showAmount, size, errorMessage, hintMessage, ...props }: RadioGroupProps): import("react/jsx-runtime").JSX.Element;
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
- export function RadioGroup({ className, radios, label, orientation = 'vertical', showAmount = 0, size = 'medium', errorMessage, hintMessage, ...props }) {
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 { SelectorButtonGroupContextState, SelectorButtonGroupProps } from './selector-button-group.types.js';
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 function SelectorButtonGroup({ className, children, label, orientation, errorMessage, description, value, onChange, isDisabled, ...props }: SelectorButtonGroupProps): import("react/jsx-runtime").JSX.Element;
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>>;