diff --git a/README.md b/README.md index 8acceeb..2adbfdd 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,37 @@ const button = windctrl({ The scope classes are automatically prefixed with `group-data-[windctrl-scope=...]/windctrl-scope:` to target the parent's data attribute. +## Type Helpers (`StyleProps`) + +When building reusable components, you often want to expose the exact style-related props inferred from a `windctrl()` definition. + +WindCtrl exports a small type helper for this purpose: + +```typescript +import type { StyleProps } from "windctrl"; +``` + +`StyleProps` extracts all variant, trait, and dynamic props from a WindCtrl instance — similar to `VariantProps` in cva. + +```typescript +const button = windctrl({ ... }); + +type ButtonProps = { + as?: T; +} & Omit, keyof StyleProps> + & StyleProps; +``` + +This lets you: + +- Avoid manually duplicating variant/trait prop definitions +- Keep component props automatically in sync with styling config +- Refactor styles without touching component typings + +> `StyleProps` is optional - you can always define props manually if you prefer. + +> `wcProps` is provided as an alias of `StyleProps` for convenience. + ## Gotchas - **Tailwind JIT:** Tailwind only generates CSS for class names it can statically detect. Avoid constructing class strings dynamically unless you safelist them. diff --git a/examples/Button.tsx b/examples/Button.tsx index 363e6ea..aa3c750 100644 --- a/examples/Button.tsx +++ b/examples/Button.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { windctrl, dynamic as d, wcn } from "../src/index"; +import { windctrl, dynamic as d, wcn, type StyleProps } from "../src/index"; import type { ComponentPropsWithoutRef, ElementType } from "react"; const button = windctrl({ @@ -39,14 +39,8 @@ const button = windctrl({ type ButtonProps = { as?: T; - intent?: "primary" | "secondary" | "destructive" | "outline" | "ghost"; - size?: "sm" | "md" | "lg"; - traits?: - | Array<"loading" | "glass" | "disabled"> - | { loading?: boolean; glass?: boolean; disabled?: boolean }; - w?: string | number; - h?: string | number; -} & ComponentPropsWithoutRef; +} & Omit, keyof StyleProps> & + StyleProps; export function Button({ as, diff --git a/src/index.ts b/src/index.ts index b1caa2f..11b5d79 100644 --- a/src/index.ts +++ b/src/index.ts @@ -389,3 +389,7 @@ export const wc = windctrl; export function wcn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } + +// Extract the props type from a windctrl instance +export type StyleProps = T extends (props?: infer P) => any ? P : never; +export type wcProps = StyleProps;