@hh.ru/magritte-ui-snackbar 6.4.25 → 6.4.27

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.
@@ -15,248 +15,318 @@ import { SnackbarTransitionName } from './types.js';
15
15
  import { useAriaSnackbar } from './useAriaSnackbar.js';
16
16
  import { ThemeWrapper } from '@hh.ru/magritte-ui-theme-wrapper';
17
17
  import { useTimer, Timer } from '@hh.ru/magritte-ui-timer';
18
- import { s as styles } from './snackbar-ClWKT5ad.js';
18
+ import { s as styles } from './snackbar-DxehbKoS.js';
19
19
 
20
20
  const OTHER_CLASS_NAMES = {
21
- [SnackbarTransitionName.Hide]: {
22
- exit: styles.exit,
23
- exitActive: styles['exit-active'],
24
- exitDone: styles['exit-done'],
25
- },
26
- [SnackbarTransitionName.Autohide]: {
27
- exit: styles.exit,
28
- exitActive: styles['exit-active_autohide'],
29
- exitDone: styles['exit-done'],
30
- },
31
- [SnackbarTransitionName.RemoveImmediately]: {},
21
+ [SnackbarTransitionName.Hide]: {
22
+ exit: styles.exit,
23
+ exitActive: styles["exit-active"],
24
+ exitDone: styles["exit-done"]
25
+ },
26
+ [SnackbarTransitionName.Autohide]: {
27
+ exit: styles.exit,
28
+ exitActive: styles["exit-active_autohide"],
29
+ exitDone: styles["exit-done"]
30
+ },
31
+ [SnackbarTransitionName.RemoveImmediately]: {}
32
32
  };
