@mmflow/react 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,91 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var charts = require('@mmflow/charts');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/Chart.tsx
8
+ var Chart = react.forwardRef(function Chart2(props, ref) {
9
+ const containerRef = react.useRef(null);
10
+ const apiRef = react.useRef(null);
11
+ react.useImperativeHandle(
12
+ ref,
13
+ () => ({
14
+ get api() {
15
+ return apiRef.current;
16
+ },
17
+ screenshot: () => apiRef.current?.takeScreenshot() ?? null
18
+ }),
19
+ []
20
+ );
21
+ react.useEffect(() => {
22
+ const container = containerRef.current;
23
+ if (!container) return;
24
+ const api = charts.createChart({
25
+ container,
26
+ theme: props.theme,
27
+ autosize: props.autosize
28
+ });
29
+ apiRef.current = api;
30
+ if (props.candles !== false) api.addCandleSeries();
31
+ if (props.volume) api.addVolumeSeries();
32
+ for (const inst of props.indicators ?? []) api.addIndicator(inst);
33
+ props.onReady?.(api);
34
+ return () => {
35
+ api.dispose();
36
+ apiRef.current = null;
37
+ };
38
+ }, []);
39
+ react.useEffect(() => {
40
+ const api = apiRef.current;
41
+ if (!api || !props.feed) return;
42
+ void api.setData(props.feed, {
43
+ symbol: props.symbol,
44
+ resolution: props.resolution
45
+ });
46
+ }, [props.feed, props.symbol, props.resolution]);
47
+ react.useEffect(() => {
48
+ if (props.theme) apiRef.current?.applyTheme(props.theme);
49
+ }, [props.theme]);
50
+ return /* @__PURE__ */ jsxRuntime.jsx(
51
+ "div",
52
+ {
53
+ ref: containerRef,
54
+ className: props.className,
55
+ style: { width: "100%", height: "100%", ...props.style }
56
+ }
57
+ );
58
+ });
59
+ function useIndicator(factory, overrides) {
60
+ const key = overrides ? JSON.stringify(overrides) : "";
61
+ return react.useMemo(() => factory(overrides), [factory, key]);
62
+ }
63
+
64
+ Object.defineProperty(exports, "composeFeeds", {
65
+ enumerable: true,
66
+ get: function () { return charts.composeFeeds; }
67
+ });
68
+ Object.defineProperty(exports, "createDataFeed", {
69
+ enumerable: true,
70
+ get: function () { return charts.createDataFeed; }
71
+ });
72
+ Object.defineProperty(exports, "defineIndicator", {
73
+ enumerable: true,
74
+ get: function () { return charts.defineIndicator; }
75
+ });
76
+ Object.defineProperty(exports, "defineTheme", {
77
+ enumerable: true,
78
+ get: function () { return charts.defineTheme; }
79
+ });
80
+ Object.defineProperty(exports, "getControls", {
81
+ enumerable: true,
82
+ get: function () { return charts.getControls; }
83
+ });
84
+ Object.defineProperty(exports, "resolveTheme", {
85
+ enumerable: true,
86
+ get: function () { return charts.resolveTheme; }
87
+ });
88
+ exports.Chart = Chart;
89
+ exports.useIndicator = useIndicator;
90
+ //# sourceMappingURL=index.cjs.map
91
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Chart.tsx","../src/useIndicator.ts"],"names":["forwardRef","Chart","useRef","useImperativeHandle","useEffect","createChart","jsx","useMemo"],"mappings":";;;;;;;AAmDO,IAAM,KAAA,GAAQA,gBAAA,CAAoC,SAASC,MAAAA,CAChE,OACA,GAAA,EACA;AACA,EAAA,MAAM,YAAA,GAAeC,aAAuB,IAAI,CAAA;AAChD,EAAA,MAAM,MAAA,GAASA,aAAyB,IAAI,CAAA;AAE5C,EAAAC,yBAAA;AAAA,IACE,GAAA;AAAA,IACA,OAAO;AAAA,MACL,IAAI,GAAA,GAAM;AACR,QAAA,OAAO,MAAA,CAAO,OAAA;AAAA,MAChB,CAAA;AAAA,MACA,UAAA,EAAY,MAAM,MAAA,CAAO,OAAA,EAAS,gBAAe,IAAK;AAAA,KACxD,CAAA;AAAA,IACA;AAAC,GACH;AAKA,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,MAAM,MAAMC,kBAAA,CAAY;AAAA,MACtB,SAAA;AAAA,MACA,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,UAAU,KAAA,CAAM;AAAA,KACjB,CAAA;AACD,IAAA,MAAA,CAAO,OAAA,GAAU,GAAA;AACjB,IAAA,IAAI,KAAA,CAAM,OAAA,KAAY,KAAA,EAAO,GAAA,CAAI,eAAA,EAAgB;AACjD,IAAA,IAAI,KAAA,CAAM,MAAA,EAAQ,GAAA,CAAI,eAAA,EAAgB;AACtC,IAAA,KAAA,MAAW,QAAQ,KAAA,CAAM,UAAA,IAAc,EAAC,EAAG,GAAA,CAAI,aAAa,IAAI,CAAA;AAChE,IAAA,KAAA,CAAM,UAAU,GAAG,CAAA;AACnB,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,CAAI,OAAA,EAAQ;AACZ,MAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AAAA,IACnB,CAAA;AAAA,EAGF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAAD,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,MAAM,MAAA,CAAO,OAAA;AACnB,IAAA,IAAI,CAAC,GAAA,IAAO,CAAC,KAAA,CAAM,IAAA,EAAM;AACzB,IAAA,KAAK,GAAA,CAAI,OAAA,CAAQ,KAAA,CAAM,IAAA,EAAM;AAAA,MAC3B,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,YAAY,KAAA,CAAM;AAAA,KACnB,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAA,CAAM,IAAA,EAAM,MAAM,MAAA,EAAQ,KAAA,CAAM,UAAU,CAAC,CAAA;AAG/C,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAM,KAAA,EAAO,MAAA,CAAO,OAAA,EAAS,UAAA,CAAW,MAAM,KAAK,CAAA;AAAA,EACzD,CAAA,EAAG,CAAC,KAAA,CAAM,KAAK,CAAC,CAAA;AAEhB,EAAA,uBACEE,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,YAAA;AAAA,MACL,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,QAAQ,MAAA,EAAQ,GAAG,MAAM,KAAA;AAAM;AAAA,GACzD;AAEJ,CAAC;ACxGM,SAAS,YAAA,CACd,SACA,SAAA,EACmB;AACnB,EAAA,MAAM,GAAA,GAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,SAAS,CAAA,GAAI,EAAA;AAEpD,EAAA,OAAOC,aAAA,CAAQ,MAAM,OAAA,CAAQ,SAAS,GAAG,CAAC,OAAA,EAAS,GAAG,CAAC,CAAA;AACzD","file":"index.cjs","sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n type CSSProperties,\n} from \"react\";\nimport {\n createChart,\n type IChartApi,\n type DataFeed,\n type IndicatorInstance,\n type ThemeTokens,\n} from \"@mmflow/charts\";\n\nexport interface ChartProps {\n /** Bring-your-own-data feed. When provided with `symbol`, the chart loads\n * history and subscribes to live updates automatically. */\n feed?: DataFeed;\n symbol?: string;\n resolution?: string; // default \"1m\"\n /** White-label theme tokens (hex + font). Applied live on change. */\n theme?: ThemeTokens;\n /** Indicators to mount on first render (overlay or sub-pane is decided by\n * each instance's `overlay` flag). */\n indicators?: IndicatorInstance[];\n /** Add the default candle series (default true). */\n candles?: boolean;\n /** Add a volume sub-pane. */\n volume?: boolean;\n autosize?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Called once the engine is constructed — escape hatch to the imperative\n * API for anything the declarative props don't cover. */\n onReady?: (api: IChartApi) => void;\n}\n\nexport interface ChartHandle {\n /** The live imperative chart API (null before mount / after unmount). */\n api: IChartApi | null;\n screenshot: () => HTMLCanvasElement | null;\n}\n\n/**\n * A declarative, typed React wrapper over the @mmflow/charts engine. The\n * engine is client-only (WebGL); in Next.js App Router, render this in a\n * client component or via `next/dynamic({ ssr: false })`.\n */\nexport const Chart = forwardRef<ChartHandle, ChartProps>(function Chart(\n props,\n ref,\n) {\n const containerRef = useRef<HTMLDivElement>(null);\n const apiRef = useRef<IChartApi | null>(null);\n\n useImperativeHandle(\n ref,\n () => ({\n get api() {\n return apiRef.current;\n },\n screenshot: () => apiRef.current?.takeScreenshot() ?? null,\n }),\n [],\n );\n\n // Construct the engine once on mount; tear it down on unmount. Series and\n // indicators declared at mount time are added here. Strict-mode double\n // invoke is safe — dispose() fully releases the GL context.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const api = createChart({\n container,\n theme: props.theme,\n autosize: props.autosize,\n });\n apiRef.current = api;\n if (props.candles !== false) api.addCandleSeries();\n if (props.volume) api.addVolumeSeries();\n for (const inst of props.indicators ?? []) api.addIndicator(inst);\n props.onReady?.(api);\n return () => {\n api.dispose();\n apiRef.current = null;\n };\n // Intentionally mount-once: live updates flow through the effects below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // (Re)load data whenever the feed/symbol/resolution changes.\n useEffect(() => {\n const api = apiRef.current;\n if (!api || !props.feed) return;\n void api.setData(props.feed, {\n symbol: props.symbol,\n resolution: props.resolution,\n });\n }, [props.feed, props.symbol, props.resolution]);\n\n // Re-skin live.\n useEffect(() => {\n if (props.theme) apiRef.current?.applyTheme(props.theme);\n }, [props.theme]);\n\n return (\n <div\n ref={containerRef}\n className={props.className}\n style={{ width: \"100%\", height: \"100%\", ...props.style }}\n />\n );\n});\n","import { useMemo } from \"react\";\nimport type { IndicatorInstance } from \"@mmflow/charts\";\n\n/**\n * Memoize an indicator instance from a `defineIndicator` factory so it isn't\n * rebuilt on every render. Re-evaluates only when the overrides change.\n *\n * const myVWAP = defineIndicator({ ... });\n * const inst = useIndicator(myVWAP, { period: 20 });\n * <Chart indicators={[inst]} ... />\n */\nexport function useIndicator<O extends Record<string, unknown>>(\n factory: (overrides?: O) => IndicatorInstance,\n overrides?: O,\n): IndicatorInstance {\n const key = overrides ? JSON.stringify(overrides) : \"\";\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => factory(overrides), [factory, key]);\n}\n"]}
@@ -0,0 +1,50 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties } from 'react';
3
+ import { DataFeed, ThemeTokens, IndicatorInstance, IChartApi } from '@mmflow/charts';
4
+ export { Candle, CandleRange, ControlDescriptor, DataFeed, FeedUpdate, IChartApi, IndicatorDefinition, IndicatorInstance, ParamSpec, ThemeTokens, composeFeeds, createDataFeed, defineIndicator, defineTheme, getControls, resolveTheme } from '@mmflow/charts';
5
+
6
+ interface ChartProps {
7
+ /** Bring-your-own-data feed. When provided with `symbol`, the chart loads
8
+ * history and subscribes to live updates automatically. */
9
+ feed?: DataFeed;
10
+ symbol?: string;
11
+ resolution?: string;
12
+ /** White-label theme tokens (hex + font). Applied live on change. */
13
+ theme?: ThemeTokens;
14
+ /** Indicators to mount on first render (overlay or sub-pane is decided by
15
+ * each instance's `overlay` flag). */
16
+ indicators?: IndicatorInstance[];
17
+ /** Add the default candle series (default true). */
18
+ candles?: boolean;
19
+ /** Add a volume sub-pane. */
20
+ volume?: boolean;
21
+ autosize?: boolean;
22
+ className?: string;
23
+ style?: CSSProperties;
24
+ /** Called once the engine is constructed — escape hatch to the imperative
25
+ * API for anything the declarative props don't cover. */
26
+ onReady?: (api: IChartApi) => void;
27
+ }
28
+ interface ChartHandle {
29
+ /** The live imperative chart API (null before mount / after unmount). */
30
+ api: IChartApi | null;
31
+ screenshot: () => HTMLCanvasElement | null;
32
+ }
33
+ /**
34
+ * A declarative, typed React wrapper over the @mmflow/charts engine. The
35
+ * engine is client-only (WebGL); in Next.js App Router, render this in a
36
+ * client component or via `next/dynamic({ ssr: false })`.
37
+ */
38
+ declare const Chart: react.ForwardRefExoticComponent<ChartProps & react.RefAttributes<ChartHandle>>;
39
+
40
+ /**
41
+ * Memoize an indicator instance from a `defineIndicator` factory so it isn't
42
+ * rebuilt on every render. Re-evaluates only when the overrides change.
43
+ *
44
+ * const myVWAP = defineIndicator({ ... });
45
+ * const inst = useIndicator(myVWAP, { period: 20 });
46
+ * <Chart indicators={[inst]} ... />
47
+ */
48
+ declare function useIndicator<O extends Record<string, unknown>>(factory: (overrides?: O) => IndicatorInstance, overrides?: O): IndicatorInstance;
49
+
50
+ export { Chart, type ChartHandle, type ChartProps, useIndicator };
@@ -0,0 +1,50 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties } from 'react';
3
+ import { DataFeed, ThemeTokens, IndicatorInstance, IChartApi } from '@mmflow/charts';
4
+ export { Candle, CandleRange, ControlDescriptor, DataFeed, FeedUpdate, IChartApi, IndicatorDefinition, IndicatorInstance, ParamSpec, ThemeTokens, composeFeeds, createDataFeed, defineIndicator, defineTheme, getControls, resolveTheme } from '@mmflow/charts';
5
+
6
+ interface ChartProps {
7
+ /** Bring-your-own-data feed. When provided with `symbol`, the chart loads
8
+ * history and subscribes to live updates automatically. */
9
+ feed?: DataFeed;
10
+ symbol?: string;
11
+ resolution?: string;
12
+ /** White-label theme tokens (hex + font). Applied live on change. */
13
+ theme?: ThemeTokens;
14
+ /** Indicators to mount on first render (overlay or sub-pane is decided by
15
+ * each instance's `overlay` flag). */
16
+ indicators?: IndicatorInstance[];
17
+ /** Add the default candle series (default true). */
18
+ candles?: boolean;
19
+ /** Add a volume sub-pane. */
20
+ volume?: boolean;
21
+ autosize?: boolean;
22
+ className?: string;
23
+ style?: CSSProperties;
24
+ /** Called once the engine is constructed — escape hatch to the imperative
25
+ * API for anything the declarative props don't cover. */
26
+ onReady?: (api: IChartApi) => void;
27
+ }
28
+ interface ChartHandle {
29
+ /** The live imperative chart API (null before mount / after unmount). */
30
+ api: IChartApi | null;
31
+ screenshot: () => HTMLCanvasElement | null;
32
+ }
33
+ /**
34
+ * A declarative, typed React wrapper over the @mmflow/charts engine. The
35
+ * engine is client-only (WebGL); in Next.js App Router, render this in a
36
+ * client component or via `next/dynamic({ ssr: false })`.
37
+ */
38
+ declare const Chart: react.ForwardRefExoticComponent<ChartProps & react.RefAttributes<ChartHandle>>;
39
+
40
+ /**
41
+ * Memoize an indicator instance from a `defineIndicator` factory so it isn't
42
+ * rebuilt on every render. Re-evaluates only when the overrides change.
43
+ *
44
+ * const myVWAP = defineIndicator({ ... });
45
+ * const inst = useIndicator(myVWAP, { period: 20 });
46
+ * <Chart indicators={[inst]} ... />
47
+ */
48
+ declare function useIndicator<O extends Record<string, unknown>>(factory: (overrides?: O) => IndicatorInstance, overrides?: O): IndicatorInstance;
49
+
50
+ export { Chart, type ChartHandle, type ChartProps, useIndicator };
package/dist/index.js ADDED
@@ -0,0 +1,65 @@
1
+ import { forwardRef, useRef, useImperativeHandle, useEffect, useMemo } from 'react';
2
+ import { createChart } from '@mmflow/charts';
3
+ export { composeFeeds, createDataFeed, defineIndicator, defineTheme, getControls, resolveTheme } from '@mmflow/charts';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/Chart.tsx
7
+ var Chart = forwardRef(function Chart2(props, ref) {
8
+ const containerRef = useRef(null);
9
+ const apiRef = useRef(null);
10
+ useImperativeHandle(
11
+ ref,
12
+ () => ({
13
+ get api() {
14
+ return apiRef.current;
15
+ },
16
+ screenshot: () => apiRef.current?.takeScreenshot() ?? null
17
+ }),
18
+ []
19
+ );
20
+ useEffect(() => {
21
+ const container = containerRef.current;
22
+ if (!container) return;
23
+ const api = createChart({
24
+ container,
25
+ theme: props.theme,
26
+ autosize: props.autosize
27
+ });
28
+ apiRef.current = api;
29
+ if (props.candles !== false) api.addCandleSeries();
30
+ if (props.volume) api.addVolumeSeries();
31
+ for (const inst of props.indicators ?? []) api.addIndicator(inst);
32
+ props.onReady?.(api);
33
+ return () => {
34
+ api.dispose();
35
+ apiRef.current = null;
36
+ };
37
+ }, []);
38
+ useEffect(() => {
39
+ const api = apiRef.current;
40
+ if (!api || !props.feed) return;
41
+ void api.setData(props.feed, {
42
+ symbol: props.symbol,
43
+ resolution: props.resolution
44
+ });
45
+ }, [props.feed, props.symbol, props.resolution]);
46
+ useEffect(() => {
47
+ if (props.theme) apiRef.current?.applyTheme(props.theme);
48
+ }, [props.theme]);
49
+ return /* @__PURE__ */ jsx(
50
+ "div",
51
+ {
52
+ ref: containerRef,
53
+ className: props.className,
54
+ style: { width: "100%", height: "100%", ...props.style }
55
+ }
56
+ );
57
+ });
58
+ function useIndicator(factory, overrides) {
59
+ const key = overrides ? JSON.stringify(overrides) : "";
60
+ return useMemo(() => factory(overrides), [factory, key]);
61
+ }
62
+
63
+ export { Chart, useIndicator };
64
+ //# sourceMappingURL=index.js.map
65
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Chart.tsx","../src/useIndicator.ts"],"names":["Chart"],"mappings":";;;;;;AAmDO,IAAM,KAAA,GAAQ,UAAA,CAAoC,SAASA,MAAAA,CAChE,OACA,GAAA,EACA;AACA,EAAA,MAAM,YAAA,GAAe,OAAuB,IAAI,CAAA;AAChD,EAAA,MAAM,MAAA,GAAS,OAAyB,IAAI,CAAA;AAE5C,EAAA,mBAAA;AAAA,IACE,GAAA;AAAA,IACA,OAAO;AAAA,MACL,IAAI,GAAA,GAAM;AACR,QAAA,OAAO,MAAA,CAAO,OAAA;AAAA,MAChB,CAAA;AAAA,MACA,UAAA,EAAY,MAAM,MAAA,CAAO,OAAA,EAAS,gBAAe,IAAK;AAAA,KACxD,CAAA;AAAA,IACA;AAAC,GACH;AAKA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,YAAY,YAAA,CAAa,OAAA;AAC/B,IAAA,IAAI,CAAC,SAAA,EAAW;AAChB,IAAA,MAAM,MAAM,WAAA,CAAY;AAAA,MACtB,SAAA;AAAA,MACA,OAAO,KAAA,CAAM,KAAA;AAAA,MACb,UAAU,KAAA,CAAM;AAAA,KACjB,CAAA;AACD,IAAA,MAAA,CAAO,OAAA,GAAU,GAAA;AACjB,IAAA,IAAI,KAAA,CAAM,OAAA,KAAY,KAAA,EAAO,GAAA,CAAI,eAAA,EAAgB;AACjD,IAAA,IAAI,KAAA,CAAM,MAAA,EAAQ,GAAA,CAAI,eAAA,EAAgB;AACtC,IAAA,KAAA,MAAW,QAAQ,KAAA,CAAM,UAAA,IAAc,EAAC,EAAG,GAAA,CAAI,aAAa,IAAI,CAAA;AAChE,IAAA,KAAA,CAAM,UAAU,GAAG,CAAA;AACnB,IAAA,OAAO,MAAM;AACX,MAAA,GAAA,CAAI,OAAA,EAAQ;AACZ,MAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AAAA,IACnB,CAAA;AAAA,EAGF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,MAAM,MAAA,CAAO,OAAA;AACnB,IAAA,IAAI,CAAC,GAAA,IAAO,CAAC,KAAA,CAAM,IAAA,EAAM;AACzB,IAAA,KAAK,GAAA,CAAI,OAAA,CAAQ,KAAA,CAAM,IAAA,EAAM;AAAA,MAC3B,QAAQ,KAAA,CAAM,MAAA;AAAA,MACd,YAAY,KAAA,CAAM;AAAA,KACnB,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAA,CAAM,IAAA,EAAM,MAAM,MAAA,EAAQ,KAAA,CAAM,UAAU,CAAC,CAAA;AAG/C,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAM,KAAA,EAAO,MAAA,CAAO,OAAA,EAAS,UAAA,CAAW,MAAM,KAAK,CAAA;AAAA,EACzD,CAAA,EAAG,CAAC,KAAA,CAAM,KAAK,CAAC,CAAA;AAEhB,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,YAAA;AAAA,MACL,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,QAAQ,MAAA,EAAQ,GAAG,MAAM,KAAA;AAAM;AAAA,GACzD;AAEJ,CAAC;ACxGM,SAAS,YAAA,CACd,SACA,SAAA,EACmB;AACnB,EAAA,MAAM,GAAA,GAAM,SAAA,GAAY,IAAA,CAAK,SAAA,CAAU,SAAS,CAAA,GAAI,EAAA;AAEpD,EAAA,OAAO,OAAA,CAAQ,MAAM,OAAA,CAAQ,SAAS,GAAG,CAAC,OAAA,EAAS,GAAG,CAAC,CAAA;AACzD","file":"index.js","sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n type CSSProperties,\n} from \"react\";\nimport {\n createChart,\n type IChartApi,\n type DataFeed,\n type IndicatorInstance,\n type ThemeTokens,\n} from \"@mmflow/charts\";\n\nexport interface ChartProps {\n /** Bring-your-own-data feed. When provided with `symbol`, the chart loads\n * history and subscribes to live updates automatically. */\n feed?: DataFeed;\n symbol?: string;\n resolution?: string; // default \"1m\"\n /** White-label theme tokens (hex + font). Applied live on change. */\n theme?: ThemeTokens;\n /** Indicators to mount on first render (overlay or sub-pane is decided by\n * each instance's `overlay` flag). */\n indicators?: IndicatorInstance[];\n /** Add the default candle series (default true). */\n candles?: boolean;\n /** Add a volume sub-pane. */\n volume?: boolean;\n autosize?: boolean;\n className?: string;\n style?: CSSProperties;\n /** Called once the engine is constructed — escape hatch to the imperative\n * API for anything the declarative props don't cover. */\n onReady?: (api: IChartApi) => void;\n}\n\nexport interface ChartHandle {\n /** The live imperative chart API (null before mount / after unmount). */\n api: IChartApi | null;\n screenshot: () => HTMLCanvasElement | null;\n}\n\n/**\n * A declarative, typed React wrapper over the @mmflow/charts engine. The\n * engine is client-only (WebGL); in Next.js App Router, render this in a\n * client component or via `next/dynamic({ ssr: false })`.\n */\nexport const Chart = forwardRef<ChartHandle, ChartProps>(function Chart(\n props,\n ref,\n) {\n const containerRef = useRef<HTMLDivElement>(null);\n const apiRef = useRef<IChartApi | null>(null);\n\n useImperativeHandle(\n ref,\n () => ({\n get api() {\n return apiRef.current;\n },\n screenshot: () => apiRef.current?.takeScreenshot() ?? null,\n }),\n [],\n );\n\n // Construct the engine once on mount; tear it down on unmount. Series and\n // indicators declared at mount time are added here. Strict-mode double\n // invoke is safe — dispose() fully releases the GL context.\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const api = createChart({\n container,\n theme: props.theme,\n autosize: props.autosize,\n });\n apiRef.current = api;\n if (props.candles !== false) api.addCandleSeries();\n if (props.volume) api.addVolumeSeries();\n for (const inst of props.indicators ?? []) api.addIndicator(inst);\n props.onReady?.(api);\n return () => {\n api.dispose();\n apiRef.current = null;\n };\n // Intentionally mount-once: live updates flow through the effects below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // (Re)load data whenever the feed/symbol/resolution changes.\n useEffect(() => {\n const api = apiRef.current;\n if (!api || !props.feed) return;\n void api.setData(props.feed, {\n symbol: props.symbol,\n resolution: props.resolution,\n });\n }, [props.feed, props.symbol, props.resolution]);\n\n // Re-skin live.\n useEffect(() => {\n if (props.theme) apiRef.current?.applyTheme(props.theme);\n }, [props.theme]);\n\n return (\n <div\n ref={containerRef}\n className={props.className}\n style={{ width: \"100%\", height: \"100%\", ...props.style }}\n />\n );\n});\n","import { useMemo } from \"react\";\nimport type { IndicatorInstance } from \"@mmflow/charts\";\n\n/**\n * Memoize an indicator instance from a `defineIndicator` factory so it isn't\n * rebuilt on every render. Re-evaluates only when the overrides change.\n *\n * const myVWAP = defineIndicator({ ... });\n * const inst = useIndicator(myVWAP, { period: 20 });\n * <Chart indicators={[inst]} ... />\n */\nexport function useIndicator<O extends Record<string, unknown>>(\n factory: (overrides?: O) => IndicatorInstance,\n overrides?: O,\n): IndicatorInstance {\n const key = overrides ? JSON.stringify(overrides) : \"\";\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => factory(overrides), [factory, key]);\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@mmflow/react",
3
+ "version": "0.1.0",
4
+ "description": "React bindings for @mmflow/charts — a typed <Chart/> component with bring-your-own-data feeds, declarative custom indicators, and white-label theming.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.cts",
19
+ "default": "./dist/index.cjs"
20
+ }
21
+ }
22
+ },
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "dependencies": {
27
+ "@mmflow/charts": "0.1.0"
28
+ },
29
+ "peerDependencies": {
30
+ "react": ">=18"
31
+ },
32
+ "scripts": {
33
+ "build": "tsup src/index.ts --format esm,cjs --dts --treeshake --external react --external @mmflow/charts",
34
+ "typecheck": "tsc --noEmit"
35
+ }
36
+ }