@openeuropa/bcl-theme-joinup 0.3791.202505281825 → 0.3821.202510100015

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 (98) hide show
  1. package/bcl-builder.config.js +2 -0
  2. package/css/oe-bcl-joinup.css +782 -275
  3. package/css/oe-bcl-joinup.css.map +1 -1
  4. package/css/oe-bcl-joinup.min.css +1 -1
  5. package/css/oe-bcl-joinup.min.css.map +1 -1
  6. package/fonts/files/roboto-cyrillic-400-italic.woff +0 -0
  7. package/fonts/files/roboto-cyrillic-400-italic.woff2 +0 -0
  8. package/fonts/files/roboto-cyrillic-400-normal.woff +0 -0
  9. package/fonts/files/roboto-cyrillic-400-normal.woff2 +0 -0
  10. package/fonts/files/roboto-cyrillic-500-italic.woff +0 -0
  11. package/fonts/files/roboto-cyrillic-500-italic.woff2 +0 -0
  12. package/fonts/files/roboto-cyrillic-500-normal.woff +0 -0
  13. package/fonts/files/roboto-cyrillic-500-normal.woff2 +0 -0
  14. package/fonts/files/roboto-cyrillic-700-italic.woff +0 -0
  15. package/fonts/files/roboto-cyrillic-700-italic.woff2 +0 -0
  16. package/fonts/files/roboto-cyrillic-700-normal.woff +0 -0
  17. package/fonts/files/roboto-cyrillic-700-normal.woff2 +0 -0
  18. package/fonts/files/roboto-greek-400-italic.woff +0 -0
  19. package/fonts/files/roboto-greek-400-italic.woff2 +0 -0
  20. package/fonts/files/roboto-greek-400-normal.woff +0 -0
  21. package/fonts/files/roboto-greek-400-normal.woff2 +0 -0
  22. package/fonts/files/roboto-greek-500-italic.woff +0 -0
  23. package/fonts/files/roboto-greek-500-italic.woff2 +0 -0
  24. package/fonts/files/roboto-greek-500-normal.woff +0 -0
  25. package/fonts/files/roboto-greek-500-normal.woff2 +0 -0
  26. package/fonts/files/roboto-greek-700-italic.woff +0 -0
  27. package/fonts/files/roboto-greek-700-italic.woff2 +0 -0
  28. package/fonts/files/roboto-greek-700-normal.woff +0 -0
  29. package/fonts/files/roboto-greek-700-normal.woff2 +0 -0
  30. package/fonts/files/roboto-latin-400-italic.woff +0 -0
  31. package/fonts/files/roboto-latin-400-italic.woff2 +0 -0
  32. package/fonts/files/roboto-latin-400-normal.woff +0 -0
  33. package/fonts/files/roboto-latin-400-normal.woff2 +0 -0
  34. package/fonts/files/roboto-latin-500-italic.woff +0 -0
  35. package/fonts/files/roboto-latin-500-italic.woff2 +0 -0
  36. package/fonts/files/roboto-latin-500-normal.woff +0 -0
  37. package/fonts/files/roboto-latin-500-normal.woff2 +0 -0
  38. package/fonts/files/roboto-latin-700-italic.woff +0 -0
  39. package/fonts/files/roboto-latin-700-italic.woff2 +0 -0
  40. package/fonts/files/roboto-latin-700-normal.woff +0 -0
  41. package/fonts/files/roboto-latin-700-normal.woff2 +0 -0
  42. package/fonts/files/roboto-latin-ext-400-italic.woff +0 -0
  43. package/fonts/files/roboto-latin-ext-400-italic.woff2 +0 -0
  44. package/fonts/files/roboto-latin-ext-400-normal.woff +0 -0
  45. package/fonts/files/roboto-latin-ext-400-normal.woff2 +0 -0
  46. package/fonts/files/roboto-latin-ext-500-italic.woff +0 -0
  47. package/fonts/files/roboto-latin-ext-500-italic.woff2 +0 -0
  48. package/fonts/files/roboto-latin-ext-500-normal.woff +0 -0
  49. package/fonts/files/roboto-latin-ext-500-normal.woff2 +0 -0
  50. package/fonts/files/roboto-latin-ext-700-italic.woff +0 -0
  51. package/fonts/files/roboto-latin-ext-700-italic.woff2 +0 -0
  52. package/fonts/files/roboto-latin-ext-700-normal.woff +0 -0
  53. package/fonts/files/roboto-latin-ext-700-normal.woff2 +0 -0
  54. package/icons/bcl-default-icons.svg +1 -1
  55. package/icons/bootstrap-icons.svg +1 -1
  56. package/js/oe-bcl-joinup.bundle.js +189 -5
  57. package/js/oe-bcl-joinup.bundle.js.map +1 -1
  58. package/js/oe-bcl-joinup.bundle.min.js +1 -1
  59. package/js/oe-bcl-joinup.bundle.min.js.map +1 -1
  60. package/js/oe-bcl-joinup.esm.js +188 -6
  61. package/js/oe-bcl-joinup.esm.js.map +1 -1
  62. package/js/oe-bcl-joinup.esm.min.js +1 -1
  63. package/js/oe-bcl-joinup.esm.min.js.map +1 -1
  64. package/js/oe-bcl-joinup.umd.js +189 -5
  65. package/js/oe-bcl-joinup.umd.js.map +1 -1
  66. package/js/oe-bcl-joinup.umd.min.js +1 -1
  67. package/js/oe-bcl-joinup.umd.min.js.map +1 -1
  68. package/js/slim-select-2/slimselect.min.js +1 -1
  69. package/package.json +12 -12
  70. package/src/js/index.esm.js +4 -0
  71. package/src/js/index.umd.js +4 -0
  72. package/src/scss/oe-bcl-joinup.scss +1 -0
  73. package/templates/bcl-base-templates/listing-page.html.twig +17 -19
  74. package/templates/bcl-button/button.html.twig +3 -2
  75. package/templates/bcl-contact-form/contact-form.html.twig +3 -3
  76. package/templates/bcl-content-banner/content-banner.html.twig +3 -0
  77. package/templates/bcl-dropdown/dropdown.html.twig +12 -7
  78. package/templates/bcl-event/event.html.twig +5 -5
  79. package/templates/bcl-glossary/glossary-detail.html.twig +4 -5
  80. package/templates/bcl-glossary/glossary-listing.html.twig +5 -5
  81. package/templates/bcl-group/group-landing.html.twig +5 -5
  82. package/templates/bcl-group/group.html.twig +3 -3
  83. package/templates/bcl-header/header.html.twig +37 -6
  84. package/templates/bcl-inpage-navigation/inpage-navigation.html.twig +7 -2
  85. package/templates/bcl-landing-page/landing-page.html.twig +5 -8
  86. package/templates/bcl-mega-menu/mega-menu-items.html.twig +35 -0
  87. package/templates/bcl-mega-menu/mega-menu-submenu.html.twig +65 -0
  88. package/templates/bcl-mega-menu/mega-menu.html.twig +115 -0
  89. package/templates/bcl-navigation/navigation.html.twig +11 -1
  90. package/templates/bcl-offcanvas/offcanvas.html.twig +9 -6
  91. package/templates/bcl-page/page.html.twig +5 -5
  92. package/templates/bcl-person/person.html.twig +5 -5
  93. package/templates/bcl-project/project.html.twig +7 -7
  94. package/templates/bcl-project-status/project-contributions.html.twig +1 -1
  95. package/templates/bcl-search/search.html.twig +3 -3
  96. package/templates/bcl-subscription/subscription.html.twig +5 -5
  97. package/templates/bcl-user/user-terms.html.twig +3 -3
  98. package/templates/bcl-user/user.html.twig +3 -3
