@skbkontur/react-ui 6.1.5 → 6.1.6-084cd.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.
Files changed (185) hide show
  1. package/components/FxInput/FxInput.d.ts +1 -1
  2. package/components/FxInput/FxInput.js.map +1 -1
  3. package/components/MaskedInput/MaskedInput.d.ts +6 -2
  4. package/components/MaskedInput/MaskedInput.js +10 -126
  5. package/components/MaskedInput/MaskedInput.js.map +1 -1
  6. package/components/MaskedInput/MaskedInputLegacy.d.ts +3 -0
  7. package/components/MaskedInput/MaskedInputLegacy.js +142 -0
  8. package/components/MaskedInput/MaskedInputLegacy.js.map +1 -0
  9. package/components/MaskedInput/index.d.ts +1 -0
  10. package/components/MaskedInput/index.js +1 -0
  11. package/components/MaskedInput/index.js.map +1 -1
  12. package/components/MaskedInputV2/MaskedInputV2.d.ts +62 -0
  13. package/components/MaskedInputV2/MaskedInputV2.helpers.d.ts +9 -0
  14. package/components/MaskedInputV2/MaskedInputV2.helpers.js +17 -0
  15. package/components/MaskedInputV2/MaskedInputV2.helpers.js.map +1 -0
  16. package/components/MaskedInputV2/MaskedInputV2.js +307 -0
  17. package/components/MaskedInputV2/MaskedInputV2.js.map +1 -0
  18. package/components/MaskedInputV2/MaskedInputV2.phone.d.ts +27 -0
  19. package/components/MaskedInputV2/MaskedInputV2.phone.js +37 -0
  20. package/components/MaskedInputV2/MaskedInputV2.phone.js.map +1 -0
  21. package/components/MaskedInputV2/MaskedInputV2.styles.d.ts +7 -0
  22. package/components/MaskedInputV2/MaskedInputV2.styles.js +19 -0
  23. package/components/MaskedInputV2/MaskedInputV2.styles.js.map +1 -0
  24. package/components/MaskedInputV2/index.d.ts +2 -0
  25. package/components/MaskedInputV2/index.js +3 -0
  26. package/components/MaskedInputV2/index.js.map +1 -0
  27. package/components/MaskedInputV2/internal/MaskOverlay.d.ts +19 -0
  28. package/components/MaskedInputV2/internal/MaskOverlay.js +54 -0
  29. package/components/MaskedInputV2/internal/MaskOverlay.js.map +1 -0
  30. package/components/MaskedInputV2/internal/MaskedCore.d.ts +8 -0
  31. package/components/MaskedInputV2/internal/MaskedCore.js +186 -0
  32. package/components/MaskedInputV2/internal/MaskedCore.js.map +1 -0
  33. package/components/MaskedInputV2/internal/MaskedCore.types.d.ts +37 -0
  34. package/components/MaskedInputV2/internal/MaskedCore.types.js +2 -0
  35. package/components/MaskedInputV2/internal/MaskedCore.types.js.map +1 -0
  36. package/components/MaskedInputV2/internal/MaskedInternal.styles.d.ts +15 -0
  37. package/components/MaskedInputV2/internal/MaskedInternal.styles.js +34 -0
  38. package/components/MaskedInputV2/internal/MaskedInternal.styles.js.map +1 -0
  39. package/components/MaskedInputV2/internal/buildSlotMap.d.ts +11 -0
  40. package/components/MaskedInputV2/internal/buildSlotMap.js +37 -0
  41. package/components/MaskedInputV2/internal/buildSlotMap.js.map +1 -0
  42. package/components/MaskedInputV2/internal/computeMaskAlignPadding.d.ts +6 -0
  43. package/components/MaskedInputV2/internal/computeMaskAlignPadding.js +47 -0
  44. package/components/MaskedInputV2/internal/computeMaskAlignPadding.js.map +1 -0
  45. package/components/MaskedInputV2/internal/computePasteMaskedCursor.d.ts +3 -0
  46. package/components/MaskedInputV2/internal/computePasteMaskedCursor.js +11 -0
  47. package/components/MaskedInputV2/internal/computePasteMaskedCursor.js.map +1 -0
  48. package/components/MaskedInputV2/internal/extractRaw.d.ts +10 -0
  49. package/components/MaskedInputV2/internal/extractRaw.js +16 -0
  50. package/components/MaskedInputV2/internal/extractRaw.js.map +1 -0
  51. package/components/MaskedInputV2/internal/findNearestRawLeft.d.ts +10 -0
  52. package/components/MaskedInputV2/internal/findNearestRawLeft.js +18 -0
  53. package/components/MaskedInputV2/internal/findNearestRawLeft.js.map +1 -0
  54. package/components/MaskedInputV2/internal/helpers.d.ts +8 -0
  55. package/components/MaskedInputV2/internal/helpers.js +9 -0
  56. package/components/MaskedInputV2/internal/helpers.js.map +1 -0
  57. package/components/MaskedInputV2/internal/maskedCoreClipboard.d.ts +37 -0
  58. package/components/MaskedInputV2/internal/maskedCoreClipboard.js +52 -0
  59. package/components/MaskedInputV2/internal/maskedCoreClipboard.js.map +1 -0
  60. package/components/MaskedInputV2/internal/maskedCoreDeletion.d.ts +28 -0
  61. package/components/MaskedInputV2/internal/maskedCoreDeletion.js +70 -0
  62. package/components/MaskedInputV2/internal/maskedCoreDeletion.js.map +1 -0
  63. package/components/MaskedInputV2/internal/maskedCoreInputChange.d.ts +38 -0
  64. package/components/MaskedInputV2/internal/maskedCoreInputChange.js +49 -0
  65. package/components/MaskedInputV2/internal/maskedCoreInputChange.js.map +1 -0
  66. package/components/MaskedInputV2/internal/maskedCoreNavigation.d.ts +13 -0
  67. package/components/MaskedInputV2/internal/maskedCoreNavigation.js +79 -0
  68. package/components/MaskedInputV2/internal/maskedCoreNavigation.js.map +1 -0
  69. package/components/MaskedInputV2/internal/measureInputTextWidth.d.ts +2 -0
  70. package/components/MaskedInputV2/internal/measureInputTextWidth.js +30 -0
  71. package/components/MaskedInputV2/internal/measureInputTextWidth.js.map +1 -0
  72. package/components/MaskedInputV2/internal/setMaskInputSelectionRange.d.ts +2 -0
  73. package/components/MaskedInputV2/internal/setMaskInputSelectionRange.js +25 -0
  74. package/components/MaskedInputV2/internal/setMaskInputSelectionRange.js.map +1 -0
  75. package/components/MaskedInputV2/internal/showOverlay.d.ts +3 -0
  76. package/components/MaskedInputV2/internal/showOverlay.js +16 -0
  77. package/components/MaskedInputV2/internal/showOverlay.js.map +1 -0
  78. package/components/MaskedInputV2/internal/stripMaskChars.d.ts +11 -0
  79. package/components/MaskedInputV2/internal/stripMaskChars.js +20 -0
  80. package/components/MaskedInputV2/internal/stripMaskChars.js.map +1 -0
  81. package/components/MaskedInputV2/internal/types.d.ts +74 -0
  82. package/components/MaskedInputV2/internal/types.js +2 -0
  83. package/components/MaskedInputV2/internal/types.js.map +1 -0
  84. package/components/MaskedInputV2/internal/useInputOverflow.d.ts +4 -0
  85. package/components/MaskedInputV2/internal/useInputOverflow.js +34 -0
  86. package/components/MaskedInputV2/internal/useInputOverflow.js.map +1 -0
  87. package/components/MaskedInputV2/internal/useMaskAlignPadding.d.ts +2 -0
  88. package/components/MaskedInputV2/internal/useMaskAlignPadding.js +33 -0
  89. package/components/MaskedInputV2/internal/useMaskAlignPadding.js.map +1 -0
  90. package/components/MaskedInputV2/internal/useMaskEngine.d.ts +42 -0
  91. package/components/MaskedInputV2/internal/useMaskEngine.js +84 -0
  92. package/components/MaskedInputV2/internal/useMaskEngine.js.map +1 -0
  93. package/components/MaskedInputV2/internal/useMaskedCoreHandlers.d.ts +34 -0
  94. package/components/MaskedInputV2/internal/useMaskedCoreHandlers.js +311 -0
  95. package/components/MaskedInputV2/internal/useMaskedCoreHandlers.js.map +1 -0
  96. package/components/MaskedInputV2/react-imask/imask/controls/html-input-mask-element.d.ts +16 -0
  97. package/components/MaskedInputV2/react-imask/imask/controls/html-input-mask-element.js +59 -0
  98. package/components/MaskedInputV2/react-imask/imask/controls/html-input-mask-element.js.map +1 -0
  99. package/components/MaskedInputV2/react-imask/imask/controls/html-mask-element.d.ts +20 -0
  100. package/components/MaskedInputV2/react-imask/imask/controls/html-mask-element.js +106 -0
  101. package/components/MaskedInputV2/react-imask/imask/controls/html-mask-element.js.map +1 -0
  102. package/components/MaskedInputV2/react-imask/imask/controls/input-history.d.ts +17 -0
  103. package/components/MaskedInputV2/react-imask/imask/controls/input-history.js +49 -0
  104. package/components/MaskedInputV2/react-imask/imask/controls/input-history.js.map +1 -0
  105. package/components/MaskedInputV2/react-imask/imask/controls/input.d.ts +95 -0
  106. package/components/MaskedInputV2/react-imask/imask/controls/input.js +420 -0
  107. package/components/MaskedInputV2/react-imask/imask/controls/input.js.map +1 -0
  108. package/components/MaskedInputV2/react-imask/imask/controls/mask-element.d.ts +30 -0
  109. package/components/MaskedInputV2/react-imask/imask/controls/mask-element.js +59 -0
  110. package/components/MaskedInputV2/react-imask/imask/controls/mask-element.js.map +1 -0
  111. package/components/MaskedInputV2/react-imask/imask/core/action-details.d.ts +30 -0
  112. package/components/MaskedInputV2/react-imask/imask/core/action-details.js +100 -0
  113. package/components/MaskedInputV2/react-imask/imask/core/action-details.js.map +1 -0
  114. package/components/MaskedInputV2/react-imask/imask/core/change-details.d.ts +20 -0
  115. package/components/MaskedInputV2/react-imask/imask/core/change-details.js +46 -0
  116. package/components/MaskedInputV2/react-imask/imask/core/change-details.js.map +1 -0
  117. package/components/MaskedInputV2/react-imask/imask/core/continuous-tail-details.d.ts +21 -0
  118. package/components/MaskedInputV2/react-imask/imask/core/continuous-tail-details.js +52 -0
  119. package/components/MaskedInputV2/react-imask/imask/core/continuous-tail-details.js.map +1 -0
  120. package/components/MaskedInputV2/react-imask/imask/core/holder.d.ts +34 -0
  121. package/components/MaskedInputV2/react-imask/imask/core/holder.js +38 -0
  122. package/components/MaskedInputV2/react-imask/imask/core/holder.js.map +1 -0
  123. package/components/MaskedInputV2/react-imask/imask/core/tail-details.d.ts +20 -0
  124. package/components/MaskedInputV2/react-imask/imask/core/tail-details.js +2 -0
  125. package/components/MaskedInputV2/react-imask/imask/core/tail-details.js.map +1 -0
  126. package/components/MaskedInputV2/react-imask/imask/core/utils.d.ts +24 -0
  127. package/components/MaskedInputV2/react-imask/imask/core/utils.js +100 -0
  128. package/components/MaskedInputV2/react-imask/imask/core/utils.js.map +1 -0
  129. package/components/MaskedInputV2/react-imask/imask/imask.d.ts +5 -0
  130. package/components/MaskedInputV2/react-imask/imask/imask.js +7 -0
  131. package/components/MaskedInputV2/react-imask/imask/imask.js.map +1 -0
  132. package/components/MaskedInputV2/react-imask/imask/index.d.ts +17 -0
  133. package/components/MaskedInputV2/react-imask/imask/index.js +16 -0
  134. package/components/MaskedInputV2/react-imask/imask/index.js.map +1 -0
  135. package/components/MaskedInputV2/react-imask/imask/masked/base.d.ts +114 -0
  136. package/components/MaskedInputV2/react-imask/imask/masked/base.js +411 -0
  137. package/components/MaskedInputV2/react-imask/imask/masked/base.js.map +1 -0
  138. package/components/MaskedInputV2/react-imask/imask/masked/create.d.ts +14 -0
  139. package/components/MaskedInputV2/react-imask/imask/masked/create.js +11 -0
  140. package/components/MaskedInputV2/react-imask/imask/masked/create.js.map +1 -0
  141. package/components/MaskedInputV2/react-imask/imask/masked/factory.d.ts +62 -0
  142. package/components/MaskedInputV2/react-imask/imask/masked/factory.js +107 -0
  143. package/components/MaskedInputV2/react-imask/imask/masked/factory.js.map +1 -0
  144. package/components/MaskedInputV2/react-imask/imask/masked/pattern.d.ts +101 -0
  145. package/components/MaskedInputV2/react-imask/imask/masked/pattern.js +549 -0
  146. package/components/MaskedInputV2/react-imask/imask/masked/pattern.js.map +1 -0
  147. package/components/MaskedInputV2/react-imask/imask/masked/patterns/block.d.ts +30 -0
  148. package/components/MaskedInputV2/react-imask/imask/masked/patterns/block.js +2 -0
  149. package/components/MaskedInputV2/react-imask/imask/masked/patterns/block.js.map +1 -0
  150. package/components/MaskedInputV2/react-imask/imask/masked/patterns/chunk-tail-details.d.ts +20 -0
  151. package/components/MaskedInputV2/react-imask/imask/masked/patterns/chunk-tail-details.js +182 -0
  152. package/components/MaskedInputV2/react-imask/imask/masked/patterns/chunk-tail-details.js.map +1 -0
  153. package/components/MaskedInputV2/react-imask/imask/masked/patterns/cursor.d.ts +31 -0
  154. package/components/MaskedInputV2/react-imask/imask/masked/patterns/cursor.js +163 -0
  155. package/components/MaskedInputV2/react-imask/imask/masked/patterns/cursor.js.map +1 -0
  156. package/components/MaskedInputV2/react-imask/imask/masked/patterns/fixed-definition.d.ts +42 -0
  157. package/components/MaskedInputV2/react-imask/imask/masked/patterns/fixed-definition.js +158 -0
  158. package/components/MaskedInputV2/react-imask/imask/masked/patterns/fixed-definition.js.map +1 -0
  159. package/components/MaskedInputV2/react-imask/imask/masked/patterns/input-definition.d.ts +56 -0
  160. package/components/MaskedInputV2/react-imask/imask/masked/patterns/input-definition.js +185 -0
  161. package/components/MaskedInputV2/react-imask/imask/masked/patterns/input-definition.js.map +1 -0
  162. package/components/MaskedInputV2/react-imask/imask/masked/regexp.d.ts +17 -0
  163. package/components/MaskedInputV2/react-imask/imask/masked/regexp.js +36 -0
  164. package/components/MaskedInputV2/react-imask/imask/masked/regexp.js.map +1 -0
  165. package/components/MaskedInputV2/react-imask/index.d.ts +3 -0
  166. package/components/MaskedInputV2/react-imask/index.js +4 -0
  167. package/components/MaskedInputV2/react-imask/index.js.map +1 -0
  168. package/components/MaskedInputV2/react-imask/input.d.ts +8 -0
  169. package/components/MaskedInputV2/react-imask/input.js +35 -0
  170. package/components/MaskedInputV2/react-imask/input.js.map +1 -0
  171. package/components/MaskedInputV2/react-imask/mixin.d.ts +31 -0
  172. package/components/MaskedInputV2/react-imask/mixin.js +246 -0
  173. package/components/MaskedInputV2/react-imask/mixin.js.map +1 -0
  174. package/lib/events/keyboard/KeyboardEventCodes.d.ts +2 -0
  175. package/lib/events/keyboard/KeyboardEventCodes.js +2 -0
  176. package/lib/events/keyboard/KeyboardEventCodes.js.map +1 -1
  177. package/lib/events/keyboard/KeyboardMapKeys.js +2 -0
  178. package/lib/events/keyboard/KeyboardMapKeys.js.map +1 -1
  179. package/lib/events/keyboard/identifiers.d.ts +2 -0
  180. package/lib/events/keyboard/identifiers.js +6 -0
  181. package/lib/events/keyboard/identifiers.js.map +1 -1
  182. package/lib/featureFlagsContext/ReactUIFeatureFlagsContext.d.ts +1 -0
  183. package/lib/featureFlagsContext/ReactUIFeatureFlagsContext.js +1 -0
  184. package/lib/featureFlagsContext/ReactUIFeatureFlagsContext.js.map +1 -1
  185. package/package.json +4 -1
