@scrabble-solver/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.
Files changed (137) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +7 -7
  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 +523 -611
  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 +0 -24
  21. package/.next/server/pages/_app.js.nft.json +1 -1
  22. package/.next/server/pages/_document.js.nft.json +1 -1
  23. package/.next/server/pages/api/dictionary/[locale]/[word].js +0 -1
  24. package/.next/server/pages/api/dictionary/[locale].js +0 -1
  25. package/.next/server/pages/api/solve.js +28 -8
  26. package/.next/server/pages/api/verify.js +0 -1
  27. package/.next/server/pages/api/visit.js +0 -1
  28. package/.next/server/pages/index.html +1 -1
  29. package/.next/server/pages/index.js +49 -90
  30. package/.next/server/pages/index.js.nft.json +1 -1
  31. package/.next/server/pages/index.json +1 -1
  32. package/.next/static/Mdvi3FY0PqkILKLbPlVBU/_buildManifest.js +1 -0
  33. package/.next/static/chunks/pages/{404-e0f30450e9920dc3.js → 404-448ba28510855455.js} +1 -1
  34. package/.next/static/chunks/pages/_app-495e6f4ccc278bb2.js +28 -0
  35. package/.next/static/chunks/pages/index-5ecc51900ca29685.js +1 -0
  36. package/.next/static/css/17b0a2db8742105f.css +1 -0
  37. package/.next/static/css/e1ffeb2558330c55.css +2 -0
  38. package/.next/trace +54 -55
  39. package/package.json +9 -14
  40. package/src/components/{Solver/components/EmptyState/EmptyState.module.scss → Alert/Alert.module.scss} +11 -7
  41. package/src/components/{Solver/components/EmptyState/EmptyState.tsx → Alert/Alert.tsx} +8 -6
  42. package/src/components/Alert/index.ts +1 -0
  43. package/src/components/Board/Board.module.scss +55 -0
  44. package/src/components/Board/BoardPure.tsx +4 -0
  45. package/src/components/Board/components/Cell/Cell.module.scss +51 -2
  46. package/src/components/Board/components/Cell/Cell.tsx +12 -0
  47. package/src/components/Board/components/Cell/CellPure.tsx +12 -0
  48. package/src/components/Board/hooks/useGrid.ts +9 -26
  49. package/src/components/Board/lib/getPositionInGrid.ts +1 -1
  50. package/src/components/Dictionary/Dictionary.module.scss +4 -0
  51. package/src/components/DictionaryInput/DictionaryInput.module.scss +1 -0
  52. package/src/components/EmptyState/EmptyState.module.scss +2 -1
  53. package/src/components/EmptyState/EmptyState.tsx +1 -2
  54. package/src/components/Loading/Loading.module.scss +1 -1
  55. package/src/components/Logo/Logo.tsx +5 -0
  56. package/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +4 -1
  57. package/src/components/Modal/Modal.module.scss +14 -0
  58. package/src/components/Modal/Modal.tsx +4 -1
  59. package/src/components/PlainTiles/PlainTiles.module.scss +1 -1
  60. package/src/components/PlainTiles/Tile.tsx +3 -3
  61. package/src/components/Rack/Rack.module.scss +25 -0
  62. package/src/components/Rack/Rack.tsx +5 -4
  63. package/src/components/Rack/RackTile.tsx +6 -13
  64. package/src/components/Results/HeaderButton.tsx +5 -12
  65. package/src/components/Results/Result.tsx +5 -3
  66. package/src/components/Results/Results.module.scss +41 -1
  67. package/src/components/Results/Results.tsx +29 -43
  68. package/src/components/Results/types.ts +1 -1
  69. package/src/components/ResultsInput/ResultsInput.module.scss +1 -0
  70. package/src/components/Solver/Solver.module.scss +9 -4
  71. package/src/components/Solver/Solver.tsx +17 -19
  72. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +5 -6
  73. package/src/components/Solver/components/index.ts +0 -1
  74. package/src/components/Tile/Tile.module.scss +42 -61
  75. package/src/components/Tile/Tile.tsx +4 -3
  76. package/src/components/Tile/TilePure.tsx +4 -13
  77. package/src/components/Tooltip/Tooltip.module.scss +1 -72
  78. package/src/components/Tooltip/useTooltip.tsx +25 -35
  79. package/src/components/index.ts +1 -0
  80. package/src/hooks/index.ts +0 -1
  81. package/src/hooks/useAppLayout.ts +3 -1
  82. package/src/i18n/de.json +0 -1
  83. package/src/i18n/en.json +0 -1
  84. package/src/i18n/es.json +0 -1
  85. package/src/i18n/fa.json +0 -1
  86. package/src/i18n/fr.json +0 -1
  87. package/src/i18n/pl.json +0 -1
  88. package/src/lib/createRegExp.ts +13 -0
  89. package/src/lib/groupResults.ts +38 -0
  90. package/src/lib/guessLocale.ts +22 -0
  91. package/src/lib/index.ts +4 -2
  92. package/src/lib/sortResults.ts +6 -10
  93. package/src/modals/DictionaryModal/DictionaryModal.module.scss +6 -2
  94. package/src/modals/KeyMapModal/KeyMapModal.tsx +5 -21
  95. package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +4 -0
  96. package/src/modals/MenuModal/MenuModal.module.scss +7 -0
  97. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
  98. package/src/modals/ResultsModal/ResultsModal.module.scss +3 -3
  99. package/src/modals/ResultsModal/ResultsModal.tsx +23 -11
  100. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +2 -0
  101. package/src/modals/WordsModal/WordsModal.module.scss +8 -1
  102. package/src/pages/api/dictionary/[locale]/[word].ts +0 -1
  103. package/src/pages/api/dictionary/[locale]/index.ts +0 -1
  104. package/src/pages/api/solve.ts +0 -1
  105. package/src/pages/api/verify.ts +0 -1
  106. package/src/pages/api/visit.ts +0 -1
  107. package/src/pages/index.tsx +13 -15
  108. package/src/parameters/index.ts +2 -2
  109. package/src/state/createAppStore.ts +26 -10
  110. package/src/state/sagas.ts +1 -0
  111. package/src/state/selectors.ts +37 -37
  112. package/src/state/slices/boardInitialState.ts +3 -1
  113. package/src/state/slices/cellFilterInitialState.ts +3 -3
  114. package/src/state/slices/cellFilterSlice.ts +3 -1
  115. package/src/state/slices/dictionaryInitialState.ts +2 -2
  116. package/src/state/slices/rackInitialState.ts +3 -1
  117. package/src/state/slices/resultsInitialState.ts +11 -4
  118. package/src/state/slices/settingsInitialState.ts +10 -21
  119. package/src/state/slices/solveInitialState.ts +2 -2
  120. package/src/state/slices/solveSlice.ts +2 -0
  121. package/src/state/slices/verifyInitialState.ts +13 -4
  122. package/src/state/types.ts +20 -2
  123. package/src/styles/mixins.scss +25 -1
  124. package/src/styles/variables.scss +17 -1
  125. package/src/types/index.ts +10 -2
  126. package/.next/static/45ye7793DY705HOcuK9lJ/_buildManifest.js +0 -1
  127. package/.next/static/chunks/pages/_app-d7acee5e526752d9.js +0 -28
  128. package/.next/static/chunks/pages/index-35d2c1c79a201ae2.js +0 -1
  129. package/.next/static/css/a48caa6f57de6e98.css +0 -1
  130. package/.next/static/css/c49bbe944ddd1b39.css +0 -2
  131. package/src/components/Board/types/index.ts +0 -4
  132. package/src/components/Solver/components/EmptyState/index.ts +0 -1
  133. package/src/components/Tooltip/constants.ts +0 -28
  134. package/src/hooks/useUniqueId.ts +0 -9
  135. package/src/lib/isCtrl.ts +0 -7
  136. package/src/state/rootReducer.ts +0 -25
  137. /package/.next/static/{45ye7793DY705HOcuK9lJ → 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.0",
3
+ "version": "2.11.2",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -30,15 +30,14 @@
30
30
  "dependencies": {
31
31
  "@floating-ui/react": "^0.20.1",
32
32
  "@kamilmielnik/trie": "^2.0.1",
33
- "@popperjs/core": "^2.11.6",
34
33
  "@reduxjs/toolkit": "^1.9.3",
35
- "@scrabble-solver/configs": "^2.11.0",
36
- "@scrabble-solver/constants": "^2.11.0",
37
- "@scrabble-solver/dictionaries": "^2.11.0",
38
- "@scrabble-solver/logger": "^2.11.0",
39
- "@scrabble-solver/solver": "^2.11.0",
40
- "@scrabble-solver/types": "^2.11.0",
41
- "@scrabble-solver/word-definitions": "^2.11.0",
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",
42
41
  "classnames": "^2.3.2",
43
42
  "include-media": "^2.0.0",
44
43
  "include-media-query-builder": "^1.1.0",
@@ -47,15 +46,12 @@
47
46
  "react": "^18.2.0",
48
47
  "react-dom": "^18.2.0",
49
48
  "react-modal": "^3.16.1",
50
- "react-popper": "^2.3.0",
51
49
  "react-portal": "^4.2.2",
52
50
  "react-redux": "^8.0.5",
53
51
  "react-use": "^17.4.0",
54
52
  "react-window": "^1.8.8",
55
- "redux": "^4.2.1",
56
53
  "redux-saga": "^1.2.2",
57
54
  "store2": "^2.14.2",
58
- "uuid": "^9.0.0",
59
55
  "workbox-expiration": "^6.5.4",
60
56
  "workbox-precaching": "^6.5.4",
61
57
  "workbox-routing": "^6.5.4",
@@ -72,10 +68,9 @@
72
68
  "@types/react-window": "^1.8.5",
73
69
  "@types/redux": "^3.6.31",
74
70
  "@types/redux-saga": "^0.10.5",
75
- "@types/uuid": "^9.0.1",
76
71
  "env-cmd": "^10.1.0",
77
72
  "sass": "^1.59.2",
78
73
  "workbox-webpack-plugin": "^6.5.4"
79
74
  },
80
- "gitHead": "493dd931e7f16c34c425295a0f048756d6c192c8"
75
+ "gitHead": "b7ac80ab2a6c0af218756953e354d1e0c7f1e58a"
81
76
  }
