polpo 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/.storybook/theme.ts +2 -2
  2. package/.turbo/turbo-lint.log +1 -1
  3. package/README.md +2 -5
  4. package/dist/chunk-CFYQBHH5.js +3 -0
  5. package/dist/chunk-CFYQBHH5.js.map +1 -0
  6. package/dist/chunk-MAWW6AA7.js +3 -0
  7. package/dist/chunk-MAWW6AA7.js.map +1 -0
  8. package/dist/get-modal-position-drle0OjP.d.cts +49 -0
  9. package/dist/get-modal-position-drle0OjP.d.ts +49 -0
  10. package/dist/helpers.cjs +1 -1
  11. package/dist/helpers.cjs.map +1 -1
  12. package/dist/helpers.d.cts +9 -2
  13. package/dist/helpers.d.ts +9 -2
  14. package/dist/helpers.js +1 -1
  15. package/dist/hooks.cjs +1 -1
  16. package/dist/hooks.cjs.map +1 -1
  17. package/dist/hooks.d.cts +59 -21
  18. package/dist/hooks.d.ts +59 -21
  19. package/dist/hooks.js +1 -1
  20. package/dist/ui.cjs +601 -389
  21. package/dist/ui.cjs.map +1 -1
  22. package/dist/ui.d.cts +97 -77
  23. package/dist/ui.d.ts +97 -77
  24. package/dist/ui.js +585 -373
  25. package/dist/ui.js.map +1 -1
  26. package/dist/use-modal-in-container-DiNW1PE_.d.cts +34 -0
  27. package/dist/use-modal-in-container-neGo-kMk.d.ts +34 -0
  28. package/package.json +2 -2
  29. package/src/components/buttons/button/button.stories.tsx +4 -4
  30. package/src/components/buttons/button/button.style.ts +10 -5
  31. package/src/components/buttons/button/button.tsx +7 -19
  32. package/src/components/cards/flip-card/flip-card.tsx +1 -1
  33. package/src/components/cursor/cursor.stories.tsx +35 -0
  34. package/src/components/cursor/cursor.style.ts +73 -0
  35. package/src/components/cursor/cursor.tsx +49 -0
  36. package/src/components/cursor/index.ts +1 -0
  37. package/src/components/form/checkbox/checkbox.stories.tsx +51 -0
  38. package/src/components/form/checkbox/checkbox.style.ts +73 -37
  39. package/src/components/form/checkbox/checkbox.tsx +38 -4
  40. package/src/components/form/field/field.stories.tsx +5 -1
  41. package/src/components/form/field/field.style.ts +12 -0
  42. package/src/components/form/field/field.tsx +3 -1
  43. package/src/components/form/field/field.types.ts +6 -0
  44. package/src/components/form/input-color/input-color.style.ts +5 -4
  45. package/src/components/form/input-color/input-color.tsx +41 -44
  46. package/src/components/form/radio/radio.stories.tsx +29 -5
  47. package/src/components/form/radio/radio.style.ts +45 -24
  48. package/src/components/form/radio/radio.tsx +22 -3
  49. package/src/components/form/select/options.tsx +119 -67
  50. package/src/components/form/select/select.stories.tsx +103 -42
  51. package/src/components/form/select/select.style.ts +10 -92
  52. package/src/components/form/select/select.tsx +19 -42
  53. package/src/components/form/select/select.types.ts +4 -21
  54. package/src/components/form/slider/slider.style.ts +2 -0
  55. package/src/components/icon/icons/social.tsx +17 -1
  56. package/src/components/index.ts +1 -0
  57. package/src/components/infinity-scroll/infinity-scroll.tsx +1 -1
  58. package/src/components/line/line.stories.tsx +3 -4
  59. package/src/components/modals/action-modal/action-modal.stories.tsx +58 -39
  60. package/src/components/modals/action-modal/action-modal.style.ts +13 -25
  61. package/src/components/modals/action-modal/action-modal.tsx +68 -70
  62. package/src/components/modals/aside-modal/aside-modal.stories.tsx +11 -15
  63. package/src/components/modals/aside-modal/aside-modal.style.ts +17 -37
  64. package/src/components/modals/aside-modal/aside-modal.tsx +41 -43
  65. package/src/components/modals/confirmation-modal/confirmation-modal.stories.tsx +21 -9
  66. package/src/components/modals/index.ts +2 -0
  67. package/src/components/modals/menu/index.ts +1 -0
  68. package/src/components/modals/menu/menu.stories.tsx +69 -0
  69. package/src/components/modals/menu/menu.style.ts +62 -0
  70. package/src/components/modals/menu/menu.tsx +142 -0
  71. package/src/components/modals/modal/backdrop.tsx +70 -0
  72. package/src/components/modals/modal/index.ts +1 -0
  73. package/src/components/modals/modal/modal.stories.tsx +325 -0
  74. package/src/components/modals/modal/modal.style.ts +62 -2
  75. package/src/components/modals/modal/modal.tsx +82 -123
  76. package/src/components/modals/portal/index.ts +1 -0
  77. package/src/components/modals/portal/portal.tsx +18 -0
  78. package/src/components/tabs/tabs-list.tsx +13 -10
  79. package/src/components/tabs/tabs.style.ts +48 -43
  80. package/src/components/tag/tag.stories.tsx +11 -12
  81. package/src/components/tag/tag.style.ts +9 -4
  82. package/src/components/tag/tag.tsx +2 -12
  83. package/src/components/tooltips/tooltip/tooltip.stories.tsx +5 -2
  84. package/src/components/tooltips/tooltip/tooltip.style.ts +37 -6
  85. package/src/components/tooltips/tooltip/tooltip.tsx +33 -19
  86. package/src/components/typography/typography.stories.tsx +3 -1
  87. package/src/components/typography/typography.tsx +21 -0
  88. package/src/contexts/theme-context/theme.animations.ts +91 -2
  89. package/src/contexts/theme-context/theme.defaults.ts +1 -1
  90. package/src/core/http-client.ts +49 -47
  91. package/src/core/variants/color.ts +3 -30
  92. package/src/core/variants/radius.ts +12 -41
  93. package/src/core/variants/size.ts +8 -33
  94. package/src/helpers/get-modal-position-relative-to-screen.ts +86 -0
  95. package/src/helpers/get-modal-position.ts +173 -28
  96. package/src/helpers/index.ts +1 -0
  97. package/src/hooks/index.ts +9 -3
  98. package/src/hooks/use-click-outside.ts +32 -0
  99. package/src/hooks/use-cookie.ts +124 -0
  100. package/src/hooks/use-dimensions.ts +11 -14
  101. package/src/hooks/use-dom-container.ts +32 -0
  102. package/src/hooks/use-event-listener.ts +4 -4
  103. package/src/hooks/use-geolocation.ts +63 -0
  104. package/src/hooks/use-in-view.ts +9 -11
  105. package/src/hooks/use-intersection-observer.ts +19 -0
  106. package/src/hooks/use-modal-in-container.ts +60 -52
  107. package/src/hooks/use-modal-transition.ts +54 -0
  108. package/src/hooks/use-modal.ts +21 -0
  109. package/src/hooks/use-mouse-position.ts +55 -7
  110. package/src/hooks/use-resize-observer.ts +18 -0
  111. package/src/stories/GettingStarted.mdx +2 -6
  112. package/svg/Name=npm, Category=social.svg +3 -0
  113. package/dist/chunk-M4KRSYE7.js +0 -3
  114. package/dist/chunk-M4KRSYE7.js.map +0 -1
  115. package/dist/chunk-U5XSMSKZ.js +0 -3
  116. package/dist/chunk-U5XSMSKZ.js.map +0 -1
  117. package/dist/get-modal-position-DPftPoU2.d.cts +0 -28
  118. package/dist/get-modal-position-DPftPoU2.d.ts +0 -28
  119. package/src/components/form/select/select-option.tsx +0 -84
  120. package/src/hooks/use-observer.ts +0 -18
  121. package/src/hooks/use-on-click-outside-ref.ts +0 -17
