@workday/canvas-kit-react 8.6.10 → 8.6.11

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.
Files changed (39) hide show
  1. package/dist/commonjs/popup/lib/Popper.d.ts +8 -0
  2. package/dist/commonjs/popup/lib/Popper.d.ts.map +1 -1
  3. package/dist/commonjs/popup/lib/Popper.js +26 -10
  4. package/dist/commonjs/popup/lib/PopupPopper.d.ts +7 -0
  5. package/dist/commonjs/popup/lib/PopupPopper.d.ts.map +1 -1
  6. package/dist/commonjs/popup/lib/fallbackPlacements.d.ts +9 -0
  7. package/dist/commonjs/popup/lib/fallbackPlacements.d.ts.map +1 -0
  8. package/dist/commonjs/popup/lib/fallbackPlacements.js +110 -0
  9. package/dist/commonjs/popup/lib/hooks/usePopupPopper.d.ts.map +1 -1
  10. package/dist/commonjs/popup/lib/hooks/usePopupPopper.js +5 -2
  11. package/dist/commonjs/tooltip/lib/OverflowTooltip.d.ts +8 -1
  12. package/dist/commonjs/tooltip/lib/OverflowTooltip.d.ts.map +1 -1
  13. package/dist/commonjs/tooltip/lib/OverflowTooltip.js +4 -4
  14. package/dist/commonjs/tooltip/lib/Tooltip.d.ts +7 -0
  15. package/dist/commonjs/tooltip/lib/Tooltip.d.ts.map +1 -1
  16. package/dist/commonjs/tooltip/lib/Tooltip.js +4 -4
  17. package/dist/es6/popup/lib/Popper.d.ts +8 -0
  18. package/dist/es6/popup/lib/Popper.d.ts.map +1 -1
  19. package/dist/es6/popup/lib/Popper.js +25 -9
  20. package/dist/es6/popup/lib/PopupPopper.d.ts +7 -0
  21. package/dist/es6/popup/lib/PopupPopper.d.ts.map +1 -1
  22. package/dist/es6/popup/lib/fallbackPlacements.d.ts +9 -0
  23. package/dist/es6/popup/lib/fallbackPlacements.d.ts.map +1 -0
  24. package/dist/es6/popup/lib/fallbackPlacements.js +88 -0
  25. package/dist/es6/popup/lib/hooks/usePopupPopper.d.ts.map +1 -1
  26. package/dist/es6/popup/lib/hooks/usePopupPopper.js +5 -2
  27. package/dist/es6/tooltip/lib/OverflowTooltip.d.ts +8 -1
  28. package/dist/es6/tooltip/lib/OverflowTooltip.d.ts.map +1 -1
  29. package/dist/es6/tooltip/lib/OverflowTooltip.js +5 -5
  30. package/dist/es6/tooltip/lib/Tooltip.d.ts +7 -0
  31. package/dist/es6/tooltip/lib/Tooltip.d.ts.map +1 -1
  32. package/dist/es6/tooltip/lib/Tooltip.js +5 -5
  33. package/package.json +3 -3
  34. package/popup/lib/Popper.tsx +39 -6
  35. package/popup/lib/PopupPopper.tsx +7 -0
  36. package/popup/lib/fallbackPlacements.ts +90 -0
  37. package/popup/lib/hooks/usePopupPopper.ts +6 -2
  38. package/tooltip/lib/OverflowTooltip.tsx +15 -2
  39. package/tooltip/lib/Tooltip.tsx +15 -2
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import * as PopperJS from '@popperjs/core';
3
3
  export declare type Placement = `${PopperJS.Placement}`;
4
4
  export declare type PopperOptions = PopperJS.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
@@ -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,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,oBAAY,SAAS,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;AAChD,oBAAY,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;AAK7C,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;;;;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,QAAQ,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,oFAQlB,CAAC"}
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,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,oBAAY,SAAS,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;AAChD,oBAAY,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;AAC7C,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,QAAQ,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,oFAQlB,CAAC"}
@@ -46,12 +46,14 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
46
46
  return to;
47
47
  };
48
48
  Object.defineProperty(exports, "__esModule", { value: true });
49
- exports.Popper = void 0;
49
+ exports.Popper = exports.defaultFallbackPlacements = void 0;
50
50
  var React = __importStar(require("react"));
51
51
  var ReactDOM = __importStar(require("react-dom"));
52
52
  var PopperJS = __importStar(require("@popperjs/core"));
53
+ exports.defaultFallbackPlacements = ['top', 'right', 'bottom', 'left'];
53
54
  var hooks_1 = require("./hooks");
54
55
  var common_1 = require("@workday/canvas-kit-react/common");
