@purpurds/tabs 8.5.0 → 8.5.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@purpurds/tabs",
3
- "version": "8.5.0",
3
+ "version": "8.5.2",
4
4
  "license": "AGPL-3.0-only",
5
5
  "main": "./dist/tabs.cjs.js",
6
6
  "types": "./dist/tabs.d.ts",
@@ -17,10 +17,10 @@
17
17
  "dependencies": {
18
18
  "@radix-ui/react-tabs": "~1.1.3",
19
19
  "classnames": "~2.5.0",
20
- "@purpurds/icon": "8.5.0",
21
- "@purpurds/common-types": "8.5.0",
22
- "@purpurds/tokens": "8.5.0",
23
- "@purpurds/paragraph": "8.5.0"
20
+ "@purpurds/common-types": "8.5.2",
21
+ "@purpurds/icon": "8.5.2",
22
+ "@purpurds/paragraph": "8.5.2",
23
+ "@purpurds/tokens": "8.5.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@storybook/react-vite": "^9.0.18",
@@ -40,10 +40,10 @@
40
40
  "typescript": "^5.6.3",
41
41
  "vite": "^6.2.1",
42
42
  "vitest": "^3.1.2",
43
- "@purpurds/icon": "8.5.0",
44
- "@purpurds/paragraph": "8.5.0",
43
+ "@purpurds/button": "8.5.2",
45
44
  "@purpurds/component-rig": "1.0.0",
46
- "@purpurds/button": "8.5.0"
45
+ "@purpurds/icon": "8.5.2",
46
+ "@purpurds/paragraph": "8.5.2"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "@types/react": "^18 || ^19",
@@ -7,7 +7,7 @@
7
7
  display: flex;
8
8
  align-items: center;
9
9
  justify-content: center;
10
- width: 100%;
10
+ width: auto;
11
11
  padding: calc(var(--purpur-spacing-100) + var(--purpur-spacing-25)) var(--purpur-spacing-200);
12
12
  border: 0;
13
13
  border-radius: var(--purpur-border-radius-sm) var(--purpur-border-radius-sm) 0 0;
@@ -33,7 +33,8 @@
33
33
  content: "";
34
34
  position: absolute;
35
35
  inset: calc(-1 * var(--purpur-border-width-xs));
36
- border: var(--purpur-border-width-sm) solid var(--purpur-color-border-interactive-subtle-hover);
36
+ border: var(--purpur-border-width-sm) solid
37
+ var(--purpur-color-border-interactive-subtle-hover);
37
38
  border-radius: var(--purpur-border-radius-xs);
38
39
  box-sizing: border-box;
39
40
  opacity: 0;
@@ -86,13 +87,13 @@
86
87
  right: 0;
87
88
  }
88
89
 
89
- &--scroll-end {
90
+ &--scroll-start {
90
91
  #{$root}__scroll-button--left {
91
92
  display: flex;
92
93
  }
93
94
  }
94
95
 
95
- &--scroll-start {
96
+ &--scroll-end {
96
97
  #{$root}__scroll-button--right {
97
98
  display: flex;
98
99
  }
package/src/tabs.tsx CHANGED
@@ -205,46 +205,37 @@ export const Tabs: TabsCmp<TabsProps> = ({
205
205
  }, [activeIndex, fullWidth, tabContentChildren.length, variant]); // eslint-disable-line react-hooks/exhaustive-deps
206
206
 
207
207
  useEffect(() => {
208
- const onIntersection = (entries: IntersectionObserverEntry[]): void => {
209
- const allEntriesVisible =
210
- entries.every((entry) => entry.isIntersecting) &&
211
- entries.length === tabContentChildren.length;
208
+ const root = tabList.current;
209
+ if (!root) return;
212
210
 
213
- if (allEntriesVisible) {
211
+ const updateScrollState = () => {
212
+ const { scrollLeft, scrollWidth, clientWidth } = root;
213
+
214
+ const canScroll = scrollWidth > clientWidth;
215
+ const atStart = scrollLeft <= 1;
216
+ const atEnd = scrollLeft + clientWidth >= scrollWidth - 1;
217
+
218
+ if (!canScroll) {
214
219
  setScrollClasses({});
215
220
  return;
216
221
  }
217
222
 
218
- entries.forEach((entry) => {
219
- const entryIndex = Number(entry.target.getAttribute("data-index"));
220
- const isStartEntry = entryIndex === 0;
221
- const isLastEntry = entryIndex === tabContentChildren.length - 1;
222
-
223
- setScrollClasses((currentScrollClasses) => ({
224
- ...currentScrollClasses,
225
- ...(isStartEntry && {
226
- [`${rootClassName}__wrapper--scroll-end`]: !entry.isIntersecting,
227
- }),
228
- ...(isLastEntry && {
229
- [`${rootClassName}__wrapper--scroll-start`]: !entry.isIntersecting,
230
- }),
231
- }));
223
+ setScrollClasses({
224
+ [`${rootClassName}__wrapper--scroll-start`]: !atStart,
225
+ [`${rootClassName}__wrapper--scroll-end`]: !atEnd,
232
226
  });
233
227
  };
234
228
 
235
- const observer = new IntersectionObserver(onIntersection, {
236
- threshold: [0.99],
237
- root: tabList.current,
238
- });
239
-
240
- const currentTabChildren = tabChildren.current;
229
+ updateScrollState();
241
230
 
242
- currentTabChildren.forEach((el) => observer.observe(el));
231
+ root.addEventListener("scroll", updateScrollState, { passive: true });
232
+ window.addEventListener("resize", updateScrollState);
243
233
 
244
234
  return () => {
245
- currentTabChildren.forEach((el) => observer.unobserve(el));
235
+ root.removeEventListener("scroll", updateScrollState);
236
+ window.removeEventListener("resize", updateScrollState);
246
237
  };
247
- }, [tabContentChildren.length]);
238
+ }, []);
248
239
 
249
240
  return (
250
241
  <Root