@justeattakeaway/pie-tooltip 0.1.0 → 0.2.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/README.md +161 -15
- package/custom-elements.json +459 -3
- package/dist/index.d.ts +123 -2
- package/dist/index.js +266 -18
- package/dist/react.d.ts +128 -3
- package/dist/react.js +21 -7
- package/package.json +5 -3
- package/src/defs.ts +117 -3
- package/src/index.ts +395 -9
- package/src/react.ts +9 -3
- package/src/tooltip.scss +364 -2
package/src/index.ts
CHANGED
|
@@ -1,28 +1,414 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
nothing,
|
|
3
|
+
unsafeCSS,
|
|
4
|
+
type PropertyValues,
|
|
5
|
+
type TemplateResult,
|
|
6
|
+
} from 'lit';
|
|
3
7
|
import { PieElement } from '@justeattakeaway/pie-webc-core/src/internals/PieElement';
|
|
8
|
+
import {
|
|
9
|
+
property, query, queryAssignedElements, state,
|
|
10
|
+
} from 'lit/decorators.js';
|
|
11
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
12
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
13
|
+
import { html, unsafeStatic } from 'lit/static-html.js';
|
|
4
14
|
import {
|
|
5
15
|
safeCustomElement,
|
|
16
|
+
validPropertyValues,
|
|
6
17
|
} from '@justeattakeaway/pie-webc-core';
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
componentClass,
|
|
21
|
+
componentSelector,
|
|
22
|
+
defaultProps,
|
|
23
|
+
headingLevels,
|
|
24
|
+
ON_TOOLTIP_CLOSE_EVENT,
|
|
25
|
+
positions,
|
|
26
|
+
sizes,
|
|
27
|
+
types,
|
|
28
|
+
variants,
|
|
29
|
+
type TooltipMode,
|
|
30
|
+
type TooltipProps,
|
|
31
|
+
} from './defs';
|
|
7
32
|
import styles from './tooltip.scss?inline';
|
|
8
|
-
import { type TooltipProps } from './defs';
|
|
9
33
|
|
|
10
|
-
|
|
34
|
+
import '@justeattakeaway/pie-icon-button';
|
|
35
|
+
import '@justeattakeaway/pie-icons-webc/dist/IconClose.js';
|
|
36
|
+
|
|
11
37
|
export * from './defs';
|
|
12
38
|
|
|
13
|
-
const
|
|
39
|
+
const headingId = 'pie-tooltip-heading';
|
|
40
|
+
|
|
41
|
+
// Returns true if the element establishes a containing block through a property other than
|
|
42
|
+
// `position` — i.e. for both absolute and fixed descendants, not just absolute.
|
|
43
|
+
const createsContainingBlock = (styles: CSSStyleDeclaration): boolean => {
|
|
44
|
+
const isSet = (value: string | undefined) => !!value && value !== 'none';
|
|
45
|
+
|
|
46
|
+
const containingBlockValues = [
|
|
47
|
+
styles.transform,
|
|
48
|
+
styles.perspective,
|
|
49
|
+
styles.filter,
|
|
50
|
+
styles.backdropFilter,
|
|
51
|
+
styles.translate,
|
|
52
|
+
styles.rotate,
|
|
53
|
+
styles.scale,
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
if (containingBlockValues.some(isSet)) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// `size` and `style` containment do not establish a containing block; everything else does.
|
|
61
|
+
if (/\b(paint|layout|content|strict)\b/.test(styles.contain)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (styles.containerType && styles.containerType !== 'normal') {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// will-change pre-establishes the containing block before the property is applied.
|
|
70
|
+
return /\b(transform|perspective|filter|backdrop-filter|contain|translate|rotate|scale)\b/.test(styles.willChange);
|
|
71
|
+
};
|
|
14
72
|
|
|
15
73
|
/**
|
|
16
74
|
* @tagname pie-tooltip
|
|
75
|
+
* @event {Event} pie-tooltip-close - When the close button is clicked. Set `isOpen` to `false` in response.
|
|
76
|
+
* @slot content - The descriptive content of the panel. Must not contain focusable elements.
|
|
77
|
+
* @slot action - An optional slot for interactive content such as a `pie-button`. Filling this slot switches the panel to a non-modal dialog.
|
|
17
78
|
*/
|
|
18
79
|
@safeCustomElement('pie-tooltip')
|
|
19
80
|
export class PieTooltip extends PieElement implements TooltipProps {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
81
|
+
@property({ type: String })
|
|
82
|
+
public trigger: TooltipProps['trigger'];
|
|
83
|
+
|
|
84
|
+
@property({ type: Boolean })
|
|
85
|
+
public isOpen = defaultProps.isOpen;
|
|
86
|
+
|
|
87
|
+
@property({ type: String })
|
|
88
|
+
@validPropertyValues(componentSelector, positions, defaultProps.position)
|
|
89
|
+
public position = defaultProps.position;
|
|
90
|
+
|
|
91
|
+
@property({ type: String })
|
|
92
|
+
@validPropertyValues(componentSelector, sizes, defaultProps.size)
|
|
93
|
+
public size = defaultProps.size;
|
|
94
|
+
|
|
95
|
+
@property({ type: String })
|
|
96
|
+
@validPropertyValues(componentSelector, variants, defaultProps.variant)
|
|
97
|
+
public variant = defaultProps.variant;
|
|
98
|
+
|
|
99
|
+
@property({ type: String })
|
|
100
|
+
@validPropertyValues(componentSelector, types, defaultProps.type)
|
|
101
|
+
public type = defaultProps.type;
|
|
102
|
+
|
|
103
|
+
@property({ type: Boolean })
|
|
104
|
+
public isDismissible = defaultProps.isDismissible;
|
|
105
|
+
|
|
106
|
+
@property({ type: String })
|
|
107
|
+
public heading: TooltipProps['heading'];
|
|
108
|
+
|
|
109
|
+
@property({ type: String })
|
|
110
|
+
@validPropertyValues(componentSelector, headingLevels, defaultProps.headingLevel)
|
|
111
|
+
public headingLevel = defaultProps.headingLevel;
|
|
112
|
+
|
|
113
|
+
@property({ type: Object })
|
|
114
|
+
public aria: TooltipProps['aria'];
|
|
115
|
+
|
|
116
|
+
@queryAssignedElements({ slot: 'action' }) private _assignedActionElements!: Array<HTMLElement>;
|
|
117
|
+
|
|
118
|
+
@query('.c-tooltip-origin') private _originElement!: HTMLElement | null;
|
|
119
|
+
|
|
120
|
+
@state() private _hasActionContent: boolean | undefined;
|
|
121
|
+
|
|
122
|
+
@state() private _isPositioned = false;
|
|
123
|
+
|
|
124
|
+
private _triggerTrackingController: AbortController | undefined;
|
|
125
|
+
|
|
126
|
+
private _directionObserver: MutationObserver | undefined;
|
|
127
|
+
|
|
128
|
+
private _reanchorFrame = 0;
|
|
129
|
+
|
|
130
|
+
private _shouldResolveOverlayMode = false;
|
|
23
131
|
|
|
24
|
-
// Renders a `CSSResult` generated from SCSS by Vite
|
|
25
132
|
static styles = unsafeCSS(styles);
|
|
133
|
+
|
|
134
|
+
private get _mode (): TooltipMode | undefined {
|
|
135
|
+
if (this._hasActionContent === undefined) {
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return this._hasActionContent ? 'dialog' : 'tooltip';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
protected firstUpdated (): void {
|
|
143
|
+
this.resolveMode();
|
|
144
|
+
this.projectOverTrigger();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
protected updated (changedProperties: PropertyValues<this>): void {
|
|
148
|
+
const anchoringProperties: Array<keyof PieTooltip> = ['trigger', 'isOpen', 'position', 'size'];
|
|
149
|
+
|
|
150
|
+
if (this.isOpen && changedProperties.has('isOpen')) {
|
|
151
|
+
this.resolveOverlayMode();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (anchoringProperties.some((prop) => changedProperties.has(prop))) {
|
|
155
|
+
this.projectOverTrigger();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (this.isOpen) {
|
|
159
|
+
this.startTrackingTrigger();
|
|
160
|
+
} else {
|
|
161
|
+
this.stopTrackingTrigger();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public disconnectedCallback (): void {
|
|
166
|
+
this.stopTrackingTrigger();
|
|
167
|
+
super.disconnectedCallback();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Listens for scroll (capture — catches any ancestor), resize, and dir-attribute changes to
|
|
171
|
+
// re-anchor the panel. Multiple events per frame coalesce into one requestAnimationFrame call.
|
|
172
|
+
private startTrackingTrigger (): void {
|
|
173
|
+
if (this._triggerTrackingController) {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const controller = new AbortController();
|
|
178
|
+
const { signal } = controller;
|
|
179
|
+
|
|
180
|
+
const handleViewportChange = () => {
|
|
181
|
+
if (this._reanchorFrame) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this._reanchorFrame = requestAnimationFrame(() => {
|
|
186
|
+
this._reanchorFrame = 0;
|
|
187
|
+
|
|
188
|
+
if (this._shouldResolveOverlayMode) {
|
|
189
|
+
this._shouldResolveOverlayMode = false;
|
|
190
|
+
this.resolveOverlayMode();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
this.projectOverTrigger();
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Flagged rather than resolved immediately so window-drag cannot walk ancestors more than once per frame.
|
|
198
|
+
const handleResize = () => {
|
|
199
|
+
this._shouldResolveOverlayMode = true;
|
|
200
|
+
handleViewportChange();
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
window.addEventListener('scroll', handleViewportChange, { capture: true, passive: true, signal });
|
|
204
|
+
window.addEventListener('resize', handleResize, { passive: true, signal });
|
|
205
|
+
|
|
206
|
+
this._directionObserver = new MutationObserver(handleViewportChange);
|
|
207
|
+
this._directionObserver.observe(this.ownerDocument.documentElement, {
|
|
208
|
+
attributeFilter: ['dir'],
|
|
209
|
+
subtree: true,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
this._triggerTrackingController = controller;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
private stopTrackingTrigger (): void {
|
|
216
|
+
this._triggerTrackingController?.abort();
|
|
217
|
+
this._triggerTrackingController = undefined;
|
|
218
|
+
|
|
219
|
+
this._directionObserver?.disconnect();
|
|
220
|
+
this._directionObserver = undefined;
|
|
221
|
+
|
|
222
|
+
this._shouldResolveOverlayMode = false;
|
|
223
|
+
|
|
224
|
+
if (this._reanchorFrame) {
|
|
225
|
+
cancelAnimationFrame(this._reanchorFrame);
|
|
226
|
+
this._reanchorFrame = 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private resolveMode (): void {
|
|
231
|
+
this._hasActionContent = this._assignedActionElements.length > 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Picks between `absolute` (browser handles scrolling, but clipped by overflow ancestors) and
|
|
235
|
+
// `fixed` (escapes overflow clips, but must re-offset on every scroll). Switches to `fixed`
|
|
236
|
+
// only when it escapes a clip that `absolute` would not.
|
|
237
|
+
private resolveOverlayMode (): void {
|
|
238
|
+
let isAtOrAboveAbsoluteContainingBlock = false;
|
|
239
|
+
let isAtOrAboveFixedContainingBlock = false;
|
|
240
|
+
let isAbsoluteClipped = false;
|
|
241
|
+
let isFixedClipped = false;
|
|
242
|
+
|
|
243
|
+
let node: Node | null = this.parentNode;
|
|
244
|
+
|
|
245
|
+
while (node) {
|
|
246
|
+
// Step over shadow roots to the host; layout follows the light DOM, not slot assignment.
|
|
247
|
+
const element = node instanceof ShadowRoot ? node.host : node;
|
|
248
|
+
|
|
249
|
+
if (!(element instanceof Element)) {
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const styles = getComputedStyle(element);
|
|
254
|
+
const isContainingBlock = createsContainingBlock(styles);
|
|
255
|
+
|
|
256
|
+
if (isContainingBlock || styles.position !== 'static') {
|
|
257
|
+
isAtOrAboveAbsoluteContainingBlock = true;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (isContainingBlock) {
|
|
261
|
+
isAtOrAboveFixedContainingBlock = true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Check after setting the containing-block flags so an ancestor that is both the
|
|
265
|
+
// containing block and the clipper is counted correctly.
|
|
266
|
+
if (styles.overflowX !== 'visible' || styles.overflowY !== 'visible') {
|
|
267
|
+
isAbsoluteClipped = isAbsoluteClipped || isAtOrAboveAbsoluteContainingBlock;
|
|
268
|
+
isFixedClipped = isFixedClipped || isAtOrAboveFixedContainingBlock;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (element === this.ownerDocument.documentElement) {
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
node = element.parentNode;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this.style.position = isAbsoluteClipped && !isFixedClipped ? 'fixed' : '';
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Measures the trigger relative to the origin marker (which sits at the containing block's
|
|
282
|
+
// origin) and writes CSS custom properties. Self-referential: correct for any containing
|
|
283
|
+
// block. Physical values; shadow-root CSS uses logical properties for RTL mirroring.
|
|
284
|
+
private projectOverTrigger (): void {
|
|
285
|
+
this._isPositioned = false;
|
|
286
|
+
|
|
287
|
+
const triggerElement = this.trigger ? this.ownerDocument.getElementById(this.trigger) : null;
|
|
288
|
+
|
|
289
|
+
if (!triggerElement || !this._originElement) {
|
|
290
|
+
['top', 'left', 'width', 'height'].forEach((suffix) => {
|
|
291
|
+
this.style.removeProperty(`--tooltip-anchor-${suffix}`);
|
|
292
|
+
});
|
|
293
|
+
this.style.removeProperty('--tooltip-container-inline-size');
|
|
294
|
+
this._isPositioned = true;
|
|
295
|
+
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const originRect = this._originElement.getBoundingClientRect();
|
|
300
|
+
const {
|
|
301
|
+
top, left, width, height,
|
|
302
|
+
} = triggerElement.getBoundingClientRect();
|
|
303
|
+
|
|
304
|
+
this.style.setProperty('--tooltip-anchor-top', `${top - originRect.top}px`);
|
|
305
|
+
this.style.setProperty('--tooltip-anchor-left', `${left - originRect.left}px`);
|
|
306
|
+
this.style.setProperty('--tooltip-anchor-width', `${width}px`);
|
|
307
|
+
this.style.setProperty('--tooltip-anchor-height', `${height}px`);
|
|
308
|
+
|
|
309
|
+
const container = triggerElement.parentElement;
|
|
310
|
+
const containerInlineSize = container ? container.getBoundingClientRect().width : width;
|
|
311
|
+
|
|
312
|
+
this.style.setProperty('--tooltip-container-inline-size', `${containerInlineSize}px`);
|
|
313
|
+
this._isPositioned = true;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private handleCloseButtonClick (): void {
|
|
317
|
+
/**
|
|
318
|
+
* The custom elements manifest analyser scans `this.dispatchEvent` calls for event names
|
|
319
|
+
* but cannot resolve constants, so it would record an event literally named
|
|
320
|
+
* `ON_TOOLTIP_CLOSE_EVENT` and generate a matching React callback prop. `@ignore` skips
|
|
321
|
+
* this call site; the event is declared by the class-level `@event` tag instead.
|
|
322
|
+
*
|
|
323
|
+
* @ignore
|
|
324
|
+
*/
|
|
325
|
+
this.dispatchEvent(new Event(ON_TOOLTIP_CLOSE_EVENT, { bubbles: true, composed: true }));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private renderHeading (): TemplateResult {
|
|
329
|
+
const tag = unsafeStatic(this.headingLevel);
|
|
330
|
+
|
|
331
|
+
return html`<${tag}
|
|
332
|
+
id="${headingId}"
|
|
333
|
+
class="${componentClass}-heading"
|
|
334
|
+
data-test-id="${headingId}">${this.heading}</${tag}>`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
private renderCloseButton (): TemplateResult {
|
|
338
|
+
return html`
|
|
339
|
+
<pie-icon-button
|
|
340
|
+
class="${componentClass}-close"
|
|
341
|
+
data-test-id="${componentSelector}-close"
|
|
342
|
+
size="xsmall"
|
|
343
|
+
variant="${this.variant === 'inverse' ? 'ghost-secondary' : 'ghost-inverse'}"
|
|
344
|
+
.aria="${{ label: this.aria?.close }}"
|
|
345
|
+
@click="${this.handleCloseButtonClick}">
|
|
346
|
+
<icon-close></icon-close>
|
|
347
|
+
</pie-icon-button>`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
render () {
|
|
351
|
+
const {
|
|
352
|
+
aria,
|
|
353
|
+
heading,
|
|
354
|
+
isDismissible,
|
|
355
|
+
isOpen,
|
|
356
|
+
position,
|
|
357
|
+
size,
|
|
358
|
+
type,
|
|
359
|
+
variant,
|
|
360
|
+
_mode: mode,
|
|
361
|
+
} = this;
|
|
362
|
+
|
|
363
|
+
const isIconType = type === 'icon';
|
|
364
|
+
|
|
365
|
+
const layerClasses = {
|
|
366
|
+
[`${componentClass}-layer`]: true,
|
|
367
|
+
[`${componentClass}-layer--${position}`]: true,
|
|
368
|
+
[`${componentClass}-layer--type-${type}`]: true,
|
|
369
|
+
'is-open': !!isOpen,
|
|
370
|
+
'is-positioned': this._isPositioned,
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const panelClasses = {
|
|
374
|
+
[componentClass]: true,
|
|
375
|
+
[`${componentClass}--${position}`]: true,
|
|
376
|
+
[`${componentClass}--${variant}`]: true,
|
|
377
|
+
[`${componentClass}--type-${type}`]: true,
|
|
378
|
+
[`${componentClass}--size-${size}`]: !isIconType,
|
|
379
|
+
'is-dismissible': !!isDismissible,
|
|
380
|
+
'has-action': mode === 'dialog',
|
|
381
|
+
'has-heading': !!heading,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
const isDialog = mode === 'dialog';
|
|
385
|
+
|
|
386
|
+
return html`
|
|
387
|
+
<div class="${componentClass}-origin" data-test-id="${componentSelector}-origin"></div>
|
|
388
|
+
<div class="${componentClass}-anchor" data-test-id="${componentSelector}-anchor">
|
|
389
|
+
<div class="${classMap(layerClasses)}" data-test-id="${componentSelector}-layer">
|
|
390
|
+
<div
|
|
391
|
+
class="${classMap(panelClasses)}"
|
|
392
|
+
data-test-id="${componentSelector}"
|
|
393
|
+
role="${ifDefined(mode)}"
|
|
394
|
+
aria-hidden="${!isOpen}"
|
|
395
|
+
aria-labelledby="${isDialog && heading ? headingId : nothing}"
|
|
396
|
+
aria-label="${isDialog && !heading && aria?.label ? aria.label : nothing}">
|
|
397
|
+
${isIconType ? nothing : html`<div class="${componentClass}-arrow" data-test-id="${componentSelector}-arrow"></div>`}
|
|
398
|
+
<div class="${componentClass}-body">
|
|
399
|
+
${heading ? this.renderHeading() : nothing}
|
|
400
|
+
<div class="${componentClass}-content" data-test-id="${componentSelector}-content">
|
|
401
|
+
<slot name="content"></slot>
|
|
402
|
+
</div>
|
|
403
|
+
</div>
|
|
404
|
+
<div class="${componentClass}-action" data-test-id="${componentSelector}-action">
|
|
405
|
+
<slot name="action" @slotchange="${this.resolveMode}"></slot>
|
|
406
|
+
</div>
|
|
407
|
+
${isDismissible ? this.renderCloseButton() : nothing}
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>`;
|
|
411
|
+
}
|
|
26
412
|
}
|
|
27
413
|
|
|
28
414
|
declare global {
|
package/src/react.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { createComponent } from '@lit/react';
|
|
2
|
+
import { createComponent, type EventName } from '@lit/react';
|
|
3
3
|
import { PieTooltip as PieTooltipLit } from './index';
|
|
4
4
|
import { type TooltipProps } from './defs';
|
|
5
5
|
|
|
@@ -10,10 +10,16 @@ const PieTooltipReact = createComponent({
|
|
|
10
10
|
elementClass: PieTooltipLit,
|
|
11
11
|
react: React,
|
|
12
12
|
tagName: 'pie-tooltip',
|
|
13
|
-
events: {
|
|
13
|
+
events: {
|
|
14
|
+
onPieTooltipClose: 'pie-tooltip-close' as EventName<Event>, // When the close button is clicked. Set `isOpen` to `false` in response.
|
|
15
|
+
},
|
|
14
16
|
});
|
|
15
17
|
|
|
16
18
|
type ReactBaseType = React.HTMLAttributes<HTMLElement>
|
|
17
19
|
|
|
20
|
+
type PieTooltipEvents = {
|
|
21
|
+
onPieTooltipClose?: (event: Event) => void;
|
|
22
|
+
};
|
|
23
|
+
|
|
18
24
|
export const PieTooltip = PieTooltipReact as React.ForwardRefExoticComponent<React.PropsWithChildren<Omit<React.PropsWithoutRef<TooltipProps>, 'children'>>
|
|
19
|
-
& React.RefAttributes<PieTooltipLit> & ReactBaseType>;
|
|
25
|
+
& React.RefAttributes<PieTooltipLit> & PieTooltipEvents & ReactBaseType>;
|