@scrabble-solver/scrabble-solver 2.11.1 → 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 (98) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +6 -6
  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 +203 -173
  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.nft.json +1 -1
  21. package/.next/server/pages/_document.js.nft.json +1 -1
  22. package/.next/server/pages/api/dictionary/[locale]/[word].js +0 -1
  23. package/.next/server/pages/api/dictionary/[locale].js +0 -1
  24. package/.next/server/pages/api/solve.js +29 -8
  25. package/.next/server/pages/api/verify.js +0 -1
  26. package/.next/server/pages/api/visit.js +0 -1
  27. package/.next/server/pages/index.html +1 -1
  28. package/.next/server/pages/index.js +46 -39
  29. package/.next/server/pages/index.js.nft.json +1 -1
  30. package/.next/server/pages/index.json +1 -1
  31. package/.next/static/{esK8DG-6aS5V7QFRtR3YE → Mdvi3FY0PqkILKLbPlVBU}/_buildManifest.js +1 -1
  32. package/.next/static/chunks/pages/_app-495e6f4ccc278bb2.js +28 -0
  33. package/.next/static/chunks/pages/index-5ecc51900ca29685.js +1 -0
  34. package/.next/static/css/17b0a2db8742105f.css +1 -0
  35. package/.next/static/css/e1ffeb2558330c55.css +2 -0
  36. package/.next/trace +54 -53
  37. package/package.json +9 -9
  38. package/src/components/Board/components/Cell/Cell.module.scss +10 -2
  39. package/src/components/Board/hooks/useGrid.ts +1 -2
  40. package/src/components/Board/lib/getPositionInGrid.ts +1 -1
  41. package/src/components/LogoSplashScreen/LogoSplashScreen.module.scss +4 -1
  42. package/src/components/Modal/Modal.module.scss +12 -0
  43. package/src/components/Modal/Modal.tsx +4 -1
  44. package/src/components/Results/HeaderButton.tsx +5 -12
  45. package/src/components/Results/Result.tsx +5 -3
  46. package/src/components/Results/Results.module.scss +13 -1
  47. package/src/components/Results/Results.tsx +29 -43
  48. package/src/components/Results/types.ts +1 -1
  49. package/src/components/Solver/Solver.module.scss +4 -0
  50. package/src/components/Solver/Solver.tsx +9 -12
  51. package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +5 -6
  52. package/src/components/Tile/Tile.module.scss +40 -71
  53. package/src/components/Tile/Tile.tsx +4 -3
  54. package/src/components/Tile/TilePure.tsx +4 -13
  55. package/src/hooks/useAppLayout.ts +3 -1
  56. package/src/i18n/de.json +0 -1
  57. package/src/i18n/en.json +0 -1
  58. package/src/i18n/es.json +0 -1
  59. package/src/i18n/fa.json +0 -1
  60. package/src/i18n/fr.json +0 -1
  61. package/src/i18n/pl.json +0 -1
  62. package/src/lib/createRegExp.ts +13 -0
  63. package/src/lib/groupResults.ts +38 -0
  64. package/src/lib/guessLocale.ts +22 -0
  65. package/src/lib/index.ts +4 -1
  66. package/src/lib/sortResults.ts +6 -10
  67. package/src/modals/DictionaryModal/DictionaryModal.module.scss +0 -1
  68. package/src/modals/MenuModal/MenuModal.module.scss +7 -0
  69. package/src/modals/ResultsModal/ResultsModal.module.scss +2 -3
  70. package/src/modals/ResultsModal/ResultsModal.tsx +23 -11
  71. package/src/pages/api/dictionary/[locale]/[word].ts +0 -1
  72. package/src/pages/api/dictionary/[locale]/index.ts +0 -1
  73. package/src/pages/api/solve.ts +0 -1
  74. package/src/pages/api/verify.ts +0 -1
  75. package/src/pages/api/visit.ts +0 -1
  76. package/src/pages/index.tsx +13 -15
  77. package/src/parameters/index.ts +2 -2
  78. package/src/state/sagas.ts +1 -0
  79. package/src/state/selectors.ts +37 -37
  80. package/src/state/slices/boardInitialState.ts +3 -1
  81. package/src/state/slices/cellFilterInitialState.ts +3 -3
  82. package/src/state/slices/cellFilterSlice.ts +3 -1
  83. package/src/state/slices/dictionaryInitialState.ts +2 -2
  84. package/src/state/slices/rackInitialState.ts +3 -1
  85. package/src/state/slices/resultsInitialState.ts +11 -4
  86. package/src/state/slices/settingsInitialState.ts +10 -21
  87. package/src/state/slices/solveInitialState.ts +2 -2
  88. package/src/state/slices/solveSlice.ts +2 -0
  89. package/src/state/slices/verifyInitialState.ts +13 -4
  90. package/src/styles/mixins.scss +3 -1
  91. package/src/styles/variables.scss +1 -0
  92. package/src/types/index.ts +10 -2
  93. package/.next/static/chunks/pages/_app-270526803bc274eb.js +0 -28
  94. package/.next/static/chunks/pages/index-c6e7754ccf3532df.js +0 -1
  95. package/.next/static/css/ad39b36eab07e613.css +0 -1
  96. package/.next/static/css/e5803e581e4c0451.css +0 -2
  97. package/src/components/Board/types/index.ts +0 -4
  98. /package/.next/static/{esK8DG-6aS5V7QFRtR3YE → Mdvi3FY0PqkILKLbPlVBU}/_ssgManifest.js +0 -0
