Prism Helper

Tokens

Token Example
keyword
import { stuff } from 'some/where.js';
builtin
pi = round(float('3.14159'), 2)
class-name
class Wizard extends Human { /* ... */ }
function
function helloGrumpy(name) { /* ... */ }
helloGrumpy('Wizard');
parameter
function helloGrumpy(name) { /* ... */ }
boolean
const wizardsLikeBeer = false;
number
const favouriteNumber = 3.14159;
string
const hiGrumpy = 'Hi Grumpy!';
template-string, template-punctuation
const hiGrumpy = `Hi Grumpy!`;
interpolation, interpolation-punctuation
console.log(`Hi there ${name}.`);
char
symbol
regex
let entity = /&#x?[\da-f]{1,8};/;
url
body { background: url("wizard.png"); }
operator
x += (y + 4 >> -z === w) ? b ** c : ~a;
variable
DECLARE @MyCounter INT;
constant
const PI = 3.14159;
property
.grumpy > img { height: 100%; }
punctuation
import { stuff } from 'some/where.js';
important
.grumpy > img { height: 100% !important; }
comment
/* grump wizards */
tag
<h1>Grumpy Wizards</h1>
attr-name, attr-value
<h1 class="dangerous">Grumpy Wizards</h1>
namespace
throw new java.lang.UnsupportedOperationException();
prolog
<?xml version="1.0" encoding="utf-8"?>
doctype
<!DOCTYPE html>
cdata
<![CDATA[ grumpy wizards eat donuts ]]>
entity
&pound; &#163;
atrule
@media (prefers-reduced-motion: reduce) { /* no animations */ }
selector
.grumpy > img { /* ... */ }
null
{ "fritter": null }
color
background-color: rgba(0, 0, 0, 0.4);
border: 1px solid #cd2026;

Large Samples

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta charset="UTF-8">
		<link rel="stylesheet" href="../../demo/styles.css" type="text/css">
		<script type="module">
			import '../../demo/demo-page.js';
			import '../../button/button.js';
			import '../../button/button-icon.js';
			import '../../dropdown/dropdown-more.js';
			import '../../dropdown/dropdown-content.js';
			import '../../status-indicator/status-indicator.js';
			import '../../tooltip/tooltip.js';
			import '../card.js';
			import '../card-loading-shimmer.js';
			import '../card-content-meta.js';
			import '../card-content-title.js';
			import '../card-footer-link.js';
		</script>
		<style>
			d2l-card {
				vertical-align: top;
			}
			.subtle-demo {
				background-color: #f6f7f8;
				padding: 20px;
			}
			.badge {
				text-align: center;
			}
			.badge > img {
				background-color: white;
				border: 1px solid #202122; /* ferrite */
				border-radius: 6px;
				height: 70px;
				object-fit: cover;
				object-position: center;
			}
			.badge-status {
				background-color: white;
				border: 1px solid white;
				border-radius: 0.6rem;
				display: inline-block;
			}
			div[slot="footer"] {
				display: inline-block;
			}
			#toggleLoading {
				margin-top: 20px;
			}
		</style>
	</head>
	<body unresolved>

		<d2l-demo-page page-title="d2l-card">

			<h2>Subtle Card (badges, no-link)</h2>

			<d2l-demo-snippet>
				<template>
					<div class="subtle-demo">

						<d2l-card subtle align-center text="Image Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
							<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
							<div slot="badge" class="badge">
								<img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Stick_Figure.svg/340px-Stick_Figure.svg.png">
							</div>
							<div slot="content">Image Badge</div>
						</d2l-card>

						<d2l-card subtle align-center text="Status Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
							<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
							<div class="badge-status" slot="badge">
								<d2l-status-indicator text="Success" state="success"></d2l-status-indicator>
							</div>
							<div slot="content">Status Badge</div>
						</d2l-card>

						<d2l-card subtle align-center text="No Link" style="height: 280px; width: 245px;">
							<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
							<div slot="content">No Link</div>
						</d2l-card>

					</div>
				</template>
			</d2l-demo-snippet>

			<h2>Subtle Card (header actions, meta-content, footer links)</h2>

			<d2l-demo-snippet>
				<template>
					<div class="subtle-demo">

						<d2l-card subtle align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;">
							<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
							<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
									<d2l-dropdown-content>
										<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
										<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
										<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
									</d2l-dropdown-content>
							</d2l-dropdown-more>
							<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
							<div slot="content"><div>Hydrology</div><d2l-card-content-meta>This is some extra meta data that will fill the content slot of the card.</d2l-card-content-meta></div>
							<div slot="footer">
								<d2l-card-footer-link id="googleDriveLink1" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/">
									<d2l-tooltip slot="tooltip" for="googleDriveLink1">Go to Google Drive</d2l-tooltip>
								</d2l-card-footer-link>
								<d2l-card-footer-link id="rssFeedLink1" icon="tier1:rss" text="RSS Feed" secondary-count="1">
									<d2l-tooltip slot="tooltip" for="rssFeedLink1">RSS Feed</d2l-tooltip>
								</d2l-card-footer-link>
								<d2l-card-footer-link id="outcomesLink1" icon="tier1:outcomes" text="Outcomes" secondary-count="5">
									<d2l-tooltip slot="tooltip" for="outcomesLink1">Outcomes</d2l-tooltip>
								</d2l-card-footer-link>
								<d2l-card-footer-link id="assignmentsLink1" icon="tier1:assignments" text="Assignments" secondary-count="3">
									<d2l-tooltip slot="tooltip" position="top" style="width: 100%;" for="assignmentsLink1">You have 3 assignments due tomorrow.</d2l-tooltip>
								</d2l-card-footer-link>
							</div>
						</d2l-card>

						<d2l-card subtle align-center text="Grade 2" href="https://en.wikipedia.org/wiki/Second_grade" style="height: 300px; width: 245px;">
							<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-low-density-max-size.jpg">
							<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
									<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
							</d2l-dropdown-more>
							<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
							<div slot="content">Grade 2</div>
							<div slot="footer">
								<d2l-card-footer-link id="googleDriveLink2" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/">
									<d2l-tooltip slot="tooltip" for="googleDriveLink2">Go to Google Drive</d2l-tooltip>
								</d2l-card-footer-link>
								<d2l-card-footer-link id="rssFeedLink2" icon="tier1:rss" text="RSS Feed" secondary-count="1">
									<d2l-tooltip slot="tooltip" for="rssFeedLink2">RSS Feed</d2l-tooltip>
								</d2l-card-footer-link>
								<d2l-card-footer-link id="outcomesLink2" icon="tier1:outcomes" text="Outcomes" secondary-count="5">
									<d2l-tooltip slot="tooltip" for="outcomesLink2">Outcomes</d2l-tooltip>
								</d2l-card-footer-link>
							</div>
						</d2l-card>

						<d2l-card subtle align-center text="Painting" href="https://en.wikipedia.org/wiki/Painting" style="height: 300px; width: 245px;">
							<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-low-density-max-size.jpg">
							<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
									<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
							</d2l-dropdown-more>
							<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
							<div slot="content">Painting</div>
							<d2l-button slot="footer" style="width: 100%;">Shiny Button</d2l-button>
						</d2l-card>

					</div>
				</template>
			</d2l-demo-snippet>

			<h2>Card (badges, no-link)</h2>

			<d2l-demo-snippet>
				<template>

					<d2l-card align-center text="Image Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
						<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
						<div slot="badge" class="badge">
							<img alt="" src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/94/Stick_Figure.svg/340px-Stick_Figure.svg.png">
						</div>
						<div slot="content">Image Badge</div>
					</d2l-card>

					<d2l-card align-center text="Status Badge" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 280px; width: 245px;">
						<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
						<div class="badge-status" slot="badge">
							<d2l-status-indicator text="Success" state="success"></d2l-status-indicator>
						</div>
						<div slot="content">Status Badge</div>
					</d2l-card>

					<d2l-card align-center text="No Link" style="height: 280px; width: 245px;">
						<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
						<div slot="content">No Link</div>
					</d2l-card>

				</template>
			</d2l-demo-snippet>

			<h2>Card (header actions, meta-content, footer links)</h2>

			<d2l-demo-snippet>
				<template>

					<d2l-card align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;">
						<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
						<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
								<d2l-dropdown-content>
									<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
									<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
									<div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div>
								</d2l-dropdown-content>
						</d2l-dropdown-more>
						<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
						<div slot="content"><div>Hydrology</div><d2l-card-content-meta>This is some extra meta data that will fill the content slot of the card.</d2l-card-content-meta></div>
						<div slot="footer">
							<d2l-card-footer-link id="googleDriveLink3" icon="tier1:google-drive" text="Google Drive" secondary-count="100" href="https://www.google.ca/drive/">
								<d2l-tooltip slot="tooltip" for="googleDriveLink3">Go to Google Drive</d2l-tooltip>
							</d2l-card-footer-link>
							<d2l-card-footer-link id="rssFeedLink3" icon="tier1:rss" text="RSS Feed" secondary-count="1">
								<d2l-tooltip slot="tooltip" for="rssFeedLink3">RSS Feed</d2l-tooltip>
							</d2l-card-footer-link>
							<d2l-card-footer-link id="outcomesLink3" icon="tier1:outcomes" text="Outcomes" secondary-count="5">
								<d2l-tooltip slot="tooltip" for="outcomesLink3">Outcomes</d2l-tooltip>
							</d2l-card-footer-link>
							<d2l-card-footer-link id="assignmentsLink3" icon="tier1:assignments" text="Assignments" secondary-count="3">
								<d2l-tooltip slot="tooltip" position="top" style="width: 100%;" for="assignmentsLink3">You have 3 assignments due tomorrow.</d2l-tooltip>
							</d2l-card-footer-link>
						</div>
					</d2l-card>

					<d2l-card align-center text="Painting" href="https://en.wikipedia.org/wiki/Painting" style="height: 300px; width: 245px;">
						<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/63b162ab-b582-4bf9-8c1d-1dad04714121/tile-low-density-max-size.jpg">
						<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
								<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
						</d2l-dropdown-more>
						<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
						<div slot="content">Painting</div>
						<d2l-button slot="footer" style="width: 100%;">Shiny Button</d2l-button>
					</d2l-card>

					<d2l-card align-center text="Grade 2" href="https://en.wikipedia.org/wiki/Second_grade" style="height: 300px; width: 245px;">
						<img slot="header" alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/e5fd575a-bc14-4a80-89e1-46f349a76178/tile-low-density-max-size.jpg">
						<d2l-dropdown-more slot="actions" translucent visible-on-ancestor text="Open!">
								<d2l-dropdown-content><div>This is where you could put the super cool features for your card!</div><br><div>As with all dropdowns, you can choose between a generic dropdown container, or a menu specific one.</div></d2l-dropdown-content>
						</d2l-dropdown-more>
						<d2l-button-icon slot="actions" translucent text="unpin" icon="tier1:pin-filled"></d2l-button-icon>
						<div slot="content">Grade 2</div>
						<div slot="footer">
							<d2l-card-footer-link id="googleDriveLink4" icon="tier1:google-drive" text="Google Drive" secondary-count-type="count" secondary-count="100" href="https://www.google.ca/drive/">
								<d2l-tooltip slot="tooltip" for="googleDriveLink4">Go to Google Drive</d2l-tooltip>
							</d2l-card-footer-link>
							<d2l-card-footer-link id="rssFeedLink4" icon="tier1:rss" text="RSS Feed" secondary-count-type="count" secondary-count="1">
								<d2l-tooltip slot="tooltip" for="rssFeedLink4">RSS Feed</d2l-tooltip>
							</d2l-card-footer-link>
							<d2l-card-footer-link id="outcomesLink4" icon="tier1:outcomes" text="Outcomes" secondary-count-type="count" secondary-count="5">
								<d2l-tooltip slot="tooltip" for="outcomesLink4">Outcomes</d2l-tooltip>
							</d2l-card-footer-link>
						</div>
					</d2l-card>

				</template>
			</d2l-demo-snippet>

			<h2>Card (with header loading)</h2>

			<d2l-demo-snippet>
				<template>

					<d2l-card align-center text="Hydrology" href="https://en.wikipedia.org/wiki/Hydrology" style="height: 300px; width: 245px;">
						<d2l-card-loading-shimmer slot="header" loading style="display: block; height: 103.5px; width: 100%;">
							<img  alt="" style="display: block; width: 100%;" src="https://s.brightspace.com/course-images/images/38e839b1-37fa-470c-8830-b189ce4ae134/tile-high-density-max-size.jpg">
						</d2l-card-loading-shimmer>
						<div slot="content"><div>Hydrology</div><d2l-card-content-meta>This is some extra meta data that will fill the content slot of the card.</d2l-card-content-meta></div>
					</d2l-card>

					<div>
						<d2l-button id="toggleLoading">Toggle Loading State</d2l-button>
					</div>

					<script>
						document.querySelector('#toggleLoading').addEventListener('click', () => {
							const loadingContainer = document.querySelector('d2l-card-loading-shimmer');
							loadingContainer.loading = !loadingContainer.loading;
						});
					</script>
				</template>
			</d2l-demo-snippet>

		</d2l-demo-page>
	</body>