@@ -1,47 +1,49 @@
1
- import axios, { AxiosInstance } from 'axios';
2
-
3
- export class HttpClient {
4
- private _instance: AxiosInstance;
5
- private _token: string;
6
-
7
- public logout = () => localStorage.removeItem('token');
8
-
9
- constructor(baseURL: string) {
10
- this._token = localStorage.getItem('token') ?? '';
11
-
12
- this._instance = axios.create({
13
- baseURL: baseURL,
14
- headers: {
15
- 'Content-Type': 'application/json',
16
- },
17
- });
18
-
19
- this._instance.interceptors.request.use(req => {
20
- const token = this.token;
21
- token !== null && req.headers.setAuthorization(`Bearer ${token}`);
22
-
23
- return req;
24
- });
25
-
26
- this._instance.interceptors.response.use(
27
- response => Promise.resolve(response),
28
- error => {
29
- error.response.status === 401 && this.logout();
30
- Promise.reject(error);
31
- },
32
- );
33
- }
34
-
35
- public get instance(): AxiosInstance {
36
- return this._instance;
37
- }
38
-
39
- public get token() {
40
- return this._token;
41
- }
42
-
43
- public set token(token: string) {
44
- this._token = token;
45
- localStorage.setItem('token', token);
46
- }
47
- }
1
+ /*
2
+ * import axios, { AxiosInstance } from 'axios';
3
+ *
4
+ * export class HttpClient {
5
+ * private _instance: AxiosInstance;
6
+ * private _token: string;
7
+ *
8
+ * public logout = () => localStorage.removeItem('token');
9
+ *
10
+ * constructor(baseURL: string) {
11
+ * this._token = localStorage.getItem('token') ?? '';
12
+ *
13
+ * this._instance = axios.create({
14
+ * baseURL: baseURL,
15
+ * headers: {
16
+ * 'Content-Type': 'application/json',
17
+ * },
18
+ * });
19
+ *
20
+ * this._instance.interceptors.request.use(req => {
21
+ * const token = this.token;
22
+ * token !== null && req.headers.setAuthorization(`Bearer ${token}`);
23
+ *
24
+ * return req;
25
+ * });
26
+ *
27
+ * this._instance.interceptors.response.use(
28
+ * response => Promise.resolve(response),
29
+ * error => {
30
+ * error.response.status === 401 && this.logout();
31
+ * Promise.reject(error);
32
+ * },
33
+ * );
34
+ * }
35
+ *
36
+ * public get instance(): AxiosInstance {
37
+ * return this._instance;
38
+ * }
39
+ *
40
+ * public get token() {
41
+ * return this._token;
42
+ * }
43
+ *
44
+ * public set token(token: string) {
45
+ * this._token = token;
46
+ * localStorage.setItem('token', token);
47
+ * }
48
+ * }
49
+ */
@@ -1,36 +1,9 @@
1
- import { useClassNames } from '@polpo/hooks';
2
-
3
1
  export enum ColorVariants {
4
- Primary = 'small',
5
- Secondary = 'medium',
6
- Tertiary = 'large',
2
+ Primary = 'primary',
3
+ Secondary = 'secondary',
4
+ Tertiary = 'tertiary',
7
5
  Info = 'info',
8
6
  Active = 'active',
9
7
  Warning = 'warning',
10
8
  Alert = 'alert',
11
9
  }
