scrabble-solver 2.13.6 → 2.13.8

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 (131) hide show
  1. package/.nx/cache/d/server-process.json +1 -0
  2. package/.nx/cache/file-map.json +1293 -1298
  3. package/.nx/cache/lockfile.hash +1 -1
  4. package/.nx/cache/nx_files.nxt +0 -0
  5. package/.nx/cache/parsed-lock-file.json +306 -361
  6. package/.nx/cache/project-graph.json +316 -382
  7. package/.nx/workspace-data/file-map.json +2594 -0
  8. package/.nx/workspace-data/lockfile.hash +1 -0
  9. package/.nx/workspace-data/parsed-lock-file.json +31666 -0
  10. package/.nx/workspace-data/project-graph.json +31937 -0
  11. package/README.md +10 -19
  12. package/bump-version.js +15 -9
  13. package/lerna.json +1 -1
  14. package/package.json +9 -9
  15. package/packages/configs/package.json +3 -3
  16. package/packages/constants/package.json +1 -1
  17. package/packages/dictionaries/package-lock.json +2 -2
  18. package/packages/dictionaries/package.json +4 -4
  19. package/packages/logger/package-lock.json +2 -2
  20. package/packages/logger/package.json +1 -1
  21. package/packages/scrabble-solver/.next/BUILD_ID +1 -1
  22. package/packages/scrabble-solver/.next/build-manifest.json +11 -11
  23. package/packages/scrabble-solver/.next/cache/.tsbuildinfo +1 -1
  24. package/packages/scrabble-solver/.next/cache/eslint/.cache_8dgz12 +1 -1
  25. package/packages/scrabble-solver/.next/cache/webpack/client-production/0.pack +0 -0
  26. package/packages/scrabble-solver/.next/cache/webpack/client-production/index.pack +0 -0
  27. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/0.pack +0 -0
  28. package/packages/scrabble-solver/.next/cache/webpack/edge-server-production/index.pack +0 -0
  29. package/packages/scrabble-solver/.next/cache/webpack/server-production/0.pack +0 -0
  30. package/packages/scrabble-solver/.next/cache/webpack/server-production/index.pack +0 -0
  31. package/packages/scrabble-solver/.next/prerender-manifest.js +1 -1
  32. package/packages/scrabble-solver/.next/prerender-manifest.json +1 -1
  33. package/packages/scrabble-solver/.next/routes-manifest.json +1 -1
  34. package/packages/scrabble-solver/.next/server/chunks/577.js +1 -1
  35. package/packages/scrabble-solver/.next/server/chunks/807.js +1 -1
  36. package/packages/scrabble-solver/.next/server/chunks/977.js +1 -1
  37. package/packages/scrabble-solver/.next/server/middleware-build-manifest.js +1 -1
  38. package/packages/scrabble-solver/.next/server/pages/404.html +1 -1
  39. package/packages/scrabble-solver/.next/server/pages/500.html +1 -1
  40. package/packages/scrabble-solver/.next/server/pages/_app.js +1 -1
  41. package/packages/scrabble-solver/.next/server/pages/_error.js +1 -1
  42. package/packages/scrabble-solver/.next/server/pages/api/solve.js +1 -1
  43. package/packages/scrabble-solver/.next/server/pages/index.html +1 -1
  44. package/packages/scrabble-solver/.next/server/pages/index.js +1 -1
  45. package/packages/scrabble-solver/.next/server/pages/index.json +1 -1
  46. package/packages/scrabble-solver/.next/server/pages-manifest.json +1 -1
  47. package/packages/scrabble-solver/.next/static/7zESQYo9UAqNh9LV0b7Sd/_buildManifest.js +1 -0
  48. package/packages/scrabble-solver/.next/static/chunks/{main-6e708370ad13b1f9.js → main-b5b360c6afb66b05.js} +1 -1
  49. package/packages/scrabble-solver/.next/static/chunks/pages/{404-129e0943628b6fab.js → 404-63b972b24be99c62.js} +1 -1
  50. package/packages/scrabble-solver/.next/static/chunks/pages/_app-a2848b7efa6bb6b0.js +17 -0
  51. package/packages/scrabble-solver/.next/static/chunks/pages/index-7b73be2915cc7099.js +1 -0
  52. package/packages/scrabble-solver/.next/static/css/6682db14f926d4c7.css +1 -0
  53. package/packages/scrabble-solver/.next/static/css/b37850c8d5270d91.css +2 -0
  54. package/packages/scrabble-solver/.next/trace +44 -44
  55. package/packages/scrabble-solver/package-lock.json +5 -6
  56. package/packages/scrabble-solver/package.json +11 -12
  57. package/packages/scrabble-solver/public/service-worker.js +1 -1
  58. package/packages/scrabble-solver/src/components/Alert/Alert.module.scss +3 -12
  59. package/packages/scrabble-solver/src/components/Board/Board.module.scss +1 -4
  60. package/packages/scrabble-solver/src/components/Board/BoardPure.tsx +1 -1
  61. package/packages/scrabble-solver/src/components/Board/components/Actions/Actions.module.scss +7 -27
  62. package/packages/scrabble-solver/src/components/Board/components/Cell/Cell.module.scss +5 -32
  63. package/packages/scrabble-solver/src/components/Board/components/InputPrompt/InputPrompt.module.scss +4 -18
  64. package/packages/scrabble-solver/src/components/Board/hooks/useBackgroundImage.tsx +15 -4
  65. package/packages/scrabble-solver/src/components/Board/hooks/useGrid.ts +13 -5
  66. package/packages/scrabble-solver/src/components/Board/lib/index.ts +0 -1
  67. package/packages/scrabble-solver/src/components/Button/Button.module.scss +1 -8
  68. package/packages/scrabble-solver/src/components/Button/Button.tsx +16 -17
  69. package/packages/scrabble-solver/src/components/Button/Link.tsx +15 -16
  70. package/packages/scrabble-solver/src/components/Dictionary/Dictionary.module.scss +1 -8
  71. package/packages/scrabble-solver/src/components/IconButton/IconButton.tsx +8 -8
  72. package/packages/scrabble-solver/src/components/IconButton/Link.tsx +8 -8
  73. package/packages/scrabble-solver/src/components/Loading/Loading.module.scss +1 -4
  74. package/packages/scrabble-solver/src/components/Modal/Modal.module.scss +2 -16
  75. package/packages/scrabble-solver/src/components/Rack/Rack.module.scss +4 -18
  76. package/packages/scrabble-solver/src/components/Rack/components/InputPrompt/InputPrompt.module.scss +1 -4
  77. package/packages/scrabble-solver/src/components/Results/Cell.tsx +4 -5
  78. package/packages/scrabble-solver/src/components/Results/HeaderButton.tsx +25 -22
  79. package/packages/scrabble-solver/src/components/Results/Result.tsx +15 -3
  80. package/packages/scrabble-solver/src/components/Results/Results.module.scss +31 -48
  81. package/packages/scrabble-solver/src/components/Results/Results.tsx +1 -1
  82. package/packages/scrabble-solver/src/components/Results/getCoordinatesColumn.ts +15 -0
  83. package/packages/scrabble-solver/src/components/Results/getLocaleColumns.ts +7 -0
  84. package/packages/scrabble-solver/src/components/Results/types.ts +1 -0
  85. package/packages/scrabble-solver/src/components/Results/useColumns.ts +10 -7
  86. package/packages/scrabble-solver/src/components/Solver/components/ResultCandidatePicker/ResultCandidatePicker.module.scss +9 -40
  87. package/packages/scrabble-solver/src/components/Tile/Tile.module.scss +6 -26
  88. package/packages/scrabble-solver/src/components/Tooltip/Tooltip.tsx +28 -0
  89. package/packages/scrabble-solver/src/components/Tooltip/TooltipContent.tsx +53 -0
  90. package/packages/scrabble-solver/src/components/Tooltip/TooltipTrigger.tsx +26 -0
  91. package/packages/scrabble-solver/src/components/Tooltip/context.ts +17 -0
  92. package/packages/scrabble-solver/src/components/Tooltip/index.ts +1 -1
  93. package/packages/scrabble-solver/src/components/Tooltip/useTooltip.ts +54 -0
  94. package/packages/scrabble-solver/src/components/index.ts +1 -2
  95. package/packages/scrabble-solver/src/hooks/index.ts +0 -1
  96. package/packages/scrabble-solver/src/i18n/languages/german.json +1 -1
  97. package/packages/scrabble-solver/src/icons/index.ts +0 -2
  98. package/packages/scrabble-solver/src/lib/getCoordinates.ts +18 -0
  99. package/packages/scrabble-solver/src/lib/groupResults.ts +16 -11
  100. package/packages/scrabble-solver/src/lib/index.ts +2 -1
  101. package/packages/scrabble-solver/src/lib/sortResults.ts +1 -0
  102. package/packages/scrabble-solver/src/modals/KeyMapModal/components/Mapping/Mapping.module.scss +2 -2
  103. package/packages/scrabble-solver/src/modals/MenuModal/MenuModal.module.scss +2 -15
  104. package/packages/scrabble-solver/src/modals/RemainingTilesModal/RemainingTilesModal.module.scss +1 -7
  105. package/packages/scrabble-solver/src/modals/WordsModal/WordsModal.module.scss +2 -15
  106. package/packages/scrabble-solver/src/pages/_app.tsx +5 -1
  107. package/packages/scrabble-solver/src/parameters/index.ts +1 -0
  108. package/packages/scrabble-solver/src/styles/mixins.scss +2 -5
  109. package/packages/scrabble-solver/src/types/index.ts +1 -0
  110. package/packages/solver/package-lock.json +2 -2
  111. package/packages/solver/package.json +5 -5
  112. package/packages/types/package.json +2 -2
  113. package/packages/word-definitions/package-lock.json +2 -2
  114. package/packages/word-definitions/package.json +2 -2
  115. package/packages/word-lists/package-lock.json +3 -3
  116. package/packages/word-lists/package.json +3 -3
  117. package/packages/scrabble-solver/.next/static/4GWIKe7khKxREyq3ZamDK/_buildManifest.js +0 -1
  118. package/packages/scrabble-solver/.next/static/chunks/pages/_app-cccda36d00fa2328.js +0 -17
  119. package/packages/scrabble-solver/.next/static/chunks/pages/index-caaf20b2488cb10e.js +0 -1
  120. package/packages/scrabble-solver/.next/static/css/11366b7489cf90ac.css +0 -1
  121. package/packages/scrabble-solver/.next/static/css/f549d7823f599b8d.css +0 -2
  122. package/packages/scrabble-solver/src/components/Checkbox/Checkbox.module.scss +0 -45
  123. package/packages/scrabble-solver/src/components/Checkbox/Checkbox.tsx +0 -38
  124. package/packages/scrabble-solver/src/components/Checkbox/index.ts +0 -1
  125. package/packages/scrabble-solver/src/components/Tooltip/useTooltip.tsx +0 -134
  126. package/packages/scrabble-solver/src/hooks/usePortal.tsx +0 -47
  127. package/packages/scrabble-solver/src/icons/CheckboxChecked.svg +0 -4
  128. package/packages/scrabble-solver/src/icons/CheckboxEmpty.svg +0 -4
  129. package/packages/scrabble-solver/src/lib/canUseDom.ts +0 -3
  130. /package/packages/scrabble-solver/.next/static/{4GWIKe7khKxREyq3ZamDK → 7zESQYo9UAqNh9LV0b7Sd}/_ssgManifest.js +0 -0
  131. /package/packages/scrabble-solver/src/{components/Board/lib → lib}/getCoordinate.ts +0 -0
