@scrabble-solver/scrabble-solver 2.13.7 → 2.13.9

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 (89) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +11 -11
  3. package/.next/cache/.tsbuildinfo +1 -1
  4. package/.next/cache/eslint/.cache_8dgz12 +1 -1
  5. package/.next/cache/webpack/client-production/0.pack +0 -0
  6. package/.next/cache/webpack/client-production/index.pack +0 -0
  7. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  8. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  9. package/.next/cache/webpack/server-production/0.pack +0 -0
  10. package/.next/cache/webpack/server-production/index.pack +0 -0
  11. package/.next/prerender-manifest.js +1 -1
  12. package/.next/prerender-manifest.json +1 -1
  13. package/.next/routes-manifest.json +1 -1
  14. package/.next/server/chunks/577.js +1 -1
  15. package/.next/server/chunks/807.js +1 -1
  16. package/.next/server/middleware-build-manifest.js +1 -1
  17. package/.next/server/pages/404.html +1 -1
  18. package/.next/server/pages/500.html +1 -1
  19. package/.next/server/pages/index.html +1 -1
  20. package/.next/server/pages/index.js +1 -1
  21. package/.next/server/pages/index.json +1 -1
  22. package/.next/static/chunks/{main-6e708370ad13b1f9.js → main-b5b360c6afb66b05.js} +1 -1
  23. package/.next/static/chunks/pages/{404-9d5621b1ca024a45.js → 404-01653a877b233143.js} +1 -1
  24. package/.next/static/chunks/pages/_app-735b5863675c1b5d.js +17 -0
  25. package/.next/static/chunks/pages/{index-710b5c27542027be.js → index-36c448d585a58425.js} +1 -1
  26. package/.next/static/css/6682db14f926d4c7.css +1 -0
  27. package/.next/static/css/841a5b5f0b2fb131.css +2 -0
  28. package/.next/static/eLvYNd4B2hzSgBZ_PuZcQ/_buildManifest.js +1 -0
  29. package/.next/trace +44 -44
  30. package/LICENSE +1 -1
  31. package/package.json +12 -12
  32. package/src/components/Alert/Alert.module.scss +3 -12
  33. package/src/components/Board/Board.module.scss +1 -4
  34. package/src/components/Board/Board.tsx +3 -3
  35. package/src/components/Board/BoardPure.tsx +27 -19
  36. package/src/components/Board/components/Actions/Actions.module.scss +7 -27
  37. package/src/components/Board/components/Actions/Actions.tsx +8 -12
  38. package/src/components/Board/components/Actions/lib.ts +30 -0
  39. package/src/components/Board/components/Cell/Cell.module.scss +5 -32
  40. package/src/components/Board/components/InputPrompt/InputPrompt.module.scss +4 -18
  41. package/src/components/Board/hooks/useBackgroundImage.tsx +18 -28
  42. package/src/components/Button/Button.module.scss +1 -8
  43. package/src/components/Dictionary/Dictionary.module.scss +1 -8
  44. package/src/components/Loading/Loading.module.scss +1 -4
  45. package/src/components/Modal/Modal.module.scss +2 -16
  46. package/src/components/Rack/Rack.module.scss +4 -18
  47. package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +1 -4
  48. package/src/components/Radio/Radio.module.scss +2 -1
  49. package/src/components/Results/Results.module.scss +7 -39
  50. package/src/components/Results/useColumns.ts +1 -1
  51. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +9 -40
  52. package/src/components/Tile/Tile.module.scss +6 -28
  53. package/src/components/Tile/Tile.tsx +1 -15
  54. package/src/components/Tooltip/Tooltip.module.scss +1 -0
  55. package/src/components/index.ts +0 -1
  56. package/src/hooks/useAppLayout.ts +0 -1
  57. package/src/i18n/languages/english.json +2 -1
  58. package/src/i18n/languages/french.json +2 -1
  59. package/src/i18n/languages/german.json +3 -2
  60. package/src/i18n/languages/persian.json +2 -1
  61. package/src/i18n/languages/polish.json +2 -1
  62. package/src/i18n/languages/romanian.json +2 -1
  63. package/src/i18n/languages/spanish.json +2 -1
  64. package/src/icons/Ban.svg +4 -0
  65. package/src/icons/index.ts +1 -2
  66. package/src/lib/groupResults.ts +4 -7
  67. package/src/lib/index.ts +1 -0
  68. package/src/lib/resultMatchesCellFilter.ts +23 -0
  69. package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +2 -2
  70. package/src/modals/MenuModal/MenuModal.module.scss +2 -15
  71. package/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +1 -7
  72. package/src/modals/WordsModal/WordsModal.module.scss +2 -15
  73. package/src/parameters/index.ts +0 -9
  74. package/src/state/sagas.ts +4 -4
  75. package/src/state/selectors.ts +5 -8
  76. package/src/state/slices/cellFilterInitialState.ts +2 -2
  77. package/src/state/slices/cellFilterSlice.ts +29 -4
  78. package/src/styles/mixins.scss +2 -5
  79. package/src/types/index.ts +10 -1
  80. package/.next/static/QbBIK_mEs1LhYSpQwv6rZ/_buildManifest.js +0 -1
  81. package/.next/static/chunks/pages/_app-7bc3bf713c40526a.js +0 -17
  82. package/.next/static/css/11366b7489cf90ac.css +0 -1
  83. package/.next/static/css/fe70298e6f597553.css +0 -2
  84. package/src/components/Checkbox/Checkbox.module.scss +0 -45
  85. package/src/components/Checkbox/Checkbox.tsx +0 -38
  86. package/src/components/Checkbox/index.ts +0 -1
  87. package/src/icons/CheckboxChecked.svg +0 -4
  88. package/src/icons/CheckboxEmpty.svg +0 -4
  89. /package/.next/static/{QbBIK_mEs1LhYSpQwv6rZ → eLvYNd4B2hzSgBZ_PuZcQ}/_ssgManifest.js +0 -0
