@oanda/labs-order-book-widget 1.0.62 → 1.0.63

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +240 -0
  2. package/dist/main/OrderBookWidget/OrderBookWidget.js +6 -3
  3. package/dist/main/OrderBookWidget/OrderBookWidget.js.map +1 -1
  4. package/dist/main/OrderBookWidget/Widget.js +12 -14
  5. package/dist/main/OrderBookWidget/Widget.js.map +1 -1
  6. package/dist/main/OrderBookWidget/components/Chart/Chart.js +49 -14
  7. package/dist/main/OrderBookWidget/components/Chart/Chart.js.map +1 -1
  8. package/dist/main/OrderBookWidget/components/Chart/constants.js +7 -3
  9. package/dist/main/OrderBookWidget/components/Chart/constants.js.map +1 -1
  10. package/dist/main/OrderBookWidget/components/Chart/formatters.js +14 -0
  11. package/dist/main/OrderBookWidget/components/Chart/formatters.js.map +1 -0
  12. package/dist/main/OrderBookWidget/components/Chart/getOption.js +274 -0
  13. package/dist/main/OrderBookWidget/components/Chart/getOption.js.map +1 -0
  14. package/dist/main/OrderBookWidget/components/Chart/types.js +6 -0
  15. package/dist/main/OrderBookWidget/components/Chart/types.js.map +1 -0
  16. package/dist/main/OrderBookWidget/config.js +15 -0
  17. package/dist/main/OrderBookWidget/config.js.map +1 -0
  18. package/dist/main/OrderBookWidget/render.js +31 -10
  19. package/dist/main/OrderBookWidget/render.js.map +1 -1
  20. package/dist/main/OrderBookWidget/types.js.map +1 -1
  21. package/dist/module/OrderBookWidget/OrderBookWidget.js +7 -4
  22. package/dist/module/OrderBookWidget/OrderBookWidget.js.map +1 -1
  23. package/dist/module/OrderBookWidget/Widget.js +13 -15
  24. package/dist/module/OrderBookWidget/Widget.js.map +1 -1
  25. package/dist/module/OrderBookWidget/components/Chart/Chart.js +47 -14
  26. package/dist/module/OrderBookWidget/components/Chart/Chart.js.map +1 -1
  27. package/dist/module/OrderBookWidget/components/Chart/constants.js +6 -2
  28. package/dist/module/OrderBookWidget/components/Chart/constants.js.map +1 -1
  29. package/dist/module/OrderBookWidget/components/Chart/formatters.js +8 -0
  30. package/dist/module/OrderBookWidget/components/Chart/formatters.js.map +1 -0
  31. package/dist/module/OrderBookWidget/components/Chart/getOption.js +266 -0
  32. package/dist/module/OrderBookWidget/components/Chart/getOption.js.map +1 -0
  33. package/dist/module/OrderBookWidget/components/Chart/types.js +2 -0
  34. package/dist/module/OrderBookWidget/components/Chart/types.js.map +1 -0
  35. package/dist/module/OrderBookWidget/config.js +10 -0
  36. package/dist/module/OrderBookWidget/config.js.map +1 -0
  37. package/dist/module/OrderBookWidget/render.js +31 -10
  38. package/dist/module/OrderBookWidget/render.js.map +1 -1
  39. package/dist/module/OrderBookWidget/types.js.map +1 -1
  40. package/dist/types/OrderBookWidget/OrderBookWidget.d.ts +1 -1
  41. package/dist/types/OrderBookWidget/components/Chart/Chart.d.ts +2 -6
  42. package/dist/types/OrderBookWidget/components/Chart/constants.d.ts +6 -2
  43. package/dist/types/OrderBookWidget/components/Chart/formatters.d.ts +3 -0
  44. package/dist/types/OrderBookWidget/components/Chart/getOption.d.ts +174 -0
  45. package/dist/types/OrderBookWidget/components/Chart/types.d.ts +18 -0
  46. package/dist/types/OrderBookWidget/config.d.ts +6 -0
  47. package/dist/types/OrderBookWidget/render.d.ts +1 -6
  48. package/dist/types/OrderBookWidget/types.d.ts +2 -0
  49. package/package.json +3 -3
  50. package/src/OrderBookWidget/OrderBookWidget.tsx +9 -6
  51. package/src/OrderBookWidget/Widget.tsx +12 -21
  52. package/src/OrderBookWidget/components/Chart/Chart.tsx +56 -18
  53. package/src/OrderBookWidget/components/Chart/constants.ts +7 -2
  54. package/src/OrderBookWidget/components/Chart/formatters.ts +11 -0
  55. package/src/OrderBookWidget/components/Chart/getOption.ts +296 -0
  56. package/src/OrderBookWidget/components/Chart/types.ts +29 -0
  57. package/src/OrderBookWidget/config.ts +11 -0
  58. package/src/OrderBookWidget/render.tsx +36 -18
  59. package/src/OrderBookWidget/types.ts +2 -0
  60. package/dist/main/OrderBookWidget/components/Chart/getOptions.js +0 -322
  61. package/dist/main/OrderBookWidget/components/Chart/getOptions.js.map +0 -1
  62. package/dist/module/OrderBookWidget/components/Chart/getOptions.js +0 -315
  63. package/dist/module/OrderBookWidget/components/Chart/getOptions.js.map +0 -1
  64. package/dist/types/OrderBookWidget/components/Chart/getOptions.d.ts +0 -6
  65. package/src/OrderBookWidget/components/Chart/getOptions.ts +0 -361
