@scrabble-solver/scrabble-solver 2.11.0 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +7 -7
  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 +341 -459
  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 +0 -24
  21. package/.next/server/pages/_app.js.nft.json +1 -1
  22. package/.next/server/pages/_document.js.nft.json +1 -1
  23. package/.next/server/pages/api/solve.js +0 -1
  24. package/.next/server/pages/index.html +1 -1
  25. package/.next/server/pages/index.js +4 -52
  26. package/.next/server/pages/index.js.nft.json +1 -1
  27. package/.next/server/pages/index.json +1 -1
  28. package/.next/static/chunks/pages/{404-e0f30450e9920dc3.js → 404-448ba28510855455.js} +1 -1
  29. package/.next/static/chunks/pages/_app-270526803bc274eb.js +28 -0
  30. package/.next/static/chunks/pages/index-c6e7754ccf3532df.js +1 -0
  31. package/.next/static/css/ad39b36eab07e613.css +1 -0
  32. package/.next/static/css/e5803e581e4c0451.css +2 -0
  33. package/.next/static/esK8DG-6aS5V7QFRtR3YE/_buildManifest.js +1 -0
  34. package/.next/trace +53 -55
  35. package/package.json +9 -14
  36. package/src/components/{Solver/components/EmptyState/EmptyState.module.scss → Alert/Alert.module.scss} +11 -7
  37. package/src/components/{Solver/components/EmptyState/EmptyState.tsx → Alert/Alert.tsx} +8 -6
  38. package/src/components/Alert/index.ts +1 -0
  39. package/src/components/Board/Board.module.scss +55 -0
  40. package/src/components/Board/BoardPure.tsx +4 -0
  41. package/src/components/Board/components/Cell/Cell.module.scss +41 -0
  42. package/src/components/Board/components/Cell/Cell.tsx +12 -0
  43. package/src/components/Board/components/Cell/CellPure.tsx +12 -0
  44. package/src/components/Board/hooks/useGrid.ts +8 -24
  45. package/src/components/Dictionary/Dictionary.module.scss +4 -0
  46. package/src/components/DictionaryInput/DictionaryInput.module.scss +1 -0
  47. package/src/components/EmptyState/EmptyState.module.scss +2 -1
  48. package/src/components/EmptyState/EmptyState.tsx +1 -2
  49. package/src/components/Loading/Loading.module.scss +1 -1
  50. package/src/components/Logo/Logo.tsx +5 -0
  51. package/src/components/Modal/Modal.module.scss +2 -0
  52. package/src/components/PlainTiles/PlainTiles.module.scss +1 -1
  53. package/src/components/PlainTiles/Tile.tsx +3 -3
  54. package/src/components/Rack/Rack.module.scss +25 -0
  55. package/src/components/Rack/Rack.tsx +5 -4
  56. package/src/components/Rack/RackTile.tsx +6 -13
  57. package/src/components/Results/Results.module.scss +28 -0
  58. package/src/components/ResultsInput/ResultsInput.module.scss +1 -0
  59. package/src/components/Solver/Solver.module.scss +5 -4
  60. package/src/components/Solver/Solver.tsx +8 -7
  61. package/src/components/Solver/components/index.ts +0 -1
  62. package/src/components/Tile/Tile.module.scss +14 -2
  63. package/src/components/Tooltip/Tooltip.module.scss +1 -72
  64. package/src/components/Tooltip/useTooltip.tsx +25 -35
  65. package/src/components/index.ts +1 -0
  66. package/src/hooks/index.ts +0 -1
  67. package/src/lib/index.ts +0 -1
  68. package/src/modals/DictionaryModal/DictionaryModal.module.scss +6 -1
  69. package/src/modals/KeyMapModal/KeyMapModal.tsx +5 -21
  70. package/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +4 -0
  71. package/src/modals/RemainingTilesModal/components/Character/Character.module.scss +1 -0
  72. package/src/modals/ResultsModal/ResultsModal.module.scss +1 -0
  73. package/src/modals/SettingsModal/components/LocaleSetting/LocaleSetting.module.scss +2 -0
  74. package/src/modals/WordsModal/WordsModal.module.scss +8 -1
  75. package/src/state/createAppStore.ts +26 -10
  76. package/src/state/types.ts +20 -2
  77. package/src/styles/mixins.scss +22 -0
  78. package/src/styles/variables.scss +16 -1
  79. package/.next/static/45ye7793DY705HOcuK9lJ/_buildManifest.js +0 -1
  80. package/.next/static/chunks/pages/_app-d7acee5e526752d9.js +0 -28
  81. package/.next/static/chunks/pages/index-35d2c1c79a201ae2.js +0 -1
  82. package/.next/static/css/a48caa6f57de6e98.css +0 -1
  83. package/.next/static/css/c49bbe944ddd1b39.css +0 -2
  84. package/src/components/Solver/components/EmptyState/index.ts +0 -1
  85. package/src/components/Tooltip/constants.ts +0 -28
  86. package/src/hooks/useUniqueId.ts +0 -9
  87. package/src/lib/isCtrl.ts +0 -7
  88. package/src/state/rootReducer.ts +0 -25
  89. /package/.next/static/{45ye7793DY705HOcuK9lJ → esK8DG-6aS5V7QFRtR3YE}/_ssgManifest.js +0 -0
