@sima-land/ui-nucleons 41.3.0 → 42.2.0
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/alert/index.d.ts +1 -3
- package/alert/index.js +8 -32
- package/autocomplete/index.js +9 -11
- package/carousel/index.d.ts +9 -12
- package/carousel/index.js +66 -47
- package/helpers/find-child-element.d.ts +1 -1
- package/hooks/index.js +3 -6
- package/modal/index.d.ts +0 -2
- package/modal/index.js +2 -25
- package/modal/utils.d.ts +3 -2
- package/modal/utils.js +6 -3
- package/package.json +1 -1
- package/phone-input/index.d.ts +1 -1
- package/phone-input/index.js +24 -17
- package/phone-input/phone-input.module.scss +9 -2
- package/select/index.d.ts +9 -2
- package/select/index.js +18 -10
- package/text-field/index.d.ts +1 -1
- package/text-field/index.js +13 -7
package/alert/index.d.ts
CHANGED
|
@@ -8,8 +8,6 @@ export interface AlertProps extends WithBodyScrollLock {
|
|
|
8
8
|
className?: string;
|
|
9
9
|
/** Содержимое "подвала". */
|
|
10
10
|
footer?: React.ReactNode;
|
|
11
|
-
/** Нужно ли выводить в Layer. */
|
|
12
|
-
inPortal?: boolean;
|
|
13
11
|
/** Свойства компонента NavBar. */
|
|
14
12
|
navBarProps?: NavBarProps;
|
|
15
13
|
/** Заголовок. */
|
|
@@ -26,4 +24,4 @@ export interface AlertProps extends WithBodyScrollLock {
|
|
|
26
24
|
* @param props Свойства.
|
|
27
25
|
* @return Элемент.
|
|
28
26
|
*/
|
|
29
|
-
export declare const Alert: ({
|
|
27
|
+
export declare const Alert: ({ children, className, footer, navBarProps, title, withDivideNavBar, withNavBar, withScrollDisable, scrollDisableOptions, onClose, }: AlertProps) => JSX.Element;
|
package/alert/index.js
CHANGED
|
@@ -18,24 +18,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
18
|
__setModuleDefault(result, mod);
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
22
|
-
var t = {};
|
|
23
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
24
|
-
t[p] = s[p];
|
|
25
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
26
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
27
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
28
|
-
t[p[i]] = s[p[i]];
|
|
29
|
-
}
|
|
30
|
-
return t;
|
|
31
|
-
};
|
|
32
21
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
33
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
23
|
};
|
|
35
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
25
|
exports.Alert = void 0;
|
|
37
26
|
const react_1 = __importStar(require("react"));
|
|
38
|
-
const portal_1 = require("../portal");
|
|
39
27
|
const nav_bar_1 = require("../nav-bar");
|
|
40
28
|
const bind_1 = __importDefault(require("classnames/bind"));
|
|
41
29
|
const alert_module_scss_1 = __importDefault(require("./alert.module.scss"));
|
|
@@ -48,27 +36,15 @@ const cx = bind_1.default.bind(alert_module_scss_1.default);
|
|
|
48
36
|
* @param props Свойства.
|
|
49
37
|
* @return Элемент.
|
|
50
38
|
*/
|
|
51
|
-
const Alert = (
|
|
52
|
-
var { inPortal = true } = _a, restProps = __rest(_a, ["inPortal"]);
|
|
39
|
+
const Alert = ({ children, className, footer, navBarProps, title, withDivideNavBar, withNavBar = Boolean(title), withScrollDisable = false, scrollDisableOptions, onClose, }) => {
|
|
53
40
|
const layer = (0, layer_1.useLayer)() + 100;
|
|
54
|
-
const Wrapper = inPortal ? portal_1.Portal : react_1.Fragment;
|
|
55
|
-
return (react_1.default.createElement(layer_1.LayerProvider, { value: layer },
|
|
56
|
-
react_1.default.createElement(Wrapper, null,
|
|
57
|
-
react_1.default.createElement(AlertInner, Object.assign({}, restProps)))));
|
|
58
|
-
};
|
|
59
|
-
exports.Alert = Alert;
|
|
60
|
-
/**
|
|
61
|
-
* Промежуточный компонент, необходимый для того чтобы не передавать реф для блокировки прокрутки через портал.
|
|
62
|
-
* @param props Свойства.
|
|
63
|
-
* @return Элемент.
|
|
64
|
-
*/
|
|
65
|
-
const AlertInner = ({ children, className, footer, navBarProps, title, withDivideNavBar, withNavBar = Boolean(title), withScrollDisable = false, scrollDisableOptions, onClose, }) => {
|
|
66
41
|
const rootRef = (0, react_1.useRef)(null);
|
|
67
|
-
const layer = (0, layer_1.useLayer)();
|
|
68
42
|
(0, body_scroll_1.useBodyScrollLock)(rootRef, withScrollDisable, Object.assign({ allowTouchMove: body_scroll_1.allowTouchMove }, scrollDisableOptions));
|
|
69
|
-
return (react_1.default.createElement(
|
|
70
|
-
react_1.default.createElement("div", { className: cx('
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
43
|
+
return (react_1.default.createElement(layer_1.LayerProvider, { value: layer },
|
|
44
|
+
react_1.default.createElement("div", { ref: rootRef, className: cx('overlay'), style: { zIndex: layer }, onClick: e => e.target === e.currentTarget && (onClose === null || onClose === void 0 ? void 0 : onClose()), "data-testid": 'alert:overlay' },
|
|
45
|
+
react_1.default.createElement("div", { className: cx('alert', className), "data-testid": 'alert' },
|
|
46
|
+
withNavBar && (react_1.default.createElement(nav_bar_1.NavBar, Object.assign({}, navBarProps, { title: title, bottomBordered: withDivideNavBar, className: cx('header') }))),
|
|
47
|
+
react_1.default.createElement("div", { className: cx('main') }, children),
|
|
48
|
+
Boolean(footer) && react_1.default.createElement("div", { className: borders_1.InnerBorder.top }, footer)))));
|
|
74
49
|
};
|
|
50
|
+
exports.Alert = Alert;
|
package/autocomplete/index.js
CHANGED
|
@@ -66,15 +66,13 @@ const Autocomplete = (_a) => {
|
|
|
66
66
|
const rootRef = (0, react_1.useRef)(null);
|
|
67
67
|
const fieldRef = (0, react_1.useRef)();
|
|
68
68
|
const menuRef = (0, react_1.useRef)();
|
|
69
|
-
const [
|
|
69
|
+
const [withMenu, toggleMenu] = (0, react_1.useState)(false);
|
|
70
70
|
const [realValue, setRealValue] = (0, react_1.useState)(value || defaultValue);
|
|
71
71
|
const [activeIndex, setActiveIndex] = (0, react_1.useState)(null);
|
|
72
|
-
const canShowDropdown = preset === 'filled-only-list'
|
|
73
|
-
? needDropdown && realValue && realValue.length > 0
|
|
74
|
-
: needDropdown;
|
|
72
|
+
const canShowDropdown = preset === 'filled-only-list' ? withMenu && realValue && realValue.length > 0 : withMenu;
|
|
75
73
|
const endAdornment = preset === 'default' ? react_1.default.createElement(down_1.default, { fill: colors_1.COLORS.get('gray38') }) : undefined;
|
|
76
74
|
(0, hooks_1.useOutsideClick)(rootRef, () => {
|
|
77
|
-
|
|
75
|
+
toggleMenu(false);
|
|
78
76
|
});
|
|
79
77
|
(0, react_1.useEffect)(() => {
|
|
80
78
|
setRealValue(value);
|
|
@@ -88,7 +86,7 @@ const Autocomplete = (_a) => {
|
|
|
88
86
|
const osInstance = (_a = osComponentRef.current) === null || _a === void 0 ? void 0 : _a.osInstance();
|
|
89
87
|
if (menu && osInstance && activeIndex !== null) {
|
|
90
88
|
const child = menu.querySelectorAll('[role="menuitem"]')[activeIndex];
|
|
91
|
-
child &&
|
|
89
|
+
child instanceof HTMLElement &&
|
|
92
90
|
osInstance.scroll({
|
|
93
91
|
el: child,
|
|
94
92
|
scroll: { y: 'ifneeded' },
|
|
@@ -96,11 +94,11 @@ const Autocomplete = (_a) => {
|
|
|
96
94
|
}
|
|
97
95
|
}, [activeIndex]);
|
|
98
96
|
return (react_1.default.createElement("div", { ref: rootRef, style: style, className: cx('root', className), "data-testid": dataTestId },
|
|
99
|
-
react_1.default.createElement(text_field_1.TextField, Object.assign({}, restProps, { ref: fieldRef, focused:
|
|
100
|
-
|
|
97
|
+
react_1.default.createElement(text_field_1.TextField, Object.assign({}, restProps, { ref: fieldRef, focused: withMenu, endAdornment: endAdornment, "data-testid": 'autocomplete:field', variant: 'desktop', value: value, multiline: false, onClick: e => {
|
|
98
|
+
toggleMenu(true);
|
|
101
99
|
onClick && onClick(e);
|
|
102
100
|
}, onChange: (e) => {
|
|
103
|
-
|
|
101
|
+
toggleMenu(true);
|
|
104
102
|
setRealValue(e.target.value);
|
|
105
103
|
setActiveIndex(0);
|
|
106
104
|
onChange && onChange(e);
|
|
@@ -117,7 +115,7 @@ const Autocomplete = (_a) => {
|
|
|
117
115
|
case 'Enter':
|
|
118
116
|
if (items && !(0, lodash_1.isNull)(activeIndex) && items.length > activeIndex) {
|
|
119
117
|
onSelect && onSelect(items[activeIndex]);
|
|
120
|
-
|
|
118
|
+
toggleMenu(false);
|
|
121
119
|
}
|
|
122
120
|
break;
|
|
123
121
|
}
|
|
@@ -127,7 +125,7 @@ const Autocomplete = (_a) => {
|
|
|
127
125
|
canShowDropdown && (react_1.default.createElement(dropdown_1.Dropdown, Object.assign({}, (0, dropdown_2.placeDropdown)(restProps.size), { ref: menuRef, "data-testid": 'autocomplete:menu', className: cx('menu'), role: 'menu', customScrollbarProps: { osComponentRef } }), loading ? (react_1.default.createElement(dropdown_loading_1.DropdownLoading, { "data-testid": 'autocomplete:loading-area' })) : (react_1.default.createElement(react_1.default.Fragment, null, items && items.length > 0 ? (items.map((item, index) => (react_1.default.createElement(dropdown_item_1.DropdownItem, { size: itemSize, key: index, role: 'menuitem', checked: index === activeIndex, onClick: () => {
|
|
128
126
|
onSelect && onSelect(item);
|
|
129
127
|
setActiveIndex(null);
|
|
130
|
-
|
|
128
|
+
toggleMenu(false);
|
|
131
129
|
fieldRef.current && fieldRef.current.focus();
|
|
132
130
|
} }, renderItem(item))))) : (react_1.default.createElement(dropdown_item_1.DropdownItem, { size: 'm', noHover: true }, "\u041D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E"))))))));
|
|
133
131
|
};
|
package/carousel/index.d.ts
CHANGED
|
@@ -49,6 +49,9 @@ interface ControlData {
|
|
|
49
49
|
type: 'forward' | 'backward';
|
|
50
50
|
vertical?: boolean;
|
|
51
51
|
}
|
|
52
|
+
interface ElementPredicate {
|
|
53
|
+
(sibling: Element): boolean;
|
|
54
|
+
}
|
|
52
55
|
/**
|
|
53
56
|
* Карусель.
|
|
54
57
|
*/
|
|
@@ -96,8 +99,8 @@ export declare class Carousel extends Component<CarouselProps, State> {
|
|
|
96
99
|
*/
|
|
97
100
|
static makeFurthestSiblingChecker({ vertical, viewport, }: {
|
|
98
101
|
vertical: boolean;
|
|
99
|
-
viewport
|
|
100
|
-
}):
|
|
102
|
+
viewport?: DOMRect | null;
|
|
103
|
+
}): ElementPredicate;
|
|
101
104
|
/**
|
|
102
105
|
* Возвращает функцию для поиска наиболее близкого элемента карусели к viewport'у.
|
|
103
106
|
* @param data Данные.
|
|
@@ -109,8 +112,8 @@ export declare class Carousel extends Component<CarouselProps, State> {
|
|
|
109
112
|
static makeNearestSiblingChecker({ viewport, vertical, backward, }: {
|
|
110
113
|
backward: boolean;
|
|
111
114
|
vertical: boolean;
|
|
112
|
-
viewport
|
|
113
|
-
}):
|
|
115
|
+
viewport?: DOMRect | null;
|
|
116
|
+
}): ElementPredicate;
|
|
114
117
|
/**
|
|
115
118
|
* Геттер элемента списка.
|
|
116
119
|
* @return Элемент списка или null.
|
|
@@ -272,10 +275,7 @@ export declare class Carousel extends Component<CarouselProps, State> {
|
|
|
272
275
|
* @param dragEvent.offset Смещение.
|
|
273
276
|
* @param dragEvent.client Позиция.
|
|
274
277
|
*/
|
|
275
|
-
saveDragStartData({ offset, client }:
|
|
276
|
-
offset: IPoint;
|
|
277
|
-
client: IPoint;
|
|
278
|
-
}): void;
|
|
278
|
+
saveDragStartData({ offset, client }: DraggableEvent): void;
|
|
279
279
|
/**
|
|
280
280
|
* Сохраняет в состоянии смещение карусели.
|
|
281
281
|
* @param newOffset Смещение.
|
|
@@ -289,10 +289,7 @@ export declare class Carousel extends Component<CarouselProps, State> {
|
|
|
289
289
|
* @param draggableControls Функции управления Draggable.
|
|
290
290
|
*/
|
|
291
291
|
takeDragControl({ isGrabbed, setOffset, toggleTransition }: Control): void;
|
|
292
|
-
/**
|
|
293
|
-
* Рендер.
|
|
294
|
-
* @inheritDoc
|
|
295
|
-
*/
|
|
292
|
+
/** @inheritdoc */
|
|
296
293
|
render(): JSX.Element;
|
|
297
294
|
/**
|
|
298
295
|
* Формирует список элементов карусели с учетом необходимости клонирования.
|
package/carousel/index.js
CHANGED
|
@@ -106,9 +106,14 @@ class Carousel extends react_1.Component {
|
|
|
106
106
|
* @return Функция для поиска наиболее отдаленного элемента.
|
|
107
107
|
*/
|
|
108
108
|
static makeFurthestSiblingChecker({ vertical, viewport, }) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
// eslint-disable-next-line require-jsdoc
|
|
110
|
+
let checker = () => false;
|
|
111
|
+
if (viewport) {
|
|
112
|
+
checker = vertical
|
|
113
|
+
? (sibling) => (0, bounds_of_1.default)(sibling).top >= viewport.top
|
|
114
|
+
: (sibling) => (0, bounds_of_1.default)(sibling).left >= viewport.left;
|
|
115
|
+
}
|
|
116
|
+
return checker;
|
|
112
117
|
}
|
|
113
118
|
/**
|
|
114
119
|
* Возвращает функцию для поиска наиболее близкого элемента карусели к viewport'у.
|
|
@@ -121,9 +126,14 @@ class Carousel extends react_1.Component {
|
|
|
121
126
|
static makeNearestSiblingChecker({ viewport, vertical, backward, }) {
|
|
122
127
|
const verticalBoundKey = backward ? 'bottom' : 'top';
|
|
123
128
|
const horizontalBoundKey = backward ? 'right' : 'left';
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
// eslint-disable-next-line require-jsdoc
|
|
130
|
+
let checker = () => false;
|
|
131
|
+
if (viewport) {
|
|
132
|
+
checker = vertical
|
|
133
|
+
? (sibling) => viewport.top < (0, bounds_of_1.default)(sibling)[verticalBoundKey]
|
|
134
|
+
: (sibling) => viewport.left < (0, bounds_of_1.default)(sibling)[horizontalBoundKey];
|
|
135
|
+
}
|
|
136
|
+
return checker;
|
|
127
137
|
}
|
|
128
138
|
/**
|
|
129
139
|
* Геттер элемента списка.
|
|
@@ -240,12 +250,13 @@ class Carousel extends react_1.Component {
|
|
|
240
250
|
* @param step На сколько элементов надо прокрутить карусель.
|
|
241
251
|
*/
|
|
242
252
|
moveForwardFinite(step) {
|
|
253
|
+
var _a, _b;
|
|
243
254
|
const { currentIndex } = this;
|
|
244
255
|
const newIndex = currentIndex + step;
|
|
245
256
|
this.toggleDragTransition(true);
|
|
246
|
-
this.setCurrentIndex(newIndex < (0, lodash_1.size)(this.listElement.children)
|
|
257
|
+
this.setCurrentIndex(newIndex < (0, lodash_1.size)((_a = this.listElement) === null || _a === void 0 ? void 0 : _a.children)
|
|
247
258
|
? newIndex
|
|
248
|
-
: (0, max_index_of_1.default)(this.listElement.children));
|
|
259
|
+
: (0, max_index_of_1.default)((_b = this.listElement) === null || _b === void 0 ? void 0 : _b.children));
|
|
249
260
|
}
|
|
250
261
|
/**
|
|
251
262
|
* По возможности выполняет прокрутку карусели назад.
|
|
@@ -285,9 +296,11 @@ class Carousel extends react_1.Component {
|
|
|
285
296
|
const { currentOffset } = this.state;
|
|
286
297
|
const { items, vertical } = this.props;
|
|
287
298
|
const realItemsCount = (0, lodash_1.size)(items);
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
299
|
+
const listEl = this.listElement;
|
|
300
|
+
const needMoveForward = forward && currentIndex >= realItemsCount;
|
|
301
|
+
const needMoveBackward = !forward && currentIndex < realItemsCount;
|
|
302
|
+
if (listEl && (needMoveForward || needMoveBackward)) {
|
|
303
|
+
const itemsSize = listEl[vertical ? 'scrollHeight' : 'scrollWidth'] / CLONE_FACTOR;
|
|
291
304
|
const newOffset = currentOffset + (forward ? itemsSize : -itemsSize);
|
|
292
305
|
const newIndex = currentIndex + (forward ? -realItemsCount : realItemsCount);
|
|
293
306
|
this.setCurrentOffset(newOffset, { withStateUpdate: false });
|
|
@@ -324,28 +337,32 @@ class Carousel extends react_1.Component {
|
|
|
324
337
|
* @param dragEvent Событие.
|
|
325
338
|
*/
|
|
326
339
|
correctInfiniteOffset(dragEvent) {
|
|
340
|
+
var _a, _b;
|
|
327
341
|
const { vertical } = this.props;
|
|
328
342
|
const { offset, client } = dragEvent;
|
|
329
343
|
const { dragStartClient } = this;
|
|
330
344
|
const { forward, backward } = this.defineDirection(dragStartClient, client);
|
|
331
345
|
const viewport = this.getViewport();
|
|
332
|
-
const
|
|
333
|
-
const lastItem = this.listElement.lastElementChild;
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
346
|
+
const listEl = this.listElement;
|
|
347
|
+
const lastItem = (_a = this.listElement) === null || _a === void 0 ? void 0 : _a.lastElementChild;
|
|
348
|
+
if (viewport && listEl && lastItem) {
|
|
349
|
+
const offsetValue = offset[vertical ? 'y' : 'x'];
|
|
350
|
+
const lastItemStartBound = (_b = (0, bounds_of_1.default)(lastItem)) === null || _b === void 0 ? void 0 : _b[vertical ? 'top' : 'left'];
|
|
351
|
+
const viewportStartBound = viewport[vertical ? 'top' : 'left'];
|
|
352
|
+
const viewportEndBound = viewport[vertical ? 'bottom' : 'right'];
|
|
353
|
+
const itemsSize = listEl[vertical ? 'scrollHeight' : 'scrollWidth'] / CLONE_FACTOR;
|
|
354
|
+
if (forward && lastItemStartBound < viewportEndBound) {
|
|
355
|
+
const newOffset = offsetValue + itemsSize;
|
|
356
|
+
dragEvent.preventDefault();
|
|
357
|
+
this.setCurrentOffset(newOffset, { withStateUpdate: false });
|
|
358
|
+
this.saveDragStartData(dragEvent);
|
|
359
|
+
}
|
|
360
|
+
else if (backward && viewportStartBound < this.findRealItemsStartBound()) {
|
|
361
|
+
const newOffset = offsetValue - itemsSize;
|
|
362
|
+
dragEvent.preventDefault();
|
|
363
|
+
this.setCurrentOffset(newOffset, { withStateUpdate: false });
|
|
364
|
+
this.saveDragStartData(dragEvent);
|
|
365
|
+
}
|
|
349
366
|
}
|
|
350
367
|
}
|
|
351
368
|
/**
|
|
@@ -425,28 +442,30 @@ class Carousel extends react_1.Component {
|
|
|
425
442
|
* @param options.needTransition Нужна ли плавная анимация прокрутки.
|
|
426
443
|
*/
|
|
427
444
|
scrollToItem({ targetIndex = this.currentIndex, needTransition = true } = {}) {
|
|
428
|
-
|
|
429
|
-
|
|
445
|
+
var _a;
|
|
446
|
+
const listEl = this.listElement;
|
|
447
|
+
const viewport = this.getViewport();
|
|
448
|
+
const targetItemEl = (_a = this.listElement) === null || _a === void 0 ? void 0 : _a.children[targetIndex];
|
|
449
|
+
if (viewport && listEl && targetItemEl) {
|
|
430
450
|
this.toggleDragTransition(needTransition);
|
|
431
451
|
if (this.isAllItemsVisible()) {
|
|
432
452
|
this.setCurrentOffset(0);
|
|
433
453
|
}
|
|
434
454
|
else {
|
|
435
455
|
const { vertical } = this.props;
|
|
436
|
-
const viewport = this.getViewport();
|
|
437
456
|
const targetItemPos = (0, get_relative_pos_1.default)(targetItemEl);
|
|
438
457
|
const viewportEndBound = vertical ? viewport.bottom : viewport.right;
|
|
439
458
|
const nextItemsEndBound = vertical
|
|
440
|
-
? viewport.top +
|
|
441
|
-
: viewport.left +
|
|
459
|
+
? viewport.top + listEl.scrollHeight - targetItemPos.y
|
|
460
|
+
: viewport.left + listEl.scrollWidth - targetItemPos.x;
|
|
442
461
|
if (nextItemsEndBound >= viewportEndBound) {
|
|
443
462
|
const itemBound = vertical ? targetItemPos.y : targetItemPos.x;
|
|
444
463
|
this.setCurrentOffset(-itemBound);
|
|
445
464
|
}
|
|
446
465
|
else {
|
|
447
466
|
const maxItemsEndBound = vertical
|
|
448
|
-
? viewport.top +
|
|
449
|
-
: viewport.left +
|
|
467
|
+
? viewport.top + listEl.scrollHeight
|
|
468
|
+
: viewport.left + listEl.scrollWidth;
|
|
450
469
|
this.setCurrentOffset(viewportEndBound - maxItemsEndBound);
|
|
451
470
|
}
|
|
452
471
|
}
|
|
@@ -467,13 +486,14 @@ class Carousel extends react_1.Component {
|
|
|
467
486
|
*/
|
|
468
487
|
defineMinOffset() {
|
|
469
488
|
const { vertical } = this.props;
|
|
489
|
+
const viewport = this.getViewport();
|
|
490
|
+
const listEl = this.listElement;
|
|
470
491
|
let minOffset = NaN;
|
|
471
|
-
if (
|
|
472
|
-
const viewport = this.getViewport();
|
|
492
|
+
if (viewport && listEl) {
|
|
473
493
|
const viewportEndBound = vertical ? viewport.bottom : viewport.right;
|
|
474
494
|
const maxItemsEndBound = vertical
|
|
475
|
-
? viewport.top +
|
|
476
|
-
: viewport.left +
|
|
495
|
+
? viewport.top + listEl.scrollHeight
|
|
496
|
+
: viewport.left + listEl.scrollWidth;
|
|
477
497
|
minOffset = viewportEndBound - maxItemsEndBound;
|
|
478
498
|
}
|
|
479
499
|
return minOffset;
|
|
@@ -483,11 +503,12 @@ class Carousel extends react_1.Component {
|
|
|
483
503
|
* @return Длина/ширина списка элементов.
|
|
484
504
|
*/
|
|
485
505
|
getRealItemsSize() {
|
|
506
|
+
const listEl = this.listElement;
|
|
486
507
|
let result = 0;
|
|
487
|
-
if (
|
|
508
|
+
if (listEl) {
|
|
488
509
|
const { items, vertical } = this.props;
|
|
489
|
-
const firstChild =
|
|
490
|
-
const lastChild =
|
|
510
|
+
const firstChild = listEl.children[0];
|
|
511
|
+
const lastChild = listEl.children[(0, lodash_1.size)(items) - 1];
|
|
491
512
|
if (firstChild && lastChild) {
|
|
492
513
|
const startBound = (0, bounds_of_1.default)(firstChild)[vertical ? 'top' : 'left'];
|
|
493
514
|
const endBound = (0, bounds_of_1.default)(lastChild)[vertical ? 'bottom' : 'right'];
|
|
@@ -502,7 +523,8 @@ class Carousel extends react_1.Component {
|
|
|
502
523
|
*/
|
|
503
524
|
getViewportSize() {
|
|
504
525
|
const { vertical } = this.props;
|
|
505
|
-
|
|
526
|
+
const viewport = this.getViewport();
|
|
527
|
+
return viewport ? viewport[vertical ? 'height' : 'width'] : 0;
|
|
506
528
|
}
|
|
507
529
|
/**
|
|
508
530
|
* Возвращает данные прямоугольной области видимости карусели.
|
|
@@ -540,10 +562,7 @@ class Carousel extends react_1.Component {
|
|
|
540
562
|
this.setDragOffset = setOffset;
|
|
541
563
|
this.isGrabbed = isGrabbed;
|
|
542
564
|
}
|
|
543
|
-
/**
|
|
544
|
-
* Рендер.
|
|
545
|
-
* @inheritDoc
|
|
546
|
-
*/
|
|
565
|
+
/** @inheritdoc */
|
|
547
566
|
render() {
|
|
548
567
|
const { currentOffset, isAllItemsVisible } = this.state;
|
|
549
568
|
const { autoplay, autoplayHoverPause, vertical, containerProps = {}, viewportElementProps = {}, withControls = 'auto', renderControl = Carousel.defaultRenderControl, controlProps, } = this.props;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @return Родственный элемент.
|
|
11
11
|
*/
|
|
12
12
|
declare const findChildElement: ({ target, startIndex, increment, defaultResult, isSuitable, needBreakLoop, }: {
|
|
13
|
-
target
|
|
13
|
+
target?: HTMLElement | null | undefined;
|
|
14
14
|
startIndex?: number | undefined;
|
|
15
15
|
increment?: number | undefined;
|
|
16
16
|
defaultResult?: number | undefined;
|
package/hooks/index.js
CHANGED
|
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.useIsomorphicLayoutEffect = exports.useOutsideClick = exports.useInfiniteScroll = exports.useIsTouchDevice = void 0;
|
|
7
7
|
const react_1 = require("react");
|
|
8
8
|
const is_touch_device_1 = require("../helpers/is-touch-device");
|
|
9
|
-
const lodash_1 = require("lodash");
|
|
10
9
|
const on_1 = __importDefault(require("../helpers/on"));
|
|
11
10
|
const identity_1 = require("./identity");
|
|
12
11
|
/**
|
|
@@ -51,16 +50,14 @@ exports.useInfiniteScroll = useInfiniteScroll;
|
|
|
51
50
|
* @param callback Сработает при клике вне элемента.
|
|
52
51
|
*/
|
|
53
52
|
const useOutsideClick = (elementRef, callback) => {
|
|
54
|
-
const callbackRef = (0,
|
|
55
|
-
|
|
56
|
-
(0, react_1.useEffect)(() => (0, on_1.default)(document.documentElement, 'click', (event) => {
|
|
53
|
+
const callbackRef = (0, identity_1.useIdentityRef)(callback);
|
|
54
|
+
(0, react_1.useEffect)(() => (0, on_1.default)(document.documentElement, 'click', event => {
|
|
57
55
|
const { current: element } = elementRef;
|
|
58
56
|
const { current: handleClick } = callbackRef;
|
|
59
57
|
element &&
|
|
60
58
|
element !== event.target &&
|
|
61
59
|
!element.contains(event.target) &&
|
|
62
|
-
(0
|
|
63
|
-
handleClick(event);
|
|
60
|
+
(handleClick === null || handleClick === void 0 ? void 0 : handleClick(event));
|
|
64
61
|
}), []);
|
|
65
62
|
};
|
|
66
63
|
exports.useOutsideClick = useOutsideClick;
|
package/modal/index.d.ts
CHANGED
|
@@ -13,8 +13,6 @@ export interface ModalProps extends WithBodyScrollLock {
|
|
|
13
13
|
onClose?: () => void;
|
|
14
14
|
/** Размер окна. */
|
|
15
15
|
size?: ModalSize;
|
|
16
|
-
/** Нужно ли выводить элемент в портале (для SSR следует указывать false). */
|
|
17
|
-
inPortal?: boolean;
|
|
18
16
|
/** Идентификатор для систем автоматизированного тестирования. */
|
|
19
17
|
'data-testid'?: string;
|
|
20
18
|
}
|
package/modal/index.js
CHANGED
|
@@ -18,17 +18,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
18
18
|
__setModuleDefault(result, mod);
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
22
|
-
var t = {};
|
|
23
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
24
|
-
t[p] = s[p];
|
|
25
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
26
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
27
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
28
|
-
t[p[i]] = s[p[i]];
|
|
29
|
-
}
|
|
30
|
-
return t;
|
|
31
|
-
};
|
|
32
21
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
33
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
23
|
};
|
|
@@ -39,7 +28,6 @@ const top_bar_1 = require("../top-bar");
|
|
|
39
28
|
const bottom_bar_1 = require("../bottom-bar");
|
|
40
29
|
const utils_1 = require("./utils");
|
|
41
30
|
const shadows_1 = require("../styling/shadows");
|
|
42
|
-
const portal_1 = require("../portal");
|
|
43
31
|
const lodash_1 = require("lodash");
|
|
44
32
|
const slots_1 = require("./slots");
|
|
45
33
|
const layer_1 = require("../helpers/layer");
|
|
@@ -53,19 +41,7 @@ const cx = bind_1.default.bind(modal_module_scss_1.default);
|
|
|
53
41
|
* @param props Свойства.
|
|
54
42
|
* @return Элемент.
|
|
55
43
|
*/
|
|
56
|
-
const Modal = (
|
|
57
|
-
var { inPortal } = _a, restProps = __rest(_a, ["inPortal"]);
|
|
58
|
-
const Wrapper = inPortal ? portal_1.Portal : react_1.Fragment;
|
|
59
|
-
return (react_1.default.createElement(Wrapper, null,
|
|
60
|
-
react_1.default.createElement(ModalInner, Object.assign({}, restProps))));
|
|
61
|
-
};
|
|
62
|
-
exports.Modal = Modal;
|
|
63
|
-
/**
|
|
64
|
-
* Внутренний компонент для того чтобы не прокидывать реф через портал.
|
|
65
|
-
* @param props Свойства.
|
|
66
|
-
* @return Элемент.
|
|
67
|
-
*/
|
|
68
|
-
const ModalInner = ({ children, height, onClose, scrollDisableOptions = { reserveScrollBarGap: true }, size = 'm', withScrollDisable = false, 'data-testid': testId = 'modal', }) => {
|
|
44
|
+
const Modal = ({ children, height, onClose, scrollDisableOptions = { reserveScrollBarGap: true }, size = 'm', withScrollDisable = false, 'data-testid': testId = 'modal', }) => {
|
|
69
45
|
const layer = (0, layer_1.useLayer)() + 100;
|
|
70
46
|
const rootRef = (0, react_1.useRef)(null);
|
|
71
47
|
const bind = (0, utils_1.useCloseHandler)(onClose);
|
|
@@ -102,6 +78,7 @@ const ModalInner = ({ children, height, onClose, scrollDisableOptions = { reserv
|
|
|
102
78
|
!footer && !fullscreen && react_1.default.createElement("div", { className: cx('footer-stub') }),
|
|
103
79
|
!fullscreen && overlap && react_1.default.createElement("div", { className: cx('overlap') }, overlap))));
|
|
104
80
|
};
|
|
81
|
+
exports.Modal = Modal;
|
|
105
82
|
exports.Modal.Header = slots_1.ModalHeader;
|
|
106
83
|
exports.Modal.Body = slots_1.ModalBody;
|
|
107
84
|
exports.Modal.Footer = slots_1.ModalFooter;
|
package/modal/utils.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
/**
|
|
2
3
|
* Вызывает callback только если клик был начат и закончен по одному и тому же элементу.
|
|
3
4
|
* @param callback Сработает при клике.
|
|
4
5
|
* @return Свойства для целевого элемента.
|
|
5
6
|
*/
|
|
6
7
|
export declare const useCloseHandler: (callback?: (() => void) | undefined) => {
|
|
7
|
-
onMouseUp: ({ target, currentTarget, button }:
|
|
8
|
-
onMouseDown: ({ button, target }:
|
|
8
|
+
onMouseUp: ({ target, currentTarget, button }: React.MouseEvent) => void;
|
|
9
|
+
onMouseDown: ({ button, target }: React.MouseEvent) => void;
|
|
9
10
|
};
|
package/modal/utils.js
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.useCloseHandler = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
|
+
const identity_1 = require("../hooks/identity");
|
|
5
6
|
/**
|
|
6
7
|
* Вызывает callback только если клик был начат и закончен по одному и тому же элементу.
|
|
7
8
|
* @param callback Сработает при клике.
|
|
8
9
|
* @return Свойства для целевого элемента.
|
|
9
10
|
*/
|
|
10
11
|
const useCloseHandler = (callback) => {
|
|
12
|
+
const callbackRef = (0, identity_1.useIdentityRef)(callback);
|
|
11
13
|
const mouseDownTarget = (0, react_1.useRef)();
|
|
12
14
|
const onMouseDown = (0, react_1.useCallback)(({ button, target }) => {
|
|
13
15
|
if (button === 0) {
|
|
@@ -15,12 +17,13 @@ const useCloseHandler = (callback) => {
|
|
|
15
17
|
}
|
|
16
18
|
}, []);
|
|
17
19
|
const onMouseUp = (0, react_1.useCallback)(({ target, currentTarget, button }) => {
|
|
18
|
-
|
|
20
|
+
const fn = callbackRef.current;
|
|
21
|
+
fn &&
|
|
19
22
|
button === 0 &&
|
|
20
23
|
target === currentTarget &&
|
|
21
24
|
currentTarget === mouseDownTarget.current &&
|
|
22
|
-
|
|
23
|
-
}, [
|
|
25
|
+
fn();
|
|
26
|
+
}, []);
|
|
24
27
|
return { onMouseUp, onMouseDown };
|
|
25
28
|
};
|
|
26
29
|
exports.useCloseHandler = useCloseHandler;
|
package/package.json
CHANGED
package/phone-input/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Country } from './presets';
|
|
|
5
5
|
interface PhoneInputStyle extends React.CSSProperties {
|
|
6
6
|
'--phone-input-width'?: number | string;
|
|
7
7
|
}
|
|
8
|
-
export interface PhoneInputProps extends Omit<TextFieldProps, 'onChange' | 'onBlur' | 'value' | 'ref' | 'style'> {
|
|
8
|
+
export interface PhoneInputProps extends Omit<TextFieldProps, 'onChange' | 'onBlur' | 'value' | 'ref' | 'style' | 'multiline'> {
|
|
9
9
|
/** Сработает при "blur". */
|
|
10
10
|
onBlur?: (e: React.FocusEvent<HTMLInputElement>, s: MaskState & {
|
|
11
11
|
ready?: boolean;
|
package/phone-input/index.js
CHANGED
|
@@ -35,7 +35,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.PhoneInput = void 0;
|
|
37
37
|
const react_1 = __importStar(require("react"));
|
|
38
|
-
const bind_1 = __importDefault(require("classnames/bind"));
|
|
39
38
|
const down_1 = __importDefault(require("@sima-land/ui-quarks/icons/16x16/Stroked/Arrows/down"));
|
|
40
39
|
const up_1 = __importDefault(require("@sima-land/ui-quarks/icons/16x16/Stroked/Arrows/up"));
|
|
41
40
|
const dropdown_1 = require("../dropdown");
|
|
@@ -44,10 +43,9 @@ const text_field_1 = require("../text-field");
|
|
|
44
43
|
const masked_field_1 = require("../masked-field");
|
|
45
44
|
const hooks_1 = require("../hooks");
|
|
46
45
|
const presets_1 = require("./presets");
|
|
47
|
-
const sizes_1 = require("../styling/sizes");
|
|
48
|
-
const colors_1 = require("../colors");
|
|
49
|
-
const phone_input_module_scss_1 = __importDefault(require("./phone-input.module.scss"));
|
|
50
46
|
const utils_1 = require("./utils");
|
|
47
|
+
const bind_1 = __importDefault(require("classnames/bind"));
|
|
48
|
+
const phone_input_module_scss_1 = __importDefault(require("./phone-input.module.scss"));
|
|
51
49
|
const cx = bind_1.default.bind(phone_input_module_scss_1.default);
|
|
52
50
|
/**
|
|
53
51
|
* Удаляет из значения код переданной страны.
|
|
@@ -66,23 +64,32 @@ const PhoneInput = (_a) => {
|
|
|
66
64
|
// маску определяем автоматически только при старте
|
|
67
65
|
const [country, setCountry] = (0, react_1.useState)((0, utils_1.defineCountry)(value));
|
|
68
66
|
const [cleanValue, setCleanValue] = (0, react_1.useState)(formatValue(value, country));
|
|
69
|
-
const [
|
|
70
|
-
const
|
|
67
|
+
const [withMenu, toggleMenu] = (0, react_1.useState)(false);
|
|
68
|
+
const rootRef = (0, react_1.useRef)(null);
|
|
69
|
+
const openerRef = (0, react_1.useRef)(null);
|
|
71
70
|
(0, react_1.useEffect)(() => {
|
|
72
71
|
setCleanValue(formatValue(value, country));
|
|
73
72
|
}, [value]);
|
|
74
|
-
(0, hooks_1.useOutsideClick)(
|
|
75
|
-
|
|
76
|
-
togglePopup(false);
|
|
73
|
+
(0, hooks_1.useOutsideClick)(rootRef, () => {
|
|
74
|
+
toggleMenu(false);
|
|
77
75
|
});
|
|
78
|
-
const AdornmentSVG =
|
|
79
|
-
const commonFieldProps = Object.assign(Object.assign({}, restProps), { label, multiline: false, className: cx('field'), endAdornment: (react_1.default.createElement("div", { className: cx('adornment'), "data-testid": 'phone-input:dropdown-opener', onClick:
|
|
80
|
-
|
|
81
|
-
togglePopup(true);
|
|
76
|
+
const AdornmentSVG = withMenu ? up_1.default : down_1.default;
|
|
77
|
+
const commonFieldProps = Object.assign(Object.assign({}, restProps), { label, multiline: false, className: cx('field'), endAdornment: (react_1.default.createElement("div", { ref: openerRef, className: cx('adornment'), "data-testid": 'phone-input:dropdown-opener', onClick: () => {
|
|
78
|
+
toggleMenu(true);
|
|
82
79
|
} },
|
|
83
80
|
react_1.default.createElement("img", { alt: '', width: 24, height: 24, src: country.imageSrc }),
|
|
84
|
-
react_1.default.createElement(AdornmentSVG, {
|
|
85
|
-
|
|
81
|
+
react_1.default.createElement(AdornmentSVG, { className: cx('arrow') }))), onClick: event => {
|
|
82
|
+
const opener = openerRef.current;
|
|
83
|
+
if (opener instanceof Node &&
|
|
84
|
+
event.target instanceof Node &&
|
|
85
|
+
(opener === event.target || opener.contains(event.target))) {
|
|
86
|
+
event.preventDefault(); // чтобы не фокусировалось на поле
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
toggleMenu(false);
|
|
90
|
+
}
|
|
91
|
+
} });
|
|
92
|
+
return (react_1.default.createElement("div", { ref: rootRef, "data-testid": testId, style: style, className: cx('root', className) },
|
|
86
93
|
country.id === presets_1.IDS.other ? (react_1.default.createElement(text_field_1.TextField, Object.assign({}, commonFieldProps, { onChange: (e) => {
|
|
87
94
|
e.target.value = e.target.value.replace(/\D/g, '').slice(0, 20);
|
|
88
95
|
onChange && onChange(e);
|
|
@@ -101,8 +108,8 @@ const PhoneInput = (_a) => {
|
|
|
101
108
|
// вставляем код страны обратно в чистое значение
|
|
102
109
|
cleanValue: `${country.codeChars}${state.cleanValue}` }));
|
|
103
110
|
} }))),
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
withMenu && (react_1.default.createElement(dropdown_1.Dropdown, { role: 'menu', className: cx('menu'), "data-testid": 'phone-input:dropdown' }, presets_1.countriesList.map((item, index) => item.id === country.id ? null : (react_1.default.createElement(dropdown_item_1.DropdownItem, { key: index, size: 'l', role: 'menuitem', className: cx('menu-item'), onClick: () => {
|
|
112
|
+
toggleMenu(false);
|
|
106
113
|
setCountry(item);
|
|
107
114
|
onCountrySelect && onCountrySelect(item);
|
|
108
115
|
} },
|
|
@@ -17,7 +17,14 @@
|
|
|
17
17
|
cursor: pointer;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
.
|
|
20
|
+
.arrow {
|
|
21
|
+
display: block;
|
|
22
|
+
fill: colors.$gray38;
|
|
23
|
+
margin-left: 4px;
|
|
24
|
+
pointer-events: none; // игнорируем клики т.к. после них элемент стрелки подменяется и считается что он сработал вне элемента родителя
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.menu {
|
|
21
28
|
position: absolute;
|
|
22
29
|
width: 100%;
|
|
23
30
|
top: 56px;
|
|
@@ -25,7 +32,7 @@
|
|
|
25
32
|
z-index: 2;
|
|
26
33
|
}
|
|
27
34
|
|
|
28
|
-
.
|
|
35
|
+
.menu-item {
|
|
29
36
|
font-size: 16px;
|
|
30
37
|
line-height: 24px;
|
|
31
38
|
.item-name {
|
package/select/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { TextFieldProps } from '../text-field';
|
|
3
3
|
declare type Size = 's' | 'm' | 'l' | 'xl';
|
|
4
|
-
export interface SelectProps extends Omit<TextFieldProps, 'style'> {
|
|
4
|
+
export interface SelectProps extends Omit<TextFieldProps, 'style' | 'endAdornment'> {
|
|
5
5
|
/** Нужно ли выводить состояние загрузки списка. */
|
|
6
6
|
loading?: boolean;
|
|
7
7
|
/** Сработает при открытии/закрытии меню. */
|
|
@@ -16,11 +16,18 @@ export interface SelectProps extends Omit<TextFieldProps, 'style'> {
|
|
|
16
16
|
renderOption?: (option: any) => React.ReactNode;
|
|
17
17
|
/** Стили. */
|
|
18
18
|
style?: React.CSSProperties;
|
|
19
|
+
endAdornment?: TextFieldProps['endAdornment'] | ((opened: boolean) => React.ReactNode);
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Выводит иконку стрелки для поля Select по умолчанию.
|
|
23
|
+
* @param opened Открыт ли список опций.
|
|
24
|
+
* @return Элемент.
|
|
25
|
+
*/
|
|
26
|
+
export declare const renderDefaultArrow: (opened: boolean) => JSX.Element;
|
|
20
27
|
/**
|
|
21
28
|
* Поле выбора из списка.
|
|
22
29
|
* @param props Свойства.
|
|
23
30
|
* @return Элемент.
|
|
24
31
|
*/
|
|
25
|
-
export declare const Select: ({ options, optionSize, onSelect, style, className, label, onClick, value, loading, onMenuToggle, renderOption, "data-testid": dataTestId, ...restProps }: SelectProps) => JSX.Element;
|
|
32
|
+
export declare const Select: ({ options, optionSize, onSelect, style, className, label, onClick, value, loading, onMenuToggle, renderOption, "data-testid": dataTestId, size, endAdornment, ...restProps }: SelectProps) => JSX.Element;
|
|
26
33
|
export {};
|
package/select/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
33
33
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
34
|
};
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.Select = void 0;
|
|
36
|
+
exports.Select = exports.renderDefaultArrow = void 0;
|
|
37
37
|
const react_1 = __importStar(require("react"));
|
|
38
38
|
const dropdown_1 = require("../dropdown");
|
|
39
39
|
const dropdown_item_1 = require("../dropdown-item");
|
|
@@ -47,25 +47,34 @@ const colors_1 = require("../colors");
|
|
|
47
47
|
const dropdown_loading_1 = require("../_internal/dropdown-loading");
|
|
48
48
|
const hooks_1 = require("../hooks");
|
|
49
49
|
const cx = bind_1.default.bind(select_module_scss_1.default);
|
|
50
|
+
/**
|
|
51
|
+
* Выводит иконку стрелки для поля Select по умолчанию.
|
|
52
|
+
* @param opened Открыт ли список опций.
|
|
53
|
+
* @return Элемент.
|
|
54
|
+
*/
|
|
55
|
+
const renderDefaultArrow = (opened) => {
|
|
56
|
+
const ArrowSVG = opened ? up_1.default : down_1.default;
|
|
57
|
+
return react_1.default.createElement(ArrowSVG, { fill: colors_1.COLORS.get('gray38') });
|
|
58
|
+
};
|
|
59
|
+
exports.renderDefaultArrow = renderDefaultArrow;
|
|
50
60
|
/**
|
|
51
61
|
* Поле выбора из списка.
|
|
52
62
|
* @param props Свойства.
|
|
53
63
|
* @return Элемент.
|
|
54
64
|
*/
|
|
55
65
|
const Select = (_a) => {
|
|
56
|
-
var { options, optionSize, onSelect, style, className, label, onClick, value, loading, onMenuToggle, renderOption = String, 'data-testid': dataTestId } = _a, restProps = __rest(_a, ["options", "optionSize", "onSelect", "style", "className", "label", "onClick", "value", "loading", "onMenuToggle", "renderOption", 'data-testid']);
|
|
66
|
+
var { options, optionSize, onSelect, style, className, label, onClick, value, loading, onMenuToggle, renderOption = String, 'data-testid': dataTestId, size, endAdornment = exports.renderDefaultArrow } = _a, restProps = __rest(_a, ["options", "optionSize", "onSelect", "style", "className", "label", "onClick", "value", "loading", "onMenuToggle", "renderOption", 'data-testid', "size", "endAdornment"]);
|
|
57
67
|
const rootRef = (0, react_1.useRef)(null);
|
|
58
68
|
const fieldRef = (0, react_1.useRef)(null);
|
|
59
69
|
const menuRef = (0, react_1.useRef)(null);
|
|
60
70
|
const [opened, toggleMenu] = (0, react_1.useState)(false);
|
|
61
|
-
const ArrowSVG = opened ? up_1.default : down_1.default;
|
|
62
71
|
(0, react_1.useEffect)(() => {
|
|
63
72
|
opened && menuRef.current && menuRef.current.focus();
|
|
64
73
|
onMenuToggle && onMenuToggle(opened);
|
|
65
74
|
}, [opened]);
|
|
66
75
|
(0, hooks_1.useOutsideClick)(rootRef, toggleMenu.bind(null, false));
|
|
67
76
|
return (react_1.default.createElement("div", { ref: rootRef, style: style, className: cx('root', className), "data-testid": dataTestId },
|
|
68
|
-
react_1.default.createElement(text_field_1.TextField, { blockProps: {
|
|
77
|
+
react_1.default.createElement(text_field_1.TextField, Object.assign({}, restProps, { size: size, blockProps: {
|
|
69
78
|
ref: fieldRef,
|
|
70
79
|
tabIndex: 0,
|
|
71
80
|
onMouseDown: () => {
|
|
@@ -74,16 +83,15 @@ const Select = (_a) => {
|
|
|
74
83
|
onKeyDown: e => {
|
|
75
84
|
e.key === 'Enter' && toggleMenu(true);
|
|
76
85
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
},
|
|
86
|
+
}, onClick: e => {
|
|
87
|
+
e.preventDefault();
|
|
88
|
+
onClick && onClick(e);
|
|
81
89
|
}, className: select_module_scss_1.default.field, "data-testid": 'select:field', label: label, focused: opened, baseInputProps: {
|
|
82
90
|
// чтобы не ловить фокус на поле
|
|
83
91
|
style: { pointerEvents: 'none' },
|
|
84
92
|
tabIndex: -1,
|
|
85
|
-
}, value: value, multiline: false, variant: 'desktop', readOnly: true, endAdornment:
|
|
86
|
-
opened && (loading || options.length > 0) && (react_1.default.createElement(dropdown_1.Dropdown, Object.assign({}, (0, dropdown_2.placeDropdown)(
|
|
93
|
+
}, value: value, multiline: false, variant: 'desktop', readOnly: true, endAdornment: typeof endAdornment === 'function' ? endAdornment(opened) : endAdornment })),
|
|
94
|
+
opened && (loading || options.length > 0) && (react_1.default.createElement(dropdown_1.Dropdown, Object.assign({}, (0, dropdown_2.placeDropdown)(size), { ref: menuRef, "data-testid": 'select:menu', role: 'menu', tabIndex: -1, className: cx('menu'), onKeyDown: event => {
|
|
87
95
|
if (event.key === 'Enter') {
|
|
88
96
|
toggleMenu(false);
|
|
89
97
|
fieldRef.current && fieldRef.current.focus();
|
package/text-field/index.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ export interface TextFieldProps extends Omit<React.InputHTMLAttributes<HTMLInput
|
|
|
47
47
|
/** Вариант отображения. */
|
|
48
48
|
variant?: Variant;
|
|
49
49
|
/** Свойства элемента-блока. */
|
|
50
|
-
blockProps?: React.HTMLProps<HTMLDivElement>;
|
|
50
|
+
blockProps?: Omit<React.HTMLProps<HTMLDivElement>, 'onClick'>;
|
|
51
51
|
/** Идентификатор для систем автоматизированного тестирования. */
|
|
52
52
|
'data-testid'?: string;
|
|
53
53
|
}
|
package/text-field/index.js
CHANGED
|
@@ -51,7 +51,7 @@ const modifiersToClasses = ({ disabled, failed, focused, variant, }) => cx(disab
|
|
|
51
51
|
* @param props Свойства.
|
|
52
52
|
* @return Элемент.
|
|
53
53
|
*/
|
|
54
|
-
exports.TextField = (0, react_1.forwardRef)(function TextField({ autoFocus, caption, classes = {}, defaultValue, disabled, endAdornment, failed, focused: asFocused, label, onClick, onBlur, onChange, onFocus, onInput, onKeyDown, onKeyUp, placeholder, readOnly, rounds = 'all', size = exports.DEFAULTS.size, startAdornment, value, variant = 'desktop', multiline, baseInputProps = {}, className, restPlaceholder, style, blockProps, 'data-testid': dataTestId, }, ref) {
|
|
54
|
+
exports.TextField = (0, react_1.forwardRef)(function TextField({ autoFocus, caption, classes = {}, defaultValue, disabled, endAdornment, failed, focused: asFocused, label, onClick, onBlur, onChange, onFocus, onInput, onKeyDown, onKeyUp, placeholder, readOnly, rounds = 'all', size = exports.DEFAULTS.size, startAdornment, value, variant = 'desktop', multiline, baseInputProps = {}, className, restPlaceholder, style, blockProps, 'data-testid': dataTestId, type, name, autoComplete, id, }, ref) {
|
|
55
55
|
const [hasValue, toggleHasValue] = (0, react_1.useState)(isVisible(value) || isVisible(defaultValue));
|
|
56
56
|
const [reallyFocused, toggleFocused] = (0, react_1.useState)(autoFocus);
|
|
57
57
|
const focused = reallyFocused || Boolean(asFocused);
|
|
@@ -68,9 +68,9 @@ exports.TextField = (0, react_1.forwardRef)(function TextField({ autoFocus, capt
|
|
|
68
68
|
variant,
|
|
69
69
|
});
|
|
70
70
|
(0, react_1.useImperativeHandle)(ref, () => baseInputRef.current);
|
|
71
|
-
(0, react_1.useEffect)(() => toggleHasValue(Boolean(baseInputRef.current.value)));
|
|
71
|
+
(0, react_1.useEffect)(() => { var _a; return toggleHasValue(Boolean((_a = baseInputRef.current) === null || _a === void 0 ? void 0 : _a.value)); });
|
|
72
72
|
return (react_1.default.createElement("div", { "data-testid": dataTestId, className: cx('root', className, classes.root), style: style },
|
|
73
|
-
react_1.default.createElement("div", Object.assign({ "data-testid": 'text-field:block', className: cx('reset', 'input-block', commonModifyClasses, size && `size-${size}`, focused && classes.blockFocused, multiline && 'multiline', withLabel && 'with-label', variant === 'desktop' && rounds !== 'none' && shapes_1.SmallRounds[rounds], blockProps === null || blockProps === void 0 ? void 0 : blockProps.className), onClick: event => {
|
|
73
|
+
react_1.default.createElement("div", Object.assign({}, blockProps, { "data-testid": 'text-field:block', className: cx('reset', 'input-block', commonModifyClasses, size && `size-${size}`, focused && classes.blockFocused, multiline && 'multiline', withLabel && 'with-label', variant === 'desktop' && rounds !== 'none' && shapes_1.SmallRounds[rounds], blockProps === null || blockProps === void 0 ? void 0 : blockProps.className), onClick: event => {
|
|
74
74
|
const input = baseInputRef.current;
|
|
75
75
|
onClick === null || onClick === void 0 ? void 0 : onClick(event);
|
|
76
76
|
input &&
|
|
@@ -78,12 +78,12 @@ exports.TextField = (0, react_1.forwardRef)(function TextField({ autoFocus, capt
|
|
|
78
78
|
!event.defaultPrevented &&
|
|
79
79
|
input !== document.activeElement &&
|
|
80
80
|
input.focus();
|
|
81
|
-
} }
|
|
81
|
+
} }),
|
|
82
82
|
!multiline && Boolean(startAdornment) && (react_1.default.createElement(box_1.Box, { display: 'flex', alignItems: 'center', marginRight: 4 }, startAdornment)),
|
|
83
83
|
react_1.default.createElement("div", { className: cx('main-column') },
|
|
84
|
-
withLabel && (react_1.default.createElement("label", { className: cx('label', commonModifyClasses, hasValue && 'filled', labelAsPlaceholder && 'as-placeholder'), children: label, "data-testid": 'text-field:label' })),
|
|
84
|
+
withLabel && (react_1.default.createElement("label", { className: cx('label', commonModifyClasses, hasValue && 'filled', labelAsPlaceholder && 'as-placeholder'), htmlFor: id, children: label, "data-testid": 'text-field:label' })),
|
|
85
85
|
react_1.default.createElement("div", { className: cx('input-wrapper') },
|
|
86
|
-
react_1.default.createElement(base_input_1.BaseInput, Object.assign({}, baseInputProps, { "data-testid": 'text-field:field', multiline: multiline, ref: baseInputRef, placeholder: withLabel && labelAsPlaceholder ? undefined : placeholder, restPlaceholder: withLabel && labelAsPlaceholder ? undefined : restPlaceholder, autoFocus: autoFocus, className: cx('base-input', commonModifyClasses, classes.baseInput, size && `size-${size}`), defaultValue: defaultValue, value: value, readOnly: readOnly, disabled: disabled, onFocus: (event) => {
|
|
86
|
+
react_1.default.createElement(base_input_1.BaseInput, Object.assign({}, baseInputProps, { type: type, id: id, name: name, autoComplete: autoComplete, "data-testid": 'text-field:field', multiline: multiline, ref: baseInputRef, placeholder: withLabel && labelAsPlaceholder ? undefined : placeholder, restPlaceholder: withLabel && labelAsPlaceholder ? undefined : restPlaceholder, autoFocus: autoFocus, className: cx('base-input', commonModifyClasses, classes.baseInput, size && `size-${size}`), defaultValue: defaultValue, value: value, readOnly: readOnly, disabled: disabled, onFocus: (event) => {
|
|
87
87
|
onFocus && onFocus(event);
|
|
88
88
|
toggleHasValue(Boolean(event.target.value));
|
|
89
89
|
toggleFocused(true);
|
|
@@ -91,7 +91,13 @@ exports.TextField = (0, react_1.forwardRef)(function TextField({ autoFocus, capt
|
|
|
91
91
|
onBlur && onBlur(event);
|
|
92
92
|
toggleHasValue(Boolean(event.target.value));
|
|
93
93
|
toggleFocused(false);
|
|
94
|
-
}, onInput:
|
|
94
|
+
}, onInput: (event) => {
|
|
95
|
+
onInput === null || onInput === void 0 ? void 0 : onInput(event);
|
|
96
|
+
toggleHasValue(Boolean(event.target.value));
|
|
97
|
+
}, onChange: (event) => {
|
|
98
|
+
onChange === null || onChange === void 0 ? void 0 : onChange(event);
|
|
99
|
+
toggleHasValue(Boolean(event.target.value));
|
|
100
|
+
}, onKeyDown: onKeyDown, onKeyUp: onKeyUp })))),
|
|
95
101
|
!multiline && Boolean(endAdornment) && (react_1.default.createElement(box_1.Box, { display: 'flex', alignItems: 'center', marginLeft: 4 }, endAdornment))),
|
|
96
102
|
Boolean(caption) && (react_1.default.createElement("div", { className: cx('caption', (0, sizes_1.marginTop)(isMobile ? 1 : 2), failed && 'failed'), children: caption }))));
|
|
97
103
|
});
|