@snack-uikit/carousel 0.2.21-preview-e5174ad1.0 → 0.2.22-preview-71543426.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/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## 0.2.21 (2024-10-17)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **PDS-882:** scroll to partially visible slide on click ([f974fa2](https://github.com/cloud-ru-tech/snack-uikit/commit/f974fa298b3b972e4a27cb9cc5a065d92c583577))
12
+
13
+
14
+
15
+
16
+
6
17
  ## 0.2.20 (2024-09-23)
7
18
 
8
19
  ### Only dependencies have been changed
@@ -31,9 +31,7 @@ exports.Control = (0, react_1.forwardRef)((_a, ref) => {
31
31
  return (0, jsx_runtime_1.jsx)("button", Object.assign({
32
32
  ref: ref,
33
33
  className: styles_module_scss_1.default.control,
34
- onClick: () => {
35
- onClick === null || onClick === void 0 ? void 0 : onClick();
36
- },
34
+ onClick: onClick,
37
35
  type: 'button',
38
36
  "data-variant": variant
39
37
  }, (0, utils_1.extractSupportProps)(rest), {
@@ -58,28 +58,28 @@ function ItemProvider(_ref) {
58
58
  return () => observer.disconnect();
59
59
  }, [recalculateItemsSize]);
60
60
  const itemsTrackerRef = (0, react_1.useRef)(null);
61
- function hideNonVisibleItems() {
61
+ const hideNonVisibleItems = () => {
62
62
  var _a;
63
- (_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${testIds_1.TEST_IDS.trackItem}]`).forEach(function (slide) {
63
+ (_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${testIds_1.TEST_IDS.trackItem}]`).forEach(slide => {
64
64
  slide.setAttribute('aria-hidden', '0');
65
- slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(function (focusableElement) {
65
+ slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(focusableElement => {
66
66
  focusableElement.setAttribute('tabindex', '-5');
67
67
  focusableElement.classList.add(styles_module_scss_1.default.hiddenItem);
68
68
  });
69
69
  });
70
- }
71
- function showVisibleItems(slide, page, show) {
70
+ };
71
+ const showVisibleItems = (slide, page, show) => {
72
72
  var _a;
73
73
  (_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${testIds_1.TEST_IDS.trackItem}]`).forEach((item, i) => {
74
74
  if (i >= page * slide && i < page * slide + Math.trunc(show)) {
75
75
  item.removeAttribute('aria-hidden');
76
- item.querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]').forEach(function (focusableElement) {
76
+ item.querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]').forEach(focusableElement => {
77
77
  focusableElement.setAttribute('tabindex', '0');
78
78
  focusableElement.classList.remove(styles_module_scss_1.default.hiddenItem);
79
79
  });
80
80
  }
81
81
  });
82
- }
82
+ };
83
83
  const transform = (0, react_1.useMemo)(() => Number(-(page * scrollBy * computedValues.itemWidth + computedValues.gap * page * scrollBy)), [computedValues.gap, computedValues.itemWidth, page, scrollBy]);
84
84
  (0, react_1.useEffect)(() => {
85
85
  hideNonVisibleItems();
@@ -147,11 +147,23 @@ function ItemProvider(_ref) {
147
147
  onMouseUp: handleDragFinish,
148
148
  onMouseMove: handleDragMove
149
149
  } : {};
150
+ const handleSlideClick = (0, react_1.useCallback)(e => {
151
+ var _a, _b;
152
+ const slideRect = e.currentTarget.getBoundingClientRect();
153
+ const containerRect = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
154
+ const containerViewport = (_b = containerRect === null || containerRect === void 0 ? void 0 : containerRect.right) !== null && _b !== void 0 ? _b : 0;
155
+ const slidePositionDelta = containerViewport - slideRect.right;
156
+ const minPos = Math.min(slidePositionDelta, slideRect.x);
157
+ if (minPos < 0) {
158
+ slideCallback(slidePositionDelta);
159
+ }
160
+ }, [slideCallback]);
150
161
  return (0, jsx_runtime_1.jsx)("div", {
151
162
  ref: containerRef,
152
163
  className: styles_module_scss_1.default.itemProvider,
153
164
  "data-pointers": !drag.pointers || undefined,
154
165
  "data-swipe": swipe || undefined,
166
+ "data-gap": gap,
155
167
  style: Object.assign({}, Boolean(gap) ? {
156
168
  '--gap': gap
157
169
  } : {}),
@@ -163,13 +175,16 @@ function ItemProvider(_ref) {
163
175
  transition: `transform ${transition}s ease 0s`
164
176
  },
165
177
  ref: itemsTrackerRef,
166
- children: items.map((item, i) => (0, jsx_runtime_1.jsx)("div", {
178
+ children: items.map((item, i) =>
179
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
180
+ (0, jsx_runtime_1.jsx)("div", {
167
181
  style: {
168
182
  width: computedValues.itemWidth
169
183
  },
170
184
  className: styles_module_scss_1.default.itemContainer,
171
185
  role: 'group',
172
186
  "data-test-id": testIds_1.TEST_IDS.trackItem,
187
+ onClick: handleSlideClick,
173
188
  children: item
174
189
  }, i))
175
190
  }))
@@ -16,7 +16,5 @@ import { extractSupportProps } from '@snack-uikit/utils';
16
16
  import styles from './styles.module.css';
17
17
  export const Control = forwardRef((_a, ref) => {
18
18
  var { onClick, variant } = _a, rest = __rest(_a, ["onClick", "variant"]);
19
- return (_jsx("button", Object.assign({ ref: ref, className: styles.control, onClick: () => {
20
- onClick === null || onClick === void 0 ? void 0 : onClick();
21
- }, type: 'button', "data-variant": variant }, extractSupportProps(rest), { children: _jsx(ChevronLeftSVG, { size: 24, className: styles.icon }) })));
19
+ return (_jsx("button", Object.assign({ ref: ref, className: styles.control, onClick: onClick, type: 'button', "data-variant": variant }, extractSupportProps(rest), { children: _jsx(ChevronLeftSVG, { size: 24, className: styles.icon }) })));
22
20
  });
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import debounce from 'lodash.debounce';
3
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { useCallback, useEffect, useMemo, useRef, useState, } from 'react';
4
4
  import { TEST_IDS } from '../../testIds';
5
5
  import { getPageX } from './helpers';
6
6
  import styles from './styles.module.css';
@@ -37,30 +37,28 @@ export function ItemProvider({ items, showItems, scrollBy, slideCallback, transi
37
37
  return () => observer.disconnect();
38
38
  }, [recalculateItemsSize]);
39
39
  const itemsTrackerRef = useRef(null);
40
- function hideNonVisibleItems() {
40
+ const hideNonVisibleItems = () => {
41
41
  var _a;
42
- (_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach(function (slide) {
42
+ (_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach(slide => {
43
43
  slide.setAttribute('aria-hidden', '0');
44
- slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(function (focusableElement) {
44
+ slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(focusableElement => {
45
45
  focusableElement.setAttribute('tabindex', '-5');
46
46
  focusableElement.classList.add(styles.hiddenItem);
47
47
  });
48
48
  });
49
- }
50
- function showVisibleItems(slide, page, show) {
49
+ };
50
+ const showVisibleItems = (slide, page, show) => {
51
51
  var _a;
52
52
  (_a = itemsTrackerRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach((item, i) => {
53
53
  if (i >= page * slide && i < page * slide + Math.trunc(show)) {
54
54
  item.removeAttribute('aria-hidden');
55
- item
56
- .querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]')
57
- .forEach(function (focusableElement) {
55
+ item.querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]').forEach(focusableElement => {
58
56
  focusableElement.setAttribute('tabindex', '0');
59
57
  focusableElement.classList.remove(styles.hiddenItem);
60
58
  });
61
59
  }
62
60
  });
63
- }
61
+ };
64
62
  const transform = useMemo(() => Number(-(page * scrollBy * computedValues.itemWidth + computedValues.gap * page * scrollBy)), [computedValues.gap, computedValues.itemWidth, page, scrollBy]);
65
63
  useEffect(() => {
66
64
  hideNonVisibleItems();
@@ -117,8 +115,21 @@ export function ItemProvider({ items, showItems, scrollBy, slideCallback, transi
117
115
  onMouseMove: handleDragMove,
118
116
  }
119
117
  : {};
120
- return (_jsx("div", { ref: containerRef, className: styles.itemProvider, "data-pointers": !drag.pointers || undefined, "data-swipe": swipe || undefined, style: Object.assign({}, (Boolean(gap) ? { '--gap': gap } : {})), children: _jsx("div", Object.assign({}, swipeProps, { className: styles.itemTracker, "data-test-id": TEST_IDS.trackLine, style: {
118
+ const handleSlideClick = useCallback(e => {
119
+ var _a, _b;
120
+ const slideRect = e.currentTarget.getBoundingClientRect();
121
+ const containerRect = (_a = containerRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
122
+ const containerViewport = (_b = containerRect === null || containerRect === void 0 ? void 0 : containerRect.right) !== null && _b !== void 0 ? _b : 0;
123
+ const slidePositionDelta = containerViewport - slideRect.right;
124
+ const minPos = Math.min(slidePositionDelta, slideRect.x);
125
+ if (minPos < 0) {
126
+ slideCallback(slidePositionDelta);
127
+ }
128
+ }, [slideCallback]);
129
+ return (_jsx("div", { ref: containerRef, className: styles.itemProvider, "data-pointers": !drag.pointers || undefined, "data-swipe": swipe || undefined, "data-gap": gap, style: Object.assign({}, (Boolean(gap) ? { '--gap': gap } : {})), children: _jsx("div", Object.assign({}, swipeProps, { className: styles.itemTracker, "data-test-id": TEST_IDS.trackLine, style: {
121
130
  transform: `translateX(${transform - drag.drag}px)`,
122
131
  transition: `transform ${transition}s ease 0s`,
123
- }, ref: itemsTrackerRef, children: items.map((item, i) => (_jsx("div", { style: { width: computedValues.itemWidth }, className: styles.itemContainer, role: 'group', "data-test-id": TEST_IDS.trackItem, children: item }, i))) })) }));
132
+ }, ref: itemsTrackerRef, children: items.map((item, i) => (
133
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
134
+ _jsx("div", { style: { width: computedValues.itemWidth }, className: styles.itemContainer, role: 'group', "data-test-id": TEST_IDS.trackItem, onClick: handleSlideClick, children: item }, i))) })) }));
124
135
  }
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.2.21-preview-e5174ad1.0",
7
+ "version": "0.2.22-preview-71543426.0",
8
8
  "sideEffects": [
9
9
  "*.css",
10
10
  "*.woff",
@@ -34,12 +34,12 @@
34
34
  "license": "Apache-2.0",
35
35
  "scripts": {},
36
36
  "dependencies": {
37
- "@snack-uikit/icons": "0.22.2-preview-e5174ad1.0",
38
- "@snack-uikit/pagination": "0.7.2-preview-e5174ad1.0",
39
- "@snack-uikit/utils": "3.4.1-preview-e5174ad1.0",
37
+ "@snack-uikit/icons": "0.22.2-preview-71543426.0",
38
+ "@snack-uikit/pagination": "0.7.2-preview-71543426.0",
39
+ "@snack-uikit/utils": "3.4.1-preview-71543426.0",
40
40
  "classnames": "2.3.2",
41
41
  "lodash.debounce": "4.0.8",
42
42
  "uncontrollable": "8.0.4"
43
43
  },
44
- "gitHead": "3e1b0165a7ffe4fec49e268ad4c171ec97385243"
44
+ "gitHead": "3102614275e261c8f41db0f6c00a1f6b6276b2a9"
45
45
  }
@@ -15,9 +15,7 @@ export const Control = forwardRef<HTMLButtonElement, ControlProps>(
15
15
  <button
16
16
  ref={ref}
17
17
  className={styles.control}
18
- onClick={() => {
19
- onClick?.();
20
- }}
18
+ onClick={onClick}
21
19
  type='button'
22
20
  data-variant={variant}
23
21
  {...extractSupportProps(rest)}
@@ -1,5 +1,15 @@
1
1
  import debounce from 'lodash.debounce';
2
- import { MouseEvent, ReactElement, TouchEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import {
3
+ MouseEvent,
4
+ MouseEventHandler,
5
+ ReactElement,
6
+ TouchEvent,
7
+ useCallback,
8
+ useEffect,
9
+ useMemo,
10
+ useRef,
11
+ useState,
12
+ } from 'react';
3
13
 
4
14
  import { TEST_IDS } from '../../testIds';
5
15
  import { getPageX } from './helpers';
@@ -73,30 +83,28 @@ export function ItemProvider({
73
83
 
74
84
  const itemsTrackerRef = useRef<HTMLDivElement>(null);
75
85
 
76
- function hideNonVisibleItems() {
77
- itemsTrackerRef.current?.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach(function (slide) {
86
+ const hideNonVisibleItems = () => {
87
+ itemsTrackerRef.current?.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach(slide => {
78
88
  slide.setAttribute('aria-hidden', '0');
79
89
 
80
- slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(function (focusableElement) {
90
+ slide.querySelectorAll('a, button, select, input, textarea, [tabindex="0"]').forEach(focusableElement => {
81
91
  focusableElement.setAttribute('tabindex', '-5');
82
92
  focusableElement.classList.add(styles.hiddenItem);
83
93
  });
84
94
  });
85
- }
95
+ };
86
96
 
87
- function showVisibleItems(slide: number, page: number, show: number) {
97
+ const showVisibleItems = (slide: number, page: number, show: number) => {
88
98
  itemsTrackerRef.current?.querySelectorAll(`[data-test-id=${TEST_IDS.trackItem}]`).forEach((item, i) => {
89
99
  if (i >= page * slide && i < page * slide + Math.trunc(show)) {
90
100
  item.removeAttribute('aria-hidden');
91
- item
92
- .querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]')
93
- .forEach(function (focusableElement) {
94
- focusableElement.setAttribute('tabindex', '0');
95
- focusableElement.classList.remove(styles.hiddenItem);
96
- });
101
+ item.querySelectorAll('a, button, select, input, textarea, [tabindex="-5"]').forEach(focusableElement => {
102
+ focusableElement.setAttribute('tabindex', '0');
103
+ focusableElement.classList.remove(styles.hiddenItem);
104
+ });
97
105
  }
98
106
  });
99
- }
107
+ };
100
108
 
101
109
  const transform = useMemo(
102
110
  () => Number(-(page * scrollBy * computedValues.itemWidth + computedValues.gap * page * scrollBy)),
@@ -130,9 +138,11 @@ export function ItemProvider({
130
138
 
131
139
  const handleDragFinish = (e: MouseEvent | TouchEvent) => {
132
140
  e.persist();
141
+
133
142
  if (drag.finished) {
134
143
  return;
135
144
  }
145
+
136
146
  if (Math.abs(drag.drag) < swipeActivateLength) {
137
147
  return setDrag({
138
148
  initial: transform,
@@ -178,12 +188,28 @@ export function ItemProvider({
178
188
  }
179
189
  : {};
180
190
 
191
+ const handleSlideClick: MouseEventHandler = useCallback(
192
+ e => {
193
+ const slideRect = e.currentTarget.getBoundingClientRect();
194
+ const containerRect = containerRef.current?.getBoundingClientRect();
195
+ const containerViewport = containerRect?.right ?? 0;
196
+ const slidePositionDelta = containerViewport - slideRect.right;
197
+ const minPos = Math.min(slidePositionDelta, slideRect.x);
198
+
199
+ if (minPos < 0) {
200
+ slideCallback(slidePositionDelta);
201
+ }
202
+ },
203
+ [slideCallback],
204
+ );
205
+
181
206
  return (
182
207
  <div
183
208
  ref={containerRef}
184
209
  className={styles.itemProvider}
185
210
  data-pointers={!drag.pointers || undefined}
186
211
  data-swipe={swipe || undefined}
212
+ data-gap={gap}
187
213
  style={{
188
214
  ...(Boolean(gap) ? { '--gap': gap } : {}),
189
215
  }}
@@ -199,12 +225,14 @@ export function ItemProvider({
199
225
  ref={itemsTrackerRef}
200
226
  >
201
227
  {items.map((item, i) => (
228
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
202
229
  <div
203
230
  key={i}
204
231
  style={{ width: computedValues.itemWidth }}
205
232
  className={styles.itemContainer}
206
233
  role='group'
207
234
  data-test-id={TEST_IDS.trackItem}
235
+ onClick={handleSlideClick}
208
236
  >
209
237
  {item}
210
238
  </div>
@@ -39,4 +39,4 @@
39
39
  * {
40
40
  pointer-events: none;
41
41
  }
42
- }
42
+ }