@dr.pogodin/react-utils 1.25.6 → 1.26.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 (290) hide show
  1. package/babel.config.js +3 -1
  2. package/bin/build.js +18 -4
  3. package/build/development/client/getInj.js +9 -8
  4. package/build/development/client/getInj.js.map +1 -1
  5. package/build/development/client/index.js +6 -3
  6. package/build/development/client/index.js.map +1 -1
  7. package/build/development/client/init.js +4 -0
  8. package/build/development/client/init.js.map +1 -1
  9. package/build/development/index.js +166 -38
  10. package/build/development/index.js.map +1 -1
  11. package/build/development/server/Cache.js +13 -13
  12. package/build/development/server/Cache.js.map +1 -1
  13. package/build/development/server/index.js +16 -23
  14. package/build/development/server/index.js.map +1 -1
  15. package/build/development/server/renderer.js +56 -43
  16. package/build/development/server/renderer.js.map +1 -1
  17. package/build/development/server/server.js +9 -5
  18. package/build/development/server/server.js.map +1 -1
  19. package/build/development/server/utils/errors.js +12 -9
  20. package/build/development/server/utils/errors.js.map +1 -1
  21. package/build/development/server/utils/index.js +2 -2
  22. package/build/development/server/utils/index.js.map +1 -1
  23. package/build/development/shared/components/Button/index.js +7 -5
  24. package/build/development/shared/components/Button/index.js.map +1 -1
  25. package/build/development/shared/components/Checkbox/index.js +24 -26
  26. package/build/development/shared/components/Checkbox/index.js.map +1 -1
  27. package/build/development/shared/components/Dropdown/index.js +24 -17
  28. package/build/development/shared/components/Dropdown/index.js.map +1 -1
  29. package/build/development/shared/components/GenericLink/index.js +44 -37
  30. package/build/development/shared/components/GenericLink/index.js.map +1 -1
  31. package/build/development/shared/components/Input/index.js +7 -7
  32. package/build/development/shared/components/Input/index.js.map +1 -1
  33. package/build/development/shared/components/Link.js +10 -9
  34. package/build/development/shared/components/Link.js.map +1 -1
  35. package/build/development/shared/components/MetaTags.js +22 -18
  36. package/build/development/shared/components/MetaTags.js.map +1 -1
  37. package/build/development/shared/components/Modal/index.js +16 -16
  38. package/build/development/shared/components/Modal/index.js.map +1 -1
  39. package/build/development/shared/components/NavLink.js +10 -9
  40. package/build/development/shared/components/NavLink.js.map +1 -1
  41. package/build/development/shared/components/PageLayout/index.js +16 -18
  42. package/build/development/shared/components/PageLayout/index.js.map +1 -1
  43. package/build/development/shared/components/ScalableRect/index.js +27 -7
  44. package/build/development/shared/components/ScalableRect/index.js.map +1 -1
  45. package/build/development/shared/components/Throbber/index.js +14 -22
  46. package/build/development/shared/components/Throbber/index.js.map +1 -1
  47. package/build/development/shared/components/WithTooltip/Tooltip.js +19 -21
  48. package/build/development/shared/components/WithTooltip/Tooltip.js.map +1 -1
  49. package/build/development/shared/components/WithTooltip/index.js +11 -10
  50. package/build/development/shared/components/WithTooltip/index.js.map +1 -1
  51. package/build/development/shared/components/YouTubeVideo/index.js +15 -13
  52. package/build/development/shared/components/YouTubeVideo/index.js.map +1 -1
  53. package/build/development/shared/components/index.js +2 -2
  54. package/build/development/shared/components/index.js.map +1 -1
  55. package/build/development/shared/utils/config.js.map +1 -1
  56. package/build/development/shared/utils/globalState.js +15 -0
  57. package/build/development/shared/utils/globalState.js.map +1 -0
  58. package/build/development/shared/utils/index.js +13 -10
  59. package/build/development/shared/utils/index.js.map +1 -1
  60. package/build/development/shared/utils/isomorphy/buildInfo.js +7 -3
  61. package/build/development/shared/utils/isomorphy/buildInfo.js.map +1 -1
  62. package/build/development/shared/utils/isomorphy/environment-check.js.map +1 -1
  63. package/build/development/shared/utils/isomorphy/index.js.map +1 -1
  64. package/build/development/shared/utils/jest/E2eSsrEnv.js +35 -28
  65. package/build/development/shared/utils/jest/E2eSsrEnv.js.map +1 -1
  66. package/build/development/shared/utils/jest/global.js +17 -0
  67. package/build/development/shared/utils/jest/global.js.map +1 -0
  68. package/build/development/shared/utils/jest/index.js +17 -9
  69. package/build/development/shared/utils/jest/index.js.map +1 -1
  70. package/build/development/shared/utils/splitComponent.js +25 -34
  71. package/build/development/shared/utils/splitComponent.js.map +1 -1
  72. package/build/development/shared/utils/time.js +16 -12
  73. package/build/development/shared/utils/time.js.map +1 -1
  74. package/build/development/shared/utils/webpack.js +3 -3
  75. package/build/development/shared/utils/webpack.js.map +1 -1
  76. package/build/development/web.bundle.js +92 -82
  77. package/build/production/client/getInj.js +1 -1
  78. package/build/production/client/getInj.js.map +1 -1
  79. package/build/production/client/index.js +4 -4
  80. package/build/production/client/index.js.map +1 -1
  81. package/build/production/client/init.js +3 -1
  82. package/build/production/client/init.js.map +1 -1
  83. package/build/production/index.js +1 -1
  84. package/build/production/index.js.map +1 -1
  85. package/build/production/server/Cache.js +7 -8
  86. package/build/production/server/Cache.js.map +1 -1
  87. package/build/production/server/index.js +5 -4
  88. package/build/production/server/index.js.map +1 -1
  89. package/build/production/server/renderer.js +32 -30
  90. package/build/production/server/renderer.js.map +1 -1
  91. package/build/production/server/server.js +7 -5
  92. package/build/production/server/server.js.map +1 -1
  93. package/build/production/server/utils/errors.js +9 -10
  94. package/build/production/server/utils/errors.js.map +1 -1
  95. package/build/production/server/utils/index.js +1 -1
  96. package/build/production/server/utils/index.js.map +1 -1
  97. package/build/production/shared/components/Button/index.js +3 -3
  98. package/build/production/shared/components/Button/index.js.map +1 -1
  99. package/build/production/shared/components/Checkbox/index.js +11 -11
  100. package/build/production/shared/components/Checkbox/index.js.map +1 -1
  101. package/build/production/shared/components/Dropdown/index.js +11 -11
  102. package/build/production/shared/components/Dropdown/index.js.map +1 -1
  103. package/build/production/shared/components/GenericLink/index.js +25 -20
  104. package/build/production/shared/components/GenericLink/index.js.map +1 -1
  105. package/build/production/shared/components/Input/index.js +7 -7
  106. package/build/production/shared/components/Input/index.js.map +1 -1
  107. package/build/production/shared/components/Link.js +2 -2
  108. package/build/production/shared/components/Link.js.map +1 -1
  109. package/build/production/shared/components/MetaTags.js +10 -10
  110. package/build/production/shared/components/MetaTags.js.map +1 -1
  111. package/build/production/shared/components/Modal/index.js +2 -2
  112. package/build/production/shared/components/Modal/index.js.map +1 -1
  113. package/build/production/shared/components/NavLink.js +1 -1
  114. package/build/production/shared/components/NavLink.js.map +1 -1
  115. package/build/production/shared/components/PageLayout/index.js +2 -2
  116. package/build/production/shared/components/PageLayout/index.js.map +1 -1
  117. package/build/production/shared/components/ScalableRect/index.js +7 -3
  118. package/build/production/shared/components/ScalableRect/index.js.map +1 -1
  119. package/build/production/shared/components/Throbber/index.js +2 -2
  120. package/build/production/shared/components/Throbber/index.js.map +1 -1
  121. package/build/production/shared/components/WithTooltip/Tooltip.js +13 -13
  122. package/build/production/shared/components/WithTooltip/Tooltip.js.map +1 -1
  123. package/build/production/shared/components/WithTooltip/index.js +3 -3
  124. package/build/production/shared/components/WithTooltip/index.js.map +1 -1
  125. package/build/production/shared/components/YouTubeVideo/index.js +7 -7
  126. package/build/production/shared/components/YouTubeVideo/index.js.map +1 -1
  127. package/build/production/shared/components/index.js +1 -1
  128. package/build/production/shared/components/index.js.map +1 -1
  129. package/build/production/shared/utils/config.js.map +1 -1
  130. package/build/production/shared/utils/globalState.js +3 -0
  131. package/build/production/shared/utils/globalState.js.map +1 -0
  132. package/build/production/shared/utils/index.js +2 -2
  133. package/build/production/shared/utils/index.js.map +1 -1
  134. package/build/production/shared/utils/isomorphy/buildInfo.js +7 -4
  135. package/build/production/shared/utils/isomorphy/buildInfo.js.map +1 -1
  136. package/build/production/shared/utils/isomorphy/environment-check.js.map +1 -1
  137. package/build/production/shared/utils/isomorphy/index.js.map +1 -1
  138. package/build/production/shared/utils/jest/E2eSsrEnv.js +9 -9
  139. package/build/production/shared/utils/jest/E2eSsrEnv.js.map +1 -1
  140. package/build/production/shared/utils/jest/global.js +2 -0
  141. package/build/production/shared/utils/jest/global.js.map +1 -0
  142. package/build/production/shared/utils/jest/index.js +5 -5
  143. package/build/production/shared/utils/jest/index.js.map +1 -1
  144. package/build/production/shared/utils/splitComponent.js +16 -16
  145. package/build/production/shared/utils/splitComponent.js.map +1 -1
  146. package/build/production/shared/utils/time.js +12 -8
  147. package/build/production/shared/utils/time.js.map +1 -1
  148. package/build/production/shared/utils/webpack.js +3 -3
  149. package/build/production/shared/utils/webpack.js.map +1 -1
  150. package/build/production/web.bundle.js +1 -1
  151. package/build/production/web.bundle.js.map +1 -1
  152. package/build/types-code/client/getInj.d.ts +3 -0
  153. package/build/types-code/client/index.d.ts +11 -0
  154. package/build/types-code/client/init.d.ts +9 -0
  155. package/build/types-code/index.d.ts +10 -0
  156. package/build/types-code/server/Cache.d.ts +37 -0
  157. package/build/types-code/server/index.d.ts +145 -0
  158. package/build/types-code/server/renderer.d.ts +106 -0
  159. package/build/types-code/server/server.d.ts +41 -0
  160. package/build/types-code/server/utils/errors.d.ts +104 -0
  161. package/build/types-code/server/utils/index.d.ts +1 -0
  162. package/build/types-code/shared/components/Button/index.d.ts +27 -0
  163. package/build/types-code/shared/components/Checkbox/index.d.ts +21 -0
  164. package/build/types-code/shared/components/Dropdown/index.d.ts +23 -0
  165. package/build/types-code/shared/components/GenericLink/index.d.ts +61 -0
  166. package/build/types-code/shared/components/Input/index.d.ts +11 -0
  167. package/build/types-code/shared/components/Link.d.ts +12 -0
  168. package/build/types-code/shared/components/MetaTags.d.ts +68 -0
  169. package/build/types-code/shared/components/Modal/index.d.ts +26 -0
  170. package/build/types-code/shared/components/NavLink.d.ts +5 -0
  171. package/build/types-code/shared/components/PageLayout/index.d.ts +16 -0
  172. package/build/types-code/shared/components/ScalableRect/index.d.ts +19 -0
  173. package/build/types-code/shared/components/Throbber/index.d.ts +9 -0
  174. package/build/types-code/shared/components/WithTooltip/Tooltip.d.ts +23 -0
  175. package/build/types-code/shared/components/WithTooltip/index.d.ts +17 -0
  176. package/build/types-code/shared/components/YouTubeVideo/index.d.ts +13 -0
  177. package/build/types-code/shared/components/index.d.ts +16 -0
  178. package/build/types-code/shared/utils/config.d.ts +2 -0
  179. package/build/types-code/shared/utils/globalState.d.ts +20 -0
  180. package/build/types-code/shared/utils/index.d.ts +52 -0
  181. package/build/types-code/shared/utils/isomorphy/buildInfo.d.ts +23 -0
  182. package/build/types-code/shared/utils/isomorphy/environment-check.d.ts +11 -0
  183. package/build/types-code/shared/utils/isomorphy/index.d.ts +20 -0
  184. package/build/types-code/shared/utils/jest/E2eSsrEnv.d.ts +31 -0
  185. package/build/types-code/shared/utils/jest/global.d.ts +12 -0
  186. package/build/types-code/shared/utils/jest/index.d.ts +85 -0
  187. package/build/types-code/shared/utils/splitComponent.d.ts +41 -0
  188. package/build/types-code/shared/utils/time.d.ts +62 -0
  189. package/build/types-code/shared/utils/webpack.d.ts +18 -0
  190. package/build/types-scss/__tests__/js/config/publicPath support/__assets__/style.scss.d.ts +1 -0
  191. package/build/types-scss/__tests__/js/config/stylename-generation/__assets__/MockPackageA/TestComponent/style.scss.d.ts +1 -0
  192. package/build/types-scss/__tests__/js/config/stylename-generation/__assets__/MockPackageB/TestComponent/style.scss.d.ts +1 -0
  193. package/build/types-scss/__tests__/js/config/stylename-generation/__assets__/style.scss.d.ts +1 -0
  194. package/build/types-scss/__tests__/js/shared/components/NavLink/styles.scss.d.ts +1 -0
  195. package/build/types-scss/__tests__/js/shared/utils/splitComponent/__assets__/SampleScene/ComponentA/style.scss.d.ts +1 -0
  196. package/build/types-scss/__tests__/js/shared/utils/splitComponent/__assets__/SampleScene/ComponentB/style.scss.d.ts +1 -0
  197. package/build/types-scss/__tests__/js/shared/utils/splitComponent/__assets__/SampleScene/ComponentC/style.scss.d.ts +1 -0
  198. package/build/types-scss/__tests__/js/shared/utils/splitComponent/__assets__/SampleScene/style.scss.d.ts +1 -0
  199. package/build/types-scss/__tests__/ts/config/publicPath support/__assets__/style.scss.d.ts +1 -0
  200. package/build/types-scss/__tests__/ts/config/stylename-generation/__assets__/MockPackageA/TestComponent/style.scss.d.ts +1 -0
  201. package/build/types-scss/__tests__/ts/config/stylename-generation/__assets__/MockPackageB/TestComponent/style.scss.d.ts +1 -0
  202. package/build/types-scss/__tests__/ts/config/stylename-generation/__assets__/style.scss.d.ts +1 -0
  203. package/build/types-scss/__tests__/ts/shared/components/NavLink/styles.scss.d.ts +1 -0
  204. package/build/types-scss/__tests__/ts/shared/utils/splitComponent/__assets__/SampleScene/ComponentA/style.scss.d.ts +1 -0
  205. package/build/types-scss/__tests__/ts/shared/utils/splitComponent/__assets__/SampleScene/ComponentB/style.scss.d.ts +1 -0
  206. package/build/types-scss/__tests__/ts/shared/utils/splitComponent/__assets__/SampleScene/ComponentC/style.scss.d.ts +1 -0
  207. package/build/types-scss/__tests__/ts/shared/utils/splitComponent/__assets__/SampleScene/style.scss.d.ts +1 -0
  208. package/build/types-scss/src/shared/components/Button/style.scss.d.ts +6 -0
  209. package/build/types-scss/src/shared/components/Checkbox/theme.scss.d.ts +6 -0
  210. package/build/types-scss/src/shared/components/Dropdown/theme.scss.d.ts +9 -0
  211. package/build/types-scss/src/shared/components/GenericLink/style.scss.d.ts +1 -0
  212. package/build/types-scss/src/shared/components/Input/theme.scss.d.ts +6 -0
  213. package/build/types-scss/src/shared/components/Modal/base-theme.scss.d.ts +5 -0
  214. package/build/types-scss/src/shared/components/PageLayout/base-theme.scss.d.ts +6 -0
  215. package/build/types-scss/src/shared/components/ScalableRect/style.scss.d.ts +2 -0
  216. package/build/types-scss/src/shared/components/Throbber/theme.scss.d.ts +6 -0
  217. package/build/types-scss/src/shared/components/WithTooltip/default-theme.scss.d.ts +7 -0
  218. package/build/types-scss/src/shared/components/YouTubeVideo/base.scss.d.ts +5 -0
  219. package/build/types-scss/src/shared/components/YouTubeVideo/throbber.scss.d.ts +4 -0
  220. package/config/eslint/jest.json +3 -2
  221. package/config/eslint/typescript.js +34 -0
  222. package/config/jest/default.js +3 -3
  223. package/package.json +74 -32
  224. package/src/client/getInj.ts +43 -0
  225. package/src/client/index.tsx +40 -0
  226. package/src/client/init.ts +47 -0
  227. package/src/index.ts +58 -0
  228. package/src/server/Cache.ts +68 -0
  229. package/src/server/index.ts +230 -0
  230. package/src/server/renderer.tsx +604 -0
  231. package/src/server/server.ts +309 -0
  232. package/src/server/utils/errors.ts +135 -0
  233. package/src/server/utils/index.ts +3 -0
  234. package/src/shared/components/Button/index.tsx +146 -0
  235. package/src/shared/components/Button/style.scss +53 -0
  236. package/src/shared/components/Checkbox/index.tsx +71 -0
  237. package/src/shared/components/Checkbox/theme.scss +43 -0
  238. package/src/shared/components/Dropdown/index.tsx +144 -0
  239. package/src/shared/components/Dropdown/theme.scss +63 -0
  240. package/src/shared/components/GenericLink/index.tsx +157 -0
  241. package/src/shared/components/GenericLink/style.scss +3 -0
  242. package/src/shared/components/Input/index.tsx +59 -0
  243. package/src/shared/components/Input/theme.scss +27 -0
  244. package/src/shared/components/Link.tsx +21 -0
  245. package/src/shared/components/MetaTags.tsx +170 -0
  246. package/src/shared/components/Modal/base-theme.scss +38 -0
  247. package/src/shared/components/Modal/index.tsx +144 -0
  248. package/src/shared/components/Modal/styles.scss +5 -0
  249. package/src/shared/components/NavLink.tsx +13 -0
  250. package/src/shared/components/PageLayout/base-theme.scss +30 -0
  251. package/src/shared/components/PageLayout/index.tsx +76 -0
  252. package/src/shared/components/ScalableRect/index.tsx +84 -0
  253. package/src/shared/components/ScalableRect/style.scss +10 -0
  254. package/src/shared/components/Throbber/index.tsx +43 -0
  255. package/src/shared/components/Throbber/theme.scss +26 -0
  256. package/src/shared/components/WithTooltip/Tooltip.tsx +353 -0
  257. package/src/shared/components/WithTooltip/default-theme.scss +36 -0
  258. package/src/shared/components/WithTooltip/index.tsx +204 -0
  259. package/src/shared/components/YouTubeVideo/base.scss +13 -0
  260. package/src/shared/components/YouTubeVideo/index.tsx +96 -0
  261. package/src/shared/components/YouTubeVideo/throbber.scss +11 -0
  262. package/src/shared/components/index.ts +17 -0
  263. package/src/shared/utils/config.ts +21 -0
  264. package/src/shared/utils/globalState.ts +29 -0
  265. package/src/shared/utils/index.ts +105 -0
  266. package/src/shared/utils/isomorphy/buildInfo.ts +54 -0
  267. package/src/shared/utils/isomorphy/environment-check.ts +18 -0
  268. package/src/shared/utils/isomorphy/index.ts +38 -0
  269. package/src/shared/utils/jest/E2eSsrEnv.ts +250 -0
  270. package/src/shared/utils/jest/global.ts +19 -0
  271. package/src/shared/utils/jest/index.tsx +157 -0
  272. package/src/shared/utils/splitComponent.tsx +255 -0
  273. package/src/shared/utils/time.ts +118 -0
  274. package/src/shared/utils/webpack.ts +45 -0
  275. package/src/styles/_global/reset.css +52 -0
  276. package/src/styles/global.scss +11 -0
  277. package/tsconfig.configs.json +18 -0
  278. package/tsconfig.json +27 -0
  279. package/tsconfig.types.json +53 -0
  280. package/typed-scss-modules.config.ts +9 -0
  281. package/types.d.ts +37 -0
  282. package/{webpack.config.js → webpack.config.ts} +7 -3
  283. package/config/babel/node-ssr.js +0 -85
  284. package/config/babel/webpack.js +0 -123
  285. package/config/webpack/app-base.js +0 -330
  286. package/config/webpack/app-development.js +0 -80
  287. package/config/webpack/app-production.js +0 -60
  288. package/config/webpack/lib-base.js +0 -155
  289. package/config/webpack/lib-development.js +0 -45
  290. package/config/webpack/lib-production.js +0 -44
