@luomus/laji-form 15.1.24 → 15.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/laji-form.js +1 -1
- package/dist/styles.css +96 -5
- package/lib/ApiClient.d.ts +2 -1
- package/lib/components/BaseComponent.d.ts +1 -1
- package/lib/components/LajiForm.d.ts +3 -13
- package/lib/components/VirtualSchemaField.d.ts +10 -10
- package/lib/components/fields/AsArrayField.d.ts +131 -7
- package/lib/components/fields/ExtraLabelRowField.d.ts +1 -1
- package/lib/components/fields/ImageArrayField.d.ts +12 -12
- package/lib/components/fields/InitiallyHiddenField.d.ts +1 -1
- package/lib/components/fields/LocationChooserField.d.ts +1 -1
- package/lib/components/fields/MultiTagArrayField.d.ts +2 -2
- package/lib/components/fields/MultiTagArrayField.js +2 -1
- package/lib/components/fields/NamedPlaceChooserField.d.ts +88 -2
- package/lib/components/fields/NamedPlaceChooserField.js +1 -1
- package/lib/components/fields/NamedPlaceSaverField.d.ts +44 -1
- package/lib/components/fields/PdfArrayField.d.ts +2 -2
- package/lib/components/fields/ScopeField.d.ts +1 -1
- package/lib/components/fields/SingleActiveArrayField.js +1 -1
- package/lib/components/fields/SortArrayField.d.ts +93 -6
- package/lib/components/fields/SortArrayField.js +1 -1
- package/lib/components/fields/SplitField.d.ts +1 -1
- package/lib/components/fields/SplitField.js +3 -2
- package/lib/components/fields/StringToArrayField.d.ts +44 -1
- package/lib/components/fields/TagArrayField.js +1 -1
- package/lib/components/fields/ToggleAdditionalArrayFieldsField.d.ts +1 -1
- package/lib/components/fields/UnitListShorthandArrayField.d.ts +44 -1
- package/lib/components/widgets/AutosuggestWidget.js +1 -1
- package/lib/components/widgets/CheckboxWidget.js +7 -6
- package/lib/components/widgets/SelectWidget.d.ts +13 -52
- package/lib/components/widgets/SelectWidget.js +234 -145
- package/lib/services/focus-service.js +3 -2
- package/lib/services/settings-service.d.ts +2 -2
- package/lib/services/submit-hook-service.d.ts +1 -1
- package/lib/themes/theme.d.ts +4 -7
- package/lib/types.d.ts +59 -0
- package/lib/types.js +11 -0
- package/lib/utils.d.ts +13 -7
- package/lib/utils.js +19 -7
- package/package.json +3 -3
- package/test-export/test-utils.js +4 -4
|
@@ -1,158 +1,247 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const React = require("react");
|
|
4
|
-
|
|
5
|
-
const Combobox = require("react-widgets/lib/Combobox");
|
|
6
|
-
const Multiselect = require("react-widgets/lib/Multiselect");
|
|
7
|
-
const components_1 = require("../components");
|
|
8
|
-
const Context_1 = require("../../Context");
|
|
4
|
+
// import * as PropTypes from "prop-types";
|
|
9
5
|
const ReactContext_1 = require("../../ReactContext");
|
|
10
6
|
const utils_1 = require("../../utils");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const item = this.elemRef.state.focusedItem;
|
|
42
|
-
item && this.elemRef.handleSelect(item, e);
|
|
43
|
-
};
|
|
44
|
-
this.setRef = elem => {
|
|
45
|
-
this.elemRef = elem;
|
|
46
|
-
};
|
|
47
|
-
this.getEnum = val => utils_1.isEmptyString(val) ? undefined : val;
|
|
48
|
-
this.state = this.getStateFromProps(props);
|
|
49
|
-
this._context = Context_1.default(this.props.formContext.contextId);
|
|
50
|
-
}
|
|
51
|
-
componentDidMount() {
|
|
52
|
-
this.mounted = true;
|
|
53
|
-
this.props.formContext.services.focus.addFocusHandler(this.props.id, this.onFocus);
|
|
54
|
-
}
|
|
55
|
-
componentWillUnmount() {
|
|
56
|
-
this.mounted = false;
|
|
57
|
-
this.props.formContext.services.focus.removeFocusHandler(this.props.id, this.onFocus);
|
|
58
|
-
}
|
|
59
|
-
UNSAFE_componentWillReceiveProps(props) {
|
|
60
|
-
this.setState(this.getStateFromProps(props));
|
|
7
|
+
const react_1 = require("react");
|
|
8
|
+
const react_dom_1 = require("react-dom");
|
|
9
|
+
const useRangeIncrementor = (length, defaultIdx) => {
|
|
10
|
+
const [idx, _setIdx] = React.useState(defaultIdx);
|
|
11
|
+
const setIdx = react_1.useCallback((idx) => {
|
|
12
|
+
let nextIdx = idx;
|
|
13
|
+
if (idx === undefined || idx < 0 || length === 0) {
|
|
14
|
+
nextIdx = undefined;
|
|
15
|
+
}
|
|
16
|
+
else if (idx >= length) {
|
|
17
|
+
nextIdx = length - 1;
|
|
18
|
+
}
|
|
19
|
+
_setIdx(nextIdx);
|
|
20
|
+
}, [_setIdx, length]);
|
|
21
|
+
const increment = react_1.useCallback(() => setIdx((idx || 0) - 1), [idx, setIdx]);
|
|
22
|
+
const decrement = react_1.useCallback(() => setIdx(idx === undefined ? 0 : idx + 1), [idx, setIdx]);
|
|
23
|
+
return [idx === undefined ? idx : Math.min(idx, length - 1), increment, decrement, _setIdx];
|
|
24
|
+
};
|
|
25
|
+
function removeByIndex(array, index) {
|
|
26
|
+
return [...array.slice(0, index), ...array.slice(index + 1)];
|
|
27
|
+
}
|
|
28
|
+
function getEnumOptions(enumOptions, uiSchema, includeEmpty = true) {
|
|
29
|
+
const enums = (utils_1.getUiOptions(uiSchema).enumOptions || enumOptions);
|
|
30
|
+
const emptyIdx = enums.findIndex(e => e.value === "");
|
|
31
|
+
if (!includeEmpty) {
|
|
32
|
+
return emptyIdx !== -1
|
|
33
|
+
? removeByIndex(enums, emptyIdx)
|
|
34
|
+
: enums;
|
|
61
35
|
}
|
|
62
|
-
|
|
63
|
-
return
|
|
36
|
+
else {
|
|
37
|
+
return emptyIdx !== -1
|
|
38
|
+
? enums.map(e => e.value === "" ? { value: undefined, label: "" } : e)
|
|
39
|
+
: [{ value: undefined, label: "" }, ...enums];
|
|
64
40
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
41
|
+
}
|
|
42
|
+
function SelectWidget(props) {
|
|
43
|
+
// export default function SelectWidget(props: SelectWidgetProps): Widget<JSONSchemaEnum | JSONSchemaArray<JSONSchemaEnumOneOf>> {
|
|
44
|
+
return props.schema.type === "array" ? React.createElement(SearchableMultiDrowndown, Object.assign({}, props)) : React.createElement(SearchableDrowndown, Object.assign({}, props));
|
|
45
|
+
}
|
|
46
|
+
exports.default = SelectWidget;
|
|
47
|
+
function SearchableDrowndown(props) {
|
|
48
|
+
const { id, disabled, readonly, value, uiSchema, options, onChange, includeEmpty = true } = props;
|
|
49
|
+
const { theme } = React.useContext(ReactContext_1.default);
|
|
50
|
+
const containerRef = React.useRef(null);
|
|
51
|
+
const inputRef = React.useRef(null);
|
|
52
|
+
const dropdownRef = React.useRef(null);
|
|
53
|
+
const enumOptions = React.useMemo(() =>
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
55
|
+
getEnumOptions(options.enumOptions, uiSchema, includeEmpty), [options.enumOptions, uiSchema, includeEmpty]);
|
|
56
|
+
const [inputValue, setInputValue] = React.useState(value
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
58
|
+
? enumOptions.find(item => item.value === value).label
|
|
59
|
+
: "");
|
|
60
|
+
const [inputTouched, setInputTouched] = React.useState(false);
|
|
61
|
+
const [filterTerm, setFilterTerm] = React.useState("");
|
|
62
|
+
const onInputChange = react_1.useCallback((e) => {
|
|
63
|
+
const { value } = e.target;
|
|
64
|
+
setInputValue(value);
|
|
65
|
+
setInputTouched(true);
|
|
66
|
+
}, []);
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
inputTouched && setFilterTerm(inputValue);
|
|
69
|
+
}, [inputTouched, inputValue]);
|
|
70
|
+
const displayedEnums = React.useMemo(() => {
|
|
71
|
+
return filterTerm !== ""
|
|
72
|
+
? enumOptions.filter(({ label }) => label.toLowerCase().match(filterTerm.toLowerCase()))
|
|
73
|
+
: enumOptions;
|
|
74
|
+
}, [filterTerm, enumOptions]);
|
|
75
|
+
const [isOpen, show, hide] = utils_1.useBooleanSetter(false);
|
|
76
|
+
const { FormControl } = theme;
|
|
77
|
+
const [activeIdx, activeIdxUp, activeIdxDown, setActiveIdx] = useRangeIncrementor((displayedEnums || []).length, value !== undefined && value !== ""
|
|
78
|
+
? displayedEnums.findIndex(item => item.value === value)
|
|
79
|
+
: 0);
|
|
80
|
+
const onItemSelected = react_1.useCallback((item) => {
|
|
81
|
+
onChange(item.value);
|
|
82
|
+
setInputValue(item.label);
|
|
83
|
+
setInputTouched(false);
|
|
84
|
+
setActiveIdx(displayedEnums.findIndex(enu => enu.value === item.value));
|
|
85
|
+
hide();
|
|
86
|
+
}, [displayedEnums, hide, onChange, setActiveIdx]);
|
|
87
|
+
const onBlur = react_1.useCallback((e) => {
|
|
88
|
+
// Fixes the issue that when user tries to click an enum item, `setOpen(false)`
|
|
89
|
+
// hides the enum list, so the elem list item is hidden before the click, thus never
|
|
90
|
+
// sending a click event.
|
|
91
|
+
if (e.relatedTarget && utils_1.isDescendant(containerRef.current, e.relatedTarget)) {
|
|
92
|
+
return;
|
|
78
93
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
enumOptions = utils_1.filter(enumOptions, _filter, filterType, item => item.value);
|
|
94
|
+
if (activeIdx !== undefined && displayedEnums[activeIdx]) {
|
|
95
|
+
onItemSelected(displayedEnums[activeIdx]);
|
|
82
96
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return { value, label: value in labels ? labels[value] : label };
|
|
86
|
-
});
|
|
97
|
+
else {
|
|
98
|
+
setInputValue("");
|
|
87
99
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
hide();
|
|
101
|
+
}, [activeIdx, displayedEnums, hide, onItemSelected]);
|
|
102
|
+
const onKeyDown = react_1.useCallback((e) => {
|
|
103
|
+
switch (e.key) {
|
|
104
|
+
case "ArrowDown":
|
|
105
|
+
activeIdxDown();
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
break;
|
|
108
|
+
case "ArrowUp":
|
|
109
|
+
activeIdxUp();
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
break;
|
|
112
|
+
case "Enter":
|
|
113
|
+
activeIdx !== undefined && displayedEnums && onItemSelected(displayedEnums[activeIdx]);
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
break;
|
|
93
116
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const { id, disabled, readonly, multiple, formContext, } = this.props;
|
|
108
|
-
const { enumOptions } = this.state;
|
|
109
|
-
const commonOptions = {
|
|
110
|
-
id,
|
|
111
|
-
value: this.state.value,
|
|
112
|
-
placeholder: utils_1.getUiOptions(this.props).placeholder,
|
|
113
|
-
data: enumOptions,
|
|
114
|
-
valueField: "value",
|
|
115
|
-
textField: "label",
|
|
116
|
-
disabled: disabled || readonly,
|
|
117
|
-
filter: "contains",
|
|
118
|
-
messages: {
|
|
119
|
-
open: formContext.translations.Open,
|
|
120
|
-
emptyList: formContext.translations.NoResults,
|
|
121
|
-
emptyFilter: formContext.translations.NoResults
|
|
122
|
-
},
|
|
123
|
-
onFocus: this.onFocus,
|
|
124
|
-
onBlur: this.onBlur,
|
|
125
|
-
onToggle: this.onToggle,
|
|
126
|
-
open: this.state.open,
|
|
127
|
-
onKeyDown: this.onKeyDown
|
|
128
|
-
};
|
|
129
|
-
const selectComponent = multiple ? (React.createElement(Multiselect, Object.assign({}, commonOptions, { onChange: this.multiSelectOnChange, ref: this.setRef }))) : (React.createElement(Combobox, Object.assign({}, commonOptions, { onChange: this.selectOnChange, ref: this.setRef, onClick: this.onClick, onSelect: this.onSelect })));
|
|
130
|
-
return (React.createElement(components_1.TooltipComponent, { placement: "top", trigger: "hover", tooltip: (multiple || utils_1.isEmptyString(this.props.value)) ? undefined : this.state.valsToItems[this.props.value].label },
|
|
131
|
-
React.createElement("div", null, selectComponent)));
|
|
132
|
-
}
|
|
117
|
+
}, [activeIdx, activeIdxDown, activeIdxUp, displayedEnums, onItemSelected]);
|
|
118
|
+
const onFocus = react_1.useCallback(() => {
|
|
119
|
+
var _a;
|
|
120
|
+
show();
|
|
121
|
+
(_a = react_dom_1.findDOMNode(inputRef.current)) === null || _a === void 0 ? void 0 : _a.setSelectionRange(0, inputValue.length);
|
|
122
|
+
}, [inputValue.length, show]);
|
|
123
|
+
return (React.createElement("div", { onBlur: onBlur, onKeyDown: onKeyDown, ref: containerRef, style: { position: "relative" }, className: "laji-form-dropdown-container" },
|
|
124
|
+
React.createElement(FormControl, { disabled: disabled || readonly, id: id, onFocus: onFocus, value: inputValue, onChange: onInputChange, autoComplete: "off", ref: inputRef }),
|
|
125
|
+
React.createElement(Caret, { onFocus: onFocus }),
|
|
126
|
+
React.createElement("div", { className: `laji-form-dropdown laji-form-dropdown-${isOpen ? "open" : "closed"}`, style: { position: "absolute" }, tabIndex: -1, ref: dropdownRef }, displayedEnums.map((oneOf, idx) => {
|
|
127
|
+
var _a;
|
|
128
|
+
return (React.createElement(ListItem, { key: (_a = oneOf.value) !== null && _a !== void 0 ? _a : "", onSelected: onItemSelected, active: idx === activeIdx }, oneOf));
|
|
129
|
+
}))));
|
|
133
130
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
131
|
+
function SearchableMultiDrowndown(props) {
|
|
132
|
+
const { id, disabled, readonly, value, uiSchema, options, onChange, } = props;
|
|
133
|
+
const enumOptions = React.useMemo(() =>
|
|
134
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
135
|
+
getEnumOptions(options.enumOptions, uiSchema, false), [options.enumOptions, uiSchema]);
|
|
136
|
+
const [inputValue, setInputValue] = React.useState("");
|
|
137
|
+
const [filterTerm, setFilterTerm] = React.useState("");
|
|
138
|
+
const onInputChange = react_1.useCallback((e) => {
|
|
139
|
+
const { value } = e.target;
|
|
140
|
+
setInputValue(value);
|
|
141
|
+
}, []);
|
|
142
|
+
React.useEffect(() => {
|
|
143
|
+
setFilterTerm(inputValue);
|
|
144
|
+
}, [inputValue]);
|
|
145
|
+
const displayedEnums = React.useMemo(() => {
|
|
146
|
+
const notAlreadySelected = (value === null || value === void 0 ? void 0 : value.length)
|
|
147
|
+
? enumOptions.filter(({ value: enumValue }) => !value.includes(enumValue))
|
|
148
|
+
: enumOptions;
|
|
149
|
+
return filterTerm !== ""
|
|
150
|
+
? notAlreadySelected.filter(({ label, value: enumValue }) => (value || []).includes(enumValue)
|
|
151
|
+
|| label.toLowerCase().match(filterTerm.toLowerCase()))
|
|
152
|
+
: notAlreadySelected;
|
|
153
|
+
}, [filterTerm, enumOptions, value]);
|
|
154
|
+
const [isOpen, show, hide] = utils_1.useBooleanSetter(false);
|
|
155
|
+
const containerRef = React.useRef(null);
|
|
156
|
+
const inputRef = React.useRef(null);
|
|
157
|
+
const [activeIdx, activeIdxUp, activeIdxDown, setActiveIdx] = useRangeIncrementor((displayedEnums || []).length, undefined);
|
|
158
|
+
const onItemSelected = react_1.useCallback((item) => {
|
|
159
|
+
var _a;
|
|
160
|
+
onChange([...(value || []), item.value]);
|
|
161
|
+
setInputValue("");
|
|
162
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
163
|
+
setActiveIdx(undefined);
|
|
164
|
+
}, [onChange, setActiveIdx, value]);
|
|
165
|
+
const onItemSelectedByBlur = react_1.useCallback((item) => {
|
|
166
|
+
onChange([...(value || []), item.value]);
|
|
167
|
+
setInputValue("");
|
|
168
|
+
setActiveIdx(undefined);
|
|
169
|
+
}, [onChange, setActiveIdx, value]);
|
|
170
|
+
const onBlur = react_1.useCallback((e) => {
|
|
171
|
+
// Fixes the problem when user tries to click an enum item, `setOpen(false)`
|
|
172
|
+
// hides the enum list, so the elem list item is hidden before the click, thus never
|
|
173
|
+
// sending a click event.
|
|
174
|
+
if (e.relatedTarget && utils_1.isDescendant(containerRef.current, e.relatedTarget)) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
hide();
|
|
178
|
+
if (activeIdx !== undefined && displayedEnums[activeIdx]) {
|
|
179
|
+
onItemSelectedByBlur(displayedEnums[activeIdx]);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
setInputValue("");
|
|
183
|
+
}
|
|
184
|
+
}, [activeIdx, displayedEnums, hide, onItemSelectedByBlur]);
|
|
185
|
+
const onKeyDown = react_1.useCallback((e) => {
|
|
186
|
+
switch (e.key) {
|
|
187
|
+
case "ArrowDown":
|
|
188
|
+
activeIdxDown();
|
|
189
|
+
e.preventDefault();
|
|
190
|
+
break;
|
|
191
|
+
case "ArrowUp":
|
|
192
|
+
activeIdxUp();
|
|
193
|
+
e.preventDefault();
|
|
194
|
+
break;
|
|
195
|
+
case "Enter":
|
|
196
|
+
activeIdx !== undefined && displayedEnums && onItemSelected(displayedEnums[activeIdx]);
|
|
197
|
+
e.preventDefault();
|
|
198
|
+
break;
|
|
199
|
+
case "Backspace":
|
|
200
|
+
if (inputValue === "" && (value === null || value === void 0 ? void 0 : value.length)) {
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
202
|
+
onChange(value.slice(0, -1));
|
|
203
|
+
e.preventDefault();
|
|
204
|
+
}
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}, [activeIdx, activeIdxDown, activeIdxUp, displayedEnums, inputValue, onChange, onItemSelected, value]);
|
|
208
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
209
|
+
const onDelete = react_1.useCallback((enu) => {
|
|
210
|
+
const filtered = value.filter(v => v !== enu.value);
|
|
211
|
+
onChange(value.length === 0 ? undefined : filtered);
|
|
212
|
+
}, [onChange, value]);
|
|
213
|
+
/* eslint-enable @typescript-eslint/no-non-null-assertion */
|
|
214
|
+
const redirectFocusToInput = react_1.useCallback((e) => {
|
|
215
|
+
var _a;
|
|
216
|
+
// Only the input wrapper should redirect focus, otherwise the existing label deletion buttons will also redirect, breaking shift + tab navigation on the input.
|
|
217
|
+
if (!e.target.classList.contains("laji-form-multiselect-input-wrapper")) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
|
|
221
|
+
}, [inputRef]);
|
|
222
|
+
const wrapperClassNames = utils_1.classNames("laji-form-multiselect-input-wrapper", isOpen && "laji-form-multiselect-input-wrapper-focus", (readonly || disabled) && "laji-form-multiselect-input-wrapper-readonly");
|
|
223
|
+
return (React.createElement("div", { onBlur: onBlur, onKeyDown: onKeyDown, ref: containerRef, className: "laji-form-multiselect", style: { position: "relative" } },
|
|
224
|
+
React.createElement("div", { className: wrapperClassNames, tabIndex: -1, onFocus: redirectFocusToInput },
|
|
225
|
+
React.createElement("ul", { style: { listStyle: "none", display: "inline-block" } }, (value || []).map(v => enumOptions.find(({ value: _value }) => v === _value))
|
|
226
|
+
.map((enu) => React.createElement(SelectedMultiValue, { key: enu.value, onDelete: onDelete, readonly: readonly || disabled }, enu))),
|
|
227
|
+
React.createElement("input", { disabled: disabled || readonly, id: id, onFocus: show, value: inputValue, onChange: onInputChange, autoComplete: "off", ref: inputRef })),
|
|
228
|
+
React.createElement(Caret, { onFocus: show }),
|
|
229
|
+
React.createElement("div", { className: `laji-form-dropdown laji-form-dropdown-${isOpen ? "open" : "closed"}`, style: { position: "absolute", zIndex: 99999 }, tabIndex: -1 }, displayedEnums.map((oneOf, idx) => {
|
|
230
|
+
var _a;
|
|
231
|
+
return (React.createElement(ListItem, { key: (_a = oneOf.value) !== null && _a !== void 0 ? _a : "", onSelected: onItemSelected, active: idx === activeIdx }, oneOf));
|
|
232
|
+
}))));
|
|
233
|
+
}
|
|
234
|
+
const SelectedMultiValue = ({ children: enu, onDelete, readonly }) => {
|
|
235
|
+
const onDeleteClick = react_1.useCallback(() => !readonly && onDelete(enu), [enu, onDelete, readonly]);
|
|
236
|
+
return (React.createElement("li", { key: enu.value, style: { display: "inline-table" }, className: "laji-form-multiselect-tag" },
|
|
237
|
+
enu.label,
|
|
238
|
+
React.createElement("span", { tabIndex: readonly ? undefined : 0, role: readonly ? undefined : "button", onClick: onDeleteClick }, "\u00D7")));
|
|
157
239
|
};
|
|
158
|
-
|
|
240
|
+
const Caret = ({ onFocus }) => React.createElement("div", { className: "laji-form-dropdown-caret-container", style: { position: "absolute", pointerEvents: "none" } },
|
|
241
|
+
React.createElement("span", { onFocus: onFocus, className: "laji-form-dropdown-caret" }, "\u2304"));
|
|
242
|
+
function ListItem({ onSelected, active, children }) {
|
|
243
|
+
const onClick = react_1.useCallback(() => {
|
|
244
|
+
onSelected(children);
|
|
245
|
+
}, [children, onSelected]);
|
|
246
|
+
return (React.createElement("div", { onClick: onClick, className: utils_1.classNames("laji-form-dropdown-item", active && "active"), tabIndex: -1 }, children.label));
|
|
247
|
+
}
|
|
@@ -42,8 +42,9 @@ class FocusService {
|
|
|
42
42
|
const input = document.querySelector(`#${id}`);
|
|
43
43
|
if (elem)
|
|
44
44
|
utils_1.scrollIntoViewIfNeeded(elem, this.formContext.topOffset, this.formContext.bottomOffset);
|
|
45
|
-
if (input && input.focus)
|
|
45
|
+
if (input && input.focus) {
|
|
46
46
|
input.focus();
|
|
47
|
+
}
|
|
47
48
|
if (!elem)
|
|
48
49
|
return;
|
|
49
50
|
utils_1.highlightElem(elem);
|
|
@@ -51,7 +52,7 @@ class FocusService {
|
|
|
51
52
|
}
|
|
52
53
|
focusNextInput(reverse = false) {
|
|
53
54
|
if (!this.formContext.formRef.current) {
|
|
54
|
-
console.warn("Focus service
|
|
55
|
+
console.warn("Focus service doesn't have ref to the form");
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
58
|
return this.formContext.utils.focusNextInput(reverse);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
import { FieldProps, WidgetProps } from "../
|
|
2
|
+
import { FieldProps, WidgetProps } from "../types";
|
|
3
3
|
export declare type Settings = Record<string, string>;
|
|
4
4
|
declare type OnSettingsChange = (settings: Record<string, string>, global: boolean) => void;
|
|
5
5
|
/**
|
|
@@ -23,7 +23,7 @@ export default class SettingsService {
|
|
|
23
23
|
* @param that this of the React component
|
|
24
24
|
* @param props The constructor props
|
|
25
25
|
*/
|
|
26
|
-
bind<P extends (FieldProps | WidgetProps)>(that: React.Component<P>, props: P): void;
|
|
26
|
+
bind<P extends (FieldProps<any> | WidgetProps)>(that: React.Component<P>, props: P): void;
|
|
27
27
|
private loadStateSettings;
|
|
28
28
|
loadContextSettings<P extends FieldProps | WidgetProps>(props: P, context: any): any;
|
|
29
29
|
private loadSettings;
|
package/lib/themes/theme.d.ts
CHANGED
|
@@ -1,18 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { HasMaybeChildren, HasMaybeClassName } from "../types";
|
|
2
3
|
export declare type Variant = "default" | "primary" | "success" | "info" | "warning" | "danger" | "outline-danger" | string;
|
|
3
4
|
export declare type ButtonVariant = Variant | "link";
|
|
4
|
-
export interface HasMaybeChildren {
|
|
5
|
-
children?: React.ReactNode;
|
|
6
|
-
}
|
|
7
5
|
interface HasMaybeRef {
|
|
8
6
|
ref?: React.Ref<any> | React.LegacyRef<any>;
|
|
9
7
|
}
|
|
10
8
|
interface HasMaybeStyle {
|
|
11
9
|
style?: React.CSSProperties;
|
|
12
10
|
}
|
|
13
|
-
interface HasMaybeClassName {
|
|
14
|
-
className?: string;
|
|
15
|
-
}
|
|
16
11
|
export interface PanelProps extends HasMaybeRef, HasMaybeClassName, HasMaybeStyle {
|
|
17
12
|
expanded?: boolean;
|
|
18
13
|
onToggle?: () => void;
|
|
@@ -114,14 +109,16 @@ export interface FormControlProps extends React.HTMLProps<any>, HasMaybeRef {
|
|
|
114
109
|
readOnly?: boolean;
|
|
115
110
|
validationState?: ValidationState;
|
|
116
111
|
}
|
|
117
|
-
export interface ListGroupProps extends JSX.IntrinsicAttributes, HasMaybeRef {
|
|
112
|
+
export interface ListGroupProps extends JSX.IntrinsicAttributes, HasMaybeRef, HasMaybeStyle, HasMaybeClassName {
|
|
118
113
|
fill?: boolean;
|
|
114
|
+
tabIndex?: number;
|
|
119
115
|
}
|
|
120
116
|
export interface ListGroupItemProps extends JSX.IntrinsicAttributes, HasMaybeClassName {
|
|
121
117
|
onClick?: React.MouseEventHandler<any>;
|
|
122
118
|
disabled?: boolean;
|
|
123
119
|
header?: React.ReactNode;
|
|
124
120
|
active?: boolean;
|
|
121
|
+
tabIndex?: number;
|
|
125
122
|
}
|
|
126
123
|
export declare type Breadcrumb = React.ComponentType<any> & {
|
|
127
124
|
Item: React.ComponentType<BreadcrumbItem>;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { FieldProps as RJSFFieldProps, WidgetProps as RJSFWidgetProps, UiSchema as RJSFUiSchema } from "@rjsf/utils";
|
|
3
|
+
import { FormContext } from "./components/LajiForm";
|
|
4
|
+
export declare type JSON = string | number | boolean | JSONObject | JSON[] | null;
|
|
5
|
+
export declare type JSONObject = {
|
|
6
|
+
[prop: string]: JSON;
|
|
7
|
+
};
|
|
8
|
+
export declare type JSONSchema<T = any> = JSONSchemaObject | JSONSchemaArray<T> | JSONSchemaNumber | JSONSchemaInteger | JSONSchemaBoolean | JSONSchemaString | JSONSchemaEnum;
|
|
9
|
+
declare type JSONShemaTypeCommon<T, D> = {
|
|
10
|
+
type: T;
|
|
11
|
+
default?: D;
|
|
12
|
+
title?: string;
|
|
13
|
+
};
|
|
14
|
+
export declare type JSONSchemaObject = JSONShemaTypeCommon<"object", Record<string, JSONObject>> & {
|
|
15
|
+
properties: Record<string, JSONSchema>;
|
|
16
|
+
required?: string[];
|
|
17
|
+
};
|
|
18
|
+
export declare function isJSONSchemaObject(schema: JSONSchema): schema is JSONSchemaObject;
|
|
19
|
+
export declare type JSONSchemaArray<T = JSONSchema, D = never> = JSONShemaTypeCommon<"array", D[]> & {
|
|
20
|
+
items: T;
|
|
21
|
+
uniqueItems?: boolean;
|
|
22
|
+
maxItems?: number;
|
|
23
|
+
};
|
|
24
|
+
export declare type JSONSchemaNumber = JSONShemaTypeCommon<"number", number>;
|
|
25
|
+
export declare type JSONSchemaInteger = JSONShemaTypeCommon<"integer", number>;
|
|
26
|
+
export declare type JSONSchemaBoolean = JSONShemaTypeCommon<"boolean", boolean>;
|
|
27
|
+
export declare type JSONSchemaString = JSONShemaTypeCommon<"string", string>;
|
|
28
|
+
export declare type JSONSchemaEnumOneOf = {
|
|
29
|
+
const: string;
|
|
30
|
+
title: string;
|
|
31
|
+
};
|
|
32
|
+
export declare type JSONSchemaEnum = JSONSchemaString & {
|
|
33
|
+
oneOf: JSONSchemaEnumOneOf[];
|
|
34
|
+
};
|
|
35
|
+
export declare function isJSONSchemaEnum(jsonSchema: JSONSchema): jsonSchema is JSONSchemaEnum;
|
|
36
|
+
export declare type Lang = "fi" | "en" | "sv";
|
|
37
|
+
export declare type FieldProps<S extends JSONSchema = JSONSchema> = RJSFFieldProps<any, S, FormContext> & {
|
|
38
|
+
uiSchema: UiSchema;
|
|
39
|
+
errorSchema: NonNullable<RJSFFieldProps<any, S, FormContext>["errorSchema"]>;
|
|
40
|
+
formContext: FormContext;
|
|
41
|
+
registry: RJSFFieldProps<any, JSONSchema, FormContext>["registry"];
|
|
42
|
+
};
|
|
43
|
+
export declare type WidgetProps<S extends JSONSchema = JSONSchema> = RJSFWidgetProps<any, S, FormContext> & {
|
|
44
|
+
uiSchema: UiSchema;
|
|
45
|
+
errorSchema: NonNullable<RJSFFieldProps<any, JSONSchema, FormContext>["errorSchema"]>;
|
|
46
|
+
formContext: FormContext;
|
|
47
|
+
registry: RJSFWidgetProps<any, JSONSchema, FormContext>["registry"];
|
|
48
|
+
};
|
|
49
|
+
export declare type UiSchema = RJSFUiSchema<any, JSONSchemaObject, FormContext>;
|
|
50
|
+
export interface HasMaybeChildren {
|
|
51
|
+
children?: React.ReactNode;
|
|
52
|
+
}
|
|
53
|
+
export interface HasMaybeClassName {
|
|
54
|
+
className?: string;
|
|
55
|
+
}
|
|
56
|
+
export declare type Optional<T, K extends keyof T> = Omit<T, K> & Partial<{
|
|
57
|
+
[K: string]: T[K];
|
|
58
|
+
}>;
|
|
59
|
+
export {};
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isJSONSchemaEnum = exports.isJSONSchemaObject = void 0;
|
|
4
|
+
function isJSONSchemaObject(schema) {
|
|
5
|
+
return schema.type === "object";
|
|
6
|
+
}
|
|
7
|
+
exports.isJSONSchemaObject = isJSONSchemaObject;
|
|
8
|
+
function isJSONSchemaEnum(jsonSchema) {
|
|
9
|
+
return !!jsonSchema.oneOf;
|
|
10
|
+
}
|
|
11
|
+
exports.isJSONSchemaEnum = isJSONSchemaEnum;
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Spec as UpdateObject } from "immutability-helper";
|
|
3
3
|
import { isObject as _isObject } from "@luomus/laji-map/lib/utils";
|
|
4
|
-
import {
|
|
5
|
-
import { FormContext, Translations,
|
|
4
|
+
import { RJSFSchema } from "@rjsf/utils";
|
|
5
|
+
import { FormContext, Translations, ByLang } from "./components/LajiForm";
|
|
6
|
+
import { FieldProps, UiSchema } from "./types";
|
|
6
7
|
export declare const isObject: typeof _isObject;
|
|
7
8
|
export declare function isHidden(uiSchema: UiSchema, property: string): boolean;
|
|
8
9
|
export declare function isDefaultData(formData: any, schema: any): boolean;
|
|
@@ -18,8 +19,8 @@ export declare function propertyHasData(field: string, container: any): boolean;
|
|
|
18
19
|
export declare function getUpdateObjectFromJSONPath(path: string, injection: any): any;
|
|
19
20
|
export declare function getUpdateObjectFromJSONPointer(path: string, injection: any): any;
|
|
20
21
|
export declare function immutableDelete(_obj: any, _delProp: string): any;
|
|
21
|
-
export declare function getUiOptions(container
|
|
22
|
-
export declare function getInnerUiSchema(parentUiSchema
|
|
22
|
+
export declare function getUiOptions(container?: UiSchema): any;
|
|
23
|
+
export declare function getInnerUiSchema(parentUiSchema?: UiSchema): UiSchema;
|
|
23
24
|
export declare function isNullOrUndefined(val: any): boolean;
|
|
24
25
|
export declare function isEmptyString(val: any): boolean;
|
|
25
26
|
export declare function parseJSONPointer(object: any, jsonPointer: string, safeMode?: true | "createParents", strictEmptyPath?: boolean): any;
|
|
@@ -64,8 +65,8 @@ export declare const filterItemIdsDeeply: (item: any, context: FormContext, idSc
|
|
|
64
65
|
export declare const formDataIsEmpty: (props: FieldProps, context: FormContext) => any;
|
|
65
66
|
export declare const formDataEquals: (f1: any, f2: any, context: FormContext, id: string) => any;
|
|
66
67
|
export declare const keyboardClick: (fn: (e: KeyboardEvent | React.KeyboardEvent) => void, context: FormContext) => (e: KeyboardEvent | React.KeyboardEvent) => void;
|
|
67
|
-
export declare function getNestedTailUiSchema(uiSchema: UiSchema): UiSchema
|
|
68
|
-
export declare function updateTailUiSchema(uiSchema: UiSchema, updateObject: UpdateObject<any, any>): UiSchema
|
|
68
|
+
export declare function getNestedTailUiSchema(uiSchema: UiSchema): UiSchema;
|
|
69
|
+
export declare function updateTailUiSchema(uiSchema: UiSchema, updateObject: UpdateObject<any, any>): UiSchema;
|
|
69
70
|
export declare function getNestedUiFieldsList(uiSchema: UiSchema): any[];
|
|
70
71
|
declare type BootstrapColumns = {
|
|
71
72
|
lg: number;
|
|
@@ -120,7 +121,7 @@ export declare function schemaJSONPointer(schema: RJSFSchema, JSONPointer: strin
|
|
|
120
121
|
export declare function uiSchemaJSONPointer(schema: RJSFSchema, JSONPointer: string): string | undefined;
|
|
121
122
|
export declare function updateFormDataWithJSONPointer(schemaProps: Pick<FieldProps, "formData" | "registry" | "schema">, value: any, path: string): any;
|
|
122
123
|
export declare const assignUUID: (item: any, immutably?: boolean) => any;
|
|
123
|
-
export declare const getUUID: (item
|
|
124
|
+
export declare const getUUID: (item?: any) => number;
|
|
124
125
|
/**
|
|
125
126
|
* Return item UUID or the parent UUID
|
|
126
127
|
**/
|
|
@@ -164,4 +165,9 @@ export declare const classNames: (...cs: any[]) => string;
|
|
|
164
165
|
export declare function translate(translations: ByLang, key: string, params?: {
|
|
165
166
|
[key: string]: string | undefined;
|
|
166
167
|
}): string;
|
|
168
|
+
/**
|
|
169
|
+
* @param value the default value of the setter
|
|
170
|
+
* @returns [stateValue, setTrue, setFalse]
|
|
171
|
+
*/
|
|
172
|
+
export declare function useBooleanSetter(value: boolean): [boolean, () => void, () => void];
|
|
167
173
|
export {};
|