@scrabble-solver/scrabble-solver 2.10.6 → 2.10.8

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 -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 +4597 -568
  16. package/.next/server/chunks/290.js +3 -1
  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 +296 -13
  22. package/.next/server/pages/_app.js.nft.json +1 -1
  23. package/.next/server/pages/_document.js.nft.json +1 -1
  24. package/.next/server/pages/api/dictionary/[locale]/[word].js +18 -16
  25. package/.next/server/pages/api/solve.js +17 -0
  26. package/.next/server/pages/index.html +1 -9
  27. package/.next/server/pages/index.js +26 -12
  28. package/.next/server/pages/index.js.nft.json +1 -1
  29. package/.next/server/pages/index.json +1 -1
  30. package/.next/server/pages-manifest.json +2 -2
  31. package/.next/static/Cs23uxWG6AxS72F2yrjHu/_buildManifest.js +1 -0
  32. package/.next/static/chunks/pages/{404-ff35a4cf7f1ec85a.js → 404-8cab6d62fe4ead73.js} +1 -1
  33. package/.next/static/chunks/pages/_app-dcbbb823dc93a031.js +28 -0
  34. package/.next/static/chunks/pages/index-df1ff01aa82d2d4d.js +1 -0
  35. package/.next/static/css/bf2e969b88c4e3dd.css +2 -0
  36. package/.next/static/css/d1cc6b79b211b7b8.css +1 -0
  37. package/.next/trace +55 -55
  38. package/package.json +10 -9
  39. package/src/components/Badge/Badge.module.scss +1 -1
  40. package/src/components/Board/components/Cell/Cell.module.scss +32 -64
  41. package/src/components/Board/components/Cell/Cell.tsx +6 -0
  42. package/src/components/Board/components/Cell/CellPure.tsx +24 -22
  43. package/src/components/Button/Button.module.scss +2 -2
  44. package/src/components/Button/Button.tsx +1 -0
  45. package/src/components/Button/Link.tsx +1 -0
  46. package/src/components/Checkbox/Checkbox.tsx +1 -4
  47. package/src/components/Dictionary/Dictionary.tsx +28 -30
  48. package/src/components/DictionaryInput/DictionaryInput.tsx +3 -0
  49. package/src/components/{SquareButton/SquareButton.module.scss → IconButton/IconButton.module.scss} +1 -1
  50. package/src/components/{SquareButton/SquareButton.tsx → IconButton/IconButton.tsx} +7 -6
  51. package/src/components/{SquareButton → IconButton}/Link.tsx +3 -2
  52. package/src/components/IconButton/index.ts +1 -0
  53. package/src/components/Key/Key.module.scss +1 -1
  54. package/src/components/Logo/Logo.svg +44 -15
  55. package/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +1 -1
  56. package/src/components/Modal/Modal.module.scss +4 -2
  57. package/src/components/Modal/Modal.tsx +3 -2
  58. package/src/components/NavButtons/NavButtons.tsx +37 -9
  59. package/src/components/Rack/Rack.module.scss +4 -0
  60. package/src/components/Rack/RackTile.tsx +5 -0
  61. package/src/components/Radio/Radio.tsx +1 -4
  62. package/src/components/Results/HeaderButton.tsx +1 -0
  63. package/src/components/Results/Result.tsx +1 -0
  64. package/src/components/Results/Results.module.scss +2 -3
  65. package/src/components/Results/SolveButton.tsx +1 -0
  66. package/src/components/SeoMessage/SeoMessage.tsx +19 -0
  67. package/src/components/SeoMessage/index.ts +1 -0
  68. package/src/components/Solver/Solver.module.scss +4 -0
  69. package/src/components/Solver/Solver.tsx +26 -8
  70. package/src/components/Solver/components/EmptyState/EmptyState.module.scss +1 -3
  71. package/src/components/Solver/components/InsertButton/InsertButton.module.scss +15 -0
  72. package/src/components/Solver/components/{ApplyButton/ApplyButton.tsx → InsertButton/InsertButton.tsx} +10 -6
  73. package/src/components/Solver/components/InsertButton/index.ts +1 -0
  74. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +37 -7
  75. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +41 -17
  76. package/src/components/Solver/components/SolveButton/SolveButton.tsx +11 -1
  77. package/src/components/Solver/components/index.ts +1 -2
  78. package/src/components/Tile/Tile.module.scss +49 -11
  79. package/src/components/Tile/Tile.tsx +26 -8
  80. package/src/components/Tile/TilePure.tsx +29 -19
  81. package/src/components/Tooltip/Tooltip.module.scss +7 -7
  82. package/src/components/Tooltip/useTooltip.tsx +14 -2
  83. package/src/components/index.ts +2 -1
  84. package/src/i18n/de.json +6 -0
  85. package/src/i18n/en.json +6 -0
  86. package/src/i18n/es.json +6 -0
  87. package/src/i18n/fa.json +6 -0
  88. package/src/i18n/fr.json +6 -0
  89. package/src/i18n/pl.json +6 -0
  90. package/src/icons/ArrowDown.svg +1 -1
  91. package/src/icons/ArrowLeft.svg +1 -1
  92. package/src/icons/ArrowRight.svg +1 -1
  93. package/src/icons/ArrowUp.svg +1 -1
  94. package/src/icons/ChevronDown.svg +1 -1
  95. package/src/icons/ChevronLeft.svg +1 -1
  96. package/src/icons/ChevronRight.svg +1 -1
  97. package/src/icons/Flag.svg +2 -2
  98. package/src/icons/FlagFill.svg +4 -0
  99. package/src/icons/List.svg +1 -1
  100. package/src/icons/Square.svg +4 -0
  101. package/src/icons/SquareFill.svg +4 -0
  102. package/src/icons/index.ts +3 -0
  103. package/src/modals/MenuModal/MenuModal.tsx +9 -3
  104. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -1
  105. package/src/modals/RemainingTilesModal/components/Character/Character.tsx +1 -0
  106. package/src/modals/ResultsModal/ResultsModal.module.scss +1 -1
  107. package/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +0 -1
  108. package/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +0 -1
  109. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +14 -24
  110. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +0 -1
  111. package/src/pages/_app.tsx +9 -5
  112. package/src/pages/api/dictionary/[locale]/[word].ts +3 -1
  113. package/src/pages/index.module.scss +1 -2
  114. package/src/pages/index.tsx +6 -0
  115. package/src/parameters/index.ts +10 -0
  116. package/src/state/sagas.ts +5 -2
  117. package/src/state/slices/boardSlice.ts +5 -5
  118. package/src/state/useTranslate.ts +5 -2
  119. package/src/styles/mixins.scss +4 -2
  120. package/src/styles/variables.scss +39 -32
  121. package/src/types/index.ts +7 -1
  122. package/.next/server/chunks/579.js +0 -3917
  123. package/.next/static/chunks/490-d29992f1c264d70e.js +0 -5
  124. package/.next/static/chunks/791-93aa8b8c22e488ac.js +0 -1
  125. package/.next/static/chunks/pages/_app-fa0661b072fc6af9.js +0 -24
  126. package/.next/static/chunks/pages/index-ded620fd5df96be0.js +0 -1
  127. package/.next/static/css/4482c4a0064d3807.css +0 -1
  128. package/.next/static/css/78e42ad01f580f64.css +0 -1
  129. package/.next/static/css/a943dd97164732d4.css +0 -1
  130. package/.next/static/iL0av55MV28b0MXfhKKt2/_buildManifest.js +0 -1
  131. package/src/components/Board/components/Cell/Button.tsx +0 -31
  132. package/src/components/Solver/components/ApplyButton/ApplyButton.module.scss +0 -5
  133. package/src/components/Solver/components/ApplyButton/index.ts +0 -1
  134. package/src/components/Solver/components/MobileControls/MobileControls.tsx +0 -62
  135. package/src/components/Solver/components/MobileControls/index.ts +0 -1
  136. package/src/components/SquareButton/index.ts +0 -1
  137. /package/.next/static/{iL0av55MV28b0MXfhKKt2 → Cs23uxWG6AxS72F2yrjHu}/_ssgManifest.js +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrabble-solver/scrabble-solver",
