@ni/nimble-components 20.1.18 → 20.1.19

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.
@@ -5,18 +5,26 @@ import { iconBoldBTag } from '../icons/bold-b';
5
5
  import { iconItalicITag } from '../icons/italic-i';
6
6
  import { iconListTag } from '../icons/list';
7
7
  import { iconNumberListTag } from '../icons/number-list';
8
+ import { errorTextTemplate } from '../patterns/error/template';
9
+ import { iconExclamationMarkTag } from '../icons/exclamation-mark';
8
10
  // prettier-ignore
9
11
  export const template = html `
10
12
  <template>
11
13
  <div class="container">
12
14
  <section ${ref('editorContainer')} class="editor-container">
13
15
  </section>
14
- <section class="footer-section" part="footer-section">
16
+ <${iconExclamationMarkTag}
17
+ severity="error"
18
+ class="error-icon ${x => (x.scrollbarWidth >= 0 ? 'scrollbar-width-calculated' : '')}"
19
+ style="--ni-private-rich-text-editor-scrollbar-width: ${x => x.scrollbarWidth}px;"
20
+ ></${iconExclamationMarkTag}>
21
+ <section class="footer-section">
15
22
  <${toolbarTag}>
16
23
  <${toggleButtonTag}
17
24
  ${ref('boldButton')}
18
25
  appearance="ghost"
19
26
  content-hidden
27
+ ?disabled="${x => x.disabled}"
20
28
  slot="start"
21
29
  title="Bold"
22
30
  @click=${x => x.boldButtonClick()}
@@ -30,6 +38,7 @@ export const template = html `
30
38
  ${ref('italicsButton')}
31
39
  appearance="ghost"
32
40
  content-hidden
41
+ ?disabled="${x => x.disabled}"
33
42
  slot="start"
34
43
  title="Italics"
35
44
  @click=${x => x.italicsButtonClick()}
@@ -43,6 +52,7 @@ export const template = html `
43
52
  ${ref('bulletListButton')}
44
53
  appearance="ghost"
45
54
  content-hidden
55
+ ?disabled="${x => x.disabled}"
46
56
  slot="start"
47
57
  title="Bullet List"
48
58
  @click=${x => x.bulletListButtonClick()}
@@ -56,6 +66,7 @@ export const template = html `
56
66
  ${ref('numberedListButton')}
57
67
  appearance="ghost"
58
68
  content-hidden
69
+ ?disabled="${x => x.disabled}"
59
70
  slot="start"
60
71
  title="Numbered List"
61
72
  @click=${x => x.numberedListButtonClick()}