</html>
import '../backdrop/backdrop.js';
import '../button/button.js';
import '../focus-trap/focus-trap.js';
import { clearDismissible, setDismissible } from '../../helpers/dismissible.js';
import { findComposedAncestor, getBoundingAncestor, isComposedAncestor, isVisible } from '../../helpers/dom.js';
import { getComposedActiveElement, getFirstFocusableDescendant, getPreviousFocusableAncestor } from '../../helpers/focus.js';
import { classMap } from 'lit/directives/class-map.js';
import { html } from 'lit';
import { LocalizeCoreElement } from '../../helpers/localize-core-element.js';
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
import { styleMap } from 'lit/directives/style-map.js';
import { tryGetIfrauBackdropService } from '../../helpers/ifrauBackdropService.js';

const reduceMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
const minBackdropHeightMobile = 42;
const minBackdropWidthMobile = 30;
const outerMarginTopBottom = 18;
const defaultVerticalOffset = 16;

export const DropdownContentMixin = superclass => class extends LocalizeCoreElement(RtlMixin(superclass)) {

	static get properties() {
		return {
			/**
			 * Optionally align dropdown to either start or end. If not set, the dropdown will attempt be centred.
			 * @type {'start'|'end'}
			 */
			align: {
				type: String,
				reflect: true
			},
			/**
			 * Optionally provide boundaries to where the dropdown will appear. Valid properties are "above", "below", "left", and "right".
			 * @type {object}
			 */
			boundary: {
				type: Object,
			},
			/**
			 * Override default max-width (undefined). Specify a number that would be the px value.
			 * @type {number}
			 */
			maxWidth: {
				type: Number,
				reflect: true,
				attribute: 'max-width'
			},
			/**
			 * Override default min-width (undefined). Specify a number that would be the px value.
			 * @type {number}
			 */
			minWidth: {
				type: Number,
				reflect: true,
				attribute: 'min-width'
			},
			/**
			 * Override max-height. Note that the default behaviour is to be as tall as necessary within the viewport, so this property is usually not needed.
			 * @type {number}
			 */
			maxHeight: {
				type: Number,
				attribute: 'max-height'
			},
			/**
			 * Override the breakpoint at which mobile styling is used. Defaults to 616px.
			 * @type {number}
			 */
			mobileBreakpointOverride: {
				type: Number,
				attribute: 'mobile-breakpoint'
			},
			/**
			 * Override default height used for required space when `no-auto-fit` is true. Specify a number that would be the px value. Note that the default behaviour is to be as tall as necessary within the viewport, so this property is usually not needed.
			 * @type {number}
			 */
			minHeight: {
				type: Number,
				reflect: true,
				attribute: 'min-height'
			},
			/**
			 * Opt-out of showing a close button in the footer of tray-style mobile dropdowns.
			 * @type {boolean}
			 */
			noMobileCloseButton: {
				type: Boolean,
				reflect: true,
				attribute: 'no-mobile-close-button'
			},
			/**
			 * Mobile dropdown style.
			 * @type {'left'|'right'|'bottom'}
			 */
			mobileTray: {
				type: String,
				reflect: true,
				attribute: 'mobile-tray'
			},
			/**
			 * Opt out of automatically closing on focus or click outside of the dropdown content
			 * @type {boolean}
			 */
			noAutoClose: {
				type: Boolean,
				reflect: true,
				attribute: 'no-auto-close'
			},
			/**
			 * Opt out of auto-sizing
			 * @type {boolean}
			 */
			noAutoFit: {
				type: Boolean,
				reflect: true,
				attribute: 'no-auto-fit'
			},
			/**
			 * Opt out of focus being automatically moved to the first focusable element in the dropdown when opened
			 * @type {boolean}
			 */
			noAutoFocus: {
				type: Boolean,
				reflect: true,
				attribute: 'no-auto-focus'
			},
			/**
			 * Render with no padding
			 * @type {boolean}
			 */
			noPadding: {
				type: Boolean,
				reflect: true,
				attribute: 'no-padding'
			},
			/**
			 * Render the footer with no padding (if it has content)
			 * @type {boolean}
			 */
			noPaddingFooter: {
				type: Boolean,
				reflect: true,
				attribute: 'no-padding-footer'
			},
			/**
			 * Render the header with no padding (if it has content)
			 * @type {boolean}
			 */
			noPaddingHeader: {
				type: Boolean,
				reflect: true,
				attribute: 'no-padding-header'
			},
			/**
			 * Render without a pointer
			 * @type {boolean}
			 */
			noPointer: {
				type: Boolean,
				reflect: true,
				attribute: 'no-pointer'
			},
			/**
			 * Whether the dropdown is open or not
			 * @type {boolean}
			 */
			opened: {
				type: Boolean,
				reflect: true
			},
			/**
			 * Private.
			 * @ignore
			 */
			openedAbove: {
				type: Boolean,
				reflect: true,
				attribute: 'opened-above'
			},
			/**
 			* Optionally render a d2l-focus-trap around the dropdown content
			 * @type {boolean}
 			*/
			trapFocus: {
				type: Boolean,
				reflect: true,
				attribute: 'trap-focus'
			},
			/**
			 * Provide custom offset, positive or negative
			 * @type {string}
			 */
			verticalOffset: {
				type: String,
				attribute: 'vertical-offset'
			},
			_bottomOverflow: {
				type: Boolean
			},
			_closing: {
				type: Boolean
			},
			_contentOverflow: {
				type: Boolean
			},
			_dropdownContent: {
				type: Boolean,
				attribute: 'dropdown-content',
				reflect: true
			},
			_useMobileStyling: {
				type: Boolean,
				attribute: 'data-mobile',
				reflect: true
			},
			_hasHeader: {
				type: Boolean
			},
			_hasFooter: {
				type: Boolean
			},
			_contentHeight: {
				type: Number
			},
			_position: {
				type: Number
			},
			_showBackdrop: {
				type: Boolean
			},
			_topOverflow: {
				type: Boolean
			},
			_width: {
				type: Number
			}
		};
	}

	constructor() {
		super();

		this.noAutoClose = false;
		this.noAutoFit = false;
		this.noAutoFocus = false;
		this.noMobileCloseButton = false;
		this.noPadding = false;
		this.noPaddingFooter = false;
		this.noPaddingHeader = false;
		this.noPointer = false;
		this.mobileBreakpointOverride = 616;
		this.trapFocus = false;
		this._useMobileStyling = false;

		this.__opened = false;
		this.__content = null;
		this.__previousFocusableAncestor = null;
		this.__applyFocus = true;
		this.__dismissibleId = null;

		this._dropdownContent = true;
		this._bottomOverflow = false;
		this._topOverflow = false;
		this._closing = false;
		this._contentOverflow = false;
		this._hasHeader = false;
		this._hasFooter = false;
		this._showBackdrop = false;
		this._verticalOffset = defaultVerticalOffset;

		this.__onResize = this.__onResize.bind(this);
		this.__onAutoCloseFocus = this.__onAutoCloseFocus.bind(this);
		this.__onAutoCloseClick = this.__onAutoCloseClick.bind(this);
		this.__toggleScrollStyles = this.__toggleScrollStyles.bind(this);
		this._handleMobileResize = this._handleMobileResize.bind(this);
		this.__disconnectResizeObserver = this.__disconnectResizeObserver.bind(this);
	}

	get opened() {
		return this.__opened;
	}

	set opened(val) {
		const oldVal = this.__opened;
		if (oldVal !== val) {
			this.__opened = val;
			this.requestUpdate('opened', oldVal);
			this.__openedChanged(val);
		}
	}

	connectedCallback() {
		super.connectedCallback();

		window.addEventListener('resize', this.__onResize);
		this.addEventListener('blur', this.__onAutoCloseFocus, true);
		document.body.addEventListener('focus', this.__onAutoCloseFocus, true);
		document.body.addEventListener('click', this.__onAutoCloseClick, true);
		this.mediaQueryList = window.matchMedia(`(max-width: ${this.mobileBreakpointOverride - 1}px)`);
		this._useMobileStyling = this.mediaQueryList.matches;
		if (this.mediaQueryList.addEventListener) this.mediaQueryList.addEventListener('change', this._handleMobileResize);
	}

	disconnectedCallback() {
		super.disconnectedCallback();
		if (this.mediaQueryList.removeEventListener) this.mediaQueryList.removeEventListener('change', this._handleMobileResize);
		this.removeEventListener('blur', this.__onAutoCloseFocus);
		window.removeEventListener('resize', this.__onResize);
		if (document.body) {
			// DE41322: document.body can be null in some scenarios
			document.body.removeEventListener('focus', this.__onAutoCloseFocus, true);
			document.body.removeEventListener('click', this.__onAutoCloseClick, true);
		}
		clearDismissible(this.__dismissibleId);
		this.__dismissibleId = null;

		if (this.__resizeObserver) this.__resizeObserver.disconnect();
	}

	firstUpdated(changedProperties) {
		super.firstUpdated(changedProperties);

		this.__content = this.getContentContainer();
		this.addEventListener('d2l-dropdown-close', this.__onClose);
		this.addEventListener('d2l-dropdown-position', this.__toggleScrollStyles);
	}

	updated(changedProperties) {
		changedProperties.forEach((_, propName) => {
			if (propName === 'verticalOffset') {
				let newVerticalOffset = parseInt(this.verticalOffset);
				if (isNaN(newVerticalOffset)) {
					newVerticalOffset = defaultVerticalOffset;
				}
				this.style.setProperty('--d2l-dropdown-verticaloffset', `${newVerticalOffset}px`);
				this._verticalOffset = newVerticalOffset;
			}
		});
	}

	close() {
		const hide = () => {
			this._closing = false;
			this._showBackdrop = false;
			this.opened = false;
		};

		if (!reduceMotion && this._useMobileStyling && this.mobileTray && isVisible(this)) {
			if (this.shadowRoot) this.shadowRoot.querySelector('.d2l-dropdown-content-width')
				.addEventListener('animationend', hide, { once: true });
			this._closing = true;
			this._showBackdrop = false;
		} else {
			hide();
		}
	}

	/**
	 * forceRender is no longer necessary, this is left as a stub so that
	 * places calling it will not break. It will be removed once the Polymer
	 * dropdown is swapped over to use this and all instances of
	 * forceRender are removed.
	 */
	forceRender() {}

	getContentContainer() {
		return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-container');
	}

	/**
	 * Private.
	 */
	height() {
		return this.__content && this.__content.offsetHeight;
	}

	async open(applyFocus) {
		this.__applyFocus = applyFocus !== undefined ? applyFocus : true;
		this.opened = true;
		await this.updateComplete;
		this._showBackdrop = this._useMobileStyling && this.mobileTray;
	}

	/**
	 * Waits for the next resize when elem has a height > 0px,
	 * then calls the __position function.
	*/
	requestRepositionNextResize(elem) {
		if (!elem) return;
		if (this.__resizeObserver) this.__resizeObserver.disconnect();
		this.__resizeObserver = new ResizeObserver(this.__disconnectResizeObserver);
		this.__resizeObserver.observe(elem);
	}

	async resize() {
		if (!this.opened) {
			return;
		}
		this._showBackdrop = this._useMobileStyling && this.mobileTray;
		await this.__position();
	}

	/**
	 * Private.
	 */
	scrollTo(scrollTop) {
		const content = this.__content;
		if (content) {
			if (typeof scrollTop === 'number') {
				content.scrollTop = scrollTop;
			}
			return content.scrollTop;
		}
	}

	toggleOpen(applyFocus) {
		if (this.opened) {
			this.close();
		} else {
			this.open(!this.noAutoFocus && applyFocus);
		}
	}

	__disconnectResizeObserver(entries) {
		for (let i = 0; i < entries.length; i++) {
			const entry = entries[i];
			if (this.__resizeObserver && entry.contentRect.height !== 0) {
				this.__resizeObserver.disconnect();
				// wrap in rAF for Firefox
				requestAnimationFrame(() => {
					if (this.opened) this.__position();
				});
				break;
			}
		}
	}

	__getContentBottom() {
		return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-bottom');
	}

	__getContentTop() {
		return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-top');
	}

	__getOpener() {
		const opener = findComposedAncestor(this, (elem) => {
			if (elem.dropdownOpener) {
				return true;
			}
		});
		return opener;
	}

	__getPositionContainer() {
		return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-position');
	}

	__getWidthContainer() {
		return this.shadowRoot && this.shadowRoot.querySelector('.d2l-dropdown-content-width');
	}

	__handleFooterSlotChange(e) {
		this._hasFooter = e.target.assignedNodes().length !== 0;
	}

	__handleHeaderSlotChange(e) {
		this._hasHeader = e.target.assignedNodes().length !== 0;
	}

	__onAutoCloseClick(e) {
		if (!this.opened || this.noAutoClose) {
			return;
		}
		const rootTarget = e.composedPath()[0];
		const clickInside = isComposedAncestor(this.getContentContainer(), rootTarget) ||
			isComposedAncestor(this.__getContentTop(), rootTarget) ||
			isComposedAncestor(this.__getContentBottom(), rootTarget);
		if (clickInside) {
			return;
		}
		const opener = this.__getOpener();
		if (isComposedAncestor(opener.getOpenerElement(), rootTarget)) {
			return;
		}

		this.close();
	}

	__onAutoCloseFocus() {

		/* timeout needed to work around lack of support for relatedTarget */
		setTimeout(() => {
			if (!this.opened
				|| this.noAutoClose
				|| !document.activeElement
				|| document.activeElement === this.__previousFocusableAncestor
				|| document.activeElement === document.body) {
				return;
			}

			const activeElement = getComposedActiveElement();

			if (isComposedAncestor(this, activeElement)
				|| isComposedAncestor(this.__getOpener(), activeElement)) {
				return;
			}
			this.close();
		}, 0);
	}

	__onClose(e) {

		if (e.target !== this || !document.activeElement) {
			return;
		}

		const activeElement = getComposedActiveElement();

		if (!isComposedAncestor(this, activeElement)) {
			return;
		}

		const opener = this.__getOpener();
		opener.getOpenerElement().focus();

	}

	__onResize() {
		this.resize();
	}

	async __openedChanged(newValue) {

		// DE44538: wait for dropdown content to fully render,
		// otherwise this.getContentContainer() can return null.
		await this.updateComplete;

		this.__previousFocusableAncestor =
			newValue === true
				? getPreviousFocusableAncestor(this, false, false)
				: null;

		const doOpen = async() => {

			const content = this.getContentContainer();

			if (!this.noAutoFit) {
				content.scrollTop = 0;
			}

			await this.__position();
			this._showBackdrop = this._useMobileStyling && this.mobileTray;
			if (!this.noAutoFocus && this.__applyFocus) {
				const focusable = getFirstFocusableDescendant(this);
				if (focusable) {
					// Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
					requestAnimationFrame(() => focusable.focus());
				} else {
					content.setAttribute('tabindex', '-1');
					content.focus();
				}
			}

			setTimeout(() =>
				this.dispatchEvent(new CustomEvent('d2l-dropdown-open', { bubbles: true, composed: true })), 0
			);

			this.__dismissibleId = setDismissible(() => {
				this.close();
			});
		};

		const ifrauBackdropService = await tryGetIfrauBackdropService();

		if (newValue) {

			if (ifrauBackdropService && this.mobileTray && this._useMobileStyling) {
				this._ifrauContextInfo = await ifrauBackdropService.showBackdrop();
			}

			await doOpen();

		} else {

			if (this.__dismissibleId) {
				clearDismissible(this.__dismissibleId);
				this.__dismissibleId = null;
			}
			if (ifrauBackdropService && this.mobileTray && this._useMobileStyling) {
				ifrauBackdropService.hideBackdrop();
				this._ifrauContextInfo = null;
			}
			this._showBackdrop = false;
			await this.updateComplete;

			/** Dispatched when the dropdown is closed */
			this.dispatchEvent(new CustomEvent('d2l-dropdown-close', { bubbles: true, composed: true }));

		}
	}

	async __position(ignoreVertical, contentRect) {

		const opener = this.__getOpener();
		if (!opener) {
			return;
		}
		const target = opener.getOpenerElement();
		if (!target) {
			return;
		}

		const content = this.getContentContainer();
		const header = this.__getContentTop();
		const footer = this.__getContentBottom();

		if (!this.noAutoFit) {
			this._contentHeight = null;
		}

		/* don't let dropdown content horizontally overflow viewport */
		this._width = null;

		const openerPosition = window.getComputedStyle(opener, null).getPropertyValue('position');
		const boundingContainer = getBoundingAncestor(target.parentNode);
		const boundingContainerRect = boundingContainer.getBoundingClientRect();
		const scrollHeight = boundingContainer.scrollHeight;

		await this.updateComplete;

		// position check in case consuming app (LMS) has overriden position to make content absolute wrt document
		const bounded = (openerPosition === 'relative' && boundingContainer !== document.documentElement);

		const adjustPosition = async() => {

			const targetRect = target.getBoundingClientRect();
			contentRect = contentRect ? contentRect : content.getBoundingClientRect();
			const headerFooterHeight = header.getBoundingClientRect().height + footer.getBoundingClientRect().height;

			const height = this.minHeight ? this.minHeight : Math.min(this.maxHeight ? this.maxHeight : Number.MAX_VALUE, contentRect.height + headerFooterHeight);
			const spaceRequired = {
				height: height + 10,
				width: contentRect.width
			};
			let spaceAround;
			let spaceAroundScroll;
			if (bounded) {
				spaceAround = this._constrainSpaceAround({
					// allow for target offset + outer margin
					above: targetRect.top - boundingContainerRect.top - this._verticalOffset - outerMarginTopBottom,
					// allow for target offset + outer margin
					below: boundingContainerRect.bottom - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
					// allow for outer margin
					left: targetRect.left - boundingContainerRect.left - 20,
					// allow for outer margin
					right: boundingContainerRect.right - targetRect.right - 20
				}, spaceRequired, targetRect);
				spaceAroundScroll = this._constrainSpaceAround({
					above: targetRect.top - boundingContainerRect.top + boundingContainer.scrollTop,
					below: scrollHeight - targetRect.bottom + boundingContainerRect.top - boundingContainer.scrollTop
				}, spaceRequired, targetRect);
			} else {
				spaceAround = this._constrainSpaceAround({
					// allow for target offset + outer margin
					above: targetRect.top - this._verticalOffset - outerMarginTopBottom,
					// allow for target offset + outer margin
					below: window.innerHeight - targetRect.bottom - this._verticalOffset - outerMarginTopBottom,
					// allow for outer margin
					left: targetRect.left - 20,
					// allow for outer margin
					right: document.documentElement.clientWidth - targetRect.right - 15
				}, spaceRequired, targetRect);
				spaceAroundScroll = this._constrainSpaceAround({
					above: targetRect.top + document.documentElement.scrollTop,
					below: scrollHeight - targetRect.bottom - document.documentElement.scrollTop
				}, spaceRequired, targetRect);
			}

			if (!ignoreVertical) {
				this.openedAbove = this._getOpenedAbove(spaceAround, spaceAroundScroll, spaceRequired);
			}

			const centerDelta = contentRect.width - targetRect.width;
			const position = this._getPosition(spaceAround, centerDelta);
			if (position !== null) {
				this._position = position;
			}

			//Calculate height available to the dropdown contents for overflow because that is the only area capable of scrolling
			const availableHeight = this.openedAbove ? spaceAround.above : spaceAround.below;
			if (!this.noAutoFit && availableHeight && availableHeight > 0) {
				//Only apply maximum if it's less than space available and the header/footer alone won't exceed it (content must be visible)
				this._contentHeight = this.maxHeight !== null
					&& availableHeight > this.maxHeight
					&& headerFooterHeight < this.maxHeight
					? this.maxHeight - headerFooterHeight - 2
					: availableHeight - headerFooterHeight;
				this.__toggleOverflowY(contentRect.height + headerFooterHeight > availableHeight);

				// ensure the content height has updated when the __toggleScrollStyles event handler runs
				await this.updateComplete;
			}

			/** Dispatched when the dropdown position finishes adjusting */
			this.dispatchEvent(new CustomEvent('d2l-dropdown-position', { bubbles: true, composed: true }));
		};

		const scrollWidth = Math.max(header.scrollWidth, content.scrollWidth, footer.scrollWidth);
		const availableWidth = (bounded ? boundingContainerRect.width - 60 : window.innerWidth - 40);
		this._width = (availableWidth > scrollWidth ? scrollWidth : availableWidth) ;

		await this.updateComplete;

		await adjustPosition();
	}

	__toggleOverflowY(isOverflowing) {
		if (!this.__content) {
			return;
		}
		if (!this._contentHeight) {
			return;
		}
		this._contentOverflow = isOverflowing || this.__content.scrollHeight > this._contentHeight;
	}

	__toggleScrollStyles() {
		/* scrollHeight incorrect in IE by 4px second time opened */
		this._bottomOverflow = this.__content.scrollHeight - (this.__content.scrollTop + this.__content.clientHeight) >= 5;
		this._topOverflow = this.__content.scrollTop !== 0;
	}

	_constrainSpaceAround(spaceAround, spaceRequired, targetRect) {
		const constrained = { ...spaceAround };
		if (this.boundary) {
			constrained.above = this.boundary.above >= 0 ? Math.min(spaceAround.above, this.boundary.above) : spaceAround.above;
			constrained.below = this.boundary.below >= 0 ? Math.min(spaceAround.below, this.boundary.below) : spaceAround.below;
			constrained.left = this.boundary.left >= 0 ? Math.min(spaceAround.left, this.boundary.left) : spaceAround.left;
			constrained.right = this.boundary.right >= 0 ? Math.min(spaceAround.right, this.boundary.right) : spaceAround.right;
		}
		const isRTL = this.getAttribute('dir') === 'rtl';
		if ((this.align === 'start' && !isRTL) || (this.align === 'end' && isRTL)) {
			constrained.left = Math.max(0, spaceRequired.width - (targetRect.width + spaceAround.right));
		} else if ((this.align === 'start' && isRTL) || (this.align === 'end' && !isRTL)) {
			constrained.right = Math.max(0, spaceRequired.width - (targetRect.width + spaceAround.left));
		}
		return constrained;
	}

	_getBottomTrayStyling() {

		let maxHeightOverride;
		let availableHeight = Math.min(window.innerHeight, window.screen.height);
		if (this._ifrauContextInfo) availableHeight = this._ifrauContextInfo.availableHeight;
		// default maximum height for bottom tray (42px margin)
		const mobileTrayMaxHeightDefault = availableHeight - minBackdropHeightMobile;
		if (this.maxHeight) {
			// if maxWidth provided is smaller, use the maxWidth
			maxHeightOverride = Math.min(mobileTrayMaxHeightDefault, this.maxHeight);
		} else {
			maxHeightOverride = mobileTrayMaxHeightDefault;
		}
		maxHeightOverride = `${maxHeightOverride}px`;

		let bottomOverride;
		if (this._ifrauContextInfo) {
			// Bottom override is measured as
			// the distance from the bottom of the screen
			const screenHeight =
				window.innerHeight
				- this._ifrauContextInfo.availableHeight
				+ Math.min(this._ifrauContextInfo.top, 0);
			bottomOverride = `${screenHeight}px`;
		}

		const widthOverride = '100vw';

		const widthStyle = {
			minWidth: widthOverride,
			width: widthOverride,
			maxHeight: maxHeightOverride,
			bottom: bottomOverride
		};

		const contentWidthStyle = {
			/* set width of content in addition to width container so header and footer borders are full width */
			width: widthOverride
		};

		const headerStyle = {
			...contentWidthStyle,
			minHeight: this._hasHeader ? 'auto' : '5px'
		};

		const footerStyle = {
			...contentWidthStyle,
			minHeight: this._hasFooter || !this.noMobileCloseButton ? 'auto' : '5px'
		};

		const contentStyle = {
			...contentWidthStyle,
			maxHeight: maxHeightOverride,
			overflowY: this._contentOverflow ? 'auto' : 'hidden'
		};

		const closeButtonStyles = {
			display: !this.noMobileCloseButton ? 'inline-block' : 'none',
			width: this._getTrayFooterWidth(),
			padding: this._hasFooter && !this.noPaddingFooter ? '12px 0 0 0' : '12px',
			margin: this._getTrayFooterMargin()
		};

		return {
			'width' : widthStyle,
			'header' : headerStyle,
			'footer' : footerStyle,
			'content' : contentStyle,
			'close' : closeButtonStyles
		};
	}

	_getDropdownStyling() {
		const widthStyle = {
			maxWidth: this.maxWidth ? `${this.maxWidth}px` : '',
			minWidth: this.minWidth ? `${this.minWidth}px` : '',
			/* add 2 to content width since scrollWidth does not include border */
			width: this._width ? `${this._width + 20}px` : ''
		};

		const contentWidthStyle = {
			minWidth: this.minWidth ? `${this.minWidth}px` : '',
			/* set width of content in addition to width container so header and footer borders are full width */
			width: this._width ? `${this._width + 18}px` : '',
		};

		const contentStyle = {
			...contentWidthStyle,
			maxHeight: this._contentHeight ? `${this._contentHeight}px` : '',
			overflowY: this._contentOverflow ? 'auto' : 'hidden'
		};

		const closeButtonStyle = {
			display: 'none',
		};

		return {
			'width' : widthStyle,
			'content' : contentStyle,
			'close' : closeButtonStyle,
			'header' : contentWidthStyle,
			'footer' : contentWidthStyle
		};
	}

	_getLeftRightTrayStyling() {

		let maxWidthOverride = this.maxWidth;
		let availableWidth = Math.min(window.innerWidth, window.screen.width);
		if (this._ifrauContextInfo) availableWidth = this._ifrauContextInfo.availableWidth;
		// default maximum width for tray (30px margin)
		const mobileTrayMaxWidthDefault = Math.min(availableWidth - minBackdropWidthMobile, 420);
		if (maxWidthOverride) {
			// if maxWidth provided is smaller, use the maxWidth
			maxWidthOverride = Math.min(mobileTrayMaxWidthDefault, maxWidthOverride);
		} else {
			maxWidthOverride = mobileTrayMaxWidthDefault;
		}

		let minWidthOverride = this.minWidth;
		// minimum size - 285px
		const mobileTrayMinWidthDefault = 285;
		if (minWidthOverride) {
			// if minWidth provided is smaller, use the minumum width for tray
			minWidthOverride = Math.max(mobileTrayMinWidthDefault, minWidthOverride);
		} else {
			minWidthOverride = mobileTrayMinWidthDefault;
		}

		// if no width property set, automatically size to maximum width
		let widthOverride = this._width ? this._width : maxWidthOverride;
		// ensure width is between minWidth and maxWidth
		if (widthOverride && maxWidthOverride && widthOverride > (maxWidthOverride - 20)) widthOverride = maxWidthOverride - 20;
		if (widthOverride && minWidthOverride && widthOverride < (minWidthOverride - 20)) widthOverride = minWidthOverride - 20;

		maxWidthOverride = `${maxWidthOverride}px`;
		minWidthOverride = `${minWidthOverride}px`;
		const  contentWidth = `${widthOverride + 18}px`;
		/* add 2 to content width since scrollWidth does not include border */
		const containerWidth = `${widthOverride + 20}px`;

		let maxHeightOverride = '';
		if (this._ifrauContextInfo) maxHeightOverride = `${this._ifrauContextInfo.availableHeight}px`;

		let topOverride;
		if (this._ifrauContextInfo) {
			// if inside iframe, use ifrauContext top as top of screen
			topOverride = `${this._ifrauContextInfo.top < 0 ? -this._ifrauContextInfo.top : 0}px`;
		} else if (window.innerHeight > window.screen.height) {
			// non-responsive page, manually override top to scroll distance
			topOverride = window.pageYOffset;
		}

		let rightOverride;
		let leftOverride;
		if (this.mobileTray === 'right') {
			// On non-responsive pages, the innerWidth may be wider than the screen,
			// override right to stick to right of viewport
			rightOverride = `${Math.max(window.innerWidth - window.screen.width, 0)}px`;
		}
		if (this.mobileTray === 'left') {
			// On non-responsive pages, the innerWidth may be wider than the screen,
			// override left to stick to left of viewport
			leftOverride = `${Math.max(window.innerWidth - window.screen.width, 0)}px`;
		}

		const widthStyle = {
			maxWidth: maxWidthOverride,
			minWidth: minWidthOverride,
			width: containerWidth,
			maxHeight: maxHeightOverride,
			top: topOverride,
			right: rightOverride,
			left: leftOverride,
		};

		const contentWidthStyle = {
			minWidth: minWidthOverride,
			/* set width of content in addition to width container so header and footer borders are full width */
			width: contentWidth,
		};

		const headerStyle = {
			...contentWidthStyle,
			minHeight: this._hasHeader ? 'auto' : '5px'
		};

		const footerStyle = {
			...contentWidthStyle,
			minHeight: this._hasFooter || !this.noMobileCloseButton ? 'auto' : '5px'
		};

		const contentStyle = {
			...contentWidthStyle,
			maxHeight: maxHeightOverride,
			overflowY: this._contentOverflow ? 'auto' : 'hidden'
		};

		const closeButtonStyles = {
			display: !this.noMobileCloseButton ? 'inline-block' : 'none',
			width: this._getTrayFooterWidth(),
			padding: this._hasFooter && !this.noPaddingFooter ? '12px 0 0 0' : '12px',
			margin: this._getTrayFooterMargin()
		};

		return {
			'width' : widthStyle,
			'header' : headerStyle,
			'footer' : footerStyle,
			'content' : contentStyle,
			'close' : closeButtonStyles
		};
	}

	_getOpenedAbove(spaceAround, spaceAroundScroll, spaceRequired) {
		if (spaceAround.below >= spaceRequired.height) {
			return false;
		}
		if (spaceAround.above >= spaceRequired.height) {
			return true;
		}
		if (!this.noAutoFit) {
			// if auto-fit is enabled, scroll will be enabled for the
			// inner content so it will always fit in the available space
			// so pick the largest space it can be displayed in
			return spaceAround.above > spaceAround.below;
		}
		if (spaceAroundScroll.below >= spaceRequired.height) {
			return false;
		}
		if (spaceAroundScroll.above >= spaceRequired.height) {
			return true;
		}
		// if auto-fit is disabled and it doesn't fit in the scrollable space
		// above or below, always open down because it can add scrollable space
		return false;
	}

	_getPosition(spaceAround, centerDelta) {

		const contentXAdjustment = centerDelta / 2;
		if (centerDelta <= 0) {
			return contentXAdjustment * -1;
		}
		if (spaceAround.left > contentXAdjustment && spaceAround.right > contentXAdjustment) {
			// center with target
			return contentXAdjustment * -1;
		}
		const isRTL = this.getAttribute('dir') === 'rtl';
		if (!isRTL) {
			if (spaceAround.left < contentXAdjustment) {
				// slide content right (not enough space to center)
				return spaceAround.left * -1;
			} else if (spaceAround.right < contentXAdjustment) {
				// slide content left (not enough space to center)
				return (centerDelta * -1) + spaceAround.right;
			}
		} else {
			if (spaceAround.left < contentXAdjustment) {
				// slide content right (not enough space to center)
				return (centerDelta * -1) + spaceAround.left;
			} else if (spaceAround.right < contentXAdjustment) {
				// slide content left (not enough space to center)
				return spaceAround.right * -1;
			}
		}
		return null;
	}

	_getTrayFooterMargin() {
		let footerMargin;
		if (this._hasFooter) {
			footerMargin = '0';
		} else if (this.getAttribute('dir') === 'rtl') {
			footerMargin = '-20px -20px -20px 0px';
		} else {
			footerMargin = '-20px 0 -20px -20px';
		}
		return footerMargin;
	}

	_getTrayFooterWidth() {
		let footerWidth;
		if (this.noPaddingFooter) {
			footerWidth = 'calc(100% - 24px)';
		} else if (this._hasFooter) {
			footerWidth = '100%';
		} else {
			footerWidth = 'calc(100% + 16px)';
		}
		return footerWidth;
	}

	_handleFocusTrapEnter() {
		if (this.__applyFocus && !this.noAutoFocus) {
			const content = this.getContentContainer();
			const focusable = getFirstFocusableDescendant(content);
			if (focusable) {
				// Removing the rAF call can allow infinite focus looping to happen in content using a focus trap
				requestAnimationFrame(() => focusable.focus());
			} else {
				content.setAttribute('tabindex', '-1');
				content.focus();
			}
		}
		/** Dispatched when user focus enters the dropdown content (trap-focus option only) */
		this.dispatchEvent(new CustomEvent('d2l-dropdown-focus-enter', { detail:{ applyFocus: this.__applyFocus } }));
	}

	async _handleMobileResize() {
		this._useMobileStyling =  this.mediaQueryList.matches;
		if (this.opened) this._showBackdrop = this._useMobileStyling && this.mobileTray;
		if (this.opened) await this.__position();
	}

	_renderContent() {
		const positionStyle = {};
		const isRTL = this.getAttribute('dir') === 'rtl';
		if (this._position) {
			if (!isRTL) {
				positionStyle.left = `${this._position}px`;
			} else {
				positionStyle.right = `${this._position}px`;
			}
		}

		const mobileTrayRightLeft = this._useMobileStyling && (this.mobileTray === 'right' || this.mobileTray === 'left');
		const mobileTrayBottom = this._useMobileStyling && (this.mobileTray === 'bottom');

		let stylesMap;
		if (mobileTrayBottom) {
			stylesMap = this._getBottomTrayStyling();
		} else if (mobileTrayRightLeft) {
			stylesMap = this._getLeftRightTrayStyling();
		} else {
			stylesMap = this._getDropdownStyling();
		}
		const widthStyle = stylesMap['width'];
		const headerStyle = stylesMap['header'];
		const footerStyle = stylesMap['footer'];
		const contentStyle = stylesMap['content'];
		const closeButtonStyles = stylesMap['close'];

		const topClasses = {
			'd2l-dropdown-content-top': true,
			'd2l-dropdown-content-top-scroll': this._topOverflow,
			'd2l-dropdown-content-header': this._hasHeader
		};
		const bottomClasses = {
			'd2l-dropdown-content-bottom': true,
			'd2l-dropdown-content-bottom-scroll': this._bottomOverflow,
			'd2l-dropdown-content-footer': this._hasFooter || (this._useMobileStyling && this.mobileTray && !this.noMobileCloseButton)
		};

		let dropdownContentSlots = html`
			<div
			id="d2l-dropdown-wrapper"
			class="d2l-dropdown-content-width"
			style=${styleMap(widthStyle)}
			?data-closing="${this._closing}">
				<div class=${classMap(topClasses)} style=${styleMap(headerStyle)}>
					<slot name="header" @slotchange="${this.__handleHeaderSlotChange}"></slot>
				</div>
				<div
				class="d2l-dropdown-content-container"
				style=${styleMap(contentStyle)}
				@scroll=${this.__toggleScrollStyles}>
					<slot class="d2l-dropdown-content-slot"></slot>
				</div>
				<div class=${classMap(bottomClasses)} style=${styleMap(footerStyle)}>
					<slot name="footer" @slotchange="${this.__handleFooterSlotChange}"></slot>
					<d2l-button
						class="dropdown-close-btn"
						style=${styleMap(closeButtonStyles)}
						@click=${this.close}>
						${this.localize('components.dropdown.close')}
					</d2l-button>
				</div>
			</div>
		`;

		if (this.trapFocus) {
			dropdownContentSlots = html`
			<d2l-focus-trap
			@d2l-focus-trap-enter="${this._handleFocusTrapEnter}"
			?trap="${this.opened}">
			${dropdownContentSlots}
			</d2l-focus-trap>`;
		}

		const dropdown =  html`
			<div class="d2l-dropdown-content-position" style=${styleMap(positionStyle)}>
					 ${dropdownContentSlots}
			</div>
		`;

		return (this.mobileTray) ? html`
			${dropdown}
			<d2l-backdrop
				for-target="d2l-dropdown-wrapper"
				?shown="${this._showBackdrop}" >
			</d2l-backdrop>`
			: html`${dropdown}`;
	}

};
import '../colors/colors.js';
import { css, html, LitElement } from 'lit';
import { classMap } from 'lit/directives/class-map.js';
import { FocusMixin } from '../../mixins/focus/focus-mixin.js';
import { ifDefined } from 'lit/directives/if-defined.js';
import { offscreenStyles } from '../offscreen/offscreen.js';
import ResizeObserver from 'resize-observer-polyfill/dist/ResizeObserver.es.js';
import { RtlMixin } from '../../mixins/rtl/rtl-mixin.js';
import { styleMap } from 'lit/directives/style-map.js';

