@scrabble-solver/scrabble-solver 2.17.0 → 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 (328) 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/routes-manifest.json +1 -1
  21. package/.next/server/chunks/309.js +1 -0
  22. package/.next/server/chunks/{785.js → 316.js} +1 -1
  23. package/.next/server/chunks/344.js +1 -0
  24. package/.next/server/chunks/371.js +1 -0
  25. package/.next/server/chunks/465.js +1 -0
  26. package/.next/server/chunks/546.js +1 -0
  27. package/.next/server/chunks/623.js +1 -0
  28. package/.next/server/chunks/624.js +1 -0
  29. package/.next/server/chunks/641.js +1 -0
  30. package/.next/server/chunks/671.js +1 -1
  31. package/.next/server/chunks/692.js +1 -0
  32. package/.next/server/chunks/705.js +1 -0
  33. package/.next/server/chunks/712.js +1 -1
  34. package/.next/server/chunks/846.js +1 -0
  35. package/.next/server/chunks/853.js +15 -0
  36. package/.next/server/chunks/886.js +1 -0
  37. package/.next/server/chunks/916.js +1 -0
  38. package/.next/server/chunks/953.js +1 -0
  39. package/.next/server/chunks/961.js +1 -0
  40. package/.next/server/chunks/968.js +1 -0
  41. package/.next/server/dynamic-css-manifest.js +1 -1
  42. package/.next/server/middleware-build-manifest.js +1 -1
  43. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  44. package/.next/server/pages/404.html +28 -1
  45. package/.next/server/pages/500.html +28 -1
  46. package/.next/server/pages/_app.js +1 -1
  47. package/.next/server/pages/_app.js.nft.json +1 -1
  48. package/.next/server/pages/_document.js +28 -1
  49. package/.next/server/pages/_document.js.nft.json +1 -1
  50. package/.next/server/pages/_error.js +28 -1
  51. package/.next/server/pages/_error.js.nft.json +1 -1
  52. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  53. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  54. package/.next/server/pages/api/solve.js +1 -1
  55. package/.next/server/pages/api/solve.js.nft.json +1 -1
  56. package/.next/server/pages/api/verify.js.nft.json +1 -1
  57. package/.next/server/pages/api/visit.js.nft.json +1 -1
  58. package/.next/server/pages/index.html +28 -1
  59. package/.next/server/pages/index.js +30 -1
  60. package/.next/server/pages/index.js.nft.json +1 -1
  61. package/.next/server/pages/index.json +1 -1
  62. package/.next/server/pages/not-found.html +28 -1
  63. package/.next/server/pages/not-found.js.nft.json +1 -1
  64. package/.next/server/pages-manifest.json +1 -1
  65. package/.next/server/webpack-api-runtime.js +1 -1
  66. package/.next/server/webpack-runtime.js +1 -1
  67. package/.next/static/FL82obwzFHRzvV6z76I-U/_buildManifest.js +1 -0
  68. package/.next/static/chunks/101-829ab8a8d310e7a0.js +3 -0
  69. package/.next/static/chunks/106.e414e88694add27f.js +1 -0
  70. package/.next/static/chunks/127.125d896a19061d71.js +1 -0
  71. package/.next/static/chunks/18.8b91e137d239e15c.js +1 -0
  72. package/.next/static/chunks/277.6785dfaf22fdb0b7.js +1 -0
  73. package/.next/static/chunks/307.67f52f13e3d60d4e.js +1 -0
  74. package/.next/static/chunks/341.79535ba85bf1986f.js +1 -0
  75. package/.next/static/chunks/363.01eed3233f92b6a4.js +1 -0
  76. package/.next/static/chunks/422.1559ae6756912ca5.js +1 -0
  77. package/.next/static/chunks/541.dcd9e8b804f88da5.js +1 -0
  78. package/.next/static/chunks/631.98d42abad0a60af6.js +1 -0
  79. package/.next/static/chunks/663.d2c9ca36b26695b8.js +1 -0
  80. package/.next/static/chunks/711.ba7b8f900dfd40d0.js +1 -0
  81. package/.next/static/chunks/744.b06c9a3de4a1d877.js +1 -0
  82. package/.next/static/chunks/820.97b82f751ca49579.js +1 -0
  83. package/.next/static/chunks/865.a9b563a45848a83c.js +1 -0
  84. package/.next/static/chunks/912.ff8037ba9d4db5c8.js +1 -0
  85. package/.next/static/chunks/939.19b33a3d3c351d73.js +1 -0
  86. package/.next/static/chunks/990.61296e5870b91f11.js +1 -0
  87. package/.next/static/chunks/framework-626cbd48ac5aca57.js +1 -0
  88. package/.next/static/chunks/main-b92e08f3fc96dd8d.js +5 -0
  89. package/.next/static/chunks/pages/_app-ba5d628e81a15461.js +1 -0
  90. package/.next/static/chunks/pages/{_error-afeda7c5231b6c3c.js → _error-f0290a98eb3ed0ec.js} +1 -1
  91. package/.next/static/chunks/pages/index-5f9fa6ac3cd3d97b.js +1 -0
  92. package/.next/static/chunks/pages/not-found-23d61fd3ed791cad.js +1 -0
  93. package/.next/static/chunks/webpack-e34c3ae12275e978.js +1 -0
  94. package/.next/static/css/2d03f0da2c678dfc.css +1 -0
  95. package/.next/static/css/7b6724d2df70f48f.css +1 -0
  96. package/.next/static/css/abc2425d3ba607bc.css +1 -0
  97. package/.next/static/css/b736be3bd02b5d99.css +1 -0
  98. package/.next/static/css/b74cd7de82dabcdd.css +1 -0
  99. package/.next/static/css/c403ce739a9c0d83.css +1 -0
  100. package/.next/static/css/ca311e6c030663d4.css +1 -0
  101. package/.next/static/css/dee878eb64099d92.css +1 -0
  102. package/.next/static/css/fbfdce70731d0d2b.css +1 -0
  103. package/.next/trace +21 -21
  104. package/.next/trace-build +1 -1
  105. package/empty-module.js +2 -0
  106. package/next.config.js +13 -2
  107. package/package.json +34 -15
  108. package/public/llms.txt +11 -0
  109. package/public/robots.txt +4 -0
  110. package/scripts/generate-scss-types.ts +112 -0
  111. package/src/@types/scss.d.ts +6 -9
  112. package/src/@types/svg.d.ts +1 -1
  113. package/src/components/Alert/Alert.module.scss.d.ts +13 -0
  114. package/src/components/Alert/Alert.tsx +4 -1
  115. package/src/components/Badge/Badge.module.scss.d.ts +6 -0
  116. package/src/components/Board/Board.module.scss +10 -0
  117. package/src/components/Board/Board.module.scss.d.ts +17 -0
  118. package/src/components/Board/Board.tsx +14 -26
  119. package/src/components/Board/BoardPure.tsx +54 -49
  120. package/src/components/Board/components/Actions/Actions.module.scss +18 -18
  121. package/src/components/Board/components/Actions/Actions.module.scss.d.ts +7 -0
  122. package/src/components/Board/components/Actions/Actions.tsx +6 -3
  123. package/src/components/Board/components/Actions/lib.ts +3 -1
  124. package/src/components/Board/components/Cell/Cell.module.scss.d.ts +13 -0
  125. package/src/components/Board/components/Cell/Cell.tsx +28 -33
  126. package/src/components/Board/components/InputPrompt/InputPrompt.module.scss.d.ts +10 -0
  127. package/src/components/Board/components/InputPrompt/InputPrompt.tsx +1 -1
  128. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.module.scss.d.ts +8 -0
  129. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -2
  130. package/src/components/Board/getBoardBackground.ts +175 -0
  131. package/src/components/Board/hooks/index.ts +0 -1
  132. package/src/components/Board/hooks/useBoardStyle.ts +10 -20
  133. package/src/components/Board/hooks/useFloatingActions.ts +3 -6
  134. package/src/components/Board/hooks/useGrid.ts +6 -3
  135. package/src/components/Board/selectors.ts +1 -1
  136. package/src/components/Button/Button.module.scss.d.ts +12 -0
  137. package/src/components/Dictionary/Dictionary.module.scss +1 -0
  138. package/src/components/Dictionary/Dictionary.module.scss.d.ts +14 -0
  139. package/src/components/Dictionary/Dictionary.tsx +1 -3
  140. package/src/components/DictionaryInput/DictionaryInput.module.scss.d.ts +7 -0
  141. package/src/components/DictionaryInput/DictionaryInput.tsx +1 -1
  142. package/src/components/EmptyState/EmptyState.module.scss.d.ts +7 -0
  143. package/src/components/EmptyState/EmptyState.tsx +1 -1
  144. package/src/components/IconButton/IconButton.module.scss.d.ts +8 -0
  145. package/src/components/Key/Key.module.scss.d.ts +6 -0
  146. package/src/components/Keys/Arrows/Arrows.module.scss.d.ts +11 -0
  147. package/src/components/Keys/Arrows/Arrows.tsx +4 -1
  148. package/src/components/Keys/index.tsx +1 -1
  149. package/src/components/Loading/Loading.module.scss.d.ts +9 -0
  150. package/src/components/Loading/Loading.tsx +1 -1
  151. package/src/components/Logo/Logo.tsx +4 -9
  152. package/src/components/Logo/LogoBlueprint.tsx +1 -0
  153. package/src/components/Modal/Modal.module.scss.d.ts +15 -0
  154. package/src/components/Modal/Modal.tsx +16 -3
  155. package/src/components/Modal/components/Section/Section.module.scss.d.ts +7 -0
  156. package/src/components/NavButtons/NavButtons.module.scss +20 -0
  157. package/src/components/NavButtons/NavButtons.module.scss.d.ts +13 -0
  158. package/src/components/NavButtons/NavButtons.tsx +29 -45
  159. package/src/components/NotFound/NotFound.module.scss.d.ts +9 -0
  160. package/src/components/NotFound/NotFound.tsx +1 -1
  161. package/src/components/PlainTiles/PlainTiles.module.scss.d.ts +11 -0
  162. package/src/components/PlainTiles/PlainTiles.tsx +0 -1
  163. package/src/components/PlainTiles/Tile.tsx +3 -4
  164. package/src/components/PlainTiles/lib.ts +4 -19
  165. package/src/components/PlainTiles/types.ts +0 -1
  166. package/src/components/Progress/Progress.module.scss +7 -0
  167. package/src/components/Progress/Progress.module.scss.d.ts +6 -0
  168. package/src/components/Progress/Progress.tsx +2 -11
  169. package/src/components/Rack/Rack.module.scss +3 -0
  170. package/src/components/Rack/Rack.module.scss.d.ts +10 -0
  171. package/src/components/Rack/Rack.tsx +8 -11
  172. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +2 -0
  173. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss.d.ts +7 -0
  174. package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +1 -13
  175. package/src/components/Rack/components/InputPrompt/lib.ts +1 -1
  176. package/src/components/Rack/components/RackTile/RackTile.module.scss.d.ts +6 -0
  177. package/src/components/Rack/components/RackTile/RackTile.tsx +5 -4
  178. package/src/components/Rack/selectors.ts +1 -1
  179. package/src/components/Radio/Radio.module.scss.d.ts +12 -0
  180. package/src/components/Results/Cell.tsx +3 -12
  181. package/src/components/Results/Header.tsx +9 -18
  182. package/src/components/Results/HeaderButton.tsx +4 -5
  183. package/src/components/Results/Result.tsx +4 -12
  184. package/src/components/Results/Results.module.scss +4 -6
  185. package/src/components/Results/Results.module.scss.d.ts +27 -0
  186. package/src/components/Results/Results.tsx +4 -3
  187. package/src/components/Results/SolveButton.tsx +1 -1
  188. package/src/components/ResultsInput/ResultsInput.module.scss.d.ts +7 -0
  189. package/src/components/ResultsInput/ResultsInput.tsx +1 -1
  190. package/src/components/Solver/Solver.module.scss +6 -5
  191. package/src/components/Solver/Solver.module.scss.d.ts +20 -0
  192. package/src/components/Solver/Solver.tsx +19 -21
  193. package/src/components/Solver/components/InsertButton/InsertButton.module.scss.d.ts +7 -0
  194. package/src/components/Solver/components/InsertButton/InsertButton.tsx +1 -1
  195. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss.d.ts +18 -0
  196. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +3 -1
  197. package/src/components/Spinner/Spinner.module.scss.d.ts +10 -0
  198. package/src/components/Tile/Tile.module.scss +3 -0
  199. package/src/components/Tile/Tile.module.scss.d.ts +19 -0
  200. package/src/components/Tile/Tile.tsx +5 -14
  201. package/src/components/Tile/TilePure.tsx +2 -12
  202. package/src/components/Tooltip/Tooltip.module.scss.d.ts +7 -0
  203. package/src/components/Tooltip/Tooltip.tsx +14 -3
  204. package/src/components/Tooltip/useTooltip.ts +1 -0
  205. package/src/hooks/useColumns.ts +4 -7
  206. package/src/hooks/useDeferredRender.ts +20 -0
  207. package/src/hooks/useDirection.ts +4 -3
  208. package/src/hooks/useLanguage.ts +2 -2
  209. package/src/hooks/useLocalStorage.ts +32 -8
  210. package/src/hooks/useMedia.ts +26 -26
  211. package/src/i18n/constants.ts +2 -15
  212. package/src/i18n/i18n.ts +18 -17
  213. package/src/i18n/languages/english.json +0 -1
  214. package/src/i18n/languages/french.json +0 -1
  215. package/src/i18n/languages/german.json +0 -1
  216. package/src/i18n/languages/persian.json +0 -1
  217. package/src/i18n/languages/polish.json +0 -1
  218. package/src/i18n/languages/romanian.json +0 -1
  219. package/src/i18n/languages/spanish.json +0 -1
  220. package/src/i18n/languages/turkish.json +0 -1
  221. package/src/i18n/localeIcons.ts +24 -0
  222. package/src/lib/localeTransliterate.test.ts +5 -0
  223. package/src/lib/localeTransliterate.ts +26 -6
  224. package/src/lib/waitForIdleOrFirstIntent.ts +33 -0
  225. package/src/modals/DictionaryModal/DictionaryModal.module.scss.d.ts +8 -0
  226. package/src/modals/DictionaryModal/DictionaryModal.tsx +3 -1
  227. package/src/modals/KeyMapModal/KeyMapModal.tsx +3 -1
  228. package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss.d.ts +11 -0
  229. package/src/modals/MenuModal/MenuModal.module.scss +5 -0
  230. package/src/modals/MenuModal/MenuModal.module.scss.d.ts +10 -0
  231. package/src/modals/MenuModal/MenuModal.tsx +16 -5
  232. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +4 -1
  233. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss.d.ts +9 -0
  234. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +4 -6
  235. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
  236. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss.d.ts +12 -0
  237. package/src/modals/RemainingTilesModal/components/Character/Character.tsx +5 -12
  238. package/src/modals/ResultsModal/ResultsModal.module.scss.d.ts +8 -0
  239. package/src/modals/ResultsModal/ResultsModal.tsx +8 -4
  240. package/src/modals/SettingsModal/SettingsModal.tsx +2 -2
  241. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss.d.ts +7 -0
  242. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -1
  243. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.module.scss.d.ts +7 -0
  244. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +1 -1
  245. package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.module.scss.d.ts +7 -0
  246. package/src/modals/SettingsModal/components/HighlightUnreachableCellsSetting/HighlightUnreachableCellsSetting.tsx +1 -1
  247. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.module.scss.d.ts +7 -0
  248. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +1 -1
  249. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss.d.ts +8 -0
  250. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +24 -21
  251. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.module.scss.d.ts +7 -0
  252. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +1 -1
  253. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.module.scss.d.ts +7 -0
  254. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +1 -5
  255. package/src/modals/WordsModal/WordsModal.module.scss.d.ts +11 -0
  256. package/src/modals/WordsModal/WordsModal.tsx +4 -2
  257. package/src/modals/preload.ts +24 -0
  258. package/src/pages/_app.tsx +5 -8
  259. package/src/pages/_document.tsx +91 -5
  260. package/src/pages/api/solve.ts +1 -1
  261. package/src/pages/index.module.scss +1 -0
  262. package/src/pages/index.module.scss.d.ts +11 -0
  263. package/src/pages/index.tsx +98 -38
  264. package/src/pages/not-found.tsx +1 -1
  265. package/src/parameters/index.ts +24 -93
  266. package/src/serviceWorkerManager.ts +5 -2
  267. package/src/state/actions.ts +1 -1
  268. package/src/state/app/index.ts +4 -0
  269. package/src/state/app/initialState.ts +6 -0
  270. package/src/state/app/selectors.ts +5 -0
  271. package/src/state/app/slice.ts +20 -0
  272. package/src/state/app/types.ts +4 -0
  273. package/src/state/board/initialState.ts +1 -2
  274. package/src/state/i18n/index.ts +4 -0
  275. package/src/state/i18n/initialState.ts +5 -0
  276. package/src/state/i18n/selectors.ts +3 -0
  277. package/src/state/i18n/slice.ts +16 -0
  278. package/src/state/i18n/types.ts +7 -0
  279. package/src/state/index.ts +2 -0
  280. package/src/state/lib.ts +1 -1
  281. package/src/state/localStorage.ts +86 -29
  282. package/src/state/rack/initialState.ts +1 -2
  283. package/src/state/rack/slice.ts +4 -1
  284. package/src/state/results/lib.ts +5 -5
  285. package/src/state/results/selectors.ts +1 -1
  286. package/src/state/sagas.ts +125 -9
  287. package/src/state/selectors.ts +1 -1
  288. package/src/state/settings/initialState.ts +7 -10
  289. package/src/state/settings/selectors.ts +7 -2
  290. package/src/state/settings/slice.ts +5 -2
  291. package/src/state/store.ts +4 -0
  292. package/src/state/types.ts +4 -0
  293. package/src/styles/_tokens.scss +1 -0
  294. package/src/styles/global.scss +9 -0
  295. package/src/styles/variables.module.scss +0 -21
  296. package/src/styles/variables.module.scss.d.ts +27 -0
  297. package/src/styles/variables.scss +46 -2
  298. package/src/types/index.ts +1 -2
  299. package/tsconfig.tsbuildinfo +1 -1
  300. package/.next/server/chunks/129.js +0 -1
  301. package/.next/server/chunks/318.js +0 -3
  302. package/.next/server/chunks/791.js +0 -15
  303. package/.next/static/OLE8_ZInlGH7ENU0NIOpf/_buildManifest.js +0 -1
  304. package/.next/static/chunks/830.661816bf0de8c2f1.js +0 -1
  305. package/.next/static/chunks/framework-3cf15b8041c59dd3.js +0 -1
  306. package/.next/static/chunks/main-5b999f3f24ebfa84.js +0 -5
  307. package/.next/static/chunks/pages/_app-7024e7a27ffbb2fa.js +0 -7
  308. package/.next/static/chunks/pages/index-8b398b0a5d870773.js +0 -1
  309. package/.next/static/chunks/pages/not-found-9e076427bad69d90.js +0 -1
  310. package/.next/static/chunks/webpack-3943d624bbb47a64.js +0 -1
  311. package/.next/static/css/a78e04fe95452380.css +0 -1
  312. package/.next/static/css/aedeaada218d7280.css +0 -2
  313. package/src/app-layout/AppLayoutContext.tsx +0 -25
  314. package/src/app-layout/index.ts +0 -1
  315. package/src/app-layout/useAppLayoutValue.ts +0 -112
  316. package/src/components/Board/hooks/useBackgroundImage.tsx +0 -279
  317. package/src/components/index.ts +0 -26
  318. package/src/hooks/index.ts +0 -12
  319. package/src/hooks/useOnWindowResize.ts +0 -11
  320. package/src/hooks/useViewportSize.ts +0 -17
  321. package/src/i18n/index.ts +0 -2
  322. package/src/icons/Flag.svg +0 -4
  323. package/src/icons/Star.svg +0 -4
  324. package/src/icons/index.ts +0 -49
  325. package/src/lib/getTileSizes.ts +0 -13
  326. package/src/lib/index.ts +0 -24
  327. package/src/modals/index.ts +0 -7
  328. /package/.next/static/{OLE8_ZInlGH7ENU0NIOpf → FL82obwzFHRzvV6z76I-U}/_ssgManifest.js +0 -0
