Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit eccadb5

Browse files
authored
feat: add Tabs component to Common UI plus Adapters (#551)
* feat: add Tabs component with React Aria integration and improved interface design * fix: resolve TypeScript errors in Tabs component and adapter
1 parent 5122d1c commit eccadb5

File tree

10 files changed

+670
-2
lines changed

10 files changed

+670
-2
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
alwaysApply: false
3+
---
4+
5+
# No !important in Styles
6+
7+
**NEVER use `!important` in CSS/SCSS files.**
8+
9+
Use proper CSS specificity instead.
10+
11+
# No !important in Styles
12+
13+
**NEVER use `!important` in CSS/SCSS files.**
14+
15+
Use proper CSS specificity instead.

.ladle/adapters/PlainComponentAdapter.tsx

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type React from 'react'
1+
import React from 'react'
22
import type { TextInputProps } from '../../src/components/Common/UI/TextInput/TextInputTypes'
33
import type { NumberInputProps } from '../../src/components/Common/UI/NumberInput/NumberInputTypes'
44
import type { CardProps } from '../../src/components/Common/UI/Card/CardTypes'
@@ -21,6 +21,7 @@ import type {
2121
ButtonIconProps,
2222
ButtonProps,
2323
} from '../../src/components/Common/UI/Button/ButtonTypes'
24+
import type { TabsProps } from '../../src/components/Common/UI/Tabs/TabsTypes'
2425
import type { ComponentsContextType } from '@/contexts/ComponentAdapter/useComponentContext'
2526
import type { MenuProps } from '@/components/Common/UI/Menu/MenuTypes'
2627
import type { ProgressBarProps } from '@/components/Common/UI/ProgressBar/ProgressBarTypes'
@@ -1056,7 +1057,6 @@ export const PlainComponentAdapter: ComponentsContextType = {
10561057
fontWeight: weight ? fontWeights[weight] : fontWeights.regular,
10571058
}
10581059

1059-
// Use dynamic element creation based on the "as" prop
10601060
const ElementType = Component as React.ElementType
10611061
return (
10621062
<ElementType style={textStyles} className={className}>
@@ -1096,4 +1096,52 @@ export const PlainComponentAdapter: ComponentsContextType = {
10961096
</div>
10971097
)
10981098
},
1099+
1100+
Tabs: ({ tabs, selectedId, onSelectionChange, className }: TabsProps) => {
1101+
const [activeTab, setActiveTab] = React.useState(selectedId || tabs[0]?.id || '')
1102+
1103+
const currentTab = selectedId || activeTab
1104+
const selectedTabContent = tabs.find(tab => tab.id === currentTab)?.content
1105+
1106+
const handleTabClick = (tabId: string) => {
1107+
const tab = tabs.find(t => t.id === tabId)
1108+
if (tab?.isDisabled) return
1109+
1110+
if (!selectedId) {
1111+
setActiveTab(tabId)
1112+
}
1113+
onSelectionChange(tabId)
1114+
}
1115+
1116+
return (
1117+
<div className={`plain-tabs ${className || ''}`}>
1118+
<div className="plain-tabs-list">
1119+
{tabs.map(tab => (
1120+
<button
1121+
key={tab.id}
1122+
className={`plain-tab ${currentTab === tab.id ? 'active' : ''} ${
1123+
tab.isDisabled ? 'disabled' : ''
1124+
}`}
1125+
onClick={() => {
1126+
handleTabClick(tab.id)
1127+
}}
1128+
disabled={tab.isDisabled}
1129+
style={{
1130+
padding: '8px 16px',
1131+
border: '1px solid #ccc',
1132+
backgroundColor: currentTab === tab.id ? '#f0f0f0' : 'white',
1133+
cursor: tab.isDisabled ? 'not-allowed' : 'pointer',
1134+
opacity: tab.isDisabled ? 0.5 : 1,
1135+
}}
1136+
>
1137+
{tab.label}
1138+
</button>
1139+
))}
1140+
</div>
1141+
<div className="plain-tab-content" style={{ padding: '16px', border: '1px solid #ccc' }}>
1142+
{selectedTabContent}
1143+
</div>
1144+
</div>
1145+
)
1146+
},
10991147
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
@use '@/styles/Helpers';
2+
3+
:global(.GSDK) {
4+
.root {
5+
width: 100%;
6+
7+
:global(.react-aria-Tabs) {
8+
display: flex;
9+
flex-direction: column;
10+
width: 100%;
11+
color: var(--g-colorBodyContent);
12+
font-size: var(--g-fontSizeSmall);
13+
forced-color-adjust: none;
14+
15+
&[data-focus-visible] {
16+
outline: var(--g-focusRingWidth) solid var(--g-focusRingColor);
17+
outline-offset: Helpers.toRem(2);
18+
border-radius: Helpers.toRem(4);
19+
}
20+
}
21+
22+
:global(.react-aria-TabList) {
23+
display: flex;
24+
gap: Helpers.toRem(4);
25+
border-bottom: 1px solid var(--g-colorBorder);
26+
margin-bottom: Helpers.toRem(24);
27+
}
28+
29+
:global(.react-aria-Tab) {
30+
background: transparent;
31+
border: none;
32+
padding: Helpers.toRem(8) Helpers.toRem(12);
33+
margin: 0;
34+
cursor: pointer;
35+
font-size: var(--g-fontSizeSmall);
36+
font-weight: var(--g-fontWeightSemibold);
37+
color: var(--g-colorBodySubContent);
38+
transition: all var(--g-transitionDuration);
39+
border-radius: Helpers.toRem(6);
40+
position: relative;
41+
outline: none;
42+
line-height: Helpers.toRem(20);
43+
height: Helpers.toRem(36);
44+
display: flex;
45+
align-items: center;
46+
justify-content: center;
47+
text-align: center;
48+
49+
&[data-hovered] {
50+
color: var(--g-colorBodyContent);
51+
background: var(--g-colorBodyAccent);
52+
}
53+
54+
&[data-pressed] {
55+
color: var(--g-colorBodyContent);
56+
background: var(--g-colorBody);
57+
}
58+
59+
&[data-selected] {
60+
color: var(--g-colorBodyContent);
61+
font-weight: var(--g-fontWeightSemibold);
62+
background: var(--g-colorBodyAccent);
63+
}
64+
65+
&[data-focus-visible] {
66+
outline: var(--g-focusRingWidth) solid var(--g-focusRingColor);
67+
outline-offset: Helpers.toRem(2);
68+
border-radius: Helpers.toRem(4);
69+
}
70+
71+
&[data-disabled],
72+
&[aria-disabled='true'] {
73+
display: flex;
74+
align-items: center;
75+
justify-content: center;
76+
visibility: visible;
77+
color: var(--g-colorBodySubContent);
78+
background: transparent;
79+
cursor: not-allowed;
80+
opacity: 0.5;
81+
82+
&[data-hovered],
83+
&[data-pressed],
84+
&[data-selected],
85+
&:hover,
86+
&:active,
87+
&:focus {
88+
color: var(--g-colorBodySubContent);
89+
background: transparent;
90+
cursor: not-allowed;
91+
pointer-events: none;
92+
opacity: 0.5;
93+
}
94+
}
95+
}
96+
97+
:global(.react-aria-TabPanel) {
98+
outline: none;
99+
100+
&[data-focus-visible] {
101+
outline: var(--g-focusRingWidth) solid var(--g-focusRingColor);
102+
outline-offset: Helpers.toRem(2);
103+
border-radius: Helpers.toRem(4);
104+
}
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)