'use client'; import * as Ariakit from '@ariakit/react'; import React, { useState, useId, useEffect } from 'react'; import MdHelpButton from '../help/MdHelpButton'; import MdHelpText from '../help/MdHelpText'; import MdIconClose from '../icons-material/MdIconClose'; import MdIconKeyboardArrowDown from '../icons-material/MdIconKeyboardArrowDown'; import MdCheckbox from './MdCheckbox'; interface Labels { helpTextFor?: string; reset?: string; openClose?: string; } export interface MdSelectOption { text: string; value: string; } export interface MdSelectProps { label?: string | null; labels?: Labels; options?: MdSelectOption[]; id?: string; /** * v5.0.0: value is now either a string or an array of strings */ value: string | string[]; placeholder?: string; disabled?: boolean; mode?: 'large' | 'medium' | 'small'; helpText?: string; error?: boolean; errorText?: string; flip?: boolean; dropdownHeight?: number; allowReset?: boolean; /** * When `true`, the popover will be unmounted when it is hidden. This can be useful for performance reasons, but it may cause issues with animations or transitions. * @default false * @see https://ariakit.org/reference/select-popover#unmountonhide */ unmountOnHide?: boolean; /** * v5.0.0: onSelectOption now returns either a string or an array of strings */ onSelectOption(_value: string[] | string): void; } export const MdSelect = React.forwardRef( ( { label, labels = {}, value, options, id, placeholder = 'Velg verdi', disabled = false, mode = 'medium', helpText, error = false, errorText, flip = false, dropdownHeight, allowReset = false, onSelectOption, unmountOnHide, ...otherProps }, ref, ) => { const uuid = `select_${useId()}`; const selectBoxId = id || uuid; const isMultiSelect = Array.isArray(value); const [helpOpen, setHelpOpen] = useState(false); const [selectedValues, setSelectedValues] = useState(value); const [displayValue, setDisplayValue] = useState(null); const store = Ariakit.useSelectStore(); const defaultLabels: Required = { helpTextFor: 'Hjelpetekst for', reset: 'Nullstill', openClose: 'Åpne/lukke liste', }; const mergedLabels: Required = { ...defaultLabels, ...labels }; useEffect(() => { setSelectedValues(value); }, [value]); useEffect(() => { let dv = placeholder; if (selectedValues && options) { let option: string | string[] | null = selectedValues as string; if (isMultiSelect) { option = selectedValues[0] || null; } dv = options.find(opt => { return opt.value === option; })?.text || placeholder; } setDisplayValue(dv); }, [selectedValues, isMultiSelect, placeholder, options]); const onReset = (e: React.MouseEvent) => { const newValue = isMultiSelect ? [] : ''; setSelectedValues(newValue); onSelectOption(newValue); e.stopPropagation(); }; const showReset = () => { if (allowReset) { if (isMultiSelect) { return selectedValues.length > 0; } return selectedValues !== ''; } return false; }; const toggle = (e: React.MouseEvent) => { store.toggle(); e.stopPropagation(); }; let ariaDescribedBy = helpText && helpText !== '' ? `md-combobox_help-text_${selectBoxId}` : undefined; ariaDescribedBy = error && errorText && errorText !== '' ? `md-combobox_error_${selectBoxId}` : ariaDescribedBy; const showLabel = (label && label !== '') || (helpText && helpText !== ''); return (
{ const mutableVal = Array.isArray(val) ? (Array.from(val) as string[]) : (val as string); setSelectedValues(mutableVal); onSelectOption(mutableVal); }} > {showLabel && (
{label && label !== '' && {label}} {helpText && helpText !== '' && (
{ return setHelpOpen(!helpOpen); }} expanded={helpOpen} />
)}
{helpText && helpText !== '' && (
{helpText}
)}
)}
} aria-describedby={ariaDescribedBy} aria-expanded={Ariakit.useStoreState(store, 'open')} className="md-select__button" {...otherProps} > {displayValue}
{isMultiSelect && selectedValues.length > 0 && `+${selectedValues.length}`}
{showReset() && ( )}
{options && options.map(option => { const isChecked = isMultiSelect ? selectedValues.toString().includes(option.value) : selectedValues === option.value; return ( {isMultiSelect ? ( ) : ( option.text )} ); })}
{error && errorText && errorText !== '' && (
{errorText}
)}
); }, ); MdSelect.displayName = 'MdSelect'; export default MdSelect;