@@ -9,6 +9,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
9
9
  height: 100%;
10
10
  background: var(--color--background--element);
11
11
  border: var(--border);
12
+ border-radius: var(--border--radius);
12
13
  box-shadow: var(--box-shadow);
13
14
  font-family: var(--font--family--title);
14
15
  }
@@ -29,6 +30,9 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
29
30
  }
30
31
 
31
32
  .list {
33
+ @include scrollbars;
34
+
35
+ scrollbar-gutter: stable;
32
36
  transition: var(--transition);
33
37
 
34
38
  &.outdated {
@@ -44,6 +48,8 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
44
48
  justify-content: space-between;
45
49
  font-weight: 700;
46
50
  border-bottom: var(--border);
51
+ border-top-left-radius: inherit;
52
+ border-top-right-radius: inherit;
47
53
  }
48
54
 
49
55
  .headerButton {
@@ -60,6 +66,26 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
60
66
  background-color: var(--color--primary);
61
67
  color: var(--color--primary--opposite);
62
68
  }
69
+
70
+ &:first-child {
71
+ [dir='ltr'] & {
72
+ border-top-left-radius: inherit;
73
+ }
74
+
75
+ [dir='rtl'] & {
76
+ border-top-right-radius: inherit;
77
+ }
78
+ }
79
+
80
+ &:last-child {
81
+ [dir='ltr'] & {
82
+ border-top-right-radius: inherit;
83
+ }
84
+
85
+ [dir='rtl'] & {
86
+ border-top-left-radius: inherit;
87
+ }
88
+ }
63
89
  }
64
90
 
65
91
  .headerButtonLabel {
@@ -175,4 +201,6 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
175
201
 
176
202
  .input {
177
203
  border-top: var(--border);
204
+ border-bottom-left-radius: var(--border--radius);
205
+ border-bottom-right-radius: var(--border--radius);
178
206
  }
@@ -8,4 +8,5 @@
8
8
  @include text-input;
9
9
 
10
10
  border: none;
11
+ border-radius: inherit;
11
12
  }
@@ -70,16 +70,21 @@
70
70
  flex-direction: column;
71
71
  background-color: var(--color--background--element);
72
72
  border: var(--border);
73
+ border-radius: var(--border--radius);
73
74
  box-shadow: var(--box-shadow);
74
75
  }
75
76
 
76
77
  .dictionary {
77
78
  flex: 1;
78
79
  border-bottom: var(--border);
80
+ border-top-left-radius: var(--border--radius);
81
+ border-top-right-radius: var(--border--radius);
79
82
  }
80
83
 
81
84
  .dictionaryInput {
82
85
  flex: 0 0 auto;
86
+ border-bottom-left-radius: var(--border--radius);
87
+ border-bottom-right-radius: var(--border--radius);
83
88
  }
84
89
 
85
90
  .bottomContainer {
@@ -97,10 +102,6 @@
97
102
  min-width: 0;
98
103
  }
99
104
 
100
- .rack {
101
- border: var(--border);
102
- }
103
-
104
105
  .controls {
105
106
  width: 100%;
106
107
  }
@@ -19,13 +19,14 @@ import {
19
19
  useTypedSelector,
20
20
  } from 'state';
21
21
 
22
+ import Alert from '../Alert';
22
23
  import Board from '../Board';
23
24
  import Dictionary from '../Dictionary';
24
25
  import DictionaryInput from '../DictionaryInput';
