scrabble-solver 2.10.11 → 2.11.1

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 (172) hide show
  1. package/lerna.json +1 -1
  2. package/package.json +8 -8
  3. package/packages/configs/package.json +3 -3
  4. package/packages/constants/package.json +1 -1
  5. package/packages/dictionaries/package-lock.json +2 -2
  6. package/packages/dictionaries/package.json +4 -4
  7. package/packages/logger/package-lock.json +8 -8
  8. package/packages/logger/package.json +1 -1
  9. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  10. package/packages/scrabble-solver/.next/build-manifest.json +12 -12
  11. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  12. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  13. package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
  14. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  15. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  16. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  17. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  18. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  19. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  20. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  21. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  22. package/packages/scrabble-solver/.next/required-server-files.json +1 -1
  23. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  24. package/packages/scrabble-solver/.next/server/chunks/{176.js → 277.js} +956 -930
  25. package/packages/scrabble-solver/.next/server/chunks/{290.js → 417.js} +3 -3
  26. package/packages/scrabble-solver/.next/server/chunks/50.js +371 -343
  27. package/packages/scrabble-solver/.next/server/chunks/664.js +15 -15
  28. package/packages/scrabble-solver/.next/server/chunks/859.js +17 -10
  29. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  30. package/packages/scrabble-solver/.next/server/next-font-manifest.js +1 -0
  31. package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
  32. package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
  33. package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
  34. package/packages/scrabble-solver/.next/server/pages/_app.js +4 -28
  35. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  36. package/packages/scrabble-solver/.next/server/pages/_document.js +2 -2
  37. package/packages/scrabble-solver/.next/server/pages/_document.js.nft.json +1 -1
  38. package/packages/scrabble-solver/.next/server/pages/_error.js +4 -4
  39. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +4 -4
  40. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js.nft.json +1 -1
  41. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js +3 -3
  42. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale].js.nft.json +1 -1
  43. package/packages/scrabble-solver/.next/server/pages/api/solve.js +9 -11
  44. package/packages/scrabble-solver/.next/server/pages/api/solve.js.nft.json +1 -1
  45. package/packages/scrabble-solver/.next/server/pages/api/verify.js +3 -3
  46. package/packages/scrabble-solver/.next/server/pages/api/verify.js.nft.json +1 -1
  47. package/packages/scrabble-solver/.next/server/pages/api/visit.js +3 -3
  48. package/packages/scrabble-solver/.next/server/pages/api/visit.js.nft.json +1 -1
  49. package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
  50. package/packages/scrabble-solver/.next/server/pages/index.js +256 -210
  51. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  52. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  53. package/packages/scrabble-solver/.next/static/chunks/main-0ecb9ccfcb6c9b24.js +1 -0
  54. package/packages/scrabble-solver/.next/static/chunks/pages/404-448ba28510855455.js +1 -0
  55. package/packages/scrabble-solver/.next/static/chunks/pages/_app-270526803bc274eb.js +28 -0
  56. package/packages/scrabble-solver/.next/static/chunks/pages/{_error-8353112a01355ec2.js → _error-54de1933a164a1ff.js} +1 -1
  57. package/packages/scrabble-solver/.next/static/chunks/pages/index-c6e7754ccf3532df.js +1 -0
  58. package/packages/scrabble-solver/.next/static/css/ad39b36eab07e613.css +1 -0
  59. package/packages/scrabble-solver/.next/static/css/e5803e581e4c0451.css +2 -0
  60. package/packages/scrabble-solver/.next/static/esK8DG-6aS5V7QFRtR3YE/_buildManifest.js +1 -0
  61. package/packages/scrabble-solver/.next/trace +53 -55
  62. package/packages/scrabble-solver/package-lock.json +224 -310
  63. package/packages/scrabble-solver/package.json +11 -16
  64. package/packages/scrabble-solver/src/components/{Solver/components/EmptyState/EmptyState.module.scss → Alert/Alert.module.scss} +11 -7
  65. package/packages/scrabble-solver/src/components/{Solver/components/EmptyState/EmptyState.tsx → Alert/Alert.tsx} +8 -6
  66. package/packages/scrabble-solver/src/components/Alert/index.ts +1 -0
  67. package/packages/scrabble-solver/src/components/Board/Board.module.scss +55 -0
  68. package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +4 -0
  69. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +42 -0
  70. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +12 -0
  71. package/packages/scrabble-solver/src/components/Board/components/Cell/CellPure.tsx +12 -0
  72. package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +8 -24
  73. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +17 -8
  74. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.tsx +5 -5
  75. package/packages/scrabble-solver/src/components/DictionaryInput/DictionaryInput.module.scss +1 -0
  76. package/packages/scrabble-solver/src/components/EmptyState/EmptyState.module.scss +2 -1
  77. package/packages/scrabble-solver/src/components/EmptyState/EmptyState.tsx +1 -2
  78. package/packages/scrabble-solver/src/components/Loading/Loading.module.scss +1 -1
  79. package/packages/scrabble-solver/src/components/Loading/Loading.tsx +1 -1
  80. package/packages/scrabble-solver/src/components/Logo/Logo.tsx +5 -0
  81. package/packages/scrabble-solver/src/components/Modal/Modal.module.scss +2 -1
  82. package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +4 -5
  83. package/packages/scrabble-solver/src/components/PlainTiles/PlainTiles.module.scss +1 -1
  84. package/packages/scrabble-solver/src/components/PlainTiles/Tile.tsx +3 -3
  85. package/packages/scrabble-solver/src/components/Rack/Rack.module.scss +25 -0
  86. package/packages/scrabble-solver/src/components/Rack/Rack.tsx +5 -4
  87. package/packages/scrabble-solver/src/components/Rack/RackTile.tsx +6 -13
  88. package/packages/scrabble-solver/src/components/Results/Results.module.scss +33 -2
  89. package/packages/scrabble-solver/src/components/Results/Results.tsx +11 -11
  90. package/packages/scrabble-solver/src/components/ResultsInput/ResultsInput.module.scss +1 -0
  91. package/packages/scrabble-solver/src/components/Solver/Solver.module.scss +6 -4
  92. package/packages/scrabble-solver/src/components/Solver/Solver.tsx +16 -28
  93. package/packages/scrabble-solver/src/components/Solver/components/FloatingSolveButton/FloatingSolveButton.module.scss +7 -0
  94. package/packages/scrabble-solver/src/components/Solver/components/{SolveButton/SolveButton.tsx → FloatingSolveButton/FloatingSolveButton.tsx} +6 -6
  95. package/packages/scrabble-solver/src/components/Solver/components/FloatingSolveButton/index.ts +1 -0
  96. package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +19 -4
  97. package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +13 -1
  98. package/packages/scrabble-solver/src/components/Solver/components/index.ts +1 -2
  99. package/packages/scrabble-solver/src/components/Spinner/Spinner.module.scss +11 -0
  100. package/packages/scrabble-solver/src/components/Spinner/Spinner.tsx +19 -0
  101. package/packages/scrabble-solver/src/components/Spinner/index.ts +1 -0
  102. package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +14 -2
  103. package/packages/scrabble-solver/src/components/Tile/Tile.tsx +5 -5
  104. package/packages/scrabble-solver/src/components/Tooltip/Tooltip.module.scss +1 -72
  105. package/packages/scrabble-solver/src/components/Tooltip/useTooltip.tsx +25 -35
  106. package/packages/scrabble-solver/src/components/index.ts +2 -0
  107. package/packages/scrabble-solver/src/hooks/index.ts +1 -1
  108. package/packages/scrabble-solver/src/hooks/useAppLayout.ts +29 -0
  109. package/packages/scrabble-solver/src/i18n/de.json +1 -0
  110. package/packages/scrabble-solver/src/i18n/en.json +1 -0
  111. package/packages/scrabble-solver/src/i18n/es.json +1 -0
  112. package/packages/scrabble-solver/src/i18n/fa.json +1 -0
  113. package/packages/scrabble-solver/src/i18n/fr.json +1 -0
  114. package/packages/scrabble-solver/src/i18n/index.ts +1 -1
  115. package/packages/scrabble-solver/src/i18n/pl.json +1 -0
  116. package/packages/scrabble-solver/src/lib/index.ts +0 -1
  117. package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.module.scss +23 -0
  118. package/packages/scrabble-solver/src/modals/DictionaryModal/DictionaryModal.tsx +27 -0
  119. package/packages/scrabble-solver/src/modals/DictionaryModal/index.ts +1 -0
  120. package/packages/scrabble-solver/src/modals/KeyMapModal/KeyMapModal.tsx +5 -21
  121. package/packages/scrabble-solver/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +4 -0
  122. package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +7 -1
  123. package/packages/scrabble-solver/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
  124. package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.module.scss +19 -0
  125. package/packages/scrabble-solver/src/modals/ResultsModal/ResultsModal.tsx +8 -7
  126. package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +2 -0
  127. package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.module.scss +8 -1
  128. package/packages/scrabble-solver/src/modals/index.ts +1 -0
  129. package/packages/scrabble-solver/src/pages/api/solve.ts +9 -10
  130. package/packages/scrabble-solver/src/pages/index.tsx +20 -15
  131. package/packages/scrabble-solver/src/state/createAppStore.ts +26 -10
  132. package/packages/scrabble-solver/src/state/localStorage.ts +0 -9
  133. package/packages/scrabble-solver/src/state/types.ts +20 -2
  134. package/packages/scrabble-solver/src/styles/animations.scss +10 -0
  135. package/packages/scrabble-solver/src/styles/global.scss +1 -1
  136. package/packages/scrabble-solver/src/styles/mixins.scss +22 -0
  137. package/packages/scrabble-solver/src/styles/variables.scss +17 -2
  138. package/packages/scrabble-solver/src/types/index.ts +1 -0
  139. package/packages/solver/package-lock.json +2 -2
  140. package/packages/solver/package.json +5 -5
  141. package/packages/types/build/Bonus.d.ts +2 -1
  142. package/packages/types/package.json +2 -2
  143. package/packages/types/src/Bonus.ts +3 -1
  144. package/packages/word-definitions/build/lib/normalizeDefinition.js +1 -1
  145. package/packages/word-definitions/package-lock.json +8 -8
  146. package/packages/word-definitions/package.json +2 -2
  147. package/packages/word-definitions/src/lib/normalizeDefinition.ts +1 -1
  148. package/packages/word-definitions/src/parse/__tests__/expected/en-US.oe.json +7 -0
  149. package/packages/word-definitions/src/parse/__tests__/input/en-US.oe.html +1337 -0
  150. package/packages/word-definitions/src/parse/parse.test.ts +1 -0
  151. package/packages/word-lists/package-lock.json +8 -8
  152. package/packages/word-lists/package.json +2 -2
  153. package/packages/configs/package-lock.json +0 -58
  154. package/packages/constants/package-lock.json +0 -13
  155. package/packages/scrabble-solver/.next/server/font-loader-manifest.js +0 -1
  156. package/packages/scrabble-solver/.next/static/chunks/main-74c4d6b2b5c362f3.js +0 -1
  157. package/packages/scrabble-solver/.next/static/chunks/pages/404-6c1a6e3251710371.js +0 -1
  158. package/packages/scrabble-solver/.next/static/chunks/pages/_app-d98e480ff8c583de.js +0 -28
  159. package/packages/scrabble-solver/.next/static/chunks/pages/index-bd1c7d3872c37456.js +0 -1
  160. package/packages/scrabble-solver/.next/static/css/a9b55372a26cf77d.css +0 -1
  161. package/packages/scrabble-solver/.next/static/css/b8954b85e2fa5b63.css +0 -2
  162. package/packages/scrabble-solver/.next/static/msKI0ZURgJImoGBJvCBiF/_buildManifest.js +0 -1
  163. package/packages/scrabble-solver/src/components/Solver/components/EmptyState/index.ts +0 -1
  164. package/packages/scrabble-solver/src/components/Solver/components/SolveButton/SolveButton.module.scss +0 -4
  165. package/packages/scrabble-solver/src/components/Solver/components/SolveButton/index.ts +0 -1
  166. package/packages/scrabble-solver/src/components/Tooltip/constants.ts +0 -28
  167. package/packages/scrabble-solver/src/hooks/useUniqueId.ts +0 -9
  168. package/packages/scrabble-solver/src/lib/isCtrl.ts +0 -7
  169. package/packages/scrabble-solver/src/state/rootReducer.ts +0 -25
  170. package/packages/types/package-lock.json +0 -30
  171. /package/packages/scrabble-solver/.next/server/{font-loader-manifest.json → next-font-manifest.json} +0 -0
  172. /package/packages/scrabble-solver/.next/static/{msKI0ZURgJImoGBJvCBiF → esK8DG-6aS5V7QFRtR3YE}/_ssgManifest.js +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.10.11",