@@ -77,12 +77,5 @@
77
77
  flex: 1;
78
78
  font-size: var(--font--size--h3);
79
79
  transition: var(--transition);
80
-
81
- [dir='ltr'] & {
82
- text-align: left;
83
- }
84
-
85
- [dir='rtl'] & {
86
- text-align: right;
87
- }
80
+ text-align: start;
88
81
  }
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { ButtonHTMLAttributes, FunctionComponent, ReactNode, SVGAttributes } from 'react';
3
3
 
4
- import { useTooltip } from '../Tooltip';
4
+ import { Tooltip } from '../Tooltip';
5
5
 
6
6
  import styles from './Button.module.scss';
7
7
  import Link from './Link';
@@ -23,23 +23,22 @@ const Button: FunctionComponent<Props> = ({
23
23
  variant = 'default',
24
24
  ...props
25
25
  }) => {
26
- const triggerProps = useTooltip(tooltip, props);
27
-
28
26
  return (
29
- <button
30
- className={classNames(styles.button, className, {
31
- [styles.default]: variant === 'default',
32
- [styles.primary]: variant === 'primary',
33
- })}
34
- type="button"
35
- {...props}
36
- {...triggerProps}
37
- >
38
- <span className={styles.content}>
39
- {Icon && <Icon className={classNames(styles.icon, iconClassName)} />}
40
- {children && <span className={styles.label}>{children}</span>}
41
- </span>
42
- </button>
27
+ <Tooltip tooltip={tooltip}>
28
+ <button
29
+ className={classNames(styles.button, className, {
30
+ [styles.default]: variant === 'default',
31
+ [styles.primary]: variant === 'primary',
32
+ })}
33
+ type="button"
34
+ {...props}
35
+ >
36
+ <span className={styles.content}>
37
+ {Icon && <Icon className={classNames(styles.icon, iconClassName)} />}
38
+ {children && <span className={styles.label}>{children}</span>}
39
+ </span>
40
+ </button>
41
+ </Tooltip>
43
42
  );
44
43
  };
