scrabble-solver 2.15.21 → 2.15.23

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 (100) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/.github/workflows/build.yml +2 -2
  3. package/.github/workflows/cypress.yml +3 -3
  4. package/.github/workflows/deploy.yml +1 -1
  5. package/.github/workflows/eslint.yml +2 -2
  6. package/.github/workflows/jest.yml +2 -2
  7. package/.github/workflows/npx.yml +3 -3
  8. package/.next/trace +1 -1
  9. package/.next/trace-build +1 -0
  10. package/.nx/workspace-data/file-map.json +465 -457
  11. package/.nx/workspace-data/lockfile-dependencies.hash +1 -1
  12. package/.nx/workspace-data/lockfile-nodes.hash +1 -1
  13. package/.nx/workspace-data/nx_files.nxt +0 -0
  14. package/.nx/workspace-data/parsed-lock-file.dependencies.json +909 -369
  15. package/.nx/workspace-data/parsed-lock-file.nodes.json +1538 -1140
  16. package/.nx/workspace-data/project-graph.json +2104 -1271
  17. package/lerna.json +1 -1
  18. package/package.json +23 -23
  19. package/packages/configs/package.json +3 -3
  20. package/packages/constants/package.json +1 -1
  21. package/packages/dictionaries/package.json +4 -4
  22. package/packages/logger/package.json +1 -1
  23. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  24. package/packages/scrabble-solver/.next/build-manifest.json +16 -16
  25. package/packages/scrabble-solver/.next/cache/.previewinfo +1 -1
  26. package/packages/scrabble-solver/.next/cache/.rscinfo +1 -1
  27. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  28. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  29. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  30. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack.old +0 -0
  31. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  32. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  33. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  34. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  35. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack.old +0 -0
  36. package/packages/scrabble-solver/.next/diagnostics/framework.json +1 -1
  37. package/packages/scrabble-solver/.next/prerender-manifest.json +4 -4
  38. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  39. package/packages/scrabble-solver/.next/server/chunks/712.js +1 -1
  40. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  41. package/packages/scrabble-solver/.next/server/pages/404.html +1 -1
  42. package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
  43. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  44. package/packages/scrabble-solver/.next/server/pages/_error.js.nft.json +1 -1
  45. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  46. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  47. package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
  48. package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
  49. package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
  50. package/packages/scrabble-solver/.next/server/pages/index.js +1 -1
  51. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  52. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  53. package/packages/scrabble-solver/.next/server/pages/not-found.html +1 -1
  54. package/packages/scrabble-solver/.next/static/chunks/{framework-93e577820ffb186a.js → framework-f7982db529c0590c.js} +1 -1
  55. package/packages/scrabble-solver/.next/static/chunks/{main-f63f5bd5e9581250.js → main-ca07941c8a544c9a.js} +1 -1
  56. package/packages/scrabble-solver/.next/static/chunks/pages/_app-a3061a79f91b3796.js +7 -0
  57. package/packages/scrabble-solver/.next/static/chunks/pages/index-6c5b582e7afc063c.js +1 -0
  58. package/packages/scrabble-solver/.next/static/chunks/webpack-1a7a166b34ed8d24.js +1 -0
  59. package/packages/scrabble-solver/.next/static/{8q_9JlEMMcIoT2TpStZYx → zFnoNsMXUha-MKjuZn6AN}/_buildManifest.js +1 -1
  60. package/packages/scrabble-solver/.next/trace +21 -21
  61. package/packages/scrabble-solver/.next/trace-build +1 -1
  62. package/packages/scrabble-solver/package.json +19 -19
  63. package/packages/scrabble-solver/public/service-worker.js +1 -1
  64. package/packages/scrabble-solver/src/app-layout/AppLayoutContext.tsx +25 -0
  65. package/packages/scrabble-solver/src/app-layout/index.ts +1 -0
  66. package/packages/scrabble-solver/src/{hooks/useAppLayout.ts → app-layout/useAppLayoutValue.ts} +4 -6
  67. package/packages/scrabble-solver/src/components/Board/Board.tsx +1 -1
  68. package/packages/scrabble-solver/src/components/Board/components/InputPrompt/InputPrompt.tsx +9 -2
  69. package/packages/scrabble-solver/src/components/Board/hooks/useBackgroundImage.tsx +228 -165
  70. package/packages/scrabble-solver/src/components/Board/hooks/useBoardStyle.ts +1 -1
  71. package/packages/scrabble-solver/src/components/Board/hooks/useFloatingActions.ts +1 -1
  72. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +1 -1
  73. package/packages/scrabble-solver/src/components/DictionaryInput/DictionaryInput.tsx +2 -2
  74. package/packages/scrabble-solver/src/components/Logo/Logo.tsx +1 -1
  75. package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +1 -1
  76. package/packages/scrabble-solver/src/components/Rack/Rack.tsx +1 -1
  77. package/packages/scrabble-solver/src/components/Rack/components/InputPrompt/InputPrompt.tsx +4 -4
  78. package/packages/scrabble-solver/src/components/Results/Header.tsx +2 -1
  79. package/packages/scrabble-solver/src/components/Results/Result.tsx +2 -1
  80. package/packages/scrabble-solver/src/components/ResultsInput/ResultsInput.tsx +2 -2
  81. package/packages/scrabble-solver/src/components/Solver/Solver.tsx +2 -1
  82. package/packages/scrabble-solver/src/components/Tile/Tile.tsx +1 -1
  83. package/packages/scrabble-solver/src/hooks/index.ts +0 -1
  84. package/packages/scrabble-solver/src/lib/isMac.ts +0 -1
  85. package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.tsx +1 -1
  86. package/packages/scrabble-solver/src/pages/_app.tsx +7 -4
  87. package/packages/scrabble-solver/src/pages/index.tsx +42 -21
  88. package/packages/scrabble-solver/tsconfig.json +3 -2
  89. package/packages/scrabble-solver/tsconfig.tsbuildinfo +1 -1
  90. package/packages/solver/package.json +5 -5
  91. package/packages/types/package.json +2 -2
  92. package/packages/word-definitions/package.json +4 -4
  93. package/packages/word-lists/build/lib/transliterateDiacritics.d.ts +2 -2
  94. package/packages/word-lists/package.json +4 -4
  95. package/packages/word-lists/src/lib/transliterateDiacritics.ts +2 -2
  96. package/tsconfig.json +5 -4
  97. package/packages/scrabble-solver/.next/static/chunks/pages/_app-ac2ab0ef8f59ba92.js +0 -3
  98. package/packages/scrabble-solver/.next/static/chunks/pages/index-3be9ce84ae513eaa.js +0 -1
  99. package/packages/scrabble-solver/.next/static/chunks/webpack-49a83516933d4cf2.js +0 -1
  100. /package/packages/scrabble-solver/.next/static/{8q_9JlEMMcIoT2TpStZYx → zFnoNsMXUha-MKjuZn6AN}/_ssgManifest.js +0 -0
