@doyourjob/gravity-ui-page-constructor 5.31.254 → 5.31.257
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/build/cjs/blocks/LogoRotator/Item.d.ts +8 -3
- package/build/cjs/blocks/LogoRotator/Item.js +14 -9
- package/build/cjs/blocks/LogoRotator/LogoRotator.css +83 -9
- package/build/cjs/blocks/LogoRotator/LogoRotator.js +98 -60
- package/build/cjs/blocks/LogoRotator/schema.d.ts +6 -2
- package/build/cjs/blocks/LogoRotator/schema.js +6 -3
- package/build/cjs/blocks/LogoRotator/utils.d.ts +7 -0
- package/build/cjs/blocks/LogoRotator/utils.js +36 -0
- package/build/cjs/models/constructor-items/blocks.d.ts +3 -2
- package/build/esm/blocks/LogoRotator/Item.d.ts +8 -3
- package/build/esm/blocks/LogoRotator/Item.js +14 -9
- package/build/esm/blocks/LogoRotator/LogoRotator.css +83 -9
- package/build/esm/blocks/LogoRotator/LogoRotator.js +98 -60
- package/build/esm/blocks/LogoRotator/schema.d.ts +6 -2
- package/build/esm/blocks/LogoRotator/schema.js +6 -3
- package/build/esm/blocks/LogoRotator/utils.d.ts +7 -0
- package/build/esm/blocks/LogoRotator/utils.js +31 -0
- package/build/esm/models/constructor-items/blocks.d.ts +3 -2
- package/package.json +1 -1
- package/schema/index.js +1 -1
- package/server/models/constructor-items/blocks.d.ts +3 -2
- package/widget/index.js +1 -1
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { LogoRotatorBlockProps } from '../../models';
|
|
3
|
+
import type { LogoRotatorSwapAnimation } from './utils';
|
|
3
4
|
type Props = {
|
|
4
5
|
src: string;
|
|
5
6
|
url?: string;
|
|
6
|
-
|
|
7
|
+
previousSrc?: string;
|
|
8
|
+
previousUrl?: string;
|
|
9
|
+
swapAnimation: LogoRotatorSwapAnimation;
|
|
7
10
|
colSizes: LogoRotatorBlockProps['colSizes'];
|
|
11
|
+
onMouseEnter?: () => void;
|
|
12
|
+
onMouseLeave?: () => void;
|
|
8
13
|
};
|
|
9
|
-
export declare const Item: ({ url, src,
|
|
10
|
-
declare const _default: React.MemoExoticComponent<({ url, src,
|
|
14
|
+
export declare const Item: ({ url, src, previousSrc, previousUrl, swapAnimation, colSizes, onMouseEnter, onMouseLeave, }: Props) => JSX.Element;
|
|
15
|
+
declare const _default: React.MemoExoticComponent<({ url, src, previousSrc, previousUrl, swapAnimation, colSizes, onMouseEnter, onMouseLeave, }: Props) => JSX.Element>;
|
|
11
16
|
export default _default;
|
|
@@ -7,18 +7,23 @@ const uikit_1 = require("@gravity-ui/uikit");
|
|
|
7
7
|
const components_1 = require("../../components");
|
|
8
8
|
const grid_1 = require("../../grid");
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
|
+
const utils_2 = require("./utils");
|
|
10
11
|
const b = (0, utils_1.block)('logo-rotator-block');
|
|
11
12
|
const defaultColSizes = { all: 3 };
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const getLayerClassName = (layer, swapAnimation, link = false) => `${link ? `${b('item-link')} ` : ''}${b('logo-layer', (0, utils_2.getLayerModifiers)(layer, swapAnimation))}`;
|
|
14
|
+
const Item = ({ url, src, previousSrc, previousUrl, swapAnimation, colSizes, onMouseEnter, onMouseLeave, }) => {
|
|
15
|
+
const renderLayer = (layerSrc, layer, layerUrl) => {
|
|
16
|
+
const image = react_1.default.createElement(components_1.Image, { src: layerSrc, className: b('image'), alt: "", "aria-hidden": "true" });
|
|
17
|
+
if (layerUrl) {
|
|
18
|
+
return (react_1.default.createElement(uikit_1.Link, { href: layerUrl, className: getLayerClassName(layer, swapAnimation, true) }, image));
|
|
17
19
|
}
|
|
18
|
-
return
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return react_1.default.createElement(grid_1.Col, { sizes: colSizes || defaultColSizes },
|
|
20
|
+
return react_1.default.createElement("div", { className: getLayerClassName(layer, swapAnimation) }, image);
|
|
21
|
+
};
|
|
22
|
+
const isSwapping = Boolean(previousSrc);
|
|
23
|
+
return (react_1.default.createElement(grid_1.Col, { sizes: colSizes || defaultColSizes },
|
|
24
|
+
react_1.default.createElement("div", { className: b('item', { swapping: isSwapping }), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
25
|
+
previousSrc && renderLayer(previousSrc, 'from', previousUrl),
|
|
26
|
+
renderLayer(src, previousSrc ? 'to' : 'current', url))));
|
|
22
27
|
};
|
|
23
28
|
exports.Item = Item;
|
|
24
29
|
exports.default = react_1.default.memo(exports.Item);
|
|
@@ -16,6 +16,11 @@ unpredictable css rules order in build */
|
|
|
16
16
|
.pc-logo-rotator-block__row {
|
|
17
17
|
justify-content: center;
|
|
18
18
|
}
|
|
19
|
+
@media (max-width: 769px) {
|
|
20
|
+
.pc-logo-rotator-block__row > .col {
|
|
21
|
+
max-width: 50%;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
19
24
|
.pc-logo-rotator-block_theme_dark .pc-logo-rotator-block__title {
|
|
20
25
|
--pc-text-header-color: #ffffff;
|
|
21
26
|
}
|
|
@@ -30,19 +35,44 @@ unpredictable css rules order in build */
|
|
|
30
35
|
gap: 16px;
|
|
31
36
|
}
|
|
32
37
|
.pc-logo-rotator-block__item {
|
|
38
|
+
position: relative;
|
|
33
39
|
display: block;
|
|
34
40
|
height: 100px;
|
|
35
|
-
|
|
36
|
-
opacity: 1;
|
|
37
|
-
}
|
|
38
|
-
.pc-logo-rotator-block__item_hidden {
|
|
39
|
-
opacity: 0;
|
|
41
|
+
overflow: hidden;
|
|
40
42
|
}
|
|
41
43
|
@media (max-width: 769px) {
|
|
42
44
|
.pc-logo-rotator-block__item {
|
|
43
45
|
height: 80px;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
48
|
+
.pc-logo-rotator-block__item-link, .pc-logo-rotator-block__row-item-link {
|
|
49
|
+
display: block;
|
|
50
|
+
height: 100%;
|
|
51
|
+
}
|
|
52
|
+
.pc-logo-rotator-block__logo-layer {
|
|
53
|
+
display: block;
|
|
54
|
+
width: 100%;
|
|
55
|
+
height: 100%;
|
|
56
|
+
}
|
|
57
|
+
.pc-logo-rotator-block__item_swapping .pc-logo-rotator-block__logo-layer, .pc-logo-rotator-block__row-item_swapping .pc-logo-rotator-block__logo-layer {
|
|
58
|
+
position: absolute;
|
|
59
|
+
inset: 0;
|
|
60
|
+
}
|
|
61
|
+
.pc-logo-rotator-block__logo-layer_from {
|
|
62
|
+
pointer-events: none;
|
|
63
|
+
}
|
|
64
|
+
.pc-logo-rotator-block__logo-layer_fade-from {
|
|
65
|
+
animation: logo-rotator-fade-out 0.5s ease 0.1s both;
|
|
66
|
+
}
|
|
67
|
+
.pc-logo-rotator-block__logo-layer_fade-to {
|
|
68
|
+
animation: logo-rotator-fade-in 0.5s ease 0.6s both;
|
|
69
|
+
}
|
|
70
|
+
.pc-logo-rotator-block__logo-layer_morph-from {
|
|
71
|
+
animation: logo-rotator-morph-out 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
72
|
+
}
|
|
73
|
+
.pc-logo-rotator-block__logo-layer_morph-to {
|
|
74
|
+
animation: logo-rotator-morph-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
75
|
+
}
|
|
46
76
|
.pc-logo-rotator-block__image {
|
|
47
77
|
display: block;
|
|
48
78
|
width: 100%;
|
|
@@ -57,13 +87,57 @@ unpredictable css rules order in build */
|
|
|
57
87
|
gap: 46px 16px;
|
|
58
88
|
}
|
|
59
89
|
.pc-logo-rotator-block__row-item {
|
|
90
|
+
position: relative;
|
|
60
91
|
display: block;
|
|
61
92
|
height: 36px;
|
|
62
93
|
min-width: 160px;
|
|
63
94
|
flex: 1;
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
overflow: hidden;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@keyframes logo-rotator-fade-out {
|
|
99
|
+
from {
|
|
100
|
+
opacity: 1;
|
|
101
|
+
}
|
|
102
|
+
to {
|
|
103
|
+
opacity: 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
@keyframes logo-rotator-fade-in {
|
|
107
|
+
from {
|
|
108
|
+
opacity: 0;
|
|
109
|
+
}
|
|
110
|
+
to {
|
|
111
|
+
opacity: 1;
|
|
112
|
+
}
|
|
66
113
|
}
|
|
67
|
-
|
|
68
|
-
|
|
114
|
+
@keyframes logo-rotator-morph-out {
|
|
115
|
+
from {
|
|
116
|
+
clip-path: inset(0 0 0 0);
|
|
117
|
+
transform: translateX(0) scaleX(1);
|
|
118
|
+
opacity: 1;
|
|
119
|
+
}
|
|
120
|
+
to {
|
|
121
|
+
clip-path: inset(0 100% 0 0);
|
|
122
|
+
transform: translateX(-8%) scaleX(0.9);
|
|
123
|
+
opacity: 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
@keyframes logo-rotator-morph-in {
|
|
127
|
+
from {
|
|
128
|
+
clip-path: inset(0 0 0 100%);
|
|
129
|
+
transform: translateX(8%) scaleX(0.9);
|
|
130
|
+
opacity: 0;
|
|
131
|
+
}
|
|
132
|
+
to {
|
|
133
|
+
clip-path: inset(0 0 0 0);
|
|
134
|
+
transform: translateX(0) scaleX(1);
|
|
135
|
+
opacity: 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
@media (prefers-reduced-motion: reduce) {
|
|
139
|
+
.pc-logo-rotator-block__logo-layer_fade-from, .pc-logo-rotator-block__logo-layer_fade-to, .pc-logo-rotator-block__logo-layer_morph-from, .pc-logo-rotator-block__logo-layer_morph-to {
|
|
140
|
+
animation-duration: 1ms;
|
|
141
|
+
animation-delay: 0ms;
|
|
142
|
+
}
|
|
69
143
|
}
|
|
@@ -11,27 +11,11 @@ const grid_1 = require("../../grid");
|
|
|
11
11
|
const useWindowBreakpoint_1 = tslib_1.__importDefault(require("../../hooks/useWindowBreakpoint"));
|
|
12
12
|
const utils_1 = require("../../utils");
|
|
13
13
|
const Item_1 = tslib_1.__importDefault(require("./Item"));
|
|
14
|
+
const utils_2 = require("./utils");
|
|
14
15
|
const b = (0, utils_1.block)('logo-rotator-block');
|
|
15
16
|
const DEFAULT_MIN_ROTATE_COUNT = 2;
|
|
16
17
|
const DEFAULT_MAX_ROTATE_COUNT = 4;
|
|
17
|
-
const
|
|
18
|
-
var _a;
|
|
19
|
-
const staticIdxList = items.map((item, i) => (item.isStatic ? i : -1)).filter((i) => i !== -1);
|
|
20
|
-
const rotatableIdxList = items
|
|
21
|
-
.map((item, i) => (item.isStatic ? -1 : i))
|
|
22
|
-
.filter((i) => i !== -1);
|
|
23
|
-
const initial = [];
|
|
24
|
-
let rotatablePointer = 0;
|
|
25
|
-
for (let slot = 0; slot < count; slot++) {
|
|
26
|
-
if (slot < staticIdxList.length) {
|
|
27
|
-
initial.push(staticIdxList[slot]);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
initial.push((_a = rotatableIdxList[rotatablePointer++]) !== null && _a !== void 0 ? _a : 0);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return initial;
|
|
34
|
-
};
|
|
18
|
+
const emptyTransitions = (count) => Array(count).fill(undefined);
|
|
35
19
|
const pickRandomSlots = (slotIndices, count) => {
|
|
36
20
|
const shuffled = [...slotIndices];
|
|
37
21
|
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
@@ -41,34 +25,47 @@ const pickRandomSlots = (slotIndices, count) => {
|
|
|
41
25
|
return shuffled.slice(0, count);
|
|
42
26
|
};
|
|
43
27
|
const LogoRotatorBlock = (props) => {
|
|
44
|
-
const { animated, title, theme, items,
|
|
28
|
+
const { animated, title, theme, items, countMobile, countDesktop, minRotateCount = DEFAULT_MIN_ROTATE_COUNT, maxRotateCount = DEFAULT_MAX_ROTATE_COUNT, swapAnimation = utils_2.DEFAULT_SWAP_ANIMATION, colSizes, rowMode, } = props;
|
|
45
29
|
const breakpoint = (0, useWindowBreakpoint_1.default)();
|
|
46
|
-
const activeCount =
|
|
30
|
+
const activeCount = countDesktop !== undefined && breakpoint >= constants_1.BREAKPOINTS.md ? countDesktop : countMobile;
|
|
47
31
|
// Индексы логотипов, которые участвуют в ротации (не статичные)
|
|
48
32
|
const rotatableIndices = (0, react_1.useMemo)(() => items.map((item, i) => (item.isStatic ? -1 : i)).filter((i) => i !== -1), [items]);
|
|
49
33
|
// Инициализация слотов: статичные вставляются в начало, остальные по порядку
|
|
50
|
-
const [slots, setSlots] = (0, react_1.useState)(() => getInitialSlots(items, activeCount));
|
|
51
|
-
const [
|
|
34
|
+
const [slots, setSlots] = (0, react_1.useState)(() => (0, utils_2.getInitialSlots)(items, activeCount));
|
|
35
|
+
const [transitions, setTransitions] = (0, react_1.useState)(() => emptyTransitions(activeCount));
|
|
52
36
|
const nextIndexRef = (0, react_1.useRef)(activeCount - 1);
|
|
53
|
-
const
|
|
37
|
+
const hoveredSlotIndicesRef = (0, react_1.useRef)(new Set());
|
|
54
38
|
// Держим актуальные slots в ref, чтобы не пересоздавать интервал при каждом изменении
|
|
55
39
|
const slotsRef = (0, react_1.useRef)(slots);
|
|
56
40
|
(0, react_1.useEffect)(() => {
|
|
57
41
|
slotsRef.current = slots;
|
|
58
42
|
}, [slots]);
|
|
59
43
|
(0, react_1.useEffect)(() => {
|
|
60
|
-
|
|
61
|
-
|
|
44
|
+
const initialSlots = (0, utils_2.getInitialSlots)(items, activeCount);
|
|
45
|
+
slotsRef.current = initialSlots;
|
|
46
|
+
setSlots(initialSlots);
|
|
47
|
+
setTransitions(emptyTransitions(activeCount));
|
|
62
48
|
nextIndexRef.current = activeCount - 1;
|
|
49
|
+
hoveredSlotIndicesRef.current.clear();
|
|
63
50
|
}, [activeCount, items]);
|
|
51
|
+
const handleSlotMouseEnter = (0, react_1.useCallback)((slotIndex) => {
|
|
52
|
+
hoveredSlotIndicesRef.current.add(slotIndex);
|
|
53
|
+
}, []);
|
|
54
|
+
const handleSlotMouseLeave = (0, react_1.useCallback)((slotIndex) => {
|
|
55
|
+
hoveredSlotIndicesRef.current.delete(slotIndex);
|
|
56
|
+
}, []);
|
|
64
57
|
(0, react_1.useEffect)(() => {
|
|
65
58
|
let timeout = null;
|
|
66
59
|
const interval = setInterval(() => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
const currentSlots = slotsRef.current;
|
|
61
|
+
// Выбираем только не-статичные слоты, на которые не наведен указатель
|
|
62
|
+
const rotatableSlotIndices = currentSlots
|
|
63
|
+
.map((itemIdx, slotIdx) => {
|
|
64
|
+
var _a;
|
|
65
|
+
return ((_a = items[itemIdx]) === null || _a === void 0 ? void 0 : _a.isStatic) || hoveredSlotIndicesRef.current.has(slotIdx)
|
|
66
|
+
? -1
|
|
67
|
+
: slotIdx;
|
|
68
|
+
})
|
|
72
69
|
.filter((i) => i !== -1);
|
|
73
70
|
if (rotatableSlotIndices.length === 0)
|
|
74
71
|
return;
|
|
@@ -76,35 +73,56 @@ const LogoRotatorBlock = (props) => {
|
|
|
76
73
|
const rotateMax = Math.max(minRotateCount, maxRotateCount);
|
|
77
74
|
const rotateCount = rotateMin + Math.floor(Math.random() * (rotateMax - rotateMin + 1));
|
|
78
75
|
const slotIndices = pickRandomSlots(rotatableSlotIndices, Math.min(rotateCount, rotatableSlotIndices.length));
|
|
79
|
-
|
|
76
|
+
let available = rotatableIndices.filter((i) => !currentSlots.includes(i));
|
|
77
|
+
const blockedTargetSrcs = new Set();
|
|
78
|
+
const nextTransitions = [];
|
|
79
|
+
slotIndices.forEach((slotIndex) => {
|
|
80
|
+
var _a, _b;
|
|
81
|
+
if (available.length === 0)
|
|
82
|
+
return;
|
|
83
|
+
const currentItemIndex = currentSlots[slotIndex];
|
|
84
|
+
const currentSrc = (_a = items[currentItemIndex]) === null || _a === void 0 ? void 0 : _a.src;
|
|
85
|
+
const slotAvailable = available.filter((i) => {
|
|
86
|
+
var _a;
|
|
87
|
+
const src = (_a = items[i]) === null || _a === void 0 ? void 0 : _a.src;
|
|
88
|
+
return src !== currentSrc && !blockedTargetSrcs.has(src);
|
|
89
|
+
});
|
|
90
|
+
if (slotAvailable.length === 0)
|
|
91
|
+
return;
|
|
92
|
+
const newValue = slotAvailable[nextIndexRef.current % slotAvailable.length];
|
|
93
|
+
nextIndexRef.current++;
|
|
94
|
+
available = available.filter((i) => i !== newValue);
|
|
95
|
+
const newSrc = (_b = items[newValue]) === null || _b === void 0 ? void 0 : _b.src;
|
|
96
|
+
if (newSrc) {
|
|
97
|
+
blockedTargetSrcs.add(newSrc);
|
|
98
|
+
}
|
|
99
|
+
nextTransitions.push({ slotIndex, from: currentItemIndex, to: newValue });
|
|
100
|
+
});
|
|
101
|
+
if (nextTransitions.length === 0)
|
|
102
|
+
return;
|
|
103
|
+
setTransitions((prev) => {
|
|
80
104
|
const next = [...prev];
|
|
81
|
-
|
|
82
|
-
next[slotIndex] =
|
|
105
|
+
nextTransitions.forEach(({ slotIndex, from, to }) => {
|
|
106
|
+
next[slotIndex] = { from, to };
|
|
83
107
|
});
|
|
84
108
|
return next;
|
|
85
109
|
});
|
|
86
110
|
timeout = setTimeout(() => {
|
|
87
111
|
setSlots((prevSlots) => {
|
|
88
112
|
const newSlots = [...prevSlots];
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (available.length === 0)
|
|
92
|
-
return;
|
|
93
|
-
const newValue = available[nextIndexRef.current % available.length];
|
|
94
|
-
nextIndexRef.current++;
|
|
95
|
-
newSlots[slotIndex] = newValue;
|
|
96
|
-
available = available.filter((i) => i !== newValue);
|
|
113
|
+
nextTransitions.forEach(({ slotIndex, to }) => {
|
|
114
|
+
newSlots[slotIndex] = to;
|
|
97
115
|
});
|
|
98
116
|
return newSlots;
|
|
99
117
|
});
|
|
100
|
-
|
|
118
|
+
setTransitions((prev) => {
|
|
101
119
|
const next = [...prev];
|
|
102
|
-
|
|
103
|
-
next[slotIndex] =
|
|
120
|
+
nextTransitions.forEach(({ slotIndex }) => {
|
|
121
|
+
next[slotIndex] = undefined;
|
|
104
122
|
});
|
|
105
123
|
return next;
|
|
106
124
|
});
|
|
107
|
-
},
|
|
125
|
+
}, utils_2.SWAP_ANIMATION_DURATIONS[swapAnimation]);
|
|
108
126
|
}, 2000);
|
|
109
127
|
return () => {
|
|
110
128
|
clearInterval(interval);
|
|
@@ -112,29 +130,49 @@ const LogoRotatorBlock = (props) => {
|
|
|
112
130
|
clearTimeout(timeout);
|
|
113
131
|
}
|
|
114
132
|
};
|
|
115
|
-
}, [activeCount, items, maxRotateCount, minRotateCount, rotatableIndices]);
|
|
116
|
-
const renderItems = (0, react_1.useMemo)(() => slots.map((slot, index) =>
|
|
133
|
+
}, [activeCount, items, maxRotateCount, minRotateCount, rotatableIndices, swapAnimation]);
|
|
134
|
+
const renderItems = (0, react_1.useMemo)(() => slots.map((slot, index) => {
|
|
135
|
+
var _a;
|
|
136
|
+
const transition = transitions[index];
|
|
137
|
+
const item = items[(_a = transition === null || transition === void 0 ? void 0 : transition.to) !== null && _a !== void 0 ? _a : slot];
|
|
138
|
+
const previousItem = transition ? items[transition.from] : undefined;
|
|
139
|
+
return (react_1.default.createElement(Item_1.default, { key: index, colSizes: colSizes, url: item.url, src: item.src, previousUrl: previousItem === null || previousItem === void 0 ? void 0 : previousItem.url, previousSrc: previousItem === null || previousItem === void 0 ? void 0 : previousItem.src, swapAnimation: swapAnimation, onMouseEnter: () => handleSlotMouseEnter(index), onMouseLeave: () => handleSlotMouseLeave(index) }));
|
|
140
|
+
}), [
|
|
141
|
+
colSizes,
|
|
142
|
+
handleSlotMouseEnter,
|
|
143
|
+
handleSlotMouseLeave,
|
|
144
|
+
items,
|
|
145
|
+
slots,
|
|
146
|
+
swapAnimation,
|
|
147
|
+
transitions,
|
|
148
|
+
]);
|
|
117
149
|
const titleProps = !title || typeof title === 'string'
|
|
118
150
|
? { text: title, textSize: 'l' }
|
|
119
151
|
: title;
|
|
120
152
|
const hasTitle = Boolean(title);
|
|
121
153
|
return (react_1.default.createElement(AnimateBlock_1.default, { className: b({ theme }), animate: animated },
|
|
122
|
-
react_1.default.createElement("div", { className: b('root'),
|
|
123
|
-
isHoveredRef.current = true;
|
|
124
|
-
}, onMouseLeave: () => {
|
|
125
|
-
isHoveredRef.current = false;
|
|
126
|
-
} },
|
|
154
|
+
react_1.default.createElement("div", { className: b('root') },
|
|
127
155
|
hasTitle && (react_1.default.createElement(components_1.Title, { title: titleProps, className: b('title'), colSizes: { all: 12 } })),
|
|
128
156
|
rowMode ? (react_1.default.createElement("div", { className: b('row-items') }, slots.map((slot, index) => {
|
|
129
|
-
|
|
130
|
-
|
|
157
|
+
var _a;
|
|
158
|
+
const transition = transitions[index];
|
|
159
|
+
const item = items[(_a = transition === null || transition === void 0 ? void 0 : transition.to) !== null && _a !== void 0 ? _a : slot];
|
|
160
|
+
const previousItem = transition ? items[transition.from] : undefined;
|
|
161
|
+
if (item === undefined)
|
|
131
162
|
return null;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
163
|
+
const renderRowLayer = (layerItem, layer) => {
|
|
164
|
+
const layerClassName = b('logo-layer', (0, utils_2.getLayerModifiers)(layer, swapAnimation));
|
|
165
|
+
if (layerItem.url) {
|
|
166
|
+
return (react_1.default.createElement(uikit_1.Link, { href: layerItem.url, className: `${b('row-item-link')} ${layerClassName}` },
|
|
167
|
+
react_1.default.createElement(components_1.ImageBase, { src: layerItem.src, className: b('image'), alt: "", "aria-hidden": "true" })));
|
|
168
|
+
}
|
|
169
|
+
return (react_1.default.createElement("div", { className: layerClassName },
|
|
170
|
+
react_1.default.createElement(components_1.ImageBase, { src: layerItem.src, className: b('image'), alt: "", "aria-hidden": "true" })));
|
|
171
|
+
};
|
|
172
|
+
const content = (react_1.default.createElement(react_1.default.Fragment, null,
|
|
173
|
+
previousItem && renderRowLayer(previousItem, 'from'),
|
|
174
|
+
renderRowLayer(item, previousItem ? 'to' : 'current')));
|
|
175
|
+
return (react_1.default.createElement("div", { key: index, className: b('row-item', { swapping: Boolean(previousItem) }), onMouseEnter: () => handleSlotMouseEnter(index), onMouseLeave: () => handleSlotMouseLeave(index) }, content));
|
|
138
176
|
}))) : (react_1.default.createElement(grid_1.Grid, { className: b('items') },
|
|
139
177
|
react_1.default.createElement(grid_1.Row, { className: b('row') }, renderItems))))));
|
|
140
178
|
};
|
|
@@ -182,10 +182,10 @@ export declare const LogoRotatorBlock: {
|
|
|
182
182
|
};
|
|
183
183
|
};
|
|
184
184
|
};
|
|
185
|
-
|
|
185
|
+
countMobile: {
|
|
186
186
|
type: string;
|
|
187
187
|
};
|
|
188
|
-
|
|
188
|
+
countDesktop: {
|
|
189
189
|
type: string;
|
|
190
190
|
};
|
|
191
191
|
minRotateCount: {
|
|
@@ -194,6 +194,10 @@ export declare const LogoRotatorBlock: {
|
|
|
194
194
|
maxRotateCount: {
|
|
195
195
|
type: string;
|
|
196
196
|
};
|
|
197
|
+
swapAnimation: {
|
|
198
|
+
type: string;
|
|
199
|
+
enum: string[];
|
|
200
|
+
};
|
|
197
201
|
colSizes: {
|
|
198
202
|
type: string;
|
|
199
203
|
additionalProperties: {
|
|
@@ -5,7 +5,7 @@ const common_1 = require("../../schema/validators/common");
|
|
|
5
5
|
exports.LogoRotatorBlock = {
|
|
6
6
|
'logo-rotator-block': {
|
|
7
7
|
additionalProperties: false,
|
|
8
|
-
required: ['items', '
|
|
8
|
+
required: ['items', 'countMobile'],
|
|
9
9
|
properties: Object.assign(Object.assign(Object.assign({}, common_1.BaseProps), common_1.AnimatableProps), { title: {
|
|
10
10
|
oneOf: [
|
|
11
11
|
{
|
|
@@ -27,14 +27,17 @@ exports.LogoRotatorBlock = {
|
|
|
27
27
|
isStatic: { type: 'boolean' },
|
|
28
28
|
},
|
|
29
29
|
},
|
|
30
|
-
},
|
|
30
|
+
}, countMobile: {
|
|
31
31
|
type: 'number',
|
|
32
|
-
},
|
|
32
|
+
}, countDesktop: {
|
|
33
33
|
type: 'number',
|
|
34
34
|
}, minRotateCount: {
|
|
35
35
|
type: 'number',
|
|
36
36
|
}, maxRotateCount: {
|
|
37
37
|
type: 'number',
|
|
38
|
+
}, swapAnimation: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
enum: ['fade', 'morph'],
|
|
38
41
|
}, colSizes: {
|
|
39
42
|
type: 'object',
|
|
40
43
|
additionalProperties: common_1.containerSizesObject,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { LogoRotatorBlockProps } from '../../models';
|
|
2
|
+
export type LogoRotatorLayer = 'current' | 'from' | 'to';
|
|
3
|
+
export type LogoRotatorSwapAnimation = NonNullable<LogoRotatorBlockProps['swapAnimation']>;
|
|
4
|
+
export declare const DEFAULT_SWAP_ANIMATION: LogoRotatorSwapAnimation;
|
|
5
|
+
export declare const SWAP_ANIMATION_DURATIONS: Record<LogoRotatorSwapAnimation, number>;
|
|
6
|
+
export declare const getLayerModifiers: (layer: LogoRotatorLayer, swapAnimation: LogoRotatorSwapAnimation) => Record<string, boolean>;
|
|
7
|
+
export declare const getInitialSlots: (items: LogoRotatorBlockProps['items'], count: number) => number[];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getInitialSlots = exports.getLayerModifiers = exports.SWAP_ANIMATION_DURATIONS = exports.DEFAULT_SWAP_ANIMATION = void 0;
|
|
4
|
+
exports.DEFAULT_SWAP_ANIMATION = 'fade';
|
|
5
|
+
exports.SWAP_ANIMATION_DURATIONS = {
|
|
6
|
+
fade: 1100,
|
|
7
|
+
morph: 500,
|
|
8
|
+
};
|
|
9
|
+
const getLayerModifiers = (layer, swapAnimation) => {
|
|
10
|
+
const animationModifier = layer === 'current' ? undefined : `${swapAnimation}-${layer}`;
|
|
11
|
+
const modifiers = { [layer]: true };
|
|
12
|
+
if (animationModifier) {
|
|
13
|
+
modifiers[animationModifier] = true;
|
|
14
|
+
}
|
|
15
|
+
return modifiers;
|
|
16
|
+
};
|
|
17
|
+
exports.getLayerModifiers = getLayerModifiers;
|
|
18
|
+
const getInitialSlots = (items, count) => {
|
|
19
|
+
var _a;
|
|
20
|
+
const staticIdxList = items.map((item, i) => (item.isStatic ? i : -1)).filter((i) => i !== -1);
|
|
21
|
+
const rotatableIdxList = items
|
|
22
|
+
.map((item, i) => (item.isStatic ? -1 : i))
|
|
23
|
+
.filter((i) => i !== -1);
|
|
24
|
+
const initial = [];
|
|
25
|
+
let rotatablePointer = 0;
|
|
26
|
+
for (let slot = 0; slot < count; slot++) {
|
|
27
|
+
if (slot < staticIdxList.length) {
|
|
28
|
+
initial.push(staticIdxList[slot]);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
initial.push((_a = rotatableIdxList[rotatablePointer++]) !== null && _a !== void 0 ? _a : 0);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return initial;
|
|
35
|
+
};
|
|
36
|
+
exports.getInitialSlots = getInitialSlots;
|
|
@@ -302,10 +302,11 @@ export interface LogoRotatorBlockProps extends Animatable {
|
|
|
302
302
|
src: string;
|
|
303
303
|
isStatic?: boolean;
|
|
304
304
|
}[];
|
|
305
|
-
|
|
306
|
-
|
|
305
|
+
countMobile: number;
|
|
306
|
+
countDesktop?: number;
|
|
307
307
|
minRotateCount?: number;
|
|
308
308
|
maxRotateCount?: number;
|
|
309
|
+
swapAnimation?: 'fade' | 'morph';
|
|
309
310
|
colSizes?: Partial<Record<GridColumnSize, number>>;
|
|
310
311
|
theme?: TextTheme;
|
|
311
312
|
rowMode?: boolean;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { LogoRotatorBlockProps } from '../../models';
|
|
3
|
+
import type { LogoRotatorSwapAnimation } from './utils';
|
|
3
4
|
import './LogoRotator.css';
|
|
4
5
|
type Props = {
|
|
5
6
|
src: string;
|
|
6
7
|
url?: string;
|
|
7
|
-
|
|
8
|
+
previousSrc?: string;
|
|
9
|
+
previousUrl?: string;
|
|
10
|
+
swapAnimation: LogoRotatorSwapAnimation;
|
|
8
11
|
colSizes: LogoRotatorBlockProps['colSizes'];
|
|
12
|
+
onMouseEnter?: () => void;
|
|
13
|
+
onMouseLeave?: () => void;
|
|
9
14
|
};
|
|
10
|
-
export declare const Item: ({ url, src,
|
|
11
|
-
declare const _default: React.MemoExoticComponent<({ url, src,
|
|
15
|
+
export declare const Item: ({ url, src, previousSrc, previousUrl, swapAnimation, colSizes, onMouseEnter, onMouseLeave, }: Props) => JSX.Element;
|
|
16
|
+
declare const _default: React.MemoExoticComponent<({ url, src, previousSrc, previousUrl, swapAnimation, colSizes, onMouseEnter, onMouseLeave, }: Props) => JSX.Element>;
|
|
12
17
|
export default _default;
|
|
@@ -3,18 +3,23 @@ import { Link } from '@gravity-ui/uikit';
|
|
|
3
3
|
import { Image } from '../../components';
|
|
4
4
|
import { Col } from '../../grid';
|
|
5
5
|
import { block } from '../../utils';
|
|
6
|
+
import { getLayerModifiers } from './utils';
|
|
6
7
|
import './LogoRotator.css';
|
|
7
8
|
const b = block('logo-rotator-block');
|
|
8
9
|
const defaultColSizes = { all: 3 };
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const getLayerClassName = (layer, swapAnimation, link = false) => `${link ? `${b('item-link')} ` : ''}${b('logo-layer', getLayerModifiers(layer, swapAnimation))}`;
|
|
11
|
+
export const Item = ({ url, src, previousSrc, previousUrl, swapAnimation, colSizes, onMouseEnter, onMouseLeave, }) => {
|
|
12
|
+
const renderLayer = (layerSrc, layer, layerUrl) => {
|
|
13
|
+
const image = React.createElement(Image, { src: layerSrc, className: b('image'), alt: "", "aria-hidden": "true" });
|
|
14
|
+
if (layerUrl) {
|
|
15
|
+
return (React.createElement(Link, { href: layerUrl, className: getLayerClassName(layer, swapAnimation, true) }, image));
|
|
14
16
|
}
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return React.createElement(Col, { sizes: colSizes || defaultColSizes },
|
|
17
|
+
return React.createElement("div", { className: getLayerClassName(layer, swapAnimation) }, image);
|
|
18
|
+
};
|
|
19
|
+
const isSwapping = Boolean(previousSrc);
|
|
20
|
+
return (React.createElement(Col, { sizes: colSizes || defaultColSizes },
|
|
21
|
+
React.createElement("div", { className: b('item', { swapping: isSwapping }), onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave },
|
|
22
|
+
previousSrc && renderLayer(previousSrc, 'from', previousUrl),
|
|
23
|
+
renderLayer(src, previousSrc ? 'to' : 'current', url))));
|
|
19
24
|
};
|
|
20
25
|
export default React.memo(Item);
|