45
44
 
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { AnchorHTMLAttributes, FunctionComponent, ReactNode, SVGAttributes } from 'react';
3
3
 
4
- import { useTooltip } from '../Tooltip';
4
+ import { Tooltip } from '../Tooltip';
5
5
 
6
6
  import styles from './Button.module.scss';
7
7
 
@@ -23,22 +23,21 @@ const Link: FunctionComponent<Props> = ({
23
23
  variant = 'default',
24
24
  ...props
25
25
  }) => {
26
- const triggerProps = useTooltip(tooltip, props);
27
-
28
26
  return (
29
- <a
30
- className={classNames(styles.button, className, {
31
- [styles.default]: variant === 'default',
32
- [styles.primary]: variant === 'primary',
33
- })}
34
- {...props}
35
- {...triggerProps}
36
- >
37
- <span className={styles.content}>
38
- {Icon && <Icon className={classNames(styles.icon, iconClassName)} />}
39
- {children && <span className={styles.label}>{children}</span>}
40
- </span>
41
- </a>
27
+ <Tooltip tooltip={tooltip}>
28
+ <a
29
+ className={classNames(styles.button, className, {
30
+ [styles.default]: variant === 'default',
31
+ [styles.primary]: variant === 'primary',
32
+ })}
33
+ {...props}
34
+ >
35
+ <span className={styles.content}>
36
+ {Icon && <Icon className={classNames(styles.icon, iconClassName)} />}
37
+ {children && <span className={styles.label}>{children}</span>}
38
+ </span>
39
+ </a>
40
+ </Tooltip>
42
41
  );
43
42
  };
