scrabble-solver 2.11.4 → 2.11.6
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.
- package/README.md +1 -1
- package/lerna.json +1 -1
- package/nx.json +19 -0
- package/package.json +7 -7
- package/packages/configs/package.json +3 -3
- package/packages/constants/package.json +1 -1
- package/packages/dictionaries/package-lock.json +3 -10
- package/packages/dictionaries/package.json +4 -4
- package/packages/logger/package-lock.json +3 -224
- package/packages/logger/package.json +1 -1
- package/packages/scrabble-solver/.next/BUILD_ID +1 -1
- package/packages/scrabble-solver/.next/build-manifest.json +7 -7
- package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
- package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
- package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
- package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
- package/packages/scrabble-solver/.next/export-marker.json +1 -1
- package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
- package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
- package/packages/scrabble-solver/.next/server/chunks/131.js +1 -1
- package/packages/scrabble-solver/.next/server/chunks/277.js +851 -1179
- package/packages/scrabble-solver/.next/server/chunks/636.js +286 -0
- package/packages/scrabble-solver/.next/server/chunks/675.js +550 -0
- package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/404.html +1 -5
- package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/_app.js +73 -9
- package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/_document.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/_error.js +1 -280
- package/packages/scrabble-solver/.next/server/pages/_error.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/api/solve.js +22 -2
- package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.js +381 -314
- package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
- package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
- package/packages/scrabble-solver/.next/static/Jmk00rVXCbdjFgP77tKXQ/_buildManifest.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/{404-448ba28510855455.js → 404-8176f4acd0cfeb42.js} +1 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-b4fa92112b8f0385.js +28 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/index-ccd762f8f5028729.js +1 -0
- package/packages/scrabble-solver/.next/static/css/1cd302e7648d209c.css +2 -0
- package/packages/scrabble-solver/.next/static/css/34adfcf12a7d9bb6.css +1 -0
- package/packages/scrabble-solver/.next/trace +50 -53
- package/packages/scrabble-solver/next.config.js +1 -0
- package/packages/scrabble-solver/package-lock.json +137 -5220
- package/packages/scrabble-solver/package.json +11 -12
- package/packages/scrabble-solver/src/@types/svg.d.ts +1 -1
- package/packages/scrabble-solver/src/components/Board/Board.tsx +48 -44
- package/packages/scrabble-solver/src/components/Board/components/Actions/Actions.tsx +4 -2
- package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +59 -5
- package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +5 -3
- package/packages/scrabble-solver/src/components/Button/Button.module.scss +1 -1
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +0 -1
- package/packages/scrabble-solver/src/components/EmptyState/EmptyState.module.scss +0 -1
- package/packages/scrabble-solver/src/components/Key/Key.module.scss +1 -1
- package/packages/scrabble-solver/src/components/Loading/Loading.module.scss +1 -1
- package/packages/scrabble-solver/src/components/Loading/Loading.tsx +1 -1
- package/packages/scrabble-solver/src/components/Logo/Logo.tsx +10 -12
- package/packages/scrabble-solver/src/components/Logo/LogoBlueprint.tsx +21 -0
- package/packages/scrabble-solver/src/components/Logo/index.ts +1 -1
- package/packages/scrabble-solver/src/components/Modal/Modal.module.scss +1 -6
- package/packages/scrabble-solver/src/components/Modal/Modal.tsx +15 -8
- package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +2 -2
- package/packages/scrabble-solver/src/components/PlainTiles/PlainTiles.tsx +0 -10
- package/packages/scrabble-solver/src/components/PlainTiles/Tile.tsx +1 -4
- package/packages/scrabble-solver/src/components/Rack/Rack.module.scss +59 -0
- package/packages/scrabble-solver/src/components/Results/HeaderButton.tsx +6 -6
- package/packages/scrabble-solver/src/components/Results/Results.module.scss +3 -1
- package/packages/scrabble-solver/src/components/Results/Results.tsx +7 -7
- package/packages/scrabble-solver/src/components/Results/useColumns.ts +2 -5
- package/packages/scrabble-solver/src/components/Solver/Solver.tsx +6 -23
- package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +2 -1
- package/packages/scrabble-solver/src/components/Tile/Tile.tsx +8 -4
- package/packages/scrabble-solver/src/components/index.ts +0 -5
- package/packages/scrabble-solver/src/hooks/index.ts +6 -0
- package/packages/scrabble-solver/src/hooks/useAppLayout.ts +62 -12
- package/packages/scrabble-solver/src/hooks/useDirection.ts +2 -2
- package/packages/scrabble-solver/src/hooks/useEffectOnce.ts +5 -0
- package/packages/scrabble-solver/src/hooks/useIsTouchDevice.ts +1 -1
- package/packages/scrabble-solver/src/hooks/useLanguage.ts +2 -2
- package/packages/scrabble-solver/src/hooks/useLatest.ts +13 -0
- package/packages/scrabble-solver/src/hooks/useLocalStorage.ts +51 -0
- package/packages/scrabble-solver/src/hooks/useMedia.ts +36 -0
- package/packages/scrabble-solver/src/hooks/useMediaQueries.ts +13 -0
- package/packages/scrabble-solver/src/hooks/useMediaQuery.ts +2 -1
- package/packages/scrabble-solver/src/hooks/useOnWindowResize.ts +13 -0
- package/packages/scrabble-solver/src/hooks/useViewportSize.ts +19 -0
- package/packages/scrabble-solver/src/i18n/constants.ts +14 -22
- package/packages/scrabble-solver/src/lib/arrayEquals.ts +5 -0
- package/packages/scrabble-solver/src/lib/index.ts +1 -0
- package/packages/scrabble-solver/src/lib/zipCharactersAndTiles.ts +3 -1
- package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.tsx +2 -2
- package/packages/scrabble-solver/src/modals/KeyMapModal/KeyMapModal.tsx +2 -2
- package/packages/scrabble-solver/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +0 -1
- package/packages/scrabble-solver/src/modals/KeyMapModal/keys.tsx +0 -2
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss +28 -4
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +4 -4
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/RemainingTilesModal.tsx +2 -2
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.module.scss +1 -5
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.tsx +10 -2
- package/packages/scrabble-solver/src/modals/SettingsModal/SettingsModal.tsx +2 -2
- package/packages/scrabble-solver/src/modals/SettingsModal/components/AutoGroupTilesSetting/lib.ts +3 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.module.scss +0 -1
- package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +1 -6
- package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.tsx +2 -2
- package/packages/scrabble-solver/src/pages/index.module.scss +3 -21
- package/packages/scrabble-solver/src/pages/index.tsx +51 -69
- package/packages/scrabble-solver/src/parameters/index.ts +29 -2
- package/packages/scrabble-solver/src/state/localStorage.ts +13 -2
- package/packages/scrabble-solver/src/state/sagas.ts +16 -8
- package/packages/scrabble-solver/src/state/slices/boardInitialState.ts +5 -1
- package/packages/scrabble-solver/src/state/slices/boardSlice.ts +2 -2
- package/packages/scrabble-solver/src/state/slices/rackInitialState.ts +8 -2
- package/packages/scrabble-solver/src/state/slices/rackSlice.ts +16 -13
- package/packages/scrabble-solver/src/state/slices/settingsInitialState.ts +9 -4
- package/packages/scrabble-solver/src/state/slices/settingsSlice.ts +3 -1
- package/packages/scrabble-solver/src/styles/animations.scss +0 -20
- package/packages/scrabble-solver/src/styles/global.scss +4 -15
- package/packages/scrabble-solver/src/styles/mixins.scss +0 -60
- package/packages/scrabble-solver/src/styles/variables.scss +14 -5
- package/packages/scrabble-solver/src/types/index.ts +4 -0
- package/packages/solver/package-lock.json +3 -10
- package/packages/solver/package.json +5 -5
- package/packages/types/package.json +2 -2
- package/packages/word-definitions/package-lock.json +3 -153
- package/packages/word-definitions/package.json +2 -2
- package/packages/word-lists/package-lock.json +9 -401
- package/packages/word-lists/package.json +2 -2
- package/packages/scrabble-solver/.next/static/MvHZRF4XuJ7g8LLLRkf8U/_buildManifest.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-66d80a5594aab8dc.js +0 -28
- package/packages/scrabble-solver/.next/static/chunks/pages/index-0858deea02b2a417.js +0 -1
- package/packages/scrabble-solver/.next/static/css/885da289cec275b3.css +0 -1
- package/packages/scrabble-solver/.next/static/css/ea1c8134fe9a143e.css +0 -2
- package/packages/scrabble-solver/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +0 -65
- package/packages/scrabble-solver/src/components/LogoSplashScreen/LogoSplashScreen.tsx +0 -31
- package/packages/scrabble-solver/src/components/LogoSplashScreen/index.ts +0 -1
- package/packages/scrabble-solver/src/components/Sizer/Sizer.module.scss +0 -10
- package/packages/scrabble-solver/src/components/Sizer/Sizer.tsx +0 -10
- package/packages/scrabble-solver/src/components/Sizer/index.ts +0 -1
- package/packages/scrabble-solver/src/components/SplashScreen/SplashScreen.module.scss +0 -14
- package/packages/scrabble-solver/src/components/SplashScreen/SplashScreen.tsx +0 -19
- package/packages/scrabble-solver/src/components/SplashScreen/index.ts +0 -1
- package/packages/scrabble-solver/src/components/SvgFontCss/SvgFontCss.tsx +0 -14
- package/packages/scrabble-solver/src/components/SvgFontCss/createCss.ts +0 -11
- package/packages/scrabble-solver/src/components/SvgFontCss/createStyle.ts +0 -9
- package/packages/scrabble-solver/src/components/SvgFontCss/createSvg.ts +0 -10
- package/packages/scrabble-solver/src/components/SvgFontCss/index.ts +0 -1
- package/packages/scrabble-solver/src/components/SvgFontFix/SvgFontFix.module.scss +0 -5
- package/packages/scrabble-solver/src/components/SvgFontFix/SvgFontFix.tsx +0 -21
- package/packages/scrabble-solver/src/components/SvgFontFix/index.ts +0 -1
- package/packages/scrabble-solver/src/hooks/useLocalStorage/index.ts +0 -1
- package/packages/scrabble-solver/src/hooks/useLocalStorage/useLocalStorage.ts +0 -13
- package/packages/scrabble-solver/src/hooks/useLocalStorage/useLocalStorageBoard.ts +0 -29
- package/packages/scrabble-solver/src/hooks/useLocalStorage/useLocalStorageConfigId.ts +0 -29
- package/packages/scrabble-solver/src/hooks/useLocalStorage/useLocalStorageLocale.ts +0 -32
- package/packages/scrabble-solver/src/hooks/useLocalStorage/useLocalStorageRack.ts +0 -29
- /package/packages/scrabble-solver/.next/static/{MvHZRF4XuJ7g8LLLRkf8U → Jmk00rVXCbdjFgP77tKXQ}/_ssgManifest.js +0 -0
- /package/packages/scrabble-solver/{src/components/Logo/Logo.svg → public/logo.svg} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/scrabble-solver",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.6",
|
|
4
4
|
"description": "Scrabble Solver 2 - App",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16"
|
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
"start": "env-cmd next start -p 3333"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@floating-ui/react": "^0.
|
|
31
|
+
"@floating-ui/react": "^0.21.1",
|
|
32
32
|
"@kamilmielnik/trie": "^2.0.1",
|
|
33
33
|
"@reduxjs/toolkit": "^1.9.3",
|
|
34
|
-
"@scrabble-solver/configs": "^2.11.
|
|
35
|
-
"@scrabble-solver/constants": "^2.11.
|
|
36
|
-
"@scrabble-solver/dictionaries": "^2.11.
|
|
37
|
-
"@scrabble-solver/logger": "^2.11.
|
|
38
|
-
"@scrabble-solver/solver": "^2.11.
|
|
39
|
-
"@scrabble-solver/types": "^2.11.
|
|
40
|
-
"@scrabble-solver/word-definitions": "^2.11.
|
|
34
|
+
"@scrabble-solver/configs": "^2.11.6",
|
|
35
|
+
"@scrabble-solver/constants": "^2.11.6",
|
|
36
|
+
"@scrabble-solver/dictionaries": "^2.11.6",
|
|
37
|
+
"@scrabble-solver/logger": "^2.11.6",
|
|
38
|
+
"@scrabble-solver/solver": "^2.11.6",
|
|
39
|
+
"@scrabble-solver/types": "^2.11.6",
|
|
40
|
+
"@scrabble-solver/word-definitions": "^2.11.6",
|
|
41
41
|
"classnames": "^2.3.2",
|
|
42
42
|
"include-media": "^2.0.0",
|
|
43
43
|
"include-media-query-builder": "^1.1.0",
|
|
@@ -48,9 +48,8 @@
|
|
|
48
48
|
"react-modal": "^3.16.1",
|
|
49
49
|
"react-portal": "^4.2.2",
|
|
50
50
|
"react-redux": "^8.0.5",
|
|
51
|
-
"react-use": "^17.4.0",
|
|
52
51
|
"react-window": "^1.8.8",
|
|
53
|
-
"redux-saga": "^1.2.
|
|
52
|
+
"redux-saga": "^1.2.3",
|
|
54
53
|
"store2": "^2.14.2",
|
|
55
54
|
"workbox-expiration": "^6.5.4",
|
|
56
55
|
"workbox-precaching": "^6.5.4",
|
|
@@ -69,7 +68,7 @@
|
|
|
69
68
|
"@types/redux": "^3.6.31",
|
|
70
69
|
"@types/redux-saga": "^0.10.5",
|
|
71
70
|
"env-cmd": "^10.1.0",
|
|
72
|
-
"sass": "^1.59.
|
|
71
|
+
"sass": "^1.59.3",
|
|
73
72
|
"workbox-webpack-plugin": "^6.5.4"
|
|
74
73
|
},
|
|
75
74
|
"gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { autoUpdate, FloatingPortal, offset, shift, useFloating
|
|
1
|
+
import { autoUpdate, FloatingPortal, offset, shift, useFloating } from '@floating-ui/react';
|
|
2
2
|
import classNames from 'classnames';
|
|
3
|
-
import { CSSProperties, FocusEventHandler, FunctionComponent, useState } from 'react';
|
|
3
|
+
import { CSSProperties, FocusEventHandler, FunctionComponent, useCallback, useState } from 'react';
|
|
4
4
|
import { useDispatch } from 'react-redux';
|
|
5
|
-
import { useMeasure } from 'react-use';
|
|
6
5
|
|
|
6
|
+
import { useAppLayout } from 'hooks';
|
|
7
7
|
import { BOARD_CELL_ACTIONS_OFFSET, TRANSITION } from 'parameters';
|
|
8
8
|
import { boardSlice, cellFilterSlice, selectBoard, selectRowsWithCandidate, useTypedSelector } from 'state';
|
|
9
9
|
|
|
@@ -21,7 +21,7 @@ const Board: FunctionComponent<Props> = ({ cellSize, className }) => {
|
|
|
21
21
|
const dispatch = useDispatch();
|
|
22
22
|
const rows = useTypedSelector(selectRowsWithCandidate);
|
|
23
23
|
const board = useTypedSelector(selectBoard);
|
|
24
|
-
const
|
|
24
|
+
const { actionsWidth } = useAppLayout();
|
|
25
25
|
const [{ activeIndex, direction, inputRefs }, { onChange, onDirectionToggle, onFocus, onKeyDown, onPaste }] =
|
|
26
26
|
useGrid(rows);
|
|
27
27
|
const inputRef = inputRefs[activeIndex.y][activeIndex.x];
|
|
@@ -41,53 +41,57 @@ const Board: FunctionComponent<Props> = ({ cellSize, className }) => {
|
|
|
41
41
|
whileElementsMounted: autoUpdate,
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
44
|
+
const handleBlur: FocusEventHandler = useCallback(
|
|
45
|
+
(event) => {
|
|
46
|
+
const eventComesFromActions = refs.floating.current?.contains(event.relatedTarget);
|
|
47
|
+
const eventComesFromBoard = event.currentTarget.contains(event.relatedTarget);
|
|
48
|
+
const isLocalEvent = eventComesFromActions || eventComesFromBoard;
|
|
49
|
+
|
|
50
|
+
if (!isLocalEvent) {
|
|
51
|
+
setShowActions(false);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
[refs.floating],
|
|
55
|
+
);
|
|
55
56
|
|
|
56
|
-
const handleDirectionToggle = () => {
|
|
57
|
+
const handleDirectionToggle = useCallback(() => {
|
|
57
58
|
inputRef.current?.focus();
|
|
58
59
|
onDirectionToggle();
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const handleFocus: typeof onFocus = (
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
60
|
+
}, [inputRef, onDirectionToggle]);
|
|
61
|
+
|
|
62
|
+
const handleFocus: typeof onFocus = useCallback(
|
|
63
|
+
(newX, newY) => {
|
|
64
|
+
const isFirstFocus = !showActions;
|
|
65
|
+
const originalTransition = refs.floating.current?.style.transition || '';
|
|
66
|
+
const newInputRef = inputRefs[newY][newX].current;
|
|
67
|
+
const newTileElement = newInputRef?.parentElement || null;
|
|
68
|
+
|
|
69
|
+
if (isFirstFocus) {
|
|
70
|
+
setTransition('none');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
refs.setReference(newTileElement);
|
|
74
|
+
onFocus(newX, newY);
|
|
75
|
+
setShowActions(true);
|
|
76
|
+
|
|
77
|
+
if (isFirstFocus) {
|
|
78
|
+
setTimeout(() => {
|
|
79
|
+
setTransition(originalTransition);
|
|
80
|
+
}, 0);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
[inputRefs, onFocus, refs.floating, refs.setReference, showActions],
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const handleToggleBlank = useCallback(() => {
|
|
83
87
|
inputRef.current?.focus();
|
|
84
88
|
dispatch(boardSlice.actions.toggleCellIsBlank(cell));
|
|
85
|
-
};
|
|
89
|
+
}, [cell, dispatch, inputRef]);
|
|
86
90
|
|
|
87
|
-
const handleToggleFilterCell = () => {
|
|
91
|
+
const handleToggleFilterCell = useCallback(() => {
|
|
88
92
|
inputRef.current?.focus();
|
|
89
93
|
dispatch(cellFilterSlice.actions.toggle(cell));
|
|
90
|
-
};
|
|
94
|
+
}, [cell, dispatch, inputRef]);
|
|
91
95
|
|
|
92
96
|
return (
|
|
93
97
|
<>
|
|
@@ -112,7 +116,7 @@ const Board: FunctionComponent<Props> = ({ cellSize, className }) => {
|
|
|
112
116
|
})}
|
|
113
117
|
disabled={!showActions}
|
|
114
118
|
direction={direction}
|
|
115
|
-
ref={
|
|
119
|
+
ref={refs.setFloating}
|
|
116
120
|
style={{
|
|
117
121
|
position: strategy,
|
|
118
122
|
top: y ?? 0,
|
|
@@ -4,7 +4,8 @@ import classNames from 'classnames';
|
|
|
4
4
|
import { forwardRef, HTMLProps, MouseEventHandler } from 'react';
|
|
5
5
|
|
|
6
6
|
import { ArrowDown, Flag, FlagFill, Square, SquareFill } from 'icons';
|
|
7
|
-
import {
|
|
7
|
+
import { findCell } from 'lib';
|
|
8
|
+
import { selectCellIsFiltered, selectResultCandidateCells, useTranslate, useTypedSelector } from 'state';
|
|
8
9
|
|
|
9
10
|
import Button from '../../../Button';
|
|
10
11
|
|
|
@@ -22,8 +23,9 @@ const Actions = forwardRef<HTMLDivElement, Props>(
|
|
|
22
23
|
({ cell, className, direction, disabled, onDirectionToggle, onToggleBlank, onToggleFilterCell, ...props }, ref) => {
|
|
23
24
|
const translate = useTranslate();
|
|
24
25
|
const isFiltered = useTypedSelector((state) => selectCellIsFiltered(state, cell));
|
|
26
|
+
const resultCandidateCells = useTypedSelector(selectResultCandidateCells);
|
|
25
27
|
const isBlank = cell.tile.isBlank;
|
|
26
|
-
const isEmpty = cell.tile.character === EMPTY_CELL;
|
|
28
|
+
const isEmpty = cell.tile.character === EMPTY_CELL || Boolean(findCell(resultCandidateCells, cell.x, cell.y));
|
|
27
29
|
|
|
28
30
|
// On iOS it helps with losing focus too early which makes Actions disappear
|
|
29
31
|
const handleMouseDown: MouseEventHandler = (event) => event.preventDefault();
|
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
@import 'styles/mixins';
|
|
2
2
|
|
|
3
|
+
@mixin lighthouse-input-size-hack {
|
|
4
|
+
// Hack for this Lighthouse warning:
|
|
5
|
+
// > Interactive elements like buttons and links should be large enough (48x48px), and have
|
|
6
|
+
// > enough space around them, to be easy enough to tap without overlapping onto other elements.
|
|
7
|
+
|
|
8
|
+
input {
|
|
9
|
+
position: absolute;
|
|
10
|
+
top: -100%;
|
|
11
|
+
right: -100%;
|
|
12
|
+
left: -100%;
|
|
13
|
+
bottom: -100%;
|
|
14
|
+
width: 300%;
|
|
15
|
+
height: 300%;
|
|
16
|
+
clip-path: inset((100% / 3));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[dir='ltr'] & {
|
|
20
|
+
&:nth-child(1),
|
|
21
|
+
&:nth-child(2),
|
|
22
|
+
&:nth-child(3) {
|
|
23
|
+
input {
|
|
24
|
+
left: 0;
|
|
25
|
+
clip-path: polygon(0 (100% / 3), (100% / 3) (100% / 3), (100% / 3) (200% / 3), 0 (200% / 3));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&:nth-last-child(1),
|
|
30
|
+
&:nth-last-child(2),
|
|
31
|
+
&:nth-last-child(3) {
|
|
32
|
+
input {
|
|
33
|
+
left: -200%;
|
|
34
|
+
clip-path: polygon((200% / 3) (100% / 3), 100% (100% / 3), 100% (200% / 3), (200% / 3) (200% / 3));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[dir='rtl'] & {
|
|
40
|
+
&:nth-child(1),
|
|
41
|
+
&:nth-child(2),
|
|
42
|
+
&:nth-child(3) {
|
|
43
|
+
input {
|
|
44
|
+
left: -200%;
|
|
45
|
+
right: 0;
|
|
46
|
+
clip-path: polygon((200% / 3) (100% / 3), 100% (100% / 3), 100% (200% / 3), (200% / 3) (200% / 3));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&:nth-last-child(1),
|
|
51
|
+
&:nth-last-child(2),
|
|
52
|
+
&:nth-last-child(3) {
|
|
53
|
+
input {
|
|
54
|
+
left: 0;
|
|
55
|
+
right: -200%;
|
|
56
|
+
clip-path: polygon(0 (100% / 3), (100% / 3) (100% / 3), (100% / 3) (200% / 3), 0 (200% / 3));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
3
62
|
.cell {
|
|
4
63
|
@include focus-effect;
|
|
5
64
|
@include lighthouse-input-size-hack;
|
|
@@ -9,7 +68,6 @@
|
|
|
9
68
|
vertical-align: middle;
|
|
10
69
|
background-color: var(--color--white);
|
|
11
70
|
border-bottom: var(--border--width) dotted var(--border--color--light);
|
|
12
|
-
transition: var(--transition);
|
|
13
71
|
background-clip: padding-box;
|
|
14
72
|
|
|
15
73
|
[dir='ltr'] & {
|
|
@@ -121,10 +179,6 @@
|
|
|
121
179
|
font-weight: bold;
|
|
122
180
|
color: var(--color--white);
|
|
123
181
|
transition: var(--transition);
|
|
124
|
-
|
|
125
|
-
[lang='fa-IR'] & {
|
|
126
|
-
font-family: var(--font--family--latin);
|
|
127
|
-
}
|
|
128
182
|
}
|
|
129
183
|
|
|
130
184
|
&:focus-within {
|
|
@@ -14,8 +14,8 @@ import {
|
|
|
14
14
|
useState,
|
|
15
15
|
} from 'react';
|
|
16
16
|
import { useDispatch } from 'react-redux';
|
|
17
|
-
import { useLatest } from 'react-use';
|
|
18
17
|
|
|
18
|
+
import { useLatest } from 'hooks';
|
|
19
19
|
import { LOCALE_FEATURES } from 'i18n';
|
|
20
20
|
import { createGridOf, createKeyboardNavigation, extractCharacters, extractInputValue } from 'lib';
|
|
21
21
|
import { boardSlice, selectConfig, selectLocale, useTypedSelector } from 'state';
|
|
@@ -235,6 +235,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
235
235
|
|
|
236
236
|
if (direction === 'vertical') {
|
|
237
237
|
onDirectionToggle();
|
|
238
|
+
changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? -1 : 0, 0);
|
|
238
239
|
} else {
|
|
239
240
|
changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? -1 : 1, 0);
|
|
240
241
|
}
|
|
@@ -244,6 +245,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
244
245
|
|
|
245
246
|
if (direction === 'vertical') {
|
|
246
247
|
onDirectionToggle();
|
|
248
|
+
changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? 0 : -1, 0);
|
|
247
249
|
} else {
|
|
248
250
|
changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? 1 : -1, 0);
|
|
249
251
|
}
|
|
@@ -253,9 +255,9 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
253
255
|
|
|
254
256
|
if (direction === 'horizontal') {
|
|
255
257
|
onDirectionToggle();
|
|
256
|
-
} else {
|
|
257
|
-
changeActiveIndex(0, -1);
|
|
258
258
|
}
|
|
259
|
+
|
|
260
|
+
changeActiveIndex(0, -1);
|
|
259
261
|
},
|
|
260
262
|
onBackspace: (event) => {
|
|
261
263
|
const position = getInputRefPosition(event.target as HTMLInputElement);
|
|
@@ -31,7 +31,7 @@ const Loading: FunctionComponent<Props> = ({ className, wave = true }) => {
|
|
|
31
31
|
return (
|
|
32
32
|
<div aria-label={translation} className={classNames(styles.loading, className)} role="status">
|
|
33
33
|
<div className={styles.dim} />
|
|
34
|
-
<div className={styles.
|
|
34
|
+
<div className={styles.text}>
|
|
35
35
|
<PlainTiles className={classNames(styles.tiles)} content={content} dropShadow wave={wave} />
|
|
36
36
|
</div>
|
|
37
37
|
</div>
|
|
@@ -1,21 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* Logo.svg is what this component generates with all the text nodes transformed
|
|
4
|
-
* into paths (manually with Inkscape), and corner radius removed from tiles.
|
|
5
|
-
*/
|
|
6
|
-
import { CSSProperties, FunctionComponent } from 'react';
|
|
1
|
+
import Image from 'next/image';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
7
3
|
|
|
8
|
-
import
|
|
4
|
+
import { useAppLayout } from 'hooks';
|
|
5
|
+
import { LOGO_SRC } from 'parameters';
|
|
9
6
|
|
|
10
7
|
interface Props {
|
|
11
8
|
className?: string;
|
|
12
|
-
style?: CSSProperties;
|
|
13
9
|
}
|
|
14
10
|
|
|
15
|
-
const
|
|
11
|
+
const Logo = forwardRef<HTMLImageElement, Props>((props, ref) => {
|
|
12
|
+
const { logoHeight, logoWidth } = useAppLayout();
|
|
16
13
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
14
|
+
return (
|
|
15
|
+
<Image {...props} alt="Scrabble Solver 2" height={logoHeight} priority ref={ref} src={LOGO_SRC} width={logoWidth} />
|
|
16
|
+
);
|
|
17
|
+
});
|
|
20
18
|
|
|
21
19
|
export default Logo;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This component is unused, but it serves as a blueprint for the Logo.svg.
|
|
3
|
+
* Logo.svg is what this component generates with all the text nodes transformed
|
|
4
|
+
* into paths (manually with Inkscape), and corner radius removed from tiles.
|
|
5
|
+
*/
|
|
6
|
+
import { CSSProperties, FunctionComponent } from 'react';
|
|
7
|
+
|
|
8
|
+
import PlainTiles from '../PlainTiles';
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
className?: string;
|
|
12
|
+
style?: CSSProperties;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const CONTENT = [['SCRABBLE'], ['SOLVER', '2']];
|
|
16
|
+
|
|
17
|
+
const LogoBlueprint: FunctionComponent<Props> = ({ className, style }) => (
|
|
18
|
+
<PlainTiles className={className} content={CONTENT} style={style} />
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export default LogoBlueprint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from './Logo
|
|
1
|
+
export { default } from './Logo';
|
|
@@ -25,10 +25,6 @@
|
|
|
25
25
|
&:focus {
|
|
26
26
|
outline: none;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
@include media('<s') {
|
|
30
|
-
--modal--width: 100%;
|
|
31
|
-
}
|
|
32
28
|
}
|
|
33
29
|
|
|
34
30
|
.afterOpen {
|
|
@@ -126,12 +122,11 @@
|
|
|
126
122
|
flex: 0 0 auto;
|
|
127
123
|
display: flex;
|
|
128
124
|
flex-direction: row-reverse;
|
|
129
|
-
justify-content: space-between;
|
|
130
125
|
gap: var(--spacing--l);
|
|
131
126
|
padding: var(--spacing--l);
|
|
132
127
|
padding-top: 0;
|
|
133
128
|
|
|
134
|
-
@include media('>
|
|
129
|
+
@include media('>l') {
|
|
135
130
|
display: none;
|
|
136
131
|
}
|
|
137
132
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import { FunctionComponent, ReactNode, useEffect, useState } from 'react';
|
|
2
|
+
import { FunctionComponent, ReactNode, useCallback, useEffect, useState } from 'react';
|
|
3
3
|
import ReactModal from 'react-modal';
|
|
4
|
-
import { useKey } from 'react-use';
|
|
5
4
|
|
|
6
5
|
import { CrossSquareFill } from 'icons';
|
|
7
6
|
import { TRANSITION_DURATION_LONG } from 'parameters';
|
|
@@ -25,16 +24,24 @@ const Modal: FunctionComponent<Props> = ({ children, className, footer, isOpen,
|
|
|
25
24
|
const translate = useTranslate();
|
|
26
25
|
const [shouldReturnFocusAfterClose, setShouldReturnFocusAfterClose] = useState(true);
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
const handleEscape = useCallback(
|
|
28
|
+
(event: KeyboardEvent) => {
|
|
29
|
+
if (event.key === 'Escape') {
|
|
30
|
+
setShouldReturnFocusAfterClose(false);
|
|
31
|
+
onClose();
|
|
32
|
+
}
|
|
33
33
|
},
|
|
34
|
-
undefined,
|
|
35
34
|
[onClose],
|
|
36
35
|
);
|
|
37
36
|
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
document.addEventListener('keydown', handleEscape);
|
|
39
|
+
|
|
40
|
+
return () => {
|
|
41
|
+
document.removeEventListener('keydown', handleEscape);
|
|
42
|
+
};
|
|
43
|
+
}, [handleEscape]);
|
|
44
|
+
|
|
38
45
|
useEffect(() => {
|
|
39
46
|
if (isOpen) {
|
|
40
47
|
setShouldReturnFocusAfterClose(true);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
|
-
import { FunctionComponent } from 'react';
|
|
2
|
+
import { FunctionComponent, memo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { useAppLayout } from 'hooks';
|
|
5
5
|
import { CardChecklist, Cog, Eraser, Github, Keyboard, List, Sack } from 'icons';
|
|
@@ -135,4 +135,4 @@ const NavButtons: FunctionComponent<Props> = ({
|
|
|
135
135
|
);
|
|
136
136
|
};
|
|
137
137
|
|
|
138
|
-
export default NavButtons;
|
|
138
|
+
export default memo(NavButtons);
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import classNames from 'classnames';
|
|
2
2
|
import { CSSProperties, FunctionComponent, useMemo } from 'react';
|
|
3
3
|
|
|
4
|
-
import { LOCALE_FEATURES } from 'i18n';
|
|
5
|
-
import { selectLocale, useTypedSelector } from 'state';
|
|
6
|
-
|
|
7
|
-
import SvgFontCss from '../SvgFontCss';
|
|
8
|
-
|
|
9
4
|
import { createPlainTiles, getViewbox } from './lib';
|
|
10
5
|
import styles from './PlainTiles.module.scss';
|
|
11
6
|
import Tile from './Tile';
|
|
@@ -21,8 +16,6 @@ interface Props {
|
|
|
21
16
|
}
|
|
22
17
|
|
|
23
18
|
const PlainTiles: FunctionComponent<Props> = ({ className, color, content, dropShadow, showPoints, style, wave }) => {
|
|
24
|
-
const locale = useTypedSelector(selectLocale);
|
|
25
|
-
const { fontFamily } = LOCALE_FEATURES[locale];
|
|
26
19
|
const tiles = useMemo(() => createPlainTiles({ color, content, showPoints }), [color, content, showPoints]);
|
|
27
20
|
|
|
28
21
|
return (
|
|
@@ -35,14 +28,11 @@ const PlainTiles: FunctionComponent<Props> = ({ className, color, content, dropS
|
|
|
35
28
|
viewBox={getViewbox(content)}
|
|
36
29
|
xmlns="http://www.w3.org/2000/svg"
|
|
37
30
|
>
|
|
38
|
-
<SvgFontCss fontFamily={fontFamily} />
|
|
39
|
-
|
|
40
31
|
{tiles.map((tile, index) => (
|
|
41
32
|
<Tile
|
|
42
33
|
character={tile.character}
|
|
43
34
|
className={styles.tile}
|
|
44
35
|
color={tile.color}
|
|
45
|
-
fontFamily={fontFamily}
|
|
46
36
|
key={index}
|
|
47
37
|
points={tile.points}
|
|
48
38
|
size={tile.size}
|
|
@@ -4,7 +4,6 @@ interface Props {
|
|
|
4
4
|
character: string;
|
|
5
5
|
className?: string;
|
|
6
6
|
color: string;
|
|
7
|
-
fontFamily: string;
|
|
8
7
|
points?: number;
|
|
9
8
|
size: number;
|
|
10
9
|
transform?: string;
|
|
@@ -12,13 +11,12 @@ interface Props {
|
|
|
12
11
|
y: number;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
const Tile: FunctionComponent<Props> = ({ character, className, color,
|
|
14
|
+
const Tile: FunctionComponent<Props> = ({ character, className, color, points, size, transform, x, y }) => (
|
|
16
15
|
<g className={className} transform={transform}>
|
|
17
16
|
<rect fill={color} height={size} rx={size * 0.15} width={size} x={x} y={y} />
|
|
18
17
|
|
|
19
18
|
<text
|
|
20
19
|
dominantBaseline="central"
|
|
21
|
-
fontFamily={fontFamily}
|
|
22
20
|
fontSize={size * 0.6}
|
|
23
21
|
fontWeight="bold"
|
|
24
22
|
textAnchor="middle"
|
|
@@ -31,7 +29,6 @@ const Tile: FunctionComponent<Props> = ({ character, className, color, fontFamil
|
|
|
31
29
|
{typeof points === 'number' && (
|
|
32
30
|
<text
|
|
33
31
|
dominantBaseline="text-after-edge"
|
|
34
|
-
fontFamily={fontFamily}
|
|
35
32
|
fontSize={size * 0.25}
|
|
36
33
|
fontWeight="bold"
|
|
37
34
|
textAnchor="end"
|
|
@@ -1,5 +1,64 @@
|
|
|
1
1
|
@import 'styles/mixins';
|
|
2
2
|
|
|
3
|
+
@mixin lighthouse-input-size-hack {
|
|
4
|
+
// Hack for this Lighthouse warning:
|
|
5
|
+
// > Interactive elements like buttons and links should be large enough (48x48px), and have
|
|
6
|
+
// > enough space around them, to be easy enough to tap without overlapping onto other elements.
|
|
7
|
+
|
|
8
|
+
input {
|
|
9
|
+
position: absolute;
|
|
10
|
+
top: -200%;
|
|
11
|
+
right: -100%;
|
|
12
|
+
left: -100%;
|
|
13
|
+
bottom: 0;
|
|
14
|
+
width: 300%;
|
|
15
|
+
height: 300%;
|
|
16
|
+
clip-path: polygon((100% / 3) (200% / 3), (200% / 3) (200% / 3), (200% / 3) 100%, (100% / 3) 100%);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
[dir='ltr'] & {
|
|
20
|
+
&:nth-child(1),
|
|
21
|
+
&:nth-child(2),
|
|
22
|
+
&:nth-child(3) {
|
|
23
|
+
input {
|
|
24
|
+
left: 0;
|
|
25
|
+
clip-path: polygon(0 (200% / 3), (100% / 3) (200% / 3), (100% / 3) 100%, 0 100%);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&:nth-last-child(1),
|
|
30
|
+
&:nth-last-child(2),
|
|
31
|
+
&:nth-last-child(3) {
|
|
32
|
+
input {
|
|
33
|
+
left: -200%;
|
|
34
|
+
clip-path: polygon((200% / 3) (200% / 3), 100% (200% / 3), 100% 100%, (200% / 3) 100%);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[dir='rtl'] & {
|
|
40
|
+
&:nth-child(1),
|
|
41
|
+
&:nth-child(2),
|
|
42
|
+
&:nth-child(3) {
|
|
43
|
+
input {
|
|
44
|
+
left: -200%;
|
|
45
|
+
right: 0;
|
|
46
|
+
clip-path: polygon((200% / 3) (200% / 3), 100% (200% / 3), 100% 100%, (200% / 3) 100%);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&:nth-last-child(1),
|
|
51
|
+
&:nth-last-child(2),
|
|
52
|
+
&:nth-last-child(3) {
|
|
53
|
+
input {
|
|
54
|
+
left: 0;
|
|
55
|
+
right: -200%;
|
|
56
|
+
clip-path: polygon(0 (200% / 3), (100% / 3) (200% / 3), (100% / 3) 100%, 0 100%);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
3
62
|
.rack {
|
|
4
63
|
display: flex;
|
|
5
64
|
box-shadow: var(--box-shadow);
|