@scrabble-solver/scrabble-solver 2.11.1 → 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.
Files changed (98) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +6 -6
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/eslint/.cache_8dgz12 +1 -1
  5. package/.next/cache/next-server.js.nft.json +1 -1
  6. package/.next/cache/webpack/client-production/0.pack +0 -0
  7. package/.next/cache/webpack/client-production/index.pack +0 -0
  8. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  9. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  10. package/.next/cache/webpack/server-production/0.pack +0 -0
  11. package/.next/cache/webpack/server-production/index.pack +0 -0
  12. package/.next/next-server.js.nft.json +1 -1
  13. package/.next/prerender-manifest.json +1 -1
  14. package/.next/routes-manifest.json +1 -1
  15. package/.next/server/chunks/277.js +203 -173
  16. package/.next/server/middleware-build-manifest.js +1 -1
  17. package/.next/server/pages/404.html +2 -2
  18. package/.next/server/pages/404.js.nft.json +1 -1
  19. package/.next/server/pages/500.html +1 -1
  20. package/.next/server/pages/_app.js.nft.json +1 -1
  21. package/.next/server/pages/_document.js.nft.json +1 -1
  22. package/.next/server/pages/api/dictionary/[locale]/[word].js +0 -1
  23. package/.next/server/pages/api/dictionary/[locale].js +0 -1
  24. package/.next/server/pages/api/solve.js +29 -8
  25. package/.next/server/pages/api/verify.js +0 -1
  26. package/.next/server/pages/api/visit.js +0 -1
  27. package/.next/server/pages/index.html +1 -1
  28. package/.next/server/pages/index.js +46 -39
  29. package/.next/server/pages/index.js.nft.json +1 -1
  30. package/.next/server/pages/index.json +1 -1
  31. package/.next/static/{esK8DG-6aS5V7QFRtR3YE → Mdvi3FY0PqkILKLbPlVBU}/_buildManifest.js +1 -1
  32. package/.next/static/chunks/pages/_app-495e6f4ccc278bb2.js +28 -0
  33. package/.next/static/chunks/pages/index-5ecc51900ca29685.js +1 -0
  34. package/.next/static/css/17b0a2db8742105f.css +1 -0
  35. package/.next/static/css/e1ffeb2558330c55.css +2 -0
  36. package/.next/trace +54 -53
  37. package/package.json +9 -9
  38. package/src/components/Board/components/Cell/Cell.module.scss +10 -2
  39. package/src/components/Board/hooks/useGrid.ts +1 -2
  40. package/src/components/Board/lib/getPositionInGrid.ts +1 -1
  41. package/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +4 -1
  42. package/src/components/Modal/Modal.module.scss +12 -0
  43. package/src/components/Modal/Modal.tsx +4 -1
  44. package/src/components/Results/HeaderButton.tsx +5 -12
  45. package/src/components/Results/Result.tsx +5 -3
  46. package/src/components/Results/Results.module.scss +13 -1
  47. package/src/components/Results/Results.tsx +29 -43
  48. package/src/components/Results/types.ts +1 -1
  49. package/src/components/Solver/Solver.module.scss +4 -0
  50. package/src/components/Solver/Solver.tsx +9 -12
  51. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +5 -6
  52. package/src/components/Tile/Tile.module.scss +40 -71
  53. package/src/components/Tile/Tile.tsx +4 -3
  54. package/src/components/Tile/TilePure.tsx +4 -13
  55. package/src/hooks/useAppLayout.ts +3 -1
  56. package/src/i18n/de.json +0 -1
  57. package/src/i18n/en.json +0 -1
  58. package/src/i18n/es.json +0 -1
  59. package/src/i18n/fa.json +0 -1
  60. package/src/i18n/fr.json +0 -1
  61. package/src/i18n/pl.json +0 -1
  62. package/src/lib/createRegExp.ts +13 -0
  63. package/src/lib/groupResults.ts +38 -0
  64. package/src/lib/guessLocale.ts +22 -0
  65. package/src/lib/index.ts +4 -1
  66. package/src/lib/sortResults.ts +6 -10
  67. package/src/modals/DictionaryModal/DictionaryModal.module.scss +0 -1
  68. package/src/modals/MenuModal/MenuModal.module.scss +7 -0
  69. package/src/modals/ResultsModal/ResultsModal.module.scss +2 -3
  70. package/src/modals/ResultsModal/ResultsModal.tsx +23 -11
  71. package/src/pages/api/dictionary/[locale]/[word].ts +0 -1
  72. package/src/pages/api/dictionary/[locale]/index.ts +0 -1
  73. package/src/pages/api/solve.ts +0 -1
  74. package/src/pages/api/verify.ts +0 -1
  75. package/src/pages/api/visit.ts +0 -1
  76. package/src/pages/index.tsx +13 -15
  77. package/src/parameters/index.ts +2 -2
  78. package/src/state/sagas.ts +1 -0
  79. package/src/state/selectors.ts +37 -37
  80. package/src/state/slices/boardInitialState.ts +3 -1
  81. package/src/state/slices/cellFilterInitialState.ts +3 -3
  82. package/src/state/slices/cellFilterSlice.ts +3 -1
  83. package/src/state/slices/dictionaryInitialState.ts +2 -2
  84. package/src/state/slices/rackInitialState.ts +3 -1
  85. package/src/state/slices/resultsInitialState.ts +11 -4
  86. package/src/state/slices/settingsInitialState.ts +10 -21
  87. package/src/state/slices/solveInitialState.ts +2 -2
  88. package/src/state/slices/solveSlice.ts +2 -0
  89. package/src/state/slices/verifyInitialState.ts +13 -4
  90. package/src/styles/mixins.scss +3 -1
  91. package/src/styles/variables.scss +1 -0
  92. package/src/types/index.ts +10 -2
  93. package/.next/static/chunks/pages/_app-270526803bc274eb.js +0 -28
  94. package/.next/static/chunks/pages/index-c6e7754ccf3532df.js +0 -1
  95. package/.next/static/css/ad39b36eab07e613.css +0 -1
  96. package/.next/static/css/e5803e581e4c0451.css +0 -2
  97. package/src/components/Board/types/index.ts +0 -4
  98. /package/.next/static/{esK8DG-6aS5V7QFRtR3YE → Mdvi3FY0PqkILKLbPlVBU}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.11.1",