@@ -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,
@@ -36,7 +36,7 @@ const SolverBase: FunctionComponent<Props> = ({ className, onShowResults }) => {
36
36
  const dispatch = useDispatch();
37
37
  const translate = useTranslate();
38
38
  const isTouchDevice = useIsTouchDevice();
39
- const { maxControlsWidth, showCompactControls, tileSize } = useAppLayout();
39
+ const showCompactControls = useMediaQuery('<l');
40
40
  const error = useTypedSelector(selectSolveError);
41
41
  const isOutdated = useTypedSelector(selectAreResultsOutdated);
42
42
  const results = useTypedSelector(selectProcessedResults);
@@ -113,27 +113,25 @@ const SolverBase: FunctionComponent<Props> = ({ className, onShowResults }) => {
113
113
  <div className={styles.bottomContainer}>
114
114
  <div className={styles.bottomContent}>
115
115
  <form onSubmit={handleSubmit}>
116
- <Rack className={styles.rack} tileSize={tileSize} />
116
+ <Rack />
117
117
  <input className={styles.submitInput} tabIndex={-1} type="submit" />
118
118
  </form>
119
119
 
120
- {showCompactControls && (
121
- <div className={styles.controls} style={{ maxWidth: maxControlsWidth }}>
122
- <ResultCandidatePicker onResultClick={onShowResults} />
123
-
124
- {error && (
125
- <Alert className={styles.emptyState} variant="error">
126
- {error.message}
127
- </Alert>
128
- )}
129
-
130
- {results && results.length === 0 && !isOutdated && (
131
- <Alert className={styles.emptyState} variant="warning">
132
- {translate('results.empty-state.no-results')}
133
- </Alert>
134
- )}
135
- </div>
136
- )}
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>
137
135
  </div>
138
136
  </div>
139
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,
@@ -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
 
@@ -1,25 +1,49 @@
1
- import { useEffect } from 'react';
1
+ import { useEffect, useRef } from 'react';
2
2
 
3
- import { localStorage, selectBoard, selectRack, selectSettings, useTypedSelector } from '@/state';
3
+ import { localStorage, selectBoard, selectIsHydrated, selectRack, selectSettings, useTypedSelector } from '@/state';
4
+
5
+ type WriteFlags = {
6
+ board: boolean;
7
+ rack: boolean;
8
+ settings: boolean;
9
+ };
4
10
 
5
11
  export const useLocalStorage = () => {
12
+ const isHydrated = useTypedSelector(selectIsHydrated);
6
13
  const board = useTypedSelector(selectBoard);
7
14
  const rack = useTypedSelector(selectRack);
8
15
  const settings = useTypedSelector(selectSettings);
16
+ const hasSkippedFirstWrite = useRef<WriteFlags>({
17
+ board: false,
18
+ rack: false,
19
+ settings: false,
20
+ });
9
21
 
10
22
  useEffect(() => {
11
- if (board) {
23
+ if (isHydrated && board && !isFirstWriteAfterHydration(hasSkippedFirstWrite.current, 'board')) {
12
24
  localStorage.setBoard(board);
13
25
  }
14
- }, [board]);
26
+ }, [isHydrated, board]);
15
27
 
16
28
  useEffect(() => {
17
- if (rack) {
29
+ if (isHydrated && rack && !isFirstWriteAfterHydration(hasSkippedFirstWrite.current, 'rack')) {
18
30
  localStorage.setRack(rack);
19
31
  }
20
- }, [rack]);
32
+ }, [isHydrated, rack]);
21
33
 
22
34
  useEffect(() => {
23
- localStorage.setSettings(settings);
24
- }, [settings]);
35
+ if (isHydrated && !isFirstWriteAfterHydration(hasSkippedFirstWrite.current, 'settings')) {
36
+ localStorage.setSettings(settings);
37
+ }
38
+ }, [isHydrated, settings]);
25
39
  };