@@ -1,17 +1,29 @@
1
+ /* eslint-disable max-lines */
2
+
1
3
  import { createSelector } from '@reduxjs/toolkit';
2
4
  import { getLocaleConfig } from '@scrabble-solver/configs';
3
5
  import { BLANK } from '@scrabble-solver/constants';
4
- import { Cell, Config, isError, Result, Tile } from '@scrabble-solver/types';
6
+ import { Cell, Config, isError, Tile } from '@scrabble-solver/types';
5
7
 
6
8
  import i18n, { LOCALE_FEATURES } from 'i18n';
7
- import { findCell, getRemainingTiles, getRemainingTilesGroups, sortResults, unorderedArraysEqual } from 'lib';
8
- import { Translations } from 'types';
9
+ import {
10
+ createRegExp,
11
+ findCell,
12
+ getRemainingTiles,
13
+ getRemainingTilesGroups,
14
+ groupResults,
15
+ sortResults,
16
+ unorderedArraysEqual,
17
+ } from 'lib';
18
+ import { Point, Translations } from 'types';
9
19
 
10
20
  import { RootState } from './types';
11
21
 
12
22
  const selectCell = (_: unknown, cell: Cell): Cell => cell;
13
23
 
14
- const selectPoint = (_: unknown, point: { x: number; y: number }): { x: number; y: number } => point;
24
+ const selectPoint = (_: unknown, point: Point): Point => point;
25
+
26
+ const selectResultIndex = (_: unknown, index: number): number => index;
15
27
 
16
28
  const selectCharacter = (_: unknown, character: string | null): string | null => character;
17
29
 
@@ -71,54 +83,42 @@ export const selectCellIsValid = createSelector([selectConfig, selectCell], (con
71
83
  return config.tiles.some((tile) => tile.character === cell.tile.character);
72
84
  });
73
85
 
74
- export const selectResults = createSelector([selectResultsRoot], (results) => results.results);
86
+ export const selectResultsRaw = createSelector([selectResultsRoot], (results) => results.results);
75
87
 
76
88
  export const selectResultsQuery = createSelector([selectResultsRoot], (results) => results.query);
77
89
 
78
- export const selectResultsSortColumn = createSelector([selectResultsRoot], (results) => results.sort.column);
90
+ export const selectResultsSort = createSelector([selectResultsRoot], (results) => results.sort);
79
91
 
