{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "sticker-kbd", "title": "Sticker Kbd", "description": "A keycap is already a die-cut object: a 3px edge and a 2px bottom lip that compresses to nothing when the key goes down. Pass watch and it depresses on the real keystroke. frame={false} prints the cap flat, for a keycap inside a tooltip or a menu row.", "registryDependencies": [ "@duck/theme" ], "files": [ { "path": "registry/duck/ui/sticker-kbd.tsx", "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * StickerKbd — a keycap is already a die-cut object, so it needs no invention:\n * a 3px edge and a 2px hard bottom lip that compresses to nothing when the key\n * goes down. Pass `watch` and it depresses on the real keystroke, not just on\n * the mouse — the cap moves at the moment the user's finger does.\n *\n * All of the motion is reactive, so it costs nothing against the one-idle-\n * animation-per-viewport rule.\n */\nexport interface StickerKbdProps extends React.ComponentProps<\"kbd\"> {\n /**\n * A KeyboardEvent.key to listen for, case-insensitive — \"k\", \"Enter\",\n * \"Escape\". The cap presses while that key is held anywhere on the page.\n */\n watch?: string;\n /** Also require the platform's command key: Meta on Apple, Control elsewhere. */\n meta?: boolean;\n /**\n * Draw the die-cut edge and the lip. Off for a keycap printed inside a tooltip\n * or a menu row, where a third border is noise. Same prop, same reason, as on\n * GlowInput: `.sticker` lands at the end of the utilities layer, so a\n * `border-0` at the call site loses on order. `sticker-none` is the\n * class-level version.\n */\n frame?: boolean;\n}\n\nfunction StickerKbd({\n className,\n children,\n watch,\n meta,\n frame = true,\n ...props\n}: StickerKbdProps) {\n const [down, setDown] = React.useState(false);\n\n React.useEffect(() => {\n if (!watch) return;\n const wanted = watch.toLowerCase();\n const matches = (event: KeyboardEvent) =>\n event.key.toLowerCase() === wanted &&\n (!meta || event.metaKey || event.ctrlKey);\n\n const onDown = (event: KeyboardEvent) => matches(event) && setDown(true);\n const onUp = (event: KeyboardEvent) => matches(event) && setDown(false);\n // A held key that loses the window never fires keyup.\n const onBlur = () => setDown(false);\n\n document.addEventListener(\"keydown\", onDown);\n document.addEventListener(\"keyup\", onUp);\n window.addEventListener(\"blur\", onBlur);\n return () => {\n document.removeEventListener(\"keydown\", onDown);\n document.removeEventListener(\"keyup\", onUp);\n window.removeEventListener(\"blur\", onBlur);\n };\n }, [watch, meta]);\n\n return (\n \n {children}\n \n );\n}\n\nexport { StickerKbd };\n", "type": "registry:ui" } ], "type": "registry:ui" }