Clip Path Editor
ridiculous/clip-path-editorFreeComponent
Ridiculously typed CSS clip-path / shape-outside editor for a single <basic-shape> (inset / circle / ellipse / polygon) with an optional geometry-box keyword, validated by compile-time basic-shape dispatch through ParseFunction. Ships a tolerant runtime parser and a live preview with draggable polygon vertices.
Install it
npx shadcn@latest add http://ridiculous.turtlesocks.dev/r/clip-path-editor.jsonSource
1"use client"23import { useEffect, useRef, useState } from "react"4import { Button } from "@/components/ui/button"5import {6 Popover,7 PopoverContent,8 PopoverTrigger,9} from "@/components/ui/popover"10import { cn } from "@/lib/utils"11import type { ClipMode } from "./clip-path-editor.constants"12import {13 defaultShape,14 formatClipPath,15 parseClipPath,16 shapeToCss,17} from "./clip-path-editor.helpers"18import type {19 BasicShapeName,20 ClipPathShapeState,21 ClipPathState,22 ClipPathString,23 GeometryBox,24} from "./clip-path-editor.types"25import { ShapeControls } from "./controls/shape-controls"26import { ClipPathPreview } from "./preview/clip-path-preview"27import { GeometryBoxSelect } from "./primitives/geometry-box-select"28import { LiveString } from "./primitives/live-string"29import { ShapeSelect } from "./primitives/shape-select"3031// ---------------------------------------------------------------------------32// Shared props33// ---------------------------------------------------------------------------3435export interface ClipPathEditorPanelProps {36 value: ClipPathString | (string & {})37 onChange: (value: ClipPathString) => void38 /**39 * Which CSS property the live preview targets. Both `clip-path` and40 * `shape-outside` share the identical basic-shape grammar, so this does NOT41 * change validation or narrow the `onChange` output — it only drives the42 * preview render target + labels. Defaults to `"clip-path"`.43 */44 mode?: ClipMode45 className?: string46 "aria-label"?: string47}4849export interface ClipPathEditorProps extends ClipPathEditorPanelProps {}5051// ---------------------------------------------------------------------------52// ClipPathEditor — popover-wrapped53// ---------------------------------------------------------------------------5455export function ClipPathEditor(props: ClipPathEditorProps) {56 const {57 value,58 className,59 "aria-label": ariaLabel = "Edit a clip-path",60 } = props61 const state = parseClipPath(String(value))62 const label =63 state === null64 ? "invalid"65 : state.shape === null66 ? (state.box ?? "none")67 : state.shape.shape6869 return (70 <Popover>71 <PopoverTrigger asChild>72 <Button73 variant="outline"74 className={cn("h-9 gap-2 px-3 font-mono", className)}75 aria-label={ariaLabel}76 >77 <span aria-hidden="true" className="text-foreground/60">78 ⬡79 </span>80// … truncated
What it pulls in
Other registry items
Files it writes
More from ridiculous
All 22 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| All ridiculous componentsall | ridiculous | Components | Free | no deps | |
| Anchor Position Editoranchor-position-editor | ridiculous | Components | Free | no deps · 9 files | |
| Background Editorbackground-editor | ridiculous | Components | Free | no deps · 9 files | |
| Box Shadow Editorbox-shadow-editor | ridiculous | Components | Free | no deps · 7 files | |
| Calc Editorcalc-editor | ridiculous | Components | Free | no deps · 4 files | |
| Color Functioncolor-function | ridiculous | Components | Free | no deps · 10 files | |
| Color Pickercolor-picker | ridiculous | Components | Free | no deps · 11 files | |
| Easing Pickereasing-picker | ridiculous | Components | Free | no deps · 17 files |
