@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.
Files changed (41) hide show
  1. package/dist/laji-form.js +1 -1
  2. package/dist/styles.css +96 -5
  3. package/lib/ApiClient.d.ts +2 -1
  4. package/lib/components/BaseComponent.d.ts +1 -1
  5. package/lib/components/LajiForm.d.ts +3 -13
  6. package/lib/components/VirtualSchemaField.d.ts +10 -10
  7. package/lib/components/fields/AsArrayField.d.ts +131 -7
  8. package/lib/components/fields/ExtraLabelRowField.d.ts +1 -1
  9. package/lib/components/fields/ImageArrayField.d.ts +12 -12
  10. package/lib/components/fields/InitiallyHiddenField.d.ts +1 -1
  11. package/lib/components/fields/LocationChooserField.d.ts +1 -1
  12. package/lib/components/fields/MultiTagArrayField.d.ts +2 -2
  13. package/lib/components/fields/MultiTagArrayField.js +2 -1
  14. package/lib/components/fields/NamedPlaceChooserField.d.ts +88 -2
  15. package/lib/components/fields/NamedPlaceChooserField.js +1 -1
  16. package/lib/components/fields/NamedPlaceSaverField.d.ts +44 -1
  17. package/lib/components/fields/PdfArrayField.d.ts +2 -2
  18. package/lib/components/fields/ScopeField.d.ts +1 -1
  19. package/lib/components/fields/SingleActiveArrayField.js +1 -1
  20. package/lib/components/fields/SortArrayField.d.ts +93 -6
  21. package/lib/components/fields/SortArrayField.js +1 -1
  22. package/lib/components/fields/SplitField.d.ts +1 -1
  23. package/lib/components/fields/SplitField.js +3 -2
  24. package/lib/components/fields/StringToArrayField.d.ts +44 -1
  25. package/lib/components/fields/TagArrayField.js +1 -1
  26. package/lib/components/fields/ToggleAdditionalArrayFieldsField.d.ts +1 -1
  27. package/lib/components/fields/UnitListShorthandArrayField.d.ts +44 -1
  28. package/lib/components/widgets/AutosuggestWidget.js +1 -1
  29. package/lib/components/widgets/CheckboxWidget.js +7 -6
  30. package/lib/components/widgets/SelectWidget.d.ts +13 -52
  31. package/lib/components/widgets/SelectWidget.js +234 -145
  32. package/lib/services/focus-service.js +3 -2
  33. package/lib/services/settings-service.d.ts +2 -2
  34. package/lib/services/submit-hook-service.d.ts +1 -1
  35. package/lib/themes/theme.d.ts +4 -7
  36. package/lib/types.d.ts +59 -0
  37. package/lib/types.js +11 -0
  38. package/lib/utils.d.ts +13 -7
  39. package/lib/utils.js +19 -7
  40. package/package.json +3 -3
  41. 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
