scrabble-solver 2.11.0 → 2.11.2
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/lerna.json +1 -1
- package/package.json +1 -1
- package/packages/configs/package.json +3 -3
- package/packages/constants/package.json +1 -1
- package/packages/dictionaries/package-lock.json +2 -2
- package/packages/dictionaries/package.json +4 -4
- package/packages/logger/package-lock.json +2 -2
- 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/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/277.js +523 -611
- package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
- package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
- 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 +0 -24
- 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/api/dictionary/[locale]/[word].js +0 -1
- package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +0 -1
- package/packages/scrabble-solver/.next/server/pages/api/solve.js +28 -8
- package/packages/scrabble-solver/.next/server/pages/api/verify.js +0 -1
- package/packages/scrabble-solver/.next/server/pages/api/visit.js +0 -1
- package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
- package/packages/scrabble-solver/.next/server/pages/index.js +49 -90
- 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/static/Mdvi3FY0PqkILKLbPlVBU/_buildManifest.js +1 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/{404-e0f30450e9920dc3.js → 404-448ba28510855455.js} +1 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-495e6f4ccc278bb2.js +28 -0
- package/packages/scrabble-solver/.next/static/chunks/pages/index-5ecc51900ca29685.js +1 -0
- package/packages/scrabble-solver/.next/static/css/17b0a2db8742105f.css +1 -0
- package/packages/scrabble-solver/.next/static/css/e1ffeb2558330c55.css +2 -0
- package/packages/scrabble-solver/.next/trace +54 -55
- package/packages/scrabble-solver/package-lock.json +2 -79
- package/packages/scrabble-solver/package.json +8 -13
- package/packages/scrabble-solver/src/components/{Solver/components/EmptyState/EmptyState.module.scss → Alert/Alert.module.scss} +11 -7
- package/packages/scrabble-solver/src/components/{Solver/components/EmptyState/EmptyState.tsx → Alert/Alert.tsx} +8 -6
- package/packages/scrabble-solver/src/components/Alert/index.ts +1 -0
- package/packages/scrabble-solver/src/components/Board/Board.module.scss +55 -0
- package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +4 -0
- package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +51 -2
- package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +12 -0
- package/packages/scrabble-solver/src/components/Board/components/Cell/CellPure.tsx +12 -0
- package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +9 -26
- package/packages/scrabble-solver/src/components/Board/lib/getPositionInGrid.ts +1 -1
- package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +4 -0
- package/packages/scrabble-solver/src/components/DictionaryInput/DictionaryInput.module.scss +1 -0
- package/packages/scrabble-solver/src/components/EmptyState/EmptyState.module.scss +2 -1
- package/packages/scrabble-solver/src/components/EmptyState/EmptyState.tsx +1 -2
- package/packages/scrabble-solver/src/components/Loading/Loading.module.scss +1 -1
- package/packages/scrabble-solver/src/components/Logo/Logo.tsx +5 -0
- package/packages/scrabble-solver/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +4 -1
- package/packages/scrabble-solver/src/components/Modal/Modal.module.scss +14 -0
- package/packages/scrabble-solver/src/components/Modal/Modal.tsx +4 -1
- package/packages/scrabble-solver/src/components/PlainTiles/PlainTiles.module.scss +1 -1
- package/packages/scrabble-solver/src/components/PlainTiles/Tile.tsx +3 -3
- package/packages/scrabble-solver/src/components/Rack/Rack.module.scss +25 -0
- package/packages/scrabble-solver/src/components/Rack/Rack.tsx +5 -4
- package/packages/scrabble-solver/src/components/Rack/RackTile.tsx +6 -13
- package/packages/scrabble-solver/src/components/Results/HeaderButton.tsx +5 -12
- package/packages/scrabble-solver/src/components/Results/Result.tsx +5 -3
- package/packages/scrabble-solver/src/components/Results/Results.module.scss +41 -1
- package/packages/scrabble-solver/src/components/Results/Results.tsx +29 -43
- package/packages/scrabble-solver/src/components/Results/types.ts +1 -1
- package/packages/scrabble-solver/src/components/ResultsInput/ResultsInput.module.scss +1 -0
- package/packages/scrabble-solver/src/components/Solver/Solver.module.scss +9 -4
- package/packages/scrabble-solver/src/components/Solver/Solver.tsx +17 -19
- package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +5 -6
- package/packages/scrabble-solver/src/components/Solver/components/index.ts +0 -1
- package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +42 -61
- package/packages/scrabble-solver/src/components/Tile/Tile.tsx +4 -3
- package/packages/scrabble-solver/src/components/Tile/TilePure.tsx +4 -13
- package/packages/scrabble-solver/src/components/Tooltip/Tooltip.module.scss +1 -72
- package/packages/scrabble-solver/src/components/Tooltip/useTooltip.tsx +25 -35
- package/packages/scrabble-solver/src/components/index.ts +1 -0
- package/packages/scrabble-solver/src/hooks/index.ts +0 -1
- package/packages/scrabble-solver/src/hooks/useAppLayout.ts +3 -1
- package/packages/scrabble-solver/src/i18n/de.json +0 -1
- package/packages/scrabble-solver/src/i18n/en.json +0 -1
- package/packages/scrabble-solver/src/i18n/es.json +0 -1
- package/packages/scrabble-solver/src/i18n/fa.json +0 -1
- package/packages/scrabble-solver/src/i18n/fr.json +0 -1
- package/packages/scrabble-solver/src/i18n/pl.json +0 -1
- package/packages/scrabble-solver/src/lib/createRegExp.ts +13 -0
- package/packages/scrabble-solver/src/lib/groupResults.ts +38 -0
- package/packages/scrabble-solver/src/lib/guessLocale.ts +22 -0
- package/packages/scrabble-solver/src/lib/index.ts +4 -2
- package/packages/scrabble-solver/src/lib/sortResults.ts +6 -10
- package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.module.scss +6 -2
- package/packages/scrabble-solver/src/modals/KeyMapModal/KeyMapModal.tsx +5 -21
- package/packages/scrabble-solver/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +4 -0
- package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss +7 -0
- package/packages/scrabble-solver/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.module.scss +3 -3
- package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.tsx +23 -11
- package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +2 -0
- package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.module.scss +8 -1
- package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/[word].ts +0 -1
- package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/index.ts +0 -1
- package/packages/scrabble-solver/src/pages/api/solve.ts +0 -1
- package/packages/scrabble-solver/src/pages/api/verify.ts +0 -1
- package/packages/scrabble-solver/src/pages/api/visit.ts +0 -1
- package/packages/scrabble-solver/src/pages/index.tsx +13 -15
- package/packages/scrabble-solver/src/parameters/index.ts +2 -2
- package/packages/scrabble-solver/src/state/createAppStore.ts +26 -10
- package/packages/scrabble-solver/src/state/sagas.ts +1 -0
- package/packages/scrabble-solver/src/state/selectors.ts +37 -37
- package/packages/scrabble-solver/src/state/slices/boardInitialState.ts +3 -1
- package/packages/scrabble-solver/src/state/slices/cellFilterInitialState.ts +3 -3
- package/packages/scrabble-solver/src/state/slices/cellFilterSlice.ts +3 -1
- package/packages/scrabble-solver/src/state/slices/dictionaryInitialState.ts +2 -2
- package/packages/scrabble-solver/src/state/slices/rackInitialState.ts +3 -1
- package/packages/scrabble-solver/src/state/slices/resultsInitialState.ts +11 -4
- package/packages/scrabble-solver/src/state/slices/settingsInitialState.ts +10 -21
- package/packages/scrabble-solver/src/state/slices/solveInitialState.ts +2 -2
- package/packages/scrabble-solver/src/state/slices/solveSlice.ts +2 -0
- package/packages/scrabble-solver/src/state/slices/verifyInitialState.ts +13 -4
- package/packages/scrabble-solver/src/state/types.ts +20 -2
- package/packages/scrabble-solver/src/styles/mixins.scss +25 -1
- package/packages/scrabble-solver/src/styles/variables.scss +17 -1
- package/packages/scrabble-solver/src/types/index.ts +10 -2
- package/packages/solver/package-lock.json +2 -2
- package/packages/solver/package.json +5 -5
- package/packages/types/build/Bonus.d.ts +2 -1
- package/packages/types/package.json +2 -2
- package/packages/types/src/Bonus.ts +3 -1
- package/packages/word-definitions/package-lock.json +8 -8
- package/packages/word-definitions/package.json +2 -2
- package/packages/word-lists/package-lock.json +2 -2
- package/packages/word-lists/package.json +2 -2
- package/packages/scrabble-solver/.next/static/45ye7793DY705HOcuK9lJ/_buildManifest.js +0 -1
- package/packages/scrabble-solver/.next/static/chunks/pages/_app-d7acee5e526752d9.js +0 -28
- package/packages/scrabble-solver/.next/static/chunks/pages/index-35d2c1c79a201ae2.js +0 -1
- package/packages/scrabble-solver/.next/static/css/a48caa6f57de6e98.css +0 -1
- package/packages/scrabble-solver/.next/static/css/c49bbe944ddd1b39.css +0 -2
- package/packages/scrabble-solver/src/components/Board/types/index.ts +0 -4
- package/packages/scrabble-solver/src/components/Solver/components/EmptyState/index.ts +0 -1
- package/packages/scrabble-solver/src/components/Tooltip/constants.ts +0 -28
- package/packages/scrabble-solver/src/hooks/useUniqueId.ts +0 -9
- package/packages/scrabble-solver/src/lib/isCtrl.ts +0 -7
- package/packages/scrabble-solver/src/state/rootReducer.ts +0 -25
- /package/packages/scrabble-solver/.next/static/{45ye7793DY705HOcuK9lJ → Mdvi3FY0PqkILKLbPlVBU}/_ssgManifest.js +0 -0
|
@@ -41,8 +41,7 @@ const EmptyState: FunctionComponent<Props> = ({ children, className, variant })
|
|
|
41
41
|
return (
|
|
42
42
|
<div className={classNames(styles.emptyState, className)}>
|
|
43
43
|
<PlainTiles className={styles.tiles} color={COLORS_PER_TYPE[variant]} content={content} />
|
|
44
|
-
|
|
45
|
-
<div className={styles.content}>{children}</div>
|
|
44
|
+
<div>{children}</div>
|
|
46
45
|
</div>
|
|
47
46
|
);
|
|
48
47
|
};
|
|
@@ -1,3 +1,8 @@
|
|
|
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
|
+
*/
|
|
1
6
|
import { CSSProperties, FunctionComponent } from 'react';
|
|
2
7
|
|
|
3
8
|
import PlainTiles from '../PlainTiles';
|
package/packages/scrabble-solver/src/components/LogoSplashScreen/LogoSplashScreen.module.scss
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
$loading-duration: 250ms;
|
|
4
4
|
$loaded-duration: 100ms;
|
|
5
|
-
$hiding-duration:
|
|
5
|
+
$hiding-duration: 150ms;
|
|
6
6
|
|
|
7
7
|
.logoSplashScreen {
|
|
8
8
|
display: flex;
|
|
@@ -16,18 +16,21 @@ $hiding-duration: 200ms;
|
|
|
16
16
|
animation-delay: $loading-duration + $loaded-duration;
|
|
17
17
|
animation-duration: $hiding-duration;
|
|
18
18
|
animation-fill-mode: forwards;
|
|
19
|
+
animation-timing-function: linear;
|
|
19
20
|
|
|
20
21
|
.logos {
|
|
21
22
|
animation: pulse;
|
|
22
23
|
animation-delay: $loading-duration + $loaded-duration;
|
|
23
24
|
animation-duration: $hiding-duration;
|
|
24
25
|
animation-fill-mode: forwards;
|
|
26
|
+
animation-timing-function: linear;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
.logoColor {
|
|
28
30
|
animation: progress;
|
|
29
31
|
animation-duration: $loading-duration;
|
|
30
32
|
animation-fill-mode: forwards;
|
|
33
|
+
animation-timing-function: linear;
|
|
31
34
|
}
|
|
32
35
|
}
|
|
33
36
|
}
|
|
@@ -112,9 +112,23 @@
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
.content {
|
|
115
|
+
@include scrollbars;
|
|
116
|
+
|
|
115
117
|
position: relative;
|
|
116
118
|
flex: 1;
|
|
117
119
|
min-height: 0;
|
|
118
120
|
padding: var(--spacing--l);
|
|
119
121
|
overflow: auto;
|
|
120
122
|
}
|
|
123
|
+
|
|
124
|
+
.footer {
|
|
125
|
+
flex: 0 0 auto;
|
|
126
|
+
display: flex;
|
|
127
|
+
justify-content: flex-end;
|
|
128
|
+
padding: var(--spacing--l);
|
|
129
|
+
box-shadow: var(--box-shadow);
|
|
130
|
+
|
|
131
|
+
@include media('>s') {
|
|
132
|
+
display: none;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
@@ -15,12 +15,13 @@ import styles from './Modal.module.scss';
|
|
|
15
15
|
export interface Props {
|
|
16
16
|
children: ReactNode;
|
|
17
17
|
className?: string;
|
|
18
|
+
footer?: ReactNode;
|
|
18
19
|
isOpen: boolean;
|
|
19
20
|
title: string;
|
|
20
21
|
onClose: () => void;
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
const Modal: FunctionComponent<Props> = ({ children, className, isOpen, title, onClose }) => {
|
|
24
|
+
const Modal: FunctionComponent<Props> = ({ children, className, footer, isOpen, title, onClose }) => {
|
|
24
25
|
const translate = useTranslate();
|
|
25
26
|
const [shouldReturnFocusAfterClose, setShouldReturnFocusAfterClose] = useState(true);
|
|
26
27
|
|
|
@@ -68,6 +69,8 @@ const Modal: FunctionComponent<Props> = ({ children, className, isOpen, title, o
|
|
|
68
69
|
</div>
|
|
69
70
|
|
|
70
71
|
<div className={styles.content}>{children}</div>
|
|
72
|
+
|
|
73
|
+
{footer && <div className={styles.footer}>{footer}</div>}
|
|
71
74
|
</div>
|
|
72
75
|
</ReactModal>
|
|
73
76
|
);
|
|
@@ -14,12 +14,12 @@ interface Props {
|
|
|
14
14
|
|
|
15
15
|
const Tile: FunctionComponent<Props> = ({ character, className, color, fontFamily, points, size, transform, x, y }) => (
|
|
16
16
|
<g className={className} transform={transform}>
|
|
17
|
-
<rect fill={color} height={size} width={size} x={x} y={y} />
|
|
17
|
+
<rect fill={color} height={size} rx={size * 0.15} width={size} x={x} y={y} />
|
|
18
18
|
|
|
19
19
|
<text
|
|
20
20
|
dominantBaseline="central"
|
|
21
21
|
fontFamily={fontFamily}
|
|
22
|
-
fontSize={0.6
|
|
22
|
+
fontSize={size * 0.6}
|
|
23
23
|
fontWeight="bold"
|
|
24
24
|
textAnchor="middle"
|
|
25
25
|
x={x + size / 2}
|
|
@@ -32,7 +32,7 @@ const Tile: FunctionComponent<Props> = ({ character, className, color, fontFamil
|
|
|
32
32
|
<text
|
|
33
33
|
dominantBaseline="text-after-edge"
|
|
34
34
|
fontFamily={fontFamily}
|
|
35
|
-
fontSize={0.25
|
|
35
|
+
fontSize={size * 0.25}
|
|
36
36
|
fontWeight="bold"
|
|
37
37
|
textAnchor="end"
|
|
38
38
|
x={x + size * 0.9}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
.rack {
|
|
4
4
|
display: flex;
|
|
5
5
|
box-shadow: var(--box-shadow);
|
|
6
|
+
border-radius: var(--border--radius);
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
.tile {
|
|
@@ -15,3 +16,27 @@
|
|
|
15
16
|
z-index: 2;
|
|
16
17
|
}
|
|
17
18
|
}
|
|
19
|
+
|
|
20
|
+
.sharpLeft {
|
|
21
|
+
[dir='ltr'] & {
|
|
22
|
+
border-top-left-radius: 0;
|
|
23
|
+
border-bottom-left-radius: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
[dir='rtl'] & {
|
|
27
|
+
border-top-right-radius: 0;
|
|
28
|
+
border-bottom-right-radius: 0;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.sharpRight {
|
|
33
|
+
[dir='ltr'] & {
|
|
34
|
+
border-top-right-radius: 0;
|
|
35
|
+
border-bottom-right-radius: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
[dir='rtl'] & {
|
|
39
|
+
border-top-left-radius: 0;
|
|
40
|
+
border-bottom-left-radius: 0;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
createKeyboardNavigation,
|
|
9
9
|
extractCharacters,
|
|
10
10
|
extractInputValue,
|
|
11
|
-
isCtrl,
|
|
12
11
|
zipCharactersAndTiles,
|
|
13
12
|
} from 'lib';
|
|
14
13
|
import { rackSlice, selectConfig, selectLocale, selectRack, selectResultCandidateTiles, useTypedSelector } from 'state';
|
|
@@ -99,9 +98,7 @@ const Rack: FunctionComponent<Props> = ({ className, tileSize }) => {
|
|
|
99
98
|
changeActiveIndex(1);
|
|
100
99
|
},
|
|
101
100
|
onKeyDown: (event) => {
|
|
102
|
-
if (
|
|
103
|
-
changeActiveIndex(1);
|
|
104
|
-
} else if (event.currentTarget.value === event.key) {
|
|
101
|
+
if (event.currentTarget.value === event.key) {
|
|
105
102
|
// change event did not fire because the same character was typed over the current one
|
|
106
103
|
// but we still want to move the caret
|
|
107
104
|
event.preventDefault();
|
|
@@ -118,6 +115,10 @@ const Rack: FunctionComponent<Props> = ({ className, tileSize }) => {
|
|
|
118
115
|
<RackTile
|
|
119
116
|
activeIndexRef={activeIndexRef}
|
|
120
117
|
character={character}
|
|
118
|
+
className={classNames({
|
|
119
|
+
[styles.sharpLeft]: index !== 0,
|
|
120
|
+
[styles.sharpRight]: index !== tiles.length - 1,
|
|
121
|
+
})}
|
|
121
122
|
index={index}
|
|
122
123
|
inputRef={tilesRefs[index]}
|
|
123
124
|
key={index}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BLANK } from '@scrabble-solver/constants';
|
|
2
2
|
import { Tile as TileModel } from '@scrabble-solver/types';
|
|
3
|
+
import classNames from 'classnames';
|
|
3
4
|
import {
|
|
4
5
|
ChangeEvent,
|
|
5
6
|
ChangeEventHandler,
|
|
@@ -12,7 +13,7 @@ import {
|
|
|
12
13
|
} from 'react';
|
|
13
14
|
import { useDispatch } from 'react-redux';
|
|
14
15
|
|
|
15
|
-
import { createKeyboardNavigation, extractCharacters, extractInputValue
|
|
16
|
+
import { createKeyboardNavigation, extractCharacters, extractInputValue } from 'lib';
|
|
16
17
|
import {
|
|
17
18
|
rackSlice,
|
|
18
19
|
selectCharacterIsValid,
|
|
@@ -30,6 +31,7 @@ import styles from './Rack.module.scss';
|
|
|
30
31
|
interface Props {
|
|
31
32
|
activeIndexRef: MutableRefObject<number | undefined>;
|
|
32
33
|
character: string | null;
|
|
34
|
+
className?: string;
|
|
33
35
|
index: number;
|
|
34
36
|
inputRef: RefObject<HTMLInputElement>;
|
|
35
37
|
size: number;
|
|
@@ -41,6 +43,7 @@ interface Props {
|
|
|
41
43
|
const RackTile: FunctionComponent<Props> = ({
|
|
42
44
|
activeIndexRef,
|
|
43
45
|
character,
|
|
46
|
+
className,
|
|
44
47
|
index,
|
|
45
48
|
inputRef,
|
|
46
49
|
size,
|
|
@@ -77,17 +80,7 @@ const RackTile: FunctionComponent<Props> = ({
|
|
|
77
80
|
event.preventDefault();
|
|
78
81
|
dispatch(rackSlice.actions.changeCharacter({ character: null, index }));
|
|
79
82
|
},
|
|
80
|
-
onKeyDown
|
|
81
|
-
if (isCtrl(event) && config.isTwoCharacterTilePrefix(event.key)) {
|
|
82
|
-
event.preventDefault();
|
|
83
|
-
event.stopPropagation();
|
|
84
|
-
const twoTilesCharacter = config.getTwoCharacterTileByPrefix(event.key);
|
|
85
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
86
|
-
dispatch(rackSlice.actions.changeCharacter({ character: twoTilesCharacter!, index }));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
onKeyDown(event);
|
|
90
|
-
},
|
|
83
|
+
onKeyDown,
|
|
91
84
|
});
|
|
92
85
|
}, [index, onKeyDown]);
|
|
93
86
|
|
|
@@ -97,7 +90,7 @@ const RackTile: FunctionComponent<Props> = ({
|
|
|
97
90
|
index: (index + 1).toLocaleString(locale),
|
|
98
91
|
})}
|
|
99
92
|
autoFocus={index === 0}
|
|
100
|
-
className={styles.tile}
|
|
93
|
+
className={classNames(styles.tile, className)}
|
|
101
94
|
character={character === null ? undefined : character}
|
|
102
95
|
highlighted={tile !== null}
|
|
103
96
|
inputRef={inputRef}
|
|
@@ -3,13 +3,7 @@ import { ReactElement } from 'react';
|
|
|
3
3
|
import { useDispatch } from 'react-redux';
|
|
4
4
|
|
|
5
5
|
import { SortDown, SortUp } from 'icons';
|
|
6
|
-
import {
|
|
7
|
-
resultsSlice,
|
|
8
|
-
selectResultsSortColumn,
|
|
9
|
-
selectResultsSortDirection,
|
|
10
|
-
useTranslate,
|
|
11
|
-
useTypedSelector,
|
|
12
|
-
} from 'state';
|
|
6
|
+
import { resultsSlice, selectResultsSort, useTranslate, useTypedSelector } from 'state';
|
|
13
7
|
import { ResultColumn, SortDirection } from 'types';
|
|
14
8
|
|
|
15
9
|
import { useTooltip } from '../Tooltip';
|
|
@@ -24,8 +18,7 @@ interface Props {
|
|
|
24
18
|
const HeaderButton = ({ column }: Props): ReactElement => {
|
|
25
19
|
const dispatch = useDispatch();
|
|
26
20
|
const translate = useTranslate();
|
|
27
|
-
const
|
|
28
|
-
const sortDirection = useTypedSelector(selectResultsSortDirection);
|
|
21
|
+
const sort = useTypedSelector(selectResultsSort);
|
|
29
22
|
const triggerProps = useTooltip(translate(column.translationKey));
|
|
30
23
|
|
|
31
24
|
const handleOrderChange = (columnId: ResultColumn) => {
|
|
@@ -44,10 +37,10 @@ const HeaderButton = ({ column }: Props): ReactElement => {
|
|
|
44
37
|
<span className={styles.cell}>
|
|
45
38
|
<span className={styles.headerButtonLabel}>{translate(column.translationKey)}</span>
|
|
46
39
|
|
|
47
|
-
{
|
|
40
|
+
{sort.column === column.id && (
|
|
48
41
|
<>
|
|
49
|
-
{
|
|
50
|
-
{
|
|
42
|
+
{sort.direction === SortDirection.Ascending && <SortUp className={styles.sortIcon} />}
|
|
43
|
+
{sort.direction === SortDirection.Descending && <SortDown className={styles.sortIcon} />}
|
|
51
44
|
</>
|
|
52
45
|
)}
|
|
53
46
|
</span>
|
|
@@ -3,7 +3,7 @@ import { CSSProperties, FocusEventHandler, MouseEventHandler, ReactElement, useR
|
|
|
3
3
|
|
|
4
4
|
import { LOCALE_FEATURES } from 'i18n';
|
|
5
5
|
import { noop } from 'lib';
|
|
6
|
-
import { selectLocale, useTypedSelector } from 'state';
|
|
6
|
+
import { selectIsResultMatching, selectLocale, useTypedSelector } from 'state';
|
|
7
7
|
import { ResultColumn } from 'types';
|
|
8
8
|
|
|
9
9
|
import Cell from './Cell';
|
|
@@ -20,7 +20,7 @@ interface Props {
|
|
|
20
20
|
const Result = ({ data, index, style }: Props): ReactElement => {
|
|
21
21
|
const {
|
|
22
22
|
highlightedIndex,
|
|
23
|
-
results,
|
|
23
|
+
results = [],
|
|
24
24
|
onBlur = noop,
|
|
25
25
|
onClick = noop,
|
|
26
26
|
onFocus = noop,
|
|
@@ -28,11 +28,12 @@ const Result = ({ data, index, style }: Props): ReactElement => {
|
|
|
28
28
|
onMouseLeave = noop,
|
|
29
29
|
} = data;
|
|
30
30
|
const ref = useRef<HTMLButtonElement>(null);
|
|
31
|
+
const columns = useColumns();
|
|
31
32
|
const locale = useTypedSelector(selectLocale);
|
|
32
33
|
const { consonants, vowels } = LOCALE_FEATURES[locale];
|
|
33
34
|
const result = results[index];
|
|
35
|
+
const isMatching = useTypedSelector((state) => selectIsResultMatching(state, index));
|
|
34
36
|
const otherWords = result.words.slice(1).join(' / ').toLocaleUpperCase();
|
|
35
|
-
const columns = useColumns();
|
|
36
37
|
const enabledColumns = Object.fromEntries(columns.map((column) => [column.id, true]));
|
|
37
38
|
|
|
38
39
|
const handleClick: MouseEventHandler = (event) => onClick(result, event);
|
|
@@ -46,6 +47,7 @@ const Result = ({ data, index, style }: Props): ReactElement => {
|
|
|
46
47
|
aria-label={result.word}
|
|
47
48
|
className={classNames(styles.result, {
|
|
48
49
|
[styles.highlighted]: index === highlightedIndex,
|
|
50
|
+
[styles.notMatching]: !isMatching,
|
|
49
51
|
})}
|
|
50
52
|
ref={ref}
|
|
51
53
|
style={style}
|
|
@@ -9,7 +9,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
|
|
|
9
9
|
height: 100%;
|
|
10
10
|
background: var(--color--background--element);
|
|
11
11
|
border: var(--border);
|
|
12
|
-
|
|
12
|
+
border-radius: var(--border--radius);
|
|
13
13
|
font-family: var(--font--family--title);
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -29,6 +29,9 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.list {
|
|
32
|
+
@include scrollbars;
|
|
33
|
+
|
|
34
|
+
scrollbar-gutter: stable;
|
|
32
35
|
transition: var(--transition);
|
|
33
36
|
|
|
34
37
|
&.outdated {
|
|
@@ -44,6 +47,8 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
|
|
|
44
47
|
justify-content: space-between;
|
|
45
48
|
font-weight: 700;
|
|
46
49
|
border-bottom: var(--border);
|
|
50
|
+
border-top-left-radius: inherit;
|
|
51
|
+
border-top-right-radius: inherit;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
.headerButton {
|
|
@@ -60,6 +65,26 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
|
|
|
60
65
|
background-color: var(--color--primary);
|
|
61
66
|
color: var(--color--primary--opposite);
|
|
62
67
|
}
|
|
68
|
+
|
|
69
|
+
&:first-child {
|
|
70
|
+
[dir='ltr'] & {
|
|
71
|
+
border-top-left-radius: inherit;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
[dir='rtl'] & {
|
|
75
|
+
border-top-right-radius: inherit;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
&:last-child {
|
|
80
|
+
[dir='ltr'] & {
|
|
81
|
+
border-top-right-radius: inherit;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
[dir='rtl'] & {
|
|
85
|
+
border-top-left-radius: inherit;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
.headerButtonLabel {
|
|
@@ -89,6 +114,19 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
|
|
|
89
114
|
color: var(--color--primary--opposite);
|
|
90
115
|
}
|
|
91
116
|
}
|
|
117
|
+
|
|
118
|
+
&.notMatching {
|
|
119
|
+
color: var(--color--inactive);
|
|
120
|
+
|
|
121
|
+
&:focus,
|
|
122
|
+
&:hover,
|
|
123
|
+
&.highlighted {
|
|
124
|
+
&:not(:disabled) {
|
|
125
|
+
background-color: var(--color--primary--light);
|
|
126
|
+
color: var(--color--primary--opposite);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
92
130
|
}
|
|
93
131
|
|
|
94
132
|
.resultContent {
|
|
@@ -175,4 +213,6 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
|
|
|
175
213
|
|
|
176
214
|
.input {
|
|
177
215
|
border-top: var(--border);
|
|
216
|
+
border-bottom-left-radius: var(--border--radius);
|
|
217
|
+
border-bottom-right-radius: var(--border--radius);
|
|
178
218
|
}
|
|
@@ -9,9 +9,8 @@ import {
|
|
|
9
9
|
selectAreResultsOutdated,
|
|
10
10
|
selectIsLoading,
|
|
11
11
|
selectLocale,
|
|
12
|
+
selectResults,
|
|
12
13
|
selectSolveError,
|
|
13
|
-
selectSortedFilteredResults,
|
|
14
|
-
selectSortedResults,
|
|
15
14
|
useTranslate,
|
|
16
15
|
useTypedSelector,
|
|
17
16
|
} from 'state';
|
|
@@ -38,9 +37,7 @@ const Results: FunctionComponent<Props> = ({ callbacks, className, highlightedIn
|
|
|
38
37
|
const translate = useTranslate();
|
|
39
38
|
const locale = useTypedSelector(selectLocale);
|
|
40
39
|
const { direction } = LOCALE_FEATURES[locale];
|
|
41
|
-
const
|
|
42
|
-
const filteredResults = useTypedSelector(selectSortedFilteredResults);
|
|
43
|
-
const results = filteredResults || [];
|
|
40
|
+
const results = useTypedSelector(selectResults);
|
|
44
41
|
const isLoading = useTypedSelector(selectIsLoading);
|
|
45
42
|
const isOutdated = useTypedSelector(selectAreResultsOutdated);
|
|
46
43
|
const error = useTypedSelector(selectSolveError);
|
|
@@ -50,8 +47,7 @@ const Results: FunctionComponent<Props> = ({ callbacks, className, highlightedIn
|
|
|
50
47
|
const columns = useColumns();
|
|
51
48
|
const scrollToIndex = typeof highlightedIndex === 'number' ? highlightedIndex : 0;
|
|
52
49
|
const scrollToIndexRef = useLatest(scrollToIndex);
|
|
53
|
-
const hasResults =
|
|
54
|
-
typeof error === 'undefined' && typeof filteredResults !== 'undefined' && typeof allResults !== 'undefined';
|
|
50
|
+
const hasResults = typeof error === 'undefined' && typeof results !== 'undefined';
|
|
55
51
|
|
|
56
52
|
useEffect(() => {
|
|
57
53
|
// without setTimeout, the initial scrolling offset is calculated
|
|
@@ -65,7 +61,7 @@ const Results: FunctionComponent<Props> = ({ callbacks, className, highlightedIn
|
|
|
65
61
|
return () => {
|
|
66
62
|
globalThis.clearTimeout(timeout);
|
|
67
63
|
};
|
|
68
|
-
}, [
|
|
64
|
+
}, [results, listRef, scrollToIndexRef]);
|
|
69
65
|
|
|
70
66
|
return (
|
|
71
67
|
<div className={classNames(styles.results, className)}>
|
|
@@ -84,7 +80,7 @@ const Results: FunctionComponent<Props> = ({ callbacks, className, highlightedIn
|
|
|
84
80
|
</EmptyState>
|
|
85
81
|
)}
|
|
86
82
|
|
|
87
|
-
{typeof error === 'undefined' && typeof
|
|
83
|
+
{typeof error === 'undefined' && typeof results === 'undefined' && (
|
|
88
84
|
<EmptyState className={styles.emptyState} variant="info">
|
|
89
85
|
{translate('results.empty-state.uninitialized')}
|
|
90
86
|
|
|
@@ -102,45 +98,35 @@ const Results: FunctionComponent<Props> = ({ callbacks, className, highlightedIn
|
|
|
102
98
|
</EmptyState>
|
|
103
99
|
)}
|
|
104
100
|
|
|
105
|
-
{!isOutdated && (
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
itemData={itemData}
|
|
129
|
-
itemSize={RESULTS_ITEM_HEIGHT}
|
|
130
|
-
ref={setListRef}
|
|
131
|
-
width={width}
|
|
132
|
-
>
|
|
133
|
-
{Result}
|
|
134
|
-
</FixedSizeList>
|
|
135
|
-
</div>
|
|
136
|
-
)}
|
|
137
|
-
</>
|
|
101
|
+
{!isOutdated && results.length === 0 && (
|
|
102
|
+
<EmptyState className={styles.emptyState} variant="warning">
|
|
103
|
+
{translate('results.empty-state.no-results')}
|
|
104
|
+
</EmptyState>
|
|
105
|
+
)}
|
|
106
|
+
|
|
107
|
+
{!isOutdated && results.length > 0 && (
|
|
108
|
+
<div className={styles.listContainer}>
|
|
109
|
+
<FixedSizeList
|
|
110
|
+
className={classNames(styles.list, {
|
|
111
|
+
[styles.outdated]: isOutdated,
|
|
112
|
+
})}
|
|
113
|
+
direction={direction}
|
|
114
|
+
height={height}
|
|
115
|
+
itemCount={results.length}
|
|
116
|
+
itemData={itemData}
|
|
117
|
+
itemSize={RESULTS_ITEM_HEIGHT}
|
|
118
|
+
ref={setListRef}
|
|
119
|
+
width={width}
|
|
120
|
+
>
|
|
121
|
+
{Result}
|
|
122
|
+
</FixedSizeList>
|
|
123
|
+
</div>
|
|
138
124
|
)}
|
|
139
125
|
</>
|
|
140
126
|
)}
|
|
141
127
|
</div>
|
|
142
128
|
|
|
143
|
-
{hasResults &&
|
|
129
|
+
{hasResults && results.length > 0 && !isOutdated && <ResultsInput className={styles.input} />}
|
|
144
130
|
|
|
145
131
|
{isLoading && <Loading />}
|
|
146
132
|
</div>
|
|
@@ -63,6 +63,10 @@
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
.results {
|
|
67
|
+
box-shadow: var(--box-shadow);
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
.dictionaryContainer {
|
|
67
71
|
flex: 0 0 auto;
|
|
68
72
|
height: var(--dictionary--height);
|
|
@@ -70,16 +74,21 @@
|
|
|
70
74
|
flex-direction: column;
|
|
71
75
|
background-color: var(--color--background--element);
|
|
72
76
|
border: var(--border);
|
|
77
|
+
border-radius: var(--border--radius);
|
|
73
78
|
box-shadow: var(--box-shadow);
|
|
74
79
|
}
|
|
75
80
|
|
|
76
81
|
.dictionary {
|
|
77
82
|
flex: 1;
|
|
78
83
|
border-bottom: var(--border);
|
|
84
|
+
border-top-left-radius: var(--border--radius);
|
|
85
|
+
border-top-right-radius: var(--border--radius);
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
.dictionaryInput {
|
|
82
89
|
flex: 0 0 auto;
|
|
90
|
+
border-bottom-left-radius: var(--border--radius);
|
|
91
|
+
border-bottom-right-radius: var(--border--radius);
|
|
83
92
|
}
|
|
84
93
|
|
|
85
94
|
.bottomContainer {
|
|
@@ -97,10 +106,6 @@
|
|
|
97
106
|
min-width: 0;
|
|
98
107
|
}
|
|
99
108
|
|
|
100
|
-
.rack {
|
|
101
|
-
border: var(--border);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
109
|
.controls {
|
|
105
110
|
width: 100%;
|
|
106
111
|
}
|