diff --git a/.changeset/good-bobcats-sin.md b/.changeset/good-bobcats-sin.md new file mode 100644 index 0000000..170e257 --- /dev/null +++ b/.changeset/good-bobcats-sin.md @@ -0,0 +1,5 @@ +--- +"@rpxl/docs": patch +--- + +Improve recast tailwind docs diff --git a/.changeset/silly-moons-rush.md b/.changeset/silly-moons-rush.md new file mode 100644 index 0000000..04fbd55 --- /dev/null +++ b/.changeset/silly-moons-rush.md @@ -0,0 +1,5 @@ +--- +"@rpxl/recast": minor +--- + +Change nested classes prop from rcx to cls diff --git a/packages/docs/src/components/ui/button-demo/button-demo.ts b/packages/docs/src/components/ui/button-demo/button-demo.ts index b4b0bfc..6444810 100644 --- a/packages/docs/src/components/ui/button-demo/button-demo.ts +++ b/packages/docs/src/components/ui/button-demo/button-demo.ts @@ -59,7 +59,7 @@ export const Button = recast(ButtonPrimitive, { }, }, modifiers: { - pill: "rounded-full px-8", + pill: "!rounded-full !px-8", block: "w-full", floating: "shadow-lg", }, diff --git a/packages/docs/src/pages/advanced-usage.mdx b/packages/docs/src/pages/advanced-usage.mdx index 28c8264..b34a432 100644 --- a/packages/docs/src/pages/advanced-usage.mdx +++ b/packages/docs/src/pages/advanced-usage.mdx @@ -30,17 +30,17 @@ type Props = React.ComponentPropsWithoutRef & const Slider = forwardRef< React.ElementRef, Props ->(({ className, rcx, ...props }, ref) => { +>(({ className, cls, ...props }, ref) => { return ( - - + + - + ); }); @@ -61,6 +61,26 @@ export const Slider = recast(SliderPrimitive, { }); ``` +## TypeScript Integration + +Recast is designed to work seamlessly with TypeScript. When defining your +component props, you can use the `RecastWithClassNameProps` type to ensure type +safety for your nested class names: + +```jsx +import { RecastWithClassNameProps } from "@rpxl/recast"; + +type Props = YourComponentProps & + RecastWithClassNameProps<{ + root: string; + childElement: string; + // ... other nested elements + }>; +``` + +This approach provides excellent TypeScript support, enabling autocompletion and +type checking for your themed components. + ## Wrapping a Recast Component Sometimes you might want to wrap a Recast component to customize its behavior. @@ -110,32 +130,3 @@ ScrollArea.displayName = "ScrollArea"; This approach allows you to create more intuitive APIs for your components while still leveraging Recast's theming capabilities. - -## Performance Considerations - -When working with complex nested components or wrapping Recast components, keep -these performance tips in mind: - -1. Memoize child components when appropriate to prevent unnecessary re-renders. -2. Use the `useMemo` hook for expensive computations within your components. -3. Leverage Recast's conditional styling to avoid applying unnecessary classes. - -## TypeScript Integration - -Recast is designed to work seamlessly with TypeScript. When defining your -component props, you can use the `RecastWithClassNameProps` type to ensure type -safety for your nested class names: - -```jsx -import { RecastWithClassNameProps } from "@rpxl/recast"; - -type Props = YourComponentProps & - RecastWithClassNameProps<{ - root: string; - childElement: string; - // ... other nested elements - }>; -``` - -This approach provides excellent TypeScript support, enabling autocompletion and -type checking for your themed components. diff --git a/packages/docs/src/pages/index.mdx b/packages/docs/src/pages/index.mdx index 6de1fce..6739bad 100644 --- a/packages/docs/src/pages/index.mdx +++ b/packages/docs/src/pages/index.mdx @@ -66,4 +66,4 @@ for the open-source contributions of the following projects: CSS and excellent developer experience. - [Tailwind Variants](https://www.tailwind-variants.org/) - For combining the power of Tailwind with a first-class variant API, offering features like - slots, responsive variants, and component composition [^1]. + slots, responsive variants, and component composition. diff --git a/packages/docs/src/pages/quick-start.mdx b/packages/docs/src/pages/quick-start.mdx index d19c5c1..d1419bd 100644 --- a/packages/docs/src/pages/quick-start.mdx +++ b/packages/docs/src/pages/quick-start.mdx @@ -19,7 +19,7 @@ npm install @rpxl/recast If you're using Tailwind CSS, you can also install the Recast Tailwind plugin: ```bash -npm install @rpxl/recast-tailwind +npm install @rpxl/recast-tailwind-plugin ``` ## 2. Create a Component Primitive @@ -49,8 +49,15 @@ Import the component primitive and wrap it with a theme layer using Recast: import { recast } from "@rpxl/recast"; import { ButtonPrimitive } from "./ButtonPrimitive"; +// Create the Button component with Recast export const Button = recast(ButtonPrimitive, { + // Define the default values + defaults: { + variants: { variant: "primary", size: "md" }, + }, + // Define the base styles base: "inline-flex items-center justify-center rounded-md font-medium transition-colors", + // Define the variants variants: { variant: { primary: "bg-blue-500 text-white hover:bg-blue-600", @@ -63,75 +70,17 @@ export const Button = recast(ButtonPrimitive, { lg: "px-6 py-3 text-lg", }, }, + // Define the modifiers modifiers: { fullWidth: "w-full", }, - defaults: { - variants: { variant: "primary", size: "md" }, - }, }); ``` > **Note**: The example above uses Tailwind CSS classes, but Recast works with > any CSS classes or CSS-in-JS solution. -## 4. Tailwind CSS Integration (Optional) - -If you're using Tailwind CSS, add the Recast plugin to your -`tailwind.config.js`: - -```js -module.exports = { - // ...other config - plugins: [require("@rpxl/recast-tailwind")], -}; -``` - -This step is only necessary if you're using Tailwind CSS and want to leverage -the Recast Tailwind plugin features. - -### What the Tailwind CSS Integration Provides: - -1. **Automatic Safelist Generation**: The plugin automatically generates a - safelist for your Recast components, ensuring that all Tailwind classes used - in your Recast components are included in your production build, even if - they're not found in your templates. - -2. **Responsive Styling**: The plugin enables responsive styling for Recast - components using Tailwind's responsive syntax. For example: - - ```jsx - - ``` - - This button will be small by default and large on medium-sized screens and - above. The plugin will generate classes like: - - ```html - - ``` - - - Here, `px-3 py-2 text-sm` are applied by default, and `px-6 py-3 text-lg` - are applied with the `md:` prefix, activating them at the medium breakpoint - and above. - - -3. **Improved Performance**: The plugin optimizes the generation of Tailwind - classes for Recast components, potentially improving build times and reducing - CSS file size. - -4. **Better Integration**: It ensures that Recast and Tailwind work seamlessly - together, allowing you to leverage the full power of both libraries in your - project. - -This integration enhances the developer experience when using Recast with -Tailwind CSS, providing more flexibility and efficiency in styling your -components. - -## 5. Usage +## 4. Usage Now you can use your themed Button component with various props: @@ -147,7 +96,7 @@ function App() { {" "} + ); } @@ -273,4 +222,3 @@ to adjust styles without modifying the core component logic. -```` diff --git a/packages/docs/src/pages/tailwind-css.mdx b/packages/docs/src/pages/tailwind-css.mdx index 2b8f6c8..5615d61 100644 --- a/packages/docs/src/pages/tailwind-css.mdx +++ b/packages/docs/src/pages/tailwind-css.mdx @@ -1,5 +1,5 @@ import Image from "next/image"; -import { Steps } from "nextra/components"; +import { Steps, Callout } from "nextra/components"; # Recast Tailwind CSS Integration @@ -12,64 +12,54 @@ capabilities. First, install the Recast Tailwind plugin: ```bash -npm install @rpxl/recast-tailwind +npm install @rpxl/recast-tailwind-plugin ``` ## Setup -Add the plugin to your `tailwind.config.js` file: +If you're using Tailwind CSS, add the Recast plugin to your +`tailwind.config.js`: ```js -module.exports = { // ...other config plugins: -[require("@rpxl/recast-tailwind")], }; +module.exports = { + // ...other config + plugins: [require("@rpxl/recast-tailwind-plugin")], +}; ``` -This plugin automatically generates a safelist for your Recast components and -provides better integration with Tailwind CSS. +This step is necessary if you're using Tailwind CSS and want to leverage the +Recast Tailwind plugin's features. -## Features +### What the Tailwind CSS Integration Provides: -1. **Automatic Safelist Generation**: Ensures all your Recast component classes - are included in your production build. -2. **Responsive Styling**: Easily apply responsive styles to your Recast - components using Tailwind's breakpoint syntax. -3. **Improved Performance**: Optimizes class generation for better runtime - performance. +1. **Automatic Safelist Generation**: The plugin automatically generates a + safelist for your Recast components based on the breakpoints specified in + your component definitions. This ensures that all Tailwind classes used in + your Recast components are included in your production build, even if they + aren't explicitly used in your templates. -## VS Code Setup - -To get Tailwind CSS IntelliSense working with Recast in VS Code: - -1. Install the - [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) - VS Code extension. - -2. Add the following to your `.vscode/settings.json`: - -```json -{ - "tailwindCSS.experimental.classRegex": [ - ["recast\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] - ] -} -``` - -## Responsive Styling Example - -With the Recast Tailwind plugin, you can easily apply responsive styles: - -### Responsive Variants +2. **Responsive Styling**: The plugin enables responsive styling for Recast + components using Tailwind's responsive syntax. Responsive component features + are opt-in on a per-component basis. For example: ```jsx -const Button = recast(ButtonPrimitive, { variants: { size: { sm: "px-2 py-1 -text-sm", md: "px-4 py-2 text-base", lg: "px-6 py-3 text-lg", }, }, }); +const Button = recast(ButtonPrimitive, { + variants: { + size: { + sm: "px-2 py-1 text-sm", + md: "px-4 py-2 text-base", + lg: "px-6 py-3 text-lg", + }, + }, + // Only allow these breakpoints to be + // used within the button component + breakpoints: ["sm", "md", "lg"], +}); -// Usage - +; ``` -This button will be small by default, medium on md screens, and large on lg -screens. The plugin will generate classes like: +Will generate the following classes: ```html ; -``` - -The plugin generates HTML with classes like this: +This integration significantly enhances the developer experience when using +Recast with Tailwind CSS, offering increased flexibility and efficiency in +styling components. -```jsx - -``` +## VS Code Setup -### Custom Unset Utility +To get Tailwind CSS IntelliSense working with Recast in VS Code: -The Recast Tailwind plugin introduces a custom `unset` utility that allows you -to remove previously applied styles at specific breakpoints. This is -particularly useful when working with responsive modifiers. +1. Install the + [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) + VS Code extension. -#### How it works +2. Add the following to your `.vscode/settings.json`: -The `unset` utility is automatically added to your Tailwind configuration when -you use the Recast Tailwind plugin allows you to "turn off" a style at a -specific breakpoint. +```json +{ + "tailwindCSS.experimental.classRegex": [ + ["recast\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] + ] +} +``` ## Prettier Integration @@ -137,12 +129,10 @@ sorted. If you encounter any issues with the Tailwind CSS integration: -1. Ensure you've installed both `@rpxl/recast` and `@rpxl/recast-tailwind`. +1. Ensure you've installed both `@rpxl/recast` and + `@rpxl/recast-tailwind-plugin`. 2. Verify that the Recast Tailwind plugin is correctly added to your `tailwind.config.js`. 3. Check that your VS Code settings are correctly configured for Tailwind CSS IntelliSense. 4. Clear your build cache and restart your development server. - -By following these guidelines and leveraging the Recast Tailwind plugin, you can -create powerful, flexible, and responsive components with ease. diff --git a/packages/docs/src/pages/theming.mdx b/packages/docs/src/pages/theming.mdx index 2556d3c..c31976f 100644 --- a/packages/docs/src/pages/theming.mdx +++ b/packages/docs/src/pages/theming.mdx @@ -257,16 +257,16 @@ export const Button = recast(ButtonPrimitive, { - + - ```tsx /floating/ /block/ + ```tsx /floating/ /block/ /pill/ import { Button } from "@/components/ui/button" export function ButtonDemo() { return ( - + ) } ``` diff --git a/packages/lib/CHANGELOG.md b/packages/lib/CHANGELOG.md index 522640e..dc1c77c 100644 --- a/packages/lib/CHANGELOG.md +++ b/packages/lib/CHANGELOG.md @@ -34,7 +34,7 @@ ### Patch Changes -- 63cc987: Remove unused rcx props from Recast components +- 63cc987: Remove unused cls props from Recast components ## 4.0.1 diff --git a/packages/lib/src/__tests__/getRecastClasses.test.ts b/packages/lib/src/__tests__/getRecastClasses.test.ts index c3ac4d7..c256ae9 100644 --- a/packages/lib/src/__tests__/getRecastClasses.test.ts +++ b/packages/lib/src/__tests__/getRecastClasses.test.ts @@ -368,7 +368,7 @@ describe("getRecastClasses", () => { }); describe("RCX Output", () => { - it("should generate correct rcx output", () => { + it("should generate correct cls output", () => { const styles: RelaxedStyles = { base: { default: "text-base", md: "text-lg" }, variants: { @@ -379,7 +379,7 @@ describe("getRecastClasses", () => { }; const variants: RelaxedVariantProps = { color: "red" }; const result = getRecastClasses({ styles, variants, modifiers: {} }); - expect(result.rcx).toEqual({ + expect(result.cls).toEqual({ default: "text-base text-red-500", md: "text-lg", dark: "text-red-300", diff --git a/packages/lib/src/__tests__/recast.test.tsx b/packages/lib/src/__tests__/recast.test.tsx index 3148da7..d7d74ef 100644 --- a/packages/lib/src/__tests__/recast.test.tsx +++ b/packages/lib/src/__tests__/recast.test.tsx @@ -414,13 +414,13 @@ describe("recast function", () => { className?: string; }; - const SliderPrimitive = React.forwardRef(({ className, rcx, ...props }, ref) => { + const SliderPrimitive = React.forwardRef(({ className, cls, ...props }, ref) => { return ( -
-
-
+
+
+
-
+
); }); diff --git a/packages/lib/src/constants.ts b/packages/lib/src/constants.ts index afeb29f..f569fdc 100644 --- a/packages/lib/src/constants.ts +++ b/packages/lib/src/constants.ts @@ -13,4 +13,4 @@ import type { RelaxedRecastStyleProps } from "./types.js"; * return userStyles || RECAST_STYLE_PROPS; * } */ -export const RECAST_STYLE_PROPS: RelaxedRecastStyleProps = { className: "", rcx: {} }; +export const RECAST_STYLE_PROPS: RelaxedRecastStyleProps = { className: "", cls: {} }; diff --git a/packages/lib/src/recast.tsx b/packages/lib/src/recast.tsx index 81de0e8..e61c824 100644 --- a/packages/lib/src/recast.tsx +++ b/packages/lib/src/recast.tsx @@ -22,7 +22,7 @@ import { omit, isEmptyObject, isString, isNonNullObject } from "./utils/common.j * @template M - The modifier options * @template B - The breakpoint options * @param {React.ComponentType

} Component - The base component to add theming to - * @param {RecastStyles, B>} styles - The styles to apply to the component + * @param {RecastStyles, B>} styles - The styles to apply to the component * @param {MergeFn} [mergeFn] - Optional function to merge props * @returns {RecastComponent} A new component with theming capabilities */ @@ -31,7 +31,7 @@ export function recast< V extends { [K in keyof V]: { [S in keyof V[K]]: string | string[] } }, M extends { [K in keyof M]: string | string[] }, B extends keyof RecastBreakpoints | never = never, ->(Component: React.ComponentType

, styles: RecastStyles, B>, mergeFn?: MergeFn) { +>(Component: React.ComponentType

, styles: RecastStyles, B>, mergeFn?: MergeFn) { type Props = Omit | keyof ExtractModifierProps> & ExtractVariantProps & ExtractModifierProps & { className?: string }; @@ -69,7 +69,7 @@ export function recast< restProps, ); - const { className: recastClassesClassName, rcx } = getRecastClasses({ + const { className: recastClassesClassName, cls } = getRecastClasses({ styles: styles as RelaxedStyles, variants: variantProps, modifiers: modifierProps, @@ -85,7 +85,7 @@ export function recast< {...(propsWithoutModifiersAndVariants as P)} ref={ref} className={mergedClassName} - rcx={isEmptyObject(rcx) ? undefined : rcx} + cls={isEmptyObject(cls) ? undefined : cls} /> ); }); diff --git a/packages/lib/src/types.ts b/packages/lib/src/types.ts index eb9d2fb..a01e18e 100644 --- a/packages/lib/src/types.ts +++ b/packages/lib/src/types.ts @@ -24,11 +24,11 @@ export type Leaves = { }[keyof T]; /** - * Adds an optional `rcx` prop to a component's props for Recast class object properties. + * Adds an optional `cls` prop to a component's props for Recast class object properties. */ export type RecastWithClassNameProps = { /** Recast class object properties */ - rcx?: { [P in keyof Props]?: string }; + cls?: { [P in keyof Props]?: string }; }; /** @@ -55,7 +55,7 @@ export type ExtractVariantProps = V extends object /** * Base props for Recast components. */ -export type RecastProps = { [K in keyof T]: T[K] } & { rcx?: object }; +export type RecastProps = { [K in keyof T]: T[K] } & { cls?: object }; /** * Configuration object for Recast styles. @@ -187,7 +187,7 @@ export type RelaxedCondition = { */ export type RelaxedRecastStyleProps = { className: string; - rcx: ClassNameRecord; + cls: ClassNameRecord; }; /** diff --git a/packages/lib/src/utils/common.ts b/packages/lib/src/utils/common.ts index 0efa825..1d16da6 100644 --- a/packages/lib/src/utils/common.ts +++ b/packages/lib/src/utils/common.ts @@ -47,21 +47,21 @@ export const normalizeClasses = (classes?: string | string[]): string => { /** * Generates responsive classes based on the input. * @param classes - The input classes. - * @returns An object containing className and rcx properties. + * @returns An object containing className and cls properties. */ export const generateResponsiveClasses = (classes: string | string[] | ClassNameRecord): RelaxedRecastStyleProps => { if (!classes) return RECAST_STYLE_PROPS; if (isString(classes) || isStringArray(classes)) { - return { className: normalizeClasses(classes), rcx: {} }; + return { className: normalizeClasses(classes), cls: {} }; } - const rcx: ClassNameRecord = Object.entries(classes).reduce((acc, [key, value]) => { + const cls: ClassNameRecord = Object.entries(classes).reduce((acc, [key, value]) => { acc[key] = normalizeClasses(value); return acc; }, {} as ClassNameRecord); - return { className: "", rcx }; + return { className: "", cls }; }; /** @@ -204,7 +204,7 @@ export function isValidBreakpoint( * Prefixes all classes in a RelaxedRecastStyleProps object with a given prefix. * * This function is useful for adding breakpoint prefixes to classes in responsive designs. - * It handles both the `className` string and the `rcx` object, ensuring all classes are prefixed. + * It handles both the `className` string and the `cls` object, ensuring all classes are prefixed. * * @param {RelaxedRecastStyleProps} classes - The original classes object to be prefixed. * @param {string} prefix - The prefix to be added to each class. @@ -213,13 +213,13 @@ export function isValidBreakpoint( * @example * const original = { * className: "text-red-500 bg-blue-300", - * rcx: { hover: "text-blue-500", focus: ["outline-none", "ring-2"] } + * cls: { hover: "text-blue-500", focus: ["outline-none", "ring-2"] } * }; * const prefixed = prefixClasses(original, "md:"); * // Result: * // { * // className: "md:text-red-500 md:bg-blue-300", - * // rcx: { hover: "md:text-blue-500", focus: "md:outline-none md:ring-2" } + * // cls: { hover: "md:text-blue-500", focus: "md:outline-none md:ring-2" } * // } */ export const prefixResponsiveClasses = (classes: RelaxedRecastStyleProps, prefix: string): RelaxedRecastStyleProps => ({ @@ -227,10 +227,10 @@ export const prefixResponsiveClasses = (classes: RelaxedRecastStyleProps, prefix .split(" ") .map((cls) => `${prefix}${cls}`) .join(" "), - rcx: Object.entries(classes.rcx).reduce((rcxAcc, [rcxKey, rcxValue]) => { - rcxAcc[rcxKey] = (Array.isArray(rcxValue) ? rcxValue : rcxValue.split(" ")) + cls: Object.entries(classes.cls).reduce((clsAcc, [clsKey, clsValue]) => { + clsAcc[clsKey] = (Array.isArray(clsValue) ? clsValue : clsValue.split(" ")) .map((cls) => `${prefix}${cls}`) .join(" "); - return rcxAcc; + return clsAcc; }, {}), }); diff --git a/packages/lib/src/utils/generateResponsiveClasses.ts b/packages/lib/src/utils/generateResponsiveClasses.ts index 50cb538..0436bc6 100644 --- a/packages/lib/src/utils/generateResponsiveClasses.ts +++ b/packages/lib/src/utils/generateResponsiveClasses.ts @@ -6,19 +6,19 @@ import { normalizeClasses, isString, isStringArray } from "./common.js"; * Generates responsive classes based on the input. * * @param {string | string[] | ClassNameRecord} classes - The input classes - * @returns {RelaxedRecastStyleProps} An object containing className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing className and cls properties */ export const generateResponsiveClasses = (classes: string | string[] | ClassNameRecord): RelaxedRecastStyleProps => { if (!classes) return RECAST_STYLE_PROPS; if (isString(classes) || isStringArray(classes)) { - return { className: normalizeClasses(classes), rcx: {} }; + return { className: normalizeClasses(classes), cls: {} }; } - const rcx: ClassNameRecord = Object.entries(classes).reduce((acc, [key, value]) => { + const cls: ClassNameRecord = Object.entries(classes).reduce((acc, [key, value]) => { acc[key] = normalizeClasses(value); return acc; }, {} as ClassNameRecord); - return { className: "", rcx }; + return { className: "", cls }; }; diff --git a/packages/lib/src/utils/getBaseClasses.ts b/packages/lib/src/utils/getBaseClasses.ts index 758a887..7756c75 100644 --- a/packages/lib/src/utils/getBaseClasses.ts +++ b/packages/lib/src/utils/getBaseClasses.ts @@ -11,7 +11,7 @@ type GetBaseClassesProps = { * * @template B - String literal type for breakpoints * @param {GetBaseClassesProps} props - The input properties. - * @returns {RelaxedRecastStyleProps} An object containing className and rcx properties. + * @returns {RelaxedRecastStyleProps} An object containing className and cls properties. */ export const getBaseClasses = ({ styles }: GetBaseClassesProps): RelaxedRecastStyleProps => { if (!styles?.base) { @@ -21,15 +21,15 @@ export const getBaseClasses = ({ styles }: GetBaseClassesProps const { base } = styles; if (isString(base)) { - return { className: base.trim(), rcx: {} }; + return { className: base.trim(), cls: {} }; } if (isStringArray(base)) { - return { className: base.filter(Boolean).join(" ").trim(), rcx: {} }; + return { className: base.filter(Boolean).join(" ").trim(), cls: {} }; } if (isNonNullObject(base)) { - return { className: "", rcx: base }; + return { className: "", cls: base }; } // Handle unexpected input diff --git a/packages/lib/src/utils/getConditionalClasses.ts b/packages/lib/src/utils/getConditionalClasses.ts index ca676db..7be23fe 100644 --- a/packages/lib/src/utils/getConditionalClasses.ts +++ b/packages/lib/src/utils/getConditionalClasses.ts @@ -15,7 +15,7 @@ type GetConditionalClassesProps = { * * @template B - String literal type for breakpoints * @param {GetConditionalClassesProps} props - The input properties - * @returns {RelaxedRecastStyleProps} An object containing the generated className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing the generated className and cls properties */ export const getConditionalClasses = ({ styles, @@ -41,7 +41,7 @@ export const getConditionalClasses = ({ const responsiveClasses = generateResponsiveClasses(condition.className); return { className: mergeArrays(acc.className.split(" "), responsiveClasses.className.split(" ")).join(" "), - rcx: isEmptyObject(responsiveClasses.rcx) ? acc.rcx : { ...acc.rcx, ...responsiveClasses.rcx }, + cls: isEmptyObject(responsiveClasses.cls) ? acc.cls : { ...acc.cls, ...responsiveClasses.cls }, }; } diff --git a/packages/lib/src/utils/getDefaultModifierClasses.ts b/packages/lib/src/utils/getDefaultModifierClasses.ts index 82566f4..eaf1bbb 100644 --- a/packages/lib/src/utils/getDefaultModifierClasses.ts +++ b/packages/lib/src/utils/getDefaultModifierClasses.ts @@ -12,7 +12,7 @@ type GetDefaultModifierClassesProps = { * * @template B - String literal type for breakpoints * @param {GetDefaultModifierClassesProps} props - The input properties - * @returns {RelaxedRecastStyleProps} An object containing the generated className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing the generated className and cls properties */ export const getDefaultModifierClasses = ({ styles, @@ -35,7 +35,7 @@ export const getDefaultModifierClasses = ({ return { className: mergeArrays(acc.className.split(" "), classesArray).join(" "), - rcx: acc.rcx, + cls: acc.cls, }; }, RECAST_STYLE_PROPS); }; diff --git a/packages/lib/src/utils/getDefaultVariantClasses.ts b/packages/lib/src/utils/getDefaultVariantClasses.ts index 21191d0..db5608e 100644 --- a/packages/lib/src/utils/getDefaultVariantClasses.ts +++ b/packages/lib/src/utils/getDefaultVariantClasses.ts @@ -11,7 +11,7 @@ type GetDefaultVariantClassesProps = { * Generates default variant classes based on the provided styles and variants. * * @param {GetDefaultVariantClassesProps} props - The input properties - * @returns {RelaxedRecastStyleProps} An object containing the generated className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing the generated className and cls properties */ export const getDefaultVariantClasses = ({ styles, @@ -33,7 +33,7 @@ export const getDefaultVariantClasses = ({ return { className: mergeArrays(acc.className.split(" "), responsiveClasses.className.split(" ")).join(" "), - rcx: isEmptyObject(responsiveClasses.rcx) ? acc.rcx : { ...acc.rcx, ...responsiveClasses.rcx }, + cls: isEmptyObject(responsiveClasses.cls) ? acc.cls : { ...acc.cls, ...responsiveClasses.cls }, }; }, RECAST_STYLE_PROPS); }; diff --git a/packages/lib/src/utils/getModifierClasses.ts b/packages/lib/src/utils/getModifierClasses.ts index 4c54c1d..c9223ee 100644 --- a/packages/lib/src/utils/getModifierClasses.ts +++ b/packages/lib/src/utils/getModifierClasses.ts @@ -12,7 +12,7 @@ type GetModifierClassesProps = { * Generates modifier classes based on the provided styles and modifiers. * * @param {GetModifierClassesProps} props - The input properties - * @returns {RelaxedRecastStyleProps} An object containing the generated className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing the generated className and cls properties */ export const getModifierClasses = ({ styles, @@ -28,7 +28,7 @@ export const getModifierClasses = ({ const classes = generateResponsiveClasses(modifierStyles); return { className: mergeStringClassNames(acc.className, classes.className), - rcx: mergeObjectClassNames(acc.rcx, classes.rcx), + cls: mergeObjectClassNames(acc.cls, classes.cls), }; } diff --git a/packages/lib/src/utils/getRecastClasses.ts b/packages/lib/src/utils/getRecastClasses.ts index 09027a6..b7db0d8 100644 --- a/packages/lib/src/utils/getRecastClasses.ts +++ b/packages/lib/src/utils/getRecastClasses.ts @@ -25,7 +25,7 @@ type ClassGeneratorProps = { * Generates and combines CSS classes based on the provided styles, variants, and modifiers. * * @param {RecastClasses} params - The input parameters - * @returns {RelaxedRecastStyleProps} An object containing the generated className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing the generated className and cls properties */ export function getRecastClasses({ styles, @@ -53,12 +53,12 @@ export function getRecastClasses({ const generated = generator({ styles, variants, modifiers }); return { className: mergeStringClassNames(acc.className, generated.className), - rcx: mergeObjectClassNames(acc.rcx, generated.rcx), + cls: mergeObjectClassNames(acc.cls, generated.cls), }; }, RECAST_STYLE_PROPS); // Ensure className is always a string const className = Array.isArray(result.className) ? result.className.join(" ") : result.className; - return { className, rcx: result.rcx }; + return { className, cls: result.cls }; } diff --git a/packages/lib/src/utils/getVariantClasses.ts b/packages/lib/src/utils/getVariantClasses.ts index b9a7d46..a0ad020 100644 --- a/packages/lib/src/utils/getVariantClasses.ts +++ b/packages/lib/src/utils/getVariantClasses.ts @@ -12,7 +12,7 @@ type GetVariantClassesProps = { * Generates variant classes based on the provided styles and variants. * * @param {GetVariantClassesProps} props - The input properties - * @returns {RelaxedRecastStyleProps} An object containing the generated className and rcx properties + * @returns {RelaxedRecastStyleProps} An object containing the generated className and cls properties */ export const getVariantClasses = ({ styles, @@ -52,7 +52,7 @@ const processStringVariant = ( const responsiveClasses = generateResponsiveClasses(variantStyles); return { className: mergeStringClassNames(acc.className, responsiveClasses.className), - rcx: mergeObjectClassNames(acc.rcx, responsiveClasses.rcx), + cls: mergeObjectClassNames(acc.cls, responsiveClasses.cls), }; }; @@ -77,7 +77,7 @@ const processResponsiveVariant = ( return { className: mergeStringClassNames(innerAcc.className, prefixedClasses.className), - rcx: mergeObjectClassNames(innerAcc.rcx, prefixedClasses.rcx), + cls: mergeObjectClassNames(innerAcc.cls, prefixedClasses.cls), }; } } @@ -88,6 +88,6 @@ const processResponsiveVariant = ( return { className: mergeStringClassNames(acc.className, responsiveClasses.className), - rcx: mergeObjectClassNames(acc.rcx, responsiveClasses.rcx), + cls: mergeObjectClassNames(acc.cls, responsiveClasses.cls), }; }; diff --git a/packages/primitives/src/components/accordion/accordion-content.tsx b/packages/primitives/src/components/accordion/accordion-content.tsx index 6fd80e6..e52dffc 100644 --- a/packages/primitives/src/components/accordion/accordion-content.tsx +++ b/packages/primitives/src/components/accordion/accordion-content.tsx @@ -14,14 +14,14 @@ type Props = React.ComponentPropsWithoutRef< const Component = React.forwardRef< React.ElementRef, Props ->(({ className, rcx, children, ...props }, ref) => { +>(({ className, cls, children, ...props }, ref) => { return ( -

{children}
+
{children}
); }); diff --git a/packages/primitives/src/components/accordion/accordion-trigger.tsx b/packages/primitives/src/components/accordion/accordion-trigger.tsx index d278852..059ff31 100644 --- a/packages/primitives/src/components/accordion/accordion-trigger.tsx +++ b/packages/primitives/src/components/accordion/accordion-trigger.tsx @@ -19,18 +19,18 @@ const Component = React.forwardRef< Props >( ( - { className, children, icon: Icon = ChevronDownIcon, rcx, ...props }, + { className, children, icon: Icon = ChevronDownIcon, cls, ...props }, ref, ) => { return ( - + {children} - + ); diff --git a/packages/primitives/src/components/checkbox/checkbox.tsx b/packages/primitives/src/components/checkbox/checkbox.tsx index 0832159..8731da3 100644 --- a/packages/primitives/src/components/checkbox/checkbox.tsx +++ b/packages/primitives/src/components/checkbox/checkbox.tsx @@ -17,15 +17,15 @@ type Props = React.ComponentPropsWithoutRef< const Component = forwardRef< React.ElementRef, Props ->(({ className, rcx, icon: Icon = CheckIcon, ...props }, ref) => { +>(({ className, cls, icon: Icon = CheckIcon, ...props }, ref) => { return ( - - + + ); diff --git a/packages/primitives/src/components/progress/progress.tsx b/packages/primitives/src/components/progress/progress.tsx index d053c60..359b664 100644 --- a/packages/primitives/src/components/progress/progress.tsx +++ b/packages/primitives/src/components/progress/progress.tsx @@ -14,15 +14,15 @@ type Props = React.ComponentPropsWithoutRef< const Component = forwardRef< React.ElementRef, Props ->(({ className, rcx, value, ...props }, ref) => { +>(({ className, cls, value, ...props }, ref) => { return ( diff --git a/packages/primitives/src/components/radio-group/radio-group-item.tsx b/packages/primitives/src/components/radio-group/radio-group-item.tsx index 5678b7b..ab218c7 100644 --- a/packages/primitives/src/components/radio-group/radio-group-item.tsx +++ b/packages/primitives/src/components/radio-group/radio-group-item.tsx @@ -17,15 +17,15 @@ type Props = React.ComponentPropsWithoutRef< const Component = forwardRef< React.ElementRef, Props ->(({ className, icon: Icon = CheckIcon, rcx, ...props }, ref) => { +>(({ className, icon: Icon = CheckIcon, cls, ...props }, ref) => { return ( - - + + ); diff --git a/packages/primitives/src/components/scroll-area/scroll-area.tsx b/packages/primitives/src/components/scroll-area/scroll-area.tsx index 68b8249..d3cb3cf 100644 --- a/packages/primitives/src/components/scroll-area/scroll-area.tsx +++ b/packages/primitives/src/components/scroll-area/scroll-area.tsx @@ -23,23 +23,23 @@ type Props = React.ComponentPropsWithoutRef< const Component = forwardRef< React.ElementRef, Props ->(({ className, rcx, children, orientation = "vertical", ...props }, ref) => { +>(({ className, cls, children, orientation = "vertical", ...props }, ref) => { return ( - + {children} - + - + ); }); diff --git a/packages/primitives/src/components/section-wrapper/section-wrapper.tsx b/packages/primitives/src/components/section-wrapper/section-wrapper.tsx index dc59149..17d32c0 100644 --- a/packages/primitives/src/components/section-wrapper/section-wrapper.tsx +++ b/packages/primitives/src/components/section-wrapper/section-wrapper.tsx @@ -11,12 +11,12 @@ type Props = React.HTMLAttributes & { }>; const Component = forwardRef( - ({ rcx, children, className, asChild, ...props }, ref) => { + ({ cls, children, className, asChild, ...props }, ref) => { const Comp = asChild ? Slot : "section"; return ( - -
{children}
+ +
{children}
); }, diff --git a/packages/primitives/src/components/slider/slider.tsx b/packages/primitives/src/components/slider/slider.tsx index c1d2879..008375e 100644 --- a/packages/primitives/src/components/slider/slider.tsx +++ b/packages/primitives/src/components/slider/slider.tsx @@ -14,17 +14,17 @@ type Props = React.ComponentPropsWithoutRef & const Component = forwardRef< React.ElementRef, Props ->(({ className, rcx, ...props }, ref) => { +>(({ className, cls, ...props }, ref) => { return ( - - + + - + ); }); diff --git a/packages/primitives/src/components/switch/switch.tsx b/packages/primitives/src/components/switch/switch.tsx index d9a71a2..f3220e8 100644 --- a/packages/primitives/src/components/switch/switch.tsx +++ b/packages/primitives/src/components/switch/switch.tsx @@ -12,14 +12,14 @@ type Props = React.ComponentPropsWithoutRef & const Component = forwardRef< React.ElementRef, Props ->(({ className, rcx, ...props }, ref) => { +>(({ className, cls, ...props }, ref) => { return ( - + ); }); diff --git a/packages/primitives/src/components/toggle/toggle.tsx b/packages/primitives/src/components/toggle/toggle.tsx index 133e164..8d41d0a 100644 --- a/packages/primitives/src/components/toggle/toggle.tsx +++ b/packages/primitives/src/components/toggle/toggle.tsx @@ -12,11 +12,11 @@ type Props = React.ComponentPropsWithoutRef & const Component = forwardRef< React.ElementRef, Props ->(({ rcx, className, ...props }, ref) => { +>(({ cls, className, ...props }, ref) => { return ( ); diff --git a/packages/recast-tailwind-plugin/README.md b/packages/recast-tailwind-plugin/README.md index e82568f..dee39d5 100644 --- a/packages/recast-tailwind-plugin/README.md +++ b/packages/recast-tailwind-plugin/README.md @@ -17,7 +17,7 @@ Add the plugin to your `tailwind.config.js` file: ```js module.exports = { // ...other config - plugins: [require("@rpxl/recast-tailwind")], + plugins: [require("@rpxl/recast-tailwind-plugin")], }; ``` @@ -60,6 +60,7 @@ const Button = recast(ButtonPrimitive, { lg: "px-6 py-3 text-lg", }, }, + breakpoints: ["sm", "md", "lg"], }); ; @@ -75,24 +76,6 @@ This button will be small by default, medium on md screens, and large on lg scre ``` -### Modifiers - -Recast also supports modifiers with Tailwind CSS. Here's how you can use them: - -```jsx -const Button = recast(ButtonPrimitive, { - modifiers: { pill: "rounded-full" }, -}); - -; -``` - -The plugin generates HTML with classes like this: - -```html - -``` - ## Prettier Integration Recast works seamlessly with the [prettier-plugin-tailwindcss](https://github.com/tailwindlabs/prettier-plugin-tailwindcss). Add the following to your `.prettierrc`: @@ -117,53 +100,4 @@ export const breakpoints = { }; ``` -These breakpoints are then used in your Recast components for responsive styling. - -## Plugin Implementation - -The Recast Tailwind plugin handles the generation of safelist classes based on your component definitions and usages. - -```ts -usages.forEach((usage) => { - const component = components[usage.componentName]; - if (!component) { - return; - } - - // Add base classes to safelist - if (component.base) { - addToSafelist(safelist, component.base); - } - - Object.entries(usage.props).forEach(([propName, propValue]) => { - const variantGroup = component.variants?.[propName]; - if (!variantGroup) { - return; - } - - if (typeof propValue === "object" && propValue !== null) { - Object.entries(propValue).forEach(([breakpoint, value]) => { - if (typeof value === "string") { - const classes = variantGroup[value]; - if (classes) { - addToSafelist( - safelist, - classes, - breakpoint !== "default" ? breakpoint : "" - ); - } - } - }); - } else if (typeof propValue === "string") { - const classes = variantGroup[propValue]; - if (classes) { - addToSafelist(safelist, classes); - } - } - }); -}); -``` - -This implementation ensures that all necessary classes for your Recast components are included in your final CSS, even when using dynamic class generation. - -By following this setup and usage guide, you can leverage the full power of Recast with Tailwind CSS, creating flexible and responsive components with ease. +These breakpoints can then used in your Recast components for responsive styling. diff --git a/packages/recast-tailwind-plugin/src/__tests__/index.test.ts b/packages/recast-tailwind-plugin/src/__tests__/index.test.ts index 4b369bf..bc8a7bf 100644 --- a/packages/recast-tailwind-plugin/src/__tests__/index.test.ts +++ b/packages/recast-tailwind-plugin/src/__tests__/index.test.ts @@ -171,10 +171,10 @@ describe("Recast Tailwind Plugin", () => { }>; const Component = forwardRef( - ({ rcx, children, as: Tag = "section", className, ...props }, ref) => { + ({ cls, children, as: Tag = "section", className, ...props }, ref) => { return ( - -
{children}
+ +
{children}
); },