@cloud-ru/ds-fields 2.2.3-preview-7425cb27.0 → 2.2.3-preview-a42433ce.0

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": "2.2.3-preview-7425cb27.0",
3
+ "version": "2.2.3-preview-a42433ce.0",
4
4
  "description": "Поля ввода с единой обёрткой label/caption/hint/error и общими осями size/validationState — текст, пароль, число, ползунок, дата, время, выбор, цвет.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,17 +42,17 @@
42
42
  "@cloud-ru/ds-adaptive": "1.0.1",
43
43
  "@cloud-ru/ds-bottom-sheet": "1.1.1",
44
44
  "@cloud-ru/ds-button": "1.0.2",
45
- "@cloud-ru/ds-calendar": "1.0.14",
46
45
  "@cloud-ru/ds-color-picker": "1.0.6",
46
+ "@cloud-ru/ds-calendar": "1.0.15-preview-a42433ce.0",
47
47
  "@cloud-ru/ds-divider": "1.0.1",
48
+ "@cloud-ru/ds-dropdown": "1.0.8",
48
49
  "@cloud-ru/ds-field-decorator": "1.0.5",
49
50
  "@cloud-ru/ds-icons": "1.1.0",
50
- "@cloud-ru/ds-list": "2.1.3",
51
- "@cloud-ru/ds-dropdown": "1.0.8",
52
51
  "@cloud-ru/ds-input-private": "1.0.4",
53
52
  "@cloud-ru/ds-loader": "1.0.1",
54
- "@cloud-ru/ds-materials": "1.0.1",
53
+ "@cloud-ru/ds-list": "2.1.4-preview-a42433ce.0",
55
54
  "@cloud-ru/ds-scroll": "1.0.2",
55
+ "@cloud-ru/ds-materials": "1.0.1",
56
56
  "@cloud-ru/ds-skeleton": "1.0.1",
57
57
  "@cloud-ru/ds-slider": "1.0.4",
58
58
  "@cloud-ru/ds-tag": "1.1.1",