@@ -0,0 +1,174 @@
1
+ import { GetOptionType, GetResponsiveOptionsProps } from './types';
2
+ export declare const getDesktopOption: ({ isDark, isOrderBook }: GetResponsiveOptionsProps) => {
3
+ grid: {
4
+ name: string;
5
+ top: string;
6
+ left: string;
7
+ right: string;
8
+ bottom: string;
9
+ }[];
10
+ graphic: ({
11
+ top: number | undefined;
12
+ bottom: number | undefined;
13
+ left: number | undefined;
14
+ right: number | undefined;
15
+ shape: {
16
+ x1: number;
17
+ y1: number;
18
+ x2: number;
19
+ y2: number;
20
+ };
21
+ type: string;
22
+ silent: boolean;
23
+ z: number;
24
+ style: {
25
+ stroke: string;
26
+ lineWidth: number;
27
+ };
28
+ } | {
29
+ top: number;
30
+ shape: {
31
+ x1: number;
32
+ y1: number;
33
+ x2: number;
34
+ y2: number;
35
+ };
36
+ type: string;
37
+ silent: boolean;
38
+ z: number;
39
+ style: {
40
+ stroke: string;
41
+ lineWidth: number;
42
+ };
43
+ } | {
44
+ right: number;
45
+ shape: {
46
+ x1: number;
47
+ y1: number;
48
+ x2: number;
49
+ y2: number;
50
+ };
51
+ type: string;
52
+ silent: boolean;
53
+ z: number;
54
+ style: {
55
+ stroke: string;
56
+ lineWidth: number;
57
+ };
58
+ } | {
59
+ bottom: number;
60
+ shape: {
61
+ x1: number;
62
+ y1: number;
63
+ x2: number;
64
+ y2: number;
65
+ };
66
+ type: string;
67
+ silent: boolean;
68
+ z: number;
69
+ style: {
70
+ stroke: string;
71
+ lineWidth: number;
72
+ };
73
+ } | {
74
+ left: number;
75
+ shape: {
76
+ x1: number;
77
+ y1: number;
78
+ x2: number;
79
+ y2: number;
80
+ };
81
+ type: string;
82
+ silent: boolean;
83
+ z: number;
84
+ style: {
85
+ stroke: string;
86
+ lineWidth: number;
87
+ };
88
+ } | {
89
+ type: string;
90
+ left: string;
91
+ top: string;
92
+ silent: boolean;
93
+ children: ({
94
+ type: string;
95
+ z: number;
96
+ left: string;
97
+ top: string;
98
+ shape: {
99
+ width: number;
100
+ height: number;
101
+ };
102
+ style: {
103
+ fill: string;
104
+ shadowBlur: number;
105
+ shadowOffsetX: number;
106
+ shadowOffsetY: number;
107
+ shadowColor: string;
108
+ width?: undefined;
109
+ height?: undefined;
110
+ text?: undefined;
111
+ };
112
+ } | {
113
+ type: string;
114
+ z: number;
115
+ left: string;
116
+ top: string;
117
+ style: {
118
+ fill: string;
119
+ width: number;
120
+ height: number;
121
+ text: string;
122
+ shadowBlur?: undefined;
123
+ shadowOffsetX?: undefined;
124
+ shadowOffsetY?: undefined;
125
+ shadowColor?: undefined;
126
+ };
127
+ shape?: undefined;
128
+ })[];
129
+ right?: undefined;
130
+ } | {
131
+ type: string;
132
+ right: string;
133
+ top: string;
134
+ silent: boolean;
135
+ children: ({
136
+ type: string;
137
+ z: number;
138
+ right: string;
139
+ top: string;
140
+ shape: {
141
+ width: number;
142
+ height: number;
143
+ };
144
+ style: {
145
+ fill: string;
146
+ shadowBlur: number;
147
+ shadowOffsetX: number;
148
+ shadowOffsetY: number;
149
+ shadowColor: string;
150
+ width?: undefined;
151
+ height?: undefined;
152
+ text?: undefined;
153
+ };
154
+ } | {
155
+ type: string;
156
+ z: number;
157
+ right: string;
158
+ top: string;
159
+ style: {
160
+ fill: string;
161
+ width: number;
162
+ height: number;
163
+ text: string;
164
+ shadowBlur?: undefined;
165
+ shadowOffsetX?: undefined;
166
+ shadowOffsetY?: undefined;
167
+ shadowColor?: undefined;
168
+ };
169
+ shape?: undefined;
170
+ })[];
171
+ left?: undefined;
172
+ })[];
173
+ };
174
+ export declare const getOption: GetOptionType;
@@ -0,0 +1,18 @@
1
+ import { EChartsOption } from 'echarts';
2
+ import { GetOrderPositionBooksQuery } from '../../../gql/types/graphql';
3
+ export interface ChartProps {
4
+ data: GetOrderPositionBooksQuery;
5
+ isOrderBook: boolean;
6
+ }
7
+ export interface GetResponsiveOptionsProps {
8
+ isDark: boolean;
9
+ isOrderBook: boolean;
10
+ }
11
+ export interface GetOptionProps {
12
+ data: GetOrderPositionBooksQuery;
13
+ precision: number;
14
+ isDark: boolean;
15
+ isOrderBook: boolean;
16
+ }
17
+ export type GetOptionType = (props: GetOptionProps) => EChartsOption;
18
+ export type TooltipFormatterType = (data: number[], precision: number, isOrderBook: boolean) => string;
@@ -0,0 +1,6 @@
1
+ import { BookType } from '../gql/types/graphql';
2
+ declare const navigationConfig: {
3
+ id: BookType;
4
+ label: string;
5
+ }[];
6
+ export { navigationConfig };
@@ -1,6 +1 @@
1
- import { OrderBookWrapperConfig } from './types';
2
- declare global {
3
- interface Window {
4
- orderBookWidgetConfig: OrderBookWrapperConfig;
5
- }
6
- }
1
+ export {};
@@ -1,8 +1,10 @@
1
+ import { Theme } from '@oanda/labs-widget-common';
1
2
  import { Locale } from '@oanda/mono-i18n';
