@skbkontur/react-ui 6.1.4 → 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 (246) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/components/Button/Button.classes.d.ts +8 -0
  3. package/components/Button/Button.classes.js +10 -0
  4. package/components/Button/Button.classes.js.map +1 -0
  5. package/components/Button/Button.mixins.js +1 -1
  6. package/components/Button/Button.mixins.js.map +1 -1
  7. package/components/Button/Button.styles.d.ts +2 -8
  8. package/components/Button/Button.styles.js +3 -9
  9. package/components/Button/Button.styles.js.map +1 -1
  10. package/components/Calendar/Calendar.d.ts +2 -8
  11. package/components/Calendar/Calendar.js +2 -7
  12. package/components/Calendar/Calendar.js.map +1 -1
  13. package/components/Calendar/CalendarDay.js +1 -1
  14. package/components/Calendar/CalendarDay.js.map +1 -1
  15. package/components/Calendar/MonthView.js +1 -1
  16. package/components/Calendar/MonthView.js.map +1 -1
  17. package/components/Calendar/MonthViewModel.js +1 -2
  18. package/components/Calendar/MonthViewModel.js.map +1 -1
  19. package/components/Calendar/tids.d.ts +7 -0
  20. package/components/Calendar/tids.js +8 -0
  21. package/components/Calendar/tids.js.map +1 -0
  22. package/components/FxInput/FxInput.d.ts +1 -1
  23. package/components/FxInput/FxInput.js.map +1 -1
  24. package/components/MaskedInput/MaskedInput.d.ts +6 -2
  25. package/components/MaskedInput/MaskedInput.js +10 -126
  26. package/components/MaskedInput/MaskedInput.js.map +1 -1
  27. package/components/MaskedInput/MaskedInputLegacy.d.ts +3 -0
  28. package/components/MaskedInput/MaskedInputLegacy.js +142 -0
  29. package/components/MaskedInput/MaskedInputLegacy.js.map +1 -0
  30. package/components/MaskedInput/index.d.ts +1 -0
  31. package/components/MaskedInput/index.js +1 -0
  32. package/components/MaskedInput/index.js.map +1 -1
  33. package/components/MaskedInputV2/MaskedInputV2.d.ts +62 -0
  34. package/components/MaskedInputV2/MaskedInputV2.helpers.d.ts +9 -0
  35. package/components/MaskedInputV2/MaskedInputV2.helpers.js +17 -0
  36. package/components/MaskedInputV2/MaskedInputV2.helpers.js.map +1 -0
  37. package/components/MaskedInputV2/MaskedInputV2.js +307 -0
  38. package/components/MaskedInputV2/MaskedInputV2.js.map +1 -0
  39. package/components/MaskedInputV2/MaskedInputV2.phone.d.ts +27 -0
  40. package/components/MaskedInputV2/MaskedInputV2.phone.js +37 -0
  41. package/components/MaskedInputV2/MaskedInputV2.phone.js.map +1 -0
  42. package/components/MaskedInputV2/MaskedInputV2.styles.d.ts +7 -0
  43. package/components/MaskedInputV2/MaskedInputV2.styles.js +19 -0
  44. package/components/MaskedInputV2/MaskedInputV2.styles.js.map +1 -0
  45. package/components/MaskedInputV2/index.d.ts +2 -0
  46. package/components/MaskedInputV2/index.js +3 -0
  47. package/components/MaskedInputV2/index.js.map +1 -0
  48. package/components/MaskedInputV2/internal/MaskOverlay.d.ts +19 -0
  49. package/components/MaskedInputV2/internal/MaskOverlay.js +54 -0
  50. package/components/MaskedInputV2/internal/MaskOverlay.js.map +1 -0
  51. package/components/MaskedInputV2/internal/MaskedCore.d.ts +8 -0
  52. package/components/MaskedInputV2/internal/MaskedCore.js +186 -0
  53. package/components/MaskedInputV2/internal/MaskedCore.js.map +1 -0
  54. package/components/MaskedInputV2/internal/MaskedCore.types.d.ts +37 -0
  55. package/components/MaskedInputV2/internal/MaskedCore.types.js +2 -0
  56. package/components/MaskedInputV2/internal/MaskedCore.types.js.map +1 -0
  57. package/components/MaskedInputV2/internal/MaskedInternal.styles.d.ts +15 -0
  58. package/components/MaskedInputV2/internal/MaskedInternal.styles.js +34 -0
  59. package/components/MaskedInputV2/internal/MaskedInternal.styles.js.map +1 -0
  60. package/components/MaskedInputV2/internal/buildSlotMap.d.ts +11 -0
  61. package/components/MaskedInputV2/internal/buildSlotMap.js +37 -0
  62. package/components/MaskedInputV2/internal/buildSlotMap.js.map +1 -0
  63. package/components/MaskedInputV2/internal/computeMaskAlignPadding.d.ts +6 -0
  64. package/components/MaskedInputV2/internal/computeMaskAlignPadding.js +47 -0
  65. package/components/MaskedInputV2/internal/computeMaskAlignPadding.js.map +1 -0
  66. package/components/MaskedInputV2/internal/computePasteMaskedCursor.d.ts +3 -0
  67. package/components/MaskedInputV2/internal/computePasteMaskedCursor.js +11 -0
  68. package/components/MaskedInputV2/internal/computePasteMaskedCursor.js.map +1 -0
  69. package/components/MaskedInputV2/internal/extractRaw.d.ts +10 -0
  70. package/components/MaskedInputV2/internal/extractRaw.js +16 -0
  71. package/components/MaskedInputV2/internal/extractRaw.js.map +1 -0
  72. package/components/MaskedInputV2/internal/findNearestRawLeft.d.ts +10 -0
  73. package/components/MaskedInputV2/internal/findNearestRawLeft.js +18 -0
  74. package/components/MaskedInputV2/internal/findNearestRawLeft.js.map +1 -0
  75. package/components/MaskedInputV2/internal/helpers.d.ts +8 -0
  76. package/components/MaskedInputV2/internal/helpers.js +9 -0
  77. package/components/MaskedInputV2/internal/helpers.js.map +1 -0
  78. package/components/MaskedInputV2/internal/maskedCoreClipboard.d.ts +37 -0
  79. package/components/MaskedInputV2/internal/maskedCoreClipboard.js +52 -0
  80. package/components/MaskedInputV2/internal/maskedCoreClipboard.js.map +1 -0
  81. package/components/MaskedInputV2/internal/maskedCoreDeletion.d.ts +28 -0
  82. package/components/MaskedInputV2/internal/maskedCoreDeletion.js +70 -0
  83. package/components/MaskedInputV2/internal/maskedCoreDeletion.js.map +1 -0
  84. package/components/MaskedInputV2/internal/maskedCoreInputChange.d.ts +38 -0
  85. package/components/MaskedInputV2/internal/maskedCoreInputChange.js +49 -0
  86. package/components/MaskedInputV2/internal/maskedCoreInputChange.js.map +1 -0
  87. package/components/MaskedInputV2/internal/maskedCoreNavigation.d.ts +13 -0
  88. package/components/MaskedInputV2/internal/maskedCoreNavigation.js +79 -0
  89. package/components/MaskedInputV2/internal/maskedCoreNavigation.js.map +1 -0
  90. package/components/MaskedInputV2/internal/measureInputTextWidth.d.ts +2 -0
  91. package/components/MaskedInputV2/internal/measureInputTextWidth.js +30 -0
  92. package/components/MaskedInputV2/internal/measureInputTextWidth.js.map +1 -0
  93. package/components/MaskedInputV2/internal/setMaskInputSelectionRange.d.ts +2 -0
  94. package/components/MaskedInputV2/internal/setMaskInputSelectionRange.js +25 -0
  95. package/components/MaskedInputV2/internal/setMaskInputSelectionRange.js.map +1 -0
  96. package/components/MaskedInputV2/internal/showOverlay.d.ts +3 -0
  97. package/components/MaskedInputV2/internal/showOverlay.js +16 -0
  98. package/components/MaskedInputV2/internal/showOverlay.js.map +1 -0
  99. package/components/MaskedInputV2/internal/stripMaskChars.d.ts +11 -0
  100. package/components/MaskedInputV2/internal/stripMaskChars.js +20 -0
  101. package/components/MaskedInputV2/internal/stripMaskChars.js.map +1 -0
  102. package/components/MaskedInputV2/internal/types.d.ts +74 -0
  103. package/components/MaskedInputV2/internal/types.js +2 -0
  104. package/components/MaskedInputV2/internal/types.js.map +1 -0
  105. package/components/MaskedInputV2/internal/useInputOverflow.d.ts +4 -0
  106. package/components/MaskedInputV2/internal/useInputOverflow.js +34 -0
  107. package/components/MaskedInputV2/internal/useInputOverflow.js.map +1 -0
  108. package/components/MaskedInputV2/internal/useMaskAlignPadding.d.ts +2 -0
  109. package/components/MaskedInputV2/internal/useMaskAlignPadding.js +33 -0
  110. package/components/MaskedInputV2/internal/useMaskAlignPadding.js.map +1 -0
  111. package/components/MaskedInputV2/internal/useMaskEngine.d.ts +42 -0
  112. package/components/MaskedInputV2/internal/useMaskEngine.js +84 -0
  113. package/components/MaskedInputV2/internal/useMaskEngine.js.map +1 -0
  114. package/components/MaskedInputV2/internal/useMaskedCoreHandlers.d.ts +34 -0
  115. package/components/MaskedInputV2/internal/useMaskedCoreHandlers.js +311 -0
  116. package/components/MaskedInputV2/internal/useMaskedCoreHandlers.js.map +1 -0
  117. package/components/MaskedInputV2/react-imask/imask/controls/html-input-mask-element.d.ts +16 -0
  118. package/components/MaskedInputV2/react-imask/imask/controls/html-input-mask-element.js +59 -0
  119. package/components/MaskedInputV2/react-imask/imask/controls/html-input-mask-element.js.map +1 -0
  120. package/components/MaskedInputV2/react-imask/imask/controls/html-mask-element.d.ts +20 -0
  121. package/components/MaskedInputV2/react-imask/imask/controls/html-mask-element.js +106 -0
  122. package/components/MaskedInputV2/react-imask/imask/controls/html-mask-element.js.map +1 -0
  123. package/components/MaskedInputV2/react-imask/imask/controls/input-history.d.ts +17 -0
  124. package/components/MaskedInputV2/react-imask/imask/controls/input-history.js +49 -0
  125. package/components/MaskedInputV2/react-imask/imask/controls/input-history.js.map +1 -0
  126. package/components/MaskedInputV2/react-imask/imask/controls/input.d.ts +95 -0
  127. package/components/MaskedInputV2/react-imask/imask/controls/input.js +420 -0
  128. package/components/MaskedInputV2/react-imask/imask/controls/input.js.map +1 -0
  129. package/components/MaskedInputV2/react-imask/imask/controls/mask-element.d.ts +30 -0
  130. package/components/MaskedInputV2/react-imask/imask/controls/mask-element.js +59 -0
  131. package/components/MaskedInputV2/react-imask/imask/controls/mask-element.js.map +1 -0
  132. package/components/MaskedInputV2/react-imask/imask/core/action-details.d.ts +30 -0
  133. package/components/MaskedInputV2/react-imask/imask/core/action-details.js +100 -0
  134. package/components/MaskedInputV2/react-imask/imask/core/action-details.js.map +1 -0
  135. package/components/MaskedInputV2/react-imask/imask/core/change-details.d.ts +20 -0
  136. package/components/MaskedInputV2/react-imask/imask/core/change-details.js +46 -0
  137. package/components/MaskedInputV2/react-imask/imask/core/change-details.js.map +1 -0
  138. package/components/MaskedInputV2/react-imask/imask/core/continuous-tail-details.d.ts +21 -0
  139. package/components/MaskedInputV2/react-imask/imask/core/continuous-tail-details.js +52 -0
  140. package/components/MaskedInputV2/react-imask/imask/core/continuous-tail-details.js.map +1 -0
  141. package/components/MaskedInputV2/react-imask/imask/core/holder.d.ts +34 -0
  142. package/components/MaskedInputV2/react-imask/imask/core/holder.js +38 -0
  143. package/components/MaskedInputV2/react-imask/imask/core/holder.js.map +1 -0
  144. package/components/MaskedInputV2/react-imask/imask/core/tail-details.d.ts +20 -0
  145. package/components/MaskedInputV2/react-imask/imask/core/tail-details.js +2 -0
  146. package/components/MaskedInputV2/react-imask/imask/core/tail-details.js.map +1 -0
  147. package/components/MaskedInputV2/react-imask/imask/core/utils.d.ts +24 -0
  148. package/components/MaskedInputV2/react-imask/imask/core/utils.js +100 -0
  149. package/components/MaskedInputV2/react-imask/imask/core/utils.js.map +1 -0
  150. package/components/MaskedInputV2/react-imask/imask/imask.d.ts +5 -0
  151. package/components/MaskedInputV2/react-imask/imask/imask.js +7 -0
  152. package/components/MaskedInputV2/react-imask/imask/imask.js.map +1 -0
  153. package/components/MaskedInputV2/react-imask/imask/index.d.ts +17 -0
  154. package/components/MaskedInputV2/react-imask/imask/index.js +16 -0
  155. package/components/MaskedInputV2/react-imask/imask/index.js.map +1 -0
  156. package/components/MaskedInputV2/react-imask/imask/masked/base.d.ts +114 -0
  157. package/components/MaskedInputV2/react-imask/imask/masked/base.js +411 -0
  158. package/components/MaskedInputV2/react-imask/imask/masked/base.js.map +1 -0
  159. package/components/MaskedInputV2/react-imask/imask/masked/create.d.ts +14 -0
  160. package/components/MaskedInputV2/react-imask/imask/masked/create.js +11 -0
  161. package/components/MaskedInputV2/react-imask/imask/masked/create.js.map +1 -0
  162. package/components/MaskedInputV2/react-imask/imask/masked/factory.d.ts +62 -0
  163. package/components/MaskedInputV2/react-imask/imask/masked/factory.js +107 -0
  164. package/components/MaskedInputV2/react-imask/imask/masked/factory.js.map +1 -0
  165. package/components/MaskedInputV2/react-imask/imask/masked/pattern.d.ts +101 -0
  166. package/components/MaskedInputV2/react-imask/imask/masked/pattern.js +549 -0
  167. package/components/MaskedInputV2/react-imask/imask/masked/pattern.js.map +1 -0
  168. package/components/MaskedInputV2/react-imask/imask/masked/patterns/block.d.ts +30 -0
  169. package/components/MaskedInputV2/react-imask/imask/masked/patterns/block.js +2 -0
  170. package/components/MaskedInputV2/react-imask/imask/masked/patterns/block.js.map +1 -0
  171. package/components/MaskedInputV2/react-imask/imask/masked/patterns/chunk-tail-details.d.ts +20 -0
  172. package/components/MaskedInputV2/react-imask/imask/masked/patterns/chunk-tail-details.js +182 -0
  173. package/components/MaskedInputV2/react-imask/imask/masked/patterns/chunk-tail-details.js.map +1 -0
  174. package/components/MaskedInputV2/react-imask/imask/masked/patterns/cursor.d.ts +31 -0
  175. package/components/MaskedInputV2/react-imask/imask/masked/patterns/cursor.js +163 -0
  176. package/components/MaskedInputV2/react-imask/imask/masked/patterns/cursor.js.map +1 -0
  177. package/components/MaskedInputV2/react-imask/imask/masked/patterns/fixed-definition.d.ts +42 -0
  178. package/components/MaskedInputV2/react-imask/imask/masked/patterns/fixed-definition.js +158 -0
  179. package/components/MaskedInputV2/react-imask/imask/masked/patterns/fixed-definition.js.map +1 -0
  180. package/components/MaskedInputV2/react-imask/imask/masked/patterns/input-definition.d.ts +56 -0
  181. package/components/MaskedInputV2/react-imask/imask/masked/patterns/input-definition.js +185 -0
  182. package/components/MaskedInputV2/react-imask/imask/masked/patterns/input-definition.js.map +1 -0
  183. package/components/MaskedInputV2/react-imask/imask/masked/regexp.d.ts +17 -0
  184. package/components/MaskedInputV2/react-imask/imask/masked/regexp.js +36 -0
  185. package/components/MaskedInputV2/react-imask/imask/masked/regexp.js.map +1 -0
  186. package/components/MaskedInputV2/react-imask/index.d.ts +3 -0
  187. package/components/MaskedInputV2/react-imask/index.js +4 -0
  188. package/components/MaskedInputV2/react-imask/index.js.map +1 -0
  189. package/components/MaskedInputV2/react-imask/input.d.ts +8 -0
  190. package/components/MaskedInputV2/react-imask/input.js +35 -0
  191. package/components/MaskedInputV2/react-imask/input.js.map +1 -0
  192. package/components/MaskedInputV2/react-imask/mixin.d.ts +31 -0
  193. package/components/MaskedInputV2/react-imask/mixin.js +246 -0
  194. package/components/MaskedInputV2/react-imask/mixin.js.map +1 -0
  195. package/components/MenuItem/MenuItem.mixins.d.ts +1 -0
  196. package/components/MenuItem/MenuItem.mixins.js +6 -1
  197. package/components/MenuItem/MenuItem.mixins.js.map +1 -1
  198. package/components/MenuItem/MenuItem.styles.d.ts +2 -1
  199. package/components/MenuItem/MenuItem.styles.js +2 -7
  200. package/components/MenuItem/MenuItem.styles.js.map +1 -1
  201. package/components/MiniModal/MiniModal.d.ts +2 -7
  202. package/components/MiniModal/MiniModal.js +2 -7
  203. package/components/MiniModal/MiniModal.js.map +1 -1
  204. package/components/MiniModal/MiniModalBody.js +1 -1
  205. package/components/MiniModal/MiniModalBody.js.map +1 -1
  206. package/components/MiniModal/MiniModalFooter.js +1 -1
  207. package/components/MiniModal/MiniModalFooter.js.map +1 -1
  208. package/components/MiniModal/MiniModalHeader.js +1 -1
  209. package/components/MiniModal/MiniModalHeader.js.map +1 -1
  210. package/components/MiniModal/MiniModalIndent.js +1 -1
  211. package/components/MiniModal/MiniModalIndent.js.map +1 -1
  212. package/components/MiniModal/tids.d.ts +7 -0
  213. package/components/MiniModal/tids.js +8 -0
  214. package/components/MiniModal/tids.js.map +1 -0
  215. package/components/Modal/Modal.constants.d.ts +9 -0
  216. package/components/Modal/Modal.constants.js +10 -0
  217. package/components/Modal/Modal.constants.js.map +1 -0
  218. package/components/Modal/Modal.d.ts +2 -10
  219. package/components/Modal/Modal.js +2 -9
  220. package/components/Modal/Modal.js.map +1 -1
  221. package/components/Modal/ModalBody.js +1 -1
  222. package/components/Modal/ModalBody.js.map +1 -1
  223. package/components/Modal/ModalClose.js +1 -1
  224. package/components/Modal/ModalClose.js.map +1 -1
  225. package/components/Toggle/Toggle.classes.d.ts +8 -0
  226. package/components/Toggle/Toggle.classes.js +10 -0
  227. package/components/Toggle/Toggle.classes.js.map +1 -0
  228. package/components/Toggle/Toggle.mixins.js +1 -1
  229. package/components/Toggle/Toggle.mixins.js.map +1 -1
  230. package/components/Toggle/Toggle.styles.d.ts +2 -8
  231. package/components/Toggle/Toggle.styles.js +3 -9
  232. package/components/Toggle/Toggle.styles.js.map +1 -1
  233. package/lib/date/InternalDateValidator.js +1 -2
  234. package/lib/date/InternalDateValidator.js.map +1 -1
  235. package/lib/events/keyboard/KeyboardEventCodes.d.ts +2 -0
  236. package/lib/events/keyboard/KeyboardEventCodes.js +2 -0
  237. package/lib/events/keyboard/KeyboardEventCodes.js.map +1 -1
  238. package/lib/events/keyboard/KeyboardMapKeys.js +2 -0
  239. package/lib/events/keyboard/KeyboardMapKeys.js.map +1 -1
  240. package/lib/events/keyboard/identifiers.d.ts +2 -0
  241. package/lib/events/keyboard/identifiers.js +6 -0
  242. package/lib/events/keyboard/identifiers.js.map +1 -1
  243. package/lib/featureFlagsContext/ReactUIFeatureFlagsContext.d.ts +1 -0
  244. package/lib/featureFlagsContext/ReactUIFeatureFlagsContext.js +1 -0
  245. package/lib/featureFlagsContext/ReactUIFeatureFlagsContext.js.map +1 -1
  246. package/package.json +4 -1