25
26
  import Rack from '../Rack';
26
27
  import Results from '../Results';
27
28
 
28
- import { EmptyState, FloatingSolveButton, ResultCandidatePicker } from './components';
29
+ import { FloatingSolveButton, ResultCandidatePicker } from './components';
29
30
  import styles from './Solver.module.scss';
30
31
 
31
32
  interface Props {
@@ -111,7 +112,7 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
111
112
  <div className={classNames(styles.solver, className)}>
112
113
  <div className={styles.container}>
113
114
  <div className={styles.content}>
114
- <form id="a" className={styles.boardContainer} onSubmit={handleSubmit}>
115
+ <form className={styles.boardContainer} onSubmit={handleSubmit}>
115
116
  <Board cellSize={cellSizeSafe} className={styles.board} />
116
117
  <input className={styles.submitInput} tabIndex={-1} type="submit" />
117
118
  </form>
@@ -129,7 +130,7 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
129
130
 
130
131
  <div className={styles.bottomContainer} ref={bottomContainerRef}>
131
132
  <div className={styles.bottomContent}>
132
- <form id="b" onSubmit={handleSubmit}>
133
+ <form onSubmit={handleSubmit}>
133
134
  <Rack className={styles.rack} tileSize={tileSize} />
134
135
  <input className={styles.submitInput} tabIndex={-1} type="submit" />
135
136
  </form>
@@ -139,15 +140,15 @@ const Solver: FunctionComponent<Props> = ({ className, height, width, onShowResu
139
140
  <ResultCandidatePicker onResultClick={onShowResults} />
140
141
 
141
142
  {error && (
142
- <EmptyState className={styles.emptyState} variant="error">
143
+ <Alert className={styles.emptyState} variant="error">
143
144
  {error.message}
144
- </EmptyState>
145
+ </Alert>
145
146
  )}
146
147
 
147
148
  {allResults && allResults.length === 0 && !isOutdated && (
148
- <EmptyState className={styles.emptyState} variant="warning">
149
+ <Alert className={styles.emptyState} variant="warning">
149
150
  {translate('results.empty-state.no-results')}
150
- </EmptyState>
151
+ </Alert>
151
152
  )}
152
153
  </div>
153
154
  )}
@@ -1,4 +1,3 @@
1
- export { default as EmptyState } from './EmptyState';
2
1
  export { default as FloatingSolveButton } from './FloatingSolveButton';
3
2
  export { default as InsertButton } from './InsertButton';
4
3
  export { default as ResultCandidatePicker } from './ResultCandidatePicker';
@@ -5,6 +5,7 @@
5
5
 
6
6
  position: relative;
7
7
  transition: var(--transition);
8
+ border-radius: var(--border--radius);
8
9
 
9
10
  &.points1 {
10
11
  --background-color: var(--color--yellow);
@@ -85,6 +86,7 @@
85
86
  align-items: center;
86
87
  justify-content: center;
87
88
  background-color: var(--background-color);
89
+ border-radius: inherit;
88
90
  transition: var(--transition);
89
91
  pointer-events: none;
90
92
  user-select: none;
@@ -94,10 +96,18 @@
94
96
  }
95
97
 
96
98
  .raised & {
97
- box-shadow: inset -2px -2px 2px -1px rgba(34, 34, 34, 0.8);
99
+ --shadow--size: 2px;
100
+ --shadow--blur: 2px;
101
+ --shadow--spread: -1px;
102
+ --shadow--color: rgba(34, 34, 34, 0.8);
103
+
104
+ box-shadow: inset calc(-1 * var(--shadow--size)) calc(-1 * var(--shadow--size)) var(--shadow--blur)
105
+ var(--shadow--spread) var(--shadow--color);
98
106
 
99
107
  @include media('<xs') {
100
- box-shadow: inset -2px -2px 1px -1px rgba(34, 34, 34, 0.8);
108
+ --shadow--size: 1px;
109
+ --shadow--spread: 0;
110
+ --shadow--blur: 1px;
101
111
  }
102
112
  }
103
113
  }
@@ -146,10 +156,12 @@
146
156
  [dir='ltr'] & {
147
157
  top: 0;
148
158
  right: 0;
159
+ border-top-right-radius: inherit;
149
160
  }
150
161
 
151
162
  [dir='rtl'] & {
152
163
  bottom: 0;
153
164
  right: 0;
165
+ border-bottom-right-radius: inherit;
154
166
  }