@@ -0,0 +1,74 @@
1
+ import type { MaskedPattern } from '../react-imask/imask/index.js';
2
+ export interface MaskEngine {
3
+ compute(raw: string, focused: boolean): MaskState;
4
+ applyPaste(currentRaw: string, rawCursorPos: number, pasted: string): PasteResult;
5
+ slotMap: SlotMap;
6
+ imask: MaskedPattern;
7
+ }
8
+ export interface PasteResult {
9
+ raw: string;
10
+ overflow: boolean;
11
+ }
12
+ export interface MaskState {
13
+ /**
14
+ * Значение для <input value=...>.
15
+ * focused=true, alwaysShowMask=false: "12__" (с плейсхолдерами)
16
+ * focused=false, alwaysShowMask=false: "12" (lazy, без плейсхолдеров)
17
+ * alwaysShowMask=true: "12__" всегда
18
+ */
19
+ displayValue: string;
20
+ /**
21
+ * Подстрока displayValue от начала до конца последнего введённого символа
22
+ * (включая разделители маски внутри введённой части).
23
+ *
24
+ * mask="99.99", typed="12": displayValue="12.34" (нет — мы в данном примере typed="1234")
25
+ * mask="99.99", typed="12": displayValue="12.__", typedValue="12." ^^^
26
+ */
27
+ typedValue: string;
28
+ /**
29
+ * Длина typedValue в символах.
30
+ * typedValue="12." → typedLength=3
31
+ */
32
+ typedLength: number;
33
+ /**
34
+ * Значение для onValueChange.
35
+ * unmask=false: imask.value ("12.")
36
+ * unmask=true: imask.unmaskedValue ("12")
37
+ */
38
+ outputValue: string;
39
+ /**
40
+ * Маска заполнена полностью.
41
+ */
42
+ isComplete: boolean;
43
+ /**
44
+ * Количество принятых IMask пользовательских символов.
45
+ * raw="12345" для mask="999" → acceptedLength=3 ("123").
46
+ */
47
+ acceptedLength: number;
48
+ }
49
+ export interface HistoryState {
50
+ raw: string;
51
+ cursorPos: number;
52
+ }
53
+ export interface SlotMap {
54
+ /**
55
+ * Позиции пользовательских слотов в displayValue (при lazy=false, все плейсхолдеры видны).
56
+ * mask="99.99" → userSlots=[0, 1, 3, 4]
57
+ * displayValue="_._._" (пустое поле, alwaysShowMask)
58
+ */
59
+ userSlots: number[];
60
+ /**
61
+ * maskedToRaw[maskedPos] → rawPos | null
62
+ * null означает: позиция принадлежит фиксированному символу маски.
63
+ *
64
+ * mask="99.99": displayValue="_._._"
65
+ * maskedToRaw = [0, 1, null, 2, 3]
66
+ */
67
+ maskedToRaw: Array<number | null>;
68
+ /**
69
+ * rawToMasked[rawPos] → maskedPos
70
+ * Обратный maskedToRaw, только для пользовательских позиций.
71
+ * mask="99.99": rawToMasked = [0, 1, 3, 4]
72
+ */
73
+ rawToMasked: number[];
74
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["types.ts"],"names":[],"mappings":"","sourcesContent":["import type { MaskedPattern } from '../react-imask/imask/index.js';\n\nexport interface MaskEngine {\n compute(raw: string, focused: boolean): MaskState;\n applyPaste(currentRaw: string, rawCursorPos: number, pasted: string): PasteResult;\n slotMap: SlotMap;\n imask: MaskedPattern;\n}\n\nexport interface PasteResult {\n raw: string;\n overflow: boolean;\n}\n\nexport interface MaskState {\n /**\n * Значение для <input value=...>.\n * focused=true, alwaysShowMask=false: \"12__\" (с плейсхолдерами)\n * focused=false, alwaysShowMask=false: \"12\" (lazy, без плейсхолдеров)\n * alwaysShowMask=true: \"12__\" всегда\n */\n displayValue: string;\n\n /**\n * Подстрока displayValue от начала до конца последнего введённого символа\n * (включая разделители маски внутри введённой части).\n *\n * mask=\"99.99\", typed=\"12\": displayValue=\"12.34\" (нет — мы в данном примере typed=\"1234\")\n * mask=\"99.99\", typed=\"12\": displayValue=\"12.__\", typedValue=\"12.\" ^^^\n */\n typedValue: string;\n\n /**\n * Длина typedValue в символах.\n * typedValue=\"12.\" → typedLength=3\n */\n typedLength: number;\n\n /**\n * Значение для onValueChange.\n * unmask=false: imask.value (\"12.\")\n * unmask=true: imask.unmaskedValue (\"12\")\n */\n outputValue: string;\n\n /**\n * Маска заполнена полностью.\n */\n isComplete: boolean;\n\n /**\n * Количество принятых IMask пользовательских символов.\n * raw=\"12345\" для mask=\"999\" → acceptedLength=3 (\"123\").\n */\n acceptedLength: number;\n}\n\nexport interface HistoryState {\n raw: string;\n cursorPos: number;\n}\n\nexport interface SlotMap {\n /**\n * Позиции пользовательских слотов в displayValue (при lazy=false, все плейсхолдеры видны).\n * mask=\"99.99\" → userSlots=[0, 1, 3, 4]\n * displayValue=\"_._._\" (пустое поле, alwaysShowMask)\n */\n userSlots: number[];\n\n /**\n * maskedToRaw[maskedPos] → rawPos | null\n * null означает: позиция принадлежит фиксированному символу маски.\n *\n * mask=\"99.99\": displayValue=\"_._._\"\n * maskedToRaw = [0, 1, null, 2, 3]\n */\n maskedToRaw: Array<number | null>;\n\n /**\n * rawToMasked[rawPos] → maskedPos\n * Обратный maskedToRaw, только для пользовательских позиций.\n * mask=\"99.99\": rawToMasked = [0, 1, 3, 4]\n */\n rawToMasked: number[];\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type React from 'react';
2
+ export declare function isInputTextOverflowing(input: HTMLInputElement, displayValue: string): boolean;
3
+ /** Горизонтальное переполнение текста внутри input. */
4
+ export declare function useInputOverflow(inputRef: React.RefObject<HTMLInputElement | null>, displayValue: string, remeasureKey: unknown): boolean;
@@ -0,0 +1,34 @@
1
+ import { useLayoutEffect, useState } from 'react';
2
+ import { measureInputTextWidth } from './measureInputTextWidth.js';
3
+ export function isInputTextOverflowing(input, displayValue) {
4
+ if (input.scrollWidth > input.clientWidth) {
5
+ return true;
6
+ }
7
+ var text = input.value || displayValue;
8
+ return measureInputTextWidth(input, text) > input.clientWidth;
9
+ }
10
+ /** Горизонтальное переполнение текста внутри input. */
11
+ export function useInputOverflow(inputRef, displayValue, remeasureKey) {
12
+ var _a = useState(false), overflow = _a[0], setOverflow = _a[1];
13
+ useLayoutEffect(function () {
14
+ var input = inputRef.current;
15
+ if (!input) {
16
+ return;
17
+ }
18
+ var measure = function () {
19
+ setOverflow(function (prev) {
20
+ var next = isInputTextOverflowing(input, displayValue);
21
+ return prev === next ? prev : next;
22
+ });
23
+ };
24
+ measure();
25
+ if (typeof ResizeObserver === 'undefined') {
26
+ return;
27
+ }
28
+ var observer = new ResizeObserver(measure);
29
+ observer.observe(input);
30
+ return function () { return observer.disconnect(); };
31
+ }, [displayValue, inputRef, remeasureKey]);
32
+ return overflow;
33
+ }
34
+ //# sourceMappingURL=useInputOverflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useInputOverflow.js","sourceRoot":"","sources":["useInputOverflow.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,MAAM,UAAU,sBAAsB,CAAC,KAAuB,EAAE,YAAoB;IAClF,IAAI,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAM,IAAI,GAAG,KAAK,CAAC,KAAK,IAAI,YAAY,CAAC;IACzC,OAAO,qBAAqB,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC;AAChE,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,gBAAgB,CAC9B,QAAkD,EAClD,YAAoB,EACpB,YAAqB;IAEf,IAAA,KAA0B,QAAQ,CAAC,KAAK,CAAC,EAAxC,QAAQ,QAAA,EAAE,WAAW,QAAmB,CAAC;IAEhD,eAAe,CAAC;QACd,IAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QAED,IAAM,OAAO,GAAG;YACd,WAAW,CAAC,UAAC,IAAI;gBACf,IAAM,IAAI,GAAG,sBAAsB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;gBACzD,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACrC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,OAAO,EAAE,CAAC;QAEV,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;YAC1C,OAAO;QACT,CAAC;QAED,IAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,OAAO,CAAC,CAAC;QAC7C,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAExB,OAAO,cAAM,OAAA,QAAQ,CAAC,UAAU,EAAE,EAArB,CAAqB,CAAC;IACrC,CAAC,EAAE,CAAC,YAAY,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAE3C,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import type React from 'react';\nimport { useLayoutEffect, useState } from 'react';\n\nimport { measureInputTextWidth } from './measureInputTextWidth.js';\n\nexport function isInputTextOverflowing(input: HTMLInputElement, displayValue: string): boolean {\n if (input.scrollWidth > input.clientWidth) {\n return true;\n }\n\n const text = input.value || displayValue;\n return measureInputTextWidth(input, text) > input.clientWidth;\n}\n\n/** Горизонтальное переполнение текста внутри input. */\nexport function useInputOverflow(\n inputRef: React.RefObject<HTMLInputElement | null>,\n displayValue: string,\n remeasureKey: unknown,\n): boolean {\n const [overflow, setOverflow] = useState(false);\n\n useLayoutEffect(() => {\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n const measure = () => {\n setOverflow((prev) => {\n const next = isInputTextOverflowing(input, displayValue);\n return prev === next ? prev : next;\n });\n };\n\n measure();\n\n if (typeof ResizeObserver === 'undefined') {\n return;\n }\n\n const observer = new ResizeObserver(measure);\n observer.observe(input);\n\n return () => observer.disconnect();\n }, [displayValue, inputRef, remeasureKey]);\n\n return overflow;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import type React from 'react';
2
+ export declare function useMaskAlignPadding(inputRef: React.RefObject<HTMLInputElement | null>, overlayRef: React.RefObject<HTMLElement | null>, displayValue: string, textAlign: React.CSSProperties['textAlign'] | undefined, enabled: boolean): number;
@@ -0,0 +1,33 @@
1
+ import { useLayoutEffect, useState } from 'react';
2
+ import { computeMaskAlignPadding, needsMaskAlignPadding } from './computeMaskAlignPadding.js';
3
+ export function useMaskAlignPadding(inputRef, overlayRef, displayValue, textAlign, enabled) {
4
+ var _a = useState(0), paddingLeft = _a[0], setPaddingLeft = _a[1];
5
+ useLayoutEffect(function () {
6
+ if (!enabled || !needsMaskAlignPadding(textAlign)) {
7
+ setPaddingLeft(0);
8
+ return;
9
+ }
10
+ var input = inputRef.current;
11
+ if (!input) {
12
+ return;
13
+ }
14
+ var update = function () {
15
+ setPaddingLeft(function (prev) {
16
+ var next = computeMaskAlignPadding(input, displayValue, textAlign, overlayRef.current);
17
+ return prev === next ? prev : next;
18
+ });
19
+ };
20
+ update();
21
+ if (typeof ResizeObserver === 'undefined') {
22
+ return;
23
+ }
24
+ var observer = new ResizeObserver(update);
25
+ observer.observe(input);
26
+ if (overlayRef.current) {
27
+ observer.observe(overlayRef.current);
28
+ }
29
+ return function () { return observer.disconnect(); };
30
+ }, [displayValue, enabled, inputRef, overlayRef, textAlign]);
31
+ return paddingLeft;
32
+ }
33
+ //# sourceMappingURL=useMaskAlignPadding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMaskAlignPadding.js","sourceRoot":"","sources":["useMaskAlignPadding.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAElD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,MAAM,UAAU,mBAAmB,CACjC,QAAkD,EAClD,UAA+C,EAC/C,YAAoB,EACpB,SAAuD,EACvD,OAAgB;IAEV,IAAA,KAAgC,QAAQ,CAAC,CAAC,CAAC,EAA1C,WAAW,QAAA,EAAE,cAAc,QAAe,CAAC;IAElD,eAAe,CAAC;QACd,IAAI,CAAC,OAAO,IAAI,CAAC,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;YAClD,cAAc,CAAC,CAAC,CAAC,CAAC;YAClB,OAAO;QACT,CAAC;QAED,IAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QAED,IAAM,MAAM,GAAG;YACb,cAAc,CAAC,UAAC,IAAI;gBAClB,IAAM,IAAI,GAAG,uBAAuB,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;gBACzF,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACrC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,MAAM,EAAE,CAAC;QAET,IAAI,OAAO,cAAc,KAAK,WAAW,EAAE,CAAC;YAC1C,OAAO;QACT,CAAC;QAED,IAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QAC5C,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;YACvB,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QAED,OAAO,cAAM,OAAA,QAAQ,CAAC,UAAU,EAAE,EAArB,CAAqB,CAAC;IACrC,CAAC,EAAE,CAAC,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;IAE7D,OAAO,WAAW,CAAC;AACrB,CAAC","sourcesContent":["import type React from 'react';\nimport { useLayoutEffect, useState } from 'react';\n\nimport { computeMaskAlignPadding, needsMaskAlignPadding } from './computeMaskAlignPadding.js';\n\nexport function useMaskAlignPadding(\n inputRef: React.RefObject<HTMLInputElement | null>,\n overlayRef: React.RefObject<HTMLElement | null>,\n displayValue: string,\n textAlign: React.CSSProperties['textAlign'] | undefined,\n enabled: boolean,\n): number {\n const [paddingLeft, setPaddingLeft] = useState(0);\n\n useLayoutEffect(() => {\n if (!enabled || !needsMaskAlignPadding(textAlign)) {\n setPaddingLeft(0);\n return;\n }\n\n const input = inputRef.current;\n if (!input) {\n return;\n }\n\n const update = () => {\n setPaddingLeft((prev) => {\n const next = computeMaskAlignPadding(input, displayValue, textAlign, overlayRef.current);\n return prev === next ? prev : next;\n });\n };\n\n update();\n\n if (typeof ResizeObserver === 'undefined') {\n return;\n }\n\n const observer = new ResizeObserver(update);\n observer.observe(input);\n if (overlayRef.current) {\n observer.observe(overlayRef.current);\n }\n\n return () => observer.disconnect();\n }, [displayValue, enabled, inputRef, overlayRef, textAlign]);\n\n return paddingLeft;\n}\n"]}
@@ -0,0 +1,42 @@
1
+ import type { MaskedPattern, MaskedPatternOptions } from '../react-imask/imask/index.js';
2
+ import type { IMaskInputProps } from '../react-imask/index.js';
3
+ import type { MaskState, SlotMap } from './types.js';
4
+ export interface MaskEngine {
5
+ /**
6
+ * Применить raw-ввод, получить MaskState.
7
+ * Чистая функция (без побочных эффектов на внешний стейт).
8
+ */
9
+ compute(raw: string, focused: boolean): MaskState;
10
+ /**
11
+ * Применить вставку с учётом текущего курсора.
12
+ * Возвращает новый raw и флаг переполнения.
13
+ */
14
+ applyPaste(currentRaw: string, rawCursorPos: number, pasted: string): PasteResult;
15
+ /** Карта слотов. Пересчитывается только при смене маски. */
16
+ slotMap: SlotMap;
17
+ /** Доступ к IMask-инстансу для edge cases (imaskProps escape hatch). */
18
+ imask: MaskedPattern;
19
+ }
20
+ interface PasteResult {
21
+ raw: string;
22
+ overflow: boolean;
23
+ }
24
+ export type MaskEager = NonNullable<MaskedPatternOptions['eager']>;
25
+ /** Пропсы хука {@link useMaskEngine}. */
26
+ interface UseMaskEngineProps {
27
+ mask: string;
28
+ maskChar?: string;
29
+ formatChars?: Record<string, string>;
30
+ unmask: boolean;
31
+ alwaysShowMask: boolean;
32
+ imaskProps?: IMaskInputProps<HTMLInputElement>;
33
+ }
34
+ /**
35
+ * Создаёт headless IMask-движок для MaskedInputV2.
36
+ * IMask используется как калькулятор состояния, без привязки к DOM.
37
+ *
38
+ * @param props — настройки маски и поведения отображения.
39
+ * @returns объект {@link MaskEngine} с методами `compute`, `applyPaste`, `slotMap` и `imask`.
40
+ */
41
+ export declare function useMaskEngine(props: UseMaskEngineProps): MaskEngine;
42
+ export {};
@@ -0,0 +1,84 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ import { useMemo } from 'react';
13
+ import { getDefinitions, getMaskChar } from '../MaskedInputV2.helpers.js';
14
+ import { createMask } from '../react-imask/imask/masked/create.js';
15
+ import { buildSlotMap, extractRaw } from './helpers.js';
16
+ /**
17
+ * Создаёт headless IMask-движок для MaskedInputV2.
18
+ * IMask используется как калькулятор состояния, без привязки к DOM.
19
+ *
20
+ * @param props — настройки маски и поведения отображения.
21
+ * @returns объект {@link MaskEngine} с методами `compute`, `applyPaste`, `slotMap` и `imask`.
22
+ */
23
+ export function useMaskEngine(props) {
24
+ var _a, _b;
25
+ var mask = (_a = props.mask) !== null && _a !== void 0 ? _a : '';
26
+ var eager = (_b = props.imaskProps) === null || _b === void 0 ? void 0 : _b.eager;
27
+ var imask = useMemo(function () {
28
+ return createMask(__assign({ mask: mask.replace(/0/g, '{\\0}'), placeholderChar: getMaskChar(props.maskChar), definitions: getDefinitions(props.formatChars), eager: eager !== null && eager !== void 0 ? eager : 'append', overwrite: 'shift', lazy: true }, props.imaskProps));
29
+ }, [mask, props.imaskProps, props.maskChar, eager, JSON.stringify(props.formatChars)]);
30
+ // SlotMap пересчитывается при смене маски
31
+ var slotMap = useMemo(function () { return buildSlotMap(imask); }, [imask]);
32
+ function compute(raw, focused) {
33
+ var lazy = !props.alwaysShowMask && !focused;
34
+ var eagerAppend = imask.eager === 'append' || imask.eager === true;
35
+ // raw — только пользовательские слоты. resolve({ input: true }) съел бы цифру,
36
+ // совпадающую с литералом маски (`7` в `7 999` / первая `7` после `+7`).
37
+ imask.updateOptions({ lazy: true });
38
+ imask.rawInputValue = raw;
39
+ // raw-флаг не триггерит eager trailing (это делал flags.input) — добираем вручную.
40
+ if (eagerAppend && raw) {
41
+ imask._appendEager();
42
+ }
43
+ if (focused && !raw && eagerAppend) {
44
+ imask._appendEager();
45
+ }
46
+ var lazyValue = imask.value;
47
+ var displayValue = lazyValue;
48
+ var typedValue = lazyValue;
49
+ if (!lazy) {
50
+ imask.updateOptions({ lazy: false });
51
+ imask.rawInputValue = raw;
52
+ if (eagerAppend && raw) {
53
+ imask._appendEager();
54
+ }
55
+ displayValue = imask.displayValue;
56
+ }
57
+ var unmaskedValue = raw === '' ? '' : imask.unmaskedValue;
58
+ var maskedValue = raw === '' ? '' : lazyValue;
59
+ return {
60
+ displayValue: displayValue,
61
+ typedValue: typedValue,
62
+ typedLength: typedValue.length,
63
+ outputValue: props.unmask ? unmaskedValue : maskedValue,
64
+ isComplete: imask.isComplete,
65
+ acceptedLength: imask.unmaskedValue.length,
66
+ };
67
+ }
68
+ function applyPaste(currentRaw, rawCursorPos, pasted) {
69
+ var before = currentRaw.slice(0, rawCursorPos);
70
+ var after = currentRaw.slice(rawCursorPos);
71
+ // Уже «сырые» цифры (в т.ч. после normalizeRussianPhonePaste) нельзя прогонять через
72
+ // extractRaw/.value (input:true): ведущая 7 съестся литералом `+7` / `7 …`.
73
+ var pastedRaw = /^\d+$/.test(pasted) ? pasted : extractRaw(pasted, { imask: imask });
74
+ var candidate = before + pastedRaw + after;
75
+ imask.rawInputValue = candidate;
76
+ var accepted = imask.rawInputValue;
77
+ return {
78
+ raw: accepted,
79
+ overflow: accepted.length < candidate.length,
80
+ };
81
+ }
82
+ return { compute: compute, applyPaste: applyPaste, slotMap: slotMap, imask: imask };
83
+ }
84
+ //# sourceMappingURL=useMaskEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMaskEngine.js","sourceRoot":"","sources":["useMaskEngine.ts"],"names":[],"mappings":"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","sourcesContent":["import { useMemo } from 'react';\n\nimport { getDefinitions, getMaskChar } from '../MaskedInputV2.helpers.js';\nimport type { MaskedPattern, MaskedPatternOptions } from '../react-imask/imask/index.js';\nimport { createMask } from '../react-imask/imask/masked/create.js';\nimport type { IMaskInputProps } from '../react-imask/index.js';\nimport { buildSlotMap, extractRaw } from './helpers.js';\nimport type { MaskState, SlotMap } from './types.js';\n\nexport interface MaskEngine {\n /**\n * Применить raw-ввод, получить MaskState.\n * Чистая функция (без побочных эффектов на внешний стейт).\n */\n compute(raw: string, focused: boolean): MaskState;\n\n /**\n * Применить вставку с учётом текущего курсора.\n * Возвращает новый raw и флаг переполнения.\n */\n applyPaste(currentRaw: string, rawCursorPos: number, pasted: string): PasteResult;\n\n /** Карта слотов. Пересчитывается только при смене маски. */\n slotMap: SlotMap;\n\n /** Доступ к IMask-инстансу для edge cases (imaskProps escape hatch). */\n imask: MaskedPattern;\n}\n\ninterface PasteResult {\n raw: string;\n overflow: boolean;\n}\n\nexport type MaskEager = NonNullable<MaskedPatternOptions['eager']>;\n\n/** Пропсы хука {@link useMaskEngine}. */\ninterface UseMaskEngineProps {\n mask: string;\n maskChar?: string;\n formatChars?: Record<string, string>;\n unmask: boolean;\n alwaysShowMask: boolean;\n imaskProps?: IMaskInputProps<HTMLInputElement>;\n}\n\n/**\n * Создаёт headless IMask-движок для MaskedInputV2.\n * IMask используется как калькулятор состояния, без привязки к DOM.\n *\n * @param props — настройки маски и поведения отображения.\n * @returns объект {@link MaskEngine} с методами `compute`, `applyPaste`, `slotMap` и `imask`.\n */\nexport function useMaskEngine(props: UseMaskEngineProps): MaskEngine {\n const mask = props.mask ?? '';\n const eager = props.imaskProps?.eager;\n const imask = useMemo(\n () =>\n createMask({\n mask: mask.replace(/0/g, '{\\\\0}') as any,\n placeholderChar: getMaskChar(props.maskChar),\n definitions: getDefinitions(props.formatChars),\n eager: eager ?? 'append',\n overwrite: 'shift',\n lazy: true,\n ...(props.imaskProps as object),\n }) as unknown as MaskedPattern,\n [mask, props.imaskProps, props.maskChar, eager, JSON.stringify(props.formatChars)],\n );\n\n // SlotMap пересчитывается при смене маски\n const slotMap = useMemo(() => buildSlotMap(imask), [imask]);\n\n function compute(raw: string, focused: boolean): MaskState {\n const lazy = !props.alwaysShowMask && !focused;\n const eagerAppend = imask.eager === 'append' || imask.eager === true;\n\n // raw — только пользовательские слоты. resolve({ input: true }) съел бы цифру,\n // совпадающую с литералом маски (`7` в `7 999` / первая `7` после `+7`).\n imask.updateOptions({ lazy: true });\n imask.rawInputValue = raw;\n // raw-флаг не триггерит eager trailing (это делал flags.input) — добираем вручную.\n if (eagerAppend && raw) {\n imask._appendEager();\n }\n if (focused && !raw && eagerAppend) {\n imask._appendEager();\n }\n const lazyValue = imask.value;\n\n let displayValue = lazyValue;\n let typedValue = lazyValue;\n\n if (!lazy) {\n imask.updateOptions({ lazy: false });\n imask.rawInputValue = raw;\n if (eagerAppend && raw) {\n imask._appendEager();\n }\n displayValue = imask.displayValue;\n }\n\n const unmaskedValue = raw === '' ? '' : imask.unmaskedValue;\n const maskedValue = raw === '' ? '' : lazyValue;\n return {\n displayValue,\n typedValue,\n typedLength: typedValue.length,\n outputValue: props.unmask ? unmaskedValue : maskedValue,\n isComplete: imask.isComplete,\n acceptedLength: imask.unmaskedValue.length,\n };\n }\n\n function applyPaste(currentRaw: string, rawCursorPos: number, pasted: string): PasteResult {\n const before = currentRaw.slice(0, rawCursorPos);\n const after = currentRaw.slice(rawCursorPos);\n\n // Уже «сырые» цифры (в т.ч. после normalizeRussianPhonePaste) нельзя прогонять через\n // extractRaw/.value (input:true): ведущая 7 съестся литералом `+7` / `7 …`.\n const pastedRaw = /^\\d+$/.test(pasted) ? pasted : extractRaw(pasted, { imask });\n const candidate = before + pastedRaw + after;\n\n imask.rawInputValue = candidate;\n const accepted = imask.rawInputValue;\n\n return {\n raw: accepted,\n overflow: accepted.length < candidate.length,\n };\n }\n\n return { compute, applyPaste, slotMap, imask };\n}\n"]}
@@ -0,0 +1,34 @@
1
+ import type React from 'react';
2
+ import type { MaskedCoreProps, MaskedSelectionIntent } from './MaskedCore.types.js';
3
+ type MaskedCoreHandlerProps = Pick<MaskedCoreProps, 'maskState' | 'slotMap' | 'engine' | 'currentRaw' | 'onRawChange' | 'onUnexpectedInput' | 'onUndo' | 'onRedo' | 'coreInputRef' | 'onKeyDown' | 'onMouseUp' | 'onInput' | 'onSelect' | 'onFocus' | 'onBlur' | 'onPaste' | 'selectAllOnFocus'> & {
4
+ syncOverlayScroll: () => void;
5
+ requestSelectionIntent: (intent: MaskedSelectionIntent) => void;
6
+ };
7
+ /**
8
+ * Собирает обработчики DOM-событий для {@link MaskedCore}.
9
+ * Инкапсулирует логику ввода, навигации, clipboard и undo/redo.
10
+ *
11
+ * @param props — состояние маски, движок и колбэки от MaskedInputV2.
12
+ * @returns refs и обработчики для прямого `<input>`.
13
+ */
14
+ export declare function useMaskedCoreHandlers(props: MaskedCoreHandlerProps): {
15
+ pendingCursorRef: React.RefObject<number | null>;
16
+ selectionRange: {
17
+ start: number;
18
+ end: number;
19
+ };
20
+ syncSelection: (el: HTMLInputElement) => void;
21
+ handleChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
22
+ handleKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void;
23
+ handleSelect: (e?: React.SyntheticEvent<HTMLInputElement>) => void;
24
+ handlePaste: (e: React.ClipboardEvent<HTMLInputElement>) => void;
25
+ handleBeforeInput: (e: React.FormEvent<HTMLInputElement>) => void;
26
+ handleCopy: (e: React.ClipboardEvent<HTMLInputElement>) => void;
27
+ handleCut: (e: React.ClipboardEvent<HTMLInputElement>) => void;
28
+ handleInput: (e: React.ChangeEvent<HTMLInputElement>) => void;
29
+ handleMouseDown: () => void;
30
+ handleMouseUp: (e: React.MouseEvent<HTMLInputElement>) => void;
31
+ handleFocus: (e: React.FocusEvent<HTMLInputElement>) => void;
32
+ handleBlur: (e: React.FocusEvent<HTMLInputElement>) => void;
33
+ };
34
+ export {};