Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
components.form.fields.InputMultipleSelectFieldLocal.js Maven / Gradle / Ivy
import {
selectOption,
isOption,
isSelectedOption,
filterDuplicateOptions,
filterOptionsByLabelWithExpression
} from "utils/option-utils";
import * as React from "react";
import { CircularProgress } from "@mui/material";
import Checkbox from "@mui/material/Checkbox";
import TextField from "@mui/material/TextField";
import Autocomplete from "@mui/material/Autocomplete";
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
import CheckBoxIcon from "@mui/icons-material/CheckBox";
import { formatChoices } from "components/form/utils/input-utils";
import InputError from "components/form/fields/InputError";
import { validateField } from "components/form/utils/validate-utils";
import { useDebounce, withDefault } from "utils/utils";
import { Chip, Typography } from "@mui/material";
import { useFieldInfo } from "hooks/field";
import { useFormInfo } from "hooks/form";
import { useTranslator } from "hooks/translator";
import { useAutoSubmitSignal } from "hooks/autosubmit";
import { useConfig } from "hooks/config";
import { fieldMinWidthStyle } from "components/form/utils/field-utils";
const InputMultipleSelectFieldContent = (props) => {
const { augProps, fieldProps, info } = useFieldInfo()
const formInfo = useFormInfo()
const { t, translator } = useTranslator()
const [input, setInput, debouncedInput, skipDebounce] = useDebounce("", 500)
const [open, setOpen] = React.useState(false);
const [allOptions, setAllOptions] = React.useState([]);
const [options, setOptions] = React.useState([]);
const [selected, setSelected] = React.useState([]); // this value is never allowed to be 'undefined'!!
const [highlighted, setHighlighted] = React.useState(null)
const [loading, setLoading ] = React.useState(false)
const {signal} = useAutoSubmitSignal()
const {props: {taskRendering}} = useConfig()
const { setFocus, setViewOpen } = props
const loadInitialOptions = open && allOptions.length === 0;
const fancySelect = allOptions.length < 100
const getOptions = () => formatChoices(translator, info.options, info.optionsKind, formInfo.processDefinition.key)
// set selected
React.useEffect(() => {
var selected = fieldProps.value && Array.isArray(fieldProps.value) ? fieldProps.value : []
// convert values to options
if (selected.length > 0 && !isOption(selected[0]))
selected = selected.map(value => selectOption(info.options, value))
// translate options
selected = formatChoices(translator, selected, info.optionsKind, formInfo.processDefinition.key)
setSelected(selected)
}, [fieldProps.value]);
// load initial options
React.useEffect(() => {
if (!loadInitialOptions)
return
setLoading(true)
let active = true;
(async () => {
const options = formatChoices(translator, info.options, info.optionsKind, formInfo.processDefinition.key)
if (active)
setAllOptions(options)
})();
return () => { active = false; }
}, [loadInitialOptions]);
// filter options
React.useEffect(() => {
if (!(open && allOptions.length == info.numOptions))
return;
setLoading(true)
let active = true;
(async () => {
const filteredOptions = debouncedInput === ""
? allOptions
: filterOptionsByLabelWithExpression(allOptions, debouncedInput)
if (active) {
setOptions(filteredOptions)
setLoading(false)
}
})();
return () => { active = false; }
}, [open, debouncedInput, allOptions]);
// update current load state
React.useEffect(() => {
if (!open) {
setAllOptions([]);
setLoading(false)
} else {
if (options.length > 100)
setOptions([]);
if (input !== debouncedInput)
setLoading(true)
if (input === "" || fancySelect)
skipDebounce()
}
}, [input, open])
function handleValidate(e, value) {
const error = validateField("multiselect", fieldProps.required, e, value)
augProps.setError(error)
}
function handleBlur (e) {
setFocus(false)
fieldProps.onBlur(e)
handleValidate(e, selected)
signal()
}
function handleFocus(e) {
setFocus(true)
fieldProps.onFocus(e)
}
const getSelected = (value, previousSelected, allowRemoval, reason) => {
const matchesOption = (option) => option.value === value?.value || option.value === value
const addValueTo = (selected) => {
if (selected.some(matchesOption))
return allowRemoval ? selected.filter(o => !matchesOption(o)) : selected
else
return [...selected, value]
}
if (Array.isArray(value))
switch (reason) {
case "removeOption":
return value
case "selectOption":
return value
default:
return filterDuplicateOptions(withDefault(value, []))
}
else {
const selected = !Array.isArray(previousSelected) ? [] : previousSelected
return value ? addValueTo(selected) : selected
}
}
function handleChange(e, value, reason) {
augProps.setRuntimeError(undefined)
const newSelected = getSelected(value, selected, true, reason)
signal()
setSelected(newSelected)
augProps.setValue(newSelected)
handleValidate(e, newSelected)
}
function handleInputChange(e, value) {
setInput(value)
}
function optionMatches(option, value) {
return Boolean(option?.label?.toLowerCase().includes(input?.toLowerCase() || ""))
}
function handleTabSelection(e, value) {
const options = getOptions()
const opt = options.find(option => optionMatches(option, value))
if (opt){
handleChange(e, opt)
} else {
notifier.error("no option matches input: " + value)
e.stopPropagation()
e.preventDefault()
}
}
function handleKeyDown(e) {
switch (e.key) {
case "Tab": // tab completion
if (input == "")
return
e.preventDefault()
e.stopPropagation()
const option = highlighted
const tabAlreadyMatches = optionMatches(option, input)
if (tabAlreadyMatches){
handleChange(e, option)
} else {
skipDebounce()
handleTabSelection(e, input)
}
break;
case "Enter": // enter completion
e.preventDefault();
if (input !== debouncedInput) {
e.stopPropagation()
skipDebounce()
}
break;
default:
}
};
function handleHightlightChange(e, value) {
setHighlighted(value)
}
const renderOption = (props, option) => (
}
checkedIcon={ }
style={{ marginRight: 8 }}
checked={isSelectedOption(option, selected)}
/>
{option.label}
)
const renderOptions = fancySelect ? { renderOption: renderOption } : {}
const { onChange, ...localFieldProps } = fieldProps
return (
x}
// highlight options
autoHighlight
highlighted={highlighted}
onHighlightChange={handleHightlightChange}
sx={{flexGrow: 1}} //width: taskRendering == 'standard' ? "100%" : undefined}}
componentsProps={{paper: {sx: {minWidth: "100%", width: "max-content"}}}} // This increases the width of the dropdown box
// popper options
open={open}
onOpen={() => { setOpen(true); setViewOpen(true)}}
onClose={() => { setOpen(false); setViewOpen(false) }}
// localization options
loadingText={t("select.loading")}
clearText={t("select.clear")}
closeText={t("select.close")}
openText={t("select.open")}
noOptionsText={t("select.nooptions")}
// input value options
value={selected}
loading={loading}
onChange={handleChange}
isOptionEqualToValue={(option, value) => value && option.value === value.value }
onInputChange={handleInputChange}
input={input}
{...renderOptions}
renderTags={(value, getTagProps) =>
value.map((option, index) =>
{option.label}}
/>
)
}
renderInput={(params) => {
params.inputProps.onKeyDown = handleKeyDown;
return (
{loading ? : null}
{params.InputProps.endAdornment}
),
inputProps: {
...params.inputProps,
"data-state": "local"
}
}}
size={fieldProps.size}
style={taskRendering == 'standard' ? fieldMinWidthStyle(formInfo, info.field) : undefined}
fullWidth
/>
)}}
/>
);
}
const InputMultipleSelectFieldLocal = (props) => (
)
export default InputMultipleSelectFieldLocal