@via-profit/ui-kit 0.1.8 → 0.2.1-alpha.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/Accordion/index.d.ts +4 -4
- package/Autocomplete/AutocompleteContainer.d.ts +34 -7
- package/Autocomplete/AutocompleteContainer.js +28 -24
- package/Autocomplete/AutocompleteItem.d.ts +1 -1
- package/Autocomplete/AutocompleteTextField.d.ts +3 -0
- package/Autocomplete/AutocompleteTextField.js +63 -1
- package/Autocomplete/OverrideMenuList.d.ts +4 -0
- package/Autocomplete/OverrideMenuList.js +39 -0
- package/Autocomplete/context.d.ts +9 -1
- package/Autocomplete/context.js +15 -1
- package/Autocomplete/index.js +9 -10
- package/Autocomplete2/Autocomplete2.d.ts +12 -0
- package/Autocomplete2/Autocomplete2.js +83 -0
- package/Autocomplete2/Autocomplete2TextField.d.ts +7 -0
- package/Autocomplete2/Autocomplete2TextField.js +39 -0
- package/Autocomplete2/index.d.ts +2 -0
- package/Autocomplete2/index.js +7 -0
- package/Avatar/AvatarBase.d.ts +4 -4
- package/Avatar/index.js +1 -1
- package/Badge/BadgeBase.d.ts +4 -4
- package/Badge/BadgeDeleteButton.js +6 -6
- package/Badge/BadgeOutlined.js +2 -2
- package/Badge/BadgeStandard.js +1 -1
- package/Button/ButtonBase.d.ts +3 -3
- package/Button/ButtonOutlined.js +1 -1
- package/Button/ButtonPlain.js +1 -1
- package/Button/ButtonStandard.js +4 -11
- package/Calendar/CalendarCell.js +22 -4
- package/Calendar/CalendarComponent.d.ts +226 -0
- package/Calendar/CalendarComponent.js +572 -0
- package/Calendar/CalendarControlButton.js +16 -9
- package/Calendar/CalendarDayBadge.js +1 -1
- package/Calendar/CalendarEmptyCell.d.ts +2 -2
- package/Calendar/CalendarEmptyCell.js +8 -3
- package/Calendar/CalendarHeading.js +2 -1
- package/Calendar/CalendarMonthCell.js +0 -5
- package/Calendar/CalendarSubheading.js +3 -2
- package/Calendar/CalendarWeekDayCell.d.ts +10 -0
- package/Calendar/CalendarWeekDayCell.js +32 -0
- package/Calendar/CalendarWeekDayWeekNumber.d.ts +7 -0
- package/Calendar/CalendarWeekDayWeekNumber.js +38 -0
- package/Calendar/CalendarWeekRow.d.ts +2 -2
- package/Calendar/CalendarWeekRow.js +2 -1
- package/Calendar/CalendarWeekRowButton.d.ts +13 -0
- package/Calendar/CalendarWeekRowButton.js +31 -0
- package/Calendar/CalendarYearCell.js +5 -5
- package/Calendar/CalendarYearsSelector.d.ts +39 -1
- package/Calendar/CalendarYearsSelector.js +52 -16
- package/Calendar/IconChevronDown.d.ts +3 -0
- package/Calendar/IconChevronDown.js +31 -0
- package/Calendar/index.d.ts +7 -220
- package/Calendar/index.js +19 -274
- package/Calendar/use-calendar.d.ts +1 -1
- package/Calendar/use-calendar.js +102 -155
- package/Color/Color.d.ts +138 -0
- package/Color/Color.js +324 -0
- package/Color/ColorGenerator.d.ts +29 -0
- package/Color/ColorGenerator.js +141 -0
- package/Color/ColorParser.d.ts +20 -0
- package/Color/ColorParser.js +284 -0
- package/Color/index.d.ts +4 -122
- package/Color/index.js +18 -473
- package/DatePicker/index.d.ts +2 -17
- package/DatePicker/index.js +47 -61
- package/DatePicker/useDatePickerFormat.js +5 -5
- package/ErrorBoundary/Fallback.d.ts +3 -0
- package/ErrorBoundary/Fallback.js +51 -0
- package/ErrorBoundary/RenderError.d.ts +6 -0
- package/ErrorBoundary/RenderError.js +80 -0
- package/ErrorBoundary/index.d.ts +7 -11
- package/ErrorBoundary/index.js +4 -51
- package/Highlighted/index.d.ts +3 -3
- package/LoadingIndicator/Spinner.d.ts +5 -3
- package/LoadingIndicator/Spinner.js +61 -32
- package/LoadingIndicator/index.d.ts +3 -3
- package/LoadingIndicator/index.js +15 -2
- package/MaskedField/index.d.ts +1 -1
- package/MaskedField/index.js +11 -10
- package/Menu/AutoHeightWrapper.d.ts +6 -0
- package/Menu/AutoHeightWrapper.js +43 -0
- package/Menu/MeasuredItem.d.ts +10 -0
- package/Menu/MeasuredItem.js +51 -0
- package/Menu/MenuContainer.d.ts +53 -20
- package/Menu/MenuContainer.js +18 -11
- package/Menu/MenuItem.d.ts +24 -7
- package/Menu/MenuItem.js +13 -6
- package/Menu/MenuList.d.ts +4 -2
- package/Menu/MenuList.js +26 -6
- package/Menu/VirtualizedItem.d.ts +22 -0
- package/Menu/VirtualizedItem.js +69 -0
- package/Menu/VirtualizedList.d.ts +18 -0
- package/Menu/VirtualizedList.js +28 -0
- package/Menu/VirtualizedListComponent.d.ts +20 -0
- package/Menu/VirtualizedListComponent.js +305 -0
- package/Menu/index.d.ts +3 -1
- package/Menu/index.js +4 -7
- package/Modal/BaseModal/RenderModal.d.ts +3 -3
- package/Modal/BaseModal/index.d.ts +3 -3
- package/Modal/ConfirmBox/index.d.ts +5 -5
- package/Modal/Drawer/index.d.ts +5 -5
- package/Modal/MessageBox/index.d.ts +5 -5
- package/Popper/Popper.d.ts +148 -0
- package/Popper/Popper.js +113 -0
- package/Popper/PopperContainer.d.ts +2 -0
- package/Popper/PopperContainer.js +3 -6
- package/Popper/index.d.ts +5 -22
- package/Popper/index.js +18 -264
- package/Popper/usePopprer.d.ts +110 -0
- package/Popper/usePopprer.js +505 -0
- package/Selectbox/SelectboxButton.d.ts +5 -0
- package/Selectbox/SelectboxButton.js +48 -8
- package/Selectbox/SelectboxButtonWrapper.d.ts +2 -0
- package/Selectbox/SelectboxButtonWrapper.js +1 -17
- package/Selectbox/SelectboxMenu.d.ts +12 -0
- package/Selectbox/SelectboxMenu.js +50 -0
- package/Selectbox/index.d.ts +13 -13
- package/Selectbox/index.js +115 -97
- package/Surface/index.d.ts +5 -5
- package/Surface/index.js +1 -1
- package/Swiper/Swiper.d.ts +44 -0
- package/Swiper/Swiper.js +139 -0
- package/Swiper/SwiperContainer.d.ts +7 -0
- package/Swiper/SwiperContainer.js +14 -0
- package/Swiper/SwiperSlide.d.ts +7 -0
- package/Swiper/SwiperSlide.js +55 -0
- package/Swiper/SwiperTrack.d.ts +14 -0
- package/Swiper/SwiperTrack.js +58 -0
- package/Swiper/SwiperWrapper.d.ts +14 -0
- package/Swiper/SwiperWrapper.js +60 -0
- package/Swiper/index.d.ts +7 -0
- package/Swiper/index.js +26 -0
- package/Switch/SwitchDot.js +1 -1
- package/Switch/SwitchTrack.js +1 -1
- package/Switch/index.d.ts +8 -8
- package/TextArea/index.d.ts +7 -7
- package/TextField/TextFieldContainer.d.ts +2 -2
- package/TextField/TextFieldContainer.js +5 -3
- package/TextField/TextFieldErrorText.d.ts +2 -2
- package/TextField/TextFieldErrorText.js +5 -4
- package/TextField/TextFieldIconWrapper.d.ts +3 -3
- package/TextField/TextFieldIconWrapper.js +5 -3
- package/TextField/TextFieldInput.d.ts +2 -2
- package/TextField/TextFieldInput.js +6 -4
- package/TextField/TextFieldInputWrapper.d.ts +2 -2
- package/TextField/TextFieldInputWrapper.js +5 -3
- package/TextField/TextFieldLabel.d.ts +2 -2
- package/TextField/TextFieldLabel.js +5 -3
- package/TextField/TextFieldLabelAsterisk.d.ts +2 -2
- package/TextField/TextFieldLabelAsterisk.js +5 -3
- package/TextField/index.d.ts +15 -8
- package/TextField/index.js +49 -22
- package/ThemeProvider/createTheme.js +2 -2
- package/package.json +1 -1
- package/Calendar/reducer.d.ts +0 -14
- package/Calendar/reducer.js +0 -26
- /package/Calendar/{IconChevronRight.d.ts → CalendarIconNext.d.ts} +0 -0
- /package/Calendar/{IconChevronRight.js → CalendarIconNext.js} +0 -0
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.usePopper = exports.findScrollableAncestor = void 0;
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
/**
|
|
9
|
+
* Finds the closest scrollable ancestor of an element.
|
|
10
|
+
* A scrollable element is one that has overflow set to auto, scroll, or overlay
|
|
11
|
+
* and has content that overflows, allowing scrolling.
|
|
12
|
+
*
|
|
13
|
+
* @param element - The element to start searching from
|
|
14
|
+
* @param includeHidden - Whether to consider elements with overflow: hidden
|
|
15
|
+
* @returns The closest scrollable ancestor or window if none found
|
|
16
|
+
*/
|
|
17
|
+
const findScrollableAncestor = (element, includeHidden = false) => {
|
|
18
|
+
if (!element) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
// Helper to check if an element is scrollable
|
|
22
|
+
const isScrollable = (el) => {
|
|
23
|
+
const style = window.getComputedStyle(el);
|
|
24
|
+
const overflow = style.overflow + style.overflowY + style.overflowX;
|
|
25
|
+
// Check if element has overflow that enables scrolling
|
|
26
|
+
const hasOverflow = overflow.includes('auto') ||
|
|
27
|
+
overflow.includes('scroll') ||
|
|
28
|
+
(includeHidden && overflow.includes('hidden'));
|
|
29
|
+
if (!hasOverflow) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
// Check if element actually has scrollable content
|
|
33
|
+
return el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth;
|
|
34
|
+
};
|
|
35
|
+
// Start from parent (skip the element itself)
|
|
36
|
+
let parent = element.parentElement;
|
|
37
|
+
while (parent) {
|
|
38
|
+
if (isScrollable(parent)) {
|
|
39
|
+
return parent;
|
|
40
|
+
}
|
|
41
|
+
parent = parent.parentElement;
|
|
42
|
+
}
|
|
43
|
+
// If no scrollable ancestor found, return window (which is scrollable)
|
|
44
|
+
return window;
|
|
45
|
+
};
|
|
46
|
+
exports.findScrollableAncestor = findScrollableAncestor;
|
|
47
|
+
const usePopper = ({ anchorElement, anchorPos = 'auto', positionStrategy = 'fixed', autoFlip = true, offset = 0, viewportMargin = 10, isOpen = false, }) => {
|
|
48
|
+
const [actualPlacement, setActualPlacement] = react_1.default.useState(anchorPos);
|
|
49
|
+
const [style, setStyle] = react_1.default.useState(null);
|
|
50
|
+
const [isVisible, setIsVisible] = react_1.default.useState(false);
|
|
51
|
+
const popperRef = react_1.default.useRef(null);
|
|
52
|
+
// Finding the nearest scrollable ancestor
|
|
53
|
+
const scrollableAncestor = react_1.default.useMemo(() => {
|
|
54
|
+
if (!anchorElement || typeof window === 'undefined') {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return (0, exports.findScrollableAncestor)(anchorElement);
|
|
58
|
+
}, [anchorElement]);
|
|
59
|
+
// Synchronizing actualPlacement with anchorPos
|
|
60
|
+
react_1.default.useEffect(() => {
|
|
61
|
+
if (actualPlacement !== anchorPos) {
|
|
62
|
+
setActualPlacement(anchorPos);
|
|
63
|
+
}
|
|
64
|
+
}, [actualPlacement, anchorPos]);
|
|
65
|
+
const getPositionStyle = react_1.default.useCallback((props) => {
|
|
66
|
+
const { place, anchorRect, popperRect, forViewportCheck = false } = props;
|
|
67
|
+
const [direction, modifier = ''] = place.split('-');
|
|
68
|
+
let left = anchorRect.left;
|
|
69
|
+
let top = anchorRect.top;
|
|
70
|
+
let width = undefined;
|
|
71
|
+
// Calculating the position relative to the viewport
|
|
72
|
+
switch (direction) {
|
|
73
|
+
case 'top':
|
|
74
|
+
top = anchorRect.top - popperRect.height - offset;
|
|
75
|
+
if (modifier === 'fill') {
|
|
76
|
+
left = anchorRect.left;
|
|
77
|
+
width = anchorRect.width;
|
|
78
|
+
}
|
|
79
|
+
else if (modifier === 'left' || modifier === 'start') {
|
|
80
|
+
left = anchorRect.left;
|
|
81
|
+
}
|
|
82
|
+
else if (modifier === 'right' || modifier === 'end') {
|
|
83
|
+
left = anchorRect.right - popperRect.width;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
left = anchorRect.left + (anchorRect.width - popperRect.width) / 2;
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case 'bottom':
|
|
90
|
+
top = anchorRect.bottom + offset;
|
|
91
|
+
if (modifier === 'fill') {
|
|
92
|
+
left = anchorRect.left;
|
|
93
|
+
width = anchorRect.width;
|
|
94
|
+
}
|
|
95
|
+
else if (modifier === 'left' || modifier === 'start') {
|
|
96
|
+
left = anchorRect.left;
|
|
97
|
+
}
|
|
98
|
+
else if (modifier === 'right' || modifier === 'end') {
|
|
99
|
+
left = anchorRect.right - popperRect.width;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
left = anchorRect.left + (anchorRect.width - popperRect.width) / 2;
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case 'left':
|
|
106
|
+
left = anchorRect.left - popperRect.width - offset;
|
|
107
|
+
if (modifier === 'top' || modifier === 'start') {
|
|
108
|
+
top = anchorRect.top;
|
|
109
|
+
}
|
|
110
|
+
else if (modifier === 'bottom' || modifier === 'end') {
|
|
111
|
+
top = anchorRect.bottom - popperRect.height;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
top = anchorRect.top + (anchorRect.height - popperRect.height) / 2;
|
|
115
|
+
}
|
|
116
|
+
break;
|
|
117
|
+
case 'right':
|
|
118
|
+
left = anchorRect.right + offset;
|
|
119
|
+
if (modifier === 'top' || modifier === 'start') {
|
|
120
|
+
top = anchorRect.top;
|
|
121
|
+
}
|
|
122
|
+
else if (modifier === 'bottom' || modifier === 'end') {
|
|
123
|
+
top = anchorRect.bottom - popperRect.height;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
top = anchorRect.top + (anchorRect.height - popperRect.height) / 2;
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
default:
|
|
130
|
+
left = anchorRect.left + (anchorRect.width - popperRect.width) / 2;
|
|
131
|
+
top = anchorRect.bottom + offset;
|
|
132
|
+
}
|
|
133
|
+
// Returning the viewport coordinates for verification or the final coordinates
|
|
134
|
+
if (forViewportCheck) {
|
|
135
|
+
return { left, top, width };
|
|
136
|
+
}
|
|
137
|
+
// For the final positioning, we take into account the strategy
|
|
138
|
+
if (positionStrategy === 'absolute') {
|
|
139
|
+
return {
|
|
140
|
+
left: left + window.scrollX,
|
|
141
|
+
top: top + window.scrollY,
|
|
142
|
+
width,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return { left, top, width };
|
|
146
|
+
}, [offset, positionStrategy]);
|
|
147
|
+
// const clampPopperToContainer = React.useCallback(
|
|
148
|
+
// (style: { left: number; top: number; width?: number }, _popperRect: DOMRect) => style,
|
|
149
|
+
// [],
|
|
150
|
+
// );
|
|
151
|
+
const clampPopperToContainer = react_1.default.useCallback((style, popperRect) => {
|
|
152
|
+
// Если нет scrollableAncestor, используем document.documentElement как fallback
|
|
153
|
+
const container = scrollableAncestor instanceof HTMLElement ? scrollableAncestor : document.documentElement;
|
|
154
|
+
const containerRect = container.getBoundingClientRect();
|
|
155
|
+
// Базовые границы контейнера с учетом отступа
|
|
156
|
+
let minLeft = containerRect.left + viewportMargin;
|
|
157
|
+
let maxLeft = containerRect.right - popperRect.width - viewportMargin;
|
|
158
|
+
let minTop = containerRect.top + viewportMargin;
|
|
159
|
+
let maxTop = containerRect.bottom - popperRect.height - viewportMargin;
|
|
160
|
+
// Для fixed позиционирования добавляем ограничения viewport
|
|
161
|
+
if (positionStrategy === 'fixed') {
|
|
162
|
+
// Границы viewport с учетом отступа
|
|
163
|
+
const viewportMinLeft = viewportMargin;
|
|
164
|
+
const viewportMaxLeft = window.innerWidth - popperRect.width - viewportMargin;
|
|
165
|
+
const viewportMinTop = viewportMargin;
|
|
166
|
+
const viewportMaxTop = window.innerHeight - popperRect.height - viewportMargin;
|
|
167
|
+
// Берем пересечение границ контейнера и viewport
|
|
168
|
+
minLeft = Math.max(minLeft, viewportMinLeft);
|
|
169
|
+
maxLeft = Math.min(maxLeft, viewportMaxLeft);
|
|
170
|
+
minTop = Math.max(minTop, viewportMinTop);
|
|
171
|
+
maxTop = Math.min(maxTop, viewportMaxTop);
|
|
172
|
+
}
|
|
173
|
+
// Убеждаемся, что границы валидны (min не больше max)
|
|
174
|
+
const validMinLeft = Math.min(minLeft, maxLeft);
|
|
175
|
+
const validMaxLeft = Math.max(minLeft, maxLeft);
|
|
176
|
+
const validMinTop = Math.min(minTop, maxTop);
|
|
177
|
+
const validMaxTop = Math.max(minTop, maxTop);
|
|
178
|
+
// Ограничиваем позицию
|
|
179
|
+
const clampedLeft = Math.max(validMinLeft, Math.min(style.left, validMaxLeft));
|
|
180
|
+
const clampedTop = Math.max(validMinTop, Math.min(style.top, validMaxTop));
|
|
181
|
+
return {
|
|
182
|
+
left: clampedLeft,
|
|
183
|
+
top: clampedTop,
|
|
184
|
+
width: style.width,
|
|
185
|
+
};
|
|
186
|
+
}, [positionStrategy, scrollableAncestor, viewportMargin]);
|
|
187
|
+
const checkIfViewportFits = react_1.default.useCallback((style, popperRect) => {
|
|
188
|
+
const left = style.left;
|
|
189
|
+
const top = style.top;
|
|
190
|
+
const right = left + popperRect.width;
|
|
191
|
+
const bottom = top + popperRect.height;
|
|
192
|
+
if (positionStrategy === 'absolute' && scrollableAncestor instanceof HTMLElement) {
|
|
193
|
+
const containerRect = scrollableAncestor.getBoundingClientRect();
|
|
194
|
+
const relativeLeft = left - containerRect.left;
|
|
195
|
+
const relativeTop = top - containerRect.top;
|
|
196
|
+
const relativeRight = relativeLeft + popperRect.width;
|
|
197
|
+
const relativeBottom = relativeTop + popperRect.height;
|
|
198
|
+
const isWithinHorizontal = relativeLeft >= viewportMargin && relativeRight <= containerRect.width - viewportMargin;
|
|
199
|
+
const isWithinVertical = relativeTop >= viewportMargin && relativeBottom <= containerRect.height - viewportMargin;
|
|
200
|
+
return isWithinHorizontal && isWithinVertical;
|
|
201
|
+
}
|
|
202
|
+
const viewportWidth = window.innerWidth;
|
|
203
|
+
const viewportHeight = window.innerHeight;
|
|
204
|
+
const isWithinHorizontal = left >= viewportMargin && right <= viewportWidth - viewportMargin;
|
|
205
|
+
const isWithinVertical = top >= viewportMargin && bottom <= viewportHeight - viewportMargin;
|
|
206
|
+
const hasValidPosition = left >= 0 && top >= 0;
|
|
207
|
+
return hasValidPosition && isWithinHorizontal && isWithinVertical;
|
|
208
|
+
}, [viewportMargin, scrollableAncestor, positionStrategy]);
|
|
209
|
+
const placementsOrder = react_1.default.useMemo(() => {
|
|
210
|
+
const basePlacements = {
|
|
211
|
+
top: ['top', 'top-left', 'top-right', 'top-start', 'top-end'],
|
|
212
|
+
bottom: ['bottom', 'bottom-left', 'bottom-right', 'bottom-start', 'bottom-end'],
|
|
213
|
+
left: ['left', 'left-top', 'left-bottom'],
|
|
214
|
+
right: ['right', 'right-top', 'right-bottom'],
|
|
215
|
+
};
|
|
216
|
+
const allPlacements = [
|
|
217
|
+
...basePlacements.top,
|
|
218
|
+
...basePlacements.bottom,
|
|
219
|
+
...basePlacements.left,
|
|
220
|
+
...basePlacements.right,
|
|
221
|
+
];
|
|
222
|
+
const order = {};
|
|
223
|
+
allPlacements.forEach(placement => {
|
|
224
|
+
const [direction] = placement.split('-');
|
|
225
|
+
// Priority: same direction > opposite > the rest
|
|
226
|
+
const opposite = direction === 'top'
|
|
227
|
+
? 'bottom'
|
|
228
|
+
: direction === 'bottom'
|
|
229
|
+
? 'top'
|
|
230
|
+
: direction === 'left'
|
|
231
|
+
? 'right'
|
|
232
|
+
: 'left';
|
|
233
|
+
order[placement] = [
|
|
234
|
+
placement,
|
|
235
|
+
...basePlacements[direction].filter(p => p !== placement),
|
|
236
|
+
...(basePlacements[opposite] || []),
|
|
237
|
+
...(direction !== 'left' && direction !== 'right' ? basePlacements.left : []),
|
|
238
|
+
...(direction !== 'left' && direction !== 'right' ? basePlacements.right : []),
|
|
239
|
+
];
|
|
240
|
+
});
|
|
241
|
+
// console.log(order);
|
|
242
|
+
return order;
|
|
243
|
+
}, []);
|
|
244
|
+
const getPreferredPlacements = react_1.default.useCallback((preferredPlacement, anchorRect, popperRect) => {
|
|
245
|
+
// Check the auto placements
|
|
246
|
+
if (preferredPlacement.startsWith('auto')) {
|
|
247
|
+
const [, preferredDirection = 'bottom'] = preferredPlacement.split('-');
|
|
248
|
+
const allPlacements = [
|
|
249
|
+
'bottom',
|
|
250
|
+
'bottom-start',
|
|
251
|
+
'bottom-end',
|
|
252
|
+
'bottom-left',
|
|
253
|
+
'bottom-right',
|
|
254
|
+
'top',
|
|
255
|
+
'top-left',
|
|
256
|
+
'top-right',
|
|
257
|
+
'top-start',
|
|
258
|
+
'top-end',
|
|
259
|
+
'left',
|
|
260
|
+
'left-top',
|
|
261
|
+
'left-bottom',
|
|
262
|
+
'right',
|
|
263
|
+
'right-top',
|
|
264
|
+
'right-bottom',
|
|
265
|
+
];
|
|
266
|
+
// Sorting placements
|
|
267
|
+
const sortedPlacements = [...allPlacements].sort((a, b) => {
|
|
268
|
+
const aDir = a.split('-')[0];
|
|
269
|
+
const bDir = b.split('-')[0];
|
|
270
|
+
if (aDir === preferredDirection && bDir !== preferredDirection)
|
|
271
|
+
return -1;
|
|
272
|
+
if (aDir !== preferredDirection && bDir === preferredDirection)
|
|
273
|
+
return 1;
|
|
274
|
+
return 0;
|
|
275
|
+
});
|
|
276
|
+
for (const place of sortedPlacements) {
|
|
277
|
+
const viewportStyle = getPositionStyle({
|
|
278
|
+
place,
|
|
279
|
+
anchorRect,
|
|
280
|
+
popperRect,
|
|
281
|
+
forViewportCheck: true,
|
|
282
|
+
});
|
|
283
|
+
const fits = checkIfViewportFits(viewportStyle, popperRect);
|
|
284
|
+
if (fits) {
|
|
285
|
+
const finalStyle = getPositionStyle({
|
|
286
|
+
place,
|
|
287
|
+
anchorRect,
|
|
288
|
+
popperRect,
|
|
289
|
+
forViewportCheck: false,
|
|
290
|
+
});
|
|
291
|
+
return {
|
|
292
|
+
found: true,
|
|
293
|
+
placement: place,
|
|
294
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!autoFlip) {
|
|
300
|
+
const finalStyle = getPositionStyle({
|
|
301
|
+
place: preferredPlacement,
|
|
302
|
+
anchorRect,
|
|
303
|
+
popperRect,
|
|
304
|
+
forViewportCheck: false,
|
|
305
|
+
});
|
|
306
|
+
return {
|
|
307
|
+
found: false,
|
|
308
|
+
placement: preferredPlacement,
|
|
309
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* bottom-fill, top-fill
|
|
314
|
+
*/
|
|
315
|
+
if (preferredPlacement.endsWith('fill')) {
|
|
316
|
+
const [preferredDirection = 'bottom'] = preferredPlacement.split('-');
|
|
317
|
+
const allPlacements = ['top-fill', 'bottom-fill'];
|
|
318
|
+
const sortedPlacements = [...allPlacements].sort((a, b) => {
|
|
319
|
+
const aDir = a.split('-')[0];
|
|
320
|
+
const bDir = b.split('-')[0];
|
|
321
|
+
if (aDir === preferredDirection && bDir !== preferredDirection)
|
|
322
|
+
return -1;
|
|
323
|
+
if (aDir !== preferredDirection && bDir === preferredDirection)
|
|
324
|
+
return 1;
|
|
325
|
+
return 0;
|
|
326
|
+
});
|
|
327
|
+
for (const place of sortedPlacements) {
|
|
328
|
+
const viewportStyle = getPositionStyle({
|
|
329
|
+
place,
|
|
330
|
+
anchorRect,
|
|
331
|
+
popperRect,
|
|
332
|
+
forViewportCheck: true,
|
|
333
|
+
});
|
|
334
|
+
const fits = checkIfViewportFits(viewportStyle, popperRect);
|
|
335
|
+
if (fits) {
|
|
336
|
+
const finalStyle = getPositionStyle({
|
|
337
|
+
place,
|
|
338
|
+
anchorRect,
|
|
339
|
+
popperRect,
|
|
340
|
+
forViewportCheck: false,
|
|
341
|
+
});
|
|
342
|
+
return {
|
|
343
|
+
found: true,
|
|
344
|
+
placement: place,
|
|
345
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Other
|
|
352
|
+
*/
|
|
353
|
+
const order = placementsOrder[preferredPlacement] || placementsOrder.bottom;
|
|
354
|
+
for (const place of order) {
|
|
355
|
+
const viewportStyle = getPositionStyle({
|
|
356
|
+
place,
|
|
357
|
+
anchorRect,
|
|
358
|
+
popperRect,
|
|
359
|
+
forViewportCheck: true,
|
|
360
|
+
});
|
|
361
|
+
const fits = checkIfViewportFits(viewportStyle, popperRect);
|
|
362
|
+
if (fits) {
|
|
363
|
+
const finalStyle = getPositionStyle({
|
|
364
|
+
place,
|
|
365
|
+
anchorRect,
|
|
366
|
+
popperRect,
|
|
367
|
+
forViewportCheck: false,
|
|
368
|
+
});
|
|
369
|
+
return {
|
|
370
|
+
found: true,
|
|
371
|
+
placement: place,
|
|
372
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const finalStyle = getPositionStyle({
|
|
377
|
+
place: preferredPlacement,
|
|
378
|
+
anchorRect,
|
|
379
|
+
popperRect,
|
|
380
|
+
forViewportCheck: false,
|
|
381
|
+
});
|
|
382
|
+
return {
|
|
383
|
+
found: false,
|
|
384
|
+
placement: preferredPlacement,
|
|
385
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
386
|
+
};
|
|
387
|
+
}, [autoFlip, getPositionStyle, checkIfViewportFits, clampPopperToContainer, placementsOrder]);
|
|
388
|
+
const calculatePosition = react_1.default.useCallback(() => {
|
|
389
|
+
if (!anchorElement || !popperRef.current) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const anchorRect = anchorElement.getBoundingClientRect();
|
|
393
|
+
const popperRect = popperRef.current.getBoundingClientRect();
|
|
394
|
+
const { style, placement, found } = getPreferredPlacements(anchorPos, anchorRect, popperRect);
|
|
395
|
+
if (found) {
|
|
396
|
+
setActualPlacement(placement);
|
|
397
|
+
}
|
|
398
|
+
setStyle(style);
|
|
399
|
+
}, [anchorElement, anchorPos, getPreferredPlacements]);
|
|
400
|
+
// const getTransformOrigin = React.useCallback((placement: AnchorPos): string => {
|
|
401
|
+
// if (placement.startsWith('top')) return 'bottom center';
|
|
402
|
+
// if (placement.startsWith('bottom')) return 'top center';
|
|
403
|
+
// if (placement.startsWith('left')) return 'right center';
|
|
404
|
+
// if (placement.startsWith('right')) return 'left center';
|
|
405
|
+
//
|
|
406
|
+
// return 'top center';
|
|
407
|
+
// }, []);
|
|
408
|
+
/**
|
|
409
|
+
* Open / Close popper logic
|
|
410
|
+
*/
|
|
411
|
+
react_1.default.useEffect(() => {
|
|
412
|
+
if (!isOpen) {
|
|
413
|
+
setIsVisible(false);
|
|
414
|
+
setStyle(null);
|
|
415
|
+
}
|
|
416
|
+
else if (anchorElement && isOpen && popperRef.current) {
|
|
417
|
+
calculatePosition();
|
|
418
|
+
setIsVisible(true);
|
|
419
|
+
}
|
|
420
|
+
}, [actualPlacement, anchorElement, getPreferredPlacements, isOpen, calculatePosition]);
|
|
421
|
+
/**
|
|
422
|
+
* The anchor element changes
|
|
423
|
+
*/
|
|
424
|
+
react_1.default.useEffect(() => {
|
|
425
|
+
if (!isOpen || !anchorElement) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
const observer = new MutationObserver(() => {
|
|
429
|
+
window.requestAnimationFrame(() => {
|
|
430
|
+
// console.log('The anchor element was change');
|
|
431
|
+
calculatePosition();
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
observer.observe(anchorElement, {
|
|
435
|
+
attributes: true,
|
|
436
|
+
childList: true,
|
|
437
|
+
subtree: true,
|
|
438
|
+
});
|
|
439
|
+
// eslint-disable-next-line consistent-return
|
|
440
|
+
return () => {
|
|
441
|
+
observer.disconnect();
|
|
442
|
+
};
|
|
443
|
+
}, [isOpen, anchorElement, calculatePosition]);
|
|
444
|
+
/**
|
|
445
|
+
* On scroll - recalculate position
|
|
446
|
+
*/
|
|
447
|
+
react_1.default.useEffect(() => {
|
|
448
|
+
if (!isOpen || !scrollableAncestor) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const handleScroll = () => {
|
|
452
|
+
window.requestAnimationFrame(() => {
|
|
453
|
+
calculatePosition();
|
|
454
|
+
});
|
|
455
|
+
};
|
|
456
|
+
// parent scroll listener
|
|
457
|
+
if (scrollableAncestor instanceof HTMLElement) {
|
|
458
|
+
scrollableAncestor.addEventListener('scroll', handleScroll, { passive: true });
|
|
459
|
+
}
|
|
460
|
+
else if (scrollableAncestor === window) {
|
|
461
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
462
|
+
}
|
|
463
|
+
// eslint-disable-next-line consistent-return
|
|
464
|
+
return () => {
|
|
465
|
+
if (scrollableAncestor instanceof HTMLElement) {
|
|
466
|
+
scrollableAncestor.removeEventListener('scroll', handleScroll);
|
|
467
|
+
}
|
|
468
|
+
else if (scrollableAncestor === window) {
|
|
469
|
+
window.removeEventListener('scroll', handleScroll);
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
}, [isOpen, scrollableAncestor, calculatePosition]);
|
|
473
|
+
/**
|
|
474
|
+
* On window resize - recalculate position
|
|
475
|
+
*/
|
|
476
|
+
react_1.default.useEffect(() => {
|
|
477
|
+
if (!isOpen) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
const handleResize = () => {
|
|
481
|
+
window.requestAnimationFrame(() => {
|
|
482
|
+
calculatePosition();
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
// parent scroll listener
|
|
486
|
+
window.addEventListener('resize', handleResize);
|
|
487
|
+
// eslint-disable-next-line consistent-return
|
|
488
|
+
return () => {
|
|
489
|
+
window.removeEventListener('resize', handleResize);
|
|
490
|
+
};
|
|
491
|
+
}, [calculatePosition, isOpen]);
|
|
492
|
+
return {
|
|
493
|
+
actualPlacement,
|
|
494
|
+
style,
|
|
495
|
+
popperRef,
|
|
496
|
+
isVisible,
|
|
497
|
+
scrollableAncestor,
|
|
498
|
+
calculatePosition,
|
|
499
|
+
setActualPlacement,
|
|
500
|
+
setStyle,
|
|
501
|
+
setIsVisible,
|
|
502
|
+
};
|
|
503
|
+
};
|
|
504
|
+
exports.usePopper = usePopper;
|
|
505
|
+
exports.default = exports.usePopper;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { ButtonProps } from '../Button';
|
|
3
|
+
import { AnchorPos } from '../Menu';
|
|
3
4
|
export type SelectboxButtonProps = Omit<ButtonProps, 'type'> & {
|
|
4
5
|
readonly fullWidth?: boolean;
|
|
5
6
|
readonly error?: boolean;
|
|
7
|
+
readonly anchorPos?: AnchorPos;
|
|
8
|
+
readonly isOpen?: boolean;
|
|
6
9
|
};
|
|
7
10
|
declare const _default: React.ForwardRefExoticComponent<Omit<ButtonProps, "type"> & {
|
|
8
11
|
readonly fullWidth?: boolean | undefined;
|
|
9
12
|
readonly error?: boolean | undefined;
|
|
13
|
+
readonly anchorPos?: import("../Popper").AnchorPos | undefined;
|
|
14
|
+
readonly isOpen?: boolean | undefined;
|
|
10
15
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
11
16
|
export default _default;
|
|
@@ -41,25 +41,65 @@ const React = __importStar(require("react"));
|
|
|
41
41
|
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
42
42
|
const Button_1 = __importDefault(require("../Button"));
|
|
43
43
|
const ButtonTextWrapper_1 = __importDefault(require("../Button/ButtonTextWrapper"));
|
|
44
|
+
const react_1 = require("@emotion/react");
|
|
44
45
|
const StyledSelectboxButton = (0, styled_1.default)(Button_1.default) `
|
|
45
46
|
flex: 1;
|
|
46
47
|
padding: 1em 1.2em;
|
|
47
48
|
font-size: 1em;
|
|
48
49
|
background: none;
|
|
49
|
-
border-radius: inherit;
|
|
50
|
-
margin: 0;
|
|
51
|
-
border: 0;
|
|
52
50
|
width: 100%;
|
|
51
|
+
border-width: 1px;
|
|
52
|
+
border-style: solid;
|
|
53
|
+
box-shadow: none;
|
|
54
|
+
&:hover {
|
|
55
|
+
box-shadow: none;
|
|
56
|
+
}
|
|
57
|
+
border-color: ${({ theme }) => theme.isDark
|
|
58
|
+
? theme.color.textPrimary.darken(100).toString()
|
|
59
|
+
: theme.color.textPrimary.lighten(150).toString()};
|
|
60
|
+
${props => props.$error &&
|
|
61
|
+
(0, react_1.css) `
|
|
62
|
+
border-color: ${props.theme.color.error.toString()};
|
|
63
|
+
color: ${props.theme.color.error.toString()};
|
|
64
|
+
&:focus {
|
|
65
|
+
border-color: ${props.theme.color.error.lighten(0.6).toString()};
|
|
66
|
+
}
|
|
67
|
+
`}
|
|
68
|
+
transition: none;
|
|
69
|
+
${({ theme, $isOpen, $anchorPos }) => $isOpen &&
|
|
70
|
+
$anchorPos &&
|
|
71
|
+
['bottom-fill', 'top-fill'].includes($anchorPos) &&
|
|
72
|
+
(0, react_1.css) `
|
|
73
|
+
border-width: 1px;
|
|
74
|
+
border-style: solid;
|
|
75
|
+
border-color: ${theme.isDark
|
|
76
|
+
? theme.color.textPrimary.darken(100).toString()
|
|
77
|
+
: theme.color.textPrimary.lighten(150).toString()};
|
|
78
|
+
`};
|
|
79
|
+
|
|
80
|
+
${({ $anchorPos, $isOpen }) => $isOpen &&
|
|
81
|
+
$anchorPos === 'bottom-fill' &&
|
|
82
|
+
(0, react_1.css) `
|
|
83
|
+
border-bottom-left-radius: 0;
|
|
84
|
+
border-bottom-right-radius: 0;
|
|
85
|
+
border-bottom: 0;
|
|
86
|
+
`};
|
|
87
|
+
|
|
88
|
+
${({ $anchorPos, $isOpen }) => $isOpen &&
|
|
89
|
+
$anchorPos === 'top-fill' &&
|
|
90
|
+
(0, react_1.css) `
|
|
91
|
+
border-top-left-radius: 0;
|
|
92
|
+
border-top-right-radius: 0;
|
|
93
|
+
border-top: 0;
|
|
94
|
+
`};
|
|
53
95
|
`;
|
|
54
96
|
const StyledButtonTextWrapper = (0, styled_1.default)(ButtonTextWrapper_1.default) `
|
|
55
97
|
flex: 1;
|
|
56
98
|
`;
|
|
57
99
|
const SelectboxButton = (props, ref) => {
|
|
58
|
-
const { children, fullWidth, error } = props, nativeProps = __rest(props, ["children", "fullWidth", "error"]);
|
|
59
|
-
return (React.createElement(StyledSelectboxButton, Object.assign({ "$fullWidth": fullWidth, "$error": error }, nativeProps, { overrides: {
|
|
60
|
-
TextWrapper:
|
|
61
|
-
return React.createElement(StyledButtonTextWrapper, Object.assign({}, p, { ref: r }));
|
|
62
|
-
}),
|
|
100
|
+
const { children, fullWidth, error, anchorPos, isOpen } = props, nativeProps = __rest(props, ["children", "fullWidth", "error", "anchorPos", "isOpen"]);
|
|
101
|
+
return (React.createElement(StyledSelectboxButton, Object.assign({ "$fullWidth": fullWidth, "$error": error }, nativeProps, { "$isOpen": isOpen, "$anchorPos": anchorPos, overrides: {
|
|
102
|
+
TextWrapper: StyledButtonTextWrapper,
|
|
63
103
|
}, ref: ref }), children));
|
|
64
104
|
};
|
|
65
105
|
exports.default = React.forwardRef(SelectboxButton);
|
|
@@ -2,9 +2,11 @@ import * as React from 'react';
|
|
|
2
2
|
export type SelectboxButtonWrapperProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
3
3
|
readonly fullWidth?: boolean;
|
|
4
4
|
readonly error?: boolean;
|
|
5
|
+
readonly isOpen: boolean;
|
|
5
6
|
};
|
|
6
7
|
declare const _default: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & {
|
|
7
8
|
readonly fullWidth?: boolean | undefined;
|
|
8
9
|
readonly error?: boolean | undefined;
|
|
10
|
+
readonly isOpen: boolean;
|
|
9
11
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
10
12
|
export default _default;
|
|
@@ -39,7 +39,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
const React = __importStar(require("react"));
|
|
41
41
|
const styled_1 = __importDefault(require("@emotion/styled"));
|
|
42
|
-
const react_1 = require("@emotion/react");
|
|
43
42
|
const Wrapper = styled_1.default.div `
|
|
44
43
|
min-width: 16em;
|
|
45
44
|
font-size: 0.9em;
|
|
@@ -48,28 +47,13 @@ const Wrapper = styled_1.default.div `
|
|
|
48
47
|
display: flex;
|
|
49
48
|
align-items: stretch;
|
|
50
49
|
border-radius: ${({ theme }) => theme.shape.radiusFactor * 2}em;
|
|
51
|
-
border: 1px solid transparent;
|
|
52
|
-
|
|
53
|
-
border: 1px solid;
|
|
54
50
|
outline: 1px solid transparent;
|
|
55
|
-
|
|
56
|
-
border-color: ${({ theme }) => theme.isDark
|
|
57
|
-
? theme.color.textPrimary.darken(100).toString()
|
|
58
|
-
: theme.color.textPrimary.lighten(150).toString()};
|
|
59
51
|
width: ${({ $fullWidth }) => ($fullWidth ? '100%' : 'auto')};
|
|
60
|
-
|
|
61
52
|
background-color: ${({ theme }) => theme.color.surface.toString()};
|
|
62
53
|
color: ${({ theme }) => theme.color.textPrimary.toString()};
|
|
63
54
|
transition: all 180ms ease-out 0s;
|
|
64
55
|
|
|
65
|
-
|
|
66
|
-
(0, react_1.css) `
|
|
67
|
-
border-color: ${props.theme.color.error.toString()};
|
|
68
|
-
color: ${props.theme.color.error.toString()};
|
|
69
|
-
&:focus {
|
|
70
|
-
border-color: ${props.theme.color.error.lighten(0.6).toString()};
|
|
71
|
-
}
|
|
72
|
-
`}
|
|
56
|
+
|
|
73
57
|
`;
|
|
74
58
|
const SelectboxButtonWrapper = (props, ref) => {
|
|
75
59
|
const { fullWidth, children, error } = props, nativeProps = __rest(props, ["fullWidth", "children", "error"]);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { MenuProps, MenuRef } from '../Menu';
|
|
3
|
+
import { AnchorPos } from '../Popper';
|
|
4
|
+
import { OnChange } from 'Selectbox';
|
|
5
|
+
export interface SelectbosMenuProps<T, Multiple extends boolean | undefined = undefined> extends MenuProps<T, Multiple> {
|
|
6
|
+
readonly actualPlacement: AnchorPos;
|
|
7
|
+
readonly onChange?: OnChange<T, Multiple>;
|
|
8
|
+
}
|
|
9
|
+
declare const _default: <T, Multiple extends boolean | undefined = undefined>(props: SelectbosMenuProps<T, Multiple> & {
|
|
10
|
+
ref?: React.Ref<MenuRef> | undefined;
|
|
11
|
+
}) => JSX.Element;
|
|
12
|
+
export default _default;
|