diff --git a/api-generator/components/multiselect.js b/api-generator/components/multiselect.js index f8eb6130e2..9d8164b4c6 100644 --- a/api-generator/components/multiselect.js +++ b/api-generator/components/multiselect.js @@ -53,6 +53,18 @@ const MultiSelectProps = [ default: 'null', description: 'Property name or getter function that refers to the children options of option group.' }, + { + name: 'inline', + type: 'boolean', + default: 'false', + description: 'Render the items panel inline.' + }, + { + name: 'flex', + type: 'boolean', + default: 'false', + description: 'Use flex layout for the items panel.' + }, { name: 'style', type: 'string', @@ -65,6 +77,12 @@ const MultiSelectProps = [ default: 'null', description: 'Style class of the element.' }, + { + name: 'itemClassName', + type: 'string', + default: 'null', + description: 'Style class of the items.' + }, { name: 'panelClassName', type: 'string', diff --git a/components/doc/multiselect/inlinedoc.js b/components/doc/multiselect/inlinedoc.js new file mode 100644 index 0000000000..c51ab9c539 --- /dev/null +++ b/components/doc/multiselect/inlinedoc.js @@ -0,0 +1,105 @@ +import { useState } from 'react'; +import { MultiSelect } from '../../lib/multiselect/MultiSelect'; +import { DocSectionCode } from '../common/docsectioncode'; +import { DocSectionText } from '../common/docsectiontext'; + +export function InlineDoc(props) { + const [selectedCities, setSelectedCities] = useState(null); + const cities = [ + { label: 'New York', value: 'NY' }, + { label: 'Rome', value: 'RM' }, + { label: 'London', value: 'LDN' }, + { label: 'Istanbul', value: 'IST' }, + { label: 'Paris', value: 'PRS' } + ]; + + const code = { + basic: ` + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + `, + javascript: ` +import { useState } from "react"; +import { MultiSelect } from 'primereact/multiselect'; + +export default function InlineDoc() { + const [selectedCities, setSelectedCities] = useState(null); + const cities = [ + { label: 'New York', value: 'NY' }, + { label: 'Rome', value: 'RM' }, + { label: 'London', value: 'LDN' }, + { label: 'Istanbul', value: 'IST' }, + { label: 'Paris', value: 'PRS' } + ]; + + return ( + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + ); +} + `, + typescript: ` +import { useState } from "react"; +import { MultiSelect, MultiSelectChangeParams } from 'primereact/multiselect'; + +export default function InlineDoc() { + const [selectedCities, setSelectedCities] = useState(null); + const cities = [ + { label: 'New York', value: 'NY' }, + { label: 'Rome', value: 'RM' }, + { label: 'London', value: 'LDN' }, + { label: 'Istanbul', value: 'IST' }, + { label: 'Paris', value: 'PRS' } + ]; + + return ( + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + setSelectedCities(e.value)} /> + ); +} + ` + }; + + return ( + <> + + Set the property inline to true to display the items as inline panel. Set the property flex to true to use flex layout for the items panel. Use the property itemClassName to control the class of the items, for + example to display them with a fixed width. + +
+
+ inline + setSelectedCities(e.value)} /> +
+
+ flex +
+ setSelectedCities(e.value)} /> +
+
+ inline + flex + setSelectedCities(e.value)} /> +
+
+ flex + itemClassName +
+ setSelectedCities(e.value)} /> +
+
+ inline + flex + itemClassName + setSelectedCities(e.value)} /> +
+
+ + + ); +} diff --git a/components/lib/calendar/calendar.d.ts b/components/lib/calendar/calendar.d.ts index 4b2935fc3c..9ef0d3ba40 100644 --- a/components/lib/calendar/calendar.d.ts +++ b/components/lib/calendar/calendar.d.ts @@ -11,15 +11,17 @@ type CalendarIconPosType = 'left' | 'right'; type CalendarEventType = React.SyntheticEvent | undefined | null; +type CalendarValueType = Date | Date[] | string | undefined | null; + interface CalendarChangeTargetOptions { name: string; id: string; - value: Date | Date[] | undefined | null; + value: CalendarValueType; } interface CalendarChangeParams { originalEvent: React.SyntheticEvent; - value: Date | Date[] | undefined; + value: CalendarValueType; stopPropagation(): void; preventDefault(): void; target: CalendarChangeTargetOptions; @@ -37,7 +39,7 @@ interface CalendarViewChangeParams { interface CalendarSelectParams { originalEvent: React.SyntheticEvent; - value: Date | Date[]; + value: CalendarValueType; } interface CalendarDateTemplateParams { @@ -131,7 +133,7 @@ export interface CalendarProps { tooltipOptions?: TooltipOptions; touchUI?: boolean; transitionOptions?: CSSTransitionProps; - value?: Date | Date[]; + value?: CalendarValueType; view?: string; viewDate?: Date; visible?: boolean; diff --git a/components/lib/multiselect/MultiSelect.css b/components/lib/multiselect/MultiSelect.css index ea9fcc9be9..d759f23506 100644 --- a/components/lib/multiselect/MultiSelect.css +++ b/components/lib/multiselect/MultiSelect.css @@ -52,6 +52,22 @@ left: 0; } +.p-multiselect-inline.p-multiselect-panel { + border: none; + position: initial; + background: none; + box-shadow: none; +} + +.p-multiselect-inline.p-multiselect-panel .p-multiselect-items { + padding: 0; +} + +.p-multiselect-flex.p-multiselect-panel .p-multiselect-items { + display: flex; + flex-wrap: wrap; +} + .p-multiselect-items-wrapper { overflow: auto; } diff --git a/components/lib/multiselect/MultiSelect.js b/components/lib/multiselect/MultiSelect.js index a63524bbae..49ee1c26db 100644 --- a/components/lib/multiselect/MultiSelect.js +++ b/components/lib/multiselect/MultiSelect.js @@ -10,7 +10,7 @@ export const MultiSelect = React.memo( React.forwardRef((props, ref) => { const [filterState, setFilterState] = React.useState(''); const [focusedState, setFocusedState] = React.useState(false); - const [overlayVisibleState, setOverlayVisibleState] = React.useState(false); + const [overlayVisibleState, setOverlayVisibleState] = React.useState(props.inline); const elementRef = React.useRef(null); const inputRef = React.useRef(props.inputRef); const labelRef = React.useRef(null); @@ -113,7 +113,7 @@ export const MultiSelect = React.memo( }; const onClick = (event) => { - if (!props.disabled && !isPanelClicked(event) && !DomHandler.hasClass(event.target, 'p-multiselect-token-icon') && !isClearClicked(event)) { + if (!props.inline && !props.disabled && !isPanelClicked(event) && !DomHandler.hasClass(event.target, 'p-multiselect-token-icon') && !isClearClicked(event)) { overlayVisibleState ? hide() : show(); DomHandler.focus(inputRef.current); event.preventDefault(); @@ -124,6 +124,8 @@ export const MultiSelect = React.memo( switch (event.which) { //down case 40: + if (props.inline) break; + if (!overlayVisibleState && event.altKey) { show(); event.preventDefault(); @@ -133,12 +135,14 @@ export const MultiSelect = React.memo( //space case 32: + if (props.inline) break; overlayVisibleState ? hide() : show(); event.preventDefault(); break; //escape case 27: + if (props.inline) break; hide(); break; @@ -584,8 +588,8 @@ export const MultiSelect = React.memo( }, props.className ); - const label = createLabel(); - const clearIcon = createClearIcon(); + const label = !props.inline && createLabel(); + const clearIcon = !props.inline && createClearIcon(); return ( <> @@ -607,9 +611,13 @@ export const MultiSelect = React.memo( {...ariaProps} /> - {label} - {clearIcon} -
{IconUtils.getJSXIcon(props.dropdownIcon, { className: 'p-multiselect-trigger-icon p-c' }, { props })}
+ {!props.inline && ( + <> + {label} + {clearIcon} +
{IconUtils.getJSXIcon(props.dropdownIcon, { className: 'p-multiselect-trigger-icon p-c' }, { props })}
+ + )} { 'p-highlight': props.selected, 'p-disabled': props.disabled }, + props.className, props.option.className ); const checkboxClassName = classNames('p-checkbox-box', { diff --git a/components/lib/multiselect/MultiSelectPanel.js b/components/lib/multiselect/MultiSelectPanel.js index f0eaad6d26..9bb1df3b5c 100644 --- a/components/lib/multiselect/MultiSelectPanel.js +++ b/components/lib/multiselect/MultiSelectPanel.js @@ -84,6 +84,7 @@ export const MultiSelectPanel = React.memo( onKeyDown={props.onOptionKeyDown} tabIndex={tabIndex} disabled={disabled} + className={props.itemClassName} /> ); }); @@ -130,6 +131,7 @@ export const MultiSelectPanel = React.memo( onKeyDown={props.onOptionKeyDown} tabIndex={tabIndex} disabled={disabled} + className={props.itemClassName} /> ); } @@ -188,6 +190,8 @@ export const MultiSelectPanel = React.memo( const panelClassName = classNames( 'p-multiselect-panel p-component', { + 'p-multiselect-inline': props.inline, + 'p-multiselect-flex': props.flex, 'p-multiselect-limited': !allowOptionSelect }, props.panelClassName @@ -196,6 +200,15 @@ export const MultiSelectPanel = React.memo( const content = createContent(); const footer = createFooter(); + if (props.inline) { + return ( +
+ {content} + {footer} +
+ ); + } + return ( ; }) ); diff --git a/components/lib/multiselect/multiselect.d.ts b/components/lib/multiselect/multiselect.d.ts index e9c58d3707..2362516b45 100755 --- a/components/lib/multiselect/multiselect.d.ts +++ b/components/lib/multiselect/multiselect.d.ts @@ -86,8 +86,11 @@ export interface MultiSelectProps extends Omit { label: 'Basic', component: BasicDoc }, + { + id: 'inline', + label: 'Inline, flex, itemClassName', + component: InlineDoc + }, { id: 'chips', label: 'Chips',