You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.4 KiB

5 months ago
  1. /*!
  2. * Bootstrap focustrap.js v5.3.3 (https://getbootstrap.com/)
  3. * Copyright 2011-2024 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
  4. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('../dom/selector-engine.js'), require('./config.js')) :
  8. typeof define === 'function' && define.amd ? define(['../dom/event-handler', '../dom/selector-engine', './config'], factory) :
  9. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Focustrap = factory(global.EventHandler, global.SelectorEngine, global.Config));
  10. })(this, (function (EventHandler, SelectorEngine, Config) { 'use strict';
  11. /**
  12. * --------------------------------------------------------------------------
  13. * Bootstrap util/focustrap.js
  14. * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  15. * --------------------------------------------------------------------------
  16. */
  17. /**
  18. * Constants
  19. */
  20. const NAME = 'focustrap';
  21. const DATA_KEY = 'bs.focustrap';
  22. const EVENT_KEY = `.${DATA_KEY}`;
  23. const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
  24. const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`;
  25. const TAB_KEY = 'Tab';
  26. const TAB_NAV_FORWARD = 'forward';
  27. const TAB_NAV_BACKWARD = 'backward';
  28. const Default = {
  29. autofocus: true,
  30. trapElement: null // The element to trap focus inside of
  31. };
  32. const DefaultType = {
  33. autofocus: 'boolean',
  34. trapElement: 'element'
  35. };
  36. /**
  37. * Class definition
  38. */
  39. class FocusTrap extends Config {
  40. constructor(config) {
  41. super();
  42. this._config = this._getConfig(config);
  43. this._isActive = false;
  44. this._lastTabNavDirection = null;
  45. }
  46. // Getters
  47. static get Default() {
  48. return Default;
  49. }
  50. static get DefaultType() {
  51. return DefaultType;
  52. }
  53. static get NAME() {
  54. return NAME;
  55. }
  56. // Public
  57. activate() {
  58. if (this._isActive) {
  59. return;
  60. }
  61. if (this._config.autofocus) {
  62. this._config.trapElement.focus();
  63. }
  64. EventHandler.off(document, EVENT_KEY); // guard against infinite focus loop
  65. EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
  66. EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
  67. this._isActive = true;
  68. }
  69. deactivate() {
  70. if (!this._isActive) {
  71. return;
  72. }
  73. this._isActive = false;
  74. EventHandler.off(document, EVENT_KEY);
  75. }
  76. // Private
  77. _handleFocusin(event) {
  78. const {
  79. trapElement
  80. } = this._config;
  81. if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
  82. return;
  83. }
  84. const elements = SelectorEngine.focusableChildren(trapElement);
  85. if (elements.length === 0) {
  86. trapElement.focus();
  87. } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
  88. elements[elements.length - 1].focus();
  89. } else {
  90. elements[0].focus();
  91. }
  92. }
  93. _handleKeydown(event) {
  94. if (event.key !== TAB_KEY) {
  95. return;
  96. }
  97. this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
  98. }
  99. }
  100. return FocusTrap;
  101. }));
  102. //# sourceMappingURL=focustrap.js.map