@pie-lib/plot 2.24.6-esmbeta.0 → 2.25.0-mui-update.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/src/root.jsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { withStyles } from '@material-ui/core/styles';
2
+ import { styled } from '@mui/material/styles';
3
3
  import PropTypes from 'prop-types';
4
4
  import { select, mouse } from 'd3-selection';
5
5
  import cn from 'classnames';
@@ -11,12 +11,98 @@ import { GraphPropsType } from './types';
11
11
  import Label from './label';
12
12
  import { extractTextFromHTML, isEmptyObject, isEmptyString } from './utils';
13
13
 
14
+ const StyledRoot = styled('div')(({ theme }) => ({
15
+ border: `solid 1px ${color.primaryLight()}`,
16
+ color: color.defaults.TEXT,
17
+ backgroundColor: theme.palette.common.white,
18
+ touchAction: 'none',
19
+ position: 'relative',
20
+ boxSizing: 'unset', // to override the default border-box in IBX that breaks the component width layout
21
+ }));
22
+
23
+ const Wrapper = styled('div')({
24
+ display: 'flex',
25
+ position: 'relative',
26
+ });
27
+
28
+ const DefineChartSvg = styled('svg')({
29
+ paddingLeft: '50px',
30
+ overflow: 'visible',
31
+ });
32
+
33
+ const ChartSvg = styled('svg')({
34
+ overflow: 'visible',
35
+ });
36
+
37
+ const GraphBox = styled('g')({
38
+ cursor: 'pointer',
39
+ userSelect: 'none',
40
+ });
41
+
42
+ const GraphTitle = styled('div')(({ theme }) => ({
43
+ color: color.defaults.TEXT,
44
+ fontSize: theme.typography.fontSize + 2,
45
+ padding: `${theme.spacing(1.5)} ${theme.spacing(0.5)} 0`,
46
+ textAlign: 'center',
47
+ '&.disabled': {
48
+ pointerEvents: 'none',
49
+ },
50
+ '&.rightMargin': {
51
+ marginRight: '74px',
52
+ },
53
+ }));
54
+
55
+ const ChartTitle = styled('div')(({ theme }) => ({
56
+ color: color.defaults.TEXT,
57
+ fontSize: theme.typography.fontSize + 4,
58
+ padding: `${theme.spacing(1.5)} ${theme.spacing(0.5)} 0`,
59
+ textAlign: 'center',
60
+ '&.disabled': {
61
+ pointerEvents: 'none',
62
+ },
63
+ '&.rightMargin': {
64
+ marginRight: '74px',
65
+ },
66
+ }));
67
+
68
+ const TopPixelGuides = styled('div')({
69
+ display: 'flex',
70
+ paddingTop: '6px',
71
+ });
72
+
73
+ const TopPixelIndicator = styled('div')({
74
+ display: 'flex',
75
+ flexDirection: 'column',
76
+ alignItems: 'center',
77
+ width: '100px',
78
+ pointerEvents: 'none',
79
+ userSelect: 'none',
80
+ });
81
+
82
+ const SidePixelGuides = styled('div')({
83
+ width: '70px',
84
+ display: 'flex',
85
+ flexDirection: 'column',
86
+ marginRight: '6px',
87
+ });
88
+
89
+ const SidePixelIndicator = styled('div')({
90
+ textAlign: 'right',
91
+ height: '20px',
92
+ pointerEvents: 'none',
93
+ userSelect: 'none',
94
+ '&:not(:last-child)': {
95
+ marginBottom: '80px',
96
+ },
97
+ });
98
+
14
99
  export class Root extends React.Component {
15
100
  constructor(props) {
16
101
  super(props);
17
102
  this.state = {
18
103
  titleHeight: 0,
19
104
  };
105
+ this.resizeObserver = null;
20
106
  }
21
107
 
22
108
  static propTypes = {
@@ -31,7 +117,6 @@ export class Root extends React.Component {
31
117
  labelsPlaceholders: PropTypes.object,
32
118
  onChangeTitle: PropTypes.func,
33
119
  onMouseMove: PropTypes.func,
34
- classes: PropTypes.object.isRequired,
35
120
  showLabels: PropTypes.bool,
36
121
  showTitle: PropTypes.bool,
37
122
  showPixelGuides: PropTypes.bool,
@@ -66,11 +151,13 @@ export class Root extends React.Component {
66
151
  const g = select(this.g);
67
152
  g.on('mousemove', this.mouseMove.bind(this, g));
68
153
  this.measureTitleHeight();
154
+ this.setupVisibilityObserver();
69
155
  }
70
156
 
71
157
  componentWillUnmount() {
72
158
  const g = select(this.g);
73
159
  g.on('mousemove', null);
160
+ this.cleanupVisibilityObserver();
74
161
  }
75
162
 
76
163
  componentDidUpdate(prevProps) {
@@ -107,11 +194,44 @@ export class Root extends React.Component {
107
194
  if (titleElement) {
108
195
  const titleHeight = titleElement.clientHeight;
109
196
  this.setState({ titleHeight, prevTitle: this.props.title });
197
+
198
+ if (!this.resizeObserver && typeof ResizeObserver !== 'undefined') {
199
+ this.setupVisibilityObserver();
200
+ }
110
201
  }
111
202
  };
112
203
 
113
204
  handleKeyDown = () => {
114
- setTimeout(this.measureTitleHeight, 0);
205
+ setTimeout(() => {
206
+ this.measureTitleHeight();
207
+ }, 0);
208
+ };
209
+
210
+ // handle edge case where chart is hidden with display:none and then shown with display:block
211
+ setupVisibilityObserver = () => {
212
+ if (typeof ResizeObserver !== 'undefined' && this.titleRef) {
213
+ this.resizeObserver = new ResizeObserver((entries) => {
214
+ for (let entry of entries) {
215
+ const { width, height } = entry.contentRect;
216
+ // trigger if element becomes visible and we haven't measured this height yet
217
+ if (width > 0 && height > 0) {
218
+ setTimeout(() => {
219
+ this.measureTitleHeight();
220
+ }, 10);
221
+ break;
222
+ }
223
+ }
224
+ });
225
+
226
+ this.resizeObserver.observe(this.titleRef);
227
+ }
228
+ };
229
+
230
+ cleanupVisibilityObserver = () => {
231
+ if (this.resizeObserver) {
232
+ this.resizeObserver.disconnect();
233
+ this.resizeObserver = null;
234
+ }
115
235
  };
116
236
 
117
237
  render() {
@@ -123,7 +243,6 @@ export class Root extends React.Component {
123
243
  titlePlaceholder,
124
244
  graphProps,
125
245
  children,
126
- classes,
127
246
  defineChart,
128
247
  onChangeTitle,
129
248
  isChart,
@@ -164,19 +283,20 @@ export class Root extends React.Component {
164
283
  const nbOfHorizontalLines = parseInt(actualHeight / 100);
165
284
  const sideGridlinesPadding = parseInt(actualHeight % 100);
166
285
  const { titleHeight } = this.state;
286
+
167
287
  return (
168
- <div className={classes.root}>
288
+ <StyledRoot>
169
289
  {showPixelGuides && (
170
- <div className={classes.topPixelGuides} style={{ marginLeft: isChart ? 80 : showLabels ? 30 : 10 }}>
290
+ <TopPixelGuides style={{ marginLeft: isChart ? 80 : showLabels ? 30 : 10 }}>
171
291
  {[...Array(nbOfVerticalLines + 1).keys()].map((value) => (
172
292
  <Readable false key={`top-guide-${value}`}>
173
- <div className={classes.topPixelIndicator}>
293
+ <TopPixelIndicator>
174
294
  <div>{value * 100}px</div>
175
295
  <div>|</div>
176
- </div>
296
+ </TopPixelIndicator>
177
297
  </Readable>
178
298
  ))}
179
- </div>
299
+ </TopPixelGuides>
180
300
  )}
181
301
  {showTitle &&
182
302
  (disabledTitle ? (
@@ -186,31 +306,54 @@ export class Root extends React.Component {
186
306
  ...(isChart && { width: finalWidth }),
187
307
  ...(isEmptyString(extractTextFromHTML(title)) && { display: 'none' }),
188
308
  }}
189
- className={cn(isChart ? classes.chartTitle : classes.graphTitle, classes.disabledTitle)}
190
- dangerouslySetInnerHTML={{ __html: title || '' }}
191
- />
309
+ >
310
+ {isChart ? (
311
+ <ChartTitle className="disabled" dangerouslySetInnerHTML={{ __html: title || '' }} />
312
+ ) : (
313
+ <GraphTitle className="disabled" dangerouslySetInnerHTML={{ __html: title || '' }} />
314
+ )}
315
+ </div>
192
316
  ) : (
193
317
  <div ref={(r) => (this.titleRef = r)}>
194
- <EditableHtml
195
- style={
196
- isChart && {
197
- width: finalWidth,
198
- }
199
- }
200
- className={cn(
201
- { [classes.rightMargin]: showPixelGuides },
202
- isChart ? classes.chartTitle : classes.graphTitle,
203
- )}
204
- markup={title || ''}
205
- onChange={onChangeTitle}
206
- placeholder={
207
- (defineChart && titlePlaceholder) || (!disabledTitle && 'Click here to add a title for this graph')
208
- }
209
- toolbarOpts={{ noPadding: true, noBorder: true }}
210
- activePlugins={activeTitlePlugins}
211
- disableScrollbar
212
- onKeyDown={this.handleKeyDown}
213
- />
318
+ {isChart ? (
319
+ <ChartTitle className={cn({ rightMargin: showPixelGuides })}>
320
+ <EditableHtml
321
+ style={
322
+ isChart && {
323
+ width: finalWidth,
324
+ }
325
+ }
326
+ markup={title || ''}
327
+ onChange={onChangeTitle}
328
+ placeholder={
329
+ (defineChart && titlePlaceholder) || (!disabledTitle && 'Click here to add a title for this graph')
330
+ }
331
+ toolbarOpts={{ noPadding: true, noBorder: true }}
332
+ activePlugins={activeTitlePlugins}
333
+ disableScrollbar
334
+ onKeyDown={this.handleKeyDown}
335
+ />
336
+ </ChartTitle>
337
+ ) : (
338
+ <GraphTitle className={cn({ rightMargin: showPixelGuides })}>
339
+ <EditableHtml
340
+ style={
341
+ isChart && {
342
+ width: finalWidth,
343
+ }
344
+ }
345
+ markup={title || ''}
346
+ onChange={onChangeTitle}
347
+ placeholder={
348
+ (defineChart && titlePlaceholder) || (!disabledTitle && 'Click here to add a title for this graph')
349
+ }
350
+ toolbarOpts={{ noPadding: true, noBorder: true }}
351
+ activePlugins={activeTitlePlugins}
352
+ disableScrollbar
353
+ onKeyDown={this.handleKeyDown}
354
+ />
355
+ </GraphTitle>
356
+ )}
214
357
  </div>
215
358
  ))}
216
359
  {showLabels && !isChart && (
@@ -226,7 +369,7 @@ export class Root extends React.Component {
226
369
  charactersLimit={labelsCharactersLimit}
227
370
  />
228
371
  )}
229
- <div className={classes.wrapper}>
372
+ <Wrapper>
230
373
  {showLabels && (
231
374
  <Label
232
375
  side="left"
@@ -242,20 +385,35 @@ export class Root extends React.Component {
242
385
  charactersLimit={labelsCharactersLimit}
243
386
  />
244
387
  )}
245
- <svg width={finalWidth} height={finalHeight} className={defineChart ? classes.defineChart : classes.chart}>
246
- <g
247
- ref={(r) => {
248
- this.g = r;
249
- if (rootRef) {
250
- rootRef(r);
251
- }
252
- }}
253
- className={classes.graphBox}
254
- transform={`translate(${leftPadding + (domain.padding || 0)}, ${topPadding + (range.padding || 0)})`}
255
- >
256
- {children}
257
- </g>
258
- </svg>
388
+ {defineChart ? (
389
+ <DefineChartSvg width={finalWidth} height={finalHeight}>
390
+ <GraphBox
391
+ ref={(r) => {
392
+ this.g = r;
393
+ if (rootRef) {
394
+ rootRef(r);
395
+ }
396
+ }}
397
+ transform={`translate(${leftPadding + (domain.padding || 0)}, ${topPadding + (range.padding || 0)})`}
398
+ >
399
+ {children}
400
+ </GraphBox>
401
+ </DefineChartSvg>
402
+ ) : (
403
+ <ChartSvg width={finalWidth} height={finalHeight}>
404
+ <GraphBox
405
+ ref={(r) => {
406
+ this.g = r;
407
+ if (rootRef) {
408
+ rootRef(r);
409
+ }
410
+ }}
411
+ transform={`translate(${leftPadding + (domain.padding || 0)}, ${topPadding + (range.padding || 0)})`}
412
+ >
413
+ {children}
414
+ </GraphBox>
415
+ </ChartSvg>
416
+ )}
259
417
  {showLabels && !isChart && (
260
418
  <Label
261
419
  side="right"
@@ -270,8 +428,7 @@ export class Root extends React.Component {
270
428
  />
271
429
  )}
272
430
  {showPixelGuides && (
273
- <div
274
- className={classes.sidePixelGuides}
431
+ <SidePixelGuides
275
432
  style={{
276
433
  paddingTop: sideGridlinesPadding,
277
434
  marginTop: 31,
@@ -279,12 +436,12 @@ export class Root extends React.Component {
279
436
  >
280
437
  {[...Array(nbOfHorizontalLines + 1).keys()].reverse().map((value) => (
281
438
  <Readable false key={`top-guide-${value}`}>
282
- <div className={classes.sidePixelIndicator}>━ {value * 100}px</div>
439
+ <SidePixelIndicator>━ {value * 100}px</SidePixelIndicator>
283
440
  </Readable>
284
441
  ))}
285
- </div>
442
+ </SidePixelGuides>
286
443
  )}
287
- </div>
444
+ </Wrapper>
288
445
  {showLabels && (
289
446
  <Label
290
447
  side="bottom"
@@ -301,83 +458,9 @@ export class Root extends React.Component {
301
458
  charactersLimit={labelsCharactersLimit}
302
459
  />
303
460
  )}
304
- </div>
461
+ </StyledRoot>
305
462
  );
306
463
  }
307
464
  }
308
465
 
309
- // use default color theme style to avoid color contrast issues
310
- const styles = (theme) => ({
311
- root: {
312
- border: `solid 1px ${color.primaryLight()}`,
313
- color: color.defaults.TEXT,
314
- backgroundColor: theme.palette.common.white,
315
- touchAction: 'none',
316
- position: 'relative',
317
- boxSizing: 'unset', // to override the default border-box in IBX that breaks the component width layout
318
- },
319
- wrapper: {
320
- display: 'flex',
321
- position: 'relative',
322
- },
323
- svg: {},
324
- defineChart: {
325
- paddingLeft: '50px',
326
- overflow: 'visible',
327
- },
328
- chart: {
329
- overflow: 'visible',
330
- },
331
- graphBox: {
332
- cursor: 'pointer',
333
- userSelect: 'none',
334
- },
335
- graphTitle: {
336
- color: color.defaults.TEXT,
337
- fontSize: theme.typography.fontSize + 2,
338
- padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit / 2}px 0`,
339
- textAlign: 'center',
340
- },
341
- chartTitle: {
342
- color: color.defaults.TEXT,
343
- fontSize: theme.typography.fontSize + 4,
344
- padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit / 2}px 0`,
345
- textAlign: 'center',
346
- },
347
- disabledTitle: {
348
- pointerEvents: 'none',
349
- },
350
- rightMargin: {
351
- marginRight: '74px',
352
- },
353
- topPixelGuides: {
354
- display: 'flex',
355
- paddingTop: '6px',
356
- },
357
- topPixelIndicator: {
358
- display: 'flex',
359
- flexDirection: 'column',
360
- alignItems: 'center',
361
- width: '100px',
362
- pointerEvents: 'none',
363
- userSelect: 'none',
364
- },
365
- sidePixelGuides: {
366
- width: '70px',
367
- display: 'flex',
368
- flexDirection: 'column',
369
- marginRight: '6px',
370
- },
371
- sidePixelIndicator: {
372
- textAlign: 'right',
373
- height: '20px',
374
- pointerEvents: 'none',
375
- userSelect: 'none',
376
-
377
- '&:not(:last-child)': {
378
- marginBottom: '80px',
379
- },
380
- },
381
- });
382
-
383
- export default withStyles(styles)(Root);
466
+ export default Root;