diff --git a/.eslintrc.js b/.eslintrc.js
index 61ceceb2a..013e3b0b5 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -174,6 +174,16 @@ module.exports = {
'react/prop-types': 'off',
},
},
+ {
+ files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
+ globals: {
+ CHART_BACKGROUND_COLOR: true,
+ LINE_LINE_COLOR: true,
+ CHART_TEXT_COLOR: true,
+ AREA_TOP_COLOR: true,
+ AREA_BOTTOM_COLOR: true,
+ },
+ },
{
files: ['**/*.ts', '**/*.tsx'],
excludedFiles: ['dist/**'],
diff --git a/package.json b/package.json
index 4fd7d9640..65552d8cc 100644
--- a/package.json
+++ b/package.json
@@ -59,7 +59,7 @@
"eslint-plugin-mdx": "~1.16.0",
"eslint-plugin-prefer-arrow": "~1.2.1",
"eslint-plugin-tsdoc": "~0.2.14",
- "eslint-plugin-unicorn": "~41.0.0",
+ "eslint-plugin-unicorn": "~40.1.0",
"eslint-plugin-react": "~7.28.0",
"express": "~4.17.2",
"glob": "~7.2.0",
@@ -92,7 +92,7 @@
"bundle-dts": "tsc --noEmit --allowJs dts-config.js && dts-bundle-generator --config dts-config.js",
"tsc": "ttsc -p tsconfig.prod.json",
"tsc-watch": "npm run tsc -- --watch --preserveWatchOutput",
- "tsc-verify": "tsc -b tsconfig.composite.json",
+ "tsc-verify": "node website/scripts/generate-versions-dts.js && tsc -b tsconfig.composite.json",
"lint": "npm-run-all -p lint:**",
"lint:eslint": "eslint --format=unix ./",
"lint:md": "markdownlint -i \"**/node_modules/**\" -i \"**/website/docs/api/**\" -i \"**/website/versioned_docs/**/api/**\" \"**/*.md\"",
diff --git a/tsconfig.composite.json b/tsconfig.composite.json
index b8ca06f9d..5f3b32416 100644
--- a/tsconfig.composite.json
+++ b/tsconfig.composite.json
@@ -2,6 +2,7 @@
"references": [
{ "path": "./src/tsconfig.composite.json" },
{ "path": "./tests/tsconfig.composite.json" },
+ { "path": "./website/tsconfig.json" },
],
"include": []
}
diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index dfa497416..44e7d3435 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -334,13 +334,6 @@ async function getConfig() {
],
...versions.map(typedocPluginForVersion),
'./plugins/enhanced-codeblock',
- [
- './plugins/generate-versions-json-dts',
- {
- versionsJsonPath: path.resolve('./versions.json'),
- versionsDtsOutputPath: path.resolve('./versions.d.ts'),
- },
- ],
],
};
diff --git a/website/package.json b/website/package.json
index 520de5a3e..6c7a83d73 100644
--- a/website/package.json
+++ b/website/package.json
@@ -3,7 +3,7 @@
"scripts": {
"docusaurus": "docusaurus",
"start": "cross-env TYPEDOC_WATCH=true docusaurus start",
- "build": "docusaurus build",
+ "build": "node scripts/generate-versions-dts.js && docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
diff --git a/website/plugins/enhanced-codeblock/theme/CodeBlock/chart.jsx b/website/plugins/enhanced-codeblock/theme/CodeBlock/chart.jsx
deleted file mode 100644
index 8b850ef30..000000000
--- a/website/plugins/enhanced-codeblock/theme/CodeBlock/chart.jsx
+++ /dev/null
@@ -1,101 +0,0 @@
-import * as React from 'react';
-import { useDocsVersion } from '@docusaurus/theme-common';
-
-import { importLightweightChartsVersion } from './import-lightweight-charts-version';
-import styles from './styles.module.css';
-
-function getSrcDocWithScript(script, parentOrigin) {
- return `
-
-
-
- `;
-}
-
-export const Chart = props => {
- const { script } = props;
- const { origin } = window;
- const { version } = useDocsVersion();
- const srcDoc = getSrcDocWithScript(script, origin);
- const ref = React.useRef();
-
- /**
- * iOS Safari seems to run scripts within the iframe in a different order
- * compared to desktop Chrome, Safari, etc.
- *
- * On the desktop browsers the React effect will run first, so the 'ready'
- * event listener is added before the iframe script calls postMessage.
- *
- * On iOS Safari the iframe script runs before the React effect, so the
- * 'ready' event listener hasn't been added yet!
- *
- * We use the __READY_TO_RUN flag to handle this case. If __READY_TO_RUN
- * is true then we know that the inner window's run function can be
- * called immediately and we don't need to register a event listener.
- */
- React.useEffect(() => {
- const lightweightChartsImportPromise = importLightweightChartsVersion(version);
- const injectCreateChartAndRun = contentWindow => {
- lightweightChartsImportPromise.then(mod => {
- const createChart = mod.createChart;
-
- contentWindow.createChart = (container, options) => {
- const chart = createChart(container, options);
- const resizeListener = () => {
- const boundingClientRect = container.getBoundingClientRect();
- chart.resize(boundingClientRect.width, boundingClientRect.height);
- };
-
- contentWindow.addEventListener('resize', resizeListener, true);
-
- return chart;
- };
-
- contentWindow.run();
- });
- };
-
- if (ref.current.contentWindow.__READY_TO_RUN) {
- injectCreateChartAndRun(ref.current.contentWindow);
- return;
- }
-
- const readyMessageListener = event => {
- if (event.origin !== origin || event.source !== ref.current.contentWindow) {
- return;
- }
-
- if (event.data === 'ready') {
- injectCreateChartAndRun(event.source);
- window.removeEventListener('message', readyMessageListener, false);
- }
- };
-
- window.addEventListener('message', readyMessageListener, false);
- }, [origin, srcDoc]);
-
- return (
-
- );
-};
diff --git a/website/plugins/enhanced-codeblock/theme/CodeBlock/chart.tsx b/website/plugins/enhanced-codeblock/theme/CodeBlock/chart.tsx
new file mode 100644
index 000000000..23da83e2b
--- /dev/null
+++ b/website/plugins/enhanced-codeblock/theme/CodeBlock/chart.tsx
@@ -0,0 +1,102 @@
+import { useDocsVersion } from '@docusaurus/theme-common';
+import * as React from 'react';
+
+import { importLightweightChartsVersion, LightweightChartsApi } from './import-lightweight-charts-version';
+import styles from './styles.module.css';
+
+interface ChartProps {
+ script: string;
+}
+
+type IFrameWindow = Window & {
+ createChart: undefined | ((container: HTMLElement, options: never) => void);
+ run: undefined | (() => void);
+};
+
+function getSrcDocWithScript(script: string, parentOrigin: string): string {
+ return `
+
+
+
+ `;
+}
+
+export const Chart = (props: ChartProps): JSX.Element => {
+ const { script } = props;
+ const { origin } = window;
+ const { version } = useDocsVersion();
+ const srcDoc = getSrcDocWithScript(script, origin);
+ const ref = React.useRef(null);
+
+ React.useEffect(
+ () => {
+ const iframeElement = ref.current;
+ const iframeWindow = iframeElement?.contentWindow as IFrameWindow;
+ const iframeDocument = iframeElement?.contentDocument;
+
+ if (iframeElement === null || !iframeWindow || !iframeDocument) {
+ return;
+ }
+
+ const injectCreateChartAndRun = () => {
+ importLightweightChartsVersion(version).then((mod: LightweightChartsApi) => {
+ const createChart = mod.createChart;
+
+ iframeWindow.createChart = (container: HTMLElement, options: never) => {
+ const chart = createChart(container, options);
+ const resizeListener = () => {
+ const boundingClientRect = container.getBoundingClientRect();
+ chart.resize(boundingClientRect.width, boundingClientRect.height);
+ };
+
+ iframeWindow.addEventListener('resize', resizeListener, true);
+
+ return chart;
+ };
+
+ if (iframeWindow.run !== undefined) {
+ iframeWindow.run();
+ }
+ })
+ .catch((err: unknown) => {
+ // eslint-disable-next-line no-console
+ console.error(err);
+ });
+ };
+
+ if (iframeDocument.readyState === 'complete' && iframeWindow.run !== undefined) {
+ injectCreateChartAndRun();
+ } else {
+ const iframeLoadListener = () => {
+ injectCreateChartAndRun();
+ iframeElement.removeEventListener('load', iframeLoadListener);
+ };
+
+ iframeElement.addEventListener('load', iframeLoadListener);
+ }
+ },
+ [origin, srcDoc]
+ );
+
+ return (
+
+ );
+};
diff --git a/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts b/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts
index 2bab1dcb0..ab60f6be9 100644
--- a/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts
+++ b/website/plugins/enhanced-codeblock/theme/CodeBlock/import-lightweight-charts-version.ts
@@ -1,20 +1,14 @@
import type { Version } from '../../../../versions';
-interface VersionAgnosticIChartApi {
- resize: (width: number, height: number) => void;
-}
+export type LightweightChartsApi = typeof import('lightweight-charts-local') | typeof import('lightweight-charts-3.8');
-interface VersionAgnosticLightweightChartsModule {
- createChart: (container: HTMLElement, options: unknown) => VersionAgnosticIChartApi;
-}
-
-export function importLightweightChartsVersion(version: string): Promise {
+export function importLightweightChartsVersion(version: string): Promise {
switch (version as Version | 'current') {
case 'current': {
- return import('lightweight-charts-local') as Promise;
+ return import('lightweight-charts-local');
}
case '3.8': {
- return import('lightweight-charts-3.8') as Promise;
+ return import('lightweight-charts-3.8');
}
}
}
diff --git a/website/plugins/generate-versions-json-dts/index.js b/website/plugins/generate-versions-json-dts/index.js
deleted file mode 100644
index 701bc8586..000000000
--- a/website/plugins/generate-versions-json-dts/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-const { readFile, writeFile } = require('fs/promises');
-
-function getDtsContent(versions) {
- return `declare type Version = ${versions.map(x => `'${x}'`).join(' | ')};
-declare const versions: Version[];
-export type { Version };
-// eslint-disable-next-line import/no-default-export
-export default versions;
-`;
-}
-
-module.exports = function generateVersionsJsonDts(context, options) {
- return {
- name: 'generate-versions-json-dts',
- async loadContent() {
- const file = await readFile(options.versionsJsonPath, 'utf-8');
- const versions = JSON.parse(file);
- const dtsContent = getDtsContent(versions);
- await writeFile(options.versionsDtsOutputPath, dtsContent);
- },
- };
-};
diff --git a/website/scripts/generate-versions-dts.js b/website/scripts/generate-versions-dts.js
new file mode 100644
index 000000000..79e805b7f
--- /dev/null
+++ b/website/scripts/generate-versions-dts.js
@@ -0,0 +1,27 @@
+const { readFile, writeFile } = require('fs/promises');
+const { resolve } = require('path');
+
+function getDtsContent(versions) {
+ return `declare type Version = ${versions.map(x => `'${x}'`).join(' | ')};
+declare const versions: Version[];
+export type { Version };
+// eslint-disable-next-line import/no-default-export
+export default versions;
+`;
+}
+
+const versionsJsonPath = resolve(__dirname, '../versions.json');
+const versionsDtsOutputPath = resolve(__dirname, '../versions.d.ts');
+
+async function generateVersionsJsonDts() {
+ const file = await readFile(versionsJsonPath, 'utf-8');
+ const versions = JSON.parse(file);
+ const dtsContent = getDtsContent(versions);
+ await writeFile(versionsDtsOutputPath, dtsContent);
+}
+
+generateVersionsJsonDts()
+ .catch(err => {
+ // eslint-disable-next-line no-console
+ console.error(err);
+ });
diff --git a/website/src/components/tutorials/.eslintrc.js b/website/src/components/tutorials/.eslintrc.js
deleted file mode 100644
index 232c0748a..000000000
--- a/website/src/components/tutorials/.eslintrc.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = {
- globals: {
- CHART_BACKGROUND_COLOR: true,
- LINE_LINE_COLOR: true,
- CHART_TEXT_COLOR: true,
- AREA_TOP_COLOR: true,
- AREA_BOTTOM_COLOR: true,
- },
-};
diff --git a/website/src/components/tutorials/simple-react-example.jsx b/website/src/components/tutorials/simple-react-example.jsx
index f4208ff18..f13ebd9a1 100644
--- a/website/src/components/tutorials/simple-react-example.jsx
+++ b/website/src/components/tutorials/simple-react-example.jsx
@@ -30,11 +30,7 @@ export const ChartComponent = props => {
});
chart.timeScale().fitContent();
- const newSeries = chart.addAreaSeries({
- lineColor,
- topColor: areaTopColor,
- bottomColor: areaBottomColor,
- });
+ const newSeries = chart.addAreaSeries();
newSeries.setData(data);
window.addEventListener('resize', handleResize);
@@ -45,7 +41,7 @@ export const ChartComponent = props => {
chart.remove();
};
},
- [data, backgroundColor, lineColor, textColor]
+ [data, backgroundColor, lineColor, textColor, areaTopColor, areaBottomColor]
);
return (
diff --git a/website/src/components/tutorials/themed-chart-colors-wrapper.tsx b/website/src/components/tutorials/themed-chart-colors-wrapper.tsx
index 8668eff6a..a004c8d39 100644
--- a/website/src/components/tutorials/themed-chart-colors-wrapper.tsx
+++ b/website/src/components/tutorials/themed-chart-colors-wrapper.tsx
@@ -16,21 +16,15 @@ export interface ThemedChartProps {
}
function getThemeColors(isDarkTheme: boolean): ThemedChartColors {
- return isDarkTheme
- ? {
- backgroundColor: themeColors.DARK.CHART_BACKGROUND_COLOR,
- lineColor: themeColors.DARK.LINE_LINE_COLOR,
- textColor: themeColors.DARK.CHART_TEXT_COLOR,
- areaTopColor: themeColors.DARK.AREA_TOP_COLOR,
- areaBottomColor: themeColors.DARK.AREA_BOTTOM_COLOR,
- }
- : {
- backgroundColor: themeColors.LIGHT.CHART_BACKGROUND_COLOR,
- lineColor: themeColors.LIGHT.LINE_LINE_COLOR,
- textColor: themeColors.LIGHT.CHART_TEXT_COLOR,
- areaTopColor: themeColors.LIGHT.AREA_TOP_COLOR,
- areaBottomColor: themeColors.LIGHT.AREA_BOTTOM_COLOR,
- };
+ const themeKey = isDarkTheme ? 'DARK' : 'LIGHT';
+
+ return {
+ backgroundColor: themeColors[themeKey].CHART_BACKGROUND_COLOR,
+ lineColor: themeColors[themeKey].LINE_LINE_COLOR,
+ textColor: themeColors[themeKey].CHART_TEXT_COLOR,
+ areaTopColor: themeColors[themeKey].AREA_TOP_COLOR,
+ areaBottomColor: themeColors[themeKey].AREA_BOTTOM_COLOR,
+ };
}
export function useThemedChartColors(): ThemedChartColors {
diff --git a/website/theme-colors.js b/website/theme-colors.js
index 21507e922..34ae68b2b 100644
--- a/website/theme-colors.js
+++ b/website/theme-colors.js
@@ -1,5 +1,5 @@
const greenWithAlpha = alpha => `rgba(15, 216, 62, ${alpha})`;
-const redWithAlpha = alpha => `rgb(255, 64, 64, ${alpha})`;
+const redWithAlpha = alpha => `rgba(255, 64, 64, ${alpha})`;
const blueWithAlpha = alpha => `rgba(41, 98, 255, ${alpha})`;
export const themeColors = {
diff --git a/website/tsconfig.json b/website/tsconfig.json
index 08186aaf2..1415ae231 100644
--- a/website/tsconfig.json
+++ b/website/tsconfig.json
@@ -3,7 +3,6 @@
"compilerOptions": {
"strict": true,
"resolveJsonModule": true,
- "noEmit": true
},
"include": [
"./**/*.ts",
diff --git a/website/tutorials/react/01-simple.mdx b/website/tutorials/react/01-simple.mdx
index a7b38b09e..3e817938a 100644
--- a/website/tutorials/react/01-simple.mdx
+++ b/website/tutorials/react/01-simple.mdx
@@ -37,6 +37,11 @@ This will create a web page accessible by default on .
The example _React component_ on this page may not fit your requirements completely. Creating a general purpose declarative wrapper for Lightweight Charts' imperative API is a challenge, but hopefully you can adapt this example to your use case.
+:::info
+
+For this example we are using props to set chart colors based on the current theme (light or dark). In your real code it might be a better idea to use a [Context](https://reactjs.org/docs/context.html#when-to-use-context).
+:::
+
import { ThemedChart } from '@site/src/components/tutorials/themed-chart-colors-wrapper';
import CodeBlock from '@theme/CodeBlock';
import code from '!!raw-loader!@site/src/components/tutorials/simple-react-example';
diff --git a/website/tutorials/react/02-advanced.mdx b/website/tutorials/react/02-advanced.mdx
index 7e5e85b61..9c1eecfc5 100644
--- a/website/tutorials/react/02-advanced.mdx
+++ b/website/tutorials/react/02-advanced.mdx
@@ -212,6 +212,11 @@ ChildComponent.displayName = 'ChildComponent';
By considering all the above you could end up with Chart/Series components looking like the following
+:::info
+
+For this example we are using props to set chart colors based on the current theme (light or dark). In your real code it might be a better idea to use a [Context](https://reactjs.org/docs/context.html#when-to-use-context).
+:::
+
import { ThemedChart } from '@site/src/components/tutorials/themed-chart-colors-wrapper';
import CodeBlock from '@theme/CodeBlock';
import code from '!!raw-loader!@site/src/components/tutorials/advanced-react-example';