@@ -0,0 +1,54 @@
1
+ import { cx } from '@emotion/css';
2
+ import React, { useContext } from 'react';
3
+ import { useStyles } from '../../../lib/renderEnvironment/index.js';
4
+ import { ThemeContext } from '../../../lib/theming/ThemeContext.js';
5
+ import { getStyles, globalClasses } from './MaskedInternal.styles.js';
6
+ function splitTextBySelection(text, textStartOffset, selectionStart, selectionEnd) {
7
+ if (selectionStart === selectionEnd) {
8
+ return [text, '', ''];
9
+ }
10
+ var localStart = Math.max(0, selectionStart - textStartOffset);
11
+ var localEnd = Math.min(text.length, selectionEnd - textStartOffset);
12
+ if (localEnd <= localStart) {
13
+ return [text, '', ''];
14
+ }
15
+ return [text.slice(0, localStart), text.slice(localStart, localEnd), text.slice(localEnd)];
16
+ }
17
+ /**
18
+ * Абсолютно позиционированный слой над <input>.
19
+ * Input делается прозрачным (color: transparent), а весь текст
20
+ * (typedValue + maskPart) рендерится здесь с раскраской.
21
+ * При center/right align overlay выравнивает маску, а input смещается paddingLeft.
22
+ */
23
+ export function MaskOverlay(_a) {
24
+ var typedValue = _a.typedValue, displayValue = _a.displayValue, selectionStart = _a.selectionStart, selectionEnd = _a.selectionEnd, disabled = _a.disabled, textAlign = _a.textAlign, containerRef = _a.containerRef, _b = _a.colored, colored = _b === void 0 ? true : _b;
25
+ var theme = useContext(ThemeContext);
26
+ var styles = useStyles(getStyles);
27
+ var maskPart = displayValue.slice(typedValue.length);
28
+ var disabledClass = disabled && globalClasses.disabled;
29
+ var coloredClass = colored && globalClasses.colored;
30
+ var selectedSegmentClass = styles.selectedSegment();
31
+ if (!typedValue && !maskPart) {
32
+ return null;
33
+ }
34
+ function renderSegment(text, offset, segmentClassName) {
35
+ var _a = splitTextBySelection(text, offset, selectionStart, selectionEnd), before = _a[0], selected = _a[1], after = _a[2];
36
+ return (React.createElement(React.Fragment, null,
37
+ before ? React.createElement("span", { className: segmentClassName }, before) : null,
38
+ selected ? React.createElement("span", { className: selectedSegmentClass }, selected) : null,
39
+ after ? React.createElement("span", { className: segmentClassName }, after) : null));
40
+ }
41
+ return (React.createElement("span", { ref: containerRef, "aria-hidden": "true", className: styles.overlay() },
42
+ React.createElement("span", { "data-tid": "masked-input-overlay", style: {
43
+ display: 'inline-block',
44
+ width: '100%',
45
+ whiteSpace: 'nowrap',
46
+ textAlign: textAlign,
47
+ lineHeight: 'inherit',
48
+ } },
49
+ typedValue ? renderSegment(typedValue, 0, cx(styles.typed(theme), disabledClass, coloredClass)) : null,
50
+ maskPart
51
+ ? renderSegment(maskPart, typedValue.length, cx(styles.mask(theme), disabledClass, coloredClass))
52
+ : null)));
53
+ }
54
+ //# sourceMappingURL=MaskOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MaskOverlay.js","sourceRoot":"","sources":["MaskOverlay.tsx"],"names":[],"mappings":"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","sourcesContent":["import { cx } from '@emotion/css';\nimport React, { useContext } from 'react';\n\nimport { useStyles } from '../../../lib/renderEnvironment/index.js';\nimport { ThemeContext } from '../../../lib/theming/ThemeContext.js';\nimport { getStyles, globalClasses } from './MaskedInternal.styles.js';\n\ninterface MaskOverlayProps {\n typedValue: string;\n displayValue: string;\n selectionStart: number;\n selectionEnd: number;\n disabled?: boolean;\n textAlign?: React.CSSProperties['textAlign'];\n containerRef?: React.RefObject<HTMLSpanElement | null>;\n colored?: boolean;\n}\n\nfunction splitTextBySelection(\n text: string,\n textStartOffset: number,\n selectionStart: number,\n selectionEnd: number,\n): [string, string, string] {\n if (selectionStart === selectionEnd) {\n return [text, '', ''];\n }\n\n const localStart = Math.max(0, selectionStart - textStartOffset);\n const localEnd = Math.min(text.length, selectionEnd - textStartOffset);\n\n if (localEnd <= localStart) {\n return [text, '', ''];\n }\n\n return [text.slice(0, localStart), text.slice(localStart, localEnd), text.slice(localEnd)];\n}\n\n/**\n * Абсолютно позиционированный слой над <input>.\n * Input делается прозрачным (color: transparent), а весь текст\n * (typedValue + maskPart) рендерится здесь с раскраской.\n * При center/right align overlay выравнивает маску, а input смещается paddingLeft.\n */\nexport function MaskOverlay({\n typedValue,\n displayValue,\n selectionStart,\n selectionEnd,\n disabled,\n textAlign,\n containerRef,\n colored = true,\n}: MaskOverlayProps) {\n const theme = useContext(ThemeContext);\n const styles = useStyles(getStyles);\n const maskPart = displayValue.slice(typedValue.length);\n\n const disabledClass = disabled && globalClasses.disabled;\n const coloredClass = colored && globalClasses.colored;\n const selectedSegmentClass = styles.selectedSegment();\n\n if (!typedValue && !maskPart) {\n return null;\n }\n\n function renderSegment(text: string, offset: number, segmentClassName: string) {\n const [before, selected, after] = splitTextBySelection(text, offset, selectionStart, selectionEnd);\n\n return (\n <>\n {before ? <span className={segmentClassName}>{before}</span> : null}\n {selected ? <span className={selectedSegmentClass}>{selected}</span> : null}\n {after ? <span className={segmentClassName}>{after}</span> : null}\n </>\n );\n }\n\n return (\n <span ref={containerRef} aria-hidden=\"true\" className={styles.overlay()}>\n <span\n data-tid=\"masked-input-overlay\"\n style={{\n display: 'inline-block',\n width: '100%',\n whiteSpace: 'nowrap',\n textAlign,\n lineHeight: 'inherit',\n }}\n >\n {typedValue ? renderSegment(typedValue, 0, cx(styles.typed(theme), disabledClass, coloredClass)) : null}\n {maskPart\n ? renderSegment(maskPart, typedValue.length, cx(styles.mask(theme), disabledClass, coloredClass))\n : null}\n </span>\n </span>\n );\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import type { InputElement } from '../../Input/Input.typings.js';
2
+ import type { MaskedCoreProps } from './MaskedCore.types.js';
3
+ export type { MaskedCoreProps } from './MaskedCore.types.js';
4
+ /**
5
+ * Headless-слой MaskedInputV2: прозрачный `<input>` для ввода и {@link MaskOverlay} для отображения маски.
6
+ * Управляется через {@link useMaskedCoreHandlers}.
7
+ */
8
+ export declare const MaskedCore: import("../../../lib/forwardRefAndName.js").ReactUIComponentWithRef<InputElement | null, MaskedCoreProps> & Record<never, never>;
@@ -0,0 +1,186 @@
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
+ var __rest = (this && this.__rest) || function (s, e) {
13
+ var t = {};
14
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
15
+ t[p] = s[p];
16
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
17
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
18
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
19
+ t[p[i]] = s[p[i]];
20
+ }
21
+ return t;
22
+ };
23
+ import { cx } from '@emotion/css';
24
+ import React, { useCallback, useContext, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState, } from 'react';
25
+ import { forwardRefAndName } from '../../../lib/forwardRefAndName.js';
26
+ import { useGlobal, useStyles } from '../../../lib/renderEnvironment/index.js';
27
+ import { scrollInputCaretIntoView } from '../../../lib/scrollInputCaretIntoView.js';
28
+ import { ThemeContext } from '../../../lib/theming/ThemeContext.js';
29
+ import { needsMaskAlignPadding } from './computeMaskAlignPadding.js';
30
+ import { getStyles, globalClasses } from './MaskedInternal.styles.js';
31
+ import { MaskOverlay } from './MaskOverlay.js';
32
+ import { setMaskInputSelectionRange } from './setMaskInputSelectionRange.js';
33
+ import { getShowOverlay } from './showOverlay.js';
34
+ import { useInputOverflow } from './useInputOverflow.js';
35
+ import { useMaskAlignPadding } from './useMaskAlignPadding.js';
36
+ import { useMaskedCoreHandlers } from './useMaskedCoreHandlers.js';
37
+ /**
38
+ * Headless-слой MaskedInputV2: прозрачный `<input>` для ввода и {@link MaskOverlay} для отображения маски.
39
+ * Управляется через {@link useMaskedCoreHandlers}.
40
+ */
41
+ export var MaskedCore = forwardRefAndName('MaskedCore', function MaskedCore(props, ref) {
42
+ var _a, _b;
43
+ var maskState = props.maskState, slotMap = props.slotMap, engine = props.engine, focused = props.focused, currentRaw = props.currentRaw, onRawChange = props.onRawChange, onUnexpectedInput = props.onUnexpectedInput, onUndo = props.onUndo, onRedo = props.onRedo, coreInputRef = props.coreInputRef, _c = props.colored, colored = _c === void 0 ? true : _c, selectAllOnFocus = props.selectAllOnFocus, externalSelectionIntent = props.selectionIntent, onSelectionIntentChange = props.onSelectionIntentChange, onKeyDown = props.onKeyDown, onMouseUp = props.onMouseUp, onInput = props.onInput, onSelect = props.onSelect, onFocus = props.onFocus, onPaste = props.onPaste, onBlur = props.onBlur, placeholder = props.placeholder, className = props.className, disabled = props.disabled, rest = __rest(props, ["maskState", "slotMap", "engine", "focused", "currentRaw", "onRawChange", "onUnexpectedInput", "onUndo", "onRedo", "coreInputRef", "colored", "selectAllOnFocus", "selectionIntent", "onSelectionIntentChange", "onKeyDown", "onMouseUp", "onInput", "onSelect", "onFocus", "onPaste", "onBlur", "placeholder", "className", "disabled"]);
44
+ var styles = useStyles(getStyles);
45
+ var globalObject = useGlobal();
46
+ var overlayRef = useRef(null);
47
+ var theme = useContext(ThemeContext);
48
+ var textAlign = (_a = rest.style) === null || _a === void 0 ? void 0 : _a.textAlign;
49
+ var _d = useState(null), internalSelectionIntent = _d[0], setInternalSelectionIntent = _d[1];
50
+ var selectionIntent = externalSelectionIntent === undefined ? internalSelectionIntent : externalSelectionIntent;
51
+ var selectionIntentRef = useRef(selectionIntent);
52
+ selectionIntentRef.current = selectionIntent;
53
+ var requestSelectionIntent = useCallback(function (intent) {
54
+ if (onSelectionIntentChange) {
55
+ onSelectionIntentChange(intent);
56
+ return;
57
+ }
58
+ setInternalSelectionIntent(function (current) {
59
+ return current === 'select-all' && intent === 'caret-end' ? current : intent;
60
+ });
61
+ }, [onSelectionIntentChange]);
62
+ var syncOverlayScroll = useCallback(function () {
63
+ if (overlayRef.current && coreInputRef.current) {
64
+ overlayRef.current.style.transform = "translateX(-".concat(coreInputRef.current.scrollLeft, "px)");
65
+ }
66
+ }, [coreInputRef]);
67
+ var overflows = useInputOverflow(coreInputRef, maskState.displayValue, focused);
68
+ var showOverlay = getShowOverlay(maskState, focused, overflows);
69
+ var _e = useMaskedCoreHandlers({
70
+ maskState: maskState,
71
+ slotMap: slotMap,
72
+ engine: engine,
73
+ currentRaw: currentRaw,
74
+ onRawChange: onRawChange,
75
+ onUnexpectedInput: onUnexpectedInput,
76
+ onUndo: onUndo,
77
+ onRedo: onRedo,
78
+ coreInputRef: coreInputRef,
79
+ selectAllOnFocus: selectAllOnFocus,
80
+ onKeyDown: onKeyDown,
81
+ onMouseUp: onMouseUp,
82
+ onInput: onInput,
83
+ onSelect: onSelect,
84
+ onFocus: onFocus,
85
+ onBlur: onBlur,
86
+ onPaste: onPaste,
87
+ syncOverlayScroll: syncOverlayScroll,
88
+ requestSelectionIntent: requestSelectionIntent,
89
+ }), pendingCursorRef = _e.pendingCursorRef, selectionRange = _e.selectionRange, syncSelection = _e.syncSelection, handleChange = _e.handleChange, handleKeyDown = _e.handleKeyDown, handleSelect = _e.handleSelect, handlePaste = _e.handlePaste, handleBeforeInput = _e.handleBeforeInput, handleCopy = _e.handleCopy, handleCut = _e.handleCut, handleInput = _e.handleInput, handleMouseDown = _e.handleMouseDown, handleMouseUp = _e.handleMouseUp, handleFocus = _e.handleFocus, handleBlur = _e.handleBlur;
90
+ useImperativeHandle(ref, function () { return ({
91
+ input: coreInputRef.current,
92
+ getRootNode: function () { return coreInputRef.current; },
93
+ }); }, [coreInputRef]);
94
+ var applySelectionIntent = useCallback(function (intent) {
95
+ var _a, _b;
96
+ var el = coreInputRef.current;
97
+ if (!el || !focused) {
98
+ return;
99
+ }
100
+ if (intent === 'select-all') {
101
+ setMaskInputSelectionRange(el, 0, maskState.typedLength);
102
+ }
103
+ else {
104
+ var start = (_a = el.selectionStart) !== null && _a !== void 0 ? _a : 0;
105
+ var end = (_b = el.selectionEnd) !== null && _b !== void 0 ? _b : 0;
106
+ if (start === end && start !== 0 && start !== maskState.typedLength) {
107
+ return;
108
+ }
109
+ setMaskInputSelectionRange(el, maskState.typedLength);
110
+ }
111
+ scrollInputCaretIntoView(el);
112
+ syncSelection(el);
113
+ }, [coreInputRef, focused, maskState.typedLength, syncSelection]);
114
+ useLayoutEffect(function () {
115
+ var el = coreInputRef.current;
116
+ if (selectionIntent) {
117
+ applySelectionIntent(selectionIntent);
118
+ }
119
+ else if (pendingCursorRef.current !== null && el) {
120
+ var pos = pendingCursorRef.current;
121
+ pendingCursorRef.current = null;
122
+ setMaskInputSelectionRange(el, pos);
123
+ scrollInputCaretIntoView(el);
124
+ syncSelection(el);
125
+ }
126
+ else if (el && focused) {
127
+ scrollInputCaretIntoView(el);
128
+ }
129
+ syncOverlayScroll();
130
+ // typedValue в deps обязателен: после controlled-update React сбрасывает selection,
131
+ // а typedLength при shift-перезаписи в полной маске может не измениться (1212 → 1251).
132
+ }, [applySelectionIntent, focused, maskState.typedValue, selectionIntent, syncOverlayScroll, syncSelection]);
133
+ // Браузер может применить свою Tab-selection после focus-хендлеров.
134
+ // Один отменяемый retry после события оставляет последнее намерение победителем.
135
+ useEffect(function () {
136
+ if (!selectionIntent || !focused) {
137
+ return;
138
+ }
139
+ var appliedIntent = selectionIntent;
140
+ var setTimeout = globalObject.setTimeout;
141
+ if (!setTimeout) {
142
+ requestSelectionIntent(null);
143
+ return;
144
+ }
145
+ var timer = setTimeout(function () {
146
+ var _a;
147
+ if (selectionIntentRef.current !== appliedIntent) {
148
+ return;
149
+ }
150
+ var el = coreInputRef.current;
151
+ if (!el || ((_a = globalObject.document) === null || _a === void 0 ? void 0 : _a.activeElement) !== el) {
152
+ requestSelectionIntent(null);
153
+ return;
154
+ }
155
+ applySelectionIntent(appliedIntent);
156
+ requestSelectionIntent(null);
157
+ }, 0);
158
+ return function () { var _a; return (_a = globalObject.clearTimeout) === null || _a === void 0 ? void 0 : _a.call(globalObject, timer); };
159
+ }, [applySelectionIntent, coreInputRef, focused, globalObject, requestSelectionIntent, selectionIntent]);
160
+ useEffect(function () {
161
+ if (!focused) {
162
+ return;
163
+ }
164
+ var el = coreInputRef.current;
165
+ if (!el) {
166
+ return;
167
+ }
168
+ var handleSelectionChange = function () {
169
+ if (document.activeElement === el) {
170
+ handleSelect();
171
+ }
172
+ };
173
+ document.addEventListener('selectionchange', handleSelectionChange);
174
+ return function () { return document.removeEventListener('selectionchange', handleSelectionChange); };
175
+ }, [focused, handleSelect]);
176
+ var alignPadding = useMaskAlignPadding(coreInputRef, overlayRef, maskState.displayValue, textAlign, focused && showOverlay && needsMaskAlignPadding(textAlign));
177
+ var inputStyle = alignPadding > 0 ? __assign(__assign({}, rest.style), { textAlign: 'left', paddingLeft: alignPadding }) : rest.style;
178
+ return (React.createElement(React.Fragment, null,
179
+ React.createElement("input", __assign({}, rest, { style: inputStyle, placeholder: showOverlay ? undefined : placeholder, "aria-disabled": disabled, disabled: disabled, ref: coreInputRef, className: cx(globalClasses.input, styles.input(theme), showOverlay && globalClasses.masked, className), value: maskState.typedValue, onChange: handleChange, onBeforeInput: handleBeforeInput, onKeyDown: handleKeyDown, onSelect: handleSelect, onPaste: handlePaste, onCopy: handleCopy, onCut: handleCut, onFocus: handleFocus, onBlur: handleBlur, onInput: handleInput, onMouseDown: function (e) {
180
+ var _a;
181
+ handleMouseDown();
182
+ (_a = rest.onMouseDown) === null || _a === void 0 ? void 0 : _a.call(rest, e);
183
+ }, onMouseUp: handleMouseUp, onScroll: syncOverlayScroll })),
184
+ showOverlay && (React.createElement(MaskOverlay, { containerRef: overlayRef, typedValue: maskState.typedValue, displayValue: maskState.displayValue, selectionStart: selectionRange.start, selectionEnd: selectionRange.end, disabled: disabled, textAlign: (_b = rest.style) === null || _b === void 0 ? void 0 : _b.textAlign, colored: colored }))));
185
+ });
186
+ //# sourceMappingURL=MaskedCore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MaskedCore.js","sourceRoot":"","sources":["MaskedCore.tsx"],"names":[],"mappings":"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","sourcesContent":["import { cx } from '@emotion/css';\nimport React, {\n useCallback,\n useContext,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n useState,\n} from 'react';\n\nimport { forwardRefAndName } from '../../../lib/forwardRefAndName.js';\nimport { useGlobal, useStyles } from '../../../lib/renderEnvironment/index.js';\nimport { scrollInputCaretIntoView } from '../../../lib/scrollInputCaretIntoView.js';\nimport { ThemeContext } from '../../../lib/theming/ThemeContext.js';\nimport type { InputElement } from '../../Input/Input.typings.js';\nimport { needsMaskAlignPadding } from './computeMaskAlignPadding.js';\nimport type { MaskedCoreProps } from './MaskedCore.types.js';\nimport { getStyles, globalClasses } from './MaskedInternal.styles.js';\nimport { MaskOverlay } from './MaskOverlay.js';\nimport { setMaskInputSelectionRange } from './setMaskInputSelectionRange.js';\nimport { getShowOverlay } from './showOverlay.js';\nimport { useInputOverflow } from './useInputOverflow.js';\nimport { useMaskAlignPadding } from './useMaskAlignPadding.js';\nimport { useMaskedCoreHandlers } from './useMaskedCoreHandlers.js';\n\nexport type { MaskedCoreProps } from './MaskedCore.types.js';\n\n/**\n * Headless-слой MaskedInputV2: прозрачный `<input>` для ввода и {@link MaskOverlay} для отображения маски.\n * Управляется через {@link useMaskedCoreHandlers}.\n */\nexport const MaskedCore = forwardRefAndName(\n 'MaskedCore',\n function MaskedCore(props: MaskedCoreProps, ref: React.ForwardedRef<InputElement | null>) {\n const {\n maskState,\n slotMap,\n engine,\n focused,\n currentRaw,\n onRawChange,\n onUnexpectedInput,\n onUndo,\n onRedo,\n coreInputRef,\n colored = true,\n selectAllOnFocus,\n selectionIntent: externalSelectionIntent,\n onSelectionIntentChange,\n onKeyDown,\n onMouseUp,\n onInput,\n onSelect,\n onFocus,\n onPaste,\n onBlur,\n placeholder,\n className,\n disabled,\n ...rest\n } = props;\n\n const styles = useStyles(getStyles);\n const globalObject = useGlobal();\n const overlayRef = useRef<HTMLSpanElement>(null);\n const theme = useContext(ThemeContext);\n const textAlign = rest.style?.textAlign;\n const [internalSelectionIntent, setInternalSelectionIntent] = useState<NonNullable<\n MaskedCoreProps['selectionIntent']\n > | null>(null);\n const selectionIntent = externalSelectionIntent === undefined ? internalSelectionIntent : externalSelectionIntent;\n const selectionIntentRef = useRef(selectionIntent);\n selectionIntentRef.current = selectionIntent;\n\n const requestSelectionIntent = useCallback(\n (intent: NonNullable<MaskedCoreProps['selectionIntent']> | null) => {\n if (onSelectionIntentChange) {\n onSelectionIntentChange(intent);\n return;\n }\n setInternalSelectionIntent((current) =>\n current === 'select-all' && intent === 'caret-end' ? current : intent,\n );\n },\n [onSelectionIntentChange],\n );\n\n const syncOverlayScroll = useCallback(() => {\n if (overlayRef.current && coreInputRef.current) {\n overlayRef.current.style.transform = `translateX(-${coreInputRef.current.scrollLeft}px)`;\n }\n }, [coreInputRef]);\n\n const overflows = useInputOverflow(coreInputRef, maskState.displayValue, focused);\n const showOverlay = getShowOverlay(maskState, focused, overflows);\n\n const {\n pendingCursorRef,\n selectionRange,\n syncSelection,\n handleChange,\n handleKeyDown,\n handleSelect,\n handlePaste,\n handleBeforeInput,\n handleCopy,\n handleCut,\n handleInput,\n handleMouseDown,\n handleMouseUp,\n handleFocus,\n handleBlur,\n } = useMaskedCoreHandlers({\n maskState,\n slotMap,\n engine,\n currentRaw,\n onRawChange,\n onUnexpectedInput,\n onUndo,\n onRedo,\n coreInputRef,\n selectAllOnFocus,\n onKeyDown,\n onMouseUp,\n onInput,\n onSelect,\n onFocus,\n onBlur,\n onPaste,\n syncOverlayScroll,\n requestSelectionIntent,\n });\n\n useImperativeHandle(\n ref,\n () => ({\n input: coreInputRef.current,\n getRootNode: () => coreInputRef.current,\n }),\n [coreInputRef],\n );\n\n const applySelectionIntent = useCallback(\n (intent: NonNullable<MaskedCoreProps['selectionIntent']>) => {\n const el = coreInputRef.current;\n if (!el || !focused) {\n return;\n }\n\n if (intent === 'select-all') {\n setMaskInputSelectionRange(el, 0, maskState.typedLength);\n } else {\n const start = el.selectionStart ?? 0;\n const end = el.selectionEnd ?? 0;\n if (start === end && start !== 0 && start !== maskState.typedLength) {\n return;\n }\n setMaskInputSelectionRange(el, maskState.typedLength);\n }\n scrollInputCaretIntoView(el);\n syncSelection(el);\n },\n [coreInputRef, focused, maskState.typedLength, syncSelection],\n );\n\n useLayoutEffect(() => {\n const el = coreInputRef.current;\n\n if (selectionIntent) {\n applySelectionIntent(selectionIntent);\n } else if (pendingCursorRef.current !== null && el) {\n const pos = pendingCursorRef.current;\n pendingCursorRef.current = null;\n setMaskInputSelectionRange(el, pos);\n scrollInputCaretIntoView(el);\n syncSelection(el);\n } else if (el && focused) {\n scrollInputCaretIntoView(el);\n }\n\n syncOverlayScroll();\n // typedValue в deps обязателен: после controlled-update React сбрасывает selection,\n // а typedLength при shift-перезаписи в полной маске может не измениться (1212 → 1251).\n }, [applySelectionIntent, focused, maskState.typedValue, selectionIntent, syncOverlayScroll, syncSelection]);\n\n // Браузер может применить свою Tab-selection после focus-хендлеров.\n // Один отменяемый retry после события оставляет последнее намерение победителем.\n useEffect(() => {\n if (!selectionIntent || !focused) {\n return;\n }\n\n const appliedIntent = selectionIntent;\n const setTimeout = globalObject.setTimeout;\n if (!setTimeout) {\n requestSelectionIntent(null);\n return;\n }\n const timer = setTimeout(() => {\n if (selectionIntentRef.current !== appliedIntent) {\n return;\n }\n const el = coreInputRef.current;\n if (!el || globalObject.document?.activeElement !== el) {\n requestSelectionIntent(null);\n return;\n }\n applySelectionIntent(appliedIntent);\n requestSelectionIntent(null);\n }, 0);\n\n return () => globalObject.clearTimeout?.(timer);\n }, [applySelectionIntent, coreInputRef, focused, globalObject, requestSelectionIntent, selectionIntent]);\n\n useEffect(() => {\n if (!focused) {\n return;\n }\n\n const el = coreInputRef.current;\n if (!el) {\n return;\n }\n\n const handleSelectionChange = () => {\n if (document.activeElement === el) {\n handleSelect();\n }\n };\n\n document.addEventListener('selectionchange', handleSelectionChange);\n return () => document.removeEventListener('selectionchange', handleSelectionChange);\n }, [focused, handleSelect]);\n\n const alignPadding = useMaskAlignPadding(\n coreInputRef,\n overlayRef,\n maskState.displayValue,\n textAlign,\n focused && showOverlay && needsMaskAlignPadding(textAlign),\n );\n const inputStyle =\n alignPadding > 0 ? { ...rest.style, textAlign: 'left' as const, paddingLeft: alignPadding } : rest.style;\n\n return (\n <>\n <input\n {...rest}\n style={inputStyle}\n placeholder={showOverlay ? undefined : placeholder}\n aria-disabled={disabled}\n disabled={disabled}\n ref={coreInputRef}\n className={cx(globalClasses.input, styles.input(theme), showOverlay && globalClasses.masked, className)}\n value={maskState.typedValue}\n onChange={handleChange}\n onBeforeInput={handleBeforeInput}\n onKeyDown={handleKeyDown}\n onSelect={handleSelect}\n onPaste={handlePaste}\n onCopy={handleCopy}\n onCut={handleCut}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onInput={handleInput}\n onMouseDown={(e) => {\n handleMouseDown();\n rest.onMouseDown?.(e);\n }}\n onMouseUp={handleMouseUp}\n onScroll={syncOverlayScroll}\n />\n {showOverlay && (\n <MaskOverlay\n containerRef={overlayRef}\n typedValue={maskState.typedValue}\n displayValue={maskState.displayValue}\n selectionStart={selectionRange.start}\n selectionEnd={selectionRange.end}\n disabled={disabled}\n textAlign={rest.style?.textAlign}\n colored={colored}\n />\n )}\n </>\n );\n },\n);\n"]}
@@ -0,0 +1,37 @@
1
+ import type React from 'react';
2
+ import type { InputElement } from '../../Input/Input.typings.js';
3
+ import type { MaskEngine, MaskState, SlotMap } from './types.js';
4
+ export type MaskedSelectionIntent = 'caret-end' | 'select-all' | null;
5
+ /**
6
+ * Пропсы headless-слоя {@link MaskedCore}: прозрачный `<input>` + overlay маски.
7
+ */
8
+ export interface MaskedCoreProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onChange' | 'defaultValue'> {
9
+ /** Вычисленное состояние маски для отображения. */
10
+ maskState: MaskState;
11
+ /** Карта слотов для clipboard/delete/navigation. */
12
+ slotMap: SlotMap;
13
+ /** Headless IMask-движок. */
14
+ engine: MaskEngine;
15
+ /** Поле в фокусе — влияет на lazy-режим displayValue. */
16
+ focused: boolean;
17
+ /** Текущее raw-значение (источник истины). */
18
+ currentRaw: string;
19
+ /** Колбэк изменения raw от пользовательского ввода или paste. */
20
+ onRawChange: (newRaw: string, source: 'input' | 'paste', cursorPos?: number) => void;
21
+ /** Колбэк отклонённого ввода (невалидный символ или граничное удаление). */
22
+ onUnexpectedInput: () => void;
23
+ onUndo?: () => void;
24
+ onRedo?: () => void;
25
+ /** Ref на нативный `<input>` внутри MaskedCore. */
26
+ coreInputRef: React.RefObject<HTMLInputElement | null>;
27
+ /** Раскрашивать ли символы маски в overlay. @default true */
28
+ colored?: boolean;
29
+ /** Не сбрасывать каретку на mouseup — нужно для selectAllOnFocus. */
30
+ selectAllOnFocus?: boolean;
31
+ /** Намерение выставить каретку или выделение после актуализации maskState. */
32
+ selectionIntent?: MaskedSelectionIntent;
33
+ /** Запрашивает новое намерение выставить каретку или выделение. */
34
+ onSelectionIntentChange?: (intent: MaskedSelectionIntent) => void;
35
+ }
36
+ /** Ref, который MaskedCore пробрасывает наружу для совместимости с Input.refInput. */
37
+ export type MaskedCoreRef = InputElement | null;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=MaskedCore.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MaskedCore.types.js","sourceRoot":"","sources":["MaskedCore.types.ts"],"names":[],"mappings":"","sourcesContent":["import type React from 'react';\n\nimport type { InputElement } from '../../Input/Input.typings.js';\nimport type { MaskEngine, MaskState, SlotMap } from './types.js';\n\nexport type MaskedSelectionIntent = 'caret-end' | 'select-all' | null;\n\n/**\n * Пропсы headless-слоя {@link MaskedCore}: прозрачный `<input>` + overlay маски.\n */\nexport interface MaskedCoreProps extends Omit<\n React.InputHTMLAttributes<HTMLInputElement>,\n 'value' | 'onChange' | 'defaultValue'\n> {\n /** Вычисленное состояние маски для отображения. */\n maskState: MaskState;\n /** Карта слотов для clipboard/delete/navigation. */\n slotMap: SlotMap;\n /** Headless IMask-движок. */\n engine: MaskEngine;\n /** Поле в фокусе — влияет на lazy-режим displayValue. */\n focused: boolean;\n /** Текущее raw-значение (источник истины). */\n currentRaw: string;\n /** Колбэк изменения raw от пользовательского ввода или paste. */\n onRawChange: (newRaw: string, source: 'input' | 'paste', cursorPos?: number) => void;\n /** Колбэк отклонённого ввода (невалидный символ или граничное удаление). */\n onUnexpectedInput: () => void;\n onUndo?: () => void;\n onRedo?: () => void;\n /** Ref на нативный `<input>` внутри MaskedCore. */\n coreInputRef: React.RefObject<HTMLInputElement | null>;\n /** Раскрашивать ли символы маски в overlay. @default true */\n colored?: boolean;\n /** Не сбрасывать каретку на mouseup — нужно для selectAllOnFocus. */\n selectAllOnFocus?: boolean;\n /** Намерение выставить каретку или выделение после актуализации maskState. */\n selectionIntent?: MaskedSelectionIntent;\n /** Запрашивает новое намерение выставить каретку или выделение. */\n onSelectionIntentChange?: (intent: MaskedSelectionIntent) => void;\n}\n\n/** Ref, который MaskedCore пробрасывает наружу для совместимости с Input.refInput. */\nexport type MaskedCoreRef = InputElement | null;\n"]}
@@ -0,0 +1,15 @@
1
+ import type { Theme } from '../../../lib/theming/Theme.js';
2
+ export declare const globalClasses: {
3
+ input: string;
4
+ disabled: string;
5
+ selected: string;
6
+ masked: string;
7
+ colored: string;
8
+ };
9
+ export declare const getStyles: import("../../../lib/theming/Emotion.js").StylesGetter<{
10
+ input(t: Theme): string;
11
+ overlay(): string;
12
+ typed(t: Theme): string;
13
+ mask(t: Theme): string;
14
+ selectedSegment(): string;
15
+ }>;
@@ -0,0 +1,34 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ import { memoizeGetStyles, prefix } from '../../../lib/theming/Emotion.js';
6
+ export var globalClasses = prefix('masked-internal')({
7
+ input: 'input',
8
+ disabled: 'disabled',
9
+ selected: 'selected',
10
+ masked: 'masked',
11
+ colored: 'colored',
12
+ });
13
+ export var getStyles = memoizeGetStyles(function (_a) {
14
+ var css = _a.css;
15
+ return ({
16
+ input: function (t) {
17
+ return css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color-scheme: ", ";\n\n &:-internal-autofill-selected {\n background-color: ", " !important;\n background-image: none !important;\n color: ", " !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-box-shadow: 0 0 0 1000px ", " inset;\n box-shadow: 0 0 0 1000px ", " inset;\n -webkit-text-fill-color: ", " !important;\n color: ", " !important;\n /* Chrome \u0438\u043D\u0430\u0447\u0435 \u0441\u043A\u0440\u044B\u0432\u0430\u0435\u0442 caret \u043F\u0440\u0438 autofill (color/currentColor). */\n caret-color: ", " !important;\n transition:\n background-color 0s 600000s,\n color 0s 600000s !important;\n }\n\n &:disabled {\n color: ", ";\n\n &:-internal-autofill-selected {\n background-color: ", " !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-box-shadow: 0 0 0 1000px ", " inset;\n box-shadow: 0 0 0 1000px ", " inset;\n }\n }\n\n &.", " {\n color: transparent;\n -webkit-text-fill-color: transparent;\n caret-color: ", ";\n\n &::selection {\n background-color: transparent !important;\n color: transparent !important;\n -webkit-text-fill-color: transparent !important;\n }\n\n /* \u0422\u0435\u043A\u0441\u0442 \u0440\u0438\u0441\u0443\u0435\u0442 MaskOverlay; \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043F\u0440\u0438 autofill \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u043F\u0435\u0440\u0435\u0431\u0438\u0432\u0430\u0442\u044C fill-color. */\n &:-internal-autofill-selected {\n color: transparent !important;\n caret-color: ", " !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-text-fill-color: transparent !important;\n color: transparent !important;\n /* \u0411\u0435\u0437 \u044D\u0442\u043E\u0433\u043E caret \u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0441\u044F transparent \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0438 \u043D\u0435 \u043C\u0438\u0433\u0430\u0435\u0442. */\n caret-color: ", " !important;\n }\n }\n "], ["\n color-scheme: ", ";\n\n &:-internal-autofill-selected {\n background-color: ", " !important;\n background-image: none !important;\n color: ", " !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-box-shadow: 0 0 0 1000px ", " inset;\n box-shadow: 0 0 0 1000px ", " inset;\n -webkit-text-fill-color: ", " !important;\n color: ", " !important;\n /* Chrome \u0438\u043D\u0430\u0447\u0435 \u0441\u043A\u0440\u044B\u0432\u0430\u0435\u0442 caret \u043F\u0440\u0438 autofill (color/currentColor). */\n caret-color: ", " !important;\n transition:\n background-color 0s 600000s,\n color 0s 600000s !important;\n }\n\n &:disabled {\n color: ", ";\n\n &:-internal-autofill-selected {\n background-color: ", " !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-box-shadow: 0 0 0 1000px ", " inset;\n box-shadow: 0 0 0 1000px ", " inset;\n }\n }\n\n &.", " {\n color: transparent;\n -webkit-text-fill-color: transparent;\n caret-color: ", ";\n\n &::selection {\n background-color: transparent !important;\n color: transparent !important;\n -webkit-text-fill-color: transparent !important;\n }\n\n /* \u0422\u0435\u043A\u0441\u0442 \u0440\u0438\u0441\u0443\u0435\u0442 MaskOverlay; \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043F\u0440\u0438 autofill \u043D\u0435 \u0434\u043E\u043B\u0436\u0435\u043D \u043F\u0435\u0440\u0435\u0431\u0438\u0432\u0430\u0442\u044C fill-color. */\n &:-internal-autofill-selected {\n color: transparent !important;\n caret-color: ", " !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-text-fill-color: transparent !important;\n color: transparent !important;\n /* \u0411\u0435\u0437 \u044D\u0442\u043E\u0433\u043E caret \u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u0441\u044F transparent \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0438 \u043D\u0435 \u043C\u0438\u0433\u0430\u0435\u0442. */\n caret-color: ", " !important;\n }\n }\n "])), t.inputColorScheme, t.inputBg, t.inputTextColor, t.inputBg, t.inputBg, t.inputTextColor, t.inputTextColor, t.inputTextColor, t.inputTextColorDisabled, t.inputDisabledBg, t.inputDisabledBg, t.inputDisabledBg, globalClasses.masked, t.inputTextColor, t.inputTextColor, t.inputTextColor);
18
+ },
19
+ overlay: function () {
20
+ return css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n position: absolute;\n inset: 0;\n pointer-events: none;\n user-select: none;\n overflow: hidden;\n display: flex;\n align-items: center;\n z-index: 2;\n "], ["\n position: absolute;\n inset: 0;\n pointer-events: none;\n user-select: none;\n overflow: hidden;\n display: flex;\n align-items: center;\n z-index: 2;\n "])));
21
+ },
22
+ typed: function (t) {
23
+ return css(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n white-space: pre;\n color: ", ";\n\n &.", " {\n color: ", ";\n }\n "], ["\n white-space: pre;\n color: ", ";\n\n &.", " {\n color: ", ";\n }\n "])), t.inputTextColor, globalClasses.disabled, t.inputTextColorDisabled);
24
+ },
25
+ mask: function (t) {
26
+ return css(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n white-space: pre;\n color: ", ";\n\n &.", " {\n color: ", ";\n }\n\n &.", " {\n color: ", ";\n }\n "], ["\n white-space: pre;\n color: ", ";\n\n &.", " {\n color: ", ";\n }\n\n &.", " {\n color: ", ";\n }\n "])), t.inputTextColor, globalClasses.colored, t.inputPlaceholderColor, globalClasses.disabled, t.inputTextColorDisabled);
27
+ },
28
+ selectedSegment: function () {
29
+ return css(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n background-color: #3390ff;\n color: #fff !important;\n -webkit-text-fill-color: #fff !important;\n "], ["\n background-color: #3390ff;\n color: #fff !important;\n -webkit-text-fill-color: #fff !important;\n "])));
30
+ },
31
+ });
32
+ });
33
+ var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5;
34
+ //# sourceMappingURL=MaskedInternal.styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MaskedInternal.styles.js","sourceRoot":"","sources":["MaskedInternal.styles.ts"],"names":[],"mappings":";;;;AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAG3E,MAAM,CAAC,IAAM,aAAa,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACrD,KAAK,EAAE,OAAO;IACd,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;CACnB,CAAC,CAAC;AAEH,MAAM,CAAC,IAAM,SAAS,GAAG,gBAAgB,CAAC,UAAC,EAAgB;QAAd,GAAG,SAAA;IAAgB,OAAA,CAAC;QAC/D,KAAK,YAAC,CAAQ;YACZ,OAAO,GAAG,+9EAAA,wBACQ,EAAkB,wEAGZ,EAAS,2EAEpB,EAAgB,kKAMU,EAAS,4CACjB,EAAS,4CACT,EAAgB,+BAClC,EAAgB,mMAEV,EAAgB,mKAOtB,EAAwB,4EAGX,EAAiB,4KAMF,EAAiB,8CACzB,EAAiB,yCAI5C,EAAoB,uGAGP,EAAgB,mlBAWd,EAAgB,iiBAShB,EAAgB,wCAGpC,KA/DiB,CAAC,CAAC,gBAAgB,EAGZ,CAAC,CAAC,OAAO,EAEpB,CAAC,CAAC,cAAc,EAMU,CAAC,CAAC,OAAO,EACjB,CAAC,CAAC,OAAO,EACT,CAAC,CAAC,cAAc,EAClC,CAAC,CAAC,cAAc,EAEV,CAAC,CAAC,cAAc,EAOtB,CAAC,CAAC,sBAAsB,EAGX,CAAC,CAAC,eAAe,EAMF,CAAC,CAAC,eAAe,EACzB,CAAC,CAAC,eAAe,EAI5C,aAAa,CAAC,MAAM,EAGP,CAAC,CAAC,cAAc,EAWd,CAAC,CAAC,cAAc,EAShB,CAAC,CAAC,cAAc,EAGnC;QACJ,CAAC;QACD,OAAO;YACL,OAAO,GAAG,4QAAA,yMAST,KAAC;QACJ,CAAC;QACD,KAAK,YAAC,CAAQ;YACZ,OAAO,GAAG,yKAAA,0CAEC,EAAgB,eAErB,EAAsB,qBACf,EAAwB,kBAEpC,KALU,CAAC,CAAC,cAAc,EAErB,aAAa,CAAC,QAAQ,EACf,CAAC,CAAC,sBAAsB,EAEnC;QACJ,CAAC;QACD,IAAI,YAAC,CAAQ;YACX,OAAO,GAAG,0NAAA,0CAEC,EAAgB,eAErB,EAAqB,qBACd,EAAuB,wBAG9B,EAAsB,qBACf,EAAwB,kBAEpC,KATU,CAAC,CAAC,cAAc,EAErB,aAAa,CAAC,OAAO,EACd,CAAC,CAAC,qBAAqB,EAG9B,aAAa,CAAC,QAAQ,EACf,CAAC,CAAC,sBAAsB,EAEnC;QACJ,CAAC;QACD,eAAe;YACb,OAAO,GAAG,6LAAA,0HAIT,KAAC;QACJ,CAAC;KACF,CAAC;AA/G8D,CA+G9D,CAAC,CAAC","sourcesContent":["import type { Emotion } from '@emotion/css/create-instance';\n\nimport { memoizeGetStyles, prefix } from '../../../lib/theming/Emotion.js';\nimport type { Theme } from '../../../lib/theming/Theme.js';\n\nexport const globalClasses = prefix('masked-internal')({\n input: 'input',\n disabled: 'disabled',\n selected: 'selected',\n masked: 'masked',\n colored: 'colored',\n});\n\nexport const getStyles = memoizeGetStyles(({ css }: Emotion) => ({\n input(t: Theme) {\n return css`\n color-scheme: ${t.inputColorScheme};\n\n &:-internal-autofill-selected {\n background-color: ${t.inputBg} !important;\n background-image: none !important;\n color: ${t.inputTextColor} !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-box-shadow: 0 0 0 1000px ${t.inputBg} inset;\n box-shadow: 0 0 0 1000px ${t.inputBg} inset;\n -webkit-text-fill-color: ${t.inputTextColor} !important;\n color: ${t.inputTextColor} !important;\n /* Chrome иначе скрывает caret при autofill (color/currentColor). */\n caret-color: ${t.inputTextColor} !important;\n transition:\n background-color 0s 600000s,\n color 0s 600000s !important;\n }\n\n &:disabled {\n color: ${t.inputTextColorDisabled};\n\n &:-internal-autofill-selected {\n background-color: ${t.inputDisabledBg} !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-box-shadow: 0 0 0 1000px ${t.inputDisabledBg} inset;\n box-shadow: 0 0 0 1000px ${t.inputDisabledBg} inset;\n }\n }\n\n &.${globalClasses.masked} {\n color: transparent;\n -webkit-text-fill-color: transparent;\n caret-color: ${t.inputTextColor};\n\n &::selection {\n background-color: transparent !important;\n color: transparent !important;\n -webkit-text-fill-color: transparent !important;\n }\n\n /* Текст рисует MaskOverlay; браузер при autofill не должен перебивать fill-color. */\n &:-internal-autofill-selected {\n color: transparent !important;\n caret-color: ${t.inputTextColor} !important;\n }\n\n &:-webkit-autofill,\n &:-webkit-autofill:hover,\n &:-webkit-autofill:focus {\n -webkit-text-fill-color: transparent !important;\n color: transparent !important;\n /* Без этого caret становится transparent вместе с текстом и не мигает. */\n caret-color: ${t.inputTextColor} !important;\n }\n }\n `;\n },\n overlay() {\n return css`\n position: absolute;\n inset: 0;\n pointer-events: none;\n user-select: none;\n overflow: hidden;\n display: flex;\n align-items: center;\n z-index: 2;\n `;\n },\n typed(t: Theme) {\n return css`\n white-space: pre;\n color: ${t.inputTextColor};\n\n &.${globalClasses.disabled} {\n color: ${t.inputTextColorDisabled};\n }\n `;\n },\n mask(t: Theme) {\n return css`\n white-space: pre;\n color: ${t.inputTextColor};\n\n &.${globalClasses.colored} {\n color: ${t.inputPlaceholderColor};\n }\n\n &.${globalClasses.disabled} {\n color: ${t.inputTextColorDisabled};\n }\n `;\n },\n selectedSegment() {\n return css`\n background-color: #3390ff;\n color: #fff !important;\n -webkit-text-fill-color: #fff !important;\n `;\n },\n}));\n"]}
@@ -0,0 +1,11 @@
1
+ import type { MaskedPattern } from '../react-imask/imask/index.js';
2
+ import type { SlotMap } from './types.js';
3
+ /**
4
+ * Строит карту соответствия позиций displayValue и raw-слотов для текущей маски.
5
+ * Временно сбрасывает IMask в пустое состояние с `lazy: false`, чтобы получить
6
+ * полный шаблон с плейсхолдерами (например, `"__.__"` для `mask="99.99"`).
7
+ *
8
+ * @param imask — IMask-инстанс с настроенной маской.
9
+ * @returns карта пользовательских слотов и отображения masked ↔ raw.
10
+ */
11
+ export declare function buildSlotMap(imask: MaskedPattern): SlotMap;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Строит карту соответствия позиций displayValue и raw-слотов для текущей маски.
3
+ * Временно сбрасывает IMask в пустое состояние с `lazy: false`, чтобы получить
4
+ * полный шаблон с плейсхолдерами (например, `"__.__"` для `mask="99.99"`).
5
+ *
6
+ * @param imask — IMask-инстанс с настроенной маской.
7
+ * @returns карта пользовательских слотов и отображения masked ↔ raw.
8
+ */
9
+ export function buildSlotMap(imask) {
10
+ var _a, _b, _c;
11
+ // Сохраняем состояние
12
+ var savedRaw = imask.unmaskedValue;
13
+ var savedLazy = (_c = (_b = (_a = imask._masked) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.lazy) !== null && _c !== void 0 ? _c : true;
14
+ // Получаем пустой шаблон: "_._._" для mask="99.99"
15
+ imask.unmaskedValue = '';
16
+ imask.updateOptions({ lazy: false });
17
+ var emptyDisplay = imask.displayValue;
18
+ // Восстанавливаем состояние
19
+ imask.unmaskedValue = savedRaw;
20
+ imask.updateOptions({ lazy: savedLazy });
21
+ var placeholderChar = imask.placeholderChar;
22
+ var userSlots = [];
23
+ var maskedToRaw = [];
24
+ var rawToMasked = [];
25
+ for (var i = 0; i < emptyDisplay.length; i++) {
26
+ if (emptyDisplay[i] === placeholderChar) {
27
+ rawToMasked.push(i);
28
+ maskedToRaw.push(userSlots.length);
29
+ userSlots.push(i);
30
+ }
31
+ else {
32
+ maskedToRaw.push(null);
33
+ }
34
+ }
35
+ return { userSlots: userSlots, maskedToRaw: maskedToRaw, rawToMasked: rawToMasked };
36
+ }
37
+ //# sourceMappingURL=buildSlotMap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildSlotMap.js","sourceRoot":"","sources":["buildSlotMap.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAoB;;IAC/C,sBAAsB;IACtB,IAAM,QAAQ,GAAG,KAAK,CAAC,aAAa,CAAC;IACrC,IAAM,SAAS,GAAG,MAAA,MAAA,MAAC,KAAa,CAAC,OAAO,0CAAE,OAAO,0CAAE,IAAI,mCAAI,IAAI,CAAC;IAEhE,mDAAmD;IACnD,KAAK,CAAC,aAAa,GAAG,EAAE,CAAC;IACzB,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrC,IAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IAExC,4BAA4B;IAC5B,KAAK,CAAC,aAAa,GAAG,QAAQ,CAAC;IAC/B,KAAK,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAEzC,IAAM,eAAe,GAAG,KAAK,CAAC,eAAe,CAAC;IAC9C,IAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAM,WAAW,GAAyB,EAAE,CAAC;IAC7C,IAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,IAAI,YAAY,CAAC,CAAC,CAAC,KAAK,eAAe,EAAE,CAAC;YACxC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACnC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,WAAA,EAAE,WAAW,aAAA,EAAE,WAAW,aAAA,EAAE,CAAC;AACjD,CAAC","sourcesContent":["import type { MaskedPattern } from '../react-imask/imask/index.js';\nimport type { SlotMap } from './types.js';\n\n/**\n * Строит карту соответствия позиций displayValue и raw-слотов для текущей маски.\n * Временно сбрасывает IMask в пустое состояние с `lazy: false`, чтобы получить\n * полный шаблон с плейсхолдерами (например, `\"__.__\"` для `mask=\"99.99\"`).\n *\n * @param imask — IMask-инстанс с настроенной маской.\n * @returns карта пользовательских слотов и отображения masked ↔ raw.\n */\nexport function buildSlotMap(imask: MaskedPattern): SlotMap {\n // Сохраняем состояние\n const savedRaw = imask.unmaskedValue;\n const savedLazy = (imask as any)._masked?.options?.lazy ?? true;\n\n // Получаем пустой шаблон: \"_._._\" для mask=\"99.99\"\n imask.unmaskedValue = '';\n imask.updateOptions({ lazy: false });\n const emptyDisplay = imask.displayValue;\n\n // Восстанавливаем состояние\n imask.unmaskedValue = savedRaw;\n imask.updateOptions({ lazy: savedLazy });\n\n const placeholderChar = imask.placeholderChar;\n const userSlots: number[] = [];\n const maskedToRaw: Array<number | null> = [];\n const rawToMasked: number[] = [];\n\n for (let i = 0; i < emptyDisplay.length; i++) {\n if (emptyDisplay[i] === placeholderChar) {\n rawToMasked.push(i);\n maskedToRaw.push(userSlots.length);\n userSlots.push(i);\n } else {\n maskedToRaw.push(null);\n }\n }\n\n return { userSlots, maskedToRaw, rawToMasked };\n}\n"]}
@@ -0,0 +1,6 @@
1
+ import type React from 'react';
2
+ /** Горизонтальный offset начала текста overlay относительно левого края input. */
3
+ export declare function measureOverlayTextStart(input: HTMLInputElement, overlayContainer: HTMLElement | null): number;
4
+ /** Смещение текста input влево, чтобы каретка совпала с overlay при center/right align. */
5
+ export declare function computeMaskAlignPadding(input: HTMLInputElement, displayValue: string, textAlign?: React.CSSProperties['textAlign'], overlayContainer?: HTMLElement | null): number;
6
+ export declare function needsMaskAlignPadding(textAlign?: React.CSSProperties['textAlign']): boolean;
@@ -0,0 +1,47 @@
1
+ import { getOwnerGlobalObject, isBrowser } from '../../../lib/globalObject.js';
2
+ import { measureInputTextWidth } from './measureInputTextWidth.js';
3
+ /** Горизонтальный offset начала текста overlay относительно левого края input. */
4
+ export function measureOverlayTextStart(input, overlayContainer) {
5
+ if (!overlayContainer) {
6
+ return 0;
7
+ }
8
+ var textEl = overlayContainer.querySelector('[data-tid="masked-input-overlay"]');
9
+ if (!(textEl === null || textEl === void 0 ? void 0 : textEl.textContent)) {
10
+ return 0;
11
+ }
12
+ var globalObject = getOwnerGlobalObject(input);
13
+ if (!isBrowser(globalObject) || !('createRange' in globalObject.document)) {
14
+ return 0;
15
+ }
16
+ var range = globalObject.document.createRange();
17
+ range.selectNodeContents(textEl);
18
+ var textRect = range.getBoundingClientRect();
19
+ var inputRect = input.getBoundingClientRect();
20
+ return Math.max(0, textRect.left - inputRect.left);
21
+ }
22
+ function computeMaskAlignPaddingFromTextWidth(input, displayValue, textAlign) {
23
+ var textWidth = measureInputTextWidth(input, displayValue);
24
+ var availableWidth = input.clientWidth;
25
+ if (textAlign === 'center') {
26
+ return Math.max(0, (availableWidth - textWidth) / 2);
27
+ }
28
+ return Math.max(0, availableWidth - textWidth);
29
+ }
30
+ /** Смещение текста input влево, чтобы каретка совпала с overlay при center/right align. */
31
+ export function computeMaskAlignPadding(input, displayValue, textAlign, overlayContainer) {
32
+ if (textAlign !== 'center' && textAlign !== 'right') {
33
+ return 0;
34
+ }
35
+ if (!displayValue) {
36
+ return 0;
37
+ }
38
+ var measuredStart = measureOverlayTextStart(input, overlayContainer !== null && overlayContainer !== void 0 ? overlayContainer : null);
39
+ if (measuredStart > 0) {
40
+ return measuredStart;
41
+ }
42
+ return computeMaskAlignPaddingFromTextWidth(input, displayValue, textAlign);
43
+ }
44
+ export function needsMaskAlignPadding(textAlign) {
45
+ return textAlign === 'center' || textAlign === 'right';
46
+ }
47
+ //# sourceMappingURL=computeMaskAlignPadding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computeMaskAlignPadding.js","sourceRoot":"","sources":["computeMaskAlignPadding.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,kFAAkF;AAClF,MAAM,UAAU,uBAAuB,CAAC,KAAuB,EAAE,gBAAoC;IACnG,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAM,MAAM,GAAG,gBAAgB,CAAC,aAAa,CAAC,mCAAmC,CAAC,CAAC;IACnF,IAAI,CAAC,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,CAAA,EAAE,CAAC;QACzB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAM,YAAY,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACjD,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,aAAa,IAAI,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAClD,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjC,IAAM,QAAQ,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAC;IAC/C,IAAM,SAAS,GAAG,KAAK,CAAC,qBAAqB,EAAE,CAAC;IAEhD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,oCAAoC,CAC3C,KAAuB,EACvB,YAAoB,EACpB,SAA6B;IAE7B,IAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC7D,IAAM,cAAc,GAAG,KAAK,CAAC,WAAW,CAAC;IAEzC,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,cAAc,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC,CAAC;AACjD,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,uBAAuB,CACrC,KAAuB,EACvB,YAAoB,EACpB,SAA4C,EAC5C,gBAAqC;IAErC,IAAI,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QACpD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAM,aAAa,GAAG,uBAAuB,CAAC,KAAK,EAAE,gBAAgB,aAAhB,gBAAgB,cAAhB,gBAAgB,GAAI,IAAI,CAAC,CAAC;IAC/E,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,OAAO,oCAAoC,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAA4C;IAChF,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,OAAO,CAAC;AACzD,CAAC","sourcesContent":["import type React from 'react';\n\nimport { getOwnerGlobalObject, isBrowser } from '../../../lib/globalObject.js';\nimport { measureInputTextWidth } from './measureInputTextWidth.js';\n\n/** Горизонтальный offset начала текста overlay относительно левого края input. */\nexport function measureOverlayTextStart(input: HTMLInputElement, overlayContainer: HTMLElement | null): number {\n if (!overlayContainer) {\n return 0;\n }\n\n const textEl = overlayContainer.querySelector('[data-tid=\"masked-input-overlay\"]');\n if (!textEl?.textContent) {\n return 0;\n }\n\n const globalObject = getOwnerGlobalObject(input);\n if (!isBrowser(globalObject) || !('createRange' in globalObject.document)) {\n return 0;\n }\n\n const range = globalObject.document.createRange();\n range.selectNodeContents(textEl);\n const textRect = range.getBoundingClientRect();\n const inputRect = input.getBoundingClientRect();\n\n return Math.max(0, textRect.left - inputRect.left);\n}\n\nfunction computeMaskAlignPaddingFromTextWidth(\n input: HTMLInputElement,\n displayValue: string,\n textAlign: 'center' | 'right',\n): number {\n const textWidth = measureInputTextWidth(input, displayValue);\n const availableWidth = input.clientWidth;\n\n if (textAlign === 'center') {\n return Math.max(0, (availableWidth - textWidth) / 2);\n }\n\n return Math.max(0, availableWidth - textWidth);\n}\n\n/** Смещение текста input влево, чтобы каретка совпала с overlay при center/right align. */\nexport function computeMaskAlignPadding(\n input: HTMLInputElement,\n displayValue: string,\n textAlign?: React.CSSProperties['textAlign'],\n overlayContainer?: HTMLElement | null,\n): number {\n if (textAlign !== 'center' && textAlign !== 'right') {\n return 0;\n }\n\n if (!displayValue) {\n return 0;\n }\n\n const measuredStart = measureOverlayTextStart(input, overlayContainer ?? null);\n if (measuredStart > 0) {\n return measuredStart;\n }\n\n return computeMaskAlignPaddingFromTextWidth(input, displayValue, textAlign);\n}\n\nexport function needsMaskAlignPadding(textAlign?: React.CSSProperties['textAlign']): boolean {\n return textAlign === 'center' || textAlign === 'right';\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { SlotMap } from './types.js';
2
+ /** Masked-позиция каретки после вставки в rawCursorPos. */
3
+ export declare function computePasteMaskedCursor(rawBefore: string, rawAfter: string, resultRaw: string, rawCursorPos: number, slotMap: SlotMap, typedLength: number): number;
@@ -0,0 +1,11 @@
1
+ /** Masked-позиция каретки после вставки в rawCursorPos. */
2
+ export function computePasteMaskedCursor(rawBefore, rawAfter, resultRaw, rawCursorPos, slotMap, typedLength) {
3
+ var _a;
4
+ var insertedRawLength = resultRaw.length - rawBefore.length - rawAfter.length;
5
+ var newRawCursorPos = rawCursorPos + Math.max(0, insertedRawLength);
6
+ if (newRawCursorPos >= slotMap.rawToMasked.length) {
7
+ return typedLength;
8
+ }
9
+ return (_a = slotMap.rawToMasked[newRawCursorPos]) !== null && _a !== void 0 ? _a : typedLength;
10
+ }
11
+ //# sourceMappingURL=computePasteMaskedCursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"computePasteMaskedCursor.js","sourceRoot":"","sources":["computePasteMaskedCursor.ts"],"names":[],"mappings":"AAEA,2DAA2D;AAC3D,MAAM,UAAU,wBAAwB,CACtC,SAAiB,EACjB,QAAgB,EAChB,SAAiB,EACjB,YAAoB,EACpB,OAAgB,EAChB,WAAmB;;IAEnB,IAAM,iBAAiB,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;IAChF,IAAM,eAAe,GAAG,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAEtE,IAAI,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;QAClD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,MAAA,OAAO,CAAC,WAAW,CAAC,eAAe,CAAC,mCAAI,WAAW,CAAC;AAC7D,CAAC","sourcesContent":["import type { SlotMap } from './types.js';\n\n/** Masked-позиция каретки после вставки в rawCursorPos. */\nexport function computePasteMaskedCursor(\n rawBefore: string,\n rawAfter: string,\n resultRaw: string,\n rawCursorPos: number,\n slotMap: SlotMap,\n typedLength: number,\n): number {\n const insertedRawLength = resultRaw.length - rawBefore.length - rawAfter.length;\n const newRawCursorPos = rawCursorPos + Math.max(0, insertedRawLength);\n\n if (newRawCursorPos >= slotMap.rawToMasked.length) {\n return typedLength;\n }\n\n return slotMap.rawToMasked[newRawCursorPos] ?? typedLength;\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import type { MaskEngine } from './types.js';
2
+ /**
3
+ * Извлекает raw (unmasked) значение из masked или unmasked строки.
4
+ * Принимает любой формат — IMask сам разберёт.
5
+ *
6
+ * @param value — значение из props или буфера обмена (masked/unmasked).
7
+ * @param engine — движок маски с IMask-инстансом.
8
+ * @returns строка только из пользовательских символов без литералов маски.
9
+ */
10
+ export declare function extractRaw(value: string | number | null | undefined, engine: Pick<MaskEngine, 'imask'>): string;