@dr.pogodin/react-utils 1.41.17 → 1.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/babel.config.js +3 -0
  2. package/bin/build.js +5 -8
  3. package/bin/setup.js +2 -1
  4. package/build/development/client/getInj.js +7 -2
  5. package/build/development/client/getInj.js.map +1 -1
  6. package/build/development/client/index.js +1 -2
  7. package/build/development/client/index.js.map +1 -1
  8. package/build/development/client/init.js +16 -13
  9. package/build/development/client/init.js.map +1 -1
  10. package/build/development/index.js +4 -1
  11. package/build/development/index.js.map +1 -1
  12. package/build/development/server/Cache.js +5 -9
  13. package/build/development/server/Cache.js.map +1 -1
  14. package/build/development/server/index.js +14 -11
  15. package/build/development/server/index.js.map +1 -1
  16. package/build/development/server/renderer.js +36 -41
  17. package/build/development/server/renderer.js.map +1 -1
  18. package/build/development/server/server.js +22 -13
  19. package/build/development/server/server.js.map +1 -1
  20. package/build/development/server/utils/errors.js.map +1 -1
  21. package/build/development/shared/components/Button/index.js +2 -3
  22. package/build/development/shared/components/Button/index.js.map +1 -1
  23. package/build/development/shared/components/Checkbox/index.js +3 -1
  24. package/build/development/shared/components/Checkbox/index.js.map +1 -1
  25. package/build/development/shared/components/GenericLink/index.js +13 -6
  26. package/build/development/shared/components/GenericLink/index.js.map +1 -1
  27. package/build/development/shared/components/Input/index.js +5 -1
  28. package/build/development/shared/components/Input/index.js.map +1 -1
  29. package/build/development/shared/components/Link.js +5 -6
  30. package/build/development/shared/components/Link.js.map +1 -1
  31. package/build/development/shared/components/MetaTags.js +31 -24
  32. package/build/development/shared/components/MetaTags.js.map +1 -1
  33. package/build/development/shared/components/Modal/index.js +13 -6
  34. package/build/development/shared/components/Modal/index.js.map +1 -1
  35. package/build/development/shared/components/NavLink.js +6 -6
  36. package/build/development/shared/components/NavLink.js.map +1 -1
  37. package/build/development/shared/components/TextArea/index.js +6 -3
  38. package/build/development/shared/components/TextArea/index.js.map +1 -1
  39. package/build/development/shared/components/WithTooltip/Tooltip.js +35 -39
  40. package/build/development/shared/components/WithTooltip/Tooltip.js.map +1 -1
  41. package/build/development/shared/components/WithTooltip/index.js +27 -21
  42. package/build/development/shared/components/WithTooltip/index.js.map +1 -1
  43. package/build/development/shared/components/YouTubeVideo/index.js +4 -3
  44. package/build/development/shared/components/YouTubeVideo/index.js.map +1 -1
  45. package/build/development/shared/components/selectors/CustomDropdown/Options/index.js +4 -5
  46. package/build/development/shared/components/selectors/CustomDropdown/Options/index.js.map +1 -1
  47. package/build/development/shared/components/selectors/CustomDropdown/index.js +7 -9
  48. package/build/development/shared/components/selectors/CustomDropdown/index.js.map +1 -1
  49. package/build/development/shared/components/selectors/NativeDropdown/index.js +3 -5
  50. package/build/development/shared/components/selectors/NativeDropdown/index.js.map +1 -1
  51. package/build/development/shared/components/selectors/Switch/index.js +21 -20
  52. package/build/development/shared/components/selectors/Switch/index.js.map +1 -1
  53. package/build/development/shared/utils/config.js +6 -3
  54. package/build/development/shared/utils/config.js.map +1 -1
  55. package/build/development/shared/utils/globalState.js +6 -0
  56. package/build/development/shared/utils/globalState.js.map +1 -1
  57. package/build/development/shared/utils/isomorphy/buildInfo.js.map +1 -1
  58. package/build/development/shared/utils/isomorphy/environment-check.js +6 -1
  59. package/build/development/shared/utils/isomorphy/environment-check.js.map +1 -1
  60. package/build/development/shared/utils/isomorphy/index.js +1 -3
  61. package/build/development/shared/utils/isomorphy/index.js.map +1 -1
  62. package/build/development/shared/utils/jest/E2eSsrEnv.js +26 -17
  63. package/build/development/shared/utils/jest/E2eSsrEnv.js.map +1 -1
  64. package/build/development/shared/utils/jest/global.js +0 -7
  65. package/build/development/shared/utils/jest/global.js.map +1 -1
  66. package/build/development/shared/utils/jest/index.js +15 -4
  67. package/build/development/shared/utils/jest/index.js.map +1 -1
  68. package/build/development/shared/utils/splitComponent.js +37 -19
  69. package/build/development/shared/utils/splitComponent.js.map +1 -1
  70. package/build/development/shared/utils/time.js +3 -3
  71. package/build/development/shared/utils/time.js.map +1 -1
  72. package/build/development/shared/utils/webpack.js +11 -11
  73. package/build/development/shared/utils/webpack.js.map +1 -1
  74. package/build/development/web.bundle.js +31 -31
  75. package/build/production/client/getInj.js +4 -2
  76. package/build/production/client/getInj.js.map +1 -1
  77. package/build/production/client/index.js +2 -2
  78. package/build/production/client/index.js.map +1 -1
  79. package/build/production/client/init.js +4 -2
  80. package/build/production/client/init.js.map +1 -1
  81. package/build/production/index.js +2 -1
  82. package/build/production/index.js.map +1 -1
  83. package/build/production/server/Cache.js +1 -2
  84. package/build/production/server/Cache.js.map +1 -1
  85. package/build/production/server/index.js +9 -5
  86. package/build/production/server/index.js.map +1 -1
  87. package/build/production/server/renderer.js +24 -21
  88. package/build/production/server/renderer.js.map +1 -1
  89. package/build/production/server/server.js +14 -9
  90. package/build/production/server/server.js.map +1 -1
  91. package/build/production/server/utils/errors.js.map +1 -1
  92. package/build/production/shared/components/Button/index.js +1 -1
  93. package/build/production/shared/components/Button/index.js.map +1 -1
  94. package/build/production/shared/components/Checkbox/index.js +1 -1
  95. package/build/production/shared/components/Checkbox/index.js.map +1 -1
  96. package/build/production/shared/components/GenericLink/index.js +6 -4
  97. package/build/production/shared/components/GenericLink/index.js.map +1 -1
  98. package/build/production/shared/components/Input/index.js +3 -1
  99. package/build/production/shared/components/Input/index.js.map +1 -1
  100. package/build/production/shared/components/Link.js +3 -1
  101. package/build/production/shared/components/Link.js.map +1 -1
  102. package/build/production/shared/components/MetaTags.js +5 -2
  103. package/build/production/shared/components/MetaTags.js.map +1 -1
  104. package/build/production/shared/components/Modal/index.js +6 -2
  105. package/build/production/shared/components/Modal/index.js.map +1 -1
  106. package/build/production/shared/components/NavLink.js +4 -1
  107. package/build/production/shared/components/NavLink.js.map +1 -1
  108. package/build/production/shared/components/TextArea/index.js +4 -4
  109. package/build/production/shared/components/TextArea/index.js.map +1 -1
  110. package/build/production/shared/components/WithTooltip/Tooltip.js +37 -38
  111. package/build/production/shared/components/WithTooltip/Tooltip.js.map +1 -1
  112. package/build/production/shared/components/WithTooltip/index.js +4 -4
  113. package/build/production/shared/components/WithTooltip/index.js.map +1 -1
  114. package/build/production/shared/components/YouTubeVideo/index.js +3 -2
  115. package/build/production/shared/components/YouTubeVideo/index.js.map +1 -1
  116. package/build/production/shared/components/selectors/CustomDropdown/Options/index.js +2 -2
  117. package/build/production/shared/components/selectors/CustomDropdown/Options/index.js.map +1 -1
  118. package/build/production/shared/components/selectors/CustomDropdown/index.js +2 -2
  119. package/build/production/shared/components/selectors/CustomDropdown/index.js.map +1 -1
  120. package/build/production/shared/components/selectors/NativeDropdown/index.js +2 -2
  121. package/build/production/shared/components/selectors/NativeDropdown/index.js.map +1 -1
  122. package/build/production/shared/components/selectors/Switch/index.js +1 -1
  123. package/build/production/shared/components/selectors/Switch/index.js.map +1 -1
  124. package/build/production/shared/utils/config.js +6 -4
  125. package/build/production/shared/utils/config.js.map +1 -1
  126. package/build/production/shared/utils/globalState.js +4 -1
  127. package/build/production/shared/utils/globalState.js.map +1 -1
  128. package/build/production/shared/utils/isomorphy/buildInfo.js.map +1 -1
  129. package/build/production/shared/utils/isomorphy/environment-check.js +5 -1
  130. package/build/production/shared/utils/isomorphy/environment-check.js.map +1 -1
  131. package/build/production/shared/utils/isomorphy/index.js +1 -3
  132. package/build/production/shared/utils/isomorphy/index.js.map +1 -1
  133. package/build/production/shared/utils/jest/E2eSsrEnv.js +15 -8
  134. package/build/production/shared/utils/jest/E2eSsrEnv.js.map +1 -1
  135. package/build/production/shared/utils/jest/global.js +1 -1
  136. package/build/production/shared/utils/jest/global.js.map +1 -1
  137. package/build/production/shared/utils/jest/index.js +13 -5
  138. package/build/production/shared/utils/jest/index.js.map +1 -1
  139. package/build/production/shared/utils/splitComponent.js +16 -8
  140. package/build/production/shared/utils/splitComponent.js.map +1 -1
  141. package/build/production/shared/utils/time.js +2 -2
  142. package/build/production/shared/utils/time.js.map +1 -1
  143. package/build/production/shared/utils/webpack.js +5 -2
  144. package/build/production/shared/utils/webpack.js.map +1 -1
  145. package/build/production/web.bundle.js +1 -1
  146. package/build/production/web.bundle.js.map +1 -1
  147. package/build/types-code/client/getInj.d.ts +1 -1
  148. package/build/types-code/client/index.d.ts +2 -2
  149. package/build/types-code/client/init.d.ts +1 -1
  150. package/build/types-code/index.d.ts +6 -5
  151. package/build/types-code/server/Cache.d.ts +1 -2
  152. package/build/types-code/server/index.d.ts +4 -5
  153. package/build/types-code/server/renderer.d.ts +9 -11
  154. package/build/types-code/server/server.d.ts +3 -5
  155. package/build/types-code/server/utils/errors.d.ts +1 -1
  156. package/build/types-code/shared/components/Button/index.d.ts +2 -2
  157. package/build/types-code/shared/components/TextArea/index.d.ts +3 -3
  158. package/build/types-code/shared/components/WithTooltip/Tooltip.d.ts +7 -1
  159. package/build/types-code/shared/components/index.d.ts +12 -12
  160. package/build/types-code/shared/utils/config.d.ts +1 -1
  161. package/build/types-code/shared/utils/globalState.d.ts +3 -6
  162. package/build/types-code/shared/utils/isomorphy/index.d.ts +1 -3
  163. package/build/types-code/shared/utils/jest/E2eSsrEnv.d.ts +1 -1
  164. package/build/types-code/shared/utils/jest/global.d.ts +4 -4
  165. package/build/types-code/shared/utils/jest/index.d.ts +2 -2
  166. package/build/types-code/shared/utils/webpack.d.ts +1 -1
  167. package/config/babel/node-ssr.d.ts +3 -2
  168. package/config/babel/node-ssr.js +5 -7
  169. package/config/babel/webpack.d.ts +3 -11
  170. package/config/babel/webpack.js +15 -15
  171. package/config/eslint/default.mjs +32 -0
  172. package/config/jest/default.js +10 -6
  173. package/config/jest/resolver.js +2 -0
  174. package/config/jest/setup.js +2 -2
  175. package/config/stylelint/default.js +3 -0
  176. package/config/webpack/app-base.d.ts +0 -6
  177. package/config/webpack/app-base.js +64 -70
  178. package/config/webpack/app-development.d.ts +2 -2
  179. package/config/webpack/app-development.js +8 -12
  180. package/config/webpack/app-production.js +1 -0
  181. package/config/webpack/lib-base.js +20 -18
  182. package/config/webpack/lib-development.js +1 -0
  183. package/config/webpack/lib-production.js +1 -0
  184. package/config/workbox/default.js +2 -5
  185. package/dev-styles.js +1 -0
  186. package/eslint.config.mjs +13 -0
  187. package/node-entry.js +7 -2
  188. package/null.js +1 -0
  189. package/package.json +27 -35
  190. package/prod-styles.js +1 -0
  191. package/src/client/getInj.ts +8 -3
  192. package/src/client/index.tsx +4 -4
  193. package/src/client/init.ts +18 -15
  194. package/src/index.ts +8 -3
  195. package/src/server/Cache.ts +7 -15
  196. package/src/server/index.ts +30 -21
  197. package/src/server/renderer.tsx +77 -67
  198. package/src/server/server.ts +41 -21
  199. package/src/server/utils/errors.ts +6 -3
  200. package/src/shared/components/Button/index.tsx +4 -5
  201. package/src/shared/components/Checkbox/index.tsx +10 -7
  202. package/src/shared/components/GenericLink/index.tsx +14 -7
  203. package/src/shared/components/Input/index.tsx +4 -1
  204. package/src/shared/components/Link.tsx +9 -5
  205. package/src/shared/components/MetaTags.tsx +21 -15
  206. package/src/shared/components/Modal/index.tsx +12 -11
  207. package/src/shared/components/NavLink.tsx +10 -5
  208. package/src/shared/components/TextArea/index.tsx +17 -9
  209. package/src/shared/components/WithTooltip/{Tooltip.tsx → Tooltip.ts} +35 -39
  210. package/src/shared/components/WithTooltip/index.tsx +36 -30
  211. package/src/shared/components/YouTubeVideo/index.tsx +10 -6
  212. package/src/shared/components/selectors/CustomDropdown/Options/index.tsx +5 -6
  213. package/src/shared/components/selectors/CustomDropdown/index.tsx +10 -14
  214. package/src/shared/components/selectors/NativeDropdown/index.tsx +5 -7
  215. package/src/shared/components/selectors/Switch/index.tsx +19 -17
  216. package/src/shared/utils/config.ts +12 -5
  217. package/src/shared/utils/globalState.ts +8 -5
  218. package/src/shared/utils/isomorphy/buildInfo.ts +1 -1
  219. package/src/shared/utils/isomorphy/environment-check.ts +5 -1
  220. package/src/shared/utils/isomorphy/index.ts +4 -6
  221. package/src/shared/utils/jest/E2eSsrEnv.ts +64 -39
  222. package/src/shared/utils/jest/global.ts +6 -8
  223. package/src/shared/utils/jest/{index.tsx → index.ts} +25 -12
  224. package/src/shared/utils/splitComponent.tsx +44 -25
  225. package/src/shared/utils/time.ts +16 -9
  226. package/src/shared/utils/webpack.ts +19 -14
  227. package/webpack.config.ts +36 -10
  228. package/config/eslint/default.json +0 -30
  229. package/config/eslint/jest.json +0 -19
  230. package/config/eslint/typescript.js +0 -46