12
-
13
- const getColorVariantClassName = (size: `${ColorVariants}`) => {
14
- return `${size}-color`;
15
- };
16
-
17
- export const ColorClassNames: Record<keyof typeof ColorVariants, string> = {
18
- Primary: getColorVariantClassName(ColorVariants.Primary),
19
- Secondary: getColorVariantClassName(ColorVariants.Secondary),
20
- Tertiary: getColorVariantClassName(ColorVariants.Tertiary),
21
- Info: getColorVariantClassName(ColorVariants.Info),
22
- Active: getColorVariantClassName(ColorVariants.Active),
23
- Warning: getColorVariantClassName(ColorVariants.Warning),
24
- Alert: getColorVariantClassName(ColorVariants.Alert),
25
- };
26
-
27
- export const useColorClassName = (size: `${ColorVariants}`) =>
28
- useClassNames(
29
- Object.entries(ColorVariants).reduce(
30
- (object, [key, value]) => ({
31
- ...object,
32
- [ColorClassNames[key as keyof typeof ColorVariants]]: size === value,
33
- }),
34
- {},
35
- ),
36
- );
@@ -1,7 +1,5 @@
1
1
  import { css } from 'styled-components';
2
2
 
3
- import { useClassNames } from '@polpo/hooks';
4
-
5
3
  export enum RadiusVariants {
6
4
  None = 'none',
7
5
  Small = 'small',
@@ -10,47 +8,20 @@ export enum RadiusVariants {
10
8
  Full = 'full',
11
9
  }
12
10
 
13
- const getRadiusVariantClassName = (size: `${RadiusVariants}`) => {
14
- return `${size}-radius`;
15
- };
16
-
17
- export const RadiusClassNames: Record<keyof typeof RadiusVariants, string> = {
18
- None: getRadiusVariantClassName(RadiusVariants.None),
19
- Small: getRadiusVariantClassName(RadiusVariants.Small),
20
- Medium: getRadiusVariantClassName(RadiusVariants.Medium),
21
- Large: getRadiusVariantClassName(RadiusVariants.Large),
22
- Full: getRadiusVariantClassName(RadiusVariants.Full),
23
- };
24
-
25
- export const useRadiusClassName = (size: `${RadiusVariants}`) =>
26
- useClassNames(
27
- Object.entries(RadiusVariants).reduce(
28
- (object, [key, value]) => ({
29
- ...object,
30
- [RadiusClassNames[key as keyof typeof RadiusVariants]]: size === value,
31
- }),
32
- {},
33
- ),
34
- );
35
-
36
- export const RadiusStyles = css`
37
- &.${RadiusClassNames.None} {
11
+ export const RadiusStyles: Record<RadiusVariants, ReturnType<typeof css>> = {
12
+ [RadiusVariants.None]: css`
38
13
  border-radius: 0;
39
- }
40
-
41
- &.${RadiusClassNames.Small} {
14
+ `,
15
+ [RadiusVariants.Small]: css`
42
16
  border-radius: 0.5em;
43
- }
44
-
45
- &.${RadiusClassNames.Medium} {
17
+ `,
18
+ [RadiusVariants.Medium]: css`
46
19
  border-radius: 1em;
47
- }
48
-
49
- &.${RadiusClassNames.Large} {
20
+ `,
21
+ [RadiusVariants.Large]: css`
50
22
  border-radius: 1.5em;
51
- }
52
-
53
- &.${RadiusClassNames.Full} {
23
+ `,
24
+ [RadiusVariants.Full]: css`
54
25
  border-radius: 100em;
55
- }
56
- `;
26
+ `,
27
+ };
@@ -1,44 +1,19 @@
1
1
  import { css } from 'styled-components';
