@stackoverflow/stacks 1.8.0 → 1.9.1
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/README.md +161 -153
- package/dist/{controllers/s-banner.d.ts → components/banner/banner.d.ts} +1 -1
- package/dist/{controllers/s-expandable-control.d.ts → components/expandable/expandable.d.ts} +1 -1
- package/dist/{controllers/s-modal.d.ts → components/modal/modal.d.ts} +1 -1
- package/dist/{controllers/s-navigation-tablist.d.ts → components/navigation/navigation.d.ts} +1 -1
- package/dist/{controllers/s-popover.d.ts → components/popover/popover.d.ts} +1 -1
- package/dist/{controllers/s-tooltip.d.ts → components/popover/tooltip.d.ts} +1 -1
- package/dist/components/table/table.d.ts +30 -0
- package/dist/{controllers/s-toast.d.ts → components/toast/toast.d.ts} +1 -1
- package/dist/{controllers/s-uploader.d.ts → components/uploader/uploader.d.ts} +1 -1
- package/dist/controllers.d.ts +9 -0
- package/dist/css/stacks.css +2063 -1994
- package/dist/css/stacks.min.css +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/js/stacks.js +1465 -1436
- package/dist/js/stacks.min.js +1 -1
- package/lib/{css/atomic/borders.less → atomic/border.less} +397 -379
- package/lib/{css/atomic/colors.less → atomic/color.less} +210 -210
- package/lib/{css/atomic → atomic}/flex.less +426 -426
- package/lib/{css/atomic → atomic}/gap.less +44 -44
- package/lib/{css/atomic → atomic}/grid.less +139 -139
- package/lib/{css/atomic → atomic}/misc.less +343 -343
- package/lib/{css/atomic → atomic}/spacing.less +342 -342
- package/lib/{css/atomic → atomic}/typography.less +267 -267
- package/lib/{css/atomic → atomic}/width-height.less +194 -194
- package/lib/{css/base → base}/body.less +44 -44
- package/lib/{css/base → base}/configuration-static.less +61 -61
- package/lib/{css/base → base}/fieldset.less +5 -5
- package/lib/{css/base/icons.less → base/icon.less} +11 -20
- package/lib/{css/base/internals.less → base/internal.less} +220 -220
- package/lib/{css/base → base}/reset-meyer.less +64 -64
- package/lib/{css/base → base}/reset-normalize.less +449 -449
- package/lib/{css/base → base}/reset.less +20 -20
- package/lib/components/activity-indicator/activity-indicator.a11y.test.ts +21 -0
- package/lib/{css/components → components/activity-indicator}/activity-indicator.less +40 -40
- package/lib/components/activity-indicator/activity-indicator.visual.test.ts +23 -0
- package/lib/{css/components/anchors.less → components/anchor/anchor.less} +61 -61
- package/lib/components/avatar/avatar.a11y.test.ts +36 -0
- package/lib/{css/components/avatars.less → components/avatar/avatar.less} +108 -108
- package/lib/components/avatar/avatar.visual.test.ts +54 -0
- package/lib/components/award-bling/award-bling.a11y.test.ts +17 -0
- package/lib/{css/components → components/award-bling}/award-bling.less +31 -31
- package/lib/components/award-bling/award-bling.visual.test.ts +26 -0
- package/lib/{css/components/badges.less → components/badge/badge.less} +251 -251
- package/lib/components/banner/banner.a11y.test.ts +37 -0
- package/lib/components/banner/banner.less +51 -0
- package/lib/{test/s-banner.test.ts → components/banner/banner.test.ts} +73 -73
- package/lib/{ts/controllers/s-banner.ts → components/banner/banner.ts} +149 -149
- package/lib/components/banner/banner.visual.test.ts +37 -0
- package/lib/components/block-link/block-link.a11y.test.ts +68 -0
- package/lib/{css/components → components/block-link}/block-link.less +80 -80
- package/lib/components/block-link/block-link.visual.test.ts +61 -0
- package/lib/components/breadcrumbs/breadcrumbs.a11y.test.ts +37 -0
- package/lib/{css/components → components/breadcrumbs}/breadcrumbs.less +41 -41
- package/lib/components/breadcrumbs/breadcrumbs.visual.test.ts +37 -0
- package/lib/components/button/button.a11y.test.ts +32 -0
- package/lib/{css/components/buttons.less → components/button/button.less} +502 -501
- package/lib/components/button/button.visual.test.ts +52 -0
- package/lib/{css/components/button-groups.less → components/button-group/button-group.less} +83 -83
- package/lib/components/card/card.a11y.test.ts +13 -0
- package/lib/{css/components/cards.less → components/card/card.less} +29 -29
- package/lib/components/card/card.visual.test.ts +54 -0
- package/lib/components/check-control/check-control.less +17 -0
- package/lib/components/check-group/check-group.less +19 -0
- package/lib/{css/components/checkboxes-radios.less → components/checkbox_radio/checkbox_radio.less} +158 -158
- package/lib/{css/components/code-blocks.less → components/code-block/code-block.less} +116 -116
- package/lib/{css/components → components/description}/description.less +9 -9
- package/lib/{css/components/empty-states.less → components/empty-state/empty-state.less} +16 -16
- package/lib/{css/components → components/expandable}/expandable.less +118 -115
- package/lib/components/expandable/expandable.test.ts +51 -0
- package/lib/{ts/controllers/s-expandable-control.ts → components/expandable/expandable.ts} +238 -238
- package/lib/components/input-fill/input-fill.less +35 -0
- package/lib/components/input-icon/input-icon.less +45 -0
- package/lib/components/input-message/input-message.less +48 -0
- package/lib/{css/components/inputs.less → components/input_textarea/input_textarea.less} +166 -297
- package/lib/{css/components/labels.less → components/label/label.less} +111 -111
- package/lib/{css/components → components/link}/link.less +119 -119
- package/lib/{css/components/link-previews.less → components/link-preview/link-preview.less} +139 -139
- package/lib/{css/components → components/menu}/menu.less +41 -41
- package/lib/{css/components/modals.less → components/modal/modal.less} +113 -113
- package/lib/{ts/controllers/s-modal.ts → components/modal/modal.ts} +379 -379
- package/lib/{css/components → components/navigation}/navigation.less +134 -134
- package/lib/{ts/controllers/s-navigation-tablist.ts → components/navigation/navigation.ts} +128 -128
- package/lib/{css/components/notices.less → components/notice/notice.less} +203 -292
- package/lib/{css/components/page-titles.less → components/page-title/page-title.less} +51 -51
- package/lib/{css/components → components/pagination}/pagination.less +52 -52
- package/lib/{css/components/popovers.less → components/popover/popover.less} +148 -147
- package/lib/{ts/controllers/s-popover.ts → components/popover/popover.ts} +651 -651
- package/lib/{test/s-tooltip.test.ts → components/popover/tooltip.test.ts} +62 -62
- package/lib/{ts/controllers/s-tooltip.ts → components/popover/tooltip.ts} +343 -343
- package/lib/{test/s-tooltip.visual.test.ts → components/popover/tooltip.visual.test.ts} +31 -31
- package/lib/{css/components → components/post-summary}/post-summary.less +415 -415
- package/lib/{css/components/progress-bars.less → components/progress-bar/progress-bar.less} +291 -291
- package/lib/{css/components → components/prose}/prose.less +452 -452
- package/lib/{css/components → components/select}/select.less +148 -148
- package/lib/{css/components/sidebar-widgets.less → components/sidebar-widget/sidebar-widget.less} +257 -259
- package/lib/{css/components → components/spinner}/spinner.less +103 -103
- package/lib/{css/components → components/table}/table.less +307 -297
- package/lib/components/table/table.test.ts +366 -0
- package/lib/{ts/controllers/s-table.ts → components/table/table.ts} +296 -263
- package/lib/components/table-container/table-container.less +4 -0
- package/lib/{css/components/tags.less → components/tag/tag.less} +213 -213
- package/lib/components/toast/toast.less +35 -0
- package/lib/{test/s-toast.test.ts → components/toast/toast.test.ts} +63 -63
- package/lib/{ts/controllers/s-toast.ts → components/toast/toast.ts} +357 -357
- package/lib/components/toast/toast.visual.test.ts +27 -0
- package/lib/{css/components/toggle-switches.less → components/toggle-switch/toggle-switch.less} +110 -110
- package/lib/{css/components → components/topbar}/topbar.less +436 -435
- package/lib/{css/components → components/uploader}/uploader.less +195 -195
- package/lib/{ts/controllers/s-uploader.ts → components/uploader/uploader.ts} +205 -205
- package/lib/{css/components/user-cards.less → components/user-card/user-card.less} +129 -129
- package/lib/controllers.ts +33 -0
- package/lib/{css/exports → exports}/constants-colors.less +1112 -1111
- package/lib/{css/exports → exports}/constants-helpers.less +108 -108
- package/lib/{css/exports → exports}/constants-type.less +153 -153
- package/lib/{css/exports → exports}/exports.less +15 -15
- package/lib/{css/exports → exports}/mixins.less +299 -299
- package/lib/{ts/index.ts → index.ts} +32 -32
- package/lib/{css/input-utils.less → input-utils.less} +44 -44
- package/lib/{css/stacks-dynamic.less → stacks-dynamic.less} +24 -25
- package/lib/stacks-static.less +93 -0
- package/lib/{css/stacks.less → stacks.less} +13 -13
- package/lib/{ts/stacks.ts → stacks.ts} +113 -113
- package/lib/test/open-wc-testing-patch.d.ts +26 -0
- package/lib/test/test-utils.ts +466 -0
- package/lib/tsconfig.build.json +4 -0
- package/lib/tsconfig.json +16 -13
- package/package.json +106 -105
- package/dist/controllers/index.d.ts +0 -9
- package/dist/controllers/s-table.d.ts +0 -8
- package/lib/css/stacks-static.less +0 -87
- package/lib/test/s-avatar.a11y.test.ts +0 -77
- package/lib/test/s-banner.visual.test.ts +0 -61
- package/lib/test/s-btn.a11y.test.ts +0 -123
- package/lib/test/s-btn.visual.test.ts +0 -16
- package/lib/test/s-toast.visual.test.ts +0 -48
- package/lib/ts/controllers/index.ts +0 -17
package/dist/js/stacks.js
CHANGED
|
@@ -2488,7 +2488,7 @@ Controller.values = {};
|
|
|
2488
2488
|
|
|
2489
2489
|
|
|
2490
2490
|
|
|
2491
|
-
;// CONCATENATED MODULE: ./lib/
|
|
2491
|
+
;// CONCATENATED MODULE: ./lib/stacks.ts
|
|
2492
2492
|
|
|
2493
2493
|
class StacksApplication extends Application {
|
|
2494
2494
|
load(head, ...rest) {
|
|
@@ -2515,6 +2515,7 @@ class StacksApplication extends Application {
|
|
|
2515
2515
|
}
|
|
2516
2516
|
}
|
|
2517
2517
|
StacksApplication._initializing = true;
|
|
2518
|
+
|
|
2518
2519
|
const application = StacksApplication.start();
|
|
2519
2520
|
class StacksController extends Controller {
|
|
2520
2521
|
getElementData(element, key) {
|
|
@@ -2571,7 +2572,116 @@ function addController(name, controller) {
|
|
|
2571
2572
|
application.register(name, createController(controller));
|
|
2572
2573
|
}
|
|
2573
2574
|
|
|
2574
|
-
;// CONCATENATED MODULE: ./lib/
|
|
2575
|
+
;// CONCATENATED MODULE: ./lib/components/banner/banner.ts
|
|
2576
|
+
|
|
2577
|
+
class BannerController extends StacksController {
|
|
2578
|
+
/**
|
|
2579
|
+
* Toggles the visibility of the banner
|
|
2580
|
+
*/
|
|
2581
|
+
toggle(dispatcher = null) {
|
|
2582
|
+
this._toggle(undefined, dispatcher);
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* Shows the banner
|
|
2586
|
+
*/
|
|
2587
|
+
show(dispatcher = null) {
|
|
2588
|
+
this._toggle(true, dispatcher);
|
|
2589
|
+
}
|
|
2590
|
+
/**
|
|
2591
|
+
* Hides the banner
|
|
2592
|
+
*/
|
|
2593
|
+
hide(dispatcher = null) {
|
|
2594
|
+
this._toggle(false, dispatcher);
|
|
2595
|
+
}
|
|
2596
|
+
/**
|
|
2597
|
+
* Toggles the visibility of the banner element
|
|
2598
|
+
* @param show Optional parameter that force shows/hides the element or toggles it if left undefined
|
|
2599
|
+
*/
|
|
2600
|
+
_toggle(show, dispatcher = null) {
|
|
2601
|
+
let toShow = show;
|
|
2602
|
+
const isVisible = this.bannerTarget.getAttribute("aria-hidden") === "false";
|
|
2603
|
+
// if we're letting the class toggle, we need to figure out if the banner is visible manually
|
|
2604
|
+
if (typeof toShow === "undefined") {
|
|
2605
|
+
toShow = !isVisible;
|
|
2606
|
+
}
|
|
2607
|
+
// if the state matches the disired state, return without changing anything
|
|
2608
|
+
if ((toShow && isVisible) || (!toShow && !isVisible)) {
|
|
2609
|
+
return;
|
|
2610
|
+
}
|
|
2611
|
+
const dispatchingElement = this.getDispatcher(dispatcher);
|
|
2612
|
+
// show/hide events trigger before toggling the class
|
|
2613
|
+
const triggeredEvent = this.triggerEvent(toShow ? "show" : "hide", {
|
|
2614
|
+
dispatcher: this.getDispatcher(dispatchingElement),
|
|
2615
|
+
}, this.bannerTarget);
|
|
2616
|
+
// if this pre-show/hide event was prevented, don't attempt to continue changing the banner state
|
|
2617
|
+
if (triggeredEvent.defaultPrevented) {
|
|
2618
|
+
return;
|
|
2619
|
+
}
|
|
2620
|
+
this.bannerTarget.setAttribute("aria-hidden", toShow ? "false" : "true");
|
|
2621
|
+
if (!toShow) {
|
|
2622
|
+
this.removeBannerOnHide();
|
|
2623
|
+
}
|
|
2624
|
+
this.triggerEvent(toShow ? "shown" : "hidden", {
|
|
2625
|
+
dispatcher: dispatchingElement,
|
|
2626
|
+
}, this.bannerTarget);
|
|
2627
|
+
}
|
|
2628
|
+
/**
|
|
2629
|
+
* Remove the element on hide if the `remove-when-hidden` flag is set
|
|
2630
|
+
*/
|
|
2631
|
+
removeBannerOnHide() {
|
|
2632
|
+
if (this.data.get("remove-when-hidden") !== "true") {
|
|
2633
|
+
return;
|
|
2634
|
+
}
|
|
2635
|
+
this.bannerTarget.addEventListener("s-banner:hidden", () => {
|
|
2636
|
+
this.element.remove();
|
|
2637
|
+
}, { once: true });
|
|
2638
|
+
}
|
|
2639
|
+
/**
|
|
2640
|
+
* Determines the correct dispatching element from a potential input
|
|
2641
|
+
* @param dispatcher The event or element to get the dispatcher from
|
|
2642
|
+
*/
|
|
2643
|
+
getDispatcher(dispatcher = null) {
|
|
2644
|
+
if (dispatcher instanceof Event) {
|
|
2645
|
+
return dispatcher.target;
|
|
2646
|
+
}
|
|
2647
|
+
else if (dispatcher instanceof Element) {
|
|
2648
|
+
return dispatcher;
|
|
2649
|
+
}
|
|
2650
|
+
else {
|
|
2651
|
+
return this.element;
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
BannerController.targets = ["banner"];
|
|
2656
|
+
|
|
2657
|
+
/**
|
|
2658
|
+
* Helper to manually show an s-banner element via external JS
|
|
2659
|
+
* @param element the element the `data-controller="s-banner"` attribute is on
|
|
2660
|
+
*/
|
|
2661
|
+
function showBanner(element) {
|
|
2662
|
+
toggleBanner(element, true);
|
|
2663
|
+
}
|
|
2664
|
+
/**
|
|
2665
|
+
* Helper to manually hide an s-banner element via external JS
|
|
2666
|
+
* @param element the element the `data-controller="s-banner"` attribute is on
|
|
2667
|
+
*/
|
|
2668
|
+
function hideBanner(element) {
|
|
2669
|
+
toggleBanner(element, false);
|
|
2670
|
+
}
|
|
2671
|
+
/**
|
|
2672
|
+
* Helper to manually show an s-banner element via external JS
|
|
2673
|
+
* @param element the element the `data-controller="s-banner"` attribute is on
|
|
2674
|
+
* @param show whether to force show/hide the banner; toggles the banner if left undefined
|
|
2675
|
+
*/
|
|
2676
|
+
function toggleBanner(element, show) {
|
|
2677
|
+
const controller = application.getControllerForElementAndIdentifier(element, "s-banner");
|
|
2678
|
+
if (!controller) {
|
|
2679
|
+
throw "Unable to get s-banner controller from element";
|
|
2680
|
+
}
|
|
2681
|
+
show ? controller.show() : controller.hide();
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
;// CONCATENATED MODULE: ./lib/components/expandable/expandable.ts
|
|
2575
2685
|
|
|
2576
2686
|
// Radio buttons only trigger a change event when they're *checked*, but not when
|
|
2577
2687
|
// they're *unchecked*. Therefore, if we have an active `s-expandable-control` in
|
|
@@ -2765,7 +2875,7 @@ class ExpandableController extends StacksController {
|
|
|
2765
2875
|
}
|
|
2766
2876
|
}
|
|
2767
2877
|
|
|
2768
|
-
;// CONCATENATED MODULE: ./lib/
|
|
2878
|
+
;// CONCATENATED MODULE: ./lib/components/modal/modal.ts
|
|
2769
2879
|
|
|
2770
2880
|
class ModalController extends StacksController {
|
|
2771
2881
|
connect() {
|
|
@@ -3019,6 +3129,7 @@ class ModalController extends StacksController {
|
|
|
3019
3129
|
}
|
|
3020
3130
|
}
|
|
3021
3131
|
ModalController.targets = ["modal", "initialFocus"];
|
|
3132
|
+
|
|
3022
3133
|
/**
|
|
3023
3134
|
* Helper to manually show an s-modal element via external JS
|
|
3024
3135
|
* @param element the element the `data-controller="s-modal"` attribute is on
|
|
@@ -3046,832 +3157,466 @@ function toggleModal(element, show) {
|
|
|
3046
3157
|
show ? controller.show() : controller.hide();
|
|
3047
3158
|
}
|
|
3048
3159
|
|
|
3049
|
-
;// CONCATENATED MODULE: ./lib/
|
|
3160
|
+
;// CONCATENATED MODULE: ./lib/components/navigation/navigation.ts
|
|
3050
3161
|
|
|
3051
|
-
class
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
this.
|
|
3162
|
+
class TabListController extends StacksController {
|
|
3163
|
+
connect() {
|
|
3164
|
+
super.connect();
|
|
3165
|
+
this.boundSelectTab = this.selectTab.bind(this);
|
|
3166
|
+
this.boundHandleKeydown = this.handleKeydown.bind(this);
|
|
3167
|
+
for (const tab of this.tabTargets) {
|
|
3168
|
+
tab.addEventListener("click", this.boundSelectTab);
|
|
3169
|
+
tab.addEventListener("keydown", this.boundHandleKeydown);
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
disconnect() {
|
|
3173
|
+
super.disconnect();
|
|
3174
|
+
for (const tab of this.tabTargets) {
|
|
3175
|
+
tab.removeEventListener("click", this.boundSelectTab);
|
|
3176
|
+
tab.removeEventListener("keydown", this.boundHandleKeydown);
|
|
3177
|
+
}
|
|
3057
3178
|
}
|
|
3058
3179
|
/**
|
|
3059
|
-
*
|
|
3180
|
+
* Gets all tabs within the controller.
|
|
3060
3181
|
*/
|
|
3061
|
-
|
|
3062
|
-
this.
|
|
3182
|
+
get tabTargets() {
|
|
3183
|
+
return Array.from(this.element.querySelectorAll("[role=tab]"));
|
|
3063
3184
|
}
|
|
3064
3185
|
/**
|
|
3065
|
-
*
|
|
3186
|
+
* Handles click events on individual tabs, causing them to be selected.
|
|
3066
3187
|
*/
|
|
3067
|
-
|
|
3068
|
-
this.
|
|
3188
|
+
selectTab(event) {
|
|
3189
|
+
this.switchToTab(event.currentTarget);
|
|
3069
3190
|
}
|
|
3070
3191
|
/**
|
|
3071
|
-
*
|
|
3072
|
-
*
|
|
3192
|
+
* Handles left and right arrow keydown events on individual tabs,
|
|
3193
|
+
* selecting the adjacent tab corresponding to the event.
|
|
3073
3194
|
*/
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3195
|
+
handleKeydown(event) {
|
|
3196
|
+
var _a;
|
|
3197
|
+
let tabElement = event.currentTarget;
|
|
3198
|
+
const tabs = this.tabTargets;
|
|
3199
|
+
let tabIndex = tabs.indexOf(tabElement);
|
|
3200
|
+
if (event.key === "ArrowRight") {
|
|
3201
|
+
tabIndex++;
|
|
3080
3202
|
}
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
return;
|
|
3203
|
+
else if (event.key === "ArrowLeft") {
|
|
3204
|
+
tabIndex--;
|
|
3084
3205
|
}
|
|
3085
|
-
|
|
3086
|
-
// show/hide events trigger before toggling the class
|
|
3087
|
-
const triggeredEvent = this.triggerEvent(toShow ? "show" : "hide", {
|
|
3088
|
-
dispatcher: this.getDispatcher(dispatchingElement),
|
|
3089
|
-
}, this.bannerTarget);
|
|
3090
|
-
// if this pre-show/hide event was prevented, don't attempt to continue changing the banner state
|
|
3091
|
-
if (triggeredEvent.defaultPrevented) {
|
|
3206
|
+
else {
|
|
3092
3207
|
return;
|
|
3093
3208
|
}
|
|
3094
|
-
|
|
3095
|
-
if (
|
|
3096
|
-
|
|
3209
|
+
// Use circular navigation when users go past the first or last tab.
|
|
3210
|
+
if (tabIndex < 0) {
|
|
3211
|
+
tabIndex = tabs.length - 1;
|
|
3097
3212
|
}
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
}
|
|
3213
|
+
if (tabIndex >= tabs.length) {
|
|
3214
|
+
tabIndex = 0;
|
|
3215
|
+
}
|
|
3216
|
+
tabElement = tabs[tabIndex];
|
|
3217
|
+
this.switchToTab(tabElement);
|
|
3218
|
+
// Focus the newly selected tab so it can receive keyboard events.
|
|
3219
|
+
(_a = this.selectedTab) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3101
3220
|
}
|
|
3102
3221
|
/**
|
|
3103
|
-
*
|
|
3222
|
+
* Attempts to switch to a new tab, doing nothing if the tab is already selected or
|
|
3223
|
+
* the s-navigation-tablist:select event is prevented.
|
|
3104
3224
|
*/
|
|
3105
|
-
|
|
3106
|
-
|
|
3225
|
+
switchToTab(newTab) {
|
|
3226
|
+
const oldTab = this.selectedTab;
|
|
3227
|
+
if (oldTab === newTab) {
|
|
3107
3228
|
return;
|
|
3108
3229
|
}
|
|
3109
|
-
this.
|
|
3110
|
-
|
|
3111
|
-
}
|
|
3230
|
+
if (this.triggerEvent("select", { oldTab, newTab }).defaultPrevented) {
|
|
3231
|
+
return;
|
|
3232
|
+
}
|
|
3233
|
+
this.selectedTab = newTab;
|
|
3234
|
+
this.triggerEvent("selected", { oldTab, newTab });
|
|
3112
3235
|
}
|
|
3113
3236
|
/**
|
|
3114
|
-
*
|
|
3115
|
-
* @param dispatcher The event or element to get the dispatcher from
|
|
3237
|
+
* Returns the currently selected tab or null if no tabs are selected.
|
|
3116
3238
|
*/
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3239
|
+
get selectedTab() {
|
|
3240
|
+
return (this.tabTargets.find((e) => e.getAttribute("aria-selected") === "true") || null);
|
|
3241
|
+
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Switches the tablist to the provided tab, updating the tabs and panels
|
|
3244
|
+
* to reflect the change.
|
|
3245
|
+
* @param selectedTab The tab to select. If `null` is provided or the element
|
|
3246
|
+
* is not a valid tab, all tabs will be unselected.
|
|
3247
|
+
*/
|
|
3248
|
+
set selectedTab(selectedTab) {
|
|
3249
|
+
for (const tab of this.tabTargets) {
|
|
3250
|
+
const panelId = tab.getAttribute("aria-controls");
|
|
3251
|
+
const panel = panelId ? document.getElementById(panelId) : null;
|
|
3252
|
+
if (tab === selectedTab) {
|
|
3253
|
+
tab.classList.add("is-selected");
|
|
3254
|
+
tab.setAttribute("aria-selected", "true");
|
|
3255
|
+
tab.removeAttribute("tabindex");
|
|
3256
|
+
panel === null || panel === void 0 ? void 0 : panel.classList.remove("d-none");
|
|
3257
|
+
}
|
|
3258
|
+
else {
|
|
3259
|
+
tab.classList.remove("is-selected");
|
|
3260
|
+
tab.setAttribute("aria-selected", "false");
|
|
3261
|
+
tab.setAttribute("tabindex", "-1");
|
|
3262
|
+
panel === null || panel === void 0 ? void 0 : panel.classList.add("d-none");
|
|
3263
|
+
}
|
|
3126
3264
|
}
|
|
3127
3265
|
}
|
|
3128
3266
|
}
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
toggleBanner(element, false);
|
|
3267
|
+
|
|
3268
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getWindow.js
|
|
3269
|
+
function getWindow(node) {
|
|
3270
|
+
if (node == null) {
|
|
3271
|
+
return window;
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3274
|
+
if (node.toString() !== '[object Window]') {
|
|
3275
|
+
var ownerDocument = node.ownerDocument;
|
|
3276
|
+
return ownerDocument ? ownerDocument.defaultView || window : window;
|
|
3277
|
+
}
|
|
3278
|
+
|
|
3279
|
+
return node;
|
|
3143
3280
|
}
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3281
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/instanceOf.js
|
|
3282
|
+
|
|
3283
|
+
|
|
3284
|
+
function isElement(node) {
|
|
3285
|
+
var OwnElement = getWindow(node).Element;
|
|
3286
|
+
return node instanceof OwnElement || node instanceof Element;
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3289
|
+
function isHTMLElement(node) {
|
|
3290
|
+
var OwnElement = getWindow(node).HTMLElement;
|
|
3291
|
+
return node instanceof OwnElement || node instanceof HTMLElement;
|
|
3155
3292
|
}
|
|
3156
3293
|
|
|
3157
|
-
|
|
3294
|
+
function isShadowRoot(node) {
|
|
3295
|
+
// IE 11 has no ShadowRoot
|
|
3296
|
+
if (typeof ShadowRoot === 'undefined') {
|
|
3297
|
+
return false;
|
|
3298
|
+
}
|
|
3158
3299
|
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3300
|
+
var OwnElement = getWindow(node).ShadowRoot;
|
|
3301
|
+
return node instanceof OwnElement || node instanceof ShadowRoot;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
|
|
3305
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/utils/math.js
|
|
3306
|
+
var math_max = Math.max;
|
|
3307
|
+
var math_min = Math.min;
|
|
3308
|
+
var round = Math.round;
|
|
3309
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/utils/userAgent.js
|
|
3310
|
+
function getUAString() {
|
|
3311
|
+
var uaData = navigator.userAgentData;
|
|
3312
|
+
|
|
3313
|
+
if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {
|
|
3314
|
+
return uaData.brands.map(function (item) {
|
|
3315
|
+
return item.brand + "/" + item.version;
|
|
3316
|
+
}).join(' ');
|
|
3317
|
+
}
|
|
3318
|
+
|
|
3319
|
+
return navigator.userAgent;
|
|
3320
|
+
}
|
|
3321
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js
|
|
3322
|
+
|
|
3323
|
+
function isLayoutViewport() {
|
|
3324
|
+
return !/^((?!chrome|android).)*safari/i.test(getUAString());
|
|
3325
|
+
}
|
|
3326
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js
|
|
3327
|
+
|
|
3328
|
+
|
|
3329
|
+
|
|
3330
|
+
|
|
3331
|
+
function getBoundingClientRect(element, includeScale, isFixedStrategy) {
|
|
3332
|
+
if (includeScale === void 0) {
|
|
3333
|
+
includeScale = false;
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
if (isFixedStrategy === void 0) {
|
|
3337
|
+
isFixedStrategy = false;
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
var clientRect = element.getBoundingClientRect();
|
|
3341
|
+
var scaleX = 1;
|
|
3342
|
+
var scaleY = 1;
|
|
3343
|
+
|
|
3344
|
+
if (includeScale && isHTMLElement(element)) {
|
|
3345
|
+
scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
|
|
3346
|
+
scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
|
|
3347
|
+
}
|
|
3348
|
+
|
|
3349
|
+
var _ref = isElement(element) ? getWindow(element) : window,
|
|
3350
|
+
visualViewport = _ref.visualViewport;
|
|
3351
|
+
|
|
3352
|
+
var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;
|
|
3353
|
+
var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;
|
|
3354
|
+
var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;
|
|
3355
|
+
var width = clientRect.width / scaleX;
|
|
3356
|
+
var height = clientRect.height / scaleY;
|
|
3357
|
+
return {
|
|
3358
|
+
width: width,
|
|
3359
|
+
height: height,
|
|
3360
|
+
top: y,
|
|
3361
|
+
right: x + width,
|
|
3362
|
+
bottom: y + height,
|
|
3363
|
+
left: x,
|
|
3364
|
+
x: x,
|
|
3365
|
+
y: y
|
|
3366
|
+
};
|
|
3367
|
+
}
|
|
3368
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js
|
|
3369
|
+
|
|
3370
|
+
function getWindowScroll(node) {
|
|
3371
|
+
var win = getWindow(node);
|
|
3372
|
+
var scrollLeft = win.pageXOffset;
|
|
3373
|
+
var scrollTop = win.pageYOffset;
|
|
3374
|
+
return {
|
|
3375
|
+
scrollLeft: scrollLeft,
|
|
3376
|
+
scrollTop: scrollTop
|
|
3377
|
+
};
|
|
3378
|
+
}
|
|
3379
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js
|
|
3380
|
+
function getHTMLElementScroll(element) {
|
|
3381
|
+
return {
|
|
3382
|
+
scrollLeft: element.scrollLeft,
|
|
3383
|
+
scrollTop: element.scrollTop
|
|
3384
|
+
};
|
|
3385
|
+
}
|
|
3386
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js
|
|
3387
|
+
|
|
3388
|
+
|
|
3389
|
+
|
|
3390
|
+
|
|
3391
|
+
function getNodeScroll(node) {
|
|
3392
|
+
if (node === getWindow(node) || !isHTMLElement(node)) {
|
|
3393
|
+
return getWindowScroll(node);
|
|
3394
|
+
} else {
|
|
3395
|
+
return getHTMLElementScroll(node);
|
|
3396
|
+
}
|
|
3397
|
+
}
|
|
3398
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getNodeName.js
|
|
3399
|
+
function getNodeName(element) {
|
|
3400
|
+
return element ? (element.nodeName || '').toLowerCase() : null;
|
|
3401
|
+
}
|
|
3402
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js
|
|
3403
|
+
|
|
3404
|
+
function getDocumentElement(element) {
|
|
3405
|
+
// $FlowFixMe[incompatible-return]: assume body is always available
|
|
3406
|
+
return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
|
|
3407
|
+
element.document) || window.document).documentElement;
|
|
3408
|
+
}
|
|
3409
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js
|
|
3410
|
+
|
|
3411
|
+
|
|
3412
|
+
|
|
3413
|
+
function getWindowScrollBarX(element) {
|
|
3414
|
+
// If <html> has a CSS width greater than the viewport, then this will be
|
|
3415
|
+
// incorrect for RTL.
|
|
3416
|
+
// Popper 1 is broken in this case and never had a bug report so let's assume
|
|
3417
|
+
// it's not an issue. I don't think anyone ever specifies width on <html>
|
|
3418
|
+
// anyway.
|
|
3419
|
+
// Browsers where the left scrollbar doesn't cause an issue report `0` for
|
|
3420
|
+
// this (e.g. Edge 2019, IE11, Safari)
|
|
3421
|
+
return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
|
|
3422
|
+
}
|
|
3423
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js
|
|
3424
|
+
|
|
3425
|
+
function getComputedStyle_getComputedStyle(element) {
|
|
3426
|
+
return getWindow(element).getComputedStyle(element);
|
|
3427
|
+
}
|
|
3428
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js
|
|
3429
|
+
|
|
3430
|
+
function isScrollParent(element) {
|
|
3431
|
+
// Firefox wants us to check `-x` and `-y` variations as well
|
|
3432
|
+
var _getComputedStyle = getComputedStyle_getComputedStyle(element),
|
|
3433
|
+
overflow = _getComputedStyle.overflow,
|
|
3434
|
+
overflowX = _getComputedStyle.overflowX,
|
|
3435
|
+
overflowY = _getComputedStyle.overflowY;
|
|
3436
|
+
|
|
3437
|
+
return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
|
|
3438
|
+
}
|
|
3439
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js
|
|
3440
|
+
|
|
3441
|
+
|
|
3442
|
+
|
|
3443
|
+
|
|
3444
|
+
|
|
3445
|
+
|
|
3446
|
+
|
|
3447
|
+
|
|
3448
|
+
|
|
3449
|
+
function isElementScaled(element) {
|
|
3450
|
+
var rect = element.getBoundingClientRect();
|
|
3451
|
+
var scaleX = round(rect.width) / element.offsetWidth || 1;
|
|
3452
|
+
var scaleY = round(rect.height) / element.offsetHeight || 1;
|
|
3453
|
+
return scaleX !== 1 || scaleY !== 1;
|
|
3454
|
+
} // Returns the composite rect of an element relative to its offsetParent.
|
|
3455
|
+
// Composite means it takes into account transforms as well as layout.
|
|
3456
|
+
|
|
3457
|
+
|
|
3458
|
+
function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
|
|
3459
|
+
if (isFixed === void 0) {
|
|
3460
|
+
isFixed = false;
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
var isOffsetParentAnElement = isHTMLElement(offsetParent);
|
|
3464
|
+
var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);
|
|
3465
|
+
var documentElement = getDocumentElement(offsetParent);
|
|
3466
|
+
var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);
|
|
3467
|
+
var scroll = {
|
|
3468
|
+
scrollLeft: 0,
|
|
3469
|
+
scrollTop: 0
|
|
3470
|
+
};
|
|
3471
|
+
var offsets = {
|
|
3472
|
+
x: 0,
|
|
3473
|
+
y: 0
|
|
3474
|
+
};
|
|
3475
|
+
|
|
3476
|
+
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
|
|
3477
|
+
if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
|
|
3478
|
+
isScrollParent(documentElement)) {
|
|
3479
|
+
scroll = getNodeScroll(offsetParent);
|
|
3180
3480
|
}
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3481
|
+
|
|
3482
|
+
if (isHTMLElement(offsetParent)) {
|
|
3483
|
+
offsets = getBoundingClientRect(offsetParent, true);
|
|
3484
|
+
offsets.x += offsetParent.clientLeft;
|
|
3485
|
+
offsets.y += offsetParent.clientTop;
|
|
3486
|
+
} else if (documentElement) {
|
|
3487
|
+
offsets.x = getWindowScrollBarX(documentElement);
|
|
3186
3488
|
}
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
if (!this.returnElement) {
|
|
3196
|
-
throw ("Unable to find element by return-element selector: " +
|
|
3197
|
-
returnElementSelector);
|
|
3198
|
-
}
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3201
|
-
/**
|
|
3202
|
-
* Toggles the visibility of the toast element
|
|
3203
|
-
* @param show Optional parameter that force shows/hides the element or toggles it if left undefined
|
|
3204
|
-
*/
|
|
3205
|
-
_toggle(show, dispatcher = null) {
|
|
3206
|
-
let toShow = show;
|
|
3207
|
-
const isVisible = this.toastTarget.getAttribute("aria-hidden") === "false";
|
|
3208
|
-
// if we're letting the class toggle, we need to figure out if the toast is visible manually
|
|
3209
|
-
if (typeof toShow === "undefined") {
|
|
3210
|
-
toShow = !isVisible;
|
|
3211
|
-
}
|
|
3212
|
-
// if the state matches the disired state, return without changing anything
|
|
3213
|
-
if ((toShow && isVisible) || (!toShow && !isVisible)) {
|
|
3214
|
-
return;
|
|
3215
|
-
}
|
|
3216
|
-
const dispatchingElement = this.getDispatcher(dispatcher);
|
|
3217
|
-
// show/hide events trigger before toggling the class
|
|
3218
|
-
const triggeredEvent = this.triggerEvent(toShow ? "show" : "hide", {
|
|
3219
|
-
returnElement: this.returnElement,
|
|
3220
|
-
dispatcher: this.getDispatcher(dispatchingElement),
|
|
3221
|
-
}, this.toastTarget);
|
|
3222
|
-
// if this pre-show/hide event was prevented, don't attempt to continue changing the toast state
|
|
3223
|
-
if (triggeredEvent.defaultPrevented) {
|
|
3224
|
-
return;
|
|
3225
|
-
}
|
|
3226
|
-
this.returnElement = triggeredEvent.detail.returnElement;
|
|
3227
|
-
this.toastTarget.setAttribute("aria-hidden", toShow ? "false" : "true");
|
|
3228
|
-
if (toShow) {
|
|
3229
|
-
this.bindDocumentEvents();
|
|
3230
|
-
this.hideAfterTimeout();
|
|
3231
|
-
if (this.data.get("prevent-focus-capture") !== "true") {
|
|
3232
|
-
this.focusInsideToast();
|
|
3233
|
-
}
|
|
3234
|
-
}
|
|
3235
|
-
else {
|
|
3236
|
-
this.unbindDocumentEvents();
|
|
3237
|
-
this.focusReturnElement();
|
|
3238
|
-
this.removeToastOnHide();
|
|
3239
|
-
this.clearActiveTimeout();
|
|
3240
|
-
}
|
|
3241
|
-
// check for transitionend support
|
|
3242
|
-
const supportsTransitionEnd = this.toastTarget.ontransitionend !== undefined;
|
|
3243
|
-
// shown/hidden events trigger after toggling the class
|
|
3244
|
-
if (supportsTransitionEnd) {
|
|
3245
|
-
// wait until after the toast finishes transitioning to fire the event
|
|
3246
|
-
this.toastTarget.addEventListener("transitionend", () => {
|
|
3247
|
-
//TODO this is firing waaay to soon?
|
|
3248
|
-
this.triggerEvent(toShow ? "shown" : "hidden", {
|
|
3249
|
-
dispatcher: dispatchingElement,
|
|
3250
|
-
}, this.toastTarget);
|
|
3251
|
-
}, { once: true });
|
|
3252
|
-
}
|
|
3253
|
-
else {
|
|
3254
|
-
this.triggerEvent(toShow ? "shown" : "hidden", {
|
|
3255
|
-
dispatcher: dispatchingElement,
|
|
3256
|
-
}, this.toastTarget);
|
|
3257
|
-
}
|
|
3258
|
-
}
|
|
3259
|
-
/**
|
|
3260
|
-
* Listens for the s-toast:hidden event and focuses the returnElement when it is fired
|
|
3261
|
-
*/
|
|
3262
|
-
focusReturnElement() {
|
|
3263
|
-
if (!this.returnElement) {
|
|
3264
|
-
return;
|
|
3265
|
-
}
|
|
3266
|
-
this.toastTarget.addEventListener("s-toast:hidden", () => {
|
|
3267
|
-
// double check the element still exists when the event is called
|
|
3268
|
-
if (this.returnElement &&
|
|
3269
|
-
document.body.contains(this.returnElement)) {
|
|
3270
|
-
this.returnElement.focus();
|
|
3271
|
-
}
|
|
3272
|
-
}, { once: true });
|
|
3273
|
-
}
|
|
3274
|
-
/**
|
|
3275
|
-
* Remove the element on hide if the `remove-when-hidden` flag is set
|
|
3276
|
-
*/
|
|
3277
|
-
removeToastOnHide() {
|
|
3278
|
-
if (this.data.get("remove-when-hidden") !== "true") {
|
|
3279
|
-
return;
|
|
3280
|
-
}
|
|
3281
|
-
this.toastTarget.addEventListener("s-toast:hidden", () => {
|
|
3282
|
-
this.element.remove();
|
|
3283
|
-
}, { once: true });
|
|
3284
|
-
}
|
|
3285
|
-
/**
|
|
3286
|
-
* Hide the element after a delay
|
|
3287
|
-
*/
|
|
3288
|
-
hideAfterTimeout() {
|
|
3289
|
-
if (this.data.get("prevent-auto-hide") === "true" ||
|
|
3290
|
-
this.data.get("hide-after-timeout") === "0") {
|
|
3291
|
-
return;
|
|
3292
|
-
}
|
|
3293
|
-
const timeout = parseInt(this.data.get("hide-after-timeout"), 10) || 3000;
|
|
3294
|
-
this.activeTimeout = window.setTimeout(() => this.hide(), timeout);
|
|
3295
|
-
}
|
|
3296
|
-
/**
|
|
3297
|
-
* Cancels the activeTimeout
|
|
3298
|
-
*/
|
|
3299
|
-
clearActiveTimeout() {
|
|
3300
|
-
clearTimeout(this.activeTimeout);
|
|
3301
|
-
}
|
|
3302
|
-
/**
|
|
3303
|
-
* Gets all elements within the toast that could receive keyboard focus.
|
|
3304
|
-
*/
|
|
3305
|
-
getAllTabbables() {
|
|
3306
|
-
return Array.from(this.toastTarget.querySelectorAll("[href], input, select, textarea, button, [tabindex]")).filter((el) => el.matches(":not([disabled]):not([tabindex='-1'])"));
|
|
3307
|
-
}
|
|
3308
|
-
/**
|
|
3309
|
-
* Returns the first visible element in an array or `undefined` if no elements are visible.
|
|
3310
|
-
*/
|
|
3311
|
-
firstVisible(elements) {
|
|
3312
|
-
// https://stackoverflow.com/a/21696585
|
|
3313
|
-
return elements === null || elements === void 0 ? void 0 : elements.find((el) => el.offsetParent !== null);
|
|
3314
|
-
}
|
|
3315
|
-
/**
|
|
3316
|
-
* Attempts to shift keyboard focus into the toast.
|
|
3317
|
-
* If elements with `data-s-toast-target="initialFocus"` are present and visible, one of those will be selected.
|
|
3318
|
-
* Otherwise, the first visible focusable element will receive focus.
|
|
3319
|
-
*/
|
|
3320
|
-
focusInsideToast() {
|
|
3321
|
-
this.toastTarget.addEventListener("s-toast:shown", () => {
|
|
3322
|
-
var _a;
|
|
3323
|
-
const initialFocus = (_a = this.firstVisible(this.initialFocusTargets)) !== null && _a !== void 0 ? _a : this.firstVisible(this.getAllTabbables());
|
|
3324
|
-
initialFocus === null || initialFocus === void 0 ? void 0 : initialFocus.focus();
|
|
3325
|
-
}, { once: true });
|
|
3326
|
-
}
|
|
3327
|
-
/**
|
|
3328
|
-
* Binds global events to the document for hiding toasts on user interaction
|
|
3329
|
-
*/
|
|
3330
|
-
bindDocumentEvents() {
|
|
3331
|
-
// in order for removeEventListener to remove the right event, this bound function needs a constant reference
|
|
3332
|
-
this._boundClickFn =
|
|
3333
|
-
this._boundClickFn || this.hideOnOutsideClick.bind(this);
|
|
3334
|
-
this._boundKeypressFn =
|
|
3335
|
-
this._boundKeypressFn || this.hideOnEscapePress.bind(this);
|
|
3336
|
-
document.addEventListener("mousedown", this._boundClickFn);
|
|
3337
|
-
document.addEventListener("keyup", this._boundKeypressFn);
|
|
3338
|
-
}
|
|
3339
|
-
/**
|
|
3340
|
-
* Unbinds global events to the document for hiding toasts on user interaction
|
|
3341
|
-
*/
|
|
3342
|
-
unbindDocumentEvents() {
|
|
3343
|
-
document.removeEventListener("mousedown", this._boundClickFn);
|
|
3344
|
-
document.removeEventListener("keyup", this._boundKeypressFn);
|
|
3345
|
-
}
|
|
3346
|
-
/**
|
|
3347
|
-
* Forces the toast to hide if a user clicks outside of it or its reference element
|
|
3348
|
-
*/
|
|
3349
|
-
hideOnOutsideClick(e) {
|
|
3350
|
-
var _a;
|
|
3351
|
-
const target = e.target;
|
|
3352
|
-
// check if the document was clicked inside either the toggle element or the toast itself
|
|
3353
|
-
// note: .contains also returns true if the node itself matches the target element
|
|
3354
|
-
if (!((_a = this.toastTarget) === null || _a === void 0 ? void 0 : _a.contains(target)) &&
|
|
3355
|
-
document.body.contains(target) &&
|
|
3356
|
-
this.data.get("hide-on-outside-click") !== "false") {
|
|
3357
|
-
this._toggle(false, e);
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
3360
|
-
/**
|
|
3361
|
-
* Forces the toast to hide if the user presses escape while it, one of its childen, or the reference element are focused
|
|
3362
|
-
*/
|
|
3363
|
-
hideOnEscapePress(e) {
|
|
3364
|
-
// if the ESC key (27) wasn't pressed or if no toasts are showing, return
|
|
3365
|
-
if (e.which !== 27 ||
|
|
3366
|
-
this.toastTarget.getAttribute("aria-hidden") === "true") {
|
|
3367
|
-
return;
|
|
3368
|
-
}
|
|
3369
|
-
this._toggle(false, e);
|
|
3370
|
-
}
|
|
3371
|
-
/**
|
|
3372
|
-
* Determines the correct dispatching element from a potential input
|
|
3373
|
-
* @param dispatcher The event or element to get the dispatcher from
|
|
3374
|
-
*/
|
|
3375
|
-
getDispatcher(dispatcher = null) {
|
|
3376
|
-
if (dispatcher instanceof Event) {
|
|
3377
|
-
return dispatcher.target;
|
|
3378
|
-
}
|
|
3379
|
-
else if (dispatcher instanceof Element) {
|
|
3380
|
-
return dispatcher;
|
|
3381
|
-
}
|
|
3382
|
-
else {
|
|
3383
|
-
return this.element;
|
|
3384
|
-
}
|
|
3385
|
-
}
|
|
3386
|
-
}
|
|
3387
|
-
ToastController.targets = ["toast", "initialFocus"];
|
|
3388
|
-
/**
|
|
3389
|
-
* Helper to manually show an s-toast element via external JS
|
|
3390
|
-
* @param element the element the `data-controller="s-toast"` attribute is on
|
|
3391
|
-
*/
|
|
3392
|
-
function showToast(element) {
|
|
3393
|
-
toggleToast(element, true);
|
|
3394
|
-
}
|
|
3395
|
-
/**
|
|
3396
|
-
* Helper to manually hide an s-toast element via external JS
|
|
3397
|
-
* @param element the element the `data-controller="s-toast"` attribute is on
|
|
3398
|
-
*/
|
|
3399
|
-
function hideToast(element) {
|
|
3400
|
-
toggleToast(element, false);
|
|
3489
|
+
}
|
|
3490
|
+
|
|
3491
|
+
return {
|
|
3492
|
+
x: rect.left + scroll.scrollLeft - offsets.x,
|
|
3493
|
+
y: rect.top + scroll.scrollTop - offsets.y,
|
|
3494
|
+
width: rect.width,
|
|
3495
|
+
height: rect.height
|
|
3496
|
+
};
|
|
3401
3497
|
}
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3498
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js
|
|
3499
|
+
// Returns the layout rect of an element relative to its offsetParent. Layout
|
|
3500
|
+
// means it doesn't take into account transforms.
|
|
3501
|
+
|
|
3502
|
+
function getLayoutRect(element) {
|
|
3503
|
+
var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.
|
|
3504
|
+
// Fixes https://github.com/popperjs/popper-core/issues/1223
|
|
3505
|
+
|
|
3506
|
+
var width = element.offsetWidth;
|
|
3507
|
+
var height = element.offsetHeight;
|
|
3508
|
+
|
|
3509
|
+
if (Math.abs(clientRect.width - width) <= 1) {
|
|
3510
|
+
width = clientRect.width;
|
|
3511
|
+
}
|
|
3512
|
+
|
|
3513
|
+
if (Math.abs(clientRect.height - height) <= 1) {
|
|
3514
|
+
height = clientRect.height;
|
|
3515
|
+
}
|
|
3516
|
+
|
|
3517
|
+
return {
|
|
3518
|
+
x: element.offsetLeft,
|
|
3519
|
+
y: element.offsetTop,
|
|
3520
|
+
width: width,
|
|
3521
|
+
height: height
|
|
3522
|
+
};
|
|
3413
3523
|
}
|
|
3524
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getParentNode.js
|
|
3414
3525
|
|
|
3415
|
-
;// CONCATENATED MODULE: ./lib/ts/controllers/s-navigation-tablist.ts
|
|
3416
3526
|
|
|
3417
|
-
class TabListController extends StacksController {
|
|
3418
|
-
connect() {
|
|
3419
|
-
super.connect();
|
|
3420
|
-
this.boundSelectTab = this.selectTab.bind(this);
|
|
3421
|
-
this.boundHandleKeydown = this.handleKeydown.bind(this);
|
|
3422
|
-
for (const tab of this.tabTargets) {
|
|
3423
|
-
tab.addEventListener("click", this.boundSelectTab);
|
|
3424
|
-
tab.addEventListener("keydown", this.boundHandleKeydown);
|
|
3425
|
-
}
|
|
3426
|
-
}
|
|
3427
|
-
disconnect() {
|
|
3428
|
-
super.disconnect();
|
|
3429
|
-
for (const tab of this.tabTargets) {
|
|
3430
|
-
tab.removeEventListener("click", this.boundSelectTab);
|
|
3431
|
-
tab.removeEventListener("keydown", this.boundHandleKeydown);
|
|
3432
|
-
}
|
|
3433
|
-
}
|
|
3434
|
-
/**
|
|
3435
|
-
* Gets all tabs within the controller.
|
|
3436
|
-
*/
|
|
3437
|
-
get tabTargets() {
|
|
3438
|
-
return Array.from(this.element.querySelectorAll("[role=tab]"));
|
|
3439
|
-
}
|
|
3440
|
-
/**
|
|
3441
|
-
* Handles click events on individual tabs, causing them to be selected.
|
|
3442
|
-
*/
|
|
3443
|
-
selectTab(event) {
|
|
3444
|
-
this.switchToTab(event.currentTarget);
|
|
3445
|
-
}
|
|
3446
|
-
/**
|
|
3447
|
-
* Handles left and right arrow keydown events on individual tabs,
|
|
3448
|
-
* selecting the adjacent tab corresponding to the event.
|
|
3449
|
-
*/
|
|
3450
|
-
handleKeydown(event) {
|
|
3451
|
-
var _a;
|
|
3452
|
-
let tabElement = event.currentTarget;
|
|
3453
|
-
const tabs = this.tabTargets;
|
|
3454
|
-
let tabIndex = tabs.indexOf(tabElement);
|
|
3455
|
-
if (event.key === "ArrowRight") {
|
|
3456
|
-
tabIndex++;
|
|
3457
|
-
}
|
|
3458
|
-
else if (event.key === "ArrowLeft") {
|
|
3459
|
-
tabIndex--;
|
|
3460
|
-
}
|
|
3461
|
-
else {
|
|
3462
|
-
return;
|
|
3463
|
-
}
|
|
3464
|
-
// Use circular navigation when users go past the first or last tab.
|
|
3465
|
-
if (tabIndex < 0) {
|
|
3466
|
-
tabIndex = tabs.length - 1;
|
|
3467
|
-
}
|
|
3468
|
-
if (tabIndex >= tabs.length) {
|
|
3469
|
-
tabIndex = 0;
|
|
3470
|
-
}
|
|
3471
|
-
tabElement = tabs[tabIndex];
|
|
3472
|
-
this.switchToTab(tabElement);
|
|
3473
|
-
// Focus the newly selected tab so it can receive keyboard events.
|
|
3474
|
-
(_a = this.selectedTab) === null || _a === void 0 ? void 0 : _a.focus();
|
|
3475
|
-
}
|
|
3476
|
-
/**
|
|
3477
|
-
* Attempts to switch to a new tab, doing nothing if the tab is already selected or
|
|
3478
|
-
* the s-navigation-tablist:select event is prevented.
|
|
3479
|
-
*/
|
|
3480
|
-
switchToTab(newTab) {
|
|
3481
|
-
const oldTab = this.selectedTab;
|
|
3482
|
-
if (oldTab === newTab) {
|
|
3483
|
-
return;
|
|
3484
|
-
}
|
|
3485
|
-
if (this.triggerEvent("select", { oldTab, newTab }).defaultPrevented) {
|
|
3486
|
-
return;
|
|
3487
|
-
}
|
|
3488
|
-
this.selectedTab = newTab;
|
|
3489
|
-
this.triggerEvent("selected", { oldTab, newTab });
|
|
3490
|
-
}
|
|
3491
|
-
/**
|
|
3492
|
-
* Returns the currently selected tab or null if no tabs are selected.
|
|
3493
|
-
*/
|
|
3494
|
-
get selectedTab() {
|
|
3495
|
-
return (this.tabTargets.find((e) => e.getAttribute("aria-selected") === "true") || null);
|
|
3496
|
-
}
|
|
3497
|
-
/**
|
|
3498
|
-
* Switches the tablist to the provided tab, updating the tabs and panels
|
|
3499
|
-
* to reflect the change.
|
|
3500
|
-
* @param selectedTab The tab to select. If `null` is provided or the element
|
|
3501
|
-
* is not a valid tab, all tabs will be unselected.
|
|
3502
|
-
*/
|
|
3503
|
-
set selectedTab(selectedTab) {
|
|
3504
|
-
for (const tab of this.tabTargets) {
|
|
3505
|
-
const panelId = tab.getAttribute("aria-controls");
|
|
3506
|
-
const panel = panelId ? document.getElementById(panelId) : null;
|
|
3507
|
-
if (tab === selectedTab) {
|
|
3508
|
-
tab.classList.add("is-selected");
|
|
3509
|
-
tab.setAttribute("aria-selected", "true");
|
|
3510
|
-
tab.removeAttribute("tabindex");
|
|
3511
|
-
panel === null || panel === void 0 ? void 0 : panel.classList.remove("d-none");
|
|
3512
|
-
}
|
|
3513
|
-
else {
|
|
3514
|
-
tab.classList.remove("is-selected");
|
|
3515
|
-
tab.setAttribute("aria-selected", "false");
|
|
3516
|
-
tab.setAttribute("tabindex", "-1");
|
|
3517
|
-
panel === null || panel === void 0 ? void 0 : panel.classList.add("d-none");
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
}
|
|
3521
|
-
}
|
|
3522
3527
|
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
return window;
|
|
3528
|
+
function getParentNode(element) {
|
|
3529
|
+
if (getNodeName(element) === 'html') {
|
|
3530
|
+
return element;
|
|
3527
3531
|
}
|
|
3528
3532
|
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
+
return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
|
|
3534
|
+
// $FlowFixMe[incompatible-return]
|
|
3535
|
+
// $FlowFixMe[prop-missing]
|
|
3536
|
+
element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
|
|
3537
|
+
element.parentNode || ( // DOM Element detected
|
|
3538
|
+
isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
|
|
3539
|
+
// $FlowFixMe[incompatible-call]: HTMLElement is a Node
|
|
3540
|
+
getDocumentElement(element) // fallback
|
|
3533
3541
|
|
|
3534
|
-
|
|
3542
|
+
);
|
|
3535
3543
|
}
|
|
3536
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/
|
|
3544
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js
|
|
3537
3545
|
|
|
3538
3546
|
|
|
3539
|
-
function isElement(node) {
|
|
3540
|
-
var OwnElement = getWindow(node).Element;
|
|
3541
|
-
return node instanceof OwnElement || node instanceof Element;
|
|
3542
|
-
}
|
|
3543
3547
|
|
|
3544
|
-
function isHTMLElement(node) {
|
|
3545
|
-
var OwnElement = getWindow(node).HTMLElement;
|
|
3546
|
-
return node instanceof OwnElement || node instanceof HTMLElement;
|
|
3547
|
-
}
|
|
3548
3548
|
|
|
3549
|
-
function
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
return
|
|
3549
|
+
function getScrollParent(node) {
|
|
3550
|
+
if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
|
|
3551
|
+
// $FlowFixMe[incompatible-return]: assume body is always available
|
|
3552
|
+
return node.ownerDocument.body;
|
|
3553
3553
|
}
|
|
3554
3554
|
|
|
3555
|
-
|
|
3556
|
-
|
|
3555
|
+
if (isHTMLElement(node) && isScrollParent(node)) {
|
|
3556
|
+
return node;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
return getScrollParent(getParentNode(node));
|
|
3557
3560
|
}
|
|
3561
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js
|
|
3558
3562
|
|
|
3559
3563
|
|
|
3560
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/utils/math.js
|
|
3561
|
-
var math_max = Math.max;
|
|
3562
|
-
var math_min = Math.min;
|
|
3563
|
-
var round = Math.round;
|
|
3564
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/utils/userAgent.js
|
|
3565
|
-
function getUAString() {
|
|
3566
|
-
var uaData = navigator.userAgentData;
|
|
3567
3564
|
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3565
|
+
|
|
3566
|
+
/*
|
|
3567
|
+
given a DOM element, return the list of all scroll parents, up the list of ancesors
|
|
3568
|
+
until we get to the top window object. This list is what we attach scroll listeners
|
|
3569
|
+
to, because if any of these parent elements scroll, we'll need to re-calculate the
|
|
3570
|
+
reference element's position.
|
|
3571
|
+
*/
|
|
3572
|
+
|
|
3573
|
+
function listScrollParents(element, list) {
|
|
3574
|
+
var _element$ownerDocumen;
|
|
3575
|
+
|
|
3576
|
+
if (list === void 0) {
|
|
3577
|
+
list = [];
|
|
3572
3578
|
}
|
|
3573
3579
|
|
|
3574
|
-
|
|
3580
|
+
var scrollParent = getScrollParent(element);
|
|
3581
|
+
var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
|
|
3582
|
+
var win = getWindow(scrollParent);
|
|
3583
|
+
var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
|
|
3584
|
+
var updatedList = list.concat(target);
|
|
3585
|
+
return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
|
|
3586
|
+
updatedList.concat(listScrollParents(getParentNode(target)));
|
|
3575
3587
|
}
|
|
3576
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/
|
|
3588
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/isTableElement.js
|
|
3577
3589
|
|
|
3578
|
-
function
|
|
3579
|
-
return
|
|
3590
|
+
function isTableElement(element) {
|
|
3591
|
+
return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
|
|
3580
3592
|
}
|
|
3581
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/
|
|
3582
|
-
|
|
3593
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js
|
|
3583
3594
|
|
|
3584
3595
|
|
|
3585
3596
|
|
|
3586
|
-
function getBoundingClientRect(element, includeScale, isFixedStrategy) {
|
|
3587
|
-
if (includeScale === void 0) {
|
|
3588
|
-
includeScale = false;
|
|
3589
|
-
}
|
|
3590
3597
|
|
|
3591
|
-
if (isFixedStrategy === void 0) {
|
|
3592
|
-
isFixedStrategy = false;
|
|
3593
|
-
}
|
|
3594
3598
|
|
|
3595
|
-
var clientRect = element.getBoundingClientRect();
|
|
3596
|
-
var scaleX = 1;
|
|
3597
|
-
var scaleY = 1;
|
|
3598
3599
|
|
|
3599
|
-
if (includeScale && isHTMLElement(element)) {
|
|
3600
|
-
scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;
|
|
3601
|
-
scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;
|
|
3602
|
-
}
|
|
3603
3600
|
|
|
3604
|
-
var _ref = isElement(element) ? getWindow(element) : window,
|
|
3605
|
-
visualViewport = _ref.visualViewport;
|
|
3606
3601
|
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
return {
|
|
3613
|
-
width: width,
|
|
3614
|
-
height: height,
|
|
3615
|
-
top: y,
|
|
3616
|
-
right: x + width,
|
|
3617
|
-
bottom: y + height,
|
|
3618
|
-
left: x,
|
|
3619
|
-
x: x,
|
|
3620
|
-
y: y
|
|
3621
|
-
};
|
|
3622
|
-
}
|
|
3623
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js
|
|
3602
|
+
function getTrueOffsetParent(element) {
|
|
3603
|
+
if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
|
|
3604
|
+
getComputedStyle_getComputedStyle(element).position === 'fixed') {
|
|
3605
|
+
return null;
|
|
3606
|
+
}
|
|
3624
3607
|
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
var scrollTop = win.pageYOffset;
|
|
3629
|
-
return {
|
|
3630
|
-
scrollLeft: scrollLeft,
|
|
3631
|
-
scrollTop: scrollTop
|
|
3632
|
-
};
|
|
3633
|
-
}
|
|
3634
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js
|
|
3635
|
-
function getHTMLElementScroll(element) {
|
|
3636
|
-
return {
|
|
3637
|
-
scrollLeft: element.scrollLeft,
|
|
3638
|
-
scrollTop: element.scrollTop
|
|
3639
|
-
};
|
|
3640
|
-
}
|
|
3641
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js
|
|
3608
|
+
return element.offsetParent;
|
|
3609
|
+
} // `.offsetParent` reports `null` for fixed elements, while absolute elements
|
|
3610
|
+
// return the containing block
|
|
3642
3611
|
|
|
3643
3612
|
|
|
3613
|
+
function getContainingBlock(element) {
|
|
3614
|
+
var isFirefox = /firefox/i.test(getUAString());
|
|
3615
|
+
var isIE = /Trident/i.test(getUAString());
|
|
3644
3616
|
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
return getWindowScroll(node);
|
|
3649
|
-
} else {
|
|
3650
|
-
return getHTMLElementScroll(node);
|
|
3651
|
-
}
|
|
3652
|
-
}
|
|
3653
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getNodeName.js
|
|
3654
|
-
function getNodeName(element) {
|
|
3655
|
-
return element ? (element.nodeName || '').toLowerCase() : null;
|
|
3656
|
-
}
|
|
3657
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js
|
|
3658
|
-
|
|
3659
|
-
function getDocumentElement(element) {
|
|
3660
|
-
// $FlowFixMe[incompatible-return]: assume body is always available
|
|
3661
|
-
return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
|
|
3662
|
-
element.document) || window.document).documentElement;
|
|
3663
|
-
}
|
|
3664
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
function getWindowScrollBarX(element) {
|
|
3669
|
-
// If <html> has a CSS width greater than the viewport, then this will be
|
|
3670
|
-
// incorrect for RTL.
|
|
3671
|
-
// Popper 1 is broken in this case and never had a bug report so let's assume
|
|
3672
|
-
// it's not an issue. I don't think anyone ever specifies width on <html>
|
|
3673
|
-
// anyway.
|
|
3674
|
-
// Browsers where the left scrollbar doesn't cause an issue report `0` for
|
|
3675
|
-
// this (e.g. Edge 2019, IE11, Safari)
|
|
3676
|
-
return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
|
|
3677
|
-
}
|
|
3678
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js
|
|
3679
|
-
|
|
3680
|
-
function getComputedStyle_getComputedStyle(element) {
|
|
3681
|
-
return getWindow(element).getComputedStyle(element);
|
|
3682
|
-
}
|
|
3683
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js
|
|
3684
|
-
|
|
3685
|
-
function isScrollParent(element) {
|
|
3686
|
-
// Firefox wants us to check `-x` and `-y` variations as well
|
|
3687
|
-
var _getComputedStyle = getComputedStyle_getComputedStyle(element),
|
|
3688
|
-
overflow = _getComputedStyle.overflow,
|
|
3689
|
-
overflowX = _getComputedStyle.overflowX,
|
|
3690
|
-
overflowY = _getComputedStyle.overflowY;
|
|
3691
|
-
|
|
3692
|
-
return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
|
|
3693
|
-
}
|
|
3694
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
function isElementScaled(element) {
|
|
3705
|
-
var rect = element.getBoundingClientRect();
|
|
3706
|
-
var scaleX = round(rect.width) / element.offsetWidth || 1;
|
|
3707
|
-
var scaleY = round(rect.height) / element.offsetHeight || 1;
|
|
3708
|
-
return scaleX !== 1 || scaleY !== 1;
|
|
3709
|
-
} // Returns the composite rect of an element relative to its offsetParent.
|
|
3710
|
-
// Composite means it takes into account transforms as well as layout.
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
|
|
3714
|
-
if (isFixed === void 0) {
|
|
3715
|
-
isFixed = false;
|
|
3716
|
-
}
|
|
3717
|
-
|
|
3718
|
-
var isOffsetParentAnElement = isHTMLElement(offsetParent);
|
|
3719
|
-
var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);
|
|
3720
|
-
var documentElement = getDocumentElement(offsetParent);
|
|
3721
|
-
var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);
|
|
3722
|
-
var scroll = {
|
|
3723
|
-
scrollLeft: 0,
|
|
3724
|
-
scrollTop: 0
|
|
3725
|
-
};
|
|
3726
|
-
var offsets = {
|
|
3727
|
-
x: 0,
|
|
3728
|
-
y: 0
|
|
3729
|
-
};
|
|
3730
|
-
|
|
3731
|
-
if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
|
|
3732
|
-
if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
|
|
3733
|
-
isScrollParent(documentElement)) {
|
|
3734
|
-
scroll = getNodeScroll(offsetParent);
|
|
3735
|
-
}
|
|
3736
|
-
|
|
3737
|
-
if (isHTMLElement(offsetParent)) {
|
|
3738
|
-
offsets = getBoundingClientRect(offsetParent, true);
|
|
3739
|
-
offsets.x += offsetParent.clientLeft;
|
|
3740
|
-
offsets.y += offsetParent.clientTop;
|
|
3741
|
-
} else if (documentElement) {
|
|
3742
|
-
offsets.x = getWindowScrollBarX(documentElement);
|
|
3743
|
-
}
|
|
3744
|
-
}
|
|
3745
|
-
|
|
3746
|
-
return {
|
|
3747
|
-
x: rect.left + scroll.scrollLeft - offsets.x,
|
|
3748
|
-
y: rect.top + scroll.scrollTop - offsets.y,
|
|
3749
|
-
width: rect.width,
|
|
3750
|
-
height: rect.height
|
|
3751
|
-
};
|
|
3752
|
-
}
|
|
3753
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js
|
|
3754
|
-
// Returns the layout rect of an element relative to its offsetParent. Layout
|
|
3755
|
-
// means it doesn't take into account transforms.
|
|
3756
|
-
|
|
3757
|
-
function getLayoutRect(element) {
|
|
3758
|
-
var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.
|
|
3759
|
-
// Fixes https://github.com/popperjs/popper-core/issues/1223
|
|
3760
|
-
|
|
3761
|
-
var width = element.offsetWidth;
|
|
3762
|
-
var height = element.offsetHeight;
|
|
3763
|
-
|
|
3764
|
-
if (Math.abs(clientRect.width - width) <= 1) {
|
|
3765
|
-
width = clientRect.width;
|
|
3766
|
-
}
|
|
3767
|
-
|
|
3768
|
-
if (Math.abs(clientRect.height - height) <= 1) {
|
|
3769
|
-
height = clientRect.height;
|
|
3770
|
-
}
|
|
3771
|
-
|
|
3772
|
-
return {
|
|
3773
|
-
x: element.offsetLeft,
|
|
3774
|
-
y: element.offsetTop,
|
|
3775
|
-
width: width,
|
|
3776
|
-
height: height
|
|
3777
|
-
};
|
|
3778
|
-
}
|
|
3779
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getParentNode.js
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
function getParentNode(element) {
|
|
3784
|
-
if (getNodeName(element) === 'html') {
|
|
3785
|
-
return element;
|
|
3786
|
-
}
|
|
3787
|
-
|
|
3788
|
-
return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
|
|
3789
|
-
// $FlowFixMe[incompatible-return]
|
|
3790
|
-
// $FlowFixMe[prop-missing]
|
|
3791
|
-
element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
|
|
3792
|
-
element.parentNode || ( // DOM Element detected
|
|
3793
|
-
isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
|
|
3794
|
-
// $FlowFixMe[incompatible-call]: HTMLElement is a Node
|
|
3795
|
-
getDocumentElement(element) // fallback
|
|
3796
|
-
|
|
3797
|
-
);
|
|
3798
|
-
}
|
|
3799
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
function getScrollParent(node) {
|
|
3805
|
-
if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
|
|
3806
|
-
// $FlowFixMe[incompatible-return]: assume body is always available
|
|
3807
|
-
return node.ownerDocument.body;
|
|
3808
|
-
}
|
|
3809
|
-
|
|
3810
|
-
if (isHTMLElement(node) && isScrollParent(node)) {
|
|
3811
|
-
return node;
|
|
3812
|
-
}
|
|
3813
|
-
|
|
3814
|
-
return getScrollParent(getParentNode(node));
|
|
3815
|
-
}
|
|
3816
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
/*
|
|
3822
|
-
given a DOM element, return the list of all scroll parents, up the list of ancesors
|
|
3823
|
-
until we get to the top window object. This list is what we attach scroll listeners
|
|
3824
|
-
to, because if any of these parent elements scroll, we'll need to re-calculate the
|
|
3825
|
-
reference element's position.
|
|
3826
|
-
*/
|
|
3827
|
-
|
|
3828
|
-
function listScrollParents(element, list) {
|
|
3829
|
-
var _element$ownerDocumen;
|
|
3830
|
-
|
|
3831
|
-
if (list === void 0) {
|
|
3832
|
-
list = [];
|
|
3833
|
-
}
|
|
3834
|
-
|
|
3835
|
-
var scrollParent = getScrollParent(element);
|
|
3836
|
-
var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
|
|
3837
|
-
var win = getWindow(scrollParent);
|
|
3838
|
-
var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
|
|
3839
|
-
var updatedList = list.concat(target);
|
|
3840
|
-
return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
|
|
3841
|
-
updatedList.concat(listScrollParents(getParentNode(target)));
|
|
3842
|
-
}
|
|
3843
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/isTableElement.js
|
|
3844
|
-
|
|
3845
|
-
function isTableElement(element) {
|
|
3846
|
-
return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
|
|
3847
|
-
}
|
|
3848
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
function getTrueOffsetParent(element) {
|
|
3858
|
-
if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
|
|
3859
|
-
getComputedStyle_getComputedStyle(element).position === 'fixed') {
|
|
3860
|
-
return null;
|
|
3861
|
-
}
|
|
3862
|
-
|
|
3863
|
-
return element.offsetParent;
|
|
3864
|
-
} // `.offsetParent` reports `null` for fixed elements, while absolute elements
|
|
3865
|
-
// return the containing block
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
function getContainingBlock(element) {
|
|
3869
|
-
var isFirefox = /firefox/i.test(getUAString());
|
|
3870
|
-
var isIE = /Trident/i.test(getUAString());
|
|
3871
|
-
|
|
3872
|
-
if (isIE && isHTMLElement(element)) {
|
|
3873
|
-
// In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
|
|
3874
|
-
var elementCss = getComputedStyle_getComputedStyle(element);
|
|
3617
|
+
if (isIE && isHTMLElement(element)) {
|
|
3618
|
+
// In IE 9, 10 and 11 fixed elements containing block is always established by the viewport
|
|
3619
|
+
var elementCss = getComputedStyle_getComputedStyle(element);
|
|
3875
3620
|
|
|
3876
3621
|
if (elementCss.position === 'fixed') {
|
|
3877
3622
|
return null;
|
|
@@ -4420,10 +4165,9 @@ var unsetSides = {
|
|
|
4420
4165
|
// Zooming can change the DPR, but it seems to report a value that will
|
|
4421
4166
|
// cleanly divide the values into the appropriate subpixels.
|
|
4422
4167
|
|
|
4423
|
-
function roundOffsetsByDPR(_ref) {
|
|
4168
|
+
function roundOffsetsByDPR(_ref, win) {
|
|
4424
4169
|
var x = _ref.x,
|
|
4425
4170
|
y = _ref.y;
|
|
4426
|
-
var win = window;
|
|
4427
4171
|
var dpr = win.devicePixelRatio || 1;
|
|
4428
4172
|
return {
|
|
4429
4173
|
x: round(x * dpr) / dpr || 0,
|
|
@@ -4506,7 +4250,7 @@ function mapToStyles(_ref2) {
|
|
|
4506
4250
|
var _ref4 = roundOffsets === true ? roundOffsetsByDPR({
|
|
4507
4251
|
x: x,
|
|
4508
4252
|
y: y
|
|
4509
|
-
}) : {
|
|
4253
|
+
}, getWindow(popper)) : {
|
|
4510
4254
|
x: x,
|
|
4511
4255
|
y: y
|
|
4512
4256
|
};
|
|
@@ -5455,767 +5199,1050 @@ function getSideOffsets(overflow, rect, preventedOffsets) {
|
|
|
5455
5199
|
left: overflow.left - rect.width - preventedOffsets.x
|
|
5456
5200
|
};
|
|
5457
5201
|
}
|
|
5458
|
-
|
|
5459
|
-
function isAnySideFullyClipped(overflow) {
|
|
5460
|
-
return [enums_top, right, bottom, left].some(function (side) {
|
|
5461
|
-
return overflow[side] >= 0;
|
|
5462
|
-
});
|
|
5202
|
+
|
|
5203
|
+
function isAnySideFullyClipped(overflow) {
|
|
5204
|
+
return [enums_top, right, bottom, left].some(function (side) {
|
|
5205
|
+
return overflow[side] >= 0;
|
|
5206
|
+
});
|
|
5207
|
+
}
|
|
5208
|
+
|
|
5209
|
+
function hide(_ref) {
|
|
5210
|
+
var state = _ref.state,
|
|
5211
|
+
name = _ref.name;
|
|
5212
|
+
var referenceRect = state.rects.reference;
|
|
5213
|
+
var popperRect = state.rects.popper;
|
|
5214
|
+
var preventedOffsets = state.modifiersData.preventOverflow;
|
|
5215
|
+
var referenceOverflow = detectOverflow(state, {
|
|
5216
|
+
elementContext: 'reference'
|
|
5217
|
+
});
|
|
5218
|
+
var popperAltOverflow = detectOverflow(state, {
|
|
5219
|
+
altBoundary: true
|
|
5220
|
+
});
|
|
5221
|
+
var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
|
|
5222
|
+
var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
|
|
5223
|
+
var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
|
|
5224
|
+
var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
|
|
5225
|
+
state.modifiersData[name] = {
|
|
5226
|
+
referenceClippingOffsets: referenceClippingOffsets,
|
|
5227
|
+
popperEscapeOffsets: popperEscapeOffsets,
|
|
5228
|
+
isReferenceHidden: isReferenceHidden,
|
|
5229
|
+
hasPopperEscaped: hasPopperEscaped
|
|
5230
|
+
};
|
|
5231
|
+
state.attributes.popper = Object.assign({}, state.attributes.popper, {
|
|
5232
|
+
'data-popper-reference-hidden': isReferenceHidden,
|
|
5233
|
+
'data-popper-escaped': hasPopperEscaped
|
|
5234
|
+
});
|
|
5235
|
+
} // eslint-disable-next-line import/no-unused-modules
|
|
5236
|
+
|
|
5237
|
+
|
|
5238
|
+
/* harmony default export */ const modifiers_hide = ({
|
|
5239
|
+
name: 'hide',
|
|
5240
|
+
enabled: true,
|
|
5241
|
+
phase: 'main',
|
|
5242
|
+
requiresIfExists: ['preventOverflow'],
|
|
5243
|
+
fn: hide
|
|
5244
|
+
});
|
|
5245
|
+
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/popper.js
|
|
5246
|
+
|
|
5247
|
+
|
|
5248
|
+
|
|
5249
|
+
|
|
5250
|
+
|
|
5251
|
+
|
|
5252
|
+
|
|
5253
|
+
|
|
5254
|
+
|
|
5255
|
+
|
|
5256
|
+
var defaultModifiers = [eventListeners, modifiers_popperOffsets, modifiers_computeStyles, modifiers_applyStyles, modifiers_offset, modifiers_flip, modifiers_preventOverflow, modifiers_arrow, modifiers_hide];
|
|
5257
|
+
var popper_createPopper = /*#__PURE__*/popperGenerator({
|
|
5258
|
+
defaultModifiers: defaultModifiers
|
|
5259
|
+
}); // eslint-disable-next-line import/no-unused-modules
|
|
5260
|
+
|
|
5261
|
+
// eslint-disable-next-line import/no-unused-modules
|
|
5262
|
+
|
|
5263
|
+
// eslint-disable-next-line import/no-unused-modules
|
|
5264
|
+
|
|
5265
|
+
|
|
5266
|
+
;// CONCATENATED MODULE: ./lib/components/popover/popover.ts
|
|
5267
|
+
|
|
5268
|
+
|
|
5269
|
+
class BasePopoverController extends StacksController {
|
|
5270
|
+
/**
|
|
5271
|
+
* Returns true if the if the popover is currently visible.
|
|
5272
|
+
*/
|
|
5273
|
+
get isVisible() {
|
|
5274
|
+
const popoverElement = this.popoverElement;
|
|
5275
|
+
return popoverElement
|
|
5276
|
+
? popoverElement.classList.contains("is-visible")
|
|
5277
|
+
: false;
|
|
5278
|
+
}
|
|
5279
|
+
/**
|
|
5280
|
+
* Gets whether the element is visible in the browser's viewport.
|
|
5281
|
+
*/
|
|
5282
|
+
get isInViewport() {
|
|
5283
|
+
const element = this.popoverElement;
|
|
5284
|
+
if (!this.isVisible || !element) {
|
|
5285
|
+
return false;
|
|
5286
|
+
}
|
|
5287
|
+
// From https://stackoverflow.com/a/5354536. Theoretically, this could be calculated using Popper's detectOverflow function,
|
|
5288
|
+
// but it's unclear how to access that with our current configuration.
|
|
5289
|
+
const rect = element.getBoundingClientRect();
|
|
5290
|
+
const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
|
|
5291
|
+
const viewWidth = Math.max(document.documentElement.clientWidth, window.innerWidth);
|
|
5292
|
+
return (rect.bottom > 0 &&
|
|
5293
|
+
rect.top < viewHeight &&
|
|
5294
|
+
rect.right > 0 &&
|
|
5295
|
+
rect.left < viewWidth);
|
|
5296
|
+
}
|
|
5297
|
+
get shouldHideOnOutsideClick() {
|
|
5298
|
+
const hideBehavior = (this.data.get("hide-on-outside-click"));
|
|
5299
|
+
switch (hideBehavior) {
|
|
5300
|
+
case "after-dismissal":
|
|
5301
|
+
case "never":
|
|
5302
|
+
return false;
|
|
5303
|
+
case "if-in-viewport":
|
|
5304
|
+
return this.isInViewport;
|
|
5305
|
+
default:
|
|
5306
|
+
return true;
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
/**
|
|
5310
|
+
* Initializes and validates controller variables
|
|
5311
|
+
*/
|
|
5312
|
+
connect() {
|
|
5313
|
+
super.connect();
|
|
5314
|
+
this.validate();
|
|
5315
|
+
if (this.isVisible) {
|
|
5316
|
+
// just call initialize here, not show. This keeps already visible popovers from adding/firing document events
|
|
5317
|
+
this.initializePopper();
|
|
5318
|
+
}
|
|
5319
|
+
else if (this.data.get("auto-show") === "true") {
|
|
5320
|
+
this.show(null);
|
|
5321
|
+
}
|
|
5322
|
+
this.data.delete("auto-show");
|
|
5323
|
+
}
|
|
5324
|
+
/**
|
|
5325
|
+
* Cleans up popper.js elements and disconnects all added event listeners
|
|
5326
|
+
*/
|
|
5327
|
+
disconnect() {
|
|
5328
|
+
this.hide();
|
|
5329
|
+
if (this.popper) {
|
|
5330
|
+
this.popper.destroy();
|
|
5331
|
+
// eslint-disable-next-line
|
|
5332
|
+
// @ts-ignore The operand of a 'delete' operator must be optional .ts(2790)
|
|
5333
|
+
delete this.popper;
|
|
5334
|
+
}
|
|
5335
|
+
super.disconnect();
|
|
5336
|
+
}
|
|
5337
|
+
/**
|
|
5338
|
+
* Toggles the visibility of the popover
|
|
5339
|
+
*/
|
|
5340
|
+
toggle(dispatcher = null) {
|
|
5341
|
+
this.isVisible ? this.hide(dispatcher) : this.show(dispatcher);
|
|
5342
|
+
}
|
|
5343
|
+
/**
|
|
5344
|
+
* Shows the popover if not already visible
|
|
5345
|
+
*/
|
|
5346
|
+
show(dispatcher = null) {
|
|
5347
|
+
if (this.isVisible) {
|
|
5348
|
+
return;
|
|
5349
|
+
}
|
|
5350
|
+
const dispatcherElement = this.getDispatcher(dispatcher);
|
|
5351
|
+
if (this.triggerEvent("show", {
|
|
5352
|
+
dispatcher: dispatcherElement,
|
|
5353
|
+
}).defaultPrevented) {
|
|
5354
|
+
return;
|
|
5355
|
+
}
|
|
5356
|
+
if (!this.popper) {
|
|
5357
|
+
this.initializePopper();
|
|
5358
|
+
}
|
|
5359
|
+
this.popoverElement.classList.add("is-visible");
|
|
5360
|
+
// ensure the popper has been positioned correctly
|
|
5361
|
+
this.scheduleUpdate();
|
|
5362
|
+
this.shown(dispatcherElement);
|
|
5363
|
+
}
|
|
5364
|
+
/**
|
|
5365
|
+
* Hides the popover if not already hidden
|
|
5366
|
+
*/
|
|
5367
|
+
hide(dispatcher = null) {
|
|
5368
|
+
if (!this.isVisible) {
|
|
5369
|
+
return;
|
|
5370
|
+
}
|
|
5371
|
+
const dispatcherElement = this.getDispatcher(dispatcher);
|
|
5372
|
+
if (this.triggerEvent("hide", {
|
|
5373
|
+
dispatcher: dispatcherElement,
|
|
5374
|
+
}).defaultPrevented) {
|
|
5375
|
+
return;
|
|
5376
|
+
}
|
|
5377
|
+
this.popoverElement.classList.remove("is-visible");
|
|
5378
|
+
if (this.popper) {
|
|
5379
|
+
// completely destroy the popper on hide; this is in line with Popper.js's performance recommendations
|
|
5380
|
+
this.popper.destroy();
|
|
5381
|
+
// eslint-disable-next-line
|
|
5382
|
+
// @ts-ignore The operand of a 'delete' operator must be optional .ts(2790)
|
|
5383
|
+
delete this.popper;
|
|
5384
|
+
}
|
|
5385
|
+
// on first interaction, hide-on-outside-click with value "after-dismissal" reverts to the default behavior
|
|
5386
|
+
if (this.data.get("hide-on-outside-click") ===
|
|
5387
|
+
"after-dismissal") {
|
|
5388
|
+
this.data.delete("hide-on-outside-click");
|
|
5389
|
+
}
|
|
5390
|
+
this.hidden(dispatcherElement);
|
|
5391
|
+
}
|
|
5392
|
+
/**
|
|
5393
|
+
* Binds document events for this popover and fires the shown event
|
|
5394
|
+
*/
|
|
5395
|
+
shown(dispatcher = null) {
|
|
5396
|
+
this.bindDocumentEvents();
|
|
5397
|
+
this.triggerEvent("shown", {
|
|
5398
|
+
dispatcher: dispatcher,
|
|
5399
|
+
});
|
|
5400
|
+
}
|
|
5401
|
+
/**
|
|
5402
|
+
* Unbinds document events for this popover and fires the hidden event
|
|
5403
|
+
*/
|
|
5404
|
+
hidden(dispatcher = null) {
|
|
5405
|
+
this.unbindDocumentEvents();
|
|
5406
|
+
this.triggerEvent("hidden", {
|
|
5407
|
+
dispatcher: dispatcher,
|
|
5408
|
+
});
|
|
5409
|
+
}
|
|
5410
|
+
/**
|
|
5411
|
+
* Generates the popover if not found during initialization
|
|
5412
|
+
*/
|
|
5413
|
+
generatePopover() {
|
|
5414
|
+
return null;
|
|
5415
|
+
}
|
|
5416
|
+
/**
|
|
5417
|
+
* Initializes the Popper for this instance
|
|
5418
|
+
*/
|
|
5419
|
+
initializePopper() {
|
|
5420
|
+
this.popper = popper_createPopper(this.referenceElement, this.popoverElement, {
|
|
5421
|
+
placement: this.data.get("placement") || "bottom",
|
|
5422
|
+
modifiers: [
|
|
5423
|
+
{
|
|
5424
|
+
name: "offset",
|
|
5425
|
+
options: {
|
|
5426
|
+
offset: [0, 10], // The entire popover should be 10px away from the element
|
|
5427
|
+
},
|
|
5428
|
+
},
|
|
5429
|
+
{
|
|
5430
|
+
name: "arrow",
|
|
5431
|
+
options: {
|
|
5432
|
+
element: ".s-popover--arrow",
|
|
5433
|
+
},
|
|
5434
|
+
},
|
|
5435
|
+
],
|
|
5436
|
+
});
|
|
5437
|
+
}
|
|
5438
|
+
/**
|
|
5439
|
+
* Validates the popover settings and attempts to set necessary internal variables
|
|
5440
|
+
*/
|
|
5441
|
+
validate() {
|
|
5442
|
+
const referenceSelector = this.data.get("reference-selector");
|
|
5443
|
+
this.referenceElement = this.element;
|
|
5444
|
+
// if there is an alternative reference selector and that element exists, use it (and throw if it isn't found)
|
|
5445
|
+
if (referenceSelector) {
|
|
5446
|
+
this.referenceElement = (this.element.querySelector(referenceSelector));
|
|
5447
|
+
if (!this.referenceElement) {
|
|
5448
|
+
throw ("Unable to find element by reference selector: " +
|
|
5449
|
+
referenceSelector);
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5452
|
+
const popoverId = this.referenceElement.getAttribute(this.popoverSelectorAttribute);
|
|
5453
|
+
let popoverElement = null;
|
|
5454
|
+
// if the popover is named, attempt to fetch it (and throw an error if it doesn't exist)
|
|
5455
|
+
if (popoverId) {
|
|
5456
|
+
popoverElement = document.getElementById(popoverId);
|
|
5457
|
+
if (!popoverElement) {
|
|
5458
|
+
throw `[${this.popoverSelectorAttribute}="{POPOVER_ID}"] required`;
|
|
5459
|
+
}
|
|
5460
|
+
}
|
|
5461
|
+
// if the popover isn't named, attempt to generate it
|
|
5462
|
+
else {
|
|
5463
|
+
popoverElement = this.generatePopover();
|
|
5464
|
+
}
|
|
5465
|
+
if (!popoverElement) {
|
|
5466
|
+
throw "unable to find or generate popover element";
|
|
5467
|
+
}
|
|
5468
|
+
this.popoverElement = popoverElement;
|
|
5469
|
+
}
|
|
5470
|
+
/**
|
|
5471
|
+
* Determines the correct dispatching element from a potential input
|
|
5472
|
+
* @param dispatcher The event or element to get the dispatcher from
|
|
5473
|
+
*/
|
|
5474
|
+
getDispatcher(dispatcher = null) {
|
|
5475
|
+
if (dispatcher instanceof Event) {
|
|
5476
|
+
return dispatcher.target;
|
|
5477
|
+
}
|
|
5478
|
+
else if (dispatcher instanceof Element) {
|
|
5479
|
+
return dispatcher;
|
|
5480
|
+
}
|
|
5481
|
+
else {
|
|
5482
|
+
return this.element;
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
/**
|
|
5486
|
+
* Schedules the popover to update on the next animation frame if visible
|
|
5487
|
+
*/
|
|
5488
|
+
scheduleUpdate() {
|
|
5489
|
+
if (this.popper && this.isVisible) {
|
|
5490
|
+
void this.popper.update();
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
}
|
|
5494
|
+
class PopoverController extends BasePopoverController {
|
|
5495
|
+
constructor() {
|
|
5496
|
+
super(...arguments);
|
|
5497
|
+
this.popoverSelectorAttribute = "aria-controls";
|
|
5498
|
+
}
|
|
5499
|
+
/**
|
|
5500
|
+
* Toggles optional classes and accessibility attributes in addition to BasePopoverController.shown
|
|
5501
|
+
*/
|
|
5502
|
+
shown(dispatcher = null) {
|
|
5503
|
+
this.toggleOptionalClasses(true);
|
|
5504
|
+
this.toggleAccessibilityAttributes(true);
|
|
5505
|
+
super.shown(dispatcher);
|
|
5506
|
+
}
|
|
5507
|
+
/**
|
|
5508
|
+
* Toggles optional classes and accessibility attributes in addition to BasePopoverController.hidden
|
|
5509
|
+
*/
|
|
5510
|
+
hidden(dispatcher = null) {
|
|
5511
|
+
this.toggleOptionalClasses(false);
|
|
5512
|
+
this.toggleAccessibilityAttributes(false);
|
|
5513
|
+
super.hidden(dispatcher);
|
|
5514
|
+
}
|
|
5515
|
+
/**
|
|
5516
|
+
* Initializes accessibility attributes in addition to BasePopoverController.connect
|
|
5517
|
+
*/
|
|
5518
|
+
connect() {
|
|
5519
|
+
super.connect();
|
|
5520
|
+
this.toggleAccessibilityAttributes();
|
|
5521
|
+
}
|
|
5522
|
+
/**
|
|
5523
|
+
* Binds global events to the document for hiding popovers on user interaction
|
|
5524
|
+
*/
|
|
5525
|
+
bindDocumentEvents() {
|
|
5526
|
+
this.boundHideOnOutsideClick =
|
|
5527
|
+
this.boundHideOnOutsideClick || this.hideOnOutsideClick.bind(this);
|
|
5528
|
+
this.boundHideOnEscapePress =
|
|
5529
|
+
this.boundHideOnEscapePress || this.hideOnEscapePress.bind(this);
|
|
5530
|
+
document.addEventListener("mousedown", this.boundHideOnOutsideClick);
|
|
5531
|
+
document.addEventListener("keyup", this.boundHideOnEscapePress);
|
|
5532
|
+
}
|
|
5533
|
+
/**
|
|
5534
|
+
* Unbinds global events to the document for hiding popovers on user interaction
|
|
5535
|
+
*/
|
|
5536
|
+
unbindDocumentEvents() {
|
|
5537
|
+
document.removeEventListener("mousedown", this.boundHideOnOutsideClick);
|
|
5538
|
+
document.removeEventListener("keyup", this.boundHideOnEscapePress);
|
|
5539
|
+
}
|
|
5540
|
+
/**
|
|
5541
|
+
* Forces the popover to hide if a user clicks outside of it or its reference element
|
|
5542
|
+
* @param {Event} e - The document click event
|
|
5543
|
+
*/
|
|
5544
|
+
hideOnOutsideClick(e) {
|
|
5545
|
+
const target = e.target;
|
|
5546
|
+
// check if the document was clicked inside either the reference element or the popover itself
|
|
5547
|
+
// note: .contains also returns true if the node itself matches the target element
|
|
5548
|
+
if (this.shouldHideOnOutsideClick &&
|
|
5549
|
+
!this.referenceElement.contains(target) &&
|
|
5550
|
+
!this.popoverElement.contains(target) &&
|
|
5551
|
+
document.body.contains(target)) {
|
|
5552
|
+
this.hide(e);
|
|
5553
|
+
}
|
|
5554
|
+
}
|
|
5555
|
+
/**
|
|
5556
|
+
* Forces the popover to hide if the user presses escape while it, one of its childen, or the reference element are focused
|
|
5557
|
+
* @param {Event} e - The document keyup event
|
|
5558
|
+
*/
|
|
5559
|
+
hideOnEscapePress(e) {
|
|
5560
|
+
// if the ESC key (27) wasn't pressed or if no popovers are showing, return
|
|
5561
|
+
if (e.which !== 27 || !this.isVisible) {
|
|
5562
|
+
return;
|
|
5563
|
+
}
|
|
5564
|
+
// check if the target was inside the popover element and refocus the triggering element
|
|
5565
|
+
// note: .contains also returns true if the node itself matches the target element
|
|
5566
|
+
if (this.popoverElement.contains(e.target)) {
|
|
5567
|
+
this.referenceElement.focus();
|
|
5568
|
+
}
|
|
5569
|
+
this.hide(e);
|
|
5570
|
+
}
|
|
5571
|
+
/**
|
|
5572
|
+
* Toggles all classes on the originating element based on the `class-toggle` data
|
|
5573
|
+
* @param {boolean=} show - A boolean indicating whether this is being triggered by a show or hide.
|
|
5574
|
+
*/
|
|
5575
|
+
toggleOptionalClasses(show) {
|
|
5576
|
+
if (!this.data.has("toggle-class")) {
|
|
5577
|
+
return;
|
|
5578
|
+
}
|
|
5579
|
+
const toggleClass = this.data.get("toggle-class") || "";
|
|
5580
|
+
const cl = this.referenceElement.classList;
|
|
5581
|
+
toggleClass.split(/\s+/).forEach(function (cls) {
|
|
5582
|
+
cl.toggle(cls, show);
|
|
5583
|
+
});
|
|
5584
|
+
}
|
|
5585
|
+
/**
|
|
5586
|
+
* Toggles accessibility attributes based on whether the popover is shown or not
|
|
5587
|
+
* @param {boolean=} show - A boolean indicating whether this is being triggered by a show or hide.
|
|
5588
|
+
*/
|
|
5589
|
+
toggleAccessibilityAttributes(show) {
|
|
5590
|
+
const expandedValue = (show === null || show === void 0 ? void 0 : show.toString()) || this.referenceElement.ariaExpanded || "false";
|
|
5591
|
+
this.referenceElement.ariaExpanded = expandedValue;
|
|
5592
|
+
this.referenceElement.setAttribute("aria-expanded", expandedValue);
|
|
5593
|
+
}
|
|
5594
|
+
}
|
|
5595
|
+
PopoverController.targets = [];
|
|
5596
|
+
|
|
5597
|
+
/**
|
|
5598
|
+
* Helper to manually show an s-popover element via external JS
|
|
5599
|
+
* @param element the element the `data-controller="s-popover"` attribute is on
|
|
5600
|
+
*/
|
|
5601
|
+
function showPopover(element) {
|
|
5602
|
+
const { isPopover, controller } = getPopover(element);
|
|
5603
|
+
if (controller) {
|
|
5604
|
+
controller.show();
|
|
5605
|
+
}
|
|
5606
|
+
else if (isPopover) {
|
|
5607
|
+
element.setAttribute("data-s-popover-auto-show", "true");
|
|
5608
|
+
}
|
|
5609
|
+
else {
|
|
5610
|
+
throw `element does not have data-controller="s-popover"`;
|
|
5611
|
+
}
|
|
5612
|
+
}
|
|
5613
|
+
/**
|
|
5614
|
+
* Helper to manually hide an s-popover element via external JS
|
|
5615
|
+
* @param element the element the `data-controller="s-popover"` attribute is on
|
|
5616
|
+
*/
|
|
5617
|
+
function hidePopover(element) {
|
|
5618
|
+
const { isPopover, controller, popover } = getPopover(element);
|
|
5619
|
+
if (controller) {
|
|
5620
|
+
controller.hide();
|
|
5621
|
+
}
|
|
5622
|
+
else if (isPopover) {
|
|
5623
|
+
element.removeAttribute("data-s-popover-auto-show");
|
|
5624
|
+
if (popover) {
|
|
5625
|
+
popover.classList.remove("is-visible");
|
|
5626
|
+
}
|
|
5627
|
+
}
|
|
5628
|
+
else {
|
|
5629
|
+
throw `element does not have data-controller="s-popover"`;
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
/**
|
|
5633
|
+
* Attaches a popover to an element and performs additional configuration.
|
|
5634
|
+
* @param element the element that will receive the `data-controller="s-popover"` attribute.
|
|
5635
|
+
* @param popover an element with the `.s-popover` class or HTML string containing a single element with the `.s-popover` class.
|
|
5636
|
+
* If the popover does not have a parent element, it will be inserted as a immediately after the reference element.
|
|
5637
|
+
* @param options an optional collection of options to use when configuring the popover.
|
|
5638
|
+
*/
|
|
5639
|
+
function attachPopover(element, popover, options) {
|
|
5640
|
+
const { referenceElement, popover: existingPopover } = getPopover(element);
|
|
5641
|
+
if (existingPopover) {
|
|
5642
|
+
throw `element already has popover with id="${existingPopover.id}"`;
|
|
5643
|
+
}
|
|
5644
|
+
if (!referenceElement) {
|
|
5645
|
+
throw `element has invalid data-s-popover-reference-selector attribute`;
|
|
5646
|
+
}
|
|
5647
|
+
if (typeof popover === "string") {
|
|
5648
|
+
// eslint-disable-next-line no-unsanitized/method
|
|
5649
|
+
const elements = document
|
|
5650
|
+
.createRange()
|
|
5651
|
+
.createContextualFragment(popover).children;
|
|
5652
|
+
if (elements.length !== 1) {
|
|
5653
|
+
throw "popover should contain a single element";
|
|
5654
|
+
}
|
|
5655
|
+
popover = elements[0];
|
|
5656
|
+
}
|
|
5657
|
+
const existingId = referenceElement.getAttribute("aria-controls");
|
|
5658
|
+
let popoverId = popover.id;
|
|
5659
|
+
if (!popover.classList.contains("s-popover")) {
|
|
5660
|
+
throw `popover should have the "s-popover" class but had class="${popover.className}"`;
|
|
5661
|
+
}
|
|
5662
|
+
if (existingId && existingId !== popoverId) {
|
|
5663
|
+
throw `element has aria-controls="${existingId}" but popover has id="${popoverId}"`;
|
|
5664
|
+
}
|
|
5665
|
+
if (!popoverId) {
|
|
5666
|
+
popoverId =
|
|
5667
|
+
"--stacks-s-popover-" + Math.random().toString(36).substring(2, 10);
|
|
5668
|
+
popover.id = popoverId;
|
|
5669
|
+
}
|
|
5670
|
+
if (!existingId) {
|
|
5671
|
+
referenceElement.setAttribute("aria-controls", popoverId);
|
|
5672
|
+
}
|
|
5673
|
+
if (!popover.parentElement && element.parentElement) {
|
|
5674
|
+
referenceElement.insertAdjacentElement("afterend", popover);
|
|
5675
|
+
}
|
|
5676
|
+
toggleController(element, "s-popover", true);
|
|
5677
|
+
if (options) {
|
|
5678
|
+
if (options.toggleOnClick) {
|
|
5679
|
+
referenceElement.setAttribute("data-action", "click->s-popover#toggle");
|
|
5680
|
+
}
|
|
5681
|
+
if (options.placement) {
|
|
5682
|
+
element.setAttribute("data-s-popover-placement", options.placement);
|
|
5683
|
+
}
|
|
5684
|
+
if (options.autoShow) {
|
|
5685
|
+
element.setAttribute("data-s-popover-auto-show", "true");
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
/**
|
|
5690
|
+
* Removes the popover controller from an element and removes the popover from the DOM.
|
|
5691
|
+
* @param element the element that has the `data-controller="s-popover"` attribute.
|
|
5692
|
+
* @returns The popover that was attached to the element.
|
|
5693
|
+
*/
|
|
5694
|
+
function detachPopover(element) {
|
|
5695
|
+
const { isPopover, controller, referenceElement, popover } = getPopover(element);
|
|
5696
|
+
// Hide the popover so its events fire.
|
|
5697
|
+
controller === null || controller === void 0 ? void 0 : controller.hide();
|
|
5698
|
+
// Remove the popover if it exists
|
|
5699
|
+
popover === null || popover === void 0 ? void 0 : popover.remove();
|
|
5700
|
+
// Remove the popover controller and the aria-controls attributes.
|
|
5701
|
+
if (isPopover) {
|
|
5702
|
+
toggleController(element, "s-popover", false);
|
|
5703
|
+
if (referenceElement) {
|
|
5704
|
+
referenceElement.removeAttribute("aria-controls");
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5707
|
+
return popover;
|
|
5708
|
+
}
|
|
5709
|
+
/**
|
|
5710
|
+
* Gets the current state of an element that may be or is intended to be an s-popover controller
|
|
5711
|
+
* so it can be configured either directly or via the DOM.
|
|
5712
|
+
* @param element An element that may have `data-controller="s-popover"`.
|
|
5713
|
+
*/
|
|
5714
|
+
function getPopover(element) {
|
|
5715
|
+
var _a;
|
|
5716
|
+
const isPopover = ((_a = element.getAttribute("data-controller")) === null || _a === void 0 ? void 0 : _a.includes("s-popover")) || false;
|
|
5717
|
+
const controller = application.getControllerForElementAndIdentifier(element, "s-popover");
|
|
5718
|
+
const referenceSelector = element.getAttribute("data-s-popover-reference-selector");
|
|
5719
|
+
const referenceElement = referenceSelector
|
|
5720
|
+
? element.querySelector(referenceSelector)
|
|
5721
|
+
: element;
|
|
5722
|
+
const popoverId = referenceElement
|
|
5723
|
+
? referenceElement.getAttribute("aria-controls")
|
|
5724
|
+
: null;
|
|
5725
|
+
const popover = popoverId ? document.getElementById(popoverId) : null;
|
|
5726
|
+
return { isPopover, controller, referenceElement, popover };
|
|
5727
|
+
}
|
|
5728
|
+
/**
|
|
5729
|
+
* Adds or removes the controller from an element's [data-controller] attribute without altering existing entries
|
|
5730
|
+
* @param el The element to alter
|
|
5731
|
+
* @param controllerName The name of the controller to add/remove
|
|
5732
|
+
* @param include Whether to add the controllerName value
|
|
5733
|
+
*/
|
|
5734
|
+
function toggleController(el, controllerName, include) {
|
|
5735
|
+
var _a;
|
|
5736
|
+
const controllers = new Set((_a = el.getAttribute("data-controller")) === null || _a === void 0 ? void 0 : _a.split(/\s+/));
|
|
5737
|
+
if (include) {
|
|
5738
|
+
controllers.add(controllerName);
|
|
5739
|
+
}
|
|
5740
|
+
else {
|
|
5741
|
+
controllers.delete(controllerName);
|
|
5742
|
+
}
|
|
5743
|
+
el.setAttribute("data-controller", Array.from(controllers).join(" "));
|
|
5463
5744
|
}
|
|
5464
5745
|
|
|
5465
|
-
|
|
5466
|
-
var state = _ref.state,
|
|
5467
|
-
name = _ref.name;
|
|
5468
|
-
var referenceRect = state.rects.reference;
|
|
5469
|
-
var popperRect = state.rects.popper;
|
|
5470
|
-
var preventedOffsets = state.modifiersData.preventOverflow;
|
|
5471
|
-
var referenceOverflow = detectOverflow(state, {
|
|
5472
|
-
elementContext: 'reference'
|
|
5473
|
-
});
|
|
5474
|
-
var popperAltOverflow = detectOverflow(state, {
|
|
5475
|
-
altBoundary: true
|
|
5476
|
-
});
|
|
5477
|
-
var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
|
|
5478
|
-
var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
|
|
5479
|
-
var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
|
|
5480
|
-
var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
|
|
5481
|
-
state.modifiersData[name] = {
|
|
5482
|
-
referenceClippingOffsets: referenceClippingOffsets,
|
|
5483
|
-
popperEscapeOffsets: popperEscapeOffsets,
|
|
5484
|
-
isReferenceHidden: isReferenceHidden,
|
|
5485
|
-
hasPopperEscaped: hasPopperEscaped
|
|
5486
|
-
};
|
|
5487
|
-
state.attributes.popper = Object.assign({}, state.attributes.popper, {
|
|
5488
|
-
'data-popper-reference-hidden': isReferenceHidden,
|
|
5489
|
-
'data-popper-escaped': hasPopperEscaped
|
|
5490
|
-
});
|
|
5491
|
-
} // eslint-disable-next-line import/no-unused-modules
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
/* harmony default export */ const modifiers_hide = ({
|
|
5495
|
-
name: 'hide',
|
|
5496
|
-
enabled: true,
|
|
5497
|
-
phase: 'main',
|
|
5498
|
-
requiresIfExists: ['preventOverflow'],
|
|
5499
|
-
fn: hide
|
|
5500
|
-
});
|
|
5501
|
-
;// CONCATENATED MODULE: ./node_modules/@popperjs/core/lib/popper.js
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
var defaultModifiers = [eventListeners, modifiers_popperOffsets, modifiers_computeStyles, modifiers_applyStyles, modifiers_offset, modifiers_flip, modifiers_preventOverflow, modifiers_arrow, modifiers_hide];
|
|
5513
|
-
var popper_createPopper = /*#__PURE__*/popperGenerator({
|
|
5514
|
-
defaultModifiers: defaultModifiers
|
|
5515
|
-
}); // eslint-disable-next-line import/no-unused-modules
|
|
5516
|
-
|
|
5517
|
-
// eslint-disable-next-line import/no-unused-modules
|
|
5518
|
-
|
|
5519
|
-
// eslint-disable-next-line import/no-unused-modules
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
;// CONCATENATED MODULE: ./lib/ts/controllers/s-popover.ts
|
|
5523
|
-
|
|
5746
|
+
;// CONCATENATED MODULE: ./lib/components/table/table.ts
|
|
5524
5747
|
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5748
|
+
/**
|
|
5749
|
+
* The string values of these enumerations should correspond with `aria-sort` valid values.
|
|
5750
|
+
*
|
|
5751
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-sort#values
|
|
5752
|
+
*/
|
|
5753
|
+
var SortOrder;
|
|
5754
|
+
(function (SortOrder) {
|
|
5755
|
+
SortOrder["Ascending"] = "ascending";
|
|
5756
|
+
SortOrder["Descending"] = "descending";
|
|
5757
|
+
SortOrder["None"] = "none";
|
|
5758
|
+
})(SortOrder || (SortOrder = {}));
|
|
5759
|
+
class TableController extends StacksController {
|
|
5760
|
+
constructor() {
|
|
5761
|
+
super(...arguments);
|
|
5762
|
+
this.updateSortedColumnStyles = (targetColumnHeader, direction) => {
|
|
5763
|
+
// Loop through all sortable columns and remove their sorting direction
|
|
5764
|
+
// (if any), and only leave/set a sorting on `targetColumnHeader`.
|
|
5765
|
+
this.columnTargets.forEach((header) => {
|
|
5766
|
+
const isCurrent = header === targetColumnHeader;
|
|
5767
|
+
const classSuffix = isCurrent
|
|
5768
|
+
? direction === SortOrder.Ascending
|
|
5769
|
+
? "asc"
|
|
5770
|
+
: "desc"
|
|
5771
|
+
: SortOrder.None;
|
|
5772
|
+
header.classList.toggle("is-sorted", isCurrent && direction !== SortOrder.None);
|
|
5773
|
+
header.querySelectorAll(".js-sorting-indicator").forEach((icon) => {
|
|
5774
|
+
icon.classList.toggle("d-none", !icon.classList.contains("js-sorting-indicator-" + classSuffix));
|
|
5775
|
+
});
|
|
5776
|
+
if (isCurrent) {
|
|
5777
|
+
header.setAttribute("aria-sort", direction);
|
|
5778
|
+
}
|
|
5779
|
+
else {
|
|
5780
|
+
header.removeAttribute("aria-sort");
|
|
5781
|
+
}
|
|
5782
|
+
});
|
|
5783
|
+
};
|
|
5534
5784
|
}
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5785
|
+
sort(evt) {
|
|
5786
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
5787
|
+
const controller = this;
|
|
5788
|
+
const sortTriggerEl = evt.currentTarget;
|
|
5789
|
+
// TODO: support *only* button as trigger in next major release
|
|
5790
|
+
const triggerIsButton = sortTriggerEl instanceof HTMLButtonElement;
|
|
5791
|
+
// the below conditional is here for backward compatibility with the old API
|
|
5792
|
+
// where we did not advise buttons as sortable column head triggers
|
|
5793
|
+
const colHead = (triggerIsButton ? sortTriggerEl.parentElement : sortTriggerEl);
|
|
5794
|
+
const table = this.element;
|
|
5795
|
+
const tbody = table.tBodies[0];
|
|
5796
|
+
// the column slot number of the clicked header
|
|
5797
|
+
const colno = getCellSlot(colHead);
|
|
5798
|
+
if (colno < 0) {
|
|
5799
|
+
// this shouldn't happen if the clicked element is actually a column head
|
|
5800
|
+
return;
|
|
5542
5801
|
}
|
|
5543
|
-
//
|
|
5544
|
-
//
|
|
5545
|
-
const
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5802
|
+
// an index of the <tbody>, so we can find out for each row which <td> element is
|
|
5803
|
+
// in the same column slot as the header
|
|
5804
|
+
const slotIndex = buildIndex(tbody);
|
|
5805
|
+
// the default behavior when clicking a header is to sort by this column in ascending
|
|
5806
|
+
// direction, *unless* it is already sorted that way
|
|
5807
|
+
const direction = colHead.getAttribute("aria-sort") === SortOrder.Ascending ? -1 : 1;
|
|
5808
|
+
const rows = Array.from(table.tBodies[0].rows);
|
|
5809
|
+
// if this is still false after traversing the data, that means all values are integers (or empty)
|
|
5810
|
+
// and thus we'll sort numerically.
|
|
5811
|
+
let anyNonInt = false;
|
|
5812
|
+
// data will be a list of tuples [value, rowNum], where value is what we're sorting by
|
|
5813
|
+
const data = [];
|
|
5814
|
+
let firstBottomRow;
|
|
5815
|
+
rows.forEach(function (row, index) {
|
|
5816
|
+
var _a, _b;
|
|
5817
|
+
const force = controller.getElementData(row, "sort-to");
|
|
5818
|
+
if (force === "top") {
|
|
5819
|
+
return; // rows not added to the list will automatically end up at the top
|
|
5820
|
+
}
|
|
5821
|
+
else if (force === "bottom") {
|
|
5822
|
+
if (!firstBottomRow) {
|
|
5823
|
+
firstBottomRow = row;
|
|
5824
|
+
}
|
|
5825
|
+
return;
|
|
5826
|
+
}
|
|
5827
|
+
const cell = slotIndex[index][colno];
|
|
5828
|
+
if (!cell) {
|
|
5829
|
+
data.push(["", index]);
|
|
5830
|
+
return;
|
|
5831
|
+
}
|
|
5832
|
+
// unless the to-be-sorted-by value is explicitly provided on the element via this attribute,
|
|
5833
|
+
// the value we're using is the cell's text, trimmed of any whitespace
|
|
5834
|
+
const explicit = controller.getElementData(cell, "sort-val");
|
|
5835
|
+
const d = (_b = explicit !== null && explicit !== void 0 ? explicit : (_a = cell.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : "";
|
|
5836
|
+
if (d !== "" && `${parseInt(d, 10)}` !== d) {
|
|
5837
|
+
anyNonInt = true;
|
|
5838
|
+
}
|
|
5839
|
+
data.push([d, index]);
|
|
5840
|
+
});
|
|
5841
|
+
// If all values were integers (or empty cells), sort numerically, with empty cells treated as
|
|
5842
|
+
// having the lowest possible value (i.e. sorted to the top if ascending, bottom if descending)
|
|
5843
|
+
if (!anyNonInt) {
|
|
5844
|
+
data.forEach(function (tuple) {
|
|
5845
|
+
tuple[0] =
|
|
5846
|
+
tuple[0] === ""
|
|
5847
|
+
? Number.MIN_VALUE
|
|
5848
|
+
: parseInt(tuple[0], 10);
|
|
5849
|
+
});
|
|
5850
|
+
}
|
|
5851
|
+
// We don't sort an array of <tr>, but instead an arrays of row *numbers*, because this way we
|
|
5852
|
+
// can enforce stable sorting, i.e. rows that compare equal are guaranteed to remain in the same
|
|
5853
|
+
// order (the JS standard does not gurantee this for sort()).
|
|
5854
|
+
data.sort(function (a, b) {
|
|
5855
|
+
// first compare the values (a[0])
|
|
5856
|
+
if (a[0] > b[0]) {
|
|
5857
|
+
return 1 * direction;
|
|
5858
|
+
}
|
|
5859
|
+
else if (a[0] < b[0]) {
|
|
5860
|
+
return -1 * direction;
|
|
5861
|
+
}
|
|
5862
|
+
else {
|
|
5863
|
+
// if the values are equal, compare the row numbers (a[1]) to guarantee stable sorting
|
|
5864
|
+
// (note that this comparison is independent of the sorting direction)
|
|
5865
|
+
return a[1] > b[1] ? 1 : -1;
|
|
5866
|
+
}
|
|
5867
|
+
});
|
|
5868
|
+
// this is the actual reordering of the table rows
|
|
5869
|
+
data.forEach(([_, rowIndex]) => {
|
|
5870
|
+
var _a;
|
|
5871
|
+
const row = rows[rowIndex];
|
|
5872
|
+
(_a = row.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(row);
|
|
5873
|
+
if (firstBottomRow) {
|
|
5874
|
+
tbody.insertBefore(row, firstBottomRow);
|
|
5875
|
+
}
|
|
5876
|
+
else {
|
|
5877
|
+
tbody.appendChild(row);
|
|
5878
|
+
}
|
|
5879
|
+
});
|
|
5880
|
+
// update the UI and set the `data-sort-direction` attribute if appropriate, so that the next click
|
|
5881
|
+
// will cause sorting in descending direction
|
|
5882
|
+
this.updateSortedColumnStyles(colHead, direction === 1 ? SortOrder.Ascending : SortOrder.Descending);
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
TableController.targets = ["column"];
|
|
5886
|
+
|
|
5887
|
+
/**
|
|
5888
|
+
* @internal This function is exported for testing purposes but is not a part of our public API
|
|
5889
|
+
*
|
|
5890
|
+
* @param section
|
|
5891
|
+
*/
|
|
5892
|
+
function buildIndex(section) {
|
|
5893
|
+
const result = buildIndexOrGetCellSlot(section);
|
|
5894
|
+
if (!Array.isArray(result)) {
|
|
5895
|
+
throw "shouldn't happen";
|
|
5552
5896
|
}
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5897
|
+
return result;
|
|
5898
|
+
}
|
|
5899
|
+
/**
|
|
5900
|
+
* @internal This function is exported for testing purposes but is not a part of our public API
|
|
5901
|
+
*
|
|
5902
|
+
* @param cell
|
|
5903
|
+
*/
|
|
5904
|
+
function getCellSlot(cell) {
|
|
5905
|
+
var _a;
|
|
5906
|
+
const tableElement = (_a = cell.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement;
|
|
5907
|
+
if (!(tableElement instanceof HTMLTableSectionElement)) {
|
|
5908
|
+
throw "invalid table";
|
|
5909
|
+
}
|
|
5910
|
+
const result = buildIndexOrGetCellSlot(tableElement, cell);
|
|
5911
|
+
if (typeof result !== "number") {
|
|
5912
|
+
throw "shouldn't happen";
|
|
5913
|
+
}
|
|
5914
|
+
return result;
|
|
5915
|
+
}
|
|
5916
|
+
/**
|
|
5917
|
+
* Just because a <td> is the 4th *child* of its <tr> doesn't mean it belongs to the 4th *column*
|
|
5918
|
+
* of the table. Previous cells may have a colspan; cells in previous rows may have a rowspan.
|
|
5919
|
+
* Because we need to know which header cells and data cells belong together, we have to 1) find out
|
|
5920
|
+
* which column number (or "slot" as we call it here) the header cell has, and 2) for each row find
|
|
5921
|
+
* out which <td> cell corresponds to this slot (because those are the rows we're sorting by).
|
|
5922
|
+
*
|
|
5923
|
+
* That's what the following function does. If the second argument is not given, it returns an index
|
|
5924
|
+
* of the table, which is an array of arrays. Each of the sub-arrays corresponds to a table row. The
|
|
5925
|
+
* indices of the sub-array correspond to column slots; the values are the actual table cell elements.
|
|
5926
|
+
* For example index[4][3] is the <td> or <th> in row 4, column 3 of the table section (<tbody> or <thead>).
|
|
5927
|
+
* Note that this element is not necessarily even in the 4th (zero-based) <tr> -- if it has a rowSpan > 1,
|
|
5928
|
+
* it may also be in a previous <tr>.
|
|
5929
|
+
*
|
|
5930
|
+
* If the second argument is given, it's a <td> or <th> that we're trying to find, and the algorithm
|
|
5931
|
+
* stops as soon as it has found it and the function returns its slot number.
|
|
5932
|
+
*/
|
|
5933
|
+
function buildIndexOrGetCellSlot(section, findCell) {
|
|
5934
|
+
const index = [];
|
|
5935
|
+
let curRow = section.children[0];
|
|
5936
|
+
// the elements of these two arrays are synchronized; the first array contains table cell elements,
|
|
5937
|
+
// the second one contains a number that indicates for how many more rows this elements will
|
|
5938
|
+
// exist (i.e. the value is initially one less than the cell's rowspan, and will be decreased for each row)
|
|
5939
|
+
const growing = [];
|
|
5940
|
+
const growingRowsLeft = [];
|
|
5941
|
+
// continue while we have actual <tr>'s left *or* we still have rowspan'ed elements that aren't done
|
|
5942
|
+
while (curRow || growingRowsLeft.some((e) => e !== 0)) {
|
|
5943
|
+
const curIndexRow = [];
|
|
5944
|
+
index.push(curIndexRow);
|
|
5945
|
+
let curSlot = 0;
|
|
5946
|
+
if (curRow) {
|
|
5947
|
+
for (let curCellIdx = 0; curCellIdx < curRow.children.length; curCellIdx++) {
|
|
5948
|
+
while (growingRowsLeft[curSlot]) {
|
|
5949
|
+
growingRowsLeft[curSlot]--;
|
|
5950
|
+
curIndexRow[curSlot] = growing[curSlot];
|
|
5951
|
+
curSlot++;
|
|
5952
|
+
}
|
|
5953
|
+
const cell = curRow.children[curCellIdx];
|
|
5954
|
+
if (!(cell instanceof HTMLTableCellElement)) {
|
|
5955
|
+
throw "invalid table";
|
|
5956
|
+
}
|
|
5957
|
+
if (getComputedStyle(cell).display === "none") {
|
|
5958
|
+
continue;
|
|
5959
|
+
}
|
|
5960
|
+
if (cell === findCell) {
|
|
5961
|
+
return curSlot;
|
|
5962
|
+
}
|
|
5963
|
+
const nextFreeSlot = curSlot + cell.colSpan;
|
|
5964
|
+
for (; curSlot < nextFreeSlot; curSlot++) {
|
|
5965
|
+
growingRowsLeft[curSlot] = cell.rowSpan - 1; // if any of these is already growing, the table is broken -- no guarantees of anything
|
|
5966
|
+
growing[curSlot] = cell;
|
|
5967
|
+
curIndexRow[curSlot] = cell;
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
5971
|
+
while (curSlot < growing.length) {
|
|
5972
|
+
if (growingRowsLeft[curSlot]) {
|
|
5973
|
+
growingRowsLeft[curSlot]--;
|
|
5974
|
+
curIndexRow[curSlot] = growing[curSlot];
|
|
5975
|
+
}
|
|
5976
|
+
curSlot++;
|
|
5977
|
+
}
|
|
5978
|
+
if (curRow) {
|
|
5979
|
+
curRow = curRow.nextElementSibling;
|
|
5563
5980
|
}
|
|
5564
5981
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5982
|
+
// if findCell was given, but we end up here, that means it isn't in this section
|
|
5983
|
+
return findCell ? -1 : index;
|
|
5984
|
+
}
|
|
5985
|
+
|
|
5986
|
+
;// CONCATENATED MODULE: ./lib/components/toast/toast.ts
|
|
5987
|
+
|
|
5988
|
+
class ToastController extends StacksController {
|
|
5568
5989
|
connect() {
|
|
5569
|
-
super.connect();
|
|
5570
5990
|
this.validate();
|
|
5571
|
-
if (this.isVisible) {
|
|
5572
|
-
// just call initialize here, not show. This keeps already visible popovers from adding/firing document events
|
|
5573
|
-
this.initializePopper();
|
|
5574
|
-
}
|
|
5575
|
-
else if (this.data.get("auto-show") === "true") {
|
|
5576
|
-
this.show(null);
|
|
5577
|
-
}
|
|
5578
|
-
this.data.delete("auto-show");
|
|
5579
5991
|
}
|
|
5580
5992
|
/**
|
|
5581
|
-
*
|
|
5993
|
+
* Disconnects all added event listeners on controller disconnect
|
|
5582
5994
|
*/
|
|
5583
5995
|
disconnect() {
|
|
5584
|
-
this.
|
|
5585
|
-
if (this.popper) {
|
|
5586
|
-
this.popper.destroy();
|
|
5587
|
-
// eslint-disable-next-line
|
|
5588
|
-
// @ts-ignore The operand of a 'delete' operator must be optional .ts(2790)
|
|
5589
|
-
delete this.popper;
|
|
5590
|
-
}
|
|
5591
|
-
super.disconnect();
|
|
5996
|
+
this.unbindDocumentEvents();
|
|
5592
5997
|
}
|
|
5593
5998
|
/**
|
|
5594
|
-
* Toggles the visibility of the
|
|
5999
|
+
* Toggles the visibility of the toast
|
|
5595
6000
|
*/
|
|
5596
6001
|
toggle(dispatcher = null) {
|
|
5597
|
-
this.
|
|
6002
|
+
this._toggle(undefined, dispatcher);
|
|
5598
6003
|
}
|
|
5599
6004
|
/**
|
|
5600
|
-
* Shows the
|
|
6005
|
+
* Shows the toast
|
|
5601
6006
|
*/
|
|
5602
6007
|
show(dispatcher = null) {
|
|
5603
|
-
|
|
5604
|
-
return;
|
|
5605
|
-
}
|
|
5606
|
-
const dispatcherElement = this.getDispatcher(dispatcher);
|
|
5607
|
-
if (this.triggerEvent("show", {
|
|
5608
|
-
dispatcher: dispatcherElement,
|
|
5609
|
-
}).defaultPrevented) {
|
|
5610
|
-
return;
|
|
5611
|
-
}
|
|
5612
|
-
if (!this.popper) {
|
|
5613
|
-
this.initializePopper();
|
|
5614
|
-
}
|
|
5615
|
-
this.popoverElement.classList.add("is-visible");
|
|
5616
|
-
// ensure the popper has been positioned correctly
|
|
5617
|
-
this.scheduleUpdate();
|
|
5618
|
-
this.shown(dispatcherElement);
|
|
6008
|
+
this._toggle(true, dispatcher);
|
|
5619
6009
|
}
|
|
5620
6010
|
/**
|
|
5621
|
-
* Hides the
|
|
6011
|
+
* Hides the toast
|
|
5622
6012
|
*/
|
|
5623
6013
|
hide(dispatcher = null) {
|
|
5624
|
-
|
|
5625
|
-
return;
|
|
5626
|
-
}
|
|
5627
|
-
const dispatcherElement = this.getDispatcher(dispatcher);
|
|
5628
|
-
if (this.triggerEvent("hide", {
|
|
5629
|
-
dispatcher: dispatcherElement,
|
|
5630
|
-
}).defaultPrevented) {
|
|
5631
|
-
return;
|
|
5632
|
-
}
|
|
5633
|
-
this.popoverElement.classList.remove("is-visible");
|
|
5634
|
-
if (this.popper) {
|
|
5635
|
-
// completely destroy the popper on hide; this is in line with Popper.js's performance recommendations
|
|
5636
|
-
this.popper.destroy();
|
|
5637
|
-
// eslint-disable-next-line
|
|
5638
|
-
// @ts-ignore The operand of a 'delete' operator must be optional .ts(2790)
|
|
5639
|
-
delete this.popper;
|
|
5640
|
-
}
|
|
5641
|
-
// on first interaction, hide-on-outside-click with value "after-dismissal" reverts to the default behavior
|
|
5642
|
-
if (this.data.get("hide-on-outside-click") ===
|
|
5643
|
-
"after-dismissal") {
|
|
5644
|
-
this.data.delete("hide-on-outside-click");
|
|
5645
|
-
}
|
|
5646
|
-
this.hidden(dispatcherElement);
|
|
5647
|
-
}
|
|
5648
|
-
/**
|
|
5649
|
-
* Binds document events for this popover and fires the shown event
|
|
5650
|
-
*/
|
|
5651
|
-
shown(dispatcher = null) {
|
|
5652
|
-
this.bindDocumentEvents();
|
|
5653
|
-
this.triggerEvent("shown", {
|
|
5654
|
-
dispatcher: dispatcher,
|
|
5655
|
-
});
|
|
5656
|
-
}
|
|
5657
|
-
/**
|
|
5658
|
-
* Unbinds document events for this popover and fires the hidden event
|
|
5659
|
-
*/
|
|
5660
|
-
hidden(dispatcher = null) {
|
|
5661
|
-
this.unbindDocumentEvents();
|
|
5662
|
-
this.triggerEvent("hidden", {
|
|
5663
|
-
dispatcher: dispatcher,
|
|
5664
|
-
});
|
|
5665
|
-
}
|
|
5666
|
-
/**
|
|
5667
|
-
* Generates the popover if not found during initialization
|
|
5668
|
-
*/
|
|
5669
|
-
generatePopover() {
|
|
5670
|
-
return null;
|
|
6014
|
+
this._toggle(false, dispatcher);
|
|
5671
6015
|
}
|
|
5672
6016
|
/**
|
|
5673
|
-
*
|
|
6017
|
+
* Validates the toast settings and attempts to set necessary internal variables
|
|
5674
6018
|
*/
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
{
|
|
5686
|
-
name: "arrow",
|
|
5687
|
-
options: {
|
|
5688
|
-
element: ".s-popover--arrow",
|
|
5689
|
-
},
|
|
5690
|
-
},
|
|
5691
|
-
],
|
|
5692
|
-
});
|
|
6019
|
+
validate() {
|
|
6020
|
+
// check for returnElement support
|
|
6021
|
+
const returnElementSelector = this.data.get("return-element");
|
|
6022
|
+
if (returnElementSelector) {
|
|
6023
|
+
this.returnElement = (document.querySelector(returnElementSelector));
|
|
6024
|
+
if (!this.returnElement) {
|
|
6025
|
+
throw ("Unable to find element by return-element selector: " +
|
|
6026
|
+
returnElementSelector);
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
5693
6029
|
}
|
|
5694
6030
|
/**
|
|
5695
|
-
*
|
|
6031
|
+
* Toggles the visibility of the toast element
|
|
6032
|
+
* @param show Optional parameter that force shows/hides the element or toggles it if left undefined
|
|
5696
6033
|
*/
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
// if
|
|
5701
|
-
if (
|
|
5702
|
-
|
|
5703
|
-
if (!this.referenceElement) {
|
|
5704
|
-
throw ("Unable to find element by reference selector: " +
|
|
5705
|
-
referenceSelector);
|
|
5706
|
-
}
|
|
6034
|
+
_toggle(show, dispatcher = null) {
|
|
6035
|
+
let toShow = show;
|
|
6036
|
+
const isVisible = this.toastTarget.getAttribute("aria-hidden") === "false";
|
|
6037
|
+
// if we're letting the class toggle, we need to figure out if the toast is visible manually
|
|
6038
|
+
if (typeof toShow === "undefined") {
|
|
6039
|
+
toShow = !isVisible;
|
|
5707
6040
|
}
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
6041
|
+
// if the state matches the disired state, return without changing anything
|
|
6042
|
+
if ((toShow && isVisible) || (!toShow && !isVisible)) {
|
|
6043
|
+
return;
|
|
6044
|
+
}
|
|
6045
|
+
const dispatchingElement = this.getDispatcher(dispatcher);
|
|
6046
|
+
// show/hide events trigger before toggling the class
|
|
6047
|
+
const triggeredEvent = this.triggerEvent(toShow ? "show" : "hide", {
|
|
6048
|
+
returnElement: this.returnElement,
|
|
6049
|
+
dispatcher: this.getDispatcher(dispatchingElement),
|
|
6050
|
+
}, this.toastTarget);
|
|
6051
|
+
// if this pre-show/hide event was prevented, don't attempt to continue changing the toast state
|
|
6052
|
+
if (triggeredEvent.defaultPrevented) {
|
|
6053
|
+
return;
|
|
6054
|
+
}
|
|
6055
|
+
this.returnElement = triggeredEvent.detail.returnElement;
|
|
6056
|
+
this.toastTarget.setAttribute("aria-hidden", toShow ? "false" : "true");
|
|
6057
|
+
if (toShow) {
|
|
6058
|
+
this.bindDocumentEvents();
|
|
6059
|
+
this.hideAfterTimeout();
|
|
6060
|
+
if (this.data.get("prevent-focus-capture") !== "true") {
|
|
6061
|
+
this.focusInsideToast();
|
|
5715
6062
|
}
|
|
5716
6063
|
}
|
|
5717
|
-
// if the popover isn't named, attempt to generate it
|
|
5718
6064
|
else {
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
6065
|
+
this.unbindDocumentEvents();
|
|
6066
|
+
this.focusReturnElement();
|
|
6067
|
+
this.removeToastOnHide();
|
|
6068
|
+
this.clearActiveTimeout();
|
|
6069
|
+
}
|
|
6070
|
+
// check for transitionend support
|
|
6071
|
+
const supportsTransitionEnd = this.toastTarget.ontransitionend !== undefined;
|
|
6072
|
+
// shown/hidden events trigger after toggling the class
|
|
6073
|
+
if (supportsTransitionEnd) {
|
|
6074
|
+
// wait until after the toast finishes transitioning to fire the event
|
|
6075
|
+
this.toastTarget.addEventListener("transitionend", () => {
|
|
6076
|
+
//TODO this is firing waaay to soon?
|
|
6077
|
+
this.triggerEvent(toShow ? "shown" : "hidden", {
|
|
6078
|
+
dispatcher: dispatchingElement,
|
|
6079
|
+
}, this.toastTarget);
|
|
6080
|
+
}, { once: true });
|
|
6081
|
+
}
|
|
6082
|
+
else {
|
|
6083
|
+
this.triggerEvent(toShow ? "shown" : "hidden", {
|
|
6084
|
+
dispatcher: dispatchingElement,
|
|
6085
|
+
}, this.toastTarget);
|
|
5723
6086
|
}
|
|
5724
|
-
this.popoverElement = popoverElement;
|
|
5725
6087
|
}
|
|
5726
6088
|
/**
|
|
5727
|
-
*
|
|
5728
|
-
* @param dispatcher The event or element to get the dispatcher from
|
|
6089
|
+
* Listens for the s-toast:hidden event and focuses the returnElement when it is fired
|
|
5729
6090
|
*/
|
|
5730
|
-
|
|
5731
|
-
if (
|
|
5732
|
-
return
|
|
5733
|
-
}
|
|
5734
|
-
else if (dispatcher instanceof Element) {
|
|
5735
|
-
return dispatcher;
|
|
6091
|
+
focusReturnElement() {
|
|
6092
|
+
if (!this.returnElement) {
|
|
6093
|
+
return;
|
|
5736
6094
|
}
|
|
5737
|
-
|
|
5738
|
-
|
|
6095
|
+
this.toastTarget.addEventListener("s-toast:hidden", () => {
|
|
6096
|
+
// double check the element still exists when the event is called
|
|
6097
|
+
if (this.returnElement &&
|
|
6098
|
+
document.body.contains(this.returnElement)) {
|
|
6099
|
+
this.returnElement.focus();
|
|
6100
|
+
}
|
|
6101
|
+
}, { once: true });
|
|
6102
|
+
}
|
|
6103
|
+
/**
|
|
6104
|
+
* Remove the element on hide if the `remove-when-hidden` flag is set
|
|
6105
|
+
*/
|
|
6106
|
+
removeToastOnHide() {
|
|
6107
|
+
if (this.data.get("remove-when-hidden") !== "true") {
|
|
6108
|
+
return;
|
|
5739
6109
|
}
|
|
6110
|
+
this.toastTarget.addEventListener("s-toast:hidden", () => {
|
|
6111
|
+
this.element.remove();
|
|
6112
|
+
}, { once: true });
|
|
5740
6113
|
}
|
|
5741
6114
|
/**
|
|
5742
|
-
*
|
|
6115
|
+
* Hide the element after a delay
|
|
5743
6116
|
*/
|
|
5744
|
-
|
|
5745
|
-
if (this.
|
|
5746
|
-
|
|
6117
|
+
hideAfterTimeout() {
|
|
6118
|
+
if (this.data.get("prevent-auto-hide") === "true" ||
|
|
6119
|
+
this.data.get("hide-after-timeout") === "0") {
|
|
6120
|
+
return;
|
|
5747
6121
|
}
|
|
6122
|
+
const timeout = parseInt(this.data.get("hide-after-timeout"), 10) || 3000;
|
|
6123
|
+
this.activeTimeout = window.setTimeout(() => this.hide(), timeout);
|
|
5748
6124
|
}
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
this.
|
|
6125
|
+
/**
|
|
6126
|
+
* Cancels the activeTimeout
|
|
6127
|
+
*/
|
|
6128
|
+
clearActiveTimeout() {
|
|
6129
|
+
clearTimeout(this.activeTimeout);
|
|
5754
6130
|
}
|
|
5755
6131
|
/**
|
|
5756
|
-
*
|
|
6132
|
+
* Gets all elements within the toast that could receive keyboard focus.
|
|
5757
6133
|
*/
|
|
5758
|
-
|
|
5759
|
-
this.
|
|
5760
|
-
this.toggleAccessibilityAttributes(true);
|
|
5761
|
-
super.shown(dispatcher);
|
|
6134
|
+
getAllTabbables() {
|
|
6135
|
+
return Array.from(this.toastTarget.querySelectorAll("[href], input, select, textarea, button, [tabindex]")).filter((el) => el.matches(":not([disabled]):not([tabindex='-1'])"));
|
|
5762
6136
|
}
|
|
5763
6137
|
/**
|
|
5764
|
-
*
|
|
6138
|
+
* Returns the first visible element in an array or `undefined` if no elements are visible.
|
|
5765
6139
|
*/
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
super.hidden(dispatcher);
|
|
6140
|
+
firstVisible(elements) {
|
|
6141
|
+
// https://stackoverflow.com/a/21696585
|
|
6142
|
+
return elements === null || elements === void 0 ? void 0 : elements.find((el) => el.offsetParent !== null);
|
|
5770
6143
|
}
|
|
5771
6144
|
/**
|
|
5772
|
-
*
|
|
6145
|
+
* Attempts to shift keyboard focus into the toast.
|
|
6146
|
+
* If elements with `data-s-toast-target="initialFocus"` are present and visible, one of those will be selected.
|
|
6147
|
+
* Otherwise, the first visible focusable element will receive focus.
|
|
5773
6148
|
*/
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
6149
|
+
focusInsideToast() {
|
|
6150
|
+
this.toastTarget.addEventListener("s-toast:shown", () => {
|
|
6151
|
+
var _a;
|
|
6152
|
+
const initialFocus = (_a = this.firstVisible(this.initialFocusTargets)) !== null && _a !== void 0 ? _a : this.firstVisible(this.getAllTabbables());
|
|
6153
|
+
initialFocus === null || initialFocus === void 0 ? void 0 : initialFocus.focus();
|
|
6154
|
+
}, { once: true });
|
|
5777
6155
|
}
|
|
5778
6156
|
/**
|
|
5779
|
-
* Binds global events to the document for hiding
|
|
6157
|
+
* Binds global events to the document for hiding toasts on user interaction
|
|
5780
6158
|
*/
|
|
5781
6159
|
bindDocumentEvents() {
|
|
5782
|
-
this
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
document.addEventListener("
|
|
6160
|
+
// in order for removeEventListener to remove the right event, this bound function needs a constant reference
|
|
6161
|
+
this._boundClickFn =
|
|
6162
|
+
this._boundClickFn || this.hideOnOutsideClick.bind(this);
|
|
6163
|
+
this._boundKeypressFn =
|
|
6164
|
+
this._boundKeypressFn || this.hideOnEscapePress.bind(this);
|
|
6165
|
+
document.addEventListener("mousedown", this._boundClickFn);
|
|
6166
|
+
document.addEventListener("keyup", this._boundKeypressFn);
|
|
5788
6167
|
}
|
|
5789
6168
|
/**
|
|
5790
|
-
* Unbinds global events to the document for hiding
|
|
6169
|
+
* Unbinds global events to the document for hiding toasts on user interaction
|
|
5791
6170
|
*/
|
|
5792
6171
|
unbindDocumentEvents() {
|
|
5793
|
-
document.removeEventListener("mousedown", this.
|
|
5794
|
-
document.removeEventListener("keyup", this.
|
|
6172
|
+
document.removeEventListener("mousedown", this._boundClickFn);
|
|
6173
|
+
document.removeEventListener("keyup", this._boundKeypressFn);
|
|
5795
6174
|
}
|
|
5796
6175
|
/**
|
|
5797
|
-
* Forces the
|
|
5798
|
-
* @param {Event} e - The document click event
|
|
6176
|
+
* Forces the toast to hide if a user clicks outside of it or its reference element
|
|
5799
6177
|
*/
|
|
5800
6178
|
hideOnOutsideClick(e) {
|
|
6179
|
+
var _a;
|
|
5801
6180
|
const target = e.target;
|
|
5802
|
-
// check if the document was clicked inside either the
|
|
6181
|
+
// check if the document was clicked inside either the toggle element or the toast itself
|
|
5803
6182
|
// note: .contains also returns true if the node itself matches the target element
|
|
5804
|
-
if (this.
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
this.hide(e);
|
|
6183
|
+
if (!((_a = this.toastTarget) === null || _a === void 0 ? void 0 : _a.contains(target)) &&
|
|
6184
|
+
document.body.contains(target) &&
|
|
6185
|
+
this.data.get("hide-on-outside-click") !== "false") {
|
|
6186
|
+
this._toggle(false, e);
|
|
5809
6187
|
}
|
|
5810
6188
|
}
|
|
5811
6189
|
/**
|
|
5812
|
-
* Forces the
|
|
5813
|
-
* @param {Event} e - The document keyup event
|
|
6190
|
+
* Forces the toast to hide if the user presses escape while it, one of its childen, or the reference element are focused
|
|
5814
6191
|
*/
|
|
5815
6192
|
hideOnEscapePress(e) {
|
|
5816
|
-
// if the ESC key (27) wasn't pressed or if no
|
|
5817
|
-
if (e.which !== 27 ||
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
if (this.popoverElement.contains(e.target)) {
|
|
5823
|
-
this.referenceElement.focus();
|
|
5824
|
-
}
|
|
5825
|
-
this.hide(e);
|
|
5826
|
-
}
|
|
5827
|
-
/**
|
|
5828
|
-
* Toggles all classes on the originating element based on the `class-toggle` data
|
|
5829
|
-
* @param {boolean=} show - A boolean indicating whether this is being triggered by a show or hide.
|
|
5830
|
-
*/
|
|
5831
|
-
toggleOptionalClasses(show) {
|
|
5832
|
-
if (!this.data.has("toggle-class")) {
|
|
5833
|
-
return;
|
|
5834
|
-
}
|
|
5835
|
-
const toggleClass = this.data.get("toggle-class") || "";
|
|
5836
|
-
const cl = this.referenceElement.classList;
|
|
5837
|
-
toggleClass.split(/\s+/).forEach(function (cls) {
|
|
5838
|
-
cl.toggle(cls, show);
|
|
5839
|
-
});
|
|
5840
|
-
}
|
|
5841
|
-
/**
|
|
5842
|
-
* Toggles accessibility attributes based on whether the popover is shown or not
|
|
5843
|
-
* @param {boolean=} show - A boolean indicating whether this is being triggered by a show or hide.
|
|
5844
|
-
*/
|
|
5845
|
-
toggleAccessibilityAttributes(show) {
|
|
5846
|
-
const expandedValue = (show === null || show === void 0 ? void 0 : show.toString()) || this.referenceElement.ariaExpanded || "false";
|
|
5847
|
-
this.referenceElement.ariaExpanded = expandedValue;
|
|
5848
|
-
this.referenceElement.setAttribute("aria-expanded", expandedValue);
|
|
5849
|
-
}
|
|
5850
|
-
}
|
|
5851
|
-
PopoverController.targets = [];
|
|
5852
|
-
/**
|
|
5853
|
-
* Helper to manually show an s-popover element via external JS
|
|
5854
|
-
* @param element the element the `data-controller="s-popover"` attribute is on
|
|
5855
|
-
*/
|
|
5856
|
-
function showPopover(element) {
|
|
5857
|
-
const { isPopover, controller } = getPopover(element);
|
|
5858
|
-
if (controller) {
|
|
5859
|
-
controller.show();
|
|
5860
|
-
}
|
|
5861
|
-
else if (isPopover) {
|
|
5862
|
-
element.setAttribute("data-s-popover-auto-show", "true");
|
|
5863
|
-
}
|
|
5864
|
-
else {
|
|
5865
|
-
throw `element does not have data-controller="s-popover"`;
|
|
5866
|
-
}
|
|
5867
|
-
}
|
|
5868
|
-
/**
|
|
5869
|
-
* Helper to manually hide an s-popover element via external JS
|
|
5870
|
-
* @param element the element the `data-controller="s-popover"` attribute is on
|
|
5871
|
-
*/
|
|
5872
|
-
function hidePopover(element) {
|
|
5873
|
-
const { isPopover, controller, popover } = getPopover(element);
|
|
5874
|
-
if (controller) {
|
|
5875
|
-
controller.hide();
|
|
5876
|
-
}
|
|
5877
|
-
else if (isPopover) {
|
|
5878
|
-
element.removeAttribute("data-s-popover-auto-show");
|
|
5879
|
-
if (popover) {
|
|
5880
|
-
popover.classList.remove("is-visible");
|
|
5881
|
-
}
|
|
5882
|
-
}
|
|
5883
|
-
else {
|
|
5884
|
-
throw `element does not have data-controller="s-popover"`;
|
|
5885
|
-
}
|
|
5886
|
-
}
|
|
5887
|
-
/**
|
|
5888
|
-
* Attaches a popover to an element and performs additional configuration.
|
|
5889
|
-
* @param element the element that will receive the `data-controller="s-popover"` attribute.
|
|
5890
|
-
* @param popover an element with the `.s-popover` class or HTML string containing a single element with the `.s-popover` class.
|
|
5891
|
-
* If the popover does not have a parent element, it will be inserted as a immediately after the reference element.
|
|
5892
|
-
* @param options an optional collection of options to use when configuring the popover.
|
|
5893
|
-
*/
|
|
5894
|
-
function attachPopover(element, popover, options) {
|
|
5895
|
-
const { referenceElement, popover: existingPopover } = getPopover(element);
|
|
5896
|
-
if (existingPopover) {
|
|
5897
|
-
throw `element already has popover with id="${existingPopover.id}"`;
|
|
5898
|
-
}
|
|
5899
|
-
if (!referenceElement) {
|
|
5900
|
-
throw `element has invalid data-s-popover-reference-selector attribute`;
|
|
5901
|
-
}
|
|
5902
|
-
if (typeof popover === "string") {
|
|
5903
|
-
// eslint-disable-next-line no-unsanitized/method
|
|
5904
|
-
const elements = document
|
|
5905
|
-
.createRange()
|
|
5906
|
-
.createContextualFragment(popover).children;
|
|
5907
|
-
if (elements.length !== 1) {
|
|
5908
|
-
throw "popover should contain a single element";
|
|
5909
|
-
}
|
|
5910
|
-
popover = elements[0];
|
|
5911
|
-
}
|
|
5912
|
-
const existingId = referenceElement.getAttribute("aria-controls");
|
|
5913
|
-
let popoverId = popover.id;
|
|
5914
|
-
if (!popover.classList.contains("s-popover")) {
|
|
5915
|
-
throw `popover should have the "s-popover" class but had class="${popover.className}"`;
|
|
5916
|
-
}
|
|
5917
|
-
if (existingId && existingId !== popoverId) {
|
|
5918
|
-
throw `element has aria-controls="${existingId}" but popover has id="${popoverId}"`;
|
|
5919
|
-
}
|
|
5920
|
-
if (!popoverId) {
|
|
5921
|
-
popoverId =
|
|
5922
|
-
"--stacks-s-popover-" + Math.random().toString(36).substring(2, 10);
|
|
5923
|
-
popover.id = popoverId;
|
|
5924
|
-
}
|
|
5925
|
-
if (!existingId) {
|
|
5926
|
-
referenceElement.setAttribute("aria-controls", popoverId);
|
|
5927
|
-
}
|
|
5928
|
-
if (!popover.parentElement && element.parentElement) {
|
|
5929
|
-
referenceElement.insertAdjacentElement("afterend", popover);
|
|
6193
|
+
// if the ESC key (27) wasn't pressed or if no toasts are showing, return
|
|
6194
|
+
if (e.which !== 27 ||
|
|
6195
|
+
this.toastTarget.getAttribute("aria-hidden") === "true") {
|
|
6196
|
+
return;
|
|
6197
|
+
}
|
|
6198
|
+
this._toggle(false, e);
|
|
5930
6199
|
}
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
|
|
6200
|
+
/**
|
|
6201
|
+
* Determines the correct dispatching element from a potential input
|
|
6202
|
+
* @param dispatcher The event or element to get the dispatcher from
|
|
6203
|
+
*/
|
|
6204
|
+
getDispatcher(dispatcher = null) {
|
|
6205
|
+
if (dispatcher instanceof Event) {
|
|
6206
|
+
return dispatcher.target;
|
|
5935
6207
|
}
|
|
5936
|
-
if (
|
|
5937
|
-
|
|
6208
|
+
else if (dispatcher instanceof Element) {
|
|
6209
|
+
return dispatcher;
|
|
5938
6210
|
}
|
|
5939
|
-
|
|
5940
|
-
element
|
|
6211
|
+
else {
|
|
6212
|
+
return this.element;
|
|
5941
6213
|
}
|
|
5942
6214
|
}
|
|
5943
6215
|
}
|
|
6216
|
+
ToastController.targets = ["toast", "initialFocus"];
|
|
6217
|
+
|
|
5944
6218
|
/**
|
|
5945
|
-
*
|
|
5946
|
-
* @param element the element
|
|
5947
|
-
* @returns The popover that was attached to the element.
|
|
6219
|
+
* Helper to manually show an s-toast element via external JS
|
|
6220
|
+
* @param element the element the `data-controller="s-toast"` attribute is on
|
|
5948
6221
|
*/
|
|
5949
|
-
function
|
|
5950
|
-
|
|
5951
|
-
// Hide the popover so its events fire.
|
|
5952
|
-
controller === null || controller === void 0 ? void 0 : controller.hide();
|
|
5953
|
-
// Remove the popover if it exists
|
|
5954
|
-
popover === null || popover === void 0 ? void 0 : popover.remove();
|
|
5955
|
-
// Remove the popover controller and the aria-controls attributes.
|
|
5956
|
-
if (isPopover) {
|
|
5957
|
-
toggleController(element, "s-popover", false);
|
|
5958
|
-
if (referenceElement) {
|
|
5959
|
-
referenceElement.removeAttribute("aria-controls");
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
return popover;
|
|
6222
|
+
function showToast(element) {
|
|
6223
|
+
toggleToast(element, true);
|
|
5963
6224
|
}
|
|
5964
6225
|
/**
|
|
5965
|
-
*
|
|
5966
|
-
*
|
|
5967
|
-
* @param element An element that may have `data-controller="s-popover"`.
|
|
6226
|
+
* Helper to manually hide an s-toast element via external JS
|
|
6227
|
+
* @param element the element the `data-controller="s-toast"` attribute is on
|
|
5968
6228
|
*/
|
|
5969
|
-
function
|
|
5970
|
-
|
|
5971
|
-
const isPopover = ((_a = element.getAttribute("data-controller")) === null || _a === void 0 ? void 0 : _a.includes("s-popover")) || false;
|
|
5972
|
-
const controller = application.getControllerForElementAndIdentifier(element, "s-popover");
|
|
5973
|
-
const referenceSelector = element.getAttribute("data-s-popover-reference-selector");
|
|
5974
|
-
const referenceElement = referenceSelector
|
|
5975
|
-
? element.querySelector(referenceSelector)
|
|
5976
|
-
: element;
|
|
5977
|
-
const popoverId = referenceElement
|
|
5978
|
-
? referenceElement.getAttribute("aria-controls")
|
|
5979
|
-
: null;
|
|
5980
|
-
const popover = popoverId ? document.getElementById(popoverId) : null;
|
|
5981
|
-
return { isPopover, controller, referenceElement, popover };
|
|
6229
|
+
function hideToast(element) {
|
|
6230
|
+
toggleToast(element, false);
|
|
5982
6231
|
}
|
|
5983
6232
|
/**
|
|
5984
|
-
*
|
|
5985
|
-
* @param
|
|
5986
|
-
* @param
|
|
5987
|
-
* @param include Whether to add the controllerName value
|
|
6233
|
+
* Helper to manually show an s-toast element via external JS
|
|
6234
|
+
* @param element the element the `data-controller="s-toast"` attribute is on
|
|
6235
|
+
* @param show whether to force show/hide the toast; toggles the toast if left undefined
|
|
5988
6236
|
*/
|
|
5989
|
-
function
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
controllers.add(controllerName);
|
|
5994
|
-
}
|
|
5995
|
-
else {
|
|
5996
|
-
controllers.delete(controllerName);
|
|
5997
|
-
}
|
|
5998
|
-
el.setAttribute("data-controller", Array.from(controllers).join(" "));
|
|
5999
|
-
}
|
|
6000
|
-
|
|
6001
|
-
;// CONCATENATED MODULE: ./lib/ts/controllers/s-table.ts
|
|
6002
|
-
|
|
6003
|
-
class TableController extends StacksController {
|
|
6004
|
-
setCurrentSort(headElem, direction) {
|
|
6005
|
-
if (["asc", "desc", "none"].indexOf(direction) < 0) {
|
|
6006
|
-
throw "direction must be one of asc, desc, or none";
|
|
6007
|
-
}
|
|
6008
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
6009
|
-
const controller = this;
|
|
6010
|
-
this.columnTargets.forEach(function (target) {
|
|
6011
|
-
const isCurrrent = target === headElem;
|
|
6012
|
-
target.classList.toggle("is-sorted", isCurrrent && direction !== "none");
|
|
6013
|
-
target
|
|
6014
|
-
.querySelectorAll(".js-sorting-indicator")
|
|
6015
|
-
.forEach(function (icon) {
|
|
6016
|
-
const visible = isCurrrent ? direction : "none";
|
|
6017
|
-
icon.classList.toggle("d-none", !icon.classList.contains("js-sorting-indicator-" + visible));
|
|
6018
|
-
});
|
|
6019
|
-
if (!isCurrrent || direction === "none") {
|
|
6020
|
-
controller.removeElementData(target, "sort-direction");
|
|
6021
|
-
}
|
|
6022
|
-
else {
|
|
6023
|
-
controller.setElementData(target, "sort-direction", direction);
|
|
6024
|
-
}
|
|
6025
|
-
});
|
|
6026
|
-
}
|
|
6027
|
-
sort(evt) {
|
|
6028
|
-
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
6029
|
-
const controller = this;
|
|
6030
|
-
const colHead = evt.currentTarget;
|
|
6031
|
-
if (!(colHead instanceof HTMLTableCellElement)) {
|
|
6032
|
-
throw "invalid event target";
|
|
6033
|
-
}
|
|
6034
|
-
const table = this.element;
|
|
6035
|
-
const tbody = table.tBodies[0];
|
|
6036
|
-
// the column slot number of the clicked header
|
|
6037
|
-
const colno = getCellSlot(colHead);
|
|
6038
|
-
if (colno < 0) {
|
|
6039
|
-
// this shouldn't happen if the clicked element is actually a column head
|
|
6040
|
-
return;
|
|
6041
|
-
}
|
|
6042
|
-
// an index of the <tbody>, so we can find out for each row which <td> element is
|
|
6043
|
-
// in the same column slot as the header
|
|
6044
|
-
const slotIndex = buildIndex(tbody);
|
|
6045
|
-
// the default behavior when clicking a header is to sort by this column in ascending
|
|
6046
|
-
// direction, *unless* it is already sorted that way
|
|
6047
|
-
const direction = this.getElementData(colHead, "sort-direction") === "asc" ? -1 : 1;
|
|
6048
|
-
const rows = Array.from(table.tBodies[0].rows);
|
|
6049
|
-
// if this is still false after traversing the data, that means all values are integers (or empty)
|
|
6050
|
-
// and thus we'll sort numerically.
|
|
6051
|
-
let anyNonInt = false;
|
|
6052
|
-
// data will be a list of tuples [value, rowNum], where value is what we're sorting by
|
|
6053
|
-
const data = [];
|
|
6054
|
-
let firstBottomRow;
|
|
6055
|
-
rows.forEach(function (row, index) {
|
|
6056
|
-
var _a, _b;
|
|
6057
|
-
const force = controller.getElementData(row, "sort-to");
|
|
6058
|
-
if (force === "top") {
|
|
6059
|
-
return; // rows not added to the list will automatically end up at the top
|
|
6060
|
-
}
|
|
6061
|
-
else if (force === "bottom") {
|
|
6062
|
-
if (!firstBottomRow) {
|
|
6063
|
-
firstBottomRow = row;
|
|
6064
|
-
}
|
|
6065
|
-
return;
|
|
6066
|
-
}
|
|
6067
|
-
const cell = slotIndex[index][colno];
|
|
6068
|
-
if (!cell) {
|
|
6069
|
-
data.push(["", index]);
|
|
6070
|
-
return;
|
|
6071
|
-
}
|
|
6072
|
-
// unless the to-be-sorted-by value is explicitly provided on the element via this attribute,
|
|
6073
|
-
// the value we're using is the cell's text, trimmed of any whitespace
|
|
6074
|
-
const explicit = controller.getElementData(cell, "sort-val");
|
|
6075
|
-
const d = typeof explicit === "string"
|
|
6076
|
-
? explicit
|
|
6077
|
-
: (_b = (_a = cell.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : "";
|
|
6078
|
-
if (d !== "" && `${parseInt(d, 10)}` !== d) {
|
|
6079
|
-
anyNonInt = true;
|
|
6080
|
-
}
|
|
6081
|
-
data.push([d, index]);
|
|
6082
|
-
});
|
|
6083
|
-
// If all values were integers (or empty cells), sort numerically, with empty cells treated as
|
|
6084
|
-
// having the lowest possible value (i.e. sorted to the top if ascending, bottom if descending)
|
|
6085
|
-
if (!anyNonInt) {
|
|
6086
|
-
data.forEach(function (tuple) {
|
|
6087
|
-
tuple[0] =
|
|
6088
|
-
tuple[0] === ""
|
|
6089
|
-
? Number.MIN_VALUE
|
|
6090
|
-
: parseInt(tuple[0], 10);
|
|
6091
|
-
});
|
|
6092
|
-
}
|
|
6093
|
-
// We don't sort an array of <tr>, but instead an arrays of row *numbers*, because this way we
|
|
6094
|
-
// can enforce stable sorting, i.e. rows that compare equal are guaranteed to remain in the same
|
|
6095
|
-
// order (the JS standard does not gurantee this for sort()).
|
|
6096
|
-
data.sort(function (a, b) {
|
|
6097
|
-
// first compare the values (a[0])
|
|
6098
|
-
if (a[0] > b[0]) {
|
|
6099
|
-
return 1 * direction;
|
|
6100
|
-
}
|
|
6101
|
-
else if (a[0] < b[0]) {
|
|
6102
|
-
return -1 * direction;
|
|
6103
|
-
}
|
|
6104
|
-
else {
|
|
6105
|
-
// if the values are equal, compare the row numbers (a[1]) to guarantee stable sorting
|
|
6106
|
-
// (note that this comparison is independent of the sorting direction)
|
|
6107
|
-
return a[1] > b[1] ? 1 : -1;
|
|
6108
|
-
}
|
|
6109
|
-
});
|
|
6110
|
-
// this is the actual reordering of the table rows
|
|
6111
|
-
data.forEach(function (tup) {
|
|
6112
|
-
var _a;
|
|
6113
|
-
const row = rows[tup[1]];
|
|
6114
|
-
(_a = row.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(row);
|
|
6115
|
-
if (firstBottomRow) {
|
|
6116
|
-
tbody.insertBefore(row, firstBottomRow);
|
|
6117
|
-
}
|
|
6118
|
-
else {
|
|
6119
|
-
tbody.appendChild(row);
|
|
6120
|
-
}
|
|
6121
|
-
});
|
|
6122
|
-
// update the UI and set the `data-sort-direction` attribute if appropriate, so that the next click
|
|
6123
|
-
// will cause sorting in descending direction
|
|
6124
|
-
this.setCurrentSort(colHead, direction === 1 ? "asc" : "desc");
|
|
6125
|
-
}
|
|
6126
|
-
}
|
|
6127
|
-
TableController.targets = ["column"];
|
|
6128
|
-
function buildIndex(section) {
|
|
6129
|
-
const result = buildIndexOrGetCellSlot(section);
|
|
6130
|
-
if (!(result instanceof Array)) {
|
|
6131
|
-
throw "shouldn't happen";
|
|
6132
|
-
}
|
|
6133
|
-
return result;
|
|
6134
|
-
}
|
|
6135
|
-
function getCellSlot(cell) {
|
|
6136
|
-
if (!(cell.parentElement &&
|
|
6137
|
-
cell.parentElement.parentElement instanceof HTMLTableSectionElement)) {
|
|
6138
|
-
throw "invalid table";
|
|
6139
|
-
}
|
|
6140
|
-
const result = buildIndexOrGetCellSlot(cell.parentElement.parentElement, cell);
|
|
6141
|
-
if (typeof result !== "number") {
|
|
6142
|
-
throw "shouldn't happen";
|
|
6143
|
-
}
|
|
6144
|
-
return result;
|
|
6145
|
-
}
|
|
6146
|
-
// Just because a <td> is the 4th *child* of its <tr> doesn't mean it belongs to the 4th *column*
|
|
6147
|
-
// of the table. Previous cells may have a colspan; cells in previous rows may have a rowspan.
|
|
6148
|
-
// Because we need to know which header cells and data cells belong together, we have to 1) find out
|
|
6149
|
-
// which column number (or "slot" as we call it here) the header cell has, and 2) for each row find
|
|
6150
|
-
// out which <td> cell corresponds to this slot (because those are the rows we're sorting by).
|
|
6151
|
-
//
|
|
6152
|
-
// That's what the following function does. If the second argument is not given, it returns an index
|
|
6153
|
-
// of the table, which is an array of arrays. Each of the sub-arrays corresponds to a table row. The
|
|
6154
|
-
// indices of the sub-array correspond to column slots; the values are the actual table cell elements.
|
|
6155
|
-
// For example index[4][3] is the <td> or <th> in row 4, column 3 of the table section (<tbody> or <thead>).
|
|
6156
|
-
// Note that this element is not necessarily even in the 4th (zero-based) <tr> -- if it has a rowSpan > 1,
|
|
6157
|
-
// it may also be in a previous <tr>.
|
|
6158
|
-
//
|
|
6159
|
-
// If the second argument is given, it's a <td> or <th> that we're trying to find, and the algorithm
|
|
6160
|
-
// stops as soon as it has found it and the function returns its slot number.
|
|
6161
|
-
function buildIndexOrGetCellSlot(section, findCell) {
|
|
6162
|
-
const index = [];
|
|
6163
|
-
let curRow = section.children[0];
|
|
6164
|
-
// the elements of these two arrays are synchronized; the first array contains table cell elements,
|
|
6165
|
-
// the second one contains a number that indicates for how many more rows this elements will
|
|
6166
|
-
// exist (i.e. the value is initially one less than the cell's rowspan, and will be decreased for each row)
|
|
6167
|
-
const growing = [];
|
|
6168
|
-
const growingRowsLeft = [];
|
|
6169
|
-
// continue while we have actual <tr>'s left *or* we still have rowspan'ed elements that aren't done
|
|
6170
|
-
while (curRow ||
|
|
6171
|
-
growingRowsLeft.some(function (e) {
|
|
6172
|
-
return e !== 0;
|
|
6173
|
-
})) {
|
|
6174
|
-
const curIndexRow = [];
|
|
6175
|
-
index.push(curIndexRow);
|
|
6176
|
-
let curSlot = 0;
|
|
6177
|
-
if (curRow) {
|
|
6178
|
-
for (let curCellInd = 0; curCellInd < curRow.children.length; curCellInd++) {
|
|
6179
|
-
while (growingRowsLeft[curSlot]) {
|
|
6180
|
-
growingRowsLeft[curSlot]--;
|
|
6181
|
-
curIndexRow[curSlot] = growing[curSlot];
|
|
6182
|
-
curSlot++;
|
|
6183
|
-
}
|
|
6184
|
-
const cell = curRow.children[curCellInd];
|
|
6185
|
-
if (!(cell instanceof HTMLTableCellElement)) {
|
|
6186
|
-
throw "invalid table";
|
|
6187
|
-
}
|
|
6188
|
-
if (getComputedStyle(cell).display === "none") {
|
|
6189
|
-
continue;
|
|
6190
|
-
}
|
|
6191
|
-
if (cell === findCell) {
|
|
6192
|
-
return curSlot;
|
|
6193
|
-
}
|
|
6194
|
-
const nextFreeSlot = curSlot + cell.colSpan;
|
|
6195
|
-
for (; curSlot < nextFreeSlot; curSlot++) {
|
|
6196
|
-
growingRowsLeft[curSlot] = cell.rowSpan - 1; // if any of these is already growing, the table is broken -- no guarantees of anything
|
|
6197
|
-
growing[curSlot] = cell;
|
|
6198
|
-
curIndexRow[curSlot] = cell;
|
|
6199
|
-
}
|
|
6200
|
-
}
|
|
6201
|
-
}
|
|
6202
|
-
while (curSlot < growing.length) {
|
|
6203
|
-
if (growingRowsLeft[curSlot]) {
|
|
6204
|
-
growingRowsLeft[curSlot]--;
|
|
6205
|
-
curIndexRow[curSlot] = growing[curSlot];
|
|
6206
|
-
}
|
|
6207
|
-
curSlot++;
|
|
6208
|
-
}
|
|
6209
|
-
if (curRow) {
|
|
6210
|
-
curRow = curRow.nextElementSibling;
|
|
6211
|
-
}
|
|
6237
|
+
function toggleToast(element, show) {
|
|
6238
|
+
const controller = application.getControllerForElementAndIdentifier(element, "s-toast");
|
|
6239
|
+
if (!controller) {
|
|
6240
|
+
throw "Unable to get s-toast controller from element";
|
|
6212
6241
|
}
|
|
6213
|
-
|
|
6214
|
-
? -1
|
|
6215
|
-
: index; /* if findCell was given but we end up here, that means it isn't in this section */
|
|
6242
|
+
show ? controller.show() : controller.hide();
|
|
6216
6243
|
}
|
|
6217
6244
|
|
|
6218
|
-
;// CONCATENATED MODULE: ./lib/
|
|
6245
|
+
;// CONCATENATED MODULE: ./lib/components/popover/tooltip.ts
|
|
6219
6246
|
|
|
6220
6247
|
|
|
6221
6248
|
class TooltipController extends BasePopoverController {
|
|
@@ -6426,6 +6453,7 @@ class TooltipController extends BasePopoverController {
|
|
|
6426
6453
|
}
|
|
6427
6454
|
}
|
|
6428
6455
|
TooltipController.targets = [];
|
|
6456
|
+
|
|
6429
6457
|
/**
|
|
6430
6458
|
* Adds or updates a Stacks tooltip on a given element, initializing the controller if necessary
|
|
6431
6459
|
* @param element The element to add a tooltip to.
|
|
@@ -6467,7 +6495,7 @@ function applyOptionsAndTitleAttributes(element, options) {
|
|
|
6467
6495
|
}
|
|
6468
6496
|
}
|
|
6469
6497
|
|
|
6470
|
-
;// CONCATENATED MODULE: ./lib/
|
|
6498
|
+
;// CONCATENATED MODULE: ./lib/components/uploader/uploader.ts
|
|
6471
6499
|
|
|
6472
6500
|
class UploaderController extends StacksController {
|
|
6473
6501
|
connect() {
|
|
@@ -6631,7 +6659,8 @@ UploaderController.targets = ["input", "previews", "uploader"];
|
|
|
6631
6659
|
UploaderController.FILE_DISPLAY_LIMIT = 10;
|
|
6632
6660
|
UploaderController.MAX_FILE_SIZE = 1024 * 1024 * 10; // 10 MB
|
|
6633
6661
|
|
|
6634
|
-
|
|
6662
|
+
|
|
6663
|
+
;// CONCATENATED MODULE: ./lib/controllers.ts
|
|
6635
6664
|
// export all controllers *with helpers* so they can be bulk re-exported by the package entry point
|
|
6636
6665
|
|
|
6637
6666
|
|
|
@@ -6643,7 +6672,7 @@ UploaderController.MAX_FILE_SIZE = 1024 * 1024 * 10; // 10 MB
|
|
|
6643
6672
|
|
|
6644
6673
|
|
|
6645
6674
|
|
|
6646
|
-
;// CONCATENATED MODULE: ./lib/
|
|
6675
|
+
;// CONCATENATED MODULE: ./lib/index.ts
|
|
6647
6676
|
|
|
6648
6677
|
|
|
6649
6678
|
|