@@ -1,11 +1,12 @@
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, useMediaQueries } from 'hooks';
8
+ import { useAppLayout } from 'app-layout';
9
+ import { useMediaQueries } from 'hooks';
9
10
  import { LOCALE_FEATURES } from 'i18n';
10
11
  import { Star } from 'icons';
11
12
  import { getTileSizes } from 'lib';
@@ -32,7 +33,10 @@ export const useBackgroundImage = () => {
32
33
  const { isLessThanXs } = useMediaQueries();
33
34
  const borderRadius = isLessThanXs ? BORDER_RADIUS_XS : BORDER_RADIUS;
34
35
  const config = useTypedSelector(selectConfig);
35
- 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
+ );
36
40
  const viewBoxHeight = boardHeight;
37
41
  const viewBoxWidth = boardWidth;
38
42
  const bonusSize = cellSize * 0.8;
@@ -42,174 +46,233 @@ export const useBackgroundImage = () => {
42
46
  const { tileFontSize } = getTileSizes(cellSize);
43
47
  const fontSize = tileFontSize * 0.6;
44
48
  const fontOffset = cellSize / 2;
45
- const characterBonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_CHARACTER);
46
- const word2Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 2);
47
- const word3Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 3);
48
- const word4Bonuses = config.bonuses.filter((bonus) => bonus.type === BONUS_WORD && bonus.multiplier === 4);
49
-
50
- const getX = (point: Point): number =>
51
- (direction === 'ltr' ? coordinatesSize : 0) + point.x * (cellSize + BORDER_WIDTH);
52
-
53
- const getY = (point: Point): number => coordinatesSize + point.y * (cellSize + BORDER_WIDTH);
54
-
55
- const backgroundSvg = renderToString(
56
- <Provider store={store}>
57
- <svg
58
- height={viewBoxHeight}
59
- viewBox={`0 0 ${viewBoxWidth} ${viewBoxHeight}`}
60
- width={viewBoxWidth}
61
- xmlns="http://www.w3.org/2000/svg"
62
- >
63
- <defs>
64
- <symbol id={HORIZONTAL_LINE}>
65
- <rect fill={BORDER_COLOR_LIGHT} height={GRID_LINE_SIZE} width={viewBoxWidth} />
66
- </symbol>
67
-
68
- <symbol id={VERTICAL_LINE}>
69
- <rect fill={BORDER_COLOR_LIGHT} height={viewBoxHeight} width={GRID_LINE_SIZE} />
70
- </symbol>
71
-
72
- <symbol id={BONUS}>
73
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
74
- </symbol>
75
-
76
- <symbol id={BONUS_WORD_2}>
77
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
78
-
79
- <text
80
- dominantBaseline="central"
81
- fill="white"
82
- fontFamily="system-ui, sans-serif"
83
- fontSize={fontSize}
84
- fontWeight="bold"
85
- textAnchor="middle"
86
- x={fontOffset}
87
- y={fontOffset}
88
- >
89
- x2
90
- </text>
91
- </symbol>
92
-
93
- <symbol id={BONUS_WORD_3}>
94
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
95
-
96
- <text
97
- dominantBaseline="central"
98
- fill="white"
99
- fontFamily="system-ui, sans-serif"
100
- fontSize={fontSize}
101
- fontWeight="bold"
102
- textAnchor="middle"
103
- x={fontOffset}
104
- y={fontOffset}
105
- >
106
- x3
107
- </text>
108
- </symbol>
109
-
110
- <symbol id={BONUS_WORD_4}>
111
- <rect height={bonusSize} rx={borderRadius} width={bonusSize} x={bonusOffset} y={bonusOffset} />
112
-
113
- <text
114
- dominantBaseline="central"
115
- fill="white"
116
- fontFamily="system-ui, sans-serif"
117
- fontSize={fontSize}
118
- fontWeight="bold"
119
- textAnchor="middle"
120
- x={fontOffset}
121
- y={fontOffset}
122
- >
123
- x4
124
- </text>
125
- </symbol>
126
- </defs>
127
-
128
- {showCoordinates === 'hidden' && (
129
- <rect fill="white" height={viewBoxHeight} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
130
- )}
131
-
132
- {showCoordinates !== 'hidden' && (
133
- <>
134
- <rect fill={COLOR_BACKGROUND} height={viewBoxHeight} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
135
- <rect
136
- fill="white"
137
- height={viewBoxHeight - coordinatesSize}
138
- width={viewBoxWidth - coordinatesSize}
139
- x={direction === 'ltr' ? coordinatesSize : 0}
140
- y={coordinatesSize}
141
- />
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
+ x2
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
+ x3
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
+ x4
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
+ ))}
142
230
 
