@cloud-ru/ds-fields 1.0.2-preview-cd0cd6fb.0 → 1.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud-ru/ds-fields",
3
- "version": "1.0.2-preview-cd0cd6fb.0",
3
+ "version": "1.0.2",
4
4
  "description": "Поля ввода с единой обёрткой label/caption/hint/error и общими осями size/validationState — текст, пароль, число, ползунок, дата, время, выбор, цвет.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -39,24 +39,24 @@
39
39
  "classnames": "^2.5.1",
40
40
  "merge-refs": "^2.0.0",
41
41
  "react-textarea-autosize": "^8.5.9",
42
- "@cloud-ru/ds-button": "1.0.0",
43
- "@cloud-ru/ds-adaptive": "1.0.0",
44
- "@cloud-ru/ds-bottom-sheet": "1.0.0",
45
- "@cloud-ru/ds-calendar": "1.0.2-preview-cd0cd6fb.0",
46
- "@cloud-ru/ds-color-picker": "1.0.0",
47
- "@cloud-ru/ds-divider": "1.0.0",
48
- "@cloud-ru/ds-dropdown": "1.0.0",
49
- "@cloud-ru/ds-field-decorator": "1.0.0",
50
- "@cloud-ru/ds-input-private": "1.0.0",
51
- "@cloud-ru/ds-list": "1.1.1-preview-cd0cd6fb.0",
52
- "@cloud-ru/ds-icons": "1.0.0",
53
- "@cloud-ru/ds-loader": "1.0.0",
54
- "@cloud-ru/ds-materials": "1.0.0",
55
- "@cloud-ru/ds-scroll": "1.0.0",
56
- "@cloud-ru/ds-slider": "1.0.0",
57
- "@cloud-ru/ds-skeleton": "1.0.0",
58
- "@cloud-ru/ds-tooltip": "1.0.0",
59
- "@cloud-ru/ds-tag": "1.0.0",
60
- "@cloud-ru/ds-utils": "1.0.0"
42
+ "@cloud-ru/ds-adaptive": "^1.0.0",
43
+ "@cloud-ru/ds-button": "^1.0.0",
44
+ "@cloud-ru/ds-bottom-sheet": "^1.0.0",
45
+ "@cloud-ru/ds-calendar": "^1.0.1",
46
+ "@cloud-ru/ds-color-picker": "^1.0.0",
47
+ "@cloud-ru/ds-divider": "^1.0.0",
48
+ "@cloud-ru/ds-dropdown": "^1.0.0",
49
+ "@cloud-ru/ds-field-decorator": "^1.0.0",
50
+ "@cloud-ru/ds-icons": "^1.0.0",
51
+ "@cloud-ru/ds-list": "^1.1.0",
52
+ "@cloud-ru/ds-input-private": "^1.0.0",
53
+ "@cloud-ru/ds-loader": "^1.0.0",
54
+ "@cloud-ru/ds-materials": "^1.0.0",
55
+ "@cloud-ru/ds-scroll": "^1.0.0",
56
+ "@cloud-ru/ds-skeleton": "^1.0.0",
57
+ "@cloud-ru/ds-slider": "^1.0.0",
58
+ "@cloud-ru/ds-tooltip": "^1.0.0",
59
+ "@cloud-ru/ds-tag": "^1.0.1",
60
+ "@cloud-ru/ds-utils": "^1.0.0"
61
61
  }
62
62
  }