@@ -18,8 +18,10 @@ import { createPortal } from 'react-dom';
18
18
 
19
19
  import type { Theme } from '@dr.pogodin/react-themes';
20
20
 
21
- /* Valid placements of the rendered tooltip. They will be overriden when
22
- * necessary to fit the tooltip within the viewport. */
21
+ /**
22
+ * Valid placements of the rendered tooltip. They will be overriden when
23
+ * necessary to fit the tooltip within the viewport.
24
+ */
23
25
  export enum PLACEMENTS {
24
26
  ABOVE_CURSOR = 'ABOVE_CURSOR',
25
27
  ABOVE_ELEMENT = 'ABOVE_ELEMENT',
@@ -82,7 +84,7 @@ function createTooltipComponents(theme: TooltipThemeT): ComponentsT {
82
84
  container.appendChild(content);
83
85
  document.body.appendChild(container);
84
86
 
85
- return { container, arrow, content };
87
+ return { arrow, container, content };
86
88
  }
87
89
 
88
90
  type TooltipRectsT = {
@@ -115,10 +117,10 @@ function calcViewportRect() {
115
117
  const { scrollX, scrollY } = window;
116
118
  const { documentElement: { clientHeight, clientWidth } } = document;
117
119
  return {
120
+ bottom: scrollY + clientHeight,
118
121
  left: scrollX,
119
122
  right: scrollX + clientWidth,
120
123
  top: scrollY,
121
- bottom: scrollY + clientHeight,
122
124
  };
123
125
  }
124
126
 
@@ -157,15 +159,13 @@ function calcPositionAboveXY(
157
159
  };
158
160
  }
159
161
 
160
- /*
161
- const HIT = {
162
- NONE: false,
163
- LEFT: 'LEFT',
164
- RIGHT: 'RIGHT',
165
- TOP: 'TOP',
166
- BOTTOM: 'BOTTOM',
167
- };
168
- */
162
+ // const HIT = {
163
+ // NONE: false,
164
+ // LEFT: 'LEFT',
165
+ // RIGHT: 'RIGHT',
166
+ // TOP: 'TOP',
167
+ // BOTTOM: 'BOTTOM',
168
+ // };
169
169
 
170
170
  /**
171
171
  * Checks whether
@@ -174,14 +174,12 @@ const HIT = {
174
174
  * @param {object} viewportRect
175
175
  * @return {HIT}
176
176
  */
177
- /*
178
- function checkViewportFit(pos, tooltipRects, viewportRect) {
179
- const { containerX, containerY } = pos;
180
- if (containerX < viewportRect.left + 6) return HIT.LEFT;
181
- if (containerX > viewportRect.right - 6) return HIT.RIGHT;
182
- return HIT.NONE;
183
- }
184
- */
177
+ // function checkViewportFit(pos, tooltipRects, viewportRect) {
178
+ // const { containerX, containerY } = pos;
179
+ // if (containerX < viewportRect.left + 6) return HIT.LEFT;
180
+ // if (containerX > viewportRect.right - 6) return HIT.RIGHT;
181
+ // return HIT.NONE;
182
+ // }
185
183
 
186
184
  /**
187
185
  * Shifts tooltip horizontally to fit into the viewport, while keeping
@@ -192,23 +190,21 @@ function checkViewportFit(pos, tooltipRects, viewportRect) {
192
190
  * @param {number} pageXOffset
193
191
  * @param {number} pageXWidth
194
192
  */
195
- /*
196
- function xPageFitCorrection(x, y, pos, pageXOffset, pageXWidth) {
197
- if (pos.containerX < pageXOffset + 6) {
198
- pos.containerX = pageXOffset + 6;
199
- pos.arrowX = Math.max(6, pageX - containerX - arrowRect.width / 2);
200
- } else {
201
- const maxX = pageXOffset + docRect.width - containerRect.width - 6;
202
- if (containerX > maxX) {
203
- containerX = maxX;
204
- arrowX = Math.min(
205
- containerRect.width - 6,
206
- pageX - containerX - arrowRect.width / 2,
207
- );
208
- }
209
- }
210
- }
211
- */
193
+ // function xPageFitCorrection(x, y, pos, pageXOffset, pageXWidth) {
194
+ // if (pos.containerX < pageXOffset + 6) {
195
+ // pos.containerX = pageXOffset + 6;
196
+ // pos.arrowX = Math.max(6, pageX - containerX - arrowRect.width / 2);
197
+ // } else {
198
+ // const maxX = pageXOffset + docRect.width - containerRect.width - 6;
199
+ // if (containerX > maxX) {
200
+ // containerX = maxX;
201
+ // arrowX = Math.min(
202
+ // containerRect.width - 6,
203
+ // pageX - containerX - arrowRect.width / 2,
204
+ // );
205
+ // }
206
+ // }
207
+ // }
212
208
 
213
209
  /**
214
210
  * Sets positions of tooltip components to point the tooltip to the specified
@@ -272,7 +268,7 @@ function setComponentPositions(
272
268
  const Tooltip: FunctionComponent<{
273
269
  children?: ReactNode;
274
270
  ref?: RefObject<unknown>;
275
- theme: any;
271
+ theme: TooltipThemeT;
276
272
  }> = ({ children, ref, theme }) => {
277
273
  // NOTE: The way it has to be implemented, for clean mounting and unmounting
278
274
  // at the client side, the <Tooltip> is fully mounted into DOM in the next
@@ -63,34 +63,15 @@ const Wrapper: FunctionComponent<PropsT> = ({
63
63
  const { current: heap } = useRef<HeapT>({
64
64
  lastCursorX: 0,
65
65
  lastCursorY: 0,
66
- triggeredByTouch: false,
67
66
  timerId: undefined,
67
+ triggeredByTouch: false,
68
68
  });
69
69
  const tooltipRef = useRef<TooltipRefT>(null);
70
70
  const wrapperRef = useRef<HTMLDivElement>(null);
71
71
  const [showTooltip, setShowTooltip] = useState(false);
72
72
 
73
73
  const updatePortalPosition = (cursorX: number, cursorY: number) => {
74
- if (!showTooltip) {
75
- heap.lastCursorX = cursorX;
76
- heap.lastCursorY = cursorY;
77
-
78
- // If tooltip was triggered by a touch, we delay its opening by a bit,
79
- // to ensure it was not a touch-click - in the case of touch click we
80
- // want to do the click, rather than show the tooltip, and the delay
81
- // gives click handler a chance to abort the tooltip openning.
82
- if (heap.triggeredByTouch) {
83
- if (!heap.timerId) {
84
- heap.timerId = setTimeout(() => {
85
- heap.triggeredByTouch = false;
86
- heap.timerId = undefined;
87
- setShowTooltip(true);
88
- }, 300);
89
- }
90
-
91
- // Otherwise we can just open the tooltip right away.
92
- } else setShowTooltip(true);
93
- } else {
74
+ if (showTooltip) {
94
75
  const wrapperRect = wrapperRef.current!.getBoundingClientRect();
95
76
  if (
96
77
  cursorX < wrapperRect.left
@@ -103,10 +84,27 @@ const Wrapper: FunctionComponent<PropsT> = ({
103
84
  tooltipRef.current.pointTo(
104
85
  cursorX + window.scrollX,
105
86
  cursorY + window.scrollY,
106
- placement!,
87
+ placement,
107
88
  wrapperRef.current!,
108
89
  );
109
90
  }
91
+ } else {
92
+ heap.lastCursorX = cursorX;
93
+ heap.lastCursorY = cursorY;
94
+
95
+ // If tooltip was triggered by a touch, we delay its opening by a bit,
96
+ // to ensure it was not a touch-click - in the case of touch click we
97
+ // want to do the click, rather than show the tooltip, and the delay
98
+ // gives click handler a chance to abort the tooltip openning.
99
+ if (heap.triggeredByTouch) {
100
+ heap.timerId ??= setTimeout(() => {
101
+ heap.triggeredByTouch = false;
102
+ heap.timerId = undefined;
103
+ setShowTooltip(true);
104
+ }, 300);
105
+
106
+ // Otherwise we can just open the tooltip right away.
107
+ } else setShowTooltip(true);
110
108
  }
111
109
  };
112
110
 
@@ -121,14 +119,18 @@ const Wrapper: FunctionComponent<PropsT> = ({
121
119
  tooltipRef.current.pointTo(
122
120
  heap.lastCursorX + window.scrollX,
123
121
  heap.lastCursorY + window.scrollY,
124
- placement!,
122
+ placement,
125
123
  wrapperRef.current!,
126
124
  );
127
125
  }
128
126
 
129
- const listener = () => setShowTooltip(false);
127
+ const listener = () => {
128
+ setShowTooltip(false);
129
+ };
130
130
  window.addEventListener('scroll', listener);
131
- return () => window.removeEventListener('scroll', listener);
131
+ return () => {
132
+ window.removeEventListener('scroll', listener);
133
+ };
132
134
  }
133
135
  return undefined;
134
136
  }, [
@@ -142,8 +144,6 @@ const Wrapper: FunctionComponent<PropsT> = ({
142
144
  return (
143
145
  <div
144
146
  className={theme.wrapper}
145
- onMouseLeave={() => setShowTooltip(false)}
146
- onMouseMove={(e) => updatePortalPosition(e.clientX, e.clientY)}
147
147
  onClick={() => {
148
148
  if (heap.timerId) {
149
149
  clearTimeout(heap.timerId);
@@ -151,6 +151,12 @@ const Wrapper: FunctionComponent<PropsT> = ({
151
151
  heap.triggeredByTouch = false;
152
152
  }
153
153
  }}
154
+ onMouseLeave={() => {
155
+ setShowTooltip(false);
156
+ }}
157
+ onMouseMove={(e) => {
158
+ updatePortalPosition(e.clientX, e.clientY);
159
+ }}
154
160
  onTouchStart={() => {
155
161
  heap.triggeredByTouch = true;
156
162
  }}
@@ -158,9 +164,9 @@ const Wrapper: FunctionComponent<PropsT> = ({
158
164
  role="presentation"
159
165
  >
160
166
  {
161
- showTooltip && tip !== null ? (
162
- <Tooltip ref={tooltipRef} theme={theme}>{tip}</Tooltip>
163
- ) : null
167
+ showTooltip && tip !== null
168
+ ? <Tooltip ref={tooltipRef} theme={theme}>{tip}</Tooltip>
169
+ : null
164
170
  }
165
171
  {children}
166
172
  </div>
@@ -12,7 +12,7 @@ type ComponentThemeT = Theme<'container' | 'video'>;
12
12
  type PropsT = {
13
13
  autoplay?: boolean;
14
14
  src: string;
15
- theme: ComponentThemeT,
15
+ theme: ComponentThemeT;
16
16
  title?: string;
17
17
  };
18
18
 
@@ -38,12 +38,12 @@ const YouTubeVideo: React.FunctionComponent<PropsT> = ({
38
38
  title,
39
39
  }) => {
40
40
  const srcParts = src.split('?');
41
- let url = srcParts[0];
42
- const queryString = srcParts[1];
41
+ let [url] = srcParts;
42
+ const [, queryString] = srcParts;
43
43
  const query = queryString ? qs.parse(queryString) : {};
44
44
 
45
- const videoId = query.v || url?.match(/\/([a-zA-Z0-9-_]*)$/)?.[1];
46
- url = `https://www.youtube.com/embed/${videoId}`;
45
+ const videoId = query.v ?? url?.match(/\/([a-zA-Z0-9-_]*)$/)?.[1];
46
+ url = `https://www.youtube.com/embed/${videoId as string}`;
47
47
 
48
48
  delete query.v;
49
49
  query.autoplay = autoplay ? '1' : '0';
@@ -55,7 +55,11 @@ const YouTubeVideo: React.FunctionComponent<PropsT> = ({
55
55
  return (
56
56
  <div className={theme.container}>
57
57
  <Throbber theme={throbberTheme} />
58
- <iframe
58
+ {/* TODO: I guess, we better add the sanbox, but right now I don't have
59
+ time to carefully explore which restrictions should be lifted to allow
60
+ embed YouTube player to work... sometime later we'll take care of it */
61
+ }
62
+ <iframe // eslint-disable-line react/iframe-missing-sandbox
59
63
  allow="autoplay"
