feat: add tabs slot recipe for tab component styling

This commit is contained in:
2026-04-30 21:48:06 -06:00
parent 2e96108767
commit 944ef344e6
2 changed files with 181 additions and 0 deletions
+2
View File
@@ -17,6 +17,7 @@ import markRecipe from '@/recipes/mark'
import menuRecipe from '@/recipes/menu' import menuRecipe from '@/recipes/menu'
import progressBarRecipe from '@/recipes/progressBar' import progressBarRecipe from '@/recipes/progressBar'
import selectRecipe from '@/recipes/select' import selectRecipe from '@/recipes/select'
import tabsRecipe from '@/recipes/tabs'
import { type BrandColor, type Color, type ColorVariation, color, type NeutralColor } from '@/types' import { type BrandColor, type Color, type ColorVariation, color, type NeutralColor } from '@/types'
export type ThemeConfig = { export type ThemeConfig = {
@@ -78,6 +79,7 @@ const srJuggernautPandaPreset = (config?: ThemeConfig) => {
input: inputRecipe({ semanticColorNames: semanticColorKeysArray }), input: inputRecipe({ semanticColorNames: semanticColorKeysArray }),
iconButton: iconButtonRecipe({ semanticColorNames: semanticColorKeysArray }), iconButton: iconButtonRecipe({ semanticColorNames: semanticColorKeysArray }),
progressBar: progressBarRecipe({ semanticColorNames: semanticColorKeysArray }), progressBar: progressBarRecipe({ semanticColorNames: semanticColorKeysArray }),
tabs: tabsRecipe({ semanticColorNames: semanticColorKeysArray }),
select: selectRecipe({ semanticColorNames: semanticColorKeysArray }) select: selectRecipe({ semanticColorNames: semanticColorKeysArray })
}, },
breakpoints: Object.fromEntries(breakpointEntries.map(([key, value]) => [key, `${value}px`])), breakpoints: Object.fromEntries(breakpointEntries.map(([key, value]) => [key, `${value}px`])),
+179
View File
@@ -0,0 +1,179 @@
import { defineSlotRecipe, type SystemStyleObject } from '@pandacss/dev'
export const tabsSlots = ['container', 'list', 'tab', 'content'] as const
export interface TabsRecipeArg {
semanticColorNames: string[]
}
const tabsRecipe = ({ semanticColorNames }: TabsRecipeArg) => {
const colorVariants = ['neutral', ...semanticColorNames]
return defineSlotRecipe({
className: 'tabs',
slots: tabsSlots,
base: {
container: {
borderColor: 'var(--tabs-colors-6, var(--colors-neutral-6))',
backgroundColor: 'var(--tabs-colors-1, var(--colors-neutral-1))',
color: 'var(--tabs-colors-12, var(--colors-neutral-12))',
border: '1px solid',
borderRadius: 'md',
overflow: 'hidden'
},
list: {
display: 'flex',
flexWrap: 'nowrap',
width: '100%',
margin: 0,
padding: 0,
backgroundColor: 'var(--tabs-colors-list-1, var(--tabs-colors-1))',
color: 'var(--tabs-colors-list-12, var(--tabs-colors-12))',
overflowX: 'auto'
},
tab: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: 'xs',
flex: 1,
minWidth: 'max-content',
paddingBlock: 'xs',
paddingInline: 'sm',
backgroundColor: 'var(--tabs-colors-tab-3, var(--tabs-colors-list-3, var(--tabs-colors-3)))',
color: 'var(--tabs-colors-tab-12, var(--tabs-colors-list-12, var(--tabs-colors-12)))',
transitionProperty: 'color, background-color, border-color',
transitionDuration: 'normal',
transitionTimingFunction: 'easeOut',
fontWeight: 'semibold',
focusVisibleRing: 'outside',
focusRingWidth: '2px',
focusRingOffset: '0px',
cursor: 'pointer',
_hover: {
backgroundColor: 'var(--tabs-colors-tab-4, var(--tabs-colors-list-4, var(--tabs-colors-4)))'
},
_active: {
backgroundColor: 'var(--tabs-colors-tab-5, var(--tabs-colors-list-5, var(--tabs-colors-5)))',
_hover: {
backgroundColor: 'var(--tabs-colors-tab-4, var(--tabs-colors-list-4, var(--tabs-colors-4)))'
}
},
_disabled: {
cursor: 'not-allowed',
backgroundColor:
'color-mix(in srgb, var(--tabs-colors-tab-3, var(--tabs-colors-list-3, var(--tabs-colors-3))) 40%, transparent)',
color:
'color-mix(in srgb, var(--tabs-colors-tab-11, var(--tabs-colors-list-11, var(--tabs-colors-11))) 40%, transparent)',
_hover: {
backgroundColor:
'color-mix(in srgb, var(--tabs-colors-tab-3, var(--tabs-colors-list-3, var(--tabs-colors-3))) 40%, transparent)',
color:
'color-mix(in srgb, var(--tabs-colors-tab-11, var(--tabs-colors-list-11, var(--tabs-colors-11))) 40%, transparent)',
_active: {
backgroundColor:
'color-mix(in srgb, var(--tabs-colors-tab-3, var(--tabs-colors-list-3, var(--tabs-colors-3))) 40%, transparent)',
color:
'color-mix(in srgb, var(--tabs-colors-tab-11, var(--tabs-colors-list-11, var(--tabs-colors-11))) 40%, transparent)'
}
},
_active: {
backgroundColor:
'color-mix(in srgb, var(--tabs-colors-tab-3, var(--tabs-colors-list-3, var(--tabs-colors-3))) 40%, transparent)',
color:
'color-mix(in srgb, var(--tabs-colors-tab-11, var(--tabs-colors-list-11, var(--tabs-colors-11))) 40%, transparent)'
}
}
},
content: {
display: 'block',
opacity: 1,
padding: 'sm',
backgroundColor: 'var(--tabs-colors-content-1, var(--tabs-colors-1))',
color: 'var(--tabs-colors-content-12, var(--tabs-colors-12))',
transitionProperty: 'display, opacity, transform',
transitionDuration: '{durations.normal}, {durations.normal}, {durations.normal}',
transitionTimingFunction: '{easings.easeOut}, {easings.easeOutQuint}, {easings.easeOutQuint}',
transitionBehavior: 'allow-discrete',
transform: 'translateY(0)',
_hidden: {
display: 'none'
},
'&[data-starting-style]': {
opacity: 0,
'&[data-activation-direction="right"]': {
transform: 'translateX(50%)'
},
'&[data-activation-direction="left"]': {
transform: 'translateX(-50%)'
}
},
'&[data-ending-style]': {
opacity: 0,
transitionDuration: '0ms'
}
}
},
variants: {
color: {
...Object.fromEntries(
colorVariants.map((color) => [
color,
{
...Object.fromEntries(
tabsSlots.map((slot) => {
switch (slot) {
case 'container':
return [
slot,
{
'--tabs-colors-1': `{colors.${color}.1}`,
'--tabs-colors-2': `{colors.${color}.2}`,
'--tabs-colors-3': `{colors.${color}.3}`,
'--tabs-colors-4': `{colors.${color}.4}`,
'--tabs-colors-5': `{colors.${color}.5}`,
'--tabs-colors-6': `{colors.${color}.6}`,
'--tabs-colors-7': `{colors.${color}.7}`,
'--tabs-colors-8': `{colors.${color}.8}`,
'--tabs-colors-9': `{colors.${color}.9}`,
'--tabs-colors-10': `{colors.${color}.10}`,
'--tabs-colors-11': `{colors.${color}.11}`,
'--tabs-colors-12': `{colors.${color}.12}`,
'--tabs-colors-foreground': `{colors.${color}.foreground}`
} as SystemStyleObject
]
case 'list':
case 'tab':
case 'content':
return [
slot,
{
[`--tabs-colors-${slot}-1`]: `{colors.${color}.1}`,
[`--tabs-colors-${slot}-2`]: `{colors.${color}.2}`,
[`--tabs-colors-${slot}-3`]: `{colors.${color}.3}`,
[`--tabs-colors-${slot}-4`]: `{colors.${color}.4}`,
[`--tabs-colors-${slot}-5`]: `{colors.${color}.5}`,
[`--tabs-colors-${slot}-6`]: `{colors.${color}.6}`,
[`--tabs-colors-${slot}-7`]: `{colors.${color}.7}`,
[`--tabs-colors-${slot}-8`]: `{colors.${color}.8}`,
[`--tabs-colors-${slot}-9`]: `{colors.${color}.9}`,
[`--tabs-colors-${slot}-10`]: `{colors.${color}.10}`,
[`--tabs-colors-${slot}-11`]: `{colors.${color}.11}`,
[`--tabs-colors-${slot}-12`]: `{colors.${color}.12}`,
[`--tabs-colors-${slot}-foreground`]: `{colors.${color}.foreground}`
} as SystemStyleObject
]
default:
return [slot, {} as SystemStyleObject]
}
})
)
}
])
)
}
},
defaultVariants: {}
})
}
export default tabsRecipe