design-comuni-plone-theme
Version:
Volto Theme for Italia design guidelines
386 lines (362 loc) • 11 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, useIntl } from 'react-intl';
import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable';
import { Icon } from 'design-comuni-plone-theme/components/ItaliaTheme';
import './select-styles.css';
const messages = defineMessages({
select_noOptionsMessage: {
id: 'select_noOptionsMessage',
defaultMessage: 'Nessuna opzione',
},
risultato: { id: 'select_risultato', defaultMessage: 'risultato' },
risultati: { id: 'select_risultati', defaultMessage: 'risultati' },
ay11_up_down: {
id: 'ay11_Use Up and Down to choose options',
defaultMessage: "Usa le frecce Su e Giu per scegliere un'opzione",
},
ay11_select_option: {
id: 'ay11_select_press Enter to select the currently focused option',
defaultMessage: "premi Invio per selezionare l'opzione corrente",
},
ay11_exit_menu: {
id: 'ay11_select_press Escape to exit the menu',
defaultMessage: 'premi Esc per uscire dal menu',
},
ay11_tab_select_and_exit: {
id: 'ay11_select__press Tab to select the option and exit the menu',
defaultMessage: "premi Tab per selezionare l'opzione e uscire dal menu",
},
ay11_is_focused: {
id: 'ay11_select_is_focused',
defaultMessage: 'è selezionato',
},
ay11_type_to_refine_list: {
id: 'ay11_select__type to refine list',
defaultMessage: 'digita per filtrare la lista',
},
ay11_open_menu: {
id: 'ay11_select_press Down to open the menu',
defaultMessage:
'premi freccia giu per aprire il menu, premi Backspace per rimuovere il valore selezionato',
},
ay11_multi_select_focus_values: {
id: 'ay11_select_press left to focus selected values',
defaultMessage:
'premi la freccia a sinistra per evidenziare i valori selezionati',
},
ay11_toggle_values: {
id: 'ay11_select_Use left and right to toggle between focused values, press Backspace to remove the currently focused value',
defaultMessage:
'Usa le frecce destra e sinistra per attivare o disattivare i valori evidenziati, premi Backspace per rimuovere il valore corrente evidenziato',
},
ay11_option: {
id: 'ay11_select option',
defaultMessage: 'opzione',
},
ay11_option_deselected: {
id: 'ay11_select deselected',
defaultMessage: 'deselezionata',
},
ay11_option_disabled: {
id: 'ay11_select is disabled. Select another option.',
defaultMessage: "è disabilitata. Seleziona un'altra opzione",
},
ay11_option_selected: {
id: 'ay11_select selected',
defaultMessage: 'selezionata',
},
ay11_value: {
id: 'ay11_select value',
defaultMessage: 'valore',
},
ay11_focused: {
id: 'ay11_select focused',
defaultMessage: 'evidenziato',
},
ay11_disabled: {
id: 'ay11_select disabled',
defaultMessage: 'disabilitato',
},
ay11_for_search_term: {
id: 'ay11_select for search term',
defaultMessage: 'per la ricerca',
},
ay11_for_cancel: {
id: 'ay11_select cancel',
defaultMessage: 'Annulla',
},
dropwdown_indicator: {
id: 'dropdown_indicator',
defaultMessage: 'Apri il menu',
},
SelectInput_default_label: {
id: 'SelectInput_default_label',
defaultMessage: "Seleziona un'opzione",
},
});
const SelectContainer = injectLazyLibs('reactSelect')(({
children,
...props
}) => {
const components = props.reactSelect.components;
return (
<div>
<components.SelectContainer {...props}>
{children}
</components.SelectContainer>
</div>
);
});
SelectContainer.propTypes = {
children: PropTypes.node,
};
const Option = injectLazyLibs('reactSelect')((props) => {
const components = props.reactSelect.components;
return (
<div className="select-pill text-primary">
<components.Option {...props} />
</div>
);
});
const MenuList = injectLazyLibs('reactSelect')(({ children, ...props }) => {
const components = props.reactSelect.components;
return (
<div>
<components.MenuList {...props}>{children}</components.MenuList>
</div>
);
});
MenuList.propTypes = {
children: PropTypes.node,
};
const DropdownIndicator = injectLazyLibs('reactSelect')((props) => {
const intl = useIntl();
const components = props.reactSelect.components;
return (
<components.DropdownIndicator {...props}>
<Icon
icon="it-arrow-down-triangle"
style={{ ariaHidden: true }}
title={intl.formatMessage(messages.dropwdown_indicator)}
/>
</components.DropdownIndicator>
);
});
const GroupHeading = injectLazyLibs('reactSelect')((props) => {
const components = props.reactSelect.components;
return (
<div>
<components.GroupHeading {...props} />
</div>
);
});
const ClearIndicator = (props) => {
const intl = useIntl();
const {
innerProps: { ref, ...restInnerProps },
} = props;
return (
<div
className="select-pill text-primary clearButton"
{...restInnerProps}
ref={ref}
>
<div
style={{ padding: '0px 5px' }}
title={intl.formatMessage(messages.ay11_for_cancel)}
>
<Icon
icon="it-close"
style={{ ariaHidden: true }}
title={intl.formatMessage(messages.ay11_for_cancel)}
/>
</div>
</div>
);
};
ClearIndicator.propTypes = {
children: PropTypes.node,
innerProps: PropTypes.object,
};
const getSelectAriaLiveMessages = (intl) => {
return {
guidance: (props) => {
const { isSearchable, isMulti, isDisabled, tabSelectsValue, context } =
props;
switch (context) {
case 'menu':
return `${intl.formatMessage(messages.ay11_up_down)}${
isDisabled
? ''
: `, ${intl.formatMessage(messages.ay11_select_option)}`
}, ${intl.formatMessage(messages.ay11_exit_menu)}${
tabSelectsValue
? `, ${intl.formatMessage(messages.ay11_tab_select_and_exit)}`
: ''
}.`;
case 'input':
return `${props['aria-label'] || 'Select'} ${intl.formatMessage(
messages.ay11_is_focused,
)} ${
isSearchable
? `,${intl.formatMessage(messages.ay11_type_to_refine_list)}`
: ''
}, ${intl.formatMessage(messages.ay11_open_menu)}, ${
isMulti
? ` ${intl.formatMessage(
messages.ay11_multi_select_focus_values,
)}`
: ''
}`;
case 'value':
return intl.formatMessage(messages.ay11_toggle_values);
default:
return '';
}
},
onChange: (props) => {
const { action, label = '', isDisabled } = props;
switch (action) {
case 'deselect-option':
case 'pop-value':
case 'remove-value':
return `${intl.formatMessage(
messages.ay11_option,
)} ${label}, ${intl.formatMessage(messages.ay11_option_deselected)}.`;
case 'select-option':
return isDisabled
? `${intl.formatMessage(
messages.ay11_option,
)} ${label} ${intl.formatMessage(messages.ay11_option_disabled)}.`
: `${intl.formatMessage(
messages.ay11_option,
)} ${label}, ${intl.formatMessage(
messages.ay11_option_selected,
)}.`;
default:
return '';
}
},
onFocus: (props) => {
const {
context,
focused = {},
options,
label = '',
selectValue,
isDisabled,
isSelected,
} = props;
const getArrayIndex = (arr, item) =>
arr && arr.length ? `${arr.indexOf(item) + 1} of ${arr.length}` : '';
if (context === 'value' && selectValue) {
return `${intl.formatMessage(
messages.ay11_value,
)} ${label} ${intl.formatMessage(
messages.ay11_focused,
)}, ${getArrayIndex(selectValue, focused)}.`;
}
if (context === 'menu') {
const disabled = isDisabled
? ` ${intl.formatMessage(messages.ay11_disabled)}`
: '';
const status = `${
isSelected
? intl.formatMessage(messages.ay11_option_selected)
: intl.formatMessage(messages.ay11_focused)
}${disabled}`;
return `${intl.formatMessage(
messages.ay11_option,
)} ${label} ${status}, ${getArrayIndex(options, focused)}.`;
}
return '';
},
onFilter: (props) => {
const { inputValue, resultsMessage } = props;
return `${resultsMessage}${
inputValue
? ` ${intl.formatMessage(messages.ay11_for_search_term)} ` +
inputValue
: ''
}.`;
},
};
};
const SelectInput = ({
id = 'design-select',
value = null,
placeholder = '',
label,
isDisabled = false,
isSearchable = false,
isMulti = false,
isClearable = false,
onChange,
options,
components = {},
reactSelect,
labelledby,
defaultValue,
}) => {
const intl = useIntl();
const labelDefined =
label || intl.formatMessage(messages.SelectInput_default_label);
const Select = reactSelect.default;
return (
<div className="bootstrap-select-wrapper">
{label && <label htmlFor={!labelledby ? id : undefined}>{label}</label>}
<Select
components={{
MenuList,
Option,
SelectContainer,
DropdownIndicator,
ClearIndicator,
GroupHeading,
IndicatorSeparator: null,
...components,
}}
id={id}
value={value}
onChange={onChange}
options={options}
placeholder={placeholder}
isDisabled={isDisabled}
isSearchable={isSearchable}
isMulti={isMulti}
isClearable={isClearable}
aria-label={labelDefined}
aria-labelledby={!label ? labelledby : undefined}
aria-live="polite"
ariaLiveMessages={getSelectAriaLiveMessages(intl)}
noOptionsMessage={() =>
intl.formatMessage(messages.select_noOptionsMessage)
}
escapeClearsValue={true}
screenReaderStatus={({ count }) =>
`${count} ${
count !== 1
? intl.formatMessage(messages.risultato)
: intl.formatMessage(messages.risultati)
}`
}
classNamePrefix={'react-select'}
defaultValue={defaultValue}
/>
</div>
);
};
SelectInput.propTypes = {
id: PropTypes.string,
value: PropTypes.any.isRequired,
placeholder: PropTypes.string,
label: PropTypes.string,
isDisabled: PropTypes.bool,
isSearchable: PropTypes.bool,
isMulti: PropTypes.bool,
isClearable: PropTypes.bool,
onChange: PropTypes.func.isRequired,
options: PropTypes.arrayOf(PropTypes.object).isRequired,
};
export default injectLazyLibs('reactSelect')(SelectInput);