@scrabble-solver/scrabble-solver 2.10.3 → 2.10.5

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 (194) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +13 -13
  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/176.js +1439 -1658
  16. package/.next/server/chunks/579.js +50 -26
  17. package/.next/server/middleware-build-manifest.js +1 -1
  18. package/.next/server/pages/404.html +2 -2
  19. package/.next/server/pages/404.js.nft.json +1 -1
  20. package/.next/server/pages/500.html +2 -2
  21. package/.next/server/pages/_app.js.nft.json +1 -1
  22. package/.next/server/pages/api/solve.js +22 -6
  23. package/.next/server/pages/index.html +2 -2
  24. package/.next/server/pages/index.js +1509 -52
  25. package/.next/server/pages/index.js.nft.json +1 -1
  26. package/.next/server/pages/index.json +1 -1
  27. package/.next/server/pages-manifest.json +2 -2
  28. package/.next/static/WILX-RgqlLTd4ZoPs8C_E/_buildManifest.js +1 -0
  29. package/.next/static/{FJkPF91uL-OCAJKTTpVSP → WILX-RgqlLTd4ZoPs8C_E}/_ssgManifest.js +0 -0
  30. package/.next/static/chunks/144-6768fe9a92865ec8.js +1 -0
  31. package/.next/static/chunks/490-d29992f1c264d70e.js +5 -0
  32. package/.next/static/chunks/pages/{404-24f9617eeb8d6dc1.js → 404-7619583a9e7188b1.js} +1 -1
  33. package/.next/static/chunks/pages/_app-fa0661b072fc6af9.js +24 -0
  34. package/.next/static/chunks/pages/index-1a6bbb880f28606a.js +1 -0
  35. package/.next/static/css/78e42ad01f580f64.css +1 -0
  36. package/.next/static/css/d80ffccf2315791a.css +1 -0
  37. package/.next/static/css/e737d5d7fbed2434.css +1 -0
  38. package/.next/trace +55 -52
  39. package/package.json +11 -9
  40. package/src/components/Badge/Badge.module.scss +4 -5
  41. package/src/components/Board/BoardPure.tsx +5 -5
  42. package/src/components/Board/components/Cell/Cell.module.scss +11 -11
  43. package/src/components/Button/Button.module.scss +34 -40
  44. package/src/components/Button/Button.tsx +28 -8
  45. package/src/components/Button/Link.tsx +44 -0
  46. package/src/components/Dictionary/Dictionary.module.scss +1 -2
  47. package/src/components/Dictionary/Dictionary.tsx +2 -6
  48. package/src/components/DictionaryInput/DictionaryInput.module.scss +1 -3
  49. package/src/components/EmptyState/EmptyState.module.scss +6 -7
  50. package/src/components/EmptyState/EmptyState.tsx +6 -6
  51. package/src/components/Key/Key.module.scss +0 -1
  52. package/src/components/{Splash/Splash.module.scss → LogoSplashScreen/LogoSplashScreen.module.scss} +1 -1
  53. package/src/components/{Splash/Splash.tsx → LogoSplashScreen/LogoSplashScreen.tsx} +7 -7
  54. package/src/components/LogoSplashScreen/index.ts +1 -0
  55. package/src/components/{Sidebar/Sidebar.module.scss → Modal/Modal.module.scss} +25 -20
  56. package/src/components/{Sidebar/Sidebar.tsx → Modal/Modal.tsx} +9 -9
  57. package/src/components/{Sidebar → Modal}/components/Section/Section.module.scss +0 -0
  58. package/src/components/{Sidebar → Modal}/components/Section/Section.tsx +0 -0
  59. package/src/components/{Sidebar → Modal}/components/Section/index.ts +0 -0
  60. package/src/components/{Sidebar → Modal}/components/index.ts +0 -0
  61. package/src/components/Modal/index.ts +1 -0
  62. package/src/components/NavButtons/NavButtons.tsx +22 -3
  63. package/src/components/Progress/Progress.module.scss +9 -0
  64. package/src/components/Progress/Progress.tsx +38 -0
  65. package/src/components/Progress/index.ts +1 -0
  66. package/src/components/Rack/Rack.module.scss +2 -0
  67. package/src/components/Rack/Rack.tsx +3 -1
  68. package/src/components/Rack/RackTile.tsx +3 -2
  69. package/src/components/Radio/Radio.module.scss +2 -2
  70. package/src/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +76 -0
  71. package/src/components/ResultCandidatePicker/ResultCandidatePicker.tsx +38 -0
  72. package/src/components/ResultCandidatePicker/index.ts +1 -0
  73. package/src/components/Results/Result.tsx +64 -43
  74. package/src/components/Results/Results.module.scss +9 -16
  75. package/src/components/Results/Results.tsx +45 -28
  76. package/src/components/Results/SolveButton.tsx +10 -7
  77. package/src/components/Results/{getColumns.ts → getLocaleColumns.ts} +2 -2
  78. package/src/components/Results/types.ts +16 -0
  79. package/src/components/Results/useColumns.ts +44 -0
  80. package/src/components/ResultsInput/ResultsInput.module.scss +1 -3
  81. package/src/components/Sizer/Sizer.module.scss +10 -0
  82. package/src/components/Sizer/Sizer.tsx +10 -0
  83. package/src/components/Sizer/index.ts +1 -0
  84. package/src/components/Solver/Solver.module.scss +83 -27
  85. package/src/components/Solver/Solver.tsx +158 -25
  86. package/src/components/Solver/components/ApplyButton/ApplyButton.module.scss +5 -0
  87. package/src/components/Solver/components/ApplyButton/ApplyButton.tsx +38 -0
  88. package/src/components/Solver/components/ApplyButton/index.ts +1 -0
  89. package/src/components/Solver/components/EmptyState/EmptyState.module.scss +59 -0
  90. package/src/components/Solver/components/EmptyState/EmptyState.tsx +41 -0
  91. package/src/components/Solver/components/EmptyState/index.ts +1 -0
  92. package/src/components/Solver/components/SolveButton/SolveButton.module.scss +4 -0
  93. package/src/components/Solver/components/SolveButton/SolveButton.tsx +43 -0
  94. package/src/components/Solver/components/SolveButton/index.ts +1 -0
  95. package/src/components/Solver/components/index.ts +3 -0
  96. package/src/components/{Screen/Screen.module.scss → SplashScreen/SplashScreen.module.scss} +2 -12
  97. package/src/components/{Screen/Screen.tsx → SplashScreen/SplashScreen.tsx} +4 -4
  98. package/src/components/SplashScreen/index.ts +1 -0
  99. package/src/components/SquareButton/SquareButton.module.scss +3 -3
  100. package/src/components/SquareButton/SquareButton.tsx +2 -2
  101. package/src/components/Tile/Tile.module.scss +39 -30
  102. package/src/components/Tile/Tile.tsx +2 -2
  103. package/src/components/Tile/TilePure.tsx +9 -5
  104. package/src/components/Tooltip/Tooltip.module.scss +5 -6
  105. package/src/components/index.ts +6 -7
  106. package/src/hooks/index.ts +1 -1
  107. package/src/hooks/useMediaQuery.ts +11 -0
  108. package/src/hooks/usePortal.tsx +1 -1
  109. package/src/i18n/de.json +2 -0
  110. package/src/i18n/en.json +2 -0
  111. package/src/i18n/es.json +2 -0
  112. package/src/i18n/fa.json +2 -0
  113. package/src/i18n/fr.json +2 -0
  114. package/src/i18n/pl.json +2 -0
  115. package/src/icons/CardChecklist.svg +5 -0
  116. package/src/icons/Check.svg +2 -2
  117. package/src/icons/ChevronDown.svg +4 -0
  118. package/src/icons/CrossCircleFill.svg +4 -0
  119. package/src/icons/{CrossFill.svg → CrossSquareFill.svg} +0 -0
  120. package/src/icons/ExclamationTriangleFill.svg +4 -0
  121. package/src/icons/InfoCircleFill.svg +4 -0
  122. package/src/icons/List.svg +4 -0
  123. package/src/icons/Search.svg +4 -0
  124. package/src/icons/index.ts +8 -2
  125. package/src/{components/KeyMap/KeyMap.tsx → modals/KeyMapModal/KeyMapModal.tsx} +11 -13
  126. package/src/{components/KeyMap → modals/KeyMapModal}/components/Mapping/Mapping.module.scss +0 -0
  127. package/src/{components/KeyMap → modals/KeyMapModal}/components/Mapping/Mapping.tsx +0 -0
  128. package/src/{components/KeyMap → modals/KeyMapModal}/components/Mapping/index.ts +0 -0
  129. package/src/{components/KeyMap → modals/KeyMapModal}/components/index.ts +0 -0
  130. package/src/modals/KeyMapModal/index.ts +1 -0
  131. package/src/{components/KeyMap → modals/KeyMapModal}/keys.tsx +1 -2
  132. package/src/modals/MenuModal/MenuModal.module.scss +11 -0
  133. package/src/modals/MenuModal/MenuModal.tsx +56 -0
  134. package/src/modals/MenuModal/index.ts +1 -0
  135. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +28 -0
  136. package/src/{components/RemainingTiles/RemainingTiles.tsx → modals/RemainingTilesModal/RemainingTilesModal.tsx} +14 -12
  137. package/src/{components/RemainingTiles → modals/RemainingTilesModal/components/Character}/Character.module.scss +7 -3
  138. package/src/{components/RemainingTiles → modals/RemainingTilesModal/components/Character}/Character.tsx +11 -3
  139. package/src/modals/RemainingTilesModal/components/Character/index.ts +1 -0
  140. package/src/modals/RemainingTilesModal/components/index.ts +1 -0
  141. package/src/modals/RemainingTilesModal/index.ts +1 -0
  142. package/src/modals/ResultsModal/ResultsModal.module.scss +7 -0
  143. package/src/modals/ResultsModal/ResultsModal.tsx +58 -0
  144. package/src/modals/ResultsModal/index.ts +1 -0
  145. package/src/modals/SettingsModal/SettingsModal.tsx +34 -0
  146. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/AutoGroupTilesSetting.module.scss +0 -0
  147. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +1 -2
  148. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/constants.ts +0 -0
  149. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/index.ts +0 -0
  150. package/src/{components/Settings → modals/SettingsModal}/components/AutoGroupTilesSetting/lib.ts +0 -0
  151. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/ConfigSetting.module.scss +0 -0
  152. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/ConfigSetting.tsx +1 -2
  153. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/index.ts +0 -0
  154. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/options.ts +0 -0
  155. package/src/{components/Settings → modals/SettingsModal}/components/ConfigSetting/types.ts +0 -0
  156. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/LocaleSetting.module.scss +0 -0
  157. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/LocaleSetting.tsx +1 -2
  158. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/index.ts +0 -0
  159. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/options.ts +0 -0
  160. package/src/{components/Settings → modals/SettingsModal}/components/LocaleSetting/types.ts +0 -0
  161. package/src/{components/Settings → modals/SettingsModal}/components/index.ts +0 -0
  162. package/src/modals/SettingsModal/index.ts +1 -0
  163. package/src/{components/Words/Words.module.scss → modals/WordsModal/WordsModal.module.scss} +7 -1
  164. package/src/{components/Words/Words.tsx → modals/WordsModal/WordsModal.tsx} +10 -12
  165. package/src/modals/WordsModal/index.ts +1 -0
  166. package/src/modals/index.ts +6 -0
  167. package/src/pages/index.module.scss +6 -4
  168. package/src/pages/index.tsx +63 -26
  169. package/src/parameters/index.ts +28 -6
  170. package/src/state/createAppStore.ts +7 -4
  171. package/src/styles/mixins.scss +17 -15
  172. package/src/styles/variables.scss +15 -17
  173. package/src/types/index.ts +2 -0
  174. package/tsconfig.json +1 -0
  175. package/.next/cache/webpack/client-development/7.pack_ +0 -0
  176. package/.next/static/FJkPF91uL-OCAJKTTpVSP/_buildManifest.js +0 -1
  177. package/.next/static/chunks/361-d16f336a9752a55a.js +0 -1
  178. package/.next/static/chunks/724-eb48df4d1ba3df8b.js +0 -5
  179. package/.next/static/chunks/pages/_app-959e495f0f221247.js +0 -24
  180. package/.next/static/chunks/pages/index-1e30dafa41bddb80.js +0 -1
  181. package/.next/static/css/aafd07997120f1e4.css +0 -1
  182. package/.next/static/css/cb5b206454513f3c.css +0 -1
  183. package/.next/static/css/eb9d57f7103525ab.css +0 -1
  184. package/src/components/KeyMap/index.ts +0 -1
  185. package/src/components/RemainingTiles/RemainingTiles.module.scss +0 -16
  186. package/src/components/RemainingTiles/index.ts +0 -1
  187. package/src/components/Screen/index.ts +0 -1
  188. package/src/components/Settings/Settings.tsx +0 -35
  189. package/src/components/Settings/index.ts +0 -1
  190. package/src/components/Sidebar/index.ts +0 -1
  191. package/src/components/Splash/index.ts +0 -1
  192. package/src/components/Words/index.ts +0 -1
  193. package/src/hooks/useIsTablet.ts +0 -10
  194. package/src/icons/Play.svg +0 -4
