Skip to content

Commit c959dbd

Browse files
authored
feat: tabs styles classnames (#438)
1 parent 9c0b3dc commit c959dbd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1365
-479
lines changed

.cursor/commands/component-styles.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ Review the component's JSX to identify elements that should be targetable via st
5555
| Selector | Description |
5656
| --------------------- | ----------------------------------------------------- |
5757
| `accessory` | Accessory element (e.g., chevron, icon at end) |
58+
| `activeIndicator` | Active indicator element (e.g., in tabs) |
5859
| `bottomContent` | Bottom section content |
5960
| `carousel` | Main carousel track element |
6061
| `carouselContainer` | Outer carousel container |
@@ -83,6 +84,7 @@ Review the component's JSX to identify elements that should be targetable via st
8384
| `step` | Individual step element (in steppers) |
8485
| `substepContainer` | Container for nested sub-steps |
8586
| `subtitle` | Subtitle text element |
87+
| `tab` | Tab element (in tabs) |
8688
| `tabs` | Tabs container element |
8789
| `thumb` | Draggable thumb element (in sliders) |
8890
| `title` | Title text element |

apps/docs/docs/components/charts/PeriodSelector/_mobileExamples.mdx

Lines changed: 51 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
## Basic Example
1+
PeriodSelector is a specialized [SegmentedTabs](/components/navigation/SegmentedTabs) optimized for chart time-period selection. It provides a transparent background, primary wash active state, and full-width layout by default.
2+
3+
## Basics
24

35
```jsx
4-
function BasicExample() {
6+
function Example() {
57
const tabs = [
68
{ id: '1H', label: '1H' },
79
{ id: '1D', label: '1D' },
@@ -17,12 +19,12 @@ function BasicExample() {
1719
}
1820
```
1921

20-
## Minimum Width
22+
## Sizing
2123

22-
You can set the `width` prop to `fit-content` to make the period selector as small as possible.
24+
Set `width` to `fit-content` to make the selector only as wide as its content, and use `gap` to control spacing between tabs.
2325

2426
```jsx
25-
function MinimumWidthExample() {
27+
function Example() {
2628
const tabs = [
2729
{ id: '1W', label: '1W' },
2830
{ id: '1M', label: '1M' },
@@ -43,16 +45,49 @@ function MinimumWidthExample() {
4345
}
4446
```
4547

46-
## Many Periods with Overflow
48+
## Live Indicator
49+
50+
Use the `LiveTabLabel` component (exported from PeriodSelector) to indicate a live data period. Pair it with a conditional `activeBackground` to visually differentiate the live state.
4751

4852
```jsx
49-
function ManyPeriodsExample() {
53+
function Example() {
5054
const tabs = useMemo(
5155
() => [
52-
{
53-
id: '1H',
54-
label: <LiveTabLabel />,
55-
},
56+
{ id: '1H', label: <LiveTabLabel /> },
57+
{ id: '1D', label: '1D' },
58+
{ id: '1W', label: '1W' },
59+
{ id: '1M', label: '1M' },
60+
{ id: '1Y', label: '1Y' },
61+
{ id: 'All', label: 'All' },
62+
],
63+
[],
64+
);
65+
66+
const [activeTab, setActiveTab] = useState(tabs[0]);
67+
const isLive = useMemo(() => activeTab?.id === '1H', [activeTab]);
68+
69+
const activeBackground = useMemo(() => (isLive ? 'bgNegativeWash' : 'bgPrimaryWash'), [isLive]);
70+
71+
return (
72+
<PeriodSelector
73+
activeBackground={activeBackground}
74+
activeTab={activeTab}
75+
onChange={setActiveTab}
76+
tabs={tabs}
77+
/>
78+
);
79+
}
80+
```
81+
82+
## Overflow
83+
84+
When there are too many tabs to fit in a single row, wrap the selector in a horizontal `ScrollView` with an optional action button.
85+
86+
```jsx
87+
function Example() {
88+
const tabs = useMemo(
89+
() => [
90+
{ id: '1H', label: <LiveTabLabel /> },
5691
{ id: '1D', label: '1D' },
5792
{ id: '1W', label: '1W' },
5893
{ id: '1M', label: '1M' },
@@ -98,149 +133,17 @@ function ManyPeriodsExample() {
98133
}
99134
```
100135
101-
## Live Indicator
102-
103-
```jsx
104-
function LiveExample() {
105-
const tabs = useMemo(
106-
() => [
107-
// LiveTabLabel is exported from PeriodSelector
108-
{ id: '1H', label: <LiveTabLabel /> },
109-
{ id: '1D', label: '1D' },
110-
{ id: '1W', label: '1W' },
111-
{ id: '1M', label: '1M' },
112-
{ id: '1Y', label: '1Y' },
113-
{ id: 'All', label: 'All' },
114-
],
115-
[],
116-
);
117-
118-
const [activeTab, setActiveTab] = useState(tabs[0]);
119-
const isLive = useMemo(() => activeTab?.id === '1H', [activeTab]);
120-
121-
const activeBackground = useMemo(() => (isLive ? 'bgNegativeWash' : 'bgPrimaryWash'), [isLive]);
122-
123-
return (
124-
<PeriodSelector
125-
activeBackground={activeBackground}
126-
activeTab={activeTab}
127-
onChange={setActiveTab}
128-
tabs={tabs}
129-
/>
130-
);
131-
}
132-
```
133-
134136
## Customization
135137
136138
### Custom Colors
137139
138-
```jsx
139-
function ColoredBTCExample() {
140-
const btcColor = assets.btc.color;
141-
142-
// Custom active indicator with BTC color
143-
const BTCActiveIndicator = memo((props) => {
144-
const theme = useTheme();
145-
const { activeTab } = useTabsContext();
146-
const isLive = useMemo(() => activeTab?.id === '1H', [activeTab]);
147-
148-
const backgroundColor = useMemo(
149-
() => (isLive ? theme.color.bgNegativeWash : `${btcColor}1A`),
150-
[isLive, theme.color.bgNegativeWash],
151-
);
152-
153-
return <PeriodSelectorActiveIndicator {...props} background={backgroundColor} />;
154-
});
155-
156-
// Custom tab component with BTC color
157-
const BTCTab = memo(
158-
forwardRef(({ label, ...props }, ref) => {
159-
const { activeTab } = useTabsContext();
160-
const isActive = activeTab?.id === props.id;
161-
const theme = useTheme();
162-
163-
const wrappedLabel =
164-
typeof label === 'string' ? (
165-
<Text font="label1" dangerouslySetColor={isActive ? btcColor : theme.color.fg}>
166-
{label}
167-
</Text>
168-
) : (
169-
label
170-
);
171-
172-
return <SegmentedTab ref={ref} label={wrappedLabel} {...props} />;
173-
}),
174-
);
175-
176-
// Custom live label with BTC color
177-
const BTCLiveLabel = memo(
178-
forwardRef(({ label = 'LIVE', font = 'label1', hideDot, style, ...props }, ref) => {
179-
const theme = useTheme();
180-
181-
const dotStyle = useMemo(
182-
() => ({
183-
width: theme.space[1],
184-
height: theme.space[1],
185-
borderRadius: 1000,
186-
marginRight: theme.space[0.75],
187-
backgroundColor: btcColor,
188-
}),
189-
[theme.space],
190-
);
191-
192-
return (
193-
<View
194-
ref={ref}
195-
style={[
196-
{
197-
flexDirection: 'row',
198-
alignItems: 'center',
199-
},
200-
style,
201-
]}
202-
>
203-
{!hideDot && <View style={dotStyle} />}
204-
<Text font={font} style={{ color: btcColor }} {...props}>
205-
{label}
206-
</Text>
207-
</View>
208-
);
209-
}),
210-
);
211-
212-
const tabs = [
213-
{ id: '1H', label: <BTCLiveLabel /> },
214-
{ id: '1D', label: '1D' },
215-
{ id: '1W', label: '1W' },
216-
{ id: '1M', label: '1M' },
217-
{ id: '1Y', label: '1Y' },
218-
{ id: 'All', label: 'All' },
219-
];
220-
const [activeTab, setActiveTab] = useState(tabs[0]);
221-
222-
return (
223-
<PeriodSelector
224-
TabComponent={BTCTab}
225-
TabsActiveIndicatorComponent={BTCActiveIndicator}
226-
activeTab={activeTab}
227-
onChange={setActiveTab}
228-
tabs={tabs}
229-
/>
230-
);
231-
}
232-
```
233-
234-
### Custom Colors Excluding Live
235-
236-
Customize colors for regular periods while keeping the default red styling for live periods.
140+
Use `TabComponent` and `TabsActiveIndicatorComponent` to fully brand the selector. This example applies a custom asset color to both the active indicator background and the tab text, while keeping the default red styling for live periods.
237141
238142
```jsx
239-
function ColoredExcludingLiveExample() {
143+
function Example() {
240144
const btcColor = assets.btc.color;
241145

242-
// Custom active indicator that only applies BTC color to non-live periods
243-
const BTCActiveExcludingLiveIndicator = memo((props) => {
146+
const BTCActiveIndicator = memo((props) => {
244147
const theme = useTheme();
245148
const { activeTab } = useTabsContext();
246149
const isLive = useMemo(() => activeTab?.id === '1H', [activeTab]);
@@ -253,7 +156,6 @@ function ColoredExcludingLiveExample() {
253156
return <PeriodSelectorActiveIndicator {...props} background={backgroundColor} />;
254157
});
255158

256-
// Custom tab component with BTC color
257159
const BTCTab = memo(
258160
forwardRef(({ label, ...props }, ref) => {
259161
const { activeTab } = useTabsContext();
@@ -281,12 +183,12 @@ function ColoredExcludingLiveExample() {
281183
{ id: '1Y', label: '1Y' },
282184
{ id: 'All', label: 'All' },
283185
];
284-
const [activeTab, setActiveTab] = useState(tabs[0]);
186+
const [activeTab, setActiveTab] = useState(tabs[1]);
285187

286188
return (
287189
<PeriodSelector
288190
TabComponent={BTCTab}
289-
TabsActiveIndicatorComponent={BTCActiveExcludingLiveIndicator}
191+
TabsActiveIndicatorComponent={BTCActiveIndicator}
290192
activeTab={activeTab}
291193
onChange={setActiveTab}
292194
tabs={tabs}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { ComponentStylesTable } from '@site/src/components/page/ComponentStylesTable';
2+
3+
import mobileStylesData from ':docgen/mobile-visualization/chart/PeriodSelector/styles-data';
4+
5+
## Selectors
6+
7+
<ComponentStylesTable componentName="PeriodSelector" styles={mobileStylesData} />

0 commit comments

Comments
 (0)