diff --git a/src/recipes/button.ts b/src/recipes/button.ts index 044ad20..4d35ca5 100644 --- a/src/recipes/button.ts +++ b/src/recipes/button.ts @@ -27,6 +27,9 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { transitionDuration: 'normal', transitionTimingFunction: 'easeOut', fontWeight: 'semibold', + focusVisibleRing: 'outside', + focusRingWidth: '2px', + focusRingOffset: '0px', _disabled: { cursor: 'not-allowed', _hover: { @@ -36,7 +39,14 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { }, variants: { color: { - ...Object.fromEntries(colorVariants.map((color) => [color, {}])) + ...Object.fromEntries( + colorVariants.map((color) => [ + color, + { + focusRingColor: `{colors.${color}.7}` + } + ]) + ) }, size: { ...Object.fromEntries( @@ -95,6 +105,10 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { backgroundColor: `${color}.10`, color: `${color}.foreground` }, + _focusVisible: { + backgroundColor: `${color}.10`, + color: `${color}.foreground` + }, _active: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 80%, {colors.${color}.1})`, color: `${color}.foreground` @@ -105,7 +119,7 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { borderColor: `color-mix(in srgb, {colors.${color}.9} 10%, transparent)`, _hover: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 10%, transparent)`, - color: `${color}.4/50` + color: `color-mix(in srgb, {colors.${color}.foreground} 40%, transparent)` } } } @@ -122,6 +136,10 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { backgroundColor: `${color}.10`, color: `${color}.foreground` }, + _focusVisible: { + backgroundColor: `${color}.10`, + color: `${color}.foreground` + }, _active: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 80%, {colors.${color}.1})`, color: `${color}.foreground` @@ -130,13 +148,14 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 10%, transparent)`, color: `color-mix(in srgb, {colors.${color}.foreground} 40%, transparent)`, _hover: { - backgroundColor: `color-mix(in srgb, {colors.${color}.9} 10%, transparent)` + backgroundColor: `color-mix(in srgb, {colors.${color}.9} 10%, transparent)`, + color: `color-mix(in srgb, {colors.${color}.foreground} 40%, transparent)` } } } } // case 'solid' or unmatched: - default: + case 'solid': return { color, variant, @@ -152,6 +171,10 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 80%, {colors.${color}.1})`, color: `${color}.foreground` }, + _focusVisible: { + backgroundColor: `${color}.10`, + color: `${color}.foreground` + }, _disabled: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 40%, transparent)`, color: `color-mix(in srgb, {colors.${color}.foreground} 40%, transparent)`, @@ -162,6 +185,12 @@ const buttonRecipe = ({ semanticColorNames }: ButtonRecipeArg) => { } } } + default: + return { + color, + variant, + css: {} + } } }) ), diff --git a/src/recipes/card.ts b/src/recipes/card.ts index d580144..bab00ba 100644 --- a/src/recipes/card.ts +++ b/src/recipes/card.ts @@ -31,7 +31,10 @@ const cardRecipe = ({ semanticColorNames }: CardRecipeArg) => { transitionProperty: 'color, background-color, border-color', transitionDuration: 'normal', transitionTimingFunction: 'easeOut', - focusRingColor: 'var(--card-border-color-hover)', + focusVisibleRing: 'outside', + focusRingColor: 'var(--card-background-color-hover)', + focusRingWidth: '2px', + focusRingOffset: '0px', _hover: { borderColor: 'var(--card-border-color-hover)', backgroundColor: 'var(--card-background-color-hover)', @@ -44,8 +47,6 @@ const cardRecipe = ({ semanticColorNames }: CardRecipeArg) => { backgroundColor: 'var(--card-background-color-active)' }, _focus: { - focusRing: 'outside', - focusRingWidth: '2px', borderColor: 'var(--card-border-color-hover)', backgroundColor: 'var(--card-background-color-hover)', '& .card__header': { diff --git a/src/recipes/details.ts b/src/recipes/details.ts index 5a50d4d..28f1001 100644 --- a/src/recipes/details.ts +++ b/src/recipes/details.ts @@ -38,8 +38,15 @@ const detailsRecipe = ({ semanticColorNames }: DetailsRecipeArg) => { transitionProperty: 'color, background-color', transitionDuration: 'normal', transitionTimingFunction: 'easeIn', + focusVisibleRing: 'outside', + focusRingColor: 'var(--details-background-widget-hover)', + focusRingWidth: '2px', + focusRingOffset: '0px', _hover: { backgroundColor: 'var(--details-background-widget-hover)' + }, + _focusVisible: { + backgroundColor: 'var(--details-background-widget-hover)' } }, content: { @@ -64,6 +71,8 @@ const detailsRecipe = ({ semanticColorNames }: DetailsRecipeArg) => { '--details-background-widget': `colors.${color}.3`, '--details-background-widget-hover': `colors.${color}.4`, '--details-background-widget-active': `colors.${color}.5`, + '--details-border-color': `colors.${color}.6`, + '--details-border-color-hover': `colors.${color}.7`, '--details-color': `colors.${color}.12` } as SystemStyleObject ] diff --git a/src/recipes/iconButton.ts b/src/recipes/iconButton.ts index b1303eb..dc3d5cc 100644 --- a/src/recipes/iconButton.ts +++ b/src/recipes/iconButton.ts @@ -23,6 +23,9 @@ const iconButtonRecipe = ({ semanticColorNames }: IconButtonRecipeArg) => { transitionProperty: 'color, background-color, border-color', transitionDuration: 'normal', transitionTimingFunction: 'easeOut', + focusVisibleRing: 'outside', + focusRingWidth: '2px', + focusRingOffset: '0px', _disabled: { cursor: 'not-allowed', _hover: { @@ -56,7 +59,14 @@ const iconButtonRecipe = ({ semanticColorNames }: IconButtonRecipeArg) => { ) }, color: { - ...Object.fromEntries(colors.map((color) => [color, {}])) + ...Object.fromEntries( + colors.map((color) => [ + color, + { + focusRingColor: `{colors.${color}.6}` + } + ]) + ) }, variant: { ...Object.fromEntries(iconButtonVariants.map((variant) => [variant, {}])) @@ -92,6 +102,9 @@ const iconButtonRecipe = ({ semanticColorNames }: IconButtonRecipeArg) => { _hover: { backgroundColor: `${color}.10` }, + _focusVisible: { + backgroundColor: `${color}.10` + }, _active: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 80%, {colors.${color}.1})` }, @@ -118,6 +131,10 @@ const iconButtonRecipe = ({ semanticColorNames }: IconButtonRecipeArg) => { backgroundColor: `${color}.10`, color: `${color}.foreground` }, + _focusVisible: { + backgroundColor: `${color}.10`, + color: `${color}.foreground` + }, _active: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 80%, {colors.${color}.1})`, color: `${color}.foreground` @@ -145,6 +162,10 @@ const iconButtonRecipe = ({ semanticColorNames }: IconButtonRecipeArg) => { backgroundColor: `${color}.10`, color: `${color}.foreground` }, + _focusVisible: { + backgroundColor: `${color}.10`, + color: `${color}.foreground` + }, _active: { backgroundColor: `color-mix(in srgb, {colors.${color}.9} 80%, {colors.${color}.1})`, color: `${color}.foreground` diff --git a/src/recipes/input.ts b/src/recipes/input.ts index d0a59b2..2aa5bf3 100644 --- a/src/recipes/input.ts +++ b/src/recipes/input.ts @@ -1,5 +1,6 @@ import { defineRecipe } from '@pandacss/dev' +export const inputSizes = ['small', 'medium', 'large'] as const export interface InputRecipeArg { semanticColorNames: string[] } @@ -18,27 +19,50 @@ export const inputRecipe = ({ semanticColorNames }: InputRecipeArg) => { transitionDuration: 'normal', transitionTimingFunction: 'easeOut', cursor: 'text', + focusVisibleRing: 'outside', + focusRingWidth: '2px', + focusRingOffset: '0px', _disabled: { cursor: 'not-allowed' } }, 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' - } + ...Object.fromEntries( + inputSizes.map((size) => { + switch (size) { + case 'small': + return [ + size, + { + paddingBlock: 'calc({spacing.xs} * 0.5)', + paddingInline: 'calc({spacing.xs} * 1)', + fontSize: 'sm' + } + ] + case 'medium': + return [ + size, + { + paddingBlock: 'calc({spacing.xs} * 0.75)', + paddingInline: 'calc({spacing.xs} * 1.25)', + fontSize: 'base' + } + ] + case 'large': + return [ + size, + { + paddingBlock: 'calc({spacing.xs} * 1)', + paddingInline: 'calc({spacing.xs} * 1.5)', + fontSize: 'lg' + } + ] + default: + return [size, {}] + } + }) + ) }, color: { ...Object.fromEntries( @@ -48,6 +72,7 @@ export const inputRecipe = ({ semanticColorNames }: InputRecipeArg) => { borderColor: `${color}.6`, backgroundColor: `${color}.2`, color: `${color}.12`, + focusRingColor: `{colors.${color}.7}`, _placeholder: { color: `${color}.11` }, diff --git a/src/recipes/select.ts b/src/recipes/select.ts index a7d63fc..b01aaa0 100644 --- a/src/recipes/select.ts +++ b/src/recipes/select.ts @@ -1,6 +1,6 @@ import { defineSlotRecipe, type SystemStyleObject } from '@pandacss/dev' -const selectSlots = [ +export const selectSlots = [ 'trigger', 'content', 'viewport', @@ -11,6 +11,7 @@ const selectSlots = [ 'groupLabel', 'separator' ] as const +export const selectSizes = ['small', 'medium', 'large'] as const export interface SelectRecipeArg { semanticColorNames: string[] @@ -35,7 +36,10 @@ const selectRecipe = ({ semanticColorNames }: SelectRecipeArg) => { cursor: 'pointer', transitionProperty: 'color, background-color, border-color', transitionDuration: 'normal', - transitionTimingFunction: 'easeOut' + transitionTimingFunction: 'easeOut', + focusVisibleRing: 'outside', + focusRingWidth: '2px', + focusRingOffset: '0px' }, content: { overflow: 'hidden', @@ -81,6 +85,10 @@ const selectRecipe = ({ semanticColorNames }: SelectRecipeArg) => { 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)' }, @@ -124,27 +132,47 @@ const selectRecipe = ({ semanticColorNames }: SelectRecipeArg) => { }, 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' - } - } + ...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( @@ -161,6 +189,7 @@ const selectRecipe = ({ semanticColorNames }: SelectRecipeArg) => { backgroundColor: `${color}.2`, color: `${color}.12`, borderColor: `${color}.6`, + focusRingColor: `{colors.${color}.7}`, _placeholder: { color: `${color}.11` }, @@ -203,6 +232,7 @@ const selectRecipe = ({ semanticColorNames }: SelectRecipeArg) => { '--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)`