@startlibs/form 1.1.3 → 1.2.0-rc.1

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 (112) hide show
  1. package/lib/AutoComplete.mjs +7 -7
  2. package/lib/AutoComplete.mjs.map +1 -1
  3. package/lib/Checkbox.mjs +4 -2
  4. package/lib/Checkbox.mjs.map +1 -1
  5. package/lib/Combobox.mjs +1 -1
  6. package/lib/Combobox.mjs.map +1 -1
  7. package/lib/DatePicker.mjs +25 -9
  8. package/lib/DatePicker.mjs.map +1 -1
  9. package/lib/Errors.mjs +20 -10
  10. package/lib/Errors.mjs.map +1 -1
  11. package/lib/ExpandableBox.mjs +1 -1
  12. package/lib/ExpandableBox.mjs.map +1 -1
  13. package/lib/Field.mjs +10 -5
  14. package/lib/Field.mjs.map +1 -1
  15. package/lib/FieldBox.mjs +3 -3
  16. package/lib/FieldBox.mjs.map +1 -1
  17. package/lib/InputboxGroup.mjs +1 -1
  18. package/lib/InputboxGroup.mjs.map +1 -1
  19. package/lib/RichText.mjs +11 -6
  20. package/lib/RichText.mjs.map +1 -1
  21. package/lib/TextInput.mjs +4 -4
  22. package/lib/TextInput.mjs.map +1 -1
  23. package/lib/alt/checkbox/SimpleCheckbox.mjs +1 -1
  24. package/lib/alt/checkbox/SimpleCheckbox.mjs.map +1 -1
  25. package/lib/alt/checkbox/ToggleCheckbox.mjs +4 -3
  26. package/lib/alt/checkbox/ToggleCheckbox.mjs.map +1 -1
  27. package/lib/alt/radiobox/CleanTabRadiobox.mjs +1 -1
  28. package/lib/alt/radiobox/CleanTabRadiobox.mjs.map +1 -1
  29. package/lib/alt/radiobox/SimpleRadiobox.mjs +2 -2
  30. package/lib/alt/radiobox/SimpleRadiobox.mjs.map +1 -1
  31. package/lib/alt/radiobox/TabRadiobox.mjs +1 -1
  32. package/lib/alt/radiobox/TabRadiobox.mjs.map +1 -1
  33. package/lib/index.cjs +94 -51
  34. package/lib/index.cjs.map +1 -1
  35. package/lib/index.mjs +2 -2
  36. package/lib/withFormImageInput.mjs +1 -1
  37. package/lib/withFormImageInput.mjs.map +1 -1
  38. package/lib-yak/AutoComplete.mjs +705 -0
  39. package/lib-yak/AutoComplete.mjs.map +1 -0
  40. package/lib-yak/Checkbox.mjs +80 -0
  41. package/lib-yak/Checkbox.mjs.map +1 -0
  42. package/lib-yak/Combobox.mjs +652 -0
  43. package/lib-yak/Combobox.mjs.map +1 -0
  44. package/lib-yak/ComboboxWithCustom.mjs +77 -0
  45. package/lib-yak/ComboboxWithCustom.mjs.map +1 -0
  46. package/lib-yak/DatePicker.mjs +774 -0
  47. package/lib-yak/DatePicker.mjs.map +1 -0
  48. package/lib-yak/EditableBox.mjs +495 -0
  49. package/lib-yak/EditableBox.mjs.map +1 -0
  50. package/lib-yak/Errors.mjs +226 -0
  51. package/lib-yak/Errors.mjs.map +1 -0
  52. package/lib-yak/ExpandableBox.mjs +247 -0
  53. package/lib-yak/ExpandableBox.mjs.map +1 -0
  54. package/lib-yak/Field.mjs +93 -0
  55. package/lib-yak/Field.mjs.map +1 -0
  56. package/lib-yak/FieldBox.mjs +173 -0
  57. package/lib-yak/FieldBox.mjs.map +1 -0
  58. package/lib-yak/Form.mjs +322 -0
  59. package/lib-yak/Form.mjs.map +1 -0
  60. package/lib-yak/FormValue.mjs +111 -0
  61. package/lib-yak/FormValue.mjs.map +1 -0
  62. package/lib-yak/InputboxGroup.mjs +146 -0
  63. package/lib-yak/InputboxGroup.mjs.map +1 -0
  64. package/lib-yak/Radiobox.mjs +69 -0
  65. package/lib-yak/Radiobox.mjs.map +1 -0
  66. package/lib-yak/RichText.mjs +776 -0
  67. package/lib-yak/RichText.mjs.map +1 -0
  68. package/lib-yak/TextInput.mjs +589 -0
  69. package/lib-yak/TextInput.mjs.map +1 -0
  70. package/lib-yak/alt/checkbox/SimpleCheckbox.mjs +225 -0
  71. package/lib-yak/alt/checkbox/SimpleCheckbox.mjs.map +1 -0
  72. package/lib-yak/alt/checkbox/ToggleCheckbox.mjs +173 -0
  73. package/lib-yak/alt/checkbox/ToggleCheckbox.mjs.map +1 -0
  74. package/lib-yak/alt/radiobox/CleanTabRadiobox.mjs +87 -0
  75. package/lib-yak/alt/radiobox/CleanTabRadiobox.mjs.map +1 -0
  76. package/lib-yak/alt/radiobox/IconRadioBox.mjs +138 -0
  77. package/lib-yak/alt/radiobox/IconRadioBox.mjs.map +1 -0
  78. package/lib-yak/alt/radiobox/SimpleRadiobox.mjs +203 -0
  79. package/lib-yak/alt/radiobox/SimpleRadiobox.mjs.map +1 -0
  80. package/lib-yak/alt/radiobox/TabRadiobox.mjs +117 -0
  81. package/lib-yak/alt/radiobox/TabRadiobox.mjs.map +1 -0
  82. package/lib-yak/enhanceInput.mjs +131 -0
  83. package/lib-yak/enhanceInput.mjs.map +1 -0
  84. package/lib-yak/index.mjs +28 -0
  85. package/lib-yak/index.mjs.map +1 -0
  86. package/lib-yak/useConfirmDialog.mjs +117 -0
  87. package/lib-yak/useConfirmDialog.mjs.map +1 -0
  88. package/lib-yak/useDraftConfirmation.mjs +56 -0
  89. package/lib-yak/useDraftConfirmation.mjs.map +1 -0
  90. package/lib-yak/validation.mjs +91 -0
  91. package/lib-yak/validation.mjs.map +1 -0
  92. package/lib-yak/withFormImageInput.mjs +298 -0
  93. package/lib-yak/withFormImageInput.mjs.map +1 -0
  94. package/package.json +13 -3
  95. package/src/AutoComplete.jsx +12 -12
  96. package/src/Checkbox.jsx +2 -2
  97. package/src/Combobox.jsx +1 -1
  98. package/src/DatePicker.jsx +25 -22
  99. package/src/Errors.jsx +18 -8
  100. package/src/ExpandableBox.jsx +3 -3
  101. package/src/Field.jsx +9 -4
  102. package/src/FieldBox.jsx +6 -6
  103. package/src/IconRadioBoxOldHubt.jsx +1 -1
  104. package/src/InputboxGroup.jsx +1 -1
  105. package/src/RichText.jsx +17 -13
  106. package/src/TextInput.jsx +37 -26
  107. package/src/alt/checkbox/SimpleCheckbox.jsx +5 -5
  108. package/src/alt/checkbox/ToggleCheckbox.jsx +9 -8
  109. package/src/alt/radiobox/CleanTabRadiobox.jsx +2 -2
  110. package/src/alt/radiobox/SimpleRadiobox.jsx +7 -7
  111. package/src/alt/radiobox/TabRadiobox.jsx +4 -4
  112. package/src/withFormImageInput.jsx +2 -2