@@ -24,10 +24,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
24
24
 
25
25
  .listContainer {
26
26
  position: absolute;
27
- top: 0;
28
- left: 0;
29
- right: 0;
30
- bottom: 0;
27
+ inset: 0;
31
28
  }
32
29
 
33
30
  .list {
@@ -61,23 +58,11 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
61
58
  background-color: var(--color--background);
62
59
 
63
60
  &:first-child {
64
- [dir='ltr'] & {
65
- border-top-left-radius: inherit;
66
- }
67
-
68
- [dir='rtl'] & {
69
- border-top-right-radius: inherit;
70
- }
61
+ border-start-start-radius: inherit;
71
62
  }
72
63
 
73
64
  &:last-child {
74
- [dir='ltr'] & {
75
- border-top-right-radius: inherit;
76
- }
77
-
78
- [dir='rtl'] & {
79
- border-top-left-radius: inherit;
80
- }
65
+ border-start-end-radius: inherit;
81
66
  }
82
67
  }
83
68
 
@@ -97,11 +82,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
97
82
  @include ellipsis;
98
83
 
99
84
  flex: 0 1 auto;
100
- text-align: left;
101
-
102
- [dir='rtl'] & {
103
- text-align: right;
104
- }
85
+ text-align: start;
105
86
  }
106
87
 