@@ -37,7 +37,16 @@ import {
37
37
  import fieldStyles from '../shared/styles.module.scss';
38
38
  import styles from './styles.module.scss';
39
39
  import { FieldSelectProps } from './types';
40
- import { extractAppearance, extractLabel, filterItems, findItem, isMultiple, TAG_SIZE_MAP } from './utils';
40
+ import {
41
+ extractAppearance,
42
+ extractLabel,
43
+ filterItems,
44
+ findItem,
45
+ flatten,
46
+ isMultiple,
47
+ TAG_SIZE_MAP,
48
+ WithIdContent,
49
+ } from './utils';
41
50
 
42
51
  export const FieldSelect = forwardRef<HTMLInputElement, FieldSelectProps>(function FieldSelect(props, ref) {
43
52
  const {
@@ -150,6 +159,19 @@ export const FieldSelect = forwardRef<HTMLInputElement, FieldSelectProps>(functi
150
159
 
151
160
  const allItems = useMemo(() => [...(pinTop ?? []), ...items, ...(pinBottom ?? [])], [items, pinTop, pinBottom]);
152
161
 
162
+ // Выбранное значение переживает смену `items` (серверный поиск, ленивая подгрузка).
163
+ const seenItems = useRef(new Map<ItemId, WithIdContent>());
164
+
165
+ const resolveItem = useMemo(() => {
166
+ for (const item of flatten(allItems)) {
167
+ if (item.id !== undefined) {
168
+ seenItems.current.set(item.id, item);
169
+ }
170
+ }
171
+
172
+ return (id: ItemId) => findItem(allItems, id) ?? seenItems.current.get(id);
173
+ }, [allItems]);
174
+
153
175
  const selectedPairs = useMemo(() => {
154
176
  if (!multiple || multipleValue.length === 0) {
155
177
  return [];
@@ -157,7 +179,7 @@ export const FieldSelect = forwardRef<HTMLInputElement, FieldSelectProps>(functi
157
179
 
158
180
  // Неизвестное значение (ещё не загружены опции) показываем по его id, не теряем (паритет с легаси).
159
181
  return multipleValue.map(id => {
160
- const item = findItem(allItems, id);
182
+ const item = resolveItem(id);
161
183
 
162
184
  return {
163
185
  id,
@@ -166,7 +188,7 @@ export const FieldSelect = forwardRef<HTMLInputElement, FieldSelectProps>(functi
166
188
  appearance: extractAppearance(item),
167
189
  };
168
190
  });
169
- }, [allItems, multiple, multipleValue]);
191
+ }, [multiple, multipleValue, resolveItem]);
170
192
 
171
193
  const formatPair = useCallback(
172
194
  (pair: { id: ItemId; label: string }) => (selectedOptionFormatter ? selectedOptionFormatter(pair) : pair.label),
@@ -179,7 +201,7 @@ export const FieldSelect = forwardRef<HTMLInputElement, FieldSelectProps>(functi
179
201
  return '';
180
202
  }
181
203
 
182
- const item = findItem(allItems, singleValue);
204
+ const item = resolveItem(singleValue);
183
205
  const label = item ? extractLabel(item) : String(singleValue);
184
206
 
185
207
  return formatPair({ id: singleValue, label });
@@ -194,7 +216,7 @@ export const FieldSelect = forwardRef<HTMLInputElement, FieldSelectProps>(functi
194
216
  }
195
217
 
196
218
  return selectedPairs.map(formatPair).join(', ');
197
- }, [allItems, multiple, singleValue, selectedPairs, chips, props, formatPair]);
219
+ }, [multiple, singleValue, selectedPairs, chips, props, formatPair, resolveItem]);
198
220
 
199
221
  // Строка поиска: controlled через `search.value`, иначе локальный state. Auto-sync к выбранному
200
222
  // значению делаем через СТАБИЛЬНЫЙ setLocalInput, а не через setInputValue в deps эффекта —
@@ -14,9 +14,7 @@ import {
14
14
  MouseEvent,
15
15
  ReactNode,
16
16
  useCallback,
17
- useEffect,
18
17
  useMemo,
19
- useReducer,
20
18
  useRef,
21
19
  useState,
22
20
  } from 'react';
@@ -172,12 +170,6 @@ export const FieldTextArea = forwardRef<HTMLTextAreaElement, FieldTextAreaProps>
172
170
  const [focusVisible, setFocusVisible] = useState(false);
173
171
  const [hover, setHover] = useState(false);
174
172
 
175
- // autosize меряет высоту до того, как ThemeScope навесит классы темы — пересчитываем после mount.
176
- const [, remeasure] = useReducer((tick: number) => tick + 1, 0);
177
- useEffect(() => {
178
- remeasure();
179
- }, []);
180
-
181
173
  const resolvedAutoFocus = useAdaptiveAutoFocus(autoFocus, layoutPresets);
182
174
 
183
175
  // controlled/uncontrolled: useValueControl держит внутреннее состояние при отсутствии `value`,