@coinbase/cds-mobile 9.14.0 → 9.16.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dts/accordion/Accordion.d.ts +11 -1
  3. package/dts/accordion/Accordion.d.ts.map +1 -1
  4. package/dts/accordion/AccordionHeader.d.ts +33 -5
  5. package/dts/accordion/AccordionHeader.d.ts.map +1 -1
  6. package/dts/accordion/AccordionItem.d.ts +25 -17
  7. package/dts/accordion/AccordionItem.d.ts.map +1 -1
  8. package/dts/accordion/AccordionPanel.d.ts +6 -2
  9. package/dts/accordion/AccordionPanel.d.ts.map +1 -1
  10. package/dts/alpha/select-chip/SelectChip.d.ts +6 -12
  11. package/dts/alpha/select-chip/SelectChip.d.ts.map +1 -1
  12. package/dts/alpha/select-chip/SelectChipControl.d.ts +49 -5
  13. package/dts/alpha/select-chip/SelectChipControl.d.ts.map +1 -1
  14. package/dts/alpha/select-chip/index.d.ts +1 -1
  15. package/dts/alpha/select-chip/index.d.ts.map +1 -1
  16. package/dts/alpha/tabbed-chips/TabbedChips.d.ts +4 -1
  17. package/dts/alpha/tabbed-chips/TabbedChips.d.ts.map +1 -1
  18. package/dts/chips/Chip.d.ts +3 -0
  19. package/dts/chips/Chip.d.ts.map +1 -1
  20. package/dts/chips/ChipProps.d.ts +35 -2
  21. package/dts/chips/ChipProps.d.ts.map +1 -1
  22. package/dts/chips/InputChip.d.ts.map +1 -1
  23. package/dts/chips/MediaChip.d.ts +3 -0
  24. package/dts/chips/MediaChip.d.ts.map +1 -1
  25. package/dts/collapsible/Collapsible.d.ts +5 -2
  26. package/dts/collapsible/Collapsible.d.ts.map +1 -1
  27. package/dts/controls/Switch.d.ts +10 -1
  28. package/dts/controls/Switch.d.ts.map +1 -1
  29. package/dts/core/componentConfig.d.ts +2 -0
  30. package/dts/core/componentConfig.d.ts.map +1 -1
  31. package/dts/tabs/SegmentedTabs.d.ts +10 -2
  32. package/dts/tabs/SegmentedTabs.d.ts.map +1 -1
  33. package/esm/accordion/Accordion.js +6 -2
  34. package/esm/accordion/AccordionHeader.js +49 -15
  35. package/esm/accordion/AccordionItem.js +40 -6
  36. package/esm/accordion/AccordionPanel.js +3 -1
  37. package/esm/alpha/select-chip/SelectChip.js +73 -21
  38. package/esm/alpha/select-chip/SelectChipControl.js +39 -10
  39. package/esm/alpha/select-chip/__stories__/AlphaSelectChip.stories.js +4 -4
  40. package/esm/alpha/select-chip/index.js +1 -1
  41. package/esm/alpha/tabbed-chips/TabbedChips.js +2 -2
  42. package/esm/chips/Chip.js +16 -7
  43. package/esm/chips/InputChip.js +24 -6
  44. package/esm/chips/__stories__/Chip.stories.js +2 -2
  45. package/esm/chips/__stories__/MediaChip.stories.js +2 -2
  46. package/esm/collapsible/Collapsible.js +4 -2
  47. package/esm/controls/Switch.js +25 -4
  48. package/esm/controls/__stories__/Switch.stories.js +26 -1
  49. package/esm/tabs/SegmentedTabs.js +24 -5
  50. package/package.json +3 -3
@@ -4,7 +4,15 @@ import { type TabsBaseProps, type TabsProps } from './Tabs';
4
4
  export type SegmentedTabsBaseProps<TabId extends string = string> = Partial<
5
5
  Pick<TabsBaseProps<TabId>, 'TabComponent' | 'TabsActiveIndicatorComponent'>
6
6
  > &
7
- Omit<TabsBaseProps<TabId>, 'TabComponent' | 'TabsActiveIndicatorComponent' | 'styles'>;
7
+ Omit<TabsBaseProps<TabId>, 'TabComponent' | 'TabsActiveIndicatorComponent' | 'styles'> & {
8
+ /**
9
+ * When true, each tab stretches to an equal share of the component width and the component
10
+ * fills its parent. This is the correct way to achieve distributed tab layout — do NOT use
11
+ * `justifyContent` for this, as it breaks the active indicator position calculation.
12
+ * @default false
13
+ */
14
+ equalWidth?: boolean;
15
+ };
8
16
  export type SegmentedTabsProps<TabId extends string = string> = SegmentedTabsBaseProps<TabId> &
