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
|
@@ -11,21 +11,21 @@ import {
|
|
|
11
11
|
selectAreResultsOutdated,
|
|
12
12
|
selectConfig,
|
|
13
13
|
selectResultCandidate,
|
|
14
|
+
selectResults,
|
|
14
15
|
selectSolveError,
|
|
15
|
-
selectSortedFilteredResults,
|
|
16
|
-
selectSortedResults,
|
|
17
16
|
solveSlice,
|
|
18
17
|
useTranslate,
|
|
19
18
|
useTypedSelector,
|
|
20
19
|
} from 'state';
|
|
21
20
|
|
|
21
|
+
import Alert from '../Alert';
|
|
22
22
|
import Board from '../Board';
|
|
23
23
|
import Dictionary from '../Dictionary';
|
|
24
24
|
import DictionaryInput from '../DictionaryInput';
|
|
25
25
|
import Rack from '../Rack';
|
|
26
26
|
import Results from '../Results';
|
|
27
27
|
|
|
28
|
-
import {
|
|
28
|
+
import { FloatingSolveButton, ResultCandidatePicker } from './components';
|
|
29
29
|
import styles from './Solver.module.scss';
|
|
30
30
|
|
|
31
31
|
interface Props {
|
|
@@ -40,18 +40,16 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
|
|
|
40
40
|
const dispatch = useDispatch();
|
|
41
41
|
const translate = useTranslate();
|
|
42
42
|
const isTouchDevice = useIsTouchDevice();
|
|
43
|
-
const { componentsSpacing, isBoardFullWidth, showColumn, showCompactControls, showFloatingSolveButton } =
|
|
43
|
+
const { columnWidth, componentsSpacing, isBoardFullWidth, showColumn, showCompactControls, showFloatingSolveButton } =
|
|
44
44
|
useAppLayout();
|
|
45
|
-
const [bottomContainerRef, { height: bottomContainerHeight }] = useMeasure<HTMLDivElement>();
|
|
46
|
-
const [columnRef, { width: columnWidth }] = useMeasure<HTMLDivElement>();
|
|
47
|
-
const maxBoardWidth = width - columnWidth - (showColumn ? componentsSpacing : 0) - 2 * componentsSpacing;
|
|
48
|
-
const maxBoardHeight = isBoardFullWidth ? Number.POSITIVE_INFINITY : Math.max(height - bottomContainerHeight, 0);
|
|
49
45
|
const config = useTypedSelector(selectConfig);
|
|
50
46
|
const error = useTypedSelector(selectSolveError);
|
|
51
47
|
const isOutdated = useTypedSelector(selectAreResultsOutdated);
|
|
52
48
|
const resultCandidate = useTypedSelector(selectResultCandidate);
|
|
53
|
-
const
|
|
54
|
-
const
|
|
49
|
+
const results = useTypedSelector(selectResults);
|
|
50
|
+
const [bottomContainerRef, { height: bottomContainerHeight }] = useMeasure<HTMLDivElement>();
|
|
51
|
+
const maxBoardWidth = width - columnWidth - (showColumn ? componentsSpacing : 0) - 2 * componentsSpacing;
|
|
52
|
+
const maxBoardHeight = isBoardFullWidth ? Number.POSITIVE_INFINITY : Math.max(height - bottomContainerHeight, 0);
|
|
55
53
|
const [bestResult] = results || [];
|
|
56
54
|
const cellWidth = (maxBoardWidth - (config.boardWidth + 1) * BORDER_WIDTH) / config.boardWidth;
|
|
57
55
|
const cellHeight = (maxBoardHeight - (config.boardHeight + 1) * BORDER_WIDTH) / config.boardHeight;
|
|
@@ -111,13 +109,13 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
|
|
|
111
109
|
<div className={classNames(styles.solver, className)}>
|
|
112
110
|
<div className={styles.container}>
|
|
113
111
|
<div className={styles.content}>
|
|
114
|
-
<form
|
|
112
|
+
<form className={styles.boardContainer} onSubmit={handleSubmit}>
|
|
115
113
|
<Board cellSize={cellSizeSafe} className={styles.board} />
|
|
116
114
|
<input className={styles.submitInput} tabIndex={-1} type="submit" />
|
|
117
115
|
</form>
|
|
118
116
|
|
|
119
|
-
<div className={styles.column}
|
|
120
|
-
<Results callbacks={callbacks} />
|
|
117
|
+
<div className={styles.column}>
|
|
118
|
+
<Results callbacks={callbacks} className={styles.results} />
|
|
121
119
|
|
|
122
120
|
<div className={styles.dictionaryContainer}>
|
|
123
121
|
<Dictionary className={styles.dictionary} />
|
|
@@ -129,7 +127,7 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
|
|
|
129
127
|
|
|
130
128
|
<div className={styles.bottomContainer} ref={bottomContainerRef}>
|
|
131
129
|
<div className={styles.bottomContent}>
|
|
132
|
-
<form
|
|
130
|
+
<form onSubmit={handleSubmit}>
|
|
133
131
|
<Rack className={styles.rack} tileSize={tileSize} />
|
|
134
132
|
<input className={styles.submitInput} tabIndex={-1} type="submit" />
|
|
135
133
|
</form>
|
|
@@ -139,15 +137,15 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
|
|
|
139
137
|
<ResultCandidatePicker onResultClick={onShowResults} />
|
|
140
138
|
|
|
141
139
|
{error && (
|
|
142
|
-
<
|
|
140
|
+
<Alert className={styles.emptyState} variant="error">
|
|
143
141
|
{error.message}
|
|
144
|
-
</
|
|
142
|
+
</Alert>
|
|
145
143
|
)}
|
|
146
144
|
|
|
147
|
-
{
|
|
148
|
-
<
|
|
145
|
+
{results && results.length === 0 && !isOutdated && (
|
|
146
|
+
<Alert className={styles.emptyState} variant="warning">
|
|
149
147
|
{translate('results.empty-state.no-results')}
|
|
150
|
-
</
|
|
148
|
+
</Alert>
|
|
151
149
|
)}
|
|
152
150
|
</div>
|
|
153
151
|
)}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
selectIsLoading,
|
|
11
11
|
selectLocale,
|
|
12
12
|
selectResultCandidate,
|
|
13
|
-
|
|
13
|
+
selectResults,
|
|
14
14
|
useTranslate,
|
|
15
15
|
useTypedSelector,
|
|
16
16
|
} from 'state';
|
|
@@ -31,13 +31,12 @@ const ResultCandidatePicker: FunctionComponent<Props> = ({ className, onResultCl
|
|
|
31
31
|
const locale = useTypedSelector(selectLocale);
|
|
32
32
|
const isLoading = useTypedSelector(selectIsLoading);
|
|
33
33
|
const isOutdated = useTypedSelector(selectAreResultsOutdated);
|
|
34
|
-
const
|
|
35
|
-
const results = sortedResults || [];
|
|
34
|
+
const results = useTypedSelector(selectResults);
|
|
36
35
|
const resultCandidate = useTypedSelector(selectResultCandidate);
|
|
37
|
-
const index = resultCandidate ? results.findIndex((result) => result.id === resultCandidate.id) : -1;
|
|
36
|
+
const index = resultCandidate && results ? results.findIndex((result) => result.id === resultCandidate.id) : -1;
|
|
38
37
|
const disabled = isOutdated || !resultCandidate;
|
|
39
|
-
const isPreviousDisabled = index <= 0 || disabled;
|
|
40
|
-
const isNextDisabled = index >= results.length - 1 || disabled;
|
|
38
|
+
const isPreviousDisabled = !results || index <= 0 || disabled;
|
|
39
|
+
const isNextDisabled = !results || index >= results.length - 1 || disabled;
|
|
41
40
|
const bothEnabled = !isPreviousDisabled && !isNextDisabled;
|
|
42
41
|
const { showFloatingSolveButton } = useAppLayout();
|
|
43
42
|
|
|
@@ -4,7 +4,17 @@
|
|
|
4
4
|
--background-color: transparent;
|
|
5
5
|
|
|
6
6
|
position: relative;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
padding: 0;
|
|
11
|
+
background-color: var(--background-color);
|
|
12
|
+
border-radius: var(--border--radius);
|
|
13
|
+
font-weight: bold;
|
|
14
|
+
text-transform: uppercase;
|
|
15
|
+
text-align: center;
|
|
7
16
|
transition: var(--transition);
|
|
17
|
+
user-select: none;
|
|
8
18
|
|
|
9
19
|
&.points1 {
|
|
10
20
|
--background-color: var(--color--yellow);
|
|
@@ -23,13 +33,30 @@
|
|
|
23
33
|
--background-color: var(--color--red);
|
|
24
34
|
}
|
|
25
35
|
|
|
36
|
+
&.raised {
|
|
37
|
+
--shadow--size: 2px;
|
|
38
|
+
--shadow--blur: 2px;
|
|
39
|
+
--shadow--spread: -1px;
|
|
40
|
+
--shadow--color: rgba(34, 34, 34, 0.8);
|
|
41
|
+
|
|
42
|
+
box-shadow: inset calc(-1 * var(--shadow--size)) calc(-1 * var(--shadow--size)) var(--shadow--blur)
|
|
43
|
+
var(--shadow--spread) var(--shadow--color);
|
|
44
|
+
|
|
45
|
+
@include media('<xs') {
|
|
46
|
+
--shadow--size: 1px;
|
|
47
|
+
--shadow--spread: 0;
|
|
48
|
+
--shadow--blur: 1px;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
26
52
|
&.blank {
|
|
27
53
|
--background-color: var(--color--white);
|
|
28
54
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
color: var(--color--foreground);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
&.empty {
|
|
59
|
+
color: var(--color--inactive);
|
|
33
60
|
}
|
|
34
61
|
|
|
35
62
|
&.highlighted {
|
|
@@ -37,76 +64,28 @@
|
|
|
37
64
|
|
|
38
65
|
color: var(--color--primary--opposite);
|
|
39
66
|
|
|
40
|
-
.placeholder,
|
|
41
|
-
.character {
|
|
42
|
-
color: inherit;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
67
|
.points {
|
|
46
68
|
color: inherit;
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
|
-
|
|
50
|
-
&:not(.disabled) {
|
|
51
|
-
.input::selection {
|
|
52
|
-
--background--color: transparent;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
.input,
|
|
58
|
-
.character,
|
|
59
|
-
.placeholder {
|
|
60
|
-
padding: 0;
|
|
61
|
-
font-weight: bold;
|
|
62
|
-
text-transform: uppercase;
|
|
63
|
-
text-align: center;
|
|
64
|
-
caret-color: transparent;
|
|
65
|
-
box-sizing: border-box;
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
.input {
|
|
69
|
-
width: 100%;
|
|
70
|
-
height: 100%;
|
|
71
|
-
background-color: transparent;
|
|
72
|
-
color: transparent;
|
|
73
|
-
border: none;
|
|
74
|
-
font-size: 16px; // prevent iOS from automatically zooming in on focus
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
.character,
|
|
78
|
-
.placeholder {
|
|
79
74
|
position: absolute;
|
|
80
75
|
top: 0;
|
|
81
76
|
right: 0;
|
|
82
77
|
bottom: 0;
|
|
83
78
|
left: 0;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
background-color:
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.empty & {
|
|
93
|
-
color: var(--color--inactive);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
.raised & {
|
|
97
|
-
box-shadow: inset -2px -2px 2px -1px rgba(34, 34, 34, 0.8);
|
|
98
|
-
|
|
99
|
-
@include media('<xs') {
|
|
100
|
-
box-shadow: inset -2px -2px 1px -1px rgba(34, 34, 34, 0.8);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
.character {
|
|
106
|
-
opacity: 1;
|
|
79
|
+
width: 100%;
|
|
80
|
+
height: 100%;
|
|
81
|
+
border: none;
|
|
82
|
+
background-color: transparent;
|
|
83
|
+
color: transparent;
|
|
84
|
+
caret-color: transparent;
|
|
85
|
+
font-size: 16px; // prevent iOS from automatically zooming in on focus
|
|
107
86
|
|
|
108
|
-
|
|
109
|
-
|
|
87
|
+
&::selection {
|
|
88
|
+
--background--color: transparent;
|
|
110
89
|
}
|
|
111
90
|
}
|
|
112
91
|
|
|
@@ -146,10 +125,12 @@
|
|
|
146
125
|
[dir='ltr'] & {
|
|
147
126
|
top: 0;
|
|
148
127
|
right: 0;
|
|
128
|
+
border-top-right-radius: inherit;
|
|
149
129
|
}
|
|
150
130
|
|
|
151
131
|
[dir='rtl'] & {
|
|
152
132
|
bottom: 0;
|
|
153
133
|
right: 0;
|
|
134
|
+
border-bottom-right-radius: inherit;
|
|
154
135
|
}
|
|
155
136
|
}
|
|
@@ -60,8 +60,10 @@ const Tile: FunctionComponent<Props> = ({
|
|
|
60
60
|
const locale = useTypedSelector(selectLocale);
|
|
61
61
|
const { animateTile, showTilePoints } = useAppLayout();
|
|
62
62
|
const { pointsFontSize, tileFontSize, tileSize } = getTileSizes(size);
|
|
63
|
-
const style = useMemo(
|
|
64
|
-
|
|
63
|
+
const style = useMemo(
|
|
64
|
+
() => ({ fontSize: tileFontSize, height: tileSize, width: tileSize }),
|
|
65
|
+
[tileSize, tileFontSize],
|
|
66
|
+
);
|
|
65
67
|
const pointsStyle = useMemo(() => ({ fontSize: pointsFontSize }), [pointsFontSize]);
|
|
66
68
|
const ref = useRef<HTMLInputElement>(null);
|
|
67
69
|
const mergedRef = useMergeRefs(inputRef ? [ref, inputRef] : [ref]);
|
|
@@ -98,7 +100,6 @@ const Tile: FunctionComponent<Props> = ({
|
|
|
98
100
|
autoFocus={autoFocus}
|
|
99
101
|
canShowPoints={canShowPoints}
|
|
100
102
|
character={character}
|
|
101
|
-
characterStyle={characterStyle}
|
|
102
103
|
className={className}
|
|
103
104
|
disabled={disabled}
|
|
104
105
|
highlighted={highlighted}
|
|
@@ -18,7 +18,6 @@ interface Props {
|
|
|
18
18
|
autoFocus?: boolean;
|
|
19
19
|
canShowPoints?: boolean;
|
|
20
20
|
character?: string;
|
|
21
|
-
characterStyle?: CSSProperties;
|
|
22
21
|
className?: string;
|
|
23
22
|
disabled?: boolean;
|
|
24
23
|
highlighted?: boolean;
|
|
@@ -42,7 +41,6 @@ const TilePure: FunctionComponent<Props> = ({
|
|
|
42
41
|
autoFocus,
|
|
43
42
|
canShowPoints,
|
|
44
43
|
character,
|
|
45
|
-
characterStyle,
|
|
46
44
|
className,
|
|
47
45
|
disabled,
|
|
48
46
|
highlighted,
|
|
@@ -66,15 +64,18 @@ const TilePure: FunctionComponent<Props> = ({
|
|
|
66
64
|
[styles.disabled]: disabled,
|
|
67
65
|
[styles.empty]: !character,
|
|
68
66
|
[styles.highlighted]: highlighted,
|
|
69
|
-
[styles.
|
|
67
|
+
[styles.placeholder]: !character,
|
|
70
68
|
[styles.points1]: points === 1,
|
|
71
69
|
[styles.points2]: points === 2,
|
|
72
70
|
[styles.points3]: points === 3,
|
|
73
71
|
[styles.points4]: points === 4,
|
|
74
72
|
[styles.points5]: typeof points === 'number' && points >= 5,
|
|
73
|
+
[styles.raised]: raised,
|
|
75
74
|
})}
|
|
76
75
|
style={style}
|
|
77
76
|
>
|
|
77
|
+
{character || placeholder}
|
|
78
|
+
|
|
78
79
|
<input
|
|
79
80
|
aria-label={ariaLabel}
|
|
80
81
|
autoCapitalize="none"
|
|
@@ -92,16 +93,6 @@ const TilePure: FunctionComponent<Props> = ({
|
|
|
92
93
|
onKeyDown={onKeyDown}
|
|
93
94
|
/>
|
|
94
95
|
|
|
95
|
-
{placeholder && (
|
|
96
|
-
<div className={styles.placeholder} style={characterStyle} tabIndex={-1}>
|
|
97
|
-
{placeholder}
|
|
98
|
-
</div>
|
|
99
|
-
)}
|
|
100
|
-
|
|
101
|
-
<div className={styles.character} style={characterStyle} tabIndex={-1}>
|
|
102
|
-
{character}
|
|
103
|
-
</div>
|
|
104
|
-
|
|
105
96
|
{canShowPoints && (
|
|
106
97
|
<span className={styles.points} style={pointsStyle}>
|
|
107
98
|
{pointsFormatted}
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
$arrow-size: 4px;
|
|
2
|
-
|
|
3
|
-
:export {
|
|
4
|
-
ARROW_SIZE: $arrow-size;
|
|
5
|
-
PREVENT_OVERFLOW: 10px;
|
|
6
|
-
OFFSET: 2px;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
1
|
.tooltip {
|
|
10
2
|
padding: var(--spacing--s) var(--spacing--m);
|
|
11
3
|
box-shadow: var(--box-shadow);
|
|
@@ -13,71 +5,8 @@ $arrow-size: 4px;
|
|
|
13
5
|
background-color: var(--color--tooltip--background);
|
|
14
6
|
color: var(--color--tooltip--foreground);
|
|
15
7
|
z-index: var(--z-index--tooltip);
|
|
16
|
-
|
|
17
|
-
&.top {
|
|
18
|
-
.arrow {
|
|
19
|
-
bottom: -$arrow-size;
|
|
20
|
-
|
|
21
|
-
&::after {
|
|
22
|
-
left: 0;
|
|
23
|
-
bottom: 0;
|
|
24
|
-
border-top-color: var(--color--tooltip--background);
|
|
25
|
-
border-bottom: none;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
&.right {
|
|
31
|
-
.arrow {
|
|
32
|
-
left: -$arrow-size;
|
|
33
|
-
|
|
34
|
-
&::after {
|
|
35
|
-
left: 0;
|
|
36
|
-
top: 0;
|
|
37
|
-
border-right-color: var(--color--tooltip--background);
|
|
38
|
-
border-left: none;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
&.bottom {
|
|
44
|
-
.arrow {
|
|
45
|
-
top: -$arrow-size;
|
|
46
|
-
|
|
47
|
-
&::after {
|
|
48
|
-
top: 0;
|
|
49
|
-
left: 0;
|
|
50
|
-
border-bottom-color: var(--color--tooltip--background);
|
|
51
|
-
border-top: none;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
&.left {
|
|
57
|
-
.arrow {
|
|
58
|
-
right: -$arrow-size;
|
|
59
|
-
|
|
60
|
-
&::after {
|
|
61
|
-
right: 0;
|
|
62
|
-
top: 0;
|
|
63
|
-
border-left-color: var(--color--tooltip--background);
|
|
64
|
-
border-right: none;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
8
|
}
|
|
69
9
|
|
|
70
10
|
.arrow {
|
|
71
|
-
|
|
72
|
-
width: 2 * $arrow-size;
|
|
73
|
-
height: 2 * $arrow-size;
|
|
74
|
-
|
|
75
|
-
&::after {
|
|
76
|
-
content: ' ';
|
|
77
|
-
position: absolute;
|
|
78
|
-
height: 0;
|
|
79
|
-
width: 0;
|
|
80
|
-
pointer-events: none;
|
|
81
|
-
border: $arrow-size solid transparent;
|
|
82
|
-
}
|
|
11
|
+
fill: var(--color--tooltip--background);
|
|
83
12
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { arrow, autoUpdate, flip, FloatingArrow, offset, shift, useFloating } from '@floating-ui/react';
|
|
1
2
|
import classNames from 'classnames';
|
|
2
3
|
import {
|
|
3
4
|
FocusEvent,
|
|
@@ -6,16 +7,15 @@ import {
|
|
|
6
7
|
MouseEventHandler,
|
|
7
8
|
ReactNode,
|
|
8
9
|
useCallback,
|
|
10
|
+
useId,
|
|
9
11
|
useMemo,
|
|
12
|
+
useRef,
|
|
10
13
|
useState,
|
|
11
14
|
} from 'react';
|
|
12
|
-
import { usePopper } from 'react-popper';
|
|
13
|
-
import { useMountedState, useRafLoop } from 'react-use';
|
|
14
15
|
|
|
15
|
-
import { useIsTouchDevice, usePortal
|
|
16
|
+
import { useIsTouchDevice, usePortal } from 'hooks';
|
|
16
17
|
import { noop } from 'lib';
|
|
17
18
|
|
|
18
|
-
import { MODIFIERS } from './constants';
|
|
19
19
|
import styles from './Tooltip.module.scss';
|
|
20
20
|
|
|
21
21
|
interface Props {
|
|
@@ -36,29 +36,27 @@ interface TriggerProps {
|
|
|
36
36
|
onMouseOver?: MouseEventHandler;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
const ARROW_SIZE = 7;
|
|
40
|
+
const ARROW_GAP = 3;
|
|
41
|
+
const PADDING = 10;
|
|
42
|
+
|
|
39
43
|
// eslint-disable-next-line max-statements
|
|
40
44
|
const useTooltip = (
|
|
41
45
|
tooltip: ReactNode,
|
|
42
46
|
{ className, placement = 'top', onBlur = noop, onFocus = noop, onMouseOut = noop, onMouseOver = noop }: Props = {},
|
|
43
47
|
): TriggerProps => {
|
|
44
|
-
const id =
|
|
48
|
+
const id = useId();
|
|
45
49
|
const isTouchDevice = useIsTouchDevice();
|
|
46
50
|
const isEnabled = Boolean(tooltip) || tooltip === 0;
|
|
47
|
-
const isMounted = useMountedState();
|
|
48
51
|
const [isShown, setIsShown] = useState<boolean>(false);
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const {
|
|
53
|
-
|
|
54
|
-
styles: popperStyles,
|
|
55
|
-
update,
|
|
56
|
-
} = usePopper(referenceElement, popperElement, {
|
|
57
|
-
modifiers: [{ name: 'arrow', options: { element: arrowElement } }, ...MODIFIERS],
|
|
52
|
+
const arrowRef = useRef(null);
|
|
53
|
+
const ariaAttributes = useMemo(() => (isShown ? { 'aria-describedby': id } : {}), [id, isShown]);
|
|
54
|
+
|
|
55
|
+
const { x, y, context, refs, strategy } = useFloating({
|
|
56
|
+
middleware: [flip(), shift({ padding: PADDING }), offset(ARROW_SIZE + ARROW_GAP), arrow({ element: arrowRef })],
|
|
58
57
|
placement,
|
|
58
|
+
whileElementsMounted: autoUpdate,
|
|
59
59
|
});
|
|
60
|
-
const computedPlacement = attributes.popper ? attributes.popper['data-popper-placement'] : placement;
|
|
61
|
-
const ariaAttributes = useMemo(() => (isShown ? { 'aria-describedby': id } : {}), [id, isShown]);
|
|
62
60
|
|
|
63
61
|
const handleBlur = useCallback(
|
|
64
62
|
(event: FocusEvent) => {
|
|
@@ -95,7 +93,7 @@ const useTooltip = (
|
|
|
95
93
|
const mouseTriggerProps = useMemo(
|
|
96
94
|
() => ({
|
|
97
95
|
...ariaAttributes,
|
|
98
|
-
ref:
|
|
96
|
+
ref: refs.setReference,
|
|
99
97
|
onBlur: handleBlur,
|
|
100
98
|
onFocus: handleFocus,
|
|
101
99
|
onMouseOut: handleMouseOut,
|
|
@@ -107,33 +105,25 @@ const useTooltip = (
|
|
|
107
105
|
const touchTriggerProps = useMemo(
|
|
108
106
|
() => ({
|
|
109
107
|
...ariaAttributes,
|
|
110
|
-
ref:
|
|
108
|
+
ref: refs.setReference,
|
|
111
109
|
}),
|
|
112
110
|
[ariaAttributes],
|
|
113
111
|
);
|
|
114
112
|
|
|
115
113
|
const triggerProps = isTouchDevice ? touchTriggerProps : mouseTriggerProps;
|
|
116
114
|
|
|
117
|
-
useRafLoop(() => {
|
|
118
|
-
if (isMounted() && update) {
|
|
119
|
-
update();
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
115
|
usePortal(
|
|
124
116
|
<div
|
|
125
|
-
className={classNames(styles.tooltip, className
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
style={popperStyles.popper}
|
|
133
|
-
{...attributes.popper}
|
|
117
|
+
className={classNames(styles.tooltip, className)}
|
|
118
|
+
ref={refs.setFloating}
|
|
119
|
+
style={{
|
|
120
|
+
position: strategy,
|
|
121
|
+
top: y ?? 0,
|
|
122
|
+
left: x ?? 0,
|
|
123
|
+
}}
|
|
134
124
|
>
|
|
135
125
|
<div>{tooltip}</div>
|
|
136
|
-
<
|
|
126
|
+
<FloatingArrow className={styles.arrow} context={context} ref={arrowRef} />
|
|
137
127
|
</div>,
|
|
138
128
|
{ disabled: !isEnabled || !isShown },
|
|
139
129
|
);
|
|
@@ -5,4 +5,3 @@ export { default as useLanguage } from './useLanguage';
|
|
|
5
5
|
export { default as useLocalStorage } from './useLocalStorage';
|
|
6
6
|
export { default as useMediaQuery } from './useMediaQuery';
|
|
7
7
|
export { default as usePortal } from './usePortal';
|
|
8
|
-
export { default as useUniqueId } from './useUniqueId';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { COMPONENTS_SPACING, COMPONENTS_SPACING_SMALL } from 'parameters';
|
|
1
|
+
import { COMPONENTS_SPACING, COMPONENTS_SPACING_SMALL, SOLVER_COLUMN_WIDTH } from 'parameters';
|
|
2
2
|
|
|
3
3
|
import useIsTouchDevice from './useIsTouchDevice';
|
|
4
4
|
import useMediaQuery from './useMediaQuery';
|
|
@@ -14,8 +14,10 @@ const useAppLayout = () => {
|
|
|
14
14
|
|
|
15
15
|
return {
|
|
16
16
|
animateTile: !isLessThanXs,
|
|
17
|
+
columnWidth: showColumn ? SOLVER_COLUMN_WIDTH : 0,
|
|
17
18
|
componentsSpacing: isLessThanXl ? COMPONENTS_SPACING_SMALL : COMPONENTS_SPACING,
|
|
18
19
|
isBoardFullWidth: isLessThanM,
|
|
20
|
+
isModalFullWidth: isLessThanS,
|
|
19
21
|
showColumn,
|
|
20
22
|
showCompactControls: !showColumn,
|
|
21
23
|
showFloatingSolveButton: isTouchDevice,
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"rack.tile.location": "Ablage: Stein ({{index}})",
|
|
46
46
|
"remaining-tiles": "Restliche Steine",
|
|
47
47
|
"results": "Ergebnisse",
|
|
48
|
-
"results.empty-state.no-filtered-results": "Keine Ergebnisse für diese Anfrage.",
|
|
49
48
|
"results.empty-state.no-results": "Keine Ergebnisse - kein Wort konnte generiert werden.",
|
|
50
49
|
"results.empty-state.outdated": "Ergebnisse sind alt. Klicken zum Aktualisieren.",
|
|
51
50
|
"results.empty-state.uninitialized": "Wörter die aus deinen Buchstaben generiert wurden erscheinen hier.",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"rack.tile.location": "Rack: tile ({{index}})",
|
|
46
46
|
"remaining-tiles": "Remaining tiles",
|
|
47
47
|
"results": "Results",
|
|
48
|
-
"results.empty-state.no-filtered-results": "No result matches this query.",
|
|
49
48
|
"results.empty-state.no-results": "No results - unable to generate any words.",
|
|
50
49
|
"results.empty-state.outdated": "Results are outdated. Click below to update.",
|
|
51
50
|
"results.empty-state.uninitialized": "Words generated from your letters will be shown here.",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"rack.tile.location": "Estante: espacio ({{index}})",
|
|
46
46
|
"remaining-tiles": "Casillas restantes",
|
|
47
47
|
"results": "Resultados",
|
|
48
|
-
"results.empty-state.no-filtered-results": "Ningún resultado coincide con esta consulta.",
|
|
49
48
|
"results.empty-state.no-results": "No hay resultados; no se pueden generar palabras",
|
|
50
49
|
"results.empty-state.outdated": "Los resultados están desactualizados. Haga clic a continuación para actualizar.",
|
|
51
50
|
"results.empty-state.uninitialized": "Aquí se mostrarán las palabras generadas a partir de sus letras.",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"rack.tile.location": "({{index}}) کاشی: طاقچه",
|
|
46
46
|
"remaining-tiles": "کاشی های باقی مانده",
|
|
47
47
|
"results": "نتایج",
|
|
48
|
-
"results.empty-state.no-filtered-results": "پاسخی یافت نشد.",
|
|
49
48
|
"results.empty-state.no-results": "کلمه قابل استفاده پیدا نشد.",
|
|
50
49
|
"results.empty-state.outdated": "نتایج به روز نیستند، برای بروز رسانی کلیک کنید.",
|
|
51
50
|
"results.empty-state.uninitialized": "کلمات تولید شده از حروف شما اینجا نمایش داده خواهد شد.",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"rack.tile.location": "Chevalet: la case ({{index}})",
|
|
46
46
|
"remaining-tiles": "Cases restantes",
|
|
47
47
|
"results": "Résultats",
|
|
48
|
-
"results.empty-state.no-filtered-results": "Aucun résultat ne correspond à cette requête",
|
|
49
48
|
"results.empty-state.no-results": "Pas de résultats - impossible de générer des mots.",
|
|
50
49
|
"results.empty-state.outdated": "Les résultats sont dépassé. Cliquer ci-dessous pour mettre à jour.",
|
|
51
50
|
"results.empty-state.uninitialized": "Les mots générés à partir de vos lettres seront affichés ici.",
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"rack.tile.location": "Stojak: płytka ({{index}})",
|
|
46
46
|
"remaining-tiles": "Pozostałe płytki",
|
|
47
47
|
"results": "Wyniki",
|
|
48
|
-
"results.empty-state.no-filtered-results": "Żaden wynik nie pasuje do tej kwerendy.",
|
|
49
48
|
"results.empty-state.no-results": "Brak wyników - nie można wygenerować żadnego słowa.",
|
|
50
49
|
"results.empty-state.outdated": "Wyniki są nieaktualne. Kliknij poniżej, aby zaktualizować.",
|
|
51
50
|
"results.empty-state.uninitialized": "Tu zostaną wyświetlone słowa wygenerowane z Twoich liter.",
|