@workday/canvas-kit-popup-stack 8.0.0-alpha.253-next.22 → 8.0.0-alpha.428-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/lib/PopupStack.d.ts +22 -0
- package/dist/commonjs/lib/PopupStack.d.ts.map +1 -1
- package/dist/commonjs/lib/PopupStack.js +82 -65
- package/dist/es6/lib/PopupStack.d.ts +22 -0
- package/dist/es6/lib/PopupStack.d.ts.map +1 -1
- package/dist/es6/lib/PopupStack.js +82 -65
- package/lib/PopupStack.ts +22 -0
- package/package.json +2 -2
|
@@ -42,6 +42,24 @@ interface Stack {
|
|
|
42
42
|
};
|
|
43
43
|
_adapter: Partial<typeof PopupStack>;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The `PopupStack` is a framework agnostic first-in-last-out (FILO) stack that tracks all popups
|
|
47
|
+
* ("floating UI" or any UI that renders on top of other content). It contains methods that interact
|
|
48
|
+
* with the stack to support all coordinating behaviors of all popups on the page. The `PopupStack`
|
|
49
|
+
* helps:
|
|
50
|
+
*
|
|
51
|
+
* - Render popups in the right order on the page
|
|
52
|
+
* - Helps accessibility with the Escape key (topmost popup is closed)
|
|
53
|
+
* - Handles transition to [Full
|
|
54
|
+
* Screen](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
|
|
55
|
+
*
|
|
56
|
+
* The `PopupStack` supports adapters to work with existing popup systems. {@link createAdapter} is
|
|
57
|
+
* exported to accept an adapter. Only a single adapter should be used per page.
|
|
58
|
+
*
|
|
59
|
+
* The `PopupStack` is designed to handle multiple versions of `PopupStack` on the page at once
|
|
60
|
+
* while the internal FILO stack is shared between instances. You should not attempt to use the
|
|
61
|
+
* internal FILO stack. If an adapter is used, the internal FILO stack may be empty.
|
|
62
|
+
*/
|
|
45
63
|
export declare const PopupStack: {
|
|
46
64
|
/**
|
|
47
65
|
* Create a HTMLElement as the container for the popup stack item. The returned element reference
|
|
@@ -139,6 +157,10 @@ export declare const PopupStack: {
|
|
|
139
157
|
*/
|
|
140
158
|
export declare function resetStack(): void;
|
|
141
159
|
/**
|
|
160
|
+
* An adapter is a custom implementation of the {@link PopupStack}. There is only ever a single
|
|
161
|
+
* instance of an adapter on the page. It allows an adapter to intercept any `PopupStack` method.
|
|
162
|
+
* This could bypass the internal FILO stack of the `PopupStack` and allows the FILO stack to be
|
|
163
|
+
* handled by something else.
|
|
142
164
|
*
|
|
143
165
|
* @param adapter The parts of the PopupStack that we want to override
|
|
144
166
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PopupStack.d.ts","sourceRoot":"","sources":["../../../lib/PopupStack.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AASD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAO9D;AA2CD,UAAU,KAAK;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,WAAW,CAAC;IAC9B,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,OAAO,QAAQ,CAAC;KAC3B,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC,OAAO,UAAU,CAAC,CAAC;CACtC;AAwFD,eAAO,MAAM,UAAU;IACrB;;;;;OAKG;uBACgB,WAAW;IAS9B;;;;;OAKG;cACO,cAAc,GAAG,IAAI;IAY/B;;;;;;OAMG;oBACa,WAAW,GAAG,IAAI;IAelC;;;;OAIG;uBACgB,WAAW,GAAG,OAAO;IAaxC;;;;OAIG;oDACiC,WAAW,EAAE;IAQjD;;;;;;;;;;;OAWG;wBACiB,WAAW,GAAG,IAAI;IA6BtC;;;;;;;;;;OAUG;sBACe,WAAW,eAAe,WAAW,GAAG,OAAO;IA2BjE;;;;;;OAMG;gCACyB,WAAW,GAAG,IAAI;IAoB9C;;;;OAIG;+BACwB,WAAW,GAAG,IAAI;IAY7C;;;;;;;;;;;;;;OAcG;mCAC4B,cAAc,GAAG,IAAI;CAqBrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,UAAU,SAEzB;AAED
|
|
1
|
+
{"version":3,"file":"PopupStack.d.ts","sourceRoot":"","sources":["../../../lib/PopupStack.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AASD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAO9D;AA2CD,UAAU,KAAK;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,WAAW,CAAC;IAC9B,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,OAAO,QAAQ,CAAC;KAC3B,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC,OAAO,UAAU,CAAC,CAAC;CACtC;AAwFD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU;IACrB;;;;;OAKG;uBACgB,WAAW;IAS9B;;;;;OAKG;cACO,cAAc,GAAG,IAAI;IAY/B;;;;;;OAMG;oBACa,WAAW,GAAG,IAAI;IAelC;;;;OAIG;uBACgB,WAAW,GAAG,OAAO;IAaxC;;;;OAIG;oDACiC,WAAW,EAAE;IAQjD;;;;;;;;;;;OAWG;wBACiB,WAAW,GAAG,IAAI;IA6BtC;;;;;;;;;;OAUG;sBACe,WAAW,eAAe,WAAW,GAAG,OAAO;IA2BjE;;;;;;OAMG;gCACyB,WAAW,GAAG,IAAI;IAoB9C;;;;OAIG;+BACwB,WAAW,GAAG,IAAI;IAY7C;;;;;;;;;;;;;;OAcG;mCAC4B,cAAc,GAAG,IAAI;CAqBrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,UAAU,SAEzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,YAAa,QAAQ,iBAAiB,CAAC,SAEhE,CAAC"}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __spreadArrays = (this && this.__spreadArrays) || function () {
|
|
3
|
-
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
|
4
|
-
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
|
5
|
-
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
|
6
|
-
r[k] = a[j];
|
|
7
|
-
return r;
|
|
8
|
-
};
|
|
9
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
4
|
};
|
|
12
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
6
|
exports.createAdapter = exports.resetStack = exports.PopupStack = exports.getValue = void 0;
|
|
14
|
-
|
|
7
|
+
const screenfull_1 = __importDefault(require("screenfull"));
|
|
15
8
|
function getLast(items) {
|
|
16
9
|
if (items.length) {
|
|
17
10
|
return items[items.length - 1];
|
|
@@ -25,7 +18,7 @@ function getLast(items) {
|
|
|
25
18
|
* popups.
|
|
26
19
|
*/
|
|
27
20
|
function getValue(index, length) {
|
|
28
|
-
|
|
21
|
+
const { min, max } = stack.zIndex;
|
|
29
22
|
if (length <= max - min) {
|
|
30
23
|
return index + min;
|
|
31
24
|
}
|
|
@@ -37,8 +30,8 @@ exports.getValue = getValue;
|
|
|
37
30
|
* will be run any time the stack changes.
|
|
38
31
|
*/
|
|
39
32
|
function setZIndexOfElements(elements) {
|
|
40
|
-
|
|
41
|
-
elements.forEach(
|
|
33
|
+
const length = elements.length;
|
|
34
|
+
elements.forEach((element, index) => {
|
|
42
35
|
element.style.zIndex = String(getValue(index, length));
|
|
43
36
|
});
|
|
44
37
|
}
|
|
@@ -47,9 +40,9 @@ function setZIndexOfElements(elements) {
|
|
|
47
40
|
* to the stack.
|
|
48
41
|
*/
|
|
49
42
|
function getOwnerPopup(element, items) {
|
|
50
|
-
|
|
43
|
+
let parentEl = element;
|
|
51
44
|
do {
|
|
52
|
-
|
|
45
|
+
const owner = items.find(el => el.element === parentEl);
|
|
53
46
|
if (owner) {
|
|
54
47
|
return owner.element;
|
|
55
48
|
}
|
|
@@ -62,10 +55,10 @@ function getOwnerPopup(element, items) {
|
|
|
62
55
|
* hierarchy.
|
|
63
56
|
*/
|
|
64
57
|
function getChildPopups(item, items) {
|
|
65
|
-
|
|
66
|
-
.filter(
|
|
67
|
-
.map(
|
|
68
|
-
.filter(
|
|
58
|
+
const owners = items
|
|
59
|
+
.filter(i => i.owner)
|
|
60
|
+
.map(i => ({ element: i.element, parent: getOwnerPopup(i.owner, items) }))
|
|
61
|
+
.filter(i => i.parent === item.element);
|
|
69
62
|
return owners;
|
|
70
63
|
}
|
|
71
64
|
/**
|
|
@@ -75,8 +68,8 @@ function getChildPopups(item, items) {
|
|
|
75
68
|
* @param path dot-notation path of a deep property
|
|
76
69
|
*/
|
|
77
70
|
function get(obj, path) {
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
const parts = path.split('.');
|
|
72
|
+
const first = parts.splice(0, 1)[0];
|
|
80
73
|
if (parts.length && obj[first]) {
|
|
81
74
|
return get(obj[first], parts.join('.'));
|
|
82
75
|
}
|
|
@@ -91,8 +84,8 @@ function get(obj, path) {
|
|
|
91
84
|
* @param value Any value
|
|
92
85
|
*/
|
|
93
86
|
function set(obj, path, value) {
|
|
94
|
-
|
|
95
|
-
|
|
87
|
+
const parts = path.split('.');
|
|
88
|
+
const first = parts.splice(0, 1)[0];
|
|
96
89
|
if (parts.length) {
|
|
97
90
|
if (obj[first] === undefined) {
|
|
98
91
|
obj[first] = {};
|
|
@@ -113,7 +106,7 @@ if (typeof window !== 'undefined') {
|
|
|
113
106
|
* environments without a `window` object, so it is safe to use in server-side rendering.
|
|
114
107
|
* @param path Any dot-notation path
|
|
115
108
|
*/
|
|
116
|
-
|
|
109
|
+
const getFromWindow = (path) => {
|
|
117
110
|
if (typeof window !== 'undefined') {
|
|
118
111
|
return get(window, path);
|
|
119
112
|
}
|
|
@@ -125,7 +118,7 @@ var getFromWindow = function (path) {
|
|
|
125
118
|
* @param path dot-notation path of a deep property
|
|
126
119
|
* @param value Any value
|
|
127
120
|
*/
|
|
128
|
-
|
|
121
|
+
const setToWindow = (path, value) => {
|
|
129
122
|
if (typeof window !== 'undefined') {
|
|
130
123
|
set(window, path, value);
|
|
131
124
|
}
|
|
@@ -133,20 +126,38 @@ var setToWindow = function (path, value) {
|
|
|
133
126
|
// We need to make sure only one stack is ever in use on the page - ever. If a stack is already
|
|
134
127
|
// defined on the page, we need to use that one. Never, ever, ever change this variable name on
|
|
135
128
|
// window
|
|
136
|
-
|
|
129
|
+
const stack = getFromWindow('workday.__popupStack') || {
|
|
137
130
|
description: 'Global popup stack from @workday/canvas-kit/popup-stack',
|
|
138
|
-
container:
|
|
131
|
+
container: () => document.body,
|
|
139
132
|
items: [],
|
|
140
133
|
zIndex: { min: 30, max: 50, getValue: getValue },
|
|
141
134
|
_adapter: {},
|
|
142
135
|
};
|
|
143
136
|
setToWindow('workday.__popupStack', stack);
|
|
144
|
-
|
|
137
|
+
const stacks = getFromWindow('workday.__popupStackOfStacks') || [stack];
|
|
145
138
|
stacks.description = 'Global stack of popup stacks from @workday/canvas-kit/popup-stack';
|
|
146
139
|
setToWindow('workday.__popupStackOfStacks', stacks);
|
|
147
140
|
function getTopStack() {
|
|
148
141
|
return stacks[stacks.length - 1];
|
|
149
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* The `PopupStack` is a framework agnostic first-in-last-out (FILO) stack that tracks all popups
|
|
145
|
+
* ("floating UI" or any UI that renders on top of other content). It contains methods that interact
|
|
146
|
+
* with the stack to support all coordinating behaviors of all popups on the page. The `PopupStack`
|
|
147
|
+
* helps:
|
|
148
|
+
*
|
|
149
|
+
* - Render popups in the right order on the page
|
|
150
|
+
* - Helps accessibility with the Escape key (topmost popup is closed)
|
|
151
|
+
* - Handles transition to [Full
|
|
152
|
+
* Screen](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
|
|
153
|
+
*
|
|
154
|
+
* The `PopupStack` supports adapters to work with existing popup systems. {@link createAdapter} is
|
|
155
|
+
* exported to accept an adapter. Only a single adapter should be used per page.
|
|
156
|
+
*
|
|
157
|
+
* The `PopupStack` is designed to handle multiple versions of `PopupStack` on the page at once
|
|
158
|
+
* while the internal FILO stack is shared between instances. You should not attempt to use the
|
|
159
|
+
* internal FILO stack. If an adapter is used, the internal FILO stack may be empty.
|
|
160
|
+
*/
|
|
150
161
|
exports.PopupStack = {
|
|
151
162
|
/**
|
|
152
163
|
* Create a HTMLElement as the container for the popup stack item. The returned element reference
|
|
@@ -154,13 +165,13 @@ exports.PopupStack = {
|
|
|
154
165
|
* element is added and removed from the DOM as well as the `z-index` style property. Your content
|
|
155
166
|
* should be added to this element.
|
|
156
167
|
*/
|
|
157
|
-
createContainer
|
|
168
|
+
createContainer() {
|
|
158
169
|
var _a;
|
|
159
|
-
|
|
170
|
+
const stack = getTopStack();
|
|
160
171
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.createContainer) {
|
|
161
172
|
return stack._adapter.createContainer();
|
|
162
173
|
}
|
|
163
|
-
|
|
174
|
+
const div = document.createElement('div');
|
|
164
175
|
div.style.position = 'relative'; // z-index only works on _positioned_ elements
|
|
165
176
|
return div;
|
|
166
177
|
},
|
|
@@ -170,9 +181,9 @@ exports.PopupStack = {
|
|
|
170
181
|
* popups to be registered initially, but rendered when the user triggers some event, call this
|
|
171
182
|
* method when the event triggers.
|
|
172
183
|
*/
|
|
173
|
-
add
|
|
184
|
+
add(item) {
|
|
174
185
|
var _a, _b;
|
|
175
|
-
|
|
186
|
+
const stack = getTopStack();
|
|
176
187
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.add) {
|
|
177
188
|
stack._adapter.add(item);
|
|
178
189
|
return;
|
|
@@ -188,16 +199,16 @@ exports.PopupStack = {
|
|
|
188
199
|
* called when the element is removed from the DOM. This method will reset z-index values of the
|
|
189
200
|
* stack.
|
|
190
201
|
*/
|
|
191
|
-
remove
|
|
202
|
+
remove(element) {
|
|
192
203
|
var _a, _b;
|
|
193
204
|
// Find the stack the popup belongs to.
|
|
194
|
-
|
|
205
|
+
const stack = stacks.find(stack => !!exports.PopupStack.getElements(stack).find(el => el === element));
|
|
195
206
|
if (stack) {
|
|
196
207
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.remove) {
|
|
197
208
|
stack._adapter.remove(element);
|
|
198
209
|
return;
|
|
199
210
|
}
|
|
200
|
-
stack.items = stack.items.filter(
|
|
211
|
+
stack.items = stack.items.filter(item => item.element !== element);
|
|
201
212
|
(((_b = stack.container) === null || _b === void 0 ? void 0 : _b.call(stack)) || document.body).removeChild(element);
|
|
202
213
|
setZIndexOfElements(exports.PopupStack.getElements(stack));
|
|
203
214
|
}
|
|
@@ -207,13 +218,13 @@ exports.PopupStack = {
|
|
|
207
218
|
* is not the top of the stack or is not found in the stack. The `element` should be the same
|
|
208
219
|
* reference that was passed to `add`
|
|
209
220
|
*/
|
|
210
|
-
isTopmost
|
|
221
|
+
isTopmost(element) {
|
|
211
222
|
var _a;
|
|
212
|
-
|
|
223
|
+
const stack = getTopStack();
|
|
213
224
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.isTopmost) {
|
|
214
225
|
return stack._adapter.isTopmost(element);
|
|
215
226
|
}
|
|
216
|
-
|
|
227
|
+
const last = getLast(stack.items);
|
|
217
228
|
if (last) {
|
|
218
229
|
return last.element === element;
|
|
219
230
|
}
|
|
@@ -224,13 +235,13 @@ exports.PopupStack = {
|
|
|
224
235
|
* elements in the order of lowest z-index to highest z-index. Some popup behaviors will need to
|
|
225
236
|
* make decisions based on z-index order.
|
|
226
237
|
*/
|
|
227
|
-
getElements
|
|
238
|
+
getElements(stackOverride) {
|
|
228
239
|
var _a;
|
|
229
|
-
|
|
240
|
+
const stack = stackOverride || getTopStack();
|
|
230
241
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.getElements) {
|
|
231
242
|
return stack._adapter.getElements();
|
|
232
243
|
}
|
|
233
|
-
return stack.items.map(
|
|
244
|
+
return stack.items.map(i => i.element);
|
|
234
245
|
},
|
|
235
246
|
/**
|
|
236
247
|
* Bring the element to the top of the stack. This is useful for persistent popups to place them
|
|
@@ -244,30 +255,30 @@ exports.PopupStack = {
|
|
|
244
255
|
* This does not need to be called when a popup is added since added popups are already place on
|
|
245
256
|
* the top of the stack.
|
|
246
257
|
*/
|
|
247
|
-
bringToTop
|
|
258
|
+
bringToTop(element) {
|
|
248
259
|
var _a;
|
|
249
|
-
|
|
260
|
+
const stack = getTopStack();
|
|
250
261
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.bringToTop) {
|
|
251
262
|
stack._adapter.bringToTop(element);
|
|
252
263
|
return;
|
|
253
264
|
}
|
|
254
|
-
|
|
265
|
+
const item = stack.items.find(i => i.element === element);
|
|
255
266
|
if (item) {
|
|
256
|
-
stack.items =
|
|
267
|
+
stack.items = [...stack.items.filter(i => i !== item), item];
|
|
257
268
|
// Also bring children to top. There are a few cases where stacking might break otherwise:
|
|
258
269
|
// - Clicking a Popup calls `bringToTop`, but mouse is over a Tooltip so that Tooltip is now
|
|
259
270
|
// under the Popup
|
|
260
271
|
// - Clicking a button opens a new Popup, but that click bubbles up to a `bringToTop` call
|
|
261
272
|
// putting the new popup under an existing one
|
|
262
273
|
// Example: https://user-images.githubusercontent.com/338257/83924476-031af580-a742-11ea-8f68-0edabdf0fd6a.gif
|
|
263
|
-
getChildPopups(item, stack.items).forEach(
|
|
274
|
+
getChildPopups(item, stack.items).forEach(popup => {
|
|
264
275
|
exports.PopupStack.bringToTop(popup.element);
|
|
265
276
|
});
|
|
266
277
|
setZIndexOfElements(exports.PopupStack.getElements());
|
|
267
278
|
}
|
|
268
279
|
else {
|
|
269
280
|
// not found
|
|
270
|
-
|
|
281
|
+
const e = new Error();
|
|
271
282
|
console.warn('Could not find item', e.stack);
|
|
272
283
|
}
|
|
273
284
|
},
|
|
@@ -282,22 +293,24 @@ exports.PopupStack = {
|
|
|
282
293
|
* opt-in to toggling. Otherwise there is no way to opt-out of toggle behavior (because the target
|
|
283
294
|
* is not inside `element`).
|
|
284
295
|
*/
|
|
285
|
-
contains
|
|
296
|
+
contains(element, eventTarget) {
|
|
286
297
|
var _a, _b;
|
|
287
|
-
|
|
298
|
+
const stack = getTopStack();
|
|
288
299
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.contains) {
|
|
289
300
|
return stack._adapter.contains(element, eventTarget);
|
|
290
301
|
}
|
|
291
|
-
|
|
292
|
-
|
|
302
|
+
const item = stack.items.find(i => i.element === element);
|
|
303
|
+
const containsOwnerOfAnotherPopupTargeted = stack.items.some(currentItem => {
|
|
293
304
|
var _a;
|
|
294
305
|
return ((item === null || item === void 0 ? void 0 : item.element.contains(currentItem.owner || null)) &&
|
|
295
|
-
(eventTarget === currentItem.owner ||
|
|
306
|
+
(eventTarget === currentItem.owner ||
|
|
307
|
+
((_a = currentItem.owner) === null || _a === void 0 ? void 0 : _a.contains(eventTarget)) ||
|
|
296
308
|
currentItem.element.contains(eventTarget)));
|
|
297
309
|
});
|
|
298
310
|
if (item) {
|
|
299
311
|
return (containsOwnerOfAnotherPopupTargeted ||
|
|
300
|
-
eventTarget === item.owner ||
|
|
312
|
+
eventTarget === item.owner ||
|
|
313
|
+
((_b = item.owner) === null || _b === void 0 ? void 0 : _b.contains(eventTarget)) ||
|
|
301
314
|
element.contains(eventTarget));
|
|
302
315
|
}
|
|
303
316
|
return false;
|
|
@@ -309,9 +322,9 @@ exports.PopupStack = {
|
|
|
309
322
|
* pushing the same element which is very difficult to ensure only one stack is used. To mitigate,
|
|
310
323
|
* this method filters out multiple calls to push the same element as a new stack context.
|
|
311
324
|
*/
|
|
312
|
-
pushStackContext
|
|
325
|
+
pushStackContext(container) {
|
|
313
326
|
var _a, _b;
|
|
314
|
-
|
|
327
|
+
const stack = getTopStack();
|
|
315
328
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.pushStackContext) {
|
|
316
329
|
return stack._adapter.pushStackContext(container);
|
|
317
330
|
}
|
|
@@ -319,10 +332,10 @@ exports.PopupStack = {
|
|
|
319
332
|
if (((_b = stack.container) === null || _b === void 0 ? void 0 : _b.call(stack)) === container) {
|
|
320
333
|
return;
|
|
321
334
|
}
|
|
322
|
-
|
|
335
|
+
const newStack = {
|
|
323
336
|
items: [],
|
|
324
337
|
zIndex: stack.zIndex,
|
|
325
|
-
container:
|
|
338
|
+
container: () => container,
|
|
326
339
|
_adapter: {},
|
|
327
340
|
};
|
|
328
341
|
stacks.push(newStack);
|
|
@@ -332,9 +345,9 @@ exports.PopupStack = {
|
|
|
332
345
|
* context container element matches to guard against accidental remove of other stack contexts
|
|
333
346
|
* you don't own.
|
|
334
347
|
*/
|
|
335
|
-
popStackContext
|
|
348
|
+
popStackContext(container) {
|
|
336
349
|
var _a, _b;
|
|
337
|
-
|
|
350
|
+
const stack = getTopStack();
|
|
338
351
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.popStackContext) {
|
|
339
352
|
return stack._adapter.popStackContext(container);
|
|
340
353
|
}
|
|
@@ -357,19 +370,19 @@ exports.PopupStack = {
|
|
|
357
370
|
* members of different popup stack contexts which will cause unspecified results (like the escape
|
|
358
371
|
* key will choose the wrong popup as the "topmost").
|
|
359
372
|
*/
|
|
360
|
-
transferToCurrentContext
|
|
373
|
+
transferToCurrentContext(item) {
|
|
361
374
|
var _a;
|
|
362
|
-
|
|
375
|
+
const stack = getTopStack();
|
|
363
376
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.transferToCurrentContext) {
|
|
364
377
|
return stack._adapter.transferToCurrentContext(item);
|
|
365
378
|
}
|
|
366
|
-
if (stack.items.find(
|
|
379
|
+
if (stack.items.find(i => i.element === item.element)) {
|
|
367
380
|
// The element is already in the stack, don't do anything
|
|
368
381
|
return;
|
|
369
382
|
}
|
|
370
383
|
// Try to find the element in existing stacks. If it exists, we need to first remove from that
|
|
371
384
|
// stack context
|
|
372
|
-
|
|
385
|
+
const oldStack = stacks.find(stack => !!stack.items.find(i => i.element === item.element));
|
|
373
386
|
if (oldStack) {
|
|
374
387
|
exports.PopupStack.remove(item.element);
|
|
375
388
|
}
|
|
@@ -385,21 +398,25 @@ function resetStack() {
|
|
|
385
398
|
}
|
|
386
399
|
exports.resetStack = resetStack;
|
|
387
400
|
/**
|
|
401
|
+
* An adapter is a custom implementation of the {@link PopupStack}. There is only ever a single
|
|
402
|
+
* instance of an adapter on the page. It allows an adapter to intercept any `PopupStack` method.
|
|
403
|
+
* This could bypass the internal FILO stack of the `PopupStack` and allows the FILO stack to be
|
|
404
|
+
* handled by something else.
|
|
388
405
|
*
|
|
389
406
|
* @param adapter The parts of the PopupStack that we want to override
|
|
390
407
|
*/
|
|
391
|
-
|
|
408
|
+
const createAdapter = (adapter) => {
|
|
392
409
|
stack._adapter = adapter;
|
|
393
410
|
};
|
|
394
411
|
exports.createAdapter = createAdapter;
|
|
395
412
|
// keep track of the element ourselves to avoid accidentally popping off someone else's stack
|
|
396
413
|
// context
|
|
397
|
-
|
|
414
|
+
let element = null;
|
|
398
415
|
// Where should this go? Each version of `PopupStack` on a page will add a listener. The
|
|
399
416
|
// `PopupStack` should guard against multiple handlers like this simultaneously and there is no
|
|
400
417
|
// lifecycle here.
|
|
401
418
|
if (screenfull_1.default.isEnabled) {
|
|
402
|
-
screenfull_1.default.on('change',
|
|
419
|
+
screenfull_1.default.on('change', () => {
|
|
403
420
|
if (screenfull_1.default.isFullscreen) {
|
|
404
421
|
if (screenfull_1.default.element) {
|
|
405
422
|
element = screenfull_1.default.element;
|
|
@@ -42,6 +42,24 @@ interface Stack {
|
|
|
42
42
|
};
|
|
43
43
|
_adapter: Partial<typeof PopupStack>;
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* The `PopupStack` is a framework agnostic first-in-last-out (FILO) stack that tracks all popups
|
|
47
|
+
* ("floating UI" or any UI that renders on top of other content). It contains methods that interact
|
|
48
|
+
* with the stack to support all coordinating behaviors of all popups on the page. The `PopupStack`
|
|
49
|
+
* helps:
|
|
50
|
+
*
|
|
51
|
+
* - Render popups in the right order on the page
|
|
52
|
+
* - Helps accessibility with the Escape key (topmost popup is closed)
|
|
53
|
+
* - Handles transition to [Full
|
|
54
|
+
* Screen](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
|
|
55
|
+
*
|
|
56
|
+
* The `PopupStack` supports adapters to work with existing popup systems. {@link createAdapter} is
|
|
57
|
+
* exported to accept an adapter. Only a single adapter should be used per page.
|
|
58
|
+
*
|
|
59
|
+
* The `PopupStack` is designed to handle multiple versions of `PopupStack` on the page at once
|
|
60
|
+
* while the internal FILO stack is shared between instances. You should not attempt to use the
|
|
61
|
+
* internal FILO stack. If an adapter is used, the internal FILO stack may be empty.
|
|
62
|
+
*/
|
|
45
63
|
export declare const PopupStack: {
|
|
46
64
|
/**
|
|
47
65
|
* Create a HTMLElement as the container for the popup stack item. The returned element reference
|
|
@@ -139,6 +157,10 @@ export declare const PopupStack: {
|
|
|
139
157
|
*/
|
|
140
158
|
export declare function resetStack(): void;
|
|
141
159
|
/**
|
|
160
|
+
* An adapter is a custom implementation of the {@link PopupStack}. There is only ever a single
|
|
161
|
+
* instance of an adapter on the page. It allows an adapter to intercept any `PopupStack` method.
|
|
162
|
+
* This could bypass the internal FILO stack of the `PopupStack` and allows the FILO stack to be
|
|
163
|
+
* handled by something else.
|
|
142
164
|
*
|
|
143
165
|
* @param adapter The parts of the PopupStack that we want to override
|
|
144
166
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PopupStack.d.ts","sourceRoot":"","sources":["../../../lib/PopupStack.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AASD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAO9D;AA2CD,UAAU,KAAK;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,WAAW,CAAC;IAC9B,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,OAAO,QAAQ,CAAC;KAC3B,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC,OAAO,UAAU,CAAC,CAAC;CACtC;AAwFD,eAAO,MAAM,UAAU;IACrB;;;;;OAKG;uBACgB,WAAW;IAS9B;;;;;OAKG;cACO,cAAc,GAAG,IAAI;IAY/B;;;;;;OAMG;oBACa,WAAW,GAAG,IAAI;IAelC;;;;OAIG;uBACgB,WAAW,GAAG,OAAO;IAaxC;;;;OAIG;oDACiC,WAAW,EAAE;IAQjD;;;;;;;;;;;OAWG;wBACiB,WAAW,GAAG,IAAI;IA6BtC;;;;;;;;;;OAUG;sBACe,WAAW,eAAe,WAAW,GAAG,OAAO;IA2BjE;;;;;;OAMG;gCACyB,WAAW,GAAG,IAAI;IAoB9C;;;;OAIG;+BACwB,WAAW,GAAG,IAAI;IAY7C;;;;;;;;;;;;;;OAcG;mCAC4B,cAAc,GAAG,IAAI;CAqBrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,UAAU,SAEzB;AAED
|
|
1
|
+
{"version":3,"file":"PopupStack.d.ts","sourceRoot":"","sources":["../../../lib/PopupStack.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,OAAO,EAAE,WAAW,CAAC;IACrB;;;;;;;;;;;;;;;OAeG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AASD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAO9D;AA2CD,UAAU,KAAK;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,WAAW,CAAC;IAC9B,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,QAAQ,EAAE,OAAO,QAAQ,CAAC;KAC3B,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC,OAAO,UAAU,CAAC,CAAC;CACtC;AAwFD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU;IACrB;;;;;OAKG;uBACgB,WAAW;IAS9B;;;;;OAKG;cACO,cAAc,GAAG,IAAI;IAY/B;;;;;;OAMG;oBACa,WAAW,GAAG,IAAI;IAelC;;;;OAIG;uBACgB,WAAW,GAAG,OAAO;IAaxC;;;;OAIG;oDACiC,WAAW,EAAE;IAQjD;;;;;;;;;;;OAWG;wBACiB,WAAW,GAAG,IAAI;IA6BtC;;;;;;;;;;OAUG;sBACe,WAAW,eAAe,WAAW,GAAG,OAAO;IA2BjE;;;;;;OAMG;gCACyB,WAAW,GAAG,IAAI;IAoB9C;;;;OAIG;+BACwB,WAAW,GAAG,IAAI;IAY7C;;;;;;;;;;;;;;OAcG;mCAC4B,cAAc,GAAG,IAAI;CAqBrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,UAAU,SAEzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,YAAa,QAAQ,iBAAiB,CAAC,SAEhE,CAAC"}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
var __spreadArrays = (this && this.__spreadArrays) || function () {
|
|
2
|
-
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
|
3
|
-
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
|
4
|
-
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
|
5
|
-
r[k] = a[j];
|
|
6
|
-
return r;
|
|
7
|
-
};
|
|
8
1
|
import screenfull from 'screenfull';
|
|
9
2
|
function getLast(items) {
|
|
10
3
|
if (items.length) {
|
|
@@ -19,7 +12,7 @@ function getLast(items) {
|
|
|
19
12
|
* popups.
|
|
20
13
|
*/
|
|
21
14
|
export function getValue(index, length) {
|
|
22
|
-
|
|
15
|
+
const { min, max } = stack.zIndex;
|
|
23
16
|
if (length <= max - min) {
|
|
24
17
|
return index + min;
|
|
25
18
|
}
|
|
@@ -30,8 +23,8 @@ export function getValue(index, length) {
|
|
|
30
23
|
* will be run any time the stack changes.
|
|
31
24
|
*/
|
|
32
25
|
function setZIndexOfElements(elements) {
|
|
33
|
-
|
|
34
|
-
elements.forEach(
|
|
26
|
+
const length = elements.length;
|
|
27
|
+
elements.forEach((element, index) => {
|
|
35
28
|
element.style.zIndex = String(getValue(index, length));
|
|
36
29
|
});
|
|
37
30
|
}
|
|
@@ -40,9 +33,9 @@ function setZIndexOfElements(elements) {
|
|
|
40
33
|
* to the stack.
|
|
41
34
|
*/
|
|
42
35
|
function getOwnerPopup(element, items) {
|
|
43
|
-
|
|
36
|
+
let parentEl = element;
|
|
44
37
|
do {
|
|
45
|
-
|
|
38
|
+
const owner = items.find(el => el.element === parentEl);
|
|
46
39
|
if (owner) {
|
|
47
40
|
return owner.element;
|
|
48
41
|
}
|
|
@@ -55,10 +48,10 @@ function getOwnerPopup(element, items) {
|
|
|
55
48
|
* hierarchy.
|
|
56
49
|
*/
|
|
57
50
|
function getChildPopups(item, items) {
|
|
58
|
-
|
|
59
|
-
.filter(
|
|
60
|
-
.map(
|
|
61
|
-
.filter(
|
|
51
|
+
const owners = items
|
|
52
|
+
.filter(i => i.owner)
|
|
53
|
+
.map(i => ({ element: i.element, parent: getOwnerPopup(i.owner, items) }))
|
|
54
|
+
.filter(i => i.parent === item.element);
|
|
62
55
|
return owners;
|
|
63
56
|
}
|
|
64
57
|
/**
|
|
@@ -68,8 +61,8 @@ function getChildPopups(item, items) {
|
|
|
68
61
|
* @param path dot-notation path of a deep property
|
|
69
62
|
*/
|
|
70
63
|
function get(obj, path) {
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
const parts = path.split('.');
|
|
65
|
+
const first = parts.splice(0, 1)[0];
|
|
73
66
|
if (parts.length && obj[first]) {
|
|
74
67
|
return get(obj[first], parts.join('.'));
|
|
75
68
|
}
|
|
@@ -84,8 +77,8 @@ function get(obj, path) {
|
|
|
84
77
|
* @param value Any value
|
|
85
78
|
*/
|
|
86
79
|
function set(obj, path, value) {
|
|
87
|
-
|
|
88
|
-
|
|
80
|
+
const parts = path.split('.');
|
|
81
|
+
const first = parts.splice(0, 1)[0];
|
|
89
82
|
if (parts.length) {
|
|
90
83
|
if (obj[first] === undefined) {
|
|
91
84
|
obj[first] = {};
|
|
@@ -106,7 +99,7 @@ if (typeof window !== 'undefined') {
|
|
|
106
99
|
* environments without a `window` object, so it is safe to use in server-side rendering.
|
|
107
100
|
* @param path Any dot-notation path
|
|
108
101
|
*/
|
|
109
|
-
|
|
102
|
+
const getFromWindow = (path) => {
|
|
110
103
|
if (typeof window !== 'undefined') {
|
|
111
104
|
return get(window, path);
|
|
112
105
|
}
|
|
@@ -118,7 +111,7 @@ var getFromWindow = function (path) {
|
|
|
118
111
|
* @param path dot-notation path of a deep property
|
|
119
112
|
* @param value Any value
|
|
120
113
|
*/
|
|
121
|
-
|
|
114
|
+
const setToWindow = (path, value) => {
|
|
122
115
|
if (typeof window !== 'undefined') {
|
|
123
116
|
set(window, path, value);
|
|
124
117
|
}
|
|
@@ -126,34 +119,52 @@ var setToWindow = function (path, value) {
|
|
|
126
119
|
// We need to make sure only one stack is ever in use on the page - ever. If a stack is already
|
|
127
120
|
// defined on the page, we need to use that one. Never, ever, ever change this variable name on
|
|
128
121
|
// window
|
|
129
|
-
|
|
122
|
+
const stack = getFromWindow('workday.__popupStack') || {
|
|
130
123
|
description: 'Global popup stack from @workday/canvas-kit/popup-stack',
|
|
131
|
-
container:
|
|
124
|
+
container: () => document.body,
|
|
132
125
|
items: [],
|
|
133
126
|
zIndex: { min: 30, max: 50, getValue: getValue },
|
|
134
127
|
_adapter: {},
|
|
135
128
|
};
|
|
136
129
|
setToWindow('workday.__popupStack', stack);
|
|
137
|
-
|
|
130
|
+
const stacks = getFromWindow('workday.__popupStackOfStacks') || [stack];
|
|
138
131
|
stacks.description = 'Global stack of popup stacks from @workday/canvas-kit/popup-stack';
|
|
139
132
|
setToWindow('workday.__popupStackOfStacks', stacks);
|
|
140
133
|
function getTopStack() {
|
|
141
134
|
return stacks[stacks.length - 1];
|
|
142
135
|
}
|
|
143
|
-
|
|
136
|
+
/**
|
|
137
|
+
* The `PopupStack` is a framework agnostic first-in-last-out (FILO) stack that tracks all popups
|
|
138
|
+
* ("floating UI" or any UI that renders on top of other content). It contains methods that interact
|
|
139
|
+
* with the stack to support all coordinating behaviors of all popups on the page. The `PopupStack`
|
|
140
|
+
* helps:
|
|
141
|
+
*
|
|
142
|
+
* - Render popups in the right order on the page
|
|
143
|
+
* - Helps accessibility with the Escape key (topmost popup is closed)
|
|
144
|
+
* - Handles transition to [Full
|
|
145
|
+
* Screen](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
|
|
146
|
+
*
|
|
147
|
+
* The `PopupStack` supports adapters to work with existing popup systems. {@link createAdapter} is
|
|
148
|
+
* exported to accept an adapter. Only a single adapter should be used per page.
|
|
149
|
+
*
|
|
150
|
+
* The `PopupStack` is designed to handle multiple versions of `PopupStack` on the page at once
|
|
151
|
+
* while the internal FILO stack is shared between instances. You should not attempt to use the
|
|
152
|
+
* internal FILO stack. If an adapter is used, the internal FILO stack may be empty.
|
|
153
|
+
*/
|
|
154
|
+
export const PopupStack = {
|
|
144
155
|
/**
|
|
145
156
|
* Create a HTMLElement as the container for the popup stack item. The returned element reference
|
|
146
157
|
* will be the reference to be passed to all other methods. The Popup Stack will control when this
|
|
147
158
|
* element is added and removed from the DOM as well as the `z-index` style property. Your content
|
|
148
159
|
* should be added to this element.
|
|
149
160
|
*/
|
|
150
|
-
createContainer
|
|
161
|
+
createContainer() {
|
|
151
162
|
var _a;
|
|
152
|
-
|
|
163
|
+
const stack = getTopStack();
|
|
153
164
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.createContainer) {
|
|
154
165
|
return stack._adapter.createContainer();
|
|
155
166
|
}
|
|
156
|
-
|
|
167
|
+
const div = document.createElement('div');
|
|
157
168
|
div.style.position = 'relative'; // z-index only works on _positioned_ elements
|
|
158
169
|
return div;
|
|
159
170
|
},
|
|
@@ -163,9 +174,9 @@ export var PopupStack = {
|
|
|
163
174
|
* popups to be registered initially, but rendered when the user triggers some event, call this
|
|
164
175
|
* method when the event triggers.
|
|
165
176
|
*/
|
|
166
|
-
add
|
|
177
|
+
add(item) {
|
|
167
178
|
var _a, _b;
|
|
168
|
-
|
|
179
|
+
const stack = getTopStack();
|
|
169
180
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.add) {
|
|
170
181
|
stack._adapter.add(item);
|
|
171
182
|
return;
|
|
@@ -181,16 +192,16 @@ export var PopupStack = {
|
|
|
181
192
|
* called when the element is removed from the DOM. This method will reset z-index values of the
|
|
182
193
|
* stack.
|
|
183
194
|
*/
|
|
184
|
-
remove
|
|
195
|
+
remove(element) {
|
|
185
196
|
var _a, _b;
|
|
186
197
|
// Find the stack the popup belongs to.
|
|
187
|
-
|
|
198
|
+
const stack = stacks.find(stack => !!PopupStack.getElements(stack).find(el => el === element));
|
|
188
199
|
if (stack) {
|
|
189
200
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.remove) {
|
|
190
201
|
stack._adapter.remove(element);
|
|
191
202
|
return;
|
|
192
203
|
}
|
|
193
|
-
stack.items = stack.items.filter(
|
|
204
|
+
stack.items = stack.items.filter(item => item.element !== element);
|
|
194
205
|
(((_b = stack.container) === null || _b === void 0 ? void 0 : _b.call(stack)) || document.body).removeChild(element);
|
|
195
206
|
setZIndexOfElements(PopupStack.getElements(stack));
|
|
196
207
|
}
|
|
@@ -200,13 +211,13 @@ export var PopupStack = {
|
|
|
200
211
|
* is not the top of the stack or is not found in the stack. The `element` should be the same
|
|
201
212
|
* reference that was passed to `add`
|
|
202
213
|
*/
|
|
203
|
-
isTopmost
|
|
214
|
+
isTopmost(element) {
|
|
204
215
|
var _a;
|
|
205
|
-
|
|
216
|
+
const stack = getTopStack();
|
|
206
217
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.isTopmost) {
|
|
207
218
|
return stack._adapter.isTopmost(element);
|
|
208
219
|
}
|
|
209
|
-
|
|
220
|
+
const last = getLast(stack.items);
|
|
210
221
|
if (last) {
|
|
211
222
|
return last.element === element;
|
|
212
223
|
}
|
|
@@ -217,13 +228,13 @@ export var PopupStack = {
|
|
|
217
228
|
* elements in the order of lowest z-index to highest z-index. Some popup behaviors will need to
|
|
218
229
|
* make decisions based on z-index order.
|
|
219
230
|
*/
|
|
220
|
-
getElements
|
|
231
|
+
getElements(stackOverride) {
|
|
221
232
|
var _a;
|
|
222
|
-
|
|
233
|
+
const stack = stackOverride || getTopStack();
|
|
223
234
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.getElements) {
|
|
224
235
|
return stack._adapter.getElements();
|
|
225
236
|
}
|
|
226
|
-
return stack.items.map(
|
|
237
|
+
return stack.items.map(i => i.element);
|
|
227
238
|
},
|
|
228
239
|
/**
|
|
229
240
|
* Bring the element to the top of the stack. This is useful for persistent popups to place them
|
|
@@ -237,30 +248,30 @@ export var PopupStack = {
|
|
|
237
248
|
* This does not need to be called when a popup is added since added popups are already place on
|
|
238
249
|
* the top of the stack.
|
|
239
250
|
*/
|
|
240
|
-
bringToTop
|
|
251
|
+
bringToTop(element) {
|
|
241
252
|
var _a;
|
|
242
|
-
|
|
253
|
+
const stack = getTopStack();
|
|
243
254
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.bringToTop) {
|
|
244
255
|
stack._adapter.bringToTop(element);
|
|
245
256
|
return;
|
|
246
257
|
}
|
|
247
|
-
|
|
258
|
+
const item = stack.items.find(i => i.element === element);
|
|
248
259
|
if (item) {
|
|
249
|
-
stack.items =
|
|
260
|
+
stack.items = [...stack.items.filter(i => i !== item), item];
|
|
250
261
|
// Also bring children to top. There are a few cases where stacking might break otherwise:
|
|
251
262
|
// - Clicking a Popup calls `bringToTop`, but mouse is over a Tooltip so that Tooltip is now
|
|
252
263
|
// under the Popup
|
|
253
264
|
// - Clicking a button opens a new Popup, but that click bubbles up to a `bringToTop` call
|
|
254
265
|
// putting the new popup under an existing one
|
|
255
266
|
// Example: https://user-images.githubusercontent.com/338257/83924476-031af580-a742-11ea-8f68-0edabdf0fd6a.gif
|
|
256
|
-
getChildPopups(item, stack.items).forEach(
|
|
267
|
+
getChildPopups(item, stack.items).forEach(popup => {
|
|
257
268
|
PopupStack.bringToTop(popup.element);
|
|
258
269
|
});
|
|
259
270
|
setZIndexOfElements(PopupStack.getElements());
|
|
260
271
|
}
|
|
261
272
|
else {
|
|
262
273
|
// not found
|
|
263
|
-
|
|
274
|
+
const e = new Error();
|
|
264
275
|
console.warn('Could not find item', e.stack);
|
|
265
276
|
}
|
|
266
277
|
},
|
|
@@ -275,22 +286,24 @@ export var PopupStack = {
|
|
|
275
286
|
* opt-in to toggling. Otherwise there is no way to opt-out of toggle behavior (because the target
|
|
276
287
|
* is not inside `element`).
|
|
277
288
|
*/
|
|
278
|
-
contains
|
|
289
|
+
contains(element, eventTarget) {
|
|
279
290
|
var _a, _b;
|
|
280
|
-
|
|
291
|
+
const stack = getTopStack();
|
|
281
292
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.contains) {
|
|
282
293
|
return stack._adapter.contains(element, eventTarget);
|
|
283
294
|
}
|
|
284
|
-
|
|
285
|
-
|
|
295
|
+
const item = stack.items.find(i => i.element === element);
|
|
296
|
+
const containsOwnerOfAnotherPopupTargeted = stack.items.some(currentItem => {
|
|
286
297
|
var _a;
|
|
287
298
|
return ((item === null || item === void 0 ? void 0 : item.element.contains(currentItem.owner || null)) &&
|
|
288
|
-
(eventTarget === currentItem.owner ||
|
|
299
|
+
(eventTarget === currentItem.owner ||
|
|
300
|
+
((_a = currentItem.owner) === null || _a === void 0 ? void 0 : _a.contains(eventTarget)) ||
|
|
289
301
|
currentItem.element.contains(eventTarget)));
|
|
290
302
|
});
|
|
291
303
|
if (item) {
|
|
292
304
|
return (containsOwnerOfAnotherPopupTargeted ||
|
|
293
|
-
eventTarget === item.owner ||
|
|
305
|
+
eventTarget === item.owner ||
|
|
306
|
+
((_b = item.owner) === null || _b === void 0 ? void 0 : _b.contains(eventTarget)) ||
|
|
294
307
|
element.contains(eventTarget));
|
|
295
308
|
}
|
|
296
309
|
return false;
|
|
@@ -302,9 +315,9 @@ export var PopupStack = {
|
|
|
302
315
|
* pushing the same element which is very difficult to ensure only one stack is used. To mitigate,
|
|
303
316
|
* this method filters out multiple calls to push the same element as a new stack context.
|
|
304
317
|
*/
|
|
305
|
-
pushStackContext
|
|
318
|
+
pushStackContext(container) {
|
|
306
319
|
var _a, _b;
|
|
307
|
-
|
|
320
|
+
const stack = getTopStack();
|
|
308
321
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.pushStackContext) {
|
|
309
322
|
return stack._adapter.pushStackContext(container);
|
|
310
323
|
}
|
|
@@ -312,10 +325,10 @@ export var PopupStack = {
|
|
|
312
325
|
if (((_b = stack.container) === null || _b === void 0 ? void 0 : _b.call(stack)) === container) {
|
|
313
326
|
return;
|
|
314
327
|
}
|
|
315
|
-
|
|
328
|
+
const newStack = {
|
|
316
329
|
items: [],
|
|
317
330
|
zIndex: stack.zIndex,
|
|
318
|
-
container:
|
|
331
|
+
container: () => container,
|
|
319
332
|
_adapter: {},
|
|
320
333
|
};
|
|
321
334
|
stacks.push(newStack);
|
|
@@ -325,9 +338,9 @@ export var PopupStack = {
|
|
|
325
338
|
* context container element matches to guard against accidental remove of other stack contexts
|
|
326
339
|
* you don't own.
|
|
327
340
|
*/
|
|
328
|
-
popStackContext
|
|
341
|
+
popStackContext(container) {
|
|
329
342
|
var _a, _b;
|
|
330
|
-
|
|
343
|
+
const stack = getTopStack();
|
|
331
344
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.popStackContext) {
|
|
332
345
|
return stack._adapter.popStackContext(container);
|
|
333
346
|
}
|
|
@@ -350,19 +363,19 @@ export var PopupStack = {
|
|
|
350
363
|
* members of different popup stack contexts which will cause unspecified results (like the escape
|
|
351
364
|
* key will choose the wrong popup as the "topmost").
|
|
352
365
|
*/
|
|
353
|
-
transferToCurrentContext
|
|
366
|
+
transferToCurrentContext(item) {
|
|
354
367
|
var _a;
|
|
355
|
-
|
|
368
|
+
const stack = getTopStack();
|
|
356
369
|
if ((_a = stack._adapter) === null || _a === void 0 ? void 0 : _a.transferToCurrentContext) {
|
|
357
370
|
return stack._adapter.transferToCurrentContext(item);
|
|
358
371
|
}
|
|
359
|
-
if (stack.items.find(
|
|
372
|
+
if (stack.items.find(i => i.element === item.element)) {
|
|
360
373
|
// The element is already in the stack, don't do anything
|
|
361
374
|
return;
|
|
362
375
|
}
|
|
363
376
|
// Try to find the element in existing stacks. If it exists, we need to first remove from that
|
|
364
377
|
// stack context
|
|
365
|
-
|
|
378
|
+
const oldStack = stacks.find(stack => !!stack.items.find(i => i.element === item.element));
|
|
366
379
|
if (oldStack) {
|
|
367
380
|
PopupStack.remove(item.element);
|
|
368
381
|
}
|
|
@@ -377,20 +390,24 @@ export function resetStack() {
|
|
|
377
390
|
stack.items = [];
|
|
378
391
|
}
|
|
379
392
|
/**
|
|
393
|
+
* An adapter is a custom implementation of the {@link PopupStack}. There is only ever a single
|
|
394
|
+
* instance of an adapter on the page. It allows an adapter to intercept any `PopupStack` method.
|
|
395
|
+
* This could bypass the internal FILO stack of the `PopupStack` and allows the FILO stack to be
|
|
396
|
+
* handled by something else.
|
|
380
397
|
*
|
|
381
398
|
* @param adapter The parts of the PopupStack that we want to override
|
|
382
399
|
*/
|
|
383
|
-
export
|
|
400
|
+
export const createAdapter = (adapter) => {
|
|
384
401
|
stack._adapter = adapter;
|
|
385
402
|
};
|
|
386
403
|
// keep track of the element ourselves to avoid accidentally popping off someone else's stack
|
|
387
404
|
// context
|
|
388
|
-
|
|
405
|
+
let element = null;
|
|
389
406
|
// Where should this go? Each version of `PopupStack` on a page will add a listener. The
|
|
390
407
|
// `PopupStack` should guard against multiple handlers like this simultaneously and there is no
|
|
391
408
|
// lifecycle here.
|
|
392
409
|
if (screenfull.isEnabled) {
|
|
393
|
-
screenfull.on('change',
|
|
410
|
+
screenfull.on('change', () => {
|
|
394
411
|
if (screenfull.isFullscreen) {
|
|
395
412
|
if (screenfull.element) {
|
|
396
413
|
element = screenfull.element;
|
package/lib/PopupStack.ts
CHANGED
|
@@ -188,6 +188,24 @@ function getTopStack() {
|
|
|
188
188
|
return stacks[stacks.length - 1];
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* The `PopupStack` is a framework agnostic first-in-last-out (FILO) stack that tracks all popups
|
|
193
|
+
* ("floating UI" or any UI that renders on top of other content). It contains methods that interact
|
|
194
|
+
* with the stack to support all coordinating behaviors of all popups on the page. The `PopupStack`
|
|
195
|
+
* helps:
|
|
196
|
+
*
|
|
197
|
+
* - Render popups in the right order on the page
|
|
198
|
+
* - Helps accessibility with the Escape key (topmost popup is closed)
|
|
199
|
+
* - Handles transition to [Full
|
|
200
|
+
* Screen](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API)
|
|
201
|
+
*
|
|
202
|
+
* The `PopupStack` supports adapters to work with existing popup systems. {@link createAdapter} is
|
|
203
|
+
* exported to accept an adapter. Only a single adapter should be used per page.
|
|
204
|
+
*
|
|
205
|
+
* The `PopupStack` is designed to handle multiple versions of `PopupStack` on the page at once
|
|
206
|
+
* while the internal FILO stack is shared between instances. You should not attempt to use the
|
|
207
|
+
* internal FILO stack. If an adapter is used, the internal FILO stack may be empty.
|
|
208
|
+
*/
|
|
191
209
|
export const PopupStack = {
|
|
192
210
|
/**
|
|
193
211
|
* Create a HTMLElement as the container for the popup stack item. The returned element reference
|
|
@@ -445,6 +463,10 @@ export function resetStack() {
|
|
|
445
463
|
}
|
|
446
464
|
|
|
447
465
|
/**
|
|
466
|
+
* An adapter is a custom implementation of the {@link PopupStack}. There is only ever a single
|
|
467
|
+
* instance of an adapter on the page. It allows an adapter to intercept any `PopupStack` method.
|
|
468
|
+
* This could bypass the internal FILO stack of the `PopupStack` and allows the FILO stack to be
|
|
469
|
+
* handled by something else.
|
|
448
470
|
*
|
|
449
471
|
* @param adapter The parts of the PopupStack that we want to override
|
|
450
472
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workday/canvas-kit-popup-stack",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.428-next.2+2c79134a",
|
|
4
4
|
"description": "Stack for managing popup UIs to coordinate global concerns like escape key handling and rendering order",
|
|
5
5
|
"author": "Workday, Inc. (https://www.workday.com)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"screenfull": "^5.2.0"
|
|
39
39
|
},
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "2c79134aa48ef0efde9cdf883b529b8157337a28"
|
|
41
41
|
}
|