3
- "version": "2.10.6",
3
+ "version": "2.10.8",
4
4
  "description": "Scrabble Solver 2 - App",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -31,16 +31,17 @@
31
31
  "@kamilmielnik/trie": "^2.0.1",
32
32
  "@popperjs/core": "^2.11.6",
33
33
  "@reduxjs/toolkit": "^1.9.3",
34
- "@scrabble-solver/configs": "^2.10.6",
35
- "@scrabble-solver/constants": "^2.10.6",
36
- "@scrabble-solver/dictionaries": "^2.10.6",
37
- "@scrabble-solver/logger": "^2.10.6",
38
- "@scrabble-solver/solver": "^2.10.6",
39
- "@scrabble-solver/types": "^2.10.6",
40
- "@scrabble-solver/word-definitions": "^2.10.6",
34
+ "@scrabble-solver/configs": "^2.10.8",
35
+ "@scrabble-solver/constants": "^2.10.8",
36
+ "@scrabble-solver/dictionaries": "^2.10.8",
37
+ "@scrabble-solver/logger": "^2.10.8",
38
+ "@scrabble-solver/solver": "^2.10.8",
39
+ "@scrabble-solver/types": "^2.10.8",
40
+ "@scrabble-solver/word-definitions": "^2.10.8",
41
41
  "classnames": "^2.3.2",
