@scrabble-solver/scrabble-solver 2.16.7 → 2.18.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 (370) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +22 -20
  3. package/.next/cache/.previewinfo +1 -1
  4. package/.next/cache/.rscinfo +1 -1
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/index.pack +0 -0
  8. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  9. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  10. package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  11. package/.next/cache/webpack/server-production/0.pack +0 -0
  12. package/.next/cache/webpack/server-production/index.pack +0 -0
  13. package/.next/cache/webpack/server-production/index.pack.old +0 -0
  14. package/.next/diagnostics/framework.json +1 -1
  15. package/.next/dynamic-css-manifest.json +8 -1
  16. package/.next/next-minimal-server.js.nft.json +1 -1
  17. package/.next/next-server.js.nft.json +1 -1
  18. package/.next/prerender-manifest.json +4 -4
  19. package/.next/react-loadable-manifest.json +176 -1
  20. package/.next/required-server-files.js +3 -2
  21. package/.next/required-server-files.json +3 -2
  22. package/.next/routes-manifest.json +1 -1
  23. package/.next/server/chunks/30.js +1 -1
  24. package/.next/server/chunks/309.js +1 -0
  25. package/.next/server/chunks/316.js +1 -0
  26. package/.next/server/chunks/344.js +1 -0
  27. package/.next/server/chunks/371.js +1 -0
  28. package/.next/server/chunks/392.js +1 -1
  29. package/.next/server/chunks/465.js +1 -0
  30. package/.next/server/chunks/546.js +1 -0
  31. package/.next/server/chunks/623.js +1 -0
  32. package/.next/server/chunks/624.js +1 -0
  33. package/.next/server/chunks/641.js +1 -0
  34. package/.next/server/chunks/671.js +1 -1
  35. package/.next/server/chunks/692.js +1 -0
  36. package/.next/server/chunks/705.js +1 -0
  37. package/.next/server/chunks/712.js +1 -1
  38. package/.next/server/chunks/846.js +1 -0
  39. package/.next/server/chunks/853.js +15 -0
  40. package/.next/server/chunks/886.js +1 -0
  41. package/.next/server/chunks/916.js +1 -0
  42. package/.next/server/chunks/953.js +1 -0
  43. package/.next/server/chunks/961.js +1 -0
  44. package/.next/server/chunks/968.js +1 -0
  45. package/.next/server/dynamic-css-manifest.js +1 -1
  46. package/.next/server/middleware-build-manifest.js +1 -1
  47. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  48. package/.next/server/pages/404.html +28 -1
  49. package/.next/server/pages/500.html +28 -1
  50. package/.next/server/pages/_app.js +1 -1
  51. package/.next/server/pages/_app.js.nft.json +1 -1
  52. package/.next/server/pages/_document.js +28 -1
  53. package/.next/server/pages/_document.js.nft.json +1 -1
  54. package/.next/server/pages/_error.js +28 -1
  55. package/.next/server/pages/_error.js.nft.json +1 -1
  56. package/.next/server/pages/api/dictionary/[locale]/[word].js +1 -1
  57. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  58. package/.next/server/pages/api/dictionary/[locale].js +1 -1
  59. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  60. package/.next/server/pages/api/solve.js +1 -1
  61. package/.next/server/pages/api/solve.js.nft.json +1 -1
  62. package/.next/server/pages/api/verify.js +1 -1
  63. package/.next/server/pages/api/verify.js.nft.json +1 -1
  64. package/.next/server/pages/api/visit.js.nft.json +1 -1
  65. package/.next/server/pages/index.html +28 -1
  66. package/.next/server/pages/index.js +30 -1
  67. package/.next/server/pages/index.js.nft.json +1 -1
  68. package/.next/server/pages/index.json +1 -1
  69. package/.next/server/pages/not-found.html +28 -1
  70. package/.next/server/pages/not-found.js.nft.json +1 -1
  71. package/.next/server/pages-manifest.json +1 -1
  72. package/.next/server/webpack-api-runtime.js +1 -1
  73. package/.next/server/webpack-runtime.js +1 -1
  74. package/.next/static/FL82obwzFHRzvV6z76I-U/_buildManifest.js +1 -0
  75. package/.next/static/chunks/101-829ab8a8d310e7a0.js +3 -0
  76. package/.next/static/chunks/106.e414e88694add27f.js +1 -0
  77. package/.next/static/chunks/127.125d896a19061d71.js +1 -0
  78. package/.next/static/chunks/18.8b91e137d239e15c.js +1 -0
  79. package/.next/static/chunks/277.6785dfaf22fdb0b7.js +1 -0
  80. package/.next/static/chunks/307.67f52f13e3d60d4e.js +1 -0
  81. package/.next/static/chunks/341.79535ba85bf1986f.js +1 -0
  82. package/.next/static/chunks/363.01eed3233f92b6a4.js +1 -0
  83. package/.next/static/chunks/422.1559ae6756912ca5.js +1 -0
  84. package/.next/static/chunks/541.dcd9e8b804f88da5.js +1 -0
  85. package/.next/static/chunks/583.7a46807be14c377e.js +1 -0
  86. package/.next/static/chunks/631.98d42abad0a60af6.js +1 -0
  87. package/.next/static/chunks/663.d2c9ca36b26695b8.js +1 -0
  88. package/.next/static/chunks/711.ba7b8f900dfd40d0.js +1 -0
  89. package/.next/static/chunks/744.b06c9a3de4a1d877.js +1 -0
  90. package/.next/static/chunks/820.97b82f751ca49579.js +1 -0
  91. package/.next/static/chunks/865.a9b563a45848a83c.js +1 -0
  92. package/.next/static/chunks/912.ff8037ba9d4db5c8.js +1 -0
  93. package/.next/static/chunks/939.19b33a3d3c351d73.js +1 -0
  94. package/.next/static/chunks/990.61296e5870b91f11.js +1 -0
  95. package/.next/static/chunks/framework-626cbd48ac5aca57.js +1 -0
  96. package/.next/static/chunks/main-b92e08f3fc96dd8d.js +5 -0
  97. package/.next/static/chunks/pages/_app-ba5d628e81a15461.js +1 -0
  98. package/.next/static/chunks/pages/{_error-afeda7c5231b6c3c.js → _error-f0290a98eb3ed0ec.js} +1 -1
  99. package/.next/static/chunks/pages/index-5f9fa6ac3cd3d97b.js +1 -0
  100. package/.next/static/chunks/pages/not-found-23d61fd3ed791cad.js +1 -0
  101. package/.next/static/chunks/webpack-e34c3ae12275e978.js +1 -0
  102. package/.next/static/css/2d03f0da2c678dfc.css +1 -0
  103. package/.next/static/css/7b6724d2df70f48f.css +1 -0
  104. package/.next/static/css/abc2425d3ba607bc.css +1 -0
  105. package/.next/static/css/b736be3bd02b5d99.css +1 -0
  106. package/.next/static/css/b74cd7de82dabcdd.css +1 -0
  107. package/.next/static/css/c403ce739a9c0d83.css +1 -0
  108. package/.next/static/css/ca311e6c030663d4.css +1 -0
  109. package/.next/static/css/dee878eb64099d92.css +1 -0
  110. package/.next/static/css/fbfdce70731d0d2b.css +1 -0
  111. package/.next/trace +21 -21
  112. package/.next/trace-build +1 -1
  113. package/empty-module.js +2 -0
  114. package/next.config.js +13 -8
  115. package/package.json +35 -16
  116. package/public/llms.txt +11 -0
  117. package/public/robots.txt +4 -0
  118. package/scripts/generate-scss-types.ts +112 -0
  119. package/src/@types/scss.d.ts +6 -9
  120. package/src/@types/svg.d.ts +1 -1
  121. package/src/components/Alert/Alert.module.scss.d.ts +13 -0
  122. package/src/components/Alert/Alert.tsx +4 -1
  123. package/src/components/Badge/Badge.module.scss.d.ts +6 -0
  124. package/src/components/Board/Board.module.scss +10 -0
  125. package/src/components/Board/Board.module.scss.d.ts +17 -0
  126. package/src/components/Board/Board.tsx +14 -26
  127. package/src/components/Board/BoardPure.tsx +54 -49
  128. package/src/components/Board/components/Actions/Actions.module.scss +18 -18
  129. package/src/components/Board/components/Actions/Actions.module.scss.d.ts +7 -0
  130. package/src/components/Board/components/Actions/Actions.tsx +6 -3
  131. package/src/components/Board/components/Actions/lib.ts +3 -1
  132. package/src/components/Board/components/Cell/Cell.module.scss.d.ts +13 -0
  133. package/src/components/Board/components/Cell/Cell.tsx +32 -34
  134. package/src/components/Board/components/InputPrompt/InputPrompt.module.scss.d.ts +10 -0
  135. package/src/components/Board/components/InputPrompt/InputPrompt.tsx +1 -1
  136. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.module.scss.d.ts +8 -0
  137. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -2
  138. package/src/components/Board/getBoardBackground.ts +175 -0
  139. package/src/components/Board/hooks/index.ts +0 -1
  140. package/src/components/Board/hooks/useBoardStyle.ts +10 -20
  141. package/src/components/Board/hooks/useFloatingActions.ts +3 -6
  142. package/src/components/Board/hooks/useGrid.ts +23 -9
  143. package/src/components/Board/selectors.ts +1 -1
  144. package/src/components/Button/Button.module.scss.d.ts +12 -0
  145. package/src/components/Dictionary/Dictionary.module.scss +8 -22
  146. package/src/components/Dictionary/Dictionary.module.scss.d.ts +14 -0
  147. package/src/components/Dictionary/Dictionary.tsx +1 -10
  148. package/src/components/DictionaryInput/DictionaryInput.module.scss.d.ts +7 -0
  149. package/src/components/DictionaryInput/DictionaryInput.tsx +1 -1
  150. package/src/components/EmptyState/EmptyState.module.scss.d.ts +7 -0
  151. package/src/components/EmptyState/EmptyState.tsx +1 -1
  152. package/src/components/IconButton/IconButton.module.scss.d.ts +8 -0
  153. package/src/components/Key/Key.module.scss.d.ts +6 -0
  154. package/src/components/Keys/Arrows/Arrows.module.scss.d.ts +11 -0
  155. package/src/components/Keys/Arrows/Arrows.tsx +4 -1
  156. package/src/components/Keys/index.tsx +1 -1
  157. package/src/components/Loading/Loading.module.scss.d.ts +9 -0
  158. package/src/components/Loading/Loading.tsx +1 -1
  159. package/src/components/Logo/Logo.tsx +4 -9
  160. package/src/components/Logo/LogoBlueprint.tsx +1 -0
  161. package/src/components/Modal/Modal.module.scss.d.ts +15 -0
  162. package/src/components/Modal/Modal.tsx +16 -3
  163. package/src/components/Modal/components/Section/Section.module.scss.d.ts +7 -0
  164. package/src/components/NavButtons/NavButtons.module.scss +20 -0
  165. package/src/components/NavButtons/NavButtons.module.scss.d.ts +13 -0
  166. package/src/components/NavButtons/NavButtons.tsx +29 -45
  167. package/src/components/NotFound/NotFound.module.scss.d.ts +9 -0
  168. package/src/components/NotFound/NotFound.tsx +1 -1
  169. package/src/components/PlainTiles/PlainTiles.module.scss.d.ts +11 -0
  170. package/src/components/PlainTiles/PlainTiles.tsx +0 -1
  171. package/src/components/PlainTiles/Tile.tsx +3 -4
  172. package/src/components/PlainTiles/lib.ts +4 -19
  173. package/src/components/PlainTiles/types.ts +0 -1
  174. package/src/components/Progress/Progress.module.scss +7 -0
  175. package/src/components/Progress/Progress.module.scss.d.ts +6 -0
  176. package/src/components/Progress/Progress.tsx +2 -11
  177. package/src/components/Rack/Rack.module.scss +3 -0
  178. package/src/components/Rack/Rack.module.scss.d.ts +10 -0
  179. package/src/components/Rack/Rack.tsx +8 -11
  180. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +2 -0
  181. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss.d.ts +7 -0
  182. package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +1 -13
  183. package/src/components/Rack/components/InputPrompt/lib.ts +1 -1
  184. package/src/components/Rack/components/RackTile/RackTile.module.scss.d.ts +6 -0
  185. package/src/components/Rack/components/RackTile/RackTile.tsx +5 -4
  186. package/src/components/Rack/selectors.ts +1 -1
  187. package/src/components/Radio/Radio.module.scss.d.ts +12 -0
  188. package/src/components/Results/Cell.tsx +3 -12
  189. package/src/components/Results/Header.tsx +9 -18
  190. package/src/components/Results/HeaderButton.tsx +4 -5
  191. package/src/components/Results/Result.tsx +4 -15
  192. package/src/components/Results/Results.module.scss +4 -7
  193. package/src/components/Results/Results.module.scss.d.ts +27 -0
  194. package/src/components/Results/Results.tsx +14 -5
  195. package/src/components/Results/SolveButton.tsx +1 -1
  196. package/src/components/Results/types.ts +3 -3
  197. package/src/components/ResultsInput/ResultsInput.module.scss.d.ts +7 -0
  198. package/src/components/ResultsInput/ResultsInput.tsx +1 -1
  199. package/src/components/Solver/Solver.module.scss +6 -5
  200. package/src/components/Solver/Solver.module.scss.d.ts +20 -0
  201. package/src/components/Solver/Solver.tsx +23 -24
  202. package/src/components/Solver/components/InsertButton/InsertButton.module.scss.d.ts +7 -0
  203. package/src/components/Solver/components/InsertButton/InsertButton.tsx +1 -1
  204. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss.d.ts +18 -0
  205. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +3 -1
  206. package/src/components/Spinner/Spinner.module.scss.d.ts +10 -0
  207. package/src/components/Tile/Tile.module.scss +3 -0
  208. package/src/components/Tile/Tile.module.scss.d.ts +19 -0
  209. package/src/components/Tile/Tile.tsx +5 -14
  210. package/src/components/Tile/TilePure.tsx +2 -12
  211. package/src/components/Tooltip/Tooltip.module.scss.d.ts +7 -0
  212. package/src/components/Tooltip/Tooltip.tsx +14 -3
  213. package/src/components/Tooltip/useTooltip.ts +2 -1
  214. package/src/hooks/useColumns.ts +4 -7
  215. package/src/hooks/useDeferredRender.ts +20 -0
  216. package/src/hooks/useDirection.ts +4 -3
  217. package/src/hooks/useLanguage.ts +2 -2
  218. package/src/hooks/useLocalStorage.ts +32 -8
  219. package/src/hooks/useMedia.ts +26 -26
  220. package/src/i18n/constants.ts +2 -15
  221. package/src/i18n/i18n.ts +18 -17
  222. package/src/i18n/languages/english.json +0 -1
  223. package/src/i18n/languages/french.json +0 -1
  224. package/src/i18n/languages/german.json +0 -1
  225. package/src/i18n/languages/persian.json +0 -1
  226. package/src/i18n/languages/polish.json +0 -1
  227. package/src/i18n/languages/romanian.json +0 -1
  228. package/src/i18n/languages/spanish.json +0 -1
  229. package/src/i18n/languages/turkish.json +0 -1
  230. package/src/i18n/localeIcons.ts +24 -0
  231. package/src/lib/localeTransliterate.test.ts +5 -0
  232. package/src/lib/localeTransliterate.ts +26 -6
  233. package/src/lib/waitForIdleOrFirstIntent.ts +33 -0
  234. package/src/modals/DictionaryModal/DictionaryModal.module.scss.d.ts +8 -0
  235. package/src/modals/DictionaryModal/DictionaryModal.tsx +3 -1
  236. package/src/modals/KeyMapModal/KeyMapModal.tsx +3 -1
  237. package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss.d.ts +11 -0
  238. package/src/modals/MenuModal/MenuModal.module.scss +5 -0
  239. package/src/modals/MenuModal/MenuModal.module.scss.d.ts +10 -0
  240. package/src/modals/MenuModal/MenuModal.tsx +16 -5
  241. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +4 -1
  242. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss.d.ts +9 -0
  243. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -6
  244. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
  245. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss.d.ts +12 -0
  246. package/src/modals/RemainingTilesModal/components/Character/Character.tsx +5 -12
  247. package/src/modals/ResultsModal/ResultsModal.module.scss.d.ts +8 -0
  248. package/src/modals/ResultsModal/ResultsModal.tsx +8 -4
  249. package/src/modals/SettingsModal/SettingsModal.tsx +2 -2
  250. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss.d.ts +7 -0
  251. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -1
  252. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.module.scss.d.ts +7 -0
  253. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +1 -1
  254. package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.module.scss.d.ts +7 -0
  255. package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.tsx +1 -1
  256. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.module.scss.d.ts +7 -0
  257. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +1 -1
  258. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss.d.ts +8 -0
  259. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +24 -21
  260. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.module.scss.d.ts +7 -0
  261. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +1 -1
  262. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.module.scss.d.ts +7 -0
  263. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +1 -5
  264. package/src/modals/WordsModal/WordsModal.module.scss.d.ts +11 -0
  265. package/src/modals/WordsModal/WordsModal.tsx +4 -2
  266. package/src/modals/preload.ts +24 -0
  267. package/src/pages/_app.tsx +5 -8
  268. package/src/pages/_document.tsx +91 -5
  269. package/src/pages/api/dictionary/[locale]/[word].ts +2 -2
  270. package/src/pages/api/dictionary/[locale]/index.ts +80 -3
  271. package/src/pages/api/solve.ts +3 -3
  272. package/src/pages/api/verify.ts +12 -3
  273. package/src/pages/index.module.scss +1 -0
  274. package/src/pages/index.module.scss.d.ts +11 -0
  275. package/src/pages/index.tsx +98 -38
  276. package/src/pages/not-found.tsx +1 -1
  277. package/src/parameters/index.ts +24 -93
  278. package/src/sdk/solve.ts +13 -7
  279. package/src/sdk/verify.ts +12 -6
  280. package/src/service-worker/appShell.test.ts +86 -0
  281. package/src/service-worker/appShell.ts +39 -0
  282. package/src/service-worker/index.ts +4 -5
  283. package/src/serviceWorkerManager.ts +5 -19
  284. package/src/solver-worker/client.test.ts +151 -0
  285. package/src/solver-worker/client.ts +106 -0
  286. package/src/solver-worker/dictionaries/constants.ts +9 -0
  287. package/src/solver-worker/dictionaries/getDictionary.ts +21 -0
  288. package/src/solver-worker/dictionaries/index.ts +2 -0
  289. package/src/solver-worker/dictionaries/revalidateDictionary.test.ts +199 -0
  290. package/src/solver-worker/dictionaries/revalidateDictionary.ts +86 -0
  291. package/src/solver-worker/dictionaries/revalidatedAt.ts +43 -0
  292. package/src/solver-worker/getGaddag.test.ts +109 -0
  293. package/src/solver-worker/getGaddag.ts +62 -0
  294. package/src/solver-worker/index.ts +1 -0
  295. package/src/solver-worker/index.worker.ts +124 -0
  296. package/src/solver-worker/messages.ts +20 -0
  297. package/src/state/actions.ts +1 -1
  298. package/src/state/app/index.ts +4 -0
  299. package/src/state/app/initialState.ts +6 -0
  300. package/src/state/app/selectors.ts +5 -0
  301. package/src/state/app/slice.ts +20 -0
  302. package/src/state/app/types.ts +4 -0
  303. package/src/state/board/initialState.ts +1 -2
  304. package/src/state/i18n/index.ts +4 -0
  305. package/src/state/i18n/initialState.ts +5 -0
  306. package/src/state/i18n/selectors.ts +3 -0
  307. package/src/state/i18n/slice.ts +16 -0
  308. package/src/state/i18n/types.ts +7 -0
  309. package/src/state/index.ts +3 -0
  310. package/src/state/lib.ts +1 -1
  311. package/src/state/localStorage.ts +86 -29
  312. package/src/state/rack/initialState.ts +1 -2
  313. package/src/state/rack/slice.ts +4 -1
  314. package/src/state/results/lib.ts +5 -5
  315. package/src/state/results/selectors.ts +1 -1
  316. package/src/state/sagas.ts +139 -13
  317. package/src/state/selectors.ts +1 -1
  318. package/src/state/settings/initialState.ts +7 -10
  319. package/src/state/settings/selectors.ts +7 -2
  320. package/src/state/settings/slice.ts +5 -2
  321. package/src/state/store.ts +4 -0
  322. package/src/state/types.ts +4 -0
  323. package/src/state/useTypedStore.ts +6 -0
  324. package/src/styles/_tokens.scss +1 -0
  325. package/src/styles/global.scss +9 -0
  326. package/src/styles/variables.module.scss +0 -21
  327. package/src/styles/variables.module.scss.d.ts +27 -0
  328. package/src/styles/variables.scss +46 -2
  329. package/src/types/api.ts +1 -2
  330. package/src/types/index.ts +1 -2
  331. package/tsconfig.json +4 -0
  332. package/tsconfig.tsbuildinfo +1 -1
  333. package/.next/server/chunks/318.js +0 -3
  334. package/.next/server/chunks/791.js +0 -15
  335. package/.next/static/chunks/framework-3cf15b8041c59dd3.js +0 -1
  336. package/.next/static/chunks/main-852475ca502b4e49.js +0 -5
  337. package/.next/static/chunks/pages/_app-a5bbe02710f13d05.js +0 -7
  338. package/.next/static/chunks/pages/index-ec0f6aeeaf7be227.js +0 -1
  339. package/.next/static/chunks/pages/not-found-9e076427bad69d90.js +0 -1
  340. package/.next/static/chunks/webpack-1a7a166b34ed8d24.js +0 -1
  341. package/.next/static/css/0af35adb4bab56f0.css +0 -2
  342. package/.next/static/css/a78e04fe95452380.css +0 -1
  343. package/.next/static/vYpMmuC_yEurZGcyGVnLf/_buildManifest.js +0 -1
  344. package/src/app-layout/AppLayoutContext.tsx +0 -25
  345. package/src/app-layout/index.ts +0 -1
  346. package/src/app-layout/useAppLayoutValue.ts +0 -112
  347. package/src/components/Board/hooks/useBackgroundImage.tsx +0 -279
  348. package/src/components/index.ts +0 -26
  349. package/src/hooks/index.ts +0 -12
  350. package/src/hooks/useOnWindowResize.ts +0 -11
  351. package/src/hooks/useViewportSize.ts +0 -17
  352. package/src/i18n/index.ts +0 -2
  353. package/src/icons/Flag.svg +0 -4
  354. package/src/icons/Star.svg +0 -4
  355. package/src/icons/index.ts +0 -49
  356. package/src/lib/getTileSizes.ts +0 -13
  357. package/src/lib/index.ts +0 -24
  358. package/src/modals/index.ts +0 -7
  359. package/src/sdk/getDictionary.ts +0 -9
  360. package/src/service-worker/average.ts +0 -7
  361. package/src/service-worker/dictionaries/constants.ts +0 -5
  362. package/src/service-worker/dictionaries/getDictionary.ts +0 -20
  363. package/src/service-worker/dictionaries/index.ts +0 -2
  364. package/src/service-worker/dictionaries/revalidateDictionary.ts +0 -33
  365. package/src/service-worker/getTrie.ts +0 -24
  366. package/src/service-worker/routeSolveRequests.ts +0 -91
  367. package/src/service-worker/routeVerifyRequests.ts +0 -37
  368. /package/.next/static/{vYpMmuC_yEurZGcyGVnLf → FL82obwzFHRzvV6z76I-U}/_ssgManifest.js +0 -0
  369. /package/src/{service-worker → solver-worker}/dictionaries/expirationManager.ts +0 -0
  370. /package/src/{service-worker → solver-worker}/dictionaries/getDictionaryUrl.ts +0 -0