107
88
  .result {
@@ -163,26 +144,13 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
163
144
 
164
145
  .result &:first-child,
165
146
  .headerButton:first-child & {
166
- [dir='ltr'] & {
167
- padding-left: $row-padding-horizontal;
168
- text-align: left;
169
- }
170
-
171
- [dir='rtl'] & {
172
- padding-right: $row-padding-horizontal;
173
- text-align: right;
174
- }
147
+ text-align: start;
148
+ padding-inline-start: $row-padding-horizontal;
175
149
  }
176
150
 
177
151
  .result &:last-child,
178
152
  .headerButton:last-child & {
179
- [dir='ltr'] & {
180
- padding-right: $row-padding-horizontal;
181
- }
182
-
183
- [dir='rtl'] & {
184
- padding-left: $row-padding-horizontal;
185
- }
153
+ padding-inline-end: $row-padding-horizontal;
186
154
  }
187
155
 
188
156
  &:last-child {
@@ -7,7 +7,7 @@ import getCoordinatesColumn from './getCoordinatesColumn';
7
7
  import getLocaleColumns from './getLocaleColumns';
8
8
  import { Column } from './types';
9
9
 
10
- const COLUMNS_XS = [ResultColumn.Word, ResultColumn.Points];
10
+ const COLUMNS_XS = [ResultColumn.Coordinates, ResultColumn.Word, ResultColumn.Points];
11
11
 
12
12
  const COLUMNS_S = [...COLUMNS_XS, ResultColumn.BlanksCount, ResultColumn.WordsCount];
13
13
 
@@ -82,23 +82,11 @@
82
82
  .points {
83
83
  flex: 0 0 auto;
84
84
  font-weight: bold;
85
+ border-inline-end: var(--border);
85
86
 
86
- [dir='ltr'] & {
87
- border-right: var(--border);
88
-
89
- @include media('<xs') {
90
- border-right: none;
91
- padding-right: var(--spacing--xs);
92
- }
93
- }
94
-
95
- [dir='rtl'] & {
96
- border-left: var(--border);
97
-
98
- @include media('<xs') {
99
- border-left: none;
100
- padding-left: var(--spacing--xs);
101
- }
87
+ @include media('<xs') {
88
+ border-inline-end: none;
89
+ padding-inline-end: var(--spacing--xs);
102
90
  }
103
91
  }
104
92
 
@@ -110,40 +98,21 @@
110
98
  text-align: center;
111
99
  white-space: pre-wrap;
112
100
 
113
- [dir='ltr'] & {
114
- @include media('<xs') {
115
- padding: var(--spacing--m);
116
- text-align: left;
117
- }
118
- }
119
-
120
- [dir='rtl'] & {
121
- @include media('<xs') {
122
- padding: var(--spacing--m);
123
- text-align: right;
124
- }
101
+ @include media('<xs') {
102
+ padding: var(--spacing--m);
103
+ text-align: start;
125
104
  }
126
105
  }
127
106
 
128
107
  .iconContainer {
129
108
  flex: 0 0 auto;
130
109
  display: flex;
131
-
132
- [dir='ltr'] & {
133
- padding-right: var(--spacing--l);
134
- }
135
-
136
- [dir='rtl'] & {
137
- padding-left: var(--spacing--l);
138
- }
110
+ padding-inline-end: var(--spacing--l);
139
111
  }
140
112
 
141
113
  .spinnerContainer {
142
114
  position: absolute;
143
- top: 0;
144
- right: 0;
145
- bottom: 0;
146
- left: 0;
115
+ inset: 0;
147
116
  display: flex;
148
117
  align-items: center;
149
118
  justify-content: center;
@@ -13,8 +13,6 @@
13
13
  font-weight: bold;
14
14
  text-transform: uppercase;
15
15
  text-align: center;
16
- transition: var(--transition);
17
- transition-property: background-color, color, box-shadow;
18
16
  user-select: none;
19
17
 
20
18
  @include media('<xs') {
@@ -76,10 +74,7 @@
76
74
 
77
75
  .input {
78
76
  position: absolute;
79
- top: 0;
80
- right: 0;
81
- bottom: 0;
82
- left: 0;
77
+ inset: 0;
83
78
  width: 100%;
84
79
  height: 100%;
85
80
  border: none;
@@ -98,6 +93,8 @@
98
93
  @include text-stroke(var(--background-color), 1px);
99
94
 
100
95
  position: absolute;
96
+ inset-block-end: 1%;
97
+ inset-inline-end: 9%;
101
98
  font-weight: bold;
102
99
  user-select: none;
103
100
  pointer-events: none;
@@ -106,16 +103,6 @@
106
103
  @include media('<xs') {
107
104
  display: none;
108
105
  }
109
-
110
- [dir='ltr'] & {
111
- bottom: 1%;
112
- right: 9%;
113
- }
114
-
115
- [dir='rtl'] & {
116
- top: 1%;
117
- left: 9%;
118
- }
119
106
  }
120
107
 
121
108
  .alert {
@@ -124,6 +111,9 @@
124
111
  position: absolute;
125
112
  width: var(--size);
126
113
  height: var(--size);
114
+ inset-block-start: 0;
115
+ inset-inline-end: 0;
116
+ border-start-end-radius: inherit;
127
117
  background: radial-gradient(
128
118
  var(--color--error--opposite),
129
119
  var(--color--error--opposite) 85%,
@@ -132,16 +122,4 @@
132
122
  );
133
123
  color: var(--color--error);
134
124
  pointer-events: none;
135
-
136
- [dir='ltr'] & {
137
- top: 0;
138
- right: 0;
139
- border-top-right-radius: inherit;
140
- }
141
-
142
- [dir='rtl'] & {
143
- top: 0;
144
- left: 0;
145
- border-top-left-radius: inherit;
146
- }
147
125
  }
@@ -9,14 +9,12 @@ import {
9
9
  Ref,
10
10
  TouchEventHandler,
11
11
  useCallback,
12
- useEffect,
13
12
  useMemo,
14
13
  useRef,
15
14
  } from 'react';
16
15
 
17
16
  import { useAppLayout } from 'hooks';
18
17
  import { getTileSizes, noop } from 'lib';
19
- import { EASE_OUT_CUBIC, TILE_APPEAR_DURATION, TILE_APPEAR_KEYFRAMES } from 'parameters';
20
18
  import { selectLocale, useTypedSelector } from 'state';
21
19
 
22
20
  import TilePure from './TilePure';
@@ -65,7 +63,7 @@ const Tile: FunctionComponent<Props> = ({
65
63
  onTouchStart = noop,
66
64
  }) => {
67
65
  const locale = useTypedSelector(selectLocale);
68
- const { animateTile, showTilePoints } = useAppLayout();
66
+ const { showTilePoints } = useAppLayout();
69
67
  const { pointsFontSize, tileSize } = getTileSizes(size);
70
68
  const style = useMemo(() => ({ height: tileSize, width: tileSize }), [tileSize]);
71
69
  const pointsStyle = useMemo(() => ({ fontSize: pointsFontSize }), [pointsFontSize]);
@@ -83,18 +81,6 @@ const Tile: FunctionComponent<Props> = ({
83
81
  [onKeyDown],
84
82
  );
85
83
 
86
- useEffect(() => {
87
- if (!ref.current?.parentElement || !character || !animateTile) {
88
- return;
89
- }
90
-
91
- ref.current.parentElement.animate(TILE_APPEAR_KEYFRAMES, {
92
- duration: TILE_APPEAR_DURATION,
93
- easing: EASE_OUT_CUBIC,
94
- fill: 'forwards',
95
- });
96
- }, [character, animateTile]);
97
-
98
84
  return (
99
85
  <TilePure
100
86
  aria-label={ariaLabel}
@@ -7,6 +7,7 @@
7
7
  color: var(--color--tooltip--foreground);
8
8
  z-index: var(--z-index--tooltip);
9
9
  text-align: center;
10
+ pointer-events: none;
10
11
  }
11
12
 
12
13
  .arrow {
@@ -2,7 +2,6 @@ export { default as Alert } from './Alert';
2
2
  export { default as Badge } from './Badge';
3
3
  export { default as Board } from './Board';
4
4
  export { default as Button } from './Button';
5
- export { default as Checkbox } from './Checkbox';
6
5
  export { default as Dictionary } from './Dictionary';
7
6
  export { default as DictionaryInput } from './DictionaryInput';
8
7
  export { default as EmptyState } from './EmptyState';
@@ -71,7 +71,6 @@ const useAppLayout = () => {
71
71
 
72
72
  return {
73
73
  actionsWidth: 2 * BUTTON_HEIGHT - BORDER_WIDTH,
74
- animateTile: !isLessThanXs,
75
74
  boardSize,
76
75
  cellSize,
77
76
  coordinatesFontSize: coordinatesSize * 0.6,
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "Enter word",
3
- "cell.filter-cell": "Target destination",
3
+ "cell.filter-cell.exclude": "Exclude destination",
4
+ "cell.filter-cell.include": "Target destination",
4
5
  "cell.set-blank": "Mark it a blank",
5
6
  "cell.set-not-blank": "Mark it not a blank",
6
7
  "cell.tile.location": "Board: tile ({{x}}, {{y}})",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "Entrez un mot",
3
- "cell.filter-cell": "Destination cible",
3
+ "cell.filter-cell.exclude": "Exclure la destination",
4
+ "cell.filter-cell.include": "Destination cible",
4
5
  "cell.set-blank": "Marquer comme vide",
5
6
  "cell.set-not-blank": "Marquer comme non vide",
6
7
  "cell.tile.location": "Plateau: la case ({{x}}, {{y}})",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "Wort eingeben",
3
- "cell.filter-cell": "Zielort",
3
+ "cell.filter-cell.exclude": "Ziel ausschließen",
4
+ "cell.filter-cell.include": "Ziel anvisieren",
4
5
  "cell.set-blank": "Als Blanko markieren",
5
6
  "cell.set-not-blank": "Nicht als Blanko markieren",
6
7
  "cell.tile.location": "Brett: Stein ({{x}}, {{y}})",
@@ -22,7 +23,7 @@
22
23
  "dictionary.empty-state.no-definitions": "Wort existiert im Wörterbuch aber hat keine Definition.",
23
24
  "dictionary.empty-state.no-results": "Wort kann nicht im Wörterbuch gefunden werden.",
24
25
  "dictionary.empty-state.not-allowed": "Dieses Wort ist nicht erlaubt.",
25
- "dictionary.empty-state.uninitialized": "Die Wörterbuchdéfinition wird hier angezeigt.",
26
+ "dictionary.empty-state.uninitialized": "Die Wörterbuchdefinition wird hier angezeigt.",
26
27
  "dictionary.input.placeholder": "Durchsuche Wörterbuch…",
27
28
  "dictionary.input.title": "Durch Kommas getrennte Wörter",
28
29
  "empty-state.error": "Fehler",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "کلمه را وارد کنید",
3
- "cell.filter-cell": "مقصد",
3
+ "cell.filter-cell.exclude": "مقصد را حذف کنید",
4
+ "cell.filter-cell.include": "مقصد مورد نظر",
4
5
  "cell.set-blank": "علامت گذاری به عنوان خالی",
5
6
  "cell.set-not-blank": "علامت گذاری به عنوان غیر خالی",
6
7
  "cell.tile.location": "({{x}}، {{y}}) کاشی: صفحه",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "Wprowadź słowo",
3
- "cell.filter-cell": "Miejsce docelowe",
3
+ "cell.filter-cell.exclude": "Wyklucz miejsce",
4
+ "cell.filter-cell.include": "Miejsce docelowe",
4
5
  "cell.set-blank": "Oznacz jako blank",
5
6
  "cell.set-not-blank": "Oznacz jako nie blank",
6
7
  "cell.tile.location": "Plansza: płytka ({{x}}, {{y}})",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "Introducere cuvant",
3
- "cell.filter-cell": "Destinatia",
3
+ "cell.filter-cell.exclude": "Excludeți destinația",
4
+ "cell.filter-cell.include": "Destinație țintă",
4
5
  "cell.set-blank": "Marcare camp liber",
5
6
  "cell.set-not-blank": "Marcare camp ocupat ",
6
7
  "cell.tile.location": "Tabla: camp ({{x}}, {{y}})",
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "cell.enter-word": "Ingresar palabra",
3
- "cell.filter-cell": "Destino objetivo",
3
+ "cell.filter-cell.exclude": "Excluir destino",
4
+ "cell.filter-cell.include": "Destino objetivo",
4
5
  "cell.set-blank": "Marcar como en blanco",
5
6
  "cell.set-not-blank": "Marcar como no en blanco",
6
7
  "cell.tile.location": "Tablero: espacio ({{x}}, {{y}})",
@@ -0,0 +1,4 @@
1
+ <!-- https://icons.getbootstrap.com/icons/ban/ -->
2
+ <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M15 8a6.97 6.97 0 0 0-1.71-4.584l-9.874 9.875A7 7 0 0 0 15 8M2.71 12.584l9.874-9.875a7 7 0 0 0-9.874 9.874ZM16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0" fill="currentColor" />
4
+ </svg>
@@ -2,11 +2,10 @@ export { default as ArrowDown } from './ArrowDown.svg';
2
2
  export { default as ArrowLeft } from './ArrowLeft.svg';
3
3
  export { default as ArrowRight } from './ArrowRight.svg';
4
4
  export { default as ArrowUp } from './ArrowUp.svg';
5
+ export { default as Ban } from './Ban.svg';
5
6
  export { default as BookHalf } from './BookHalf.svg';
6
7
  export { default as CardChecklist } from './CardChecklist.svg';
7
8
  export { default as Check } from './Check.svg';
8
- export { default as CheckboxChecked } from './CheckboxChecked.svg';
9
- export { default as CheckboxEmpty } from './CheckboxEmpty.svg';
10
9
  export { default as ChevronDown } from './ChevronDown.svg';
11
10
  export { default as ChevronLeft } from './ChevronLeft.svg';
12
11
  export { default as ChevronRight } from './ChevronRight.svg';
@@ -1,8 +1,9 @@
1
1
  import { Result } from '@scrabble-solver/types';
2
2
 
3
- import { Point } from 'types';
3
+ import { CellFilterEntry } from 'types';
4
4
 
5
5
  import createRegExp from './createRegExp';
6
+ import resultMatchesCellFilter from './resultMatchesCellFilter';
6
7
 
7
8
  interface GroupedResults {
8
9
  matching: Result[];
@@ -12,7 +13,7 @@ interface GroupedResults {
12
13
  const groupResults = (
13
14
  results: Result[] | undefined,
14
15
  query: string,
15
- cellFilter: Point[],
16
+ cellFilter: CellFilterEntry[],
16
17
  ): GroupedResults | undefined => {
17
18
  if (typeof results === 'undefined') {
18
19
  return results;
@@ -23,12 +24,8 @@ const groupResults = (
23
24
  return results.reduce<GroupedResults>(
24
25
  (groupedResults, result) => {
25
26
  const matchesQuery = () => regExp.test(result.word);
26
- const matchesCellFilter = () =>
27
- cellFilter.every(({ x, y }) => {
28
- return result.cells.some((cell) => cell.x === x && cell.y === y);
29
- });
30
27
 
31
- if (matchesCellFilter() && matchesQuery()) {
28
+ if (resultMatchesCellFilter(result, cellFilter) && matchesQuery()) {
32
29
  groupedResults.matching.push(result);
33
30
  } else {
34
31
  groupedResults.other.push(result);
package/src/lib/index.ts CHANGED
@@ -32,6 +32,7 @@ export { default as isUpperCase } from './isUpperCase';
32
32
  export { default as memoize } from './memoize';
33
33
  export { default as noop } from './noop';
34
34
  export { default as numberComparator } from './numberComparator';
35
+ export { default as resultMatchesCellFilter } from './resultMatchesCellFilter';
35
36
  export { default as reverseComparator } from './reverseComparator';
36
37
  export { default as sortResults } from './sortResults';
37
38
  export { default as unorderedArraysEqual } from './unorderedArraysEqual';
@@ -0,0 +1,23 @@
1
+ import { Result } from '@scrabble-solver/types';
2
+
3
+ import { CellFilterEntry } from 'types';
4
+
5
+ const resultMatchesCellFilter = (result: Result, cellFilter: CellFilterEntry[]) => {
6
+ const excludeFilters = cellFilter.filter((filter) => filter.type === 'exclude');
7
+ const matchesExcludeFilters = excludeFilters.every(({ x, y }) => {
8
+ return result.cells.every((cell) => cell.x !== x || cell.y !== y);
9
+ });
10
+
11
+ if (!matchesExcludeFilters) {
12
+ return false;
13
+ }
14
+
15
+ const includeFilter = cellFilter.filter((filter) => filter.type === 'include');
16
+ const matchesIncludeFilters = includeFilter.every(({ x, y }) => {
17
+ return result.cells.some((cell) => cell.x === x && cell.y === y);
18
+ });
19
+
20
+ return matchesExcludeFilters && matchesIncludeFilters;
21
+ };
22
+
23
+ export default resultMatchesCellFilter;
@@ -39,10 +39,10 @@
39
39
  }
40
40
 
41
41
  &:first-child {
42
- margin-left: 0;
42
+ margin-inline-start: 0;
43
43
  }
44
44
 
45
45
  &:last-child {
46
- margin-right: 0;
46
+ margin-inline-end: 0;
47
47
  }
48
48
  }
@@ -31,13 +31,7 @@
31
31
  --aspect-ratio: var(--highest-flag-aspect-ratio);
32
32
  --padding: calc(var(--spacing--l) + var(--button--icon--size) * var(--aspect-ratio));
33
33
 
34
- [dir='ltr'] & {
35
- padding-right: var(--padding);
36
- }
37
-
38
- [dir='rtl'] & {
39
- padding-left: var(--padding);
40
- }
34
+ padding-inline-end: var(--padding);
41
35
  }
42
36
 
43
37
  .flag {
@@ -45,12 +39,5 @@
45
39
  height: var(--button--icon--size);
46
40
  border-radius: var(--border--radius);
47
41
  box-shadow: 0 0 0 1px var(--box-shadow--color);
48
-
49
- [dir='ltr'] & {
50
- right: calc(2 * var(--spacing--l));
51
- }
52
-
53
- [dir='rtl'] & {
54
- left: calc(2 * var(--spacing--l));
55
- }
42
+ inset-inline-end: calc(2 * var(--spacing--l));
56
43
  }
@@ -12,13 +12,7 @@
12
12
  }
13
13
 
14
14
  .badge {
15
- [dir='ltr'] & {
16
- margin-left: var(--spacing--m);
17
- }
18
-
19
- [dir='rtl'] & {
20
- margin-right: var(--spacing--m);
21
- }
15
+ margin-inline-start: var(--spacing--m);
22
16
  }
23
17
 
24
18
  .character {
@@ -6,13 +6,7 @@
6
6
  }
7
7
 
8
8
  .badge {
9
- [dir='ltr'] & {
10
- margin-left: var(--spacing--m);
11
- }
12
-
13
- [dir='rtl'] & {
14
- margin-right: var(--spacing--m);
15
- }
9
+ margin-inline-start: var(--spacing--m);
16
10
  }
17
11
 
18
12
  .word {
@@ -37,12 +31,5 @@
37
31
 
38
32
  width: $size;
39
33
  height: $size;
40
-
41
- [dir='ltr'] & {
42
- margin-right: var(--spacing--s);
43
- }
44
-
45
- [dir='rtl'] & {
46
- margin-left: var(--spacing--s);
47
- }
34
+ margin-inline-end: var(--spacing--s);
48
35
  }
@@ -6,7 +6,6 @@ export const BREAKPOINTS = {
6
6
  xl: 1400,
7
7
  };
8
8
 
9
- export const EASE_OUT_CUBIC = 'cubic-bezier(0.33, 1, 0.68, 1)'; // https://easings.net/#easeOutCubic
10
9
  export const TRANSITION = 'var(--transition)';
11
10
 
12
11
  export const GITHUB_PROJECT_URL = 'https://github.com/kamilmielnik/scrabble-solver';
@@ -128,11 +127,3 @@ export const RESULTS_HEADER_HEIGHT = RESULTS_ITEM_HEIGHT;
128
127
  export const SOLVER_COLUMN_WIDTH = 580;
129
128
 
130
129
  export const TEXT_INPUT_HEIGHT = 40;
131
-
132
- export const TILE_APPEAR_DURATION = 200;
133
-
134
- export const TILE_APPEAR_KEYFRAMES = [
135
- { transform: 'translateY(0)' },
136
- { transform: 'translateY(10%)', offset: 0.5 },
137
- { transform: 'translateY(0)' },
138
- ];
@@ -12,7 +12,7 @@ import { findWordDefinitions, solve, verify, visit } from 'sdk';
12
12
  import { initialize, reset } from './actions';
13
13
  import {
14
14
  selectBoard,
15
- selectCellIsFiltered,
15
+ selectCellFilter,
16
16
  selectCharacters,
17
17
  selectConfig,
18
18
  selectDictionary,
@@ -56,10 +56,10 @@ export function* rootSaga(): AnyGenerator {
56
56
  }
57
57
 
58
58
  function* onCellValueChange({ payload }: PayloadAction<{ value: string; x: number; y: number }>): AnyGenerator {
59
- const isFiltered = yield select((state) => selectCellIsFiltered(state, payload));
59
+ const filter = yield select((state) => selectCellFilter(state, payload));
60
60
 
61
- if (isFiltered) {
62
- yield put(cellFilterSlice.actions.toggle(payload));
61
+ if (filter) {
62
+ yield put(cellFilterSlice.actions.cancel(payload));
63
63
  }
64
64
 
65
65
  yield put(resultsSlice.actions.changeResultCandidate(null));
@@ -12,6 +12,7 @@ import {
12
12
  getRemainingTiles,
13
13
  getRemainingTilesGroups,
14
14
  groupResults,
15
+ resultMatchesCellFilter,
15
16
  sortResults,
16
17
  unorderedArraysEqual,
17
18
  } from 'lib';
@@ -75,8 +76,8 @@ export const selectConfig = createSelector([selectGame, selectLocale], getConfig
75
76
 
76
77
  export const selectFilteredCells = selectCellFilterRoot;
77
78
 
78
- export const selectCellIsFiltered = createSelector([selectFilteredCells, selectPoint], (cellFilter, { x, y }) => {
79
- return cellFilter.some((cell) => cell.x === x && cell.y === y);
79
+ export const selectCellFilter = createSelector([selectFilteredCells, selectPoint], (cellFilter, { x, y }) => {
80
+ return cellFilter.find((cell) => cell.x === x && cell.y === y);
80
81
  });
81
82
 
82
83
  export const selectCellIsValid = createSelector([selectConfig, selectCell], (config, cell) => {
@@ -106,7 +107,7 @@ export const selectResults = createSelector([selectGroupedResults], (groupedResu
106
107
 
107
108
  export const selectIsResultMatching = createSelector(
108
109
  [selectResults, selectResultsQuery, selectFilteredCells, selectResultIndex],
109
- (results, query, filteredCells, index) => {
110
+ (results, query, cellFilter, index) => {
110
111
  if (!results) {
111
112
  return false;
112
113
  }
@@ -118,11 +119,7 @@ export const selectIsResultMatching = createSelector(
118
119
  return false;
119
120
  }
120
121
 
121
- if (filteredCells) {
122
- return filteredCells.every(({ x, y }) => result.cells.some((cell) => cell.x === x && cell.y === y));
123
- }
124
-
125
- return true;
122
+ return resultMatchesCellFilter(result, cellFilter);
126
123
  },
127
124
  );
128
125
 
@@ -1,6 +1,6 @@
1
- import { Point } from 'types';
1
+ import { CellFilterEntry } from 'types';
2
2
 
3
- export type CellFilterState = Point[];
3
+ export type CellFilterState = CellFilterEntry[];
4
4
 
5
5
  const cellFilterInitialState: CellFilterState = [];
6
6