9
17
  Partial<Pick<TabsProps<TabId>, 'TabComponent' | 'TabsActiveIndicatorComponent'>> &
10
18
  Omit<TabsProps<TabId>, 'TabComponent' | 'TabsActiveIndicatorComponent' | 'styles'> & {
@@ -12,7 +20,7 @@ export type SegmentedTabsProps<TabId extends string = string> = SegmentedTabsBas
12
20
  styles?: {
13
21
  /** Root container element */
14
22
  root?: StyleProp<ViewStyle>;
15
- /** Container element wrapping each tab */
23
+ /** Wrapper View around each tab — use `{ flex: 1 }` for equal-width distribution */
16
24
  tabContainer?: StyleProp<ViewStyle>;
17
25
  /** Tab element */
18
26
  tab?: StyleProp<ViewStyle>;
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedTabs.d.ts","sourceRoot":"","sources":["../../src/tabs/SegmentedTabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAe,MAAM,OAAO,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM/D,OAAO,EAAQ,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAKlE,MAAM,MAAM,sBAAsB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,OAAO,CACzE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,CAAC,CAC5E,GACC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,GAAG,QAAQ,CAAC,CAAC;AAEzF,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,sBAAsB,CAAC,KAAK,CAAC,GAC3F,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,CAAC,CAAC,GAChF,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,GAAG,QAAQ,CAAC,GAAG;IACnF,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,6BAA6B;QAC7B,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5B,0CAA0C;QAC1C,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,kBAAkB;QAClB,GAAG,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAC3B,+BAA+B;QAC/B,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;KACxC,CAAC;CACH,CAAC;AAEJ,KAAK,eAAe,GAAG,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACnD,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;CAAE,KAClE,KAAK,CAAC,YAAY,CAAC;AAkCxB,eAAO,MAAM,aAAa,EAA6B,eAAe,CAAC"}
1
+ {"version":3,"file":"SegmentedTabs.d.ts","sourceRoot":"","sources":["../../src/tabs/SegmentedTabs.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAM/D,OAAO,EAAQ,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAQlE,MAAM,MAAM,sBAAsB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,OAAO,CACzE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,CAAC,CAC5E,GACC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,GAAG,QAAQ,CAAC,GAAG;IACvF;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEJ,MAAM,MAAM,kBAAkB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,sBAAsB,CAAC,KAAK,CAAC,GAC3F,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,CAAC,CAAC,GAChF,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,cAAc,GAAG,8BAA8B,GAAG,QAAQ,CAAC,GAAG;IACnF,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,6BAA6B;QAC7B,IAAI,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5B,oFAAoF;QACpF,YAAY,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,kBAAkB;QAClB,GAAG,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAC3B,+BAA+B;QAC/B,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;KACxC,CAAC;CACH,CAAC;AAEJ,KAAK,eAAe,GAAG,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACnD,KAAK,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG;IAAE,GAAG,CAAC,EAAE,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;CAAE,KAClE,KAAK,CAAC,YAAY,CAAC;AAiDxB,eAAO,MAAM,aAAa,EAA6B,eAAe,CAAC"}
@@ -14,7 +14,9 @@ export const Accordion = /*#__PURE__*/memo(_props => {
14
14
  onChange,
15
15
  setActiveKey,
16
16
  testID,
17
- style
17
+ style,
18
+ borderRadius,
19
+ showItemSeparators = true
18
20
  } = mergedProps;
19
21
  return /*#__PURE__*/_jsx(AccordionProvider, {
20
22
  activeKey: activeKey,
@@ -22,10 +24,12 @@ export const Accordion = /*#__PURE__*/memo(_props => {
22
24
  onChange: onChange,
23
25
  setActiveKey: setActiveKey,
24
26
  children: /*#__PURE__*/_jsx(VStack, {
27
+ borderRadius: borderRadius,
28
+ overflow: borderRadius !== undefined ? 'hidden' : undefined,
25
29
  style: style,
26
30
  testID: testID,
27
31
  width: "100%",
28
- children: join(Children.toArray(children), /*#__PURE__*/_jsx(Divider, {}))
32
+ children: showItemSeparators ? join(Children.toArray(children), /*#__PURE__*/_jsx(Divider, {})) : children
29
33
  })
30
34
  });
31
35
  });
@@ -1,5 +1,5 @@
1
1
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
- import React, { memo, useCallback } from 'react';
2
+ import React, { memo, useCallback, useMemo } from 'react';
3
3
  import { useAccordionContext } from '@coinbase/cds-common/accordion/AccordionProvider';
4
4
  import { accordionIconHiddenRotate, accordionIconVisibleRotate } from '@coinbase/cds-common/animation/accordion';
5
5
  import { listHeight } from '@coinbase/cds-common/tokens/cell';
@@ -11,20 +11,28 @@ import { AnimatedCaret } from '../motion/AnimatedCaret';
11
11
  import { Pressable } from '../system/Pressable';
12
12
  import { Text } from '../typography/Text';
13
13
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- export const AccordionMedia = /*#__PURE__*/memo(_ref => {
14
+ const compactPaddingProps = paddingProps => {
15
+ const entries = Object.entries(paddingProps).filter(_ref => {
16
+ let [, value] = _ref;
17
+ return value !== undefined;
18
+ });
19
+ if (entries.length === 0) return undefined;
20
+ return Object.fromEntries(entries);
21
+ };
22
+ export const AccordionMedia = /*#__PURE__*/memo(_ref2 => {
15
23
  let {
16
24
  media
17
- } = _ref;
25
+ } = _ref2;
18
26
  return /*#__PURE__*/_jsx(Box, {
19
27
  children: media
20
28
  });
21
29
  });
22
- export const AccordionTitle = /*#__PURE__*/memo(_ref2 => {
30
+ export const AccordionTitle = /*#__PURE__*/memo(_ref3 => {
23
31
  let {
24
32
  title,
25
33
  subtitle,
26
34
  tertiaryTitle
27
- } = _ref2;
35
+ } = _ref3;
28
36
  return /*#__PURE__*/_jsx(Box, {
29
37
  flexGrow: 1,
30
38
  flexShrink: 1,
@@ -45,14 +53,16 @@ export const AccordionTitle = /*#__PURE__*/memo(_ref2 => {
45
53
  })
46
54
  });
47
55
  });
48
- export const AccordionIcon = /*#__PURE__*/memo(_ref3 => {
56
+ export const AccordionIcon = /*#__PURE__*/memo(_ref4 => {
49
57
  let {
50
- collapsed
51
- } = _ref3;
58
+ collapsed,
59
+ caretSize = 's'
60
+ } = _ref4;
52
61
  return /*#__PURE__*/_jsx(Box, {
53
62
  justifyContent: "flex-end",
54
63
  children: /*#__PURE__*/_jsx(AnimatedCaret, {
55
- rotate: collapsed ? accordionIconHiddenRotate : accordionIconVisibleRotate
64
+ rotate: collapsed ? accordionIconHiddenRotate : accordionIconVisibleRotate,
65
+ size: caretSize
56
66
  })
57
67
  });
58
68
  });
@@ -60,7 +70,7 @@ export const AccordionIcon = /*#__PURE__*/memo(_ref3 => {
60
70
  * Renders a Pressable element to use as the header to an AccordionItem.
61
71
  * Composes an Accordion Media, Title, and Icon.
62
72
  */
63
- export const AccordionHeader = /*#__PURE__*/memo(_ref4 => {
73
+ export const AccordionHeader = /*#__PURE__*/memo(_ref5 => {
64
74
  let {
65
75
  ref: forwardedRef,
66
76
  itemKey,
@@ -70,13 +80,35 @@ export const AccordionHeader = /*#__PURE__*/memo(_ref4 => {
70
80
  onPress,
71
81
  media,
72
82
  collapsed,
73
- testID
74
- } = _ref4;
83
+ testID,
84
+ style,
85
+ background = 'bg',
86
+ caretSize,
87
+ padding,
88
+ paddingX,
89
+ paddingY,
90
+ paddingTop,
91
+ paddingBottom,
92
+ paddingStart,
93
+ paddingEnd
94
+ } = _ref5;
75
95
  const {
76
96
  setActiveKey,
77
97
  activeKey
78
98
  } = useAccordionContext();
79
- const spacing = useCellSpacing();
99
+ const outerSpacing = useMemo(() => compactPaddingProps({
100
+ padding,
101
+ paddingX,
102
+ paddingY,
103
+ paddingTop,
104
+ paddingBottom,
105
+ paddingStart,
106
+ paddingEnd
107
+ }), [padding, paddingX, paddingY, paddingTop, paddingBottom, paddingStart, paddingEnd]);
108
+ // Header padding follows the same outer spacing rules as Cell.
109
+ const spacing = useCellSpacing({
110
+ outerSpacing
111
+ });
80
112
  const accessibilityLabel = [title, subtitle, tertiaryTitle].filter(Boolean).join(', ');
81
113
  const handlePress = useCallback(() => {
82
114
  onPress == null || onPress(itemKey);
@@ -85,15 +117,16 @@ export const AccordionHeader = /*#__PURE__*/memo(_ref4 => {
85
117
  return /*#__PURE__*/_jsx(Pressable, {
86
118
  ref: forwardedRef,
87
119
  noScaleOnPress: true,
88
- transparentWhileInactive: true,
89
120
  accessibilityLabel: accessibilityLabel,
90
121
  accessibilityRole: "togglebutton",
91
122
  accessibilityState: {
92
123
  expanded: !collapsed
93
124
  },
94
- background: "bg",
125
+ background: background,
95
126
  onPress: handlePress,
127
+ style: style,
96
128
  testID: testID,
129
+ transparentWhileInactive: true,
97
130
  children: /*#__PURE__*/_jsxs(HStack, _extends({
98
131
  alignItems: "center",
99
132
  gap: 2,
@@ -107,6 +140,7 @@ export const AccordionHeader = /*#__PURE__*/memo(_ref4 => {
107
140
  tertiaryTitle: tertiaryTitle,
108
141
  title: title
109
142
  }), /*#__PURE__*/_jsx(AccordionIcon, {
143
+ caretSize: caretSize,
110
144
  collapsed: collapsed
111
145
  })]
112
146
  }))
@@ -1,6 +1,8 @@
1
1
  import React, { memo } from 'react';
2
2
  import { useAccordionContext } from '@coinbase/cds-common/accordion/AccordionProvider';
3
3
  import { accordionMinWidth } from '@coinbase/cds-common/tokens/accordion';
4
+ import { useComponentConfig } from '../hooks/useComponentConfig';
5
+ import { Divider } from '../layout/Divider';
4
6
  import { VStack } from '../layout/VStack';
5
7
  import { AccordionHeader } from './AccordionHeader';
6
8
  import { AccordionPanel } from './AccordionPanel';
@@ -10,8 +12,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
12
  * It composes together an AccordionHeader and a collapsible AccordionPanel.
11
13
  * Accepts a unique `itemKey` prop to uniquely identify one item from another within the same Accordion.
12
14
  */
13
- export const AccordionItem = /*#__PURE__*/memo(_ref => {
14
- let {
15
+ export const AccordionItem = /*#__PURE__*/memo(_props => {
16
+ const mergedProps = useComponentConfig('AccordionItem', _props);
17
+ const {
15
18
  itemKey,
16
19
  title,
17
20
  subtitle,
@@ -22,30 +25,61 @@ export const AccordionItem = /*#__PURE__*/memo(_ref => {
22
25
  testID,
23
26
  headerRef,
24
27
  panelRef,
25
- style
26
- } = _ref;
28
+ style,
29
+ styles,
30
+ showHeaderBorder = false,
31
+ background,
32
+ caretSize,
33
+ borderRadius,
34
+ padding,
35
+ paddingX,
36
+ paddingY,
37
+ paddingTop,
38
+ paddingBottom,
39
+ paddingStart,
40
+ paddingEnd
41
+ } = mergedProps;
27
42
  const {
28
43
  activeKey
29
44
  } = useAccordionContext();
30
45
  const collapsed = activeKey !== itemKey;
31
46
  return /*#__PURE__*/_jsxs(VStack, {
47
+ borderRadius: borderRadius,
32
48
  minWidth: accordionMinWidth,
33
- style: style,
49
+ overflow: borderRadius !== undefined ? 'hidden' : undefined,
50
+ style: [style, styles == null ? void 0 : styles.root],
34
51
  testID: testID,
52
+ width: "100%",
35
53
  children: [/*#__PURE__*/_jsx(AccordionHeader, {
36
54
  ref: headerRef,
55
+ background: background,
56
+ caretSize: caretSize,
37
57
  collapsed: collapsed,
38
58
  itemKey: itemKey,
39
59
  media: media,
40
60
  onPress: onPress,
61
+ padding: padding,
62
+ paddingBottom: paddingBottom,
63
+ paddingEnd: paddingEnd,
64
+ paddingStart: paddingStart,
65
+ paddingTop: paddingTop,
66
+ paddingX: paddingX,
67
+ paddingY: paddingY,
68
+ style: styles == null ? void 0 : styles.header,
41
69
  subtitle: subtitle,
42
70
  tertiaryTitle: tertiaryTitle,
43
71
  testID: testID && testID + "-header",
44
72
  title: title
45
- }), /*#__PURE__*/_jsx(AccordionPanel, {
73
+ }), showHeaderBorder ? /*#__PURE__*/_jsx(Divider, {
74
+ paddingEnd: paddingEnd,
75
+ paddingStart: paddingStart,
76
+ paddingX: paddingX,
77
+ testID: testID && testID + "-divider"
78
+ }) : null, /*#__PURE__*/_jsx(AccordionPanel, {
46
79
  ref: panelRef,
47
80
  collapsed: collapsed,
48
81
  itemKey: itemKey,
82
+ style: styles == null ? void 0 : styles.panel,
49
83
  testID: testID && testID + "-panel",
50
84
  children: children
51
85
  })]
@@ -13,12 +13,14 @@ export const AccordionPanel = /*#__PURE__*/memo(_ref => {
13
13
  ref: forwardedRef,
14
14
  children,
15
15
  collapsed = true,
16
- testID
16
+ testID,
17
+ style
17
18
  } = _ref;
18
19
  return /*#__PURE__*/_jsx(Collapsible, _extends({
19
20
  ref: forwardedRef,
20
21
  collapsed: collapsed,
21
22
  maxHeight: accordionVisibleMaxHeight,
23
+ style: style,
22
24
  testID: testID
23
25
  }, accordionSpacing, {
24
26
  children: children
@@ -1,12 +1,30 @@
1
1
  const _excluded = ["ref"],
2
- _excluded2 = ["invertColorScheme", "numberOfLines", "maxWidth", "displayValue", "size", "compact"];
3
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ _excluded2 = ["active", "invertColorScheme", "inverted", "value"],
3
+ _excluded3 = ["active", "activeBackground", "activeColor", "background", "color", "numberOfLines", "maxWidth", "displayValue", "size", "compact", "borderWidth", "borderColor", "bordered", "borderRadius", "invertColorScheme", "inverted"];
4
4
  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; }
5
- import React, { memo, useCallback } from 'react';
5
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
6
+ import React, { memo, useMemo } from 'react';
7
+ import { getSelectChipActive } from '@coinbase/cds-common/chips/getSelectChipActive';
6
8
  import { useComponentConfig } from '../../hooks/useComponentConfig';
7
9
  import { Select } from '../select/Select';
8
10
  import { SelectChipControl } from './SelectChipControl';
11
+
12
+ // TODO(CDS-2544): SelectChipBaseProps should also compose SelectBaseProps.
13
+ // https://linear.app/coinbase/issue/CDS-2544/selectchipbaseprops-should-compose-selectbaseprops
9
14
  import { jsx as _jsx } from "react/jsx-runtime";
15
+ /**
16
+ * Creates a wrapper component that injects chip-specific props into SelectChipControl.
17
+ * Select only forwards generic control props to `SelectControlComponent`; chip styling
18
+ * and `active` are owned by SelectChip and must be closed over here.
19
+ */
20
+ function createSelectChipControlWrapper(chipProps) {
21
+ return /*#__PURE__*/memo(controlProps => {
22
+ // Chip props are spread last so they win at runtime; the cast bridges overlapping keys
23
+ // (`size`, borders) where SelectControlProps and SelectChipBaseProps use different types.
24
+ return /*#__PURE__*/_jsx(SelectChipControl, _extends({}, _extends({}, controlProps, chipProps)));
25
+ });
26
+ }
27
+
10
28
  /**
11
29
  * Chip-styled Select control built on top of the Alpha Select.
12
30
  * Supports both single and multi selection via Select's `type` prop.
@@ -16,33 +34,67 @@ const SelectChipComponent = /*#__PURE__*/memo(_ref => {
16
34
  ref
17
35
  } = _ref,
18
36
  _props = _objectWithoutPropertiesLoose(_ref, _excluded);
19
- const mergedProps = useComponentConfig('SelectChip', _props);
37
+ // Resolve `active` from instance props before config merge so state-aware resolvers
38
+ // (active vs inactive border styling) see the final selection state. `value` and
39
+ // legacy invert props are pulled out with `active` and passed back explicitly because
40
+ // they feed that resolution and must remain available to the config resolver input.
20
41
  const {
42
+ active: activeProp,
21
43
  invertColorScheme,
44
+ inverted,
45
+ value
46
+ } = _props,
47
+ restProps = _objectWithoutPropertiesLoose(_props, _excluded2);
48
+ const resolvedActive = getSelectChipActive(activeProp, value, invertColorScheme, inverted);
49
+ const mergedProps = useComponentConfig('SelectChip', _extends({}, restProps, {
50
+ value,
51
+ active: resolvedActive,
52
+ invertColorScheme,
53
+ inverted
54
+ }));
55
+ // SelectChip composes Select + MediaChip; peel chip props off merged props so the rest
56
+ // can flow to `<Select>` without chip-only fields leaking into the select interface.
57
+ const {
58
+ active,
59
+ activeBackground,
60
+ activeColor,
61
+ background,
62
+ color,
22
63
  numberOfLines,
23
64
  maxWidth,
24
65
  displayValue,
25
66
  size,
26
- compact
67
+ compact,
68
+ borderWidth,
69
+ borderColor,
70
+ bordered,
71
+ borderRadius,
72
+ invertColorScheme: mergedInvertColorScheme,
73
+ inverted: mergedInverted
27
74
  } = mergedProps,
28
- props = _objectWithoutPropertiesLoose(mergedProps, _excluded2);
29
- // Select doesn't pass the chip-specific props (size/compact/displayValue/etc.) down to the
30
- // control, so they're injected here. They're listed AFTER the `controlProps` spread so the
31
- // chip-level values win — matching the web SelectChip wrapper.
32
- const SelectChipControlComponent = useCallback(controlProps => {
33
- return /*#__PURE__*/_jsx(SelectChipControl, _extends({}, controlProps, {
34
- compact: compact,
35
- displayValue: displayValue,
36
- invertColorScheme: invertColorScheme,
37
- maxWidth: maxWidth,
38
- numberOfLines: numberOfLines,
39
- size: size
40
- }));
41
- }, [displayValue, invertColorScheme, maxWidth, numberOfLines, size, compact]);
75
+ selectProps = _objectWithoutPropertiesLoose(mergedProps, _excluded3);
76
+ const WrappedSelectChipControl = useMemo(() => createSelectChipControlWrapper({
77
+ active,
78
+ activeBackground,
79
+ activeColor,
80
+ background,
81
+ color,
82
+ numberOfLines,
83
+ maxWidth,
84
+ displayValue,
85
+ size,
86
+ compact,
87
+ borderWidth,
88
+ borderColor,
89
+ bordered,
90
+ borderRadius,
91
+ invertColorScheme: mergedInvertColorScheme,
92
+ inverted: mergedInverted
93
+ }), [active, activeBackground, activeColor, background, color, displayValue, numberOfLines, maxWidth, size, compact, borderWidth, borderColor, bordered, borderRadius, mergedInvertColorScheme, mergedInverted]);
42
94
  return /*#__PURE__*/_jsx(Select, _extends({
43
95
  ref: ref,
44
- SelectControlComponent: SelectChipControlComponent
45
- }, props));
96
+ SelectControlComponent: WrappedSelectChipControl
97
+ }, selectProps));
46
98
  });
47
99
  SelectChipComponent.displayName = 'SelectChip';
48
100
  export const SelectChip = SelectChipComponent;
@@ -1,7 +1,19 @@
1
1
  import React, { memo, useMemo } from 'react';
2
+ import { getSelectChipHasValue } from '@coinbase/cds-common/chips/getSelectChipActive';
2
3
  import { MediaChip } from '../../chips/MediaChip';
3
4
  import { AnimatedCaret } from '../../motion/AnimatedCaret';
4
5
  import { isSelectOptionGroup } from '../select/types';
6
+
7
+ /**
8
+ * Chip props accepted by {@link SelectChipControl} and forwarded to {@link MediaChip}.
9
+ * Includes selection state, layout, borders, and `displayValue` for the control label.
10
+ */
11
+
12
+ /**
13
+ * SelectControlProps fields superseded by {@link SelectChipControlChipProps}.
14
+ * Omit is required: intersection would merge overlapping keys (e.g. `size` as SelectSize &
15
+ * ChipSize, `background` as Box vs chip tokens) instead of replacing select-scale definitions.
16
+ */
5
17
  import { jsx as _jsx } from "react/jsx-runtime";
6
18
  const SelectChipControlComponent = /*#__PURE__*/memo(_ref => {
7
19
  let {
@@ -22,13 +34,23 @@ const SelectChipControlComponent = /*#__PURE__*/memo(_ref => {
22
34
  label,
23
35
  compact,
24
36
  size,
37
+ active,
38
+ activeBackground,
39
+ activeColor,
40
+ background,
41
+ color,
25
42
  invertColorScheme,
43
+ inverted,
26
44
  numberOfLines,
27
45
  maxWidth,
28
- displayValue
46
+ displayValue,
47
+ borderWidth,
48
+ borderColor,
49
+ bordered,
50
+ borderRadius
29
51
  } = _ref;
30
52
  const isMultiSelect = type === 'multi';
31
- const hasValue = value !== null && !(Array.isArray(value) && value.length === 0);
53
+ const hasValue = getSelectChipHasValue(value);
32
54
 
33
55
  // Map of options to their values
34
56
  // If multiple options share the same value, the first occurrence wins (matches native HTML select behavior)
@@ -83,30 +105,34 @@ const SelectChipControlComponent = /*#__PURE__*/memo(_ref => {
83
105
  const opt = optionsMap.get(value);
84
106
  return (_ref6 = (_ref7 = (_ref8 = (_opt$label2 = opt == null ? void 0 : opt.label) != null ? _opt$label2 : opt == null ? void 0 : opt.description) != null ? _ref8 : opt == null ? void 0 : opt.value) != null ? _ref7 : placeholder) != null ? _ref6 : null;
85
107
  }, [hasValue, label, placeholder, displayValue, isMultiSelect, optionsMap, value, maxSelectedOptionsToShow, hiddenSelectedOptionsLabel]);
108
+ const resolvedColor = active && activeColor !== undefined ? activeColor : color;
86
109
  const endNode = useMemo(() => {
110
+ // Match Chip's label color. `fg` still inverts with the chip when active uses theme inversion.
87
111
  return customEndNode != null ? customEndNode : /*#__PURE__*/_jsx(AnimatedCaret, {
88
112
  active: true,
89
- color: hasValue ? 'fgInverse' : 'fg',
113
+ color: resolvedColor != null ? resolvedColor : 'fg',
90
114
  rotate: open ? 0 : 180,
91
115
  size: "xs"
92
116
  });
93
- }, [customEndNode, open, hasValue]);
94
- const color = useMemo(() => {
95
- return hasValue ? 'fgInverse' : 'fg';
96
- }, [hasValue]);
97
- const background = useMemo(() => {
98
- return hasValue ? 'bgInverse' : 'bgSecondary';
99
- }, [hasValue]);
117
+ }, [customEndNode, open, resolvedColor]);
100
118
  return /*#__PURE__*/_jsx(MediaChip, {
101
119
  ref: ref,
102
120
  accessibilityHint: accessibilityHint,
103
121
  accessibilityLabel: accessibilityLabel,
122
+ active: active,
123
+ activeBackground: activeBackground,
124
+ activeColor: activeColor,
104
125
  background: background,
126
+ bordered: bordered,
127
+ borderColor: borderColor,
128
+ borderRadius: borderRadius,
129
+ borderWidth: borderWidth,
105
130
  color: color,
106
131
  compact: compact,
107
132
  disabled: disabled,
108
133
  end: endNode,
109
134
  invertColorScheme: invertColorScheme,
135
+ inverted: inverted,
110
136
  maxWidth: maxWidth,
111
137
  numberOfLines: numberOfLines,
112
138
  onPress: () => setOpen(s => !s),
@@ -115,4 +141,7 @@ const SelectChipControlComponent = /*#__PURE__*/memo(_ref => {
115
141
  children: labelContent
116
142
  });
117
143
  });
144
+ SelectChipControlComponent.displayName = 'SelectChipControl';
145
+
146
+ /** Generic memo components need an explicit cast for the public polymorphic signature. */
118
147
  export const SelectChipControl = SelectChipControlComponent;
@@ -217,7 +217,7 @@ export const MultiSelectWithAssets = () => {
217
217
  value: value
218
218
  });
219
219
  };
220
- export const InvertColorScheme = () => {
220
+ export const Active = () => {
221
221
  const exampleOptions = [{
222
222
  value: '1',
223
223
  label: 'Option 1'
@@ -231,7 +231,7 @@ export const InvertColorScheme = () => {
231
231
  borderRadius: 200,
232
232
  padding: 2,
233
233
  children: /*#__PURE__*/_jsx(SelectChip, {
234
- invertColorScheme: true,
234
+ active: true,
235
235
  onChange: setValue,
236
236
  options: exampleOptions,
237
237
  placeholder: "Choose an option",
@@ -587,8 +587,8 @@ const SelectChipScreen = () => {
587
587
  title: "Multi-Select with Assets",
588
588
  children: /*#__PURE__*/_jsx(MultiSelectWithAssets, {})
589
589
  }), /*#__PURE__*/_jsx(Example, {
590
- title: "Invert Color Scheme",
591
- children: /*#__PURE__*/_jsx(InvertColorScheme, {})
590
+ title: "Active",
591
+ children: /*#__PURE__*/_jsx(Active, {})
592
592
  }), /*#__PURE__*/_jsx(Example, {
593
593
  title: "Empty Options",
594
594
  children: /*#__PURE__*/_jsx(EmptyOptions, {})
@@ -1,2 +1,2 @@
1
1
  export * from './SelectChip';
2
- export * from './SelectChipControl';
2
+ export { SelectChipControl } from './SelectChipControl';
@@ -1,4 +1,4 @@
1
- const _excluded = ["label", "id", "activeBackground", "activeColor", "color"],
1
+ const _excluded = ["label", "id", "Component", "activeBackground", "activeColor", "color"],
2
2
  _excluded2 = ["ref"],
3
3
  _excluded3 = ["tabs", "activeTab", "testID", "TabComponent", "onChange", "width", "gap", "compact", "size", "styles", "autoScrollOffset"];
4
4
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
@@ -32,9 +32,9 @@ const DefaultTabComponent = _ref => {
32
32
  accessibilityState: {
33
33
  selected: isActive
34
34
  },
35
+ active: isActive && !activeBackground,
35
36
  background: isActive && activeBackground ? activeBackground : undefined,
36
37
  color: isActive && activeColor ? activeColor : color,
37
- invertColorScheme: isActive && !activeBackground,
38
38
  onPress: handlePress
39
39
  }, tabProps, {
40
40
  children: label
package/esm/chips/Chip.js CHANGED
@@ -1,8 +1,8 @@
1
1
  const _excluded = ["ref"],
2
- _excluded2 = ["alignSelf", "children", "start", "end", "invertColorScheme", "inverted", "maxWidth", "compact", "size", "gap", "paddingX", "paddingY", "alignItems", "justifyContent", "padding", "paddingTop", "paddingBottom", "paddingStart", "paddingEnd", "numberOfLines", "testID", "contentStyle", "borderRadius", "background", "style", "styles", "onPress", "color", "font"];
2
+ _excluded2 = ["alignSelf", "children", "start", "end", "active", "activeBackground", "activeColor", "invertColorScheme", "inverted", "maxWidth", "compact", "size", "gap", "paddingX", "paddingY", "alignItems", "justifyContent", "padding", "paddingTop", "paddingBottom", "paddingStart", "paddingEnd", "numberOfLines", "testID", "contentStyle", "borderRadius", "background", "style", "styles", "onPress", "color", "font"];
3
3
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4
4
  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; }
5
- import React, { Fragment, memo } from 'react';
5
+ import React, { Fragment, memo, useMemo } from 'react';
6
6
  import { chipMaxWidth } from '@coinbase/cds-common/tokens/chip';
7
7
  import { useComponentConfig } from '../hooks/useComponentConfig';
8
8
  import { Box } from '../layout/Box';
@@ -44,6 +44,9 @@ export const Chip = /*#__PURE__*/memo(function Chip(_ref) {
44
44
  children,
45
45
  start,
46
46
  end,
47
+ active = false,
48
+ activeBackground,
49
+ activeColor,
47
50
  invertColorScheme,
48
51
  inverted,
49
52
  maxWidth = chipMaxWidth,
@@ -69,14 +72,20 @@ export const Chip = /*#__PURE__*/memo(function Chip(_ref) {
69
72
  font = sizeConfig.font
70
73
  } = mergedProps,
71
74
  props = _objectWithoutPropertiesLoose(mergedProps, _excluded2);
72
- const WrapperComponent = (invertColorScheme != null ? invertColorScheme : inverted) ? InvertedThemeProvider : Fragment;
75
+ const hasActiveColorOverrides = activeBackground !== undefined || activeColor !== undefined;
76
+ const activeUsesThemeInversion = active && !hasActiveColorOverrides;
77
+ const shouldInvert = Boolean(invertColorScheme != null ? invertColorScheme : inverted) || activeUsesThemeInversion;
78
+ const WrapperComponent = shouldInvert ? InvertedThemeProvider : Fragment;
79
+ const resolvedBackground = active && activeBackground !== undefined ? activeBackground : background;
80
+ const resolvedColor = active && activeColor !== undefined ? activeColor : color;
81
+ const containerStyle = useMemo(() => [style, styles == null ? void 0 : styles.root], [style, styles == null ? void 0 : styles.root]);
73
82
  const containerProps = {
74
83
  testID,
75
- background,
84
+ background: resolvedBackground,
76
85
  borderRadius,
77
86
  ref,
78
87
  alignSelf,
79
- style: [style, styles == null ? void 0 : styles.root]
88
+ style: containerStyle
80
89
  };
81
90
  const content = /*#__PURE__*/_jsxs(HStack, {
82
91
  alignItems: alignItems,
@@ -93,13 +102,13 @@ export const Chip = /*#__PURE__*/memo(function Chip(_ref) {
93
102
  style: [contentStyle, styles == null ? void 0 : styles.content],
94
103
  testID: testID ? testID + "-content" : undefined,
95
104
  children: [start, typeof children === 'string' ? /*#__PURE__*/_jsx(Text, {
96
- color: color,
105
+ color: resolvedColor,
97
106
  flexShrink: 1,
98
107
  font: font,
99
108
  numberOfLines: numberOfLines,
100
109
  children: children
101
110
  }) : children ? /*#__PURE__*/_jsx(Box, {
102
- color: color,
111
+ color: resolvedColor,
103
112
  flexShrink: 1,
104
113
  children: children
105
114
  }) : null, end]