@coinbase/cds-web 8.18.0 → 8.19.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
@@ -8,6 +8,17 @@ All notable changes to this project will be documented in this file.
8
8
 
9
9
  <!-- template-start -->
10
10
 
11
+ ## 8.19.0 (10/29/2025 PST)
12
+
13
+ #### 🚀 Updates
14
+
15
+ - Added MediaChip component. [[#125](https://github.com/coinbase/cds/pull/125)]
16
+ - Simplified Chip construct. [[#125](https://github.com/coinbase/cds/pull/125)]
17
+
18
+ #### 🐞 Fixes
19
+
20
+ - Fixed TabbedChip auto-scrolling issue. [[#125](https://github.com/coinbase/cds/pull/125)]
21
+
11
22
  ## 8.18.0 (10/29/2025 PST)
12
23
 
13
24
  #### 🚀 Updates
@@ -1,10 +1,12 @@
1
- import React from 'react';
2
1
  /**
3
2
  * This is a basic Chip component used to create all Chip components.
3
+ * When onClick is provided, the ref will be typed as HTMLButtonElement.
4
+ * When onClick is not provided, the ref will be typed as HTMLDivElement.
4
5
  */
5
- export declare const Chip: React.MemoExoticComponent<
6
- React.ForwardRefExoticComponent<
7
- Omit<import('./ChipProps').ChipBaseProps, 'ref'> & React.RefAttributes<HTMLButtonElement>
6
+ export declare const Chip: import('react').MemoExoticComponent<
7
+ import('react').ForwardRefExoticComponent<
8
+ Omit<import('./ChipProps').ChipBaseProps, 'ref'> &
9
+ import('react').RefAttributes<HTMLButtonElement | HTMLDivElement>
8
10
  >
9
11
  >;
10
12
  //# sourceMappingURL=Chip.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../../src/chips/Chip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAsB1D;;GAEG;AACH,eAAO,MAAM,IAAI,uJAsEhB,CAAC"}
1
+ {"version":3,"file":"Chip.d.ts","sourceRoot":"","sources":["../../src/chips/Chip.tsx"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,eAAO,MAAM,IAAI,sMA2HhB,CAAC"}
@@ -17,7 +17,7 @@ export type ChipBaseProps = SharedProps &
17
17
  > &
18
18
  Pick<SharedAccessibilityProps, 'accessibilityLabel'> & {
19
19
  /** ReactNode placed in the center of the Chip */
20
- children: React.ReactNode;
20
+ children?: React.ReactNode;
21
21
  /** ReactNode placed before the value */
22
22
  start?: React.ReactNode;
23
23
  /** ReactNode placed after the value */
@@ -40,8 +40,21 @@ export type ChipBaseProps = SharedProps &
40
40
  * @default 1
41
41
  */
42
42
  numberOfLines?: number;
43
- /** Apply styles to Chip content. */
43
+ /**
44
+ * @deprecated Use `styles.content` instead.
45
+ * Apply styles to Chip content.
46
+ */
44
47
  contentStyle?: React.CSSProperties;
48
+ /** Apply styles to the container and content. */
49
+ styles?: {
50
+ root?: React.CSSProperties;
51
+ content?: React.CSSProperties;
52
+ };
53
+ /** Class names for the components */
54
+ classNames?: {
55
+ root?: string;
56
+ content?: string;
57
+ };
45
58
  };
46
59
  export type ChipProps = ChipBaseProps;
47
60
  export type InputChipProps = {
@@ -1 +1 @@
1
- {"version":3,"file":"ChipProps.d.ts","sourceRoot":"","sources":["../../src/chips/ChipProps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,wBAAwB,EACxB,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEnF,MAAM,MAAM,aAAa,GAAG,WAAW,GACrC,IAAI,CACF,cAAc,CAAC,uBAAuB,CAAC,EACrC,UAAU,GACV,SAAS,GACT,OAAO,GACP,eAAe,GACf,mBAAmB,GACnB,yBAAyB,GACzB,UAAU,CACb,GACD,IAAI,CAAC,wBAAwB,EAAE,oBAAoB,CAAC,GAAG;IACrD,iDAAiD;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,uCAAuC;IACvC,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,YAAY,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CACpC,CAAC;AAEJ,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG;IAC3B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC,CAAC"}
1
+ {"version":3,"file":"ChipProps.d.ts","sourceRoot":"","sources":["../../src/chips/ChipProps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,wBAAwB,EACxB,WAAW,EACZ,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,uBAAuB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEnF,MAAM,MAAM,aAAa,GAAG,WAAW,GACrC,IAAI,CACF,cAAc,CAAC,uBAAuB,CAAC,EACrC,UAAU,GACV,SAAS,GACT,OAAO,GACP,eAAe,GACf,mBAAmB,GACnB,yBAAyB,GACzB,UAAU,CACb,GACD,IAAI,CAAC,wBAAwB,EAAE,oBAAoB,CAAC,GAAG;IACrD,iDAAiD;IACjD,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,uCAAuC;IACvC,GAAG,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,0CAA0C;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IACnC,iDAAiD;IACjD,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;QAC3B,OAAO,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;KAC/B,CAAC;IACF,qCAAqC;IACrC,UAAU,CAAC,EAAE;QACX,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,CAAC;AAEJ,MAAM,MAAM,SAAS,GAAG,aAAa,CAAC;AAEtC,MAAM,MAAM,cAAc,GAAG;IAC3B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"InputChip.d.ts","sourceRoot":"","sources":["../../src/chips/InputChip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAKhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,eAAO,MAAM,SAAS,kIA6BrB,CAAC"}
1
+ {"version":3,"file":"InputChip.d.ts","sourceRoot":"","sources":["../../src/chips/InputChip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAIhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,eAAO,MAAM,SAAS,kIA8BrB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { ChipProps } from './ChipProps';
2
+ export type MediaChipProps = ChipProps;
3
+ export declare const MediaChip: import('react').MemoExoticComponent<
4
+ import('react').ForwardRefExoticComponent<
5
+ Omit<import('./ChipProps').ChipBaseProps, 'ref'> &
6
+ import('react').RefAttributes<HTMLButtonElement | HTMLDivElement>
7
+ >
8
+ >;
9
+ //# sourceMappingURL=MediaChip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MediaChip.d.ts","sourceRoot":"","sources":["../../src/chips/MediaChip.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG,SAAS,CAAC;AAEvC,eAAO,MAAM,SAAS,sMAqDrB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SelectChip.d.ts","sourceRoot":"","sources":["../../src/chips/SelectChip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAKjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,eAAO,MAAM,2BAA2B,gBAAgB,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG;IAC5B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,gBAAgB,GAAG,SAAS,CAAC,GACpF,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,YAAY,GAAG,aAAa,GAAG,OAAO,CAAC,GAC1E,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;AAE/C,eAAO,MAAM,UAAU,yHAoFtB,CAAC"}
1
+ {"version":3,"file":"SelectChip.d.ts","sourceRoot":"","sources":["../../src/chips/SelectChip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,eAAO,MAAM,2BAA2B,gBAAgB,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG;IAC5B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,gBAAgB,GAAG,SAAS,CAAC,GACpF,IAAI,CAAC,eAAe,EAAE,UAAU,GAAG,YAAY,GAAG,aAAa,GAAG,OAAO,CAAC,GAC1E,IAAI,CAAC,aAAa,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;AAE/C,eAAO,MAAM,UAAU,yHAoFtB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TabbedChips.d.ts","sourceRoot":"","sources":["../../src/chips/TabbedChips.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAC;AAMxF,OAAO,EAAE,KAAK,YAAY,EAAU,MAAM,WAAW,CAAC;AACtD,OAAO,EAAU,KAAK,sBAAsB,EAAQ,MAAM,SAAS,CAAC;AAmCpE,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,YAAY,GACxE,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAE7C,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAElF,KAAK,aAAa,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAC7C,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;CAAE,KACnE,KAAK,CAAC,YAAY,CAAC;AAwHxB,eAAO,MAAM,WAAW,EAA2B,aAAa,CAAC"}
1
+ {"version":3,"file":"TabbedChips.d.ts","sourceRoot":"","sources":["../../src/chips/TabbedChips.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2D,MAAM,OAAO,CAAC;AAMhF,OAAO,EAAE,KAAK,YAAY,EAAU,MAAM,WAAW,CAAC;AACtD,OAAO,EAAU,KAAK,sBAAsB,EAAQ,MAAM,SAAS,CAAC;AAiCpE,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,YAAY,GACxE,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAE7C,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,oBAAoB,CAAC,CAAC,CAAC,CAAC;AAElF,KAAK,aAAa,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EAC7C,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;CAAE,KACnE,KAAK,CAAC,YAAY,CAAC;AAkGxB,eAAO,MAAM,WAAW,EAA2B,aAAa,CAAC"}
@@ -1,6 +1,7 @@
1
1
  export * from './Chip';
2
2
  export * from './ChipProps';
3
3
  export * from './InputChip';
4
+ export * from './MediaChip';
4
5
  export * from './SelectChip';
5
6
  export * from './TabbedChips';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chips/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/chips/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
@@ -0,0 +1,28 @@
1
+ export type UseHorizontalScrollToTargetOptions = {
2
+ scrollThrottleWaitTime?: number;
3
+ activeTarget?: HTMLElement | null;
4
+ scrollPadding?: number;
5
+ overflowThreshold?: number;
6
+ };
7
+ /**
8
+ * A hook for managing horizontal scrolling with overflow detection.
9
+ * Useful for horizontally scrollable content that needs to show overflow indicators.
10
+ * Optionally handles scrolling to an active target element.
11
+ *
12
+ * @param scrollThrottleWaitTime - Throttle time for scroll events (default: 200ms)
13
+ * @param activeTarget - The active element to scroll to when it's offscreen
14
+ * @param scrollPadding - Padding to add when scrolling to position elements (useful for paddles/overlays, default: 0)
15
+ * @param overflowThreshold - Threshold for detecting if content is offscreen (default: 5px)
16
+ */
17
+ export declare const useHorizontalScrollToTarget: ({
18
+ scrollThrottleWaitTime,
19
+ activeTarget,
20
+ scrollPadding,
21
+ overflowThreshold,
22
+ }?: UseHorizontalScrollToTargetOptions) => {
23
+ scrollRef: import('react').RefObject<HTMLDivElement>;
24
+ isScrollContentOffscreenLeft: boolean;
25
+ isScrollContentOffscreenRight: boolean;
26
+ handleScroll: () => void;
27
+ };
28
+ //# sourceMappingURL=useHorizontalScrollToTarget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHorizontalScrollToTarget.d.ts","sourceRoot":"","sources":["../../src/hooks/useHorizontalScrollToTarget.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kCAAkC,GAAG;IAC/C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,YAAY,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,GAAI,8EAKzC,kCAAuC;;;;;CAkEzC,CAAC"}
@@ -29,6 +29,8 @@ export type TabsProps<T extends string = string> = {
29
29
  TabsActiveIndicatorComponent: TabsActiveIndicatorComponent;
30
30
  /** Background color passed to the TabsActiveIndicatorComponent. */
31
31
  activeBackground?: ThemeVars.Color;
32
+ /** Optional callback to receive the active tab element. */
33
+ onActiveTabElementChange?: (element: HTMLElement | null) => void;
32
34
  } & Omit<TabsOptions<T>, 'tabs'> &
33
35
  Omit<HStackProps<HStackDefaultElement>, 'onChange' | 'ref'>;
34
36
  type TabsFC = <T extends string = string>(
@@ -1 +1 @@
1
- {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../src/tabs/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAIjE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,QAAQ,EAEd,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAe,KAAK,WAAW,EAAmB,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAO,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAU,KAAK,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAkBvF,eAAO,MAAM,oBAAoB;;;;;;CAMF,CAAC;AAEhC,MAAM,MAAM,wBAAwB,GAAG;IACrC,aAAa,EAAE,IAAI,CAAC;CACrB,GAAG,QAAQ,CAAC,iBAAiB,CAAC,GAC7B,WAAW,CAAC;AAEd,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAE5E,MAAM,MAAM,4BAA4B,GAAG,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC;AAE9E,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IACjD,2FAA2F;IAC3F,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;QAAE,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC,EAAE,CAAC;IACxD,gDAAgD;IAChD,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,iEAAiE;IACjE,4BAA4B,EAAE,4BAA4B,CAAC;IAC3D,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC;CACpC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,GAC9B,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC;AAE9D,KAAK,MAAM,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACtC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;CAAE,KAC5D,KAAK,CAAC,YAAY,CAAC;AAoFxB,eAAO,MAAM,IAAI,EAAoB,MAAM,CAAC;AAE5C,eAAO,MAAM,mBAAmB,GAAI,uCAIjC,wBAAwB,mDAgB1B,CAAC"}
1
+ {"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../src/tabs/Tabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAEtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAIjE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,QAAQ,EAEd,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAe,KAAK,IAAI,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAe,KAAK,WAAW,EAAmB,MAAM,eAAe,CAAC;AAE/E,OAAO,EAAO,KAAK,iBAAiB,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAU,KAAK,oBAAoB,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAkBvF,eAAO,MAAM,oBAAoB;;;;;;CAMF,CAAC;AAEhC,MAAM,MAAM,wBAAwB,GAAG;IACrC,aAAa,EAAE,IAAI,CAAC;CACrB,GAAG,QAAQ,CAAC,iBAAiB,CAAC,GAC7B,WAAW,CAAC;AAEd,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAE5E,MAAM,MAAM,4BAA4B,GAAG,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC;AAE9E,MAAM,MAAM,SAAS,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IACjD,2FAA2F;IAC3F,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG;QAAE,SAAS,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC,EAAE,CAAC;IACxD,gDAAgD;IAChD,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,iEAAiE;IACjE,4BAA4B,EAAE,4BAA4B,CAAC;IAC3D,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,SAAS,CAAC,KAAK,CAAC;IACnC,2DAA2D;IAC3D,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CAClE,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,GAC9B,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC,CAAC;AAE9D,KAAK,MAAM,GAAG,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,EACtC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,CAAA;CAAE,KAC5D,KAAK,CAAC,YAAY,CAAC;AA0FxB,eAAO,MAAM,IAAI,EAAoB,MAAM,CAAC;AAE5C,eAAO,MAAM,mBAAmB,GAAI,uCAIjC,wBAAwB,mDAgB1B,CAAC"}
@@ -1,2 +1 @@
1
- @layer cds{.contentCss-chdcix9{-webkit-transition:background 150ms cubic-bezier(0.6,0,0.15,1);transition:background 150ms cubic-bezier(0.6,0,0.15,1);}
2
- .containerCss-c1792b5d{max-height:-webkit-fit-content;max-height:-moz-fit-content;max-height:fit-content;min-width:min(fit-content,200px);}}
1
+ @layer cds{.transitionCss-thdcix9{-webkit-transition:background 150ms cubic-bezier(0.6,0,0.15,1);transition:background 150ms cubic-bezier(0.6,0,0.15,1);}}
package/esm/chips/Chip.js CHANGED
@@ -1,4 +1,4 @@
1
- const _excluded = ["children", "start", "end", "maxWidth", "inverted", "compact", "numberOfLines", "onClick", "testID", "accessibilityLabel", "contentStyle", "borderRadius", "background"];
1
+ const _excluded = ["as", "alignItems", "width", "height", "compact", "gap", "start", "end", "paddingX", "paddingY", "padding", "paddingTop", "paddingBottom", "paddingStart", "paddingEnd", "justifyContent", "children", "maxWidth", "inverted", "numberOfLines", "testID", "contentStyle", "borderRadius", "background", "style", "className", "styles", "classNames", "font", "onClick"];
2
2
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
@@ -6,74 +6,105 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
6
6
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
7
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
8
8
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
9
- import React, { forwardRef, Fragment, memo } from 'react';
9
+ import { forwardRef, Fragment, memo, useMemo } from 'react';
10
10
  import { curves, durations } from '@coinbase/cds-common/motion/tokens';
11
11
  import { chipMaxWidth } from '@coinbase/cds-common/tokens/chip';
12
+ import { cx } from '../cx';
12
13
  import { Box, HStack } from '../layout';
13
- import { Pressable } from '../system/Pressable';
14
- import { InvertedThemeProvider } from '../system/ThemeProvider';
14
+ import { InvertedThemeProvider, Pressable } from '../system';
15
15
  import { Text } from '../typography/Text';
16
16
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
- const contentCss = "contentCss-chdcix9";
18
-
19
- // styles that clamp the width and height of the Chip container
20
- const containerCss = "containerCss-c1792b5d";
17
+ const transitionCss = "transitionCss-thdcix9";
21
18
 
22
19
  /**
23
20
  * This is a basic Chip component used to create all Chip components.
21
+ * When onClick is provided, the ref will be typed as HTMLButtonElement.
22
+ * When onClick is not provided, the ref will be typed as HTMLDivElement.
24
23
  */
25
24
  export const Chip = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Chip(_ref, ref) {
26
25
  let {
27
- children,
26
+ as,
27
+ alignItems = 'center',
28
+ width = 'fit-content',
29
+ height = 'fit-content',
30
+ compact,
31
+ gap = 1,
28
32
  start,
29
33
  end,
34
+ paddingX = compact ? 1.5 : 2,
35
+ paddingY = compact ? 0.5 : 1,
36
+ padding,
37
+ paddingTop,
38
+ paddingBottom,
39
+ paddingStart,
40
+ paddingEnd,
41
+ justifyContent,
42
+ children,
30
43
  maxWidth = chipMaxWidth,
31
44
  inverted,
32
- compact,
33
45
  numberOfLines = 1,
34
- onClick,
35
46
  testID,
36
- accessibilityLabel,
37
47
  contentStyle,
38
48
  borderRadius = 700,
39
- background = 'bgSecondary'
49
+ background = 'bgSecondary',
50
+ style,
51
+ className,
52
+ styles,
53
+ classNames,
54
+ font = compact ? 'label1' : 'headline',
55
+ onClick
40
56
  } = _ref,
41
57
  props = _objectWithoutProperties(_ref, _excluded);
42
58
  const WrapperComponent = inverted ? InvertedThemeProvider : Fragment;
43
- const content = /*#__PURE__*/_jsxs(HStack, {
44
- alignItems: "center",
45
- background: onClick ? undefined : background,
46
- borderRadius: borderRadius,
47
- className: contentCss,
48
- gap: 1,
49
- maxWidth: maxWidth,
50
- paddingX: compact ? 1 : 2,
51
- paddingY: compact ? 0.5 : 1,
52
- style: contentStyle,
53
- testID: !onClick ? testID : undefined,
54
- children: [start, typeof children === 'string' ? /*#__PURE__*/_jsx(Text, {
55
- font: "headline",
56
- numberOfLines: numberOfLines,
57
- children: children
58
- }) : children, end]
59
- });
60
-
61
- // The wrapping Box ensures that the layout is consistent since the child pressable and provider child elements conditionally render
62
- return /*#__PURE__*/_jsx(Box, {
63
- className: containerCss,
64
- display: "block",
65
- children: /*#__PURE__*/_jsx(WrapperComponent, {
66
- children: onClick ? /*#__PURE__*/_jsx(Pressable, _objectSpread(_objectSpread({
67
- ref: ref,
68
- accessibilityLabel: accessibilityLabel,
69
- background: background,
70
- borderRadius: borderRadius,
71
- onClick: onClick,
72
- testID: testID
73
- }, props), {}, {
74
- children: content
75
- })) : content
76
- })
77
- });
59
+ const containerProps = {
60
+ background,
61
+ borderRadius,
62
+ className: cx(transitionCss, className, classNames === null || classNames === void 0 ? void 0 : classNames.root),
63
+ style: _objectSpread(_objectSpread({}, style), styles === null || styles === void 0 ? void 0 : styles.root),
64
+ testID,
65
+ width,
66
+ height,
67
+ maxWidth
68
+ };
69
+ const content = useMemo(() => {
70
+ return /*#__PURE__*/_jsxs(HStack, {
71
+ alignItems: alignItems,
72
+ className: classNames === null || classNames === void 0 ? void 0 : classNames.content,
73
+ gap: gap,
74
+ justifyContent: justifyContent,
75
+ maxWidth: maxWidth,
76
+ padding: padding,
77
+ paddingBottom: paddingBottom,
78
+ paddingEnd: paddingEnd,
79
+ paddingStart: paddingStart,
80
+ paddingTop: paddingTop,
81
+ paddingX: paddingX,
82
+ paddingY: paddingY,
83
+ style: _objectSpread(_objectSpread({}, contentStyle), styles === null || styles === void 0 ? void 0 : styles.content),
84
+ children: [start, typeof children === 'string' ? /*#__PURE__*/_jsx(Text, {
85
+ flexShrink: 1,
86
+ font: font,
87
+ numberOfLines: numberOfLines,
88
+ children: children
89
+ }) : children ? /*#__PURE__*/_jsx(Box, {
90
+ flexShrink: 1,
91
+ children: children
92
+ }) : null, end]
93
+ });
94
+ }, [alignItems, classNames === null || classNames === void 0 ? void 0 : classNames.content, gap, justifyContent, maxWidth, padding, paddingBottom, paddingEnd, paddingStart, paddingTop, paddingX, paddingY, contentStyle, styles === null || styles === void 0 ? void 0 : styles.content, start, children, font, numberOfLines, end]);
95
+ return /*#__PURE__*/_jsx(WrapperComponent, _objectSpread(_objectSpread({}, inverted ? {
96
+ display: 'content'
97
+ } : {}), {}, {
98
+ children: onClick ? /*#__PURE__*/_jsx(Pressable, _objectSpread(_objectSpread(_objectSpread({
99
+ ref: ref,
100
+ onClick: onClick
101
+ }, containerProps), props), {}, {
102
+ children: content
103
+ })) : /*#__PURE__*/_jsx(HStack, _objectSpread(_objectSpread(_objectSpread({
104
+ ref: ref
105
+ }, containerProps), props), {}, {
106
+ children: content
107
+ }))
108
+ }));
78
109
  }));
79
110
  import "./Chip.css";
@@ -8,7 +8,7 @@ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i
8
8
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
9
9
  import React, { forwardRef, memo } from 'react';
10
10
  import { Icon } from '../icons/Icon';
11
- import { Chip } from './Chip';
11
+ import { MediaChip } from './MediaChip';
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  export const InputChip = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function InputChip(_ref, ref) {
14
14
  let {
@@ -17,14 +17,15 @@ export const InputChip = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Inpu
17
17
  testID = 'input-chip'
18
18
  } = _ref,
19
19
  props = _objectWithoutProperties(_ref, _excluded);
20
- return /*#__PURE__*/_jsx(Chip, _objectSpread(_objectSpread({
20
+ return /*#__PURE__*/_jsx(MediaChip, _objectSpread(_objectSpread({
21
21
  ref: ref,
22
22
  inverted: true,
23
23
  accessibilityLabel: accessibilityLabel,
24
24
  end: /*#__PURE__*/_jsx(Icon, {
25
+ active: true,
25
26
  color: "fg",
26
27
  name: "close",
27
- size: "s",
28
+ size: "xs",
28
29
  testID: testID ? "".concat(testID, "-close-icon") : 'input-chip-close-icon'
29
30
  })
30
31
  }, props), {}, {
@@ -0,0 +1,53 @@
1
+ const _excluded = ["start", "children", "end", "compact", "padding", "paddingX", "paddingY", "paddingTop", "paddingBottom", "paddingStart", "paddingEnd"];
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
8
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
9
+ import { forwardRef, memo, useMemo } from 'react';
10
+ import { getMediaChipSpacingProps } from '@coinbase/cds-common/chips/getMediaChipSpacingProps';
11
+ import { Chip } from './Chip';
12
+ import { jsx as _jsx } from "react/jsx-runtime";
13
+ export const MediaChip = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function MediaChip(_ref, ref) {
14
+ let {
15
+ start,
16
+ children,
17
+ end,
18
+ compact,
19
+ padding,
20
+ paddingX,
21
+ paddingY,
22
+ paddingTop,
23
+ paddingBottom,
24
+ paddingStart,
25
+ paddingEnd
26
+ } = _ref,
27
+ props = _objectWithoutProperties(_ref, _excluded);
28
+ const spacingProps = useMemo(() => {
29
+ const defaults = getMediaChipSpacingProps({
30
+ compact: !!compact,
31
+ start: !!start,
32
+ end: !!end,
33
+ children: !!children
34
+ });
35
+ return {
36
+ padding: padding !== null && padding !== void 0 ? padding : defaults.padding,
37
+ paddingX: paddingX !== null && paddingX !== void 0 ? paddingX : defaults.paddingX,
38
+ paddingY: paddingY !== null && paddingY !== void 0 ? paddingY : defaults.paddingY,
39
+ paddingTop: paddingTop !== null && paddingTop !== void 0 ? paddingTop : defaults.paddingTop,
40
+ paddingBottom: paddingBottom !== null && paddingBottom !== void 0 ? paddingBottom : defaults.paddingBottom,
41
+ paddingStart: paddingStart !== null && paddingStart !== void 0 ? paddingStart : defaults.paddingStart,
42
+ paddingEnd: paddingEnd !== null && paddingEnd !== void 0 ? paddingEnd : defaults.paddingEnd
43
+ };
44
+ }, [compact, start, end, children, padding, paddingX, paddingY, paddingTop, paddingBottom, paddingStart, paddingEnd]);
45
+ return /*#__PURE__*/_jsx(Chip, _objectSpread(_objectSpread(_objectSpread({
46
+ ref: ref,
47
+ compact: compact,
48
+ end: end,
49
+ start: start
50
+ }, spacingProps), props), {}, {
51
+ children: children
52
+ }));
53
+ }));
@@ -11,7 +11,7 @@ import { useMergeRefs } from '@coinbase/cds-common/hooks/useMergeRefs';
11
11
  import { useRefocusTrigger } from '../controls/useRefocusTrigger';
12
12
  import { Dropdown } from '../dropdown';
13
13
  import { AnimatedCaret } from '../motion/AnimatedCaret';
14
- import { Chip } from './Chip';
14
+ import { MediaChip } from './MediaChip';
15
15
  import { jsx as _jsx } from "react/jsx-runtime";
16
16
  export const SELECT_CHIP_DEFAULT_TEST_ID = 'select-chip';
17
17
  export const SelectChip = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function SelectChip(_ref, ref) {
@@ -76,13 +76,15 @@ export const SelectChip = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Sel
76
76
  testID: "".concat(testID, "-dropdown"),
77
77
  value: value,
78
78
  width: width,
79
- children: /*#__PURE__*/_jsx(Chip, _objectSpread(_objectSpread({
79
+ children: /*#__PURE__*/_jsx(MediaChip, _objectSpread(_objectSpread({
80
80
  ref: mergedRefs,
81
81
  noScaleOnPress: true,
82
82
  disabled: disabled,
83
83
  end: end !== null && end !== void 0 ? end : /*#__PURE__*/_jsx(AnimatedCaret, {
84
+ active: true,
84
85
  color: "fg",
85
- rotate: isOpen ? 0 : 180
86
+ rotate: isOpen ? 0 : 180,
87
+ size: "xs"
86
88
  }),
87
89
  inverted: active,
88
90
  onClick: handleOpenMenu,
@@ -7,14 +7,13 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
7
7
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
8
8
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
9
9
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
10
- import React, { forwardRef, memo, useCallback, useMemo, useRef, useState } from 'react';
10
+ import React, { forwardRef, memo, useCallback, useMemo, useState } from 'react';
11
11
  import { useTabsContext } from '@coinbase/cds-common/tabs/TabsContext';
12
- import { useDimensions } from '../hooks/useDimensions';
12
+ import { useHorizontalScrollToTarget } from '../hooks/useHorizontalScrollToTarget';
13
13
  import { HStack } from '../layout';
14
14
  import { Paddle, Tabs } from '../tabs';
15
- import { Chip } from './Chip';
15
+ import { MediaChip } from './MediaChip';
16
16
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
- const scrollPadding = 5;
18
17
  const scrollContainerCss = "scrollContainerCss-s19l7spv";
19
18
  const TabComponent = _ref => {
20
19
  let {
@@ -28,7 +27,7 @@ const TabComponent = _ref => {
28
27
  } = useTabsContext();
29
28
  const isActive = useMemo(() => (activeTab === null || activeTab === void 0 ? void 0 : activeTab.id) === id, [activeTab, id]);
30
29
  const handleClick = useCallback(() => updateActiveTab(id), [id, updateActiveTab]);
31
- return /*#__PURE__*/_jsx(Chip, _objectSpread(_objectSpread({
30
+ return /*#__PURE__*/_jsx(MediaChip, _objectSpread(_objectSpread({
32
31
  "aria-selected": isActive,
33
32
  inverted: isActive,
34
33
  onClick: handleClick,
@@ -42,7 +41,6 @@ const TabsActiveIndicatorComponent = () => {
42
41
  return null;
43
42
  };
44
43
  const TabbedChipsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function TabbedChips(_ref2, ref) {
45
- var _scrollRef$current, _scrollRef$current2, _scrollRef$current3;
46
44
  let {
47
45
  tabs,
48
46
  value,
@@ -58,57 +56,38 @@ const TabbedChipsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function
58
56
  width = '100%'
59
57
  } = _ref2,
60
58
  props = _objectWithoutProperties(_ref2, _excluded2);
59
+ const [scrollTarget, setScrollTarget] = useState(null);
60
+ const {
61
+ scrollRef,
62
+ isScrollContentOffscreenLeft,
63
+ isScrollContentOffscreenRight,
64
+ handleScroll
65
+ } = useHorizontalScrollToTarget({
66
+ activeTarget: scrollTarget,
67
+ scrollPadding: 50
68
+ });
61
69
  const activeTab = useMemo(() => tabs.find(tab => tab.id === value), [tabs, value]);
62
- const scrollRef = useRef(null);
63
- const end = Number((_scrollRef$current = scrollRef.current) === null || _scrollRef$current === void 0 ? void 0 : _scrollRef$current.scrollWidth) - Number((_scrollRef$current2 = scrollRef.current) === null || _scrollRef$current2 === void 0 ? void 0 : _scrollRef$current2.offsetWidth);
64
- const canScrollRight = Number((_scrollRef$current3 = scrollRef.current) === null || _scrollRef$current3 === void 0 ? void 0 : _scrollRef$current3.scrollLeft) < end;
65
- const [showLeftPaddle, setShowLeftPaddle] = useState(false);
66
- const [showRightPaddle, setShowRightPaddle] = useState(canScrollRight);
67
70
  const handleChange = useCallback(tabValue => {
68
71
  if (tabValue) onChange === null || onChange === void 0 || onChange(tabValue.id);
69
72
  }, [onChange]);
70
- const handleOnScroll = useCallback(() => {
71
- var _scrollRef$current4;
72
- const scrollDistance = Number((_scrollRef$current4 = scrollRef.current) === null || _scrollRef$current4 === void 0 ? void 0 : _scrollRef$current4.scrollLeft);
73
- const endTrigger = end - scrollPadding;
74
- const startTrigger = scrollPadding;
75
-
76
- // Hide/show the left paddle
77
- if (scrollDistance > startTrigger) setShowLeftPaddle(true);else if (scrollDistance <= startTrigger) setShowLeftPaddle(false);
78
-
79
- // Hide/show the right paddle
80
- if (scrollDistance < endTrigger) setShowRightPaddle(true);else if (scrollDistance >= endTrigger) setShowRightPaddle(false);
81
- }, [end]);
82
- if (canScrollRight && !showRightPaddle) {
83
- var _scrollRef$current5;
84
- const scrollLeft = Number((_scrollRef$current5 = scrollRef.current) === null || _scrollRef$current5 === void 0 ? void 0 : _scrollRef$current5.scrollLeft);
85
- const endTrigger = end - scrollPadding;
86
- if (scrollLeft < endTrigger) {
87
- setShowRightPaddle(true);
88
- }
89
- }
90
- const {
91
- observe
92
- } = useDimensions({
93
- onResize: handleOnScroll
94
- });
95
73
  const handleScrollLeft = useCallback(() => {
96
- var _scrollRef$current6;
97
- scrollRef === null || scrollRef === void 0 || (_scrollRef$current6 = scrollRef.current) === null || _scrollRef$current6 === void 0 || _scrollRef$current6.scrollTo({
74
+ var _scrollRef$current;
75
+ scrollRef === null || scrollRef === void 0 || (_scrollRef$current = scrollRef.current) === null || _scrollRef$current === void 0 || _scrollRef$current.scrollTo({
98
76
  left: 0,
99
77
  behavior: 'smooth'
100
78
  });
101
79
  }, [scrollRef]);
102
80
  const handleScrollRight = useCallback(() => {
103
- var _scrollRef$current7;
104
- scrollRef === null || scrollRef === void 0 || (_scrollRef$current7 = scrollRef.current) === null || _scrollRef$current7 === void 0 || _scrollRef$current7.scrollTo({
105
- left: end,
81
+ if (!scrollRef.current) return;
82
+ const maxScroll = scrollRef.current.scrollWidth - scrollRef.current.clientWidth;
83
+ scrollRef.current.scrollTo({
84
+ left: maxScroll,
106
85
  behavior: 'smooth'
107
86
  });
108
- }, [end]);
87
+ }, [scrollRef]);
109
88
  return /*#__PURE__*/_jsxs(HStack, _objectSpread(_objectSpread({
110
- ref: observe,
111
89
  alignItems: "center",
90
+ overflow: "hidden",
112
91
  position: "relative",
113
92
  testID: testID,
114
93
  width: width
@@ -119,15 +98,13 @@ const TabbedChipsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function
119
98
  direction: "left",
120
99
  onClick: handleScrollLeft,
121
100
  paddleStyle: paddleStyle,
122
- show: showLeftPaddle,
101
+ show: isScrollContentOffscreenLeft,
123
102
  variant: "secondary"
124
103
  }), /*#__PURE__*/_jsx(HStack, {
125
104
  ref: scrollRef,
126
105
  alignItems: "center",
127
106
  className: scrollContainerCss,
128
- onScroll: handleOnScroll
129
- // TODO: this overflow styling is necessary for the Paddle feature but cuts off child Chips' focus ring
130
- ,
107
+ onScroll: handleScroll,
131
108
  overflow: "auto",
132
109
  children: /*#__PURE__*/_jsx(Tabs, _objectSpread({
133
110
  ref: ref,
@@ -136,6 +113,7 @@ const TabbedChipsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function
136
113
  activeTab: activeTab || null,
137
114
  background: background,
138
115
  gap: gap,
116
+ onActiveTabElementChange: setScrollTarget,
139
117
  onChange: handleChange,
140
118
  role: role,
141
119
  tabs: tabs
@@ -146,7 +124,7 @@ const TabbedChipsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function
146
124
  direction: "right",
147
125
  onClick: handleScrollRight,
148
126
  paddleStyle: paddleStyle,
149
- show: showRightPaddle,
127
+ show: isScrollContentOffscreenRight,
150
128
  variant: "secondary"
151
129
  })]
152
130
  }));
@@ -1,5 +1,6 @@
1
1
  export * from './Chip';
2
2
  export * from './ChipProps';
3
3
  export * from './InputChip';
4
+ export * from './MediaChip';
4
5
  export * from './SelectChip';
5
6
  export * from './TabbedChips';
@@ -0,0 +1,75 @@
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import throttle from 'lodash/throttle';
3
+ /**
4
+ * A hook for managing horizontal scrolling with overflow detection.
5
+ * Useful for horizontally scrollable content that needs to show overflow indicators.
6
+ * Optionally handles scrolling to an active target element.
7
+ *
8
+ * @param scrollThrottleWaitTime - Throttle time for scroll events (default: 200ms)
9
+ * @param activeTarget - The active element to scroll to when it's offscreen
10
+ * @param scrollPadding - Padding to add when scrolling to position elements (useful for paddles/overlays, default: 0)
11
+ * @param overflowThreshold - Threshold for detecting if content is offscreen (default: 5px)
12
+ */
13
+ export const useHorizontalScrollToTarget = function () {
14
+ let {
15
+ scrollThrottleWaitTime = 200,
16
+ activeTarget,
17
+ scrollPadding = 0,
18
+ overflowThreshold = 5
19
+ } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
20
+ const scrollRef = useRef(null);
21
+ const [isScrollContentOffscreenLeft, setIsScrollContentOffscreenLeft] = useState(false);
22
+ const [isScrollContentOffscreenRight, setIsScrollContentOffscreenRight] = useState(false);
23
+ const checkScrollOverflow = useCallback(() => {
24
+ if (!scrollRef.current) return;
25
+ const {
26
+ scrollLeft,
27
+ scrollWidth,
28
+ clientWidth
29
+ } = scrollRef.current;
30
+ const maxScroll = scrollWidth - clientWidth;
31
+ setIsScrollContentOffscreenLeft(scrollLeft > overflowThreshold);
32
+ setIsScrollContentOffscreenRight(scrollLeft < maxScroll - overflowThreshold);
33
+ }, [overflowThreshold]);
34
+ const throttledHandleScroll = useRef(throttle(checkScrollOverflow, scrollThrottleWaitTime)).current;
35
+ const handleScroll = useCallback(() => {
36
+ throttledHandleScroll();
37
+ }, [throttledHandleScroll]);
38
+
39
+ // Set up ResizeObserver and cleanup throttle on unmount
40
+ useEffect(() => {
41
+ throttledHandleScroll();
42
+ if (!scrollRef.current) return;
43
+ const resizeObserver = new ResizeObserver(throttledHandleScroll);
44
+ resizeObserver.observe(scrollRef.current);
45
+ return () => {
46
+ resizeObserver.disconnect();
47
+ throttledHandleScroll.cancel();
48
+ };
49
+ }, [throttledHandleScroll]);
50
+
51
+ // Scroll to active target when it changes
52
+ useEffect(() => {
53
+ if (!activeTarget || !scrollRef.current) return;
54
+ const container = scrollRef.current;
55
+ const targetX = activeTarget.offsetLeft;
56
+ const targetWidth = activeTarget.offsetWidth;
57
+ const scrollLeft = container.scrollLeft;
58
+ const containerWidth = container.clientWidth;
59
+ const isOffscreenLeft = targetX < scrollLeft + scrollPadding;
60
+ const isOffscreenRight = targetX + targetWidth > scrollLeft + containerWidth - scrollPadding;
61
+ if (isOffscreenLeft || isOffscreenRight) {
62
+ const scrollToX = isOffscreenLeft ? Math.max(0, targetX - scrollPadding) : targetX - scrollPadding;
63
+ container.scrollTo({
64
+ left: scrollToX,
65
+ behavior: 'smooth'
66
+ });
67
+ }
68
+ }, [activeTarget, scrollPadding]);
69
+ return {
70
+ scrollRef,
71
+ isScrollContentOffscreenLeft,
72
+ isScrollContentOffscreenRight,
73
+ handleScroll
74
+ };
75
+ };
package/esm/tabs/Tabs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const _excluded = ["id", "registerRef"],
2
- _excluded2 = ["tabs", "TabComponent", "TabsActiveIndicatorComponent", "activeBackground", "activeTab", "disabled", "onChange", "role", "position", "width", "style"],
2
+ _excluded2 = ["tabs", "TabComponent", "TabsActiveIndicatorComponent", "activeBackground", "activeTab", "onActiveTabElementChange", "disabled", "onChange", "role", "position", "width", "style"],
3
3
  _excluded3 = ["id", "Component", "disabled"],
4
4
  _excluded4 = ["activeTabRect", "position"];
5
5
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
@@ -47,6 +47,7 @@ const TabsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) =>
47
47
  TabsActiveIndicatorComponent,
48
48
  activeBackground,
49
49
  activeTab,
50
+ onActiveTabElementChange,
50
51
  disabled,
51
52
  onChange,
52
53
  role = 'tablist',
@@ -55,19 +56,19 @@ const TabsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) =>
55
56
  style
56
57
  } = _ref2,
57
58
  props = _objectWithoutProperties(_ref2, _excluded2);
58
- const refMap = useRefMap();
59
59
  const api = useTabs({
60
60
  tabs,
61
61
  activeTab,
62
62
  disabled,
63
63
  onChange
64
64
  });
65
- const activeTabRef = activeTab ? refMap.getRef(activeTab.id) : null;
66
65
  const [tabsContainerRef, tabsContainerRect] = useMeasure({
67
66
  debounce: 20
68
67
  });
69
68
  const mergedContainerRefs = useMergeRefs(ref, tabsContainerRef);
69
+ const refMap = useRefMap();
70
70
  const activeTabRect = useMemo(() => {
71
+ const activeTabRef = activeTab ? refMap.getRef(activeTab.id) : null;
71
72
  if (!activeTabRef || !tabsContainerRect.width) return defaultRect;
72
73
  return {
73
74
  x: activeTabRef.offsetLeft,
@@ -75,27 +76,16 @@ const TabsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) =>
75
76
  width: activeTabRef.offsetWidth,
76
77
  height: activeTabRef.offsetHeight
77
78
  };
78
- }, [activeTabRef, tabsContainerRect]);
79
- const tabComponents = useMemo(() => tabs.map(_ref3 => {
80
- let {
81
- id,
82
- Component: CustomTabComponent,
83
- disabled: tabDisabled
84
- } = _ref3,
85
- props = _objectWithoutProperties(_ref3, _excluded3);
86
- const RenderedTab = CustomTabComponent !== null && CustomTabComponent !== void 0 ? CustomTabComponent : TabComponent;
87
- return /*#__PURE__*/_jsx(TabContainer, {
88
- id: id,
89
- registerRef: refMap.registerRef,
90
- children: /*#__PURE__*/_jsx(RenderedTab, _objectSpread({
91
- disabled: tabDisabled,
92
- id: id
93
- }, props))
94
- }, id);
95
- }), [tabs, TabComponent, refMap.registerRef]);
79
+ }, [activeTab, refMap, tabsContainerRect.width]);
96
80
  const containerStyle = useMemo(() => _objectSpread({
97
81
  opacity: disabled ? accessibleOpacityDisabled : 1
98
82
  }, style), [disabled, style]);
83
+ const registerRef = useCallback((tabId, ref) => {
84
+ refMap.registerRef(tabId, ref);
85
+ if ((activeTab === null || activeTab === void 0 ? void 0 : activeTab.id) === tabId) {
86
+ onActiveTabElementChange === null || onActiveTabElementChange === void 0 || onActiveTabElementChange(ref);
87
+ }
88
+ }, [activeTab, onActiveTabElementChange, refMap]);
99
89
  return /*#__PURE__*/_jsx(HStack, _objectSpread(_objectSpread({
100
90
  ref: mergedContainerRefs,
101
91
  position: position,
@@ -108,7 +98,23 @@ const TabsComponent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) =>
108
98
  children: [/*#__PURE__*/_jsx(TabsActiveIndicatorComponent, {
109
99
  activeTabRect: activeTabRect,
110
100
  background: activeBackground
111
- }), tabComponents]
101
+ }), tabs.map(_ref3 => {
102
+ let {
103
+ id,
104
+ Component: CustomTabComponent,
105
+ disabled: tabDisabled
106
+ } = _ref3,
107
+ props = _objectWithoutProperties(_ref3, _excluded3);
108
+ const RenderedTab = CustomTabComponent !== null && CustomTabComponent !== void 0 ? CustomTabComponent : TabComponent;
109
+ return /*#__PURE__*/_jsx(TabContainer, {
110
+ id: id,
111
+ registerRef: registerRef,
112
+ children: /*#__PURE__*/_jsx(RenderedTab, _objectSpread({
113
+ disabled: tabDisabled,
114
+ id: id
115
+ }, props))
116
+ }, id);
117
+ })]
112
118
  })
113
119
  }));
114
120
  }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cds-web",
3
- "version": "8.18.0",
3
+ "version": "8.19.0",
4
4
  "description": "Coinbase Design System - Web",
5
5
  "repository": {
6
6
  "type": "git",
@@ -147,7 +147,7 @@
147
147
  "react-dom": "^18.3.1"
148
148
  },
149
149
  "dependencies": {
150
- "@coinbase/cds-common": "^8.18.0",
150
+ "@coinbase/cds-common": "^8.19.0",
151
151
  "@coinbase/cds-icons": "^5.5.0",
152
152
  "@coinbase/cds-illustrations": "^4.25.0",
153
153
  "@coinbase/cds-lottie-files": "^3.3.2",