@@ -0,0 +1,71 @@
1
+ import PT from 'prop-types';
2
+
3
+ import themed, { type Theme } from '@dr.pogodin/react-themes';
4
+
5
+ import defaultTheme from './theme.scss';
6
+
7
+ type PropT = {
8
+ checked?: boolean;
9
+ label?: string;
10
+ onChange?: React.ChangeEventHandler<HTMLInputElement>;
11
+ theme: Theme & {
12
+ checkbox?: string;
13
+ container?: string
14
+ label?: string;
15
+ };
16
+ };
17
+
18
+ const Checkbox: React.FunctionComponent<PropT> = ({
19
+ checked,
20
+ label,
21
+ onChange,
22
+ theme,
23
+ }) => (
24
+ <div className={theme.container}>
25
+ { label === undefined ? null : <p className={theme.label}>{label}</p> }
26
+ <input
27
+ checked={checked}
28
+ className={theme.checkbox}
29
+ onChange={onChange}
30
+ type="checkbox"
31
+ />
32
+ </div>
33
+ );
34
+
35
+ /**
36
+ * Checkbox component theme: a map of
37
+ * CSS classes to append to its elements:
38
+ * @prop [checkbox] to the underlying checkbox `<input>` element.
39
+ * @prop [container] to the root checkbox element.
40
+ * @prop [label] to the checkbox label element.
41
+ */
42
+ const ThemedCheckbox = themed(Checkbox, 'Checkbox', [
43
+ 'checkbox',
44
+ 'container',
45
+ 'label',
46
+ ], defaultTheme);
47
+
48
+ /**
49
+ * The `<Checkbox>` component implements themeable checkboxes.
50
+ * @param [props] Component properties.
51
+ * @param [props.checked] Checkbox value.
52
+ * @param [props.label] Checkbox label.
53
+ * @param [props.onChange] State change handler.
54
+ * @param [props.theme] _Ad hoc_ theme.
55
+ * @param [props....]
56
+ * [Other properties of themeable components](https://www.npmjs.com/package/@dr.pogodin/react-themes#themed-component-properties).
57
+ */
58
+ Checkbox.propTypes = {
59
+ checked: PT.bool,
60
+ label: PT.string,
61
+ onChange: PT.func,
62
+ theme: ThemedCheckbox.themeType.isRequired,
63
+ };
64
+
65
+ Checkbox.defaultProps = {
66
+ checked: undefined,
67
+ label: undefined,
68
+ onChange: undefined,
69
+ };
70
+
71
+ export default ThemedCheckbox;
@@ -0,0 +1,43 @@
1
+ *,
2
+ .context,
3
+ .ad.hoc {
4
+ &.checkbox {
5
+ appearance: none;
6
+ background: white;
7
+ border: 1px solid gray;
8
+ border-radius: 0.3em;
9
+ cursor: pointer;
10
+ font: inherit;
11
+ height: 1.5em;
12
+ outline: none;
13
+ margin: 0;
14
+ width: 1.5em;
15
+
16
+ &:checked {
17
+ &::after {
18
+ background: black;
19
+ border-radius: 0.3em;
20
+ content: "";
21
+ display: block;
22
+ height: 1em;
23
+ margin: 0.2em;
24
+ width: 1em;
25
+ }
26
+ }
27
+
28
+ &:focus {
29
+ border-color: blue;
30
+ box-shadow: 0 0 3px 1px lightblue;
31
+ }
32
+ }
33
+
34
+ &.container {
35
+ align-items: center;
36
+ display: inline-flex;
37
+ margin: 0.1em;
38
+ }
39
+
40
+ &.label {
41
+ margin: 0 0.6em 0 1.5em;
42
+ }
43
+ }
@@ -0,0 +1,144 @@
1
+ import PT from 'prop-types';
2
+
3
+ import themed, { type Theme } from '@dr.pogodin/react-themes';
4
+
5
+ import defaultTheme from './theme.scss';
6
+
7
+ type DropdownOptionT = {
8
+ name?: string | null;
9
+ value: string;
10
+ };
11
+
12
+ type PropsT = {
13
+ filter?: (item: DropdownOptionT | string) => boolean;
14
+ label?: string;
15
+ onChange?: React.ChangeEventHandler<HTMLSelectElement>;
16
+ options?: Array<DropdownOptionT | string>;
17
+ theme: Theme & {
18
+ arrow?: string;
19
+ container?: string;
20
+ hiddenOption?: string;
21
+ label?: string;
22
+ option?: string;
23
+ select?: string;
24
+ };
25
+ value?: string;
26
+ };
27
+
28
+ /**
29
+ * Implements a themeable dropdown list. Internally it is rendered with help of
30
+ * the standard HTML `<select>` element, thus the styling support is somewhat
31
+ * limited.
32
+ * @param [props] Component properties.
33
+ * @param [props.filter] Options filter function. If provided, only
34
+ * those elements of `options` list will be used by the dropdown, for which this
35
+ * filter returns `true`.
36
+ * @param [props.label] Dropdown label.
37
+ * @param [props.onChange] Selection event handler.
38
+ * @param [props.options=[]] Array of dropdown
39
+ * options. For string elements the option value and name will be the same.
40
+ * It is allowed to mix DropdownOption and string elements in the same option
41
+ * list.
42
+ * @param [props.theme] _Ad hoc_ theme.
43
+ * @param [props.value] Currently selected value.
44
+ * @param [props....]
45
+ * [Other theming properties](https://www.npmjs.com/package/@dr.pogodin/react-themes#themed-component-properties)
46
+ */
47
+ const Dropdown: React.FunctionComponent<PropsT> = ({
48
+ filter,
49
+ label,
50
+ onChange,
51
+ options = [],
52
+ theme,
53
+ value,
54
+ }) => {
55
+ let isValidValue = false;
56
+ const optionElements = [];
57
+
58
+ for (let i = 0; i < options.length; ++i) {
59
+ const option = options[i];
60
+ if (!filter || filter(option)) {
61
+ let optionValue: string;
62
+ let optionName: string;
63
+ if (typeof option === 'string') {
64
+ optionName = option;
65
+ optionValue = option;
66
+ } else {
67
+ optionName = option.name || option.value;
68
+ optionValue = option.value;
69
+ }
70
+ isValidValue ||= optionValue === value;
71
+ optionElements.push(
72
+ <option className={theme.option} key={optionValue} value={optionValue}>
73
+ {optionName}
74
+ </option>,
75
+ );
76
+ }
77
+ }
78
+
79
+ // NOTE: This element represents the current `value` when it does not match
80
+ // any valid option. In Chrome, and some other browsers, we are able to hide
81
+ // it from the opened dropdown; in others, e.g. Safari, the best we can do is
82
+ // to show it as disabled.
83
+ const hiddenOption = isValidValue ? null : (
84
+ <option
85
+ disabled
86
+ className={theme.hiddenOption}
87
+ key="__reactUtilsHiddenOption"
88
+ value={value}
89
+ >
90
+ {value}
91
+ </option>
92
+ );
93
+
94
+ return (
95
+ <div className={theme.container}>
96
+ { label === undefined ? null : <p className={theme.label}>{label}</p> }
97
+ <select
98
+ className={theme.select}
99
+ onChange={onChange}
100
+ value={value}
101
+ >
102
+ {hiddenOption}
103
+ {optionElements}
104
+ </select>
105
+ <div className={theme.arrow}>▼</div>
106
+ </div>
107
+ );
108
+ };
109
+
110
+ const ThemedDropdown = themed(Dropdown, 'Dropdown', [
111
+ 'arrow',
112
+ 'container',
113
+ 'hiddenOption',
114
+ 'label',
115
+ 'option',
116
+ 'select',
117
+ ], defaultTheme);
118
+
119
+ Dropdown.propTypes = {
120
+ filter: PT.func,
121
+ label: PT.string,
122
+ onChange: PT.func,
123
+ options: PT.arrayOf(
124
+ PT.oneOfType([
125
+ PT.shape({
126
+ name: PT.string,
127
+ value: PT.string.isRequired,
128
+ }),
129
+ PT.string,
130
+ ]).isRequired,
131
+ ),
132
+ theme: ThemedDropdown.themeType.isRequired,
133
+ value: PT.string,
134
+ };
135
+
136
+ Dropdown.defaultProps = {
137
+ filter: undefined,
138
+ label: undefined,
139
+ onChange: undefined,
140
+ options: [],
141
+ value: '',
142
+ };
143
+
144
+ export default ThemedDropdown;
@@ -0,0 +1,63 @@
1
+ @import "styles/mixins";
2
+
3
+ *,
4
+ .context,
5
+ .ad.hoc {
6
+ &.arrow {
7
+ background-image: linear-gradient(to top, lightgray, white 50%, white);
8
+ border: 1px solid gray;
9
+ border-radius: 0 0.3em 0.3em 0;
10
+ padding: 0.3em 0.6em;
11
+ pointer-events: none;
12
+ position: absolute;
13
+ right: 0;
14
+ }
15
+
16
+ &.container {
17
+ align-items: center;
18
+ display: inline-flex;
19
+ margin: 0.1em;
20
+ position: relative;
21
+ }
22
+
23
+ :active + &.arrow {
24
+ background-image: linear-gradient(to bottom, lightgray, white 50%, white);
25
+ border-bottom-right-radius: 0;
26
+ }
27
+
28
+ :focus + &.arrow {
29
+ border-color: blue;
30
+ border-left-color: gray;
31
+ }
32
+
33
+ &.label {
34
+ margin: 0 0.6em 0 1.5em;
35
+ }
36
+
37
+ &.option { /* Empty style */ }
38
+ &.hiddenOption { display: none; }
39
+
40
+ &.select {
41
+ appearance: none;
42
+ background: white;
43
+ border: 1px solid gray;
44
+ border-radius: 0.3em;
45
+ color: inherit;
46
+ cursor: pointer;
47
+ display: inline-block;
48
+ font: inherit;
49
+ outline: none;
50
+ padding: 0.3em 3.3em calc(0.3em + 1px) 1.2em;
51
+
52
+ &:active {
53
+ background: white;
54
+ border-bottom-left-radius: 0;
55
+ border-bottom-right-radius: 0;
56
+ }
57
+
58
+ &:focus {
59
+ border-color: blue;
60
+ box-shadow: 0 0 3px 1px lightblue;
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,157 @@
1
+ /* global window */
2
+
3
+ import PT from 'prop-types';
4
+ import { type ReactNode } from 'react';
5
+
6
+ import { type Link, type NavLink } from 'react-router-dom';
7
+
8
+ import './style.scss';
9
+
10
+ type ToT = Parameters<typeof Link>[0]['to'];
11
+
12
+ interface LinkI {}
13
+
14
+ export type PropsT = {
15
+ children?: ReactNode;
16
+ className?: string;
17
+ disabled?: boolean;
18
+ enforceA?: boolean;
19
+ keepScrollPosition?: boolean;
20
+ onClick?: React.MouseEventHandler<HTMLAnchorElement>;
21
+ onMouseDown?: React.MouseEventHandler<HTMLAnchorElement>;
22
+ openNewTab?: boolean;
23
+ replace?: boolean;
24
+ routerLinkType: LinkI;
25
+ to?: ToT;
26
+ };
27
+
28
+ /**
29
+ * The `<Link>` component, and almost identical `<NavLink>` component, are
30
+ * auxiliary wrappers around
31
+ * [React Router](https://github.com/ReactTraining/react-router)'s
32
+ * `<Link>` and `<NavLink>` components; they help to handle external and
33
+ * internal links in uniform manner.
34
+ *
35
+ * @param [props] Component properties.
36
+ * @param [props.className] CSS classes to apply to the link.
37
+ * @param [props.disabled] Disables the link.
38
+ * @param [props.enforceA] `true` enforces rendering of the link as
39
+ * a simple `<a>` element.
40
+ * @param [props.keepScrollPosition] If `true`, and the link is
41
+ * rendered as a React Router's component, it won't reset the viewport scrolling
42
+ * position to the origin when clicked.
43
+ * @param [props.onClick] Event handler to trigger upon click.
44
+ * @param [props.onMouseDown] Event handler to trigger on MouseDown
45
+ * event.
46
+ * @param [props.openNewTab] If `true` the link opens in a new tab.
47
+ * @param [props.replace] When `true`, the link will replace current
48
+ * entry in the history stack instead of adding a new one.
49
+ * @param [props.to] Link URL.
50
+ * @param [props.activeClassName] **`<NavLink>`** only: CSS class(es)
51
+ * to apply to rendered link when it is active.
52
+ * @param [props.activeStyle] **`<NavLink>`** only: CSS styles
53
+ * to apply to the rendered link when it is active.
54
+ * @param [props.exact] **`<NavLink>`** only: if `true`, the active
55
+ * class/style will only be applied if the location is matched exactly.
56
+ * @param [props.isActive] **`<NavLink>`** only: Add extra
57
+ * logic for determining whether the link is active. This should be used if you
58
+ * want to do more than verify that the link’s pathname matches the current URL
59
+ * pathname.
60
+ * @param [props.location] **`<NavLink>`** only: `isActive` compares
61
+ * current history location (usually the current browser URL). To compare to
62
+ * a different location, a custom `location` can be passed.
63
+ * @param [props.strict] **`<NavLink>`** only: . When `true`, trailing
64
+ * slash on a location’s pathname will be taken into consideration when
65
+ * determining if the location matches the current URL. See the `<Route strict>`
66
+ * documentation for more information.
67
+ */
68
+ const GenericLink: React.FunctionComponent<PropsT> = ({
69
+ children,
70
+ className,
71
+ disabled,
72
+ enforceA,
73
+ keepScrollPosition,
74
+ onClick,
75
+ onMouseDown,
76
+ openNewTab,
77
+ replace,
78
+ routerLinkType,
79
+ to,
80
+ ...rest
81
+ }) => {
82
+ /* Renders Link as <a> element if:
83
+ * - It is opted explicitely by `enforceA` prop;
84
+ * - It should be opened in a new tab;
85
+ * - It is an absolte URL (starts with http:// or https://);
86
+ * - It is anchor link (starts with #). */
87
+ if (disabled || enforceA || openNewTab || (to as string)?.match(/^(#|(https?|mailto):)/)) {
88
+ return (
89
+ <a
90
+ className={className}
91
+ // TODO: This requires a fix: disabled is not really an attribute of <a>
92
+ // tag, thus for disabled option we rather should render a plain text
93
+ // styled as a link.
94
+ // disabled={disabled}
95
+ href={to as string}
96
+ onClick={disabled ? (e) => e.preventDefault() : onClick}
97
+ onMouseDown={disabled ? (e) => e.preventDefault() : onMouseDown}
98
+ rel="noopener noreferrer"
99
+ styleName="link"
100
+ target={openNewTab ? '_blank' : ''}
101
+ >
102
+ {children}
103
+ </a>
104
+ );
105
+ }
106
+
107
+ const L = routerLinkType as typeof NavLink;
108
+
109
+ return (
110
+ <L
111
+ className={className}
112
+ // disabled
113
+ onMouseDown={onMouseDown}
114
+ replace={replace}
115
+ to={to!}
116
+ onClick={(e: React.MouseEvent<HTMLAnchorElement>) => {
117
+ // Executes the user-provided event handler, if any.
118
+ if (onClick) onClick(e);
119
+
120
+ // By default, clicking the link scrolls the page to beginning.
121
+ if (!keepScrollPosition) window.scroll(0, 0);
122
+ }}
123
+ {...rest} // eslint-disable-line react/jsx-props-no-spreading
124
+ >
125
+ {children}
126
+ </L>
127
+ );
128
+ };
129
+
130
+ GenericLink.defaultProps = {
131
+ children: null,
132
+ className: '',
133
+ disabled: false,
134
+ enforceA: false,
135
+ keepScrollPosition: false,
136
+ onClick: undefined,
137
+ onMouseDown: undefined,
138
+ openNewTab: false,
139
+ replace: false,
140
+ to: '',
141
+ };
142
+
143
+ GenericLink.propTypes = {
144
+ children: PT.node,
145
+ className: PT.string,
146
+ disabled: PT.bool,
147
+ enforceA: PT.bool,
148
+ keepScrollPosition: PT.bool,
149
+ onClick: PT.func,
150
+ onMouseDown: PT.func,
151
+ openNewTab: PT.bool,
152
+ replace: PT.bool,
153
+ routerLinkType: PT.elementType.isRequired,
154
+ to: PT.oneOfType([PT.object, PT.string]),
155
+ };
156
+
157
+ export default GenericLink;
@@ -0,0 +1,3 @@
1
+ .link[disabled] {
2
+ cursor: not-allowed;
3
+ }
@@ -0,0 +1,59 @@
1
+ import PT from 'prop-types';
2
+ import { forwardRef } from 'react';
3
+
4
+ import themed, { type Theme } from '@dr.pogodin/react-themes';
5
+
6
+ import defaultTheme from './theme.scss';
7
+
8
+ type PropsT = React.InputHTMLAttributes<HTMLInputElement> & {
9
+ label?: string;
10
+ theme: Theme & {
11
+ container?: string;
12
+ input?: string;
13
+ label?: string;
14
+ };
15
+ };
16
+
17
+ /**
18
+ * Themeable input field, based on the standard HTML `<input>` element.
19
+ * @param [props]
20
+ * @param [props.label] Input label.
21
+ * @param [props.theme] _Ad hoc_ theme.
22
+ * @param [props...] [Other theming properties](https://www.npmjs.com/package/@dr.pogodin/react-themes#themed-component-properties)
23
+ * @param [props...] Any other properties are passed to the underlying
24
+ * `<input>` element.
25
+ */
26
+ const Input = forwardRef<HTMLInputElement, PropsT>((
27
+ {
28
+ label,
29
+ theme,
30
+ ...rest
31
+ }: PropsT,
32
+ ref,
33
+ ) => (
34
+ <span className={theme.container}>
35
+ { label === undefined ? null : <p className={theme.label}>{label}</p> }
36
+ <input
37
+ className={theme.input}
38
+ ref={ref}
39
+ {...rest} // eslint-disable-line react/jsx-props-no-spreading
40
+ />
41
+ </span>
42
+ ));
43
+
44
+ const ThemedInput = themed(Input, 'Input', [
45
+ 'container',
46
+ 'input',
47
+ 'label',
48
+ ], defaultTheme);
49
+
50
+ Input.propTypes = {
51
+ label: PT.string,
52
+ theme: ThemedInput.themeType.isRequired,
53
+ };
54
+
55
+ Input.defaultProps = {
56
+ label: undefined,
57
+ };
58
+
59
+ export default ThemedInput;
@@ -0,0 +1,27 @@
1
+ *,
2
+ .context,
3
+ .ad.hoc {
4
+ &.container {
5
+ align-items: center;
6
+ display: inline-flex;
7
+ margin: 0.1em;
8
+ }
9
+
10
+ &.input {
11
+ border: 1px solid gray;
12
+ border-radius: 0.3em;
13
+ cursor: text;
14
+ font: inherit;
15
+ outline: none;
16
+ padding: 0.3em 0.3em calc(0.3em + 1px);
17
+
18
+ &:focus {
19
+ border-color: blue;
20
+ box-shadow: 0 0 3px 1px lightblue;
21
+ }
22
+ }
23
+
24
+ &.label {
25
+ margin: 0 0.6em 0 1.5em;
26
+ }
27
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The Link wraps around React Router's Link component, to automatically replace
3
+ * it by the regular <a> element when:
4
+ * - The target reference points to another domain;
5
+ * - User opts to open the reference in a new tab;
6
+ * - User explicitely opts to use <a>.
7
+ */
8
+
9
+ import { Link as RrLink } from 'react-router-dom';
10
+
11
+ import GenericLink, { type PropsT as GenericLinkPropsT } from './GenericLink';
12
+
13
+ type PropsT = Omit<GenericLinkPropsT, 'routerLinkType'>;
14
+
15
+ const Link: React.FunctionComponent<PropsT> = (props) => (
16
+ /* eslint-disable react/jsx-props-no-spreading */
17
+ <GenericLink {...props} routerLinkType={RrLink} />
18
+ /* eslint-enable react/jsx-props-no-spreading */
19
+ );
20
+
21
+ export default Link;