Compare commits

...

2 Commits

4 changed files with 284 additions and 13 deletions

View File

@@ -14,6 +14,7 @@ import alertRecipe from './recipes/alert.js'
import chipRecipe from './recipes/chip.js'
import iconButtonRecipe from './recipes/iconButton.js'
import markRecipe from './recipes/mark.js'
import selectRecipe from './recipes/select.js'
export type ThemeConfig = {
neutral?: NeutralColor
@@ -48,7 +49,8 @@ const srJuggernautPandaPreset = (config?: ThemeConfig) => {
details: detailsRecipe({ semanticColorNames: semanticColorKeysArray }),
mark: markRecipe({ semanticColorNames: semanticColorKeysArray }),
input: inputRecipe({ semanticColorNames: semanticColorKeysArray }),
iconButton: iconButtonRecipe({ semanticColorNames: semanticColorKeysArray })
iconButton: iconButtonRecipe({ semanticColorNames: semanticColorKeysArray }),
select: selectRecipe({ semanticColorNames: semanticColorKeysArray })
},
tokens: {
animations: {},
@@ -186,6 +188,11 @@ const srJuggernautPandaPreset = (config?: ThemeConfig) => {
}
}
},
conditions: {
extend: {
active: '&[data-state="open"]'
}
},
globalCss: {
'*, *:before, *:after': {
boxSizing: 'border-box',

View File

@@ -21,7 +21,7 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => {
paddingBlock: 'xs',
paddingInline: 'sm',
cursor: 'pointer',
transition: 'all',
transitionProperty: 'color, background-color, border-color',
transitionDuration: 'normal',
transitionTimingFunction: 'easeOut'
},

View File

@@ -12,8 +12,6 @@ export const inputRecipe = ({ semanticColorNames }: InputRecipeArg) => {
base: {
display: 'inline-flex',
borderRadius: 'sm',
paddingBlock: 'xs',
paddingInline: 'sm',
border: '1px solid',
outline: 'none',
transitionProperty: 'color, background-color, border-color',
@@ -25,6 +23,23 @@ export const inputRecipe = ({ semanticColorNames }: InputRecipeArg) => {
}
},
variants: {
size: {
small: {
paddingBlock: 'calc({spacing.xs} * 0.5)',
paddingInline: 'calc({spacing.xs} * 1)',
fontSize: 'sm'
},
medium: {
paddingBlock: 'calc({spacing.xs} * 0.75)',
paddingInline: 'calc({spacing.xs} * 1.25)',
fontSize: 'base'
},
large: {
paddingBlock: 'calc({spacing.xs} * 1)',
paddingInline: 'calc({spacing.xs} * 1.5)',
fontSize: 'lg'
}
},
color: {
...Object.fromEntries(
colorVariants.map((color) => [
@@ -33,34 +48,49 @@ export const inputRecipe = ({ semanticColorNames }: InputRecipeArg) => {
borderColor: `${color}.6`,
backgroundColor: `${color}.2`,
color: `${color}.12`,
_placeholder: {
color: `${color}.11`
},
_hover: {
backgroundColor: `${color}.3`
},
_active: {
backgroundColor: `${color}.4`
},
_focus: {
backgroundColor: `${color}.3`,
borderColor: `${color}.7`
},
_disabled: {
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 30%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 30%, transparent)`,
borderColor: `color-mix(in srgb, {colors.${color}.6} 30%, transparent)`,
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`,
borderColor: `color-mix(in srgb, {colors.${color}.6} 40%, transparent)`,
_placeholder: {
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
},
_hover: {
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 30%, transparent)`,
borderColor: `color-mix(in srgb, {colors.${color}.6} 30%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 30%, transparent)`
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
borderColor: `color-mix(in srgb, {colors.${color}.6} 40%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
},
_focus: {
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 30%, transparent)`,
borderColor: `color-mix(in srgb, {colors.${color}.6} 30%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 30%, transparent)`
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
borderColor: `color-mix(in srgb, {colors.${color}.6} 40%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
}
}
}
])
)
},
fullWidth: {
true: {
width: '100%'
}
}
},
defaultVariants: {
size: 'medium',
color: 'neutral'
}
})

234
src/recipes/select.ts Normal file
View File