- const PropTypes = require("prop-types");
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
- class SelectWidget extends React.Component {
12
- constructor(props) {
13
- super(props);
14
- this.multiSelectOnChange = (values) => {
15
- const lengthBeforeFiltering = values.length;
16
- values = values.filter(v => v.value !== "");
17
- if (this.props.value.length === lengthBeforeFiltering) {
18
- return;
19
- }
20
- this.props.onChange(values.map(({ value }) => this.getEnum(value)));
21
- };
22
- this.selectOnChange = (item) => {
23
- this.props.onChange(this.getEnum(item.value));
24
- };
25
- this.onClick = () => {
26
- !this.props.disabled && !this.props.readonly && this.setState({ open: true });
27
- };
28
- this.onFocus = () => this.setState({ open: true });
29
- this.onBlur = () => this.setState({ open: false });
30
- this.onSelect = (item) => {
31
- this.state.open && this.props.formContext.setTimeout(() => this.mounted && this.setState({ open: false, value: item.value }));
32
- const value = this.getEnum(item.value);
33
- (!this.state.value || value !== this.state.value.value) && this.props.onChange(value);
34
- };
35
- // Quelch a warning from react-widgets with noop handler.
36
- this.onToggle = () => { };
37
- this.onKeyDown = (e) => {
38
- if (e.key !== "Tab") {
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
- getEnumOptions(props) {
63
- return utils_1.getUiOptions(props.uiSchema).enumOptions || props.options.enumOptions;
36
+ else {
37
+ return emptyIdx !== -1
38
+ ? enums.map(e => e.value === "" ? { value: undefined, label: "" } : e)
39
+ : [{ value: undefined, label: "" }, ...enums];
64
40
  }
65
- getStateFromProps(props) {
66
- let { multiple, value } = props;
67
- let enumOptions = this.getEnumOptions(props);
68
- function sort(enumOptions, order) {
69
- if (!Array.isArray(order))
70
- return enumOptions;
71
- const idxs = order.reduce((idxs, _enum, i) => {
72
- idxs[_enum] = i;
73
- return idxs;
74
- }, {});
75
- return enumOptions.slice(0).sort((a, b) => {
76
- return idxs[a.value] - idxs[b.value];
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
- const { filter: _filter, filterType, labels, order } = utils_1.getUiOptions(props);
80
- if (_filter) {
81
- enumOptions = utils_1.filter(enumOptions, _filter, filterType, item => item.value);
94
+ if (activeIdx !== undefined && displayedEnums[activeIdx]) {
95
+ onItemSelected(displayedEnums[activeIdx]);
82
96
  }
83
- if (labels) {
84
- enumOptions = enumOptions.map(({ value, label }) => {
85
- return { value, label: value in labels ? labels[value] : label };
86
- });
97
+ else {
98
+ setInputValue("");
87
99
  }
88
- if (enumOptions.every(({ value: _value }) => value !== _value)) {
89
- const _enum = this.getEnumOptions(props).find(({ value: _value }) => value === _value);
90
- if (_enum) {
91
- enumOptions.push(_enum);
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
- if (order)
95
- enumOptions = sort(enumOptions, order);
96
- const valsToItems = enumOptions.reduce((map, item) => {
97
- map[item.value] = item;
98
- return map;
99
- }, {});
100
- return {
101
- valsToItems,
102
- enumOptions,
103
- value: multiple ? value : valsToItems[value]
104
- };
105
- }
106
- render() {
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
- SelectWidget.contextType = ReactContext_1.default;
135
- SelectWidget.defaultProps = {
136
- autofocus: false,
137
- };
138
- SelectWidget.propTypes = {
139
- schema: PropTypes.shape({
140
- type: PropTypes.oneOf(["string", "array"])
141
- }),
142
- id: PropTypes.string.isRequired,
143
- uiSchema: PropTypes.shape({
144
- "ui:options": PropTypes.shape({
145
- enumOptions: PropTypes.array,
146
- order: PropTypes.array,
147
- filter: PropTypes.array,
148
- filterType: PropTypes.string,
149
- labels: PropTypes.object,
150
- })
151
- }),
152
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
153
- required: PropTypes.bool,
154
- multiple: PropTypes.bool,
155
- autofocus: PropTypes.bool,
156
- onChange: PropTypes.func,
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
- exports.default = SelectWidget;
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 can't doesn't have ref to the form");
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 "../components/LajiForm";
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;
@@ -1,4 +1,4 @@
1
- import { FieldProps, WidgetProps } from "../components/LajiForm";
1
+ import { FieldProps, WidgetProps } from "../types";
2
2
  export interface SubmitHook {
3
3
  hook: () => void;
4
4
  promise: Promise<any>;
@@ -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 { UiSchema, RJSFSchema } from "@rjsf/utils";
5
- import { FormContext, Translations, FieldProps, ByLang } from "./components/LajiForm";
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: UiSchema): any;
22
- export declare function getInnerUiSchema(parentUiSchema: UiSchema): any;
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<any, RJSFSchema, any>;
68
- export declare function updateTailUiSchema(uiSchema: UiSchema, updateObject: UpdateObject<any, any>): UiSchema<any, RJSFSchema, any>;
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: any) => number;
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 {};