{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "highlight",
  "title": "Highlight",
  "description": "Highlight effect component for tabs and other interactive elements.",
  "dependencies": [
    "motion",
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "https://optics.agusmayol.com.ar/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/optics/helpers/primitives/effects/highlight.jsx",
      "content": "\"use client\";\nimport * as React from \"react\";\nimport { AnimatePresence, motion } from \"motion/react\";\n\nimport { cn } from \"@/registry/optics/lib/utils\";\n\nconst HighlightContext = React.createContext(\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tundefined,\n);\n\nfunction useHighlight() {\n\tconst context = React.useContext(HighlightContext);\n\tif (!context) {\n\t\tthrow new Error(\"useHighlight must be used within a HighlightProvider\");\n\t}\n\treturn context;\n}\n\nfunction Highlight({ ref, ...props }) {\n\tconst {\n\t\tas: Component = \"div\",\n\t\tchildren,\n\t\tvalue,\n\t\tdefaultValue,\n\t\tonValueChange,\n\t\tclassName,\n\t\tstyle,\n\t\ttransition = { type: \"spring\", stiffness: 350, damping: 35 },\n\t\thover = false,\n\t\tclick = true,\n\t\tenabled = true,\n\t\tcontrolledItems,\n\t\tdisabled = false,\n\t\texitDelay = 200,\n\t\tmode = \"children\",\n\t} = props;\n\n\tconst localRef = React.useRef(null);\n\tReact.useImperativeHandle(ref, () => localRef.current);\n\n\tconst [activeValue, setActiveValue] = React.useState(\n\t\tvalue ?? defaultValue ?? null,\n\t);\n\tconst [boundsState, setBoundsState] = React.useState(null);\n\tconst [activeClassNameState, setActiveClassNameState] = React.useState(\"\");\n\n\tconst safeSetActiveValue = React.useCallback(\n\t\t(id) => {\n\t\t\tsetActiveValue((prev) => (prev === id ? prev : id));\n\t\t\tif (id !== activeValue) onValueChange?.(id);\n\t\t},\n\t\t[activeValue, onValueChange],\n\t);\n\n\tconst safeSetBounds = React.useCallback(\n\t\t(bounds) => {\n\t\t\tif (!localRef.current) return;\n\n\t\t\tconst boundsOffset = props?.boundsOffset ?? {\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0,\n\t\t\t\twidth: 0,\n\t\t\t\theight: 0,\n\t\t\t};\n\n\t\t\tconst containerRect = localRef.current.getBoundingClientRect();\n\t\t\tconst newBounds = {\n\t\t\t\ttop: bounds.top - containerRect.top + (boundsOffset.top ?? 0),\n\t\t\t\tleft: bounds.left - containerRect.left + (boundsOffset.left ?? 0),\n\t\t\t\twidth: bounds.width + (boundsOffset.width ?? 0),\n\t\t\t\theight: bounds.height + (boundsOffset.height ?? 0),\n\t\t\t};\n\n\t\t\tsetBoundsState((prev) => {\n\t\t\t\tif (\n\t\t\t\t\tprev &&\n\t\t\t\t\tprev.top === newBounds.top &&\n\t\t\t\t\tprev.left === newBounds.left &&\n\t\t\t\t\tprev.width === newBounds.width &&\n\t\t\t\t\tprev.height === newBounds.height\n\t\t\t\t) {\n\t\t\t\t\treturn prev;\n\t\t\t\t}\n\t\t\t\treturn newBounds;\n\t\t\t});\n\t\t},\n\t\t[props],\n\t);\n\n\tconst clearBounds = React.useCallback(() => {\n\t\tsetBoundsState((prev) => (prev === null ? prev : null));\n\t}, []);\n\n\tReact.useEffect(() => {\n\t\tif (value !== undefined) setActiveValue(value);\n\t\telse if (defaultValue !== undefined) setActiveValue(defaultValue);\n\t}, [value, defaultValue]);\n\n\tconst id = React.useId();\n\n\tReact.useEffect(() => {\n\t\tif (mode !== \"parent\") return;\n\t\tconst container = localRef.current;\n\t\tif (!container) return;\n\n\t\tconst onScroll = () => {\n\t\t\tif (!activeValue) return;\n\t\t\tconst activeEl = container.querySelector(\n\t\t\t\t`[data-value=\"${activeValue}\"][data-highlight=\"true\"]`,\n\t\t\t);\n\t\t\tif (activeEl) safeSetBounds(activeEl.getBoundingClientRect());\n\t\t};\n\n\t\tcontainer.addEventListener(\"scroll\", onScroll, { passive: true });\n\t\treturn () => container.removeEventListener(\"scroll\", onScroll);\n\t}, [mode, activeValue, safeSetBounds]);\n\n\tconst render = React.useCallback(\n\t\t(children) => {\n\t\t\tif (mode === \"parent\") {\n\t\t\t\treturn (\n\t\t\t\t\t<Component\n\t\t\t\t\t\tref={localRef}\n\t\t\t\t\t\tdata-slot=\"motion-highlight-container\"\n\t\t\t\t\t\tstyle={{ position: \"relative\", zIndex: 1 }}\n\t\t\t\t\t\tclassName={props?.containerClassName}\n\t\t\t\t\t>\n\t\t\t\t\t\t<AnimatePresence initial={false} mode=\"wait\">\n\t\t\t\t\t\t\t{boundsState && (\n\t\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\t\tdata-slot=\"motion-highlight\"\n\t\t\t\t\t\t\t\t\tanimate={{\n\t\t\t\t\t\t\t\t\t\ttop: boundsState.top,\n\t\t\t\t\t\t\t\t\t\tleft: boundsState.left,\n\t\t\t\t\t\t\t\t\t\twidth: boundsState.width,\n\t\t\t\t\t\t\t\t\t\theight: boundsState.height,\n\t\t\t\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\tinitial={{\n\t\t\t\t\t\t\t\t\t\ttop: boundsState.top,\n\t\t\t\t\t\t\t\t\t\tleft: boundsState.left,\n\t\t\t\t\t\t\t\t\t\twidth: boundsState.width,\n\t\t\t\t\t\t\t\t\t\theight: boundsState.height,\n\t\t\t\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\t\t\t\t...transition,\n\t\t\t\t\t\t\t\t\t\t\tdelay: (transition?.delay ?? 0) + (exitDelay ?? 0) / 1000,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\ttransition={transition}\n\t\t\t\t\t\t\t\t\tstyle={{ position: \"absolute\", zIndex: 0, ...style }}\n\t\t\t\t\t\t\t\t\tclassName={cn(className, activeClassNameState)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</AnimatePresence>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</Component>\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn children;\n\t\t},\n\t\t[\n\t\t\tmode,\n\t\t\tComponent,\n\t\t\tprops,\n\t\t\tboundsState,\n\t\t\ttransition,\n\t\t\texitDelay,\n\t\t\tstyle,\n\t\t\tclassName,\n\t\t\tactiveClassNameState,\n\t\t],\n\t);\n\n\treturn (\n\t\t<HighlightContext.Provider\n\t\t\tvalue={{\n\t\t\t\tmode,\n\t\t\t\tactiveValue,\n\t\t\t\tsetActiveValue: safeSetActiveValue,\n\t\t\t\tid,\n\t\t\t\thover,\n\t\t\t\tclick,\n\t\t\t\tclassName,\n\t\t\t\tstyle,\n\t\t\t\ttransition,\n\t\t\t\tdisabled,\n\t\t\t\tenabled,\n\t\t\t\texitDelay,\n\t\t\t\tsetBounds: safeSetBounds,\n\t\t\t\tclearBounds,\n\t\t\t\tactiveClassName: activeClassNameState,\n\t\t\t\tsetActiveClassName: setActiveClassNameState,\n\t\t\t\tforceUpdateBounds: props?.forceUpdateBounds,\n\t\t\t}}\n\t\t>\n\t\t\t{enabled\n\t\t\t\t? controlledItems\n\t\t\t\t\t? render(children)\n\t\t\t\t\t: render(\n\t\t\t\t\t\t\tReact.Children.map(children, (child, index) => (\n\t\t\t\t\t\t\t\t<HighlightItem key={index} className={props?.itemsClassName}>\n\t\t\t\t\t\t\t\t\t{child}\n\t\t\t\t\t\t\t\t</HighlightItem>\n\t\t\t\t\t\t\t)),\n\t\t\t\t\t\t)\n\t\t\t\t: children}\n\t\t</HighlightContext.Provider>\n\t);\n}\n\nfunction getNonOverridingDataAttributes(element, dataAttributes) {\n\treturn Object.keys(dataAttributes).reduce((acc, key) => {\n\t\tif (element.props[key] === undefined) {\n\t\t\tacc[key] = dataAttributes[key];\n\t\t}\n\t\treturn acc;\n\t}, {});\n}\n\nfunction HighlightItem({\n\tref,\n\tas,\n\tchildren,\n\tid,\n\tvalue,\n\tclassName,\n\tstyle,\n\ttransition,\n\tdisabled = false,\n\tactiveClassName,\n\texitDelay,\n\tasChild = false,\n\tforceUpdateBounds,\n\t...props\n}) {\n\tconst itemId = React.useId();\n\tconst {\n\t\tactiveValue,\n\t\tsetActiveValue,\n\t\tmode,\n\t\tsetBounds,\n\t\tclearBounds,\n\t\thover,\n\t\tclick,\n\t\tenabled,\n\t\tclassName: contextClassName,\n\t\tstyle: contextStyle,\n\t\ttransition: contextTransition,\n\t\tid: contextId,\n\t\tdisabled: contextDisabled,\n\t\texitDelay: contextExitDelay,\n\t\tforceUpdateBounds: contextForceUpdateBounds,\n\t\tsetActiveClassName,\n\t} = useHighlight();\n\n\tconst Component = as ?? \"div\";\n\tconst element = children;\n\tconst childValue =\n\t\tid ?? value ?? element.props?.[\"data-value\"] ?? element.props?.id ?? itemId;\n\tconst isActive = activeValue === childValue;\n\tconst isDisabled = disabled === undefined ? contextDisabled : disabled;\n\tconst itemTransition = transition ?? contextTransition;\n\n\tconst localRef = React.useRef(null);\n\tReact.useImperativeHandle(ref, () => localRef.current);\n\n\tReact.useEffect(() => {\n\t\tif (mode !== \"parent\") return;\n\t\tlet rafId;\n\t\tlet previousBounds = null;\n\t\tconst shouldUpdateBounds =\n\t\t\tforceUpdateBounds === true ||\n\t\t\t(contextForceUpdateBounds && forceUpdateBounds !== false);\n\n\t\tconst updateBounds = () => {\n\t\t\tif (!localRef.current) return;\n\n\t\t\tconst bounds = localRef.current.getBoundingClientRect();\n\n\t\t\tif (shouldUpdateBounds) {\n\t\t\t\tif (\n\t\t\t\t\tpreviousBounds &&\n\t\t\t\t\tpreviousBounds.top === bounds.top &&\n\t\t\t\t\tpreviousBounds.left === bounds.left &&\n\t\t\t\t\tpreviousBounds.width === bounds.width &&\n\t\t\t\t\tpreviousBounds.height === bounds.height\n\t\t\t\t) {\n\t\t\t\t\trafId = requestAnimationFrame(updateBounds);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tpreviousBounds = bounds;\n\t\t\t\trafId = requestAnimationFrame(updateBounds);\n\t\t\t}\n\n\t\t\tsetBounds(bounds);\n\t\t};\n\n\t\tif (isActive) {\n\t\t\tupdateBounds();\n\t\t\tsetActiveClassName(activeClassName ?? \"\");\n\t\t} else if (!activeValue) clearBounds();\n\n\t\tif (shouldUpdateBounds) return () => cancelAnimationFrame(rafId);\n\t}, [\n\t\tmode,\n\t\tisActive,\n\t\tactiveValue,\n\t\tsetBounds,\n\t\tclearBounds,\n\t\tactiveClassName,\n\t\tsetActiveClassName,\n\t\tforceUpdateBounds,\n\t\tcontextForceUpdateBounds,\n\t]);\n\n\tif (!React.isValidElement(children)) return children;\n\n\tconst dataAttributes = {\n\t\t\"data-active\": isActive ? \"true\" : \"false\",\n\t\t\"aria-selected\": isActive,\n\t\t\"data-disabled\": isDisabled,\n\t\t\"data-value\": childValue,\n\t\t\"data-highlight\": true,\n\t};\n\n\tconst commonHandlers = hover\n\t\t? {\n\t\t\t\tonMouseEnter: (e) => {\n\t\t\t\t\tsetActiveValue(childValue);\n\t\t\t\t\telement.props.onMouseEnter?.(e);\n\t\t\t\t},\n\t\t\t\tonMouseLeave: (e) => {\n\t\t\t\t\tsetActiveValue(null);\n\t\t\t\t\telement.props.onMouseLeave?.(e);\n\t\t\t\t},\n\t\t\t}\n\t\t: click\n\t\t\t? {\n\t\t\t\t\tonClick: (e) => {\n\t\t\t\t\t\tsetActiveValue(childValue);\n\t\t\t\t\t\telement.props.onClick?.(e);\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {};\n\n\tif (asChild) {\n\t\tif (mode === \"children\") {\n\t\t\treturn React.cloneElement(\n\t\t\t\telement,\n\t\t\t\t{\n\t\t\t\t\tkey: childValue,\n\t\t\t\t\tref: localRef,\n\t\t\t\t\tclassName: cn(\"relative\", element.props.className),\n\t\t\t\t\t...getNonOverridingDataAttributes(element, {\n\t\t\t\t\t\t...dataAttributes,\n\t\t\t\t\t\t\"data-slot\": \"motion-highlight-item-container\",\n\t\t\t\t\t}),\n\t\t\t\t\t...commonHandlers,\n\t\t\t\t\t...props,\n\t\t\t\t},\n\t\t\t\t<>\n\t\t\t\t\t<AnimatePresence initial={false} mode=\"wait\">\n\t\t\t\t\t\t{isActive && !isDisabled && (\n\t\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\t\tlayoutId={`transition-background-${contextId}`}\n\t\t\t\t\t\t\t\tdata-slot=\"motion-highlight\"\n\t\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\t\t\tzIndex: 0,\n\t\t\t\t\t\t\t\t\t...contextStyle,\n\t\t\t\t\t\t\t\t\t...style,\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName={cn(contextClassName, activeClassName)}\n\t\t\t\t\t\t\t\ttransition={itemTransition}\n\t\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\t\t\t...itemTransition,\n\t\t\t\t\t\t\t\t\t\tdelay:\n\t\t\t\t\t\t\t\t\t\t\t(itemTransition?.delay ?? 0) +\n\t\t\t\t\t\t\t\t\t\t\t(exitDelay ?? contextExitDelay ?? 0) / 1000,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t{...dataAttributes}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</AnimatePresence>\n\n\t\t\t\t\t<Component\n\t\t\t\t\t\tdata-slot=\"motion-highlight-item\"\n\t\t\t\t\t\tstyle={{ position: \"relative\", zIndex: 1 }}\n\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\t{...dataAttributes}\n\t\t\t\t\t>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</Component>\n\t\t\t\t</>,\n\t\t\t);\n\t\t}\n\n\t\treturn React.cloneElement(element, {\n\t\t\tref: localRef,\n\t\t\t...getNonOverridingDataAttributes(element, {\n\t\t\t\t...dataAttributes,\n\t\t\t\t\"data-slot\": \"motion-highlight-item\",\n\t\t\t}),\n\t\t\t...commonHandlers,\n\t\t});\n\t}\n\n\treturn enabled ? (\n\t\t<Component\n\t\t\tkey={childValue}\n\t\t\tref={localRef}\n\t\t\tdata-slot=\"motion-highlight-item-container\"\n\t\t\tclassName={cn(mode === \"children\" && \"relative\", className)}\n\t\t\t{...dataAttributes}\n\t\t\t{...props}\n\t\t\t{...commonHandlers}\n\t\t>\n\t\t\t{mode === \"children\" && (\n\t\t\t\t<AnimatePresence initial={false} mode=\"wait\">\n\t\t\t\t\t{isActive && !isDisabled && (\n\t\t\t\t\t\t<motion.div\n\t\t\t\t\t\t\tlayoutId={`transition-background-${contextId}`}\n\t\t\t\t\t\t\tdata-slot=\"motion-highlight\"\n\t\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\t\tposition: \"absolute\",\n\t\t\t\t\t\t\t\tzIndex: 0,\n\t\t\t\t\t\t\t\t...contextStyle,\n\t\t\t\t\t\t\t\t...style,\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tclassName={cn(contextClassName, activeClassName)}\n\t\t\t\t\t\t\ttransition={itemTransition}\n\t\t\t\t\t\t\tinitial={{ opacity: 0 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1 }}\n\t\t\t\t\t\t\texit={{\n\t\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\t\t...itemTransition,\n\t\t\t\t\t\t\t\t\tdelay:\n\t\t\t\t\t\t\t\t\t\t(itemTransition?.delay ?? 0) +\n\t\t\t\t\t\t\t\t\t\t(exitDelay ?? contextExitDelay ?? 0) / 1000,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t{...dataAttributes}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</AnimatePresence>\n\t\t\t)}\n\n\t\t\t{React.cloneElement(element, {\n\t\t\t\tstyle: { position: \"relative\", zIndex: 1 },\n\t\t\t\tclassName: element.props.className,\n\t\t\t\t...getNonOverridingDataAttributes(element, {\n\t\t\t\t\t...dataAttributes,\n\t\t\t\t\t\"data-slot\": \"motion-highlight-item\",\n\t\t\t\t}),\n\t\t\t})}\n\t\t</Component>\n\t) : (\n\t\tchildren\n\t);\n}\n\nexport { Highlight, HighlightItem, useHighlight };\n",
      "type": "registry:component",
      "target": "components/optics/helpers/primitives/effects/highlight.jsx"
    }
  ],
  "type": "registry:component"
}