1 |
|
2 |
|
3 | import { nullTranslator } from '@jupyterlab/translation';
|
4 | import { Button, closeIcon, LabIcon, ReactWidget, Styling } from '@jupyterlab/ui-components';
|
5 | import { ArrayExt } from '@lumino/algorithm';
|
6 | import { PromiseDelegate } from '@lumino/coreutils';
|
7 | import { MessageLoop } from '@lumino/messaging';
|
8 | import { Panel, PanelLayout, Widget } from '@lumino/widgets';
|
9 | import * as React from 'react';
|
10 | import { WidgetTracker } from './widgettracker';
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | export function showDialog(options = {}) {
|
19 | const dialog = new Dialog(options);
|
20 | return dialog.launch();
|
21 | }
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | export function showErrorMessage(title, error, buttons) {
|
31 | const trans = Dialog.translator.load('jupyterlab');
|
32 | buttons = buttons !== null && buttons !== void 0 ? buttons : [Dialog.okButton({ label: trans.__('Dismiss') })];
|
33 | console.warn('Showing error:', error);
|
34 |
|
35 |
|
36 | const body = typeof error === 'string' ? error : error.message;
|
37 | const key = title + '----' + body;
|
38 | const promise = Private.errorMessagePromiseCache.get(key);
|
39 | if (promise) {
|
40 | return promise;
|
41 | }
|
42 | else {
|
43 | const dialogPromise = showDialog({
|
44 | title: title,
|
45 | body: body,
|
46 | buttons: buttons
|
47 | }).then(() => {
|
48 | Private.errorMessagePromiseCache.delete(key);
|
49 | }, error => {
|
50 |
|
51 | Private.errorMessagePromiseCache.delete(key);
|
52 | throw error;
|
53 | });
|
54 | Private.errorMessagePromiseCache.set(key, dialogPromise);
|
55 | return dialogPromise;
|
56 | }
|
57 | }
|
58 |
|
59 |
|
60 |
|
61 | export class Dialog extends Widget {
|
62 | |
63 |
|
64 |
|
65 |
|
66 |
|
67 | constructor(options = {}) {
|
68 | const dialogNode = document.createElement('dialog');
|
69 | dialogNode.ariaModal = 'true';
|
70 | super({ node: dialogNode });
|
71 | this._hasValidationErrors = false;
|
72 | this._ready = new PromiseDelegate();
|
73 | this._focusNodeSelector = '';
|
74 | this.addClass('jp-Dialog');
|
75 | const normalized = Private.handleOptions(options);
|
76 | const renderer = normalized.renderer;
|
77 | this._host = normalized.host;
|
78 | this._defaultButton = normalized.defaultButton;
|
79 | this._buttons = normalized.buttons;
|
80 | this._hasClose = normalized.hasClose;
|
81 | this._buttonNodes = this._buttons.map(b => renderer.createButtonNode(b));
|
82 | this._checkboxNode = null;
|
83 | this._lastMouseDownInDialog = false;
|
84 | if (normalized.checkbox) {
|
85 | const { label = '', caption = '', checked = false, className = '' } = normalized.checkbox;
|
86 | this._checkboxNode = renderer.createCheckboxNode({
|
87 | label,
|
88 | caption: caption !== null && caption !== void 0 ? caption : label,
|
89 | checked,
|
90 | className
|
91 | });
|
92 | }
|
93 | const layout = (this.layout = new PanelLayout());
|
94 | const content = new Panel();
|
95 | content.addClass('jp-Dialog-content');
|
96 | if (typeof options.body === 'string') {
|
97 | content.addClass('jp-Dialog-content-small');
|
98 | dialogNode.ariaLabel = [normalized.title, options.body].join(' ');
|
99 | }
|
100 | layout.addWidget(content);
|
101 | this._body = normalized.body;
|
102 | const header = renderer.createHeader(normalized.title, () => this.reject(), options);
|
103 | const body = renderer.createBody(normalized.body);
|
104 | const footer = renderer.createFooter(this._buttonNodes, this._checkboxNode);
|
105 | content.addWidget(header);
|
106 | content.addWidget(body);
|
107 | content.addWidget(footer);
|
108 | this._bodyWidget = body;
|
109 | this._primary = this._buttonNodes[this._defaultButton];
|
110 | this._focusNodeSelector = options.focusNodeSelector;
|
111 |
|
112 | void Dialog.tracker.add(this);
|
113 | }
|
114 | |
115 |
|
116 |
|
117 | get ready() {
|
118 | return this._ready.promise;
|
119 | }
|
120 | |
121 |
|
122 |
|
123 | dispose() {
|
124 | const promise = this._promise;
|
125 | if (promise) {
|
126 | this._promise = null;
|
127 | promise.reject(void 0);
|
128 | ArrayExt.removeFirstOf(Private.launchQueue, promise.promise);
|
129 | }
|
130 | super.dispose();
|
131 | }
|
132 | |
133 |
|
134 |
|
135 |
|
136 |
|
137 | launch() {
|
138 |
|
139 | if (this._promise) {
|
140 | return this._promise.promise;
|
141 | }
|
142 | const promise = (this._promise = new PromiseDelegate());
|
143 | const promises = Promise.all(Private.launchQueue);
|
144 | Private.launchQueue.push(this._promise.promise);
|
145 | return promises.then(() => {
|
146 |
|
147 | if (!this._promise) {
|
148 | return Promise.resolve({
|
149 | button: Dialog.cancelButton(),
|
150 | isChecked: null,
|
151 | value: null
|
152 | });
|
153 | }
|
154 | Widget.attach(this, this._host);
|
155 | return promise.promise;
|
156 | });
|
157 | }
|
158 | |
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 | resolve(index) {
|
169 | if (!this._promise) {
|
170 | return;
|
171 | }
|
172 | if (index === undefined) {
|
173 | index = this._defaultButton;
|
174 | }
|
175 | this._resolve(this._buttons[index]);
|
176 | }
|
177 | |
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | reject() {
|
184 | if (!this._promise) {
|
185 | return;
|
186 | }
|
187 | this._resolve(Dialog.cancelButton());
|
188 | }
|
189 | |
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 | handleEvent(event) {
|
200 | switch (event.type) {
|
201 | case 'keydown':
|
202 | this._evtKeydown(event);
|
203 | break;
|
204 | case 'mousedown':
|
205 | this._evtMouseDown(event);
|
206 | break;
|
207 | case 'click':
|
208 | this._evtClick(event);
|
209 | break;
|
210 | case 'input':
|
211 | this._evtInput(event);
|
212 | break;
|
213 | case 'focus':
|
214 | this._evtFocus(event);
|
215 | break;
|
216 | case 'contextmenu':
|
217 | event.preventDefault();
|
218 | event.stopPropagation();
|
219 | break;
|
220 | default:
|
221 | break;
|
222 | }
|
223 | }
|
224 | |
225 |
|
226 |
|
227 | onAfterAttach(msg) {
|
228 | const node = this.node;
|
229 | node.addEventListener('keydown', this, true);
|
230 | node.addEventListener('contextmenu', this, true);
|
231 | node.addEventListener('click', this, true);
|
232 | document.addEventListener('mousedown', this, true);
|
233 | document.addEventListener('focus', this, true);
|
234 | document.addEventListener('input', this, true);
|
235 | this._first = Private.findFirstFocusable(this.node);
|
236 | this._original = document.activeElement;
|
237 | const setFocus = () => {
|
238 | var _a;
|
239 | if (this._focusNodeSelector) {
|
240 | const body = this.node.querySelector('.jp-Dialog-body');
|
241 | const el = body === null || body === void 0 ? void 0 : body.querySelector(this._focusNodeSelector);
|
242 | if (el) {
|
243 | this._primary = el;
|
244 | }
|
245 | }
|
246 | (_a = this._primary) === null || _a === void 0 ? void 0 : _a.focus();
|
247 | this._ready.resolve();
|
248 | };
|
249 | if (this._bodyWidget instanceof ReactWidget &&
|
250 | this._bodyWidget.renderPromise !== undefined) {
|
251 | this._bodyWidget
|
252 | .renderPromise.then(() => {
|
253 | setFocus();
|
254 | })
|
255 | .catch(() => {
|
256 | console.error("Error while loading Dialog's body");
|
257 | });
|
258 | }
|
259 | else {
|
260 | setFocus();
|
261 | }
|
262 | }
|
263 | |
264 |
|
265 |
|
266 | onAfterDetach(msg) {
|
267 | const node = this.node;
|
268 | node.removeEventListener('keydown', this, true);
|
269 | node.removeEventListener('contextmenu', this, true);
|
270 | node.removeEventListener('click', this, true);
|
271 | document.removeEventListener('focus', this, true);
|
272 | document.removeEventListener('mousedown', this, true);
|
273 | document.removeEventListener('input', this, true);
|
274 | this._original.focus();
|
275 | }
|
276 | |
277 |
|
278 |
|
279 | onCloseRequest(msg) {
|
280 | if (this._promise) {
|
281 | this.reject();
|
282 | }
|
283 | super.onCloseRequest(msg);
|
284 | }
|
285 | |
286 |
|
287 |
|
288 |
|
289 |
|
290 | _evtInput(_event) {
|
291 | this._hasValidationErrors = !!this.node.querySelector(':invalid');
|
292 | for (let i = 0; i < this._buttons.length; i++) {
|
293 | if (this._buttons[i].accept) {
|
294 | this._buttonNodes[i].disabled = this._hasValidationErrors;
|
295 | }
|
296 | }
|
297 | }
|
298 | |
299 |
|
300 |
|
301 |
|
302 |
|
303 | _evtClick(event) {
|
304 | const content = this.node.getElementsByClassName('jp-Dialog-content')[0];
|
305 | if (!content.contains(event.target)) {
|
306 | event.stopPropagation();
|
307 | event.preventDefault();
|
308 | if (this._hasClose && !this._lastMouseDownInDialog) {
|
309 | this.reject();
|
310 | }
|
311 | return;
|
312 | }
|
313 | for (const buttonNode of this._buttonNodes) {
|
314 | if (buttonNode.contains(event.target)) {
|
315 | const index = this._buttonNodes.indexOf(buttonNode);
|
316 | this.resolve(index);
|
317 | }
|
318 | }
|
319 | }
|
320 | |
321 |
|
322 |
|
323 |
|
324 |
|
325 | _evtKeydown(event) {
|
326 |
|
327 | switch (event.keyCode) {
|
328 | case 27:
|
329 | event.stopPropagation();
|
330 | event.preventDefault();
|
331 | if (this._hasClose) {
|
332 | this.reject();
|
333 | }
|
334 | break;
|
335 | case 37: {
|
336 |
|
337 | const activeEl = document.activeElement;
|
338 | if (activeEl instanceof HTMLButtonElement) {
|
339 | let idx = this._buttonNodes.indexOf(activeEl) - 1;
|
340 |
|
341 | if (idx < 0) {
|
342 | idx = this._buttonNodes.length - 1;
|
343 | }
|
344 | const node = this._buttonNodes[idx];
|
345 | event.stopPropagation();
|
346 | event.preventDefault();
|
347 | node.focus();
|
348 | }
|
349 | break;
|
350 | }
|
351 | case 39: {
|
352 |
|
353 | const activeEl = document.activeElement;
|
354 | if (activeEl instanceof HTMLButtonElement) {
|
355 | let idx = this._buttonNodes.indexOf(activeEl) + 1;
|
356 |
|
357 | if (idx == this._buttons.length) {
|
358 | idx = 0;
|
359 | }
|
360 | const node = this._buttonNodes[idx];
|
361 | event.stopPropagation();
|
362 | event.preventDefault();
|
363 | node.focus();
|
364 | }
|
365 | break;
|
366 | }
|
367 | case 9: {
|
368 |
|
369 |
|
370 | const node = this._buttonNodes[this._buttons.length - 1];
|
371 | if (document.activeElement === node && !event.shiftKey) {
|
372 | event.stopPropagation();
|
373 | event.preventDefault();
|
374 | this._first.focus();
|
375 | }
|
376 | break;
|
377 | }
|
378 | case 13: {
|
379 |
|
380 | event.stopPropagation();
|
381 | event.preventDefault();
|
382 | const activeEl = document.activeElement;
|
383 | let index;
|
384 | if (activeEl instanceof HTMLButtonElement) {
|
385 | index = this._buttonNodes.indexOf(activeEl);
|
386 | }
|
387 | this.resolve(index);
|
388 | break;
|
389 | }
|
390 | default:
|
391 | break;
|
392 | }
|
393 | }
|
394 | |
395 |
|
396 |
|
397 |
|
398 |
|
399 | _evtFocus(event) {
|
400 | var _a;
|
401 | const target = event.target;
|
402 | if (!this.node.contains(target)) {
|
403 | event.stopPropagation();
|
404 | (_a = this._buttonNodes[this._defaultButton]) === null || _a === void 0 ? void 0 : _a.focus();
|
405 | }
|
406 | }
|
407 | |
408 |
|
409 |
|
410 |
|
411 |
|
412 | _evtMouseDown(event) {
|
413 | const content = this.node.getElementsByClassName('jp-Dialog-content')[0];
|
414 | const target = event.target;
|
415 | this._lastMouseDownInDialog = content.contains(target);
|
416 | }
|
417 | |
418 |
|
419 |
|
420 | _resolve(button) {
|
421 | var _a, _b, _c;
|
422 | if (this._hasValidationErrors && button.accept) {
|
423 |
|
424 | return;
|
425 | }
|
426 |
|
427 | const promise = this._promise;
|
428 | if (!promise) {
|
429 | this.dispose();
|
430 | return;
|
431 | }
|
432 | this._promise = null;
|
433 | ArrayExt.removeFirstOf(Private.launchQueue, promise.promise);
|
434 | const body = this._body;
|
435 | let value = null;
|
436 | if (button.accept &&
|
437 | body instanceof Widget &&
|
438 | typeof body.getValue === 'function') {
|
439 | value = body.getValue();
|
440 | }
|
441 | this.dispose();
|
442 | promise.resolve({
|
443 | button,
|
444 | isChecked: (_c = (_b = (_a = this._checkboxNode) === null || _a === void 0 ? void 0 : _a.querySelector('input')) === null || _b === void 0 ? void 0 : _b.checked) !== null && _c !== void 0 ? _c : null,
|
445 | value
|
446 | });
|
447 | }
|
448 | }
|
449 |
|
450 |
|
451 |
|
452 | (function (Dialog) {
|
453 | |
454 |
|
455 |
|
456 | Dialog.translator = nullTranslator;
|
457 | |
458 |
|
459 |
|
460 | function createButton(value) {
|
461 | value.accept = value.accept !== false;
|
462 | const trans = Dialog.translator.load('jupyterlab');
|
463 | const defaultLabel = value.accept ? trans.__('Ok') : trans.__('Cancel');
|
464 | return {
|
465 | ariaLabel: value.ariaLabel || value.label || defaultLabel,
|
466 | label: value.label || defaultLabel,
|
467 | iconClass: value.iconClass || '',
|
468 | iconLabel: value.iconLabel || '',
|
469 | caption: value.caption || '',
|
470 | className: value.className || '',
|
471 | accept: value.accept,
|
472 | actions: value.actions || [],
|
473 | displayType: value.displayType || 'default'
|
474 | };
|
475 | }
|
476 | Dialog.createButton = createButton;
|
477 | |
478 |
|
479 |
|
480 | function cancelButton(options = {}) {
|
481 | options.accept = false;
|
482 | return createButton(options);
|
483 | }
|
484 | Dialog.cancelButton = cancelButton;
|
485 | |
486 |
|
487 |
|
488 | function okButton(options = {}) {
|
489 | options.accept = true;
|
490 | return createButton(options);
|
491 | }
|
492 | Dialog.okButton = okButton;
|
493 | |
494 |
|
495 |
|
496 | function warnButton(options = {}) {
|
497 | options.displayType = 'warn';
|
498 | return createButton(options);
|
499 | }
|
500 | Dialog.warnButton = warnButton;
|
501 | |
502 |
|
503 |
|
504 |
|
505 |
|
506 |
|
507 |
|
508 | function flush() {
|
509 | Dialog.tracker.forEach(dialog => {
|
510 | dialog.dispose();
|
511 | });
|
512 | }
|
513 | Dialog.flush = flush;
|
514 | |
515 |
|
516 |
|
517 | class Renderer {
|
518 | |
519 |
|
520 |
|
521 |
|
522 |
|
523 |
|
524 |
|
525 | createHeader(title, reject = () => {
|
526 |
|
527 | }, options = {}) {
|
528 | let header;
|
529 | const handleMouseDown = (event) => {
|
530 |
|
531 | if (event.button === 0) {
|
532 | event.preventDefault();
|
533 | reject();
|
534 | }
|
535 | };
|
536 | const handleKeyDown = (event) => {
|
537 | const { key } = event;
|
538 | if (key === 'Enter' || key === ' ') {
|
539 | reject();
|
540 | }
|
541 | };
|
542 | if (typeof title === 'string') {
|
543 | const trans = Dialog.translator.load('jupyterlab');
|
544 | header = ReactWidget.create(React.createElement(React.Fragment, null,
|
545 | title,
|
546 | options.hasClose && (React.createElement(Button, { className: "jp-Dialog-close-button", onMouseDown: handleMouseDown, onKeyDown: handleKeyDown, title: trans.__('Cancel'), minimal: true },
|
547 | React.createElement(LabIcon.resolveReact, { icon: closeIcon, tag: "span" })))));
|
548 | }
|
549 | else {
|
550 | header = ReactWidget.create(title);
|
551 | }
|
552 | header.addClass('jp-Dialog-header');
|
553 | Styling.styleNode(header.node);
|
554 | return header;
|
555 | }
|
556 | |
557 |
|
558 |
|
559 |
|
560 |
|
561 |
|
562 |
|
563 | createBody(value) {
|
564 | const styleReactWidget = (widget) => {
|
565 | if (widget.renderPromise !== undefined) {
|
566 | widget.renderPromise
|
567 | .then(() => {
|
568 | Styling.styleNode(widget.node);
|
569 | })
|
570 | .catch(() => {
|
571 | console.error("Error while loading Dialog's body");
|
572 | });
|
573 | }
|
574 | else {
|
575 | Styling.styleNode(widget.node);
|
576 | }
|
577 | };
|
578 | let body;
|
579 | if (typeof value === 'string') {
|
580 | body = new Widget({ node: document.createElement('span') });
|
581 | body.node.textContent = value;
|
582 | }
|
583 | else if (value instanceof Widget) {
|
584 | body = value;
|
585 | if (body instanceof ReactWidget) {
|
586 | styleReactWidget(body);
|
587 | }
|
588 | else {
|
589 | Styling.styleNode(body.node);
|
590 | }
|
591 | }
|
592 | else {
|
593 | body = ReactWidget.create(value);
|
594 |
|
595 |
|
596 | MessageLoop.sendMessage(body, Widget.Msg.UpdateRequest);
|
597 | styleReactWidget(body);
|
598 | }
|
599 | body.addClass('jp-Dialog-body');
|
600 | return body;
|
601 | }
|
602 | |
603 |
|
604 |
|
605 |
|
606 |
|
607 |
|
608 |
|
609 |
|
610 | createFooter(buttons, checkbox) {
|
611 | const footer = new Widget();
|
612 | footer.addClass('jp-Dialog-footer');
|
613 | if (checkbox) {
|
614 | footer.node.appendChild(checkbox);
|
615 | footer.node.insertAdjacentHTML('beforeend', '<div class="jp-Dialog-spacer"></div>');
|
616 | }
|
617 | for (const button of buttons) {
|
618 | footer.node.appendChild(button);
|
619 | }
|
620 | Styling.styleNode(footer.node);
|
621 | return footer;
|
622 | }
|
623 | |
624 |
|
625 |
|
626 |
|
627 |
|
628 |
|
629 |
|
630 | createButtonNode(button) {
|
631 | const e = document.createElement('button');
|
632 | e.className = this.createItemClass(button);
|
633 | e.appendChild(this.renderIcon(button));
|
634 | e.appendChild(this.renderLabel(button));
|
635 | return e;
|
636 | }
|
637 | |
638 |
|
639 |
|
640 |
|
641 |
|
642 |
|
643 |
|
644 | createCheckboxNode(checkbox) {
|
645 | const e = document.createElement('label');
|
646 | e.className = 'jp-Dialog-checkbox';
|
647 | if (checkbox.className) {
|
648 | e.classList.add(checkbox.className);
|
649 | }
|
650 | e.title = checkbox.caption;
|
651 | e.textContent = checkbox.label;
|
652 | const input = document.createElement('input');
|
653 | input.type = 'checkbox';
|
654 | input.checked = !!checkbox.checked;
|
655 | e.insertAdjacentElement('afterbegin', input);
|
656 | return e;
|
657 | }
|
658 | |
659 |
|
660 |
|
661 |
|
662 |
|
663 |
|
664 |
|
665 | createItemClass(data) {
|
666 |
|
667 | let name = 'jp-Dialog-button';
|
668 |
|
669 | if (data.accept) {
|
670 | name += ' jp-mod-accept';
|
671 | }
|
672 | else {
|
673 | name += ' jp-mod-reject';
|
674 | }
|
675 | if (data.displayType === 'warn') {
|
676 | name += ' jp-mod-warn';
|
677 | }
|
678 |
|
679 | const extra = data.className;
|
680 | if (extra) {
|
681 | name += ` ${extra}`;
|
682 | }
|
683 |
|
684 | return name;
|
685 | }
|
686 | |
687 |
|
688 |
|
689 |
|
690 |
|
691 |
|
692 |
|
693 | renderIcon(data) {
|
694 | const e = document.createElement('div');
|
695 | e.className = this.createIconClass(data);
|
696 | e.appendChild(document.createTextNode(data.iconLabel));
|
697 | return e;
|
698 | }
|
699 | |
700 |
|
701 |
|
702 |
|
703 |
|
704 |
|
705 |
|
706 | createIconClass(data) {
|
707 | const name = 'jp-Dialog-buttonIcon';
|
708 | const extra = data.iconClass;
|
709 | return extra ? `${name} ${extra}` : name;
|
710 | }
|
711 | |
712 |
|
713 |
|
714 |
|
715 |
|
716 |
|
717 |
|
718 | renderLabel(data) {
|
719 | const e = document.createElement('div');
|
720 | e.className = 'jp-Dialog-buttonLabel';
|
721 | e.title = data.caption;
|
722 | e.ariaLabel = data.ariaLabel;
|
723 | e.appendChild(document.createTextNode(data.label));
|
724 | return e;
|
725 | }
|
726 | }
|
727 | Dialog.Renderer = Renderer;
|
728 | |
729 |
|
730 |
|
731 | Dialog.defaultRenderer = new Renderer();
|
732 | |
733 |
|
734 |
|
735 | Dialog.tracker = new WidgetTracker({
|
736 | namespace: '@jupyterlab/apputils:Dialog'
|
737 | });
|
738 | })(Dialog || (Dialog = {}));
|
739 |
|
740 |
|
741 |
|
742 | var Private;
|
743 | (function (Private) {
|
744 | |
745 |
|
746 |
|
747 | Private.launchQueue = [];
|
748 | Private.errorMessagePromiseCache = new Map();
|
749 | |
750 |
|
751 |
|
752 |
|
753 |
|
754 |
|
755 |
|
756 | function handleOptions(options = {}) {
|
757 | var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
758 | const buttons = (_a = options.buttons) !== null && _a !== void 0 ? _a : [
|
759 | Dialog.cancelButton(),
|
760 | Dialog.okButton()
|
761 | ];
|
762 | return {
|
763 | title: (_b = options.title) !== null && _b !== void 0 ? _b : '',
|
764 | body: (_c = options.body) !== null && _c !== void 0 ? _c : '',
|
765 | host: (_d = options.host) !== null && _d !== void 0 ? _d : document.body,
|
766 | checkbox: (_e = options.checkbox) !== null && _e !== void 0 ? _e : null,
|
767 | buttons,
|
768 | defaultButton: (_f = options.defaultButton) !== null && _f !== void 0 ? _f : buttons.length - 1,
|
769 | renderer: (_g = options.renderer) !== null && _g !== void 0 ? _g : Dialog.defaultRenderer,
|
770 | focusNodeSelector: (_h = options.focusNodeSelector) !== null && _h !== void 0 ? _h : '',
|
771 | hasClose: (_j = options.hasClose) !== null && _j !== void 0 ? _j : true
|
772 | };
|
773 | }
|
774 | Private.handleOptions = handleOptions;
|
775 | |
776 |
|
777 |
|
778 | function findFirstFocusable(node) {
|
779 | const candidateSelectors = [
|
780 | 'input',
|
781 | 'select',
|
782 | 'a[href]',
|
783 | 'textarea',
|
784 | 'button',
|
785 | '[tabindex]'
|
786 | ].join(',');
|
787 | return node.querySelectorAll(candidateSelectors)[0];
|
788 | }
|
789 | Private.findFirstFocusable = findFirstFocusable;
|
790 | })(Private || (Private = {}));
|
791 |
|
\ | No newline at end of file |