@scrabble-solver/scrabble-solver 2.15.11 → 2.15.13

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 (309) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +16 -16
  3. package/.next/cache/.previewinfo +1 -0
  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/0.pack +0 -0
  10. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  11. package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  12. package/.next/cache/webpack/server-production/0.pack +0 -0
  13. package/.next/cache/webpack/server-production/index.pack +0 -0
  14. package/.next/cache/webpack/server-production/index.pack.old +0 -0
  15. package/.next/diagnostics/framework.json +1 -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/required-server-files.json +23 -12
  20. package/.next/routes-manifest.json +7 -3
  21. package/.next/server/chunks/106.js +1 -0
  22. package/.next/server/chunks/30.js +4 -4
  23. package/.next/server/chunks/318.js +1 -0
  24. package/.next/server/chunks/50.js +19 -0
  25. package/.next/server/chunks/812.js +1 -1
  26. package/.next/server/chunks/929.js +1 -0
  27. package/.next/server/chunks/974.js +1 -1
  28. package/.next/server/middleware-build-manifest.js +1 -1
  29. package/.next/server/pages/404.html +1 -1
  30. package/.next/server/pages/404.js.nft.json +1 -1
  31. package/.next/server/pages/500.html +1 -1
  32. package/.next/server/pages/_app.js +1 -1
  33. package/.next/server/pages/_app.js.nft.json +1 -1
  34. package/.next/server/pages/_document.js +1 -1
  35. package/.next/server/pages/_document.js.nft.json +1 -1
  36. package/.next/server/pages/_error.js +1 -1
  37. package/.next/server/pages/_error.js.nft.json +1 -1
  38. package/.next/server/pages/api/dictionary/[locale]/[word].js +2 -2
  39. package/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  40. package/.next/server/pages/api/dictionary/[locale].js +1 -1
  41. package/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  42. package/.next/server/pages/api/solve.js +1 -1
  43. package/.next/server/pages/api/solve.js.nft.json +1 -1
  44. package/.next/server/pages/api/verify.js +1 -1
  45. package/.next/server/pages/api/verify.js.nft.json +1 -1
  46. package/.next/server/pages/api/visit.js +1 -1
  47. package/.next/server/pages/api/visit.js.nft.json +1 -1
  48. package/.next/server/pages/index.html +1 -1
  49. package/.next/server/pages/index.js +1 -1
  50. package/.next/server/pages/index.js.nft.json +1 -1
  51. package/.next/server/pages/index.json +1 -1
  52. package/.next/server/pages-manifest.json +1 -1
  53. package/.next/server/webpack-api-runtime.js +1 -1
  54. package/.next/server/webpack-runtime.js +1 -1
  55. package/.next/static/{47JHul8F9NSWCNSEuahuL → MhrqAqLI9_L8obb7tgjvi}/_buildManifest.js +1 -1
  56. package/.next/static/chunks/framework-aad31c68dd0bb0ea.js +1 -0
  57. package/.next/static/chunks/main-eab5847b41f0af4a.js +1 -0
  58. package/.next/static/chunks/pages/{404-590e2a3839c1d9e0.js → 404-04457ede98c6b53e.js} +1 -1
  59. package/.next/static/chunks/pages/_app-bf81f201c021fdc1.js +1 -0
  60. package/.next/static/chunks/pages/{_error-7ea2d37f66343175.js → _error-a9800cedd835bcad.js} +1 -1
  61. package/.next/static/chunks/pages/index-79a390f3c2a2499f.js +1 -0
  62. package/.next/static/css/{6682db14f926d4c7.css → 04a3767982ec10e8.css} +1 -1
  63. package/.next/static/css/{d875648f38121a28.css → 1fae874a25934f54.css} +1 -1
  64. package/.next/trace +24 -23
  65. package/coverage/clover.xml +6 -0
  66. package/coverage/coverage-final.json +1 -0
  67. package/coverage/lcov-report/base.css +224 -0
  68. package/coverage/lcov-report/block-navigation.js +87 -0
  69. package/coverage/lcov-report/favicon.png +0 -0
  70. package/coverage/lcov-report/index.html +101 -0
  71. package/coverage/lcov-report/prettify.css +1 -0
  72. package/coverage/lcov-report/prettify.js +2 -0
  73. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  74. package/coverage/lcov-report/sorter.js +196 -0
  75. package/coverage/lcov.info +0 -0
  76. package/package.json +18 -18
  77. package/src/api/getServerLoggingData.ts +1 -1
  78. package/src/api/isBoardValid.ts +1 -1
  79. package/src/api/isCellValid.ts +1 -1
  80. package/src/api/isRowValid.ts +1 -1
  81. package/src/components/Alert/Alert.tsx +1 -1
  82. package/src/components/Badge/Badge.tsx +1 -1
  83. package/src/components/Board/Board.tsx +8 -8
  84. package/src/components/Board/BoardPure.tsx +11 -11
  85. package/src/components/Board/components/Actions/Actions.tsx +3 -3
  86. package/src/components/Board/components/Actions/lib.ts +3 -3
  87. package/src/components/Board/components/Cell/Cell.tsx +7 -7
  88. package/src/components/Board/components/InputPrompt/InputPrompt.tsx +2 -2
  89. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +2 -2
  90. package/src/components/Board/hooks/useBackgroundImage.tsx +1 -1
  91. package/src/components/Board/hooks/useBoardStyle.ts +1 -1
  92. package/src/components/Board/hooks/useGrid.ts +13 -13
  93. package/src/components/Board/lib.ts +37 -0
  94. package/src/components/Board/selectors.ts +8 -0
  95. package/src/components/Button/Button.tsx +1 -1
  96. package/src/components/Button/Link.tsx +1 -1
  97. package/src/components/Dictionary/Dictionary.tsx +10 -3
  98. package/src/components/DictionaryInput/DictionaryInput.tsx +1 -1
  99. package/src/components/EmptyState/EmptyState.tsx +3 -3
  100. package/src/components/IconButton/IconButton.tsx +1 -1
  101. package/src/components/IconButton/Link.tsx +1 -1
  102. package/src/components/Key/Key.tsx +1 -1
  103. package/src/components/Keys/Arrows/Arrows.tsx +1 -1
  104. package/src/components/Keys/index.tsx +1 -1
  105. package/src/components/Loading/Loading.tsx +6 -8
  106. package/src/components/Logo/LogoBlueprint.tsx +1 -1
  107. package/src/components/Modal/Modal.tsx +4 -2
  108. package/src/components/Modal/components/Section/Section.tsx +1 -1
  109. package/src/components/NavButtons/NavButtons.tsx +4 -3
  110. package/src/components/NavButtons/selectors.ts +11 -0
  111. package/src/components/NotFound/NotFound.tsx +1 -1
  112. package/src/components/PlainTiles/PlainTiles.tsx +1 -1
  113. package/src/components/PlainTiles/Tile.tsx +1 -1
  114. package/src/components/PlainTiles/lib.ts +90 -0
  115. package/src/components/Progress/Progress.tsx +1 -1
  116. package/src/components/Rack/Rack.tsx +10 -26
  117. package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +5 -8
  118. package/src/components/Rack/components/InputPrompt/lib.test.ts +27 -0
  119. package/src/components/Rack/components/InputPrompt/lib.ts +19 -0
  120. package/src/components/Rack/components/RackTile/RackTile.tsx +9 -9
  121. package/src/components/Rack/selectors.ts +9 -0
  122. package/src/components/Radio/Radio.tsx +1 -1
  123. package/src/components/Results/Cell.tsx +2 -2
  124. package/src/components/Results/Header.tsx +1 -1
  125. package/src/components/Results/HeaderButton.tsx +2 -2
  126. package/src/components/Results/Result.tsx +5 -6
  127. package/src/components/Results/Results.tsx +6 -6
  128. package/src/components/Results/SolveButton.tsx +3 -3
  129. package/src/components/Results/types.ts +2 -2
  130. package/src/components/ResultsInput/ResultsInput.tsx +1 -1
  131. package/src/components/SeoMessage/SeoMessage.tsx +1 -1
  132. package/src/components/Solver/Solver.tsx +4 -4
  133. package/src/components/Solver/components/InsertButton/InsertButton.tsx +1 -1
  134. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +5 -5
  135. package/src/components/Spinner/Spinner.tsx +1 -1
  136. package/src/components/Tile/Tile.tsx +7 -7
  137. package/src/components/Tile/TilePure.tsx +8 -8
  138. package/src/components/Tooltip/Tooltip.tsx +1 -1
  139. package/src/components/Tooltip/TooltipContent.tsx +1 -1
  140. package/src/components/Tooltip/TooltipTrigger.tsx +1 -1
  141. package/src/components/Tooltip/context.ts +1 -1
  142. package/src/components/Tooltip/useTooltip.ts +1 -1
  143. package/src/hooks/useAppLayout.ts +1 -1
  144. package/src/hooks/useColumns.ts +28 -1
  145. package/src/hooks/useEffectOnce.ts +1 -1
  146. package/src/hooks/useLocalStorage.ts +8 -0
  147. package/src/i18n/constants.ts +1 -1
  148. package/src/i18n/i18n.ts +1 -1
  149. package/src/i18n/languages/english.json +3 -0
  150. package/src/i18n/languages/french.json +3 -0
  151. package/src/i18n/languages/german.json +3 -0
  152. package/src/i18n/languages/persian.json +3 -0
  153. package/src/i18n/languages/polish.json +3 -0
  154. package/src/i18n/languages/romanian.json +3 -0
  155. package/src/i18n/languages/spanish.json +3 -0
  156. package/src/i18n/languages/turkish.json +3 -0
  157. package/src/lib/createComparator.ts +1 -1
  158. package/src/lib/createKeyComparator.ts +1 -1
  159. package/src/lib/createKeyboardNavigation.ts +1 -1
  160. package/src/lib/createStringComparator.ts +1 -1
  161. package/src/lib/extractCharacters.test.ts +42 -15
  162. package/src/lib/extractCharacters.ts +27 -25
  163. package/src/lib/findCell.ts +1 -1
  164. package/src/lib/index.ts +2 -17
  165. package/src/lib/isCtrl.ts +1 -1
  166. package/src/lib/localeTransliterate.test.ts +14 -0
  167. package/src/lib/localeTransliterate.ts +18 -0
  168. package/src/lib/numberComparator.ts +1 -1
  169. package/src/lib/reverseComparator.ts +1 -1
  170. package/src/lib/zipCharactersAndTiles.ts +2 -2
  171. package/src/modals/DictionaryModal/DictionaryModal.tsx +1 -1
  172. package/src/modals/KeyMapModal/KeyMapModal.tsx +1 -1
  173. package/src/modals/KeyMapModal/components/Mapping/Mapping.tsx +1 -1
  174. package/src/modals/MenuModal/MenuModal.tsx +1 -1
  175. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +3 -2
  176. package/src/modals/RemainingTilesModal/components/Character/Character.tsx +2 -2
  177. package/src/{lib/getRemainingTilesGroups.ts → modals/RemainingTilesModal/lib.ts} +26 -9
  178. package/src/modals/RemainingTilesModal/selectors.ts +7 -0
  179. package/src/modals/ResultsModal/ResultsModal.tsx +4 -4
  180. package/src/modals/SettingsModal/SettingsModal.tsx +6 -1
  181. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -1
  182. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/lib.ts +1 -1
  183. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +1 -1
  184. package/src/modals/SettingsModal/components/ConfigSetting/lib.ts +1 -1
  185. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +1 -1
  186. package/src/modals/SettingsModal/components/InputModeSetting/lib.ts +1 -1
  187. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +2 -2
  188. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.module.scss +12 -0
  189. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +53 -0
  190. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/index.ts +1 -0
  191. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/lib.ts +13 -0
  192. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +2 -2
  193. package/src/modals/SettingsModal/components/index.ts +1 -0
  194. package/src/modals/WordsModal/WordsModal.tsx +4 -3
  195. package/src/pages/_app.tsx +2 -2
  196. package/src/pages/_document.tsx +1 -1
  197. package/src/pages/api/dictionary/[locale]/[word].ts +2 -2
  198. package/src/pages/api/dictionary/[locale]/index.ts +2 -2
  199. package/src/pages/api/solve.ts +11 -2
  200. package/src/pages/api/verify.ts +2 -2
  201. package/src/pages/api/visit.ts +1 -1
  202. package/src/pages/index.tsx +34 -43
  203. package/src/parameters/index.ts +1 -0
  204. package/src/sdk/findWordDefinitions.ts +1 -1
  205. package/src/sdk/getDictionary.ts +1 -1
  206. package/src/sdk/solve.ts +1 -1
  207. package/src/sdk/verify.ts +1 -1
  208. package/src/service-worker/dictionaries/getDictionary.ts +1 -1
  209. package/src/service-worker/dictionaries/getDictionaryUrl.ts +1 -1
  210. package/src/service-worker/dictionaries/revalidateDictionary.ts +1 -1
  211. package/src/service-worker/getTrie.ts +1 -1
  212. package/src/service-worker/routeSolveRequests.ts +2 -2
  213. package/src/service-worker/routeVerifyRequests.ts +1 -1
  214. package/src/state/board/index.ts +4 -0
  215. package/src/state/{slices/boardInitialState.ts → board/initialState.ts} +3 -6
  216. package/src/state/board/selectors.ts +3 -0
  217. package/src/state/{slices/boardSlice.ts → board/slice.ts} +5 -4
  218. package/src/state/board/types.ts +3 -0
  219. package/src/state/cellFilters/index.ts +4 -0
  220. package/src/state/cellFilters/initialState.ts +3 -0
  221. package/src/state/cellFilters/lib.ts +8 -0
  222. package/src/state/cellFilters/selectors.ts +13 -0
  223. package/src/state/{slices/cellFilterSlice.ts → cellFilters/slice.ts} +15 -14
  224. package/src/state/cellFilters/types.ts +3 -0
  225. package/src/state/dictionary/index.ts +4 -0
  226. package/src/state/dictionary/initialState.ts +8 -0
  227. package/src/state/dictionary/selectors.ts +16 -0
  228. package/src/state/{slices/dictionarySlice.ts → dictionary/slice.ts} +3 -3
  229. package/src/state/dictionary/types.ts +8 -0
  230. package/src/state/index.ts +12 -5
  231. package/src/{lib/getRemainingTiles.ts → state/lib.ts} +3 -4
  232. package/src/state/localStorage.ts +11 -2
  233. package/src/state/rack/index.ts +4 -0
  234. package/src/state/rack/initialState.ts +12 -0
  235. package/src/state/rack/selectors.ts +7 -0
  236. package/src/state/{slices/rackSlice.ts → rack/slice.ts} +4 -4
  237. package/src/state/rack/types.ts +3 -0
  238. package/src/state/results/index.ts +4 -0
  239. package/src/state/results/initialState.ts +13 -0
  240. package/src/state/results/lib.ts +96 -0
  241. package/src/state/results/selectors.ts +75 -0
  242. package/src/state/{slices/resultsSlice.ts → results/slice.ts} +4 -4
  243. package/src/state/results/types.ts +10 -0
  244. package/src/state/sagas.ts +22 -23
  245. package/src/state/selectors.ts +15 -235
  246. package/src/state/settings/index.ts +4 -0
  247. package/src/state/{slices/settingsInitialState.ts → settings/initialState.ts} +4 -11
  248. package/src/state/settings/lib.ts +42 -0
  249. package/src/state/settings/selectors.ts +69 -0
  250. package/src/state/{slices/settingsSlice.ts → settings/slice.ts} +9 -4
  251. package/src/state/settings/types.ts +12 -0
  252. package/src/state/solve/index.ts +4 -0
  253. package/src/state/solve/initialState.ts +12 -0
  254. package/src/state/solve/selectors.ts +14 -0
  255. package/src/state/{slices/solveSlice.ts → solve/slice.ts} +3 -3
  256. package/src/state/solve/types.ts +10 -0
  257. package/src/state/store.ts +9 -11
  258. package/src/state/types.ts +16 -18
  259. package/src/state/useTranslate.ts +2 -2
  260. package/src/state/useTypedSelector.ts +2 -2
  261. package/src/state/verify/index.ts +4 -0
  262. package/src/state/verify/initialState.ts +12 -0
  263. package/src/state/verify/selectors.ts +9 -0
  264. package/src/state/{slices/verifySlice.ts → verify/slice.ts} +3 -3
  265. package/src/state/verify/types.ts +10 -0
  266. package/src/styles/global.scss +5 -0
  267. package/src/types/api.ts +1 -1
  268. package/src/types/index.ts +8 -3
  269. package/tsconfig.tsbuildinfo +1 -1
  270. package/.eslintrc.js +0 -10
  271. package/.next/server/chunks/60.js +0 -1
  272. package/.next/server/chunks/968.js +0 -1
  273. package/.next/static/chunks/framework-288d1abd95de88d9.js +0 -1
  274. package/.next/static/chunks/main-016492249b3393e2.js +0 -1
  275. package/.next/static/chunks/pages/_app-0e951de0aebb6505.js +0 -1
  276. package/.next/static/chunks/pages/index-c1d5a66d0f4794a6.js +0 -1
  277. package/src/components/Board/lib/getBonusColor.ts +0 -16
  278. package/src/components/Board/lib/getPositionInGrid.ts +0 -13
  279. package/src/components/Board/lib/index.ts +0 -2
  280. package/src/components/PlainTiles/lib/createPlainTile.ts +0 -41
  281. package/src/components/PlainTiles/lib/createPlainTiles.ts +0 -25
  282. package/src/components/PlainTiles/lib/getViewbox.ts +0 -17
  283. package/src/components/PlainTiles/lib/getX.ts +0 -5
  284. package/src/components/PlainTiles/lib/getY.ts +0 -5
  285. package/src/components/PlainTiles/lib/index.ts +0 -6
  286. package/src/components/PlainTiles/lib/randomize.ts +0 -1
  287. package/src/lib/createArray.ts +0 -1
  288. package/src/lib/createGridOf.ts +0 -9
  289. package/src/lib/detectLocale.ts +0 -27
  290. package/src/lib/extractCharactersByCase.test.ts +0 -29
  291. package/src/lib/extractCharactersByCase.ts +0 -29
  292. package/src/lib/getCellSize.ts +0 -10
  293. package/src/lib/getCoordinates.ts +0 -16
  294. package/src/lib/getRemainingTilesCount.ts +0 -11
  295. package/src/lib/getTotalRemainingTilesCount.ts +0 -11
  296. package/src/lib/groupResults.ts +0 -35
  297. package/src/lib/guessLocale.ts +0 -20
  298. package/src/lib/isUpperCase.ts +0 -5
  299. package/src/lib/resultMatchesCellFilter.ts +0 -21
  300. package/src/lib/sortGroupedResults.ts +0 -21
  301. package/src/lib/sortResults.ts +0 -41
  302. package/src/state/slices/cellFilterInitialState.ts +0 -5
  303. package/src/state/slices/dictionaryInitialState.ts +0 -15
  304. package/src/state/slices/index.ts +0 -16
  305. package/src/state/slices/rackInitialState.ts +0 -9
  306. package/src/state/slices/resultsInitialState.ts +0 -20
  307. package/src/state/slices/solveInitialState.ts +0 -21
  308. package/src/state/slices/verifyInitialState.ts +0 -19
  309. /package/.next/static/{47JHul8F9NSWCNSEuahuL → MhrqAqLI9_L8obb7tgjvi}/_ssgManifest.js +0 -0