60
64
  allowFullScreen
61
65
  className={theme.video}
@@ -71,13 +71,13 @@ const Options: FunctionComponent<PropsT> = ({
71
71
  }), []);
72
72
 
73
73
  const optionNodes: ReactNode[] = [];
74
- for (let i = 0; i < options.length; ++i) {
75
- const option = options[i];
76
- if (option !== undefined && (!filter || filter(option))) {
74
+ for (const option of options) {
75
+ if (!filter || filter(option)) {
77
76
  const [iValue, iName] = optionValueName(option);
78
77
  optionNodes.push(
79
78
  <div
80
79
  className={optionClass}
80
+ key={iValue}
81
81
  onClick={(e) => {
82
82
  onChange(iValue);
83
83
  e.stopPropagation();
@@ -88,7 +88,6 @@ const Options: FunctionComponent<PropsT> = ({
88
88
  e.stopPropagation();
89
89
  }
90
90
  }}
91
- key={iValue}
92
91
  role="button"
93
92
  tabIndex={0}
94
93
  >
@@ -106,14 +105,14 @@ const Options: FunctionComponent<PropsT> = ({
106
105
  // dropdowns during the scrolling (that would need to re-position it in
107
106
  // response to the position changes of the root dropdown element).
108
107
  cancelOnScrolling
109
- style={containerStyle}
110
108
  dontDisableScrolling
111
109
  onCancel={onCancel}
110
+ style={containerStyle}
112
111
  theme={{
113
112
  ad: '',
114
- hoc: '',
115
113
  container: containerClass,
116
114
  context: '',
115
+ hoc: '',
117
116
  overlay: S.overlay,
118
117
  }}
119
118
  >
@@ -9,7 +9,7 @@ import defaultTheme from './theme.scss';
9
9
  import { type PropsT, type ValueT, optionValueName } from '../common';
10
10
 
11
11
  const BaseCustomDropdown: React.FunctionComponent<
12
- PropsT<React.ReactNode, (value: ValueT) => void>
12
+ PropsT<React.ReactNode, (value: ValueT) => void>
13
13
  > = ({
14
14
  filter,
15
15
  label,
@@ -18,8 +18,6 @@ PropsT<React.ReactNode, (value: ValueT) => void>
18
18
  theme,
19
19
  value,
20
20
  }) => {
21
- if (!options) throw Error('Internal error');
22
-
23
21
  const [active, setActive] = useState(false);
24
22
 
25
23
  const dropdownRef = useRef<HTMLDivElement>(null);
@@ -44,8 +42,8 @@ PropsT<React.ReactNode, (value: ValueT) => void>
44
42
  setUpward(up);
45
43
 
46
44
  const pos = up ? {
47
- top: anchor.top - opsRect.height - 1,
48
45
  left: anchor.left,
46
+ top: anchor.top - opsRect.height - 1,
49
47
  width: anchor.width,
50
48
  } : {
51
49
  left: anchor.left,
@@ -78,8 +76,8 @@ PropsT<React.ReactNode, (value: ValueT) => void>
78
76
  // move it above, at least with the current position update via local
79
77
  // react state, and not imperatively).
80
78
  setOpsPos({
81
- left: view?.width || 0,
82
- top: view?.height || 0,
79
+ left: view?.width ?? 0,
80
+ top: view?.height ?? 0,
83
81
  width: rect.width,
84
82
  });
85
83
 
@@ -87,9 +85,8 @@ PropsT<React.ReactNode, (value: ValueT) => void>
87
85
  };
88
86
 
89
87
  let selected: React.ReactNode = <>&zwnj;</>;
90
- for (let i = 0; i < options.length; ++i) {
91
- const option = options[i];
92
- if (option !== undefined && (!filter || filter(option))) {
88
+ for (const option of options) {
89
+ if (!filter || filter(option)) {
93
90
  const [iValue, iName] = optionValueName(option);
94
91
  if (iValue === value) {
95
92
  selected = iName;
@@ -101,7 +98,7 @@ PropsT<React.ReactNode, (value: ValueT) => void>
101
98
  let containerClassName = theme.container;
102
99
  if (active) containerClassName += ` ${theme.active}`;
103
100
 
104
- let opsContainerClass = theme.select || '';
101
+ let opsContainerClass = theme.select ?? '';
105
102
  if (upward) {
106
103
  containerClassName += ` ${theme.upward}`;
107
104
  opsContainerClass += ` ${theme.upward}`;
@@ -109,9 +106,8 @@ PropsT<React.ReactNode, (value: ValueT) => void>
109
106
 
110
107
  return (
111
108
  <div className={containerClassName}>
112
- {label === undefined ? null : (
113
- <div className={theme.label}>{label}</div>
114
- )}
109
+ {label === undefined ? null
110
+ : <div className={theme.label}>{label}</div>}
115
111
  <div
116
112
  className={theme.dropdown}
117
113
  onClick={openList}
@@ -137,7 +133,7 @@ PropsT<React.ReactNode, (value: ValueT) => void>
137
133
  setActive(false);
138
134
  if (onChange) onChange(newValue);
139
135
  }}
140
- optionClass={theme.option || ''}
136
+ optionClass={theme.option ?? ''}
141
137
  options={options}
142
138
  ref={opsRef}
143
139
  />
@@ -34,14 +34,11 @@ const Dropdown: React.FunctionComponent<PropsT<string>> = ({
34
34
  theme,
35
35
  value,
36
36
  }) => {
37
- if (!options) throw Error('Internal error');
38
-
39
37
  let isValidValue = false;
40
38
  const optionElements = [];
41
39
 
42
- for (let i = 0; i < options.length; ++i) {
43
- const option = options[i];
44
- if (option !== undefined && (!filter || filter(option))) {
40
+ for (const option of options) {
41
+ if (!filter || filter(option)) {
45
42
  const [iValue, iName] = optionValueName(option);
46
43
  isValidValue ||= iValue === value;
47
44
  optionElements.push(
@@ -58,8 +55,8 @@ const Dropdown: React.FunctionComponent<PropsT<string>> = ({
58
55
  // to show it as disabled.
59
56
  const hiddenOption = isValidValue ? null : (
60
57
  <option
61
- disabled
62
58
  className={theme.hiddenOption}
59
+ disabled
63
60
  key="__reactUtilsHiddenOption"
64
61
  value={value}
65
62
  >
@@ -72,7 +69,8 @@ const Dropdown: React.FunctionComponent<PropsT<string>> = ({
72
69
 
73
70
  return (
74
71
  <div className={theme.container}>
75
- { label === undefined ? null : <div className={theme.label}>{label}</div> }
72
+ { label === undefined
73
+ ? null : <div className={theme.label}>{label}</div> }
76
74
  <div className={theme.dropdown}>
77
75
  <select
78
76
  className={selectClassName}
@@ -33,40 +33,42 @@ const BaseSwitch: React.FunctionComponent<PropsT> = ({
33
33
  if (!options || !theme.option) throw Error('Internal error');
34
34
 
35
35
  const optionNodes: React.ReactNode[] = [];
36
- for (let i = 0; i < options?.length; ++i) {
37
- const option = options[i];
38
- if (option !== undefined) {
39
- const [iValue, iName] = optionValueName(option);
36
+ for (const option of options) {
37
+ const [iValue, iName] = optionValueName(option);
40
38
 
41
- let className: string = theme.option;
42
- let onPress: (() => void) | undefined;
43
- if (iValue === value) className += ` ${theme.selected}`;
44
- else if (onChange) onPress = () => onChange(iValue);
39
+ let className: string = theme.option;
40
+ let onPress: (() => void) | undefined;
41
+ if (iValue === value) className += ` ${theme.selected}`;
42
+ else if (onChange) {
43
+ onPress = () => {
44
+ onChange(iValue);
45
+ };
46
+ }
45
47
 
46
- optionNodes.push(
47
- onPress ? (
48
+ optionNodes.push(
49
+ onPress
50
+ ? (
48
51
  <div
49
52
  className={className}
53
+ key={iValue}
50
54
  onClick={onPress}
51
55
  onKeyDown={(e) => {
52
- if (onPress && e.key === 'Enter') onPress();
56
+ if (e.key === 'Enter') onPress();
53
57
  }}
54
- key={iValue}
55
58
  role="button"
56
59
  tabIndex={0}
57
60
  >
58
61
  {iName}
59
62
  </div>
60
- ) : (
61
- <div className={className} key={iValue}>{iName}</div>
62
- ),
63
- );
64
- }
63
+ )
64
+ : <div className={className} key={iValue}>{iName}</div>,
65
+ );
65
66
  }
66
67
 
67
68
  return (
68
69
  <div className={theme.container}>
69
70
  {label ? <div className={theme.label}>{label}</div> : null}
71
+
70
72
  <div className={theme.options}>
71
73
  {optionNodes}
72
74
  </div>
@@ -1,20 +1,27 @@
1
1
  /* global document */
2
2
 
3
+ import type CookieM from 'cookie';
4
+
3
5
  import { IS_CLIENT_SIDE } from './isomorphy/environment-check';
4
6
  import { requireWeak } from './webpack';
5
7
 
6
- const config = (
8
+ // TODO: The internal type casting is somewhat messed up here,
9
+ // to be corrected later.
10
+ const config: Record<string, unknown> = (
7
11
  IS_CLIENT_SIDE
8
- // eslint-disable-next-line global-require
9
- ? require('client/getInj').default().CONFIG
12
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
13
+ ? (require('client/getInj') as {
14
+ default: () => Record<string, unknown>;
15
+ }).default().CONFIG
10
16
  : requireWeak('config')
11
- ) || {};
17
+ ) as (Record<string, unknown> | undefined) ?? ({} as Record<string, unknown>);
12
18
 
13
19
  // The safeguard for "document" is necessary because in non-Node environments,
14
20
  // like React Native, IS_CLIENT_SIDE is "true", however "document" and a bunch
15
21
  // of other browser-world features are not available.
16
22
  if (IS_CLIENT_SIDE && typeof document !== 'undefined') {
17
- const cookie = require('cookie'); // eslint-disable-line global-require
23
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
24
+ const cookie = require('cookie') as typeof CookieM;
18
25
  config.CSRF = cookie.parse(document.cookie).csrfToken;
19
26
  }
20
27
 
@@ -2,27 +2,30 @@ import type { Request } from 'express';
2
2
 
3
3
  import { type SsrContext, withGlobalStateType } from '@dr.pogodin/react-global-state';
4
4
 
5
- export type ChunkGroupsT = {
6
- [chunkName: string]: string[];
7
- };
5
+ /** Mapping "chunkName" > array of asset paths. */
6
+ export type ChunkGroupsT = Record<string, string[]>;
8
7
 
9
8
  // The type of data object injected by server into generated markup.
10
9
  export type InjT = {
11
10
  CHUNK_GROUPS?: ChunkGroupsT;
12
- CONFIG?: { [key: string]: any },
11
+ CONFIG?: Record<string, unknown>;
13
12
  ISTATE?: unknown;
14
13
  };
15
14
 
16
15
  declare global {
16
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
17
17
  interface Window {
18
18
  REACT_UTILS_INJECTION?: InjT;
19
19
  }
20
20
  }
21
21
 
22
+ // TODO: Not 100% sure now, whether it indeed can be replaced by type,
23
+ // or do we really need it to be an interface. Keeping the interface for now.
24
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
22
25
  export interface SsrContextT<StateT> extends SsrContext<StateT> {
23
26
  chunkGroups: ChunkGroupsT;
24
27
  chunks: string[];
25
- req: Request,
28
+ req: Request;
26
29
  status: number;
27
30
  }
28
31
 
@@ -31,7 +31,7 @@ if (typeof BUILD_INFO !== 'undefined') buildInfo = BUILD_INFO;
31
31
  * @param info
32
32
  * @param force
33
33
  */
34
- export function setBuildInfo(info?: BuildInfoT, force = false) {
34
+ export function setBuildInfo(info?: BuildInfoT, force = false): void {
35
35
  if (buildInfo !== undefined && !force) {
36
36
  throw Error('"Build Info" is already initialized');
37
37
  }
@@ -4,7 +4,11 @@
4
4
  * `true` within client-side environment (browser), `false` at server-side.
5
5
  */
6
6
  export const IS_CLIENT_SIDE: boolean = typeof process !== 'object'
7
- || !process.versions || !process.versions.node
7
+ // NOTE: Because in this case we assume the host environment might be partially
8
+ // polyfilled to emulate some Node interfaces, thus it might have global `process`
9
+ // object, but without `versions` sub-object inside it.
10
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
11
+ || !process.versions?.node
8
12
  || !!global.REACT_UTILS_FORCE_CLIENT_SIDE;
9
13
 
10
14
  /**
@@ -12,26 +12,24 @@ function getMode() {
12
12
  /**
13
13
  * Returns `true` if development version of the code is running;
14
14
  * `false` otherwise.
15
- * @return {boolean}
16
15
  */
17
- export function isDevBuild() {
16
+ export function isDevBuild(): boolean {
18
17
  return getMode() === 'development';
19
18
  }
20
19
 
21
20
  /**
22
21
  * Returns `true` if production build of the code is running;
23
22
  * `false` otherwise.
24
- * @return {boolean}
25
23
  */
26
- export function isProdBuild() {
24
+ export function isProdBuild(): boolean {
27
25
  return getMode() === 'production';
28
26
  }
29
27
 
30
28
  /**
31
29
  * Returns build timestamp of the front-end JS bundle.
32
- * @return {string} ISO date/time string.
30
+ * @return ISO date/time string.
33
31
  */
34
- export function buildTimestamp() {
32
+ export function buildTimestamp(): string {
35
33
  return getBuildInfo().timestamp;
36
34
  }
37
35