| 152 | * multiple selection state. |
| 153 | */ |
| 154 | export function useSelectState<T, M extends SelectionMode = 'single'>( |
| 155 | props: SelectStateOptions<T, M> |
| 156 | ): SelectState<T, M> { |
| 157 | let {selectionMode = 'single' as M, shouldCloseOnSelect = selectionMode === 'single'} = props; |
| 158 | let triggerState = useOverlayTriggerState(props); |
| 159 | let [focusStrategy, setFocusStrategy] = useState<FocusStrategy | null>(null); |
| 160 | let defaultValue = useMemo(() => { |
| 161 | return props.defaultValue !== undefined |
| 162 | ? props.defaultValue |
| 163 | : ((selectionMode === 'single' ? (props.defaultSelectedKey ?? null) : []) as ValueType<M>); |
| 164 | }, [props.defaultValue, props.defaultSelectedKey, selectionMode]); |
| 165 | let value = useMemo(() => { |
| 166 | return props.value !== undefined |
| 167 | ? props.value |
| 168 | : ((selectionMode === 'single' ? props.selectedKey : undefined) as ValueType<M>); |
| 169 | }, [props.value, props.selectedKey, selectionMode]); |
| 170 | let [controlledValue, setControlledValue] = useControlledState<Key | readonly Key[] | null>( |
| 171 | value, |
| 172 | defaultValue, |
| 173 | props.onChange as any |
| 174 | ); |
| 175 | // Only display the first selected item if in single selection mode but the value is an array. |
| 176 | let displayValue = |
| 177 | selectionMode === 'single' && Array.isArray(controlledValue) |
| 178 | ? controlledValue[0] |
| 179 | : controlledValue; |
| 180 | let setValue = (value: Key | Key[] | null) => { |
| 181 | if (selectionMode === 'single') { |
| 182 | let key = Array.isArray(value) ? (value[0] ?? null) : value; |
| 183 | setControlledValue(key); |
| 184 | if (key !== displayValue) { |
| 185 | props.onSelectionChange?.(key); |
| 186 | } |
| 187 | } else { |
| 188 | let keys: Key[] = []; |
| 189 | if (Array.isArray(value)) { |
| 190 | keys = value; |
| 191 | } else if (value != null) { |
| 192 | keys = [value]; |
| 193 | } |
| 194 | |
| 195 | setControlledValue(keys); |
| 196 | } |
| 197 | }; |
| 198 | |
| 199 | let listState = useListState({ |
| 200 | ...props, |
| 201 | selectionMode, |
| 202 | disallowEmptySelection: selectionMode === 'single', |
| 203 | allowDuplicateSelectionEvents: true, |
| 204 | selectedKeys: useMemo(() => convertValue(displayValue), [displayValue]), |
| 205 | onSelectionChange: (keys: Selection) => { |
| 206 | // impossible, but TS doesn't know that |
| 207 | if (keys === 'all') { |
| 208 | return; |
| 209 | } |
| 210 | |
| 211 | if (selectionMode === 'single') { |