@@ -638,7 +638,7 @@ class Config {
638
638
  * Constants
639
639
  */
640
640
 
641
- const VERSION = '5.3.6';
641
+ const VERSION = '5.3.8';
642
642
 
643
643
  /**
644
644
  * Class definition
@@ -1844,9 +1844,6 @@ class Dropdown extends BaseComponent {
1844
1844
  this._element.setAttribute('aria-expanded', 'false');
1845
1845
  Manipulator$1.removeDataAttribute(this._menu, 'popper');
1846
1846
  EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget);
1847
-
1848
- // Explicitly return focus to the trigger element
1849
- this._element.focus();
1850
1847
  }
1851
1848
  _getConfig(config) {
1852
1849
  config = super._getConfig(config);
@@ -3167,6 +3164,191 @@ class AccordionToggle {
3167
3164
  }
3168
3165
  }
3169
3166
 
3167
+ class MainNavigation {
3168
+ constructor(toggler) {
3169
+ this.toggler = toggler;
3170
+ this.top = 0;
3171
+ this.target = this.getTargetFromToggler(toggler);
3172
+ if (!this.target) return;
3173
+ this.addListeners();
3174
+ }
3175
+ getTargetFromToggler(toggler) {
3176
+ const selector = toggler.getAttribute("data-bs-target");
3177
+ if (!selector) return null;
3178
+ try {
3179
+ return document.querySelector(selector);
3180
+ } catch {
3181
+ return null;
3182
+ }
3183
+ }
3184
+ addListeners() {
3185
+ EventHandler.on(this.target, "show.bs.collapse", () => {
3186
+ window.scrollTo(0, this.top);
3187
+ });
3188
+ }
3189
+ static init(selector = ".bcl-toggler", options) {
3190
+ const togglers = SelectorEngine.find(selector);
3191
+ togglers.forEach(toggler => new MainNavigation(toggler, options));
3192
+ }
3193
+ }
3194
+ document.addEventListener("DOMContentLoaded", () => {
3195
+ // Run for all .bcl-toggler buttons
3196
+ MainNavigation.init(".bcl-navbar-toggler");
3197
+ });
3198
+
3199
+ class MegaMenu {
3200
+ constructor(root) {
3201
+ this.root = root;
3202
+ this.backButton = SelectorEngine.findOne(".back-button", this.root);
3203
+ this.trigger = SelectorEngine.findOne(':scope > .dropdown-toggle[data-bs-toggle="dropdown"]', this.root);
3204
+ this.ul = SelectorEngine.findOne('.bcl-mega-menu__items.__level-1', this.root);
3205
+ this.addSubmenuTriggerListeners();
3206
+ this.addBackButtonListener();
3207
+ this.addTriggerListeners();
3208
+ this.addEscapeKeyHandler();
3209
+ }
3210
+ getPanelForTrigger(trigger) {
3211
+ const id = trigger.getAttribute('aria-controls');
3212
+ return id ? document.getElementById(id) : null;
3213
+ }
3214
+ getFocusableChildren(container) {
3215
+ if (!container) return [];
3216
+ return Array.from(container.querySelectorAll('a[href], button:not([disabled]):not(.back-button), [tabindex]:not([tabindex="-1"])')).filter(el => !el.hasAttribute('disabled') && el.tabIndex !== -1);
3217
+ }
3218
+ focusFirstItemInPanel(trigger) {
3219
+ const panel = this.getPanelForTrigger(trigger);
3220
+ if (!panel) return;
3221
+ const list = SelectorEngine.findOne('ul.bcl-mega-menu__items', panel);
3222
+ if (!list) return;
3223
+ const first = this.getFocusableChildren(list)[0];
3224
+ if (first) first.focus();
3225
+ }
3226
+ addEscapeKeyHandler() {
3227
+ // Bootstrap attaches its dropdown keydown listener on `document` in the capture phase.
3228
+ // By listening on `window` in the capture phase, our handler runs *before* Bootstrap’s.
3229
+ // This lets us intercept Esc inside mega menu submenus and stop Bootstrap from closing
3230
+ // the entire dropdown.
3231
+ window.addEventListener('keydown', e => {
3232
+ if (e.key !== 'Escape') return;
3233
+
3234
+ // Only act if Esc originated inside THIS mega menu's open submenu
3235
+ const panel = e.target.closest('.bcl-mega-menu__submenu');
3236
+ if (!panel || panel.hidden || !this.root.contains(panel)) {
3237
+ // Not our submenu: let Bootstrap handle it normally
3238
+ return;
3239
+ }
3240
+
3241
+ // Stop the event BEFORE it reaches Bootstrap's document-capture handler
3242
+ e.preventDefault();
3243
+ e.stopImmediatePropagation();
3244
+ e.stopPropagation();
3245
+
3246
+ // Close only this submenu and focus its trigger
3247
+ const triggerId = panel.getAttribute('aria-labelledby');
3248
+ const trigger = triggerId ? document.getElementById(triggerId) : null;
3249
+ if (trigger) {
3250
+ this.closeSubmenu(trigger);
3251
+ trigger.focus();
3252
+ }
3253
+ }, true);
3254
+ }
3255
+ addTriggerListeners() {
3256
+ if (!this.trigger) return;
3257
+
3258
+ // When the mega menu is opened, focus the first item in the menu.
3259
+ EventHandler.on(this.trigger, 'shown.bs.dropdown', () => {
3260
+ const panelId = this.trigger.getAttribute('aria-controls');
3261
+ const panel = panelId ? document.getElementById(panelId) : null;
3262
+ const firstFocusable = panel ? this.getFocusableChildren(panel)[0] : null;
3263
+ if (firstFocusable) firstFocusable.focus();
3264
+ });
3265
+
3266
+ // When the mega menu is closed, close all submenus.
3267
+ EventHandler.on(this.trigger, 'hide.bs.dropdown', () => {
3268
+ this.closeAllSubmenus();
3269
+ });
3270
+ }
3271
+ addSubmenuTriggerListeners() {
3272
+ // Clicking/activating a parent item button toggles the submenu.
3273
+ SelectorEngine.find(':scope li > button[aria-expanded]', this.root).forEach(trigger => {
3274
+ EventHandler.on(trigger, "click", () => {
3275
+ const expanded = trigger.getAttribute('aria-expanded') === 'true';
3276
+ if (expanded) {
3277
+ // Close this submenu.
3278
+ this.closeSubmenu(trigger);
3279
+ } else {
3280
+ this.openSubmenu(trigger);
3281
+ // The back button is only visible in mobile / narrow viewport.
3282
+ if (this.backButton && this.backButton.offsetParent !== null) {
3283
+ this.backButton.focus();
3284
+ } else {
3285
+ this.focusFirstItemInPanel(trigger);
3286
+ }
3287
+ }
3288
+ });
3289
+ });
3290
+ }
3291
+ addBackButtonListener() {
3292
+ // Clicking a back button closes the submenu or the menu itself.
3293
+ if (!this.backButton) {
3294
+ return;
3295
+ }
3296
+ EventHandler.on(this.backButton, "click", () => {
3297
+ const submenusThatWereOpen = this.closeAllSubmenus();
3298
+ if (submenusThatWereOpen.length > 0) {
3299
+ // Focus the submenu trigger, to allow quick reopen by keystroke.
3300
+ submenusThatWereOpen[0].focus();
3301
+ return;
3302
+ }
3303
+ // Close the mega menu itself.
3304
+ if (this.trigger) {
3305
+ // Close using the Bootstrap dropdown API.
3306
+ Dropdown.getOrCreateInstance(this.trigger).hide();
3307
+ // Focus the main trigger, to allow quick reopen by keystroke.
3308
+ this.trigger.focus();
3309
+ }
3310
+ });
3311
+ }
3312
+ openSubmenu(trigger) {
3313
+ // Close all submenus, then open the current submenu.
3314
+ this.closeAllSubmenus();
3315
+ trigger.setAttribute('aria-expanded', 'true');
3316
+ const panel = this.getPanelForTrigger(trigger);
3317
+ if (panel) panel.hidden = false;
3318
+ }
3319
+
3320
+ /**
3321
+ * Closes all submenus.
3322
+ *
3323
+ * This is simple while there is only one submenu level.
3324
+ *
3325
+ * @returns {HTMLElement[]}
3326
+ * Triggers for submenus that were closed.
3327
+ * Usually this is either exactly one, or none.
3328
+ */
3329
+ closeAllSubmenus() {
3330
+ if (!this.ul) {
3331
+ return;
3332
+ }
3333
+ const triggers = SelectorEngine.find(':scope > li > button[aria-expanded="true"]', this.ul);
3334
+ // Use arrow fn to keep `this` bound.
3335
+ triggers.forEach(t => this.closeSubmenu(t));
3336
+ return triggers;
3337
+ }
3338
+ closeSubmenu(trigger) {
3339
+ trigger.setAttribute('aria-expanded', 'false');
3340
+ const panel = this.getPanelForTrigger(trigger);
3341
+ if (panel) panel.hidden = true;
3342
+ }
3343
+ static init(selector = ".bcl-mega-menu") {
3344
+ const megaMenus = SelectorEngine.find(selector);
3345
+ megaMenus.forEach(menuEl => new MegaMenu(menuEl));
3346
+ }
3347
+ }
3348
+ document.addEventListener("DOMContentLoaded", () => {
3349
+ MegaMenu.init();
3350
+ });
3351
+
3170
3352
  /**
3171
3353
  * --------------------------------------------------------------------------
3172
3354
  * Bootstrap util/sanitizer.js
@@ -3222,7 +3404,6 @@ const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longde
3222
3404
  *
3223
3405
  * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
3224
3406
  */