3
+ "version": "2.11.2",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -31,13 +31,13 @@
31
31
  "@floating-ui/react": "^0.20.1",
32
32
  "@kamilmielnik/trie": "^2.0.1",
33
33
  "@reduxjs/toolkit": "^1.9.3",
34
- "@scrabble-solver/configs": "^2.11.1",
35
- "@scrabble-solver/constants": "^2.11.1",
36
- "@scrabble-solver/dictionaries": "^2.11.1",
37
- "@scrabble-solver/logger": "^2.11.1",
38
- "@scrabble-solver/solver": "^2.11.1",
39
- "@scrabble-solver/types": "^2.11.1",
40
- "@scrabble-solver/word-definitions": "^2.11.1",
34
+ "@scrabble-solver/configs": "^2.11.2",
35
+ "@scrabble-solver/constants": "^2.11.2",
36
+ "@scrabble-solver/dictionaries": "^2.11.2",
37
+ "@scrabble-solver/logger": "^2.11.2",
38
+ "@scrabble-solver/solver": "^2.11.2",
39
+ "@scrabble-solver/types": "^2.11.2",
40
+ "@scrabble-solver/word-definitions": "^2.11.2",
41
41
  "classnames": "^2.3.2",
42
42
  "include-media": "^2.0.0",
43
43
  "include-media-query-builder": "^1.1.0",
@@ -72,5 +72,5 @@
72
72
  "sass": "^1.59.2",
73
73
  "workbox-webpack-plugin": "^6.5.4"
74
74
  },
75
- "gitHead": "8dea3cee4e6f902ab8d1ae2339dd1e48b11db39d"
75
+ "gitHead": "b7ac80ab2a6c0af218756953e354d1e0c7f1e58a"
76
76
  }
@@ -6,6 +6,7 @@
6
6
 
7
7
  position: relative;
8
8
  display: table-cell;
9
+ vertical-align: middle;
9
10
  background-color: var(--color--white);
10
11
  border-bottom: var(--border--width) dotted var(--border--color--light);
11
12
  transition: var(--transition);
@@ -35,42 +36,49 @@
35
36
 