@@ -0,0 +1,234 @@
import { defineSlotRecipe, type SystemStyleObject } from '@pandacss/dev'
const selectSlots = [
'trigger',
'content',
'viewport',
'scrollButton',
'item',
'itemIndicator',
'group',
'groupLabel',
'separator'
] as const
export interface SelectRecipeArg {
semanticColorNames: string[]
}
const selectRecipe = ({ semanticColorNames }: SelectRecipeArg) => {
const colorVariants = ['neutral', ...semanticColorNames]
return defineSlotRecipe({
className: 'select',
slots: selectSlots,
base: {
trigger: {
all: 'unset',
boxSizing: 'border-box',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: 'xs',
minWidth: 'fit-content',
borderRadius: 'sm',
border: '1px solid',
cursor: 'pointer',
transitionProperty: 'color, background-color, border-color',
transitionDuration: 'normal',
transitionTimingFunction: 'easeOut'
},
content: {
overflow: 'hidden',
maxHeight: 'var(--radix-select-content-available-height, 90dvh)',
width: 'var(--radix-select-trigger-width, min(max-content, 90dvw))',
backgroundColor: 'var(--select-background-color)',
color: 'var(--select-color)',
borderRadius: 'sm',
_active: {
animationName: 'fade',
animationDuration: 'normal'
},
'&[data-state=closed]': {
animationName: 'fade',
animationDuration: 'normal',
animationDirection: 'reverse'
}
},
viewport: {
padding: 'xs'
},
scrollButton: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'var(--select-color-subtle)',
cursor: 'pointer',
transitionProperty: 'color, background-color',
transitionDuration: 'normal',
transitionTimingFunction: 'easeOut',
'&:hover': {
color: 'var(--select-color)'
}
},
item: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
gap: 'xs',
padding: 'xs',
borderRadius: 'sm',
cursor: 'pointer',
transitionProperty: 'color, background-color',
transitionDuration: 'normal',
transitionTimingFunction: 'easeOut',
_highlighted: {
backgroundColor: 'var(--select-background-color-hover)'
},
'&[data-state=checked]': {
backgroundColor: 'var(--select-background-color-active)'
},
_disabled: {
color: 'var(--select-color-disabled)',
backgroundColor: 'var(--select-background-color-disabled)',
cursor: 'not-allowed',
_highlighted: {
backgroundColor: 'var(--select-background-color-disabled)',
color: 'var(--select-color-disabled)'
}
}
},
itemIndicator: {
color: 'var(--select-color-subtle)'
},
group: {
display: 'flex',
flexDirection: 'column',
gap: 'xs',
marginInline: '-xs',
borderBlock: '1px solid var(--select-border-color)',
paddingInline: 'xs'
},
groupLabel: {
color: 'var(--select-color-subtle)',
fontSize: 'sm',
fontWeight: 'semibold',
lineHeight: 'tight',
userSelect: 'none'
},
separator: {
height: '1px',
backgroundColor: 'var(--select-border-color)',
marginBlock: 'xs',
marginInline: '-xs'
}
},
variants: {
size: {
small: {
trigger: {
paddingBlock: 'calc({spacing.xs} * 0.5)',
paddingInline: 'calc({spacing.xs} * 1)',
fontSize: 'sm'
}
},
medium: {
trigger: {
paddingBlock: 'calc({spacing.xs} * 0.75)',
paddingInline: 'calc({spacing.xs} * 1.25)',
fontSize: 'base'
}
},
large: {
trigger: {
paddingBlock: 'calc({spacing.xs} * 1)',
paddingInline: 'calc({spacing.xs} * 1.5)',
fontSize: 'lg'
}
}
},
color: {
...Object.fromEntries(
colorVariants.map((color) => [
color,
Object.fromEntries(
selectSlots.map((slot) => {
switch (slot) {
case 'trigger':
// Trigger is outside the content, so it needs to be set independently
return [
slot,
{
backgroundColor: `${color}.2`,
color: `${color}.12`,
borderColor: `${color}.6`,
_placeholder: {
color: `${color}.11`
},
_hover: {
backgroundColor: `${color}.3`
},
_active: {
backgroundColor: `${color}.4`
},
_focus: {
backgroundColor: `${color}.3`,
borderColor: `${color}.7`
},
_disabled: {
cursor: 'not-allowed',
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`,
_placeholder: {
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
},
_hover: {
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
},
_active: {
backgroundColor: `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
color: `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
}
}
} as SystemStyleObject
]
case 'content':
// Items, Group, ScrollButtons are inside the content, so we can set them together
return [
slot,
{
'--select-background-color': `{colors.${color}.2}`,
'--select-background-color-hover': `{colors.${color}.4}`,
'--select-background-color-active': `{colors.${color}.5}`,
'--select-background-color-disabled': `color-mix(in srgb, {colors.${color}.2} 40%, transparent)`,
'--select-border-color': `{colors.${color}.6}`,
'--select-color-subtle': `{colors.${color}.11}`,
'--select-color': `{colors.${color}.12}`,
'--select-color-disabled': `color-mix(in srgb, {colors.${color}.11} 40%, transparent)`
} as SystemStyleObject
]
default:
return [slot, {}]
}
})
)
])
)
},
fullWidth: {
true: {
trigger: {
width: '100%'
}
}
}
},
defaultVariants: {
color: 'neutral',
size: 'medium'
}
})
}
export default selectRecipe