@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.
Files changed (79) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/component-type.json +1 -1
  3. package/dist/components/button/button.component.d.ts +2 -17
  4. package/dist/components/button/button.component.js +9 -4
  5. package/dist/components/button/button.types.d.ts +16 -6
  6. package/dist/components/button-group/button-group.component.d.ts +2 -1
  7. package/dist/components/button-group/button-group.component.js +6 -3
  8. package/dist/components/checkbox-group/checkbox-group.component.d.ts +11 -2
  9. package/dist/components/checkbox-group/checkbox-group.component.js +10 -3
  10. package/dist/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.d.ts +1 -1
  11. package/dist/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.js +5 -6
  12. package/dist/components/date-picker/components/date-field/components/date-segment/date-segment.component.d.ts +6 -5
  13. package/dist/components/date-picker/components/date-field/components/date-segment/date-segment.component.js +6 -4
  14. package/dist/components/date-picker/components/date-field/date-field.component.d.ts +5 -5
  15. package/dist/components/date-picker/components/date-field/date-field.component.js +7 -3
  16. package/dist/components/date-picker/date-picker.component.d.ts +19 -2
  17. package/dist/components/date-picker/date-picker.component.js +10 -5
  18. package/dist/components/date-picker/date-picker.styles.js +5 -5
  19. package/dist/components/link/link.component.d.ts +4 -12
  20. package/dist/components/link/link.component.js +30 -7
  21. package/dist/components/link/link.types.d.ts +26 -3
  22. package/dist/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.component.d.ts +1 -1
  23. package/dist/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.component.js +14 -7
  24. package/dist/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.types.d.ts +11 -0
  25. package/dist/components/multi-select/components/multi-select-list-box/components/multi-select-option/multi-select-option.component.js +3 -7
  26. 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
  27. package/dist/components/multi-select/components/multi-select-popover/multi-select-popover.component.js +5 -2
  28. package/dist/components/multi-select/components/multi-select-searchbar/multi-select-searchbar.component.js +4 -7
  29. package/dist/components/multi-select/multi-select.component.d.ts +14 -3
  30. package/dist/components/multi-select/multi-select.component.js +10 -16
  31. package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.d.ts +1 -1
  32. package/dist/components/radio-group/components/radio-group-radio/radio-group-radio.component.js +5 -6
  33. package/dist/components/radio-group/radio-group.component.d.ts +10 -2
  34. package/dist/components/radio-group/radio-group.component.js +10 -3
  35. package/dist/components/selector/components/selector-button-group/selector-button-group.component.d.ts +9 -2
  36. package/dist/components/selector/components/selector-button-group/selector-button-group.component.js +8 -3
  37. package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.d.ts +6 -2
  38. package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.js +8 -3
  39. package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.d.ts +6 -2
  40. package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.js +8 -3
  41. package/dist/components/selector/selector.component.d.ts +3 -1
  42. package/dist/components/selector/selector.component.js +16 -5
  43. package/dist/components/switch/switch.component.d.ts +8 -2
  44. package/dist/components/switch/switch.component.js +6 -4
  45. package/dist/css/westpac-ui.css +12 -12
  46. package/dist/css/westpac-ui.min.css +12 -12
  47. package/dist/hook/focus-manager-ref.hook.d.ts +29 -0
  48. package/dist/hook/focus-manager-ref.hook.js +23 -0
  49. package/dist/hook/index.d.ts +1 -0
  50. package/dist/index.d.ts +1 -0
  51. package/package.json +5 -3
  52. package/src/components/button/button.component.tsx +10 -9
  53. package/src/components/button/button.types.ts +21 -8
  54. package/src/components/button-group/button-group.component.tsx +26 -16
  55. package/src/components/checkbox-group/checkbox-group.component.tsx +24 -14
  56. package/src/components/checkbox-group/components/checkbox-group-checkbox/checkbox-group-checkbox.component.tsx +7 -7
  57. package/src/components/date-picker/components/date-field/components/date-segment/date-segment.component.tsx +10 -4
  58. package/src/components/date-picker/components/date-field/date-field.component.tsx +17 -3
  59. package/src/components/date-picker/date-picker.component.tsx +32 -21
  60. package/src/components/date-picker/date-picker.styles.ts +5 -5
  61. package/src/components/link/link.component.tsx +60 -12
  62. package/src/components/link/link.types.ts +31 -4
  63. package/src/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.component.tsx +16 -2
  64. package/src/components/modal/components/modal-dialog/components/modal-dialog-footer/modal-dialog-footer.types.ts +12 -0
  65. package/src/components/multi-select/components/multi-select-list-box/components/multi-select-option/multi-select-option.component.tsx +3 -5
  66. 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
  67. package/src/components/multi-select/components/multi-select-popover/multi-select-popover.component.tsx +8 -2
  68. package/src/components/multi-select/components/multi-select-searchbar/multi-select-searchbar.component.tsx +3 -6
  69. package/src/components/multi-select/multi-select.component.tsx +33 -28
  70. package/src/components/radio-group/components/radio-group-radio/radio-group-radio.component.tsx +10 -7
  71. package/src/components/radio-group/radio-group.component.tsx +24 -14
  72. package/src/components/selector/components/selector-button-group/selector-button-group.component.tsx +23 -14
  73. package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx +12 -3
  74. package/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx +21 -11
  75. package/src/components/selector/selector.component.tsx +16 -5
  76. package/src/components/switch/switch.component.tsx +10 -12
  77. package/src/hook/focus-manager-ref.hook.ts +56 -0
  78. package/src/hook/index.ts +1 -0
  79. package/src/index.ts +1 -0
