From 90aef6735ed485f0c6b36d633d7e6242b1a305fa Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Tue, 11 Jul 2023 21:10:36 -0400 Subject: [PATCH 1/3] feat(card): Use an attribute to signal card is in full screen Allows us to use [data-full-screen] to know card has full screen capabilities Or [data-full-screen="false"] to know card is collapsed (or ="true" to know it's expanded) --- R/card.R | 1 + inst/components/scss/card.scss | 6 +++--- srcts/src/components/card.ts | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/R/card.R b/R/card.R index d701894e5..2ee6fb194 100644 --- a/R/card.R +++ b/R/card.R @@ -68,6 +68,7 @@ card <- function(..., full_screen = FALSE, height = NULL, max_height = NULL, min min_height = validateCssUnit(min_height) ), "data-bslib-card-init" = NA, + "data-full-screen" = if (full_screen) "false", !!!attribs, !!!children, if (full_screen) full_screen_toggle(), diff --git a/inst/components/scss/card.scss b/inst/components/scss/card.scss index 213c79c91..050b5e88f 100644 --- a/inst/components/scss/card.scss +++ b/inst/components/scss/card.scss @@ -19,7 +19,7 @@ max-height: var(--bslib-card-body-max-height, none); } - &.bslib-full-screen > .card-body { + &[data-full-screen="true"] > .card-body { max-height: var(--bslib-card-body-max-height-full-screen, none); } @@ -67,7 +67,7 @@ * Full screen card logic *************************************************/ -.bslib-full-screen { +[data-full-screen="true"] { position: fixed; inset: 3.5rem 1rem 1rem; height: auto !important; @@ -93,7 +93,7 @@ z-index: $zindex-popover; } -.card:hover:not(.bslib-full-screen) > .bslib-full-screen-enter { +.card[data-full-screen="false"]:hover > .bslib-full-screen-enter { display: block; } diff --git a/srcts/src/components/card.ts b/srcts/src/components/card.ts index d983263c8..7f55bc1f2 100644 --- a/srcts/src/components/card.ts +++ b/srcts/src/components/card.ts @@ -60,7 +60,7 @@ class Card { // eslint-disable-next-line @typescript-eslint/naming-convention CLASS_CARD: "bslib-card", // eslint-disable-next-line @typescript-eslint/naming-convention - CLASS_FULL_SCREEN: "bslib-full-screen", + ATTR_FULL_SCREEN: "data-full-screen", // eslint-disable-next-line @typescript-eslint/naming-convention CLASS_HAS_FULL_SCREEN: "bslib-has-full-screen", // eslint-disable-next-line @typescript-eslint/naming-convention @@ -133,7 +133,7 @@ class Card { this.card.focus(); } - this.card.classList.add(Card.attr.CLASS_FULL_SCREEN); + this.card.setAttribute(Card.attr.ATTR_FULL_SCREEN, "true"); document.body.classList.add(Card.attr.CLASS_HAS_FULL_SCREEN); this.card.insertAdjacentElement("beforebegin", this.overlay.container); } @@ -153,7 +153,7 @@ class Card { // Remove overlay and remove full screen classes from card this.overlay.container.remove(); - this.card.classList.remove(Card.attr.CLASS_FULL_SCREEN); + this.card.setAttribute(Card.attr.ATTR_FULL_SCREEN, "false"); this.card.removeAttribute("tabindex"); document.body.classList.remove(Card.attr.CLASS_HAS_FULL_SCREEN); } From d1c9d9e1947eeff4d05f6f52d32108a4cb458e4d Mon Sep 17 00:00:00 2001 From: Garrick Aden-Buie Date: Wed, 12 Jul 2023 10:02:26 -0400 Subject: [PATCH 2/3] chore(card): yarn build --- inst/components/dist/card/card.js | 6 +++--- inst/components/dist/card/card.js.map | 4 ++-- inst/components/dist/card/card.min.js | 2 +- inst/components/dist/card/card.min.js.map | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/inst/components/dist/card/card.js b/inst/components/dist/card/card.js index 91bb68b60..fed1d7321 100644 --- a/inst/components/dist/card/card.js +++ b/inst/components/dist/card/card.js @@ -171,7 +171,7 @@ this.card.setAttribute("tabindex", "-1"); this.card.focus(); } - this.card.classList.add(_Card.attr.CLASS_FULL_SCREEN); + this.card.setAttribute(_Card.attr.ATTR_FULL_SCREEN, "true"); document.body.classList.add(_Card.attr.CLASS_HAS_FULL_SCREEN); this.card.insertAdjacentElement("beforebegin", this.overlay.container); } @@ -188,7 +188,7 @@ ); document.removeEventListener("keydown", this._trapFocusExit, true); this.overlay.container.remove(); - this.card.classList.remove(_Card.attr.CLASS_FULL_SCREEN); + this.card.setAttribute(_Card.attr.ATTR_FULL_SCREEN, "false"); this.card.removeAttribute("tabindex"); document.body.classList.remove(_Card.attr.CLASS_HAS_FULL_SCREEN); } @@ -382,7 +382,7 @@ // eslint-disable-next-line @typescript-eslint/naming-convention CLASS_CARD: "bslib-card", // eslint-disable-next-line @typescript-eslint/naming-convention - CLASS_FULL_SCREEN: "bslib-full-screen", + ATTR_FULL_SCREEN: "data-full-screen", // eslint-disable-next-line @typescript-eslint/naming-convention CLASS_HAS_FULL_SCREEN: "bslib-has-full-screen", // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/inst/components/dist/card/card.js.map b/inst/components/dist/card/card.js.map index 6b0dd7d87..32d24f9a2 100644 --- a/inst/components/dist/card/card.js.map +++ b/inst/components/dist/card/card.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../../../srcts/src/components/_utils.ts", "../../../../srcts/src/components/_shinyResizeObserver.ts", "../../../../srcts/src/components/card.ts"], - "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import type { Tooltip as TooltipType } from \"bootstrap\";\nimport { getAllFocusableChildren } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst Tooltip = (\n window.bootstrap ? window.bootstrap.Tooltip : class {}\n) as typeof TooltipType;\n\n/**\n * The overlay element that is placed behind the card when expanded full screen.\n *\n * @interface CardFullScreenOverlay\n * @typedef {CardFullScreenOverlay}\n */\ninterface CardFullScreenOverlay {\n /**\n * The full screen overlay container.\n * @type {HTMLDivElement}\n */\n container: HTMLDivElement;\n /**\n * The anchor element used to close the full screen overlay.\n * @type {HTMLAnchorElement}\n */\n anchor: HTMLAnchorElement;\n}\n\n/**\n * The bslib card component class.\n *\n * @class Card\n * @typedef {Card}\n */\nclass Card {\n /**\n * The card container element.\n * @private\n * @type {HTMLElement}\n */\n private card: HTMLElement;\n /**\n * The card's full screen overlay element. We create this element once and add\n * and remove it from the DOM as needed (this simplifies focus management\n * while in full screen mode).\n * @private\n * @type {CardFullScreenOverlay}\n */\n private overlay: CardFullScreenOverlay;\n\n /**\n * Key bslib-specific classes and attributes used by the card component.\n * @private\n * @static\n * @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; }}\n */\n private static attr = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ATTR_INIT: \"data-bslib-card-init\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_CARD: \"bslib-card\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN: \"bslib-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_HAS_FULL_SCREEN: \"bslib-has-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_ENTER: \"bslib-full-screen-enter\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_EXIT: \"bslib-full-screen-exit\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ID_FULL_SCREEN_OVERLAY: \"bslib-full-screen-overlay\",\n };\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in within the\n * card resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a bslib Card component.\n *\n * @constructor\n * @param {HTMLElement} card\n */\n constructor(card: HTMLElement) {\n // remove initialization attribute and script\n card.removeAttribute(Card.attr.ATTR_INIT);\n card\n .querySelector(`script[${Card.attr.ATTR_INIT}]`)\n ?.remove();\n\n this.card = card;\n Card.instanceMap.set(card, this);\n\n // Let Shiny know to trigger resize when the card size changes\n // TODO: shiny could/should do this itself (rstudio/shiny#3682)\n Card.shinyResizeObserver.observe(this.card);\n\n this._addEventListeners();\n this._enableTooltips();\n this.overlay = this._createOverlay();\n\n // bind event handler methods to this card instance\n this._exitFullScreenOnEscape = this._exitFullScreenOnEscape.bind(this);\n this._trapFocusExit = this._trapFocusExit.bind(this);\n }\n\n /**\n * Enter the card's full screen mode, either programmatically or via an event\n * handler. Full screen mode is activated by adding a class to the card that\n * positions it absolutely and expands it to fill the viewport. In addition,\n * we add a full screen overlay element behind the card and we trap focus in\n * the expanded card while in full screen mode.\n *\n * @param {?Event} [event]\n */\n enterFullScreen(event?: Event): void {\n if (event) event.preventDefault();\n\n document.addEventListener(\"keydown\", this._exitFullScreenOnEscape, false);\n\n // trap focus in the fullscreen container, listening for Tab key on the\n // capture phase so we have the best chance of preventing other handlers\n document.addEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Set initial focus on the card, if not already\n if (!this.card.contains(document.activeElement)) {\n this.card.setAttribute(\"tabindex\", \"-1\");\n this.card.focus();\n }\n\n this.card.classList.add(Card.attr.CLASS_FULL_SCREEN);\n document.body.classList.add(Card.attr.CLASS_HAS_FULL_SCREEN);\n this.card.insertAdjacentElement(\"beforebegin\", this.overlay.container);\n }\n\n /**\n * Exit full screen mode. This removes the full screen overlay element,\n * removes the full screen class from the card, and removes the keyboard event\n * listeners that were added when entering full screen mode.\n */\n exitFullScreen(): void {\n document.removeEventListener(\n \"keydown\",\n this._exitFullScreenOnEscape,\n false\n );\n document.removeEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Remove overlay and remove full screen classes from card\n this.overlay.container.remove();\n this.card.classList.remove(Card.attr.CLASS_FULL_SCREEN);\n this.card.removeAttribute(\"tabindex\");\n document.body.classList.remove(Card.attr.CLASS_HAS_FULL_SCREEN);\n }\n\n /**\n * Adds general card-specific event listeners.\n * @private\n */\n private _addEventListeners(): void {\n const btnFullScreen = this.card.querySelector(\n `:scope > .${Card.attr.CLASS_FULL_SCREEN_ENTER}`\n );\n if (!btnFullScreen) return;\n btnFullScreen.addEventListener(\"click\", (ev) => this.enterFullScreen(ev));\n }\n\n /**\n * Enable tooltips used by the card component.\n * @private\n */\n private _enableTooltips(): void {\n const selector = `.${Card.attr.CLASS_FULL_SCREEN_ENTER}[data-bs-toggle='tooltip']`;\n if (!this.card.querySelector(selector)) {\n return;\n }\n const tooltipList = this.card.querySelectorAll(selector);\n tooltipList.forEach((tt) => new Tooltip(tt));\n }\n\n /**\n * An event handler to exit full screen mode when the Escape key is pressed.\n * @private\n * @param {KeyboardEvent} event\n */\n private _exitFullScreenOnEscape(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLElement)) return;\n // If the user is in the middle of a select input choice, don't exit\n const selOpenSelectInput = [\"select[open]\", \"input[aria-expanded='true']\"];\n if (event.target.matches(selOpenSelectInput.join(\", \"))) return;\n\n if (event.key === \"Escape\") {\n this.exitFullScreen();\n }\n }\n\n /**\n * An event handler to trap focus within the card when in full screen mode.\n *\n * @description\n * This keyboard event handler ensures that tab focus stays within the card\n * when in full screen mode. When the card is first expanded,\n * we move focus to the card element itself. If focus somehow leaves the card,\n * we returns focus to the card container.\n *\n * Within the card, we handle only tabbing from the close anchor or the last\n * focusable element and only when tab focus would have otherwise left the\n * card. In those cases, we cycle focus to the last focusable element or back\n * to the anchor. If the card doesn't have any focusable elements, we move\n * focus to the close anchor.\n *\n * @note\n * Because the card contents may change, we check for focusable elements\n * every time the handler is called.\n *\n * @private\n * @param {KeyboardEvent} event\n */\n private _trapFocusExit(event: KeyboardEvent): void {\n if (!(event instanceof KeyboardEvent)) return;\n if (event.key !== \"Tab\") return;\n\n const isFocusedContainer = event.target === this.card;\n const isFocusedAnchor = event.target === this.overlay.anchor;\n const isFocusedWithin = this.card.contains(event.target as Node);\n\n const stopEvent = () => {\n event.preventDefault();\n event.stopImmediatePropagation();\n };\n\n if (!(isFocusedWithin || isFocusedContainer || isFocusedAnchor)) {\n // If focus is outside the card, return to the card\n stopEvent();\n this.card.focus();\n return;\n }\n\n // Check focusables every time because the card contents may have changed\n const focusableElements = getAllFocusableChildren(this.card);\n const hasFocusableElements = focusableElements.length > 0;\n\n // We need to handle five cases:\n // 1. The card has no focusable elements --> focus the anchor\n // 2. Focus is on the card container (do nothing, natural tab order)\n // 3. Focus is on the anchor and the user pressed Tab + Shift (backwards)\n // -> Move to the last focusable element (end of card)\n // 4. Focus is on the last focusable element and the user pressed Tab\n // (forwards) -> Move to the anchor (top of card)\n // 5. otherwise we don't interfere\n\n if (!hasFocusableElements) {\n // case 1\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n\n // case 2\n if (isFocusedContainer) return;\n\n const lastFocusable = focusableElements[focusableElements.length - 1];\n const isFocusedLast = event.target === lastFocusable;\n\n if (isFocusedAnchor && event.shiftKey) {\n stopEvent();\n lastFocusable.focus();\n return;\n }\n\n if (isFocusedLast && !event.shiftKey) {\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n }\n\n /**\n * Creates the full screen overlay.\n * @private\n * @returns {CardFullScreenOverlay}\n */\n private _createOverlay(): CardFullScreenOverlay {\n const container = document.createElement(\"div\");\n container.id = Card.attr.ID_FULL_SCREEN_OVERLAY;\n container.onclick = this.exitFullScreen.bind(this);\n\n const anchor = this._createOverlayCloseAnchor();\n container.appendChild(anchor);\n\n return { container, anchor };\n }\n\n /**\n * Creates the anchor element used to exit the full screen mode.\n * @private\n * @returns {HTMLAnchorElement}\n */\n private _createOverlayCloseAnchor(): HTMLAnchorElement {\n const anchor = document.createElement(\"a\");\n anchor.classList.add(Card.attr.CLASS_FULL_SCREEN_EXIT);\n anchor.tabIndex = 0;\n anchor.onclick = () => this.exitFullScreen();\n anchor.onkeydown = (ev) => {\n if (ev.key === \"Enter\" || ev.key === \" \") {\n this.exitFullScreen();\n }\n };\n anchor.innerHTML = this._overlayCloseHtml();\n\n return anchor;\n }\n\n /**\n * Returns the HTML for the close icon.\n * @private\n * @returns {string}\n */\n private _overlayCloseHtml(): string {\n return (\n \"Close \" +\n \"\" +\n \"\"\n );\n }\n\n /**\n * The registry of card instances and their associated DOM elements.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Returns the card instance associated with the given element, if any.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Card | undefined)}\n */\n public static getInstance(el: HTMLElement): Card | undefined {\n return Card.instanceMap.get(el);\n }\n\n /**\n * If cards are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n\n /**\n * Initializes all cards that require initialization on the page, or schedules\n * initialization if the DOM is not yet ready.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true]\n */\n public static initializeAllCards(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Card.onReadyScheduled) {\n Card.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Card.initializeAllCards(false);\n });\n }\n return;\n }\n\n if (flushResizeObserver) {\n // Trigger a recheck of observed cards to unobserve non-existent cards\n Card.shinyResizeObserver.flush();\n }\n\n const initSelector = `.${Card.attr.CLASS_CARD}[${Card.attr.ATTR_INIT}]`;\n if (!document.querySelector(initSelector)) {\n // no cards to initialize\n return;\n }\n\n const cards = document.querySelectorAll(initSelector);\n cards.forEach((card) => new Card(card as HTMLElement));\n }\n}\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Card = Card;\n\nexport { Card };\n"], - "mappings": "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", + "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import type { Tooltip as TooltipType } from \"bootstrap\";\nimport { getAllFocusableChildren } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst Tooltip = (\n window.bootstrap ? window.bootstrap.Tooltip : class {}\n) as typeof TooltipType;\n\n/**\n * The overlay element that is placed behind the card when expanded full screen.\n *\n * @interface CardFullScreenOverlay\n * @typedef {CardFullScreenOverlay}\n */\ninterface CardFullScreenOverlay {\n /**\n * The full screen overlay container.\n * @type {HTMLDivElement}\n */\n container: HTMLDivElement;\n /**\n * The anchor element used to close the full screen overlay.\n * @type {HTMLAnchorElement}\n */\n anchor: HTMLAnchorElement;\n}\n\n/**\n * The bslib card component class.\n *\n * @class Card\n * @typedef {Card}\n */\nclass Card {\n /**\n * The card container element.\n * @private\n * @type {HTMLElement}\n */\n private card: HTMLElement;\n /**\n * The card's full screen overlay element. We create this element once and add\n * and remove it from the DOM as needed (this simplifies focus management\n * while in full screen mode).\n * @private\n * @type {CardFullScreenOverlay}\n */\n private overlay: CardFullScreenOverlay;\n\n /**\n * Key bslib-specific classes and attributes used by the card component.\n * @private\n * @static\n * @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; }}\n */\n private static attr = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ATTR_INIT: \"data-bslib-card-init\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_CARD: \"bslib-card\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ATTR_FULL_SCREEN: \"data-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_HAS_FULL_SCREEN: \"bslib-has-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_ENTER: \"bslib-full-screen-enter\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_EXIT: \"bslib-full-screen-exit\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ID_FULL_SCREEN_OVERLAY: \"bslib-full-screen-overlay\",\n };\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in within the\n * card resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a bslib Card component.\n *\n * @constructor\n * @param {HTMLElement} card\n */\n constructor(card: HTMLElement) {\n // remove initialization attribute and script\n card.removeAttribute(Card.attr.ATTR_INIT);\n card\n .querySelector(`script[${Card.attr.ATTR_INIT}]`)\n ?.remove();\n\n this.card = card;\n Card.instanceMap.set(card, this);\n\n // Let Shiny know to trigger resize when the card size changes\n // TODO: shiny could/should do this itself (rstudio/shiny#3682)\n Card.shinyResizeObserver.observe(this.card);\n\n this._addEventListeners();\n this._enableTooltips();\n this.overlay = this._createOverlay();\n\n // bind event handler methods to this card instance\n this._exitFullScreenOnEscape = this._exitFullScreenOnEscape.bind(this);\n this._trapFocusExit = this._trapFocusExit.bind(this);\n }\n\n /**\n * Enter the card's full screen mode, either programmatically or via an event\n * handler. Full screen mode is activated by adding a class to the card that\n * positions it absolutely and expands it to fill the viewport. In addition,\n * we add a full screen overlay element behind the card and we trap focus in\n * the expanded card while in full screen mode.\n *\n * @param {?Event} [event]\n */\n enterFullScreen(event?: Event): void {\n if (event) event.preventDefault();\n\n document.addEventListener(\"keydown\", this._exitFullScreenOnEscape, false);\n\n // trap focus in the fullscreen container, listening for Tab key on the\n // capture phase so we have the best chance of preventing other handlers\n document.addEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Set initial focus on the card, if not already\n if (!this.card.contains(document.activeElement)) {\n this.card.setAttribute(\"tabindex\", \"-1\");\n this.card.focus();\n }\n\n this.card.setAttribute(Card.attr.ATTR_FULL_SCREEN, \"true\");\n document.body.classList.add(Card.attr.CLASS_HAS_FULL_SCREEN);\n this.card.insertAdjacentElement(\"beforebegin\", this.overlay.container);\n }\n\n /**\n * Exit full screen mode. This removes the full screen overlay element,\n * removes the full screen class from the card, and removes the keyboard event\n * listeners that were added when entering full screen mode.\n */\n exitFullScreen(): void {\n document.removeEventListener(\n \"keydown\",\n this._exitFullScreenOnEscape,\n false\n );\n document.removeEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Remove overlay and remove full screen classes from card\n this.overlay.container.remove();\n this.card.setAttribute(Card.attr.ATTR_FULL_SCREEN, \"false\");\n this.card.removeAttribute(\"tabindex\");\n document.body.classList.remove(Card.attr.CLASS_HAS_FULL_SCREEN);\n }\n\n /**\n * Adds general card-specific event listeners.\n * @private\n */\n private _addEventListeners(): void {\n const btnFullScreen = this.card.querySelector(\n `:scope > .${Card.attr.CLASS_FULL_SCREEN_ENTER}`\n );\n if (!btnFullScreen) return;\n btnFullScreen.addEventListener(\"click\", (ev) => this.enterFullScreen(ev));\n }\n\n /**\n * Enable tooltips used by the card component.\n * @private\n */\n private _enableTooltips(): void {\n const selector = `.${Card.attr.CLASS_FULL_SCREEN_ENTER}[data-bs-toggle='tooltip']`;\n if (!this.card.querySelector(selector)) {\n return;\n }\n const tooltipList = this.card.querySelectorAll(selector);\n tooltipList.forEach((tt) => new Tooltip(tt));\n }\n\n /**\n * An event handler to exit full screen mode when the Escape key is pressed.\n * @private\n * @param {KeyboardEvent} event\n */\n private _exitFullScreenOnEscape(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLElement)) return;\n // If the user is in the middle of a select input choice, don't exit\n const selOpenSelectInput = [\"select[open]\", \"input[aria-expanded='true']\"];\n if (event.target.matches(selOpenSelectInput.join(\", \"))) return;\n\n if (event.key === \"Escape\") {\n this.exitFullScreen();\n }\n }\n\n /**\n * An event handler to trap focus within the card when in full screen mode.\n *\n * @description\n * This keyboard event handler ensures that tab focus stays within the card\n * when in full screen mode. When the card is first expanded,\n * we move focus to the card element itself. If focus somehow leaves the card,\n * we returns focus to the card container.\n *\n * Within the card, we handle only tabbing from the close anchor or the last\n * focusable element and only when tab focus would have otherwise left the\n * card. In those cases, we cycle focus to the last focusable element or back\n * to the anchor. If the card doesn't have any focusable elements, we move\n * focus to the close anchor.\n *\n * @note\n * Because the card contents may change, we check for focusable elements\n * every time the handler is called.\n *\n * @private\n * @param {KeyboardEvent} event\n */\n private _trapFocusExit(event: KeyboardEvent): void {\n if (!(event instanceof KeyboardEvent)) return;\n if (event.key !== \"Tab\") return;\n\n const isFocusedContainer = event.target === this.card;\n const isFocusedAnchor = event.target === this.overlay.anchor;\n const isFocusedWithin = this.card.contains(event.target as Node);\n\n const stopEvent = () => {\n event.preventDefault();\n event.stopImmediatePropagation();\n };\n\n if (!(isFocusedWithin || isFocusedContainer || isFocusedAnchor)) {\n // If focus is outside the card, return to the card\n stopEvent();\n this.card.focus();\n return;\n }\n\n // Check focusables every time because the card contents may have changed\n const focusableElements = getAllFocusableChildren(this.card);\n const hasFocusableElements = focusableElements.length > 0;\n\n // We need to handle five cases:\n // 1. The card has no focusable elements --> focus the anchor\n // 2. Focus is on the card container (do nothing, natural tab order)\n // 3. Focus is on the anchor and the user pressed Tab + Shift (backwards)\n // -> Move to the last focusable element (end of card)\n // 4. Focus is on the last focusable element and the user pressed Tab\n // (forwards) -> Move to the anchor (top of card)\n // 5. otherwise we don't interfere\n\n if (!hasFocusableElements) {\n // case 1\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n\n // case 2\n if (isFocusedContainer) return;\n\n const lastFocusable = focusableElements[focusableElements.length - 1];\n const isFocusedLast = event.target === lastFocusable;\n\n if (isFocusedAnchor && event.shiftKey) {\n stopEvent();\n lastFocusable.focus();\n return;\n }\n\n if (isFocusedLast && !event.shiftKey) {\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n }\n\n /**\n * Creates the full screen overlay.\n * @private\n * @returns {CardFullScreenOverlay}\n */\n private _createOverlay(): CardFullScreenOverlay {\n const container = document.createElement(\"div\");\n container.id = Card.attr.ID_FULL_SCREEN_OVERLAY;\n container.onclick = this.exitFullScreen.bind(this);\n\n const anchor = this._createOverlayCloseAnchor();\n container.appendChild(anchor);\n\n return { container, anchor };\n }\n\n /**\n * Creates the anchor element used to exit the full screen mode.\n * @private\n * @returns {HTMLAnchorElement}\n */\n private _createOverlayCloseAnchor(): HTMLAnchorElement {\n const anchor = document.createElement(\"a\");\n anchor.classList.add(Card.attr.CLASS_FULL_SCREEN_EXIT);\n anchor.tabIndex = 0;\n anchor.onclick = () => this.exitFullScreen();\n anchor.onkeydown = (ev) => {\n if (ev.key === \"Enter\" || ev.key === \" \") {\n this.exitFullScreen();\n }\n };\n anchor.innerHTML = this._overlayCloseHtml();\n\n return anchor;\n }\n\n /**\n * Returns the HTML for the close icon.\n * @private\n * @returns {string}\n */\n private _overlayCloseHtml(): string {\n return (\n \"Close \" +\n \"\" +\n \"\"\n );\n }\n\n /**\n * The registry of card instances and their associated DOM elements.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Returns the card instance associated with the given element, if any.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Card | undefined)}\n */\n public static getInstance(el: HTMLElement): Card | undefined {\n return Card.instanceMap.get(el);\n }\n\n /**\n * If cards are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n\n /**\n * Initializes all cards that require initialization on the page, or schedules\n * initialization if the DOM is not yet ready.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true]\n */\n public static initializeAllCards(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Card.onReadyScheduled) {\n Card.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Card.initializeAllCards(false);\n });\n }\n return;\n }\n\n if (flushResizeObserver) {\n // Trigger a recheck of observed cards to unobserve non-existent cards\n Card.shinyResizeObserver.flush();\n }\n\n const initSelector = `.${Card.attr.CLASS_CARD}[${Card.attr.ATTR_INIT}]`;\n if (!document.querySelector(initSelector)) {\n // no cards to initialize\n return;\n }\n\n const cards = document.querySelectorAll(initSelector);\n cards.forEach((card) => new Card(card as HTMLElement));\n }\n}\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Card = Card;\n\nexport { Card };\n"], + "mappings": "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", "names": [] } diff --git a/inst/components/dist/card/card.min.js b/inst/components/dist/card/card.min.js index 28f26fa3e..9acb3c666 100644 --- a/inst/components/dist/card/card.min.js +++ b/inst/components/dist/card/card.min.js @@ -1,3 +1,3 @@ /*! bslib 0.5.0.9000 | (c) 2012-2023 RStudio, PBC. | License: MIT + file LICENSE */ -"use strict";(()=>{var b=window.Shiny?Shiny.InputBinding:class{};function p(u){let e=["a[href]","area[href]","button","details summary","input","iframe","select","textarea",'[contentEditable=""]','[contentEditable="true"]','[contentEditable="TRUE"]',"[tabindex]"],t=[':not([tabindex="-1"])',":not([disabled])"],r=e.map(n=>n+t.join("")),s=u.querySelectorAll(r.join(", "));return Array.from(s)}var d=class{constructor(){this.resizeObserverEntries=[],this.resizeObserver=new ResizeObserver(e=>{let t=new Event("resize");if(window.dispatchEvent(t),!window.Shiny)return;let r=[];for(let s of e)s.target instanceof HTMLElement&&s.target.querySelector(".shiny-bound-output")&&s.target.querySelectorAll(".shiny-bound-output").forEach(n=>{if(r.includes(n))return;let{binding:a,onResize:h}=$(n).data("shinyOutputBinding");if(!a||!a.resize)return;let c=n.shinyResizeObserver;if(c&&c!==this||(c||(n.shinyResizeObserver=this),h(n),r.push(n),!n.classList.contains("shiny-plot-output")))return;let l=n.querySelector('img:not([width="100%"])');l&&l.setAttribute("width","100%")})})}observe(e){this.resizeObserver.observe(e),this.resizeObserverEntries.push(e)}unobserve(e){let t=this.resizeObserverEntries.indexOf(e);t<0||(this.resizeObserver.unobserve(e),this.resizeObserverEntries.splice(t,1))}flush(){this.resizeObserverEntries.forEach(e=>{document.body.contains(e)||this.unobserve(e)})}};var E=window.bootstrap?window.bootstrap.Tooltip:class{},i=class{constructor(e){var t;e.removeAttribute(i.attr.ATTR_INIT),(t=e.querySelector(`script[${i.attr.ATTR_INIT}]`))==null||t.remove(),this.card=e,i.instanceMap.set(e,this),i.shinyResizeObserver.observe(this.card),this._addEventListeners(),this._enableTooltips(),this.overlay=this._createOverlay(),this._exitFullScreenOnEscape=this._exitFullScreenOnEscape.bind(this),this._trapFocusExit=this._trapFocusExit.bind(this)}enterFullScreen(e){e&&e.preventDefault(),document.addEventListener("keydown",this._exitFullScreenOnEscape,!1),document.addEventListener("keydown",this._trapFocusExit,!0),this.card.contains(document.activeElement)||(this.card.setAttribute("tabindex","-1"),this.card.focus()),this.card.classList.add(i.attr.CLASS_FULL_SCREEN),document.body.classList.add(i.attr.CLASS_HAS_FULL_SCREEN),this.card.insertAdjacentElement("beforebegin",this.overlay.container)}exitFullScreen(){document.removeEventListener("keydown",this._exitFullScreenOnEscape,!1),document.removeEventListener("keydown",this._trapFocusExit,!0),this.overlay.container.remove(),this.card.classList.remove(i.attr.CLASS_FULL_SCREEN),this.card.removeAttribute("tabindex"),document.body.classList.remove(i.attr.CLASS_HAS_FULL_SCREEN)}_addEventListeners(){let e=this.card.querySelector(`:scope > .${i.attr.CLASS_FULL_SCREEN_ENTER}`);e&&e.addEventListener("click",t=>this.enterFullScreen(t))}_enableTooltips(){let e=`.${i.attr.CLASS_FULL_SCREEN_ENTER}[data-bs-toggle='tooltip']`;if(!this.card.querySelector(e))return;this.card.querySelectorAll(e).forEach(r=>new E(r))}_exitFullScreenOnEscape(e){if(!(e.target instanceof HTMLElement))return;let t=["select[open]","input[aria-expanded='true']"];e.target.matches(t.join(", "))||e.key==="Escape"&&this.exitFullScreen()}_trapFocusExit(e){if(!(e instanceof KeyboardEvent)||e.key!=="Tab")return;let t=e.target===this.card,r=e.target===this.overlay.anchor,s=this.card.contains(e.target),n=()=>{e.preventDefault(),e.stopImmediatePropagation()};if(!(s||t||r)){n(),this.card.focus();return}let a=p(this.card);if(!(a.length>0)){n(),this.overlay.anchor.focus();return}if(t)return;let c=a[a.length-1],l=e.target===c;if(r&&e.shiftKey){n(),c.focus();return}if(l&&!e.shiftKey){n(),this.overlay.anchor.focus();return}}_createOverlay(){let e=document.createElement("div");e.id=i.attr.ID_FULL_SCREEN_OVERLAY,e.onclick=this.exitFullScreen.bind(this);let t=this._createOverlayCloseAnchor();return e.appendChild(t),{container:e,anchor:t}}_createOverlayCloseAnchor(){let e=document.createElement("a");return e.classList.add(i.attr.CLASS_FULL_SCREEN_EXIT),e.tabIndex=0,e.onclick=()=>this.exitFullScreen(),e.onkeydown=t=>{(t.key==="Enter"||t.key===" ")&&this.exitFullScreen()},e.innerHTML=this._overlayCloseHtml(),e}_overlayCloseHtml(){return"Close "}static getInstance(e){return i.instanceMap.get(e)}static initializeAllCards(e=!0){if(document.readyState==="loading"){i.onReadyScheduled||(i.onReadyScheduled=!0,document.addEventListener("DOMContentLoaded",()=>{i.initializeAllCards(!1)}));return}e&&i.shinyResizeObserver.flush();let t=`.${i.attr.CLASS_CARD}[${i.attr.ATTR_INIT}]`;if(!document.querySelector(t))return;document.querySelectorAll(t).forEach(s=>new i(s))}},o=i;o.attr={ATTR_INIT:"data-bslib-card-init",CLASS_CARD:"bslib-card",CLASS_FULL_SCREEN:"bslib-full-screen",CLASS_HAS_FULL_SCREEN:"bslib-has-full-screen",CLASS_FULL_SCREEN_ENTER:"bslib-full-screen-enter",CLASS_FULL_SCREEN_EXIT:"bslib-full-screen-exit",ID_FULL_SCREEN_OVERLAY:"bslib-full-screen-overlay"},o.shinyResizeObserver=new d,o.instanceMap=new WeakMap,o.onReadyScheduled=!1;window.bslib=window.bslib||{};window.bslib.Card=o;})(); +"use strict";(()=>{var b=window.Shiny?Shiny.InputBinding:class{};function p(u){let e=["a[href]","area[href]","button","details summary","input","iframe","select","textarea",'[contentEditable=""]','[contentEditable="true"]','[contentEditable="TRUE"]',"[tabindex]"],t=[':not([tabindex="-1"])',":not([disabled])"],r=e.map(n=>n+t.join("")),s=u.querySelectorAll(r.join(", "));return Array.from(s)}var d=class{constructor(){this.resizeObserverEntries=[],this.resizeObserver=new ResizeObserver(e=>{let t=new Event("resize");if(window.dispatchEvent(t),!window.Shiny)return;let r=[];for(let s of e)s.target instanceof HTMLElement&&s.target.querySelector(".shiny-bound-output")&&s.target.querySelectorAll(".shiny-bound-output").forEach(n=>{if(r.includes(n))return;let{binding:a,onResize:h}=$(n).data("shinyOutputBinding");if(!a||!a.resize)return;let c=n.shinyResizeObserver;if(c&&c!==this||(c||(n.shinyResizeObserver=this),h(n),r.push(n),!n.classList.contains("shiny-plot-output")))return;let l=n.querySelector('img:not([width="100%"])');l&&l.setAttribute("width","100%")})})}observe(e){this.resizeObserver.observe(e),this.resizeObserverEntries.push(e)}unobserve(e){let t=this.resizeObserverEntries.indexOf(e);t<0||(this.resizeObserver.unobserve(e),this.resizeObserverEntries.splice(t,1))}flush(){this.resizeObserverEntries.forEach(e=>{document.body.contains(e)||this.unobserve(e)})}};var E=window.bootstrap?window.bootstrap.Tooltip:class{},i=class{constructor(e){var t;e.removeAttribute(i.attr.ATTR_INIT),(t=e.querySelector(`script[${i.attr.ATTR_INIT}]`))==null||t.remove(),this.card=e,i.instanceMap.set(e,this),i.shinyResizeObserver.observe(this.card),this._addEventListeners(),this._enableTooltips(),this.overlay=this._createOverlay(),this._exitFullScreenOnEscape=this._exitFullScreenOnEscape.bind(this),this._trapFocusExit=this._trapFocusExit.bind(this)}enterFullScreen(e){e&&e.preventDefault(),document.addEventListener("keydown",this._exitFullScreenOnEscape,!1),document.addEventListener("keydown",this._trapFocusExit,!0),this.card.contains(document.activeElement)||(this.card.setAttribute("tabindex","-1"),this.card.focus()),this.card.setAttribute(i.attr.ATTR_FULL_SCREEN,"true"),document.body.classList.add(i.attr.CLASS_HAS_FULL_SCREEN),this.card.insertAdjacentElement("beforebegin",this.overlay.container)}exitFullScreen(){document.removeEventListener("keydown",this._exitFullScreenOnEscape,!1),document.removeEventListener("keydown",this._trapFocusExit,!0),this.overlay.container.remove(),this.card.setAttribute(i.attr.ATTR_FULL_SCREEN,"false"),this.card.removeAttribute("tabindex"),document.body.classList.remove(i.attr.CLASS_HAS_FULL_SCREEN)}_addEventListeners(){let e=this.card.querySelector(`:scope > .${i.attr.CLASS_FULL_SCREEN_ENTER}`);e&&e.addEventListener("click",t=>this.enterFullScreen(t))}_enableTooltips(){let e=`.${i.attr.CLASS_FULL_SCREEN_ENTER}[data-bs-toggle='tooltip']`;if(!this.card.querySelector(e))return;this.card.querySelectorAll(e).forEach(r=>new E(r))}_exitFullScreenOnEscape(e){if(!(e.target instanceof HTMLElement))return;let t=["select[open]","input[aria-expanded='true']"];e.target.matches(t.join(", "))||e.key==="Escape"&&this.exitFullScreen()}_trapFocusExit(e){if(!(e instanceof KeyboardEvent)||e.key!=="Tab")return;let t=e.target===this.card,r=e.target===this.overlay.anchor,s=this.card.contains(e.target),n=()=>{e.preventDefault(),e.stopImmediatePropagation()};if(!(s||t||r)){n(),this.card.focus();return}let a=p(this.card);if(!(a.length>0)){n(),this.overlay.anchor.focus();return}if(t)return;let c=a[a.length-1],l=e.target===c;if(r&&e.shiftKey){n(),c.focus();return}if(l&&!e.shiftKey){n(),this.overlay.anchor.focus();return}}_createOverlay(){let e=document.createElement("div");e.id=i.attr.ID_FULL_SCREEN_OVERLAY,e.onclick=this.exitFullScreen.bind(this);let t=this._createOverlayCloseAnchor();return e.appendChild(t),{container:e,anchor:t}}_createOverlayCloseAnchor(){let e=document.createElement("a");return e.classList.add(i.attr.CLASS_FULL_SCREEN_EXIT),e.tabIndex=0,e.onclick=()=>this.exitFullScreen(),e.onkeydown=t=>{(t.key==="Enter"||t.key===" ")&&this.exitFullScreen()},e.innerHTML=this._overlayCloseHtml(),e}_overlayCloseHtml(){return"Close "}static getInstance(e){return i.instanceMap.get(e)}static initializeAllCards(e=!0){if(document.readyState==="loading"){i.onReadyScheduled||(i.onReadyScheduled=!0,document.addEventListener("DOMContentLoaded",()=>{i.initializeAllCards(!1)}));return}e&&i.shinyResizeObserver.flush();let t=`.${i.attr.CLASS_CARD}[${i.attr.ATTR_INIT}]`;if(!document.querySelector(t))return;document.querySelectorAll(t).forEach(s=>new i(s))}},o=i;o.attr={ATTR_INIT:"data-bslib-card-init",CLASS_CARD:"bslib-card",ATTR_FULL_SCREEN:"data-full-screen",CLASS_HAS_FULL_SCREEN:"bslib-has-full-screen",CLASS_FULL_SCREEN_ENTER:"bslib-full-screen-enter",CLASS_FULL_SCREEN_EXIT:"bslib-full-screen-exit",ID_FULL_SCREEN_OVERLAY:"bslib-full-screen-overlay"},o.shinyResizeObserver=new d,o.instanceMap=new WeakMap,o.onReadyScheduled=!1;window.bslib=window.bslib||{};window.bslib.Card=o;})(); //# sourceMappingURL=card.min.js.map diff --git a/inst/components/dist/card/card.min.js.map b/inst/components/dist/card/card.min.js.map index 2b13a8483..1ae857dcf 100644 --- a/inst/components/dist/card/card.min.js.map +++ b/inst/components/dist/card/card.min.js.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../../../../srcts/src/components/_utils.ts", "../../../../srcts/src/components/_shinyResizeObserver.ts", "../../../../srcts/src/components/card.ts"], - "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import type { Tooltip as TooltipType } from \"bootstrap\";\nimport { getAllFocusableChildren } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst Tooltip = (\n window.bootstrap ? window.bootstrap.Tooltip : class {}\n) as typeof TooltipType;\n\n/**\n * The overlay element that is placed behind the card when expanded full screen.\n *\n * @interface CardFullScreenOverlay\n * @typedef {CardFullScreenOverlay}\n */\ninterface CardFullScreenOverlay {\n /**\n * The full screen overlay container.\n * @type {HTMLDivElement}\n */\n container: HTMLDivElement;\n /**\n * The anchor element used to close the full screen overlay.\n * @type {HTMLAnchorElement}\n */\n anchor: HTMLAnchorElement;\n}\n\n/**\n * The bslib card component class.\n *\n * @class Card\n * @typedef {Card}\n */\nclass Card {\n /**\n * The card container element.\n * @private\n * @type {HTMLElement}\n */\n private card: HTMLElement;\n /**\n * The card's full screen overlay element. We create this element once and add\n * and remove it from the DOM as needed (this simplifies focus management\n * while in full screen mode).\n * @private\n * @type {CardFullScreenOverlay}\n */\n private overlay: CardFullScreenOverlay;\n\n /**\n * Key bslib-specific classes and attributes used by the card component.\n * @private\n * @static\n * @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; }}\n */\n private static attr = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ATTR_INIT: \"data-bslib-card-init\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_CARD: \"bslib-card\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN: \"bslib-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_HAS_FULL_SCREEN: \"bslib-has-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_ENTER: \"bslib-full-screen-enter\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_EXIT: \"bslib-full-screen-exit\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ID_FULL_SCREEN_OVERLAY: \"bslib-full-screen-overlay\",\n };\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in within the\n * card resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a bslib Card component.\n *\n * @constructor\n * @param {HTMLElement} card\n */\n constructor(card: HTMLElement) {\n // remove initialization attribute and script\n card.removeAttribute(Card.attr.ATTR_INIT);\n card\n .querySelector(`script[${Card.attr.ATTR_INIT}]`)\n ?.remove();\n\n this.card = card;\n Card.instanceMap.set(card, this);\n\n // Let Shiny know to trigger resize when the card size changes\n // TODO: shiny could/should do this itself (rstudio/shiny#3682)\n Card.shinyResizeObserver.observe(this.card);\n\n this._addEventListeners();\n this._enableTooltips();\n this.overlay = this._createOverlay();\n\n // bind event handler methods to this card instance\n this._exitFullScreenOnEscape = this._exitFullScreenOnEscape.bind(this);\n this._trapFocusExit = this._trapFocusExit.bind(this);\n }\n\n /**\n * Enter the card's full screen mode, either programmatically or via an event\n * handler. Full screen mode is activated by adding a class to the card that\n * positions it absolutely and expands it to fill the viewport. In addition,\n * we add a full screen overlay element behind the card and we trap focus in\n * the expanded card while in full screen mode.\n *\n * @param {?Event} [event]\n */\n enterFullScreen(event?: Event): void {\n if (event) event.preventDefault();\n\n document.addEventListener(\"keydown\", this._exitFullScreenOnEscape, false);\n\n // trap focus in the fullscreen container, listening for Tab key on the\n // capture phase so we have the best chance of preventing other handlers\n document.addEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Set initial focus on the card, if not already\n if (!this.card.contains(document.activeElement)) {\n this.card.setAttribute(\"tabindex\", \"-1\");\n this.card.focus();\n }\n\n this.card.classList.add(Card.attr.CLASS_FULL_SCREEN);\n document.body.classList.add(Card.attr.CLASS_HAS_FULL_SCREEN);\n this.card.insertAdjacentElement(\"beforebegin\", this.overlay.container);\n }\n\n /**\n * Exit full screen mode. This removes the full screen overlay element,\n * removes the full screen class from the card, and removes the keyboard event\n * listeners that were added when entering full screen mode.\n */\n exitFullScreen(): void {\n document.removeEventListener(\n \"keydown\",\n this._exitFullScreenOnEscape,\n false\n );\n document.removeEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Remove overlay and remove full screen classes from card\n this.overlay.container.remove();\n this.card.classList.remove(Card.attr.CLASS_FULL_SCREEN);\n this.card.removeAttribute(\"tabindex\");\n document.body.classList.remove(Card.attr.CLASS_HAS_FULL_SCREEN);\n }\n\n /**\n * Adds general card-specific event listeners.\n * @private\n */\n private _addEventListeners(): void {\n const btnFullScreen = this.card.querySelector(\n `:scope > .${Card.attr.CLASS_FULL_SCREEN_ENTER}`\n );\n if (!btnFullScreen) return;\n btnFullScreen.addEventListener(\"click\", (ev) => this.enterFullScreen(ev));\n }\n\n /**\n * Enable tooltips used by the card component.\n * @private\n */\n private _enableTooltips(): void {\n const selector = `.${Card.attr.CLASS_FULL_SCREEN_ENTER}[data-bs-toggle='tooltip']`;\n if (!this.card.querySelector(selector)) {\n return;\n }\n const tooltipList = this.card.querySelectorAll(selector);\n tooltipList.forEach((tt) => new Tooltip(tt));\n }\n\n /**\n * An event handler to exit full screen mode when the Escape key is pressed.\n * @private\n * @param {KeyboardEvent} event\n */\n private _exitFullScreenOnEscape(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLElement)) return;\n // If the user is in the middle of a select input choice, don't exit\n const selOpenSelectInput = [\"select[open]\", \"input[aria-expanded='true']\"];\n if (event.target.matches(selOpenSelectInput.join(\", \"))) return;\n\n if (event.key === \"Escape\") {\n this.exitFullScreen();\n }\n }\n\n /**\n * An event handler to trap focus within the card when in full screen mode.\n *\n * @description\n * This keyboard event handler ensures that tab focus stays within the card\n * when in full screen mode. When the card is first expanded,\n * we move focus to the card element itself. If focus somehow leaves the card,\n * we returns focus to the card container.\n *\n * Within the card, we handle only tabbing from the close anchor or the last\n * focusable element and only when tab focus would have otherwise left the\n * card. In those cases, we cycle focus to the last focusable element or back\n * to the anchor. If the card doesn't have any focusable elements, we move\n * focus to the close anchor.\n *\n * @note\n * Because the card contents may change, we check for focusable elements\n * every time the handler is called.\n *\n * @private\n * @param {KeyboardEvent} event\n */\n private _trapFocusExit(event: KeyboardEvent): void {\n if (!(event instanceof KeyboardEvent)) return;\n if (event.key !== \"Tab\") return;\n\n const isFocusedContainer = event.target === this.card;\n const isFocusedAnchor = event.target === this.overlay.anchor;\n const isFocusedWithin = this.card.contains(event.target as Node);\n\n const stopEvent = () => {\n event.preventDefault();\n event.stopImmediatePropagation();\n };\n\n if (!(isFocusedWithin || isFocusedContainer || isFocusedAnchor)) {\n // If focus is outside the card, return to the card\n stopEvent();\n this.card.focus();\n return;\n }\n\n // Check focusables every time because the card contents may have changed\n const focusableElements = getAllFocusableChildren(this.card);\n const hasFocusableElements = focusableElements.length > 0;\n\n // We need to handle five cases:\n // 1. The card has no focusable elements --> focus the anchor\n // 2. Focus is on the card container (do nothing, natural tab order)\n // 3. Focus is on the anchor and the user pressed Tab + Shift (backwards)\n // -> Move to the last focusable element (end of card)\n // 4. Focus is on the last focusable element and the user pressed Tab\n // (forwards) -> Move to the anchor (top of card)\n // 5. otherwise we don't interfere\n\n if (!hasFocusableElements) {\n // case 1\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n\n // case 2\n if (isFocusedContainer) return;\n\n const lastFocusable = focusableElements[focusableElements.length - 1];\n const isFocusedLast = event.target === lastFocusable;\n\n if (isFocusedAnchor && event.shiftKey) {\n stopEvent();\n lastFocusable.focus();\n return;\n }\n\n if (isFocusedLast && !event.shiftKey) {\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n }\n\n /**\n * Creates the full screen overlay.\n * @private\n * @returns {CardFullScreenOverlay}\n */\n private _createOverlay(): CardFullScreenOverlay {\n const container = document.createElement(\"div\");\n container.id = Card.attr.ID_FULL_SCREEN_OVERLAY;\n container.onclick = this.exitFullScreen.bind(this);\n\n const anchor = this._createOverlayCloseAnchor();\n container.appendChild(anchor);\n\n return { container, anchor };\n }\n\n /**\n * Creates the anchor element used to exit the full screen mode.\n * @private\n * @returns {HTMLAnchorElement}\n */\n private _createOverlayCloseAnchor(): HTMLAnchorElement {\n const anchor = document.createElement(\"a\");\n anchor.classList.add(Card.attr.CLASS_FULL_SCREEN_EXIT);\n anchor.tabIndex = 0;\n anchor.onclick = () => this.exitFullScreen();\n anchor.onkeydown = (ev) => {\n if (ev.key === \"Enter\" || ev.key === \" \") {\n this.exitFullScreen();\n }\n };\n anchor.innerHTML = this._overlayCloseHtml();\n\n return anchor;\n }\n\n /**\n * Returns the HTML for the close icon.\n * @private\n * @returns {string}\n */\n private _overlayCloseHtml(): string {\n return (\n \"Close \" +\n \"\" +\n \"\"\n );\n }\n\n /**\n * The registry of card instances and their associated DOM elements.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Returns the card instance associated with the given element, if any.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Card | undefined)}\n */\n public static getInstance(el: HTMLElement): Card | undefined {\n return Card.instanceMap.get(el);\n }\n\n /**\n * If cards are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n\n /**\n * Initializes all cards that require initialization on the page, or schedules\n * initialization if the DOM is not yet ready.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true]\n */\n public static initializeAllCards(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Card.onReadyScheduled) {\n Card.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Card.initializeAllCards(false);\n });\n }\n return;\n }\n\n if (flushResizeObserver) {\n // Trigger a recheck of observed cards to unobserve non-existent cards\n Card.shinyResizeObserver.flush();\n }\n\n const initSelector = `.${Card.attr.CLASS_CARD}[${Card.attr.ATTR_INIT}]`;\n if (!document.querySelector(initSelector)) {\n // no cards to initialize\n return;\n }\n\n const cards = document.querySelectorAll(initSelector);\n cards.forEach((card) => new Card(card as HTMLElement));\n }\n}\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Card = Card;\n\nexport { Card };\n"], - "mappings": "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", + "sourcesContent": ["import type { HtmlDep } from \"rstudio-shiny/srcts/types/src/shiny/render\";\n\nimport type { InputBinding as InputBindingType } from \"rstudio-shiny/srcts/types/src/bindings/input\";\n\n// Exclude undefined from T\ntype NotUndefined = T extends undefined ? never : T;\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst InputBinding = (\n window.Shiny ? Shiny.InputBinding : class {}\n) as typeof InputBindingType;\n\nfunction registerBinding(\n inputBindingClass: new () => InputBindingType,\n name: string\n): void {\n if (window.Shiny) {\n Shiny.inputBindings.register(new inputBindingClass(), \"bslib.\" + name);\n }\n}\n\n// Return true if the key exists on the object and the value is not undefined.\n//\n// This method is mainly used in input bindings' `receiveMessage` method.\n// Since we know that the values are sent by Shiny via `{jsonlite}`,\n// then we know that there are no `undefined` values. `null` is possible, but not `undefined`.\nfunction hasDefinedProperty<\n Prop extends keyof X,\n X extends { [key: string]: any }\n>(\n obj: X,\n prop: Prop\n): obj is X & { [key in NonNullable]: NotUndefined } {\n return (\n Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== undefined\n );\n}\n\n// TODO: Shiny should trigger resize events when the output\n// https://github.com/rstudio/shiny/pull/3682\nfunction doWindowResizeOnElementResize(el: HTMLElement): void {\n if ($(el).data(\"window-resize-observer\")) {\n return;\n }\n const resizeEvent = new Event(\"resize\");\n const ro = new ResizeObserver(() => {\n window.dispatchEvent(resizeEvent);\n });\n ro.observe(el);\n $(el).data(\"window-resize-observer\", ro);\n}\n\nfunction getAllFocusableChildren(el: HTMLElement): HTMLElement[] {\n // Cross-referenced with https://allyjs.io/data-tables/focusable.html\n const base = [\n \"a[href]\",\n \"area[href]\",\n \"button\",\n \"details summary\",\n \"input\",\n \"iframe\",\n \"select\",\n \"textarea\",\n '[contentEditable=\"\"]',\n '[contentEditable=\"true\"]',\n '[contentEditable=\"TRUE\"]',\n \"[tabindex]\",\n ];\n const modifiers = [':not([tabindex=\"-1\"])', \":not([disabled])\"];\n const selectors = base.map((b) => b + modifiers.join(\"\"));\n const focusable = el.querySelectorAll(selectors.join(\", \"));\n return Array.from(focusable) as HTMLElement[];\n}\n\nexport {\n InputBinding,\n registerBinding,\n hasDefinedProperty,\n doWindowResizeOnElementResize,\n getAllFocusableChildren,\n};\nexport type { HtmlDep };\n", "/**\n * A resize observer that ensures Shiny outputs resize during or just after\n * their parent container size changes. Useful, in particular, for sidebar\n * transitions or for full-screen card transitions.\n *\n * @class ShinyResizeObserver\n * @typedef {ShinyResizeObserver}\n */\nclass ShinyResizeObserver {\n /**\n * The actual ResizeObserver instance.\n * @private\n * @type {ResizeObserver}\n */\n private resizeObserver: ResizeObserver;\n /**\n * An array of elements that are currently being watched by the Resize\n * Observer.\n *\n * @details\n * We don't currently have lifecycle hooks that allow us to unobserve elements\n * when they are removed from the DOM. As a result, we need to manually check\n * that the elements we're watching still exist in the DOM. This array keeps\n * track of the elements we're watching so that we can check them later.\n * @private\n * @type {HTMLElement[]}\n */\n private resizeObserverEntries: HTMLElement[];\n\n /**\n * Watch containers for size changes and ensure that Shiny outputs and\n * htmlwidgets within resize appropriately.\n *\n * @details\n * The ShinyResizeObserver is used to watch the containers, such as Sidebars\n * and Cards for size changes, in particular when the sidebar state is toggled\n * or the card body is expanded full screen. It performs two primary tasks:\n *\n * 1. Dispatches a `resize` event on the window object. This is necessary to\n * ensure that Shiny outputs resize appropriately. In general, the window\n * resizing is throttled and the output update occurs when the transition\n * is complete.\n * 2. If an output with a resize method on the output binding is detected, we\n * directly call the `.onResize()` method of the binding. This ensures that\n * htmlwidgets transition smoothly. In static mode, htmlwidgets does this\n * already.\n *\n * @note\n * This resize observer also handles race conditions in some complex\n * fill-based layouts with multiple outputs (e.g., plotly), where shiny\n * initializes with the correct sizing, but in-between the 1st and last\n * renderValue(), the size of the output containers can change, meaning every\n * output but the 1st gets initialized with the wrong size during their\n * renderValue(). Then, after the render phase, shiny won't know to trigger a\n * resize since all the widgets will return to their original size (and thus,\n * Shiny thinks there isn't any resizing to do). The resize observer works\n * around this by ensuring that the output is resized whenever its container\n * size changes.\n * @constructor\n */\n constructor() {\n this.resizeObserverEntries = [];\n this.resizeObserver = new ResizeObserver((entries) => {\n const resizeEvent = new Event(\"resize\");\n window.dispatchEvent(resizeEvent);\n\n // the rest of this callback is only relevant in Shiny apps\n if (!window.Shiny) return;\n\n const resized = [] as HTMLElement[];\n\n for (const entry of entries) {\n if (!(entry.target instanceof HTMLElement)) continue;\n if (!entry.target.querySelector(\".shiny-bound-output\")) continue;\n\n entry.target\n .querySelectorAll(\".shiny-bound-output\")\n .forEach((el) => {\n if (resized.includes(el)) return;\n\n const { binding, onResize } = $(el).data(\"shinyOutputBinding\");\n if (!binding || !binding.resize) return;\n\n // if this output is owned by another observer, skip it\n const owner = (el as any).shinyResizeObserver;\n if (owner && owner !== this) return;\n // mark this output as owned by this shinyResizeObserver instance\n if (!owner) (el as any).shinyResizeObserver = this;\n\n // trigger immediate resizing of outputs with a resize method\n onResize(el);\n // only once per output and resize event\n resized.push(el);\n\n // set plot images to 100% width temporarily during the transition\n if (!el.classList.contains(\"shiny-plot-output\")) return;\n const img = el.querySelector(\n 'img:not([width=\"100%\"])'\n );\n if (img) img.setAttribute(\"width\", \"100%\");\n });\n }\n });\n }\n\n /**\n * Observe an element for size changes.\n * @param {HTMLElement} el - The element to observe.\n */\n observe(el: HTMLElement): void {\n this.resizeObserver.observe(el);\n this.resizeObserverEntries.push(el);\n }\n\n /**\n * Stop observing an element for size changes.\n * @param {HTMLElement} el - The element to stop observing.\n */\n unobserve(el: HTMLElement): void {\n const idxEl = this.resizeObserverEntries.indexOf(el);\n if (idxEl < 0) return;\n\n this.resizeObserver.unobserve(el);\n this.resizeObserverEntries.splice(idxEl, 1);\n }\n\n /**\n * This method checks that we're not continuing to watch elements that no\n * longer exist in the DOM. If any are found, we stop observing them and\n * remove them from our array of observed elements.\n *\n * @private\n * @static\n */\n flush(): void {\n this.resizeObserverEntries.forEach((el) => {\n if (!document.body.contains(el)) this.unobserve(el);\n });\n }\n}\n\nexport { ShinyResizeObserver };\n", "import type { Tooltip as TooltipType } from \"bootstrap\";\nimport { getAllFocusableChildren } from \"./_utils\";\nimport { ShinyResizeObserver } from \"./_shinyResizeObserver\";\n\n// eslint-disable-next-line @typescript-eslint/naming-convention\nconst Tooltip = (\n window.bootstrap ? window.bootstrap.Tooltip : class {}\n) as typeof TooltipType;\n\n/**\n * The overlay element that is placed behind the card when expanded full screen.\n *\n * @interface CardFullScreenOverlay\n * @typedef {CardFullScreenOverlay}\n */\ninterface CardFullScreenOverlay {\n /**\n * The full screen overlay container.\n * @type {HTMLDivElement}\n */\n container: HTMLDivElement;\n /**\n * The anchor element used to close the full screen overlay.\n * @type {HTMLAnchorElement}\n */\n anchor: HTMLAnchorElement;\n}\n\n/**\n * The bslib card component class.\n *\n * @class Card\n * @typedef {Card}\n */\nclass Card {\n /**\n * The card container element.\n * @private\n * @type {HTMLElement}\n */\n private card: HTMLElement;\n /**\n * The card's full screen overlay element. We create this element once and add\n * and remove it from the DOM as needed (this simplifies focus management\n * while in full screen mode).\n * @private\n * @type {CardFullScreenOverlay}\n */\n private overlay: CardFullScreenOverlay;\n\n /**\n * Key bslib-specific classes and attributes used by the card component.\n * @private\n * @static\n * @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; }}\n */\n private static attr = {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ATTR_INIT: \"data-bslib-card-init\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_CARD: \"bslib-card\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ATTR_FULL_SCREEN: \"data-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_HAS_FULL_SCREEN: \"bslib-has-full-screen\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_ENTER: \"bslib-full-screen-enter\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n CLASS_FULL_SCREEN_EXIT: \"bslib-full-screen-exit\",\n // eslint-disable-next-line @typescript-eslint/naming-convention\n ID_FULL_SCREEN_OVERLAY: \"bslib-full-screen-overlay\",\n };\n\n /**\n * A Shiny-specific resize observer that ensures Shiny outputs in within the\n * card resize appropriately.\n * @private\n * @type {ShinyResizeObserver}\n * @static\n */\n private static shinyResizeObserver = new ShinyResizeObserver();\n\n /**\n * Creates an instance of a bslib Card component.\n *\n * @constructor\n * @param {HTMLElement} card\n */\n constructor(card: HTMLElement) {\n // remove initialization attribute and script\n card.removeAttribute(Card.attr.ATTR_INIT);\n card\n .querySelector(`script[${Card.attr.ATTR_INIT}]`)\n ?.remove();\n\n this.card = card;\n Card.instanceMap.set(card, this);\n\n // Let Shiny know to trigger resize when the card size changes\n // TODO: shiny could/should do this itself (rstudio/shiny#3682)\n Card.shinyResizeObserver.observe(this.card);\n\n this._addEventListeners();\n this._enableTooltips();\n this.overlay = this._createOverlay();\n\n // bind event handler methods to this card instance\n this._exitFullScreenOnEscape = this._exitFullScreenOnEscape.bind(this);\n this._trapFocusExit = this._trapFocusExit.bind(this);\n }\n\n /**\n * Enter the card's full screen mode, either programmatically or via an event\n * handler. Full screen mode is activated by adding a class to the card that\n * positions it absolutely and expands it to fill the viewport. In addition,\n * we add a full screen overlay element behind the card and we trap focus in\n * the expanded card while in full screen mode.\n *\n * @param {?Event} [event]\n */\n enterFullScreen(event?: Event): void {\n if (event) event.preventDefault();\n\n document.addEventListener(\"keydown\", this._exitFullScreenOnEscape, false);\n\n // trap focus in the fullscreen container, listening for Tab key on the\n // capture phase so we have the best chance of preventing other handlers\n document.addEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Set initial focus on the card, if not already\n if (!this.card.contains(document.activeElement)) {\n this.card.setAttribute(\"tabindex\", \"-1\");\n this.card.focus();\n }\n\n this.card.setAttribute(Card.attr.ATTR_FULL_SCREEN, \"true\");\n document.body.classList.add(Card.attr.CLASS_HAS_FULL_SCREEN);\n this.card.insertAdjacentElement(\"beforebegin\", this.overlay.container);\n }\n\n /**\n * Exit full screen mode. This removes the full screen overlay element,\n * removes the full screen class from the card, and removes the keyboard event\n * listeners that were added when entering full screen mode.\n */\n exitFullScreen(): void {\n document.removeEventListener(\n \"keydown\",\n this._exitFullScreenOnEscape,\n false\n );\n document.removeEventListener(\"keydown\", this._trapFocusExit, true);\n\n // Remove overlay and remove full screen classes from card\n this.overlay.container.remove();\n this.card.setAttribute(Card.attr.ATTR_FULL_SCREEN, \"false\");\n this.card.removeAttribute(\"tabindex\");\n document.body.classList.remove(Card.attr.CLASS_HAS_FULL_SCREEN);\n }\n\n /**\n * Adds general card-specific event listeners.\n * @private\n */\n private _addEventListeners(): void {\n const btnFullScreen = this.card.querySelector(\n `:scope > .${Card.attr.CLASS_FULL_SCREEN_ENTER}`\n );\n if (!btnFullScreen) return;\n btnFullScreen.addEventListener(\"click\", (ev) => this.enterFullScreen(ev));\n }\n\n /**\n * Enable tooltips used by the card component.\n * @private\n */\n private _enableTooltips(): void {\n const selector = `.${Card.attr.CLASS_FULL_SCREEN_ENTER}[data-bs-toggle='tooltip']`;\n if (!this.card.querySelector(selector)) {\n return;\n }\n const tooltipList = this.card.querySelectorAll(selector);\n tooltipList.forEach((tt) => new Tooltip(tt));\n }\n\n /**\n * An event handler to exit full screen mode when the Escape key is pressed.\n * @private\n * @param {KeyboardEvent} event\n */\n private _exitFullScreenOnEscape(event: KeyboardEvent): void {\n if (!(event.target instanceof HTMLElement)) return;\n // If the user is in the middle of a select input choice, don't exit\n const selOpenSelectInput = [\"select[open]\", \"input[aria-expanded='true']\"];\n if (event.target.matches(selOpenSelectInput.join(\", \"))) return;\n\n if (event.key === \"Escape\") {\n this.exitFullScreen();\n }\n }\n\n /**\n * An event handler to trap focus within the card when in full screen mode.\n *\n * @description\n * This keyboard event handler ensures that tab focus stays within the card\n * when in full screen mode. When the card is first expanded,\n * we move focus to the card element itself. If focus somehow leaves the card,\n * we returns focus to the card container.\n *\n * Within the card, we handle only tabbing from the close anchor or the last\n * focusable element and only when tab focus would have otherwise left the\n * card. In those cases, we cycle focus to the last focusable element or back\n * to the anchor. If the card doesn't have any focusable elements, we move\n * focus to the close anchor.\n *\n * @note\n * Because the card contents may change, we check for focusable elements\n * every time the handler is called.\n *\n * @private\n * @param {KeyboardEvent} event\n */\n private _trapFocusExit(event: KeyboardEvent): void {\n if (!(event instanceof KeyboardEvent)) return;\n if (event.key !== \"Tab\") return;\n\n const isFocusedContainer = event.target === this.card;\n const isFocusedAnchor = event.target === this.overlay.anchor;\n const isFocusedWithin = this.card.contains(event.target as Node);\n\n const stopEvent = () => {\n event.preventDefault();\n event.stopImmediatePropagation();\n };\n\n if (!(isFocusedWithin || isFocusedContainer || isFocusedAnchor)) {\n // If focus is outside the card, return to the card\n stopEvent();\n this.card.focus();\n return;\n }\n\n // Check focusables every time because the card contents may have changed\n const focusableElements = getAllFocusableChildren(this.card);\n const hasFocusableElements = focusableElements.length > 0;\n\n // We need to handle five cases:\n // 1. The card has no focusable elements --> focus the anchor\n // 2. Focus is on the card container (do nothing, natural tab order)\n // 3. Focus is on the anchor and the user pressed Tab + Shift (backwards)\n // -> Move to the last focusable element (end of card)\n // 4. Focus is on the last focusable element and the user pressed Tab\n // (forwards) -> Move to the anchor (top of card)\n // 5. otherwise we don't interfere\n\n if (!hasFocusableElements) {\n // case 1\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n\n // case 2\n if (isFocusedContainer) return;\n\n const lastFocusable = focusableElements[focusableElements.length - 1];\n const isFocusedLast = event.target === lastFocusable;\n\n if (isFocusedAnchor && event.shiftKey) {\n stopEvent();\n lastFocusable.focus();\n return;\n }\n\n if (isFocusedLast && !event.shiftKey) {\n stopEvent();\n this.overlay.anchor.focus();\n return;\n }\n }\n\n /**\n * Creates the full screen overlay.\n * @private\n * @returns {CardFullScreenOverlay}\n */\n private _createOverlay(): CardFullScreenOverlay {\n const container = document.createElement(\"div\");\n container.id = Card.attr.ID_FULL_SCREEN_OVERLAY;\n container.onclick = this.exitFullScreen.bind(this);\n\n const anchor = this._createOverlayCloseAnchor();\n container.appendChild(anchor);\n\n return { container, anchor };\n }\n\n /**\n * Creates the anchor element used to exit the full screen mode.\n * @private\n * @returns {HTMLAnchorElement}\n */\n private _createOverlayCloseAnchor(): HTMLAnchorElement {\n const anchor = document.createElement(\"a\");\n anchor.classList.add(Card.attr.CLASS_FULL_SCREEN_EXIT);\n anchor.tabIndex = 0;\n anchor.onclick = () => this.exitFullScreen();\n anchor.onkeydown = (ev) => {\n if (ev.key === \"Enter\" || ev.key === \" \") {\n this.exitFullScreen();\n }\n };\n anchor.innerHTML = this._overlayCloseHtml();\n\n return anchor;\n }\n\n /**\n * Returns the HTML for the close icon.\n * @private\n * @returns {string}\n */\n private _overlayCloseHtml(): string {\n return (\n \"Close \" +\n \"\" +\n \"\"\n );\n }\n\n /**\n * The registry of card instances and their associated DOM elements.\n * @private\n * @static\n * @type {WeakMap}\n */\n private static instanceMap: WeakMap = new WeakMap();\n\n /**\n * Returns the card instance associated with the given element, if any.\n * @public\n * @static\n * @param {HTMLElement} el\n * @returns {(Card | undefined)}\n */\n public static getInstance(el: HTMLElement): Card | undefined {\n return Card.instanceMap.get(el);\n }\n\n /**\n * If cards are initialized before the DOM is ready, we re-schedule the\n * initialization to occur on DOMContentLoaded.\n * @private\n * @static\n * @type {boolean}\n */\n private static onReadyScheduled = false;\n\n /**\n * Initializes all cards that require initialization on the page, or schedules\n * initialization if the DOM is not yet ready.\n * @public\n * @static\n * @param {boolean} [flushResizeObserver=true]\n */\n public static initializeAllCards(flushResizeObserver = true): void {\n if (document.readyState === \"loading\") {\n if (!Card.onReadyScheduled) {\n Card.onReadyScheduled = true;\n document.addEventListener(\"DOMContentLoaded\", () => {\n Card.initializeAllCards(false);\n });\n }\n return;\n }\n\n if (flushResizeObserver) {\n // Trigger a recheck of observed cards to unobserve non-existent cards\n Card.shinyResizeObserver.flush();\n }\n\n const initSelector = `.${Card.attr.CLASS_CARD}[${Card.attr.ATTR_INIT}]`;\n if (!document.querySelector(initSelector)) {\n // no cards to initialize\n return;\n }\n\n const cards = document.querySelectorAll(initSelector);\n cards.forEach((card) => new Card(card as HTMLElement));\n }\n}\n\n// attach Sidebar class to window for global usage\n(window as any).bslib = (window as any).bslib || {};\n(window as any).bslib.Card = Card;\n\nexport { Card };\n"], + "mappings": "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", "names": ["InputBinding", "getAllFocusableChildren", "el", "base", "modifiers", "selectors", "b", "focusable", "ShinyResizeObserver", "entries", "resizeEvent", "resized", "entry", "el", "binding", "onResize", "owner", "img", "idxEl", "Tooltip", "_Card", "card", "_a", "event", "btnFullScreen", "ev", "selector", "tt", "selOpenSelectInput", "isFocusedContainer", "isFocusedAnchor", "isFocusedWithin", "stopEvent", "focusableElements", "getAllFocusableChildren", "lastFocusable", "isFocusedLast", "container", "anchor", "el", "flushResizeObserver", "initSelector", "Card", "ShinyResizeObserver"] } From ff6e2db51c1f50ad264a0809e309e74ac5bb818e Mon Sep 17 00:00:00 2001 From: gadenbuie Date: Wed, 12 Jul 2023 14:12:58 +0000 Subject: [PATCH 3/3] Resave distributed files (GitHub Action) --- inst/components/dist/card/card.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inst/components/dist/card/card.css b/inst/components/dist/card/card.css index c50b6fdcf..32d770797 100644 --- a/inst/components/dist/card/card.css +++ b/inst/components/dist/card/card.css @@ -1 +1 @@ -.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card.bslib-full-screen>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border="true"]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius="true"]){border-top-left-radius:0;border-top-right-radius:0}.bslib-full-screen{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:1px;right:3px;margin:0.5rem;padding:0.55rem !important;font-size:.8rem;cursor:pointer;opacity:.6;color:rgba(var(--bs-body-bg-rgb), 1);z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card:hover:not(.bslib-full-screen)>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>.bslib-full-screen-enter{display:none}@media (max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:0.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:0.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}} +.bslib-card .card-body+.card-body{padding-top:0}.bslib-card .card-body{overflow:auto}.bslib-card .card-body p{margin-top:0}.bslib-card .card-body p:last-child{margin-bottom:0}.bslib-card .card-body{max-height:var(--bslib-card-body-max-height, none)}.bslib-card[data-full-screen="true"]>.card-body{max-height:var(--bslib-card-body-max-height-full-screen, none)}.bslib-card .card-header .form-group{margin-bottom:0}.bslib-card .card-header .selectize-control{margin-bottom:0}.bslib-card .card-header .selectize-control .item{margin-right:1.15rem}.bslib-card .card-footer{margin-top:auto}.bslib-card .bslib-navs-card-title{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center}.bslib-card .bslib-navs-card-title .nav{margin-left:auto}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border="true"]){border:none}.bslib-card .bslib-sidebar-layout:not([data-bslib-sidebar-border-radius="true"]){border-top-left-radius:0;border-top-right-radius:0}[data-full-screen="true"]{position:fixed;inset:3.5rem 1rem 1rem;height:auto !important;max-height:none !important;width:auto !important;z-index:1070}.bslib-full-screen-enter{display:none;position:absolute;bottom:1px;right:3px;margin:0.5rem;padding:0.55rem !important;font-size:.8rem;cursor:pointer;opacity:.6;color:rgba(var(--bs-body-bg-rgb), 1);z-index:1070}.bslib-full-screen-enter:hover{opacity:1}.card[data-full-screen="false"]:hover>.bslib-full-screen-enter{display:block}.bslib-has-full-screen .card:hover>.bslib-full-screen-enter{display:none}@media (max-width: 575.98px){.bslib-full-screen-enter{display:none !important}}.bslib-full-screen-exit{position:relative;top:1.35rem;font-size:0.9rem;cursor:pointer;text-decoration:none;display:flex;float:right;margin-right:2.15rem;align-items:center;color:rgba(var(--bs-body-bg-rgb), 0.8)}.bslib-full-screen-exit:hover{color:rgba(var(--bs-body-bg-rgb), 1)}.bslib-full-screen-exit svg{margin-left:0.5rem;font-size:1.5rem}#bslib-full-screen-overlay{position:fixed;inset:0;background-color:rgba(var(--bs-body-color-rgb), 0.6);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);z-index:1069;animation:bslib-full-screen-overlay-enter 400ms cubic-bezier(0.6, 0.02, 0.65, 1) forwards}@keyframes bslib-full-screen-overlay-enter{0%{opacity:0}100%{opacity:1}}