From dde31f1cdf233f840db4707cf849d638aa9b6ee0 Mon Sep 17 00:00:00 2001 From: Alex Grozav Date: Wed, 8 Apr 2026 12:42:37 +0700 Subject: [PATCH 1/3] feat: Add Skeleton recipe with pulse animation and supporting utilities Add a Skeleton loading placeholder recipe with size (xs-xl) and rounded variants, plus a built-in skeleton-pulse keyframes animation. Includes animation longhand utilities, spacing support for height/width utilities, a fix for compound keyframe selectors, and documentation. --- .../02.composables/08.skeleton.md | 358 ++++++++++++++++++ .../components/skeleton/Skeleton.vue | 23 ++ .../skeleton/preview/SkeletonGrid.vue | 33 ++ .../skeleton/preview/SkeletonSizeGrid.vue | 16 + .../stories/components/skeleton.stories.ts | 98 +++++ .../stories/components/skeleton.styleframe.ts | 37 ++ engine/core/src/tokens/declarations.test.ts | 35 ++ engine/core/src/tokens/declarations.ts | 4 +- theme/src/presets/useUtilitiesPreset.ts | 58 +++ theme/src/recipes/index.ts | 1 + theme/src/recipes/skeleton/index.ts | 1 + .../skeleton/useSkeletonRecipe.test.ts | 144 +++++++ .../src/recipes/skeleton/useSkeletonRecipe.ts | 46 +++ .../utilities/sizing/useHeightUtility.test.ts | 12 + .../src/utilities/sizing/useHeightUtility.ts | 22 +- .../utilities/sizing/useWidthUtility.test.ts | 12 + theme/src/utilities/sizing/useWidthUtility.ts | 22 +- .../useAnimationUtility.test.ts | 168 +++++++- .../useAnimationUtility.ts | 42 ++ 19 files changed, 1116 insertions(+), 16 deletions(-) create mode 100644 apps/docs/content/docs/06.components/02.composables/08.skeleton.md create mode 100644 apps/storybook/src/components/components/skeleton/Skeleton.vue create mode 100644 apps/storybook/src/components/components/skeleton/preview/SkeletonGrid.vue create mode 100644 apps/storybook/src/components/components/skeleton/preview/SkeletonSizeGrid.vue create mode 100644 apps/storybook/stories/components/skeleton.stories.ts create mode 100644 apps/storybook/stories/components/skeleton.styleframe.ts create mode 100644 theme/src/recipes/skeleton/index.ts create mode 100644 theme/src/recipes/skeleton/useSkeletonRecipe.test.ts create mode 100644 theme/src/recipes/skeleton/useSkeletonRecipe.ts diff --git a/apps/docs/content/docs/06.components/02.composables/08.skeleton.md b/apps/docs/content/docs/06.components/02.composables/08.skeleton.md new file mode 100644 index 00000000..7eb87aa6 --- /dev/null +++ b/apps/docs/content/docs/06.components/02.composables/08.skeleton.md @@ -0,0 +1,358 @@ +--- +title: Skeleton +description: A loading placeholder component that displays a pulsing gray block to indicate content is being loaded. Supports multiple sizes and a rounded option through the recipe system. +--- + +## Overview + +The **Skeleton** is a loading placeholder element used to indicate that content is being fetched or processed. The `useSkeletonRecipe()` composable creates a fully configured [recipe](/docs/api/recipes) with size and rounded options, plus a built-in pulse animation via keyframes — no additional CSS required. + +The Skeleton recipe integrates directly with the default [design tokens preset](/docs/design-tokens/presets) and generates type-safe utility classes at build time with zero runtime CSS. + +## Why use the Skeleton recipe? + +The Skeleton recipe helps you: + +- **Ship faster with sensible defaults**: Get 5 sizes and a rounded option out of the box with a single composable call. +- **Animate without extra CSS**: The pulse keyframes animation is registered automatically when you use the recipe — no manual `@keyframes` definition needed. +- **Maintain consistency**: All skeleton placeholders share the same animation timing, colors, and border radius across your application. +- **Customize without forking**: Override base styles, default variants, or filter out options you don't need — all through the options API. +- **Stay type-safe**: Full TypeScript support means your editor catches invalid size values at compile time. +- **Integrate with your tokens**: Every value references the design tokens preset, so theme changes propagate automatically. +- **Support dark mode**: Background colors adapt automatically between light and dark color schemes. + +## Usage + +::steps{level="4"} + +#### Register the recipe + +Add the Skeleton recipe to a local Styleframe instance. The global `styleframe.config.ts` provides design tokens and utilities, while the component-level file registers the recipe itself: + +:::code-tree{default-value="src/components/skeleton.styleframe.ts"} + +```ts [src/components/skeleton.styleframe.ts] +import { styleframe } from 'virtual:styleframe'; +import { useSkeletonRecipe } from '@styleframe/theme'; + +const s = styleframe(); + +const skeleton = useSkeletonRecipe(s); + +export default s; +``` + +```ts [styleframe.config.ts] +import { styleframe } from 'styleframe'; +import { useDesignTokensPreset, useUtilitiesPreset } from '@styleframe/theme'; + +const s = styleframe(); + +useDesignTokensPreset(s); +useUtilitiesPreset(s); + +export default s; +``` + +::: + +#### Build the component + +Import the `skeleton` runtime function from the virtual module and pass variant props to compute class names: + +:::tabs +::::tabs-item{icon="i-devicon-react" label="React"} + +```ts [src/components/Skeleton.tsx] +import { skeleton } from "virtual:styleframe"; + +interface SkeletonProps { + size?: "xs" | "sm" | "md" | "lg" | "xl"; + rounded?: boolean; + className?: string; +} + +export function Skeleton({ + size = "md", + rounded = false, + className, +}: SkeletonProps) { + return ( +