@@ -1,17 +1,2 @@
1
- import React from 'react';
2
- import { ButtonRef } from './button.types.js';
3
- export declare const Button: React.ForwardRefExoticComponent<{
4
- block?: import("../../types/responsive-variants.types.js").ResponsiveVariants<boolean | undefined>;
5
- children?: React.ReactNode;
6
- iconAfter?: (props: import("../icon/icon.types.js").IconProps) => JSX.Element;
7
- iconBefore?: (props: import("../icon/icon.types.js").IconProps) => JSX.Element;
8
- iconColor?: import("../icon/icon.types.js").IconProps["color"];
9
- iconLook?: import("../icon/icon.types.js").IconProps["look"];
10
- iconSize?: import("../icon/icon.types.js").IconProps["size"];
11
- justify?: import("../../types/responsive-variants.types.js").ResponsiveVariants<boolean | undefined>;
12
- look?: import("../../types/responsive-variants.types.js").ResponsiveVariants<"link" | "primary" | "hero" | "faint" | "unstyled" | undefined>;
13
- removeLinkPadding?: boolean;
14
- size?: import("../../types/responsive-variants.types.js").ResponsiveVariants<"small" | "xlarge" | "medium" | "large" | undefined>;
15
- soft?: import("../../types/responsive-variants.types.js").ResponsiveVariants<boolean | undefined>;
16
- tag?: keyof Pick<JSX.IntrinsicElements, "a" | "span" | "button" | "div">;
17
- } & React.ButtonHTMLAttributes<Element> & React.AnchorHTMLAttributes<Element> & React.RefAttributes<ButtonRef>>;
1
+ import { ButtonComponent } from './button.types.js';
2
+ export declare const Button: ButtonComponent;
@@ -5,7 +5,13 @@ import { useBreakpoint } from '../../hook/breakpoints.hook.js';
5
5
  import { resolveResponsiveVariant } from '../../utils/breakpoint.util.js';
6
6
  import { styles as buttonStyles } from './button.styles.js';
7
7
  import { getIconSize } from './button.utils.js';
