@scrabble-solver/scrabble-solver 2.11.7 → 2.11.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.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +7 -7
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/cache/eslint/.cache_8dgz12 +1 -1
- package/.next/cache/next-server.js.nft.json +1 -1
- package/.next/cache/webpack/client-production/0.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +1 -1
- package/.next/routes-manifest.json +1 -1
- package/.next/server/chunks/131.js +153 -115
- package/.next/server/chunks/277.js +1430 -691
- package/.next/server/chunks/44.js +3 -0
- package/.next/server/chunks/50.js +20 -78
- package/.next/server/chunks/865.js +153 -115
- package/.next/server/chunks/911.js +14 -14
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/404.js.nft.json +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages/_app.js +8 -0
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/api/solve.js +44 -11
- package/.next/server/pages/index.html +1 -1
- package/.next/server/pages/index.js +169 -15
- package/.next/server/pages/index.js.nft.json +1 -1
- package/.next/server/pages/index.json +1 -1
- package/.next/static/9oRWxnZ1xFLSs55FJtiYi/_buildManifest.js +1 -0
- package/.next/static/chunks/pages/{404-ca203fa27afc37d8.js → 404-b4b5ce15153d4825.js} +1 -1
- package/.next/static/chunks/pages/_app-b0231bed954dd413.js +28 -0
- package/.next/static/chunks/pages/index-4e8566409753e1c3.js +1 -0
- package/.next/static/css/60e8258da7362a1a.css +1 -0
- package/.next/static/css/fcc46fec97b11afc.css +2 -0
- package/.next/trace +52 -50
- package/package.json +14 -13
- package/src/components/Board/Board.module.scss +18 -4
- package/src/components/Board/Board.tsx +145 -76
- package/src/components/Board/BoardPure.tsx +32 -40
- package/src/components/Board/components/Actions/Actions.module.scss +6 -17
- package/src/components/Board/components/Actions/Actions.tsx +36 -18
- package/src/components/Board/components/Cell/Cell.module.scss +12 -13
- package/src/components/Board/components/Cell/Cell.tsx +53 -3
- package/src/components/Board/components/InputPrompt/InputPrompt.module.scss +47 -0
- package/src/components/Board/components/InputPrompt/InputPrompt.tsx +81 -0
- package/src/components/Board/components/InputPrompt/index.ts +1 -0
- package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.module.scss +21 -0
- package/src/components/Board/components/ToggleDirectionButton/ToggleDirectionButton.tsx +34 -0
- package/src/components/Board/components/ToggleDirectionButton/index.ts +1 -0
- package/src/components/Board/components/index.ts +2 -0
- package/src/components/Board/hooks/index.ts +4 -0
- package/src/components/Board/hooks/useBackgroundImage.tsx +13 -9
- package/src/components/Board/hooks/useBoardStyle.ts +27 -0
- package/src/components/Board/hooks/useFloatingActions.ts +22 -0
- package/src/components/Board/hooks/useFloatingFocus.ts +10 -0
- package/src/components/Board/hooks/useFloatingInputPrompt.ts +19 -0
- package/src/components/Board/hooks/useGrid.ts +19 -2
- package/src/components/Key/Key.module.scss +7 -11
- package/src/components/NavButtons/NavButtons.tsx +2 -2
- package/src/components/Rack/Rack.module.scss +6 -6
- package/src/components/Rack/Rack.tsx +102 -24
- package/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +22 -0
- package/src/components/Rack/components/InputPrompt/InputPrompt.tsx +89 -0
- package/src/components/Rack/components/InputPrompt/index.ts +1 -0
- package/src/components/Rack/components/RackTile/RackTile.module.scss +11 -0
- package/src/components/Rack/{RackTile.tsx → components/RackTile/RackTile.tsx} +59 -9
- package/src/components/Rack/components/RackTile/index.ts +1 -0
- package/src/components/Rack/components/index.ts +2 -0
- package/src/components/Radio/Radio.module.scss +0 -8
- package/src/components/Solver/Solver.module.scss +0 -20
- package/src/components/Solver/Solver.tsx +2 -4
- package/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.tsx +2 -10
- package/src/components/Solver/components/index.ts +0 -1
- package/src/components/Tile/Tile.module.scss +5 -0
- package/src/components/Tile/Tile.tsx +8 -6
- package/src/components/Tile/TilePure.tsx +8 -0
- package/src/hooks/useAppLayout.ts +3 -1
- package/src/hooks/useLocalStorage.ts +8 -0
- package/src/i18n/de.json +6 -1
- package/src/i18n/en.json +6 -1
- package/src/i18n/es.json +6 -1
- package/src/i18n/fa.json +6 -1
- package/src/i18n/fr.json +6 -1
- package/src/i18n/pl.json +6 -1
- package/src/icons/Keyboard.svg +4 -3
- package/src/icons/KeyboardFill.svg +4 -0
- package/src/icons/index.ts +1 -0
- package/src/lib/extractCharacters.test.ts +26 -0
- package/src/lib/extractCharacters.ts +11 -9
- package/src/lib/extractCharactersByCase.test.ts +31 -0
- package/src/lib/extractCharactersByCase.ts +31 -0
- package/src/lib/index.ts +4 -1
- package/src/lib/isCtrl.ts +7 -0
- package/src/lib/isUpperCase.ts +7 -0
- package/src/modals/KeyMapModal/KeyMapModal.tsx +20 -4
- package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +10 -4
- package/src/modals/SettingsModal/SettingsModal.tsx +5 -1
- package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.module.scss +12 -0
- package/src/modals/SettingsModal/components/InputModeSetting/InputModeSetting.tsx +55 -0
- package/src/modals/SettingsModal/components/InputModeSetting/index.ts +1 -0
- package/src/modals/SettingsModal/components/InputModeSetting/lib.ts +13 -0
- package/src/modals/SettingsModal/components/InputModeSetting/types.ts +7 -0
- package/src/modals/SettingsModal/components/index.ts +1 -0
- package/src/state/localStorage.ts +10 -1
- package/src/state/selectors.ts +2 -0
- package/src/state/slices/settingsInitialState.ts +4 -1
- package/src/state/slices/settingsSlice.ts +6 -1
- package/src/styles/mixins.scss +1 -0
- package/src/styles/variables.scss +2 -0
- package/src/types/index.ts +7 -0
- package/.next/static/chunks/pages/_app-e89a3c225b87516a.js +0 -28
- package/.next/static/chunks/pages/index-58744f49bf6b891f.js +0 -1
- package/.next/static/css/34adfcf12a7d9bb6.css +0 -1
- package/.next/static/css/edaeaa48321b4cf2.css +0 -2
- package/.next/static/uhB6d-q63uRC6RubwepLq/_buildManifest.js +0 -1
- package/src/components/Solver/components/FloatingSolveButton/FloatingSolveButton.module.scss +0 -7
- package/src/components/Solver/components/FloatingSolveButton/FloatingSolveButton.tsx +0 -53
- package/src/components/Solver/components/FloatingSolveButton/index.ts +0 -1
- /package/.next/static/{uhB6d-q63uRC6RubwepLq → 9oRWxnZ1xFLSs55FJtiYi}/_ssgManifest.js +0 -0
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
selectAutoGroupTiles,
|
|
6
6
|
selectBoard,
|
|
7
7
|
selectConfigId,
|
|
8
|
+
selectInputMode,
|
|
8
9
|
selectLocale,
|
|
9
10
|
selectRack,
|
|
10
11
|
useTypedSelector,
|
|
@@ -14,6 +15,7 @@ const useLocalStorage = () => {
|
|
|
14
15
|
const autoGroupTiles = useTypedSelector(selectAutoGroupTiles);
|
|
15
16
|
const board = useTypedSelector(selectBoard);
|
|
16
17
|
const configId = useTypedSelector(selectConfigId);
|
|
18
|
+
const inputMode = useTypedSelector(selectInputMode);
|
|
17
19
|
const locale = useTypedSelector(selectLocale);
|
|
18
20
|
const rack = useTypedSelector(selectRack);
|
|
19
21
|
|
|
@@ -35,6 +37,12 @@ const useLocalStorage = () => {
|
|
|
35
37
|
}
|
|
36
38
|
}, [configId]);
|
|
37
39
|
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (inputMode) {
|
|
42
|
+
localStorage.setInputMode(inputMode);
|
|
43
|
+
}
|
|
44
|
+
}, [inputMode]);
|
|
45
|
+
|
|
38
46
|
useEffect(() => {
|
|
39
47
|
if (locale) {
|
|
40
48
|
localStorage.setLocale(locale);
|
package/src/i18n/de.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"cell.enter-word": "Wort eingeben",
|
|
2
3
|
"cell.filter-cell": "Zielort",
|
|
3
4
|
"cell.set-blank": "Als Blanko markieren",
|
|
4
5
|
"cell.set-not-blank": "Nicht als Blanko markieren",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"dictionary.empty-state.no-results": "Wort kann nicht im Wörterbuch gefunden werden.",
|
|
23
24
|
"dictionary.empty-state.not-allowed": "Dieses Wort ist nicht erlaubt.",
|
|
24
25
|
"dictionary.empty-state.uninitialized": "Die Wörterbuchdéfinition wird hier angezeigt.",
|
|
25
|
-
"dictionary.input.placeholder": "Durchsuche Wörterbuch
|
|
26
|
+
"dictionary.input.placeholder": "Durchsuche Wörterbuch…",
|
|
26
27
|
"dictionary.input.title": "Durch Kommas getrennte Wörter",
|
|
27
28
|
"empty-state.error": "Fehler",
|
|
28
29
|
"empty-state.info": "Info",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"menu": "Menü",
|
|
44
45
|
"rack.placeholder": "Steine…",
|
|
45
46
|
"rack.tile.location": "Ablage: Stein ({{index}})",
|
|
47
|
+
"rack.touchscreen.placeholder": "Steine…",
|
|
46
48
|
"remaining-tiles": "Restliche Steine",
|
|
47
49
|
"results": "Ergebnisse",
|
|
48
50
|
"results.empty-state.no-results": "Keine Ergebnisse - kein Wort konnte generiert werden.",
|
|
@@ -58,6 +60,9 @@
|
|
|
58
60
|
"settings.autoGroupTiles.right": "Rechte Seite",
|
|
59
61
|
"settings.autoGroupTiles.null": "Nicht gruppieren",
|
|
60
62
|
"settings.game": "Spiel",
|
|
63
|
+
"settings.inputMode": "Eingabemodus",
|
|
64
|
+
"settings.inputMode.keyboard": "Tastatur",
|
|
65
|
+
"settings.inputMode.touchscreen": "Touchscreen",
|
|
61
66
|
"settings.language": "Sprache",
|
|
62
67
|
"words": "Gebildete Wörter",
|
|
63
68
|
"words.invalid": "Falsch",
|
package/src/i18n/en.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"cell.enter-word": "Enter word",
|
|
2
3
|
"cell.filter-cell": "Target destination",
|
|
3
4
|
"cell.set-blank": "Mark it a blank",
|
|
4
5
|
"cell.set-not-blank": "Mark it not a blank",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"dictionary.empty-state.no-results": "Unable to find word definition in the dictionary.",
|
|
23
24
|
"dictionary.empty-state.not-allowed": "This word is not allowed.",
|
|
24
25
|
"dictionary.empty-state.uninitialized": "Word definition will be shown here.",
|
|
25
|
-
"dictionary.input.placeholder": "Search dictionary
|
|
26
|
+
"dictionary.input.placeholder": "Search dictionary…",
|
|
26
27
|
"dictionary.input.title": "Comma-separated words",
|
|
27
28
|
"empty-state.error": "Error",
|
|
28
29
|
"empty-state.info": "Info",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"menu": "Menu",
|
|
44
45
|
"rack.placeholder": "Letters",
|
|
45
46
|
"rack.tile.location": "Rack: tile ({{index}})",
|
|
47
|
+
"rack.touchscreen.placeholder": "Letters…",
|
|
46
48
|
"remaining-tiles": "Remaining tiles",
|
|
47
49
|
"results": "Results",
|
|
48
50
|
"results.empty-state.no-results": "No results - unable to generate any words.",
|
|
@@ -58,6 +60,9 @@
|
|
|
58
60
|
"settings.autoGroupTiles.right": "On the right",
|
|
59
61
|
"settings.autoGroupTiles.null": "Do not group",
|
|
60
62
|
"settings.game": "Game",
|
|
63
|
+
"settings.inputMode": "Input mode",
|
|
64
|
+
"settings.inputMode.keyboard": "Keyboard",
|
|
65
|
+
"settings.inputMode.touchscreen": "Touchscreen",
|
|
61
66
|
"settings.language": "Language",
|
|
62
67
|
"words": "Created words",
|
|
63
68
|
"words.invalid": "Invalid",
|
package/src/i18n/es.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"cell.enter-word": "Ingresar palabra",
|
|
2
3
|
"cell.filter-cell": "Destino objetivo",
|
|
3
4
|
"cell.set-blank": "Marcar como en blanco",
|
|
4
5
|
"cell.set-not-blank": "Marcar como no en blanco",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"dictionary.empty-state.no-results": "No se puede encontrar la definición de palabra en el diccionario.",
|
|
23
24
|
"dictionary.empty-state.not-allowed": "Esta palabra no es aceptable.",
|
|
24
25
|
"dictionary.empty-state.uninitialized": "Aquí se mostrará la definición del diccionario.",
|
|
25
|
-
"dictionary.input.placeholder": "Busca el diccionario
|
|
26
|
+
"dictionary.input.placeholder": "Busca el diccionario…",
|
|
26
27
|
"dictionary.input.title": "Palabras separadas por comas",
|
|
27
28
|
"empty-state.error": "Error",
|
|
28
29
|
"empty-state.info": "Info",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"menu": "Menú",
|
|
44
45
|
"rack.placeholder": "Letras…",
|
|
45
46
|
"rack.tile.location": "Estante: espacio ({{index}})",
|
|
47
|
+
"rack.touchscreen.placeholder": "Letras… (p.ej. LLabcCHhRR)",
|
|
46
48
|
"remaining-tiles": "Casillas restantes",
|
|
47
49
|
"results": "Resultados",
|
|
48
50
|
"results.empty-state.no-results": "No hay resultados; no se pueden generar palabras",
|
|
@@ -58,6 +60,9 @@
|
|
|
58
60
|
"settings.autoGroupTiles.right": "A la derecha",
|
|
59
61
|
"settings.autoGroupTiles.null": "No agrupar",
|
|
60
62
|
"settings.game": "Juego",
|
|
63
|
+
"settings.inputMode": "Modo de entrada",
|
|
64
|
+
"settings.inputMode.keyboard": "Teclado",
|
|
65
|
+
"settings.inputMode.touchscreen": "Pantalla táctil",
|
|
61
66
|
"settings.language": "Idioma",
|
|
62
67
|
"words": "Palabras creadas",
|
|
63
68
|
"words.invalid": "Incorrecto",
|
package/src/i18n/fa.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"cell.enter-word": "کلمه را وارد کنید",
|
|
2
3
|
"cell.filter-cell": "مقصد",
|
|
3
4
|
"cell.set-blank": "علامت گذاری به عنوان خالی",
|
|
4
5
|
"cell.set-not-blank": "علامت گذاری به عنوان غیر خالی",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"dictionary.empty-state.no-results": "کلمه در فرهنگ لغت یافت نشد.",
|
|
23
24
|
"dictionary.empty-state.not-allowed": "این کلمه مجاز نیست.",
|
|
24
25
|
"dictionary.empty-state.uninitialized": "معنی لغت اینجا نمایش داده خواهد شد.",
|
|
25
|
-
"dictionary.input.placeholder": "جستجو در فرهنگ لغت
|
|
26
|
+
"dictionary.input.placeholder": "جستجو در فرهنگ لغت …",
|
|
26
27
|
"dictionary.input.title": "کلمات جدا شده با کاما",
|
|
27
28
|
"empty-state.error": "خطا",
|
|
28
29
|
"empty-state.info": "اطلاعات",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"menu": "منو",
|
|
44
45
|
"rack.placeholder": "لیستحرف",
|
|
45
46
|
"rack.tile.location": "({{index}}) کاشی: طاقچه",
|
|
47
|
+
"rack.touchscreen.placeholder": "لیستحرف…",
|
|
46
48
|
"remaining-tiles": "کاشی های باقی مانده",
|
|
47
49
|
"results": "نتایج",
|
|
48
50
|
"results.empty-state.no-results": "کلمه قابل استفاده پیدا نشد.",
|
|
@@ -58,6 +60,9 @@
|
|
|
58
60
|
"settings.autoGroupTiles.right": "در سمت راست",
|
|
59
61
|
"settings.autoGroupTiles.null": "کنار هم قرار نده",
|
|
60
62
|
"settings.game": "بازی",
|
|
63
|
+
"settings.inputMode": "حالت ورودی",
|
|
64
|
+
"settings.inputMode.keyboard": "صفحه کلید",
|
|
65
|
+
"settings.inputMode.touchscreen": "صفحه لمسی",
|
|
61
66
|
"settings.language": "زبان",
|
|
62
67
|
"words": "کلمات ساخته شده",
|
|
63
68
|
"words.invalid": "نا معتبر",
|
package/src/i18n/fr.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"cell.enter-word": "Entrez un mot",
|
|
2
3
|
"cell.filter-cell": "Destination cible",
|
|
3
4
|
"cell.set-blank": "Marquer comme vide",
|
|
4
5
|
"cell.set-not-blank": "Marquer comme non vide",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"dictionary.empty-state.no-results": "Impossible de trouver une définition pour ce mot dans le dictionaire.",
|
|
23
24
|
"dictionary.empty-state.not-allowed": "Ce mot n'est pas pas acceptable.",
|
|
24
25
|
"dictionary.empty-state.uninitialized": "La définition dictionaire sera affichée ici.",
|
|
25
|
-
"dictionary.input.placeholder": "Rechercher dans le dictionnaire
|
|
26
|
+
"dictionary.input.placeholder": "Rechercher dans le dictionnaire…",
|
|
26
27
|
"dictionary.input.title": "Mots séparées par des virgules",
|
|
27
28
|
"empty-state.error": "Erreur",
|
|
28
29
|
"empty-state.info": "Info",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"menu": "Menu",
|
|
44
45
|
"rack.placeholder": "Lettres",
|
|
45
46
|
"rack.tile.location": "Chevalet: la case ({{index}})",
|
|
47
|
+
"rack.touchscreen.placeholder": "Lettres…",
|
|
46
48
|
"remaining-tiles": "Cases restantes",
|
|
47
49
|
"results": "Résultats",
|
|
48
50
|
"results.empty-state.no-results": "Pas de résultats - impossible de générer des mots.",
|
|
@@ -58,6 +60,9 @@
|
|
|
58
60
|
"settings.autoGroupTiles.right": "Vers la gauche",
|
|
59
61
|
"settings.autoGroupTiles.null": "Ne pas grouper",
|
|
60
62
|
"settings.game": "Jeu",
|
|
63
|
+
"settings.inputMode": "Mode de saisie",
|
|
64
|
+
"settings.inputMode.keyboard": "Clavier",
|
|
65
|
+
"settings.inputMode.touchscreen": "Écran tactile",
|
|
61
66
|
"settings.language": "Langue",
|
|
62
67
|
"words": "Mots créés",
|
|
63
68
|
"words.invalid": "Incorrect",
|
package/src/i18n/pl.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
+
"cell.enter-word": "Wprowadź słowo",
|
|
2
3
|
"cell.filter-cell": "Miejsce docelowe",
|
|
3
4
|
"cell.set-blank": "Oznacz jako blank",
|
|
4
5
|
"cell.set-not-blank": "Oznacz jako nie blank",
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
"dictionary.empty-state.no-results": "Nie udało się znaleźć definicji słowa w słowniku.",
|
|
23
24
|
"dictionary.empty-state.not-allowed": "To słowo nie jest dopuszczalne w grach.",
|
|
24
25
|
"dictionary.empty-state.uninitialized": "Tu zostanie wyświetlona definicja słowa.",
|
|
25
|
-
"dictionary.input.placeholder": "Szukaj w słowniku
|
|
26
|
+
"dictionary.input.placeholder": "Szukaj w słowniku…",
|
|
26
27
|
"dictionary.input.title": "Słowa rozdzielone przecinkiem",
|
|
27
28
|
"empty-state.error": "Błąd",
|
|
28
29
|
"empty-state.info": "Info",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"menu": "Menu",
|
|
44
45
|
"rack.placeholder": "Literki",
|
|
45
46
|
"rack.tile.location": "Stojak: płytka ({{index}})",
|
|
47
|
+
"rack.touchscreen.placeholder": "Literki…",
|
|
46
48
|
"remaining-tiles": "Pozostałe płytki",
|
|
47
49
|
"results": "Wyniki",
|
|
48
50
|
"results.empty-state.no-results": "Brak wyników - nie można wygenerować żadnego słowa.",
|
|
@@ -58,6 +60,9 @@
|
|
|
58
60
|
"settings.autoGroupTiles.right": "Po prawej",
|
|
59
61
|
"settings.autoGroupTiles.null": "Nie grupuj",
|
|
60
62
|
"settings.game": "Gra",
|
|
63
|
+
"settings.inputMode": "Tryb wpisywania",
|
|
64
|
+
"settings.inputMode.keyboard": "Klawiatura",
|
|
65
|
+
"settings.inputMode.touchscreen": "Ekran dotykowy",
|
|
61
66
|
"settings.language": "Język",
|
|
62
67
|
"words": "Utworzone słowa",
|
|
63
68
|
"words.invalid": "Niepoprawne",
|
package/src/icons/Keyboard.svg
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<!-- https://icons.getbootstrap.com/icons/keyboard
|
|
2
|
-
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
-
<path d="
|
|
1
|
+
<!-- https://icons.getbootstrap.com/icons/keyboard/ -->
|
|
2
|
+
<svg fill="currentColor" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path d="M14 5a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h12zM2 4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H2z" />
|
|
4
|
+
<path d="M13 10.25a.25.25 0 0 1 .25-.25h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5a.25.25 0 0 1-.25-.25v-.5zm0-2a.25.25 0 0 1 .25-.25h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5a.25.25 0 0 1-.25-.25v-.5zm-5 0A.25.25 0 0 1 8.25 8h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 8 8.75v-.5zm2 0a.25.25 0 0 1 .25-.25h1.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-1.5a.25.25 0 0 1-.25-.25v-.5zm1 2a.25.25 0 0 1 .25-.25h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5a.25.25 0 0 1-.25-.25v-.5zm-5-2A.25.25 0 0 1 6.25 8h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 6 8.75v-.5zm-2 0A.25.25 0 0 1 4.25 8h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 4 8.75v-.5zm-2 0A.25.25 0 0 1 2.25 8h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 2 8.75v-.5zm11-2a.25.25 0 0 1 .25-.25h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5a.25.25 0 0 1-.25-.25v-.5zm-2 0a.25.25 0 0 1 .25-.25h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5a.25.25 0 0 1-.25-.25v-.5zm-2 0A.25.25 0 0 1 9.25 6h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 9 6.75v-.5zm-2 0A.25.25 0 0 1 7.25 6h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 7 6.75v-.5zm-2 0A.25.25 0 0 1 5.25 6h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5A.25.25 0 0 1 5 6.75v-.5zm-3 0A.25.25 0 0 1 2.25 6h1.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-1.5A.25.25 0 0 1 2 6.75v-.5zm0 4a.25.25 0 0 1 .25-.25h.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-.5a.25.25 0 0 1-.25-.25v-.5zm2 0a.25.25 0 0 1 .25-.25h5.5a.25.25 0 0 1 .25.25v.5a.25.25 0 0 1-.25.25h-5.5a.25.25 0 0 1-.25-.25v-.5z" />
|
|
4
5
|
</svg>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<!-- https://icons.getbootstrap.com/icons/keyboard-fill/ -->
|
|
2
|
+
<svg fill="currentColor" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path d="M0 6a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V6zm13 .25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25zM2.25 8a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h.5A.25.25 0 0 0 3 8.75v-.5A.25.25 0 0 0 2.75 8h-.5zM4 8.25v.5c0 .138.112.25.25.25h.5A.25.25 0 0 0 5 8.75v-.5A.25.25 0 0 0 4.75 8h-.5a.25.25 0 0 0-.25.25zM6.25 8a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h.5A.25.25 0 0 0 7 8.75v-.5A.25.25 0 0 0 6.75 8h-.5zM8 8.25v.5c0 .138.112.25.25.25h.5A.25.25 0 0 0 9 8.75v-.5A.25.25 0 0 0 8.75 8h-.5a.25.25 0 0 0-.25.25zM13.25 8a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-.5zm0 2a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-.5zm-3-2a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h1.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-1.5zm.75 2.25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25zM11.25 6a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-.5zM9 6.25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5A.25.25 0 0 0 9.75 6h-.5a.25.25 0 0 0-.25.25zM7.25 6a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h.5A.25.25 0 0 0 8 6.75v-.5A.25.25 0 0 0 7.75 6h-.5zM5 6.25v.5c0 .138.112.25.25.25h.5A.25.25 0 0 0 6 6.75v-.5A.25.25 0 0 0 5.75 6h-.5a.25.25 0 0 0-.25.25zM2.25 6a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h1.5A.25.25 0 0 0 4 6.75v-.5A.25.25 0 0 0 3.75 6h-1.5zM2 10.25v.5c0 .138.112.25.25.25h.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-.5a.25.25 0 0 0-.25.25zM4.25 10a.25.25 0 0 0-.25.25v.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.25.25 0 0 0-.25-.25h-5.5z" />
|
|
4
|
+
</svg>
|
package/src/icons/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ export { default as FlagUs } from './FlagUs.svg';
|
|
|
31
31
|
export { default as Github } from './Github.svg';
|
|
32
32
|
export { default as InfoCircleFill } from './InfoCircleFill.svg';
|
|
33
33
|
export { default as Keyboard } from './Keyboard.svg';
|
|
34
|
+
export { default as KeyboardFill } from './KeyboardFill.svg';
|
|
34
35
|
export { default as List } from './List.svg';
|
|
35
36
|
export { default as Sack } from './Sack.svg';
|
|
36
37
|
export { default as Search } from './Search.svg';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { scrabble } from '@scrabble-solver/configs';
|
|
2
|
+
import { BLANK } from '@scrabble-solver/constants';
|
|
3
|
+
import { Locale } from '@scrabble-solver/types';
|
|
4
|
+
|
|
5
|
+
import extractCharacters from './extractCharacters';
|
|
6
|
+
|
|
7
|
+
const tests = [
|
|
8
|
+
{ input: 'ab ', expected: ['a', 'b', BLANK] },
|
|
9
|
+
{ input: 'śćźa', expected: ['a'] },
|
|
10
|
+
{ input: 'bueno', expected: ['b', 'u', 'e', 'n', 'o'] },
|
|
11
|
+
{ input: 'bellas', expected: ['b', 'e', 'll', 'a', 's'] },
|
|
12
|
+
{ input: 'BELLAS', expected: ['b', 'e', 'll', 'a', 's'] },
|
|
13
|
+
{ input: 'churro', expected: ['ch', 'u', 'rr', 'o'] },
|
|
14
|
+
{ input: 'challulla', expected: ['ch', 'a', 'll', 'u', 'll', 'a'] },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe('extractCharacters', () => {
|
|
18
|
+
const locale = Locale.ES_ES;
|
|
19
|
+
const config = scrabble[locale];
|
|
20
|
+
|
|
21
|
+
for (const { input, expected } of tests) {
|
|
22
|
+
it(`[${locale}] "${input}"`, () => {
|
|
23
|
+
expect(extractCharacters(config, input)).toEqual(expected);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
@@ -4,20 +4,22 @@ import { Config } from '@scrabble-solver/types';
|
|
|
4
4
|
const extractCharacters = (config: Config, value: string): string[] => {
|
|
5
5
|
let index = 0;
|
|
6
6
|
const characters: string[] = [];
|
|
7
|
+
const valueLowercase = value.toLocaleLowerCase(config.locale);
|
|
7
8
|
|
|
8
|
-
while (index <
|
|
9
|
-
const character =
|
|
10
|
-
const nextCharacter =
|
|
11
|
-
const
|
|
9
|
+
while (index < valueLowercase.length) {
|
|
10
|
+
const character = valueLowercase[index];
|
|
11
|
+
const nextCharacter = valueLowercase[index + 1];
|
|
12
|
+
const digraph = `${character}${nextCharacter}`;
|
|
12
13
|
|
|
13
|
-
if (config.twoCharacterTiles.includes(
|
|
14
|
-
characters.push(
|
|
15
|
-
|
|
14
|
+
if (config.twoCharacterTiles.includes(digraph)) {
|
|
15
|
+
characters.push(digraph);
|
|
16
|
+
index += digraph.length;
|
|
16
17
|
} else if (config.hasCharacter(character) || character === BLANK) {
|
|
17
18
|
characters.push(character);
|
|
19
|
+
++index;
|
|
20
|
+
} else {
|
|
21
|
+
++index;
|
|
18
22
|
}
|
|
19
|
-
|
|
20
|
-
++index;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
return characters;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { scrabble } from '@scrabble-solver/configs';
|
|
2
|
+
import { BLANK } from '@scrabble-solver/constants';
|
|
3
|
+
import { Locale } from '@scrabble-solver/types';
|
|
4
|
+
|
|
5
|
+
import extractCharactersByCase from './extractCharactersByCase';
|
|
6
|
+
|
|
7
|
+
const tests = [
|
|
8
|
+
{ input: 'ab ', expected: ['a', 'b', BLANK] },
|
|
9
|
+
{ input: 'śćźa', expected: ['a'] },
|
|
10
|
+
{ input: 'bueno', expected: ['b', 'u', 'e', 'n', 'o'] },
|
|
11
|
+
{ input: 'bellas', expected: ['b', 'e', 'l', 'l', 'a', 's'] },
|
|
12
|
+
{ input: 'churro', expected: ['c', 'h', 'u', 'r', 'r', 'o'] },
|
|
13
|
+
{ input: 'challulla', expected: ['c', 'h', 'a', 'l', 'l', 'u', 'l', 'l', 'a'] },
|
|
14
|
+
{ input: 'beLlas', expected: ['b', 'e', 'l', 'l', 'a', 's'] },
|
|
15
|
+
{ input: 'belLas', expected: ['b', 'e', 'l', 'l', 'a', 's'] },
|
|
16
|
+
{ input: 'beLLas', expected: ['b', 'e', 'll', 'a', 's'] },
|
|
17
|
+
{ input: 'chuRRo', expected: ['c', 'h', 'u', 'rr', 'o'] },
|
|
18
|
+
{ input: 'CHuRRo', expected: ['ch', 'u', 'rr', 'o'] },
|
|
19
|
+
{ input: 'CHaLLuLLa', expected: ['ch', 'a', 'll', 'u', 'll', 'a'] },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
describe('extractCharactersByCase', () => {
|
|
23
|
+
const locale = Locale.ES_ES;
|
|
24
|
+
const config = scrabble[locale];
|
|
25
|
+
|
|
26
|
+
for (const { input, expected } of tests) {
|
|
27
|
+
it(`[${locale}] "${input}"`, () => {
|
|
28
|
+
expect(extractCharactersByCase(config, input)).toEqual(expected);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { BLANK } from '@scrabble-solver/constants';
|
|
2
|
+
import { Config } from '@scrabble-solver/types';
|
|
3
|
+
|
|
4
|
+
import isUpperCase from './isUpperCase';
|
|
5
|
+
|
|
6
|
+
const extractCharactersByCase = (config: Config, value: string): string[] => {
|
|
7
|
+
let index = 0;
|
|
8
|
+
const characters: string[] = [];
|
|
9
|
+
|
|
10
|
+
while (index < value.length) {
|
|
11
|
+
const character = value[index];
|
|
12
|
+
const characterLowercase = value[index].toLocaleLowerCase(config.locale);
|
|
13
|
+
const nextCharacter = value[index + 1];
|
|
14
|
+
const digraph = `${character}${nextCharacter}`;
|
|
15
|
+
const digraphLowercase = digraph.toLocaleLowerCase(config.locale);
|
|
16
|
+
|
|
17
|
+
if (isUpperCase(config.locale, digraph) && config.twoCharacterTiles.includes(digraphLowercase)) {
|
|
18
|
+
characters.push(digraphLowercase);
|
|
19
|
+
index += digraphLowercase.length;
|
|
20
|
+
} else if (config.hasCharacter(characterLowercase) || characterLowercase === BLANK) {
|
|
21
|
+
characters.push(characterLowercase);
|
|
22
|
+
++index;
|
|
23
|
+
} else {
|
|
24
|
+
++index;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return characters;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export default extractCharactersByCase;
|
package/src/lib/index.ts
CHANGED
|
@@ -3,14 +3,15 @@ export { default as canUseDom } from './canUseDom';
|
|
|
3
3
|
export { default as createArray } from './createArray';
|
|
4
4
|
export { default as createComparator } from './createComparator';
|
|
5
5
|
export { default as createGridOf } from './createGridOf';
|
|
6
|
-
export { default as createKeyboardNavigation } from './createKeyboardNavigation';
|
|
7
6
|
export { default as createKeyComparator } from './createKeyComparator';
|
|
7
|
+
export { default as createKeyboardNavigation } from './createKeyboardNavigation';
|
|
8
8
|
export { default as createNullMovingComparator } from './createNullMovingComparator';
|
|
9
9
|
export { default as createRegExp } from './createRegExp';
|
|
10
10
|
export { default as createStringComparator } from './createStringComparator';
|
|
11
11
|
export { default as dataUrlToBlob } from './dataUrlToBlob';
|
|
12
12
|
export { default as detectLocale } from './detectLocale';
|
|
13
13
|
export { default as extractCharacters } from './extractCharacters';
|
|
14
|
+
export { default as extractCharactersByCase } from './extractCharactersByCase';
|
|
14
15
|
export { default as extractInputValue } from './extractInputValue';
|
|
15
16
|
export { default as findCell } from './findCell';
|
|
16
17
|
export { default as getCellSize } from './getCellSize';
|
|
@@ -22,9 +23,11 @@ export { default as getTotalRemainingTilesCount } from './getTotalRemainingTiles
|
|
|
22
23
|
export { default as groupResults } from './groupResults';
|
|
23
24
|
export { default as guessLocale } from './guessLocale';
|
|
24
25
|
export { default as inverseDirection } from './inverseDirection';
|
|
26
|
+
export { default as isCtrl } from './isCtrl';
|
|
25
27
|
export { default as isMac } from './isMac';
|
|
26
28
|
export { default as isRegExp } from './isRegExp';
|
|
27
29
|
export { default as isStringArray } from './isStringArray';
|
|
30
|
+
export { default as isUpperCase } from './isUpperCase';
|
|
28
31
|
export { default as memoize } from './memoize';
|
|
29
32
|
export { default as noop } from './noop';
|
|
30
33
|
export { default as numberComparator } from './numberComparator';
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { FunctionComponent, memo } from 'react';
|
|
2
2
|
|
|
3
|
-
import { Modal } from 'components';
|
|
4
|
-
import { useTranslate } from 'state';
|
|
3
|
+
import { Key, Modal } from 'components';
|
|
4
|
+
import { selectConfig, useTranslate, useTypedSelector } from 'state';
|
|
5
5
|
|
|
6
6
|
import { Mapping } from './components';
|
|
7
|
-
import { ARROWS, BACKSPACE, DEL, ENTER, SPACE } from './keys';
|
|
7
|
+
import { ARROWS, BACKSPACE, CTRL, DEL, ENTER, SPACE } from './keys';
|
|
8
8
|
|
|
9
9
|
interface Props {
|
|
10
10
|
className?: string;
|
|
@@ -14,6 +14,7 @@ interface Props {
|
|
|
14
14
|
|
|
15
15
|
const KeyMapModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
|
|
16
16
|
const translate = useTranslate();
|
|
17
|
+
const config = useTypedSelector(selectConfig);
|
|
17
18
|
|
|
18
19
|
return (
|
|
19
20
|
<Modal className={className} isOpen={isOpen} title={translate('keyMap')} onClose={onClose}>
|
|
@@ -21,10 +22,25 @@ const KeyMapModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) =
|
|
|
21
22
|
<Mapping description={translate('keyMap.board-and-rack.navigate')} mapping={[ARROWS]} />
|
|
22
23
|
<Mapping description={translate('keyMap.board-and-rack.remove-tile')} mapping={[DEL, BACKSPACE]} />
|
|
23
24
|
<Mapping description={translate('keyMap.board-and-rack.submit')} mapping={[ENTER]} />
|
|
25
|
+
{config.twoCharacterTiles.length > 0 && (
|
|
26
|
+
<Mapping
|
|
27
|
+
description={translate('keyMap.board-and-rack.insert-two-letter-tile')}
|
|
28
|
+
mapping={[
|
|
29
|
+
[
|
|
30
|
+
CTRL,
|
|
31
|
+
<>
|
|
32
|
+
{config.twoCharacterTiles.map(([firstLetter]) => (
|
|
33
|
+
<Key key={firstLetter}>{firstLetter.toUpperCase()}</Key>
|
|
34
|
+
))}
|
|
35
|
+
</>,
|
|
36
|
+
],
|
|
37
|
+
]}
|
|
38
|
+
/>
|
|
39
|
+
)}
|
|
24
40
|
</Modal.Section>
|
|
25
41
|
|
|
26
42
|
<Modal.Section title={translate('keyMap.board')}>
|
|
27
|
-
<Mapping description={translate('keyMap.board.toggle-blank')} mapping={[SPACE]} />
|
|
43
|
+
<Mapping description={translate('keyMap.board.toggle-blank')} mapping={[SPACE, [CTRL, <Key key="b">B</Key>]]} />
|
|
28
44
|
<Mapping description={translate('keyMap.board.toggle-direction')} mapping={[ARROWS]} />
|
|
29
45
|
</Modal.Section>
|
|
30
46
|
|
|
@@ -18,13 +18,19 @@
|
|
|
18
18
|
flex-wrap: wrap;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
.group
|
|
22
|
-
.plus {
|
|
21
|
+
.group {
|
|
23
22
|
margin: 0 var(--spacing--s);
|
|
24
23
|
}
|
|
25
24
|
|
|
26
|
-
.slash
|
|
27
|
-
|
|
25
|
+
.slash,
|
|
26
|
+
.plus {
|
|
27
|
+
min-width: var(--key--height);
|
|
28
|
+
height: var(--key--height);
|
|
29
|
+
padding: var(--spacing--s) var(--spacing--m);
|
|
30
|
+
font-family: var(--font--family--monospace);
|
|
31
|
+
line-height: calc(var(--key--height) - 2 * (var(--spacing--s) + var(--border--width)));
|
|
32
|
+
vertical-align: middle;
|
|
33
|
+
text-align: center;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
36
|
.group {
|
|
@@ -3,7 +3,7 @@ import { FunctionComponent, memo } from 'react';
|
|
|
3
3
|
import { Modal } from 'components';
|
|
4
4
|
import { useTranslate } from 'state';
|
|
5
5
|
|
|
6
|
-
import { AutoGroupTilesSetting, ConfigSetting, LocaleSetting } from './components';
|
|
6
|
+
import { AutoGroupTilesSetting, ConfigSetting, InputModeSetting, LocaleSetting } from './components';
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
9
9
|
className?: string;
|
|
@@ -24,6 +24,10 @@ const SettingsModal: FunctionComponent<Props> = ({ className, isOpen, onClose })
|
|
|
24
24
|
<LocaleSetting disabled={!isOpen} />
|
|
25
25
|
</Modal.Section>
|
|
26
26
|
|
|
27
|
+
<Modal.Section title={translate('settings.inputMode')}>
|
|
28
|
+
<InputModeSetting disabled={!isOpen} />
|
|
29
|
+
</Modal.Section>
|
|
30
|
+
|
|
27
31
|
<Modal.Section title={translate('settings.autoGroupTiles')}>
|
|
28
32
|
<AutoGroupTilesSetting disabled={!isOpen} />
|
|
29
33
|
</Modal.Section>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ChangeEvent, FunctionComponent } from 'react';
|
|
2
|
+
import { useDispatch } from 'react-redux';
|
|
3
|
+
|
|
4
|
+
import { Radio } from 'components';
|
|
5
|
+
import { selectInputMode, settingsSlice, useTranslate, useTypedSelector } from 'state';
|
|
6
|
+
|
|
7
|
+
import styles from './InputModeSetting.module.scss';
|
|
8
|
+
import { parseValue } from './lib';
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
className?: string;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const InputModeSetting: FunctionComponent<Props> = ({ className, disabled }) => {
|
|
16
|
+
const dispatch = useDispatch();
|
|
17
|
+
const translate = useTranslate();
|
|
18
|
+
const value = useTypedSelector(selectInputMode);
|
|
19
|
+
|
|
20
|
+
const options = [
|
|
21
|
+
{
|
|
22
|
+
label: translate('settings.inputMode.keyboard'),
|
|
23
|
+
value: 'keyboard',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: translate('settings.inputMode.touchscreen'),
|
|
27
|
+
value: 'touchscreen',
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
|
|
32
|
+
const inputMode = parseValue(event.target.value);
|
|
33
|
+
dispatch(settingsSlice.actions.changeInputMode(inputMode));
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className={className}>
|
|
38
|
+
{options.map((option) => (
|
|
39
|
+
<Radio
|
|
40
|
+
checked={value === option.value}
|
|
41
|
+
className={styles.option}
|
|
42
|
+
disabled={disabled}
|
|
43
|
+
key={option.value}
|
|
44
|
+
name="inputMode"
|
|
45
|
+
value={option.value}
|
|
46
|
+
onChange={handleChange}
|
|
47
|
+
>
|
|
48
|
+
<div className={styles.label}>{option.label}</div>
|
|
49
|
+
</Radio>
|
|
50
|
+
))}
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default InputModeSetting;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './InputModeSetting';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { InputMode } from 'types';
|
|
2
|
+
|
|
3
|
+
export const parseValue = (value: string): InputMode => {
|
|
4
|
+
if (value === 'keyboard') {
|
|
5
|
+
return 'keyboard';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (value === 'touchscreen') {
|
|
9
|
+
return 'touchscreen';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
throw new Error(`"${value}" is not valid. Should be "keyboard" or "touchscreen"`);
|
|
13
|
+
};
|