npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@iccandle/reactjs-widget

v0.2.28

Published

React scanner overlay for TradingView Charting Library — ICCandle pattern search, remote theming, and plugin iframe integration.

Downloads

5,379

Readme

@iccandle/reactjs-widget

React overlay for the TradingView Charting Library that adds ICCandle’s pattern scanner, results iframe, pattern tracker, and news/event integration.

The package ships ESM + CommonJS. Component styles are injected at runtime (no separate CSS import).

What it does

WidgetIccandle wraps your chart and renders:

| Surface | Role | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | | Scanner popup | Draggable overlay over the chart. Select a bar window with TradingView’s Date Range tool, then run a scan or subscribe to pattern alerts. | | Results iframe | Side-by-side panel hosting the ICCandle embed app (embed-iccandle-app.iccandle.ai) — search results, similar events, auth, billing. | | Chart sync | Bidirectional postMessage bridge: pattern selection, chart replay, news marks, sign-in tokens, loading state. |

Typical flow:

  1. User draws a Date Range on the chart (or activates the scanner).
  2. Scanner caches the selected candles and opens the results iframe with search parameters.
  3. The embed app returns matches; selecting a pattern redraws the range on the chart. Replay / news flows inject predicted candles via custom indicators.

Install

npm install @iccandle/reactjs-widget
# or
pnpm add @iccandle/reactjs-widget

Prerequisites

  • React 18+react and react-dom are peer dependencies.
  • TradingView Charting Library — obtain under your own license, host the static assets (e.g. /charting_library/), and bootstrap the widget yourself. This package does not ship the charting library.
  • Auth token — API calls (candle cache, pattern tracker) use Bearer auth from localStorage key iccandle_token. The embedded results app sets this via a sign-in-success postMessage after login.

Quick start

import { useEffect, useRef, useState } from "react";
import type {
  ChartingLibraryWidgetOptions,
  IChartingLibraryWidget,
  ResolutionString,
} from "charting_library/charting_library";
import { widget } from "charting_library/charting_library";
import {
  WidgetIccandle,
  withPlayChart,
  getCustomIndicators,
} from "@iccandle/reactjs-widget";

const LIBRARY_PATH = "/charting_library/";

function App() {
  const containerRef = useRef<HTMLDivElement>(null);
  const [chartWidget, setChartWidget] = useState<IChartingLibraryWidget | null>(
    null,
  );

  return (
    <div style={{ height: "100vh", width: "100%" }}>
      <WidgetIccandle chartWidget={chartWidget} theme="light" language="en">
        <ChartHost containerRef={containerRef} onReady={setChartWidget} />
      </WidgetIccandle>
    </div>
  );
}

function ChartHost({
  containerRef,
  chartRefs,
  onReady,
}: {
  containerRef: React.RefObject<HTMLDivElement | null>;
  chartRefs: import("@iccandle/reactjs-widget").WidgetIccandleChartRefs;
  onReady: (w: IChartingLibraryWidget | null) => void;
}) {
  useEffect(() => {
    const el = containerRef.current;
    if (!el) return;

    const options: ChartingLibraryWidgetOptions = {
      container: el,
      library_path: LIBRARY_PATH,
      symbol: "EURUSD",
      interval: "60" as ResolutionString,
      datafeed: withPlayChart(yourDatafeed), // enables chart replay injection
      locale: "en",
      autosize: true,
      drawings_access: {
        type: "black",
        tools: [{ name: "Date Range" }],
      },
      custom_indicators_getter: () => getCustomIndicators("light"),
    };

    const tv = new widget(options);
    onReady(tv);

    return () => {
      try {
        tv.remove();
      } catch {
        /* no-op */
      }
      onReady(null);
    };
  }, [containerRef, chartRefs, onReady]);

  return <div ref={containerRef} style={{ height: "100%", width: "100%" }} />;
}

Use a render-prop children when you need chartRefs for generated-candle studies (replay / predict). A plain React node also works if you do not need those refs.