8
- function BaseButton({ className, size = 'medium', look = 'hero', soft, block = false, justify, tag: Tag = 'button', iconBefore: IconBefore, iconAfter: IconAfter, iconLook, iconColor, iconSize, children, removeLinkPadding, type = Tag === 'button' ? 'button' : undefined, ...props }, ref) {
8
+ function BaseButton({ className, size = 'medium', look = 'hero', soft, block = false, justify, tag: Tag, iconBefore: IconBefore, iconAfter: IconAfter, iconLook, iconColor, iconSize, children, removeLinkPadding, ...props }, ref) {
9
+ var _props_type;
10
+ const Component = Tag !== null && Tag !== void 0 ? Tag : 'button';
11
+ const renderProps = Component === 'button' ? {
12
+ ...props,
13
+ type: (_props_type = props.type) !== null && _props_type !== void 0 ? _props_type : 'button'
14
+ } : props;
9
15
  const { isFocusVisible, focusProps } = useFocusRing();
10
16
  const btnIconSize = useMemo(()=>iconSize || getIconSize(size), [
11
17
  iconSize,
@@ -52,13 +58,12 @@ function BaseButton({ className, size = 'medium', look = 'hero', soft, block = f
52
58
  look,
53
59
  soft
54
60
  ]);
55
- return React.createElement(Tag, {
61
+ return React.createElement(Component, {
56
62
  ref: ref,
57
63
  className: styles.base({
58
64
  className
59
65
  }),
60
- ...mergeProps(props, focusProps),
61
- type: type
66
+ ...mergeProps(renderProps, focusProps)
62
67
  }, IconBefore && React.createElement(IconBefore, {
63
68
  look: iconLook,
64
69
  size: btnIconSize,
@@ -1,11 +1,10 @@
1
- import { AnchorHTMLAttributes, ButtonHTMLAttributes, ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
  import { type VariantProps } from 'tailwind-variants';
3
3
  import { ResponsiveVariants } from '../../types/responsive-variants.types.js';
4
4
  import { IconProps } from '../icon/index.js';
5
5
  import { styles } from './button.styles.js';
6
6
  type Variants = VariantProps<typeof styles>;
7
- export type ButtonRef = HTMLButtonElement & HTMLAnchorElement & HTMLSpanElement & HTMLDivElement;
8
- export type ButtonProps = {
7
+ export type BaseButtonProps = {
9
8
  /**
10
9
  * Fit button width to its parent width.
11
10
  * @default false
@@ -64,10 +63,21 @@ export type ButtonProps = {
64
63
  * Removes background colour and adjusts text colour.
65
64
  */
66
65
  soft?: ResponsiveVariants<Variants['soft']>;
66
+ };
67
+ export type ButtonRef<C extends React.ElementType = 'button'> = React.ComponentRef<C>;
68
+ export type PolymorphicRef<C extends React.ElementType> = React.ComponentPropsWithRef<C>['ref'];
69
+ export type ButtonProps<C extends React.ElementType = 'button'> = BaseButtonProps & {
67
70
  /**
68
- * Tag to render
71
+ * Type to render
69
72
  * @default button
70
73
  */
71
- tag?: keyof Pick<JSX.IntrinsicElements, 'a' | 'span' | 'button' | 'div'>;
72
- } & ButtonHTMLAttributes<Element> & AnchorHTMLAttributes<Element>;
74
+ tag?: C;
75
+ } & Omit<React.ComponentPropsWithoutRef<C>, keyof BaseButtonProps | 'tag'>;
76
+ export type ButtonImplementationProps = BaseButtonProps & {
77
+ className?: string;
78
+ tag?: React.ElementType;
79
+ } & Record<string, unknown>;
80
+ export type ButtonComponent = <C extends React.ElementType = 'button'>(props: ButtonProps<C> & {
81
+ ref?: PolymorphicRef<C>;
82
+ }) => React.ReactElement | null;
73
83
  export {};
@@ -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,12 +1,4 @@
1
- import React, { ForwardedRef } from 'react';
2
- import { type LinkProps } from './link.types.js';
3
- export declare function BaseLink({ className, children, href, iconBefore: IconBefore, iconAfter: IconAfter, iconSize, target, type, underline, ...props }: LinkProps, ref: ForwardedRef<HTMLAnchorElement>): import("react/jsx-runtime").JSX.Element;
4
- export declare const Link: React.ForwardRefExoticComponent<{
5
- children?: React.ReactNode;
6
- className?: string;
7
- iconAfter?: (props: import("../icon/icon.types.js").IconProps) => JSX.Element;
8
- iconBefore?: (props: import("../icon/icon.types.js").IconProps) => JSX.Element;
9
- iconSize?: "xsmall" | "small" | "medium" | "large" | "xlarge";
10
- type?: "inline" | "standalone";
11
- underline?: boolean;
12
- } & Omit<import("react-aria").AriaLinkOptions, "isDisabled" | "elementType"> & React.AnchorHTMLAttributes<Element> & React.RefAttributes<HTMLAnchorElement>>;
1
+ import { ForwardedRef } from 'react';
2
+ import { LinkComponent, LinkImplementationProps } from './link.types.js';
3
+ export declare function BaseLink({ className, children, href, tag: Tag, iconBefore: IconBefore, iconAfter: IconAfter, iconSize, target, type, underline, autoFocus, elementType, onBlur, onClick, onFocus, onFocusChange, onKeyDown, onKeyUp, onPress, onPressChange, onPressEnd, onPressStart, onPressUp, download, ping, referrerPolicy, rel, routerOptions, ...componentProps }: LinkImplementationProps, ref: ForwardedRef<unknown>): import("react/jsx-runtime").JSX.Element;
4
+ export declare const Link: LinkComponent;
@@ -1,13 +1,35 @@
1
1
  'use client';
2
2
  import React, { forwardRef } from 'react';
3
- import { mergeProps, useFocusRing, useLink } from 'react-aria';
3
+ import { mergeProps, useFocusRing, useLink, useObjectRef } from 'react-aria';
4
4
  import { ArrowRightIcon } from '../icon/index.js';
5
5
  import { styles as linkStyles } from './link.styles.js';
6
- export function BaseLink({ className, children, href, iconBefore: IconBefore, iconAfter: IconAfter, iconSize = 'small', target, type = 'standalone', underline = true, ...props }, ref) {
6
+ export function BaseLink({ className, children, href, tag: Tag, iconBefore: IconBefore, iconAfter: IconAfter, iconSize = 'small', target, type = 'standalone', underline = true, autoFocus, elementType, onBlur, onClick, onFocus, onFocusChange, onKeyDown, onKeyUp, onPress, onPressChange, onPressEnd, onPressStart, onPressUp, download, ping, referrerPolicy, rel, routerOptions, ...componentProps }, ref) {
7
+ const Component = Tag !== null && Tag !== void 0 ? Tag : 'a';
8
+ const ariaElementType = typeof Component === 'string' ? Component : elementType !== null && elementType !== void 0 ? elementType : 'a';
9
+ const linkRef = useObjectRef(ref);
7
10
  const { linkProps } = useLink({
8
- ...props,
9
- elementType: 'a'
10
- }, ref);
11
+ ...componentProps,
12
+ autoFocus,
13
+ download,
14
+ elementType: ariaElementType,
15
+ href: typeof href === 'string' ? href : undefined,
16
+ onBlur,
17
+ onClick,
18
+ onFocus,
19
+ onFocusChange,
20
+ onKeyDown,
21
+ onKeyUp,
22
+ onPress,
23
+ onPressChange,
24
+ onPressEnd,
25
+ onPressStart,
26
+ onPressUp,
27
+ ping,
28
+ referrerPolicy,
29
+ rel,
30
+ routerOptions,
31
+ target
32
+ }, linkRef);
11
33
  const { isFocusVisible, focusProps } = useFocusRing();
12
34
  const styles = linkStyles({
13
35
  type,
@@ -17,9 +39,10 @@ export function BaseLink({ className, children, href, iconBefore: IconBefore, ic
17
39
  if (type === 'standalone' && !IconBefore && !IconAfter) {
18
40
  IconBefore = ArrowRightIcon;
19
41
  }
20
- return React.createElement("a", {
42
+ return React.createElement(Component, {
43
+ ...componentProps,
21
44
  ...mergeProps(linkProps, focusProps),
22
- ref: ref,
45
+ ref: linkRef,
23
46
  href: href,
24
47
  target: target,
25
48
  className: styles.base({
@@ -1,7 +1,7 @@
1
- import { AnchorHTMLAttributes, ReactNode } from 'react';
1
+ import { ReactNode } from 'react';
2
2
  import { AriaLinkOptions } from 'react-aria';
3
3
  import { IconProps } from '../icon/index.js';
4
- export type LinkProps = {
4
+ export type BaseLinkProps = {
5
5
  /**
6
6
  * Link text or component
7
7
  */
@@ -33,4 +33,27 @@ export type LinkProps = {
33
33
  * @default true
34
34
  */
35
35
  underline?: boolean;
36
- } & Omit<AriaLinkOptions, 'isDisabled' | 'elementType'> & AnchorHTMLAttributes<Element>;
36
+ /**
37
+ * Specifies DOM element rendered by a custom component
38
+ * Required when the custom component does not render an '<a>' element
39
+ * @default 'a'
40
+ */
41
+ elementType?: AriaLinkOptions['elementType'];
42
+ } & Omit<AriaLinkOptions, 'elementType' | 'href' | 'isDisabled'>;
43
+ export type LinkRef<C extends React.ElementType = 'a'> = React.ComponentRef<C>;
44
+ export type PolymorphicRef<C extends React.ElementType> = React.ComponentPropsWithRef<C>['ref'];
45
+ export type LinkProps<C extends React.ElementType = 'a'> = BaseLinkProps & {
46
+ /**
47
+ * Type to render
48
+ * @default a
49
+ */
50
+ tag?: C;
51
+ } & Omit<React.ComponentPropsWithoutRef<C>, keyof BaseLinkProps | 'tag'>;
52
+ export type LinkImplementationProps = BaseLinkProps & {
53
+ className?: string;
54
+ href?: unknown;
55
+ tag?: React.ElementType;
56
+ } & Record<string, unknown>;
57
+ export type LinkComponent = <C extends React.ElementType = 'a'>(props: LinkProps<C> & {
58
+ ref?: PolymorphicRef<C>;
59
+ }) => React.ReactElement | null;
@@ -1,2 +1,2 @@
1
1
  import { type ModalDialogFooterProps } from './modal-dialog-footer.types.js';
2
- export declare function ModalDialogFooter({ className, primaryLabel, primaryOnClick, secondaryLabel, secondaryOnClick, ...props }: ModalDialogFooterProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function ModalDialogFooter({ className, primaryButtonProps, primaryLabel, primaryOnClick, secondaryButtonProps, secondaryLabel, secondaryOnClick, ...props }: ModalDialogFooterProps): import("react/jsx-runtime").JSX.Element;
@@ -5,7 +5,8 @@ import { resolveResponsiveVariant } from '../../../../../../utils/breakpoint.uti
5
5
  import { Button } from '../../../../../button/index.js';
6
6
  import { useModalDialogContext } from '../../modal-dialog.component.js';
7
7
  import { styles as modalFooterStyles } from './modal-dialog-footer.styles.js';
8
- export function ModalDialogFooter({ className, primaryLabel, primaryOnClick, secondaryLabel, secondaryOnClick, ...props }) {
8
+ export function ModalDialogFooter({ className, primaryButtonProps, primaryLabel, primaryOnClick, secondaryButtonProps, secondaryLabel, secondaryOnClick, ...props }) {
9
+ var _ref, _ref1, _ref2, _ref3;
9
10
  const { size, compact, setFooterPresent } = useModalDialogContext();
10
11
  const breakpoint = useBreakpoint();
11
12
  const styles = modalFooterStyles({
@@ -23,14 +24,20 @@ export function ModalDialogFooter({ className, primaryLabel, primaryOnClick, sec
23
24
  }),
24
25
  ...props
25
26
  }, React.createElement(Button, {
26
- look: "primary",
27
- size: "large",
28
- className: styles.primaryBtn(),
27
+ ...primaryButtonProps,
28
+ look: (_ref = primaryButtonProps === null || primaryButtonProps === void 0 ? void 0 : primaryButtonProps.look) !== null && _ref !== void 0 ? _ref : 'primary',
29
+ size: (_ref1 = primaryButtonProps === null || primaryButtonProps === void 0 ? void 0 : primaryButtonProps.size) !== null && _ref1 !== void 0 ? _ref1 : 'large',
30
+ className: styles.primaryBtn({
31
+ className: primaryButtonProps === null || primaryButtonProps === void 0 ? void 0 : primaryButtonProps.className
32
+ }),
29
33
  onClick: primaryOnClick
30
34
  }, primaryLabel), secondaryLabel && React.createElement(Button, {
31
- look: "link",
32
- size: "large",
33
- className: styles.secondaryBtn(),
35
+ ...secondaryButtonProps,
36
+ look: (_ref2 = secondaryButtonProps === null || secondaryButtonProps === void 0 ? void 0 : secondaryButtonProps.look) !== null && _ref2 !== void 0 ? _ref2 : 'link',
37
+ size: (_ref3 = secondaryButtonProps === null || secondaryButtonProps === void 0 ? void 0 : secondaryButtonProps.size) !== null && _ref3 !== void 0 ? _ref3 : 'large',
38
+ className: styles.secondaryBtn({
39
+ className: secondaryButtonProps === null || secondaryButtonProps === void 0 ? void 0 : secondaryButtonProps.className
40
+ }),
34
41
  onClick: secondaryOnClick
35
42
  }, secondaryLabel));
36
43
  }
@@ -1,9 +1,15 @@
1
1
  import { HTMLAttributes, ReactNode } from 'react';
2
+ import { type ButtonProps } from '../../../../../button/index.js';
3
+ type ModalFooterButtonProps = Omit<ButtonProps, 'children' | 'onClick'>;
2
4
  export type ModalDialogFooterProps = {
3
5
  /**
4
6
  * Footer content
5
7
  */
6
8
  children?: ReactNode;
9
+ /**
10
+ * Props passed to the primary button
11
+ */
12
+ primaryButtonProps?: ModalFooterButtonProps;
7
13
  /**
8
14
  * Label for primary button
9
15
  */
@@ -12,6 +18,10 @@ export type ModalDialogFooterProps = {
12
18
  * onClick for primary button
13
19
  */
14
20
  primaryOnClick: () => void;
21
+ /**
22
+ * Props passed to the secondary button
23
+ */
24
+ secondaryButtonProps?: ModalFooterButtonProps;
15
25
  /**
16
26
  * Label for secondary button
17
27
  */
@@ -21,3 +31,4 @@ export type ModalDialogFooterProps = {
21
31
  */
22
32
  secondaryOnClick?: () => void;
23
33
  } & HTMLAttributes<HTMLElement>;
34
+ export {};
@@ -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();