40
+
41
+ // Each effect's first post-hydration run would only write back what hydration just read, so it is skipped
42
+ function isFirstWriteAfterHydration(flags: WriteFlags, key: keyof WriteFlags): boolean {
43
+ if (flags[key]) {
44
+ return false;
45
+ }
46
+
47
+ flags[key] = true;
48
+ return true;
49
+ }
@@ -1,34 +1,34 @@
1
- import { useEffect, useState } from 'react';
1
+ import { useCallback, useSyncExternalStore } from 'react';
2
2
 
3
- const getInitialState = (query: string, defaultState?: boolean) => {
4
- if (typeof defaultState !== 'undefined') {
5
- return defaultState;
6
- }
7
-
8
- if (typeof window === 'undefined') {
9
- return false;
10
- }
3
+ export const useMedia = (query: string, defaultState = false) => {
4
+ const subscribe = useCallback(
5
+ (onChange: () => void) => {
6
+ const mediaQueryList = getMediaQueryList(query);
7
+ mediaQueryList.addEventListener('change', onChange);
11
8
 
12
- return window.matchMedia(query).matches;
13
- };
9
+ return () => {
10
+ mediaQueryList.removeEventListener('change', onChange);
11
+ };
12
+ },
13
+ [query],
14
+ );
14
15
 
15
- export const useMedia = (query: string, defaultState?: boolean) => {
16
- const [state, setState] = useState(getInitialState(query, defaultState));
16
+ const getSnapshot = useCallback(() => getMediaQueryList(query).matches, [query]);
17
+ const getServerSnapshot = useCallback(() => defaultState, [defaultState]);
17
18
 
18
- useEffect(() => {
19
- const mediaQuery = window.matchMedia(query);
19
+ return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
20
+ };
20
21
 
21
- const handleChange = () => {
22
- setState(mediaQuery.matches);
23
- };
22
+ // cache because matchMedia returns a new MediaQueryList on every call
23
+ const mediaQueryLists = new Map<string, MediaQueryList>();
24
24
 
25
- setState(mediaQuery.matches);
26
- mediaQuery.addEventListener('change', handleChange);
25
+ function getMediaQueryList(query: string): MediaQueryList {
26
+ let mediaQueryList = mediaQueryLists.get(query);
27
27
 
28
- return () => {
29
- mediaQuery.removeEventListener('change', handleChange);
30
- };
31
- }, [query]);
28
+ if (!mediaQueryList) {
29
+ mediaQueryList = window.matchMedia(query);
30
+ mediaQueryLists.set(query, mediaQueryList);
31
+ }
32
32
 
33
- return state;
34
- };
33
+ return mediaQueryList;
34
+ }
@@ -1,14 +1,10 @@
1
1
  import { COMMA_ARABIC, COMMA_LATIN } from '@scrabble-solver/constants';