80
- export const selectResultsSortDirection = createSelector([selectResultsRoot], (results) => results.sort.direction);
92
+ export const selectSortedResults = createSelector([selectResultsRaw, selectResultsSort, selectLocale], sortResults);
81
93
 
82
- export const selectSortedResults = createSelector(
83
- [selectResults, selectResultsSortColumn, selectResultsSortDirection, selectLocale],
84
- sortResults,
94
+ export const selectGroupedResults = createSelector(
95
+ [selectSortedResults, selectResultsQuery, selectCellFilter],
96
+ groupResults,
85
97
  );
86
98
 
87
- const filterResultsByQuery = (results: Result[], query: string): Result[] => {
88
- if (query.trim().length === 0) {
89
- return results;
90
- }
91
-
92
- let regExp: RegExp | undefined;
93
-
94
- try {
95
- regExp = new RegExp(query, 'gi');
96
- } catch {
97
- return results;
98
- }
99
-
100
- return results.filter((result) => {
101
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
102
- return regExp!.test(result.word);
103
- });
104
- };
99
+ export const selectResults = createSelector([selectGroupedResults], (groupedResults) => {
100
+ return groupedResults ? [...groupedResults.matching, ...groupedResults.other] : groupedResults;
101
+ });
105
102
 
106
- export const selectSortedFilteredResults = createSelector(
107
- [selectSortedResults, selectResultsQuery, selectCellFilter],
108
- (results, query, cellFilter) => {
103
+ export const selectIsResultMatching = createSelector(
104
+ [selectResults, selectResultsQuery, selectCellFilter, selectResultIndex],
105
+ (results, query, cellFilter, index) => {
109
106
  if (!results) {
110
- return results;
107
+ return false;
111
108
  }
112
109
 
113
- const filteredByQuery = filterResultsByQuery(results, query);
110
+ const result = results[index];
111
+ const regExp = createRegExp(query);
114
112
 
115
- if (!cellFilter) {
116
- return filteredByQuery;
113
+ if (!regExp.test(result.word)) {
114
+ return false;
117
115
  }
118
116
 
119
- return filteredByQuery.filter((result) => {
117
+ if (cellFilter) {
120
118
  return cellFilter.every(({ x, y }) => result.cells.some((cell) => cell.x === x && cell.y === y));
121
- });
119
+ }
120
+
121
+ return true;
122
122
  },
123
123
  );
124
124
 
@@ -3,9 +3,11 @@ import { Board } from '@scrabble-solver/types';
3
3
 
4
4
  import settingsInitialState from './settingsInitialState';
5
5
 
6
+ export type BoardState = Board;
7
+
6
8
  const { configId, locale } = settingsInitialState;
7
9
  const { boardHeight, boardWidth } = getLocaleConfig(configId, locale);
8
- const boardInitialState: Board = Board.create(boardWidth, boardHeight);
10
+ const boardInitialState: BoardState = Board.create(boardWidth, boardHeight);
9
11
 
10
12
  // const createOxyphenbutazone = () => {
11
13
  // // Tiles: oypbaze
@@ -1,7 +1,7 @@
1
- import { Cell } from '@scrabble-solver/types';
1
+ import { Point } from 'types';
2
2
 
3
- export type Point = Pick<Cell, 'x' | 'y'>;
3
+ export type CellFilterState = Point[];
4
4
 
5
- const cellFilterInitialState: Point[] = [];
5
+ const cellFilterInitialState: CellFilterState = [];
6
6
 
7
7
  export default cellFilterInitialState;
@@ -1,6 +1,8 @@
1
1
  import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2
2
 
3
- import cellFilterInitialState, { Point } from './cellFilterInitialState';
3
+ import { Point } from 'types';
4
+
5
+ import cellFilterInitialState from './cellFilterInitialState';
4
6
 
5
7
  const cellFilterSlice = createSlice({
6
8
  initialState: cellFilterInitialState,
@@ -1,13 +1,13 @@
1
1
  import { WordDefinition } from '@scrabble-solver/types';
2
2
 
3
- interface DictionaryInitialState {
3
+ export interface DictionaryState {
4
4
  error: unknown | undefined;
5
5
  input: string;
6
6
  isLoading: boolean;
7
7
  results: WordDefinition[];
8
8
  }
9
9
 
10
- const dictionaryInitialState: DictionaryInitialState = {
10
+ const dictionaryInitialState: DictionaryState = {
11
11
  error: undefined,
12
12
  input: '',
13
13
  isLoading: false,
@@ -1,3 +1,5 @@
1
- const rackInitialState: (string | null)[] = [null, null, null, null, null, null, null];
1
+ export type RackState = (string | null)[];
2
+
3
+ const rackInitialState: RackState = [null, null, null, null, null, null, null];
2
4
 
3
5
  export default rackInitialState;
@@ -1,11 +1,18 @@
1
1
  import { Result } from '@scrabble-solver/types';
2
2
 
3
- import { ResultColumn, SortDirection } from 'types';
3
+ import { ResultColumn, Sort, SortDirection } from 'types';
4
4
 
5
- const resultsInitialState = {
6
- candidate: null as Result | null,
5
+ export interface ResultsState {
6
+ candidate: Result | null;
7
+ query: string;
8
+ results: Result[] | undefined;
9
+ sort: Sort;
10
+ }
11
+
12
+ const resultsInitialState: ResultsState = {
13
+ candidate: null,
7
14
  query: '',
8
- results: undefined as Result[] | undefined,
15
+ results: undefined,
9
16
  sort: {
10
17
  column: ResultColumn.Points,
11
18
  direction: SortDirection.Descending,
@@ -1,29 +1,18 @@
1
- import { scrabble } from '@scrabble-solver/configs';
1
+ import { literaki, scrabble } from '@scrabble-solver/configs';
2
2
  import { Locale } from '@scrabble-solver/types';
3
3
 
4
- const getInitialLocale = (): Locale => {
5
- if (!globalThis.navigator) {
6
- return Locale.EN_US;
7
- }
4
+ import { guessLocale } from 'lib';
8
5
 
9
- const locales = Object.values(Locale);
10
- const exactMatch = locales.find((locale) => globalThis.navigator.language === locale);
6
+ export interface SettingsState {
7
+ autoGroupTiles: 'left' | 'right' | null;
8
+ configId: typeof literaki.id | typeof scrabble.id;
9
+ locale: Locale;
10
+ }
11
11
 
12
- if (exactMatch) {
13
- return exactMatch;
14
- }
15
-
16
- const partialMatch = locales.find((locale) => {
17
- return globalThis.navigator.language === locale.substring(0, 2);
18
- });
19
-
20
- return partialMatch || Locale.EN_US;
21
- };
22
-
23
- const settingsInitialState = {
24
- autoGroupTiles: 'left' as 'left' | 'right' | null,
12
+ const settingsInitialState: SettingsState = {
13
+ autoGroupTiles: 'left',
25
14
  configId: scrabble.id,
26
- locale: getInitialLocale(),
15
+ locale: guessLocale(),
27
16
  };
28
17
 
29
18
  export default settingsInitialState;
@@ -2,7 +2,7 @@ import { Board } from '@scrabble-solver/types';
2
2
 
3
3
  import boardInitialState from './boardInitialState';
4
4
 
5
- interface SolveInitialState {
5
+ export interface SolveState {
6
6
  error: unknown | undefined;
7
7
  isLoading: boolean;
8
8
  lastSolvedParameters: {
@@ -11,7 +11,7 @@ interface SolveInitialState {
11
11
  };
12
12
  }
13
13
 
14
- const solveInitialState: SolveInitialState = {
14
+ const solveInitialState: SolveState = {
15
15
  error: undefined,
16
16
  isLoading: false,
17
17
  lastSolvedParameters: {
@@ -12,6 +12,8 @@ const solveSlice = createSlice({
12
12
  initialState: solveInitialState,
13
13
  name: 'solve',
14
14
  reducers: {
15
+ reset: () => solveInitialState,
16
+
15
17
  submit: (state) => {
16
18
  const error = solveInitialState.error;
17
19
  return { ...state, error, isLoading: true };
@@ -1,12 +1,21 @@
1
- import boardInitialState from './boardInitialState';
1
+ import boardInitialState, { BoardState } from './boardInitialState';
2
2
 
3
- const verifyInitialState = {
3
+ export interface VerifyState {
4
+ isLoading: boolean;
5
+ lastSolvedParameters: {
6
+ board: BoardState;
7
+ };
8
+ invalidWords: string[];
9
+ validWords: string[];
10
+ }
11
+
12
+ const verifyInitialState: VerifyState = {
4
13
  isLoading: false,
5
14
  lastSolvedParameters: {
6
15
  board: boardInitialState,
7
16
  },
8
- invalidWords: [] as string[],
9
- validWords: [] as string[],
17
+ invalidWords: [],
18
+ validWords: [],
10
19
  };
11
20
 
12
21
  export default verifyInitialState;
@@ -43,7 +43,6 @@ $media-expressions: (
43
43
  position: relative;
44
44
 
45
45
  &::after {
46
- content: '';
47
46
  position: absolute;
48
47
  top: 0;
49
48
  right: 0;
@@ -63,6 +62,7 @@ $media-expressions: (
63
62
  }
64
63
 
65
64
  &::after {
65
+ content: '';
66
66
  box-shadow: 0 0 0 var(--focus-effect--size) var(--color--focus);
67
67
  }
68
68
  }
@@ -151,6 +151,7 @@ $media-expressions: (
151
151
  &:nth-child(3) {
152
152
  input {
153
153
  left: -200%;
154
+ right: 0;
154
155
  clip-path: polygon((200% / 3) (100% / 3), 100% (100% / 3), 100% (200% / 3), (200% / 3) (200% / 3));
155
156
  }
156
157
  }
@@ -160,6 +161,7 @@ $media-expressions: (
160
161
  &:nth-last-child(3) {
161
162
  input {
162
163
  left: 0;
164
+ right: -200%;
163
165
  clip-path: polygon(0 (100% / 3), (100% / 3) (100% / 3), (100% / 3) (200% / 3), 0 (200% / 3));
164
166
  }
165
167
  }
@@ -41,6 +41,7 @@ $easeOutSine: cubic-bezier(0.61, 1, 0.88, 1);
41
41
  --color--success: #00a900;
42
42
  --color--warning: hsl(35, 90%, 60%);
43
43
  --color--primary: var(--color--violet);
44
+ --color--primary--light: var(--color--violet--light);
44
45
  --color--primary--opposite: var(--color--white);
45
46
 
46
47
  --color--bonus--character--1: var(--color--yellow--light);
@@ -2,6 +2,16 @@ export type Comparator<T> = (a: T, B: T) => number;
2
2
 
3
3
  export type Direction = 'horizontal' | 'vertical';
4
4
 
5
+ export interface Point {
6
+ x: number;
7
+ y: number;
8
+ }
9
+
10
+ export interface Sort {
11
+ column: ResultColumn;
12
+ direction: SortDirection;
13
+ }
14
+
5
15
  export enum SortDirection {
6
16
  Ascending = 'ascending',
7
17
  Descending = 'descending',
@@ -30,7 +40,6 @@ export enum ResultColumn {
30
40
  Word = 'word',
31
41
  WordsCount = 'words-count',
32
42
  }
33
-
34
43
  export type TranslationKey =
35
44
  | 'cell.filter-cell'
36
45
  | 'cell.set-blank'
@@ -78,7 +87,6 @@ export type TranslationKey =
78
87
  | 'rack.tile.location'
79
88
  | 'remaining-tiles'
80
89
  | 'results'
81
- | 'results.empty-state.no-filtered-results'
82
90
  | 'results.empty-state.no-results'
83
91
  | 'results.empty-state.outdated'
84
92
  | 'results.empty-state.uninitialized'