@@ -1,9 +1,9 @@
1
1
  import classNames from 'classnames';
2
- import { FunctionComponent, useLayoutEffect, useRef } from 'react';
2
+ import { FunctionComponent, useEffect, useMemo, useState } from 'react';
3
3
  import { FixedSizeList } from 'react-window';
4
4
 
5
5
  import { LOCALE_FEATURES } from 'i18n';
6
- import { RESULTS_HEADER_HEIGHT, RESULTS_INPUT_HEIGHT, RESULTS_ITEM_HEIGHT } from 'parameters';
6
+ import { BORDER_WIDTH, RESULTS_HEADER_HEIGHT, RESULTS_INPUT_HEIGHT, RESULTS_ITEM_HEIGHT } from 'parameters';
7
7
  import {
8
8
  selectAreResultsOutdated,
9
9
  selectIsLoading,
@@ -19,33 +19,48 @@ import EmptyState from '../EmptyState';
19
19
  import Loading from '../Loading';
20
20
  import ResultsInput from '../ResultsInput';
21
21
 
22
- import getColumns from './getColumns';
23
22
  import HeaderButton from './HeaderButton';
24
23
  import Result from './Result';
25
24
  import styles from './Results.module.scss';
26
25
  import SolveButton from './SolveButton';
26
+ import { ResultCallbacks, ResultData } from './types';
27
+ import useColumns from './useColumns';
27
28
 
28
29
  interface Props {
30
+ callbacks: ResultCallbacks;
29
31
  height: number;
32
+ highlightedIndex?: number;
30
33
  width: number;
31
34
  }
32
35
 
33
- const Results: FunctionComponent<Props> = ({ height, width }) => {
34
- const locale = useTypedSelector(selectLocale);
36
+ const Results: FunctionComponent<Props> = ({ callbacks, height, highlightedIndex, width }) => {
35
37
  const translate = useTranslate();
38
+ const locale = useTypedSelector(selectLocale);
39
+ const { direction } = LOCALE_FEATURES[locale];
36
40
  const allResults = useTypedSelector(selectSortedResults);
37
- const results = useTypedSelector(selectSortedFilteredResults);
41
+ const filteredResults = useTypedSelector(selectSortedFilteredResults);
42
+ const results = filteredResults || [];
38
43
  const isLoading = useTypedSelector(selectIsLoading);
39
44
  const isOutdated = useTypedSelector(selectAreResultsOutdated);
40
45
  const error = useTypedSelector(selectSolveError);
41
- const listRef = useRef<HTMLElement>();
42
- const columns = getColumns(LOCALE_FEATURES[locale]);
43
-
44
- useLayoutEffect(() => {
45
- if (listRef.current) {
46
- listRef.current.scrollTo(0, 0);
47
- }
48
- }, [listRef, results]);
46
+ const itemData = useMemo(() => ({ ...callbacks, highlightedIndex, results }), [callbacks, highlightedIndex, results]);
47
+ const [listRef, setListRef] = useState<FixedSizeList<ResultData> | null>(null);
48
+ const columns = useColumns();
49
+ const scrollToIndex = typeof highlightedIndex === 'number' ? highlightedIndex : 0;
50
+
51
+ useEffect(() => {
52
+ // without setTimeout, the initial scrolling offset is calculated
53
+ // incorrectly, as the list is not fully rendered by the browser yet
54
+ const timeout = globalThis.setTimeout(() => {
55
+ if (listRef) {
56
+ listRef.scrollToItem(scrollToIndex, 'center');
57
+ }
58
+ }, 0);
59
+
60
+ return () => {
61
+ globalThis.clearTimeout(timeout);
62
+ };
63
+ }, [listRef, scrollToIndex]);
49
64
 
50
65
  return (
51
66
  <div className={styles.results}>
@@ -56,52 +71,54 @@ const Results: FunctionComponent<Props> = ({ height, width }) => {
56
71
  </div>
57
72
 
58
73
  {typeof error !== 'undefined' && (
59
- <EmptyState className={styles.emptyState} type="error">
74
+ <EmptyState className={styles.emptyState} variant="error">
60
75
  {error.message}
61
76
  </EmptyState>
62
77
  )}
63
78
 
64
- {typeof error === 'undefined' && typeof results === 'undefined' && (
65
- <EmptyState className={styles.emptyState} type="info">
79
+ {typeof error === 'undefined' && typeof filteredResults === 'undefined' && (
80
+ <EmptyState className={styles.emptyState} variant="info">
66
81
  {translate('results.empty-state.uninitialized')}
67
82
 
68
- <SolveButton />
83
+ <SolveButton className={styles.solveButton} />
69
84
  </EmptyState>
70
85
  )}
71
86
 
72
- {typeof error === 'undefined' && typeof results !== 'undefined' && typeof allResults !== 'undefined' && (
87
+ {typeof error === 'undefined' && typeof filteredResults !== 'undefined' && typeof allResults !== 'undefined' && (
73
88
  <>
74
89
  {isOutdated && (
75
- <EmptyState className={styles.emptyState} type="info">
90
+ <EmptyState className={styles.emptyState} variant="info">
76
91
  {translate('results.empty-state.outdated')}
77
92
 
78
- <SolveButton />
93
+ <SolveButton className={styles.solveButton} />
79
94
  </EmptyState>
80
95
  )}
81
96
 
82
97
  {!isOutdated && (
83
98
  <>
84
99
  {allResults.length === 0 && (
85
- <EmptyState className={styles.emptyState} type="warning">
100
+ <EmptyState className={styles.emptyState} variant="warning">
86
101
  {translate('results.empty-state.no-results')}
87
102
  </EmptyState>
88
103
  )}
89
104
 
90
- {allResults.length > 0 && results.length === 0 && (
91
- <EmptyState className={styles.emptyState} type="info">
105
+ {allResults.length > 0 && filteredResults.length === 0 && (
106
+ <EmptyState className={styles.emptyState} variant="info">
92
107
  {translate('results.empty-state.no-filtered-results')}
93
108
  </EmptyState>
94
109
  )}
95
110
 
96
- {allResults.length > 0 && results.length > 0 && (
111
+ {allResults.length > 0 && filteredResults.length > 0 && (
97
112
  <FixedSizeList
98
113
  className={classNames(styles.list, {
99
114
  [styles.outdated]: isOutdated,
100
115
  })}
101
- height={height - RESULTS_HEADER_HEIGHT - RESULTS_INPUT_HEIGHT}
102
- innerRef={listRef}
103
- itemCount={results.length}
116
+ direction={direction}
117
+ height={height - RESULTS_HEADER_HEIGHT - RESULTS_INPUT_HEIGHT - 2 * BORDER_WIDTH}
118
+ itemCount={filteredResults.length}
119
+ itemData={itemData}
104
120
  itemSize={RESULTS_ITEM_HEIGHT}
121
+ ref={setListRef}
105
122
  width={width}
106
123
  >
107
124
  {Result}
@@ -1,7 +1,7 @@
1
1
  import { FunctionComponent } from 'react';
2
2
  import { useDispatch } from 'react-redux';
3
3
 
4
- import { Play } from 'icons';
4
+ import { Search } from 'icons';
5
5
  import {
6
6
  selectAreResultsOutdated,
7
7
  selectIsLoading,
@@ -13,9 +13,11 @@ import {
13
13
 
14
14
  import Button from '../Button';
15
15
 
16
- import styles from './Results.module.scss';
16
+ interface Props {
17
+ className?: string;
18
+ }
17
19
 
18
- const SolveButton: FunctionComponent = () => {
20
+ const SolveButton: FunctionComponent<Props> = ({ className }) => {
19
21
  const dispatch = useDispatch();
20
22
  const translate = useTranslate();
21
23
  const isLoading = useTypedSelector(selectIsLoading);
@@ -23,17 +25,18 @@ const SolveButton: FunctionComponent = () => {
23
25
  const isOutdated = useTypedSelector(selectAreResultsOutdated);
24
26
  const hasTiles = rack.some((tile) => tile !== null);
25
27
 
26
- const handleRefresh = () => {
28
+ const handleClick = () => {
27
29
  dispatch(solveSlice.actions.submit());
28
30
  };
29
31
 
30
32
  return (
31
33
  <Button
32
- className={styles.outdatedButton}
34
+ className={className}
33
35
  disabled={isLoading || !isOutdated || !hasTiles}
34
- Icon={Play}
36
+ Icon={Search}
35
37
  type="submit"
36
- onClick={handleRefresh}
38
+ variant="primary"
39
+ onClick={handleClick}
37
40
  >
38
41
  {translate('results.solve')}
39
42
  </Button>
@@ -3,7 +3,7 @@ import { ResultColumn } from 'types';
3
3
  import styles from './Results.module.scss';
4
4
  import { Column } from './types';
5
5
 
6
- const getColumns = (options: { consonants: boolean; vowels: boolean }): Column[] => {
6
+ const getLocaleColumns = (options: { consonants: boolean; vowels: boolean }): Column[] => {
7
7
  const { consonants, vowels } = options;
8
8
  const columns: Column[] = [
9
9
  {
@@ -55,4 +55,4 @@ const getColumns = (options: { consonants: boolean; vowels: boolean }): Column[]
55
55
  return columns;
56
56
  };
57
57
 
58
- export default getColumns;
58
+ export default getLocaleColumns;
@@ -1,3 +1,6 @@
1
+ import { Result } from '@scrabble-solver/types';
2
+ import { FocusEvent, MouseEvent } from 'react';
3
+
1
4
  import { ResultColumn, TranslationKey } from 'types';
2
5
 
3
6
  export interface Column {
@@ -5,3 +8,16 @@ export interface Column {
5
8
  id: ResultColumn;
6
9
  translationKey: TranslationKey;
7
10
  }
11
+
12
+ export interface ResultCallbacks {
13
+ onBlur?: (result: Result, event: FocusEvent) => void;
14
+ onClick?: (result: Result, event: MouseEvent) => void;
15
+ onFocus?: (result: Result, event: FocusEvent) => void;
16
+ onMouseEnter?: (result: Result, event: MouseEvent) => void;
17
+ onMouseLeave?: (result: Result, event: MouseEvent) => void;
18
+ }
19
+
20
+ export interface ResultData extends ResultCallbacks {
21
+ highlightedIndex?: number;
22
+ results: Result[];
23
+ }
@@ -0,0 +1,44 @@
1
+ import { useMediaQuery } from 'hooks';
2
+ import { LOCALE_FEATURES } from 'i18n';
3
+ import { selectLocale, useTypedSelector } from 'state';
4
+ import { ResultColumn } from 'types';
5
+
6
+ import getLocaleColumns from './getLocaleColumns';
7
+ import { Column } from './types';
8
+
9
+ const COLUMNS_XS = [ResultColumn.Word, ResultColumn.Points];
10
+
11
+ const COLUMNS_S = [...COLUMNS_XS, ResultColumn.BlanksCount, ResultColumn.WordsCount];
12
+
13
+ const COLUMNS_M = [...COLUMNS_XS];
14
+
15
+ const COLUMNS_L = [...COLUMNS_XS];
16
+
17
+ const useColumns = (): Column[] => {
18
+ const locale = useTypedSelector(selectLocale);
19
+ const localeColumns = getLocaleColumns(LOCALE_FEATURES[locale]);
20
+ const isLessThanXs = useMediaQuery('<xs');
21
+ const isLessThanS = useMediaQuery('<s');
22
+ const isLessThanM = useMediaQuery('<m');
23
+ const isLessThanL = useMediaQuery('<l');
24
+
25
+ if (isLessThanXs) {
26
+ return localeColumns.filter((column) => COLUMNS_XS.includes(column.id));
27
+ }
28
+
29
+ if (isLessThanS) {
30
+ return localeColumns.filter((column) => COLUMNS_S.includes(column.id));
31
+ }
32
+
33
+ if (isLessThanM) {
34
+ return localeColumns.filter((column) => COLUMNS_M.includes(column.id));
35
+ }
36
+
37
+ if (isLessThanL) {
38
+ return localeColumns.filter((column) => COLUMNS_L.includes(column.id));
39
+ }
40
+
41
+ return localeColumns;
42
+ };
43
+
44
+ export default useColumns;
@@ -1,9 +1,7 @@
1
1
  @import 'styles/mixins';
2
2
 
3
3
  .resultsInput {
4
- &:focus-within {
5
- @include focus-effect;
6
- }
4
+ @include focus-effect;
7
5
  }
8
6
 
9
7
  .input {
@@ -0,0 +1,10 @@
1
+ .sizer {
2
+ position: absolute;
3
+ top: 0;
4
+ right: 0;
5
+ bottom: 0;
6
+ left: 0;
7
+ width: 100%;
8
+ height: 100%;
9
+ visibility: hidden;
10
+ }
@@ -0,0 +1,10 @@
1
+ import classNames from 'classnames';
2
+ import { forwardRef, HTMLProps } from 'react';
3
+
4
+ import styles from './Sizer.module.scss';
5
+
6
+ const Sizer = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(({ className, ...props }, ref) => (
7
+ <div className={classNames(styles.sizer, className)} ref={ref} {...props} />
8
+ ));
9
+
10
+ export default Sizer;
@@ -0,0 +1 @@
1
+ export { default } from './Sizer';
@@ -1,46 +1,60 @@
1
1
  @import 'styles/mixins';
2
2
 
3
3
  .solver {
4
+ --spacing: var(--spacing--xl);
5
+
6
+ position: relative;
7
+ margin: 0 var(--spacing);
4
8
  display: flex;
5
9
  flex-direction: column;
6
- height: 100%;
7
- }
8
10
 
9
- .contentWrapper {
10
- $board-size: 15;
11
- $tile-size-max: 60px;
12
- $tile-border-size: 1px;
11
+ @include media('<xl') {
12
+ --spacing: var(--spacing--l);
13
+ }
13
14
 
14
- flex: 1;
15
- padding: 0 var(--spacing--xl);
16
- max-height: $board-size * ($tile-size-max + $tile-border-size) + $tile-border-size;
15
+ @include media('<l', 'touch') {
16
+ margin-bottom: calc(3 * var(--spacing--l) + var(--button--icon--size));
17
+ }
18
+
19
+ @include media('<xs', 'touch') {
20
+ margin-bottom: calc(1 * var(--spacing--m) + 2 * var(--spacing--l) + var(--button--icon--size));
21
+ }
17
22
  }
18
23
 
19
- .content {
24
+ .container {
25
+ position: relative;
20
26
  display: flex;
21
27
  align-items: center;
22
28
  justify-content: center;
23
- height: 100%;
24
- gap: var(--spacing--xl);
29
+ }
25
30
 
26
- @include tablet {
27
- gap: var(--spacing--l);
31
+ .content {
32
+ display: grid;
33
+ grid-template-columns: minmax(0, 1fr) var(--solver-column--width);
34
+ gap: var(--spacing);
35
+ margin: 0 auto;
36
+
37
+ @include media('<l') {
38
+ grid-template-columns: 1fr;
28
39
  }
29
40
  }
30
41
 
31
42
  .boardContainer {
32
- display: flex;
33
43
  position: relative;
34
44
  }
35
45
 
36
- .sidebar {
46
+ .board {
47
+ margin: 0 auto;
48
+ }
49
+
50
+ .column {
37
51
  display: flex;
38
52
  flex-direction: column;
39
- flex: 0 0 var(--sidebar--width);
40
- gap: var(--spacing--xl);
53
+ flex: 0 0 var(--solver-column--width);
54
+ gap: var(--spacing);
41
55
 
42
- @include tablet {
43
- gap: var(--spacing--l);
56
+ @include media('<l') {
57
+ display: none;
44
58
  }
45
59
  }
46
60
 
@@ -63,17 +77,24 @@
63
77
  position: relative;
64
78
  }
65
79
 
66
- .rackContainer {
67
- position: relative;
68
- z-index: 1;
80
+ .bottomContainer {
69
81
  flex: 0 0 auto;
70
82
  display: flex;
71
83
  justify-content: center;
72
- margin: var(--spacing--xl) var(--spacing--l);
84
+ }
73
85
 
74
- @include tablet {
75
- margin: var(--spacing--l);
76
- }
86
+ .bottomContent {
87
+ display: inline-flex;
88
+ flex-direction: column;
89
+ align-items: center;
90
+ gap: var(--spacing);
91
+ margin: var(--spacing) auto;
92
+ min-width: 0;
93
+ }
94
+
95
+ .rackContainer {
96
+ display: flex;
97
+ justify-content: center;
77
98
  }
78
99
 
79
100
  .rack {
@@ -83,3 +104,38 @@
83
104
  .submitInput {
84
105
  display: none;
85
106
  }
107
+
108
+ .controls {
109
+ width: 100%;
110
+ display: flex;
111
+ align-items: flex-start;
112
+ justify-content: center;
113
+ gap: var(--spacing--l);
114
+ }
115
+
116
+ .resultCandidatePicker {
117
+ flex: 1;
118
+ }
119
+
120
+ .apply {
121
+ flex: 0 0 auto;
122
+ }
123
+
124
+ .solve {
125
+ --spacing: var(--spacing--l);
126
+
127
+ position: fixed;
128
+ bottom: var(--spacing);
129
+
130
+ @include media('<xs') {
131
+ --spacing: var(--spacing--m);
132
+ }
133
+
134
+ [dir='ltr'] & {
135
+ right: var(--spacing);
136
+ }
137
+
138
+ [dir='rtl'] & {
139
+ left: var(--spacing);
140
+ }
141
+ }