mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-18 13:21:35 +00:00
Compare commits
4 Commits
shadcn@3.4
...
shadcn@3.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed9d5939e6 | ||
|
|
b52ec12f1e | ||
|
|
2ab9bff4bb | ||
|
|
2f6b51fa0a |
@@ -49,7 +49,7 @@ import { Badge } from "@/components/ui/badge"
|
||||
```
|
||||
|
||||
```tsx
|
||||
<Badge variant="default |outline | secondary | destructive">Badge</Badge>
|
||||
<Badge variant="default | outline | secondary | destructive">Badge</Badge>
|
||||
```
|
||||
|
||||
### Link
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
"recharts": "2.15.1",
|
||||
"rehype-pretty-code": "^0.14.1",
|
||||
"rimraf": "^6.0.1",
|
||||
"shadcn": "3.4.1",
|
||||
"shadcn": "3.4.2",
|
||||
"shiki": "^1.10.1",
|
||||
"sonner": "^2.0.0",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"@bucharitesh": "https://bucharitesh.in/r/{name}.json",
|
||||
"@clerk": "https://clerk.com/r/{name}.json",
|
||||
"@cult-ui": "https://cult-ui.com/r/{name}.json",
|
||||
"@efferd-ui": "https://ui.efferd.com/r/{name}.json",
|
||||
"@eldoraui": "https://eldoraui.site/r/{name}.json",
|
||||
"@elements": "https://tryelements.dev/r/{name}.json",
|
||||
"@elevenlabs-ui": "https://ui.elevenlabs.io/r/{name}.json",
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
"react-resizable-panels": "^2.0.22",
|
||||
"react-wrap-balancer": "^0.4.1",
|
||||
"recharts": "2.12.7",
|
||||
"shadcn": "3.4.1",
|
||||
"shadcn": "3.4.2",
|
||||
"sharp": "^0.32.6",
|
||||
"sonner": "^1.2.3",
|
||||
"swr": "2.2.6-beta.3",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @shadcn/ui
|
||||
|
||||
## 3.4.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#8478](https://github.com/shadcn-ui/ui/pull/8478) [`b52ec12f1e22cf89270bf3d931f5b7544e4b80b4`](https://github.com/shadcn-ui/ui/commit/b52ec12f1e22cf89270bf3d931f5b7544e4b80b4) Thanks [@shadcn](https://github.com/shadcn)! - fix regression with universal item detection
|
||||
|
||||
## 3.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "shadcn",
|
||||
"version": "3.4.1",
|
||||
"version": "3.4.2",
|
||||
"description": "Add components to your apps.",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -144,6 +144,7 @@ describe("isLocalFile", () => {
|
||||
describe("isUniversalRegistryItem", () => {
|
||||
it("should return true when all files have targets with registry:file type", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "file1.ts",
|
||||
@@ -160,7 +161,26 @@ describe("isUniversalRegistryItem", () => {
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true for any registry item type if all files are registry:file with targets", () => {
|
||||
it("should return true when registry item type is registry:file and all files have targets", () => {
|
||||
const registryItem = {
|
||||
type: "registry:file" as const,
|
||||
files: [
|
||||
{
|
||||
path: "file1.ts",
|
||||
target: "src/file1.ts",
|
||||
type: "registry:file" as const,
|
||||
},
|
||||
{
|
||||
path: "file2.ts",
|
||||
target: "src/utils/file2.ts",
|
||||
type: "registry:item" as const,
|
||||
},
|
||||
],
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false for any registry item type other than registry:item or registry:file", () => {
|
||||
const registryItem = {
|
||||
type: "registry:ui" as const,
|
||||
files: [
|
||||
@@ -171,11 +191,12 @@ describe("isUniversalRegistryItem", () => {
|
||||
},
|
||||
],
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(true)
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false when some files lack targets", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "file1.ts",
|
||||
@@ -190,6 +211,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when files have non-registry:file type", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "file1.ts",
|
||||
@@ -208,6 +230,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when no files have targets", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{ path: "file1.ts", target: "", type: "registry:file" as const },
|
||||
{ path: "file2.ts", target: "", type: "registry:file" as const },
|
||||
@@ -216,18 +239,44 @@ describe("isUniversalRegistryItem", () => {
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(false)
|
||||
})
|
||||
|
||||
it("should return true when files array is empty", () => {
|
||||
it("should return true when files array is empty and type is registry:item", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [],
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return true when files is undefined", () => {
|
||||
const registryItem = {}
|
||||
it("should return true when files is undefined and type is registry:item", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when type is registry:style", () => {
|
||||
const registryItem = {
|
||||
type: "registry:style" as const,
|
||||
files: [],
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false when type is registry:ui", () => {
|
||||
const registryItem = {
|
||||
type: "registry:ui" as const,
|
||||
files: [],
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false when files is undefined and type is not registry:item or registry:file", () => {
|
||||
const registryItem = {
|
||||
type: "registry:component" as const,
|
||||
}
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(false)
|
||||
})
|
||||
|
||||
it("should return false when registryItem is null", () => {
|
||||
expect(isUniversalRegistryItem(null)).toBe(false)
|
||||
})
|
||||
@@ -238,6 +287,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when target is null", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "file1.ts",
|
||||
@@ -251,6 +301,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when target is undefined", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "file1.ts",
|
||||
@@ -264,6 +315,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when files have registry:component type even with targets", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "component.tsx",
|
||||
@@ -277,6 +329,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when files have registry:hook type even with targets", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "use-hook.ts",
|
||||
@@ -290,6 +343,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return false when files have registry:lib type even with targets", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "utils.ts",
|
||||
@@ -303,6 +357,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should return true when all targets are non-empty strings for registry:file", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{ path: "file1.ts", target: " ", type: "registry:file" as const }, // whitespace is truthy
|
||||
{ path: "file2.ts", target: "0", type: "registry:file" as const }, // "0" is truthy
|
||||
@@ -313,6 +368,7 @@ describe("isUniversalRegistryItem", () => {
|
||||
|
||||
it("should handle real-world example with path traversal attempts for registry:file", () => {
|
||||
const registryItem = {
|
||||
type: "registry:item" as const,
|
||||
files: [
|
||||
{
|
||||
path: "malicious.ts",
|
||||
@@ -326,18 +382,18 @@ describe("isUniversalRegistryItem", () => {
|
||||
},
|
||||
],
|
||||
}
|
||||
// The function should still return true - path validation is handled elsewhere
|
||||
// The function should still return true - path validation is handled elsewhere.
|
||||
expect(isUniversalRegistryItem(registryItem)).toBe(true)
|
||||
})
|
||||
|
||||
it("should return false when files have non-registry:file type in a UI registry item", () => {
|
||||
it("should return false when registry item type is registry:ui", () => {
|
||||
const registryItem = {
|
||||
type: "registry:ui" as const,
|
||||
files: [
|
||||
{
|
||||
path: "button.tsx",
|
||||
target: "src/components/ui/button.tsx",
|
||||
type: "registry:ui" as const, // Not registry:file
|
||||
type: "registry:file" as const,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -267,14 +267,14 @@ export function isLocalFile(path: string) {
|
||||
|
||||
/**
|
||||
* Check if a registry item is universal (framework-agnostic).
|
||||
* A universal registry item must have all files with:
|
||||
* 1. Explicit targets
|
||||
* 2. Type "registry:file"
|
||||
* A universal registry item must:
|
||||
* 1. Have type "registry:item" or "registry:file"
|
||||
* 2. If it has files, all files must have explicit targets and be type "registry:file" or "registry:item"
|
||||
* It can be installed without framework detection or components.json.
|
||||
*/
|
||||
export function isUniversalRegistryItem(
|
||||
registryItem:
|
||||
| Pick<z.infer<typeof registryItemSchema>, "files">
|
||||
| Pick<z.infer<typeof registryItemSchema>, "files" | "type">
|
||||
| null
|
||||
| undefined
|
||||
): boolean {
|
||||
@@ -282,8 +282,16 @@ export function isUniversalRegistryItem(
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
registryItem.type !== "registry:item" &&
|
||||
registryItem.type !== "registry:file"
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
const files = registryItem.files ?? []
|
||||
|
||||
// If there are files, all must have targets and be of type registry:file or registry:item.
|
||||
return files.every(
|
||||
(file) =>
|
||||
!!file.target &&
|
||||
|
||||
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@@ -331,7 +331,7 @@ importers:
|
||||
specifier: ^6.0.1
|
||||
version: 6.0.1
|
||||
shadcn:
|
||||
specifier: 3.4.1
|
||||
specifier: 3.4.2
|
||||
version: link:../../packages/shadcn
|
||||
shiki:
|
||||
specifier: ^1.10.1
|
||||
@@ -611,7 +611,7 @@ importers:
|
||||
specifier: 2.12.7
|
||||
version: 2.12.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
shadcn:
|
||||
specifier: 3.4.1
|
||||
specifier: 3.4.2
|
||||
version: link:../../packages/shadcn
|
||||
sharp:
|
||||
specifier: ^0.32.6
|
||||
|
||||
Reference in New Issue
Block a user