3
+ "version": "2.11.1",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -28,34 +28,30 @@
28
28
  "start": "env-cmd next start -p 3333"
29
29
  },
30
30
  "dependencies": {
31
- "@floating-ui/react": "^0.19.2",
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.10.11",
36
- "@scrabble-solver/constants": "^2.10.11",
37
- "@scrabble-solver/dictionaries": "^2.10.11",
38
- "@scrabble-solver/logger": "^2.10.11",
39
- "@scrabble-solver/solver": "^2.10.11",
40
- "@scrabble-solver/types": "^2.10.11",
41
- "@scrabble-solver/word-definitions": "^2.10.11",
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",
42
41
  "classnames": "^2.3.2",
43
42
  "include-media": "^2.0.0",
44
43
  "include-media-query-builder": "^1.1.0",
45
- "next": "^13.2.1",
44
+ "next": "^13.2.4",
46
45
  "normalize.css": "^8.0.1",
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,9 +68,8 @@
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
- "sass": "^1.58.3",
72
+ "sass": "^1.59.2",
78
73
  "workbox-webpack-plugin": "^6.5.4"
79
74
  },
80
75
  "gitHead": "1e2d1ad49a288d4a44196d8e3336740da132c637"
@@ -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}
@@ -112,6 +112,7 @@
112
112
  font-size: 60%;