44
43
 
@@ -55,14 +55,7 @@
55
55
 
56
56
  .definitions {
57
57
  margin: 0;
58
-
59
- [dir='ltr'] & {
60
- padding-left: var(--spacing--l);
61
- }
62
-
63
- [dir='rtl'] & {
64
- padding-right: var(--spacing--l);
65
- }
58
+ padding-inline-start: var(--spacing--l);
66
59
  }
67
60
 
68
61
  .definition {
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { ButtonHTMLAttributes, FunctionComponent, MouseEventHandler, SVGAttributes } from 'react';
3
3
 
4
- import { useTooltip } from '../Tooltip';
4
+ import { Tooltip } from '../Tooltip';
5
5
 
6
6
  import styles from './IconButton.module.scss';
7
7
  import Link from './Link';
@@ -15,14 +15,14 @@ interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
15
15
  }
16
16
 
17
17
  const IconButton: FunctionComponent<Props> = ({ className, Icon, tooltip, ...props }) => {
18
- const triggerProps = useTooltip(tooltip, props);
19
-
20
18
  return (
21
- <button className={classNames(styles.iconButton, className)} type="button" {...props} {...triggerProps}>
22
- <span className={styles.content}>
23
- <Icon className={styles.icon} />
24
- </span>
25
- </button>
19
+ <Tooltip tooltip={tooltip}>
20
+ <button className={classNames(styles.iconButton, className)} type="button" {...props}>
21
+ <span className={styles.content}>
22
+ <Icon className={styles.icon} />
23
+ </span>
24
+ </button>
25
+ </Tooltip>
26
26
  );
27
27
  };
28
28
 
@@ -1,7 +1,7 @@
1
1
  import classNames from 'classnames';
2
2
  import { AnchorHTMLAttributes, FunctionComponent, SVGAttributes } from 'react';
3
3
 
4
- import { useTooltip } from '../Tooltip';
4
+ import { Tooltip } from '../Tooltip';
5
5
 
