@via-profit/ui-kit 0.2.2 → 0.2.4
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/Autocomplete/AutocompleteContainer.d.ts +5 -4
- package/Autocomplete/AutocompleteContainer.js +128 -142
- package/Autocomplete/AutocompleteItem.js +1 -1
- package/Autocomplete/context.d.ts +3 -5
- package/Autocomplete/context.js +22 -14
- package/Highlighted/index.js +10 -5
- package/Highlighted/splitTextIntoParts.d.ts +5 -0
- package/Highlighted/splitTextIntoParts.js +46 -0
- package/Menu/MenuContainer.d.ts +24 -2
- package/Menu/MenuContainer.js +193 -242
- package/Menu/MenuList.d.ts +1 -0
- package/Menu/MenuList.js +15 -16
- package/Popper/Popper.d.ts +3 -2
- package/Popper/Popper.js +9 -7
- package/Popper/PopperContainer.d.ts +0 -1
- package/Popper/PopperContainer.js +8 -3
- package/Popper/index.d.ts +1 -1
- package/Popper/index.js +1 -1
- package/Popper/usePopper.d.ts +111 -0
- package/Popper/usePopper.js +489 -0
- package/Selectbox/SelectboxButton.js +2 -27
- package/Selectbox/SelectboxMenu.d.ts +0 -2
- package/Selectbox/SelectboxMenu.js +13 -5
- package/Selectbox/index.d.ts +5 -3
- package/Selectbox/index.js +4 -4
- package/Swiper/Swiper.d.ts +0 -2
- package/Swiper/Swiper.js +1 -18
- package/package.json +1 -1
|
@@ -0,0 +1,489 @@
|
|
|
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 = (props) => {
|
|
48
|
+
const { anchorElement, anchorPos = 'auto', positionStrategy = 'fixed', autoFlip = false, offset = 0, viewportMargin = 10, isOpen = false, alternativePlacements, } = props;
|
|
49
|
+
const isMountedRef = react_1.default.useRef(false);
|
|
50
|
+
const isPositioningRef = react_1.default.useRef(false);
|
|
51
|
+
const [actualPlacement, setActualPlacement] = react_1.default.useState(anchorPos);
|
|
52
|
+
const [style, setStyle] = react_1.default.useState(null);
|
|
53
|
+
const [isVisible, setIsVisible] = react_1.default.useState(false);
|
|
54
|
+
const popperRef = react_1.default.useRef(null);
|
|
55
|
+
// Finding the nearest scrollable ancestor
|
|
56
|
+
const scrollableAncestor = react_1.default.useMemo(() => {
|
|
57
|
+
if (!anchorElement || typeof window === 'undefined') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return (0, exports.findScrollableAncestor)(anchorElement);
|
|
61
|
+
}, [anchorElement]);
|
|
62
|
+
// Synchronizing actualPlacement with anchorPos
|
|
63
|
+
react_1.default.useEffect(() => {
|
|
64
|
+
if (actualPlacement !== anchorPos) {
|
|
65
|
+
setActualPlacement(anchorPos);
|
|
66
|
+
}
|
|
67
|
+
}, [actualPlacement, anchorPos]);
|
|
68
|
+
const getPositionStyle = react_1.default.useCallback((props) => {
|
|
69
|
+
var _a;
|
|
70
|
+
const { place, anchorRect, popperRect, forViewportCheck = false } = props;
|
|
71
|
+
const [direction, modifier = ''] = place.split('-');
|
|
72
|
+
let left = anchorRect.left;
|
|
73
|
+
let top = anchorRect.top;
|
|
74
|
+
let width = undefined;
|
|
75
|
+
// Calculating the position relative to the viewport
|
|
76
|
+
switch (direction) {
|
|
77
|
+
case 'top':
|
|
78
|
+
top = anchorRect.top - popperRect.height - offset;
|
|
79
|
+
if (modifier === 'fill') {
|
|
80
|
+
left = anchorRect.left;
|
|
81
|
+
width = anchorRect.width;
|
|
82
|
+
}
|
|
83
|
+
else if (modifier === 'left' || modifier === 'start') {
|
|
84
|
+
left = anchorRect.left;
|
|
85
|
+
}
|
|
86
|
+
else if (modifier === 'right' || modifier === 'end') {
|
|
87
|
+
left = anchorRect.right - popperRect.width;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
left = anchorRect.left + (anchorRect.width - popperRect.width) / 2;
|
|
91
|
+
}
|
|
92
|
+
break;
|
|
93
|
+
case 'bottom':
|
|
94
|
+
top = anchorRect.bottom + offset;
|
|
95
|
+
if (modifier === 'fill') {
|
|
96
|
+
left = anchorRect.left;
|
|
97
|
+
width = anchorRect.width;
|
|
98
|
+
}
|
|
99
|
+
else if (modifier === 'left' || modifier === 'start') {
|
|
100
|
+
left = anchorRect.left;
|
|
101
|
+
}
|
|
102
|
+
else if (modifier === 'right' || modifier === 'end') {
|
|
103
|
+
left = anchorRect.right - popperRect.width;
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
left = anchorRect.left + (anchorRect.width - popperRect.width) / 2;
|
|
107
|
+
}
|
|
108
|
+
break;
|
|
109
|
+
case 'left':
|
|
110
|
+
left = anchorRect.left - popperRect.width - offset;
|
|
111
|
+
if (modifier === 'top' || modifier === 'start') {
|
|
112
|
+
top = anchorRect.top;
|
|
113
|
+
}
|
|
114
|
+
else if (modifier === 'bottom' || modifier === 'end') {
|
|
115
|
+
top = anchorRect.bottom - popperRect.height;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
top = anchorRect.top + (anchorRect.height - popperRect.height) / 2;
|
|
119
|
+
}
|
|
120
|
+
break;
|
|
121
|
+
case 'right':
|
|
122
|
+
left = anchorRect.right + offset;
|
|
123
|
+
if (modifier === 'top' || modifier === 'start') {
|
|
124
|
+
top = anchorRect.top;
|
|
125
|
+
}
|
|
126
|
+
else if (modifier === 'bottom' || modifier === 'end') {
|
|
127
|
+
top = anchorRect.bottom - popperRect.height;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
top = anchorRect.top + (anchorRect.height - popperRect.height) / 2;
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
default:
|
|
134
|
+
left = anchorRect.left + (anchorRect.width - popperRect.width) / 2;
|
|
135
|
+
top = anchorRect.bottom + offset;
|
|
136
|
+
}
|
|
137
|
+
// Returning the viewport coordinates for verification or the final coordinates
|
|
138
|
+
if (forViewportCheck) {
|
|
139
|
+
return { left, top, width };
|
|
140
|
+
}
|
|
141
|
+
// For the final positioning, we take into account the strategy
|
|
142
|
+
if (positionStrategy === 'absolute') {
|
|
143
|
+
// Для absolute позиционирования нужно учитывать:
|
|
144
|
+
// 1. Прокрутку страницы (scrollX/scrollY)
|
|
145
|
+
// 2. Позицию относительно ближайшего positioned ancestor
|
|
146
|
+
// Получаем offset родителя с позиционированием
|
|
147
|
+
let offsetParent = ((_a = popperRef.current) === null || _a === void 0 ? void 0 : _a.offsetParent) || null;
|
|
148
|
+
// Если нет offsetParent или это body, используем document.documentElement
|
|
149
|
+
if (!offsetParent || offsetParent === document.body) {
|
|
150
|
+
offsetParent = document.documentElement;
|
|
151
|
+
}
|
|
152
|
+
const offsetParentRect = offsetParent.getBoundingClientRect();
|
|
153
|
+
// Вычисляем позицию относительно offsetParent
|
|
154
|
+
// left/top уже относительно viewport, вычитаем позицию offsetParent
|
|
155
|
+
let relativeLeft = left - offsetParentRect.left;
|
|
156
|
+
let relativeTop = top - offsetParentRect.top;
|
|
157
|
+
// Добавляем прокрутку offsetParent (если он скроллится)
|
|
158
|
+
if (offsetParent !== document.documentElement && offsetParent !== document.body) {
|
|
159
|
+
relativeLeft += offsetParent.scrollLeft || 0;
|
|
160
|
+
relativeTop += offsetParent.scrollTop || 0;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Для document.documentElement используем window.scroll
|
|
164
|
+
relativeLeft += window.scrollX;
|
|
165
|
+
relativeTop += window.scrollY;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
left: relativeLeft,
|
|
169
|
+
top: relativeTop,
|
|
170
|
+
width,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
return { left, top, width };
|
|
174
|
+
}, [offset, positionStrategy]);
|
|
175
|
+
const clampPopperToContainer = react_1.default.useCallback((style, popperRect) => {
|
|
176
|
+
if (positionStrategy === 'absolute') {
|
|
177
|
+
return style;
|
|
178
|
+
}
|
|
179
|
+
const viewportMinLeft = viewportMargin;
|
|
180
|
+
const viewportMaxLeft = window.innerWidth - popperRect.width - viewportMargin;
|
|
181
|
+
const viewportMinTop = viewportMargin;
|
|
182
|
+
const viewportMaxTop = window.innerHeight - popperRect.height - viewportMargin;
|
|
183
|
+
return {
|
|
184
|
+
left: Math.max(viewportMinLeft, Math.min(style.left, viewportMaxLeft)),
|
|
185
|
+
top: Math.max(viewportMinTop, Math.min(style.top, viewportMaxTop)),
|
|
186
|
+
width: style.width,
|
|
187
|
+
};
|
|
188
|
+
}, [positionStrategy, viewportMargin]);
|
|
189
|
+
const checkIfViewportFits = react_1.default.useCallback((style, popperRect) => {
|
|
190
|
+
const left = style.left;
|
|
191
|
+
const top = style.top;
|
|
192
|
+
const right = left + popperRect.width;
|
|
193
|
+
const bottom = top + popperRect.height;
|
|
194
|
+
const viewportWidth = window.innerWidth;
|
|
195
|
+
const viewportHeight = window.innerHeight;
|
|
196
|
+
const isWithinHorizontal = left >= viewportMargin && right <= viewportWidth - viewportMargin;
|
|
197
|
+
const isWithinVertical = top >= viewportMargin && bottom <= viewportHeight - viewportMargin;
|
|
198
|
+
return isWithinHorizontal && isWithinVertical;
|
|
199
|
+
}, [viewportMargin]);
|
|
200
|
+
const placementsOrder = react_1.default.useMemo(() => {
|
|
201
|
+
const basePlacements = {
|
|
202
|
+
top: ['top', 'top-left', 'top-right', 'top-start', 'top-end'],
|
|
203
|
+
bottom: ['bottom', 'bottom-left', 'bottom-right', 'bottom-start', 'bottom-end'],
|
|
204
|
+
left: ['left', 'left-top', 'left-bottom'],
|
|
205
|
+
right: ['right', 'right-top', 'right-bottom'],
|
|
206
|
+
};
|
|
207
|
+
const allPlacements = [
|
|
208
|
+
...basePlacements.top,
|
|
209
|
+
...basePlacements.bottom,
|
|
210
|
+
...basePlacements.left,
|
|
211
|
+
...basePlacements.right,
|
|
212
|
+
];
|
|
213
|
+
const order = {};
|
|
214
|
+
allPlacements.forEach(placement => {
|
|
215
|
+
const [direction] = placement.split('-');
|
|
216
|
+
// Priority: same direction > opposite > the rest
|
|
217
|
+
const opposite = direction === 'top'
|
|
218
|
+
? 'bottom'
|
|
219
|
+
: direction === 'bottom'
|
|
220
|
+
? 'top'
|
|
221
|
+
: direction === 'left'
|
|
222
|
+
? 'right'
|
|
223
|
+
: 'left';
|
|
224
|
+
order[placement] = [
|
|
225
|
+
placement,
|
|
226
|
+
...basePlacements[direction].filter(p => p !== placement),
|
|
227
|
+
...(basePlacements[opposite] || []),
|
|
228
|
+
...(direction !== 'left' && direction !== 'right' ? basePlacements.left : []),
|
|
229
|
+
...(direction !== 'left' && direction !== 'right' ? basePlacements.right : []),
|
|
230
|
+
];
|
|
231
|
+
});
|
|
232
|
+
// console.log(order);
|
|
233
|
+
return order;
|
|
234
|
+
}, []);
|
|
235
|
+
// #region Get Preferred Placements
|
|
236
|
+
const getPreferredPlacements = react_1.default.useCallback((preferredPlacement, anchorRect, popperRect) => {
|
|
237
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
238
|
+
const tryPlacement = (placement) => {
|
|
239
|
+
const viewportStyle = getPositionStyle({
|
|
240
|
+
place: placement,
|
|
241
|
+
anchorRect,
|
|
242
|
+
popperRect,
|
|
243
|
+
forViewportCheck: true,
|
|
244
|
+
});
|
|
245
|
+
if (!checkIfViewportFits(viewportStyle, popperRect)) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
const finalStyle = getPositionStyle({
|
|
249
|
+
place: placement,
|
|
250
|
+
anchorRect,
|
|
251
|
+
popperRect,
|
|
252
|
+
forViewportCheck: false,
|
|
253
|
+
});
|
|
254
|
+
return {
|
|
255
|
+
found: true,
|
|
256
|
+
placement,
|
|
257
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
const fallback = (placement) => {
|
|
261
|
+
const finalStyle = getPositionStyle({
|
|
262
|
+
place: placement,
|
|
263
|
+
anchorRect,
|
|
264
|
+
popperRect,
|
|
265
|
+
forViewportCheck: false,
|
|
266
|
+
});
|
|
267
|
+
return {
|
|
268
|
+
found: false,
|
|
269
|
+
placement,
|
|
270
|
+
style: clampPopperToContainer(finalStyle, popperRect),
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
const isAuto = preferredPlacement.startsWith('auto');
|
|
274
|
+
const isFill = preferredPlacement.endsWith('fill');
|
|
275
|
+
// -------------------------------------------------------
|
|
276
|
+
// 1. EXPLICIT (top, bottom, left, right, top-left, ...)
|
|
277
|
+
// -------------------------------------------------------
|
|
278
|
+
if (!isAuto && !isFill) {
|
|
279
|
+
if (!autoFlip) {
|
|
280
|
+
return (_a = tryPlacement(preferredPlacement)) !== null && _a !== void 0 ? _a : fallback(preferredPlacement);
|
|
281
|
+
}
|
|
282
|
+
// Формируем порядок без дубликатов
|
|
283
|
+
const order = Array.from(new Set([
|
|
284
|
+
preferredPlacement,
|
|
285
|
+
...((_b = alternativePlacements === null || alternativePlacements === void 0 ? void 0 : alternativePlacements.filter(p => !p.startsWith('auto') && !p.endsWith('fill'))) !== null && _b !== void 0 ? _b : []),
|
|
286
|
+
...((_c = placementsOrder[preferredPlacement]) !== null && _c !== void 0 ? _c : []),
|
|
287
|
+
]));
|
|
288
|
+
for (const p of order) {
|
|
289
|
+
const r = tryPlacement(p);
|
|
290
|
+
if (r)
|
|
291
|
+
return r;
|
|
292
|
+
}
|
|
293
|
+
return fallback(preferredPlacement);
|
|
294
|
+
}
|
|
295
|
+
// -------------------------------------------------------
|
|
296
|
+
// 2. FILL (bottom-fill, top-fill)
|
|
297
|
+
// -------------------------------------------------------
|
|
298
|
+
if (isFill) {
|
|
299
|
+
const [dir] = preferredPlacement.split('-');
|
|
300
|
+
if (!autoFlip) {
|
|
301
|
+
return (_d = tryPlacement(preferredPlacement)) !== null && _d !== void 0 ? _d : fallback(preferredPlacement);
|
|
302
|
+
}
|
|
303
|
+
const opposite = dir === 'bottom' ? 'top-fill' : 'bottom-fill';
|
|
304
|
+
// Формируем порядок: fill сначала, потом обычные позиции из альтернатив, потом дефолтные
|
|
305
|
+
const order = Array.from(new Set([
|
|
306
|
+
preferredPlacement,
|
|
307
|
+
opposite,
|
|
308
|
+
// Обычные позиции из alternativePlacements (не auto и не fill)
|
|
309
|
+
...((_e = alternativePlacements === null || alternativePlacements === void 0 ? void 0 : alternativePlacements.filter(p => !p.startsWith('auto') && !p.endsWith('fill'))) !== null && _e !== void 0 ? _e : []),
|
|
310
|
+
// Обычные позиции из дефолтного порядка (не fill)
|
|
311
|
+
...((_g = (_f = placementsOrder[preferredPlacement]) === null || _f === void 0 ? void 0 : _f.filter(p => !p.endsWith('fill'))) !== null && _g !== void 0 ? _g : []),
|
|
312
|
+
]));
|
|
313
|
+
for (const p of order) {
|
|
314
|
+
const r = tryPlacement(p);
|
|
315
|
+
if (r)
|
|
316
|
+
return r;
|
|
317
|
+
}
|
|
318
|
+
return fallback(preferredPlacement);
|
|
319
|
+
}
|
|
320
|
+
// -------------------------------------------------------
|
|
321
|
+
// 3. AUTO
|
|
322
|
+
// -------------------------------------------------------
|
|
323
|
+
if (isAuto) {
|
|
324
|
+
// Если autoFlip выключен - просто используем дефолтное направление
|
|
325
|
+
if (!autoFlip) {
|
|
326
|
+
const [, dir = 'bottom'] = preferredPlacement.split('-');
|
|
327
|
+
const defaultPlacement = dir;
|
|
328
|
+
return (_h = tryPlacement(defaultPlacement)) !== null && _h !== void 0 ? _h : fallback(defaultPlacement);
|
|
329
|
+
}
|
|
330
|
+
const [, dir = 'bottom'] = preferredPlacement.split('-');
|
|
331
|
+
const base = (alternativePlacements === null || alternativePlacements === void 0 ? void 0 : alternativePlacements.length)
|
|
332
|
+
? alternativePlacements
|
|
333
|
+
: [
|
|
334
|
+
'bottom',
|
|
335
|
+
'bottom-start',
|
|
336
|
+
'bottom-end',
|
|
337
|
+
'bottom-left',
|
|
338
|
+
'bottom-right',
|
|
339
|
+
'top',
|
|
340
|
+
'top-left',
|
|
341
|
+
'top-right',
|
|
342
|
+
'top-start',
|
|
343
|
+
'top-end',
|
|
344
|
+
'left',
|
|
345
|
+
'left-top',
|
|
346
|
+
'left-bottom',
|
|
347
|
+
'right',
|
|
348
|
+
'right-top',
|
|
349
|
+
'right-bottom',
|
|
350
|
+
];
|
|
351
|
+
const sorted = [...base].sort((a, b) => {
|
|
352
|
+
const ad = a.split('-')[0];
|
|
353
|
+
const bd = b.split('-')[0];
|
|
354
|
+
if (ad === dir && bd !== dir)
|
|
355
|
+
return -1;
|
|
356
|
+
if (ad !== dir && bd === dir)
|
|
357
|
+
return 1;
|
|
358
|
+
return 0;
|
|
359
|
+
});
|
|
360
|
+
for (const p of sorted) {
|
|
361
|
+
const r = tryPlacement(p);
|
|
362
|
+
if (r)
|
|
363
|
+
return r;
|
|
364
|
+
}
|
|
365
|
+
return fallback(dir);
|
|
366
|
+
}
|
|
367
|
+
// -------------------------------------------------------
|
|
368
|
+
// 4. SUPER FALLBACK
|
|
369
|
+
// -------------------------------------------------------
|
|
370
|
+
return fallback('bottom');
|
|
371
|
+
}, [
|
|
372
|
+
autoFlip,
|
|
373
|
+
getPositionStyle,
|
|
374
|
+
checkIfViewportFits,
|
|
375
|
+
clampPopperToContainer,
|
|
376
|
+
placementsOrder,
|
|
377
|
+
alternativePlacements,
|
|
378
|
+
]);
|
|
379
|
+
// #region Calculate Position
|
|
380
|
+
const calculatePosition = react_1.default.useCallback(() => {
|
|
381
|
+
if (!anchorElement || !popperRef.current) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const anchorRect = anchorElement.getBoundingClientRect();
|
|
385
|
+
const popperRect = popperRef.current.getBoundingClientRect();
|
|
386
|
+
const { style, placement, found } = getPreferredPlacements(anchorPos, anchorRect, popperRect);
|
|
387
|
+
if (found) {
|
|
388
|
+
setActualPlacement(placement);
|
|
389
|
+
}
|
|
390
|
+
setStyle(style);
|
|
391
|
+
}, [anchorElement, anchorPos, getPreferredPlacements]);
|
|
392
|
+
/**
|
|
393
|
+
* Open / Close popper logic
|
|
394
|
+
*/
|
|
395
|
+
react_1.default.useEffect(() => {
|
|
396
|
+
if (!isOpen) {
|
|
397
|
+
setIsVisible(false);
|
|
398
|
+
setStyle(null);
|
|
399
|
+
}
|
|
400
|
+
else if (anchorElement && isOpen && popperRef.current) {
|
|
401
|
+
calculatePosition();
|
|
402
|
+
setIsVisible(true);
|
|
403
|
+
}
|
|
404
|
+
}, [anchorElement, getPreferredPlacements, isOpen, calculatePosition]);
|
|
405
|
+
/**
|
|
406
|
+
* The anchor element changes
|
|
407
|
+
*/
|
|
408
|
+
react_1.default.useEffect(() => {
|
|
409
|
+
if (!isOpen || !anchorElement) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const observer = new MutationObserver(() => {
|
|
413
|
+
window.requestAnimationFrame(() => {
|
|
414
|
+
// console.log('The anchor element was change');
|
|
415
|
+
calculatePosition();
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
observer.observe(anchorElement, {
|
|
419
|
+
attributes: true,
|
|
420
|
+
childList: true,
|
|
421
|
+
subtree: true,
|
|
422
|
+
});
|
|
423
|
+
// eslint-disable-next-line consistent-return
|
|
424
|
+
return () => {
|
|
425
|
+
observer.disconnect();
|
|
426
|
+
};
|
|
427
|
+
}, [isOpen, anchorElement, calculatePosition]);
|
|
428
|
+
/**
|
|
429
|
+
* On scroll - recalculate position
|
|
430
|
+
*/
|
|
431
|
+
react_1.default.useEffect(() => {
|
|
432
|
+
if (!isOpen || !scrollableAncestor) {
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const handleScroll = () => {
|
|
436
|
+
window.requestAnimationFrame(() => {
|
|
437
|
+
calculatePosition();
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
// parent scroll listener
|
|
441
|
+
if (scrollableAncestor instanceof HTMLElement) {
|
|
442
|
+
scrollableAncestor.addEventListener('scroll', handleScroll, { passive: true });
|
|
443
|
+
}
|
|
444
|
+
else if (scrollableAncestor === window) {
|
|
445
|
+
window.addEventListener('scroll', handleScroll, { passive: true });
|
|
446
|
+
}
|
|
447
|
+
// eslint-disable-next-line consistent-return
|
|
448
|
+
return () => {
|
|
449
|
+
if (scrollableAncestor instanceof HTMLElement) {
|
|
450
|
+
scrollableAncestor.removeEventListener('scroll', handleScroll);
|
|
451
|
+
}
|
|
452
|
+
else if (scrollableAncestor === window) {
|
|
453
|
+
window.removeEventListener('scroll', handleScroll);
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
}, [isOpen, scrollableAncestor, calculatePosition]);
|
|
457
|
+
/**
|
|
458
|
+
* On window resize - recalculate position
|
|
459
|
+
*/
|
|
460
|
+
react_1.default.useEffect(() => {
|
|
461
|
+
if (!isOpen) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const handleResize = () => {
|
|
465
|
+
window.requestAnimationFrame(() => {
|
|
466
|
+
calculatePosition();
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
// parent scroll listener
|
|
470
|
+
window.addEventListener('resize', handleResize);
|
|
471
|
+
// eslint-disable-next-line consistent-return
|
|
472
|
+
return () => {
|
|
473
|
+
window.removeEventListener('resize', handleResize);
|
|
474
|
+
};
|
|
475
|
+
}, [calculatePosition, isOpen]);
|
|
476
|
+
return {
|
|
477
|
+
actualPlacement,
|
|
478
|
+
style,
|
|
479
|
+
popperRef,
|
|
480
|
+
isVisible,
|
|
481
|
+
scrollableAncestor,
|
|
482
|
+
calculatePosition,
|
|
483
|
+
setActualPlacement,
|
|
484
|
+
setStyle,
|
|
485
|
+
setIsVisible,
|
|
486
|
+
};
|
|
487
|
+
};
|
|
488
|
+
exports.usePopper = usePopper;
|
|
489
|
+
exports.default = exports.usePopper;
|
|
@@ -66,39 +66,14 @@ const StyledSelectboxButton = (0, styled_1.default)(Button_1.default) `
|
|
|
66
66
|
}
|
|
67
67
|
`}
|
|
68
68
|
transition: none;
|
|
69
|
-
|
|
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
|
-
`};
|
|
69
|
+
|
|
95
70
|
`;
|
|
96
71
|
const StyledButtonTextWrapper = (0, styled_1.default)(ButtonTextWrapper_1.default) `
|
|
97
72
|
flex: 1;
|
|
98
73
|
`;
|
|
99
74
|
const SelectboxButton = (props, ref) => {
|
|
100
75
|
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,
|
|
76
|
+
return (React.createElement(StyledSelectboxButton, Object.assign({ "$fullWidth": fullWidth, "$error": error }, nativeProps, { "$isOpen": isOpen, overrides: {
|
|
102
77
|
TextWrapper: StyledButtonTextWrapper,
|
|
103
78
|
}, ref: ref }), children));
|
|
104
79
|
};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { MenuProps, MenuRef } from '../Menu';
|
|
3
|
-
import { AnchorPos } from '../Popper';
|
|
4
3
|
import { OnChange } from 'Selectbox';
|
|
5
4
|
export interface SelectbosMenuProps<T, Multiple extends boolean | undefined = undefined> extends MenuProps<T, Multiple> {
|
|
6
|
-
readonly actualPlacement: AnchorPos;
|
|
7
5
|
readonly onChange?: OnChange<T, Multiple>;
|
|
8
6
|
}
|
|
9
7
|
declare const _default: <T, Multiple extends boolean | undefined = undefined>(props: SelectbosMenuProps<T, Multiple> & {
|
|
@@ -22,15 +22,25 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
26
|
+
var t = {};
|
|
27
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
+
t[p] = s[p];
|
|
29
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
+
t[p[i]] = s[p[i]];
|
|
33
|
+
}
|
|
34
|
+
return t;
|
|
35
|
+
};
|
|
25
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
38
|
};
|
|
28
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
40
|
const React = __importStar(require("react"));
|
|
30
41
|
const Menu_1 = __importDefault(require("../Menu"));
|
|
31
|
-
const OverrideMenuList_1 = __importDefault(require("../Autocomplete/OverrideMenuList"));
|
|
32
42
|
const SelectboxMenu = React.forwardRef((props, ref) => {
|
|
33
|
-
const {
|
|
43
|
+
const { multiple, items, value, isOpen, anchorPos, anchorElement, getOptionSelected, onChange, onRequestClose, children } = props, restMenuProps = __rest(props, ["multiple", "items", "value", "isOpen", "anchorPos", "anchorElement", "getOptionSelected", "onChange", "onRequestClose", "children"]);
|
|
34
44
|
const handleSelectItem = React.useCallback((item) => {
|
|
35
45
|
onChange === null || onChange === void 0 ? void 0 : onChange(item);
|
|
36
46
|
}, [onChange]);
|
|
@@ -42,9 +52,7 @@ const SelectboxMenu = React.forwardRef((props, ref) => {
|
|
|
42
52
|
anchorElement === null || anchorElement === void 0 ? void 0 : anchorElement.focus();
|
|
43
53
|
}
|
|
44
54
|
}, [onRequestClose, anchorElement]);
|
|
45
|
-
return (React.createElement(Menu_1.default, { ref: ref, offset: 0, anchorPos:
|
|
46
|
-
List: OverrideMenuList_1.default,
|
|
47
|
-
}, closeOnSelect: !multiple, onRequestClose: handleRequestClose }, ({ index, item }, itemProps) => children({ index, item: item }, itemProps)));
|
|
55
|
+
return (React.createElement(Menu_1.default, Object.assign({ ref: ref, offset: 0, anchorPos: anchorPos, multiple: multiple, items: items, value: value, isOpen: isOpen && items.length > 0, autofocus: true, anchorElement: anchorElement, closeOutsideClick: false, getOptionSelected: getOptionSelected, onSelectItem: handleSelectItem, closeOnSelect: !multiple, onRequestClose: handleRequestClose }, restMenuProps), ({ index, item }, itemProps) => children({ index, item: item }, itemProps)));
|
|
48
56
|
});
|
|
49
57
|
SelectboxMenu.displayName = 'SelectboxMenu';
|
|
50
58
|
exports.default = React.memo(SelectboxMenu);
|
package/Selectbox/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { GetOptionSelected, OnRequestClose, Value } from '../Menu';
|
|
3
|
-
import type {
|
|
3
|
+
import type { MenuItemProps } from '../Menu/MenuItem';
|
|
4
4
|
import SelectboxItem from '../Menu/MenuItem';
|
|
5
5
|
import { SelectboxButtonProps } from './SelectboxButton';
|
|
6
6
|
import { SelectboxChevronIconProps } from './SelectboxChevronIcon';
|
|
7
|
-
import { AnchorPos } from '../Popper';
|
|
7
|
+
import { AnchorPos, PositionStrategy } from '../Popper';
|
|
8
8
|
import { TextFieldLabelProps } from '../TextField/TextFieldLabel';
|
|
9
9
|
import { TextFieldLabelAsteriskProps } from '../TextField/TextFieldLabelAsterisk';
|
|
10
10
|
import { TextFieldErrorTextProps } from '../TextField/TextFieldErrorText';
|
|
@@ -36,6 +36,8 @@ export interface SelectboxProps<T, Multiple extends boolean | undefined = undefi
|
|
|
36
36
|
* Default: `bottom`
|
|
37
37
|
*/
|
|
38
38
|
readonly anchorPos?: AnchorPos;
|
|
39
|
+
readonly positionStrategy?: PositionStrategy;
|
|
40
|
+
readonly autoFlip?: boolean;
|
|
39
41
|
/**
|
|
40
42
|
* Text field loading state\
|
|
41
43
|
* If `true` then text field has been contained the loading indicator, otherwise - nop
|
|
@@ -154,7 +156,7 @@ export interface SelectboxOverrides {
|
|
|
154
156
|
export type Children<T> = (data: {
|
|
155
157
|
item: T;
|
|
156
158
|
index: number;
|
|
157
|
-
}, itemProps:
|
|
159
|
+
}, itemProps: MenuItemProps) => React.ReactNode;
|
|
158
160
|
export type ItemToString<T, Multiple extends boolean | undefined = undefined> = (item: Multiple extends undefined ? T : readonly T[]) => string;
|
|
159
161
|
export type OnChange<T, Multiple extends boolean | undefined = undefined> = (item: Value<T, Multiple>) => void;
|
|
160
162
|
declare const _default: <T, Multiple extends boolean | undefined = undefined>(props: SelectboxProps<T, Multiple> & {
|
package/Selectbox/index.js
CHANGED
|
@@ -70,9 +70,8 @@ const generateGuid = () => {
|
|
|
70
70
|
].join('-');
|
|
71
71
|
};
|
|
72
72
|
const Selectbox = React.forwardRef((props, ref) => {
|
|
73
|
-
const { items, value, multiple, isOpen = false, isLoading = false, anchorPos = 'bottom-fill', fullWidth = false, children, onChange, selectedItemToString, getOptionSelected, onRequestOpen = () => undefined, onRequestClose = () => undefined, overrides, id, label, onFocus, requiredAsterisk, error, errorText, notSetLabel = 'Not set' } = props, nativeButtonProps = __rest(props, ["items", "value", "multiple", "isOpen", "isLoading", "anchorPos", "fullWidth", "children", "onChange", "selectedItemToString", "getOptionSelected", "onRequestOpen", "onRequestClose", "overrides", "id", "label", "onFocus", "requiredAsterisk", "error", "errorText", "notSetLabel"]);
|
|
73
|
+
const { items, value, multiple, isOpen = false, isLoading = false, anchorPos = 'bottom-fill', fullWidth = false, children, onChange, selectedItemToString, getOptionSelected, onRequestOpen = () => undefined, onRequestClose = () => undefined, overrides, id, label, onFocus, requiredAsterisk, error, errorText, notSetLabel = 'Not set', autoFlip = true, positionStrategy } = props, nativeButtonProps = __rest(props, ["items", "value", "multiple", "isOpen", "isLoading", "anchorPos", "fullWidth", "children", "onChange", "selectedItemToString", "getOptionSelected", "onRequestOpen", "onRequestClose", "overrides", "id", "label", "onFocus", "requiredAsterisk", "error", "errorText", "notSetLabel", "autoFlip", "positionStrategy"]);
|
|
74
74
|
const menuRef = React.useRef(null);
|
|
75
|
-
const [actualPlacement, setActualPlacement] = React.useState(anchorPos);
|
|
76
75
|
const [anchorElement, setAnchorElement] = React.useState(null);
|
|
77
76
|
const overridesMap = React.useMemo(() => (Object.assign(Object.assign({}, DEFAULT_OVERRIDES), overrides)), [overrides]);
|
|
78
77
|
const inputID = React.useMemo(() => {
|
|
@@ -136,7 +135,8 @@ const Selectbox = React.forwardRef((props, ref) => {
|
|
|
136
135
|
}, [handleMouseDown]);
|
|
137
136
|
const buttonProps = React.useMemo(() => (Object.assign({ fullWidth,
|
|
138
137
|
error,
|
|
139
|
-
isOpen,
|
|
138
|
+
isOpen,
|
|
139
|
+
anchorPos, endIcon: isLoading ? React.createElement(Spinner_1.default, null) : React.createElement(overridesMap.Icon, { isOpen: isOpen }) }, nativeButtonProps)), [fullWidth, error, isOpen, anchorPos, isLoading, overridesMap, nativeButtonProps]);
|
|
140
140
|
const labelProps = React.useMemo(() => ({
|
|
141
141
|
htmlFor: inputID,
|
|
142
142
|
error,
|
|
@@ -151,7 +151,7 @@ const Selectbox = React.forwardRef((props, ref) => {
|
|
|
151
151
|
React.createElement(overridesMap.ButtonWrapper, { fullWidth: fullWidth, error: error, isOpen: isOpen },
|
|
152
152
|
React.createElement(overridesMap.Button, Object.assign({}, buttonProps, { onClick: handleButtonClick, ref: setRefs }), renderValueAsString())),
|
|
153
153
|
React.createElement(overridesMap.ErrorText, { error: error }, errorText),
|
|
154
|
-
React.createElement(SelectboxMenu_1.default, {
|
|
154
|
+
React.createElement(SelectboxMenu_1.default, { multiple: multiple, items: items, value: value, isOpen: isOpen, anchorPos: anchorPos, positionStrategy: positionStrategy, autoFlip: autoFlip, alternativePlacements: ['bottom-fill', 'top-fill'], anchorElement: anchorElement, getOptionSelected: getOptionSelected, onChange: onChange, onRequestClose: onRequestClose, ref: menuRef }, children)));
|
|
155
155
|
});
|
|
156
156
|
Selectbox.displayName = 'Selectbox';
|
|
157
157
|
exports.default = Selectbox;
|
package/Swiper/Swiper.d.ts
CHANGED
|
@@ -30,7 +30,6 @@ export type SwiperProps = Omit<React.HTMLAttributes<HTMLDivElement>, 'children'>
|
|
|
30
30
|
readonly autoplay?: boolean;
|
|
31
31
|
readonly autoplayInterval?: number;
|
|
32
32
|
readonly pauseOnHover?: boolean;
|
|
33
|
-
readonly keyboardControl?: boolean;
|
|
34
33
|
readonly threshold?: number;
|
|
35
34
|
readonly resistance?: boolean;
|
|
36
35
|
readonly slidesPerView?: number;
|
|
@@ -47,7 +46,6 @@ export declare const Swiper: React.ForwardRefExoticComponent<Omit<React.HTMLAttr
|
|
|
47
46
|
readonly autoplay?: boolean | undefined;
|
|
48
47
|
readonly autoplayInterval?: number | undefined;
|
|
49
48
|
readonly pauseOnHover?: boolean | undefined;
|
|
50
|
-
readonly keyboardControl?: boolean | undefined;
|
|
51
49
|
readonly threshold?: number | undefined;
|
|
52
50
|
readonly resistance?: boolean | undefined;
|
|
53
51
|
readonly slidesPerView?: number | undefined;
|