2
3
  export interface OrderBookWidgetConfig {
3
4
  graphqlUrl: string;
4
5
  instrument: string;
5
6
  locale: Locale;
7
+ theme?: Theme;
6
8
  }
7
9
  export interface OrderBookWrapperConfig extends OrderBookWidgetConfig {
8
10
  renderElementId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oanda/labs-order-book-widget",
3
- "version": "1.0.62",
3
+ "version": "1.0.63",
4
4
  "description": "Labs Order Book Widget",
5
5
  "main": "dist/main/index.js",
6
6
  "module": "dist/module/index.js",
@@ -13,7 +13,7 @@
13
13
  "license": "UNLICENSED",
14
14
  "dependencies": {
15
15
  "@apollo/client": "3.7.17",
16
- "@oanda/labs-widget-common": "^1.0.62",
16
+ "@oanda/labs-widget-common": "^1.0.63",
17
17
  "@oanda/mono-i18n": "9.0.0",
18
18
  "classnames": "2.3.2",
19
19
  "echarts": "5.4.3",
@@ -25,5 +25,5 @@
25
25
  "@graphql-codegen/client-preset": "4.1.0",
26
26
  "@graphql-codegen/typescript": "4.0.1"
27
27
  },
28
- "gitHead": "0954a60e9c2d28ec2c2d4240fc15fbf132f827d2"
28
+ "gitHead": "f09946395428aaec61ae575a8c762be67e3f05d5"
29
29
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';
3
3
  import { LocaleProvider } from '@oanda/mono-i18n';
4
- import { getLocale } from '@oanda/labs-widget-common';
4
+ import { ThemeProvider, getLocale } from '@oanda/labs-widget-common';
5
5
  import { Widget } from './Widget';
6
6
  import { OrderBookWidgetConfig } from './types';
7
7
  import { translations } from '../translations';
@@ -10,6 +10,7 @@ const OrderBookWidget = ({
10
10
  graphqlUrl,
11
11
  instrument,
12
12
  locale,
13
+ theme,
13
14
  }: OrderBookWidgetConfig) => {
14
15
  const client = new ApolloClient({
15
16
  uri: graphqlUrl,
@@ -17,11 +18,13 @@ const OrderBookWidget = ({
17
18
  });
18
19
 
19
20
  return (
20
- <LocaleProvider locale={getLocale(locale)} translations={translations}>
21
- <ApolloProvider client={client}>
22
- <Widget instrument={instrument} />
23
- </ApolloProvider>
24
- </LocaleProvider>
21
+ <ThemeProvider theme={theme}>
22
+ <LocaleProvider locale={getLocale(locale)} translations={translations}>
23
+ <ApolloProvider client={client}>
24
+ <Widget instrument={instrument} />
25
+ </ApolloProvider>
26
+ </LocaleProvider>
27
+ </ThemeProvider>
25
28
  );
26
29
  };
27
30
 
@@ -1,13 +1,14 @@
1
1
  import React, { useState } from 'react';
2
2
  import { useQuery } from '@apollo/client';
3
3
  import {
4
- Button, ButtonVariant, ChartError, Spinner, SpinnerSize,
4
+ ChartError, Spinner, SpinnerSize, Tabs,
5
5
  } from '@oanda/labs-widget-common';
6
6
  import { useLocale } from '@oanda/mono-i18n';
7
7
  import { WidgetProps } from './types';
8
8
  import { getOrderPositionBooks } from '../gql/getOrderPositionBooks';
9
9
  import { GetOrderPositionBooksQuery, GetOrderPositionBooksQueryVariables, BookType } from '../gql/types/graphql';
10
10
  import { Chart } from './components/Chart/Chart';
11
+ import { navigationConfig } from './config';
11
12
 
12
13
  const Widget = ({
13
14
  instrument,
@@ -28,39 +29,29 @@ const Widget = ({
28
29
 
29
30
  const isError = (!loading && !data) || !!error;
30
31
 
31
- const isTypeOrder = bookType === BookType.Order;
32
-
33
32
  return (
34
33
  <div data-testid="order-book-widget" className="lw-p-4 lw-text-sm lw-tracking-normal lw-text-black">
35
- <div className="lw-flex lw-gap-2">
36
- <Button
37
- variant={isTypeOrder ? ButtonVariant.primary : ButtonVariant.secondary}
38
- onClick={() => setBookType(BookType.Order)}
39
- >
40
- {lang('order_book')}
41
- </Button>
42
- <Button
43
- variant={isTypeOrder ? ButtonVariant.secondary : ButtonVariant.primary}
44
- onClick={() => setBookType(BookType.Position)}
45
- >
46
- {lang('position_book')}
47
- </Button>
48
- </div>
34
+ <Tabs
35
+ activeTab={bookType}
36
+ handleClick={(e) => setBookType(e.currentTarget.value as BookType)}
37
+ labelCallback={lang}
38
+ items={navigationConfig}
39
+ />
49
40
  {/* @todo: chart height */}
50
- <div className="lw-relative lw-h-[700px] lw-w-full">
41
+ <div className="lw-relative lw-h-[450px] lw-w-full">
51
42
  {isError && (
52
- <div className="lw-absolute lw-left-0 lw-top-0 lw-flex lw-h-full lw-w-full lw-items-center lw-justify-center lw-bg-lightGrey/[0.4]">
43
+ <div className="lw-absolute lw-left-0 lw-top-0 lw-flex lw-h-full lw-w-full lw-items-center lw-justify-center lw-border lw-border-solid lw-border-border-primary">
53
44
  <ChartError />
54
45
  </div>
55
46
  )}
56
47
  {loading && (
57
- <div className="lw-absolute lw-left-0 lw-top-0 lw-flex lw-h-full lw-w-full lw-items-center lw-justify-center lw-bg-lightGrey/[0.4]">
48
+ <div className="lw-absolute lw-left-0 lw-top-0 lw-flex lw-h-full lw-w-full lw-items-center lw-justify-center lw-border lw-border-solid lw-border-border-primary">
58
49
  <Spinner size={SpinnerSize.lg} />
59
50
  </div>
60
51
  )}
61
52
  {data && (
62
53
  <div className="lw-absolute lw-left-0 lw-top-0 lw-flex lw-h-full lw-w-full">
63
- <Chart data={data} />
54
+ <Chart data={data} isOrderBook={bookType === BookType.Order} />
64
55
  </div>
65
56
  )}
66
57
  </div>
@@ -1,33 +1,71 @@
1
- import React from 'react';
1
+ import React, { useRef, useEffect, useContext } from 'react';
2
2
  import ReactEcharts from 'echarts-for-react';
3
- import { getOptions } from './getOptions';
4
- import { GetOrderPositionBooksQuery } from '../../../gql/types/graphql';
3
+ import { registerTheme, EChartsType, Color } from 'echarts';
4
+ import {
5
+ Theme, ThemeContext, colorPalette, getChartTheme,
6
+ } from '@oanda/labs-widget-common';
7
+ import { useMediaQuery } from 'usehooks-ts';
8
+ import { getDesktopOption, getOption } from './getOption';
9
+ import { ChartProps } from './types';
5
10
 
6
- interface ChartProps {
7
- data: GetOrderPositionBooksQuery;
8
- }
11
+ registerTheme('dark_theme', getChartTheme(Theme.Dark));
12
+ registerTheme('light_theme', getChartTheme(Theme.Light));
9
13
 
10
- export const Chart = ({ data }: ChartProps) => {
11
- const buckets = data.orderPositionBooks[0]?.buckets || [];
12
- const bucketWidth = data.orderPositionBooks[0]?.bucketWidth;
13
- const price = data.orderPositionBooks[0]?.price;
14
+ export const Chart = ({ data, isOrderBook }: ChartProps) => {
15
+ const isDark = useContext(ThemeContext) === Theme.Dark;
16
+ const echartRef = useRef(null);
17
+ const isDesktop = useMediaQuery('(min-width: 768px)');
14
18
 
15
- const chartData = buckets.map((item) => ([
16
- item!.price,
17
- Number(item!.longCountPercent),
18
- Number(item!.shortCountPercent) * -1,
19
- ]));
19
+ useEffect(() => {
20
+ if (echartRef.current) {
21
+ // @ts-ignore
22
+ const echartInstance = echartRef.current.getEchartsInstance() as EChartsType;
23
+
24
+ echartInstance.on('highlight', () => {
25
+ if ((echartInstance.getOption().color as Color[])[0] === colorPalette.bottleGreenLight) {
26
+ echartInstance.setOption({
27
+ color: [
28
+ colorPalette.bottleGreenLight70,
29
+ isDark ? colorPalette.orange70 : colorPalette.raspberryDark70,
30
+ ],
31
+ });
32
+ }
33
+ });
34
+
35
+ echartInstance.on('globalout', () => {
36
+ echartInstance.setOption({
37
+ color: [
38
+ colorPalette.bottleGreenLight,
39
+ isDark ? colorPalette.orange : colorPalette.raspberryDark,
40
+ ],
41
+ });
42
+ });
43
+ }
44
+ }, [echartRef, isDark]);
45
+
46
+ useEffect(() => {
47
+ if (echartRef.current) {
48
+ // @ts-ignore
49
+ const echartInstance = echartRef.current.getEchartsInstance() as EChartsType;
50
+
51
+ echartInstance.setOption(getDesktopOption({ isDark, isOrderBook }));
52
+ }
53
+ }, [echartRef, isDesktop, isDark, isOrderBook]);
20
54
 
21
55
  return (
22
56
  <div className="lw-relative lw-w-full">
23
57
  <div>
24
- {price && bucketWidth && (
58
+ {data && (
25
59
  <ReactEcharts
60
+ ref={echartRef}
61
+ theme={isDark ? 'dark_theme' : 'light_theme'}
26
62
  style={{
27
- height: '600px',
63
+ height: '450px',
28
64
  width: '100%',
29
65
  }}
30
- option={getOptions({ data: chartData, price, bucketWidth })}
66
+ option={getOption({
67
+ data, precision: 4, isDark, isOrderBook,
68
+ })}
31
69
  />
32
70
  )}
33
71
  </div>
@@ -1,2 +1,7 @@
1
- export const INITIAL_BARS = 150;
2
- export const ZOOM_BARS = 10;
1
+ export const INITIAL_BARS = 80;
2
+
3
+ export const X_LABEL_SIZE = 40;
4
+ export const Y_LABEL_SIZE_MOBILE = 35;
5
+ export const Y_LABEL_SIZE_DESKTOP = 120;
6
+ export const CHART_WIDTH = 9999;
7
+ export const CHART_HEIGHT = 450;
@@ -0,0 +1,11 @@
1
+ import { TooltipFormatterType } from './types';
2
+
3
+ const tooltipFormatter: TooltipFormatterType = (data, precision, isOrderBook) => {
4
+ const priceText = `Price: ${data[0].toFixed(precision)}`;
5
+ const buyText = data[1] ? `<br />${isOrderBook ? 'Buy' : 'Long positions'}: ${data[1]}%` : '';
6
+ const sellText = data[2] ? `<br />${isOrderBook ? 'Sell' : 'Short positions'}: ${data[2] * -1}%` : '';
7
+
8
+ return priceText + buyText + sellText;
9
+ };
10
+
11
+ export { tooltipFormatter };