2
- import { Locale } from '@scrabble-solver/types';
3
- import { type FunctionComponent, type SVGAttributes } from 'react';
4
-
5
- import { FlagDe, FlagEs, FlagFa, FlagFr, FlagGb, FlagPl, FlagRo, FlagTr, FlagUs } from '@/icons';
2
+ import { Locale, type TextDirection } from '@scrabble-solver/types';
6
3
 
7
4
  interface LocaleFeatures {
8
5
  comma: string;
9
6
  consonants: boolean;
10
- direction: 'ltr' | 'rtl';
11
- Icon: FunctionComponent<SVGAttributes<SVGElement>>;
7
+ direction: TextDirection;
12
8
  label: string;
13
9
  locale: Locale;
14
10
  name: string;
@@ -21,7 +17,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
21
17
  comma: COMMA_LATIN,
22
18
  consonants: true,
23
19
  direction: 'ltr',
24
- Icon: FlagDe,
25
20
  label: 'Deutsch',
26
21
  locale: Locale.DE_DE,
27
22
  name: 'German',
@@ -32,7 +27,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
32
27
  comma: COMMA_LATIN,
33
28
  consonants: true,
34
29
  direction: 'ltr',
35
- Icon: FlagGb,
36
30
  label: 'English (GB)',
37
31
  locale: Locale.EN_GB,
38
32
  name: 'English (GB)',
@@ -43,7 +37,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
43
37
  comma: COMMA_LATIN,
44
38
  consonants: true,
45
39
  direction: 'ltr',
46
- Icon: FlagUs,
47
40
  label: 'English (US)',
48
41
  locale: Locale.EN_US,
49
42
  name: 'English (US)',
@@ -54,7 +47,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
54
47
  comma: COMMA_LATIN,
55
48
  consonants: true,
56
49
  direction: 'ltr',
57
- Icon: FlagEs,
58
50
  label: 'Español',
59
51
  locale: Locale.ES_ES,
60
52
  name: 'Spanish',
@@ -65,7 +57,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
65
57
  comma: COMMA_ARABIC,
66
58
  consonants: false,
67
59
  direction: 'rtl',
68
- Icon: FlagFa,
69
60
  label: 'فارسی',
70
61
  locale: Locale.FA_IR,
71
62
  name: 'Persian',
@@ -76,7 +67,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
76
67
  comma: COMMA_LATIN,
77
68
  consonants: true,
78
69
  direction: 'ltr',
79
- Icon: FlagFr,
80
70
  label: 'Français',
81
71
  locale: Locale.FR_FR,
82
72
  name: 'French',
@@ -87,7 +77,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
87
77
  comma: COMMA_LATIN,
88
78
  consonants: true,
89
79
  direction: 'ltr',
90
- Icon: FlagPl,
91
80
  label: 'Polski',
92
81
  locale: Locale.PL_PL,
93
82
  name: 'Polish',
@@ -98,7 +87,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
98
87
  comma: COMMA_LATIN,
99
88
  consonants: true,
100
89
  direction: 'ltr',
101
- Icon: FlagRo,
102
90
  label: 'Română',
103
91
  locale: Locale.RO_RO,
104
92
  name: 'Romanian',
@@ -109,7 +97,6 @@ export const LOCALE_FEATURES: Record<Locale, LocaleFeatures> = {
109
97
  comma: COMMA_LATIN,
110
98
  consonants: true,
111
99
  direction: 'ltr',
112
- Icon: FlagTr,
113
100
  label: 'Türkçe',
114
101
  locale: Locale.TR_TR,
115
102
  name: 'Turkish',