@@ -0,0 +1,27 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly cell: string;
4
+ readonly content: string;
5
+ readonly coordinates: string;
6
+ readonly emptyState: string;
7
+ readonly header: string;
8
+ readonly headerButton: string;
9
+ readonly headerButtonIcon: string;
10
+ readonly headerButtonLabel: string;
11
+ readonly highlight: string;
12
+ readonly highlighted: string;
13
+ readonly input: string;
14
+ readonly list: string;
15
+ readonly listContainer: string;
16
+ readonly outdated: string;
17
+ readonly points: string;
18
+ readonly result: string;
19
+ readonly resultContent: string;
20
+ readonly results: string;
21
+ readonly solveButton: string;
22
+ readonly sortIcon: string;
23
+ readonly stat: string;
24
+ readonly word: string;
25
+ };
26
+
27
+ export default styles;
@@ -3,9 +3,9 @@ import { useEffect, useMemo, type FunctionComponent } from 'react';
3
3
  import { List, useListRef } from 'react-window';
4
4
  import { useDebounce } from 'use-debounce';
5
5
 
6
- import { useLatest } from '@/hooks';
7
- import { LOCALE_FEATURES } from '@/i18n';
8
- import { RESULTS_ITEM_HEIGHT } from '@/parameters';
6
+ import { useLatest } from '@/hooks/useLatest';
7
+ import { LOCALE_FEATURES } from '@/i18n/constants';
8
+ import { RESULTS_ITEM_HEIGHT, RESULTS_OVERSCAN_COUNT } from '@/parameters';
9
9
  import {
10
10
  selectAreResultsOutdated,
11
11
  selectLocale,
@@ -44,7 +44,14 @@ export const Results: FunctionComponent<Props> = ({ callbacks, className, highli
44
44
  const isOutdated = useTypedSelector(selectAreResultsOutdated);
45
45
  const error = useTypedSelector(selectSolveError);
46
46
  const itemData = useMemo<ResultData>(
47
- () => ({ ...callbacks, highlightedIndex, results }),
47
+ () => ({
48
+ highlightedIndex,
49
+ results,
50
+ onBlur: callbacks.onBlur,
51
+ onClick: callbacks.onClick,
52
+ onFocus: callbacks.onFocus,
53
+ onMouseEnter: callbacks.onMouseEnter,
54
+ }),
48
55
  [callbacks, highlightedIndex, results],
49
56
  );
50
57
  const listRef = useListRef(null);
@@ -74,6 +81,7 @@ export const Results: FunctionComponent<Props> = ({ callbacks, className, highli
74
81
  aria-busy={isLoadingDebounced}
75
82
  aria-label={translate('results')}
76
83
  className={classNames(styles.results, className)}
84
+ data-outdated={isOutdated}
77
85
  data-testid="results"
78
86
  role="region"
79
87
  >
@@ -111,13 +119,14 @@ export const Results: FunctionComponent<Props> = ({ callbacks, className, highli
111
119
  )}
112
120
 
113
121
  {!isOutdated && results.length > 0 && (
114
- <div className={styles.listContainer}>
122
+ <div className={styles.listContainer} onMouseLeave={callbacks.onMouseLeave}>
115
123
  <List
116
124
  className={classNames(styles.list, {
117
125
  [styles.outdated]: isOutdated,
118
126
  })}
119
127
  dir={direction}
120
128
  listRef={listRef}
129
+ overscanCount={RESULTS_OVERSCAN_COUNT}
121
130
  rowComponent={Result}
122
131
  rowCount={results.length}
123
132
  rowHeight={RESULTS_ITEM_HEIGHT}
@@ -1,7 +1,7 @@
1
1
  import { type FunctionComponent } from 'react';
2
2
  import { useDispatch } from 'react-redux';
3
3
 
4
- import { Search } from '@/icons';
4
+ import Search from '@/icons/Search.svg';
5
5
  import {
6
6
  selectAreResultsOutdated,
7
7
  selectSolveIsLoading,
@@ -1,15 +1,15 @@
1
1
  import { type Result } from '@scrabble-solver/types';
2
- import { type FocusEvent, type MouseEvent } from 'react';
2
+ import { type FocusEvent, type MouseEvent, type MouseEventHandler } from 'react';
3
3
 
4
4
  export interface ResultCallbacks {
5
5
  onBlur?: (result: Result, event: FocusEvent) => void;
6
6
  onClick?: (result: Result, event: MouseEvent) => void;
7
7
  onFocus?: (result: Result, event: FocusEvent) => void;
8
8
  onMouseEnter?: (result: Result, event: MouseEvent) => void;
9
- onMouseLeave?: (result: Result, event: MouseEvent) => void;
9
+ onMouseLeave?: MouseEventHandler;
10
10
  }
11
11
 
12
- export interface ResultData extends ResultCallbacks {
12
+ export interface ResultData extends Omit<ResultCallbacks, 'onMouseLeave'> {
13
13
  highlightedIndex?: number;
14
14
  results: Result[] | undefined;
15
15
  }
@@ -0,0 +1,7 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly input: string;
4
+ readonly resultsInput: string;
5
+ };
6
+
7
+ export default styles;
@@ -2,7 +2,7 @@ import classNames from 'classnames';
2
2
  import { type ChangeEvent, type FunctionComponent, type SubmitEventHandler, useState } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
- import { isRegExp } from '@/lib';
5
+ import { isRegExp } from '@/lib/isRegExp';
6
6
  import { resultsSlice, selectResultsQuery, useTranslate, useTypedSelector } from '@/state';
7
7
 
8
8
  import styles from './ResultsInput.module.scss';
@@ -1,17 +1,13 @@
1
1
  @use 'styles/mixins' as *;
2
2
 
3
3
  .solver {
4
- --spacing: var(--spacing--xl);
4
+ --spacing: var(--components-spacing);
5
5
 
6
6
  position: relative;
7
7
  margin: 0 var(--spacing);
8
8
  display: flex;
9
9
  flex-direction: column;
10
10
 
11
- @include media('<xl') {
12
- --spacing: var(--spacing--l);
13
- }
14
-
15
11
  @include media('<l', 'touch') {
16
12
  margin-bottom: calc(3 * var(--spacing--l) + var(--button--icon--size));
17
13
  }
@@ -108,6 +104,11 @@
108
104
 
109
105
  .controls {
110
106
  width: 100%;
107
+ max-width: var(--controls-max-width);
108
+
109
+ @include media('>=l') {
110
+ display: none;
111
+ }
111
112
  }
112
113
 
113
114
  .emptyState {
@@ -0,0 +1,20 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly board: string;
4
+ readonly boardContainer: string;
5
+ readonly bottomContainer: string;
6
+ readonly bottomContent: string;
7
+ readonly column: string;
8
+ readonly container: string;
9
+ readonly content: string;
10
+ readonly controls: string;
11
+ readonly dictionary: string;
12
+ readonly dictionaryContainer: string;
13
+ readonly dictionaryInput: string;
14
+ readonly emptyState: string;
15
+ readonly results: string;
16
+ readonly solver: string;
17
+ readonly submitInput: string;
18
+ };
19
+
20
+ export default styles;
@@ -3,8 +3,8 @@ import classNames from 'classnames';
3
3
  import { type FunctionComponent, memo, type SyntheticEvent, useEffect, useMemo } from 'react';
4
4
  import { useDispatch } from 'react-redux';
5
5
 
6
- import { useAppLayout } from '@/app-layout';
7
- import { useIsTouchDevice } from '@/hooks';
6
+ import { useIsTouchDevice } from '@/hooks/useIsTouchDevice';
7
+ import { useMediaQuery } from '@/hooks/useMediaQuery';
8
8
  import {
9
9
  resultsSlice,
10
10
  selectAreResultsOutdated,
@@ -14,6 +14,7 @@ import {
14
14
  solveSlice,
15
15
  useTranslate,
16
16
  useTypedSelector,
17
+ useTypedStore,
17
18
  } from '@/state';
18
19
 
19
20
  import { Alert } from '../Alert';
@@ -35,16 +36,16 @@ const SolverBase: FunctionComponent<Props> = ({ className, onShowResults }) => {
35
36
  const dispatch = useDispatch();
36
37
  const translate = useTranslate();
37
38
  const isTouchDevice = useIsTouchDevice();
38
- const { maxControlsWidth, showCompactControls, tileSize } = useAppLayout();
39
+ const showCompactControls = useMediaQuery('<l');
39
40
  const error = useTypedSelector(selectSolveError);
40
41
  const isOutdated = useTypedSelector(selectAreResultsOutdated);
41
- const resultCandidate = useTypedSelector(selectResultCandidate);
42
42
  const results = useTypedSelector(selectProcessedResults);
43
+ const store = useTypedStore();
43
44
  const [bestResult] = results || [];
44
45
  const touchCallbacks = useMemo(
45
46
  () => ({
46
47
  onClick: (result: Result) => {
47
- const isSelected = result === resultCandidate;
48
+ const isSelected = result === selectResultCandidate(store.getState());
48
49
 
49
50
  if (isSelected) {
50
51
  dispatch(resultsSlice.actions.applyResult(result));
@@ -53,7 +54,7 @@ const SolverBase: FunctionComponent<Props> = ({ className, onShowResults }) => {
53
54
  }
54
55
  },
55
56
  }),
56
- [dispatch, resultCandidate],
57
+ [dispatch, store],
57
58
  );
58
59
  const mouseCallbacks = useMemo(
59
60
  () => ({
@@ -112,27 +113,25 @@ const SolverBase: FunctionComponent<Props> = ({ className, onShowResults }) => {
112
113
  <div className={styles.bottomContainer}>
113
114
  <div className={styles.bottomContent}>
114
115
  <form onSubmit={handleSubmit}>
115
- <Rack className={styles.rack} tileSize={tileSize} />
116
+ <Rack />
116
117
  <input className={styles.submitInput} tabIndex={-1} type="submit" />
117
118
  </form>
118
119
 
119
- {showCompactControls && (
120
- <div className={styles.controls} style={{ maxWidth: maxControlsWidth }}>
121
- <ResultCandidatePicker onResultClick={onShowResults} />
122
-
123
- {error && (
124
- <Alert className={styles.emptyState} variant="error">
125
- {error.message}
126
- </Alert>
127
- )}
128
-
129
- {results && results.length === 0 && !isOutdated && (
130
- <Alert className={styles.emptyState} variant="warning">
131
- {translate('results.empty-state.no-results')}
132
- </Alert>
133
- )}
134
- </div>
135
- )}
120
+ <div className={styles.controls}>
121
+ <ResultCandidatePicker onResultClick={onShowResults} />
122
+
123
+ {error && (
124
+ <Alert className={styles.emptyState} variant="error">
125
+ {error.message}
126
+ </Alert>
127
+ )}
128
+
129
+ {results && results.length === 0 && !isOutdated && (
130
+ <Alert className={styles.emptyState} variant="warning">
131
+ {translate('results.empty-state.no-results')}
132
+ </Alert>
133
+ )}
134
+ </div>
136
135
  </div>
137
136
  </div>
138
137
  </div>
@@ -0,0 +1,7 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly icon: string;
4
+ readonly insertButton: string;
5
+ };
6
+
7
+ export default styles;
@@ -2,7 +2,7 @@ import classNames from 'classnames';
2
2
  import { type FunctionComponent } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
- import { Check } from '@/icons';
5
+ import Check from '@/icons/Check.svg';
6
6
  import { resultsSlice, selectAreResultsOutdated, selectResultCandidate, useTranslate, useTypedSelector } from '@/state';
7
7
 
8
8
  import { Button } from '../../../Button';
@@ -0,0 +1,18 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly bothEnabled: string;
4
+ readonly button: string;
5
+ readonly buttons: string;
6
+ readonly content: string;
7
+ readonly icon: string;
8
+ readonly iconContainer: string;
9
+ readonly insert: string;
10
+ readonly loading: string;
11
+ readonly points: string;
12
+ readonly resultCandidate: string;
13
+ readonly resultCandidatePicker: string;
14
+ readonly spinnerContainer: string;
15
+ readonly word: string;
16
+ };
17
+
18
+ export default styles;
@@ -2,7 +2,9 @@ import classNames from 'classnames';
2
2
  import { type FunctionComponent, type HTMLProps, type MouseEventHandler } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
- import { ChevronDown, ChevronLeft, ChevronRight } from '@/icons';
5
+ import ChevronDown from '@/icons/ChevronDown.svg';
6
+ import ChevronLeft from '@/icons/ChevronLeft.svg';
7
+ import ChevronRight from '@/icons/ChevronRight.svg';
6
8
  import {
7
9
  resultsSlice,
8
10
  selectAreResultsOutdated,
@@ -0,0 +1,10 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly hide: string;
4
+ readonly rotate: string;
5
+ readonly show: string;
6
+ readonly spinner: string;
7
+ readonly wave: string;
8
+ };
9
+
10
+ export default styles;
@@ -4,6 +4,8 @@
4
4
  --background-color: transparent;
5
5
 
6
6
  position: relative;
7
+ width: var(--tile-size, auto);
8
+ height: var(--tile-size, auto);
7
9
  display: flex;
8
10
  align-items: center;
9
11
  justify-content: center;
@@ -92,6 +94,7 @@
92
94
  .points {
93
95
  @include text-stroke(var(--background-color), 1px);
94
96
 
97
+ font-size: max(10px, calc(var(--tile-size) * 0.25));
95
98
  position: absolute;
96
99
  inset-block-end: 1%;
97
100
  inset-inline-end: 9%;
@@ -0,0 +1,19 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly alert: string;
4
+ readonly blank: string;
5
+ readonly empty: string;
6
+ readonly highlighted: string;
7
+ readonly input: string;
8
+ readonly invalid: string;
9
+ readonly points: string;
10
+ readonly points1: string;
11
+ readonly points2: string;
12
+ readonly points3: string;
13
+ readonly points4: string;
14
+ readonly points5: string;
15
+ readonly raised: string;
16
+ readonly tile: string;
17
+ };
18
+
19
+ export default styles;
@@ -1,5 +1,6 @@
1
1
  import { useMergeRefs } from '@floating-ui/react';
2
2
  import { EMPTY_CELL } from '@scrabble-solver/constants';
3
+ import { type Locale } from '@scrabble-solver/types';
3
4
  import {
4
5
  type ChangeEventHandler,
5
6
  type FocusEventHandler,
@@ -9,13 +10,10 @@ import {
9
10
  type Ref,
10
11
  type TouchEventHandler,
11
12
  useCallback,
12
- useMemo,
13
13
  useRef,
14
14
  } from 'react';
15
15
 
16
- import { useAppLayout } from '@/app-layout';
17
- import { getTileSizes, noop } from '@/lib';
18
- import { selectLocale, useTypedSelector } from '@/state';
16
+ import { noop } from '@/lib/noop';
19
17
 
20
18
  import { TilePure } from './TilePure';
21
19
 
@@ -29,10 +27,10 @@ interface Props {
29
27
  inputRef?: Ref<HTMLInputElement | null>;
30
28
  isBlank?: boolean;
31
29
  isValid?: boolean;
30
+ locale: Locale;
32
31
  placeholder?: string;
33
32
  points?: number;
34
33
  raised?: boolean;
35
- size: number;
36
34
  tabIndex?: number;
37
35
  onChange?: ChangeEventHandler<HTMLInputElement>;
38
36
  onFocus?: FocusEventHandler<HTMLInputElement>;
@@ -51,10 +49,10 @@ export const Tile: FunctionComponent<Props> = ({
51
49
  inputRef,
52
50
  isBlank,
53
51
  isValid,
52
+ locale,
54
53
  placeholder,
55
54
  points,
56
55
  raised,
57
- size,
58
56
  tabIndex,
59
57
  onChange,
60
58
  onFocus = noop,
@@ -62,15 +60,10 @@ export const Tile: FunctionComponent<Props> = ({
62
60
  onMouseDown = noop,
63
61
  onTouchStart = noop,
64
62
  }) => {
65
- const locale = useTypedSelector(selectLocale);
66
- const { showTilePoints } = useAppLayout();
67
- const { pointsFontSize, tileSize } = getTileSizes(size);
68
- const style = useMemo(() => ({ height: tileSize, width: tileSize }), [tileSize]);
69
- const pointsStyle = useMemo(() => ({ fontSize: pointsFontSize }), [pointsFontSize]);
70
63
  const ref = useRef<HTMLInputElement>(null);
71
64
  const mergedRef = useMergeRefs(inputRef ? [ref, inputRef] : [ref]);
72
65
  const isEmpty = !character || character === EMPTY_CELL;
73
- const canShowPoints = showTilePoints && (!isEmpty || isBlank) && typeof points !== 'undefined';
66
+ const canShowPoints = (!isEmpty || isBlank) && typeof points !== 'undefined';
74
67
  const pointsFormatted = typeof points === 'number' ? points.toLocaleString(locale) : '';
75
68
 
76
69
  const handleKeyDown: KeyboardEventHandler<HTMLInputElement> = useCallback(
@@ -96,9 +89,7 @@ export const Tile: FunctionComponent<Props> = ({
96
89
  placeholder={placeholder}
97
90
  points={points}
98
91
  pointsFormatted={pointsFormatted}
99
- pointsStyle={pointsStyle}
100
92
  raised={raised}
101
- style={style}
102
93
  tabIndex={tabIndex}
103
94
  onChange={onChange}
104
95
  onFocus={onFocus}
@@ -1,7 +1,6 @@
1
1
  import classNames from 'classnames';
2
2
  import {
3
3
  type ChangeEventHandler,
4
- type CSSProperties,
5
4
  type FocusEventHandler,
6
5
  type FunctionComponent,
7
6
  type KeyboardEventHandler,
@@ -11,7 +10,7 @@ import {
11
10
  type TouchEventHandler,
12
11
  } from 'react';
13
12
 
14
- import { ExclamationSquareFill } from '@/icons';
13
+ import ExclamationSquareFill from '@/icons/ExclamationSquareFill.svg';
15
14
 
16
15
  import styles from './Tile.module.scss';
17
16
 
@@ -29,9 +28,7 @@ interface Props {
29
28
  placeholder?: string;
30
29
  points?: number;
31
30
  pointsFormatted?: string;
32
- pointsStyle?: CSSProperties;
33
31
  raised?: boolean;
34
- style?: CSSProperties;
35
32
  tabIndex?: number;
36
33
  onChange?: ChangeEventHandler<HTMLInputElement>;
37
34
  onFocus?: FocusEventHandler<HTMLInputElement>;
@@ -54,9 +51,7 @@ const TilePureBase: FunctionComponent<Props> = ({
54
51
  placeholder,
55
52
  points,
56
53
  pointsFormatted,
57
- pointsStyle,
58
54
  raised,
59
- style,
60
55
  tabIndex,
61
56
  onChange,
62
57
  onFocus,
@@ -78,7 +73,6 @@ const TilePureBase: FunctionComponent<Props> = ({
78
73
  [styles.raised]: raised,
79
74
  })}
80
75
  role={highlighted ? 'mark' : undefined}
81
- style={style}
82
76
  >
83
77
  {character || placeholder}
84
78
 
@@ -103,11 +97,7 @@ const TilePureBase: FunctionComponent<Props> = ({
103
97
  />
104
98
  )}
105
99
 
106
- {canShowPoints && (
107
- <span className={styles.points} style={pointsStyle}>
108
- {pointsFormatted}
109
- </span>
110
- )}
100
+ {canShowPoints && <span className={styles.points}>{pointsFormatted}</span>}
111
101
 
112
102
  {!isValid && <ExclamationSquareFill aria-hidden="true" className={styles.alert} role="img" />}
113
103
  </div>
@@ -0,0 +1,7 @@
1
+ // Generated by scripts/generate-scss-types.ts - do not edit.
2
+ declare const styles: {
3
+ readonly arrow: string;
4
+ readonly tooltip: string;
5
+ };
6
+
7
+ export default styles;
@@ -1,7 +1,8 @@
1
1
  import type { Placement } from '@floating-ui/react';
2
2
  import { type FunctionComponent, type ReactNode } from 'react';
3
3
 
4
- import { useIsTouchDevice } from '@/hooks';
4
+ import { useDeferredRender } from '@/hooks/useDeferredRender';
5
+ import { useIsTouchDevice } from '@/hooks/useIsTouchDevice';
5
6
 
6
7
  import { TooltipContext } from './context';
7
8
  import { TooltipContent } from './TooltipContent';
@@ -15,13 +16,23 @@ interface Props {
15
16
  }
16
17
 
17
18
  export const Tooltip: FunctionComponent<Props> = ({ children, placement, tooltip }) => {
18
- const state = useTooltip({ placement });
19
+ const canRenderTooltip = useDeferredRender();
19
20
  const isTouchDevice = useIsTouchDevice();
20
21
 
21
- if (!tooltip || isTouchDevice) {
22
+ if (!tooltip || !canRenderTooltip || isTouchDevice) {
22
23
  return children;
23
24
  }
24
25
 
26
+ return (
27
+ <TooltipBase placement={placement} tooltip={tooltip}>
28
+ {children}
29
+ </TooltipBase>
30
+ );
31
+ };
32
+
33
+ const TooltipBase: FunctionComponent<Props> = ({ children, placement, tooltip }) => {
34
+ const state = useTooltip({ placement });
35
+
25
36
  return (
26
37
  <TooltipContext.Provider value={state}>
27
38
  <TooltipTrigger>{children}</TooltipTrigger>
@@ -28,6 +28,7 @@ export const useTooltip = ({ placement = 'top' }: TooltipOptions = {}) => {
28
28
  const arrowRef = useRef(null);
29
29
  const data = useFloating({
30
30
  placement,
31
+ strategy: 'fixed',
31
32
  open: isOpen,
32
33
  onOpenChange: setIsOpen,
33
34
  whileElementsMounted: autoUpdate,
@@ -37,7 +38,7 @@ export const useTooltip = ({ placement = 'top' }: TooltipOptions = {}) => {
37
38
  const { delay } = useDelayGroup(context);
38
39
  const hover = useHover(context, { move: false, delay });
39
40
  const focus = useFocus(context);
40
- const dismiss = useDismiss(context);
41
+ const dismiss = useDismiss(context, { ancestorScroll: true });
41
42
  const role = useRole(context, { role: 'tooltip' });
42
43
  const interactions = useInteractions([hover, focus, dismiss, role]);
43
44
 
@@ -1,8 +1,8 @@
1
1
  import { createSelector } from '@reduxjs/toolkit';
2
2
  import { useMemo } from 'react';
3
3
 
4
- import { LOCALE_FEATURES } from '@/i18n';
5
- import { selectLocale, selectShowCoordinates, useTypedSelector } from '@/state';
4
+ import { LOCALE_FEATURES } from '@/i18n/constants';
5
+ import { selectLocale, useTypedSelector } from '@/state';
6
6
  import { ResultColumnId } from '@/types';
7
7
 
8
8
  import { useMediaQueries } from './useMediaQueries';
@@ -15,7 +15,7 @@ const COLUMNS_M = [...COLUMNS_XS];
15
15
 
16
16
  const COLUMNS_L = [...COLUMNS_XS];
17
17
 
18
- const selectColumns = createSelector([selectLocale, selectShowCoordinates], (locale, showCoordinates) => {
18
+ const selectColumns = createSelector([selectLocale], (locale) => {
19
19
  const { consonants, vowels } = LOCALE_FEATURES[locale];
20
20
  const columns: ResultColumnId[] = [
21
21
  ResultColumnId.Word,
@@ -23,12 +23,9 @@ const selectColumns = createSelector([selectLocale, selectShowCoordinates], (loc
23
23
  ResultColumnId.BlanksCount,
24
24
  ResultColumnId.WordsCount,
25
25
  ResultColumnId.Points,
26
+ ResultColumnId.Coordinates,
26
27
  ];
27
28
 
28
- if (showCoordinates !== 'hidden') {
29
- columns.push(ResultColumnId.Coordinates);
30
- }
31
-
32
29
  if (vowels) {
33
30
  columns.push(ResultColumnId.VowelsCount);
34
31
  }
@@ -0,0 +1,20 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ /**
4
+ * False during SSR and hydration.
5
+ */
6
+ export const useDeferredRender = (): boolean => {
7
+ const [canRender, setCanRender] = useState(false);
8
+
9
+ useEffect(() => {
10
+ const timeoutId = window.setTimeout(() => {
11
+ return setCanRender(true);
12
+ }, 0);
13
+
14
+ return () => {
15
+ return window.clearTimeout(timeoutId);
16
+ };
17
+ }, []);
18
+
19
+ return canRender;
20
+ };
@@ -1,12 +1,13 @@
1
+ import { type TextDirection } from '@scrabble-solver/types';
1
2
  import { useEffect } from 'react';
2
3
 
3
- import { noop } from '@/lib';
4
+ import { noop } from '@/lib/noop';
4
5
 
5
- export const useDirection = (direction: 'ltr' | 'rtl') => {
6
+ export const useDirection = (direction: TextDirection) => {
6
7
  useEffect(() => {
7
8
  const html = document.body.parentElement;
8
9
 
9
- if (!html) {
10
+ if (!html || html.dir === direction) {
10
11
  return noop;
11
12
  }
12
13
 
@@ -1,12 +1,12 @@
1
1
  import { useEffect } from 'react';
2
2
 
3
- import { noop } from '@/lib';
3
+ import { noop } from '@/lib/noop';
4
4
 
5
5
  export const useLanguage = (language: string) => {
6
6
  useEffect(() => {
7
7
  const html = document.body.parentElement;
8
8
 
9
- if (!html) {
9
+ if (!html || html.lang === language) {
10
10
  return noop;
11
11
  }
12
12