Button
avenra/liquid-buttonFreeComponent
A liquid glass button.
Install it
npx shadcn@latest add https://docs.avenra.online/r/liquid-button.jsonSource
1'use client';23import React, { useEffect, useRef, forwardRef, useImperativeHandle } from 'react';4import {5 createLiquidButton,6 LiquidButtonEventMap,7 LiquidButtonHandle,8 LiquidButtonOptions,9} from '@avenra/liquid-glass';1011/**12 * Fully type-safe event handler mapping13 */14type LiquidButtonEvents = {15 [K in keyof LiquidButtonEventMap]?: (event: LiquidButtonEventMap[K]) => void;16};1718export interface LiquidButtonProps extends Omit<19 React.ButtonHTMLAttributes<HTMLButtonElement>,20 'onClick'21> {22 label: string;23 options?: LiquidButtonOptions;24 events?: LiquidButtonEvents;25}2627export const LiquidButton = forwardRef<HTMLButtonElement, LiquidButtonProps>(28 ({ label, options, events, ...props }, ref) => {29 const buttonRef = useRef<HTMLButtonElement>(null);30 const handleRef = useRef<LiquidButtonHandle | null>(null);3132 useImperativeHandle(ref, () => buttonRef.current as HTMLButtonElement);3334 /**35 * Initialize + cleanup lifecycle36 */37 useEffect(() => {38 if (!buttonRef.current) return;3940 handleRef.current = createLiquidButton(buttonRef.current, {41 label,42 ...options,43 });4445 return () => {46 handleRef.current?.destroy();47 handleRef.current = null;48 };49 }, []);5051 /**52 * Sync label updates53 */54 useEffect(() => {55 handleRef.current?.setLabel(label);56 }, [label]);5758 /**59 * Strictly typed event binding (no unsafe iteration tricks)60 */61 useEffect(() => {62 if (!handleRef.current || !events) return;63 (Object.keys(events) as (keyof LiquidButtonEventMap)[]).forEach((event) => {64 const handler = events[event];6566 if (handler) {67 handleRef.current?.on(event, handler as (e: LiquidButtonEventMap[typeof event]) => void);68 }69 });7071 return () => {72 if (!handleRef.current || !events) return;73 (Object.keys(events) as (keyof LiquidButtonEventMap)[]).forEach((event) => {74 handleRef.current?.off?.(event);75 });76 };77 }, [events]);7879 return <button ref={buttonRef} {...props} />;80 },81);8283LiquidButton.displayName = 'LiquidButton';
