@westpac/ui 1.1.1 → 1.2.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 (30) hide show
  1. package/.agents/skills/creating-gel-component/SKILL.md +13 -9
  2. package/.agents/skills/reviewing-gel-component/SKILL.md +19 -9
  3. package/.agents/skills/writing-gel-tests/SKILL.md +10 -6
  4. package/CHANGELOG.md +19 -0
  5. package/dist/component-type.json +1 -1
  6. package/dist/components/autocomplete/autocomplete.component.js +2 -2
  7. package/dist/components/multi-select/components/multi-select-dropdown/multi-select-dropdown.component.d.ts +1 -1
  8. package/dist/components/multi-select/components/multi-select-dropdown/multi-select-dropdown.component.js +2 -2
  9. package/dist/components/multi-select/components/multi-select-dropdown/multi-select-dropdown.types.d.ts +1 -0
  10. package/dist/components/multi-select/components/multi-select-list-box/multi-select-list-box.component.js +2 -2
  11. package/dist/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.component.d.ts +1 -1
  12. package/dist/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.component.js +3 -2
  13. package/dist/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.styles.d.ts +42 -39
  14. package/dist/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.styles.js +15 -14
  15. package/dist/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.types.d.ts +1 -0
  16. package/dist/components/multi-select/components/multi-select-popover/multi-select-popover.component.js +19 -6
  17. package/dist/components/multi-select/multi-select.component.d.ts +1 -1
  18. package/dist/components/multi-select/multi-select.component.js +19 -6
  19. package/dist/components/multi-select/multi-select.types.d.ts +22 -1
  20. package/package.json +4 -4
  21. package/src/components/autocomplete/autocomplete.component.tsx +2 -2
  22. package/src/components/multi-select/components/multi-select-dropdown/multi-select-dropdown.component.tsx +4 -1
  23. package/src/components/multi-select/components/multi-select-dropdown/multi-select-dropdown.types.ts +1 -0
  24. package/src/components/multi-select/components/multi-select-list-box/multi-select-list-box.component.tsx +2 -2
  25. package/src/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.component.tsx +2 -0
  26. package/src/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.styles.ts +14 -14
  27. package/src/components/multi-select/components/multi-select-list-box-trigger/multi-select-list-box-trigger.types.ts +1 -0
  28. package/src/components/multi-select/components/multi-select-popover/multi-select-popover.component.tsx +32 -5
  29. package/src/components/multi-select/multi-select.component.tsx +18 -3
  30. package/src/components/multi-select/multi-select.types.ts +23 -1