@@ -1,255 +1,35 @@
1
- /* eslint-disable max-lines */
2
-
3
1
  import { createSelector } from '@reduxjs/toolkit';
4
- import { getConfig } from '@scrabble-solver/configs';
5
- import { BLANK } from '@scrabble-solver/constants';
6
- import { Cell, Config, isError, Tile } from '@scrabble-solver/types';
7
-
8
- import { i18n, LOCALE_FEATURES } from 'i18n';
9
- import {
10
- createRegExp,
11
- findCell,
12
- getRemainingTiles,
13
- getRemainingTilesGroups,
14
- groupResults,
15
- resultMatchesCellFilter,
16
- sortGroupedResults,
17
- unorderedArraysEqual,
18
- } from 'lib';
19
- import { Point, ResultColumnId, Translations } from 'types';
20
-
21
- import { RootState } from './types';
22
-
23
- const selectCell = (_: unknown, cell: Cell): Cell => cell;
24
-
25
- const selectPoint = (_: unknown, point: Point): Point => point;
26
-
27
- const selectResultIndex = (_: unknown, index: number): number => index;
28
-
29
- const selectCharacter = (_: unknown, character: string | null): string | null => character;
30
-
31
- const selectTile = (_: unknown, tile: Tile | null): Tile | null => tile;
32
-
33
- const selectBoardRoot = (state: RootState): RootState['board'] => state.board;
34
-
35
- const selectDictionaryRoot = (state: RootState): RootState['dictionary'] => state.dictionary;
36
-
37
- const selectCellFilterRoot = (state: RootState): RootState['cellFilter'] => state.cellFilter;
38
-
39
- const selectRackRoot = (state: RootState): RootState['rack'] => state.rack;
40
-
41
- const selectResultsRoot = (state: RootState): RootState['results'] => state.results;
42
-
43
- const selectSettingsRoot = (state: RootState): RootState['settings'] => state.settings;
44
-
45
- const selectSolveRoot = (state: RootState): RootState['solve'] => state.solve;
46
-
47
- const selectVerifyRoot = (state: RootState): RootState['verify'] => state.verify;
48
-
49
- export const selectDictionary = selectDictionaryRoot;
50
-
51
- export const selectDictionaryError = createSelector([selectDictionaryRoot], (dictionary) => {
52
- return isError(dictionary.error) ? dictionary.error : undefined;
53
- });
54
-
55
- export const selectLocale = createSelector([selectSettingsRoot], (settings) => settings.locale);
56
-
57
- export const selectAutoGroupTiles = createSelector([selectSettingsRoot], (settings) => settings.autoGroupTiles);
58
-
59
- export const selectLocaleAutoGroupTiles = createSelector([selectLocale, selectSettingsRoot], (locale, settings) => {
60
- if (LOCALE_FEATURES[locale].direction === 'ltr' || settings.autoGroupTiles === null) {
61
- return settings.autoGroupTiles;
62
- }
63
-
64
- return settings.autoGroupTiles === 'left' ? 'right' : 'left';
65
- });
66
-
67
- export const selectBoard = selectBoardRoot;
68
-
69
- export const selectInputMode = createSelector([selectSettingsRoot], (settings) => settings.inputMode);
70
-
71
- export const selectShowCoordinates = createSelector([selectSettingsRoot], (settings) => settings.showCoordinates);
72
-
73
- export const selectGame = createSelector([selectSettingsRoot], (settings) => settings.game);
74
-
75
- export const selectConfig = createSelector([selectGame, selectLocale], getConfig);
76
-
77
- export const selectFilteredCells = selectCellFilterRoot;
78
-
79
- export const selectCellFilter = createSelector([selectFilteredCells, selectPoint], (cellFilter, { x, y }) => {
80
- return cellFilter.find((cell) => cell.x === x && cell.y === y);
81
- });
82
-
83
- export const selectCellIsValid = createSelector([selectConfig, selectCell], (config, cell) => {
84
- if (!cell.hasTile()) {
85
- return true;
86
- }
87
-
88
- return config.tiles.some((tile) => tile.character === cell.tile.character);
89
- });
90
-
91
- export const selectResultsRaw = createSelector([selectResultsRoot], (results) => results.results);
92
-
93
- export const selectResultsQuery = createSelector([selectResultsRoot], (results) => results.query);
94
-
95
- export const selectResultsSort = createSelector([selectResultsRoot], (results) => results.sort);
96
-
97
- export const selectGroupedResults = createSelector(
98
- [selectResultsRaw, selectResultsQuery, selectFilteredCells],
99
- groupResults,
100
- );
101
-
102
- export const selectGroupedSortedResults = createSelector(
103
- [selectGroupedResults, selectResultsSort, selectLocale, selectShowCoordinates],
104
- sortGroupedResults,
105
- );
106
-
107
- export const selectResults = createSelector([selectGroupedSortedResults], (groupedResults) => {
108
- return groupedResults ? [...groupedResults.matching, ...groupedResults.other] : groupedResults;
109
- });
110
2
 