155
167
  }
@@ -1,11 +1,3 @@
1
- $arrow-size: 4px;
2
-
3
- :export {
4
- ARROW_SIZE: $arrow-size;
5
- PREVENT_OVERFLOW: 10px;
6
- OFFSET: 2px;
7
- }
8
-
9
1
  .tooltip {
10
2
  padding: var(--spacing--s) var(--spacing--m);
11
3
  box-shadow: var(--box-shadow);
@@ -13,71 +5,8 @@ $arrow-size: 4px;
13
5
  background-color: var(--color--tooltip--background);
14
6
  color: var(--color--tooltip--foreground);
15
7
  z-index: var(--z-index--tooltip);
16
-
17
- &.top {
18
- .arrow {
19
- bottom: -$arrow-size;
20
-
21
- &::after {
22
- left: 0;
23
- bottom: 0;
24
- border-top-color: var(--color--tooltip--background);
25
- border-bottom: none;
26
- }
27
- }
28
- }
29
-
30
- &.right {
31
- .arrow {
32
- left: -$arrow-size;
33
-
34
- &::after {
35
- left: 0;
36
- top: 0;
37
- border-right-color: var(--color--tooltip--background);
38
- border-left: none;
39
- }
40
- }
41
- }
42
-
43
- &.bottom {
44
- .arrow {
45
- top: -$arrow-size;
46
-
47
- &::after {
48
- top: 0;
49
- left: 0;
50
- border-bottom-color: var(--color--tooltip--background);
51
- border-top: none;
52
- }
53
- }
54
- }
55
-
56
- &.left {
57
- .arrow {
58
- right: -$arrow-size;
59
-
60
- &::after {
61
- right: 0;
62
- top: 0;
63
- border-left-color: var(--color--tooltip--background);
64
- border-right: none;
65
- }
66
- }
67
- }
68
8
  }
69
9
 
70
10
  .arrow {
71
- position: absolute;
72
- width: 2 * $arrow-size;
73
- height: 2 * $arrow-size;
74
-
75
- &::after {
76
- content: ' ';
77
- position: absolute;
78
- height: 0;
79
- width: 0;
80
- pointer-events: none;
81
- border: $arrow-size solid transparent;
82
- }
11
+ fill: var(--color--tooltip--background);
83
12
  }
@@ -1,3 +1,4 @@
1
+ import { arrow, autoUpdate, flip, FloatingArrow, offset, shift, useFloating } from '@floating-ui/react';
1
2
  import classNames from 'classnames';