/**
 * A container element that provides specific layout using several slots.
 * @slot content - Slot for primary content such as title and supplementary info (no actionable elements)
 * @slot actions - Slot for buttons and dropdown openers to be placed in top right corner of header
 * @slot badge - Slot for badge content, such as a profile image or status indicator
 * @slot footer - Slot for footer content, such secondary actions
 * @slot header - Slot for header content, such as course image (no actionable elements)
 */
class Card extends FocusMixin(RtlMixin(LitElement)) {

	static get properties() {
		return {
			/**
			 * Style the card's content and footer as centered horizontally
			 * @type {boolean}
			 */
			alignCenter: { type: Boolean, attribute: 'align-center', reflect: true },
			/**
			 * Download a URL instead of navigating to it
			 * @type {boolean}
			 */
			download: { type: Boolean, reflect: true },
			/**
			 * Location for the primary action/navigation
			 * @type {string}
			 */
			href: { type: String, reflect: true },
			/**
			 * Indicates the human language of the linked resource; purely advisory, with no built-in functionality
			 * @type {string}
			 */
			hreflang: { type: String, reflect: true },
			/**
			 * Specifies the relationship of the target object to the link object
			 * @type {string}
			 */
			rel: { type: String, reflect: true },
			/**
			 * Subtle aesthetic on non-white backgrounds
			 * @type {boolean}
			 */
			subtle: { type: Boolean, reflect: true },
			/**
			 * Where to display the linked URL
			 * @type {string}
			 */
			target: { type: String, reflect: true },
			/**
			 * Accessible text for the card (will be announced when AT user focuses)
			 * @type {string}
			 */
			text: { type: String, reflect: true },
			/**
			 * Specifies the media type in the form of a MIME type for the linked URL; purely advisory, with no built-in functionality
			 * @type {string}
			 */
			type: { type: String, reflect: true },
			_active: { type: Boolean, reflect: true },
			_dropdownActionOpen: { type: Boolean, attribute: '_dropdown-action-open', reflect: true },
			_hover: { type: Boolean },
			_badgeMarginTop: { type: String },
			_footerHidden: { type: Boolean },
			_tooltipShowing: { type: Boolean, attribute: '_tooltip_showing', reflect: true }
		};
	}

