@aokiapp/rjsf-mantine-corporate
Version:
Corporational variant of theme, based on @aokiapp/rjsf-mantine-theme
91 lines • 4.53 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { createErrors } from '@aokiapp/rjsf-mantine-theme';
import { Pill, PillsInput } from '@mantine/core';
import { labelValue, ariaDescribedByIds, } from '@rjsf/utils';
import { useCallback, useMemo, useState } from 'react';
/**
* The `PillInputWidget` is the special case of the array field where the user can enter a value and press enter to add
* it to the array.
* The schema of this widget must match the follwing criteria:
* - type: array
* - items: type: string
* - uniqueItems: true
*/
export default function PillInputWidget({ id, placeholder, label, hideLabel, value, required, readonly, disabled, onChange: onChangeBase, onChangeOverride, autofocus, rawErrors, hideError, schema, options: { description, removeOnBackspace = false, punctuation = null }, }) {
// check the schema criteria
if (schema.type !== 'array' ||
typeof schema.items !== 'object' ||
Array.isArray(schema.items) ||
schema.items.type !== 'string') {
throw new Error('The PillInputWidget is only compatible with a schema that is an array of unique strings');
}
// field-level controls start
const _value = useMemo(() => (Array.isArray(value) ? value : []), [value]);
const onChange = onChangeOverride || onChangeBase;
const onRemove = useCallback((i) => {
onChange(_value.filter((_, index) => index !== i));
}, [_value, onChange]);
const onAdd = useCallback((value) => {
onChange([..._value, value]);
}, [_value, onChange]);
// add multiple values at once
// I need this onAdd can be called within one render
const onBulkAdd = useCallback((values) => {
onChange([..._value, ...values]);
}, [_value, onChange]);
const currentPills = _value.map((v, i) => (_jsx(Pill, { withRemoveButton: !disabled && !readonly, onRemove: () => {
onRemove(i);
}, children: v }, i)));
// field-level controls end
// pill input start
const [tmpValue, setTmpValue] = useState('');
const handleChange = useCallback((e) => {
const v = e.target.value;
if (typeof punctuation === 'string' && punctuation.length) {
// split by punctuation
const split = v.split(punctuation);
// add all but the last one
onBulkAdd(split.slice(0, -1));
// set the last one as the tmp value
setTmpValue(split[split.length - 1]);
}
else {
setTmpValue(v);
}
}, [onBulkAdd, punctuation]);
// Japanese IME support
const [isComposing, setIsComposing] = useState(false);
const handleCompositionStart = useCallback(() => {
setIsComposing(true);
}, [setIsComposing]);
const handleCompositionEnd = useCallback(() => {
setIsComposing(false);
}, [setIsComposing]);
const handleBlur = useCallback(() => {
if (tmpValue) {
onAdd(tmpValue);
setTmpValue('');
}
}, [tmpValue, onAdd]);
const handleKeyDown = useCallback((e) => {
// handle enter air shot
if (e.key === 'Enter' && !isComposing && tmpValue) {
e.preventDefault(); // without this, enter will trigger the form submit
onAdd(tmpValue);
setTmpValue('');
}
// handle backspace when empty
if (e.key === 'Backspace' && !tmpValue && _value.length > 0) {
e.preventDefault(); // without this, the last character also gets deleted
const last = _value[_value.length - 1];
onRemove(_value.length - 1);
if (!removeOnBackspace) {
setTmpValue(last);
}
}
}, [isComposing, tmpValue, _value, onAdd, onRemove, removeOnBackspace]);
const pillInput = (_jsx(PillsInput.Field, { placeholder: placeholder, id: id, value: tmpValue, onChange: handleChange, onKeyDown: handleKeyDown, onCompositionStart: handleCompositionStart, onCompositionEnd: handleCompositionEnd, autoFocus: autofocus, disabled: disabled || readonly, onBlur: handleBlur }));
// pill input end
return (_jsx(PillsInput, { label: labelValue(label, hideLabel, undefined), description: description, disabled: disabled || readonly, error: createErrors(rawErrors, hideError), "aria-describedby": ariaDescribedByIds(id), required: required, className: 'armt-widget-pill-input', children: _jsxs(Pill.Group, { children: [currentPills, pillInput] }) }));
}
//# sourceMappingURL=PillInputWidget.js.map