113
113
  font-weight: bold;
114
114
  color: var(--color--white);
115
+ transition: var(--transition);
115
116
  content: ' ';
116
117
 
117
118
  [lang='fa-IR'] & {
@@ -124,6 +125,47 @@
124
125
  }
125
126
  }
126
127
 
128
+ .tile {
129
+ .sharpTopLeft & {
130
+ [dir='ltr'] & {
131
+ border-top-left-radius: 0;
132
+ }
133
+
134
+ [dir='rtl'] & {
135
+ border-top-right-radius: 0;
136
+ }
137
+ }
138
+
139
+ .sharpTopRight & {
140
+ [dir='ltr'] & {
141
+ border-top-right-radius: 0;
142
+ }
143
+
144
+ [dir='rtl'] & {
145
+ border-top-left-radius: 0;
146
+ }
147
+ }
148
+
149
+ .sharpBottomLeft & {
150
+ [dir='ltr'] & {
151
+ border-bottom-left-radius: 0;
152
+ }
153
+
154
+ [dir='rtl'] & {
155
+ border-bottom-right-radius: 0;
156
+ }
157
+ }
158
+
159
+ .sharpBottomRight & {
160
+ [dir='ltr'] & {
161
+ border-bottom-right-radius: 0;
162
+ }
163
+
164
+ [dir='rtl'] & {
165
+ border-bottom-left-radius: 0;
166
+ }
167
+ }
168
+ }
127
169
  .icon {
128
170
  $size: 40%;
129
171
 
@@ -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,10 +15,9 @@ 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
22
  import { Direction } from 'types';
23
23
 
@@ -85,7 +85,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
85
85
  const insertValue = useCallback(
86
86
  (position: Point, value: string) => {
87
87
  const characters = value ? extractCharacters(config, value).filter((character) => character !== BLANK) : [BLANK];
88
- const actions: AnyAction[] = [];
88
+ const actions: PayloadAction<unknown>[] = [];
89
89
  let board = new Board({ rows: rows.map((row) => row.map((cell) => cell.clone())) });
90
90
  let { x, y } = position;
91
91
 
@@ -225,7 +225,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
225
225
  onArrowDown: (event) => {
226
226
  event.preventDefault();
227
227
 
228
- if (isCtrl(event)) {
228
+ if (direction === 'horizontal') {
229
229
  onDirectionToggle();
230
230
  } else {
231
231
  changeActiveIndex(0, 1);
@@ -234,7 +234,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
234
234
  onArrowLeft: (event) => {
235
235
  event.preventDefault();
236
236
 
237
- if (isCtrl(event)) {
237
+ if (direction === 'vertical') {
238
238
  onDirectionToggle();
239
239
  } else {
240
240
  changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? -1 : 1, 0);
@@ -243,7 +243,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
243
243
  onArrowRight: (event) => {
244
244
  event.preventDefault();
245
245
 
246
- if (isCtrl(event)) {
246
+ if (direction === 'vertical') {
247
247
  onDirectionToggle();
248
248
  } else {
249
249
  changeActiveIndex(LOCALE_FEATURES[locale].direction === 'ltr' ? 1 : -1, 0);
@@ -252,7 +252,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
252
252
  onArrowUp: (event) => {
253
253
  event.preventDefault();
254
254
 
255
- if (isCtrl(event)) {
255
+ if (direction === 'horizontal') {
256
256
  onDirectionToggle();
257
257
  } else {
258
258
  changeActiveIndex(0, -1);
@@ -289,22 +289,6 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
289
289
 
290
290
  const { x, y } = position;
291
291
  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
292
  const cell = rows[y][x];
309
293
  const twoCharacterCandidate = cell.tile.character + character;
310
294
 
@@ -333,7 +317,7 @@ const useGrid = (rows: Cell[][]): [State, Actions] => {
333
317
  dispatch(boardSlice.actions.toggleCellIsBlank(position));
334
318
  },
335
319
  });
336
- }, [changeActiveIndex, config, dispatch, locale, onDirectionToggle, rows]);
320
+ }, [changeActiveIndex, config, direction, dispatch, locale, moveFocus, onDirectionToggle, rows]);
337
321
 
338
322
  const onPaste = useCallback<ClipboardEventHandler>(
339
323
  (event) => {
@@ -1,15 +1,30 @@
1
+ @import 'styles/mixins';
2
+
1
3
  .dictionary {
4
+ @include scrollbars;
5
+
2
6
  position: relative;
7
+ max-height: var(--dictionary--height);
3
8
  height: var(--dictionary--height);
4
9
  overflow-y: auto;
5
10
  word-break: break-word;
6
11
  transition: var(--transition);
12
+
13
+ &.isAllowed {
14
+ background-color: var(--color--green--light);
15
+ }
16
+
17
+ &.isNotAllowed {
18
+ background-color: var(--color--red--light);
19
+ }
7
20
  }
8
21
 
9
22
  .result {
10
23
  transition: var(--transition);
11
24
 
12
25
  &.isAllowed {
26
+ background-color: var(--color--green--light);
27
+
13
28
  & + & {
14
29
  .content {
15
30
  padding-top: 0;
@@ -18,6 +33,8 @@
18
33
  }
19
34
 
20
35
  &.isNotAllowed {
36
+ background-color: var(--color--red--light);
37
+
21
38
  & + & {
22
39
  .content {
23
40
  padding-top: 0;
@@ -37,14 +54,6 @@
37
54
  text-transform: uppercase;
38
55
  }
39
56
 
40
- .isAllowed {
41
- background-color: var(--color--green--light);
42
- }
43
-
44
- .isNotAllowed {
45
- background-color: var(--color--red--light);
46
- }
47
-
48
57
  .definitions {
49
58
  margin: 0;
50
59
 
@@ -16,18 +16,18 @@ const Dictionary: FunctionComponent<Props> = ({ className }) => {
16
16
  const translate = useTranslate();
17
17
  const { results, isLoading } = useTypedSelector(selectDictionary);
18
18
  const error = useTypedSelector(selectDictionaryError);
19
- const isFirstAllowed = results.length > 0 ? results[0].isAllowed : undefined;
19
+ const isLastAllowed = results.length > 0 ? results[results.length - 1].isAllowed : undefined;
20
20
 
21
21
  return (
22
22
  <div
23
23
  className={classNames(styles.dictionary, className, {
24
- [styles.isAllowed]: isFirstAllowed === true,
25
- [styles.isNotAllowed]: isFirstAllowed === false,
24
+ [styles.isAllowed]: isLastAllowed === true,
25
+ [styles.isNotAllowed]: isLastAllowed === false,
26
26
  })}
27
27
  >
28
- {typeof error !== 'undefined' && <EmptyState variant="error">{error.message}</EmptyState>}
28
+ {typeof error !== 'undefined' && !isLoading && <EmptyState variant="error">{error.message}</EmptyState>}
29
29
 
30
- {typeof error === 'undefined' && results.length === 0 && (
30
+ {typeof error === 'undefined' && !isLoading && results.length === 0 && (
31
31
  <EmptyState variant="info">{translate('dictionary.empty-state.uninitialized')}</EmptyState>
32
32
  )}
33
33
 
@@ -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
  }
@@ -29,7 +29,7 @@ const Loading: FunctionComponent<Props> = ({ className, wave = true }) => {
29
29
  const content = useMemo(() => prepareContent(message), [message]);
30
30
 
31
31
  return (
32
- <div className={classNames(styles.loading, className)}>
32
+ <div aria-label={translation} className={classNames(styles.loading, className)} role="status">
33
33
  <div className={styles.dim} />
34
34
  <div className={styles.logo}>
35
35
  <PlainTiles className={classNames(styles.tiles)} content={content} dropShadow wave={wave} />
@@ -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';
@@ -112,10 +112,11 @@
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
- margin-top: calc(-1 * var(--spacing--l));
119
120
  padding: var(--spacing--l);
120
121
  overflow: auto;
121
122
  }
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { FunctionComponent } from 'react';
3
3
 
4
- import { useIsTouchDevice, useMediaQuery } from 'hooks';
4
+ import { useAppLayout } from 'hooks';
5
5
  import { CardChecklist, Cog, Eraser, Github, Keyboard, List, Sack } from 'icons';
6
6
  import { GITHUB_PROJECT_URL } from 'parameters';
7
7
  import { selectHasInvalidWords, selectHasOverusedTiles, useTranslate, useTypedSelector } from 'state';
@@ -30,10 +30,9 @@ const NavButtons: FunctionComponent<Props> = ({
30
30
  const translate = useTranslate();
31
31
  const hasOverusedTiles = useTypedSelector(selectHasOverusedTiles);
32
32
  const hasInvalidWords = useTypedSelector(selectHasInvalidWords);
33
- const isTouchDevice = useIsTouchDevice();
34
- const isLessThanS = useMediaQuery('<s');
33
+ const { showKeyMap, showShortNav } = useAppLayout();
35
34
 
36
- if (isLessThanS) {
35
+ if (showShortNav) {
37
36
  return (
38
37
  <div className={styles.navButtons}>
39
38
  <div className={styles.group}>
@@ -114,7 +113,7 @@ const NavButtons: FunctionComponent<Props> = ({
114
113
  <div className={styles.separator} />
115
114
 
116
115
  <div className={styles.group}>
117
- {!isTouchDevice && (
116
+ {showKeyMap && (
118
117
  <IconButton
119
118
  aria-label={translate('keyMap')}
120
119
  className={styles.button}
@@ -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
  }
@@ -14,12 +14,12 @@ interface Props {
14
14
 
15
15
  const Tile: FunctionComponent<Props> = ({ character, className, color, fontFamily, points, size, transform, x, y }) => (
16
16
  <g className={className} transform={transform}>
17
- <rect fill={color} height={size} width={size} x={x} y={y} />
17
+ <rect fill={color} height={size} rx={size * 0.15} width={size} x={x} y={y} />
18
18
 
19
19
  <text
20
20
  dominantBaseline="central"
21
21
  fontFamily={fontFamily}
22
- fontSize={0.6 * size}
22
+ fontSize={size * 0.6}
23
23
  fontWeight="bold"
24
24
  textAnchor="middle"
25
25
  x={x + size / 2}
@@ -32,7 +32,7 @@ const Tile: FunctionComponent<Props> = ({ character, className, color, fontFamil
32
32
  <text
33
33
  dominantBaseline="text-after-edge"
34
34
  fontFamily={fontFamily}
35
- fontSize={0.25 * size}
35
+ fontSize={size * 0.25}
36
36
  fontWeight="bold"
37
37
  textAnchor="end"
38
38
  x={x + size * 0.9}