mirror of
https://gitcode.com/GitHub_Trending/ji/jitsi-meet.git
synced 2025-12-30 11:22:31 +00:00
ref(invite): add people form (#13207)
This commit is contained in:
@@ -105,3 +105,11 @@ export interface ISwitchProps {
|
||||
*/
|
||||
onChange: (on?: boolean) => void;
|
||||
}
|
||||
|
||||
export type MultiSelectItem = {
|
||||
content: string;
|
||||
description?: string;
|
||||
elemBefore?: Element;
|
||||
isDisabled?: boolean;
|
||||
value: string;
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@ interface IProps extends IInputProps {
|
||||
maxRows?: number;
|
||||
minRows?: number;
|
||||
name?: string;
|
||||
onBlur?: (e: any) => void;
|
||||
onFocus?: (event: React.FocusEvent) => void;
|
||||
onKeyPress?: (e: React.KeyboardEvent) => void;
|
||||
readOnly?: boolean;
|
||||
required?: boolean;
|
||||
@@ -148,7 +150,9 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
maxRows,
|
||||
minRows,
|
||||
name,
|
||||
onBlur,
|
||||
onChange,
|
||||
onFocus,
|
||||
onKeyPress,
|
||||
placeholder,
|
||||
readOnly = false,
|
||||
@@ -208,7 +212,9 @@ const Input = React.forwardRef<any, IProps>(({
|
||||
{ ...(id ? { id } : {}) }
|
||||
maxLength = { maxLength }
|
||||
name = { name }
|
||||
onBlur = { onBlur }
|
||||
onChange = { handleChange }
|
||||
onFocus = { onFocus }
|
||||
onKeyPress = { onKeyPress }
|
||||
placeholder = { placeholder }
|
||||
readOnly = { readOnly }
|
||||
|
||||
175
react/features/base/ui/components/web/MultiSelect.tsx
Normal file
175
react/features/base/ui/components/web/MultiSelect.tsx
Normal file
@@ -0,0 +1,175 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import { makeStyles } from 'tss-react/mui';
|
||||
|
||||
import { IconCloseLarge } from '../../../icons/svg';
|
||||
import { withPixelLineHeight } from '../../../styles/functions.web';
|
||||
import { MultiSelectItem } from '../types';
|
||||
|
||||
import ClickableIcon from './ClickableIcon';
|
||||
import Input from './Input';
|
||||
|
||||
interface IProps {
|
||||
autoFocus?: boolean;
|
||||
disabled?: boolean;
|
||||
error?: boolean;
|
||||
errorDialog?: JSX.Element | null;
|
||||
filterValue?: string;
|
||||
isOpen?: boolean;
|
||||
items: MultiSelectItem[];
|
||||
noMatchesText?: string;
|
||||
onFilterChange?: (value: string) => void;
|
||||
onRemoved: (item: any) => void;
|
||||
onSelected: (item: any) => void;
|
||||
placeholder?: string;
|
||||
selectedItems?: MultiSelectItem[];
|
||||
}
|
||||
|
||||
const useStyles = makeStyles()(theme => {
|
||||
return {
|
||||
container: {
|
||||
position: 'relative'
|
||||
},
|
||||
items: {
|
||||
'&.found': {
|
||||
position: 'absolute',
|
||||
boxShadow: '0px 5px 10px rgba(0, 0, 0, 0.75)'
|
||||
},
|
||||
marginTop: theme.spacing(2),
|
||||
width: '100%',
|
||||
backgroundColor: theme.palette.ui01,
|
||||
border: `1px solid ${theme.palette.ui04}`,
|
||||
borderRadius: `${Number(theme.shape.borderRadius)}px`,
|
||||
...withPixelLineHeight(theme.typography.bodyShortRegular),
|
||||
zIndex: 2,
|
||||
maxHeight: '400px',
|
||||
overflowY: 'auto',
|
||||
padding: '0'
|
||||
},
|
||||
listItem: {
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
padding: `${theme.spacing(2)} ${theme.spacing(3)}`,
|
||||
alignItems: 'center',
|
||||
'& .content': {
|
||||
// 38px because of the icon before the content
|
||||
inlineSize: 'calc(100% - 38px)',
|
||||
overflowWrap: 'break-word',
|
||||
marginLeft: theme.spacing(2),
|
||||
color: theme.palette.text01,
|
||||
'&.with-remove': {
|
||||
// 60px because of the icon before the content and the remove button
|
||||
inlineSize: 'calc(100% - 60px)',
|
||||
marginRight: theme.spacing(2),
|
||||
'&.without-before': {
|
||||
marginLeft: 0,
|
||||
inlineSize: 'calc(100% - 38px)'
|
||||
}
|
||||
},
|
||||
'&.without-before': {
|
||||
marginLeft: 0,
|
||||
inlineSize: '100%'
|
||||
}
|
||||
},
|
||||
'&.found': {
|
||||
cursor: 'pointer',
|
||||
padding: `10px ${theme.spacing(3)}`,
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui02
|
||||
}
|
||||
},
|
||||
'&.disabled': {
|
||||
cursor: 'not-allowed',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.ui01
|
||||
},
|
||||
color: theme.palette.text03
|
||||
}
|
||||
},
|
||||
errorMessage: {
|
||||
position: 'absolute',
|
||||
marginTop: theme.spacing(2),
|
||||
width: '100%'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const MultiSelect = ({
|
||||
autoFocus,
|
||||
disabled,
|
||||
error,
|
||||
errorDialog,
|
||||
placeholder,
|
||||
items,
|
||||
filterValue,
|
||||
onFilterChange,
|
||||
isOpen,
|
||||
noMatchesText,
|
||||
onSelected,
|
||||
selectedItems,
|
||||
onRemoved
|
||||
}: IProps) => {
|
||||
const { classes } = useStyles();
|
||||
const inputRef = useRef();
|
||||
const selectItem = useCallback(item => () => onSelected(item), [ onSelected ]);
|
||||
const removeItem = useCallback(item => () => onRemoved(item), [ onRemoved ]);
|
||||
const foundItems = useMemo(() => (
|
||||
<div className = { `${classes.items} found` }>
|
||||
{
|
||||
items.length > 0
|
||||
? items.map(item => (
|
||||
<div
|
||||
className = { `${classes.listItem} ${item.isDisabled ? 'disabled' : ''} found` }
|
||||
key = { item.value }
|
||||
onClick = { item.isDisabled ? undefined : selectItem(item) }>
|
||||
{item.elemBefore}
|
||||
<div className = { `content ${item.elemBefore ? '' : 'without-before'}` }>
|
||||
{item.content}
|
||||
{item.description && <p>{item.description}</p>}
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
: <div>{noMatchesText}</div>
|
||||
}
|
||||
</div>
|
||||
), [ items ]);
|
||||
|
||||
const errorMessageDialog = useMemo(() =>
|
||||
error && <div className = { classes.errorMessage }>
|
||||
{ errorDialog }
|
||||
</div>, [ error ]);
|
||||
|
||||
return (
|
||||
<div className = { classes.container }>
|
||||
<Input
|
||||
autoFocus = { autoFocus }
|
||||
disabled = { disabled }
|
||||
onChange = { onFilterChange }
|
||||
placeholder = { placeholder }
|
||||
ref = { inputRef }
|
||||
value = { filterValue ?? '' } />
|
||||
{isOpen && foundItems}
|
||||
{ errorMessageDialog }
|
||||
{ selectedItems && selectedItems?.length > 0 && (
|
||||
<div className = { classes.items }>
|
||||
{ selectedItems.map(item => (
|
||||
<div
|
||||
className = { `${classes.listItem} ${item.isDisabled ? 'disabled' : ''}` }
|
||||
key = { item.value }>
|
||||
{item.elemBefore}
|
||||
<div className = { `content with-remove ${item.elemBefore ? '' : 'without-before'}` }>
|
||||
<p>{item.content}</p>
|
||||
</div>
|
||||
<ClickableIcon
|
||||
accessibilityLabel = { 'multi-select-unselect' }
|
||||
icon = { IconCloseLarge }
|
||||
id = 'modal-header-close-button'
|
||||
onClick = { removeItem(item) } />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MultiSelect;
|
||||
Reference in New Issue
Block a user