@@ -45,9 +45,7 @@ type UseSegmentedMaskParams = {
45
45
  * Сегментный ввод даты/времени (порт `useDateField` из @snack-uikit/fields). Каретка ходит по
46
46
  * сегментам (`setSelectionRange` подсвечивает текущий), цифры заполняют сегмент с авто-переходом,
47
47
  * стрелки двигают по сегментам, Backspace очищает сегмент до плейсхолдера.
48
- *
49
- * Навигация идёт через `handleKeyDown`, правка значения — через нативные `beforeinput`/`input`:
50
- * `nativeInputRef` нужно передать в `ref` того же input'а.
48
+ * `nativeInputRef` передаётся в `ref` того же input'а: значение правится через нативные `beforeinput`/`input`.
51
49
  */
52
50
  export function useSegmentedMask({
53
51
  inputRef,
@@ -190,8 +188,7 @@ export function useSegmentedMask({
190
188
  [clearSlot, isValidDate, lastSlot, nextSlot, selectSlot, slots, tryToComplete],
191
189
  );
192
190
 
193
- // Цифры, набранные в текущий сегмент. Храним отдельно от текста: по `01` в поле нельзя понять,
194
- // набрали `1` или `0` + `1`, а от этого зависит, ждать ли вторую цифру.
191
+ // Цифры сегмента храним отдельно от текста: по `01` в поле не отличить `1` от `0` + `1`.
195
192
  const typedRef = useRef<{ key: SegmentKey; digits: string } | null>(null);
196
193
  const resetTyped = useCallback(() => {
197
194
  typedRef.current = null;
@@ -202,12 +199,11 @@ export function useSegmentedMask({
202
199
  const maxLength = slot.max.toString().length;
203
200
  const prev = typedRef.current?.key === slot.key ? typedRef.current.digits : '';
204
201
  const appended = prev + key;
205
- // Цифра выводит сегмент за max — сегмент начинается с неё заново (как React Aria и MUI X): `13` в месяце → `03`.
202
+ // Как в React Aria и MUI X: `13` в месяце → `03`.
206
203
  const overflow = Number(appended) > slot.max;
207
204
  const digits = overflow ? key : appended;
208
205
  const value = Number(digits);
209
206
  const complete = overflow || digits.length >= maxLength || value * 10 > slot.max;
210
- // Значение ниже min (`0` в дне) не показываем, но помним цифру до следующей.
211
207
  const accepted = value >= slot.min;
212
208
 
213
209
  if (accepted) updateSlot(slot, value);
@@ -256,7 +252,6 @@ export function useSegmentedMask({
256
252
  const input = inputRef.current;
257
253
  if (!input || readonly || disabled) return;
258
254
 
259
- // Навигация и правка начинают набор сегмента заново. Цифры, `Unidentified` (Android) и модификаторы — нет.
260
255
  if (RESET_TYPED_KEYS.has(event.key)) resetTyped();
261
256
 
262
257
  // Tab уводит фокус из поля — не перехватываем.
@@ -275,12 +270,12 @@ export function useSegmentedMask({
275
270
  return;
276
271
  }
277
272
 
278
- // Сочетания (копирование, вставка, выделение) отдаём браузеру: правку поля перехватит beforeinput.
273
+ // Копирование и вставку не блокируем: правку поля перехватит beforeinput.
279
274
  if (event.ctrlKey || event.metaKey || event.altKey) return;
280
275
 
281
276
  onEdit?.();
282
277
 
283
- // Цифры и `Unidentified` (экранные клавиатуры Android, IME) вводятся через beforeinput.
278
+ // Экранные клавиатуры присылают `Unidentified` вместо цифры, её данные есть только в beforeinput.
284
279
  if (/^\d$/.test(event.key) || event.key === 'Unidentified') return;
285
280
 
286
281
  if (event.key === 'Escape') {
@@ -343,7 +338,6 @@ export function useSegmentedMask({
343
338
  ],
344
339
  );
345
340
 
346
- // Раскладывает цифры по сегментам слева направо полными кусками — для вставки и автозаполнения.
347
341
  const fillFromDigits = useCallback(
348
342
  (digits: string) => {
349
343
  resetTyped();
@@ -369,8 +363,6 @@ export function useSegmentedMask({
369
363
  [ensureMask, lastSlot, nextSlot, resetTyped, selectSlot, slots, tryToComplete, updateSlot],
370
364
  );
371
365
 
372
- // Вставка (Ctrl+V) полной строки даты/времени. Нативный onChange у поля игнорируется (движок
373
- // controlled), поэтому без этого обработчика вставка не работала бы вовсе.
374
366
  const handlePaste = useCallback(
375
367
  (event: ClipboardEvent<HTMLInputElement>) => {
376
368
  if (readonly || disabled) return;
@@ -399,7 +391,7 @@ export function useSegmentedMask({
399
391
  const digits = text.replace(/\D/g, '');
400
392
  if (!inputType.startsWith('insert') || !digits) return;
401
393
 
402
- // Строка целиком (автозаполнение, `fill`, drop) раскладывается с начала маски, одиночная цифра — в текущий сегмент.
394
+ // Автозаполнение, `fill` и drop присылают строку целиком.
403
395
  if (text.length > 1) {
404
396
  fillFromDigits(digits);
405
397
  } else {
@@ -410,7 +402,7 @@ export function useSegmentedMask({
410
402
  [clearSlot, emit, fillFromDigits, inputRef, onEdit, resetTyped, slotFromIndex, typeDigit],
411
403
  );
412
404
 
413
- // Значение и выделение до правки, которую браузер не дал отменить (композиция IME).
405
+ // Композицию IME браузер не даёт отменить — откатываем её в input.
414
406
  const pendingEditRef = useRef<{ value: string; start: number; end: number } | null>(null);
415
407
 
416
408
  const handleBeforeInput = useCallback(
@@ -438,18 +430,17 @@ export function useSegmentedMask({
438
430
  pendingEditRef.current = null;
439
431
 
440
432
  if (pending) {
441
- // Браузер уже изменил значение: вырезаем вставленное, возвращаем прежнее и применяем как обычный ввод.
442
433
  const inputType = event instanceof InputEvent ? event.inputType : '';
443
434
  const inserted = input.value.slice(pending.start, input.value.length - (pending.value.length - pending.end));
444
435
  input.value = pending.value;
445
436
  setValue(pending.value);
446
437
  input.setSelectionRange(pending.start, pending.end);
447
- // Цифру из композиции IME применит её фиксация (отменяемый insertText), как в React Aria.
438
+ // Цифру композиции вводит её фиксация (insertText), иначе цифра запишется дважды.
448
439
  if (!inputType.includes('Composition')) applyEdit(inputType, inserted);
449
440
  return;
450
441
  }
451
442
 
452
- // Значение сменили без beforeinput (автозаполнение браузера).
443
+ // Автозаполнение меняет значение без beforeinput.
453
444
  const digits = input.value.replace(/\D/g, '');
454
445
  input.value = mask;
455
446
  setValue(mask);