@krizaka/ui 3.18.0 → 3.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/media-grid.js
CHANGED
|
@@ -187,7 +187,7 @@ var Card = {
|
|
|
187
187
|
};
|
|
188
188
|
|
|
189
189
|
// src/media-grid/video-card.tsx
|
|
190
|
-
import {
|
|
190
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
191
191
|
var FRAME = { landscape: "aspect-video", portrait: "aspect-[9/16]" };
|
|
192
192
|
function VideoCard({
|
|
193
193
|
title,
|
|
@@ -217,6 +217,7 @@ function VideoCard({
|
|
|
217
217
|
const [live, setLive] = React2.useState(false);
|
|
218
218
|
const picture = live && previewSrc ? previewSrc : poster;
|
|
219
219
|
const row = layout === "row";
|
|
220
|
+
const tall = aspect === "portrait" && !row;
|
|
220
221
|
return /* @__PURE__ */ jsx5(
|
|
221
222
|
"article",
|
|
222
223
|
{
|
|
@@ -238,13 +239,15 @@ function VideoCard({
|
|
|
238
239
|
] }),
|
|
239
240
|
/* @__PURE__ */ jsxs4(Card.Body, { className: "min-w-0 flex-1 justify-between gap-2 p-3", children: [
|
|
240
241
|
/* @__PURE__ */ jsx5("h3", { className: "m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg", children: /* @__PURE__ */ jsx5(BlockLink, { href, linkAs, className: "line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring", children: title }) }),
|
|
241
|
-
/* @__PURE__ */ jsxs4("div", { className: "relative z-10 flex h-8 items-center gap-2
|
|
242
|
-
creator && /* @__PURE__ */ jsxs4(
|
|
242
|
+
/* @__PURE__ */ jsxs4("div", { className: cn("relative z-10 text-xs text-fg-secondary", tall ? "flex flex-col gap-1" : "flex h-8 items-center gap-2"), children: [
|
|
243
|
+
creator && /* @__PURE__ */ jsxs4("div", { className: "flex h-6 min-w-0 items-center gap-2", children: [
|
|
243
244
|
/* @__PURE__ */ jsx5(Avatar, { src: creator.avatarSrc, defaultAvatar: creator.defaultAvatar, alt: "", fallback: creator.name.charAt(0), size: "xs", className: "shrink-0" }),
|
|
244
|
-
creator.href ? /* @__PURE__ */ jsx5(BlockLink, { href: creator.href, linkAs, className: "truncate hover:text-fg", children: creator.name }) : /* @__PURE__ */ jsx5("span", { className: "truncate", children: creator.name })
|
|
245
|
+
creator.href ? /* @__PURE__ */ jsx5(BlockLink, { href: creator.href, linkAs, className: "min-w-0 truncate hover:text-fg", children: creator.name }) : /* @__PURE__ */ jsx5("span", { className: "min-w-0 truncate", children: creator.name })
|
|
245
246
|
] }),
|
|
246
|
-
meta && /* @__PURE__ */
|
|
247
|
-
|
|
247
|
+
(meta || action) && /* @__PURE__ */ jsxs4("div", { className: cn("flex items-center gap-2", tall ? "h-7 justify-between" : "ml-auto shrink-0"), children: [
|
|
248
|
+
meta && /* @__PURE__ */ jsx5("span", { className: "shrink-0 font-mono text-[11px] text-fg-muted", children: meta }),
|
|
249
|
+
action && /* @__PURE__ */ jsx5("span", { className: "shrink-0", children: action })
|
|
250
|
+
] })
|
|
248
251
|
] })
|
|
249
252
|
] })
|
|
250
253
|
] })
|
package/dist/media-grid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/media-grid/shorts-shelf.tsx","../src/block-link.tsx","../src/media-grid/media-grid.tsx","../src/media-grid/video-card.tsx","../src/card/card.tsx","../src/card/recipe.ts"],"sourcesContent":["// Client (the arrows scroll the row). A horizontal row of 9:16 cards of one height: scroll-snap, arrows with a mouse,\n// a swipe on touch, a \"See all\" link. The row is a labelled list that scrolls with the keyboard (it takes focus).\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\nexport interface ShortsShelfProps<T> extends Omit<React.ComponentProps<\"section\">, \"children\" | \"title\"> {\n /** The shelf's accessible name (\"Shorts\"), passed translated; shown as its heading unless `title` is set. */\n label: string;\n /** A heading different from the name. */\n title?: React.ReactNode;\n /** The clips, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** One card: use `VideoCard aspect=\"portrait\"`. */\n renderItem: (item: T, index: number) => React.ReactNode;\n /** Opens the vertical feed. */\n seeAll?: { href: string; label: string; linkAs?: LinkComponent };\n /** The arrows' names, passed translated. */\n previousLabel: string;\n /** The next arrow's name. */\n nextLabel: string;\n}\n\nconst Chevron = ({ flip }: { flip?: boolean }) => (\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden className={flip ? \"rotate-180\" : undefined}>\n <path d=\"m9 6 6 6-6 6\" />\n </svg>\n);\n\nconst ARROW =\n \"hidden h-9 w-9 items-center justify-center rounded-full border border-border-default bg-surface-1 text-fg shadow-sm transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-40 [@media(hover:hover)]:inline-flex\";\n\n/** A Shorts shelf: equal-height 9:16 cards in a snap-scrolling row. */\nexport function ShortsShelf<T>({ label, title, items, getId, renderItem, seeAll, previousLabel, nextLabel, className, ...props }: ShortsShelfProps<T>) {\n const row = React.useRef<HTMLUListElement>(null);\n const [edge, setEdge] = React.useState({ start: true, end: false });\n const measure = React.useCallback(() => {\n const el = row.current;\n if (!el) return;\n setEdge({ start: el.scrollLeft <= 2, end: el.scrollLeft + el.clientWidth >= el.scrollWidth - 2 });\n }, []);\n React.useEffect(measure, [measure, items.length]);\n const page = (dir: 1 | -1) => {\n const el = row.current;\n if (el) el.scrollBy({ left: dir * el.clientWidth * 0.85, behavior: window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\" });\n };\n const headingId = React.useId();\n if (items.length === 0) return null;\n return (\n <section aria-labelledby={headingId} data-shorts-shelf className={cn(\"min-w-0\", className)} {...props}>\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={headingId} className=\"m-0 mr-auto text-base font-bold text-fg\">\n {title ?? label}\n </h2>\n {seeAll && (\n <BlockLink href={seeAll.href} linkAs={seeAll.linkAs} className=\"text-sm font-semibold text-fg-accent hover:underline\">\n {seeAll.label}\n </BlockLink>\n )}\n <button type=\"button\" aria-label={previousLabel} disabled={edge.start} onClick={() => page(-1)} className={ARROW}>\n <Chevron flip />\n </button>\n <button type=\"button\" aria-label={nextLabel} disabled={edge.end} onClick={() => page(1)} className={ARROW}>\n <Chevron />\n </button>\n </div>\n <ul\n ref={row}\n onScroll={measure}\n // biome-ignore: a scroll container must take the keyboard focus to scroll with the arrow keys\n tabIndex={0}\n aria-labelledby={headingId}\n className=\"m-0 flex list-none snap-x snap-mandatory items-stretch gap-3 overflow-x-auto overscroll-x-contain p-0 pb-2 [scrollbar-width:none] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-scrollbar]:hidden\"\n >\n {items.map((item, i) => (\n <li key={getId(item)} className=\"w-[9.5rem] shrink-0 snap-start sm:w-44\">\n {renderItem(item, i)}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} {...props} />;\n}\n","// Client (it renders the shelf). Mixed orientations without a broken grid. `split` (the feed default) sends the 9:16\n// clips to a `ShortsShelf` and lays the rest in a uniform 16:9 grid; `uniform` puts everything in one grid of one frame\n// (a source of the other orientation is told to `contain`, never cropped to a face). `layout=\"list\"` is one column.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { ShortsShelf, type ShortsShelfProps } from \"./shorts-shelf\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface MediaGridState {\n /** The frame the card is drawn in (`aspect` of `VideoCard`). */\n aspect: VideoCardAspect;\n /** The card's `layout`. */\n layout: \"stack\" | \"row\";\n /** The source's orientation differs from the frame: pass `fit=\"contain\"`. */\n mismatch: boolean;\n}\n\nexport interface MediaGridProps<T> extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** The videos, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** The source's orientation (from its width and height). */\n orientationOf: (item: T) => VideoCardAspect;\n /** One card, drawn in the frame the grid gives (`state`): use `VideoCard`. */\n renderItem: (item: T, state: MediaGridState) => React.ReactNode;\n /**\n * `split`: verticals on the shelf, the others in the grid · `uniform`: all in one frame (`frame`).\n * @default \"split\"\n */\n mode?: \"split\" | \"uniform\";\n /** The frame of `uniform`. @default \"landscape\" */\n frame?: VideoCardAspect;\n /** `grid` or `list` (one row per video). @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The shelf of `split`: its name, \"See all\" and arrows, passed translated. */\n shelf: Pick<ShortsShelfProps<unknown>, \"label\" | \"title\" | \"seeAll\" | \"previousLabel\" | \"nextLabel\">;\n}\n\nconst GRID = {\n landscape: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n portrait: \"grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6\",\n} as const;\n\n/** A media grid that never mixes heights badly: a shelf for the 9:16, a uniform grid for the rest. */\nexport function MediaGrid<T>({ items, getId, orientationOf, renderItem, mode = \"split\", frame = \"landscape\", layout = \"grid\", shelf, className, ...props }: MediaGridProps<T>) {\n const row = layout === \"list\";\n const split = mode === \"split\";\n const verticals = split ? items.filter((i) => orientationOf(i) === \"portrait\") : [];\n const rest = split ? items.filter((i) => orientationOf(i) !== \"portrait\") : items;\n const gridFrame: VideoCardAspect = split ? \"landscape\" : frame;\n const state = (item: T, aspect: VideoCardAspect): MediaGridState => ({ aspect, layout: row ? \"row\" : \"stack\", mismatch: orientationOf(item) !== aspect });\n return (\n <div data-media-grid={mode} className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n {verticals.length > 0 && <ShortsShelf {...shelf} items={verticals} getId={getId} renderItem={(item) => renderItem(item, { ...state(item, \"portrait\"), layout: \"stack\" })} />}\n {rest.length > 0 && (\n <ul data-grid-frame={gridFrame} className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[gridFrame])}>\n {rest.map((item) => (\n <li key={getId(item)} className=\"min-w-0\">\n {renderItem(item, state(item, gridFrame))}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n","// Client (hover / focus swaps the picture for its animated preview). A video in a grid or a shelf: the picture in a 16:9\n// or 9:16 frame (a source of the other shape is shown inside, never stretched), badges, duration, the title on two lines\n// reserved, the creator, a count and one quick action — the same height of body in every card so a row aligns.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport type { DefaultAvatar } from \"../avatar/default-avatar\";\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\n\nexport type VideoCardAspect = \"landscape\" | \"portrait\";\n\nexport interface VideoCardCreator {\n /** The creator's name. */\n name: string;\n /** Their photo. */\n avatarSrc?: string | null;\n /** Their profile. */\n href?: string;\n /** The Krizaka default picture when there is no photo (a brand and a seed). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport interface VideoCardProps extends Omit<React.ComponentProps<\"article\">, \"title\"> {\n /** The title; it names the card and is its link. */\n title: string;\n /** Where the card opens. */\n href: string;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n /**\n * The frame: `landscape` (16:9) or `portrait` (9:16).\n * @default \"landscape\"\n */\n aspect?: VideoCardAspect;\n /**\n * `stack` (picture over text) or `row` (picture beside the text: the list mode of a section).\n * @default \"stack\"\n */\n layout?: \"stack\" | \"row\";\n /** The picture. */\n poster?: string | null;\n /** An animated picture (WebP) shown while the card is hovered or focused. */\n previewSrc?: string | null;\n /**\n * `cover` fills the frame; `contain` draws the whole picture over a blurred copy of itself (a source of the other\n * orientation: no cropped face, no black bar).\n * @default \"cover\"\n */\n fit?: \"cover\" | \"contain\";\n /** The length, already formatted (`3:42`). */\n duration?: string;\n /** Badges at the top-left of the picture (Free, a price, 18+). Put them on `scrim` so they read in both themes. */\n badges?: React.ReactNode;\n /** Who made it: name, photo, profile. */\n creator?: VideoCardCreator;\n /** What is counted (`12.4K views`), already formatted. */\n meta?: React.ReactNode;\n /** One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. */\n action?: React.ReactNode;\n /** A sensitive picture: blurred and scaled so nothing shows (put the reveal button in `overlay`). */\n blurred?: boolean;\n /** Over the whole picture, above the card's link (a veil, a reveal button). */\n overlay?: React.ReactNode;\n /** Shown instead of the picture while there is none. */\n fallback?: React.ReactNode;\n /** `eager` for the first cards of a page. */\n loading?: \"lazy\" | \"eager\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers. */\nexport function VideoCard({\n title,\n href,\n linkAs,\n aspect = \"landscape\",\n layout = \"stack\",\n poster,\n previewSrc,\n fit = \"cover\",\n duration,\n badges,\n creator,\n meta,\n action,\n fallback,\n blurred = false,\n overlay,\n loading = \"lazy\",\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}: VideoCardProps) {\n const [live, setLive] = React.useState(false);\n const picture = live && previewSrc ? previewSrc : poster;\n const row = layout === \"row\";\n return (\n <article\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n onMouseEnter={(e) => (setLive(true), onMouseEnter?.(e))}\n onMouseLeave={(e) => (setLive(false), onMouseLeave?.(e))}\n onFocus={(e) => (setLive(true), onFocus?.(e))}\n onBlur={(e) => (setLive(false), onBlur?.(e))}\n {...props}\n >\n <Card.Root interactive tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n {fit === \"contain\" && picture && <img src={picture} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image src={picture} loading={loading} fallback={fallback} className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")} />\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\">\n <span className=\"rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media\">{duration}</span>\n </Card.Overlay>\n )}\n </Card.Media>\n <Card.Body className=\"min-w-0 flex-1 justify-between gap-2 p-3\">\n <h3 className=\"m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg\">\n <BlockLink href={href} linkAs={linkAs} className=\"line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring\">\n {title}\n </BlockLink>\n </h3>\n <div className=\"relative z-10 flex h-8 items-center gap-2 text-xs text-fg-secondary\">\n {creator && (\n <>\n <Avatar src={creator.avatarSrc} defaultAvatar={creator.defaultAvatar} alt=\"\" fallback={creator.name.charAt(0)} size=\"xs\" className=\"shrink-0\" />\n {creator.href ? (\n <BlockLink href={creator.href} linkAs={linkAs} className=\"truncate hover:text-fg\">\n {creator.name}\n </BlockLink>\n ) : (\n <span className=\"truncate\">{creator.name}</span>\n )}\n </>\n )}\n {meta && <span className=\"ml-auto shrink-0 font-mono text-[11px] text-fg-muted\">{meta}</span>}\n {action && <span className=\"shrink-0\">{action}</span>}\n </div>\n </Card.Body>\n </Card.Root>\n </article>\n );\n}\n","// Server-safe: no hook, no context. One `tv` definition with slots: each part takes its slot, and a product overrides\n// any part through `className` (merged last by tailwind-merge).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { cardRecipe } from \"./recipe\";\n\nexport const card = tv(cardRecipe);\n\ntype CardVariants = VariantProps<typeof card>;\n/** The parts without a variant read the default slots: no context, so server-safe. */\nconst slots = card();\n\nexport type CardRootProps = React.ComponentProps<\"div\"> &\n Pick<CardVariants, \"radius\" | \"tone\" | \"interactive\"> & {\n /**\n * md · lg · xl.\n * @default \"xl\"\n */\n radius?: CardVariants[\"radius\"];\n /**\n * default (the base surface) · elevated (raised, a shadow) · glass (translucent, blurred).\n * @default \"default\"\n */\n tone?: CardVariants[\"tone\"];\n /** The spotlight that follows the pointer and the lift on hover: for a card that is a link. */\n interactive?: CardVariants[\"interactive\"];\n /** Renders the child (a link, an article) instead of the <div>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Enters on scroll (MotionObserver): the index in the grid becomes the delay (50 ms a step, 8 steps at most). */\n reveal?: number;\n };\n\nexport function CardRoot({ asChild, reveal, radius, tone, interactive, className, style, ...props }: CardRootProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n const revealStyle =\n reveal === undefined ? style : ({ ...style, \"--kz-delay\": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` } as React.CSSProperties);\n return (\n <Comp\n data-reveal={reveal === undefined ? undefined : \"\"}\n data-interactive={interactive ? \"\" : undefined}\n style={revealStyle}\n className={card({ radius, tone, interactive }).root({ className })}\n {...props}\n />\n );\n}\n\nconst ASPECT = { video: \"aspect-video\", square: \"aspect-square\", portrait: \"aspect-[3/4]\", auto: \"\" } as const;\nexport type CardMediaProps = React.ComponentProps<\"div\"> & {\n /** The ratio of the media: video (16:9) · square · portrait (3:4) · auto (the content's). */\n aspect?: keyof typeof ASPECT;\n};\n\nexport function CardMedia({ aspect = \"video\", className, ...props }: CardMediaProps) {\n return <div data-aspect={aspect} className={slots.media({ className: cn(ASPECT[aspect], className) })} {...props} />;\n}\n\nexport type CardImageProps = Omit<React.ComponentProps<\"img\">, \"src\"> & {\n /** The image's URL; `null` or nothing shows the `fallback`. */\n src?: string | null;\n /** Shown when there is no image: an icon, an illustration (decorative). */\n fallback?: React.ReactNode;\n /**\n * When the browser loads it: `lazy` (default, a card in a list or below the fold) or `eager` for the first cards\n * of a page — the image that is the largest contentful paint must not wait (add `fetchPriority=\"high\"`).\n * @default \"lazy\"\n */\n loading?: \"lazy\" | \"eager\";\n};\n\n/** The image of a media, or its `fallback` when there is none. `alt` is empty by default: the title names the card. */\nexport function CardImage({ src, alt = \"\", fallback, loading = \"lazy\", className, ...props }: CardImageProps) {\n if (!src) {\n return (\n <div data-fallback=\"\" aria-hidden className={slots.fallback({ className })}>\n {fallback}\n </div>\n );\n }\n return <img src={src} alt={alt} loading={loading} decoding=\"async\" className={slots.image({ className })} {...props} />;\n}\n\nconst CORNER = {\n \"top-left\": \"left-2.5 top-2.5\",\n \"top-right\": \"right-2.5 top-2.5\",\n \"bottom-left\": \"bottom-2.5 left-2.5\",\n \"bottom-right\": \"bottom-2.5 right-2.5\",\n} as const;\nexport type CardOverlayProps = React.ComponentProps<\"div\"> & {\n /** The corner of the media it sits in. */\n corner?: keyof typeof CORNER;\n};\n\n/** What sits on the media (badges, a caption). `scrim` and `fg-on-media` are invariant: nothing to do for light. */\nexport function CardOverlay({ corner = \"top-left\", className, ...props }: CardOverlayProps) {\n return <div data-corner={corner} className={slots.overlay({ className: cn(CORNER[corner], className) })} {...props} />;\n}\n\nexport type CardBodyProps = React.ComponentProps<\"div\"> & {\n /**\n * none · sm · md · lg.\n * @default \"md\"\n */\n padding?: CardVariants[\"padding\"];\n};\n\nexport function CardBody({ padding, className, ...props }: CardBodyProps) {\n return <div className={card({ padding }).body({ className })} {...props} />;\n}\n\nexport type CardTitleProps = React.ComponentProps<\"h3\"> & {\n /** The heading level, to fit the page's outline. */\n as?: \"h2\" | \"h3\" | \"h4\";\n};\n\nexport function CardTitle({ as: Tag = \"h3\", className, ...props }: CardTitleProps) {\n return <Tag className={slots.title({ className })} {...props} />;\n}\n\nexport function CardDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return <p className={slots.description({ className })} {...props} />;\n}\n\nexport type CardStatProps = React.ComponentProps<\"div\"> & {\n /** What the figure is, in small capitals above it (the figure is the children). */\n label: React.ReactNode;\n};\n\n/** A figure put forward: the label in capitals, the value in tabular digits. */\nexport function CardStat({ label, className, children, ...props }: CardStatProps) {\n return (\n <div className={slots.stat({ className })} {...props}>\n <p className={slots.statLabel()}>{label}</p>\n <p className={slots.statValue()}>{children}</p>\n </div>\n );\n}\n\nexport function CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={slots.footer({ className })} {...props} />;\n}\n\n/** `Card.Root/Media/Image/Overlay/Body/Title/Description/Stat/Footer`. */\nexport const Card = {\n Root: CardRoot,\n Media: CardMedia,\n Image: CardImage,\n Overlay: CardOverlay,\n Body: CardBody,\n Title: CardTitle,\n Description: CardDescription,\n Stat: CardStat,\n Footer: CardFooter,\n};\n","// The card's parts, radii, tones and paddings, written once as classes of the Krizaka tokens: the web wears them with\n// `tv(cardRecipe)`, React Native reads the same classes into styles (native/card.tsx): a part of the card that exists only\n// on the web (the media's zoom, the spotlight) is simply ignored there.\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const cardRecipe = defineRecipe({\n slots: {\n root:\n \"group relative flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n media: \"relative overflow-hidden bg-media\",\n image: \"h-full w-full object-cover transition-transform duration-500 motion-safe:group-hover:scale-105\",\n fallback: \"flex h-full w-full items-center justify-center bg-linear-to-br from-accent/15 via-media to-accent-2/15 text-accent/60\",\n overlay: \"absolute z-10 flex items-center gap-1.5\",\n body: \"relative flex flex-1 flex-col gap-3\",\n title: \"line-clamp-1 text-sm font-semibold text-fg transition-colors group-hover:text-fg-accent\",\n description: \"line-clamp-2 text-xs text-fg-secondary\",\n stat: \"min-w-0\",\n statLabel: \"text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n statValue: \"font-display text-xl font-black tabular-nums text-fg\",\n footer: \"relative mt-auto flex items-center gap-2 border-t border-border-subtle pt-3 text-xs text-fg-secondary\",\n },\n variants: {\n radius: { md: { root: \"rounded-md\" }, lg: { root: \"rounded-lg\" }, xl: { root: \"rounded-xl\" } },\n tone: { default: {}, elevated: { root: \"bg-surface-2 shadow-md\" }, glass: { root: \"bg-surface-1/70 backdrop-blur-md\" } },\n interactive: { true: { root: \"kz-spotlight kz-lift hover:border-accent/50\" } },\n padding: { none: { body: \"p-0\" }, sm: { body: \"p-3\" }, md: { body: \"p-4\" }, lg: { body: \"p-6\" } },\n },\n defaultVariants: { radius: \"xl\", tone: \"default\", padding: \"md\" },\n});\n"],"mappings":"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","names":["jsx","jsx","jsxs","React","jsx","jsxs","jsx","jsxs"]}
|
|
1
|
+
{"version":3,"sources":["../src/media-grid/shorts-shelf.tsx","../src/block-link.tsx","../src/media-grid/media-grid.tsx","../src/media-grid/video-card.tsx","../src/card/card.tsx","../src/card/recipe.ts"],"sourcesContent":["// Client (the arrows scroll the row). A horizontal row of 9:16 cards of one height: scroll-snap, arrows with a mouse,\n// a swipe on touch, a \"See all\" link. The row is a labelled list that scrolls with the keyboard (it takes focus).\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\nexport interface ShortsShelfProps<T> extends Omit<React.ComponentProps<\"section\">, \"children\" | \"title\"> {\n /** The shelf's accessible name (\"Shorts\"), passed translated; shown as its heading unless `title` is set. */\n label: string;\n /** A heading different from the name. */\n title?: React.ReactNode;\n /** The clips, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** One card: use `VideoCard aspect=\"portrait\"`. */\n renderItem: (item: T, index: number) => React.ReactNode;\n /** Opens the vertical feed. */\n seeAll?: { href: string; label: string; linkAs?: LinkComponent };\n /** The arrows' names, passed translated. */\n previousLabel: string;\n /** The next arrow's name. */\n nextLabel: string;\n}\n\nconst Chevron = ({ flip }: { flip?: boolean }) => (\n <svg viewBox=\"0 0 24 24\" width=\"18\" height=\"18\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden className={flip ? \"rotate-180\" : undefined}>\n <path d=\"m9 6 6 6-6 6\" />\n </svg>\n);\n\nconst ARROW =\n \"hidden h-9 w-9 items-center justify-center rounded-full border border-border-default bg-surface-1 text-fg shadow-sm transition-colors hover:bg-surface-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-40 [@media(hover:hover)]:inline-flex\";\n\n/** A Shorts shelf: equal-height 9:16 cards in a snap-scrolling row. */\nexport function ShortsShelf<T>({ label, title, items, getId, renderItem, seeAll, previousLabel, nextLabel, className, ...props }: ShortsShelfProps<T>) {\n const row = React.useRef<HTMLUListElement>(null);\n const [edge, setEdge] = React.useState({ start: true, end: false });\n const measure = React.useCallback(() => {\n const el = row.current;\n if (!el) return;\n setEdge({ start: el.scrollLeft <= 2, end: el.scrollLeft + el.clientWidth >= el.scrollWidth - 2 });\n }, []);\n React.useEffect(measure, [measure, items.length]);\n const page = (dir: 1 | -1) => {\n const el = row.current;\n if (el) el.scrollBy({ left: dir * el.clientWidth * 0.85, behavior: window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? \"auto\" : \"smooth\" });\n };\n const headingId = React.useId();\n if (items.length === 0) return null;\n return (\n <section aria-labelledby={headingId} data-shorts-shelf className={cn(\"min-w-0\", className)} {...props}>\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={headingId} className=\"m-0 mr-auto text-base font-bold text-fg\">\n {title ?? label}\n </h2>\n {seeAll && (\n <BlockLink href={seeAll.href} linkAs={seeAll.linkAs} className=\"text-sm font-semibold text-fg-accent hover:underline\">\n {seeAll.label}\n </BlockLink>\n )}\n <button type=\"button\" aria-label={previousLabel} disabled={edge.start} onClick={() => page(-1)} className={ARROW}>\n <Chevron flip />\n </button>\n <button type=\"button\" aria-label={nextLabel} disabled={edge.end} onClick={() => page(1)} className={ARROW}>\n <Chevron />\n </button>\n </div>\n <ul\n ref={row}\n onScroll={measure}\n // biome-ignore: a scroll container must take the keyboard focus to scroll with the arrow keys\n tabIndex={0}\n aria-labelledby={headingId}\n className=\"m-0 flex list-none snap-x snap-mandatory items-stretch gap-3 overflow-x-auto overscroll-x-contain p-0 pb-2 [scrollbar-width:none] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-scrollbar]:hidden\"\n >\n {items.map((item, i) => (\n <li key={getId(item)} className=\"w-[9.5rem] shrink-0 snap-start sm:w-44\">\n {renderItem(item, i)}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","// The links of the page blocks (PageHero's back link, LinkCard, ArgumentCard, ActionBar): an internal path renders\n// through the app's router link (`linkAs`, e.g. Next's `Link`), anything else is an `<a>` that opens in a new tab.\n// Shared by the block entries; never exported on its own.\nimport type * as React from \"react\";\n\n/** The app's link component (Next's `Link`, React Router's `Link`…): receives `href`, `className` and the children. */\nexport type LinkComponent = React.ElementType<{ href: string; className?: string; children?: React.ReactNode; \"aria-label\"?: string; \"aria-describedby\"?: string }>;\n\n/** An address that leaves the app: an absolute URL or a protocol (`mailto:`). */\nexport const isExternal = (href: string) => /^[a-z][a-z0-9+.-]*:/i.test(href);\n\nexport function BlockLink({\n href,\n linkAs: Link = \"a\",\n external = isExternal(href),\n rel,\n ...props\n}: Omit<React.ComponentProps<\"a\">, \"href\"> & { href: string; linkAs?: LinkComponent; external?: boolean }) {\n if (external) return <a href={href} target=\"_blank\" rel={rel ?? \"noopener noreferrer\"} {...props} />;\n const Comp = Link as React.ElementType;\n return <Comp href={href} {...props} />;\n}\n","// Client (it renders the shelf). Mixed orientations without a broken grid. `split` (the feed default) sends the 9:16\n// clips to a `ShortsShelf` and lays the rest in a uniform 16:9 grid; `uniform` puts everything in one grid of one frame\n// (a source of the other orientation is told to `contain`, never cropped to a face). `layout=\"list\"` is one column.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\nimport { ShortsShelf, type ShortsShelfProps } from \"./shorts-shelf\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface MediaGridState {\n /** The frame the card is drawn in (`aspect` of `VideoCard`). */\n aspect: VideoCardAspect;\n /** The card's `layout`. */\n layout: \"stack\" | \"row\";\n /** The source's orientation differs from the frame: pass `fit=\"contain\"`. */\n mismatch: boolean;\n}\n\nexport interface MediaGridProps<T> extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** The videos, in order. */\n items: readonly T[];\n /** A stable key for an item. */\n getId: (item: T) => string;\n /** The source's orientation (from its width and height). */\n orientationOf: (item: T) => VideoCardAspect;\n /** One card, drawn in the frame the grid gives (`state`): use `VideoCard`. */\n renderItem: (item: T, state: MediaGridState) => React.ReactNode;\n /**\n * `split`: verticals on the shelf, the others in the grid · `uniform`: all in one frame (`frame`).\n * @default \"split\"\n */\n mode?: \"split\" | \"uniform\";\n /** The frame of `uniform`. @default \"landscape\" */\n frame?: VideoCardAspect;\n /** `grid` or `list` (one row per video). @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The shelf of `split`: its name, \"See all\" and arrows, passed translated. */\n shelf: Pick<ShortsShelfProps<unknown>, \"label\" | \"title\" | \"seeAll\" | \"previousLabel\" | \"nextLabel\">;\n}\n\nconst GRID = {\n landscape: \"grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\",\n portrait: \"grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6\",\n} as const;\n\n/** A media grid that never mixes heights badly: a shelf for the 9:16, a uniform grid for the rest. */\nexport function MediaGrid<T>({ items, getId, orientationOf, renderItem, mode = \"split\", frame = \"landscape\", layout = \"grid\", shelf, className, ...props }: MediaGridProps<T>) {\n const row = layout === \"list\";\n const split = mode === \"split\";\n const verticals = split ? items.filter((i) => orientationOf(i) === \"portrait\") : [];\n const rest = split ? items.filter((i) => orientationOf(i) !== \"portrait\") : items;\n const gridFrame: VideoCardAspect = split ? \"landscape\" : frame;\n const state = (item: T, aspect: VideoCardAspect): MediaGridState => ({ aspect, layout: row ? \"row\" : \"stack\", mismatch: orientationOf(item) !== aspect });\n return (\n <div data-media-grid={mode} className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n {verticals.length > 0 && <ShortsShelf {...shelf} items={verticals} getId={getId} renderItem={(item) => renderItem(item, { ...state(item, \"portrait\"), layout: \"stack\" })} />}\n {rest.length > 0 && (\n <ul data-grid-frame={gridFrame} className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[gridFrame])}>\n {rest.map((item) => (\n <li key={getId(item)} className=\"min-w-0\">\n {renderItem(item, state(item, gridFrame))}\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n","// Client (hover / focus swaps the picture for its animated preview). A video in a grid or a shelf: the picture in a 16:9\n// or 9:16 frame (a source of the other shape is shown inside, never stretched), badges, duration, the title on two lines\n// reserved, the creator, a count and one quick action — the same height of body in every card so a row aligns.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport type { DefaultAvatar } from \"../avatar/default-avatar\";\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\n\nexport type VideoCardAspect = \"landscape\" | \"portrait\";\n\nexport interface VideoCardCreator {\n /** The creator's name. */\n name: string;\n /** Their photo. */\n avatarSrc?: string | null;\n /** Their profile. */\n href?: string;\n /** The Krizaka default picture when there is no photo (a brand and a seed). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport interface VideoCardProps extends Omit<React.ComponentProps<\"article\">, \"title\"> {\n /** The title; it names the card and is its link. */\n title: string;\n /** Where the card opens. */\n href: string;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n /**\n * The frame: `landscape` (16:9) or `portrait` (9:16).\n * @default \"landscape\"\n */\n aspect?: VideoCardAspect;\n /**\n * `stack` (picture over text) or `row` (picture beside the text: the list mode of a section).\n * @default \"stack\"\n */\n layout?: \"stack\" | \"row\";\n /** The picture. */\n poster?: string | null;\n /** An animated picture (WebP) shown while the card is hovered or focused. */\n previewSrc?: string | null;\n /**\n * `cover` fills the frame; `contain` draws the whole picture over a blurred copy of itself (a source of the other\n * orientation: no cropped face, no black bar).\n * @default \"cover\"\n */\n fit?: \"cover\" | \"contain\";\n /** The length, already formatted (`3:42`). */\n duration?: string;\n /** Badges at the top-left of the picture (Free, a price, 18+). Put them on `scrim` so they read in both themes. */\n badges?: React.ReactNode;\n /** Who made it: name, photo, profile. */\n creator?: VideoCardCreator;\n /** What is counted (`12.4K views`), already formatted. */\n meta?: React.ReactNode;\n /** One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. */\n action?: React.ReactNode;\n /** A sensitive picture: blurred and scaled so nothing shows (put the reveal button in `overlay`). */\n blurred?: boolean;\n /** Over the whole picture, above the card's link (a veil, a reveal button). */\n overlay?: React.ReactNode;\n /** Shown instead of the picture while there is none. */\n fallback?: React.ReactNode;\n /** `eager` for the first cards of a page. */\n loading?: \"lazy\" | \"eager\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers. */\nexport function VideoCard({\n title,\n href,\n linkAs,\n aspect = \"landscape\",\n layout = \"stack\",\n poster,\n previewSrc,\n fit = \"cover\",\n duration,\n badges,\n creator,\n meta,\n action,\n fallback,\n blurred = false,\n overlay,\n loading = \"lazy\",\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}: VideoCardProps) {\n const [live, setLive] = React.useState(false);\n const picture = live && previewSrc ? previewSrc : poster;\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <article\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n onMouseEnter={(e) => (setLive(true), onMouseEnter?.(e))}\n onMouseLeave={(e) => (setLive(false), onMouseLeave?.(e))}\n onFocus={(e) => (setLive(true), onFocus?.(e))}\n onBlur={(e) => (setLive(false), onBlur?.(e))}\n {...props}\n >\n <Card.Root interactive tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n {fit === \"contain\" && picture && <img src={picture} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image src={picture} loading={loading} fallback={fallback} className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")} />\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\">\n <span className=\"rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media\">{duration}</span>\n </Card.Overlay>\n )}\n </Card.Media>\n <Card.Body className=\"min-w-0 flex-1 justify-between gap-2 p-3\">\n <h3 className=\"m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg\">\n <BlockLink href={href} linkAs={linkAs} className=\"line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring\">\n {title}\n </BlockLink>\n </h3>\n {/* A narrow card (9:16 on a shelf) puts the count and the action on a second line so the name is never cut to an initial. */}\n <div className={cn(\"relative z-10 text-xs text-fg-secondary\", tall ? \"flex flex-col gap-1\" : \"flex h-8 items-center gap-2\")}>\n {creator && (\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Avatar src={creator.avatarSrc} defaultAvatar={creator.defaultAvatar} alt=\"\" fallback={creator.name.charAt(0)} size=\"xs\" className=\"shrink-0\" />\n {creator.href ? (\n <BlockLink href={creator.href} linkAs={linkAs} className=\"min-w-0 truncate hover:text-fg\">\n {creator.name}\n </BlockLink>\n ) : (\n <span className=\"min-w-0 truncate\">{creator.name}</span>\n )}\n </div>\n )}\n {(meta || action) && (\n <div className={cn(\"flex items-center gap-2\", tall ? \"h-7 justify-between\" : \"ml-auto shrink-0\")}>\n {meta && <span className=\"shrink-0 font-mono text-[11px] text-fg-muted\">{meta}</span>}\n {action && <span className=\"shrink-0\">{action}</span>}\n </div>\n )}\n </div>\n </Card.Body>\n </Card.Root>\n </article>\n );\n}\n","// Server-safe: no hook, no context. One `tv` definition with slots: each part takes its slot, and a product overrides\n// any part through `className` (merged last by tailwind-merge).\nimport { Slot } from \"radix-ui\";\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { cn } from \"../cn\";\nimport { cardRecipe } from \"./recipe\";\n\nexport const card = tv(cardRecipe);\n\ntype CardVariants = VariantProps<typeof card>;\n/** The parts without a variant read the default slots: no context, so server-safe. */\nconst slots = card();\n\nexport type CardRootProps = React.ComponentProps<\"div\"> &\n Pick<CardVariants, \"radius\" | \"tone\" | \"interactive\"> & {\n /**\n * md · lg · xl.\n * @default \"xl\"\n */\n radius?: CardVariants[\"radius\"];\n /**\n * default (the base surface) · elevated (raised, a shadow) · glass (translucent, blurred).\n * @default \"default\"\n */\n tone?: CardVariants[\"tone\"];\n /** The spotlight that follows the pointer and the lift on hover: for a card that is a link. */\n interactive?: CardVariants[\"interactive\"];\n /** Renders the child (a link, an article) instead of the <div>, with props, classes and ref merged. */\n asChild?: boolean;\n /** Enters on scroll (MotionObserver): the index in the grid becomes the delay (50 ms a step, 8 steps at most). */\n reveal?: number;\n };\n\nexport function CardRoot({ asChild, reveal, radius, tone, interactive, className, style, ...props }: CardRootProps) {\n const Comp = asChild ? Slot.Root : \"div\";\n const revealStyle =\n reveal === undefined ? style : ({ ...style, \"--kz-delay\": `${Math.min(Math.max(reveal, 0), 8) * 50}ms` } as React.CSSProperties);\n return (\n <Comp\n data-reveal={reveal === undefined ? undefined : \"\"}\n data-interactive={interactive ? \"\" : undefined}\n style={revealStyle}\n className={card({ radius, tone, interactive }).root({ className })}\n {...props}\n />\n );\n}\n\nconst ASPECT = { video: \"aspect-video\", square: \"aspect-square\", portrait: \"aspect-[3/4]\", auto: \"\" } as const;\nexport type CardMediaProps = React.ComponentProps<\"div\"> & {\n /** The ratio of the media: video (16:9) · square · portrait (3:4) · auto (the content's). */\n aspect?: keyof typeof ASPECT;\n};\n\nexport function CardMedia({ aspect = \"video\", className, ...props }: CardMediaProps) {\n return <div data-aspect={aspect} className={slots.media({ className: cn(ASPECT[aspect], className) })} {...props} />;\n}\n\nexport type CardImageProps = Omit<React.ComponentProps<\"img\">, \"src\"> & {\n /** The image's URL; `null` or nothing shows the `fallback`. */\n src?: string | null;\n /** Shown when there is no image: an icon, an illustration (decorative). */\n fallback?: React.ReactNode;\n /**\n * When the browser loads it: `lazy` (default, a card in a list or below the fold) or `eager` for the first cards\n * of a page — the image that is the largest contentful paint must not wait (add `fetchPriority=\"high\"`).\n * @default \"lazy\"\n */\n loading?: \"lazy\" | \"eager\";\n};\n\n/** The image of a media, or its `fallback` when there is none. `alt` is empty by default: the title names the card. */\nexport function CardImage({ src, alt = \"\", fallback, loading = \"lazy\", className, ...props }: CardImageProps) {\n if (!src) {\n return (\n <div data-fallback=\"\" aria-hidden className={slots.fallback({ className })}>\n {fallback}\n </div>\n );\n }\n return <img src={src} alt={alt} loading={loading} decoding=\"async\" className={slots.image({ className })} {...props} />;\n}\n\nconst CORNER = {\n \"top-left\": \"left-2.5 top-2.5\",\n \"top-right\": \"right-2.5 top-2.5\",\n \"bottom-left\": \"bottom-2.5 left-2.5\",\n \"bottom-right\": \"bottom-2.5 right-2.5\",\n} as const;\nexport type CardOverlayProps = React.ComponentProps<\"div\"> & {\n /** The corner of the media it sits in. */\n corner?: keyof typeof CORNER;\n};\n\n/** What sits on the media (badges, a caption). `scrim` and `fg-on-media` are invariant: nothing to do for light. */\nexport function CardOverlay({ corner = \"top-left\", className, ...props }: CardOverlayProps) {\n return <div data-corner={corner} className={slots.overlay({ className: cn(CORNER[corner], className) })} {...props} />;\n}\n\nexport type CardBodyProps = React.ComponentProps<\"div\"> & {\n /**\n * none · sm · md · lg.\n * @default \"md\"\n */\n padding?: CardVariants[\"padding\"];\n};\n\nexport function CardBody({ padding, className, ...props }: CardBodyProps) {\n return <div className={card({ padding }).body({ className })} {...props} />;\n}\n\nexport type CardTitleProps = React.ComponentProps<\"h3\"> & {\n /** The heading level, to fit the page's outline. */\n as?: \"h2\" | \"h3\" | \"h4\";\n};\n\nexport function CardTitle({ as: Tag = \"h3\", className, ...props }: CardTitleProps) {\n return <Tag className={slots.title({ className })} {...props} />;\n}\n\nexport function CardDescription({ className, ...props }: React.ComponentProps<\"p\">) {\n return <p className={slots.description({ className })} {...props} />;\n}\n\nexport type CardStatProps = React.ComponentProps<\"div\"> & {\n /** What the figure is, in small capitals above it (the figure is the children). */\n label: React.ReactNode;\n};\n\n/** A figure put forward: the label in capitals, the value in tabular digits. */\nexport function CardStat({ label, className, children, ...props }: CardStatProps) {\n return (\n <div className={slots.stat({ className })} {...props}>\n <p className={slots.statLabel()}>{label}</p>\n <p className={slots.statValue()}>{children}</p>\n </div>\n );\n}\n\nexport function CardFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div className={slots.footer({ className })} {...props} />;\n}\n\n/** `Card.Root/Media/Image/Overlay/Body/Title/Description/Stat/Footer`. */\nexport const Card = {\n Root: CardRoot,\n Media: CardMedia,\n Image: CardImage,\n Overlay: CardOverlay,\n Body: CardBody,\n Title: CardTitle,\n Description: CardDescription,\n Stat: CardStat,\n Footer: CardFooter,\n};\n","// The card's parts, radii, tones and paddings, written once as classes of the Krizaka tokens: the web wears them with\n// `tv(cardRecipe)`, React Native reads the same classes into styles (native/card.tsx): a part of the card that exists only\n// on the web (the media's zoom, the spotlight) is simply ignored there.\nimport { defineRecipe } from \"../recipes/define\";\n\nexport const cardRecipe = defineRecipe({\n slots: {\n root:\n \"group relative flex flex-col overflow-hidden border border-border-default bg-surface-1 text-fg transition-colors \" +\n \"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\",\n media: \"relative overflow-hidden bg-media\",\n image: \"h-full w-full object-cover transition-transform duration-500 motion-safe:group-hover:scale-105\",\n fallback: \"flex h-full w-full items-center justify-center bg-linear-to-br from-accent/15 via-media to-accent-2/15 text-accent/60\",\n overlay: \"absolute z-10 flex items-center gap-1.5\",\n body: \"relative flex flex-1 flex-col gap-3\",\n title: \"line-clamp-1 text-sm font-semibold text-fg transition-colors group-hover:text-fg-accent\",\n description: \"line-clamp-2 text-xs text-fg-secondary\",\n stat: \"min-w-0\",\n statLabel: \"text-[10px] font-semibold uppercase tracking-wider text-fg-secondary\",\n statValue: \"font-display text-xl font-black tabular-nums text-fg\",\n footer: \"relative mt-auto flex items-center gap-2 border-t border-border-subtle pt-3 text-xs text-fg-secondary\",\n },\n variants: {\n radius: { md: { root: \"rounded-md\" }, lg: { root: \"rounded-lg\" }, xl: { root: \"rounded-xl\" } },\n tone: { default: {}, elevated: { root: \"bg-surface-2 shadow-md\" }, glass: { root: \"bg-surface-1/70 backdrop-blur-md\" } },\n interactive: { true: { root: \"kz-spotlight kz-lift hover:border-accent/50\" } },\n padding: { none: { body: \"p-0\" }, sm: { body: \"p-3\" }, md: { body: \"p-4\" }, lg: { body: \"p-6\" } },\n },\n defaultVariants: { radius: \"xl\", tone: \"default\", padding: \"md\" },\n});\n"],"mappings":"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","names":["jsx","jsx","jsxs","React","jsx","jsxs","jsx","jsxs"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krizaka/ui",
|
|
3
|
-
"version": "3.18.
|
|
3
|
+
"version": "3.18.1",
|
|
4
4
|
"description": "The Krizaka front-end platform's components: the primitives (button, card, dialog, toast, menu, field, tabs, chip, switch, slider, command palette, theme, countdown…) on the semantic --kz-* tokens, the animated marks (Krizaka, Orazaka, Orochia, Yasakia, Yororis) and the motion signature — web and /native.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"krizaka",
|
|
@@ -629,7 +629,7 @@
|
|
|
629
629
|
],
|
|
630
630
|
"peerDependencies": {
|
|
631
631
|
"@krizaka/query": ">=0.2.1",
|
|
632
|
-
"@krizaka/tailwind": ">=3.18.
|
|
632
|
+
"@krizaka/tailwind": ">=3.18.1",
|
|
633
633
|
"@maplibre/maplibre-react-native": ">=11",
|
|
634
634
|
"@shopify/flash-list": ">=2",
|
|
635
635
|
"expo-camera": ">=16",
|
|
@@ -689,8 +689,8 @@
|
|
|
689
689
|
"typescript": "^5.9.0",
|
|
690
690
|
"vitest": "^4.1.11",
|
|
691
691
|
"zod": "^4.6.5",
|
|
692
|
-
"@krizaka/
|
|
693
|
-
"@krizaka/
|
|
692
|
+
"@krizaka/config": "0.4.1",
|
|
693
|
+
"@krizaka/query": "0.2.1"
|
|
694
694
|
},
|
|
695
695
|
"engines": {
|
|
696
696
|
"node": ">=22"
|
|
@@ -2143,7 +2143,7 @@
|
|
|
2143
2143
|
"sonner": "^2.0.8",
|
|
2144
2144
|
"tailwind-variants": "^3.3.1",
|
|
2145
2145
|
"@krizaka/intl": "^0.2.1",
|
|
2146
|
-
"@krizaka/tokens": "^3.18.
|
|
2146
|
+
"@krizaka/tokens": "^3.18.1",
|
|
2147
2147
|
"@krizaka/pacer": "^0.1.0"
|
|
2148
2148
|
},
|
|
2149
2149
|
"scripts": {
|
package/registry/index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krizaka/ui",
|
|
3
|
-
"version": "3.18.
|
|
3
|
+
"version": "3.18.1",
|
|
4
4
|
"templatePurposes": {
|
|
5
5
|
"convince": {
|
|
6
6
|
"title": "Convince",
|
|
@@ -1750,7 +1750,7 @@
|
|
|
1750
1750
|
"native": 2
|
|
1751
1751
|
},
|
|
1752
1752
|
"dependencies": [
|
|
1753
|
-
"@krizaka/tokens@^3.18.
|
|
1753
|
+
"@krizaka/tokens@^3.18.1",
|
|
1754
1754
|
"@protomaps/basemaps@5.7.2",
|
|
1755
1755
|
"tailwind-variants@^3.3.1"
|
|
1756
1756
|
],
|
|
@@ -1978,7 +1978,7 @@
|
|
|
1978
1978
|
"native": 0
|
|
1979
1979
|
},
|
|
1980
1980
|
"dependencies": [
|
|
1981
|
-
"@krizaka/tokens@^3.18.
|
|
1981
|
+
"@krizaka/tokens@^3.18.1",
|
|
1982
1982
|
"radix-ui@^1.7.0",
|
|
1983
1983
|
"tailwind-variants@^3.3.1"
|
|
1984
1984
|
],
|
|
@@ -2494,7 +2494,7 @@
|
|
|
2494
2494
|
"native": 0
|
|
2495
2495
|
},
|
|
2496
2496
|
"dependencies": [
|
|
2497
|
-
"@krizaka/tokens@^3.18.
|
|
2497
|
+
"@krizaka/tokens@^3.18.1",
|
|
2498
2498
|
"radix-ui@^1.7.0",
|
|
2499
2499
|
"tailwind-variants@^3.3.1"
|
|
2500
2500
|
],
|
package/registry/map.json
CHANGED
package/registry/media-grid.json
CHANGED
|
@@ -347,7 +347,7 @@
|
|
|
347
347
|
},
|
|
348
348
|
{
|
|
349
349
|
"path": "media-grid/video-card.tsx",
|
|
350
|
-
"content": "// Client (hover / focus swaps the picture for its animated preview). A video in a grid or a shelf: the picture in a 16:9\n// or 9:16 frame (a source of the other shape is shown inside, never stretched), badges, duration, the title on two lines\n// reserved, the creator, a count and one quick action — the same height of body in every card so a row aligns.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport type { DefaultAvatar } from \"../avatar/default-avatar\";\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\n\nexport type VideoCardAspect = \"landscape\" | \"portrait\";\n\nexport interface VideoCardCreator {\n /** The creator's name. */\n name: string;\n /** Their photo. */\n avatarSrc?: string | null;\n /** Their profile. */\n href?: string;\n /** The Krizaka default picture when there is no photo (a brand and a seed). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport interface VideoCardProps extends Omit<React.ComponentProps<\"article\">, \"title\"> {\n /** The title; it names the card and is its link. */\n title: string;\n /** Where the card opens. */\n href: string;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n /**\n * The frame: `landscape` (16:9) or `portrait` (9:16).\n * @default \"landscape\"\n */\n aspect?: VideoCardAspect;\n /**\n * `stack` (picture over text) or `row` (picture beside the text: the list mode of a section).\n * @default \"stack\"\n */\n layout?: \"stack\" | \"row\";\n /** The picture. */\n poster?: string | null;\n /** An animated picture (WebP) shown while the card is hovered or focused. */\n previewSrc?: string | null;\n /**\n * `cover` fills the frame; `contain` draws the whole picture over a blurred copy of itself (a source of the other\n * orientation: no cropped face, no black bar).\n * @default \"cover\"\n */\n fit?: \"cover\" | \"contain\";\n /** The length, already formatted (`3:42`). */\n duration?: string;\n /** Badges at the top-left of the picture (Free, a price, 18+). Put them on `scrim` so they read in both themes. */\n badges?: React.ReactNode;\n /** Who made it: name, photo, profile. */\n creator?: VideoCardCreator;\n /** What is counted (`12.4K views`), already formatted. */\n meta?: React.ReactNode;\n /** One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. */\n action?: React.ReactNode;\n /** A sensitive picture: blurred and scaled so nothing shows (put the reveal button in `overlay`). */\n blurred?: boolean;\n /** Over the whole picture, above the card's link (a veil, a reveal button). */\n overlay?: React.ReactNode;\n /** Shown instead of the picture while there is none. */\n fallback?: React.ReactNode;\n /** `eager` for the first cards of a page. */\n loading?: \"lazy\" | \"eager\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers. */\nexport function VideoCard({\n title,\n href,\n linkAs,\n aspect = \"landscape\",\n layout = \"stack\",\n poster,\n previewSrc,\n fit = \"cover\",\n duration,\n badges,\n creator,\n meta,\n action,\n fallback,\n blurred = false,\n overlay,\n loading = \"lazy\",\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}: VideoCardProps) {\n const [live, setLive] = React.useState(false);\n const picture = live && previewSrc ? previewSrc : poster;\n const row = layout === \"row\";\n return (\n <article\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n onMouseEnter={(e) => (setLive(true), onMouseEnter?.(e))}\n onMouseLeave={(e) => (setLive(false), onMouseLeave?.(e))}\n onFocus={(e) => (setLive(true), onFocus?.(e))}\n onBlur={(e) => (setLive(false), onBlur?.(e))}\n {...props}\n >\n <Card.Root interactive tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n {fit === \"contain\" && picture && <img src={picture} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image src={picture} loading={loading} fallback={fallback} className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")} />\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\">\n <span className=\"rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media\">{duration}</span>\n </Card.Overlay>\n )}\n </Card.Media>\n <Card.Body className=\"min-w-0 flex-1 justify-between gap-2 p-3\">\n <h3 className=\"m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg\">\n <BlockLink href={href} linkAs={linkAs} className=\"line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring\">\n {title}\n </BlockLink>\n </h3>\n <div className
|
|
350
|
+
"content": "// Client (hover / focus swaps the picture for its animated preview). A video in a grid or a shelf: the picture in a 16:9\n// or 9:16 frame (a source of the other shape is shown inside, never stretched), badges, duration, the title on two lines\n// reserved, the creator, a count and one quick action — the same height of body in every card so a row aligns.\nimport * as React from \"react\";\n\nimport { Avatar } from \"../avatar\";\nimport type { DefaultAvatar } from \"../avatar/default-avatar\";\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\n\nexport type VideoCardAspect = \"landscape\" | \"portrait\";\n\nexport interface VideoCardCreator {\n /** The creator's name. */\n name: string;\n /** Their photo. */\n avatarSrc?: string | null;\n /** Their profile. */\n href?: string;\n /** The Krizaka default picture when there is no photo (a brand and a seed). */\n defaultAvatar?: DefaultAvatar;\n}\n\nexport interface VideoCardProps extends Omit<React.ComponentProps<\"article\">, \"title\"> {\n /** The title; it names the card and is its link. */\n title: string;\n /** Where the card opens. */\n href: string;\n /** The app's router link (Next's `Link`). */\n linkAs?: LinkComponent;\n /**\n * The frame: `landscape` (16:9) or `portrait` (9:16).\n * @default \"landscape\"\n */\n aspect?: VideoCardAspect;\n /**\n * `stack` (picture over text) or `row` (picture beside the text: the list mode of a section).\n * @default \"stack\"\n */\n layout?: \"stack\" | \"row\";\n /** The picture. */\n poster?: string | null;\n /** An animated picture (WebP) shown while the card is hovered or focused. */\n previewSrc?: string | null;\n /**\n * `cover` fills the frame; `contain` draws the whole picture over a blurred copy of itself (a source of the other\n * orientation: no cropped face, no black bar).\n * @default \"cover\"\n */\n fit?: \"cover\" | \"contain\";\n /** The length, already formatted (`3:42`). */\n duration?: string;\n /** Badges at the top-left of the picture (Free, a price, 18+). Put them on `scrim` so they read in both themes. */\n badges?: React.ReactNode;\n /** Who made it: name, photo, profile. */\n creator?: VideoCardCreator;\n /** What is counted (`12.4K views`), already formatted. */\n meta?: React.ReactNode;\n /** One quick action at the end of the footer (a tip, a save). Its clicks must not follow the card's link. */\n action?: React.ReactNode;\n /** A sensitive picture: blurred and scaled so nothing shows (put the reveal button in `overlay`). */\n blurred?: boolean;\n /** Over the whole picture, above the card's link (a veil, a reveal button). */\n overlay?: React.ReactNode;\n /** Shown instead of the picture while there is none. */\n fallback?: React.ReactNode;\n /** `eager` for the first cards of a page. */\n loading?: \"lazy\" | \"eager\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** A video card whose frame, body and footer have one height per aspect, so a grid row or a shelf never staggers. */\nexport function VideoCard({\n title,\n href,\n linkAs,\n aspect = \"landscape\",\n layout = \"stack\",\n poster,\n previewSrc,\n fit = \"cover\",\n duration,\n badges,\n creator,\n meta,\n action,\n fallback,\n blurred = false,\n overlay,\n loading = \"lazy\",\n className,\n onMouseEnter,\n onMouseLeave,\n onFocus,\n onBlur,\n ...props\n}: VideoCardProps) {\n const [live, setLive] = React.useState(false);\n const picture = live && previewSrc ? previewSrc : poster;\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <article\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n onMouseEnter={(e) => (setLive(true), onMouseEnter?.(e))}\n onMouseLeave={(e) => (setLive(false), onMouseLeave?.(e))}\n onFocus={(e) => (setLive(true), onFocus?.(e))}\n onBlur={(e) => (setLive(false), onBlur?.(e))}\n {...props}\n >\n <Card.Root interactive tone=\"glass\" className={cn(\"h-full w-full max-w-full\", row ? \"flex-row\" : \"flex-col\")}>\n <Card.Media aspect=\"auto\" className={cn(\"shrink-0\", FRAME[aspect], row && (aspect === \"portrait\" ? \"w-24 sm:w-28\" : \"w-40 sm:w-56\"))}>\n {fit === \"contain\" && picture && <img src={picture} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image src={picture} loading={loading} fallback={fallback} className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")} />\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\">\n <span className=\"rounded-sm bg-scrim px-1.5 py-0.5 font-mono text-[11px] text-fg-on-media\">{duration}</span>\n </Card.Overlay>\n )}\n </Card.Media>\n <Card.Body className=\"min-w-0 flex-1 justify-between gap-2 p-3\">\n <h3 className=\"m-0 min-h-[2.5em] text-sm font-semibold leading-tight text-fg\">\n <BlockLink href={href} linkAs={linkAs} className=\"line-clamp-2 outline-none after:absolute after:inset-0 after:z-0 after:content-[''] focus-visible:after:ring-2 focus-visible:after:ring-ring\">\n {title}\n </BlockLink>\n </h3>\n {/* A narrow card (9:16 on a shelf) puts the count and the action on a second line so the name is never cut to an initial. */}\n <div className={cn(\"relative z-10 text-xs text-fg-secondary\", tall ? \"flex flex-col gap-1\" : \"flex h-8 items-center gap-2\")}>\n {creator && (\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Avatar src={creator.avatarSrc} defaultAvatar={creator.defaultAvatar} alt=\"\" fallback={creator.name.charAt(0)} size=\"xs\" className=\"shrink-0\" />\n {creator.href ? (\n <BlockLink href={creator.href} linkAs={linkAs} className=\"min-w-0 truncate hover:text-fg\">\n {creator.name}\n </BlockLink>\n ) : (\n <span className=\"min-w-0 truncate\">{creator.name}</span>\n )}\n </div>\n )}\n {(meta || action) && (\n <div className={cn(\"flex items-center gap-2\", tall ? \"h-7 justify-between\" : \"ml-auto shrink-0\")}>\n {meta && <span className=\"shrink-0 font-mono text-[11px] text-fg-muted\">{meta}</span>}\n {action && <span className=\"shrink-0\">{action}</span>}\n </div>\n )}\n </div>\n </Card.Body>\n </Card.Root>\n </article>\n );\n}\n"
|
|
351
351
|
},
|
|
352
352
|
{
|
|
353
353
|
"path": "meta.ts",
|
package/registry/nav-bar.json
CHANGED