33
33
  const OPEN_CLASS_NAMES = {
34
- [SnackbarTransitionName.Show]: {
35
- top: {
36
- appear: styles.appearTop,
37
- appearActive: styles['appear-active'],
38
- appearDone: styles['appear-done'],
39
- },
40
- bottom: {
41
- appear: styles.appearBottom,
42
- appearActive: styles['appear-active'],
43
- appearDone: styles['appear-done'],
44
- },
34
+ [SnackbarTransitionName.Show]: {
35
+ top: {
36
+ appear: styles.appearTop,
37
+ appearActive: styles["appear-active"],
38
+ appearDone: styles["appear-done"]
45
39
  },
40
+ bottom: {
41
+ appear: styles.appearBottom,
42
+ appearActive: styles["appear-active"],
43
+ appearDone: styles["appear-done"]
44
+ }
45
+ }
46
46
  };
47
- const DEFAULT_AUTOHIDE_TIME_MS = 6000;
47
+ const DEFAULT_AUTOHIDE_TIME_MS = 6e3;
48
48
  const BASE_VERTICAL_PADDING = 16;
49
49
  const VERTICAL_PADDING_BETWEEN_SNACKBAR = 8;
50
- const SnackbarRenderer = ({ actionLabel, addon, align = 'bottom', animateOut, autohideTime = DEFAULT_AUTOHIDE_TIME_MS, children, containerId, isShown, onAction, onClose, onShown, showClose, showTimer, timeout, transition, 'aria-label': ariaLabel, 'aria-label-close': ariaLabelClose, role = 'status', stretched = true, position, container, 'data-qa': dataQa, ...props }) => {
51
- const actionFunc = useCallback(() => onAction?.(), [onAction]);
52
- const [hasKeyboardFocus, setHasKeyboardFocus] = useState(false);
53
- const [hasHover, setHasHover] = useState(false);
54
- const [isTouched, setisTouched] = useState(false);
55
- const hasTouchSupportRef = useRef(false);
56
- const prevWidth = useRef(0);
57
- const stretchedRef = useRef(stretched);
58
- const closeReasonRef = useRef(null);
59
- const autohideFunc = useCallback(() => {
60
- closeReasonRef.current = 'timeout';
61
- animateOut(SnackbarTransitionName.Autohide);
62
- }, [animateOut]);
63
- const closeFunc = useCallback(() => {
64
- closeReasonRef.current = 'user';
65
- animateOut(SnackbarTransitionName.Hide);
66
- }, [animateOut]);
67
- const ariaAttributes = useAriaSnackbar({ role, hasAction: !!actionLabel, 'aria-label': ariaLabel });
68
- const visible = transition === SnackbarTransitionName.Show;
69
- const maxDistanceSqRef = useRef({ nearestSide: Number.POSITIVE_INFINITY, farSide: Number.POSITIVE_INFINITY });
70
- const swipeThresholdXRef = useRef(null);
71
- const swipeThresholdYRef = useRef(null);
72
- const isTimerPaused = hasKeyboardFocus || hasHover || isTouched;
73
- const removeImmediately = useCallback(() => {
74
- animateOut(SnackbarTransitionName.RemoveImmediately);
75
- onClose?.({ reason: closeReasonRef.current });
76
- closeReasonRef.current = null;
77
- }, [animateOut, onClose]);
78
- const snackbarRef = useRef(null);
79
- const bindEscapeToClose = useEscapeToClose(closeFunc);
80
- const snackbarRefMultiplexer = useMultipleRefs(snackbarRef, bindEscapeToClose);
81
- useTimer(!!autohideTime && !showTimer ? autohideTime : -1, (callable) => {
82
- const timeoutId = setTimeout(callable, 50);
83
- return () => clearTimeout(timeoutId);
84
- }, (remaining) => {
85
- remaining < 0 && autohideFunc();
86
- }, isTimerPaused);
87
- useEffect(() => {
88
- if (snackbarRef.current !== null) {
89
- const maxDistanceX = snackbarRef.current.clientWidth * 0.66;
90
- const maxDistanceNearestY = snackbarRef.current.clientHeight * 0.5;
91
- const maxDistanceFarY = snackbarRef.current.clientHeight;
92
- maxDistanceSqRef.current.nearestSide = Math.pow(maxDistanceX, 2) + Math.pow(maxDistanceNearestY, 2);
93
- maxDistanceSqRef.current.farSide = Math.pow(maxDistanceX, 2) + Math.pow(maxDistanceFarY, 2);
94
- swipeThresholdXRef.current = { minDelta: -maxDistanceX, maxDelta: maxDistanceX };
95
- swipeThresholdYRef.current =
96
- align === 'top'
97
- ? { minDelta: -maxDistanceNearestY, maxDelta: maxDistanceFarY }
98
- : { minDelta: -maxDistanceFarY, maxDelta: maxDistanceNearestY };
99
- }
100
- }, [align, visible]);
101
- const handleSwipeMove = useCallback((event) => {
102
- if (snackbarRef.current !== null) {
103
- // насколько прозрачным нужно сделать снекбар с учетом расстояния от начальной позиции
104
- let maxDistanceSq = maxDistanceSqRef.current.nearestSide;
105
- // определяем был ли свайп в дальнюю сторону экрана по вертикали
106
- if ((align === 'top' && event.distanceY > 0) || (align === 'bottom' && event.distanceY < 0)) {
107
- maxDistanceSq = maxDistanceSqRef.current.farSide;
108
- }
109
- const fadeDistanceSq = Math.pow(event.distanceX, 2) + Math.pow(event.distanceY, 2);
110
- snackbarRef.current.style.opacity = `${1 - fadeDistanceSq / maxDistanceSq}`;
111
- snackbarRef.current.style.transform = `translate(${event.distanceX}px, ${event.distanceY}px)`;
112
- }
113
- }, [align]);
114
- const handleSwipeEnd = useCallback(() => {
115
- if (snackbarRef.current !== null) {
116
- snackbarRef.current.style.opacity = `0`;
117
- }
118
- closeFunc();
119
- }, [closeFunc]);
120
- const handleSwipeCancel = useCallback(() => {
121
- if (snackbarRef.current !== null) {
122
- snackbarRef.current.style.removeProperty('opacity');
123
- snackbarRef.current.style.removeProperty('transform');
124
- }
125
- }, []);
126
- const swipeHandlers = useSwipeHandlers({
127
- thresholdXRef: swipeThresholdXRef,
128
- thresholdYRef: swipeThresholdYRef,
129
- onSwipeMove: handleSwipeMove,
130
- onSwipeEnd: handleSwipeEnd,
131
- onSwipeCancel: handleSwipeCancel,
132
- });
133
- useEffect(() => {
134
- const snackbar = snackbarRef.current;
135
- if (!snackbar) {
136
- return void 0;
137
- }
138
- const handleTouchStart = (event) => {
139
- event.stopPropagation();
140
- hasTouchSupportRef.current = true;
141
- setisTouched(true);
142
- swipeHandlers.onTouchStart(event);
143
- };
144
- const handleTouchMove = (event) => {
145
- event.preventDefault();
146
- event.stopPropagation();
147
- swipeHandlers.onTouchMove(event);
148
- };
149
- const handleTouchEnd = (event) => {
150
- setisTouched(false);
151
- swipeHandlers.onTouchEnd(event);
152
- };
153
- const handleTouchCancel = (event) => {
154
- setisTouched(false);
155
- swipeHandlers.onTouchCancel(event);
156
- };
157
- snackbar.addEventListener('touchstart', handleTouchStart);
158
- snackbar.addEventListener('touchmove', handleTouchMove, { passive: false });
159
- snackbar.addEventListener('touchend', handleTouchEnd);
160
- snackbar.addEventListener('touchcancel', handleTouchCancel);
161
- return () => {
162
- snackbar.removeEventListener('touchstart', handleTouchStart);
163
- snackbar.removeEventListener('touchmove', handleTouchMove);
164
- snackbar.removeEventListener('touchend', handleTouchEnd);
165
- snackbar.removeEventListener('touchcancel', handleTouchCancel);
166
- };
167
- }, [swipeHandlers]);
168
- useEffect(() => {
169
- const snackbar = snackbarRef.current;
170
- if (!snackbar) {
171
- return;
50
+ const SnackbarRenderer = ({
51
+ actionLabel,
52
+ addon,
53
+ align = "bottom",
54
+ animateOut,
55
+ autohideTime = DEFAULT_AUTOHIDE_TIME_MS,
56
+ children,
57
+ containerId,
58
+ isShown,
59
+ onAction,
60
+ onClose,
61
+ onShown,
62
+ showClose,
63
+ showTimer,
64
+ timeout,
65
+ transition,
66
+ "aria-label": ariaLabel,
67
+ "aria-label-close": ariaLabelClose,
68
+ role = "status",
69
+ stretched = true,
70
+ position,
71
+ container,
72
+ "data-qa": dataQa,
73
+ ...props
74
+ }) => {
75
+ const actionFunc = useCallback(() => onAction?.(), [onAction]);
76
+ const [hasKeyboardFocus, setHasKeyboardFocus] = useState(false);
77
+ const [hasHover, setHasHover] = useState(false);
78
+ const [isTouched, setisTouched] = useState(false);
79
+ const hasTouchSupportRef = useRef(false);
80
+ const prevWidth = useRef(0);
81
+ const stretchedRef = useRef(stretched);
82
+ const closeReasonRef = useRef(null);
83
+ const autohideFunc = useCallback(() => {
84
+ closeReasonRef.current = "timeout";
85
+ animateOut(SnackbarTransitionName.Autohide);
86
+ }, [animateOut]);
87
+ const closeFunc = useCallback(() => {
88
+ closeReasonRef.current = "user";
89
+ animateOut(SnackbarTransitionName.Hide);
90
+ }, [animateOut]);
91
+ const ariaAttributes = useAriaSnackbar({ role, hasAction: !!actionLabel, "aria-label": ariaLabel });
92
+ const visible = transition === SnackbarTransitionName.Show;
93
+ const maxDistanceSqRef = useRef({ nearestSide: Number.POSITIVE_INFINITY, farSide: Number.POSITIVE_INFINITY });
94
+ const swipeThresholdXRef = useRef(null);
95
+ const swipeThresholdYRef = useRef(null);
96
+ const isTimerPaused = hasKeyboardFocus || hasHover || isTouched;
97
+ const removeImmediately = useCallback(() => {
98
+ animateOut(SnackbarTransitionName.RemoveImmediately);
99
+ onClose?.({ reason: closeReasonRef.current });
100
+ closeReasonRef.current = null;
101
+ }, [animateOut, onClose]);
102
+ const snackbarRef = useRef(null);
103
+ const bindEscapeToClose = useEscapeToClose(closeFunc);
104
+ const snackbarRefMultiplexer = useMultipleRefs(snackbarRef, bindEscapeToClose);
105
+ useTimer(
106
+ !!autohideTime && !showTimer ? autohideTime : -1,
107
+ (callable) => {
108
+ const timeoutId = setTimeout(callable, 50);
109
+ return () => clearTimeout(timeoutId);
110
+ },
111
+ (remaining) => {
112
+ remaining < 0 && autohideFunc();
113
+ },
114
+ isTimerPaused
115
+ );
116
+ useEffect(() => {
117
+ if (snackbarRef.current !== null) {
118
+ const maxDistanceX = snackbarRef.current.clientWidth * 0.66;
119
+ const maxDistanceNearestY = snackbarRef.current.clientHeight * 0.5;
120
+ const maxDistanceFarY = snackbarRef.current.clientHeight;
121
+ maxDistanceSqRef.current.nearestSide = Math.pow(maxDistanceX, 2) + Math.pow(maxDistanceNearestY, 2);
122
+ maxDistanceSqRef.current.farSide = Math.pow(maxDistanceX, 2) + Math.pow(maxDistanceFarY, 2);
123
+ swipeThresholdXRef.current = { minDelta: -maxDistanceX, maxDelta: maxDistanceX };
124
+ swipeThresholdYRef.current = align === "top" ? { minDelta: -maxDistanceNearestY, maxDelta: maxDistanceFarY } : { minDelta: -maxDistanceFarY, maxDelta: maxDistanceNearestY };
125
+ }
126
+ }, [align, visible]);
127
+ const handleSwipeMove = useCallback(
128
+ (event) => {
129
+ if (snackbarRef.current !== null) {
130
+ let maxDistanceSq = maxDistanceSqRef.current.nearestSide;
131
+ if (align === "top" && event.distanceY > 0 || align === "bottom" && event.distanceY < 0) {
132
+ maxDistanceSq = maxDistanceSqRef.current.farSide;
172
133
  }
173
- snackbar.style.setProperty('--snackbar-offset', `${snackbarRef.current.offsetHeight}px`);
174
- prevWidth.current = snackbar.getBoundingClientRect().width;
175
- }, []);
176
- useEffect(() => {
177
- const snackbar = snackbarRef.current;
178
- if (!snackbar) {
179
- return;
134
+ const fadeDistanceSq = Math.pow(event.distanceX, 2) + Math.pow(event.distanceY, 2);
135
+ snackbarRef.current.style.opacity = `${1 - fadeDistanceSq / maxDistanceSq}`;
136
+ snackbarRef.current.style.transform = `translate(${event.distanceX}px, ${event.distanceY}px)`;
137
+ }
138
+ },
139
+ [align]
140
+ );
141
+ const handleSwipeEnd = useCallback(() => {
142
+ if (snackbarRef.current !== null) {
143
+ snackbarRef.current.style.opacity = `0`;
144
+ }
145
+ closeFunc();
146
+ }, [closeFunc]);
147
+ const handleSwipeCancel = useCallback(() => {
148
+ if (snackbarRef.current !== null) {
149
+ snackbarRef.current.style.removeProperty("opacity");
150
+ snackbarRef.current.style.removeProperty("transform");
151
+ }
152
+ }, []);
153
+ const swipeHandlers = useSwipeHandlers({
154
+ thresholdXRef: swipeThresholdXRef,
155
+ thresholdYRef: swipeThresholdYRef,
156
+ onSwipeMove: handleSwipeMove,
157
+ onSwipeEnd: handleSwipeEnd,
158
+ onSwipeCancel: handleSwipeCancel
159
+ });
160
+ useEffect(() => {
161
+ const snackbar = snackbarRef.current;
162
+ if (!snackbar) {
163
+ return void 0;
164
+ }
165
+ const handleTouchStart = (event) => {
166
+ event.stopPropagation();
167
+ hasTouchSupportRef.current = true;
168
+ setisTouched(true);
169
+ swipeHandlers.onTouchStart(event);
170
+ };
171
+ const handleTouchMove = (event) => {
172
+ event.preventDefault();
173
+ event.stopPropagation();
174
+ swipeHandlers.onTouchMove(event);
175
+ };
176
+ const handleTouchEnd = (event) => {
177
+ setisTouched(false);
178
+ swipeHandlers.onTouchEnd(event);
179
+ };
180
+ const handleTouchCancel = (event) => {
181
+ setisTouched(false);
182
+ swipeHandlers.onTouchCancel(event);
183
+ };
184
+ snackbar.addEventListener("touchstart", handleTouchStart);
185
+ snackbar.addEventListener("touchmove", handleTouchMove, { passive: false });
186
+ snackbar.addEventListener("touchend", handleTouchEnd);
187
+ snackbar.addEventListener("touchcancel", handleTouchCancel);
188
+ return () => {
189
+ snackbar.removeEventListener("touchstart", handleTouchStart);
190
+ snackbar.removeEventListener("touchmove", handleTouchMove);
191
+ snackbar.removeEventListener("touchend", handleTouchEnd);
192
+ snackbar.removeEventListener("touchcancel", handleTouchCancel);
193
+ };
194
+ }, [swipeHandlers]);
195
+ useEffect(() => {
196
+ const snackbar = snackbarRef.current;
197
+ if (!snackbar) {
198
+ return;
199
+ }
200
+ snackbar.style.setProperty("--snackbar-offset", `${snackbarRef.current.offsetHeight}px`);
201
+ prevWidth.current = snackbar.getBoundingClientRect().width;
202
+ }, []);
203
+ useEffect(() => {
204
+ const snackbar = snackbarRef.current;
205
+ if (!snackbar) {
206
+ return;
207
+ }
208
+ const snackbars = container.querySelectorAll('[data-magritte-snackbar="true"]');
209
+ let offset = 0;
210
+ let found = false;
211
+ for (const node of snackbars) {
212
+ if (found) {
213
+ offset += node.offsetHeight;
214
+ }
215
+ if (node === snackbar) {
216
+ found = true;
217
+ }
218
+ }
219
+ const value = `${offset + VERTICAL_PADDING_BETWEEN_SNACKBAR * position + BASE_VERTICAL_PADDING}px`;
220
+ if (align === "top") {
221
+ snackbar.style.top = value;
222
+ snackbar.style.removeProperty("bottom");
223
+ return;
224
+ }
225
+ snackbar.style.bottom = value;
226
+ snackbar.style.removeProperty("top");
227
+ }, [position, align, container]);
228
+ useLayoutEffect(() => {
229
+ const snackbar = snackbarRef.current;
230
+ if (!snackbar || stretched === stretchedRef.current) {
231
+ return void 0;
232
+ }
233
+ const width = snackbar.getBoundingClientRect().width;
234
+ if (Math.abs(width - prevWidth.current) < 1) {
235
+ return void 0;
236
+ }
237
+ snackbar.style.width = `${prevWidth.current}px`;
238
+ void snackbar.offsetWidth;
239
+ snackbar.style.width = `${width}px`;
240
+ const onEnd = (event) => {
241
+ if (event.propertyName !== "width") {
242
+ return;
243
+ }
244
+ snackbar.style.removeProperty("width");
245
+ snackbar.removeEventListener("transitionend", onEnd);
246
+ };
247
+ snackbar.addEventListener("transitionend", onEnd);
248
+ stretchedRef.current = stretched;
249
+ prevWidth.current = width;
250
+ return () => {
251
+ snackbar.removeEventListener("transitionend", onEnd);
252
+ snackbar.style.removeProperty("width");
253
+ };
254
+ }, [stretched]);
255
+ const showDivider = showClose || Boolean(actionLabel);
256
+ const classNames = transition === SnackbarTransitionName.Show ? OPEN_CLASS_NAMES[transition][align] : OTHER_CLASS_NAMES[transition];
257
+ return /* @__PURE__ */ jsx(
258
+ CSSTransition,
259
+ {
260
+ appear: true,
261
+ classNames,
262
+ in: visible,
263
+ nodeRef: snackbarRef,
264
+ onEnter: () => {
265
+ onShown();
266
+ },
267
+ onEntered: () => {
268
+ if (actionLabel) {
269
+ snackbarRef.current?.focus();
180
270
  }
181
- // снекбары могут быть разные по высоте
182
- // для расчета текущей позиции
183
- // высоту каждого предыдущего надо учесть
184
- const snackbars = container.querySelectorAll('[data-magritte-snackbar="true"]');
185
- let offset = 0;
186
- let found = false;
187
- for (const node of snackbars) {
188
- if (found) {
189
- offset += node.offsetHeight;
271
+ },
272
+ onExited: removeImmediately,
273
+ timeout,
274
+ children: /* @__PURE__ */ jsx(ThemeWrapper, { children: (themeClass) => /* @__PURE__ */ jsx(Layer, { layer: "snackbar", children: /* @__PURE__ */ jsx(
275
+ "div",
276
+ {
277
+ ...props,
278
+ ...ariaAttributes,
279
+ className: classnames(styles.snackbar, themeClass, {
280
+ [styles.snackbarStretched]: stretched,
281
+ [styles[`snackbar_align-${align}`]]: align,
282
+ [styles.snackbarInBody]: !containerId
283
+ }),
284
+ "data-qa": classnames(dataQa, dataQa !== "snackbar" && "snackbar"),
285
+ ref: snackbarRefMultiplexer,
286
+ onFocus: (event) => {
287
+ if (event.target !== snackbarRef.current && event.target.classList.contains("focus-visible")) {
288
+ setHasKeyboardFocus(true);
190
289
  }
191
- if (node === snackbar) {
192
- found = true;
193
- }
194
- }
195
- const value = `${offset + VERTICAL_PADDING_BETWEEN_SNACKBAR * position + BASE_VERTICAL_PADDING}px`;
196
- if (align === 'top') {
197
- snackbar.style.top = value;
198
- snackbar.style.removeProperty('bottom');
199
- return;
290
+ },
291
+ onBlur: () => setHasKeyboardFocus(false),
292
+ onMouseEnter: () => !hasTouchSupportRef.current && setHasHover(true),
293
+ onMouseLeave: () => !hasTouchSupportRef.current && setHasHover(false),
294
+ "data-magritte-snackbar": true,
295
+ children: /* @__PURE__ */ jsxs("div", { className: styles.snackbarContent, children: [
296
+ !!addon && /* @__PURE__ */ jsx("div", { className: styles.snackbarAddon, "data-qa": "snackbar-addon", children: addon }),
297
+ !!autohideTime && showTimer && /* @__PURE__ */ jsx("div", { className: styles.snackbarAddon, "data-qa": "snackbar-timer", children: /* @__PURE__ */ jsx(Timer, { timeout: autohideTime, pause: isTimerPaused, callback: autohideFunc }) }),
298
+ /* @__PURE__ */ jsx("div", { className: styles.snackbarTextWrapper, children: /* @__PURE__ */ jsx("div", { className: styles.snackbarText, id: "dialog-description", children }) }),
299
+ showDivider && /* @__PURE__ */ jsx("div", { className: styles.divider, children: /* @__PURE__ */ jsx(Divider, { mode: "vertical" }) }),
300
+ !!actionLabel && /* @__PURE__ */ jsx("div", { className: styles.action, children: /* @__PURE__ */ jsx(
301
+ Link,
302
+ {
303
+ "data-qa": "snackbar-user-action",
304
+ "aria-label": actionLabel,
305
+ Element: "button",
306
+ type: "button",
307
+ onClick: actionFunc,
308
+ typography: "subtitle-1-semibold",
309
+ style: "constant",
310
+ children: actionLabel
311
+ }
312
+ ) }),
313
+ showClose && /* @__PURE__ */ jsx("div", { className: styles.snackbarClose, children: /* @__PURE__ */ jsx(
314
+ CrossOutlinedSize24,
315
+ {
316
+ padding: 8,
317
+ borderRadius: "halfHeight",
318
+ initialColor: "constant-secondary",
319
+ "data-qa": "snackbar-close-action",
320
+ tabIndex: actionLabel ? 0 : -1,
321
+ "aria-label": actionLabel && typeof ariaLabelClose === "string" ? ariaLabelClose : void 0,
322
+ onClick: closeFunc
323
+ }
324
+ ) })
325
+ ] })
200
326
  }
201
- snackbar.style.bottom = value;
202
- snackbar.style.removeProperty('top');
203
- }, [position, align, container]);
204
- useLayoutEffect(() => {
205
- const snackbar = snackbarRef.current;
206
- if (!snackbar || stretched === stretchedRef.current) {
207
- return void 0;
208
- }
209
- const width = snackbar.getBoundingClientRect().width;
210
- if (Math.abs(width - prevWidth.current) < 1) {
211
- return void 0;
212
- }
213
- // width: auto не анимируется, поэтому
214
- // зафиксировали ширину → анимировали → снял инлайн свойство
215
- snackbar.style.width = `${prevWidth.current}px`;
216
- void snackbar.offsetWidth; // force layout
217
- snackbar.style.width = `${width}px`;
218
- const onEnd = (event) => {
219
- if (event.propertyName !== 'width') {
220
- return;
221
- }
222
- snackbar.style.removeProperty('width');
223
- snackbar.removeEventListener('transitionend', onEnd);
224
- };
225
- snackbar.addEventListener('transitionend', onEnd);
226
- stretchedRef.current = stretched;
227
- prevWidth.current = width;
228
- return () => {
229
- snackbar.removeEventListener('transitionend', onEnd);
230
- snackbar.style.removeProperty('width');
231
- };
232
- }, [stretched]);
233
- const showDivider = showClose || Boolean(actionLabel);
234
- const classNames = transition === SnackbarTransitionName.Show
235
- ? OPEN_CLASS_NAMES[transition][align]
236
- : OTHER_CLASS_NAMES[transition];
237
- return (jsx(CSSTransition, { appear: true, classNames: classNames, in: visible, nodeRef: snackbarRef, onEnter: () => {
238
- onShown();
239
- }, onEntered: () => {
240
- if (actionLabel) {
241
- snackbarRef.current?.focus();
242
- }
243
- }, onExited: removeImmediately, timeout: timeout, children: jsx(ThemeWrapper, { children: (themeClass) => (jsx(Layer, { layer: "snackbar", children: jsx("div", { ...props, ...ariaAttributes, className: classnames(styles.snackbar, themeClass, {
244
- [styles.snackbarStretched]: stretched,
245
- [styles[`snackbar_align-${align}`]]: align,
246
- [styles.snackbarInBody]: !containerId,
247
- }), "data-qa": classnames(dataQa, dataQa !== 'snackbar' && 'snackbar'), ref: snackbarRefMultiplexer, onFocus: (event) => {
248
- // полифилл `@hh.ru/magritte-common-focus-visible` вешает класс
249
- // только на клавиатурный фокус — по клику таймер не останавливаем
250
- if (event.target !== snackbarRef.current &&
251
- event.target.classList.contains('focus-visible')) {
252
- setHasKeyboardFocus(true);
253
- }
254
- }, onBlur: () => setHasKeyboardFocus(false),
255
- // на тач-устройствах браузер эмулирует mouseenter после тапа
256
- // и «залипший» ховер останавливал бы таймер до следующего тапа
257
- onMouseEnter: () => !hasTouchSupportRef.current && setHasHover(true), onMouseLeave: () => !hasTouchSupportRef.current && setHasHover(false), "data-magritte-snackbar": true, children: jsxs("div", { className: styles.snackbarContent, children: [!!addon && (jsx("div", { className: styles.snackbarAddon, "data-qa": "snackbar-addon", children: addon })), !!autohideTime && showTimer && (jsx("div", { className: styles.snackbarAddon, "data-qa": "snackbar-timer", children: jsx(Timer, { timeout: autohideTime, pause: isTimerPaused, callback: autohideFunc }) })), jsx("div", { className: styles.snackbarTextWrapper, children: jsx("div", { className: styles.snackbarText, id: "dialog-description", children: children }) }), showDivider && (jsx("div", { className: styles.divider, children: jsx(Divider, { mode: "vertical" }) })), !!actionLabel && (jsx("div", { className: styles.action, children: jsx(Link, { "data-qa": "snackbar-user-action", "aria-label": actionLabel, Element: "button", type: "button", onClick: actionFunc, typography: "subtitle-1-semibold", style: "constant", children: actionLabel }) })), showClose && (jsx("div", { className: styles.snackbarClose, children: jsx(CrossOutlinedSize24, { padding: 8, borderRadius: "halfHeight", initialColor: "constant-secondary", "data-qa": "snackbar-close-action", tabIndex: actionLabel ? 0 : -1, "aria-label": actionLabel && typeof ariaLabelClose === 'string'
258
- ? ariaLabelClose
259
- : undefined, onClick: closeFunc }) }))] }) }) })) }) }));
327
+ ) }) })
328
+ }
329
+ );
260
330
  };
261
331
 
262
332
  export { SnackbarRenderer };