For a full in-repo reference, see src/tradingview/TradingviewChart.tsx.

Features

Pattern scanner

  • Subscribes to chart readiness, symbol, resolution, and drawing events.
  • Manages a date_range multipoint drawing so the user can adjust the bar window (default window size: 25 bars).
  • On scan: posts candles to https://scan-service.iccandle.ai/cacheCandle, then navigates the results iframe with query params (ws, tk, et, symbol, tf, cid, filters, theme).
  • Optional advanced filters (symbols, top-k, lookback period, probability window) stored in localStorage under search-filter.

Results iframe

  • Loads https://embed-iccandle-app.iccandle.ai/{language}?theme=... by default.
  • After scan / news navigation, the src updates with search or similar-events paths.
  • On iframe load, the parent posts { type: "parent-origin", origin } so Stripe checkout can return to the host domain. If the host URL has ?payment=success, it also posts { type: "payment-success" } so the embed can refresh subscription state.

Pattern tracker

From the scanner popup, users can open a subscription modal to track a custom pattern (name + timeframes + symbols). Requires a valid iccandle_token.

News / economic events

  • Clicking a timescale mark can open an event info modal (currency calendar events; skips holidays / early / sentiment-only marks).
  • “Go to detail” loads similar events in the iframe and draws a vertical line on the chart.
  • Marks can be driven from localStorage keys tv:selected-news-events and tv:clicked-news-event if your datafeed implements getTimescaleMarks (see below).

Chart replay (play candles)

Wrap your datafeed with withPlayChart and register custom indicators via getCustomIndicators so the embed can inject predicted / replay bars without live ticks fighting the playback.

API

Exports

| Name | Kind | Description | | ------------------------------ | --------- | ------------------------------------------------------ | | WidgetIccandle | Component | Chart overlay + results iframe | | WidgetIccandleProps | Type | Props for WidgetIccandle | | WidgetIccandleChartRefs | Type | Refs for highlight bars / generated-candle studies | | WidgetLanguage | Type | Supported locale codes | | withPlayChart | Function | Wraps a TradingView datafeed for replay bar injection | | getCustomIndicators | Function | Returns ICCandle custom indicators (generated candles) | | getGeneratedCandlesMaskColor | Function | Theme-aware mask color for generated candles |

WidgetIccandle props

| Prop | Type | Required | Description | | --------------- | ----------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | | chartWidget | IChartingLibraryWidget \| null | Yes | Live TradingView widget (null until ready). | | children | ReactNode \| ((chartRefs) => ReactNode) | Yes | Chart UI, or render prop receiving WidgetIccandleChartRefs. | | theme | "light" \| "dark" \| "system" | No | Scanner chrome + iframe theme. "system" follows prefers-color-scheme. | | language | WidgetLanguage | No | UI + iframe locale. One of: en, zh, vi, th, ko, ja, mn, ru. Defaults to en. | | onCloseResult | () => void | No | Called when the embed posts close-result. | | iframeLoaded | boolean | No | When false, disables scan / track actions until the results iframe is ready. Defaults to enabled behavior in the scanner. |

IChartingLibraryWidget must be imported from your Charting Library typings — this package does not re-export TradingView types.

withPlayChart(datafeed)

Wraps subscribeBars so ICCandle can push replay bars and optionally block live ticks during playback.

import { withPlayChart } from "@iccandle/reactjs-widget";

datafeed: withPlayChart(myDatafeed),

getCustomIndicators(theme?)

Returns a Promise of TradingView CustomIndicator[] used for generated / predicted candle overlays. Pass "light" or "dark" to match chart theme. Wire it into widget options:

custom_indicators_getter: () => getCustomIndicators("light"),

Auth and storage

| Key | Purpose | | ------------------------- | ------------------------------------------------------------------------------------------------------- | | iccandle_token | Bearer token for scan cache, pattern tracker, and related APIs. Set by the embed via sign-in-success. | | search-filter | Scanner advanced options (symbols, top_k, period, probability). | | tv:selected-news-events | JSON array of news events used as timescale marks. | | tv:clicked-news-event | Last clicked calendar event for mark highlighting. | | tv:latest-symbol | Last chart symbol (used by the demo app / fallbacks). |

