@luomus/laji-form 15.1.27 → 15.1.29

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/styles.css CHANGED
@@ -2077,7 +2077,7 @@ body .laji-form {
2077
2077
  border-radius: 2px;
2078
2078
  line-height: 12.5px;
2079
2079
  }
2080
- .laji-form .form-control:not(textarea), .laji-form .rw-widget-picker.rw-widget-container, .laji-form .rw-combobox > .rw-widget-container, .laji-form .autosuggest-wrapper:not(.laji-form-enum-range), .laji-form .rw-datetimepicker, .laji-form .tristate-buttons .btn {
2080
+ .laji-form .form-control:not(textarea), .laji-form .rw-widget-picker.rw-widget-container, .laji-form .rw-combobox > .rw-widget-container, .laji-form .rw-datetimepicker, .laji-form .tristate-buttons .btn {
2081
2081
  height: 25px;
2082
2082
  }
2083
2083
  .laji-form .form-control-feedback {
@@ -84,7 +84,10 @@ export interface FormContext {
84
84
  googleApiKey: string;
85
85
  notifier: Notifier;
86
86
  apiClient: ApiClient;
87
- Label: React.Component;
87
+ Label: React.ComponentType<{
88
+ label?: string;
89
+ id: string;
90
+ }>;
88
91
  formDataTransformers?: any[];
89
92
  _parentLajiFormId?: number;
90
93
  mediaMetadata?: MediaMetadata;
@@ -1,5 +1,9 @@
1
- export default class EnumRangeArrayField extends React.Component<any, any, any> {
2
- static propTypes: {
1
+ /// <reference types="react" />
2
+ import * as PropTypes from "prop-types";
3
+ import { FieldProps, JSONSchemaArray, JSONSchemaString } from "../../types";
4
+ declare function EnumRangeArrayField(props: FieldProps<JSONSchemaArray<JSONSchemaString>>): JSX.Element | null;
5
+ declare namespace EnumRangeArrayField {
6
+ var propTypes: {
3
7
  uiSchema: PropTypes.Requireable<PropTypes.InferProps<{
4
8
  "ui:options": PropTypes.Requireable<PropTypes.InferProps<{
5
9
  range: PropTypes.Requireable<string>;
@@ -10,18 +14,5 @@ export default class EnumRangeArrayField extends React.Component<any, any, any>
10
14
  }>>;
11
15
  formData: PropTypes.Requireable<any[]>;
12
16
  };
13
- static getName(): string;
14
- constructor(props: any);
15
- setRef: (elem: any) => void;
16
- autosuggestRef: any;
17
- onInputChange: ({ target: { value } }: {
18
- target: {
19
- value: any;
20
- };
21
- }, reason: any, callback: any) => any;
22
- onSuggestionSelected: (suggestion: any) => void;
23
- onUnsuggestedSelected: (value: any) => void;
24
- onChange: (formData: any, reason: any) => void;
25
17
  }
26
- import * as React from "react";
27
- import * as PropTypes from "prop-types";
18
+ export default EnumRangeArrayField;
@@ -1,89 +1,37 @@
1
1
  "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
7
10
  };
8
11
  Object.defineProperty(exports, "__esModule", { value: true });
9
12
  const React = require("react");
10
13
  const PropTypes = require("prop-types");
11
- const react_dom_1 = require("react-dom");
12
- const BaseComponent_1 = require("../BaseComponent");
13
14
  const utils_1 = require("../../utils");
14
- const AutosuggestWidget_1 = require("../widgets/AutosuggestWidget");
15
- const TagArrayField_1 = require("./TagArrayField");
16
- let EnumRangeArrayField = class EnumRangeArrayField extends React.Component {
17
- constructor(props) {
18
- super(props);
19
- this.setRef = (elem) => {
20
- this.autosuggestRef = elem;
21
- };
22
- this.onInputChange = ({ target: { value } }, reason, callback) => {
23
- this.setState({ value }, callback);
24
- if (reason === "click") {
25
- const tagComponent = this.autosuggestRef.autosuggestRef.inputElem;
26
- const tagComponentElem = react_dom_1.findDOMNode(tagComponent);
27
- const input = tagComponentElem.querySelector("input");
28
- if (input) {
29
- input.focus();
30
- }
31
- }
32
- return value;
33
- };
34
- this.onSuggestionSelected = (suggestion) => {
35
- this.setState({ value: "" }, () => {
36
- this.onChange([...(this.props.formData || []), suggestion.value], "suggestion selected");
37
- });
38
- };
39
- this.onUnsuggestedSelected = (value) => {
40
- this.setState({ value: "" }, () => {
41
- this.onChange([...(this.props.formData || []), value], "unsuggested selected");
42
- });
43
- };
44
- this.onChange = (formData, reason) => {
45
- function onlyUnique(value, index, self) {
46
- return self.indexOf(value) === index;
47
- }
48
- formData = formData.filter(onlyUnique);
49
- if (reason !== "remove" && reason !== "suggestion selected" && reason !== "unsuggested selected") {
50
- this.setState({ value: "" });
51
- return;
52
- }
53
- this.setState({ value: "" }, () => {
54
- this.props.onChange(formData);
55
- });
56
- };
57
- this.state = { value: "" };
58
- }
59
- static getName() { return "EnumRangeArrayField"; }
60
- render() {
61
- const { range } = utils_1.getUiOptions(this.props.uiSchema);
62
- const autosuggestOptions = {
63
- autosuggestField: range,
64
- onSuggestionSelected: this.onSuggestionSelected,
65
- onConfirmUnsuggested: this.onConfirmUnsuggested,
66
- id: this.props.idSchema.$id,
67
- value: this.state.value,
68
- controlledValue: true,
69
- minFetchLength: 0,
70
- wrapperClassName: "laji-form-enum-range",
71
- inputProps: {
72
- value: this.state.value,
73
- that: this,
74
- InputComponent: EnumRangeInputInjection,
75
- onChange: this.onInputChange,
76
- tags: this.props.formData,
77
- id: this.props.idSchema.$id
78
- },
79
- allowNonsuggestedValue: false
80
- };
81
- const { Label } = this.props.formContext;
82
- return (React.createElement(React.Fragment, null,
83
- React.createElement(Label, { label: this.props.schema.title, id: this.props.idSchema.$id }),
84
- React.createElement(AutosuggestWidget_1.Autosuggest, Object.assign({}, this.props, { onChange: undefined }, autosuggestOptions, { ref: this.setRef }))));
85
- }
86
- };
15
+ const react_1 = require("react");
16
+ const SelectWidget_1 = require("../widgets/SelectWidget");
17
+ const options = {};
18
+ const schema = { type: "array", items: { type: "string" } };
19
+ function EnumRangeArrayField(props) {
20
+ const { onChange: propsOnChange } = props;
21
+ const { range } = utils_1.getUiOptions(props.uiSchema);
22
+ const onChange = react_1.useCallback((value) => {
23
+ propsOnChange(value);
24
+ }, [propsOnChange]);
25
+ const getEnumOptionsAsync = react_1.useCallback(() => __awaiter(this, void 0, void 0, function* () {
26
+ const enums = yield props.formContext.apiClient.fetchCached(`/metadata/ranges/${range}`);
27
+ return enums.map(({ value }) => ({ value, label: value }));
28
+ }), [props.formContext.apiClient, range]);
29
+ const { Label } = props.formContext;
30
+ return React.createElement(React.Fragment, null,
31
+ React.createElement(Label, { label: props.schema.title, id: props.idSchema.$id }),
32
+ React.createElement(SelectWidget_1.default, { getEnumOptionsAsync: getEnumOptionsAsync, schema: schema, onChange: onChange, value: props.formData, options: options }));
33
+ }
34
+ exports.default = EnumRangeArrayField;
87
35
  EnumRangeArrayField.propTypes = {
88
36
  uiSchema: PropTypes.shape({
89
37
  "ui:options": PropTypes.shape({
@@ -95,21 +43,3 @@ EnumRangeArrayField.propTypes = {
95
43
  }).isRequired,
96
44
  formData: PropTypes.array
97
45
  };
98
- EnumRangeArrayField = __decorate([
99
- BaseComponent_1.default
100
- ], EnumRangeArrayField);
101
- exports.default = EnumRangeArrayField;
102
- class EnumRangeInputInjection extends React.Component {
103
- constructor() {
104
- super(...arguments);
105
- this.onInputChange = e => {
106
- this.props.onChange(e);
107
- };
108
- this.onChange = (tags, reason) => {
109
- this.props.that.onChange(tags, reason);
110
- };
111
- }
112
- render() {
113
- return React.createElement(TagArrayField_1.TagInputComponent, Object.assign({}, this.props, { formContext: this.props.that.props.formContext, onChange: this.onChange, onInputChange: this.onInputChange }));
114
- }
115
- }
@@ -46,12 +46,6 @@ class CheckboxWidget extends React.Component {
46
46
  this.onGroupKeyDown = this.props.formContext.utils.keyboardClick((e) => {
47
47
  this.getToggleMode(this.props) && this.toggle(e);
48
48
  }, [" "]);
49
- // onTrueKeyDown = this.props.formContext.utils.keyboardClick(() => {
50
- // if (this.props.disabled || this.props.readonly) {
51
- // return;
52
- // }
53
- // this.onChange(true);
54
- // }, [" "]);
55
49
  this.onTrueKeyDown = (e) => {
56
50
  const { key } = e;
57
51
  if (key === " ") {
@@ -1,13 +1,21 @@
1
1
  /// <reference types="react" />
2
+ import { EnumOptionsType as _EnumOptionsType } from "@rjsf/utils";
2
3
  import { JSONSchemaArray, JSONSchemaEnum, JSONSchemaEnumOneOf, WidgetProps } from "../../types";
4
+ declare type EnumOptionsType<T = string | undefined> = Omit<_EnumOptionsType, "value"> & {
5
+ value: T;
6
+ };
7
+ declare type SelectWidgetCustomProps = {
8
+ includeEmpty?: boolean;
9
+ getEnumOptionsAsync?: () => Promise<EnumOptionsType<string>[]>;
10
+ };
3
11
  declare type SingleSelectWidgetProps = Omit<WidgetProps<JSONSchemaEnum>, "value" | "onChange"> & {
4
12
  value?: string;
5
13
  onChange: (value?: string) => void;
6
- };
14
+ } & SelectWidgetCustomProps;
7
15
  declare type MultiSelectWidgetProps = Omit<WidgetProps<JSONSchemaArray<JSONSchemaEnumOneOf>>, "value" | "onChange"> & {
8
16
  value?: string[];
9
17
  onChange: (value?: string[]) => void;
10
- };
18
+ } & SelectWidgetCustomProps;
11
19
  declare type SelectWidgetProps = SingleSelectWidgetProps | MultiSelectWidgetProps;
12
20
  export default function SelectWidget(props: SelectWidgetProps): JSX.Element | null;
13
21
  export {};
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  const React = require("react");
4
13
  // import * as PropTypes from "prop-types";
@@ -6,8 +15,9 @@ const ReactContext_1 = require("../../ReactContext");
6
15
  const utils_1 = require("../../utils");
7
16
  const react_1 = require("react");
8
17
  const react_dom_1 = require("react-dom");
18
+ const Spinner = require("react-spinner");
9
19
  const useRangeIncrementor = (length, defaultIdx) => {
10
- const [idx, _setIdx] = React.useState(defaultIdx);
20
+ const [idx, _setIdx] = react_1.useState(defaultIdx);
11
21
  const setIdx = react_1.useCallback((idx) => {
12
22
  let nextIdx = idx;
13
23
  if (idx === undefined || idx < 0 || length === 0) {
@@ -40,7 +50,6 @@ function getEnumOptions(enumOptions, uiSchema, includeEmpty = true) {
40
50
  }
41
51
  }
42
52
  function SelectWidget(props) {
43
- // export default function SelectWidget(props: SelectWidgetProps): Widget<JSONSchemaEnum | JSONSchemaArray<JSONSchemaEnumOneOf>> {
44
53
  return props.schema.type === "array" ? React.createElement(SearchableMultiDrowndown, Object.assign({}, props)) : React.createElement(SearchableDrowndown, Object.assign({}, props));
45
54
  }
46
55
  exports.default = SelectWidget;
@@ -53,12 +62,12 @@ function SearchableDrowndown(props) {
53
62
  const enumOptions = React.useMemo(() =>
54
63
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
55
64
  getEnumOptions(options.enumOptions, uiSchema, includeEmpty), [options.enumOptions, uiSchema, includeEmpty]);
56
- const [inputValue, setInputValue] = React.useState(value
65
+ const [inputValue, setInputValue] = react_1.useState(value
57
66
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
58
67
  ? enumOptions.find(item => item.value === value).label
59
68
  : "");
60
- const [inputTouched, setInputTouched] = React.useState(false);
61
- const [filterTerm, setFilterTerm] = React.useState("");
69
+ const [inputTouched, setInputTouched] = react_1.useState(false);
70
+ const [filterTerm, setFilterTerm] = react_1.useState("");
62
71
  const onInputChange = react_1.useCallback((e) => {
63
72
  const { value } = e.target;
64
73
  setInputValue(value);
@@ -74,9 +83,7 @@ function SearchableDrowndown(props) {
74
83
  }, [filterTerm, enumOptions]);
75
84
  const [isOpen, show, hide] = utils_1.useBooleanSetter(false);
76
85
  const { FormControl } = theme;
77
- const [activeIdx, activeIdxUp, activeIdxDown, setActiveIdx] = useRangeIncrementor((displayedEnums || []).length, value !== undefined && value !== ""
78
- ? displayedEnums.findIndex(item => item.value === value)
79
- : 0);
86
+ const [activeIdx, activeIdxUp, activeIdxDown, setActiveIdx] = useRangeIncrementor((displayedEnums || []).length, getDefaultActiveIdx(displayedEnums, value));
80
87
  const onItemSelected = react_1.useCallback((item) => {
81
88
  onChange(item.value);
82
89
  setInputValue(item.label);
@@ -113,8 +120,13 @@ function SearchableDrowndown(props) {
113
120
  activeIdx !== undefined && displayedEnums && onItemSelected(displayedEnums[activeIdx]);
114
121
  e.preventDefault();
115
122
  break;
123
+ case "Escape":
124
+ setInputValue("");
125
+ setActiveIdx(getDefaultActiveIdx(displayedEnums, value));
126
+ e.preventDefault();
127
+ break;
116
128
  }
117
- }, [activeIdx, activeIdxDown, activeIdxUp, displayedEnums, onItemSelected]);
129
+ }, [activeIdx, activeIdxDown, activeIdxUp, displayedEnums, onItemSelected, setActiveIdx, value]);
118
130
  const onFocus = react_1.useCallback(() => {
119
131
  var _a;
120
132
  show();
@@ -129,12 +141,21 @@ function SearchableDrowndown(props) {
129
141
  }))));
130
142
  }
131
143
  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("");
144
+ const { id, disabled, readonly, value, uiSchema, options, onChange, getEnumOptionsAsync } = props;
145
+ // const enumOptions = React.useMemo(() =>
146
+ // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
147
+ // getEnumOptions(options.enumOptions!, uiSchema, false),
148
+ // [options.enumOptions, uiSchema]);
149
+ const [enumOptions, setEnumOptions] = react_1.useState(getEnumOptionsAsync
150
+ ? undefined
151
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
152
+ : getEnumOptions(options.enumOptions, uiSchema, false));
153
+ const [inputValue, setInputValue] = react_1.useState("");
154
+ const [filterTerm, setFilterTerm] = react_1.useState("");
155
+ const [loading, setLoading] = react_1.useState(undefined);
156
+ const [isOpen, show, hide] = utils_1.useBooleanSetter(false);
157
+ const containerRef = React.useRef(null);
158
+ const inputRef = React.useRef(null);
138
159
  const onInputChange = react_1.useCallback((e) => {
139
160
  const { value } = e.target;
140
161
  setInputValue(value);
@@ -143,6 +164,9 @@ function SearchableMultiDrowndown(props) {
143
164
  setFilterTerm(inputValue);
144
165
  }, [inputValue]);
145
166
  const displayedEnums = React.useMemo(() => {
167
+ if (!enumOptions) {
168
+ return [];
169
+ }
146
170
  const notAlreadySelected = (value === null || value === void 0 ? void 0 : value.length)
147
171
  ? enumOptions.filter(({ value: enumValue }) => !value.includes(enumValue))
148
172
  : enumOptions;
@@ -151,9 +175,6 @@ function SearchableMultiDrowndown(props) {
151
175
  || label.toLowerCase().match(filterTerm.toLowerCase()))
152
176
  : notAlreadySelected;
153
177
  }, [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
178
  const [activeIdx, activeIdxUp, activeIdxDown, setActiveIdx] = useRangeIncrementor((displayedEnums || []).length, undefined);
158
179
  const onItemSelected = react_1.useCallback((item) => {
159
180
  var _a;
@@ -167,6 +188,48 @@ function SearchableMultiDrowndown(props) {
167
188
  setInputValue("");
168
189
  setActiveIdx(undefined);
169
190
  }, [onChange, setActiveIdx, value]);
191
+ const [isFocused, setFocused, setBlurred] = utils_1.useBooleanSetter(false);
192
+ const loadEnums = react_1.useCallback(() => {
193
+ const asyncOp = () => __awaiter(this, void 0, void 0, function* () {
194
+ try {
195
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
196
+ const enums = yield getEnumOptionsAsync();
197
+ setEnumOptions(enums);
198
+ }
199
+ finally {
200
+ setLoading(false);
201
+ }
202
+ });
203
+ setLoading(true);
204
+ void asyncOp();
205
+ }, [getEnumOptionsAsync]);
206
+ const prevEnumOptions = utils_1.usePrevious(enumOptions);
207
+ // If the enums are async loaded, this effect takes care of opening the
208
+ // dropdown once the enums are loaded, if the input if still focused.
209
+ react_1.useEffect(() => {
210
+ if (!getEnumOptionsAsync) {
211
+ return;
212
+ }
213
+ if (isFocused && !(prevEnumOptions === null || prevEnumOptions === void 0 ? void 0 : prevEnumOptions.length) && (enumOptions === null || enumOptions === void 0 ? void 0 : enumOptions.length)) {
214
+ show();
215
+ }
216
+ }, [prevEnumOptions, enumOptions, isFocused, show, getEnumOptionsAsync]);
217
+ // If there is a pre-existing value (or a value is updated from parent after component is rendered) and we are async,
218
+ // load the enums.
219
+ react_1.useEffect(() => {
220
+ if ((value === null || value === void 0 ? void 0 : value.length) && getEnumOptionsAsync && !enumOptions && !loading) {
221
+ loadEnums();
222
+ }
223
+ }, [enumOptions, getEnumOptionsAsync, loadEnums, loading, value === null || value === void 0 ? void 0 : value.length]);
224
+ const onFocus = react_1.useCallback(() => {
225
+ setFocused();
226
+ if (!(enumOptions === null || enumOptions === void 0 ? void 0 : enumOptions.length) && getEnumOptionsAsync) {
227
+ void loadEnums();
228
+ }
229
+ else {
230
+ show();
231
+ }
232
+ }, [enumOptions === null || enumOptions === void 0 ? void 0 : enumOptions.length, getEnumOptionsAsync, loadEnums, setFocused, show]);
170
233
  const onBlur = react_1.useCallback((e) => {
171
234
  // Fixes the problem when user tries to click an enum item, `setOpen(false)`
172
235
  // hides the enum list, so the elem list item is hidden before the click, thus never
@@ -174,6 +237,7 @@ function SearchableMultiDrowndown(props) {
174
237
  if (e.relatedTarget && utils_1.isDescendant(containerRef.current, e.relatedTarget)) {
175
238
  return;
176
239
  }
240
+ setBlurred();
177
241
  hide();
178
242
  if (activeIdx !== undefined && displayedEnums[activeIdx]) {
179
243
  onItemSelectedByBlur(displayedEnums[activeIdx]);
@@ -181,7 +245,7 @@ function SearchableMultiDrowndown(props) {
181
245
  else {
182
246
  setInputValue("");
183
247
  }
184
- }, [activeIdx, displayedEnums, hide, onItemSelectedByBlur]);
248
+ }, [activeIdx, displayedEnums, hide, onItemSelectedByBlur, setBlurred]);
185
249
  const onKeyDown = react_1.useCallback((e) => {
186
250
  switch (e.key) {
187
251
  case "ArrowDown":
@@ -196,6 +260,11 @@ function SearchableMultiDrowndown(props) {
196
260
  activeIdx !== undefined && displayedEnums && onItemSelected(displayedEnums[activeIdx]);
197
261
  e.preventDefault();
198
262
  break;
263
+ case "Escape":
264
+ setInputValue("");
265
+ setActiveIdx(undefined);
266
+ e.preventDefault();
267
+ break;
199
268
  case "Backspace":
200
269
  if (inputValue === "" && (value === null || value === void 0 ? void 0 : value.length)) {
201
270
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -204,7 +273,7 @@ function SearchableMultiDrowndown(props) {
204
273
  }
205
274
  break;
206
275
  }
207
- }, [activeIdx, activeIdxDown, activeIdxUp, displayedEnums, inputValue, onChange, onItemSelected, value]);
276
+ }, [activeIdx, activeIdxDown, activeIdxUp, displayedEnums, inputValue, onChange, onItemSelected, setActiveIdx, value]);
208
277
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
209
278
  const onDelete = react_1.useCallback((enu) => {
210
279
  const filtered = value.filter(v => v !== enu.value);
@@ -219,13 +288,14 @@ function SearchableMultiDrowndown(props) {
219
288
  }
220
289
  (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
221
290
  }, [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");
291
+ const wrapperClassNames = utils_1.classNames("laji-form-multiselect-input-wrapper", isOpen && "laji-form-multiselect-input-wrapper-focus", isOpen && "input-highlight", (readonly || disabled) && "laji-form-multiselect-input-wrapper-readonly");
223
292
  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 }),
293
+ React.createElement("div", { className: wrapperClassNames, tabIndex: -1, onFocus: redirectFocusToInput, style: { cursor: "text" } },
294
+ React.createElement("ul", { style: { listStyle: "none", display: "inline-block" } }, value && enumOptions && value.map(v => enumOptions.find(({ value: _value }) => v === _value) || ({ value: v, label: v }))
295
+ .map(enu => React.createElement(SelectedMultiValue, { key: enu.value, onDelete: onDelete, readonly: readonly || disabled }, enu))),
296
+ React.createElement("input", { disabled: disabled || readonly, id: id, onFocus: onFocus, value: inputValue, onChange: onInputChange, autoComplete: "off", ref: inputRef }),
297
+ loading && React.createElement(Spinner, null)),
298
+ React.createElement(Caret, { onFocus: onFocus }),
229
299
  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
300
  var _a;
231
301
  return (React.createElement(ListItem, { key: (_a = oneOf.value) !== null && _a !== void 0 ? _a : "", onSelected: onItemSelected, active: idx === activeIdx }, oneOf));
@@ -245,3 +315,6 @@ function ListItem({ onSelected, active, children }) {
245
315
  }, [children, onSelected]);
246
316
  return (React.createElement("div", { onClick: onClick, className: utils_1.classNames("laji-form-dropdown-item", active && "active"), tabIndex: -1 }, children.label));
247
317
  }
318
+ const getDefaultActiveIdx = (displayedEnums, value) => value !== undefined && value !== ""
319
+ ? displayedEnums.findIndex(item => item.value === value)
320
+ : 0;
package/lib/utils.d.ts CHANGED
@@ -170,4 +170,5 @@ export declare function translate(translations: ByLang, key: string, params?: {
170
170
  * @returns [stateValue, setTrue, setFalse]
171
171
  */
172
172
  export declare function useBooleanSetter(value: boolean): [boolean, () => void, () => void];
173
+ export declare function usePrevious<T>(value: T): T | undefined;
173
174
  export {};
package/lib/utils.js CHANGED
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.bsSizeToPixels = exports.canAdd = exports.stringifyKeyCombo = exports.decapitalizeFirstLetter = exports.capitalizeFirstLetter = exports.getKeyHandlerTargetId = exports.isDescendant = exports.getBootstrapCols = exports.getNestedUiFieldsList = exports.updateTailUiSchema = exports.getNestedTailUiSchema = exports.keyboardClick = exports.formDataEquals = exports.formDataIsEmpty = exports.filterItemIdsDeeply = exports.filterItemId = exports.filterLajiFormId = exports.syncScroll = exports._syncScroll = exports.shouldSyncScroll = exports.focusAndScroll = exports.focusById = exports.getSchemaElementById = exports.findNearestParentSchemaElemId = exports.focusNextInput = exports.getNextInput = exports.getNextInputInInputs = exports.ReactUtils = exports.findNearestParentTabbableElem = exports.findNearestParentSchemaElem = exports.canFocusNextInput = exports.isTabbableInput = exports.getTabbableFields = exports.isSelect = exports.isMultiSelect = exports.getReactComponentName = exports.parseJSONPointer = exports.isEmptyString = exports.isNullOrUndefined = exports.getInnerUiSchema = exports.getUiOptions = exports.immutableDelete = exports.getUpdateObjectFromJSONPointer = exports.getUpdateObjectFromJSONPath = exports.propertyHasData = exports.hasData = exports.getDefaultFormState = exports.isDefaultData = exports.isHidden = exports.isObject = void 0;
15
- exports.useBooleanSetter = exports.translate = exports.classNames = exports.getTitle = exports.toJSONPointer = exports.getReversedFormDataIndex = exports.getFormDataIndex = exports.getIdxWithoutOffset = exports.getIdxWithOffset = exports.constructTranslations = exports.filteredErrors = exports.highlightElem = exports.findPointerForLajiFormId = exports.removeLajiFormIds = exports.getAllLajiFormIdsDeeply = exports.addLajiFormIds = exports.getFieldUUID = exports.getUUID = exports.assignUUID = exports.updateFormDataWithJSONPointer = exports.uiSchemaJSONPointer = exports.schemaJSONPointer = exports.idSchemaIdToJSONPointer = exports.JSONPointerToId = exports.checkJSONPointer = exports.parseUiSchemaFromFormDataPointer = exports.parseSchemaFromFormDataPointer = exports.triggerParentComponent = exports.bringRemoteFormData = exports.checkArrayRules = exports.checkRules = exports.formatErrorMessage = exports.formatValue = exports.dictionarify = exports.injectButtons = exports.updateSafelyWithJSONPointer = exports.updateSafelyWithJSONPath = exports.filter = exports.scrollIntoViewIfNeeded = exports.getScrollPositionForScrollIntoViewIfNeeded = exports.getWindowScrolled = exports.applyFunction = exports.pixelsToBsSize = void 0;
15
+ exports.usePrevious = exports.useBooleanSetter = exports.translate = exports.classNames = exports.getTitle = exports.toJSONPointer = exports.getReversedFormDataIndex = exports.getFormDataIndex = exports.getIdxWithoutOffset = exports.getIdxWithOffset = exports.constructTranslations = exports.filteredErrors = exports.highlightElem = exports.findPointerForLajiFormId = exports.removeLajiFormIds = exports.getAllLajiFormIdsDeeply = exports.addLajiFormIds = exports.getFieldUUID = exports.getUUID = exports.assignUUID = exports.updateFormDataWithJSONPointer = exports.uiSchemaJSONPointer = exports.schemaJSONPointer = exports.idSchemaIdToJSONPointer = exports.JSONPointerToId = exports.checkJSONPointer = exports.parseUiSchemaFromFormDataPointer = exports.parseSchemaFromFormDataPointer = exports.triggerParentComponent = exports.bringRemoteFormData = exports.checkArrayRules = exports.checkRules = exports.formatErrorMessage = exports.formatValue = exports.dictionarify = exports.injectButtons = exports.updateSafelyWithJSONPointer = exports.updateSafelyWithJSONPath = exports.filter = exports.scrollIntoViewIfNeeded = exports.getScrollPositionForScrollIntoViewIfNeeded = exports.getWindowScrolled = exports.applyFunction = exports.pixelsToBsSize = void 0;
16
16
  const React = require("react");
17
17
  const react_dom_1 = require("react-dom");
18
18
  const utils_1 = require("@rjsf/utils");
@@ -1195,3 +1195,11 @@ function useBooleanSetter(value) {
1195
1195
  return [open, setTrue, setFalse];
1196
1196
  }
1197
1197
  exports.useBooleanSetter = useBooleanSetter;
1198
+ function usePrevious(value) {
1199
+ const ref = React.useRef();
1200
+ React.useEffect(() => {
1201
+ ref.current = value;
1202
+ });
1203
+ return ref.current;
1204
+ }
1205
+ exports.usePrevious = usePrevious;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luomus/laji-form",
3
- "version": "15.1.27",
3
+ "version": "15.1.29",
4
4
  "description": "React module capable of building dynamic forms from Laji form json schemas",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",