3225
- // eslint-disable-next-line unicorn/better-regex
3226
3407
  const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
3227
3408
  const allowedAttribute = (attribute, allowedAttributeList) => {
3228
3409
  const attributeName = attribute.nodeName.toLowerCase();
@@ -3766,6 +3947,7 @@ class Tooltip extends BaseComponent {
3766
3947
  if (trigger === 'click') {
3767
3948
  EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => {
3768
3949
  const context = this._initializeOnDelegatedTarget(event);
3950
+ context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK]);
3769
3951
  context.toggle();
3770
3952
  });
3771
3953
  } else if (trigger !== TRIGGER_MANUAL) {
@@ -5066,5 +5248,5 @@ enableDismissTrigger(Toast);
5066
5248
 
5067
5249
  defineJQueryPlugin$1(Toast);
5068
5250
 
5069
- export { AccessibleToggle, AccordionToggle, Alert, Button, Carousel, Collapse, Dropdown, Gallery, Modal, Offcanvas, Popover, ScrollSpy, ScrollSpy$1 as ScrollSpyV2, Tab, Toast, Tooltip };
5251
+ export { AccessibleToggle, AccordionToggle, Alert, Button, Carousel, Collapse, Dropdown, Gallery, MainNavigation, MegaMenu, Modal, Offcanvas, Popover, ScrollSpy, ScrollSpy$1 as ScrollSpyV2, Tab, Toast, Tooltip };
5070
5252
  //# sourceMappingURL=oe-bcl-joinup.esm.js.map