@khanacademy/wonder-blocks-tooltip 1.4.1 → 1.4.2
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/CHANGELOG.md +13 -0
- package/dist/es/index.js +0 -18
- package/package.json +6 -6
- package/src/components/__tests__/tooltip-anchor.test.js +366 -423
- package/src/components/__tests__/tooltip-bubble.test.js +32 -49
- package/src/components/__tests__/tooltip-popper.test.js +2 -3
- package/src/components/__tests__/tooltip-tail.test.js +6 -84
- package/src/components/__tests__/tooltip.test.js +129 -246
- package/src/components/tooltip-tail.js +0 -18
- package/src/util/__tests__/ref-tracker.test.js +5 -7
- package/dist/index.js +0 -1495
- package/dist/index.js.flow +0 -2
- package/docs.md +0 -4
- package/src/components/__tests__/__snapshots__/tooltip-tail.test.js.snap +0 -9
- package/src/components/__tests__/__snapshots__/tooltip.test.js.snap +0 -53
package/dist/index.js
DELETED
|
@@ -1,1495 +0,0 @@
|
|
|
1
|
-
module.exports =
|
|
2
|
-
/******/ (function(modules) { // webpackBootstrap
|
|
3
|
-
/******/ // The module cache
|
|
4
|
-
/******/ var installedModules = {};
|
|
5
|
-
/******/
|
|
6
|
-
/******/ // The require function
|
|
7
|
-
/******/ function __webpack_require__(moduleId) {
|
|
8
|
-
/******/
|
|
9
|
-
/******/ // Check if module is in cache
|
|
10
|
-
/******/ if(installedModules[moduleId]) {
|
|
11
|
-
/******/ return installedModules[moduleId].exports;
|
|
12
|
-
/******/ }
|
|
13
|
-
/******/ // Create a new module (and put it into the cache)
|
|
14
|
-
/******/ var module = installedModules[moduleId] = {
|
|
15
|
-
/******/ i: moduleId,
|
|
16
|
-
/******/ l: false,
|
|
17
|
-
/******/ exports: {}
|
|
18
|
-
/******/ };
|
|
19
|
-
/******/
|
|
20
|
-
/******/ // Execute the module function
|
|
21
|
-
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
22
|
-
/******/
|
|
23
|
-
/******/ // Flag the module as loaded
|
|
24
|
-
/******/ module.l = true;
|
|
25
|
-
/******/
|
|
26
|
-
/******/ // Return the exports of the module
|
|
27
|
-
/******/ return module.exports;
|
|
28
|
-
/******/ }
|
|
29
|
-
/******/
|
|
30
|
-
/******/
|
|
31
|
-
/******/ // expose the modules object (__webpack_modules__)
|
|
32
|
-
/******/ __webpack_require__.m = modules;
|
|
33
|
-
/******/
|
|
34
|
-
/******/ // expose the module cache
|
|
35
|
-
/******/ __webpack_require__.c = installedModules;
|
|
36
|
-
/******/
|
|
37
|
-
/******/ // define getter function for harmony exports
|
|
38
|
-
/******/ __webpack_require__.d = function(exports, name, getter) {
|
|
39
|
-
/******/ if(!__webpack_require__.o(exports, name)) {
|
|
40
|
-
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
|
|
41
|
-
/******/ }
|
|
42
|
-
/******/ };
|
|
43
|
-
/******/
|
|
44
|
-
/******/ // define __esModule on exports
|
|
45
|
-
/******/ __webpack_require__.r = function(exports) {
|
|
46
|
-
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
47
|
-
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
48
|
-
/******/ }
|
|
49
|
-
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
50
|
-
/******/ };
|
|
51
|
-
/******/
|
|
52
|
-
/******/ // create a fake namespace object
|
|
53
|
-
/******/ // mode & 1: value is a module id, require it
|
|
54
|
-
/******/ // mode & 2: merge all properties of value into the ns
|
|
55
|
-
/******/ // mode & 4: return value when already ns object
|
|
56
|
-
/******/ // mode & 8|1: behave like require
|
|
57
|
-
/******/ __webpack_require__.t = function(value, mode) {
|
|
58
|
-
/******/ if(mode & 1) value = __webpack_require__(value);
|
|
59
|
-
/******/ if(mode & 8) return value;
|
|
60
|
-
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
|
|
61
|
-
/******/ var ns = Object.create(null);
|
|
62
|
-
/******/ __webpack_require__.r(ns);
|
|
63
|
-
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
|
|
64
|
-
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
|
|
65
|
-
/******/ return ns;
|
|
66
|
-
/******/ };
|
|
67
|
-
/******/
|
|
68
|
-
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
69
|
-
/******/ __webpack_require__.n = function(module) {
|
|
70
|
-
/******/ var getter = module && module.__esModule ?
|
|
71
|
-
/******/ function getDefault() { return module['default']; } :
|
|
72
|
-
/******/ function getModuleExports() { return module; };
|
|
73
|
-
/******/ __webpack_require__.d(getter, 'a', getter);
|
|
74
|
-
/******/ return getter;
|
|
75
|
-
/******/ };
|
|
76
|
-
/******/
|
|
77
|
-
/******/ // Object.prototype.hasOwnProperty.call
|
|
78
|
-
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
|
79
|
-
/******/
|
|
80
|
-
/******/ // __webpack_public_path__
|
|
81
|
-
/******/ __webpack_require__.p = "";
|
|
82
|
-
/******/
|
|
83
|
-
/******/
|
|
84
|
-
/******/ // Load entry module and return exports
|
|
85
|
-
/******/ return __webpack_require__(__webpack_require__.s = 19);
|
|
86
|
-
/******/ })
|
|
87
|
-
/************************************************************************/
|
|
88
|
-
/******/ ([
|
|
89
|
-
/* 0 */
|
|
90
|
-
/***/ (function(module, exports) {
|
|
91
|
-
|
|
92
|
-
module.exports = require("react");
|
|
93
|
-
|
|
94
|
-
/***/ }),
|
|
95
|
-
/* 1 */
|
|
96
|
-
/***/ (function(module, exports) {
|
|
97
|
-
|
|
98
|
-
module.exports = require("@khanacademy/wonder-blocks-spacing");
|
|
99
|
-
|
|
100
|
-
/***/ }),
|
|
101
|
-
/* 2 */
|
|
102
|
-
/***/ (function(module, exports) {
|
|
103
|
-
|
|
104
|
-
module.exports = require("@khanacademy/wonder-blocks-color");
|
|
105
|
-
|
|
106
|
-
/***/ }),
|
|
107
|
-
/* 3 */
|
|
108
|
-
/***/ (function(module, exports) {
|
|
109
|
-
|
|
110
|
-
module.exports = require("@khanacademy/wonder-blocks-core");
|
|
111
|
-
|
|
112
|
-
/***/ }),
|
|
113
|
-
/* 4 */
|
|
114
|
-
/***/ (function(module, exports) {
|
|
115
|
-
|
|
116
|
-
module.exports = require("aphrodite");
|
|
117
|
-
|
|
118
|
-
/***/ }),
|
|
119
|
-
/* 5 */
|
|
120
|
-
/***/ (function(module, exports) {
|
|
121
|
-
|
|
122
|
-
module.exports = require("react-dom");
|
|
123
|
-
|
|
124
|
-
/***/ }),
|
|
125
|
-
/* 6 */
|
|
126
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
127
|
-
|
|
128
|
-
"use strict";
|
|
129
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TooltipTail; });
|
|
130
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
131
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
132
|
-
/* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
|
|
133
|
-
/* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
|
|
134
|
-
/* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
|
|
135
|
-
/* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__);
|
|
136
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3);
|
|
137
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
|
|
138
|
-
/* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
|
|
139
|
-
/* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
// TODO(somewhatabstract): Replace this really basic unique ID work with
|
|
146
|
-
// something SSR-friendly and more robust.
|
|
147
|
-
let tempIdCounter = 0;
|
|
148
|
-
class TooltipTail extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
149
|
-
_calculateDimensionsFromPlacement() {
|
|
150
|
-
const {
|
|
151
|
-
placement
|
|
152
|
-
} = this.props; // The trimline, which we draw to make the tail flush to the bubble,
|
|
153
|
-
// has a thickness of 1. Since the line is drawn centered to the
|
|
154
|
-
// coordinates, we use an offset of 0.5 so that it properly covers what
|
|
155
|
-
// we want it to.
|
|
156
|
-
|
|
157
|
-
const trimlineOffset = 0.5; // Calculate the three points of the arrow. Depending on the tail's
|
|
158
|
-
// direction (i.e., the tooltip's "side"), we choose different points,
|
|
159
|
-
// and set our SVG's bounds differently.
|
|
160
|
-
//
|
|
161
|
-
// Note that when the tail points to the left or right, the width/height
|
|
162
|
-
// are inverted.
|
|
163
|
-
|
|
164
|
-
switch (placement) {
|
|
165
|
-
case "top":
|
|
166
|
-
return {
|
|
167
|
-
trimlinePoints: [`0,-${trimlineOffset}`, `${ARROW_WIDTH},-${trimlineOffset}`],
|
|
168
|
-
points: ["0,0", `${ARROW_WIDTH / 2},${ARROW_HEIGHT}`, `${ARROW_WIDTH},0`],
|
|
169
|
-
height: ARROW_HEIGHT,
|
|
170
|
-
width: ARROW_WIDTH
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
case "right":
|
|
174
|
-
return {
|
|
175
|
-
trimlinePoints: [`${ARROW_HEIGHT + trimlineOffset},0`, `${ARROW_HEIGHT + trimlineOffset},${ARROW_WIDTH}`],
|
|
176
|
-
points: [`${ARROW_HEIGHT},0`, `0,${ARROW_WIDTH / 2}`, `${ARROW_HEIGHT},${ARROW_WIDTH}`],
|
|
177
|
-
width: ARROW_HEIGHT,
|
|
178
|
-
height: ARROW_WIDTH
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
case "bottom":
|
|
182
|
-
return {
|
|
183
|
-
trimlinePoints: [`0, ${ARROW_HEIGHT + trimlineOffset}`, `${ARROW_WIDTH},${ARROW_HEIGHT + trimlineOffset}`],
|
|
184
|
-
points: [`0, ${ARROW_HEIGHT}`, `${ARROW_WIDTH / 2},0`, `${ARROW_WIDTH},${ARROW_HEIGHT}`],
|
|
185
|
-
width: ARROW_WIDTH,
|
|
186
|
-
height: ARROW_HEIGHT
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
case "left":
|
|
190
|
-
return {
|
|
191
|
-
trimlinePoints: [`-${trimlineOffset},0`, `-${trimlineOffset},${ARROW_WIDTH}`],
|
|
192
|
-
points: [`0,0`, `${ARROW_HEIGHT},${ARROW_WIDTH / 2}`, `0,${ARROW_WIDTH}`],
|
|
193
|
-
width: ARROW_HEIGHT,
|
|
194
|
-
height: ARROW_WIDTH
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
default:
|
|
198
|
-
throw new Error(`Unknown placement: ${placement}`);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
_getFilterPositioning() {
|
|
203
|
-
const {
|
|
204
|
-
placement
|
|
205
|
-
} = this.props;
|
|
206
|
-
|
|
207
|
-
switch (placement) {
|
|
208
|
-
case "top":
|
|
209
|
-
return {
|
|
210
|
-
y: "-50%",
|
|
211
|
-
x: "-50%",
|
|
212
|
-
offsetShadowX: 0
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
case "bottom":
|
|
216
|
-
// No shadow on the arrow as it falls "under" the bubble.
|
|
217
|
-
return null;
|
|
218
|
-
|
|
219
|
-
case "left":
|
|
220
|
-
return {
|
|
221
|
-
y: "-50%",
|
|
222
|
-
x: "0%",
|
|
223
|
-
offsetShadowX: 1
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
case "right":
|
|
227
|
-
return {
|
|
228
|
-
y: "-50%",
|
|
229
|
-
x: "-100%",
|
|
230
|
-
offsetShadowX: -1
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
default:
|
|
234
|
-
throw new Error(`Unknown placement: ${placement}`);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Create an SVG filter that applies a blur to an element.
|
|
239
|
-
* We'll apply it to a dark shape outlining the tooltip, which
|
|
240
|
-
* will produce the overall effect of a drop-shadow.
|
|
241
|
-
*
|
|
242
|
-
* Also, scope its ID by side, so that tooltips with other
|
|
243
|
-
* "side" values don't end up using the wrong filter from
|
|
244
|
-
* elsewhere in the document. (The `height` value depends on
|
|
245
|
-
* which way the arrow is turned!)
|
|
246
|
-
*/
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
_maybeRenderDropshadow(points) {
|
|
250
|
-
const position = this._getFilterPositioning();
|
|
251
|
-
|
|
252
|
-
if (!position) {
|
|
253
|
-
return null;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const {
|
|
257
|
-
placement
|
|
258
|
-
} = this.props;
|
|
259
|
-
const {
|
|
260
|
-
y,
|
|
261
|
-
x,
|
|
262
|
-
offsetShadowX
|
|
263
|
-
} = position;
|
|
264
|
-
const dropShadowFilterId = `tooltip-dropshadow-${placement}-${tempIdCounter++}`;
|
|
265
|
-
return [/*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("filter", {
|
|
266
|
-
key: "filter",
|
|
267
|
-
id: dropShadowFilterId // Height and width tell the filter how big of a canvas to
|
|
268
|
-
// draw based on its parent size. i.e. 2 times bigger.
|
|
269
|
-
// This is so that the diffuse gaussian blur has space to
|
|
270
|
-
// bleed into.
|
|
271
|
-
,
|
|
272
|
-
width: "200%",
|
|
273
|
-
height: "200%" // The x and y values tell the filter where, relative to its
|
|
274
|
-
// parent, it should begin showing its canvas. Without these
|
|
275
|
-
// the filter would clip at 0,0, which would look really
|
|
276
|
-
// strange.
|
|
277
|
-
,
|
|
278
|
-
x: x,
|
|
279
|
-
y: y
|
|
280
|
-
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("feGaussianBlur", {
|
|
281
|
-
in: "SourceAlpha",
|
|
282
|
-
stdDeviation: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xxSmall_6 / 2
|
|
283
|
-
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("feComponentTransfer", null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("feFuncA", {
|
|
284
|
-
type: "linear",
|
|
285
|
-
slope: "0.3"
|
|
286
|
-
}))),
|
|
287
|
-
/*#__PURE__*/
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Draw the tooltip arrow and apply the blur filter we created
|
|
291
|
-
* above, to produce a drop shadow effect.
|
|
292
|
-
* We move it down a bit with a translation, so that it is what
|
|
293
|
-
* we want.
|
|
294
|
-
*
|
|
295
|
-
* We offset the shadow on the X-axis because for left/right
|
|
296
|
-
* tails, we move the tail 1px toward the bubble. If we didn't
|
|
297
|
-
* offset the shadow, it would crash the bubble outline.
|
|
298
|
-
*
|
|
299
|
-
* See styles below for why we offset the arrow.
|
|
300
|
-
*/
|
|
301
|
-
react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("g", {
|
|
302
|
-
key: "dropshadow",
|
|
303
|
-
transform: `translate(${offsetShadowX},5.5)`
|
|
304
|
-
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("polyline", {
|
|
305
|
-
fill: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack16,
|
|
306
|
-
points: points.join(" "),
|
|
307
|
-
stroke: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack32,
|
|
308
|
-
filter: `url(#${dropShadowFilterId})`
|
|
309
|
-
}))];
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
_minDistanceFromCorners(placement) {
|
|
313
|
-
const minDistanceFromCornersForTopBottom = _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16;
|
|
314
|
-
const minDistanceFromCornersForLeftRight = 7;
|
|
315
|
-
|
|
316
|
-
switch (placement) {
|
|
317
|
-
case "top":
|
|
318
|
-
case "bottom":
|
|
319
|
-
return minDistanceFromCornersForTopBottom;
|
|
320
|
-
|
|
321
|
-
case "left":
|
|
322
|
-
case "right":
|
|
323
|
-
return minDistanceFromCornersForLeftRight;
|
|
324
|
-
|
|
325
|
-
default:
|
|
326
|
-
throw new Error(`Unknown placement: ${placement}`);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
_getFullTailWidth() {
|
|
331
|
-
return ARROW_WIDTH + 2 * MIN_DISTANCE_FROM_CORNERS;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
_getFullTailHeight() {
|
|
335
|
-
return ARROW_HEIGHT + DISTANCE_FROM_ANCHOR;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
_getContainerStyle() {
|
|
339
|
-
const {
|
|
340
|
-
placement
|
|
341
|
-
} = this.props;
|
|
342
|
-
/**
|
|
343
|
-
* Ensure the container is sized properly for us to be placed correctly
|
|
344
|
-
* by the Popper.js code.
|
|
345
|
-
*
|
|
346
|
-
* Here we offset the arrow 1px toward the bubble. This ensures the arrow
|
|
347
|
-
* outline meets the bubble outline and allows the arrow to erase the bubble
|
|
348
|
-
* outline between the ends of the arrow outline. We do this so that the
|
|
349
|
-
* arrow outline and bubble outline create a single, seamless outline of
|
|
350
|
-
* the callout.
|
|
351
|
-
*
|
|
352
|
-
* NOTE: The widths and heights refer to the downward-pointing tail
|
|
353
|
-
* (i.e. placement="top"). When the tail points to the left or right
|
|
354
|
-
* instead, the width/height are inverted.
|
|
355
|
-
*/
|
|
356
|
-
|
|
357
|
-
const fullTailWidth = this._getFullTailWidth();
|
|
358
|
-
|
|
359
|
-
const fullTailHeight = this._getFullTailHeight();
|
|
360
|
-
|
|
361
|
-
switch (placement) {
|
|
362
|
-
case "top":
|
|
363
|
-
return {
|
|
364
|
-
top: -1,
|
|
365
|
-
width: fullTailWidth,
|
|
366
|
-
height: fullTailHeight
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
case "right":
|
|
370
|
-
return {
|
|
371
|
-
left: 1,
|
|
372
|
-
width: fullTailHeight,
|
|
373
|
-
height: fullTailWidth
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
case "bottom":
|
|
377
|
-
return {
|
|
378
|
-
top: 1,
|
|
379
|
-
width: fullTailWidth,
|
|
380
|
-
height: fullTailHeight
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
case "left":
|
|
384
|
-
return {
|
|
385
|
-
left: -1,
|
|
386
|
-
width: fullTailHeight,
|
|
387
|
-
height: fullTailWidth
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
default:
|
|
391
|
-
throw new Error(`Unknown placement: ${placement}`);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
_getArrowStyle() {
|
|
396
|
-
const {
|
|
397
|
-
placement
|
|
398
|
-
} = this.props;
|
|
399
|
-
|
|
400
|
-
switch (placement) {
|
|
401
|
-
case "top":
|
|
402
|
-
return {
|
|
403
|
-
marginLeft: MIN_DISTANCE_FROM_CORNERS,
|
|
404
|
-
marginRight: MIN_DISTANCE_FROM_CORNERS,
|
|
405
|
-
paddingBottom: DISTANCE_FROM_ANCHOR
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
case "right":
|
|
409
|
-
return {
|
|
410
|
-
marginTop: MIN_DISTANCE_FROM_CORNERS,
|
|
411
|
-
marginBottom: MIN_DISTANCE_FROM_CORNERS,
|
|
412
|
-
paddingLeft: DISTANCE_FROM_ANCHOR
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
case "bottom":
|
|
416
|
-
return {
|
|
417
|
-
marginLeft: MIN_DISTANCE_FROM_CORNERS,
|
|
418
|
-
marginRight: MIN_DISTANCE_FROM_CORNERS,
|
|
419
|
-
paddingTop: DISTANCE_FROM_ANCHOR
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
case "left":
|
|
423
|
-
return {
|
|
424
|
-
marginTop: MIN_DISTANCE_FROM_CORNERS,
|
|
425
|
-
marginBottom: MIN_DISTANCE_FROM_CORNERS,
|
|
426
|
-
paddingRight: DISTANCE_FROM_ANCHOR
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
default:
|
|
430
|
-
throw new Error(`Unknown placement: ${placement}`);
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
_renderArrow() {
|
|
435
|
-
const {
|
|
436
|
-
trimlinePoints,
|
|
437
|
-
points,
|
|
438
|
-
height,
|
|
439
|
-
width
|
|
440
|
-
} = this._calculateDimensionsFromPlacement();
|
|
441
|
-
|
|
442
|
-
const {
|
|
443
|
-
color
|
|
444
|
-
} = this.props;
|
|
445
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("svg", {
|
|
446
|
-
className: Object(aphrodite__WEBPACK_IMPORTED_MODULE_1__["css"])(styles.arrow),
|
|
447
|
-
style: this._getArrowStyle(),
|
|
448
|
-
width: width,
|
|
449
|
-
height: height,
|
|
450
|
-
"aria-hidden": true
|
|
451
|
-
}, this._maybeRenderDropshadow(points), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("polyline", {
|
|
452
|
-
fill: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a[color],
|
|
453
|
-
stroke: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a[color],
|
|
454
|
-
points: points.join(" ")
|
|
455
|
-
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("polyline", {
|
|
456
|
-
// Redraw the stroke on top of the background color,
|
|
457
|
-
// so that the ends aren't extra dark where they meet
|
|
458
|
-
// the border of the tooltip.
|
|
459
|
-
fill: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a[color],
|
|
460
|
-
points: points.join(" "),
|
|
461
|
-
stroke: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack16
|
|
462
|
-
}), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"]("polyline", {
|
|
463
|
-
stroke: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a[color],
|
|
464
|
-
points: trimlinePoints.join(" ")
|
|
465
|
-
}));
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
render() {
|
|
469
|
-
const {
|
|
470
|
-
offset,
|
|
471
|
-
placement,
|
|
472
|
-
updateRef
|
|
473
|
-
} = this.props;
|
|
474
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
|
|
475
|
-
style: [styles.tailContainer, { ...offset
|
|
476
|
-
}, this._getContainerStyle()],
|
|
477
|
-
"data-placement": placement,
|
|
478
|
-
ref: updateRef
|
|
479
|
-
}, this._renderArrow());
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Some constants to make style generation easier to understand.
|
|
485
|
-
* NOTE: The widths and heights refer to the downward-pointing tail
|
|
486
|
-
* (i.e. placement="top"). When the tail points to the left or right instead,
|
|
487
|
-
* the width/height are inverted.
|
|
488
|
-
*/
|
|
489
|
-
|
|
490
|
-
TooltipTail.defaultProps = {
|
|
491
|
-
color: "white"
|
|
492
|
-
};
|
|
493
|
-
const DISTANCE_FROM_ANCHOR = _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8;
|
|
494
|
-
const MIN_DISTANCE_FROM_CORNERS = _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8;
|
|
495
|
-
const ARROW_WIDTH = _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.large_24;
|
|
496
|
-
const ARROW_HEIGHT = _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.small_12;
|
|
497
|
-
const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
|
|
498
|
-
/**
|
|
499
|
-
* Container
|
|
500
|
-
*/
|
|
501
|
-
tailContainer: {
|
|
502
|
-
position: "relative",
|
|
503
|
-
pointerEvents: "none"
|
|
504
|
-
},
|
|
505
|
-
|
|
506
|
-
/**
|
|
507
|
-
* Arrow
|
|
508
|
-
*/
|
|
509
|
-
arrow: {
|
|
510
|
-
// Ensure the dropshadow bleeds outside our bounds.
|
|
511
|
-
overflow: "visible"
|
|
512
|
-
}
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
/***/ }),
|
|
516
|
-
/* 7 */
|
|
517
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
518
|
-
|
|
519
|
-
"use strict";
|
|
520
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TooltipContent; });
|
|
521
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
522
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
523
|
-
/* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
|
|
524
|
-
/* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_1__);
|
|
525
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
526
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__);
|
|
527
|
-
/* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(17);
|
|
528
|
-
/* harmony import */ var _khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__);
|
|
529
|
-
/* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
|
|
530
|
-
/* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
|
|
531
|
-
/* harmony import */ var _khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
|
|
532
|
-
/* harmony import */ var _khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_5__);
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* This component is used to provide the content that is to be rendered in the
|
|
542
|
-
* tooltip bubble.
|
|
543
|
-
*
|
|
544
|
-
* ### Usage
|
|
545
|
-
*
|
|
546
|
-
* ```jsx
|
|
547
|
-
* import {TooltipContent} from "@khanacademy/wonder-blocks-tooltip";
|
|
548
|
-
*
|
|
549
|
-
* <TooltipContent title="Title text!">
|
|
550
|
-
* Some content in my tooltip.
|
|
551
|
-
* </TooltipContent>
|
|
552
|
-
* ```
|
|
553
|
-
*/
|
|
554
|
-
class TooltipContent extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
555
|
-
_renderTitle() {
|
|
556
|
-
const {
|
|
557
|
-
title
|
|
558
|
-
} = this.props;
|
|
559
|
-
|
|
560
|
-
if (title) {
|
|
561
|
-
if (typeof title === "string") {
|
|
562
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_5__["HeadingSmall"], null, title);
|
|
563
|
-
} else {
|
|
564
|
-
return title;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
return null;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
_renderChildren() {
|
|
572
|
-
const {
|
|
573
|
-
children
|
|
574
|
-
} = this.props;
|
|
575
|
-
|
|
576
|
-
if (typeof children === "string") {
|
|
577
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_typography__WEBPACK_IMPORTED_MODULE_5__["LabelMedium"], null, children);
|
|
578
|
-
} else {
|
|
579
|
-
return children;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
render() {
|
|
584
|
-
const title = this._renderTitle();
|
|
585
|
-
|
|
586
|
-
const children = this._renderChildren();
|
|
587
|
-
|
|
588
|
-
const containerStyle = title ? styles.withTitle : styles.withoutTitle;
|
|
589
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["View"], {
|
|
590
|
-
style: containerStyle
|
|
591
|
-
}, title, title && children && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_3__["Strut"], {
|
|
592
|
-
size: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xxxSmall_4
|
|
593
|
-
}), children);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
const styles = aphrodite__WEBPACK_IMPORTED_MODULE_1__["StyleSheet"].create({
|
|
598
|
-
withoutTitle: {
|
|
599
|
-
padding: `10px ${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16}px`
|
|
600
|
-
},
|
|
601
|
-
withTitle: {
|
|
602
|
-
padding: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.medium_16
|
|
603
|
-
}
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
/***/ }),
|
|
607
|
-
/* 8 */
|
|
608
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
609
|
-
|
|
610
|
-
"use strict";
|
|
611
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TooltipPopper; });
|
|
612
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
613
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
614
|
-
/* harmony import */ var react_popper__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(18);
|
|
615
|
-
/* harmony import */ var react_popper__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_popper__WEBPACK_IMPORTED_MODULE_1__);
|
|
616
|
-
/* harmony import */ var _util_ref_tracker_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11);
|
|
617
|
-
/**
|
|
618
|
-
* This component is a light wrapper for react-popper, allowing us to position
|
|
619
|
-
* and control the tooltip bubble location and visibility as we need.
|
|
620
|
-
*/
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
class TooltipPopper extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
625
|
-
constructor(...args) {
|
|
626
|
-
super(...args);
|
|
627
|
-
this._bubbleRefTracker = new _util_ref_tracker_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ "a"]();
|
|
628
|
-
this._tailRefTracker = new _util_ref_tracker_js__WEBPACK_IMPORTED_MODULE_2__[/* default */ "a"]();
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
_renderPositionedContent(popperProps) {
|
|
632
|
-
const {
|
|
633
|
-
children
|
|
634
|
-
} = this.props; // We'll hide some complexity from the children here and ensure
|
|
635
|
-
// that our placement always has a value.
|
|
636
|
-
|
|
637
|
-
const placement = // We know that popperProps.placement will only be one of our
|
|
638
|
-
// supported values, so just cast it.
|
|
639
|
-
popperProps.placement || this.props.placement; // Just in case the callbacks have changed, let's update our reference
|
|
640
|
-
// trackers.
|
|
641
|
-
|
|
642
|
-
this._bubbleRefTracker.setCallback(popperProps.ref);
|
|
643
|
-
|
|
644
|
-
this._tailRefTracker.setCallback(popperProps.arrowProps.ref); // Here we translate from the react-popper's PropperChildrenProps
|
|
645
|
-
// to our own TooltipBubbleProps.
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const bubbleProps = {
|
|
649
|
-
placement,
|
|
650
|
-
style: {
|
|
651
|
-
// NOTE(jeresig): We can't just use `popperProps.style` here
|
|
652
|
-
// as the Flow type doesn't match Aphrodite's CSS flow props
|
|
653
|
-
// (as it doesn't camelCase props). So we just copy over the
|
|
654
|
-
// props that we need, instead.
|
|
655
|
-
top: popperProps.style.top,
|
|
656
|
-
left: popperProps.style.left,
|
|
657
|
-
bottom: popperProps.style.bottom,
|
|
658
|
-
right: popperProps.style.right,
|
|
659
|
-
position: popperProps.style.position,
|
|
660
|
-
transform: popperProps.style.transform
|
|
661
|
-
},
|
|
662
|
-
updateBubbleRef: this._bubbleRefTracker.updateRef,
|
|
663
|
-
tailOffset: {
|
|
664
|
-
bottom: popperProps.arrowProps.style.bottom,
|
|
665
|
-
right: popperProps.arrowProps.style.right,
|
|
666
|
-
top: popperProps.arrowProps.style.top,
|
|
667
|
-
left: popperProps.arrowProps.style.left,
|
|
668
|
-
transform: popperProps.arrowProps.style.transform
|
|
669
|
-
},
|
|
670
|
-
updateTailRef: this._tailRefTracker.updateRef,
|
|
671
|
-
isReferenceHidden: popperProps.isReferenceHidden
|
|
672
|
-
};
|
|
673
|
-
return children(bubbleProps);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
render() {
|
|
677
|
-
const {
|
|
678
|
-
anchorElement,
|
|
679
|
-
placement
|
|
680
|
-
} = this.props;
|
|
681
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](react_popper__WEBPACK_IMPORTED_MODULE_1__["Popper"], {
|
|
682
|
-
referenceElement: anchorElement,
|
|
683
|
-
strategy: "fixed",
|
|
684
|
-
placement: placement,
|
|
685
|
-
modifiers: [{
|
|
686
|
-
name: "preventOverflow",
|
|
687
|
-
options: {
|
|
688
|
-
rootBoundary: "viewport"
|
|
689
|
-
}
|
|
690
|
-
}]
|
|
691
|
-
}, props => this._renderPositionedContent(props));
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/***/ }),
|
|
697
|
-
/* 9 */
|
|
698
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
699
|
-
|
|
700
|
-
"use strict";
|
|
701
|
-
/* unused harmony export TooltipPortalAttributeName */
|
|
702
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TooltipAppearanceDelay; });
|
|
703
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return TooltipDisappearanceDelay; });
|
|
704
|
-
/**
|
|
705
|
-
* The attribute used to identify a tooltip portal.
|
|
706
|
-
*/
|
|
707
|
-
const TooltipPortalAttributeName = "data-tooltip-portal";
|
|
708
|
-
const TooltipAppearanceDelay = 100;
|
|
709
|
-
const TooltipDisappearanceDelay = 75;
|
|
710
|
-
|
|
711
|
-
/***/ }),
|
|
712
|
-
/* 10 */
|
|
713
|
-
/***/ (function(module, exports) {
|
|
714
|
-
|
|
715
|
-
module.exports = require("@khanacademy/wonder-blocks-typography");
|
|
716
|
-
|
|
717
|
-
/***/ }),
|
|
718
|
-
/* 11 */
|
|
719
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
720
|
-
|
|
721
|
-
"use strict";
|
|
722
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RefTracker; });
|
|
723
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
724
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
725
|
-
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
|
726
|
-
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
|
727
|
-
/**
|
|
728
|
-
* This is a little helper that we can use to wrap the react-popper reference
|
|
729
|
-
* update methods so that we can convert a regular React ref into a DOM node
|
|
730
|
-
* as react-popper expects, and also ensure we only update react-popper
|
|
731
|
-
* on actual changes, and not just renders of the same thing.
|
|
732
|
-
*/
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
class RefTracker {
|
|
736
|
-
constructor() {
|
|
737
|
-
this.updateRef = ref => {
|
|
738
|
-
if (ref) {
|
|
739
|
-
// We only want to update the reference if it is
|
|
740
|
-
// actually changed. Otherwise, we can trigger another render that
|
|
741
|
-
// would then update the reference again and just keep looping.
|
|
742
|
-
const domNode = react_dom__WEBPACK_IMPORTED_MODULE_1__["findDOMNode"](ref);
|
|
743
|
-
|
|
744
|
-
if (domNode instanceof HTMLElement && domNode !== this._lastRef) {
|
|
745
|
-
this._lastRef = domNode;
|
|
746
|
-
this._targetFn && this._targetFn(domNode);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
};
|
|
750
|
-
|
|
751
|
-
this.setCallback = targetFn => {
|
|
752
|
-
if (this._targetFn !== targetFn) {
|
|
753
|
-
if (targetFn && typeof targetFn !== "function") {
|
|
754
|
-
throw new Error("targetFn must be a function");
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
this._targetFn = targetFn || null;
|
|
758
|
-
|
|
759
|
-
if (this._lastRef && this._targetFn) {
|
|
760
|
-
this._targetFn(this._lastRef);
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
/***/ }),
|
|
769
|
-
/* 12 */
|
|
770
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
771
|
-
|
|
772
|
-
"use strict";
|
|
773
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return Tooltip; });
|
|
774
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
775
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
776
|
-
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
|
777
|
-
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
|
778
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
779
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__);
|
|
780
|
-
/* harmony import */ var _khanacademy_wonder_blocks_modal__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(13);
|
|
781
|
-
/* harmony import */ var _khanacademy_wonder_blocks_modal__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_modal__WEBPACK_IMPORTED_MODULE_3__);
|
|
782
|
-
/* harmony import */ var _tooltip_anchor_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(14);
|
|
783
|
-
/* harmony import */ var _tooltip_bubble_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(16);
|
|
784
|
-
/* harmony import */ var _tooltip_content_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(7);
|
|
785
|
-
/* harmony import */ var _tooltip_popper_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(8);
|
|
786
|
-
/**
|
|
787
|
-
* The Tooltip component provides the means to anchor some additional
|
|
788
|
-
* information to some content. The additional information is shown in a
|
|
789
|
-
* callout that hovers above the page content. This additional information is
|
|
790
|
-
* invoked by hovering over the anchored content, or focusing all or part of the
|
|
791
|
-
* anchored content.
|
|
792
|
-
*
|
|
793
|
-
* This component is structured as follows:
|
|
794
|
-
*
|
|
795
|
-
* Tooltip (this component)
|
|
796
|
-
* - TooltipAnchor (provides hover/focus behaviors on anchored content)
|
|
797
|
-
* - TooltipPortalMounter (creates portal into which the callout is rendered)
|
|
798
|
-
* --------------------------- [PORTAL BOUNDARY] ------------------------------
|
|
799
|
-
* - TooltipPopper (provides positioning for the callout using react-popper)
|
|
800
|
-
* - TooltipBubble (renders the callout borders, background and shadow)
|
|
801
|
-
* - TooltipContent (renders the callout content; the actual information)
|
|
802
|
-
* - TooltipTail (renders the callout tail and shadow that points from the
|
|
803
|
-
* callout to the anchor content)
|
|
804
|
-
*/
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
/**
|
|
815
|
-
* Use a tooltip to help describe an on screen object.
|
|
816
|
-
*
|
|
817
|
-
* Tooltips:
|
|
818
|
-
* - contain text
|
|
819
|
-
* - (optional) contain small graphic elements to complement the text
|
|
820
|
-
* - appear on hover or focus (for non-assistive tech keyboard users)
|
|
821
|
-
* - must have a tail that points to a parent object
|
|
822
|
-
* - DO NOT include actions
|
|
823
|
-
*
|
|
824
|
-
* For more rich content see Popovers, for taking action on an object, see
|
|
825
|
-
* Snackbars (proposed).
|
|
826
|
-
*
|
|
827
|
-
* ### Usage
|
|
828
|
-
*
|
|
829
|
-
* ```jsx
|
|
830
|
-
* import Tooltip from "@khanacademy/wonder-blocks-tooltip";
|
|
831
|
-
*
|
|
832
|
-
* <Tooltip content="This is a text tooltip">
|
|
833
|
-
* Tooltip anchor
|
|
834
|
-
* </Tooltip>
|
|
835
|
-
* ```
|
|
836
|
-
*
|
|
837
|
-
*/
|
|
838
|
-
class Tooltip extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
839
|
-
constructor(...args) {
|
|
840
|
-
super(...args);
|
|
841
|
-
this.state = {
|
|
842
|
-
active: false,
|
|
843
|
-
activeBubble: false,
|
|
844
|
-
anchorElement: null
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
/**
|
|
849
|
-
* Used to sync the `opened` state when Tooltip acts as a controlled
|
|
850
|
-
* component
|
|
851
|
-
*/
|
|
852
|
-
static getDerivedStateFromProps(props, state) {
|
|
853
|
-
return {
|
|
854
|
-
active: typeof props.opened === "boolean" ? props.opened : state.active
|
|
855
|
-
};
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
_updateAnchorElement(ref) {
|
|
859
|
-
if (ref && ref !== this.state.anchorElement) {
|
|
860
|
-
this.setState({
|
|
861
|
-
anchorElement: ref
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
_renderBubbleContent() {
|
|
867
|
-
const {
|
|
868
|
-
title,
|
|
869
|
-
content
|
|
870
|
-
} = this.props;
|
|
871
|
-
|
|
872
|
-
if (typeof content === "string") {
|
|
873
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_tooltip_content_js__WEBPACK_IMPORTED_MODULE_6__[/* default */ "a"], {
|
|
874
|
-
title: title
|
|
875
|
-
}, content);
|
|
876
|
-
} else if (title) {
|
|
877
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["cloneElement"](content, {
|
|
878
|
-
title
|
|
879
|
-
});
|
|
880
|
-
} else {
|
|
881
|
-
return content;
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
_renderPopper(ids) {
|
|
886
|
-
const {
|
|
887
|
-
id
|
|
888
|
-
} = this.props;
|
|
889
|
-
const bubbleId = ids ? ids.get(Tooltip.ariaContentId) : id;
|
|
890
|
-
|
|
891
|
-
if (!bubbleId) {
|
|
892
|
-
throw new Error("Did not get an identifier factory nor a id prop");
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
const {
|
|
896
|
-
placement
|
|
897
|
-
} = this.props;
|
|
898
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_tooltip_popper_js__WEBPACK_IMPORTED_MODULE_7__[/* default */ "a"], {
|
|
899
|
-
anchorElement: this.state.anchorElement,
|
|
900
|
-
placement: placement
|
|
901
|
-
}, props => /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_tooltip_bubble_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"], {
|
|
902
|
-
id: bubbleId,
|
|
903
|
-
style: props.style,
|
|
904
|
-
tailOffset: props.tailOffset,
|
|
905
|
-
isReferenceHidden: props.isReferenceHidden,
|
|
906
|
-
placement: props.placement,
|
|
907
|
-
updateTailRef: props.updateTailRef,
|
|
908
|
-
updateBubbleRef: props.updateBubbleRef,
|
|
909
|
-
onActiveChanged: active => this.setState({
|
|
910
|
-
activeBubble: active
|
|
911
|
-
})
|
|
912
|
-
}, this._renderBubbleContent()));
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
_getHost() {
|
|
916
|
-
const {
|
|
917
|
-
anchorElement
|
|
918
|
-
} = this.state;
|
|
919
|
-
return Object(_khanacademy_wonder_blocks_modal__WEBPACK_IMPORTED_MODULE_3__["maybeGetPortalMountedModalHostElement"])(anchorElement) || document.body;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
_renderTooltipAnchor(ids) {
|
|
923
|
-
const {
|
|
924
|
-
children,
|
|
925
|
-
forceAnchorFocusivity
|
|
926
|
-
} = this.props;
|
|
927
|
-
const {
|
|
928
|
-
active,
|
|
929
|
-
activeBubble
|
|
930
|
-
} = this.state;
|
|
931
|
-
|
|
932
|
-
const popperHost = this._getHost(); // TODO(kevinb): update to use ReactPopper's React 16-friendly syntax
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](react__WEBPACK_IMPORTED_MODULE_0__["Fragment"], null, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_tooltip_anchor_js__WEBPACK_IMPORTED_MODULE_4__[/* default */ "a"], {
|
|
936
|
-
forceAnchorFocusivity: forceAnchorFocusivity,
|
|
937
|
-
anchorRef: r => this._updateAnchorElement(r),
|
|
938
|
-
onActiveChanged: active => this.setState({
|
|
939
|
-
active
|
|
940
|
-
}),
|
|
941
|
-
ids: ids
|
|
942
|
-
}, children), popperHost && (active || activeBubble) && /*#__PURE__*/react_dom__WEBPACK_IMPORTED_MODULE_1__["createPortal"](this._renderPopper(ids), popperHost));
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
render() {
|
|
946
|
-
const {
|
|
947
|
-
id
|
|
948
|
-
} = this.props;
|
|
949
|
-
|
|
950
|
-
if (id) {
|
|
951
|
-
// Let's bypass the extra weight of an id provider since we don't
|
|
952
|
-
// need it.
|
|
953
|
-
return this._renderTooltipAnchor();
|
|
954
|
-
} else {
|
|
955
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["UniqueIDProvider"], {
|
|
956
|
-
scope: "tooltip",
|
|
957
|
-
mockOnFirstRender: true
|
|
958
|
-
}, ids => this._renderTooltipAnchor(ids));
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
}
|
|
963
|
-
Tooltip.defaultProps = {
|
|
964
|
-
forceAnchorFocusivity: true,
|
|
965
|
-
placement: "top"
|
|
966
|
-
};
|
|
967
|
-
Tooltip.ariaContentId = "aria-content";
|
|
968
|
-
|
|
969
|
-
/***/ }),
|
|
970
|
-
/* 13 */
|
|
971
|
-
/***/ (function(module, exports) {
|
|
972
|
-
|
|
973
|
-
module.exports = require("@khanacademy/wonder-blocks-modal");
|
|
974
|
-
|
|
975
|
-
/***/ }),
|
|
976
|
-
/* 14 */
|
|
977
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
978
|
-
|
|
979
|
-
"use strict";
|
|
980
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TooltipAnchor; });
|
|
981
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
982
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
983
|
-
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
|
984
|
-
/* harmony import */ var react_dom__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react_dom__WEBPACK_IMPORTED_MODULE_1__);
|
|
985
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
986
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__);
|
|
987
|
-
/* harmony import */ var _util_active_tracker_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(15);
|
|
988
|
-
/* harmony import */ var _util_constants_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
|
|
989
|
-
/**
|
|
990
|
-
* This component turns the given content into an accessible anchor for
|
|
991
|
-
* positioning and displaying tooltips.
|
|
992
|
-
*/
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
const TRACKER = new _util_active_tracker_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"]();
|
|
999
|
-
class TooltipAnchor extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
1000
|
-
constructor(props) {
|
|
1001
|
-
super(props);
|
|
1002
|
-
|
|
1003
|
-
this.activeStateStolen = () => {
|
|
1004
|
-
// Something wants the active state.
|
|
1005
|
-
// Do we have it? If so, let's remember that.
|
|
1006
|
-
// If we are already active, or we're inactive but have a timeoutID,
|
|
1007
|
-
// then it was stolen from us.
|
|
1008
|
-
this._stolenFromUs = this.state.active || !!this._timeoutID; // Let's first tell ourselves we're not focused (otherwise the tooltip
|
|
1009
|
-
// will be sticky on the next hover of this anchor and that just looks
|
|
1010
|
-
// weird).
|
|
1011
|
-
|
|
1012
|
-
this._focused = false; // Now update our actual state.
|
|
1013
|
-
|
|
1014
|
-
this._setActiveState(false, true);
|
|
1015
|
-
};
|
|
1016
|
-
|
|
1017
|
-
this._handleFocusIn = () => {
|
|
1018
|
-
this._updateActiveState(this._hovered, true);
|
|
1019
|
-
};
|
|
1020
|
-
|
|
1021
|
-
this._handleFocusOut = () => {
|
|
1022
|
-
this._updateActiveState(this._hovered, false);
|
|
1023
|
-
};
|
|
1024
|
-
|
|
1025
|
-
this._handleMouseEnter = () => {
|
|
1026
|
-
this._updateActiveState(true, this._focused);
|
|
1027
|
-
};
|
|
1028
|
-
|
|
1029
|
-
this._handleMouseLeave = () => {
|
|
1030
|
-
this._updateActiveState(false, this._focused);
|
|
1031
|
-
};
|
|
1032
|
-
|
|
1033
|
-
this._handleKeyUp = e => {
|
|
1034
|
-
// We check the key as that's keyboard layout agnostic and also avoids
|
|
1035
|
-
// the minefield of deprecated number type properties like keyCode and
|
|
1036
|
-
// which, with the replacement code, which uses a string instead.
|
|
1037
|
-
if (e.key === "Escape" && this.state.active) {
|
|
1038
|
-
// Stop the event going any further.
|
|
1039
|
-
// For cancellation events, like the Escape key, we generally should
|
|
1040
|
-
// air on the side of caution and only allow it to cancel one thing.
|
|
1041
|
-
// So, it's polite for us to stop propagation of the event.
|
|
1042
|
-
// Otherwise, we end up with UX where one Escape key press
|
|
1043
|
-
// unexpectedly cancels multiple things.
|
|
1044
|
-
//
|
|
1045
|
-
// For example, using Escape to close a tooltip or a dropdown while
|
|
1046
|
-
// displaying a modal and having the modal close as well. This would
|
|
1047
|
-
// be annoyingly bad UX.
|
|
1048
|
-
e.preventDefault();
|
|
1049
|
-
e.stopPropagation();
|
|
1050
|
-
|
|
1051
|
-
this._updateActiveState(false, false);
|
|
1052
|
-
}
|
|
1053
|
-
};
|
|
1054
|
-
|
|
1055
|
-
this._focused = false;
|
|
1056
|
-
this._hovered = false;
|
|
1057
|
-
this.state = {
|
|
1058
|
-
active: false
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
componentDidMount() {
|
|
1063
|
-
const anchorNode = react_dom__WEBPACK_IMPORTED_MODULE_1__["findDOMNode"](this); // This should never happen, but we have this check here to make flow
|
|
1064
|
-
// happy and ensure that if this does happen, we'll know about it.
|
|
1065
|
-
|
|
1066
|
-
if (anchorNode instanceof Text) {
|
|
1067
|
-
throw new Error("TooltipAnchor must be applied to an Element. Text content is not supported.");
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
this._unsubscribeFromTracker = TRACKER.subscribe(this);
|
|
1071
|
-
this._anchorNode = anchorNode;
|
|
1072
|
-
|
|
1073
|
-
this._updateFocusivity();
|
|
1074
|
-
|
|
1075
|
-
if (anchorNode) {
|
|
1076
|
-
/**
|
|
1077
|
-
* TODO(somewhatabstract): Work out how to allow pointer to go over
|
|
1078
|
-
* the tooltip content to keep it active. This likely requires
|
|
1079
|
-
* pointer events but that would break the obscurement checks we do.
|
|
1080
|
-
* So, careful consideration required. See WB-302.
|
|
1081
|
-
*/
|
|
1082
|
-
anchorNode.addEventListener("focusin", this._handleFocusIn);
|
|
1083
|
-
anchorNode.addEventListener("focusout", this._handleFocusOut);
|
|
1084
|
-
anchorNode.addEventListener("mouseenter", this._handleMouseEnter);
|
|
1085
|
-
anchorNode.addEventListener("mouseleave", this._handleMouseLeave);
|
|
1086
|
-
this.props.anchorRef(this._anchorNode);
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
componentDidUpdate(prevProps) {
|
|
1091
|
-
if (prevProps.forceAnchorFocusivity !== this.props.forceAnchorFocusivity || prevProps.children !== this.props.children) {
|
|
1092
|
-
this._updateFocusivity();
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
componentWillUnmount() {
|
|
1097
|
-
if (this._unsubscribeFromTracker) {
|
|
1098
|
-
this._unsubscribeFromTracker();
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
this._clearPendingAction();
|
|
1102
|
-
|
|
1103
|
-
const anchorNode = this._anchorNode;
|
|
1104
|
-
|
|
1105
|
-
if (anchorNode) {
|
|
1106
|
-
anchorNode.removeEventListener("focusin", this._handleFocusIn);
|
|
1107
|
-
anchorNode.removeEventListener("focusout", this._handleFocusOut);
|
|
1108
|
-
anchorNode.removeEventListener("mouseenter", this._handleMouseEnter);
|
|
1109
|
-
anchorNode.removeEventListener("mouseleave", this._handleMouseLeave);
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
if (this.state.active) {
|
|
1113
|
-
document.removeEventListener("keyup", this._handleKeyUp);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
_updateFocusivity() {
|
|
1118
|
-
const anchorNode = this._anchorNode;
|
|
1119
|
-
|
|
1120
|
-
if (!anchorNode) {
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
const {
|
|
1125
|
-
forceAnchorFocusivity
|
|
1126
|
-
} = this.props;
|
|
1127
|
-
const currentTabIndex = anchorNode.getAttribute("tabindex");
|
|
1128
|
-
|
|
1129
|
-
if (forceAnchorFocusivity && !currentTabIndex) {
|
|
1130
|
-
// Ensure that the anchor point is keyboard focusable so that
|
|
1131
|
-
// we can show the tooltip for visually impaired users that don't
|
|
1132
|
-
// use pointer devices nor assistive technology like screen readers.
|
|
1133
|
-
anchorNode.setAttribute("tabindex", "0");
|
|
1134
|
-
this._weSetFocusivity = true;
|
|
1135
|
-
} else if (!forceAnchorFocusivity && currentTabIndex) {
|
|
1136
|
-
// We may not be forcing it, but we also want to ensure that if we
|
|
1137
|
-
// did before, we remove it.
|
|
1138
|
-
if (this._weSetFocusivity) {
|
|
1139
|
-
anchorNode.removeAttribute("tabindex");
|
|
1140
|
-
this._weSetFocusivity = false;
|
|
1141
|
-
}
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
_updateActiveState(hovered, focused) {
|
|
1146
|
-
// Update our stored values.
|
|
1147
|
-
this._hovered = hovered;
|
|
1148
|
-
this._focused = focused;
|
|
1149
|
-
|
|
1150
|
-
this._setActiveState(hovered || focused);
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
_clearPendingAction() {
|
|
1154
|
-
if (this._timeoutID) {
|
|
1155
|
-
clearTimeout(this._timeoutID);
|
|
1156
|
-
this._timeoutID = null;
|
|
1157
|
-
}
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
_setActiveState(active, instant) {
|
|
1161
|
-
if (this._stolenFromUs || active !== this.state.active || !this.state.active && this._timeoutID) {
|
|
1162
|
-
// If we are about to lose active state or change it, we need to
|
|
1163
|
-
// cancel any pending action to show ourselves.
|
|
1164
|
-
// So, if active is stolen from us, we are changing active state,
|
|
1165
|
-
// or we are inactive and have a timer, clear the action.
|
|
1166
|
-
this._clearPendingAction();
|
|
1167
|
-
} else if (active === this.state.active && !this._timeoutID) {
|
|
1168
|
-
// Nothing to do if we're already active.
|
|
1169
|
-
return;
|
|
1170
|
-
} // Determine if we are doing things immediately or not.
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
instant = instant || active && TRACKER.steal(this);
|
|
1174
|
-
|
|
1175
|
-
if (instant) {
|
|
1176
|
-
if (active) {
|
|
1177
|
-
document.addEventListener("keyup", this._handleKeyUp);
|
|
1178
|
-
} else {
|
|
1179
|
-
document.removeEventListener("keyup", this._handleKeyUp);
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
this.setState({
|
|
1183
|
-
active
|
|
1184
|
-
});
|
|
1185
|
-
this.props.onActiveChanged(active);
|
|
1186
|
-
|
|
1187
|
-
if (!this._stolenFromUs && !active) {
|
|
1188
|
-
// Only the very last thing going inactive will giveup
|
|
1189
|
-
// the stolen active state.
|
|
1190
|
-
TRACKER.giveup();
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
this._stolenFromUs = false;
|
|
1194
|
-
} else {
|
|
1195
|
-
const delay = active ? _util_constants_js__WEBPACK_IMPORTED_MODULE_4__[/* TooltipAppearanceDelay */ "a"] : _util_constants_js__WEBPACK_IMPORTED_MODULE_4__[/* TooltipDisappearanceDelay */ "b"];
|
|
1196
|
-
this._timeoutID = setTimeout(() => {
|
|
1197
|
-
this._timeoutID = null;
|
|
1198
|
-
|
|
1199
|
-
this._setActiveState(active, true);
|
|
1200
|
-
}, delay);
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
_renderAnchorableChildren() {
|
|
1205
|
-
const {
|
|
1206
|
-
children
|
|
1207
|
-
} = this.props;
|
|
1208
|
-
return typeof children === "string" ? /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_2__["Text"], null, children) : children;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
_renderAccessibleChildren(ids) {
|
|
1212
|
-
const anchorableChildren = this._renderAnchorableChildren();
|
|
1213
|
-
|
|
1214
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["cloneElement"](anchorableChildren, {
|
|
1215
|
-
"aria-describedby": ids.get(TooltipAnchor.ariaContentId)
|
|
1216
|
-
});
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
render() {
|
|
1220
|
-
// We need to make sure we can anchor on our content.
|
|
1221
|
-
// If the content is just a string, we wrap it in a Text element
|
|
1222
|
-
// so as not to affect styling or layout but still have an element
|
|
1223
|
-
// to anchor to.
|
|
1224
|
-
if (this.props.ids) {
|
|
1225
|
-
return this._renderAccessibleChildren(this.props.ids);
|
|
1226
|
-
}
|
|
1227
|
-
|
|
1228
|
-
return this._renderAnchorableChildren();
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
}
|
|
1232
|
-
TooltipAnchor.defaultProps = {
|
|
1233
|
-
forceAnchorFocusivity: true
|
|
1234
|
-
};
|
|
1235
|
-
TooltipAnchor.ariaContentId = "aria-content";
|
|
1236
|
-
|
|
1237
|
-
/***/ }),
|
|
1238
|
-
/* 15 */
|
|
1239
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1240
|
-
|
|
1241
|
-
"use strict";
|
|
1242
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ActiveTracker; });
|
|
1243
|
-
/**
|
|
1244
|
-
* This interface should be implemented by types that are interested in the
|
|
1245
|
-
* notifications of active state being stolen. Generally, this would also be
|
|
1246
|
-
* subscribers that may also steal active state, but not necessarily.
|
|
1247
|
-
*
|
|
1248
|
-
* Once implemented, the type must call subscribe on a tracker to begin
|
|
1249
|
-
* receiving notifications.
|
|
1250
|
-
*/
|
|
1251
|
-
|
|
1252
|
-
/**
|
|
1253
|
-
* This class is used to track the concept of active state (though technically
|
|
1254
|
-
* that could be any boolean state). The tracker has a variety of subscribers
|
|
1255
|
-
* that receive notifications of state theft and can steal the state.
|
|
1256
|
-
*
|
|
1257
|
-
* For the tooltip, this enables us to have a single tooltip active at any one
|
|
1258
|
-
* time. The tracker allows tooltip anchors to coordinate which of them is
|
|
1259
|
-
* active, and to ensure that if a different one becomes active, all the others
|
|
1260
|
-
* know that they aren't.
|
|
1261
|
-
*
|
|
1262
|
-
* - When notified that the state has been stolen, subscribers can immediately
|
|
1263
|
-
* reflect that theft (in the case of a tooltip, they would hide themselves).
|
|
1264
|
-
* - The thief does not get notified if they were the one who stole the state
|
|
1265
|
-
* since they should already know that they did that (this avoids having to have
|
|
1266
|
-
* checks for reentrancy, for example).
|
|
1267
|
-
* - When the subscriber that owns the state no longer needs it, it can
|
|
1268
|
-
* voluntarily give it up.
|
|
1269
|
-
* - If the state is stolen while a subscriber owns the
|
|
1270
|
-
* state, that subscriber does not give up the state, as it doesn't have it
|
|
1271
|
-
* anymore (it was stolen).
|
|
1272
|
-
*/
|
|
1273
|
-
class ActiveTracker {
|
|
1274
|
-
constructor() {
|
|
1275
|
-
this._subscribers = [];
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
_getIndex(who) {
|
|
1279
|
-
return this._subscribers.findIndex(v => v === who);
|
|
1280
|
-
}
|
|
1281
|
-
/**
|
|
1282
|
-
* Called when a tooltip anchor becomes active so that it can tell all other
|
|
1283
|
-
* anchors that they are no longer the active tooltip. Returns true if
|
|
1284
|
-
* the there was a steal of active state from another anchor; otherwise, if
|
|
1285
|
-
* no other anchor had been active, returns false.
|
|
1286
|
-
*/
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
steal(who) {
|
|
1290
|
-
const wasActive = !!this._active;
|
|
1291
|
-
this._active = true;
|
|
1292
|
-
|
|
1293
|
-
for (const anchor of this._subscribers) {
|
|
1294
|
-
if (anchor === who) {
|
|
1295
|
-
// We don't need to notify the thief.
|
|
1296
|
-
continue;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
anchor.activeStateStolen();
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
return wasActive;
|
|
1303
|
-
}
|
|
1304
|
-
/**
|
|
1305
|
-
* Called if a tooltip doesn't want to be active anymore.
|
|
1306
|
-
* Should not be called when being told the active spot was stolen by
|
|
1307
|
-
* another anchor, only when the anchor is unhovered and unfocused and they
|
|
1308
|
-
* were active.
|
|
1309
|
-
*/
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
giveup() {
|
|
1313
|
-
this._active = false;
|
|
1314
|
-
}
|
|
1315
|
-
/**
|
|
1316
|
-
* Subscribes a tooltip anchor to the tracker so that it can be notified of
|
|
1317
|
-
* steals. Returns a method that can be used to unsubscribe the anchor from
|
|
1318
|
-
* notifications.
|
|
1319
|
-
*/
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
subscribe(who) {
|
|
1323
|
-
if (this._getIndex(who) >= 0) {
|
|
1324
|
-
throw new Error("Already subscribed.");
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
this._subscribers.push(who);
|
|
1328
|
-
|
|
1329
|
-
const unsubscribe = () => {
|
|
1330
|
-
const index = this._getIndex(who);
|
|
1331
|
-
|
|
1332
|
-
this._subscribers.splice(index, 1);
|
|
1333
|
-
};
|
|
1334
|
-
|
|
1335
|
-
return unsubscribe;
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
/***/ }),
|
|
1341
|
-
/* 16 */
|
|
1342
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1343
|
-
|
|
1344
|
-
"use strict";
|
|
1345
|
-
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TooltipBubble; });
|
|
1346
|
-
/* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4);
|
|
1347
|
-
/* harmony import */ var aphrodite__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(aphrodite__WEBPACK_IMPORTED_MODULE_0__);
|
|
1348
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
|
|
1349
|
-
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
|
|
1350
|
-
/* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2);
|
|
1351
|
-
/* harmony import */ var _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2__);
|
|
1352
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3);
|
|
1353
|
-
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__);
|
|
1354
|
-
/* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1);
|
|
1355
|
-
/* harmony import */ var _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4__);
|
|
1356
|
-
/* harmony import */ var _tooltip_tail_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(6);
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
class TooltipBubble extends react__WEBPACK_IMPORTED_MODULE_1__["Component"] {
|
|
1364
|
-
constructor(...args) {
|
|
1365
|
-
super(...args);
|
|
1366
|
-
this.state = {
|
|
1367
|
-
active: false
|
|
1368
|
-
};
|
|
1369
|
-
|
|
1370
|
-
this.handleMouseEnter = () => {
|
|
1371
|
-
this._setActiveState(true);
|
|
1372
|
-
};
|
|
1373
|
-
|
|
1374
|
-
this.handleMouseLeave = () => {
|
|
1375
|
-
this.props.onActiveChanged(false);
|
|
1376
|
-
};
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
_setActiveState(active) {
|
|
1380
|
-
this.setState({
|
|
1381
|
-
active
|
|
1382
|
-
});
|
|
1383
|
-
this.props.onActiveChanged(active);
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
render() {
|
|
1387
|
-
const {
|
|
1388
|
-
id,
|
|
1389
|
-
children,
|
|
1390
|
-
updateBubbleRef,
|
|
1391
|
-
placement,
|
|
1392
|
-
isReferenceHidden,
|
|
1393
|
-
style,
|
|
1394
|
-
updateTailRef,
|
|
1395
|
-
tailOffset
|
|
1396
|
-
} = this.props;
|
|
1397
|
-
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
|
|
1398
|
-
id: id,
|
|
1399
|
-
role: "tooltip",
|
|
1400
|
-
"data-placement": placement,
|
|
1401
|
-
onMouseEnter: this.handleMouseEnter,
|
|
1402
|
-
onMouseLeave: this.handleMouseLeave,
|
|
1403
|
-
ref: updateBubbleRef,
|
|
1404
|
-
style: [isReferenceHidden && styles.hide, styles.bubble, styles[`content-${placement}`], style]
|
|
1405
|
-
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
|
|
1406
|
-
style: styles.content
|
|
1407
|
-
}, children), /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_tooltip_tail_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"], {
|
|
1408
|
-
updateRef: updateTailRef,
|
|
1409
|
-
placement: placement,
|
|
1410
|
-
offset: tailOffset
|
|
1411
|
-
}));
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
}
|
|
1415
|
-
const styles = aphrodite__WEBPACK_IMPORTED_MODULE_0__["StyleSheet"].create({
|
|
1416
|
-
bubble: {
|
|
1417
|
-
position: "absolute"
|
|
1418
|
-
},
|
|
1419
|
-
|
|
1420
|
-
/**
|
|
1421
|
-
* The hide style ensures that the bounds of the bubble stay unchanged.
|
|
1422
|
-
* This is because popper.js calculates the bubble position based off its
|
|
1423
|
-
* bounds and if we stopped rendering it entirely, it wouldn't know where to
|
|
1424
|
-
* place it when it reappeared.
|
|
1425
|
-
*/
|
|
1426
|
-
hide: {
|
|
1427
|
-
pointerEvents: "none",
|
|
1428
|
-
opacity: 0,
|
|
1429
|
-
backgroundColor: "transparent",
|
|
1430
|
-
color: "transparent"
|
|
1431
|
-
},
|
|
1432
|
-
|
|
1433
|
-
/**
|
|
1434
|
-
* Ensure the content and tail are properly arranged.
|
|
1435
|
-
*/
|
|
1436
|
-
"content-top": {
|
|
1437
|
-
flexDirection: "column"
|
|
1438
|
-
},
|
|
1439
|
-
"content-right": {
|
|
1440
|
-
flexDirection: "row-reverse"
|
|
1441
|
-
},
|
|
1442
|
-
"content-bottom": {
|
|
1443
|
-
flexDirection: "column-reverse"
|
|
1444
|
-
},
|
|
1445
|
-
"content-left": {
|
|
1446
|
-
flexDirection: "row"
|
|
1447
|
-
},
|
|
1448
|
-
content: {
|
|
1449
|
-
maxWidth: 472,
|
|
1450
|
-
borderRadius: _khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xxxSmall_4,
|
|
1451
|
-
border: `solid 1px ${_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack16}`,
|
|
1452
|
-
backgroundColor: _khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.white,
|
|
1453
|
-
boxShadow: `0 ${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8}px ${_khanacademy_wonder_blocks_spacing__WEBPACK_IMPORTED_MODULE_4___default.a.xSmall_8}px 0 ${_khanacademy_wonder_blocks_color__WEBPACK_IMPORTED_MODULE_2___default.a.offBlack8}`,
|
|
1454
|
-
justifyContent: "center"
|
|
1455
|
-
}
|
|
1456
|
-
});
|
|
1457
|
-
|
|
1458
|
-
/***/ }),
|
|
1459
|
-
/* 17 */
|
|
1460
|
-
/***/ (function(module, exports) {
|
|
1461
|
-
|
|
1462
|
-
module.exports = require("@khanacademy/wonder-blocks-layout");
|
|
1463
|
-
|
|
1464
|
-
/***/ }),
|
|
1465
|
-
/* 18 */
|
|
1466
|
-
/***/ (function(module, exports) {
|
|
1467
|
-
|
|
1468
|
-
module.exports = require("react-popper");
|
|
1469
|
-
|
|
1470
|
-
/***/ }),
|
|
1471
|
-
/* 19 */
|
|
1472
|
-
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1473
|
-
|
|
1474
|
-
"use strict";
|
|
1475
|
-
__webpack_require__.r(__webpack_exports__);
|
|
1476
|
-
/* harmony import */ var _components_tooltip_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(12);
|
|
1477
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "default", function() { return _components_tooltip_js__WEBPACK_IMPORTED_MODULE_0__["a"]; });
|
|
1478
|
-
|
|
1479
|
-
/* harmony import */ var _components_tooltip_content_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
|
|
1480
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "TooltipContent", function() { return _components_tooltip_content_js__WEBPACK_IMPORTED_MODULE_1__["a"]; });
|
|
1481
|
-
|
|
1482
|
-
/* harmony import */ var _components_tooltip_popper_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8);
|
|
1483
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "TooltipPopper", function() { return _components_tooltip_popper_js__WEBPACK_IMPORTED_MODULE_2__["a"]; });
|
|
1484
|
-
|
|
1485
|
-
/* harmony import */ var _components_tooltip_tail_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6);
|
|
1486
|
-
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "TooltipTail", function() { return _components_tooltip_tail_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
/***/ })
|
|
1495
|
-
/******/ ]);
|