@@ -70,6 +81,7 @@ export const template = html `
70
81
  <slot name="footer-actions"></slot>
71
82
  </span>
72
83
  </section>
84
+ ${errorTextTemplate}
73
85
  </div>
74
86
  </template>
75
87
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/rich-text-editor/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEzD,kBAAkB;AAClB,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAgB;;;uBAGrB,GAAG,CAAC,iBAAiB,CAAC;;;mBAG1B,UAAU;uBACN,eAAe;0BACZ,GAAG,CAAC,YAAY,CAAC;;;;;iCAKV,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE;kCACvB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;mCACxC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAsB,CAAC;;;2BAG/D,YAAY,mBAAmB,YAAY;wBAC9C,eAAe;uBAChB,eAAe;0BACZ,GAAG,CAAC,eAAe,CAAC;;;;;iCAKb,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB,EAAE;kCAC1B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;mCACxC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAsB,CAAC;;;2BAGlE,cAAc,mBAAmB,cAAc;wBAClD,eAAe;uBAChB,eAAe;0BACZ,GAAG,CAAC,kBAAkB,CAAC;;;;;iCAKhB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,EAAE;kCAC7B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;mCACxC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,KAAsB,CAAC;;;2BAGrE,WAAW,mBAAmB,WAAW;wBAC5C,eAAe;uBAChB,eAAe;0BACZ,GAAG,CAAC,oBAAoB,CAAC;;;;;iCAKlB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAuB,EAAE;kCAC/B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,KAAK,CAAC;mCACxC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,KAAsB,CAAC;;;2BAGvE,iBAAiB,mBAAmB,iBAAiB;wBACxD,eAAe;oBACnB,UAAU;;;;;;;CAO7B,CAAC"}
1
+ {"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/rich-text-editor/template.ts"],"names":[],"mappings":"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"}
@@ -12,37 +12,24 @@ export declare class RichTextEditorPageObject {
12
12
  pressEnterKeyInEditor(): Promise<void>;
13
13
  pressTabKeyInEditor(): Promise<void>;
14
14
  pressShiftTabKeysInEditor(): Promise<void>;
15
- /**
16
- * To click a formatting button in the footer section, pass its position value as an index (starting from '0')
17
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
18
- */
19
15
  clickFooterButton(button: ToolbarButton): Promise<void>;
20
- /**
21
- * To retrieve the checked state of the button, provide its position value as an index (starting from '0')
22
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
23
- */
24
16
  getButtonCheckedState(button: ToolbarButton): boolean;
25
- /**
26
- * To retrieve the tab index of the button, provide its position value as an index (starting from '0')
27
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
28
- */
29
17
  getButtonTabIndex(button: ToolbarButton): number;
30
- /**
31
- * To trigger a space key press for the button, provide its position value as an index (starting from '0')
32
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
33
- */
34
18
  spaceKeyActivatesButton(button: ToolbarButton): void;
35
- /**
36
- * To trigger a enter key press for the button, provide its position value as an index (starting from '0')
37
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
38
- */
39
19
  enterKeyActivatesButton(button: ToolbarButton): void;
40
20
  setEditorTextContent(value: string): Promise<void>;
41
21
  getEditorFirstChildTagName(): string;
42
22
  getEditorFirstChildTextContent(): string;
43
23
  getEditorTagNames(): string[];
44
24
  getEditorLeafContents(): string[];
25
+ getEditorTabIndex(): string;
26
+ setFooterHidden(footerHidden: boolean): Promise<void>;
27
+ isFooterHidden(): boolean;
28
+ setDisabled(disabled: boolean): Promise<void>;
29
+ isButtonDisabled(button: ToolbarButton): boolean;
30
+ getPlaceholderValue(): string;
45
31
  private getEditorSection;
32
+ private getFooter;
46
33
  private getTiptapEditor;
47
34
  private getFormattingButton;
48
35
  }
@@ -58,35 +58,19 @@ export class RichTextEditorPageObject {
58
58
  editor.dispatchEvent(shiftTabEvent);
59
59
  await waitForUpdatesAsync();
60
60
  }
61
- /**
62
- * To click a formatting button in the footer section, pass its position value as an index (starting from '0')
63
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
64
- */
65
61
  async clickFooterButton(button) {
66
62
  const toggleButton = this.getFormattingButton(button);
67
63
  toggleButton.click();
68
64
  await waitForUpdatesAsync();
69
65
  }
70
- /**
71
- * To retrieve the checked state of the button, provide its position value as an index (starting from '0')
72
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
73
- */
74
66
  getButtonCheckedState(button) {
75
67
  const toggleButton = this.getFormattingButton(button);
76
68
  return toggleButton.checked;
77
69
  }
78
- /**
79
- * To retrieve the tab index of the button, provide its position value as an index (starting from '0')
80
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
81
- */
82
70
  getButtonTabIndex(button) {
83
71
  const toggleButton = this.getFormattingButton(button);
84
72
  return toggleButton.tabIndex;
85
73
  }
86
- /**
87
- * To trigger a space key press for the button, provide its position value as an index (starting from '0')
88
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
89
- */
90
74
  spaceKeyActivatesButton(button) {
91
75
  const toggleButton = this.getFormattingButton(button);
92
76
  const event = new KeyboardEvent('keypress', {
@@ -94,10 +78,6 @@ export class RichTextEditorPageObject {
94
78
  });
95
79
  toggleButton.control.dispatchEvent(event);
96
80
  }
97
- /**
98
- * To trigger a enter key press for the button, provide its position value as an index (starting from '0')
99
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
100
- */
101
81
  enterKeyActivatesButton(button) {
102
82
  const toggleButton = this.getFormattingButton(button);
103
83
  const event = new KeyboardEvent('keypress', {
@@ -129,15 +109,51 @@ export class RichTextEditorPageObject {
129
109
  })
130
110
  .map(el => el.textContent || '');
131
111
  }
112
+ getEditorTabIndex() {
113
+ return this.getTiptapEditor()?.getAttribute('tabindex') ?? '';
114
+ }
115
+ async setFooterHidden(footerHidden) {
116
+ if (footerHidden) {
117
+ this.richTextEditorElement.setAttribute('footer-hidden', '');
118
+ }
119
+ else {
120
+ this.richTextEditorElement.removeAttribute('footer-hidden');
121
+ }
122
+ await waitForUpdatesAsync();
123
+ }
124
+ isFooterHidden() {
125
+ const footerSection = this.getFooter();
126
+ return window.getComputedStyle(footerSection).display === 'none';
127
+ }
128
+ async setDisabled(disabled) {
129
+ if (disabled) {
130
+ this.richTextEditorElement.setAttribute('disabled', '');
131
+ }
132
+ else {
133
+ this.richTextEditorElement.removeAttribute('disabled');
134
+ }
135
+ await waitForUpdatesAsync();
136
+ }
137
+ isButtonDisabled(button) {
138
+ const toggleButton = this.getFormattingButton(button);
139
+ return toggleButton.hasAttribute('disabled');
140
+ }
141
+ getPlaceholderValue() {
142
+ const editor = this.getTiptapEditor();
143
+ return editor.firstElementChild?.getAttribute('data-placeholder') ?? '';
144
+ }
132
145
  getEditorSection() {
133
146
  return this.richTextEditorElement.shadowRoot?.querySelector('.editor');
134
147
  }
148
+ getFooter() {
149
+ return this.richTextEditorElement.shadowRoot.querySelector('.footer-section');
150
+ }
135
151
  getTiptapEditor() {
136
152
  return this.richTextEditorElement.shadowRoot?.querySelector('.ProseMirror');
137
153
  }
138
- getFormattingButton(index) {
154
+ getFormattingButton(button) {
139
155
  const buttons = this.richTextEditorElement.shadowRoot.querySelectorAll('nimble-toggle-button');
140
- return buttons[index];
156
+ return buttons[button];
141
157
  }
142
158
  }
143
159
  //# sourceMappingURL=rich-text-editor.pageobject.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rich-text-editor.pageobject.js","sourceRoot":"","sources":["../../../../src/rich-text-editor/testing/rich-text-editor.pageobject.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rich-text-editor.pageobject.js","sourceRoot":"","sources":["../../../../src/rich-text-editor/testing/rich-text-editor.pageobject.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,7 @@
1
- import { FoundationElement } from '@microsoft/fast-foundation';
1
+ import { ARIAGlobalStatesAndProperties, FoundationElement } from '@microsoft/fast-foundation';
2
+ import { Editor } from '@tiptap/core';
2
3
  import type { ToggleButton } from '../toggle-button';
4
+ import type { ErrorPattern } from '../patterns/error/types';
3
5
  declare global {
4
6
  interface HTMLElementTagNameMap {
5
7
  'nimble-rich-text-editor': RichTextEditor;
@@ -8,7 +10,54 @@ declare global {
8
10
  /**
9
11
  * A nimble styled rich text editor
10
12
  */
11
- export declare class RichTextEditor extends FoundationElement {
13
+ export declare class RichTextEditor extends FoundationElement implements ErrorPattern {
14
+ /**
15
+ * @internal
16
+ */
17
+ editor: HTMLDivElement;
18
+ /**
19
+ * @internal
20
+ */
21
+ tiptapEditor: Editor;
22
+ /**
23
+ * Whether to disable user from editing and interacting with toolbar buttons
24
+ *
25
+ * @public
26
+ * HTML Attribute: disabled
27
+ */
28
+ disabled: boolean;
29
+ /**
30
+ * Whether to hide the footer of the rich text editor
31
+ *
32
+ * @public
33
+ * HTML Attribute: footer-hidden
34
+ */
35
+ footerHidden: boolean;
36
+ /**
37
+ * Whether to display the error state.
38
+ *
39
+ * @public
40
+ * HTML Attribute: error-visible
41
+ */
42
+ errorVisible: boolean;
43
+ /**
44
+ * A message explaining why the value is invalid.
45
+ *
46
+ * @public
47
+ * HTML Attribute: error-text
48
+ */
49
+ errorText?: string;
50
+ /**
51
+ * @public
52
+ * HTML Attribute: placeholder
53
+ */
54
+ placeholder?: string;
55
+ /**
56
+ * True if the editor is empty or contains only whitespace, false otherwise.
57
+ *
58
+ * @public
59
+ */
60
+ get empty(): boolean;
12
61
  /**
13
62
  * @internal
14
63
  */
@@ -25,17 +74,21 @@ export declare class RichTextEditor extends FoundationElement {
25
74
  * @internal
26
75
  */
27
76
  numberedListButton: ToggleButton;
77
+ /**
78
+ * The width of the vertical scrollbar, if displayed.
79
+ * @internal
80
+ */
81
+ scrollbarWidth: number;
28
82
  /**
29
83
  * @internal
30
84
  */
31
85
  editorContainer: HTMLDivElement;
32
- private tiptapEditor;
33
- private editor;
86
+ private resizeObserver?;
87
+ private updateScrollbarWidthQueued;
34
88
  private readonly markdownParser;
35
89
  private readonly markdownSerializer;
36
90
  private readonly domSerializer;
37
91
  private readonly xmlSerializer;
38
- constructor();
39
92
  /**
40
93
  * @internal
41
94
  */
@@ -44,6 +97,19 @@ export declare class RichTextEditor extends FoundationElement {
44
97
  * @internal
45
98
  */
46
99
  disconnectedCallback(): void;
100
+ /**
101
+ * @internal
102
+ */
103
+ disabledChanged(): void;
104
+ /**
105
+ * Update the placeholder text and view of the editor.
106
+ * @internal
107
+ */
108
+ placeholderChanged(): void;
109
+ /**
110
+ * @internal
111
+ */
112
+ ariaLabelChanged(): void;
47
113
  /**
48
114
  * Toggle the bold mark and focus back to the editor
49
115
  * @internal
@@ -98,6 +164,8 @@ export declare class RichTextEditor extends FoundationElement {
98
164
  * @internal
99
165
  */
100
166
  stopEventPropagation(event: Event): boolean;
167
+ private createEditor;
168
+ private createTiptapEditor;
101
169
  /**
102
170
  * This function takes the Fragment from parseMarkdownToDOM function and return the serialized string using XMLSerializer
103
171
  */
@@ -105,7 +173,6 @@ export declare class RichTextEditor extends FoundationElement {
105
173
  private initializeMarkdownParser;
106
174
  private initializeMarkdownSerializer;
107
175
  private parseMarkdownToDOM;
108
- private initializeEditor;
109
176
  /**
110
177
  * Binding the "transaction" event to the editor allows continuous monitoring the events and updating the button state in response to
111
178
  * various actions such as mouse events, keyboard events, changes in the editor content etc,.
@@ -115,5 +182,29 @@ export declare class RichTextEditor extends FoundationElement {
115
182
  private unbindEditorTransactionEvent;
116
183
  private updateEditorButtonsState;
117
184
  private keyActivatesButton;
185
+ private unbindEditorUpdateEvent;
186
+ /**
187
+ * input event is fired when there is a change in the content of the editor.
188
+ *
189
+ * https://tiptap.dev/api/events#update
190
+ */
191
+ private bindEditorUpdateEvent;
192
+ /**
193
+ * Stopping the native input event propagation emitted by the contenteditable element in the Tiptap
194
+ * since there is an issue (linked below) in ProseMirror where selecting the text and removing it
195
+ * does not trigger the native HTMLElement input event. So using the "update" event emitted by the
196
+ * Tiptap to capture it as an "input" customEvent in the rich text editor.
197
+ *
198
+ * Prose Mirror issue: https://discuss.prosemirror.net/t/how-to-handle-select-backspace-delete-cut-type-kind-of-events-handletextinput-or-handledomevents-input-doesnt-help/4844
199
+ */
200
+ private stopNativeInputEventPropagation;
201
+ private unbindNativeInputEvent;
202
+ private queueUpdateScrollbarWidth;
203
+ private updateScrollbarWidth;
204
+ private onResize;
205
+ private getTipTapExtension;
206
+ private setEditorTabIndex;
207
+ }
208
+ export interface RichTextEditor extends ARIAGlobalStatesAndProperties {
118
209
  }
119
210
  export declare const richTextEditorTag: string;
@@ -12,37 +12,24 @@ export declare class RichTextEditorPageObject {
12
12
  pressEnterKeyInEditor(): Promise<void>;
13
13
  pressTabKeyInEditor(): Promise<void>;
14
14
  pressShiftTabKeysInEditor(): Promise<void>;
15
- /**
16
- * To click a formatting button in the footer section, pass its position value as an index (starting from '0')
17
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
18
- */
19
15
  clickFooterButton(button: ToolbarButton): Promise<void>;
20
- /**
21
- * To retrieve the checked state of the button, provide its position value as an index (starting from '0')
22
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
23
- */
24
16
  getButtonCheckedState(button: ToolbarButton): boolean;
25
- /**
26
- * To retrieve the tab index of the button, provide its position value as an index (starting from '0')
27
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
28
- */
29
17
  getButtonTabIndex(button: ToolbarButton): number;
30
- /**
31
- * To trigger a space key press for the button, provide its position value as an index (starting from '0')
32
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
33
- */
34
18
  spaceKeyActivatesButton(button: ToolbarButton): void;
35
- /**
36
- * To trigger a enter key press for the button, provide its position value as an index (starting from '0')
37
- * @param button can be imported from an enum for each button using the `ButtonIndex`.
38
- */
39
19
  enterKeyActivatesButton(button: ToolbarButton): void;
40
20
  setEditorTextContent(value: string): Promise<void>;
41
21
  getEditorFirstChildTagName(): string;
42
22
  getEditorFirstChildTextContent(): string;
43
23
  getEditorTagNames(): string[];
44
24
  getEditorLeafContents(): string[];
25
+ getEditorTabIndex(): string;
26
+ setFooterHidden(footerHidden: boolean): Promise<void>;
27
+ isFooterHidden(): boolean;
28
+ setDisabled(disabled: boolean): Promise<void>;
29
+ isButtonDisabled(button: ToolbarButton): boolean;
30
+ getPlaceholderValue(): string;
45
31
  private getEditorSection;
32
+ private getFooter;
46
33
  private getTiptapEditor;
47
34
  private getFormattingButton;
48
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ni/nimble-components",
3
- "version": "20.1.18",
3
+ "version": "20.1.19",
4
4
  "description": "Styled web components for the NI Nimble Design System",
5
5
  "scripts": {
6
6
  "build": "npm run generate-icons && npm run build-components && npm run bundle-components && npm run generate-scss && npm run build-storybook",
@@ -64,16 +64,17 @@
64
64
  "@ni/nimble-tokens": "^6.3.0",
65
65
  "@tanstack/table-core": "^8.9.3",
66
66
  "@tanstack/virtual-core": "^3.0.0-beta.44",
67
- "@tiptap/core": "^2.0.4",
68
- "@tiptap/extension-bold": "^2.0.4",
69
- "@tiptap/extension-bullet-list": "^2.0.4",
70
- "@tiptap/extension-document": "^2.0.4",
71
- "@tiptap/extension-history": "^2.0.4",
72
- "@tiptap/extension-italic": "^2.0.4",
73
- "@tiptap/extension-list-item": "^2.0.4",
74
- "@tiptap/extension-ordered-list": "^2.0.4",
75
- "@tiptap/extension-paragraph": "^2.0.4",
76
- "@tiptap/extension-text": "^2.0.4",
67
+ "@tiptap/core": "^2.1.6",
68
+ "@tiptap/extension-bold": "^2.1.6",
69
+ "@tiptap/extension-bullet-list": "^2.1.6",
70
+ "@tiptap/extension-document": "^2.1.6",
71
+ "@tiptap/extension-history": "^2.1.6",
72
+ "@tiptap/extension-italic": "^2.1.6",
73
+ "@tiptap/extension-list-item": "^2.1.6",
74
+ "@tiptap/extension-ordered-list": "^2.1.6",
75
+ "@tiptap/extension-paragraph": "^2.1.6",
76
+ "@tiptap/extension-placeholder": "^2.1.6",
77
+ "@tiptap/extension-text": "^2.1.6",
77
78
  "@types/d3-array": "^3.0.4",
78
79
  "@types/d3-random": "^3.0.1",
79
80
  "@types/d3-scale": "^4.0.2",