Selection Presence

Superposition a bordure en pointilles marquant ce qu'un autre utilisateur a selectionne sur le canvas. Installez Selection Presence depuis le registre VLLNT UI avec la CLI shadcn.

Signaler un bug

Superposition a bordure en pointilles marquant ce qu'un autre utilisateur a selectionne sur le canvas. Fait partie de la famille utility dans VLLNT UI, il est publie comme entree de registre lisible par machine — copiez la source directement dans votre application avec la CLI shadcn et possedez-la, sans dependance d'execution a une bibliotheque de composants.

Apercu

Basculez entre clair et sombre pour inspecter l'apercu Storybook integre.

Installation

Ajoutez Selection Presence a votre projet avec la CLI shadcn. La source arrive dans votre code, prete a etre adaptee :

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/selection-presence.json

Source

"use client"; import type { ComponentPropsWithoutRef, ReactNode } from "react"; import { cn } from "../../lib/utils"; /** * Localizable strings. * * @public */ export type SelectionPresenceLabels = { /** Aria-label override. Defaults to `"Selection presence"`. */ region?: string; }; const DEFAULT_LABELS = { region: "Selection presence", } as const satisfies Required<SelectionPresenceLabels>; /** * Props for {@link SelectionPresence}. * * @public */ export type SelectionPresenceProps = { /** Tailwind / CSS color used for the border + chip. Defaults to `var(--foreground)`. */ color?: string; /** Selection rectangle height in pixels. */ height: number; /** Localizable strings. */ labels?: SelectionPresenceLabels; /** Optional name shown in the corner chip (e.g. owner of the selection). */ name?: ReactNode; /** Selection rectangle width in pixels. */ width: number; /** Selection rectangle X (top-left) in canvas pixels. */ x: number; /** Selection rectangle Y (top-left) in canvas pixels. */ y: number; } & ComponentPropsWithoutRef<"div">; /** * Overlay marking what another user has selected on the canvas. The * dashed border + soft fill stay calm so they communicate * "someone-else's-selection" without blocking primary content. Pure * presentation; the host computes the rect from the remote user's * viewport and supplies an accent color per user. * * The wrapper is `pointer-events: none` so host gestures pass through. * * @example * ```tsx * <div className="relative h-screen w-screen"> * <Canvas /> * <SelectionPresence * x={120} y={80} width={240} height={120} * color="#5b8def" * name="Bea" * /> * </div> * ``` * * @public */ export const SelectionPresence = ({ ref, ...props }: SelectionPresenceProps & { ref?: React.Ref<HTMLDivElement> }) => { const { className, color, height, labels, name, width, x, y, ...rest } = props; const resolvedLabels = { ...DEFAULT_LABELS, ...labels }; const accent = color ?? "var(--foreground)"; const ariaLabel = typeof name === "string" ? `${resolvedLabels.region}: ${name}` : resolvedLabels.region; return ( <div aria-label={ariaLabel} className={cn( "pointer-events-none absolute z-20 rounded-md border-2 border-dashed", className, )} data-selection-presence ref={ref} role="img" style={{ backgroundColor: `color-mix(in srgb, ${accent} 10%, transparent)`, borderColor: accent, height, left: x, top: y, width, }} {...rest} > {name === null || name === undefined ? null : ( <span className="absolute -top-5 left-0 inline-flex items-center rounded-md px-1.5 py-0.5 text-[10px] font-medium text-white shadow-sm" data-selection-presence-chip style={{ backgroundColor: accent }} > {name} </span> )} </div> ); }; SelectionPresence.displayName = "SelectionPresence";

Stories

Explorez chaque variante et etat dans le Storybook interactif :

Apercu

Basculez entre clair et sombre pour inspecter l'apercu Storybook integre.

Dependances

  • @vllnt/ui@^0.3.0