@krizaka/ui 3.52.0 → 3.54.0
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/action-bar.js +1 -1
- package/dist/argument-card.js +2 -2
- package/dist/blocks.css +148 -0
- package/dist/chapter.d.ts +106 -0
- package/dist/chapter.js +174 -0
- package/dist/chapter.js.map +1 -0
- package/dist/choice-grid.js +1 -1
- package/dist/choice-grid.js.map +1 -1
- package/dist/{chunk-IBDTAMPF.js → chunk-7JG3VR4C.js} +2 -2
- package/dist/{chunk-C7LTF5CC.js → chunk-ENOS6ETI.js} +2 -2
- package/dist/{chunk-C7LTF5CC.js.map → chunk-ENOS6ETI.js.map} +1 -1
- package/dist/{chunk-2AGSO3WH.js → chunk-FVGFPB73.js} +2 -2
- package/dist/{chunk-2AGSO3WH.js.map → chunk-FVGFPB73.js.map} +1 -1
- package/dist/cover-hero.js +1 -1
- package/dist/link-card.js +2 -2
- package/dist/media-grid.js +1 -1
- package/dist/media-grid.js.map +1 -1
- package/dist/page-hero.js +1 -1
- package/dist/page-index.js +1 -1
- package/dist/service-card.js +1 -1
- package/dist/slot-picker.js +1 -1
- package/package.json +17 -3
- package/registry/account-menu.json +1 -1
- package/registry/account-settings.json +1 -1
- package/registry/achievement.json +1 -1
- package/registry/action-bar.json +2 -2
- package/registry/activity-feed.json +1 -1
- package/registry/agenda.json +1 -1
- package/registry/alert.json +1 -1
- package/registry/anatomy-plate.json +1 -1
- package/registry/app-header.json +1 -1
- package/registry/app-shell.json +1 -1
- package/registry/argument-card.json +2 -2
- package/registry/audio-player.json +1 -1
- package/registry/auth-layout.json +1 -1
- package/registry/avatar.json +1 -1
- package/registry/badge.json +1 -1
- package/registry/bird-plate.json +1 -1
- package/registry/button.json +1 -1
- package/registry/captcha.json +1 -1
- package/registry/card-grid.json +1 -1
- package/registry/card.json +1 -1
- package/registry/catalogue-page.json +1 -1
- package/registry/changelog-page.json +1 -1
- package/registry/chapter.json +514 -0
- package/registry/chat.json +1 -1
- package/registry/checkbox.json +1 -1
- package/registry/chip-link.json +1 -1
- package/registry/chip-row.json +1 -1
- package/registry/chip.json +1 -1
- package/registry/choice-grid.json +2 -2
- package/registry/code-block.json +1 -1
- package/registry/combobox.json +1 -1
- package/registry/command.json +1 -1
- package/registry/comparison-table.json +1 -1
- package/registry/component-page.json +1 -1
- package/registry/confirm-button.json +1 -1
- package/registry/contact-page.json +1 -1
- package/registry/continue-prompt.json +1 -1
- package/registry/countdown.json +1 -1
- package/registry/cover-hero.json +2 -2
- package/registry/cta-panel.json +1 -1
- package/registry/dashboard-layout.json +1 -1
- package/registry/data-table.json +1 -1
- package/registry/date-picker.json +1 -1
- package/registry/decision-list.json +1 -1
- package/registry/description-list.json +1 -1
- package/registry/detail-layout.json +1 -1
- package/registry/dialog.json +1 -1
- package/registry/docs-article-page.json +1 -1
- package/registry/docs-hub-page.json +1 -1
- package/registry/docs-layout.json +1 -1
- package/registry/docs-nav.json +1 -1
- package/registry/document-viewer.json +1 -1
- package/registry/drop-overlay.json +1 -1
- package/registry/dropdown-menu.json +1 -1
- package/registry/elephant.json +2 -2
- package/registry/empty-state.json +1 -1
- package/registry/engine-flow.json +1 -1
- package/registry/error-page.json +1 -1
- package/registry/examples/chapter/album.d.ts +4 -0
- package/registry/examples/chapter/album.js +34 -0
- package/registry/examples/chapter/album.tsx +30 -0
- package/registry/examples/chapter/detail.d.ts +4 -0
- package/registry/examples/chapter/detail.js +21 -0
- package/registry/examples/chapter/detail.tsx +16 -0
- package/registry/examples/chapter/foot.d.ts +4 -0
- package/registry/examples/chapter/foot.js +20 -0
- package/registry/examples/chapter/foot.tsx +15 -0
- package/registry/examples/chapter/head.d.ts +4 -0
- package/registry/examples/chapter/head.js +22 -0
- package/registry/examples/chapter/head.tsx +17 -0
- package/registry/examples/chapter/in-ruled-page.d.ts +4 -0
- package/registry/examples/chapter/in-ruled-page.js +23 -0
- package/registry/examples/chapter/in-ruled-page.tsx +19 -0
- package/registry/examples/chapter/index.d.ts +4 -0
- package/registry/examples/chapter/index.js +34 -0
- package/registry/examples/chapter/index.tsx +30 -0
- package/registry/examples/chapter/reading-page.d.ts +4 -0
- package/registry/examples/chapter/reading-page.js +34 -0
- package/registry/examples/chapter/reading-page.tsx +25 -0
- package/registry/field.json +1 -1
- package/registry/file-upload.json +1 -1
- package/registry/filter-bar.json +1 -1
- package/registry/flock.json +1 -1
- package/registry/footnote.json +1 -1
- package/registry/force-update-screen.json +1 -1
- package/registry/form.json +1 -1
- package/registry/gallery-page.json +1 -1
- package/registry/genui.json +1 -1
- package/registry/glossary-term.json +1 -1
- package/registry/glossary.json +1 -1
- package/registry/glow-card.json +1 -1
- package/registry/goal-gauge.json +1 -1
- package/registry/how-it-works-page.json +1 -1
- package/registry/image-cropper.json +1 -1
- package/registry/index.json +38 -6
- package/registry/iso.json +1 -1
- package/registry/kanban.json +1 -1
- package/registry/kbd.json +1 -1
- package/registry/kpi-explained.json +1 -1
- package/registry/landing-page.json +1 -1
- package/registry/landscape.json +1 -1
- package/registry/language-switch.json +1 -1
- package/registry/legal-page.json +1 -1
- package/registry/link-card.json +2 -2
- package/registry/list.json +1 -1
- package/registry/loader.json +1 -1
- package/registry/longform-page.json +1 -1
- package/registry/maintenance-screen.json +1 -1
- package/registry/map.json +2 -2
- package/registry/markdown.json +1 -1
- package/registry/marketing-layout.json +1 -1
- package/registry/marquee.json +1 -1
- package/registry/mascot-quote.json +1 -1
- package/registry/mascot-state.json +1 -1
- package/registry/mascots.json +1 -1
- package/registry/match-dialog.json +1 -1
- package/registry/media-capture.json +1 -1
- package/registry/media-gallery.json +1 -1
- package/registry/media-grid.json +2 -2
- package/registry/meta-row.json +1 -1
- package/registry/meter.json +1 -1
- package/registry/nav-bar.json +2 -2
- package/registry/next-actions.json +1 -1
- package/registry/number-ticker.json +1 -1
- package/registry/opening-hours.json +1 -1
- package/registry/page-header.json +1 -1
- package/registry/page-hero.json +2 -2
- package/registry/page-index.json +2 -2
- package/registry/page.json +1 -1
- package/registry/pagination.json +1 -1
- package/registry/photo-grid.json +1 -1
- package/registry/pointer-light.json +1 -1
- package/registry/popover.json +1 -1
- package/registry/pricing-page.json +1 -1
- package/registry/product-page.json +1 -1
- package/registry/profile-card.json +1 -1
- package/registry/progress.json +1 -1
- package/registry/promise-card.json +1 -1
- package/registry/radio-group.json +1 -1
- package/registry/rail-nav.json +2 -2
- package/registry/recipes.json +1 -1
- package/registry/router.json +1 -1
- package/registry/scroll-stage.json +1 -1
- package/registry/search-field.json +1 -1
- package/registry/section-backdrop.json +1 -1
- package/registry/separator.json +1 -1
- package/registry/service-card.json +2 -2
- package/registry/settings-layout.json +1 -1
- package/registry/showcase.json +1 -1
- package/registry/site-footer.json +2 -2
- package/registry/sites.json +1 -1
- package/registry/skeleton.json +1 -1
- package/registry/skip-link.json +1 -1
- package/registry/slider.json +1 -1
- package/registry/slot-picker.json +2 -2
- package/registry/slot.json +1 -1
- package/registry/specimen-tag.json +1 -1
- package/registry/spinner.json +1 -1
- package/registry/split-view.json +1 -1
- package/registry/stage-banner.json +1 -1
- package/registry/stat.json +1 -1
- package/registry/status-page.json +1 -1
- package/registry/step-progress.json +1 -1
- package/registry/step-showcase.json +1 -1
- package/registry/stepper.json +1 -1
- package/registry/sticky-action.json +1 -1
- package/registry/swipe-deck.json +1 -1
- package/registry/switch.json +1 -1
- package/registry/tabs.json +1 -1
- package/registry/tag-input.json +1 -1
- package/registry/tag-selector.json +1 -1
- package/registry/taped-photo.json +1 -1
- package/registry/terminal-replay.json +1 -1
- package/registry/text-style.json +1 -1
- package/registry/theme.json +1 -1
- package/registry/toast.json +1 -1
- package/registry/toc.json +1 -1
- package/registry/tooltip.json +1 -1
- package/registry/tree-view.json +1 -1
- package/registry/update-prompt.json +1 -1
- package/registry/upload-queue.json +1 -1
- package/registry/verified-badge.json +1 -1
- package/registry/vertical-video.json +1 -1
- package/registry/video-player.json +1 -1
- package/registry/video-trimmer.json +1 -1
- package/registry/virtual.json +1 -1
- package/registry/waveform.json +1 -1
- /package/dist/{chunk-IBDTAMPF.js.map → chunk-7JG3VR4C.js.map} +0 -0
package/dist/choice-grid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/choice-grid/choice-grid.tsx","../src/block-link.tsx","../src/router/route-state.tsx"],"sourcesContent":["// Client. A row of choices shown as tiles — a visual, a name, a line (story.css): pick a plan, a persona, a team, a side.\n// Selectable (`onValueChange`), it is a radio group with roving focus; with `href` on its items, a set of links (a\n// line-up that leads somewhere); otherwise a showcase of the line-up.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { useRouteBinding } from \"../router\";\nimport { brandClass, type StoryVariant, storyVariantClass } from \"../story-variant\";\n\nexport interface ChoiceItem {\n /** The value of the choice (and its React key). */\n id: string;\n /** What represents it: a mark, an avatar, an illustration. Decorative — the name carries the meaning. */\n visual: React.ReactNode;\n /** Its name, short. */\n name: React.ReactNode;\n /** One line under the name: what it is, its role. */\n title?: React.ReactNode;\n /** A small line above the visual (a family, a tier), after its `icon`. */\n eyebrow?: React.ReactNode;\n /** A small glyph before the eyebrow (decorative). */\n icon?: React.ReactNode;\n /** A short tag in the top corner (“P1”, “New”, “Popular”). */\n badge?: React.ReactNode;\n /** Under the line: a gauge (`StatGauge`), facts, a price. */\n extra?: React.ReactNode;\n /** At the bottom: where the tile leads (“Chapter 2 ↓”, “See the plan”). */\n meta?: React.ReactNode;\n /** Makes the tile a link (ignored when the grid is selectable). */\n href?: string;\n /** A brand scope for this tile (`orazaka` → `.brand-orazaka`): its accent becomes that brand's. */\n brand?: string;\n /** Not selectable. */\n disabled?: boolean;\n}\n\nexport type ChoiceGridProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"defaultValue\" | \"onChange\"> & {\n /** The accessible name of the group (“Choose your plan”) — passed translated. */\n label: string;\n /** The choices, in reading order. */\n items: readonly ChoiceItem[];\n /** A short mono line above the grid (a step, a tag). */\n tag?: React.ReactNode;\n /** A line beside the tag: what the choice means. */\n caption?: React.ReactNode;\n /** A call above the tiles, larger (“Choose your plan”). */\n prompt?: React.ReactNode;\n /** The chosen id (controlled). */\n value?: string;\n /** The chosen id at first (uncontrolled). */\n defaultValue?: string;\n /** Makes the grid a radio group: called with the id chosen by click, Enter, Space or the arrow keys. */\n onValueChange?: (id: string) => void;\n /** Binds the choice to this search parameter of the URL (`?type=…`): the URL is the state. Without it the state is local — only for an ephemeral choice. */\n routeKey?: string;\n /** The ids the parameter may hold; the first is the default unless `defaultValue` says otherwise. */\n routeValues?: readonly string[];\n /** The app's link component for the tiles' internal `href`s (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n /**\n * The number of columns (one on a phone).\n * @default min(items, 4)\n */\n columns?: number;\n /**\n * `default`: sober tiles. `arcade`: the select screen — the brand's light on each card, corners that lock, a flash.\n * @default \"default\"\n */\n variant?: StoryVariant;\n /** A brand scope for the whole grid (`orochia` → `.brand-orochia`). */\n brand?: string;\n /**\n * The tiles' arrival on mount (arcade: the corners locking one by one, the gauges filling). Always off under\n * `prefers-reduced-motion`.\n * @default true\n */\n animated?: boolean;\n};\n\nconst CORNERS = [\"tl\", \"tr\", \"bl\", \"br\"] as const;\n\n/**\n * A line-up of choices as tiles. With `onValueChange` (or `value`), a radio group: one tab stop, the arrow keys move\n * and choose, Home/End jump, the chosen tile is marked. With `href` on the items, a list of links. Otherwise a list\n * named by `label` that presents the line-up.\n */\nexport function ChoiceGrid({\n label,\n items,\n tag,\n caption,\n prompt,\n value: valueProp,\n defaultValue: defaultValueProp,\n onValueChange: onValueChangeProp,\n routeKey,\n routeValues,\n linkAs,\n columns,\n variant,\n brand,\n animated = true,\n className,\n style,\n ...props\n}: ChoiceGridProps) {\n const { value, defaultValue, onValueChange } = useRouteBinding(routeKey, routeValues, { value: valueProp, defaultValue: defaultValueProp, onValueChange: onValueChangeProp });\n const selectable = onValueChange !== undefined || value !== undefined;\n const [inner, setInner] = React.useState(defaultValue);\n const current = value ?? inner;\n const refs = React.useRef<(HTMLButtonElement | null)[]>([]);\n const enabled = items.map((item, i) => (item.disabled ? -1 : i)).filter((i) => i >= 0);\n const chosenIndex = items.findIndex((item) => item.id === current && !item.disabled);\n const focusIndex = chosenIndex >= 0 ? chosenIndex : (enabled[0] ?? 0);\n\n const choose = (i: number) => {\n const item = items[i];\n if (!item || item.disabled) return;\n if (value === undefined) setInner(item.id);\n onValueChange?.(item.id);\n };\n const onKeyDown = (e: React.KeyboardEvent, i: number) => {\n const at = enabled.indexOf(i);\n let next: number | undefined;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") next = enabled[(at + 1) % enabled.length];\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") next = enabled[(at - 1 + enabled.length) % enabled.length];\n else if (e.key === \"Home\") next = enabled[0];\n else if (e.key === \"End\") next = enabled[enabled.length - 1];\n if (next === undefined) return;\n e.preventDefault();\n refs.current[next]?.focus();\n choose(next);\n };\n\n // A radio group holds radios, not list items; a showcase or a set of links is a list named by `label`.\n const Grid = selectable ? \"div\" : \"ul\";\n const Item = selectable ? \"div\" : \"li\";\n const vars = { \"--kzs-cols\": columns ?? Math.min(items.length, 4), ...style } as React.CSSProperties;\n return (\n <div data-kzs-scene=\"\" data-animated={animated ? \"\" : undefined} className={cn(\"kzs-choice\", storyVariantClass(variant), brandClass(brand), className)} style={vars} {...props}>\n <span className=\"kzs-texture\" aria-hidden />\n <span className=\"kzs-scan kzs-loop\" aria-hidden />\n {(tag || caption) && (\n <p className=\"kzs-choice-head\">\n {tag && <span className=\"kzs-choice-tag\">{tag}</span>}\n {tag && caption && <span className=\"kzs-choice-sep\" aria-hidden />}\n {caption && <span className=\"kzs-choice-caption\">{caption}</span>}\n </p>\n )}\n {prompt && <p className=\"kzs-choice-prompt\">{prompt}</p>}\n <Grid className=\"kzs-choice-grid\" role={selectable ? \"radiogroup\" : undefined} aria-label={label}>\n {items.map((item, i) => {\n const body = (\n <>\n <span className=\"kzs-choice-aura\" aria-hidden />\n <span className=\"kzs-choice-flash\" aria-hidden />\n {CORNERS.map((at) => (\n <span key={at} className=\"kzs-corner\" data-at={at} aria-hidden />\n ))}\n {(item.badge || item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-top\">\n {item.badge ? <span className=\"kzs-choice-badge\">{item.badge}</span> : <span />}\n {(item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-eyebrow\">\n {item.icon && <span aria-hidden>{item.icon}</span>}\n {item.eyebrow}\n </span>\n )}\n </span>\n )}\n <span className=\"kzs-choice-frame\" aria-hidden>\n <span className=\"kzs-choice-floor\" />\n <span className=\"kzs-choice-visual\">{item.visual}</span>\n </span>\n <span className=\"kzs-choice-name\">{item.name}</span>\n {item.title && <span className=\"kzs-choice-title\">{item.title}</span>}\n {item.extra && <span className=\"kzs-choice-extra\">{item.extra}</span>}\n {item.meta && <span className=\"kzs-choice-meta\">{item.meta}</span>}\n <span className=\"kzs-choice-check\" aria-hidden>\n <svg viewBox=\"0 0 24 24\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 5 5 9-10\" />\n </svg>\n </span>\n </>\n );\n const itemStyle = { \"--i\": i } as React.CSSProperties;\n let tile: React.ReactNode;\n if (selectable)\n tile = (\n <button\n ref={(el) => {\n refs.current[i] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={current === item.id}\n tabIndex={i === focusIndex ? 0 : -1}\n disabled={item.disabled}\n data-selectable=\"\"\n className=\"kzs-choice-item\"\n style={itemStyle}\n onClick={() => choose(i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n >\n {body}\n </button>\n );\n else if (item.href)\n tile = (\n <BlockLink href={item.href} linkAs={linkAs} className=\"kzs-choice-item\" data-link=\"\" style={itemStyle}>\n {body}\n </BlockLink>\n );\n else\n tile = (\n <div className=\"kzs-choice-item\" style={itemStyle}>\n {body}\n </div>\n );\n return (\n <Item key={item.id} className={cn(\"kzs-choice-slot\", brandClass(item.brand))} style={itemStyle}>\n {tile}\n </Item>\n );\n })}\n </Grid>\n </div>\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. The URL is the state: a selection the user would want to share, reload or come back to (a tab, a type, a\n// filter) lives in a search parameter, never in `useState` (Oussama, 2026-10-22: « changer les tabs doit changer les routes »).\n// One primitive reads and writes it: `useRouteState`. The selection components take `routeKey` and bind to it.\nimport * as React from \"react\";\n\n/** How a router moves and reads the address: the browser's by default, your framework's through `RouteStateProvider`. */\nexport interface RouteAdapter {\n /** The current query string, with or without `?` (`\"\"` on the server). */\n search: () => string;\n /** Go to `search` (`?type=bail`, or `\"\"`), keeping the path and the hash; `replace` keeps the history as it is. */\n navigate: (search: string, options: { replace: boolean }) => void;\n /** Calls `onChange` when the address changes under you (back, forward, another navigation); returns the unsubscribe. */\n subscribe: (onChange: () => void) => () => void;\n}\n\nconst CHANGE = \"kz-route-state\";\n\n/** The History API: any web app (Vite, a static site). Next.js apps pass their router's adapter once, in the layout. */\nexport const browserAdapter: RouteAdapter = {\n search: () => (typeof window === \"undefined\" ? \"\" : window.location.search),\n navigate: (search, { replace }) => {\n const url = `${window.location.pathname}${search}${window.location.hash}`;\n window.history[replace ? \"replaceState\" : \"pushState\"](window.history.state, \"\", url);\n window.dispatchEvent(new Event(CHANGE));\n },\n subscribe: (onChange) => {\n window.addEventListener(\"popstate\", onChange);\n window.addEventListener(CHANGE, onChange);\n return () => {\n window.removeEventListener(\"popstate\", onChange);\n window.removeEventListener(CHANGE, onChange);\n };\n },\n};\n\nconst AdapterContext = React.createContext<RouteAdapter>(browserAdapter);\n\nexport interface RouteStateProviderProps {\n /** How your router reads the query string, navigates and tells about changes. */\n adapter: RouteAdapter;\n children: React.ReactNode;\n}\n\n/** Gives `useRouteState` your router: `<RouteStateProvider adapter={nextAdapter}>` once, in the root layout. */\nexport function RouteStateProvider({ adapter, children }: RouteStateProviderProps) {\n return <AdapterContext.Provider value={adapter}>{children}</AdapterContext.Provider>;\n}\n\nexport interface RouteStateOptions<V extends string> {\n /** The values the parameter may hold, as a const list: anything else in the address reads as the default. Omit for free text. */\n values?: readonly V[];\n /** The value when the parameter is absent. It is never written to the address (a clean URL). */\n default: V;\n /** `push` (the default) keeps each change in the history, `replace` overwrites it: use `replace` for a filter typed or toggled in passing. */\n history?: \"push\" | \"replace\";\n}\n\n/** The value a query string holds for `key`, checked against `values`. Pure: the hook and the tests share it. */\nexport function readRouteValue<V extends string>(search: string, key: string, { values, default: fallback }: Pick<RouteStateOptions<V>, \"values\" | \"default\">): V {\n const raw = new URLSearchParams(search).get(key);\n if (raw === null) return fallback;\n return !values || (values as readonly string[]).includes(raw) ? (raw as V) : fallback;\n}\n\n/** The query string with `key` set to `value` (removed when it is the default); every other parameter is kept. Pure. */\nexport function writeRouteValue(search: string, key: string, value: string, fallback: string): string {\n const params = new URLSearchParams(search);\n if (value === fallback) params.delete(key);\n else params.set(key, value);\n const text = params.toString();\n return text ? `?${text}` : \"\";\n}\n\n/**\n * A value kept in the URL's search parameter `key`: `const [type, setType] = useRouteState(\"type\", { values: TYPES, default: \"auto\" })`\n * with `const TYPES = [\"auto\", \"lease\", \"contract\", \"invoice\", \"other\"] as const`. The value is typed from the list, an\n * unknown one in the address reads as the default, the default is not written, other parameters are kept.\n * `key` undefined makes the hook inert (it returns the default) so a component can call it unconditionally.\n */\nexport function useRouteState<V extends string>(key: string | undefined, { values, default: fallback, history = \"push\" }: RouteStateOptions<V>): readonly [V, (next: V) => void] {\n const adapter = React.useContext(AdapterContext);\n const search = React.useSyncExternalStore(adapter.subscribe, adapter.search, () => \"\");\n const value = key === undefined ? fallback : readRouteValue(search, key, { values, default: fallback });\n const set = React.useCallback(\n (next: V) => {\n if (key === undefined) return;\n adapter.navigate(writeRouteValue(adapter.search(), key, next, fallback), { replace: history === \"replace\" });\n },\n [adapter, key, fallback, history],\n );\n return [value, set] as const;\n}\n\n/** What a selection component spreads on its root: `value` and `onValueChange` bound to the URL when `routeKey` is set. */\nexport interface RouteBindable {\n value?: string | null;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n}\n\n/** The props of a selection component bound to the URL (`routeKey`), or its own, unchanged, when there is no `routeKey`. */\nexport function useRouteBinding<P extends RouteBindable>(routeKey: string | undefined, routeValues: readonly string[] | undefined, props: P): P {\n const initial = props.defaultValue ?? props.value ?? routeValues?.[0] ?? \"\";\n const [value, set] = useRouteState<string>(routeKey, { values: routeValues, default: initial });\n if (routeKey === undefined) return props;\n return {\n ...props,\n value,\n defaultValue: undefined,\n onValueChange: (next: string) => {\n set(next);\n props.onValueChange?.(next);\n },\n };\n}\n"],"mappings":"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","names":["React","jsx","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/choice-grid/choice-grid.tsx","../src/block-link.tsx","../src/router/route-state.tsx"],"sourcesContent":["// Client. A row of choices shown as tiles — a visual, a name, a line (story.css): pick a plan, a persona, a team, a side.\n// Selectable (`onValueChange`), it is a radio group with roving focus; with `href` on its items, a set of links (a\n// line-up that leads somewhere); otherwise a showcase of the line-up.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\nimport { useRouteBinding } from \"../router\";\nimport { brandClass, type StoryVariant, storyVariantClass } from \"../story-variant\";\n\nexport interface ChoiceItem {\n /** The value of the choice (and its React key). */\n id: string;\n /** What represents it: a mark, an avatar, an illustration. Decorative — the name carries the meaning. */\n visual: React.ReactNode;\n /** Its name, short. */\n name: React.ReactNode;\n /** One line under the name: what it is, its role. */\n title?: React.ReactNode;\n /** A small line above the visual (a family, a tier), after its `icon`. */\n eyebrow?: React.ReactNode;\n /** A small glyph before the eyebrow (decorative). */\n icon?: React.ReactNode;\n /** A short tag in the top corner (“P1”, “New”, “Popular”). */\n badge?: React.ReactNode;\n /** Under the line: a gauge (`StatGauge`), facts, a price. */\n extra?: React.ReactNode;\n /** At the bottom: where the tile leads (“Chapter 2 ↓”, “See the plan”). */\n meta?: React.ReactNode;\n /** Makes the tile a link (ignored when the grid is selectable). */\n href?: string;\n /** A brand scope for this tile (`orazaka` → `.brand-orazaka`): its accent becomes that brand's. */\n brand?: string;\n /** Not selectable. */\n disabled?: boolean;\n}\n\nexport type ChoiceGridProps = Omit<React.HTMLAttributes<HTMLDivElement>, \"defaultValue\" | \"onChange\"> & {\n /** The accessible name of the group (“Choose your plan”) — passed translated. */\n label: string;\n /** The choices, in reading order. */\n items: readonly ChoiceItem[];\n /** A short mono line above the grid (a step, a tag). */\n tag?: React.ReactNode;\n /** A line beside the tag: what the choice means. */\n caption?: React.ReactNode;\n /** A call above the tiles, larger (“Choose your plan”). */\n prompt?: React.ReactNode;\n /** The chosen id (controlled). */\n value?: string;\n /** The chosen id at first (uncontrolled). */\n defaultValue?: string;\n /** Makes the grid a radio group: called with the id chosen by click, Enter, Space or the arrow keys. */\n onValueChange?: (id: string) => void;\n /** Binds the choice to this search parameter of the URL (`?type=…`): the URL is the state. Without it the state is local — only for an ephemeral choice. */\n routeKey?: string;\n /** The ids the parameter may hold; the first is the default unless `defaultValue` says otherwise. */\n routeValues?: readonly string[];\n /** The app's link component for the tiles' internal `href`s (Next's `Link`); an `<a>` otherwise. */\n linkAs?: LinkComponent;\n /**\n * The number of columns (one on a phone).\n * @default min(items, 4)\n */\n columns?: number;\n /**\n * `default`: sober tiles. `arcade`: the select screen — the brand's light on each card, corners that lock, a flash.\n * @default \"default\"\n */\n variant?: StoryVariant;\n /** A brand scope for the whole grid (`orochia` → `.brand-orochia`). */\n brand?: string;\n /**\n * The tiles' arrival on mount (arcade: the corners locking one by one, the gauges filling). Always off under\n * `prefers-reduced-motion`.\n * @default true\n */\n animated?: boolean;\n};\n\nconst CORNERS = [\"tl\", \"tr\", \"bl\", \"br\"] as const;\n\n/**\n * A line-up of choices as tiles. With `onValueChange` (or `value`), a radio group: one tab stop, the arrow keys move\n * and choose, Home/End jump, the chosen tile is marked. With `href` on the items, a list of links. Otherwise a list\n * named by `label` that presents the line-up.\n */\nexport function ChoiceGrid({\n label,\n items,\n tag,\n caption,\n prompt,\n value: valueProp,\n defaultValue: defaultValueProp,\n onValueChange: onValueChangeProp,\n routeKey,\n routeValues,\n linkAs,\n columns,\n variant,\n brand,\n animated = true,\n className,\n style,\n ...props\n}: ChoiceGridProps) {\n const { value, defaultValue, onValueChange } = useRouteBinding(routeKey, routeValues, { value: valueProp, defaultValue: defaultValueProp, onValueChange: onValueChangeProp });\n const selectable = onValueChange !== undefined || value !== undefined;\n const [inner, setInner] = React.useState(defaultValue);\n const current = value ?? inner;\n const refs = React.useRef<(HTMLButtonElement | null)[]>([]);\n const enabled = items.map((item, i) => (item.disabled ? -1 : i)).filter((i) => i >= 0);\n const chosenIndex = items.findIndex((item) => item.id === current && !item.disabled);\n const focusIndex = chosenIndex >= 0 ? chosenIndex : (enabled[0] ?? 0);\n\n const choose = (i: number) => {\n const item = items[i];\n if (!item || item.disabled) return;\n if (value === undefined) setInner(item.id);\n onValueChange?.(item.id);\n };\n const onKeyDown = (e: React.KeyboardEvent, i: number) => {\n const at = enabled.indexOf(i);\n let next: number | undefined;\n if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") next = enabled[(at + 1) % enabled.length];\n else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") next = enabled[(at - 1 + enabled.length) % enabled.length];\n else if (e.key === \"Home\") next = enabled[0];\n else if (e.key === \"End\") next = enabled[enabled.length - 1];\n if (next === undefined) return;\n e.preventDefault();\n refs.current[next]?.focus();\n choose(next);\n };\n\n // A radio group holds radios, not list items; a showcase or a set of links is a list named by `label`.\n const Grid = selectable ? \"div\" : \"ul\";\n const Item = selectable ? \"div\" : \"li\";\n const vars = { \"--kzs-cols\": columns ?? Math.min(items.length, 4), ...style } as React.CSSProperties;\n return (\n <div data-kzs-scene=\"\" data-animated={animated ? \"\" : undefined} className={cn(\"kzs-choice\", storyVariantClass(variant), brandClass(brand), className)} style={vars} {...props}>\n <span className=\"kzs-texture\" aria-hidden />\n <span className=\"kzs-scan kzs-loop\" aria-hidden />\n {(tag || caption) && (\n <p className=\"kzs-choice-head\">\n {tag && <span className=\"kzs-choice-tag\">{tag}</span>}\n {tag && caption && <span className=\"kzs-choice-sep\" aria-hidden />}\n {caption && <span className=\"kzs-choice-caption\">{caption}</span>}\n </p>\n )}\n {prompt && <p className=\"kzs-choice-prompt\">{prompt}</p>}\n <Grid className=\"kzs-choice-grid\" role={selectable ? \"radiogroup\" : undefined} aria-label={label}>\n {items.map((item, i) => {\n const body = (\n <>\n <span className=\"kzs-choice-aura\" aria-hidden />\n <span className=\"kzs-choice-flash\" aria-hidden />\n {CORNERS.map((at) => (\n <span key={at} className=\"kzs-corner\" data-at={at} aria-hidden />\n ))}\n {(item.badge || item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-top\">\n {item.badge ? <span className=\"kzs-choice-badge\">{item.badge}</span> : <span />}\n {(item.eyebrow || item.icon) && (\n <span className=\"kzs-choice-eyebrow\">\n {item.icon && <span aria-hidden>{item.icon}</span>}\n {item.eyebrow}\n </span>\n )}\n </span>\n )}\n <span className=\"kzs-choice-frame\" aria-hidden>\n <span className=\"kzs-choice-floor\" />\n <span className=\"kzs-choice-visual\">{item.visual}</span>\n </span>\n <span className=\"kzs-choice-name\">{item.name}</span>\n {item.title && <span className=\"kzs-choice-title\">{item.title}</span>}\n {item.extra && <span className=\"kzs-choice-extra\">{item.extra}</span>}\n {item.meta && <span className=\"kzs-choice-meta\">{item.meta}</span>}\n <span className=\"kzs-choice-check\" aria-hidden>\n <svg viewBox=\"0 0 24 24\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"3\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"m5 12 5 5 9-10\" />\n </svg>\n </span>\n </>\n );\n const itemStyle = { \"--i\": i } as React.CSSProperties;\n let tile: React.ReactNode;\n if (selectable)\n tile = (\n <button\n ref={(el) => {\n refs.current[i] = el;\n }}\n type=\"button\"\n role=\"radio\"\n aria-checked={current === item.id}\n tabIndex={i === focusIndex ? 0 : -1}\n disabled={item.disabled}\n data-selectable=\"\"\n className=\"kzs-choice-item\"\n style={itemStyle}\n onClick={() => choose(i)}\n onKeyDown={(e) => onKeyDown(e, i)}\n >\n {body}\n </button>\n );\n else if (item.href)\n tile = (\n <BlockLink href={item.href} linkAs={linkAs} className=\"kzs-choice-item\" data-link=\"\" style={itemStyle}>\n {body}\n </BlockLink>\n );\n else\n tile = (\n <div className=\"kzs-choice-item\" style={itemStyle}>\n {body}\n </div>\n );\n return (\n <Item key={item.id} className={cn(\"kzs-choice-slot\", brandClass(item.brand))} style={itemStyle}>\n {tile}\n </Item>\n );\n })}\n </Grid>\n </div>\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} rel={rel} {...props} />;\n}\n","// Client. The URL is the state: a selection the user would want to share, reload or come back to (a tab, a type, a\n// filter) lives in a search parameter, never in `useState` (Oussama, 2026-10-22: « changer les tabs doit changer les routes »).\n// One primitive reads and writes it: `useRouteState`. The selection components take `routeKey` and bind to it.\nimport * as React from \"react\";\n\n/** How a router moves and reads the address: the browser's by default, your framework's through `RouteStateProvider`. */\nexport interface RouteAdapter {\n /** The current query string, with or without `?` (`\"\"` on the server). */\n search: () => string;\n /** Go to `search` (`?type=bail`, or `\"\"`), keeping the path and the hash; `replace` keeps the history as it is. */\n navigate: (search: string, options: { replace: boolean }) => void;\n /** Calls `onChange` when the address changes under you (back, forward, another navigation); returns the unsubscribe. */\n subscribe: (onChange: () => void) => () => void;\n}\n\nconst CHANGE = \"kz-route-state\";\n\n/** The History API: any web app (Vite, a static site). Next.js apps pass their router's adapter once, in the layout. */\nexport const browserAdapter: RouteAdapter = {\n search: () => (typeof window === \"undefined\" ? \"\" : window.location.search),\n navigate: (search, { replace }) => {\n const url = `${window.location.pathname}${search}${window.location.hash}`;\n window.history[replace ? \"replaceState\" : \"pushState\"](window.history.state, \"\", url);\n window.dispatchEvent(new Event(CHANGE));\n },\n subscribe: (onChange) => {\n window.addEventListener(\"popstate\", onChange);\n window.addEventListener(CHANGE, onChange);\n return () => {\n window.removeEventListener(\"popstate\", onChange);\n window.removeEventListener(CHANGE, onChange);\n };\n },\n};\n\nconst AdapterContext = React.createContext<RouteAdapter>(browserAdapter);\n\nexport interface RouteStateProviderProps {\n /** How your router reads the query string, navigates and tells about changes. */\n adapter: RouteAdapter;\n children: React.ReactNode;\n}\n\n/** Gives `useRouteState` your router: `<RouteStateProvider adapter={nextAdapter}>` once, in the root layout. */\nexport function RouteStateProvider({ adapter, children }: RouteStateProviderProps) {\n return <AdapterContext.Provider value={adapter}>{children}</AdapterContext.Provider>;\n}\n\nexport interface RouteStateOptions<V extends string> {\n /** The values the parameter may hold, as a const list: anything else in the address reads as the default. Omit for free text. */\n values?: readonly V[];\n /** The value when the parameter is absent. It is never written to the address (a clean URL). */\n default: V;\n /** `push` (the default) keeps each change in the history, `replace` overwrites it: use `replace` for a filter typed or toggled in passing. */\n history?: \"push\" | \"replace\";\n}\n\n/** The value a query string holds for `key`, checked against `values`. Pure: the hook and the tests share it. */\nexport function readRouteValue<V extends string>(search: string, key: string, { values, default: fallback }: Pick<RouteStateOptions<V>, \"values\" | \"default\">): V {\n const raw = new URLSearchParams(search).get(key);\n if (raw === null) return fallback;\n return !values || (values as readonly string[]).includes(raw) ? (raw as V) : fallback;\n}\n\n/** The query string with `key` set to `value` (removed when it is the default); every other parameter is kept. Pure. */\nexport function writeRouteValue(search: string, key: string, value: string, fallback: string): string {\n const params = new URLSearchParams(search);\n if (value === fallback) params.delete(key);\n else params.set(key, value);\n const text = params.toString();\n return text ? `?${text}` : \"\";\n}\n\n/**\n * A value kept in the URL's search parameter `key`: `const [type, setType] = useRouteState(\"type\", { values: TYPES, default: \"auto\" })`\n * with `const TYPES = [\"auto\", \"lease\", \"contract\", \"invoice\", \"other\"] as const`. The value is typed from the list, an\n * unknown one in the address reads as the default, the default is not written, other parameters are kept.\n * `key` undefined makes the hook inert (it returns the default) so a component can call it unconditionally.\n */\nexport function useRouteState<V extends string>(key: string | undefined, { values, default: fallback, history = \"push\" }: RouteStateOptions<V>): readonly [V, (next: V) => void] {\n const adapter = React.useContext(AdapterContext);\n const search = React.useSyncExternalStore(adapter.subscribe, adapter.search, () => \"\");\n const value = key === undefined ? fallback : readRouteValue(search, key, { values, default: fallback });\n const set = React.useCallback(\n (next: V) => {\n if (key === undefined) return;\n adapter.navigate(writeRouteValue(adapter.search(), key, next, fallback), { replace: history === \"replace\" });\n },\n [adapter, key, fallback, history],\n );\n return [value, set] as const;\n}\n\n/** What a selection component spreads on its root: `value` and `onValueChange` bound to the URL when `routeKey` is set. */\nexport interface RouteBindable {\n value?: string | null;\n defaultValue?: string;\n onValueChange?: (value: string) => void;\n}\n\n/** The props of a selection component bound to the URL (`routeKey`), or its own, unchanged, when there is no `routeKey`. */\nexport function useRouteBinding<P extends RouteBindable>(routeKey: string | undefined, routeValues: readonly string[] | undefined, props: P): P {\n const initial = props.defaultValue ?? props.value ?? routeValues?.[0] ?? \"\";\n const [value, set] = useRouteState<string>(routeKey, { values: routeValues, default: initial });\n if (routeKey === undefined) return props;\n return {\n ...props,\n value,\n defaultValue: undefined,\n onValueChange: (next: string) => {\n set(next);\n props.onValueChange?.(next);\n },\n };\n}\n"],"mappings":"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","names":["React","jsx","jsx"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BlockLink,
|
|
3
3
|
isExternal
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-FVGFPB73.js";
|
|
5
5
|
import {
|
|
6
6
|
ArrowGlyph,
|
|
7
7
|
ExternalGlyph
|
|
@@ -50,4 +50,4 @@ export {
|
|
|
50
50
|
cardHoverClass,
|
|
51
51
|
LinkCard
|
|
52
52
|
};
|
|
53
|
-
//# sourceMappingURL=chunk-
|
|
53
|
+
//# sourceMappingURL=chunk-7JG3VR4C.js.map
|
|
@@ -12,10 +12,10 @@ function BlockLink({
|
|
|
12
12
|
}) {
|
|
13
13
|
if (external) return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
14
14
|
const Comp = Link;
|
|
15
|
-
return /* @__PURE__ */ jsx(Comp, { href, ...props });
|
|
15
|
+
return /* @__PURE__ */ jsx(Comp, { href, rel, ...props });
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export {
|
|
19
19
|
BlockLink
|
|
20
20
|
};
|
|
21
|
-
//# sourceMappingURL=chunk-
|
|
21
|
+
//# sourceMappingURL=chunk-ENOS6ETI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// 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"],"mappings":";;;AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,
|
|
1
|
+
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// 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} rel={rel} {...props} />;\n}\n"],"mappings":";;;AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,MAAY,KAAW,GAAG,OAAO;AAChD;","names":[]}
|
|
@@ -10,11 +10,11 @@ function BlockLink({
|
|
|
10
10
|
}) {
|
|
11
11
|
if (external) return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
12
12
|
const Comp = Link;
|
|
13
|
-
return /* @__PURE__ */ jsx(Comp, { href, ...props });
|
|
13
|
+
return /* @__PURE__ */ jsx(Comp, { href, rel, ...props });
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export {
|
|
17
17
|
isExternal,
|
|
18
18
|
BlockLink
|
|
19
19
|
};
|
|
20
|
-
//# sourceMappingURL=chunk-
|
|
20
|
+
//# sourceMappingURL=chunk-FVGFPB73.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// 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"],"mappings":";AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,
|
|
1
|
+
{"version":3,"sources":["../src/block-link.tsx"],"sourcesContent":["// 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} rel={rel} {...props} />;\n}\n"],"mappings":";AAkBuB;AAThB,IAAM,aAAa,CAAC,SAAiB,uBAAuB,KAAK,IAAI;AAErE,SAAS,UAAU;AAAA,EACxB;AAAA,EACA,QAAQ,OAAO;AAAA,EACf,WAAW,WAAW,IAAI;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2G;AACzG,MAAI,SAAU,QAAO,oBAAC,OAAE,MAAY,QAAO,UAAS,KAAK,OAAO,uBAAwB,GAAG,OAAO;AAClG,QAAM,OAAO;AACb,SAAO,oBAAC,QAAK,MAAY,KAAW,GAAG,OAAO;AAChD;","names":[]}
|
package/dist/cover-hero.js
CHANGED
package/dist/link-card.js
CHANGED
package/dist/media-grid.js
CHANGED
|
@@ -82,7 +82,7 @@ function BlockLink({
|
|
|
82
82
|
}) {
|
|
83
83
|
if (external) return /* @__PURE__ */ jsx3("a", { href, target: "_blank", rel: rel ?? "noopener noreferrer", ...props });
|
|
84
84
|
const Comp = Link;
|
|
85
|
-
return /* @__PURE__ */ jsx3(Comp, { href, ...props });
|
|
85
|
+
return /* @__PURE__ */ jsx3(Comp, { href, rel, ...props });
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// src/media-grid/section-hint.tsx
|
package/dist/media-grid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/media-grid/load-more.tsx","../src/spinner/spinner.tsx","../src/media-grid/media-grid.tsx","../src/media-grid/section-hint.tsx","../src/block-link.tsx","../src/media-grid/shorts-shelf.tsx","../src/media-grid/video-card.tsx","../src/media-grid/preview-focus.ts","../src/media-grid/video-card-skeleton.tsx"],"sourcesContent":["// Client (IntersectionObserver). The end of a long list: the next page is requested while the person is still a\n// screenful away (`rootMargin`), so it is there before they reach it; the button stays as the way that never fails\n// (no observer, a failed page, a keyboard).\nimport * as React from \"react\";\n\nimport { Button } from \"../button\";\nimport { cn } from \"../cn\";\nimport { Spinner } from \"../spinner\";\n\nexport interface LoadMoreProps extends Omit<React.ComponentProps<\"div\">, \"children\" | \"onError\"> {\n /** Asks for the next page. Not called while `loading`, nor once `hasMore` is false. */\n onLoadMore: () => void;\n /** There is a next page. */\n hasMore: boolean;\n /** A page is on its way. */\n loading?: boolean;\n /** The last page failed: the button reads `retryLabel`, and nothing loads by itself until it is pressed. */\n failed?: boolean;\n /** The button, passed translated (\"Load more\"). */\n label: string;\n /** The wait, passed translated (\"Loading more videos\"). */\n loadingLabel: string;\n /** The button after a failure, passed translated (\"Try again\"). Defaults to `label`. */\n retryLabel?: string;\n /** Shown instead of the button when the list is over, passed translated (\"You have seen everything\"). Nothing if absent. */\n endLabel?: string;\n /**\n * How far below the viewport the page is already requested (an IntersectionObserver `rootMargin`).\n * @default \"900px 0px\"\n */\n rootMargin?: string;\n}\n\n/** Infinite scroll with a visible \"Load more\" under it. */\nexport function LoadMore({ onLoadMore, hasMore, loading = false, failed = false, label, loadingLabel, retryLabel, endLabel, rootMargin = \"900px 0px\", className, ...props }: LoadMoreProps) {\n const sentinel = React.useRef<HTMLDivElement>(null);\n const ask = React.useRef(onLoadMore);\n React.useEffect(() => {\n ask.current = onLoadMore;\n });\n // Observing again after each page makes the observer report the current state: a short page that leaves the sentinel in view asks for the next.\n React.useEffect(() => {\n const el = sentinel.current;\n if (!el || !hasMore || loading || failed || typeof IntersectionObserver === \"undefined\") return;\n const io = new IntersectionObserver((entries) => entries.some((e) => e.isIntersecting) && ask.current(), { rootMargin });\n io.observe(el);\n return () => io.disconnect();\n }, [hasMore, loading, failed, rootMargin]);\n return (\n <div data-load-more=\"\" data-state={loading ? \"loading\" : failed ? \"failed\" : hasMore ? \"idle\" : \"end\"} className={cn(\"relative flex min-h-14 items-center justify-center py-6\", className)} {...props}>\n <div ref={sentinel} aria-hidden className=\"pointer-events-none absolute inset-x-0 top-0 h-px\" />\n {loading ? (\n <Spinner label={loadingLabel} size=\"md\" />\n ) : hasMore ? (\n <Button type=\"button\" variant=\"secondary\" size=\"md\" onClick={() => onLoadMore()}>\n {failed ? (retryLabel ?? label) : label}\n </Button>\n ) : endLabel ? (\n <p className=\"m-0 text-sm text-fg-secondary\">{endLabel}</p>\n ) : null}\n </div>\n );\n}\n","// Server-safe. An indeterminate wait: the Krizaka loader glyph (a hexagon traced by light around a node), announced as\n// a status with its `label`. For a wait with a delay, a value, an ETA or an ending, see `@krizaka/ui/loader`.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { LoaderGlyph } from \"./glyph\";\n\nexport const spinnerVariants = tv({\n base: \"shrink-0 text-accent\",\n variants: { size: { sm: \"h-4 w-4\", md: \"h-6 w-6\", lg: \"h-10 w-10\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type SpinnerProps = Omit<React.ComponentProps<\"svg\">, \"children\"> &\n VariantProps<typeof spinnerVariants> & {\n /**\n * sm · md · lg.\n * @default \"md\"\n */\n size?: VariantProps<typeof spinnerVariants>[\"size\"];\n /** The accessible name of the wait, e.g. \"Loading\" — passed translated. */\n label: string;\n /** Between 0 and 1: the trace grows to the value (a determinate wait). Absent: it travels around. */\n value?: number | null;\n };\n\n/**\n * The Krizaka spinner: a hexagon traced by a segment of light around a breathing node, in `currentColor` (the accent by\n * default). `role=\"status\"`, named by `label`. Under prefers-reduced-motion it rests — a segment and the node lit.\n */\nexport function Spinner({ label, size, value, className, ...props }: SpinnerProps) {\n return (\n <LoaderGlyph\n role=\"status\"\n aria-label={label}\n aria-hidden={undefined}\n value={value}\n data-size={size ?? \"md\"}\n className={spinnerVariants({ size, className })}\n {...props}\n />\n );\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 { SectionHint, type SectionHintProps } from \"./section-hint\";\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\" | \"hint\" | \"seeAll\" | \"previousLabel\" | \"nextLabel\">;\n /** A heading for the grid of the others (“Videos”), in the style of the shelf's, with an optional definition. */\n grid?: { label: string; hint?: SectionHintProps };\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, grid, className, ...props }: MediaGridProps<T>) {\n const gridHeading = React.useId();\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 <section aria-labelledby={grid ? gridHeading : undefined} data-media-grid-section className=\"min-w-0\">\n {grid && (\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={gridHeading} className=\"m-0 text-base font-bold text-fg\">\n {grid.label}\n </h2>\n {grid.hint && <SectionHint {...grid.hint} />}\n </div>\n )}\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 </section>\n )}\n </div>\n );\n}\n","// Client (open state). A tiny \"i\" button beside a section heading: it opens a one-line definition and, when given, a link to\n// the glossary. Opens on a tap or a press, on hover with a mouse, closes on Escape or when the focus leaves.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\nexport interface SectionHintProps {\n /** The button's accessible name, passed translated (“What are Shorts?”). */\n label: string;\n /** The definition, in one line. */\n text: string;\n /** A link to the full definition (the glossary). */\n link?: { href: string; label: string; linkAs?: LinkComponent };\n}\n\n/** The definition of a section, one tap away from its heading. */\nexport function SectionHint({ label, text, link }: SectionHintProps) {\n const [open, setOpen] = React.useState(false);\n const id = React.useId();\n return (\n <span\n className=\"relative inline-flex\"\n onMouseEnter={() => setOpen(true)}\n onMouseLeave={() => setOpen(false)}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget)) setOpen(false);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setOpen(false);\n }}\n >\n <button\n type=\"button\"\n aria-label={label}\n aria-expanded={open}\n aria-controls={id}\n onClick={() => setOpen((o) => !o)}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-full text-fg-muted transition-colors hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 11v5M12 8h.01\" />\n </svg>\n </button>\n <span\n id={id}\n role=\"tooltip\"\n hidden={!open}\n className={cn(\"absolute left-0 top-full z-20 mt-1 w-64 max-w-[80vw] rounded-xl border border-border-default bg-surface-1 p-3 text-sm font-normal leading-snug text-fg-secondary shadow-lg\")}\n >\n {text}\n {link && (\n <>\n {\" \"}\n <BlockLink href={link.href} linkAs={link.linkAs} className=\"font-semibold text-fg-accent hover:underline\">\n {link.label}\n </BlockLink>\n </>\n )}\n </span>\n </span>\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 (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\";\nimport { SectionHint, type SectionHintProps } from \"./section-hint\";\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 /** A small “i” beside the heading: the one-line definition of the section and a link to the glossary. */\n hint?: SectionHintProps;\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, hint, 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 {hint && <SectionHint {...hint} />}\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 overflow-y-hidden overscroll-x-contain p-0 pt-1 -mt-1 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","// 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\";\nimport { isLeader, subscribeLeader, trackVisibility } from \"./preview-focus\";\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 /**\n * An animated picture (WebP, a few hundred kB) that fades in over the poster once the pointer has rested on the card\n * (or it is focused) for `previewDelay`, and is removed again on leave. It is never requested before. On a phone (no\n * hover) only the card most inside the viewport plays it, unless the person asked for less data or less motion.\n */\n previewSrc?: string | null;\n /**\n * How long the pointer must rest before the preview is requested, in ms: a pointer crossing the grid loads nothing.\n * @default 200\n */\n previewDelay?: number;\n /**\n * `fetchPriority` of the poster: `high` for the first row (the largest contentful paint).\n * @default \"auto\"\n */\n posterPriority?: \"high\" | \"low\" | \"auto\";\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 previewDelay = 200,\n posterPriority = \"auto\",\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 ref,\n ...props\n}: VideoCardProps) {\n const [node, setNode] = React.useState<HTMLElement | null>(null);\n const setRef = React.useCallback(\n (el: HTMLElement | null) => {\n setNode(el);\n if (typeof ref === \"function\") ref(el);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = el;\n },\n [ref],\n );\n const canPreview = Boolean(previewSrc) && !blurred;\n const { live, arm, disarm } = usePreviewIntent(node, canPreview, previewDelay);\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <article\n ref={setRef}\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n data-preview={live ? \"on\" : undefined}\n onMouseEnter={(e) => (arm(\"pointer\"), onMouseEnter?.(e))}\n onMouseLeave={(e) => (disarm(\"pointer\"), onMouseLeave?.(e))}\n onFocus={(e) => (arm(\"focus\"), onFocus?.(e))}\n onBlur={(e) => (disarm(\"focus\"), 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\" && poster && <img src={poster} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image\n src={poster}\n loading={loading}\n fetchPriority={posterPriority === \"auto\" ? undefined : posterPriority}\n fallback={fallback}\n className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")}\n />\n {live && previewSrc && <PreviewLayer src={previewSrc} contain={fit === \"contain\"} />}\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark pointer-events-none flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\" className=\"pointer-events-none\">\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 {/* `static`: the body must not be the containing block of the title link's ::after, or the link would cover the text only and the picture would not open the video. */}\n <Card.Body className=\"static 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\n/** The animated preview, fading in over the poster once it has loaded; unmounted (so unloaded) on leave. */\nfunction PreviewLayer({ src, contain }: { src: string; contain: boolean }) {\n const [ready, setReady] = React.useState(false);\n return (\n <img\n src={src}\n alt=\"\"\n aria-hidden\n decoding=\"async\"\n data-preview-layer=\"\"\n data-ready={ready ? \"\" : undefined}\n onLoad={() => setReady(true)}\n className={cn(\"pointer-events-none absolute inset-0 h-full w-full opacity-0 transition-opacity duration-300 data-[ready]:opacity-100 motion-reduce:transition-none\", contain ? \"object-contain\" : \"object-cover\")}\n />\n );\n}\n\ntype Cause = \"pointer\" | \"focus\";\n\nconst matches = (query: string) => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(query).matches;\nconst hoverCapable = () => matches(\"(hover: hover)\");\nconst saveData = () => typeof navigator !== \"undefined\" && (navigator as Navigator & { connection?: { saveData?: boolean } }).connection?.saveData === true;\n\n/**\n * When the preview is wanted. A desktop pointer or the keyboard focus must rest `delay` ms first; on a phone the card\n * the page shows most (and only one) wants it, never under Save-Data or reduced motion. Leaving clears everything.\n */\nfunction usePreviewIntent(node: HTMLElement | null, enabled: boolean, delay: number) {\n const [causes, setCauses] = React.useState<ReadonlySet<Cause>>(new Set());\n const timers = React.useRef(new Map<Cause, ReturnType<typeof setTimeout>>());\n const arm = React.useCallback(\n (cause: Cause) => {\n if (!enabled || saveData()) return;\n if (cause === \"pointer\" && !hoverCapable()) return;\n clearTimeout(timers.current.get(cause));\n timers.current.set(\n cause,\n setTimeout(() => setCauses((c) => new Set(c).add(cause)), delay),\n );\n },\n [enabled, delay],\n );\n const disarm = React.useCallback((cause: Cause) => {\n clearTimeout(timers.current.get(cause));\n timers.current.delete(cause);\n setCauses((c) => {\n if (!c.has(cause)) return c;\n const next = new Set(c);\n next.delete(cause);\n return next;\n });\n }, []);\n React.useEffect(() => {\n const pending = timers.current;\n return () => {\n for (const t of pending.values()) clearTimeout(t);\n pending.clear();\n };\n }, []);\n\n // A phone: the single most visible card, after the same rest.\n const touch = enabled && !hoverCapable();\n const leading = React.useSyncExternalStore(\n subscribeLeader,\n () => isLeader(node),\n () => false,\n );\n React.useEffect(() => {\n if (!node || !touch) return;\n return trackVisibility(node);\n }, [node, touch]);\n const [ready, setReady] = React.useState(false);\n const [wasLeading, setWasLeading] = React.useState(false);\n if (leading !== wasLeading) {\n setWasLeading(leading);\n if (!leading) setReady(false);\n }\n const wanted = touch && leading && !saveData() && !matches(\"(prefers-reduced-motion: reduce)\");\n React.useEffect(() => {\n if (!wanted) return;\n const t = setTimeout(() => setReady(true), delay);\n return () => clearTimeout(t);\n }, [wanted, delay]);\n\n return { live: enabled && (causes.size > 0 || (wanted && ready)), arm, disarm };\n}\n","// Client only. Which card of the page is the most visible: on a phone there is no hover, so exactly one card at a time\n// (the one most inside the viewport) may play its preview. One IntersectionObserver for the whole page, no per-card\n// observer; the answer is a store read with `useSyncExternalStore`.\nconst MIN_RATIO = 0.6;\nconst ratios = new Map<Element, number>();\nconst listeners = new Set<() => void>();\nlet observer: IntersectionObserver | null = null;\nlet leader: Element | null = null;\n\nfunction elect() {\n let best: Element | null = null;\n let bestRatio = MIN_RATIO - Number.EPSILON;\n for (const [el, ratio] of ratios) {\n if (ratio > bestRatio) {\n best = el;\n bestRatio = ratio;\n }\n }\n if (best === leader) return;\n leader = best;\n for (const l of listeners) l();\n}\n\n/** Starts counting an element's visibility; returns the function that stops it. */\nexport function trackVisibility(el: Element): () => void {\n if (typeof IntersectionObserver === \"undefined\") return () => {};\n observer ??= new IntersectionObserver(\n (entries) => {\n for (const e of entries) ratios.set(e.target, e.isIntersecting ? e.intersectionRatio : 0);\n elect();\n },\n { threshold: [0, 0.25, 0.5, 0.6, 0.75, 1] },\n );\n ratios.set(el, 0);\n observer.observe(el);\n return () => {\n observer?.unobserve(el);\n ratios.delete(el);\n elect();\n };\n}\n\nexport const subscribeLeader = (l: () => void) => (listeners.add(l), () => void listeners.delete(l));\n\n/** Whether this element is the card the page is showing most. */\nexport const isLeader = (el: Element | null) => el !== null && leader === el;\n\n/** Test seam: forget everything. */\nexport function resetPreviewFocus() {\n observer?.disconnect();\n observer = null;\n ratios.clear();\n leader = null;\n}\n","// A video card on its way: the same frame, body and footer heights as `VideoCard`, so nothing moves when it arrives.\nimport * as React from \"react\";\n\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\nimport { Skeleton } from \"../skeleton\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface VideoCardSkeletonProps extends React.ComponentProps<\"div\"> {\n /** `landscape` (16:9) or `portrait` (9:16), as the card it stands for. @default \"landscape\" */\n aspect?: VideoCardAspect;\n /** `stack` or `row`, as the card it stands for. @default \"stack\" */\n layout?: \"stack\" | \"row\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** The placeholder of a `VideoCard` (decorative: announce the wait on the list, with `MediaGridSkeleton`). */\nexport function VideoCardSkeleton({ aspect = \"landscape\", layout = \"stack\", className, ...props }: VideoCardSkeletonProps) {\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <div aria-hidden data-skeleton=\"video-card\" data-aspect={aspect} data-layout={layout} className={cn(\"h-full min-w-0\", className)} {...props}>\n <Card.Root 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 <Skeleton shape=\"rect\" className=\"h-full w-full rounded-none\" />\n </Card.Media>\n <Card.Body className=\"static min-w-0 flex-1 justify-between gap-2 p-3\">\n <div className=\"flex min-h-[2.5em] flex-col justify-center gap-1.5\">\n <Skeleton className=\"h-3\" />\n <Skeleton className=\"h-3 w-3/5\" />\n </div>\n <div className={cn(\"flex text-xs\", tall ? \"flex-col gap-1\" : \"h-8 items-center gap-2\")}>\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Skeleton shape=\"circle\" className=\"h-6 w-6 shrink-0\" />\n <Skeleton className=\"h-2.5 w-20\" />\n </div>\n <div className={cn(\"flex items-center\", tall ? \"h-7\" : \"ml-auto\")}>\n <Skeleton className=\"h-2.5 w-14\" />\n </div>\n </div>\n </Card.Body>\n </Card.Root>\n </div>\n );\n}\n\nexport interface MediaGridSkeletonProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** What is loading, passed translated (\"Loading videos\"): announced once, the cards are hidden from assistive technology. */\n label: string;\n /** Cards in the grid. @default 8 */\n count?: number;\n /** Cards on the Shorts shelf above the grid (`split` mode); 0 for none. @default 0 */\n shelfCount?: number;\n /** `grid` or `list`. @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The frame of the grid. @default \"landscape\" */\n frame?: VideoCardAspect;\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/** The placeholder of a `MediaGrid`: the same shelf and grid, skeleton cards, one polite announcement. */\nexport function MediaGridSkeleton({ label, count = 8, shelfCount = 0, layout = \"grid\", frame = \"landscape\", className, ...props }: MediaGridSkeletonProps) {\n const row = layout === \"list\";\n return (\n <div role=\"status\" aria-busy=\"true\" data-media-grid-skeleton=\"\" className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n <span className=\"sr-only\">{label}</span>\n {shelfCount > 0 && (\n <div aria-hidden className=\"min-w-0\">\n <Skeleton className=\"mb-3 h-4 w-24\" />\n <ul className=\"m-0 flex list-none items-stretch gap-3 overflow-hidden p-0\">\n {Array.from({ length: shelfCount }, (_, i) => (\n <li key={i} className=\"w-[9.5rem] shrink-0 sm:w-44\">\n <VideoCardSkeleton aspect=\"portrait\" />\n </li>\n ))}\n </ul>\n </div>\n )}\n <ul aria-hidden className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[frame])}>\n {Array.from({ length: count }, (_, i) => (\n <li key={i} className=\"min-w-0\">\n <VideoCardSkeleton aspect={frame} layout={row ? \"row\" : \"stack\"} />\n </li>\n ))}\n </ul>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","React","React","jsx","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","FRAME","GRID"]}
|
|
1
|
+
{"version":3,"sources":["../src/media-grid/load-more.tsx","../src/spinner/spinner.tsx","../src/media-grid/media-grid.tsx","../src/media-grid/section-hint.tsx","../src/block-link.tsx","../src/media-grid/shorts-shelf.tsx","../src/media-grid/video-card.tsx","../src/media-grid/preview-focus.ts","../src/media-grid/video-card-skeleton.tsx"],"sourcesContent":["// Client (IntersectionObserver). The end of a long list: the next page is requested while the person is still a\n// screenful away (`rootMargin`), so it is there before they reach it; the button stays as the way that never fails\n// (no observer, a failed page, a keyboard).\nimport * as React from \"react\";\n\nimport { Button } from \"../button\";\nimport { cn } from \"../cn\";\nimport { Spinner } from \"../spinner\";\n\nexport interface LoadMoreProps extends Omit<React.ComponentProps<\"div\">, \"children\" | \"onError\"> {\n /** Asks for the next page. Not called while `loading`, nor once `hasMore` is false. */\n onLoadMore: () => void;\n /** There is a next page. */\n hasMore: boolean;\n /** A page is on its way. */\n loading?: boolean;\n /** The last page failed: the button reads `retryLabel`, and nothing loads by itself until it is pressed. */\n failed?: boolean;\n /** The button, passed translated (\"Load more\"). */\n label: string;\n /** The wait, passed translated (\"Loading more videos\"). */\n loadingLabel: string;\n /** The button after a failure, passed translated (\"Try again\"). Defaults to `label`. */\n retryLabel?: string;\n /** Shown instead of the button when the list is over, passed translated (\"You have seen everything\"). Nothing if absent. */\n endLabel?: string;\n /**\n * How far below the viewport the page is already requested (an IntersectionObserver `rootMargin`).\n * @default \"900px 0px\"\n */\n rootMargin?: string;\n}\n\n/** Infinite scroll with a visible \"Load more\" under it. */\nexport function LoadMore({ onLoadMore, hasMore, loading = false, failed = false, label, loadingLabel, retryLabel, endLabel, rootMargin = \"900px 0px\", className, ...props }: LoadMoreProps) {\n const sentinel = React.useRef<HTMLDivElement>(null);\n const ask = React.useRef(onLoadMore);\n React.useEffect(() => {\n ask.current = onLoadMore;\n });\n // Observing again after each page makes the observer report the current state: a short page that leaves the sentinel in view asks for the next.\n React.useEffect(() => {\n const el = sentinel.current;\n if (!el || !hasMore || loading || failed || typeof IntersectionObserver === \"undefined\") return;\n const io = new IntersectionObserver((entries) => entries.some((e) => e.isIntersecting) && ask.current(), { rootMargin });\n io.observe(el);\n return () => io.disconnect();\n }, [hasMore, loading, failed, rootMargin]);\n return (\n <div data-load-more=\"\" data-state={loading ? \"loading\" : failed ? \"failed\" : hasMore ? \"idle\" : \"end\"} className={cn(\"relative flex min-h-14 items-center justify-center py-6\", className)} {...props}>\n <div ref={sentinel} aria-hidden className=\"pointer-events-none absolute inset-x-0 top-0 h-px\" />\n {loading ? (\n <Spinner label={loadingLabel} size=\"md\" />\n ) : hasMore ? (\n <Button type=\"button\" variant=\"secondary\" size=\"md\" onClick={() => onLoadMore()}>\n {failed ? (retryLabel ?? label) : label}\n </Button>\n ) : endLabel ? (\n <p className=\"m-0 text-sm text-fg-secondary\">{endLabel}</p>\n ) : null}\n </div>\n );\n}\n","// Server-safe. An indeterminate wait: the Krizaka loader glyph (a hexagon traced by light around a node), announced as\n// a status with its `label`. For a wait with a delay, a value, an ETA or an ending, see `@krizaka/ui/loader`.\nimport type * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { LoaderGlyph } from \"./glyph\";\n\nexport const spinnerVariants = tv({\n base: \"shrink-0 text-accent\",\n variants: { size: { sm: \"h-4 w-4\", md: \"h-6 w-6\", lg: \"h-10 w-10\" } },\n defaultVariants: { size: \"md\" },\n});\n\nexport type SpinnerProps = Omit<React.ComponentProps<\"svg\">, \"children\"> &\n VariantProps<typeof spinnerVariants> & {\n /**\n * sm · md · lg.\n * @default \"md\"\n */\n size?: VariantProps<typeof spinnerVariants>[\"size\"];\n /** The accessible name of the wait, e.g. \"Loading\" — passed translated. */\n label: string;\n /** Between 0 and 1: the trace grows to the value (a determinate wait). Absent: it travels around. */\n value?: number | null;\n };\n\n/**\n * The Krizaka spinner: a hexagon traced by a segment of light around a breathing node, in `currentColor` (the accent by\n * default). `role=\"status\"`, named by `label`. Under prefers-reduced-motion it rests — a segment and the node lit.\n */\nexport function Spinner({ label, size, value, className, ...props }: SpinnerProps) {\n return (\n <LoaderGlyph\n role=\"status\"\n aria-label={label}\n aria-hidden={undefined}\n value={value}\n data-size={size ?? \"md\"}\n className={spinnerVariants({ size, className })}\n {...props}\n />\n );\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 { SectionHint, type SectionHintProps } from \"./section-hint\";\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\" | \"hint\" | \"seeAll\" | \"previousLabel\" | \"nextLabel\">;\n /** A heading for the grid of the others (“Videos”), in the style of the shelf's, with an optional definition. */\n grid?: { label: string; hint?: SectionHintProps };\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, grid, className, ...props }: MediaGridProps<T>) {\n const gridHeading = React.useId();\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 <section aria-labelledby={grid ? gridHeading : undefined} data-media-grid-section className=\"min-w-0\">\n {grid && (\n <div className=\"mb-3 flex items-center gap-2\">\n <h2 id={gridHeading} className=\"m-0 text-base font-bold text-fg\">\n {grid.label}\n </h2>\n {grid.hint && <SectionHint {...grid.hint} />}\n </div>\n )}\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 </section>\n )}\n </div>\n );\n}\n","// Client (open state). A tiny \"i\" button beside a section heading: it opens a one-line definition and, when given, a link to\n// the glossary. Opens on a tap or a press, on hover with a mouse, closes on Escape or when the focus leaves.\nimport * as React from \"react\";\n\nimport { BlockLink, type LinkComponent } from \"../block-link\";\nimport { cn } from \"../cn\";\n\nexport interface SectionHintProps {\n /** The button's accessible name, passed translated (“What are Shorts?”). */\n label: string;\n /** The definition, in one line. */\n text: string;\n /** A link to the full definition (the glossary). */\n link?: { href: string; label: string; linkAs?: LinkComponent };\n}\n\n/** The definition of a section, one tap away from its heading. */\nexport function SectionHint({ label, text, link }: SectionHintProps) {\n const [open, setOpen] = React.useState(false);\n const id = React.useId();\n return (\n <span\n className=\"relative inline-flex\"\n onMouseEnter={() => setOpen(true)}\n onMouseLeave={() => setOpen(false)}\n onBlur={(e) => {\n if (!e.currentTarget.contains(e.relatedTarget)) setOpen(false);\n }}\n onKeyDown={(e) => {\n if (e.key === \"Escape\") setOpen(false);\n }}\n >\n <button\n type=\"button\"\n aria-label={label}\n aria-expanded={open}\n aria-controls={id}\n onClick={() => setOpen((o) => !o)}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-full text-fg-muted transition-colors hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"9\" />\n <path d=\"M12 11v5M12 8h.01\" />\n </svg>\n </button>\n <span\n id={id}\n role=\"tooltip\"\n hidden={!open}\n className={cn(\"absolute left-0 top-full z-20 mt-1 w-64 max-w-[80vw] rounded-xl border border-border-default bg-surface-1 p-3 text-sm font-normal leading-snug text-fg-secondary shadow-lg\")}\n >\n {text}\n {link && (\n <>\n {\" \"}\n <BlockLink href={link.href} linkAs={link.linkAs} className=\"font-semibold text-fg-accent hover:underline\">\n {link.label}\n </BlockLink>\n </>\n )}\n </span>\n </span>\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} rel={rel} {...props} />;\n}\n","// 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\";\nimport { SectionHint, type SectionHintProps } from \"./section-hint\";\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 /** A small “i” beside the heading: the one-line definition of the section and a link to the glossary. */\n hint?: SectionHintProps;\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, hint, 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 {hint && <SectionHint {...hint} />}\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 overflow-y-hidden overscroll-x-contain p-0 pt-1 -mt-1 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","// 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\";\nimport { isLeader, subscribeLeader, trackVisibility } from \"./preview-focus\";\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 /**\n * An animated picture (WebP, a few hundred kB) that fades in over the poster once the pointer has rested on the card\n * (or it is focused) for `previewDelay`, and is removed again on leave. It is never requested before. On a phone (no\n * hover) only the card most inside the viewport plays it, unless the person asked for less data or less motion.\n */\n previewSrc?: string | null;\n /**\n * How long the pointer must rest before the preview is requested, in ms: a pointer crossing the grid loads nothing.\n * @default 200\n */\n previewDelay?: number;\n /**\n * `fetchPriority` of the poster: `high` for the first row (the largest contentful paint).\n * @default \"auto\"\n */\n posterPriority?: \"high\" | \"low\" | \"auto\";\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 previewDelay = 200,\n posterPriority = \"auto\",\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 ref,\n ...props\n}: VideoCardProps) {\n const [node, setNode] = React.useState<HTMLElement | null>(null);\n const setRef = React.useCallback(\n (el: HTMLElement | null) => {\n setNode(el);\n if (typeof ref === \"function\") ref(el);\n else if (ref) (ref as React.RefObject<HTMLElement | null>).current = el;\n },\n [ref],\n );\n const canPreview = Boolean(previewSrc) && !blurred;\n const { live, arm, disarm } = usePreviewIntent(node, canPreview, previewDelay);\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <article\n ref={setRef}\n data-aspect={aspect}\n data-layout={layout}\n className={cn(\"group relative h-full min-w-0\", className)}\n data-preview={live ? \"on\" : undefined}\n onMouseEnter={(e) => (arm(\"pointer\"), onMouseEnter?.(e))}\n onMouseLeave={(e) => (disarm(\"pointer\"), onMouseLeave?.(e))}\n onFocus={(e) => (arm(\"focus\"), onFocus?.(e))}\n onBlur={(e) => (disarm(\"focus\"), 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\" && poster && <img src={poster} alt=\"\" aria-hidden loading=\"lazy\" className=\"absolute inset-0 h-full w-full scale-125 object-cover opacity-70 blur-2xl\" />}\n <Card.Image\n src={poster}\n loading={loading}\n fetchPriority={posterPriority === \"auto\" ? undefined : posterPriority}\n fallback={fallback}\n className={cn(fit === \"contain\" && \"relative object-contain\", blurred && \"scale-110 blur-xl\")}\n />\n {live && previewSrc && <PreviewLayer src={previewSrc} contain={fit === \"contain\"} />}\n {overlay && <div className=\"absolute inset-0 z-20 flex\">{overlay}</div>}\n {badges && (\n <Card.Overlay corner=\"top-left\" className=\"theme-dark pointer-events-none flex-wrap\">\n {badges}\n </Card.Overlay>\n )}\n {duration && (\n <Card.Overlay corner=\"bottom-right\" className=\"pointer-events-none\">\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 {/* `static`: the body must not be the containing block of the title link's ::after, or the link would cover the text only and the picture would not open the video. */}\n <Card.Body className=\"static 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\n/** The animated preview, fading in over the poster once it has loaded; unmounted (so unloaded) on leave. */\nfunction PreviewLayer({ src, contain }: { src: string; contain: boolean }) {\n const [ready, setReady] = React.useState(false);\n return (\n <img\n src={src}\n alt=\"\"\n aria-hidden\n decoding=\"async\"\n data-preview-layer=\"\"\n data-ready={ready ? \"\" : undefined}\n onLoad={() => setReady(true)}\n className={cn(\"pointer-events-none absolute inset-0 h-full w-full opacity-0 transition-opacity duration-300 data-[ready]:opacity-100 motion-reduce:transition-none\", contain ? \"object-contain\" : \"object-cover\")}\n />\n );\n}\n\ntype Cause = \"pointer\" | \"focus\";\n\nconst matches = (query: string) => typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(query).matches;\nconst hoverCapable = () => matches(\"(hover: hover)\");\nconst saveData = () => typeof navigator !== \"undefined\" && (navigator as Navigator & { connection?: { saveData?: boolean } }).connection?.saveData === true;\n\n/**\n * When the preview is wanted. A desktop pointer or the keyboard focus must rest `delay` ms first; on a phone the card\n * the page shows most (and only one) wants it, never under Save-Data or reduced motion. Leaving clears everything.\n */\nfunction usePreviewIntent(node: HTMLElement | null, enabled: boolean, delay: number) {\n const [causes, setCauses] = React.useState<ReadonlySet<Cause>>(new Set());\n const timers = React.useRef(new Map<Cause, ReturnType<typeof setTimeout>>());\n const arm = React.useCallback(\n (cause: Cause) => {\n if (!enabled || saveData()) return;\n if (cause === \"pointer\" && !hoverCapable()) return;\n clearTimeout(timers.current.get(cause));\n timers.current.set(\n cause,\n setTimeout(() => setCauses((c) => new Set(c).add(cause)), delay),\n );\n },\n [enabled, delay],\n );\n const disarm = React.useCallback((cause: Cause) => {\n clearTimeout(timers.current.get(cause));\n timers.current.delete(cause);\n setCauses((c) => {\n if (!c.has(cause)) return c;\n const next = new Set(c);\n next.delete(cause);\n return next;\n });\n }, []);\n React.useEffect(() => {\n const pending = timers.current;\n return () => {\n for (const t of pending.values()) clearTimeout(t);\n pending.clear();\n };\n }, []);\n\n // A phone: the single most visible card, after the same rest.\n const touch = enabled && !hoverCapable();\n const leading = React.useSyncExternalStore(\n subscribeLeader,\n () => isLeader(node),\n () => false,\n );\n React.useEffect(() => {\n if (!node || !touch) return;\n return trackVisibility(node);\n }, [node, touch]);\n const [ready, setReady] = React.useState(false);\n const [wasLeading, setWasLeading] = React.useState(false);\n if (leading !== wasLeading) {\n setWasLeading(leading);\n if (!leading) setReady(false);\n }\n const wanted = touch && leading && !saveData() && !matches(\"(prefers-reduced-motion: reduce)\");\n React.useEffect(() => {\n if (!wanted) return;\n const t = setTimeout(() => setReady(true), delay);\n return () => clearTimeout(t);\n }, [wanted, delay]);\n\n return { live: enabled && (causes.size > 0 || (wanted && ready)), arm, disarm };\n}\n","// Client only. Which card of the page is the most visible: on a phone there is no hover, so exactly one card at a time\n// (the one most inside the viewport) may play its preview. One IntersectionObserver for the whole page, no per-card\n// observer; the answer is a store read with `useSyncExternalStore`.\nconst MIN_RATIO = 0.6;\nconst ratios = new Map<Element, number>();\nconst listeners = new Set<() => void>();\nlet observer: IntersectionObserver | null = null;\nlet leader: Element | null = null;\n\nfunction elect() {\n let best: Element | null = null;\n let bestRatio = MIN_RATIO - Number.EPSILON;\n for (const [el, ratio] of ratios) {\n if (ratio > bestRatio) {\n best = el;\n bestRatio = ratio;\n }\n }\n if (best === leader) return;\n leader = best;\n for (const l of listeners) l();\n}\n\n/** Starts counting an element's visibility; returns the function that stops it. */\nexport function trackVisibility(el: Element): () => void {\n if (typeof IntersectionObserver === \"undefined\") return () => {};\n observer ??= new IntersectionObserver(\n (entries) => {\n for (const e of entries) ratios.set(e.target, e.isIntersecting ? e.intersectionRatio : 0);\n elect();\n },\n { threshold: [0, 0.25, 0.5, 0.6, 0.75, 1] },\n );\n ratios.set(el, 0);\n observer.observe(el);\n return () => {\n observer?.unobserve(el);\n ratios.delete(el);\n elect();\n };\n}\n\nexport const subscribeLeader = (l: () => void) => (listeners.add(l), () => void listeners.delete(l));\n\n/** Whether this element is the card the page is showing most. */\nexport const isLeader = (el: Element | null) => el !== null && leader === el;\n\n/** Test seam: forget everything. */\nexport function resetPreviewFocus() {\n observer?.disconnect();\n observer = null;\n ratios.clear();\n leader = null;\n}\n","// A video card on its way: the same frame, body and footer heights as `VideoCard`, so nothing moves when it arrives.\nimport * as React from \"react\";\n\nimport { Card } from \"../card\";\nimport { cn } from \"../cn\";\nimport { Skeleton } from \"../skeleton\";\nimport type { VideoCardAspect } from \"./video-card\";\n\nexport interface VideoCardSkeletonProps extends React.ComponentProps<\"div\"> {\n /** `landscape` (16:9) or `portrait` (9:16), as the card it stands for. @default \"landscape\" */\n aspect?: VideoCardAspect;\n /** `stack` or `row`, as the card it stands for. @default \"stack\" */\n layout?: \"stack\" | \"row\";\n}\n\nconst FRAME = { landscape: \"aspect-video\", portrait: \"aspect-[9/16]\" } as const;\n\n/** The placeholder of a `VideoCard` (decorative: announce the wait on the list, with `MediaGridSkeleton`). */\nexport function VideoCardSkeleton({ aspect = \"landscape\", layout = \"stack\", className, ...props }: VideoCardSkeletonProps) {\n const row = layout === \"row\";\n const tall = aspect === \"portrait\" && !row;\n return (\n <div aria-hidden data-skeleton=\"video-card\" data-aspect={aspect} data-layout={layout} className={cn(\"h-full min-w-0\", className)} {...props}>\n <Card.Root 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 <Skeleton shape=\"rect\" className=\"h-full w-full rounded-none\" />\n </Card.Media>\n <Card.Body className=\"static min-w-0 flex-1 justify-between gap-2 p-3\">\n <div className=\"flex min-h-[2.5em] flex-col justify-center gap-1.5\">\n <Skeleton className=\"h-3\" />\n <Skeleton className=\"h-3 w-3/5\" />\n </div>\n <div className={cn(\"flex text-xs\", tall ? \"flex-col gap-1\" : \"h-8 items-center gap-2\")}>\n <div className=\"flex h-6 min-w-0 items-center gap-2\">\n <Skeleton shape=\"circle\" className=\"h-6 w-6 shrink-0\" />\n <Skeleton className=\"h-2.5 w-20\" />\n </div>\n <div className={cn(\"flex items-center\", tall ? \"h-7\" : \"ml-auto\")}>\n <Skeleton className=\"h-2.5 w-14\" />\n </div>\n </div>\n </Card.Body>\n </Card.Root>\n </div>\n );\n}\n\nexport interface MediaGridSkeletonProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** What is loading, passed translated (\"Loading videos\"): announced once, the cards are hidden from assistive technology. */\n label: string;\n /** Cards in the grid. @default 8 */\n count?: number;\n /** Cards on the Shorts shelf above the grid (`split` mode); 0 for none. @default 0 */\n shelfCount?: number;\n /** `grid` or `list`. @default \"grid\" */\n layout?: \"grid\" | \"list\";\n /** The frame of the grid. @default \"landscape\" */\n frame?: VideoCardAspect;\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/** The placeholder of a `MediaGrid`: the same shelf and grid, skeleton cards, one polite announcement. */\nexport function MediaGridSkeleton({ label, count = 8, shelfCount = 0, layout = \"grid\", frame = \"landscape\", className, ...props }: MediaGridSkeletonProps) {\n const row = layout === \"list\";\n return (\n <div role=\"status\" aria-busy=\"true\" data-media-grid-skeleton=\"\" className={cn(\"flex min-w-0 flex-col gap-8\", className)} {...props}>\n <span className=\"sr-only\">{label}</span>\n {shelfCount > 0 && (\n <div aria-hidden className=\"min-w-0\">\n <Skeleton className=\"mb-3 h-4 w-24\" />\n <ul className=\"m-0 flex list-none items-stretch gap-3 overflow-hidden p-0\">\n {Array.from({ length: shelfCount }, (_, i) => (\n <li key={i} className=\"w-[9.5rem] shrink-0 sm:w-44\">\n <VideoCardSkeleton aspect=\"portrait\" />\n </li>\n ))}\n </ul>\n </div>\n )}\n <ul aria-hidden className={cn(\"m-0 grid list-none auto-rows-fr gap-4 p-0\", row ? \"grid-cols-1\" : GRID[frame])}>\n {Array.from({ length: count }, (_, i) => (\n <li key={i} className=\"min-w-0\">\n <VideoCardSkeleton aspect={frame} layout={row ? \"row\" : \"stack\"} />\n </li>\n ))}\n </ul>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","React","React","jsx","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","React","jsx","jsxs","jsx","jsxs","FRAME","GRID"]}
|
package/dist/page-hero.js
CHANGED
package/dist/page-index.js
CHANGED
package/dist/service-card.js
CHANGED
package/dist/slot-picker.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krizaka/ui",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.54.0",
|
|
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",
|
|
@@ -525,6 +525,10 @@
|
|
|
525
525
|
"types": "./dist/page-index.d.ts",
|
|
526
526
|
"import": "./dist/page-index.js"
|
|
527
527
|
},
|
|
528
|
+
"./chapter": {
|
|
529
|
+
"types": "./dist/chapter.d.ts",
|
|
530
|
+
"import": "./dist/chapter.js"
|
|
531
|
+
},
|
|
528
532
|
"./footnote": {
|
|
529
533
|
"types": "./dist/footnote.d.ts",
|
|
530
534
|
"import": "./dist/footnote.js"
|
|
@@ -797,7 +801,7 @@
|
|
|
797
801
|
],
|
|
798
802
|
"peerDependencies": {
|
|
799
803
|
"@krizaka/query": ">=0.2.1",
|
|
800
|
-
"@krizaka/tailwind": ">=3.
|
|
804
|
+
"@krizaka/tailwind": ">=3.54.0",
|
|
801
805
|
"@maplibre/maplibre-react-native": ">=11",
|
|
802
806
|
"@shopify/flash-list": ">=2",
|
|
803
807
|
"expo-camera": ">=16",
|
|
@@ -2023,6 +2027,16 @@
|
|
|
2023
2027
|
"clsx"
|
|
2024
2028
|
]
|
|
2025
2029
|
},
|
|
2030
|
+
{
|
|
2031
|
+
"name": "./chapter",
|
|
2032
|
+
"path": "dist/chapter.js",
|
|
2033
|
+
"limit": "1.8 kB",
|
|
2034
|
+
"gzip": true,
|
|
2035
|
+
"ignore": [
|
|
2036
|
+
"tailwind-variants",
|
|
2037
|
+
"clsx"
|
|
2038
|
+
]
|
|
2039
|
+
},
|
|
2026
2040
|
{
|
|
2027
2041
|
"name": "./footnote",
|
|
2028
2042
|
"path": "dist/footnote.js",
|
|
@@ -2679,7 +2693,7 @@
|
|
|
2679
2693
|
"zod": "^4.6.5",
|
|
2680
2694
|
"@krizaka/intl": "^0.3.0",
|
|
2681
2695
|
"@krizaka/pacer": "^0.1.0",
|
|
2682
|
-
"@krizaka/tokens": "^3.
|
|
2696
|
+
"@krizaka/tokens": "^3.54.0"
|
|
2683
2697
|
},
|
|
2684
2698
|
"scripts": {
|
|
2685
2699
|
"build": "node -e \"const fs=require('node:fs');fs.rmSync('dist',{recursive:true,force:true});for(const f of fs.readdirSync('registry/examples',{recursive:true}))if(/\\.(js|d\\.ts)$/.test(f))fs.rmSync('registry/examples/'+f)\" && tsup && node -e \"require('node:fs').copyFileSync('src/motion.css','dist/motion.css');require('node:fs').copyFileSync('src/blocks.css','dist/blocks.css');require('node:fs').copyFileSync('src/story.css','dist/story.css')\" && node scripts/build-registry.mjs",
|