@rescui/dropdown 0.8.3 → 0.8.4-RUI-262-Migrate-to-GH-Actions-Release-dummy-8695a904.3
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/package.json +7 -7
- package/lib/css-vars-utils.d.ts +0 -3
- package/lib/css-vars-utils.js +0 -20
- package/lib/custom-modifiers.d.ts +0 -12
- package/lib/custom-modifiers.js +0 -101
- package/lib/dropdown.d.ts +0 -43
- package/lib/dropdown.js +0 -273
- package/lib/dropdown.p.module.css.js +0 -15
- package/lib/index.css +0 -161
- package/lib/index.d.ts +0 -8
- package/lib/index.js +0 -9
- package/lib/use-dropdown-state.d.ts +0 -7
- package/lib/use-dropdown-state.js +0 -36
- package/lib/use-scrollable-container.d.ts +0 -14
- package/lib/use-scrollable-container.js +0 -49
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rescui/dropdown",
|
|
3
|
-
"version": "0.8.3",
|
|
3
|
+
"version": "0.8.4-RUI-262-Migrate-to-GH-Actions-Release-dummy-8695a904.3+8695a904",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "JetBrains",
|
|
@@ -29,15 +29,15 @@
|
|
|
29
29
|
"react-dom": ">=16.8.0 <20"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@rescui/colors": "
|
|
33
|
-
"@rescui/icons": "
|
|
34
|
-
"@rescui/scripts": "
|
|
35
|
-
"@rescui/typography": "
|
|
36
|
-
"@rescui/visual-regression": "
|
|
32
|
+
"@rescui/colors": "0.2.11-RUI-262-Migrate-to-GH-Actions-Release-dummy-8695a904.19+8695a904",
|
|
33
|
+
"@rescui/icons": "1.6.1-RUI-262-Migrate-to-GH-Actions-Release-dummy-8695a904.3+8695a904",
|
|
34
|
+
"@rescui/scripts": "0.5.1",
|
|
35
|
+
"@rescui/typography": "0.24.1-RUI-262-Migrate-to-GH-Actions-Release-dummy-8695a904.19+8695a904",
|
|
36
|
+
"@rescui/visual-regression": "0.1.2"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"build": "rescui-scripts build"
|
|
40
40
|
},
|
|
41
41
|
"nx": {},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "8695a9042a55369f8df8f03ffd61c988cd3d3df4"
|
|
43
43
|
}
|
package/lib/css-vars-utils.d.ts
DELETED
package/lib/css-vars-utils.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const PRIMARY_COLORS = ['--rs-color-primary-light-theme', '--rs-color-primary-dim-light-theme', '--rs-color-primary-fog-light-theme', '--rs-color-primary-t-dim-light-theme', '--rs-color-primary-t-fog-light-theme', '--rs-color-primary-dark-theme', '--rs-color-primary-dim-dark-theme', '--rs-color-primary-fog-dark-theme', '--rs-color-primary-t-dim-dark-theme', '--rs-color-primary-t-fog-dark-theme'];
|
|
2
|
-
|
|
3
|
-
const extractPrimaryColors = styles => {
|
|
4
|
-
const colors = {};
|
|
5
|
-
PRIMARY_COLORS.forEach(varName => {
|
|
6
|
-
colors[varName] = styles.getPropertyValue(varName) || 'initial';
|
|
7
|
-
});
|
|
8
|
-
return colors;
|
|
9
|
-
};
|
|
10
|
-
/** Check out `@rescui/colors/src/public-api.p.css` file */
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const extractThemeFromCss = styles => {
|
|
14
|
-
const themeDark = parseInt(styles.getPropertyValue('--rs-theme-dark'), 10) || 0;
|
|
15
|
-
const themeFlip = parseInt(styles.getPropertyValue('--rs-theme-flip'), 10) || 0;
|
|
16
|
-
const themeDarkCoefficient = themeDark * (1 - themeFlip) + themeFlip * (1 - themeDark);
|
|
17
|
-
return themeDarkCoefficient === 1 ? 'dark' : 'light';
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export { extractPrimaryColors, extractThemeFromCss };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Modifier } from 'react-popper';
|
|
2
|
-
import { Property } from 'csstype';
|
|
3
|
-
export declare type DropdownMaxWidth = 'trigger' | Property.MaxWidth;
|
|
4
|
-
export declare type DropdownMinWidth = 'trigger' | Property.MinWidth;
|
|
5
|
-
export declare const sameWidthModifier: Modifier<'sameWidth', {
|
|
6
|
-
maxWidth: DropdownMaxWidth;
|
|
7
|
-
minWidth: DropdownMinWidth;
|
|
8
|
-
}>;
|
|
9
|
-
export declare const applyMaxSize: Modifier<'applyMaxSize', {
|
|
10
|
-
leastMaxHeight: number;
|
|
11
|
-
maxHeight: number;
|
|
12
|
-
}>;
|
package/lib/custom-modifiers.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
function getMaxWidth(dropdownMaxWidth, referenceWidth) {
|
|
2
|
-
if (dropdownMaxWidth === 'trigger') {
|
|
3
|
-
return `${referenceWidth}px`;
|
|
4
|
-
} else if (typeof dropdownMaxWidth === 'number') {
|
|
5
|
-
return `${dropdownMaxWidth}px`;
|
|
6
|
-
} else if (dropdownMaxWidth) {
|
|
7
|
-
return dropdownMaxWidth;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
return undefined; //rely on CSS by default
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function getMinWidth(dropdownMinWidth, referenceWidth) {
|
|
14
|
-
if (dropdownMinWidth === 'trigger') {
|
|
15
|
-
return `${referenceWidth}px`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (typeof dropdownMinWidth === 'number') {
|
|
19
|
-
return `${dropdownMinWidth}px`;
|
|
20
|
-
} else if (dropdownMinWidth) {
|
|
21
|
-
return dropdownMinWidth;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return undefined; //rely on CSS by default
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const sameWidthModifier = {
|
|
28
|
-
name: 'sameWidth',
|
|
29
|
-
enabled: true,
|
|
30
|
-
phase: 'beforeWrite',
|
|
31
|
-
requires: ['computeStyles'],
|
|
32
|
-
fn: _ref => {
|
|
33
|
-
let {
|
|
34
|
-
state,
|
|
35
|
-
options: {
|
|
36
|
-
maxWidth,
|
|
37
|
-
minWidth
|
|
38
|
-
} = {}
|
|
39
|
-
} = _ref;
|
|
40
|
-
state.styles.popper.minWidth = getMinWidth(minWidth, state.rects.reference.width);
|
|
41
|
-
state.styles.popper.maxWidth = getMaxWidth(maxWidth, state.rects.reference.width);
|
|
42
|
-
},
|
|
43
|
-
effect: _ref2 => {
|
|
44
|
-
let {
|
|
45
|
-
state,
|
|
46
|
-
options: {
|
|
47
|
-
maxWidth,
|
|
48
|
-
minWidth
|
|
49
|
-
} = {}
|
|
50
|
-
} = _ref2;
|
|
51
|
-
state.elements.popper.style.minWidth = getMinWidth(minWidth, state.elements.reference.offsetWidth);
|
|
52
|
-
state.elements.popper.style.maxWidth = getMaxWidth(maxWidth, state.elements.reference.offsetWidth);
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
const applyMaxSize = {
|
|
57
|
-
name: 'applyMaxSize',
|
|
58
|
-
enabled: true,
|
|
59
|
-
phase: 'beforeWrite',
|
|
60
|
-
requires: ['maxSize'],
|
|
61
|
-
|
|
62
|
-
// eslint-disable-next-line complexity
|
|
63
|
-
fn(_ref3) {
|
|
64
|
-
let {
|
|
65
|
-
state,
|
|
66
|
-
options: {
|
|
67
|
-
leastMaxHeight = 0,
|
|
68
|
-
maxHeight = Infinity
|
|
69
|
-
}
|
|
70
|
-
} = _ref3;
|
|
71
|
-
const {
|
|
72
|
-
height
|
|
73
|
-
} = state.modifiersData.maxSize;
|
|
74
|
-
const heightLeft = height;
|
|
75
|
-
let resultHeightString;
|
|
76
|
-
|
|
77
|
-
if (maxHeight > heightLeft && heightLeft > leastMaxHeight) {
|
|
78
|
-
resultHeightString = `${heightLeft}px`;
|
|
79
|
-
|
|
80
|
-
if (state.styles.popper.maxHeight !== resultHeightString && state.rects.popper.height >= heightLeft) {
|
|
81
|
-
// change popper height for detectOverflow util to force flip modifier to find better placement
|
|
82
|
-
state.rects.popper.height = heightLeft;
|
|
83
|
-
state.reset = true;
|
|
84
|
-
}
|
|
85
|
-
} else if (heightLeft < leastMaxHeight) {
|
|
86
|
-
resultHeightString = `${leastMaxHeight}px`;
|
|
87
|
-
|
|
88
|
-
if (state.styles.popper.maxHeight !== resultHeightString && state.rects.popper.height >= leastMaxHeight) {
|
|
89
|
-
// change popper height for detectOverflow util to force flip modifier to find better placement
|
|
90
|
-
state.rects.popper.height = leastMaxHeight;
|
|
91
|
-
state.reset = true;
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
resultHeightString = `${maxHeight}px`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
state.styles.popper.maxHeight = resultHeightString;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
export { applyMaxSize, sameWidthModifier };
|
package/lib/dropdown.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import React, { ReactNode } from 'react';
|
|
2
|
-
import type { ReferenceChildrenProps } from 'react-popper';
|
|
3
|
-
import { Theme } from '@rescui/ui-contexts';
|
|
4
|
-
import type { Placement } from '@popperjs/core';
|
|
5
|
-
import { DropdownMaxWidth, DropdownMinWidth } from './custom-modifiers';
|
|
6
|
-
export declare type DropdownTrigger = ((props: ReferenceChildrenProps) => JSX.Element) | JSX.Element;
|
|
7
|
-
export interface DropdownProps {
|
|
8
|
-
trigger: DropdownTrigger;
|
|
9
|
-
isOpen: boolean;
|
|
10
|
-
onRequestClose?: () => void;
|
|
11
|
-
theme?: Theme;
|
|
12
|
-
maxHeight?: number;
|
|
13
|
-
/** Least possible maxHeight value, even if there is less space let on the screen. It's not the same thing as minHeight because actual height still depends on dropdown content which can be smaller. Eg. leastMaxHeight equals to item height at DropdownMenu */
|
|
14
|
-
leastMaxHeight?: number;
|
|
15
|
-
/**
|
|
16
|
-
* See [MDN spec](https://developer.mozilla.org/en-US/docs/Web/CSS/max-width).
|
|
17
|
-
* `trigger` is a special value that substitutes with trigger's width calculated on every dropdown position update
|
|
18
|
-
* @type 'trigger' | MinWidthProperty<string | number>;
|
|
19
|
-
* */
|
|
20
|
-
minWidth?: DropdownMinWidth;
|
|
21
|
-
/**
|
|
22
|
-
* See [MDN spec](https://developer.mozilla.org/en-US/docs/Web/CSS/min-width).
|
|
23
|
-
* `trigger` is a special value that substitutes with trigger's width calculated on every dropdown position update
|
|
24
|
-
* @type 'trigger' | MaxWidthProperty<string | number>;
|
|
25
|
-
* */
|
|
26
|
-
maxWidth?: DropdownMaxWidth;
|
|
27
|
-
className?: string;
|
|
28
|
-
mode?: 'classic' | 'rock';
|
|
29
|
-
placement?: Placement;
|
|
30
|
-
/** @ignore */
|
|
31
|
-
cancelCloseAnimation?: boolean;
|
|
32
|
-
children?: ReactNode;
|
|
33
|
-
closeOnEsc?: boolean;
|
|
34
|
-
closeOnTab?: boolean;
|
|
35
|
-
disableFocusLock?: boolean;
|
|
36
|
-
/** Render dropdown inside trigger function or wrapper. May be useful when the trigger placed in the fixed layout. */
|
|
37
|
-
renderInTrigger?: boolean;
|
|
38
|
-
}
|
|
39
|
-
export interface DropdownImperativeHandle {
|
|
40
|
-
scheduleUpdate: () => void;
|
|
41
|
-
}
|
|
42
|
-
export declare const Dropdown: React.ForwardRefExoticComponent<DropdownProps & React.RefAttributes<DropdownImperativeHandle>>;
|
|
43
|
-
export default Dropdown;
|
package/lib/dropdown.js
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import React, { useState, useEffect, useImperativeHandle, useContext, useCallback } from 'react';
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
4
|
-
import cn from 'classnames';
|
|
5
|
-
import { usePopper } from 'react-popper';
|
|
6
|
-
import maxSizeModifier from 'popper-max-size-modifier';
|
|
7
|
-
import { useLayeringContext, ThemeContext, getInverseTheme, LayeringProvider, ThemeProvider } from '@rescui/ui-contexts';
|
|
8
|
-
import FocusLock from 'react-focus-lock';
|
|
9
|
-
import ReactDOM from 'react-dom';
|
|
10
|
-
import { useDropdownState, DROPDOWN_STATES } from './use-dropdown-state.js';
|
|
11
|
-
import { useScrollableContainer } from './use-scrollable-container.js';
|
|
12
|
-
import styles from './dropdown.p.module.css.js';
|
|
13
|
-
import { applyMaxSize, sameWidthModifier } from './custom-modifiers.js';
|
|
14
|
-
import { extractThemeFromCss, extractPrimaryColors } from './css-vars-utils.js';
|
|
15
|
-
|
|
16
|
-
function getPopperOptions(_ref) {
|
|
17
|
-
let {
|
|
18
|
-
placement,
|
|
19
|
-
maxHeight,
|
|
20
|
-
leastMaxHeight,
|
|
21
|
-
maxWidth,
|
|
22
|
-
minWidth
|
|
23
|
-
} = _ref;
|
|
24
|
-
return {
|
|
25
|
-
placement,
|
|
26
|
-
modifiers: [{
|
|
27
|
-
name: 'hide',
|
|
28
|
-
enabled: false
|
|
29
|
-
}, {
|
|
30
|
-
name: 'flip',
|
|
31
|
-
enabled: true
|
|
32
|
-
}, {
|
|
33
|
-
name: 'offset',
|
|
34
|
-
enabled: true,
|
|
35
|
-
options: {
|
|
36
|
-
offset: [0, 8]
|
|
37
|
-
}
|
|
38
|
-
}, maxSizeModifier, { ...applyMaxSize,
|
|
39
|
-
options: {
|
|
40
|
-
maxHeight,
|
|
41
|
-
leastMaxHeight
|
|
42
|
-
}
|
|
43
|
-
}, { ...sameWidthModifier,
|
|
44
|
-
options: {
|
|
45
|
-
maxWidth,
|
|
46
|
-
minWidth
|
|
47
|
-
}
|
|
48
|
-
}]
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const Portal = _ref2 => {
|
|
53
|
-
let {
|
|
54
|
-
children,
|
|
55
|
-
target = typeof window !== 'undefined' ? document.body : undefined
|
|
56
|
-
} = _ref2;
|
|
57
|
-
return target ? /*#__PURE__*/ReactDOM.createPortal(children, target) : null;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
function useOnOutsideClick(_ref3) {
|
|
61
|
-
let {
|
|
62
|
-
onOutsideClick,
|
|
63
|
-
isEnabled,
|
|
64
|
-
ignoreElements = []
|
|
65
|
-
} = _ref3;
|
|
66
|
-
const ignoreElementRefsExists = ignoreElements.length > 0 && ignoreElements.every(Boolean);
|
|
67
|
-
const handleDocumentClick = useCallback(e => {
|
|
68
|
-
for (const element of ignoreElements) {
|
|
69
|
-
if (!element || e.target === element || element.contains(e.target)) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
onOutsideClick();
|
|
75
|
-
}, [onOutsideClick, ...ignoreElements]); // eslint-disable-next-line consistent-return
|
|
76
|
-
|
|
77
|
-
useEffect(() => {
|
|
78
|
-
if (isEnabled && ignoreElementRefsExists) {
|
|
79
|
-
document.addEventListener('click', handleDocumentClick, true);
|
|
80
|
-
return () => document.removeEventListener('click', handleDocumentClick, true);
|
|
81
|
-
}
|
|
82
|
-
}, [handleDocumentClick, isEnabled, ignoreElementRefsExists]);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function useKeyPress(_ref4) {
|
|
86
|
-
let {
|
|
87
|
-
key,
|
|
88
|
-
onKeyPress,
|
|
89
|
-
isEnabled
|
|
90
|
-
} = _ref4;
|
|
91
|
-
useEffect(() => {
|
|
92
|
-
if (!isEnabled) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const keyDownHandler = e => {
|
|
97
|
-
if (e.key === key) {
|
|
98
|
-
e.preventDefault();
|
|
99
|
-
onKeyPress();
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
document.addEventListener('keydown', keyDownHandler, true); // eslint-disable-next-line consistent-return
|
|
104
|
-
|
|
105
|
-
return () => {
|
|
106
|
-
document.removeEventListener('keydown', keyDownHandler, true);
|
|
107
|
-
};
|
|
108
|
-
}, [key, onKeyPress, isEnabled]);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const THEME_STYLES = {
|
|
112
|
-
light: styles.themeLight,
|
|
113
|
-
dark: styles.themeDark
|
|
114
|
-
};
|
|
115
|
-
const MODE_STYLES = {
|
|
116
|
-
classic: styles.modeClassic,
|
|
117
|
-
rock: styles.modeRock
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const DropdownRender = (_ref5, externalRef) => {
|
|
121
|
-
let {
|
|
122
|
-
children,
|
|
123
|
-
trigger,
|
|
124
|
-
theme: themeFromProps,
|
|
125
|
-
isOpen: isOpenFromProps = false,
|
|
126
|
-
placement = 'bottom-start',
|
|
127
|
-
mode = 'classic',
|
|
128
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
129
|
-
onRequestClose = () => {},
|
|
130
|
-
minWidth,
|
|
131
|
-
maxWidth,
|
|
132
|
-
maxHeight,
|
|
133
|
-
leastMaxHeight,
|
|
134
|
-
cancelCloseAnimation = false,
|
|
135
|
-
className,
|
|
136
|
-
closeOnEsc = true,
|
|
137
|
-
closeOnTab = false,
|
|
138
|
-
disableFocusLock = false,
|
|
139
|
-
renderInTrigger = false
|
|
140
|
-
} = _ref5;
|
|
141
|
-
const [popperRef, setPopperRef] = useState(null);
|
|
142
|
-
const [triggerRef, setTriggerRef] = useState(null);
|
|
143
|
-
const {
|
|
144
|
-
setContentEl,
|
|
145
|
-
scrollableStyles
|
|
146
|
-
} = useScrollableContainer(); // We set isOpen this way to avoid hydration issue due to
|
|
147
|
-
// the Portal to document.body which does not exist on the server.
|
|
148
|
-
// So even if isOpen prop is used, the tooltip will not render on the server, and
|
|
149
|
-
// it's the same on the first client render, so there is no hydration issue.
|
|
150
|
-
|
|
151
|
-
const [isFirstRender, setIsFirstRender] = useState(true);
|
|
152
|
-
useEffect(() => {
|
|
153
|
-
setIsFirstRender(false);
|
|
154
|
-
}, []);
|
|
155
|
-
const isOpen = isFirstRender && !renderInTrigger ? false : isOpenFromProps;
|
|
156
|
-
useOnOutsideClick({
|
|
157
|
-
isEnabled: isOpen,
|
|
158
|
-
onOutsideClick: onRequestClose,
|
|
159
|
-
ignoreElements: [popperRef, triggerRef]
|
|
160
|
-
});
|
|
161
|
-
useKeyPress({
|
|
162
|
-
key: 'Escape',
|
|
163
|
-
isEnabled: isOpen && closeOnEsc,
|
|
164
|
-
onKeyPress: onRequestClose
|
|
165
|
-
});
|
|
166
|
-
useKeyPress({
|
|
167
|
-
key: 'Tab',
|
|
168
|
-
isEnabled: isOpen && closeOnTab,
|
|
169
|
-
onKeyPress: onRequestClose
|
|
170
|
-
});
|
|
171
|
-
const [handleAnimationEnd, dropdownState] = useDropdownState(isOpen, cancelCloseAnimation);
|
|
172
|
-
const {
|
|
173
|
-
styles: popperStyles,
|
|
174
|
-
attributes,
|
|
175
|
-
update
|
|
176
|
-
} = usePopper(triggerRef, popperRef, getPopperOptions({
|
|
177
|
-
placement,
|
|
178
|
-
maxHeight,
|
|
179
|
-
leastMaxHeight,
|
|
180
|
-
minWidth,
|
|
181
|
-
maxWidth
|
|
182
|
-
}));
|
|
183
|
-
useImperativeHandle(externalRef, () => ({
|
|
184
|
-
scheduleUpdate: () => {
|
|
185
|
-
if (update) {
|
|
186
|
-
update();
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}));
|
|
190
|
-
const {
|
|
191
|
-
dropdownZIndex
|
|
192
|
-
} = useLayeringContext();
|
|
193
|
-
const triggerRenderer = typeof trigger === 'function' ? trigger({
|
|
194
|
-
ref: setTriggerRef
|
|
195
|
-
}) : /*#__PURE__*/React.createElement("span", {
|
|
196
|
-
"data-test": "dropdown-trigger",
|
|
197
|
-
className: styles.triggerWrapper,
|
|
198
|
-
ref: setTriggerRef
|
|
199
|
-
}, trigger);
|
|
200
|
-
const dropdownShouldBeRendered = dropdownState !== DROPDOWN_STATES.CLOSE;
|
|
201
|
-
const wrapperShouldBeHidden = dropdownState === DROPDOWN_STATES.CLOSING;
|
|
202
|
-
let primaryColors = {};
|
|
203
|
-
let themeFromCss = 'light';
|
|
204
|
-
|
|
205
|
-
if (triggerRef && dropdownShouldBeRendered) {
|
|
206
|
-
// In theory this part of the code might cause issues with SSR.
|
|
207
|
-
// But in this specific context, because of the nature of the state-ref "triggerRef",
|
|
208
|
-
// we are sure that the dropdown wouldn't be rendered on the first client render.
|
|
209
|
-
// Therefore, the first render on the client will be the same as on the server.
|
|
210
|
-
const triggerStyles = getComputedStyle(triggerRef);
|
|
211
|
-
themeFromCss = extractThemeFromCss(triggerStyles);
|
|
212
|
-
primaryColors = extractPrimaryColors(triggerStyles);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const {
|
|
216
|
-
theme: themeFromContext,
|
|
217
|
-
noProvider
|
|
218
|
-
} = useContext(ThemeContext);
|
|
219
|
-
const theme = themeFromProps || (noProvider ? themeFromCss : themeFromContext);
|
|
220
|
-
const childrenTheme = mode === 'rock' ? getInverseTheme(theme) : theme;
|
|
221
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null, triggerRenderer, dropdownShouldBeRendered && /*#__PURE__*/React.createElement(Portal, {
|
|
222
|
-
target: renderInTrigger ? triggerRef : undefined
|
|
223
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
224
|
-
ref: setPopperRef,
|
|
225
|
-
style: {
|
|
226
|
-
maxHeight,
|
|
227
|
-
...popperStyles.popper,
|
|
228
|
-
zIndex: dropdownZIndex,
|
|
229
|
-
...primaryColors
|
|
230
|
-
},
|
|
231
|
-
className: cn(styles.dropdown, className, MODE_STYLES[mode], THEME_STYLES[theme]),
|
|
232
|
-
"data-test": "dropdown",
|
|
233
|
-
...attributes.popper
|
|
234
|
-
}, /*#__PURE__*/React.createElement(LayeringProvider, {
|
|
235
|
-
baseLayer: 'dropdown'
|
|
236
|
-
}, /*#__PURE__*/React.createElement("div", {
|
|
237
|
-
style: scrollableStyles,
|
|
238
|
-
className: cn(styles.contentWrapper, wrapperShouldBeHidden && styles.wrapperHidden),
|
|
239
|
-
onTransitionEnd: handleAnimationEnd,
|
|
240
|
-
onAnimationEnd: handleAnimationEnd,
|
|
241
|
-
"data-test": "dropdown-content"
|
|
242
|
-
}, /*#__PURE__*/React.createElement(ThemeProvider, {
|
|
243
|
-
ignoreThemeValueForCSSApi: noProvider,
|
|
244
|
-
theme: childrenTheme
|
|
245
|
-
}, /*#__PURE__*/React.createElement(FocusLock, {
|
|
246
|
-
className: THEME_STYLES[childrenTheme],
|
|
247
|
-
ref: setContentEl,
|
|
248
|
-
disabled: dropdownState !== DROPDOWN_STATES.OPEN || disableFocusLock,
|
|
249
|
-
returnFocus: {
|
|
250
|
-
preventScroll: true
|
|
251
|
-
},
|
|
252
|
-
focusOptions: {
|
|
253
|
-
preventScroll: true
|
|
254
|
-
}
|
|
255
|
-
}, children)))))));
|
|
256
|
-
};
|
|
257
|
-
/* eslint-enable react/prop-types */
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const Dropdown = /*#__PURE__*/React.forwardRef(DropdownRender);
|
|
261
|
-
Dropdown.propTypes = {
|
|
262
|
-
trigger: PropTypes.oneOfType([PropTypes.element, PropTypes.func]).isRequired,
|
|
263
|
-
isOpen: PropTypes.bool.isRequired,
|
|
264
|
-
onRequestClose: PropTypes.func,
|
|
265
|
-
theme: PropTypes.oneOf(['light', 'dark']),
|
|
266
|
-
mode: PropTypes.oneOf(['classic', 'rock']),
|
|
267
|
-
placement: PropTypes.oneOf(['auto-start', 'auto', 'auto-end', 'top-start', 'top', 'top-end', 'right-start', 'right', 'right-end', 'bottom-end', 'bottom', 'bottom-start', 'left-end', 'left', 'left-start']),
|
|
268
|
-
minWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
269
|
-
maxWidth: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
|
|
270
|
-
maxHeight: PropTypes.number,
|
|
271
|
-
leastMaxHeight: PropTypes.number
|
|
272
|
-
};
|
|
273
|
-
export { Dropdown, Dropdown as default };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
var styles = {
|
|
2
|
-
"themeLight": "_themeLight_1eyuq1h_60",
|
|
3
|
-
"themeDark": "_themeDark_1eyuq1h_63",
|
|
4
|
-
"dropdown": "_dropdown_1eyuq1h_67",
|
|
5
|
-
"triggerWrapper": "_triggerWrapper_1eyuq1h_74",
|
|
6
|
-
"contentWrapper": "_contentWrapper_1eyuq1h_78",
|
|
7
|
-
"fadeInBottomToTop": "_fadeInBottomToTop_1eyuq1h_1",
|
|
8
|
-
"fadeInTopToBottom": "_fadeInTopToBottom_1eyuq1h_1",
|
|
9
|
-
"fadeInLeftToRight": "_fadeInLeftToRight_1eyuq1h_1",
|
|
10
|
-
"fadeInRightToLeft": "_fadeInRightToLeft_1eyuq1h_1",
|
|
11
|
-
"wrapperHidden": "_wrapperHidden_1eyuq1h_109",
|
|
12
|
-
"modeClassic": "_modeClassic_1eyuq1h_129",
|
|
13
|
-
"modeRock": "_modeRock_1eyuq1h_133"
|
|
14
|
-
};
|
|
15
|
-
export { styles as default };
|
package/lib/index.css
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
@keyframes _fadeInTopToBottom_1eyuq1h_1{
|
|
2
|
-
0%{
|
|
3
|
-
opacity:0;
|
|
4
|
-
|
|
5
|
-
transform:translateY(-10px);
|
|
6
|
-
}
|
|
7
|
-
100%{
|
|
8
|
-
opacity:1;
|
|
9
|
-
|
|
10
|
-
transform:none;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
@keyframes _fadeInBottomToTop_1eyuq1h_1{
|
|
14
|
-
0%{
|
|
15
|
-
opacity:0;
|
|
16
|
-
|
|
17
|
-
transform:translateY(10px);
|
|
18
|
-
}
|
|
19
|
-
100%{
|
|
20
|
-
opacity:1;
|
|
21
|
-
|
|
22
|
-
transform:none;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
@keyframes _fadeInLeftToRight_1eyuq1h_1{
|
|
26
|
-
0%{
|
|
27
|
-
opacity:0;
|
|
28
|
-
|
|
29
|
-
transform:translateX(-10px);
|
|
30
|
-
}
|
|
31
|
-
100%{
|
|
32
|
-
opacity:1;
|
|
33
|
-
|
|
34
|
-
transform:none;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
@keyframes _fadeInRightToLeft_1eyuq1h_1{
|
|
38
|
-
0%{
|
|
39
|
-
opacity:0;
|
|
40
|
-
|
|
41
|
-
transform:translateX(10px);
|
|
42
|
-
}
|
|
43
|
-
100%{
|
|
44
|
-
opacity:1;
|
|
45
|
-
|
|
46
|
-
transform:none;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
._themeLight_1eyuq1h_60{
|
|
50
|
-
--rs-theme-dark:0;
|
|
51
|
-
}
|
|
52
|
-
._themeDark_1eyuq1h_63{
|
|
53
|
-
--rs-theme-dark:1;
|
|
54
|
-
}
|
|
55
|
-
._dropdown_1eyuq1h_67{
|
|
56
|
-
--_rs-theme-dark:var(
|
|
57
|
-
--_rs-internal-force-theme-dark-consult-rescui-before-using,
|
|
58
|
-
var(--rs-theme-dark, 0)
|
|
59
|
-
);
|
|
60
|
-
--_rs-theme-flip:var(--rs-theme-flip, 0);
|
|
61
|
-
--_rs-theme-dark-coefficient:calc(var(--_rs-theme-dark)*(1 - var(--_rs-theme-flip)) + var(--_rs-theme-flip)*(1 - var(--_rs-theme-dark)));
|
|
62
|
-
--_rs-theme-light-coefficient:calc(1 - var(--_rs-theme-dark-coefficient));
|
|
63
|
-
}
|
|
64
|
-
@supports (color: color-mix(in srgb, #fff 50%, #000 50%)){
|
|
65
|
-
._dropdown_1eyuq1h_67{
|
|
66
|
-
--_rs-color-primary:color-mix(in srgb, var(--rs-color-primary-light-theme, #6B57FF) calc(100%*var(--_rs-theme-light-coefficient, 1)), var(--rs-color-primary-dark-theme, #8473FF) calc(100%*var(--_rs-theme-dark-coefficient, 0)));
|
|
67
|
-
--_rs-color-primary-dim:color-mix(in srgb, var(--rs-color-primary-dim-light-theme, #8979ff) calc(100%*var(--_rs-theme-light-coefficient, 1)), var(--rs-color-primary-dim-dark-theme, #6f61d2) calc(100%*var(--_rs-theme-dark-coefficient, 0)));
|
|
68
|
-
--_rs-color-primary-fog:color-mix(in srgb, var(--rs-color-primary-fog-light-theme, #e1ddff) calc(100%*var(--_rs-theme-light-coefficient, 1)), var(--rs-color-primary-fog-dark-theme, #2e2b49) calc(100%*var(--_rs-theme-dark-coefficient, 0)));
|
|
69
|
-
--_rs-color-primary-t-dim:color-mix(in srgb, var(--rs-color-primary-t-dim-light-theme, rgba(107, 87, 255, 0.8)) calc(100%*var(--_rs-theme-light-coefficient, 1)), var(--rs-color-primary-t-dim-dark-theme, rgba(132, 115, 255,0.8)) calc(100%*var(--_rs-theme-dark-coefficient, 0)));
|
|
70
|
-
--_rs-color-primary-t-fog:color-mix(in srgb, var(--rs-color-primary-t-fog-light-theme, rgba(107, 87, 255,0.2)) calc(100%*var(--_rs-theme-light-coefficient, 1)), var(--rs-color-primary-t-fog-dark-theme, rgba(132, 115, 255,0.3)) calc(100%*var(--_rs-theme-dark-coefficient, 0)));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
@supports not (color: color-mix(in srgb, #fff 50%, #000 50%)){
|
|
74
|
-
._dropdown_1eyuq1h_67{
|
|
75
|
-
--_rs-color-primary:rgb(calc(var(--_rs-theme-light-coefficient, 1)*107 + var(--_rs-theme-dark-coefficient, 0)*132), calc(var(--_rs-theme-light-coefficient, 1)*87 + var(--_rs-theme-dark-coefficient, 0)*115), 255);
|
|
76
|
-
--_rs-color-primary-dim:rgb(calc(var(--_rs-theme-light-coefficient, 1)*137 + var(--_rs-theme-dark-coefficient, 0)*111), calc(var(--_rs-theme-light-coefficient, 1)*121 + var(--_rs-theme-dark-coefficient, 0)*97), calc(var(--_rs-theme-light-coefficient, 1)*255 + var(--_rs-theme-dark-coefficient, 0)*210));
|
|
77
|
-
--_rs-color-primary-fog:rgb(calc(var(--_rs-theme-light-coefficient, 1)*225 + var(--_rs-theme-dark-coefficient, 0)*46), calc(var(--_rs-theme-light-coefficient, 1)*221 + var(--_rs-theme-dark-coefficient, 0)*43), calc(var(--_rs-theme-light-coefficient, 1)*255 + var(--_rs-theme-dark-coefficient, 0)*73));
|
|
78
|
-
--_rs-color-primary-t-dim:rgba(calc(var(--_rs-theme-light-coefficient, 1)*107 + var(--_rs-theme-dark-coefficient, 0)*132), calc(var(--_rs-theme-light-coefficient, 1)*87 + var(--_rs-theme-dark-coefficient, 0)*115), 255, 0.8);
|
|
79
|
-
--_rs-color-primary-t-fog:rgba(calc(var(--_rs-theme-light-coefficient, 1)*107 + var(--_rs-theme-dark-coefficient, 0)*132), calc(var(--_rs-theme-light-coefficient, 1)*87 + var(--_rs-theme-dark-coefficient, 0)*115), 255, calc(var(--_rs-theme-light-coefficient, 1)*0.2 + var(--_rs-theme-dark-coefficient, 0)*0.3));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
._dropdown_1eyuq1h_67 {
|
|
83
|
-
display:flex;
|
|
84
|
-
flex-direction:column;
|
|
85
|
-
}
|
|
86
|
-
._triggerWrapper_1eyuq1h_74{
|
|
87
|
-
display:inline-block;
|
|
88
|
-
}
|
|
89
|
-
._contentWrapper_1eyuq1h_78{
|
|
90
|
-
position:relative;
|
|
91
|
-
|
|
92
|
-
display:block;
|
|
93
|
-
overflow-y:auto;
|
|
94
|
-
|
|
95
|
-
box-sizing:border-box;
|
|
96
|
-
margin:1px;
|
|
97
|
-
|
|
98
|
-
background-clip:padding-box;
|
|
99
|
-
box-shadow:0 0 0 1px rgb(calc(209 - var(--_rs-theme-dark-coefficient, 0)*92), calc(209 - var(--_rs-theme-dark-coefficient, 0)*92), calc(210 - var(--_rs-theme-dark-coefficient, 0)*91));
|
|
100
|
-
|
|
101
|
-
transition:opacity linear 200ms, transform linear 200ms;
|
|
102
|
-
}
|
|
103
|
-
[data-popper-placement^="top" ] ._contentWrapper_1eyuq1h_78{
|
|
104
|
-
animation:_fadeInBottomToTop_1eyuq1h_1 ease 200ms;
|
|
105
|
-
}
|
|
106
|
-
[data-popper-placement^="bottom" ] ._contentWrapper_1eyuq1h_78{
|
|
107
|
-
animation:_fadeInTopToBottom_1eyuq1h_1 ease 200ms;
|
|
108
|
-
}
|
|
109
|
-
[data-popper-placement^="right"] ._contentWrapper_1eyuq1h_78{
|
|
110
|
-
animation:_fadeInLeftToRight_1eyuq1h_1 ease 200ms;
|
|
111
|
-
}
|
|
112
|
-
[data-popper-placement^="left"] ._contentWrapper_1eyuq1h_78{
|
|
113
|
-
animation:_fadeInRightToLeft_1eyuq1h_1 ease 200ms;
|
|
114
|
-
}
|
|
115
|
-
._wrapperHidden_1eyuq1h_109{
|
|
116
|
-
opacity:0;
|
|
117
|
-
}
|
|
118
|
-
[data-popper-placement^="top" ] ._wrapperHidden_1eyuq1h_109{
|
|
119
|
-
transform:translateY(10px);
|
|
120
|
-
}
|
|
121
|
-
[data-popper-placement^="bottom" ] ._wrapperHidden_1eyuq1h_109{
|
|
122
|
-
transform:translateY(-10px);
|
|
123
|
-
}
|
|
124
|
-
[data-popper-placement^="right"] ._wrapperHidden_1eyuq1h_109{
|
|
125
|
-
transform:translateX(-10px);
|
|
126
|
-
}
|
|
127
|
-
[data-popper-placement^="left"] ._wrapperHidden_1eyuq1h_109{
|
|
128
|
-
transform:translateX(10px);
|
|
129
|
-
}
|
|
130
|
-
._modeClassic_1eyuq1h_129 ._contentWrapper_1eyuq1h_78{
|
|
131
|
-
background-color:rgb(calc(255 - var(--_rs-theme-dark-coefficient, 0)*207), calc(255 - var(--_rs-theme-dark-coefficient, 0)*207), calc(255 - var(--_rs-theme-dark-coefficient, 0)*204));
|
|
132
|
-
}
|
|
133
|
-
._modeRock_1eyuq1h_133 ._contentWrapper_1eyuq1h_78{
|
|
134
|
-
background-color:rgb(calc(25 + var(--_rs-theme-dark-coefficient, 0)*230), calc(25 + var(--_rs-theme-dark-coefficient, 0)*230), calc(28 + var(--_rs-theme-dark-coefficient, 0)*227));
|
|
135
|
-
}
|
|
136
|
-
._modeRock_1eyuq1h_133{
|
|
137
|
-
--rs-parent-color-primary-light-theme:var(--rs-color-primary-light-theme);
|
|
138
|
-
--rs-parent-color-primary-dim-light-theme:var(--rs-color-primary-dim-light-theme);
|
|
139
|
-
--rs-parent-color-primary-fog-light-theme:var(--rs-color-primary-fog-light-theme);
|
|
140
|
-
--rs-parent-color-primary-t-dim-light-theme:var(--rs-color-primary-t-dim-light-theme);
|
|
141
|
-
--rs-parent-color-primary-t-fog-light-theme:var(--rs-color-primary-t-fog-light-theme);
|
|
142
|
-
|
|
143
|
-
--rs-parent-color-primary-dark-theme:var(--rs-color-primary-dark-theme);
|
|
144
|
-
--rs-parent-color-primary-dim-dark-theme:var(--rs-color-primary-dim-dark-theme);
|
|
145
|
-
--rs-parent-color-primary-fog-dark-theme:var(--rs-color-primary-fog-dark-theme);
|
|
146
|
-
--rs-parent-color-primary-t-dim-dark-theme:var(--rs-color-primary-t-dim-dark-theme);
|
|
147
|
-
--rs-parent-color-primary-t-fog-dark-theme:var(--rs-color-primary-t-fog-dark-theme);
|
|
148
|
-
}
|
|
149
|
-
._modeRock_1eyuq1h_133 > *{
|
|
150
|
-
--rs-color-primary-dark-theme:var(--rs-parent-color-primary-light-theme);
|
|
151
|
-
--rs-color-primary-dim-dark-theme:var(--rs-parent-color-primary-dim-light-theme);
|
|
152
|
-
--rs-color-primary-fog-dark-theme:var(--rs-parent-color-primary-fog-light-theme);
|
|
153
|
-
--rs-color-primary-t-dim-dark-theme:var(--rs-parent-color-primary-t-dim-light-theme);
|
|
154
|
-
--rs-color-primary-t-fog-dark-theme:var(--rs-parent-color-primary-t-fog-light-theme);
|
|
155
|
-
|
|
156
|
-
--rs-color-primary-light-theme:var(--rs-parent-color-primary-dark-theme);
|
|
157
|
-
--rs-color-primary-dim-light-theme:var(--rs-parent-color-primary-dim-dark-theme);
|
|
158
|
-
--rs-color-primary-fog-light-theme:var(--rs-parent-color-primary-fog-dark-theme);
|
|
159
|
-
--rs-color-primary-t-dim-light-theme:var(--rs-parent-color-primary-t-dim-dark-theme);
|
|
160
|
-
--rs-color-primary-t-fog-light-theme:var(--rs-parent-color-primary-t-fog-dark-theme);
|
|
161
|
-
}
|
package/lib/index.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
/**
|
|
3
|
-
* @deprecated use named import instead
|
|
4
|
-
*/
|
|
5
|
-
declare const DefaultDropdown: import("react").ForwardRefExoticComponent<import("./dropdown").DropdownProps & import("react").RefAttributes<import("./dropdown").DropdownImperativeHandle>>;
|
|
6
|
-
export default DefaultDropdown;
|
|
7
|
-
export { Dropdown } from './dropdown';
|
|
8
|
-
export type { DropdownProps } from './dropdown';
|
package/lib/index.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useState, useRef, useCallback } from 'react';
|
|
3
|
-
var DROPDOWN_STATES;
|
|
4
|
-
|
|
5
|
-
(function (DROPDOWN_STATES) {
|
|
6
|
-
DROPDOWN_STATES["OPENING"] = "OPENING";
|
|
7
|
-
DROPDOWN_STATES["OPEN"] = "OPEN";
|
|
8
|
-
DROPDOWN_STATES["CLOSING"] = "CLOSING";
|
|
9
|
-
DROPDOWN_STATES["CLOSE"] = "CLOSE";
|
|
10
|
-
})(DROPDOWN_STATES || (DROPDOWN_STATES = {}));
|
|
11
|
-
|
|
12
|
-
function useDropdownState(isOpen, cancelCloseAnimation) {
|
|
13
|
-
const [, setDummyState] = useState(false);
|
|
14
|
-
const stateRef = useRef(DROPDOWN_STATES.CLOSE);
|
|
15
|
-
const onAnimationEnd = useCallback(() => {
|
|
16
|
-
if ((stateRef.current === DROPDOWN_STATES.CLOSING || stateRef.current === DROPDOWN_STATES.OPENING) && !isOpen) {
|
|
17
|
-
stateRef.current = DROPDOWN_STATES.CLOSE; //force rerender
|
|
18
|
-
|
|
19
|
-
setDummyState(s => !s);
|
|
20
|
-
} else if (stateRef.current === DROPDOWN_STATES.OPENING && isOpen) {
|
|
21
|
-
stateRef.current = DROPDOWN_STATES.OPEN; //force rerender
|
|
22
|
-
|
|
23
|
-
setDummyState(s => !s);
|
|
24
|
-
}
|
|
25
|
-
}, [isOpen]);
|
|
26
|
-
|
|
27
|
-
if (isOpen && stateRef.current !== DROPDOWN_STATES.OPEN) {
|
|
28
|
-
stateRef.current = DROPDOWN_STATES.OPENING;
|
|
29
|
-
} else if (stateRef.current === DROPDOWN_STATES.OPEN && !isOpen) {
|
|
30
|
-
stateRef.current = cancelCloseAnimation ? DROPDOWN_STATES.CLOSE : DROPDOWN_STATES.CLOSING;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return [onAnimationEnd, stateRef.current];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { DROPDOWN_STATES, useDropdownState };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
import { Property } from 'csstype';
|
|
3
|
-
/**
|
|
4
|
-
* Hack for firefox and old safari.
|
|
5
|
-
* Set "overflowY: scroll" for scrollable container when there is something to scroll.
|
|
6
|
-
* Fixes situation when scrollbar takes space from the content which causes unexpected wrapping.
|
|
7
|
-
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=764076
|
|
8
|
-
*/
|
|
9
|
-
export declare const useScrollableContainer: () => {
|
|
10
|
-
setContentEl: import("react").Dispatch<import("react").SetStateAction<HTMLElement>>;
|
|
11
|
-
scrollableStyles: {
|
|
12
|
-
overflowY: Property.OverflowY;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
3
|
-
|
|
4
|
-
function isOverflown(element) {
|
|
5
|
-
return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Hack for firefox and old safari.
|
|
9
|
-
* Set "overflowY: scroll" for scrollable container when there is something to scroll.
|
|
10
|
-
* Fixes situation when scrollbar takes space from the content which causes unexpected wrapping.
|
|
11
|
-
* @see https://bugzilla.mozilla.org/show_bug.cgi?id=764076
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const useScrollableContainer = () => {
|
|
16
|
-
const [contentEl, setContentEl] = useState(null);
|
|
17
|
-
const [isScrollable, setIsScrollable] = useState(false);
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (contentEl && typeof ResizeObserver !== 'undefined') {
|
|
20
|
-
const containerEl = contentEl.parentElement;
|
|
21
|
-
const resizeObserver = new ResizeObserver(entries => {
|
|
22
|
-
// @see https://stackoverflow.com/a/58701523
|
|
23
|
-
window.requestAnimationFrame(() => {
|
|
24
|
-
if (!Array.isArray(entries) || !entries.length) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
setIsScrollable(isOverflown(containerEl));
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
resizeObserver.observe(contentEl);
|
|
32
|
-
return () => {
|
|
33
|
-
resizeObserver.disconnect();
|
|
34
|
-
};
|
|
35
|
-
} // eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return () => {};
|
|
39
|
-
}, [contentEl]);
|
|
40
|
-
const scrollableStyles = {
|
|
41
|
-
overflowY: isScrollable ? 'scroll' : 'auto'
|
|
42
|
-
};
|
|
43
|
-
return {
|
|
44
|
-
setContentEl,
|
|
45
|
-
scrollableStyles
|
|
46
|
-
};
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export { useScrollableContainer };
|