@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 +91 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/package.json +36 -0
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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|