36
37
  &.bonusStart {
37
38
  &::before {
39
+ content: '';
38
40
  background-color: var(--color--bonus--start);
39
41
  }
40
42
  }
41
43
 
42
44
  &.bonusCharacter1 {
43
45
  &::before {
46
+ content: '';
44
47
  background-color: var(--color--bonus--character--1);
45
48
  }
46
49
  }
47
50
 
48
51
  &.bonusCharacter2 {
49
52
  &::before {
53
+ content: '';
50
54
  background-color: var(--color--bonus--character--2);
51
55
  }
52
56
  }
53
57
 
54
58
  &.bonusCharacter3 {
55
59
  &::before {
60
+ content: '';
56
61
  background-color: var(--color--bonus--character--3);
57
62
  }
58
63
  }
59
64
 
60
65
  &.bonusCharacter5 {
61
66
  &::before {
67
+ content: '';
62
68
  background-color: var(--color--bonus--character--5);
63
69
  }
64
70
  }
65
71
 
66
72
  &.bonusCharacterMultiplier2 {
67
73
  &::before {
74
+ content: '';
68
75
  background-color: var(--color--bonus--character-multiplier--2);
69
76
  }
70
77
  }
71
78
 
72
79
  &.bonusCharacterMultiplier3 {
73
80
  &::before {
81
+ content: '';
74
82
  background-color: var(--color--bonus--character-multiplier--3);
75
83
  }
76
84
  }
@@ -91,7 +99,7 @@
91
99
 
92
100
  &.filtered {
93
101
  &::before {
94
- content: ' ';
102
+ content: '';
95
103
  background-color: var(--color--foreground--secondary);
96
104
  }
97
105
  }
@@ -113,7 +121,6 @@
113
121
  font-weight: bold;
114
122
  color: var(--color--white);
115
123
  transition: var(--transition);
116
- content: ' ';
117
124
 
118
125
  [lang='fa-IR'] & {
119
126
  font-family: var(--font--family--latin);
@@ -166,6 +173,7 @@
166
173
  }
167
174
  }
168
175
  }
176
+
169
177
  .icon {
170
178
  $size: 40%;
171
179
 
@@ -19,10 +19,9 @@ import { useLatest } from 'react-use';
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';
22
- import { Direction } from 'types';
22
+ import { Direction, Point } from 'types';
23
23
 
24
24
  import { getPositionInGrid } from '../lib';
25
- import { Point } from '../types';
26
25
 
27
26
  const toggleDirection = (direction: Direction) => (direction === 'vertical' ? 'horizontal' : 'vertical');
28
27
 
@@ -1,4 +1,4 @@
1
- import { Point } from '../types';
1
+ import { Point } from 'types';
2
2
 
3
3
  const getPositionInGrid = <T>(grid: T[][], constraint: (value: T) => boolean): Point | undefined => {
4
4
  for (let y = 0; y < grid.length; ++y) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  $loading-duration: 250ms;
4
4
  $loaded-duration: 100ms;
5
- $hiding-duration: 200ms;
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
  }
@@ -120,3 +120,15 @@
120
120
  padding: var(--spacing--l);
121
121
  overflow: auto;
122
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
  );
@@ -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 sortColumn = useTypedSelector(selectResultsSortColumn);
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
- {sortColumn === column.id && (
40
+ {sort.column === column.id && (
48
41
  <>
49
- {sortDirection === SortDirection.Ascending && <SortUp className={styles.sortIcon} />}
50
- {sortDirection === SortDirection.Descending && <SortDown className={styles.sortIcon} />}
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}
@@ -10,7 +10,6 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
10
10
  background: var(--color--background--element);
11
11
  border: var(--border);
12
12
  border-radius: var(--border--radius);
13
- box-shadow: var(--box-shadow);
14
13
  font-family: var(--font--family--title);
15
14
  }
16
15
 
@@ -115,6 +114,19 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
115
114
  color: var(--color--primary--opposite);
116
115
  }
117
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
+ }
118
130
  }
119
131
 
