scrabble-solver 2.10.5 → 2.10.7

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 (132) hide show
  1. package/README.md +12 -12
  2. package/lerna.json +1 -1
  3. package/package.json +10 -10
  4. package/packages/configs/package-lock.json +4 -4
  5. package/packages/configs/package.json +3 -3
  6. package/packages/constants/build/index.d.ts +2 -0
  7. package/packages/constants/build/index.js +3 -1
  8. package/packages/constants/package-lock.json +2 -2
  9. package/packages/constants/package.json +1 -1
  10. package/packages/constants/src/index.ts +4 -0
  11. package/packages/dictionaries/package-lock.json +2 -2
  12. package/packages/dictionaries/package.json +4 -4
  13. package/packages/logger/package-lock.json +2 -2
  14. package/packages/logger/package.json +1 -1
  15. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  16. package/packages/scrabble-solver/.next/build-manifest.json +10 -10
  17. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  18. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  19. package/packages/scrabble-solver/.next/cache/next-server.js.nft.json +1 -1
  20. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  21. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  22. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  23. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  24. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  25. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  26. package/packages/scrabble-solver/.next/next-server.js.nft.json +1 -1
  27. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  28. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  29. package/packages/scrabble-solver/.next/server/chunks/176.js +551 -447
  30. package/packages/scrabble-solver/.next/server/chunks/290.js +3 -1
  31. package/packages/scrabble-solver/.next/server/chunks/579.js +24 -16
  32. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  33. package/packages/scrabble-solver/.next/server/pages/404.html +2 -2
  34. package/packages/scrabble-solver/.next/server/pages/404.js.nft.json +1 -1
  35. package/packages/scrabble-solver/.next/server/pages/500.html +2 -2
  36. package/packages/scrabble-solver/.next/server/pages/_app.js.nft.json +1 -1
  37. package/packages/scrabble-solver/.next/server/pages/api/dictionary/[locale]/[word].js +18 -16
  38. package/packages/scrabble-solver/.next/server/pages/index.html +2 -2
  39. package/packages/scrabble-solver/.next/server/pages/index.js +18 -11
  40. package/packages/scrabble-solver/.next/server/pages/index.js.nft.json +1 -1
  41. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  42. package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
  43. package/packages/scrabble-solver/.next/static/6RggBFm8kHrh-k1-CG3um/_buildManifest.js +1 -0
  44. package/packages/scrabble-solver/.next/static/chunks/509-6ad4482d4351452c.js +1 -0
  45. package/packages/scrabble-solver/.next/static/chunks/pages/{404-7619583a9e7188b1.js → 404-67383848027ec49b.js} +1 -1
  46. package/packages/scrabble-solver/.next/static/chunks/pages/_app-c58cfa832b76cc87.js +24 -0
  47. package/packages/scrabble-solver/.next/static/chunks/pages/index-146039f501e49c08.js +1 -0
  48. package/packages/scrabble-solver/.next/static/css/4482c4a0064d3807.css +1 -0
  49. package/packages/scrabble-solver/.next/static/css/9d1013ec684361b9.css +1 -0
  50. package/packages/scrabble-solver/.next/trace +55 -55
  51. package/packages/scrabble-solver/package-lock.json +37 -37
  52. package/packages/scrabble-solver/package.json +13 -13
  53. package/packages/scrabble-solver/src/components/Board/components/Cell/Button.tsx +1 -0
  54. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.tsx +6 -0
  55. package/packages/scrabble-solver/src/components/Board/components/Cell/CellPure.tsx +10 -1
  56. package/packages/scrabble-solver/src/components/Button/Button.module.scss +2 -5
  57. package/packages/scrabble-solver/src/components/Button/Button.tsx +1 -0
  58. package/packages/scrabble-solver/src/components/Button/Link.tsx +1 -0
  59. package/packages/scrabble-solver/src/components/{SquareButton/SquareButton.module.scss → IconButton/IconButton.module.scss} +2 -3
  60. package/packages/scrabble-solver/src/components/{SquareButton/SquareButton.tsx → IconButton/IconButton.tsx} +7 -6
  61. package/packages/scrabble-solver/src/components/{SquareButton → IconButton}/Link.tsx +3 -2
  62. package/packages/scrabble-solver/src/components/IconButton/index.ts +1 -0
  63. package/packages/scrabble-solver/src/components/Logo/Logo.svg +44 -15
  64. package/packages/scrabble-solver/src/components/Modal/Modal.tsx +3 -2
  65. package/packages/scrabble-solver/src/components/NavButtons/NavButtons.tsx +37 -9
  66. package/packages/scrabble-solver/src/components/Rack/RackTile.tsx +5 -0
  67. package/packages/scrabble-solver/src/components/Results/HeaderButton.tsx +1 -0
  68. package/packages/scrabble-solver/src/components/Results/Result.tsx +1 -0
  69. package/packages/scrabble-solver/src/components/Results/Results.module.scss +0 -1
  70. package/packages/scrabble-solver/src/components/Results/SolveButton.tsx +1 -0
  71. package/packages/scrabble-solver/src/components/Solver/Solver.module.scss +11 -19
  72. package/packages/scrabble-solver/src/components/Solver/Solver.tsx +18 -36
  73. package/packages/scrabble-solver/src/components/Solver/components/EmptyState/EmptyState.module.scss +0 -2
  74. package/packages/scrabble-solver/src/components/Solver/components/InsertButton/InsertButton.module.scss +15 -0
  75. package/packages/scrabble-solver/src/components/Solver/components/{ApplyButton/ApplyButton.tsx → InsertButton/InsertButton.tsx} +10 -6
  76. package/packages/scrabble-solver/src/components/Solver/components/InsertButton/index.ts +1 -0
  77. package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +143 -0
  78. package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +98 -0
  79. package/packages/scrabble-solver/src/components/Solver/components/SolveButton/SolveButton.tsx +11 -1
  80. package/packages/scrabble-solver/src/components/Solver/components/index.ts +2 -1
  81. package/packages/scrabble-solver/src/components/Tile/Tile.tsx +3 -0
  82. package/packages/scrabble-solver/src/components/Tile/TilePure.tsx +3 -0
  83. package/packages/scrabble-solver/src/components/Tooltip/useTooltip.tsx +14 -2
  84. package/packages/scrabble-solver/src/components/index.ts +1 -2
  85. package/packages/scrabble-solver/src/i18n/de.json +5 -0
  86. package/packages/scrabble-solver/src/i18n/en.json +5 -0
  87. package/packages/scrabble-solver/src/i18n/es.json +5 -0
  88. package/packages/scrabble-solver/src/i18n/fa.json +5 -0
  89. package/packages/scrabble-solver/src/i18n/fr.json +5 -0
  90. package/packages/scrabble-solver/src/i18n/pl.json +5 -0
  91. package/packages/scrabble-solver/src/icons/ArrowDown.svg +1 -1
  92. package/packages/scrabble-solver/src/icons/ArrowLeft.svg +1 -1
  93. package/packages/scrabble-solver/src/icons/ArrowRight.svg +1 -1
  94. package/packages/scrabble-solver/src/icons/ArrowUp.svg +1 -1
  95. package/packages/scrabble-solver/src/icons/ChevronDown.svg +1 -1
  96. package/packages/scrabble-solver/src/icons/ChevronLeft.svg +4 -0
  97. package/packages/scrabble-solver/src/icons/ChevronRight.svg +4 -0
  98. package/packages/scrabble-solver/src/icons/List.svg +1 -1
  99. package/packages/scrabble-solver/src/icons/index.ts +2 -0
  100. package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss +2 -3
  101. package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.tsx +9 -3
  102. package/packages/scrabble-solver/src/modals/RemainingTilesModal/components/Character/Character.tsx +1 -0
  103. package/packages/scrabble-solver/src/modals/SettingsModal/components/AutoGroupTilesSetting/AutoGroupTilesSetting.tsx +2 -2
  104. package/packages/scrabble-solver/src/modals/SettingsModal/components/ConfigSetting/ConfigSetting.tsx +2 -2
  105. package/packages/scrabble-solver/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.tsx +2 -2
  106. package/packages/scrabble-solver/src/pages/api/dictionary/[locale]/[word].ts +3 -1
  107. package/packages/scrabble-solver/src/pages/index.tsx +10 -6
  108. package/packages/scrabble-solver/src/state/sagas.ts +5 -2
  109. package/packages/scrabble-solver/src/state/useTranslate.ts +5 -2
  110. package/packages/scrabble-solver/src/styles/mixins.scss +6 -0
  111. package/packages/scrabble-solver/src/types/index.ts +6 -1
  112. package/packages/solver/package-lock.json +2 -2
  113. package/packages/solver/package.json +5 -5
  114. package/packages/types/package-lock.json +3 -3
  115. package/packages/types/package.json +2 -2
  116. package/packages/word-definitions/package-lock.json +8 -8
  117. package/packages/word-definitions/package.json +2 -2
  118. package/packages/word-lists/package-lock.json +2 -2
  119. package/packages/word-lists/package.json +2 -2
  120. package/packages/scrabble-solver/.next/static/WILX-RgqlLTd4ZoPs8C_E/_buildManifest.js +0 -1
  121. package/packages/scrabble-solver/.next/static/chunks/144-6768fe9a92865ec8.js +0 -1
  122. package/packages/scrabble-solver/.next/static/chunks/pages/_app-fa0661b072fc6af9.js +0 -24
  123. package/packages/scrabble-solver/.next/static/chunks/pages/index-1a6bbb880f28606a.js +0 -1
  124. package/packages/scrabble-solver/.next/static/css/d80ffccf2315791a.css +0 -1
  125. package/packages/scrabble-solver/.next/static/css/e737d5d7fbed2434.css +0 -1
  126. package/packages/scrabble-solver/src/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +0 -76
  127. package/packages/scrabble-solver/src/components/ResultCandidatePicker/ResultCandidatePicker.tsx +0 -38
  128. package/packages/scrabble-solver/src/components/Solver/components/ApplyButton/ApplyButton.module.scss +0 -5
  129. package/packages/scrabble-solver/src/components/Solver/components/ApplyButton/index.ts +0 -1
  130. package/packages/scrabble-solver/src/components/SquareButton/index.ts +0 -1
  131. /package/packages/scrabble-solver/.next/static/{WILX-RgqlLTd4ZoPs8C_E → 6RggBFm8kHrh-k1-CG3um}/_ssgManifest.js +0 -0
  132. /package/packages/scrabble-solver/src/components/{ResultCandidatePicker → Solver/components/ResultCandidatePicker}/index.ts +0 -0