@@ -71,12 +71,12 @@ function Autocomplete({ size = 'medium', invalid = false, isDisabled, footer, po
71
71
  const { buttonProps } = useButton(clearButtonProps, clearButtonRef);
72
72
  const outerRef = React.useRef(null);
73
73
  const isNoOptionPopOverOpen = useMemo(()=>{
74
- return !!(noOptionsMessage && (!state.isOpen && state.isFocused && searchProps.value.length > 0 && !state.selectedItem || state.collection.size === 0 && searchProps.value.length > 0));
74
+ return !!(noOptionsMessage && (!state.isOpen && state.isFocused && searchProps.value.length > 0 && state.selectedItems.length === 0 || state.collection.size === 0 && searchProps.value.length > 0));
75
75
  }, [
76
76
  noOptionsMessage,
77
77
  state.isOpen,
78
78
  state.isFocused,
79
- state.selectedItem,
79
+ state.selectedItems,
80
80
  state.collection.size,
81
81
  searchProps.value.length
82
82
  ]);
@@ -1,2 +1,2 @@
1
1
  import { MultiSelectDropdownProps } from './multi-select-dropdown.types.js';
2
- export declare function MultiSelectDropdown<T extends object = object>({ setFilterText, ...props }: MultiSelectDropdownProps<T>): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MultiSelectDropdown<T extends object = object>({ setFilterText, hideFilter, ...props }: MultiSelectDropdownProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -4,10 +4,10 @@ import { MultiSelectListBox } from '../../components/multi-select-list-box/multi
4
4
  import { MultiSelectContext } from '../../multi-select.component.js';
5
5
  import { MultiSelectPopover } from '../multi-select-popover/multi-select-popover.component.js';
6
6
  import { MultiSelectSearchbar } from '../multi-select-searchbar/multi-select-searchbar.component.js';
7
- export function MultiSelectDropdown({ setFilterText, ...props }) {
7
+ export function MultiSelectDropdown({ setFilterText, hideFilter, ...props }) {
8
8
  const { filterText, listBoxRef } = useContext(MultiSelectContext);
9
9
  const closeBtnRef = useRef(null);
10
- return React.createElement(MultiSelectPopover, null, React.createElement(MultiSelectSearchbar, {
10
+ return React.createElement(MultiSelectPopover, null, !hideFilter && React.createElement(MultiSelectSearchbar, {
11
11
  filterText: filterText,
12
12
  setFilterText: setFilterText,
13
13
  closeBtnRef: closeBtnRef
@@ -1,5 +1,6 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
2
  import { AriaListBoxOptions } from 'react-aria';
3
3
  export type MultiSelectDropdownProps<T> = {
4
+ hideFilter?: boolean;
4
5
  setFilterText: Dispatch<SetStateAction<string>>;
5
6
  } & AriaListBoxOptions<T>;
@@ -7,7 +7,7 @@ import { MultiSelectOption } from './components/multi-select-option/multi-select
7
7
  import { MultiSelectSelectAllOption } from './components/multi-select-select-all-option/multi-select-select-all-option.component.js';
8
8
  import { styles as listBoxStyles } from './multi-select-list-box.styles.js';
9
9
  export function MultiSelectListBox({ listBoxRef, ...props }) {
10
- const { listState } = useContext(MultiSelectContext);
10
+ const { listState, hideSelectAll } = useContext(MultiSelectContext);
11
11
  const selectionMode = listState.selectionManager.selectionMode;
12
12
  const { listBoxProps } = useListBox({
13
13
  selectionMode,
@@ -19,7 +19,7 @@ export function MultiSelectListBox({ listBoxRef, ...props }) {
19
19
  const styles = listBoxStyles();
20
20
  return React.createElement("div", {
21
21
  className: styles.container()
22
- }, selectionMode === 'multiple' && stateCollection.length > 0 && React.createElement(MultiSelectSelectAllOption, null), React.createElement("ul", {
22
+ }, selectionMode === 'multiple' && stateCollection.length > 0 && !hideSelectAll && React.createElement(MultiSelectSelectAllOption, null), React.createElement("ul", {
23
23
  ...listBoxProps,
24
24
  ref: listBoxRef,
25
25
  className: styles.ul()
@@ -1,2 +1,2 @@
1
1
  import { MultiSelectListBoxTriggerProps } from './multi-select-list-box-trigger.types.js';
2
- export declare function MultiSelectListBoxTrigger<T>({ placeholder, showSingleSectionTitle, selectedKeys, triggerProps, id, }: MultiSelectListBoxTriggerProps<T>): import("react/jsx-runtime").JSX.Element;
2
+ export declare function MultiSelectListBoxTrigger<T>({ placeholder, showSingleSectionTitle, selectedKeys, triggerProps, id, width, }: MultiSelectListBoxTriggerProps<T>): import("react/jsx-runtime").JSX.Element;
@@ -7,7 +7,7 @@ import { DropDownIcon, ClearIcon } from '../../../icon/index.js';
7
7
  import { Tooltip } from '../../../tooltip/tooltip.component.js';
8
8
  import { MultiSelectContext } from '../../multi-select.component.js';
9
9
  import { styles as triggerStyles } from './multi-select-list-box-trigger.styles.js';
10
- export function MultiSelectListBoxTrigger({ placeholder, showSingleSectionTitle, selectedKeys, triggerProps, id }) {
10
+ export function MultiSelectListBoxTrigger({ placeholder, showSingleSectionTitle, selectedKeys, triggerProps, id, width }) {
11
11
  const { size, overlayState, listState, buttonRef, inputRef } = useContext(MultiSelectContext);
12
12
  const selectionMode = listState.selectionManager.selectionMode;
13
13
  const breakpoint = useBreakpoint();
@@ -18,7 +18,8 @@ export function MultiSelectListBoxTrigger({ placeholder, showSingleSectionTitle,
18
18
  const finalButtonProps = mergeProps(focusProps, buttonProps);
19
19
  const styles = triggerStyles({
20
20
  size: resolveResponsiveVariant(size, breakpoint),
21
- isFocusVisible
21
+ isFocusVisible,
22
+ width: resolveResponsiveVariant(width, breakpoint)
22
23
  });
23
24
  const getSectionTitle = useCallback((key)=>{
24
25
  const parentKey = key !== null && key !== void 0 ? key : '';
@@ -36,43 +36,44 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
36
36
  };
37
37
  width: {
38
38
  full: {
39
- control: string;
39
+ selectionSpan: string;
40
+ buttonContainer: string;
40
41
  };
41
42
  1: {
42
- control: string;
43
+ selectionSpan: string;
43
44
  };
44
45
  2: {
45
- control: string;
46
+ selectionSpan: string;
46
47
  };
47
48
  3: {
48
- control: string;
49
+ selectionSpan: string;
49
50
  };
50
51
  4: {
51
- control: string;
52
+ selectionSpan: string;
52
53
  };
53
54
  5: {
54
- control: string;
55
+ selectionSpan: string;
55
56
  };
56
57
  6: {
57
- control: string;
58
+ selectionSpan: string;
58
59
  };
59
60
  7: {
60
- control: string;
61
+ selectionSpan: string;
61
62
  };
62
63
  8: {
63
- control: string;
64
+ selectionSpan: string;
64
65
  };
65
66
  9: {
66
- control: string;
67
+ selectionSpan: string;
67
68
  };
68
69
  10: {
69
- control: string;
70
+ selectionSpan: string;
70
71
  };
71
72
  20: {
72
- control: string;
73
+ selectionSpan: string;
73
74
  };
74
75
  30: {
75
- control: string;
76
+ selectionSpan: string;
76
77
  };
77
78
  };
78
79
  }, {
@@ -122,43 +123,44 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
122
123
  };
123
124
  width: {
124
125
  full: {
125
- control: string;
126
+ selectionSpan: string;
127
+ buttonContainer: string;
126
128
  };
127
129
  1: {
128
- control: string;
130
+ selectionSpan: string;
129
131
  };
130
132
  2: {
131
- control: string;
133
+ selectionSpan: string;
132
134
  };
133
135
  3: {
134
- control: string;
136
+ selectionSpan: string;
135
137
  };
136
138
  4: {
137
- control: string;
139
+ selectionSpan: string;
138
140
  };
139
141
  5: {
140
- control: string;
142
+ selectionSpan: string;
141
143
  };
142
144
  6: {
143
- control: string;
145
+ selectionSpan: string;
144
146
  };
145
147
  7: {
146
- control: string;
148
+ selectionSpan: string;
147
149
  };
148
150
  8: {
149
- control: string;
151
+ selectionSpan: string;
150
152
  };
151
153
  9: {
152
- control: string;
154
+ selectionSpan: string;
153
155
  };
154
156
  10: {
155
- control: string;
157
+ selectionSpan: string;
156
158
  };
157
159
  20: {
158
- control: string;
160
+ selectionSpan: string;
159
161
  };
160
162
  30: {
161
- control: string;
163
+ selectionSpan: string;
162
164
  };
163
165
  };
164
166
  }, {
@@ -208,43 +210,44 @@ export declare const styles: import("tailwind-variants").TVReturnType<{
208
210
  };
209
211
  width: {
210
212
  full: {
211
- control: string;
213
+ selectionSpan: string;
214
+ buttonContainer: string;
212
215
  };
213
216
  1: {
214
- control: string;
217
+ selectionSpan: string;
215
218
  };
216
219
  2: {
217
- control: string;
220
+ selectionSpan: string;
218
221
  };
219
222
  3: {
220
- control: string;
223
+ selectionSpan: string;
221
224
  };
222
225
  4: {
223
- control: string;
226
+ selectionSpan: string;
224
227
  };
225
228
  5: {
226
- control: string;
229
+ selectionSpan: string;
227
230
  };
228
231
  6: {
229
- control: string;
232
+ selectionSpan: string;
230
233
  };
231
234
  7: {
232
- control: string;
235
+ selectionSpan: string;
233
236
  };
234
237
  8: {
235
- control: string;
238
+ selectionSpan: string;
236
239
  };
237
240
  9: {
238
- control: string;
241
+ selectionSpan: string;
239
242
  };
240
243
  10: {
241
- control: string;
244
+ selectionSpan: string;
242
245
  };
243
246
  20: {
244
- control: string;
247
+ selectionSpan: string;
245
248
  };
246
249
  30: {
247
- control: string;
250
+ selectionSpan: string;
248
251
  };
249
252
  };
250
253
  }, {
@@ -1,7 +1,7 @@
1
1
  import { tv } from 'tailwind-variants';
2
2
  export const styles = tv({
3
3
  slots: {
4
- buttonContainer: 'relative w-full',
4
+ buttonContainer: 'relative w-fit',
5
5
  control: 'form-control relative box-border inline-flex w-full flex-row overflow-hidden',
6
6
  selection: 'flex flex-1 items-center overflow-hidden pr-4.5 text-left whitespace-nowrap',
7
7
  selectionSpan: 'w-full overflow-hidden text-ellipsis',
@@ -48,43 +48,44 @@ export const styles = tv({
48
48
  },
49
49
  width: {
50
50
  full: {
51
- control: 'w-full'
51
+ selectionSpan: 'w-full',
52
+ buttonContainer: 'w-full'
52
53
  },
53
54
  1: {
54
- control: 'box-content w-[1.81ex]'
55
+ selectionSpan: 'w-[1.81ex]'
55
56
  },
56
57
  2: {
57
- control: 'box-content w-[3.62ex]'
58
+ selectionSpan: 'w-[3.62ex]'
58
59
  },
59
60
  3: {
60
- control: 'box-content w-[5.43ex]'
61
+ selectionSpan: 'w-[5.43ex]'
61
62
  },
62
63
  4: {
63
- control: 'box-content w-[7.24ex]'
64
+ selectionSpan: 'w-[7.24ex]'
64
65
  },
65
66
  5: {
66
- control: 'box-content w-[9.05ex]'
67
+ selectionSpan: 'w-[9.05ex]'
67
68
  },
68
69
  6: {
69
- control: 'box-content w-[10.86ex]'
70
+ selectionSpan: 'w-[10.86ex]'
70
71
  },
71
72
  7: {
72
- control: 'box-content w-[12.67ex]'
73
+ selectionSpan: 'w-[12.67ex]'
73
74
  },
74
75
  8: {
75
- control: 'box-content w-[14.48ex]'
76
+ selectionSpan: 'w-[14.48ex]'
76
77
  },
77
78
  9: {
78
- control: 'box-content w-[16.29ex]'
79
+ selectionSpan: 'w-[16.29ex]'
79
80
  },
80
81
  10: {
81
- control: 'box-content w-[18.1ex]'
82
+ selectionSpan: 'w-[18.1ex]'
82
83
  },
83
84
  20: {
84
- control: 'box-content w-[36.2ex]'
85
+ selectionSpan: 'w-[36.2ex]'
85
86
  },
86
87
  30: {
87
- control: 'box-content w-[54.3ex]'
88
+ selectionSpan: 'w-[54.3ex]'
88
89
  }
89
90
  }
90
91
  }
@@ -12,5 +12,6 @@ export type MultiSelectListBoxTriggerProps<T> = {
12
12
  selectedKeys?: ListProps<T>['selectedKeys'];
13
13
  showSingleSectionTitle?: MultiSelectProps<T>['showSingleSectionTitle'];
14
14
  triggerProps: AriaButtonProps<'button'>;
15
+ width?: ResponsiveVariants<Variants['width']>;
15
16
  };
16
17
  export {};
@@ -1,14 +1,22 @@
1
1
  'use client';
2
- import React, { useContext } from 'react';
2
+ import React, { useContext, useLayoutEffect, useMemo } from 'react';
3
3
  import { DismissButton, mergeProps, Overlay, usePopover } from 'react-aria';
4
4
  import { MultiSelectContext } from '../../multi-select.component.js';
5
5
  import { styles as popoverStyles } from './multi-select-popover.styles.js';
6
6
  export function MultiSelectPopover({ children, className, ...props }) {
7
- var _buttonRef_current;
7
+ var _buttonRef_current, _popoverProps_style;
8
8
  const { overlayState, overlayProps, popoverRef, buttonRef, placement, portalContainer } = useContext(MultiSelectContext);
9
+ const [isPopoverSmaller, setIsPopoverSmaller] = React.useState(false);
10
+ useLayoutEffect(()=>{
11
+ if (buttonRef.current && popoverRef.current) {
12
+ const buttonWidth = buttonRef.current.getBoundingClientRect().width;
13
+ const popoverWidth = popoverRef.current.getBoundingClientRect().width;
14
+ setIsPopoverSmaller(popoverWidth < buttonWidth);
15
+ }
16
+ }, []);
9
17
  const { popoverProps } = usePopover({
10
18
  ...props,
11
- placement,
19
+ placement: placement,
12
20
  popoverRef,
13
21
  triggerRef: buttonRef,
14
22
  isNonModal: true,
@@ -16,11 +24,15 @@ export function MultiSelectPopover({ children, className, ...props }) {
16
24
  shouldCloseOnInteractOutside: ()=>false,
17
25
  offset: 6
18
26
  }, overlayState);
19
- const width = (_buttonRef_current = buttonRef.current) === null || _buttonRef_current === void 0 ? void 0 : _buttonRef_current.getBoundingClientRect().width;
27
+ const brandContainer = useMemo(()=>{
28
+ if (typeof window !== 'undefined') {
29
+ return document.querySelector('[data-theme]') || document.querySelector('[class^="theme-"], [class*=" theme-"]') || document.body;
30
+ }
31
+ }, []);
20
32
  const styles = popoverStyles();
21
33
  return React.createElement(Overlay, {
22
34
  disableFocusManagement: true,
23
- portalContainer: portalContainer
35
+ portalContainer: portalContainer || brandContainer
24
36
  }, React.createElement("div", {
25
37
  ...mergeProps(popoverProps, overlayProps),
26
38
  ref: popoverRef,
@@ -29,7 +41,8 @@ export function MultiSelectPopover({ children, className, ...props }) {
29
41
  }),
30
42
  style: {
31
43
  ...popoverProps.style,
32
- width: width ? `${width}px` : undefined
44
+ width: isPopoverSmaller ? (_buttonRef_current = buttonRef.current) === null || _buttonRef_current === void 0 ? void 0 : _buttonRef_current.getBoundingClientRect().width : undefined,
45
+ maxWidth: brandContainer ? brandContainer.getBoundingClientRect().width - (parseInt((_popoverProps_style = popoverProps.style) === null || _popoverProps_style === void 0 ? void 0 : _popoverProps_style.left) || 0) : undefined
33
46
  },
34
47
  onBlur: (e)=>{
35
48
  const related = e.relatedTarget;
@@ -1,7 +1,7 @@
1
1
  import React 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, ...props }: MultiSelectProps<T>): import("react/jsx-runtime").JSX.Element;
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
5
  export declare const MultiSelect: React.MemoExoticComponent<typeof BaseMultiSelect>;
6
6
  export declare const MultiSelectItem: (props: MultiSelectItemProps) => JSX.Element;
7
7
  export { Section as MultiSelectSection } from 'react-stately';
@@ -25,9 +25,10 @@ export const MultiSelectContext = createContext({
25
25
  current: null
26
26
  },
27
27
  filterText: '',
28
- overlayProps: {}
28
+ overlayProps: {},
29
+ hideSelectAll: false
29
30
  });
30
- export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode = 'multiple', selectedKeys, onSelectionChange, placeholder = 'Select', showSingleSectionTitle = false, placement, portalContainer, id, ...props }) {
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 }) {
31
32
  const [filterText, setFilterText] = useState('');
32
33
  const filter = useFilter({
33
34
  sensitivity: 'base'
@@ -48,8 +49,17 @@ export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode =
48
49
  onOpenChange: (isOpen)=>{
49
50
  if (isOpen) {
50
51
  requestAnimationFrame(()=>{
51
- var _inputRef_current;
52
- (_inputRef_current = inputRef.current) === null || _inputRef_current === void 0 ? void 0 : _inputRef_current.focus();
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
63
  });
54
64
  }
55
65
  if (!isOpen) {
@@ -75,7 +85,8 @@ export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode =
75
85
  listBoxRef,
76
86
  inputRef,
77
87
  overlayProps,
78
- portalContainer
88
+ portalContainer,
89
+ hideSelectAll
79
90
  }
80
91
  }, React.createElement("div", {
81
92
  className: styles.root()
@@ -84,9 +95,11 @@ export function BaseMultiSelect({ size = 'medium', listBoxProps, selectionMode =
84
95
  selectedKeys: selectedKeys,
85
96
  showSingleSectionTitle: showSingleSectionTitle,
86
97
  triggerProps: triggerProps,
87
- id: id
98
+ id: id,
99
+ width: width
88
100
  }), overlayState.isOpen && React.createElement(MultiSelectDropdown, {
89
101
  setFilterText: setFilterText,
102
+ hideFilter: hideFilter,
90
103
  ...listBoxProps
91
104
  })));
92
105
  }
@@ -2,7 +2,11 @@ import { DOMProps } from '@react-types/shared';
2
2
  import { Key, ReactNode, RefObject } from 'react';
3
3
  import { AriaListBoxOptions, AriaPopoverProps } from 'react-aria';
4
4
  import { ItemProps, ListProps, ListState, OverlayTriggerState } from 'react-stately';
5
+ import { VariantProps } from 'tailwind-variants';
6
+ import { ResponsiveVariants } from '../../types/responsive-variants.types.js';
7
+ import { styles as triggerStyles } from './components/multi-select-list-box-trigger/multi-select-list-box-trigger.styles.js';
5
8
  import { MultiSelectSize } from './components/multi-select-list-box-trigger/multi-select-list-box-trigger.types.js';
9
+ type Variants = VariantProps<typeof triggerStyles>;
6
10
  export type MultiSelectContextProps<T extends object = object> = {
7
11
  size?: MultiSelectSize;
8
12
  overlayState: OverlayTriggerState;
@@ -16,6 +20,7 @@ export type MultiSelectContextProps<T extends object = object> = {
16
20
  overlayProps: DOMProps;
17
21
  placement?: AriaPopoverProps['placement'];
18
22
  portalContainer?: Element;
23
+ hideSelectAll?: boolean;
19
24
  };
20
25
  export type MultiSelectItemProps<T extends object = object> = {
21
26
  description?: string;
@@ -27,6 +32,16 @@ export type MultiSelectValue = {
27
32
  description?: string;
28
33
  };
29
34
  export type MultiSelectProps<T> = {
35
+ /**
36
+ * Whether to hide the filter input in the dropdown
37
+ * @default false
38
+ */
39
+ hideFilter?: boolean;
40
+ /**
41
+ * Whether to hide the "Select All" option in the dropdown for multiple selection multi-selects
42
+ * @default false
43
+ */
44
+ hideSelectAll?: boolean;
30
45
  /**
31
46
  * Props for the list box within the multi-select
32
47
  */
@@ -41,7 +56,7 @@ export type MultiSelectProps<T> = {
41
56
  placeholder?: string;
42
57
  /**
43
58
  * Manual placement of the dropdown, will flip automatically if there is not enough space
44
- * @default bottom
59
+ * @default 'bottom left'
45
60
  */
46
61
  placement?: AriaPopoverProps['placement'];
47
62
  /**
@@ -58,4 +73,10 @@ export type MultiSelectProps<T> = {
58
73
  * @default medium
59
74
  */
60
75
  size?: MultiSelectSize;
76
+ /**
77
+ * Width of the multi-select, can be a fixed width or full width
78
+ * @default full
79
+ */
80
+ width?: ResponsiveVariants<Variants['width']>;
61
81
  } & ListProps<T>;
82
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@westpac/ui",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -254,9 +254,9 @@
254
254
  "vite": "^7.1.12",
255
255
  "vitest": "^3.2.4",
256
256
  "@westpac/eslint-config": "~1.1.0",
257
- "@westpac/style-config": "~1.0.1",
258
- "@westpac/ts-config": "~0.0.0",
259
- "@westpac/test-config": "~0.0.0"
257
+ "@westpac/style-config": "~1.0.2",
258
+ "@westpac/test-config": "~0.0.0",
259
+ "@westpac/ts-config": "~0.0.0"
260
260
  },
261
261
  "dependencies": {
262
262
  "@internationalized/date": "~3.10.0",
@@ -99,14 +99,14 @@ function Autocomplete<T extends object>(
99
99
  const isNoOptionPopOverOpen = useMemo(() => {
100
100
  return !!(
101
101
  noOptionsMessage &&
102
- ((!state.isOpen && state.isFocused && searchProps.value.length > 0 && !state.selectedItem) ||
102
+ ((!state.isOpen && state.isFocused && searchProps.value.length > 0 && state.selectedItems.length === 0) ||
103
103
  (state.collection.size === 0 && searchProps.value.length > 0))
104
104
  );
105
105
  }, [
106
106
  noOptionsMessage,
107
107
  state.isOpen,
108
108
  state.isFocused,
109
- state.selectedItem,
109
+ state.selectedItems,
110
110
  state.collection.size,
111
111
  searchProps.value.length,
112
112
  ]);
@@ -12,6 +12,7 @@ import { MultiSelectDropdownProps } from './multi-select-dropdown.types.js';
12
12
 
13
13
  export function MultiSelectDropdown<T extends object = object>({
14
14
  setFilterText,
15
+ hideFilter,
15
16
  ...props
16
17
  }: MultiSelectDropdownProps<T>) {
17
18
  const { filterText, listBoxRef } = useContext(MultiSelectContext);
@@ -19,7 +20,9 @@ export function MultiSelectDropdown<T extends object = object>({
19
20
 
20
21
  return (
21
22
  <MultiSelectPopover>
22
- <MultiSelectSearchbar filterText={filterText} setFilterText={setFilterText} closeBtnRef={closeBtnRef} />
23
+ {!hideFilter && (
24
+ <MultiSelectSearchbar filterText={filterText} setFilterText={setFilterText} closeBtnRef={closeBtnRef} />
25
+ )}
23
26
  <MultiSelectListBox {...props} aria-label="multiselect list" escapeKeyBehavior="none" listBoxRef={listBoxRef} />
24
27
  </MultiSelectPopover>
25
28
  );
@@ -2,5 +2,6 @@ import { Dispatch, SetStateAction } from 'react';
2
2
  import { AriaListBoxOptions } from 'react-aria';
3
3
 
4
4
  export type MultiSelectDropdownProps<T> = {
5
+ hideFilter?: boolean;
5
6
  setFilterText: Dispatch<SetStateAction<string>>;
6
7
  } & AriaListBoxOptions<T>;
@@ -13,7 +13,7 @@ import { styles as listBoxStyles } from './multi-select-list-box.styles.js';
13
13
  import type { MultiSelectListBoxProps } from './multi-select-list-box.types.js';
14
14
 
15
15
  export function MultiSelectListBox<T extends object = object>({ listBoxRef, ...props }: MultiSelectListBoxProps<T>) {
16
- const { listState } = useContext(MultiSelectContext);
16
+ const { listState, hideSelectAll } = useContext(MultiSelectContext);
17
17
  const selectionMode = listState.selectionManager.selectionMode;
18
18
  const { listBoxProps } = useListBox({ selectionMode, ...props }, listState, listBoxRef);
19
19
 
@@ -23,7 +23,7 @@ export function MultiSelectListBox<T extends object = object>({ listBoxRef, ...p
23
23
 
24
24
  return (
25
25
  <div className={styles.container()}>
26
- {selectionMode === 'multiple' && stateCollection.length > 0 && <MultiSelectSelectAllOption />}
26
+ {selectionMode === 'multiple' && stateCollection.length > 0 && !hideSelectAll && <MultiSelectSelectAllOption />}
27
27
  <ul {...listBoxProps} ref={listBoxRef} className={styles.ul()}>
28
28
  {stateCollection.length > 0 ? (
29
29
  stateCollection.map(item =>
@@ -17,6 +17,7 @@ export function MultiSelectListBoxTrigger<T>({
17
17
  selectedKeys,
18
18
  triggerProps,
19
19
  id,
20
+ width,
20
21
  }: MultiSelectListBoxTriggerProps<T>) {
21
22
  const { size, overlayState, listState, buttonRef, inputRef } = useContext(MultiSelectContext);
22
23
  const selectionMode = listState.selectionManager.selectionMode;
@@ -30,6 +31,7 @@ export function MultiSelectListBoxTrigger<T>({
30
31
  const styles = triggerStyles({
31
32
  size: resolveResponsiveVariant(size, breakpoint),
32
33
  isFocusVisible,
34
+ width: resolveResponsiveVariant(width, breakpoint),
33
35
  });
34
36
 
35
37
  const getSectionTitle = useCallback(