42
42
  "include-media": "^2.0.0",
43
43
  "include-media-query-builder": "^1.1.0",
44
+ "merge-refs": "^1.1.2",
44
45
  "next": "^13.1.6",
45
46
  "normalize.css": "^8.0.1",
46
47
  "react": "^18.2.0",
@@ -76,5 +77,5 @@
76
77
  "sass": "^1.58.3",
77
78
  "workbox-webpack-plugin": "^6.5.4"
78
79
  },
79
- "gitHead": "188bb77933a4e88af88b05063a4977c50c788071"
80
+ "gitHead": "faa8a69c239fd14a2b07fe18744580e8713e93ea"
80
81
  }
@@ -5,7 +5,7 @@
5
5
  padding: var(--spacing--xs) var(--spacing--m);
6
6
  border: var(--border);
7
7
  border-radius: var(--border--radius);
8
- background-color: var(--color--background--overlay);
8
+ background-color: var(--color--background--element);
9
9
  line-height: var(--line-height);
10
10
  font-size: var(--font--size--m);
11
11
  font-weight: bold;
@@ -1,13 +1,11 @@
1
1
  @import 'styles/mixins';
2
2
 
3
- $icon-size: 16px;
4
-
5
3
  .cell {
6
4
  @include focus-effect;
7
5
 
8
6
  position: relative;
9
7
  display: table-cell;
10
- background-color: white;
8
+ background-color: var(--color--white);
11
9
  border-bottom: var(--border--width) dotted var(--border--color--light);
12
10
  transition: var(--transition);
13
11
  background-clip: padding-box;
@@ -36,57 +34,57 @@ $icon-size: 16px;
36
34
 
37
35
  &.bonusStart {
38
36
  &::before {
39
- background-color: var(--color--violet--light);
37
+ background-color: var(--color--bonus--start);
40
38
  }
41
39
  }
42
40
 
43
41
  &.bonusCharacter1 {
44
42
  &::before {
45
- background-color: var(--color--yellow--light);
43
+ background-color: var(--color--bonus--character--1);
46
44
  }
47
45
  }
48
46
 
49
47
  &.bonusCharacter2 {
50
48
  &::before {
51
- background-color: var(--color--green--light);
49
+ background-color: var(--color--bonus--character--2);
52
50
  }
53
51
  }
54
52
 
55
53
  &.bonusCharacter3 {
56
54
  &::before {
57
- background-color: var(--color--blue--light);
55
+ background-color: var(--color--bonus--character--3);
58
56
  }
59
57
  }
60
58
 
61
59
  &.bonusCharacter5 {
62
60
  &::before {
63
- background-color: var(--color--red--light);
61
+ background-color: var(--color--bonus--character--5);
64
62
  }
65
63
  }
66
64
 
67
65
  &.bonusCharacterMultiplier2 {
68
66
  &::before {
69
- background-color: var(--color--light-blue--light);
67
+ background-color: var(--color--bonus--character-multiplier--2);
70
68
  }
71
69
  }
72
70
 
73
71
  &.bonusCharacterMultiplier3 {
74
72
  &::before {
75
- background-color: var(--color--dark-blue--light);
73
+ background-color: var(--color--bonus--character-multiplier--3);
76
74
  }
77
75
  }
78
76
 
79
77
  &.bonusWord2 {
80
78
  &::before {
81
79
  content: 'x2';
82
- background-color: var(--color--orange);
80
+ background-color: var(--color--bonus--word-multiplier--2);
83
81
  }
84
82
  }
85
83
 
86
84
  &.bonusWord3 {
87
85
  &::before {
88
86
  content: 'x3';
89
- background-color: var(--color--pink);
87
+ background-color: var(--color--bonus--word-multiplier--3);
90
88
  }
91
89
  }
92
90
 
@@ -112,7 +110,7 @@ $icon-size: 16px;
112
110
  pointer-events: none;
113
111
  font-size: 60%;
114
112
  font-weight: bold;
115
- color: white;
113
+ color: var(--color--white);
116
114
  content: ' ';
117
115
 
118
116
  [lang='fa-IR'] & {
@@ -121,7 +119,7 @@ $icon-size: 16px;
121
119
  }
122
120
 
123
121
  &:focus-within {
124
- z-index: 1;
122
+ z-index: 2;
125
123
 
126
124
  .actions {
127
125
  display: flex;
@@ -135,9 +133,15 @@ $icon-size: 16px;
135
133
  }
136
134
 
137
135
  .actions {
136
+ --offset: var(--spacing--m);
137
+
138
+ @include media('<xs') {
139
+ --offset: var(--spacing--s);
140
+ }
141
+
138
142
  display: none;
139
143
  position: absolute;
140
- top: -$icon-size;
144
+ bottom: calc(100% - var(--offset));
141
145
  z-index: 2;
142
146
  transition: var(--transition);
143
147
  pointer-events: none;
@@ -145,30 +149,17 @@ $icon-size: 16px;
145
149
  border-radius: var(--border--radius);
146
150
 
147
151
  [dir='ltr'] & {
148
- left: calc(100% + var(--spacing--s) - #{$icon-size});
152
+ left: calc(100% - var(--offset));
149
153
  }
150
154
 
151
155
  [dir='rtl'] & {
152
- right: calc(100% + var(--spacing--s) - #{$icon-size});
156
+ right: calc(100% - var(--offset));
153
157
  }
154
158
  }
155
159
 
156
160
  .action {
157
- @include button-reset;
158
-
159
- display: flex;
160
- justify-content: center;
161
- padding: var(--spacing--s);
162
- user-select: none;
163
- pointer-events: none;
164
- box-sizing: content-box;
165
- background-color: white;
166
- border: var(--border);
167
- font-size: var(--font--size--m);
168
- line-height: $icon-size;
169
- color: var(--color--foreground--secondary);
170
- transition: var(--transition);
171
- cursor: pointer;
161
+ padding: var(--spacing--m);
162
+ box-shadow: none !important;
172
163
 
173
164
  & + & {
174
165
  [dir='ltr'] & {
@@ -182,35 +173,28 @@ $icon-size: 16px;
182
173
 
183
174
  [dir='ltr'] & {
184
175
  &:first-child {
185
- border-top-left-radius: var(--border--radius);
186
- border-bottom-left-radius: var(--border--radius);
176
+ border-top-right-radius: 0;
177
+ border-bottom-right-radius: 0;
187
178
  }
188
179
 
189
180
  &:last-child {
190
- border-top-right-radius: var(--border--radius);
191
- border-bottom-right-radius: var(--border--radius);
181
+ border-top-left-radius: 0;
182
+ border-bottom-left-radius: 0;
192
183
  }
193
184
  }
194
185
 
195
186
  [dir='rtl'] & {
196
187
  &:first-child {
197
- border-top-right-radius: var(--border--radius);
198
- border-bottom-right-radius: var(--border--radius);
188
+ border-top-left-radius: 0;
189
+ border-bottom-left-radius: 0;
199
190
  }
200
191
 
201
192
  &:last-child {
202
- border-top-left-radius: var(--border--radius);
203
- border-bottom-left-radius: var(--border--radius);
193
+ border-top-right-radius: 0;
194
+ border-bottom-right-radius: 0;
204
195
  }
205
196
  }
206
197
 
207
- &,
208
- .filterCell,
209
- .toggleDirection {
210
- width: $icon-size;
211
- height: $icon-size;
212
- }
213
-
214
198
  &:active,
215
199
  &:hover {
216
200
  color: var(--color--foreground);
@@ -229,22 +213,6 @@ $icon-size: 16px;
229
213
  }
230
214
  }
231
215
 
232
- .blank {
233
- user-select: none;
234
-
235
- &.active {
236
- font-weight: bold;
237
- }
238
- }
239
-
240
- .filterCell {
241
- color: var(--color--inactive);
242
-
243
- &.filtered {
244
- color: var(--color--foreground--secondary);
245
- }
246
- }
247
-
248
216
  .iconContainer {
249
217
  position: absolute;
250
218
  top: 0;
@@ -262,7 +230,7 @@ $icon-size: 16px;
262
230
 
263
231
  .flag,
264
232
  .star {
265
- color: white;
233
+ color: var(--color--white);
266
234
  }
267
235
 
268
236
  .star {
@@ -10,6 +10,7 @@ import {
10
10
  selectCellBonus,
11
11
  selectCellIsFiltered,
12
12
  selectCellIsValid,
13
+ selectLocale,
13
14
  selectTilePoints,
14
15
  useTranslate,
15
16
  useTypedSelector,
@@ -47,6 +48,7 @@ const Cell: FunctionComponent<Props> = ({
47
48
  const { tile, x, y } = cell;
48
49
  const dispatch = useDispatch();
49
50
  const translate = useTranslate();
51
+ const locale = useTypedSelector(selectLocale);
50
52
  const bonus = useTypedSelector((state) => selectCellBonus(state, cell));
51
53
  const points = useTypedSelector((state) => selectTilePoints(state, cell.tile));
52
54
  const isFiltered = useTypedSelector((state) => selectCellIsFiltered(state, cell));
@@ -83,6 +85,10 @@ const Cell: FunctionComponent<Props> = ({
83
85
 
84
86
  return (
85
87
  <CellPure
88
+ aria-label={translate('cell.tile.location', {
89
+ x: (x + 1).toLocaleString(locale),
90
+ y: (y + 1).toLocaleString(locale),
91
+ })}
86
92
  bonus={bonus}
87
93
  cell={cell}
88
94
  className={className}
@@ -10,16 +10,17 @@ import {
10
10
  RefObject,
11
11
  } from 'react';
12
12
 
13
- import { ArrowDown, Flag, Star } from 'icons';
13
+ import { ArrowDown, Flag, FlagFill, Square, SquareFill, Star } from 'icons';
14
14
  import { Translate } from 'types';
15
15
 
16
+ import Button from '../../../Button';
16
17
  import Tile from '../../../Tile';
17
18
 
18
- import Button from './Button';
19
19
  import styles from './Cell.module.scss';
20
20
  import { getBonusClassname } from './lib';
21
21
 
22
22
  interface Props {
23
+ 'aria-label': string;
23
24
  bonus: Bonus | undefined;
24
25
  cell: Cell;
25
26
  className?: string;
@@ -44,6 +45,7 @@ interface Props {
44
45
  }
45
46
 
46
47
  const CellPure: FunctionComponent<Props> = ({
48
+ 'aria-label': ariaLabel,
47
49
  bonus,
48
50
  cell,
49
51
  className,
@@ -82,11 +84,12 @@ const CellPure: FunctionComponent<Props> = ({
82
84
 
83
85
  {isFiltered && (
84
86
  <div className={classNames(styles.iconContainer, styles.flagContainer)}>
85
- <Flag className={styles.flag} />
87
+ <FlagFill className={styles.flag} />
86
88
  </div>
87
89
  )}
88
90
 
89
91
  <Tile
92
+ aria-label={ariaLabel}
90
93
  className={styles.tile}
91
94
  character={isEmpty ? undefined : tile.character}
92
95
  highlighted={cell.isCandidate()}
@@ -103,36 +106,35 @@ const CellPure: FunctionComponent<Props> = ({
103
106
 
104
107
  {!cell.isCandidate() && (
105
108
  <div className={styles.actions}>
106
- <Button tooltip={translate('cell.toggle-direction')} onClick={onDirectionToggleClick}>
107
- <ArrowDown
108
- className={classNames(styles.toggleDirection, {
109
- [styles.right]: direction === 'horizontal',
110
- })}
111
- />
112
- </Button>
109
+ <Button
110
+ aria-label={translate('cell.toggle-direction')}
111
+ className={styles.action}
112
+ Icon={ArrowDown}
113
+ iconClassName={classNames(styles.toggleDirection, {
114
+ [styles.right]: direction === 'horizontal',
115
+ })}
116
+ tooltip={translate('cell.toggle-direction')}
117
+ onClick={onDirectionToggleClick}
118
+ />
113
119
 
114
120
  {isEmpty && (
115
121
  <Button
116
- className={classNames(styles.filterCell, {
117
- [styles.filtered]: isFiltered,
118
- })}
122
+ aria-label={translate('cell.filter-cell')}
123
+ className={classNames(styles.action)}
124
+ Icon={isFiltered ? Flag : FlagFill}
119
125
  tooltip={translate('cell.filter-cell')}
120
126
  onClick={onToggleFilterCellClick}
121
- >
122
- <Flag />
123
- </Button>
127
+ />
124
128
  )}
125
129
 
126
130
  {!isEmpty && (
127
131
  <Button
128
- className={classNames(styles.blank, {
129
- [styles.active]: tile.isBlank,
130
- })}
132
+ aria-label={tile.isBlank ? translate('cell.set-not-blank') : translate('cell.set-blank')}
133
+ className={styles.action}
134
+ Icon={tile.isBlank ? SquareFill : Square}
131
135
  tooltip={tile.isBlank ? translate('cell.set-not-blank') : translate('cell.set-blank')}
132
136
  onClick={onToggleBlankClick}
133
- >
134
- B
135
- </Button>
137
+ />
136
138
  )}
137
139
  </div>
138
140
  )}
@@ -21,11 +21,11 @@
21
21
 
22
22
  &.primary {
23
23
  background-color: var(--color--primary);
24
- color: white;
24
+ color: var(--color--primary--opposite);
25
25
  }
26
26
 
27
27
  &.default {
28
- background-color: var(--color--background--overlay);
28
+ background-color: var(--color--background--element);
29
29
  color: var(--color--foreground);
30
30
 
31
31
  .icon {
@@ -7,6 +7,7 @@ import styles from './Button.module.scss';
7
7
  import Link from './Link';
8
8
 
9
9
  interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
10
+ 'aria-label': string;
10
11
  Icon?: FunctionComponent<SVGAttributes<SVGElement>>;
11
12
  iconClassName?: string;
12
13
  tooltip?: ReactNode;
@@ -6,6 +6,7 @@ import { useTooltip } from '../Tooltip';
6
6
  import styles from './Button.module.scss';
7
7
 
8
8
  interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
9
+ 'aria-label': string;
9
10
  href: string;
10
11
  Icon: FunctionComponent<SVGAttributes<SVGElement>>;
11
12
  iconClassName?: string;
@@ -10,23 +10,20 @@ interface Props {
10
10
  children?: ReactNode;
11
11
  className?: string;
12
12
  disabled?: boolean;
13
- id: string;
14
13
  name: string;
15
14
  onChange: ChangeEventHandler<HTMLInputElement>;
16
15
  }
17
16
 
18
- const Checkbox: FunctionComponent<Props> = ({ checked, children, className, disabled, id, name, onChange }) => (
17
+ const Checkbox: FunctionComponent<Props> = ({ checked, children, className, disabled, name, onChange }) => (
19
18
  <label
20
19
  className={classNames(styles.checkbox, className, {
21
20
  [styles.checked]: checked,
22
21
  })}
23
- htmlFor={id}
24
22
  >
25
23
  <input
26
24
  checked={checked}
27
25
  className={styles.input}
28
26
  disabled={disabled}
29
- id={id}
30
27
  name={name}
31
28
  type="checkbox"
32
29
  onChange={onChange}
@@ -27,6 +27,10 @@ const Dictionary: FunctionComponent<Props> = ({ className }) => {
27
27
  >
28
28
  {typeof error !== 'undefined' && <EmptyState variant="error">{error.message}</EmptyState>}
29
29
 
30
+ {results.length === 0 && (
31
+ <EmptyState variant="info">{translate('dictionary.empty-state.uninitialized')}</EmptyState>
32
+ )}
33
+
30
34
  {results.map(({ definitions, exists, isAllowed, word }) => (
31
35
  <div
32
36
  className={classNames(styles.result, {
@@ -35,40 +39,34 @@ const Dictionary: FunctionComponent<Props> = ({ className }) => {
35
39
  })}
36
40
  key={word}
37
41
  >
38
- {typeof word === 'undefined' && (
39
- <EmptyState variant="info">{translate('dictionary.empty-state.uninitialized')}</EmptyState>
40
- )}
41
-
42
- {typeof word !== 'undefined' && (
43
- <div className={styles.content}>
44
- {word && <h2 className={styles.word}>{word}</h2>}
42
+ <div className={styles.content}>
43
+ {word && <h2 className={styles.word}>{word}</h2>}
45
44
 
46
- {isAllowed === false && <div>{translate('dictionary.empty-state.not-allowed')}</div>}
45
+ {isAllowed === false && <div>{translate('dictionary.empty-state.not-allowed')}</div>}
47
46
 
48
- {isAllowed === true && (
49
- <>
50
- {definitions.length === 0 && (
51
- <>
52
- {exists && <div>{translate('dictionary.empty-state.no-definitions')}</div>}
53
- {!exists && <div>{translate('dictionary.empty-state.no-results')}</div>}
54
- </>
55
- )}
47
+ {isAllowed === true && (
48
+ <>
49
+ {definitions.length === 0 && (
50
+ <>
51
+ {exists && <div>{translate('dictionary.empty-state.no-definitions')}</div>}
52
+ {!exists && <div>{translate('dictionary.empty-state.no-results')}</div>}
53
+ </>
54
+ )}
56
55
 
57
- {definitions.length > 0 && (
58
- <ul className={styles.definitions}>
59
- {definitions.map((result, index) => (
60
- <li key={index} className={styles.definition}>
61
- {result}
62
- </li>
63
- ))}
64
- </ul>
65
- )}
66
- </>
67
- )}
56
+ {definitions.length > 0 && (
57
+ <ul className={styles.definitions}>
58
+ {definitions.map((result, index) => (
59
+ <li key={index} className={styles.definition}>
60
+ {result}
61
+ </li>
62
+ ))}
63
+ </ul>
64
+ )}
65
+ </>
66
+ )}
68
67
 
69
- {!isLoading && isAllowed === null && <div>{translate('dictionary.empty-state.no-results')}</div>}
70
- </div>
71
- )}
68
+ {!isLoading && isAllowed === null && <div>{translate('dictionary.empty-state.no-results')}</div>}
69
+ </div>
72
70
  </div>
73
71
  ))}
74
72
 
@@ -1,3 +1,4 @@
1
+ import { COMMA_ARABIC, COMMA_LATIN } from '@scrabble-solver/constants';
1
2
  import classNames from 'classnames';
2
3
  import { ChangeEvent, FormEvent, FunctionComponent } from 'react';
3
4
  import { useDispatch } from 'react-redux';
@@ -28,8 +29,10 @@ const DictionaryInput: FunctionComponent<Props> = ({ className }) => {
28
29
  <form className={classNames(styles.dictionaryInput, className)} onSubmit={handleSubmit}>
29
30
  <input
30
31
  className={styles.input}
32
+ pattern={`.*[^\\s${COMMA_ARABIC}${COMMA_LATIN}].*`}
31
33
  placeholder={translate('dictionary.input.placeholder')}
32
34
  required
35
+ title={translate('dictionary.input.title')}
33
36
  type="text"
34
37
  value={input}
35
38
  onChange={handleChange}
@@ -1,6 +1,6 @@
1
1
  @import 'styles/mixins';
2
2
 
3
- .squareButton {
3
+ .iconButton {
4
4
  @include button-reset;
5
5
  @include focus-effect;
6
6
 
@@ -1,23 +1,24 @@
1
1
  import classNames from 'classnames';
2
- import { ButtonHTMLAttributes, FunctionComponent, MouseEventHandler, ReactNode, SVGAttributes } from 'react';
2
+ import { ButtonHTMLAttributes, FunctionComponent, MouseEventHandler, SVGAttributes } from 'react';
3
3
 
4
4
  import { useTooltip } from '../Tooltip';
5
5
 
6
+ import styles from './IconButton.module.scss';
6
7
  import Link from './Link';
7
- import styles from './SquareButton.module.scss';
8
8
 
9
9
  interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
10
+ 'aria-label': string;
10
11
  children?: never;
11
12
  Icon: FunctionComponent<SVGAttributes<SVGElement>>;
12
- tooltip: ReactNode;
13
+ tooltip: string;
13
14
  onClick: MouseEventHandler<HTMLButtonElement>;
14
15
  }
15
16
 
16
- const SquareButton: FunctionComponent<Props> = ({ className, Icon, tooltip, ...props }) => {
17
+ const IconButton: FunctionComponent<Props> = ({ className, Icon, tooltip, ...props }) => {
17
18
  const triggerProps = useTooltip(tooltip, props);
18
19
 
19
20
  return (
20
- <button className={classNames(styles.squareButton, className)} type="button" {...props} {...triggerProps}>
21
+ <button className={classNames(styles.iconButton, className)} type="button" {...props} {...triggerProps}>
21
22
  <span className={styles.content}>
22
23
  <Icon className={styles.icon} />
23
24
  </span>
@@ -25,6 +26,6 @@ const SquareButton: FunctionComponent<Props> = ({ className, Icon, tooltip, ...p
25
26
  );
26
27
  };
27
28
 
28
- export default Object.assign(SquareButton, {
29
+ export default Object.assign(IconButton, {
29
30
  Link,
30
31
  });
@@ -3,9 +3,10 @@ import { AnchorHTMLAttributes, FunctionComponent, SVGAttributes } from 'react';
3
3
 
4
4
  import { useTooltip } from '../Tooltip';
5
5
 
6
- import styles from './SquareButton.module.scss';
6
+ import styles from './IconButton.module.scss';
7
7
 
8
8
  interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
9
+ 'aria-label': string;
9
10
  children?: never;
10
11
  href: string;
11
12
  Icon: FunctionComponent<SVGAttributes<SVGElement>>;
@@ -16,7 +17,7 @@ const Link: FunctionComponent<Props> = ({ className, Icon, tooltip, ...props })
16
17
  const triggerProps = useTooltip(tooltip, props);
17
18
 
18
19
  return (
19
- <a className={classNames(styles.squareButton, className)} {...props} {...triggerProps}>
20
+ <a className={classNames(styles.iconButton, className)} {...props} {...triggerProps}>
20
21
  <span className={styles.content}>
21
22
  <Icon className={styles.icon} />
22
23
  </span>
@@ -0,0 +1 @@
1
+ export { default } from './IconButton';
@@ -8,7 +8,7 @@ $icon-size: 15px;
8
8
  min-width: $key-size;
9
9
  height: $key-size;
10
10
  padding: var(--spacing--s) var(--spacing--m);
11
- background-color: white;
11
+ background-color: var(--color--white);
12
12
  border: var(--border);
13
13
  border-radius: var(--border--radius);
14
14
  box-shadow: var(--box-shadow);