	static get styles() {
		return [offscreenStyles, css`
			:host {
				background-color: #ffffff;
				border: 1px solid var(--d2l-color-gypsum);
				border-radius: 6px;
				box-sizing: border-box;
				display: inline-block;
				position: relative;
				z-index: 0;
			}
			.d2l-card-container {
				align-items: flex-start; /* required so that footer will not stretch to 100% width */
				display: flex;
				flex-direction: column;
				height: 100%;
				position: relative;
			}
			.d2l-card-link-container {
				flex-basis: auto;
				flex-grow: 1;
				flex-shrink: 1;
				width: 100%; /* required for Legacy-Edge and FF when align-items: flex-start is specified */
			}
			.d2l-card-link-text {
				display: inline-block;
			}
			.d2l-card-header {
				border-start-end-radius: 6px;
				border-start-start-radius: 6px;
				overflow: hidden;
			}

			a {
				bottom: -1px;
				display: block;
				left: -1px;
				outline: none;
				position: absolute;
				right: -1px;
				top: -1px;
				z-index: 1;
			}
			:host([subtle]) a {
				bottom: 0;
				left: 0;
				right: 0;
				top: 0;
			}

			:host(:hover) a {
				bottom: -5px;
			}
			:host([subtle]:hover) a {
				bottom: -4px;
			}

			.d2l-card-content {
				padding: 1.2rem 0.8rem 0 0.8rem;
			}
			:host([align-center]) .d2l-card-content {
				text-align: center;
			}

			.d2l-card-footer-hidden .d2l-card-content {
				padding-bottom: 1.2rem;
			}
			.d2l-card-actions {
				inset-inline-end: 0.6rem;
				position: absolute;
				top: 0.6rem;
				/* this must be higher than footer z-index so dropdowns will be on top */
				z-index: 3;
			}
			.d2l-card-actions ::slotted(*) {
				margin-inline-start: 0.3rem;
			}
			.d2l-card-badge {
				line-height: 0;
				padding: 0 0.8rem;
			}
			.d2l-card-footer {
				box-sizing: border-box;
				flex: none;
				padding: 1.2rem 0.8rem 0.6rem 0.8rem;
				pointer-events: none;
				width: 100%;
				z-index: 2;
			}
			:host([align-center]) .d2l-card-footer {
				text-align: center;
			}

			.d2l-card-footer ::slotted([slot="footer"]) {
				pointer-events: all;
			}

			.d2l-card-footer-hidden .d2l-card-footer {
				box-sizing: content-box;
				height: auto;
			}

			:host([subtle]) {
				border: none;
			}
			:host([subtle][href]) {
				box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.03);
			}
			:host([href]:not([_active]):hover) {
				box-shadow: 0 2px 14px 1px rgba(0, 0, 0, 0.06);
			}
			:host([subtle][href]:not([_active]):hover) {
				box-shadow: 0 4px 18px 2px rgba(0, 0, 0, 0.06);
			}
			${getFocusRingStyles(() => ':host([_active])', {'extraStyles': css`border-color: transparent;`})}
			/* .d2l-card-link-container-hover is used to only color/underline when
			hovering the anchor; these styles are not applied when hovering actions */
			:host([href]) .d2l-card-link-container-hover,
			:host([href][_active]) .d2l-card-content {
				color: var(--d2l-color-celestine);
				text-decoration: underline;
			}
			/* this is needed to ensure tooltip is not be clipped by adjacent cards */
			:host([_tooltip_showing]) {
				z-index: 1;
			}
			/* this is needed to ensure open menu will be ontop of adjacent cards */
			:host([_dropdown-action-open]) {
				z-index: 2;
			}
			@media (prefers-reduced-motion: no-preference) {
				:host {
					transition: box-shadow 0.2s;
				}
			}
			@media (prefers-contrast: more) {
				:host([subtle]) {
					border: 1px solid var(--d2l-color-gypsum);;
				}
			}
		`];
	}

