@workday/canvas-kit-react 9.0.8 → 9.0.10
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/dist/commonjs/popup/lib/Popper.d.ts +12 -4
- package/dist/commonjs/popup/lib/Popper.d.ts.map +1 -1
- package/dist/commonjs/popup/lib/Popper.js +34 -10
- package/dist/commonjs/popup/lib/PopupPopper.d.ts +7 -0
- package/dist/commonjs/popup/lib/PopupPopper.d.ts.map +1 -1
- package/dist/commonjs/popup/lib/fallbackPlacements.d.ts +9 -0
- package/dist/commonjs/popup/lib/fallbackPlacements.d.ts.map +1 -0
- package/dist/commonjs/popup/lib/fallbackPlacements.js +75 -0
- package/dist/commonjs/popup/lib/hooks/usePopupPopper.d.ts.map +1 -1
- package/dist/commonjs/popup/lib/hooks/usePopupPopper.js +5 -2
- package/dist/commonjs/tooltip/lib/OverflowTooltip.d.ts +8 -1
- package/dist/commonjs/tooltip/lib/OverflowTooltip.d.ts.map +1 -1
- package/dist/commonjs/tooltip/lib/OverflowTooltip.js +2 -2
- package/dist/commonjs/tooltip/lib/Tooltip.d.ts +7 -0
- package/dist/commonjs/tooltip/lib/Tooltip.d.ts.map +1 -1
- package/dist/commonjs/tooltip/lib/Tooltip.js +2 -2
- package/dist/es6/popup/lib/Popper.d.ts +12 -4
- package/dist/es6/popup/lib/Popper.d.ts.map +1 -1
- package/dist/es6/popup/lib/Popper.js +33 -9
- package/dist/es6/popup/lib/PopupPopper.d.ts +7 -0
- package/dist/es6/popup/lib/PopupPopper.d.ts.map +1 -1
- package/dist/es6/popup/lib/fallbackPlacements.d.ts +9 -0
- package/dist/es6/popup/lib/fallbackPlacements.d.ts.map +1 -0
- package/dist/es6/popup/lib/fallbackPlacements.js +72 -0
- package/dist/es6/popup/lib/hooks/usePopupPopper.d.ts.map +1 -1
- package/dist/es6/popup/lib/hooks/usePopupPopper.js +5 -2
- package/dist/es6/tooltip/lib/OverflowTooltip.d.ts +8 -1
- package/dist/es6/tooltip/lib/OverflowTooltip.d.ts.map +1 -1
- package/dist/es6/tooltip/lib/OverflowTooltip.js +3 -3
- package/dist/es6/tooltip/lib/Tooltip.d.ts +7 -0
- package/dist/es6/tooltip/lib/Tooltip.d.ts.map +1 -1
- package/dist/es6/tooltip/lib/Tooltip.js +3 -3
- package/package.json +3 -3
- package/popup/lib/Popper.tsx +45 -12
- package/popup/lib/PopupPopper.tsx +7 -0
- package/popup/lib/fallbackPlacements.ts +98 -0
- package/popup/lib/hooks/usePopupPopper.ts +6 -2
- package/tooltip/lib/OverflowTooltip.tsx +15 -2
- package/tooltip/lib/Tooltip.tsx +15 -2
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import
|
|
3
|
-
export declare type Placement = `${
|
|
4
|
-
export declare type PopperOptions =
|
|
2
|
+
import { Placement as PopperJSPlacement, Options, Instance } from '@popperjs/core';
|
|
3
|
+
export declare type Placement = `${PopperJSPlacement}`;
|
|
4
|
+
export declare type PopperOptions = Options;
|
|
5
|
+
export declare const defaultFallbackPlacements: Placement[];
|
|
5
6
|
export interface PopperProps {
|
|
6
7
|
/**
|
|
7
8
|
* The reference element used to position the Popper. Popper content will try to follow the
|
|
@@ -39,6 +40,13 @@ export interface PopperProps {
|
|
|
39
40
|
* @default bottom
|
|
40
41
|
*/
|
|
41
42
|
placement?: Placement;
|
|
43
|
+
/**
|
|
44
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
45
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
46
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
47
|
+
* disable the fallback placements.
|
|
48
|
+
*/
|
|
49
|
+
fallbackPlacements?: Placement[];
|
|
42
50
|
/**
|
|
43
51
|
* A callback function that will be called whenever PopperJS chooses a placement that is different
|
|
44
52
|
* from the provided `placement` preference. If a `placement` preference doesn't fit, PopperJS
|
|
@@ -61,7 +69,7 @@ export interface PopperProps {
|
|
|
61
69
|
* Reference to the PopperJS instance. Useful for making direct method calls on the popper
|
|
62
70
|
* instance like `update`.
|
|
63
71
|
*/
|
|
64
|
-
popperInstanceRef?: React.Ref<
|
|
72
|
+
popperInstanceRef?: React.Ref<Instance>;
|
|
65
73
|
}
|
|
66
74
|
/**
|
|
67
75
|
* A thin wrapper component around the Popper.js positioning engine. For reference:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/Popper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,
|
|
1
|
+
{"version":3,"file":"Popper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/Popper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,SAAS,IAAI,iBAAiB,EAAE,OAAO,EAAE,QAAQ,EAA0B,MAAM,gBAAgB,CAAC;AAE3G,oBAAY,SAAS,GAAG,GAAG,iBAAiB,EAAE,CAAC;AAC/C,oBAAY,aAAa,GAAG,OAAO,CAAC;AACpC,eAAO,MAAM,yBAAyB,EAAE,SAAS,EAAuC,CAAC;AAMzF,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;IAC1D;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE;QAAC,SAAS,EAAE,SAAS,CAAA;KAAC,KAAK,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;IACjF;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;IACpC;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACvC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,oFAQlB,CAAC"}
|
|
@@ -19,12 +19,14 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.Popper = void 0;
|
|
22
|
+
exports.Popper = exports.defaultFallbackPlacements = void 0;
|
|
23
23
|
const React = __importStar(require("react"));
|
|
24
24
|
const ReactDOM = __importStar(require("react-dom"));
|
|
25
|
-
const
|
|
25
|
+
const core_1 = require("@popperjs/core");
|
|
26
|
+
exports.defaultFallbackPlacements = ['top', 'right', 'bottom', 'left'];
|
|
26
27
|
const hooks_1 = require("./hooks");
|
|
27
28
|
const common_1 = require("@workday/canvas-kit-react/common");
|
|
29
|
+
const fallbackPlacements_1 = require("./fallbackPlacements");
|
|
28
30
|
/**
|
|
29
31
|
* A thin wrapper component around the Popper.js positioning engine. For reference:
|
|
30
32
|
* https://popper.js.org/. `Popper` also automatically works with the {@link PopupStack} system.
|
|
@@ -61,19 +63,23 @@ const getElementFromRefOrElement = (input) => {
|
|
|
61
63
|
const defaultPopperOptions = {};
|
|
62
64
|
// Popper bails early if `open` is false and React hooks cannot be called conditionally,
|
|
63
65
|
// so we're breaking out the open version into another component.
|
|
64
|
-
const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, popperOptions = defaultPopperOptions, placement: popperPlacement = 'bottom', onPlacementChange, children, portal, popperInstanceRef, }, ref) => {
|
|
66
|
+
const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, popperOptions = defaultPopperOptions, placement: popperPlacement = 'bottom', fallbackPlacements = exports.defaultFallbackPlacements, onPlacementChange, children, portal, popperInstanceRef, }, ref) => {
|
|
65
67
|
const firstRender = React.useRef(true);
|
|
66
68
|
const { localRef, elementRef } = common_1.useLocalRef(popperInstanceRef);
|
|
67
69
|
const [placement, setPlacement] = React.useState(popperPlacement);
|
|
68
70
|
const stackRef = hooks_1.usePopupStack(ref, anchorElement);
|
|
71
|
+
const placementRef = React.useRef(popperPlacement);
|
|
72
|
+
placementRef.current = placement;
|
|
69
73
|
const placementModifier = React.useMemo(() => {
|
|
70
74
|
return {
|
|
71
75
|
name: 'setPlacement',
|
|
72
76
|
enabled: true,
|
|
73
|
-
phase: '
|
|
77
|
+
phase: 'afterWrite',
|
|
74
78
|
fn({ state }) {
|
|
75
|
-
|
|
76
|
-
|
|
79
|
+
if (placementRef.current !== state.placement) {
|
|
80
|
+
setPlacement(state.placement);
|
|
81
|
+
onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement);
|
|
82
|
+
}
|
|
77
83
|
},
|
|
78
84
|
};
|
|
79
85
|
}, [setPlacement, onPlacementChange]);
|
|
@@ -87,10 +93,19 @@ const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, poppe
|
|
|
87
93
|
return undefined;
|
|
88
94
|
}
|
|
89
95
|
if (stackRef.current) {
|
|
90
|
-
const instance =
|
|
96
|
+
const instance = core_1.createPopper(anchorEl, stackRef.current, {
|
|
91
97
|
placement: popperPlacement,
|
|
92
98
|
...popperOptions,
|
|
93
|
-
modifiers: [
|
|
99
|
+
modifiers: [
|
|
100
|
+
placementModifier,
|
|
101
|
+
{
|
|
102
|
+
...fallbackPlacements_1.fallbackPlacementsModifier,
|
|
103
|
+
options: {
|
|
104
|
+
fallbackPlacements,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
...(popperOptions.modifiers || []),
|
|
108
|
+
],
|
|
94
109
|
});
|
|
95
110
|
elementRef(instance); // update the ref with the instance
|
|
96
111
|
return () => {
|
|
@@ -110,11 +125,20 @@ const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, poppe
|
|
|
110
125
|
(_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions({
|
|
111
126
|
placement: popperPlacement,
|
|
112
127
|
...popperOptions,
|
|
113
|
-
modifiers: [
|
|
128
|
+
modifiers: [
|
|
129
|
+
placementModifier,
|
|
130
|
+
{
|
|
131
|
+
...fallbackPlacements_1.fallbackPlacementsModifier,
|
|
132
|
+
options: {
|
|
133
|
+
fallbackPlacements,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
...(popperOptions.modifiers || []),
|
|
137
|
+
],
|
|
114
138
|
});
|
|
115
139
|
}
|
|
116
140
|
firstRender.current = false;
|
|
117
|
-
}, [popperOptions, popperPlacement, placementModifier, localRef]);
|
|
141
|
+
}, [popperOptions, popperPlacement, fallbackPlacements, placementModifier, localRef]);
|
|
118
142
|
const contents = React.createElement(React.Fragment, null, isRenderProp(children) ? children({ placement }) : children);
|
|
119
143
|
if (!portal) {
|
|
120
144
|
return contents;
|
|
@@ -8,6 +8,13 @@ export interface PopupPopperProps extends PopperProps {
|
|
|
8
8
|
* @default bottom
|
|
9
9
|
*/
|
|
10
10
|
placement?: Placement;
|
|
11
|
+
/**
|
|
12
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
13
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
14
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
15
|
+
* disable the fallback placements.
|
|
16
|
+
*/
|
|
17
|
+
fallbackPlacements?: Placement[];
|
|
11
18
|
/**
|
|
12
19
|
* The additional options passed to the Popper's `popper.js` instance.
|
|
13
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PopupPopper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/PopupPopper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,EAAC,SAAS,EAAE,aAAa,EAAU,WAAW,EAAC,MAAM,UAAU,CAAC;AAEvE,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;EAMtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"PopupPopper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/PopupPopper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,EAAC,SAAS,EAAE,aAAa,EAAU,WAAW,EAAC,MAAM,UAAU,CAAC;AAEvE,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;EAMtB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Placement as PopperJSPlacement, Modifier } from '@popperjs/core';
|
|
2
|
+
export declare type Placement = PopperJSPlacement;
|
|
3
|
+
export declare type Options = {
|
|
4
|
+
fallbackPlacements: Placement[];
|
|
5
|
+
};
|
|
6
|
+
declare const name = "fallbackModifier";
|
|
7
|
+
export declare const fallbackPlacementsModifier: Modifier<typeof name, Options>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=fallbackPlacements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallbackPlacements.d.ts","sourceRoot":"","sources":["../../../../popup/lib/fallbackPlacements.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,IAAI,iBAAiB,EAK9B,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAExB,oBAAY,SAAS,GAAG,iBAAiB,CAAC;AAyD1C,oBAAY,OAAO,GAAG;IACpB,kBAAkB,EAAE,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,QAAA,MAAM,IAAI,qBAAqB,CAAC;AAEhC,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,OAAO,IAAI,EAAE,OAAO,CAwBrE,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fallbackPlacementsModifier = void 0;
|
|
4
|
+
const core_1 = require("@popperjs/core");
|
|
5
|
+
const getOppositePlacement = (popperPlacement) => {
|
|
6
|
+
var _a;
|
|
7
|
+
const [first, second] = popperPlacement.split('-');
|
|
8
|
+
let oppositePlacement;
|
|
9
|
+
switch (first) {
|
|
10
|
+
case 'top':
|
|
11
|
+
oppositePlacement = 'bottom';
|
|
12
|
+
break;
|
|
13
|
+
case 'bottom':
|
|
14
|
+
oppositePlacement = 'top';
|
|
15
|
+
break;
|
|
16
|
+
case 'left':
|
|
17
|
+
oppositePlacement = 'right';
|
|
18
|
+
break;
|
|
19
|
+
case 'right':
|
|
20
|
+
oppositePlacement = 'left';
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
oppositePlacement = 'auto';
|
|
24
|
+
}
|
|
25
|
+
if (second) {
|
|
26
|
+
oppositePlacement =
|
|
27
|
+
(_a = core_1.placements.find(placement => placement.includes(`${oppositePlacement}-${second}`))) !== null && _a !== void 0 ? _a : oppositePlacement;
|
|
28
|
+
}
|
|
29
|
+
return oppositePlacement;
|
|
30
|
+
};
|
|
31
|
+
const choseAvailablePlacement = (placements, state, preferredPlacement) => {
|
|
32
|
+
if (placements.length === 0 || placements[0].split('-')[0] === 'auto') {
|
|
33
|
+
return preferredPlacement;
|
|
34
|
+
}
|
|
35
|
+
const { reference, popper } = state.rects;
|
|
36
|
+
const overflow = core_1.detectOverflow({ ...state, placement: placements[0] });
|
|
37
|
+
const direction = /left|right/.test(placements[0].split('-')[0]) ? 'horizontal' : 'vertical';
|
|
38
|
+
const isOverflowed = (overflow.top > 0 || overflow.bottom > 0 || overflow.left > 0 || overflow.right > 0) &&
|
|
39
|
+
(direction === 'horizontal'
|
|
40
|
+
? popper.height / 2 - overflow.top < reference.height ||
|
|
41
|
+
popper.height / 2 - overflow.bottom < reference.height
|
|
42
|
+
: popper.width - overflow.left < reference.width ||
|
|
43
|
+
popper.width - overflow.right < reference.width);
|
|
44
|
+
const key = placements[0].split('-')[0];
|
|
45
|
+
if (!isOverflowed && overflow[key] <= 0) {
|
|
46
|
+
return placements[0];
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
return choseAvailablePlacement(placements.slice(1), state, preferredPlacement);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
const name = 'fallbackModifier';
|
|
53
|
+
exports.fallbackPlacementsModifier = {
|
|
54
|
+
name: name,
|
|
55
|
+
enabled: true,
|
|
56
|
+
phase: 'main',
|
|
57
|
+
data: {
|
|
58
|
+
_skip: false,
|
|
59
|
+
},
|
|
60
|
+
fn({ state, options }) {
|
|
61
|
+
const preferredPlacement = state.options.placement;
|
|
62
|
+
const { fallbackPlacements } = options;
|
|
63
|
+
const placements = [
|
|
64
|
+
preferredPlacement,
|
|
65
|
+
getOppositePlacement(preferredPlacement),
|
|
66
|
+
...(fallbackPlacements || []),
|
|
67
|
+
];
|
|
68
|
+
const placementOverride = choseAvailablePlacement(placements, state, preferredPlacement);
|
|
69
|
+
if (state.placement !== placementOverride) {
|
|
70
|
+
state.modifiersData[name]._skip = true;
|
|
71
|
+
state.placement = placementOverride;
|
|
72
|
+
state.reset = true;
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupPopper.d.ts","sourceRoot":"","sources":["../../../../../popup/lib/hooks/usePopupPopper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"usePopupPopper.d.ts","sourceRoot":"","sources":["../../../../../popup/lib/hooks/usePopupPopper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;mCAOX,SAAS;EAevB,CAAC"}
|
|
@@ -13,12 +13,15 @@ const react_1 = __importDefault(require("react"));
|
|
|
13
13
|
*/
|
|
14
14
|
exports.usePopupPopper = common_1.createElemPropsHook(usePopupModel_1.usePopupModel)(({ state, events }, ref) => {
|
|
15
15
|
const elementRef = common_1.useForkRef(ref, state.stackRef);
|
|
16
|
+
// Create a mutable ref of the placement to keep a stable `onPlacementChange` reference.
|
|
17
|
+
const placementRef = react_1.default.useRef(state.placement);
|
|
18
|
+
placementRef.current = state.placement;
|
|
16
19
|
const onPlacementChange = react_1.default.useCallback((placement) => {
|
|
17
|
-
if (placement !==
|
|
20
|
+
if (placement !== placementRef.current) {
|
|
18
21
|
// only update if the placement has changed
|
|
19
22
|
events.updatePlacement({ placement });
|
|
20
23
|
}
|
|
21
|
-
}, [events
|
|
24
|
+
}, [events]);
|
|
22
25
|
return {
|
|
23
26
|
open: state.visibility !== 'hidden',
|
|
24
27
|
anchorElement: state.targetRef,
|
|
@@ -25,6 +25,13 @@ export interface OverflowTooltipProps extends Omit<React.HTMLAttributes<HTMLDivE
|
|
|
25
25
|
* @default 'top'
|
|
26
26
|
*/
|
|
27
27
|
placement?: Placement;
|
|
28
|
+
/**
|
|
29
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
30
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
31
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
32
|
+
* disable the fallback placements.
|
|
33
|
+
*/
|
|
34
|
+
fallbackPlacements?: Placement[];
|
|
28
35
|
}
|
|
29
|
-
export declare const OverflowTooltip: ({ placement, children, ...elemProps }: OverflowTooltipProps) => JSX.Element;
|
|
36
|
+
export declare const OverflowTooltip: ({ placement, fallbackPlacements, children, ...elemProps }: OverflowTooltipProps) => JSX.Element;
|
|
30
37
|
//# sourceMappingURL=OverflowTooltip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverflowTooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/OverflowTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,
|
|
1
|
+
{"version":3,"file":"OverflowTooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/OverflowTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAEL,SAAS,EAGV,MAAM,iCAAiC,CAAC;AAMzC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,YAAa,OAAO,KAAG,OAAO,GAAG,IAmBhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,YAAa,OAAO,KAAG,OAAO,GAAG,IAahE,CAAC;AAcF,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAC/F;;;;;;;OAOG;IACH,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;CAClC;AAiBD,eAAO,MAAM,eAAe,8DAKzB,oBAAoB,gBAwCtB,CAAC"}
|
|
@@ -88,7 +88,7 @@ function mergeCallbacks(elemProps, componentProps, keys = Object.keys(componentP
|
|
|
88
88
|
return mergedProps;
|
|
89
89
|
}, {});
|
|
90
90
|
}
|
|
91
|
-
const OverflowTooltip = ({ placement = 'top', children, ...elemProps }) => {
|
|
91
|
+
const OverflowTooltip = ({ placement = 'top', fallbackPlacements = popup_1.defaultFallbackPlacements, children, ...elemProps }) => {
|
|
92
92
|
const [titleText, setTitleText] = React.useState('');
|
|
93
93
|
const { targetProps, popperProps, tooltipProps } = useTooltip_1.useTooltip({ type: 'muted' });
|
|
94
94
|
const onMouseEnter = (event) => {
|
|
@@ -113,7 +113,7 @@ const OverflowTooltip = ({ placement = 'top', children, ...elemProps }) => {
|
|
|
113
113
|
'aria-label': undefined,
|
|
114
114
|
...mergeCallbacks({ ...targetProps, onMouseEnter, onFocus }, children.props),
|
|
115
115
|
}),
|
|
116
|
-
React.createElement(popup_1.Popper, Object.assign({ placement: placement }, popperProps), ({ placement }) => {
|
|
116
|
+
React.createElement(popup_1.Popper, Object.assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), ({ placement }) => {
|
|
117
117
|
const transformOrigin = popup_1.getTransformFromPlacement(placement);
|
|
118
118
|
return (React.createElement(TooltipContainer_1.TooltipContainer, Object.assign({ transformOrigin: transformOrigin }, tooltipProps, elemProps), titleText));
|
|
119
119
|
})));
|
|
@@ -20,6 +20,13 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
20
20
|
* @default 'top'
|
|
21
21
|
*/
|
|
22
22
|
placement?: Placement;
|
|
23
|
+
/**
|
|
24
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
25
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
26
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
27
|
+
* disable the fallback placements.
|
|
28
|
+
*/
|
|
29
|
+
fallbackPlacements?: Placement[];
|
|
23
30
|
/**
|
|
24
31
|
* Determines the tooltip type for accessibility.
|
|
25
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAEL,SAAS,EAGV,MAAM,iCAAiC,CAAC;AAMzC,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACvF;;;OAGG;IACH,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB;;;;;;;OAOG;IACH,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IACtC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiBD,eAAO,MAAM,OAAO,kFA0ClB,CAAC"}
|
|
@@ -42,7 +42,7 @@ function mergeCallbacks(elemProps, componentProps, keys = Object.keys(componentP
|
|
|
42
42
|
}
|
|
43
43
|
exports.Tooltip = common_1.createComponent('div')({
|
|
44
44
|
displayName: 'Tooltip',
|
|
45
|
-
Component({ type = 'label', placement = 'top', title, children, showDelay = 300, hideDelay = 100, ...elemProps }) {
|
|
45
|
+
Component({ type = 'label', placement = 'top', title, children, showDelay = 300, hideDelay = 100, fallbackPlacements = popup_1.defaultFallbackPlacements, ...elemProps }) {
|
|
46
46
|
const titleText = react_innertext_1.default(title);
|
|
47
47
|
const { targetProps, popperProps, tooltipProps } = useTooltip_1.useTooltip({
|
|
48
48
|
type,
|
|
@@ -58,7 +58,7 @@ exports.Tooltip = common_1.createComponent('div')({
|
|
|
58
58
|
? { 'aria-label': children.props['aria-label'] }
|
|
59
59
|
: {}),
|
|
60
60
|
}),
|
|
61
|
-
React.createElement(popup_1.Popper, Object.assign({ placement: placement }, popperProps), ({ placement }) => {
|
|
61
|
+
React.createElement(popup_1.Popper, Object.assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), ({ placement }) => {
|
|
62
62
|
const transformOrigin = popup_1.getTransformFromPlacement(placement);
|
|
63
63
|
return (React.createElement(TooltipContainer_1.TooltipContainer, Object.assign({ transformOrigin: transformOrigin }, elemProps, tooltipProps), title));
|
|
64
64
|
})));
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import
|
|
3
|
-
export declare type Placement = `${
|
|
4
|
-
export declare type PopperOptions =
|
|
2
|
+
import { Placement as PopperJSPlacement, Options, Instance } from '@popperjs/core';
|
|
3
|
+
export declare type Placement = `${PopperJSPlacement}`;
|
|
4
|
+
export declare type PopperOptions = Options;
|
|
5
|
+
export declare const defaultFallbackPlacements: Placement[];
|
|
5
6
|
export interface PopperProps {
|
|
6
7
|
/**
|
|
7
8
|
* The reference element used to position the Popper. Popper content will try to follow the
|
|
@@ -39,6 +40,13 @@ export interface PopperProps {
|
|
|
39
40
|
* @default bottom
|
|
40
41
|
*/
|
|
41
42
|
placement?: Placement;
|
|
43
|
+
/**
|
|
44
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
45
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
46
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
47
|
+
* disable the fallback placements.
|
|
48
|
+
*/
|
|
49
|
+
fallbackPlacements?: Placement[];
|
|
42
50
|
/**
|
|
43
51
|
* A callback function that will be called whenever PopperJS chooses a placement that is different
|
|
44
52
|
* from the provided `placement` preference. If a `placement` preference doesn't fit, PopperJS
|
|
@@ -61,7 +69,7 @@ export interface PopperProps {
|
|
|
61
69
|
* Reference to the PopperJS instance. Useful for making direct method calls on the popper
|
|
62
70
|
* instance like `update`.
|
|
63
71
|
*/
|
|
64
|
-
popperInstanceRef?: React.Ref<
|
|
72
|
+
popperInstanceRef?: React.Ref<Instance>;
|
|
65
73
|
}
|
|
66
74
|
/**
|
|
67
75
|
* A thin wrapper component around the Popper.js positioning engine. For reference:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Popper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/Popper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,
|
|
1
|
+
{"version":3,"file":"Popper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/Popper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,SAAS,IAAI,iBAAiB,EAAE,OAAO,EAAE,QAAQ,EAA0B,MAAM,gBAAgB,CAAC;AAE3G,oBAAY,SAAS,GAAG,GAAG,iBAAiB,EAAE,CAAC;AAC/C,oBAAY,aAAa,GAAG,OAAO,CAAC;AACpC,eAAO,MAAM,yBAAyB,EAAE,SAAS,EAAuC,CAAC;AAMzF,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;IAC1D;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE;QAAC,SAAS,EAAE,SAAS,CAAA;KAAC,KAAK,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC;IACjF;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,OAAO,CAAC;IACpC;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACvC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;CACzC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,oFAQlB,CAAC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as ReactDOM from 'react-dom';
|
|
3
|
-
import
|
|
3
|
+
import { createPopper } from '@popperjs/core';
|
|
4
|
+
export const defaultFallbackPlacements = ['top', 'right', 'bottom', 'left'];
|
|
4
5
|
import { usePopupStack } from './hooks';
|
|
5
6
|
import { useLocalRef } from '@workday/canvas-kit-react/common';
|
|
7
|
+
import { fallbackPlacementsModifier } from './fallbackPlacements';
|
|
6
8
|
/**
|
|
7
9
|
* A thin wrapper component around the Popper.js positioning engine. For reference:
|
|
8
10
|
* https://popper.js.org/. `Popper` also automatically works with the {@link PopupStack} system.
|
|
@@ -39,19 +41,23 @@ const getElementFromRefOrElement = (input) => {
|
|
|
39
41
|
const defaultPopperOptions = {};
|
|
40
42
|
// Popper bails early if `open` is false and React hooks cannot be called conditionally,
|
|
41
43
|
// so we're breaking out the open version into another component.
|
|
42
|
-
const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, popperOptions = defaultPopperOptions, placement: popperPlacement = 'bottom', onPlacementChange, children, portal, popperInstanceRef, }, ref) => {
|
|
44
|
+
const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, popperOptions = defaultPopperOptions, placement: popperPlacement = 'bottom', fallbackPlacements = defaultFallbackPlacements, onPlacementChange, children, portal, popperInstanceRef, }, ref) => {
|
|
43
45
|
const firstRender = React.useRef(true);
|
|
44
46
|
const { localRef, elementRef } = useLocalRef(popperInstanceRef);
|
|
45
47
|
const [placement, setPlacement] = React.useState(popperPlacement);
|
|
46
48
|
const stackRef = usePopupStack(ref, anchorElement);
|
|
49
|
+
const placementRef = React.useRef(popperPlacement);
|
|
50
|
+
placementRef.current = placement;
|
|
47
51
|
const placementModifier = React.useMemo(() => {
|
|
48
52
|
return {
|
|
49
53
|
name: 'setPlacement',
|
|
50
54
|
enabled: true,
|
|
51
|
-
phase: '
|
|
55
|
+
phase: 'afterWrite',
|
|
52
56
|
fn({ state }) {
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
if (placementRef.current !== state.placement) {
|
|
58
|
+
setPlacement(state.placement);
|
|
59
|
+
onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement);
|
|
60
|
+
}
|
|
55
61
|
},
|
|
56
62
|
};
|
|
57
63
|
}, [setPlacement, onPlacementChange]);
|
|
@@ -65,10 +71,19 @@ const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, poppe
|
|
|
65
71
|
return undefined;
|
|
66
72
|
}
|
|
67
73
|
if (stackRef.current) {
|
|
68
|
-
const instance =
|
|
74
|
+
const instance = createPopper(anchorEl, stackRef.current, {
|
|
69
75
|
placement: popperPlacement,
|
|
70
76
|
...popperOptions,
|
|
71
|
-
modifiers: [
|
|
77
|
+
modifiers: [
|
|
78
|
+
placementModifier,
|
|
79
|
+
{
|
|
80
|
+
...fallbackPlacementsModifier,
|
|
81
|
+
options: {
|
|
82
|
+
fallbackPlacements,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
...(popperOptions.modifiers || []),
|
|
86
|
+
],
|
|
72
87
|
});
|
|
73
88
|
elementRef(instance); // update the ref with the instance
|
|
74
89
|
return () => {
|
|
@@ -88,11 +103,20 @@ const OpenPopper = React.forwardRef(({ anchorElement, getAnchorClientRect, poppe
|
|
|
88
103
|
(_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions({
|
|
89
104
|
placement: popperPlacement,
|
|
90
105
|
...popperOptions,
|
|
91
|
-
modifiers: [
|
|
106
|
+
modifiers: [
|
|
107
|
+
placementModifier,
|
|
108
|
+
{
|
|
109
|
+
...fallbackPlacementsModifier,
|
|
110
|
+
options: {
|
|
111
|
+
fallbackPlacements,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
...(popperOptions.modifiers || []),
|
|
115
|
+
],
|
|
92
116
|
});
|
|
93
117
|
}
|
|
94
118
|
firstRender.current = false;
|
|
95
|
-
}, [popperOptions, popperPlacement, placementModifier, localRef]);
|
|
119
|
+
}, [popperOptions, popperPlacement, fallbackPlacements, placementModifier, localRef]);
|
|
96
120
|
const contents = React.createElement(React.Fragment, null, isRenderProp(children) ? children({ placement }) : children);
|
|
97
121
|
if (!portal) {
|
|
98
122
|
return contents;
|
|
@@ -8,6 +8,13 @@ export interface PopupPopperProps extends PopperProps {
|
|
|
8
8
|
* @default bottom
|
|
9
9
|
*/
|
|
10
10
|
placement?: Placement;
|
|
11
|
+
/**
|
|
12
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
13
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
14
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
15
|
+
* disable the fallback placements.
|
|
16
|
+
*/
|
|
17
|
+
fallbackPlacements?: Placement[];
|
|
11
18
|
/**
|
|
12
19
|
* The additional options passed to the Popper's `popper.js` instance.
|
|
13
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PopupPopper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/PopupPopper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,EAAC,SAAS,EAAE,aAAa,EAAU,WAAW,EAAC,MAAM,UAAU,CAAC;AAEvE,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;EAMtB,CAAC"}
|
|
1
|
+
{"version":3,"file":"PopupPopper.d.ts","sourceRoot":"","sources":["../../../../popup/lib/PopupPopper.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,EAAC,SAAS,EAAE,aAAa,EAAU,WAAW,EAAC,MAAM,UAAU,CAAC;AAEvE,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CACxC;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;EAMtB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Placement as PopperJSPlacement, Modifier } from '@popperjs/core';
|
|
2
|
+
export declare type Placement = PopperJSPlacement;
|
|
3
|
+
export declare type Options = {
|
|
4
|
+
fallbackPlacements: Placement[];
|
|
5
|
+
};
|
|
6
|
+
declare const name = "fallbackModifier";
|
|
7
|
+
export declare const fallbackPlacementsModifier: Modifier<typeof name, Options>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=fallbackPlacements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fallbackPlacements.d.ts","sourceRoot":"","sources":["../../../../popup/lib/fallbackPlacements.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,IAAI,iBAAiB,EAK9B,QAAQ,EAET,MAAM,gBAAgB,CAAC;AAExB,oBAAY,SAAS,GAAG,iBAAiB,CAAC;AAyD1C,oBAAY,OAAO,GAAG;IACpB,kBAAkB,EAAE,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,QAAA,MAAM,IAAI,qBAAqB,CAAC;AAEhC,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,OAAO,IAAI,EAAE,OAAO,CAwBrE,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { placements, detectOverflow, } from '@popperjs/core';
|
|
2
|
+
const getOppositePlacement = (popperPlacement) => {
|
|
3
|
+
var _a;
|
|
4
|
+
const [first, second] = popperPlacement.split('-');
|
|
5
|
+
let oppositePlacement;
|
|
6
|
+
switch (first) {
|
|
7
|
+
case 'top':
|
|
8
|
+
oppositePlacement = 'bottom';
|
|
9
|
+
break;
|
|
10
|
+
case 'bottom':
|
|
11
|
+
oppositePlacement = 'top';
|
|
12
|
+
break;
|
|
13
|
+
case 'left':
|
|
14
|
+
oppositePlacement = 'right';
|
|
15
|
+
break;
|
|
16
|
+
case 'right':
|
|
17
|
+
oppositePlacement = 'left';
|
|
18
|
+
break;
|
|
19
|
+
default:
|
|
20
|
+
oppositePlacement = 'auto';
|
|
21
|
+
}
|
|
22
|
+
if (second) {
|
|
23
|
+
oppositePlacement =
|
|
24
|
+
(_a = placements.find(placement => placement.includes(`${oppositePlacement}-${second}`))) !== null && _a !== void 0 ? _a : oppositePlacement;
|
|
25
|
+
}
|
|
26
|
+
return oppositePlacement;
|
|
27
|
+
};
|
|
28
|
+
const choseAvailablePlacement = (placements, state, preferredPlacement) => {
|
|
29
|
+
if (placements.length === 0 || placements[0].split('-')[0] === 'auto') {
|
|
30
|
+
return preferredPlacement;
|
|
31
|
+
}
|
|
32
|
+
const { reference, popper } = state.rects;
|
|
33
|
+
const overflow = detectOverflow({ ...state, placement: placements[0] });
|
|
34
|
+
const direction = /left|right/.test(placements[0].split('-')[0]) ? 'horizontal' : 'vertical';
|
|
35
|
+
const isOverflowed = (overflow.top > 0 || overflow.bottom > 0 || overflow.left > 0 || overflow.right > 0) &&
|
|
36
|
+
(direction === 'horizontal'
|
|
37
|
+
? popper.height / 2 - overflow.top < reference.height ||
|
|
38
|
+
popper.height / 2 - overflow.bottom < reference.height
|
|
39
|
+
: popper.width - overflow.left < reference.width ||
|
|
40
|
+
popper.width - overflow.right < reference.width);
|
|
41
|
+
const key = placements[0].split('-')[0];
|
|
42
|
+
if (!isOverflowed && overflow[key] <= 0) {
|
|
43
|
+
return placements[0];
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return choseAvailablePlacement(placements.slice(1), state, preferredPlacement);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const name = 'fallbackModifier';
|
|
50
|
+
export const fallbackPlacementsModifier = {
|
|
51
|
+
name: name,
|
|
52
|
+
enabled: true,
|
|
53
|
+
phase: 'main',
|
|
54
|
+
data: {
|
|
55
|
+
_skip: false,
|
|
56
|
+
},
|
|
57
|
+
fn({ state, options }) {
|
|
58
|
+
const preferredPlacement = state.options.placement;
|
|
59
|
+
const { fallbackPlacements } = options;
|
|
60
|
+
const placements = [
|
|
61
|
+
preferredPlacement,
|
|
62
|
+
getOppositePlacement(preferredPlacement),
|
|
63
|
+
...(fallbackPlacements || []),
|
|
64
|
+
];
|
|
65
|
+
const placementOverride = choseAvailablePlacement(placements, state, preferredPlacement);
|
|
66
|
+
if (state.placement !== placementOverride) {
|
|
67
|
+
state.modifiersData[name]._skip = true;
|
|
68
|
+
state.placement = placementOverride;
|
|
69
|
+
state.reset = true;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupPopper.d.ts","sourceRoot":"","sources":["../../../../../popup/lib/hooks/usePopupPopper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"usePopupPopper.d.ts","sourceRoot":"","sources":["../../../../../popup/lib/hooks/usePopupPopper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAC,SAAS,EAAC,MAAM,WAAW,CAAC;AAEpC;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;mCAOX,SAAS;EAevB,CAAC"}
|
|
@@ -7,12 +7,15 @@ import React from 'react';
|
|
|
7
7
|
*/
|
|
8
8
|
export const usePopupPopper = createElemPropsHook(usePopupModel)(({ state, events }, ref) => {
|
|
9
9
|
const elementRef = useForkRef(ref, state.stackRef);
|
|
10
|
+
// Create a mutable ref of the placement to keep a stable `onPlacementChange` reference.
|
|
11
|
+
const placementRef = React.useRef(state.placement);
|
|
12
|
+
placementRef.current = state.placement;
|
|
10
13
|
const onPlacementChange = React.useCallback((placement) => {
|
|
11
|
-
if (placement !==
|
|
14
|
+
if (placement !== placementRef.current) {
|
|
12
15
|
// only update if the placement has changed
|
|
13
16
|
events.updatePlacement({ placement });
|
|
14
17
|
}
|
|
15
|
-
}, [events
|
|
18
|
+
}, [events]);
|
|
16
19
|
return {
|
|
17
20
|
open: state.visibility !== 'hidden',
|
|
18
21
|
anchorElement: state.targetRef,
|
|
@@ -25,6 +25,13 @@ export interface OverflowTooltipProps extends Omit<React.HTMLAttributes<HTMLDivE
|
|
|
25
25
|
* @default 'top'
|
|
26
26
|
*/
|
|
27
27
|
placement?: Placement;
|
|
28
|
+
/**
|
|
29
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
30
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
31
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
32
|
+
* disable the fallback placements.
|
|
33
|
+
*/
|
|
34
|
+
fallbackPlacements?: Placement[];
|
|
28
35
|
}
|
|
29
|
-
export declare const OverflowTooltip: ({ placement, children, ...elemProps }: OverflowTooltipProps) => JSX.Element;
|
|
36
|
+
export declare const OverflowTooltip: ({ placement, fallbackPlacements, children, ...elemProps }: OverflowTooltipProps) => JSX.Element;
|
|
30
37
|
//# sourceMappingURL=OverflowTooltip.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverflowTooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/OverflowTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,
|
|
1
|
+
{"version":3,"file":"OverflowTooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/OverflowTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAEL,SAAS,EAGV,MAAM,iCAAiC,CAAC;AAMzC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,YAAa,OAAO,KAAG,OAAO,GAAG,IAmBhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,mBAAmB,YAAa,OAAO,KAAG,OAAO,GAAG,IAahE,CAAC;AAcF,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAC/F;;;;;;;OAOG;IACH,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;CAClC;AAiBD,eAAO,MAAM,eAAe,8DAKzB,oBAAoB,gBAwCtB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { getTransformFromPlacement, Popper } from '@workday/canvas-kit-react/popup';
|
|
2
|
+
import { getTransformFromPlacement, Popper, defaultFallbackPlacements, } from '@workday/canvas-kit-react/popup';
|
|
3
3
|
import { mergeCallback } from '@workday/canvas-kit-react/common';
|
|
4
4
|
import { TooltipContainer } from './TooltipContainer';
|
|
5
5
|
import { useTooltip } from './useTooltip';
|
|
@@ -64,7 +64,7 @@ function mergeCallbacks(elemProps, componentProps, keys = Object.keys(componentP
|
|
|
64
64
|
return mergedProps;
|
|
65
65
|
}, {});
|
|
66
66
|
}
|
|
67
|
-
export const OverflowTooltip = ({ placement = 'top', children, ...elemProps }) => {
|
|
67
|
+
export const OverflowTooltip = ({ placement = 'top', fallbackPlacements = defaultFallbackPlacements, children, ...elemProps }) => {
|
|
68
68
|
const [titleText, setTitleText] = React.useState('');
|
|
69
69
|
const { targetProps, popperProps, tooltipProps } = useTooltip({ type: 'muted' });
|
|
70
70
|
const onMouseEnter = (event) => {
|
|
@@ -89,7 +89,7 @@ export const OverflowTooltip = ({ placement = 'top', children, ...elemProps }) =
|
|
|
89
89
|
'aria-label': undefined,
|
|
90
90
|
...mergeCallbacks({ ...targetProps, onMouseEnter, onFocus }, children.props),
|
|
91
91
|
}),
|
|
92
|
-
React.createElement(Popper, Object.assign({ placement: placement }, popperProps), ({ placement }) => {
|
|
92
|
+
React.createElement(Popper, Object.assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), ({ placement }) => {
|
|
93
93
|
const transformOrigin = getTransformFromPlacement(placement);
|
|
94
94
|
return (React.createElement(TooltipContainer, Object.assign({ transformOrigin: transformOrigin }, tooltipProps, elemProps), titleText));
|
|
95
95
|
})));
|
|
@@ -20,6 +20,13 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
20
20
|
* @default 'top'
|
|
21
21
|
*/
|
|
22
22
|
placement?: Placement;
|
|
23
|
+
/**
|
|
24
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
25
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
26
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
27
|
+
* disable the fallback placements.
|
|
28
|
+
*/
|
|
29
|
+
fallbackPlacements?: Placement[];
|
|
23
30
|
/**
|
|
24
31
|
* Determines the tooltip type for accessibility.
|
|
25
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,
|
|
1
|
+
{"version":3,"file":"Tooltip.d.ts","sourceRoot":"","sources":["../../../../tooltip/lib/Tooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAEL,SAAS,EAGV,MAAM,iCAAiC,CAAC;AAMzC,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACvF;;;OAGG;IACH,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB;;;;;;;OAOG;IACH,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAClC;;;OAGG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC;IACjC;;;;;;;;;;;;;;;OAeG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IACtC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiBD,eAAO,MAAM,OAAO,kFA0ClB,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import innerText from 'react-innertext';
|
|
3
|
-
import { getTransformFromPlacement, Popper } from '@workday/canvas-kit-react/popup';
|
|
3
|
+
import { getTransformFromPlacement, Popper, defaultFallbackPlacements, } from '@workday/canvas-kit-react/popup';
|
|
4
4
|
import { createComponent, mergeCallback } from '@workday/canvas-kit-react/common';
|
|
5
5
|
import { TooltipContainer } from './TooltipContainer';
|
|
6
6
|
import { useTooltip } from './useTooltip';
|
|
@@ -17,7 +17,7 @@ function mergeCallbacks(elemProps, componentProps, keys = Object.keys(componentP
|
|
|
17
17
|
}
|
|
18
18
|
export const Tooltip = createComponent('div')({
|
|
19
19
|
displayName: 'Tooltip',
|
|
20
|
-
Component({ type = 'label', placement = 'top', title, children, showDelay = 300, hideDelay = 100, ...elemProps }) {
|
|
20
|
+
Component({ type = 'label', placement = 'top', title, children, showDelay = 300, hideDelay = 100, fallbackPlacements = defaultFallbackPlacements, ...elemProps }) {
|
|
21
21
|
const titleText = innerText(title);
|
|
22
22
|
const { targetProps, popperProps, tooltipProps } = useTooltip({
|
|
23
23
|
type,
|
|
@@ -33,7 +33,7 @@ export const Tooltip = createComponent('div')({
|
|
|
33
33
|
? { 'aria-label': children.props['aria-label'] }
|
|
34
34
|
: {}),
|
|
35
35
|
}),
|
|
36
|
-
React.createElement(Popper, Object.assign({ placement: placement }, popperProps), ({ placement }) => {
|
|
36
|
+
React.createElement(Popper, Object.assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), ({ placement }) => {
|
|
37
37
|
const transformOrigin = getTransformFromPlacement(placement);
|
|
38
38
|
return (React.createElement(TooltipContainer, Object.assign({ transformOrigin: transformOrigin }, elemProps, tooltipProps), title));
|
|
39
39
|
})));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workday/canvas-kit-react",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.10",
|
|
4
4
|
"description": "The parent module that contains all Workday Canvas Kit React components",
|
|
5
5
|
"author": "Workday, Inc. (https://www.workday.com)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"@emotion/styled": "^11.6.0",
|
|
50
50
|
"@popperjs/core": "^2.5.4",
|
|
51
51
|
"@workday/canvas-colors-web": "^2.0.0",
|
|
52
|
-
"@workday/canvas-kit-popup-stack": "^9.0.
|
|
52
|
+
"@workday/canvas-kit-popup-stack": "^9.0.10",
|
|
53
53
|
"@workday/canvas-system-icons-web": "^3.0.0",
|
|
54
54
|
"@workday/design-assets-types": "^0.2.8",
|
|
55
55
|
"chroma-js": "^2.1.0",
|
|
@@ -66,5 +66,5 @@
|
|
|
66
66
|
"@workday/canvas-accent-icons-web": "^3.0.0",
|
|
67
67
|
"@workday/canvas-applet-icons-web": "^2.0.0"
|
|
68
68
|
},
|
|
69
|
-
"gitHead": "
|
|
69
|
+
"gitHead": "8fa72860c376f39967e95014afe43664f55d1683"
|
|
70
70
|
}
|
package/popup/lib/Popper.tsx
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as ReactDOM from 'react-dom';
|
|
3
|
-
import
|
|
3
|
+
import { Placement as PopperJSPlacement, Options, Instance, Modifier, createPopper } from '@popperjs/core';
|
|
4
4
|
|
|
5
|
-
export type Placement = `${
|
|
6
|
-
export type PopperOptions =
|
|
5
|
+
export type Placement = `${PopperJSPlacement}`; // Use template literals to make documentation list them out
|
|
6
|
+
export type PopperOptions = Options;
|
|
7
|
+
export const defaultFallbackPlacements: Placement[] = ['top', 'right', 'bottom', 'left'];
|
|
7
8
|
|
|
8
9
|
import {usePopupStack} from './hooks';
|
|
9
10
|
import {useLocalRef} from '@workday/canvas-kit-react/common';
|
|
11
|
+
import {fallbackPlacementsModifier} from './fallbackPlacements';
|
|
10
12
|
|
|
11
13
|
export interface PopperProps {
|
|
12
14
|
/**
|
|
@@ -43,6 +45,13 @@ export interface PopperProps {
|
|
|
43
45
|
* @default bottom
|
|
44
46
|
*/
|
|
45
47
|
placement?: Placement;
|
|
48
|
+
/**
|
|
49
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
50
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
51
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
52
|
+
* disable the fallback placements.
|
|
53
|
+
*/
|
|
54
|
+
fallbackPlacements?: Placement[];
|
|
46
55
|
/**
|
|
47
56
|
* A callback function that will be called whenever PopperJS chooses a placement that is different
|
|
48
57
|
* from the provided `placement` preference. If a `placement` preference doesn't fit, PopperJS
|
|
@@ -65,7 +74,7 @@ export interface PopperProps {
|
|
|
65
74
|
* Reference to the PopperJS instance. Useful for making direct method calls on the popper
|
|
66
75
|
* instance like `update`.
|
|
67
76
|
*/
|
|
68
|
-
popperInstanceRef?: React.Ref<
|
|
77
|
+
popperInstanceRef?: React.Ref<Instance>;
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
/**
|
|
@@ -117,6 +126,7 @@ const OpenPopper = React.forwardRef<HTMLDivElement, PopperProps>(
|
|
|
117
126
|
getAnchorClientRect,
|
|
118
127
|
popperOptions = defaultPopperOptions,
|
|
119
128
|
placement: popperPlacement = 'bottom',
|
|
129
|
+
fallbackPlacements = defaultFallbackPlacements,
|
|
120
130
|
onPlacementChange,
|
|
121
131
|
children,
|
|
122
132
|
portal,
|
|
@@ -129,14 +139,19 @@ const OpenPopper = React.forwardRef<HTMLDivElement, PopperProps>(
|
|
|
129
139
|
const [placement, setPlacement] = React.useState(popperPlacement);
|
|
130
140
|
const stackRef = usePopupStack(ref, anchorElement as HTMLElement);
|
|
131
141
|
|
|
132
|
-
const
|
|
142
|
+
const placementRef = React.useRef(popperPlacement);
|
|
143
|
+
placementRef.current = placement;
|
|
144
|
+
|
|
145
|
+
const placementModifier = React.useMemo((): Modifier<any, any> => {
|
|
133
146
|
return {
|
|
134
147
|
name: 'setPlacement',
|
|
135
148
|
enabled: true,
|
|
136
|
-
phase: '
|
|
149
|
+
phase: 'afterWrite',
|
|
137
150
|
fn({state}) {
|
|
138
|
-
|
|
139
|
-
|
|
151
|
+
if (placementRef.current !== state.placement) {
|
|
152
|
+
setPlacement(state.placement);
|
|
153
|
+
onPlacementChange?.(state.placement);
|
|
154
|
+
}
|
|
140
155
|
},
|
|
141
156
|
};
|
|
142
157
|
}, [setPlacement, onPlacementChange]);
|
|
@@ -154,10 +169,19 @@ const OpenPopper = React.forwardRef<HTMLDivElement, PopperProps>(
|
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
if (stackRef.current) {
|
|
157
|
-
const instance =
|
|
172
|
+
const instance = createPopper(anchorEl, stackRef.current, {
|
|
158
173
|
placement: popperPlacement,
|
|
159
174
|
...popperOptions,
|
|
160
|
-
modifiers: [
|
|
175
|
+
modifiers: [
|
|
176
|
+
placementModifier,
|
|
177
|
+
{
|
|
178
|
+
...fallbackPlacementsModifier,
|
|
179
|
+
options: {
|
|
180
|
+
fallbackPlacements,
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
...(popperOptions.modifiers || []),
|
|
184
|
+
],
|
|
161
185
|
});
|
|
162
186
|
elementRef(instance); // update the ref with the instance
|
|
163
187
|
|
|
@@ -179,11 +203,20 @@ const OpenPopper = React.forwardRef<HTMLDivElement, PopperProps>(
|
|
|
179
203
|
localRef.current?.setOptions({
|
|
180
204
|
placement: popperPlacement,
|
|
181
205
|
...popperOptions,
|
|
182
|
-
modifiers: [
|
|
206
|
+
modifiers: [
|
|
207
|
+
placementModifier,
|
|
208
|
+
{
|
|
209
|
+
...fallbackPlacementsModifier,
|
|
210
|
+
options: {
|
|
211
|
+
fallbackPlacements,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
...(popperOptions.modifiers || []),
|
|
215
|
+
],
|
|
183
216
|
});
|
|
184
217
|
}
|
|
185
218
|
firstRender.current = false;
|
|
186
|
-
}, [popperOptions, popperPlacement, placementModifier, localRef]);
|
|
219
|
+
}, [popperOptions, popperPlacement, fallbackPlacements, placementModifier, localRef]);
|
|
187
220
|
|
|
188
221
|
const contents = <>{isRenderProp(children) ? children({placement}) : children}</>;
|
|
189
222
|
|
|
@@ -13,6 +13,13 @@ export interface PopupPopperProps extends PopperProps {
|
|
|
13
13
|
* @default bottom
|
|
14
14
|
*/
|
|
15
15
|
placement?: Placement;
|
|
16
|
+
/**
|
|
17
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
18
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
19
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
20
|
+
* disable the fallback placements.
|
|
21
|
+
*/
|
|
22
|
+
fallbackPlacements?: Placement[];
|
|
16
23
|
/**
|
|
17
24
|
* The additional options passed to the Popper's `popper.js` instance.
|
|
18
25
|
*/
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Placement as PopperJSPlacement,
|
|
3
|
+
placements,
|
|
4
|
+
State,
|
|
5
|
+
detectOverflow,
|
|
6
|
+
SideObject,
|
|
7
|
+
Modifier,
|
|
8
|
+
ModifierArguments,
|
|
9
|
+
} from '@popperjs/core';
|
|
10
|
+
|
|
11
|
+
export type Placement = PopperJSPlacement; // Use template literals to make documentation list them out
|
|
12
|
+
|
|
13
|
+
const getOppositePlacement = (popperPlacement: Placement): Placement => {
|
|
14
|
+
const [first, second] = popperPlacement.split('-');
|
|
15
|
+
let oppositePlacement: Placement;
|
|
16
|
+
switch (first) {
|
|
17
|
+
case 'top':
|
|
18
|
+
oppositePlacement = 'bottom';
|
|
19
|
+
break;
|
|
20
|
+
case 'bottom':
|
|
21
|
+
oppositePlacement = 'top';
|
|
22
|
+
break;
|
|
23
|
+
case 'left':
|
|
24
|
+
oppositePlacement = 'right';
|
|
25
|
+
break;
|
|
26
|
+
case 'right':
|
|
27
|
+
oppositePlacement = 'left';
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
oppositePlacement = 'auto';
|
|
31
|
+
}
|
|
32
|
+
if (second) {
|
|
33
|
+
oppositePlacement =
|
|
34
|
+
placements.find(placement => placement.includes(`${oppositePlacement}-${second}`)) ??
|
|
35
|
+
oppositePlacement;
|
|
36
|
+
}
|
|
37
|
+
return oppositePlacement;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const choseAvailablePlacement = (
|
|
41
|
+
placements: Placement[],
|
|
42
|
+
state: State,
|
|
43
|
+
preferredPlacement: Placement
|
|
44
|
+
): Placement => {
|
|
45
|
+
if (placements.length === 0 || placements[0].split('-')[0] === 'auto') {
|
|
46
|
+
return preferredPlacement;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const {reference, popper} = state.rects;
|
|
50
|
+
const overflow = detectOverflow({...state, placement: placements[0]});
|
|
51
|
+
const direction = /left|right/.test(placements[0].split('-')[0]) ? 'horizontal' : 'vertical';
|
|
52
|
+
const isOverflowed =
|
|
53
|
+
(overflow.top > 0 || overflow.bottom > 0 || overflow.left > 0 || overflow.right > 0) &&
|
|
54
|
+
(direction === 'horizontal'
|
|
55
|
+
? popper.height / 2 - overflow.top < reference.height ||
|
|
56
|
+
popper.height / 2 - overflow.bottom < reference.height
|
|
57
|
+
: popper.width - overflow.left < reference.width ||
|
|
58
|
+
popper.width - overflow.right < reference.width);
|
|
59
|
+
const key = placements[0].split('-')[0] as keyof SideObject;
|
|
60
|
+
|
|
61
|
+
if (!isOverflowed && overflow[key] <= 0) {
|
|
62
|
+
return placements[0];
|
|
63
|
+
} else {
|
|
64
|
+
return choseAvailablePlacement(placements.slice(1), state, preferredPlacement);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export type Options = {
|
|
69
|
+
fallbackPlacements: Placement[];
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const name = 'fallbackModifier';
|
|
73
|
+
|
|
74
|
+
export const fallbackPlacementsModifier: Modifier<typeof name, Options> = {
|
|
75
|
+
name: name,
|
|
76
|
+
enabled: true,
|
|
77
|
+
phase: 'main',
|
|
78
|
+
data: {
|
|
79
|
+
_skip: false,
|
|
80
|
+
},
|
|
81
|
+
fn({state, options}: ModifierArguments<Options>) {
|
|
82
|
+
const preferredPlacement = state.options.placement;
|
|
83
|
+
const {fallbackPlacements} = options;
|
|
84
|
+
|
|
85
|
+
const placements = [
|
|
86
|
+
preferredPlacement,
|
|
87
|
+
getOppositePlacement(preferredPlacement),
|
|
88
|
+
...(fallbackPlacements || []),
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const placementOverride = choseAvailablePlacement(placements, state, preferredPlacement);
|
|
92
|
+
if (state.placement !== placementOverride) {
|
|
93
|
+
state.modifiersData[name]._skip = true;
|
|
94
|
+
state.placement = placementOverride;
|
|
95
|
+
state.reset = true;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
};
|
|
@@ -9,14 +9,18 @@ import {Placement} from '../Popper';
|
|
|
9
9
|
*/
|
|
10
10
|
export const usePopupPopper = createElemPropsHook(usePopupModel)(({state, events}, ref) => {
|
|
11
11
|
const elementRef = useForkRef(ref, state.stackRef);
|
|
12
|
+
|
|
13
|
+
// Create a mutable ref of the placement to keep a stable `onPlacementChange` reference.
|
|
14
|
+
const placementRef = React.useRef(state.placement);
|
|
15
|
+
placementRef.current = state.placement;
|
|
12
16
|
const onPlacementChange = React.useCallback(
|
|
13
17
|
(placement: Placement) => {
|
|
14
|
-
if (placement !==
|
|
18
|
+
if (placement !== placementRef.current) {
|
|
15
19
|
// only update if the placement has changed
|
|
16
20
|
events.updatePlacement({placement});
|
|
17
21
|
}
|
|
18
22
|
},
|
|
19
|
-
[events
|
|
23
|
+
[events]
|
|
20
24
|
);
|
|
21
25
|
|
|
22
26
|
return {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getTransformFromPlacement,
|
|
5
|
+
Placement,
|
|
6
|
+
Popper,
|
|
7
|
+
defaultFallbackPlacements,
|
|
8
|
+
} from '@workday/canvas-kit-react/popup';
|
|
4
9
|
import {mergeCallback} from '@workday/canvas-kit-react/common';
|
|
5
10
|
|
|
6
11
|
import {TooltipContainer} from './TooltipContainer';
|
|
@@ -77,6 +82,13 @@ export interface OverflowTooltipProps extends Omit<React.HTMLAttributes<HTMLDivE
|
|
|
77
82
|
* @default 'top'
|
|
78
83
|
*/
|
|
79
84
|
placement?: Placement;
|
|
85
|
+
/**
|
|
86
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
87
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
88
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
89
|
+
* disable the fallback placements.
|
|
90
|
+
*/
|
|
91
|
+
fallbackPlacements?: Placement[];
|
|
80
92
|
}
|
|
81
93
|
|
|
82
94
|
function mergeCallbacks<T extends {[key: string]: any}>(
|
|
@@ -96,6 +108,7 @@ function mergeCallbacks<T extends {[key: string]: any}>(
|
|
|
96
108
|
|
|
97
109
|
export const OverflowTooltip = ({
|
|
98
110
|
placement = 'top',
|
|
111
|
+
fallbackPlacements = defaultFallbackPlacements,
|
|
99
112
|
children,
|
|
100
113
|
...elemProps
|
|
101
114
|
}: OverflowTooltipProps) => {
|
|
@@ -126,7 +139,7 @@ export const OverflowTooltip = ({
|
|
|
126
139
|
'aria-label': undefined, // we don't need a label, the accessible name will be the content
|
|
127
140
|
...mergeCallbacks({...targetProps, onMouseEnter, onFocus}, children.props),
|
|
128
141
|
})}
|
|
129
|
-
<Popper placement={placement} {...popperProps}>
|
|
142
|
+
<Popper placement={placement} fallbackPlacements={fallbackPlacements} {...popperProps}>
|
|
130
143
|
{({placement}) => {
|
|
131
144
|
const transformOrigin = getTransformFromPlacement(placement);
|
|
132
145
|
return (
|
package/tooltip/lib/Tooltip.tsx
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import innerText from 'react-innertext';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getTransformFromPlacement,
|
|
6
|
+
Placement,
|
|
7
|
+
Popper,
|
|
8
|
+
defaultFallbackPlacements,
|
|
9
|
+
} from '@workday/canvas-kit-react/popup';
|
|
5
10
|
import {createComponent, mergeCallback} from '@workday/canvas-kit-react/common';
|
|
6
11
|
|
|
7
12
|
import {TooltipContainer} from './TooltipContainer';
|
|
@@ -27,6 +32,13 @@ export interface TooltipProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
27
32
|
* @default 'top'
|
|
28
33
|
*/
|
|
29
34
|
placement?: Placement;
|
|
35
|
+
/**
|
|
36
|
+
* Define fallback placements by providing a list of {@link Placement} in array (in order of preference).
|
|
37
|
+
* The default preference is following the order of `top`, `right`, `bottom`, and `left`. Once the initial
|
|
38
|
+
* and opposite placements are not available, the fallback placements will be in use. Use an empty array to
|
|
39
|
+
* disable the fallback placements.
|
|
40
|
+
*/
|
|
41
|
+
fallbackPlacements?: Placement[];
|
|
30
42
|
/**
|
|
31
43
|
* Determines the tooltip type for accessibility.
|
|
32
44
|
*
|
|
@@ -78,6 +90,7 @@ export const Tooltip = createComponent('div')({
|
|
|
78
90
|
children,
|
|
79
91
|
showDelay = 300,
|
|
80
92
|
hideDelay = 100,
|
|
93
|
+
fallbackPlacements = defaultFallbackPlacements,
|
|
81
94
|
...elemProps
|
|
82
95
|
}: TooltipProps) {
|
|
83
96
|
const titleText = innerText(title);
|
|
@@ -97,7 +110,7 @@ export const Tooltip = createComponent('div')({
|
|
|
97
110
|
? {'aria-label': children.props['aria-label']}
|
|
98
111
|
: {}),
|
|
99
112
|
})}
|
|
100
|
-
<Popper placement={placement} {...popperProps}>
|
|
113
|
+
<Popper placement={placement} fallbackPlacements={fallbackPlacements} {...popperProps}>
|
|
101
114
|
{({placement}) => {
|
|
102
115
|
const transformOrigin = getTransformFromPlacement(placement);
|
|
103
116
|
return (
|