@@ -0,0 +1,705 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import _extends from '@babel/runtime/helpers/extends';
3
+ import _objectWithoutProperties from '@babel/runtime/helpers/objectWithoutProperties';
4
+ import _isString from 'lodash/fp/isString';
5
+ import _filter from 'lodash/fp/filter';
6
+ import _concat from 'lodash/fp/concat';
7
+ import _set from 'lodash/fp/set';
8
+ import _flow from 'lodash/fp/flow';
9
+ import _without from 'lodash/fp/without';
10
+ import _isEqual from 'lodash/fp/isEqual';
11
+ import _last from 'lodash/fp/last';
12
+ import { yakDomTag } from '@startlibs/utils/yakDomTag';
13
+ import React, { useRef, useState, useEffect } from 'react';
14
+ import ContentEditableModule from 'react-contenteditable';
15
+ import { useToggle, useEnsureRef, useRefState } from '@startlibs/core';
16
+ import { Loading, Icon, ContextMenu, ListItem, Li } from '@startlibs/components';
17
+ import { Errors, ErrorsItem, ErrorsCloseIcon, useProvideErrors } from './Errors.mjs';
18
+ import { Field } from './Field.mjs';
19
+ import { useInput } from './enhanceInput.mjs';
20
+ import { getColor, callIfFunction, constrainEvent, _s, stopPropagation } from '@startlibs/utils';
21
+ import { styled, css } from '@yak/react';
22
+ import { darken } from 'polished';
23
+
24
+ const _excluded = ["CompletedBox", "isEditable", "getLabel", "cancelEditable", "value", "remove", "index"],
25
+ _excluded2 = ["value", "confirmKeys", "index", "EditableInput", "confirmIfNewKeys", "confirmIfNew", "confirm", "remove"];
26
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
27
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
28
+
29
+ // Node/esbuild interop em .mjs devolve module.exports; Rollup devolve o default. Cobre os dois.
30
+ const ContentEditable = ContentEditableModule.default || ContentEditableModule;
31
+ const ua = navigator.userAgent.toLowerCase();
32
+ const isSafari = ua.indexOf('safari') >= 0 && ua.indexOf('chrome') < 0;
33
+ const InputLoading = styled(Loading)`
34
+ bottom: 8px;
35
+ right: 0.6rem;
36
+ left: auto;
37
+ top: 50%;
38
+ transform: translate(-50%);
39
+ `;
40
+ const AutoCompleteInput = styled(yakDomTag("div")).attrs({
41
+ className: "styled-theme-text-input"
42
+ })`
43
+ width: 100%;
44
+ font-size: 14px;
45
+ border: 1px solid ${__yakProps => {
46
+ const v = getColor('gray210');
47
+ return typeof v === 'function' ? v(__yakProps) : v;
48
+ }};
49
+ border-radius: 8px;
50
+ color: ${__yakProps => {
51
+ const v = getColor('gray60');
52
+ return typeof v === 'function' ? v(__yakProps) : v;
53
+ }};
54
+ cursor: text;
55
+ background: white;
56
+ position: relative;
57
+ outline: 0;
58
+ outline: none;
59
+ min-height: 3rem;
60
+ line-height: 28px;
61
+ padding: 0.25rem 0.7rem;
62
+ display: flex;
63
+ align-items: center;
64
+ flex-wrap: wrap;
65
+ ${props => props.focused && css`
66
+ border-color: ${__yakProps => {
67
+ const v = getColor('gray180');
68
+ return typeof v === 'function' ? v(__yakProps) : v;
69
+ }};
70
+ box-shadow: 0px 0px 0px 2px rgba(0,0,0,0.075);
71
+ `}
72
+ ${props => props.hasErrors && css`
73
+ border-color: ${__yakProps => {
74
+ const v = getColor('alert');
75
+ return typeof v === 'function' ? v(__yakProps) : v;
76
+ }} !important;
77
+ `}
78
+ @media (max-width: 600px) {
79
+ padding: 0.25rem 1rem;
80
+ min-height: 42px;
81
+ }
82
+ ${props => props.withDropdown && css`
83
+ padding-right: 3rem;
84
+ @media (max-width: 600px) {
85
+ padding-right: 4rem;
86
+ }
87
+ `}
88
+
89
+ `;
90
+ const AutoCompletePlaceholder = styled(yakDomTag("span"))`
91
+ position: absolute;
92
+ top: 50%;
93
+ transform: translateY(-50%);
94
+ pointer-events: none;
95
+ color: rgba(0,0,0,0.3);
96
+ left: 0.7rem;
97
+ right: 0.7rem;
98
+ @media (max-width: 600px) {
99
+ left: 1rem;
100
+ right: 1rem;
101
+ }
102
+ `;
103
+ const AutoCompleteTextboxDiv = styled(ContentEditable)`
104
+ display: inline-block;
105
+ outline: 0;
106
+ outline: none;
107
+ padding: 0 1px;
108
+ line-height: 130%;
109
+ `;
110
+ const AddedBox = styled(yakDomTag("span"))`
111
+ background-color: rgb(230,230,230);
112
+ padding: 5px 2rem 5px 0.75rem;
113
+ border-radius: 12px;
114
+ font-size: 13px;
115
+ position: relative;
116
+ margin-left: -3px;
117
+ margin-right: 9px;
118
+ white-space: nowrap;
119
+ cursor: default;
120
+ line-height: normal;
121
+ max-width: 90%;
122
+ white-space: nowrap;
123
+ overflow: hidden;
124
+ text-overflow: ellipsis;
125
+ /* isSafari não depende de props; uma const de módulo com um css condicional (ternário)
126
+ não é um mixin válido pro yak ("not a valid css value or css mixin"). Em posição de
127
+ valor, uma arrow function comum (mesmo sem usar props) segue a mesma regra de qualquer
128
+ valor dinâmico (R3). */
129
+ vertical-align: ${() => isSafari ? '2px' : '-7px'};
130
+ `;
131
+ const RemoveIcon = styled(Icon)`
132
+ width: 20px;
133
+ height: 20px;
134
+ border-radius: 50%;
135
+ display: inline-block;
136
+ position: absolute;
137
+ top: 50%;
138
+ line-height: 20px;
139
+ transform: translateY(-50%);
140
+ right: 2px;
141
+ font-size: 14px;
142
+ text-align: center;
143
+ cursor: pointer;
144
+ color: ${__yakProps => {
145
+ const v = getColor('gray120');
146
+ return typeof v === 'function' ? v(__yakProps) : v;
147
+ }};
148
+ &:hover {
149
+ background-color: ${__yakProps => {
150
+ const v = getColor('gray210');
151
+ return typeof v === 'function' ? v(__yakProps) : v;
152
+ }};
153
+ color: ${props => darken(0.05, getColor('alert')(props))};
154
+ }
155
+ `;
156
+ const AutoCompleteMenu = styled(ContextMenu)`
157
+ box-shadow: 0 2px 3px 1px rgba(0,0,0,0.2),0 0px 0px 1px rgba(0,0,0,0.05);
158
+ max-height: 22rem;
159
+ overflow: auto;
160
+ ${ListItem} {
161
+ > * {
162
+ padding: 11px;
163
+ }
164
+ }
165
+ `;
166
+ const AutoCompleteError = styled(Errors)`
167
+ ${ErrorsItem} {
168
+ background: transparent;
169
+ border: none;
170
+ color: ${__yakProps => {
171
+ const v = getColor('alert');
172
+ return typeof v === 'function' ? v(__yakProps) : v;
173
+ }};
174
+ padding: 0;
175
+ margin-top: 0.5rem;
176
+ font-weight: 600;
177
+ ${ErrorsCloseIcon} {
178
+ display: none;
179
+ }
180
+ }
181
+ `;
182
+ const DropdownIconContainer = styled(Icon)`
183
+ position: absolute;
184
+ right: 0;
185
+ bottom: 0;
186
+ width: 3rem;
187
+ height: 3rem;
188
+ bottom: -1px;
189
+ @media (max-width: 600px) {
190
+ height: 42px;
191
+ }
192
+ ${Icon} {
193
+ position: absolute;
194
+ width: 2rem;
195
+ height: 2rem;
196
+ line-height: 2rem;
197
+ top: 50%;
198
+ left: 50%;
199
+ transform: translate(-50%,-50%);
200
+ background: rgba(0,0,0,0.1);
201
+ border-radius: 50%;
202
+ text-align: center;
203
+ cursor: pointer;
204
+ color: ${__yakProps => {
205
+ const v = getColor('gray90');
206
+ return typeof v === 'function' ? v(__yakProps) : v;
207
+ }};
208
+ &:hover, &:active {
209
+ background: rgba(0,0,0,0.15);
210
+ }
211
+ }
212
+ `;
213
+ const focusBeforeLast = e => {
214
+ if (e.target && e.target !== e.currentTarget) return;
215
+ const el = [].slice.call(e.currentTarget.querySelectorAll('div[contenteditable]')).slice(-1)[0];
216
+ if (!el) return;
217
+ el.focus();
218
+ if (!el.firstChild) {
219
+ const node = document.createTextNode('');
220
+ el.appendChild(node);
221
+ }
222
+ setSelectionRange(el.firstChild, el.textContent.length + 1);
223
+ };
224
+ const setSelectionRange = function (input, selectionStart) {
225
+ let range = document.createRange();
226
+ let sel = window.getSelection();
227
+ range.setStart(input, Math.max(selectionStart - 1, 0));
228
+ sel.removeAllRanges();
229
+ sel.addRange(range);
230
+ };
231
+ const AutoComplete = /*#__PURE__*/React.forwardRef((_ref, outerRef) => {
232
+ let {
233
+ path,
234
+ AutoCompleteLi = Li,
235
+ CompletedBox = _ref2 => {
236
+ let {
237
+ label,
238
+ remove,
239
+ value
240
+ } = _ref2;
241
+ return /*#__PURE__*/React.createElement(AddedBox, {
242
+ title: label
243
+ }, label, /*#__PURE__*/React.createElement(RemoveIcon, {
244
+ icon: "x",
245
+ onMouseUp: constrainEvent(remove)
246
+ }));
247
+ },
248
+ EditableInput = props => /*#__PURE__*/React.createElement(AutoCompleteTextboxDiv, props),
249
+ getLabel = v => v,
250
+ minQueryLength = 3,
251
+ ignoreCase = true,
252
+ autoSelect,
253
+ autoSelectEquals,
254
+ fetchLimit = 6,
255
+ deleteOnBackspace = true,
256
+ fetchSuggestions: rawFetchSuggestions,
257
+ validation = value => ({
258
+ success: value.trim()
259
+ }),
260
+ transform,
261
+ withDropdown,
262
+ autoFocus,
263
+ clickOpensWhenEmpty,
264
+ tabIndex = 1,
265
+ confirmIfNewKeys = [],
266
+ confirmKeys = ['Enter', ','],
267
+ confirmIfValueKeys = ['Tab'],
268
+ placeholder,
269
+ className,
270
+ getListItem = getLabel,
271
+ onAddValue,
272
+ getUniqueKey,
273
+ translatable = true,
274
+ withoutField,
275
+ fieldClassName,
276
+ bellowDescText,
277
+ mandatory,
278
+ descText,
279
+ helpText,
280
+ label,
281
+ value,
282
+ setValue,
283
+ raw
284
+ } = _ref;
285
+ const autoCompleteBox = useToggle();
286
+ const hoverIndex = useToggle();
287
+ const isLoading = useToggle();
288
+ const cancelEditable = useRef();
289
+ const [formValue, _setFormValue, {
290
+ hasErrors
291
+ }] = useInput({
292
+ path,
293
+ transform,
294
+ value,
295
+ setValue
296
+ }, raw);
297
+ const formValueRef = useRef(formValue);
298
+ formValueRef.current = formValue;
299
+ const [localFormValue, setLocalFormValue] = useState(_last(formValue) === "" ? formValue : formValue.concat(""));
300
+ const setFormValue = updater => {
301
+ _setFormValue(updater);
302
+ setLocalFormValue(updater);
303
+ formValueRef.current = typeof updater === 'function' ? updater(formValueRef.current) : updater;
304
+ };
305
+ const lastIsEditable = _isEqual(localFormValue, formValue);
306
+ const [ErrorProvider, errorUtils] = useProvideErrors();
307
+ const hooksRef = useEnsureRef(outerRef);
308
+ const ref = useRef();
309
+ const queries = useRefState([]);
310
+ const suggestionsFetchCache = useRefState({});
311
+ const suggestionsLabelMapCache = useRefState({});
312
+ const lastSuggestionQuery = useRefState('');
313
+ const [autoCompleteList, setAutoCompleteList] = useState([]);
314
+ const getValue = () => formValueRef.current || [];
315
+ const shouldFocusInput = useToggle();
316
+ const recentlyAdded = useRefState(false);
317
+ useEffect(() => {
318
+ if (autoFocus) {
319
+ focusInput();
320
+ }
321
+ }, []);
322
+ const focusInput = () => shouldFocusInput.openWith(i => i + 1);
323
+ useEffect(() => {
324
+ if (shouldFocusInput.isOpen) focusBeforeLast({
325
+ currentTarget: ref.current,
326
+ target: ref.current
327
+ });
328
+ }, [shouldFocusInput.isOpen]);
329
+ const editableIsEmpty = () => !lastIsEditable || lastIsEditable && !formValue[formValue.length - 1];
330
+ const ignoreCaseIfNeeded = s => ignoreCase ? (s || '').toLowerCase() : s;
331
+ const refreshSuggestions = function () {
332
+ let value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
333
+ let justFetch = arguments.length > 1 ? arguments[1] : undefined;
334
+ let dropdownFetch = arguments.length > 2 ? arguments[2] : undefined;
335
+ if ((value.length >= minQueryLength || dropdownFetch) && rawFetchSuggestions) {
336
+ queries.set([value]);
337
+ const removeEditable = list => lastIsEditable ? list.slice(0, -1) : list;
338
+ return isLoading.wait(Promise.resolve(fetchSuggestions(ignoreCaseIfNeeded(value))).then(list => {
339
+ const noRepeatedList = list.filter(v => !removeEditable(getValue()).find(_ => getLabel(v) === getLabel(_)));
340
+ if (justFetch) {
341
+ return noRepeatedList;
342
+ }
343
+ const index = queries.get().indexOf(value);
344
+ if (index >= 0) {
345
+ queries.set(q => q.slice(index + 1));
346
+ if (!autoSelect && !(autoSelectEquals && noRepeatedList.slice(0, 1).find(v => ignoreCaseIfNeeded(getLabel(v)) === ignoreCaseIfNeeded(value)))) {
347
+ hoverIndex.openWith(-1);
348
+ } else {
349
+ hoverIndex.openWith(0);
350
+ }
351
+ autoCompleteBox.open();
352
+ setAutoCompleteList(noRepeatedList);
353
+ }
354
+ }));
355
+ } else {
356
+ hoverIndex.openWith(-1);
357
+ setAutoCompleteList([]);
358
+ return Promise.resolve([]);
359
+ }
360
+ };
361
+ const fetchSuggestions = s => {
362
+ const prevQuery = lastSuggestionQuery.get();
363
+ lastSuggestionQuery.set(s);
364
+ if (suggestionsFetchCache.get()[s]) {
365
+ return suggestionsFetchCache.get()[s];
366
+ } else {
367
+ const lastFetch = suggestionsFetchCache.get()[ignoreCaseIfNeeded(prevQuery)];
368
+ if (s.indexOf(ignoreCaseIfNeeded(prevQuery)) >= 0 && lastFetch && lastFetch.length < fetchLimit) {
369
+ return suggestionsFetchCache.get()[s] = lastFetch.map(getLabel).filter(_ => ignoreCaseIfNeeded(_).indexOf(ignoreCaseIfNeeded(s)) >= 0).map(_ => suggestionsLabelMapCache.get()()[ignoreCaseIfNeeded(_)]);
370
+ } else {
371
+ const fetch = Promise.resolve(rawFetchSuggestions(s));
372
+ fetch.then(list => {
373
+ suggestionsFetchCache[ignoreCaseIfNeeded(s)] = list;
374
+ list.forEach(suggestion => suggestionsLabelMapCache.get()[ignoreCaseIfNeeded(getLabel(suggestion))] = suggestionsLabelMapCache.get()[ignoreCaseIfNeeded(getLabel(suggestion))] || suggestion);
375
+ });
376
+ return fetch;
377
+ }
378
+ }
379
+ };
380
+ useEffect(() => {
381
+ if (!lastIsEditable) {
382
+ if (recentlyAdded.get() !== cancelEditable.current) {
383
+ setFormValue(_without([cancelEditable.current], formValue).concat(""));
384
+ } else {
385
+ setLocalFormValue(_last(formValue) === "" ? formValue : formValue.concat(""));
386
+ }
387
+ cancelEditable.current = null;
388
+ }
389
+ }, [lastIsEditable]);
390
+ useEffect(() => {
391
+ refreshSuggestions(lastIsEditable ? getValue().slice(-1)[0] : '');
392
+ if (recentlyAdded.get()) {
393
+ recentlyAdded.set(false);
394
+ callIfFunction(onAddValue, formValue, setFormValue);
395
+ }
396
+ }, [formValue]);
397
+ const confirmIfNew = (index, newValue) => {
398
+ refreshSuggestions(newValue, true).then(list => {
399
+ if (!list.length) {
400
+ confirm(index, newValue);
401
+ } else {
402
+ onChange(index, newValue);
403
+ }
404
+ });
405
+ };
406
+ const confirm = (index, newValue) => {
407
+ if (autoCompleteList.length && hoverIndex.isOpen >= 0) {
408
+ addValue(autoCompleteList[hoverIndex.isOpen]);
409
+ } else {
410
+ confirmValue(index, newValue);
411
+ }
412
+ };
413
+ const confirmValue = (index, newValue, fromBlur) => {
414
+ if (!newValue) {
415
+ return;
416
+ }
417
+ const suggestedValue = suggestionsLabelMapCache[ignoreCaseIfNeeded(newValue || '').trim()];
418
+ if (suggestedValue) {
419
+ addValue(suggestedValue, fromBlur);
420
+ return;
421
+ }
422
+ const {
423
+ success,
424
+ errors
425
+ } = validation(newValue);
426
+ if (errors) {
427
+ errorUtils.setErrors({
428
+ errors
429
+ });
430
+ } else {
431
+ addValue(success, fromBlur);
432
+ }
433
+ };
434
+ const onChange = (index, value) => {
435
+ errorUtils.clearErrors();
436
+ setFormValue(_s.set([index], value));
437
+ };
438
+ const addValue = (value, fromBlur) => {
439
+ const index = Math.max(lastIsEditable ? getValue().length - 1 : getValue().length, 0);
440
+ recentlyAdded.set((formValue === null || formValue === void 0 ? void 0 : formValue[index]) || "");
441
+ setFormValue(_flow(_set([index], value), _concat(_concat.placeholder, "")));
442
+ if (!fromBlur) {
443
+ focusInput();
444
+ }
445
+ };
446
+ const remove = index => {
447
+ setFormValue(_flow(_s.unset(index), _filter(_ => _ !== undefined)));
448
+ focusInput();
449
+ };
450
+ const onBlur = e => {
451
+ autoCompleteBox.close();
452
+ const v = getValue().slice(-1)[0];
453
+ if (lastIsEditable) {
454
+ const {
455
+ errors
456
+ } = validation(v);
457
+ const firstIsEqual = autoCompleteList.slice(0, 1).find(item => ignoreCaseIfNeeded(getLabel(item)) === ignoreCaseIfNeeded(v));
458
+ if (v && autoSelect && (autoCompleteList.length === 1 || firstIsEqual) && errors) {
459
+ addValue(autoCompleteList[0], true);
460
+ } else if (autoSelectEquals && firstIsEqual) {
461
+ addValue(autoCompleteList[0], true);
462
+ } else {
463
+ confirmValue(getValue().length - 1, v, true);
464
+ }
465
+ } else if (autoCompleteList.length) {
466
+ setAutoCompleteList([]);
467
+ }
468
+ };
469
+ React.useImperativeHandle(hooksRef, () => ({
470
+ addValue,
471
+ confirm,
472
+ remove
473
+ }), [formValue]);
474
+ const validValue = formValue || [''];
475
+ const uniqueKeyLabel = {};
476
+ const _getUniqueKey = value => {
477
+ if (getUniqueKey) {
478
+ return getUniqueKey(value);
479
+ }
480
+ const label = getLabel(value);
481
+ const uid = uniqueKeyLabel[label] = (uniqueKeyLabel[label] || 0) + 1;
482
+ return label + uid;
483
+ };
484
+ const tryOpenSuggestions = e => {
485
+ if (autoCompleteBox.get()) {
486
+ stopPropagation(onBlur)(e);
487
+ } else {
488
+ errorUtils.clearErrors();
489
+ refreshSuggestions(lastIsEditable ? getValue().slice(-1)[0] : '', false, true);
490
+ focusInput();
491
+ }
492
+ };
493
+ const input = /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(AutoCompleteInput, {
494
+ onKeyDown: e => e.key === ' ' && e.stopPropagation(),
495
+ className: className,
496
+ ref: ref,
497
+ onFocus: () => {
498
+ if (autoCompleteList.length) autoCompleteBox.open();else if (withDropdown && editableIsEmpty()) refreshSuggestions(undefined, undefined, true);
499
+ },
500
+ hasErrors: errorUtils.errors.length > 0 || hasErrors,
501
+ onBlur: onBlur,
502
+ onClick: e => {
503
+ focusBeforeLast(e);
504
+ if (editableIsEmpty() && !isLoading.isOpen) {
505
+ refreshSuggestions(undefined, undefined, true);
506
+ }
507
+ },
508
+ focused: autoCompleteBox.isOpen,
509
+ withDropdown: withDropdown
510
+ }, /*#__PURE__*/React.createElement("span", null, '\u200b'), validValue.map((v, i) => /*#__PURE__*/React.createElement(ValueItem, {
511
+ value: v,
512
+ index: i,
513
+ cancelEditable: v => {
514
+ cancelEditable.current = v;
515
+ },
516
+ isEditable: lastIsEditable && validValue.length === i + 1,
517
+ confirmKeys: confirmKeys,
518
+ confirmIfValueKeys: confirmIfValueKeys,
519
+ deleteOnBackspace: deleteOnBackspace,
520
+ EditableInput: EditableInput,
521
+ key: lastIsEditable && validValue.length === i + 1 ? '$$editable$$' : _getUniqueKey(v),
522
+ onChange: onChange,
523
+ remove: remove,
524
+ confirm: confirm,
525
+ getLabel: getLabel,
526
+ tabIndex: tabIndex,
527
+ confirmIfNew: confirmIfNew,
528
+ confirmIfNewKeys: confirmIfNewKeys,
529
+ CompletedBox: CompletedBox
530
+ })), /*#__PURE__*/React.createElement("span", null, '\u200b'), (!formValue || !formValue.join('')) && placeholder && /*#__PURE__*/React.createElement(AutoCompletePlaceholder, {
531
+ onClick: e => ref.current.click()
532
+ }, placeholder), withDropdown && !isLoading.isOpen && /*#__PURE__*/React.createElement(DropdownIconContainer, {
533
+ onClick: tryOpenSuggestions
534
+ }, /*#__PURE__*/React.createElement(Icon, {
535
+ icon: "arrow-down"
536
+ }))), autoCompleteBox.isOpen !== false && !errorUtils.errors.length && autoCompleteList.length > 0 && /*#__PURE__*/React.createElement(AutoCompleteMenu, {
537
+ hoverIndex: hoverIndex.isOpen,
538
+ autoHover: autoSelect,
539
+ onClick: constrainEvent(),
540
+ onHover: hoverIndex.openWith,
541
+ my: "top left",
542
+ at: "bottom left",
543
+ fill: true
544
+ }, autoCompleteList.map(value => /*#__PURE__*/React.createElement(AutoCompleteLi, {
545
+ className: !translatable ? 'notranslate' : null,
546
+ key: _getUniqueKey(value),
547
+ label: getListItem(value),
548
+ onMouseDown: e => e.preventDefault(),
549
+ onClick: () => addValue(value)
550
+ }))), /*#__PURE__*/React.createElement(ErrorProvider, {
551
+ value: errorUtils
552
+ }, /*#__PURE__*/React.createElement(AutoCompleteError, null)));
553
+ return withoutField ? input : /*#__PURE__*/React.createElement(Field, {
554
+ bellowDescText: bellowDescText,
555
+ className: fieldClassName,
556
+ value: formValue,
557
+ mandatory: mandatory,
558
+ descText: descText,
559
+ helpText: helpText,
560
+ label: label,
561
+ labelClick: focusInput
562
+ }, isLoading.isOpen && /*#__PURE__*/React.createElement(InputLoading, {
563
+ absolute: true,
564
+ size: 24
565
+ }), input);
566
+ });
567
+ AutoComplete.AddedBox = AddedBox;
568
+ AutoComplete.RemoveIcon = RemoveIcon;
569
+ AutoComplete.AutoCompleteTextboxDiv = AutoCompleteTextboxDiv;
570
+ const cleanText = text => {
571
+ const clean = text.replace('\u200b', '').replace(/\n/g, ' ').replace(/\s+/g, ' ');
572
+ return clean.trim() ? clean : '';
573
+ };
574
+ const ValueItem = _ref3 => {
575
+ let {
576
+ CompletedBox,
577
+ isEditable,
578
+ getLabel,
579
+ cancelEditable,
580
+ value,
581
+ remove,
582
+ index
583
+ } = _ref3,
584
+ props = _objectWithoutProperties(_ref3, _excluded);
585
+ const isEditing = useToggle(isEditable);
586
+ const valueRef = useRef(value);
587
+ valueRef.current = value;
588
+ useEffect(() => () => {
589
+ if (isEditing.isOpen) {
590
+ cancelEditable(valueRef.current);
591
+ }
592
+ }, []);
593
+ return isEditing.isOpen ? /*#__PURE__*/React.createElement(AutoCompleteTextbox, _extends({}, props, {
594
+ value: value,
595
+ index: index,
596
+ remove: remove
597
+ })) : /*#__PURE__*/React.createElement(CompletedBox, {
598
+ label: getLabel(value),
599
+ value: value,
600
+ remove: () => remove(index)
601
+ });
602
+ };
603
+ class AutoCompleteTextbox extends React.Component {
604
+ constructor() {
605
+ super(...arguments);
606
+ this.state = {
607
+ value: this.props.value
608
+ };
609
+ this.deletePrev = () => this.props.index > 0 && this.props.remove(this.props.index - 1);
610
+ this.onKeyDown = e => {
611
+ const range = window.getSelection().getRangeAt(0);
612
+ if (this.props.confirmIfNewKeys.indexOf(e.key) >= 0) {
613
+ e.preventDefault();
614
+ const text = range.startContainer.textContent;
615
+ this.props.confirmIfNew(this.props.index, cleanText((text.slice(0, range.startOffset) + '\uFFFD' + text.slice(range.startOffset)).replace('\uFFFD', e.key)));
616
+ } else if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
617
+ e.stopPropagation();
618
+ } else if (this.props.confirmKeys.indexOf(e.key) >= 0 || this.props.confirmIfValueKeys.indexOf(e.key) >= 0) {
619
+ if (this.props.confirmKeys.indexOf(e.key) >= 0) {
620
+ e.preventDefault();
621
+ }
622
+ if (this.props.value) {
623
+ e.preventDefault();
624
+ e.stopPropagation();
625
+ this.props.confirm(this.props.index, this.props.value);
626
+ }
627
+ } else if (e.key === 'Backspace' && this.props.deleteOnBackspace) {
628
+ if (e.target.textContent !== '\u200b' || !range.collapsed) {
629
+ if (range.startContainer.previousSibling) {
630
+ if (range.startContainer.previousSibling.textContent.length) {
631
+ return;
632
+ }
633
+ } else if (range.startOffset > 0) {
634
+ return;
635
+ }
636
+ }
637
+ e.preventDefault();
638
+ this.deletePrev();
639
+ }
640
+ };
641
+ this.onChange = evt => {
642
+ this.props.onChange(this.props.index, cleanText(evt.currentTarget.isContentEditable ? evt.currentTarget.innerText : evt.target.value));
643
+ };
644
+ this.setEl = ref => this.el = ref;
645
+ this.onPaste = ev => {
646
+ ev.preventDefault();
647
+ const text = ev.clipboardData.getData('text');
648
+ document.execCommand('insertText', false, text);
649
+ };
650
+ }
651
+ shouldComponentUpdate(nextProps) {
652
+ const event = new CustomEvent('portalReposition');
653
+ setTimeout(() => window.dispatchEvent(event), 1);
654
+ if (this.el.innerHTML === '<br>' || !this.el.innerHTML) {
655
+ this.props.onChange(this.props.index, '');
656
+ }
657
+ return nextProps.value !== cleanText(this.el.innerText) || !!Object.keys(nextProps).find(k => nextProps[k] !== this.props[k]);
658
+ }
659
+
660
+ // Only a programmatic change (not the user typing) should move the caret to the end
661
+ getSnapshotBeforeUpdate() {
662
+ return this.props.value !== cleanText(this.el.innerText);
663
+ }
664
+ componentDidUpdate(oldProps, prevState, changedOutside) {
665
+ let rewritten = false;
666
+ if (this.props.value.slice(-1) === ' ' && /\S/.test(this.el.textContent.slice(-1))) {
667
+ // does not have blank space as last
668
+ this.el.innerHTML = this.props.value.replace(/\s/, '&nbsp;');
669
+ rewritten = true;
670
+ }
671
+ if (this.props.value !== oldProps.value && (changedOutside || rewritten) && document.activeElement === this.el) {
672
+ setSelectionRange(this.el.firstChild || this.el, this.el.textContent.length + 1);
673
+ }
674
+ }
675
+ render() {
676
+ const _this$props = this.props,
677
+ {
678
+ value,
679
+ confirmKeys,
680
+ index,
681
+ EditableInput,
682
+ confirmIfNewKeys,
683
+ confirmIfNew,
684
+ confirm,
685
+ remove
686
+ } = _this$props,
687
+ rest = _objectWithoutProperties(_this$props, _excluded2);
688
+ const valueOrBlank = /*android fix, not needed? value || */_isString(value) && value ? value : '\u200b';
689
+ const props = _objectSpread(_objectSpread({
690
+ // stable ref: a new function each render makes ContentEditable re-render and jump the caret to the end
691
+ innerRef: this.setEl,
692
+ onKeyDown: this.onKeyDown,
693
+ onPaste: this.onPaste,
694
+ value: value,
695
+ index: index,
696
+ html: valueOrBlank.replace(/\s$/, '&nbsp;')
697
+ }, rest), {}, {
698
+ onChange: this.onChange
699
+ });
700
+ return typeof EditableInput === 'function' ? EditableInput(props) : /*#__PURE__*/React.createElement(EditableInput, props);
701
+ }
702
+ }
703
+
704
+ export { AutoComplete, AutoCompleteTextbox };
705
+ //# sourceMappingURL=AutoComplete.mjs.map