@@ -1,4 +1,4 @@
1
- .emptyState {
1
+ .alert {
2
2
  display: flex;
3
3
  min-width: 0;
4
4
  width: 100%;
@@ -11,7 +11,6 @@
11
11
  .iconContainer {
12
12
  flex: 0 0 auto;
13
13
  display: flex;
14
- align-items: center;
15
14
  justify-content: center;
16
15
  padding: var(--spacing--m);
17
16
  color: var(--color--foreground--secondary);
@@ -33,15 +32,20 @@
33
32
  color: var(--color--error);
34
33
  }
35
34
 
36
- .warning & {
37
- background-color: var(--color--yellow--light);
38
- color: var(--color--warning);
39
- }
40
-
41
35
  .info & {
42
36
  background-color: var(--color--blue--light);
43
37
  color: var(--color--info);
44
38
  }
39
+
40
+ .success & {
41
+ background-color: var(--color--green--light);
42
+ color: var(--color--success);
43
+ }
44
+
45
+ .warning & {
46
+ background-color: var(--color--yellow--light);
47
+ color: var(--color--warning);
48
+ }
45
49
  }
46
50
 
47
51
  .icon {
@@ -1,30 +1,32 @@
1
1
  import classNames from 'classnames';
2
2
  import { FunctionComponent, HTMLProps, ReactNode, SVGAttributes } from 'react';
3
3
 
4
- import { CrossCircleFill, ExclamationTriangleFill, InfoCircleFill } from 'icons';
4
+ import { Check, CrossCircleFill, ExclamationTriangleFill, InfoCircleFill } from 'icons';
5
5
 
6
- import styles from './EmptyState.module.scss';
6
+ import styles from './Alert.module.scss';
7
7
 
8
8
  interface Props extends HTMLProps<HTMLDivElement> {
9
9
  children: ReactNode;
10
10
  className?: string;
11
- variant: 'error' | 'info' | 'warning';
11
+ variant: 'error' | 'info' | 'success' | 'warning';
12
12
  }
13
13
 
14
14
  const ICON_PER_TYPE: Record<Props['variant'], FunctionComponent<SVGAttributes<SVGElement>>> = {
15
15
  error: CrossCircleFill,
16
16
  info: InfoCircleFill,
17
+ success: Check,
17
18
  warning: ExclamationTriangleFill,
18
19
  };
19
20
 
20
- const EmptyState: FunctionComponent<Props> = ({ children, className, variant, ...props }) => {
21
+ const Alert: FunctionComponent<Props> = ({ children, className, variant, ...props }) => {
21
22
  const Icon = ICON_PER_TYPE[variant];
22
23
 
23
24
  return (
24
25
  <div
25
- className={classNames(styles.emptyState, className, {
26
+ className={classNames(styles.alert, className, {
26
27
  [styles.error]: variant === 'error',
27
28
  [styles.info]: variant === 'info',
29
+ [styles.success]: variant === 'success',
28
30
  [styles.warning]: variant === 'warning',
29
31
  })}
30
32
  {...props}
@@ -38,4 +40,4 @@ const EmptyState: FunctionComponent<Props> = ({ children, className, variant, ..
38
40
  );
39
41
  };
40
42
 
41
- export default EmptyState;
43
+ export default Alert;
@@ -0,0 +1 @@
1
+ export { default } from './Alert';
@@ -4,10 +4,65 @@
4
4
  display: table;
5
5
  box-shadow: var(--box-shadow);
6
6
  border: var(--border);
7
+ border-radius: var(--border--radius);
7
8
  }
8
9
 
9
10
  .row {
10
11
  display: table-row;
12
+
13
+ &:first-child {
14
+ border-top-left-radius: var(--border--radius);
15
+ border-top-right-radius: var(--border--radius);
16
+
17
+ .cell {
18
+ &:first-child {
19
+ [dir='ltr'] & {
20
+ border-top-left-radius: var(--border--radius);
21
+ }
22
+
23
+ [dir='rtl'] & {
24
+ border-top-right-radius: var(--border--radius);
25
+ }
26
+ }
27
+
28
+ &:last-child {
29
+ [dir='ltr'] & {
30
+ border-top-right-radius: var(--border--radius);
31
+ }
32
+
33
+ [dir='rtl'] & {
34
+ border-top-left-radius: var(--border--radius);
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ &:last-child {
41
+ border-bottom-left-radius: var(--border--radius);
42
+ border-bottom-right-radius: var(--border--radius);
43
+
44
+ .cell {
45
+ &:first-child {
46
+ [dir='ltr'] & {
47
+ border-bottom-left-radius: var(--border--radius);
48
+ }
49
+
50
+ [dir='rtl'] & {
51
+ border-bottom-right-radius: var(--border--radius);
52
+ }
53
+ }
54
+
55
+ &:last-child {
56
+ [dir='ltr'] & {
57
+ border-bottom-right-radius: var(--border--radius);
58
+ }
59
+
60
+ [dir='rtl'] & {
61
+ border-bottom-left-radius: var(--border--radius);
62
+ }
63
+ }
64
+ }
65
+ }
11
66
  }
12
67
 
13
68
  .actions {
@@ -45,6 +45,10 @@ const BoardPure: FunctionComponent<Props> = ({
45
45
  <Cell
46
46
  className={styles.cell}
47
47
  cell={cell}
48
+ cellBottom={y < rows.length - 1 ? rows[y + 1][x] : undefined}
49
+ cellLeft={x > 0 ? rows[y][x - 1] : undefined}
50
+ cellRight={x < rows.length - 1 ? rows[y][x + 1] : undefined}
51
+ cellTop={y > 0 ? rows[y - 1][x] : undefined}
48
52
  inputRef={inputRefs[y][x]}
49
53
  isBottom={y === rows.length - 1}
50
54
  isCenter={center.x === x && center.y === y}
@@ -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);
@@ -125,6 +132,48 @@
125
132
  }
126
133
  }
127
134
 
135
+ .tile {
136
+ .sharpTopLeft & {
137
+ [dir='ltr'] & {
138
+ border-top-left-radius: 0;
139
+ }
140
+
141
+ [dir='rtl'] & {
142
+ border-top-right-radius: 0;
143
+ }
144
+ }
145
+
146
+ .sharpTopRight & {
147
+ [dir='ltr'] & {
148
+ border-top-right-radius: 0;
149
+ }
150
+
151
+ [dir='rtl'] & {
152
+ border-top-left-radius: 0;
153
+ }
154
+ }
155
+
156
+ .sharpBottomLeft & {
157
+ [dir='ltr'] & {
158
+ border-bottom-left-radius: 0;
159
+ }
160
+
161
+ [dir='rtl'] & {
162
+ border-bottom-right-radius: 0;
163
+ }
164
+ }
165
+
166
+ .sharpBottomRight & {
167
+ [dir='ltr'] & {
168
+ border-bottom-right-radius: 0;
169
+ }
170
+
171
+ [dir='rtl'] & {
172
+ border-bottom-left-radius: 0;
173
+ }
174
+ }
175
+ }
176
+
128
177
  .icon {
129
178
  $size: 40%;
130
179
 
@@ -17,6 +17,10 @@ import CellPure from './CellPure';
17
17
 
18
18
  interface Props {
19
19
  cell: CellModel;
20
+ cellBottom?: CellModel;
21
+ cellLeft?: CellModel;
22
+ cellRight?: CellModel;
23
+ cellTop?: CellModel;
20
24
  className?: string;
21
25
  inputRef: RefObject<HTMLInputElement>;
22
26
  isBottom: boolean;
@@ -29,6 +33,10 @@ interface Props {
29
33
 
30
34
  const Cell: FunctionComponent<Props> = ({
31
35
  cell,
36
+ cellBottom,
37
+ cellLeft,
38
+ cellRight,
39
+ cellTop,
32
40
  className,
33
41
  inputRef,
34
42
  isBottom,
@@ -59,6 +67,10 @@ const Cell: FunctionComponent<Props> = ({
59
67
  })}
60
68
  bonus={bonus}
61
69
  cell={cell}
70
+ cellBottom={cellBottom}
71
+ cellLeft={cellLeft}
72
+ cellRight={cellRight}
73
+ cellTop={cellTop}
62
74
  className={className}
63
75
  inputRef={inputRef}
64
76
  isBottom={isBottom}
@@ -13,6 +13,10 @@ interface Props {
13
13
  'aria-label': string;
14
14
  bonus: Bonus | undefined;
15
15
  cell: Cell;
16
+ cellBottom?: Cell;
17
+ cellLeft?: Cell;
18
+ cellRight?: Cell;
19
+ cellTop?: Cell;
16
20
  className?: string;
17
21
  inputRef: RefObject<HTMLInputElement>;
18
22
  isBottom: boolean;
@@ -33,6 +37,10 @@ const CellPure: FunctionComponent<Props> = ({
33
37
  'aria-label': ariaLabel,
34
38
  bonus,
35
39
  cell,
40
+ cellBottom,
41
+ cellLeft,
42
+ cellRight,
43
+ cellTop,
36
44
  className,
37
45
  inputRef,
38
46
  isBottom,
@@ -53,6 +61,10 @@ const CellPure: FunctionComponent<Props> = ({
53
61
  [styles.bottom]: isBottom,
54
62
  [styles.filtered]: isFiltered,
55
63
  [styles.right]: isRight,
64
+ [styles.sharpTopLeft]: cellTop?.hasTile() || cellLeft?.hasTile(),
65
+ [styles.sharpTopRight]: cellTop?.hasTile() || cellRight?.hasTile(),
66
+ [styles.sharpBottomLeft]: cellBottom?.hasTile() || cellLeft?.hasTile(),
67
+ [styles.sharpBottomRight]: cellBottom?.hasTile() || cellRight?.hasTile(),
56
68
  })}
57
69
  style={style}
58
70
  >
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable max-lines, max-statements */
2
+ import { PayloadAction } from '@reduxjs/toolkit';
2
3
  import { BLANK, EMPTY_CELL } from '@scrabble-solver/constants';
3
4
  import { Board, Cell } from '@scrabble-solver/types';
4
5
  import {
@@ -14,15 +15,13 @@ import {
14
15
  } from 'react';
15
16
  import { useDispatch } from 'react-redux';
16
17
  import { useLatest } from 'react-use';
17
- import { AnyAction } from 'redux';
18
18
 
19
19
  import { LOCALE_FEATURES } from 'i18n';
20
- import { createGridOf, createKeyboardNavigation, extractCharacters, extractInputValue, isCtrl } from 'lib';
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
 
@@ -85,7 +84,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
85
84
  const insertValue = useCallback(
86
85
  (position: Point, value: string) => {
87
86
  const characters = value ? extractCharacters(config, value).filter((character) => character !== BLANK) : [BLANK];
88
- const actions: AnyAction[] = [];
87
+ const actions: PayloadAction<unknown>[] = [];
89
88
  let board = new Board({ rows: rows.map((row) => row.map((cell) => cell.clone())) });
90
89
  let { x, y } = position;
91
90
 
@@ -225,7 +224,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
225
224
  onArrowDown: (event) => {
226
225
  event.preventDefault();
227
226
 
228
- if (isCtrl(event)) {
227
+ if (direction === 'horizontal') {
229
228
  onDirectionToggle();
230
229
  } else {
231
230
  changeActiveIndex(0, 1);
@@ -234,7 +233,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
234
233
  onArrowLeft: (event) => {
235
234
  event.preventDefault();
236
235
 
237
- if (isCtrl(event)) {
236
+ if (direction === 'vertical') {
238
237
  onDirectionToggle();
239
238
  } else {
240
239
  changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? -1 : 1, 0);
@@ -243,7 +242,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
243
242
  onArrowRight: (event) => {
244
243
  event.preventDefault();
245
244
 
246
- if (isCtrl(event)) {
245
+ if (direction === 'vertical') {
247
246
  onDirectionToggle();
248
247
  } else {
249
248
  changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? 1 : -1, 0);
@@ -252,7 +251,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
252
251
  onArrowUp: (event) => {
253
252
  event.preventDefault();
254
253
 
255
- if (isCtrl(event)) {
254
+ if (direction === 'horizontal') {
256
255
  onDirectionToggle();
257
256
  } else {
258
257
  changeActiveIndex(0, -1);
@@ -289,22 +288,6 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
289
288
 
290
289
  const { x, y } = position;
291
290
  const character = event.key.toLowerCase();
292
- const isTogglingBlank = isCtrl(event) && character === 'b';
293
- const twoCharacterTile = config.getTwoCharacterTileByPrefix(character);
294
-
295
- if (isTogglingBlank) {
296
- event.preventDefault();
297
- dispatch(boardSlice.actions.toggleCellIsBlank(position));
298
- return;
299
- }
300
-
301
- if (isCtrl(event) && twoCharacterTile) {
302
- event.preventDefault();
303
- dispatch(boardSlice.actions.changeCellValue({ x, y, value: twoCharacterTile }));
304
- moveFocus(1);
305
- return;
306
- }
307
-
308
291
  const cell = rows[y][x];
309
292
  const twoCharacterCandidate = cell.tile.character + character;
310
293
 
@@ -333,7 +316,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
333
316
  dispatch(boardSlice.actions.toggleCellIsBlank(position));
334
317
  },
335
318
  });
336
- }, [changeActiveIndex, config, dispatch, locale, moveFocus, onDirectionToggle, rows]);
319
+ }, [changeActiveIndex, config, direction, dispatch, locale, moveFocus, onDirectionToggle, rows]);
337
320
 
338
321
  const onPaste = useCallback<ClipboardEventHandler>(
339
322
  (event) => {
@@ -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) {
@@ -1,4 +1,8 @@
1
+ @import 'styles/mixins';
2
+
1
3
  .dictionary {
4
+ @include scrollbars;
5
+
2
6
  position: relative;
3
7
  max-height: var(--dictionary--height);
4
8
  height: var(--dictionary--height);
@@ -8,4 +8,5 @@
8
8
  @include text-input;
9
9
 
10
10
  border: none;
11
+ border-radius: inherit;
11
12
  }
@@ -8,7 +8,8 @@
8
8
 
9
9
  .tiles {
10
10
  display: inline-block;
11
+ max-width: 100%;
11
12
  margin-bottom: var(--spacing--m);
12
- height: 40px;
13
+ height: 48px;
13
14
  overflow: visible;
14
15
  }
@@ -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
  };
@@ -30,6 +30,6 @@
30
30
  }
31
31
 
32
32
  .tiles {
33
- width: 298px;
33
+ width: 100% * 2 / 3;
34
34
  height: 100%;
35
35
  }
@@ -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';
@@ -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
  }
@@ -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
  );
@@ -20,5 +20,5 @@ $duration: 750ms;
20
20
  }
21
21
 
22
22
  .dropShadow {
23
- filter: drop-shadow(0 0 4px rgba(#000, 0.4));
23
+ filter: drop-shadow(0 3px 3px rgba(0, 0, 0, 0.4));
24
24
  }