	constructor() {
		super();
		this.alignCenter = false;
		this.download = false;
		this.subtle = false;
		this._active = false;
		this._dropdownActionOpen = false;
		this._footerHidden = true;
		this._hover = false;
		this._tooltipShowing = false;
		this._onBadgeResize = this._onBadgeResize.bind(this);
		this._onFooterResize = this._onFooterResize.bind(this);
	}

	static get focusElementSelector() {
		return 'a';
	}

	firstUpdated(changedProperties) {
		super.firstUpdated(changedProperties);
		const badgeObserver = new ResizeObserver(this._onBadgeResize);
		badgeObserver.observe(this.shadowRoot.querySelector('.d2l-card-badge'));
		const footerObserver = new ResizeObserver(this._onFooterResize);
		footerObserver.observe(this.shadowRoot.querySelector('.d2l-card-footer'));
	}

	render() {

		const containerClass = {
			'd2l-card-container': true,
			'd2l-visible-on-ancestor-target': true,
			'd2l-card-footer-hidden': this._footerHidden
		};

		const linkContainerClass = {
			'd2l-card-link-container': true,
			'd2l-card-link-container-hover': this._hover
		};

		const badgeStyle = {};
		if (this._badgeMarginTop) badgeStyle.marginTop = this._badgeMarginTop;

		const footerClass = {
			'd2l-card-footer': true,
			'd2l-offscreen': this._footerHidden
		};

		return html`
			<div class="${classMap(containerClass)}"
				@d2l-dropdown-open="${this._onDropdownOpen}"
				@d2l-dropdown-close="${this._onDropdownClose}"
				@d2l-tooltip-show="${this._onTooltipShow}"
				@d2l-tooltip-hide="${this._onTooltipHide}">
				<a @blur="${this._onLinkBlur}"
					?download="${this.download}"
					@focus="${this._onLinkFocus}"
					href="${ifDefined(this.href ? this.href : undefined)}"
					hreflang="${ifDefined(this.hreflang)}"
					@mouseenter="${this._onLinkMouseEnter}"
					@mouseleave="${this._onLinkMouseLeave}"
					rel="${ifDefined(this.rel)}"
					target="${ifDefined(this.target)}"
					type="${ifDefined(this.type)}">
					<span class="d2l-card-link-text d2l-offscreen">${this.text}</span>
				</a>
				<div class="${classMap(linkContainerClass)}">
					<div class="d2l-card-header"><slot name="header"></slot></div>
					<div class="d2l-card-badge" style="${styleMap(badgeStyle)}"><slot name="badge"></slot></div>
					<div class="d2l-card-content"><slot name="content"></slot></div>
				</div>
				<div class="d2l-card-actions"><slot name="actions"></slot></div>
				<div class="${classMap(footerClass)}"><slot name="footer"></slot></div>
			</div>
		`;
	}

