{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "ikui",
  "homepage": "https://ik-ui.pages.dev",
  "author": "wudi <wuchendi96@gmail.com>",
  "items": [
    {
      "name": "chart",
      "type": "registry:component",
      "title": "Chart",
      "description": "Recharts-based chart primitives (container, tooltip, legend) with theme-aware colors. Compose bar, area, line, pie, radar, and radial charts from a single config.",
      "files": [
        {
          "path": "registry/ikui/chart.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "recharts"],
      "registryDependencies": [],
      "category": "display"
    },
    {
      "name": "spark-chart",
      "type": "registry:component",
      "title": "Spark Chart",
      "description": "Dependency-free interactive line chart with a cursor-tracked tooltip, snap-to-point hover, reveal effect, and built-in X-axis labels.",
      "files": [
        {
          "path": "registry/ikui/spark-chart.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [],
      "category": "display"
    },
    {
      "name": "qr-code",
      "type": "registry:component",
      "title": "QR Code",
      "description": "QR code generator with rounded finder patterns and dot-style data modules.",
      "files": [
        {
          "path": "registry/ikui/qr-code.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "qrcode", "lucide-react"],
      "registryDependencies": [],
      "category": "display"
    },
    {
      "name": "copy-button",
      "type": "registry:component",
      "title": "Copy Button",
      "description": "A copy-to-clipboard button with blur transition effect.",
      "files": [
        {
          "path": "registry/ikui/copy-button.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "lucide-react"],
      "registryDependencies": [],
      "category": "button"
    },
    {
      "name": "cascader",
      "type": "registry:component",
      "title": "Cascader",
      "description": "A column-based cascading dropdown for selecting a path through hierarchical data (region \u2192 city \u2192 district, category trees). Desktop popover / mobile drawer, keyboard navigable, controlled or uncontrolled, with clear and custom display rendering.",
      "files": [
        {
          "path": "registry/ikui/cascader.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "lucide-react"],
      "registryDependencies": ["popover", "drawer", "use-mobile"],
      "category": "form"
    },
    {
      "name": "password-input",
      "type": "registry:component",
      "title": "Password Input",
      "description": "A password field with a trailing show/hide toggle, composed from the input-group primitive. Spreads native input props (name, value, onChange, placeholder).",
      "files": [
        {
          "path": "registry/ikui/password-input.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["lucide-react"],
      "registryDependencies": ["input-group"],
      "category": "form"
    },
    {
      "name": "tree",
      "type": "registry:component",
      "title": "Tree",
      "description": "A data-driven hierarchical tree view of folders and leaves with selection, expand/collapse, per-node icons, an actions slot, and a custom renderItem. Self-managed expand state, animated open/close, ARIA roving-tabindex keyboard navigation, and native drag-and-drop to reorder or re-parent nodes via onDocumentDrag. Controlled or uncontrolled selection reported through onSelectChange.",
      "files": [
        {
          "path": "registry/ikui/tree.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "lucide-react"],
      "registryDependencies": [],
      "category": "display"
    },
    {
      "name": "date-range-picker",
      "type": "registry:component",
      "title": "Date Range Picker",
      "description": "A popover date range picker with a quick-preset side panel (Today, Last 7 days, This month, …), a two-month calendar with live hover-range preview, min/max clamping, and a clearable trigger. Controlled or uncontrolled, with configurable presets and date-fns locale.",
      "files": [
        {
          "path": "registry/ikui/date-range-picker.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "date-fns", "react-day-picker", "lucide-react"],
      "registryDependencies": ["calendar", "popover", "button"],
      "category": "form"
    },
    {
      "name": "heatmap-calendar",
      "type": "registry:component",
      "title": "Heatmap Calendar",
      "description": "A GitHub-style contribution heatmap. Buckets dated values into color levels across a weeks × weekdays grid, with month/weekday axis labels, a Less→More legend, a shared hover tooltip, and custom palettes. Driven purely by data — no card or title scaffolding.",
      "files": [
        {
          "path": "registry/ikui/heatmap-calendar.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "date-fns"],
      "registryDependencies": ["tooltip"],
      "category": "display"
    },
    {
      "name": "audio-waveform",
      "type": "registry:component",
      "title": "Audio Waveform",
      "description": "A static, width-explicit waveform for timelines. Decodes audio (URL / Blob / AudioBuffer) into normalized peaks \u2014 or takes precomputed peaks \u2014 and renders mirrored canvas bars at any pixel width, with optional played-progress coloring. Backs the waveform-player.",
      "files": [
        {
          "path": "registry/ikui/audio-waveform.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [],
      "category": "audio"
    },
    {
      "name": "waveform-player",
      "type": "registry:component",
      "title": "Waveform Player",
      "description": "A compact audio player built on audio-waveform: play/pause, elapsed and total time, played-progress coloring, and click/drag-to-seek on the waveform.",
      "files": [
        {
          "path": "registry/ikui/waveform-player.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "lucide-react"],
      "registryDependencies": ["button", "@ikui/audio-waveform"],
      "category": "audio"
    },
    {
      "name": "video-thumbnail-cache",
      "type": "registry:lib",
      "title": "Video Thumbnail Cache",
      "description": "Decode video frames via mediabunny on demand and cache them as ImageBitmaps. Backs the thumbnail-strip and segmented-timeline-strip components.",
      "files": [
        {
          "path": "registry/ikui/video-thumbnail-cache.ts",
          "type": "registry:lib"
        }
      ],
      "dependencies": ["mediabunny"],
      "registryDependencies": [],
      "category": "video"
    },
    {
      "name": "thumbnail-strip",
      "type": "registry:component",
      "title": "Thumbnail Strip",
      "description": "A viewport-virtualized canvas strip rendering video thumbnails along a horizontal timeline. Pairs with video-thumbnail-cache for the frame decoding.",
      "files": [
        {
          "path": "registry/ikui/thumbnail-strip.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": [],
      "registryDependencies": ["@ikui/video-thumbnail-cache"],
      "category": "video"
    },
    {
      "name": "segmented-timeline-strip",
      "type": "registry:component",
      "title": "Segmented Timeline Strip",
      "description": "Multi-clip timeline overview built by composing one thumbnail-strip per segment with DOM chrome (active border, dim mask, label, playhead, total duration badge) and click-to-seek.",
      "files": [
        {
          "path": "registry/ikui/segmented-timeline-strip.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [
        "@ikui/thumbnail-strip",
        "@ikui/video-thumbnail-cache"
      ],
      "category": "video"
    },
    {
      "name": "timeline-ruler",
      "type": "registry:component",
      "title": "Timeline Ruler",
      "description": "A pure, zoom-aware, horizontally-scrollable time ruler: adaptive tick density and MM:SS / frame labels, with viewport virtualization. Just the scale \u2014 playhead, seeking, and tracks are left to the consumer.",
      "files": [
        {
          "path": "registry/ikui/timeline-ruler.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [],
      "category": "timeline"
    },
    {
      "name": "timeline-element",
      "type": "registry:component",
      "title": "Timeline Element",
      "description": "A positioned, trimmable timeline clip: places itself on a track by time (startTime/duration \u00d7 pixelsPerSecond \u00d7 zoom, the same basis as timeline-ruler) and renders any content inside \u2014 an audio waveform, a thumbnail strip, a label. Selectable, with left/right trim handles that emit the new geometry. The track, playhead, and seeking are left to the consumer.",
      "files": [
        {
          "path": "registry/ikui/timeline-element.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": [],
      "registryDependencies": [],
      "category": "timeline"
    },
    {
      "name": "timeline-playhead",
      "type": "registry:component",
      "title": "Timeline Playhead",
      "description": "A draggable timeline playhead: a vertical line with a top knob, positioned by time (currentTime \u00d7 pixelsPerSecond \u00d7 zoom, the same basis as timeline-ruler) and scrubbable. Drag it to seek; it scrolls with the tracks it sits over. Spans whatever container it is placed in. The playback clock and click-to-seek on the tracks are left to the consumer.",
      "files": [
        {
          "path": "registry/ikui/timeline-playhead.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": [],
      "registryDependencies": [],
      "category": "timeline"
    },
    {
      "name": "audio-trimmer",
      "type": "registry:block",
      "title": "Audio Trimmer",
      "description": "A business composition built from the timeline primitives: trim an audio clip with the timeline-element handles, then play back only the trimmed [startTime, startTime + duration] window. The playhead follows playback, the waveform colors in as it plays, and an In / Out / length readout tracks the selection.",
      "files": [
        {
          "path": "registry/ikui/blocks/audio-trimmer.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react", "mediabunny"],
      "registryDependencies": [
        "@ikui/timeline-ruler",
        "@ikui/timeline-element",
        "@ikui/timeline-playhead",
        "@ikui/audio-waveform",
        "button",
        "card",
        "slider",
        "scroll-area",
        "skeleton"
      ],
      "category": "blocks",
      "categories": ["audio"]
    },
    {
      "name": "video-trimmer",
      "type": "registry:block",
      "title": "Video Trimmer",
      "description": "A business composition built from the timeline primitives: trim a video clip with the timeline-element handles over a thumbnail strip, then play back only the trimmed [startTime, startTime + duration] window in the preview. The playhead follows playback, the frames outside the selection dim, and an In / Out / length readout tracks the selection. Export cuts the window to an MP4 via mediabunny.",
      "files": [
        {
          "path": "registry/ikui/blocks/video-trimmer.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react", "mediabunny"],
      "registryDependencies": [
        "@ikui/timeline-ruler",
        "@ikui/timeline-element",
        "@ikui/timeline-playhead",
        "@ikui/thumbnail-strip",
        "@ikui/video-thumbnail-cache",
        "button",
        "card",
        "slider",
        "scroll-area",
        "skeleton"
      ],
      "category": "blocks",
      "categories": ["video"],
      "meta": {
        "iframeHeight": 640
      }
    },
    {
      "name": "video-audio-extractor",
      "type": "registry:block",
      "title": "Video Audio Extractor",
      "description": "A business composition built from the timeline primitives: pick a range on a video with the timeline-element handles over a thumbnail strip, then export just that window as an audio file. The playhead follows playback, the frames outside the selection dim, and an In / Out / length readout tracks the selection. Export discards the picture and writes the trimmed audio as WAV, M4A or OGG via mediabunny.",
      "files": [
        {
          "path": "registry/ikui/blocks/video-audio-extractor.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react", "mediabunny"],
      "registryDependencies": [
        "@ikui/timeline-ruler",
        "@ikui/timeline-element",
        "@ikui/timeline-playhead",
        "@ikui/thumbnail-strip",
        "@ikui/video-thumbnail-cache",
        "button",
        "card",
        "select",
        "slider",
        "scroll-area",
        "skeleton"
      ],
      "category": "blocks",
      "categories": ["video", "audio"],
      "meta": {
        "iframeHeight": 640
      }
    },
    {
      "name": "media-compressor",
      "type": "registry:block",
      "title": "Media Compressor",
      "description": "A business composition over mediabunny's Conversion: load an audio or video file, pick a quality preset and (for video) a target resolution, then re-encode to a smaller MP4 \u2014 video as H.264 + AAC, audio-only as AAC. A before/after readout shows the original size, the compressed size, and the percentage saved; the result auto-downloads.",
      "files": [
        {
          "path": "registry/ikui/blocks/media-compressor.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react", "mediabunny"],
      "registryDependencies": [
        "@ikui/waveform-player",
        "button",
        "card",
        "select",
        "skeleton"
      ],
      "category": "blocks",
      "categories": ["video", "audio"],
      "meta": {
        "iframeHeight": 560
      }
    },
    {
      "name": "image-compare",
      "type": "registry:component",
      "title": "Image Compare",
      "description": "A before/after image comparison slider. Drag (or hover) to reveal one image over another, horizontally or vertically, with optional labels, a custom handle, and a loading skeleton. Responsive out of the box.",
      "files": [
        {
          "path": "registry/ikui/image-compare.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "lucide-react"],
      "registryDependencies": [],
      "category": "image"
    },
    {
      "name": "image-crop",
      "type": "registry:component",
      "title": "Image Crop",
      "description": "A responsive, pointer- and keyboard-driven image cropping tool. Draw, drag, and 8-way resize a crop over any image or video, with fixed aspect ratios, circular crops, min/max bounds, rule-of-thirds guides, and percent/pixel crop callbacks. Self-contained Tailwind styling, zero dependencies.",
      "files": [
        {
          "path": "registry/ikui/image-crop.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [],
      "category": "image"
    },
    {
      "name": "image-grid",
      "type": "registry:component",
      "title": "Image Grid",
      "description": "An adaptive photo grid that lays out 1 to 9 images in WeChat-moments style: 1\u20138 use hand-tuned collage layouts on a 6\u00d76 grid (every cell stays a healthy size) and 9 fills a uniform 3\u00d73 grid, with the container always staying square. Responsive, dependency-free, with optional keyboard-accessible per-cell click and custom rendering for lightbox integration.",
      "files": [
        {
          "path": "registry/ikui/image-grid.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [],
      "category": "image"
    },
    {
      "name": "image-cropper",
      "type": "registry:block",
      "title": "Image Cropper",
      "description": "A business composition built on the image-crop primitive: load an image and frame a crop inline, with the selection rendered live as a real image in the preview beside it \u2014 that preview is the cropped result. Switch to a circular avatar crop, rotate the source in 90\u00b0 steps, or lock the box to an aspect-ratio preset; the output is validated against min/max source-pixel bounds (the readout turns red until it fits) and downloads at full resolution.",
      "files": [
        {
          "path": "registry/ikui/blocks/image-cropper.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react"],
      "registryDependencies": ["@ikui/image-crop", "button", "card"],
      "category": "blocks",
      "categories": ["image"],
      "meta": {
        "iframeHeight": 580
      }
    },
    {
      "name": "image-editor",
      "type": "registry:block",
      "title": "Image Editor",
      "description": "A full single-image editor built on fabric.js, wrapped in ikui's Base UI toolbar. Annotate with text, shapes, arrows, and image overlays; free-draw; pixelate a region for a privacy mosaic; tune brightness, contrast, and saturation; apply filter presets; crop (via the image-crop primitive) and resize; rotate, flip, undo, and redo; then export to PNG or JPEG. The fabric canvas is created from a lazily-imported module inside an effect, so the browser-only library never runs during SSR.",
      "files": [
        {
          "path": "registry/ikui/blocks/image-editor.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": [
        "cn",
        "fabric",
        "lucide-react",
        "@dnd-kit/core",
        "@dnd-kit/sortable",
        "@dnd-kit/utilities"
      ],
      "registryDependencies": [
        "@ikui/image-crop",
        "alert-dialog",
        "button",
        "card",
        "dropdown-menu",
        "field",
        "popover",
        "resizable",
        "select",
        "slider",
        "toggle-group"
      ],
      "category": "blocks",
      "categories": ["image"],
      "meta": {
        "iframeHeight": 700
      }
    },
    {
      "name": "particle-image",
      "type": "registry:component",
      "title": "Particle Image",
      "description": "Turn any image into an interactive particle field that scatters from the pointer and settles back toward its origin.",
      "files": [
        {
          "path": "registry/ikui/particle-image.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn"],
      "registryDependencies": [],
      "category": "image"
    },
    {
      "name": "storyboard-timeline",
      "type": "registry:block",
      "title": "Storyboard Timeline",
      "description": "A business composition built from the timeline primitives: lays out a mix of video and image shots end-to-end on a single absolute time axis, each shot wrapped in its own card (header label, duration, type tag) over a shared timeline-ruler, with a draggable timeline-playhead that follows playback across shots. Videos play in the preview and are driven by the media clock; image stills advance on an rAF clock for their set duration. Zoom widens the strips and ruler while the timeline scrolls; the preview swaps source at shot boundaries.",
      "files": [
        {
          "path": "registry/ikui/blocks/storyboard-timeline.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react"],
      "registryDependencies": [
        "@ikui/timeline-ruler",
        "@ikui/timeline-playhead",
        "@ikui/thumbnail-strip",
        "@ikui/video-thumbnail-cache",
        "button",
        "card",
        "slider",
        "scroll-area",
        "skeleton"
      ],
      "category": "blocks",
      "categories": ["video"],
      "meta": {
        "iframeHeight": 560
      }
    },
    {
      "name": "video-frame-extractor",
      "type": "registry:block",
      "title": "Video Frame Extractor",
      "description": "A business composition over mediabunny's VideoSampleSink: load a video, then grab the still under the playhead at native resolution. A ruler aligned to the real duration sits above a continuous filmstrip carrying a playhead that tracks playback; the `<video>` has no native controls \u2014 play/pause lives outside it \u2014 so wherever it plays (or you drag the playhead) to, one button saves that exact frame. The zoom slider sets the timeline density for fine scrubbing. PNG or JPEG.",
      "files": [
        {
          "path": "registry/ikui/blocks/video-frame-extractor.tsx",
          "type": "registry:block"
        }
      ],
      "dependencies": ["lucide-react", "mediabunny"],
      "registryDependencies": [
        "@ikui/timeline-ruler",
        "@ikui/timeline-playhead",
        "@ikui/thumbnail-strip",
        "@ikui/video-thumbnail-cache",
        "button",
        "card",
        "select",
        "slider",
        "scroll-area",
        "skeleton"
      ],
      "category": "blocks",
      "categories": ["video"],
      "meta": {
        "iframeHeight": 640
      }
    },
    {
      "name": "data-table",
      "type": "registry:component",
      "title": "Data Table",
      "description": "A full-featured data table built on TanStack Table: sticky column pinning, row virtualization for large datasets, dnd-kit drag-to-reorder rows, a paginated footer, a filter toolbar with text / number / range (slider) / date / faceted (select) filters driven by per-column meta, a column-visibility view menu, sortable column headers, and a loading skeleton. Bring your own TanStack table instance; the pieces are composable.",
      "files": [
        {
          "path": "registry/ikui/data-table.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-toolbar.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-pagination.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-view-options.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-column-header.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-faceted-filter.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-date-filter.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-slider-filter.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-skeleton.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-draggable-row.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-drag-handle.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-utils.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/ikui/data-table-cell-utils.ts",
          "type": "registry:lib"
        },
        {
          "path": "registry/ikui/text-with-tooltip.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/hover-card-timestamp.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-badge.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-bar.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-boolean.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-code.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-gauge.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-heatmap.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-level-indicator.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-number.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-star.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-status-code.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-text.tsx",
          "type": "registry:component"
        },
        {
          "path": "registry/ikui/data-table-cell-timestamp.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": [
        "cn",
        "@tanstack/react-table",
        "@tanstack/react-virtual",
        "@dnd-kit/core",
        "@dnd-kit/modifiers",
        "@dnd-kit/sortable",
        "@dnd-kit/utilities",
        "date-fns",
        "lucide-react"
      ],
      "registryDependencies": [
        "table",
        "button",
        "select",
        "dropdown-menu",
        "popover",
        "command",
        "badge",
        "separator",
        "input",
        "input-group",
        "label",
        "slider",
        "calendar",
        "skeleton",
        "tooltip",
        "hover-card"
      ],
      "category": "display"
    },
    {
      "name": "media-viewer",
      "type": "registry:component",
      "title": "Media Viewer",
      "description": "A full-screen media lightbox that pages through a mixed list of images, videos, and audio in one swipeable carousel. Images fit the viewport, videos play inline with native controls, and audio slides show a waveform player under an optional cover that scales while it plays. Renders through a portal with its own fade, scroll lock, Escape-to-close, and slide counter — no dialog dependency. Controlled via open / onOpenChange with an initialIndex.",
      "files": [
        {
          "path": "registry/ikui/media-viewer.tsx",
          "type": "registry:component"
        }
      ],
      "dependencies": ["cn", "lucide-react"],
      "registryDependencies": ["@ikui/waveform-player", "carousel", "button"],
      "category": "image"
    }
  ]
}
