Path: blob/main/src/resources/formats/html/bslib/components/dist/components.js
12924 views
/*! bslib 0.5.1.9000 | (c) 2012-2023 RStudio, PBC. | License: MIT + file LICENSE */1"use strict";2(() => {3// srcts/src/components/_utils.ts4var InputBinding = window.Shiny ? Shiny.InputBinding : class {5};6function registerBinding(inputBindingClass, name) {7if (window.Shiny) {8Shiny.inputBindings.register(new inputBindingClass(), "bslib." + name);9}10}11function hasDefinedProperty(obj, prop) {12return Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== void 0;13}14function getAllFocusableChildren(el) {15const base = [16"a[href]",17"area[href]",18"button",19"details summary",20"input",21"iframe",22"select",23"textarea",24'[contentEditable=""]',25'[contentEditable="true"]',26'[contentEditable="TRUE"]',27"[tabindex]"28];29const modifiers = [':not([tabindex="-1"])', ":not([disabled])"];30const selectors = base.map((b) => b + modifiers.join(""));31const focusable = el.querySelectorAll(selectors.join(", "));32return Array.from(focusable);33}3435// srcts/src/components/accordion.ts36var AccordionInputBinding = class extends InputBinding {37find(scope) {38return $(scope).find(".accordion.bslib-accordion-input");39}40getValue(el) {41const items = this._getItemInfo(el);42const selected = items.filter((x) => x.isOpen()).map((x) => x.value);43return selected.length === 0 ? null : selected;44}45subscribe(el, callback) {46$(el).on(47"shown.bs.collapse.accordionInputBinding hidden.bs.collapse.accordionInputBinding",48// eslint-disable-next-line @typescript-eslint/no-unused-vars49function(event) {50callback(true);51}52);53}54unsubscribe(el) {55$(el).off(".accordionInputBinding");56}57receiveMessage(el, data) {58const method = data.method;59if (method === "set") {60this._setItems(el, data);61} else if (method === "open") {62this._openItems(el, data);63} else if (method === "close") {64this._closeItems(el, data);65} else if (method === "remove") {66this._removeItem(el, data);67} else if (method === "insert") {68this._insertItem(el, data);69} else if (method === "update") {70this._updateItem(el, data);71} else {72throw new Error(`Method not yet implemented: ${method}`);73}74}75_setItems(el, data) {76const items = this._getItemInfo(el);77const vals = this._getValues(el, items, data.values);78items.forEach((x) => {79vals.indexOf(x.value) > -1 ? x.show() : x.hide();80});81}82_openItems(el, data) {83const items = this._getItemInfo(el);84const vals = this._getValues(el, items, data.values);85items.forEach((x) => {86if (vals.indexOf(x.value) > -1)87x.show();88});89}90_closeItems(el, data) {91const items = this._getItemInfo(el);92const vals = this._getValues(el, items, data.values);93items.forEach((x) => {94if (vals.indexOf(x.value) > -1)95x.hide();96});97}98_insertItem(el, data) {99let targetItem = this._findItem(el, data.target);100if (!targetItem) {101targetItem = data.position === "before" ? el.firstElementChild : el.lastElementChild;102}103const panel = data.panel;104if (targetItem) {105Shiny.renderContent(106targetItem,107panel,108data.position === "before" ? "beforeBegin" : "afterEnd"109);110} else {111Shiny.renderContent(el, panel);112}113if (this._isAutoClosing(el)) {114const val = $(panel.html).attr("data-value");115$(el).find(`[data-value="${val}"] .accordion-collapse`).attr("data-bs-parent", "#" + el.id);116}117}118_removeItem(el, data) {119const targetItems = this._getItemInfo(el).filter(120(x) => data.target.indexOf(x.value) > -1121);122const unbindAll = Shiny == null ? void 0 : Shiny.unbindAll;123targetItems.forEach((x) => {124if (unbindAll)125unbindAll(x.item);126x.item.remove();127});128}129_updateItem(el, data) {130const target = this._findItem(el, data.target);131if (!target) {132throw new Error(133`Unable to find an accordion_panel() with a value of ${data.target}`134);135}136if (hasDefinedProperty(data, "value")) {137target.dataset.value = data.value;138}139if (hasDefinedProperty(data, "body")) {140const body = target.querySelector(".accordion-body");141Shiny.renderContent(body, data.body);142}143const header = target.querySelector(".accordion-header");144if (hasDefinedProperty(data, "title")) {145const title = header.querySelector(".accordion-title");146Shiny.renderContent(title, data.title);147}148if (hasDefinedProperty(data, "icon")) {149const icon = header.querySelector(150".accordion-button > .accordion-icon"151);152Shiny.renderContent(icon, data.icon);153}154}155_getItemInfo(el) {156const items = Array.from(157el.querySelectorAll(":scope > .accordion-item")158);159return items.map((x) => this._getSingleItemInfo(x));160}161_getSingleItemInfo(x) {162const collapse = x.querySelector(".accordion-collapse");163const isOpen = () => $(collapse).hasClass("show");164return {165item: x,166value: x.dataset.value,167isOpen,168show: () => {169if (!isOpen())170$(collapse).collapse("show");171},172hide: () => {173if (isOpen())174$(collapse).collapse("hide");175}176};177}178_getValues(el, items, values) {179let vals = values !== true ? values : items.map((x) => x.value);180const autoclose = this._isAutoClosing(el);181if (autoclose) {182vals = vals.slice(vals.length - 1, vals.length);183}184return vals;185}186_findItem(el, value) {187return el.querySelector(`[data-value="${value}"]`);188}189_isAutoClosing(el) {190return el.classList.contains("autoclose");191}192};193registerBinding(AccordionInputBinding, "accordion");194195// srcts/src/components/_shinyResizeObserver.ts196var ShinyResizeObserver = class {197/**198* Watch containers for size changes and ensure that Shiny outputs and199* htmlwidgets within resize appropriately.200*201* @details202* The ShinyResizeObserver is used to watch the containers, such as Sidebars203* and Cards for size changes, in particular when the sidebar state is toggled204* or the card body is expanded full screen. It performs two primary tasks:205*206* 1. Dispatches a `resize` event on the window object. This is necessary to207* ensure that Shiny outputs resize appropriately. In general, the window208* resizing is throttled and the output update occurs when the transition209* is complete.210* 2. If an output with a resize method on the output binding is detected, we211* directly call the `.onResize()` method of the binding. This ensures that212* htmlwidgets transition smoothly. In static mode, htmlwidgets does this213* already.214*215* @note216* This resize observer also handles race conditions in some complex217* fill-based layouts with multiple outputs (e.g., plotly), where shiny218* initializes with the correct sizing, but in-between the 1st and last219* renderValue(), the size of the output containers can change, meaning every220* output but the 1st gets initialized with the wrong size during their221* renderValue(). Then, after the render phase, shiny won't know to trigger a222* resize since all the widgets will return to their original size (and thus,223* Shiny thinks there isn't any resizing to do). The resize observer works224* around this by ensuring that the output is resized whenever its container225* size changes.226* @constructor227*/228constructor() {229this.resizeObserverEntries = [];230this.resizeObserver = new ResizeObserver((entries) => {231const resizeEvent = new Event("resize");232window.dispatchEvent(resizeEvent);233if (!window.Shiny)234return;235const resized = [];236for (const entry of entries) {237if (!(entry.target instanceof HTMLElement))238continue;239if (!entry.target.querySelector(".shiny-bound-output"))240continue;241entry.target.querySelectorAll(".shiny-bound-output").forEach((el) => {242if (resized.includes(el))243return;244const { binding, onResize } = $(el).data("shinyOutputBinding");245if (!binding || !binding.resize)246return;247const owner = el.shinyResizeObserver;248if (owner && owner !== this)249return;250if (!owner)251el.shinyResizeObserver = this;252onResize(el);253resized.push(el);254if (!el.classList.contains("shiny-plot-output"))255return;256const img = el.querySelector(257'img:not([width="100%"])'258);259if (img)260img.setAttribute("width", "100%");261});262}263});264}265/**266* Observe an element for size changes.267* @param {HTMLElement} el - The element to observe.268*/269observe(el) {270this.resizeObserver.observe(el);271this.resizeObserverEntries.push(el);272}273/**274* Stop observing an element for size changes.275* @param {HTMLElement} el - The element to stop observing.276*/277unobserve(el) {278const idxEl = this.resizeObserverEntries.indexOf(el);279if (idxEl < 0)280return;281this.resizeObserver.unobserve(el);282this.resizeObserverEntries.splice(idxEl, 1);283}284/**285* This method checks that we're not continuing to watch elements that no286* longer exist in the DOM. If any are found, we stop observing them and287* remove them from our array of observed elements.288*289* @private290* @static291*/292flush() {293this.resizeObserverEntries.forEach((el) => {294if (!document.body.contains(el))295this.unobserve(el);296});297}298};299300// srcts/src/components/card.ts301var _Card = class {302/**303* Creates an instance of a bslib Card component.304*305* @constructor306* @param {HTMLElement} card307*/308constructor(card) {309var _a;310card.removeAttribute(_Card.attr.ATTR_INIT);311(_a = card.querySelector(`script[${_Card.attr.ATTR_INIT}]`)) == null ? void 0 : _a.remove();312this.card = card;313_Card.instanceMap.set(card, this);314_Card.shinyResizeObserver.observe(this.card);315this._addEventListeners();316this.overlay = this._createOverlay();317this._exitFullScreenOnEscape = this._exitFullScreenOnEscape.bind(this);318this._trapFocusExit = this._trapFocusExit.bind(this);319}320/**321* Enter the card's full screen mode, either programmatically or via an event322* handler. Full screen mode is activated by adding a class to the card that323* positions it absolutely and expands it to fill the viewport. In addition,324* we add a full screen overlay element behind the card and we trap focus in325* the expanded card while in full screen mode.326*327* @param {?Event} [event]328*/329enterFullScreen(event) {330var _a;331if (event)332event.preventDefault();333document.addEventListener("keydown", this._exitFullScreenOnEscape, false);334document.addEventListener("keydown", this._trapFocusExit, true);335this.card.setAttribute(_Card.attr.ATTR_FULL_SCREEN, "true");336document.body.classList.add(_Card.attr.CLASS_HAS_FULL_SCREEN);337this.card.insertAdjacentElement("beforebegin", this.overlay.container);338if (!this.card.contains(document.activeElement) || ((_a = document.activeElement) == null ? void 0 : _a.classList.contains(339_Card.attr.CLASS_FULL_SCREEN_ENTER340))) {341this.card.setAttribute("tabindex", "-1");342this.card.focus();343}344}345/**346* Exit full screen mode. This removes the full screen overlay element,347* removes the full screen class from the card, and removes the keyboard event348* listeners that were added when entering full screen mode.349*/350exitFullScreen() {351document.removeEventListener(352"keydown",353this._exitFullScreenOnEscape,354false355);356document.removeEventListener("keydown", this._trapFocusExit, true);357this.overlay.container.remove();358this.card.setAttribute(_Card.attr.ATTR_FULL_SCREEN, "false");359this.card.removeAttribute("tabindex");360document.body.classList.remove(_Card.attr.CLASS_HAS_FULL_SCREEN);361}362/**363* Adds general card-specific event listeners.364* @private365*/366_addEventListeners() {367const btnFullScreen = this.card.querySelector(368`:scope > * > .${_Card.attr.CLASS_FULL_SCREEN_ENTER}`369);370if (!btnFullScreen)371return;372btnFullScreen.addEventListener("click", (ev) => this.enterFullScreen(ev));373}374/**375* An event handler to exit full screen mode when the Escape key is pressed.376* @private377* @param {KeyboardEvent} event378*/379_exitFullScreenOnEscape(event) {380if (!(event.target instanceof HTMLElement))381return;382const selOpenSelectInput = ["select[open]", "input[aria-expanded='true']"];383if (event.target.matches(selOpenSelectInput.join(", ")))384return;385if (event.key === "Escape") {386this.exitFullScreen();387}388}389/**390* An event handler to trap focus within the card when in full screen mode.391*392* @description393* This keyboard event handler ensures that tab focus stays within the card394* when in full screen mode. When the card is first expanded,395* we move focus to the card element itself. If focus somehow leaves the card,396* we returns focus to the card container.397*398* Within the card, we handle only tabbing from the close anchor or the last399* focusable element and only when tab focus would have otherwise left the400* card. In those cases, we cycle focus to the last focusable element or back401* to the anchor. If the card doesn't have any focusable elements, we move402* focus to the close anchor.403*404* @note405* Because the card contents may change, we check for focusable elements406* every time the handler is called.407*408* @private409* @param {KeyboardEvent} event410*/411_trapFocusExit(event) {412if (!(event instanceof KeyboardEvent))413return;414if (event.key !== "Tab")415return;416const isFocusedContainer = event.target === this.card;417const isFocusedAnchor = event.target === this.overlay.anchor;418const isFocusedWithin = this.card.contains(event.target);419const stopEvent = () => {420event.preventDefault();421event.stopImmediatePropagation();422};423if (!(isFocusedWithin || isFocusedContainer || isFocusedAnchor)) {424stopEvent();425this.card.focus();426return;427}428const focusableElements = getAllFocusableChildren(this.card).filter(429(el) => !el.classList.contains(_Card.attr.CLASS_FULL_SCREEN_ENTER)430);431const hasFocusableElements = focusableElements.length > 0;432if (!hasFocusableElements) {433stopEvent();434this.overlay.anchor.focus();435return;436}437if (isFocusedContainer)438return;439const lastFocusable = focusableElements[focusableElements.length - 1];440const isFocusedLast = event.target === lastFocusable;441if (isFocusedAnchor && event.shiftKey) {442stopEvent();443lastFocusable.focus();444return;445}446if (isFocusedLast && !event.shiftKey) {447stopEvent();448this.overlay.anchor.focus();449return;450}451}452/**453* Creates the full screen overlay.454* @private455* @returns {CardFullScreenOverlay}456*/457_createOverlay() {458const container = document.createElement("div");459container.id = _Card.attr.ID_FULL_SCREEN_OVERLAY;460container.onclick = this.exitFullScreen.bind(this);461const anchor = this._createOverlayCloseAnchor();462container.appendChild(anchor);463return { container, anchor };464}465/**466* Creates the anchor element used to exit the full screen mode.467* @private468* @returns {HTMLAnchorElement}469*/470_createOverlayCloseAnchor() {471const anchor = document.createElement("a");472anchor.classList.add(_Card.attr.CLASS_FULL_SCREEN_EXIT);473anchor.tabIndex = 0;474anchor.onclick = () => this.exitFullScreen();475anchor.onkeydown = (ev) => {476if (ev.key === "Enter" || ev.key === " ") {477this.exitFullScreen();478}479};480anchor.innerHTML = this._overlayCloseHtml();481return anchor;482}483/**484* Returns the HTML for the close icon.485* @private486* @returns {string}487*/488_overlayCloseHtml() {489return "Close <svg width='20' height='20' fill='currentColor' class='bi bi-x-lg' viewBox='0 0 16 16'><path d='M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8 2.146 2.854Z'/></svg>";490}491/**492* Returns the card instance associated with the given element, if any.493* @public494* @static495* @param {HTMLElement} el496* @returns {(Card | undefined)}497*/498static getInstance(el) {499return _Card.instanceMap.get(el);500}501/**502* Initializes all cards that require initialization on the page, or schedules503* initialization if the DOM is not yet ready.504* @public505* @static506* @param {boolean} [flushResizeObserver=true]507*/508static initializeAllCards(flushResizeObserver = true) {509if (document.readyState === "loading") {510if (!_Card.onReadyScheduled) {511_Card.onReadyScheduled = true;512document.addEventListener("DOMContentLoaded", () => {513_Card.initializeAllCards(false);514});515}516return;517}518if (flushResizeObserver) {519_Card.shinyResizeObserver.flush();520}521const initSelector = `.${_Card.attr.CLASS_CARD}[${_Card.attr.ATTR_INIT}]`;522if (!document.querySelector(initSelector)) {523return;524}525const cards = document.querySelectorAll(initSelector);526cards.forEach((card) => new _Card(card));527}528};529var Card = _Card;530/**531* Key bslib-specific classes and attributes used by the card component.532* @private533* @static534* @type {{ ATTR_INIT: string; CLASS_CARD: string; CLASS_FULL_SCREEN: string; CLASS_HAS_FULL_SCREEN: string; CLASS_FULL_SCREEN_ENTER: string; CLASS_FULL_SCREEN_EXIT: string; ID_FULL_SCREEN_OVERLAY: string; }}535*/536Card.attr = {537// eslint-disable-next-line @typescript-eslint/naming-convention538ATTR_INIT: "data-bslib-card-init",539// eslint-disable-next-line @typescript-eslint/naming-convention540CLASS_CARD: "bslib-card",541// eslint-disable-next-line @typescript-eslint/naming-convention542ATTR_FULL_SCREEN: "data-full-screen",543// eslint-disable-next-line @typescript-eslint/naming-convention544CLASS_HAS_FULL_SCREEN: "bslib-has-full-screen",545// eslint-disable-next-line @typescript-eslint/naming-convention546CLASS_FULL_SCREEN_ENTER: "bslib-full-screen-enter",547// eslint-disable-next-line @typescript-eslint/naming-convention548CLASS_FULL_SCREEN_EXIT: "bslib-full-screen-exit",549// eslint-disable-next-line @typescript-eslint/naming-convention550ID_FULL_SCREEN_OVERLAY: "bslib-full-screen-overlay"551};552/**553* A Shiny-specific resize observer that ensures Shiny outputs in within the554* card resize appropriately.555* @private556* @type {ShinyResizeObserver}557* @static558*/559Card.shinyResizeObserver = new ShinyResizeObserver();560/**561* The registry of card instances and their associated DOM elements.562* @private563* @static564* @type {WeakMap<HTMLElement, Card>}565*/566Card.instanceMap = /* @__PURE__ */ new WeakMap();567/**568* If cards are initialized before the DOM is ready, we re-schedule the569* initialization to occur on DOMContentLoaded.570* @private571* @static572* @type {boolean}573*/574Card.onReadyScheduled = false;575window.bslib = window.bslib || {};576window.bslib.Card = Card;577578// srcts/src/components/sidebar.ts579var _Sidebar = class {580/**581* Creates an instance of a collapsible bslib Sidebar.582* @constructor583* @param {HTMLElement} container584*/585constructor(container) {586var _a;587_Sidebar.instanceMap.set(container, this);588this.layout = {589container,590main: container.querySelector(":scope > .main"),591sidebar: container.querySelector(":scope > .sidebar"),592toggle: container.querySelector(593":scope > .collapse-toggle"594)595};596const sideAccordion = this.layout.sidebar.querySelector(597":scope > .sidebar-content > .accordion"598);599if (sideAccordion) {600(_a = sideAccordion == null ? void 0 : sideAccordion.parentElement) == null ? void 0 : _a.classList.add("has-accordion");601sideAccordion.classList.add("accordion-flush");602}603if (this.layout.toggle) {604this._initEventListeners();605this._initSidebarCounters();606this._initDesktop();607}608_Sidebar.shinyResizeObserver.observe(this.layout.main);609container.removeAttribute("data-bslib-sidebar-init");610const initScript = container.querySelector(611":scope > script[data-bslib-sidebar-init]"612);613if (initScript) {614container.removeChild(initScript);615}616}617/**618* Read the current state of the sidebar. Note that, when calling this method,619* the sidebar may be transitioning into the state returned by this method.620*621* @description622* The sidebar state works as follows, starting from the open state. When the623* sidebar is closed:624* 1. We add both the `COLLAPSE` and `TRANSITIONING` classes to the sidebar.625* 2. The sidebar collapse begins to animate. On desktop devices, and where it626* is supported, we transition the `grid-template-columns` property of the627* sidebar layout. On mobile, the sidebar is hidden immediately. In both628* cases, the collapse icon rotates and we use this rotation to determine629* when the transition is complete.630* 3. If another sidebar state toggle is requested while closing the sidebar,631* we remove the `COLLAPSE` class and the animation immediately starts to632* reverse.633* 4. When the `transition` is complete, we remove the `TRANSITIONING` class.634* @readonly635* @type {boolean}636*/637get isClosed() {638return this.layout.container.classList.contains(_Sidebar.classes.COLLAPSE);639}640/**641* Given a sidebar container, return the Sidebar instance associated with it.642* @public643* @static644* @param {HTMLElement} el645* @returns {(Sidebar | undefined)}646*/647static getInstance(el) {648return _Sidebar.instanceMap.get(el);649}650/**651* Initialize all collapsible sidebars on the page.652* @public653* @static654* @param {boolean} [flushResizeObserver=true] When `true`, we remove655* non-existent elements from the ResizeObserver. This is required656* periodically to prevent memory leaks. To avoid over-checking, we only flush657* the ResizeObserver when initializing sidebars after page load.658*/659static initCollapsibleAll(flushResizeObserver = true) {660if (document.readyState === "loading") {661if (!_Sidebar.onReadyScheduled) {662_Sidebar.onReadyScheduled = true;663document.addEventListener("DOMContentLoaded", () => {664_Sidebar.initCollapsibleAll(false);665});666}667return;668}669const initSelector = `.${_Sidebar.classes.LAYOUT}[data-bslib-sidebar-init]`;670if (!document.querySelector(initSelector)) {671return;672}673if (flushResizeObserver)674_Sidebar.shinyResizeObserver.flush();675const containers = document.querySelectorAll(initSelector);676containers.forEach((container) => new _Sidebar(container));677}678/**679* Initialize event listeners for the sidebar toggle button.680* @private681*/682_initEventListeners() {683var _a;684const { toggle } = this.layout;685toggle.addEventListener("click", (ev) => {686ev.preventDefault();687this.toggle("toggle");688});689(_a = toggle.querySelector(".collapse-icon")) == null ? void 0 : _a.addEventListener("transitionend", () => this._finalizeState());690}691/**692* Initialize nested sidebar counters.693*694* @description695* This function walks up the DOM tree, adding CSS variables to each direct696* parent sidebar layout that count the layout's position in the stack of697* nested layouts. We use these counters to keep the collapse toggles from698* overlapping. Note that always-open sidebars that don't have collapse699* toggles break the chain of nesting.700* @private701*/702_initSidebarCounters() {703const { container } = this.layout;704const selectorChildLayouts = `.${_Sidebar.classes.LAYOUT}> .main > .${_Sidebar.classes.LAYOUT}:not([data-bslib-sidebar-open="always"])`;705const isInnermostLayout = container.querySelector(selectorChildLayouts) === null;706if (!isInnermostLayout) {707return;708}709function nextSidebarParent(el) {710el = el ? el.parentElement : null;711if (el && el.classList.contains("main")) {712el = el.parentElement;713}714if (el && el.classList.contains(_Sidebar.classes.LAYOUT)) {715return el;716}717return null;718}719const layouts = [container];720let parent = nextSidebarParent(container);721while (parent) {722layouts.unshift(parent);723parent = nextSidebarParent(parent);724}725const count = { left: 0, right: 0 };726layouts.forEach(function(x, i) {727x.style.setProperty("--bslib-sidebar-counter", i.toString());728const isRight = x.classList.contains("sidebar-right");729const thisCount = isRight ? count.right++ : count.left++;730x.style.setProperty(731"--bslib-sidebar-overlap-counter",732thisCount.toString()733);734});735}736/**737* Initialize the sidebar's initial state when `open = "desktop"`.738* @private739*/740_initDesktop() {741var _a;742const { container } = this.layout;743if (((_a = container.dataset.bslibSidebarOpen) == null ? void 0 : _a.trim()) !== "desktop") {744return;745}746const initCollapsed = window.getComputedStyle(container).getPropertyValue("--bslib-sidebar-js-init-collapsed");747if (initCollapsed.trim() === "true") {748this.toggle("close");749}750}751/**752* Toggle the sidebar's open/closed state.753* @public754* @param {SidebarToggleMethod | undefined} method Whether to `"open"`,755* `"close"` or `"toggle"` the sidebar. If `.toggle()` is called without an756* argument, it will toggle the sidebar's state.757*/758toggle(method) {759if (typeof method === "undefined") {760method = "toggle";761}762const { container, sidebar } = this.layout;763const isClosed = this.isClosed;764if (["open", "close", "toggle"].indexOf(method) === -1) {765throw new Error(`Unknown method ${method}`);766}767if (method === "toggle") {768method = isClosed ? "open" : "close";769}770if (isClosed && method === "close" || !isClosed && method === "open") {771return;772}773if (method === "open") {774sidebar.hidden = false;775}776container.classList.add(_Sidebar.classes.TRANSITIONING);777container.classList.toggle(_Sidebar.classes.COLLAPSE);778}779/**780* When the sidebar open/close transition ends, finalize the sidebar's state.781* @private782*/783_finalizeState() {784const { container, sidebar, toggle } = this.layout;785container.classList.remove(_Sidebar.classes.TRANSITIONING);786sidebar.hidden = this.isClosed;787toggle.setAttribute("aria-expanded", this.isClosed ? "false" : "true");788const event = new CustomEvent("bslib.sidebar", {789bubbles: true,790detail: { open: !this.isClosed }791});792sidebar.dispatchEvent(event);793$(sidebar).trigger("toggleCollapse.sidebarInputBinding");794$(sidebar).trigger(this.isClosed ? "hidden" : "shown");795}796};797var Sidebar = _Sidebar;798/**799* A Shiny-specific resize observer that ensures Shiny outputs in the main800* content areas of the sidebar resize appropriately.801* @private802* @type {ShinyResizeObserver}803* @static804*/805Sidebar.shinyResizeObserver = new ShinyResizeObserver();806/**807* Static classes related to the sidebar layout or state.808* @public809* @static810* @readonly811* @type {{ LAYOUT: string; COLLAPSE: string; TRANSITIONING: string; }}812*/813Sidebar.classes = {814// eslint-disable-next-line @typescript-eslint/naming-convention815LAYOUT: "bslib-sidebar-layout",816// eslint-disable-next-line @typescript-eslint/naming-convention817COLLAPSE: "sidebar-collapsed",818// eslint-disable-next-line @typescript-eslint/naming-convention819TRANSITIONING: "transitioning"820};821/**822* If sidebars are initialized before the DOM is ready, we re-schedule the823* initialization to occur on DOMContentLoaded.824* @private825* @static826* @type {boolean}827*/828Sidebar.onReadyScheduled = false;829/**830* A map of initialized sidebars to their respective Sidebar instances.831* @private832* @static833* @type {WeakMap<HTMLElement, Sidebar>}834*/835Sidebar.instanceMap = /* @__PURE__ */ new WeakMap();836var SidebarInputBinding = class extends InputBinding {837find(scope) {838return $(scope).find(`.${Sidebar.classes.LAYOUT} > .bslib-sidebar-input`);839}840getValue(el) {841const sb = Sidebar.getInstance(el.parentElement);842if (!sb)843return false;844return !sb.isClosed;845}846setValue(el, value) {847const method = value ? "open" : "close";848this.receiveMessage(el, { method });849}850subscribe(el, callback) {851$(el).on(852"toggleCollapse.sidebarInputBinding",853// eslint-disable-next-line @typescript-eslint/no-unused-vars854function(event) {855callback(true);856}857);858}859unsubscribe(el) {860$(el).off(".sidebarInputBinding");861}862receiveMessage(el, data) {863const sb = Sidebar.getInstance(el.parentElement);864if (sb)865sb.toggle(data.method);866}867};868registerBinding(SidebarInputBinding, "sidebar");869window.bslib = window.bslib || {};870window.bslib.Sidebar = Sidebar;871872// srcts/src/components/_shinyAddCustomMessageHandlers.ts873function shinyAddCustomMessageHandlers(handlers) {874if (!window.Shiny) {875return;876}877for (const [name, handler] of Object.entries(handlers)) {878Shiny.addCustomMessageHandler(name, handler);879}880}881882// srcts/src/components/index.ts883var bslibMessageHandlers = {884// eslint-disable-next-line @typescript-eslint/naming-convention885"bslib.toggle-input-binary": (msg) => {886const el = document.getElementById(msg.id);887if (!el) {888console.warn("[bslib.toggle-input-binary] No element found", msg);889}890const binding = $(el).data("shiny-input-binding");891if (!(binding instanceof InputBinding)) {892console.warn("[bslib.toggle-input-binary] No input binding found", msg);893return;894}895let value = msg.value;896if (typeof value === "undefined") {897value = !binding.getValue(el);898}899binding.receiveMessage(el, { value });900}901};902if (window.Shiny) {903shinyAddCustomMessageHandlers(bslibMessageHandlers);904}905function insertSvgGradient() {906const temp = document.createElement("div");907temp.innerHTML = `908<svg aria-hidden="true" focusable="false" style="width:0;height:0;position:absolute;">909<!-- ref: https://fvsch.com/svg-gradient-fill -->910<linearGradient id='bslib---icon-gradient' x1='0' y1='0' x2='1.6' y2='2.4'>911<stop offset='0%' stop-color='var(--bslib-icon-gradient-0, #007bc2)' />912<stop offset='14.29%' stop-color='var(--bslib-icon-gradient-1, #0770c9)' />913<stop offset='28.57%' stop-color='var(--bslib-icon-gradient-2, #0d63da)' />914<stop offset='42.86%' stop-color='var(--bslib-icon-gradient-3, #2b4af9)' />915<stop offset='57.14%' stop-color='var(--bslib-icon-gradient-4, #5e29f7)' />916<stop offset='71.43%' stop-color='var(--bslib-icon-gradient-5, #7217d7)' />917<stop offset='100%' stop-color='var(--bslib-icon-gradient-6, #74149c)' />918</linearGradient>919</svg>`;920document.body.appendChild(temp.children[0]);921}922if (document.readyState === "complete") {923insertSvgGradient();924} else {925document.addEventListener("DOMContentLoaded", insertSvgGradient);926}927})();928929930931