Compare commits

...

4 Commits

Author SHA1 Message Date
shadcn
8392c7fa0c feat(cli): add css updates 2024-01-18 21:06:20 +04:00
Thomas Marrec
a465432a66 fix(carousel): adjust types for embla-carousel-react@8 (#2326)
Fixes #2322 , #2281 

Thanks to @akynau & @nianiam
2024-01-18 07:22:45 +00:00
Oguz Kazkayasi
7822e06904 Adds missing display names to Pagination Elements (#2178)
* fix: add missing pagination names

* chore: build registry

---------

Co-authored-by: shadcn <m@shadcn.com>
2024-01-18 11:08:25 +04:00
Takeshi Kriang
578d2c1823 fix(pagination): remove incorrect nested li from pagination link (#2190)
* feat: remove PaginationItem

* chore: build registry

---------

Co-authored-by: shadcn <m@shadcn.com>
2024-01-18 10:58:22 +04:00
17 changed files with 673 additions and 45 deletions

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
"files": [
{
"name": "pagination.tsx",
"content": "import * as React from \"react\"\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ButtonProps, buttonVariants } from \"@/registry/default/ui/button\"\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n)\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n))\nPaginationContent.displayName = \"PaginationContent\"\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(\"\", className)} {...props} />\n))\nPaginationItem.displayName = \"PaginationItem\"\n\ntype PaginationLinkProps = {\n isActive?: boolean\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<\"a\">\n\nconst PaginationLink = ({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) => (\n <PaginationItem>\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n </PaginationItem>\n)\nPaginationLink.displayName = \"PaginationLink\"\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n <span>Previous</span>\n </PaginationLink>\n)\nPaginationPrevious.displayName = \"PaginationPrevious\"\n\nconst PaginationNext = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <ChevronRight className=\"h-4 w-4\" />\n </PaginationLink>\n)\n\nconst PaginationEllipsis = ({\n className,\n ...props\n}: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n)\n\nexport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n}\n"
"content": "import * as React from \"react\"\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ButtonProps, buttonVariants } from \"@/registry/default/ui/button\"\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n)\nPagination.displayName = \"Pagination\"\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n))\nPaginationContent.displayName = \"PaginationContent\"\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(\"\", className)} {...props} />\n))\nPaginationItem.displayName = \"PaginationItem\"\n\ntype PaginationLinkProps = {\n isActive?: boolean\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<\"a\">\n\nconst PaginationLink = ({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) => (\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n)\nPaginationLink.displayName = \"PaginationLink\"\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <ChevronLeft className=\"h-4 w-4\" />\n <span>Previous</span>\n </PaginationLink>\n)\nPaginationPrevious.displayName = \"PaginationPrevious\"\n\nconst PaginationNext = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <ChevronRight className=\"h-4 w-4\" />\n </PaginationLink>\n)\nPaginationNext.displayName = \"PaginationNext\"\n\nconst PaginationEllipsis = ({\n className,\n ...props\n}: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <MoreHorizontal className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n)\nPaginationEllipsis.displayName = \"PaginationEllipsis\"\n\nexport {\n Pagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n PaginationNext,\n PaginationPrevious,\n}\n"
}
],
"type": "components:ui"

File diff suppressed because one or more lines are too long

View File

@@ -6,7 +6,7 @@
"files": [
{
"name": "pagination.tsx",
"content": "import * as React from \"react\"\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n DotsHorizontalIcon,\n} from \"@radix-ui/react-icons\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ButtonProps, buttonVariants } from \"@/registry/new-york/ui/button\"\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n)\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n))\nPaginationContent.displayName = \"PaginationContent\"\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(\"\", className)} {...props} />\n))\nPaginationItem.displayName = \"PaginationItem\"\n\ntype PaginationLinkProps = {\n isActive?: boolean\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<\"a\">\n\nconst PaginationLink = ({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) => (\n <PaginationItem>\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n </PaginationItem>\n)\nPaginationLink.displayName = \"PaginationLink\"\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <ChevronLeftIcon className=\"h-4 w-4\" />\n <span>Previous</span>\n </PaginationLink>\n)\nPaginationPrevious.displayName = \"PaginationPrevious\"\n\nconst PaginationNext = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <ChevronRightIcon className=\"h-4 w-4\" />\n </PaginationLink>\n)\n\nconst PaginationEllipsis = ({\n className,\n ...props\n}: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <DotsHorizontalIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n)\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n}\n"
"content": "import * as React from \"react\"\nimport {\n ChevronLeftIcon,\n ChevronRightIcon,\n DotsHorizontalIcon,\n} from \"@radix-ui/react-icons\"\n\nimport { cn } from \"@/lib/utils\"\nimport { ButtonProps, buttonVariants } from \"@/registry/new-york/ui/button\"\n\nconst Pagination = ({ className, ...props }: React.ComponentProps<\"nav\">) => (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n)\nPagination.displayName = \"Pagination\"\n\nconst PaginationContent = React.forwardRef<\n HTMLUListElement,\n React.ComponentProps<\"ul\">\n>(({ className, ...props }, ref) => (\n <ul\n ref={ref}\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n))\nPaginationContent.displayName = \"PaginationContent\"\n\nconst PaginationItem = React.forwardRef<\n HTMLLIElement,\n React.ComponentProps<\"li\">\n>(({ className, ...props }, ref) => (\n <li ref={ref} className={cn(\"\", className)} {...props} />\n))\nPaginationItem.displayName = \"PaginationItem\"\n\ntype PaginationLinkProps = {\n isActive?: boolean\n} & Pick<ButtonProps, \"size\"> &\n React.ComponentProps<\"a\">\n\nconst PaginationLink = ({\n className,\n isActive,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) => (\n <a\n aria-current={isActive ? \"page\" : undefined}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n)\nPaginationLink.displayName = \"PaginationLink\"\n\nconst PaginationPrevious = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 pl-2.5\", className)}\n {...props}\n >\n <ChevronLeftIcon className=\"h-4 w-4\" />\n <span>Previous</span>\n </PaginationLink>\n)\nPaginationPrevious.displayName = \"PaginationPrevious\"\n\nconst PaginationNext = ({\n className,\n ...props\n}: React.ComponentProps<typeof PaginationLink>) => (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 pr-2.5\", className)}\n {...props}\n >\n <span>Next</span>\n <ChevronRightIcon className=\"h-4 w-4\" />\n </PaginationLink>\n)\nPaginationNext.displayName = \"PaginationNext\"\n\nconst PaginationEllipsis = ({\n className,\n ...props\n}: React.ComponentProps<\"span\">) => (\n <span\n aria-hidden\n className={cn(\"flex h-9 w-9 items-center justify-center\", className)}\n {...props}\n >\n <DotsHorizontalIcon className=\"h-4 w-4\" />\n <span className=\"sr-only\">More pages</span>\n </span>\n)\nPaginationEllipsis.displayName = \"PaginationEllipsis\"\n\nexport {\n Pagination,\n PaginationContent,\n PaginationLink,\n PaginationItem,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n}\n"
}
],
"type": "components:ui"

View File

@@ -2,18 +2,21 @@
import * as React from "react"
import useEmblaCarousel, {
type EmblaCarouselType as CarouselApi,
type EmblaOptionsType as CarouselOptions,
type EmblaPluginType as CarouselPlugin,
type UseEmblaCarouselType,
} from "embla-carousel-react"
import { ArrowLeft, ArrowRight } from "lucide-react"
import { cn } from "@/lib/utils"
import { Button } from "@/registry/default/ui/button"
type CarouselApi = UseEmblaCarouselType[1]
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
type CarouselOptions = UseCarouselParameters[0]
type CarouselPlugin = UseCarouselParameters[1]
type CarouselProps = {
opts?: CarouselOptions
plugins?: CarouselPlugin[]
plugins?: CarouselPlugin
orientation?: "horizontal" | "vertical"
setApi?: (api: CarouselApi) => void
}

View File

@@ -12,6 +12,7 @@ const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
{...props}
/>
)
Pagination.displayName = "Pagination"
const PaginationContent = React.forwardRef<
HTMLUListElement,
@@ -44,19 +45,17 @@ const PaginationLink = ({
size = "icon",
...props
}: PaginationLinkProps) => (
<PaginationItem>
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className
)}
{...props}
/>
</PaginationItem>
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className
)}
{...props}
/>
)
PaginationLink.displayName = "PaginationLink"
@@ -90,6 +89,7 @@ const PaginationNext = ({
<ChevronRight className="h-4 w-4" />
</PaginationLink>
)
PaginationNext.displayName = "PaginationNext"
const PaginationEllipsis = ({
className,
@@ -104,6 +104,7 @@ const PaginationEllipsis = ({
<span className="sr-only">More pages</span>
</span>
)
PaginationEllipsis.displayName = "PaginationEllipsis"
export {
Pagination,

View File

@@ -3,17 +3,20 @@
import * as React from "react"
import { ArrowLeftIcon, ArrowRightIcon } from "@radix-ui/react-icons"
import useEmblaCarousel, {
type EmblaCarouselType as CarouselApi,
type EmblaOptionsType as CarouselOptions,
type EmblaPluginType as CarouselPlugin,
type UseEmblaCarouselType,
} from "embla-carousel-react"
import { cn } from "@/lib/utils"
import { Button } from "@/registry/new-york/ui/button"
type CarouselApi = UseEmblaCarouselType[1]
type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
type CarouselOptions = UseCarouselParameters[0]
type CarouselPlugin = UseCarouselParameters[1]
type CarouselProps = {
opts?: CarouselOptions
plugins?: CarouselPlugin[]
plugins?: CarouselPlugin
orientation?: "horizontal" | "vertical"
setApi?: (api: CarouselApi) => void
}

View File

@@ -16,6 +16,7 @@ const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
{...props}
/>
)
Pagination.displayName = "Pagination"
const PaginationContent = React.forwardRef<
HTMLUListElement,
@@ -48,19 +49,17 @@ const PaginationLink = ({
size = "icon",
...props
}: PaginationLinkProps) => (
<PaginationItem>
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className
)}
{...props}
/>
</PaginationItem>
<a
aria-current={isActive ? "page" : undefined}
className={cn(
buttonVariants({
variant: isActive ? "outline" : "ghost",
size,
}),
className
)}
{...props}
/>
)
PaginationLink.displayName = "PaginationLink"
@@ -94,6 +93,7 @@ const PaginationNext = ({
<ChevronRightIcon className="h-4 w-4" />
</PaginationLink>
)
PaginationNext.displayName = "PaginationNext"
const PaginationEllipsis = ({
className,
@@ -108,6 +108,7 @@ const PaginationEllipsis = ({
<span className="sr-only">More pages</span>
</span>
)
PaginationEllipsis.displayName = "PaginationEllipsis"
export {
Pagination,

View File

@@ -60,7 +60,6 @@ const ui: Registry = [
files: ["ui/carousel.tsx"],
registryDependencies: ["button"],
dependencies: ["embla-carousel-react"],
devDependencies: ["embla-carousel"],
},
{
name: "checkbox",

View File

@@ -1,5 +1,6 @@
import { existsSync, promises as fs } from "fs"
import path from "path"
import { applyCSSUpdates } from "@/src/utils/css"
import {
DEFAULT_COMPONENTS,
DEFAULT_TAILWIND_CONFIG,
@@ -357,16 +358,17 @@ export async function runInit(cwd: string, config: Config) {
// Write css file.
const baseColor = await getRegistryBaseColor(config.tailwind.baseColor)
if (baseColor) {
await fs.writeFile(
const cssFileInput = await fs.readFile(
config.resolvedPaths.tailwindCss,
config.tailwind.cssVariables
? config.tailwind.prefix
? applyPrefixesCss(baseColor.cssVarsTemplate, config.tailwind.prefix)
: baseColor.cssVarsTemplate
: baseColor.inlineColorsTemplate,
"utf8"
)
// const cssFileTemplate = config.tailwind.cssVariables
// ? baseColor.cssVarsTemplate
// : baseColor.inlineColorsTemplate
const cssFileContent = applyCSSUpdates(cssFileInput, baseColor, config)
await fs.writeFile(config.resolvedPaths.tailwindCss, cssFileContent, "utf8")
}
// Write cn file.

View File

@@ -0,0 +1,86 @@
import { Config } from "@/src/utils/get-config"
import { registryBaseColorSchema } from "@/src/utils/registry/schema"
import { applyPrefixesCss } from "@/src/utils/transformers/transform-tw-prefix"
import * as z from "zod"
// This does a simple string replacement.
// TODO: Do we want to use a proper CSS transformer here? Probably not right now.
export function applyCSSUpdates(
input: string,
baseColor: Pick<z.infer<typeof registryBaseColorSchema>, "cssVars">,
config: Partial<Config>
) {
if (!isCSSUpdateRequired(input, config)) {
return input
}
let output = input
// Check if the file contains the `@tailwind` directives.
// We assume it does since Tailwind CSS is checked in preflight.
if (!input.includes("@tailwind base")) {
// Prepend the `@tailwind` directives.
output = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n${input}`
}
// No additional changes if not using CSS variables.
if (!config.tailwind?.cssVariables) {
return output
}
const lightColors = Object.entries(baseColor.cssVars.light).map(
([name, value]) => ` --${name}: ${value};`
)
const darkColors = Object.entries(baseColor.cssVars.dark).map(
([name, value]) => ` --${name}: ${value};`
)
output = output.replace(
/@tailwind utilities;/,
`@tailwind utilities;\n
@layer base {
:root {
${lightColors.join("\n")}
}
.dark {
${darkColors.join("\n")}
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}`
)
if (config.tailwind.prefix) {
output = applyPrefixesCss(output, config.tailwind.prefix)
}
return output
}
function isCSSUpdateRequired(input: string, config: Partial<Config>) {
// Check for tailwind directives.
const hasTailwindDirectives =
input.includes("@tailwind base") &&
input.includes("@tailwind utilities") &&
input.includes("@tailwind components")
// If we're not using CSS variables, we only check for the `@tailwind` directives.
if (!config.tailwind?.cssVariables) {
return !hasTailwindDirectives
}
// If we are using CSS variables, we check for the `@layer base` directives.
// And we check for the `--background` and `--foreground` variables.
return !(
input.includes("@layer base") &&
input.includes("--background") &&
input.includes("--foreground")
)
}

View File

@@ -0,0 +1,27 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}

View File

@@ -0,0 +1,38 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 71.4% 4.1%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
body {
background-color: tomato;
}

View File

@@ -0,0 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
background-color: tomato;
}

View File

@@ -0,0 +1,3 @@
body {
background-color: tomato;
}

View File

@@ -0,0 +1,304 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`apply css updates 1`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
body {
background-color: tomato;
}
"
`;
exports[`apply css updates 2`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}
"
`;
exports[`apply css updates 3`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 71.4% 4.1%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
body {
background-color: tomato;
}
"
`;
exports[`apply css updates 4`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 71.4% 4.1%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}
"
`;
exports[`apply css updates 5`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 71.4% 4.1%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply tw-border-border;
}
body {
@apply tw-bg-background tw-text-foreground;
}
}
body {
background-color: tomato;
}
"
`;
exports[`apply css updates 6`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 71.4% 4.1%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply cn-border-border;
}
body {
@apply cn-bg-background cn-text-foreground;
}
}
:root {
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
}
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
}
"
`;
exports[`apply css updates 7`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
body {
background-color: tomato;
}
"
`;
exports[`apply css updates 8`] = `
"@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 224 71.4% 4.1%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
body {
background-color: tomato;
}
"
`;

View File

@@ -0,0 +1,154 @@
import { promises as fs } from "fs"
import path from "path"
import { expect, test } from "vitest"
import { applyCSSUpdates } from "../../src/utils/css"
const baseColor = {
cssVars: {
light: {
background: "0 0% 100%",
foreground: "224 71.4% 4.1%",
primary: "220.9 39.3% 11%",
"primary-foreground": "210 20% 98%",
border: "220 13% 91%",
input: "220 13% 91%",
ring: "224 71.4% 4.1%",
},
dark: {
background: "224 71.4% 4.1%",
foreground: "210 20% 98%",
primary: "210 20% 98%",
"primary-foreground": "220.9 39.3% 11%",
border: "215 27.9% 16.9%",
input: "215 27.9% 16.9%",
ring: "216 12.2% 83.9%",
},
},
}
test("apply css updates", async () => {
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/no-tailwind.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: false,
},
}
)
).toMatchSnapshot()
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/app-globals.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: false,
},
}
)
).toMatchSnapshot()
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/no-tailwind.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: true,
},
}
)
).toMatchSnapshot()
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/app-globals.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: true,
},
}
)
).toMatchSnapshot()
// Prefix.
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/no-tailwind.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: true,
prefix: "tw-",
},
}
)
).toMatchSnapshot()
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/app-globals.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: true,
prefix: "cn-",
},
}
)
).toMatchSnapshot()
// Applied.
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/applied.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: false,
},
}
)
).toMatchSnapshot()
expect(
await applyCSSUpdates(
await fs.readFile(
path.resolve(__dirname, "../fixtures/css/applied-css-vars.css"),
"utf8"
),
baseColor,
{
tailwind: {
cssVariables: true,
},
}
)
).toMatchSnapshot()
})