@@ -16,6 +16,7 @@ import { selectLocale, useTypedSelector } from 'state';
16
16
  import TilePure from './TilePure';
17
17
 
18
18
  interface Props {
19
+ 'aria-label': string;
19
20
  autoFocus?: boolean;
20
21
  character?: string;
21
22
  className?: string;
@@ -35,6 +36,7 @@ interface Props {
35
36
  }
36
37
 
37
38
  const Tile: FunctionComponent<Props> = ({
39
+ 'aria-label': ariaLabel,
38
40
  autoFocus,
39
41
  className,
40
42
  character = '',
@@ -75,6 +77,7 @@ const Tile: FunctionComponent<Props> = ({
75
77
 
76
78
  return (
77
79
  <TilePure
80
+ aria-label={ariaLabel}
78
81
  autoFocus={autoFocus}
79
82
  canShowPoints={canShowPoints}
80
83
  character={character}
@@ -14,6 +14,7 @@ import { ExclamationSquareFill } from 'icons';
14
14
  import styles from './Tile.module.scss';
15
15
 
16
16
  interface Props {
17
+ 'aria-label': string;
17
18
  autoFocus?: boolean;
18
19
  canShowPoints?: boolean;
19
20
  character?: string;
@@ -37,6 +38,7 @@ interface Props {
37
38
  }
38
39
 
39
40
  const TilePure: FunctionComponent<Props> = ({
41
+ 'aria-label': ariaLabel,
40
42
  autoFocus,
41
43
  canShowPoints,
42
44
  character,
@@ -75,6 +77,7 @@ const TilePure: FunctionComponent<Props> = ({
75
77
  style={style}
76
78
  >
77
79
  <input
80
+ aria-label={ariaLabel}
78
81
  autoCapitalize="none"
79
82
  autoComplete="off"
80
83
  autoCorrect="off"
@@ -12,7 +12,7 @@ import {
12
12
  import { usePopper } from 'react-popper';
13
13
  import { useMountedState, useRafLoop } from 'react-use';
14
14
 
15
- import { usePortal, useUniqueId } from 'hooks';
15
+ import { useIsTouchDevice, usePortal, useUniqueId } from 'hooks';
16
16
  import { noop } from 'lib';
17
17
 
18
18
  import { MODIFIERS } from './constants';
@@ -36,11 +36,13 @@ interface TriggerProps {
36
36
  onMouseOver?: MouseEventHandler;
37
37
  }
38
38
 
39
+ // eslint-disable-next-line max-statements
39
40
  const useTooltip = (
40
41
  tooltip: ReactNode,
41
42
  { className, placement = 'top', onBlur = noop, onFocus = noop, onMouseOut = noop, onMouseOver = noop }: Props = {},
42
43
  ): TriggerProps => {
43
44
  const id = useUniqueId();
45
+ const isTouchDevice = useIsTouchDevice();
44
46
  const isEnabled = Boolean(tooltip) || tooltip === 0;
45
47
  const isMounted = useMountedState();
46
48
  const [isShown, setIsShown] = useState<boolean>(false);
@@ -90,7 +92,7 @@ const useTooltip = (
90
92
  [onMouseOver],
91
93
  );
92
94
 
93
- const triggerProps = useMemo(
95
+ const mouseTriggerProps = useMemo(
94
96
  () => ({
95
97
  ...ariaAttributes,
96
98
  ref: setReferenceElement,
@@ -102,6 +104,16 @@ const useTooltip = (
102
104
  [ariaAttributes, handleBlur, handleFocus, handleMouseOut, handleMouseOver],
103
105
  );
104
106
 
107
+ const touchTriggerProps = useMemo(
108
+ () => ({
109
+ ...ariaAttributes,
110
+ ref: setReferenceElement,
111
+ }),
112
+ [ariaAttributes],
113
+ );
114
+
115
+ const triggerProps = isTouchDevice ? touchTriggerProps : mouseTriggerProps;
116
+
105
117
  useRafLoop(() => {
106
118
  if (isMounted() && update) {
107
119
  update();
@@ -5,6 +5,7 @@ export { default as Checkbox } from './Checkbox';
5
5
  export { default as Dictionary } from './Dictionary';
6
6
  export { default as DictionaryInput } from './DictionaryInput';
7
7
  export { default as EmptyState } from './EmptyState';
8
+ export { default as IconButton } from './IconButton';
8
9
  export { default as Key } from './Key';
9
10
  export { default as Loading } from './Loading';
10
11
  export { default as Logo } from './Logo';
@@ -16,13 +17,11 @@ export { default as PlainTiles } from './PlainTiles';
16
17
  export { default as Progress } from './Progress';
17
18
  export { default as Rack } from './Rack';
18
19
  export { default as Radio } from './Radio';
19
- export { default as ResultCandidatePicker } from './ResultCandidatePicker';
20
20
  export { default as Results } from './Results';
21
21
  export { default as ResultsInput } from './ResultsInput';
22
22
  export { default as Sizer } from './Sizer';
23
23
  export { default as Solver } from './Solver';
24
24
  export { default as SplashScreen } from './SplashScreen';
25
- export { default as SquareButton } from './SquareButton';
26
25
  export { default as SvgFontCss } from './SvgFontCss';
27
26
  export { default as SvgFontFix } from './SvgFontFix';
28
27
  export { default as Tile } from './Tile';
@@ -2,13 +2,16 @@
2
2
  "cell.filter-cell": "Zielort - klicken zum Wechseln",
3
3
  "cell.set-blank": "Als Blanko markieren",
4
4
  "cell.set-not-blank": "Nicht als Blanko markieren",
5
+ "cell.tile.location": "Brett: Stein ({{x}}, {{y}})",
5
6
  "cell.toggle-direction": "Schreibrichtung - klicken zum Wechseln",
6
7
  "common.blanks": "Blankos",
7
8
  "common.clear": "Löschen",
8
9
  "common.close": "Schließen",
9
10
  "common.consonants": "Konsonanten",
10
11
  "common.loading": "Laden",
12
+ "common.next": "Weiter",
11
13
  "common.points": "Punkte",
14
+ "common.previous": "Zurück",
12
15
  "common.tiles": "Steine",
13
16
  "common.two-letter-tiles": "Zwei-Buchstaben",
14
17
  "common.vowels": "Vokale",
@@ -37,6 +40,7 @@
37
40
  "keyMap.rack.insert-blank": "Blanko hinzufügen (Leertaste)",
38
41
  "menu": "Menü",
39
42
  "rack.placeholder": "Steine…",
43
+ "rack.tile.location": "Ablage: Stein ({{index}})",
40
44
  "remaining-tiles": "Restliche Steine",
41
45
  "results": "Ergebnisse",
42
46
  "results.empty-state.no-filtered-results": "Keine Ergebnisse für diese Anfrage.",
@@ -44,6 +48,7 @@
44
48
  "results.empty-state.outdated": "Ergebnisse sind alt. Klicken zum Aktualisieren.",
45
49
  "results.empty-state.uninitialized": "Wörter die aus deinen Buchstaben generiert wurden erscheinen hier.",
46
50
  "results.input.placeholder": "Suchergebnisse... (RegExp)",
51
+ "results.insert": "Hinzufügen",
47
52
  "results.solve": "Lösen",
48
53
  "settings": "Einstellungen",
49
54
  "settings.autoGroupTiles": "Restliche Steine gruppieren",
@@ -2,13 +2,16 @@
2
2
  "cell.filter-cell": "Target destination - click to toggle",
3
3
  "cell.set-blank": "Mark it a blank",
4
4
  "cell.set-not-blank": "Mark it not a blank",
5
+ "cell.tile.location": "Board: tile ({{x}}, {{y}})",
5
6
  "cell.toggle-direction": "Typing direction - click to toggle",
6
7
  "common.blanks": "Blanks",
7
8
  "common.clear": "Clear",
8
9
  "common.close": "Close",
9
10
  "common.consonants": "Consonants",
10
11
  "common.loading": "Loading",
12
+ "common.next": "Next",
11
13
  "common.points": "Points",
14
+ "common.previous": "Previous",
12
15
  "common.tiles": "Tiles",
13
16
  "common.two-letter-tiles": "Two-letter",
14
17
  "common.vowels": "Vowels",
@@ -37,6 +40,7 @@
37
40
  "keyMap.rack.insert-blank": "Insert blank (spacebar)",
38
41
  "menu": "Menu",
39
42
  "rack.placeholder": "Letters",
43
+ "rack.tile.location": "Rack: tile ({{index}})",
40
44
  "remaining-tiles": "Remaining tiles",
41
45
  "results": "Results",
42
46
  "results.empty-state.no-filtered-results": "No result matches this query.",
@@ -44,6 +48,7 @@
44
48
  "results.empty-state.outdated": "Results are outdated. Click below to update.",
45
49
  "results.empty-state.uninitialized": "Words generated from your letters will be shown here.",
46
50
  "results.input.placeholder": "Search results... (RegExp)",
51
+ "results.insert": "Insert",
47
52
  "results.solve": "Solve",
48
53
  "settings": "Settings",
49
54
  "settings.autoGroupTiles": "Group remaining tiles",
@@ -2,13 +2,16 @@
2
2
  "cell.filter-cell": "Destino objetivo: haga clic para alternar",
3
3
  "cell.set-blank": "Marcar como en blanco",
4
4
  "cell.set-not-blank": "Marcar como no en blanco",
5
+ "cell.tile.location": "Tablero: espacio ({{x}}, {{y}})",
5
6
  "cell.toggle-direction": "Dirección de escritura: haga clic para alternar",
6
7
  "common.blanks": "Blancos",
7
8
  "common.clear": "Borrar",
8
9
  "common.close": "Cerrar",
9
10
  "common.consonants": "Consonantes",
10
11
  "common.loading": "Cargando",
12
+ "common.next": "Siguiente",
11
13
  "common.points": "Puntos",
14
+ "common.previous": "Anterior",
12
15
  "common.tiles": "Longitud",
13
16
  "common.two-letter-tiles": "Dos letras",
14
17
  "common.vowels": "Vocales",
@@ -37,6 +40,7 @@
37
40
  "keyMap.rack.insert-blank": "Insertar espacio en blanco (barra espaciadora)",
38
41
  "menu": "Menú",
39
42
  "rack.placeholder": "Letras…",
43
+ "rack.tile.location": "Estante: espacio ({{index}})",
40
44
  "remaining-tiles": "Casillas restantes",
41
45
  "results": "Resultados",
42
46
  "results.empty-state.no-filtered-results": "Ningún resultado coincide con esta consulta.",
@@ -44,6 +48,7 @@
44
48
  "results.empty-state.outdated": "Los resultados están desactualizados. Haga clic a continuación para actualizar.",
45
49
  "results.empty-state.uninitialized": "Aquí se mostrarán las palabras generadas a partir de sus letras.",
46
50
  "results.input.placeholder": "Busque una solución... (RegExp)",
51
+ "results.insert": "Insertar",
47
52
  "results.solve": "Resolver",
48
53
  "settings": "Configuración",
49
54
  "settings.autoGroupTiles": "Agrupar casillas restantes",
@@ -3,12 +3,15 @@
3
3
  "cell.set-blank": "علامت گذاری به عنوان خالی",
4
4
  "cell.set-not-blank": "علامت گذاری به عنوان غیر خالی",
5
5
  "cell.toggle-direction": "جهت تایپ - کلیک برای تغییر",
6
+ "cell.tile.location": "({{x}}، {{y}}) کاشی: صفحه",
6
7
  "common.blanks": "خالی",
7
8
  "common.clear": "پاک کردن",
8
9
  "common.close": "بستن",
9
10
  "common.consonants": "حروف صامت",
10
11
  "common.loading": "در حال بارگزاری",
12
+ "common.next": "بعدی",
11
13
  "common.points": "امتیازات",
14
+ "common.previous": "قبلی",
12
15
  "common.tiles": "کاشی ها",
13
16
  "common.two-letter-tiles": "دو حرفی",
14
17
  "common.vowels": "حروف مصوت",
@@ -37,6 +40,7 @@
37
40
  "keyMap.rack.insert-blank": "وارد کردن کاشی خالی (دکمه اسپیس)",
38
41
  "menu": "منو",
39
42
  "rack.placeholder": "لیستحرف",
43
+ "rack.tile.location": "({{index}}) کاشی: طاقچه",
40
44
  "remaining-tiles": "کاشی های باقی مانده",
41
45
  "results": "نتایج",
42
46
  "results.empty-state.no-filtered-results": "پاسخی یافت نشد.",
@@ -44,6 +48,7 @@
44
48
  "results.empty-state.outdated": "نتایج به روز نیستند، برای بروز رسانی کلیک کنید.",
45
49
  "results.empty-state.uninitialized": "کلمات تولید شده از حروف شما اینجا نمایش داده خواهد شد.",
46
50
  "results.input.placeholder": "جستجو در نتایج (RegExp)",
51
+ "results.insert": "وارد کردن",
47
52
  "results.solve": "حل کن",
48
53
  "settings": "تنظیمات",
49
54
  "settings.autoGroupTiles": "کاشی های باقی مانده ی طاقچه را کنار هم قرار بده",
@@ -2,13 +2,16 @@
2
2
  "cell.filter-cell": "Destination cible - cliquer pour changer",
3
3
  "cell.set-blank": "Marquer comme vide",
4
4
  "cell.set-not-blank": "Marquer comme non vide",
5
+ "cell.tile.location": "Plateau: la case ({{x}}, {{y}})",
5
6
  "cell.toggle-direction": "Direction d'écriture - cliquer pour changer",
6
7
  "common.blanks": "Cases vides",
7
8
  "common.clear": "Effacer",
8
9
  "common.close": "Fermer",
9
10
  "common.consonants": "Consonnes",
10
11
  "common.loading": "Chargement",
12
+ "common.next": "Suivant",
11
13
  "common.points": "Points",
14
+ "common.previous": "Précédent",
12
15
  "common.tiles": "Cases",
13
16
  "common.two-letter-tiles": "Deux lettres",
14
17
  "common.vowels": "Voyelles",
@@ -37,6 +40,7 @@
37
40
  "keyMap.rack.insert-blank": "Inserer une case vide (spacebar)",
38
41
  "menu": "Menu",
39
42
  "rack.placeholder": "Lettres",
43
+ "rack.tile.location": "Chevalet: la case ({{index}})",
40
44
  "remaining-tiles": "Cases restantes",
41
45
  "results": "Résultats",
42
46
  "results.empty-state.no-filtered-results": "Aucun résultat ne correspond à cette requête",
@@ -44,6 +48,7 @@
44
48
  "results.empty-state.outdated": "Les résultats sont dépassé. Cliquer ci-dessous pour mettre à jour.",
45
49
  "results.empty-state.uninitialized": "Les mots générés à partir de vos lettres seront affichés ici.",
46
50
  "results.input.placeholder": "Rechercher les résultats... (RegExp)",
51
+ "results.insert": "Inserer",
47
52
  "results.solve": "Résoudre",
48
53
  "settings": "Options",
49
54
  "settings.autoGroupTiles": "Grouper les cases restantes",
@@ -2,13 +2,16 @@
2
2
  "cell.filter-cell": "Miejsce docelowe - kliknij aby zmienić",
3
3
  "cell.set-blank": "Oznacz jako blank",
4
4
  "cell.set-not-blank": "Oznacz jako nie blank",
5
+ "cell.tile.location": "Plansza: płytka ({{x}}, {{y}})",
5
6
  "cell.toggle-direction": "Kierunek wpisywania - kliknij aby zmienić",
6
7
  "common.blanks": "Blanki",
7
8
  "common.clear": "Wyczyść",
8
9
  "common.close": "Zamknij",
9
10
  "common.consonants": "Spółgłoski",
10
11
  "common.loading": "Ładowanie",
12
+ "common.next": "Następne",
11
13
  "common.points": "Punkty",
14
+ "common.previous": "Poprzednie",
12
15
  "common.tiles": "Płytki",
13
16
  "common.two-letter-tiles": "Dwuliterowe",
14
17
  "common.vowels": "Samogłoski",
@@ -37,6 +40,7 @@
37
40
  "keyMap.rack.insert-blank": "Wstaw blanka (spacja)",
38
41
  "menu": "Menu",
39
42
  "rack.placeholder": "Literki",
43
+ "rack.tile.location": "Stojak: płytka ({{index}})",
40
44
  "remaining-tiles": "Pozostałe płytki",
41
45
  "results": "Wyniki",
42
46
  "results.empty-state.no-filtered-results": "Żaden wynik nie pasuje do tej kwerendy.",
@@ -44,6 +48,7 @@
44
48
  "results.empty-state.outdated": "Wyniki są nieaktualne. Kliknij poniżej, aby zaktualizować.",
45
49
  "results.empty-state.uninitialized": "Tu zostaną wyświetlone słowa wygenerowane z Twoich liter.",
46
50
  "results.input.placeholder": "Szukaj rozwiązania... (RegExp)",
51
+ "results.insert": "Wstaw",
47
52
  "results.solve": "Rozwiąż",
48
53
  "settings": "Opcje",
49
54
  "settings.autoGroupTiles": "Grupuj pozostałe płytki",
@@ -1,4 +1,4 @@
1
1
  <!-- https://icons.getbootstrap.com/icons/arrow-down/ -->
2
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
- <path d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z" fill="currentColor" fill-rule="evenodd" />
3
+ <path d="M8 1a.5.5 0 0 1 .5.5v11.793l3.146-3.147a.5.5 0 0 1 .708.708l-4 4a.5.5 0 0 1-.708 0l-4-4a.5.5 0 0 1 .708-.708L7.5 13.293V1.5A.5.5 0 0 1 8 1z" fill="currentColor" />
4
4
  </svg>
@@ -1,4 +1,4 @@
1
1
  <!-- https://icons.getbootstrap.com/icons/arrow-left/ -->
2
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
- <path d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z" fill="currentColor" fill-rule="evenodd" />
3
+ <path d="M15 8a.5.5 0 0 0-.5-.5H2.707l3.147-3.146a.5.5 0 1 0-.708-.708l-4 4a.5.5 0 0 0 0 .708l4 4a.5.5 0 0 0 .708-.708L2.707 8.5H14.5A.5.5 0 0 0 15 8z" fill="currentColor" />
4
4
  </svg>
@@ -1,4 +1,4 @@
1
1
  <!-- https://icons.getbootstrap.com/icons/arrow-right/ -->
2
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
- <path d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z" fill="currentColor" fill-rule="evenodd" />
3
+ <path d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z" fill="currentColor" />
4
4
  </svg>
@@ -1,4 +1,4 @@
1
1
  <!-- https://icons.getbootstrap.com/icons/arrow-up/ -->
2
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
- <path d="M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5z" fill="currentColor" fill-rule="evenodd" />
3
+ <path d="M8 15a.5.5 0 0 0 .5-.5V2.707l3.146 3.147a.5.5 0 0 0 .708-.708l-4-4a.5.5 0 0 0-.708 0l-4 4a.5.5 0 1 0 .708.708L7.5 2.707V14.5a.5.5 0 0 0 .5.5z" fill="currentColor" />
4
4
  </svg>
@@ -1,4 +1,4 @@
1
1
  <!-- https://icons.getbootstrap.com/icons/chevron-down/ -->
2
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
- <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" fill="currentColor" />
3
+ <path d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z" fill="currentColor" />
4
4
  </svg>
@@ -0,0 +1,4 @@
1
+ <!-- https://icons.getbootstrap.com/icons/chevron-left/ -->
2
+ <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z" fill="currentColor" />
4
+ </svg>
@@ -0,0 +1,4 @@
1
+ <!-- https://icons.getbootstrap.com/icons/chevron-right/ -->
2
+ <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z" fill="currentColor" />
4
+ </svg>
@@ -1,4 +1,4 @@
1
1
  <!-- https://icons.getbootstrap.com/icons/list/ -->
2
2
  <svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" >
3
- <path fill-rule="evenodd" d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z" fill="currentColor" />
3
+ <path d="M2.5 12a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5z" fill="currentColor" />
4
4
  </svg>
@@ -8,6 +8,8 @@ export { default as Check } from './Check.svg';
8
8
  export { default as CheckboxChecked } from './CheckboxChecked.svg';
9
9
  export { default as CheckboxEmpty } from './CheckboxEmpty.svg';
10
10
  export { default as ChevronDown } from './ChevronDown.svg';
11
+ export { default as ChevronLeft } from './ChevronLeft.svg';
12
+ export { default as ChevronRight } from './ChevronRight.svg';
11
13
  export { default as Cog } from './Cog.svg';
12
14
  export { default as Cross } from './Cross.svg';
13
15
  export { default as CrossCircleFill } from './CrossCircleFill.svg';
@@ -2,10 +2,9 @@
2
2
 
3
3
  .button {
4
4
  width: 100%;
5
- margin-bottom: var(--spacing--m);
6
5
  text-transform: none;
7
6
 
8
- &:last-child {
9
- margin-bottom: 0;
7
+ & + & {
8
+ margin-top: var(--spacing--l);
10
9
  }
11
10
  }
@@ -28,15 +28,21 @@ const Menu: FunctionComponent<Props> = ({
28
28
 
29
29
  return (
30
30
  <Modal className={className} isOpen={isOpen} title={translate('menu')} onClose={onClose}>
31
- <Button className={styles.button} Icon={Sack} onClick={onShowRemainingTiles}>
31
+ <Button
32
+ aria-label={translate('remaining-tiles')}
33
+ className={styles.button}
34
+ Icon={Sack}
35
+ onClick={onShowRemainingTiles}
36
+ >
32
37
  {translate('remaining-tiles')}
33
38
  </Button>
34
39
 
35
- <Button className={styles.button} Icon={CardChecklist} onClick={onShowWords}>
40
+ <Button aria-label={translate('words')} className={styles.button} Icon={CardChecklist} onClick={onShowWords}>
36
41
  {translate('words')}
37
42
  </Button>
38
43
 
39
44
  <Button.Link
45
+ aria-label={translate('github')}
40
46
  className={styles.button}
41
47
  href={GITHUB_PROJECT_URL}
42
48
  Icon={Github}
@@ -46,7 +52,7 @@ const Menu: FunctionComponent<Props> = ({
46
52
  {translate('github')}
47
53
  </Button.Link>
48
54
 
49
- <Button className={styles.button} Icon={Cog} onClick={onShowSettings}>
55
+ <Button aria-label={translate('settings')} className={styles.button} Icon={Cog} onClick={onShowSettings}>
50
56
  {translate('settings')}
51
57
  </Button>
52
58
  </Modal>
@@ -31,6 +31,7 @@ const Character: FunctionComponent<Props> = ({ tile }) => {
31
31
  })}
32
32
  >
33
33
  <Tile
34
+ aria-label={character}
34
35
  character={character}
35
36
  className={styles.tile}
36
37
  disabled
@@ -40,12 +40,12 @@ const AutoGroupTilesSetting: FunctionComponent<Props> = ({ className, disabled }
40
40
 
41
41
  return (
42
42
  <div className={className}>
43
- {options.map((option) => (
43
+ {options.map((option, index) => (
44
44
  <Radio
45
45
  checked={value === parseValue(option.value)}
46
46
  className={styles.option}
47
47
  disabled={disabled}
48
- id="autoGroupTiles"
48
+ id={`autoGroupTiles-${index}`}
49
49
  key={option.value}
50
50
  name="autoGroupTiles"
51
51
  value={option.value}
@@ -22,12 +22,12 @@ const ConfigSetting: FunctionComponent<Props> = ({ className, disabled }) => {
22
22
 
23
23
  return (
24
24
  <div className={className}>
25
- {options.map((option) => (
25
+ {options.map((option, index) => (
26
26
  <Radio
27
27
  checked={configId === option.value}
28
28
  className={styles.option}
29
29
  disabled={disabled}
30
- id="configId"
30
+ id={`configId-${index}`}
31
31
  key={option.value}
32
32
  name="configId"
33
33
  value={option.value}
@@ -25,14 +25,14 @@ const LocaleSetting: FunctionComponent<Props> = ({ className, disabled }) => {
25
25
 
26
26
  return (
27
27
  <div className={className}>
28
- {options.map(({ Icon, ...option }) => (
28
+ {options.map(({ Icon, ...option }, index) => (
29
29
  <Radio
30
30
  checked={locale === option.value}
31
31
  className={classNames(styles.option, className, {
32
32
  [styles.checked]: locale === option.value,
33
33
  })}
34
34
  disabled={disabled}
35
- id="locale"
35
+ id={`locale-${index}`}
36
36
  key={option.value}
37
37
  name="locale"
38
38
  value={option.value}
@@ -1,4 +1,5 @@
1
1
  import { scrabble } from '@scrabble-solver/configs';
2
+ import { COMMA_ARABIC, COMMA_LATIN } from '@scrabble-solver/constants';
2
3
  import { dictionaries } from '@scrabble-solver/dictionaries';
3
4
  import logger from '@scrabble-solver/logger';
4
5
  import { isLocale, Locale } from '@scrabble-solver/types';
@@ -54,7 +55,8 @@ const parseRequest = (request: NextApiRequest): RequestData => {
54
55
  const words = Array.from(
55
56
  new Set(
56
57
  word
57
- .split(',')
58
+ .replaceAll(COMMA_ARABIC, COMMA_LATIN)
59
+ .split(COMMA_LATIN)
58
60
  .map((part) => part.trim())
59
61
  .filter(Boolean),
60
62
  ),
@@ -38,6 +38,7 @@ const Index: FunctionComponent<Props> = ({ version }) => {
38
38
  const [navRef, { height: navHeight }] = useMeasure<HTMLDivElement>();
39
39
  const solverHeight = indexHeight - navHeight;
40
40
  const solverWidth = indexWidth;
41
+ const [isClient, setIsClient] = useState(false);
41
42
 
42
43
  const handleClear = () => {
43
44
  dispatch(reset());
@@ -55,6 +56,7 @@ const Index: FunctionComponent<Props> = ({ version }) => {
55
56
  useLocalStorage();
56
57
 
57
58
  useEffectOnce(() => {
59
+ setIsClient(true);
58
60
  dispatch(initialize());
59
61
 
60
62
  globalThis.setTimeout(() => {
@@ -98,12 +100,14 @@ const Index: FunctionComponent<Props> = ({ version }) => {
98
100
  </div>
99
101
  </div>
100
102
 
101
- <Solver
102
- className={styles.solver}
103
- height={solverHeight}
104
- width={solverWidth}
105
- onShowResults={() => setShowResults(true)}
106
- />
103
+ {isClient && (
104
+ <Solver
105
+ className={styles.solver}
106
+ height={solverHeight}
107
+ width={solverWidth}
108
+ onShowResults={() => setShowResults(true)}
109
+ />
110
+ )}
107
111
  </div>
108
112
 
109
113
  <MenuModal
@@ -1,5 +1,6 @@
1
1
  import { PayloadAction } from '@reduxjs/toolkit';
2
- import { Result } from '@scrabble-solver/types';
2
+ import { COMMA_ARABIC, COMMA_LATIN } from '@scrabble-solver/constants';
3
+ import { Locale, Result } from '@scrabble-solver/types';
3
4
  import { call, delay, put, select, takeEvery, takeLatest } from 'redux-saga/effects';
4
5
 
5
6
  import { memoize } from 'lib';
@@ -134,7 +135,9 @@ function* onLocaleChange(): AnyGenerator {
134
135
 
135
136
  function* onResultCandidateChange({ payload: result }: PayloadAction<Result | null>): AnyGenerator {
136
137
  if (result) {
137
- yield put(dictionarySlice.actions.changeInput(result.words.join(', ')));
138
+ const locale = yield select(selectLocale);
139
+ const comma = locale === Locale.FA_IR ? ` ${COMMA_ARABIC}` : `${COMMA_LATIN} `;
140
+ yield put(dictionarySlice.actions.changeInput(result.words.join(comma)));
138
141
  yield put(dictionarySlice.actions.submit());
139
142
  }
140
143
  }
@@ -9,14 +9,17 @@ const useTranslate = (): Translate => {
9
9
  const translations = useTypedSelector(selectTranslations);
10
10
  const locale = useTypedSelector(selectLocale);
11
11
  const translate: Translate = useCallback(
12
- (id) => {
12
+ (id, replacements = {}) => {
13
13
  const translation = translations[id];
14
14
 
15
15
  if (typeof translation === 'undefined') {
16
16
  throw new Error(`Untranslated key "${id}" in locale "${locale}"`);
17
17
  }
18
18
 
19
- return translation;
19
+ return Object.entries(replacements).reduce(
20
+ (result, [key, value]) => result.replaceAll(`{{${key}}}`, value),
21
+ translation,
22
+ );
20
23
  },
21
24
  [translations, locale],
22
25
  );
@@ -44,6 +44,12 @@ $media-expressions: (
44
44
  }
45
45
  }
46
46
 
47
+ @mixin disabled {
48
+ opacity: var(--opacity--disabled);
49
+ box-shadow: none;
50
+ cursor: not-allowed;
51
+ }
52
+
47
53
  @mixin ellipsis {
48
54
  display: block;
49
55
  text-overflow: ellipsis;
@@ -36,12 +36,15 @@ export type TranslationKey =
36
36
  | 'cell.set-blank'
37
37
  | 'cell.set-not-blank'
38
38
  | 'cell.toggle-direction'
39
+ | 'cell.tile.location'
39
40
  | 'common.clear'
40
41
  | 'common.close'
41
42
  | 'common.loading'
42
43
  | 'common.blanks'
43
44
  | 'common.consonants'
45
+ | 'common.next'
44
46
  | 'common.points'
47
+ | 'common.previous'
45
48
  | 'common.tiles'
46
49
  | 'common.two-letter-tiles'
47
50
  | 'common.vowels'
@@ -70,6 +73,7 @@ export type TranslationKey =
70
73
  | 'keyMap.rack.insert-blank'
71
74
  | 'menu'
72
75
  | 'rack.placeholder'
76
+ | 'rack.tile.location'
73
77
  | 'remaining-tiles'
74
78
  | 'results'
75
79
  | 'results.empty-state.no-filtered-results'
@@ -77,6 +81,7 @@ export type TranslationKey =
77
81
  | 'results.empty-state.outdated'
78
82
  | 'results.empty-state.uninitialized'
79
83
  | 'results.input.placeholder'
84
+ | 'results.insert'
80
85
  | 'results.solve'
81
86
  | 'settings'
82
87
  | 'settings.autoGroupTiles'
@@ -89,6 +94,6 @@ export type TranslationKey =
89
94
  | 'words.invalid'
90
95
  | 'words.valid';
91
96
 
92
- export type Translate = (key: TranslationKey) => string;
97
+ export type Translate = (key: TranslationKey, replacements?: Record<string, string>) => string;
93
98
 
94
99
  export type Translations = Record<TranslationKey, string>;