snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
All checks were successful
Release / Create Version PR or Publish Stable Release (push) Has been skipped
Release / Publish Prerelease to NPM (push) Has been skipped
Monitor Registries / Monitor registry health (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 22:44:43 +05:00
commit 1416db152c
5727 changed files with 630238 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
"use client"
import * as React from "react"
import { CMD_K_FORWARD_TYPE } from "@/app/(app)/(create)/components/action-menu"
import { CreateDevtools } from "@/app/(app)/(create)/components/create-devtools"
import {
REDO_FORWARD_TYPE,
UNDO_FORWARD_TYPE,
} from "@/app/(app)/(create)/components/history-buttons"
import { DARK_MODE_FORWARD_TYPE } from "@/app/(app)/(create)/components/mode-switcher"
import { usePreviewOverrideValue } from "@/app/(app)/(create)/components/preview-override"
import { PreviewSwitcher } from "@/app/(app)/(create)/components/preview-switcher"
import { RANDOMIZE_FORWARD_TYPE } from "@/app/(app)/(create)/components/random-button"
import { sendToIframe } from "@/app/(app)/(create)/hooks/use-iframe-sync"
import { OPEN_PRESET_FORWARD_TYPE } from "@/app/(app)/(create)/hooks/use-open-preset"
import { RESET_FORWARD_TYPE } from "@/app/(app)/(create)/hooks/use-reset"
import {
serializeDesignSystemSearchParams,
useDesignSystemSearchParams,
} from "@/app/(app)/(create)/lib/search-params"
// Hoisted — avoids recreating on every message event. (js-hoist-regexp)
const MAC_REGEX = /Mac|iPhone|iPad|iPod/
function isSameParams(
a: ReturnType<typeof useDesignSystemSearchParams>[0] | null,
b: ReturnType<typeof useDesignSystemSearchParams>[0]
) {
if (!a) {
return false
}
return Object.keys(b).every(
(key) => a[key as keyof typeof b] === b[key as keyof typeof b]
)
}
export function Preview() {
const [params] = useDesignSystemSearchParams()
const override = usePreviewOverrideValue()
const iframeRef = React.useRef<HTMLIFrameElement>(null)
const lastSentParamsRef = React.useRef<typeof params | null>(null)
// Hover previews overlay the committed params without touching the URL —
// clearing the override re-sends the committed params, reverting the preview.
const mergedParams = React.useMemo(
() => (override ? { ...params, ...override } : params),
[params, override]
)
React.useEffect(() => {
const iframe = iframeRef.current
if (!iframe) {
return
}
const sendParams = () => {
sendToIframe(iframe, "design-system-params", mergedParams)
lastSentParamsRef.current = mergedParams
}
// Skip content-identical re-sends (e.g. an override matching the committed
// params) — each message triggers a full param sync in the iframe.
if (
iframe.contentWindow &&
!isSameParams(lastSentParamsRef.current, mergedParams)
) {
sendParams()
}
iframe.addEventListener("load", sendParams)
return () => {
iframe.removeEventListener("load", sendParams)
}
}, [mergedParams])
React.useEffect(() => {
const handleMessage = (event: MessageEvent) => {
const iframeWindow = iframeRef.current?.contentWindow
if (
!iframeWindow ||
event.origin !== window.location.origin ||
event.source !== iframeWindow ||
!event.data ||
typeof event.data !== "object"
) {
return
}
const type = event.data.type
if (type === CMD_K_FORWARD_TYPE) {
const isMac = MAC_REGEX.test(navigator.userAgent)
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: event.data.key || "k",
metaKey: isMac,
ctrlKey: !isMac,
bubbles: true,
cancelable: true,
})
)
} else if (type === RANDOMIZE_FORWARD_TYPE) {
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: event.data.key || "r",
bubbles: true,
cancelable: true,
})
)
} else if (type === OPEN_PRESET_FORWARD_TYPE) {
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: event.data.key || "o",
bubbles: true,
cancelable: true,
})
)
} else if (type === UNDO_FORWARD_TYPE) {
const isMac = MAC_REGEX.test(navigator.userAgent)
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: "z",
metaKey: isMac,
ctrlKey: !isMac,
bubbles: true,
cancelable: true,
})
)
} else if (type === REDO_FORWARD_TYPE) {
const isMac = MAC_REGEX.test(navigator.userAgent)
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: "z",
shiftKey: true,
metaKey: isMac,
ctrlKey: !isMac,
bubbles: true,
cancelable: true,
})
)
} else if (type === RESET_FORWARD_TYPE) {
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: "R",
shiftKey: true,
bubbles: true,
cancelable: true,
})
)
} else if (type === DARK_MODE_FORWARD_TYPE) {
document.dispatchEvent(
new KeyboardEvent("keydown", {
key: event.data.key || "d",
bubbles: true,
cancelable: true,
})
)
}
}
window.addEventListener("message", handleMessage)
return () => {
window.removeEventListener("message", handleMessage)
}
}, [])
const iframeSrc = React.useMemo(() => {
// The iframe src needs to include the serialized design system params
// for the initial load, but not be reactive to them as it would cause
// full-iframe reloads on every param change (flashes & loss of state).
// Further updates of the search params will be sent to the iframe
// via a postMessage channel, for it to sync its own history onto the host's.
return serializeDesignSystemSearchParams(
`/preview/${params.base}/${params.item}`,
params
)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [params.base, params.item])
return (
<div className="relative flex flex-1 flex-col justify-center overflow-hidden rounded-2xl ring ring-foreground/10 md:ring-muted dark:ring-foreground/10">
<div className="relative z-0 mx-auto flex w-full flex-1 flex-col overflow-hidden">
<div className="absolute inset-0 bg-muted dark:bg-muted/30" />
<iframe
key={params.base + params.item}
ref={iframeRef}
src={iframeSrc}
className="z-10 size-full flex-1"
title="Preview"
/>
</div>
<CreateDevtools />
<PreviewSwitcher />
</div>
)
}