	_onBadgeResize(entries) {
		if (!entries || entries.length === 0) return;
		const entry = entries[0];
		this._badgeMarginTop = `${-0.5 * entry.contentRect.height}px`;
	}

	_onDropdownClose() {
		this._dropdownActionOpen = false;
	}

	_onDropdownOpen() {
		this._dropdownActionOpen = true;
	}

	_onFooterResize(entries) {
		if (!entries || entries.length === 0) return;
		const entry = entries[0];
		// firefox has a rounding error when calculating the height of the contentRect
		// with `box-sizing: border-box;` so check for numbers which are close to 0 as well
		this._footerHidden = (entry.contentRect.height < 1);
	}

	_onLinkBlur() {
		this._active = false;
	}

	_onLinkFocus() {
		this._active = true;
	}

	_onLinkMouseEnter() {
		this._hover = true;
	}

	_onLinkMouseLeave() {
		this._hover = false;
	}

	_onTooltipHide() {
		this._tooltipShowing = false;
	}

	_onTooltipShow() {
		this._tooltipShowing = true;
	}

}

customElements.define('d2l-card', Card);

Language Samples

// digital pin 2 has a pushbutton attached to it. Give it a name:
int pushButton = 2;

// the setup routine runs once when you press reset:
void setup() {
	// initialize serial communication at 9600 bits per second:
	Serial.begin(9600);
	// make the pushbutton's pin an input:
	pinMode(pushButton, INPUT);
}

