@wavv/ui 2.4.7 → 2.4.8-alpha.2

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.
@@ -65,10 +65,12 @@ const CalendarHeader = ({ date, setDate })=>{
65
65
  const month = mth?.toString() || '';
66
66
  const year = yr?.toString() || '';
67
67
  const handleMonth = (monthId)=>{
68
- setDate(new CalendarDate(+year, +monthId, day || 1));
68
+ const id = Array.isArray(monthId) ? monthId[0] : monthId;
69
+ setDate(new CalendarDate(+year, +id, day || 1));
69
70
  };
70
71
  const handleYear = (yearId)=>{
71
- setDate(new CalendarDate(+yearId, +month, day || 1));
72
+ const id = Array.isArray(yearId) ? yearId[0] : yearId;
73
+ setDate(new CalendarDate(+id, +month, day || 1));
72
74
  };
73
75
  return /*#__PURE__*/ jsxs(Header, {
74
76
  children: [
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { ComboBoxProps } from './typeDefs/reactAriaTypes';
3
- import type { OpenStateProps, SelectInputProps } from './typeDefs/selectionTypes';
3
+ import type { ComboBoxInputProps, OpenStateProps } from './typeDefs/selectionTypes';
4
4
  type Props = {
5
5
  /** Use when loading options asynchronously with onTextChange */
6
6
  loadingResults?: boolean;
@@ -13,9 +13,11 @@ type Props = {
13
13
  /** Customize the create option label. Receives raw inputText and returns the label to display. */
14
14
  formatCreateOption?: (inputText: string) => ReactNode;
15
15
  ref?: React.Ref<HTMLInputElement>;
16
- } & SelectInputProps & OpenStateProps & ComboBoxProps;
16
+ } & ComboBoxInputProps & OpenStateProps & ComboBoxProps;
17
17
  declare const _default: (({ backgroundColor, menuBackground, children, fontSize, disabled, invalid, required, readOnly, loading, loadingResults, label, options, placeholder, placeholderColor, description, errorMessage, textOnly, value, defaultValue, width, height, maxHeight, iconLeft, leftElement, rightElement, allowRepeatSelection, allowsEmptyCollection, emptyFallback, position, fixedPosition, open, onOpenChange, before, after, onChange, onCreate, formatCreateOption, afterShow, afterHide, onTextChange, ref, ...props }: Props) => import("react/jsx-runtime").JSX.Element) & {
18
- Item: ({ id, value, header, body, leftElement, rightElement, inline, disabled, ...props }: import("..").SelectItem & Omit<import("react-aria-components").ListBoxItemProps<object>, "id" | "value" | "isDisabled">) => import("react/jsx-runtime").JSX.Element;
18
+ Item: ({ id, value, header, body, leftElement, rightElement, inline, disabled, selectionMode, ...props }: import("..").SelectItem & Omit<import("react-aria-components").ListBoxItemProps<object>, "id" | "value" | "isDisabled"> & {
19
+ selectionMode?: import("react-aria-components").SelectionMode;
20
+ }) => import("react/jsx-runtime").JSX.Element;
19
21
  Section: ({ id, title, children }: {
20
22
  id?: string;
21
23
  title?: string;
@@ -26,7 +26,7 @@ const ComboBox_ComboBox = ({ backgroundColor, menuBackground, children, fontSize
26
26
  afterShow,
27
27
  afterHide
28
28
  });
29
- const [internalValue, setInternalValue] = useState(defaultValue || '');
29
+ const [internalValue, setInternalValue] = useState(defaultValue ? String(defaultValue) : '');
30
30
  const [inputText, setInputText] = useState((value || defaultValue || '').toString());
31
31
  const pendingSelectionRef = useRef(null);
32
32
  const isControlled = void 0 !== value;
@@ -1,9 +1,9 @@
1
1
  import { type ButtonProps } from 'react-aria-components';
2
- import type { ListOption, OpenStateProps, SelectInputProps, SelectItem } from './typeDefs/selectionTypes';
2
+ import type { ComboBoxInputProps, ListOption, OpenStateProps, SelectItem } from './typeDefs/selectionTypes';
3
3
  type Props = {
4
4
  /** The options to be displayed in the dropdown */
5
5
  options?: ListOption[];
6
- } & Omit<SelectInputProps, 'options' | 'textOnly'> & OpenStateProps & Omit<ButtonProps, 'ref' | 'isDisabled'>;
6
+ } & Omit<ComboBoxInputProps, 'options' | 'textOnly'> & OpenStateProps & Omit<ButtonProps, 'ref' | 'isDisabled'>;
7
7
  declare const _default: (({ children, before, after, open, label, placeholder, options, width, height, value, defaultValue, loading, hideCaret, color, disabled, readOnly, required, invalid, placeholderColor, fontSize, fontWeight, description, errorMessage, position, backgroundColor, menuBackground, iconLeft, leftElement, rightElement, onChange, onOpenChange, afterShow, afterHide, ...props }: Props) => import("react/jsx-runtime").JSX.Element) & {
8
8
  Item: ({ children, id, value, header, body, leftElement, rightElement, inline, disabled, ...props }: {
9
9
  children?: import("react").ReactNode;
@@ -1,110 +1,152 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { keyframes } from "@emotion/react";
2
3
  import styled from "@emotion/styled";
3
- import { useEffect, useState } from "react";
4
- import { useOnClickOutside } from "../hooks/index.js";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { Dialog, Modal, ModalOverlay } from "react-aria-components";
6
+ import useEventListener from "../hooks/useEventListener.js";
5
7
  import Icon from "./Icon/index.js";
6
8
  const ImageViewer = ({ visible, close, images, startIndex, alt, maxWidth, maxHeight, opacity, ...rest })=>{
7
9
  const [currentIndex, setCurrentIndex] = useState(startIndex);
8
- const exclusions = [
9
- '#viewer-prev',
10
- '#viewer-next',
11
- '#viewer-prev *',
12
- '#viewer-next *'
13
- ];
14
- const imageRef = useOnClickOutside(close, visible, exclusions);
10
+ const handleOpenChange = (open)=>{
11
+ if (!open) close();
12
+ };
15
13
  useEffect(()=>{
16
- setCurrentIndex(startIndex);
14
+ if (visible) setCurrentIndex(startIndex);
17
15
  }, [
16
+ visible,
18
17
  startIndex
19
18
  ]);
20
- const handlePrev = ()=>currentIndex > 0 ? setCurrentIndex(currentIndex - 1) : setCurrentIndex(images.length - 1);
21
- const handleNext = ()=>currentIndex < images.length - 1 ? setCurrentIndex(currentIndex + 1) : setCurrentIndex(0);
22
- const handleKeyPress = (event)=>{
23
- const { key } = event;
24
- switch(key){
19
+ const handlePrev = ()=>setCurrentIndex((prev)=>prev > 0 ? prev - 1 : images.length - 1);
20
+ const handleNext = ()=>setCurrentIndex((prev)=>prev < images.length - 1 ? prev + 1 : 0);
21
+ const handleKeyDown = useCallback((e)=>{
22
+ switch(e.key){
23
+ case 'Escape':
24
+ e.preventDefault();
25
+ close();
26
+ break;
25
27
  case 'ArrowLeft':
26
28
  case 'ArrowDown':
27
- event.preventDefault();
28
- handlePrev();
29
+ e.preventDefault();
30
+ setCurrentIndex((prev)=>prev > 0 ? prev - 1 : images.length - 1);
29
31
  break;
30
32
  case 'ArrowRight':
31
33
  case 'ArrowUp':
32
- event.preventDefault();
33
- handleNext();
34
- break;
35
- case 'Escape':
36
- event.preventDefault();
37
- close();
34
+ e.preventDefault();
35
+ setCurrentIndex((prev)=>prev < images.length - 1 ? prev + 1 : 0);
38
36
  break;
39
37
  default:
40
38
  break;
41
39
  }
42
- };
43
- useEffect(()=>{
44
- const ssr = "u" < typeof window;
45
- const cleanup = ssr ? ()=>null : ()=>window.removeEventListener('keydown', handleKeyPress);
46
- if (visible && !ssr) window.addEventListener('keydown', handleKeyPress);
47
- return cleanup;
48
40
  }, [
49
- visible,
50
- currentIndex
41
+ close,
42
+ images.length
43
+ ]);
44
+ useEventListener("u" > typeof window ? window : {
45
+ current: null
46
+ }, 'keydown', handleKeyDown, visible, [
47
+ handleKeyDown
51
48
  ]);
52
- return visible ? /*#__PURE__*/ jsxs(Viewer, {
49
+ if (0 === images.length) return null;
50
+ return /*#__PURE__*/ jsx(Overlay, {
51
+ isOpen: visible,
52
+ onOpenChange: handleOpenChange,
53
+ isDismissable: true,
53
54
  opacity: opacity,
54
55
  prevNext: images.length > 1,
55
56
  ...rest,
56
- children: [
57
- /*#__PURE__*/ jsx(Close, {
58
- onClick: close,
59
- children: /*#__PURE__*/ jsx(Icon, {
60
- name: "close",
61
- color: "white"
62
- })
63
- }),
64
- images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
65
- id: "viewer-prev",
66
- onClick: handlePrev,
67
- children: /*#__PURE__*/ jsx(Icon, {
68
- name: "chevron-left",
69
- size: 35,
70
- color: "white"
71
- })
72
- }),
73
- /*#__PURE__*/ jsx(Media, {
74
- ref: imageRef,
75
- src: images[currentIndex],
76
- alt: alt,
77
- maxWidth: maxWidth,
78
- maxHeight: maxHeight
79
- }),
80
- images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
81
- next: true,
82
- id: "viewer-next",
83
- onClick: handleNext,
84
- children: /*#__PURE__*/ jsx(Icon, {
85
- name: "chevron-right",
86
- size: 35,
87
- color: "white"
57
+ children: /*#__PURE__*/ jsx(StyledModal, {
58
+ children: /*#__PURE__*/ jsx(StyledDialog, {
59
+ "aria-label": alt || 'Image viewer',
60
+ children: /*#__PURE__*/ jsxs(ViewerContent, {
61
+ children: [
62
+ /*#__PURE__*/ jsx(Close, {
63
+ onClick: close,
64
+ children: /*#__PURE__*/ jsx(Icon, {
65
+ name: "close",
66
+ color: "white"
67
+ })
68
+ }),
69
+ images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
70
+ id: "viewer-prev",
71
+ onClick: handlePrev,
72
+ children: /*#__PURE__*/ jsx(Icon, {
73
+ name: "chevron-left",
74
+ size: 35,
75
+ color: "white"
76
+ })
77
+ }),
78
+ /*#__PURE__*/ jsx(Media, {
79
+ src: images[currentIndex],
80
+ alt: alt,
81
+ maxWidth: maxWidth,
82
+ maxHeight: maxHeight
83
+ }),
84
+ images.length > 1 && /*#__PURE__*/ jsx(PrevNext, {
85
+ $next: true,
86
+ id: "viewer-next",
87
+ onClick: handleNext,
88
+ children: /*#__PURE__*/ jsx(Icon, {
89
+ name: "chevron-right",
90
+ size: 35,
91
+ color: "white"
92
+ })
93
+ })
94
+ ]
88
95
  })
89
96
  })
90
- ]
91
- }) : null;
97
+ })
98
+ });
92
99
  };
93
- const Viewer = styled.div(({ prevNext, opacity })=>({
94
- width: '100%',
95
- height: '100%',
96
- backgroundColor: `rgba(0, 0, 0, ${opacity ?? 0.3})`,
100
+ const fadeIn = keyframes({
101
+ from: {
102
+ opacity: 0
103
+ },
104
+ to: {
105
+ opacity: 1
106
+ }
107
+ });
108
+ const fadeOut = keyframes({
109
+ from: {
110
+ opacity: 1
111
+ },
112
+ to: {
113
+ opacity: 0
114
+ }
115
+ });
116
+ const Overlay = styled(ModalOverlay)(({ prevNext, opacity })=>({
97
117
  position: 'fixed',
98
118
  top: 0,
99
119
  left: 0,
120
+ width: '100%',
121
+ height: '100%',
122
+ backgroundColor: `rgba(0, 0, 0, ${opacity ?? 0.3})`,
100
123
  display: 'grid',
101
124
  gridTemplateColumns: prevNext ? 'auto 1fr auto' : '1fr',
102
125
  justifyContent: 'space-between',
103
126
  alignItems: 'center',
104
127
  zIndex: 10000,
105
128
  userSelect: 'none',
106
- borderRadius: 5
129
+ borderRadius: 5,
130
+ '&[data-entering]': {
131
+ animation: `${fadeIn} 200ms ease-out`
132
+ },
133
+ '&[data-exiting]': {
134
+ animation: `${fadeOut} 200ms ease-in forwards`
135
+ }
107
136
  }));
137
+ const StyledModal = styled(Modal)({
138
+ outline: 'none',
139
+ pointerEvents: 'none',
140
+ display: 'contents'
141
+ });
142
+ const StyledDialog = styled(Dialog)({
143
+ outline: 'none',
144
+ pointerEvents: 'none',
145
+ display: 'contents'
146
+ });
147
+ const ViewerContent = styled.div({
148
+ display: 'contents'
149
+ });
108
150
  const Close = styled.div({
109
151
  position: 'absolute',
110
152
  top: 0,
@@ -115,9 +157,10 @@ const Close = styled.div({
115
157
  cursor: 'pointer',
116
158
  width: 50,
117
159
  height: 50,
118
- zIndex: 1
160
+ zIndex: 1,
161
+ pointerEvents: 'auto'
119
162
  });
120
- const PrevNext = styled.div(({ next })=>({
163
+ const PrevNext = styled.div(({ $next })=>({
121
164
  display: 'flex',
122
165
  justifyContent: 'center',
123
166
  alignItems: 'center',
@@ -125,18 +168,20 @@ const PrevNext = styled.div(({ next })=>({
125
168
  width: 50,
126
169
  height: '100%',
127
170
  backgroundColor: 'transparent',
128
- left: next ? void 0 : 0,
129
- right: next ? 0 : void 0,
171
+ left: $next ? void 0 : 0,
172
+ right: $next ? 0 : void 0,
130
173
  zIndex: 0,
174
+ pointerEvents: 'auto',
131
175
  '&:hover': {
132
- background: `linear-gradient(90deg, rgba(0,0,0,${next ? 0 : 0.4}) 0%, rgba(0,0,0,${next ? 0.4 : 0}) 100%)`
176
+ background: `linear-gradient(90deg, rgba(0,0,0,${$next ? 0 : 0.4}) 0%, rgba(0,0,0,${$next ? 0.4 : 0}) 100%)`
133
177
  }
134
178
  }));
135
179
  const Media = styled.img(({ maxWidth, maxHeight })=>({
136
180
  display: 'block',
137
181
  justifySelf: 'center',
138
182
  maxWidth: maxWidth || '100%',
139
- maxHeight: maxHeight || '100%'
183
+ maxHeight: maxHeight || '100%',
184
+ pointerEvents: 'auto'
140
185
  }));
141
186
  const components_ImageViewer = ImageViewer;
142
187
  export { components_ImageViewer as default };
@@ -1,5 +1,7 @@
1
- import { type ListBoxItemProps } from 'react-aria-components';
1
+ import { type ListBoxItemProps, type SelectionMode } from 'react-aria-components';
2
2
  import type { SelectItem } from '../typeDefs/selectionTypes';
3
- type Props = SelectItem & Omit<ListBoxItemProps, 'value' | 'id' | 'isDisabled'>;
4
- declare const ListBoxItem: ({ id, value, header, body, leftElement, rightElement, inline, disabled, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
3
+ type Props = SelectItem & Omit<ListBoxItemProps, 'value' | 'id' | 'isDisabled'> & {
4
+ selectionMode?: SelectionMode;
5
+ };
6
+ declare const ListBoxItem: ({ id, value, header, body, leftElement, rightElement, inline, disabled, selectionMode, ...props }: Props) => import("react/jsx-runtime").JSX.Element;
5
7
  export default ListBoxItem;
@@ -1,30 +1,44 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import styled from "@emotion/styled";
3
3
  import { ListBoxItem } from "react-aria-components";
4
+ import Icon from "../Icon/index.js";
4
5
  import ItemHeaderBody from "../ListHelpers/ItemHeaderBody.js";
5
6
  import ListItemStyles, { preventProps } from "../ListHelpers/ListItemStyles.js";
6
- const ListBoxItem_ListBoxItem = ({ id, value, header, body, leftElement, rightElement, inline, disabled, ...props })=>{
7
+ const ListBoxItem_ListBoxItem = ({ id, value, header, body, leftElement, rightElement, inline, disabled, selectionMode, ...props })=>{
7
8
  const headerText = header || value;
8
- return /*#__PURE__*/ jsxs(Item, {
9
+ return /*#__PURE__*/ jsx(Item, {
9
10
  id: id || value,
10
11
  textValue: value,
11
12
  isDisabled: disabled,
12
13
  ...props,
13
- children: [
14
- leftElement || null,
15
- headerText && body ? /*#__PURE__*/ jsx(ItemHeaderBody, {
16
- header: headerText,
17
- body: body,
18
- inline: inline,
19
- disabled: disabled
20
- }) : value,
21
- rightElement && /*#__PURE__*/ jsx("div", {
22
- style: {
23
- marginLeft: 'auto'
24
- },
25
- children: rightElement
26
- })
27
- ]
14
+ children: ({ isSelected })=>{
15
+ const showCheck = 'multiple' === selectionMode || 'single' === selectionMode;
16
+ const check = showCheck ? /*#__PURE__*/ jsx(Icon, {
17
+ name: "check",
18
+ color: isSelected ? void 0 : 'transparent',
19
+ size: "small",
20
+ marginLeft: -12,
21
+ marginRight: 4
22
+ }) : null;
23
+ return /*#__PURE__*/ jsxs(Fragment, {
24
+ children: [
25
+ check,
26
+ leftElement || null,
27
+ headerText && body ? /*#__PURE__*/ jsx(ItemHeaderBody, {
28
+ header: headerText,
29
+ body: body,
30
+ inline: inline,
31
+ disabled: disabled
32
+ }) : value,
33
+ rightElement && /*#__PURE__*/ jsx("div", {
34
+ style: {
35
+ marginLeft: 'auto'
36
+ },
37
+ children: rightElement
38
+ })
39
+ ]
40
+ });
41
+ }
28
42
  });
29
43
  };
30
44
  const Item = styled(ListBoxItem, preventProps)(ListItemStyles);
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import { type ListBoxProps } from 'react-aria-components';
2
+ import { type ListBoxProps, type SelectionMode } from 'react-aria-components';
3
3
  import type { ListOption, SelectInputProps } from '../typeDefs/selectionTypes';
4
4
  import type { Width } from '../types';
5
5
  type Props = {
@@ -8,6 +8,7 @@ type Props = {
8
8
  autoWidth?: boolean;
9
9
  readOnly?: boolean;
10
10
  createOptionItem?: ReactNode;
11
+ selectionMode?: SelectionMode;
11
12
  } & Width & ListBoxProps<ListOption> & Pick<SelectInputProps, 'before' | 'after' | 'menuBackground'>;
12
- declare const ListOptions: ({ options, children, autoWidth, width, before, after, menuBackground, createOptionItem, ...props }: Props) => ReactNode;
13
+ declare const ListOptions: ({ options, children, autoWidth, width, before, after, menuBackground, createOptionItem, selectionMode, ...props }: Props) => ReactNode;
13
14
  export default ListOptions;
@@ -4,7 +4,7 @@ import { ListBox } from "react-aria-components";
4
4
  import ListSection from "../ListHelpers/ListSection.js";
5
5
  import ListStyles, { preventProps } from "../ListHelpers/ListStyles.js";
6
6
  import ListBoxItem from "./ListBoxItem.js";
7
- const ListOptions = ({ options, children, autoWidth, width, before, after, menuBackground, createOptionItem, ...props })=>/*#__PURE__*/ jsxs(ListContainer, {
7
+ const ListOptions = ({ options, children, autoWidth, width, before, after, menuBackground, createOptionItem, selectionMode, ...props })=>/*#__PURE__*/ jsxs(ListContainer, {
8
8
  autoWidth: autoWidth,
9
9
  width: autoWidth ? void 0 : width,
10
10
  background: menuBackground,
@@ -15,6 +15,7 @@ const ListOptions = ({ options, children, autoWidth, width, before, after, menuB
15
15
  style: {
16
16
  outline: 'none'
17
17
  },
18
+ selectionMode: selectionMode,
18
19
  ...props,
19
20
  children: [
20
21
  createOptionItem,
@@ -25,13 +26,15 @@ const ListOptions = ({ options, children, autoWidth, width, before, after, menuB
25
26
  id: section.id,
26
27
  title: section.title,
27
28
  children: section.options.map((item)=>/*#__PURE__*/ jsx(ListBoxItem, {
28
- ...item
29
+ ...item,
30
+ selectionMode: selectionMode
29
31
  }, item.id || item.value))
30
32
  }, section.id);
31
33
  }
32
34
  const item = option;
33
35
  return /*#__PURE__*/ jsx(ListBoxItem, {
34
- ...item
36
+ ...item,
37
+ selectionMode: selectionMode
35
38
  }, item.id || item.value);
36
39
  }),
37
40
  children
@@ -1,10 +1,13 @@
1
+ import { type SelectionMode } from 'react-aria-components';
1
2
  import type { SelectProps } from './typeDefs/reactAriaTypes';
2
3
  import type { OpenStateProps, SelectInputProps } from './typeDefs/selectionTypes';
3
4
  type Props = {
4
5
  ref?: React.Ref<HTMLButtonElement>;
5
6
  } & SelectInputProps & OpenStateProps & SelectProps;
6
- declare const _default: (({ backgroundColor, menuBackground, children, fontSize, fontWeight, color, disabled, invalid, required, readOnly, loading, label, options, placeholder, placeholderColor, description, errorMessage, textOnly, value, defaultValue, width, height, maxHeight, allowRepeatSelection, hideCaret, position, fixedPosition, borderRadius, iconLeft, leftElement, rightElement, before, after, open, onOpenChange, onChange, afterShow, afterHide, ref, ...props }: Props) => import("react/jsx-runtime").JSX.Element) & {
7
- Item: ({ id, value, header, body, leftElement, rightElement, inline, disabled, ...props }: import("..").SelectItem & Omit<import("react-aria-components").ListBoxItemProps<object>, "id" | "value" | "isDisabled">) => import("react/jsx-runtime").JSX.Element;
7
+ declare const _default: (({ backgroundColor, menuBackground, children, fontSize, fontWeight, color, disabled, invalid, required, readOnly, loading, label, options, placeholder, placeholderColor, description, errorMessage, textOnly, value, defaultValue, width, height, maxHeight, allowRepeatSelection, hideCaret, position, fixedPosition, borderRadius, iconLeft, leftElement, rightElement, before, after, open, onOpenChange, onChange, afterShow, afterHide, selectionMode, ref, ...props }: Props) => import("react/jsx-runtime").JSX.Element) & {
8
+ Item: ({ id, value, header, body, leftElement, rightElement, inline, disabled, selectionMode, ...props }: import("..").SelectItem & Omit<import("react-aria-components").ListBoxItemProps<object>, "id" | "value" | "isDisabled"> & {
9
+ selectionMode?: SelectionMode;
10
+ }) => import("react/jsx-runtime").JSX.Element;
8
11
  Section: ({ id, title, children }: {
9
12
  id?: string;
10
13
  title?: string;
@@ -15,14 +15,24 @@ import ListRootStyles, { preventProps } from "./ListHelpers/ListRootStyles.js";
15
15
  import ListSection from "./ListHelpers/ListSection.js";
16
16
  import MotionPopover from "./MotionPopover.js";
17
17
  import Spinner from "./Spinner.js";
18
- const Select_Select = ({ backgroundColor, menuBackground, children, fontSize, fontWeight, color, disabled, invalid, required, readOnly, loading, label, options, placeholder = 'Select', placeholderColor, description, errorMessage, textOnly, value, defaultValue, width, height, maxHeight, allowRepeatSelection, hideCaret, position, fixedPosition, borderRadius, iconLeft, leftElement, rightElement, before, after, open, onOpenChange, onChange, afterShow, afterHide, ref, ...props })=>{
18
+ const Select_Select = ({ backgroundColor, menuBackground, children, fontSize, fontWeight, color, disabled, invalid, required, readOnly, loading, label, options, placeholder = 'Select', placeholderColor, description, errorMessage, textOnly, value, defaultValue, width, height, maxHeight, allowRepeatSelection, hideCaret, position, fixedPosition, borderRadius, iconLeft, leftElement, rightElement, before, after, open, onOpenChange, onChange, afterShow, afterHide, selectionMode, ref, ...props })=>{
19
19
  const [isOpen, handleOpenChange] = useControlledOpenState({
20
20
  open,
21
21
  onOpenChange,
22
22
  afterShow,
23
23
  afterHide
24
24
  });
25
- const [internalValue, setInternalValue] = useState(defaultValue || '');
25
+ const actualSelectionMode = selectionMode ?? 'single';
26
+ const isMultiple = 'multiple' === actualSelectionMode;
27
+ const [internalValue, setInternalValue] = useState(()=>{
28
+ if (isMultiple) {
29
+ const defaultValueArray = defaultValue;
30
+ return Array.isArray(defaultValueArray) ? defaultValueArray.map(String) : defaultValueArray ? [
31
+ String(defaultValueArray)
32
+ ] : [];
33
+ }
34
+ return defaultValue ? String(defaultValue) : '';
35
+ });
26
36
  const isControlled = void 0 !== value;
27
37
  const currentValue = isControlled ? value : internalValue;
28
38
  const { padding, paddingTop, paddingBottom, paddingRight, paddingLeft } = props;
@@ -43,11 +53,26 @@ const Select_Select = ({ backgroundColor, menuBackground, children, fontSize, fo
43
53
  };
44
54
  const handleSelect = (val)=>{
45
55
  if (!val) return;
46
- if (!allowRepeatSelection && val === currentValue) return;
47
- if (!isControlled) setInternalValue(val);
48
- if (onChange) onChange(val);
56
+ if (isMultiple) {
57
+ const newValue = Array.isArray(val) ? val.map(String) : [
58
+ String(val)
59
+ ];
60
+ const currentArray = Array.isArray(currentValue) ? currentValue : [];
61
+ if (!allowRepeatSelection && JSON.stringify([
62
+ ...newValue
63
+ ].sort()) === JSON.stringify([
64
+ ...currentArray
65
+ ].sort())) return;
66
+ if (!isControlled) setInternalValue(newValue);
67
+ if (onChange) onChange(newValue);
68
+ } else {
69
+ const stringVal = String(val);
70
+ if (!allowRepeatSelection && stringVal === currentValue) return;
71
+ if (!isControlled) setInternalValue(stringVal);
72
+ if (onChange) onChange(stringVal);
73
+ }
49
74
  };
50
- const hasValue = !!(currentValue || defaultValue);
75
+ const hasValue = isMultiple ? (Array.isArray(currentValue) ? currentValue.length > 0 : false) || (Array.isArray(defaultValue) ? defaultValue.length > 0 : false) : !!(currentValue || defaultValue);
51
76
  const hidePlaceholder = !hasValue && label;
52
77
  const caret = hideCaret ? null : /*#__PURE__*/ jsx(Icon, {
53
78
  name: isOpen ? 'caret-up' : 'caret-down',
@@ -65,7 +90,7 @@ const Select_Select = ({ backgroundColor, menuBackground, children, fontSize, fo
65
90
  defaultValue: defaultValue,
66
91
  textOnly: textOnly,
67
92
  width: width,
68
- selectionMode: "single",
93
+ selectionMode: selectionMode ?? 'single',
69
94
  ...props,
70
95
  children: [
71
96
  /*#__PURE__*/ jsxs(SelectContainer, {
@@ -103,7 +128,14 @@ const Select_Select = ({ backgroundColor, menuBackground, children, fontSize, fo
103
128
  opacity: 0,
104
129
  position: 'absolute'
105
130
  } : {},
106
- children: ({ isPlaceholder, selectedText, defaultChildren })=>isPlaceholder ? defaultChildren : selectedText
131
+ children: ({ isPlaceholder, selectedText, selectedItems, defaultChildren })=>{
132
+ if (isPlaceholder) return defaultChildren;
133
+ if (isMultiple && selectedItems) {
134
+ const count = selectedItems.length;
135
+ return count > 0 ? `${count} items selected` : defaultChildren;
136
+ }
137
+ return selectedText;
138
+ }
107
139
  })
108
140
  }),
109
141
  rightElement,
@@ -129,6 +161,7 @@ const Select_Select = ({ backgroundColor, menuBackground, children, fontSize, fo
129
161
  before: before,
130
162
  after: after,
131
163
  menuBackground: menuBackground,
164
+ selectionMode: selectionMode,
132
165
  children: children
133
166
  })
134
167
  })
@@ -98,7 +98,7 @@ export type ComboBoxProps = {
98
98
  onOpenChange?: Combo['onOpenChange'];
99
99
  onInputChange?: Combo['onInputChange'];
100
100
  } & Omit<Combo, 'children' | 'defaultItems' | 'items' | 'onSelectionChange' | 'selectedKey' | 'defaultSelectedKey' | 'defaultInputValue' | 'isOpen' | 'isDisabled' | 'isInvalid' | 'isRequired'>;
101
- type Select = AriaSelectProps<SelectItem>;
101
+ type Select = AriaSelectProps<SelectItem, 'single' | 'multiple'>;
102
102
  export type SelectProps = {
103
103
  autoComplete?: Select['autoComplete'];
104
104
  name?: Select['name'];
@@ -108,10 +108,11 @@ export type SelectProps = {
108
108
  defaultValue?: Select['defaultValue'];
109
109
  autoFocus?: Select['autoFocus'];
110
110
  validationBehavior?: Select['validationBehavior'];
111
+ selectionMode?: Select['selectionMode'];
111
112
  className?: Select['className'];
112
113
  style?: Select['style'];
113
114
  onOpenChange?: Select['onOpenChange'];
114
- } & Omit<Select, 'placeholder' | 'selectionMode' | 'value' | 'children' | 'isOpen' | 'isDisabled' | 'isInvalid' | 'isRequired' | 'defaultSelectedKey' | 'selectionMode' | 'onChange' | 'validate' | 'onSelectionChange'>;
115
+ } & Omit<Select, 'placeholder' | 'value' | 'children' | 'isOpen' | 'isDisabled' | 'isInvalid' | 'isRequired' | 'defaultSelectedKey' | 'selectionMode' | 'onChange' | 'validate' | 'onSelectionChange'>;
115
116
  type MenuProps = AriaMenuProps<ListOption>;
116
117
  export type DropdownMenuProps = {
117
118
  defaultSelectedKeys?: MenuProps['defaultSelectedKeys'];
@@ -43,15 +43,11 @@ export type ListOption<T = ListItem> = T | ListSection<T>;
43
43
  export type SelectItem = Omit<ListItem, 'onClick'>;
44
44
  export type MultiSelectItem = WithRequired<SelectItem, 'id'>;
45
45
  export type MultiSelectOption = ListOption<MultiSelectItem>;
46
- export type SelectInputProps = {
46
+ type BaseSelectInputProps = {
47
47
  /** The option Items to be displayed in the menu */
48
48
  children?: ReactNode;
49
49
  /** The options to be displayed in the menu */
50
50
  options?: ListOption<SelectItem>[];
51
- /** The controlled value of the input */
52
- value?: Key;
53
- /** The uncontrolled initial value of the input */
54
- defaultValue?: Key;
55
51
  /** Allow the selected option to be re-selected */
56
52
  allowRepeatSelection?: boolean;
57
53
  /** Hides the caret icon toggle */
@@ -66,10 +62,24 @@ export type SelectInputProps = {
66
62
  before?: ReactNode;
67
63
  /** The element to display after the menu options */
68
64
  after?: ReactNode;
69
- /** The function to be called when an option is selected */
70
- onChange?: (key: string) => void;
71
65
  maxHeight?: PopoverProps['maxHeight'];
72
66
  } & Omit<InputProps, 'iconRight'> & ShowHideCallbacks & Pick<PopoverProps, 'maxHeight'>;
67
+ export type SelectInputProps = BaseSelectInputProps & {
68
+ /** The controlled value of the input */
69
+ value?: Key | Key[];
70
+ /** The uncontrolled initial value of the input */
71
+ defaultValue?: Key | Key[];
72
+ /** The function to be called when an option is selected */
73
+ onChange?: (key: string | string[]) => void;
74
+ };
75
+ export type ComboBoxInputProps = BaseSelectInputProps & {
76
+ /** The controlled value of the input */
77
+ value?: Key;
78
+ /** The uncontrolled initial value of the input */
79
+ defaultValue?: Key;
80
+ /** The function to be called when an option is selected */
81
+ onChange?: (key: string) => void;
82
+ };
73
83
  export type CalendarBaseProps = {
74
84
  /** Prevents selection of dates in the past (relative to the set date or current date). */
75
85
  preventPast?: boolean | Date;
@@ -82,3 +92,4 @@ export type DateInputProps = {
82
92
  /** Hides the calendar picker icon */
83
93
  hidePicker?: boolean;
84
94
  } & ShowHideCallbacks & Omit<CalendarBaseProps, 'noShadow'> & Omit<InputProps, 'placeholder'>;
95
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wavv/ui",
3
- "version": "2.4.7",
3
+ "version": "2.4.8-alpha.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {