@scrabble-solver/scrabble-solver 2.15.22 → 2.15.24

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 (154) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +12 -12
  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/prerender-manifest.json +4 -4
  16. package/.next/routes-manifest.json +1 -1
  17. package/.next/server/chunks/712.js +1 -1
  18. package/.next/server/middleware-build-manifest.js +1 -1
  19. package/.next/server/pages/404.html +1 -1
  20. package/.next/server/pages/500.html +1 -1
  21. package/.next/server/pages/index.html +1 -1
  22. package/.next/server/pages/index.js +1 -1
  23. package/.next/server/pages/index.json +1 -1
  24. package/.next/server/pages/not-found.html +1 -1
  25. package/.next/static/chunks/{framework-906c47013125d174.js → framework-f7982db529c0590c.js} +1 -1
  26. package/.next/static/chunks/{main-f63f5bd5e9581250.js → main-ca07941c8a544c9a.js} +1 -1
  27. package/.next/static/chunks/pages/{_app-6a68c941d55599c8.js → _app-369e5cb907606ad4.js} +5 -5
  28. package/.next/static/chunks/pages/{index-6c5b582e7afc063c.js → index-08b3b0a754095919.js} +1 -1
  29. package/.next/static/{MxQ5rcf448WOpfCa2_VVz → f_g0t0jBAscXxDrNYOuV0}/_buildManifest.js +1 -1
  30. package/.next/trace +21 -21
  31. package/.next/trace-build +1 -1
  32. package/package.json +12 -12
  33. package/src/app-layout/useAppLayoutValue.ts +4 -4
  34. package/src/components/Alert/Alert.tsx +1 -1
  35. package/src/components/Board/Board.tsx +4 -4
  36. package/src/components/Board/BoardPure.tsx +4 -4
  37. package/src/components/Board/components/Actions/Actions.tsx +5 -5
  38. package/src/components/Board/components/Actions/lib.ts +2 -2
  39. package/src/components/Board/components/Cell/Cell.tsx +1 -1
  40. package/src/components/Board/components/InputPrompt/InputPrompt.tsx +3 -3
  41. package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +4 -4
  42. package/src/components/Board/hooks/useBackgroundImage.tsx +235 -172
  43. package/src/components/Board/hooks/useBoardStyle.ts +4 -4
  44. package/src/components/Board/hooks/useFloatingActions.ts +2 -2
  45. package/src/components/Board/hooks/useFloatingInputPrompt.ts +1 -1
  46. package/src/components/Board/hooks/useGrid.ts +5 -5
  47. package/src/components/Board/lib.ts +2 -2
  48. package/src/components/Board/selectors.ts +2 -2
  49. package/src/components/Dictionary/Dictionary.tsx +2 -2
  50. package/src/components/DictionaryInput/DictionaryInput.tsx +2 -2
  51. package/src/components/EmptyState/EmptyState.tsx +13 -5
  52. package/src/components/Keys/Arrows/Arrows.tsx +1 -1
  53. package/src/components/Keys/index.tsx +2 -2
  54. package/src/components/Loading/Loading.tsx +2 -2
  55. package/src/components/Logo/Logo.tsx +2 -2
  56. package/src/components/Modal/Modal.tsx +3 -3
  57. package/src/components/NavButtons/NavButtons.tsx +4 -4
  58. package/src/components/NavButtons/selectors.ts +1 -1
  59. package/src/components/NotFound/NotFound.tsx +1 -1
  60. package/src/components/PlainTiles/lib.ts +1 -1
  61. package/src/components/Progress/Progress.tsx +2 -2
  62. package/src/components/Rack/Rack.tsx +4 -4
  63. package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +2 -2
  64. package/src/components/Rack/components/InputPrompt/lib.ts +1 -3
  65. package/src/components/Rack/components/RackTile/RackTile.tsx +2 -2
  66. package/src/components/Rack/selectors.ts +2 -2
  67. package/src/components/Results/Cell.tsx +2 -2
  68. package/src/components/Results/Header.tsx +5 -5
  69. package/src/components/Results/HeaderButton.tsx +3 -3
  70. package/src/components/Results/Result.tsx +6 -6
  71. package/src/components/Results/Results.tsx +4 -4
  72. package/src/components/Results/SolveButton.tsx +2 -2
  73. package/src/components/ResultsInput/ResultsInput.tsx +2 -2
  74. package/src/components/Solver/Solver.tsx +3 -3
  75. package/src/components/Solver/components/InsertButton/InsertButton.tsx +2 -2
  76. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +2 -2
  77. package/src/components/Spinner/Spinner.tsx +1 -1
  78. package/src/components/Tile/Tile.tsx +3 -3
  79. package/src/components/Tile/TilePure.tsx +1 -1
  80. package/src/components/Tooltip/TooltipContent.tsx +1 -1
  81. package/src/hooks/useColumns.ts +3 -3
  82. package/src/hooks/useDirection.ts +1 -1
  83. package/src/hooks/useLanguage.ts +1 -1
  84. package/src/hooks/useLocalStorage.ts +1 -1
  85. package/src/hooks/useMediaQuery.ts +1 -1
  86. package/src/i18n/constants.ts +1 -1
  87. package/src/i18n/i18n.ts +1 -1
  88. package/src/i18n/languages/english.json +1 -1
  89. package/src/i18n/languages/french.json +1 -1
  90. package/src/i18n/languages/german.json +1 -1
  91. package/src/i18n/languages/polish.json +1 -1
  92. package/src/i18n/languages/romanian.json +1 -1
  93. package/src/i18n/languages/spanish.json +1 -1
  94. package/src/i18n/languages/turkish.json +1 -1
  95. package/src/lib/createComparator.ts +1 -1
  96. package/src/lib/createKeyComparator.ts +1 -1
  97. package/src/lib/createStringComparator.ts +1 -1
  98. package/src/lib/getTileSizes.ts +1 -1
  99. package/src/lib/numberComparator.ts +1 -1
  100. package/src/lib/reverseComparator.ts +1 -1
  101. package/src/lib/zipCharactersAndTiles.ts +1 -1
  102. package/src/modals/DictionaryModal/DictionaryModal.tsx +2 -2
  103. package/src/modals/KeyMapModal/KeyMapModal.tsx +2 -2
  104. package/src/modals/MenuModal/MenuModal.tsx +5 -5
  105. package/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +5 -5
  106. package/src/modals/RemainingTilesModal/components/Character/Character.tsx +5 -5
  107. package/src/modals/RemainingTilesModal/lib.ts +1 -1
  108. package/src/modals/RemainingTilesModal/selectors.ts +1 -1
  109. package/src/modals/ResultsModal/ResultsModal.tsx +4 -4
  110. package/src/modals/SettingsModal/SettingsModal.tsx +3 -3
  111. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +2 -2
  112. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/lib.ts +1 -1
  113. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +2 -2
  114. package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +2 -2
  115. package/src/modals/SettingsModal/components/InputModeSetting/lib.ts +1 -1
  116. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +3 -3
  117. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/RemoveCellFiltersSetting.tsx +2 -2
  118. package/src/modals/SettingsModal/components/RemoveCellFiltersSetting/lib.ts +1 -1
  119. package/src/modals/SettingsModal/components/ShowCoordinatesSetting/ShowCoordinatesSetting.tsx +2 -2
  120. package/src/modals/WordsModal/WordsModal.tsx +3 -3
  121. package/src/pages/_app.tsx +3 -3
  122. package/src/pages/api/dictionary/[locale]/[word].ts +1 -1
  123. package/src/pages/api/dictionary/[locale]/index.ts +1 -1
  124. package/src/pages/api/solve.ts +2 -2
  125. package/src/pages/api/verify.ts +1 -1
  126. package/src/pages/api/visit.ts +1 -1
  127. package/src/pages/index.tsx +6 -6
  128. package/src/pages/not-found.tsx +1 -1
  129. package/src/parameters/index.ts +1 -1
  130. package/src/service-worker/routeSolveRequests.ts +1 -1
  131. package/src/service-worker/routeVerifyRequests.ts +1 -1
  132. package/src/state/board/slice.ts +24 -1
  133. package/src/state/cellFilters/lib.ts +1 -1
  134. package/src/state/cellFilters/selectors.ts +1 -1
  135. package/src/state/cellFilters/slice.ts +1 -1
  136. package/src/state/cellFilters/types.ts +1 -1
  137. package/src/state/lib.ts +2 -2
  138. package/src/state/localStorage.ts +1 -1
  139. package/src/state/rack/slice.ts +2 -2
  140. package/src/state/rack/types.ts +1 -1
  141. package/src/state/results/initialState.ts +1 -1
  142. package/src/state/results/lib.ts +9 -2
  143. package/src/state/results/selectors.ts +1 -1
  144. package/src/state/results/slice.ts +1 -1
  145. package/src/state/results/types.ts +1 -1
  146. package/src/state/sagas.ts +3 -3
  147. package/src/state/selectors.ts +1 -1
  148. package/src/state/settings/selectors.ts +1 -1
  149. package/src/state/settings/slice.ts +1 -1
  150. package/src/state/settings/types.ts +1 -1
  151. package/src/state/useTranslate.ts +1 -1
  152. package/tsconfig.json +1 -15
  153. package/tsconfig.tsbuildinfo +1 -1
  154. /package/.next/static/{MxQ5rcf448WOpfCa2_VVz → f_g0t0jBAscXxDrNYOuV0}/_ssgManifest.js +0 -0
package/.next/trace-build CHANGED
@@ -1 +1 @@
1
- [{"name":"run-typescript","duration":1892271,"timestamp":10741325368,"id":13,"parentId":1,"tags":{},"startTime":1775397253884,"traceId":"142e972b1da52edc"},{"name":"run-webpack","duration":6166870,"timestamp":10743220826,"id":15,"parentId":1,"tags":{},"startTime":1775397255780,"traceId":"142e972b1da52edc"},{"name":"static-check","duration":176351,"timestamp":10749456101,"id":2016,"parentId":1,"tags":{},"startTime":1775397262015,"traceId":"142e972b1da52edc"},{"name":"static-generation","duration":820346,"timestamp":10749640404,"id":2034,"parentId":1,"tags":{},"startTime":1775397262199,"traceId":"142e972b1da52edc"},{"name":"collect-build-traces","duration":3624593,"timestamp":10749632918,"id":2031,"parentId":1,"tags":{},"startTime":1775397262192,"traceId":"142e972b1da52edc"},{"name":"telemetry-flush","duration":17,"timestamp":10753258582,"id":2046,"parentId":1,"tags":{},"startTime":1775397265817,"traceId":"142e972b1da52edc"},{"name":"next-build","duration":12173853,"timestamp":10741084749,"id":1,"tags":{"buildMode":"default","version":"16.2.2","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1775397253644,"traceId":"142e972b1da52edc"}]
1
+ [{"name":"run-typescript","duration":1924166,"timestamp":5612708199,"id":13,"parentId":1,"tags":{},"startTime":1776200797413,"traceId":"a247f46abd30b936"},{"name":"run-webpack","duration":6261220,"timestamp":5614634557,"id":15,"parentId":1,"tags":{},"startTime":1776200799339,"traceId":"a247f46abd30b936"},{"name":"static-check","duration":185822,"timestamp":5620982865,"id":2016,"parentId":1,"tags":{},"startTime":1776200805688,"traceId":"a247f46abd30b936"},{"name":"static-generation","duration":834210,"timestamp":5621177262,"id":2034,"parentId":1,"tags":{},"startTime":1776200805882,"traceId":"a247f46abd30b936"},{"name":"collect-build-traces","duration":3625253,"timestamp":5621169330,"id":2031,"parentId":1,"tags":{},"startTime":1776200805874,"traceId":"a247f46abd30b936"},{"name":"telemetry-flush","duration":18,"timestamp":5624795666,"id":2046,"parentId":1,"tags":{},"startTime":1776200809500,"traceId":"a247f46abd30b936"},{"name":"next-build","duration":12329041,"timestamp":5612466647,"id":1,"tags":{"buildMode":"default","version":"16.2.3","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1776200797171,"traceId":"a247f46abd30b936"}]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.15.22",
3
+ "version": "2.15.24",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,22 +28,22 @@
28
28
  "@floating-ui/react": "^0.27.19",
29
29
  "@kamilmielnik/trie": "^4.0.0",
30
30
  "@reduxjs/toolkit": "^2.11.2",
31
- "@scrabble-solver/configs": "^2.15.22",
32
- "@scrabble-solver/constants": "^2.15.22",
33
- "@scrabble-solver/dictionaries": "^2.15.22",
34
- "@scrabble-solver/logger": "^2.15.22",
35
- "@scrabble-solver/solver": "^2.15.22",
36
- "@scrabble-solver/types": "^2.15.22",
37
- "@scrabble-solver/word-definitions": "^2.15.22",
31
+ "@scrabble-solver/configs": "^2.15.24",
32
+ "@scrabble-solver/constants": "^2.15.24",
33
+ "@scrabble-solver/dictionaries": "^2.15.24",
34
+ "@scrabble-solver/logger": "^2.15.24",
35
+ "@scrabble-solver/solver": "^2.15.24",
36
+ "@scrabble-solver/types": "^2.15.24",
37
+ "@scrabble-solver/word-definitions": "^2.15.24",
38
38
  "classnames": "^2.5.1",
39
39
  "env-cmd": "^11.0.0",
40
40
  "include-media": "^2.0.0",
41
41
  "include-media-query-builder": "^1.1.0",
42
- "next": "^16.2.2",
42
+ "next": "^16.2.3",
43
43
  "normalize.css": "^8.0.1",
44
- "react": "^19.2.4",
44
+ "react": "^19.2.5",
45
45
  "react-cool-onclickoutside": "^1.7.0",
46
- "react-dom": "^19.2.4",
46
+ "react-dom": "^19.2.5",
47
47
  "react-highlight-words": "^0.21.0",
48
48
  "react-modal": "^3.16.3",
49
49
  "react-redux": "^9.2.0",
@@ -69,5 +69,5 @@
69
69
  "@types/redux": "^3.6.31",
70
70
  "sass": "^1.99.0"
71
71
  },
72
- "gitHead": "6d8b6b51e3cad36844454d3564b90b1e14e9fcf8"
72
+ "gitHead": "28330eeb094266d16a0e2c80f3333f534c70dea1"
73
73
  }
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable max-statements */
2
2
 
3
- import { useColumns, useIsTouchDevice, useMediaQueries, useViewportSize } from 'hooks';
3
+ import { useColumns, useIsTouchDevice, useMediaQueries, useViewportSize } from '@/hooks';
4
4
  import {
5
5
  BOARD_TILE_SIZE_MAX,
6
6
  BORDER_WIDTH,
@@ -19,9 +19,9 @@ import {
19
19
  RESULTS_COLUMN_WIDTH,
20
20
  SOLVER_COLUMN_WIDTH,
21
21
  TEXT_INPUT_HEIGHT,
22
- } from 'parameters';
23
- import { selectConfig, selectShowCoordinates, useTypedSelector } from 'state';
24
- import { type ResultColumnId } from 'types';
22
+ } from '@/parameters';
23
+ import { selectConfig, selectShowCoordinates, useTypedSelector } from '@/state';
24
+ import { type ResultColumnId } from '@/types';
25
25
 
26
26
  export const useAppLayoutValue = () => {
27
27
  const { viewportHeight, viewportWidth } = useViewportSize();
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { type FunctionComponent, type HTMLProps, type ReactNode, type SVGAttributes } from 'react';
3
3
 
4
- import { Check, CrossCircleFill, ExclamationTriangleFill, InfoCircleFill } from 'icons';
4
+ import { Check, CrossCircleFill, ExclamationTriangleFill, InfoCircleFill } from '@/icons';
5
5
 
6
6
  import styles from './Alert.module.scss';
7
7
 
@@ -7,9 +7,9 @@ import { type CSSProperties, type FocusEventHandler, type FunctionComponent, use
7
7
  import useOnclickOutside from 'react-cool-onclickoutside';
8
8
  import { useDispatch } from 'react-redux';
9
9
 
10
- import { useAppLayout } from 'app-layout';
11
- import { LOCALE_FEATURES } from 'i18n';
12
- import { TRANSITION } from 'parameters';
10
+ import { useAppLayout } from '@/app-layout';
11
+ import { LOCALE_FEATURES } from '@/i18n';
12
+ import { TRANSITION } from '@/parameters';
13
13
  import {
14
14
  boardSlice,
15
15
  cellFiltersSlice,
@@ -19,7 +19,7 @@ import {
19
19
  selectShowCoordinates,
20
20
  solveSlice,
21
21
  useTypedSelector,
22
- } from 'state';
22
+ } from '@/state';
23
23
 
24
24
  import styles from './Board.module.scss';
25
25
  import { BoardPure } from './BoardPure';
@@ -12,10 +12,10 @@ import {
12
12
  memo,
13
13
  } from 'react';
14
14
 
15
- import { Ban, FlagFill } from 'icons';
16
- import { getCoordinate } from 'lib';
17
- import { BORDER_WIDTH } from 'parameters';
18
- import { type CellFilter } from 'types';
15
+ import { Ban, FlagFill } from '@/icons';
16
+ import { getCoordinate } from '@/lib';
17
+ import { BORDER_WIDTH } from '@/parameters';
18
+ import { type CellFilter } from '@/types';
19
19
 
20
20
  import styles from './Board.module.scss';
21
21
  import { Cell } from './components';
@@ -3,11 +3,11 @@ import { type Cell } from '@scrabble-solver/types';
3
3
  import classNames from 'classnames';
4
4
  import { forwardRef, type HTMLProps, type MouseEventHandler } from 'react';
5
5
 
6
- import { useIsTouchDevice } from 'hooks';
7
- import { Keyboard, Square, SquareFill } from 'icons';
8
- import { findCell, isMac } from 'lib';
9
- import { selectCellFilter, selectInputMode, selectResultCandidateCells, useTranslate, useTypedSelector } from 'state';
10
- import { type Direction } from 'types';
6
+ import { useIsTouchDevice } from '@/hooks';
7
+ import { Keyboard, Square, SquareFill } from '@/icons';
8
+ import { findCell, isMac } from '@/lib';
9
+ import { selectCellFilter, selectInputMode, selectResultCandidateCells, useTranslate, useTypedSelector } from '@/state';
10
+ import { type Direction } from '@/types';
11
11
 
12
12
  import { Button } from '../../../Button';
13
13
  import { ToggleDirectionButton } from '../ToggleDirectionButton';
@@ -1,7 +1,7 @@
1
1
  import { type FunctionComponent, type SVGAttributes } from 'react';
2
2
 
3
- import { Ban, Eraser, FlagFill } from 'icons';
4
- import { type CellFilter, type TranslationKey } from 'types';
3
+ import { Ban, Eraser, FlagFill } from '@/icons';
4
+ import { type CellFilter, type TranslationKey } from '@/types';
5
5
 
6
6
  export const getNextCellFilter = (
7
7
  filter: CellFilter | undefined,
@@ -19,7 +19,7 @@ import {
19
19
  selectTilePoints,
20
20
  useTranslate,
21
21
  useTypedSelector,
22
- } from 'state';
22
+ } from '@/state';
23
23
 
24
24
  import { Tile } from '../../../Tile';
25
25
 
@@ -8,9 +8,9 @@ import {
8
8
  useState,
9
9
  } from 'react';
10
10
 
11
- import { Check } from 'icons';
12
- import { useTranslate } from 'state';
13
- import { type Direction } from 'types';
11
+ import { Check } from '@/icons';
12
+ import { useTranslate } from '@/state';
13
+ import { type Direction } from '@/types';
14
14
 
15
15
  import { Button } from '../../../Button';
16
16
  import { ToggleDirectionButton } from '../ToggleDirectionButton';
@@ -1,10 +1,10 @@
1
1
  import classNames from 'classnames';
2
2
  import { type ButtonHTMLAttributes, type FunctionComponent } from 'react';
3
3
 
4
- import { useIsTouchDevice } from 'hooks';
5
- import { ArrowDown } from 'icons';
6
- import { useTranslate } from 'state';
7
- import { type Direction } from 'types';
4
+ import { useIsTouchDevice } from '@/hooks';
5
+ import { ArrowDown } from '@/icons';
6
+ import { useTranslate } from '@/state';
7
+ import { type Direction } from '@/types';
8
8
 
9
9
  import { Button } from '../../../Button';
10
10
 
@@ -1,18 +1,18 @@
1
1
  /* eslint-disable max-lines, max-statements */
2
2
 
3
3
  import { BONUS_CHARACTER, BONUS_WORD } from '@scrabble-solver/constants';
4
- import { useMemo } from 'react';
4
+ import { useCallback, useMemo } from 'react';
5
5
  import { renderToString } from 'react-dom/server';
6
6
  import { Provider } from 'react-redux';
7
7
 
8
- import { useAppLayout } from 'app-layout';
9
- import { useMediaQueries } from 'hooks';
10
- import { LOCALE_FEATURES } from 'i18n';
11
- import { Star } from 'icons';
12
- import { getTileSizes } from 'lib';
13
- import { BORDER_COLOR_LIGHT, BORDER_RADIUS, BORDER_WIDTH, COLOR_BACKGROUND, COLOR_BONUS_START } from 'parameters';
14
- import { selectConfig, selectLocale, selectShowCoordinates, store, useTypedSelector } from 'state';
15
- import { type Point } from 'types';
8
+ import { useAppLayout } from '@/app-layout';
9
+ import { useMediaQueries } from '@/hooks';
10
+ import { LOCALE_FEATURES } from '@/i18n';
11
+ import { Star } from '@/icons';
12
+ import { getTileSizes } from '@/lib';
13
+ import { BORDER_COLOR_LIGHT, BORDER_RADIUS, BORDER_WIDTH, COLOR_BACKGROUND, COLOR_BONUS_START } from '@/parameters';
14
+ import { selectConfig, selectLocale, selectShowCoordinates, store, useTypedSelector } from '@/state';
15
+ import { type Point } from '@/types';
16
16
 
17
17
  import { getBonusColor } from '../lib';
18
18
 
@@ -33,7 +33,10 @@ export const useBackgroundImage = () => {
33
33
  const { isLessThanXs } = useMediaQueries();
34
34
  const borderRadius = isLessThanXs ? BORDER_RADIUS_XS : BORDER_RADIUS;
35
35
  const config = useTypedSelector(selectConfig);
36
- const center = { x: Math.floor(config.boardWidth / 2), y: Math.floor(config.boardHeight / 2) };
36
+ const center = useMemo(
37
+ () => ({ x: Math.floor(config.boardWidth / 2), y: Math.floor(config.boardHeight / 2) }),
38
+ [config.boardHeight, config.boardWidth],
39
+ );
37
40
  const viewBoxHeight = boardHeight;
38
41
  const viewBoxWidth = boardWidth;
39
42
  const bonusSize = cellSize * 0.8;
@@ -43,174 +46,234 @@ export const useBackgroundImage = () => {
43
46
  const { tileFontSize } = getTileSizes(cellSize);
44
47
  const fontSize = tileFontSize * 0.6;
45
48
  const fontOffset = cellSize / 2;
46
- const characterBonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_CHARACTER);
47
- const word2Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 2);
48
- const word3Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 3);
49
- const word4Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 4);
50
-
51
- const getX = (point: Point): number =>
52
- (direction === 'ltr' ? coordinatesSize : 0) + point.x * (cellSize + BORDER_WIDTH);
53
-
54
- const getY = (point: Point): number => coordinatesSize + point.y * (cellSize + BORDER_WIDTH);
55
-
56
- const backgroundSvg = renderToString(
57
- <Provider store={store}>
58
- <svg
59
- height={viewBoxHeight}
60
- viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
61
- width={viewBoxWidth}
62
- xmlns="http://www.w3.org/2000/svg"
63
- >
64
- <defs>
65
- <symbol id={HORIZONTAL_LINE}>
66
- <rect fill={BORDER_COLOR_LIGHT} height={GRID_LINE_SIZE} width={viewBoxWidth} />
67
- </symbol>
68
-
69
- <symbol id={VERTICAL_LINE}>
70
- <rect fill={BORDER_COLOR_LIGHT} height={viewBoxHeight} width={GRID_LINE_SIZE} />
71
- </symbol>
72
-
73
- <symbol id={BONUS}>
74
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
75
- </symbol>
76
-
77
- <symbol id={BONUS_WORD_2}>
78
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
79
-
80
- <text
81
- dominantBaseline="central"
82
- fill="white"
83
- fontFamily="system-ui, sans-serif"
84
- fontSize={fontSize}
85
- fontWeight="bold"
86
- textAnchor="middle"
87
- x={fontOffset}
88
- y={fontOffset}
89
- >
90
- x2
91
- </text>
92
- </symbol>
93
-
94
- <symbol id={BONUS_WORD_3}>
95
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
96
-
97
- <text
98
- dominantBaseline="central"
99
- fill="white"
100
- fontFamily="system-ui, sans-serif"
101
- fontSize={fontSize}
102
- fontWeight="bold"
103
- textAnchor="middle"
104
- x={fontOffset}
105
- y={fontOffset}
106
- >
107
- x3
108
- </text>
109
- </symbol>
110
-
111
- <symbol id={BONUS_WORD_4}>
112
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
113
-
114
- <text
115
- dominantBaseline="central"
116
- fill="white"
117
- fontFamily="system-ui, sans-serif"
118
- fontSize={fontSize}
119
- fontWeight="bold"
120
- textAnchor="middle"
121
- x={fontOffset}
122
- y={fontOffset}
123
- >
124
- x4
125
- </text>
126
- </symbol>
127
- </defs>
128
-
129
- {showCoordinates === 'hidden' && (
130
- <rect fill="white" height={viewBoxHeight} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
131
- )}
132
-
133
- {showCoordinates !== 'hidden' && (
134
- <>
135
- <rect fill={COLOR_BACKGROUND} height={viewBoxHeight} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
136
- <rect
137
- fill="white"
138
- height={viewBoxHeight - coordinatesSize}
139
- width={viewBoxWidth - coordinatesSize}
140
- x={direction === 'ltr' ? coordinatesSize : 0}
141
- y={coordinatesSize}
142
- />
49
+ const characterBonuses = useMemo(
50
+ () => config.bonuses.filter((bonus) => bonus.type === BONUS_CHARACTER),
51
+ [config.bonuses],
52
+ );
53
+ const word2Bonuses = useMemo(
54
+ () => config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 2),
55
+ [config.bonuses],
56
+ );
57
+ const word3Bonuses = useMemo(
58
+ () => config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 3),
59
+ [config.bonuses],
60
+ );
61
+ const word4Bonuses = useMemo(
62
+ () => config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 4),
63
+ [config.bonuses],
64
+ );
65
+
66
+ const getX = useCallback(
67
+ (point: Point): number => (direction === 'ltr' ? coordinatesSize : 0) + point.x * (cellSize + BORDER_WIDTH),
68
+ [coordinatesSize, cellSize, direction],
69
+ );
70
+
71
+ const getY = useCallback(
72
+ (point: Point): number => coordinatesSize + point.y * (cellSize + BORDER_WIDTH),
73
+ [coordinatesSize, cellSize],
74
+ );
75
+
76
+ const backgroundSvg = useMemo(
77
+ () =>
78
+ renderToString(
79
+ <Provider store={store}>
80
+ <svg
81
+ height={viewBoxHeight}
82
+ viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
83
+ width={viewBoxWidth}
84
+ xmlns="http://www.w3.org/2000/svg"
85
+ >
86
+ <defs>
87
+ <symbol id={HORIZONTAL_LINE}>
88
+ <rect fill={BORDER_COLOR_LIGHT} height={GRID_LINE_SIZE} width={viewBoxWidth} />
89
+ </symbol>
90
+
91
+ <symbol id={VERTICAL_LINE}>
92
+ <rect fill={BORDER_COLOR_LIGHT} height={viewBoxHeight} width={GRID_LINE_SIZE} />
93
+ </symbol>
94
+
95
+ <symbol id={BONUS}>
96
+ <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
97
+ </symbol>
98
+
99
+ <symbol id={BONUS_WORD_2}>
100
+ <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
101
+
102
+ <text
103
+ dominantBaseline="central"
104
+ fill="white"
105
+ fontFamily="system-ui, sans-serif"
106
+ fontSize={fontSize}
107
+ fontWeight="bold"
108
+ textAnchor="middle"
109
+ x={fontOffset}
110
+ y={fontOffset}
111
+ >
112
+ ×2
113
+ </text>
114
+ </symbol>
115
+
116
+ <symbol id={BONUS_WORD_3}>
117
+ <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
118
+
119
+ <text
120
+ dominantBaseline="central"
121
+ fill="white"
122
+ fontFamily="system-ui, sans-serif"
123
+ fontSize={fontSize}
124
+ fontWeight="bold"
125
+ textAnchor="middle"
126
+ x={fontOffset}
127
+ y={fontOffset}
128
+ >
129
+ ×3
130
+ </text>
131
+ </symbol>
132
+
133
+ <symbol id={BONUS_WORD_4}>
134
+ <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
135
+
136
+ <text
137
+ dominantBaseline="central"
138
+ fill="white"
139
+ fontFamily="system-ui, sans-serif"
140
+ fontSize={fontSize}
141
+ fontWeight="bold"
142
+ textAnchor="middle"
143
+ x={fontOffset}
144
+ y={fontOffset}
145
+ >
146
+ ×4
147
+ </text>
148
+ </symbol>
149
+ </defs>
150
+
151
+ {showCoordinates === 'hidden' && (
152
+ <rect fill="white" height={viewBoxHeight} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
153
+ )}
154
+
155
+ {showCoordinates !== 'hidden' && (
156
+ <>
157
+ <rect
158
+ fill={COLOR_BACKGROUND}
159
+ height={viewBoxHeight}
160
+ rx={borderRadius}
161
+ width={viewBoxWidth}
162
+ x="0"
163
+ y="0"
164
+ />
165
+ <rect
166
+ fill="white"
167
+ height={viewBoxHeight - coordinatesSize}
168
+ width={viewBoxWidth - coordinatesSize}
169
+ x={direction === 'ltr' ? coordinatesSize : 0}
170
+ y={coordinatesSize}
171
+ />
172
+
173
+ <rect
174
+ fill={COLOR_BACKGROUND}
175
+ height={coordinatesSize}
176
+ rx={borderRadius}
177
+ width={viewBoxWidth}
178
+ x="0"
179
+ y="0"
180
+ />
181
+ <rect
182
+ fill={COLOR_BACKGROUND}
183
+ height={viewBoxHeight}
184
+ rx={borderRadius}
185
+ x={direction === 'ltr' ? 0 : viewBoxWidth - coordinatesSize}
186
+ y="0"
187
+ width={coordinatesSize}
188
+ />
189
+ <use href={`#${HORIZONTAL_LINE}`} y={coordinatesSize - BORDER_WIDTH} />
190
+ <use
191
+ href={`#${VERTICAL_LINE}`}
192
+ x={
193
+ direction === 'ltr' ? coordinatesSize - BORDER_WIDTH : viewBoxWidth - coordinatesSize - BORDER_WIDTH
194
+ }
195
+ />
196
+ </>
197
+ )}
198
+
199
+ {Array.from({ length: config.boardHeight - 1 }).map((_value, index) => (
200
+ <use
201
+ key={index}
202
+ href={`#${HORIZONTAL_LINE}`}
203
+ y={coordinatesSize + (index + 1) * (cellSize + BORDER_WIDTH) - BORDER_WIDTH}
204
+ />
205
+ ))}
206
+
207
+ {Array.from({ length: config.boardWidth - 1 }).map((_value, index) => (
208
+ <use
209
+ key={index}
210
+ href={`#${VERTICAL_LINE}`}
211
+ x={(direction === 'ltr' ? coordinatesSize : 0) + (index + 1) * (cellSize + BORDER_WIDTH) - BORDER_WIDTH}
212
+ />
213
+ ))}
214
+
215
+ {characterBonuses.map((bonus, index) => (
216
+ <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS}`} x={getX(bonus)} y={getY(bonus)} />
217
+ ))}
218
+
219
+ {word2Bonuses.map((bonus, index) => (
220
+ <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_2}`} x={getX(bonus)} y={getY(bonus)} />
221
+ ))}
222
+
223
+ {word3Bonuses.map((bonus, index) => (
224
+ <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_3}`} x={getX(bonus)} y={getY(bonus)} />
225
+ ))}
226
+
227
+ {word4Bonuses.map((bonus, index) => (
228
+ <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_4}`} x={getX(bonus)} y={getY(bonus)} />
229
+ ))}
143
230
 
144
- <rect fill={COLOR_BACKGROUND} height={coordinatesSize} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
145
231
  <rect
146
- fill={COLOR_BACKGROUND}
147
- height={viewBoxHeight}
232
+ fill={COLOR_BONUS_START}
233
+ height={bonusSize}
148
234
  rx={borderRadius}
149
- x={direction === 'ltr' ? 0 : viewBoxWidth - coordinatesSize}
150
- y="0"
151
- width={coordinatesSize}
235
+ width={bonusSize}
236
+ x={getX(center) + bonusOffset}
237
+ y={getY(center) + bonusOffset}
152
238
  />
153
- <use href={`#${HORIZONTAL_LINE}`} y={coordinatesSize - BORDER_WIDTH} />
154
- <use
155
- href={`#${VERTICAL_LINE}`}
156
- x={direction === 'ltr' ? coordinatesSize - BORDER_WIDTH : viewBoxWidth - coordinatesSize - BORDER_WIDTH}
239
+
240
+ <Star
241
+ color="white"
242
+ height={iconSize}
243
+ width={iconSize}
244
+ x={getX(center) + iconOffset}
245
+ y={getY(center) + iconOffset}
157
246
  />
158
- </>
159
- )}
160
-
161
- {Array.from({ length: config.boardHeight - 1 }).map((_value, index) => (
162
- <use
163
- key={index}
164
- href={`#${HORIZONTAL_LINE}`}
165
- y={coordinatesSize + (index + 1) * (cellSize + BORDER_WIDTH) - BORDER_WIDTH}
166
- />
167
- ))}
168
-
169
- {Array.from({ length: config.boardWidth - 1 }).map((_value, index) => (
170
- <use
171
- key={index}
172
- href={`#${VERTICAL_LINE}`}
173
- x={(direction === 'ltr' ? coordinatesSize : 0) + (index + 1) * (cellSize + BORDER_WIDTH) - BORDER_WIDTH}
174
- />
175
- ))}
176
-
177
- {characterBonuses.map((bonus, index) => (
178
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS}`} x={getX(bonus)} y={getY(bonus)} />
179
- ))}
180
-
181
- {word2Bonuses.map((bonus, index) => (
182
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_2}`} x={getX(bonus)} y={getY(bonus)} />
183
- ))}
184
-
185
- {word3Bonuses.map((bonus, index) => (
186
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_3}`} x={getX(bonus)} y={getY(bonus)} />
187
- ))}
188
-
189
- {word4Bonuses.map((bonus, index) => (
190
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_4}`} x={getX(bonus)} y={getY(bonus)} />
191
- ))}
192
-
193
- <rect
194
- fill={COLOR_BONUS_START}
195
- height={bonusSize}
196
- rx={borderRadius}
197
- width={bonusSize}
198
- x={getX(center) + bonusOffset}
199
- y={getY(center) + bonusOffset}
200
- />
201
-
202
- <Star
203
- color="white"
204
- height={iconSize}
205
- width={iconSize}
206
- x={getX(center) + iconOffset}
207
- y={getY(center) + iconOffset}
208
- />
209
- </svg>
210
- </Provider>,
247
+ </svg>
248
+ </Provider>,
249
+ ),
250
+ [
251
+ bonusOffset,
252
+ bonusSize,
253
+ borderRadius,
254
+ cellSize,
255
+ center,
256
+ characterBonuses,
257
+ config.boardHeight,
258
+ config.boardWidth,
259
+ coordinatesSize,
260
+ direction,
261
+ fontOffset,
262
+ fontSize,
263
+ getX,
264
+ getY,
265
+ iconOffset,
266
+ iconSize,
267
+ showCoordinates,
268
+ viewBoxHeight,
269
+ viewBoxWidth,
270
+ word2Bonuses,
271
+ word3Bonuses,
272
+ word4Bonuses,
273
+ ],
211
274
  );
212
275
 
213
- const encodedSvg = useMemo(() => globalThis.btoa(backgroundSvg), [backgroundSvg]);
214
- const dataUrl = `data:image/svg+xml;base64,${encodedSvg}`;
276
+ const dataUrl = useMemo(() => `data:image/svg+xml,${encodeURIComponent(backgroundSvg)}`, [backgroundSvg]);
277
+
215
278
  return dataUrl;
216
279
  };
@@ -1,9 +1,9 @@
1
1
  import { type CSSProperties, useMemo } from 'react';
2
2
 
3
- import { useAppLayout } from 'app-layout';
4
- import { getTileSizes } from 'lib';
5
- import { BORDER_WIDTH } from 'parameters';
6
- import { selectConfig, selectShowCoordinates, useTypedSelector } from 'state';
3
+ import { useAppLayout } from '@/app-layout';
4
+ import { getTileSizes } from '@/lib';
5
+ import { BORDER_WIDTH } from '@/parameters';
6
+ import { selectConfig, selectShowCoordinates, useTypedSelector } from '@/state';
7
7
 
8
8
  import { useBackgroundImage } from './useBackgroundImage';
9
9