// the loop routine runs over and over again forever:
void loop() {
	// read the input pin:
	int buttonState = digitalRead(pushButton);
	// print out the state of the button:
	Serial.println(buttonState);
	delay(1); // delay in between reads for stability
}

	AREA     ARMex, CODE, READONLY
                            ; Name this block of code ARMex
	ENTRY                   ; Mark first instruction to execute
start
	MOV      r0, #10        ; Set up parameters
	MOV      r1, #3
	ADD      r0, r0, r1     ; r0 = r0 + r1
stop
	MOV      r0, #0x18      ; angel_SWIreason_ReportException
	LDR      r1, =0x20026   ; ADP_Stopped_ApplicationExit
	SVC      #0x123456      ; ARM semihosting (formerly SWI)
	END                     ; Mark end of file
#!/bin/bash
if [ -d $directory ]; then
	echo "Directory exists"
else
	echo "Directory does not exists"
fi
#include <stdio.h>
int main() {
	char c;
	printf("Enter a character: ");
	scanf("%c", &c);

	// %d displays the integer value of a character
	// %c displays the actual character
	printf("ASCII value of %c = %d", c, c);

	return 0;
}
#include <iostream>
using namespace std;

int main()
{
	int divisor, dividend, quotient, remainder;

	cout << "Enter dividend: ";
	cin >> dividend;

	cout << "Enter divisor: ";
	cin >> divisor;

	quotient = dividend / divisor;
	remainder = dividend % divisor;

	cout << "Quotient = " << quotient << endl;
	cout << "Remainder = " << remainder;

	return 0;
}
using System;

