Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: motion styles and better keyframe defaults #2701

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/rotten-plums-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@pandacss/preset-panda': minor
'@pandacss/generator': minor
'@pandacss/types': minor
'@pandacss/core': minor
'@pandacss/dev': minor
---

Add support for motion styles and keyframes
4 changes: 4 additions & 0 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ export function defineStyles(definition: SystemStyleObject) {
return definition
}

export function defineMotionStyles(definition: CompositionStyles['motionStyles']) {
return definition
}

export type {
CompositionStyles,
Config,
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export class Context {

// Relies on this.encoder, this.decoder
this.setupCompositions(theme)
this.registerAnimationName(theme)

this.recipes.save(this.baseSheetContext)

this.staticCss = new StaticCss({
Expand Down Expand Up @@ -269,9 +271,13 @@ export class Context {
}

setupCompositions = (theme: Theme): void => {
const { textStyles, layerStyles } = theme
const { textStyles, layerStyles, motionStyles } = theme

const compositions = compact({ textStyle: textStyles, layerStyle: layerStyles })
const compositions = compact({
textStyle: textStyles,
layerStyle: layerStyles,
motionStyle: motionStyles,
})

const stylesheetCtx = {
...this.baseSheetContext,
Expand All @@ -297,6 +303,10 @@ export class Context {
}
}

private registerAnimationName = (theme: Theme): void => {
this.utility.addPropertyType('animationName', Object.keys(theme.keyframes ?? {}))
}

setupProperties = (): void => {
this.properties = new Set(['css', ...this.utility.keys(), ...this.conditions.keys()])
this.isValidProperty = memo((key: string) => this.properties.has(key) || isCssProperty(key))
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,11 @@ export class Utility {
}
}

addPropertyType = (property: string, type: string[]) => {
const set = this.types.get(property) ?? new Set()
this.types.set(property, new Set([...set, ...type]))
}

/**
* Returns the Typescript type for the define properties
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"content": "import type { CompositionStyleObject } from './system-types'\n\ninterface Token<T> {\n value: T\n description?: string\n}\n\ninterface Recursive<T> {\n [key: string]: Recursive<T> | T\n}\n\n/* -----------------------------------------------------------------------------\n * Text styles\n * -----------------------------------------------------------------------------*/\n\ntype TextStyleProperty =\n | 'font'\n | 'fontFamily'\n | 'fontFeatureSettings'\n | 'fontKerning'\n | 'fontLanguageOverride'\n | 'fontOpticalSizing'\n | 'fontPalette'\n | 'fontSize'\n | 'fontSizeAdjust'\n | 'fontStretch'\n | 'fontStyle'\n | 'fontSynthesis'\n | 'fontVariant'\n | 'fontVariantAlternates'\n | 'fontVariantCaps'\n | 'fontVariantLigatures'\n | 'fontVariantNumeric'\n | 'fontVariantPosition'\n | 'fontVariationSettings'\n | 'fontWeight'\n | 'hypens'\n | 'hyphenateCharacter'\n | 'hyphenateLimitChars'\n | 'letterSpacing'\n | 'lineBreak'\n | 'lineHeight'\n | 'quotes'\n | 'overflowWrap'\n | 'textCombineUpright'\n | 'textDecoration'\n | 'textDecorationColor'\n | 'textDecorationLine'\n | 'textDecorationSkipInk'\n | 'textDecorationStyle'\n | 'textDecorationThickness'\n | 'textEmphasis'\n | 'textEmphasisColor'\n | 'textEmphasisPosition'\n | 'textEmphasisStyle'\n | 'textIndent'\n | 'textJustify'\n | 'textOrientation'\n | 'textOverflow'\n | 'textRendering'\n | 'textShadow'\n | 'textTransform'\n | 'textUnderlineOffset'\n | 'textUnderlinePosition'\n | 'textWrap'\n | 'textWrapMode'\n | 'textWrapStyle'\n | 'verticalAlign'\n | 'whiteSpace'\n | 'wordBreak'\n | 'wordSpacing'\n\nexport type TextStyle = CompositionStyleObject<TextStyleProperty>\n\nexport type TextStyles = Recursive<Token<TextStyle>>\n\n/* -----------------------------------------------------------------------------\n * Layer styles\n * -----------------------------------------------------------------------------*/\n\ntype Placement =\n | 'Top'\n | 'Right'\n | 'Bottom'\n | 'Left'\n | 'Inline'\n | 'Block'\n | 'InlineStart'\n | 'InlineEnd'\n | 'BlockStart'\n | 'BlockEnd'\n\ntype Radius =\n | `Top${'Right' | 'Left'}`\n | `Bottom${'Right' | 'Left'}`\n | `Start${'Start' | 'End'}`\n | `End${'Start' | 'End'}`\n\ntype LayerStyleProperty =\n | 'background'\n | 'backgroundColor'\n | 'backgroundImage'\n | 'borderRadius'\n | 'border'\n | 'borderWidth'\n | 'borderColor'\n | 'borderStyle'\n | 'boxShadow'\n | 'filter'\n | 'backdropFilter'\n | 'transform'\n | 'color'\n | 'opacity'\n | 'backgroundBlendMode'\n | 'backgroundAttachment'\n | 'backgroundClip'\n | 'backgroundOrigin'\n | 'backgroundPosition'\n | 'backgroundRepeat'\n | 'backgroundSize'\n | `border${Placement}`\n | `border${Placement}Width`\n | 'borderRadius'\n | `border${Radius}Radius`\n | `border${Placement}Color`\n | `border${Placement}Style`\n | 'padding'\n | `padding${Placement}`\n\nexport type LayerStyle = CompositionStyleObject<LayerStyleProperty>\n\nexport type LayerStyles = Recursive<Token<LayerStyle>>\n\nexport interface CompositionStyles {\n textStyles: TextStyles\n layerStyles: LayerStyles\n}\n"
"content": "import type { CompositionStyleObject } from './system-types'\n\ninterface Token<T> {\n value: T\n description?: string\n}\n\ninterface Recursive<T> {\n [key: string]: Recursive<T> | T\n}\n\n/* -----------------------------------------------------------------------------\n * Text styles\n * -----------------------------------------------------------------------------*/\n\ntype TextStyleProperty =\n | 'font'\n | 'fontFamily'\n | 'fontFeatureSettings'\n | 'fontKerning'\n | 'fontLanguageOverride'\n | 'fontOpticalSizing'\n | 'fontPalette'\n | 'fontSize'\n | 'fontSizeAdjust'\n | 'fontStretch'\n | 'fontStyle'\n | 'fontSynthesis'\n | 'fontVariant'\n | 'fontVariantAlternates'\n | 'fontVariantCaps'\n | 'fontVariantLigatures'\n | 'fontVariantNumeric'\n | 'fontVariantPosition'\n | 'fontVariationSettings'\n | 'fontWeight'\n | 'hypens'\n | 'hyphenateCharacter'\n | 'hyphenateLimitChars'\n | 'letterSpacing'\n | 'lineBreak'\n | 'lineHeight'\n | 'quotes'\n | 'overflowWrap'\n | 'textCombineUpright'\n | 'textDecoration'\n | 'textDecorationColor'\n | 'textDecorationLine'\n | 'textDecorationSkipInk'\n | 'textDecorationStyle'\n | 'textDecorationThickness'\n | 'textEmphasis'\n | 'textEmphasisColor'\n | 'textEmphasisPosition'\n | 'textEmphasisStyle'\n | 'textIndent'\n | 'textJustify'\n | 'textOrientation'\n | 'textOverflow'\n | 'textRendering'\n | 'textShadow'\n | 'textTransform'\n | 'textUnderlineOffset'\n | 'textUnderlinePosition'\n | 'textWrap'\n | 'textWrapMode'\n | 'textWrapStyle'\n | 'verticalAlign'\n | 'whiteSpace'\n | 'wordBreak'\n | 'wordSpacing'\n\nexport type TextStyle = CompositionStyleObject<TextStyleProperty>\n\nexport type TextStyles = Recursive<Token<TextStyle>>\n\n/* -----------------------------------------------------------------------------\n * Layer styles\n * -----------------------------------------------------------------------------*/\n\ntype Placement =\n | 'Top'\n | 'Right'\n | 'Bottom'\n | 'Left'\n | 'Inline'\n | 'Block'\n | 'InlineStart'\n | 'InlineEnd'\n | 'BlockStart'\n | 'BlockEnd'\n\ntype Radius =\n | `Top${'Right' | 'Left'}`\n | `Bottom${'Right' | 'Left'}`\n | `Start${'Start' | 'End'}`\n | `End${'Start' | 'End'}`\n\ntype LayerStyleProperty =\n | 'background'\n | 'backgroundColor'\n | 'backgroundImage'\n | 'borderRadius'\n | 'border'\n | 'borderWidth'\n | 'borderColor'\n | 'borderStyle'\n | 'boxShadow'\n | 'filter'\n | 'backdropFilter'\n | 'transform'\n | 'color'\n | 'opacity'\n | 'backgroundBlendMode'\n | 'backgroundAttachment'\n | 'backgroundClip'\n | 'backgroundOrigin'\n | 'backgroundPosition'\n | 'backgroundRepeat'\n | 'backgroundSize'\n | `border${Placement}`\n | `border${Placement}Width`\n | 'borderRadius'\n | `border${Radius}Radius`\n | `border${Placement}Color`\n | `border${Placement}Style`\n | 'padding'\n | `padding${Placement}`\n\nexport type LayerStyle = CompositionStyleObject<LayerStyleProperty>\n\nexport type LayerStyles = Recursive<Token<LayerStyle>>\n\n/* -----------------------------------------------------------------------------\n * Motion styles\n * -----------------------------------------------------------------------------*/\n\ntype MotionStyleProperty =\n | 'animation'\n | 'animationComposition'\n | 'animationDelay'\n | 'animationDirection'\n | 'animationDuration'\n | 'animationFillMode'\n | 'animationIterationCount'\n | 'animationName'\n | 'animationPlayState'\n | 'animationTimingFunction'\n | 'animationRange'\n | 'animationRangeStart'\n | 'animationRangeEnd'\n | 'animationTimeline'\n | 'transformOrigin'\n\nexport type MotionStyle = CompositionStyleObject<MotionStyleProperty>\n\nexport type MotionStyles = Recursive<Token<MotionStyle>>\n\nexport interface CompositionStyles {\n textStyles: TextStyles\n layerStyles: LayerStyles\n motionStyles: MotionStyles\n}\n"
}
1 change: 1 addition & 0 deletions packages/generator/src/artifacts/types/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const generateTypesEntry = (ctx: Context, isJsxRequired: boolean) => {
export function defineStyles(definition: SystemStyleObject): SystemStyleObject
export function defineGlobalStyles(definition: GlobalStyleObject): Panda.GlobalStyleObject
export function defineTextStyles(definition: CompositionStyles['textStyles']): Panda.TextStyles
export function defineMotionStyles(definition: CompositionStyles['motionStyles']): Panda.MotionStyles
export function defineLayerStyles(definition: CompositionStyles['layerStyles']): Panda.LayerStyles
export function definePattern<T extends PatternProperties>(config: PatternConfig<T>): Panda.PatternConfig
export function defineParts<T extends Parts>(parts: T): (config: Partial<Record<keyof T, SystemStyleObject>>) => Partial<Record<keyof T, SystemStyleObject>>
Expand Down
74 changes: 74 additions & 0 deletions packages/preset-panda/src/keyframes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,80 @@ export const keyframes = {
animationTimingFunction: 'cubic-bezier(0,0,0.2,1)',
},
},

// fade
'fade-in': {
from: { opacity: 0 },
to: { opacity: 1 },
},
'fade-out': {
from: { opacity: 1 },
to: { opacity: 0 },
},

// slide out of view
'slide-out-left': {
from: { translate: '-100% 0' },
to: { translate: '0 0' },
},
'slide-out-right': {
from: { translate: '100% 0' },
to: { translate: '0 0' },
},
'slide-out-up': {
from: { translate: '0 -100%' },
to: { translate: '0 0' },
},
'slide-out-down': {
from: { translate: '0 100%' },
to: { translate: '0 0' },
},

// slide from
'slide-from-top': {
'0%': { translate: '0 0.5rem' },
to: { translate: '0' },
},
'slide-from-bottom': {
'0%': { translate: '0 -0.5rem' },
to: { translate: '0' },
},
'slide-from-left': {
'0%': { translate: '0.5rem 0' },
to: { translate: '0' },
},
'slide-from-right': {
'0%': { translate: '-0.5rem 0' },
to: { translate: '0' },
},

// slide to
'slide-to-top': {
'0%': { translate: '0' },
to: { translate: '0 0.5rem' },
},
'slide-to-bottom': {
'0%': { translate: '0' },
to: { translate: '0 -0.5rem' },
},
'slide-to-left': {
'0%': { translate: '0' },
to: { translate: '0.5rem 0' },
},
'slide-to-right': {
'0%': { translate: '0' },
to: { translate: '-0.5rem 0' },
},

// scale
'scale-in': {
from: { scale: '0.97' },
to: { scale: '1' },
},
'scale-out': {
from: { scale: '1' },
to: { scale: '0.97' },
},
}

export const animations = {
Expand Down
26 changes: 26 additions & 0 deletions packages/studio/styled-system/types/composition.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,33 @@ export type LayerStyle = CompositionStyleObject<LayerStyleProperty>

export type LayerStyles = Recursive<Token<LayerStyle>>

/* -----------------------------------------------------------------------------
* Motion styles
* -----------------------------------------------------------------------------*/

type MotionStyleProperty =
| 'animation'
| 'animationComposition'
| 'animationDelay'
| 'animationDirection'
| 'animationDuration'
| 'animationFillMode'
| 'animationIterationCount'
| 'animationName'
| 'animationPlayState'
| 'animationTimingFunction'
| 'animationRange'
| 'animationRangeStart'
| 'animationRangeEnd'
| 'animationTimeline'
| 'transformOrigin'

export type MotionStyle = CompositionStyleObject<MotionStyleProperty>

export type MotionStyles = Recursive<Token<MotionStyle>>

export interface CompositionStyles {
textStyles: TextStyles
layerStyles: LayerStyles
motionStyles: MotionStyles
}
1 change: 1 addition & 0 deletions packages/studio/styled-system/types/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ declare module '@pandacss/dev' {
export function defineStyles(definition: SystemStyleObject): SystemStyleObject
export function defineGlobalStyles(definition: GlobalStyleObject): Panda.GlobalStyleObject
export function defineTextStyles(definition: CompositionStyles['textStyles']): Panda.TextStyles
export function defineMotionStyles(definition: CompositionStyles['motionStyles']): Panda.MotionStyles
export function defineLayerStyles(definition: CompositionStyles['layerStyles']): Panda.LayerStyles
export function definePattern<T extends PatternProperties>(config: PatternConfig<T>): Panda.PatternConfig
export function defineParts<T extends Parts>(parts: T): (config: Partial<Record<keyof T, SystemStyleObject>>) => Partial<Record<keyof T, SystemStyleObject>>
Expand Down
2 changes: 1 addition & 1 deletion packages/studio/styled-system/types/prop-type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export interface UtilityValues {
transitionDuration: Tokens["durations"];
transition: "all" | "common" | "background" | "colors" | "opacity" | "shadow" | "transform";
animation: Tokens["animations"];
animationName: "spin" | "ping" | "pulse" | "bounce";
animationName: "spin" | "ping" | "pulse" | "bounce" | "fade-in" | "fade-out" | "slide-out-left" | "slide-out-right" | "slide-out-up" | "slide-out-down" | "slide-from-top" | "slide-from-bottom" | "slide-from-left" | "slide-from-right" | "slide-to-top" | "slide-to-bottom" | "slide-to-left" | "slide-to-right" | "scale-in" | "scale-out";
animationTimingFunction: Tokens["easings"];
animationDuration: Tokens["durations"];
animationDelay: Tokens["durations"];
Expand Down
26 changes: 26 additions & 0 deletions packages/types/src/composition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,33 @@ export type LayerStyle = CompositionStyleObject<LayerStyleProperty>

export type LayerStyles = Recursive<Token<LayerStyle>>

/* -----------------------------------------------------------------------------
* Motion styles
* -----------------------------------------------------------------------------*/

type MotionStyleProperty =
| 'animation'
| 'animationComposition'
| 'animationDelay'
| 'animationDirection'
| 'animationDuration'
| 'animationFillMode'
| 'animationIterationCount'
| 'animationName'
| 'animationPlayState'
| 'animationTimingFunction'
| 'animationRange'
| 'animationRangeStart'
| 'animationRangeEnd'
| 'animationTimeline'
| 'transformOrigin'

export type MotionStyle = CompositionStyleObject<MotionStyleProperty>

export type MotionStyles = Recursive<Token<MotionStyle>>

export interface CompositionStyles {
textStyles: TextStyles
layerStyles: LayerStyles
motionStyles: MotionStyles
}
6 changes: 5 additions & 1 deletion packages/types/src/theme.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { LayerStyles, TextStyles } from './composition'
import type { LayerStyles, MotionStyles, TextStyles } from './composition'
import type { RecipeConfig, SlotRecipeConfig } from './recipe'
import type { CssKeyframes } from './system-types'
import type { SemanticTokens, Tokens } from './tokens'
Expand Down Expand Up @@ -28,6 +28,10 @@ export interface Theme {
* The layer styles for your project.
*/
layerStyles?: LayerStyles
/**
* The animation styles for your project.
*/
motionStyles?: MotionStyles
/**
* Multi-variant style definitions for your project.
* Useful for defining component styles.
Expand Down
Loading