@scrabble-solver/scrabble-solver 2.10.0 → 2.10.1
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/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +5 -5
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/eslint/.cache_8dgz12 +1 -1
- package/.next/cache/next-server.js.nft.json +1 -1
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/413.js +49 -31
- package/.next/server/chunks/515.js +97 -71
- package/.next/server/chunks/939.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.html +2 -2
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/pages/api/dictionary/[locale]/[word].js +1 -1
- package/.next/server/pages/api/solve.js +20 -23
- package/.next/server/pages/index.html +2 -2
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/index.json +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/static/chunks/368-8b386c3106556f62.js +1 -0
- package/.next/static/chunks/pages/_app-8f0df20f771045ed.js +1 -0
- package/.next/static/hf94cues-LcXZRCpAzQ6w/_buildManifest.js +1 -0
- package/.next/static/{vscqn7BEtAxJteWSwNnas → hf94cues-LcXZRCpAzQ6w}/_ssgManifest.js +0 -0
- package/.next/trace +52 -52
- package/package.json +9 -9
- package/src/components/Board/hooks/useGrid.ts +6 -6
- package/src/components/Rack/Rack.tsx +16 -4
- package/src/components/Results/Results.tsx +2 -2
- package/src/components/Settings/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +2 -2
- package/src/components/Settings/components/LocaleSetting/options.ts +9 -1
- package/src/i18n/fr.json +1 -1
- package/src/lib/getRemainingTilesGroups.ts +24 -26
- package/src/sdk/findWordDefinitions.ts +1 -1
- package/src/state/sagas.ts +19 -5
- package/src/state/selectors.ts +10 -2
- package/.next/static/chunks/368-d423e70be6c0c473.js +0 -1
- package/.next/static/chunks/pages/_app-3f5508a5f544d9eb.js +0 -1
- package/.next/static/vscqn7BEtAxJteWSwNnas/_buildManifest.js +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scrabble-solver/scrabble-solver",
|
|
3
|
-
"version": "2.10.
|
|
3
|
+
"version": "2.10.1",
|
|
4
4
|
"description": "Scrabble Solver 2 - App",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16"
|
|
@@ -31,13 +31,13 @@
|
|
|
31
31
|
"@kamilmielnik/trie": "^2.0.1",
|
|
32
32
|
"@popperjs/core": "^2.11.6",
|
|
33
33
|
"@reduxjs/toolkit": "^1.8.6",
|
|
34
|
-
"@scrabble-solver/configs": "^2.10.
|
|
35
|
-
"@scrabble-solver/constants": "^2.10.
|
|
36
|
-
"@scrabble-solver/dictionaries": "^2.10.
|
|
37
|
-
"@scrabble-solver/logger": "^2.10.
|
|
38
|
-
"@scrabble-solver/solver": "^2.10.
|
|
39
|
-
"@scrabble-solver/types": "^2.10.
|
|
40
|
-
"@scrabble-solver/word-definitions": "^2.10.
|
|
34
|
+
"@scrabble-solver/configs": "^2.10.1",
|
|
35
|
+
"@scrabble-solver/constants": "^2.10.1",
|
|
36
|
+
"@scrabble-solver/dictionaries": "^2.10.1",
|
|
37
|
+
"@scrabble-solver/logger": "^2.10.1",
|
|
38
|
+
"@scrabble-solver/solver": "^2.10.1",
|
|
39
|
+
"@scrabble-solver/types": "^2.10.1",
|
|
40
|
+
"@scrabble-solver/word-definitions": "^2.10.1",
|
|
41
41
|
"classnames": "^2.3.2",
|
|
42
42
|
"next": "^12.3.1",
|
|
43
43
|
"normalize.css": "^8.0.1",
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"sass": "^1.55.0",
|
|
75
75
|
"workbox-webpack-plugin": "^6.5.4"
|
|
76
76
|
},
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "506586e8bb9e71f9f784dabffae2229c587c5e5a"
|
|
78
78
|
}
|
|
@@ -17,8 +17,9 @@ import { useDispatch } from 'react-redux';
|
|
|
17
17
|
import { useLatest } from 'react-use';
|
|
18
18
|
import { AnyAction } from 'redux';
|
|
19
19
|
|
|
20
|
+
import { LOCALE_FEATURES } from 'i18n';
|
|
20
21
|
import { createGridOf, createKeyboardNavigation, extractCharacters, extractInputValue, isCtrl } from 'lib';
|
|
21
|
-
import { boardSlice, selectConfig, useTypedSelector } from 'state';
|
|
22
|
+
import { boardSlice, selectConfig, selectLocale, useTypedSelector } from 'state';
|
|
22
23
|
import { Direction } from 'types';
|
|
23
24
|
|
|
24
25
|
import { getPositionInGrid } from '../lib';
|
|
@@ -44,6 +45,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
44
45
|
const width = rows[0].length;
|
|
45
46
|
const dispatch = useDispatch();
|
|
46
47
|
const config = useTypedSelector(selectConfig);
|
|
48
|
+
const locale = useTypedSelector(selectLocale);
|
|
47
49
|
const refs = useMemo(
|
|
48
50
|
() => createGridOf<RefObject<HTMLInputElement>>(width, height, () => createRef()),
|
|
49
51
|
[width, height],
|
|
@@ -235,8 +237,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
235
237
|
if (isCtrl(event)) {
|
|
236
238
|
onDirectionToggle();
|
|
237
239
|
} else {
|
|
238
|
-
|
|
239
|
-
changeActiveIndex(isRtl ? 1 : -1, 0);
|
|
240
|
+
changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? -1 : 1, 0);
|
|
240
241
|
}
|
|
241
242
|
},
|
|
242
243
|
onArrowRight: (event) => {
|
|
@@ -245,8 +246,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
245
246
|
if (isCtrl(event)) {
|
|
246
247
|
onDirectionToggle();
|
|
247
248
|
} else {
|
|
248
|
-
|
|
249
|
-
changeActiveIndex(isRtl ? -1 : 1, 0);
|
|
249
|
+
changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? 1 : -1, 0);
|
|
250
250
|
}
|
|
251
251
|
},
|
|
252
252
|
onArrowUp: (event) => {
|
|
@@ -333,7 +333,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
|
|
|
333
333
|
dispatch(boardSlice.actions.toggleCellIsBlank(position));
|
|
334
334
|
},
|
|
335
335
|
});
|
|
336
|
-
}, [changeActiveIndex, config, dispatch, onDirectionToggle, rows]);
|
|
336
|
+
}, [changeActiveIndex, config, dispatch, locale, onDirectionToggle, rows]);
|
|
337
337
|
|
|
338
338
|
const onPaste = useCallback<ClipboardEventHandler>(
|
|
339
339
|
(event) => {
|
|
@@ -2,6 +2,7 @@ import classNames from 'classnames';
|
|
|
2
2
|
import { ChangeEvent, ClipboardEvent, createRef, FunctionComponent, useCallback, useMemo, useRef } from 'react';
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
|
|
5
|
+
import { LOCALE_FEATURES } from 'i18n';
|
|
5
6
|
import {
|
|
6
7
|
createArray,
|
|
7
8
|
createKeyboardNavigation,
|
|
@@ -10,7 +11,7 @@ import {
|
|
|
10
11
|
isCtrl,
|
|
11
12
|
zipCharactersAndTiles,
|
|
12
13
|
} from 'lib';
|
|
13
|
-
import { rackSlice, selectConfig, selectRack, selectResultCandidateTiles, useTypedSelector } from 'state';
|
|
14
|
+
import { rackSlice, selectConfig, selectLocale, selectRack, selectResultCandidateTiles, useTypedSelector } from 'state';
|
|
14
15
|
|
|
15
16
|
import styles from './Rack.module.scss';
|
|
16
17
|
import RackTile from './RackTile';
|
|
@@ -22,12 +23,14 @@ interface Props {
|
|
|
22
23
|
const Rack: FunctionComponent<Props> = ({ className }) => {
|
|
23
24
|
const dispatch = useDispatch();
|
|
24
25
|
const config = useTypedSelector(selectConfig);
|
|
26
|
+
const locale = useTypedSelector(selectLocale);
|
|
25
27
|
const rack = useTypedSelector(selectRack);
|
|
26
28
|
const resultCandidateTiles = useTypedSelector(selectResultCandidateTiles);
|
|
27
29
|
const tiles = useMemo(() => zipCharactersAndTiles(rack, resultCandidateTiles), [rack, resultCandidateTiles]);
|
|
28
30
|
const tilesCount = tiles.length;
|
|
29
31
|
const tilesRefs = useMemo(() => createArray(tilesCount).map(() => createRef<HTMLInputElement>()), [tilesCount]);
|
|
30
32
|
const activeIndexRef = useRef<number>();
|
|
33
|
+
const { direction } = LOCALE_FEATURES[locale];
|
|
31
34
|
|
|
32
35
|
const changeActiveIndex = useCallback(
|
|
33
36
|
(offset: number) => {
|
|
@@ -73,18 +76,27 @@ const Rack: FunctionComponent<Props> = ({ className }) => {
|
|
|
73
76
|
return createKeyboardNavigation({
|
|
74
77
|
onArrowLeft: (event) => {
|
|
75
78
|
event.preventDefault();
|
|
76
|
-
const direction = document.body.parentElement?.dir || 'ltr';
|
|
77
79
|
changeActiveIndex(direction === 'ltr' ? -1 : 1);
|
|
78
80
|
},
|
|
79
81
|
onArrowRight: (event) => {
|
|
80
82
|
event.preventDefault();
|
|
81
|
-
const direction = document.body.parentElement?.dir || 'ltr';
|
|
82
83
|
changeActiveIndex(direction === 'ltr' ? 1 : -1);
|
|
83
84
|
},
|
|
84
85
|
onBackspace: (event) => {
|
|
85
86
|
event.preventDefault();
|
|
86
87
|
changeActiveIndex(-1);
|
|
87
88
|
},
|
|
89
|
+
onDelete: (event) => {
|
|
90
|
+
const index = activeIndexRef.current;
|
|
91
|
+
|
|
92
|
+
if (typeof index === 'undefined') {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
event.preventDefault();
|
|
97
|
+
dispatch(rackSlice.actions.changeCharacters({ characters: [null], index }));
|
|
98
|
+
changeActiveIndex(1);
|
|
99
|
+
},
|
|
88
100
|
onKeyDown: (event) => {
|
|
89
101
|
if (isCtrl(event) && config.isTwoCharacterTilePrefix(event.key)) {
|
|
90
102
|
changeActiveIndex(1);
|
|
@@ -97,7 +109,7 @@ const Rack: FunctionComponent<Props> = ({ className }) => {
|
|
|
97
109
|
}
|
|
98
110
|
},
|
|
99
111
|
});
|
|
100
|
-
}, [changeActiveIndex, config]);
|
|
112
|
+
}, [changeActiveIndex, config, direction]);
|
|
101
113
|
|
|
102
114
|
return (
|
|
103
115
|
<div className={classNames(styles.rack, className)} onPaste={handlePaste}>
|
|
@@ -61,7 +61,7 @@ const Results: FunctionComponent<Props> = ({ height, width }) => {
|
|
|
61
61
|
</EmptyState>
|
|
62
62
|
)}
|
|
63
63
|
|
|
64
|
-
{typeof
|
|
64
|
+
{typeof error === 'undefined' && typeof results === 'undefined' && (
|
|
65
65
|
<EmptyState className={styles.emptyState} type="info">
|
|
66
66
|
{translate('results.empty-state.uninitialized')}
|
|
67
67
|
|
|
@@ -69,7 +69,7 @@ const Results: FunctionComponent<Props> = ({ height, width }) => {
|
|
|
69
69
|
</EmptyState>
|
|
70
70
|
)}
|
|
71
71
|
|
|
72
|
-
{typeof
|
|
72
|
+
{typeof error === 'undefined' && typeof results !== 'undefined' && typeof allResults !== 'undefined' && (
|
|
73
73
|
<>
|
|
74
74
|
{isOutdated && (
|
|
75
75
|
<EmptyState className={styles.emptyState} type="info">
|
|
@@ -17,7 +17,7 @@ interface Props {
|
|
|
17
17
|
const AutoGroupTilesSetting: FunctionComponent<Props> = ({ className, disabled }) => {
|
|
18
18
|
const dispatch = useDispatch();
|
|
19
19
|
const translate = useTranslate();
|
|
20
|
-
const
|
|
20
|
+
const value = useTypedSelector(selectAutoGroupTiles);
|
|
21
21
|
|
|
22
22
|
const options = [
|
|
23
23
|
{
|
|
@@ -43,7 +43,7 @@ const AutoGroupTilesSetting: FunctionComponent<Props> = ({ className, disabled }
|
|
|
43
43
|
<div className={className}>
|
|
44
44
|
{options.map((option) => (
|
|
45
45
|
<Radio
|
|
46
|
-
checked={
|
|
46
|
+
checked={value === parseValue(option.value)}
|
|
47
47
|
className={styles.option}
|
|
48
48
|
disabled={disabled}
|
|
49
49
|
id="autoGroupTiles"
|
|
@@ -9,6 +9,7 @@ interface Option {
|
|
|
9
9
|
className: string;
|
|
10
10
|
Icon: FunctionComponent<SVGAttributes<SVGElement>>;
|
|
11
11
|
label: string;
|
|
12
|
+
name: string;
|
|
12
13
|
value: Locale;
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -17,44 +18,51 @@ const options: Option[] = [
|
|
|
17
18
|
className: styles.gb,
|
|
18
19
|
Icon: FlagGb,
|
|
19
20
|
label: 'English (GB)',
|
|
21
|
+
name: 'English (GB)',
|
|
20
22
|
value: Locale.EN_GB,
|
|
21
23
|
},
|
|
22
24
|
{
|
|
23
25
|
className: styles.us,
|
|
24
26
|
Icon: FlagUs,
|
|
25
27
|
label: 'English (US)',
|
|
28
|
+
name: 'English (US)',
|
|
26
29
|
value: Locale.EN_US,
|
|
27
30
|
},
|
|
28
31
|
{
|
|
29
32
|
className: styles.fa,
|
|
30
33
|
Icon: FlagFa,
|
|
31
34
|
label: 'فارسی',
|
|
35
|
+
name: 'Persian',
|
|
32
36
|
value: Locale.FA_IR,
|
|
33
37
|
},
|
|
34
38
|
{
|
|
35
39
|
className: styles.fr,
|
|
36
40
|
Icon: FlagFr,
|
|
37
41
|
label: 'Français',
|
|
42
|
+
name: 'French',
|
|
38
43
|
value: Locale.FR_FR,
|
|
39
44
|
},
|
|
40
45
|
{
|
|
41
46
|
className: styles.de,
|
|
42
47
|
Icon: FlagDe,
|
|
43
48
|
label: 'Deutsch',
|
|
49
|
+
name: 'German',
|
|
44
50
|
value: Locale.DE_DE,
|
|
45
51
|
},
|
|
46
52
|
{
|
|
47
53
|
className: styles.pl,
|
|
48
54
|
Icon: FlagPl,
|
|
49
55
|
label: 'Polski',
|
|
56
|
+
name: 'Polish',
|
|
50
57
|
value: Locale.PL_PL,
|
|
51
58
|
},
|
|
52
59
|
{
|
|
53
60
|
className: styles.es,
|
|
54
61
|
Icon: FlagEs,
|
|
55
62
|
label: 'Español',
|
|
63
|
+
name: 'Spanish',
|
|
56
64
|
value: Locale.ES_ES,
|
|
57
65
|
},
|
|
58
|
-
];
|
|
66
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
59
67
|
|
|
60
68
|
export default options;
|
package/src/i18n/fr.json
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"results.empty-state.no-filtered-results": "Aucun résultat ne correspond à cette requête",
|
|
41
41
|
"results.empty-state.no-results": "Pas de résultats - impossible de générer des mots.",
|
|
42
42
|
"results.empty-state.outdated": "Les résultats sont dépassé. Cliquer ci-dessous pour mettre à jour.",
|
|
43
|
-
"results.empty-state.uninitialized": "
|
|
43
|
+
"results.empty-state.uninitialized": "Les mots générés à partir de vos lettres seront affichés ici.",
|
|
44
44
|
"results.input.placeholder": "Rechercher les résultats... (RegExp)",
|
|
45
45
|
"results.solve": "Résoudre",
|
|
46
46
|
"settings": "Options",
|
|
@@ -8,32 +8,29 @@ import getTotalRemainingTilesCount from './getTotalRemainingTilesCount';
|
|
|
8
8
|
const getRemainingTilesGroups = (remainingTiles: RemainingTile[]): RemainingTilesGroup[] => {
|
|
9
9
|
const consonants = remainingTiles.filter(isConsonant);
|
|
10
10
|
const vowels = remainingTiles.filter(isVowel);
|
|
11
|
+
const other = remainingTiles.filter(isOther);
|
|
11
12
|
const groups: RemainingTilesGroup[] = [];
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
translationKey: 'common.tiles',
|
|
34
|
-
totalCount: getTotalRemainingTilesCount(tiles),
|
|
35
|
-
});
|
|
36
|
-
}
|
|
14
|
+
groups.push({
|
|
15
|
+
remainingCount: getRemainingTilesCount(vowels),
|
|
16
|
+
tiles: vowels,
|
|
17
|
+
translationKey: 'common.vowels',
|
|
18
|
+
totalCount: getTotalRemainingTilesCount(vowels),
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
groups.push({
|
|
22
|
+
remainingCount: getRemainingTilesCount(consonants),
|
|
23
|
+
tiles: consonants,
|
|
24
|
+
translationKey: 'common.consonants',
|
|
25
|
+
totalCount: getTotalRemainingTilesCount(consonants),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
groups.push({
|
|
29
|
+
remainingCount: getRemainingTilesCount(other),
|
|
30
|
+
tiles: other,
|
|
31
|
+
translationKey: 'common.tiles',
|
|
32
|
+
totalCount: getTotalRemainingTilesCount(other),
|
|
33
|
+
});
|
|
37
34
|
|
|
38
35
|
const twoCharacterTiles = remainingTiles.filter(isTwoCharacter);
|
|
39
36
|
const blanks = remainingTiles.filter(isBlank);
|
|
@@ -59,10 +56,11 @@ const isConsonant = (tile: RemainingTile): boolean => CONSONANTS.includes(tile.c
|
|
|
59
56
|
|
|
60
57
|
const isVowel = (tile: RemainingTile): boolean => VOWELS.includes(tile.character);
|
|
61
58
|
|
|
62
|
-
const isLetter = (tile: RemainingTile): boolean => !isBlank(tile) && !isTwoCharacter(tile);
|
|
63
|
-
|
|
64
59
|
const isTwoCharacter = (tile: RemainingTile): boolean => tile.character.length === 2;
|
|
65
60
|
|
|
66
61
|
const isBlank = (tile: RemainingTile): boolean => tile.character === BLANK;
|
|
67
62
|
|
|
63
|
+
const isOther = (tile: RemainingTile) =>
|
|
64
|
+
!isConsonant(tile) && !isVowel(tile) && !isBlank(tile) && !isTwoCharacter(tile);
|
|
65
|
+
|
|
68
66
|
export default getRemainingTilesGroups;
|
|
@@ -3,7 +3,7 @@ import { Locale, WordDefinition, WordDefinitionJson } from '@scrabble-solver/typ
|
|
|
3
3
|
import fetchJson from './fetchJson';
|
|
4
4
|
|
|
5
5
|
const findWordDefinitions = async (locale: Locale, word: string): Promise<WordDefinition[]> => {
|
|
6
|
-
const json = await fetchJson<WordDefinitionJson[]>(`/api/dictionary/${locale}/${word}`);
|
|
6
|
+
const json = await fetchJson<WordDefinitionJson[]>(`/api/dictionary/${locale}/${encodeURIComponent(word)}`);
|
|
7
7
|
return json.map(WordDefinition.fromJson);
|
|
8
8
|
};
|
|
9
9
|
|
package/src/state/sagas.ts
CHANGED
|
@@ -7,13 +7,13 @@ import { findWordDefinitions, solve, verify, visit } from 'sdk';
|
|
|
7
7
|
|
|
8
8
|
import { initialize, reset } from './actions';
|
|
9
9
|
import {
|
|
10
|
-
selectAutoGroupTiles,
|
|
11
10
|
selectBoard,
|
|
12
11
|
selectCellIsFiltered,
|
|
13
12
|
selectCharacters,
|
|
14
13
|
selectConfig,
|
|
15
14
|
selectDictionary,
|
|
16
15
|
selectLocale,
|
|
16
|
+
selectLocaleAutoGroupTiles,
|
|
17
17
|
} from './selectors';
|
|
18
18
|
import {
|
|
19
19
|
boardSlice,
|
|
@@ -65,7 +65,7 @@ function* onRackValueChange(): AnyGenerator {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerator {
|
|
68
|
-
const autoGroupTiles = yield select(
|
|
68
|
+
const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
|
|
69
69
|
yield put(boardSlice.actions.applyResult(result));
|
|
70
70
|
yield put(cellFilterSlice.actions.reset());
|
|
71
71
|
yield put(rackSlice.actions.removeTiles(result.tiles));
|
|
@@ -74,8 +74,15 @@ function* onApplyResult({ payload: result }: PayloadAction<Result>): AnyGenerato
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
function* onConfigIdChange(): AnyGenerator {
|
|
77
|
+
const characters = yield select(selectCharacters);
|
|
78
|
+
|
|
79
|
+
if (characters.length > 0) {
|
|
80
|
+
yield put(solveSlice.actions.submit());
|
|
81
|
+
} else {
|
|
82
|
+
yield put(resultsSlice.actions.reset());
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
yield put(resultsSlice.actions.reset());
|
|
78
|
-
yield put(solveSlice.actions.submit());
|
|
79
86
|
yield put(verifySlice.actions.submit());
|
|
80
87
|
yield* ensureProperTilesCount();
|
|
81
88
|
}
|
|
@@ -112,9 +119,16 @@ function* onReset(): AnyGenerator {
|
|
|
112
119
|
}
|
|
113
120
|
|
|
114
121
|
function* onLocaleChange(): AnyGenerator {
|
|
122
|
+
const characters = yield select(selectCharacters);
|
|
123
|
+
|
|
124
|
+
if (characters.length > 0) {
|
|
125
|
+
yield put(solveSlice.actions.submit());
|
|
126
|
+
} else {
|
|
127
|
+
yield put(resultsSlice.actions.reset());
|
|
128
|
+
}
|
|
129
|
+
|
|
115
130
|
yield put(dictionarySlice.actions.reset());
|
|
116
131
|
yield put(resultsSlice.actions.changeResultCandidate(null));
|
|
117
|
-
yield put(solveSlice.actions.submit());
|
|
118
132
|
yield put(verifySlice.actions.submit());
|
|
119
133
|
}
|
|
120
134
|
|
|
@@ -181,7 +195,7 @@ function* ensureProperTilesCount(): AnyGenerator {
|
|
|
181
195
|
} else if (config.maximumCharactersCount < characters.length) {
|
|
182
196
|
const nonNulls = characters.filter(Boolean).slice(0, config.maximumCharactersCount);
|
|
183
197
|
const differenceCount = Math.abs(config.maximumCharactersCount - nonNulls.length);
|
|
184
|
-
const autoGroupTiles = yield select(
|
|
198
|
+
const autoGroupTiles = yield select(selectLocaleAutoGroupTiles);
|
|
185
199
|
yield put(rackSlice.actions.init([...nonNulls, ...Array(differenceCount).fill(null)]));
|
|
186
200
|
yield put(rackSlice.actions.groupTiles(autoGroupTiles));
|
|
187
201
|
}
|
package/src/state/selectors.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { getLocaleConfig } from '@scrabble-solver/configs';
|
|
3
3
|
import { Cell, Config, isError, Result, Tile } from '@scrabble-solver/types';
|
|
4
4
|
|
|
5
|
-
import i18n from 'i18n';
|
|
5
|
+
import i18n, { LOCALE_FEATURES } from 'i18n';
|
|
6
6
|
import { findCell, getRemainingTiles, getRemainingTilesGroups, sortResults, unorderedArraysEqual } from 'lib';
|
|
7
7
|
import { Translations } from 'types';
|
|
8
8
|
|
|
@@ -38,9 +38,17 @@ export const selectDictionaryError = createSelector([selectDictionaryRoot], (dic
|
|
|
38
38
|
return isError(dictionary.error) ? dictionary.error : undefined;
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
export const selectLocale = createSelector([selectSettingsRoot], (settings) => settings.locale);
|
|
42
|
+
|
|
41
43
|
export const selectAutoGroupTiles = createSelector([selectSettingsRoot], (settings) => settings.autoGroupTiles);
|
|
42
44
|
|
|
43
|
-
export const
|
|
45
|
+
export const selectLocaleAutoGroupTiles = createSelector([selectLocale, selectSettingsRoot], (locale, settings) => {
|
|
46
|
+
if (LOCALE_FEATURES[locale].direction === 'ltr' || settings.autoGroupTiles === null) {
|
|
47
|
+
return settings.autoGroupTiles;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return settings.autoGroupTiles === 'left' ? 'right' : 'left';
|
|
51
|
+
});
|
|
44
52
|
|
|
45
53
|
export const selectBoard = selectBoardRoot;
|
|
46
54
|
|