namespace Method {

	class Program {

		// method declaration
		public void display() {
			Console.WriteLine("Hello World");
		}

		static void Main(string[] args) {

			// create class object
			Program p1 = new Program();

			//call method
			p1.display();

			Console.ReadLine();

		}
	}
}
.grumpy > img {
	background-image: url("smile.png");
	height: 100%;
	width: var(--some-var);
}
@font-face {
	font-family: 'Lato';
	font-style: normal;
	src: local('Lato Regular');
}
@media (prefers-reduced-motion: reduce) {
	:host([opened]), :host([opened-above]) {
		animation: none !important;
	}
}
{-# START_FILE main.hs #-}
import System.IO

main = do
	handle <- openFile "file.txt" ReadMode
	contents <- hGetContents handle
	putStr contents
	hClose handle

{-# START_FILE file.txt #-}
Hello, world!

import System.Random

main = (randomRIO (1, 100) :: IO Int) >>= print
public class VowelConsonant {

	public static void main(String[] args) {

		char ch = 'i';

		if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' )
			System.out.println(ch + " is vowel");
		else
			System.out.println(ch + " is consonant");

	}
}

/* grumpy javascript */

import { stuff } from 'some/where.js';

function helloGrumpy(name) {
	console.log(`Hi there ${name}.`);
}

class Wizard extends Human { }

const grumpy = new Wizard();

let wizardFoods = [...donuts, ... cakes, ...pies];

const wizardsLikeBeer = false;

const favouriteNumber = 3.14159;

const PI = 3.14159;

const regex = /[^\w\s]/g; // regex, regex-delimiter, regex-source, regex-flag
{
	"jinxed": "gnomes",
	"grumpy": [ "wizards" ],
	"jelly": 99,
	"donut": true,
	"fritter": null
}
fun main(args: Array) {

	val a = 2.3
	val b = 4
	val c = 5.6
	val root1: Double
	val root2: Double
	val output: String

	val determinant = b * b - 4.0 * a * c

	// condition for real and different roots
	if (determinant > 0) {
		root1 = (-b + Math.sqrt(determinant)) / (2 * a)
		root2 = (-b - Math.sqrt(determinant)) / (2 * a)

		output = "root1 = %.2f and root2 = %.2f".format(root1, root2)
	}
	// Condition for real and equal roots
	else if (determinant == 0.0) {
		root2 = -b / (2 * a)
		root1 = root2

		output = "root1 = root2 = %.2f;".format(root1)
	}
	// If roots are not real
	else {
		val realPart = -b / (2 * a)
		val imaginaryPart = Math.sqrt(-determinant) / (2 * a)

		output = "root1 = %.2f+%.2fi and root2 = %.2f-%.2fi".format(realPart, imaginaryPart, realPart, imaginaryPart)
	}

	println(output)
}

\begin{aligned} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{aligned}

P(E) = {n \choose k} p^k (1-p)^{ n-k}

\begin{aligned} \dot{x} & = \sigma(y-x) \\ \dot{y} & = \rho x - y - xz \\ \dot{z} & = -\beta z + xy \end{aligned}
<!DOCTYPE html> <!-- doctype, doctype-tag, name -->
<html>
	<body class="typography">
		<![CDATA[ some cdata section ]]>
		<div style="color: blue;">
			&pound;
			&#163;
		</div>
	</body>
</html>
for n = 1:5
	x = n*0.1;
	z = myfunc2(x,2,3,7);
	fprintf('x = %4.2f f(x) = %8.4f \r',x,z)
end
# Program to check if a number is prime or not

num = 29

# To take input from the user
#num = int(input("Enter a number: "))

# define a flag variable
flag = False

# prime numbers are greater than 1
if num > 1:
    # check for factors
    for i in range(2, num):
        if (num % i) == 0:
            # if factor is found, set flag to True
            flag = True
            # break out of loop
            break

# check if flag is True
if flag:
    print(num, "is not a prime number")
else:
    print(num, "is a prime number")
# decimal variable
num = as.integer(readline(prompt = "Enter a number: "))
# num = 15
isPrime = 0
if (num > 1) {
	isPrime = 1
	for (i in 2: (num - 1)) {
		if ((num %% i) == 0) {
			isPrime = 0
			break
		}
	}
}
if (num == 2) isPrime = 1
if (isPrime == 1) {
	print(paste(num, "is a prime number"))
} else {
	print(paste(num, "is not a prime number"))
}
(define (rgb-maker mk)
  (lambda (sz)
    (vc-append (colorize (mk sz) "red")
               (colorize (mk sz) "green")
               (colorize (mk sz) "blue"))))
(\W|^)[\w.\-]{0,25}@(yahoo|hotmail|gmail)\.com(\W|$)
(\W|^)po[#\-]{0,1}\s{0,1}\d{2}[\s-]{0,1}\d{4}(\W|$)
^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$
\b(?:word1\W+(?:\w+\W+){1,6}?word2|word2\W+(?:\w+\W+){1,6}?word1)\b
^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
DECLARE @MyCounter INT; /* keyword, variable, punctuation */

SELECT AVG(Calories) AS AverageCalories FROM Desserts;

SELECT * FROM Desserts

SET ROWCOUNT 4;

SET @Hidden = FALSE;

SET @Donuts = 'Yummy';
CloudDeploy[
 FormFunction[FormObject[{"ImageURL" -> "String"}],
  ImageEffect[
    ColorConvert[
     ImageMultiply[
      ColorConvert[
       ImageAdd[ImageAdjust[Import[#ImageURL], .2],
        RGBColor[.25, .25, -.1]], "HSB"], Hue[1, .7, 1]],
     "RGB"], {"PoissonNoise", .5}] &, "JPEG"],
 Permissions -> "Public"]

More Samples (Web Component Scope)