265 lines
8.6 KiB
TypeScript
265 lines
8.6 KiB
TypeScript
import { defineSlotRecipe, type SystemStyleObject } from '@pandacss/dev'
|
|
|
|
export const selectSlots = [
|
|
'trigger',
|
|
'content',
|
|
'viewport',
|
|
'scrollButton',
|
|
'item',
|
|
'itemIndicator',
|
|
'group',
|
|
'groupLabel',
|
|
'separator'
|
|
] as const
|
|
export const selectSizes = ['small', 'medium', 'large'] 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',
|
|
focusVisibleRing: 'outside',
|
|
focusRingWidth: '2px',
|
|
focusRingOffset: '0px'
|
|
},
|
|
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',
|
|
focusRingColor: 'var(--select-border-color-focus)',
|
|
focusVisibleRing: 'outside',
|
|
focusRingWidth: '2px',
|
|
focusRingOffset: '0px',
|
|
_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: {
|
|
...Object.fromEntries(
|
|
selectSizes.map((size) => {
|
|
switch (size) {
|
|
case 'small':
|
|
return [
|
|
size,
|
|
{
|
|
trigger: {
|
|
paddingBlock: 'calc({spacing.xs} * 0.5)',
|
|
paddingInline: 'calc({spacing.xs} * 1)',
|
|
fontSize: 'sm'
|
|
}
|
|
}
|
|
]
|
|
case 'medium':
|
|
return [
|
|
size,
|
|
{
|
|
trigger: {
|
|
paddingBlock: 'calc({spacing.xs} * 0.75)',
|
|
paddingInline: 'calc({spacing.xs} * 1.25)',
|
|
fontSize: 'base'
|
|
}
|
|
}
|
|
]
|
|
case 'large':
|
|
return [
|
|
size,
|
|
{
|
|
trigger: {
|
|
paddingBlock: 'calc({spacing.xs} * 1)',
|
|
paddingInline: 'calc({spacing.xs} * 1.5)',
|
|
fontSize: 'lg'
|
|
}
|
|
}
|
|
]
|
|
default:
|
|
return [size, {}]
|
|
}
|
|
})
|
|
)
|
|
},
|
|
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`,
|
|
focusRingColor: `{colors.${color}.7}`,
|
|
_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-border-color-focus': `{colors.${color}.7}`,
|
|
'--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
|