mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 14:43:46 +01:00
Merge pull request #14585 from overleaf/msm-sso-config-modal
[web] SSO Config modal GitOrigin-RevId: e704afa61fe14390b64ce29a27ccbce7e884b396
This commit is contained in:
@@ -1,20 +1,38 @@
|
||||
/* eslint-disable jsx-a11y/label-has-for */
|
||||
/* eslint-disable jsx-a11y/label-has-associated-control */
|
||||
import { useRef, useEffect } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { useSelect } from 'downshift'
|
||||
import Icon from './icon'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
type SelectProps<T> = {
|
||||
export type SelectProps<T> = {
|
||||
// The items rendered as dropdown options.
|
||||
items: T[]
|
||||
itemToString: (item: T | null) => string
|
||||
// Stringifies an item of type T. The resulting string is rendered as a dropdown option.
|
||||
itemToString: (item: T | null | undefined) => string
|
||||
// Caption for the dropdown.
|
||||
label?: string
|
||||
// Attribute used to identify the component inside a Form. This name is used to
|
||||
// retrieve FormData when the form is submitted. The value of the FormData entry
|
||||
// is the string returned by `itemToString(selectedItem)`.
|
||||
name?: string
|
||||
// Hint text displayed in the initial render.
|
||||
defaultText?: string
|
||||
itemToSubtitle?: (item: T | null) => string
|
||||
// Initial selected item, displayed in the initial render. When both `defaultText`
|
||||
// and `defaultItem` are set the latter is ignored.
|
||||
defaultItem?: T
|
||||
// Stringifies an item. The resulting string is rendered as a subtitle in a dropdown option.
|
||||
itemToSubtitle?: (item: T | null | undefined) => string
|
||||
// Stringifies an item. The resulting string is rendered as a React `key` for each item.
|
||||
itemToKey: (item: T) => string
|
||||
// Callback invoked after the selected item is updated.
|
||||
onSelectedItemChanged?: (item: T | null | undefined) => void
|
||||
// When `true` item selection is disabled.
|
||||
disabled?: boolean
|
||||
// When `true` displays an "Optional" subtext after the `label` caption.
|
||||
optionalLabel?: boolean
|
||||
// When `true` displays a spinner next to the `label` caption.
|
||||
loading?: boolean
|
||||
}
|
||||
|
||||
@@ -22,7 +40,9 @@ export const Select = <T,>({
|
||||
items,
|
||||
itemToString = item => (item === null ? '' : String(item)),
|
||||
label,
|
||||
name,
|
||||
defaultText = 'Items',
|
||||
defaultItem,
|
||||
itemToSubtitle,
|
||||
itemToKey,
|
||||
onSelectedItemChanged,
|
||||
@@ -48,8 +68,37 @@ export const Select = <T,>({
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const rootRef = useRef<HTMLDivElement | null>(null)
|
||||
useEffect(() => {
|
||||
if (!name || !rootRef.current) return
|
||||
|
||||
const parentForm: HTMLFormElement | null | undefined =
|
||||
rootRef.current?.closest('form')
|
||||
if (!parentForm) return
|
||||
|
||||
function handleFormDataEvent(event: FormDataEvent) {
|
||||
const data = event.formData
|
||||
const key = name as string // can't be undefined due to early exit in the effect
|
||||
if (selectedItem || defaultItem) {
|
||||
data.append(key, itemToString(selectedItem || defaultItem))
|
||||
}
|
||||
}
|
||||
|
||||
parentForm.addEventListener('formdata', handleFormDataEvent)
|
||||
return () => {
|
||||
parentForm.removeEventListener('formdata', handleFormDataEvent)
|
||||
}
|
||||
}, [name, itemToString, selectedItem, defaultItem])
|
||||
|
||||
let value: string | undefined
|
||||
if (selectedItem || defaultItem) {
|
||||
value = itemToString(selectedItem || defaultItem)
|
||||
} else {
|
||||
value = defaultText
|
||||
}
|
||||
return (
|
||||
<div className="select-wrapper">
|
||||
<div className="select-wrapper" ref={rootRef}>
|
||||
<div>
|
||||
{label ? (
|
||||
<label {...getLabelProps()}>
|
||||
@@ -59,14 +108,14 @@ export const Select = <T,>({
|
||||
({t('optional')})
|
||||
</span>
|
||||
)}{' '}
|
||||
{loading && <Icon fw type="spinner" spin />}
|
||||
{loading && <Icon data-testid="spinner" fw type="spinner" spin />}
|
||||
</label>
|
||||
) : null}
|
||||
<div
|
||||
className={classNames({ disabled }, 'select-trigger')}
|
||||
{...getToggleButtonProps({ disabled })}
|
||||
>
|
||||
<div>{selectedItem ? itemToString(selectedItem) : defaultText}</div>
|
||||
<div>{value}</div>
|
||||
<div>
|
||||
{isOpen ? (
|
||||
<Icon type="chevron-up" fw />
|
||||
|
||||
Reference in New Issue
Block a user