111
- export const selectIsResultMatching = createSelector(
112
- [selectResults, selectResultsQuery, selectFilteredCells, selectResultIndex],
113
- (results, query, cellFilter, index) => {
114
- if (!results) {
115
- return false;
116
- }
3
+ import { unorderedArraysEqual } from 'lib';
117
4
 
118
- const result = results[index];
119
- const regExp = createRegExp(query);
5
+ import { selectBoard } from './board';
6
+ import { getRemainingTiles } from './lib';
7
+ import { selectCharacters } from './rack';
8
+ import { selectConfig, selectLocale } from './settings';
9
+ import { selectLastSolvedParameters } from './solve';
120
10
 
121
- if (!regExp.test(result.word)) {
122
- return false;
123
- }
124
-
125
- return resultMatchesCellFilter(result, cellFilter);
126
- },
127
- );
128
-
129
- export const selectResultCandidate = createSelector([selectResultsRoot], (results) => results.candidate);
130
-
131
- export const selectResultCandidateCells = createSelector(
132
- [selectResultCandidate],
133
- (resultCandidate): Cell[] => resultCandidate?.cells || [],
134
- );
135
-
136
- export const selectResultCandidateTiles = createSelector(
137
- [selectResultCandidate],
138
- (resultCandidate): Tile[] => resultCandidate?.tiles || [],
139
- );
140
-
141
- export const selectRowsWithCandidate = createSelector([selectBoardRoot, selectResultCandidateCells], (board, cells) => {
142
- return board.rows.map((row: Cell[], y: number) => row.map((cell: Cell, x: number) => findCell(cells, x, y) || cell));
143
- });
144
-
145
- export const selectCellBonus = createSelector([selectConfig, selectCell], (config: Config, cell: Cell) => {
146
- return config.getCellBonus(cell);
147
- });
148
-
149
- export const selectCharacterPoints = createSelector(
150
- [selectConfig, selectCharacter],
151
- (config: Config, character: string | null) => {
152
- return config.getCharacterPoints(character);
153
- },
154
- );
155
-
156
- export const selectCharacterIsValid = createSelector(
157
- [selectConfig, selectCharacter],
158
- (config: Config, character: string | null) => {
159
- if (character === null || character === BLANK) {
160
- return true;
161
- }
162
-
163
- return config.tiles.some((tile) => tile.character === character);
11
+ const selectHasBoardChanged = createSelector(
12
+ [selectLastSolvedParameters, selectBoard],
13
+ (lastSolvedParameters, board) => {
14
+ return !lastSolvedParameters.board.equals(board);
164
15
  },
165
16
  );
166
17
 
167
- export const selectTilePoints = createSelector([selectConfig, selectTile], (config: Config, tile: Tile | null) => {
168
- return config.getTilePoints(tile);
169
- });
170
-
171
- export const selectTranslations = createSelector([selectLocale], (locale) => i18n[locale]);
172
-
173
- export const selectTranslation = createSelector(
174
- [selectTranslations, selectLocale, (_: unknown, id: keyof Translations) => id],
175
- (translations, locale, id): string => {
176
- const translation = translations[id];
177
-
178
- if (typeof translation === 'undefined') {
179
- throw new Error(`Untranslated key "${id}" in locale "${locale}"`);
180
- }
181
-
182
- return translation;
183
- },
184
- );
185
-
186
- export const selectRack = selectRackRoot;
187
-
188
- export const selectCharacters = createSelector(selectRackRoot, (rack) => rack.filter((tile) => tile !== null));
189
-
190
- export const selectLastSolvedParameters = createSelector([selectSolveRoot], (solve) => solve.lastSolvedParameters);
191
-
192
- export const selectIsLoading = createSelector([selectSolveRoot], (solve) => solve.isLoading);
193
-
194
- export const selectSolveError = createSelector([selectSolveRoot], (solve) => {
195
- return isError(solve.error) ? solve.error : undefined;
196
- });
197
-
198
- export const selectHaveCharactersChanged = createSelector(
18
+ const selectHaveCharactersChanged = createSelector(
199
19
  [selectLastSolvedParameters, selectCharacters, selectLocale],
200
20
  (lastSolvedParameters, characters, locale) => {
201
21
  return !unorderedArraysEqual(lastSolvedParameters.characters, characters, locale);
202
22
  },
203
23
  );
204
24
 
205
- export const selectHasBoardChanged = createSelector(
206
- [selectLastSolvedParameters, selectBoardRoot],
207
- (lastSolvedParameters, board) => !lastSolvedParameters.board.equals(board),
208
- );
209
-
210
25
  export const selectAreResultsOutdated = createSelector(
211
26
  [selectHasBoardChanged, selectHaveCharactersChanged],
212
- (hasBoardChanged, haveCharactersChanged) => hasBoardChanged || haveCharactersChanged,
27
+ (hasBoardChanged, haveCharactersChanged) => {
28
+ return hasBoardChanged || haveCharactersChanged;
29
+ },
213
30
  );
214
31
 
215
32
  export const selectRemainingTiles = createSelector(
216
- [selectConfig, selectBoardRoot, selectCharacters, selectLocale],
33
+ [selectConfig, selectBoard, selectCharacters, selectLocale],
217
34
  getRemainingTiles,
218
35
  );
219
-
220
- export const selectHasOverusedTiles = createSelector([selectRemainingTiles], (remainingTiles) => {
221
- return remainingTiles.some(({ count = 0, usedCount }) => usedCount > count);
222
- });
223
-
224
- export const selectRemainingTilesGroups = createSelector([selectRemainingTiles], getRemainingTilesGroups);
225
-
226
- export const selectVerify = selectVerifyRoot;
227
-
228
- export const selectHasInvalidWords = createSelector([selectVerify], ({ invalidWords }) => {
229
- return invalidWords.length > 0;
230
- });
231
-
232
- export const selectColumns = createSelector([selectLocale, selectShowCoordinates], (locale, showCoordinates) => {
233
- const { consonants, vowels } = LOCALE_FEATURES[locale];
234
- const columns: ResultColumnId[] = [
235
- ResultColumnId.Word,
236
- ResultColumnId.TilesCount,
237
- ResultColumnId.BlanksCount,
238
- ResultColumnId.WordsCount,
239
- ResultColumnId.Points,
240
- ];
241
-
242
- if (showCoordinates !== 'hidden') {
243
- columns.push(ResultColumnId.Coordinates);
244
- }
245
-
246
- if (vowels) {
247
- columns.push(ResultColumnId.VowelsCount);
248
- }
249
-
250
- if (consonants) {
251
- columns.push(ResultColumnId.ConsonantsCount);
252
- }
253
-
254
- return columns;
255
- });
@@ -0,0 +1,4 @@
1
+ export * from './initialState';
2
+ export * from './selectors';
3
+ export * from './slice';
4
+ export * from './types';
@@ -1,17 +1,9 @@
1
- import { Game, Locale, ShowCoordinates } from '@scrabble-solver/types';
2
-
3
- import { guessLocale } from 'lib';
4
- import { AutoGroupTiles, InputMode } from 'types';
1
+ import { Game } from '@scrabble-solver/types';
5
2
 
6
3
  import { localStorage } from '../localStorage';
7
4
 
8
- export interface SettingsState {
9
- autoGroupTiles: AutoGroupTiles;
10
- game: Game;
11
- inputMode: InputMode;
12
- locale: Locale;
13
- showCoordinates: ShowCoordinates;
14
- }
5
+ import { guessLocale } from './lib';
6
+ import type { SettingsState } from './types';
15
7
 
16
8
  const localStorageAutoGroupTiles = localStorage.getAutoGroupTiles();
17
9
  const isTouchScreen = typeof globalThis.matchMedia !== 'undefined' && globalThis.matchMedia('(hover: none)').matches;
@@ -22,4 +14,5 @@ export const settingsInitialState: SettingsState = {
22
14
  inputMode: localStorage.getInputMode() ?? (isTouchScreen ? 'touchscreen' : 'keyboard'),
23
15
  locale: localStorage.getLocale() ?? guessLocale(),
24
16
  showCoordinates: localStorage.getShowCoordinates() ?? 'hidden',
17
+ removeCellFilters: localStorage.getRemoveCellFilters() ?? 'always',
25
18
  };
@@ -0,0 +1,42 @@
1
+ import { Locale } from '@scrabble-solver/types';
2
+
3
+ export const guessLocale = (): Locale => {
4
+ if (!globalThis.navigator) {
5
+ return Locale.EN_US;
6
+ }
7
+
8
+ const languages = globalThis.navigator.languages;
9
+
10
+ if (languages.includes('pl') || languages.includes('pl-PL')) {
11
+ return Locale.PL_PL;
12
+ }
13
+
14
+ if (languages.includes('en-GB')) {
15
+ return Locale.EN_GB;
16
+ }
17
+
18
+ if (languages.includes('fa') || languages.includes('fa-IR')) {
19
+ return Locale.FA_IR;
20
+ }
21
+
22
+ if (languages.includes('fr-FR')) {
23
+ return Locale.FR_FR;
24
+ }
25
+
26
+ if (languages.includes('ro') || languages.includes('ro-RO')) {
27
+ return Locale.RO_RO;
28
+ }
29
+
30
+ const locales = Object.values(Locale);
31
+ const exactMatch = locales.find((locale) => globalThis.navigator.language === String(locale));
32
+
33
+ if (exactMatch) {
34
+ return exactMatch;
35
+ }
36
+
37
+ const partialMatch = locales.find((locale) => {
38
+ return globalThis.navigator.language === locale.substring(0, 2);
39
+ });
40
+
41
+ return partialMatch ?? Locale.EN_US;
42
+ };
@@ -0,0 +1,69 @@
1
+ import { createSelector } from '@reduxjs/toolkit';
2
+ import { getConfig } from '@scrabble-solver/configs';
3
+ import { BLANK } from '@scrabble-solver/constants';
4
+ import { type Cell, type Tile } from '@scrabble-solver/types';
5
+
6
+ import { i18n, LOCALE_FEATURES } from 'i18n';
7
+
8
+ import type { RootState } from '../types';
9
+
10
+ const selectCell = (_: unknown, cell: Cell): Cell => cell;
11
+
12
+ const selectCharacter = (_: unknown, character: string | null): string | null => character;
13
+
14
+ const selectTile = (_: unknown, tile: Tile | null): Tile | null => tile;
15
+
16
+ export const selectSettings = (state: RootState) => state.settings;
17
+
18
+ export const selectAutoGroupTiles = createSelector([selectSettings], (settings) => settings.autoGroupTiles);
19
+
20
+ export const selectGame = createSelector([selectSettings], (settings) => settings.game);
21
+
22
+ export const selectInputMode = createSelector([selectSettings], (settings) => settings.inputMode);
23
+
24
+ export const selectLocale = createSelector([selectSettings], (settings) => settings.locale);
25
+
26
+ export const selectLocaleAutoGroupTiles = createSelector([selectLocale, selectSettings], (locale, settings) => {
27
+ if (LOCALE_FEATURES[locale].direction === 'ltr' || settings.autoGroupTiles === null) {
28
+ return settings.autoGroupTiles;
29
+ }
30
+
31
+ return settings.autoGroupTiles === 'left' ? 'right' : 'left';
32
+ });
33
+
34
+ export const selectShowCoordinates = createSelector([selectSettings], (settings) => settings.showCoordinates);
35
+
36
+ export const selectConfig = createSelector([selectGame, selectLocale], getConfig);
37
+
38
+ export const selectCharacterPoints = createSelector([selectConfig, selectCharacter], (config, character) => {
39
+ return config.getCharacterPoints(character);
40
+ });
41
+
42
+ export const selectCharacterIsValid = createSelector([selectConfig, selectCharacter], (config, character) => {
43
+ if (character === null || character === BLANK) {
44
+ return true;
45
+ }
46
+
47
+ return config.tiles.some((tile) => tile.character === character);
48
+ });
49
+
50
+ export const selectCellBonus = createSelector([selectConfig, selectCell], (config, cell) => {
51
+ return config.getCellBonus(cell);
52
+ });
53
+
54
+ export const selectTilePoints = createSelector([selectConfig, selectTile], (config, tile) => {
55
+ return config.getTilePoints(tile);
56
+ });
57
+
58
+ export const selectCellIsValid = createSelector([selectConfig, selectCell], (config, cell) => {
59
+ if (!cell.hasTile()) {
60
+ return true;
61
+ }
62
+
63
+ return config.tiles.some((tile) => tile.character === cell.tile.character);
64
+ });
65
+
66
+ export const selectTranslations = createSelector([selectLocale], (locale) => i18n[locale]);
67
+
68
+ export const selectRemoveCellFilters = createSelector([selectSettings], (settings) => settings.removeCellFilters);
69
+
@@ -1,9 +1,9 @@
1
- import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
- import { Game, Locale, ShowCoordinates } from '@scrabble-solver/types';
1
+ import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
2
+ import { type Game, type Locale, type ShowCoordinates } from '@scrabble-solver/types';
3
3
 
4
- import { AutoGroupTiles, InputMode } from 'types';
4
+ import type { AutoGroupTiles, InputMode, RemoveCellFilters } from 'types';
5
5
 
6
- import { settingsInitialState } from './settingsInitialState';
6
+ import { settingsInitialState } from './initialState';
7
7
 
8
8
  export const settingsSlice = createSlice({
9
9
  initialState: settingsInitialState,
@@ -34,6 +34,11 @@ export const settingsSlice = createSlice({
34
34
  return { ...state, showCoordinates };
35
35
  },
36
36
 
37
+ changeRemoveCellFilters: (state, action: PayloadAction<RemoveCellFilters>) => {
38
+ const removeCellFilters = action.payload;
39
+ return { ...state, removeCellFilters };
40
+ },
41
+
37
42
  init: (state, action: PayloadAction<Partial<Pick<typeof settingsInitialState, 'game' | 'locale'>>>) => {
38
43
  return { ...state, ...action.payload };
39
44
  },
@@ -0,0 +1,12 @@
1
+ import { type Game, type Locale, type ShowCoordinates } from '@scrabble-solver/types';
2
+
3
+ import type { AutoGroupTiles, InputMode, RemoveCellFilters } from 'types';
4
+
5
+ export interface SettingsState {
6
+ autoGroupTiles: AutoGroupTiles;
7
+ game: Game;
8
+ inputMode: InputMode;
9
+ locale: Locale;
10
+ showCoordinates: ShowCoordinates;
11
+ removeCellFilters: RemoveCellFilters;
12
+ }
@@ -0,0 +1,4 @@
1
+ export * from './initialState';
2
+ export * from './selectors';
3
+ export * from './slice';
4
+ export * from './types';
@@ -0,0 +1,12 @@
1
+ import { boardInitialState } from '../board';
2
+
3
+ import type { SolveState } from './types';
4
+
5
+ export const solveInitialState: SolveState = {
6
+ error: undefined,
7
+ isLoading: false,
8
+ lastSolvedParameters: {
9
+ board: boardInitialState,
10
+ characters: [],
11
+ },
12
+ };
@@ -0,0 +1,14 @@
1
+ import { createSelector } from '@reduxjs/toolkit';
2
+ import { isError } from '@scrabble-solver/types';
3
+
4
+ import type { RootState } from '../types';
5
+
6
+ export const selectSolve = (state: RootState) => state.solve;
7
+
8
+ export const selectSolveError = createSelector([selectSolve], (solve) => {
9
+ return isError(solve.error) ? solve.error : undefined;
10
+ });
11
+
12
+ export const selectSolveIsLoading = createSelector([selectSolve], (solve) => solve.isLoading);
13
+
14
+ export const selectLastSolvedParameters = createSelector([selectSolve], (solve) => solve.lastSolvedParameters);
@@ -1,7 +1,7 @@
1
- import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
- import { Board } from '@scrabble-solver/types';
1
+ import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
2
+ import { type Board } from '@scrabble-solver/types';
3
3
 
4
- import { solveInitialState } from './solveInitialState';
4
+ import { solveInitialState } from './initialState';
5
5
 
6
6
  interface SolveParameters {
7
7
  board: Board;
@@ -0,0 +1,10 @@
1
+ import { type Board } from '@scrabble-solver/types';
2
+
3
+ export interface SolveState {
4
+ error: unknown;
5
+ isLoading: boolean;
6
+ lastSolvedParameters: {
7
+ board: Board;
8
+ characters: string[];
9
+ };
10
+ }
@@ -1,24 +1,22 @@
1
1
  import { configureStore } from '@reduxjs/toolkit';
2
2
  import reduxSaga from 'redux-saga';
3
3
 
4
+ import { boardSlice } from './board';
5
+ import { cellFiltersSlice } from './cellFilters';
6
+ import { dictionarySlice } from './dictionary';
7
+ import { rackSlice } from './rack';
8
+ import { resultsSlice } from './results';
4
9
  import { rootSaga } from './sagas';
5
- import {
6
- boardSlice,
7
- cellFilterSlice,
8
- dictionarySlice,
9
- rackSlice,
10
- resultsSlice,
11
- settingsSlice,
12
- solveSlice,
13
- verifySlice,
14
- } from './slices';
10
+ import { settingsSlice } from './settings';
11
+ import { solveSlice } from './solve';
12
+ import { verifySlice } from './verify';
15
13
 
16
14
  const sagaMiddleware = reduxSaga();
17
15
 
18
16
  export const store = configureStore({
19
17
  reducer: {
20
18
  board: boardSlice.reducer,
21
- cellFilter: cellFilterSlice.reducer,
19
+ cellFilters: cellFiltersSlice.reducer,
22
20
  dictionary: dictionarySlice.reducer,
23
21
  rack: rackSlice.reducer,
24
22
  results: resultsSlice.reducer,
@@ -1,21 +1,19 @@
1
- import {
2
- boardSlice,
3
- cellFilterSlice,
4
- dictionarySlice,
5
- rackSlice,
6
- resultsSlice,
7
- settingsSlice,
8
- solveSlice,
9
- verifySlice,
10
- } from './slices';
1
+ import type { BoardState } from './board';
2
+ import type { CellFiltersState } from './cellFilters';
3
+ import type { DictionaryState } from './dictionary';
4
+ import type { RackState } from './rack';
5
+ import type { ResultsState } from './results';
6
+ import type { SettingsState } from './settings';
7
+ import type { SolveState } from './solve';
8
+ import type { VerifyState } from './verify';
11
9
 
12
10
  export type RootState = {
13
- board: ReturnType<typeof boardSlice.reducer>;
14
- cellFilter: ReturnType<typeof cellFilterSlice.reducer>;
15
- dictionary: ReturnType<typeof dictionarySlice.reducer>;
16
- rack: ReturnType<typeof rackSlice.reducer>;
17
- results: ReturnType<typeof resultsSlice.reducer>;
18
- settings: ReturnType<typeof settingsSlice.reducer>;
19
- solve: ReturnType<typeof solveSlice.reducer>;
20
- verify: ReturnType<typeof verifySlice.reducer>;
11
+ board: BoardState;
12
+ cellFilters: CellFiltersState;
13
+ dictionary: DictionaryState;
14
+ rack: RackState;
15
+ results: ResultsState;
16
+ settings: SettingsState;
17
+ solve: SolveState;
18
+ verify: VerifyState;
21
19
  };
@@ -1,8 +1,8 @@
1
1
  import { useCallback } from 'react';
2
2
 
3
- import { Translate } from 'types';
3
+ import type { Translate } from 'types';
4
4
 
5
- import { selectLocale, selectTranslations } from './selectors';
5
+ import { selectLocale, selectTranslations } from './settings';
6
6
  import { useTypedSelector } from './useTypedSelector';
7
7
 
8
8
  export const useTranslate = (): Translate => {
@@ -1,5 +1,5 @@
1
- import { TypedUseSelectorHook, useSelector } from 'react-redux';
1
+ import { type TypedUseSelectorHook, useSelector } from 'react-redux';
2
2
 
3
- import { RootState } from './types';
3
+ import type { RootState } from './types';
4
4
 
5
5
  export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
@@ -0,0 +1,4 @@
1
+ export * from './initialState';
2
+ export * from './selectors';
3
+ export * from './slice';
4
+ export * from './types';
@@ -0,0 +1,12 @@
1
+ import { boardInitialState } from '../board';
2
+
3
+ import type { VerifyState } from './types';
4
+
5
+ export const verifyInitialState: VerifyState = {
6
+ isLoading: false,
7
+ lastSolvedParameters: {
8
+ board: boardInitialState,
9
+ },
10
+ invalidWords: [],
11
+ validWords: [],
12
+ };
@@ -0,0 +1,9 @@
1
+ import { createSelector } from '@reduxjs/toolkit';
2
+
3
+ import type { RootState } from '../types';
4
+
5
+ export const selectVerify = (state: RootState) => state.verify;
6
+
7
+ export const selectInvalidWords = createSelector([selectVerify], (verify) => verify.invalidWords);
8
+
9
+ export const selectValidWords = createSelector([selectVerify], (verify) => verify.validWords);
@@ -1,7 +1,7 @@
1
- import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
- import { Board } from '@scrabble-solver/types';
1
+ import { createSlice, type PayloadAction } from '@reduxjs/toolkit';
2
+ import { type Board } from '@scrabble-solver/types';
3
3
 
4
- import { verifyInitialState } from './verifyInitialState';
4
+ import { verifyInitialState } from './initialState';
5
5
 
6
6
  interface VerifyParameters {
7
7
  board: Board;
@@ -0,0 +1,10 @@
1
+ import type { BoardState } from '../board';
2
+
3
+ export interface VerifyState {
4
+ isLoading: boolean;
5
+ lastSolvedParameters: {
6
+ board: BoardState;
7
+ };
8
+ invalidWords: string[];
9
+ validWords: string[];
10
+ }
@@ -45,3 +45,8 @@ h4 {
45
45
  -webkit-margin-after: 0;
46
46
  margin: 0;
47
47
  }
48
+
49
+ /* https://github.com/vercel/next.js/discussions/13387#discussioncomment-5694715 */
50
+ nextjs-portal {
51
+ display: none;
52
+ }