postMessage bridge

Messages are accepted only from the results origin (https://embed-iccandle-app.iccandle.ai).

| Direction | Type / action | Effect | | -------------- | ---------------------------------------------------------- | ------------------------------------------------ | | Embed → parent | play-chart | Inject / clear replay candles on the chart | | Embed → parent | loading | Toggle scanner loading UI | | Embed → parent | sign-in-success | Persist iccandle_token from payload.id_token | | Embed → parent | close-result | Clears play state; calls onCloseResult | | Embed → parent | pattern_selected / custom_pattern_selected | Draw date range for the compared pattern | | Embed → parent | clear_pattern_selected / clear_custom_pattern_selected | Remove pattern date range | | Embed → parent | eventClicked | Center chart, draw event line, show mark | | Embed → parent | replay | Start / stop event replay candles | | Embed → parent | back / back-to-similar-events | Clear event line / replay | | Embed → parent | nav-click | Hide scanner on /news; restore otherwise | | Parent → embed | parent-origin | Host origin for Stripe return | | Parent → embed | payment-success | Refresh subscription after checkout |

Optional: timescale marks (news/events)

If your datafeed implements getTimescaleMarks, surface stored events as marks:

getTimescaleMarks: async (symbolInfo, from, to, onResult) => {
  const marks = [];
  try {
    const allNewsEvents = JSON.parse(
      localStorage.getItem("tv:selected-news-events") || "[]",
    );

    allNewsEvents?.forEach(({ id, timestamp, event_name, currency }) => {
      if (!id || !Number.isFinite(timestamp) || timestamp <= 0) return;
      if (marks.some((m) => String(m.id) === String(id))) return;

      marks.push({
        id,
        time: timestamp / 1000,
        color: "green",
        label: event_name.slice(0, 1) || "N",
        tooltip: [event_name],
        ...(currency ? { imageUrl: `/images/symbols/${currency}.svg` } : {}),
        showLabelWhenImageLoaded: true,
      });
    });
  } catch {
    /* ignore */
  }
  onResult(marks);
};

Theming

Scanner UI uses CSS variables on .iccandle-selector-widget:

  • --iccandle-primary
  • --iccandle-primary-gradient-end
  • --iccandle-background
  • --iccandle-border
  • --iccandle-text
  • --iccandle-secondary
  • --iccandle-font

Light and dark defaults live in the bundled stylesheet. The theme prop toggles the .iccandle-dark class and is forwarded to the iframe.

Development (this repo)

| Script | Command | Purpose | | ------------- | --------------------- | ----------------------------------------------- | | Dev demo | pnpm run dev | Vite app with local charting library | | Library build | pnpm run build | Emits dist/ (ESM, CJS, injected CSS, .d.ts) | | Web build | pnpm run build:web | SPA build to dist-web/ | | Deploy web | pnpm run deploy:web | Build + Vercel production deploy | | Lint | pnpm run lint | ESLint | | Preview web | pnpm run preview | Preview the web build |

prepublishOnly runs build before npm publish.

Troubleshooting

| Issue | What to check | | ------------------------------ | ----------------------------------------------------------------------------------------------------------- | | Chart stays blank | library_path must serve TradingView static files; container must be mounted before new widget(...). | | chartWidget is always null | Call setChartWidget after create (or inside onChartReady if required). | | Scan fails / 401 | Ensure the user signed in via the results iframe so iccandle_token is set. | | Date Range tool missing | Enable it in drawings_access (see Quick start). | | Replay bars do not appear | Wrap the datafeed with withPlayChart and register getCustomIndicators. | | Scanner actions disabled | Pass iframeLoaded={true} once the results iframe has loaded, or omit the prop if you do not gate on load. |

License

MIT. TradingView Charting Library is subject to its own license from TradingView.