6
6
  import styles from './IconButton.module.scss';
7
7
 
@@ -14,14 +14,14 @@ interface Props extends AnchorHTMLAttributes<HTMLAnchorElement> {
14
14
  }
15
15
 
16
16
  const Link: FunctionComponent<Props> = ({ className, Icon, tooltip, ...props }) => {
17
- const triggerProps = useTooltip(tooltip, props);
18
-
19
17
  return (
20
- <a className={classNames(styles.iconButton, className)} {...props} {...triggerProps}>
21
- <span className={styles.content}>
22
- <Icon className={styles.icon} />
23
- </span>
24
- </a>
18
+ <Tooltip tooltip={tooltip}>
19
+ <a className={classNames(styles.iconButton, className)} {...props}>
20
+ <span className={styles.content}>
21
+ <Icon className={styles.icon} />
22
+ </span>
23
+ </a>
24
+ </Tooltip>
25
25
  );
26
26
  };
27
27
 
@@ -1,10 +1,7 @@
1
1
  .loading,
2
2
  .dim {
3
3
  position: absolute;
4
- top: 0;
5
- bottom: 0;
6
- left: 0;
7
- right: 0;
4
+ inset: 0;
8
5
  }
9
6
 
10
7
  .loading {
@@ -3,14 +3,7 @@
3
3
  .modal,
4
4
  .closeButton {
5
5
  top: 0;
6
-
7
- [dir='ltr'] & {
8
- right: 0;
9
- }
10
-
11
- [dir='rtl'] & {
12
- left: 0;
13
- }
6
+ inset-inline-end: 0;
14
7
  }
15
8
 
16
9
  .modal {
@@ -92,14 +85,7 @@
92
85
  .title {
93
86
  font-size: var(--font--size--h1);
94
87
  font-weight: 300;
95
-
96
- [dir='ltr'] & {
97
- padding-right: calc(var(--square-button--size) + var(--spacing--s));
98
- }
99
-
100
- [dir='rtl'] & {
101
- padding-left: calc(var(--square-button--size) + var(--spacing--s));
102
- }
88
+ padding-inline-end: calc(var(--square-button--size) + var(--spacing--s));
103
89
  }
104
90
 
105
91
  .closeButton {
@@ -77,25 +77,11 @@
77
77
  }
78
78
 
79
79
  .sharpLeft {
80
- [dir='ltr'] & {
81
- border-top-left-radius: 0;
82
- border-bottom-left-radius: 0;
83
- }
84
-
85
- [dir='rtl'] & {
86
- border-top-right-radius: 0;
87
- border-bottom-right-radius: 0;
88
- }
80
+ border-start-start-radius: 0;
81
+ border-end-start-radius: 0;
89
82
  }
90
83
 
91
84
  .sharpRight {
92
- [dir='ltr'] & {
93
- border-top-right-radius: 0;
94
- border-bottom-right-radius: 0;
95
- }
96
-
97
- [dir='rtl'] & {
98
- border-top-left-radius: 0;
99
- border-bottom-left-radius: 0;
100
- }
85
+ border-start-end-radius: 0;
86
+ border-end-end-radius: 0;
101
87
  }
@@ -10,10 +10,7 @@
10
10
  @include text-input;
11
11
 
12
12
  position: absolute;
13
- top: 0;
14
- right: 0;
15
- bottom: 0;
16
- left: 0;
13
+ inset: 0;
17
14
  width: 100%;
18
15
  height: 100%;
19
16
  border-radius: var(--border--radius);
@@ -4,7 +4,7 @@ import { FunctionComponent, ReactNode } from 'react';
4
4
  import { selectLocale, useTranslate, useTypedSelector } from 'state';
5
5
  import { TranslationKey } from 'types';
6
6
 
7
- import { useTooltip } from '../Tooltip';
7
+ import { Tooltip } from '../Tooltip';
8
8
 
9
9
  import styles from './Results.module.scss';
10
10
 
@@ -20,12 +20,11 @@ const Cell: FunctionComponent<Props> = ({ children, className, translationKey, t
20
20
  const translate = useTranslate();
21
21
  const locale = useTypedSelector(selectLocale);
22
22
  const formattedValue = value.toLocaleString(locale);
23
- const triggerProps = useTooltip(`${translate(translationKey)}: ${tooltip || formattedValue}`);
24
23
 
25
24
  return (
26
- <div className={classNames(styles.cell, className)} {...triggerProps}>
27
- {children || formattedValue}
28
- </div>
25
+ <Tooltip tooltip={`${translate(translationKey)}: ${tooltip || formattedValue}`}>
26
+ <div className={classNames(styles.cell, className)}>{children || formattedValue}</div>
27
+ </Tooltip>
29
28
  );
30
29
  };
31
30
 
@@ -6,45 +6,48 @@ import { SortDown, SortUp } from 'icons';
6
6
  import { resultsSlice, selectResultsSort, useTranslate, useTypedSelector } from 'state';
7
7
  import { SortDirection } from 'types';
8
8
 
9
- import { useTooltip } from '../Tooltip';
9
+ import { Tooltip } from '../Tooltip';
10
10
 
11
11
  import styles from './Results.module.scss';
12
12
  import { Column } from './types';
13
13
 
14
14
  interface Props {
15
15
  column: Column;
16
+ sortable?: boolean;
16
17
  }
17
18
 
18
- const HeaderButton = ({ column }: Props): ReactElement => {
19
+ const HeaderButton = ({ column, sortable }: Props): ReactElement => {
19
20
  const dispatch = useDispatch();
20
21
  const translate = useTranslate();
21
22
  const sort = useTypedSelector(selectResultsSort);
22
- const triggerProps = useTooltip(translate(column.translationKey));
23
23
 
24
24
  const handleClick = useCallback(() => {
25
25
  dispatch(resultsSlice.actions.sort(column.id));
26
26
  }, [column.id, dispatch]);
27
27
 
28
28
  return (
29
- <button
30
- aria-label={translate(column.translationKey)}
31
- className={classNames(styles.headerButton, column.className)}
32
- key={column.id}
33
- type="button"
34
- onClick={handleClick}
35
- {...triggerProps}
36
- >
37
- <span className={styles.cell}>
38
- <span className={styles.headerButtonLabel}>{translate(column.translationKey)}</span>
39
-
40
- {sort.column === column.id && (
41
- <>
42
- {sort.direction === SortDirection.Ascending && <SortUp className={styles.sortIcon} />}
43
- {sort.direction === SortDirection.Descending && <SortDown className={styles.sortIcon} />}
44
- </>
45
- )}
46
- </span>
47
- </button>
29
+ <Tooltip tooltip={translate(column.translationKey)}>
30
+ <button
31
+ aria-label={translate(column.translationKey)}
32
+ className={classNames(styles.headerButton, column.className, {
33
+ [styles.sortable]: sortable,
34
+ })}
35
+ key={column.id}
36
+ type="button"
37
+ onClick={sortable ? handleClick : undefined}
38
+ >
39
+ <span className={styles.cell}>
40
+ <span className={styles.headerButtonLabel}>{translate(column.translationKey)}</span>
41
+
42
+ {sort.column === column.id && (
43
+ <>
44
+ {sort.direction === SortDirection.Ascending && <SortUp className={styles.sortIcon} />}
45
+ {sort.direction === SortDirection.Descending && <SortDown className={styles.sortIcon} />}
46
+ </>
47
+ )}
48
+ </span>
49
+ </button>
50
+ </Tooltip>
48
51
  );
49
52
  };
50
53
 
@@ -1,10 +1,16 @@
1
1
  import classNames from 'classnames';
2
- import { CSSProperties, FocusEventHandler, MouseEventHandler, ReactElement, useRef } from 'react';
2
+ import { CSSProperties, FocusEventHandler, MouseEventHandler, ReactElement, useMemo, useRef } from 'react';
3
3
  import Highlighter from 'react-highlight-words';
4
4
 
5
5
  import { LOCALE_FEATURES } from 'i18n';
6
- import { noop } from 'lib';
7
- import { selectIsResultMatching, selectLocale, selectResultsQuery, useTypedSelector } from 'state';
6
+ import { getCoordinates, noop } from 'lib';
7
+ import {
8
+ selectIsResultMatching,
9
+ selectLocale,
10
+ selectResultsQuery,
11
+ selectShowCoordinates,
12
+ useTypedSelector,
13
+ } from 'state';
8
14
  import { ResultColumn } from 'types';
9
15
 
10
16
  import Cell from './Cell';
@@ -31,12 +37,14 @@ const Result = ({ data, index, style }: Props): ReactElement => {
31
37
  const ref = useRef<HTMLButtonElement>(null);
32
38
  const columns = useColumns();
33
39
  const locale = useTypedSelector(selectLocale);
40
+ const showCoordinates = useTypedSelector(selectShowCoordinates);
34
41
  const query = useTypedSelector(selectResultsQuery);
35
42
  const { consonants, direction, separator, vowels } = LOCALE_FEATURES[locale];
36
43
  const result = results[index];
37
44
  const isMatching = useTypedSelector((state) => selectIsResultMatching(state, index));
38
45
  const words = direction === 'rtl' ? [...result.words].reverse() : result.words;
39
46
  const enabledColumns = Object.fromEntries(columns.map((column) => [column.id, true]));
47
+ const coordinates = useMemo(() => getCoordinates(result, showCoordinates), [result, showCoordinates]);
40
48
 
41
49
  const handleClick: MouseEventHandler = (event) => onClick(result, event);
42
50
  const handleMouseEnter: MouseEventHandler = (event) => onMouseEnter(result, event);
@@ -61,6 +69,10 @@ const Result = ({ data, index, style }: Props): ReactElement => {
61
69
  onMouseLeave={handleMouseLeave}
62
70
  >
63
71
  <span className={styles.resultContent}>
72
+ {enabledColumns[ResultColumn.Coordinates] && (
73
+ <Cell className={styles.coordinates} translationKey="settings.showCoordinates" value={coordinates} />
74
+ )}
75
+
64
76
  {enabledColumns[ResultColumn.Word] && (
65
77
  <Cell className={styles.word} translationKey="common.word" value={result.word}>
66
78
  <Highlighter highlightClassName={styles.highlight} searchWords={[query]} textToHighlight={result.word} />
@@ -24,10 +24,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
24
24
 
25
25
  .listContainer {
26
26
  position: absolute;
27
- top: 0;
28
- left: 0;
29
- right: 0;
30
- bottom: 0;
27
+ inset: 0;
31
28
  }
32
29
 
33
30
  .list {
@@ -55,37 +52,29 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
55
52
 
56
53
  .headerButton {
57
54
  @include button-reset;
58
- @include focus-effect;
59
55
 
60
- cursor: pointer;
61
56
  text-transform: uppercase;
62
57
  transition: var(--transition);
63
58
  background-color: var(--color--background);
64
59
 
65
- &:focus,
66
- &:hover {
67
- background-color: var(--color--primary);
68
- color: var(--color--primary--opposite);
69
- }
70
-
71
60
  &:first-child {
72
- [dir='ltr'] & {
73
- border-top-left-radius: inherit;
74
- }
75
-
76
- [dir='rtl'] & {
77
- border-top-right-radius: inherit;
78
- }
61
+ border-start-start-radius: inherit;
79
62
  }
80
63
 
81
64
  &:last-child {
82
- [dir='ltr'] & {
83
- border-top-right-radius: inherit;
84
- }
65
+ border-start-end-radius: inherit;
66
+ }
67
+ }
85
68
 
86
- [dir='rtl'] & {
87
- border-top-left-radius: inherit;
88
- }
69
+ .sortable {
70
+ @include focus-effect;
71
+
72
+ cursor: pointer;
73
+
74
+ &:focus,
75
+ &:hover {
76
+ background-color: var(--color--primary);
77
+ color: var(--color--primary--opposite);
89
78
  }
90
79
  }
91
80
 
@@ -93,11 +82,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
93
82
  @include ellipsis;
94
83
 
95
84
  flex: 0 1 auto;
96
- text-align: left;
97
-
98
- [dir='rtl'] & {
99
- text-align: right;
100
- }
85
+ text-align: start;
101
86
  }
102
87
 
103
88
  .result {
@@ -139,6 +124,7 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
139
124
 
140
125
  .word {
141
126
  @include ellipsis;
127
+ display: flex;
142
128
  }
143
129
  }
144
130
 
@@ -151,30 +137,20 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
151
137
  gap: var(--spacing--s);
152
138
  line-height: var(--results--item--height);
153
139
 
154
- .result &:first-child,
155
- .headerButton:first-child & {
140
+ &.word,
141
+ .headerButton.word & {
156
142
  justify-content: flex-start;
143
+ }
157
144
 
158
- [dir='ltr'] & {
159
- padding-left: $row-padding-horizontal;
160
- text-align: left;
161
- }
162
-
163
- [dir='rtl'] & {
164
- padding-right: $row-padding-horizontal;
165
- text-align: right;
166
- }
145
+ .result &:first-child,
146
+ .headerButton:first-child & {
147
+ text-align: start;
148
+ padding-inline-start: $row-padding-horizontal;
167
149
  }
168
150
 
169
151
  .result &:last-child,
170
152
  .headerButton:last-child & {
171
- [dir='ltr'] & {
172
- padding-right: $row-padding-horizontal;
173
- }
174
-
175
- [dir='rtl'] & {
176
- padding-left: $row-padding-horizontal;
177
- }
153
+ padding-inline-end: $row-padding-horizontal;
178
154
  }
179
155
 
180
156
  &:last-child {
@@ -203,6 +179,13 @@ $row-padding-horizontal: calc(var(--spacing--m) + var(--spacing--s));
203
179
  font-weight: bold;
204
180
  }
205
181
 
182
+ .coordinates {
183
+ $width: 50px;
184
+
185
+ flex: 0 0 $width;
186
+ max-width: $width;
187
+ }
188
+
206
189
  .solveButton {
207
190
  display: block;
208
191
  margin: var(--spacing--xl) auto 0;
@@ -69,7 +69,7 @@ const Results: FunctionComponent<Props> = ({ callbacks, className, highlightedIn
69
69
  <div className={classNames(styles.results, className)}>
70
70
  <div className={styles.header}>
71
71
  {columns.map((column) => (
72
- <HeaderButton column={column} key={column.id} />
72
+ <HeaderButton column={column} key={column.id} sortable={column.sortable} />
73
73
  ))}
74
74
  </div>
75
75
 
@@ -0,0 +1,15 @@
1
+ import { ResultColumn } from 'types';
2
+
3
+ import styles from './Results.module.scss';
4
+ import { Column } from './types';
5
+
6
+ const getCoordinatesColumn = (): Column => {
7
+ return {
8
+ className: styles.coordinates,
9
+ id: ResultColumn.Coordinates,
10
+ translationKey: 'settings.showCoordinates',
11
+ sortable: false,
12
+ };
13
+ };
14
+
15
+ export default getCoordinatesColumn;
@@ -10,11 +10,13 @@ const getLocaleColumns = (options: { consonants: boolean; vowels: boolean }): Co
10
10
  className: styles.word,
11
11
  id: ResultColumn.Word,
12
12
  translationKey: 'common.word',
13
+ sortable: true,
13
14
  },
14
15
  {
15
16
  className: styles.stat,
16
17
  id: ResultColumn.TilesCount,
17
18
  translationKey: 'common.tiles',
19
+ sortable: true,
18
20
  },
19
21
  ];
20
22
 
@@ -23,6 +25,7 @@ const getLocaleColumns = (options: { consonants: boolean; vowels: boolean }): Co
23
25
  className: styles.stat,
24
26
  id: ResultColumn.ConsonantsCount,
25
27
  translationKey: 'common.consonants',
28
+ sortable: true,
26
29
  });
27
30
  }
28
31
 
@@ -31,6 +34,7 @@ const getLocaleColumns = (options: { consonants: boolean; vowels: boolean }): Co
31
34
  className: styles.stat,
32
35
  id: ResultColumn.VowelsCount,
33
36
  translationKey: 'common.vowels',
37
+ sortable: true,
34
38
  });
35
39
  }
36
40
 
@@ -39,16 +43,19 @@ const getLocaleColumns = (options: { consonants: boolean; vowels: boolean }): Co
39
43
  className: styles.stat,
40
44
  id: ResultColumn.BlanksCount,
41
45
  translationKey: 'common.blanks',
46
+ sortable: true,
42
47
  },
43
48
  {
44
49
  className: styles.stat,
45
50
  id: ResultColumn.WordsCount,
46
51
  translationKey: 'common.words',
52
+ sortable: true,
47
53
  },
48
54
  {
49
55
  className: styles.points,
50
56
  id: ResultColumn.Points,
51
57
  translationKey: 'common.points',
58
+ sortable: true,
52
59
  },
53
60
  );
54
61
 
@@ -7,6 +7,7 @@ export interface Column {
7
7
  className: string;
8
8
  id: ResultColumn;
9
9
  translationKey: TranslationKey;
10
+ sortable?: boolean;
10
11
  }
11
12
 
12
13
  export interface ResultCallbacks {