120
132
  .resultContent {
@@ -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 allResults = useTypedSelector(selectSortedResults);
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
- }, [allResults, listRef, scrollToIndexRef]);
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 filteredResults === 'undefined' && (
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
- {allResults.length === 0 && (
108
- <EmptyState className={styles.emptyState} variant="warning">
109
- {translate('results.empty-state.no-results')}
110
- </EmptyState>
111
- )}
112
-
113
- {allResults.length > 0 && filteredResults.length === 0 && (
114
- <EmptyState className={styles.emptyState} variant="info">
115
- {translate('results.empty-state.no-filtered-results')}
116
- </EmptyState>
117
- )}
118
-
119
- {allResults.length > 0 && filteredResults.length > 0 && (
120
- <div className={styles.listContainer}>
121
- <FixedSizeList
122
- className={classNames(styles.list, {
123
- [styles.outdated]: isOutdated,
124
- })}
125
- direction={direction}
126
- height={height}
127
- itemCount={filteredResults.length}
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 && allResults.length > 0 && !isOutdated && <ResultsInput className={styles.input} />}
129
+ {hasResults && results.length > 0 && !isOutdated && <ResultsInput className={styles.input} />}
144
130
 
145
131
  {isLoading && <Loading />}
146
132
  </div>
@@ -19,5 +19,5 @@ export interface ResultCallbacks {
19
19
 
20
20
  export interface ResultData extends ResultCallbacks {
21
21
  highlightedIndex?: number;
22
- results: Result[];
22
+ results: Result[] | undefined;
23
23
  }
@@ -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);
@@ -11,9 +11,8 @@ 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,
@@ -41,18 +40,16 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
41
40
  const dispatch = useDispatch();
42
41
  const translate = useTranslate();
43
42
  const isTouchDevice = useIsTouchDevice();
44
- const { componentsSpacing, isBoardFullWidth, showColumn, showCompactControls, showFloatingSolveButton } =
43
+ const { columnWidth, componentsSpacing, isBoardFullWidth, showColumn, showCompactControls, showFloatingSolveButton } =
45
44
  useAppLayout();
46
- const [bottomContainerRef, { height: bottomContainerHeight }] = useMeasure<HTMLDivElement>();
47
- const [columnRef, { width: columnWidth }] = useMeasure<HTMLDivElement>();
48
- const maxBoardWidth = width - columnWidth - (showColumn ? componentsSpacing : 0) - 2 * componentsSpacing;
49
- const maxBoardHeight = isBoardFullWidth ? Number.POSITIVE_INFINITY : Math.max(height - bottomContainerHeight, 0);
50
45
  const config = useTypedSelector(selectConfig);
51
46
  const error = useTypedSelector(selectSolveError);
52
47
  const isOutdated = useTypedSelector(selectAreResultsOutdated);
53
48
  const resultCandidate = useTypedSelector(selectResultCandidate);
54
- const allResults = useTypedSelector(selectSortedResults);
55
- const results = useTypedSelector(selectSortedFilteredResults);
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);
56
53
  const [bestResult] = results || [];
57
54
  const cellWidth = (maxBoardWidth - (config.boardWidth + 1) * BORDER_WIDTH) / config.boardWidth;
58
55
  const cellHeight = (maxBoardHeight - (config.boardHeight + 1) * BORDER_WIDTH) / config.boardHeight;
@@ -117,8 +114,8 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
117
114
  <input className={styles.submitInput} tabIndex={-1} type="submit" />
118
115
  </form>
119
116
 
120
- <div className={styles.column} ref={columnRef}>
121
- <Results callbacks={callbacks} />
117
+ <div className={styles.column}>
118
+ <Results callbacks={callbacks} className={styles.results} />
122
119
 
123
120
  <div className={styles.dictionaryContainer}>
124
121
  <Dictionary className={styles.dictionary} />
@@ -145,7 +142,7 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
145
142
  </Alert>
146
143
  )}
147
144
 
148
- {allResults && allResults.length === 0 && !isOutdated && (
145
+ {results && results.length === 0 && !isOutdated && (
149
146
  <Alert className={styles.emptyState} variant="warning">
150
147
  {translate('results.empty-state.no-results')}
151
148
  </Alert>
@@ -10,7 +10,7 @@ import {
10
10
  selectIsLoading,
11
11
  selectLocale,
12
12
  selectResultCandidate,
13
- selectSortedResults,
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 sortedResults = useTypedSelector(selectSortedResults);
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