2
2
 
3
- import { useClassNames } from '@polpo/hooks';
4
-
5
3
  export enum SizeVariants {
6
4
  Small = 'small',
7
5
  Medium = 'medium',
8
6
  Large = 'large',
9
7
  }
10
8
 
11
- const getSizeVariantClassName = (size: `${SizeVariants}`) => {
12
- return `${size}-size`;
13
- };
14
-
15
- export const SizeClassNames: Record<keyof typeof SizeVariants, string> = {
16
- Small: getSizeVariantClassName(SizeVariants.Small),
17
- Medium: getSizeVariantClassName(SizeVariants.Medium),
18
- Large: getSizeVariantClassName(SizeVariants.Large),
19
- };
20
-
21
- export const useSizeClassName = (size: `${SizeVariants}`) =>
22
- useClassNames(
23
- Object.entries(SizeVariants).reduce(
24
- (object, [key, value]) => ({
25
- ...object,
26
- [SizeClassNames[key as keyof typeof SizeVariants]]: size === value,
27
- }),
28
- {},
29
- ),
30
- );
31
-
32
- export const SizeStyles = css`
33
- &.${SizeClassNames.Small} {
9
+ export const SizeStyles: Record<SizeVariants, ReturnType<typeof css>> = {
10
+ [SizeVariants.Small]: css`
34
11
  font-size: ${props => props.theme.constants.typography.small.fontSize};