2
3
  import {
3
4
  FocusEvent,
@@ -6,16 +7,15 @@ import {
6
7
  MouseEventHandler,
7
8
  ReactNode,
8
9
  useCallback,
10
+ useId,
9
11
  useMemo,
12
+ useRef,
10
13
  useState,
11
14
  } from 'react';
12
- import { usePopper } from 'react-popper';
13
- import { useMountedState, useRafLoop } from 'react-use';
14
15
 
15
- import { useIsTouchDevice, usePortal, useUniqueId } from 'hooks';
16
+ import { useIsTouchDevice, usePortal } from 'hooks';
16
17
  import { noop } from 'lib';
17
18
 
18
- import { MODIFIERS } from './constants';
19
19
  import styles from './Tooltip.module.scss';
20
20
 
21
21
  interface Props {
@@ -36,29 +36,27 @@ interface TriggerProps {
36
36
  onMouseOver?: MouseEventHandler;
37
37
  }
38
38
 
39
+ const ARROW_SIZE = 7;
40
+ const ARROW_GAP = 3;
41
+ const PADDING = 10;
42
+
39
43
  // eslint-disable-next-line max-statements
40
44
  const useTooltip = (
41
45
  tooltip: ReactNode,
42
46
  { className, placement = 'top', onBlur = noop, onFocus = noop, onMouseOut = noop, onMouseOver = noop }: Props = {},
43
47
  ): TriggerProps => {
44
- const id = useUniqueId();
48
+ const id = useId();
45
49
  const isTouchDevice = useIsTouchDevice();
46
50
  const isEnabled = Boolean(tooltip) || tooltip === 0;
47
- const isMounted = useMountedState();
48
51
  const [isShown, setIsShown] = useState<boolean>(false);
49
- const [referenceElement, setReferenceElement] = useState<HTMLElement | null>(null);
50
- const [popperElement, setPopperElement] = useState<HTMLElement | null>(null);
51
- const [arrowElement, setArrowElement] = useState<HTMLElement | null>(null);
52
- const {
53
- attributes,
54
- styles: popperStyles,
55
- update,
56
- } = usePopper(referenceElement, popperElement, {
57
- modifiers: [{ name: 'arrow', options: { element: arrowElement } }, ...MODIFIERS],
52
+ const arrowRef = useRef(null);
53
+ const ariaAttributes = useMemo(() => (isShown ? { 'aria-describedby': id } : {}), [id, isShown]);
54
+
55
+ const { x, y, context, refs, strategy } = useFloating({
56
+ middleware: [flip(), shift({ padding: PADDING }), offset(ARROW_SIZE + ARROW_GAP), arrow({ element: arrowRef })],
58
57
  placement,
58
+ whileElementsMounted: autoUpdate,
59
59
  });
60
- const computedPlacement = attributes.popper ? attributes.popper['data-popper-placement'] : placement;
61
- const ariaAttributes = useMemo(() => (isShown ? { 'aria-describedby': id } : {}), [id, isShown]);
62
60
 
63
61
  const handleBlur = useCallback(
64
62
  (event: FocusEvent) => {
@@ -95,7 +93,7 @@ const useTooltip = (
95
93
  const mouseTriggerProps = useMemo(
96
94
  () => ({
97
95
  ...ariaAttributes,
98
- ref: setReferenceElement,
96
+ ref: refs.setReference,
99
97
  onBlur: handleBlur,
100
98
  onFocus: handleFocus,
101
99
  onMouseOut: handleMouseOut,
@@ -107,33 +105,25 @@ const useTooltip = (
107
105
  const touchTriggerProps = useMemo(
108
106
  () => ({
109
107
  ...ariaAttributes,
110
- ref: setReferenceElement,
108
+ ref: refs.setReference,
111
109
  }),
112
110
  [ariaAttributes],
113
111
  );
114
112
 
115
113
  const triggerProps = isTouchDevice ? touchTriggerProps : mouseTriggerProps;
116
114
 
117
- useRafLoop(() => {
118
- if (isMounted() && update) {
119
- update();
120
- }
121
- });
122
-
123
115
  usePortal(
124
116
  <div
125
- className={classNames(styles.tooltip, className, {
126
- [styles.top]: computedPlacement === 'top',
127
- [styles.right]: computedPlacement === 'right',
128
- [styles.bottom]: computedPlacement === 'bottom',
129
- [styles.left]: computedPlacement === 'left',
130
- })}
131
- ref={setPopperElement}
132
- style={popperStyles.popper}
133
- {...attributes.popper}
117
+ className={classNames(styles.tooltip, className)}
118
+ ref={refs.setFloating}
119
+ style={{
120
+ position: strategy,
121
+ top: y ?? 0,
122
+ left: x ?? 0,
123
+ }}
134
124
  >
135
125
  <div>{tooltip}</div>
136
- <div className={styles.arrow} ref={setArrowElement} style={popperStyles.arrow} />
126
+ <FloatingArrow className={styles.arrow} context={context} ref={arrowRef} />
137
127
  </div>,
138
128
  { disabled: !isEnabled || !isShown },
139
129
  );
@@ -1,3 +1,4 @@
1
+ export { default as Alert } from './Alert';
1
2
  export { default as Badge } from './Badge';
2
3
  export { default as Board } from './Board';
3
4
  export { default as Button } from './Button';
@@ -5,4 +5,3 @@ export { default as useLanguage } from './useLanguage';
5
5
  export { default as useLocalStorage } from './useLocalStorage';
6
6
  export { default as useMediaQuery } from './useMediaQuery';
7
7
  export { default as usePortal } from './usePortal';
8
- export { default as useUniqueId } from './useUniqueId';
package/src/lib/index.ts CHANGED
@@ -17,7 +17,6 @@ export { default as getRemainingTilesGroups } from './getRemainingTilesGroups';
17
17
  export { default as getTotalRemainingTilesCount } from './getTotalRemainingTilesCount';
18
18
  export { default as getTileSizes } from './getTileSizes';
19
19
  export { default as inverseDirection } from './inverseDirection';
20
- export { default as isCtrl } from './isCtrl';
21
20
  export { default as isMac } from './isMac';
22
21
  export { default as isRegExp } from './isRegExp';
23
22
  export { default as isStringArray } from './isStringArray';
@@ -4,15 +4,20 @@
4
4
  flex-direction: column;
5
5
  background-color: var(--color--background--element);
6
6
  border: var(--border);
7
+ border-radius: var(--border--radius);
7
8
  box-shadow: var(--box-shadow);
8
9
  }
9
10
 
10
11
  .dictionary {
11
12
  flex: 1;
12
- border-bottom: var(--border);
13
13
  max-height: initial;
14
+ border-bottom: var(--border);
15
+ border-top-left-radius: var(--border--radius);
16
+ border-top-right-radius: var(--border--radius);
14
17
  }
15
18
 
16
19
  .dictionaryInput {
17
20
  flex: 0 0 auto;
21
+ border-bottom-left-radius: var(--border--radius);
22
+ border-bottom-right-radius: var(--border--radius);
18
23
  }
@@ -1,10 +1,10 @@
1
1
  import { FunctionComponent } from 'react';
2
2
 
3
- import { Key, Modal } from 'components';
4
- import { selectConfig, useTranslate, useTypedSelector } from 'state';
3
+ import { Modal } from 'components';
4
+ import { useTranslate } from 'state';
5
5
 
6
6
  import { Mapping } from './components';
7
- import { ARROWS, BACKSPACE, CTRL, DEL, ENTER, SPACE } from './keys';
7
+ import { ARROWS, BACKSPACE, DEL, ENTER, SPACE } from './keys';
8
8
 
9
9
  interface Props {
10
10
  className?: string;
@@ -14,7 +14,6 @@ interface Props {
14
14
 
15
15
  const KeyMapModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) => {
16
16
  const translate = useTranslate();
17
- const config = useTypedSelector(selectConfig);
18
17
 
19
18
  return (
20
19
  <Modal className={className} isOpen={isOpen} title={translate('keyMap')} onClose={onClose}>
@@ -22,26 +21,11 @@ const KeyMapModal: FunctionComponent<Props> = ({ className, isOpen, onClose }) =
22
21
  <Mapping description={translate('keyMap.board-and-rack.navigate')} mapping={[ARROWS]} />
23
22
  <Mapping description={translate('keyMap.board-and-rack.remove-tile')} mapping={[DEL, BACKSPACE]} />
24
23
  <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
- )}
40
24
  </Modal.Section>
41
25
 
42
26
  <Modal.Section title={translate('keyMap.board')}>
43
- <Mapping description={translate('keyMap.board.toggle-blank')} mapping={[SPACE, [CTRL, <Key key="b">B</Key>]]} />
44
- <Mapping description={translate('keyMap.board.toggle-direction')} mapping={[[CTRL, ARROWS]]} />
27
+ <Mapping description={translate('keyMap.board.toggle-blank')} mapping={[SPACE]} />
28
+ <Mapping description={translate('keyMap.board.toggle-direction')} mapping={[ARROWS]} />
45
29
  </Modal.Section>
46
30
 
47
31
  <Modal.Section title={translate('keyMap.rack')}>
@@ -29,6 +29,10 @@
29
29
  }
30
30
 
31
31
  .group {
32
+ [dir='rtl'] & {
33
+ flex-direction: row-reverse;
34
+ }
35
+
32
36
  &:first-child {
33
37
  margin-left: 0;
34
38
  }
@@ -19,6 +19,7 @@
19
19
  width: 100%;
20
20
  height: 100%;
21
21
  content: ' ';
22
+ border-radius: inherit;
22
23
  box-shadow: var(--box-shadow--error);
23
24
  }
24
25
  }
@@ -16,6 +16,7 @@
16
16
  flex: 0 0 calc(var(--dictionary--height) - var(--text-input--height));
17
17
  background-color: var(--color--background--element);
18
18
  border: var(--border);
19
+ border-radius: var(--border--radius);
19
20
  box-shadow: var(--box-shadow);
20
21
 
21
22
  @media (max-height: 600px) {
@@ -21,6 +21,8 @@
21
21
  $height: 32px;
22
22
 
23
23
  height: $height;
24
+ border-radius: var(--border--radius);
25
+ box-shadow: var(--box-shadow);
24
26
  transition: var(--transition);
25
27
 
26
28
  &.de {
@@ -37,5 +37,12 @@
37
37
 
38
38
  width: $size;
39
39
  height: $size;
40
- margin-right: var(--spacing--s);
40
+
41
+ [dir='ltr'] & {
42
+ margin-right: var(--spacing--s);
43
+ }
44
+
45
+ [dir='rtl'] & {
46
+ margin-left: var(--spacing--s);
47
+ }
41
48
  }
@@ -1,21 +1,37 @@
1
- import { applyMiddleware, compose, createStore } from 'redux';
1
+ import { configureStore } from '@reduxjs/toolkit';
2
2
  import reduxSaga from 'redux-saga';
3
3
 
4
- import rootReducer from './rootReducer';
5
4
  import { rootSaga } from './sagas';
6
- import { RootState } from './types';
5
+ import {
6
+ boardSlice,
7
+ cellFilterSlice,
8
+ dictionarySlice,
9
+ rackSlice,
10
+ resultsSlice,
11
+ settingsSlice,
12
+ solveSlice,
13
+ verifySlice,
14
+ } from './slices';
7
15
 
8
16
  const sagaMiddleware = reduxSaga();
9
- const initialState: Partial<RootState> | undefined = undefined;
10
17
 
11
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
12
- // @ts-ignore
13
- // eslint-disable-next-line no-underscore-dangle
14
- const composeEnhancers = globalThis.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
18
+ const createAppStore = () => {
19
+ const store = configureStore({
20
+ reducer: {
21
+ board: boardSlice.reducer,
22
+ cellFilter: cellFilterSlice.reducer,
23
+ dictionary: dictionarySlice.reducer,
24
+ rack: rackSlice.reducer,
25
+ results: resultsSlice.reducer,
26
+ settings: settingsSlice.reducer,
27
+ solve: solveSlice.reducer,
28
+ verify: verifySlice.reducer,
29
+ },
30
+ middleware: [sagaMiddleware],
31
+ });
15
32
 
16
- const createAppStore = (): ReturnType<typeof createStore> => {
17
- const store = createStore(rootReducer, initialState, composeEnhancers(applyMiddleware(sagaMiddleware)));
18
33
  sagaMiddleware.run(rootSaga);
34
+
19
35
  return store;
20
36
  };
21
37
 
@@ -1,3 +1,21 @@
1
- import rootReducer from './rootReducer';
1
+ import {
2
+ boardSlice,
3
+ cellFilterSlice,
4
+ dictionarySlice,
5
+ rackSlice,
6
+ resultsSlice,
7
+ settingsSlice,
8
+ solveSlice,
9
+ verifySlice,
10
+ } from './slices';
2
11
 
3
- export type RootState = ReturnType<typeof rootReducer>;
12
+ export type RootState = {
13
+ board: ReturnType<typeof boardSlice.reducer>;
14
+ cellFilter: ReturnType<typeof cellFilterSlice.reducer>;
15
+ dictionary: ReturnType<typeof dictionarySlice.reducer>;
16
+ rack: ReturnType<typeof rackSlice.reducer>;
17
+ results: ReturnType<typeof resultsSlice.reducer>;
18
+ settings: ReturnType<typeof settingsSlice.reducer>;
19
+ solve: ReturnType<typeof solveSlice.reducer>;
20
+ verify: ReturnType<typeof verifySlice.reducer>;
21
+ };
@@ -12,6 +12,28 @@ $media-expressions: (
12
12
  touch: '(hover: none)',
13
13
  );
14
14
 
15
+ @mixin scrollbars {
16
+ scrollbar-color: var(--scrollbar--thumb--color) var(--scrollbar--thumb--track);
17
+ scrollbar-width: auto;
18
+
19
+ &::-webkit-scrollbar {
20
+ width: var(--scrollbar--size);
21
+ background-color: var(--scrollbar--track--color);
22
+ }
23
+
24
+ &::-webkit-scrollbar-thumb {
25
+ background-color: var(--scrollbar--thumb--color);
26
+ }
27
+
28
+ &:hover {
29
+ scrollbar-color: var(--scrollbar--thumb--color--highlight) var(--scrollbar--track--color);
30
+
31
+ &::-webkit-scrollbar-thumb {
32
+ background-color: var(--scrollbar--thumb--color--highlight);
33
+ }
34
+ }
35
+ }
36
+
15
37
  /**
16
38
  * It does not work when applied on input elements.
17
39
  */