143
- <rect fill={COLOR_BACKGROUND} height={coordinatesSize} rx={borderRadius} width={viewBoxWidth} x="0" y="0" />
144
231
  <rect
145
- fill={COLOR_BACKGROUND}
146
- height={viewBoxHeight}
232
+ fill={COLOR_BONUS_START}
233
+ height={bonusSize}
147
234
  rx={borderRadius}
148
- x={direction === 'ltr' ? 0 : viewBoxWidth - coordinatesSize}
149
- y="0"
150
- width={coordinatesSize}
235
+ width={bonusSize}
236
+ x={getX(center) + bonusOffset}
237
+ y={getY(center) + bonusOffset}
151
238
  />
152
- <use href={`#${HORIZONTAL_LINE}`} y={coordinatesSize - BORDER_WIDTH} />
153
- <use
154
- href={`#${VERTICAL_LINE}`}
155
- 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}
156
246
  />
157
- </>
158
- )}
159
-
160
- {Array.from({ length: config.boardHeight - 1 }).map((_value, index) => (
161
- <use
162
- key={index}
163
- href={`#${HORIZONTAL_LINE}`}
164
- y={coordinatesSize + (index + 1) * (cellSize + BORDER_WIDTH) - BORDER_WIDTH}
165
- />
166
- ))}
167
-
168
- {Array.from({ length: config.boardWidth - 1 }).map((_value, index) => (
169
- <use
170
- key={index}
171
- href={`#${VERTICAL_LINE}`}
172
- x={(direction === 'ltr' ? coordinatesSize : 0) + (index + 1) * (cellSize + BORDER_WIDTH) - BORDER_WIDTH}
173
- />
174
- ))}
175
-
176
- {characterBonuses.map((bonus, index) => (
177
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS}`} x={getX(bonus)} y={getY(bonus)} />
178
- ))}
179
-
180
- {word2Bonuses.map((bonus, index) => (
181
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_2}`} x={getX(bonus)} y={getY(bonus)} />
182
- ))}
183
-
184
- {word3Bonuses.map((bonus, index) => (
185
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_3}`} x={getX(bonus)} y={getY(bonus)} />
186
- ))}
187
-
188
- {word4Bonuses.map((bonus, index) => (
189
- <use fill={getBonusColor(bonus)} key={index} href={`#${BONUS_WORD_4}`} x={getX(bonus)} y={getY(bonus)} />
190
- ))}
191
-
192
- <rect
193
- fill={COLOR_BONUS_START}
194
- height={bonusSize}
195
- rx={borderRadius}
196
- width={bonusSize}
197
- x={getX(center) + bonusOffset}
198
- y={getY(center) + bonusOffset}
199
- />
200
-
201
- <Star
202
- color="white"
203
- height={iconSize}
204
- width={iconSize}
205
- x={getX(center) + iconOffset}
206
- y={getY(center) + iconOffset}
207
- />
208
- </svg>
209
- </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
+ ],
210
274
  );