35
- }
36
-
37
- &.${SizeClassNames.Medium} {
12
+ `,
13
+ [SizeVariants.Medium]: css`
38
14
  font-size: ${props => props.theme.constants.typography.label.fontSize};
39
- }
40
-
41
- &.${SizeClassNames.Large} {
15
+ `,
16
+ [SizeVariants.Large]: css`
42
17
  font-size: ${props => props.theme.constants.typography.body.fontSize};
43
- }
44
- `;
18
+ `,
19
+ };
@@ -0,0 +1,86 @@
1
+ import { PositionContainer } from './get-modal-position';
2
+
3
+ export type GetModalPositionRelativeToScreenParams = {
4
+ position: PositionContainer;
5
+ windowOffset: number;
6
+ };
7
+
8
+ export const getModalPositionRelativeToScreen = ({
9
+ position,
10
+ windowOffset,
11
+ }: GetModalPositionRelativeToScreenParams): Record<string, string> => {
12
+ switch (position) {
13
+ case PositionContainer.CENTER:
14
+ return {
15
+ top: '50%',
16
+ left: '50%',
17
+ transform: 'translate(-50%, -50%)',
18
+ };
19
+
20
+ case PositionContainer.TOP:
21
+ case PositionContainer.TOP_CENTER:
22
+ return {
23
+ top: `${windowOffset}px`,
24
+ left: '50%',
25
+ transform: 'translateX(-50%)',
26
+ };
27
+
28
+ case PositionContainer.TOP_LEFT:
29
+ case PositionContainer.LEFT_TOP:
30
+ return {
31
+ top: `${windowOffset}px`,
32
+ left: `${windowOffset}px`,
33
+ };
34
+
35
+ case PositionContainer.TOP_RIGHT:
36
+ case PositionContainer.RIGHT_TOP:
37
+ return {
38
+ top: `${windowOffset}px`,
39
+ right: `${windowOffset}px`,
40
+ };
41
+
42
+ case PositionContainer.BOTTOM:
43
+ case PositionContainer.BOTTOM_CENTER:
44
+ return {
45
+ bottom: `${windowOffset}px`,
46
+ left: '50%',
47
+ transform: 'translateX(-50%)',
48
+ };
49
+
50
+ case PositionContainer.LEFT_BOTTOM:
51
+ case PositionContainer.BOTTOM_LEFT:
52
+ return {
53
+ bottom: `${windowOffset}px`,
54
+ left: `${windowOffset}px`,
55
+ };
56
+
57
+ case PositionContainer.RIGHT_BOTTOM:
58
+ case PositionContainer.BOTTOM_RIGHT:
59
+ return {
60
+ bottom: `${windowOffset}px`,
61
+ right: `${windowOffset}px`,
62
+ };
63
+
64
+ case PositionContainer.LEFT:
65
+ case PositionContainer.LEFT_CENTER:
66
+ return {
67
+ top: '50%',
68
+ left: `${windowOffset}px`,
69
+ transform: 'translateY(-50%)',
70
+ };
71
+
72
+ case PositionContainer.RIGHT:
73
+ case PositionContainer.RIGHT_CENTER:
74
+ return {
75
+ top: '50%',
76
+ right: `${windowOffset}px`,
77
+ transform: 'translateY(-50%)',
78
+ };
79
+ }
80
+
81
+ return {
82
+ top: '50%',
83
+ left: '50%',
84
+ transform: 'translate(-50%, -50%)',
85
+ };
86
+ };
@@ -1,8 +1,21 @@
1
- export enum POSITION {
2
- top = 'top',
3
- left = 'left',
4
- right = 'right',
5
- bottom = 'bottom',
1
+ export enum PositionContainer {
2
+ CENTER = 'center',
3
+ TOP = 'top',
4
+ TOP_LEFT = 'top left',
5
+ TOP_RIGHT = 'top right',
6
+ TOP_CENTER = 'top center',
7
+ LEFT = 'left',
8
+ LEFT_TOP = 'left top',
9
+ LEFT_BOTTOM = 'left bottom',
10
+ LEFT_CENTER = 'left center',
11
+ RIGHT = 'right',
12
+ RIGHT_TOP = 'right top',
13
+ RIGHT_BOTTOM = 'right bottom',
14
+ RIGHT_CENTER = 'right center',
15
+ BOTTOM = 'bottom',
16
+ BOTTOM_LEFT = 'bottom left',
17
+ BOTTOM_RIGHT = 'bottom right',
18
+ BOTTOM_CENTER = 'bottom center',
6
19
  }
7
20
 
8
21
  export type PositionObject = {
@@ -14,53 +27,185 @@ export type PositionObject = {
14
27
  h: number;
15
28
  };
16
29
 
30
+ export type ModalPosition = {
31
+ left: number;
32
+ top: number;
33
+ };
34
+
17
35
  export type GetModalPositionParams = {
18
36
  c: PositionObject;
19
37
  m: PositionObject;
20
38
  offset: number;
21
- windowOffset: number;
22
- position?: `${POSITION}`;
23
- distancePercentage?: number;
39
+ position: PositionContainer;
24
40
  };
25
41
 
26
- export const getModalPosition = ({
27
- c,
28
- m,
29
- offset,
30
- windowOffset,
31
- position,
32
- distancePercentage = 50,
33
- }: GetModalPositionParams) => {
42
+ /*
43
+ * @description Calculates the position of the modal relative to the container
44
+ *
45
+ * @param c - The container's position object
46
+ * @param m - The modal's position object
47
+ * @param offset - The offset between the container and the modal
48
+ * @param position - The position of the modal
49
+ *
50
+ * -----------------------------------------------------------------------------
51
+ * @returns The position of the modal relative to the container
52
+ */
53
+ export const getModalPosition = ({ c, m, offset, position }: GetModalPositionParams): ModalPosition => {
34
54
  // Default bottom
35
55
  let top = c.y + c.h + offset;
36
- let left = c.x - (m.w - c.w);
56
+ let left = c.x - (m.w - c.w) * (50 / 100);
37
57
 
38
58
  switch (position) {
39
- case POSITION.top:
59
+ case PositionContainer.TOP:
60
+ case PositionContainer.TOP_CENTER:
40
61
  top = c.y - m.h - offset;
41
- left = c.x - (m.w - c.w) * (distancePercentage / 100);
62
+ left = c.x - (m.w - c.w) / 2;
63
+
64
+ break;
65
+ case PositionContainer.TOP_LEFT:
66
+ top = c.y - m.h - offset;
67
+ left = c.x - m.w + c.w;
68
+
69
+ break;
70
+
71
+ case PositionContainer.TOP_RIGHT:
72
+ top = c.y - m.h - offset;
73
+ left = c.x;
74
+
75
+ break;
76
+
77
+ case PositionContainer.BOTTOM:
78
+ case PositionContainer.BOTTOM_CENTER:
79
+ top = c.y + c.h + offset;
80
+ left = c.x - (m.w - c.w) / 2;
42
81
 
43
82
  break;
44
- case POSITION.bottom:
83
+
84
+ case PositionContainer.BOTTOM_LEFT:
45
85
  top = c.y + c.h + offset;
46
- left = c.x - (m.w - c.w) * (distancePercentage / 100);
86
+ left = c.x - m.w + c.w;
87
+
88
+ break;
89
+
90
+ case PositionContainer.BOTTOM_RIGHT:
91
+ top = c.y + c.h + offset;
92
+ left = c.x;
93
+
94
+ break;
95
+
96
+ case PositionContainer.LEFT:
97
+ case PositionContainer.LEFT_CENTER:
98
+ top = c.y - (m.h - c.h) / 2;
99
+ left = c.x - m.w - offset;
47
100
 
48
101
  break;
49
- case POSITION.left:
50
- top = c.y - (m.h - c.h) * (distancePercentage / 100);
102
+
103
+ case PositionContainer.LEFT_TOP:
104
+ top = c.y - m.h + c.h;
51
105
  left = c.x - m.w - offset;
52
106
 
53
107
  break;
54
- case POSITION.right:
55
- top = c.y - (m.h - c.h) * (distancePercentage / 100);
108
+
109
+ case PositionContainer.LEFT_BOTTOM:
110
+ top = c.y;
111
+ left = c.x - m.w - offset;
112
+
113
+ break;
114
+
115
+ case PositionContainer.RIGHT:
116
+ case PositionContainer.RIGHT_CENTER:
117
+ top = c.y - (m.h - c.h) / 2;
56
118
  left = c.x + c.w + offset;
57
119
 
58
120
  break;
121
+
122
+ case PositionContainer.RIGHT_TOP:
123
+ top = c.y - m.h + c.h;
124
+ left = c.x + c.w + offset;
125
+
126
+ break;
127
+
128
+ case PositionContainer.RIGHT_BOTTOM:
129
+ top = c.y;
130
+ left = c.x + c.w + offset;
131
+
132
+ break;
133
+ }
134
+
135
+ return {
136
+ left: Math.round(left),
137
+ top: Math.round(top),
138
+ };
139
+ };
140
+
141
+ export const getOppositePosition = (
142
+ { top, left }: ModalPosition,
143
+ position: PositionContainer,
144
+ windowOffset: number,
145
+ m: PositionObject,
146
+ ) => {
147
+ const positions = position.split(' ');
148
+ const newPosition = [];
149
+ const rightOffset = left + m.w + windowOffset - window.innerWidth;
150
+ const bottomOffset = top + m.h + windowOffset - window.innerHeight;
151
+
152
+ for (const p of positions) {
153
+ if (p === PositionContainer.TOP && top < windowOffset) {
154
+ newPosition.push(PositionContainer.BOTTOM);
155
+ } else if (p === PositionContainer.LEFT && left < windowOffset) {
156
+ newPosition.push(PositionContainer.RIGHT);
157
+ } else if (p === PositionContainer.BOTTOM && bottomOffset > 0) {
158
+ newPosition.push(PositionContainer.TOP);
159
+ } else if (p === PositionContainer.RIGHT && rightOffset > 0) {
160
+ newPosition.push(PositionContainer.LEFT);
161
+ } else {
162
+ newPosition.push(p);
163
+ }
59
164
  }
60
165
 
166
+ return newPosition.join(' ') as PositionContainer;
167
+ };
168
+
169
+ export const fixModalPosition = ({ top, left }: ModalPosition, m: PositionObject, windowOffset: number) => {
170
+ const rightOffset = left + m.w + windowOffset - window.innerWidth;
171
+ const bottomOffset = top + m.h + windowOffset - window.innerHeight;
172
+
173
+ left = rightOffset > 0 ? left - rightOffset : left;
174
+ top = bottomOffset > 0 ? top - bottomOffset : top;
175
+
176
+ left = left < windowOffset ? windowOffset : left;
177
+ top = top < windowOffset ? windowOffset : top;
178
+
179
+ return { top, left };
180
+ };
181
+
182
+ type getModalPositionRelativeToContainerParams = GetModalPositionParams & {
183
+ windowOffset: number;
184
+ };
185
+
186
+ export const getModalPositionRelativeToContainer = ({
187
+ c,
188
+ m,
189
+ offset,
190
+ windowOffset,
191
+ position,
192
+ }: getModalPositionRelativeToContainerParams): Record<string, string> => {
193
+ const params = { c, m, offset, position };
194
+ let modalContainerStyle = getModalPosition(params);
195
+
196
+ const oppositePosition = getOppositePosition(modalContainerStyle, position, windowOffset, m);
197
+
198
+ if (oppositePosition !== position) {
199
+ modalContainerStyle = getModalPosition({
200
+ ...params,
201
+ position: oppositePosition,
202
+ });
203
+ }
204
+
205
+ const fixedPosition = fixModalPosition(modalContainerStyle, m, windowOffset);
206
+
61
207
  return {
62
- left:
63
- left + m.w + windowOffset > window.innerWidth ? c.left - (left + m.w - window.innerWidth) - windowOffset : left,
64
- top: top + m.h + windowOffset > window.innerHeight ? c.top - (top + m.h - window.innerHeight) - windowOffset : top,
208
+ left: `${fixedPosition.left}px`,
209
+ top: `${fixedPosition.top}px`,
65
210
  };
66
211
  };
@@ -1,4 +1,5 @@
1
1
  export * from './format-bytes';
2
2
  export * from './format-dates';
3
3
  export * from './get-modal-position';
4
+ export * from './get-modal-position-relative-to-screen';
4
5
  export * from './text';
@@ -1,20 +1,26 @@
1
1
  export * from './use-async';
2
- export * from './use-async';
3
2
  export * from './use-classnames';
3
+ export * from './use-click-outside';
4
4
  export * from './use-constant';
5
+ export * from './use-cookie';
5
6
  export * from './use-debounce';
6
7
  export * from './use-dimensions';
8
+ export * from './use-dom-container';
7
9
  export * from './use-event-listener';
8
10
  export * from './use-file-reader';
11
+ export * from './use-geolocation';
12
+ export * from './use-hover';
9
13
  export * from './use-in-view';
10
14
  export * from './use-input-handlers';
15
+ export * from './use-intersection-observer';
11
16
  export * from './use-media-query';
17
+ export * from './use-modal';
12
18
  export * from './use-modal-in-container';
19
+ export * from './use-modal-transition';
13
20
  export * from './use-mouse-position';
14
- export * from './use-observer';
15
- export * from './use-on-click-outside-ref';
16
21
  export * from './use-online-status';
17
22
  export * from './use-render-count';
23
+ export * from './use-resize-observer';
18
24
  export * from './use-safe-dispatch';
19
25
  export * from './use-scroll';
20
26
  export * from './use-state-history';
@@ -0,0 +1,32 @@
1
+ import { RefObject } from 'react';
2
+
3
+ import { useEventListener } from './use-event-listener';
4
+
5
+ const checkIsOutside = (ref: RefObject<HTMLElement>, target: Node) => {
6
+ return ref.current && !ref.current.contains(target);
7
+ };
8
+
9
+ export const useClickOutside = <T extends HTMLElement>(
10
+ ref: RefObject<T> | Array<RefObject<T>>,
11
+ callback: () => void,
12
+ ) => {
13
+ useEventListener('keydown', e => {
14
+ if (e.key === 'Escape') {
15
+ callback();
16
+ }
17
+ });
18
+
19
+ useEventListener('mousedown', event => {
20
+ const target = event.target as Node;
21
+
22
+ if (!target?.isConnected) {
23
+ return;
24
+ }
25
+
26
+ const isOutside = (Array.isArray(ref) ? ref : [ref]).every(r => checkIsOutside(r, target));
27
+
28
+ if (isOutside) {
29
+ callback();
30
+ }
31
+ });
32
+ };