56
+ var fallbackPlacements_1 = require("./fallbackPlacements");
55
57
  /**
56
58
  * A thin wrapper component around the Popper.js positioning engine. For reference:
57
59
  * https://popper.js.org/. `Popper` also automatically works with the {@link PopupStack} system.
@@ -90,20 +92,24 @@ var defaultPopperOptions = {};
90
92
  // Popper bails early if `open` is false and React hooks cannot be called conditionally,
91
93
  // so we're breaking out the open version into another component.
92
94
  var OpenPopper = React.forwardRef(function (_a, ref) {
93
- var anchorElement = _a.anchorElement, getAnchorClientRect = _a.getAnchorClientRect, _b = _a.popperOptions, popperOptions = _b === void 0 ? defaultPopperOptions : _b, _c = _a.placement, popperPlacement = _c === void 0 ? 'bottom' : _c, onPlacementChange = _a.onPlacementChange, children = _a.children, portal = _a.portal, popperInstanceRef = _a.popperInstanceRef;
95
+ var anchorElement = _a.anchorElement, getAnchorClientRect = _a.getAnchorClientRect, _b = _a.popperOptions, popperOptions = _b === void 0 ? defaultPopperOptions : _b, _c = _a.placement, popperPlacement = _c === void 0 ? 'bottom' : _c, _d = _a.fallbackPlacements, fallbackPlacements = _d === void 0 ? exports.defaultFallbackPlacements : _d, onPlacementChange = _a.onPlacementChange, children = _a.children, portal = _a.portal, popperInstanceRef = _a.popperInstanceRef;
94
96
  var firstRender = React.useRef(true);
95
- var _d = common_1.useLocalRef(popperInstanceRef), localRef = _d.localRef, elementRef = _d.elementRef;
96
- var _e = React.useState(popperPlacement), placement = _e[0], setPlacement = _e[1];
97
+ var _e = common_1.useLocalRef(popperInstanceRef), localRef = _e.localRef, elementRef = _e.elementRef;
98
+ var _f = React.useState(popperPlacement), placement = _f[0], setPlacement = _f[1];
97
99
  var stackRef = hooks_1.usePopupStack(ref, anchorElement);
100
+ var placementRef = React.useRef(popperPlacement);
101
+ placementRef.current = placement;
98
102
  var placementModifier = React.useMemo(function () {
99
103
  return {
100
104
  name: 'setPlacement',
101
105
  enabled: true,
102
- phase: 'main',
106
+ phase: 'afterWrite',
103
107
  fn: function (_a) {
104
108
  var state = _a.state;
105
- setPlacement(state.placement);
106
- onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement);
109
+ if (placementRef.current !== state.placement) {
110
+ setPlacement(state.placement);
111
+ onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement);
112
+ }
107
113
  },
108
114
  };
109
115
  }, [setPlacement, onPlacementChange]);
@@ -117,7 +123,12 @@ var OpenPopper = React.forwardRef(function (_a, ref) {
117
123
  return undefined;
118
124
  }
119
125
  if (stackRef.current) {
120
- var instance_1 = PopperJS.createPopper(anchorEl, stackRef.current, __assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray(__spreadArray([], (popperOptions.modifiers || [])), [placementModifier]) }));
126
+ var instance_1 = PopperJS.createPopper(anchorEl, stackRef.current, __assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray([
127
+ placementModifier,
128
+ __assign(__assign({}, fallbackPlacements_1.fallbackPlacementsModifier), { options: {
129
+ fallbackPlacements: fallbackPlacements,
130
+ } })
131
+ ], (popperOptions.modifiers || [])) }));
121
132
  elementRef(instance_1); // update the ref with the instance
122
133
  return function () {
123
134
  instance_1 === null || instance_1 === void 0 ? void 0 : instance_1.destroy();
@@ -133,10 +144,15 @@ var OpenPopper = React.forwardRef(function (_a, ref) {
133
144
  var _a;
134
145
  // Only update options if this is _not_ the first render
135
146
  if (!firstRender.current) {
136
- (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions(__assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray(__spreadArray([], (popperOptions.modifiers || [])), [placementModifier]) }));
147
+ (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions(__assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray([
148
+ placementModifier,
149
+ __assign(__assign({}, fallbackPlacements_1.fallbackPlacementsModifier), { options: {
150
+ fallbackPlacements: fallbackPlacements,
151
+ } })
152
+ ], (popperOptions.modifiers || [])) }));
137
153
  }
138
154
  firstRender.current = false;
139
- }, [popperOptions, popperPlacement, placementModifier, localRef]);
155
+ }, [popperOptions, popperPlacement, fallbackPlacements, placementModifier, localRef]);
140
156
  var contents = React.createElement(React.Fragment, null, isRenderProp(children) ? children({ placement: placement }) : children);
141
157
  if (!portal) {
142
158
  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 * as PopperJS from '@popperjs/core';
2
+ export declare type Placement = PopperJS.Placement;
3
+ export declare type Options = {
4
+ fallbackPlacements: Placement[];
5
+ };
6
+ declare const name = "fallbackModifier";
7
+ export declare const fallbackPlacementsModifier: PopperJS.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,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,oBAAY,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;AAyD3C,oBAAY,OAAO,GAAG;IACpB,kBAAkB,EAAE,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,QAAA,MAAM,IAAI,qBAAqB,CAAC;AAEhC,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,OAAO,CAwB9E,CAAC"}
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || function (mod) {
26
+ if (mod && mod.__esModule) return mod;
27
+ var result = {};
28
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
29
+ __setModuleDefault(result, mod);
30
+ return result;
31
+ };
32
+ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
33
+ for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
34
+ to[j] = from[i];
35
+ return to;
36
+ };
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.fallbackPlacementsModifier = void 0;
39
+ var PopperJS = __importStar(require("@popperjs/core"));
40
+ var getOppositePlacement = function (popperPlacement) {
41
+ var _a;
42
+ var _b = popperPlacement.split('-'), first = _b[0], second = _b[1];
43
+ var oppositePlacement;
44
+ switch (first) {
45
+ case 'top':
46
+ oppositePlacement = 'bottom';
47
+ break;
48
+ case 'bottom':
49
+ oppositePlacement = 'top';
50
+ break;
51
+ case 'left':
52
+ oppositePlacement = 'right';
53
+ break;
54
+ case 'right':
55
+ oppositePlacement = 'left';
56
+ break;
57
+ default:
58
+ oppositePlacement = 'auto';
59
+ }
60
+ if (second) {
61
+ oppositePlacement =
62
+ (_a = PopperJS.placements.find(function (placement) { return placement.includes(oppositePlacement + "-" + second); })) !== null && _a !== void 0 ? _a : oppositePlacement;
63
+ }
64
+ return oppositePlacement;
65
+ };
66
+ var choseAvailablePlacement = function (placements, state, preferredPlacement) {
67
+ if (placements.length === 0 || placements[0].split('-')[0] === 'auto') {
68
+ return preferredPlacement;
69
+ }
70
+ var _a = state.rects, reference = _a.reference, popper = _a.popper;
71
+ var overflow = PopperJS.detectOverflow(__assign(__assign({}, state), { placement: placements[0] }));
72
+ var direction = /left|right/.test(placements[0].split('-')[0]) ? 'horizontal' : 'vertical';
73
+ var isOverflowed = (overflow.top > 0 || overflow.bottom > 0 || overflow.left > 0 || overflow.right > 0) &&
74
+ (direction === 'horizontal'
75
+ ? popper.height / 2 - overflow.top < reference.height ||
76
+ popper.height / 2 - overflow.bottom < reference.height
77
+ : popper.width - overflow.left < reference.width ||
78
+ popper.width - overflow.right < reference.width);
79
+ var key = placements[0].split('-')[0];
80
+ if (!isOverflowed && overflow[key] <= 0) {
81
+ return placements[0];
82
+ }
83
+ else {
84
+ return choseAvailablePlacement(placements.slice(1), state, preferredPlacement);
85
+ }
86
+ };
87
+ var name = 'fallbackModifier';
88
+ exports.fallbackPlacementsModifier = {
89
+ name: name,
90
+ enabled: true,
91
+ phase: 'main',
92
+ data: {
93
+ _skip: false,
94
+ },
95
+ fn: function (_a) {
96
+ var state = _a.state, options = _a.options;
97
+ var preferredPlacement = state.options.placement;
98
+ var fallbackPlacements = options.fallbackPlacements;
99
+ var placements = __spreadArray([
100
+ preferredPlacement,
101
+ getOppositePlacement(preferredPlacement)
102
+ ], (fallbackPlacements || []));
103
+ var placementOverride = choseAvailablePlacement(placements, state, preferredPlacement);
104
+ if (state.placement !== placementOverride) {
105
+ state.modifiersData[name]._skip = true;
106
+ state.placement = placementOverride;
107
+ state.reset = true;
108
+ }
109
+ },
110
+ };
@@ -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;;;;;;;;;;;;;;;;;;;;;mCAGX,SAAS;;;OAevB,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;;;OAevB,CAAC"}
@@ -14,12 +14,15 @@ var react_1 = __importDefault(require("react"));
14
14
  exports.usePopupPopper = common_1.createElemPropsHook(usePopupModel_1.usePopupModel)(function (_a, ref) {
15
15
  var state = _a.state, events = _a.events;
16
16
  var elementRef = common_1.useForkRef(ref, state.stackRef);
17
+ // Create a mutable ref of the placement to keep a stable `onPlacementChange` reference.
18
+ var placementRef = react_1.default.useRef(state.placement);
19
+ placementRef.current = state.placement;
17
20
  var onPlacementChange = react_1.default.useCallback(function (placement) {
18
- if (placement !== state.placement) {
21
+ if (placement !== placementRef.current) {
19
22
  // only update if the placement has changed
20
23
  events.updatePlacement({ placement: placement });
21
24
  }
22
- }, [events, state.placement]);
25
+ }, [events]);
23
26
  return {
24
27
  open: state.visibility !== 'hidden',
25
28
  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,EAA4B,SAAS,EAAS,MAAM,iCAAiC,CAAC;AAM7F;;;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;CACvB;AAiBD,eAAO,MAAM,eAAe,0CAIzB,oBAAoB,gBAwCtB,CAAC"}
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"}
@@ -112,9 +112,9 @@ function mergeCallbacks(elemProps, componentProps, keys) {
112
112
  }, {});
113
113
  }
114
114
  var OverflowTooltip = function (_a) {
115
- var _b = _a.placement, placement = _b === void 0 ? 'top' : _b, children = _a.children, elemProps = __rest(_a, ["placement", "children"]);
116
- var _c = React.useState(''), titleText = _c[0], setTitleText = _c[1];
117
- var _d = useTooltip_1.useTooltip({ type: 'muted' }), targetProps = _d.targetProps, popperProps = _d.popperProps, tooltipProps = _d.tooltipProps;
115
+ var _b = _a.placement, placement = _b === void 0 ? 'top' : _b, _c = _a.fallbackPlacements, fallbackPlacements = _c === void 0 ? popup_1.defaultFallbackPlacements : _c, children = _a.children, elemProps = __rest(_a, ["placement", "fallbackPlacements", "children"]);
116
+ var _d = React.useState(''), titleText = _d[0], setTitleText = _d[1];
117
+ var _e = useTooltip_1.useTooltip({ type: 'muted' }), targetProps = _e.targetProps, popperProps = _e.popperProps, tooltipProps = _e.tooltipProps;
118
118
  var onMouseEnter = function (event) {
119
119
  var target = event.currentTarget;
120
120
  setTitleText(target instanceof HTMLElement ? target.innerText : '');
@@ -132,7 +132,7 @@ var OverflowTooltip = function (_a) {
132
132
  return (React.createElement(React.Fragment, null,
133
133
  React.cloneElement(children, __assign(__assign(__assign({}, targetProps), { onMouseEnter: onMouseEnter,
134
134
  onFocus: onFocus, 'aria-label': undefined }), mergeCallbacks(__assign(__assign({}, targetProps), { onMouseEnter: onMouseEnter, onFocus: onFocus }), children.props))),
135
- React.createElement(popup_1.Popper, __assign({ placement: placement }, popperProps), function (_a) {
135
+ React.createElement(popup_1.Popper, __assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), function (_a) {
136
136
  var placement = _a.placement;
137
137
  var transformOrigin = popup_1.getTransformFromPlacement(placement);
138
138
  return (React.createElement(TooltipContainer_1.TooltipContainer, __assign({ transformOrigin: transformOrigin }, tooltipProps, elemProps), titleText));
@@ -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,EAA4B,SAAS,EAAS,MAAM,iCAAiC,CAAC;AAM7F,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;;;;;;;;;;;;;;;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,kFAyClB,CAAC"}
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"}
@@ -66,19 +66,19 @@ function mergeCallbacks(elemProps, componentProps, keys) {
66
66
  exports.Tooltip = common_1.createComponent('div')({
67
67
  displayName: 'Tooltip',
68
68
  Component: function (_a) {
69
- var _b = _a.type, type = _b === void 0 ? 'label' : _b, _c = _a.placement, placement = _c === void 0 ? 'top' : _c, title = _a.title, children = _a.children, _d = _a.showDelay, showDelay = _d === void 0 ? 300 : _d, _e = _a.hideDelay, hideDelay = _e === void 0 ? 100 : _e, elemProps = __rest(_a, ["type", "placement", "title", "children", "showDelay", "hideDelay"]);
69
+ var _b = _a.type, type = _b === void 0 ? 'label' : _b, _c = _a.placement, placement = _c === void 0 ? 'top' : _c, title = _a.title, children = _a.children, _d = _a.showDelay, showDelay = _d === void 0 ? 300 : _d, _e = _a.hideDelay, hideDelay = _e === void 0 ? 100 : _e, _f = _a.fallbackPlacements, fallbackPlacements = _f === void 0 ? popup_1.defaultFallbackPlacements : _f, elemProps = __rest(_a, ["type", "placement", "title", "children", "showDelay", "hideDelay", "fallbackPlacements"]);
70
70
  var titleText = react_innertext_1.default(title);
71
- var _f = useTooltip_1.useTooltip({
71
+ var _g = useTooltip_1.useTooltip({
72
72
  type: type,
73
73
  titleText: titleText,
74
74
  showDelay: showDelay,
75
75
  hideDelay: hideDelay,
76
- }), targetProps = _f.targetProps, popperProps = _f.popperProps, tooltipProps = _f.tooltipProps;
76
+ }), targetProps = _g.targetProps, popperProps = _g.popperProps, tooltipProps = _g.tooltipProps;
77
77
  return (React.createElement(React.Fragment, null,
78
78
  React.cloneElement(children, __assign(__assign(__assign({}, targetProps), mergeCallbacks(children.props, targetProps)), (type === 'muted' && children.props['aria-label']
79
79
  ? { 'aria-label': children.props['aria-label'] }
80
80
  : {}))),
81
- React.createElement(popup_1.Popper, __assign({ placement: placement }, popperProps), function (_a) {
81
+ React.createElement(popup_1.Popper, __assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), function (_a) {
82
82
  var placement = _a.placement;
83
83
  var transformOrigin = popup_1.getTransformFromPlacement(placement);
84
84
  return (React.createElement(TooltipContainer_1.TooltipContainer, __assign({ transformOrigin: transformOrigin }, elemProps, tooltipProps), title));
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import * as PopperJS from '@popperjs/core';
3
3
  export declare type Placement = `${PopperJS.Placement}`;
4
4
  export declare type PopperOptions = PopperJS.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
@@ -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,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,oBAAY,SAAS,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;AAChD,oBAAY,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;AAK7C,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;;;;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,QAAQ,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,oFAQlB,CAAC"}
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,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,oBAAY,SAAS,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;AAChD,oBAAY,aAAa,GAAG,QAAQ,CAAC,OAAO,CAAC;AAC7C,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,QAAQ,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,oFAQlB,CAAC"}
@@ -28,8 +28,10 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
28
28
  import * as React from 'react';
29
29
  import * as ReactDOM from 'react-dom';
30
30
  import * as PopperJS from '@popperjs/core';
31
+ export var defaultFallbackPlacements = ['top', 'right', 'bottom', 'left'];
31
32
  import { usePopupStack } from './hooks';
32
33
  import { useLocalRef } from '@workday/canvas-kit-react/common';
34
+ import { fallbackPlacementsModifier } from './fallbackPlacements';
33
35
  /**
34
36
  * A thin wrapper component around the Popper.js positioning engine. For reference:
35
37
  * https://popper.js.org/. `Popper` also automatically works with the {@link PopupStack} system.
@@ -68,20 +70,24 @@ var defaultPopperOptions = {};
68
70
  // Popper bails early if `open` is false and React hooks cannot be called conditionally,
69
71
  // so we're breaking out the open version into another component.
70
72
  var OpenPopper = React.forwardRef(function (_a, ref) {
71
- var anchorElement = _a.anchorElement, getAnchorClientRect = _a.getAnchorClientRect, _b = _a.popperOptions, popperOptions = _b === void 0 ? defaultPopperOptions : _b, _c = _a.placement, popperPlacement = _c === void 0 ? 'bottom' : _c, onPlacementChange = _a.onPlacementChange, children = _a.children, portal = _a.portal, popperInstanceRef = _a.popperInstanceRef;
73
+ var anchorElement = _a.anchorElement, getAnchorClientRect = _a.getAnchorClientRect, _b = _a.popperOptions, popperOptions = _b === void 0 ? defaultPopperOptions : _b, _c = _a.placement, popperPlacement = _c === void 0 ? 'bottom' : _c, _d = _a.fallbackPlacements, fallbackPlacements = _d === void 0 ? defaultFallbackPlacements : _d, onPlacementChange = _a.onPlacementChange, children = _a.children, portal = _a.portal, popperInstanceRef = _a.popperInstanceRef;
72
74
  var firstRender = React.useRef(true);
73
- var _d = useLocalRef(popperInstanceRef), localRef = _d.localRef, elementRef = _d.elementRef;
74
- var _e = React.useState(popperPlacement), placement = _e[0], setPlacement = _e[1];
75
+ var _e = useLocalRef(popperInstanceRef), localRef = _e.localRef, elementRef = _e.elementRef;
76
+ var _f = React.useState(popperPlacement), placement = _f[0], setPlacement = _f[1];
75
77
  var stackRef = usePopupStack(ref, anchorElement);
78
+ var placementRef = React.useRef(popperPlacement);
79
+ placementRef.current = placement;
76
80
  var placementModifier = React.useMemo(function () {
77
81
  return {
78
82
  name: 'setPlacement',
79
83
  enabled: true,
80
- phase: 'main',
84
+ phase: 'afterWrite',
81
85
  fn: function (_a) {
82
86
  var state = _a.state;
83
- setPlacement(state.placement);
84
- onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement);
87
+ if (placementRef.current !== state.placement) {
88
+ setPlacement(state.placement);
89
+ onPlacementChange === null || onPlacementChange === void 0 ? void 0 : onPlacementChange(state.placement);
90
+ }
85
91
  },
86
92
  };
87
93
  }, [setPlacement, onPlacementChange]);
@@ -95,7 +101,12 @@ var OpenPopper = React.forwardRef(function (_a, ref) {
95
101
  return undefined;
96
102
  }
97
103
  if (stackRef.current) {
98
- var instance_1 = PopperJS.createPopper(anchorEl, stackRef.current, __assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray(__spreadArray([], (popperOptions.modifiers || [])), [placementModifier]) }));
104
+ var instance_1 = PopperJS.createPopper(anchorEl, stackRef.current, __assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray([
105
+ placementModifier,
106
+ __assign(__assign({}, fallbackPlacementsModifier), { options: {
107
+ fallbackPlacements: fallbackPlacements,
108
+ } })
109
+ ], (popperOptions.modifiers || [])) }));
99
110
  elementRef(instance_1); // update the ref with the instance
100
111
  return function () {
101
112
  instance_1 === null || instance_1 === void 0 ? void 0 : instance_1.destroy();
@@ -111,10 +122,15 @@ var OpenPopper = React.forwardRef(function (_a, ref) {
111
122
  var _a;
112
123
  // Only update options if this is _not_ the first render
113
124
  if (!firstRender.current) {
114
- (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions(__assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray(__spreadArray([], (popperOptions.modifiers || [])), [placementModifier]) }));
125
+ (_a = localRef.current) === null || _a === void 0 ? void 0 : _a.setOptions(__assign(__assign({ placement: popperPlacement }, popperOptions), { modifiers: __spreadArray([
126
+ placementModifier,
127
+ __assign(__assign({}, fallbackPlacementsModifier), { options: {
128
+ fallbackPlacements: fallbackPlacements,
129
+ } })
130
+ ], (popperOptions.modifiers || [])) }));
115
131
  }
116
132
  firstRender.current = false;
117
- }, [popperOptions, popperPlacement, placementModifier, localRef]);
133
+ }, [popperOptions, popperPlacement, fallbackPlacements, placementModifier, localRef]);
118
134
  var contents = React.createElement(React.Fragment, null, isRenderProp(children) ? children({ placement: placement }) : children);
119
135
  if (!portal) {
120
136
  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 * as PopperJS from '@popperjs/core';
2
+ export declare type Placement = PopperJS.Placement;
3
+ export declare type Options = {
4
+ fallbackPlacements: Placement[];
5
+ };
6
+ declare const name = "fallbackModifier";
7
+ export declare const fallbackPlacementsModifier: PopperJS.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,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C,oBAAY,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;AAyD3C,oBAAY,OAAO,GAAG;IACpB,kBAAkB,EAAE,SAAS,EAAE,CAAC;CACjC,CAAC;AAEF,QAAA,MAAM,IAAI,qBAAqB,CAAC;AAEhC,eAAO,MAAM,0BAA0B,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,OAAO,CAwB9E,CAAC"}
@@ -0,0 +1,88 @@
1
+ var __assign = (this && this.__assign) || function () {
2
+ __assign = Object.assign || function(t) {
3
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
4
+ s = arguments[i];
5
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
6
+ t[p] = s[p];
7
+ }
8
+ return t;
9
+ };
10
+ return __assign.apply(this, arguments);
11
+ };
12
+ var __spreadArray = (this && this.__spreadArray) || function (to, from) {
13
+ for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
14
+ to[j] = from[i];
15
+ return to;
16
+ };
17
+ import * as PopperJS from '@popperjs/core';
18
+ var getOppositePlacement = function (popperPlacement) {
19
+ var _a;
20
+ var _b = popperPlacement.split('-'), first = _b[0], second = _b[1];
21
+ var oppositePlacement;
22
+ switch (first) {
23
+ case 'top':
24
+ oppositePlacement = 'bottom';
25
+ break;
26
+ case 'bottom':
27
+ oppositePlacement = 'top';
28
+ break;
29
+ case 'left':
30
+ oppositePlacement = 'right';
31
+ break;
32
+ case 'right':
33
+ oppositePlacement = 'left';
34
+ break;
35
+ default:
36
+ oppositePlacement = 'auto';
37
+ }
38
+ if (second) {
39
+ oppositePlacement =
40
+ (_a = PopperJS.placements.find(function (placement) { return placement.includes(oppositePlacement + "-" + second); })) !== null && _a !== void 0 ? _a : oppositePlacement;
41
+ }
42
+ return oppositePlacement;
43
+ };
44
+ var choseAvailablePlacement = function (placements, state, preferredPlacement) {
45
+ if (placements.length === 0 || placements[0].split('-')[0] === 'auto') {
46
+ return preferredPlacement;
47
+ }
48
+ var _a = state.rects, reference = _a.reference, popper = _a.popper;
49
+ var overflow = PopperJS.detectOverflow(__assign(__assign({}, state), { placement: placements[0] }));
50
+ var direction = /left|right/.test(placements[0].split('-')[0]) ? 'horizontal' : 'vertical';
51
+ var isOverflowed = (overflow.top > 0 || overflow.bottom > 0 || overflow.left > 0 || overflow.right > 0) &&
52
+ (direction === 'horizontal'
53
+ ? popper.height / 2 - overflow.top < reference.height ||
54
+ popper.height / 2 - overflow.bottom < reference.height
55
+ : popper.width - overflow.left < reference.width ||
56
+ popper.width - overflow.right < reference.width);
57
+ var key = placements[0].split('-')[0];
58
+ if (!isOverflowed && overflow[key] <= 0) {
59
+ return placements[0];
60
+ }
61
+ else {
62
+ return choseAvailablePlacement(placements.slice(1), state, preferredPlacement);
63
+ }
64
+ };
65
+ var name = 'fallbackModifier';
66
+ export var fallbackPlacementsModifier = {
67
+ name: name,
68
+ enabled: true,
69
+ phase: 'main',
70
+ data: {
71
+ _skip: false,
72
+ },
73
+ fn: function (_a) {
74
+ var state = _a.state, options = _a.options;
75
+ var preferredPlacement = state.options.placement;
76
+ var fallbackPlacements = options.fallbackPlacements;
77
+ var placements = __spreadArray([
78
+ preferredPlacement,
79
+ getOppositePlacement(preferredPlacement)
80
+ ], (fallbackPlacements || []));
81
+ var placementOverride = choseAvailablePlacement(placements, state, preferredPlacement);
82
+ if (state.placement !== placementOverride) {
83
+ state.modifiersData[name]._skip = true;
84
+ state.placement = placementOverride;
85
+ state.reset = true;
86
+ }
87
+ },
88
+ };
@@ -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;;;;;;;;;;;;;;;;;;;;;mCAGX,SAAS;;;OAevB,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;;;OAevB,CAAC"}
@@ -8,12 +8,15 @@ import React from 'react';
8
8
  export var usePopupPopper = createElemPropsHook(usePopupModel)(function (_a, ref) {
9
9
  var state = _a.state, events = _a.events;
10
10
  var elementRef = useForkRef(ref, state.stackRef);
11
+ // Create a mutable ref of the placement to keep a stable `onPlacementChange` reference.
12
+ var placementRef = React.useRef(state.placement);
13
+ placementRef.current = state.placement;
11
14
  var onPlacementChange = React.useCallback(function (placement) {
12
- if (placement !== state.placement) {
15
+ if (placement !== placementRef.current) {
13
16
  // only update if the placement has changed
14
17
  events.updatePlacement({ placement: placement });
15
18
  }
16
- }, [events, state.placement]);
19
+ }, [events]);
17
20
  return {
18
21
  open: state.visibility !== 'hidden',
19
22
  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,EAA4B,SAAS,EAAS,MAAM,iCAAiC,CAAC;AAM7F;;;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;CACvB;AAiBD,eAAO,MAAM,eAAe,0CAIzB,oBAAoB,gBAwCtB,CAAC"}
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"}
@@ -21,7 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  return t;
22
22
  };
23
23
  import * as React from 'react';
24
- import { getTransformFromPlacement, Popper } from '@workday/canvas-kit-react/popup';
24
+ import { getTransformFromPlacement, Popper, defaultFallbackPlacements, } from '@workday/canvas-kit-react/popup';
25
25
  import { mergeCallback } from '@workday/canvas-kit-react/common';
26
26
  import { TooltipContainer } from './TooltipContainer';
27
27
  import { useTooltip } from './useTooltip';
@@ -88,9 +88,9 @@ function mergeCallbacks(elemProps, componentProps, keys) {
88
88
  }, {});
89
89
  }
90
90
  export var OverflowTooltip = function (_a) {
91
- var _b = _a.placement, placement = _b === void 0 ? 'top' : _b, children = _a.children, elemProps = __rest(_a, ["placement", "children"]);
92
- var _c = React.useState(''), titleText = _c[0], setTitleText = _c[1];
93
- var _d = useTooltip({ type: 'muted' }), targetProps = _d.targetProps, popperProps = _d.popperProps, tooltipProps = _d.tooltipProps;
91
+ var _b = _a.placement, placement = _b === void 0 ? 'top' : _b, _c = _a.fallbackPlacements, fallbackPlacements = _c === void 0 ? defaultFallbackPlacements : _c, children = _a.children, elemProps = __rest(_a, ["placement", "fallbackPlacements", "children"]);
92
+ var _d = React.useState(''), titleText = _d[0], setTitleText = _d[1];
93
+ var _e = useTooltip({ type: 'muted' }), targetProps = _e.targetProps, popperProps = _e.popperProps, tooltipProps = _e.tooltipProps;
94
94
  var onMouseEnter = function (event) {
95
95
  var target = event.currentTarget;
96
96
  setTitleText(target instanceof HTMLElement ? target.innerText : '');
@@ -108,7 +108,7 @@ export var OverflowTooltip = function (_a) {
108
108
  return (React.createElement(React.Fragment, null,
109
109
  React.cloneElement(children, __assign(__assign(__assign({}, targetProps), { onMouseEnter: onMouseEnter,
110
110
  onFocus: onFocus, 'aria-label': undefined }), mergeCallbacks(__assign(__assign({}, targetProps), { onMouseEnter: onMouseEnter, onFocus: onFocus }), children.props))),
111
- React.createElement(Popper, __assign({ placement: placement }, popperProps), function (_a) {
111
+ React.createElement(Popper, __assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), function (_a) {
112
112
  var placement = _a.placement;
113
113
  var transformOrigin = getTransformFromPlacement(placement);
114
114
  return (React.createElement(TooltipContainer, __assign({ transformOrigin: transformOrigin }, tooltipProps, elemProps), titleText));
@@ -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,EAA4B,SAAS,EAAS,MAAM,iCAAiC,CAAC;AAM7F,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;;;;;;;;;;;;;;;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,kFAyClB,CAAC"}
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"}
@@ -22,7 +22,7 @@ var __rest = (this && this.__rest) || function (s, e) {
22
22
  };
23
23
  import * as React from 'react';
24
24
  import innerText from 'react-innertext';
25
- import { getTransformFromPlacement, Popper } from '@workday/canvas-kit-react/popup';
25
+ import { getTransformFromPlacement, Popper, defaultFallbackPlacements, } from '@workday/canvas-kit-react/popup';
26
26
  import { createComponent, mergeCallback } from '@workday/canvas-kit-react/common';
27
27
  import { TooltipContainer } from './TooltipContainer';
28
28
  import { useTooltip } from './useTooltip';
@@ -41,19 +41,19 @@ function mergeCallbacks(elemProps, componentProps, keys) {
41
41
  export var Tooltip = createComponent('div')({
42
42
  displayName: 'Tooltip',
43
43
  Component: function (_a) {
44
- var _b = _a.type, type = _b === void 0 ? 'label' : _b, _c = _a.placement, placement = _c === void 0 ? 'top' : _c, title = _a.title, children = _a.children, _d = _a.showDelay, showDelay = _d === void 0 ? 300 : _d, _e = _a.hideDelay, hideDelay = _e === void 0 ? 100 : _e, elemProps = __rest(_a, ["type", "placement", "title", "children", "showDelay", "hideDelay"]);
44
+ var _b = _a.type, type = _b === void 0 ? 'label' : _b, _c = _a.placement, placement = _c === void 0 ? 'top' : _c, title = _a.title, children = _a.children, _d = _a.showDelay, showDelay = _d === void 0 ? 300 : _d, _e = _a.hideDelay, hideDelay = _e === void 0 ? 100 : _e, _f = _a.fallbackPlacements, fallbackPlacements = _f === void 0 ? defaultFallbackPlacements : _f, elemProps = __rest(_a, ["type", "placement", "title", "children", "showDelay", "hideDelay", "fallbackPlacements"]);
45
45
  var titleText = innerText(title);
46
- var _f = useTooltip({
46
+ var _g = useTooltip({
47
47
  type: type,
48
48
  titleText: titleText,
49
49
  showDelay: showDelay,
50
50
  hideDelay: hideDelay,
51
- }), targetProps = _f.targetProps, popperProps = _f.popperProps, tooltipProps = _f.tooltipProps;
51
+ }), targetProps = _g.targetProps, popperProps = _g.popperProps, tooltipProps = _g.tooltipProps;
52
52
  return (React.createElement(React.Fragment, null,
53
53
  React.cloneElement(children, __assign(__assign(__assign({}, targetProps), mergeCallbacks(children.props, targetProps)), (type === 'muted' && children.props['aria-label']
54
54
  ? { 'aria-label': children.props['aria-label'] }
55
55
  : {}))),
56
- React.createElement(Popper, __assign({ placement: placement }, popperProps), function (_a) {
56
+ React.createElement(Popper, __assign({ placement: placement, fallbackPlacements: fallbackPlacements }, popperProps), function (_a) {
57
57
  var placement = _a.placement;
58
58
  var transformOrigin = getTransformFromPlacement(placement);
59
59
  return (React.createElement(TooltipContainer, __assign({ transformOrigin: transformOrigin }, elemProps, tooltipProps), title));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workday/canvas-kit-react",
3
- "version": "8.6.10",
3
+ "version": "8.6.11",
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": "^8.6.10",
52
+ "@workday/canvas-kit-popup-stack": "^8.6.11",
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",
@@ -67,5 +67,5 @@
67
67
  "@workday/canvas-accent-icons-web": "^3.0.0",
68
68
  "@workday/canvas-applet-icons-web": "^2.0.0"
69
69
  },
70
- "gitHead": "bb8329642b121f28363380a4de395d97c30afa7a"
70
+ "gitHead": "2281a7827d217de9c9532f480579becac6550607"
71
71
  }
@@ -4,9 +4,11 @@ import * as PopperJS from '@popperjs/core';
4
4
 
5
5
  export type Placement = `${PopperJS.Placement}`; // Use template literals to make documentation list them out
6
6
  export type PopperOptions = PopperJS.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
@@ -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
 
142
+ const placementRef = React.useRef(popperPlacement);
143
+ placementRef.current = placement;
144
+
132
145
  const placementModifier = React.useMemo((): PopperJS.Modifier<any, any> => {
133
146
  return {
134
147
  name: 'setPlacement',
135
148
  enabled: true,
136
- phase: 'main',
149
+ phase: 'afterWrite',
137
150
  fn({state}) {
138
- setPlacement(state.placement);
139
- onPlacementChange?.(state.placement);
151
+ if (placementRef.current !== state.placement) {
152
+ setPlacement(state.placement);
153
+ onPlacementChange?.(state.placement);
154
+ }
140
155
  },
141
156
  };
142
157
  }, [setPlacement, onPlacementChange]);
@@ -157,7 +172,16 @@ const OpenPopper = React.forwardRef<HTMLDivElement, PopperProps>(
157
172
  const instance = PopperJS.createPopper(anchorEl, stackRef.current, {
158
173
  placement: popperPlacement,
159
174
  ...popperOptions,
160
- modifiers: [...(popperOptions.modifiers || []), placementModifier],
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: [...(popperOptions.modifiers || []), placementModifier],
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,90 @@
1
+ import * as PopperJS from '@popperjs/core';
2
+
3
+ export type Placement = PopperJS.Placement; // Use template literals to make documentation list them out
4
+
5
+ const getOppositePlacement = (popperPlacement: Placement): Placement => {
6
+ const [first, second] = popperPlacement.split('-');
7
+ let oppositePlacement: Placement;
8
+ switch (first) {
9
+ case 'top':
10
+ oppositePlacement = 'bottom';
11
+ break;
12
+ case 'bottom':
13
+ oppositePlacement = 'top';
14
+ break;
15
+ case 'left':
16
+ oppositePlacement = 'right';
17
+ break;
18
+ case 'right':
19
+ oppositePlacement = 'left';
20
+ break;
21
+ default:
22
+ oppositePlacement = 'auto';
23
+ }
24
+ if (second) {
25
+ oppositePlacement =
26
+ PopperJS.placements.find(placement => placement.includes(`${oppositePlacement}-${second}`)) ??
27
+ oppositePlacement;
28
+ }
29
+ return oppositePlacement;
30
+ };
31
+
32
+ const choseAvailablePlacement = (
33
+ placements: Placement[],
34
+ state: PopperJS.State,
35
+ preferredPlacement: Placement
36
+ ): Placement => {
37
+ if (placements.length === 0 || placements[0].split('-')[0] === 'auto') {
38
+ return preferredPlacement;
39
+ }
40
+
41
+ const {reference, popper} = state.rects;
42
+ const overflow = PopperJS.detectOverflow({...state, placement: placements[0]});
43
+ const direction = /left|right/.test(placements[0].split('-')[0]) ? 'horizontal' : 'vertical';
44
+ const isOverflowed =
45
+ (overflow.top > 0 || overflow.bottom > 0 || overflow.left > 0 || overflow.right > 0) &&
46
+ (direction === 'horizontal'
47
+ ? popper.height / 2 - overflow.top < reference.height ||
48
+ popper.height / 2 - overflow.bottom < reference.height
49
+ : popper.width - overflow.left < reference.width ||
50
+ popper.width - overflow.right < reference.width);
51
+ const key = placements[0].split('-')[0] as keyof PopperJS.SideObject;
52
+
53
+ if (!isOverflowed && overflow[key] <= 0) {
54
+ return placements[0];
55
+ } else {
56
+ return choseAvailablePlacement(placements.slice(1), state, preferredPlacement);
57
+ }
58
+ };
59
+
60
+ export type Options = {
61
+ fallbackPlacements: Placement[];
62
+ };
63
+
64
+ const name = 'fallbackModifier';
65
+
66
+ export const fallbackPlacementsModifier: PopperJS.Modifier<typeof name, Options> = {
67
+ name: name,
68
+ enabled: true,
69
+ phase: 'main',
70
+ data: {
71
+ _skip: false,
72
+ },
73
+ fn({state, options}: PopperJS.ModifierArguments<Options>) {
74
+ const preferredPlacement = state.options.placement;
75
+ const {fallbackPlacements} = options;
76
+
77
+ const placements = [
78
+ preferredPlacement,
79
+ getOppositePlacement(preferredPlacement),
80
+ ...(fallbackPlacements || []),
81
+ ];
82
+
83
+ const placementOverride = choseAvailablePlacement(placements, state, preferredPlacement);
84
+ if (state.placement !== placementOverride) {
85
+ state.modifiersData[name]._skip = true;
86
+ state.placement = placementOverride;
87
+ state.reset = true;
88
+ }
89
+ },
90
+ };
@@ -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 !== state.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, state.placement]
23
+ [events]
20
24
  );
21
25
 
22
26
  return {
@@ -1,6 +1,11 @@
1
1
  import * as React from 'react';
2
2
 
3
- import {getTransformFromPlacement, Placement, Popper} from '@workday/canvas-kit-react/popup';
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 (
@@ -1,7 +1,12 @@
1
1
  import * as React from 'react';
2
2
  import innerText from 'react-innertext';
3
3
 
4
- import {getTransformFromPlacement, Placement, Popper} from '@workday/canvas-kit-react/popup';
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 (