211
275
 
212
- const encodedSvg = useMemo(() => globalThis.btoa(backgroundSvg), [backgroundSvg]);
213
- const dataUrl = `data:image/svg+xml;base64,${encodedSvg}`;
276
+ const dataUrl = useMemo(() => `data:image/svg+xml;base64,${globalThis.btoa(backgroundSvg)}`, [backgroundSvg]);
214
277
  return dataUrl;
215
278
  };
@@ -1,6 +1,6 @@
1
1
  import { type CSSProperties, useMemo } from 'react';
2
2
 
3
- import { useAppLayout } from 'hooks';
3
+ import { useAppLayout } from 'app-layout';
4
4
  import { getTileSizes } from 'lib';
5
5
  import { BORDER_WIDTH } from 'parameters';
6
6
  import { selectConfig, selectShowCoordinates, useTypedSelector } from 'state';
@@ -1,6 +1,6 @@
1
1
  import { autoUpdate, offset, shift, useFloating } from '@floating-ui/react';
2
2
 
3
- import { useAppLayout } from 'hooks';
3
+ import { useAppLayout } from 'app-layout';
4
4
  import { BOARD_CELL_ACTIONS_OFFSET } from 'parameters';
5
5
 
6
6
  export const useFloatingActions = () => {
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { type FunctionComponent } from 'react';
3
3
 
4
- import { useAppLayout } from 'hooks';
4
+ import { useAppLayout } from 'app-layout';
5
5
  import {
6
6
  selectDictionaryError,
7
7
  selectDictionaryIsLoading,
@@ -1,5 +1,5 @@
1
1
  import classNames from 'classnames';
2
- import { type ChangeEvent, type FormEvent, type FunctionComponent } from 'react';
2
+ import { type ChangeEvent, type FunctionComponent, type SubmitEvent } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
5
  import { LOCALE_FEATURES } from 'i18n';
@@ -22,7 +22,7 @@ export const DictionaryInput: FunctionComponent<Props> = ({ className }) => {
22
22
  dispatch(dictionarySlice.actions.changeInput(event.target.value));
23
23
  };
24
24
 
25
- const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
25
+ const handleSubmit = (event: SubmitEvent<HTMLFormElement>) => {
26
26
  event.preventDefault();
27
27
  dispatch(dictionarySlice.actions.submit());
28
28
  };
@@ -1,7 +1,7 @@
1
1
  import Image from 'next/image';
2
2
  import { forwardRef } from 'react';
3
3
 
4
- import { useAppLayout } from 'hooks';
4
+ import { useAppLayout } from 'app-layout';
5
5
  import { LOGO_SRC } from 'parameters';
6
6
 
7
7
  interface Props {
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { type FunctionComponent, memo } from 'react';
3
3
 
4
- import { useAppLayout } from 'hooks';
4
+ import { useAppLayout } from 'app-layout';
5
5
  import { CardChecklist, Cog, Eraser, Github, KeyboardFill, List, Sack } from 'icons';
6
6
  import { GITHUB_PROJECT_URL } from 'parameters';
7
7
  import { selectConfig, useTranslate, useTypedSelector } from 'state';
@@ -16,7 +16,7 @@ import {
16
16
  import useOnclickOutside from 'react-cool-onclickoutside';
17
17
  import { useDispatch } from 'react-redux';
18
18
 
19
- import { useAppLayout } from 'hooks';
19
+ import { useAppLayout } from 'app-layout';
20
20
  import { LOCALE_FEATURES } from 'i18n';
21
21
  import { createKeyboardNavigation, extractCharacters, extractInputValue, getTileSizes, isCtrl } from 'lib';
22
22
  import { rackSlice, selectConfig, selectInputMode, selectLocale, selectRack, useTypedSelector } from 'state';
@@ -2,7 +2,7 @@ import classNames from 'classnames';
2
2
  import {
3
3
  type CSSProperties,
4
4
  type ChangeEventHandler,
5
- type FormEventHandler,
5
+ type SubmitEventHandler,
6
6
  forwardRef,
7
7
  useCallback,
8
8
  useEffect,
@@ -10,7 +10,7 @@ import {
10
10
  } from 'react';
11
11
  import { useDispatch } from 'react-redux';
12
12
 
13
- import { useAppLayout } from 'hooks';
13
+ import { useAppLayout } from 'app-layout';
14
14
  import { rackSlice, selectConfig, useTranslate, useTypedSelector } from 'state';
15
15
 
16
16
  import styles from './InputPrompt.module.scss';
@@ -22,7 +22,7 @@ interface Props {
22
22
  value: string;
23
23
  onBlur: () => void;
24
24
  onChange: ChangeEventHandler<HTMLInputElement>;
25
- onSubmit: FormEventHandler<HTMLFormElement>;
25
+ onSubmit: SubmitEventHandler<HTMLFormElement>;
26
26
  }
27
27
 
28
28
  const InputPromptBase = forwardRef<HTMLFormElement, Props>(
@@ -33,7 +33,7 @@ const InputPromptBase = forwardRef<HTMLFormElement, Props>(
33
33
  const config = useTypedSelector(selectConfig);
34
34
  const [inputRef, setInputRef] = useState<HTMLInputElement | null>(null);
35
35
 
36
- const handleSubmit: FormEventHandler<HTMLFormElement> = useCallback(
36
+ const handleSubmit: SubmitEventHandler<HTMLFormElement> = useCallback(
37
37
  (event) => {
38
38
  event.preventDefault();
39
39
  const characters = extractRack(config, value);
@@ -1,6 +1,7 @@
1
1
  import { type FunctionComponent } from 'react';
2
2
 
3
- import { useAppLayout, useColumns } from 'hooks';
3
+ import { useAppLayout } from 'app-layout';
4
+ import { useColumns } from 'hooks';
4
5
  import { GeoAlt, OneTwoThree, Square, SquareA, SquareB, Squares, Words } from 'icons';
5
6
  import { RESULTS_COLUMN_WIDTH } from 'parameters';
6
7
  import { ResultColumnId } from 'types';
@@ -3,7 +3,8 @@ import { type FocusEventHandler, type MouseEventHandler, type ReactElement, useR
3
3
  import Highlighter from 'react-highlight-words';
4
4
  import { type RowComponentProps } from 'react-window';
5
5
 
6
- import { useAppLayout, useColumns } from 'hooks';
6
+ import { useAppLayout } from 'app-layout';
7
+ import { useColumns } from 'hooks';
7
8
  import { LOCALE_FEATURES } from 'i18n';
8
9
  import { noop } from 'lib';
9
10
  import {
@@ -1,5 +1,5 @@
1
1
  import classNames from 'classnames';
2
- import { type ChangeEvent, type FormEventHandler, type FunctionComponent, useState } from 'react';
2
+ import { type ChangeEvent, type FunctionComponent, type SubmitEventHandler, useState } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
5
  import { isRegExp } from 'lib';
@@ -27,7 +27,7 @@ export const ResultsInput: FunctionComponent<Props> = ({ className }) => {
27
27
  }
28
28
  };
29
29
 
30
- const handleSubmit: FormEventHandler = (event) => {
30
+ const handleSubmit: SubmitEventHandler = (event) => {
31
31
  event.preventDefault();
32
32
  };
33
33
 
@@ -3,7 +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, useIsTouchDevice } from 'hooks';
6
+ import { useAppLayout } from 'app-layout';
7
+ import { useIsTouchDevice } from 'hooks';
7
8
  import {
8
9
  resultsSlice,
9
10
  selectAreResultsOutdated,
@@ -13,7 +13,7 @@ import {
13
13
  useRef,
14
14
  } from 'react';
15
15
 
16
- import { useAppLayout } from 'hooks';
16
+ import { useAppLayout } from 'app-layout';
17
17
  import { getTileSizes, noop } from 'lib';
18
18
  import { selectLocale, useTypedSelector } from 'state';
19
19
 
@@ -1,4 +1,3 @@
1
- export { useAppLayout } from './useAppLayout';
2
1
  export { useColumns } from './useColumns';
3
2
  export { useDirection } from './useDirection';
4
3
  export { useEffectOnce } from './useEffectOnce';
@@ -3,6 +3,5 @@ export const isMac = (): boolean => {
3
3
  return false;
4
4
  }
5
5
 
6
- // eslint-disable-next-line @typescript-eslint/no-deprecated
7
6
  return globalThis.navigator.platform.startsWith('Mac') || globalThis.navigator.platform === 'iPhone';
8
7
  };
@@ -2,8 +2,8 @@ import { type Result } from '@scrabble-solver/types';
2
2
  import { type FunctionComponent, memo, useEffect, useMemo } from 'react';
3
3
  import { useDispatch } from 'react-redux';
4
4
 
5
+ import { useAppLayout } from 'app-layout';
5
6
  import { Button, Dictionary, Modal, Results } from 'components';
6
- import { useAppLayout } from 'hooks';
7
7
  import { Check, EyeFill } from 'icons';
8
8
  import { resultsSlice, selectProcessedResults, selectResultCandidate, useTranslate, useTypedSelector } from 'state';
9
9
 
@@ -4,6 +4,7 @@ import Head from 'next/head';
4
4
  import { type FunctionComponent } from 'react';
5
5
  import { Provider } from 'react-redux';
6
6
 
7
+ import { AppLayoutProvider } from 'app-layout';
7
8
  import { SeoMessage } from 'components';
8
9
  import { store } from 'state';
9
10
 
@@ -77,11 +78,13 @@ const App: FunctionComponent<AppProps> = ({ Component, pageProps }) => (
77
78
  </Head>
78
79
 
79
80
  <Provider store={store}>
80
- <SeoMessage />
81
+ <AppLayoutProvider>
82
+ <SeoMessage />
81
83
 
82
- <FloatingDelayGroup delay={0}>
83
- <Component {...pageProps} />
84
- </FloatingDelayGroup>
84
+ <FloatingDelayGroup delay={0}>
85
+ <Component {...pageProps} />
86
+ </FloatingDelayGroup>
87
+ </AppLayoutProvider>
85
88
  </Provider>
86
89
  </>
87
90
  );