React Broadcast Channel Demo ✨

This is a demo page for the @nayaabh/react-broadcast-channel library. Open this page in multiple tabs or windows to see how messages are broadcasted between them.

How It Works
Steps to use the demo:
  1. Pop out this window in a new tab.
  2. Enter a message and choose a color for the message.
  3. Click on the "Publish" button to broadcast the message.
  4. The message will be displayed in all open windows or tabs, based on the color selected.
See @nayaabh/react-broadcast-channel demo in action
See @nayaabh/react-broadcast-channel demo in action
Code

Sample code for above example

demo-code.tsx
"use client";

import { useBroadcastState } from "@nayaabh/react-broadcast-channel";
import { useCallback, useEffect, useState } from "react";
import { FixedSizeList, ListChildComponentProps } from "react-window";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";

const CHANNEL_NAME = "BroadcastChannel-001";

type MessageType = {
  message: string;
  color: string;
  timeStamp: string;
};

export const BroadcastSandbox = () => {
  const [message, setMessage] = useBroadcastState<MessageType>(CHANNEL_NAME);
  const [logs, setLogs] = useState<MessageType[]>([]);

  const onPublish = useCallback((e: any) => {
    e.preventDefault();
    const data = new FormData(e.target);
    const text = data.get("message") as string;
    const color = data.get("color") as string;
    const dateTime = getTimestamp();
    setMessage({ message: text, color, timeStamp: dateTime });
  }, [setMessage]);

  useEffect(() => {
    if (message) {
      setLogs((logs) => [message, ...logs]);
    }
  }, [message]);

  return (
    <div className="space-y-6">
      <form onSubmit={onPublish} className="flex flex-col sm:flex-row gap-3">
        <Input
          name="message"
          placeholder="Enter a message"
          maxLength={100}
          className="flex-1"
        />
        <div className="flex items-center gap-2">
          <input
            type="color"
            name="color"
            defaultValue="#6b7280"
            className="w-10 h-10 p-0 border-none bg-transparent cursor-pointer rounded-md overflow-hidden"
          />
          <Button type="submit">
            Publish
          </Button>
        </div>
      </form>
      
      <div className="w-full border rounded-md bg-muted/20 overflow-hidden shadow-sm">
        <FixedSizeList 
          height={200} 
          width="100%" 
          itemSize={36} 
          itemCount={logs.length} 
          overscanCount={5}
        >
          {(props: ListChildComponentProps) => {
            const { index, style } = props;
            const { message, timeStamp, color } = logs[index] || {};
            const log = `${timeStamp} - ${message}`;
            
            return (
              <div
                key={index}
                style={style}
                className="px-4 py-2 border-b last:border-0 border-border/40 flex items-center text-xs font-mono"
              >
                <span style={{ color }} className="truncate">
                  {log}
                </span>
              </div>
            );
          }}
        </FixedSizeList>
      </div>
    </div>
  );
};

function getTimestamp() {
  const date = new Date();
  const year = date.getFullYear();
  const month = `${date.getMonth() + 1}`.padStart(2, "0");
  const day = `${date.getDate()}`.padStart(2, "0");
  const hour = `${date.getHours()}`.padStart(2, "0");
  const minute = `${date.getMinutes()}`.padStart(2, "0");
  const second = `${date.getSeconds()}`.padStart(2, "0");
  const millisecond = `${date.getMilliseconds()}`.padStart(2, "0");
  return `${year}-${month}-${day} ${hour}:${minute}:${second}.${millisecond}`;
}