Engagement Bar
ilinxa/engagement-barFreeBlock
Social action row — like, comment, share, bookmark, custom actions, and a multi-reaction picker with realtime counts and burst animation.
Install it
npx shadcn@latest add https://ui.ilinxa.com/r/engagement-bar.jsonSource
1"use client";23import { memo, useEffect, useImperativeHandle, useMemo, useRef } from "react";4import { cn } from "@/lib/utils";5import {6 DEFAULT_ENGAGEMENT_BAR_LABELS,7 type EngagementAction,8 type EngagementActionAlign,9 type EngagementBarHandle,10 type EngagementBarProps,11 type EngagementBarLabels,12 type EngagementState,13} from "./types";14import { ActionButton } from "./parts/action-button";15import {16 deriveStateFromActions,17 useEngagementState,18} from "./hooks/use-engagement-state";19import { formatEngagementCount } from "./lib/format-count";2021interface EngagementBarInnerProps extends EngagementBarProps {22 ref?: React.Ref<EngagementBarHandle>;23}2425function defaultAlignFor(kind: EngagementAction["kind"]): EngagementActionAlign {26 return kind === "bookmark" || kind === "view-count" ? "right" : "left";27}2829function actionKey(action: EngagementAction, index: number): string {30 if (action.kind === "custom") return `custom-${action.id}`;31 return `${action.kind}-${index}`;32}3334function EngagementBarInner({35 actions,36 variant = "default",37 subscribe,38 onSubscribeDelta,39 likersPreview,40 reactionsPreview,41 labels: labelsProp,42 className,43 actionClassName,44 ref,45}: EngagementBarInnerProps) {46 const { state, dispatch, controlled } = useEngagementState({47 actions,48 subscribe,49 onSubscribeDelta,50 });5152 const labels = useMemo<Required<Omit<EngagementBarLabels, "formatCount">>>(53 () => ({ ...DEFAULT_ENGAGEMENT_BAR_LABELS, ...labelsProp }),54 [labelsProp],55 );5657 const format = useMemo<(n: number) => string>(58 () => labelsProp?.formatCount ?? formatEngagementCount,59 [labelsProp?.formatCount],60 );6162 // Stable handle identity — refs mirror state + actions via passive effect63 // (refs must not be written during render).64 const stateRef = useRef<EngagementState>(state);65 const actionsRef = useRef<EngagementAction[]>(actions);66 useEffect(() => {67 stateRef.current = state;68 actionsRef.current = actions;69 });7071 useImperativeHandle(72 ref,73 () => ({74 triggerLike: () => {75 const likeAction = actionsRef.current.find((a) => a.kind === "like");76 if (!likeAction || likeAction.kind !== "like") return;77 const next = !stateRef.current.liked;78 if (likeAction.liked === undefined) {79 dispatch({ kind: "like-toggle" });80 }81 likeAction.onToggle?.(next);82 },83 triggerBookmark: () => {84 const bookmarkAction = actionsRef.current.find(85// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from ilinxa
All 184 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Account Switcheraccount-switcher | ilinxa | Blocks | Free | 1 dep · 10 files | |
| Account Switcher (deprecated alias)account-switcher-01 | ilinxa | Blocks | Free | no deps | |
| Account Switcher — fixturesaccount-switcher-fixtures | ilinxa | Blocks | Free | no deps | |
| App Sidebarapp-sidebar | ilinxa | Blocks | Free | 1 dep · 37 files | |
| App Sidebar — fixturesapp-sidebar-fixtures | ilinxa | Blocks | Free | no deps | |
| Rich Text Editor (deprecated alias)article-body-01 | ilinxa | Blocks | Free | no deps | |
| Article Metaarticle-meta | ilinxa | Blocks | Free | 1 dep · 4 files | |
| Article Meta (deprecated alias)article-meta-01 | ilinxa | Blocks | Free | no deps |
