You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

53867 lines
2.5 MiB

/*!
* (C) Ionic http://ionicframework.com - MIT License
*/
'use strict';
var stream = require('stream');
const modeResolutionChain = [];
function hydrateFactory($stencilWindow, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve) {
var globalThis = $stencilWindow;
var self = $stencilWindow;
var top = $stencilWindow;
var parent = $stencilWindow;
var addEventListener = $stencilWindow.addEventListener.bind($stencilWindow);
var alert = $stencilWindow.alert.bind($stencilWindow);
var blur = $stencilWindow.blur.bind($stencilWindow);
var cancelAnimationFrame = $stencilWindow.cancelAnimationFrame.bind($stencilWindow);
var cancelIdleCallback = $stencilWindow.cancelIdleCallback.bind($stencilWindow);
var clearInterval = $stencilWindow.clearInterval.bind($stencilWindow);
var clearTimeout = $stencilWindow.clearTimeout.bind($stencilWindow);
var close = () => {};
var confirm = $stencilWindow.confirm.bind($stencilWindow);
var dispatchEvent = $stencilWindow.dispatchEvent.bind($stencilWindow);
var focus = $stencilWindow.focus.bind($stencilWindow);
var getComputedStyle = $stencilWindow.getComputedStyle.bind($stencilWindow);
var matchMedia = $stencilWindow.matchMedia.bind($stencilWindow);
var open = $stencilWindow.open.bind($stencilWindow);
var prompt = $stencilWindow.prompt.bind($stencilWindow);
var removeEventListener = $stencilWindow.removeEventListener.bind($stencilWindow);
var requestAnimationFrame = $stencilWindow.requestAnimationFrame.bind($stencilWindow);
var requestIdleCallback = $stencilWindow.requestIdleCallback.bind($stencilWindow);
var setInterval = $stencilWindow.setInterval.bind($stencilWindow);
var setTimeout = $stencilWindow.setTimeout.bind($stencilWindow);
var CharacterData = $stencilWindow.CharacterData;
var CSS = $stencilWindow.CSS;
var CustomEvent = $stencilWindow.CustomEvent;
var CSSStyleSheet = $stencilWindow.CSSStyleSheet;
var Document = $stencilWindow.Document;
var ShadowRoot = $stencilWindow.ShadowRoot;
var DocumentFragment = $stencilWindow.DocumentFragment;
var DocumentType = $stencilWindow.DocumentType;
var DOMTokenList = $stencilWindow.DOMTokenList;
var Element = $stencilWindow.Element;
var Event = $stencilWindow.Event;
var HTMLAnchorElement = $stencilWindow.HTMLAnchorElement;
var HTMLBaseElement = $stencilWindow.HTMLBaseElement;
var HTMLButtonElement = $stencilWindow.HTMLButtonElement;
var HTMLCanvasElement = $stencilWindow.HTMLCanvasElement;
var HTMLElement = $stencilWindow.HTMLElement;
var HTMLFormElement = $stencilWindow.HTMLFormElement;
var HTMLImageElement = $stencilWindow.HTMLImageElement;
var HTMLInputElement = $stencilWindow.HTMLInputElement;
var HTMLLinkElement = $stencilWindow.HTMLLinkElement;
var HTMLMetaElement = $stencilWindow.HTMLMetaElement;
var HTMLScriptElement = $stencilWindow.HTMLScriptElement;
var HTMLStyleElement = $stencilWindow.HTMLStyleElement;
var HTMLTemplateElement = $stencilWindow.HTMLTemplateElement;
var HTMLTitleElement = $stencilWindow.HTMLTitleElement;
var IntersectionObserver = $stencilWindow.IntersectionObserver;
var ResizeObserver = $stencilWindow.ResizeObserver;
var KeyboardEvent = $stencilWindow.KeyboardEvent;
var MouseEvent = $stencilWindow.MouseEvent;
var Node = $stencilWindow.Node;
var NodeList = $stencilWindow.NodeList;
var URL = $stencilWindow.URL;
var console = $stencilWindow.console;
var customElements = $stencilWindow.customElements;
var history = $stencilWindow.history;
var localStorage = $stencilWindow.localStorage;
var location = $stencilWindow.location;
var navigator = $stencilWindow.navigator;
var performance = $stencilWindow.performance;
var sessionStorage = $stencilWindow.sessionStorage;
var devicePixelRatio = $stencilWindow.devicePixelRatio;
var innerHeight = $stencilWindow.innerHeight;
var innerWidth = $stencilWindow.innerWidth;
var origin = $stencilWindow.origin;
var pageXOffset = $stencilWindow.pageXOffset;
var pageYOffset = $stencilWindow.pageYOffset;
var screen = $stencilWindow.screen;
var screenLeft = $stencilWindow.screenLeft;
var screenTop = $stencilWindow.screenTop;
var screenX = $stencilWindow.screenX;
var screenY = $stencilWindow.screenY;
var scrollX = $stencilWindow.scrollX;
var scrollY = $stencilWindow.scrollY;
var exports = {};
var fetch, FetchError, Headers, Request, Response;
if (typeof $stencilWindow.fetch === 'function') {
fetch = $stencilWindow.fetch;
} else {
fetch = $stencilWindow.fetch = function() { throw new Error('fetch() is not implemented'); };
}
if (typeof $stencilWindow.FetchError === 'function') {
FetchError = $stencilWindow.FetchError;
} else {
FetchError = $stencilWindow.FetchError = class FetchError { constructor() { throw new Error('FetchError is not implemented'); } };
}
if (typeof $stencilWindow.Headers === 'function') {
Headers = $stencilWindow.Headers;
} else {
Headers = $stencilWindow.Headers = class Headers { constructor() { throw new Error('Headers is not implemented'); } };
}
if (typeof $stencilWindow.Request === 'function') {
Request = $stencilWindow.Request;
} else {
Request = $stencilWindow.Request = class Request { constructor() { throw new Error('Request is not implemented'); } };
}
if (typeof $stencilWindow.Response === 'function') {
Response = $stencilWindow.Response;
} else {
Response = $stencilWindow.Response = class Response { constructor() { throw new Error('Response is not implemented'); } };
}
function hydrateAppClosure($stencilWindow) {
const window = $stencilWindow;
const document = $stencilWindow.document;
/*hydrateAppClosure start*/
const NAMESPACE = 'ionic';
const BUILD = /* ionic */ { hydratedSelectorName: "hydrated", slotRelocation: true, updatable: true};
// TODO(FW-2832): types
class Config {
constructor() {
this.m = new Map();
}
reset(configObj) {
this.m = new Map(Object.entries(configObj));
}
get(key, fallback) {
const value = this.m.get(key);
return value !== undefined ? value : fallback;
}
getBoolean(key, fallback = false) {
const val = this.m.get(key);
if (val === undefined) {
return fallback;
}
if (typeof val === 'string') {
return val === 'true';
}
return !!val;
}
getNumber(key, fallback) {
const val = parseFloat(this.m.get(key));
return isNaN(val) ? (fallback !== undefined ? fallback : NaN) : val;
}
set(key, value) {
this.m.set(key, value);
}
}
const config = /*@__PURE__*/ new Config();
const configFromSession = (win) => {
try {
const configStr = win.sessionStorage.getItem(IONIC_SESSION_KEY);
return configStr !== null ? JSON.parse(configStr) : {};
}
catch (e) {
return {};
}
};
const saveConfig = (win, c) => {
try {
win.sessionStorage.setItem(IONIC_SESSION_KEY, JSON.stringify(c));
}
catch (e) {
return;
}
};
const configFromURL = (win) => {
const configObj = {};
win.location.search
.slice(1)
.split('&')
.map((entry) => entry.split('='))
.map(([key, value]) => {
try {
return [decodeURIComponent(key), decodeURIComponent(value)];
}
catch (e) {
return ['', ''];
}
})
.filter(([key]) => startsWith(key, IONIC_PREFIX))
.map(([key, value]) => [key.slice(IONIC_PREFIX.length), value])
.forEach(([key, value]) => {
configObj[key] = value;
});
return configObj;
};
const startsWith = (input, search) => {
return input.substr(0, search.length) === search;
};
const IONIC_PREFIX = 'ionic:';
const IONIC_SESSION_KEY = 'ionic-persist-config';
var LogLevel;
(function (LogLevel) {
LogLevel["OFF"] = "OFF";
LogLevel["ERROR"] = "ERROR";
LogLevel["WARN"] = "WARN";
})(LogLevel || (LogLevel = {}));
/**
* Logs a warning to the console with an Ionic prefix
* to indicate the library that is warning the developer.
*
* @param message - The string message to be logged to the console.
*/
const printIonWarning = (message, ...params) => {
const logLevel = config.get('logLevel', LogLevel.WARN);
if ([LogLevel.WARN].includes(logLevel)) {
return console.warn(`[Ionic Warning]: ${message}`, ...params);
}
};
/**
* Logs an error to the console with an Ionic prefix
* to indicate the library that is warning the developer.
*
* @param message - The string message to be logged to the console.
* @param params - Additional arguments to supply to the console.error.
*/
const printIonError = (message, ...params) => {
const logLevel = config.get('logLevel', LogLevel.ERROR);
if ([LogLevel.ERROR, LogLevel.WARN].includes(logLevel)) {
return console.error(`[Ionic Error]: ${message}`, ...params);
}
};
/**
* Prints an error informing developers that an implementation requires an element to be used
* within a specific selector.
*
* @param el The web component element this is requiring the element.
* @param targetSelectors The selector or selectors that were not found.
*/
const printRequiredElementError = (el, ...targetSelectors) => {
return console.error(`<${el.tagName.toLowerCase()}> must be used inside ${targetSelectors.join(' or ')}.`);
};
const getPlatforms = (win) => setupPlatforms(win);
const isPlatform = (winOrPlatform, platform) => {
if (typeof winOrPlatform === 'string') {
platform = winOrPlatform;
winOrPlatform = undefined;
}
return getPlatforms(winOrPlatform).includes(platform);
};
const setupPlatforms = (win = window) => {
if (typeof win === 'undefined') {
return [];
}
win.Ionic = win.Ionic || {};
let platforms = win.Ionic.platforms;
if (platforms == null) {
platforms = win.Ionic.platforms = detectPlatforms(win);
platforms.forEach((p) => win.document.documentElement.classList.add(`plt-${p}`));
}
return platforms;
};
const detectPlatforms = (win) => {
const customPlatformMethods = config.get('platform');
return Object.keys(PLATFORMS_MAP).filter((p) => {
const customMethod = customPlatformMethods === null || customPlatformMethods === void 0 ? void 0 : customPlatformMethods[p];
return typeof customMethod === 'function' ? customMethod(win) : PLATFORMS_MAP[p](win);
});
};
const isMobileWeb = (win) => isMobile(win) && !isHybrid(win);
const isIpad = (win) => {
// iOS 12 and below
if (testUserAgent(win, /iPad/i)) {
return true;
}
// iOS 13+
if (testUserAgent(win, /Macintosh/i) && isMobile(win)) {
return true;
}
return false;
};
const isIphone = (win) => testUserAgent(win, /iPhone/i);
const isIOS = (win) => testUserAgent(win, /iPhone|iPod/i) || isIpad(win);
const isAndroid = (win) => testUserAgent(win, /android|sink/i);
const isAndroidTablet = (win) => {
return isAndroid(win) && !testUserAgent(win, /mobile/i);
};
const isPhablet = (win) => {
const width = win.innerWidth;
const height = win.innerHeight;
const smallest = Math.min(width, height);
const largest = Math.max(width, height);
return smallest > 390 && smallest < 520 && largest > 620 && largest < 800;
};
const isTablet = (win) => {
const width = win.innerWidth;
const height = win.innerHeight;
const smallest = Math.min(width, height);
const largest = Math.max(width, height);
return isIpad(win) || isAndroidTablet(win) || (smallest > 460 && smallest < 820 && largest > 780 && largest < 1400);
};
const isMobile = (win) => matchMedia$1(win, '(any-pointer:coarse)');
const isDesktop = (win) => !isMobile(win);
const isHybrid = (win) => isCordova(win) || isCapacitorNative(win);
const isCordova = (win) => !!(win['cordova'] || win['phonegap'] || win['PhoneGap']);
const isCapacitorNative = (win) => {
const capacitor = win['Capacitor'];
// TODO(ROU-11693): Remove when we no longer support Capacitor 2, which does not have isNativePlatform
return !!((capacitor === null || capacitor === void 0 ? void 0 : capacitor.isNative) || ((capacitor === null || capacitor === void 0 ? void 0 : capacitor.isNativePlatform) && !!capacitor.isNativePlatform()));
};
const isElectron = (win) => testUserAgent(win, /electron/i);
const isPWA = (win) => { var _a; return !!(((_a = win.matchMedia) === null || _a === void 0 ? void 0 : _a.call(win, '(display-mode: standalone)').matches) || win.navigator.standalone); };
const testUserAgent = (win, expr) => expr.test(win.navigator.userAgent);
const matchMedia$1 = (win, query) => { var _a; return (_a = win.matchMedia) === null || _a === void 0 ? void 0 : _a.call(win, query).matches; };
const PLATFORMS_MAP = {
ipad: isIpad,
iphone: isIphone,
ios: isIOS,
android: isAndroid,
phablet: isPhablet,
tablet: isTablet,
cordova: isCordova,
capacitor: isCapacitorNative,
electron: isElectron,
pwa: isPWA,
mobile: isMobile,
mobileweb: isMobileWeb,
desktop: isDesktop,
hybrid: isHybrid,
};
// TODO(FW-2832): types
let defaultMode;
const getIonMode$1 = (ref) => {
return (ref && getMode(ref)) || defaultMode;
};
const initialize = (userConfig = {}) => {
if (typeof window === 'undefined') {
return;
}
const doc = window.document;
const win = window;
const Ionic = (win.Ionic = win.Ionic || {});
// create the Ionic.config from raw config object (if it exists)
// and convert Ionic.config into a ConfigApi that has a get() fn
const configObj = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, configFromSession(win)), { persistConfig: false }), Ionic.config), configFromURL(win)), userConfig);
config.reset(configObj);
if (config.getBoolean('persistConfig')) {
saveConfig(win, configObj);
}
// Setup platforms
setupPlatforms(win);
// first see if the mode was set as an attribute on <html>
// which could have been set by the user, or by pre-rendering
// otherwise get the mode via config settings, and fallback to md
Ionic.config = config;
Ionic.mode = defaultMode = config.get('mode', doc.documentElement.getAttribute('mode') || (isPlatform(win, 'ios') ? 'ios' : 'md'));
config.set('mode', defaultMode);
doc.documentElement.setAttribute('mode', defaultMode);
doc.documentElement.classList.add(defaultMode);
if (config.getBoolean('_testing')) {
config.set('animated', false);
}
const isIonicElement = (elm) => { var _a; return (_a = elm.tagName) === null || _a === void 0 ? void 0 : _a.startsWith('ION-'); };
const isAllowedIonicModeValue = (elmMode) => ['ios', 'md'].includes(elmMode);
setMode((elm) => {
while (elm) {
const elmMode = elm.mode || elm.getAttribute('mode');
if (elmMode) {
if (isAllowedIonicModeValue(elmMode)) {
return elmMode;
}
else if (isIonicElement(elm)) {
printIonWarning('Invalid ionic mode: "' + elmMode + '", expected: "ios" or "md"');
}
}
elm = elm.parentElement;
}
return defaultMode;
});
};
const globalScripts = initialize;
/*
Stencil Hydrate Platform v4.38.0 | MIT Licensed | https://stenciljs.com
*/
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/utils/constants.ts
var SVG_NS = "http://www.w3.org/2000/svg";
var HTML_NS = "http://www.w3.org/1999/xhtml";
var PrimitiveType = /* @__PURE__ */ ((PrimitiveType2) => {
PrimitiveType2["Undefined"] = "undefined";
PrimitiveType2["Null"] = "null";
PrimitiveType2["String"] = "string";
PrimitiveType2["Number"] = "number";
PrimitiveType2["SpecialNumber"] = "number";
PrimitiveType2["Boolean"] = "boolean";
PrimitiveType2["BigInt"] = "bigint";
return PrimitiveType2;
})(PrimitiveType || {});
var NonPrimitiveType = /* @__PURE__ */ ((NonPrimitiveType2) => {
NonPrimitiveType2["Array"] = "array";
NonPrimitiveType2["Date"] = "date";
NonPrimitiveType2["Map"] = "map";
NonPrimitiveType2["Object"] = "object";
NonPrimitiveType2["RegularExpression"] = "regexp";
NonPrimitiveType2["Set"] = "set";
NonPrimitiveType2["Channel"] = "channel";
NonPrimitiveType2["Symbol"] = "symbol";
return NonPrimitiveType2;
})(NonPrimitiveType || {});
var TYPE_CONSTANT = "type";
var VALUE_CONSTANT = "value";
var SERIALIZED_PREFIX = "serialized:";
// src/utils/helpers.ts
var isDef = (v) => v != null && v !== void 0;
var isComplexType = (o) => {
o = typeof o;
return o === "object" || o === "function";
};
// src/utils/query-nonce-meta-tag-content.ts
function queryNonceMetaTagContent(doc) {
var _a, _b, _c;
return (_c = (_b = (_a = doc.head) == null ? void 0 : _a.querySelector('meta[name="csp-nonce"]')) == null ? void 0 : _b.getAttribute("content")) != null ? _c : void 0;
}
// src/utils/regular-expression.ts
var escapeRegExpSpecialCharacters = (text) => {
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};
// src/utils/remote-value.ts
var RemoteValue = class _RemoteValue {
/**
* Deserializes a LocalValue serialized object back to its original JavaScript representation
*
* @param serialized The serialized LocalValue object
* @returns The original JavaScript value/object
*/
static fromLocalValue(serialized) {
const type = serialized[TYPE_CONSTANT];
const value = VALUE_CONSTANT in serialized ? serialized[VALUE_CONSTANT] : void 0;
switch (type) {
case "string" /* String */:
return value;
case "boolean" /* Boolean */:
return value;
case "bigint" /* BigInt */:
return BigInt(value);
case "undefined" /* Undefined */:
return void 0;
case "null" /* Null */:
return null;
case "number" /* Number */:
if (value === "NaN") return NaN;
if (value === "-0") return -0;
if (value === "Infinity") return Infinity;
if (value === "-Infinity") return -Infinity;
return value;
case "array" /* Array */:
return value.map((item) => _RemoteValue.fromLocalValue(item));
case "date" /* Date */:
return new Date(value);
case "map" /* Map */:
const map2 = /* @__PURE__ */ new Map();
for (const [key, val] of value) {
const deserializedKey = typeof key === "object" && key !== null ? _RemoteValue.fromLocalValue(key) : key;
const deserializedValue = _RemoteValue.fromLocalValue(val);
map2.set(deserializedKey, deserializedValue);
}
return map2;
case "object" /* Object */:
const obj = {};
for (const [key, val] of value) {
obj[key] = _RemoteValue.fromLocalValue(val);
}
return obj;
case "regexp" /* RegularExpression */:
const { pattern, flags } = value;
return new RegExp(pattern, flags);
case "set" /* Set */:
const set = /* @__PURE__ */ new Set();
for (const item of value) {
set.add(_RemoteValue.fromLocalValue(item));
}
return set;
case "symbol" /* Symbol */:
return Symbol(value);
default:
throw new Error(`Unsupported type: ${type}`);
}
}
/**
* Utility method to deserialize multiple LocalValues at once
*
* @param serializedValues Array of serialized LocalValue objects
* @returns Array of deserialized JavaScript values
*/
static fromLocalValueArray(serializedValues) {
return serializedValues.map((value) => _RemoteValue.fromLocalValue(value));
}
/**
* Verifies if the given object matches the structure of a serialized LocalValue
*
* @param obj Object to verify
* @returns boolean indicating if the object has LocalValue structure
*/
static isLocalValueObject(obj) {
if (typeof obj !== "object" || obj === null) {
return false;
}
if (!obj.hasOwnProperty(TYPE_CONSTANT)) {
return false;
}
const type = obj[TYPE_CONSTANT];
const hasTypeProperty = Object.values({ ...PrimitiveType, ...NonPrimitiveType }).includes(type);
if (!hasTypeProperty) {
return false;
}
if (type !== "null" /* Null */ && type !== "undefined" /* Undefined */) {
return obj.hasOwnProperty(VALUE_CONSTANT);
}
return true;
}
};
// src/utils/result.ts
var result_exports = {};
__export(result_exports, {
err: () => err,
map: () => map,
ok: () => ok,
unwrap: () => unwrap,
unwrapErr: () => unwrapErr
});
var ok = (value) => ({
isOk: true,
isErr: false,
value
});
var err = (value) => ({
isOk: false,
isErr: true,
value
});
function map(result, fn) {
if (result.isOk) {
const val = fn(result.value);
if (val instanceof Promise) {
return val.then((newVal) => ok(newVal));
} else {
return ok(val);
}
}
if (result.isErr) {
const value = result.value;
return err(value);
}
throw "should never get here";
}
var unwrap = (result) => {
if (result.isOk) {
return result.value;
} else {
throw result.value;
}
};
var unwrapErr = (result) => {
if (result.isErr) {
return result.value;
} else {
throw result.value;
}
};
// src/utils/serialize.ts
function deserializeProperty(value) {
if (typeof value !== "string" || !value.startsWith(SERIALIZED_PREFIX)) {
return value;
}
return RemoteValue.fromLocalValue(JSON.parse(atob(value.slice(SERIALIZED_PREFIX.length))));
}
// src/utils/style.ts
function createStyleSheetIfNeededAndSupported(styles2) {
return void 0;
}
// src/utils/shadow-root.ts
var globalStyleSheet;
function createShadowRoot(cmpMeta) {
var _a;
const shadowRoot = this.attachShadow({
mode: "open",
delegatesFocus: !!(cmpMeta.$flags$ & 16 /* shadowDelegatesFocus */)
}) ;
if (globalStyleSheet === void 0) globalStyleSheet = (_a = createStyleSheetIfNeededAndSupported()) != null ? _a : null;
if (globalStyleSheet) {
{
shadowRoot.adoptedStyleSheets = [...shadowRoot.adoptedStyleSheets, globalStyleSheet];
}
}
}
// src/runtime/runtime-constants.ts
var CONTENT_REF_ID = "r";
var ORG_LOCATION_ID = "o";
var SLOT_NODE_ID = "s";
var TEXT_NODE_ID = "t";
var COMMENT_NODE_ID = "c";
var HYDRATE_ID = "s-id";
var HYDRATED_STYLE_ID = "sty-id";
var HYDRATE_CHILD_ID = "c-id";
var STENCIL_DOC_DATA = "_stencilDocData";
var DEFAULT_DOC_DATA = {
hostIds: 0,
rootLevelIds: 0,
staticComponents: /* @__PURE__ */ new Set()
};
var SLOT_FB_CSS = "slot-fb{display:contents}slot-fb[hidden]{display:none}";
var XLINK_NS = "http://www.w3.org/1999/xlink";
// src/runtime/slot-polyfill-utils.ts
var updateFallbackSlotVisibility = (elm) => {
const childNodes = internalCall(elm, "childNodes");
if (elm.tagName && elm.tagName.includes("-") && elm["s-cr"] && elm.tagName !== "SLOT-FB") {
getHostSlotNodes(childNodes, elm.tagName).forEach((slotNode) => {
if (slotNode.nodeType === 1 /* ElementNode */ && slotNode.tagName === "SLOT-FB") {
if (getSlotChildSiblings(slotNode, getSlotName(slotNode), false).length) {
slotNode.hidden = true;
} else {
slotNode.hidden = false;
}
}
});
}
let i2 = 0;
for (i2 = 0; i2 < childNodes.length; i2++) {
const childNode = childNodes[i2];
if (childNode.nodeType === 1 /* ElementNode */ && internalCall(childNode, "childNodes").length) {
updateFallbackSlotVisibility(childNode);
}
}
};
var getSlottedChildNodes = (childNodes) => {
const result = [];
for (let i2 = 0; i2 < childNodes.length; i2++) {
const slottedNode = childNodes[i2]["s-nr"] || void 0;
if (slottedNode && slottedNode.isConnected) {
result.push(slottedNode);
}
}
return result;
};
function getHostSlotNodes(childNodes, hostName, slotName) {
let i2 = 0;
let slottedNodes = [];
let childNode;
for (; i2 < childNodes.length; i2++) {
childNode = childNodes[i2];
if (childNode["s-sr"] && (!hostName || childNode["s-hn"] === hostName) && (slotName === void 0)) {
slottedNodes.push(childNode);
}
slottedNodes = [...slottedNodes, ...getHostSlotNodes(childNode.childNodes, hostName, slotName)];
}
return slottedNodes;
}
var getSlotChildSiblings = (slot, slotName, includeSlot = true) => {
const childNodes = [];
if (includeSlot && slot["s-sr"] || !slot["s-sr"]) childNodes.push(slot);
let node = slot;
while (node = node.nextSibling) {
if (getSlotName(node) === slotName && (includeSlot || !node["s-sr"])) childNodes.push(node);
}
return childNodes;
};
var isNodeLocatedInSlot = (nodeToRelocate, slotName) => {
if (nodeToRelocate.nodeType === 1 /* ElementNode */) {
if (nodeToRelocate.getAttribute("slot") === null && slotName === "") {
return true;
}
if (nodeToRelocate.getAttribute("slot") === slotName) {
return true;
}
return false;
}
if (nodeToRelocate["s-sn"] === slotName) {
return true;
}
return slotName === "";
};
var addSlotRelocateNode = (newChild, slotNode, prepend, position) => {
if (newChild["s-ol"] && newChild["s-ol"].isConnected) {
return;
}
const slottedNodeLocation = document.createTextNode("");
slottedNodeLocation["s-nr"] = newChild;
if (!slotNode["s-cr"] || !slotNode["s-cr"].parentNode) return;
const parent = slotNode["s-cr"].parentNode;
const appendMethod = internalCall(parent, "appendChild");
if (typeof position !== "undefined") {
slottedNodeLocation["s-oo"] = position;
const childNodes = internalCall(parent, "childNodes");
const slotRelocateNodes = [slottedNodeLocation];
childNodes.forEach((n) => {
if (n["s-nr"]) slotRelocateNodes.push(n);
});
slotRelocateNodes.sort((a, b) => {
if (!a["s-oo"] || a["s-oo"] < (b["s-oo"] || 0)) return -1;
else if (!b["s-oo"] || b["s-oo"] < a["s-oo"]) return 1;
return 0;
});
slotRelocateNodes.forEach((n) => appendMethod.call(parent, n));
} else {
appendMethod.call(parent, slottedNodeLocation);
}
newChild["s-ol"] = slottedNodeLocation;
newChild["s-sh"] = slotNode["s-hn"];
};
var getSlotName = (node) => typeof node["s-sn"] === "string" ? node["s-sn"] : node.nodeType === 1 && node.getAttribute("slot") || void 0;
function patchSlotNode(node) {
if (node.assignedElements || node.assignedNodes || !node["s-sr"]) return;
const assignedFactory = (elementsOnly) => (function(opts) {
const toReturn = [];
const slotName = this["s-sn"];
if (opts == null ? void 0 : opts.flatten) {
console.error(`
Flattening is not supported for Stencil non-shadow slots.
You can use \`.childNodes\` to nested slot fallback content.
If you have a particular use case, please open an issue on the Stencil repo.
`);
}
const parent = this["s-cr"].parentElement;
const slottedNodes = parent.__childNodes ? parent.childNodes : getSlottedChildNodes(parent.childNodes);
slottedNodes.forEach((n) => {
if (slotName === getSlotName(n)) {
toReturn.push(n);
}
});
if (elementsOnly) {
return toReturn.filter((n) => n.nodeType === 1 /* ElementNode */);
}
return toReturn;
}).bind(node);
node.assignedElements = assignedFactory(true);
node.assignedNodes = assignedFactory(false);
}
function internalCall(node, method) {
if ("__" + method in node) {
const toReturn = node["__" + method];
if (typeof toReturn !== "function") return toReturn;
return toReturn.bind(node);
} else {
if (typeof node[method] !== "function") return node[method];
return node[method].bind(node);
}
}
var createTime = (fnName, tagName = "") => {
{
return () => {
return;
};
}
};
var uniqueTime = (key, measureText) => {
{
return () => {
return;
};
}
};
var rootAppliedStyles = /* @__PURE__ */ new WeakMap();
var registerStyle = (scopeId2, cssText, allowCS) => {
let style = styles.get(scopeId2);
{
style = cssText;
}
styles.set(scopeId2, style);
};
var addStyle = (styleContainerNode, cmpMeta, mode) => {
var _a;
const scopeId2 = getScopeId(cmpMeta, mode);
const style = styles.get(scopeId2);
if (!win$2.document) {
return scopeId2;
}
styleContainerNode = styleContainerNode.nodeType === 11 /* DocumentFragment */ ? styleContainerNode : win$2.document;
if (style) {
if (typeof style === "string") {
styleContainerNode = styleContainerNode.head || styleContainerNode;
let appliedStyles = rootAppliedStyles.get(styleContainerNode);
let styleElm;
if (!appliedStyles) {
rootAppliedStyles.set(styleContainerNode, appliedStyles = /* @__PURE__ */ new Set());
}
if (!appliedStyles.has(scopeId2)) {
if (styleContainerNode.host && (styleElm = styleContainerNode.querySelector(`[${HYDRATED_STYLE_ID}="${scopeId2}"]`))) {
styleElm.innerHTML = style;
} else {
styleElm = win$2.document.createElement("style");
styleElm.innerHTML = style;
const nonce = (_a = plt.$nonce$) != null ? _a : queryNonceMetaTagContent(win$2.document);
if (nonce != null) {
styleElm.setAttribute("nonce", nonce);
}
if ((cmpMeta.$flags$ & 2 /* scopedCssEncapsulation */ || cmpMeta.$flags$ & 128 /* shadowNeedsScopedCss */)) {
styleElm.setAttribute(HYDRATED_STYLE_ID, scopeId2);
}
if (!(cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */)) {
if (styleContainerNode.nodeName === "HEAD") {
const preconnectLinks = styleContainerNode.querySelectorAll("link[rel=preconnect]");
const referenceNode2 = preconnectLinks.length > 0 ? preconnectLinks[preconnectLinks.length - 1].nextSibling : styleContainerNode.querySelector("style");
styleContainerNode.insertBefore(
styleElm,
(referenceNode2 == null ? void 0 : referenceNode2.parentNode) === styleContainerNode ? referenceNode2 : null
);
} else if ("host" in styleContainerNode) {
{
const existingStyleContainer = styleContainerNode.querySelector("style");
if (existingStyleContainer) {
existingStyleContainer.innerHTML = style + existingStyleContainer.innerHTML;
} else {
styleContainerNode.prepend(styleElm);
}
}
} else {
styleContainerNode.append(styleElm);
}
}
if (cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */) {
styleContainerNode.insertBefore(styleElm, null);
}
}
if (cmpMeta.$flags$ & 4 /* hasSlotRelocation */) {
styleElm.innerHTML += SLOT_FB_CSS;
}
if (appliedStyles) {
appliedStyles.add(scopeId2);
}
}
}
}
return scopeId2;
};
var attachStyles = (hostRef) => {
const cmpMeta = hostRef.$cmpMeta$;
const elm = hostRef.$hostElement$;
const flags = cmpMeta.$flags$;
const endAttachStyles = createTime("attachStyles", cmpMeta.$tagName$);
const scopeId2 = addStyle(
elm.shadowRoot ? elm.shadowRoot : elm.getRootNode(),
cmpMeta,
hostRef.$modeName$
);
if (flags & 10 /* needsScopedEncapsulation */) {
elm["s-sc"] = scopeId2;
elm.classList.add(scopeId2 + "-h");
}
endAttachStyles();
};
var getScopeId = (cmp, mode) => "sc-" + (mode && cmp.$flags$ & 32 /* hasMode */ ? cmp.$tagName$ + "-" + mode : cmp.$tagName$);
var h = (nodeName, vnodeData, ...children) => {
let child = null;
let key = null;
let slotName = null;
let simple = false;
let lastSimple = false;
const vNodeChildren = [];
const walk = (c) => {
for (let i2 = 0; i2 < c.length; i2++) {
child = c[i2];
if (Array.isArray(child)) {
walk(child);
} else if (child != null && typeof child !== "boolean") {
if (simple = typeof nodeName !== "function" && !isComplexType(child)) {
child = String(child);
}
if (simple && lastSimple) {
vNodeChildren[vNodeChildren.length - 1].$text$ += child;
} else {
vNodeChildren.push(simple ? newVNode(null, child) : child);
}
lastSimple = simple;
}
}
};
walk(children);
if (vnodeData) {
if (vnodeData.key) {
key = vnodeData.key;
}
if (vnodeData.name) {
slotName = vnodeData.name;
}
{
const classData = vnodeData.className || vnodeData.class;
if (classData) {
vnodeData.class = typeof classData !== "object" ? classData : Object.keys(classData).filter((k) => classData[k]).join(" ");
}
}
}
if (typeof nodeName === "function") {
return nodeName(
vnodeData === null ? {} : vnodeData,
vNodeChildren,
vdomFnUtils
);
}
const vnode = newVNode(nodeName, null);
vnode.$attrs$ = vnodeData;
if (vNodeChildren.length > 0) {
vnode.$children$ = vNodeChildren;
}
{
vnode.$key$ = key;
}
{
vnode.$name$ = slotName;
}
return vnode;
};
var newVNode = (tag, text) => {
const vnode = {
$flags$: 0,
$tag$: tag,
$text$: text,
$elm$: null,
$children$: null
};
{
vnode.$attrs$ = null;
}
{
vnode.$key$ = null;
}
{
vnode.$name$ = null;
}
return vnode;
};
var Host = {};
var isHost = (node) => node && node.$tag$ === Host;
var vdomFnUtils = {
forEach: (children, cb) => children.map(convertToPublic).forEach(cb),
map: (children, cb) => children.map(convertToPublic).map(cb).map(convertToPrivate)
};
var convertToPublic = (node) => ({
vattrs: node.$attrs$,
vchildren: node.$children$,
vkey: node.$key$,
vname: node.$name$,
vtag: node.$tag$,
vtext: node.$text$
});
var convertToPrivate = (node) => {
if (typeof node.vtag === "function") {
const vnodeData = { ...node.vattrs };
if (node.vkey) {
vnodeData.key = node.vkey;
}
if (node.vname) {
vnodeData.name = node.vname;
}
return h(node.vtag, vnodeData, ...node.vchildren || []);
}
const vnode = newVNode(node.vtag, node.vtext);
vnode.$attrs$ = node.vattrs;
vnode.$children$ = node.vchildren;
vnode.$key$ = node.vkey;
vnode.$name$ = node.vname;
return vnode;
};
// src/runtime/client-hydrate.ts
var initializeClientHydrate = (hostElm, tagName, hostId, hostRef) => {
var _a, _b;
const endHydrate = createTime("hydrateClient", tagName);
const shadowRoot = hostElm.shadowRoot;
const childRenderNodes = [];
const slotNodes = [];
const slottedNodes = [];
const shadowRootNodes = shadowRoot ? [] : null;
const vnode = newVNode(tagName, null);
vnode.$elm$ = hostElm;
let scopeId2;
{
const cmpMeta = hostRef.$cmpMeta$;
if (cmpMeta && cmpMeta.$flags$ & 10 /* needsScopedEncapsulation */ && hostElm["s-sc"]) {
scopeId2 = hostElm["s-sc"];
hostElm.classList.add(scopeId2 + "-h");
} else if (hostElm["s-sc"]) {
delete hostElm["s-sc"];
}
}
if (win$2.document && (!plt.$orgLocNodes$ || !plt.$orgLocNodes$.size)) {
initializeDocumentHydrate(win$2.document.body, plt.$orgLocNodes$ = /* @__PURE__ */ new Map());
}
hostElm[HYDRATE_ID] = hostId;
hostElm.removeAttribute(HYDRATE_ID);
hostRef.$vnode$ = clientHydrate(
vnode,
childRenderNodes,
slotNodes,
shadowRootNodes,
hostElm,
hostElm,
hostId,
slottedNodes
);
let crIndex = 0;
const crLength = childRenderNodes.length;
let childRenderNode;
for (crIndex; crIndex < crLength; crIndex++) {
childRenderNode = childRenderNodes[crIndex];
const orgLocationId = childRenderNode.$hostId$ + "." + childRenderNode.$nodeId$;
const orgLocationNode = plt.$orgLocNodes$.get(orgLocationId);
const node = childRenderNode.$elm$;
if (!shadowRoot) {
node["s-hn"] = tagName.toUpperCase();
if (childRenderNode.$tag$ === "slot") {
node["s-cr"] = hostElm["s-cr"];
}
} else if (((_a = childRenderNode.$tag$) == null ? void 0 : _a.toString().includes("-")) && childRenderNode.$tag$ !== "slot-fb" && !childRenderNode.$elm$.shadowRoot) {
const cmpMeta = getHostRef(childRenderNode.$elm$);
if (cmpMeta) {
const scopeId3 = getScopeId(
cmpMeta.$cmpMeta$,
childRenderNode.$elm$.getAttribute("s-mode")
);
const styleSheet = win$2.document.querySelector(`style[sty-id="${scopeId3}"]`);
if (styleSheet) {
hostElm.shadowRoot.append(styleSheet.cloneNode(true));
}
}
}
if (childRenderNode.$tag$ === "slot") {
childRenderNode.$name$ = childRenderNode.$elm$["s-sn"] || childRenderNode.$elm$["name"] || null;
if (childRenderNode.$children$) {
childRenderNode.$flags$ |= 2 /* isSlotFallback */;
if (!childRenderNode.$elm$.childNodes.length) {
childRenderNode.$children$.forEach((c) => {
childRenderNode.$elm$.appendChild(c.$elm$);
});
}
} else {
childRenderNode.$flags$ |= 1 /* isSlotReference */;
}
}
if (orgLocationNode && orgLocationNode.isConnected) {
if (orgLocationNode.parentElement.shadowRoot && orgLocationNode["s-en"] === "") {
orgLocationNode.parentNode.insertBefore(node, orgLocationNode.nextSibling);
}
orgLocationNode.parentNode.removeChild(orgLocationNode);
if (!shadowRoot) {
node["s-oo"] = parseInt(childRenderNode.$nodeId$);
}
}
if (orgLocationNode && !orgLocationNode["s-id"]) {
plt.$orgLocNodes$.delete(orgLocationId);
}
}
const hosts = [];
const snLen = slottedNodes.length;
let snIndex = 0;
let slotGroup;
let snGroupIdx;
let snGroupLen;
let slottedItem;
for (snIndex; snIndex < snLen; snIndex++) {
slotGroup = slottedNodes[snIndex];
if (!slotGroup || !slotGroup.length) continue;
snGroupLen = slotGroup.length;
snGroupIdx = 0;
for (snGroupIdx; snGroupIdx < snGroupLen; snGroupIdx++) {
slottedItem = slotGroup[snGroupIdx];
if (!hosts[slottedItem.hostId]) {
hosts[slottedItem.hostId] = plt.$orgLocNodes$.get(slottedItem.hostId);
}
if (!hosts[slottedItem.hostId]) continue;
const hostEle = hosts[slottedItem.hostId];
if (hostEle.shadowRoot && slottedItem.node.parentElement !== hostEle) {
hostEle.appendChild(slottedItem.node);
}
if (!hostEle.shadowRoot || !shadowRoot) {
if (!slottedItem.slot["s-cr"]) {
slottedItem.slot["s-cr"] = hostEle["s-cr"];
if (!slottedItem.slot["s-cr"] && hostEle.shadowRoot) {
slottedItem.slot["s-cr"] = hostEle;
} else {
slottedItem.slot["s-cr"] = (hostEle.__childNodes || hostEle.childNodes)[0];
}
}
addSlotRelocateNode(slottedItem.node, slottedItem.slot, false, slottedItem.node["s-oo"]);
if (((_b = slottedItem.node.parentElement) == null ? void 0 : _b.shadowRoot) && slottedItem.node["getAttribute"] && slottedItem.node.getAttribute("slot")) {
slottedItem.node.removeAttribute("slot");
}
}
}
}
if (scopeId2 && slotNodes.length) {
slotNodes.forEach((slot) => {
slot.$elm$.parentElement.classList.add(scopeId2 + "-s");
});
}
if (shadowRoot) {
let rnIdex = 0;
const rnLen = shadowRootNodes.length;
if (rnLen) {
for (rnIdex; rnIdex < rnLen; rnIdex++) {
const node = shadowRootNodes[rnIdex];
if (node) {
shadowRoot.appendChild(node);
}
}
Array.from(hostElm.childNodes).forEach((node) => {
if (typeof node["s-en"] !== "string" && typeof node["s-sn"] !== "string") {
if (node.nodeType === 1 /* ElementNode */ && node.slot && node.hidden) {
node.removeAttribute("hidden");
} else if (node.nodeType === 8 /* CommentNode */ && !node.nodeValue || node.nodeType === 3 /* TextNode */ && !node.wholeText.trim()) {
node.parentNode.removeChild(node);
}
}
});
}
}
hostRef.$hostElement$ = hostElm;
endHydrate();
};
var clientHydrate = (parentVNode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, node, hostId, slottedNodes = []) => {
let childNodeType;
let childIdSplt;
let childVNode;
let i2;
const scopeId2 = hostElm["s-sc"];
if (node.nodeType === 1 /* ElementNode */) {
childNodeType = node.getAttribute(HYDRATE_CHILD_ID);
if (childNodeType) {
childIdSplt = childNodeType.split(".");
if (childIdSplt[0] === hostId || childIdSplt[0] === "0") {
childVNode = createSimpleVNode({
$flags$: 0,
$hostId$: childIdSplt[0],
$nodeId$: childIdSplt[1],
$depth$: childIdSplt[2],
$index$: childIdSplt[3],
$tag$: node.tagName.toLowerCase(),
$elm$: node,
// If we don't add the initial classes to the VNode, the first `vdom-render.ts` patch
// won't try to reconcile them. Classes set on the node will be blown away.
$attrs$: { class: node.className || "" }
});
childRenderNodes.push(childVNode);
node.removeAttribute(HYDRATE_CHILD_ID);
if (!parentVNode.$children$) {
parentVNode.$children$ = [];
}
if (scopeId2 && childIdSplt[0] === hostId) {
node["s-si"] = scopeId2;
childVNode.$attrs$.class += " " + scopeId2;
}
const slotName = childVNode.$elm$.getAttribute("s-sn");
if (typeof slotName === "string") {
if (childVNode.$tag$ === "slot-fb") {
addSlot(
slotName,
childIdSplt[2],
childVNode,
node,
parentVNode,
childRenderNodes,
slotNodes,
shadowRootNodes,
slottedNodes
);
if (scopeId2) {
node.classList.add(scopeId2);
}
}
childVNode.$elm$["s-sn"] = slotName;
childVNode.$elm$.removeAttribute("s-sn");
}
if (childVNode.$index$ !== void 0) {
parentVNode.$children$[childVNode.$index$] = childVNode;
}
parentVNode = childVNode;
if (shadowRootNodes && childVNode.$depth$ === "0") {
shadowRootNodes[childVNode.$index$] = childVNode.$elm$;
}
}
}
if (node.shadowRoot) {
for (i2 = node.shadowRoot.childNodes.length - 1; i2 >= 0; i2--) {
clientHydrate(
parentVNode,
childRenderNodes,
slotNodes,
shadowRootNodes,
hostElm,
node.shadowRoot.childNodes[i2],
hostId,
slottedNodes
);
}
}
const nonShadowNodes = node.__childNodes || node.childNodes;
for (i2 = nonShadowNodes.length - 1; i2 >= 0; i2--) {
clientHydrate(
parentVNode,
childRenderNodes,
slotNodes,
shadowRootNodes,
hostElm,
nonShadowNodes[i2],
hostId,
slottedNodes
);
}
} else if (node.nodeType === 8 /* CommentNode */) {
childIdSplt = node.nodeValue.split(".");
if (childIdSplt[1] === hostId || childIdSplt[1] === "0") {
childNodeType = childIdSplt[0];
childVNode = createSimpleVNode({
$hostId$: childIdSplt[1],
$nodeId$: childIdSplt[2],
$depth$: childIdSplt[3],
$index$: childIdSplt[4] || "0",
$elm$: node,
$attrs$: null,
$children$: null,
$key$: null,
$name$: null,
$tag$: null,
$text$: null
});
if (childNodeType === TEXT_NODE_ID) {
childVNode.$elm$ = findCorrespondingNode(node, 3 /* TextNode */);
if (childVNode.$elm$ && childVNode.$elm$.nodeType === 3 /* TextNode */) {
childVNode.$text$ = childVNode.$elm$.textContent;
childRenderNodes.push(childVNode);
node.remove();
if (hostId === childVNode.$hostId$) {
if (!parentVNode.$children$) {
parentVNode.$children$ = [];
}
parentVNode.$children$[childVNode.$index$] = childVNode;
}
if (shadowRootNodes && childVNode.$depth$ === "0") {
shadowRootNodes[childVNode.$index$] = childVNode.$elm$;
}
}
} else if (childNodeType === COMMENT_NODE_ID) {
childVNode.$elm$ = findCorrespondingNode(node, 8 /* CommentNode */);
if (childVNode.$elm$ && childVNode.$elm$.nodeType === 8 /* CommentNode */) {
childRenderNodes.push(childVNode);
node.remove();
}
} else if (childVNode.$hostId$ === hostId) {
if (childNodeType === SLOT_NODE_ID) {
const slotName = node["s-sn"] = childIdSplt[5] || "";
addSlot(
slotName,
childIdSplt[2],
childVNode,
node,
parentVNode,
childRenderNodes,
slotNodes,
shadowRootNodes,
slottedNodes
);
} else if (childNodeType === CONTENT_REF_ID) {
if (shadowRootNodes) {
node.remove();
} else {
hostElm["s-cr"] = node;
node["s-cn"] = true;
}
}
}
}
} else if (parentVNode && parentVNode.$tag$ === "style") {
const vnode = newVNode(null, node.textContent);
vnode.$elm$ = node;
vnode.$index$ = "0";
parentVNode.$children$ = [vnode];
} else {
if (node.nodeType === 3 /* TextNode */ && !node.wholeText.trim() && !node["s-nr"]) {
node.remove();
}
}
return parentVNode;
};
var initializeDocumentHydrate = (node, orgLocNodes) => {
if (node.nodeType === 1 /* ElementNode */) {
const componentId = node[HYDRATE_ID] || node.getAttribute(HYDRATE_ID);
if (componentId) {
orgLocNodes.set(componentId, node);
}
let i2 = 0;
if (node.shadowRoot) {
for (; i2 < node.shadowRoot.childNodes.length; i2++) {
initializeDocumentHydrate(node.shadowRoot.childNodes[i2], orgLocNodes);
}
}
const nonShadowNodes = node.__childNodes || node.childNodes;
for (i2 = 0; i2 < nonShadowNodes.length; i2++) {
initializeDocumentHydrate(nonShadowNodes[i2], orgLocNodes);
}
} else if (node.nodeType === 8 /* CommentNode */) {
const childIdSplt = node.nodeValue.split(".");
if (childIdSplt[0] === ORG_LOCATION_ID) {
orgLocNodes.set(childIdSplt[1] + "." + childIdSplt[2], node);
node.nodeValue = "";
node["s-en"] = childIdSplt[3];
}
}
};
var createSimpleVNode = (vnode) => {
const defaultVNode = {
$flags$: 0,
$hostId$: null,
$nodeId$: null,
$depth$: null,
$index$: "0",
$elm$: null,
$attrs$: null,
$children$: null,
$key$: null,
$name$: null,
$tag$: null,
$text$: null
};
return { ...defaultVNode, ...vnode };
};
function addSlot(slotName, slotId, childVNode, node, parentVNode, childRenderNodes, slotNodes, shadowRootNodes, slottedNodes) {
node["s-sr"] = true;
childVNode.$name$ = slotName || null;
childVNode.$tag$ = "slot";
const parentNodeId = (parentVNode == null ? void 0 : parentVNode.$elm$) ? parentVNode.$elm$["s-id"] || parentVNode.$elm$.getAttribute("s-id") : "";
if (shadowRootNodes && win$2.document) {
const slot = childVNode.$elm$ = win$2.document.createElement(childVNode.$tag$);
if (childVNode.$name$) {
childVNode.$elm$.setAttribute("name", slotName);
}
if (parentVNode.$elm$.shadowRoot && parentNodeId && parentNodeId !== childVNode.$hostId$) {
internalCall(parentVNode.$elm$, "insertBefore")(slot, internalCall(parentVNode.$elm$, "children")[0]);
} else {
internalCall(internalCall(node, "parentNode"), "insertBefore")(slot, node);
}
addSlottedNodes(slottedNodes, slotId, slotName, node, childVNode.$hostId$);
node.remove();
if (childVNode.$depth$ === "0") {
shadowRootNodes[childVNode.$index$] = childVNode.$elm$;
}
} else {
const slot = childVNode.$elm$;
const shouldMove = parentNodeId && parentNodeId !== childVNode.$hostId$ && parentVNode.$elm$.shadowRoot;
addSlottedNodes(slottedNodes, slotId, slotName, node, shouldMove ? parentNodeId : childVNode.$hostId$);
patchSlotNode(node);
if (shouldMove) {
parentVNode.$elm$.insertBefore(slot, parentVNode.$elm$.children[0]);
}
}
childRenderNodes.push(childVNode);
slotNodes.push(childVNode);
if (!parentVNode.$children$) {
parentVNode.$children$ = [];
}
parentVNode.$children$[childVNode.$index$] = childVNode;
}
var addSlottedNodes = (slottedNodes, slotNodeId, slotName, slotNode, hostId) => {
var _a, _b;
let slottedNode = slotNode.nextSibling;
slottedNodes[slotNodeId] = slottedNodes[slotNodeId] || [];
if (!slottedNode || ((_a = slottedNode.nodeValue) == null ? void 0 : _a.startsWith(SLOT_NODE_ID + "."))) return;
do {
if (slottedNode && ((slottedNode["getAttribute"] && slottedNode.getAttribute("slot") || slottedNode["s-sn"]) === slotName || slotName === "" && !slottedNode["s-sn"] && (!slottedNode["getAttribute"] || !slottedNode.getAttribute("slot")) && (slottedNode.nodeType === 8 /* CommentNode */ || slottedNode.nodeType === 3 /* TextNode */))) {
slottedNode["s-sn"] = slotName;
slottedNodes[slotNodeId].push({ slot: slotNode, node: slottedNode, hostId });
}
slottedNode = slottedNode == null ? void 0 : slottedNode.nextSibling;
} while (slottedNode && !((_b = slottedNode.nodeValue) == null ? void 0 : _b.startsWith(SLOT_NODE_ID + ".")));
};
var findCorrespondingNode = (node, type) => {
let sibling = node;
do {
sibling = sibling.nextSibling;
} while (sibling && (sibling.nodeType !== type || !sibling.nodeValue));
return sibling;
};
// src/utils/shadow-css.ts
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*
* This file is a port of shadowCSS from `webcomponents.js` to TypeScript.
* https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
* https://github.com/angular/angular/blob/master/packages/compiler/src/shadow_css.ts
*/
var safeSelector = (selector) => {
const placeholders = [];
let index = 0;
selector = selector.replace(/(\[\s*part~=\s*("[^"]*"|'[^']*')\s*\])/g, (_, keep) => {
const replaceBy = `__part-${index}__`;
placeholders.push(keep);
index++;
return replaceBy;
});
selector = selector.replace(/(\[[^\]]*\])/g, (_, keep) => {
const replaceBy = `__ph-${index}__`;
placeholders.push(keep);
index++;
return replaceBy;
});
const content = selector.replace(/(:nth-[-\w]+)(\([^)]+\))/g, (_, pseudo, exp) => {
const replaceBy = `__ph-${index}__`;
placeholders.push(exp);
index++;
return pseudo + replaceBy;
});
const ss = {
content,
placeholders
};
return ss;
};
var restoreSafeSelector = (placeholders, content) => {
content = content.replace(/__part-(\d+)__/g, (_, index) => placeholders[+index]);
return content.replace(/__ph-(\d+)__/g, (_, index) => placeholders[+index]);
};
var _polyfillHost = "-shadowcsshost";
var _polyfillSlotted = "-shadowcssslotted";
var _polyfillHostContext = "-shadowcsscontext";
var _parenSuffix = ")(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)";
var _cssColonHostRe = new RegExp("(" + _polyfillHost + _parenSuffix, "gim");
var _cssColonHostContextRe = new RegExp("(" + _polyfillHostContext + _parenSuffix, "gim");
var _cssColonSlottedRe = new RegExp("(" + _polyfillSlotted + _parenSuffix, "gim");
var _polyfillHostNoCombinator = _polyfillHost + "-no-combinator";
var _polyfillHostNoCombinatorRe = /-shadowcsshost-no-combinator([^\s]*)/;
var _shadowDOMSelectorsRe = [/::shadow/g, /::content/g];
var _safePartRe = /__part-(\d+)__/g;
var _selectorReSuffix = "([>\\s~+[.,{:][\\s\\S]*)?$";
var _polyfillHostRe = /-shadowcsshost/gim;
var createSupportsRuleRe = (selector) => {
const safeSelector2 = escapeRegExpSpecialCharacters(selector);
return new RegExp(
// First capture group: match any context before the selector that's not inside @supports selector()
// Using negative lookahead to avoid matching inside @supports selector(...) condition
`(^|[^@]|@(?!supports\\s+selector\\s*\\([^{]*?${safeSelector2}))(${safeSelector2}\\b)`,
"g"
);
};
var _colonSlottedRe = createSupportsRuleRe("::slotted");
var _colonHostRe = createSupportsRuleRe(":host");
var _colonHostContextRe = createSupportsRuleRe(":host-context");
var _commentRe = /\/\*\s*[\s\S]*?\*\//g;
var stripComments = (input) => {
return input.replace(_commentRe, "");
};
var _commentWithHashRe = /\/\*\s*#\s*source(Mapping)?URL=[\s\S]+?\*\//g;
var extractCommentsWithHash = (input) => {
return input.match(_commentWithHashRe) || [];
};
var _ruleRe = /(\s*)([^;\{\}]+?)(\s*)((?:{%BLOCK%}?\s*;?)|(?:\s*;))/g;
var _curlyRe = /([{}])/g;
var _selectorPartsRe = /(^.*?[^\\])??((:+)(.*)|$)/;
var OPEN_CURLY = "{";
var CLOSE_CURLY = "}";
var BLOCK_PLACEHOLDER = "%BLOCK%";
var processRules = (input, ruleCallback) => {
const inputWithEscapedBlocks = escapeBlocks(input);
let nextBlockIndex = 0;
return inputWithEscapedBlocks.escapedString.replace(_ruleRe, (...m) => {
const selector = m[2];
let content = "";
let suffix = m[4];
let contentPrefix = "";
if (suffix && suffix.startsWith("{" + BLOCK_PLACEHOLDER)) {
content = inputWithEscapedBlocks.blocks[nextBlockIndex++];
suffix = suffix.substring(BLOCK_PLACEHOLDER.length + 1);
contentPrefix = "{";
}
const cssRule = {
selector,
content
};
const rule = ruleCallback(cssRule);
return `${m[1]}${rule.selector}${m[3]}${contentPrefix}${rule.content}${suffix}`;
});
};
var escapeBlocks = (input) => {
const inputParts = input.split(_curlyRe);
const resultParts = [];
const escapedBlocks = [];
let bracketCount = 0;
let currentBlockParts = [];
for (let partIndex = 0; partIndex < inputParts.length; partIndex++) {
const part = inputParts[partIndex];
if (part === CLOSE_CURLY) {
bracketCount--;
}
if (bracketCount > 0) {
currentBlockParts.push(part);
} else {
if (currentBlockParts.length > 0) {
escapedBlocks.push(currentBlockParts.join(""));
resultParts.push(BLOCK_PLACEHOLDER);
currentBlockParts = [];
}
resultParts.push(part);
}
if (part === OPEN_CURLY) {
bracketCount++;
}
}
if (currentBlockParts.length > 0) {
escapedBlocks.push(currentBlockParts.join(""));
resultParts.push(BLOCK_PLACEHOLDER);
}
const strEscapedBlocks = {
escapedString: resultParts.join(""),
blocks: escapedBlocks
};
return strEscapedBlocks;
};
var insertPolyfillHostInCssText = (cssText) => {
const supportsBlocks = [];
cssText = cssText.replace(/@supports\s+selector\s*\(\s*([^)]*)\s*\)/g, (_, selectorContent) => {
const placeholder = `__supports_${supportsBlocks.length}__`;
supportsBlocks.push(selectorContent);
return `@supports selector(${placeholder})`;
});
cssText = cssText.replace(_colonHostContextRe, `$1${_polyfillHostContext}`).replace(_colonHostRe, `$1${_polyfillHost}`).replace(_colonSlottedRe, `$1${_polyfillSlotted}`);
supportsBlocks.forEach((originalSelector, index) => {
cssText = cssText.replace(`__supports_${index}__`, originalSelector);
});
return cssText;
};
var convertColonRule = (cssText, regExp, partReplacer) => {
return cssText.replace(regExp, (...m) => {
if (m[2]) {
const parts = m[2].split(",");
const r = [];
for (let i2 = 0; i2 < parts.length; i2++) {
const p = parts[i2].trim();
if (!p) break;
r.push(partReplacer(_polyfillHostNoCombinator, p, m[3]));
}
return r.join(",");
} else {
return _polyfillHostNoCombinator + m[3];
}
});
};
var colonHostPartReplacer = (host, part, suffix) => {
return host + part.replace(_polyfillHost, "") + suffix;
};
var convertColonHost = (cssText) => {
return convertColonRule(cssText, _cssColonHostRe, colonHostPartReplacer);
};
var colonHostContextPartReplacer = (host, part, suffix) => {
if (part.indexOf(_polyfillHost) > -1) {
return colonHostPartReplacer(host, part, suffix);
} else {
return host + part + suffix + ", " + part + " " + host + suffix;
}
};
var convertColonSlotted = (cssText, slotScopeId) => {
const slotClass = "." + slotScopeId + " > ";
const selectors = [];
cssText = cssText.replace(_cssColonSlottedRe, (...m) => {
if (m[2]) {
const compound = m[2].trim();
const suffix = m[3];
const slottedSelector = slotClass + compound + suffix;
let prefixSelector = "";
for (let i2 = m[4] - 1; i2 >= 0; i2--) {
const char = m[5][i2];
if (char === "}" || char === ",") {
break;
}
prefixSelector = char + prefixSelector;
}
const orgSelector = (prefixSelector + slottedSelector).trim();
const addedSelector = `${prefixSelector.trimEnd()}${slottedSelector.trim()}`.trim();
if (orgSelector !== addedSelector) {
const updatedSelector = `${addedSelector}, ${orgSelector}`;
selectors.push({
orgSelector,
updatedSelector
});
}
return slottedSelector;
} else {
return _polyfillHostNoCombinator + m[3];
}
});
return {
selectors,
cssText
};
};
var convertColonHostContext = (cssText) => {
return convertColonRule(cssText, _cssColonHostContextRe, colonHostContextPartReplacer);
};
var convertShadowDOMSelectors = (cssText) => {
return _shadowDOMSelectorsRe.reduce((result, pattern) => result.replace(pattern, " "), cssText);
};
var makeScopeMatcher = (scopeSelector2) => {
const lre = /\[/g;
const rre = /\]/g;
scopeSelector2 = scopeSelector2.replace(lre, "\\[").replace(rre, "\\]");
return new RegExp("^(" + scopeSelector2 + ")" + _selectorReSuffix, "m");
};
var selectorNeedsScoping = (selector, scopeSelector2) => {
const re = makeScopeMatcher(scopeSelector2);
return !re.test(selector);
};
var injectScopingSelector = (selector, scopingSelector) => {
return selector.replace(_selectorPartsRe, (_, before = "", _colonGroup, colon = "", after = "") => {
return before + scopingSelector + colon + after;
});
};
var applySimpleSelectorScope = (selector, scopeSelector2, hostSelector) => {
_polyfillHostRe.lastIndex = 0;
if (_polyfillHostRe.test(selector)) {
const replaceBy = `.${hostSelector}`;
return selector.replace(_polyfillHostNoCombinatorRe, (_, selector2) => injectScopingSelector(selector2, replaceBy)).replace(_polyfillHostRe, replaceBy + " ");
}
return scopeSelector2 + " " + selector;
};
var applyStrictSelectorScope = (selector, scopeSelector2, hostSelector) => {
const isRe = /\[is=([^\]]*)\]/g;
scopeSelector2 = scopeSelector2.replace(isRe, (_, ...parts) => parts[0]);
const className = "." + scopeSelector2;
const _scopeSelectorPart = (p) => {
let scopedP = p.trim();
if (!scopedP) {
return "";
}
if (p.indexOf(_polyfillHostNoCombinator) > -1) {
scopedP = applySimpleSelectorScope(p, scopeSelector2, hostSelector);
} else {
const t = p.replace(_polyfillHostRe, "");
if (t.length > 0) {
scopedP = injectScopingSelector(t, className);
}
}
return scopedP;
};
const safeContent = safeSelector(selector);
selector = safeContent.content;
let scopedSelector = "";
let startIndex = 0;
let res;
const sep = /( |>|\+|~(?!=))(?=(?:[^()]*\([^()]*\))*[^()]*$)\s*/g;
const hasHost = selector.indexOf(_polyfillHostNoCombinator) > -1;
let shouldScope = !hasHost;
while ((res = sep.exec(selector)) !== null) {
const separator = res[1];
const part2 = selector.slice(startIndex, res.index).trim();
shouldScope = shouldScope || part2.indexOf(_polyfillHostNoCombinator) > -1;
const scopedPart = shouldScope ? _scopeSelectorPart(part2) : part2;
scopedSelector += `${scopedPart} ${separator} `;
startIndex = sep.lastIndex;
}
const part = selector.substring(startIndex);
shouldScope = !part.match(_safePartRe) && (shouldScope || part.indexOf(_polyfillHostNoCombinator) > -1);
scopedSelector += shouldScope ? _scopeSelectorPart(part) : part;
return restoreSafeSelector(safeContent.placeholders, scopedSelector);
};
var scopeSelector = (selector, scopeSelectorText, hostSelector, slotSelector) => {
return selector.split(",").map((shallowPart) => {
if (slotSelector && shallowPart.indexOf("." + slotSelector) > -1) {
return shallowPart.trim();
}
if (selectorNeedsScoping(shallowPart, scopeSelectorText)) {
return applyStrictSelectorScope(shallowPart, scopeSelectorText, hostSelector).trim();
} else {
return shallowPart.trim();
}
}).join(", ");
};
var scopeSelectors = (cssText, scopeSelectorText, hostSelector, slotSelector, commentOriginalSelector) => {
return processRules(cssText, (rule) => {
let selector = rule.selector;
let content = rule.content;
if (rule.selector[0] !== "@") {
selector = scopeSelector(rule.selector, scopeSelectorText, hostSelector, slotSelector);
} else if (rule.selector.startsWith("@media") || rule.selector.startsWith("@supports") || rule.selector.startsWith("@page") || rule.selector.startsWith("@document")) {
content = scopeSelectors(rule.content, scopeSelectorText, hostSelector, slotSelector);
}
const cssRule = {
selector: selector.replace(/\s{2,}/g, " ").trim(),
content
};
return cssRule;
});
};
var scopeCssText = (cssText, scopeId2, hostScopeId, slotScopeId, commentOriginalSelector) => {
cssText = insertPolyfillHostInCssText(cssText);
cssText = convertColonHost(cssText);
cssText = convertColonHostContext(cssText);
const slotted = convertColonSlotted(cssText, slotScopeId);
cssText = slotted.cssText;
cssText = convertShadowDOMSelectors(cssText);
if (scopeId2) {
cssText = scopeSelectors(cssText, scopeId2, hostScopeId, slotScopeId);
}
cssText = replaceShadowCssHost(cssText, hostScopeId);
cssText = cssText.replace(/>\s*\*\s+([^{, ]+)/gm, " $1 ");
return {
cssText: cssText.trim(),
// We need to replace the shadow CSS host string in each of these selectors since we created
// them prior to the replacement happening in the components CSS text.
slottedSelectors: slotted.selectors.map((ref) => ({
orgSelector: replaceShadowCssHost(ref.orgSelector, hostScopeId),
updatedSelector: replaceShadowCssHost(ref.updatedSelector, hostScopeId)
}))
};
};
var replaceShadowCssHost = (cssText, hostScopeId) => {
return cssText.replace(/-shadowcsshost-no-combinator/g, `.${hostScopeId}`);
};
var expandPartSelectors = (cssText) => {
const partSelectorRe = /([^\s,{][^,{]*?)::part\(\s*([^)]+?)\s*\)((?:[:.][^,{]*)*)/g;
return processRules(cssText, (rule) => {
if (rule.selector[0] === "@") {
return rule;
}
const selectors = rule.selector.split(",").map((sel) => {
const out = [sel.trim()];
let m;
while ((m = partSelectorRe.exec(sel)) !== null) {
const before = m[1].trimEnd();
const partNames = m[2].trim().split(/\s+/);
const after = m[3] || "";
const partAttr = partNames.flatMap((p) => {
if (!rule.selector.includes(`[part~="${p}"]`)) {
return [`[part~="${p}"]`];
}
return [];
}).join("");
const expanded = `${before} ${partAttr}${after}`;
if (!!partAttr && expanded !== sel.trim()) {
out.push(expanded);
}
}
return out.join(", ");
});
rule.selector = selectors.join(", ");
return rule;
});
};
var scopeCss = (cssText, scopeId2, commentOriginalSelector) => {
const hostScopeId = scopeId2 + "-h";
const slotScopeId = scopeId2 + "-s";
const commentsWithHash = extractCommentsWithHash(cssText);
cssText = stripComments(cssText);
const orgSelectors = [];
{
const processCommentedSelector = (rule) => {
const placeholder = `/*!@___${orgSelectors.length}___*/`;
const comment = `/*!@${rule.selector}*/`;
orgSelectors.push({ placeholder, comment });
rule.selector = placeholder + rule.selector;
return rule;
};
cssText = processRules(cssText, (rule) => {
if (rule.selector[0] !== "@") {
return processCommentedSelector(rule);
} else if (rule.selector.startsWith("@media") || rule.selector.startsWith("@supports") || rule.selector.startsWith("@page") || rule.selector.startsWith("@document")) {
rule.content = processRules(rule.content, processCommentedSelector);
return rule;
}
return rule;
});
}
const scoped = scopeCssText(cssText, scopeId2, hostScopeId, slotScopeId);
cssText = [scoped.cssText, ...commentsWithHash].join("\n");
{
orgSelectors.forEach(({ placeholder, comment }) => {
cssText = cssText.replace(placeholder, comment);
});
}
scoped.slottedSelectors.forEach((slottedSelector) => {
const regex = new RegExp(escapeRegExpSpecialCharacters(slottedSelector.orgSelector), "g");
cssText = cssText.replace(regex, slottedSelector.updatedSelector);
});
cssText = expandPartSelectors(cssText);
return cssText;
};
// src/runtime/mode.ts
var computeMode = (elm) => modeResolutionChain.map((h2) => h2(elm)).find((m) => !!m);
var setMode = (handler) => modeResolutionChain.push(handler);
var getMode = (ref) => {
var _a;
return (_a = getHostRef(ref)) == null ? void 0 : _a.$modeName$;
};
var parsePropertyValue = (propValue, propType, isFormAssociated) => {
if (typeof propValue === "string" && propValue.startsWith(SERIALIZED_PREFIX)) {
propValue = deserializeProperty(propValue);
return propValue;
}
if (propValue != null && !isComplexType(propValue)) {
if (propType & 4 /* Boolean */) {
{
return propValue === "false" ? false : propValue === "" || !!propValue;
}
}
if (propType & 2 /* Number */) {
return typeof propValue === "string" ? parseFloat(propValue) : typeof propValue === "number" ? propValue : NaN;
}
if (propType & 1 /* String */) {
return String(propValue);
}
return propValue;
}
return propValue;
};
var getElement = (ref) => {
var _a;
return (_a = getHostRef(ref)) == null ? void 0 : _a.$hostElement$ ;
};
// src/runtime/event-emitter.ts
var createEvent = (ref, name, flags) => {
const elm = getElement(ref);
return {
emit: (detail) => {
return emitEvent(elm, name, {
bubbles: !!(flags & 4 /* Bubbles */),
composed: !!(flags & 2 /* Composed */),
cancelable: !!(flags & 1 /* Cancellable */),
detail
});
}
};
};
var emitEvent = (elm, name, opts) => {
const ev = plt.ce(name, opts);
elm.dispatchEvent(ev);
return ev;
};
var setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags, initialRender) => {
if (oldValue === newValue) {
return;
}
let isProp = isMemberInElement(elm, memberName);
let ln = memberName.toLowerCase();
if (memberName === "class") {
const classList = elm.classList;
const oldClasses = parseClassList(oldValue);
let newClasses = parseClassList(newValue);
if ((elm["s-si"] || elm["s-sc"]) && initialRender) {
const scopeId2 = elm["s-sc"] || elm["s-si"];
newClasses.push(scopeId2);
oldClasses.forEach((c) => {
if (c.startsWith(scopeId2)) newClasses.push(c);
});
newClasses = [...new Set(newClasses)].filter((c) => c);
classList.add(...newClasses);
} else {
classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
}
} else if (memberName === "style") {
{
for (const prop in oldValue) {
if (!newValue || newValue[prop] == null) {
{
elm.style[prop] = "";
}
}
}
}
for (const prop in newValue) {
if (!oldValue || newValue[prop] !== oldValue[prop]) {
{
elm.style[prop] = newValue[prop];
}
}
}
} else if (memberName === "key") ; else if (memberName === "ref") {
if (newValue) {
newValue(elm);
}
} else if ((!isProp ) && memberName[0] === "o" && memberName[1] === "n") {
if (memberName[2] === "-") {
memberName = memberName.slice(3);
} else if (isMemberInElement(win$2, ln)) {
memberName = ln.slice(2);
} else {
memberName = ln[2] + memberName.slice(3);
}
if (oldValue || newValue) {
const capture = memberName.endsWith(CAPTURE_EVENT_SUFFIX);
memberName = memberName.replace(CAPTURE_EVENT_REGEX, "");
if (oldValue) {
plt.rel(elm, memberName, oldValue, capture);
}
if (newValue) {
plt.ael(elm, memberName, newValue, capture);
}
}
} else {
const isComplex = isComplexType(newValue);
if ((isProp || isComplex && newValue !== null) && !isSvg) {
try {
if (!elm.tagName.includes("-")) {
const n = newValue == null ? "" : newValue;
if (memberName === "list") {
isProp = false;
} else if (oldValue == null || elm[memberName] != n) {
if (typeof elm.__lookupSetter__(memberName) === "function") {
elm[memberName] = n;
} else {
elm.setAttribute(memberName, n);
}
}
} else if (elm[memberName] !== newValue) {
elm[memberName] = newValue;
}
} catch (e) {
}
}
let xlink = false;
{
if (ln !== (ln = ln.replace(/^xlink\:?/, ""))) {
memberName = ln;
xlink = true;
}
}
if (newValue == null || newValue === false) {
if (newValue !== false || elm.getAttribute(memberName) === "") {
if (xlink) {
elm.removeAttributeNS(XLINK_NS, memberName);
} else {
elm.removeAttribute(memberName);
}
}
} else if ((!isProp || flags & 4 /* isHost */ || isSvg) && !isComplex && elm.nodeType === 1 /* ElementNode */) {
newValue = newValue === true ? "" : newValue;
if (xlink) {
elm.setAttributeNS(XLINK_NS, memberName, newValue);
} else {
elm.setAttribute(memberName, newValue);
}
}
}
};
var parseClassListRegex = /\s/;
var parseClassList = (value) => {
if (typeof value === "object" && value && "baseVal" in value) {
value = value.baseVal;
}
if (!value || typeof value !== "string") {
return [];
}
return value.split(parseClassListRegex);
};
var CAPTURE_EVENT_SUFFIX = "Capture";
var CAPTURE_EVENT_REGEX = new RegExp(CAPTURE_EVENT_SUFFIX + "$");
// src/runtime/vdom/update-element.ts
var updateElement = (oldVnode, newVnode, isSvgMode2, isInitialRender) => {
const elm = newVnode.$elm$.nodeType === 11 /* DocumentFragment */ && newVnode.$elm$.host ? newVnode.$elm$.host : newVnode.$elm$;
const oldVnodeAttrs = oldVnode && oldVnode.$attrs$ || {};
const newVnodeAttrs = newVnode.$attrs$ || {};
{
for (const memberName of sortedAttrNames(Object.keys(oldVnodeAttrs))) {
if (!(memberName in newVnodeAttrs)) {
setAccessor(
elm,
memberName,
oldVnodeAttrs[memberName],
void 0,
isSvgMode2,
newVnode.$flags$,
isInitialRender
);
}
}
}
for (const memberName of sortedAttrNames(Object.keys(newVnodeAttrs))) {
setAccessor(
elm,
memberName,
oldVnodeAttrs[memberName],
newVnodeAttrs[memberName],
isSvgMode2,
newVnode.$flags$,
isInitialRender
);
}
};
function sortedAttrNames(attrNames) {
return attrNames.includes("ref") ? (
// we need to sort these to ensure that `'ref'` is the last attr
[...attrNames.filter((attr) => attr !== "ref"), "ref"]
) : (
// no need to sort, return the original array
attrNames
);
}
// src/runtime/vdom/vdom-render.ts
var scopeId;
var contentRef;
var hostTagName;
var useNativeShadowDom = false;
var checkSlotFallbackVisibility = false;
var checkSlotRelocate = false;
var isSvgMode = false;
var createElm = (oldParentVNode, newParentVNode, childIndex) => {
var _a;
const newVNode2 = newParentVNode.$children$[childIndex];
let i2 = 0;
let elm;
let childNode;
let oldVNode;
if (!useNativeShadowDom) {
checkSlotRelocate = true;
if (newVNode2.$tag$ === "slot") {
newVNode2.$flags$ |= newVNode2.$children$ ? (
// slot element has fallback content
// still create an element that "mocks" the slot element
2 /* isSlotFallback */
) : (
// slot element does not have fallback content
// create an html comment we'll use to always reference
// where actual slot content should sit next to
1 /* isSlotReference */
);
}
}
if (newVNode2.$text$ !== null) {
elm = newVNode2.$elm$ = win$2.document.createTextNode(newVNode2.$text$);
} else if (newVNode2.$flags$ & 1 /* isSlotReference */) {
elm = newVNode2.$elm$ = slotReferenceDebugNode(newVNode2) ;
{
updateElement(null, newVNode2, isSvgMode);
}
} else {
if (!isSvgMode) {
isSvgMode = newVNode2.$tag$ === "svg";
}
if (!win$2.document) {
throw new Error(
"You are trying to render a Stencil component in an environment that doesn't support the DOM. Make sure to populate the [`window`](https://developer.mozilla.org/en-US/docs/Web/API/Window/window) object before rendering a component."
);
}
elm = newVNode2.$elm$ = win$2.document.createElementNS(
isSvgMode ? SVG_NS : HTML_NS,
!useNativeShadowDom && BUILD.slotRelocation && newVNode2.$flags$ & 2 /* isSlotFallback */ ? "slot-fb" : newVNode2.$tag$
) ;
if (isSvgMode && newVNode2.$tag$ === "foreignObject") {
isSvgMode = false;
}
{
updateElement(null, newVNode2, isSvgMode);
}
if (isDef(scopeId) && elm["s-si"] !== scopeId) {
elm.classList.add(elm["s-si"] = scopeId);
}
if (newVNode2.$children$) {
for (i2 = 0; i2 < newVNode2.$children$.length; ++i2) {
childNode = createElm(oldParentVNode, newVNode2, i2);
if (childNode) {
elm.appendChild(childNode);
}
}
}
{
if (newVNode2.$tag$ === "svg") {
isSvgMode = false;
} else if (elm.tagName === "foreignObject") {
isSvgMode = true;
}
}
}
elm["s-hn"] = hostTagName;
{
if (newVNode2.$flags$ & (2 /* isSlotFallback */ | 1 /* isSlotReference */)) {
elm["s-sr"] = true;
elm["s-cr"] = contentRef;
elm["s-sn"] = newVNode2.$name$ || "";
elm["s-rf"] = (_a = newVNode2.$attrs$) == null ? void 0 : _a.ref;
patchSlotNode(elm);
oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex];
if (oldVNode && oldVNode.$tag$ === newVNode2.$tag$ && oldParentVNode.$elm$) {
{
putBackInOriginalLocation(oldParentVNode.$elm$, false);
}
}
{
addRemoveSlotScopedClass(contentRef, elm, newParentVNode.$elm$, oldParentVNode == null ? void 0 : oldParentVNode.$elm$);
}
}
}
return elm;
};
var putBackInOriginalLocation = (parentElm, recursive) => {
plt.$flags$ |= 1 /* isTmpDisconnected */;
const oldSlotChildNodes = Array.from(parentElm.__childNodes || parentElm.childNodes);
for (let i2 = oldSlotChildNodes.length - 1; i2 >= 0; i2--) {
const childNode = oldSlotChildNodes[i2];
if (childNode["s-hn"] !== hostTagName && childNode["s-ol"]) {
insertBefore(referenceNode(childNode).parentNode, childNode, referenceNode(childNode));
childNode["s-ol"].remove();
childNode["s-ol"] = void 0;
childNode["s-sh"] = void 0;
checkSlotRelocate = true;
}
if (recursive) {
putBackInOriginalLocation(childNode, recursive);
}
}
plt.$flags$ &= -2 /* isTmpDisconnected */;
};
var addVnodes = (parentElm, before, parentVNode, vnodes, startIdx, endIdx) => {
let containerElm = parentElm["s-cr"] && parentElm["s-cr"].parentNode || parentElm;
let childNode;
if (containerElm.shadowRoot && containerElm.tagName === hostTagName) {
containerElm = containerElm.shadowRoot;
}
for (; startIdx <= endIdx; ++startIdx) {
if (vnodes[startIdx]) {
childNode = createElm(null, parentVNode, startIdx);
if (childNode) {
vnodes[startIdx].$elm$ = childNode;
insertBefore(containerElm, childNode, referenceNode(before) );
}
}
}
};
var removeVnodes = (vnodes, startIdx, endIdx) => {
for (let index = startIdx; index <= endIdx; ++index) {
const vnode = vnodes[index];
if (vnode) {
const elm = vnode.$elm$;
nullifyVNodeRefs(vnode);
if (elm) {
{
checkSlotFallbackVisibility = true;
if (elm["s-ol"]) {
elm["s-ol"].remove();
} else {
putBackInOriginalLocation(elm, true);
}
}
elm.remove();
}
}
}
};
var updateChildren = (parentElm, oldCh, newVNode2, newCh, isInitialRender = false) => {
let oldStartIdx = 0;
let newStartIdx = 0;
let idxInOld = 0;
let i2 = 0;
let oldEndIdx = oldCh.length - 1;
let oldStartVnode = oldCh[0];
let oldEndVnode = oldCh[oldEndIdx];
let newEndIdx = newCh.length - 1;
let newStartVnode = newCh[0];
let newEndVnode = newCh[newEndIdx];
let node;
let elmToMove;
while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (oldStartVnode == null) {
oldStartVnode = oldCh[++oldStartIdx];
} else if (oldEndVnode == null) {
oldEndVnode = oldCh[--oldEndIdx];
} else if (newStartVnode == null) {
newStartVnode = newCh[++newStartIdx];
} else if (newEndVnode == null) {
newEndVnode = newCh[--newEndIdx];
} else if (isSameVnode(oldStartVnode, newStartVnode, isInitialRender)) {
patch(oldStartVnode, newStartVnode, isInitialRender);
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
} else if (isSameVnode(oldEndVnode, newEndVnode, isInitialRender)) {
patch(oldEndVnode, newEndVnode, isInitialRender);
oldEndVnode = oldCh[--oldEndIdx];
newEndVnode = newCh[--newEndIdx];
} else if (isSameVnode(oldStartVnode, newEndVnode, isInitialRender)) {
if ((oldStartVnode.$tag$ === "slot" || newEndVnode.$tag$ === "slot")) {
putBackInOriginalLocation(oldStartVnode.$elm$.parentNode, false);
}
patch(oldStartVnode, newEndVnode, isInitialRender);
insertBefore(parentElm, oldStartVnode.$elm$, oldEndVnode.$elm$.nextSibling);
oldStartVnode = oldCh[++oldStartIdx];
newEndVnode = newCh[--newEndIdx];
} else if (isSameVnode(oldEndVnode, newStartVnode, isInitialRender)) {
if ((oldStartVnode.$tag$ === "slot" || newEndVnode.$tag$ === "slot")) {
putBackInOriginalLocation(oldEndVnode.$elm$.parentNode, false);
}
patch(oldEndVnode, newStartVnode, isInitialRender);
insertBefore(parentElm, oldEndVnode.$elm$, oldStartVnode.$elm$);
oldEndVnode = oldCh[--oldEndIdx];
newStartVnode = newCh[++newStartIdx];
} else {
idxInOld = -1;
{
for (i2 = oldStartIdx; i2 <= oldEndIdx; ++i2) {
if (oldCh[i2] && oldCh[i2].$key$ !== null && oldCh[i2].$key$ === newStartVnode.$key$) {
idxInOld = i2;
break;
}
}
}
if (idxInOld >= 0) {
elmToMove = oldCh[idxInOld];
if (elmToMove.$tag$ !== newStartVnode.$tag$) {
node = createElm(oldCh && oldCh[newStartIdx], newVNode2, idxInOld);
} else {
patch(elmToMove, newStartVnode, isInitialRender);
oldCh[idxInOld] = void 0;
node = elmToMove.$elm$;
}
newStartVnode = newCh[++newStartIdx];
} else {
node = createElm(oldCh && oldCh[newStartIdx], newVNode2, newStartIdx);
newStartVnode = newCh[++newStartIdx];
}
if (node) {
{
insertBefore(
referenceNode(oldStartVnode.$elm$).parentNode,
node,
referenceNode(oldStartVnode.$elm$)
);
}
}
}
}
if (oldStartIdx > oldEndIdx) {
addVnodes(
parentElm,
newCh[newEndIdx + 1] == null ? null : newCh[newEndIdx + 1].$elm$,
newVNode2,
newCh,
newStartIdx,
newEndIdx
);
} else if (newStartIdx > newEndIdx) {
removeVnodes(oldCh, oldStartIdx, oldEndIdx);
}
};
var isSameVnode = (leftVNode, rightVNode, isInitialRender = false) => {
if (leftVNode.$tag$ === rightVNode.$tag$) {
if (leftVNode.$tag$ === "slot") {
return leftVNode.$name$ === rightVNode.$name$;
}
if (!isInitialRender) {
return leftVNode.$key$ === rightVNode.$key$;
}
if (isInitialRender && !leftVNode.$key$ && rightVNode.$key$) {
leftVNode.$key$ = rightVNode.$key$;
}
return true;
}
return false;
};
var referenceNode = (node) => node && node["s-ol"] || node;
var patch = (oldVNode, newVNode2, isInitialRender = false) => {
const elm = newVNode2.$elm$ = oldVNode.$elm$;
const oldChildren = oldVNode.$children$;
const newChildren = newVNode2.$children$;
const tag = newVNode2.$tag$;
const text = newVNode2.$text$;
let defaultHolder;
if (text === null) {
{
isSvgMode = tag === "svg" ? true : tag === "foreignObject" ? false : isSvgMode;
}
{
updateElement(oldVNode, newVNode2, isSvgMode, isInitialRender);
}
if (oldChildren !== null && newChildren !== null) {
updateChildren(elm, oldChildren, newVNode2, newChildren, isInitialRender);
} else if (newChildren !== null) {
if (oldVNode.$text$ !== null) {
elm.textContent = "";
}
addVnodes(elm, null, newVNode2, newChildren, 0, newChildren.length - 1);
} else if (
// don't do this on initial render as it can cause non-hydrated content to be removed
!isInitialRender && BUILD.updatable && oldChildren !== null
) {
removeVnodes(oldChildren, 0, oldChildren.length - 1);
} else if (isInitialRender && BUILD.updatable && oldChildren !== null && newChildren === null) {
newVNode2.$children$ = oldChildren;
}
if (isSvgMode && tag === "svg") {
isSvgMode = false;
}
} else if ((defaultHolder = elm["s-cr"])) {
defaultHolder.parentNode.textContent = text;
} else if (oldVNode.$text$ !== text) {
elm.data = text;
}
};
var relocateNodes = [];
var markSlotContentForRelocation = (elm) => {
let node;
let hostContentNodes;
let j;
const children = elm.__childNodes || elm.childNodes;
for (const childNode of children) {
if (childNode["s-sr"] && (node = childNode["s-cr"]) && node.parentNode) {
hostContentNodes = node.parentNode.__childNodes || node.parentNode.childNodes;
const slotName = childNode["s-sn"];
for (j = hostContentNodes.length - 1; j >= 0; j--) {
node = hostContentNodes[j];
if (!node["s-cn"] && !node["s-nr"] && node["s-hn"] !== childNode["s-hn"] && (true)) {
if (isNodeLocatedInSlot(node, slotName)) {
let relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
checkSlotFallbackVisibility = true;
node["s-sn"] = node["s-sn"] || slotName;
if (relocateNodeData) {
relocateNodeData.$nodeToRelocate$["s-sh"] = childNode["s-hn"];
relocateNodeData.$slotRefNode$ = childNode;
} else {
node["s-sh"] = childNode["s-hn"];
relocateNodes.push({
$slotRefNode$: childNode,
$nodeToRelocate$: node
});
}
if (node["s-sr"]) {
relocateNodes.map((relocateNode) => {
if (isNodeLocatedInSlot(relocateNode.$nodeToRelocate$, node["s-sn"])) {
relocateNodeData = relocateNodes.find((r) => r.$nodeToRelocate$ === node);
if (relocateNodeData && !relocateNode.$slotRefNode$) {
relocateNode.$slotRefNode$ = relocateNodeData.$slotRefNode$;
}
}
});
}
} else if (!relocateNodes.some((r) => r.$nodeToRelocate$ === node)) {
relocateNodes.push({
$nodeToRelocate$: node
});
}
}
}
}
if (childNode.nodeType === 1 /* ElementNode */) {
markSlotContentForRelocation(childNode);
}
}
};
var nullifyVNodeRefs = (vNode) => {
{
vNode.$attrs$ && vNode.$attrs$.ref && vNode.$attrs$.ref(null);
vNode.$children$ && vNode.$children$.map(nullifyVNodeRefs);
}
};
var insertBefore = (parent, newNode, reference) => {
if (typeof newNode["s-sn"] === "string" && !!newNode["s-sr"] && !!newNode["s-cr"]) {
addRemoveSlotScopedClass(newNode["s-cr"], newNode, parent, newNode.parentElement);
}
{
return parent == null ? void 0 : parent.insertBefore(newNode, reference);
}
};
function addRemoveSlotScopedClass(reference, slotNode, newParent, oldParent) {
var _a, _b;
let scopeId2;
if (reference && typeof slotNode["s-sn"] === "string" && !!slotNode["s-sr"] && reference.parentNode && reference.parentNode["s-sc"] && (scopeId2 = slotNode["s-si"] || reference.parentNode["s-sc"])) {
const scopeName = slotNode["s-sn"];
const hostName = slotNode["s-hn"];
(_a = newParent.classList) == null ? void 0 : _a.add(scopeId2 + "-s");
if (oldParent && ((_b = oldParent.classList) == null ? void 0 : _b.contains(scopeId2 + "-s"))) {
let child = (oldParent.__childNodes || oldParent.childNodes)[0];
let found = false;
while (child) {
if (child["s-sn"] !== scopeName && child["s-hn"] === hostName && !!child["s-sr"]) {
found = true;
break;
}
child = child.nextSibling;
}
if (!found) oldParent.classList.remove(scopeId2 + "-s");
}
}
}
var renderVdom = (hostRef, renderFnResults, isInitialLoad = false) => {
var _c, _d;
const hostElm = hostRef.$hostElement$;
const cmpMeta = hostRef.$cmpMeta$;
const oldVNode = hostRef.$vnode$ || newVNode(null, null);
const isHostElement = isHost(renderFnResults);
const rootVnode = isHostElement ? renderFnResults : h(null, null, renderFnResults);
hostTagName = hostElm.tagName;
if (cmpMeta.$attrsToReflect$) {
rootVnode.$attrs$ = rootVnode.$attrs$ || {};
cmpMeta.$attrsToReflect$.forEach(([propName, attribute]) => {
{
rootVnode.$attrs$[attribute] = hostElm[propName];
}
});
}
if (isInitialLoad && rootVnode.$attrs$) {
for (const key of Object.keys(rootVnode.$attrs$)) {
if (hostElm.hasAttribute(key) && !["key", "ref", "style", "class"].includes(key)) {
rootVnode.$attrs$[key] = hostElm[key];
}
}
}
rootVnode.$tag$ = null;
rootVnode.$flags$ |= 4 /* isHost */;
hostRef.$vnode$ = rootVnode;
rootVnode.$elm$ = oldVNode.$elm$ = hostElm.shadowRoot || hostElm ;
{
scopeId = hostElm["s-sc"];
}
useNativeShadowDom = !!(cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */) && !(cmpMeta.$flags$ & 128 /* shadowNeedsScopedCss */);
{
contentRef = hostElm["s-cr"];
checkSlotFallbackVisibility = false;
}
patch(oldVNode, rootVnode, isInitialLoad);
{
plt.$flags$ |= 1 /* isTmpDisconnected */;
if (checkSlotRelocate) {
markSlotContentForRelocation(rootVnode.$elm$);
for (const relocateData of relocateNodes) {
const nodeToRelocate = relocateData.$nodeToRelocate$;
if (!nodeToRelocate["s-ol"] && win$2.document) {
const orgLocationNode = originalLocationDebugNode(nodeToRelocate) ;
orgLocationNode["s-nr"] = nodeToRelocate;
insertBefore(nodeToRelocate.parentNode, nodeToRelocate["s-ol"] = orgLocationNode, nodeToRelocate);
}
}
for (const relocateData of relocateNodes) {
const nodeToRelocate = relocateData.$nodeToRelocate$;
const slotRefNode = relocateData.$slotRefNode$;
if (slotRefNode) {
const parentNodeRef = slotRefNode.parentNode;
let insertBeforeNode = slotRefNode.nextSibling;
const parent = nodeToRelocate.__parentNode || nodeToRelocate.parentNode;
const nextSibling = nodeToRelocate.__nextSibling || nodeToRelocate.nextSibling;
if (!insertBeforeNode && parentNodeRef !== parent || nextSibling !== insertBeforeNode) {
if (nodeToRelocate !== insertBeforeNode) {
if (!nodeToRelocate["s-hn"] && nodeToRelocate["s-ol"]) {
nodeToRelocate["s-hn"] = nodeToRelocate["s-ol"].parentNode.nodeName;
}
insertBefore(parentNodeRef, nodeToRelocate, insertBeforeNode);
if (nodeToRelocate.nodeType === 1 /* ElementNode */ && nodeToRelocate.tagName !== "SLOT-FB") {
nodeToRelocate.hidden = (_c = nodeToRelocate["s-ih"]) != null ? _c : false;
}
}
}
nodeToRelocate && typeof slotRefNode["s-rf"] === "function" && slotRefNode["s-rf"](slotRefNode);
} else {
if (nodeToRelocate.nodeType === 1 /* ElementNode */) {
if (isInitialLoad) {
nodeToRelocate["s-ih"] = (_d = nodeToRelocate.hidden) != null ? _d : false;
}
nodeToRelocate.hidden = true;
}
}
}
}
if (checkSlotFallbackVisibility) {
updateFallbackSlotVisibility(rootVnode.$elm$);
}
plt.$flags$ &= -2 /* isTmpDisconnected */;
relocateNodes.length = 0;
}
contentRef = void 0;
};
var slotReferenceDebugNode = (slotVNode) => {
var _a;
return (_a = win$2.document) == null ? void 0 : _a.createComment(
`<slot${slotVNode.$name$ ? ' name="' + slotVNode.$name$ + '"' : ""}> (host=${hostTagName.toLowerCase()})`
);
};
var originalLocationDebugNode = (nodeToRelocate) => {
var _a;
return (_a = win$2.document) == null ? void 0 : _a.createComment(
`org-location for ` + (nodeToRelocate.localName ? `<${nodeToRelocate.localName}> (host=${nodeToRelocate["s-hn"]})` : `[${nodeToRelocate.textContent}]`)
);
};
// src/runtime/update-component.ts
var attachToAncestor = (hostRef, ancestorComponent) => {
if (ancestorComponent && !hostRef.$onRenderResolve$ && ancestorComponent["s-p"]) {
const index = ancestorComponent["s-p"].push(
new Promise(
(r) => hostRef.$onRenderResolve$ = () => {
ancestorComponent["s-p"].splice(index - 1, 1);
r();
}
)
);
}
};
var scheduleUpdate = (hostRef, isInitialLoad) => {
{
hostRef.$flags$ |= 16 /* isQueuedForUpdate */;
}
if (hostRef.$flags$ & 4 /* isWaitingForChildren */) {
hostRef.$flags$ |= 512 /* needsRerender */;
return;
}
attachToAncestor(hostRef, hostRef.$ancestorComponent$);
const dispatch = () => dispatchHooks(hostRef, isInitialLoad);
if (isInitialLoad) {
queueMicrotask(() => {
dispatch();
});
return;
}
return writeTask(dispatch) ;
};
var dispatchHooks = (hostRef, isInitialLoad) => {
const elm = hostRef.$hostElement$;
const endSchedule = createTime("scheduleUpdate", hostRef.$cmpMeta$.$tagName$);
const instance = hostRef.$lazyInstance$ ;
if (!instance) {
throw new Error(
`Can't render component <${elm.tagName.toLowerCase()} /> with invalid Stencil runtime! Make sure this imported component is compiled with a \`externalRuntime: true\` flag. For more information, please refer to https://stenciljs.com/docs/custom-elements#externalruntime`
);
}
let maybePromise;
if (isInitialLoad) {
{
{
hostRef.$flags$ |= 256 /* isListenReady */;
if (hostRef.$queuedListeners$) {
hostRef.$queuedListeners$.map(([methodName, event]) => safeCall$1(instance, methodName, event, elm));
hostRef.$queuedListeners$ = void 0;
}
}
if (hostRef.$fetchedCbList$.length) {
hostRef.$fetchedCbList$.forEach((cb) => cb(elm));
}
}
maybePromise = safeCall$1(instance, "componentWillLoad", void 0, elm);
} else {
maybePromise = safeCall$1(instance, "componentWillUpdate", void 0, elm);
}
maybePromise = enqueue(maybePromise, () => safeCall$1(instance, "componentWillRender", void 0, elm));
endSchedule();
return enqueue(maybePromise, () => updateComponent(hostRef, instance, isInitialLoad));
};
var enqueue = (maybePromise, fn) => isPromisey(maybePromise) ? maybePromise.then(fn).catch((err2) => {
console.error(err2);
fn();
}) : fn();
var isPromisey = (maybePromise) => maybePromise instanceof Promise || maybePromise && maybePromise.then && typeof maybePromise.then === "function";
var updateComponent = async (hostRef, instance, isInitialLoad) => {
var _a;
const elm = hostRef.$hostElement$;
const endUpdate = createTime("update", hostRef.$cmpMeta$.$tagName$);
const rc = elm["s-rc"];
if (isInitialLoad) {
attachStyles(hostRef);
}
const endRender = createTime("render", hostRef.$cmpMeta$.$tagName$);
{
await callRender(hostRef, instance, elm, isInitialLoad);
}
{
try {
serverSideConnected(elm);
if (isInitialLoad) {
if (hostRef.$cmpMeta$.$flags$ & 1 /* shadowDomEncapsulation */) {
elm["s-en"] = "";
} else if (hostRef.$cmpMeta$.$flags$ & 2 /* scopedCssEncapsulation */) {
elm["s-en"] = "c";
}
}
} catch (e) {
consoleError(e, elm);
}
}
if (rc) {
rc.map((cb) => cb());
elm["s-rc"] = void 0;
}
endRender();
endUpdate();
{
const childrenPromises = (_a = elm["s-p"]) != null ? _a : [];
const postUpdate = () => postUpdateComponent(hostRef);
if (childrenPromises.length === 0) {
postUpdate();
} else {
Promise.all(childrenPromises).then(postUpdate);
hostRef.$flags$ |= 4 /* isWaitingForChildren */;
childrenPromises.length = 0;
}
}
};
var callRender = (hostRef, instance, elm, isInitialLoad) => {
try {
instance = instance.render && instance.render();
{
hostRef.$flags$ &= -17 /* isQueuedForUpdate */;
}
{
hostRef.$flags$ |= 2 /* hasRendered */;
}
{
{
{
return Promise.resolve(instance).then((value) => renderVdom(hostRef, value, isInitialLoad));
}
}
}
} catch (e) {
consoleError(e, hostRef.$hostElement$);
}
return null;
};
var postUpdateComponent = (hostRef) => {
const tagName = hostRef.$cmpMeta$.$tagName$;
const elm = hostRef.$hostElement$;
const endPostUpdate = createTime("postUpdate", tagName);
const instance = hostRef.$lazyInstance$ ;
const ancestorComponent = hostRef.$ancestorComponent$;
safeCall$1(instance, "componentDidRender", void 0, elm);
if (!(hostRef.$flags$ & 64 /* hasLoadedComponent */)) {
hostRef.$flags$ |= 64 /* hasLoadedComponent */;
{
addHydratedFlag(elm);
}
safeCall$1(instance, "componentDidLoad", void 0, elm);
endPostUpdate();
{
hostRef.$onReadyResolve$(elm);
if (!ancestorComponent) {
appDidLoad();
}
}
} else {
safeCall$1(instance, "componentDidUpdate", void 0, elm);
endPostUpdate();
}
{
hostRef.$onInstanceResolve$(elm);
}
{
if (hostRef.$onRenderResolve$) {
hostRef.$onRenderResolve$();
hostRef.$onRenderResolve$ = void 0;
}
if (hostRef.$flags$ & 512 /* needsRerender */) {
nextTick(() => scheduleUpdate(hostRef, false));
}
hostRef.$flags$ &= -517;
}
};
var forceUpdate = (ref) => {
return false;
};
var appDidLoad = (who) => {
var _a;
if (BUILD.asyncQueue) {
plt.$flags$ |= 2 /* appLoaded */;
}
nextTick(() => emitEvent(win$2, "appload", { detail: { namespace: NAMESPACE } }));
{
if ((_a = plt.$orgLocNodes$) == null ? void 0 : _a.size) {
plt.$orgLocNodes$.clear();
}
}
};
var safeCall$1 = (instance, method, arg, elm) => {
if (instance && instance[method]) {
try {
return instance[method](arg);
} catch (e) {
consoleError(e, elm);
}
}
return void 0;
};
var addHydratedFlag = (elm) => {
var _a;
return elm.classList.add((_a = BUILD.hydratedSelectorName) != null ? _a : "hydrated") ;
};
var serverSideConnected = (elm) => {
const children = elm.children;
if (children != null) {
for (let i2 = 0, ii = children.length; i2 < ii; i2++) {
const childElm = children[i2];
if (typeof childElm.connectedCallback === "function") {
childElm.connectedCallback();
}
serverSideConnected(childElm);
}
}
};
// src/runtime/set-value.ts
var getValue = (ref, propName) => getHostRef(ref).$instanceValues$.get(propName);
var setValue = (ref, propName, newVal, cmpMeta) => {
const hostRef = getHostRef(ref);
if (!hostRef) {
return;
}
if (!hostRef) {
throw new Error(
`Couldn't find host element for "${cmpMeta.$tagName$}" as it is unknown to this Stencil runtime. This usually happens when integrating a 3rd party Stencil component with another Stencil component or application. Please reach out to the maintainers of the 3rd party Stencil component or report this on the Stencil Discord server (https://chat.stenciljs.com) or comment on this similar [GitHub issue](https://github.com/stenciljs/core/issues/5457).`
);
}
const elm = hostRef.$hostElement$ ;
const oldVal = hostRef.$instanceValues$.get(propName);
const flags = hostRef.$flags$;
const instance = hostRef.$lazyInstance$ ;
newVal = parsePropertyValue(
newVal,
cmpMeta.$members$[propName][0]);
const areBothNaN = Number.isNaN(oldVal) && Number.isNaN(newVal);
const didValueChange = newVal !== oldVal && !areBothNaN;
if ((!(flags & 8 /* isConstructingInstance */) || oldVal === void 0) && didValueChange) {
hostRef.$instanceValues$.set(propName, newVal);
if (instance) {
if (cmpMeta.$watchers$ && flags & 128 /* isWatchReady */) {
const watchMethods = cmpMeta.$watchers$[propName];
if (watchMethods) {
watchMethods.map((watchMethodName) => {
try {
instance[watchMethodName](newVal, oldVal, propName);
} catch (e) {
consoleError(e, elm);
}
});
}
}
if ((flags & (2 /* hasRendered */ | 16 /* isQueuedForUpdate */)) === 2 /* hasRendered */) {
if (instance.componentShouldUpdate) {
if (instance.componentShouldUpdate(newVal, oldVal, propName) === false) {
return;
}
}
scheduleUpdate(hostRef, false);
}
}
}
};
// src/runtime/proxy-component.ts
var proxyComponent = (Cstr, cmpMeta, flags) => {
var _a;
const prototype = Cstr.prototype;
{
{
if (Cstr.watchers && !cmpMeta.$watchers$) {
cmpMeta.$watchers$ = Cstr.watchers;
}
if (Cstr.deserializers && !cmpMeta.$deserializers$) {
cmpMeta.$deserializers$ = Cstr.deserializers;
}
if (Cstr.serializers && !cmpMeta.$serializers$) {
cmpMeta.$serializers$ = Cstr.serializers;
}
}
const members = Object.entries((_a = cmpMeta.$members$) != null ? _a : {});
members.map(([memberName, [memberFlags]]) => {
if ((memberFlags & 31 /* Prop */ || memberFlags & 32 /* State */)) {
const { get: origGetter, set: origSetter } = Object.getOwnPropertyDescriptor(prototype, memberName) || {};
if (origGetter) cmpMeta.$members$[memberName][0] |= 2048 /* Getter */;
if (origSetter) cmpMeta.$members$[memberName][0] |= 4096 /* Setter */;
if (!origGetter) {
Object.defineProperty(prototype, memberName, {
get() {
{
if ((cmpMeta.$members$[memberName][0] & 2048 /* Getter */) === 0) {
return getValue(this, memberName);
}
const ref = getHostRef(this);
const instance = ref ? ref.$lazyInstance$ : prototype;
if (!instance) return;
return instance[memberName];
}
},
configurable: true,
enumerable: true
});
}
Object.defineProperty(prototype, memberName, {
set(newValue) {
const ref = getHostRef(this);
if (!ref) {
return;
}
if (origSetter) {
const currentValue = memberFlags & 32 /* State */ ? this[memberName] : ref.$hostElement$[memberName];
if (typeof currentValue === "undefined" && ref.$instanceValues$.get(memberName)) {
newValue = ref.$instanceValues$.get(memberName);
}
origSetter.apply(this, [
parsePropertyValue(
newValue,
memberFlags)
]);
newValue = memberFlags & 32 /* State */ ? this[memberName] : ref.$hostElement$[memberName];
setValue(this, memberName, newValue, cmpMeta);
return;
}
{
{
setValue(this, memberName, newValue, cmpMeta);
return;
}
}
}
});
}
});
}
return Cstr;
};
// src/runtime/initialize-component.ts
var initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId) => {
let Cstr;
if ((hostRef.$flags$ & 32 /* hasInitializedComponent */) === 0) {
hostRef.$flags$ |= 32 /* hasInitializedComponent */;
const bundleId = cmpMeta.$lazyBundleId$;
if (bundleId) {
const CstrImport = loadModule(cmpMeta);
if (CstrImport && "then" in CstrImport) {
const endLoad = uniqueTime();
Cstr = await CstrImport;
endLoad();
} else {
Cstr = CstrImport;
}
if (!Cstr) {
throw new Error(`Constructor for "${cmpMeta.$tagName$}#${hostRef.$modeName$}" was not found`);
}
if (!Cstr.isProxied) {
{
cmpMeta.$watchers$ = Cstr.watchers;
cmpMeta.$serializers$ = Cstr.serializers;
cmpMeta.$deserializers$ = Cstr.deserializers;
}
proxyComponent(Cstr, cmpMeta);
Cstr.isProxied = true;
}
const endNewInstance = createTime("createInstance", cmpMeta.$tagName$);
{
hostRef.$flags$ |= 8 /* isConstructingInstance */;
}
try {
new Cstr(hostRef);
} catch (e) {
consoleError(e, elm);
}
{
hostRef.$flags$ &= -9 /* isConstructingInstance */;
}
{
hostRef.$flags$ |= 128 /* isWatchReady */;
}
endNewInstance();
fireConnectedCallback(hostRef.$lazyInstance$, elm);
} else {
Cstr = elm.constructor;
const cmpTag = elm.localName;
customElements.whenDefined(cmpTag).then(() => hostRef.$flags$ |= 128 /* isWatchReady */);
}
if (Cstr && Cstr.style) {
let style;
if (typeof Cstr.style === "string") {
style = Cstr.style;
} else if (typeof Cstr.style !== "string") {
hostRef.$modeName$ = computeMode(elm);
if (hostRef.$modeName$) {
style = Cstr.style[hostRef.$modeName$];
}
if (hostRef.$modeName$) {
elm.setAttribute("s-mode", hostRef.$modeName$);
}
}
const scopeId2 = getScopeId(cmpMeta, hostRef.$modeName$);
if (!styles.has(scopeId2)) {
const endRegisterStyles = createTime("registerStyles", cmpMeta.$tagName$);
{
if (cmpMeta.$flags$ & 128 /* shadowNeedsScopedCss */) {
style = scopeCss(style, scopeId2);
} else if (needsScopedSSR()) {
style = expandPartSelectors(style);
}
}
registerStyle(scopeId2, style);
endRegisterStyles();
}
}
}
const ancestorComponent = hostRef.$ancestorComponent$;
const schedule = () => scheduleUpdate(hostRef, true);
if (ancestorComponent && ancestorComponent["s-rc"]) {
ancestorComponent["s-rc"].push(schedule);
} else {
schedule();
}
};
var fireConnectedCallback = (instance, elm) => {
{
safeCall$1(instance, "connectedCallback", void 0, elm);
}
};
// src/runtime/connected-callback.ts
var connectedCallback = (elm) => {
if ((plt.$flags$ & 1 /* isTmpDisconnected */) === 0) {
const hostRef = getHostRef(elm);
if (!hostRef) {
return;
}
const cmpMeta = hostRef.$cmpMeta$;
const endConnected = createTime("connectedCallback", cmpMeta.$tagName$);
if (!(hostRef.$flags$ & 1 /* hasConnected */)) {
hostRef.$flags$ |= 1 /* hasConnected */;
let hostId;
{
hostId = elm.getAttribute(HYDRATE_ID);
if (hostId) {
if (cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */) {
const scopeId2 = addStyle(elm.shadowRoot, cmpMeta, elm.getAttribute("s-mode")) ;
elm.classList.remove(scopeId2 + "-h", scopeId2 + "-s");
} else if (cmpMeta.$flags$ & 2 /* scopedCssEncapsulation */) {
const scopeId2 = getScopeId(cmpMeta, elm.getAttribute("s-mode") );
elm["s-sc"] = scopeId2;
}
initializeClientHydrate(elm, cmpMeta.$tagName$, hostId, hostRef);
}
}
if (!hostId) {
{
setContentReference(elm);
}
}
{
let ancestorComponent = elm;
while (ancestorComponent = ancestorComponent.parentNode || ancestorComponent.host) {
if (ancestorComponent.nodeType === 1 /* ElementNode */ && ancestorComponent.hasAttribute("s-id") && ancestorComponent["s-p"] || ancestorComponent["s-p"]) {
attachToAncestor(hostRef, hostRef.$ancestorComponent$ = ancestorComponent);
break;
}
}
}
if (BUILD.initializeNextTick) {
nextTick(() => initializeComponent(elm, hostRef, cmpMeta));
} else {
initializeComponent(elm, hostRef, cmpMeta);
}
} else {
addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
if (hostRef == null ? void 0 : hostRef.$lazyInstance$) {
fireConnectedCallback(hostRef.$lazyInstance$, elm);
} else if (hostRef == null ? void 0 : hostRef.$onReadyPromise$) {
hostRef.$onReadyPromise$.then(() => fireConnectedCallback(hostRef.$lazyInstance$, elm));
}
}
endConnected();
}
};
var setContentReference = (elm) => {
if (!win$2.document) {
return;
}
const contentRefElm = elm["s-cr"] = win$2.document.createComment(
""
);
contentRefElm["s-cn"] = true;
insertBefore(elm, contentRefElm, elm.firstChild);
};
// src/runtime/fragment.ts
var Fragment = (_, children) => children;
var addHostEventListeners = (elm, hostRef, listeners, attachParentListeners) => {
if (listeners && win$2.document) {
listeners.map(([flags, name, method]) => {
const target = getHostListenerTarget(win$2.document, elm, flags) ;
const handler = hostListenerProxy(hostRef, method);
const opts = hostListenerOpts(flags);
plt.ael(target, name, handler, opts);
(hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));
});
}
};
var hostListenerProxy = (hostRef, methodName) => (ev) => {
var _a;
try {
{
if (hostRef.$flags$ & 256 /* isListenReady */) {
(_a = hostRef.$lazyInstance$) == null ? void 0 : _a[methodName](ev);
} else {
(hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]);
}
}
} catch (e) {
consoleError(e, hostRef.$hostElement$);
}
};
var getHostListenerTarget = (doc, elm, flags) => {
if (flags & 4 /* TargetDocument */) {
return doc;
}
if (flags & 8 /* TargetWindow */) {
return win$2;
}
if (flags & 16 /* TargetBody */) {
return doc.body;
}
return elm;
};
var hostListenerOpts = (flags) => (flags & 2 /* Capture */) !== 0;
// src/runtime/vdom/vdom-annotations.ts
var insertVdomAnnotations = (doc, staticComponents) => {
if (doc != null) {
const docData = STENCIL_DOC_DATA in doc ? doc[STENCIL_DOC_DATA] : { ...DEFAULT_DOC_DATA };
docData.staticComponents = new Set(staticComponents);
const orgLocationNodes = [];
parseVNodeAnnotations(doc, doc.body, docData, orgLocationNodes);
orgLocationNodes.forEach((orgLocationNode) => {
var _a;
if (orgLocationNode != null && orgLocationNode["s-nr"]) {
const nodeRef = orgLocationNode["s-nr"];
let hostId = nodeRef["s-host-id"];
let nodeId = nodeRef["s-node-id"];
let childId = `${hostId}.${nodeId}`;
if (hostId == null) {
hostId = 0;
docData.rootLevelIds++;
nodeId = docData.rootLevelIds;
childId = `${hostId}.${nodeId}`;
if (nodeRef.nodeType === 1 /* ElementNode */) {
nodeRef.setAttribute(HYDRATE_CHILD_ID, childId);
if (typeof nodeRef["s-sn"] === "string" && !nodeRef.getAttribute("slot")) {
nodeRef.setAttribute("s-sn", nodeRef["s-sn"]);
}
} else if (nodeRef.nodeType === 3 /* TextNode */) {
if (hostId === 0) {
const textContent = (_a = nodeRef.nodeValue) == null ? void 0 : _a.trim();
if (textContent === "") {
orgLocationNode.remove();
return;
}
}
const commentBeforeTextNode = doc.createComment(childId);
commentBeforeTextNode.nodeValue = `${TEXT_NODE_ID}.${childId}`;
insertBefore(nodeRef.parentNode, commentBeforeTextNode, nodeRef);
} else if (nodeRef.nodeType === 8 /* CommentNode */) {
const commentBeforeTextNode = doc.createComment(childId);
commentBeforeTextNode.nodeValue = `${COMMENT_NODE_ID}.${childId}`;
nodeRef.parentNode.insertBefore(commentBeforeTextNode, nodeRef);
}
}
let orgLocationNodeId = `${ORG_LOCATION_ID}.${childId}`;
const orgLocationParentNode = orgLocationNode.parentElement;
if (orgLocationParentNode) {
if (orgLocationParentNode["s-en"] === "") {
orgLocationNodeId += `.`;
} else if (orgLocationParentNode["s-en"] === "c") {
orgLocationNodeId += `.c`;
}
}
orgLocationNode.nodeValue = orgLocationNodeId;
}
});
}
};
var parseVNodeAnnotations = (doc, node, docData, orgLocationNodes) => {
var _a;
if (node == null) {
return;
}
if (node["s-nr"] != null) {
orgLocationNodes.push(node);
}
if (node.nodeType === 1 /* ElementNode */) {
const childNodes = [...Array.from(node.childNodes), ...Array.from(((_a = node.shadowRoot) == null ? void 0 : _a.childNodes) || [])];
childNodes.forEach((childNode) => {
const hostRef = getHostRef(childNode);
if (hostRef != null && !docData.staticComponents.has(childNode.nodeName.toLowerCase())) {
const cmpData = {
nodeIds: 0
};
insertVNodeAnnotations(doc, childNode, hostRef.$vnode$, docData, cmpData);
}
parseVNodeAnnotations(doc, childNode, docData, orgLocationNodes);
});
}
};
var insertVNodeAnnotations = (doc, hostElm, vnode, docData, cmpData) => {
if (vnode != null) {
const hostId = ++docData.hostIds;
hostElm.setAttribute(HYDRATE_ID, hostId);
if (hostElm["s-cr"] != null) {
hostElm["s-cr"].nodeValue = `${CONTENT_REF_ID}.${hostId}`;
}
if (vnode.$children$ != null) {
const depth = 0;
vnode.$children$.forEach((vnodeChild, index) => {
insertChildVNodeAnnotations(doc, vnodeChild, cmpData, hostId, depth, index);
});
}
if (hostElm && vnode && vnode.$elm$ && !hostElm.hasAttribute(HYDRATE_CHILD_ID)) {
const parent = hostElm.parentElement;
if (parent && parent.childNodes) {
const parentChildNodes = Array.from(parent.childNodes);
const comment = parentChildNodes.find(
(node) => node.nodeType === 8 /* CommentNode */ && node["s-sr"]
);
if (comment) {
const index = parentChildNodes.indexOf(hostElm) - 1;
vnode.$elm$.setAttribute(
HYDRATE_CHILD_ID,
`${comment["s-host-id"]}.${comment["s-node-id"]}.0.${index}`
);
}
}
}
}
};
var insertChildVNodeAnnotations = (doc, vnodeChild, cmpData, hostId, depth, index) => {
const childElm = vnodeChild.$elm$;
if (childElm == null) {
return;
}
const nodeId = cmpData.nodeIds++;
const childId = `${hostId}.${nodeId}.${depth}.${index}`;
childElm["s-host-id"] = hostId;
childElm["s-node-id"] = nodeId;
if (childElm.nodeType === 1 /* ElementNode */) {
childElm.setAttribute(HYDRATE_CHILD_ID, childId);
if (typeof childElm["s-sn"] === "string" && !childElm.getAttribute("slot")) {
childElm.setAttribute("s-sn", childElm["s-sn"]);
}
} else if (childElm.nodeType === 3 /* TextNode */) {
const parentNode = childElm.parentNode;
const nodeName = parentNode == null ? void 0 : parentNode.nodeName;
if (nodeName !== "STYLE" && nodeName !== "SCRIPT") {
const textNodeId = `${TEXT_NODE_ID}.${childId}`;
const commentBeforeTextNode = doc.createComment(textNodeId);
insertBefore(parentNode, commentBeforeTextNode, childElm);
}
} else if (childElm.nodeType === 8 /* CommentNode */) {
if (childElm["s-sr"]) {
const slotName = childElm["s-sn"] || "";
const slotNodeId = `${SLOT_NODE_ID}.${childId}.${slotName}`;
childElm.nodeValue = slotNodeId;
}
}
if (vnodeChild.$children$ != null) {
const childDepth = depth + 1;
vnodeChild.$children$.forEach((vnode, index2) => {
insertChildVNodeAnnotations(doc, vnode, cmpData, hostId, childDepth, index2);
});
}
};
// src/hydrate/platform/h-async.ts
var hAsync = (nodeName, vnodeData, ...children) => {
if (Array.isArray(children) && children.length > 0) {
const flatChildren = children.flat(Infinity);
if (flatChildren.some((child) => child instanceof Promise)) {
return Promise.all(flatChildren).then((resolvedChildren) => {
return h(nodeName, vnodeData, ...resolvedChildren);
}).catch((err2) => {
return h(nodeName, vnodeData);
});
}
return h(nodeName, vnodeData, ...flatChildren);
}
return h(nodeName, vnodeData);
};
// src/hydrate/platform/proxy-host-element.ts
function proxyHostElement(elm, cstr) {
const cmpMeta = cstr.cmpMeta;
cmpMeta.$watchers$ = cmpMeta.$watchers$ || cstr.watchers;
cmpMeta.$deserializers$ = cmpMeta.$deserializers$ || cstr.deserializers;
cmpMeta.$serializers$ = cmpMeta.$serializers$ || cstr.serializers;
if (typeof elm.componentOnReady !== "function") {
elm.componentOnReady = componentOnReady$1;
}
if (typeof elm.forceUpdate !== "function") {
elm.forceUpdate = forceUpdate2;
}
if (!elm.shadowRoot && !!(cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */) && !(cmpMeta.$flags$ & 128 /* shadowNeedsScopedCss */)) {
createShadowRoot.call(elm, cmpMeta);
}
if (cmpMeta.$members$ != null) {
const hostRef = getHostRef(elm);
const members = Object.entries(cmpMeta.$members$);
members.forEach(([memberName, [memberFlags, metaAttributeName]]) => {
var _a, _b;
if (memberFlags & 31 /* Prop */) {
const attributeName = metaAttributeName || memberName;
const attrValue = elm.getAttribute(attributeName);
const propValue = elm[memberName];
let attrPropVal;
const { get: origGetter, set: origSetter } = Object.getOwnPropertyDescriptor(cstr.prototype, memberName) || {};
if (attrValue != null) {
if ((_a = cmpMeta.$deserializers$) == null ? void 0 : _a[memberName]) {
for (const methodName of cmpMeta.$deserializers$[memberName]) {
attrPropVal = cstr.prototype[methodName](attrValue, memberName);
}
} else {
attrPropVal = parsePropertyValue(attrValue, memberFlags);
}
}
if (propValue !== void 0) {
attrPropVal = propValue;
delete elm[memberName];
}
if (attrPropVal !== void 0) {
if (origSetter) {
origSetter.apply(elm, [attrPropVal]);
attrPropVal = origGetter ? origGetter.apply(elm) : attrPropVal;
}
(_b = hostRef == null ? void 0 : hostRef.$instanceValues$) == null ? void 0 : _b.set(memberName, attrPropVal);
}
const getterSetterDescriptor = {
get: function() {
return getValue(this, memberName);
},
set: function(newValue) {
setValue(this, memberName, newValue, cmpMeta);
},
configurable: true,
enumerable: true
};
Object.defineProperty(elm, memberName, getterSetterDescriptor);
Object.defineProperty(elm, metaAttributeName, getterSetterDescriptor);
hostRef.$fetchedCbList$.push(() => {
var _a2;
if (!((_a2 = hostRef == null ? void 0 : hostRef.$instanceValues$) == null ? void 0 : _a2.has(memberName))) {
setValue(
elm,
memberName,
attrPropVal !== void 0 ? attrPropVal : hostRef.$lazyInstance$[memberName],
cmpMeta
);
}
Object.defineProperty(hostRef.$lazyInstance$, memberName, getterSetterDescriptor);
});
} else if (memberFlags & 64 /* Method */) {
Object.defineProperty(elm, memberName, {
value(...args) {
var _a2;
const ref = getHostRef(this);
return (_a2 = ref == null ? void 0 : ref.$onInstancePromise$) == null ? void 0 : _a2.then(() => {
var _a3;
return (_a3 = ref == null ? void 0 : ref.$lazyInstance$) == null ? void 0 : _a3[memberName](...args);
}).catch((e) => {
consoleError(e, this);
});
}
});
}
});
}
}
function componentOnReady$1() {
var _a;
return (_a = getHostRef(this)) == null ? void 0 : _a.$onReadyPromise$;
}
function forceUpdate2() {
}
// src/hydrate/platform/hydrate-app.ts
function hydrateApp(win2, opts, results, afterHydrate, resolve) {
const connectedElements = /* @__PURE__ */ new Set();
const createdElements = /* @__PURE__ */ new Set();
const waitingElements = /* @__PURE__ */ new Set();
const orgDocumentCreateElement = win2.document.createElement;
const orgDocumentCreateElementNS = win2.document.createElementNS;
const resolved2 = Promise.resolve();
setScopedSSR(opts);
let tmrId;
let ranCompleted = false;
function hydratedComplete() {
globalThis.clearTimeout(tmrId);
createdElements.clear();
connectedElements.clear();
if (!ranCompleted) {
ranCompleted = true;
try {
if (opts.clientHydrateAnnotations) {
insertVdomAnnotations(win2.document, opts.staticComponents);
}
win2.dispatchEvent(new win2.Event("DOMContentLoaded"));
win2.document.createElement = orgDocumentCreateElement;
win2.document.createElementNS = orgDocumentCreateElementNS;
} catch (e) {
renderCatchError(opts, results, e);
}
}
afterHydrate(win2, opts, results, resolve);
}
function hydratedError(err2) {
renderCatchError(opts, results, err2);
hydratedComplete();
}
function timeoutExceeded() {
hydratedError(`Hydrate exceeded timeout${waitingOnElementsMsg(waitingElements)}`);
}
try {
let patchedConnectedCallback2 = function() {
return connectElement2(this);
}, patchElement2 = function(elm) {
if (isValidComponent(elm, opts)) {
const hostRef = getHostRef(elm);
if (!hostRef) {
const Cstr = loadModule(
{
$tagName$: elm.nodeName.toLowerCase()});
if (Cstr != null && Cstr.cmpMeta != null) {
if (opts.serializeShadowRoot !== false && !!(Cstr.cmpMeta.$flags$ & 1 /* shadowDomEncapsulation */) && tagRequiresScoped(elm.tagName, opts.serializeShadowRoot)) {
const cmpMeta = Cstr.cmpMeta;
cmpMeta.$flags$ |= 128 /* shadowNeedsScopedCss */;
Object.defineProperty(Cstr, "cmpMeta", {
get: function() {
return cmpMeta;
}
});
}
createdElements.add(elm);
elm.connectedCallback = patchedConnectedCallback2;
registerHost(elm, Cstr.cmpMeta);
proxyHostElement(elm, Cstr);
}
}
}
}, patchChild2 = function(elm) {
if (elm != null && elm.nodeType === 1) {
patchElement2(elm);
const children = elm.children;
for (let i2 = 0, ii = children.length; i2 < ii; i2++) {
patchChild2(children[i2]);
}
}
}, connectElement2 = function(elm) {
createdElements.delete(elm);
if (isValidComponent(elm, opts) && results.hydratedCount < opts.maxHydrateCount) {
if (!connectedElements.has(elm) && shouldHydrate(elm)) {
connectedElements.add(elm);
return hydrateComponent.call(elm, win2, results, elm.nodeName, elm, waitingElements);
}
}
return resolved2;
}, waitLoop2 = function() {
const toConnect = Array.from(createdElements).filter((elm) => elm.parentElement);
if (toConnect.length > 0) {
return Promise.all(toConnect.map(connectElement2)).then(waitLoop2);
}
return resolved2;
};
win2.document.createElement = function patchedCreateElement(tagName) {
const elm = orgDocumentCreateElement.call(win2.document, tagName);
patchElement2(elm);
return elm;
};
win2.document.createElementNS = function patchedCreateElement(namespaceURI, tagName) {
const elm = orgDocumentCreateElementNS.call(win2.document, namespaceURI, tagName);
patchElement2(elm);
return elm;
};
tmrId = globalThis.setTimeout(timeoutExceeded, opts.timeout);
plt.$resourcesUrl$ = new URL(opts.resourcesUrl || "./", win2.document.baseURI).href;
globalScripts();
patchChild2(win2.document.body);
waitLoop2().then(hydratedComplete).catch(hydratedError);
} catch (e) {
hydratedError(e);
}
}
async function hydrateComponent(win2, results, tagName, elm, waitingElements) {
tagName = tagName.toLowerCase();
const Cstr = loadModule(
{
$tagName$: tagName});
if (Cstr != null) {
const cmpMeta = Cstr.cmpMeta;
if (cmpMeta != null) {
waitingElements.add(elm);
const hostRef = getHostRef(this);
if (!hostRef) {
return;
}
addHostEventListeners(this, hostRef, cmpMeta.$listeners$);
try {
connectedCallback(elm);
await elm.componentOnReady();
results.hydratedCount++;
const ref = getHostRef(elm);
const modeName = !(ref == null ? void 0 : ref.$modeName$) ? "$" : ref == null ? void 0 : ref.$modeName$;
if (!results.components.some((c) => c.tag === tagName && c.mode === modeName)) {
results.components.push({
tag: tagName,
mode: modeName,
count: 0,
depth: -1
});
}
} catch (e) {
win2.console.error(e);
}
waitingElements.delete(elm);
}
}
}
function isValidComponent(elm, opts) {
if (elm != null && elm.nodeType === 1) {
const tagName = elm.nodeName;
if (typeof tagName === "string" && tagName.includes("-")) {
if (opts.excludeComponents.includes(tagName.toLowerCase())) {
return false;
}
return true;
}
}
return false;
}
function shouldHydrate(elm) {
if (elm.nodeType === 9) {
return true;
}
if (NO_HYDRATE_TAGS.has(elm.nodeName)) {
return false;
}
if (elm.hasAttribute("no-prerender")) {
return false;
}
const parentNode = elm.parentNode;
if (parentNode == null) {
return true;
}
return shouldHydrate(parentNode);
}
var NO_HYDRATE_TAGS = /* @__PURE__ */ new Set([
"CODE",
"HEAD",
"IFRAME",
"INPUT",
"OBJECT",
"OUTPUT",
"NOSCRIPT",
"PRE",
"SCRIPT",
"SELECT",
"STYLE",
"TEMPLATE",
"TEXTAREA"
]);
function renderCatchError(opts, results, err2) {
const diagnostic = {
level: "error",
type: "build",
header: "Hydrate Error",
messageText: "",
relFilePath: void 0,
absFilePath: void 0,
lines: []
};
if (opts.url) {
try {
const u = new URL(opts.url);
if (u.pathname !== "/") {
diagnostic.header += ": " + u.pathname;
}
} catch (e) {
}
}
if (err2 != null) {
if (err2.stack != null) {
diagnostic.messageText = err2.stack.toString();
} else if (err2.message != null) {
diagnostic.messageText = err2.message.toString();
} else {
diagnostic.messageText = err2.toString();
}
}
results.diagnostics.push(diagnostic);
}
function printTag(elm) {
let tag = `<${elm.nodeName.toLowerCase()}`;
if (Array.isArray(elm.attributes)) {
for (let i2 = 0; i2 < elm.attributes.length; i2++) {
const attr = elm.attributes[i2];
tag += ` ${attr.name}`;
if (attr.value !== "") {
tag += `="${attr.value}"`;
}
}
}
tag += `>`;
return tag;
}
function waitingOnElementMsg(waitingElement) {
let msg = "";
if (waitingElement) {
const lines = [];
msg = " - waiting on:";
let elm = waitingElement;
while (elm && elm.nodeType !== 9 && elm.nodeName !== "BODY") {
lines.unshift(printTag(elm));
elm = elm.parentElement;
}
let indent = "";
for (const ln of lines) {
indent += " ";
msg += `
${indent}${ln}`;
}
}
return msg;
}
function waitingOnElementsMsg(waitingElements) {
return Array.from(waitingElements).map(waitingOnElementMsg);
}
function tagRequiresScoped(tagName, opts) {
if (typeof opts === "string") {
return opts === "scoped";
}
if (typeof opts === "boolean") {
return opts === true ? false : true;
}
if (typeof opts === "object") {
tagName = tagName.toLowerCase();
if (Array.isArray(opts["declarative-shadow-dom"]) && opts["declarative-shadow-dom"].includes(tagName)) {
return false;
} else if ((!Array.isArray(opts.scoped) || !opts.scoped.includes(tagName)) && opts.default === "declarative-shadow-dom") {
return false;
} else {
return true;
}
}
return false;
}
var cmpModules = /* @__PURE__ */ new Map();
var getModule = (tagName) => {
if (typeof tagName === "string") {
tagName = tagName.toLowerCase();
const cmpModule = cmpModules.get(tagName);
if (cmpModule != null) {
return cmpModule[tagName];
}
}
return null;
};
var loadModule = (cmpMeta, _hostRef, _hmrVersionId) => {
return getModule(cmpMeta.$tagName$);
};
var isMemberInElement = (elm, memberName) => {
if (elm != null) {
if (memberName in elm) {
return true;
}
const cstr = getModule(elm.nodeName);
if (cstr != null) {
const hostRef = cstr;
if (hostRef != null && hostRef.cmpMeta != null && hostRef.cmpMeta.$members$ != null) {
return memberName in hostRef.cmpMeta.$members$;
}
}
}
return false;
};
var registerComponents = (Cstrs) => {
for (const Cstr of Cstrs) {
const exportName = Cstr.cmpMeta.$tagName$;
cmpModules.set(exportName, {
[exportName]: Cstr
});
}
};
var win$2 = window;
var readTask = (cb) => {
nextTick(() => {
try {
cb();
} catch (e) {
consoleError(e);
}
});
};
var writeTask = (cb) => {
nextTick(() => {
try {
cb();
} catch (e) {
consoleError(e);
}
});
};
var resolved = /* @__PURE__ */ Promise.resolve();
var nextTick = (cb) => resolved.then(cb);
var defaultConsoleError = (e) => {
if (e != null) {
console.error(e.stack || e.message || e);
}
};
var consoleError = (e, el) => (defaultConsoleError)(e, el);
var plt = {
$flags$: 0,
$resourcesUrl$: "",
jmp: (h2) => h2(),
raf: (h2) => requestAnimationFrame(h2),
ael: (el, eventName, listener, opts) => el.addEventListener(eventName, listener, opts),
rel: (el, eventName, listener, opts) => el.removeEventListener(eventName, listener, opts),
ce: (eventName, opts) => new win$2.CustomEvent(eventName, opts)
};
var getHostRef = (ref) => {
if (ref.__stencil__getHostRef) {
return ref.__stencil__getHostRef();
}
return void 0;
};
var registerInstance = (lazyInstance, hostRef) => {
if (!hostRef) return void 0;
lazyInstance.__stencil__getHostRef = () => hostRef;
hostRef.$lazyInstance$ = lazyInstance;
return hostRef;
};
var registerHost = (elm, cmpMeta) => {
const hostRef = {
$flags$: 0,
$cmpMeta$: cmpMeta,
$hostElement$: elm,
$instanceValues$: /* @__PURE__ */ new Map(),
$serializerValues$: /* @__PURE__ */ new Map(),
$renderCount$: 0
};
hostRef.$fetchedCbList$ = [];
hostRef.$onInstancePromise$ = new Promise((r) => hostRef.$onInstanceResolve$ = r);
hostRef.$onReadyPromise$ = new Promise((r) => hostRef.$onReadyResolve$ = r);
elm["s-p"] = [];
elm["s-rc"] = [];
elm.__stencil__getHostRef = () => hostRef;
return hostRef;
};
var Build = {
isBrowser: false};
var styles = /* @__PURE__ */ new Map();
var setScopedSSR = (opts) => {
scopedSSR = opts.serializeShadowRoot !== false && opts.serializeShadowRoot !== "declarative-shadow-dom";
};
var needsScopedSSR = () => scopedSSR;
var scopedSSR = false;
const transitionEndAsync = (el, expectedDuration = 0) => {
return new Promise((resolve) => {
transitionEnd(el, expectedDuration, resolve);
});
};
/**
* Allows developer to wait for a transition
* to finish and fallback to a timer if the
* transition is cancelled or otherwise
* never finishes. Also see transitionEndAsync
* which is an await-able version of this.
*/
const transitionEnd = (el, expectedDuration = 0, callback) => {
let unRegTrans;
let animationTimeout;
const opts = { passive: true };
const ANIMATION_FALLBACK_TIMEOUT = 500;
const unregister = () => {
if (unRegTrans) {
unRegTrans();
}
};
const onTransitionEnd = (ev) => {
if (ev === undefined || el === ev.target) {
unregister();
callback(ev);
}
};
if (el) {
el.addEventListener('webkitTransitionEnd', onTransitionEnd, opts);
el.addEventListener('transitionend', onTransitionEnd, opts);
animationTimeout = setTimeout(onTransitionEnd, expectedDuration + ANIMATION_FALLBACK_TIMEOUT);
unRegTrans = () => {
if (animationTimeout !== undefined) {
clearTimeout(animationTimeout);
animationTimeout = undefined;
}
el.removeEventListener('webkitTransitionEnd', onTransitionEnd, opts);
el.removeEventListener('transitionend', onTransitionEnd, opts);
};
}
return unregister;
};
/**
* Waits for a component to be ready for
* both custom element and non-custom element builds.
* If non-custom element build, el.componentOnReady
* will be used.
* For custom element builds, we wait a frame
* so that the inner contents of the component
* have a chance to render.
*
* Use this utility rather than calling
* el.componentOnReady yourself.
*/
const componentOnReady = (el, callback) => {
if (el.componentOnReady) {
// eslint-disable-next-line custom-rules/no-component-on-ready-method
el.componentOnReady().then((resolvedEl) => callback(resolvedEl));
}
else {
raf(() => callback(el));
}
};
/**
* This functions checks if a Stencil component is using
* the lazy loaded build of Stencil. Returns `true` if
* the component is lazy loaded. Returns `false` otherwise.
*/
const hasLazyBuild = (stencilEl) => {
return stencilEl.componentOnReady !== undefined;
};
/**
* Elements inside of web components sometimes need to inherit global attributes
* set on the host. For example, the inner input in `ion-input` should inherit
* the `title` attribute that developers set directly on `ion-input`. This
* helper function should be called in componentWillLoad and assigned to a variable
* that is later used in the render function.
*
* This does not need to be reactive as changing attributes on the host element
* does not trigger a re-render.
*/
const inheritAttributes$1 = (el, attributes = []) => {
const attributeObject = {};
attributes.forEach((attr) => {
if (el.hasAttribute(attr)) {
const value = el.getAttribute(attr);
if (value !== null) {
attributeObject[attr] = el.getAttribute(attr);
}
el.removeAttribute(attr);
}
});
return attributeObject;
};
/**
* List of available ARIA attributes + `role`.
* Removed deprecated attributes.
* https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes
*/
const ariaAttributes = [
'role',
'aria-activedescendant',
'aria-atomic',
'aria-autocomplete',
'aria-braillelabel',
'aria-brailleroledescription',
'aria-busy',
'aria-checked',
'aria-colcount',
'aria-colindex',
'aria-colindextext',
'aria-colspan',
'aria-controls',
'aria-current',
'aria-describedby',
'aria-description',
'aria-details',
'aria-disabled',
'aria-errormessage',
'aria-expanded',
'aria-flowto',
'aria-haspopup',
'aria-hidden',
'aria-invalid',
'aria-keyshortcuts',
'aria-label',
'aria-labelledby',
'aria-level',
'aria-live',
'aria-multiline',
'aria-multiselectable',
'aria-orientation',
'aria-owns',
'aria-placeholder',
'aria-posinset',
'aria-pressed',
'aria-readonly',
'aria-relevant',
'aria-required',
'aria-roledescription',
'aria-rowcount',
'aria-rowindex',
'aria-rowindextext',
'aria-rowspan',
'aria-selected',
'aria-setsize',
'aria-sort',
'aria-valuemax',
'aria-valuemin',
'aria-valuenow',
'aria-valuetext',
];
/**
* Returns an array of aria attributes that should be copied from
* the shadow host element to a target within the light DOM.
* @param el The element that the attributes should be copied from.
* @param ignoreList The list of aria-attributes to ignore reflecting and removing from the host.
* Use this in instances where we manually specify aria attributes on the `<Host>` element.
*/
const inheritAriaAttributes = (el, ignoreList) => {
let attributesToInherit = ariaAttributes;
return inheritAttributes$1(el, attributesToInherit);
};
const addEventListener$1 = (el, eventName, callback, opts) => {
return el.addEventListener(eventName, callback, opts);
};
const removeEventListener = (el, eventName, callback, opts) => {
return el.removeEventListener(eventName, callback, opts);
};
/**
* Gets the root context of a shadow dom element
* On newer browsers this will be the shadowRoot,
* but for older browser this may just be the
* element itself.
*
* Useful for whenever you need to explicitly
* do "myElement.shadowRoot!.querySelector(...)".
*/
const getElementRoot = (el, fallback = el) => {
return el.shadowRoot || fallback;
};
/**
* Patched version of requestAnimationFrame that avoids ngzone
* Use only when you know ngzone should not run
*/
const raf = (h) => {
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
return __zone_symbol__requestAnimationFrame(h);
}
if (typeof requestAnimationFrame === 'function') {
return requestAnimationFrame(h);
}
return setTimeout(h);
};
const hasShadowDom = (el) => {
return !!el.shadowRoot && !!el.attachShadow;
};
const focusVisibleElement = (el) => {
el.focus();
/**
* When programmatically focusing an element,
* the focus-visible utility will not run because
* it is expecting a keyboard event to have triggered this;
* however, there are times when we need to manually control
* this behavior so we call the `setFocus` method on ion-app
* which will let us explicitly set the elements to focus.
*/
if (el.classList.contains('ion-focusable')) {
const app = el.closest('ion-app');
if (app) {
app.setFocus([el]);
}
}
};
/**
* This method is used to add a hidden input to a host element that contains
* a Shadow DOM. It does not add the input inside of the Shadow root which
* allows it to be picked up inside of forms. It should contain the same
* values as the host element.
*
* @param always Add a hidden input even if the container does not use Shadow
* @param container The element where the input will be added
* @param name The name of the input
* @param value The value of the input
* @param disabled If true, the input is disabled
*/
const renderHiddenInput = (always, container, name, value, disabled) => {
{
let input = container.querySelector('input.aux-input');
if (!input) {
input = container.ownerDocument.createElement('input');
input.type = 'hidden';
input.classList.add('aux-input');
container.appendChild(input);
}
input.disabled = disabled;
input.name = name;
input.value = value || '';
}
};
const clamp = (min, n, max) => {
return Math.max(min, Math.min(n, max));
};
const assert = (actual, reason) => {
if (!actual) {
const message = 'ASSERT: ' + reason;
printIonError(message);
debugger; // eslint-disable-line
throw new Error(message);
}
};
/**
* @hidden
* Given a side, return if it should be on the end
* based on the value of dir
* @param side the side
* @param isRTL whether the application dir is rtl
*/
const isEndSide = (side) => {
const isRTL = document.dir === 'rtl';
switch (side) {
case 'start':
return isRTL;
case 'end':
return !isRTL;
default:
throw new Error(`"${side}" is not a valid value for [side]. Use "start" or "end" instead.`);
}
};
const debounceEvent = (event, wait) => {
const original = event._original || event;
return {
_original: event,
emit: debounce(original.emit.bind(original), wait),
};
};
const debounce = (func, wait = 0) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(func, wait, ...args);
};
};
/**
* Check whether the two string maps are shallow equal.
*
* undefined is treated as an empty map.
*
* @returns whether the keys are the same and the values are shallow equal.
*/
const shallowEqualStringMap = (map1, map2) => {
map1 !== null && map1 !== void 0 ? map1 : (map1 = {});
map2 !== null && map2 !== void 0 ? map2 : (map2 = {});
if (map1 === map2) {
return true;
}
const keys1 = Object.keys(map1);
if (keys1.length !== Object.keys(map2).length) {
return false;
}
for (const k1 of keys1) {
if (!(k1 in map2)) {
return false;
}
if (map1[k1] !== map2[k1]) {
return false;
}
}
return true;
};
/**
* Checks input for usable number. Not NaN and not Infinite.
*/
const isSafeNumber = (input) => {
return typeof input === 'number' && !isNaN(input) && isFinite(input);
};
/* Ionicons v8.0.13, ES Modules */
const arrowBackSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M244 400 100 256l144-144M120 256h292' stroke-linecap='square' stroke-miterlimit='10' stroke-width='48px' class='ionicon-fill-none'/></svg>";
const arrowDown = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='m112 268 144 144 144-144M256 392V100' stroke-linecap='round' stroke-linejoin='round' stroke-width='48px' class='ionicon-fill-none'/></svg>";
const caretBackSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M368 64 144 256l224 192z'/></svg>";
const caretDownSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='m64 144 192 224 192-224z'/></svg>";
const caretUpSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M448 368 256 144 64 368z'/></svg>";
const checkmarkOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M416 128 192 384l-96-96' stroke-linecap='round' stroke-linejoin='round' class='ionicon-fill-none ionicon-stroke-width'/></svg>";
const chevronBack = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M328 112 184 256l144 144' stroke-linecap='round' stroke-linejoin='round' stroke-width='48px' class='ionicon-fill-none'/></svg>";
const chevronDown = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='m112 184 144 144 144-144' stroke-linecap='round' stroke-linejoin='round' stroke-width='48px' class='ionicon-fill-none'/></svg>";
const chevronExpand = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path stroke-linecap='round' stroke-linejoin='round' stroke-width='48' d='m136 208 120-104 120 104M136 304l120 104 120-104' class='ionicon-fill-none'/></svg>";
const chevronForward = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='m184 112 144 144-144 144' stroke-linecap='round' stroke-linejoin='round' stroke-width='48px' class='ionicon-fill-none'/></svg>";
const chevronForwardOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='m184 112 144 144-144 144' stroke-linecap='round' stroke-linejoin='round' stroke-width='48px' class='ionicon-fill-none'/></svg>";
const close = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='m289.94 256 95-95A24 24 0 0 0 351 127l-95 95-95-95a24 24 0 0 0-34 34l95 95-95 95a24 24 0 1 0 34 34l95-95 95 95a24 24 0 0 0 34-34Z'/></svg>";
const closeCircle = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M256 48C141.31 48 48 141.31 48 256s93.31 208 208 208 208-93.31 208-208S370.69 48 256 48m75.31 260.69a16 16 0 1 1-22.62 22.62L256 278.63l-52.69 52.68a16 16 0 0 1-22.62-22.62L233.37 256l-52.68-52.69a16 16 0 0 1 22.62-22.62L256 233.37l52.69-52.68a16 16 0 0 1 22.62 22.62L278.63 256Z'/></svg>";
const closeSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256z'/></svg>";
const ellipseOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><circle cx='256' cy='256' r='192' stroke-linecap='round' stroke-linejoin='round' class='ionicon-fill-none ionicon-stroke-width'/></svg>";
const ellipsisHorizontal = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><circle cx='256' cy='256' r='48'/><circle cx='416' cy='256' r='48'/><circle cx='96' cy='256' r='48'/></svg>";
const eye = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><circle cx='256' cy='256' r='64'/><path d='M490.84 238.6c-26.46-40.92-60.79-75.68-99.27-100.53C349 110.55 302 96 255.66 96c-42.52 0-84.33 12.15-124.27 36.11-40.73 24.43-77.63 60.12-109.68 106.07a31.92 31.92 0 0 0-.64 35.54c26.41 41.33 60.4 76.14 98.28 100.65C162 402 207.9 416 255.66 416c46.71 0 93.81-14.43 136.2-41.72 38.46-24.77 72.72-59.66 99.08-100.92a32.2 32.2 0 0 0-.1-34.76M256 352a96 96 0 1 1 96-96 96.11 96.11 0 0 1-96 96'/></svg>";
const eyeOff = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M432 448a15.92 15.92 0 0 1-11.31-4.69l-352-352a16 16 0 0 1 22.62-22.62l352 352A16 16 0 0 1 432 448M248 315.85l-51.79-51.79a2 2 0 0 0-3.39 1.69 64.11 64.11 0 0 0 53.49 53.49 2 2 0 0 0 1.69-3.39M264 196.15 315.87 248a2 2 0 0 0 3.4-1.69 64.13 64.13 0 0 0-53.55-53.55 2 2 0 0 0-1.72 3.39'/><path d='M491 273.36a32.2 32.2 0 0 0-.1-34.76c-26.46-40.92-60.79-75.68-99.27-100.53C349 110.55 302 96 255.68 96a226.5 226.5 0 0 0-71.82 11.79 4 4 0 0 0-1.56 6.63l47.24 47.24a4 4 0 0 0 3.82 1.05 96 96 0 0 1 116 116 4 4 0 0 0 1.05 3.81l67.95 68a4 4 0 0 0 5.4.24 343.8 343.8 0 0 0 67.24-77.4M256 352a96 96 0 0 1-93.3-118.63 4 4 0 0 0-1.05-3.81l-66.84-66.87a4 4 0 0 0-5.41-.23c-24.39 20.81-47 46.13-67.67 75.72a31.92 31.92 0 0 0-.64 35.54c26.41 41.33 60.39 76.14 98.28 100.65C162.06 402 207.92 416 255.68 416a238.2 238.2 0 0 0 72.64-11.55 4 4 0 0 0 1.61-6.64l-47.47-47.46a4 4 0 0 0-3.81-1.05A96 96 0 0 1 256 352'/></svg>";
const menuOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M80 160h352M80 256h352M80 352h352' stroke-linecap='round' stroke-miterlimit='10' class='ionicon-fill-none ionicon-stroke-width'/></svg>";
const menuSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M64 384h384v-42.67H64Zm0-106.67h384v-42.66H64ZM64 128v42.67h384V128Z'/></svg>";
const removeOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M400 256H112' stroke-linecap='round' stroke-linejoin='round' class='ionicon-fill-none ionicon-stroke-width'/></svg>";
const reorderThreeOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M96 256h320M96 176h320M96 336h320' stroke-linecap='round' stroke-linejoin='round' class='ionicon-fill-none ionicon-stroke-width'/></svg>";
const reorderTwoSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M118 304h276M118 208h276' stroke-linecap='square' stroke-linejoin='round' stroke-width='44px' class='ionicon-fill-none'/></svg>";
const searchOutline = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M221.09 64a157.09 157.09 0 1 0 157.09 157.09A157.1 157.1 0 0 0 221.09 64Z' stroke-miterlimit='10' class='ionicon-fill-none ionicon-stroke-width'/><path d='M338.29 338.29 448 448' stroke-linecap='round' stroke-miterlimit='10' class='ionicon-fill-none ionicon-stroke-width'/></svg>";
const searchSharp = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' class='ionicon'><path d='M464 428 339.92 303.9a160.48 160.48 0 0 0 30.72-94.58C370.64 120.37 298.27 48 209.32 48S48 120.37 48 209.32s72.37 161.32 161.32 161.32a160.48 160.48 0 0 0 94.58-30.72L428 464ZM209.32 319.69a110.38 110.38 0 1 1 110.37-110.37 110.5 110.5 0 0 1-110.37 110.37'/></svg>";
const accordionIosCss = ":host{display:block;position:relative;width:100%;background-color:var(--ion-background-color, #ffffff);overflow:hidden;z-index:0}:host(.accordion-expanding) ::slotted(ion-item[slot=header]),:host(.accordion-expanded) ::slotted(ion-item[slot=header]){--border-width:0px}:host(.accordion-animated){-webkit-transition:all 300ms cubic-bezier(0.25, 0.8, 0.5, 1);transition:all 300ms cubic-bezier(0.25, 0.8, 0.5, 1)}:host(.accordion-animated) #content{-webkit-transition:max-height 300ms cubic-bezier(0.25, 0.8, 0.5, 1);transition:max-height 300ms cubic-bezier(0.25, 0.8, 0.5, 1)}#content{overflow:hidden;will-change:max-height}:host(.accordion-collapsing) #content{max-height:0 !important}:host(.accordion-collapsed) #content{display:none}:host(.accordion-expanding) #content{max-height:0}:host(.accordion-expanding) #content-wrapper{overflow:auto}:host(.accordion-disabled) #header,:host(.accordion-readonly) #header,:host(.accordion-disabled) #content,:host(.accordion-readonly) #content{pointer-events:none}:host(.accordion-disabled) #header,:host(.accordion-disabled) #content{opacity:0.4}@media (prefers-reduced-motion: reduce){:host,#content{-webkit-transition:none !important;transition:none !important}}:host(.accordion-next) ::slotted(ion-item[slot=header]){--border-width:0.55px 0px 0.55px 0px}";
const accordionMdCss = ":host{display:block;position:relative;width:100%;background-color:var(--ion-background-color, #ffffff);overflow:hidden;z-index:0}:host(.accordion-expanding) ::slotted(ion-item[slot=header]),:host(.accordion-expanded) ::slotted(ion-item[slot=header]){--border-width:0px}:host(.accordion-animated){-webkit-transition:all 300ms cubic-bezier(0.25, 0.8, 0.5, 1);transition:all 300ms cubic-bezier(0.25, 0.8, 0.5, 1)}:host(.accordion-animated) #content{-webkit-transition:max-height 300ms cubic-bezier(0.25, 0.8, 0.5, 1);transition:max-height 300ms cubic-bezier(0.25, 0.8, 0.5, 1)}#content{overflow:hidden;will-change:max-height}:host(.accordion-collapsing) #content{max-height:0 !important}:host(.accordion-collapsed) #content{display:none}:host(.accordion-expanding) #content{max-height:0}:host(.accordion-expanding) #content-wrapper{overflow:auto}:host(.accordion-disabled) #header,:host(.accordion-readonly) #header,:host(.accordion-disabled) #content,:host(.accordion-readonly) #content{pointer-events:none}:host(.accordion-disabled) #header,:host(.accordion-disabled) #content{opacity:0.4}@media (prefers-reduced-motion: reduce){:host,#content{-webkit-transition:none !important;transition:none !important}}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot header - Content is placed at the top and is used to
* expand or collapse the accordion item.
* @slot content - Content is placed below the header and is
* shown or hidden based on expanded state.
*
* @part header - The wrapper element for the header slot.
* @part content - The wrapper element for the content slot.
* @part expanded - The expanded element. Can be used in combination
* with the `header` and `content` parts (i.e. `::part(header expanded)`).
*/
class Accordion {
constructor(hostRef) {
registerInstance(this, hostRef);
this.updateListener = () => this.updateState(false);
this.state = 1 /* AccordionState.Collapsed */;
this.isNext = false;
this.isPrevious = false;
/**
* The value of the accordion. Defaults to an autogenerated
* value.
*/
this.value = `ion-accordion-${accordionIds++}`;
/**
* If `true`, the accordion cannot be interacted with.
*/
this.disabled = false;
/**
* If `true`, the accordion cannot be interacted with,
* but does not alter the opacity.
*/
this.readonly = false;
/**
* The toggle icon to use. This icon will be
* rotated when the accordion is expanded
* or collapsed.
*/
this.toggleIcon = chevronDown;
/**
* The slot inside of `ion-item` to
* place the toggle icon. Defaults to `"end"`.
*/
this.toggleIconSlot = 'end';
this.setItemDefaults = () => {
const ionItem = this.getSlottedHeaderIonItem();
if (!ionItem) {
return;
}
/**
* For a11y purposes, we make
* the ion-item a button so users
* can tab to it and use keyboard
* navigation to get around.
*/
ionItem.button = true;
ionItem.detail = false;
/**
* By default, the lines in an
* item should be full here, but
* only do that if a user has
* not explicitly overridden them
*/
if (ionItem.lines === undefined) {
ionItem.lines = 'full';
}
};
this.getSlottedHeaderIonItem = () => {
const { headerEl } = this;
if (!headerEl) {
return;
}
/**
* Get the first ion-item
* slotted in the header slot
*/
const slot = headerEl.querySelector('slot');
if (!slot) {
return;
}
// This is not defined in unit tests
if (slot.assignedElements === undefined)
return;
return slot.assignedElements().find((el) => el.tagName === 'ION-ITEM');
};
this.setAria = (expanded = false) => {
const ionItem = this.getSlottedHeaderIonItem();
if (!ionItem) {
return;
}
/**
* Get the native <button> element inside of
* ion-item because that is what will be focused
*/
const root = getElementRoot(ionItem);
const button = root.querySelector('button');
if (!button) {
return;
}
button.setAttribute('aria-expanded', `${expanded}`);
};
this.slotToggleIcon = () => {
const ionItem = this.getSlottedHeaderIonItem();
if (!ionItem) {
return;
}
const { toggleIconSlot, toggleIcon } = this;
/**
* Check if there already is a toggle icon.
* If so, do not add another one.
*/
const existingToggleIcon = ionItem.querySelector('.ion-accordion-toggle-icon');
if (existingToggleIcon) {
return;
}
const iconEl = document.createElement('ion-icon');
iconEl.slot = toggleIconSlot;
iconEl.lazy = false;
iconEl.classList.add('ion-accordion-toggle-icon');
iconEl.icon = toggleIcon;
iconEl.setAttribute('aria-hidden', 'true');
ionItem.appendChild(iconEl);
};
this.expandAccordion = (initialUpdate = false) => {
const { contentEl, contentElWrapper } = this;
if (initialUpdate || contentEl === undefined || contentElWrapper === undefined) {
this.state = 4 /* AccordionState.Expanded */;
return;
}
if (this.state === 4 /* AccordionState.Expanded */) {
return;
}
if (this.currentRaf !== undefined) {
cancelAnimationFrame(this.currentRaf);
}
if (this.shouldAnimate()) {
raf(() => {
this.state = 8 /* AccordionState.Expanding */;
this.currentRaf = raf(async () => {
const contentHeight = contentElWrapper.offsetHeight;
const waitForTransition = transitionEndAsync(contentEl, 2000);
contentEl.style.setProperty('max-height', `${contentHeight}px`);
await waitForTransition;
this.state = 4 /* AccordionState.Expanded */;
contentEl.style.removeProperty('max-height');
});
});
}
else {
this.state = 4 /* AccordionState.Expanded */;
}
};
this.collapseAccordion = (initialUpdate = false) => {
const { contentEl } = this;
if (initialUpdate || contentEl === undefined) {
this.state = 1 /* AccordionState.Collapsed */;
return;
}
if (this.state === 1 /* AccordionState.Collapsed */) {
return;
}
if (this.currentRaf !== undefined) {
cancelAnimationFrame(this.currentRaf);
}
if (this.shouldAnimate()) {
this.currentRaf = raf(async () => {
const contentHeight = contentEl.offsetHeight;
contentEl.style.setProperty('max-height', `${contentHeight}px`);
raf(async () => {
const waitForTransition = transitionEndAsync(contentEl, 2000);
this.state = 2 /* AccordionState.Collapsing */;
await waitForTransition;
this.state = 1 /* AccordionState.Collapsed */;
contentEl.style.removeProperty('max-height');
});
});
}
else {
this.state = 1 /* AccordionState.Collapsed */;
}
};
/**
* Helper function to determine if
* something should animate.
* If prefers-reduced-motion is set
* then we should not animate, regardless
* of what is set in the config.
*/
this.shouldAnimate = () => {
if (typeof window === 'undefined') {
return false;
}
const prefersReducedMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
if (prefersReducedMotion) {
return false;
}
const animated = config.get('animated', true);
if (!animated) {
return false;
}
if (this.accordionGroupEl && !this.accordionGroupEl.animated) {
return false;
}
return true;
};
this.updateState = async (initialUpdate = false) => {
const accordionGroup = this.accordionGroupEl;
const accordionValue = this.value;
if (!accordionGroup) {
return;
}
const value = accordionGroup.value;
const shouldExpand = Array.isArray(value) ? value.includes(accordionValue) : value === accordionValue;
if (shouldExpand) {
this.expandAccordion(initialUpdate);
this.isNext = this.isPrevious = false;
}
else {
this.collapseAccordion(initialUpdate);
/**
* When using popout or inset,
* the collapsed accordion items
* may need additional border radius
* applied. Check to see if the
* next or previous accordion is selected.
*/
const nextAccordion = this.getNextSibling();
const nextAccordionValue = nextAccordion === null || nextAccordion === void 0 ? void 0 : nextAccordion.value;
if (nextAccordionValue !== undefined) {
this.isPrevious = Array.isArray(value) ? value.includes(nextAccordionValue) : value === nextAccordionValue;
}
const previousAccordion = this.getPreviousSibling();
const previousAccordionValue = previousAccordion === null || previousAccordion === void 0 ? void 0 : previousAccordion.value;
if (previousAccordionValue !== undefined) {
this.isNext = Array.isArray(value) ? value.includes(previousAccordionValue) : value === previousAccordionValue;
}
}
};
this.getNextSibling = () => {
if (!this.el) {
return;
}
const nextSibling = this.el.nextElementSibling;
if ((nextSibling === null || nextSibling === void 0 ? void 0 : nextSibling.tagName) !== 'ION-ACCORDION') {
return;
}
return nextSibling;
};
this.getPreviousSibling = () => {
if (!this.el) {
return;
}
const previousSibling = this.el.previousElementSibling;
if ((previousSibling === null || previousSibling === void 0 ? void 0 : previousSibling.tagName) !== 'ION-ACCORDION') {
return;
}
return previousSibling;
};
}
valueChanged() {
this.updateState();
}
connectedCallback() {
var _a;
const accordionGroupEl = (this.accordionGroupEl = (_a = this.el) === null || _a === void 0 ? void 0 : _a.closest('ion-accordion-group'));
if (accordionGroupEl) {
this.updateState(true);
addEventListener$1(accordionGroupEl, 'ionValueChange', this.updateListener);
}
}
disconnectedCallback() {
const accordionGroupEl = this.accordionGroupEl;
if (accordionGroupEl) {
removeEventListener(accordionGroupEl, 'ionValueChange', this.updateListener);
}
}
componentDidLoad() {
this.setItemDefaults();
this.slotToggleIcon();
/**
* We need to wait a tick because we
* just set ionItem.button = true and
* the button has not have been rendered yet.
*/
raf(() => {
/**
* Set aria label on button inside of ion-item
* once the inner content has been rendered.
*/
const expanded = this.state === 4 /* AccordionState.Expanded */ || this.state === 8 /* AccordionState.Expanding */;
this.setAria(expanded);
});
}
toggleExpanded() {
const { accordionGroupEl, disabled, readonly, value, state } = this;
if (disabled || readonly)
return;
if (accordionGroupEl) {
/**
* Because the accordion group may or may
* not allow multiple accordions open, we
* need to request the toggling of this
* accordion and the accordion group will
* make the decision on whether or not
* to allow it.
*/
const expand = state === 1 /* AccordionState.Collapsed */ || state === 2 /* AccordionState.Collapsing */;
accordionGroupEl.requestAccordionToggle(value, expand);
}
}
render() {
const { disabled, readonly } = this;
const mode = getIonMode$1(this);
const expanded = this.state === 4 /* AccordionState.Expanded */ || this.state === 8 /* AccordionState.Expanding */;
const headerPart = expanded ? 'header expanded' : 'header';
const contentPart = expanded ? 'content expanded' : 'content';
this.setAria(expanded);
return (hAsync(Host, { key: '073e1d02c18dcbc20c68648426e87c14750c031d', class: {
[mode]: true,
'accordion-expanding': this.state === 8 /* AccordionState.Expanding */,
'accordion-expanded': this.state === 4 /* AccordionState.Expanded */,
'accordion-collapsing': this.state === 2 /* AccordionState.Collapsing */,
'accordion-collapsed': this.state === 1 /* AccordionState.Collapsed */,
'accordion-next': this.isNext,
'accordion-previous': this.isPrevious,
'accordion-disabled': disabled,
'accordion-readonly': readonly,
'accordion-animated': this.shouldAnimate(),
} }, hAsync("div", { key: '9b4cf326de8bb6b4033992903c0c1bfd7eea9bcc', onClick: () => this.toggleExpanded(), id: "header", part: headerPart, "aria-controls": "content", ref: (headerEl) => (this.headerEl = headerEl) }, hAsync("slot", { key: '464c32a37f64655eacf4218284214f5f30b14a1e', name: "header" })), hAsync("div", { key: '8bb52e6a62d7de0106b253201a89a32e79d9a594', id: "content", part: contentPart, role: "region", "aria-labelledby": "header", ref: (contentEl) => (this.contentEl = contentEl) }, hAsync("div", { key: '1d9dfd952ad493754aaeea7a8f625b33c2dd90a0', id: "content-wrapper", ref: (contentElWrapper) => (this.contentElWrapper = contentElWrapper) }, hAsync("slot", { key: '970dfbc55a612d739d0ca3b7b1a08e5c96d0c479', name: "content" })))));
}
static get delegatesFocus() { return true; }
get el() { return getElement(this); }
static get watchers() { return {
"value": ["valueChanged"]
}; }
static get style() { return {
ios: accordionIosCss,
md: accordionMdCss
}; }
static get cmpMeta() { return {
"$flags$": 313,
"$tagName$": "ion-accordion",
"$members$": {
"value": [1],
"disabled": [4],
"readonly": [4],
"toggleIcon": [1, "toggle-icon"],
"toggleIconSlot": [1, "toggle-icon-slot"],
"state": [32],
"isNext": [32],
"isPrevious": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
let accordionIds = 0;
const accordionGroupIosCss = ":host{display:block}:host(.accordion-group-expand-inset){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:16px;margin-bottom:16px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanding),:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanded){border-bottom:none}";
const accordionGroupMdCss = ":host{display:block}:host(.accordion-group-expand-inset){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:16px;margin-bottom:16px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion){-webkit-box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);box-shadow:0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12)}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanding),:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-expanded){margin-left:0;margin-right:0;margin-top:16px;margin-bottom:16px;border-radius:6px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-previous){border-end-end-radius:6px;border-end-start-radius:6px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion.accordion-next){border-start-start-radius:6px;border-start-end-radius:6px}:host(.accordion-group-expand-inset) ::slotted(ion-accordion):first-of-type{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class AccordionGroup {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionValueChange = createEvent(this, "ionValueChange", 7);
/**
* If `true`, all accordions inside of the
* accordion group will animate when expanding
* or collapsing.
*/
this.animated = true;
/**
* If `true`, the accordion group cannot be interacted with.
*/
this.disabled = false;
/**
* If `true`, the accordion group cannot be interacted with,
* but does not alter the opacity.
*/
this.readonly = false;
/**
* Describes the expansion behavior for each accordion.
* Possible values are `"compact"` and `"inset"`.
* Defaults to `"compact"`.
*/
this.expand = 'compact';
}
valueChanged() {
const { value, multiple } = this;
if (!multiple && Array.isArray(value)) {
/**
* We do some processing on the `value` array so
* that it looks more like an array when logged to
* the console.
* Example given ['a', 'b']
* Default toString() behavior: a,b
* Custom behavior: ['a', 'b']
*/
printIonWarning(`[ion-accordion-group] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
`, this.el);
}
/**
* Do not use `value` here as that will be
* not account for the adjustment we make above.
*/
this.ionValueChange.emit({ value: this.value });
}
async disabledChanged() {
const { disabled } = this;
const accordions = await this.getAccordions();
for (const accordion of accordions) {
accordion.disabled = disabled;
}
}
async readonlyChanged() {
const { readonly } = this;
const accordions = await this.getAccordions();
for (const accordion of accordions) {
accordion.readonly = readonly;
}
}
async onKeydown(ev) {
const activeElement = document.activeElement;
if (!activeElement) {
return;
}
/**
* Make sure focus is in the header, not the body, of the accordion. This ensures
* that if there are any interactable elements in the body, their keyboard
* interaction doesn't get stolen by the accordion. Example: using up/down keys
* in ion-textarea.
*/
const activeAccordionHeader = activeElement.closest('ion-accordion [slot="header"]');
if (!activeAccordionHeader) {
return;
}
const accordionEl = activeElement.tagName === 'ION-ACCORDION' ? activeElement : activeElement.closest('ion-accordion');
if (!accordionEl) {
return;
}
const closestGroup = accordionEl.closest('ion-accordion-group');
if (closestGroup !== this.el) {
return;
}
// If the active accordion is not in the current array of accordions, do not do anything
const accordions = await this.getAccordions();
const startingIndex = accordions.findIndex((a) => a === accordionEl);
if (startingIndex === -1) {
return;
}
let accordion;
if (ev.key === 'ArrowDown') {
accordion = this.findNextAccordion(accordions, startingIndex);
}
else if (ev.key === 'ArrowUp') {
accordion = this.findPreviousAccordion(accordions, startingIndex);
}
else if (ev.key === 'Home') {
accordion = accordions[0];
}
else if (ev.key === 'End') {
accordion = accordions[accordions.length - 1];
}
if (accordion !== undefined && accordion !== activeElement) {
accordion.focus();
}
}
async componentDidLoad() {
if (this.disabled) {
this.disabledChanged();
}
if (this.readonly) {
this.readonlyChanged();
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.valueChanged();
}
/**
* Sets the value property and emits ionChange.
* This should only be called when the user interacts
* with the accordion and not for any update
* to the value property. The exception is when
* the app sets the value of a single-select
* accordion group to an array.
*/
setValue(accordionValue) {
const value = (this.value = accordionValue);
this.ionChange.emit({ value });
}
/**
* This method is used to ensure that the value
* of ion-accordion-group is being set in a valid
* way. This method should only be called in
* response to a user generated action.
* @internal
*/
async requestAccordionToggle(accordionValue, accordionExpand) {
const { multiple, value, readonly, disabled } = this;
if (readonly || disabled) {
return;
}
if (accordionExpand) {
/**
* If group accepts multiple values
* check to see if value is already in
* in values array. If not, add it
* to the array.
*/
if (multiple) {
const groupValue = value !== null && value !== void 0 ? value : [];
const processedValue = Array.isArray(groupValue) ? groupValue : [groupValue];
const valueExists = processedValue.find((v) => v === accordionValue);
if (valueExists === undefined && accordionValue !== undefined) {
this.setValue([...processedValue, accordionValue]);
}
}
else {
this.setValue(accordionValue);
}
}
else {
/**
* If collapsing accordion, either filter the value
* out of the values array or unset the value.
*/
if (multiple) {
const groupValue = value !== null && value !== void 0 ? value : [];
const processedValue = Array.isArray(groupValue) ? groupValue : [groupValue];
this.setValue(processedValue.filter((v) => v !== accordionValue));
}
else {
this.setValue(undefined);
}
}
}
findNextAccordion(accordions, startingIndex) {
const nextAccordion = accordions[startingIndex + 1];
if (nextAccordion === undefined) {
return accordions[0];
}
return nextAccordion;
}
findPreviousAccordion(accordions, startingIndex) {
const prevAccordion = accordions[startingIndex - 1];
if (prevAccordion === undefined) {
return accordions[accordions.length - 1];
}
return prevAccordion;
}
/**
* @internal
*/
async getAccordions() {
return Array.from(this.el.querySelectorAll(':scope > ion-accordion'));
}
render() {
const { disabled, readonly, expand } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd1a79a93179474fbba66fcf11a92f4871dacc975', class: {
[mode]: true,
'accordion-group-disabled': disabled,
'accordion-group-readonly': readonly,
[`accordion-group-expand-${expand}`]: true,
}, role: "presentation" }, hAsync("slot", { key: 'e6b8954b686d1fbb4fc92adb07fddc97a24b0a31' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"value": ["valueChanged"],
"disabled": ["disabledChanged"],
"readonly": ["readonlyChanged"]
}; }
static get style() { return {
ios: accordionGroupIosCss,
md: accordionGroupMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-accordion-group",
"$members$": {
"animated": [4],
"multiple": [4],
"value": [1025],
"disabled": [4],
"readonly": [4],
"expand": [1],
"requestAccordionToggle": [64],
"getAccordions": [64]
},
"$listeners$": [[0, "keydown", "onKeydown"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const win$1 = typeof window !== 'undefined' ? window : undefined;
const doc = typeof document !== 'undefined' ? document : undefined;
const getCapacitor = () => {
if (win$1 !== undefined) {
return win$1.Capacitor;
}
return undefined;
};
var ImpactStyle;
(function (ImpactStyle) {
/**
* A collision between large, heavy user interface elements
*
* @since 1.0.0
*/
ImpactStyle["Heavy"] = "HEAVY";
/**
* A collision between moderately sized user interface elements
*
* @since 1.0.0
*/
ImpactStyle["Medium"] = "MEDIUM";
/**
* A collision between small, light user interface elements
*
* @since 1.0.0
*/
ImpactStyle["Light"] = "LIGHT";
})(ImpactStyle || (ImpactStyle = {}));
var NotificationType;
(function (NotificationType) {
/**
* A notification feedback type indicating that a task has completed successfully
*
* @since 1.0.0
*/
NotificationType["Success"] = "SUCCESS";
/**
* A notification feedback type indicating that a task has produced a warning
*
* @since 1.0.0
*/
NotificationType["Warning"] = "WARNING";
/**
* A notification feedback type indicating that a task has failed
*
* @since 1.0.0
*/
NotificationType["Error"] = "ERROR";
})(NotificationType || (NotificationType = {}));
const HapticEngine = {
getEngine() {
const capacitor = getCapacitor();
if (capacitor === null || capacitor === void 0 ? void 0 : capacitor.isPluginAvailable('Haptics')) {
// Capacitor
return capacitor.Plugins.Haptics;
}
return undefined;
},
available() {
const engine = this.getEngine();
if (!engine) {
return false;
}
const capacitor = getCapacitor();
/**
* Developers can manually import the
* Haptics plugin in their app which will cause
* getEngine to return the Haptics engine. However,
* the Haptics engine will throw an error if
* used in a web browser that does not support
* the Vibrate API. This check avoids that error
* if the browser does not support the Vibrate API.
*/
if ((capacitor === null || capacitor === void 0 ? void 0 : capacitor.getPlatform()) === 'web') {
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
return typeof navigator !== 'undefined' && navigator.vibrate !== undefined;
}
return true;
},
impact(options) {
const engine = this.getEngine();
if (!engine) {
return;
}
engine.impact({ style: options.style });
},
notification(options) {
const engine = this.getEngine();
if (!engine) {
return;
}
engine.notification({ type: options.type });
},
selection() {
this.impact({ style: ImpactStyle.Light });
},
selectionStart() {
const engine = this.getEngine();
if (!engine) {
return;
}
engine.selectionStart();
},
selectionChanged() {
const engine = this.getEngine();
if (!engine) {
return;
}
engine.selectionChanged();
},
selectionEnd() {
const engine = this.getEngine();
if (!engine) {
return;
}
engine.selectionEnd();
},
};
/**
* Check to see if the Haptic Plugin is available
* @return Returns `true` or false if the plugin is available
*/
const hapticAvailable = () => {
return HapticEngine.available();
};
/**
* Trigger a selection changed haptic event. Good for one-time events
* (not for gestures)
*/
const hapticSelection = () => {
hapticAvailable() && HapticEngine.selection();
};
/**
* Tell the haptic engine that a gesture for a selection change is starting.
*/
const hapticSelectionStart = () => {
hapticAvailable() && HapticEngine.selectionStart();
};
/**
* Tell the haptic engine that a selection changed during a gesture.
*/
const hapticSelectionChanged = () => {
hapticAvailable() && HapticEngine.selectionChanged();
};
/**
* Tell the haptic engine we are done with a gesture. This needs to be
* called lest resources are not properly recycled.
*/
const hapticSelectionEnd = () => {
hapticAvailable() && HapticEngine.selectionEnd();
};
/**
* Use this to indicate success/failure/warning to the user.
* options should be of the type `{ style: ImpactStyle.LIGHT }` (or `MEDIUM`/`HEAVY`)
*/
const hapticImpact = (options) => {
hapticAvailable() && HapticEngine.impact(options);
};
class GestureController {
constructor() {
this.gestureId = 0;
this.requestedStart = new Map();
this.disabledGestures = new Map();
this.disabledScroll = new Set();
}
/**
* Creates a gesture delegate based on the GestureConfig passed
*/
createGesture(config) {
var _a;
return new GestureDelegate(this, this.newID(), config.name, (_a = config.priority) !== null && _a !== void 0 ? _a : 0, !!config.disableScroll);
}
/**
* Creates a blocker that will block any other gesture events from firing. Set in the ion-gesture component.
*/
createBlocker(opts = {}) {
return new BlockerDelegate(this, this.newID(), opts.disable, !!opts.disableScroll);
}
start(gestureName, id, priority) {
if (!this.canStart(gestureName)) {
this.requestedStart.delete(id);
return false;
}
this.requestedStart.set(id, priority);
return true;
}
capture(gestureName, id, priority) {
if (!this.start(gestureName, id, priority)) {
return false;
}
const requestedStart = this.requestedStart;
let maxPriority = -1e4;
requestedStart.forEach((value) => {
maxPriority = Math.max(maxPriority, value);
});
if (maxPriority === priority) {
this.capturedId = id;
requestedStart.clear();
const event = new CustomEvent('ionGestureCaptured', { detail: { gestureName } });
document.dispatchEvent(event);
return true;
}
requestedStart.delete(id);
return false;
}
release(id) {
this.requestedStart.delete(id);
if (this.capturedId === id) {
this.capturedId = undefined;
}
}
disableGesture(gestureName, id) {
let set = this.disabledGestures.get(gestureName);
if (set === undefined) {
set = new Set();
this.disabledGestures.set(gestureName, set);
}
set.add(id);
}
enableGesture(gestureName, id) {
const set = this.disabledGestures.get(gestureName);
if (set !== undefined) {
set.delete(id);
}
}
disableScroll(id) {
this.disabledScroll.add(id);
if (this.disabledScroll.size === 1) {
document.body.classList.add(BACKDROP_NO_SCROLL);
}
}
enableScroll(id) {
this.disabledScroll.delete(id);
if (this.disabledScroll.size === 0) {
document.body.classList.remove(BACKDROP_NO_SCROLL);
}
}
canStart(gestureName) {
if (this.capturedId !== undefined) {
// a gesture already captured
return false;
}
if (this.isDisabled(gestureName)) {
return false;
}
return true;
}
isCaptured() {
return this.capturedId !== undefined;
}
isScrollDisabled() {
return this.disabledScroll.size > 0;
}
isDisabled(gestureName) {
const disabled = this.disabledGestures.get(gestureName);
if (disabled && disabled.size > 0) {
return true;
}
return false;
}
newID() {
this.gestureId++;
return this.gestureId;
}
}
class GestureDelegate {
constructor(ctrl, id, name, priority, disableScroll) {
this.id = id;
this.name = name;
this.disableScroll = disableScroll;
this.priority = priority * 1000000 + id;
this.ctrl = ctrl;
}
canStart() {
if (!this.ctrl) {
return false;
}
return this.ctrl.canStart(this.name);
}
start() {
if (!this.ctrl) {
return false;
}
return this.ctrl.start(this.name, this.id, this.priority);
}
capture() {
if (!this.ctrl) {
return false;
}
const captured = this.ctrl.capture(this.name, this.id, this.priority);
if (captured && this.disableScroll) {
this.ctrl.disableScroll(this.id);
}
return captured;
}
release() {
if (this.ctrl) {
this.ctrl.release(this.id);
if (this.disableScroll) {
this.ctrl.enableScroll(this.id);
}
}
}
destroy() {
this.release();
this.ctrl = undefined;
}
}
class BlockerDelegate {
constructor(ctrl, id, disable, disableScroll) {
this.id = id;
this.disable = disable;
this.disableScroll = disableScroll;
this.ctrl = ctrl;
}
block() {
if (!this.ctrl) {
return;
}
if (this.disable) {
for (const gesture of this.disable) {
this.ctrl.disableGesture(gesture, this.id);
}
}
if (this.disableScroll) {
this.ctrl.disableScroll(this.id);
}
}
unblock() {
if (!this.ctrl) {
return;
}
if (this.disable) {
for (const gesture of this.disable) {
this.ctrl.enableGesture(gesture, this.id);
}
}
if (this.disableScroll) {
this.ctrl.enableScroll(this.id);
}
}
destroy() {
this.unblock();
this.ctrl = undefined;
}
}
const BACKDROP_NO_SCROLL = 'backdrop-no-scroll';
const GESTURE_CONTROLLER = new GestureController();
const addEventListener = (el, // TODO(FW-2832): type
eventName, callback, opts) => {
// use event listener options when supported
// otherwise it's just a boolean for the "capture" arg
const listenerOpts = supportsPassive(el)
? {
capture: false,
passive: !!opts.passive,
}
: false;
let add;
let remove;
if (el['__zone_symbol__addEventListener']) {
add = '__zone_symbol__addEventListener';
remove = '__zone_symbol__removeEventListener';
}
else {
add = 'addEventListener';
remove = 'removeEventListener';
}
el[add](eventName, callback, listenerOpts);
return () => {
el[remove](eventName, callback, listenerOpts);
};
};
const supportsPassive = (node) => {
if (_sPassive === undefined) {
try {
const opts = Object.defineProperty({}, 'passive', {
get: () => {
_sPassive = true;
},
});
node.addEventListener('optsTest', () => {
return;
}, opts);
}
catch (e) {
_sPassive = false;
}
}
return !!_sPassive;
};
let _sPassive;
const MOUSE_WAIT = 2000;
// TODO(FW-2832): types
const createPointerEvents = (el, pointerDown, pointerMove, pointerUp, options) => {
let rmTouchStart;
let rmTouchMove;
let rmTouchEnd;
let rmTouchCancel;
let rmMouseStart;
let rmMouseMove;
let rmMouseUp;
let lastTouchEvent = 0;
const handleTouchStart = (ev) => {
lastTouchEvent = Date.now() + MOUSE_WAIT;
if (!pointerDown(ev)) {
return;
}
if (!rmTouchMove && pointerMove) {
rmTouchMove = addEventListener(el, 'touchmove', pointerMove, options);
}
/**
* Events are dispatched on the element that is tapped and bubble up to
* the reference element in the gesture. In the event that the element this
* event was first dispatched on is removed from the DOM, the event will no
* longer bubble up to our reference element. This leaves the gesture in an
* unusable state. To account for this, the touchend and touchcancel listeners
* should be added to the event target so that they still fire even if the target
* is removed from the DOM.
*/
if (!rmTouchEnd) {
rmTouchEnd = addEventListener(ev.target, 'touchend', handleTouchEnd, options);
}
if (!rmTouchCancel) {
rmTouchCancel = addEventListener(ev.target, 'touchcancel', handleTouchEnd, options);
}
};
const handleMouseDown = (ev) => {
if (lastTouchEvent > Date.now()) {
return;
}
if (!pointerDown(ev)) {
return;
}
if (!rmMouseMove && pointerMove) {
rmMouseMove = addEventListener(getDocument(el), 'mousemove', pointerMove, options);
}
if (!rmMouseUp) {
rmMouseUp = addEventListener(getDocument(el), 'mouseup', handleMouseUp, options);
}
};
const handleTouchEnd = (ev) => {
stopTouch();
if (pointerUp) {
pointerUp(ev);
}
};
const handleMouseUp = (ev) => {
stopMouse();
if (pointerUp) {
pointerUp(ev);
}
};
const stopTouch = () => {
if (rmTouchMove) {
rmTouchMove();
}
if (rmTouchEnd) {
rmTouchEnd();
}
if (rmTouchCancel) {
rmTouchCancel();
}
rmTouchMove = rmTouchEnd = rmTouchCancel = undefined;
};
const stopMouse = () => {
if (rmMouseMove) {
rmMouseMove();
}
if (rmMouseUp) {
rmMouseUp();
}
rmMouseMove = rmMouseUp = undefined;
};
const stop = () => {
stopTouch();
stopMouse();
};
const enable = (isEnabled = true) => {
if (!isEnabled) {
if (rmTouchStart) {
rmTouchStart();
}
if (rmMouseStart) {
rmMouseStart();
}
rmTouchStart = rmMouseStart = undefined;
stop();
}
else {
if (!rmTouchStart) {
rmTouchStart = addEventListener(el, 'touchstart', handleTouchStart, options);
}
if (!rmMouseStart) {
rmMouseStart = addEventListener(el, 'mousedown', handleMouseDown, options);
}
}
};
const destroy = () => {
enable(false);
pointerUp = pointerMove = pointerDown = undefined;
};
return {
enable,
stop,
destroy,
};
};
const getDocument = (node) => {
return node instanceof Document ? node : node.ownerDocument;
};
const createPanRecognizer = (direction, thresh, maxAngle) => {
const radians = maxAngle * (Math.PI / 180);
const isDirX = direction === 'x';
const maxCosine = Math.cos(radians);
const threshold = thresh * thresh;
let startX = 0;
let startY = 0;
let dirty = false;
let isPan = 0;
return {
start(x, y) {
startX = x;
startY = y;
isPan = 0;
dirty = true;
},
detect(x, y) {
if (!dirty) {
return false;
}
const deltaX = x - startX;
const deltaY = y - startY;
const distance = deltaX * deltaX + deltaY * deltaY;
if (distance < threshold) {
return false;
}
const hypotenuse = Math.sqrt(distance);
const cosine = (isDirX ? deltaX : deltaY) / hypotenuse;
if (cosine > maxCosine) {
isPan = 1;
}
else if (cosine < -maxCosine) {
isPan = -1;
}
else {
isPan = 0;
}
dirty = false;
return true;
},
isGesture() {
return isPan !== 0;
},
getDirection() {
return isPan;
},
};
};
// TODO(FW-2832): types
const createGesture = (config) => {
let hasCapturedPan = false;
let hasStartedPan = false;
let hasFiredStart = true;
let isMoveQueued = false;
const finalConfig = Object.assign({ disableScroll: false, direction: 'x', gesturePriority: 0, passive: true, maxAngle: 40, threshold: 10 }, config);
const canStart = finalConfig.canStart;
const onWillStart = finalConfig.onWillStart;
const onStart = finalConfig.onStart;
const onEnd = finalConfig.onEnd;
const notCaptured = finalConfig.notCaptured;
const onMove = finalConfig.onMove;
const threshold = finalConfig.threshold;
const passive = finalConfig.passive;
const blurOnStart = finalConfig.blurOnStart;
const detail = {
type: 'pan',
startX: 0,
startY: 0,
startTime: 0,
currentX: 0,
currentY: 0,
velocityX: 0,
velocityY: 0,
deltaX: 0,
deltaY: 0,
currentTime: 0,
event: undefined,
data: undefined,
};
const pan = createPanRecognizer(finalConfig.direction, finalConfig.threshold, finalConfig.maxAngle);
const gesture = GESTURE_CONTROLLER.createGesture({
name: config.gestureName,
priority: config.gesturePriority,
disableScroll: config.disableScroll,
});
const pointerDown = (ev) => {
const timeStamp = now(ev);
if (hasStartedPan || !hasFiredStart) {
return false;
}
updateDetail(ev, detail);
detail.startX = detail.currentX;
detail.startY = detail.currentY;
detail.startTime = detail.currentTime = timeStamp;
detail.velocityX = detail.velocityY = detail.deltaX = detail.deltaY = 0;
detail.event = ev;
// Check if gesture can start
if (canStart && canStart(detail) === false) {
return false;
}
// Release fallback
gesture.release();
// Start gesture
if (!gesture.start()) {
return false;
}
hasStartedPan = true;
if (threshold === 0) {
return tryToCapturePan();
}
pan.start(detail.startX, detail.startY);
return true;
};
const pointerMove = (ev) => {
// fast path, if gesture is currently captured
// do minimum job to get user-land even dispatched
if (hasCapturedPan) {
if (!isMoveQueued && hasFiredStart) {
isMoveQueued = true;
calcGestureData(detail, ev);
requestAnimationFrame(fireOnMove);
}
return;
}
// gesture is currently being detected
calcGestureData(detail, ev);
if (pan.detect(detail.currentX, detail.currentY)) {
if (!pan.isGesture() || !tryToCapturePan()) {
abortGesture();
}
}
};
const fireOnMove = () => {
// Since fireOnMove is called inside a RAF, onEnd() might be called,
// we must double check hasCapturedPan
if (!hasCapturedPan) {
return;
}
isMoveQueued = false;
if (onMove) {
onMove(detail);
}
};
const tryToCapturePan = () => {
if (!gesture.capture()) {
return false;
}
hasCapturedPan = true;
hasFiredStart = false;
// reset start position since the real user-land event starts here
// If the pan detector threshold is big, not resetting the start position
// will cause a jump in the animation equal to the detector threshold.
// the array of positions used to calculate the gesture velocity does not
// need to be cleaned, more points in the positions array always results in a
// more accurate value of the velocity.
detail.startX = detail.currentX;
detail.startY = detail.currentY;
detail.startTime = detail.currentTime;
if (onWillStart) {
onWillStart(detail).then(fireOnStart);
}
else {
fireOnStart();
}
return true;
};
const blurActiveElement = () => {
if (typeof document !== 'undefined') {
const activeElement = document.activeElement;
if (activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) {
activeElement.blur();
}
}
};
const fireOnStart = () => {
if (blurOnStart) {
blurActiveElement();
}
if (onStart) {
onStart(detail);
}
hasFiredStart = true;
};
const reset = () => {
hasCapturedPan = false;
hasStartedPan = false;
isMoveQueued = false;
hasFiredStart = true;
gesture.release();
};
// END *************************
const pointerUp = (ev) => {
const tmpHasCaptured = hasCapturedPan;
const tmpHasFiredStart = hasFiredStart;
reset();
if (!tmpHasFiredStart) {
return;
}
calcGestureData(detail, ev);
// Try to capture press
if (tmpHasCaptured) {
if (onEnd) {
onEnd(detail);
}
return;
}
// Not captured any event
if (notCaptured) {
notCaptured(detail);
}
};
const pointerEvents = createPointerEvents(finalConfig.el, pointerDown, pointerMove, pointerUp, {
passive,
});
const abortGesture = () => {
reset();
pointerEvents.stop();
if (notCaptured) {
notCaptured(detail);
}
};
return {
enable(enable = true) {
if (!enable) {
if (hasCapturedPan) {
pointerUp(undefined);
}
reset();
}
pointerEvents.enable(enable);
},
destroy() {
gesture.destroy();
pointerEvents.destroy();
},
};
};
const calcGestureData = (detail, ev) => {
if (!ev) {
return;
}
const prevX = detail.currentX;
const prevY = detail.currentY;
const prevT = detail.currentTime;
updateDetail(ev, detail);
const currentX = detail.currentX;
const currentY = detail.currentY;
const timestamp = (detail.currentTime = now(ev));
const timeDelta = timestamp - prevT;
if (timeDelta > 0 && timeDelta < 100) {
const velocityX = (currentX - prevX) / timeDelta;
const velocityY = (currentY - prevY) / timeDelta;
detail.velocityX = velocityX * 0.7 + detail.velocityX * 0.3;
detail.velocityY = velocityY * 0.7 + detail.velocityY * 0.3;
}
detail.deltaX = currentX - detail.startX;
detail.deltaY = currentY - detail.startY;
detail.event = ev;
};
const updateDetail = (ev, detail) => {
// get X coordinates for either a mouse click
// or a touch depending on the given event
let x = 0;
let y = 0;
if (ev) {
const changedTouches = ev.changedTouches;
if (changedTouches && changedTouches.length > 0) {
const touch = changedTouches[0];
x = touch.clientX;
y = touch.clientY;
}
else if (ev.pageX !== undefined) {
x = ev.pageX;
y = ev.pageY;
}
}
detail.currentX = x;
detail.currentY = y;
};
const now = (ev) => {
return ev.timeStamp || Date.now();
};
var index = /*#__PURE__*/Object.freeze({
__proto__: null,
GESTURE_CONTROLLER: GESTURE_CONTROLLER,
createGesture: createGesture
});
const createButtonActiveGesture = (el, isButton) => {
let currentTouchedButton;
let initialTouchedButton;
const activateButtonAtPoint = (x, y, hapticFeedbackFn) => {
if (typeof document === 'undefined') {
return;
}
const target = document.elementFromPoint(x, y);
if (!target || !isButton(target) || target.disabled) {
clearActiveButton();
return;
}
if (target !== currentTouchedButton) {
clearActiveButton();
setActiveButton(target, hapticFeedbackFn);
}
};
const setActiveButton = (button, hapticFeedbackFn) => {
currentTouchedButton = button;
if (!initialTouchedButton) {
initialTouchedButton = currentTouchedButton;
}
const buttonToModify = currentTouchedButton;
writeTask(() => buttonToModify.classList.add('ion-activated'));
hapticFeedbackFn();
};
const clearActiveButton = (dispatchClick = false) => {
if (!currentTouchedButton) {
return;
}
const buttonToModify = currentTouchedButton;
writeTask(() => buttonToModify.classList.remove('ion-activated'));
/**
* Clicking on one button, but releasing on another button
* does not dispatch a click event in browsers, so we
* need to do it manually here. Some browsers will
* dispatch a click if clicking on one button, dragging over
* another button, and releasing on the original button. In that
* case, we need to make sure we do not cause a double click there.
*/
if (dispatchClick && initialTouchedButton !== currentTouchedButton) {
currentTouchedButton.click();
}
currentTouchedButton = undefined;
};
return createGesture({
el,
gestureName: 'buttonActiveDrag',
threshold: 0,
onStart: (ev) => activateButtonAtPoint(ev.currentX, ev.currentY, hapticSelectionStart),
onMove: (ev) => activateButtonAtPoint(ev.currentX, ev.currentY, hapticSelectionChanged),
onEnd: () => {
clearActiveButton(true);
hapticSelectionEnd();
initialTouchedButton = undefined;
},
});
};
/**
* Creates a lock controller.
*
* Claiming a lock means that nothing else can acquire the lock until it is released.
* This can momentarily prevent execution of code that needs to wait for the earlier code to finish.
* For example, this can be used to prevent multiple transitions from occurring at the same time.
*/
const createLockController = () => {
let waitPromise;
/**
* When lock() is called, the lock is claimed.
* Once a lock has been claimed, it cannot be claimed again until it is released.
* When this function gets resolved, the lock is released, allowing it to be claimed again.
*
* @example ```tsx
* const unlock = await this.lockController.lock();
* // do other stuff
* unlock();
* ```
*/
const lock = async () => {
const p = waitPromise;
let resolve;
waitPromise = new Promise((r) => (resolve = r));
if (p !== undefined) {
await p;
}
return resolve;
};
return {
lock,
};
};
/**
* This query string selects elements that
* are eligible to receive focus. We select
* interactive elements that meet the following
* criteria:
* 1. Element does not have a negative tabindex
* 2. Element does not have `hidden`
* 3. Element does not have `disabled` for non-Ionic components.
* 4. Element does not have `disabled` or `disabled="true"` for Ionic components.
* Note: We need this distinction because `disabled="false"` is
* valid usage for the disabled property on ion-button.
*/
const focusableQueryString = '[tabindex]:not([tabindex^="-"]):not([hidden]):not([disabled]), input:not([type=hidden]):not([tabindex^="-"]):not([hidden]):not([disabled]), textarea:not([tabindex^="-"]):not([hidden]):not([disabled]), button:not([tabindex^="-"]):not([hidden]):not([disabled]), select:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-checkbox:not([tabindex^="-"]):not([hidden]):not([disabled]), ion-radio:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable:not([tabindex^="-"]):not([hidden]):not([disabled]), .ion-focusable[disabled="false"]:not([tabindex^="-"]):not([hidden])';
/**
* Focuses the first descendant in a context
* that can receive focus. If none exists,
* a fallback element will be focused.
* This fallback is typically an ancestor
* container such as a menu or overlay so focus does not
* leave the container we are trying to trap focus in.
*
* If no fallback is specified then we focus the container itself.
*/
const focusFirstDescendant = (ref, fallbackElement) => {
const firstInput = ref.querySelector(focusableQueryString);
focusElementInContext(firstInput, fallbackElement !== null && fallbackElement !== void 0 ? fallbackElement : ref);
};
/**
* Focuses the last descendant in a context
* that can receive focus. If none exists,
* a fallback element will be focused.
* This fallback is typically an ancestor
* container such as a menu or overlay so focus does not
* leave the container we are trying to trap focus in.
*
* If no fallback is specified then we focus the container itself.
*/
const focusLastDescendant = (ref, fallbackElement) => {
const inputs = Array.from(ref.querySelectorAll(focusableQueryString));
const lastInput = inputs.length > 0 ? inputs[inputs.length - 1] : null;
focusElementInContext(lastInput, fallbackElement !== null && fallbackElement !== void 0 ? fallbackElement : ref);
};
/**
* Focuses a particular element in a context. If the element
* doesn't have anything focusable associated with it then
* a fallback element will be focused.
*
* This fallback is typically an ancestor
* container such as a menu or overlay so focus does not
* leave the container we are trying to trap focus in.
* This should be used instead of the focus() method
* on most elements because the focusable element
* may not be the host element.
*
* For example, if an ion-button should be focused
* then we should actually focus the native <button>
* element inside of ion-button's shadow root, not
* the host element itself.
*/
const focusElementInContext = (hostToFocus, fallbackElement) => {
let elementToFocus = hostToFocus;
const shadowRoot = hostToFocus === null || hostToFocus === void 0 ? void 0 : hostToFocus.shadowRoot;
if (shadowRoot) {
// If there are no inner focusable elements, just focus the host element.
elementToFocus = shadowRoot.querySelector(focusableQueryString) || hostToFocus;
}
if (elementToFocus) {
const radioGroup = elementToFocus.closest('ion-radio-group');
if (radioGroup) {
radioGroup.setFocus();
}
else {
focusVisibleElement(elementToFocus);
}
}
else {
// Focus fallback element instead of letting focus escape
fallbackElement.focus();
}
};
/**
* CloseWatcher is a newer API that lets
* use detect the hardware back button event
* in a web browser: https://caniuse.com/?search=closewatcher
* However, not every browser supports it yet.
*
* This needs to be a function so that we can
* check the config once it has been set.
* Otherwise, this code would be evaluated the
* moment this file is evaluated which could be
* before the config is set.
*/
const shouldUseCloseWatcher = () => config.get('experimentalCloseWatcher', false) && win$1 !== undefined && 'CloseWatcher' in win$1;
const OVERLAY_BACK_BUTTON_PRIORITY = 100;
const MENU_BACK_BUTTON_PRIORITY = 99; // 1 less than overlay priority since menu is displayed behind overlays
// TODO(FW-2832): types
const attachComponent = async (delegate, container, component, cssClasses, componentProps, inline) => {
var _a;
if (delegate) {
return delegate.attachViewToDom(container, component, componentProps, cssClasses);
}
if (!inline && typeof component !== 'string' && !(component instanceof HTMLElement)) {
throw new Error('framework delegate is missing');
}
const el = typeof component === 'string' ? (_a = container.ownerDocument) === null || _a === void 0 ? void 0 : _a.createElement(component) : component;
if (cssClasses) {
cssClasses.forEach((c) => el.classList.add(c));
}
if (componentProps) {
Object.assign(el, componentProps);
}
container.appendChild(el);
await new Promise((resolve) => componentOnReady(el, resolve));
return el;
};
const detachComponent = (delegate, element) => {
if (element) {
if (delegate) {
const container = element.parentElement;
return delegate.removeViewFromDom(container, element);
}
element.remove();
}
return Promise.resolve();
};
const CoreDelegate = () => {
let BaseComponent;
let Reference;
const attachViewToDom = async (parentElement, userComponent, userComponentProps = {}, cssClasses = []) => {
var _a, _b;
BaseComponent = parentElement;
let ChildComponent;
/**
* If passing in a component via the `component` props
* we need to append it inside of our overlay component.
*/
if (userComponent) {
/**
* If passing in the tag name, create
* the element otherwise just get a reference
* to the component.
*/
const el = typeof userComponent === 'string' ? (_a = BaseComponent.ownerDocument) === null || _a === void 0 ? void 0 : _a.createElement(userComponent) : userComponent;
/**
* Add any css classes passed in
* via the cssClasses prop on the overlay.
*/
cssClasses.forEach((c) => el.classList.add(c));
/**
* Add any props passed in
* via the componentProps prop on the overlay.
*/
Object.assign(el, userComponentProps);
/**
* Finally, append the component
* inside of the overlay component.
*/
BaseComponent.appendChild(el);
ChildComponent = el;
await new Promise((resolve) => componentOnReady(el, resolve));
}
else if (BaseComponent.children.length > 0 &&
(BaseComponent.tagName === 'ION-MODAL' || BaseComponent.tagName === 'ION-POPOVER')) {
/**
* The delegate host wrapper el is only needed for modals and popovers
* because they allow the dev to provide custom content to the overlay.
*/
const root = (ChildComponent = BaseComponent.children[0]);
if (!root.classList.contains('ion-delegate-host')) {
/**
* If the root element is not a delegate host, it means
* that the overlay has not been presented yet and we need
* to create the containing element with the specified classes.
*/
const el = (_b = BaseComponent.ownerDocument) === null || _b === void 0 ? void 0 : _b.createElement('div');
// Add a class to track if the root element was created by the delegate.
el.classList.add('ion-delegate-host');
cssClasses.forEach((c) => el.classList.add(c));
// Move each child from the original template to the new parent element.
el.append(...BaseComponent.children);
// Append the new parent element to the original parent element.
BaseComponent.appendChild(el);
/**
* Update the ChildComponent to be the
* newly created div in the event that one
* does not already exist.
*/
ChildComponent = el;
}
}
/**
* Get the root of the app and
* add the overlay there.
*/
const app = document.querySelector('ion-app') || document.body;
/**
* Create a placeholder comment so that
* we can return this component to where
* it was previously.
*/
Reference = document.createComment('ionic teleport');
BaseComponent.parentNode.insertBefore(Reference, BaseComponent);
app.appendChild(BaseComponent);
/**
* We return the child component rather than the overlay
* reference itself since modal and popover will
* use this to wait for any Ionic components in the child view
* to be ready (i.e. componentOnReady) when using the
* lazy loaded component bundle.
*
* However, we fall back to returning BaseComponent
* in the event that a modal or popover is presented
* with no child content.
*/
return ChildComponent !== null && ChildComponent !== void 0 ? ChildComponent : BaseComponent;
};
const removeViewFromDom = () => {
/**
* Return component to where it was previously in the DOM.
*/
if (BaseComponent && Reference) {
Reference.parentNode.insertBefore(BaseComponent, Reference);
Reference.remove();
}
return Promise.resolve();
};
return { attachViewToDom, removeViewFromDom };
};
let lastOverlayIndex = 0;
let lastId = 0;
const activeAnimations = new WeakMap();
const createController = (tagName) => {
return {
create(options) {
return createOverlay(tagName, options);
},
dismiss(data, role, id) {
return dismissOverlay(document, data, role, tagName, id);
},
async getTop() {
return getPresentedOverlay(document, tagName);
},
};
};
const alertController = /*@__PURE__*/ createController('ion-alert');
const actionSheetController = /*@__PURE__*/ createController('ion-action-sheet');
const modalController = /*@__PURE__*/ createController('ion-modal');
const popoverController = /*@__PURE__*/ createController('ion-popover');
/**
* Prepares the overlay element to be presented.
*/
const prepareOverlay = (el) => {
if (typeof document !== 'undefined') {
/**
* Adds a single instance of event listeners for application behaviors:
*
* - Escape Key behavior to dismiss an overlay
* - Trapping focus within an overlay
* - Back button behavior to dismiss an overlay
*
* This only occurs when the first overlay is created.
*/
connectListeners(document);
}
const overlayIndex = lastOverlayIndex++;
/**
* overlayIndex is used in the overlay components to set a zIndex.
* This ensures that the most recently presented overlay will be
* on top.
*/
el.overlayIndex = overlayIndex;
};
/**
* Assigns an incrementing id to an overlay element, that does not
* already have an id assigned to it.
*
* Used to track unique instances of an overlay element.
*/
const setOverlayId = (el) => {
if (!el.hasAttribute('id')) {
el.id = `ion-overlay-${++lastId}`;
}
return el.id;
};
const createOverlay = (tagName, opts) => {
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (typeof window !== 'undefined' && typeof window.customElements !== 'undefined') {
return window.customElements.whenDefined(tagName).then(() => {
const element = document.createElement(tagName);
element.classList.add('overlay-hidden');
/**
* Convert the passed in overlay options into props
* that get passed down into the new overlay.
*/
Object.assign(element, Object.assign(Object.assign({}, opts), { hasController: true }));
// append the overlay element to the document body
getAppRoot(document).appendChild(element);
return new Promise((resolve) => componentOnReady(element, resolve));
});
}
return Promise.resolve();
};
const isOverlayHidden = (overlay) => overlay.classList.contains('overlay-hidden');
/**
* Focuses a particular element in an overlay. If the element
* doesn't have anything focusable associated with it then
* the overlay itself will be focused.
* This should be used instead of the focus() method
* on most elements because the focusable element
* may not be the host element.
*
* For example, if an ion-button should be focused
* then we should actually focus the native <button>
* element inside of ion-button's shadow root, not
* the host element itself.
*/
const focusElementInOverlay = (hostToFocus, overlay) => {
let elementToFocus = hostToFocus;
const shadowRoot = hostToFocus === null || hostToFocus === void 0 ? void 0 : hostToFocus.shadowRoot;
if (shadowRoot) {
// If there are no inner focusable elements, just focus the host element.
elementToFocus = shadowRoot.querySelector(focusableQueryString) || hostToFocus;
}
if (elementToFocus) {
focusVisibleElement(elementToFocus);
}
else {
// Focus overlay instead of letting focus escape
overlay.focus();
}
};
/**
* Traps keyboard focus inside of overlay components.
* Based on https://w3c.github.io/aria-practices/examples/dialog-modal/alertdialog.html
* This includes the following components: Action Sheet, Alert, Loading, Modal,
* Picker, and Popover.
* Should NOT include: Toast
*/
const trapKeyboardFocus = (ev, doc) => {
const lastOverlay = getPresentedOverlay(doc, 'ion-alert,ion-action-sheet,ion-loading,ion-modal,ion-picker-legacy,ion-popover');
const target = ev.target;
/**
* If no active overlay, ignore this event.
*
* If this component uses the shadow dom,
* this global listener is pointless
* since it will not catch the focus
* traps as they are inside the shadow root.
* We need to add a listener to the shadow root
* itself to ensure the focus trap works.
*/
if (!lastOverlay || !target) {
return;
}
/**
* If the ion-disable-focus-trap class
* is present on an overlay, then this component
* instance has opted out of focus trapping.
* An example of this is when the sheet modal
* has a backdrop that is disabled. The content
* behind the sheet should be focusable until
* the backdrop is enabled.
*/
if (lastOverlay.classList.contains(FOCUS_TRAP_DISABLE_CLASS)) {
return;
}
const trapScopedFocus = () => {
/**
* If we are focusing the overlay, clear
* the last focused element so that hitting
* tab activates the first focusable element
* in the overlay wrapper.
*/
if (lastOverlay === target) {
lastOverlay.lastFocus = undefined;
/**
* Toasts can be presented from an overlay.
* However, focus should still be returned to
* the overlay when clicking a toast. Normally,
* focus would be returned to the last focusable
* descendant in the overlay which may not always be
* the button that the toast was presented from. In this case,
* the focus may be returned to an unexpected element.
* To account for this, we make sure to return focus to the
* last focused element in the overlay if focus is
* moved to the toast.
*/
}
else if (target.tagName === 'ION-TOAST') {
focusElementInOverlay(lastOverlay.lastFocus, lastOverlay);
/**
* Otherwise, we must be focusing an element
* inside of the overlay. The two possible options
* here are an input/button/etc or the ion-focus-trap
* element. The focus trap element is used to prevent
* the keyboard focus from leaving the overlay when
* using Tab or screen assistants.
*/
}
else {
/**
* We do not want to focus the traps, so get the overlay
* wrapper element as the traps live outside of the wrapper.
*/
const overlayRoot = getElementRoot(lastOverlay);
if (!overlayRoot.contains(target)) {
return;
}
const overlayWrapper = overlayRoot.querySelector('.ion-overlay-wrapper');
if (!overlayWrapper) {
return;
}
/**
* If the target is inside the wrapper, let the browser
* focus as normal and keep a log of the last focused element.
* Additionally, if the backdrop was tapped we should not
* move focus back inside the wrapper as that could cause
* an interactive elements focus state to activate.
*/
if (overlayWrapper.contains(target) || target === overlayRoot.querySelector('ion-backdrop')) {
lastOverlay.lastFocus = target;
}
else {
/**
* Otherwise, we must have focused one of the focus traps.
* We need to wrap the focus to either the first element
* or the last element.
*/
/**
* Once we call `focusFirstDescendant` and focus the first
* descendant, another focus event will fire which will
* cause `lastOverlay.lastFocus` to be updated before
* we can run the code after that. We will cache the value
* here to avoid that.
*/
const lastFocus = lastOverlay.lastFocus;
// Focus the first element in the overlay wrapper
focusFirstDescendant(overlayWrapper, lastOverlay);
/**
* If the cached last focused element is the
* same as the active element, then we need
* to wrap focus to the last descendant. This happens
* when the first descendant is focused, and the user
* presses Shift + Tab. The previous line will focus
* the same descendant again (the first one), causing
* last focus to equal the active element.
*/
if (lastFocus === doc.activeElement) {
focusLastDescendant(overlayWrapper, lastOverlay);
}
lastOverlay.lastFocus = doc.activeElement;
}
}
};
const trapShadowFocus = () => {
/**
* If the target is inside the wrapper, let the browser
* focus as normal and keep a log of the last focused element.
*/
if (lastOverlay.contains(target)) {
lastOverlay.lastFocus = target;
/**
* Toasts can be presented from an overlay.
* However, focus should still be returned to
* the overlay when clicking a toast. Normally,
* focus would be returned to the last focusable
* descendant in the overlay which may not always be
* the button that the toast was presented from. In this case,
* the focus may be returned to an unexpected element.
* To account for this, we make sure to return focus to the
* last focused element in the overlay if focus is
* moved to the toast.
*/
}
else if (target.tagName === 'ION-TOAST') {
focusElementInOverlay(lastOverlay.lastFocus, lastOverlay);
}
else {
/**
* Otherwise, we are about to have focus
* go out of the overlay. We need to wrap
* the focus to either the first element
* or the last element.
*/
/**
* Once we call `focusFirstDescendant` and focus the first
* descendant, another focus event will fire which will
* cause `lastOverlay.lastFocus` to be updated before
* we can run the code after that. We will cache the value
* here to avoid that.
*/
const lastFocus = lastOverlay.lastFocus;
// Focus the first element in the overlay wrapper
focusFirstDescendant(lastOverlay);
/**
* If the cached last focused element is the
* same as the active element, then we need
* to wrap focus to the last descendant. This happens
* when the first descendant is focused, and the user
* presses Shift + Tab. The previous line will focus
* the same descendant again (the first one), causing
* last focus to equal the active element.
*/
if (lastFocus === doc.activeElement) {
focusLastDescendant(lastOverlay);
}
lastOverlay.lastFocus = doc.activeElement;
}
};
if (lastOverlay.shadowRoot) {
trapShadowFocus();
}
else {
trapScopedFocus();
}
};
const connectListeners = (doc) => {
if (lastOverlayIndex === 0) {
lastOverlayIndex = 1;
doc.addEventListener('focus', (ev) => {
trapKeyboardFocus(ev, doc);
}, true);
// handle back-button click
doc.addEventListener('ionBackButton', (ev) => {
const lastOverlay = getPresentedOverlay(doc);
if (lastOverlay === null || lastOverlay === void 0 ? void 0 : lastOverlay.backdropDismiss) {
ev.detail.register(OVERLAY_BACK_BUTTON_PRIORITY, () => {
/**
* Do not return this promise otherwise
* the hardware back button utility will
* be blocked until the overlay dismisses.
* This is important for a modal with canDismiss.
* If the application presents a confirmation alert
* in the "canDismiss" callback, then it will be impossible
* to use the hardware back button to dismiss the alert
* dialog because the hardware back button utility
* is blocked on waiting for the modal to dismiss.
*/
lastOverlay.dismiss(undefined, BACKDROP);
});
}
});
/**
* Handle ESC to close overlay.
* CloseWatcher also handles pressing the Esc
* key, so if a browser supports CloseWatcher then
* this behavior will be handled via the ionBackButton
* event.
*/
if (!shouldUseCloseWatcher()) {
doc.addEventListener('keydown', (ev) => {
if (ev.key === 'Escape') {
const lastOverlay = getPresentedOverlay(doc);
if (lastOverlay === null || lastOverlay === void 0 ? void 0 : lastOverlay.backdropDismiss) {
lastOverlay.dismiss(undefined, BACKDROP);
}
}
});
}
}
};
const dismissOverlay = (doc, data, role, overlayTag, id) => {
const overlay = getPresentedOverlay(doc, overlayTag, id);
if (!overlay) {
return Promise.reject('overlay does not exist');
}
return overlay.dismiss(data, role);
};
/**
* Returns a list of all overlays in the DOM even if they are not presented.
*/
const getOverlays = (doc, selector) => {
if (selector === undefined) {
selector = 'ion-alert,ion-action-sheet,ion-loading,ion-modal,ion-picker-legacy,ion-popover,ion-toast';
}
return Array.from(doc.querySelectorAll(selector)).filter((c) => c.overlayIndex > 0);
};
/**
* Returns a list of all presented overlays.
* Inline overlays can exist in the DOM but not be presented,
* so there are times when we want to exclude those.
* @param doc The document to find the element within.
* @param overlayTag The selector for the overlay, defaults to Ionic overlay components.
*/
const getPresentedOverlays = (doc, overlayTag) => {
return getOverlays(doc, overlayTag).filter((o) => !isOverlayHidden(o));
};
/**
* Returns a presented overlay element.
* @param doc The document to find the element within.
* @param overlayTag The selector for the overlay, defaults to Ionic overlay components.
* @param id The unique identifier for the overlay instance.
* @returns The overlay element or `undefined` if no overlay element is found.
*/
const getPresentedOverlay = (doc, overlayTag, id) => {
const overlays = getPresentedOverlays(doc, overlayTag);
return id === undefined ? overlays[overlays.length - 1] : overlays.find((o) => o.id === id);
};
/**
* When an overlay is presented, the main
* focus is the overlay not the page content.
* We need to remove the page content from the
* accessibility tree otherwise when
* users use "read screen from top" gestures with
* TalkBack and VoiceOver, the screen reader will begin
* to read the content underneath the overlay.
*
* We need a container where all page components
* exist that is separate from where the overlays
* are added in the DOM. For most apps, this element
* is the top most ion-router-outlet. In the event
* that devs are not using a router,
* they will need to add the "ion-view-container-root"
* id to the element that contains all of their views.
*
* TODO: If Framework supports having multiple top
* level router outlets we would need to update this.
* Example: One outlet for side menu and one outlet
* for main content.
*/
const setRootAriaHidden = (hidden = false) => {
const root = getAppRoot(document);
const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root');
if (!viewContainer) {
return;
}
if (hidden) {
viewContainer.setAttribute('aria-hidden', 'true');
}
else {
viewContainer.removeAttribute('aria-hidden');
}
};
const present = async (overlay, name, iosEnterAnimation, mdEnterAnimation, opts) => {
var _a, _b;
if (overlay.presented) {
return;
}
/**
* When an overlay that steals focus
* is dismissed, focus should be returned
* to the element that was focused
* prior to the overlay opening. Toast
* does not steal focus and is excluded
* from returning focus as a result.
*/
if (overlay.el.tagName !== 'ION-TOAST') {
restoreElementFocus(overlay.el);
}
/**
* Due to accessibility guidelines, toasts do not have
* focus traps.
*
* All other overlays should have focus traps to prevent
* the keyboard focus from leaving the overlay unless
* developers explicitly opt out (for example, sheet
* modals that should permit background interaction).
*
* Note: Some apps move inline overlays to a specific container
* during the willPresent lifecycle (e.g., React portals via
* onWillPresent). Defer applying aria-hidden/inert to the app
* root until after willPresent so we can detect where the
* overlay is finally inserted. If the overlay is inside the
* view container subtree, skip adding aria-hidden/inert there
* to avoid disabling the overlay.
*/
const overlayEl = overlay.el;
const shouldTrapFocus = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false;
// Only lock out root content when backdrop is active. Developers relying on showBackdrop=false
// expect background interaction to remain enabled.
const shouldLockRoot = shouldTrapFocus && overlayEl.showBackdrop !== false;
overlay.presented = true;
overlay.willPresent.emit();
if (shouldLockRoot) {
const root = getAppRoot(document);
const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root');
const overlayInsideViewContainer = viewContainer ? viewContainer.contains(overlayEl) : false;
if (!overlayInsideViewContainer) {
setRootAriaHidden(true);
}
document.body.classList.add(BACKDROP_NO_SCROLL);
}
(_a = overlay.willPresentShorthand) === null || _a === void 0 ? void 0 : _a.emit();
const mode = getIonMode$1(overlay);
// get the user's animation fn if one was provided
const animationBuilder = overlay.enterAnimation
? overlay.enterAnimation
: config.get(name, mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
const completed = await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
if (completed) {
overlay.didPresent.emit();
(_b = overlay.didPresentShorthand) === null || _b === void 0 ? void 0 : _b.emit();
}
/**
* If the focused element is already
* inside the overlay component then
* focus should not be moved from that
* to the overlay container.
*/
if (overlay.keyboardClose && (document.activeElement === null || !overlay.el.contains(document.activeElement))) {
overlay.el.focus();
}
/**
* If this overlay was previously dismissed without being
* the topmost one (such as by manually calling dismiss()),
* it would still have aria-hidden on being presented again.
* Removing it here ensures the overlay is visible to screen
* readers.
*
* If this overlay was being presented, then it was hidden
* from screen readers during the animation. Now that the
* animation is complete, we can reveal the overlay to
* screen readers.
*/
overlay.el.removeAttribute('aria-hidden');
overlay.el.removeAttribute('inert');
};
/**
* When an overlay component is dismissed,
* focus should be returned to the element
* that presented the overlay. Otherwise
* focus will be set on the body which
* means that people using screen readers
* or tabbing will need to re-navigate
* to where they were before they
* opened the overlay.
*/
const restoreElementFocus = async (overlayEl) => {
let previousElement = document.activeElement;
if (!previousElement) {
return;
}
// Ensure active element is blurred to prevent a11y warning issues
previousElement.blur();
const shadowRoot = previousElement === null || previousElement === void 0 ? void 0 : previousElement.shadowRoot;
if (shadowRoot) {
// If there are no inner focusable elements, just focus the host element.
previousElement = shadowRoot.querySelector(focusableQueryString) || previousElement;
}
await overlayEl.onDidDismiss();
/**
* After onDidDismiss, the overlay loses focus
* because it is removed from the document
*
* > An element will also lose focus [...]
* > if the element is removed from the document)
*
* https://developer.mozilla.org/en-US/docs/Web/API/Element/blur_event
*
* Additionally, `document.activeElement` returns:
*
* > The Element which currently has focus,
* > `<body>` or null if there is
* > no focused element.
*
* https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement#value
*
* However, if the user has already focused
* an element sometime between onWillDismiss
* and onDidDismiss (for example, focusing a
* text box after tapping a button in an
* action sheet) then don't restore focus to
* previous element
*/
if (document.activeElement === null || document.activeElement === document.body) {
previousElement.focus();
}
};
const dismiss = async (overlay, data, role, name, iosLeaveAnimation, mdLeaveAnimation, opts) => {
var _a, _b;
if (!overlay.presented) {
return false;
}
const presentedOverlays = doc !== undefined ? getPresentedOverlays(doc) : [];
/**
* For accessibility, toasts lack focus traps and don't receive
* `aria-hidden` on the root element when presented.
*
* Overlays that opt into focus trapping set `aria-hidden`
* on the root element to keep keyboard focus and pointer
* events inside the overlay. We must remove `aria-hidden`
* from the root element when the last focus-trapping overlay
* is dismissed.
*/
const overlaysLockingRoot = presentedOverlays.filter((o) => {
const el = o;
return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && el.showBackdrop !== false;
});
const overlayEl = overlay.el;
const locksRoot = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && overlayEl.showBackdrop !== false;
/**
* If this is the last visible overlay that is trapping focus
* then we want to re-add the root to the accessibility tree.
*/
const lastOverlayTrappingFocus = locksRoot && overlaysLockingRoot.length === 1 && overlaysLockingRoot[0].id === overlayEl.id;
if (lastOverlayTrappingFocus) {
setRootAriaHidden(false);
document.body.classList.remove(BACKDROP_NO_SCROLL);
}
overlay.presented = false;
try {
// Overlay contents should not be clickable during dismiss
overlay.el.style.setProperty('pointer-events', 'none');
overlay.willDismiss.emit({ data, role });
(_a = overlay.willDismissShorthand) === null || _a === void 0 ? void 0 : _a.emit({ data, role });
const mode = getIonMode$1(overlay);
const animationBuilder = overlay.leaveAnimation
? overlay.leaveAnimation
: config.get(name, mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
// If dismissed via gesture, no need to play leaving animation again
if (role !== GESTURE) {
await overlayAnimation(overlay, animationBuilder, overlay.el, opts);
}
overlay.didDismiss.emit({ data, role });
(_b = overlay.didDismissShorthand) === null || _b === void 0 ? void 0 : _b.emit({ data, role });
// Get a reference to all animations currently assigned to this overlay
// Then tear them down to return the overlay to its initial visual state
const animations = activeAnimations.get(overlay) || [];
animations.forEach((ani) => ani.destroy());
activeAnimations.delete(overlay);
/**
* Make overlay hidden again in case it is being reused.
* We can safely remove pointer-events: none as
* overlay-hidden will set display: none.
*/
overlay.el.classList.add('overlay-hidden');
overlay.el.style.removeProperty('pointer-events');
/**
* Clear any focus trapping references
* when the overlay is dismissed.
*/
if (overlay.el.lastFocus !== undefined) {
overlay.el.lastFocus = undefined;
}
}
catch (err) {
printIonError(`[${overlay.el.tagName.toLowerCase()}] - `, err);
}
overlay.el.remove();
return true;
};
const getAppRoot = (doc) => {
return doc.querySelector('ion-app') || doc.body;
};
const overlayAnimation = async (overlay, animationBuilder, baseEl, opts) => {
// Make overlay visible in case it's hidden
baseEl.classList.remove('overlay-hidden');
const aniRoot = overlay.el;
const animation = animationBuilder(aniRoot, opts);
if (!overlay.animated || !config.getBoolean('animated', true)) {
animation.duration(0);
}
if (overlay.keyboardClose) {
animation.beforeAddWrite(() => {
const activeElement = baseEl.ownerDocument.activeElement;
if (activeElement === null || activeElement === void 0 ? void 0 : activeElement.matches('input,ion-input, ion-textarea')) {
activeElement.blur();
}
});
}
const activeAni = activeAnimations.get(overlay) || [];
activeAnimations.set(overlay, [...activeAni, animation]);
await animation.play();
return true;
};
const eventMethod = (element, eventName) => {
let resolve;
const promise = new Promise((r) => (resolve = r));
onceEvent(element, eventName, (event) => {
resolve(event.detail);
});
return promise;
};
const onceEvent = (element, eventName, callback) => {
const handler = (ev) => {
removeEventListener(element, eventName, handler);
callback(ev);
};
addEventListener$1(element, eventName, handler);
};
const isCancel = (role) => {
return role === 'cancel' || role === BACKDROP;
};
const defaultGate = (h) => h();
/**
* Calls a developer provided method while avoiding
* Angular Zones. Since the handler is provided by
* the developer, we should throw any errors
* received so that developer-provided bug
* tracking software can log it.
*/
const safeCall = (handler, arg) => {
if (typeof handler === 'function') {
const jmp = config.get('_zoneGate', defaultGate);
return jmp(() => {
try {
return handler(arg);
}
catch (e) {
throw e;
}
});
}
return undefined;
};
const BACKDROP = 'backdrop';
const GESTURE = 'gesture';
const OVERLAY_GESTURE_PRIORITY = 39;
/**
* Creates a delegate controller.
*
* Requires that the component has the following properties:
* - `el: HTMLElement`
* - `hasController: boolean`
* - `delegate?: FrameworkDelegate`
*
* @param ref The component class instance.
*/
const createDelegateController = (ref) => {
let inline = false;
let workingDelegate;
const coreDelegate = CoreDelegate();
/**
* Determines whether or not an overlay is being used
* inline or via a controller/JS and returns the correct delegate.
* By default, subsequent calls to getDelegate will use
* a cached version of the delegate.
* This is useful for calling dismiss after present,
* so that the correct delegate is given.
* @param force `true` to force the non-cached version of the delegate.
* @returns The delegate to use and whether or not the overlay is inline.
*/
const getDelegate = (force = false) => {
if (workingDelegate && !force) {
return {
delegate: workingDelegate,
inline,
};
}
const { el, hasController, delegate } = ref;
/**
* If using overlay inline
* we potentially need to use the coreDelegate
* so that this works in vanilla JS apps.
* If a developer has presented this component
* via a controller, then we can assume
* the component is already in the
* correct place.
*/
const parentEl = el.parentNode;
inline = parentEl !== null && !hasController;
workingDelegate = inline ? delegate || coreDelegate : delegate;
return { inline, delegate: workingDelegate };
};
/**
* Attaches a component in the DOM. Teleports the component
* to the root of the app.
* @param component The component to optionally construct and append to the element.
*/
const attachViewToDom = async (component) => {
const { delegate } = getDelegate(true);
if (delegate) {
return await delegate.attachViewToDom(ref.el, component);
}
const { hasController } = ref;
if (hasController && component !== undefined) {
throw new Error('framework delegate is missing');
}
return null;
};
/**
* Moves a component back to its original location in the DOM.
*/
const removeViewFromDom = () => {
const { delegate } = getDelegate();
if (delegate && ref.el !== undefined) {
delegate.removeViewFromDom(ref.el.parentElement, ref.el);
}
};
return {
attachViewToDom,
removeViewFromDom,
};
};
/**
* Constructs a trigger interaction for an overlay.
* Presents an overlay when the trigger is clicked.
*
* Usage:
* ```ts
* triggerController = createTriggerController();
* triggerController.addClickListener(el, trigger);
* ```
*/
const createTriggerController = () => {
let destroyTriggerInteraction;
/**
* Removes the click listener from the trigger element.
*/
const removeClickListener = () => {
if (destroyTriggerInteraction) {
destroyTriggerInteraction();
destroyTriggerInteraction = undefined;
}
};
/**
* Adds a click listener to the trigger element.
* Presents the overlay when the trigger is clicked.
* @param el The overlay element.
* @param trigger The ID of the element to add a click listener to.
*/
const addClickListener = (el, trigger) => {
removeClickListener();
const triggerEl = trigger !== undefined ? document.getElementById(trigger) : null;
if (!triggerEl) {
printIonWarning(`[${el.tagName.toLowerCase()}] - A trigger element with the ID "${trigger}" was not found in the DOM. The trigger element must be in the DOM when the "trigger" property is set on an overlay component.`, el);
return;
}
const configureTriggerInteraction = (targetEl, overlayEl) => {
const openOverlay = () => {
overlayEl.present();
};
targetEl.addEventListener('click', openOverlay);
return () => {
targetEl.removeEventListener('click', openOverlay);
};
};
destroyTriggerInteraction = configureTriggerInteraction(triggerEl, el);
};
return {
addClickListener,
removeClickListener,
};
};
const FOCUS_TRAP_DISABLE_CLASS = 'ion-disable-focus-trap';
const hostContext = (selector, el) => {
return el.closest(selector) !== null;
};
/**
* Create the mode and color classes for the component based on the classes passed in
*/
const createColorClasses$1 = (color, cssClassMap) => {
return typeof color === 'string' && color.length > 0
? Object.assign({ 'ion-color': true, [`ion-color-${color}`]: true }, cssClassMap) : cssClassMap;
};
const getClassList = (classes) => {
if (classes !== undefined) {
const array = Array.isArray(classes) ? classes : classes.split(' ');
return array
.filter((c) => c != null)
.map((c) => c.trim())
.filter((c) => c !== '');
}
return [];
};
const getClassMap = (classes) => {
const map = {};
getClassList(classes).forEach((c) => (map[c] = true));
return map;
};
const SCHEME = /^[a-z][a-z0-9+\-.]*:/;
const openURL = async (url, ev, direction, animation) => {
if (url != null && url[0] !== '#' && !SCHEME.test(url)) {
const router = document.querySelector('ion-router');
if (router) {
if (ev != null) {
ev.preventDefault();
}
return router.push(url, direction, animation);
}
}
return false;
};
let animationPrefix;
const getAnimationPrefix = (el) => {
if (animationPrefix === undefined) {
const supportsUnprefixed = el.style.animationName !== undefined;
const supportsWebkitPrefix = el.style.webkitAnimationName !== undefined;
animationPrefix = !supportsUnprefixed && supportsWebkitPrefix ? '-webkit-' : '';
}
return animationPrefix;
};
const setStyleProperty = (element, propertyName, value) => {
const prefix = propertyName.startsWith('animation') ? getAnimationPrefix(element) : '';
element.style.setProperty(prefix + propertyName, value);
};
const addClassToArray = (classes = [], className) => {
if (className !== undefined) {
const classNameToAppend = Array.isArray(className) ? className : [className];
return [...classes, ...classNameToAppend];
}
return classes;
};
const createAnimation = (animationId) => {
let _delay;
let _duration;
let _easing;
let _iterations;
let _fill;
let _direction;
let _keyframes = [];
let beforeAddClasses = [];
let beforeRemoveClasses = [];
let initialized = false;
let parentAnimation;
let beforeStylesValue = {};
let afterAddClasses = [];
let afterRemoveClasses = [];
let afterStylesValue = {};
let numAnimationsRunning = 0;
let shouldForceLinearEasing = false;
let shouldForceSyncPlayback = false;
let forceDirectionValue;
let forceDurationValue;
let forceDelayValue;
let willComplete = true;
let finished = false;
let shouldCalculateNumAnimations = true;
let ani;
let paused = false;
const id = animationId;
const onFinishCallbacks = [];
const onFinishOneTimeCallbacks = [];
const onStopOneTimeCallbacks = [];
const elements = [];
const childAnimations = [];
const stylesheets = [];
const _beforeAddReadFunctions = [];
const _beforeAddWriteFunctions = [];
const _afterAddReadFunctions = [];
const _afterAddWriteFunctions = [];
const webAnimations = [];
const supportsAnimationEffect = typeof AnimationEffect === 'function' ||
(win$1 !== undefined && typeof win$1.AnimationEffect === 'function');
/**
* This is a feature detection for Web Animations.
*
* Certain environments such as emulated browser environments for testing,
* do not support Web Animations. As a result, we need to check for support
* and provide a fallback to test certain functionality related to Web Animations.
*/
const supportsWebAnimations = typeof Element === 'function' &&
typeof Element.prototype.animate === 'function' &&
supportsAnimationEffect;
const getWebAnimations = () => {
return webAnimations;
};
const destroy = (clearStyleSheets) => {
childAnimations.forEach((childAnimation) => {
childAnimation.destroy(clearStyleSheets);
});
cleanUp(clearStyleSheets);
elements.length = 0;
childAnimations.length = 0;
_keyframes.length = 0;
clearOnFinish();
initialized = false;
shouldCalculateNumAnimations = true;
return ani;
};
/**
* Cancels any Web Animations, removes
* any animation properties from the
* animation's elements, and removes the
* animation's stylesheets from the DOM.
*/
const cleanUp = (clearStyleSheets) => {
cleanUpElements();
if (clearStyleSheets) {
cleanUpStyleSheets();
}
};
const resetFlags = () => {
shouldForceLinearEasing = false;
shouldForceSyncPlayback = false;
shouldCalculateNumAnimations = true;
forceDirectionValue = undefined;
forceDurationValue = undefined;
forceDelayValue = undefined;
numAnimationsRunning = 0;
finished = false;
willComplete = true;
paused = false;
};
const isRunning = () => {
return numAnimationsRunning !== 0 && !paused;
};
/**
* @internal
* Remove a callback from a chosen callback array
* @param callbackToRemove: A reference to the callback that should be removed
* @param callbackObjects: An array of callbacks that callbackToRemove should be removed from.
*/
const clearCallback = (callbackToRemove, callbackObjects) => {
const index = callbackObjects.findIndex((callbackObject) => callbackObject.c === callbackToRemove);
if (index > -1) {
callbackObjects.splice(index, 1);
}
};
/**
* @internal
* Add a callback to be fired when an animation is stopped/cancelled.
* @param callback: A reference to the callback that should be fired
* @param opts: Any options associated with this particular callback
*/
const onStop = (callback, opts) => {
onStopOneTimeCallbacks.push({ c: callback, o: opts });
return ani;
};
const onFinish = (callback, opts) => {
const callbacks = (opts === null || opts === void 0 ? void 0 : opts.oneTimeCallback) ? onFinishOneTimeCallbacks : onFinishCallbacks;
callbacks.push({ c: callback, o: opts });
return ani;
};
const clearOnFinish = () => {
onFinishCallbacks.length = 0;
onFinishOneTimeCallbacks.length = 0;
return ani;
};
/**
* Cancels any Web Animations and removes
* any animation properties from the
* the animation's elements.
*/
const cleanUpElements = () => {
if (supportsWebAnimations) {
webAnimations.forEach((animation) => {
animation.cancel();
});
webAnimations.length = 0;
}
};
/**
* Removes the animation's stylesheets
* from the DOM.
*/
const cleanUpStyleSheets = () => {
stylesheets.forEach((stylesheet) => {
/**
* When sharing stylesheets, it's possible
* for another animation to have already
* cleaned up a particular stylesheet
*/
if (stylesheet === null || stylesheet === void 0 ? void 0 : stylesheet.parentNode) {
stylesheet.parentNode.removeChild(stylesheet);
}
});
stylesheets.length = 0;
};
const beforeAddRead = (readFn) => {
_beforeAddReadFunctions.push(readFn);
return ani;
};
const beforeAddWrite = (writeFn) => {
_beforeAddWriteFunctions.push(writeFn);
return ani;
};
const afterAddRead = (readFn) => {
_afterAddReadFunctions.push(readFn);
return ani;
};
const afterAddWrite = (writeFn) => {
_afterAddWriteFunctions.push(writeFn);
return ani;
};
const beforeAddClass = (className) => {
beforeAddClasses = addClassToArray(beforeAddClasses, className);
return ani;
};
const beforeRemoveClass = (className) => {
beforeRemoveClasses = addClassToArray(beforeRemoveClasses, className);
return ani;
};
/**
* Set CSS inline styles to the animation's
* elements before the animation begins.
*/
const beforeStyles = (styles = {}) => {
beforeStylesValue = styles;
return ani;
};
/**
* Clear CSS inline styles from the animation's
* elements before the animation begins.
*/
const beforeClearStyles = (propertyNames = []) => {
for (const property of propertyNames) {
beforeStylesValue[property] = '';
}
return ani;
};
const afterAddClass = (className) => {
afterAddClasses = addClassToArray(afterAddClasses, className);
return ani;
};
const afterRemoveClass = (className) => {
afterRemoveClasses = addClassToArray(afterRemoveClasses, className);
return ani;
};
const afterStyles = (styles = {}) => {
afterStylesValue = styles;
return ani;
};
const afterClearStyles = (propertyNames = []) => {
for (const property of propertyNames) {
afterStylesValue[property] = '';
}
return ani;
};
const getFill = () => {
if (_fill !== undefined) {
return _fill;
}
if (parentAnimation) {
return parentAnimation.getFill();
}
return 'both';
};
const getDirection = () => {
if (forceDirectionValue !== undefined) {
return forceDirectionValue;
}
if (_direction !== undefined) {
return _direction;
}
if (parentAnimation) {
return parentAnimation.getDirection();
}
return 'normal';
};
const getEasing = () => {
if (shouldForceLinearEasing) {
return 'linear';
}
if (_easing !== undefined) {
return _easing;
}
if (parentAnimation) {
return parentAnimation.getEasing();
}
return 'linear';
};
const getDuration = () => {
if (shouldForceSyncPlayback) {
return 0;
}
if (forceDurationValue !== undefined) {
return forceDurationValue;
}
if (_duration !== undefined) {
return _duration;
}
if (parentAnimation) {
return parentAnimation.getDuration();
}
return 0;
};
const getIterations = () => {
if (_iterations !== undefined) {
return _iterations;
}
if (parentAnimation) {
return parentAnimation.getIterations();
}
return 1;
};
const getDelay = () => {
if (forceDelayValue !== undefined) {
return forceDelayValue;
}
if (_delay !== undefined) {
return _delay;
}
if (parentAnimation) {
return parentAnimation.getDelay();
}
return 0;
};
const getKeyframes = () => {
return _keyframes;
};
const direction = (animationDirection) => {
_direction = animationDirection;
update(true);
return ani;
};
const fill = (animationFill) => {
_fill = animationFill;
update(true);
return ani;
};
const delay = (animationDelay) => {
_delay = animationDelay;
update(true);
return ani;
};
const easing = (animationEasing) => {
_easing = animationEasing;
update(true);
return ani;
};
const duration = (animationDuration) => {
/**
* CSS Animation Durations of 0ms work fine on Chrome
* but do not run on Safari, so force it to 1ms to
* get it to run on both platforms.
*/
if (!supportsWebAnimations && animationDuration === 0) {
animationDuration = 1;
}
_duration = animationDuration;
update(true);
return ani;
};
const iterations = (animationIterations) => {
_iterations = animationIterations;
update(true);
return ani;
};
const parent = (animation) => {
parentAnimation = animation;
return ani;
};
const addElement = (el) => {
if (el != null) {
if (el.nodeType === 1) {
elements.push(el);
}
else if (el.length >= 0) {
for (let i = 0; i < el.length; i++) {
elements.push(el[i]);
}
}
else {
printIonError('createAnimation - Invalid addElement value.');
}
}
return ani;
};
const addAnimation = (animationToAdd) => {
if (animationToAdd != null) {
if (Array.isArray(animationToAdd)) {
for (const animation of animationToAdd) {
animation.parent(ani);
childAnimations.push(animation);
}
}
else {
animationToAdd.parent(ani);
childAnimations.push(animationToAdd);
}
}
return ani;
};
const keyframes = (keyframeValues) => {
const different = _keyframes !== keyframeValues;
_keyframes = keyframeValues;
if (different) {
updateKeyframes(_keyframes);
}
return ani;
};
const updateKeyframes = (keyframeValues) => {
if (supportsWebAnimations) {
getWebAnimations().forEach((animation) => {
/**
* animation.effect's type is AnimationEffect.
* However, in this case we have a more specific
* type of AnimationEffect called KeyframeEffect which
* inherits from AnimationEffect. As a result,
* we cast animation.effect to KeyframeEffect.
*/
const keyframeEffect = animation.effect;
/**
* setKeyframes is not supported in all browser
* versions that Ionic supports, so we need to
* check for support before using it.
*/
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (keyframeEffect.setKeyframes) {
keyframeEffect.setKeyframes(keyframeValues);
}
else {
const newEffect = new KeyframeEffect(keyframeEffect.target, keyframeValues, keyframeEffect.getTiming());
animation.effect = newEffect;
}
});
}
};
/**
* Run all "before" animation hooks.
*/
const beforeAnimation = () => {
// Runs all before read callbacks
_beforeAddReadFunctions.forEach((callback) => callback());
// Runs all before write callbacks
_beforeAddWriteFunctions.forEach((callback) => callback());
// Updates styles and classes before animation runs
const addClasses = beforeAddClasses;
const removeClasses = beforeRemoveClasses;
const styles = beforeStylesValue;
elements.forEach((el) => {
const elementClassList = el.classList;
addClasses.forEach((c) => elementClassList.add(c));
removeClasses.forEach((c) => elementClassList.remove(c));
for (const property in styles) {
// eslint-disable-next-line no-prototype-builtins
if (styles.hasOwnProperty(property)) {
setStyleProperty(el, property, styles[property]);
}
}
});
};
/**
* Run all "after" animation hooks.
*/
const afterAnimation = () => {
// Runs all after read callbacks
_afterAddReadFunctions.forEach((callback) => callback());
// Runs all after write callbacks
_afterAddWriteFunctions.forEach((callback) => callback());
// Updates styles and classes before animation ends
const currentStep = willComplete ? 1 : 0;
const addClasses = afterAddClasses;
const removeClasses = afterRemoveClasses;
const styles = afterStylesValue;
elements.forEach((el) => {
const elementClassList = el.classList;
addClasses.forEach((c) => elementClassList.add(c));
removeClasses.forEach((c) => elementClassList.remove(c));
for (const property in styles) {
// eslint-disable-next-line no-prototype-builtins
if (styles.hasOwnProperty(property)) {
setStyleProperty(el, property, styles[property]);
}
}
});
/**
* Clean up any value coercion before
* the user callbacks fire otherwise
* they may get stale values. For example,
* if someone calls progressStart(0) the
* animation may still be reversed.
*/
forceDurationValue = undefined;
forceDirectionValue = undefined;
forceDelayValue = undefined;
onFinishCallbacks.forEach((onFinishCallback) => {
return onFinishCallback.c(currentStep, ani);
});
onFinishOneTimeCallbacks.forEach((onFinishCallback) => {
return onFinishCallback.c(currentStep, ani);
});
onFinishOneTimeCallbacks.length = 0;
shouldCalculateNumAnimations = true;
if (willComplete) {
finished = true;
}
willComplete = true;
};
const animationFinish = () => {
if (numAnimationsRunning === 0) {
return;
}
numAnimationsRunning--;
if (numAnimationsRunning === 0) {
afterAnimation();
if (parentAnimation) {
parentAnimation.animationFinish();
}
}
};
const initializeWebAnimation = () => {
elements.forEach((element) => {
const animation = element.animate(_keyframes, {
id,
delay: getDelay(),
duration: getDuration(),
easing: getEasing(),
iterations: getIterations(),
fill: getFill(),
direction: getDirection(),
});
animation.pause();
webAnimations.push(animation);
});
if (webAnimations.length > 0) {
webAnimations[0].onfinish = () => {
animationFinish();
};
}
};
const initializeAnimation = () => {
beforeAnimation();
if (_keyframes.length > 0) {
if (supportsWebAnimations) {
initializeWebAnimation();
}
}
initialized = true;
};
const setAnimationStep = (step) => {
step = Math.min(Math.max(step, 0), 0.9999);
if (supportsWebAnimations) {
webAnimations.forEach((animation) => {
// When creating the animation the delay is guaranteed to be set to a number.
animation.currentTime = animation.effect.getComputedTiming().delay + getDuration() * step;
animation.pause();
});
}
};
const updateWebAnimation = (step) => {
webAnimations.forEach((animation) => {
animation.effect.updateTiming({
delay: getDelay(),
duration: getDuration(),
easing: getEasing(),
iterations: getIterations(),
fill: getFill(),
direction: getDirection(),
});
});
if (step !== undefined) {
setAnimationStep(step);
}
};
const update = (deep = false, toggleAnimationName = true, step) => {
if (deep) {
childAnimations.forEach((animation) => {
animation.update(deep, toggleAnimationName, step);
});
}
if (supportsWebAnimations) {
updateWebAnimation(step);
}
return ani;
};
const progressStart = (forceLinearEasing = false, step) => {
childAnimations.forEach((animation) => {
animation.progressStart(forceLinearEasing, step);
});
pauseAnimation();
shouldForceLinearEasing = forceLinearEasing;
if (!initialized) {
initializeAnimation();
}
update(false, true, step);
return ani;
};
const progressStep = (step) => {
childAnimations.forEach((animation) => {
animation.progressStep(step);
});
setAnimationStep(step);
return ani;
};
const progressEnd = (playTo, step, dur) => {
shouldForceLinearEasing = false;
childAnimations.forEach((animation) => {
animation.progressEnd(playTo, step, dur);
});
if (dur !== undefined) {
forceDurationValue = dur;
}
finished = false;
willComplete = true;
if (playTo === 0) {
forceDirectionValue = getDirection() === 'reverse' ? 'normal' : 'reverse';
if (forceDirectionValue === 'reverse') {
willComplete = false;
}
if (supportsWebAnimations) {
update();
setAnimationStep(1 - step);
}
else {
forceDelayValue = (1 - step) * getDuration() * -1;
update(false, false);
}
}
else if (playTo === 1) {
if (supportsWebAnimations) {
update();
setAnimationStep(step);
}
else {
forceDelayValue = step * getDuration() * -1;
update(false, false);
}
}
if (playTo !== undefined && !parentAnimation) {
play();
}
return ani;
};
const pauseAnimation = () => {
if (initialized) {
if (supportsWebAnimations) {
webAnimations.forEach((animation) => {
animation.pause();
});
}
else {
elements.forEach((element) => {
setStyleProperty(element, 'animation-play-state', 'paused');
});
}
paused = true;
}
};
const pause = () => {
childAnimations.forEach((animation) => {
animation.pause();
});
pauseAnimation();
return ani;
};
const playCSSAnimations = () => {
animationFinish();
};
const playWebAnimations = () => {
webAnimations.forEach((animation) => {
animation.play();
});
if (_keyframes.length === 0 || elements.length === 0) {
animationFinish();
}
};
const resetAnimation = () => {
if (supportsWebAnimations) {
setAnimationStep(0);
updateWebAnimation();
}
};
const play = (opts) => {
return new Promise((resolve) => {
if (opts === null || opts === void 0 ? void 0 : opts.sync) {
shouldForceSyncPlayback = true;
onFinish(() => (shouldForceSyncPlayback = false), { oneTimeCallback: true });
}
if (!initialized) {
initializeAnimation();
}
if (finished) {
resetAnimation();
finished = false;
}
if (shouldCalculateNumAnimations) {
numAnimationsRunning = childAnimations.length + 1;
shouldCalculateNumAnimations = false;
}
/**
* When one of these callbacks fires we
* need to clear the other's callback otherwise
* you can potentially get these callbacks
* firing multiple times if the play method
* is subsequently called.
* Example:
* animation.play() (onStop and onFinish callbacks are registered)
* animation.stop() (onStop callback is fired, onFinish is not)
* animation.play() (onStop and onFinish callbacks are registered)
* Total onStop callbacks: 1
* Total onFinish callbacks: 2
*/
const onStopCallback = () => {
clearCallback(onFinishCallback, onFinishOneTimeCallbacks);
resolve();
};
const onFinishCallback = () => {
clearCallback(onStopCallback, onStopOneTimeCallbacks);
resolve();
};
/**
* The play method resolves when an animation
* run either finishes or is cancelled.
*/
onFinish(onFinishCallback, { oneTimeCallback: true });
onStop(onStopCallback, { oneTimeCallback: true });
childAnimations.forEach((animation) => {
animation.play();
});
if (supportsWebAnimations) {
playWebAnimations();
}
else {
playCSSAnimations();
}
paused = false;
});
};
/**
* Stops an animation and resets it state to the
* beginning. This does not fire any onFinish
* callbacks because the animation did not finish.
* However, since the animation was not destroyed
* (i.e. the animation could run again) we do not
* clear the onFinish callbacks.
*/
const stop = () => {
childAnimations.forEach((animation) => {
animation.stop();
});
if (initialized) {
cleanUpElements();
initialized = false;
}
resetFlags();
onStopOneTimeCallbacks.forEach((onStopCallback) => onStopCallback.c(0, ani));
onStopOneTimeCallbacks.length = 0;
};
const from = (property, value) => {
const firstFrame = _keyframes[0];
if (firstFrame !== undefined && (firstFrame.offset === undefined || firstFrame.offset === 0)) {
firstFrame[property] = value;
}
else {
_keyframes = [{ offset: 0, [property]: value }, ..._keyframes];
}
return ani;
};
const to = (property, value) => {
const lastFrame = _keyframes[_keyframes.length - 1];
if (lastFrame !== undefined && (lastFrame.offset === undefined || lastFrame.offset === 1)) {
lastFrame[property] = value;
}
else {
_keyframes = [..._keyframes, { offset: 1, [property]: value }];
}
return ani;
};
const fromTo = (property, fromValue, toValue) => {
return from(property, fromValue).to(property, toValue);
};
return (ani = {
parentAnimation,
elements,
childAnimations,
id,
animationFinish,
from,
to,
fromTo,
parent,
play,
pause,
stop,
destroy,
keyframes,
addAnimation,
addElement,
update,
fill,
direction,
iterations,
duration,
easing,
delay,
getWebAnimations,
getKeyframes,
getFill,
getDirection,
getDelay,
getIterations,
getEasing,
getDuration,
afterAddRead,
afterAddWrite,
afterClearStyles,
afterStyles,
afterRemoveClass,
afterAddClass,
beforeAddRead,
beforeAddWrite,
beforeClearStyles,
beforeStyles,
beforeRemoveClass,
beforeAddClass,
onFinish,
isRunning,
progressStart,
progressStep,
progressEnd,
});
};
/**
* iOS Action Sheet Enter Animation
*/
const iosEnterAnimation$6 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.action-sheet-wrapper'))
.fromTo('transform', 'translateY(100%)', 'translateY(0%)');
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(.36,.66,.04,1)')
.duration(400)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* iOS Action Sheet Leave Animation
*/
const iosLeaveAnimation$6 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(baseEl.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation
.addElement(baseEl.querySelector('.action-sheet-wrapper'))
.fromTo('transform', 'translateY(0%)', 'translateY(100%)');
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(.36,.66,.04,1)')
.duration(450)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* MD Action Sheet Enter Animation
*/
const mdEnterAnimation$5 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.action-sheet-wrapper'))
.fromTo('transform', 'translateY(100%)', 'translateY(0%)');
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(.36,.66,.04,1)')
.duration(400)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* MD Action Sheet Leave Animation
*/
const mdLeaveAnimation$5 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(baseEl.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation
.addElement(baseEl.querySelector('.action-sheet-wrapper'))
.fromTo('transform', 'translateY(0%)', 'translateY(100%)');
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(.36,.66,.04,1)')
.duration(450)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
const actionSheetIosCss = ".sc-ion-action-sheet-ios-h{--color:initial;--button-color-activated:var(--button-color);--button-color-focused:var(--button-color);--button-color-hover:var(--button-color);--button-color-selected:var(--button-color);--min-width:auto;--width:100%;--max-width:500px;--min-height:auto;--height:auto;--max-height:calc(100% - (var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;left:0;right:0;top:0;bottom:0;display:block;position:fixed;outline:none;font-family:var(--ion-font-family, inherit);-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.overlay-hidden.sc-ion-action-sheet-ios-h{display:none}.action-sheet-wrapper.sc-ion-action-sheet-ios{left:0;right:0;bottom:0;-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);display:block;position:absolute;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);z-index:10;pointer-events:none}.action-sheet-button.sc-ion-action-sheet-ios{display:block;position:relative;width:100%;border:0;outline:none;background:var(--button-background);color:var(--button-color);font-family:inherit;overflow:hidden}.action-sheet-button.sc-ion-action-sheet-ios:disabled{color:var(--button-color-disabled);opacity:0.4}.action-sheet-button-inner.sc-ion-action-sheet-ios{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;pointer-events:none;width:100%;height:100%;z-index:1}.action-sheet-container.sc-ion-action-sheet-ios{display:-ms-flexbox;display:flex;-ms-flex-flow:column;flex-flow:column;-ms-flex-pack:end;justify-content:flex-end;height:100%;max-height:calc(100vh - (var(--ion-safe-area-top, 0) + var(--ion-safe-area-bottom, 0)));max-height:calc(100dvh - (var(--ion-safe-area-top, 0) + var(--ion-safe-area-bottom, 0)))}.action-sheet-group.sc-ion-action-sheet-ios{-ms-flex-negative:2;flex-shrink:2;overscroll-behavior-y:contain;overflow-y:auto;-webkit-overflow-scrolling:touch;pointer-events:all;background:var(--background)}@media (any-pointer: coarse){.action-sheet-group.sc-ion-action-sheet-ios::-webkit-scrollbar{display:none}}.action-sheet-group-cancel.sc-ion-action-sheet-ios{-ms-flex-negative:0;flex-shrink:0;overflow:hidden}.action-sheet-button.sc-ion-action-sheet-ios::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.action-sheet-selected.sc-ion-action-sheet-ios{color:var(--button-color-selected)}.action-sheet-selected.sc-ion-action-sheet-ios::after{background:var(--button-background-selected);opacity:var(--button-background-selected-opacity)}.action-sheet-button.ion-activated.sc-ion-action-sheet-ios{color:var(--button-color-activated)}.action-sheet-button.ion-activated.sc-ion-action-sheet-ios::after{background:var(--button-background-activated);opacity:var(--button-background-activated-opacity)}.action-sheet-button.ion-focused.sc-ion-action-sheet-ios{color:var(--button-color-focused)}.action-sheet-button.ion-focused.sc-ion-action-sheet-ios::after{background:var(--button-background-focused);opacity:var(--button-background-focused-opacity)}@media (any-hover: hover){.action-sheet-button.sc-ion-action-sheet-ios:not(:disabled):hover{color:var(--button-color-hover)}.action-sheet-button.sc-ion-action-sheet-ios:not(:disabled):hover::after{background:var(--button-background-hover);opacity:var(--button-background-hover-opacity)}}.sc-ion-action-sheet-ios-h{--background:var(--ion-overlay-background-color, var(--ion-color-step-100, var(--ion-background-color-step-100, #f9f9f9)));--backdrop-opacity:var(--ion-backdrop-opacity, 0.4);--button-background:linear-gradient(0deg, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08), rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08) 50%, transparent 50%) bottom/100% 1px no-repeat transparent;--button-background-activated:var(--ion-text-color, #000);--button-background-activated-opacity:.08;--button-background-hover:currentColor;--button-background-hover-opacity:.04;--button-background-focused:currentColor;--button-background-focused-opacity:.12;--button-background-selected:var(--ion-color-step-150, var(--ion-background-color-step-150, var(--ion-background-color, #fff)));--button-background-selected-opacity:1;--button-color:var(--ion-color-primary, #0054e9);--button-color-disabled:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));--color:var(--ion-color-step-400, var(--ion-text-color-step-600, #999999));text-align:center}.action-sheet-wrapper.sc-ion-action-sheet-ios{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:var(--ion-safe-area-top, 0);padding-bottom:var(--ion-safe-area-bottom, 0);-webkit-box-sizing:content-box;box-sizing:content-box}.action-sheet-container.sc-ion-action-sheet-ios{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:0;padding-bottom:0}.action-sheet-group.sc-ion-action-sheet-ios{border-radius:13px;margin-bottom:8px}.action-sheet-group.sc-ion-action-sheet-ios:first-child{margin-top:10px}.action-sheet-group.sc-ion-action-sheet-ios:last-child{margin-bottom:10px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.action-sheet-translucent.sc-ion-action-sheet-ios-h .action-sheet-group.sc-ion-action-sheet-ios{background-color:transparent;-webkit-backdrop-filter:saturate(280%) blur(20px);backdrop-filter:saturate(280%) blur(20px)}.action-sheet-translucent.sc-ion-action-sheet-ios-h .action-sheet-title.sc-ion-action-sheet-ios,.action-sheet-translucent.sc-ion-action-sheet-ios-h .action-sheet-button.sc-ion-action-sheet-ios{background-color:transparent;background-image:-webkit-gradient(linear, left bottom, left top, from(rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8)), to(rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8))), -webkit-gradient(linear, left bottom, left top, from(rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.4)), color-stop(50%, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.4)), color-stop(50%, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8)));background-image:linear-gradient(0deg, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8), rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8) 100%), linear-gradient(0deg, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.4), rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.4) 50%, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8) 50%);background-repeat:no-repeat;background-position:top, bottom;background-size:100% calc(100% - 1px), 100% 1px;-webkit-backdrop-filter:saturate(120%);backdrop-filter:saturate(120%)}.action-sheet-translucent.sc-ion-action-sheet-ios-h .action-sheet-button.ion-activated.sc-ion-action-sheet-ios{background-color:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.7);background-image:none}.action-sheet-translucent.sc-ion-action-sheet-ios-h .action-sheet-cancel.sc-ion-action-sheet-ios{background:var(--button-background-selected)}}.action-sheet-title.sc-ion-action-sheet-ios{background:-webkit-gradient(linear, left bottom, left top, from(rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08)), color-stop(50%, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08)), color-stop(50%, transparent)) bottom/100% 1px no-repeat transparent;background:linear-gradient(0deg, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08), rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08) 50%, transparent 50%) bottom/100% 1px no-repeat transparent}.action-sheet-title.sc-ion-action-sheet-ios{-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px;padding-top:14px;padding-bottom:13px;color:var(--color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-size:max(13px, 0.8125rem);font-weight:400;text-align:center}.action-sheet-title.action-sheet-has-sub-title.sc-ion-action-sheet-ios{font-weight:600}.action-sheet-sub-title.sc-ion-action-sheet-ios{padding-left:0;padding-right:0;padding-top:6px;padding-bottom:0;font-size:max(13px, 0.8125rem);font-weight:400}.action-sheet-button.sc-ion-action-sheet-ios{-webkit-padding-start:14px;padding-inline-start:14px;-webkit-padding-end:14px;padding-inline-end:14px;padding-top:14px;padding-bottom:14px;min-height:56px;font-size:max(20px, 1.25rem);contain:content}.action-sheet-button.sc-ion-action-sheet-ios .action-sheet-icon.sc-ion-action-sheet-ios{-webkit-margin-end:0.3em;margin-inline-end:0.3em;font-size:max(28px, 1.75rem);pointer-events:none}.action-sheet-button.sc-ion-action-sheet-ios:last-child{background-image:none}.action-sheet-selected.sc-ion-action-sheet-ios{font-weight:bold}.action-sheet-cancel.sc-ion-action-sheet-ios{font-weight:600}.action-sheet-cancel.sc-ion-action-sheet-ios::after{background:var(--button-background-selected);opacity:var(--button-background-selected-opacity)}.action-sheet-destructive.sc-ion-action-sheet-ios,.action-sheet-destructive.ion-activated.sc-ion-action-sheet-ios,.action-sheet-destructive.ion-focused.sc-ion-action-sheet-ios{color:var(--ion-color-danger, #c5000f)}@media (any-hover: hover){.action-sheet-destructive.sc-ion-action-sheet-ios:hover{color:var(--ion-color-danger, #c5000f)}}";
const actionSheetMdCss = ".sc-ion-action-sheet-md-h{--color:initial;--button-color-activated:var(--button-color);--button-color-focused:var(--button-color);--button-color-hover:var(--button-color);--button-color-selected:var(--button-color);--min-width:auto;--width:100%;--max-width:500px;--min-height:auto;--height:auto;--max-height:calc(100% - (var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;left:0;right:0;top:0;bottom:0;display:block;position:fixed;outline:none;font-family:var(--ion-font-family, inherit);-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.overlay-hidden.sc-ion-action-sheet-md-h{display:none}.action-sheet-wrapper.sc-ion-action-sheet-md{left:0;right:0;bottom:0;-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);display:block;position:absolute;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);z-index:10;pointer-events:none}.action-sheet-button.sc-ion-action-sheet-md{display:block;position:relative;width:100%;border:0;outline:none;background:var(--button-background);color:var(--button-color);font-family:inherit;overflow:hidden}.action-sheet-button.sc-ion-action-sheet-md:disabled{color:var(--button-color-disabled);opacity:0.4}.action-sheet-button-inner.sc-ion-action-sheet-md{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;pointer-events:none;width:100%;height:100%;z-index:1}.action-sheet-container.sc-ion-action-sheet-md{display:-ms-flexbox;display:flex;-ms-flex-flow:column;flex-flow:column;-ms-flex-pack:end;justify-content:flex-end;height:100%;max-height:calc(100vh - (var(--ion-safe-area-top, 0) + var(--ion-safe-area-bottom, 0)));max-height:calc(100dvh - (var(--ion-safe-area-top, 0) + var(--ion-safe-area-bottom, 0)))}.action-sheet-group.sc-ion-action-sheet-md{-ms-flex-negative:2;flex-shrink:2;overscroll-behavior-y:contain;overflow-y:auto;-webkit-overflow-scrolling:touch;pointer-events:all;background:var(--background)}@media (any-pointer: coarse){.action-sheet-group.sc-ion-action-sheet-md::-webkit-scrollbar{display:none}}.action-sheet-group-cancel.sc-ion-action-sheet-md{-ms-flex-negative:0;flex-shrink:0;overflow:hidden}.action-sheet-button.sc-ion-action-sheet-md::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.action-sheet-selected.sc-ion-action-sheet-md{color:var(--button-color-selected)}.action-sheet-selected.sc-ion-action-sheet-md::after{background:var(--button-background-selected);opacity:var(--button-background-selected-opacity)}.action-sheet-button.ion-activated.sc-ion-action-sheet-md{color:var(--button-color-activated)}.action-sheet-button.ion-activated.sc-ion-action-sheet-md::after{background:var(--button-background-activated);opacity:var(--button-background-activated-opacity)}.action-sheet-button.ion-focused.sc-ion-action-sheet-md{color:var(--button-color-focused)}.action-sheet-button.ion-focused.sc-ion-action-sheet-md::after{background:var(--button-background-focused);opacity:var(--button-background-focused-opacity)}@media (any-hover: hover){.action-sheet-button.sc-ion-action-sheet-md:not(:disabled):hover{color:var(--button-color-hover)}.action-sheet-button.sc-ion-action-sheet-md:not(:disabled):hover::after{background:var(--button-background-hover);opacity:var(--button-background-hover-opacity)}}.sc-ion-action-sheet-md-h{--background:var(--ion-overlay-background-color, var(--ion-background-color, #fff));--backdrop-opacity:var(--ion-backdrop-opacity, 0.32);--button-background:transparent;--button-background-selected:currentColor;--button-background-selected-opacity:0;--button-background-activated:transparent;--button-background-activated-opacity:0;--button-background-hover:currentColor;--button-background-hover-opacity:.04;--button-background-focused:currentColor;--button-background-focused-opacity:.12;--button-color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));--button-color-disabled:var(--button-color);--color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54)}.action-sheet-wrapper.sc-ion-action-sheet-md{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:var(--ion-safe-area-top, 0);margin-bottom:0}.action-sheet-title.sc-ion-action-sheet-md{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:20px;padding-bottom:17px;min-height:60px;color:var(--color, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54));font-size:1rem;text-align:start}.action-sheet-sub-title.sc-ion-action-sheet-md{padding-left:0;padding-right:0;padding-top:16px;padding-bottom:0;font-size:0.875rem}.action-sheet-group.sc-ion-action-sheet-md:first-child{padding-top:0}.action-sheet-group.sc-ion-action-sheet-md:last-child{padding-bottom:var(--ion-safe-area-bottom)}.action-sheet-button.sc-ion-action-sheet-md{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:12px;padding-bottom:12px;position:relative;min-height:52px;font-size:1rem;text-align:start;contain:content;overflow:hidden}.action-sheet-icon.sc-ion-action-sheet-md{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:32px;margin-inline-end:32px;margin-top:0;margin-bottom:0;color:var(--color);font-size:1.5rem}.action-sheet-button-inner.sc-ion-action-sheet-md{-ms-flex-pack:start;justify-content:flex-start}.action-sheet-selected.sc-ion-action-sheet-md{font-weight:bold}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class ActionSheet {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionActionSheetDidPresent", 7);
this.willPresent = createEvent(this, "ionActionSheetWillPresent", 7);
this.willDismiss = createEvent(this, "ionActionSheetWillDismiss", 7);
this.didDismiss = createEvent(this, "ionActionSheetDidDismiss", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.delegateController = createDelegateController(this);
this.lockController = createLockController();
this.triggerController = createTriggerController();
this.presented = false;
/** @internal */
this.hasController = false;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = true;
/**
* An array of buttons for the action sheet.
*/
this.buttons = [];
/**
* If `true`, the action sheet will be dismissed when the backdrop is clicked.
*/
this.backdropDismiss = true;
/**
* If `true`, the action sheet will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
/**
* If `true`, the action sheet will animate.
*/
this.animated = true;
/**
* If `true`, the action sheet will open. If `false`, the action sheet will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the actionSheetController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the action sheet dismisses. You will need to do that in your code.
*/
this.isOpen = false;
this.onBackdropTap = () => {
this.dismiss(undefined, BACKDROP);
};
this.dispatchCancelHandler = (ev) => {
const role = ev.detail.role;
if (isCancel(role)) {
const cancelButton = this.getButtons().find((b) => b.role === 'cancel');
this.callButtonHandler(cancelButton);
}
};
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
triggerChanged() {
const { trigger, el, triggerController } = this;
if (trigger) {
triggerController.addClickListener(el, trigger);
}
}
/**
* Present the action sheet overlay after it has been created.
*/
async present() {
const unlock = await this.lockController.lock();
await this.delegateController.attachViewToDom();
await present(this, 'actionSheetEnter', iosEnterAnimation$6, mdEnterAnimation$5);
unlock();
}
/**
* Dismiss the action sheet overlay after it has been presented.
* This is a no-op if the overlay has not been presented yet. If you want
* to remove an overlay from the DOM that was never presented, use the
* [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the action sheet.
* This can be useful in a button handler for determining which button was
* clicked to dismiss the action sheet. Some examples include:
* `"cancel"`, `"destructive"`, `"selected"`, and `"backdrop"`.
*/
async dismiss(data, role) {
const unlock = await this.lockController.lock();
const dismissed = await dismiss(this, data, role, 'actionSheetLeave', iosLeaveAnimation$6, mdLeaveAnimation$5);
if (dismissed) {
this.delegateController.removeViewFromDom();
}
unlock();
return dismissed;
}
/**
* Returns a promise that resolves when the action sheet did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionActionSheetDidDismiss');
}
/**
* Returns a promise that resolves when the action sheet will dismiss.
*
*/
onWillDismiss() {
return eventMethod(this.el, 'ionActionSheetWillDismiss');
}
async buttonClick(button) {
const role = button.role;
if (isCancel(role)) {
return this.dismiss(button.data, role);
}
const shouldDismiss = await this.callButtonHandler(button);
if (shouldDismiss) {
return this.dismiss(button.data, button.role);
}
return Promise.resolve();
}
async callButtonHandler(button) {
if (button) {
// a handler has been provided, execute it
// pass the handler the values from the inputs
const rtn = await safeCall(button.handler);
if (rtn === false) {
// if the return value of the handler is false then do not dismiss
return false;
}
}
return true;
}
getButtons() {
return this.buttons.map((b) => {
return typeof b === 'string' ? { text: b } : b;
});
}
connectedCallback() {
prepareOverlay(this.el);
this.triggerChanged();
}
disconnectedCallback() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
this.triggerController.removeClickListener();
}
componentWillLoad() {
var _a;
if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
setOverlayId(this.el);
}
}
componentDidLoad() {
/**
* Only create gesture if:
* 1. A gesture does not already exist
* 2. App is running in iOS mode
* 3. A wrapper ref exists
* 4. A group ref exists
*/
const { groupEl, wrapperEl } = this;
if (!this.gesture && getIonMode$1(this) === 'ios' && wrapperEl && groupEl) {
readTask(() => {
const isScrollable = groupEl.scrollHeight > groupEl.clientHeight;
if (!isScrollable) {
this.gesture = createButtonActiveGesture(wrapperEl, (refEl) => refEl.classList.contains('action-sheet-button'));
this.gesture.enable(true);
}
});
}
/**
* If action sheet was rendered with isOpen="true"
* then we should open action sheet immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.triggerChanged();
}
render() {
const { header, htmlAttributes, overlayIndex } = this;
const mode = getIonMode$1(this);
const allButtons = this.getButtons();
const cancelButton = allButtons.find((b) => b.role === 'cancel');
const buttons = allButtons.filter((b) => b.role !== 'cancel');
const headerID = `action-sheet-${overlayIndex}-header`;
return (hAsync(Host, Object.assign({ key: '9fef156b2a1f09ca4a6c1fe1f37c374139bde03c', role: "dialog", "aria-modal": "true", "aria-labelledby": header !== undefined ? headerID : null, tabindex: "-1" }, htmlAttributes, { style: {
zIndex: `${20000 + this.overlayIndex}`,
}, class: Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'action-sheet-translucent': this.translucent }), onIonActionSheetWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }), hAsync("ion-backdrop", { key: '81cf3f7d19864e041813987b46d2d115b8466819', tappable: this.backdropDismiss }), hAsync("div", { key: '791c6a976683646fc306a42c15c5078b6f06a45f', tabindex: "0", "aria-hidden": "true" }), hAsync("div", { key: 'a350b489ef7852eab9dc2227ce6d92da27dd9bf9', class: "action-sheet-wrapper ion-overlay-wrapper", ref: (el) => (this.wrapperEl = el) }, hAsync("div", { key: '69ba51ee13510c1a411d87cb4845b11b7302a36f', class: "action-sheet-container" }, hAsync("div", { key: 'bded15b8306c36591e526f0f99e1eeabcbab3915', class: "action-sheet-group", ref: (el) => (this.groupEl = el) }, header !== undefined && (hAsync("div", { key: '06b5147c0f6d9180fe8f12e75c9b4a0310226adc', id: headerID, class: {
'action-sheet-title': true,
'action-sheet-has-sub-title': this.subHeader !== undefined,
} }, header, this.subHeader && hAsync("div", { key: '54874362a75c679aba803bf4f8768f5404d2dd28', class: "action-sheet-sub-title" }, this.subHeader))), buttons.map((b) => (hAsync("button", Object.assign({}, b.htmlAttributes, { type: "button", id: b.id, class: buttonClass$3(b), onClick: () => this.buttonClick(b), disabled: b.disabled }), hAsync("span", { class: "action-sheet-button-inner" }, b.icon && hAsync("ion-icon", { icon: b.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" }), b.text), mode === 'md' && hAsync("ion-ripple-effect", null))))), cancelButton && (hAsync("div", { key: '67b0de298eb424f3dea846a841b7a06d70e3930d', class: "action-sheet-group action-sheet-group-cancel" }, hAsync("button", Object.assign({ key: 'e7e3f9a5495eea9b97dbf885ef36944f2e420eff' }, cancelButton.htmlAttributes, { type: "button", class: buttonClass$3(cancelButton), onClick: () => this.buttonClick(cancelButton) }), hAsync("span", { key: 'f889d29ed6c3d14bbc1d805888351d87f5122377', class: "action-sheet-button-inner" }, cancelButton.icon && (hAsync("ion-icon", { key: '7c05cf424b38c37fd40aaeb42a494387291571fb', icon: cancelButton.icon, "aria-hidden": "true", lazy: false, class: "action-sheet-icon" })), cancelButton.text), mode === 'md' && hAsync("ion-ripple-effect", { key: 'bed927b477dc2708a5123ef560274fca9819b3d6' })))))), hAsync("div", { key: 'c5df1b11dc15a93892d57065d3dd5fbe02e43b39', tabindex: "0", "aria-hidden": "true" })));
}
get el() { return getElement(this); }
static get watchers() { return {
"isOpen": ["onIsOpenChange"],
"trigger": ["triggerChanged"]
}; }
static get style() { return {
ios: actionSheetIosCss,
md: actionSheetMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-action-sheet",
"$members$": {
"overlayIndex": [2, "overlay-index"],
"delegate": [16],
"hasController": [4, "has-controller"],
"keyboardClose": [4, "keyboard-close"],
"enterAnimation": [16],
"leaveAnimation": [16],
"buttons": [16],
"cssClass": [1, "css-class"],
"backdropDismiss": [4, "backdrop-dismiss"],
"header": [1],
"subHeader": [1, "sub-header"],
"translucent": [4],
"animated": [4],
"htmlAttributes": [16],
"isOpen": [4, "is-open"],
"trigger": [1],
"present": [64],
"dismiss": [64],
"onDidDismiss": [64],
"onWillDismiss": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const buttonClass$3 = (button) => {
return Object.assign({ 'action-sheet-button': true, 'ion-activatable': !button.disabled, 'ion-focusable': !button.disabled, [`action-sheet-${button.role}`]: button.role !== undefined }, getClassMap(button.cssClass));
};
const ENABLE_HTML_CONTENT_DEFAULT = false;
/**
* Does a simple sanitization of all elements
* in an untrusted string
*/
const sanitizeDOMString = (untrustedString) => {
try {
if (untrustedString instanceof IonicSafeString) {
return untrustedString.value;
}
if (!isSanitizerEnabled() || typeof untrustedString !== 'string' || untrustedString === '') {
return untrustedString;
}
/**
* onload is fired when appending to a document
* fragment in Chrome. If a string
* contains onload then we should not
* attempt to add this to the fragment.
*/
if (untrustedString.includes('onload=')) {
return '';
}
/**
* Create a document fragment
* separate from the main DOM,
* create a div to do our work in
*/
const documentFragment = document.createDocumentFragment();
const workingDiv = document.createElement('div');
documentFragment.appendChild(workingDiv);
workingDiv.innerHTML = untrustedString;
/**
* Remove any elements
* that are blocked
*/
blockedTags.forEach((blockedTag) => {
const getElementsToRemove = documentFragment.querySelectorAll(blockedTag);
for (let elementIndex = getElementsToRemove.length - 1; elementIndex >= 0; elementIndex--) {
const element = getElementsToRemove[elementIndex];
if (element.parentNode) {
element.parentNode.removeChild(element);
}
else {
documentFragment.removeChild(element);
}
/**
* We still need to sanitize
* the children of this element
* as they are left behind
*/
const childElements = getElementChildren(element);
/* eslint-disable-next-line */
for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
sanitizeElement(childElements[childIndex]);
}
}
});
/**
* Go through remaining elements and remove
* non-allowed attribs
*/
// IE does not support .children on document fragments, only .childNodes
const dfChildren = getElementChildren(documentFragment);
/* eslint-disable-next-line */
for (let childIndex = 0; childIndex < dfChildren.length; childIndex++) {
sanitizeElement(dfChildren[childIndex]);
}
// Append document fragment to div
const fragmentDiv = document.createElement('div');
fragmentDiv.appendChild(documentFragment);
// First child is always the div we did our work in
const getInnerDiv = fragmentDiv.querySelector('div');
return getInnerDiv !== null ? getInnerDiv.innerHTML : fragmentDiv.innerHTML;
}
catch (err) {
printIonError('sanitizeDOMString', err);
return '';
}
};
/**
* Clean up current element based on allowed attributes
* and then recursively dig down into any child elements to
* clean those up as well
*/
// TODO(FW-2832): type (using Element triggers other type errors as well)
const sanitizeElement = (element) => {
// IE uses childNodes, so ignore nodes that are not elements
if (element.nodeType && element.nodeType !== 1) {
return;
}
/**
* If attributes is not a NamedNodeMap
* then we should remove the element entirely.
* This helps avoid DOM Clobbering attacks where
* attributes is overridden.
*/
if (typeof NamedNodeMap !== 'undefined' && !(element.attributes instanceof NamedNodeMap)) {
element.remove();
return;
}
for (let i = element.attributes.length - 1; i >= 0; i--) {
const attribute = element.attributes.item(i);
const attributeName = attribute.name;
// remove non-allowed attribs
if (!allowedAttributes.includes(attributeName.toLowerCase())) {
element.removeAttribute(attributeName);
continue;
}
// clean up any allowed attribs
// that attempt to do any JS funny-business
const attributeValue = attribute.value;
/**
* We also need to check the property value
* as javascript: can allow special characters
* such as &Tab; and still be valid (i.e. java&Tab;script)
*/
const propertyValue = element[attributeName];
/* eslint-disable */
if ((attributeValue != null && attributeValue.toLowerCase().includes('javascript:')) ||
(propertyValue != null && propertyValue.toLowerCase().includes('javascript:'))) {
element.removeAttribute(attributeName);
}
/* eslint-enable */
}
/**
* Sanitize any nested children
*/
const childElements = getElementChildren(element);
/* eslint-disable-next-line */
for (let i = 0; i < childElements.length; i++) {
sanitizeElement(childElements[i]);
}
};
/**
* IE doesn't always support .children
* so we revert to .childNodes instead
*/
// TODO(FW-2832): type
const getElementChildren = (el) => {
return el.children != null ? el.children : el.childNodes;
};
const isSanitizerEnabled = () => {
var _a;
const win = window;
const config = (_a = win === null || win === void 0 ? void 0 : win.Ionic) === null || _a === void 0 ? void 0 : _a.config;
if (config) {
if (config.get) {
return config.get('sanitizerEnabled', true);
}
else {
return config.sanitizerEnabled === true || config.sanitizerEnabled === undefined;
}
}
return true;
};
const allowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
const blockedTags = ['script', 'style', 'iframe', 'meta', 'link', 'object', 'embed'];
class IonicSafeString {
constructor(value) {
this.value = value;
}
}
/**
* iOS Alert Enter Animation
*/
const iosEnterAnimation$5 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation.addElement(baseEl.querySelector('.alert-wrapper')).keyframes([
{ offset: 0, opacity: '0.01', transform: 'scale(1.1)' },
{ offset: 1, opacity: '1', transform: 'scale(1)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* iOS Alert Leave Animation
*/
const iosLeaveAnimation$5 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(baseEl.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation.addElement(baseEl.querySelector('.alert-wrapper')).keyframes([
{ offset: 0, opacity: 0.99, transform: 'scale(1)' },
{ offset: 1, opacity: 0, transform: 'scale(0.9)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* Md Alert Enter Animation
*/
const mdEnterAnimation$4 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation.addElement(baseEl.querySelector('.alert-wrapper')).keyframes([
{ offset: 0, opacity: '0.01', transform: 'scale(0.9)' },
{ offset: 1, opacity: '1', transform: 'scale(1)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(150)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* Md Alert Leave Animation
*/
const mdLeaveAnimation$4 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(baseEl.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation.addElement(baseEl.querySelector('.alert-wrapper')).fromTo('opacity', 0.99, 0);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(150)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
const alertIosCss = ".sc-ion-alert-ios-h{--min-width:250px;--width:auto;--min-height:auto;--height:auto;--max-height:90%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;font-family:var(--ion-font-family, inherit);contain:strict;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.overlay-hidden.sc-ion-alert-ios-h{display:none}.alert-top.sc-ion-alert-ios-h{padding-top:50px;-ms-flex-align:start;align-items:flex-start}.alert-wrapper.sc-ion-alert-ios{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);contain:content;opacity:0;z-index:10}.alert-title.sc-ion-alert-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}.alert-sub-title.sc-ion-alert-ios{margin-left:0;margin-right:0;margin-top:5px;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-weight:normal}.alert-message.sc-ion-alert-ios,.alert-input-group.sc-ion-alert-ios{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-overflow-scrolling:touch;overflow-y:auto;overscroll-behavior-y:contain}.alert-checkbox-label.sc-ion-alert-ios,.alert-radio-label.sc-ion-alert-ios{overflow-wrap:anywhere}@media (any-pointer: coarse){.alert-checkbox-group.sc-ion-alert-ios::-webkit-scrollbar,.alert-radio-group.sc-ion-alert-ios::-webkit-scrollbar,.alert-message.sc-ion-alert-ios::-webkit-scrollbar{display:none}}.alert-input.sc-ion-alert-ios{padding-left:0;padding-right:0;padding-top:10px;padding-bottom:10px;width:100%;border:0;background:inherit;font:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}.alert-button-group.sc-ion-alert-ios{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;width:100%}.alert-button-group-vertical.sc-ion-alert-ios{-ms-flex-direction:column;flex-direction:column;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.alert-button.sc-ion-alert-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;border:0;font-size:0.875rem;line-height:1.25rem;z-index:0}.alert-button.ion-focused.sc-ion-alert-ios,.alert-tappable.ion-focused.sc-ion-alert-ios{background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.alert-button-inner.sc-ion-alert-ios{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;min-height:inherit}.alert-input-disabled.sc-ion-alert-ios,.alert-checkbox-button-disabled.sc-ion-alert-ios .alert-button-inner.sc-ion-alert-ios,.alert-radio-button-disabled.sc-ion-alert-ios .alert-button-inner.sc-ion-alert-ios{cursor:default;opacity:0.5;pointer-events:none}.alert-tappable.sc-ion-alert-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:-ms-flexbox;display:flex;width:100%;border:0;background:transparent;font-size:inherit;line-height:initial;text-align:start;-webkit-appearance:none;-moz-appearance:none;appearance:none;contain:content}.alert-button.sc-ion-alert-ios,.alert-checkbox.sc-ion-alert-ios,.alert-input.sc-ion-alert-ios,.alert-radio.sc-ion-alert-ios{outline:none}.alert-radio-icon.sc-ion-alert-ios,.alert-checkbox-icon.sc-ion-alert-ios,.alert-checkbox-inner.sc-ion-alert-ios{-webkit-box-sizing:border-box;box-sizing:border-box}textarea.alert-input.sc-ion-alert-ios{min-height:37px;resize:none}.sc-ion-alert-ios-h{--background:var(--ion-overlay-background-color, var(--ion-color-step-100, var(--ion-background-color-step-100, #f9f9f9)));--max-width:clamp(270px, 16.875rem, 324px);--backdrop-opacity:var(--ion-backdrop-opacity, 0.3);font-size:max(14px, 0.875rem)}.alert-wrapper.sc-ion-alert-ios{border-radius:13px;-webkit-box-shadow:none;box-shadow:none;overflow:hidden}.alert-button.sc-ion-alert-ios .alert-button-inner.sc-ion-alert-ios{pointer-events:none}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.alert-translucent.sc-ion-alert-ios-h .alert-wrapper.sc-ion-alert-ios{background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.9);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}}.alert-head.sc-ion-alert-ios{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:12px;padding-bottom:7px;text-align:center}.alert-title.sc-ion-alert-ios{margin-top:8px;color:var(--ion-text-color, #000);font-size:max(17px, 1.0625rem);font-weight:600}.alert-sub-title.sc-ion-alert-ios{color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));font-size:max(14px, 0.875rem)}.alert-message.sc-ion-alert-ios,.alert-input-group.sc-ion-alert-ios{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:0;padding-bottom:21px;color:var(--ion-text-color, #000);font-size:max(13px, 0.8125rem);text-align:center}.alert-message.sc-ion-alert-ios{max-height:240px}.alert-message.sc-ion-alert-ios:empty{padding-left:0;padding-right:0;padding-top:0;padding-bottom:12px}.alert-input.sc-ion-alert-ios{border-radius:7px;margin-top:10px;-webkit-padding-start:7px;padding-inline-start:7px;-webkit-padding-end:7px;padding-inline-end:7px;padding-top:7px;padding-bottom:7px;border:0.55px solid var(--ion-color-step-250, var(--ion-background-color-step-250, #bfbfbf));background-color:var(--ion-background-color, #fff);-webkit-appearance:none;-moz-appearance:none;appearance:none;font-size:1rem}.alert-input.sc-ion-alert-ios::-webkit-input-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-ios::-moz-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-ios:-ms-input-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-ios::-ms-input-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-ios::placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-ios::-ms-clear{display:none}.alert-input.sc-ion-alert-ios::-webkit-date-and-time-value{height:18px}.alert-radio-group.sc-ion-alert-ios,.alert-checkbox-group.sc-ion-alert-ios{-ms-scroll-chaining:none;overscroll-behavior:contain;max-height:240px;border-top:0.55px solid rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2);overflow-y:auto;-webkit-overflow-scrolling:touch}.alert-tappable.sc-ion-alert-ios{min-height:44px}.alert-radio-label.sc-ion-alert-ios{-webkit-padding-start:13px;padding-inline-start:13px;-webkit-padding-end:13px;padding-inline-end:13px;padding-top:13px;padding-bottom:13px;-ms-flex:1;flex:1;-ms-flex-order:0;order:0;color:var(--ion-text-color, #000)}[aria-checked=true].sc-ion-alert-ios .alert-radio-label.sc-ion-alert-ios{color:var(--ion-color-primary, #0054e9)}.alert-radio-icon.sc-ion-alert-ios{position:relative;-ms-flex-order:1;order:1;min-width:30px}[aria-checked=true].sc-ion-alert-ios .alert-radio-inner.sc-ion-alert-ios{top:-7px;position:absolute;width:6px;height:12px;-webkit-transform:rotate(45deg);transform:rotate(45deg);border-width:2px;border-top-width:0;border-left-width:0;border-style:solid;border-color:var(--ion-color-primary, #0054e9)}[aria-checked=true].sc-ion-alert-ios .alert-radio-inner.sc-ion-alert-ios{inset-inline-start:7px}.alert-checkbox-label.sc-ion-alert-ios{-webkit-padding-start:13px;padding-inline-start:13px;-webkit-padding-end:13px;padding-inline-end:13px;padding-top:13px;padding-bottom:13px;-ms-flex:1;flex:1;color:var(--ion-text-color, #000)}.alert-checkbox-icon.sc-ion-alert-ios{border-radius:50%;-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:6px;margin-inline-end:6px;margin-top:10px;margin-bottom:10px;position:relative;width:min(1.375rem, 55.836px);height:min(1.375rem, 55.836px);border-width:0.125rem;border-style:solid;border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));background-color:var(--ion-item-background, var(--ion-background-color, #fff));contain:strict}[aria-checked=true].sc-ion-alert-ios .alert-checkbox-icon.sc-ion-alert-ios{border-color:var(--ion-color-primary, #0054e9);background-color:var(--ion-color-primary, #0054e9)}[aria-checked=true].sc-ion-alert-ios .alert-checkbox-inner.sc-ion-alert-ios{top:calc(min(1.375rem, 55.836px) / 8);position:absolute;width:calc(min(1.375rem, 55.836px) / 6 + 1px);height:calc(min(1.375rem, 55.836px) * 0.5);-webkit-transform:rotate(45deg);transform:rotate(45deg);border-width:0.125rem;border-top-width:0;border-left-width:0;border-style:solid;border-color:var(--ion-background-color, #fff)}[aria-checked=true].sc-ion-alert-ios .alert-checkbox-inner.sc-ion-alert-ios{inset-inline-start:calc(min(1.375rem, 55.836px) / 3)}.alert-button-group.sc-ion-alert-ios{-webkit-margin-end:-0.55px;margin-inline-end:-0.55px;-ms-flex-wrap:wrap;flex-wrap:wrap}.alert-button-group-vertical.sc-ion-alert-ios .alert-button.sc-ion-alert-ios{border-right:none}[dir=rtl].sc-ion-alert-ios-h .alert-button-group-vertical.sc-ion-alert-ios .alert-button.sc-ion-alert-ios:last-child,[dir=rtl] .sc-ion-alert-ios-h .alert-button-group-vertical.sc-ion-alert-ios .alert-button.sc-ion-alert-ios:last-child{border-right:none}[dir=rtl].sc-ion-alert-ios .alert-button-group-vertical.sc-ion-alert-ios .alert-button.sc-ion-alert-ios:last-child{border-right:none}@supports selector(:dir(rtl)){.alert-button-group-vertical.sc-ion-alert-ios .alert-button.sc-ion-alert-ios:last-child:dir(rtl){border-right:none}}.alert-button.sc-ion-alert-ios{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;border-radius:0;-ms-flex:1 1 auto;flex:1 1 auto;min-width:50%;height:max(44px, 2.75rem);border-top:0.55px solid rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2);border-right:0.55px solid rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2);background-color:transparent;color:var(--ion-color-primary, #0054e9);font-size:max(17px, 1.0625rem);overflow:hidden}[dir=rtl].sc-ion-alert-ios-h .alert-button.sc-ion-alert-ios:first-child,[dir=rtl] .sc-ion-alert-ios-h .alert-button.sc-ion-alert-ios:first-child{border-right:0}[dir=rtl].sc-ion-alert-ios .alert-button.sc-ion-alert-ios:first-child{border-right:0}@supports selector(:dir(rtl)){.alert-button.sc-ion-alert-ios:first-child:dir(rtl){border-right:0}}.alert-button.sc-ion-alert-ios:last-child{border-right:0;font-weight:bold}[dir=rtl].sc-ion-alert-ios-h .alert-button.sc-ion-alert-ios:last-child,[dir=rtl] .sc-ion-alert-ios-h .alert-button.sc-ion-alert-ios:last-child{border-right:0.55px solid rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2)}[dir=rtl].sc-ion-alert-ios .alert-button.sc-ion-alert-ios:last-child{border-right:0.55px solid rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2)}@supports selector(:dir(rtl)){.alert-button.sc-ion-alert-ios:last-child:dir(rtl){border-right:0.55px solid rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2)}}.alert-button.ion-activated.sc-ion-alert-ios{background-color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1)}.alert-button-role-destructive.sc-ion-alert-ios,.alert-button-role-destructive.ion-activated.sc-ion-alert-ios,.alert-button-role-destructive.ion-focused.sc-ion-alert-ios{color:var(--ion-color-danger, #c5000f)}";
const alertMdCss = ".sc-ion-alert-md-h{--min-width:250px;--width:auto;--min-height:auto;--height:auto;--max-height:90%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;font-family:var(--ion-font-family, inherit);contain:strict;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.overlay-hidden.sc-ion-alert-md-h{display:none}.alert-top.sc-ion-alert-md-h{padding-top:50px;-ms-flex-align:start;align-items:flex-start}.alert-wrapper.sc-ion-alert-md{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);contain:content;opacity:0;z-index:10}.alert-title.sc-ion-alert-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}.alert-sub-title.sc-ion-alert-md{margin-left:0;margin-right:0;margin-top:5px;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-weight:normal}.alert-message.sc-ion-alert-md,.alert-input-group.sc-ion-alert-md{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-overflow-scrolling:touch;overflow-y:auto;overscroll-behavior-y:contain}.alert-checkbox-label.sc-ion-alert-md,.alert-radio-label.sc-ion-alert-md{overflow-wrap:anywhere}@media (any-pointer: coarse){.alert-checkbox-group.sc-ion-alert-md::-webkit-scrollbar,.alert-radio-group.sc-ion-alert-md::-webkit-scrollbar,.alert-message.sc-ion-alert-md::-webkit-scrollbar{display:none}}.alert-input.sc-ion-alert-md{padding-left:0;padding-right:0;padding-top:10px;padding-bottom:10px;width:100%;border:0;background:inherit;font:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}.alert-button-group.sc-ion-alert-md{display:-ms-flexbox;display:flex;-ms-flex-direction:row;flex-direction:row;width:100%}.alert-button-group-vertical.sc-ion-alert-md{-ms-flex-direction:column;flex-direction:column;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.alert-button.sc-ion-alert-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;border:0;font-size:0.875rem;line-height:1.25rem;z-index:0}.alert-button.ion-focused.sc-ion-alert-md,.alert-tappable.ion-focused.sc-ion-alert-md{background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.alert-button-inner.sc-ion-alert-md{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;min-height:inherit}.alert-input-disabled.sc-ion-alert-md,.alert-checkbox-button-disabled.sc-ion-alert-md .alert-button-inner.sc-ion-alert-md,.alert-radio-button-disabled.sc-ion-alert-md .alert-button-inner.sc-ion-alert-md{cursor:default;opacity:0.5;pointer-events:none}.alert-tappable.sc-ion-alert-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:-ms-flexbox;display:flex;width:100%;border:0;background:transparent;font-size:inherit;line-height:initial;text-align:start;-webkit-appearance:none;-moz-appearance:none;appearance:none;contain:content}.alert-button.sc-ion-alert-md,.alert-checkbox.sc-ion-alert-md,.alert-input.sc-ion-alert-md,.alert-radio.sc-ion-alert-md{outline:none}.alert-radio-icon.sc-ion-alert-md,.alert-checkbox-icon.sc-ion-alert-md,.alert-checkbox-inner.sc-ion-alert-md{-webkit-box-sizing:border-box;box-sizing:border-box}textarea.alert-input.sc-ion-alert-md{min-height:37px;resize:none}.sc-ion-alert-md-h{--background:var(--ion-overlay-background-color, var(--ion-background-color, #fff));--max-width:280px;--backdrop-opacity:var(--ion-backdrop-opacity, 0.32);font-size:0.875rem}.alert-wrapper.sc-ion-alert-md{border-radius:4px;-webkit-box-shadow:0 11px 15px -7px rgba(0, 0, 0, 0.2), 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12);box-shadow:0 11px 15px -7px rgba(0, 0, 0, 0.2), 0 24px 38px 3px rgba(0, 0, 0, 0.14), 0 9px 46px 8px rgba(0, 0, 0, 0.12)}.alert-head.sc-ion-alert-md{-webkit-padding-start:23px;padding-inline-start:23px;-webkit-padding-end:23px;padding-inline-end:23px;padding-top:20px;padding-bottom:15px;text-align:start}.alert-title.sc-ion-alert-md{color:var(--ion-text-color, #000);font-size:1.25rem;font-weight:500}.alert-sub-title.sc-ion-alert-md{color:var(--ion-text-color, #000);font-size:1rem}.alert-message.sc-ion-alert-md,.alert-input-group.sc-ion-alert-md{-webkit-padding-start:24px;padding-inline-start:24px;-webkit-padding-end:24px;padding-inline-end:24px;padding-top:20px;padding-bottom:20px;color:var(--ion-color-step-550, var(--ion-text-color-step-450, #737373))}.alert-message.sc-ion-alert-md{font-size:1rem}@media screen and (max-width: 767px){.alert-message.sc-ion-alert-md{max-height:266px}}.alert-message.sc-ion-alert-md:empty{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}.alert-head.sc-ion-alert-md+.alert-message.sc-ion-alert-md{padding-top:0}.alert-input.sc-ion-alert-md{margin-left:0;margin-right:0;margin-top:5px;margin-bottom:5px;border-bottom:1px solid var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));color:var(--ion-text-color, #000)}.alert-input.sc-ion-alert-md::-webkit-input-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-md::-moz-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-md:-ms-input-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-md::-ms-input-placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-md::placeholder{color:var(--ion-placeholder-color, var(--ion-color-step-400, var(--ion-text-color-step-600, #999999)));font-family:inherit;font-weight:inherit}.alert-input.sc-ion-alert-md::-ms-clear{display:none}.alert-input.sc-ion-alert-md:focus{margin-bottom:4px;border-bottom:2px solid var(--ion-color-primary, #0054e9)}.alert-radio-group.sc-ion-alert-md,.alert-checkbox-group.sc-ion-alert-md{position:relative;border-top:1px solid var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));border-bottom:1px solid var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));overflow:auto}@media screen and (max-width: 767px){.alert-radio-group.sc-ion-alert-md,.alert-checkbox-group.sc-ion-alert-md{max-height:266px}}.alert-tappable.sc-ion-alert-md{position:relative;min-height:48px}.alert-radio-label.sc-ion-alert-md{-webkit-padding-start:52px;padding-inline-start:52px;-webkit-padding-end:26px;padding-inline-end:26px;padding-top:13px;padding-bottom:13px;-ms-flex:1;flex:1;color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));font-size:1rem}.alert-radio-icon.sc-ion-alert-md{top:0;border-radius:50%;display:block;position:relative;width:20px;height:20px;border-width:2px;border-style:solid;border-color:var(--ion-color-step-550, var(--ion-background-color-step-550, #737373))}.alert-radio-icon.sc-ion-alert-md{inset-inline-start:26px}.alert-radio-inner.sc-ion-alert-md{top:3px;border-radius:50%;position:absolute;width:10px;height:10px;-webkit-transform:scale3d(0, 0, 0);transform:scale3d(0, 0, 0);-webkit-transition:-webkit-transform 280ms cubic-bezier(0.4, 0, 0.2, 1);transition:-webkit-transform 280ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 280ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 280ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 280ms cubic-bezier(0.4, 0, 0.2, 1);background-color:var(--ion-color-primary, #0054e9)}.alert-radio-inner.sc-ion-alert-md{inset-inline-start:3px}[aria-checked=true].sc-ion-alert-md .alert-radio-label.sc-ion-alert-md{color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626))}[aria-checked=true].sc-ion-alert-md .alert-radio-icon.sc-ion-alert-md{border-color:var(--ion-color-primary, #0054e9)}[aria-checked=true].sc-ion-alert-md .alert-radio-inner.sc-ion-alert-md{-webkit-transform:scale3d(1, 1, 1);transform:scale3d(1, 1, 1)}.alert-checkbox-label.sc-ion-alert-md{-webkit-padding-start:53px;padding-inline-start:53px;-webkit-padding-end:26px;padding-inline-end:26px;padding-top:13px;padding-bottom:13px;-ms-flex:1;flex:1;width:calc(100% - 53px);color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));font-size:1rem}.alert-checkbox-icon.sc-ion-alert-md{top:0;border-radius:2px;position:relative;width:16px;height:16px;border-width:2px;border-style:solid;border-color:var(--ion-color-step-550, var(--ion-background-color-step-550, #737373));contain:strict}.alert-checkbox-icon.sc-ion-alert-md{inset-inline-start:26px}[aria-checked=true].sc-ion-alert-md .alert-checkbox-icon.sc-ion-alert-md{border-color:var(--ion-color-primary, #0054e9);background-color:var(--ion-color-primary, #0054e9)}[aria-checked=true].sc-ion-alert-md .alert-checkbox-inner.sc-ion-alert-md{top:0;position:absolute;width:6px;height:10px;-webkit-transform:rotate(45deg);transform:rotate(45deg);border-width:2px;border-top-width:0;border-left-width:0;border-style:solid;border-color:var(--ion-color-primary-contrast, #fff)}[aria-checked=true].sc-ion-alert-md .alert-checkbox-inner.sc-ion-alert-md{inset-inline-start:3px}.alert-button-group.sc-ion-alert-md{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:8px;padding-bottom:8px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-wrap:wrap-reverse;flex-wrap:wrap-reverse;-ms-flex-pack:end;justify-content:flex-end}.alert-button.sc-ion-alert-md{border-radius:2px;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:0;margin-bottom:0;-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px;padding-top:10px;padding-bottom:10px;position:relative;background-color:transparent;color:var(--ion-color-primary, #0054e9);font-weight:500;text-align:end;text-transform:uppercase;overflow:hidden}.alert-button-inner.sc-ion-alert-md{-ms-flex-pack:end;justify-content:flex-end}@media screen and (min-width: 768px){.sc-ion-alert-md-h{--max-width:min(100vw - 96px, 560px);--max-height:min(100vh - 96px, 560px)}}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Alert {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionAlertDidPresent", 7);
this.willPresent = createEvent(this, "ionAlertWillPresent", 7);
this.willDismiss = createEvent(this, "ionAlertWillDismiss", 7);
this.didDismiss = createEvent(this, "ionAlertDidDismiss", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.delegateController = createDelegateController(this);
this.lockController = createLockController();
this.triggerController = createTriggerController();
this.customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
this.processedInputs = [];
this.processedButtons = [];
this.presented = false;
/** @internal */
this.hasController = false;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = true;
/**
* Array of buttons to be added to the alert.
*/
this.buttons = [];
/**
* Array of input to show in the alert.
*/
this.inputs = [];
/**
* If `true`, the alert will be dismissed when the backdrop is clicked.
*/
this.backdropDismiss = true;
/**
* If `true`, the alert will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
/**
* If `true`, the alert will animate.
*/
this.animated = true;
/**
* If `true`, the alert will open. If `false`, the alert will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the alertController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the alert dismisses. You will need to do that in your code.
*/
this.isOpen = false;
this.onBackdropTap = () => {
this.dismiss(undefined, BACKDROP);
};
this.dispatchCancelHandler = (ev) => {
const role = ev.detail.role;
if (isCancel(role)) {
const cancelButton = this.processedButtons.find((b) => b.role === 'cancel');
this.callButtonHandler(cancelButton);
}
};
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
triggerChanged() {
const { trigger, el, triggerController } = this;
if (trigger) {
triggerController.addClickListener(el, trigger);
}
}
onKeydown(ev) {
var _a;
const inputTypes = new Set(this.processedInputs.map((i) => i.type));
/**
* Based on keyboard navigation requirements, the
* checkbox should not respond to the enter keydown event.
*/
if (inputTypes.has('checkbox') && ev.key === 'Enter') {
ev.preventDefault();
return;
}
/**
* Ensure when alert container is being focused, and the user presses the tab + shift keys, the focus will be set to the last alert button.
*/
if (ev.target.classList.contains('alert-wrapper')) {
if (ev.key === 'Tab' && ev.shiftKey) {
ev.preventDefault();
const lastChildBtn = (_a = this.wrapperEl) === null || _a === void 0 ? void 0 : _a.querySelector('.alert-button:last-child');
lastChildBtn.focus();
return;
}
}
// The only inputs we want to navigate between using arrow keys are the radios
// ignore the keydown event if it is not on a radio button
if (!inputTypes.has('radio') ||
(ev.target && !this.el.contains(ev.target)) ||
ev.target.classList.contains('alert-button')) {
return;
}
// Get all radios inside of the radio group and then
// filter out disabled radios since we need to skip those
const query = this.el.querySelectorAll('.alert-radio');
const radios = Array.from(query).filter((radio) => !radio.disabled);
// The focused radio is the one that shares the same id as
// the event target
const index = radios.findIndex((radio) => radio.id === ev.target.id);
// We need to know what the next radio element should
// be in order to change the focus
let nextEl;
// If hitting arrow down or arrow right, move to the next radio
// If we're on the last radio, move to the first radio
if (['ArrowDown', 'ArrowRight'].includes(ev.key)) {
nextEl = index === radios.length - 1 ? radios[0] : radios[index + 1];
}
// If hitting arrow up or arrow left, move to the previous radio
// If we're on the first radio, move to the last radio
if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) {
nextEl = index === 0 ? radios[radios.length - 1] : radios[index - 1];
}
if (nextEl && radios.includes(nextEl)) {
const nextProcessed = this.processedInputs.find((input) => input.id === (nextEl === null || nextEl === void 0 ? void 0 : nextEl.id));
if (nextProcessed) {
this.rbClick(nextProcessed);
nextEl.focus();
}
}
}
buttonsChanged() {
const buttons = this.buttons;
this.processedButtons = buttons.map((btn) => {
return typeof btn === 'string' ? { text: btn, role: btn.toLowerCase() === 'cancel' ? 'cancel' : undefined } : btn;
});
}
inputsChanged() {
const inputs = this.inputs;
// Get the first input that is not disabled and the checked one
// If an enabled checked input exists, set it to be the focusable input
// otherwise we default to focus the first input
// This will only be used when the input is type radio
const first = inputs.find((input) => !input.disabled);
const checked = inputs.find((input) => input.checked && !input.disabled);
const focusable = checked || first;
// An alert can be created with several different inputs. Radios,
// checkboxes and inputs are all accepted, but they cannot be mixed.
const inputTypes = new Set(inputs.map((i) => i.type));
if (inputTypes.has('checkbox') && inputTypes.has('radio')) {
printIonWarning(`[ion-alert] - Alert cannot mix input types: ${Array.from(inputTypes.values()).join('/')}. Please see alert docs for more info.`);
}
this.inputType = inputTypes.values().next().value;
this.processedInputs = inputs.map((i, index) => {
var _a;
return ({
type: i.type || 'text',
name: i.name || `${index}`,
placeholder: i.placeholder || '',
value: i.value,
label: i.label,
checked: !!i.checked,
disabled: !!i.disabled,
id: i.id || `alert-input-${this.overlayIndex}-${index}`,
handler: i.handler,
min: i.min,
max: i.max,
cssClass: (_a = i.cssClass) !== null && _a !== void 0 ? _a : '',
attributes: i.attributes || {},
tabindex: i.type === 'radio' && i !== focusable ? -1 : 0,
});
});
}
connectedCallback() {
prepareOverlay(this.el);
this.triggerChanged();
}
componentWillLoad() {
var _a;
if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
setOverlayId(this.el);
}
this.inputsChanged();
this.buttonsChanged();
}
disconnectedCallback() {
this.triggerController.removeClickListener();
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
componentDidLoad() {
/**
* Only create gesture if:
* 1. A gesture does not already exist
* 2. App is running in iOS mode
* 3. A wrapper ref exists
*/
if (!this.gesture && getIonMode$1(this) === 'ios' && this.wrapperEl) {
this.gesture = createButtonActiveGesture(this.wrapperEl, (refEl) => refEl.classList.contains('alert-button'));
this.gesture.enable(true);
}
/**
* If alert was rendered with isOpen="true"
* then we should open alert immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.triggerChanged();
}
/**
* Present the alert overlay after it has been created.
*/
async present() {
const unlock = await this.lockController.lock();
await this.delegateController.attachViewToDom();
await present(this, 'alertEnter', iosEnterAnimation$5, mdEnterAnimation$4).then(() => {
var _a, _b;
/**
* Check if alert has only one button and no inputs.
* If so, then focus on the button. Otherwise, focus the alert wrapper.
* This will map to the default native alert behavior.
*/
if (this.buttons.length === 1 && this.inputs.length === 0) {
const queryBtn = (_a = this.wrapperEl) === null || _a === void 0 ? void 0 : _a.querySelector('.alert-button');
queryBtn.focus();
}
else {
(_b = this.wrapperEl) === null || _b === void 0 ? void 0 : _b.focus();
}
});
unlock();
}
/**
* Dismiss the alert overlay after it has been presented.
* This is a no-op if the overlay has not been presented yet. If you want
* to remove an overlay from the DOM that was never presented, use the
* [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the alert.
* This can be useful in a button handler for determining which button was
* clicked to dismiss the alert. Some examples include:
* `"cancel"`, `"destructive"`, `"selected"`, and `"backdrop"`.
*/
async dismiss(data, role) {
const unlock = await this.lockController.lock();
const dismissed = await dismiss(this, data, role, 'alertLeave', iosLeaveAnimation$5, mdLeaveAnimation$4);
if (dismissed) {
this.delegateController.removeViewFromDom();
}
unlock();
return dismissed;
}
/**
* Returns a promise that resolves when the alert did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionAlertDidDismiss');
}
/**
* Returns a promise that resolves when the alert will dismiss.
*/
onWillDismiss() {
return eventMethod(this.el, 'ionAlertWillDismiss');
}
rbClick(selectedInput) {
for (const input of this.processedInputs) {
input.checked = input === selectedInput;
input.tabindex = input === selectedInput ? 0 : -1;
}
this.activeId = selectedInput.id;
safeCall(selectedInput.handler, selectedInput);
}
cbClick(selectedInput) {
selectedInput.checked = !selectedInput.checked;
safeCall(selectedInput.handler, selectedInput);
}
async buttonClick(button) {
const role = button.role;
const values = this.getValues();
if (isCancel(role)) {
return this.dismiss({ values }, role);
}
const returnData = await this.callButtonHandler(button, values);
if (returnData !== false) {
return this.dismiss(Object.assign({ values }, returnData), button.role);
}
return false;
}
async callButtonHandler(button, data) {
if (button === null || button === void 0 ? void 0 : button.handler) {
// a handler has been provided, execute it
// pass the handler the values from the inputs
const returnData = await safeCall(button.handler, data);
if (returnData === false) {
// if the return value of the handler is false then do not dismiss
return false;
}
if (typeof returnData === 'object') {
return returnData;
}
}
return {};
}
getValues() {
if (this.processedInputs.length === 0) {
// this is an alert without any options/inputs at all
return undefined;
}
if (this.inputType === 'radio') {
// this is an alert with radio buttons (single value select)
// return the one value which is checked, otherwise undefined
const checkedInput = this.processedInputs.find((i) => !!i.checked);
return checkedInput ? checkedInput.value : undefined;
}
if (this.inputType === 'checkbox') {
// this is an alert with checkboxes (multiple value select)
// return an array of all the checked values
return this.processedInputs.filter((i) => i.checked).map((i) => i.value);
}
// this is an alert with text inputs
// return an object of all the values with the input name as the key
const values = {};
this.processedInputs.forEach((i) => {
values[i.name] = i.value || '';
});
return values;
}
renderAlertInputs() {
switch (this.inputType) {
case 'checkbox':
return this.renderCheckbox();
case 'radio':
return this.renderRadio();
default:
return this.renderInput();
}
}
renderCheckbox() {
const inputs = this.processedInputs;
const mode = getIonMode$1(this);
if (inputs.length === 0) {
return null;
}
return (hAsync("div", { class: "alert-checkbox-group" }, inputs.map((i) => (hAsync("button", { type: "button", onClick: () => this.cbClick(i), "aria-checked": `${i.checked}`, id: i.id, disabled: i.disabled, tabIndex: i.tabindex, role: "checkbox", class: Object.assign(Object.assign({}, getClassMap(i.cssClass)), { 'alert-tappable': true, 'alert-checkbox': true, 'alert-checkbox-button': true, 'ion-focusable': true, 'alert-checkbox-button-disabled': i.disabled || false }) }, hAsync("div", { class: "alert-button-inner" }, hAsync("div", { class: "alert-checkbox-icon" }, hAsync("div", { class: "alert-checkbox-inner" })), hAsync("div", { class: "alert-checkbox-label" }, i.label)), mode === 'md' && hAsync("ion-ripple-effect", null))))));
}
renderRadio() {
const inputs = this.processedInputs;
if (inputs.length === 0) {
return null;
}
return (hAsync("div", { class: "alert-radio-group", role: "radiogroup", "aria-activedescendant": this.activeId }, inputs.map((i) => (hAsync("button", { type: "button", onClick: () => this.rbClick(i), "aria-checked": `${i.checked}`, disabled: i.disabled, id: i.id, tabIndex: i.tabindex, class: Object.assign(Object.assign({}, getClassMap(i.cssClass)), { 'alert-radio-button': true, 'alert-tappable': true, 'alert-radio': true, 'ion-focusable': true, 'alert-radio-button-disabled': i.disabled || false }), role: "radio" }, hAsync("div", { class: "alert-button-inner" }, hAsync("div", { class: "alert-radio-icon" }, hAsync("div", { class: "alert-radio-inner" })), hAsync("div", { class: "alert-radio-label" }, i.label)))))));
}
renderInput() {
const inputs = this.processedInputs;
if (inputs.length === 0) {
return null;
}
return (hAsync("div", { class: "alert-input-group" }, inputs.map((i) => {
var _a, _b, _c, _d;
if (i.type === 'textarea') {
return (hAsync("div", { class: "alert-input-wrapper" }, hAsync("textarea", Object.assign({ placeholder: i.placeholder, value: i.value, id: i.id, tabIndex: i.tabindex }, i.attributes, { disabled: (_b = (_a = i.attributes) === null || _a === void 0 ? void 0 : _a.disabled) !== null && _b !== void 0 ? _b : i.disabled, class: inputClass(i), onInput: (e) => {
var _a;
i.value = e.target.value;
if ((_a = i.attributes) === null || _a === void 0 ? void 0 : _a.onInput) {
i.attributes.onInput(e);
}
} }))));
}
else {
return (hAsync("div", { class: "alert-input-wrapper" }, hAsync("input", Object.assign({ placeholder: i.placeholder, type: i.type, min: i.min, max: i.max, value: i.value, id: i.id, tabIndex: i.tabindex }, i.attributes, { disabled: (_d = (_c = i.attributes) === null || _c === void 0 ? void 0 : _c.disabled) !== null && _d !== void 0 ? _d : i.disabled, class: inputClass(i), onInput: (e) => {
var _a;
i.value = e.target.value;
if ((_a = i.attributes) === null || _a === void 0 ? void 0 : _a.onInput) {
i.attributes.onInput(e);
}
} }))));
}
})));
}
renderAlertButtons() {
const buttons = this.processedButtons;
const mode = getIonMode$1(this);
const alertButtonGroupClass = {
'alert-button-group': true,
'alert-button-group-vertical': buttons.length > 2,
};
return (hAsync("div", { class: alertButtonGroupClass }, buttons.map((button) => (hAsync("button", Object.assign({}, button.htmlAttributes, { type: "button", id: button.id, class: buttonClass$2(button), tabIndex: 0, onClick: () => this.buttonClick(button) }), hAsync("span", { class: "alert-button-inner" }, button.text), mode === 'md' && hAsync("ion-ripple-effect", null))))));
}
renderAlertMessage(msgId) {
const { customHTMLEnabled, message } = this;
if (customHTMLEnabled) {
return hAsync("div", { id: msgId, class: "alert-message", innerHTML: sanitizeDOMString(message) });
}
return (hAsync("div", { id: msgId, class: "alert-message" }, message));
}
render() {
const { overlayIndex, header, subHeader, message, htmlAttributes } = this;
const mode = getIonMode$1(this);
const hdrId = `alert-${overlayIndex}-hdr`;
const msgId = `alert-${overlayIndex}-msg`;
const subHdrId = `alert-${overlayIndex}-sub-hdr`;
const role = this.inputs.length > 0 || this.buttons.length > 0 ? 'alertdialog' : 'alert';
/**
* Use both the header and subHeader ids if they are defined.
* If only the header is defined, use the header id.
* If only the subHeader is defined, use the subHeader id.
* If neither are defined, do not set aria-labelledby.
*/
const ariaLabelledBy = header && subHeader ? `${hdrId} ${subHdrId}` : header ? hdrId : subHeader ? subHdrId : null;
return (hAsync(Host, { key: '6025440b9cd369d4fac89e7e4296c84a10a0b8e0', tabindex: "-1", style: {
zIndex: `${20000 + overlayIndex}`,
}, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'overlay-hidden': true, 'alert-translucent': this.translucent }), onIonAlertWillDismiss: this.dispatchCancelHandler, onIonBackdropTap: this.onBackdropTap }, hAsync("ion-backdrop", { key: '3cd5ca8b99cb95b11dd22ab41a820d841142896f', tappable: this.backdropDismiss }), hAsync("div", { key: '4cc62ae6e21424057d22aeef1e8fc77011e77cd5', tabindex: "0", "aria-hidden": "true" }), hAsync("div", Object.assign({ key: '364057a69f25aa88904df17bdcf7e5bf714e7830', class: "alert-wrapper ion-overlay-wrapper", role: role, "aria-modal": "true", "aria-labelledby": ariaLabelledBy, "aria-describedby": message !== undefined ? msgId : null, tabindex: "0", ref: (el) => (this.wrapperEl = el) }, htmlAttributes), hAsync("div", { key: '78694e3c0db2d408df3899fb1a90859bcc8d14cc', class: "alert-head" }, header && (hAsync("h2", { key: 'ec88ff3e4e1ea871b5975133fdcf4cac38b05e0f', id: hdrId, class: "alert-title" }, header)), subHeader && !header && (hAsync("h2", { key: '9b09bc8bb68af255ef8b7d22587acc946148e544', id: subHdrId, class: "alert-sub-title" }, subHeader)), subHeader && header && (hAsync("h3", { key: '99abe815f75d2df7f1b77c0df9f3436724fea76f', id: subHdrId, class: "alert-sub-title" }, subHeader))), this.renderAlertMessage(msgId), this.renderAlertInputs(), this.renderAlertButtons()), hAsync("div", { key: 'a43d0c22c0e46b1ef911f92ffeb253d7911b85f7', tabindex: "0", "aria-hidden": "true" })));
}
get el() { return getElement(this); }
static get watchers() { return {
"isOpen": ["onIsOpenChange"],
"trigger": ["triggerChanged"],
"buttons": ["buttonsChanged"],
"inputs": ["inputsChanged"]
}; }
static get style() { return {
ios: alertIosCss,
md: alertMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-alert",
"$members$": {
"overlayIndex": [2, "overlay-index"],
"delegate": [16],
"hasController": [4, "has-controller"],
"keyboardClose": [4, "keyboard-close"],
"enterAnimation": [16],
"leaveAnimation": [16],
"cssClass": [1, "css-class"],
"header": [1],
"subHeader": [1, "sub-header"],
"message": [1],
"buttons": [16],
"inputs": [1040],
"backdropDismiss": [4, "backdrop-dismiss"],
"translucent": [4],
"animated": [4],
"htmlAttributes": [16],
"isOpen": [4, "is-open"],
"trigger": [1],
"present": [64],
"dismiss": [64],
"onDidDismiss": [64],
"onWillDismiss": [64]
},
"$listeners$": [[4, "keydown", "onKeydown"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const inputClass = (input) => {
var _a, _b, _c;
return Object.assign(Object.assign({ 'alert-input': true, 'alert-input-disabled': ((_b = (_a = input.attributes) === null || _a === void 0 ? void 0 : _a.disabled) !== null && _b !== void 0 ? _b : input.disabled) || false }, getClassMap(input.cssClass)), getClassMap(input.attributes ? (_c = input.attributes.class) === null || _c === void 0 ? void 0 : _c.toString() : ''));
};
const buttonClass$2 = (button) => {
return Object.assign({ 'alert-button': true, 'ion-focusable': true, 'ion-activatable': true, [`alert-button-role-${button.role}`]: button.role !== undefined }, getClassMap(button.cssClass));
};
const appCss = "html.plt-mobile ion-app{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}html.plt-mobile ion-app [contenteditable]{-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}ion-app.force-statusbar-padding{--ion-safe-area-top:20px}";
class App {
constructor(hostRef) {
registerInstance(this, hostRef);
}
componentDidLoad() {
}
/**
* Used to set focus on an element that uses `ion-focusable`.
* Do not use this if focusing the element as a result of a keyboard
* event as the focus utility should handle this for us. This method
* should be used when we want to programmatically focus an element as
* a result of another user action. (Ex: We focus the first element
* inside of a popover when the user presents it, but the popover is not always
* presented as a result of keyboard action.)
*
* @param elements An array of HTML elements to set focus on.
*/
async setFocus(elements) {
if (this.focusVisible) {
this.focusVisible.setFocus(elements);
}
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '9be440c65819e4fa67c2c3c6477ab40b3ad3eed3', class: {
[mode]: true,
'ion-page': true,
'force-statusbar-padding': config.getBoolean('_forceStatusbarPadding'),
} }));
}
get el() { return getElement(this); }
static get style() { return appCss; }
static get cmpMeta() { return {
"$flags$": 256,
"$tagName$": "ion-app",
"$members$": {
"setFocus": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const avatarIosCss = ":host{border-radius:var(--border-radius);display:block}::slotted(ion-img),::slotted(img){border-radius:var(--border-radius);width:100%;height:100%;-o-object-fit:cover;object-fit:cover;overflow:hidden}:host{--border-radius:50%;width:48px;height:48px}";
const avatarMdCss = ":host{border-radius:var(--border-radius);display:block}::slotted(ion-img),::slotted(img){border-radius:var(--border-radius);width:100%;height:100%;-o-object-fit:cover;object-fit:cover;overflow:hidden}:host{--border-radius:50%;width:64px;height:64px}";
class Avatar {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
return (hAsync(Host, { key: '998217066084f966bf5d356fed85bcbd451f675a', class: getIonMode$1(this) }, hAsync("slot", { key: '1a6f7c9d4dc6a875f86b5b3cda6d59cb39587f22' })));
}
static get style() { return {
ios: avatarIosCss,
md: avatarMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-avatar",
"$members$": undefined,
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const backButtonIosCss = ":host{--background:transparent;--color-focused:currentColor;--color-hover:currentColor;--icon-margin-top:0;--icon-margin-bottom:0;--icon-padding-top:0;--icon-padding-end:0;--icon-padding-bottom:0;--icon-padding-start:0;--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--min-width:auto;--min-height:auto;--padding-top:0;--padding-end:0;--padding-bottom:0;--padding-start:0;--opacity:1;--ripple-color:currentColor;--transition:background-color, opacity 100ms linear;display:none;min-width:var(--min-width);min-height:var(--min-height);color:var(--color);font-family:var(--ion-font-family, inherit);text-align:center;text-decoration:none;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-font-kerning:none;font-kerning:none}ion-ripple-effect{color:var(--ripple-color)}:host(.ion-color) .button-native{color:var(--ion-color-base)}:host(.show-back-button){display:block}:host(.back-button-disabled){cursor:default;opacity:0.5;pointer-events:none}.button-native{border-radius:var(--border-radius);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:block;position:relative;width:100%;height:100%;min-height:inherit;-webkit-transition:var(--transition);transition:var(--transition);border:0;outline:none;background:var(--background);line-height:1;cursor:pointer;opacity:var(--opacity);overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}ion-icon{-webkit-padding-start:var(--icon-padding-start);padding-inline-start:var(--icon-padding-start);-webkit-padding-end:var(--icon-padding-end);padding-inline-end:var(--icon-padding-end);padding-top:var(--icon-padding-top);padding-bottom:var(--icon-padding-bottom);-webkit-margin-start:var(--icon-margin-start);margin-inline-start:var(--icon-margin-start);-webkit-margin-end:var(--icon-margin-end);margin-inline-end:var(--icon-margin-end);margin-top:var(--icon-margin-top);margin-bottom:var(--icon-margin-bottom);display:inherit;font-size:var(--icon-font-size);font-weight:var(--icon-font-weight);pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}}:host(.ion-color.ion-focused) .button-native{color:var(--ion-color-base)}@media (any-hover: hover){:host(.ion-color:hover) .button-native{color:var(--ion-color-base)}}:host(.in-toolbar:not(.in-toolbar-color)){color:var(--ion-toolbar-color, var(--color))}:host{--background-hover:transparent;--background-hover-opacity:1;--background-focused:currentColor;--background-focused-opacity:.1;--border-radius:4px;--color:var(--ion-color-primary, #0054e9);--icon-margin-end:1px;--icon-margin-start:-4px;--icon-font-size:1.6em;--min-height:32px;font-size:clamp(17px, 1.0625rem, 21.998px)}.button-native{-webkit-transform:translateZ(0);transform:translateZ(0);overflow:visible;z-index:99}:host(.ion-activated) .button-native{opacity:0.4}@media (any-hover: hover){:host(:hover){opacity:0.6}}";
const backButtonMdCss = ":host{--background:transparent;--color-focused:currentColor;--color-hover:currentColor;--icon-margin-top:0;--icon-margin-bottom:0;--icon-padding-top:0;--icon-padding-end:0;--icon-padding-bottom:0;--icon-padding-start:0;--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--min-width:auto;--min-height:auto;--padding-top:0;--padding-end:0;--padding-bottom:0;--padding-start:0;--opacity:1;--ripple-color:currentColor;--transition:background-color, opacity 100ms linear;display:none;min-width:var(--min-width);min-height:var(--min-height);color:var(--color);font-family:var(--ion-font-family, inherit);text-align:center;text-decoration:none;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-font-kerning:none;font-kerning:none}ion-ripple-effect{color:var(--ripple-color)}:host(.ion-color) .button-native{color:var(--ion-color-base)}:host(.show-back-button){display:block}:host(.back-button-disabled){cursor:default;opacity:0.5;pointer-events:none}.button-native{border-radius:var(--border-radius);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:block;position:relative;width:100%;height:100%;min-height:inherit;-webkit-transition:var(--transition);transition:var(--transition);border:0;outline:none;background:var(--background);line-height:1;cursor:pointer;opacity:var(--opacity);overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}ion-icon{-webkit-padding-start:var(--icon-padding-start);padding-inline-start:var(--icon-padding-start);-webkit-padding-end:var(--icon-padding-end);padding-inline-end:var(--icon-padding-end);padding-top:var(--icon-padding-top);padding-bottom:var(--icon-padding-bottom);-webkit-margin-start:var(--icon-margin-start);margin-inline-start:var(--icon-margin-start);-webkit-margin-end:var(--icon-margin-end);margin-inline-end:var(--icon-margin-end);margin-top:var(--icon-margin-top);margin-bottom:var(--icon-margin-bottom);display:inherit;font-size:var(--icon-font-size);font-weight:var(--icon-font-weight);pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}}:host(.ion-color.ion-focused) .button-native{color:var(--ion-color-base)}@media (any-hover: hover){:host(.ion-color:hover) .button-native{color:var(--ion-color-base)}}:host(.in-toolbar:not(.in-toolbar-color)){color:var(--ion-toolbar-color, var(--color))}:host{--border-radius:4px;--background-focused:currentColor;--background-focused-opacity:.12;--background-hover:currentColor;--background-hover-opacity:0.04;--color:currentColor;--icon-margin-end:0;--icon-margin-start:0;--icon-font-size:1.5rem;--icon-font-weight:normal;--min-height:32px;--min-width:44px;--padding-start:12px;--padding-end:12px;font-size:0.875rem;font-weight:500;text-transform:uppercase}:host(.back-button-has-icon-only){--border-radius:50%;min-width:48px;min-height:48px;aspect-ratio:1/1}.button-native{-webkit-box-shadow:none;box-shadow:none}.button-text{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:0;padding-bottom:0}ion-icon{line-height:0.67;text-align:start}@media (any-hover: hover){:host(.ion-color:hover) .button-native::after{background:var(--ion-color-base)}}:host(.ion-color.ion-focused) .button-native::after{background:var(--ion-color-base)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML button element that wraps all child elements.
* @part icon - The back button icon (uses ion-icon).
* @part text - The back button text.
*/
class BackButton {
constructor(hostRef) {
registerInstance(this, hostRef);
this.inheritedAttributes = {};
/**
* If `true`, the user cannot interact with the button.
*/
this.disabled = false;
/**
* The type of the button.
*/
this.type = 'button';
this.onClick = async (ev) => {
const nav = this.el.closest('ion-nav');
ev.preventDefault();
if (nav && (await nav.canGoBack())) {
return nav.pop({ animationBuilder: this.routerAnimation, skipIfBusy: true });
}
return openURL(this.defaultHref, ev, 'back', this.routerAnimation);
};
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
if (this.defaultHref === undefined) {
this.defaultHref = config.get('backButtonDefaultHref');
}
}
get backButtonIcon() {
const icon = this.icon;
if (icon != null) {
// icon is set on the component or by the config
return icon;
}
if (getIonMode$1(this) === 'ios') {
// default ios back button icon
return config.get('backButtonIcon', chevronBack);
}
// default md back button icon
return config.get('backButtonIcon', arrowBackSharp);
}
get backButtonText() {
const defaultBackButtonText = getIonMode$1(this) === 'ios' ? 'Back' : null;
return this.text != null ? this.text : config.get('backButtonText', defaultBackButtonText);
}
get hasIconOnly() {
return this.backButtonIcon && !this.backButtonText;
}
get rippleType() {
// If the button only has an icon we use the unbounded
// "circular" ripple effect
if (this.hasIconOnly) {
return 'unbounded';
}
return 'bounded';
}
render() {
const { color, defaultHref, disabled, type, hasIconOnly, backButtonIcon, backButtonText, icon, inheritedAttributes, } = this;
const showBackButton = defaultHref !== undefined;
const mode = getIonMode$1(this);
const ariaLabel = inheritedAttributes['aria-label'] || backButtonText || 'back';
return (hAsync(Host, { key: '5466624a10f1ab56f5469e6dc07080303880f2fe', onClick: this.onClick, class: createColorClasses$1(color, {
[mode]: true,
button: true, // ion-buttons target .button
'back-button-disabled': disabled,
'back-button-has-icon-only': hasIconOnly,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'ion-activatable': true,
'ion-focusable': true,
'show-back-button': showBackButton,
}) }, hAsync("button", { key: '63bc75ef0ad7cc9fb79e58217a3314b20acd73e3', type: type, disabled: disabled, class: "button-native", part: "native", "aria-label": ariaLabel }, hAsync("span", { key: '5d3eacbd11af2245c6e1151cab446a0d96559ad8', class: "button-inner" }, backButtonIcon && (hAsync("ion-icon", { key: '6439af0ae463764174e7d3207f02267811df666d', part: "icon", icon: backButtonIcon, "aria-hidden": "true", lazy: false, "flip-rtl": icon === undefined })), backButtonText && (hAsync("span", { key: '8ee89fb18dfdb5b75948a8b197ff4cdbc008742f', part: "text", "aria-hidden": "true", class: "button-text" }, backButtonText))), mode === 'md' && hAsync("ion-ripple-effect", { key: '63803a884998bc73bea5afe0b2a0a14e3fa4d6bf', type: this.rippleType }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: backButtonIosCss,
md: backButtonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-back-button",
"$members$": {
"color": [513],
"defaultHref": [1025, "default-href"],
"disabled": [516],
"icon": [1],
"text": [1],
"type": [1],
"routerAnimation": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["disabled", "disabled"]]
}; }
}
const backdropIosCss = ":host{left:0;right:0;top:0;bottom:0;display:block;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);contain:strict;cursor:pointer;opacity:0.01;-ms-touch-action:none;touch-action:none;z-index:2}:host(.backdrop-hide){background:transparent}:host(.backdrop-no-tappable){cursor:auto}:host{background-color:var(--ion-backdrop-color, #000)}";
const backdropMdCss = ":host{left:0;right:0;top:0;bottom:0;display:block;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);contain:strict;cursor:pointer;opacity:0.01;-ms-touch-action:none;touch-action:none;z-index:2}:host(.backdrop-hide){background:transparent}:host(.backdrop-no-tappable){cursor:auto}:host{background-color:var(--ion-backdrop-color, #000)}";
class Backdrop {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionBackdropTap = createEvent(this, "ionBackdropTap", 7);
/**
* If `true`, the backdrop will be visible.
*/
this.visible = true;
/**
* If `true`, the backdrop will can be clicked and will emit the `ionBackdropTap` event.
*/
this.tappable = true;
/**
* If `true`, the backdrop will stop propagation on tap.
*/
this.stopPropagation = true;
}
onMouseDown(ev) {
this.emitTap(ev);
}
emitTap(ev) {
if (this.stopPropagation) {
ev.preventDefault();
ev.stopPropagation();
}
if (this.tappable) {
this.ionBackdropTap.emit();
}
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '7abaf2c310aa399607451b14063265e8a5846938', "aria-hidden": "true", class: {
[mode]: true,
'backdrop-hide': !this.visible,
'backdrop-no-tappable': !this.tappable,
} }));
}
static get style() { return {
ios: backdropIosCss,
md: backdropMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-backdrop",
"$members$": {
"visible": [4],
"tappable": [4],
"stopPropagation": [4, "stop-propagation"]
},
"$listeners$": [[2, "click", "onMouseDown"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const badgeIosCss = ":host{--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff);--padding-top:3px;--padding-end:8px;--padding-bottom:3px;--padding-start:8px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:inline-block;min-width:10px;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);font-size:0.8125rem;font-weight:bold;line-height:1;text-align:center;white-space:nowrap;contain:content;vertical-align:baseline}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(:empty){display:none}:host{border-radius:10px;font-size:max(13px, 0.8125rem)}";
const badgeMdCss = ":host{--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff);--padding-top:3px;--padding-end:8px;--padding-bottom:3px;--padding-start:8px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:inline-block;min-width:10px;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);font-size:0.8125rem;font-weight:bold;line-height:1;text-align:center;white-space:nowrap;contain:content;vertical-align:baseline}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(:empty){display:none}:host{--padding-top:3px;--padding-end:4px;--padding-bottom:4px;--padding-start:4px;border-radius:4px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Badge {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '1a2d39c5deec771a2f2196447627b62a7d4c8389', class: createColorClasses$1(this.color, {
[mode]: true,
}) }, hAsync("slot", { key: 'fc1b6587f1ed24715748eb6785e7fb7a57cdd5cd' })));
}
static get style() { return {
ios: badgeIosCss,
md: badgeMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-badge",
"$members$": {
"color": [513]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const breadcrumbIosCss = ":host{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-align:center;align-items:center;color:var(--color);font-size:1rem;font-weight:400;line-height:1.5}.breadcrumb-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;width:100%;outline:none;background:inherit}:host(.breadcrumb-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.breadcrumb-active){color:var(--color-active)}:host(.ion-focused){color:var(--color-focused)}:host(.ion-focused) .breadcrumb-native{background:var(--background-focused)}@media (any-hover: hover){:host(.ion-activatable:hover){color:var(--color-hover)}:host(.ion-activatable.in-breadcrumbs-color:hover),:host(.ion-activatable.ion-color:hover){color:var(--ion-color-shade)}}.breadcrumb-separator{display:-ms-inline-flexbox;display:inline-flex}:host(.breadcrumb-collapsed) .breadcrumb-native{display:none}:host(.in-breadcrumbs-color),:host(.in-breadcrumbs-color.breadcrumb-active){color:var(--ion-color-base)}:host(.in-breadcrumbs-color) .breadcrumb-separator{color:var(--ion-color-base)}:host(.ion-color){color:var(--ion-color-base)}:host(.in-toolbar-color),:host(.in-toolbar-color) .breadcrumb-separator{color:rgba(var(--ion-color-contrast-rgb), 0.8)}:host(.in-toolbar-color.breadcrumb-active){color:var(--ion-color-contrast)}.breadcrumbs-collapsed-indicator{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:14px;margin-inline-end:14px;margin-top:0;margin-bottom:0;display:-ms-flexbox;display:flex;-ms-flex:1 1 100%;flex:1 1 100%;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:32px;height:18px;border:0;outline:none;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}.breadcrumbs-collapsed-indicator ion-icon{margin-top:1px;font-size:1.375rem}:host{--color:var(--ion-color-step-850, var(--ion-text-color-step-150, #2d4665));--color-active:var(--ion-text-color, #03060b);--color-hover:var(--ion-text-color, #03060b);--color-focused:var(--color-active);--background-focused:var(--ion-color-step-50, var(--ion-background-color-step-50, rgba(233, 237, 243, 0.7)));font-size:clamp(16px, 1rem, 22px)}:host(.breadcrumb-active){font-weight:600}.breadcrumb-native{border-radius:4px;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:5px;padding-bottom:5px;border:1px solid transparent}:host(.ion-focused) .breadcrumb-native{border-radius:8px}:host(.in-breadcrumbs-color.ion-focused) .breadcrumb-native,:host(.ion-color.ion-focused) .breadcrumb-native{background:rgba(var(--ion-color-base-rgb), 0.1);color:var(--ion-color-base)}:host(.ion-focused) ::slotted(ion-icon),:host(.in-breadcrumbs-color.ion-focused) ::slotted(ion-icon),:host(.ion-color.ion-focused) ::slotted(ion-icon){color:var(--ion-color-step-750, var(--ion-text-color-step-250, #445b78))}.breadcrumb-separator{color:var(--ion-color-step-550, var(--ion-text-color-step-450, #73849a))}::slotted(ion-icon){color:var(--ion-color-step-400, var(--ion-text-color-step-600, #92a0b3));font-size:min(1.125rem, 21.6px)}::slotted(ion-icon[slot=start]){-webkit-margin-end:8px;margin-inline-end:8px}::slotted(ion-icon[slot=end]){-webkit-margin-start:8px;margin-inline-start:8px}:host(.breadcrumb-active) ::slotted(ion-icon){color:var(--ion-color-step-850, var(--ion-text-color-step-150, #242d39))}.breadcrumbs-collapsed-indicator{border-radius:4px;background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e9edf3));color:var(--ion-color-step-550, var(--ion-text-color-step-450, #73849a))}.breadcrumbs-collapsed-indicator:hover{opacity:0.45}.breadcrumbs-collapsed-indicator:focus{background:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9e0ea))}.breadcrumbs-collapsed-indicator ion-icon{font-size:min(1.375rem, 22px)}";
const breadcrumbMdCss = ":host{display:-ms-flexbox;display:flex;-ms-flex:0 0 auto;flex:0 0 auto;-ms-flex-align:center;align-items:center;color:var(--color);font-size:1rem;font-weight:400;line-height:1.5}.breadcrumb-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;width:100%;outline:none;background:inherit}:host(.breadcrumb-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.breadcrumb-active){color:var(--color-active)}:host(.ion-focused){color:var(--color-focused)}:host(.ion-focused) .breadcrumb-native{background:var(--background-focused)}@media (any-hover: hover){:host(.ion-activatable:hover){color:var(--color-hover)}:host(.ion-activatable.in-breadcrumbs-color:hover),:host(.ion-activatable.ion-color:hover){color:var(--ion-color-shade)}}.breadcrumb-separator{display:-ms-inline-flexbox;display:inline-flex}:host(.breadcrumb-collapsed) .breadcrumb-native{display:none}:host(.in-breadcrumbs-color),:host(.in-breadcrumbs-color.breadcrumb-active){color:var(--ion-color-base)}:host(.in-breadcrumbs-color) .breadcrumb-separator{color:var(--ion-color-base)}:host(.ion-color){color:var(--ion-color-base)}:host(.in-toolbar-color),:host(.in-toolbar-color) .breadcrumb-separator{color:rgba(var(--ion-color-contrast-rgb), 0.8)}:host(.in-toolbar-color.breadcrumb-active){color:var(--ion-color-contrast)}.breadcrumbs-collapsed-indicator{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:14px;margin-inline-end:14px;margin-top:0;margin-bottom:0;display:-ms-flexbox;display:flex;-ms-flex:1 1 100%;flex:1 1 100%;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:32px;height:18px;border:0;outline:none;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}.breadcrumbs-collapsed-indicator ion-icon{margin-top:1px;font-size:1.375rem}:host{--color:var(--ion-color-step-600, var(--ion-text-color-step-400, #677483));--color-active:var(--ion-text-color, #03060b);--color-hover:var(--ion-text-color, #03060b);--color-focused:var(--ion-color-step-800, var(--ion-text-color-step-200, #35404e));--background-focused:var(--ion-color-step-50, var(--ion-background-color-step-50, #fff))}:host(.breadcrumb-active){font-weight:500}.breadcrumb-native{-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px}.breadcrumb-separator{-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:-1px}:host(.ion-focused) .breadcrumb-native{border-radius:4px;-webkit-box-shadow:0px 1px 2px rgba(0, 0, 0, 0.2), 0px 2px 8px rgba(0, 0, 0, 0.12);box-shadow:0px 1px 2px rgba(0, 0, 0, 0.2), 0px 2px 8px rgba(0, 0, 0, 0.12)}.breadcrumb-separator{color:var(--ion-color-step-550, var(--ion-text-color-step-450, #73849a))}::slotted(ion-icon){color:var(--ion-color-step-550, var(--ion-text-color-step-450, #7d8894));font-size:1.125rem}::slotted(ion-icon[slot=start]){-webkit-margin-end:8px;margin-inline-end:8px}::slotted(ion-icon[slot=end]){-webkit-margin-start:8px;margin-inline-start:8px}:host(.breadcrumb-active) ::slotted(ion-icon){color:var(--ion-color-step-850, var(--ion-text-color-step-150, #222d3a))}.breadcrumbs-collapsed-indicator{border-radius:2px;background:var(--ion-color-step-100, var(--ion-background-color-step-100, #eef1f3));color:var(--ion-color-step-550, var(--ion-text-color-step-450, #73849a))}.breadcrumbs-collapsed-indicator:hover{opacity:0.7}.breadcrumbs-collapsed-indicator:focus{background:var(--ion-color-step-150, var(--ion-background-color-step-150, #dfe5e8))}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML anchor or div element that wraps all child elements.
* @part separator - The separator element between each breadcrumb.
* @part collapsed-indicator - The indicator element that shows the breadcrumbs are collapsed.
*/
class Breadcrumb {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.collapsedClick = createEvent(this, "collapsedClick", 7);
this.inheritedAttributes = {};
/** @internal */
this.collapsed = false;
/**
* If `true`, the breadcrumb will take on a different look to show that
* it is the currently active breadcrumb. Defaults to `true` for the
* last breadcrumb if it is not set on any.
*/
this.active = false;
/**
* If `true`, the user cannot interact with the breadcrumb.
*/
this.disabled = false;
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
*/
this.routerDirection = 'forward';
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
this.collapsedIndicatorClick = () => {
this.collapsedClick.emit({ ionShadowTarget: this.collapsedRef });
};
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
isClickable() {
return this.href !== undefined;
}
render() {
const { color, active, collapsed, disabled, download, el, inheritedAttributes, last, routerAnimation, routerDirection, separator, showCollapsedIndicator, target, } = this;
const clickable = this.isClickable();
const TagType = this.href === undefined ? 'span' : 'a';
// Links can still be tabbed to when set to disabled if they have an href
// in order to truly disable them we can keep it as an anchor but remove the href
const href = disabled ? undefined : this.href;
const mode = getIonMode$1(this);
const attrs = TagType === 'span'
? {}
: {
download,
href,
target,
};
// If the breadcrumb is collapsed, check if it contains the collapsed indicator
// to show the separator as long as it isn't also the last breadcrumb
// otherwise if not collapsed use the value in separator
const showSeparator = last ? false : collapsed ? (showCollapsedIndicator && !last ? true : false) : separator;
return (hAsync(Host, { key: '32ca61c83721dff52b5e97171ed449dce3584a55', onClick: (ev) => openURL(href, ev, routerDirection, routerAnimation), "aria-disabled": disabled ? 'true' : null, class: createColorClasses$1(color, {
[mode]: true,
'breadcrumb-active': active,
'breadcrumb-collapsed': collapsed,
'breadcrumb-disabled': disabled,
'in-breadcrumbs-color': hostContext('ion-breadcrumbs[color]', el),
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'ion-activatable': clickable,
'ion-focusable': clickable,
}) }, hAsync(TagType, Object.assign({ key: '479feb845f4a6d8009d5422b33eb423730b9722b' }, attrs, { class: "breadcrumb-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), hAsync("slot", { key: '3c5dcaeb0d258235d1b7707868026ff1d1404099', name: "start" }), hAsync("slot", { key: 'f1cfb934443cd97dc220882c5e3596ea879d66cf' }), hAsync("slot", { key: '539710121b5b1f3ee8d4c24a9651b67c2ae08add', name: "end" })), showCollapsedIndicator && (hAsync("button", { key: 'ed53a95ccd89022c8b7bee0658a221ec62a5c73b', part: "collapsed-indicator", "aria-label": "Show more breadcrumbs", onClick: () => this.collapsedIndicatorClick(), ref: (collapsedEl) => (this.collapsedRef = collapsedEl), class: {
'breadcrumbs-collapsed-indicator': true,
} }, hAsync("ion-icon", { key: 'a849e1142a86f06f207cf11662fa2a560ab7fc6a', "aria-hidden": "true", icon: ellipsisHorizontal, lazy: false }))), showSeparator && (
/**
* Separators should not be announced by narrators.
* We add aria-hidden on the span so that this applies
* to any custom separators too.
*/
hAsync("span", { key: 'fc3c741cb01fafef8b26046c7ee5b190efc69a7c', class: "breadcrumb-separator", part: "separator", "aria-hidden": "true" }, hAsync("slot", { key: '4871932ae1dae520767e0713e7cee2d11b0bba6d', name: "separator" }, mode === 'ios' ? (hAsync("ion-icon", { icon: chevronForwardOutline, lazy: false, "flip-rtl": true })) : (hAsync("span", null, "/")))))));
}
get el() { return getElement(this); }
static get style() { return {
ios: breadcrumbIosCss,
md: breadcrumbMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-breadcrumb",
"$members$": {
"collapsed": [4],
"last": [4],
"showCollapsedIndicator": [4, "show-collapsed-indicator"],
"color": [1],
"active": [4],
"disabled": [4],
"download": [1],
"href": [1],
"rel": [1],
"separator": [4],
"target": [1],
"routerDirection": [1, "router-direction"],
"routerAnimation": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const breadcrumbsIosCss = ":host{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center}:host(.in-toolbar-color),:host(.in-toolbar-color) .breadcrumbs-collapsed-indicator ion-icon{color:var(--ion-color-contrast)}:host(.in-toolbar-color) .breadcrumbs-collapsed-indicator{background:rgba(var(--ion-color-contrast-rgb), 0.11)}:host(.in-toolbar){-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px;padding-top:0;padding-bottom:0;-ms-flex-pack:center;justify-content:center}";
const breadcrumbsMdCss = ":host{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center}:host(.in-toolbar-color),:host(.in-toolbar-color) .breadcrumbs-collapsed-indicator ion-icon{color:var(--ion-color-contrast)}:host(.in-toolbar-color) .breadcrumbs-collapsed-indicator{background:rgba(var(--ion-color-contrast-rgb), 0.11)}:host(.in-toolbar){-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:0;padding-bottom:0}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
*/
class Breadcrumbs {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionCollapsedClick = createEvent(this, "ionCollapsedClick", 7);
/**
* The number of breadcrumbs to show before the collapsed indicator.
* If `itemsBeforeCollapse` + `itemsAfterCollapse` is greater than `maxItems`,
* the breadcrumbs will not be collapsed.
*/
this.itemsBeforeCollapse = 1;
/**
* The number of breadcrumbs to show after the collapsed indicator.
* If `itemsBeforeCollapse` + `itemsAfterCollapse` is greater than `maxItems`,
* the breadcrumbs will not be collapsed.
*/
this.itemsAfterCollapse = 1;
this.breadcrumbsInit = () => {
this.setBreadcrumbSeparator();
this.setMaxItems();
};
this.resetActiveBreadcrumb = () => {
const breadcrumbs = this.getBreadcrumbs();
// Only reset the active breadcrumb if we were the ones to change it
// otherwise use the one set on the component
const activeBreadcrumb = breadcrumbs.find((breadcrumb) => breadcrumb.active);
if (activeBreadcrumb && this.activeChanged) {
activeBreadcrumb.active = false;
}
};
this.setMaxItems = () => {
const { itemsAfterCollapse, itemsBeforeCollapse, maxItems } = this;
const breadcrumbs = this.getBreadcrumbs();
for (const breadcrumb of breadcrumbs) {
breadcrumb.showCollapsedIndicator = false;
breadcrumb.collapsed = false;
}
// If the number of breadcrumbs exceeds the maximum number of items
// that should show and the items before / after collapse do not
// exceed the maximum items then we need to collapse the breadcrumbs
const shouldCollapse = maxItems !== undefined && breadcrumbs.length > maxItems && itemsBeforeCollapse + itemsAfterCollapse <= maxItems;
if (shouldCollapse) {
// Show the collapsed indicator in the first breadcrumb that collapses
breadcrumbs.forEach((breadcrumb, index) => {
if (index === itemsBeforeCollapse) {
breadcrumb.showCollapsedIndicator = true;
}
// Collapse all breadcrumbs that have an index greater than or equal to
// the number before collapse and an index less than the total number
// of breadcrumbs minus the items that should show after the collapse
if (index >= itemsBeforeCollapse && index < breadcrumbs.length - itemsAfterCollapse) {
breadcrumb.collapsed = true;
}
});
}
};
this.setBreadcrumbSeparator = () => {
const { itemsAfterCollapse, itemsBeforeCollapse, maxItems } = this;
const breadcrumbs = this.getBreadcrumbs();
// Check if an active breadcrumb exists already
const active = breadcrumbs.find((breadcrumb) => breadcrumb.active);
// Set the separator on all but the last breadcrumb
for (const breadcrumb of breadcrumbs) {
// The only time the last breadcrumb changes is when
// itemsAfterCollapse is set to 0, in this case the
// last breadcrumb will be the collapsed indicator
const last = maxItems !== undefined && itemsAfterCollapse === 0
? breadcrumb === breadcrumbs[itemsBeforeCollapse]
: breadcrumb === breadcrumbs[breadcrumbs.length - 1];
breadcrumb.last = last;
// If the breadcrumb has defined whether or not to show the
// separator then use that value, otherwise check if it's the
// last breadcrumb
const separator = breadcrumb.separator !== undefined ? breadcrumb.separator : last ? undefined : true;
breadcrumb.separator = separator;
// If there is not an active breadcrumb already
// set the last one to active
if (!active && last) {
breadcrumb.active = true;
this.activeChanged = true;
}
}
};
this.getBreadcrumbs = () => {
return Array.from(this.el.querySelectorAll('ion-breadcrumb'));
};
this.slotChanged = () => {
this.resetActiveBreadcrumb();
this.breadcrumbsInit();
};
}
onCollapsedClick(ev) {
const breadcrumbs = this.getBreadcrumbs();
const collapsedBreadcrumbs = breadcrumbs.filter((breadcrumb) => breadcrumb.collapsed);
this.ionCollapsedClick.emit(Object.assign(Object.assign({}, ev.detail), { collapsedBreadcrumbs }));
}
maxItemsChanged() {
this.resetActiveBreadcrumb();
this.breadcrumbsInit();
}
componentWillLoad() {
this.breadcrumbsInit();
}
render() {
const { color, collapsed } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'fe64e9cdf597ede2db140bf5fa05a0359d82db57', class: createColorClasses$1(color, {
[mode]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'breadcrumbs-collapsed': collapsed,
}) }, hAsync("slot", { key: 'a2c99b579e339055c50a613d5c6b61032f5ddffe', onSlotchange: this.slotChanged })));
}
get el() { return getElement(this); }
static get watchers() { return {
"maxItems": ["maxItemsChanged"],
"itemsBeforeCollapse": ["maxItemsChanged"],
"itemsAfterCollapse": ["maxItemsChanged"]
}; }
static get style() { return {
ios: breadcrumbsIosCss,
md: breadcrumbsMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-breadcrumbs",
"$members$": {
"color": [513],
"maxItems": [2, "max-items"],
"itemsBeforeCollapse": [2, "items-before-collapse"],
"itemsAfterCollapse": [2, "items-after-collapse"],
"collapsed": [32],
"activeChanged": [32]
},
"$listeners$": [[0, "collapsedClick", "onCollapsedClick"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const buttonIosCss = ":host{--overflow:hidden;--ripple-color:currentColor;--border-width:initial;--border-color:initial;--border-style:initial;--color-activated:var(--color);--color-focused:var(--color);--color-hover:var(--color);--box-shadow:none;display:inline-block;width:auto;color:var(--color);font-family:var(--ion-font-family, inherit);text-align:center;text-decoration:none;white-space:normal;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top;vertical-align:-webkit-baseline-middle;-webkit-font-kerning:none;font-kerning:none}:host(.button-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.button-solid){--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff)}:host(.button-outline){--border-color:var(--ion-color-primary, #0054e9);--background:transparent;--color:var(--ion-color-primary, #0054e9)}:host(.button-clear){--border-width:0;--background:transparent;--color:var(--ion-color-primary, #0054e9)}:host(.button-block){display:block}:host(.button-block) .button-native{margin-left:0;margin-right:0;width:100%;clear:both;contain:content}:host(.button-block) .button-native::after{clear:both}:host(.button-full){display:block}:host(.button-full) .button-native{margin-left:0;margin-right:0;width:100%;contain:content}:host(.button-full:not(.button-round)) .button-native{border-radius:0;border-right-width:0;border-left-width:0}.button-native{border-radius:var(--border-radius);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;width:100%;height:100%;min-height:inherit;-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:var(--background);line-height:1;-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);contain:layout style;cursor:pointer;opacity:var(--opacity);overflow:var(--overflow);z-index:0;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}.button-native::-moz-focus-inner{border:0}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}::slotted([slot=start]),::slotted([slot=end]){-ms-flex-negative:0;flex-shrink:0}::slotted(ion-icon){font-size:1.35em;pointer-events:none}::slotted(ion-icon[slot=start]){-webkit-margin-start:-0.3em;margin-inline-start:-0.3em;-webkit-margin-end:0.3em;margin-inline-end:0.3em;margin-top:0;margin-bottom:0}::slotted(ion-icon[slot=end]){-webkit-margin-start:0.3em;margin-inline-start:0.3em;-webkit-margin-end:-0.2em;margin-inline-end:-0.2em;margin-top:0;margin-bottom:0}ion-ripple-effect{color:var(--ripple-color)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}:host(.ion-focused){color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}@media (any-hover: hover){:host(:hover){color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}}:host(.ion-activated){color:var(--color-activated)}:host(.ion-activated) .button-native::after{background:var(--background-activated);opacity:var(--background-activated-opacity)}:host(.button-solid.ion-color) .button-native{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.button-outline.ion-color) .button-native{border-color:var(--ion-color-base);background:transparent;color:var(--ion-color-base)}:host(.button-clear.ion-color) .button-native{background:transparent;color:var(--ion-color-base)}:host(.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{color:var(--ion-toolbar-color, var(--color))}:host(.button-outline.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{border-color:var(--ion-toolbar-color, var(--color, var(--border-color)))}:host(.button-solid.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{background:var(--ion-toolbar-color, var(--background));color:var(--ion-toolbar-background, var(--color))}:host{--border-radius:14px;--padding-top:13px;--padding-bottom:13px;--padding-start:1em;--padding-end:1em;--transition:background-color, opacity 100ms linear;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;margin-top:4px;margin-bottom:4px;min-height:3.1em;font-size:min(1rem, 48px);font-weight:500;letter-spacing:0}:host(.button-solid){--background-activated:var(--ion-color-primary-shade, #004acd);--background-focused:var(--ion-color-primary-shade, #004acd);--background-hover:var(--ion-color-primary-tint, #1a65eb);--background-activated-opacity:1;--background-focused-opacity:1;--background-hover-opacity:1}:host(.button-outline){--border-radius:14px;--border-width:1px;--border-style:solid;--background-activated:var(--ion-color-primary, #0054e9);--background-focused:var(--ion-color-primary, #0054e9);--background-hover:transparent;--background-focused-opacity:.1;--color-activated:var(--ion-color-primary-contrast, #fff)}:host(.button-clear){--background-activated:transparent;--background-activated-opacity:0;--background-focused:var(--ion-color-primary, #0054e9);--background-hover:transparent;--background-focused-opacity:.1;font-size:min(1.0625rem, 51px);font-weight:normal}:host(.in-buttons){font-size:clamp(17px, 1.0625rem, 21.08px);font-weight:400}:host(.button-large){--border-radius:16px;--padding-top:17px;--padding-start:1em;--padding-end:1em;--padding-bottom:17px;min-height:3.1em;font-size:min(1.25rem, 60px)}:host(.button-small){--border-radius:6px;--padding-top:4px;--padding-start:0.9em;--padding-end:0.9em;--padding-bottom:4px;min-height:2.1em;font-size:min(0.8125rem, 39px)}:host(.button-round){--border-radius:999px;--padding-top:0;--padding-start:26px;--padding-end:26px;--padding-bottom:0}:host(.button-strong){font-weight:600}:host(.button-has-icon-only){--padding-top:0;--padding-bottom:var(--padding-top);--padding-end:var(--padding-top);--padding-start:var(--padding-end);min-width:clamp(30px, 2.125em, 60px);min-height:clamp(30px, 2.125em, 60px)}::slotted(ion-icon[slot=icon-only]){font-size:clamp(15.12px, 1.125em, 43.02px)}:host(.button-small.button-has-icon-only){min-width:clamp(23px, 2.16em, 54px);min-height:clamp(23px, 2.16em, 54px)}:host(.button-small) ::slotted(ion-icon[slot=icon-only]){font-size:clamp(12.1394px, 1.308125em, 40.1856px)}:host(.button-large.button-has-icon-only){min-width:clamp(46px, 2.5em, 78px);min-height:clamp(46px, 2.5em, 78px)}:host(.button-large) ::slotted(ion-icon[slot=icon-only]){font-size:clamp(15.12px, 0.9em, 43.056px)}:host(.button-outline.ion-focused.ion-color) .button-native,:host(.button-clear.ion-focused.ion-color) .button-native{color:var(--ion-color-base)}:host(.button-outline.ion-focused.ion-color) .button-native::after,:host(.button-clear.ion-focused.ion-color) .button-native::after{background:var(--ion-color-base)}:host(.button-solid.ion-color.ion-focused) .button-native::after{background:var(--ion-color-shade)}@media (any-hover: hover){:host(.button-clear:not(.ion-activated):hover),:host(.button-outline:not(.ion-activated):hover){opacity:0.6}:host(.button-clear.ion-color:hover) .button-native,:host(.button-outline.ion-color:hover) .button-native{color:var(--ion-color-base)}:host(.button-clear.ion-color:hover) .button-native::after,:host(.button-outline.ion-color:hover) .button-native::after{background:transparent}:host(.button-solid.ion-color:hover) .button-native::after{background:var(--ion-color-tint)}:host(:hover.button-solid.in-toolbar:not(.ion-color):not(.in-toolbar-color):not(.ion-activated)) .button-native::after{background:#fff;opacity:0.1}}:host(.button-clear.ion-activated){opacity:0.4}:host(.button-outline.ion-activated.ion-color) .button-native{color:var(--ion-color-contrast)}:host(.button-outline.ion-activated.ion-color) .button-native::after{background:var(--ion-color-base)}:host(.button-solid.ion-color.ion-activated) .button-native::after{background:var(--ion-color-shade)}:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{background:var(--ion-toolbar-color, var(--color));color:var(--ion-toolbar-background, var(--background), var(--ion-color-primary-contrast, #fff))}";
const buttonMdCss = ":host{--overflow:hidden;--ripple-color:currentColor;--border-width:initial;--border-color:initial;--border-style:initial;--color-activated:var(--color);--color-focused:var(--color);--color-hover:var(--color);--box-shadow:none;display:inline-block;width:auto;color:var(--color);font-family:var(--ion-font-family, inherit);text-align:center;text-decoration:none;white-space:normal;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:top;vertical-align:-webkit-baseline-middle;-webkit-font-kerning:none;font-kerning:none}:host(.button-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.button-solid){--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff)}:host(.button-outline){--border-color:var(--ion-color-primary, #0054e9);--background:transparent;--color:var(--ion-color-primary, #0054e9)}:host(.button-clear){--border-width:0;--background:transparent;--color:var(--ion-color-primary, #0054e9)}:host(.button-block){display:block}:host(.button-block) .button-native{margin-left:0;margin-right:0;width:100%;clear:both;contain:content}:host(.button-block) .button-native::after{clear:both}:host(.button-full){display:block}:host(.button-full) .button-native{margin-left:0;margin-right:0;width:100%;contain:content}:host(.button-full:not(.button-round)) .button-native{border-radius:0;border-right-width:0;border-left-width:0}.button-native{border-radius:var(--border-radius);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;width:100%;height:100%;min-height:inherit;-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:var(--background);line-height:1;-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);contain:layout style;cursor:pointer;opacity:var(--opacity);overflow:var(--overflow);z-index:0;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}.button-native::-moz-focus-inner{border:0}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}::slotted([slot=start]),::slotted([slot=end]){-ms-flex-negative:0;flex-shrink:0}::slotted(ion-icon){font-size:1.35em;pointer-events:none}::slotted(ion-icon[slot=start]){-webkit-margin-start:-0.3em;margin-inline-start:-0.3em;-webkit-margin-end:0.3em;margin-inline-end:0.3em;margin-top:0;margin-bottom:0}::slotted(ion-icon[slot=end]){-webkit-margin-start:0.3em;margin-inline-start:0.3em;-webkit-margin-end:-0.2em;margin-inline-end:-0.2em;margin-top:0;margin-bottom:0}ion-ripple-effect{color:var(--ripple-color)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}:host(.ion-focused){color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}@media (any-hover: hover){:host(:hover){color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}}:host(.ion-activated){color:var(--color-activated)}:host(.ion-activated) .button-native::after{background:var(--background-activated);opacity:var(--background-activated-opacity)}:host(.button-solid.ion-color) .button-native{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.button-outline.ion-color) .button-native{border-color:var(--ion-color-base);background:transparent;color:var(--ion-color-base)}:host(.button-clear.ion-color) .button-native{background:transparent;color:var(--ion-color-base)}:host(.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{color:var(--ion-toolbar-color, var(--color))}:host(.button-outline.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{border-color:var(--ion-toolbar-color, var(--color, var(--border-color)))}:host(.button-solid.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{background:var(--ion-toolbar-color, var(--background));color:var(--ion-toolbar-background, var(--color))}:host{--border-radius:4px;--padding-top:8px;--padding-bottom:8px;--padding-start:1.1em;--padding-end:1.1em;--transition:box-shadow 280ms cubic-bezier(.4, 0, .2, 1),\n background-color 15ms linear,\n color 15ms linear;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;margin-top:4px;margin-bottom:4px;min-height:36px;font-size:0.875rem;font-weight:500;letter-spacing:0.06em;text-transform:uppercase}:host(.button-solid){--background-activated:transparent;--background-hover:var(--ion-color-primary-contrast, #fff);--background-focused:var(--ion-color-primary-contrast, #fff);--background-activated-opacity:0;--background-focused-opacity:.24;--background-hover-opacity:.08;--box-shadow:0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12)}:host(.button-solid.ion-activated){--box-shadow:0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12)}:host(.button-outline){--border-width:2px;--border-style:solid;--box-shadow:none;--background-activated:transparent;--background-focused:var(--ion-color-primary, #0054e9);--background-hover:var(--ion-color-primary, #0054e9);--background-activated-opacity:0;--background-focused-opacity:.12;--background-hover-opacity:.04}:host(.button-outline.ion-activated.ion-color) .button-native{background:transparent}:host(.button-clear){--background-activated:transparent;--background-focused:var(--ion-color-primary, #0054e9);--background-hover:var(--ion-color-primary, #0054e9);--background-activated-opacity:0;--background-focused-opacity:.12;--background-hover-opacity:.04}:host(.button-round){--border-radius:999px;--padding-top:0;--padding-start:26px;--padding-end:26px;--padding-bottom:0}:host(.button-large){--padding-top:14px;--padding-start:1em;--padding-end:1em;--padding-bottom:14px;min-height:2.8em;font-size:1.25rem}:host(.button-small){--padding-top:4px;--padding-start:0.9em;--padding-end:0.9em;--padding-bottom:4px;min-height:2.1em;font-size:0.8125rem}:host(.button-strong){font-weight:bold}:host(.button-has-icon-only){--padding-top:0;--padding-bottom:var(--padding-top);--padding-end:var(--padding-top);--padding-start:var(--padding-end);min-width:clamp(30px, 2.86em, 60px);min-height:clamp(30px, 2.86em, 60px)}::slotted(ion-icon[slot=icon-only]){font-size:clamp(15.104px, 1.6em, 43.008px)}:host(.button-small.button-has-icon-only){min-width:clamp(23px, 2.16em, 54px);min-height:clamp(23px, 2.16em, 54px)}:host(.button-small) ::slotted(ion-icon[slot=icon-only]){font-size:clamp(13.002px, 1.23125em, 40.385px)}:host(.button-large.button-has-icon-only){min-width:clamp(46px, 2.5em, 78px);min-height:clamp(46px, 2.5em, 78px)}:host(.button-large) ::slotted(ion-icon[slot=icon-only]){font-size:clamp(15.008px, 1.4em, 43.008px)}:host(.button-solid.ion-color.ion-focused) .button-native::after{background:var(--ion-color-contrast)}:host(.button-clear.ion-color.ion-focused) .button-native::after,:host(.button-outline.ion-color.ion-focused) .button-native::after{background:var(--ion-color-base)}@media (any-hover: hover){:host(.button-solid.ion-color:hover) .button-native::after{background:var(--ion-color-contrast)}:host(.button-clear.ion-color:hover) .button-native::after,:host(.button-outline.ion-color:hover) .button-native::after{background:var(--ion-color-base)}}:host(.button-outline.ion-activated.in-toolbar:not(.ion-color):not(.in-toolbar-color)) .button-native{background:var(--ion-toolbar-background, var(--color));color:var(--ion-toolbar-color, var(--background), var(--ion-color-primary-contrast, #fff))}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot icon-only - Should be used on an icon in a button that has no text.
* @slot start - Content is placed to the left of the button text in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the button text in LTR, and to the left in RTL.
*
* @part native - The native HTML button or anchor element that wraps all child elements.
*/
class Button {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.inItem = false;
this.inListHeader = false;
this.inToolbar = false;
this.formButtonEl = null;
this.formEl = null;
this.inheritedAttributes = {};
/**
* If `true`, the button only has an icon.
*/
this.isCircle = false;
/**
* The type of button.
*/
this.buttonType = 'button';
/**
* If `true`, the user cannot interact with the button.
*/
this.disabled = false;
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
*/
this.routerDirection = 'forward';
/**
* If `true`, activates a button with a heavier font weight.
*/
this.strong = false;
/**
* The type of the button.
*/
this.type = 'button';
this.handleClick = (ev) => {
const { el } = this;
if (this.type === 'button') {
openURL(this.href, ev, this.routerDirection, this.routerAnimation);
}
else if (hasShadowDom(el)) {
this.submitForm(ev);
}
};
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
this.slotChanged = () => {
/**
* Ensures that the 'has-icon-only' class is properly added
* or removed from `ion-button` when manipulating the
* `icon-only` slot.
*
* Without this, the 'has-icon-only' class is only checked
* or added when `ion-button` component first renders.
*/
this.isCircle = this.hasIconOnly;
};
}
disabledChanged() {
const { disabled } = this;
if (this.formButtonEl) {
this.formButtonEl.disabled = disabled;
}
}
/**
* This component is used within the `ion-input-password-toggle` component
* to toggle the visibility of the password input.
* These attributes need to update based on the state of the password input.
* Otherwise, the values will be stale.
*
* @param newValue
* @param _oldValue
* @param propName
*/
onAriaChanged(newValue, _oldValue, propName) {
this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { [propName]: newValue });
}
/**
* This is responsible for rendering a hidden native
* button element inside the associated form. This allows
* users to submit a form by pressing "Enter" when a text
* field inside of the form is focused. The native button
* rendered inside of `ion-button` is in the Shadow DOM
* and therefore does not participate in form submission
* which is why the following code is necessary.
*/
renderHiddenButton() {
const formEl = (this.formEl = this.findForm());
if (formEl) {
const { formButtonEl } = this;
/**
* If the form already has a rendered form button
* then do not append a new one again.
*/
if (formButtonEl !== null && formEl.contains(formButtonEl)) {
return;
}
// Create a hidden native button inside of the form
const newFormButtonEl = (this.formButtonEl = document.createElement('button'));
newFormButtonEl.type = this.type;
newFormButtonEl.style.display = 'none';
// Only submit if the button is not disabled.
newFormButtonEl.disabled = this.disabled;
formEl.appendChild(newFormButtonEl);
}
}
componentWillLoad() {
this.inToolbar = !!this.el.closest('ion-buttons');
this.inListHeader = !!this.el.closest('ion-list-header');
this.inItem = !!this.el.closest('ion-item') || !!this.el.closest('ion-item-divider');
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
get hasIconOnly() {
return !!this.el.querySelector('[slot="icon-only"]');
}
get rippleType() {
const hasClearFill = this.fill === undefined || this.fill === 'clear';
// If the button is in a toolbar, has a clear fill (which is the default)
// and only has an icon we use the unbounded "circular" ripple effect
if (hasClearFill && this.hasIconOnly && this.inToolbar) {
return 'unbounded';
}
return 'bounded';
}
/**
* Finds the form element based on the provided `form` selector
* or element reference provided.
*/
findForm() {
const { form } = this;
if (form instanceof HTMLFormElement) {
return form;
}
if (typeof form === 'string') {
// Check if the string provided is a form id.
const el = document.getElementById(form);
if (el) {
if (el instanceof HTMLFormElement) {
return el;
}
else {
/**
* The developer specified a string for the form attribute, but the
* element with that id is not a form element.
*/
printIonWarning(`[ion-button] - Form with selector: "#${form}" could not be found. Verify that the id is attached to a <form> element.`, this.el);
return null;
}
}
else {
/**
* The developer specified a string for the form attribute, but the
* element with that id could not be found in the DOM.
*/
printIonWarning(`[ion-button] - Form with selector: "#${form}" could not be found. Verify that the id is correct and the form is rendered in the DOM.`, this.el);
return null;
}
}
if (form !== undefined) {
/**
* The developer specified a HTMLElement for the form attribute,
* but the element is not a HTMLFormElement.
* This will also catch if the developer tries to pass in null
* as the form attribute.
*/
printIonWarning(`[ion-button] - The provided "form" element is invalid. Verify that the form is a HTMLFormElement and rendered in the DOM.`, this.el);
return null;
}
/**
* If the form element is not set, the button may be inside
* of a form element. Query the closest form element to the button.
*/
return this.el.closest('form');
}
submitForm(ev) {
// this button wants to specifically submit a form
// climb up the dom to see if we're in a <form>
// and if so, then use JS to submit it
if (this.formEl && this.formButtonEl) {
ev.preventDefault();
this.formButtonEl.click();
}
}
render() {
const mode = getIonMode$1(this);
const { buttonType, type, disabled, rel, target, size, href, color, expand, hasIconOnly, shape, strong, inheritedAttributes, } = this;
const finalSize = size === undefined && this.inItem ? 'small' : size;
const TagType = href === undefined ? 'button' : 'a';
const attrs = TagType === 'button'
? { type }
: {
download: this.download,
href,
rel,
target,
};
let fill = this.fill;
if (fill === undefined) {
fill = this.inToolbar || this.inListHeader ? 'clear' : 'solid';
}
/**
* We call renderHiddenButton in the render function to account
* for any properties being set async. For example, changing the
* "type" prop from "button" to "submit" after the component has
* loaded would warrant the hidden button being added to the
* associated form.
*/
{
type !== 'button' && this.renderHiddenButton();
}
return (hAsync(Host, { key: 'ed82ea53705523f9afc5f1a9addff44cc6424f27', onClick: this.handleClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses$1(color, {
[mode]: true,
[buttonType]: true,
[`${buttonType}-${expand}`]: expand !== undefined,
[`${buttonType}-${finalSize}`]: finalSize !== undefined,
[`${buttonType}-${shape}`]: shape !== undefined,
[`${buttonType}-${fill}`]: true,
[`${buttonType}-strong`]: strong,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'in-buttons': hostContext('ion-buttons', this.el),
'button-has-icon-only': hasIconOnly,
'button-disabled': disabled,
'ion-activatable': true,
'ion-focusable': true,
}) }, hAsync(TagType, Object.assign({ key: 'fadec13053469dd0405bbbc61b70ced568aa4826' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur }, inheritedAttributes), hAsync("span", { key: '6bf0e5144fb1148002e88038522402b789689d2c', class: "button-inner" }, hAsync("slot", { key: '25da0ca155cfa9e2754842c34f4fd09f576ac2d2', name: "icon-only", onSlotchange: this.slotChanged }), hAsync("slot", { key: '51414065bb11953ec9d818f8d9353589bc9072c5', name: "start" }), hAsync("slot", { key: 'c9b5f8842aeabd20628df2f4600f1257ea913d8d' }), hAsync("slot", { key: '478dd3671c7be1909fc84e672f0fa8dfe6082263', name: "end" })), mode === 'md' && hAsync("ion-ripple-effect", { key: 'e1d55f85a55144d743f58a5914cd116cb065fa8c', type: this.rippleType }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"disabled": ["disabledChanged"],
"aria-checked": ["onAriaChanged"],
"aria-label": ["onAriaChanged"]
}; }
static get style() { return {
ios: buttonIosCss,
md: buttonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-button",
"$members$": {
"color": [513],
"buttonType": [1025, "button-type"],
"disabled": [516],
"expand": [513],
"fill": [1537],
"routerDirection": [1, "router-direction"],
"routerAnimation": [16],
"download": [1],
"href": [1],
"rel": [1],
"shape": [513],
"size": [513],
"strong": [4],
"target": [1],
"type": [1],
"form": [1],
"isCircle": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["disabled", "disabled"], ["expand", "expand"], ["fill", "fill"], ["shape", "shape"], ["size", "size"]]
}; }
}
const buttonsIosCss = ".sc-ion-buttons-ios-h{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:99}.sc-ion-buttons-ios-s ion-button{--padding-top:0;--padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.sc-ion-buttons-ios-s ion-button{--padding-top:3px;--padding-bottom:3px;--padding-start:5px;--padding-end:5px;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;min-height:32px}.sc-ion-buttons-ios-s .button-has-icon-only{--padding-top:0;--padding-bottom:0}.sc-ion-buttons-ios-s ion-button:not(.button-round){--border-radius:4px}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button{--color:initial;--border-color:initial;--background-focused:var(--ion-color-contrast)}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button-solid,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button-solid{--background:var(--ion-color-contrast);--background-focused:#000;--background-focused-opacity:.12;--background-activated:#000;--background-activated-opacity:.12;--background-hover:var(--ion-color-base);--background-hover-opacity:0.45;--color:var(--ion-color-base);--color-focused:var(--ion-color-base)}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button-clear,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button-clear{--color-activated:var(--ion-color-contrast);--color-focused:var(--ion-color-contrast)}.sc-ion-buttons-ios-h.ion-color.sc-ion-buttons-ios-s .button-outline,.ion-color .sc-ion-buttons-ios-h.sc-ion-buttons-ios-s .button-outline{--color-activated:var(--ion-color-base);--color-focused:var(--ion-color-contrast);--background-activated:var(--ion-color-contrast)}.sc-ion-buttons-ios-s .button-clear,.sc-ion-buttons-ios-s .button-outline{--background-activated:transparent;--background-focused:currentColor;--background-hover:transparent}.sc-ion-buttons-ios-s .button-solid:not(.ion-color){--background-focused:#000;--background-focused-opacity:.12;--background-activated:#000;--background-activated-opacity:.12}.sc-ion-buttons-ios-s ion-icon[slot=start]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-margin-end:0.3em;margin-inline-end:0.3em;font-size:1.41em;line-height:0.67}.sc-ion-buttons-ios-s ion-icon[slot=end]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-margin-start:0.4em;margin-inline-start:0.4em;font-size:1.41em;line-height:0.67}.sc-ion-buttons-ios-s ion-icon[slot=icon-only]{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;font-size:1.65em;line-height:0.67}";
const buttonsMdCss = ".sc-ion-buttons-md-h{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:99}.sc-ion-buttons-md-s ion-button{--padding-top:0;--padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.sc-ion-buttons-md-s ion-button{--padding-top:3px;--padding-bottom:3px;--padding-start:8px;--padding-end:8px;--box-shadow:none;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;min-height:32px}.sc-ion-buttons-md-s .button-has-icon-only{--padding-top:0;--padding-bottom:0}.sc-ion-buttons-md-s ion-button:not(.button-round){--border-radius:2px}.sc-ion-buttons-md-h.ion-color.sc-ion-buttons-md-s .button,.ion-color .sc-ion-buttons-md-h.sc-ion-buttons-md-s .button{--color:initial;--color-focused:var(--ion-color-contrast);--color-hover:var(--ion-color-contrast);--background-activated:transparent;--background-focused:var(--ion-color-contrast);--background-hover:var(--ion-color-contrast)}.sc-ion-buttons-md-h.ion-color.sc-ion-buttons-md-s .button-solid,.ion-color .sc-ion-buttons-md-h.sc-ion-buttons-md-s .button-solid{--background:var(--ion-color-contrast);--background-activated:transparent;--background-focused:var(--ion-color-shade);--background-hover:var(--ion-color-base);--color:var(--ion-color-base);--color-focused:var(--ion-color-base);--color-hover:var(--ion-color-base)}.sc-ion-buttons-md-h.ion-color.sc-ion-buttons-md-s .button-outline,.ion-color .sc-ion-buttons-md-h.sc-ion-buttons-md-s .button-outline{--border-color:var(--ion-color-contrast)}.sc-ion-buttons-md-s .button-has-icon-only.button-clear{--padding-top:12px;--padding-end:12px;--padding-bottom:12px;--padding-start:12px;--border-radius:50%;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;width:3rem;height:3rem}.sc-ion-buttons-md-s .button{--background-hover:currentColor}.sc-ion-buttons-md-s .button-solid{--color:var(--ion-toolbar-background, var(--ion-background-color, #fff));--background:var(--ion-toolbar-color, var(--ion-text-color, #424242));--background-activated:transparent;--background-focused:currentColor}.sc-ion-buttons-md-s .button-outline{--color:initial;--background:transparent;--background-activated:transparent;--background-focused:currentColor;--background-hover:currentColor;--border-color:currentColor}.sc-ion-buttons-md-s .button-clear{--color:initial;--background:transparent;--background-activated:transparent;--background-focused:currentColor;--background-hover:currentColor}.sc-ion-buttons-md-s ion-icon[slot=start]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-margin-end:0.3em;margin-inline-end:0.3em;font-size:1.4em}.sc-ion-buttons-md-s ion-icon[slot=end]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-margin-start:0.4em;margin-inline-start:0.4em;font-size:1.4em}.sc-ion-buttons-md-s ion-icon[slot=icon-only]{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;font-size:1.8em}";
class Buttons {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If true, buttons will disappear when its
* parent toolbar has fully collapsed if the toolbar
* is not the first toolbar. If the toolbar is the
* first toolbar, the buttons will be hidden and will
* only be shown once all toolbars have fully collapsed.
*
* Only applies in `ios` mode with `collapse` set to
* `true` on `ion-header`.
*
* Typically used for [Collapsible Large Titles](https://ionicframework.com/docs/api/title#collapsible-large-titles)
*/
this.collapse = false;
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '58c1fc5eb867d0731c63549b1ccb3ec3bbbe6e1b', class: {
[mode]: true,
['buttons-collapse']: this.collapse,
} }, hAsync("slot", { key: '0c8f95b9840c8fa0c4e50be84c5159620a3eb5c8' })));
}
static get style() { return {
ios: buttonsIosCss,
md: buttonsMdCss
}; }
static get cmpMeta() { return {
"$flags$": 294,
"$tagName$": "ion-buttons",
"$members$": {
"collapse": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const cardIosCss = ":host{--ion-safe-area-left:0px;--ion-safe-area-right:0px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:block;position:relative;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);contain:content;overflow:hidden}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.card-disabled){cursor:default;opacity:0.3;pointer-events:none}.card-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;width:100%;min-height:var(--min-height);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:inherit}.card-native::-moz-focus-inner{border:0}button,a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none}ion-ripple-effect{color:var(--ripple-color)}:host{--background:var(--ion-card-background, var(--ion-item-background, var(--ion-background-color, #fff)));--color:var(--ion-card-color, var(--ion-item-color, var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))));-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:24px;margin-bottom:24px;border-radius:8px;-webkit-transition:-webkit-transform 500ms cubic-bezier(0.12, 0.72, 0.29, 1);transition:-webkit-transform 500ms cubic-bezier(0.12, 0.72, 0.29, 1);transition:transform 500ms cubic-bezier(0.12, 0.72, 0.29, 1);transition:transform 500ms cubic-bezier(0.12, 0.72, 0.29, 1), -webkit-transform 500ms cubic-bezier(0.12, 0.72, 0.29, 1);font-size:0.875rem;-webkit-box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);box-shadow:0 4px 16px rgba(0, 0, 0, 0.12)}:host(.ion-activated){-webkit-transform:scale3d(0.97, 0.97, 1);transform:scale3d(0.97, 0.97, 1)}";
const cardMdCss = ":host{--ion-safe-area-left:0px;--ion-safe-area-right:0px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:block;position:relative;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);contain:content;overflow:hidden}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.card-disabled){cursor:default;opacity:0.3;pointer-events:none}.card-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;width:100%;min-height:var(--min-height);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:inherit}.card-native::-moz-focus-inner{border:0}button,a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none}ion-ripple-effect{color:var(--ripple-color)}:host{--background:var(--ion-card-background, var(--ion-item-background, var(--ion-background-color, #fff)));--color:var(--ion-card-color, var(--ion-item-color, var(--ion-color-step-550, var(--ion-text-color-step-450, #737373))));-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:10px;margin-bottom:10px;border-radius:4px;font-size:0.875rem;-webkit-box-shadow:0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);box-shadow:0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML button, anchor, or div element that wraps all child elements.
*/
class Card {
constructor(hostRef) {
registerInstance(this, hostRef);
this.inheritedAriaAttributes = {};
/**
* If `true`, a button tag will be rendered and the card will be tappable.
*/
this.button = false;
/**
* The type of the button. Only used when an `onclick` or `button` property is present.
*/
this.type = 'button';
/**
* If `true`, the user cannot interact with the card.
*/
this.disabled = false;
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
*/
this.routerDirection = 'forward';
}
componentWillLoad() {
this.inheritedAriaAttributes = inheritAttributes$1(this.el, ['aria-label']);
}
isClickable() {
return this.href !== undefined || this.button;
}
renderCard(mode) {
const clickable = this.isClickable();
if (!clickable) {
return [hAsync("slot", null)];
}
const { href, routerAnimation, routerDirection, inheritedAriaAttributes } = this;
const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div';
const attrs = TagType === 'button'
? { type: this.type }
: {
download: this.download,
href: this.href,
rel: this.rel,
target: this.target,
};
return (hAsync(TagType, Object.assign({}, attrs, inheritedAriaAttributes, { class: "card-native", part: "native", disabled: this.disabled, onClick: (ev) => openURL(href, ev, routerDirection, routerAnimation) }), hAsync("slot", null), clickable && mode === 'md' && hAsync("ion-ripple-effect", null)));
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '85e9b30bd81e79a0c7ac75cb3664bdcf9e4afc4d', class: createColorClasses$1(this.color, {
[mode]: true,
'card-disabled': this.disabled,
'ion-activatable': this.isClickable(),
}) }, this.renderCard(mode)));
}
get el() { return getElement(this); }
static get style() { return {
ios: cardIosCss,
md: cardMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-card",
"$members$": {
"color": [513],
"button": [4],
"type": [1],
"disabled": [4],
"download": [1],
"href": [1],
"rel": [1],
"routerDirection": [1, "router-direction"],
"routerAnimation": [16],
"target": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const cardContentIosCss = "ion-card-content{display:block;position:relative}.card-content-ios{-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px;padding-top:20px;padding-bottom:20px;font-size:1rem;line-height:1.4}.card-content-ios h1{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:1.5rem;font-weight:normal}.card-content-ios h2{margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:1rem;font-weight:normal}.card-content-ios h3,.card-content-ios h4,.card-content-ios h5,.card-content-ios h6{margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:0.875rem;font-weight:normal}.card-content-ios p{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:0.875rem}ion-card-header+.card-content-ios{padding-top:0}";
const cardContentMdCss = "ion-card-content{display:block;position:relative}.card-content-md{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:13px;padding-bottom:13px;font-size:0.875rem;line-height:1.5}.card-content-md h1{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:1.5rem;font-weight:normal}.card-content-md h2{margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:1rem;font-weight:normal}.card-content-md h3,.card-content-md h4,.card-content-md h5,.card-content-md h6{margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:0.875rem;font-weight:normal}.card-content-md p{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:0.875rem;font-weight:normal;line-height:1.5}ion-card-header+.card-content-md{padding-top:0}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class CardContent {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd98e4d1fc6ad3237549f9bc17e4c67ec5059b1b3', class: {
[mode]: true,
// Used internally for styling
[`card-content-${mode}`]: true,
} }));
}
static get style() { return {
ios: cardContentIosCss,
md: cardContentMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-card-content",
"$members$": undefined,
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const cardHeaderIosCss = ":host{--background:transparent;--color:inherit;display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:column;flex-direction:column;background:var(--background);color:var(--color)}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host{-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px;padding-top:20px;padding-bottom:16px;-ms-flex-direction:column-reverse;flex-direction:column-reverse}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.card-header-translucent){background-color:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.9);-webkit-backdrop-filter:saturate(180%) blur(30px);backdrop-filter:saturate(180%) blur(30px)}}";
const cardHeaderMdCss = ":host{--background:transparent;--color:inherit;display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:column;flex-direction:column;background:var(--background);color:var(--color)}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:16px;padding-bottom:16px}::slotted(ion-card-title:not(:first-child)),::slotted(ion-card-subtitle:not(:first-child)){margin-top:8px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class CardHeader {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the card header will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '64246b81931203a64d553c788cd736f41e23f37b', class: createColorClasses$1(this.color, {
'card-header-translucent': this.translucent,
'ion-inherit-color': true,
[mode]: true,
}) }, hAsync("slot", { key: 'af2da2dfe266889afeb57fac25c6a730558dbba4' })));
}
static get style() { return {
ios: cardHeaderIosCss,
md: cardHeaderMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-card-header",
"$members$": {
"color": [513],
"translucent": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const cardSubtitleIosCss = ":host{display:block;position:relative;color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}:host{--color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));margin-left:0;margin-right:0;margin-top:0;margin-bottom:4px;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-size:0.75rem;font-weight:700;letter-spacing:0.4px;text-transform:uppercase}";
const cardSubtitleMdCss = ":host{display:block;position:relative;color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}:host{--color:var(--ion-color-step-550, var(--ion-text-color-step-450, #737373));margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-size:0.875rem;font-weight:500}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class CardSubtitle {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '84d820a19d9074f9c8bc61ccba1ca40062a60b73', role: "heading", "aria-level": "3", class: createColorClasses$1(this.color, {
'ion-inherit-color': true,
[mode]: true,
}) }, hAsync("slot", { key: 'e4d07d395a1f4469a90847636083101b32b776a1' })));
}
static get style() { return {
ios: cardSubtitleIosCss,
md: cardSubtitleMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-card-subtitle",
"$members$": {
"color": [513]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const cardTitleIosCss = ":host{display:block;position:relative;color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}:host{--color:var(--ion-text-color, #000);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-size:1.75rem;font-weight:700;line-height:1.2}";
const cardTitleMdCss = ":host{display:block;position:relative;color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}:host{--color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-size:1.25rem;font-weight:500;line-height:1.2}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class CardTitle {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'fca001a86396e83718d5211cd71912fdf40dea2f', role: "heading", "aria-level": "2", class: createColorClasses$1(this.color, {
'ion-inherit-color': true,
[mode]: true,
}) }, hAsync("slot", { key: '2ba416aed488b2ff462fa75fb3b70373a6dd7da6' })));
}
static get style() { return {
ios: cardTitleIosCss,
md: cardTitleMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-card-title",
"$members$": {
"color": [513]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const checkboxIosCss = ":host{--checkbox-background-checked:var(--ion-color-primary, #0054e9);--border-color-checked:var(--ion-color-primary, #0054e9);--checkmark-color:var(--ion-color-primary-contrast, #fff);--transition:none;display:inline-block;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}:host(.ion-color){--checkbox-background-checked:var(--ion-color-base);--border-color-checked:var(--ion-color-base);--checkmark-color:var(--ion-color-contrast)}.checkbox-wrapper{display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper,:host(.in-item:not(.checkbox-label-placement-stacked):not([slot])) .native-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.checkbox-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.checkbox-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}input{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.checkbox-icon{border-radius:var(--border-radius);position:relative;width:var(--size);height:var(--size);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--checkbox-background);-webkit-box-sizing:border-box;box-sizing:border-box}.checkbox-icon path{fill:none;stroke:var(--checkmark-color);stroke-width:var(--checkmark-width);opacity:0}.checkbox-bottom{padding-top:4px;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;font-size:0.75rem;white-space:normal}:host(.checkbox-label-placement-stacked) .checkbox-bottom{font-size:1rem}.checkbox-bottom .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.checkbox-bottom .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}:host(.ion-touched.ion-invalid) .checkbox-bottom .error-text{display:block}:host(.ion-touched.ion-invalid) .checkbox-bottom .helper-text{display:none}:host(.checkbox-label-placement-start) .checkbox-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.checkbox-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.checkbox-label-placement-end) .checkbox-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse;-ms-flex-pack:start;justify-content:start}:host(.checkbox-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.checkbox-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.checkbox-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.checkbox-label-placement-stacked) .checkbox-wrapper{-ms-flex-direction:column;flex-direction:column;text-align:center}:host(.checkbox-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.checkbox-label-placement-stacked.checkbox-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.checkbox-label-placement-stacked.checkbox-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).checkbox-label-placement-stacked.checkbox-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.checkbox-label-placement-stacked.checkbox-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.checkbox-label-placement-stacked.checkbox-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.checkbox-label-placement-stacked.checkbox-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).checkbox-label-placement-stacked.checkbox-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.checkbox-label-placement-stacked.checkbox-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host(.checkbox-justify-space-between) .checkbox-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.checkbox-justify-start) .checkbox-wrapper{-ms-flex-pack:start;justify-content:start}:host(.checkbox-justify-end) .checkbox-wrapper{-ms-flex-pack:end;justify-content:end}:host(.checkbox-alignment-start) .checkbox-wrapper{-ms-flex-align:start;align-items:start}:host(.checkbox-alignment-center) .checkbox-wrapper{-ms-flex-align:center;align-items:center}:host(.checkbox-justify-space-between),:host(.checkbox-justify-start),:host(.checkbox-justify-end),:host(.checkbox-alignment-start),:host(.checkbox-alignment-center){display:block}:host(.checkbox-checked) .checkbox-icon,:host(.checkbox-indeterminate) .checkbox-icon{border-color:var(--border-color-checked);background:var(--checkbox-background-checked)}:host(.checkbox-checked) .checkbox-icon path,:host(.checkbox-indeterminate) .checkbox-icon path{opacity:1}:host(.checkbox-disabled){pointer-events:none}:host{--border-radius:50%;--border-width:0.125rem;--border-style:solid;--border-color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.23);--checkbox-background:var(--ion-item-background, var(--ion-background-color, #fff));--size:min(1.375rem, 55.836px);--checkmark-width:1.5px}:host(.checkbox-disabled){opacity:0.3}";
const checkboxMdCss = ":host{--checkbox-background-checked:var(--ion-color-primary, #0054e9);--border-color-checked:var(--ion-color-primary, #0054e9);--checkmark-color:var(--ion-color-primary-contrast, #fff);--transition:none;display:inline-block;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}:host(.ion-color){--checkbox-background-checked:var(--ion-color-base);--border-color-checked:var(--ion-color-base);--checkmark-color:var(--ion-color-contrast)}.checkbox-wrapper{display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper,:host(.in-item:not(.checkbox-label-placement-stacked):not([slot])) .native-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.checkbox-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.checkbox-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}input{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.checkbox-icon{border-radius:var(--border-radius);position:relative;width:var(--size);height:var(--size);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--checkbox-background);-webkit-box-sizing:border-box;box-sizing:border-box}.checkbox-icon path{fill:none;stroke:var(--checkmark-color);stroke-width:var(--checkmark-width);opacity:0}.checkbox-bottom{padding-top:4px;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;font-size:0.75rem;white-space:normal}:host(.checkbox-label-placement-stacked) .checkbox-bottom{font-size:1rem}.checkbox-bottom .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.checkbox-bottom .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}:host(.ion-touched.ion-invalid) .checkbox-bottom .error-text{display:block}:host(.ion-touched.ion-invalid) .checkbox-bottom .helper-text{display:none}:host(.checkbox-label-placement-start) .checkbox-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.checkbox-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.checkbox-label-placement-end) .checkbox-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse;-ms-flex-pack:start;justify-content:start}:host(.checkbox-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.checkbox-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.checkbox-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.checkbox-label-placement-stacked) .checkbox-wrapper{-ms-flex-direction:column;flex-direction:column;text-align:center}:host(.checkbox-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.checkbox-label-placement-stacked.checkbox-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.checkbox-label-placement-stacked.checkbox-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).checkbox-label-placement-stacked.checkbox-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.checkbox-label-placement-stacked.checkbox-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.checkbox-label-placement-stacked.checkbox-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.checkbox-label-placement-stacked.checkbox-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).checkbox-label-placement-stacked.checkbox-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.checkbox-label-placement-stacked.checkbox-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host(.checkbox-justify-space-between) .checkbox-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.checkbox-justify-start) .checkbox-wrapper{-ms-flex-pack:start;justify-content:start}:host(.checkbox-justify-end) .checkbox-wrapper{-ms-flex-pack:end;justify-content:end}:host(.checkbox-alignment-start) .checkbox-wrapper{-ms-flex-align:start;align-items:start}:host(.checkbox-alignment-center) .checkbox-wrapper{-ms-flex-align:center;align-items:center}:host(.checkbox-justify-space-between),:host(.checkbox-justify-start),:host(.checkbox-justify-end),:host(.checkbox-alignment-start),:host(.checkbox-alignment-center){display:block}:host(.checkbox-checked) .checkbox-icon,:host(.checkbox-indeterminate) .checkbox-icon{border-color:var(--border-color-checked);background:var(--checkbox-background-checked)}:host(.checkbox-checked) .checkbox-icon path,:host(.checkbox-indeterminate) .checkbox-icon path{opacity:1}:host(.checkbox-disabled){pointer-events:none}:host{--border-radius:calc(var(--size) * .125);--border-width:2px;--border-style:solid;--border-color:rgb(var(--ion-text-color-rgb, 0, 0, 0), 0.6);--checkmark-width:3;--checkbox-background:var(--ion-item-background, var(--ion-background-color, #fff));--transition:background 180ms cubic-bezier(0.4, 0, 0.2, 1);--size:18px}.checkbox-icon path{stroke-dasharray:30;stroke-dashoffset:30}:host(.checkbox-checked) .checkbox-icon path,:host(.checkbox-indeterminate) .checkbox-icon path{stroke-dashoffset:0;-webkit-transition:stroke-dashoffset 90ms linear 90ms;transition:stroke-dashoffset 90ms linear 90ms}:host(.checkbox-disabled) .label-text-wrapper{opacity:0.38}:host(.checkbox-disabled) .native-wrapper{opacity:0.63}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - The label text to associate with the checkbox. Use the "labelPlacement" property to control where the label is placed relative to the checkbox.
*
* @part container - The container for the checkbox mark.
* @part label - The label text describing the checkbox.
* @part mark - The checkmark used to indicate the checked state.
* @part supporting-text - Supporting text displayed beneath the checkbox label.
* @part helper-text - Supporting text displayed beneath the checkbox label when the checkbox is valid.
* @part error-text - Supporting text displayed beneath the checkbox label when the checkbox is invalid and touched.
*/
class Checkbox {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.inputId = `ion-cb-${checkboxIds++}`;
this.inputLabelId = `${this.inputId}-lbl`;
this.helperTextId = `${this.inputId}-helper-text`;
this.errorTextId = `${this.inputId}-error-text`;
this.inheritedAttributes = {};
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* If `true`, the checkbox is selected.
*/
this.checked = false;
/**
* If `true`, the checkbox will visually appear as indeterminate.
*/
this.indeterminate = false;
/**
* If `true`, the user cannot interact with the checkbox.
*/
this.disabled = false;
/**
* The value of the checkbox does not mean if it's checked or not, use the `checked`
* property for that.
*
* The value of a checkbox is analogous to the value of an `<input type="checkbox">`,
* it's only used when the checkbox participates in a native `<form>`.
*/
this.value = 'on';
/**
* Where to place the label relative to the checkbox.
* `"start"`: The label will appear to the left of the checkbox in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the checkbox in LTR and to the left in RTL.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
* `"stacked"`: The label will appear above the checkbox regardless of the direction. The alignment of the label can be controlled with the `alignment` property.
*/
this.labelPlacement = 'start';
/**
* If true, screen readers will announce it as a required field. This property
* works only for accessibility purposes, it will not prevent the form from
* submitting if the value is invalid.
*/
this.required = false;
/**
* Sets the checked property and emits
* the ionChange event. Use this to update the
* checked state in response to user-generated
* actions such as a click.
*/
this.setChecked = (state) => {
const isChecked = (this.checked = state);
this.ionChange.emit({
checked: isChecked,
value: this.value,
});
};
this.toggleChecked = (ev) => {
ev.preventDefault();
this.setChecked(!this.checked);
this.indeterminate = false;
};
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
this.onKeyDown = (ev) => {
if (ev.key === ' ') {
ev.preventDefault();
if (!this.disabled) {
this.toggleChecked(ev);
}
}
};
this.onClick = (ev) => {
if (this.disabled) {
return;
}
this.toggleChecked(ev);
};
/**
* Stops propagation when the display label is clicked,
* otherwise, two clicks will be triggered.
*/
this.onDivLabelClick = (ev) => {
ev.stopPropagation();
};
}
componentWillLoad() {
this.inheritedAttributes = Object.assign({}, inheritAriaAttributes(this.el));
}
/** @internal */
async setFocus() {
this.el.focus();
}
getHintTextID() {
const { el, helperText, errorText, helperTextId, errorTextId } = this;
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
/**
* Responsible for rendering helper text and error text.
* This element should only be rendered if hint text is set.
*/
renderHintText() {
const { helperText, errorText, helperTextId, errorTextId } = this;
/**
* undefined and empty string values should
* be treated as not having helper/error text.
*/
const hasHintText = !!helperText || !!errorText;
if (!hasHintText) {
return;
}
return (hAsync("div", { class: "checkbox-bottom" }, hAsync("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text" }, helperText), hAsync("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text" }, errorText)));
}
render() {
const { color, checked, disabled, el, getSVGPath, indeterminate, inheritedAttributes, inputId, justify, labelPlacement, name, value, alignment, required, } = this;
const mode = getIonMode$1(this);
const path = getSVGPath(mode, indeterminate);
const hasLabelContent = el.textContent !== '';
renderHiddenInput(true, el, name, checked ? value : '', disabled);
// The host element must have a checkbox role to ensure proper VoiceOver
// support in Safari for accessibility.
return (hAsync(Host, { key: 'ee2e02d28f9d15a1ec746609f7e9559444f621e5', role: "checkbox", "aria-checked": indeterminate ? 'mixed' : `${checked}`, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId, "aria-labelledby": hasLabelContent ? this.inputLabelId : null, "aria-label": inheritedAttributes['aria-label'] || null, "aria-disabled": disabled ? 'true' : null, tabindex: disabled ? undefined : 0, onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, onClick: this.onClick, class: createColorClasses$1(color, {
[mode]: true,
'in-item': hostContext('ion-item', el),
'checkbox-checked': checked,
'checkbox-disabled': disabled,
'checkbox-indeterminate': indeterminate,
interactive: true,
[`checkbox-justify-${justify}`]: justify !== undefined,
[`checkbox-alignment-${alignment}`]: alignment !== undefined,
[`checkbox-label-placement-${labelPlacement}`]: true,
}) }, hAsync("label", { key: '84d4c33da0348dc65ad36fb0fafd48be366dcf3b', class: "checkbox-wrapper", htmlFor: inputId }, hAsync("input", Object.assign({ key: '427db69a3ab8a17aa0867519c90f585b8930406b', type: "checkbox", checked: checked ? true : undefined, disabled: disabled, id: inputId, onChange: this.toggleChecked, required: required }, inheritedAttributes)), hAsync("div", { key: '9dda7024b3a4f1ee55351f783f9a10f9b4ad0d12', class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !hasLabelContent,
}, part: "label", id: this.inputLabelId, onClick: this.onDivLabelClick }, hAsync("slot", { key: 'f9d1d545ffd4164b650808241b51ea1bedc6a42c' }), this.renderHintText()), hAsync("div", { key: 'a96d61ac324864228f14caa0e9f2c0d15418882e', class: "native-wrapper" }, hAsync("svg", { key: '64ff3e4d87e190601811ef64323edec18d510cd1', class: "checkbox-icon", viewBox: "0 0 24 24", part: "container", "aria-hidden": "true" }, path)))));
}
getSVGPath(mode, indeterminate) {
let path = indeterminate ? (hAsync("path", { d: "M6 12L18 12", part: "mark" })) : (hAsync("path", { d: "M5.9,12.5l3.8,3.8l8.8-8.8", part: "mark" }));
if (mode === 'md') {
path = indeterminate ? (hAsync("path", { d: "M2 12H22", part: "mark" })) : (hAsync("path", { d: "M1.73,12.91 8.1,19.28 22.79,4.59", part: "mark" }));
}
return path;
}
get el() { return getElement(this); }
static get style() { return {
ios: checkboxIosCss,
md: checkboxMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-checkbox",
"$members$": {
"color": [513],
"name": [1],
"checked": [1028],
"indeterminate": [1028],
"disabled": [4],
"errorText": [1, "error-text"],
"helperText": [1, "helper-text"],
"value": [8],
"labelPlacement": [1, "label-placement"],
"justify": [1],
"alignment": [1],
"required": [4],
"setFocus": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
let checkboxIds = 0;
const chipIosCss = ":host{--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.12);--color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.87);border-radius:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:4px;margin-inline-end:4px;margin-top:4px;margin-bottom:4px;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px;display:-ms-inline-flexbox;display:inline-flex;position:relative;-ms-flex-align:center;align-items:center;min-height:32px;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);cursor:pointer;overflow:hidden;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.chip-disabled){cursor:default;opacity:0.4;pointer-events:none}:host(.ion-color){background:rgba(var(--ion-color-base-rgb), 0.08);color:var(--ion-color-shade)}:host(.ion-color:focus){background:rgba(var(--ion-color-base-rgb), 0.12)}:host(.ion-color.ion-activated){background:rgba(var(--ion-color-base-rgb), 0.16)}:host(.chip-outline){border-width:1px;border-style:solid}:host(.chip-outline){border-color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.32);background:transparent}:host(.chip-outline.ion-color){border-color:rgba(var(--ion-color-base-rgb), 0.32)}:host(.chip-outline:not(.ion-color):focus){background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.04)}:host(.chip-outline.ion-activated:not(.ion-color)){background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08)}::slotted(ion-icon){font-size:1.4285714286em}:host(:not(.ion-color)) ::slotted(ion-icon){color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54)}::slotted(ion-icon:first-child){-webkit-margin-start:-4px;margin-inline-start:-4px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:-4px;margin-bottom:-4px}::slotted(ion-icon:last-child){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:-4px;margin-inline-end:-4px;margin-top:-4px;margin-bottom:-4px}::slotted(ion-avatar){-ms-flex-negative:0;flex-shrink:0;width:1.7142857143em;height:1.7142857143em}::slotted(ion-avatar:first-child){-webkit-margin-start:-8px;margin-inline-start:-8px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:-4px;margin-bottom:-4px}::slotted(ion-avatar:last-child){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:-8px;margin-inline-end:-8px;margin-top:-4px;margin-bottom:-4px}:host(:focus){outline:none}:host(:focus){--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.16)}:host(.ion-activated){--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2)}@media (any-hover: hover){:host(:hover){--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.16)}:host(.ion-color:hover){background:rgba(var(--ion-color-base-rgb), 0.12)}:host(.chip-outline:not(.ion-color):hover){background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.04)}}:host{font-size:clamp(13px, 0.875rem, 22px)}";
const chipMdCss = ":host{--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.12);--color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.87);border-radius:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:4px;margin-inline-end:4px;margin-top:4px;margin-bottom:4px;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px;display:-ms-inline-flexbox;display:inline-flex;position:relative;-ms-flex-align:center;align-items:center;min-height:32px;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);cursor:pointer;overflow:hidden;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.chip-disabled){cursor:default;opacity:0.4;pointer-events:none}:host(.ion-color){background:rgba(var(--ion-color-base-rgb), 0.08);color:var(--ion-color-shade)}:host(.ion-color:focus){background:rgba(var(--ion-color-base-rgb), 0.12)}:host(.ion-color.ion-activated){background:rgba(var(--ion-color-base-rgb), 0.16)}:host(.chip-outline){border-width:1px;border-style:solid}:host(.chip-outline){border-color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.32);background:transparent}:host(.chip-outline.ion-color){border-color:rgba(var(--ion-color-base-rgb), 0.32)}:host(.chip-outline:not(.ion-color):focus){background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.04)}:host(.chip-outline.ion-activated:not(.ion-color)){background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08)}::slotted(ion-icon){font-size:1.4285714286em}:host(:not(.ion-color)) ::slotted(ion-icon){color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54)}::slotted(ion-icon:first-child){-webkit-margin-start:-4px;margin-inline-start:-4px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:-4px;margin-bottom:-4px}::slotted(ion-icon:last-child){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:-4px;margin-inline-end:-4px;margin-top:-4px;margin-bottom:-4px}::slotted(ion-avatar){-ms-flex-negative:0;flex-shrink:0;width:1.7142857143em;height:1.7142857143em}::slotted(ion-avatar:first-child){-webkit-margin-start:-8px;margin-inline-start:-8px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:-4px;margin-bottom:-4px}::slotted(ion-avatar:last-child){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:-8px;margin-inline-end:-8px;margin-top:-4px;margin-bottom:-4px}:host(:focus){outline:none}:host(:focus){--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.16)}:host(.ion-activated){--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.2)}@media (any-hover: hover){:host(:hover){--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.16)}:host(.ion-color:hover){background:rgba(var(--ion-color-base-rgb), 0.12)}:host(.chip-outline:not(.ion-color):hover){background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.04)}}:host{font-size:0.875rem}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Chip {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* Display an outline style button.
*/
this.outline = false;
/**
* If `true`, the user cannot interact with the chip.
*/
this.disabled = false;
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'fa2e9a4837ef87a17ef10f388e8caa7f604d9145', "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses$1(this.color, {
[mode]: true,
'chip-outline': this.outline,
'chip-disabled': this.disabled,
'ion-activatable': true,
}) }, hAsync("slot", { key: '3793fbd9d915cef7241fb101e2bc64c08b9ba482' }), mode === 'md' && hAsync("ion-ripple-effect", { key: 'd3b95b53918611dec095a50f2aaaab65617947a4' })));
}
static get style() { return {
ios: chipIosCss,
md: chipMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-chip",
"$members$": {
"color": [513],
"outline": [4],
"disabled": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const SIZE_TO_MEDIA = {
xs: '(min-width: 0px)',
sm: '(min-width: 576px)',
md: '(min-width: 768px)',
lg: '(min-width: 992px)',
xl: '(min-width: 1200px)',
};
// Check if the window matches the media query
// at the breakpoint passed
// e.g. matchBreakpoint('sm') => true if screen width exceeds 576px
const matchBreakpoint = (breakpoint) => {
if (breakpoint === undefined || breakpoint === '') {
return true;
}
if (window.matchMedia) {
const mediaQuery = SIZE_TO_MEDIA[breakpoint];
return window.matchMedia(mediaQuery).matches;
}
return false;
};
const colCss = ":host{-webkit-padding-start:var(--ion-grid-column-padding-xs, var(--ion-grid-column-padding, 5px));padding-inline-start:var(--ion-grid-column-padding-xs, var(--ion-grid-column-padding, 5px));-webkit-padding-end:var(--ion-grid-column-padding-xs, var(--ion-grid-column-padding, 5px));padding-inline-end:var(--ion-grid-column-padding-xs, var(--ion-grid-column-padding, 5px));padding-top:var(--ion-grid-column-padding-xs, var(--ion-grid-column-padding, 5px));padding-bottom:var(--ion-grid-column-padding-xs, var(--ion-grid-column-padding, 5px));margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;-ms-flex-preferred-size:0;flex-basis:0;-ms-flex-positive:1;flex-grow:1;width:100%;max-width:100%;min-height:1px}@media (min-width: 576px){:host{-webkit-padding-start:var(--ion-grid-column-padding-sm, var(--ion-grid-column-padding, 5px));padding-inline-start:var(--ion-grid-column-padding-sm, var(--ion-grid-column-padding, 5px));-webkit-padding-end:var(--ion-grid-column-padding-sm, var(--ion-grid-column-padding, 5px));padding-inline-end:var(--ion-grid-column-padding-sm, var(--ion-grid-column-padding, 5px));padding-top:var(--ion-grid-column-padding-sm, var(--ion-grid-column-padding, 5px));padding-bottom:var(--ion-grid-column-padding-sm, var(--ion-grid-column-padding, 5px))}}@media (min-width: 768px){:host{-webkit-padding-start:var(--ion-grid-column-padding-md, var(--ion-grid-column-padding, 5px));padding-inline-start:var(--ion-grid-column-padding-md, var(--ion-grid-column-padding, 5px));-webkit-padding-end:var(--ion-grid-column-padding-md, var(--ion-grid-column-padding, 5px));padding-inline-end:var(--ion-grid-column-padding-md, var(--ion-grid-column-padding, 5px));padding-top:var(--ion-grid-column-padding-md, var(--ion-grid-column-padding, 5px));padding-bottom:var(--ion-grid-column-padding-md, var(--ion-grid-column-padding, 5px))}}@media (min-width: 992px){:host{-webkit-padding-start:var(--ion-grid-column-padding-lg, var(--ion-grid-column-padding, 5px));padding-inline-start:var(--ion-grid-column-padding-lg, var(--ion-grid-column-padding, 5px));-webkit-padding-end:var(--ion-grid-column-padding-lg, var(--ion-grid-column-padding, 5px));padding-inline-end:var(--ion-grid-column-padding-lg, var(--ion-grid-column-padding, 5px));padding-top:var(--ion-grid-column-padding-lg, var(--ion-grid-column-padding, 5px));padding-bottom:var(--ion-grid-column-padding-lg, var(--ion-grid-column-padding, 5px))}}@media (min-width: 1200px){:host{-webkit-padding-start:var(--ion-grid-column-padding-xl, var(--ion-grid-column-padding, 5px));padding-inline-start:var(--ion-grid-column-padding-xl, var(--ion-grid-column-padding, 5px));-webkit-padding-end:var(--ion-grid-column-padding-xl, var(--ion-grid-column-padding, 5px));padding-inline-end:var(--ion-grid-column-padding-xl, var(--ion-grid-column-padding, 5px));padding-top:var(--ion-grid-column-padding-xl, var(--ion-grid-column-padding, 5px));padding-bottom:var(--ion-grid-column-padding-xl, var(--ion-grid-column-padding, 5px))}}";
const win = typeof window !== 'undefined' ? window : undefined;
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const SUPPORTS_VARS = win && !!(win.CSS && win.CSS.supports && win.CSS.supports('--a: 0'));
const BREAKPOINTS = ['', 'xs', 'sm', 'md', 'lg', 'xl'];
class Col {
constructor(hostRef) {
registerInstance(this, hostRef);
}
onResize() {
}
// Loop through all of the breakpoints to see if the media query
// matches and grab the column value from the relevant prop if so
getColumns(property) {
let matched;
for (const breakpoint of BREAKPOINTS) {
const matches = matchBreakpoint(breakpoint);
// Grab the value of the property, if it exists and our
// media query matches we return the value
const columns = this[property + breakpoint.charAt(0).toUpperCase() + breakpoint.slice(1)];
if (matches && columns !== undefined) {
matched = columns;
}
}
// Return the last matched columns since the breakpoints
// increase in size and we want to return the largest match
return matched;
}
calculateSize() {
const columns = this.getColumns('size');
// If size wasn't set for any breakpoint
// or if the user set the size without a value
// it means we need to stick with the default and return
// e.g. <ion-col size-md>
if (!columns || columns === '') {
return;
}
// If the size is set to auto then don't calculate a size
const colSize = columns === 'auto'
? 'auto'
: // If CSS supports variables we should use the grid columns var
SUPPORTS_VARS
? `calc(calc(${columns} / var(--ion-grid-columns, 12)) * 100%)`
: // Convert the columns to a percentage by dividing by the total number
// of columns (12) and then multiplying by 100
(columns / 12) * 100 + '%';
return {
flex: `0 0 ${colSize}`,
width: `${colSize}`,
'max-width': `${colSize}`,
};
}
// Called by push, pull, and offset since they use the same calculations
calculatePosition(property, modifier) {
const columns = this.getColumns(property);
if (!columns) {
return;
}
// If the number of columns passed are greater than 0 and less than
// 12 we can position the column, else default to auto
const amount = SUPPORTS_VARS
? // If CSS supports variables we should use the grid columns var
`calc(calc(${columns} / var(--ion-grid-columns, 12)) * 100%)`
: // Convert the columns to a percentage by dividing by the total number
// of columns (12) and then multiplying by 100
columns > 0 && columns < 12
? (columns / 12) * 100 + '%'
: 'auto';
return {
[modifier]: amount,
};
}
calculateOffset(isRTL) {
return this.calculatePosition('offset', isRTL ? 'margin-right' : 'margin-left');
}
calculatePull(isRTL) {
return this.calculatePosition('pull', isRTL ? 'left' : 'right');
}
calculatePush(isRTL) {
return this.calculatePosition('push', isRTL ? 'right' : 'left');
}
render() {
const isRTL = document.dir === 'rtl';
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '32ed75d81dd09d9bc8999f6d42e5b3cb99c84d91', class: {
[mode]: true,
}, style: Object.assign(Object.assign(Object.assign(Object.assign({}, this.calculateOffset(isRTL)), this.calculatePull(isRTL)), this.calculatePush(isRTL)), this.calculateSize()) }, hAsync("slot", { key: '38f8d0440c20cc6d1b1d6a654d07f16de61d8134' })));
}
static get style() { return colCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-col",
"$members$": {
"offset": [1],
"offsetXs": [1, "offset-xs"],
"offsetSm": [1, "offset-sm"],
"offsetMd": [1, "offset-md"],
"offsetLg": [1, "offset-lg"],
"offsetXl": [1, "offset-xl"],
"pull": [1],
"pullXs": [1, "pull-xs"],
"pullSm": [1, "pull-sm"],
"pullMd": [1, "pull-md"],
"pullLg": [1, "pull-lg"],
"pullXl": [1, "pull-xl"],
"push": [1],
"pushXs": [1, "push-xs"],
"pushSm": [1, "push-sm"],
"pushMd": [1, "push-md"],
"pushLg": [1, "push-lg"],
"pushXl": [1, "push-xl"],
"size": [1],
"sizeXs": [1, "size-xs"],
"sizeSm": [1, "size-sm"],
"sizeMd": [1, "size-md"],
"sizeLg": [1, "size-lg"],
"sizeXl": [1, "size-xl"]
},
"$listeners$": [[9, "resize", "onResize"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
/**
* Returns `true` if the document or host element
* has a `dir` set to `rtl`. The host value will always
* take priority over the root document value.
*/
const isRTL$1 = (hostEl) => {
if (hostEl) {
if (hostEl.dir !== '') {
return hostEl.dir.toLowerCase() === 'rtl';
}
}
return (document === null || document === void 0 ? void 0 : document.dir.toLowerCase()) === 'rtl';
};
const contentCss = ":host{--background:var(--ion-background-color, #fff);--color:var(--ion-text-color, #000);--padding-top:0px;--padding-bottom:0px;--padding-start:0px;--padding-end:0px;--keyboard-offset:0px;--offset-top:0px;--offset-bottom:0px;--overflow:auto;display:block;position:relative;-ms-flex:1;flex:1;width:100%;height:100%;margin:0 !important;padding:0 !important;font-family:var(--ion-font-family, inherit);contain:size style}:host(.ion-color) .inner-scroll{background:var(--ion-color-base);color:var(--ion-color-contrast)}#background-content{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);position:absolute;background:var(--background)}.inner-scroll{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:calc(var(--padding-top) + var(--offset-top));padding-bottom:calc(var(--padding-bottom) + var(--keyboard-offset) + var(--offset-bottom));position:absolute;color:var(--color);-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;-ms-touch-action:pan-x pan-y pinch-zoom;touch-action:pan-x pan-y pinch-zoom}.scroll-y,.scroll-x{-webkit-overflow-scrolling:touch;z-index:0;will-change:scroll-position}.scroll-y{overflow-y:var(--overflow);overscroll-behavior-y:contain}.scroll-x{overflow-x:var(--overflow);overscroll-behavior-x:contain}.overscroll::before,.overscroll::after{position:absolute;width:1px;height:1px;content:\"\"}.overscroll::before{bottom:-1px}.overscroll::after{top:-1px}:host(.content-sizing){display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-height:0;contain:none}:host(.content-sizing) .inner-scroll{position:relative;top:0;bottom:0;margin-top:calc(var(--offset-top) * -1);margin-bottom:calc(var(--offset-bottom) * -1)}.transition-effect{display:none;position:absolute;width:100%;height:100vh;opacity:0;pointer-events:none}:host(.content-ltr) .transition-effect{left:-100%;}:host(.content-rtl) .transition-effect{right:-100%;}.transition-cover{position:absolute;right:0;width:100%;height:100%;background:black;opacity:0.1}.transition-shadow{display:block;position:absolute;width:100%;height:100%;-webkit-box-shadow:inset -9px 0 9px 0 rgba(0, 0, 100, 0.03);box-shadow:inset -9px 0 9px 0 rgba(0, 0, 100, 0.03)}:host(.content-ltr) .transition-shadow{right:0;}:host(.content-rtl) .transition-shadow{left:0;-webkit-transform:scaleX(-1);transform:scaleX(-1)}::slotted([slot=fixed]){position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0)}";
/**
* @slot - Content is placed in the scrollable area if provided without a slot.
* @slot fixed - Should be used for fixed content that should not scroll.
*
* @part background - The background of the content.
* @part scroll - The scrollable container of the content.
*/
class Content {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionScrollStart = createEvent(this, "ionScrollStart", 7);
this.ionScroll = createEvent(this, "ionScroll", 7);
this.ionScrollEnd = createEvent(this, "ionScrollEnd", 7);
this.watchDog = null;
this.isScrolling = false;
this.lastScroll = 0;
this.queued = false;
this.cTop = -1;
this.cBottom = -1;
this.isMainContent = true;
this.resizeTimeout = null;
this.inheritedAttributes = {};
this.tabsElement = null;
// Detail is used in a hot loop in the scroll event, by allocating it here
// V8 will be able to inline any read/write to it since it's a monomorphic class.
// https://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html
this.detail = {
scrollTop: 0,
scrollLeft: 0,
type: 'scroll',
event: undefined,
startX: 0,
startY: 0,
startTime: 0,
currentX: 0,
currentY: 0,
velocityX: 0,
velocityY: 0,
deltaX: 0,
deltaY: 0,
currentTime: 0,
data: undefined,
isScrolling: true,
};
/**
* If `true`, the content will scroll behind the headers
* and footers. This effect can easily be seen by setting the toolbar
* to transparent.
*/
this.fullscreen = false;
/**
* Controls where the fixed content is placed relative to the main content
* in the DOM. This can be used to control the order in which fixed elements
* receive keyboard focus.
* For example, if a FAB in the fixed slot should receive keyboard focus before
* the main page content, set this property to `'before'`.
*/
this.fixedSlotPlacement = 'after';
/**
* If you want to enable the content scrolling in the X axis, set this property to `true`.
*/
this.scrollX = false;
/**
* If you want to disable the content scrolling in the Y axis, set this property to `false`.
*/
this.scrollY = true;
/**
* Because of performance reasons, ionScroll events are disabled by default, in order to enable them
* and start listening from (ionScroll), set this property to `true`.
*/
this.scrollEvents = false;
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
connectedCallback() {
this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
/**
* The fullscreen content offsets need to be
* computed after the tab bar has loaded. Since
* lazy evaluation means components are not hydrated
* at the same time, we need to wait for the ionTabBarLoaded
* event to fire. This does not impact dist-custom-elements
* because there is no hydration there.
*/
if (hasLazyBuild(this.el)) {
/**
* We need to cache the reference to the tabs.
* If just the content is unmounted then we won't
* be able to query for the closest tabs on disconnectedCallback
* since the content has been removed from the DOM tree.
*/
const closestTabs = (this.tabsElement = this.el.closest('ion-tabs'));
if (closestTabs !== null) {
/**
* When adding and removing the event listener
* we need to make sure we pass the same function reference
* otherwise the event listener will not be removed properly.
* We can't only pass `this.resize` because "this" in the function
* context becomes a reference to IonTabs instead of IonContent.
*
* Additionally, we listen for ionTabBarLoaded on the IonTabs
* instance rather than the IonTabBar instance. It's possible for
* a tab bar to be conditionally rendered/mounted. Since ionTabBarLoaded
* bubbles, we can catch any instances of child tab bars loading by listening
* on IonTabs.
*/
this.tabsLoadCallback = () => this.resize();
closestTabs.addEventListener('ionTabBarLoaded', this.tabsLoadCallback);
}
}
}
disconnectedCallback() {
this.onScrollEnd();
if (hasLazyBuild(this.el)) {
/**
* The event listener and tabs caches need to
* be cleared otherwise this will create a memory
* leak where the IonTabs instance can never be
* garbage collected.
*/
const { tabsElement, tabsLoadCallback } = this;
if (tabsElement !== null && tabsLoadCallback !== undefined) {
tabsElement.removeEventListener('ionTabBarLoaded', tabsLoadCallback);
}
this.tabsElement = null;
this.tabsLoadCallback = undefined;
}
}
/**
* Rotating certain devices can update
* the safe area insets. As a result,
* the fullscreen feature on ion-content
* needs to be recalculated.
*
* We listen for "resize" because we
* do not care what the orientation of
* the device is. Other APIs
* such as ScreenOrientation or
* the deviceorientation event must have
* permission from the user first whereas
* the "resize" event does not.
*
* We also throttle the callback to minimize
* thrashing when quickly resizing a window.
*/
onResize() {
if (this.resizeTimeout) {
clearTimeout(this.resizeTimeout);
this.resizeTimeout = null;
}
this.resizeTimeout = setTimeout(() => {
/**
* Resize should only happen
* if the content is visible.
* When the content is hidden
* then offsetParent will be null.
*/
if (this.el.offsetParent === null) {
return;
}
this.resize();
}, 100);
}
shouldForceOverscroll() {
const { forceOverscroll } = this;
const mode = getIonMode$1(this);
return forceOverscroll === undefined ? mode === 'ios' && isPlatform('ios') : forceOverscroll;
}
resize() {
}
readDimensions() {
const page = getPageElement(this.el);
const top = Math.max(this.el.offsetTop, 0);
const bottom = Math.max(page.offsetHeight - top - this.el.offsetHeight, 0);
const dirty = top !== this.cTop || bottom !== this.cBottom;
if (dirty) {
this.cTop = top;
this.cBottom = bottom;
}
}
onScroll(ev) {
const timeStamp = Date.now();
const shouldStart = !this.isScrolling;
this.lastScroll = timeStamp;
if (shouldStart) {
this.onScrollStart();
}
if (!this.queued && this.scrollEvents) {
this.queued = true;
readTask((ts) => {
this.queued = false;
this.detail.event = ev;
updateScrollDetail(this.detail, this.scrollEl, ts, shouldStart);
this.ionScroll.emit(this.detail);
});
}
}
/**
* Get the element where the actual scrolling takes place.
* This element can be used to subscribe to `scroll` events or manually modify
* `scrollTop`. However, it's recommended to use the API provided by `ion-content`:
*
* i.e. Using `ionScroll`, `ionScrollStart`, `ionScrollEnd` for scrolling events
* and `scrollToPoint()` to scroll the content into a certain point.
*/
async getScrollElement() {
/**
* If this gets called in certain early lifecycle hooks (ex: Vue onMounted),
* scrollEl won't be defined yet with the custom elements build, so wait for it to load in.
*/
if (!this.scrollEl) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.scrollEl);
}
/**
* Returns the background content element.
* @internal
*/
async getBackgroundElement() {
if (!this.backgroundContentEl) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.backgroundContentEl);
}
/**
* Scroll to the top of the component.
*
* @param duration The amount of time to take scrolling to the top. Defaults to `0`.
*/
scrollToTop(duration = 0) {
return this.scrollToPoint(undefined, 0, duration);
}
/**
* Scroll to the bottom of the component.
*
* @param duration The amount of time to take scrolling to the bottom. Defaults to `0`.
*/
async scrollToBottom(duration = 0) {
const scrollEl = await this.getScrollElement();
const y = scrollEl.scrollHeight - scrollEl.clientHeight;
return this.scrollToPoint(undefined, y, duration);
}
/**
* Scroll by a specified X/Y distance in the component.
*
* @param x The amount to scroll by on the horizontal axis.
* @param y The amount to scroll by on the vertical axis.
* @param duration The amount of time to take scrolling by that amount.
*/
async scrollByPoint(x, y, duration) {
const scrollEl = await this.getScrollElement();
return this.scrollToPoint(x + scrollEl.scrollLeft, y + scrollEl.scrollTop, duration);
}
/**
* Scroll to a specified X/Y location in the component.
*
* @param x The point to scroll to on the horizontal axis.
* @param y The point to scroll to on the vertical axis.
* @param duration The amount of time to take scrolling to that point. Defaults to `0`.
*/
async scrollToPoint(x, y, duration = 0) {
const el = await this.getScrollElement();
if (duration < 32) {
if (y != null) {
el.scrollTop = y;
}
if (x != null) {
el.scrollLeft = x;
}
return;
}
let resolve;
let startTime = 0;
const promise = new Promise((r) => (resolve = r));
const fromY = el.scrollTop;
const fromX = el.scrollLeft;
const deltaY = y != null ? y - fromY : 0;
const deltaX = x != null ? x - fromX : 0;
// scroll loop
const step = (timeStamp) => {
const linearTime = Math.min(1, (timeStamp - startTime) / duration) - 1;
const easedT = Math.pow(linearTime, 3) + 1;
if (deltaY !== 0) {
el.scrollTop = Math.floor(easedT * deltaY + fromY);
}
if (deltaX !== 0) {
el.scrollLeft = Math.floor(easedT * deltaX + fromX);
}
if (easedT < 1) {
// do not use DomController here
// must use nativeRaf in order to fire in the next frame
requestAnimationFrame(step);
}
else {
resolve();
}
};
// chill out for a frame first
requestAnimationFrame((ts) => {
startTime = ts;
step(ts);
});
return promise;
}
onScrollStart() {
this.isScrolling = true;
this.ionScrollStart.emit({
isScrolling: true,
});
if (this.watchDog) {
clearInterval(this.watchDog);
}
// watchdog
this.watchDog = setInterval(() => {
if (this.lastScroll < Date.now() - 120) {
this.onScrollEnd();
}
}, 100);
}
onScrollEnd() {
if (this.watchDog)
clearInterval(this.watchDog);
this.watchDog = null;
if (this.isScrolling) {
this.isScrolling = false;
this.ionScrollEnd.emit({
isScrolling: false,
});
}
}
render() {
const { fixedSlotPlacement, inheritedAttributes, isMainContent, scrollX, scrollY, el } = this;
const rtl = isRTL$1(el) ? 'rtl' : 'ltr';
const mode = getIonMode$1(this);
const forceOverscroll = this.shouldForceOverscroll();
const transitionShadow = mode === 'ios';
this.resize();
return (hAsync(Host, Object.assign({ key: 'f2a24aa66dbf5c76f9d4b06f708eb73cadc239df', role: isMainContent ? 'main' : undefined, class: createColorClasses$1(this.color, {
[mode]: true,
'content-sizing': hostContext('ion-popover', this.el),
overscroll: forceOverscroll,
[`content-${rtl}`]: true,
}), style: {
'--offset-top': `${this.cTop}px`,
'--offset-bottom': `${this.cBottom}px`,
} }, inheritedAttributes), hAsync("div", { key: '6480ca7648b278abb36477b3838bccbcd4995e2a', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? hAsync("slot", { name: "fixed" }) : null, hAsync("div", { key: '29a23b663f5f0215bb000820c01e1814c0d55985', class: {
'inner-scroll': true,
'scroll-x': scrollX,
'scroll-y': scrollY,
overscroll: (scrollX || scrollY) && forceOverscroll,
}, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, hAsync("slot", { key: '0fe1bd05609a4b88ae2ce9addf5d5dc5dc1806f0' })), transitionShadow ? (hAsync("div", { class: "transition-effect" }, hAsync("div", { class: "transition-cover" }), hAsync("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? hAsync("slot", { name: "fixed" }) : null));
}
get el() { return getElement(this); }
static get style() { return contentCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-content",
"$members$": {
"color": [513],
"fullscreen": [4],
"fixedSlotPlacement": [1, "fixed-slot-placement"],
"forceOverscroll": [1028, "force-overscroll"],
"scrollX": [4, "scroll-x"],
"scrollY": [4, "scroll-y"],
"scrollEvents": [4, "scroll-events"],
"getScrollElement": [64],
"getBackgroundElement": [64],
"scrollToTop": [64],
"scrollToBottom": [64],
"scrollByPoint": [64],
"scrollToPoint": [64]
},
"$listeners$": [[9, "resize", "onResize"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const getParentElement = (el) => {
var _a;
if (el.parentElement) {
// normal element with a parent element
return el.parentElement;
}
if ((_a = el.parentNode) === null || _a === void 0 ? void 0 : _a.host) {
// shadow dom's document fragment
return el.parentNode.host;
}
return null;
};
const getPageElement = (el) => {
const tabs = el.closest('ion-tabs');
if (tabs) {
return tabs;
}
/**
* If we're in a popover, we need to use its wrapper so we can account for space
* between the popover and the edges of the screen. But if the popover contains
* its own page element, we should use that instead.
*/
const page = el.closest('ion-app, ion-page, .ion-page, page-inner, .popover-content');
if (page) {
return page;
}
return getParentElement(el);
};
// ******** DOM READ ****************
const updateScrollDetail = (detail, el, timestamp, shouldStart) => {
const prevX = detail.currentX;
const prevY = detail.currentY;
const prevT = detail.currentTime;
const currentX = el.scrollLeft;
const currentY = el.scrollTop;
const timeDelta = timestamp - prevT;
if (shouldStart) {
// remember the start positions
detail.startTime = timestamp;
detail.startX = currentX;
detail.startY = currentY;
detail.velocityX = detail.velocityY = 0;
}
detail.currentTime = timestamp;
detail.currentX = detail.scrollLeft = currentX;
detail.currentY = detail.scrollTop = currentY;
detail.deltaX = currentX - detail.startX;
detail.deltaY = currentY - detail.startY;
if (timeDelta > 0 && timeDelta < 100) {
const velocityX = (currentX - prevX) / timeDelta;
const velocityY = (currentY - prevY) / timeDelta;
detail.velocityX = velocityX * 0.7 + detail.velocityX * 0.3;
detail.velocityY = velocityY * 0.7 + detail.velocityY * 0.3;
}
};
const ION_FOCUSED = 'ion-focused';
const ION_FOCUSABLE = 'ion-focusable';
const FOCUS_KEYS = [
'Tab',
'ArrowDown',
'Space',
'Escape',
' ',
'Shift',
'Enter',
'ArrowLeft',
'ArrowRight',
'ArrowUp',
'Home',
'End',
];
const startFocusVisible = (rootEl) => {
let currentFocus = [];
let keyboardMode = true;
const ref = rootEl ? rootEl.shadowRoot : document;
const root = rootEl ? rootEl : document.body;
const setFocus = (elements) => {
currentFocus.forEach((el) => el.classList.remove(ION_FOCUSED));
elements.forEach((el) => el.classList.add(ION_FOCUSED));
currentFocus = elements;
};
const pointerDown = () => {
keyboardMode = false;
setFocus([]);
};
const onKeydown = (ev) => {
keyboardMode = FOCUS_KEYS.includes(ev.key);
if (!keyboardMode) {
setFocus([]);
}
};
const onFocusin = (ev) => {
if (keyboardMode && ev.composedPath !== undefined) {
const toFocus = ev.composedPath().filter((el) => {
// TODO(FW-2832): type
if (el.classList) {
return el.classList.contains(ION_FOCUSABLE);
}
return false;
});
setFocus(toFocus);
}
};
const onFocusout = () => {
if (ref.activeElement === root) {
setFocus([]);
}
};
ref.addEventListener('keydown', onKeydown);
ref.addEventListener('focusin', onFocusin);
ref.addEventListener('focusout', onFocusout);
ref.addEventListener('touchstart', pointerDown, { passive: true });
ref.addEventListener('mousedown', pointerDown);
const destroy = () => {
ref.removeEventListener('keydown', onKeydown);
ref.removeEventListener('focusin', onFocusin);
ref.removeEventListener('focusout', onFocusout);
ref.removeEventListener('touchstart', pointerDown);
ref.removeEventListener('mousedown', pointerDown);
};
return {
destroy,
setFocus,
};
};
/**
* Returns true if the selected day is equal to the reference day
*/
const isSameDay = (baseParts, compareParts) => {
return (baseParts.month === compareParts.month && baseParts.day === compareParts.day && baseParts.year === compareParts.year);
};
/**
* Returns true is the selected day is before the reference day.
*/
const isBefore = (baseParts, compareParts) => {
return !!(baseParts.year < compareParts.year ||
(baseParts.year === compareParts.year && baseParts.month < compareParts.month) ||
(baseParts.year === compareParts.year &&
baseParts.month === compareParts.month &&
baseParts.day !== null &&
baseParts.day < compareParts.day));
};
/**
* Returns true is the selected day is after the reference day.
*/
const isAfter = (baseParts, compareParts) => {
return !!(baseParts.year > compareParts.year ||
(baseParts.year === compareParts.year && baseParts.month > compareParts.month) ||
(baseParts.year === compareParts.year &&
baseParts.month === compareParts.month &&
baseParts.day !== null &&
baseParts.day > compareParts.day));
};
const warnIfValueOutOfBounds = (value, min, max) => {
const valueArray = Array.isArray(value) ? value : [value];
for (const val of valueArray) {
if ((min !== undefined && isBefore(val, min)) || (max !== undefined && isAfter(val, max))) {
printIonWarning('[ion-datetime] - The value provided to ion-datetime is out of bounds.\n\n' +
`Min: ${JSON.stringify(min)}\n` +
`Max: ${JSON.stringify(max)}\n` +
`Value: ${JSON.stringify(value)}`);
break;
}
}
};
/**
* Determines if given year is a
* leap year. Returns `true` if year
* is a leap year. Returns `false`
* otherwise.
*/
const isLeapYear = (year) => {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
};
/**
* Determines the hour cycle for a user.
* If the hour cycle is explicitly defined, just use that.
* Otherwise, we try to derive it from either the specified
* locale extension tags or from Intl.DateTimeFormat directly.
*/
const getHourCycle = (locale, hourCycle) => {
/**
* If developer has explicitly enabled 24-hour time
* then return early and do not look at the system default.
*/
if (hourCycle !== undefined) {
return hourCycle;
}
/**
* If hourCycle was not specified, check the locale
* that is set on the user's device. We first check the
* Intl.DateTimeFormat hourCycle option as developers can encode this
* option into the locale string. Example: `en-US-u-hc-h23`
*/
const formatted = new Intl.DateTimeFormat(locale, { hour: 'numeric' });
const options = formatted.resolvedOptions();
if (options.hourCycle !== undefined) {
return options.hourCycle;
}
/**
* If hourCycle is not specified (either through lack
* of browser support or locale information) then fall
* back to this slower hourCycle check.
*/
const date = new Date('5/18/2021 00:00');
const parts = formatted.formatToParts(date);
const hour = parts.find((p) => p.type === 'hour');
if (!hour) {
throw new Error('Hour value not found from DateTimeFormat');
}
/**
* Midnight for h11 starts at 0:00am
* Midnight for h12 starts at 12:00am
* Midnight for h23 starts at 00:00
* Midnight for h24 starts at 24:00
*/
switch (hour.value) {
case '0':
return 'h11';
case '12':
return 'h12';
case '00':
return 'h23';
case '24':
return 'h24';
default:
throw new Error(`Invalid hour cycle "${hourCycle}"`);
}
};
/**
* Determine if the hour cycle uses a 24-hour format.
* Returns true for h23 and h24. Returns false otherwise.
* If you don't know the hourCycle, use getHourCycle above
* and pass the result into this function.
*/
const is24Hour = (hourCycle) => {
return hourCycle === 'h23' || hourCycle === 'h24';
};
/**
* Given a date object, returns the number
* of days in that month.
* Month value begin at 1, not 0.
* i.e. January = month 1.
*/
const getNumDaysInMonth = (month, year) => {
return month === 4 || month === 6 || month === 9 || month === 11
? 30
: month === 2
? isLeapYear(year)
? 29
: 28
: 31;
};
/**
* Certain locales display month then year while
* others display year then month.
* We can use Intl.DateTimeFormat to determine
* the ordering for each locale.
* The formatOptions param can be used to customize
* which pieces of a date to compare against the month
* with. For example, some locales render dd/mm/yyyy
* while others render mm/dd/yyyy. This function can be
* used for variations of the same "month first" check.
*/
const isMonthFirstLocale = (locale, formatOptions = {
month: 'numeric',
year: 'numeric',
}) => {
/**
* By setting month and year we guarantee that only
* month, year, and literal (slashes '/', for example)
* values are included in the formatToParts results.
*
* The ordering of the parts will be determined by
* the locale. So if the month is the first value,
* then we know month should be shown first. If the
* year is the first value, then we know year should be shown first.
*
* This ordering can be controlled by customizing the locale property.
*/
const parts = new Intl.DateTimeFormat(locale, formatOptions).formatToParts(new Date());
return parts[0].type === 'month';
};
/**
* Determines if the given locale formats the day period (am/pm) to the
* left or right of the hour.
* @param locale The locale to check.
* @returns `true` if the locale formats the day period to the left of the hour.
*/
const isLocaleDayPeriodRTL = (locale) => {
const parts = new Intl.DateTimeFormat(locale, { hour: 'numeric' }).formatToParts(new Date());
return parts[0].type === 'dayPeriod';
};
const ISO_8601_REGEXP =
// eslint-disable-next-line no-useless-escape
/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/;
// eslint-disable-next-line no-useless-escape
const TIME_REGEXP = /^((\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/;
/**
* Use to convert a string of comma separated numbers or
* an array of numbers, and clean up any user input
*/
const convertToArrayOfNumbers = (input) => {
if (input === undefined) {
return;
}
let processedInput = input;
if (typeof input === 'string') {
// convert the string to an array of strings
// auto remove any whitespace and [] characters
processedInput = input.replace(/\[|\]|\s/g, '').split(',');
}
let values;
if (Array.isArray(processedInput)) {
// ensure each value is an actual number in the returned array
values = processedInput.map((num) => parseInt(num, 10)).filter(isFinite);
}
else {
values = [processedInput];
}
return values;
};
/**
* Extracts date information
* from a .calendar-day element
* into DatetimeParts.
*/
const getPartsFromCalendarDay = (el) => {
return {
month: parseInt(el.getAttribute('data-month'), 10),
day: parseInt(el.getAttribute('data-day'), 10),
year: parseInt(el.getAttribute('data-year'), 10),
dayOfWeek: parseInt(el.getAttribute('data-day-of-week'), 10),
};
};
function parseDate(val) {
if (Array.isArray(val)) {
const parsedArray = [];
for (const valStr of val) {
const parsedVal = parseDate(valStr);
/**
* If any of the values weren't parsed correctly, consider
* the entire batch incorrect. This simplifies the type
* signatures by having "undefined" be a general error case
* instead of returning (Datetime | undefined)[], which is
* harder for TS to perform type narrowing on.
*/
if (!parsedVal) {
return undefined;
}
parsedArray.push(parsedVal);
}
return parsedArray;
}
// manually parse IS0 cuz Date.parse cannot be trusted
// ISO 8601 format: 1994-12-15T13:47:20Z
let parse = null;
if (val != null && val !== '') {
// try parsing for just time first, HH:MM
parse = TIME_REGEXP.exec(val);
if (parse) {
// adjust the array so it fits nicely with the datetime parse
parse.unshift(undefined, undefined);
parse[2] = parse[3] = undefined;
}
else {
// try parsing for full ISO datetime
parse = ISO_8601_REGEXP.exec(val);
}
}
if (parse === null) {
// wasn't able to parse the ISO datetime
printIonWarning(`[ion-datetime] - Unable to parse date string: ${val}. Please provide a valid ISO 8601 datetime string.`);
return undefined;
}
// ensure all the parse values exist with at least 0
for (let i = 1; i < 8; i++) {
parse[i] = parse[i] !== undefined ? parseInt(parse[i], 10) : undefined;
}
// can also get second and millisecond from parse[6] and parse[7] if needed
return {
year: parse[1],
month: parse[2],
day: parse[3],
hour: parse[4],
minute: parse[5],
ampm: parse[4] < 12 ? 'am' : 'pm',
};
}
const clampDate = (dateParts, minParts, maxParts) => {
if (minParts && isBefore(dateParts, minParts)) {
return minParts;
}
else if (maxParts && isAfter(dateParts, maxParts)) {
return maxParts;
}
return dateParts;
};
/**
* Parses an hour and returns if the value is in the morning (am) or afternoon (pm).
* @param hour The hour to format, should be 0-23
* @returns `pm` if the hour is greater than or equal to 12, `am` if less than 12.
*/
const parseAmPm = (hour) => {
return hour >= 12 ? 'pm' : 'am';
};
/**
* Takes a max date string and creates a DatetimeParts
* object, filling in any missing information.
* For example, max="2012" would fill in the missing
* month, day, hour, and minute information.
*/
const parseMaxParts = (max, todayParts) => {
const result = parseDate(max);
/**
* If min was not a valid date then return undefined.
*/
if (result === undefined) {
return;
}
const { month, day, year, hour, minute } = result;
/**
* When passing in `max` or `min`, developers
* can pass in any ISO-8601 string. This means
* that not all of the date/time fields are defined.
* For example, passing max="2012" is valid even though
* there is no month, day, hour, or minute data.
* However, all of this data is required when clamping the date
* so that the correct initial value can be selected. As a result,
* we need to fill in any omitted data with the min or max values.
*/
const yearValue = year !== null && year !== void 0 ? year : todayParts.year;
const monthValue = month !== null && month !== void 0 ? month : 12;
return {
month: monthValue,
day: day !== null && day !== void 0 ? day : getNumDaysInMonth(monthValue, yearValue),
/**
* Passing in "HH:mm" is a valid ISO-8601
* string, so we just default to the current year
* in this case.
*/
year: yearValue,
hour: hour !== null && hour !== void 0 ? hour : 23,
minute: minute !== null && minute !== void 0 ? minute : 59,
};
};
/**
* Takes a min date string and creates a DatetimeParts
* object, filling in any missing information.
* For example, min="2012" would fill in the missing
* month, day, hour, and minute information.
*/
const parseMinParts = (min, todayParts) => {
const result = parseDate(min);
/**
* If min was not a valid date then return undefined.
*/
if (result === undefined) {
return;
}
const { month, day, year, hour, minute } = result;
/**
* When passing in `max` or `min`, developers
* can pass in any ISO-8601 string. This means
* that not all of the date/time fields are defined.
* For example, passing max="2012" is valid even though
* there is no month, day, hour, or minute data.
* However, all of this data is required when clamping the date
* so that the correct initial value can be selected. As a result,
* we need to fill in any omitted data with the min or max values.
*/
return {
month: month !== null && month !== void 0 ? month : 1,
day: day !== null && day !== void 0 ? day : 1,
/**
* Passing in "HH:mm" is a valid ISO-8601
* string, so we just default to the current year
* in this case.
*/
year: year !== null && year !== void 0 ? year : todayParts.year,
hour: hour !== null && hour !== void 0 ? hour : 0,
minute: minute !== null && minute !== void 0 ? minute : 0,
};
};
const twoDigit = (val) => {
return ('0' + (val !== undefined ? Math.abs(val) : '0')).slice(-2);
};
const fourDigit = (val) => {
return ('000' + (val !== undefined ? Math.abs(val) : '0')).slice(-4);
};
function convertDataToISO(data) {
if (Array.isArray(data)) {
return data.map((parts) => convertDataToISO(parts));
}
// https://www.w3.org/TR/NOTE-datetime
let rtn = '';
if (data.year !== undefined) {
// YYYY
rtn = fourDigit(data.year);
if (data.month !== undefined) {
// YYYY-MM
rtn += '-' + twoDigit(data.month);
if (data.day !== undefined) {
// YYYY-MM-DD
rtn += '-' + twoDigit(data.day);
if (data.hour !== undefined) {
// YYYY-MM-DDTHH:mm:SS
rtn += `T${twoDigit(data.hour)}:${twoDigit(data.minute)}:00`;
}
}
}
}
else if (data.hour !== undefined) {
// HH:mm
rtn = twoDigit(data.hour) + ':' + twoDigit(data.minute);
}
return rtn;
}
/**
* Converts an 12 hour value to 24 hours.
*/
const convert12HourTo24Hour = (hour, ampm) => {
if (ampm === undefined) {
return hour;
}
/**
* If AM and 12am
* then return 00:00.
* Otherwise just return
* the hour since it is
* already in 24 hour format.
*/
if (ampm === 'am') {
if (hour === 12) {
return 0;
}
return hour;
}
/**
* If PM and 12pm
* just return 12:00
* since it is already
* in 24 hour format.
* Otherwise add 12 hours
* to the time.
*/
if (hour === 12) {
return 12;
}
return hour + 12;
};
const getStartOfWeek = (refParts) => {
const { dayOfWeek } = refParts;
if (dayOfWeek === null || dayOfWeek === undefined) {
throw new Error('No day of week provided');
}
return subtractDays(refParts, dayOfWeek);
};
const getEndOfWeek = (refParts) => {
const { dayOfWeek } = refParts;
if (dayOfWeek === null || dayOfWeek === undefined) {
throw new Error('No day of week provided');
}
return addDays(refParts, 6 - dayOfWeek);
};
const getNextDay = (refParts) => {
return addDays(refParts, 1);
};
const getPreviousDay = (refParts) => {
return subtractDays(refParts, 1);
};
const getPreviousWeek = (refParts) => {
return subtractDays(refParts, 7);
};
const getNextWeek = (refParts) => {
return addDays(refParts, 7);
};
/**
* Given datetime parts, subtract
* numDays from the date.
* Returns a new DatetimeParts object
* Currently can only go backward at most 1 month.
*/
const subtractDays = (refParts, numDays) => {
const { month, day, year } = refParts;
if (day === null) {
throw new Error('No day provided');
}
const workingParts = {
month,
day,
year,
};
workingParts.day = day - numDays;
/**
* If wrapping to previous month
* update days and decrement month
*/
if (workingParts.day < 1) {
workingParts.month -= 1;
}
/**
* If moving to previous year, reset
* month to December and decrement year
*/
if (workingParts.month < 1) {
workingParts.month = 12;
workingParts.year -= 1;
}
/**
* Determine how many days are in the current
* month
*/
if (workingParts.day < 1) {
const daysInMonth = getNumDaysInMonth(workingParts.month, workingParts.year);
/**
* Take num days in month and add the
* number of underflow days. This number will
* be negative.
* Example: 1 week before Jan 2, 2021 is
* December 26, 2021 so:
* 2 - 7 = -5
* 31 + (-5) = 26
*/
workingParts.day = daysInMonth + workingParts.day;
}
return workingParts;
};
/**
* Given datetime parts, add
* numDays to the date.
* Returns a new DatetimeParts object
* Currently can only go forward at most 1 month.
*/
const addDays = (refParts, numDays) => {
const { month, day, year } = refParts;
if (day === null) {
throw new Error('No day provided');
}
const workingParts = {
month,
day,
year,
};
const daysInMonth = getNumDaysInMonth(month, year);
workingParts.day = day + numDays;
/**
* If wrapping to next month
* update days and increment month
*/
if (workingParts.day > daysInMonth) {
workingParts.day -= daysInMonth;
workingParts.month += 1;
}
/**
* If moving to next year, reset
* month to January and increment year
*/
if (workingParts.month > 12) {
workingParts.month = 1;
workingParts.year += 1;
}
return workingParts;
};
/**
* Given DatetimeParts, generate the previous month.
*/
const getPreviousMonth = (refParts) => {
/**
* If current month is January, wrap backwards
* to December of the previous year.
*/
const month = refParts.month === 1 ? 12 : refParts.month - 1;
const year = refParts.month === 1 ? refParts.year - 1 : refParts.year;
const numDaysInMonth = getNumDaysInMonth(month, year);
const day = numDaysInMonth < refParts.day ? numDaysInMonth : refParts.day;
return { month, year, day };
};
/**
* Given DatetimeParts, generate the next month.
*/
const getNextMonth = (refParts) => {
/**
* If current month is December, wrap forwards
* to January of the next year.
*/
const month = refParts.month === 12 ? 1 : refParts.month + 1;
const year = refParts.month === 12 ? refParts.year + 1 : refParts.year;
const numDaysInMonth = getNumDaysInMonth(month, year);
const day = numDaysInMonth < refParts.day ? numDaysInMonth : refParts.day;
return { month, year, day };
};
const changeYear = (refParts, yearDelta) => {
const month = refParts.month;
const year = refParts.year + yearDelta;
const numDaysInMonth = getNumDaysInMonth(month, year);
const day = numDaysInMonth < refParts.day ? numDaysInMonth : refParts.day;
return { month, year, day };
};
/**
* Given DatetimeParts, generate the previous year.
*/
const getPreviousYear = (refParts) => {
return changeYear(refParts, -1);
};
/**
* Given DatetimeParts, generate the next year.
*/
const getNextYear = (refParts) => {
return changeYear(refParts, 1);
};
/**
* If PM, then internal value should
* be converted to 24-hr time.
* Does not apply when public
* values are already 24-hr time.
*/
const getInternalHourValue = (hour, use24Hour, ampm) => {
if (use24Hour) {
return hour;
}
return convert12HourTo24Hour(hour, ampm);
};
/**
* Unless otherwise stated, all month values are
* 1 indexed instead of the typical 0 index in JS Date.
* Example:
* January = Month 0 when using JS Date
* January = Month 1 when using this datetime util
*/
/**
* Given the current datetime parts and a new AM/PM value
* calculate what the hour should be in 24-hour time format.
* Used when toggling the AM/PM segment since we store our hours
* in 24-hour time format internally.
*/
const calculateHourFromAMPM = (currentParts, newAMPM) => {
const { ampm: currentAMPM, hour } = currentParts;
let newHour = hour;
/**
* If going from AM --> PM, need to update the
*
*/
if (currentAMPM === 'am' && newAMPM === 'pm') {
newHour = convert12HourTo24Hour(newHour, 'pm');
/**
* If going from PM --> AM
*/
}
else if (currentAMPM === 'pm' && newAMPM === 'am') {
newHour = Math.abs(newHour - 12);
}
return newHour;
};
/**
* Updates parts to ensure that month and day
* values are valid. For days that do not exist,
* or are outside the min/max bounds, the closest
* valid day is used.
*/
const validateParts = (parts, minParts, maxParts) => {
const { month, day, year } = parts;
const partsCopy = clampDate(Object.assign({}, parts), minParts, maxParts);
const numDays = getNumDaysInMonth(month, year);
/**
* If the max number of days
* is greater than the day we want
* to set, update the DatetimeParts
* day field to be the max days.
*/
if (day !== null && numDays < day) {
partsCopy.day = numDays;
}
/**
* If value is same day as min day,
* make sure the time value is in bounds.
*/
if (minParts !== undefined && isSameDay(partsCopy, minParts)) {
/**
* If the hour is out of bounds,
* update both the hour and minute.
* This is done so that the new time
* is closest to what the user selected.
*/
if (partsCopy.hour !== undefined && minParts.hour !== undefined) {
if (partsCopy.hour < minParts.hour) {
partsCopy.hour = minParts.hour;
partsCopy.minute = minParts.minute;
/**
* If only the minute is out of bounds,
* set it to the min minute.
*/
}
else if (partsCopy.hour === minParts.hour &&
partsCopy.minute !== undefined &&
minParts.minute !== undefined &&
partsCopy.minute < minParts.minute) {
partsCopy.minute = minParts.minute;
}
}
}
/**
* If value is same day as max day,
* make sure the time value is in bounds.
*/
if (maxParts !== undefined && isSameDay(parts, maxParts)) {
/**
* If the hour is out of bounds,
* update both the hour and minute.
* This is done so that the new time
* is closest to what the user selected.
*/
if (partsCopy.hour !== undefined && maxParts.hour !== undefined) {
if (partsCopy.hour > maxParts.hour) {
partsCopy.hour = maxParts.hour;
partsCopy.minute = maxParts.minute;
/**
* If only the minute is out of bounds,
* set it to the max minute.
*/
}
else if (partsCopy.hour === maxParts.hour &&
partsCopy.minute !== undefined &&
maxParts.minute !== undefined &&
partsCopy.minute > maxParts.minute) {
partsCopy.minute = maxParts.minute;
}
}
}
return partsCopy;
};
/**
* Returns the closest date to refParts
* that also meets the constraints of
* the *Values params.
*/
const getClosestValidDate = ({ refParts, monthValues, dayValues, yearValues, hourValues, minuteValues, minParts, maxParts, }) => {
const { hour, minute, day, month, year } = refParts;
const copyParts = Object.assign(Object.assign({}, refParts), { dayOfWeek: undefined });
if (yearValues !== undefined) {
// Filters out years that are out of the min/max bounds
const filteredYears = yearValues.filter((year) => {
if (minParts !== undefined && year < minParts.year) {
return false;
}
if (maxParts !== undefined && year > maxParts.year) {
return false;
}
return true;
});
copyParts.year = findClosestValue(year, filteredYears);
}
if (monthValues !== undefined) {
// Filters out months that are out of the min/max bounds
const filteredMonths = monthValues.filter((month) => {
if (minParts !== undefined && copyParts.year === minParts.year && month < minParts.month) {
return false;
}
if (maxParts !== undefined && copyParts.year === maxParts.year && month > maxParts.month) {
return false;
}
return true;
});
copyParts.month = findClosestValue(month, filteredMonths);
}
// Day is nullable but cannot be undefined
if (day !== null && dayValues !== undefined) {
// Filters out days that are out of the min/max bounds
const filteredDays = dayValues.filter((day) => {
if (minParts !== undefined && isBefore(Object.assign(Object.assign({}, copyParts), { day }), minParts)) {
return false;
}
if (maxParts !== undefined && isAfter(Object.assign(Object.assign({}, copyParts), { day }), maxParts)) {
return false;
}
return true;
});
copyParts.day = findClosestValue(day, filteredDays);
}
if (hour !== undefined && hourValues !== undefined) {
// Filters out hours that are out of the min/max bounds
const filteredHours = hourValues.filter((hour) => {
if ((minParts === null || minParts === void 0 ? void 0 : minParts.hour) !== undefined && isSameDay(copyParts, minParts) && hour < minParts.hour) {
return false;
}
if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.hour) !== undefined && isSameDay(copyParts, maxParts) && hour > maxParts.hour) {
return false;
}
return true;
});
copyParts.hour = findClosestValue(hour, filteredHours);
copyParts.ampm = parseAmPm(copyParts.hour);
}
if (minute !== undefined && minuteValues !== undefined) {
// Filters out minutes that are out of the min/max bounds
const filteredMinutes = minuteValues.filter((minute) => {
if ((minParts === null || minParts === void 0 ? void 0 : minParts.minute) !== undefined &&
isSameDay(copyParts, minParts) &&
copyParts.hour === minParts.hour &&
minute < minParts.minute) {
return false;
}
if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.minute) !== undefined &&
isSameDay(copyParts, maxParts) &&
copyParts.hour === maxParts.hour &&
minute > maxParts.minute) {
return false;
}
return true;
});
copyParts.minute = findClosestValue(minute, filteredMinutes);
}
return copyParts;
};
/**
* Finds the value in "values" that is
* numerically closest to "reference".
* This function assumes that "values" is
* already sorted in ascending order.
* @param reference The reference number to use
* when finding the closest value
* @param values The allowed values that will be
* searched to find the closest value to "reference"
*/
const findClosestValue = (reference, values) => {
let closestValue = values[0];
let rank = Math.abs(closestValue - reference);
for (let i = 1; i < values.length; i++) {
const value = values[i];
/**
* This code prioritizes the first
* closest result. Given two values
* with the same distance from reference,
* this code will prioritize the smaller of
* the two values.
*/
const valueRank = Math.abs(value - reference);
if (valueRank < rank) {
closestValue = value;
rank = valueRank;
}
}
return closestValue;
};
const getFormattedDayPeriod = (dayPeriod) => {
if (dayPeriod === undefined) {
return '';
}
return dayPeriod.toUpperCase();
};
/**
* Including time zone options may lead to the rendered text showing a
* different time from what was selected in the Datetime, which could cause
* confusion.
*/
const stripTimeZone = (formatOptions) => {
return Object.assign(Object.assign({}, formatOptions), {
/**
* Setting the time zone to UTC ensures that the value shown is always the
* same as what was selected and safeguards against older Safari bugs with
* Intl.DateTimeFormat.
*/
timeZone: 'UTC',
/**
* We do not want to display the time zone name
*/
timeZoneName: undefined
});
};
const getLocalizedTime = (locale, refParts, hourCycle, formatOptions = { hour: 'numeric', minute: 'numeric' }) => {
const timeParts = {
hour: refParts.hour,
minute: refParts.minute,
};
if (timeParts.hour === undefined || timeParts.minute === undefined) {
return 'Invalid Time';
}
return new Intl.DateTimeFormat(locale, Object.assign(Object.assign({}, stripTimeZone(formatOptions)), {
/**
* We use hourCycle here instead of hour12 due to:
* https://bugs.chromium.org/p/chromium/issues/detail?id=1347316&q=hour12&can=2
*/
hourCycle
})).format(new Date(convertDataToISO(Object.assign({
/**
* JS uses a simplified ISO 8601 format which allows for
* date-only formats and date-time formats, but not
* time-only formats: https://tc39.es/ecma262/#sec-date-time-string-format
* As a result, developers who only pass a time will get
* an "Invalid Date" error. To account for this, we make sure that
* year/day/month values are set when passing to new Date().
* The Intl.DateTimeFormat call above only uses the hour/minute
* values, so passing these date values should have no impact
* on the time output.
*/
year: 2023, day: 1, month: 1
}, timeParts)) + 'Z'));
};
/**
* Adds padding to a time value so
* that it is always 2 digits.
*/
const addTimePadding = (value) => {
const valueToString = value.toString();
if (valueToString.length > 1) {
return valueToString;
}
return `0${valueToString}`;
};
/**
* Formats 24 hour times so that
* it always has 2 digits. For
* 12 hour times it ensures that
* hour 0 is formatted as '12'.
*/
const getFormattedHour = (hour, hourCycle) => {
/**
* Midnight for h11 starts at 0:00am
* Midnight for h12 starts at 12:00am
* Midnight for h23 starts at 00:00
* Midnight for h24 starts at 24:00
*/
if (hour === 0) {
switch (hourCycle) {
case 'h11':
return '0';
case 'h12':
return '12';
case 'h23':
return '00';
case 'h24':
return '24';
default:
throw new Error(`Invalid hour cycle "${hourCycle}"`);
}
}
const use24Hour = is24Hour(hourCycle);
/**
* h23 and h24 use 24 hour times.
*/
if (use24Hour) {
return addTimePadding(hour);
}
return hour.toString();
};
/**
* Generates an aria-label to be read by screen readers
* given a local, a date, and whether or not that date is
* today's date.
*/
const generateDayAriaLabel = (locale, today, refParts) => {
if (refParts.day === null) {
return null;
}
/**
* MM/DD/YYYY will return midnight in the user's timezone.
*/
const date = getNormalizedDate(refParts);
const labelString = new Intl.DateTimeFormat(locale, {
weekday: 'long',
month: 'long',
day: 'numeric',
timeZone: 'UTC',
}).format(date);
/**
* If date is today, prepend "Today" so screen readers indicate
* that the date is today.
*/
return today ? `Today, ${labelString}` : labelString;
};
/**
* Given a locale and a date object,
* return a formatted string that includes
* the month name and full year.
* Example: May 2021
*/
const getMonthAndYear = (locale, refParts) => {
const date = getNormalizedDate(refParts);
return new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric', timeZone: 'UTC' }).format(date);
};
/**
* Given a locale and a date object,
* return a formatted string that includes
* the numeric day.
* Note: Some languages will add literal characters
* to the end. This function removes those literals.
* Example: 29
*/
const getDay = (locale, refParts) => {
return getLocalizedDateTimeParts(locale, refParts, { day: 'numeric' }).find((obj) => obj.type === 'day').value;
};
/**
* Given a locale and a date object,
* return a formatted string that includes
* the numeric year.
* Example: 2022
*/
const getYear = (locale, refParts) => {
return getLocalizedDateTime(locale, refParts, { year: 'numeric' });
};
/**
* Given reference parts, return a JS Date object
* with a normalized time.
*/
const getNormalizedDate = (refParts) => {
var _a, _b, _c;
const timeString = refParts.hour !== undefined && refParts.minute !== undefined ? ` ${refParts.hour}:${refParts.minute}` : '';
/**
* We use / notation here for the date
* so we do not need to do extra work and pad values with zeroes.
* Values such as YYYY-MM are still valid, so
* we add fallback values so we still get
* a valid date otherwise we will pass in a string
* like "//2023". Some browsers, such as Chrome, will
* account for this and still return a valid date. However,
* this is not a consistent behavior across all browsers.
*/
return new Date(`${(_a = refParts.month) !== null && _a !== void 0 ? _a : 1}/${(_b = refParts.day) !== null && _b !== void 0 ? _b : 1}/${(_c = refParts.year) !== null && _c !== void 0 ? _c : 2023}${timeString} GMT+0000`);
};
/**
* Given a locale, DatetimeParts, and options
* format the DatetimeParts according to the options
* and locale combination. This returns a string. If
* you want an array of the individual pieces
* that make up the localized date string, use
* getLocalizedDateTimeParts.
*/
const getLocalizedDateTime = (locale, refParts, options) => {
const date = getNormalizedDate(refParts);
return getDateTimeFormat(locale, stripTimeZone(options)).format(date);
};
/**
* Given a locale, DatetimeParts, and options
* format the DatetimeParts according to the options
* and locale combination. This returns an array of
* each piece of the date.
*/
const getLocalizedDateTimeParts = (locale, refParts, options) => {
const date = getNormalizedDate(refParts);
return getDateTimeFormat(locale, options).formatToParts(date);
};
/**
* Wrapper function for Intl.DateTimeFormat.
* Allows developers to apply an allowed format to DatetimeParts.
* This function also has built in safeguards for older browser bugs
* with Intl.DateTimeFormat.
*/
const getDateTimeFormat = (locale, options) => {
return new Intl.DateTimeFormat(locale, Object.assign(Object.assign({}, options), { timeZone: 'UTC' }));
};
/**
* Gets a localized version of "Today"
* Falls back to "Today" in English for
* browsers that do not support RelativeTimeFormat.
*/
const getTodayLabel = (locale) => {
if ('RelativeTimeFormat' in Intl) {
const label = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(0, 'day');
return label.charAt(0).toUpperCase() + label.slice(1);
}
else {
return 'Today';
}
};
/**
* When calling toISOString(), the browser
* will convert the date to UTC time by either adding
* or subtracting the time zone offset.
* To work around this, we need to either add
* or subtract the time zone offset to the Date
* object prior to calling toISOString().
* This allows us to get an ISO string
* that is in the user's time zone.
*
* Example:
* Time zone offset is 240
* Meaning: The browser needs to add 240 minutes
* to the Date object to get UTC time.
* What Ionic does: We subtract 240 minutes
* from the Date object. The browser then adds
* 240 minutes in toISOString(). The result
* is a time that is in the user's time zone
* and not UTC.
*
* Note: Some timezones include minute adjustments
* such as 30 or 45 minutes. This is why we use setMinutes
* instead of setHours.
* Example: India Standard Time
* Timezone offset: -330 = -5.5 hours.
*
* List of timezones with 30 and 45 minute timezones:
* https://www.timeanddate.com/time/time-zones-interesting.html
*/
const removeDateTzOffset = (date) => {
const tzOffset = date.getTimezoneOffset();
date.setMinutes(date.getMinutes() - tzOffset);
return date;
};
const DATE_AM = removeDateTzOffset(new Date('2022T01:00'));
const DATE_PM = removeDateTzOffset(new Date('2022T13:00'));
/**
* Formats the locale's string representation of the day period (am/pm) for a given
* ref parts day period.
*
* @param locale The locale to format the day period in.
* @param value The date string, in ISO format.
* @returns The localized day period (am/pm) representation of the given value.
*/
const getLocalizedDayPeriod = (locale, dayPeriod) => {
const date = dayPeriod === 'am' ? DATE_AM : DATE_PM;
const localizedDayPeriod = new Intl.DateTimeFormat(locale, {
hour: 'numeric',
timeZone: 'UTC',
})
.formatToParts(date)
.find((part) => part.type === 'dayPeriod');
if (localizedDayPeriod) {
return localizedDayPeriod.value;
}
return getFormattedDayPeriod(dayPeriod);
};
/**
* Formats the datetime's value to a string, for use in the native input.
*
* @param value The value to format, either an ISO string or an array thereof.
*/
const formatValue = (value) => {
return Array.isArray(value) ? value.join(',') : value;
};
/**
* Returns the current date as
* an ISO string in the user's
* time zone.
*/
const getToday = () => {
/**
* ion-datetime intentionally does not
* parse time zones/do automatic time zone
* conversion when accepting user input.
* However when we get today's date string,
* we want it formatted relative to the user's
* time zone.
*
* When calling toISOString(), the browser
* will convert the date to UTC time by either adding
* or subtracting the time zone offset.
* To work around this, we need to either add
* or subtract the time zone offset to the Date
* object prior to calling toISOString().
* This allows us to get an ISO string
* that is in the user's time zone.
*/
return removeDateTzOffset(new Date()).toISOString();
};
const minutes = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
];
// h11 hour system uses 0-11. Midnight starts at 0:00am.
const hour11 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
// h12 hour system uses 0-12. Midnight starts at 12:00am.
const hour12 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
// h23 hour system uses 0-23. Midnight starts at 0:00.
const hour23 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23];
// h24 hour system uses 1-24. Midnight starts at 24:00.
const hour24 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 0];
/**
* Given a locale and a mode,
* return an array with formatted days
* of the week. iOS should display days
* such as "Mon" or "Tue".
* MD should display days such as "M"
* or "T".
*/
const getDaysOfWeek = (locale, mode, firstDayOfWeek = 0) => {
/**
* Nov 1st, 2020 starts on a Sunday.
* ion-datetime assumes weeks start on Sunday,
* but is configurable via `firstDayOfWeek`.
*/
const weekdayFormat = mode === 'ios' ? 'short' : 'narrow';
const intl = new Intl.DateTimeFormat(locale, { weekday: weekdayFormat });
const startDate = new Date('11/01/2020');
const daysOfWeek = [];
/**
* For each day of the week,
* get the day name.
*/
for (let i = firstDayOfWeek; i < firstDayOfWeek + 7; i++) {
const currentDate = new Date(startDate);
currentDate.setDate(currentDate.getDate() + i);
daysOfWeek.push(intl.format(currentDate));
}
return daysOfWeek;
};
/**
* Returns an array containing all of the
* days in a month for a given year. Values are
* aligned with a week calendar starting on
* the firstDayOfWeek value (Sunday by default)
* using null values.
*/
const getDaysOfMonth = (month, year, firstDayOfWeek, showAdjacentDays = false) => {
const numDays = getNumDaysInMonth(month, year);
let previousNumDays; //previous month number of days
if (month === 1) {
// If the current month is January, the previous month should be December of the previous year.
previousNumDays = getNumDaysInMonth(12, year - 1);
}
else {
// Otherwise, the previous month should be the current month - 1 of the same year.
previousNumDays = getNumDaysInMonth(month - 1, year);
}
const firstOfMonth = new Date(`${month}/1/${year}`).getDay();
/**
* To get the first day of the month aligned on the correct
* day of the week, we need to determine how many "filler" days
* to generate. These filler days as empty/disabled buttons
* that fill the space of the days of the week before the first
* of the month.
*
* There are two cases here:
*
* 1. If firstOfMonth = 4, firstDayOfWeek = 0 then the offset
* is (4 - (0 + 1)) = 3. Since the offset loop goes from 0 to 3 inclusive,
* this will generate 4 filler days (0, 1, 2, 3), and then day of week 4 will have
* the first day of the month.
*
* 2. If firstOfMonth = 2, firstDayOfWeek = 4 then the offset
* is (6 - (4 - 2)) = 4. Since the offset loop goes from 0 to 4 inclusive,
* this will generate 5 filler days (0, 1, 2, 3, 4), and then day of week 5 will have
* the first day of the month.
*/
const offset = firstOfMonth >= firstDayOfWeek ? firstOfMonth - (firstDayOfWeek + 1) : 6 - (firstDayOfWeek - firstOfMonth);
let days = [];
for (let i = 1; i <= numDays; i++) {
days.push({ day: i, dayOfWeek: (offset + i) % 7, isAdjacentDay: false });
}
if (showAdjacentDays) {
for (let i = 0; i <= offset; i++) {
// Using offset create previous month adjacent day, starting from last day
days = [{ day: previousNumDays - i, dayOfWeek: (previousNumDays - i) % 7, isAdjacentDay: true }, ...days];
}
// Calculate positiveOffset
// The calendar will display 42 days (6 rows of 7 columns)
// Knowing this the offset is 41 (we start at index 0)
// minus (the previous offset + the current month days)
const positiveOffset = 41 - (numDays + offset);
for (let i = 0; i < positiveOffset; i++) {
days.push({ day: i + 1, dayOfWeek: (numDays + offset + i) % 7, isAdjacentDay: true });
}
}
else {
for (let i = 0; i <= offset; i++) {
days = [{ day: null, dayOfWeek: null, isAdjacentDay: false }, ...days];
}
}
return days;
};
/**
* Returns an array of pre-defined hour
* values based on the provided hourCycle.
*/
const getHourData = (hourCycle) => {
switch (hourCycle) {
case 'h11':
return hour11;
case 'h12':
return hour12;
case 'h23':
return hour23;
case 'h24':
return hour24;
default:
throw new Error(`Invalid hour cycle "${hourCycle}"`);
}
};
/**
* Given a local, reference datetime parts and option
* max/min bound datetime parts, calculate the acceptable
* hour and minute values according to the bounds and locale.
*/
const generateTime = (locale, refParts, hourCycle = 'h12', minParts, maxParts, hourValues, minuteValues) => {
const computedHourCycle = getHourCycle(locale, hourCycle);
const use24Hour = is24Hour(computedHourCycle);
let processedHours = getHourData(computedHourCycle);
let processedMinutes = minutes;
let isAMAllowed = true;
let isPMAllowed = true;
if (hourValues) {
processedHours = processedHours.filter((hour) => hourValues.includes(hour));
}
if (minuteValues) {
processedMinutes = processedMinutes.filter((minute) => minuteValues.includes(minute));
}
if (minParts) {
/**
* If ref day is the same as the
* minimum allowed day, filter hour/minute
* values according to min hour and minute.
*/
if (isSameDay(refParts, minParts)) {
/**
* Users may not always set the hour/minute for
* min value (i.e. 2021-06-02) so we should allow
* all hours/minutes in that case.
*/
if (minParts.hour !== undefined) {
processedHours = processedHours.filter((hour) => {
const convertedHour = refParts.ampm === 'pm' ? (hour + 12) % 24 : hour;
return (use24Hour ? hour : convertedHour) >= minParts.hour;
});
isAMAllowed = minParts.hour < 13;
}
if (minParts.minute !== undefined) {
/**
* The minimum minute range should not be enforced when
* the hour is greater than the min hour.
*
* For example with a minimum range of 09:30, users
* should be able to select 10:00-10:29 and beyond.
*/
let isPastMinHour = false;
if (minParts.hour !== undefined && refParts.hour !== undefined) {
if (refParts.hour > minParts.hour) {
isPastMinHour = true;
}
}
processedMinutes = processedMinutes.filter((minute) => {
if (isPastMinHour) {
return true;
}
return minute >= minParts.minute;
});
}
/**
* If ref day is before minimum
* day do not render any hours/minute values
*/
}
else if (isBefore(refParts, minParts)) {
processedHours = [];
processedMinutes = [];
isAMAllowed = isPMAllowed = false;
}
}
if (maxParts) {
/**
* If ref day is the same as the
* maximum allowed day, filter hour/minute
* values according to max hour and minute.
*/
if (isSameDay(refParts, maxParts)) {
/**
* Users may not always set the hour/minute for
* max value (i.e. 2021-06-02) so we should allow
* all hours/minutes in that case.
*/
if (maxParts.hour !== undefined) {
processedHours = processedHours.filter((hour) => {
const convertedHour = refParts.ampm === 'pm' ? (hour + 12) % 24 : hour;
return (use24Hour ? hour : convertedHour) <= maxParts.hour;
});
isPMAllowed = maxParts.hour >= 12;
}
if (maxParts.minute !== undefined && refParts.hour === maxParts.hour) {
// The available minutes should only be filtered when the hour is the same as the max hour.
// For example if the max hour is 10:30 and the current hour is 10:00,
// users should be able to select 00-30 minutes.
// If the current hour is 09:00, users should be able to select 00-60 minutes.
processedMinutes = processedMinutes.filter((minute) => minute <= maxParts.minute);
}
/**
* If ref day is after minimum
* day do not render any hours/minute values
*/
}
else if (isAfter(refParts, maxParts)) {
processedHours = [];
processedMinutes = [];
isAMAllowed = isPMAllowed = false;
}
}
return {
hours: processedHours,
minutes: processedMinutes,
am: isAMAllowed,
pm: isPMAllowed,
};
};
/**
* Given DatetimeParts, generate the previous,
* current, and and next months.
*/
const generateMonths = (refParts, forcedDate) => {
const current = { month: refParts.month, year: refParts.year, day: refParts.day };
/**
* If we're forcing a month to appear, and it's different from the current month,
* ensure it appears by replacing the next or previous month as appropriate.
*/
if (forcedDate !== undefined && (refParts.month !== forcedDate.month || refParts.year !== forcedDate.year)) {
const forced = { month: forcedDate.month, year: forcedDate.year, day: forcedDate.day };
const forcedMonthIsBefore = isBefore(forced, current);
return forcedMonthIsBefore
? [forced, current, getNextMonth(refParts)]
: [getPreviousMonth(refParts), current, forced];
}
return [getPreviousMonth(refParts), current, getNextMonth(refParts)];
};
const getMonthColumnData = (locale, refParts, minParts, maxParts, monthValues, formatOptions = {
month: 'long',
}) => {
const { year } = refParts;
const months = [];
if (monthValues !== undefined) {
let processedMonths = monthValues;
if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.month) !== undefined) {
processedMonths = processedMonths.filter((month) => month <= maxParts.month);
}
if ((minParts === null || minParts === void 0 ? void 0 : minParts.month) !== undefined) {
processedMonths = processedMonths.filter((month) => month >= minParts.month);
}
processedMonths.forEach((processedMonth) => {
const date = new Date(`${processedMonth}/1/${year} GMT+0000`);
const monthString = new Intl.DateTimeFormat(locale, Object.assign(Object.assign({}, formatOptions), { timeZone: 'UTC' })).format(date);
months.push({ text: monthString, value: processedMonth });
});
}
else {
const maxMonth = maxParts && maxParts.year === year ? maxParts.month : 12;
const minMonth = minParts && minParts.year === year ? minParts.month : 1;
for (let i = minMonth; i <= maxMonth; i++) {
/**
*
* There is a bug on iOS 14 where
* Intl.DateTimeFormat takes into account
* the local timezone offset when formatting dates.
*
* Forcing the timezone to 'UTC' fixes the issue. However,
* we should keep this workaround as it is safer. In the event
* this breaks in another browser, we will not be impacted
* because all dates will be interpreted in UTC.
*
* Example:
* new Intl.DateTimeFormat('en-US', { month: 'long' }).format(new Date('Sat Apr 01 2006 00:00:00 GMT-0400 (EDT)')) // "March"
* new Intl.DateTimeFormat('en-US', { month: 'long', timeZone: 'UTC' }).format(new Date('Sat Apr 01 2006 00:00:00 GMT-0400 (EDT)')) // "April"
*
* In certain timezones, iOS 14 shows the wrong
* date for .toUTCString(). To combat this, we
* force all of the timezones to GMT+0000 (UTC).
*
* Example:
* Time Zone: Central European Standard Time
* new Date('1/1/1992').toUTCString() // "Tue, 31 Dec 1991 23:00:00 GMT"
* new Date('1/1/1992 GMT+0000').toUTCString() // "Wed, 01 Jan 1992 00:00:00 GMT"
*/
const date = new Date(`${i}/1/${year} GMT+0000`);
const monthString = new Intl.DateTimeFormat(locale, Object.assign(Object.assign({}, formatOptions), { timeZone: 'UTC' })).format(date);
months.push({ text: monthString, value: i });
}
}
return months;
};
/**
* Returns information regarding
* selectable dates (i.e 1st, 2nd, 3rd, etc)
* within a reference month.
* @param locale The locale to format the date with
* @param refParts The reference month/year to generate dates for
* @param minParts The minimum bound on the date that can be returned
* @param maxParts The maximum bound on the date that can be returned
* @param dayValues The allowed date values
* @returns Date data to be used in ion-picker-column
*/
const getDayColumnData = (locale, refParts, minParts, maxParts, dayValues, formatOptions = {
day: 'numeric',
}) => {
const { month, year } = refParts;
const days = [];
/**
* If we have max/min bounds that in the same
* month/year as the refParts, we should
* use the define day as the max/min day.
* Otherwise, fallback to the max/min days in a month.
*/
const numDaysInMonth = getNumDaysInMonth(month, year);
const maxDay = (maxParts === null || maxParts === void 0 ? void 0 : maxParts.day) !== null && (maxParts === null || maxParts === void 0 ? void 0 : maxParts.day) !== undefined && maxParts.year === year && maxParts.month === month
? maxParts.day
: numDaysInMonth;
const minDay = (minParts === null || minParts === void 0 ? void 0 : minParts.day) !== null && (minParts === null || minParts === void 0 ? void 0 : minParts.day) !== undefined && minParts.year === year && minParts.month === month
? minParts.day
: 1;
if (dayValues !== undefined) {
let processedDays = dayValues;
processedDays = processedDays.filter((day) => day >= minDay && day <= maxDay);
processedDays.forEach((processedDay) => {
const date = new Date(`${month}/${processedDay}/${year} GMT+0000`);
const dayString = new Intl.DateTimeFormat(locale, Object.assign(Object.assign({}, formatOptions), { timeZone: 'UTC' })).format(date);
days.push({ text: dayString, value: processedDay });
});
}
else {
for (let i = minDay; i <= maxDay; i++) {
const date = new Date(`${month}/${i}/${year} GMT+0000`);
const dayString = new Intl.DateTimeFormat(locale, Object.assign(Object.assign({}, formatOptions), { timeZone: 'UTC' })).format(date);
days.push({ text: dayString, value: i });
}
}
return days;
};
const getYearColumnData = (locale, refParts, minParts, maxParts, yearValues) => {
var _a, _b;
let processedYears = [];
if (yearValues !== undefined) {
processedYears = yearValues;
if ((maxParts === null || maxParts === void 0 ? void 0 : maxParts.year) !== undefined) {
processedYears = processedYears.filter((year) => year <= maxParts.year);
}
if ((minParts === null || minParts === void 0 ? void 0 : minParts.year) !== undefined) {
processedYears = processedYears.filter((year) => year >= minParts.year);
}
}
else {
const { year } = refParts;
const maxYear = (_a = maxParts === null || maxParts === void 0 ? void 0 : maxParts.year) !== null && _a !== void 0 ? _a : year;
const minYear = (_b = minParts === null || minParts === void 0 ? void 0 : minParts.year) !== null && _b !== void 0 ? _b : year - 100;
for (let i = minYear; i <= maxYear; i++) {
processedYears.push(i);
}
}
return processedYears.map((year) => ({
text: getYear(locale, { year, month: refParts.month, day: refParts.day }),
value: year,
}));
};
/**
* Given a starting date and an upper bound,
* this functions returns an array of all
* month objects in that range.
*/
const getAllMonthsInRange = (currentParts, maxParts) => {
if (currentParts.month === maxParts.month && currentParts.year === maxParts.year) {
return [currentParts];
}
return [currentParts, ...getAllMonthsInRange(getNextMonth(currentParts), maxParts)];
};
/**
* Creates and returns picker items
* that represent the days in a month.
* Example: "Thu, Jun 2"
*/
const getCombinedDateColumnData = (locale, todayParts, minParts, maxParts, dayValues, monthValues) => {
let items = [];
let parts = [];
/**
* Get all month objects from the min date
* to the max date. Note: Do not use getMonthColumnData
* as that function only generates dates within a
* single year.
*/
let months = getAllMonthsInRange(minParts, maxParts);
/**
* Filter out any disallowed month values.
*/
if (monthValues) {
months = months.filter(({ month }) => monthValues.includes(month));
}
/**
* Get all of the days in the month.
* From there, generate an array where
* each item has the month, date, and day
* of work as the text.
*/
months.forEach((monthObject) => {
const referenceMonth = { month: monthObject.month, day: null, year: monthObject.year };
const monthDays = getDayColumnData(locale, referenceMonth, minParts, maxParts, dayValues, {
month: 'short',
day: 'numeric',
weekday: 'short',
});
const dateParts = [];
const dateColumnItems = [];
monthDays.forEach((dayObject) => {
const isToday = isSameDay(Object.assign(Object.assign({}, referenceMonth), { day: dayObject.value }), todayParts);
/**
* Today's date should read as "Today" (localized)
* not the actual date string
*/
dateColumnItems.push({
text: isToday ? getTodayLabel(locale) : dayObject.text,
value: `${referenceMonth.year}-${referenceMonth.month}-${dayObject.value}`,
});
/**
* When selecting a date in the wheel picker
* we need access to the raw datetime parts data.
* The picker column only accepts values of
* type string or number, so we need to return
* two sets of data: A data set to be passed
* to the picker column, and a data set to
* be used to reference the raw data when
* updating the picker column value.
*/
dateParts.push({
month: referenceMonth.month,
year: referenceMonth.year,
day: dayObject.value,
});
});
parts = [...parts, ...dateParts];
items = [...items, ...dateColumnItems];
});
return {
parts,
items,
};
};
const getTimeColumnsData = (locale, refParts, hourCycle, minParts, maxParts, allowedHourValues, allowedMinuteValues) => {
const computedHourCycle = getHourCycle(locale, hourCycle);
const use24Hour = is24Hour(computedHourCycle);
const { hours, minutes, am, pm } = generateTime(locale, refParts, computedHourCycle, minParts, maxParts, allowedHourValues, allowedMinuteValues);
const hoursItems = hours.map((hour) => {
return {
text: getFormattedHour(hour, computedHourCycle),
value: getInternalHourValue(hour, use24Hour, refParts.ampm),
};
});
const minutesItems = minutes.map((minute) => {
return {
text: addTimePadding(minute),
value: minute,
};
});
const dayPeriodItems = [];
if (am && !use24Hour) {
dayPeriodItems.push({
text: getLocalizedDayPeriod(locale, 'am'),
value: 'am',
});
}
if (pm && !use24Hour) {
dayPeriodItems.push({
text: getLocalizedDayPeriod(locale, 'pm'),
value: 'pm',
});
}
return {
minutesData: minutesItems,
hoursData: hoursItems,
dayPeriodData: dayPeriodItems,
};
};
const isYearDisabled = (refYear, minParts, maxParts) => {
if (minParts && minParts.year > refYear) {
return true;
}
if (maxParts && maxParts.year < refYear) {
return true;
}
return false;
};
/**
* Returns true if a given day should
* not be interactive according to its value,
* or the max/min dates.
*/
const isDayDisabled = (refParts, minParts, maxParts, dayValues) => {
/**
* If this is a filler date (i.e. padding)
* then the date is disabled.
*/
if (refParts.day === null) {
return true;
}
/**
* If user passed in a list of acceptable day values
* check to make sure that the date we are looking
* at is in this array.
*/
if (dayValues !== undefined && !dayValues.includes(refParts.day)) {
return true;
}
/**
* Given a min date, perform the following
* checks. If any of them are true, then the
* day should be disabled:
* 1. Is the current year < the min allowed year?
* 2. Is the current year === min allowed year,
* but the current month < the min allowed month?
* 3. Is the current year === min allowed year, the
* current month === min allow month, but the current
* day < the min allowed day?
*/
if (minParts && isBefore(refParts, minParts)) {
return true;
}
/**
* Given a max date, perform the following
* checks. If any of them are true, then the
* day should be disabled:
* 1. Is the current year > the max allowed year?
* 2. Is the current year === max allowed year,
* but the current month > the max allowed month?
* 3. Is the current year === max allowed year, the
* current month === max allow month, but the current
* day > the max allowed day?
*/
if (maxParts && isAfter(refParts, maxParts)) {
return true;
}
/**
* If none of these checks
* passed then the date should
* be interactive.
*/
return false;
};
/**
* Given a locale, a date, the selected date(s), and today's date,
* generate the state for a given calendar day button.
*/
const getCalendarDayState = (locale, refParts, activeParts, todayParts, minParts, maxParts, dayValues) => {
/**
* activeParts signals what day(s) are currently selected in the datetime.
* If multiple="true", this will be an array, but the logic in this util
* is the same whether we have one selected day or many because we're only
* calculating the state for one button. So, we treat a single activeParts value
* the same as an array of length one.
*/
const activePartsArray = Array.isArray(activeParts) ? activeParts : [activeParts];
/**
* The day button is active if it is selected, or in other words, if refParts
* matches at least one selected date.
*/
const isActive = activePartsArray.find((parts) => isSameDay(refParts, parts)) !== undefined;
const isToday = isSameDay(refParts, todayParts);
const disabled = isDayDisabled(refParts, minParts, maxParts, dayValues);
/**
* Note that we always return one object regardless of whether activeParts
* was an array, since we pare down to one value for isActive.
*/
return {
disabled,
isActive,
isToday,
ariaSelected: isActive ? 'true' : null,
ariaLabel: generateDayAriaLabel(locale, isToday, refParts),
text: refParts.day != null ? getDay(locale, refParts) : null,
};
};
/**
* Returns `true` if the month is disabled given the
* current date value and min/max date constraints.
*/
const isMonthDisabled = (refParts, { minParts, maxParts, }) => {
// If the year is disabled then the month is disabled.
if (isYearDisabled(refParts.year, minParts, maxParts)) {
return true;
}
// If the date value is before the min date, then the month is disabled.
// If the date value is after the max date, then the month is disabled.
if ((minParts && isBefore(refParts, minParts)) || (maxParts && isAfter(refParts, maxParts))) {
return true;
}
return false;
};
/**
* Given a working date, an optional minimum date range,
* and an optional maximum date range; determine if the
* previous navigation button is disabled.
*/
const isPrevMonthDisabled = (refParts, minParts, maxParts) => {
const prevMonth = Object.assign(Object.assign({}, getPreviousMonth(refParts)), { day: null });
return isMonthDisabled(prevMonth, {
minParts,
maxParts,
});
};
/**
* Given a working date and a maximum date range,
* determine if the next navigation button is disabled.
*/
const isNextMonthDisabled = (refParts, maxParts) => {
const nextMonth = Object.assign(Object.assign({}, getNextMonth(refParts)), { day: null });
return isMonthDisabled(nextMonth, {
maxParts,
});
};
/**
* Given the value of the highlightedDates property
* and an ISO string, return the styles to use for
* that date, or undefined if none are found.
*/
const getHighlightStyles = (highlightedDates, dateIsoString, el) => {
if (Array.isArray(highlightedDates)) {
const dateStringWithoutTime = dateIsoString.split('T')[0];
const matchingHighlight = highlightedDates.find((hd) => hd.date === dateStringWithoutTime);
if (matchingHighlight) {
return {
textColor: matchingHighlight.textColor,
backgroundColor: matchingHighlight.backgroundColor,
border: matchingHighlight.border,
};
}
}
else {
/**
* Wrap in a try-catch to prevent exceptions in the user's function
* from interrupting the calendar's rendering.
*/
try {
return highlightedDates(dateIsoString);
}
catch (e) {
printIonError('[ion-datetime] - Exception thrown from provided `highlightedDates` callback. Please check your function and try again.', el, e);
}
}
return undefined;
};
/**
* If a time zone is provided in the format options, the rendered text could
* differ from what was selected in the Datetime, which could cause
* confusion.
*/
const warnIfTimeZoneProvided = (el, formatOptions) => {
var _a, _b, _c, _d;
if (((_a = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.date) === null || _a === void 0 ? void 0 : _a.timeZone) ||
((_b = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.date) === null || _b === void 0 ? void 0 : _b.timeZoneName) ||
((_c = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time) === null || _c === void 0 ? void 0 : _c.timeZone) ||
((_d = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time) === null || _d === void 0 ? void 0 : _d.timeZoneName)) {
printIonWarning('[ion-datetime] - "timeZone" and "timeZoneName" are not supported in "formatOptions".', el);
}
};
const checkForPresentationFormatMismatch = (el, presentation, formatOptions) => {
// formatOptions is not required
if (!formatOptions)
return;
// If formatOptions is provided, the date and/or time objects are required, depending on the presentation
switch (presentation) {
case 'date':
case 'month-year':
case 'month':
case 'year':
if (formatOptions.date === undefined) {
printIonWarning(`[ion-datetime] - The '${presentation}' presentation requires a date object in formatOptions.`, el);
}
break;
case 'time':
if (formatOptions.time === undefined) {
printIonWarning(`[ion-datetime] - The 'time' presentation requires a time object in formatOptions.`, el);
}
break;
case 'date-time':
case 'time-date':
if (formatOptions.date === undefined && formatOptions.time === undefined) {
printIonWarning(`[ion-datetime] - The '${presentation}' presentation requires either a date or time object (or both) in formatOptions.`, el);
}
break;
}
};
const datetimeIosCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-flow:column;flex-flow:column;background:var(--background);overflow:hidden}:host(.datetime-size-fixed){width:auto;height:auto}:host(.datetime-size-fixed:not(.datetime-prefer-wheel)){max-width:350px}:host(.datetime-size-fixed.datetime-prefer-wheel){min-width:350px;max-width:-webkit-max-content;max-width:-moz-max-content;max-width:max-content}:host(.datetime-size-cover){width:100%}:host .calendar-body,:host .datetime-year{opacity:0}:host(:not(.datetime-ready)) .datetime-year{position:absolute;pointer-events:none}:host(.datetime-ready) .calendar-body{opacity:1}:host(.datetime-ready) .datetime-year{display:none;opacity:1}:host .wheel-order-year-first .day-column{-ms-flex-order:3;order:3;text-align:end}:host .wheel-order-year-first .month-column{-ms-flex-order:2;order:2;text-align:end}:host .wheel-order-year-first .year-column{-ms-flex-order:1;order:1;text-align:start}:host .datetime-calendar,:host .datetime-year{display:-ms-flexbox;display:flex;-ms-flex:1 1 auto;flex:1 1 auto;-ms-flex-flow:column;flex-flow:column}:host(.show-month-and-year) .datetime-year{display:-ms-flexbox;display:flex}:host(.show-month-and-year) .calendar-next-prev,:host(.show-month-and-year) .calendar-days-of-week,:host(.show-month-and-year) .calendar-body,:host(.show-month-and-year) .datetime-time{display:none}:host(.month-year-picker-open) .datetime-footer{display:none}:host(.datetime-disabled){pointer-events:none}:host(.datetime-disabled) .calendar-days-of-week,:host(.datetime-disabled) .datetime-time{opacity:0.4}:host(.datetime-readonly){pointer-events:none;}:host(.datetime-readonly) .calendar-action-buttons,:host(.datetime-readonly) .calendar-body,:host(.datetime-readonly) .datetime-year{pointer-events:initial}:host(.datetime-readonly) .calendar-day[disabled]:not(.calendar-day-constrained),:host(.datetime-readonly) .datetime-action-buttons ion-button[disabled]{opacity:1}:host .datetime-header .datetime-title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host .datetime-action-buttons.has-clear-button{width:100%}:host .datetime-action-buttons ion-buttons{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between}.datetime-action-buttons .datetime-action-buttons-container{display:-ms-flexbox;display:flex}:host .calendar-action-buttons{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between}:host .calendar-action-buttons ion-button{--background:transparent}:host .calendar-days-of-week{display:grid;grid-template-columns:repeat(7, 1fr);text-align:center}.calendar-days-of-week .day-of-week{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0}:host .calendar-body{display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;-webkit-scroll-snap-type:x mandatory;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;overflow-x:scroll;overflow-y:hidden;scrollbar-width:none;outline:none}:host .calendar-body .calendar-month{display:-ms-flexbox;display:flex;-ms-flex-flow:column;flex-flow:column;scroll-snap-align:start;scroll-snap-stop:always;-ms-flex-negative:0;flex-shrink:0;width:100%}:host .calendar-body .calendar-month-disabled{scroll-snap-align:none}:host .calendar-body::-webkit-scrollbar{display:none}:host .calendar-body .calendar-month-grid{display:grid;grid-template-columns:repeat(7, 1fr)}:host .calendar-day-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:0;min-height:0;overflow:visible}.calendar-day{border-radius:50%;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:0px;padding-bottom:0px;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;margin-top:0px;margin-bottom:0px;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;border:none;outline:none;background:none;color:currentColor;font-family:var(--ion-font-family, inherit);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;z-index:0}:host .calendar-day[disabled]{pointer-events:none;opacity:0.4}.calendar-day:not(.calendar-day-adjacent-day):focus{background:rgba(var(--ion-color-base-rgb), 0.2);-webkit-box-shadow:0px 0px 0px 4px rgba(var(--ion-color-base-rgb), 0.2);box-shadow:0px 0px 0px 4px rgba(var(--ion-color-base-rgb), 0.2)}:host .datetime-time{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between}:host(.datetime-presentation-time) .datetime-time{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}:host ion-popover{--height:200px}:host .time-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}:host .time-body{border-radius:8px;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px;display:-ms-flexbox;display:flex;border:none;background:var(--ion-color-step-300, var(--ion-background-color-step-300, #edeef0));color:var(--ion-text-color, #000);font-family:inherit;font-size:inherit;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host .time-body-active{color:var(--ion-color-base)}:host(.in-item){position:static}:host(.show-month-and-year) .calendar-action-buttons .calendar-month-year-toggle{color:var(--ion-color-base)}.calendar-month-year{min-width:0}.calendar-month-year-toggle{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;position:relative;border:0;outline:none;background:transparent;cursor:pointer;z-index:1}.calendar-month-year-toggle::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0;-webkit-transition:opacity 15ms linear, background-color 15ms linear;transition:opacity 15ms linear, background-color 15ms linear;z-index:-1}.calendar-month-year-toggle.ion-focused::after{background:currentColor}.calendar-month-year-toggle:disabled{opacity:0.3;pointer-events:none}.calendar-month-year-toggle ion-icon{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:0;padding-inline-end:0;padding-top:0;padding-bottom:0;-ms-flex-negative:0;flex-shrink:0}.calendar-month-year-toggle #toggle-wrapper{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center}ion-picker{--highlight-background:var(--wheel-highlight-background);--highlight-border-radius:var(--wheel-highlight-border-radius);--fade-background-rgb:var(--wheel-fade-background-rgb)}:host{--background:var(--ion-color-light, #f4f5f8);--background-rgb:var(--ion-color-light-rgb, 244, 245, 248);--title-color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}:host(.datetime-presentation-date-time:not(.datetime-prefer-wheel)),:host(.datetime-presentation-time-date:not(.datetime-prefer-wheel)),:host(.datetime-presentation-date:not(.datetime-prefer-wheel)){min-height:350px}:host .datetime-header{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:16px;padding-bottom:16px;border-bottom:0.55px solid var(--ion-color-step-200, var(--ion-background-color-step-200, #cccccc));font-size:min(0.875rem, 22.4px)}:host .datetime-header .datetime-title{color:var(--title-color)}:host .datetime-header .datetime-selected-date{margin-top:10px}.calendar-month-year-toggle{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:0px;padding-bottom:0px;min-height:44px;font-size:min(1rem, 25.6px);font-weight:600}.calendar-month-year-toggle.ion-focused::after{opacity:0.15}.calendar-month-year-toggle #toggle-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:10px;margin-bottom:10px}:host .calendar-action-buttons .calendar-month-year-toggle ion-icon,:host .calendar-action-buttons ion-buttons ion-button{color:var(--ion-color-base)}:host .calendar-action-buttons ion-buttons{padding-left:0;padding-right:0;padding-top:8px;padding-bottom:0}:host .calendar-action-buttons ion-buttons ion-button{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}:host .calendar-days-of-week{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:0;padding-bottom:0;color:var(--ion-color-step-300, var(--ion-text-color-step-700, #b3b3b3));font-size:min(0.75rem, 19.2px);font-weight:600;line-height:24px;text-transform:uppercase}@supports (border-radius: mod(1px, 1px)){.calendar-days-of-week .day-of-week{width:clamp(20px, calc(mod(min(1rem, 24px), 24px) * 10), 100%);height:24px;overflow:hidden}.calendar-day{border-radius:max(8px, mod(min(1rem, 24px), 24px) * 10)}}@supports ((border-radius: mod(1px, 1px)) and (background: -webkit-named-image(apple-pay-logo-black)) and (not (contain-intrinsic-size: none))) or (not (border-radius: mod(1px, 1px))){.calendar-days-of-week .day-of-week{width:auto;height:auto;overflow:initial}.calendar-day{border-radius:32px}}:host .calendar-body .calendar-month .calendar-month-grid{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:8px;padding-bottom:8px;-ms-flex-align:center;align-items:center;height:calc(100% - 16px)}:host .calendar-day-wrapper{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;height:0;min-height:1rem}:host .calendar-day{width:40px;min-width:40px;height:40px;font-size:min(1.25rem, 32px)}.calendar-day.calendar-day-active{background:rgba(var(--ion-color-base-rgb), 0.2);font-size:min(1.375rem, 35.2px)}:host .calendar-day.calendar-day-today{color:var(--ion-color-base)}:host .calendar-day.calendar-day-active,:host .calendar-day.calendar-day-adjacent-day.calendar-day-active{color:var(--ion-color-base);font-weight:600}:host .calendar-day.calendar-day-today.calendar-day-active{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host .calendar-day.calendar-day-adjacent-day{color:var(--ion-color-step-300, var(--ion-text-color-step-700, #b3b3b3))}:host .datetime-time{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:8px;padding-bottom:16px;font-size:min(1rem, 25.6px)}:host .datetime-time .time-header{font-weight:600}:host .datetime-buttons{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:8px;padding-bottom:8px;border-top:0.55px solid var(--ion-color-step-200, var(--ion-background-color-step-200, #cccccc))}:host .datetime-buttons ::slotted(ion-buttons),:host .datetime-buttons ion-buttons{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between}:host .datetime-action-buttons{width:100%}";
const datetimeMdCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-flow:column;flex-flow:column;background:var(--background);overflow:hidden}:host(.datetime-size-fixed){width:auto;height:auto}:host(.datetime-size-fixed:not(.datetime-prefer-wheel)){max-width:350px}:host(.datetime-size-fixed.datetime-prefer-wheel){min-width:350px;max-width:-webkit-max-content;max-width:-moz-max-content;max-width:max-content}:host(.datetime-size-cover){width:100%}:host .calendar-body,:host .datetime-year{opacity:0}:host(:not(.datetime-ready)) .datetime-year{position:absolute;pointer-events:none}:host(.datetime-ready) .calendar-body{opacity:1}:host(.datetime-ready) .datetime-year{display:none;opacity:1}:host .wheel-order-year-first .day-column{-ms-flex-order:3;order:3;text-align:end}:host .wheel-order-year-first .month-column{-ms-flex-order:2;order:2;text-align:end}:host .wheel-order-year-first .year-column{-ms-flex-order:1;order:1;text-align:start}:host .datetime-calendar,:host .datetime-year{display:-ms-flexbox;display:flex;-ms-flex:1 1 auto;flex:1 1 auto;-ms-flex-flow:column;flex-flow:column}:host(.show-month-and-year) .datetime-year{display:-ms-flexbox;display:flex}:host(.show-month-and-year) .calendar-next-prev,:host(.show-month-and-year) .calendar-days-of-week,:host(.show-month-and-year) .calendar-body,:host(.show-month-and-year) .datetime-time{display:none}:host(.month-year-picker-open) .datetime-footer{display:none}:host(.datetime-disabled){pointer-events:none}:host(.datetime-disabled) .calendar-days-of-week,:host(.datetime-disabled) .datetime-time{opacity:0.4}:host(.datetime-readonly){pointer-events:none;}:host(.datetime-readonly) .calendar-action-buttons,:host(.datetime-readonly) .calendar-body,:host(.datetime-readonly) .datetime-year{pointer-events:initial}:host(.datetime-readonly) .calendar-day[disabled]:not(.calendar-day-constrained),:host(.datetime-readonly) .datetime-action-buttons ion-button[disabled]{opacity:1}:host .datetime-header .datetime-title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host .datetime-action-buttons.has-clear-button{width:100%}:host .datetime-action-buttons ion-buttons{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between}.datetime-action-buttons .datetime-action-buttons-container{display:-ms-flexbox;display:flex}:host .calendar-action-buttons{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between}:host .calendar-action-buttons ion-button{--background:transparent}:host .calendar-days-of-week{display:grid;grid-template-columns:repeat(7, 1fr);text-align:center}.calendar-days-of-week .day-of-week{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0}:host .calendar-body{display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;-webkit-scroll-snap-type:x mandatory;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;overflow-x:scroll;overflow-y:hidden;scrollbar-width:none;outline:none}:host .calendar-body .calendar-month{display:-ms-flexbox;display:flex;-ms-flex-flow:column;flex-flow:column;scroll-snap-align:start;scroll-snap-stop:always;-ms-flex-negative:0;flex-shrink:0;width:100%}:host .calendar-body .calendar-month-disabled{scroll-snap-align:none}:host .calendar-body::-webkit-scrollbar{display:none}:host .calendar-body .calendar-month-grid{display:grid;grid-template-columns:repeat(7, 1fr)}:host .calendar-day-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:0;min-height:0;overflow:visible}.calendar-day{border-radius:50%;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:0px;padding-bottom:0px;-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;margin-top:0px;margin-bottom:0px;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;border:none;outline:none;background:none;color:currentColor;font-family:var(--ion-font-family, inherit);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;z-index:0}:host .calendar-day[disabled]{pointer-events:none;opacity:0.4}.calendar-day:not(.calendar-day-adjacent-day):focus{background:rgba(var(--ion-color-base-rgb), 0.2);-webkit-box-shadow:0px 0px 0px 4px rgba(var(--ion-color-base-rgb), 0.2);box-shadow:0px 0px 0px 4px rgba(var(--ion-color-base-rgb), 0.2)}:host .datetime-time{display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between}:host(.datetime-presentation-time) .datetime-time{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0}:host ion-popover{--height:200px}:host .time-header{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}:host .time-body{border-radius:8px;-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px;display:-ms-flexbox;display:flex;border:none;background:var(--ion-color-step-300, var(--ion-background-color-step-300, #edeef0));color:var(--ion-text-color, #000);font-family:inherit;font-size:inherit;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host .time-body-active{color:var(--ion-color-base)}:host(.in-item){position:static}:host(.show-month-and-year) .calendar-action-buttons .calendar-month-year-toggle{color:var(--ion-color-base)}.calendar-month-year{min-width:0}.calendar-month-year-toggle{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;position:relative;border:0;outline:none;background:transparent;cursor:pointer;z-index:1}.calendar-month-year-toggle::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0;-webkit-transition:opacity 15ms linear, background-color 15ms linear;transition:opacity 15ms linear, background-color 15ms linear;z-index:-1}.calendar-month-year-toggle.ion-focused::after{background:currentColor}.calendar-month-year-toggle:disabled{opacity:0.3;pointer-events:none}.calendar-month-year-toggle ion-icon{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:0;padding-inline-end:0;padding-top:0;padding-bottom:0;-ms-flex-negative:0;flex-shrink:0}.calendar-month-year-toggle #toggle-wrapper{display:-ms-inline-flexbox;display:inline-flex;-ms-flex-align:center;align-items:center}ion-picker{--highlight-background:var(--wheel-highlight-background);--highlight-border-radius:var(--wheel-highlight-border-radius);--fade-background-rgb:var(--wheel-fade-background-rgb)}:host{--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #ffffff));--title-color:var(--ion-color-contrast)}:host .datetime-header{-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px;padding-top:20px;padding-bottom:20px;background:var(--ion-color-base);color:var(--title-color)}:host .datetime-header .datetime-title{font-size:0.75rem;text-transform:uppercase}:host .datetime-header .datetime-selected-date{margin-top:30px;font-size:2.125rem}:host .calendar-action-buttons ion-button{--color:var(--ion-color-step-650, var(--ion-text-color-step-350, #595959))}.calendar-month-year-toggle{-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:12px;padding-bottom:12px;min-height:48px;background:transparent;color:var(--ion-color-step-650, var(--ion-text-color-step-350, #595959));z-index:1}.calendar-month-year-toggle.ion-focused::after{opacity:0.04}.calendar-month-year-toggle ion-ripple-effect{color:currentColor}@media (any-hover: hover){.calendar-month-year-toggle.ion-activatable:not(.ion-focused):hover::after{background:currentColor;opacity:0.04}}:host .calendar-days-of-week{-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px;padding-top:0px;padding-bottom:0px;color:var(--ion-color-step-500, var(--ion-text-color-step-500, gray));font-size:0.875rem;line-height:36px}:host .calendar-body .calendar-month .calendar-month-grid{-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px;padding-top:4px;padding-bottom:4px;grid-template-rows:repeat(6, 1fr)}:host .calendar-day{width:42px;min-width:42px;height:42px;font-size:0.875rem}:host .calendar-day.calendar-day-today{border:1px solid var(--ion-color-base);color:var(--ion-color-base)}:host .calendar-day.calendar-day-active,:host .calendar-day.calendar-day-adjacent-day.calendar-day-active{color:var(--ion-color-contrast)}.calendar-day.calendar-day-active,.calendar-day.calendar-day-active:focus{border:1px solid var(--ion-color-base);background:var(--ion-color-base)}:host .calendar-day.calendar-day-adjacent-day{color:var(--ion-color-step-500, var(--ion-text-color-step-500, gray))}:host .datetime-time{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:8px;padding-bottom:8px}:host .time-header{color:var(--ion-color-step-650, var(--ion-text-color-step-350, #595959))}:host(.datetime-presentation-month) .datetime-year,:host(.datetime-presentation-year) .datetime-year,:host(.datetime-presentation-month-year) .datetime-year{margin-top:20px;margin-bottom:20px}:host .datetime-buttons{-webkit-padding-start:10px;padding-inline-start:10px;-webkit-padding-end:10px;padding-inline-end:10px;padding-top:10px;padding-bottom:10px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:end;justify-content:flex-end}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot title - The title of the datetime.
* @slot buttons - The buttons in the datetime.
* @slot time-label - The label for the time selector in the datetime.
*
* @part wheel-item - The individual items when using a wheel style layout, or in the
* month/year picker when using a grid style layout.
* @part wheel-item active - The currently selected wheel-item.
*
* @part time-button - The button that opens the time picker when using a grid style
* layout with `presentation="date-time"` or `"time-date"`.
* @part time-button active - The time picker button when the picker is open.
*
* @part month-year-button - The button that opens the month/year picker when
* using a grid style layout.
*
* @part calendar-day - The individual buttons that display a day inside of the datetime
* calendar.
* @part calendar-day active - The currently selected calendar day.
* @part calendar-day today - The calendar day that contains the current day.
* @part calendar-day disabled - The calendar day that is disabled.
*/
class Datetime {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionCancel = createEvent(this, "ionCancel", 7);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionValueChange = createEvent(this, "ionValueChange", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionStyle = createEvent(this, "ionStyle", 7);
this.ionRender = createEvent(this, "ionRender", 7);
this.inputId = `ion-dt-${datetimeIds++}`;
this.prevPresentation = null;
this.showMonthAndYear = false;
this.activeParts = [];
this.workingParts = {
month: 5,
day: 28,
year: 2021,
hour: 13,
minute: 52,
ampm: 'pm',
isAdjacentDay: false,
};
this.isTimePopoverOpen = false;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
this.color = 'primary';
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* If `true`, the user cannot interact with the datetime.
*/
this.disabled = false;
/**
* If `true`, the datetime appears normal but the selected date cannot be changed.
*/
this.readonly = false;
/**
* If `true`, the datetime calendar displays a six-week (42-day) layout,
* including days from the previous and next months to fill the grid.
* These adjacent days are selectable unless disabled.
*/
this.showAdjacentDays = false;
/**
* Which values you want to select. `"date"` will show
* a calendar picker to select the month, day, and year. `"time"`
* will show a time picker to select the hour, minute, and (optionally)
* AM/PM. `"date-time"` will show the date picker first and time picker second.
* `"time-date"` will show the time picker first and date picker second.
*/
this.presentation = 'date-time';
/**
* The text to display on the picker's cancel button.
*/
this.cancelText = 'Cancel';
/**
* The text to display on the picker's "Done" button.
*/
this.doneText = 'Done';
/**
* The text to display on the picker's "Clear" button.
*/
this.clearText = 'Clear';
/**
* The locale to use for `ion-datetime`. This
* impacts month and day name formatting.
* The `"default"` value refers to the default
* locale set by your device.
*/
this.locale = 'default';
/**
* The first day of the week to use for `ion-datetime`. The
* default value is `0` and represents Sunday.
*/
this.firstDayOfWeek = 0;
/**
* If `true`, multiple dates can be selected at once. Only
* applies to `presentation="date"` and `preferWheel="false"`.
*/
this.multiple = false;
/**
* If `true`, a header will be shown above the calendar
* picker. This will include both the slotted title, and
* the selected date.
*/
this.showDefaultTitle = false;
/**
* If `true`, the default "Cancel" and "OK" buttons
* will be rendered at the bottom of the `ion-datetime`
* component. Developers can also use the `button` slot
* if they want to customize these buttons. If custom
* buttons are set in the `button` slot then the
* default buttons will not be rendered.
*/
this.showDefaultButtons = false;
/**
* If `true`, a "Clear" button will be rendered alongside
* the default "Cancel" and "OK" buttons at the bottom of the `ion-datetime`
* component. Developers can also use the `button` slot
* if they want to customize these buttons. If custom
* buttons are set in the `button` slot then the
* default buttons will not be rendered.
*/
this.showClearButton = false;
/**
* If `true`, the default "Time" label will be rendered
* for the time selector of the `ion-datetime` component.
* Developers can also use the `time-label` slot
* if they want to customize this label. If a custom
* label is set in the `time-label` slot then the
* default label will not be rendered.
*/
this.showDefaultTimeLabel = true;
/**
* If `cover`, the `ion-datetime` will expand to cover the full width of its container.
* If `fixed`, the `ion-datetime` will have a fixed width.
*/
this.size = 'fixed';
/**
* If `true`, a wheel picker will be rendered instead of a calendar grid
* where possible. If `false`, a calendar grid will be rendered instead of
* a wheel picker where possible.
*
* A wheel picker can be rendered instead of a grid when `presentation` is
* one of the following values: `"date"`, `"date-time"`, or `"time-date"`.
*
* A wheel picker will always be rendered regardless of
* the `preferWheel` value when `presentation` is one of the following values:
* `"time"`, `"month"`, `"month-year"`, or `"year"`.
*/
this.preferWheel = false;
this.warnIfIncorrectValueUsage = () => {
const { multiple, value } = this;
if (!multiple && Array.isArray(value)) {
/**
* We do some processing on the `value` array so
* that it looks more like an array when logged to
* the console.
* Example given ['a', 'b']
* Default toString() behavior: a,b
* Custom behavior: ['a', 'b']
*/
printIonWarning(`[ion-datetime] - An array of values was passed, but multiple is "false". This is incorrect usage and may result in unexpected behaviors. To dismiss this warning, pass a string to the "value" property when multiple="false".
Value Passed: [${value.map((v) => `'${v}'`).join(', ')}]
`, this.el);
}
};
this.setValue = (value) => {
this.value = value;
this.ionChange.emit({ value });
};
/**
* Returns the DatetimePart interface
* to use when rendering an initial set of
* data. This should be used when rendering an
* interface in an environment where the `value`
* may not be set. This function works
* by returning the first selected date and then
* falling back to defaultParts if no active date
* is selected.
*/
this.getActivePartsWithFallback = () => {
var _a;
const { defaultParts } = this;
return (_a = this.getActivePart()) !== null && _a !== void 0 ? _a : defaultParts;
};
this.getActivePart = () => {
const { activeParts } = this;
return Array.isArray(activeParts) ? activeParts[0] : activeParts;
};
this.closeParentOverlay = (role) => {
const popoverOrModal = this.el.closest('ion-modal, ion-popover');
if (popoverOrModal) {
popoverOrModal.dismiss(undefined, role);
}
};
this.setWorkingParts = (parts) => {
this.workingParts = Object.assign({}, parts);
};
this.setActiveParts = (parts, removeDate = false) => {
/** if the datetime component is in readonly mode,
* allow browsing of the calendar without changing
* the set value
*/
if (this.readonly) {
return;
}
const { multiple, minParts, maxParts, activeParts } = this;
/**
* When setting the active parts, it is possible
* to set invalid data. For example,
* when updating January 31 to February,
* February 31 does not exist. As a result
* we need to validate the active parts and
* ensure that we are only setting valid dates.
* Additionally, we need to update the working parts
* too in the event that the validated parts are different.
*/
const validatedParts = validateParts(parts, minParts, maxParts);
this.setWorkingParts(validatedParts);
if (multiple) {
const activePartsArray = Array.isArray(activeParts) ? activeParts : [activeParts];
if (removeDate) {
this.activeParts = activePartsArray.filter((p) => !isSameDay(p, validatedParts));
}
else {
this.activeParts = [...activePartsArray, validatedParts];
}
}
else {
this.activeParts = Object.assign({}, validatedParts);
}
const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
if (hasSlottedButtons || this.showDefaultButtons) {
return;
}
this.confirm();
};
this.initializeKeyboardListeners = () => {
const calendarBodyRef = this.calendarBodyRef;
if (!calendarBodyRef) {
return;
}
const root = this.el.shadowRoot;
/**
* Get a reference to the month
* element we are currently viewing.
*/
const currentMonth = calendarBodyRef.querySelector('.calendar-month:nth-of-type(2)');
/**
* When focusing the calendar body, we want to pass focus
* to the working day, but other days should
* only be accessible using the arrow keys. Pressing
* Tab should jump between bodies of selectable content.
*/
const checkCalendarBodyFocus = (ev) => {
var _a;
const record = ev[0];
/**
* If calendar body was already focused
* when this fired or if the calendar body
* if not currently focused, we should not re-focus
* the inner day.
*/
if (((_a = record.oldValue) === null || _a === void 0 ? void 0 : _a.includes('ion-focused')) || !calendarBodyRef.classList.contains('ion-focused')) {
return;
}
this.focusWorkingDay(currentMonth);
};
const mo = new MutationObserver(checkCalendarBodyFocus);
mo.observe(calendarBodyRef, { attributeFilter: ['class'], attributeOldValue: true });
this.destroyKeyboardMO = () => {
mo === null || mo === void 0 ? void 0 : mo.disconnect();
};
/**
* We must use keydown not keyup as we want
* to prevent scrolling when using the arrow keys.
*/
calendarBodyRef.addEventListener('keydown', (ev) => {
const activeElement = root.activeElement;
if (!activeElement || !activeElement.classList.contains('calendar-day')) {
return;
}
const parts = getPartsFromCalendarDay(activeElement);
let partsToFocus;
switch (ev.key) {
case 'ArrowDown':
ev.preventDefault();
partsToFocus = getNextWeek(parts);
break;
case 'ArrowUp':
ev.preventDefault();
partsToFocus = getPreviousWeek(parts);
break;
case 'ArrowRight':
ev.preventDefault();
partsToFocus = getNextDay(parts);
break;
case 'ArrowLeft':
ev.preventDefault();
partsToFocus = getPreviousDay(parts);
break;
case 'Home':
ev.preventDefault();
partsToFocus = getStartOfWeek(parts);
break;
case 'End':
ev.preventDefault();
partsToFocus = getEndOfWeek(parts);
break;
case 'PageUp':
ev.preventDefault();
partsToFocus = ev.shiftKey ? getPreviousYear(parts) : getPreviousMonth(parts);
break;
case 'PageDown':
ev.preventDefault();
partsToFocus = ev.shiftKey ? getNextYear(parts) : getNextMonth(parts);
break;
/**
* Do not preventDefault here
* as we do not want to override other
* browser defaults such as pressing Enter/Space
* to select a day.
*/
default:
return;
}
/**
* If the day we want to move focus to is
* disabled, do not do anything.
*/
if (isDayDisabled(partsToFocus, this.minParts, this.maxParts)) {
return;
}
this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), partsToFocus));
/**
* Give view a chance to re-render
* then move focus to the new working day
*/
requestAnimationFrame(() => this.focusWorkingDay(currentMonth));
});
};
this.focusWorkingDay = (currentMonth) => {
/**
* Get the number of offset days so
* we know how much to offset our next selector by
* to grab the correct calendar-day element.
*/
const { day, month, year } = this.workingParts;
const firstOfMonth = new Date(`${month}/1/${year}`).getDay();
const offset = firstOfMonth >= this.firstDayOfWeek
? firstOfMonth - this.firstDayOfWeek
: 7 - (this.firstDayOfWeek - firstOfMonth);
if (day === null) {
return;
}
/**
* Get the calendar day element
* and focus it.
*/
const dayEl = currentMonth.querySelector(`.calendar-day-wrapper:nth-of-type(${offset + day}) .calendar-day`);
if (dayEl) {
dayEl.focus();
}
};
this.processMinParts = () => {
const { min, defaultParts } = this;
if (min === undefined) {
this.minParts = undefined;
return;
}
this.minParts = parseMinParts(min, defaultParts);
};
this.processMaxParts = () => {
const { max, defaultParts } = this;
if (max === undefined) {
this.maxParts = undefined;
return;
}
this.maxParts = parseMaxParts(max, defaultParts);
};
this.initializeCalendarListener = () => {
const calendarBodyRef = this.calendarBodyRef;
if (!calendarBodyRef) {
return;
}
/**
* For performance reasons, we only render 3
* months at a time: The current month, the previous
* month, and the next month. We have a scroll listener
* on the calendar body to append/prepend new months.
*
* We can do this because Stencil is smart enough to not
* re-create the .calendar-month containers, but rather
* update the content within those containers.
*
* As an added bonus, WebKit has some troubles with
* scroll-snap-stop: always, so not rendering all of
* the months in a row allows us to mostly sidestep
* that issue.
*/
const months = calendarBodyRef.querySelectorAll('.calendar-month');
const startMonth = months[0];
const workingMonth = months[1];
const endMonth = months[2];
const mode = getIonMode$1(this);
const needsiOSRubberBandFix = mode === 'ios' && typeof navigator !== 'undefined' && navigator.maxTouchPoints > 1;
/**
* Before setting up the scroll listener,
* scroll the middle month into view.
* scrollIntoView() will scroll entire page
* if element is not in viewport. Use scrollLeft instead.
*/
writeTask(() => {
calendarBodyRef.scrollLeft = startMonth.clientWidth * (isRTL$1(this.el) ? -1 : 1);
const getChangedMonth = (parts) => {
const box = calendarBodyRef.getBoundingClientRect();
/**
* If the current scroll position is all the way to the left
* then we have scrolled to the previous month.
* Otherwise, assume that we have scrolled to the next
* month. We have a tolerance of 2px to account for
* sub pixel rendering.
*
* Check below the next line ensures that we did not
* swipe and abort (i.e. we swiped but we are still on the current month).
*/
const condition = isRTL$1(this.el) ? calendarBodyRef.scrollLeft >= -2 : calendarBodyRef.scrollLeft <= 2;
const month = condition ? startMonth : endMonth;
/**
* The edge of the month must be lined up with
* the edge of the calendar body in order for
* the component to update. Otherwise, it
* may be the case that the user has paused their
* swipe or the browser has not finished snapping yet.
* Rather than check if the x values are equal,
* we give it a tolerance of 2px to account for
* sub pixel rendering.
*/
const monthBox = month.getBoundingClientRect();
if (Math.abs(monthBox.x - box.x) > 2)
return;
/**
* If we're force-rendering a month, assume we've
* scrolled to that and return it.
*
* If forceRenderDate is ever used in a context where the
* forced month is not immediately auto-scrolled to, this
* should be updated to also check whether `month` has the
* same month and year as the forced date.
*/
const { forceRenderDate } = this;
if (forceRenderDate !== undefined) {
return { month: forceRenderDate.month, year: forceRenderDate.year, day: forceRenderDate.day };
}
/**
* From here, we can determine if the start
* month or the end month was scrolled into view.
* If no month was changed, then we can return from
* the scroll callback early.
*/
if (month === startMonth) {
return getPreviousMonth(parts);
}
else if (month === endMonth) {
return getNextMonth(parts);
}
else {
return;
}
};
const updateActiveMonth = () => {
if (needsiOSRubberBandFix) {
calendarBodyRef.style.removeProperty('pointer-events');
appliediOSRubberBandFix = false;
}
/**
* If the month did not change
* then we can return early.
*/
const newDate = getChangedMonth(this.workingParts);
if (!newDate)
return;
const { month, day, year } = newDate;
if (isMonthDisabled({ month, year, day: null }, {
minParts: Object.assign(Object.assign({}, this.minParts), { day: null }),
maxParts: Object.assign(Object.assign({}, this.maxParts), { day: null }),
})) {
return;
}
/**
* Prevent scrolling for other browsers
* to give the DOM time to update and the container
* time to properly snap.
*/
calendarBodyRef.style.setProperty('overflow', 'hidden');
/**
* Use a writeTask here to ensure
* that the state is updated and the
* correct month is scrolled into view
* in the same frame. This is not
* typically a problem on newer devices
* but older/slower device may have a flicker
* if we did not do this.
*/
writeTask(() => {
this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), { month, day: day, year }));
calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL$1(this.el) ? -1 : 1);
calendarBodyRef.style.removeProperty('overflow');
if (this.resolveForceDateScrolling) {
this.resolveForceDateScrolling();
}
});
};
/**
* When the container finishes scrolling we
* need to update the DOM with the selected month.
*/
let scrollTimeout;
/**
* We do not want to attempt to set pointer-events
* multiple times within a single swipe gesture as
* that adds unnecessary work to the main thread.
*/
let appliediOSRubberBandFix = false;
const scrollCallback = () => {
if (scrollTimeout) {
clearTimeout(scrollTimeout);
}
/**
* On iOS it is possible to quickly rubber band
* the scroll area before the scroll timeout has fired.
* This results in users reaching the end of the scrollable
* container before the DOM has updated.
* By setting `pointer-events: none` we can ensure that
* subsequent swipes do not happen while the container
* is snapping.
*/
if (!appliediOSRubberBandFix && needsiOSRubberBandFix) {
calendarBodyRef.style.setProperty('pointer-events', 'none');
appliediOSRubberBandFix = true;
}
// Wait ~3 frames
scrollTimeout = setTimeout(updateActiveMonth, 50);
};
calendarBodyRef.addEventListener('scroll', scrollCallback);
this.destroyCalendarListener = () => {
calendarBodyRef.removeEventListener('scroll', scrollCallback);
};
});
};
/**
* Clean up all listeners except for the overlay
* listener. This is so that we can re-create the listeners
* if the datetime has been hidden/presented by a modal or popover.
*/
this.destroyInteractionListeners = () => {
const { destroyCalendarListener, destroyKeyboardMO } = this;
if (destroyCalendarListener !== undefined) {
destroyCalendarListener();
}
if (destroyKeyboardMO !== undefined) {
destroyKeyboardMO();
}
};
this.processValue = (value) => {
const hasValue = value !== null && value !== undefined && value !== '' && (!Array.isArray(value) || value.length > 0);
const valueToProcess = hasValue ? parseDate(value) : this.defaultParts;
const { minParts, maxParts, workingParts, el } = this;
this.warnIfIncorrectValueUsage();
/**
* Return early if the value wasn't parsed correctly, such as
* if an improperly formatted date string was provided.
*/
if (!valueToProcess) {
return;
}
/**
* Datetime should only warn of out of bounds values
* if set by the user. If the `value` is undefined,
* we will default to today's date which may be out
* of bounds. In this case, the warning makes it look
* like the developer did something wrong which is
* not true.
*/
if (hasValue) {
warnIfValueOutOfBounds(valueToProcess, minParts, maxParts);
}
/**
* If there are multiple values, clamp to the last one.
* This is because the last value is the one that the user
* has most recently interacted with.
*/
const singleValue = Array.isArray(valueToProcess) ? valueToProcess[valueToProcess.length - 1] : valueToProcess;
const targetValue = clampDate(singleValue, minParts, maxParts);
const { month, day, year, hour, minute } = targetValue;
const ampm = parseAmPm(hour);
/**
* Since `activeParts` indicates a value that been explicitly selected
* either by the user or the app, only update `activeParts` if the
* `value` property is set.
*/
if (hasValue) {
if (Array.isArray(valueToProcess)) {
this.activeParts = [...valueToProcess];
}
else {
this.activeParts = {
month,
day,
year,
hour,
minute,
ampm,
};
}
}
else {
/**
* Reset the active parts if the value is not set.
* This will clear the selected calendar day when
* performing a clear action or using the reset() method.
*/
this.activeParts = [];
}
const didChangeMonth = (month !== undefined && month !== workingParts.month) || (year !== undefined && year !== workingParts.year);
const bodyIsVisible = el.classList.contains('datetime-ready');
const { isGridStyle, showMonthAndYear } = this;
if (isGridStyle && didChangeMonth && bodyIsVisible && !showMonthAndYear) {
/**
* Only animate if:
* 1. We're using grid style (wheel style pickers should just jump to new value)
* 2. The month and/or year actually changed, and both are defined (otherwise there's nothing to animate to)
* 3. The calendar body is visible (prevents animation when in collapsed datetime-button, for example)
* 4. The month/year picker is not open (since you wouldn't see the animation anyway)
*/
this.animateToDate(targetValue);
}
else {
this.setWorkingParts({
month,
day,
year,
hour,
minute,
ampm,
});
}
};
this.animateToDate = async (targetValue) => {
const { workingParts } = this;
/**
* Tell other render functions that we need to force the
* target month to appear in place of the actual next/prev month.
* Because this is a State variable, a rerender will be triggered
* automatically, updating the rendered months.
*/
this.forceRenderDate = targetValue;
/**
* Flag that we've started scrolling to the forced date.
* The resolve function will be called by the datetime's
* scroll listener when it's done updating everything.
* This is a replacement for making prev/nextMonth async,
* since the logic we're waiting on is in a listener.
*/
const forceDateScrollingPromise = new Promise((resolve) => {
this.resolveForceDateScrolling = resolve;
});
/**
* Animate smoothly to the forced month. This will also update
* workingParts and correct the surrounding months for us.
*/
const targetMonthIsBefore = isBefore(targetValue, workingParts);
targetMonthIsBefore ? this.prevMonth() : this.nextMonth();
await forceDateScrollingPromise;
this.resolveForceDateScrolling = undefined;
this.forceRenderDate = undefined;
};
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
this.hasValue = () => {
return this.value != null;
};
this.nextMonth = () => {
const calendarBodyRef = this.calendarBodyRef;
if (!calendarBodyRef) {
return;
}
const nextMonth = calendarBodyRef.querySelector('.calendar-month:last-of-type');
if (!nextMonth) {
return;
}
const left = nextMonth.offsetWidth * 2;
calendarBodyRef.scrollTo({
top: 0,
left: left * (isRTL$1(this.el) ? -1 : 1),
behavior: 'smooth',
});
};
this.prevMonth = () => {
const calendarBodyRef = this.calendarBodyRef;
if (!calendarBodyRef) {
return;
}
const prevMonth = calendarBodyRef.querySelector('.calendar-month:first-of-type');
if (!prevMonth) {
return;
}
calendarBodyRef.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
};
this.toggleMonthAndYearView = () => {
this.showMonthAndYear = !this.showMonthAndYear;
};
}
formatOptionsChanged() {
const { el, formatOptions, presentation } = this;
checkForPresentationFormatMismatch(el, presentation, formatOptions);
warnIfTimeZoneProvided(el, formatOptions);
}
disabledChanged() {
this.emitStyle();
}
minChanged() {
this.processMinParts();
}
maxChanged() {
this.processMaxParts();
}
presentationChanged() {
const { el, formatOptions, presentation } = this;
checkForPresentationFormatMismatch(el, presentation, formatOptions);
}
get isGridStyle() {
const { presentation, preferWheel } = this;
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
return hasDatePresentation && !preferWheel;
}
yearValuesChanged() {
this.parsedYearValues = convertToArrayOfNumbers(this.yearValues);
}
monthValuesChanged() {
this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues);
}
dayValuesChanged() {
this.parsedDayValues = convertToArrayOfNumbers(this.dayValues);
}
hourValuesChanged() {
this.parsedHourValues = convertToArrayOfNumbers(this.hourValues);
}
minuteValuesChanged() {
this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues);
}
/**
* Update the datetime value when the value changes
*/
async valueChanged() {
const { value } = this;
if (this.hasValue()) {
this.processValue(value);
}
this.emitStyle();
this.ionValueChange.emit({ value });
}
/**
* Confirms the selected datetime value, updates the
* `value` property, and optionally closes the popover
* or modal that the datetime was presented in.
*
* @param closeOverlay If `true`, closes the parent overlay. Defaults to `false`.
*/
async confirm(closeOverlay = false) {
const { isCalendarPicker, activeParts, preferWheel, workingParts } = this;
/**
* We only update the value if the presentation is not a calendar picker.
*/
if (activeParts !== undefined || !isCalendarPicker) {
const activePartsIsArray = Array.isArray(activeParts);
if (activePartsIsArray && activeParts.length === 0) {
if (preferWheel) {
/**
* If the datetime is using a wheel picker, but the
* active parts are empty, then the user has confirmed the
* initial value (working parts) presented to them.
*/
this.setValue(convertDataToISO(workingParts));
}
else {
this.setValue(undefined);
}
}
else {
this.setValue(convertDataToISO(activeParts));
}
}
if (closeOverlay) {
this.closeParentOverlay(CONFIRM_ROLE);
}
}
/**
* Resets the internal state of the datetime but does not update the value.
* Passing a valid ISO-8601 string will reset the state of the component to the provided date.
* If no value is provided, the internal state will be reset to the clamped value of the min, max and today.
*
* @param startDate A valid [ISO-8601 string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format) to reset the datetime state to.
*/
async reset(startDate) {
this.processValue(startDate);
}
/**
* Emits the ionCancel event and
* optionally closes the popover
* or modal that the datetime was
* presented in.
*
* @param closeOverlay If `true`, closes the parent overlay. Defaults to `false`.
*/
async cancel(closeOverlay = false) {
this.ionCancel.emit();
if (closeOverlay) {
this.closeParentOverlay(CANCEL_ROLE);
}
}
get isCalendarPicker() {
const { presentation } = this;
return presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
}
connectedCallback() {
this.clearFocusVisible = startFocusVisible(this.el).destroy;
}
disconnectedCallback() {
if (this.clearFocusVisible) {
this.clearFocusVisible();
this.clearFocusVisible = undefined;
}
}
initializeListeners() {
this.initializeCalendarListener();
this.initializeKeyboardListeners();
}
componentDidLoad() {
const { el, intersectionTrackerRef } = this;
/**
* If a scrollable element is hidden using `display: none`,
* it will not have a scroll height meaning we cannot scroll elements
* into view. As a result, we will need to wait for the datetime to become
* visible if used inside of a modal or a popover otherwise the scrollable
* areas will not have the correct values snapped into place.
*/
const visibleCallback = (entries) => {
const ev = entries[0];
if (!ev.isIntersecting) {
return;
}
this.initializeListeners();
/**
* TODO FW-2793: Datetime needs a frame to ensure that it
* can properly scroll contents into view. As a result
* we hide the scrollable content until after that frame
* so users do not see the content quickly shifting. The downside
* is that the content will pop into view a frame after. Maybe there
* is a better way to handle this?
*/
writeTask(() => {
this.el.classList.add('datetime-ready');
});
};
const visibleIO = new IntersectionObserver(visibleCallback, { threshold: 0.01, root: el });
/**
* Use raf to avoid a race condition between the component loading and
* its display animation starting (such as when shown in a modal). This
* could cause the datetime to start at a visibility of 0, erroneously
* triggering the `hiddenIO` observer below.
*/
raf(() => visibleIO === null || visibleIO === void 0 ? void 0 : visibleIO.observe(intersectionTrackerRef));
/**
* We need to clean up listeners when the datetime is hidden
* in a popover/modal so that we can properly scroll containers
* back into view if they are re-presented. When the datetime is hidden
* the scroll areas have scroll widths/heights of 0px, so any snapping
* we did originally has been lost.
*/
const hiddenCallback = (entries) => {
const ev = entries[0];
if (ev.isIntersecting) {
return;
}
this.destroyInteractionListeners();
/**
* When datetime is hidden, we need to make sure that
* the month/year picker is closed. Otherwise,
* it will be open when the datetime re-appears
* and the scroll area of the calendar grid will be 0.
* As a result, the wrong month will be shown.
*/
this.showMonthAndYear = false;
writeTask(() => {
this.el.classList.remove('datetime-ready');
});
};
const hiddenIO = new IntersectionObserver(hiddenCallback, { threshold: 0, root: el });
raf(() => hiddenIO === null || hiddenIO === void 0 ? void 0 : hiddenIO.observe(intersectionTrackerRef));
/**
* Datetime uses Ionic components that emit
* ionFocus and ionBlur. These events are
* composed meaning they will cross
* the shadow dom boundary. We need to
* stop propagation on these events otherwise
* developers will see 2 ionFocus or 2 ionBlur
* events at a time.
*/
const root = getElementRoot(this.el);
root.addEventListener('ionFocus', (ev) => ev.stopPropagation());
root.addEventListener('ionBlur', (ev) => ev.stopPropagation());
}
/**
* When the presentation is changed, all calendar content is recreated,
* so we need to re-init behavior with the new elements.
*/
componentDidRender() {
const { presentation, prevPresentation, calendarBodyRef, minParts, preferWheel, forceRenderDate } = this;
/**
* TODO(FW-2165)
* Remove this when https://bugs.webkit.org/show_bug.cgi?id=235960 is fixed.
* When using `min`, we add `scroll-snap-align: none`
* to the disabled month so that users cannot scroll to it.
* This triggers a bug in WebKit where the scroll position is reset.
* Since the month change logic is handled by a scroll listener,
* this causes the month to change leading to `scroll-snap-align`
* changing again, thus changing the scroll position again and causing
* an infinite loop.
* This issue only applies to the calendar grid, so we can disable
* it if the calendar grid is not being used.
*/
const hasCalendarGrid = !preferWheel && ['date-time', 'time-date', 'date'].includes(presentation);
if (minParts !== undefined && hasCalendarGrid && calendarBodyRef) {
const workingMonth = calendarBodyRef.querySelector('.calendar-month:nth-of-type(1)');
/**
* We need to make sure the datetime is not in the process
* of scrolling to a new datetime value if the value
* is updated programmatically.
* Otherwise, the datetime will appear to not scroll at all because
* we are resetting the scroll position to the center of the view.
* Prior to the datetime's value being updated programmatically,
* the calendarBodyRef is scrolled such that the middle month is centered
* in the view. The below code updates the scroll position so the middle
* month is also centered in the view. Since the scroll position did not change,
* the scroll callback in this file does not fire,
* and the resolveForceDateScrolling promise never resolves.
*/
if (workingMonth && forceRenderDate === undefined) {
calendarBodyRef.scrollLeft = workingMonth.clientWidth * (isRTL$1(this.el) ? -1 : 1);
}
}
if (prevPresentation === null) {
this.prevPresentation = presentation;
return;
}
if (presentation === prevPresentation) {
return;
}
this.prevPresentation = presentation;
this.destroyInteractionListeners();
this.initializeListeners();
/**
* The month/year picker from the date interface
* should be closed as it is not available in non-date
* interfaces.
*/
this.showMonthAndYear = false;
raf(() => {
this.ionRender.emit();
});
}
componentWillLoad() {
const { el, formatOptions, highlightedDates, multiple, presentation, preferWheel } = this;
if (multiple) {
if (presentation !== 'date') {
printIonWarning('[ion-datetime] - Multiple date selection is only supported for presentation="date".', el);
}
if (preferWheel) {
printIonWarning('[ion-datetime] - Multiple date selection is not supported with preferWheel="true".', el);
}
}
if (highlightedDates !== undefined) {
if (presentation !== 'date' && presentation !== 'date-time' && presentation !== 'time-date') {
printIonWarning('[ion-datetime] - The highlightedDates property is only supported with the date, date-time, and time-date presentations.', el);
}
if (preferWheel) {
printIonWarning('[ion-datetime] - The highlightedDates property is not supported with preferWheel="true".', el);
}
}
if (formatOptions) {
checkForPresentationFormatMismatch(el, presentation, formatOptions);
warnIfTimeZoneProvided(el, formatOptions);
}
const hourValues = (this.parsedHourValues = convertToArrayOfNumbers(this.hourValues));
const minuteValues = (this.parsedMinuteValues = convertToArrayOfNumbers(this.minuteValues));
const monthValues = (this.parsedMonthValues = convertToArrayOfNumbers(this.monthValues));
const yearValues = (this.parsedYearValues = convertToArrayOfNumbers(this.yearValues));
const dayValues = (this.parsedDayValues = convertToArrayOfNumbers(this.dayValues));
const todayParts = (this.todayParts = parseDate(getToday()));
this.processMinParts();
this.processMaxParts();
this.defaultParts = getClosestValidDate({
refParts: todayParts,
monthValues,
dayValues,
yearValues,
hourValues,
minuteValues,
minParts: this.minParts,
maxParts: this.maxParts,
});
this.processValue(this.value);
this.emitStyle();
}
emitStyle() {
this.ionStyle.emit({
interactive: true,
datetime: true,
'interactive-disabled': this.disabled,
});
}
/**
* Universal render methods
* These are pieces of datetime that
* are rendered independently of presentation.
*/
renderFooter() {
const { disabled, readonly, showDefaultButtons, showClearButton } = this;
/**
* The cancel, clear, and confirm buttons
* should not be interactive if the datetime
* is disabled or readonly.
*/
const isButtonDisabled = disabled || readonly;
const hasSlottedButtons = this.el.querySelector('[slot="buttons"]') !== null;
if (!hasSlottedButtons && !showDefaultButtons && !showClearButton) {
return;
}
const clearButtonClick = () => {
this.reset();
this.setValue(undefined);
};
/**
* By default we render two buttons:
* Cancel - Dismisses the datetime and
* does not update the `value` prop.
* OK - Dismisses the datetime and
* updates the `value` prop.
*/
return (hAsync("div", { class: "datetime-footer" }, hAsync("div", { class: "datetime-buttons" }, hAsync("div", { class: {
['datetime-action-buttons']: true,
['has-clear-button']: this.showClearButton,
} }, hAsync("slot", { name: "buttons" }, hAsync("ion-buttons", null, showDefaultButtons && (hAsync("ion-button", { id: "cancel-button", color: this.color, onClick: () => this.cancel(true), disabled: isButtonDisabled }, this.cancelText)), hAsync("div", { class: "datetime-action-buttons-container" }, showClearButton && (hAsync("ion-button", { id: "clear-button", color: this.color, onClick: () => clearButtonClick(), disabled: isButtonDisabled }, this.clearText)), showDefaultButtons && (hAsync("ion-button", { id: "confirm-button", color: this.color, onClick: () => this.confirm(true), disabled: isButtonDisabled }, this.doneText)))))))));
}
/**
* Wheel picker render methods
*/
renderWheelPicker(forcePresentation = this.presentation) {
/**
* If presentation="time-date" we switch the
* order of the render array here instead of
* manually reordering each date/time picker
* column with CSS. This allows for additional
* flexibility if we need to render subsets
* of the date/time data or do additional ordering
* within the child render functions.
*/
const renderArray = forcePresentation === 'time-date'
? [this.renderTimePickerColumns(forcePresentation), this.renderDatePickerColumns(forcePresentation)]
: [this.renderDatePickerColumns(forcePresentation), this.renderTimePickerColumns(forcePresentation)];
return hAsync("ion-picker", { class: FOCUS_TRAP_DISABLE_CLASS }, renderArray);
}
renderDatePickerColumns(forcePresentation) {
return forcePresentation === 'date-time' || forcePresentation === 'time-date'
? this.renderCombinedDatePickerColumn()
: this.renderIndividualDatePickerColumns(forcePresentation);
}
renderCombinedDatePickerColumn() {
const { defaultParts, disabled, workingParts, locale, minParts, maxParts, todayParts, isDateEnabled } = this;
const activePart = this.getActivePartsWithFallback();
/**
* By default, generate a range of 3 months:
* Previous month, current month, and next month
*/
const monthsToRender = generateMonths(workingParts);
const lastMonth = monthsToRender[monthsToRender.length - 1];
/**
* Ensure that users can select the entire window of dates.
*/
monthsToRender[0].day = 1;
lastMonth.day = getNumDaysInMonth(lastMonth.month, lastMonth.year);
/**
* Narrow the dates rendered based on min/max dates (if any).
* The `min` date is used if the min is after the generated min month.
* The `max` date is used if the max is before the generated max month.
* This ensures that the sliding window always stays at 3 months
* but still allows future dates to be lazily rendered based on any min/max
* constraints.
*/
const min = minParts !== undefined && isAfter(minParts, monthsToRender[0]) ? minParts : monthsToRender[0];
const max = maxParts !== undefined && isBefore(maxParts, lastMonth) ? maxParts : lastMonth;
const result = getCombinedDateColumnData(locale, todayParts, min, max, this.parsedDayValues, this.parsedMonthValues);
let items = result.items;
const parts = result.parts;
if (isDateEnabled) {
items = items.map((itemObject, index) => {
const referenceParts = parts[index];
let disabled;
try {
/**
* The `isDateEnabled` implementation is try-catch wrapped
* to prevent exceptions in the user's function from
* interrupting the calendar rendering.
*/
disabled = !isDateEnabled(convertDataToISO(referenceParts));
}
catch (e) {
printIonError('[ion-datetime] - Exception thrown from provided `isDateEnabled` function. Please check your function and try again.', e);
}
return Object.assign(Object.assign({}, itemObject), { disabled });
});
}
/**
* If we have selected a day already, then default the column
* to that value. Otherwise, set it to the default date.
*/
const todayString = workingParts.day !== null
? `${workingParts.year}-${workingParts.month}-${workingParts.day}`
: `${defaultParts.year}-${defaultParts.month}-${defaultParts.day}`;
return (hAsync("ion-picker-column", { "aria-label": "Select a date", class: "date-column", color: this.color, disabled: disabled, value: todayString, onIonChange: (ev) => {
const { value } = ev.detail;
const findPart = parts.find(({ month, day, year }) => value === `${year}-${month}-${day}`);
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), findPart));
this.setActiveParts(Object.assign(Object.assign({}, activePart), findPart));
ev.stopPropagation();
} }, items.map((item) => (hAsync("ion-picker-column-option", { part: item.value === todayString ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: item.value, disabled: item.disabled, value: item.value }, item.text)))));
}
renderIndividualDatePickerColumns(forcePresentation) {
const { workingParts, isDateEnabled } = this;
const shouldRenderMonths = forcePresentation !== 'year' && forcePresentation !== 'time';
const months = shouldRenderMonths
? getMonthColumnData(this.locale, workingParts, this.minParts, this.maxParts, this.parsedMonthValues)
: [];
const shouldRenderDays = forcePresentation === 'date';
let days = shouldRenderDays
? getDayColumnData(this.locale, workingParts, this.minParts, this.maxParts, this.parsedDayValues)
: [];
if (isDateEnabled) {
days = days.map((dayObject) => {
const { value } = dayObject;
const valueNum = typeof value === 'string' ? parseInt(value) : value;
const referenceParts = {
month: workingParts.month,
day: valueNum,
year: workingParts.year,
};
let disabled;
try {
/**
* The `isDateEnabled` implementation is try-catch wrapped
* to prevent exceptions in the user's function from
* interrupting the calendar rendering.
*/
disabled = !isDateEnabled(convertDataToISO(referenceParts));
}
catch (e) {
printIonError('[ion-datetime] - Exception thrown from provided `isDateEnabled` function. Please check your function and try again.', e);
}
return Object.assign(Object.assign({}, dayObject), { disabled });
});
}
const shouldRenderYears = forcePresentation !== 'month' && forcePresentation !== 'time';
const years = shouldRenderYears
? getYearColumnData(this.locale, this.defaultParts, this.minParts, this.maxParts, this.parsedYearValues)
: [];
/**
* Certain locales show the day before the month.
*/
const showMonthFirst = isMonthFirstLocale(this.locale, { month: 'numeric', day: 'numeric' });
let renderArray = [];
if (showMonthFirst) {
renderArray = [
this.renderMonthPickerColumn(months),
this.renderDayPickerColumn(days),
this.renderYearPickerColumn(years),
];
}
else {
renderArray = [
this.renderDayPickerColumn(days),
this.renderMonthPickerColumn(months),
this.renderYearPickerColumn(years),
];
}
return renderArray;
}
renderDayPickerColumn(days) {
var _a;
if (days.length === 0) {
return [];
}
const { disabled, workingParts } = this;
const activePart = this.getActivePartsWithFallback();
const pickerColumnValue = (_a = (workingParts.day !== null ? workingParts.day : this.defaultParts.day)) !== null && _a !== void 0 ? _a : undefined;
return (hAsync("ion-picker-column", { "aria-label": "Select a day", class: "day-column", color: this.color, disabled: disabled, value: pickerColumnValue, onIonChange: (ev) => {
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { day: ev.detail.value }));
this.setActiveParts(Object.assign(Object.assign({}, activePart), { day: ev.detail.value }));
ev.stopPropagation();
} }, days.map((day) => (hAsync("ion-picker-column-option", { part: day.value === pickerColumnValue ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: day.value, disabled: day.disabled, value: day.value }, day.text)))));
}
renderMonthPickerColumn(months) {
if (months.length === 0) {
return [];
}
const { disabled, workingParts } = this;
const activePart = this.getActivePartsWithFallback();
return (hAsync("ion-picker-column", { "aria-label": "Select a month", class: "month-column", color: this.color, disabled: disabled, value: workingParts.month, onIonChange: (ev) => {
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { month: ev.detail.value }));
this.setActiveParts(Object.assign(Object.assign({}, activePart), { month: ev.detail.value }));
ev.stopPropagation();
} }, months.map((month) => (hAsync("ion-picker-column-option", { part: month.value === workingParts.month ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: month.value, disabled: month.disabled, value: month.value }, month.text)))));
}
renderYearPickerColumn(years) {
if (years.length === 0) {
return [];
}
const { disabled, workingParts } = this;
const activePart = this.getActivePartsWithFallback();
return (hAsync("ion-picker-column", { "aria-label": "Select a year", class: "year-column", color: this.color, disabled: disabled, value: workingParts.year, onIonChange: (ev) => {
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { year: ev.detail.value }));
this.setActiveParts(Object.assign(Object.assign({}, activePart), { year: ev.detail.value }));
ev.stopPropagation();
} }, years.map((year) => (hAsync("ion-picker-column-option", { part: year.value === workingParts.year ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: year.value, disabled: year.disabled, value: year.value }, year.text)))));
}
renderTimePickerColumns(forcePresentation) {
if (['date', 'month', 'month-year', 'year'].includes(forcePresentation)) {
return [];
}
/**
* If a user has not selected a date,
* then we should show all times. If the
* user has selected a date (even if it has
* not been confirmed yet), we should apply
* the max and min restrictions so that the
* time picker shows values that are
* appropriate for the selected date.
*/
const activePart = this.getActivePart();
const userHasSelectedDate = activePart !== undefined;
const { hoursData, minutesData, dayPeriodData } = getTimeColumnsData(this.locale, this.workingParts, this.hourCycle, userHasSelectedDate ? this.minParts : undefined, userHasSelectedDate ? this.maxParts : undefined, this.parsedHourValues, this.parsedMinuteValues);
return [
this.renderHourPickerColumn(hoursData),
this.renderMinutePickerColumn(minutesData),
this.renderDayPeriodPickerColumn(dayPeriodData),
];
}
renderHourPickerColumn(hoursData) {
const { disabled, workingParts } = this;
if (hoursData.length === 0)
return [];
const activePart = this.getActivePartsWithFallback();
return (hAsync("ion-picker-column", { "aria-label": "Select an hour", color: this.color, disabled: disabled, value: activePart.hour, numericInput: true, onIonChange: (ev) => {
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { hour: ev.detail.value }));
this.setActiveParts(Object.assign(Object.assign({}, this.getActivePartsWithFallback()), { hour: ev.detail.value }));
ev.stopPropagation();
} }, hoursData.map((hour) => (hAsync("ion-picker-column-option", { part: hour.value === activePart.hour ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: hour.value, disabled: hour.disabled, value: hour.value }, hour.text)))));
}
renderMinutePickerColumn(minutesData) {
const { disabled, workingParts } = this;
if (minutesData.length === 0)
return [];
const activePart = this.getActivePartsWithFallback();
return (hAsync("ion-picker-column", { "aria-label": "Select a minute", color: this.color, disabled: disabled, value: activePart.minute, numericInput: true, onIonChange: (ev) => {
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { minute: ev.detail.value }));
this.setActiveParts(Object.assign(Object.assign({}, this.getActivePartsWithFallback()), { minute: ev.detail.value }));
ev.stopPropagation();
} }, minutesData.map((minute) => (hAsync("ion-picker-column-option", { part: minute.value === activePart.minute ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: minute.value, disabled: minute.disabled, value: minute.value }, minute.text)))));
}
renderDayPeriodPickerColumn(dayPeriodData) {
const { disabled, workingParts } = this;
if (dayPeriodData.length === 0) {
return [];
}
const activePart = this.getActivePartsWithFallback();
const isDayPeriodRTL = isLocaleDayPeriodRTL(this.locale);
return (hAsync("ion-picker-column", { "aria-label": "Select a day period", style: isDayPeriodRTL ? { order: '-1' } : {}, color: this.color, disabled: disabled, value: activePart.ampm, onIonChange: (ev) => {
const hour = calculateHourFromAMPM(workingParts, ev.detail.value);
this.setWorkingParts(Object.assign(Object.assign({}, workingParts), { ampm: ev.detail.value, hour }));
this.setActiveParts(Object.assign(Object.assign({}, this.getActivePartsWithFallback()), { ampm: ev.detail.value, hour }));
ev.stopPropagation();
} }, dayPeriodData.map((dayPeriod) => (hAsync("ion-picker-column-option", { part: dayPeriod.value === activePart.ampm ? `${WHEEL_ITEM_PART} ${WHEEL_ITEM_ACTIVE_PART}` : WHEEL_ITEM_PART, key: dayPeriod.value, disabled: dayPeriod.disabled, value: dayPeriod.value }, dayPeriod.text)))));
}
renderWheelView(forcePresentation) {
const { locale } = this;
const showMonthFirst = isMonthFirstLocale(locale);
const columnOrder = showMonthFirst ? 'month-first' : 'year-first';
return (hAsync("div", { class: {
[`wheel-order-${columnOrder}`]: true,
} }, this.renderWheelPicker(forcePresentation)));
}
/**
* Grid Render Methods
*/
renderCalendarHeader(mode) {
const { disabled } = this;
const expandedIcon = mode === 'ios' ? chevronDown : caretUpSharp;
const collapsedIcon = mode === 'ios' ? chevronForward : caretDownSharp;
const prevMonthDisabled = disabled || isPrevMonthDisabled(this.workingParts, this.minParts, this.maxParts);
const nextMonthDisabled = disabled || isNextMonthDisabled(this.workingParts, this.maxParts);
// don't use the inheritAttributes util because it removes dir from the host, and we still need that
const hostDir = this.el.getAttribute('dir') || undefined;
return (hAsync("div", { class: "calendar-header" }, hAsync("div", { class: "calendar-action-buttons" }, hAsync("div", { class: "calendar-month-year" }, hAsync("button", { class: {
'calendar-month-year-toggle': true,
'ion-activatable': true,
'ion-focusable': true,
}, part: "month-year-button", disabled: disabled, "aria-label": this.showMonthAndYear ? 'Hide year picker' : 'Show year picker', onClick: () => this.toggleMonthAndYearView() }, hAsync("span", { id: "toggle-wrapper" }, getMonthAndYear(this.locale, this.workingParts), hAsync("ion-icon", { "aria-hidden": "true", icon: this.showMonthAndYear ? expandedIcon : collapsedIcon, lazy: false, flipRtl: true })), mode === 'md' && hAsync("ion-ripple-effect", null))), hAsync("div", { class: "calendar-next-prev" }, hAsync("ion-buttons", null, hAsync("ion-button", { "aria-label": "Previous month", disabled: prevMonthDisabled, onClick: () => this.prevMonth() }, hAsync("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: chevronBack, lazy: false, flipRtl: true })), hAsync("ion-button", { "aria-label": "Next month", disabled: nextMonthDisabled, onClick: () => this.nextMonth() }, hAsync("ion-icon", { dir: hostDir, "aria-hidden": "true", slot: "icon-only", icon: chevronForward, lazy: false, flipRtl: true }))))), hAsync("div", { class: "calendar-days-of-week", "aria-hidden": "true" }, getDaysOfWeek(this.locale, mode, this.firstDayOfWeek % 7).map((d) => {
return hAsync("div", { class: "day-of-week" }, d);
}))));
}
renderMonth(month, year) {
const { disabled, readonly } = this;
const yearAllowed = this.parsedYearValues === undefined || this.parsedYearValues.includes(year);
const monthAllowed = this.parsedMonthValues === undefined || this.parsedMonthValues.includes(month);
const isCalMonthDisabled = !yearAllowed || !monthAllowed;
const isDatetimeDisabled = disabled || readonly;
const swipeDisabled = disabled ||
isMonthDisabled({
month,
year,
day: null,
}, {
// The day is not used when checking if a month is disabled.
// Users should be able to access the min or max month, even if the
// min/max date is out of bounds (e.g. min is set to Feb 15, Feb should not be disabled).
minParts: Object.assign(Object.assign({}, this.minParts), { day: null }),
maxParts: Object.assign(Object.assign({}, this.maxParts), { day: null }),
});
// The working month should never have swipe disabled.
// Otherwise the CSS scroll snap will not work and the user
// can free-scroll the calendar.
const isWorkingMonth = this.workingParts.month === month && this.workingParts.year === year;
const activePart = this.getActivePartsWithFallback();
return (hAsync("div", { "aria-hidden": !isWorkingMonth ? 'true' : null, class: {
'calendar-month': true,
// Prevents scroll snap swipe gestures for months outside of the min/max bounds
'calendar-month-disabled': !isWorkingMonth && swipeDisabled,
} }, hAsync("div", { class: "calendar-month-grid" }, getDaysOfMonth(month, year, this.firstDayOfWeek % 7, this.showAdjacentDays).map((dateObject, index) => {
const { day, dayOfWeek, isAdjacentDay } = dateObject;
const { el, highlightedDates, isDateEnabled, multiple, showAdjacentDays } = this;
let _month = month;
let _year = year;
if (showAdjacentDays && isAdjacentDay && day !== null) {
if (day > 20) {
// Leading with the adjacent day from the previous month
// if its a adjacent day and is higher than '20' (last week even in feb)
if (month === 1) {
_year = year - 1;
_month = 12;
}
else {
_month = month - 1;
}
}
else if (day < 15) {
// Leading with the adjacent day from the next month
// if its a adjacent day and is lower than '15' (first two weeks)
if (month === 12) {
_year = year + 1;
_month = 1;
}
else {
_month = month + 1;
}
}
}
const referenceParts = { month: _month, day, year: _year, isAdjacentDay };
const isCalendarPadding = day === null;
const { isActive, isToday, ariaLabel, ariaSelected, disabled: isDayDisabled, text, } = getCalendarDayState(this.locale, referenceParts, this.activeParts, this.todayParts, this.minParts, this.maxParts, this.parsedDayValues);
const dateIsoString = convertDataToISO(referenceParts);
let isCalDayDisabled = isCalMonthDisabled || isDayDisabled;
if (!isCalDayDisabled && isDateEnabled !== undefined) {
try {
/**
* The `isDateEnabled` implementation is try-catch wrapped
* to prevent exceptions in the user's function from
* interrupting the calendar rendering.
*/
isCalDayDisabled = !isDateEnabled(dateIsoString);
}
catch (e) {
printIonError('[ion-datetime] - Exception thrown from provided `isDateEnabled` function. Please check your function and try again.', el, e);
}
}
/**
* Some days are constrained through max & min or allowed dates
* and also disabled because the component is readonly or disabled.
* These need to be displayed differently.
*/
const isCalDayConstrained = isCalDayDisabled && isDatetimeDisabled;
const isButtonDisabled = isCalDayDisabled || isDatetimeDisabled;
let dateStyle = undefined;
/**
* Custom highlight styles should not override the style for selected dates,
* nor apply to "filler days" at the start of the grid.
*/
if (highlightedDates !== undefined && !isActive && day !== null && !isAdjacentDay) {
dateStyle = getHighlightStyles(highlightedDates, dateIsoString, el);
}
let dateParts = undefined;
// "Filler days" at the beginning of the grid should not get the calendar day
// CSS parts added to them
if (!isCalendarPadding && !isAdjacentDay) {
dateParts = `calendar-day${isActive ? ' active' : ''}${isToday ? ' today' : ''}${isCalDayDisabled ? ' disabled' : ''}`;
}
else if (isAdjacentDay) {
dateParts = `calendar-day${isCalDayDisabled ? ' disabled' : ''}`;
}
return (hAsync("div", { class: "calendar-day-wrapper" }, hAsync("button", {
// We need to use !important for the inline styles here because
// otherwise the CSS shadow parts will override these styles.
// See https://github.com/WICG/webcomponents/issues/847
// Both the CSS shadow parts and highlightedDates styles are
// provided by the developer, but highlightedDates styles should
// always take priority.
ref: (el) => {
if (el) {
el.style.setProperty('color', `${dateStyle ? dateStyle.textColor : ''}`, 'important');
el.style.setProperty('background-color', `${dateStyle ? dateStyle.backgroundColor : ''}`, 'important');
el.style.setProperty('border', `${dateStyle ? dateStyle.border : ''}`, 'important');
}
}, tabindex: "-1", "data-day": day, "data-month": _month, "data-year": _year, "data-index": index, "data-day-of-week": dayOfWeek, disabled: isButtonDisabled, class: {
'calendar-day-padding': isCalendarPadding,
'calendar-day': true,
'calendar-day-active': isActive,
'calendar-day-constrained': isCalDayConstrained,
'calendar-day-today': isToday,
'calendar-day-adjacent-day': isAdjacentDay,
}, part: dateParts, "aria-hidden": isCalendarPadding ? 'true' : null, "aria-selected": ariaSelected, "aria-label": ariaLabel, onClick: () => {
if (isCalendarPadding) {
return;
}
if (isAdjacentDay) {
// The user selected a day outside the current month. Ignore this button, as the month will be re-rendered.
this.el.blur();
this.activeParts = Object.assign(Object.assign({}, activePart), referenceParts);
this.animateToDate(referenceParts);
this.confirm();
}
else {
this.setWorkingParts(Object.assign(Object.assign({}, this.workingParts), referenceParts));
// Multiple only needs date info so we can wipe out other fields like time.
if (multiple) {
this.setActiveParts(referenceParts, isActive);
}
else {
this.setActiveParts(Object.assign(Object.assign({}, activePart), referenceParts));
}
}
}
}, text)));
}))));
}
renderCalendarBody() {
return (hAsync("div", { class: "calendar-body ion-focusable", ref: (el) => (this.calendarBodyRef = el), tabindex: "0" }, generateMonths(this.workingParts, this.forceRenderDate).map(({ month, year }) => {
return this.renderMonth(month, year);
})));
}
renderCalendar(mode) {
return (hAsync("div", { class: "datetime-calendar", key: "datetime-calendar" }, this.renderCalendarHeader(mode), this.renderCalendarBody()));
}
renderTimeLabel() {
const hasSlottedTimeLabel = this.el.querySelector('[slot="time-label"]') !== null;
if (!hasSlottedTimeLabel && !this.showDefaultTimeLabel) {
return;
}
return hAsync("slot", { name: "time-label" }, "Time");
}
renderTimeOverlay() {
const { disabled, hourCycle, isTimePopoverOpen, locale, formatOptions } = this;
const computedHourCycle = getHourCycle(locale, hourCycle);
const activePart = this.getActivePartsWithFallback();
return [
hAsync("div", { class: "time-header" }, this.renderTimeLabel()),
hAsync("button", { class: {
'time-body': true,
'time-body-active': isTimePopoverOpen,
}, part: `time-button${isTimePopoverOpen ? ' active' : ''}`, "aria-expanded": "false", "aria-haspopup": "true", disabled: disabled, onClick: async (ev) => {
const { popoverRef } = this;
if (popoverRef) {
this.isTimePopoverOpen = true;
popoverRef.present(new CustomEvent('ionShadowTarget', {
detail: {
ionShadowTarget: ev.target,
},
}));
await popoverRef.onWillDismiss();
this.isTimePopoverOpen = false;
}
} }, getLocalizedTime(locale, activePart, computedHourCycle, formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time)),
hAsync("ion-popover", { alignment: "center", translucent: true, overlayIndex: 1, arrow: false, onWillPresent: (ev) => {
/**
* Intersection Observers do not consistently fire between Blink and Webkit
* when toggling the visibility of the popover and trying to scroll the picker
* column to the correct time value.
*
* This will correctly scroll the element position to the correct time value,
* before the popover is fully presented.
*/
const cols = ev.target.querySelectorAll('ion-picker-column');
// TODO (FW-615): Potentially remove this when intersection observers are fixed in picker column
cols.forEach((col) => col.scrollActiveItemIntoView());
}, style: {
'--offset-y': '-10px',
'--min-width': 'fit-content',
},
// Allow native browser keyboard events to support up/down/home/end key
// navigation within the time picker.
keyboardEvents: true, ref: (el) => (this.popoverRef = el) }, this.renderWheelPicker('time')),
];
}
getHeaderSelectedDateText() {
var _a;
const { activeParts, formatOptions, multiple, titleSelectedDatesFormatter } = this;
const isArray = Array.isArray(activeParts);
let headerText;
if (multiple && isArray && activeParts.length !== 1) {
headerText = `${activeParts.length} days`; // default/fallback for multiple selection
if (titleSelectedDatesFormatter !== undefined) {
try {
headerText = titleSelectedDatesFormatter(convertDataToISO(activeParts));
}
catch (e) {
printIonError('[ion-datetime] - Exception in provided `titleSelectedDatesFormatter`:', e);
}
}
}
else {
// for exactly 1 day selected (multiple set or not), show a formatted version of that
headerText = getLocalizedDateTime(this.locale, this.getActivePartsWithFallback(), (_a = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.date) !== null && _a !== void 0 ? _a : { weekday: 'short', month: 'short', day: 'numeric' });
}
return headerText;
}
renderHeader(showExpandedHeader = true) {
const hasSlottedTitle = this.el.querySelector('[slot="title"]') !== null;
if (!hasSlottedTitle && !this.showDefaultTitle) {
return;
}
return (hAsync("div", { class: "datetime-header" }, hAsync("div", { class: "datetime-title" }, hAsync("slot", { name: "title" }, "Select Date")), showExpandedHeader && hAsync("div", { class: "datetime-selected-date" }, this.getHeaderSelectedDateText())));
}
/**
* Render time picker inside of datetime.
* Do not pass color prop to segment on
* iOS mode. MD segment has been customized and
* should take on the color prop, but iOS
* should just be the default segment.
*/
renderTime() {
const { presentation } = this;
const timeOnlyPresentation = presentation === 'time';
return (hAsync("div", { class: "datetime-time" }, timeOnlyPresentation ? this.renderWheelPicker() : this.renderTimeOverlay()));
}
/**
* Renders the month/year picker that is
* displayed on the calendar grid.
* The .datetime-year class has additional
* styles that let us show/hide the
* picker when the user clicks on the
* toggle in the calendar header.
*/
renderCalendarViewMonthYearPicker() {
return hAsync("div", { class: "datetime-year" }, this.renderWheelView('month-year'));
}
/**
* Render entry point
* All presentation types are rendered from here.
*/
renderDatetime(mode) {
const { presentation, preferWheel } = this;
/**
* Certain presentation types have separate grid and wheel displays.
* If preferWheel is true then we should show a wheel picker instead.
*/
const hasWheelVariant = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
if (preferWheel && hasWheelVariant) {
return [this.renderHeader(false), this.renderWheelView(), this.renderFooter()];
}
switch (presentation) {
case 'date-time':
return [
this.renderHeader(),
this.renderCalendar(mode),
this.renderCalendarViewMonthYearPicker(),
this.renderTime(),
this.renderFooter(),
];
case 'time-date':
return [
this.renderHeader(),
this.renderTime(),
this.renderCalendar(mode),
this.renderCalendarViewMonthYearPicker(),
this.renderFooter(),
];
case 'time':
return [this.renderHeader(false), this.renderTime(), this.renderFooter()];
case 'month':
case 'month-year':
case 'year':
return [this.renderHeader(false), this.renderWheelView(), this.renderFooter()];
default:
return [
this.renderHeader(),
this.renderCalendar(mode),
this.renderCalendarViewMonthYearPicker(),
this.renderFooter(),
];
}
}
render() {
const { name, value, disabled, el, color, readonly, showMonthAndYear, preferWheel, presentation, size, isGridStyle, } = this;
const mode = getIonMode$1(this);
const isMonthAndYearPresentation = presentation === 'year' || presentation === 'month' || presentation === 'month-year';
const shouldShowMonthAndYear = showMonthAndYear || isMonthAndYearPresentation;
const monthYearPickerOpen = showMonthAndYear && !isMonthAndYearPresentation;
const hasDatePresentation = presentation === 'date' || presentation === 'date-time' || presentation === 'time-date';
const hasWheelVariant = hasDatePresentation && preferWheel;
renderHiddenInput(true, el, name, formatValue(value), disabled);
return (hAsync(Host, { key: '57492534800ea059a7c2bbd9f0059cc0b75ae8d2', "aria-disabled": disabled ? 'true' : null, onFocus: this.onFocus, onBlur: this.onBlur, class: Object.assign({}, createColorClasses$1(color, {
[mode]: true,
['datetime-readonly']: readonly,
['datetime-disabled']: disabled,
'show-month-and-year': shouldShowMonthAndYear,
'month-year-picker-open': monthYearPickerOpen,
[`datetime-presentation-${presentation}`]: true,
[`datetime-size-${size}`]: true,
[`datetime-prefer-wheel`]: hasWheelVariant,
[`datetime-grid`]: isGridStyle,
})) }, hAsync("div", { key: '97dac5e5195635ac0bc5fb472b9d09e5c3c6bbc3', class: "intersection-tracker", ref: (el) => (this.intersectionTrackerRef = el) }), this.renderDatetime(mode)));
}
get el() { return getElement(this); }
static get watchers() { return {
"formatOptions": ["formatOptionsChanged"],
"disabled": ["disabledChanged"],
"min": ["minChanged"],
"max": ["maxChanged"],
"presentation": ["presentationChanged"],
"yearValues": ["yearValuesChanged"],
"monthValues": ["monthValuesChanged"],
"dayValues": ["dayValuesChanged"],
"hourValues": ["hourValuesChanged"],
"minuteValues": ["minuteValuesChanged"],
"value": ["valueChanged"]
}; }
static get style() { return {
ios: datetimeIosCss,
md: datetimeMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-datetime",
"$members$": {
"color": [1],
"name": [1],
"disabled": [4],
"formatOptions": [16],
"readonly": [4],
"isDateEnabled": [16],
"showAdjacentDays": [4, "show-adjacent-days"],
"min": [1025],
"max": [1025],
"presentation": [1],
"cancelText": [1, "cancel-text"],
"doneText": [1, "done-text"],
"clearText": [1, "clear-text"],
"yearValues": [8, "year-values"],
"monthValues": [8, "month-values"],
"dayValues": [8, "day-values"],
"hourValues": [8, "hour-values"],
"minuteValues": [8, "minute-values"],
"locale": [1],
"firstDayOfWeek": [2, "first-day-of-week"],
"titleSelectedDatesFormatter": [16],
"multiple": [4],
"highlightedDates": [16],
"value": [1025],
"showDefaultTitle": [4, "show-default-title"],
"showDefaultButtons": [4, "show-default-buttons"],
"showClearButton": [4, "show-clear-button"],
"showDefaultTimeLabel": [4, "show-default-time-label"],
"hourCycle": [1, "hour-cycle"],
"size": [1],
"preferWheel": [4, "prefer-wheel"],
"showMonthAndYear": [32],
"activeParts": [32],
"workingParts": [32],
"isTimePopoverOpen": [32],
"forceRenderDate": [32],
"confirm": [64],
"reset": [64],
"cancel": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
let datetimeIds = 0;
const CANCEL_ROLE = 'datetime-cancel';
const CONFIRM_ROLE = 'datetime-confirm';
const WHEEL_ITEM_PART = 'wheel-item';
const WHEEL_ITEM_ACTIVE_PART = `active`;
const datetimeButtonIosCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}:host button{border-radius:8px;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;margin-top:0px;margin-bottom:0px;position:relative;-webkit-transition:150ms color ease-in-out;transition:150ms color ease-in-out;border:none;background:var(--ion-color-step-300, var(--ion-background-color-step-300, #edeef0));color:var(--ion-text-color, #000);font-family:inherit;font-size:1rem;cursor:pointer;overflow:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host(.time-active) #time-button,:host(.date-active) #date-button{color:var(--ion-color-base)}:host(.datetime-button-disabled){pointer-events:none}:host(.datetime-button-disabled) button{opacity:0.4}:host button{-webkit-padding-start:13px;padding-inline-start:13px;-webkit-padding-end:13px;padding-inline-end:13px;padding-top:7px;padding-bottom:7px}:host button.ion-activated{color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}";
const datetimeButtonMdCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}:host button{border-radius:8px;-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:2px;margin-inline-end:2px;margin-top:0px;margin-bottom:0px;position:relative;-webkit-transition:150ms color ease-in-out;transition:150ms color ease-in-out;border:none;background:var(--ion-color-step-300, var(--ion-background-color-step-300, #edeef0));color:var(--ion-text-color, #000);font-family:inherit;font-size:1rem;cursor:pointer;overflow:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}:host(.time-active) #time-button,:host(.date-active) #date-button{color:var(--ion-color-base)}:host(.datetime-button-disabled){pointer-events:none}:host(.datetime-button-disabled) button{opacity:0.4}:host button{-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:6px;padding-bottom:6px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot date-target - Content displayed inside of the date button.
* @slot time-target - Content displayed inside of the time button.
*
* @part native - The native HTML button that wraps the slotted text.
*/
class DatetimeButton {
constructor(hostRef) {
registerInstance(this, hostRef);
this.datetimeEl = null;
this.overlayEl = null;
this.datetimePresentation = 'date-time';
this.datetimeActive = false;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
this.color = 'primary';
/**
* If `true`, the user cannot interact with the button.
*/
this.disabled = false;
/**
* Accepts one or more string values and converts
* them to DatetimeParts. This is done so datetime-button
* can work with an array internally and not need
* to keep checking if the datetime value is `string` or `string[]`.
*/
this.getParsedDateValues = (value) => {
if (value === undefined || value === null) {
return [];
}
if (Array.isArray(value)) {
return value;
}
return [value];
};
/**
* Check the value property on the linked
* ion-datetime and then format it according
* to the locale specified on ion-datetime.
*/
this.setDateTimeText = () => {
var _a, _b, _c, _d, _e;
const { datetimeEl, datetimePresentation } = this;
if (!datetimeEl) {
return;
}
const { value, locale, formatOptions, hourCycle, preferWheel, multiple, titleSelectedDatesFormatter } = datetimeEl;
const parsedValues = this.getParsedDateValues(value);
/**
* Both ion-datetime and ion-datetime-button default
* to today's date and time if no value is set.
*/
const parsedDatetimes = parseDate(parsedValues.length > 0 ? parsedValues : [getToday()]);
if (!parsedDatetimes) {
return;
}
/**
* If developers incorrectly use multiple="true"
* with non "date" datetimes, then just select
* the first value so the interface does
* not appear broken. Datetime will provide a
* warning in the console.
*/
const firstParsedDatetime = parsedDatetimes[0];
const computedHourCycle = getHourCycle(locale, hourCycle);
this.dateText = this.timeText = undefined;
switch (datetimePresentation) {
case 'date-time':
case 'time-date':
const dateText = getLocalizedDateTime(locale, firstParsedDatetime, (_a = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.date) !== null && _a !== void 0 ? _a : { month: 'short', day: 'numeric', year: 'numeric' });
const timeText = getLocalizedTime(locale, firstParsedDatetime, computedHourCycle, formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time);
if (preferWheel) {
this.dateText = `${dateText} ${timeText}`;
}
else {
this.dateText = dateText;
this.timeText = timeText;
}
break;
case 'date':
if (multiple && parsedValues.length !== 1) {
let headerText = `${parsedValues.length} days`; // default/fallback for multiple selection
if (titleSelectedDatesFormatter !== undefined) {
try {
headerText = titleSelectedDatesFormatter(parsedValues);
}
catch (e) {
printIonError('[ion-datetime-button] - Exception in provided `titleSelectedDatesFormatter`:', e);
}
}
this.dateText = headerText;
}
else {
this.dateText = getLocalizedDateTime(locale, firstParsedDatetime, (_b = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.date) !== null && _b !== void 0 ? _b : { month: 'short', day: 'numeric', year: 'numeric' });
}
break;
case 'time':
this.timeText = getLocalizedTime(locale, firstParsedDatetime, computedHourCycle, formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time);
break;
case 'month-year':
this.dateText = getLocalizedDateTime(locale, firstParsedDatetime, (_c = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.date) !== null && _c !== void 0 ? _c : { month: 'long', year: 'numeric' });
break;
case 'month':
this.dateText = getLocalizedDateTime(locale, firstParsedDatetime, (_d = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time) !== null && _d !== void 0 ? _d : { month: 'long' });
break;
case 'year':
this.dateText = getLocalizedDateTime(locale, firstParsedDatetime, (_e = formatOptions === null || formatOptions === void 0 ? void 0 : formatOptions.time) !== null && _e !== void 0 ? _e : { year: 'numeric' });
break;
}
};
/**
* Waits for the ion-datetime to re-render.
* This is needed in order to correctly position
* a popover relative to the trigger element.
*/
this.waitForDatetimeChanges = async () => {
const { datetimeEl } = this;
if (!datetimeEl) {
return Promise.resolve();
}
return new Promise((resolve) => {
addEventListener$1(datetimeEl, 'ionRender', resolve, { once: true });
});
};
this.handleDateClick = async (ev) => {
const { datetimeEl, datetimePresentation } = this;
if (!datetimeEl) {
return;
}
let needsPresentationChange = false;
/**
* When clicking the date button,
* we need to make sure that only a date
* picker is displayed. For presentation styles
* that display content other than a date picker,
* we need to update the presentation style.
*/
switch (datetimePresentation) {
case 'date-time':
case 'time-date':
const needsChange = datetimeEl.presentation !== 'date';
/**
* The date+time wheel picker
* shows date and time together,
* so do not adjust the presentation
* in that case.
*/
if (!datetimeEl.preferWheel && needsChange) {
datetimeEl.presentation = 'date';
needsPresentationChange = true;
}
break;
}
/**
* Track which button was clicked
* so that it can have the correct
* activated styles applied when
* the modal/popover containing
* the datetime is opened.
*/
this.selectedButton = 'date';
this.presentOverlay(ev, needsPresentationChange, this.dateTargetEl);
};
this.handleTimeClick = (ev) => {
const { datetimeEl, datetimePresentation } = this;
if (!datetimeEl) {
return;
}
let needsPresentationChange = false;
/**
* When clicking the time button,
* we need to make sure that only a time
* picker is displayed. For presentation styles
* that display content other than a time picker,
* we need to update the presentation style.
*/
switch (datetimePresentation) {
case 'date-time':
case 'time-date':
const needsChange = datetimeEl.presentation !== 'time';
if (needsChange) {
datetimeEl.presentation = 'time';
needsPresentationChange = true;
}
break;
}
/**
* Track which button was clicked
* so that it can have the correct
* activated styles applied when
* the modal/popover containing
* the datetime is opened.
*/
this.selectedButton = 'time';
this.presentOverlay(ev, needsPresentationChange, this.timeTargetEl);
};
/**
* If the datetime is presented in an
* overlay, the datetime and overlay
* should be appropriately sized.
* These classes provide default sizing values
* that developers can customize.
* The goal is to provide an overlay that is
* reasonably sized with a datetime that
* fills the entire container.
*/
this.presentOverlay = async (ev, needsPresentationChange, triggerEl) => {
const { overlayEl } = this;
if (!overlayEl) {
return;
}
if (overlayEl.tagName === 'ION-POPOVER') {
/**
* When the presentation on datetime changes,
* we need to wait for the component to re-render
* otherwise the computed width/height of the
* popover content will be wrong, causing
* the popover to not align with the trigger element.
*/
if (needsPresentationChange) {
await this.waitForDatetimeChanges();
}
/**
* We pass the trigger button element
* so that the popover aligns with the individual
* button that was clicked, not the component container.
*/
overlayEl.present(Object.assign(Object.assign({}, ev), { detail: {
ionShadowTarget: triggerEl,
} }));
}
else {
overlayEl.present();
}
};
}
async componentWillLoad() {
const { datetime } = this;
if (!datetime) {
printIonError('[ion-datetime-button] - An ID associated with an ion-datetime instance is required to function properly.', this.el);
return;
}
const datetimeEl = (this.datetimeEl = document.getElementById(datetime));
if (!datetimeEl) {
printIonError(`[ion-datetime-button] - No ion-datetime instance found for ID '${datetime}'.`, this.el);
return;
}
/**
* The element reference must be an ion-datetime. Print an error
* if a non-datetime element was provided.
*/
if (datetimeEl.tagName !== 'ION-DATETIME') {
printIonError(`[ion-datetime-button] - Expected an ion-datetime instance for ID '${datetime}' but received '${datetimeEl.tagName.toLowerCase()}' instead.`, datetimeEl);
return;
}
/**
* Since the datetime can be used in any context (overlays, accordion, etc)
* we track when it is visible to determine when it is active.
* This informs which button is highlighted as well as the
* aria-expanded state.
*/
const io = new IntersectionObserver((entries) => {
const ev = entries[0];
this.datetimeActive = ev.isIntersecting;
}, {
threshold: 0.01,
});
io.observe(datetimeEl);
/**
* Get a reference to any modal/popover
* the datetime is being used in so we can
* correctly size it when it is presented.
*/
const overlayEl = (this.overlayEl = datetimeEl.closest('ion-modal, ion-popover'));
/**
* The .ion-datetime-button-overlay class contains
* styles that allow any modal/popover to be
* sized according to the dimensions of the datetime.
* If developers want a smaller/larger overlay all they need
* to do is change the width/height of the datetime.
* Additionally, this lets us avoid having to set
* explicit widths on each variant of datetime.
*/
if (overlayEl) {
overlayEl.classList.add('ion-datetime-button-overlay');
}
componentOnReady(datetimeEl, () => {
const datetimePresentation = (this.datetimePresentation = datetimeEl.presentation || 'date-time');
/**
* Set the initial display
* in the rendered buttons.
*
* From there, we need to listen
* for ionChange to be emitted
* from datetime so we know when
* to re-render the displayed
* text in the buttons.
*/
this.setDateTimeText();
addEventListener$1(datetimeEl, 'ionValueChange', this.setDateTimeText);
/**
* Configure the initial selected button
* in the event that the datetime is displayed
* without clicking one of the datetime buttons.
* For example, a datetime could be expanded
* in an accordion. In this case users only
* need to click the accordion header to show
* the datetime.
*/
switch (datetimePresentation) {
case 'date-time':
case 'date':
case 'month-year':
case 'month':
case 'year':
this.selectedButton = 'date';
break;
case 'time-date':
case 'time':
this.selectedButton = 'time';
break;
}
});
}
render() {
const { color, dateText, timeText, selectedButton, datetimeActive, disabled } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '11d037e6ab061e5116842970760b04850b42f2c7', class: createColorClasses$1(color, {
[mode]: true,
[`${selectedButton}-active`]: datetimeActive,
['datetime-button-disabled']: disabled,
}) }, dateText && (hAsync("button", { key: '08ecb62da0fcbf7466a1f2403276712a3ff17fbc', class: "ion-activatable", id: "date-button", "aria-expanded": datetimeActive ? 'true' : 'false', onClick: this.handleDateClick, disabled: disabled, part: "native", ref: (el) => (this.dateTargetEl = el) }, hAsync("slot", { key: '1c04853d4d23c0f1a594602bde44511c98355644', name: "date-target" }, dateText), mode === 'md' && hAsync("ion-ripple-effect", { key: '5fc566cd4bc885bcf983ce99e3dc65d7f485bf9b' }))), timeText && (hAsync("button", { key: 'c9c5c34ac338badf8659da22bea5829d62c51169', class: "ion-activatable", id: "time-button", "aria-expanded": datetimeActive ? 'true' : 'false', onClick: this.handleTimeClick, disabled: disabled, part: "native", ref: (el) => (this.timeTargetEl = el) }, hAsync("slot", { key: '147a9d2069dbf737f6fc64787823d6d5af5aa653', name: "time-target" }, timeText), mode === 'md' && hAsync("ion-ripple-effect", { key: '70a5e25b75ed90ac6bba003468435f67aa9d8f0a' })))));
}
get el() { return getElement(this); }
static get style() { return {
ios: datetimeButtonIosCss,
md: datetimeButtonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-datetime-button",
"$members$": {
"color": [513],
"disabled": [516],
"datetime": [1],
"datetimePresentation": [32],
"dateText": [32],
"timeText": [32],
"datetimeActive": [32],
"selectedButton": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["disabled", "disabled"]]
}; }
}
const fabCss = ":host{position:absolute;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;height:-webkit-fit-content;height:-moz-fit-content;height:fit-content;z-index:999}:host(.fab-horizontal-center){left:0px;right:0px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto}:host(.fab-horizontal-start){left:calc(10px + var(--ion-safe-area-left, 0px));}:host-context([dir=rtl]):host(.fab-horizontal-start),:host-context([dir=rtl]).fab-horizontal-start{right:calc(10px + var(--ion-safe-area-right, 0px));left:unset}@supports selector(:dir(rtl)){:host(.fab-horizontal-start:dir(rtl)){right:calc(10px + var(--ion-safe-area-right, 0px));left:unset}}:host(.fab-horizontal-end){right:calc(10px + var(--ion-safe-area-right, 0px));}:host-context([dir=rtl]):host(.fab-horizontal-end),:host-context([dir=rtl]).fab-horizontal-end{left:calc(10px + var(--ion-safe-area-left, 0px));right:unset}@supports selector(:dir(rtl)){:host(.fab-horizontal-end:dir(rtl)){left:calc(10px + var(--ion-safe-area-left, 0px));right:unset}}:host(.fab-vertical-top){top:10px}:host(.fab-vertical-top.fab-edge){top:0}:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-button){margin-top:-50%}:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-button.fab-button-small){margin-top:calc((-100% + 16px) / 2)}:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-start),:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-end){margin-top:-50%}:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-top),:host(.fab-vertical-top.fab-edge) ::slotted(ion-fab-list.fab-list-side-bottom){margin-top:calc(50% + 10px)}:host(.fab-vertical-bottom){bottom:10px}:host(.fab-vertical-bottom.fab-edge){bottom:0}:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-button){margin-bottom:-50%}:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-button.fab-button-small){margin-bottom:calc((-100% + 16px) / 2)}:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-start),:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-end){margin-bottom:-50%}:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-top),:host(.fab-vertical-bottom.fab-edge) ::slotted(ion-fab-list.fab-list-side-bottom){margin-bottom:calc(50% + 10px)}:host(.fab-vertical-center){top:0px;bottom:0px;margin-top:auto;margin-bottom:auto}";
class Fab {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the fab will display on the edge of the header if
* `vertical` is `"top"`, and on the edge of the footer if
* it is `"bottom"`. Should be used with a `fixed` slot.
*/
this.edge = false;
/**
* If `true`, both the `ion-fab-button` and all `ion-fab-list` inside `ion-fab` will become active.
* That means `ion-fab-button` will become a `close` icon and `ion-fab-list` will become visible.
*/
this.activated = false;
}
activatedChanged() {
const activated = this.activated;
const fab = this.getFab();
if (fab) {
fab.activated = activated;
}
Array.from(this.el.querySelectorAll('ion-fab-list')).forEach((list) => {
list.activated = activated;
});
}
componentDidLoad() {
if (this.activated) {
this.activatedChanged();
}
}
/**
* Close an active FAB list container.
*/
async close() {
this.activated = false;
}
getFab() {
return this.el.querySelector('ion-fab-button');
}
/**
* Opens/Closes the FAB list container.
* @internal
*/
async toggle() {
const hasList = !!this.el.querySelector('ion-fab-list');
if (hasList) {
this.activated = !this.activated;
}
}
render() {
const { horizontal, vertical, edge } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '8a310806d0e748d7ebb0ed3d9a2652038e0f2960', class: {
[mode]: true,
[`fab-horizontal-${horizontal}`]: horizontal !== undefined,
[`fab-vertical-${vertical}`]: vertical !== undefined,
'fab-edge': edge,
} }, hAsync("slot", { key: '9394ef6d6e5b0410fa6ba212171f687fb178ce2d' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"activated": ["activatedChanged"]
}; }
static get style() { return fabCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-fab",
"$members$": {
"horizontal": [1],
"vertical": [1],
"edge": [4],
"activated": [1028],
"close": [64],
"toggle": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const fabButtonIosCss = ":host{--color-activated:var(--color);--color-focused:var(--color);--color-hover:var(--color);--background-hover:var(--ion-color-primary-contrast, #fff);--background-hover-opacity:.08;--transition:background-color, opacity 100ms linear;--ripple-color:currentColor;--border-radius:50%;--border-width:0;--border-style:none;--border-color:initial;--padding-top:0;--padding-end:0;--padding-bottom:0;--padding-start:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;width:56px;height:56px;font-size:14px;text-align:center;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:var(--border-radius);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:block;position:relative;width:100%;height:100%;-webkit-transform:var(--transform);transform:var(--transform);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:var(--background);background-clip:padding-box;color:var(--color);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);contain:strict;cursor:pointer;overflow:hidden;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-sizing:border-box;box-sizing:border-box}::slotted(ion-icon){line-height:1}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.button-inner{left:0;right:0;top:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;height:100%;-webkit-transition:all ease-in-out 300ms;transition:all ease-in-out 300ms;-webkit-transition-property:opacity, -webkit-transform;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;z-index:1}:host(.fab-button-disabled){cursor:default;opacity:0.5;pointer-events:none}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}:host(.ion-activated) .button-native{color:var(--color-activated)}:host(.ion-activated) .button-native::after{background:var(--background-activated);opacity:var(--background-activated-opacity)}::slotted(ion-icon){line-height:1}:host(.fab-button-small){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:8px;margin-bottom:8px;width:40px;height:40px}.close-icon{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;left:0;right:0;top:0;position:absolute;height:100%;-webkit-transform:scale(0.4) rotateZ(-45deg);transform:scale(0.4) rotateZ(-45deg);-webkit-transition:all ease-in-out 300ms;transition:all ease-in-out 300ms;-webkit-transition-property:opacity, -webkit-transform;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;font-size:var(--close-icon-font-size);opacity:0;z-index:1}:host(.fab-button-close-active) .close-icon{-webkit-transform:scale(1) rotateZ(0deg);transform:scale(1) rotateZ(0deg);opacity:1}:host(.fab-button-close-active) .button-inner{-webkit-transform:scale(0.4) rotateZ(45deg);transform:scale(0.4) rotateZ(45deg);opacity:0}ion-ripple-effect{color:var(--ripple-color)}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.fab-button-translucent) .button-native{-webkit-backdrop-filter:var(--backdrop-filter);backdrop-filter:var(--backdrop-filter)}}:host(.ion-color) .button-native{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host{--background:var(--ion-color-primary, #0054e9);--background-activated:var(--ion-color-primary-shade, #004acd);--background-focused:var(--ion-color-primary-shade, #004acd);--background-hover:var(--ion-color-primary-tint, #1a65eb);--background-activated-opacity:1;--background-focused-opacity:1;--background-hover-opacity:1;--color:var(--ion-color-primary-contrast, #fff);--box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);--transition:0.2s transform cubic-bezier(0.25, 1.11, 0.78, 1.59);--close-icon-font-size:28px}:host(.ion-activated){--box-shadow:0 4px 16px rgba(0, 0, 0, 0.12);--transform:scale(1.1);--transition:0.2s transform ease-out}::slotted(ion-icon){font-size:28px}:host(.fab-button-in-list){--background:var(--ion-color-light, #f4f5f8);--background-activated:var(--ion-color-light-shade, #d7d8da);--background-focused:var(--background-activated);--background-hover:var(--ion-color-light-tint, #f5f6f9);--color:var(--ion-color-light-contrast, #000);--color-activated:var(--ion-color-light-contrast, #000);--color-focused:var(--color-activated);--transition:transform 200ms ease 10ms, opacity 200ms ease 10ms}:host(.fab-button-in-list) ::slotted(ion-icon){font-size:18px}:host(.ion-color.ion-focused) .button-native::after{background:var(--ion-color-shade)}:host(.ion-color.ion-focused) .button-native,:host(.ion-color.ion-activated) .button-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-focused) .button-native::after,:host(.ion-color.ion-activated) .button-native::after{background:var(--ion-color-shade)}@media (any-hover: hover){:host(.ion-color:hover) .button-native{color:var(--ion-color-contrast)}:host(.ion-color:hover) .button-native::after{background:var(--ion-color-tint)}}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.fab-button-translucent){--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.9);--background-hover:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.8);--background-focused:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.82);--backdrop-filter:saturate(180%) blur(20px)}:host(.fab-button-translucent-in-list){--background:rgba(var(--ion-color-light-rgb, 244, 245, 248), 0.9);--background-hover:rgba(var(--ion-color-light-rgb, 244, 245, 248), 0.8);--background-focused:rgba(var(--ion-color-light-rgb, 244, 245, 248), 0.82)}}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){@media (any-hover: hover){:host(.fab-button-translucent.ion-color:hover) .button-native{background:rgba(var(--ion-color-base-rgb), 0.8)}}:host(.ion-color.fab-button-translucent) .button-native{background:rgba(var(--ion-color-base-rgb), 0.9)}:host(.ion-color.ion-focused.fab-button-translucent) .button-native,:host(.ion-color.ion-activated.fab-button-translucent) .button-native{background:var(--ion-color-base)}}";
const fabButtonMdCss = ":host{--color-activated:var(--color);--color-focused:var(--color);--color-hover:var(--color);--background-hover:var(--ion-color-primary-contrast, #fff);--background-hover-opacity:.08;--transition:background-color, opacity 100ms linear;--ripple-color:currentColor;--border-radius:50%;--border-width:0;--border-style:none;--border-color:initial;--padding-top:0;--padding-end:0;--padding-bottom:0;--padding-start:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;width:56px;height:56px;font-size:14px;text-align:center;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:var(--border-radius);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:block;position:relative;width:100%;height:100%;-webkit-transform:var(--transform);transform:var(--transform);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:var(--background);background-clip:padding-box;color:var(--color);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);contain:strict;cursor:pointer;overflow:hidden;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-sizing:border-box;box-sizing:border-box}::slotted(ion-icon){line-height:1}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.button-inner{left:0;right:0;top:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;height:100%;-webkit-transition:all ease-in-out 300ms;transition:all ease-in-out 300ms;-webkit-transition-property:opacity, -webkit-transform;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;z-index:1}:host(.fab-button-disabled){cursor:default;opacity:0.5;pointer-events:none}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}:host(.ion-activated) .button-native{color:var(--color-activated)}:host(.ion-activated) .button-native::after{background:var(--background-activated);opacity:var(--background-activated-opacity)}::slotted(ion-icon){line-height:1}:host(.fab-button-small){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:8px;margin-bottom:8px;width:40px;height:40px}.close-icon{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;left:0;right:0;top:0;position:absolute;height:100%;-webkit-transform:scale(0.4) rotateZ(-45deg);transform:scale(0.4) rotateZ(-45deg);-webkit-transition:all ease-in-out 300ms;transition:all ease-in-out 300ms;-webkit-transition-property:opacity, -webkit-transform;transition-property:opacity, -webkit-transform;transition-property:transform, opacity;transition-property:transform, opacity, -webkit-transform;font-size:var(--close-icon-font-size);opacity:0;z-index:1}:host(.fab-button-close-active) .close-icon{-webkit-transform:scale(1) rotateZ(0deg);transform:scale(1) rotateZ(0deg);opacity:1}:host(.fab-button-close-active) .button-inner{-webkit-transform:scale(0.4) rotateZ(45deg);transform:scale(0.4) rotateZ(45deg);opacity:0}ion-ripple-effect{color:var(--ripple-color)}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.fab-button-translucent) .button-native{-webkit-backdrop-filter:var(--backdrop-filter);backdrop-filter:var(--backdrop-filter)}}:host(.ion-color) .button-native{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host{--background:var(--ion-color-primary, #0054e9);--background-activated:transparent;--background-focused:currentColor;--background-hover:currentColor;--background-activated-opacity:0;--background-focused-opacity:.24;--background-hover-opacity:.08;--color:var(--ion-color-primary-contrast, #fff);--box-shadow:0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);--transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1), background-color 280ms cubic-bezier(0.4, 0, 0.2, 1), color 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 15ms linear 30ms, transform 270ms cubic-bezier(0, 0, 0.2, 1) 0ms;--close-icon-font-size:24px}:host(.ion-activated){--box-shadow:0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 12px 17px 2px rgba(0, 0, 0, 0.14), 0 5px 22px 4px rgba(0, 0, 0, 0.12)}::slotted(ion-icon){font-size:24px}:host(.fab-button-in-list){--color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54);--color-activated:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54);--color-focused:var(--color-activated);--background:var(--ion-color-light, #f4f5f8);--background-activated:transparent;--background-focused:var(--ion-color-light-shade, #d7d8da);--background-hover:var(--ion-color-light-tint, #f5f6f9)}:host(.fab-button-in-list) ::slotted(ion-icon){font-size:18px}:host(.ion-color.ion-focused) .button-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-focused) .button-native::after{background:var(--ion-color-contrast)}:host(.ion-color.ion-activated) .button-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-activated) .button-native::after{background:transparent}@media (any-hover: hover){:host(.ion-color:hover) .button-native{color:var(--ion-color-contrast)}:host(.ion-color:hover) .button-native::after{background:var(--ion-color-contrast)}}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML button or anchor element that wraps all child elements.
* @part close-icon - The close icon that is displayed when a fab list opens (uses ion-icon).
*/
class FabButton {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.fab = null;
this.inheritedAttributes = {};
/**
* If `true`, the fab button will be show a close icon.
*/
this.activated = false;
/**
* If `true`, the user cannot interact with the fab button.
*/
this.disabled = false;
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
*/
this.routerDirection = 'forward';
/**
* If `true`, the fab button will show when in a fab-list.
*/
this.show = false;
/**
* If `true`, the fab button will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
/**
* The type of the button.
*/
this.type = 'button';
/**
* The icon name to use for the close icon. This will appear when the fab button
* is pressed. Only applies if it is the main button inside of a fab containing a
* fab list.
*/
this.closeIcon = close;
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
this.onClick = () => {
const { fab } = this;
if (!fab) {
return;
}
fab.toggle();
};
}
connectedCallback() {
this.fab = this.el.closest('ion-fab');
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
render() {
const { el, disabled, color, href, activated, show, translucent, size, inheritedAttributes } = this;
const inList = hostContext('ion-fab-list', el);
const mode = getIonMode$1(this);
const TagType = href === undefined ? 'button' : 'a';
const attrs = TagType === 'button'
? { type: this.type }
: {
download: this.download,
href,
rel: this.rel,
target: this.target,
};
return (hAsync(Host, { key: '4eee204d20b0e2ffed49a88f6cb3e04b6697965c', onClick: this.onClick, "aria-disabled": disabled ? 'true' : null, class: createColorClasses$1(color, {
[mode]: true,
'fab-button-in-list': inList,
'fab-button-translucent-in-list': inList && translucent,
'fab-button-close-active': activated,
'fab-button-show': show,
'fab-button-disabled': disabled,
'fab-button-translucent': translucent,
'ion-activatable': true,
'ion-focusable': true,
[`fab-button-${size}`]: size !== undefined,
}) }, hAsync(TagType, Object.assign({ key: '914561622c0c6bd41453e828a7d8a39f924875ac' }, attrs, { class: "button-native", part: "native", disabled: disabled, onFocus: this.onFocus, onBlur: this.onBlur, onClick: (ev) => openURL(href, ev, this.routerDirection, this.routerAnimation) }, inheritedAttributes), hAsync("ion-icon", { key: '2c8090742a64c62a79243667027a195cca9d5912', "aria-hidden": "true", icon: this.closeIcon, part: "close-icon", class: "close-icon", lazy: false }), hAsync("span", { key: 'c3e55291e4c4d306d34a4b95dd2e727e87bdf39c', class: "button-inner" }, hAsync("slot", { key: 'f8e57f71d8f8878d9746cfece82f57f19ef9e988' })), mode === 'md' && hAsync("ion-ripple-effect", { key: 'a5e94fa0bb9836072300617245ed0c1b4887bac6' }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: fabButtonIosCss,
md: fabButtonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-fab-button",
"$members$": {
"color": [513],
"activated": [4],
"disabled": [4],
"download": [1],
"href": [1],
"rel": [1],
"routerDirection": [1, "router-direction"],
"routerAnimation": [16],
"target": [1],
"show": [4],
"translucent": [4],
"type": [1],
"size": [1],
"closeIcon": [1, "close-icon"]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const fabListCss = ":host{margin-left:0;margin-right:0;margin-top:calc(100% + 10px);margin-bottom:calc(100% + 10px);display:none;position:absolute;top:0;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;min-width:56px;min-height:56px}:host(.fab-list-active){display:-ms-flexbox;display:flex}::slotted(.fab-button-in-list){margin-left:0;margin-right:0;margin-top:8px;margin-bottom:8px;width:40px;height:40px;-webkit-transform:scale(0);transform:scale(0);opacity:0;visibility:hidden}:host(.fab-list-side-top) ::slotted(.fab-button-in-list),:host(.fab-list-side-bottom) ::slotted(.fab-button-in-list){margin-left:0;margin-right:0;margin-top:5px;margin-bottom:5px}:host(.fab-list-side-start) ::slotted(.fab-button-in-list),:host(.fab-list-side-end) ::slotted(.fab-button-in-list){-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:5px;margin-inline-end:5px;margin-top:0;margin-bottom:0}::slotted(.fab-button-in-list.fab-button-show){-webkit-transform:scale(1);transform:scale(1);opacity:1;visibility:visible}:host(.fab-list-side-top){top:auto;bottom:0;-ms-flex-direction:column-reverse;flex-direction:column-reverse}:host(.fab-list-side-start){-webkit-margin-start:calc(100% + 10px);margin-inline-start:calc(100% + 10px);-webkit-margin-end:calc(100% + 10px);margin-inline-end:calc(100% + 10px);margin-top:0;margin-bottom:0;-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.fab-list-side-start){inset-inline-end:0}:host(.fab-list-side-end){-webkit-margin-start:calc(100% + 10px);margin-inline-start:calc(100% + 10px);-webkit-margin-end:calc(100% + 10px);margin-inline-end:calc(100% + 10px);margin-top:0;margin-bottom:0;-ms-flex-direction:row;flex-direction:row}:host(.fab-list-side-end){inset-inline-start:0}";
class FabList {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the fab list will show all fab buttons in the list.
*/
this.activated = false;
/**
* The side the fab list will show on relative to the main fab button.
*/
this.side = 'bottom';
}
activatedChanged(activated) {
const fabs = Array.from(this.el.querySelectorAll('ion-fab-button'));
// if showing the fabs add a timeout, else show immediately
const timeout = activated ? 30 : 0;
fabs.forEach((fab, i) => {
setTimeout(() => (fab.show = activated), i * timeout);
});
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '64b33366447f66c7f979cfac56307fbb1a6fac1c', class: {
[mode]: true,
'fab-list-active': this.activated,
[`fab-list-side-${this.side}`]: true,
} }, hAsync("slot", { key: 'd9f474f7f20fd7e813db358fddc720534ca05bb6' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"activated": ["activatedChanged"]
}; }
static get style() { return fabListCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-fab-list",
"$members$": {
"activated": [4],
"side": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const ION_CONTENT_TAG_NAME = 'ION-CONTENT';
const ION_CONTENT_ELEMENT_SELECTOR = 'ion-content';
const ION_CONTENT_CLASS_SELECTOR = '.ion-content-scroll-host';
/**
* Selector used for implementations reliant on `<ion-content>` for scroll event changes.
*
* Developers should use the `.ion-content-scroll-host` selector to target the element emitting
* scroll events. With virtual scroll implementations this will be the host element for
* the scroll viewport.
*/
const ION_CONTENT_SELECTOR = `${ION_CONTENT_ELEMENT_SELECTOR}, ${ION_CONTENT_CLASS_SELECTOR}`;
const isIonContent = (el) => el.tagName === ION_CONTENT_TAG_NAME;
/**
* Waits for the element host fully initialize before
* returning the inner scroll element.
*
* For `ion-content` the scroll target will be the result
* of the `getScrollElement` function.
*
* For custom implementations it will be the element host
* or a selector within the host, if supplied through `scrollTarget`.
*/
const getScrollElement = async (el) => {
if (isIonContent(el)) {
await new Promise((resolve) => componentOnReady(el, resolve));
return el.getScrollElement();
}
return el;
};
/**
* Queries the element matching the selector for IonContent.
* See ION_CONTENT_SELECTOR for the selector used.
*/
const findIonContent = (el) => {
/**
* First we try to query the custom scroll host selector in cases where
* the implementation is using an outer `ion-content` with an inner custom
* scroll container.
*/
const customContentHost = el.querySelector(ION_CONTENT_CLASS_SELECTOR);
if (customContentHost) {
return customContentHost;
}
return el.querySelector(ION_CONTENT_SELECTOR);
};
/**
* Queries the closest element matching the selector for IonContent.
*/
const findClosestIonContent = (el) => {
return el.closest(ION_CONTENT_SELECTOR);
};
/**
* Prints an error informing developers that an implementation requires an element to be used
* within either the `ion-content` selector or the `.ion-content-scroll-host` class.
*/
const printIonContentErrorMsg = (el) => {
return printRequiredElementError(el, ION_CONTENT_ELEMENT_SELECTOR);
};
/**
* Several components in Ionic need to prevent scrolling
* during a gesture (card modal, range, item sliding, etc).
* Use this utility to account for ion-content and custom content hosts.
*/
const disableContentScrollY = (contentEl) => {
if (isIonContent(contentEl)) {
const ionContent = contentEl;
const initialScrollY = ionContent.scrollY;
ionContent.scrollY = false;
/**
* This should be passed into resetContentScrollY
* so that we can revert ion-content's scrollY to the
* correct state. For example, if scrollY = false
* initially, we do not want to enable scrolling
* when we call resetContentScrollY.
*/
return initialScrollY;
}
else {
contentEl.style.setProperty('overflow', 'hidden');
return true;
}
};
const resetContentScrollY = (contentEl, initialScrollY) => {
if (isIonContent(contentEl)) {
contentEl.scrollY = initialScrollY;
}
else {
contentEl.style.removeProperty('overflow');
}
};
var ExceptionCode;
(function (ExceptionCode) {
/**
* API is not implemented.
*
* This usually means the API can't be used because it is not implemented for
* the current platform.
*/
ExceptionCode["Unimplemented"] = "UNIMPLEMENTED";
/**
* API is not available.
*
* This means the API can't be used right now because:
* - it is currently missing a prerequisite, such as network connectivity
* - it requires a particular platform or browser version
*/
ExceptionCode["Unavailable"] = "UNAVAILABLE";
})(ExceptionCode || (ExceptionCode = {}));
var KeyboardResize;
(function (KeyboardResize) {
/**
* Only the `body` HTML element will be resized.
* Relative units are not affected, because the viewport does not change.
*
* @since 1.0.0
*/
KeyboardResize["Body"] = "body";
/**
* Only the `ion-app` HTML element will be resized.
* Use it only for Ionic Framework apps.
*
* @since 1.0.0
*/
KeyboardResize["Ionic"] = "ionic";
/**
* The whole native Web View will be resized when the keyboard shows/hides.
* This affects the `vh` relative unit.
*
* @since 1.0.0
*/
KeyboardResize["Native"] = "native";
/**
* Neither the app nor the Web View are resized.
*
* @since 1.0.0
*/
KeyboardResize["None"] = "none";
})(KeyboardResize || (KeyboardResize = {}));
const Keyboard = {
getEngine() {
const capacitor = getCapacitor();
if (capacitor === null || capacitor === void 0 ? void 0 : capacitor.isPluginAvailable('Keyboard')) {
return capacitor.Plugins.Keyboard;
}
return undefined;
},
getResizeMode() {
const engine = this.getEngine();
if (!(engine === null || engine === void 0 ? void 0 : engine.getResizeMode)) {
return Promise.resolve(undefined);
}
return engine.getResizeMode().catch((e) => {
if (e.code === ExceptionCode.Unimplemented) {
// If the native implementation is not available
// we treat it the same as if the plugin is not available.
return undefined;
}
throw e;
});
},
};
/**
* The element that resizes when the keyboard opens
* is going to depend on the resize mode
* which is why we check that here.
*/
const getResizeContainer = (resizeMode) => {
/**
* If doc is undefined then we are
* in an SSR environment, so the keyboard
* adjustment does not apply.
* If the webview does not resize then there
* is no container to resize.
*/
if (doc === undefined || resizeMode === KeyboardResize.None || resizeMode === undefined) {
return null;
}
/**
* The three remaining resize modes: Native, Ionic, and Body
* all cause `ion-app` to resize, so we can listen for changes
* on that. In the event `ion-app` is not available then
* we can fall back to `body`.
*/
const ionApp = doc.querySelector('ion-app');
return ionApp !== null && ionApp !== void 0 ? ionApp : doc.body;
};
/**
* Get the height of ion-app or body.
* This is used for determining if the webview
* has resized before the keyboard closed.
* */
const getResizeContainerHeight = (resizeMode) => {
const containerElement = getResizeContainer(resizeMode);
return containerElement === null ? 0 : containerElement.clientHeight;
};
/**
* Creates a controller that tracks and reacts to opening or closing the keyboard.
*
* @internal
* @param keyboardChangeCallback A function to call when the keyboard opens or closes.
*/
const createKeyboardController = async (keyboardChangeCallback) => {
let keyboardWillShowHandler;
let keyboardWillHideHandler;
let keyboardVisible;
/**
* This lets us determine if the webview content
* has resized as a result of the keyboard.
*/
let initialResizeContainerHeight;
const init = async () => {
const resizeOptions = await Keyboard.getResizeMode();
const resizeMode = resizeOptions === undefined ? undefined : resizeOptions.mode;
keyboardWillShowHandler = () => {
/**
* We need to compute initialResizeContainerHeight right before
* the keyboard opens to guarantee the resize container is visible.
* The resize container may not be visible if we compute this
* as soon as the keyboard controller is created.
* We should only need to do this once to avoid additional clientHeight
* computations.
*/
if (initialResizeContainerHeight === undefined) {
initialResizeContainerHeight = getResizeContainerHeight(resizeMode);
}
keyboardVisible = true;
fireChangeCallback(keyboardVisible, resizeMode);
};
keyboardWillHideHandler = () => {
keyboardVisible = false;
fireChangeCallback(keyboardVisible, resizeMode);
};
win$1 === null || win$1 === void 0 ? void 0 : win$1.addEventListener('keyboardWillShow', keyboardWillShowHandler);
win$1 === null || win$1 === void 0 ? void 0 : win$1.addEventListener('keyboardWillHide', keyboardWillHideHandler);
};
const fireChangeCallback = (state, resizeMode) => {
if (keyboardChangeCallback) {
keyboardChangeCallback(state, createResizePromiseIfNeeded(resizeMode));
}
};
/**
* Code responding to keyboard lifecycles may need
* to show/hide content once the webview has
* resized as a result of the keyboard showing/hiding.
* createResizePromiseIfNeeded provides a way for code to wait for the
* resize event that was triggered as a result of the keyboard.
*/
const createResizePromiseIfNeeded = (resizeMode) => {
if (
/**
* If we are in an SSR environment then there is
* no window to resize. Additionally, if there
* is no resize mode or the resize mode is "None"
* then initialResizeContainerHeight will be 0
*/
initialResizeContainerHeight === 0 ||
/**
* If the keyboard is closed before the webview resizes initially
* then the webview will never resize.
*/
initialResizeContainerHeight === getResizeContainerHeight(resizeMode)) {
return;
}
/**
* Get the resize container so we can
* attach the ResizeObserver below to
* the correct element.
*/
const containerElement = getResizeContainer(resizeMode);
if (containerElement === null) {
return;
}
/**
* Some part of the web content should resize,
* and we need to listen for a resize.
*/
return new Promise((resolve) => {
const callback = () => {
/**
* As per the spec, the ResizeObserver
* will fire when observation starts if
* the observed element is rendered and does not
* have a size of 0 x 0. However, the watched element
* may or may not have resized by the time this first
* callback is fired. As a result, we need to check
* the dimensions of the element.
*
* https://www.w3.org/TR/resize-observer/#intro
*/
if (containerElement.clientHeight === initialResizeContainerHeight) {
/**
* The resize happened, so stop listening
* for resize on this element.
*/
ro.disconnect();
resolve();
}
};
/**
* In Capacitor there can be delay between when the window
* resizes and when the container element resizes, so we cannot
* rely on a 'resize' event listener on the window.
* Instead, we need to determine when the container
* element resizes using a ResizeObserver.
*/
const ro = new ResizeObserver(callback);
ro.observe(containerElement);
});
};
const destroy = () => {
win$1 === null || win$1 === void 0 ? void 0 : win$1.removeEventListener('keyboardWillShow', keyboardWillShowHandler);
win$1 === null || win$1 === void 0 ? void 0 : win$1.removeEventListener('keyboardWillHide', keyboardWillHideHandler);
keyboardWillShowHandler = keyboardWillHideHandler = undefined;
};
const isKeyboardVisible = () => keyboardVisible;
await init();
return { init, destroy, isKeyboardVisible };
};
const handleFooterFade = (scrollEl, baseEl) => {
readTask(() => {
const scrollTop = scrollEl.scrollTop;
const maxScroll = scrollEl.scrollHeight - scrollEl.clientHeight;
/**
* Toolbar background will fade
* out over fadeDuration in pixels.
*/
const fadeDuration = 10;
/**
* Begin fading out maxScroll - 30px
* from the bottom of the content.
* Also determine how close we are
* to starting the fade. If we are
* before the starting point, the
* scale value will get clamped to 0.
* If we are after the maxScroll (rubber
* band scrolling), the scale value will
* get clamped to 1.
*/
const fadeStart = maxScroll - fadeDuration;
const distanceToStart = scrollTop - fadeStart;
const scale = clamp(0, 1 - distanceToStart / fadeDuration, 1);
writeTask(() => {
baseEl.style.setProperty('--opacity-scale', scale.toString());
});
});
};
const footerIosCss = "ion-footer{display:block;position:relative;-ms-flex-order:1;order:1;width:100%;z-index:10}ion-footer.footer-toolbar-padding ion-toolbar:last-of-type{padding-bottom:var(--ion-safe-area-bottom, 0)}.footer-ios ion-toolbar:first-of-type{--border-width:0.55px 0 0}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.footer-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.footer-translucent-ios ion-toolbar{--opacity:.8}}.footer-ios.ion-no-border ion-toolbar:first-of-type{--border-width:0}.footer-collapse-fade ion-toolbar{--opacity-scale:inherit}";
const footerMdCss = "ion-footer{display:block;position:relative;-ms-flex-order:1;order:1;width:100%;z-index:10}ion-footer.footer-toolbar-padding ion-toolbar:last-of-type{padding-bottom:var(--ion-safe-area-bottom, 0)}.footer-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.footer-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Footer {
constructor(hostRef) {
registerInstance(this, hostRef);
this.keyboardCtrl = null;
this.keyboardVisible = false;
/**
* If `true`, the footer will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*
* Note: In order to scroll content behind the footer, the `fullscreen`
* attribute needs to be set on the content.
*/
this.translucent = false;
this.checkCollapsibleFooter = () => {
const mode = getIonMode$1(this);
if (mode !== 'ios') {
return;
}
const { collapse } = this;
const hasFade = collapse === 'fade';
this.destroyCollapsibleFooter();
if (hasFade) {
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
const contentEl = pageEl ? findIonContent(pageEl) : null;
if (!contentEl) {
printIonContentErrorMsg(this.el);
return;
}
this.setupFadeFooter(contentEl);
}
};
this.setupFadeFooter = async (contentEl) => {
const scrollEl = (this.scrollEl = await getScrollElement(contentEl));
/**
* Handle fading of toolbars on scroll
*/
this.contentScrollCallback = () => {
handleFooterFade(scrollEl, this.el);
};
scrollEl.addEventListener('scroll', this.contentScrollCallback);
handleFooterFade(scrollEl, this.el);
};
}
componentDidLoad() {
this.checkCollapsibleFooter();
}
componentDidUpdate() {
this.checkCollapsibleFooter();
}
async connectedCallback() {
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
/**
* If the keyboard is hiding, then we need to wait
* for the webview to resize. Otherwise, the footer
* will flicker before the webview resizes.
*/
if (keyboardOpen === false && waitForResize !== undefined) {
await waitForResize;
}
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
});
}
disconnectedCallback() {
if (this.keyboardCtrl) {
this.keyboardCtrl.destroy();
}
}
destroyCollapsibleFooter() {
if (this.scrollEl && this.contentScrollCallback) {
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
this.contentScrollCallback = undefined;
}
}
render() {
const { translucent, collapse } = this;
const mode = getIonMode$1(this);
const tabs = this.el.closest('ion-tabs');
const tabBar = tabs === null || tabs === void 0 ? void 0 : tabs.querySelector(':scope > ion-tab-bar');
return (hAsync(Host, { key: 'ddc228f1a1e7fa4f707dccf74db2490ca3241137', role: "contentinfo", class: {
[mode]: true,
// Used internally for styling
[`footer-${mode}`]: true,
[`footer-translucent`]: translucent,
[`footer-translucent-${mode}`]: translucent,
['footer-toolbar-padding']: !this.keyboardVisible && (!tabBar || tabBar.slot !== 'bottom'),
[`footer-collapse-${collapse}`]: collapse !== undefined,
} }, mode === 'ios' && translucent && hAsync("div", { key: 'e16ed4963ff94e06de77eb8038201820af73937c', class: "footer-background" }), hAsync("slot", { key: 'f186934febf85d37133d9351a96c1a64b0a4b203' })));
}
get el() { return getElement(this); }
static get style() { return {
ios: footerIosCss,
md: footerMdCss
}; }
static get cmpMeta() { return {
"$flags$": 292,
"$tagName$": "ion-footer",
"$members$": {
"collapse": [1],
"translucent": [4],
"keyboardVisible": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const gridCss = ":host{-webkit-padding-start:var(--ion-grid-padding-xs, var(--ion-grid-padding, 5px));padding-inline-start:var(--ion-grid-padding-xs, var(--ion-grid-padding, 5px));-webkit-padding-end:var(--ion-grid-padding-xs, var(--ion-grid-padding, 5px));padding-inline-end:var(--ion-grid-padding-xs, var(--ion-grid-padding, 5px));padding-top:var(--ion-grid-padding-xs, var(--ion-grid-padding, 5px));padding-bottom:var(--ion-grid-padding-xs, var(--ion-grid-padding, 5px));-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;display:block;-ms-flex:1;flex:1}@media (min-width: 576px){:host{-webkit-padding-start:var(--ion-grid-padding-sm, var(--ion-grid-padding, 5px));padding-inline-start:var(--ion-grid-padding-sm, var(--ion-grid-padding, 5px));-webkit-padding-end:var(--ion-grid-padding-sm, var(--ion-grid-padding, 5px));padding-inline-end:var(--ion-grid-padding-sm, var(--ion-grid-padding, 5px));padding-top:var(--ion-grid-padding-sm, var(--ion-grid-padding, 5px));padding-bottom:var(--ion-grid-padding-sm, var(--ion-grid-padding, 5px))}}@media (min-width: 768px){:host{-webkit-padding-start:var(--ion-grid-padding-md, var(--ion-grid-padding, 5px));padding-inline-start:var(--ion-grid-padding-md, var(--ion-grid-padding, 5px));-webkit-padding-end:var(--ion-grid-padding-md, var(--ion-grid-padding, 5px));padding-inline-end:var(--ion-grid-padding-md, var(--ion-grid-padding, 5px));padding-top:var(--ion-grid-padding-md, var(--ion-grid-padding, 5px));padding-bottom:var(--ion-grid-padding-md, var(--ion-grid-padding, 5px))}}@media (min-width: 992px){:host{-webkit-padding-start:var(--ion-grid-padding-lg, var(--ion-grid-padding, 5px));padding-inline-start:var(--ion-grid-padding-lg, var(--ion-grid-padding, 5px));-webkit-padding-end:var(--ion-grid-padding-lg, var(--ion-grid-padding, 5px));padding-inline-end:var(--ion-grid-padding-lg, var(--ion-grid-padding, 5px));padding-top:var(--ion-grid-padding-lg, var(--ion-grid-padding, 5px));padding-bottom:var(--ion-grid-padding-lg, var(--ion-grid-padding, 5px))}}@media (min-width: 1200px){:host{-webkit-padding-start:var(--ion-grid-padding-xl, var(--ion-grid-padding, 5px));padding-inline-start:var(--ion-grid-padding-xl, var(--ion-grid-padding, 5px));-webkit-padding-end:var(--ion-grid-padding-xl, var(--ion-grid-padding, 5px));padding-inline-end:var(--ion-grid-padding-xl, var(--ion-grid-padding, 5px));padding-top:var(--ion-grid-padding-xl, var(--ion-grid-padding, 5px));padding-bottom:var(--ion-grid-padding-xl, var(--ion-grid-padding, 5px))}}:host(.grid-fixed){width:var(--ion-grid-width-xs, var(--ion-grid-width, 100%));max-width:100%}@media (min-width: 576px){:host(.grid-fixed){width:var(--ion-grid-width-sm, var(--ion-grid-width, 540px))}}@media (min-width: 768px){:host(.grid-fixed){width:var(--ion-grid-width-md, var(--ion-grid-width, 720px))}}@media (min-width: 992px){:host(.grid-fixed){width:var(--ion-grid-width-lg, var(--ion-grid-width, 960px))}}@media (min-width: 1200px){:host(.grid-fixed){width:var(--ion-grid-width-xl, var(--ion-grid-width, 1140px))}}:host(.ion-no-padding){--ion-grid-column-padding:0;--ion-grid-column-padding-xs:0;--ion-grid-column-padding-sm:0;--ion-grid-column-padding-md:0;--ion-grid-column-padding-lg:0;--ion-grid-column-padding-xl:0}";
class Grid {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the grid will have a fixed width based on the screen size.
*/
this.fixed = false;
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '617127ecfabf9bf615bef1dda1be3fed5a065949', class: {
[mode]: true,
'grid-fixed': this.fixed,
} }, hAsync("slot", { key: 'c781fff853b093d8f44bdb7943bbc4f17c903803' })));
}
static get style() { return gridCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-grid",
"$members$": {
"fixed": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const TRANSITION = 'all 0.2s ease-in-out';
const ROLE_NONE = 'none';
const ROLE_BANNER = 'banner';
const cloneElement = (tagName) => {
const getCachedEl = document.querySelector(`${tagName}.ion-cloned-element`);
if (getCachedEl !== null) {
return getCachedEl;
}
const clonedEl = document.createElement(tagName);
clonedEl.classList.add('ion-cloned-element');
clonedEl.style.setProperty('display', 'none');
document.body.appendChild(clonedEl);
return clonedEl;
};
const createHeaderIndex = (headerEl) => {
if (!headerEl) {
return;
}
const toolbars = headerEl.querySelectorAll('ion-toolbar');
return {
el: headerEl,
toolbars: Array.from(toolbars).map((toolbar) => {
const ionTitleEl = toolbar.querySelector('ion-title');
return {
el: toolbar,
background: toolbar.shadowRoot.querySelector('.toolbar-background'),
ionTitleEl,
innerTitleEl: ionTitleEl ? ionTitleEl.shadowRoot.querySelector('.toolbar-title') : null,
ionButtonsEl: Array.from(toolbar.querySelectorAll('ion-buttons')),
};
}),
};
};
const handleContentScroll = (scrollEl, scrollHeaderIndex, contentEl) => {
readTask(() => {
const scrollTop = scrollEl.scrollTop;
const scale = clamp(1, 1 + -scrollTop / 500, 1.1);
// Native refresher should not cause titles to scale
const nativeRefresher = contentEl.querySelector('ion-refresher.refresher-native');
if (nativeRefresher === null) {
writeTask(() => {
scaleLargeTitles(scrollHeaderIndex.toolbars, scale);
});
}
});
};
const setToolbarBackgroundOpacity = (headerEl, opacity) => {
/**
* Fading in the backdrop opacity
* should happen after the large title
* has collapsed, so it is handled
* by handleHeaderFade()
*/
if (headerEl.collapse === 'fade') {
return;
}
if (opacity === undefined) {
headerEl.style.removeProperty('--opacity-scale');
}
else {
headerEl.style.setProperty('--opacity-scale', opacity.toString());
}
};
const handleToolbarBorderIntersection = (ev, mainHeaderIndex, scrollTop) => {
if (!ev[0].isIntersecting) {
return;
}
/**
* There is a bug in Safari where overflow scrolling on a non-body element
* does not always reset the scrollTop position to 0 when letting go. It will
* set to 1 once the rubber band effect has ended. This causes the background to
* appear slightly on certain app setups.
*
* Additionally, we check if user is rubber banding (scrolling is negative)
* as this can mean they are using pull to refresh. Once the refresher starts,
* the content is transformed which can cause the intersection observer to erroneously
* fire here as well.
*/
const scale = ev[0].intersectionRatio > 0.9 || scrollTop <= 0 ? 0 : ((1 - ev[0].intersectionRatio) * 100) / 75;
setToolbarBackgroundOpacity(mainHeaderIndex.el, scale === 1 ? undefined : scale);
};
/**
* If toolbars are intersecting, hide the scrollable toolbar content
* and show the primary toolbar content. If the toolbars are not intersecting,
* hide the primary toolbar content and show the scrollable toolbar content
*/
const handleToolbarIntersection = (ev, // TODO(FW-2832): type (IntersectionObserverEntry[] triggers errors which should be sorted)
mainHeaderIndex, scrollHeaderIndex, scrollEl) => {
writeTask(() => {
const scrollTop = scrollEl.scrollTop;
handleToolbarBorderIntersection(ev, mainHeaderIndex, scrollTop);
const event = ev[0];
const intersection = event.intersectionRect;
const intersectionArea = intersection.width * intersection.height;
const rootArea = event.rootBounds.width * event.rootBounds.height;
const isPageHidden = intersectionArea === 0 && rootArea === 0;
const leftDiff = Math.abs(intersection.left - event.boundingClientRect.left);
const rightDiff = Math.abs(intersection.right - event.boundingClientRect.right);
const isPageTransitioning = intersectionArea > 0 && (leftDiff >= 5 || rightDiff >= 5);
if (isPageHidden || isPageTransitioning) {
return;
}
if (event.isIntersecting) {
setHeaderActive(mainHeaderIndex, false);
setHeaderActive(scrollHeaderIndex);
}
else {
/**
* There is a bug with IntersectionObserver on Safari
* where `event.isIntersecting === false` when cancelling
* a swipe to go back gesture. Checking the intersection
* x, y, width, and height provides a workaround. This bug
* does not happen when using Safari + Web Animations,
* only Safari + CSS Animations.
*/
const hasValidIntersection = (intersection.x === 0 && intersection.y === 0) || (intersection.width !== 0 && intersection.height !== 0);
if (hasValidIntersection && scrollTop > 0) {
setHeaderActive(mainHeaderIndex);
setHeaderActive(scrollHeaderIndex, false);
setToolbarBackgroundOpacity(mainHeaderIndex.el);
}
}
});
};
const setHeaderActive = (headerIndex, active = true) => {
const headerEl = headerIndex.el;
const toolbars = headerIndex.toolbars;
const ionTitles = toolbars.map((toolbar) => toolbar.ionTitleEl);
if (active) {
headerEl.setAttribute('role', ROLE_BANNER);
headerEl.classList.remove('header-collapse-condense-inactive');
ionTitles.forEach((ionTitle) => {
if (ionTitle) {
ionTitle.removeAttribute('aria-hidden');
}
});
}
else {
/**
* There can only be one banner landmark per page.
* By default, all ion-headers have the banner role.
* This causes an accessibility issue when using a
* condensed header since there are two ion-headers
* on the page at once (active and inactive).
* To solve this, the role needs to be toggled
* based on which header is active.
*/
headerEl.setAttribute('role', ROLE_NONE);
headerEl.classList.add('header-collapse-condense-inactive');
/**
* The small title should only be accessed by screen readers
* when the large title collapses into the small title due
* to scrolling.
*
* Originally, the header was given `aria-hidden="true"`
* but this caused issues with screen readers not being
* able to access any focusable elements within the header.
*/
ionTitles.forEach((ionTitle) => {
if (ionTitle) {
ionTitle.setAttribute('aria-hidden', 'true');
}
});
}
};
const scaleLargeTitles = (toolbars = [], scale = 1, transition = false) => {
toolbars.forEach((toolbar) => {
const ionTitle = toolbar.ionTitleEl;
const titleDiv = toolbar.innerTitleEl;
if (!ionTitle || ionTitle.size !== 'large') {
return;
}
titleDiv.style.transition = transition ? TRANSITION : '';
titleDiv.style.transform = `scale3d(${scale}, ${scale}, 1)`;
});
};
const handleHeaderFade = (scrollEl, baseEl, condenseHeader) => {
readTask(() => {
const scrollTop = scrollEl.scrollTop;
const baseElHeight = baseEl.clientHeight;
const fadeStart = condenseHeader ? condenseHeader.clientHeight : 0;
/**
* If we are using fade header with a condense
* header, then the toolbar backgrounds should
* not begin to fade in until the condense
* header has fully collapsed.
*
* Additionally, the main content should not
* overflow out of the container until the
* condense header has fully collapsed. When
* using just the condense header the content
* should overflow out of the container.
*/
if (condenseHeader !== null && scrollTop < fadeStart) {
baseEl.style.setProperty('--opacity-scale', '0');
scrollEl.style.setProperty('clip-path', `inset(${baseElHeight}px 0px 0px 0px)`);
return;
}
const distanceToStart = scrollTop - fadeStart;
const fadeDuration = 10;
const scale = clamp(0, distanceToStart / fadeDuration, 1);
writeTask(() => {
scrollEl.style.removeProperty('clip-path');
baseEl.style.setProperty('--opacity-scale', scale.toString());
});
});
};
/**
* Get the role type for the ion-header.
*
* @param isInsideMenu If ion-header is inside ion-menu.
* @param isCondensed If ion-header has collapse="condense".
* @param mode The current mode.
* @returns 'none' if inside ion-menu or if condensed in md
* mode, otherwise 'banner'.
*/
const getRoleType = (isInsideMenu, isCondensed, mode) => {
// If the header is inside a menu, it should not have the banner role.
if (isInsideMenu) {
return ROLE_NONE;
}
/**
* Only apply role="none" to `md` mode condensed headers
* since the large header is never shown.
*/
if (isCondensed && mode === 'md') {
return ROLE_NONE;
}
// Default to banner role.
return ROLE_BANNER;
};
const headerIosCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-ios ion-toolbar:last-of-type{--border-width:0 0 0.55px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.header-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}.header-translucent-ios ion-toolbar{--opacity:.8}.header-collapse-condense-inactive .header-background{-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px)}}.header-ios.ion-no-border ion-toolbar:last-of-type{--border-width:0}.header-collapse-fade ion-toolbar{--opacity-scale:inherit}.header-collapse-fade.header-transitioning ion-toolbar{--background:transparent;--border-style:none}.header-collapse-condense{z-index:9}.header-collapse-condense ion-toolbar{position:-webkit-sticky;position:sticky;top:0}.header-collapse-condense ion-toolbar:first-of-type{padding-top:0px;z-index:1}.header-collapse-condense ion-toolbar{z-index:0}.header-collapse-condense ion-toolbar:last-of-type{--border-width:0px}.header-collapse-condense ion-toolbar ion-searchbar{padding-top:0px;padding-bottom:13px}.header-collapse-main{--opacity-scale:1}.header-collapse-main ion-toolbar{--opacity-scale:inherit}.header-collapse-main ion-toolbar.in-toolbar ion-title,.header-collapse-main ion-toolbar.in-toolbar ion-buttons{-webkit-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out}.header-collapse-condense ion-toolbar,.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--background:var(--ion-background-color, #fff)}.header-collapse-condense-inactive.header-transitioning:not(.header-collapse-condense) ion-toolbar{--border-style:none;--opacity-scale:1}.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-buttons.buttons-collapse{opacity:0;pointer-events:none}.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-title,.header-collapse-condense-inactive.header-collapse-condense ion-toolbar.in-toolbar ion-buttons.buttons-collapse{visibility:hidden}ion-header.header-ios:not(.header-collapse-main):has(~ion-content ion-header.header-ios[collapse=condense],~ion-content ion-header.header-ios.header-collapse-condense){opacity:0}";
const headerMdCss = "ion-header{display:block;position:relative;-ms-flex-order:-1;order:-1;width:100%;z-index:10}ion-header ion-toolbar:first-of-type{padding-top:var(--ion-safe-area-top, 0)}.header-md{-webkit-box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);box-shadow:0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12)}.header-collapse-condense{display:none}.header-md.ion-no-border{-webkit-box-shadow:none;box-shadow:none}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Header {
constructor(hostRef) {
registerInstance(this, hostRef);
this.inheritedAttributes = {};
/**
* If `true`, the header will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*
* Note: In order to scroll content behind the header, the `fullscreen`
* attribute needs to be set on the content.
*/
this.translucent = false;
this.setupFadeHeader = async (contentEl, condenseHeader) => {
const scrollEl = (this.scrollEl = await getScrollElement(contentEl));
/**
* Handle fading of toolbars on scroll
*/
this.contentScrollCallback = () => {
handleHeaderFade(this.scrollEl, this.el, condenseHeader);
};
scrollEl.addEventListener('scroll', this.contentScrollCallback);
handleHeaderFade(this.scrollEl, this.el, condenseHeader);
};
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
componentDidLoad() {
this.checkCollapsibleHeader();
}
componentDidUpdate() {
this.checkCollapsibleHeader();
}
disconnectedCallback() {
this.destroyCollapsibleHeader();
}
async checkCollapsibleHeader() {
const mode = getIonMode$1(this);
if (mode !== 'ios') {
return;
}
const { collapse } = this;
const hasCondense = collapse === 'condense';
const hasFade = collapse === 'fade';
this.destroyCollapsibleHeader();
if (hasCondense) {
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
const contentEl = pageEl ? findIonContent(pageEl) : null;
// Cloned elements are always needed in iOS transition
writeTask(() => {
const title = cloneElement('ion-title');
title.size = 'large';
cloneElement('ion-back-button');
});
await this.setupCondenseHeader(contentEl, pageEl);
}
else if (hasFade) {
const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
const contentEl = pageEl ? findIonContent(pageEl) : null;
if (!contentEl) {
printIonContentErrorMsg(this.el);
return;
}
const condenseHeader = contentEl.querySelector('ion-header[collapse="condense"]');
await this.setupFadeHeader(contentEl, condenseHeader);
}
}
destroyCollapsibleHeader() {
if (this.intersectionObserver) {
this.intersectionObserver.disconnect();
this.intersectionObserver = undefined;
}
if (this.scrollEl && this.contentScrollCallback) {
this.scrollEl.removeEventListener('scroll', this.contentScrollCallback);
this.contentScrollCallback = undefined;
}
if (this.collapsibleMainHeader) {
this.collapsibleMainHeader.classList.remove('header-collapse-main');
this.collapsibleMainHeader = undefined;
}
}
async setupCondenseHeader(contentEl, pageEl) {
if (!contentEl || !pageEl) {
printIonContentErrorMsg(this.el);
return;
}
if (typeof IntersectionObserver === 'undefined') {
return;
}
this.scrollEl = await getScrollElement(contentEl);
const headers = pageEl.querySelectorAll('ion-header');
this.collapsibleMainHeader = Array.from(headers).find((header) => header.collapse !== 'condense');
if (!this.collapsibleMainHeader) {
return;
}
const mainHeaderIndex = createHeaderIndex(this.collapsibleMainHeader);
const scrollHeaderIndex = createHeaderIndex(this.el);
if (!mainHeaderIndex || !scrollHeaderIndex) {
return;
}
setHeaderActive(mainHeaderIndex, false);
setToolbarBackgroundOpacity(mainHeaderIndex.el, 0);
/**
* Handle interaction between toolbar collapse and
* showing/hiding content in the primary ion-header
* as well as progressively showing/hiding the main header
* border as the top-most toolbar collapses or expands.
*/
const toolbarIntersection = (ev) => {
handleToolbarIntersection(ev, mainHeaderIndex, scrollHeaderIndex, this.scrollEl);
};
this.intersectionObserver = new IntersectionObserver(toolbarIntersection, {
root: contentEl,
threshold: [0.25, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1],
});
this.intersectionObserver.observe(scrollHeaderIndex.toolbars[scrollHeaderIndex.toolbars.length - 1].el);
/**
* Handle scaling of large iOS titles and
* showing/hiding border on last toolbar
* in primary header
*/
this.contentScrollCallback = () => {
handleContentScroll(this.scrollEl, scrollHeaderIndex, contentEl);
};
this.scrollEl.addEventListener('scroll', this.contentScrollCallback);
writeTask(() => {
if (this.collapsibleMainHeader !== undefined) {
this.collapsibleMainHeader.classList.add('header-collapse-main');
}
});
}
render() {
const { translucent, inheritedAttributes } = this;
const mode = getIonMode$1(this);
const collapse = this.collapse || 'none';
const isCondensed = collapse === 'condense';
// banner role must be at top level, so remove role if inside a menu
const roleType = getRoleType(hostContext('ion-menu', this.el), isCondensed, mode);
return (hAsync(Host, Object.assign({ key: '863c4568cd7b8c0ec55109f193bbbaed68a1346e', role: roleType, class: {
[mode]: true,
// Used internally for styling
[`header-${mode}`]: true,
[`header-translucent`]: this.translucent,
[`header-collapse-${collapse}`]: true,
[`header-translucent-${mode}`]: this.translucent,
} }, inheritedAttributes), mode === 'ios' && translucent && hAsync("div", { key: '25c3bdce328b0b35607d154c8b8374679313d881', class: "header-background" }), hAsync("slot", { key: 'b44fab0a9be7920b9650da26117c783e751e1702' })));
}
get el() { return getElement(this); }
static get style() { return {
ios: headerIosCss,
md: headerMdCss
}; }
static get cmpMeta() { return {
"$flags$": 292,
"$tagName$": "ion-header",
"$members$": {
"collapse": [1],
"translucent": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const getName = (iconName, icon, mode, ios, md) => {
// default to "md" if somehow the mode wasn't set
mode = (mode && toLower(mode)) === 'ios' ? 'ios' : 'md';
// if an icon was passed in using the ios or md attributes
// set the iconName to whatever was passed in
if (ios && mode === 'ios') {
iconName = toLower(ios);
}
else if (md && mode === 'md') {
iconName = toLower(md);
}
else {
if (!iconName && icon && !isSrc(icon)) {
iconName = icon;
}
if (isStr(iconName)) {
iconName = toLower(iconName);
}
}
if (!isStr(iconName) || iconName.trim() === '') {
return null;
}
// only allow alpha characters and dash
const invalidChars = iconName.replace(/[a-z]|-|\d/gi, '');
if (invalidChars !== '') {
return null;
}
return iconName;
};
const isSrc = (str) => str.length > 0 && /(\/|\.)/.test(str);
const isStr = (val) => typeof val === 'string';
const toLower = (val) => val.toLowerCase();
/**
* Elements inside of web components sometimes need to inherit global attributes
* set on the host. For example, the inner input in `ion-input` should inherit
* the `title` attribute that developers set directly on `ion-input`. This
* helper function should be called in componentWillLoad and assigned to a variable
* that is later used in the render function.
*
* This does not need to be reactive as changing attributes on the host element
* does not trigger a re-render.
*/
const inheritAttributes = (el, attributes = []) => {
const attributeObject = {};
attributes.forEach((attr) => {
if (el.hasAttribute(attr)) {
const value = el.getAttribute(attr);
if (value !== null) {
attributeObject[attr] = el.getAttribute(attr);
}
el.removeAttribute(attr);
}
});
return attributeObject;
};
/**
* Returns `true` if the document or host element
* has a `dir` set to `rtl`. The host value will always
* take priority over the root document value.
*/
const isRTL = (hostEl) => {
if (hostEl) {
if (hostEl.dir !== '') {
return hostEl.dir.toLowerCase() === 'rtl';
}
}
return (document === null || document === void 0 ? void 0 : document.dir.toLowerCase()) === 'rtl';
};
const iconCss = ":host{display:inline-block;width:1em;height:1em;contain:strict;fill:currentColor;-webkit-box-sizing:content-box !important;box-sizing:content-box !important}:host .ionicon{stroke:currentColor}.ionicon-fill-none{fill:none}.ionicon-stroke-width{stroke-width:var(--ionicon-stroke-width, 32px)}.icon-inner,.ionicon,svg{display:block;height:100%;width:100%}@supports (background: -webkit-named-image(i)){:host(.icon-rtl) .icon-inner{-webkit-transform:scaleX(-1);transform:scaleX(-1)}}@supports not selector(:dir(rtl)) and selector(:host-context([dir='rtl'])){:host(.icon-rtl) .icon-inner{-webkit-transform:scaleX(-1);transform:scaleX(-1)}}:host(.flip-rtl):host-context([dir='rtl']) .icon-inner{-webkit-transform:scaleX(-1);transform:scaleX(-1)}@supports selector(:dir(rtl)){:host(.flip-rtl:dir(rtl)) .icon-inner{-webkit-transform:scaleX(-1);transform:scaleX(-1)}:host(.flip-rtl:dir(ltr)) .icon-inner{-webkit-transform:scaleX(1);transform:scaleX(1)}}:host(.icon-small){font-size:1.125rem !important}:host(.icon-large){font-size:2rem !important}:host(.ion-color){color:var(--ion-color-base) !important}:host(.ion-color-primary){--ion-color-base:var(--ion-color-primary, #3880ff)}:host(.ion-color-secondary){--ion-color-base:var(--ion-color-secondary, #0cd1e8)}:host(.ion-color-tertiary){--ion-color-base:var(--ion-color-tertiary, #f4a942)}:host(.ion-color-success){--ion-color-base:var(--ion-color-success, #10dc60)}:host(.ion-color-warning){--ion-color-base:var(--ion-color-warning, #ffce00)}:host(.ion-color-danger){--ion-color-base:var(--ion-color-danger, #f14141)}:host(.ion-color-light){--ion-color-base:var(--ion-color-light, #f4f5f8)}:host(.ion-color-medium){--ion-color-base:var(--ion-color-medium, #989aa2)}:host(.ion-color-dark){--ion-color-base:var(--ion-color-dark, #222428)}";
class Icon {
constructor(hostRef) {
registerInstance(this, hostRef);
this.iconName = null;
this.inheritedAttributes = {};
this.didLoadIcon = false;
this.isVisible = false;
/**
* The mode determines which platform styles to use.
*/
this.mode = getIonMode();
/**
* If enabled, ion-icon will be loaded lazily when it's visible in the viewport.
* Default, `false`.
*/
this.lazy = false;
/**
* When set to `false`, SVG content that is HTTP fetched will not be checked
* if the response SVG content has any `<script>` elements, or any attributes
* that start with `on`, such as `onclick`.
* @default true
*/
this.sanitize = true;
}
componentWillLoad() {
this.inheritedAttributes = inheritAttributes(this.el, ['aria-label']);
}
connectedCallback() {
/**
* purposely do not return the promise here because loading
* the svg file should not hold up loading the app
* only load the svg if it's visible
*/
this.waitUntilVisible(this.el, '50px', () => {
this.isVisible = true;
this.loadIcon();
});
}
/**
* Loads the icon after the component has finished rendering.
*/
componentDidLoad() {
/**
* Addresses an Angular issue where property values are assigned after the 'connectedCallback' but prior to the registration of watchers.
* This enhancement ensures the loading of an icon when the component has finished rendering and the icon has yet to apply the SVG data.
* This modification pertains to the usage of Angular's binding syntax:
* `<ion-icon [name]="myIconName"></ion-icon>`
*/
if (!this.didLoadIcon) {
this.loadIcon();
}
}
/**
* Disconnect the IntersectionObserver.
*/
disconnectedCallback() {
if (this.io) {
this.io.disconnect();
this.io = undefined;
}
}
/**
* Wait until the icon is visible in the viewport.
* @param el - The element to observe.
* @param rootMargin - The root margin of the observer.
* @param cb - The callback to call when the element is visible.
*/
waitUntilVisible(el, rootMargin, cb) {
/**
* IntersectionObserver is a browser API that allows you to observe
* the visibility of an element relative to a root element. It is
* supported in all modern browsers, except IE and when server-side
* rendering.
*/
const hasIntersectionObserverSupport = Boolean(Build.isBrowser);
/**
* browser doesn't support IntersectionObserver
* so just fallback to always show it
*/
if (!hasIntersectionObserverSupport) {
return cb();
}
const io = (this.io = new window.IntersectionObserver((data) => {
if (data[0].isIntersecting) {
io.disconnect();
this.io = undefined;
cb();
}
}, { rootMargin }));
io.observe(el);
}
/**
* Watch for changes to the icon name, src, icon, ios, or md properties.
* When a change is detected, the icon will be loaded.
*/
loadIcon() {
this.iconName = getName(this.name, this.icon, this.mode, this.ios, this.md);
}
render() {
const { flipRtl, iconName, inheritedAttributes, el } = this;
const mode = this.mode || 'md';
/**
* we have designated that arrows & chevrons should automatically flip (unless flip-rtl
* is set to false) because "back" is left in ltr and right in rtl, and "forward" is the opposite
*/
const shouldAutoFlip = iconName
? (iconName.includes('arrow') || iconName.includes('chevron')) && flipRtl !== false
: false;
/**
* if shouldBeFlippable is true, the icon should change direction when `dir` changes
*/
const shouldBeFlippable = flipRtl || shouldAutoFlip;
return (hAsync(Host, Object.assign({ key: '0578c899781ca145dd8205acd9670af39b57cf2e', role: "img", class: Object.assign(Object.assign({ [mode]: true }, createColorClasses(this.color)), { [`icon-${this.size}`]: !!this.size, 'flip-rtl': shouldBeFlippable, 'icon-rtl': shouldBeFlippable && isRTL(el) }) }, inheritedAttributes), (hAsync("div", { class: "icon-inner" }))));
}
static get assetsDirs() { return ["svg"]; }
get el() { return getElement(this); }
static get watchers() { return {
"name": ["loadIcon"],
"src": ["loadIcon"],
"icon": ["loadIcon"],
"ios": ["loadIcon"],
"md": ["loadIcon"]
}; }
static get style() { return iconCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-icon",
"$members$": {
"mode": [1025],
"color": [1],
"ios": [1],
"md": [1],
"flipRtl": [4, "flip-rtl"],
"name": [513],
"src": [1],
"icon": [8],
"size": [1],
"lazy": [4],
"sanitize": [4],
"svgContent": [32],
"isVisible": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["name", "name"]]
}; }
}
/**
* Get the mode of the document.
* @returns The mode of the document.
*/
const getIonMode = () => 'md';
/**
* Create color classes for the icon.
* @param color - The color of the icon.
* @returns The color classes for the icon.
*/
const createColorClasses = (color) => {
return color
? {
'ion-color': true,
[`ion-color-${color}`]: true,
}
: null;
};
const imgCss = ":host{display:block;-o-object-fit:contain;object-fit:contain}img{display:block;width:100%;height:100%;-o-object-fit:inherit;object-fit:inherit;-o-object-position:inherit;object-position:inherit}";
/**
* @part image - The inner `img` element.
*/
class Img {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionImgWillLoad = createEvent(this, "ionImgWillLoad", 7);
this.ionImgDidLoad = createEvent(this, "ionImgDidLoad", 7);
this.ionError = createEvent(this, "ionError", 7);
this.inheritedAttributes = {};
this.onLoad = () => {
this.ionImgDidLoad.emit();
};
this.onError = () => {
this.ionError.emit();
};
}
srcChanged() {
this.addIO();
}
componentWillLoad() {
this.inheritedAttributes = inheritAttributes$1(this.el, ['draggable']);
}
componentDidLoad() {
this.addIO();
}
addIO() {
if (this.src === undefined) {
return;
}
if (typeof window !== 'undefined' &&
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'isIntersecting' in window.IntersectionObserverEntry.prototype) {
this.removeIO();
this.io = new IntersectionObserver((data) => {
/**
* On slower devices, it is possible for an intersection observer entry to contain multiple
* objects in the array. This happens when quickly scrolling an image into view and then out of
* view. In this case, the last object represents the current state of the component.
*/
if (data[data.length - 1].isIntersecting) {
this.load();
this.removeIO();
}
});
this.io.observe(this.el);
}
else {
// fall back to setTimeout for Safari and IE
setTimeout(() => this.load(), 200);
}
}
load() {
this.loadError = this.onError;
this.loadSrc = this.src;
this.ionImgWillLoad.emit();
}
removeIO() {
if (this.io) {
this.io.disconnect();
this.io = undefined;
}
}
render() {
const { loadSrc, alt, onLoad, loadError, inheritedAttributes } = this;
const { draggable } = inheritedAttributes;
return (hAsync(Host, { key: 'da600442894427dee1974a28e545613afac69fca', class: getIonMode$1(this) }, hAsync("img", { key: '16df0c7069af86c0fa7ce5af598bc0f63b4eb71a', decoding: "async", src: loadSrc, alt: alt, onLoad: onLoad, onError: loadError, part: "image", draggable: isDraggable(draggable) })));
}
get el() { return getElement(this); }
static get watchers() { return {
"src": ["srcChanged"]
}; }
static get style() { return imgCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-img",
"$members$": {
"alt": [1],
"src": [1],
"loadSrc": [32],
"loadError": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
/**
* Enumerated strings must be set as booleans
* as Stencil will not render 'false' in the DOM.
* The need to explicitly render draggable="true"
* as only certain elements are draggable by default.
* https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/draggable.
*/
const isDraggable = (draggable) => {
switch (draggable) {
case 'true':
return true;
case 'false':
return false;
default:
return undefined;
}
};
const infiniteScrollCss = "ion-infinite-scroll{display:none;width:100%}.infinite-scroll-enabled{display:block}";
class InfiniteScroll {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionInfinite = createEvent(this, "ionInfinite", 7);
this.thrPx = 0;
this.thrPc = 0;
/**
* didFire exists so that ionInfinite
* does not fire multiple times if
* users continue to scroll after
* scrolling into the infinite
* scroll threshold.
*/
this.didFire = false;
this.isBusy = false;
this.isLoading = false;
/**
* The threshold distance from the bottom
* of the content to call the `infinite` output event when scrolled.
* The threshold value can be either a percent, or
* in pixels. For example, use the value of `10%` for the `infinite`
* output event to get called when the user has scrolled 10%
* from the bottom of the page. Use the value `100px` when the
* scroll is within 100 pixels from the bottom of the page.
*/
this.threshold = '15%';
/**
* If `true`, the infinite scroll will be hidden and scroll event listeners
* will be removed.
*
* Set this to true to disable the infinite scroll from actively
* trying to receive new data while scrolling. This is useful
* when it is known that there is no more data that can be added, and
* the infinite scroll is no longer needed.
*/
this.disabled = false;
/**
* The position of the infinite scroll element.
* The value can be either `top` or `bottom`.
*/
this.position = 'bottom';
this.onScroll = () => {
const scrollEl = this.scrollEl;
if (!scrollEl || !this.canStart()) {
return 1;
}
const infiniteHeight = this.el.offsetHeight;
if (infiniteHeight === 0) {
// if there is no height of this element then do nothing
return 2;
}
const scrollTop = scrollEl.scrollTop;
const scrollHeight = scrollEl.scrollHeight;
const height = scrollEl.offsetHeight;
const threshold = this.thrPc !== 0 ? height * this.thrPc : this.thrPx;
const distanceFromInfinite = this.position === 'bottom'
? scrollHeight - infiniteHeight - scrollTop - threshold - height
: scrollTop - infiniteHeight - threshold;
if (distanceFromInfinite < 0) {
if (!this.didFire) {
this.isLoading = true;
this.didFire = true;
this.ionInfinite.emit();
return 3;
}
}
return 4;
};
}
thresholdChanged() {
const val = this.threshold;
if (val.lastIndexOf('%') > -1) {
this.thrPx = 0;
this.thrPc = parseFloat(val) / 100;
}
else {
this.thrPx = parseFloat(val);
this.thrPc = 0;
}
}
disabledChanged() {
const disabled = this.disabled;
if (disabled) {
this.isLoading = false;
this.isBusy = false;
}
this.enableScrollEvents(!disabled);
}
async connectedCallback() {
const contentEl = findClosestIonContent(this.el);
if (!contentEl) {
printIonContentErrorMsg(this.el);
return;
}
this.scrollEl = await getScrollElement(contentEl);
this.thresholdChanged();
this.disabledChanged();
if (this.position === 'top') {
writeTask(() => {
if (this.scrollEl) {
this.scrollEl.scrollTop = this.scrollEl.scrollHeight - this.scrollEl.clientHeight;
}
});
}
}
disconnectedCallback() {
this.enableScrollEvents(false);
this.scrollEl = undefined;
}
/**
* Call `complete()` within the `ionInfinite` output event handler when
* your async operation has completed. For example, the `loading`
* state is while the app is performing an asynchronous operation,
* such as receiving more data from an AJAX request to add more items
* to a data list. Once the data has been received and UI updated, you
* then call this method to signify that the loading has completed.
* This method will change the infinite scroll's state from `loading`
* to `enabled`.
*/
async complete() {
const scrollEl = this.scrollEl;
if (!this.isLoading || !scrollEl) {
return;
}
this.isLoading = false;
if (this.position === 'top') {
/**
* New content is being added at the top, but the scrollTop position stays the same,
* which causes a scroll jump visually. This algorithm makes sure to prevent this.
* (Frame 1)
* - complete() is called, but the UI hasn't had time to update yet.
* - Save the current content dimensions.
* - Wait for the next frame using _dom.read, so the UI will be updated.
* (Frame 2)
* - Read the new content dimensions.
* - Calculate the height difference and the new scroll position.
* - Delay the scroll position change until other possible dom reads are done using _dom.write to be performant.
* (Still frame 2, if I'm correct)
* - Change the scroll position (= visually maintain the scroll position).
* - Change the state to re-enable the InfiniteScroll.
* - This should be after changing the scroll position, or it could
* cause the InfiniteScroll to be triggered again immediately.
* (Frame 3)
* Done.
*/
this.isBusy = true;
// ******** DOM READ ****************
// Save the current content dimensions before the UI updates
const prev = scrollEl.scrollHeight - scrollEl.scrollTop;
// ******** DOM READ ****************
requestAnimationFrame(() => {
readTask(() => {
// UI has updated, save the new content dimensions
const scrollHeight = scrollEl.scrollHeight;
// New content was added on top, so the scroll position should be changed immediately to prevent it from jumping around
const newScrollTop = scrollHeight - prev;
// ******** DOM WRITE ****************
requestAnimationFrame(() => {
writeTask(() => {
scrollEl.scrollTop = newScrollTop;
this.isBusy = false;
this.didFire = false;
});
});
});
});
}
else {
this.didFire = false;
}
}
canStart() {
return !this.disabled && !this.isBusy && !!this.scrollEl && !this.isLoading;
}
enableScrollEvents(shouldListen) {
if (this.scrollEl) {
if (shouldListen) {
this.scrollEl.addEventListener('scroll', this.onScroll);
}
else {
this.scrollEl.removeEventListener('scroll', this.onScroll);
}
}
}
render() {
const mode = getIonMode$1(this);
const disabled = this.disabled;
return (hAsync(Host, { key: 'e844956795f69be33396ce4480aa7a54ad01b28c', class: {
[mode]: true,
'infinite-scroll-loading': this.isLoading,
'infinite-scroll-enabled': !disabled,
} }));
}
get el() { return getElement(this); }
static get watchers() { return {
"threshold": ["thresholdChanged"],
"disabled": ["disabledChanged"]
}; }
static get style() { return infiniteScrollCss; }
static get cmpMeta() { return {
"$flags$": 256,
"$tagName$": "ion-infinite-scroll",
"$members$": {
"threshold": [1],
"disabled": [4],
"position": [1],
"isLoading": [32],
"complete": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const infiniteScrollContentIosCss = "ion-infinite-scroll-content{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;min-height:84px;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.infinite-loading{margin-left:0;margin-right:0;margin-top:0;margin-bottom:32px;display:none;width:100%}.infinite-loading-text{-webkit-margin-start:32px;margin-inline-start:32px;-webkit-margin-end:32px;margin-inline-end:32px;margin-top:4px;margin-bottom:0}.infinite-scroll-loading ion-infinite-scroll-content>.infinite-loading{display:block}.infinite-scroll-content-ios .infinite-loading-text{color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}.infinite-scroll-content-ios .infinite-loading-spinner .spinner-lines-ios line,.infinite-scroll-content-ios .infinite-loading-spinner .spinner-lines-small-ios line,.infinite-scroll-content-ios .infinite-loading-spinner .spinner-crescent circle{stroke:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}.infinite-scroll-content-ios .infinite-loading-spinner .spinner-bubbles circle,.infinite-scroll-content-ios .infinite-loading-spinner .spinner-circles circle,.infinite-scroll-content-ios .infinite-loading-spinner .spinner-dots circle{fill:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}";
const infiniteScrollContentMdCss = "ion-infinite-scroll-content{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;min-height:84px;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.infinite-loading{margin-left:0;margin-right:0;margin-top:0;margin-bottom:32px;display:none;width:100%}.infinite-loading-text{-webkit-margin-start:32px;margin-inline-start:32px;-webkit-margin-end:32px;margin-inline-end:32px;margin-top:4px;margin-bottom:0}.infinite-scroll-loading ion-infinite-scroll-content>.infinite-loading{display:block}.infinite-scroll-content-md .infinite-loading-text{color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}.infinite-scroll-content-md .infinite-loading-spinner .spinner-lines-md line,.infinite-scroll-content-md .infinite-loading-spinner .spinner-lines-small-md line,.infinite-scroll-content-md .infinite-loading-spinner .spinner-crescent circle{stroke:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}.infinite-scroll-content-md .infinite-loading-spinner .spinner-bubbles circle,.infinite-scroll-content-md .infinite-loading-spinner .spinner-circles circle,.infinite-scroll-content-md .infinite-loading-spinner .spinner-dots circle{fill:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}";
class InfiniteScrollContent {
constructor(hostRef) {
registerInstance(this, hostRef);
this.customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
}
componentDidLoad() {
if (this.loadingSpinner === undefined) {
const mode = getIonMode$1(this);
this.loadingSpinner = config.get('infiniteLoadingSpinner', config.get('spinner', mode === 'ios' ? 'lines' : 'crescent'));
}
}
renderLoadingText() {
const { customHTMLEnabled, loadingText } = this;
if (customHTMLEnabled) {
return hAsync("div", { class: "infinite-loading-text", innerHTML: sanitizeDOMString(loadingText) });
}
return hAsync("div", { class: "infinite-loading-text" }, this.loadingText);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '7c16060dcfe2a0b0fb3e2f8f4c449589a76f1baa', class: {
[mode]: true,
// Used internally for styling
[`infinite-scroll-content-${mode}`]: true,
} }, hAsync("div", { key: 'a94f4d8746e053dc718f97520bd7e48cb316443a', class: "infinite-loading" }, this.loadingSpinner && (hAsync("div", { key: '10143d5d2a50a2a2bc5de1cee8e7ab51263bcf23', class: "infinite-loading-spinner" }, hAsync("ion-spinner", { key: '8846e88191690d9c61a0b462889ed56fbfed8b0d', name: this.loadingSpinner }))), this.loadingText !== undefined && this.renderLoadingText())));
}
static get style() { return {
ios: infiniteScrollContentIosCss,
md: infiniteScrollContentMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-infinite-scroll-content",
"$members$": {
"loadingSpinner": [1025, "loading-spinner"],
"loadingText": [1, "loading-text"]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
/**
* A utility to calculate the size of an outline notch
* width relative to the content passed. This is used in
* components such as `ion-select` with `fill="outline"`
* where we need to pass slotted HTML content. This is not
* needed when rendering plaintext content because we can
* render the plaintext again hidden with `opacity: 0` inside
* of the notch. As a result we can rely on the intrinsic size
* of the element to correctly compute the notch width. We
* cannot do this with slotted content because we cannot project
* it into 2 places at once.
*
* @internal
* @param el: The host element
* @param getNotchSpacerEl: A function that returns a reference to the notch spacer element inside of the component template.
* @param getLabelSlot: A function that returns a reference to the slotted content.
*/
const createNotchController = (el, getNotchSpacerEl, getLabelSlot) => {
let notchVisibilityIO;
const needsExplicitNotchWidth = () => {
const notchSpacerEl = getNotchSpacerEl();
if (
/**
* If the notch is not being used
* then we do not need to set the notch width.
*/
notchSpacerEl === undefined ||
/**
* If either the label property is being
* used or the label slot is not defined,
* then we do not need to estimate the notch width.
*/
el.label !== undefined ||
getLabelSlot() === null) {
return false;
}
return true;
};
const calculateNotchWidth = () => {
if (needsExplicitNotchWidth()) {
/**
* Run this the frame after
* the browser has re-painted the host element.
* Otherwise, the label element may have a width
* of 0 and the IntersectionObserver will be used.
*/
raf(() => {
setNotchWidth();
});
}
};
/**
* When using a label prop we can render
* the label value inside of the notch and
* let the browser calculate the size of the notch.
* However, we cannot render the label slot in multiple
* places so we need to manually calculate the notch dimension
* based on the size of the slotted content.
*
* This function should only be used to set the notch width
* on slotted label content. The notch width for label prop
* content is automatically calculated based on the
* intrinsic size of the label text.
*/
const setNotchWidth = () => {
const notchSpacerEl = getNotchSpacerEl();
if (notchSpacerEl === undefined) {
return;
}
if (!needsExplicitNotchWidth()) {
notchSpacerEl.style.removeProperty('width');
return;
}
const width = getLabelSlot().scrollWidth;
if (
/**
* If the computed width of the label is 0
* and notchSpacerEl's offsetParent is null
* then that means the element is hidden.
* As a result, we need to wait for the element
* to become visible before setting the notch width.
*
* We do not check el.offsetParent because
* that can be null if the host element has
* position: fixed applied to it.
* notchSpacerEl does not have position: fixed.
*/
width === 0 &&
notchSpacerEl.offsetParent === null &&
win$1 !== undefined &&
'IntersectionObserver' in win$1) {
/**
* If there is an IO already attached
* then that will update the notch
* once the element becomes visible.
* As a result, there is no need to create
* another one.
*/
if (notchVisibilityIO !== undefined) {
return;
}
const io = (notchVisibilityIO = new IntersectionObserver((ev) => {
/**
* If the element is visible then we
* can try setting the notch width again.
*/
if (ev[0].intersectionRatio === 1) {
setNotchWidth();
io.disconnect();
notchVisibilityIO = undefined;
}
},
/**
* Set the root to be the host element
* This causes the IO callback
* to be fired in WebKit as soon as the element
* is visible. If we used the default root value
* then WebKit would only fire the IO callback
* after any animations (such as a modal transition)
* finished, and there would potentially be a flicker.
*/
{ threshold: 0.01, root: el }));
io.observe(notchSpacerEl);
return;
}
/**
* If the element is visible then we can set the notch width.
* The notch is only visible when the label is scaled,
* which is why we multiply the width by 0.75 as this is
* the same amount the label element is scaled by in the host CSS.
* (See $form-control-label-stacked-scale in ionic.globals.scss).
*/
notchSpacerEl.style.setProperty('width', `${width * 0.75}px`);
};
const destroy = () => {
if (notchVisibilityIO) {
notchVisibilityIO.disconnect();
notchVisibilityIO = undefined;
}
};
return {
calculateNotchWidth,
destroy,
};
};
/**
* Uses the compareWith param to compare two values to determine if they are equal.
*
* @param currentValue The current value of the control.
* @param compareValue The value to compare against.
* @param compareWith The function or property name to use to compare values.
*/
const compareOptions = (currentValue, compareValue, compareWith) => {
if (typeof compareWith === 'function') {
return compareWith(currentValue, compareValue);
}
else if (typeof compareWith === 'string') {
return currentValue[compareWith] === compareValue[compareWith];
}
else {
return Array.isArray(compareValue) ? compareValue.includes(currentValue) : currentValue === compareValue;
}
};
/**
* Compares a value against the current value(s) to determine if it is selected.
*
* @param currentValue The current value of the control.
* @param compareValue The value to compare against.
* @param compareWith The function or property name to use to compare values.
*/
const isOptionSelected = (currentValue, compareValue, compareWith) => {
if (currentValue === undefined) {
return false;
}
if (Array.isArray(currentValue)) {
return currentValue.some((val) => compareOptions(val, compareValue, compareWith));
}
else {
return compareOptions(currentValue, compareValue, compareWith);
}
};
/**
* Checks if the form element is in an invalid state based on
* Ionic validation classes.
*
* @param el The form element to check.
* @returns `true` if the element is invalid, `false` otherwise.
*/
const checkInvalidState = (el) => {
const hasIonTouched = el.classList.contains('ion-touched');
const hasIonInvalid = el.classList.contains('ion-invalid');
return hasIonTouched && hasIonInvalid;
};
/**
* Used to update a scoped component that uses emulated slots. This fires when
* content is passed into the slot or when the content inside of a slot changes.
* This is not needed for components using native slots in the Shadow DOM.
* @internal
* @param el The host element to observe
* @param slotName mutationCallback will fire when nodes on these slot(s) change
* @param mutationCallback The callback to fire whenever the slotted content changes
*/
const createSlotMutationController = (el, slotName, mutationCallback) => {
let hostMutationObserver;
let slottedContentMutationObserver;
if (win$1 !== undefined && 'MutationObserver' in win$1) {
const slots = Array.isArray(slotName) ? slotName : [slotName];
hostMutationObserver = new MutationObserver((entries) => {
for (const entry of entries) {
for (const node of entry.addedNodes) {
/**
* Check to see if the added node
* is our slotted content.
*/
if (node.nodeType === Node.ELEMENT_NODE && slots.includes(node.slot)) {
/**
* If so, we want to watch the slotted
* content itself for changes. This lets us
* detect when content inside of the slot changes.
*/
mutationCallback();
/**
* Adding the listener in an raf
* waits until Stencil moves the slotted element
* into the correct place in the event that
* slotted content is being added.
*/
raf(() => watchForSlotChange(node));
return;
}
}
}
});
hostMutationObserver.observe(el, {
childList: true,
/**
* This fixes an issue with the `ion-input` and
* `ion-textarea` not re-rendering in some cases
* when using the label slot functionality.
*
* HTML element patches in Stencil that are enabled
* by the `experimentalSlotFixes` flag in Stencil v4
* result in DOM manipulations that won't trigger
* the current mutation observer configuration and
* callback.
*/
subtree: true,
});
}
/**
* Listen for changes inside of the slotted content.
* We can listen for subtree changes here to be
* informed of text within the slotted content
* changing. Doing this on the host is possible
* but it is much more expensive to do because
* it also listens for changes to the internals
* of the component.
*/
const watchForSlotChange = (slottedEl) => {
var _a;
if (slottedContentMutationObserver) {
slottedContentMutationObserver.disconnect();
slottedContentMutationObserver = undefined;
}
slottedContentMutationObserver = new MutationObserver((entries) => {
mutationCallback();
for (const entry of entries) {
for (const node of entry.removedNodes) {
/**
* If the element was removed then we
* need to destroy the MutationObserver
* so the element can be garbage collected.
*/
if (node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) {
destroySlottedContentObserver();
}
}
}
});
/**
* Listen for changes inside of the element
* as well as anything deep in the tree.
* We listen on the parentElement so that we can
* detect when slotted element itself is removed.
*/
slottedContentMutationObserver.observe((_a = slottedEl.parentElement) !== null && _a !== void 0 ? _a : slottedEl, { subtree: true, childList: true });
};
const destroy = () => {
if (hostMutationObserver) {
hostMutationObserver.disconnect();
hostMutationObserver = undefined;
}
destroySlottedContentObserver();
};
const destroySlottedContentObserver = () => {
if (slottedContentMutationObserver) {
slottedContentMutationObserver.disconnect();
slottedContentMutationObserver = undefined;
}
};
return {
destroy,
};
};
const getCounterText = (value, maxLength, counterFormatter) => {
const valueLength = value == null ? 0 : value.toString().length;
const defaultCounterText = defaultCounterFormatter(valueLength, maxLength);
/**
* If developers did not pass a custom formatter,
* use the default one.
*/
if (counterFormatter === undefined) {
return defaultCounterText;
}
/**
* Otherwise, try to use the custom formatter
* and fallback to the default formatter if
* there was an error.
*/
try {
return counterFormatter(valueLength, maxLength);
}
catch (e) {
printIonError('[ion-input] - Exception in provided `counterFormatter`:', e);
return defaultCounterText;
}
};
const defaultCounterFormatter = (length, maxlength) => {
return `${length} / ${maxlength}`;
};
const inputIosCss = ".sc-ion-input-ios-h{--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);--padding-top:0px;--padding-end:0px;--padding-bottom:0px;--padding-start:0px;--background:transparent;--color:initial;--border-style:solid;--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;width:100%;min-height:44px;padding:0 !important;color:var(--color);font-family:var(--ion-font-family, inherit);z-index:2}ion-item[slot=start].sc-ion-input-ios-h,ion-item [slot=start].sc-ion-input-ios-h,ion-item[slot=end].sc-ion-input-ios-h,ion-item [slot=end].sc-ion-input-ios-h{width:auto}.ion-color.sc-ion-input-ios-h{--highlight-color-focused:var(--ion-color-base)}.input-label-placement-floating.sc-ion-input-ios-h,.input-label-placement-stacked.sc-ion-input-ios-h{min-height:56px}.native-input.sc-ion-input-ios{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:inline-block;position:relative;-ms-flex:1;flex:1;width:100%;max-width:100%;height:100%;max-height:100%;border:0;outline:none;background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none;z-index:1}.native-input.sc-ion-input-ios::-webkit-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios::-moz-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios:-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios::-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios::placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-ios:-webkit-autofill{background-color:transparent}.native-input.sc-ion-input-ios:invalid{-webkit-box-shadow:none;box-shadow:none}.native-input.sc-ion-input-ios::-ms-clear{display:none}.cloned-input.sc-ion-input-ios{top:0;bottom:0;position:absolute;pointer-events:none}.cloned-input.sc-ion-input-ios{inset-inline-start:0}.cloned-input.sc-ion-input-ios:disabled{opacity:1}.input-clear-icon.sc-ion-input-ios{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;background-position:center;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:30px;height:30px;border:0;outline:none;background-color:transparent;background-repeat:no-repeat;color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));visibility:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}.in-item-color.sc-ion-input-ios-h .input-clear-icon.sc-ion-input-ios{color:inherit}.input-clear-icon.sc-ion-input-ios:focus{opacity:0.5}.has-value.sc-ion-input-ios-h .input-clear-icon.sc-ion-input-ios{visibility:visible}.input-wrapper.sc-ion-input-ios{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:stretch;align-items:stretch;height:inherit;min-height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;background:var(--background);line-height:normal}.native-wrapper.sc-ion-input-ios{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;width:100%}.ion-touched.ion-invalid.sc-ion-input-ios-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-ios-h{--highlight-color:var(--highlight-color-valid)}.input-bottom.sc-ion-input-ios{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:5px;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-top:var(--border-width) var(--border-style) var(--border-color);font-size:0.75rem;white-space:normal}.has-focus.ion-valid.sc-ion-input-ios-h,.ion-touched.ion-invalid.sc-ion-input-ios-h{--border-color:var(--highlight-color)}.input-bottom.sc-ion-input-ios .error-text.sc-ion-input-ios{display:none;color:var(--highlight-color-invalid)}.input-bottom.sc-ion-input-ios .helper-text.sc-ion-input-ios{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid.sc-ion-input-ios-h .input-bottom.sc-ion-input-ios .error-text.sc-ion-input-ios{display:block}.ion-touched.ion-invalid.sc-ion-input-ios-h .input-bottom.sc-ion-input-ios .helper-text.sc-ion-input-ios{display:none}.input-bottom.sc-ion-input-ios .counter.sc-ion-input-ios{-webkit-margin-start:auto;margin-inline-start:auto;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));white-space:nowrap;-webkit-padding-start:16px;padding-inline-start:16px}.has-focus.sc-ion-input-ios-h input.sc-ion-input-ios{caret-color:var(--highlight-color)}.label-text-wrapper.sc-ion-input-ios{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;max-width:200px;-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.label-text.sc-ion-input-ios,.sc-ion-input-ios-s>[slot=label]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden.sc-ion-input-ios,.input-outline-notch-hidden.sc-ion-input-ios{display:none}.input-wrapper.sc-ion-input-ios input.sc-ion-input-ios{-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.input-label-placement-start.sc-ion-input-ios-h .input-wrapper.sc-ion-input-ios{-ms-flex-direction:row;flex-direction:row}.input-label-placement-start.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.input-label-placement-end.sc-ion-input-ios-h .input-wrapper.sc-ion-input-ios{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.input-label-placement-end.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}.input-label-placement-fixed.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.input-label-placement-fixed.sc-ion-input-ios-h .label-text.sc-ion-input-ios{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.input-label-placement-stacked.sc-ion-input-ios-h .input-wrapper.sc-ion-input-ios,.input-label-placement-floating.sc-ion-input-ios-h .input-wrapper.sc-ion-input-ios{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:start}.input-label-placement-stacked.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,.input-label-placement-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-transform-origin:left top;transform-origin:left top;max-width:100%;z-index:2}[dir=rtl].sc-ion-input-ios-h -no-combinator.input-label-placement-stacked.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl] .sc-ion-input-ios-h -no-combinator.input-label-placement-stacked.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl].input-label-placement-stacked.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl] .input-label-placement-stacked.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl].sc-ion-input-ios-h -no-combinator.input-label-placement-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl] .sc-ion-input-ios-h -no-combinator.input-label-placement-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl].input-label-placement-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios,[dir=rtl] .input-label-placement-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.input-label-placement-stacked.sc-ion-input-ios-h:dir(rtl) .label-text-wrapper.sc-ion-input-ios,.input-label-placement-floating.sc-ion-input-ios-h:dir(rtl) .label-text-wrapper.sc-ion-input-ios{-webkit-transform-origin:right top;transform-origin:right top}}.input-label-placement-stacked.sc-ion-input-ios-h input.sc-ion-input-ios,.input-label-placement-floating.sc-ion-input-ios-h input.sc-ion-input-ios{margin-left:0;margin-right:0;margin-top:1px;margin-bottom:0}.input-label-placement-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-transform:translateY(100%) scale(1);transform:translateY(100%) scale(1)}.input-label-placement-floating.sc-ion-input-ios-h input.sc-ion-input-ios{opacity:0}.has-focus.input-label-placement-floating.sc-ion-input-ios-h input.sc-ion-input-ios,.has-value.input-label-placement-floating.sc-ion-input-ios-h input.sc-ion-input-ios{opacity:1}.label-floating.sc-ion-input-ios-h .label-text-wrapper.sc-ion-input-ios{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);max-width:calc(100% / 0.75)}.sc-ion-input-ios-s>[slot=start]:last-of-type{-webkit-margin-end:16px;margin-inline-end:16px;-webkit-margin-start:0;margin-inline-start:0}.sc-ion-input-ios-s>[slot=end]:first-of-type{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}.sc-ion-input-ios-h[disabled].sc-ion-input-ios-s>ion-input-password-toggle,.sc-ion-input-ios-h[disabled] .sc-ion-input-ios-s>ion-input-password-toggle,.sc-ion-input-ios-h[readonly].sc-ion-input-ios-s>ion-input-password-toggle,.sc-ion-input-ios-h[readonly] .sc-ion-input-ios-s>ion-input-password-toggle{visibility:hidden}.sc-ion-input-ios-h{--border-width:0.55px;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));--highlight-height:0px;font-size:inherit}.input-clear-icon.sc-ion-input-ios ion-icon.sc-ion-input-ios{width:18px;height:18px}.input-disabled.sc-ion-input-ios-h{opacity:0.3}.sc-ion-input-ios-s>ion-button[slot=start].button-has-icon-only,.sc-ion-input-ios-s>ion-button[slot=end].button-has-icon-only{--border-radius:50%;--padding-start:0;--padding-end:0;--padding-top:0;--padding-bottom:0;aspect-ratio:1}";
const inputMdCss = ".sc-ion-input-md-h{--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);--padding-top:0px;--padding-end:0px;--padding-bottom:0px;--padding-start:0px;--background:transparent;--color:initial;--border-style:solid;--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;width:100%;min-height:44px;padding:0 !important;color:var(--color);font-family:var(--ion-font-family, inherit);z-index:2}ion-item[slot=start].sc-ion-input-md-h,ion-item [slot=start].sc-ion-input-md-h,ion-item[slot=end].sc-ion-input-md-h,ion-item [slot=end].sc-ion-input-md-h{width:auto}.ion-color.sc-ion-input-md-h{--highlight-color-focused:var(--ion-color-base)}.input-label-placement-floating.sc-ion-input-md-h,.input-label-placement-stacked.sc-ion-input-md-h{min-height:56px}.native-input.sc-ion-input-md{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:inline-block;position:relative;-ms-flex:1;flex:1;width:100%;max-width:100%;height:100%;max-height:100%;border:0;outline:none;background:transparent;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none;z-index:1}.native-input.sc-ion-input-md::-webkit-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md::-moz-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md:-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md::-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md::placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-input.sc-ion-input-md:-webkit-autofill{background-color:transparent}.native-input.sc-ion-input-md:invalid{-webkit-box-shadow:none;box-shadow:none}.native-input.sc-ion-input-md::-ms-clear{display:none}.cloned-input.sc-ion-input-md{top:0;bottom:0;position:absolute;pointer-events:none}.cloned-input.sc-ion-input-md{inset-inline-start:0}.cloned-input.sc-ion-input-md:disabled{opacity:1}.input-clear-icon.sc-ion-input-md{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;background-position:center;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:30px;height:30px;border:0;outline:none;background-color:transparent;background-repeat:no-repeat;color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));visibility:hidden;-webkit-appearance:none;-moz-appearance:none;appearance:none}.in-item-color.sc-ion-input-md-h .input-clear-icon.sc-ion-input-md{color:inherit}.input-clear-icon.sc-ion-input-md:focus{opacity:0.5}.has-value.sc-ion-input-md-h .input-clear-icon.sc-ion-input-md{visibility:visible}.input-wrapper.sc-ion-input-md{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:stretch;align-items:stretch;height:inherit;min-height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;background:var(--background);line-height:normal}.native-wrapper.sc-ion-input-md{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;width:100%}.ion-touched.ion-invalid.sc-ion-input-md-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-md-h{--highlight-color:var(--highlight-color-valid)}.input-bottom.sc-ion-input-md{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:5px;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-top:var(--border-width) var(--border-style) var(--border-color);font-size:0.75rem;white-space:normal}.has-focus.ion-valid.sc-ion-input-md-h,.ion-touched.ion-invalid.sc-ion-input-md-h{--border-color:var(--highlight-color)}.input-bottom.sc-ion-input-md .error-text.sc-ion-input-md{display:none;color:var(--highlight-color-invalid)}.input-bottom.sc-ion-input-md .helper-text.sc-ion-input-md{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid.sc-ion-input-md-h .input-bottom.sc-ion-input-md .error-text.sc-ion-input-md{display:block}.ion-touched.ion-invalid.sc-ion-input-md-h .input-bottom.sc-ion-input-md .helper-text.sc-ion-input-md{display:none}.input-bottom.sc-ion-input-md .counter.sc-ion-input-md{-webkit-margin-start:auto;margin-inline-start:auto;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));white-space:nowrap;-webkit-padding-start:16px;padding-inline-start:16px}.has-focus.sc-ion-input-md-h input.sc-ion-input-md{caret-color:var(--highlight-color)}.label-text-wrapper.sc-ion-input-md{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;max-width:200px;-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.label-text.sc-ion-input-md,.sc-ion-input-md-s>[slot=label]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden.sc-ion-input-md,.input-outline-notch-hidden.sc-ion-input-md{display:none}.input-wrapper.sc-ion-input-md input.sc-ion-input-md{-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.input-label-placement-start.sc-ion-input-md-h .input-wrapper.sc-ion-input-md{-ms-flex-direction:row;flex-direction:row}.input-label-placement-start.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.input-label-placement-end.sc-ion-input-md-h .input-wrapper.sc-ion-input-md{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.input-label-placement-end.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}.input-label-placement-fixed.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.input-label-placement-fixed.sc-ion-input-md-h .label-text.sc-ion-input-md{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.input-label-placement-stacked.sc-ion-input-md-h .input-wrapper.sc-ion-input-md,.input-label-placement-floating.sc-ion-input-md-h .input-wrapper.sc-ion-input-md{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:start}.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform-origin:left top;transform-origin:left top;max-width:100%;z-index:2}[dir=rtl].sc-ion-input-md-h -no-combinator.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .sc-ion-input-md-h -no-combinator.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl].input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl].sc-ion-input-md-h -no-combinator.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .sc-ion-input-md-h -no-combinator.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl].input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.input-label-placement-stacked.sc-ion-input-md-h:dir(rtl) .label-text-wrapper.sc-ion-input-md,.input-label-placement-floating.sc-ion-input-md-h:dir(rtl) .label-text-wrapper.sc-ion-input-md{-webkit-transform-origin:right top;transform-origin:right top}}.input-label-placement-stacked.sc-ion-input-md-h input.sc-ion-input-md,.input-label-placement-floating.sc-ion-input-md-h input.sc-ion-input-md{margin-left:0;margin-right:0;margin-top:1px;margin-bottom:0}.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform:translateY(100%) scale(1);transform:translateY(100%) scale(1)}.input-label-placement-floating.sc-ion-input-md-h input.sc-ion-input-md{opacity:0}.has-focus.input-label-placement-floating.sc-ion-input-md-h input.sc-ion-input-md,.has-value.input-label-placement-floating.sc-ion-input-md-h input.sc-ion-input-md{opacity:1}.label-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);max-width:calc(100% / 0.75)}.sc-ion-input-md-s>[slot=start]:last-of-type{-webkit-margin-end:16px;margin-inline-end:16px;-webkit-margin-start:0;margin-inline-start:0}.sc-ion-input-md-s>[slot=end]:first-of-type{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}.sc-ion-input-md-h[disabled].sc-ion-input-md-s>ion-input-password-toggle,.sc-ion-input-md-h[disabled] .sc-ion-input-md-s>ion-input-password-toggle,.sc-ion-input-md-h[readonly].sc-ion-input-md-s>ion-input-password-toggle,.sc-ion-input-md-h[readonly] .sc-ion-input-md-s>ion-input-password-toggle{visibility:hidden}.input-fill-solid.sc-ion-input-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-500, var(--ion-background-color-step-500, gray));--border-radius:4px;--padding-start:16px;--padding-end:16px;min-height:56px}.input-fill-solid.sc-ion-input-md-h .input-wrapper.sc-ion-input-md{border-bottom:var(--border-width) var(--border-style) var(--border-color)}.has-focus.input-fill-solid.ion-valid.sc-ion-input-md-h,.input-fill-solid.ion-touched.ion-invalid.sc-ion-input-md-h{--border-color:var(--highlight-color)}.input-fill-solid.sc-ion-input-md-h .input-bottom.sc-ion-input-md{border-top:none}@media (any-hover: hover){.input-fill-solid.sc-ion-input-md-h:hover{--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}}.input-fill-solid.has-focus.sc-ion-input-md-h{--background:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}.input-fill-solid.sc-ion-input-md-h .input-wrapper.sc-ion-input-md{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0px;border-end-start-radius:0px}.label-floating.input-fill-solid.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{max-width:calc(100% / 0.75)}.input-fill-outline.sc-ion-input-md-h{--border-color:var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3));--border-radius:4px;--padding-start:16px;--padding-end:16px;min-height:56px}.input-fill-outline.input-shape-round.sc-ion-input-md-h{--border-radius:28px;--padding-start:32px;--padding-end:32px}.has-focus.input-fill-outline.ion-valid.sc-ion-input-md-h,.input-fill-outline.ion-touched.ion-invalid.sc-ion-input-md-h{--border-color:var(--highlight-color)}@media (any-hover: hover){.input-fill-outline.sc-ion-input-md-h:hover{--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}}.input-fill-outline.has-focus.sc-ion-input-md-h{--border-width:var(--highlight-height);--border-color:var(--highlight-color)}.input-fill-outline.sc-ion-input-md-h .input-bottom.sc-ion-input-md{border-top:none}.input-fill-outline.sc-ion-input-md-h .input-wrapper.sc-ion-input-md{border-bottom:none}.input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,.input-fill-outline.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform-origin:left top;transform-origin:left top;position:absolute;max-width:calc(100% - var(--padding-start) - var(--padding-end))}[dir=rtl].sc-ion-input-md-h -no-combinator.input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .sc-ion-input-md-h -no-combinator.input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl].input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl].sc-ion-input-md-h -no-combinator.input-fill-outline.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .sc-ion-input-md-h -no-combinator.input-fill-outline.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl].input-fill-outline.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,[dir=rtl] .input-fill-outline.input-label-placement-floating.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h:dir(rtl) .label-text-wrapper.sc-ion-input-md,.input-fill-outline.input-label-placement-floating.sc-ion-input-md-h:dir(rtl) .label-text-wrapper.sc-ion-input-md{-webkit-transform-origin:right top;transform-origin:right top}}.input-fill-outline.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{position:relative}.label-floating.input-fill-outline.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{-webkit-transform:translateY(-32%) scale(0.75);transform:translateY(-32%) scale(0.75);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;max-width:calc((100% - var(--padding-start) - var(--padding-end) - 8px) / 0.75)}.input-fill-outline.input-label-placement-stacked.sc-ion-input-md-h input.sc-ion-input-md,.input-fill-outline.input-label-placement-floating.sc-ion-input-md-h input.sc-ion-input-md{margin-left:0;margin-right:0;margin-top:6px;margin-bottom:6px}.input-fill-outline.sc-ion-input-md-h .input-outline-container.sc-ion-input-md{left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;width:100%;height:100%}.input-fill-outline.sc-ion-input-md-h .input-outline-start.sc-ion-input-md,.input-fill-outline.sc-ion-input-md-h .input-outline-end.sc-ion-input-md{pointer-events:none}.input-fill-outline.sc-ion-input-md-h .input-outline-start.sc-ion-input-md,.input-fill-outline.sc-ion-input-md-h .input-outline-notch.sc-ion-input-md,.input-fill-outline.sc-ion-input-md-h .input-outline-end.sc-ion-input-md{border-top:var(--border-width) var(--border-style) var(--border-color);border-bottom:var(--border-width) var(--border-style) var(--border-color)}.input-fill-outline.sc-ion-input-md-h .input-outline-notch.sc-ion-input-md{max-width:calc(100% - var(--padding-start) - var(--padding-end))}.input-fill-outline.sc-ion-input-md-h .notch-spacer.sc-ion-input-md{-webkit-padding-end:8px;padding-inline-end:8px;font-size:calc(1em * 0.75);opacity:0;pointer-events:none;-webkit-box-sizing:content-box;box-sizing:content-box}.input-fill-outline.sc-ion-input-md-h .input-outline-start.sc-ion-input-md{border-start-start-radius:var(--border-radius);border-start-end-radius:0px;border-end-end-radius:0px;border-end-start-radius:var(--border-radius);-webkit-border-start:var(--border-width) var(--border-style) var(--border-color);border-inline-start:var(--border-width) var(--border-style) var(--border-color);width:calc(var(--padding-start) - 4px)}.input-fill-outline.sc-ion-input-md-h .input-outline-end.sc-ion-input-md{-webkit-border-end:var(--border-width) var(--border-style) var(--border-color);border-inline-end:var(--border-width) var(--border-style) var(--border-color);border-start-start-radius:0px;border-start-end-radius:var(--border-radius);border-end-end-radius:var(--border-radius);border-end-start-radius:0px;-ms-flex-positive:1;flex-grow:1}.label-floating.input-fill-outline.sc-ion-input-md-h .input-outline-notch.sc-ion-input-md{border-top:none}.sc-ion-input-md-h{--border-width:1px;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));--highlight-height:2px;font-size:inherit}.input-clear-icon.sc-ion-input-md ion-icon.sc-ion-input-md{width:22px;height:22px}.input-disabled.sc-ion-input-md-h{opacity:0.38}.has-focus.ion-valid.sc-ion-input-md-h,.ion-touched.ion-invalid.sc-ion-input-md-h{--border-color:var(--highlight-color)}.input-bottom.sc-ion-input-md .counter.sc-ion-input-md{letter-spacing:0.0333333333em}.input-label-placement-floating.has-focus.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,.input-label-placement-stacked.has-focus.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{color:var(--highlight-color)}.has-focus.input-label-placement-floating.ion-valid.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,.input-label-placement-floating.ion-touched.ion-invalid.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,.has-focus.input-label-placement-stacked.ion-valid.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md,.input-label-placement-stacked.ion-touched.ion-invalid.sc-ion-input-md-h .label-text-wrapper.sc-ion-input-md{color:var(--highlight-color)}.input-highlight.sc-ion-input-md{bottom:-1px;position:absolute;width:100%;height:var(--highlight-height);-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform 200ms;transition:-webkit-transform 200ms;transition:transform 200ms;transition:transform 200ms, -webkit-transform 200ms;background:var(--highlight-color)}.input-highlight.sc-ion-input-md{inset-inline-start:0}.has-focus.sc-ion-input-md-h .input-highlight.sc-ion-input-md{-webkit-transform:scale(1);transform:scale(1)}.in-item.sc-ion-input-md-h .input-highlight.sc-ion-input-md{bottom:0}.in-item.sc-ion-input-md-h .input-highlight.sc-ion-input-md{inset-inline-start:0}.input-shape-round.sc-ion-input-md-h{--border-radius:16px}.sc-ion-input-md-s>ion-button[slot=start].button-has-icon-only,.sc-ion-input-md-s>ion-button[slot=end].button-has-icon-only{--border-radius:50%;--padding-start:8px;--padding-end:8px;--padding-top:8px;--padding-bottom:8px;aspect-ratio:1;min-height:40px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot label - The label text to associate with the input. Use the `labelPlacement` property to control where the label is placed relative to the input. Use this if you need to render a label with custom HTML. (EXPERIMENTAL)
* @slot start - Content to display at the leading edge of the input. (EXPERIMENTAL)
* @slot end - Content to display at the trailing edge of the input. (EXPERIMENTAL)
*/
class Input {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionInput = createEvent(this, "ionInput", 7);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.inputId = `ion-input-${inputIds$1++}`;
this.helperTextId = `${this.inputId}-helper-text`;
this.errorTextId = `${this.inputId}-error-text`;
this.inheritedAttributes = {};
this.isComposing = false;
/**
* `true` if the input was cleared as a result of the user typing
* with `clearOnEdit` enabled.
*
* Resets when the input loses focus.
*/
this.didInputClearOnEdit = false;
/**
* The `hasFocus` state ensures the focus class is
* added regardless of how the element is focused.
* The `ion-focused` class only applies when focused
* via tabbing, not by clicking.
* The `has-focus` logic was added to ensure the class
* is applied in both cases.
*/
this.hasFocus = false;
/**
* Track validation state for proper aria-live announcements
*/
this.isInvalid = false;
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
this.autocapitalize = 'off';
/**
* Indicates whether the value of the control can be automatically completed by the browser.
*/
this.autocomplete = 'off';
/**
* Whether auto correction should be enabled when the user is entering/editing the text value.
*/
this.autocorrect = 'off';
/**
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element.
*
* This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
*/
this.autofocus = false;
/**
* If `true`, a clear icon will appear in the input when there is a value. Clicking it clears the input.
*/
this.clearInput = false;
/**
* If `true`, a character counter will display the ratio of characters used and the total character limit. Developers must also set the `maxlength` property for the counter to be calculated correctly.
*/
this.counter = false;
/**
* If `true`, the user cannot interact with the input.
*/
this.disabled = false;
/**
* Where to place the label relative to the input.
* `"start"`: The label will appear to the left of the input in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the input in LTR and to the left in RTL.
* `"floating"`: The label will appear smaller and above the input when the input is focused or it has a value. Otherwise it will appear on top of the input.
* `"stacked"`: The label will appear smaller and above the input regardless even when the input is blurred or has no value.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
*/
this.labelPlacement = 'start';
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* If `true`, the user cannot modify the value.
*/
this.readonly = false;
/**
* If `true`, the user must fill in a value before submitting a form.
*/
this.required = false;
/**
* If `true`, the element will have its spelling and grammar checked.
*/
this.spellcheck = false;
/**
* The type of control to display. The default type is text.
*/
this.type = 'text';
/**
* The value of the input.
*/
this.value = '';
this.onInput = (ev) => {
const input = ev.target;
if (input) {
this.value = input.value || '';
}
this.emitInputChange(ev);
};
this.onChange = (ev) => {
this.emitValueChange(ev);
};
this.onBlur = (ev) => {
this.hasFocus = false;
if (this.focusedValue !== this.value) {
/**
* Emits the `ionChange` event when the input value
* is different than the value when the input was focused.
*/
this.emitValueChange(ev);
}
this.didInputClearOnEdit = false;
this.ionBlur.emit(ev);
};
this.onFocus = (ev) => {
this.hasFocus = true;
this.focusedValue = this.value;
this.ionFocus.emit(ev);
};
this.onKeydown = (ev) => {
this.checkClearOnEdit(ev);
};
this.onCompositionStart = () => {
this.isComposing = true;
};
this.onCompositionEnd = () => {
this.isComposing = false;
};
this.clearTextInput = (ev) => {
if (this.clearInput && !this.readonly && !this.disabled && ev) {
ev.preventDefault();
ev.stopPropagation();
// Attempt to focus input again after pressing clear button
this.setFocus();
}
this.value = '';
this.emitInputChange(ev);
};
/**
* Stops propagation when the label is clicked,
* otherwise, two clicks will be triggered.
*/
this.onLabelClick = (ev) => {
// Only stop propagation if the click was directly on the label
// and not on the input or other child elements
if (ev.target === ev.currentTarget) {
ev.stopPropagation();
}
};
}
debounceChanged() {
const { ionInput, debounce, originalIonInput } = this;
/**
* If debounce is undefined, we have to manually revert the ionInput emitter in case
* debounce used to be set to a number. Otherwise, the event would stay debounced.
*/
this.ionInput = debounce === undefined ? originalIonInput !== null && originalIonInput !== void 0 ? originalIonInput : ionInput : debounceEvent(ionInput, debounce);
}
/**
* Whenever the type on the input changes we need
* to update the internal type prop on the password
* toggle so that that correct icon is shown.
*/
onTypeChange() {
const passwordToggle = this.el.querySelector('ion-input-password-toggle');
if (passwordToggle) {
passwordToggle.type = this.type;
}
}
/**
* Update the native input element when the value changes
*/
valueChanged() {
const nativeInput = this.nativeInput;
const value = this.getValue();
if (nativeInput && nativeInput.value !== value && !this.isComposing) {
/**
* Assigning the native input's value on attribute
* value change, allows `ionInput` implementations
* to override the control's value.
*
* Used for patterns such as input trimming (removing whitespace),
* or input masking.
*/
nativeInput.value = value;
}
}
/**
* dir is a globally enumerated attribute.
* As a result, creating these as properties
* can have unintended side effects. Instead, we
* listen for attribute changes and inherit them
* to the inner `<input>` element.
*/
onDirChanged(newValue) {
this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { dir: newValue });
}
/**
* This prevents the native input from emitting the click event.
* Instead, the click event from the ion-input is emitted.
*/
onClickCapture(ev) {
const nativeInput = this.nativeInput;
if (nativeInput && ev.target === nativeInput) {
ev.stopPropagation();
this.el.click();
}
}
componentWillLoad() {
this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes$1(this.el, ['tabindex', 'title', 'data-form-type', 'dir']));
}
connectedCallback() {
const { el } = this;
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate());
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
// Always set initial state
this.isInvalid = checkInvalidState(el);
this.debounceChanged();
}
componentDidLoad() {
this.originalIonInput = this.ionInput;
/**
* Set the type on the password toggle in the event that this input's
* type was set async and does not match the default type for the password toggle.
* This can happen when the type is bound using a JS framework binding syntax
* such as [type] in Angular.
*/
this.onTypeChange();
this.debounceChanged();
}
componentDidRender() {
var _a;
(_a = this.notchController) === null || _a === void 0 ? void 0 : _a.calculateNotchWidth();
}
disconnectedCallback() {
if (this.slotMutationController) {
this.slotMutationController.destroy();
this.slotMutationController = undefined;
}
if (this.notchController) {
this.notchController.destroy();
this.notchController = undefined;
}
// Clean up validation observer to prevent memory leaks
if (this.validationObserver) {
this.validationObserver.disconnect();
this.validationObserver = undefined;
}
}
/**
* Sets focus on the native `input` in `ion-input`. Use this method instead of the global
* `input.focus()`.
*
* Developers who wish to focus an input when a page enters
* should call `setFocus()` in the `ionViewDidEnter()` lifecycle method.
*
* Developers who wish to focus an input when an overlay is presented
* should call `setFocus` after `didPresent` has resolved.
*
* See [managing focus](/docs/developing/managing-focus) for more information.
*/
async setFocus() {
if (this.nativeInput) {
this.nativeInput.focus();
}
}
/**
* Returns the native `<input>` element used under the hood.
*/
async getInputElement() {
/**
* If this gets called in certain early lifecycle hooks (ex: Vue onMounted),
* nativeInput won't be defined yet with the custom elements build, so wait for it to load in.
*/
if (!this.nativeInput) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.nativeInput);
}
/**
* Emits an `ionChange` event.
*
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitValueChange(event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
// Emitting a value change should update the internal state for tracking the focused value
this.focusedValue = newValue;
this.ionChange.emit({ value: newValue, event });
}
/**
* Emits an `ionInput` event.
*/
emitInputChange(event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
this.ionInput.emit({ value: newValue, event });
}
shouldClearOnEdit() {
const { type, clearOnEdit } = this;
return clearOnEdit === undefined ? type === 'password' : clearOnEdit;
}
getValue() {
return typeof this.value === 'number' ? this.value.toString() : (this.value || '').toString();
}
checkClearOnEdit(ev) {
if (!this.shouldClearOnEdit()) {
return;
}
/**
* The following keys do not modify the
* contents of the input. As a result, pressing
* them should not edit the input.
*
* We can't check to see if the value of the input
* was changed because we call checkClearOnEdit
* in a keydown listener, and the key has not yet
* been added to the input.
*/
const IGNORED_KEYS = ['Enter', 'Tab', 'Shift', 'Meta', 'Alt', 'Control'];
const pressedIgnoredKey = IGNORED_KEYS.includes(ev.key);
/**
* Clear the input if the control has not been previously cleared during focus.
* Do not clear if the user hitting enter to submit a form.
*/
if (!this.didInputClearOnEdit && this.hasValue() && !pressedIgnoredKey) {
this.value = '';
this.emitInputChange(ev);
}
/**
* Pressing an IGNORED_KEYS first and
* then an allowed key will cause the input to not
* be cleared.
*/
if (!pressedIgnoredKey) {
this.didInputClearOnEdit = true;
}
}
hasValue() {
return this.getValue().length > 0;
}
/**
* Renders the helper text or error text values
*/
renderHintText() {
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
return [
hAsync("div", { id: helperTextId, class: "helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
hAsync("div", { id: errorTextId, class: "error-text", role: "alert" }, isInvalid ? errorText : null),
];
}
getHintTextID() {
const { isInvalid, helperText, errorText, helperTextId, errorTextId } = this;
if (isInvalid && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
renderCounter() {
const { counter, maxlength, counterFormatter, value } = this;
if (counter !== true || maxlength === undefined) {
return;
}
return hAsync("div", { class: "counter" }, getCounterText(value, maxlength, counterFormatter));
}
/**
* Responsible for rendering helper text,
* error text, and counter. This element should only
* be rendered if hint text is set or counter is enabled.
*/
renderBottomContent() {
const { counter, helperText, errorText, maxlength } = this;
/**
* undefined and empty string values should
* be treated as not having helper/error text.
*/
const hasHintText = !!helperText || !!errorText;
const hasCounter = counter === true && maxlength !== undefined;
if (!hasHintText && !hasCounter) {
return;
}
return (hAsync("div", { class: "input-bottom" }, this.renderHintText(), this.renderCounter()));
}
renderLabel() {
const { label } = this;
return (hAsync("div", { class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !this.hasLabel,
} }, label === undefined ? hAsync("slot", { name: "label" }) : hAsync("div", { class: "label-text" }, label)));
}
/**
* Gets any content passed into the `label` slot,
* not the <slot> definition.
*/
get labelSlot() {
return this.el.querySelector('[slot="label"]');
}
/**
* Returns `true` if label content is provided
* either by a prop or a content. If you want
* to get the plaintext value of the label use
* the `labelText` getter instead.
*/
get hasLabel() {
return this.label !== undefined || this.labelSlot !== null;
}
/**
* Renders the border container
* when fill="outline".
*/
renderLabelContainer() {
const mode = getIonMode$1(this);
const hasOutlineFill = mode === 'md' && this.fill === 'outline';
if (hasOutlineFill) {
/**
* The outline fill has a special outline
* that appears around the input and the label.
* Certain stacked and floating label placements cause the
* label to translate up and create a "cut out"
* inside of that border by using the notch-spacer element.
*/
return [
hAsync("div", { class: "input-outline-container" }, hAsync("div", { class: "input-outline-start" }), hAsync("div", { class: {
'input-outline-notch': true,
'input-outline-notch-hidden': !this.hasLabel,
} }, hAsync("div", { class: "notch-spacer", "aria-hidden": "true", ref: (el) => (this.notchSpacerEl = el) }, this.label)), hAsync("div", { class: "input-outline-end" })),
this.renderLabel(),
];
}
/**
* If not using the outline style,
* we can render just the label.
*/
return this.renderLabel();
}
render() {
const { disabled, fill, readonly, shape, inputId, labelPlacement, el, hasFocus, clearInputIcon } = this;
const mode = getIonMode$1(this);
const value = this.getValue();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const defaultClearIcon = mode === 'ios' ? closeCircle : closeSharp;
const clearIconData = clearInputIcon !== null && clearInputIcon !== void 0 ? clearInputIcon : defaultClearIcon;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
/**
* If the label is stacked, it should always sit above the input.
* For floating labels, the label should move above the input if
* the input has a value, is focused, or has anything in either
* the start or end slot.
*
* If there is content in the start slot, the label would overlap
* it if not forced to float. This is also applied to the end slot
* because with the default or solid fills, the input is not
* vertically centered in the container, but the label is. This
* causes the slots and label to appear vertically offset from each
* other when the label isn't floating above the input. This doesn't
* apply to the outline fill, but this was not accounted for to keep
* things consistent.
*
* TODO(FW-5592): Remove hasStartEndSlots condition
*/
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
return (hAsync(Host, { key: '97b5308021064d9e7434ef2d3d96f27045c1b0c4', class: createColorClasses$1(this.color, {
[mode]: true,
'has-value': hasValue,
'has-focus': hasFocus,
'label-floating': labelShouldFloat,
[`input-fill-${fill}`]: fill !== undefined,
[`input-shape-${shape}`]: shape !== undefined,
[`input-label-placement-${labelPlacement}`]: true,
'in-item': inItem,
'in-item-color': hostContext('ion-item.ion-color', this.el),
'input-disabled': disabled,
}) }, hAsync("label", { key: '353f68726ce180299bd9adc81e5ff7d26a48f54f', class: "input-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: '2034b4bad04fc157f3298a1805819216b6f439d0', class: "native-wrapper", onClick: this.onLabelClick }, hAsync("slot", { key: '96bb5e30176b2bd76dfb75bfbf6c1c3d4403f4bb', name: "start" }), hAsync("input", Object.assign({ key: '1a1d75b0e414a95c89d5a760757c33548d234aca', class: "native-input", ref: (input) => (this.nativeInput = input), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, min: this.min, max: this.max, minLength: this.minlength, maxLength: this.maxlength, multiple: this.multiple, name: this.name, pattern: this.pattern, placeholder: this.placeholder || '', readOnly: readonly, required: this.required, spellcheck: this.spellcheck, step: this.step, type: this.type, value: value, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeydown, onCompositionstart: this.onCompositionStart, onCompositionend: this.onCompositionEnd, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined }, this.inheritedAttributes)), this.clearInput && !readonly && !disabled && (hAsync("button", { key: '95f3df17b7691d9a2e7dcd4a51f16a94aa3ca36f', "aria-label": "reset", type: "button", class: "input-clear-icon", onPointerDown: (ev) => {
/**
* This prevents mobile browsers from
* blurring the input when the clear
* button is activated.
*/
ev.preventDefault();
}, onClick: this.clearTextInput }, hAsync("ion-icon", { key: '16b0af75eed50c8115fb5597f73b5fbf71c2530e', "aria-hidden": "true", icon: clearIconData }))), hAsync("slot", { key: 'c48da0f8ddb3764ac43efa705bb4a6bb2d9cc2fd', name: "end" })), shouldRenderHighlight && hAsync("div", { key: 'f15238481fc20de56ca7ecb6e350b3c024cc755e', class: "input-highlight" })), this.renderBottomContent()));
}
get el() { return getElement(this); }
static get watchers() { return {
"debounce": ["debounceChanged"],
"type": ["onTypeChange"],
"value": ["valueChanged"],
"dir": ["onDirChanged"]
}; }
static get style() { return {
ios: inputIosCss,
md: inputMdCss
}; }
static get cmpMeta() { return {
"$flags$": 294,
"$tagName$": "ion-input",
"$members$": {
"color": [513],
"autocapitalize": [1],
"autocomplete": [1],
"autocorrect": [1],
"autofocus": [4],
"clearInput": [4, "clear-input"],
"clearInputIcon": [1, "clear-input-icon"],
"clearOnEdit": [4, "clear-on-edit"],
"counter": [4],
"counterFormatter": [16],
"debounce": [2],
"disabled": [516],
"enterkeyhint": [1],
"errorText": [1, "error-text"],
"fill": [1],
"inputmode": [1],
"helperText": [1, "helper-text"],
"label": [1],
"labelPlacement": [1, "label-placement"],
"max": [8],
"maxlength": [2],
"min": [8],
"minlength": [2],
"multiple": [4],
"name": [1],
"pattern": [1],
"placeholder": [1],
"readonly": [516],
"required": [4],
"shape": [1],
"spellcheck": [4],
"step": [1],
"type": [1],
"value": [1032],
"hasFocus": [32],
"isInvalid": [32],
"setFocus": [64],
"getInputElement": [64]
},
"$listeners$": [[2, "click", "onClickCapture"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["disabled", "disabled"], ["readonly", "readonly"]]
}; }
}
let inputIds$1 = 0;
const inputOtpIosCss = ".sc-ion-input-otp-ios-h{--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--padding-top:16px;--padding-end:0;--padding-bottom:16px;--padding-start:0;--color:initial;--min-width:40px;--separator-width:8px;--separator-height:var(--separator-width);--separator-border-radius:999px;--separator-color:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;font-size:0.875rem}.input-otp-group.sc-ion-input-otp-ios{-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.native-wrapper.sc-ion-input-otp-ios{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:var(--min-width)}.native-input.sc-ion-input-otp-ios{border-radius:var(--border-radius);width:var(--width);min-width:inherit;height:var(--height);border-width:var(--border-width);border-style:solid;border-color:var(--border-color);background:var(--background);color:var(--color);font-size:inherit;text-align:center;-webkit-appearance:none;-moz-appearance:none;appearance:none}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{caret-color:var(--highlight-color)}.input-otp-description.sc-ion-input-otp-ios{color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-description-hidden.sc-ion-input-otp-ios{display:none}.input-otp-separator.sc-ion-input-otp-ios{border-radius:var(--separator-border-radius);-ms-flex-negative:0;flex-shrink:0;width:var(--separator-width);height:var(--separator-height);background:var(--separator-color)}.input-otp-size-small.sc-ion-input-otp-ios-h{--width:40px;--height:40px}.input-otp-size-small.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios{gap:8px}.input-otp-size-medium.sc-ion-input-otp-ios-h{--width:48px;--height:48px}.input-otp-size-large.sc-ion-input-otp-ios-h{--width:56px;--height:56px}.input-otp-size-medium.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios,.input-otp-size-large.sc-ion-input-otp-ios-h .input-otp-group.sc-ion-input-otp-ios{gap:12px}.input-otp-shape-round.sc-ion-input-otp-ios-h{--border-radius:16px}.input-otp-shape-soft.sc-ion-input-otp-ios-h{--border-radius:8px}.input-otp-shape-rectangular.sc-ion-input-otp-ios-h{--border-radius:0}.input-otp-fill-outline.sc-ion-input-otp-ios-h{--background:none}.input-otp-fill-solid.sc-ion-input-otp-ios-h{--border-color:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-disabled.sc-ion-input-otp-ios-h{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6))}.input-otp-fill-outline.input-otp-disabled.sc-ion-input-otp-ios-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.input-otp-disabled.sc-ion-input-otp-ios-h,.input-otp-disabled.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:disabled{cursor:not-allowed}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{--border-color:var(--highlight-color);outline:none}.input-otp-fill-outline.input-otp-readonly.sc-ion-input-otp-ios-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-fill-solid.input-otp-disabled.sc-ion-input-otp-ios-h,.input-otp-fill-solid.input-otp-readonly.sc-ion-input-otp-ios-h{--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.ion-touched.ion-invalid.sc-ion-input-otp-ios-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-otp-ios-h{--highlight-color:var(--highlight-color-valid)}.has-focus.ion-valid.sc-ion-input-otp-ios-h,.ion-touched.ion-invalid.sc-ion-input-otp-ios-h{--border-color:var(--highlight-color)}.ion-color.sc-ion-input-otp-ios-h{--highlight-color-focused:var(--ion-color-base)}.input-otp-fill-outline.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{border-color:rgba(var(--ion-color-base-rgb), 0.6)}.input-otp-fill-outline.ion-color.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-outline.ion-color.has-focus.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.has-focus.ion-invalid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:var(--ion-color-danger, #c5000f)}.input-otp-fill-outline.ion-color.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-outline.ion-color.has-focus.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios,.input-otp-fill-solid.ion-color.has-focus.ion-valid.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:var(--ion-color-success, #2dd55b)}.input-otp-fill-outline.input-otp-disabled.ion-color.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios{border-color:rgba(var(--ion-color-base-rgb), 0.3)}.sc-ion-input-otp-ios-h{--border-width:0.55px}.has-focus.sc-ion-input-otp-ios-h .native-input.sc-ion-input-otp-ios:focus{--border-width:1px}.input-otp-fill-outline.sc-ion-input-otp-ios-h{--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))))}";
const inputOtpMdCss = ".sc-ion-input-otp-md-h{--margin-top:0;--margin-end:0;--margin-bottom:0;--margin-start:0;--padding-top:16px;--padding-end:0;--padding-bottom:16px;--padding-start:0;--color:initial;--min-width:40px;--separator-width:8px;--separator-height:var(--separator-width);--separator-border-radius:999px;--separator-color:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;font-size:0.875rem}.input-otp-group.sc-ion-input-otp-md{-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.native-wrapper.sc-ion-input-otp-md{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;min-width:var(--min-width)}.native-input.sc-ion-input-otp-md{border-radius:var(--border-radius);width:var(--width);min-width:inherit;height:var(--height);border-width:var(--border-width);border-style:solid;border-color:var(--border-color);background:var(--background);color:var(--color);font-size:inherit;text-align:center;-webkit-appearance:none;-moz-appearance:none;appearance:none}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{caret-color:var(--highlight-color)}.input-otp-description.sc-ion-input-otp-md{color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem;line-height:1.25rem;text-align:center}.input-otp-description-hidden.sc-ion-input-otp-md{display:none}.input-otp-separator.sc-ion-input-otp-md{border-radius:var(--separator-border-radius);-ms-flex-negative:0;flex-shrink:0;width:var(--separator-width);height:var(--separator-height);background:var(--separator-color)}.input-otp-size-small.sc-ion-input-otp-md-h{--width:40px;--height:40px}.input-otp-size-small.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md{gap:8px}.input-otp-size-medium.sc-ion-input-otp-md-h{--width:48px;--height:48px}.input-otp-size-large.sc-ion-input-otp-md-h{--width:56px;--height:56px}.input-otp-size-medium.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md,.input-otp-size-large.sc-ion-input-otp-md-h .input-otp-group.sc-ion-input-otp-md{gap:12px}.input-otp-shape-round.sc-ion-input-otp-md-h{--border-radius:16px}.input-otp-shape-soft.sc-ion-input-otp-md-h{--border-radius:8px}.input-otp-shape-rectangular.sc-ion-input-otp-md-h{--border-radius:0}.input-otp-fill-outline.sc-ion-input-otp-md-h{--background:none}.input-otp-fill-solid.sc-ion-input-otp-md-h{--border-color:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-disabled.sc-ion-input-otp-md-h{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6))}.input-otp-fill-outline.input-otp-disabled.sc-ion-input-otp-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.input-otp-disabled.sc-ion-input-otp-md-h,.input-otp-disabled.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:disabled{cursor:not-allowed}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{--border-color:var(--highlight-color);outline:none}.input-otp-fill-outline.input-otp-readonly.sc-ion-input-otp-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2))}.input-otp-fill-solid.input-otp-disabled.sc-ion-input-otp-md-h,.input-otp-fill-solid.input-otp-readonly.sc-ion-input-otp-md-h{--border-color:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.ion-touched.ion-invalid.sc-ion-input-otp-md-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-input-otp-md-h{--highlight-color:var(--highlight-color-valid)}.has-focus.ion-valid.sc-ion-input-otp-md-h,.ion-touched.ion-invalid.sc-ion-input-otp-md-h{--border-color:var(--highlight-color)}.ion-color.sc-ion-input-otp-md-h{--highlight-color-focused:var(--ion-color-base)}.input-otp-fill-outline.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{border-color:rgba(var(--ion-color-base-rgb), 0.6)}.input-otp-fill-outline.ion-color.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-outline.ion-color.has-focus.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.has-focus.ion-invalid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:var(--ion-color-danger, #c5000f)}.input-otp-fill-outline.ion-color.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-outline.ion-color.has-focus.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md,.input-otp-fill-solid.ion-color.has-focus.ion-valid.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:var(--ion-color-success, #2dd55b)}.input-otp-fill-outline.input-otp-disabled.ion-color.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md{border-color:rgba(var(--ion-color-base-rgb), 0.3)}.sc-ion-input-otp-md-h{--border-width:1px}.has-focus.sc-ion-input-otp-md-h .native-input.sc-ion-input-otp-md:focus{--border-width:2px}.input-otp-fill-outline.sc-ion-input-otp-md-h{--border-color:var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3))}";
class InputOTP {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionInput = createEvent(this, "ionInput", 7);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionComplete = createEvent(this, "ionComplete", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.inheritedAttributes = {};
this.inputRefs = [];
this.inputId = `ion-input-otp-${inputIds++}`;
this.parsedSeparators = [];
/**
* Tracks whether the user is navigating through input boxes using keyboard navigation
* (arrow keys, tab) versus mouse clicks. This is used to determine the appropriate
* focus behavior when an input box is focused.
*/
this.isKeyboardNavigation = false;
this.inputValues = [];
this.hasFocus = false;
this.previousInputValues = [];
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
this.autocapitalize = 'off';
/**
* If `true`, the user cannot interact with the input.
*/
this.disabled = false;
/**
* The fill for the input boxes. If `"solid"` the input boxes will have a background. If
* `"outline"` the input boxes will be transparent with a border.
*/
this.fill = 'outline';
/**
* The number of input boxes to display.
*/
this.length = 4;
/**
* If `true`, the user cannot modify the value.
*/
this.readonly = false;
/**
* The shape of the input boxes.
* If "round" they will have an increased border radius.
* If "rectangular" they will have no border radius.
* If "soft" they will have a soft border radius.
*/
this.shape = 'round';
/**
* The size of the input boxes.
*/
this.size = 'medium';
/**
* The type of input allowed in the input boxes.
*/
this.type = 'number';
/**
* The value of the input group.
*/
this.value = '';
/**
* Handles the focus behavior for the input OTP component.
*
* Focus behavior:
* 1. Keyboard navigation: Allow normal focus movement
* 2. Mouse click:
* - If clicked box has value: Focus that box
* - If clicked box is empty: Focus first empty box
*
* Emits the `ionFocus` event when the input group gains focus.
*/
this.onFocus = (index) => (event) => {
var _a;
const { inputRefs } = this;
// Only emit ionFocus and set the focusedValue when the
// component first gains focus
if (!this.hasFocus) {
this.ionFocus.emit(event);
this.focusedValue = this.value;
}
this.hasFocus = true;
let finalIndex = index;
if (!this.isKeyboardNavigation) {
// If the clicked box has a value, focus it
// Otherwise focus the first empty box
const targetIndex = this.inputValues[index] ? index : this.getFirstEmptyIndex();
finalIndex = targetIndex === -1 ? this.length - 1 : targetIndex;
// Focus the target box
(_a = this.inputRefs[finalIndex]) === null || _a === void 0 ? void 0 : _a.focus();
}
// Update tabIndexes to match the focused box
inputRefs.forEach((input, i) => {
input.tabIndex = i === finalIndex ? 0 : -1;
});
// Reset the keyboard navigation flag
this.isKeyboardNavigation = false;
};
/**
* Handles the blur behavior for the input OTP component.
* Emits the `ionBlur` event when the input group loses focus.
*/
this.onBlur = (event) => {
const { inputRefs } = this;
const relatedTarget = event.relatedTarget;
// Do not emit blur if we're moving to another input box in the same component
const isInternalFocus = relatedTarget != null && inputRefs.includes(relatedTarget);
if (!isInternalFocus) {
this.hasFocus = false;
// Reset tabIndexes when focus leaves the component
this.updateTabIndexes();
// Always emit ionBlur when focus leaves the component
this.ionBlur.emit(event);
// Only emit ionChange if the value has actually changed
if (this.focusedValue !== this.value) {
this.emitIonChange(event);
}
}
};
/**
* Handles keyboard navigation for the OTP component.
*
* Navigation:
* - Backspace: Clears current input and moves to previous box if empty
* - Arrow Left/Right: Moves focus between input boxes
* - Tab: Allows normal tab navigation between components
*/
this.onKeyDown = (index) => (event) => {
const { length } = this;
const rtl = isRTL$1(this.el);
const input = event.target;
// Meta shortcuts are used to copy, paste, and select text
// We don't want to handle these keys here
const metaShortcuts = ['a', 'c', 'v', 'x', 'r', 'z', 'y'];
const isTextSelection = input.selectionStart !== input.selectionEnd;
// Return if the key is a meta shortcut or the input value
// text is selected and let the onPaste / onInput handler manage it
if (isTextSelection || ((event.metaKey || event.ctrlKey) && metaShortcuts.includes(event.key.toLowerCase()))) {
return;
}
if (event.key === 'Backspace') {
if (this.inputValues[index]) {
// Shift all values to the right of the current index left by one
for (let i = index; i < length - 1; i++) {
this.inputValues[i] = this.inputValues[i + 1];
}
// Clear the last box
this.inputValues[length - 1] = '';
// Update all inputRefs to match inputValues
for (let i = 0; i < length; i++) {
this.inputRefs[i].value = this.inputValues[i] || '';
}
this.updateValue(event);
event.preventDefault();
}
else if (!this.inputValues[index] && index > 0) {
// If current input is empty, move to previous input
this.focusPrevious(index);
}
}
else if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
this.isKeyboardNavigation = true;
event.preventDefault();
const isLeft = event.key === 'ArrowLeft';
const shouldMoveNext = (isLeft && rtl) || (!isLeft && !rtl);
// Only allow moving to the next input if the current has a value
if (shouldMoveNext) {
if (this.inputValues[index] && index < length - 1) {
this.focusNext(index);
}
}
else {
this.focusPrevious(index);
}
}
else if (event.key === 'Tab') {
this.isKeyboardNavigation = true;
// Let all tab events proceed normally
return;
}
};
/**
* Processes all input scenarios for each input box.
*
* This function manages:
* 1. Autofill handling
* 2. Input validation
* 3. Full selection replacement or typing in an empty box
* 4. Inserting in the middle with available space (shifting)
* 5. Single character replacement
*/
this.onInput = (index) => (event) => {
var _a, _b;
const { length, validKeyPattern } = this;
const input = event.target;
const value = input.value;
const previousValue = this.previousInputValues[index] || '';
// 1. Autofill handling
// If the length of the value increases by more than 1 from the previous
// value, treat this as autofill. This is to prevent the case where the
// user is typing a single character into an input box containing a value
// as that will trigger this function with a value length of 2 characters.
const isAutofill = value.length - previousValue.length > 1;
if (isAutofill) {
// Distribute valid characters across input boxes
const validChars = value
.split('')
.filter((char) => validKeyPattern.test(char))
.slice(0, length);
// If there are no valid characters coming from the
// autofill, all input refs have to be cleared after the
// browser has finished the autofill behavior
if (validChars.length === 0) {
requestAnimationFrame(() => {
this.inputRefs.forEach((input) => {
input.value = '';
});
});
}
for (let i = 0; i < length; i++) {
this.inputValues[i] = validChars[i] || '';
this.inputRefs[i].value = validChars[i] || '';
}
this.updateValue(event);
// Focus the first empty input box or the last input box if all boxes
// are filled after a small delay to ensure the input boxes have been
// updated before moving the focus
setTimeout(() => {
var _a;
const nextIndex = validChars.length < length ? validChars.length : length - 1;
(_a = this.inputRefs[nextIndex]) === null || _a === void 0 ? void 0 : _a.focus();
}, 20);
this.previousInputValues = [...this.inputValues];
return;
}
// 2. Input validation
// If the character entered is invalid (does not match the pattern),
// restore the previous value and exit
if (value.length > 0 && !validKeyPattern.test(value[value.length - 1])) {
input.value = this.inputValues[index] || '';
this.previousInputValues = [...this.inputValues];
return;
}
// 3. Full selection replacement or typing in an empty box
// If the user selects all text in the input box and types, or if the
// input box is empty, replace only this input box. If the box is empty,
// move to the next box, otherwise stay focused on this box.
const isAllSelected = input.selectionStart === 0 && input.selectionEnd === value.length;
const isEmpty = !this.inputValues[index];
if (isAllSelected || isEmpty) {
this.inputValues[index] = value;
input.value = value;
this.updateValue(event);
this.focusNext(index);
this.previousInputValues = [...this.inputValues];
return;
}
// 4. Inserting in the middle with available space (shifting)
// If typing in a filled input box and there are empty boxes at the end,
// shift all values starting at the current box to the right, and insert
// the new character at the current box.
const hasAvailableBoxAtEnd = this.inputValues[this.inputValues.length - 1] === '';
if (this.inputValues[index] && hasAvailableBoxAtEnd && value.length === 2) {
// Get the inserted character (from event or by diffing value/previousValue)
let newChar = event.data;
if (!newChar) {
newChar = value.split('').find((c, i) => c !== previousValue[i]) || value[value.length - 1];
}
// Validate the new character before shifting
if (!validKeyPattern.test(newChar)) {
input.value = this.inputValues[index] || '';
this.previousInputValues = [...this.inputValues];
return;
}
// Shift values right from the end to the insertion point
for (let i = this.inputValues.length - 1; i > index; i--) {
this.inputValues[i] = this.inputValues[i - 1];
this.inputRefs[i].value = this.inputValues[i] || '';
}
this.inputValues[index] = newChar;
this.inputRefs[index].value = newChar;
this.updateValue(event);
this.previousInputValues = [...this.inputValues];
return;
}
// 5. Single character replacement
// Handles replacing a single character in a box containing a value based
// on the cursor position. We need the cursor position to determine which
// character was the last character typed. For example, if the user types "2"
// in an input box with the cursor at the beginning of the value of "6",
// the value will be "26", but we want to grab the "2" as the last character
// typed.
const cursorPos = (_a = input.selectionStart) !== null && _a !== void 0 ? _a : value.length;
const newCharIndex = cursorPos - 1;
const newChar = (_b = value[newCharIndex]) !== null && _b !== void 0 ? _b : value[0];
// Check if the new character is valid before updating the value
if (!validKeyPattern.test(newChar)) {
input.value = this.inputValues[index] || '';
this.previousInputValues = [...this.inputValues];
return;
}
this.inputValues[index] = newChar;
input.value = newChar;
this.updateValue(event);
this.previousInputValues = [...this.inputValues];
};
/**
* Handles pasting text into the input OTP component.
* This function prevents the default paste behavior and
* validates the pasted text against the allowed pattern.
* It then updates the value of the input group and focuses
* the next empty input after pasting.
*/
this.onPaste = (event) => {
var _a, _b;
const { inputRefs, length, validKeyPattern } = this;
event.preventDefault();
const pastedText = (_a = event.clipboardData) === null || _a === void 0 ? void 0 : _a.getData('text');
// If there is no pasted text, still emit the input change event
// because this is how the native input element behaves
// but return early because there is nothing to paste.
if (!pastedText) {
this.emitIonInput(event);
return;
}
const validChars = pastedText
.split('')
.filter((char) => validKeyPattern.test(char))
.slice(0, length);
// Always paste starting at the first box
validChars.forEach((char, index) => {
if (index < length) {
this.inputRefs[index].value = char;
this.inputValues[index] = char;
}
});
// Update the value so that all input boxes are updated
this.value = validChars.join('');
this.updateValue(event);
// Focus the next empty input after pasting
// If all boxes are filled, focus the last input
const nextEmptyIndex = validChars.length < length ? validChars.length : length - 1;
(_b = inputRefs[nextEmptyIndex]) === null || _b === void 0 ? void 0 : _b.focus();
};
}
/**
* Sets focus to an input box.
* @param index - The index of the input box to focus (0-based).
* If provided and the input box has a value, the input box at that index will be focused.
* Otherwise, the first empty input box or the last input if all are filled will be focused.
*/
async setFocus(index) {
var _a, _b;
if (typeof index === 'number') {
const validIndex = Math.max(0, Math.min(index, this.length - 1));
(_a = this.inputRefs[validIndex]) === null || _a === void 0 ? void 0 : _a.focus();
}
else {
const tabbableIndex = this.getTabbableIndex();
(_b = this.inputRefs[tabbableIndex]) === null || _b === void 0 ? void 0 : _b.focus();
}
}
valueChanged() {
this.initializeValues();
this.updateTabIndexes();
}
/**
* Processes the separators prop into an array of numbers.
*
* If the separators prop is not provided, returns an empty array.
* If the separators prop is 'all', returns an array of all valid positions (1 to length-1).
* If the separators prop is an array, returns it as is.
* If the separators prop is a string, splits it by commas and parses each part as a number.
*
* If the separators are greater than the input length, it will warn and ignore the separators.
*/
processSeparators() {
const { separators, length } = this;
if (separators === undefined) {
this.parsedSeparators = [];
return;
}
if (typeof separators === 'string' && separators !== 'all') {
const isValidFormat = /^(\d+)(,\d+)*$/.test(separators);
if (!isValidFormat) {
printIonWarning(`[ion-input-otp] - Invalid separators format. Expected a comma-separated list of numbers, an array of numbers, or "all". Received: ${separators}`, this.el);
this.parsedSeparators = [];
return;
}
}
let separatorValues;
if (separators === 'all') {
separatorValues = Array.from({ length: length - 1 }, (_, i) => i + 1);
}
else if (Array.isArray(separators)) {
separatorValues = separators;
}
else {
separatorValues = separators
.split(',')
.map((pos) => parseInt(pos, 10))
.filter((pos) => !isNaN(pos));
}
// Check for duplicate separator positions
const duplicates = separatorValues.filter((pos, index) => separatorValues.indexOf(pos) !== index);
if (duplicates.length > 0) {
printIonWarning(`[ion-input-otp] - Duplicate separator positions are not allowed. Received: ${separators}`, this.el);
}
const invalidSeparators = separatorValues.filter((pos) => pos > length);
if (invalidSeparators.length > 0) {
printIonWarning(`[ion-input-otp] - The following separator positions are greater than the input length (${length}): ${invalidSeparators.join(', ')}. These separators will be ignored.`, this.el);
}
this.parsedSeparators = separatorValues.filter((pos) => pos <= length);
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
this.processSeparators();
this.initializeValues();
}
componentDidLoad() {
this.updateTabIndexes();
}
/**
* Get the regex pattern for allowed characters.
* If a pattern is provided, use it to create a regex pattern
* Otherwise, use the default regex pattern based on type
*/
get validKeyPattern() {
return new RegExp(`^${this.getPattern()}$`, 'u');
}
/**
* Gets the string pattern to pass to the input element
* and use in the regex for allowed characters.
*/
getPattern() {
const { pattern, type } = this;
if (pattern) {
return pattern;
}
return type === 'number' ? '[\\p{N}]' : '[\\p{L}\\p{N}]';
}
/**
* Get the default value for inputmode.
* If inputmode is provided, use it.
* Otherwise, use the default inputmode based on type
*/
getInputmode() {
const { inputmode } = this;
if (inputmode) {
return inputmode;
}
if (this.type == 'number') {
return 'numeric';
}
else {
return 'text';
}
}
/**
* Initializes the input values array based on the current value prop.
* This splits the value into individual characters and validates them against
* the allowed pattern. The values are then used as the values in the native
* input boxes and the value of the input group is updated.
*/
initializeValues() {
// Clear all input values
this.inputValues = Array(this.length).fill('');
// If the value is null, undefined, or an empty string, return
if (this.value == null || String(this.value).length === 0) {
return;
}
// Split the value into individual characters and validate
// them against the allowed pattern
const chars = String(this.value).split('').slice(0, this.length);
chars.forEach((char, index) => {
if (this.validKeyPattern.test(char)) {
this.inputValues[index] = char;
}
});
// Update the value without emitting events
this.value = this.inputValues.join('');
this.previousInputValues = [...this.inputValues];
}
/**
* Updates the value of the input group.
* This updates the value of the input group and emits an `ionChange` event.
* If all of the input boxes are filled, it emits an `ionComplete` event.
*/
updateValue(event) {
const { inputValues, length } = this;
const newValue = inputValues.join('');
this.value = newValue;
this.emitIonInput(event);
if (newValue.length === length) {
this.ionComplete.emit({ value: newValue });
}
}
/**
* Emits an `ionChange` event.
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitIonChange(event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
this.ionChange.emit({ value: newValue, event });
}
/**
* Emits an `ionInput` event.
* This is used to emit the input value when the user types,
* backspaces, or pastes.
*/
emitIonInput(event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
this.ionInput.emit({ value: newValue, event });
}
/**
* Focuses the next input box.
*/
focusNext(currentIndex) {
var _a;
const { inputRefs, length } = this;
if (currentIndex < length - 1) {
(_a = inputRefs[currentIndex + 1]) === null || _a === void 0 ? void 0 : _a.focus();
}
}
/**
* Focuses the previous input box.
*/
focusPrevious(currentIndex) {
var _a;
const { inputRefs } = this;
if (currentIndex > 0) {
(_a = inputRefs[currentIndex - 1]) === null || _a === void 0 ? void 0 : _a.focus();
}
}
/**
* Searches through the input values and returns the index
* of the first empty input.
* Returns -1 if all inputs are filled.
*/
getFirstEmptyIndex() {
var _a;
const { inputValues, length } = this;
// Create an array of the same length as the input OTP
// and fill it with the input values
const values = Array.from({ length }, (_, i) => inputValues[i] || '');
return (_a = values.findIndex((value) => !value || value === '')) !== null && _a !== void 0 ? _a : -1;
}
/**
* Returns the index of the input that should be tabbed to.
* If all inputs are filled, returns the last input's index.
* Otherwise, returns the index of the first empty input.
*/
getTabbableIndex() {
const { length } = this;
const firstEmptyIndex = this.getFirstEmptyIndex();
return firstEmptyIndex === -1 ? length - 1 : firstEmptyIndex;
}
/**
* Updates the tabIndexes for the input boxes.
* This is used to ensure that the correct input is
* focused when the user navigates using the tab key.
*/
updateTabIndexes() {
const { inputRefs, inputValues, length } = this;
// Find first empty index after any filled boxes
let firstEmptyIndex = -1;
for (let i = 0; i < length; i++) {
if (!inputValues[i] || inputValues[i] === '') {
firstEmptyIndex = i;
break;
}
}
// Update tabIndex and aria-hidden for all inputs
inputRefs.forEach((input, index) => {
const shouldBeTabbable = firstEmptyIndex === -1 ? index === length - 1 : firstEmptyIndex === index;
input.tabIndex = shouldBeTabbable ? 0 : -1;
// If the input is empty and not the first empty input,
// it should be hidden from screen readers.
const isEmpty = !inputValues[index] || inputValues[index] === '';
input.setAttribute('aria-hidden', isEmpty && !shouldBeTabbable ? 'true' : 'false');
});
}
/**
* Determines if a separator should be shown for a given index by
* checking if the index is included in the parsed separators array.
*/
showSeparator(index) {
const { length } = this;
return this.parsedSeparators.includes(index + 1) && index < length - 1;
}
render() {
var _a, _b;
const { autocapitalize, color, disabled, el, fill, hasFocus, inheritedAttributes, inputId, inputRefs, inputValues, length, readonly, shape, size, } = this;
const mode = getIonMode$1(this);
const inputmode = this.getInputmode();
const tabbableIndex = this.getTabbableIndex();
const pattern = this.getPattern();
const hasDescription = ((_b = (_a = el.querySelector('.input-otp-description')) === null || _a === void 0 ? void 0 : _a.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== '';
return (hAsync(Host, { key: 'f15a29fb17b681ef55885ca36d3d5f899cbaca83', class: createColorClasses$1(color, {
[mode]: true,
'has-focus': hasFocus,
[`input-otp-size-${size}`]: true,
[`input-otp-shape-${shape}`]: true,
[`input-otp-fill-${fill}`]: true,
'input-otp-disabled': disabled,
'input-otp-readonly': readonly,
}) }, hAsync("div", Object.assign({ key: 'd7e1d4edd8aafcf2ed4313301287282e90fc7e82', role: "group", "aria-label": "One-time password input", class: "input-otp-group" }, inheritedAttributes), Array.from({ length }).map((_, index) => (hAsync(Fragment, null, hAsync("div", { class: "native-wrapper" }, hAsync("input", { class: "native-input", id: `${inputId}-${index}`, "aria-label": `Input ${index + 1} of ${length}`, type: "text", autoCapitalize: autocapitalize, inputmode: inputmode, pattern: pattern, disabled: disabled, readOnly: readonly, tabIndex: index === tabbableIndex ? 0 : -1, value: inputValues[index] || '', autocomplete: "one-time-code", ref: (el) => (inputRefs[index] = el), onInput: this.onInput(index), onBlur: this.onBlur, onFocus: this.onFocus(index), onKeyDown: this.onKeyDown(index), onPaste: this.onPaste })), this.showSeparator(index) && hAsync("div", { class: "input-otp-separator" }))))), hAsync("div", { key: '3724a3159d02860971879a906092f9965f5a7c47', class: {
'input-otp-description': true,
'input-otp-description-hidden': !hasDescription,
} }, hAsync("slot", { key: '11baa2624926a08274508afe0833d9237a8dc35c' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"value": ["valueChanged"],
"separators": ["processSeparators"],
"length": ["processSeparators"]
}; }
static get style() { return {
ios: inputOtpIosCss,
md: inputOtpMdCss
}; }
static get cmpMeta() { return {
"$flags$": 294,
"$tagName$": "ion-input-otp",
"$members$": {
"autocapitalize": [1],
"color": [513],
"disabled": [516],
"fill": [1],
"inputmode": [1],
"length": [2],
"pattern": [1],
"readonly": [516],
"separators": [1],
"shape": [1],
"size": [1],
"type": [1],
"value": [1032],
"inputValues": [32],
"hasFocus": [32],
"previousInputValues": [32],
"setFocus": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["disabled", "disabled"], ["readonly", "readonly"]]
}; }
}
let inputIds = 0;
const iosInputPasswordToggleCss = "";
const mdInputPasswordToggleCss = "";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class InputPasswordToggle {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* @internal
*/
this.type = 'password';
this.togglePasswordVisibility = () => {
const { inputElRef } = this;
if (!inputElRef) {
return;
}
inputElRef.type = inputElRef.type === 'text' ? 'password' : 'text';
};
}
/**
* Whenever the input type changes we need to re-run validation to ensure the password
* toggle is being used with the correct input type. If the application changes the type
* outside of this component we also need to re-render so the correct icon is shown.
*/
onTypeChange(newValue) {
if (newValue !== 'text' && newValue !== 'password') {
printIonWarning(`[ion-input-password-toggle] - Only inputs of type "text" or "password" are supported. Input of type "${newValue}" is not compatible.`, this.el);
return;
}
}
connectedCallback() {
const { el } = this;
const inputElRef = (this.inputElRef = el.closest('ion-input'));
if (!inputElRef) {
printIonWarning('[ion-input-password-toggle] - No ancestor ion-input found. This component must be slotted inside of an ion-input.', el);
return;
}
/**
* Important: Set the type in connectedCallback because the default value
* of this.type may not always be accurate. Usually inputs have the "password" type
* but it is possible to have the input to initially have the "text" type. In that scenario
* the wrong icon will show briefly before switching to the correct icon. Setting the
* type here allows us to avoid that flicker.
*/
this.type = inputElRef.type;
}
disconnectedCallback() {
this.inputElRef = null;
}
render() {
var _a, _b;
const { color, type } = this;
const mode = getIonMode$1(this);
const showPasswordIcon = (_a = this.showIcon) !== null && _a !== void 0 ? _a : eye;
const hidePasswordIcon = (_b = this.hideIcon) !== null && _b !== void 0 ? _b : eyeOff;
const isPasswordVisible = type === 'text';
return (hAsync(Host, { key: '91bc55664d496fe457518bd112865dd7811d0c17', class: createColorClasses$1(color, {
[mode]: true,
}) }, hAsync("ion-button", { key: 'f3e436422110c9cb4d5c0b83500255b24ab4cdef', mode: mode, color: color, fill: "clear", shape: "round", "aria-checked": isPasswordVisible ? 'true' : 'false', "aria-label": isPasswordVisible ? 'Hide password' : 'Show password', role: "switch", type: "button", onPointerDown: (ev) => {
/**
* This prevents mobile browsers from
* blurring the input when the password toggle
* button is activated.
*/
ev.preventDefault();
}, onClick: this.togglePasswordVisibility }, hAsync("ion-icon", { key: '5c8b121153f148f92aa7cba0447673a4f6f3ad1e', slot: "icon-only", "aria-hidden": "true", icon: isPasswordVisible ? hidePasswordIcon : showPasswordIcon }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"type": ["onTypeChange"]
}; }
static get style() { return {
ios: iosInputPasswordToggleCss,
md: mdInputPasswordToggleCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-input-password-toggle",
"$members$": {
"color": [513],
"showIcon": [1, "show-icon"],
"hideIcon": [1, "hide-icon"],
"type": [1025]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const itemIosCss = ":host{--border-radius:0px;--border-width:0px;--border-style:solid;--padding-top:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--inner-border-width:0px;--inner-padding-top:0px;--inner-padding-bottom:0px;--inner-padding-start:0px;--inner-padding-end:0px;--inner-box-shadow:none;--detail-icon-color:initial;--detail-icon-font-size:1.25em;--detail-icon-opacity:0.25;--color-activated:var(--color);--color-focused:var(--color);--color-hover:var(--color);--ripple-color:currentColor;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:block;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;outline:none;color:var(--color);font-family:var(--ion-font-family, inherit);text-align:initial;text-decoration:none;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.ion-color) .item-native{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.ion-color) .item-native,:host(.ion-color) .item-inner{border-color:var(--ion-color-shade)}:host(.ion-activated) .item-native{color:var(--color-activated)}:host(.ion-activated) .item-native::after{background:var(--background-activated);opacity:var(--background-activated-opacity)}:host(.ion-color.ion-activated) .item-native{color:var(--ion-color-contrast)}:host(.ion-focused) .item-native{color:var(--color-focused)}:host(.ion-focused) .item-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}:host(.ion-color.ion-focused) .item-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-focused) .item-native::after{background:var(--ion-color-contrast)}@media (any-hover: hover){:host(.ion-activatable:not(.ion-focused):hover) .item-native{color:var(--color-hover)}:host(.ion-activatable:not(.ion-focused):hover) .item-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}:host(.ion-color.ion-activatable:not(.ion-focused):hover) .item-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-activatable:not(.ion-focused):hover) .item-native::after{background:var(--ion-color-contrast)}}:host(.item-control-needs-pointer-cursor){cursor:pointer}:host(.item-interactive-disabled:not(.item-multiple-inputs)){cursor:default;pointer-events:none}:host(.item-disabled){cursor:default;opacity:0.3;pointer-events:none}.item-native{border-radius:var(--border-radius);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;padding-right:var(--padding-end);padding-left:calc(var(--padding-start) + var(--ion-safe-area-left, 0px));display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:100%;min-height:var(--min-height);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:var(--background);overflow:inherit;z-index:1;-webkit-box-sizing:border-box;box-sizing:border-box}:host-context([dir=rtl]) .item-native{padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}[dir=rtl] .item-native{padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}@supports selector(:dir(rtl)){.item-native:dir(rtl){padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}}.item-native::-moz-focus-inner{border:0}.item-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0;-webkit-transition:var(--transition);transition:var(--transition);z-index:-1}button,a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none}.item-inner{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--inner-padding-top);padding-bottom:var(--inner-padding-bottom);padding-right:calc(var(--ion-safe-area-right, 0px) + var(--inner-padding-end));padding-left:var(--inner-padding-start);display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;min-height:inherit;border-width:var(--inner-border-width);border-style:var(--border-style);border-color:var(--border-color);-webkit-box-shadow:var(--inner-box-shadow);box-shadow:var(--inner-box-shadow);overflow:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}:host-context([dir=rtl]) .item-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}[dir=rtl] .item-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}@supports selector(:dir(rtl)){.item-inner:dir(rtl){padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}}.item-detail-icon{-webkit-margin-start:calc(var(--inner-padding-end) / 2);margin-inline-start:calc(var(--inner-padding-end) / 2);-webkit-margin-end:-6px;margin-inline-end:-6px;color:var(--detail-icon-color);font-size:var(--detail-icon-font-size);opacity:var(--detail-icon-opacity)}::slotted(ion-icon){font-size:1.6em}::slotted(ion-button){--margin-top:0;--margin-bottom:0;--margin-start:0;--margin-end:0;z-index:1}::slotted(ion-label:not([slot=end])){-ms-flex:1;flex:1;width:-webkit-min-content;width:-moz-min-content;width:min-content;max-width:100%}:host(.item-input){-ms-flex-align:center;align-items:center}.input-wrapper{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;text-overflow:ellipsis;overflow:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.item-label-stacked),:host(.item-label-floating){-ms-flex-align:start;align-items:start}:host(.item-label-stacked) .input-wrapper,:host(.item-label-floating) .input-wrapper{-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column}:host(.item-multiple-inputs) ::slotted(ion-checkbox),:host(.item-multiple-inputs) ::slotted(ion-datetime),:host(.item-multiple-inputs) ::slotted(ion-radio){position:relative}:host(.item-textarea){-ms-flex-align:stretch;align-items:stretch}::slotted(ion-reorder[slot]){margin-top:0;margin-bottom:0}ion-ripple-effect{color:var(--ripple-color)}:host{--min-height:44px;--transition:background-color 200ms linear, opacity 200ms linear;--padding-start:16px;--inner-padding-end:16px;--inner-border-width:0px 0px 0.55px 0px;--background:var(--ion-item-background, var(--ion-background-color, #fff));--background-activated:var(--ion-text-color, #000);--background-focused:var(--ion-text-color, #000);--background-hover:currentColor;--background-activated-opacity:.12;--background-focused-opacity:.15;--background-hover-opacity:.04;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));--color:var(--ion-item-color, var(--ion-text-color, #000));font-size:1rem}:host(.ion-activated){--transition:none}:host(.ion-color.ion-focused) .item-native::after{background:#000;opacity:0.15}:host(.ion-color.ion-activated) .item-native::after{background:#000;opacity:0.12}:host(.item-lines-full){--border-width:0px 0px 0.55px 0px}:host(.item-lines-inset){--inner-border-width:0px 0px 0.55px 0px}:host(.item-lines-inset),:host(.item-lines-none){--border-width:0px}:host(.item-lines-full),:host(.item-lines-none){--inner-border-width:0px}::slotted([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:2px;margin-bottom:2px}::slotted(ion-icon[slot=start]),::slotted(ion-icon[slot=end]){margin-top:7px;margin-bottom:7px}::slotted(ion-toggle[slot=start]),::slotted(ion-toggle[slot=end]){margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}:host(.item-label-stacked) ::slotted([slot=end]),:host(.item-label-floating) ::slotted([slot=end]){margin-top:7px;margin-bottom:7px}::slotted(.button-small){--padding-top:1px;--padding-bottom:1px;--padding-start:.5em;--padding-end:.5em;min-height:24px;font-size:0.8125rem}::slotted(ion-avatar){width:36px;height:36px}::slotted(ion-thumbnail){--size:56px}::slotted(ion-avatar[slot=end]),::slotted(ion-thumbnail[slot=end]){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:8px;margin-bottom:8px}:host(.item-radio) ::slotted(ion-label),:host(.item-toggle) ::slotted(ion-label){-webkit-margin-start:0px;margin-inline-start:0px}::slotted(ion-label){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:8px;margin-inline-end:8px;margin-top:10px;margin-bottom:10px}:host(.item-label-floating),:host(.item-label-stacked){--min-height:68px}";
const itemMdCss = ":host{--border-radius:0px;--border-width:0px;--border-style:solid;--padding-top:0px;--padding-bottom:0px;--padding-end:0px;--padding-start:0px;--inner-border-width:0px;--inner-padding-top:0px;--inner-padding-bottom:0px;--inner-padding-start:0px;--inner-padding-end:0px;--inner-box-shadow:none;--detail-icon-color:initial;--detail-icon-font-size:1.25em;--detail-icon-opacity:0.25;--color-activated:var(--color);--color-focused:var(--color);--color-hover:var(--color);--ripple-color:currentColor;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:block;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;outline:none;color:var(--color);font-family:var(--ion-font-family, inherit);text-align:initial;text-decoration:none;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.ion-color) .item-native{background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.ion-color) .item-native,:host(.ion-color) .item-inner{border-color:var(--ion-color-shade)}:host(.ion-activated) .item-native{color:var(--color-activated)}:host(.ion-activated) .item-native::after{background:var(--background-activated);opacity:var(--background-activated-opacity)}:host(.ion-color.ion-activated) .item-native{color:var(--ion-color-contrast)}:host(.ion-focused) .item-native{color:var(--color-focused)}:host(.ion-focused) .item-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}:host(.ion-color.ion-focused) .item-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-focused) .item-native::after{background:var(--ion-color-contrast)}@media (any-hover: hover){:host(.ion-activatable:not(.ion-focused):hover) .item-native{color:var(--color-hover)}:host(.ion-activatable:not(.ion-focused):hover) .item-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}:host(.ion-color.ion-activatable:not(.ion-focused):hover) .item-native{color:var(--ion-color-contrast)}:host(.ion-color.ion-activatable:not(.ion-focused):hover) .item-native::after{background:var(--ion-color-contrast)}}:host(.item-control-needs-pointer-cursor){cursor:pointer}:host(.item-interactive-disabled:not(.item-multiple-inputs)){cursor:default;pointer-events:none}:host(.item-disabled){cursor:default;opacity:0.3;pointer-events:none}.item-native{border-radius:var(--border-radius);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;padding-right:var(--padding-end);padding-left:calc(var(--padding-start) + var(--ion-safe-area-left, 0px));display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:100%;min-height:var(--min-height);-webkit-transition:var(--transition);transition:var(--transition);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);outline:none;background:var(--background);overflow:inherit;z-index:1;-webkit-box-sizing:border-box;box-sizing:border-box}:host-context([dir=rtl]) .item-native{padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}[dir=rtl] .item-native{padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}@supports selector(:dir(rtl)){.item-native:dir(rtl){padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}}.item-native::-moz-focus-inner{border:0}.item-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0;-webkit-transition:var(--transition);transition:var(--transition);z-index:-1}button,a{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-user-drag:none}.item-inner{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--inner-padding-top);padding-bottom:var(--inner-padding-bottom);padding-right:calc(var(--ion-safe-area-right, 0px) + var(--inner-padding-end));padding-left:var(--inner-padding-start);display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;min-height:inherit;border-width:var(--inner-border-width);border-style:var(--border-style);border-color:var(--border-color);-webkit-box-shadow:var(--inner-box-shadow);box-shadow:var(--inner-box-shadow);overflow:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}:host-context([dir=rtl]) .item-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}[dir=rtl] .item-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}@supports selector(:dir(rtl)){.item-inner:dir(rtl){padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}}.item-detail-icon{-webkit-margin-start:calc(var(--inner-padding-end) / 2);margin-inline-start:calc(var(--inner-padding-end) / 2);-webkit-margin-end:-6px;margin-inline-end:-6px;color:var(--detail-icon-color);font-size:var(--detail-icon-font-size);opacity:var(--detail-icon-opacity)}::slotted(ion-icon){font-size:1.6em}::slotted(ion-button){--margin-top:0;--margin-bottom:0;--margin-start:0;--margin-end:0;z-index:1}::slotted(ion-label:not([slot=end])){-ms-flex:1;flex:1;width:-webkit-min-content;width:-moz-min-content;width:min-content;max-width:100%}:host(.item-input){-ms-flex-align:center;align-items:center}.input-wrapper{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;text-overflow:ellipsis;overflow:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.item-label-stacked),:host(.item-label-floating){-ms-flex-align:start;align-items:start}:host(.item-label-stacked) .input-wrapper,:host(.item-label-floating) .input-wrapper{-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column}:host(.item-multiple-inputs) ::slotted(ion-checkbox),:host(.item-multiple-inputs) ::slotted(ion-datetime),:host(.item-multiple-inputs) ::slotted(ion-radio){position:relative}:host(.item-textarea){-ms-flex-align:stretch;align-items:stretch}::slotted(ion-reorder[slot]){margin-top:0;margin-bottom:0}ion-ripple-effect{color:var(--ripple-color)}:host{--min-height:48px;--background:var(--ion-item-background, var(--ion-background-color, #fff));--background-activated:transparent;--background-focused:currentColor;--background-hover:currentColor;--background-activated-opacity:0;--background-focused-opacity:.12;--background-hover-opacity:.04;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));--color:var(--ion-item-color, var(--ion-text-color, #000));--transition:opacity 15ms linear, background-color 15ms linear;--padding-start:16px;--inner-padding-end:16px;--inner-border-width:0 0 1px 0;font-size:1rem;font-weight:normal;text-transform:none}:host(.ion-color.ion-activated) .item-native::after{background:transparent}:host(.item-interactive){--border-width:0 0 1px 0;--inner-border-width:0}:host(.item-lines-full){--border-width:0 0 1px 0}:host(.item-lines-inset){--inner-border-width:0 0 1px 0}:host(.item-lines-inset),:host(.item-lines-none){--border-width:0}:host(.item-lines-full),:host(.item-lines-none){--inner-border-width:0}:host(.item-multi-line) ::slotted([slot=start]),:host(.item-multi-line) ::slotted([slot=end]){margin-top:16px;margin-bottom:16px;-ms-flex-item-align:start;align-self:flex-start}::slotted([slot=start]){-webkit-margin-end:16px;margin-inline-end:16px}::slotted([slot=end]){-webkit-margin-start:16px;margin-inline-start:16px}::slotted(ion-icon){color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54);font-size:1.5em}:host(.ion-color) ::slotted(ion-icon){color:var(--ion-color-contrast)}::slotted(ion-icon[slot]){margin-top:12px;margin-bottom:12px}::slotted(ion-icon[slot=start]){-webkit-margin-end:32px;margin-inline-end:32px}::slotted(ion-icon[slot=end]){-webkit-margin-start:16px;margin-inline-start:16px}::slotted(ion-toggle[slot=start]),::slotted(ion-toggle[slot=end]){margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}::slotted(ion-note){margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-ms-flex-item-align:start;align-self:flex-start;font-size:0.6875rem}::slotted(ion-note[slot]){padding-left:0;padding-right:0;padding-top:18px;padding-bottom:10px}::slotted(ion-avatar){width:40px;height:40px}::slotted(ion-thumbnail){--size:56px}::slotted(ion-avatar),::slotted(ion-thumbnail){margin-top:8px;margin-bottom:8px}::slotted(ion-avatar[slot=start]),::slotted(ion-thumbnail[slot=start]){-webkit-margin-end:16px;margin-inline-end:16px}::slotted(ion-avatar[slot=end]),::slotted(ion-thumbnail[slot=end]){-webkit-margin-start:16px;margin-inline-start:16px}::slotted(ion-label){margin-left:0;margin-right:0;margin-top:10px;margin-bottom:10px}:host(.item-label-stacked) ::slotted([slot=end]),:host(.item-label-floating) ::slotted([slot=end]){margin-top:7px;margin-bottom:7px}:host(.item-toggle) ::slotted(ion-label),:host(.item-radio) ::slotted(ion-label){-webkit-margin-start:0;margin-inline-start:0}::slotted(.button-small){--padding-top:2px;--padding-bottom:2px;--padding-start:.6em;--padding-end:.6em;min-height:25px;font-size:0.75rem}:host(.item-label-floating),:host(.item-label-stacked){--min-height:55px}:host(.ion-focused:not(.ion-color)) ::slotted(.label-stacked),:host(.ion-focused:not(.ion-color)) ::slotted(.label-floating),:host(.item-has-focus:not(.ion-color)) ::slotted(.label-stacked),:host(.item-has-focus:not(.ion-color)) ::slotted(.label-floating){color:var(--ion-color-primary, #0054e9)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the item text in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the item text in LTR, and to the left in RTL.
*
* @part native - The native HTML button, anchor or div element that wraps all child elements.
* @part detail-icon - The chevron icon for the item. Only applies when `detail="true"`.
*/
class Item {
constructor(hostRef) {
registerInstance(this, hostRef);
this.labelColorStyles = {};
this.itemStyles = new Map();
this.inheritedAriaAttributes = {};
this.multipleInputs = false;
this.focusable = true;
this.isInteractive = false;
/**
* If `true`, a button tag will be rendered and the item will be tappable.
*/
this.button = false;
/**
* The icon to use when `detail` is set to `true`.
*/
this.detailIcon = chevronForward;
/**
* If `true`, the user cannot interact with the item.
*/
this.disabled = false;
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
*/
this.routerDirection = 'forward';
/**
* The type of the button. Only used when an `onclick` or `button` property is present.
*/
this.type = 'button';
// slot change listener updates state to reflect how/if item should be interactive
this.updateInteractivityOnSlotChange = () => {
this.setIsInteractive();
this.setMultipleInputs();
};
}
buttonChanged() {
// Update the focusable option when the button option is changed
this.focusable = this.isFocusable();
}
labelColorChanged(ev) {
const { color } = this;
// There will be a conflict with item color if
// we apply the label color to item, so we ignore
// the label color if the user sets a color on item
if (color === undefined) {
this.labelColorStyles = ev.detail;
}
}
itemStyle(ev) {
ev.stopPropagation();
const tagName = ev.target.tagName;
const updatedStyles = ev.detail;
const newStyles = {};
const childStyles = this.itemStyles.get(tagName) || {};
let hasStyleChange = false;
Object.keys(updatedStyles).forEach((key) => {
if (updatedStyles[key]) {
const itemKey = `item-${key}`;
if (!childStyles[itemKey]) {
hasStyleChange = true;
}
newStyles[itemKey] = true;
}
});
if (!hasStyleChange && Object.keys(newStyles).length !== Object.keys(childStyles).length) {
hasStyleChange = true;
}
if (hasStyleChange) {
this.itemStyles.set(tagName, newStyles);
}
}
connectedCallback() {
this.hasStartEl();
}
componentWillLoad() {
this.inheritedAriaAttributes = inheritAttributes$1(this.el, ['aria-label']);
}
componentDidLoad() {
raf(() => {
this.setMultipleInputs();
this.setIsInteractive();
this.focusable = this.isFocusable();
});
}
totalNestedInputs() {
// The following elements have a clickable cover that is relative to the entire item
const covers = this.el.querySelectorAll('ion-checkbox, ion-datetime, ion-select, ion-radio');
// The following elements can accept focus alongside the previous elements
// therefore if these elements are also a child of item, we don't want the
// input cover on top of those interfering with their clicks
const inputs = this.el.querySelectorAll('ion-input, ion-range, ion-searchbar, ion-segment, ion-textarea, ion-toggle');
// The following elements should also stay clickable when an input with cover is present
const clickables = this.el.querySelectorAll('ion-router-link, ion-button, a, button');
return {
covers,
inputs,
clickables,
};
}
// If the item contains multiple clickable elements and/or inputs, then the item
// should not have a clickable input cover over the entire item to prevent
// interfering with their individual click events
setMultipleInputs() {
const { covers, inputs, clickables } = this.totalNestedInputs();
// Check for multiple inputs to change the position of the input cover to relative
// for all of the covered inputs above
this.multipleInputs =
covers.length + inputs.length > 1 ||
covers.length + clickables.length > 1 ||
(covers.length > 0 && this.isClickable());
}
setIsInteractive() {
// If item contains any interactive children, set isInteractive to `true`
const { covers, inputs, clickables } = this.totalNestedInputs();
this.isInteractive = covers.length > 0 || inputs.length > 0 || clickables.length > 0;
}
// If the item contains an input including a checkbox, datetime, select, or radio
// then the item will have a clickable input cover that covers the item
// that should get the hover, focused and activated states UNLESS it has multiple
// inputs, then those need to individually get each click
hasCover() {
const inputs = this.el.querySelectorAll('ion-checkbox, ion-datetime, ion-select, ion-radio');
return inputs.length === 1 && !this.multipleInputs;
}
// If the item has an href or button property it will render a native
// anchor or button that is clickable
isClickable() {
return this.href !== undefined || this.button;
}
canActivate() {
return this.isClickable() || this.hasCover();
}
isFocusable() {
const focusableChild = this.el.querySelector('.ion-focusable');
return this.canActivate() || focusableChild !== null;
}
hasStartEl() {
const startEl = this.el.querySelector('[slot="start"]');
if (startEl !== null) {
this.el.classList.add('item-has-start-slot');
}
}
getFirstInteractive() {
const controls = this.el.querySelectorAll('ion-toggle:not([disabled]), ion-checkbox:not([disabled]), ion-radio:not([disabled]), ion-select:not([disabled]), ion-input:not([disabled]), ion-textarea:not([disabled])');
return controls[0];
}
render() {
const { detail, detailIcon, download, labelColorStyles, lines, disabled, href, rel, target, routerAnimation, routerDirection, inheritedAriaAttributes, multipleInputs, } = this;
const childStyles = {};
const mode = getIonMode$1(this);
const clickable = this.isClickable();
const canActivate = this.canActivate();
const TagType = clickable ? (href === undefined ? 'button' : 'a') : 'div';
const attrs = TagType === 'button'
? { type: this.type }
: {
download,
href,
rel,
target,
};
let clickFn = {};
const firstInteractive = this.getFirstInteractive();
// Only set onClick if the item is clickable to prevent screen
// readers from reading all items as clickable
if (clickable || (firstInteractive !== undefined && !multipleInputs)) {
clickFn = {
onClick: (ev) => {
if (clickable) {
openURL(href, ev, routerDirection, routerAnimation);
}
if (firstInteractive !== undefined && !multipleInputs) {
const path = ev.composedPath();
const target = path[0];
if (ev.isTrusted) {
/**
* Dispatches a click event to the first interactive element,
* when it is the result of a user clicking on the item.
*
* We check if the click target is in the shadow root,
* which means the user clicked on the .item-native or
* .item-inner padding.
*/
const clickedWithinShadowRoot = this.el.shadowRoot.contains(target);
if (clickedWithinShadowRoot) {
/**
* For input/textarea clicking the padding should focus the
* text field (thus making it editable). For everything else,
* we want to click the control so it activates.
*/
if (firstInteractive.tagName === 'ION-INPUT' || firstInteractive.tagName === 'ION-TEXTAREA') {
firstInteractive.setFocus();
}
firstInteractive.click();
/**
* Stop the item event from being triggered
* as the firstInteractive click event will also
* trigger the item click event.
*/
ev.stopImmediatePropagation();
}
}
}
},
};
}
const showDetail = detail !== undefined ? detail : mode === 'ios' && clickable;
this.itemStyles.forEach((value) => {
Object.assign(childStyles, value);
});
const ariaDisabled = disabled || childStyles['item-interactive-disabled'] ? 'true' : null;
const inList = hostContext('ion-list', this.el) && !hostContext('ion-radio-group', this.el);
/**
* Inputs and textareas do not need to show a cursor pointer.
* However, other form controls such as checkboxes and radios do.
*/
const firstInteractiveNeedsPointerCursor = firstInteractive !== undefined && !['ION-INPUT', 'ION-TEXTAREA'].includes(firstInteractive.tagName);
return (hAsync(Host, { key: '24b59935bd8db8b0b7f940582455a42b82cbf762', "aria-disabled": ariaDisabled, class: Object.assign(Object.assign(Object.assign({}, childStyles), labelColorStyles), createColorClasses$1(this.color, {
item: true,
[mode]: true,
'item-lines-default': lines === undefined,
[`item-lines-${lines}`]: lines !== undefined,
'item-control-needs-pointer-cursor': firstInteractiveNeedsPointerCursor,
'item-disabled': disabled,
'in-list': inList,
'item-multiple-inputs': this.multipleInputs,
'ion-activatable': canActivate,
'ion-focusable': this.focusable,
'item-rtl': document.dir === 'rtl',
})), role: inList ? 'listitem' : null }, hAsync(TagType, Object.assign({ key: 'fd77b6e5f3eb2e1857a0cdd45562d71eabd30255' }, attrs, inheritedAriaAttributes, { class: "item-native", part: "native", disabled: disabled }, clickFn), hAsync("slot", { key: '8824ac8395aafa3d63c92f2128e947cac8393ac4', name: "start", onSlotchange: this.updateInteractivityOnSlotChange }), hAsync("div", { key: '5c9127e388a432687766d86a9db91fd1663abf03', class: "item-inner" }, hAsync("div", { key: '9dc2d2f58c4067c0143b3963334c346c3c7f77df', class: "input-wrapper" }, hAsync("slot", { key: '8377d9e56dc4b1913f1346111b706e7f14c24d30', onSlotchange: this.updateInteractivityOnSlotChange })), hAsync("slot", { key: 'bc771e106174f4a84ee12e92d14df81ad7ed177d', name: "end", onSlotchange: this.updateInteractivityOnSlotChange }), showDetail && (hAsync("ion-icon", { key: '45336d121a097cbf71ee8a3f6b554745ba5e0bbf', icon: detailIcon, lazy: false, class: "item-detail-icon", part: "detail-icon", "aria-hidden": "true", "flip-rtl": detailIcon === chevronForward }))), canActivate && mode === 'md' && hAsync("ion-ripple-effect", { key: '197e244ae3bffebfa6ac9bfe7658d12e1af0ecb1' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"button": ["buttonChanged"]
}; }
static get style() { return {
ios: itemIosCss,
md: itemMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-item",
"$members$": {
"color": [513],
"button": [4],
"detail": [4],
"detailIcon": [1, "detail-icon"],
"disabled": [516],
"download": [1],
"href": [1],
"rel": [1],
"lines": [1],
"routerAnimation": [16],
"routerDirection": [1, "router-direction"],
"target": [1],
"type": [1],
"multipleInputs": [32],
"focusable": [32],
"isInteractive": [32]
},
"$listeners$": [[0, "ionColor", "labelColorChanged"], [0, "ionStyle", "itemStyle"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["disabled", "disabled"]]
}; }
}
const itemDividerIosCss = ":host{--padding-top:0px;--padding-end:0px;--padding-bottom:0px;--padding-start:0px;--inner-padding-top:0px;--inner-padding-end:0px;--inner-padding-bottom:0px;--inner-padding-start:0px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);padding-right:var(--padding-end);padding-left:calc(var(--padding-start) + var(--ion-safe-area-left, 0px));display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);overflow:hidden;z-index:100;-webkit-box-sizing:border-box;box-sizing:border-box}:host-context([dir=rtl]){padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}@supports selector(:dir(rtl)){:host(:dir(rtl)){padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.item-divider-sticky){position:-webkit-sticky;position:sticky;top:0}.item-divider-inner{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--inner-padding-top);padding-bottom:var(--inner-padding-bottom);padding-right:calc(var(--ion-safe-area-right, 0px) + var(--inner-padding-end));padding-left:var(--inner-padding-start);display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;min-height:inherit;border:0;overflow:hidden}:host-context([dir=rtl]) .item-divider-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}[dir=rtl] .item-divider-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}@supports selector(:dir(rtl)){.item-divider-inner:dir(rtl){padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}}.item-divider-wrapper{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;text-overflow:ellipsis;overflow:hidden}:host{--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));--padding-start:16px;--inner-padding-end:8px;border-radius:0;position:relative;min-height:28px;font-size:1.0625rem;font-weight:600}:host([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:2px;margin-bottom:2px}::slotted(ion-icon[slot=start]),::slotted(ion-icon[slot=end]){margin-top:7px;margin-bottom:7px}::slotted(h1){margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px}::slotted(h2){margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px}::slotted(h3),::slotted(h4),::slotted(h5),::slotted(h6){margin-left:0;margin-right:0;margin-top:0;margin-bottom:3px}::slotted(p){margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;color:var(--ion-text-color-step-550, #a3a3a3);font-size:0.875rem;line-height:normal;text-overflow:inherit;overflow:inherit}::slotted(h2:last-child) ::slotted(h3:last-child),::slotted(h4:last-child),::slotted(h5:last-child),::slotted(h6:last-child),::slotted(p:last-child){margin-bottom:0}";
const itemDividerMdCss = ":host{--padding-top:0px;--padding-end:0px;--padding-bottom:0px;--padding-start:0px;--inner-padding-top:0px;--inner-padding-end:0px;--inner-padding-bottom:0px;--inner-padding-start:0px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);padding-right:var(--padding-end);padding-left:calc(var(--padding-start) + var(--ion-safe-area-left, 0px));display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit);overflow:hidden;z-index:100;-webkit-box-sizing:border-box;box-sizing:border-box}:host-context([dir=rtl]){padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}@supports selector(:dir(rtl)){:host(:dir(rtl)){padding-right:calc(var(--padding-start) + var(--ion-safe-area-right, 0px));padding-left:var(--padding-end)}}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}:host(.item-divider-sticky){position:-webkit-sticky;position:sticky;top:0}.item-divider-inner{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-top:var(--inner-padding-top);padding-bottom:var(--inner-padding-bottom);padding-right:calc(var(--ion-safe-area-right, 0px) + var(--inner-padding-end));padding-left:var(--inner-padding-start);display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;min-height:inherit;border:0;overflow:hidden}:host-context([dir=rtl]) .item-divider-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}[dir=rtl] .item-divider-inner{padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}@supports selector(:dir(rtl)){.item-divider-inner:dir(rtl){padding-right:var(--inner-padding-start);padding-left:calc(var(--ion-safe-area-left, 0px) + var(--inner-padding-end))}}.item-divider-wrapper{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;text-overflow:ellipsis;overflow:hidden}:host{--background:var(--ion-background-color, #fff);--color:var(--ion-color-step-400, var(--ion-text-color-step-600, #999999));--padding-start:16px;--inner-padding-end:16px;min-height:30px;border-bottom:1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));font-size:0.875rem}::slotted([slot=start]){-webkit-margin-end:16px;margin-inline-end:16px}::slotted([slot=end]){-webkit-margin-start:16px;margin-inline-start:16px}::slotted(ion-label){margin-left:0;margin-right:0;margin-top:13px;margin-bottom:10px}::slotted(ion-icon){color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.54);font-size:1.7142857143em}:host(.ion-color) ::slotted(ion-icon){color:var(--ion-color-contrast)}::slotted(ion-icon[slot]){margin-top:12px;margin-bottom:12px}::slotted(ion-icon[slot=start]){-webkit-margin-end:32px;margin-inline-end:32px}::slotted(ion-icon[slot=end]){-webkit-margin-start:16px;margin-inline-start:16px}::slotted(ion-note){margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-ms-flex-item-align:start;align-self:flex-start;font-size:0.6875rem}::slotted(ion-note[slot]){padding-left:0;padding-right:0;padding-top:18px;padding-bottom:10px}::slotted(ion-avatar){width:40px;height:40px}::slotted(ion-thumbnail){--size:56px}::slotted(ion-avatar),::slotted(ion-thumbnail){margin-top:8px;margin-bottom:8px}::slotted(ion-avatar[slot=start]),::slotted(ion-thumbnail[slot=start]){-webkit-margin-end:16px;margin-inline-end:16px}::slotted(ion-avatar[slot=end]),::slotted(ion-thumbnail[slot=end]){-webkit-margin-start:16px;margin-inline-start:16px}::slotted(h1){margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px}::slotted(h2){margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px}::slotted(h3,h4,h5,h6){margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px}::slotted(p){margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));font-size:0.875rem;line-height:normal;text-overflow:inherit;overflow:inherit}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the divider text in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the divider text in LTR, and to the left in RTL.
*/
class ItemDivider {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* When it's set to `true`, the item-divider will stay visible when it reaches the top
* of the viewport until the next `ion-item-divider` replaces it.
*
* This feature relies in `position:sticky`:
* https://caniuse.com/#feat=css-sticky
*/
this.sticky = false;
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '1523095ce4af3f2611512ff0948ead659959ee4a', class: createColorClasses$1(this.color, {
[mode]: true,
'item-divider-sticky': this.sticky,
item: true,
}) }, hAsync("slot", { key: '39105d888e115416c3a3fe588da44b4c61f4e5fe', name: "start" }), hAsync("div", { key: '67e16f1056bd39187f3629c1bb383b7abbda829b', class: "item-divider-inner" }, hAsync("div", { key: 'b3a218fdcc7b9aeab6e0155340152d39fa0b6329', class: "item-divider-wrapper" }, hAsync("slot", { key: '69d8587533b387869d34b075d02f61396858fc90' })), hAsync("slot", { key: 'b91c654699b3b26d0012ea0c719c4a07d1fcfbaa', name: "end" }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: itemDividerIosCss,
md: itemDividerMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-item-divider",
"$members$": {
"color": [513],
"sticky": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const itemGroupIosCss = "ion-item-group{display:block}";
const itemGroupMdCss = "ion-item-group{display:block}";
class ItemGroup {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'e49dc8f99247d2431d7c6db01b6e021a0f5b1c37', role: "group", class: {
[mode]: true,
// Used internally for styling
[`item-group-${mode}`]: true,
item: true,
} }));
}
static get style() { return {
ios: itemGroupIosCss,
md: itemGroupMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-item-group",
"$members$": undefined,
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const itemOptionIosCss = ":host{--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff);background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit)}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}.button-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;-webkit-padding-start:0.7em;padding-inline-start:0.7em;-webkit-padding-end:0.7em;padding-inline-end:0.7em;padding-top:0;padding-bottom:0;display:inline-block;position:relative;width:100%;height:100%;border:0;outline:none;background:transparent;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-sizing:border-box;box-sizing:border-box}.button-inner{display:-ms-flexbox;display:flex;-ms-flex-flow:column nowrap;flex-flow:column nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%}.horizontal-wrapper{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%}::slotted(*){-ms-flex-negative:0;flex-shrink:0}::slotted([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:5px;margin-inline-end:5px;margin-top:0;margin-bottom:0}::slotted([slot=end]){-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}::slotted([slot=icon-only]){padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:0;margin-bottom:0;min-width:0.9em;font-size:1.8em}:host(.item-option-expandable){-ms-flex-negative:0;flex-shrink:0;-webkit-transition-duration:0;transition-duration:0;-webkit-transition-property:none;transition-property:none;-webkit-transition-timing-function:cubic-bezier(0.65, 0.05, 0.36, 1);transition-timing-function:cubic-bezier(0.65, 0.05, 0.36, 1)}:host(.item-option-disabled){pointer-events:none}:host(.item-option-disabled) .button-native{cursor:default;opacity:0.5;pointer-events:none}:host{font-size:clamp(16px, 1rem, 35.2px)}:host(.ion-activated){background:var(--ion-color-primary-shade, #004acd)}:host(.ion-color.ion-activated){background:var(--ion-color-shade)}";
const itemOptionMdCss = ":host{--background:var(--ion-color-primary, #0054e9);--color:var(--ion-color-primary-contrast, #fff);background:var(--background);color:var(--color);font-family:var(--ion-font-family, inherit)}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}.button-native{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;-webkit-padding-start:0.7em;padding-inline-start:0.7em;-webkit-padding-end:0.7em;padding-inline-end:0.7em;padding-top:0;padding-bottom:0;display:inline-block;position:relative;width:100%;height:100%;border:0;outline:none;background:transparent;cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none;-webkit-box-sizing:border-box;box-sizing:border-box}.button-inner{display:-ms-flexbox;display:flex;-ms-flex-flow:column nowrap;flex-flow:column nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%}.horizontal-wrapper{display:-ms-flexbox;display:flex;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%}::slotted(*){-ms-flex-negative:0;flex-shrink:0}::slotted([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:5px;margin-inline-end:5px;margin-top:0;margin-bottom:0}::slotted([slot=end]){-webkit-margin-start:5px;margin-inline-start:5px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}::slotted([slot=icon-only]){padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;-webkit-margin-start:10px;margin-inline-start:10px;-webkit-margin-end:10px;margin-inline-end:10px;margin-top:0;margin-bottom:0;min-width:0.9em;font-size:1.8em}:host(.item-option-expandable){-ms-flex-negative:0;flex-shrink:0;-webkit-transition-duration:0;transition-duration:0;-webkit-transition-property:none;transition-property:none;-webkit-transition-timing-function:cubic-bezier(0.65, 0.05, 0.36, 1);transition-timing-function:cubic-bezier(0.65, 0.05, 0.36, 1)}:host(.item-option-disabled){pointer-events:none}:host(.item-option-disabled) .button-native{cursor:default;opacity:0.5;pointer-events:none}:host{font-size:0.875rem;font-weight:500;text-transform:uppercase}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the option text in LTR, and to the right in RTL.
* @slot top - Content is placed above the option text.
* @slot icon-only - Should be used on an icon in an option that has no text.
* @slot bottom - Content is placed below the option text.
* @slot end - Content is placed to the right of the option text in LTR, and to the left in RTL.
*
* @part native - The native HTML button or anchor element that wraps all child elements.
*/
class ItemOption {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the user cannot interact with the item option.
*/
this.disabled = false;
/**
* If `true`, the option will expand to take up the available width and cover any other options.
*/
this.expandable = false;
/**
* The type of the button.
*/
this.type = 'button';
this.onClick = (ev) => {
const el = ev.target.closest('ion-item-option');
if (el) {
ev.preventDefault();
}
};
}
render() {
const { disabled, expandable, href } = this;
const TagType = href === undefined ? 'button' : 'a';
const mode = getIonMode$1(this);
const attrs = TagType === 'button'
? { type: this.type }
: {
download: this.download,
href: this.href,
target: this.target,
};
return (hAsync(Host, { key: '189a0040b97163b2336bf216baa71d584c5923a8', onClick: this.onClick, class: createColorClasses$1(this.color, {
[mode]: true,
'item-option-disabled': disabled,
'item-option-expandable': expandable,
'ion-activatable': true,
}) }, hAsync(TagType, Object.assign({ key: '5a7140eb99da5ec82fe2ea3ea134513130763399' }, attrs, { class: "button-native", part: "native", disabled: disabled }), hAsync("span", { key: '9b8577e612706b43e575c9a20f2f9d35c0d1bcb1', class: "button-inner" }, hAsync("slot", { key: '9acb82f04e4822bfaa363cc2c4d29d5c0fec0ad6', name: "top" }), hAsync("div", { key: '66f5fb4fdd0c39f205574c602c793dcf109c7a17', class: "horizontal-wrapper" }, hAsync("slot", { key: '3761a32bca7c6c41b7eb394045497cfde181a62a', name: "start" }), hAsync("slot", { key: 'a96a568955cf6962883dc6771726d3d07462da00', name: "icon-only" }), hAsync("slot", { key: 'af5dfe5eb41456b9359bafe3615b576617ed7b57' }), hAsync("slot", { key: '00426958066ab7b949ff966fabad5cf8a0b54079', name: "end" })), hAsync("slot", { key: 'ae66c8bd536a9f27865f49240980d7b4b831b229', name: "bottom" })), mode === 'md' && hAsync("ion-ripple-effect", { key: '30df6c935ef8a3f28a6bc1f3bb162ca4f80aaf26' }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: itemOptionIosCss,
md: itemOptionMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-item-option",
"$members$": {
"color": [513],
"disabled": [4],
"download": [1],
"expandable": [4],
"href": [1],
"rel": [1],
"target": [1],
"type": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const itemOptionsIosCss = "ion-item-options{top:0;right:0;-ms-flex-pack:end;justify-content:flex-end;display:none;position:absolute;height:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1}:host-context([dir=rtl]) ion-item-options{-ms-flex-pack:start;justify-content:flex-start}:host-context([dir=rtl]) ion-item-options:not(.item-options-end){right:auto;left:0;-ms-flex-pack:end;justify-content:flex-end}[dir=rtl] ion-item-options{-ms-flex-pack:start;justify-content:flex-start}[dir=rtl] ion-item-options:not(.item-options-end){right:auto;left:0;-ms-flex-pack:end;justify-content:flex-end}@supports selector(:dir(rtl)){ion-item-options:dir(rtl){-ms-flex-pack:start;justify-content:flex-start}ion-item-options:dir(rtl):not(.item-options-end){right:auto;left:0;-ms-flex-pack:end;justify-content:flex-end}}.item-options-start{right:auto;left:0;-ms-flex-pack:start;justify-content:flex-start}:host-context([dir=rtl]) .item-options-start{-ms-flex-pack:end;justify-content:flex-end}[dir=rtl] .item-options-start{-ms-flex-pack:end;justify-content:flex-end}@supports selector(:dir(rtl)){.item-options-start:dir(rtl){-ms-flex-pack:end;justify-content:flex-end}}[dir=ltr] .item-options-start ion-item-option:first-child,[dir=rtl] .item-options-start ion-item-option:last-child{padding-left:var(--ion-safe-area-left)}[dir=ltr] .item-options-end ion-item-option:last-child,[dir=rtl] .item-options-end ion-item-option:first-child{padding-right:var(--ion-safe-area-right)}:host-context([dir=rtl]) .item-sliding-active-slide.item-sliding-active-options-start ion-item-options:not(.item-options-end){width:100%;visibility:visible}[dir=rtl] .item-sliding-active-slide.item-sliding-active-options-start ion-item-options:not(.item-options-end){width:100%;visibility:visible}@supports selector(:dir(rtl)){.item-sliding-active-slide:dir(rtl).item-sliding-active-options-start ion-item-options:not(.item-options-end){width:100%;visibility:visible}}.item-sliding-active-slide ion-item-options{display:-ms-flexbox;display:flex;visibility:hidden}.item-sliding-active-slide.item-sliding-active-options-start .item-options-start,.item-sliding-active-slide.item-sliding-active-options-end ion-item-options:not(.item-options-start){width:100%;visibility:visible}.item-options-ios{border-bottom-width:0;border-bottom-style:solid;border-bottom-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))))}.item-options-ios.item-options-end{border-bottom-width:0.55px}.list-ios-lines-none .item-options-ios{border-bottom-width:0}.list-ios-lines-full .item-options-ios,.list-ios-lines-inset .item-options-ios.item-options-end{border-bottom-width:0.55px}";
const itemOptionsMdCss = "ion-item-options{top:0;right:0;-ms-flex-pack:end;justify-content:flex-end;display:none;position:absolute;height:100%;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1}:host-context([dir=rtl]) ion-item-options{-ms-flex-pack:start;justify-content:flex-start}:host-context([dir=rtl]) ion-item-options:not(.item-options-end){right:auto;left:0;-ms-flex-pack:end;justify-content:flex-end}[dir=rtl] ion-item-options{-ms-flex-pack:start;justify-content:flex-start}[dir=rtl] ion-item-options:not(.item-options-end){right:auto;left:0;-ms-flex-pack:end;justify-content:flex-end}@supports selector(:dir(rtl)){ion-item-options:dir(rtl){-ms-flex-pack:start;justify-content:flex-start}ion-item-options:dir(rtl):not(.item-options-end){right:auto;left:0;-ms-flex-pack:end;justify-content:flex-end}}.item-options-start{right:auto;left:0;-ms-flex-pack:start;justify-content:flex-start}:host-context([dir=rtl]) .item-options-start{-ms-flex-pack:end;justify-content:flex-end}[dir=rtl] .item-options-start{-ms-flex-pack:end;justify-content:flex-end}@supports selector(:dir(rtl)){.item-options-start:dir(rtl){-ms-flex-pack:end;justify-content:flex-end}}[dir=ltr] .item-options-start ion-item-option:first-child,[dir=rtl] .item-options-start ion-item-option:last-child{padding-left:var(--ion-safe-area-left)}[dir=ltr] .item-options-end ion-item-option:last-child,[dir=rtl] .item-options-end ion-item-option:first-child{padding-right:var(--ion-safe-area-right)}:host-context([dir=rtl]) .item-sliding-active-slide.item-sliding-active-options-start ion-item-options:not(.item-options-end){width:100%;visibility:visible}[dir=rtl] .item-sliding-active-slide.item-sliding-active-options-start ion-item-options:not(.item-options-end){width:100%;visibility:visible}@supports selector(:dir(rtl)){.item-sliding-active-slide:dir(rtl).item-sliding-active-options-start ion-item-options:not(.item-options-end){width:100%;visibility:visible}}.item-sliding-active-slide ion-item-options{display:-ms-flexbox;display:flex;visibility:hidden}.item-sliding-active-slide.item-sliding-active-options-start .item-options-start,.item-sliding-active-slide.item-sliding-active-options-end ion-item-options:not(.item-options-start){width:100%;visibility:visible}.item-options-md{border-bottom-width:0;border-bottom-style:solid;border-bottom-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))))}.list-md-lines-none .item-options-md{border-bottom-width:0}.list-md-lines-full .item-options-md,.list-md-lines-inset .item-options-md.item-options-end{border-bottom-width:1px}";
class ItemOptions {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionSwipe = createEvent(this, "ionSwipe", 7);
/**
* The side the option button should be on. Possible values: `"start"` and `"end"`. If you have multiple `ion-item-options`, a side must be provided for each.
*
*/
this.side = 'end';
}
/** @internal */
async fireSwipeEvent() {
this.ionSwipe.emit({
side: this.side,
});
}
render() {
const mode = getIonMode$1(this);
const isEnd = isEndSide(this.side);
return (hAsync(Host, { key: '05a22a505e043c2715e3805e5e26ab4668940af0', class: {
[mode]: true,
// Used internally for styling
[`item-options-${mode}`]: true,
/**
* Note: The "start" and "end" terms refer to the
* direction ion-item-option instances within ion-item-options flow.
* They do not refer to how ion-item-options flows within ion-item-sliding.
* As a result, "item-options-start" means the ion-item-options container
* always appears on the left, and "item-options-end" means the ion-item-options
* container always appears on the right.
*/
'item-options-start': !isEnd,
'item-options-end': isEnd,
} }));
}
get el() { return getElement(this); }
static get style() { return {
ios: itemOptionsIosCss,
md: itemOptionsMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-item-options",
"$members$": {
"side": [1],
"fireSwipeEvent": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const watchForOptions = (containerEl, tagName, onChange) => {
if (typeof MutationObserver === 'undefined') {
return;
}
const mutation = new MutationObserver((mutationList) => {
onChange(getSelectedOption(mutationList, tagName));
});
mutation.observe(containerEl, {
childList: true,
subtree: true,
});
return mutation;
};
const getSelectedOption = (mutationList, tagName) => {
let newOption;
mutationList.forEach((mut) => {
// eslint-disable-next-line @typescript-eslint/prefer-for-of
for (let i = 0; i < mut.addedNodes.length; i++) {
newOption = findCheckedOption(mut.addedNodes[i], tagName) || newOption;
}
});
return newOption;
};
/**
* The "value" key is only set on some components such as ion-select-option.
* As a result, we create a default union type of HTMLElement and the "value" key.
* However, implementers are required to provide the appropriate component type
* such as HTMLIonSelectOptionElement.
*/
const findCheckedOption = (node, tagName) => {
/**
* https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
* The above check ensures "node" is an Element (nodeType 1).
*/
if (node.nodeType !== 1) {
return undefined;
}
// HTMLElement inherits from Element, so we cast "el" as T.
const el = node;
const options = el.tagName === tagName.toUpperCase() ? [el] : Array.from(el.querySelectorAll(tagName));
return options.find((o) => o.value === el.value);
};
const itemSlidingCss = "ion-item-sliding{display:block;position:relative;width:100%;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}ion-item-sliding .item{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.item-sliding-active-slide .item{position:relative;-webkit-transition:-webkit-transform 500ms cubic-bezier(0.36, 0.66, 0.04, 1);transition:-webkit-transform 500ms cubic-bezier(0.36, 0.66, 0.04, 1);transition:transform 500ms cubic-bezier(0.36, 0.66, 0.04, 1);transition:transform 500ms cubic-bezier(0.36, 0.66, 0.04, 1), -webkit-transform 500ms cubic-bezier(0.36, 0.66, 0.04, 1);opacity:1;z-index:2;pointer-events:none;will-change:transform}.item-sliding-closing ion-item-options{pointer-events:none}.item-sliding-active-swipe-end .item-options-end .item-option-expandable{padding-left:100%;-ms-flex-order:1;order:1;-webkit-transition-duration:0.6s;transition-duration:0.6s;-webkit-transition-property:padding-left;transition-property:padding-left}:host-context([dir=rtl]) .item-sliding-active-swipe-end .item-options-end .item-option-expandable{-ms-flex-order:-1;order:-1}[dir=rtl] .item-sliding-active-swipe-end .item-options-end .item-option-expandable{-ms-flex-order:-1;order:-1}@supports selector(:dir(rtl)){.item-sliding-active-swipe-end .item-options-end .item-option-expandable:dir(rtl){-ms-flex-order:-1;order:-1}}.item-sliding-active-swipe-start .item-options-start .item-option-expandable{padding-right:100%;-ms-flex-order:-1;order:-1;-webkit-transition-duration:0.6s;transition-duration:0.6s;-webkit-transition-property:padding-right;transition-property:padding-right}:host-context([dir=rtl]) .item-sliding-active-swipe-start .item-options-start .item-option-expandable{-ms-flex-order:1;order:1}[dir=rtl] .item-sliding-active-swipe-start .item-options-start .item-option-expandable{-ms-flex-order:1;order:1}@supports selector(:dir(rtl)){.item-sliding-active-swipe-start .item-options-start .item-option-expandable:dir(rtl){-ms-flex-order:1;order:1}}";
const SWIPE_MARGIN = 30;
const ELASTIC_FACTOR = 0.55;
let openSlidingItem;
class ItemSliding {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionDrag = createEvent(this, "ionDrag", 7);
this.item = null;
this.openAmount = 0;
this.initialOpenAmount = 0;
this.optsWidthRightSide = 0;
this.optsWidthLeftSide = 0;
this.sides = 0 /* ItemSide.None */;
this.optsDirty = true;
this.contentEl = null;
this.initialContentScrollY = true;
this.state = 2 /* SlidingState.Disabled */;
/**
* If `true`, the user cannot interact with the sliding item.
*/
this.disabled = false;
}
disabledChanged() {
if (this.gesture) {
this.gesture.enable(!this.disabled);
}
}
async connectedCallback() {
const { el } = this;
this.item = el.querySelector('ion-item');
this.contentEl = findClosestIonContent(el);
/**
* The MutationObserver needs to be added before we
* call updateOptions below otherwise we may miss
* ion-item-option elements that are added to the DOM
* while updateOptions is running and before the MutationObserver
* has been initialized.
*/
this.mutationObserver = watchForOptions(el, 'ion-item-option', async () => {
await this.updateOptions();
});
await this.updateOptions();
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el,
gestureName: 'item-swipe',
gesturePriority: 100,
threshold: 5,
canStart: (ev) => this.canStart(ev),
onStart: () => this.onStart(),
onMove: (ev) => this.onMove(ev),
onEnd: (ev) => this.onEnd(ev),
});
this.disabledChanged();
}
disconnectedCallback() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
this.item = null;
this.leftOptions = this.rightOptions = undefined;
if (openSlidingItem === this.el) {
openSlidingItem = undefined;
}
if (this.mutationObserver) {
this.mutationObserver.disconnect();
this.mutationObserver = undefined;
}
}
/**
* Get the amount the item is open in pixels.
*/
getOpenAmount() {
return Promise.resolve(this.openAmount);
}
/**
* Get the ratio of the open amount of the item compared to the width of the options.
* If the number returned is positive, then the options on the right side are open.
* If the number returned is negative, then the options on the left side are open.
* If the absolute value of the number is greater than 1, the item is open more than
* the width of the options.
*/
getSlidingRatio() {
return Promise.resolve(this.getSlidingRatioSync());
}
/**
* Open the sliding item.
*
* @param side The side of the options to open. If a side is not provided, it will open the first set of options it finds within the item.
*/
async open(side) {
var _a;
/**
* It is possible for the item to be added to the DOM
* after the item-sliding component was created. As a result,
* if this.item is null, then we should attempt to
* query for the ion-item again.
* However, if the item is already defined then
* we do not query for it again.
*/
const item = (this.item = (_a = this.item) !== null && _a !== void 0 ? _a : this.el.querySelector('ion-item'));
if (item === null) {
return;
}
const optionsToOpen = this.getOptions(side);
if (!optionsToOpen) {
return;
}
/**
* If side is not set, we need to infer the side
* so we know which direction to move the options
*/
if (side === undefined) {
side = optionsToOpen === this.leftOptions ? 'start' : 'end';
}
// In RTL we want to switch the sides
side = isEndSide(side) ? 'end' : 'start';
const isStartOpen = this.openAmount < 0;
const isEndOpen = this.openAmount > 0;
/**
* If a side is open and a user tries to
* re-open the same side, we should not do anything
*/
if (isStartOpen && optionsToOpen === this.leftOptions) {
return;
}
if (isEndOpen && optionsToOpen === this.rightOptions) {
return;
}
this.closeOpened();
this.state = 4 /* SlidingState.Enabled */;
requestAnimationFrame(() => {
this.calculateOptsWidth();
const width = side === 'end' ? this.optsWidthRightSide : -this.optsWidthLeftSide;
openSlidingItem = this.el;
this.setOpenAmount(width, false);
this.state = side === 'end' ? 8 /* SlidingState.End */ : 16 /* SlidingState.Start */;
});
}
/**
* Close the sliding item. Items can also be closed from the [List](./list).
*/
async close() {
this.setOpenAmount(0, true);
}
/**
* Close all of the sliding items in the list. Items can also be closed from the [List](./list).
*/
async closeOpened() {
if (openSlidingItem !== undefined) {
openSlidingItem.close();
openSlidingItem = undefined;
return true;
}
return false;
}
/**
* Given an optional side, return the ion-item-options element.
*
* @param side This side of the options to get. If a side is not provided it will
* return the first one available.
*/
getOptions(side) {
if (side === undefined) {
return this.leftOptions || this.rightOptions;
}
else if (side === 'start') {
return this.leftOptions;
}
else {
return this.rightOptions;
}
}
async updateOptions() {
var _a;
const options = this.el.querySelectorAll('ion-item-options');
let sides = 0;
// Reset left and right options in case they were removed
this.leftOptions = this.rightOptions = undefined;
for (let i = 0; i < options.length; i++) {
const item = options.item(i);
/**
* We cannot use the componentOnReady helper
* util here since we need to wait for all of these items
* to be ready before we set `this.sides` and `this.optsDirty`.
*/
// eslint-disable-next-line custom-rules/no-component-on-ready-method
const option = item.componentOnReady !== undefined ? await item.componentOnReady() : item;
const side = isEndSide((_a = option.side) !== null && _a !== void 0 ? _a : option.getAttribute('side')) ? 'end' : 'start';
if (side === 'start') {
this.leftOptions = option;
sides |= 1 /* ItemSide.Start */;
}
else {
this.rightOptions = option;
sides |= 2 /* ItemSide.End */;
}
}
this.optsDirty = true;
this.sides = sides;
}
canStart(gesture) {
/**
* If very close to start of the screen
* do not open left side so swipe to go
* back will still work.
*/
const rtl = document.dir === 'rtl';
const atEdge = rtl ? window.innerWidth - gesture.startX < 15 : gesture.startX < 15;
if (atEdge) {
return false;
}
const selected = openSlidingItem;
if (selected && selected !== this.el) {
this.closeOpened();
}
return !!(this.rightOptions || this.leftOptions);
}
onStart() {
/**
* We need to query for the ion-item
* every time the gesture starts. Developers
* may toggle ion-item elements via *ngIf.
*/
this.item = this.el.querySelector('ion-item');
const { contentEl } = this;
if (contentEl) {
this.initialContentScrollY = disableContentScrollY(contentEl);
}
openSlidingItem = this.el;
if (this.tmr !== undefined) {
clearTimeout(this.tmr);
this.tmr = undefined;
}
if (this.openAmount === 0) {
this.optsDirty = true;
this.state = 4 /* SlidingState.Enabled */;
}
this.initialOpenAmount = this.openAmount;
if (this.item) {
this.item.style.transition = 'none';
}
}
onMove(gesture) {
if (this.optsDirty) {
this.calculateOptsWidth();
}
let openAmount = this.initialOpenAmount - gesture.deltaX;
switch (this.sides) {
case 2 /* ItemSide.End */:
openAmount = Math.max(0, openAmount);
break;
case 1 /* ItemSide.Start */:
openAmount = Math.min(0, openAmount);
break;
case 3 /* ItemSide.Both */:
break;
case 0 /* ItemSide.None */:
return;
default:
printIonWarning('[ion-item-sliding] - invalid ItemSideFlags value', this.sides);
break;
}
let optsWidth;
if (openAmount > this.optsWidthRightSide) {
optsWidth = this.optsWidthRightSide;
openAmount = optsWidth + (openAmount - optsWidth) * ELASTIC_FACTOR;
}
else if (openAmount < -this.optsWidthLeftSide) {
optsWidth = -this.optsWidthLeftSide;
openAmount = optsWidth + (openAmount - optsWidth) * ELASTIC_FACTOR;
}
this.setOpenAmount(openAmount, false);
}
onEnd(gesture) {
const { contentEl, initialContentScrollY } = this;
if (contentEl) {
resetContentScrollY(contentEl, initialContentScrollY);
}
const velocity = gesture.velocityX;
let restingPoint = this.openAmount > 0 ? this.optsWidthRightSide : -this.optsWidthLeftSide;
// Check if the drag didn't clear the buttons mid-point
// and we aren't moving fast enough to swipe open
const isResetDirection = this.openAmount > 0 === !(velocity < 0);
const isMovingFast = Math.abs(velocity) > 0.3;
const isOnCloseZone = Math.abs(this.openAmount) < Math.abs(restingPoint / 2);
if (swipeShouldReset(isResetDirection, isMovingFast, isOnCloseZone)) {
restingPoint = 0;
}
const state = this.state;
this.setOpenAmount(restingPoint, true);
if ((state & 32 /* SlidingState.SwipeEnd */) !== 0 && this.rightOptions) {
this.rightOptions.fireSwipeEvent();
}
else if ((state & 64 /* SlidingState.SwipeStart */) !== 0 && this.leftOptions) {
this.leftOptions.fireSwipeEvent();
}
}
calculateOptsWidth() {
this.optsWidthRightSide = 0;
if (this.rightOptions) {
this.rightOptions.style.display = 'flex';
this.optsWidthRightSide = this.rightOptions.offsetWidth;
this.rightOptions.style.display = '';
}
this.optsWidthLeftSide = 0;
if (this.leftOptions) {
this.leftOptions.style.display = 'flex';
this.optsWidthLeftSide = this.leftOptions.offsetWidth;
this.leftOptions.style.display = '';
}
this.optsDirty = false;
}
setOpenAmount(openAmount, isFinal) {
if (this.tmr !== undefined) {
clearTimeout(this.tmr);
this.tmr = undefined;
}
if (!this.item) {
return;
}
const { el } = this;
const style = this.item.style;
this.openAmount = openAmount;
if (isFinal) {
style.transition = '';
}
if (openAmount > 0) {
this.state =
openAmount >= this.optsWidthRightSide + SWIPE_MARGIN
? 8 /* SlidingState.End */ | 32 /* SlidingState.SwipeEnd */
: 8 /* SlidingState.End */;
}
else if (openAmount < 0) {
this.state =
openAmount <= -this.optsWidthLeftSide - SWIPE_MARGIN
? 16 /* SlidingState.Start */ | 64 /* SlidingState.SwipeStart */
: 16 /* SlidingState.Start */;
}
else {
/**
* The sliding options should not be
* clickable while the item is closing.
*/
el.classList.add('item-sliding-closing');
/**
* Item sliding cannot be interrupted
* while closing the item. If it did,
* it would allow the item to get into an
* inconsistent state where multiple
* items are then open at the same time.
*/
if (this.gesture) {
this.gesture.enable(false);
}
this.tmr = setTimeout(() => {
this.state = 2 /* SlidingState.Disabled */;
this.tmr = undefined;
if (this.gesture) {
this.gesture.enable(!this.disabled);
}
el.classList.remove('item-sliding-closing');
}, 600);
openSlidingItem = undefined;
style.transform = '';
return;
}
style.transform = `translate3d(${-openAmount}px,0,0)`;
this.ionDrag.emit({
amount: openAmount,
ratio: this.getSlidingRatioSync(),
});
}
getSlidingRatioSync() {
if (this.openAmount > 0) {
return this.openAmount / this.optsWidthRightSide;
}
else if (this.openAmount < 0) {
return this.openAmount / this.optsWidthLeftSide;
}
else {
return 0;
}
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd812322c9fb5da4ee16e99dc38bfb24cb4590d03', class: {
[mode]: true,
'item-sliding-active-slide': this.state !== 2 /* SlidingState.Disabled */,
'item-sliding-active-options-end': (this.state & 8 /* SlidingState.End */) !== 0,
'item-sliding-active-options-start': (this.state & 16 /* SlidingState.Start */) !== 0,
'item-sliding-active-swipe-end': (this.state & 32 /* SlidingState.SwipeEnd */) !== 0,
'item-sliding-active-swipe-start': (this.state & 64 /* SlidingState.SwipeStart */) !== 0,
} }));
}
get el() { return getElement(this); }
static get watchers() { return {
"disabled": ["disabledChanged"]
}; }
static get style() { return itemSlidingCss; }
static get cmpMeta() { return {
"$flags$": 256,
"$tagName$": "ion-item-sliding",
"$members$": {
"disabled": [4],
"state": [32],
"getOpenAmount": [64],
"getSlidingRatio": [64],
"open": [64],
"close": [64],
"closeOpened": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const swipeShouldReset = (isResetDirection, isMovingFast, isOnResetZone) => {
// The logic required to know when the sliding item should close (openAmount=0)
// depends on three booleans (isResetDirection, isMovingFast, isOnResetZone)
// and it ended up being too complicated to be written manually without errors
// so the truth table is attached below: (0=false, 1=true)
// isResetDirection | isMovingFast | isOnResetZone || shouldClose
// 0 | 0 | 0 || 0
// 0 | 0 | 1 || 1
// 0 | 1 | 0 || 0
// 0 | 1 | 1 || 0
// 1 | 0 | 0 || 0
// 1 | 0 | 1 || 1
// 1 | 1 | 0 || 1
// 1 | 1 | 1 || 1
// The resulting expression was generated by resolving the K-map (Karnaugh map):
return (!isMovingFast && isOnResetZone) || (isResetDirection && isMovingFast);
};
const labelIosCss = ".item.sc-ion-label-ios-h,.item .sc-ion-label-ios-h{--color:initial;display:block;color:var(--color);font-family:var(--ion-font-family, inherit);font-size:inherit;text-overflow:ellipsis;-webkit-box-sizing:border-box;box-sizing:border-box}.ion-color.sc-ion-label-ios-h{color:var(--ion-color-base)}.ion-text-nowrap.sc-ion-label-ios-h{overflow:hidden}.item-interactive-disabled.sc-ion-label-ios-h:not(.item-multiple-inputs),.item-interactive-disabled:not(.item-multiple-inputs) .sc-ion-label-ios-h{cursor:default;opacity:0.3;pointer-events:none}.item-input.sc-ion-label-ios-h,.item-input .sc-ion-label-ios-h{-ms-flex:initial;flex:initial;max-width:200px;pointer-events:none}.item-textarea.sc-ion-label-ios-h,.item-textarea .sc-ion-label-ios-h{-ms-flex-item-align:baseline;align-self:baseline}.item-skeleton-text.sc-ion-label-ios-h,.item-skeleton-text .sc-ion-label-ios-h{overflow:hidden}.label-fixed.sc-ion-label-ios-h{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.label-stacked.sc-ion-label-ios-h,.label-floating.sc-ion-label-ios-h{margin-bottom:0;-ms-flex-item-align:stretch;align-self:stretch;width:auto;max-width:100%}.label-no-animate.label-floating.sc-ion-label-ios-h{-webkit-transition:none;transition:none}.sc-ion-label-ios-s h1,.sc-ion-label-ios-s h2,.sc-ion-label-ios-s h3,.sc-ion-label-ios-s h4,.sc-ion-label-ios-s h5,.sc-ion-label-ios-s h6{text-overflow:inherit;overflow:inherit}.ion-text-wrap.sc-ion-label-ios-h{font-size:0.875rem;line-height:1.5}.label-stacked.sc-ion-label-ios-h{margin-bottom:4px;font-size:0.875rem}.label-floating.sc-ion-label-ios-h{margin-bottom:0;-webkit-transform:translate(0, 29px);transform:translate(0, 29px);-webkit-transform-origin:left top;transform-origin:left top;-webkit-transition:-webkit-transform 150ms ease-in-out;transition:-webkit-transform 150ms ease-in-out;transition:transform 150ms ease-in-out;transition:transform 150ms ease-in-out, -webkit-transform 150ms ease-in-out}[dir=rtl].sc-ion-label-ios-h -no-combinator.label-floating.sc-ion-label-ios-h,[dir=rtl] .sc-ion-label-ios-h -no-combinator.label-floating.sc-ion-label-ios-h,[dir=rtl].label-floating.sc-ion-label-ios-h,[dir=rtl] .label-floating.sc-ion-label-ios-h{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.label-floating.sc-ion-label-ios-h:dir(rtl){-webkit-transform-origin:right top;transform-origin:right top}}.item-textarea.label-floating.sc-ion-label-ios-h,.item-textarea .label-floating.sc-ion-label-ios-h{-webkit-transform:translate(0, 28px);transform:translate(0, 28px)}.item-has-focus.label-floating.sc-ion-label-ios-h,.item-has-focus .label-floating.sc-ion-label-ios-h,.item-has-placeholder.sc-ion-label-ios-h:not(.item-input).label-floating,.item-has-placeholder:not(.item-input) .label-floating.sc-ion-label-ios-h,.item-has-value.label-floating.sc-ion-label-ios-h,.item-has-value .label-floating.sc-ion-label-ios-h{-webkit-transform:scale(0.82);transform:scale(0.82)}.sc-ion-label-ios-s h1{margin-left:0;margin-right:0;margin-top:3px;margin-bottom:2px;font-size:1.375rem;font-weight:normal}.sc-ion-label-ios-s h2{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:1.0625rem;font-weight:normal}.sc-ion-label-ios-s h3,.sc-ion-label-ios-s h4,.sc-ion-label-ios-s h5,.sc-ion-label-ios-s h6{margin-left:0;margin-right:0;margin-top:0;margin-bottom:3px;font-size:0.875rem;font-weight:normal;line-height:normal}.sc-ion-label-ios-s p{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:0.875rem;line-height:normal;text-overflow:inherit;overflow:inherit}.sc-ion-label-ios-s>p{color:var(--ion-color-step-400, var(--ion-text-color-step-600, #999999))}.sc-ion-label-ios-h.in-item-color.sc-ion-label-ios-s>p{color:inherit}.sc-ion-label-ios-s h2:last-child,.sc-ion-label-ios-s h3:last-child,.sc-ion-label-ios-s h4:last-child,.sc-ion-label-ios-s h5:last-child,.sc-ion-label-ios-s h6:last-child,.sc-ion-label-ios-s p:last-child{margin-bottom:0}";
const labelMdCss = ".item.sc-ion-label-md-h,.item .sc-ion-label-md-h{--color:initial;display:block;color:var(--color);font-family:var(--ion-font-family, inherit);font-size:inherit;text-overflow:ellipsis;-webkit-box-sizing:border-box;box-sizing:border-box}.ion-color.sc-ion-label-md-h{color:var(--ion-color-base)}.ion-text-nowrap.sc-ion-label-md-h{overflow:hidden}.item-interactive-disabled.sc-ion-label-md-h:not(.item-multiple-inputs),.item-interactive-disabled:not(.item-multiple-inputs) .sc-ion-label-md-h{cursor:default;opacity:0.3;pointer-events:none}.item-input.sc-ion-label-md-h,.item-input .sc-ion-label-md-h{-ms-flex:initial;flex:initial;max-width:200px;pointer-events:none}.item-textarea.sc-ion-label-md-h,.item-textarea .sc-ion-label-md-h{-ms-flex-item-align:baseline;align-self:baseline}.item-skeleton-text.sc-ion-label-md-h,.item-skeleton-text .sc-ion-label-md-h{overflow:hidden}.label-fixed.sc-ion-label-md-h{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.label-stacked.sc-ion-label-md-h,.label-floating.sc-ion-label-md-h{margin-bottom:0;-ms-flex-item-align:stretch;align-self:stretch;width:auto;max-width:100%}.label-no-animate.label-floating.sc-ion-label-md-h{-webkit-transition:none;transition:none}.sc-ion-label-md-s h1,.sc-ion-label-md-s h2,.sc-ion-label-md-s h3,.sc-ion-label-md-s h4,.sc-ion-label-md-s h5,.sc-ion-label-md-s h6{text-overflow:inherit;overflow:inherit}.ion-text-wrap.sc-ion-label-md-h{line-height:1.5}.label-stacked.sc-ion-label-md-h,.label-floating.sc-ion-label-md-h{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-transform-origin:top left;transform-origin:top left}.label-stacked.label-rtl.sc-ion-label-md-h,.label-floating.label-rtl.sc-ion-label-md-h{-webkit-transform-origin:top right;transform-origin:top right}.label-stacked.sc-ion-label-md-h{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1)}.label-floating.sc-ion-label-md-h{-webkit-transform:translateY(96%);transform:translateY(96%);-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1)}.ion-focused.label-floating.sc-ion-label-md-h,.ion-focused .label-floating.sc-ion-label-md-h,.item-has-focus.label-floating.sc-ion-label-md-h,.item-has-focus .label-floating.sc-ion-label-md-h,.item-has-placeholder.sc-ion-label-md-h:not(.item-input).label-floating,.item-has-placeholder:not(.item-input) .label-floating.sc-ion-label-md-h,.item-has-value.label-floating.sc-ion-label-md-h,.item-has-value .label-floating.sc-ion-label-md-h{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75)}.ion-focused.label-stacked.sc-ion-label-md-h:not(.ion-color),.ion-focused .label-stacked.sc-ion-label-md-h:not(.ion-color),.ion-focused.label-floating.sc-ion-label-md-h:not(.ion-color),.ion-focused .label-floating.sc-ion-label-md-h:not(.ion-color),.item-has-focus.label-stacked.sc-ion-label-md-h:not(.ion-color),.item-has-focus .label-stacked.sc-ion-label-md-h:not(.ion-color),.item-has-focus.label-floating.sc-ion-label-md-h:not(.ion-color),.item-has-focus .label-floating.sc-ion-label-md-h:not(.ion-color){color:var(--ion-color-primary, #0054e9)}.ion-focused.ion-color.label-stacked.sc-ion-label-md-h:not(.ion-color),.ion-focused.ion-color .label-stacked.sc-ion-label-md-h:not(.ion-color),.ion-focused.ion-color.label-floating.sc-ion-label-md-h:not(.ion-color),.ion-focused.ion-color .label-floating.sc-ion-label-md-h:not(.ion-color),.item-has-focus.ion-color.label-stacked.sc-ion-label-md-h:not(.ion-color),.item-has-focus.ion-color .label-stacked.sc-ion-label-md-h:not(.ion-color),.item-has-focus.ion-color.label-floating.sc-ion-label-md-h:not(.ion-color),.item-has-focus.ion-color .label-floating.sc-ion-label-md-h:not(.ion-color){color:var(--ion-color-contrast)}.ion-invalid.ion-touched.label-stacked.sc-ion-label-md-h:not(.ion-color),.ion-invalid.ion-touched .label-stacked.sc-ion-label-md-h:not(.ion-color),.ion-invalid.ion-touched.label-floating.sc-ion-label-md-h:not(.ion-color),.ion-invalid.ion-touched .label-floating.sc-ion-label-md-h:not(.ion-color){color:var(--highlight-color-invalid)}.sc-ion-label-md-s h1{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:1.5rem;font-weight:normal}.sc-ion-label-md-s h2{margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:1rem;font-weight:normal}.sc-ion-label-md-s h3,.sc-ion-label-md-s h4,.sc-ion-label-md-s h5,.sc-ion-label-md-s h6{margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:0.875rem;font-weight:normal;line-height:normal}.sc-ion-label-md-s p{margin-left:0;margin-right:0;margin-top:0;margin-bottom:2px;font-size:0.875rem;line-height:1.25rem;text-overflow:inherit;overflow:inherit}.sc-ion-label-md-s>p{color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666))}.sc-ion-label-md-h.in-item-color.sc-ion-label-md-s>p{color:inherit}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Label {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionColor = createEvent(this, "ionColor", 7);
this.ionStyle = createEvent(this, "ionStyle", 7);
this.inRange = false;
this.noAnimate = false;
}
componentWillLoad() {
this.inRange = !!this.el.closest('ion-range');
this.noAnimate = this.position === 'floating';
this.emitStyle();
this.emitColor();
}
componentDidLoad() {
if (this.noAnimate) {
setTimeout(() => {
this.noAnimate = false;
}, 1000);
}
}
colorChanged() {
this.emitColor();
}
positionChanged() {
this.emitStyle();
}
emitColor() {
const { color } = this;
this.ionColor.emit({
'item-label-color': color !== undefined,
[`ion-color-${color}`]: color !== undefined,
});
}
emitStyle() {
const { inRange, position } = this;
// If the label is inside of a range we don't want
// to override the classes added by the label that
// is a direct child of the item
if (!inRange) {
this.ionStyle.emit({
label: true,
[`label-${position}`]: position !== undefined,
});
}
}
render() {
const position = this.position;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd6fba1a97189acc8ddfd64a2f009954a3e46e188', class: createColorClasses$1(this.color, {
[mode]: true,
'in-item-color': hostContext('ion-item.ion-color', this.el),
[`label-${position}`]: position !== undefined,
[`label-no-animate`]: this.noAnimate,
'label-rtl': document.dir === 'rtl',
}) }, hAsync("slot", { key: 'ce0ab50b5700398fdf50f36d02b7ad287eb71481' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"color": ["colorChanged"],
"position": ["positionChanged"]
}; }
static get style() { return {
ios: labelIosCss,
md: labelMdCss
}; }
static get cmpMeta() { return {
"$flags$": 294,
"$tagName$": "ion-label",
"$members$": {
"color": [513],
"position": [1],
"noAnimate": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const listIosCss = "ion-list{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:block;contain:content;list-style-type:none}ion-list.list-inset{-webkit-transform:translateZ(0);transform:translateZ(0);overflow:hidden}.list-ios{background:var(--ion-item-background, var(--ion-background-color, #fff))}.list-ios.list-inset{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:16px;margin-bottom:16px;border-radius:10px}.list-ios.list-inset ion-item:only-child,.list-ios.list-inset ion-item:not(:only-of-type):last-of-type,.list-ios.list-inset ion-item-sliding:last-of-type ion-item{--border-width:0;--inner-border-width:0}.list-ios.list-inset+ion-list.list-inset{margin-top:0}.list-ios-lines-none .item-lines-default{--inner-border-width:0px;--border-width:0px}.list-ios-lines-full .item-lines-default{--inner-border-width:0px;--border-width:0 0 0.55px 0}.list-ios-lines-inset .item-lines-default{--inner-border-width:0 0 0.55px 0;--border-width:0px}ion-card .list-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}";
const listMdCss = "ion-list{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:block;contain:content;list-style-type:none}ion-list.list-inset{-webkit-transform:translateZ(0);transform:translateZ(0);overflow:hidden}.list-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:8px;padding-bottom:8px;background:var(--ion-item-background, var(--ion-background-color, #fff))}.list-md>.input:last-child::after{inset-inline-start:0}.list-md.list-inset{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:16px;margin-bottom:16px;border-radius:2px}.list-md.list-inset ion-item:not(:only-of-type):last-of-type,.list-md.list-inset ion-item-sliding:last-of-type ion-item{--border-width:0;--inner-border-width:0}.list-md.list-inset ion-item:only-child{--border-width:0;--inner-border-width:0}.list-md.list-inset+ion-list.list-inset{margin-top:0}.list-md-lines-none .item-lines-default{--inner-border-width:0px;--border-width:0px}.list-md-lines-full .item-lines-default{--inner-border-width:0px;--border-width:0 0 1px 0}.list-md-lines-inset .item-lines-default{--inner-border-width:0 0 1px 0;--border-width:0px}ion-card .list-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class List {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the list will have margin around it and rounded corners.
*/
this.inset = false;
}
/**
* If `ion-item-sliding` are used inside the list, this method closes
* any open sliding item.
*
* Returns `true` if an actual `ion-item-sliding` is closed.
*/
async closeSlidingItems() {
const item = this.el.querySelector('ion-item-sliding');
if (item === null || item === void 0 ? void 0 : item.closeOpened) {
return item.closeOpened();
}
return false;
}
render() {
const mode = getIonMode$1(this);
const { lines, inset } = this;
return (hAsync(Host, { key: '7f9943751542d2cbd49a4ad3f28e16d9949f70d4', role: "list", class: {
[mode]: true,
// Used internally for styling
[`list-${mode}`]: true,
'list-inset': inset,
[`list-lines-${lines}`]: lines !== undefined,
[`list-${mode}-lines-${lines}`]: lines !== undefined,
} }));
}
get el() { return getElement(this); }
static get style() { return {
ios: listIosCss,
md: listMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-list",
"$members$": {
"lines": [1],
"inset": [4],
"closeSlidingItems": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const listHeaderIosCss = ":host{--border-style:solid;--border-width:0;--inner-border-width:0;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;min-height:40px;border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);color:var(--color);overflow:hidden}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}.list-header-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;min-height:inherit;border-width:var(--inner-border-width);border-style:var(--border-style);border-color:var(--border-color);overflow:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}::slotted(ion-label){-ms-flex:1 1 auto;flex:1 1 auto}:host(.list-header-lines-inset),:host(.list-header-lines-none){--border-width:0}:host(.list-header-lines-full),:host(.list-header-lines-none){--inner-border-width:0}:host{--background:transparent;--color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));padding-right:var(--ion-safe-area-right);padding-left:calc(var(--ion-safe-area-left, 0px) + 16px);position:relative;-ms-flex-align:end;align-items:flex-end;font-size:min(1.375rem, 56.1px);font-weight:700;letter-spacing:0}:host-context([dir=rtl]){padding-right:calc(var(--ion-safe-area-right, 0px) + 16px);padding-left:var(--ion-safe-area-left)}@supports selector(:dir(rtl)){:host(:dir(rtl)){padding-right:calc(var(--ion-safe-area-right, 0px) + 16px);padding-left:var(--ion-safe-area-left)}}::slotted(ion-button),::slotted(ion-label){margin-top:29px;margin-bottom:6px}::slotted(ion-button){--padding-top:0;--padding-bottom:0;-webkit-margin-start:3px;margin-inline-start:3px;-webkit-margin-end:3px;margin-inline-end:3px;min-height:1.4em}:host(.list-header-lines-full){--border-width:0 0 0.55px 0}:host(.list-header-lines-inset){--inner-border-width:0 0 0.55px 0}";
const listHeaderMdCss = ":host{--border-style:solid;--border-width:0;--inner-border-width:0;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;min-height:40px;border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);color:var(--color);overflow:hidden}:host(.ion-color){background:var(--ion-color-base);color:var(--ion-color-contrast)}.list-header-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-item-align:stretch;align-self:stretch;min-height:inherit;border-width:var(--inner-border-width);border-style:var(--border-style);border-color:var(--border-color);overflow:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}::slotted(ion-label){-ms-flex:1 1 auto;flex:1 1 auto}:host(.list-header-lines-inset),:host(.list-header-lines-none){--border-width:0}:host(.list-header-lines-full),:host(.list-header-lines-none){--inner-border-width:0}:host{--background:transparent;--color:var(--ion-text-color, #000);--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));padding-right:var(--ion-safe-area-right);padding-left:calc(var(--ion-safe-area-left, 0px) + 16px);min-height:45px;font-size:0.875rem}:host-context([dir=rtl]){padding-right:calc(var(--ion-safe-area-right, 0px) + 16px);padding-left:var(--ion-safe-area-left)}@supports selector(:dir(rtl)){:host(:dir(rtl)){padding-right:calc(var(--ion-safe-area-right, 0px) + 16px);padding-left:var(--ion-safe-area-left)}}:host(.list-header-lines-full){--border-width:0 0 1px 0}:host(.list-header-lines-inset){--inner-border-width:0 0 1px 0}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class ListHeader {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const { lines } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd9bc827ad8cc77231efddc2435831a7fc080f77d', class: createColorClasses$1(this.color, {
[mode]: true,
[`list-header-lines-${lines}`]: lines !== undefined,
}) }, hAsync("div", { key: '02dd9698304a7b2997ea1487e2f308bebea2b44c', class: "list-header-inner" }, hAsync("slot", { key: '01d63a572c003286ae467a1ab23631e37e695042' }))));
}
static get style() { return {
ios: listHeaderIosCss,
md: listHeaderMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-list-header",
"$members$": {
"color": [513],
"lines": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
/**
* iOS Loading Enter Animation
*/
const iosEnterAnimation$4 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation.addElement(baseEl.querySelector('.loading-wrapper')).keyframes([
{ offset: 0, opacity: 0.01, transform: 'scale(1.1)' },
{ offset: 1, opacity: 1, transform: 'scale(1)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* iOS Loading Leave Animation
*/
const iosLeaveAnimation$4 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(baseEl.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation.addElement(baseEl.querySelector('.loading-wrapper')).keyframes([
{ offset: 0, opacity: 0.99, transform: 'scale(1)' },
{ offset: 1, opacity: 0, transform: 'scale(0.9)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* Md Loading Enter Animation
*/
const mdEnterAnimation$3 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation.addElement(baseEl.querySelector('.loading-wrapper')).keyframes([
{ offset: 0, opacity: 0.01, transform: 'scale(1.1)' },
{ offset: 1, opacity: 1, transform: 'scale(1)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* Md Loading Leave Animation
*/
const mdLeaveAnimation$3 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(baseEl.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation.addElement(baseEl.querySelector('.loading-wrapper')).keyframes([
{ offset: 0, opacity: 0.99, transform: 'scale(1)' },
{ offset: 1, opacity: 0, transform: 'scale(0.9)' },
]);
return baseAnimation
.addElement(baseEl)
.easing('ease-in-out')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
const loadingIosCss = ".sc-ion-loading-ios-h{--min-width:auto;--width:auto;--min-height:auto;--height:auto;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:fixed;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;font-family:var(--ion-font-family, inherit);contain:strict;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.overlay-hidden.sc-ion-loading-ios-h{display:none}.loading-wrapper.sc-ion-loading-ios{display:-ms-flexbox;display:flex;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);opacity:0;z-index:10}ion-spinner.sc-ion-loading-ios{color:var(--spinner-color)}.sc-ion-loading-ios-h{--background:var(--ion-overlay-background-color, var(--ion-color-step-100, var(--ion-background-color-step-100, #f9f9f9)));--max-width:270px;--max-height:90%;--spinner-color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));--backdrop-opacity:var(--ion-backdrop-opacity, 0.3);color:var(--ion-text-color, #000);font-size:0.875rem}.loading-wrapper.sc-ion-loading-ios{border-radius:8px;-webkit-padding-start:34px;padding-inline-start:34px;-webkit-padding-end:34px;padding-inline-end:34px;padding-top:24px;padding-bottom:24px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){.loading-translucent.sc-ion-loading-ios-h .loading-wrapper.sc-ion-loading-ios{background-color:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}}.loading-content.sc-ion-loading-ios{font-weight:bold}.loading-spinner.sc-ion-loading-ios+.loading-content.sc-ion-loading-ios{-webkit-margin-start:16px;margin-inline-start:16px}";
const loadingMdCss = ".sc-ion-loading-md-h{--min-width:auto;--width:auto;--min-height:auto;--height:auto;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:fixed;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;font-family:var(--ion-font-family, inherit);contain:strict;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.overlay-hidden.sc-ion-loading-md-h{display:none}.loading-wrapper.sc-ion-loading-md{display:-ms-flexbox;display:flex;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);opacity:0;z-index:10}ion-spinner.sc-ion-loading-md{color:var(--spinner-color)}.sc-ion-loading-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--max-width:280px;--max-height:90%;--spinner-color:var(--ion-color-primary, #0054e9);--backdrop-opacity:var(--ion-backdrop-opacity, 0.32);color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));font-size:0.875rem}.loading-wrapper.sc-ion-loading-md{border-radius:2px;-webkit-padding-start:24px;padding-inline-start:24px;-webkit-padding-end:24px;padding-inline-end:24px;padding-top:24px;padding-bottom:24px;-webkit-box-shadow:0 16px 20px rgba(0, 0, 0, 0.4);box-shadow:0 16px 20px rgba(0, 0, 0, 0.4)}.loading-spinner.sc-ion-loading-md+.loading-content.sc-ion-loading-md{-webkit-margin-start:16px;margin-inline-start:16px}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Loading {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionLoadingDidPresent", 7);
this.willPresent = createEvent(this, "ionLoadingWillPresent", 7);
this.willDismiss = createEvent(this, "ionLoadingWillDismiss", 7);
this.didDismiss = createEvent(this, "ionLoadingDidDismiss", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.delegateController = createDelegateController(this);
this.lockController = createLockController();
this.triggerController = createTriggerController();
this.customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
this.presented = false;
/** @internal */
this.hasController = false;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = true;
/**
* Number of milliseconds to wait before dismissing the loading indicator.
*/
this.duration = 0;
/**
* If `true`, the loading indicator will be dismissed when the backdrop is clicked.
*/
this.backdropDismiss = false;
/**
* If `true`, a backdrop will be displayed behind the loading indicator.
*/
this.showBackdrop = true;
/**
* If `true`, the loading indicator will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
/**
* If `true`, the loading indicator will animate.
*/
this.animated = true;
/**
* If `true`, the loading indicator will open. If `false`, the loading indicator will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the loadingController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the loading indicator dismisses. You will need to do that in your code.
*/
this.isOpen = false;
this.onBackdropTap = () => {
this.dismiss(undefined, BACKDROP);
};
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
triggerChanged() {
const { trigger, el, triggerController } = this;
if (trigger) {
triggerController.addClickListener(el, trigger);
}
}
connectedCallback() {
prepareOverlay(this.el);
this.triggerChanged();
}
componentWillLoad() {
var _a;
if (this.spinner === undefined) {
const mode = getIonMode$1(this);
this.spinner = config.get('loadingSpinner', config.get('spinner', mode === 'ios' ? 'lines' : 'crescent'));
}
if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
setOverlayId(this.el);
}
}
componentDidLoad() {
/**
* If loading indicator was rendered with isOpen="true"
* then we should open loading indicator immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.triggerChanged();
}
disconnectedCallback() {
this.triggerController.removeClickListener();
}
/**
* Present the loading overlay after it has been created.
*/
async present() {
const unlock = await this.lockController.lock();
await this.delegateController.attachViewToDom();
await present(this, 'loadingEnter', iosEnterAnimation$4, mdEnterAnimation$3);
if (this.duration > 0) {
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration + 10);
}
unlock();
}
/**
* Dismiss the loading overlay after it has been presented.
* This is a no-op if the overlay has not been presented yet. If you want
* to remove an overlay from the DOM that was never presented, use the
* [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the loading.
* This can be useful in a button handler for determining which button was
* clicked to dismiss the loading. Some examples include:
* `"cancel"`, `"destructive"`, `"selected"`, and `"backdrop"`.
*/
async dismiss(data, role) {
const unlock = await this.lockController.lock();
if (this.durationTimeout) {
clearTimeout(this.durationTimeout);
}
const dismissed = await dismiss(this, data, role, 'loadingLeave', iosLeaveAnimation$4, mdLeaveAnimation$3);
if (dismissed) {
this.delegateController.removeViewFromDom();
}
unlock();
return dismissed;
}
/**
* Returns a promise that resolves when the loading did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionLoadingDidDismiss');
}
/**
* Returns a promise that resolves when the loading will dismiss.
*/
onWillDismiss() {
return eventMethod(this.el, 'ionLoadingWillDismiss');
}
renderLoadingMessage(msgId) {
const { customHTMLEnabled, message } = this;
if (customHTMLEnabled) {
return hAsync("div", { class: "loading-content", id: msgId, innerHTML: sanitizeDOMString(message) });
}
return (hAsync("div", { class: "loading-content", id: msgId }, message));
}
render() {
const { message, spinner, htmlAttributes, overlayIndex } = this;
const mode = getIonMode$1(this);
const msgId = `loading-${overlayIndex}-msg`;
/**
* If the message is defined, use that as the label.
* Otherwise, don't set aria-labelledby.
*/
const ariaLabelledBy = message !== undefined ? msgId : null;
return (hAsync(Host, Object.assign({ key: '4497183ce220242abe19ae15f328f9a92ccafbbc', role: "dialog", "aria-modal": "true", "aria-labelledby": ariaLabelledBy, tabindex: "-1" }, htmlAttributes, { style: {
zIndex: `${40000 + this.overlayIndex}`,
}, onIonBackdropTap: this.onBackdropTap, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'overlay-hidden': true, 'loading-translucent': this.translucent }) }), hAsync("ion-backdrop", { key: '231dec84e424a2dc358ce95b84d6035cf43e4dea', visible: this.showBackdrop, tappable: this.backdropDismiss }), hAsync("div", { key: 'c9af29b6e6bb49a217396a5c874bbfb8835a926c', tabindex: "0", "aria-hidden": "true" }), hAsync("div", { key: 'a8659863743cdeccbe1ba810eaabfd3ebfcb86f3', class: "loading-wrapper ion-overlay-wrapper" }, spinner && (hAsync("div", { key: '3b346f39bc71691bd8686556a1e142198a7b12fa', class: "loading-spinner" }, hAsync("ion-spinner", { key: '8dc2bf1556e5138e262827f1516c59ecd09f3520', name: spinner, "aria-hidden": "true" }))), message !== undefined && this.renderLoadingMessage(msgId)), hAsync("div", { key: '054164c0dbae9a0e0973dd3c8e28f5b771820310', tabindex: "0", "aria-hidden": "true" })));
}
get el() { return getElement(this); }
static get watchers() { return {
"isOpen": ["onIsOpenChange"],
"trigger": ["triggerChanged"]
}; }
static get style() { return {
ios: loadingIosCss,
md: loadingMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-loading",
"$members$": {
"overlayIndex": [2, "overlay-index"],
"delegate": [16],
"hasController": [4, "has-controller"],
"keyboardClose": [4, "keyboard-close"],
"enterAnimation": [16],
"leaveAnimation": [16],
"message": [1],
"cssClass": [1, "css-class"],
"duration": [2],
"backdropDismiss": [4, "backdrop-dismiss"],
"showBackdrop": [4, "show-backdrop"],
"spinner": [1025],
"translucent": [4],
"animated": [4],
"htmlAttributes": [16],
"isOpen": [4, "is-open"],
"trigger": [1],
"present": [64],
"dismiss": [64],
"onDidDismiss": [64],
"onWillDismiss": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
/**
* Based on:
* https://stackoverflow.com/questions/7348009/y-coordinate-for-a-given-x-cubic-bezier
* https://math.stackexchange.com/questions/26846/is-there-an-explicit-form-for-cubic-b%C3%A9zier-curves
*/
/**
* EXPERIMENTAL
* Given a cubic-bezier curve, get the x value (time) given
* the y value (progression).
* Ex: cubic-bezier(0.32, 0.72, 0, 1);
* P0: (0, 0)
* P1: (0.32, 0.72)
* P2: (0, 1)
* P3: (1, 1)
*
* If you give a cubic bezier curve that never reaches the
* provided progression, this function will return an empty array.
*/
const getTimeGivenProgression = (p0, p1, p2, p3, progression) => {
return solveCubicBezier(p0[1], p1[1], p2[1], p3[1], progression).map((tValue) => {
return solveCubicParametricEquation(p0[0], p1[0], p2[0], p3[0], tValue);
});
};
/**
* Solve a cubic equation in one dimension (time)
*/
const solveCubicParametricEquation = (p0, p1, p2, p3, t) => {
const partA = 3 * p1 * Math.pow(t - 1, 2);
const partB = -3 * p2 * t + 3 * p2 + p3 * t;
const partC = p0 * Math.pow(t - 1, 3);
return t * (partA + t * partB) - partC;
};
/**
* Find the `t` value for a cubic bezier using Cardano's formula
*/
const solveCubicBezier = (p0, p1, p2, p3, refPoint) => {
p0 -= refPoint;
p1 -= refPoint;
p2 -= refPoint;
p3 -= refPoint;
const roots = solveCubicEquation(p3 - 3 * p2 + 3 * p1 - p0, 3 * p2 - 6 * p1 + 3 * p0, 3 * p1 - 3 * p0, p0);
return roots.filter((root) => root >= 0 && root <= 1);
};
const solveQuadraticEquation = (a, b, c) => {
const discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
return [];
}
else {
return [(-b + Math.sqrt(discriminant)) / (2 * a), (-b - Math.sqrt(discriminant)) / (2 * a)];
}
};
const solveCubicEquation = (a, b, c, d) => {
if (a === 0) {
return solveQuadraticEquation(b, c, d);
}
b /= a;
c /= a;
d /= a;
const p = (3 * c - b * b) / 3;
const q = (2 * b * b * b - 9 * b * c + 27 * d) / 27;
if (p === 0) {
return [Math.pow(-q, 1 / 3)];
}
else if (q === 0) {
return [Math.sqrt(-p), -Math.sqrt(-p)];
}
const discriminant = Math.pow(q / 2, 2) + Math.pow(p / 3, 3);
if (discriminant === 0) {
return [Math.pow(q / 2, 1 / 2) - b / 3];
}
else if (discriminant > 0) {
return [
Math.pow(-(q / 2) + Math.sqrt(discriminant), 1 / 3) - Math.pow(q / 2 + Math.sqrt(discriminant), 1 / 3) - b / 3,
];
}
const r = Math.sqrt(Math.pow(-(p / 3), 3));
const phi = Math.acos(-(q / (2 * Math.sqrt(Math.pow(-(p / 3), 3)))));
const s = 2 * Math.pow(r, 1 / 3);
return [
s * Math.cos(phi / 3) - b / 3,
s * Math.cos((phi + 2 * Math.PI) / 3) - b / 3,
s * Math.cos((phi + 4 * Math.PI) / 3) - b / 3,
];
};
/**
* baseAnimation
* Base class which is extended by the various types. Each
* type will provide their own animations for open and close
* and registers itself with Menu.
*/
const baseAnimation = (isIos) => {
// https://material.io/guidelines/motion/movement.html#movement-movement-in-out-of-screen-bounds
// https://material.io/guidelines/motion/duration-easing.html#duration-easing-natural-easing-curves
/**
* "Apply the sharp curve to items temporarily leaving the screen that may return
* from the same exit point. When they return, use the deceleration curve. On mobile,
* this transition typically occurs over 300ms" -- MD Motion Guide
*/
return createAnimation().duration(isIos ? 400 : 300);
};
/**
* Menu Overlay Type
* The menu slides over the content. The content
* itself, which is under the menu, does not move.
*/
const menuOverlayAnimation = (menu) => {
let closedX;
let openedX;
const width = menu.width + 8;
const menuAnimation = createAnimation();
const backdropAnimation = createAnimation();
if (menu.isEndSide) {
// right side
closedX = width + 'px';
openedX = '0px';
}
else {
// left side
closedX = -width + 'px';
openedX = '0px';
}
menuAnimation.addElement(menu.menuInnerEl).fromTo('transform', `translateX(${closedX})`, `translateX(${openedX})`);
const mode = getIonMode$1(menu);
const isIos = mode === 'ios';
const opacity = isIos ? 0.2 : 0.25;
backdropAnimation.addElement(menu.backdropEl).fromTo('opacity', 0.01, opacity);
return baseAnimation(isIos).addAnimation([menuAnimation, backdropAnimation]);
};
/**
* Menu Push Type
* The content slides over to reveal the menu underneath.
* The menu itself also slides over to reveal its bad self.
*/
const menuPushAnimation = (menu) => {
let contentOpenedX;
let menuClosedX;
const mode = getIonMode$1(menu);
const width = menu.width;
if (menu.isEndSide) {
contentOpenedX = -width + 'px';
menuClosedX = width + 'px';
}
else {
contentOpenedX = width + 'px';
menuClosedX = -width + 'px';
}
const menuAnimation = createAnimation()
.addElement(menu.menuInnerEl)
.fromTo('transform', `translateX(${menuClosedX})`, 'translateX(0px)');
const contentAnimation = createAnimation()
.addElement(menu.contentEl)
.fromTo('transform', 'translateX(0px)', `translateX(${contentOpenedX})`);
const backdropAnimation = createAnimation().addElement(menu.backdropEl).fromTo('opacity', 0.01, 0.32);
return baseAnimation(mode === 'ios').addAnimation([menuAnimation, contentAnimation, backdropAnimation]);
};
/**
* Menu Reveal Type
* The content slides over to reveal the menu underneath.
* The menu itself, which is under the content, does not move.
*/
const menuRevealAnimation = (menu) => {
const mode = getIonMode$1(menu);
const openedX = menu.width * (menu.isEndSide ? -1 : 1) + 'px';
const contentOpen = createAnimation()
.addElement(menu.contentEl) // REVIEW
.fromTo('transform', 'translateX(0px)', `translateX(${openedX})`);
return baseAnimation(mode === 'ios').addAnimation(contentOpen);
};
const createMenuController = () => {
const menuAnimations = new Map();
const menus = [];
const open = async (menu) => {
const menuEl = await get(menu, true);
if (menuEl) {
return menuEl.open();
}
return false;
};
const close = async (menu) => {
const menuEl = await (menu !== undefined ? get(menu, true) : getOpen());
if (menuEl !== undefined) {
return menuEl.close();
}
return false;
};
const toggle = async (menu) => {
const menuEl = await get(menu, true);
if (menuEl) {
return menuEl.toggle();
}
return false;
};
const enable = async (shouldEnable, menu) => {
const menuEl = await get(menu);
if (menuEl) {
menuEl.disabled = !shouldEnable;
}
return menuEl;
};
const swipeGesture = async (shouldEnable, menu) => {
const menuEl = await get(menu);
if (menuEl) {
menuEl.swipeGesture = shouldEnable;
}
return menuEl;
};
const isOpen = async (menu) => {
if (menu != null) {
const menuEl = await get(menu);
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
return menuEl !== undefined && menuEl.isOpen();
}
else {
const menuEl = await getOpen();
return menuEl !== undefined;
}
};
const isEnabled = async (menu) => {
const menuEl = await get(menu);
if (menuEl) {
return !menuEl.disabled;
}
return false;
};
/**
* Finds and returns the menu specified by "menu" if registered.
* @param menu - The side or ID of the desired menu
* @param logOnMultipleSideMenus - If true, this function will log a warning
* if "menu" is a side but multiple menus on the same side were found. Since this function
* is used in multiple places, we default this log to false so that the calling
* functions can choose whether or not it is appropriate to log this warning.
*/
const get = async (menu, logOnMultipleSideMenus = false) => {
await waitUntilReady();
if (menu === 'start' || menu === 'end') {
// there could be more than one menu on the same side
// so first try to get the enabled one
const menuRefs = menus.filter((m) => m.side === menu && !m.disabled);
if (menuRefs.length >= 1) {
if (menuRefs.length > 1 && logOnMultipleSideMenus) {
printIonWarning(`menuController queried for a menu on the "${menu}" side, but ${menuRefs.length} menus were found. The first menu reference will be used. If this is not the behavior you want then pass the ID of the menu instead of its side.`, menuRefs.map((m) => m.el));
}
return menuRefs[0].el;
}
// didn't find a menu side that is enabled
// so try to get the first menu side found
const sideMenuRefs = menus.filter((m) => m.side === menu);
if (sideMenuRefs.length >= 1) {
if (sideMenuRefs.length > 1 && logOnMultipleSideMenus) {
printIonWarning(`menuController queried for a menu on the "${menu}" side, but ${sideMenuRefs.length} menus were found. The first menu reference will be used. If this is not the behavior you want then pass the ID of the menu instead of its side.`, sideMenuRefs.map((m) => m.el));
}
return sideMenuRefs[0].el;
}
}
else if (menu != null) {
// the menuId was not left or right
// so try to get the menu by its "id"
return find((m) => m.menuId === menu);
}
// return the first enabled menu
const menuEl = find((m) => !m.disabled);
if (menuEl) {
return menuEl;
}
// get the first menu in the array, if one exists
return menus.length > 0 ? menus[0].el : undefined;
};
/**
* Get the instance of the opened menu. Returns `null` if a menu is not found.
*/
const getOpen = async () => {
await waitUntilReady();
return _getOpenSync();
};
/**
* Get all menu instances.
*/
const getMenus = async () => {
await waitUntilReady();
return getMenusSync();
};
/**
* Get whether or not a menu is animating. Returns `true` if any
* menu is currently animating.
*/
const isAnimating = async () => {
await waitUntilReady();
return isAnimatingSync();
};
const registerAnimation = (name, animation) => {
menuAnimations.set(name, animation);
};
const _register = (menu) => {
if (menus.indexOf(menu) < 0) {
menus.push(menu);
}
};
const _unregister = (menu) => {
const index = menus.indexOf(menu);
if (index > -1) {
menus.splice(index, 1);
}
};
const _setOpen = async (menu, shouldOpen, animated, role) => {
if (isAnimatingSync()) {
return false;
}
if (shouldOpen) {
const openedMenu = await getOpen();
if (openedMenu && menu.el !== openedMenu) {
await openedMenu.setOpen(false, false);
}
}
return menu._setOpen(shouldOpen, animated, role);
};
const _createAnimation = (type, menuCmp) => {
const animationBuilder = menuAnimations.get(type); // TODO(FW-2832): type
if (!animationBuilder) {
throw new Error('animation not registered');
}
const animation = animationBuilder(menuCmp);
return animation;
};
const _getOpenSync = () => {
return find((m) => m._isOpen);
};
const getMenusSync = () => {
return menus.map((menu) => menu.el);
};
const isAnimatingSync = () => {
return menus.some((menu) => menu.isAnimating);
};
const find = (predicate) => {
const instance = menus.find(predicate);
if (instance !== undefined) {
return instance.el;
}
return undefined;
};
const waitUntilReady = () => {
return Promise.all(Array.from(document.querySelectorAll('ion-menu')).map((menu) => new Promise((resolve) => componentOnReady(menu, resolve))));
};
registerAnimation('reveal', menuRevealAnimation);
registerAnimation('push', menuPushAnimation);
registerAnimation('overlay', menuOverlayAnimation);
doc === null || doc === void 0 ? void 0 : doc.addEventListener('ionBackButton', (ev) => {
const openMenu = _getOpenSync();
if (openMenu) {
ev.detail.register(MENU_BACK_BUTTON_PRIORITY, () => {
return openMenu.close();
});
}
});
return {
registerAnimation,
get,
getMenus,
getOpen,
isEnabled,
swipeGesture,
isAnimating,
isOpen,
enable,
toggle,
close,
open,
_getOpenSync,
_createAnimation,
_register,
_unregister,
_setOpen,
};
};
const menuController = /*@__PURE__*/ createMenuController();
const menuIosCss = ":host{--width:304px;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--background:var(--ion-background-color, #fff);left:0;right:0;top:0;bottom:0;display:none;position:absolute;contain:strict}:host(.show-menu){display:block}.menu-inner{-webkit-transform:translateX(-9999px);transform:translateX(-9999px);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:justify;justify-content:space-between;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);contain:strict}:host(.menu-side-start) .menu-inner{--ion-safe-area-right:0px;top:0;bottom:0}:host(.menu-side-start) .menu-inner{inset-inline-start:0;inset-inline-end:auto}:host-context([dir=rtl]):host(.menu-side-start) .menu-inner,:host-context([dir=rtl]).menu-side-start .menu-inner{--ion-safe-area-right:unset;--ion-safe-area-left:0px}@supports selector(:dir(rtl)){:host(.menu-side-start:dir(rtl)) .menu-inner{--ion-safe-area-right:unset;--ion-safe-area-left:0px}}:host(.menu-side-end) .menu-inner{--ion-safe-area-left:0px;top:0;bottom:0}:host(.menu-side-end) .menu-inner{inset-inline-start:auto;inset-inline-end:0}:host-context([dir=rtl]):host(.menu-side-end) .menu-inner,:host-context([dir=rtl]).menu-side-end .menu-inner{--ion-safe-area-left:unset;--ion-safe-area-right:0px}@supports selector(:dir(rtl)){:host(.menu-side-end:dir(rtl)) .menu-inner{--ion-safe-area-left:unset;--ion-safe-area-right:0px}}ion-backdrop{display:none;opacity:0.01;z-index:-1}@media (max-width: 340px){.menu-inner{--width:264px}}:host(.menu-type-reveal){z-index:0}:host(.menu-type-reveal.show-menu) .menu-inner{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}:host(.menu-type-overlay){z-index:1000}:host(.menu-type-overlay) .show-backdrop{display:block;cursor:pointer}:host(.menu-pane-visible){-ms-flex:0 1 auto;flex:0 1 auto;width:var(--side-width, var(--width));min-width:var(--side-min-width, var(--min-width));max-width:var(--side-max-width, var(--max-width))}:host(.menu-pane-visible.split-pane-side){left:0;right:0;top:0;bottom:0;position:relative;-webkit-box-shadow:none;box-shadow:none;z-index:0}:host(.menu-pane-visible.split-pane-side.menu-enabled){display:-ms-flexbox;display:flex;-ms-flex-negative:0;flex-shrink:0}:host(.menu-pane-visible.split-pane-side){-ms-flex-order:-1;order:-1}:host(.menu-pane-visible.split-pane-side[side=end]){-ms-flex-order:1;order:1}:host(.menu-pane-visible) .menu-inner{left:0;right:0;width:auto;-webkit-transform:none;transform:none;-webkit-box-shadow:none;box-shadow:none}:host(.menu-pane-visible) ion-backdrop{display:hidden !important}:host(.menu-pane-visible.split-pane-side){-webkit-border-start:0;border-inline-start:0;-webkit-border-end:var(--border);border-inline-end:var(--border);border-top:0;border-bottom:0;min-width:var(--side-min-width);max-width:var(--side-max-width)}:host(.menu-pane-visible.split-pane-side[side=end]){-webkit-border-start:var(--border);border-inline-start:var(--border);-webkit-border-end:0;border-inline-end:0;border-top:0;border-bottom:0;min-width:var(--side-min-width);max-width:var(--side-max-width)}:host(.menu-type-push){z-index:1000}:host(.menu-type-push) .show-backdrop{display:block}";
const menuMdCss = ":host{--width:304px;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--background:var(--ion-background-color, #fff);left:0;right:0;top:0;bottom:0;display:none;position:absolute;contain:strict}:host(.show-menu){display:block}.menu-inner{-webkit-transform:translateX(-9999px);transform:translateX(-9999px);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:justify;justify-content:space-between;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);contain:strict}:host(.menu-side-start) .menu-inner{--ion-safe-area-right:0px;top:0;bottom:0}:host(.menu-side-start) .menu-inner{inset-inline-start:0;inset-inline-end:auto}:host-context([dir=rtl]):host(.menu-side-start) .menu-inner,:host-context([dir=rtl]).menu-side-start .menu-inner{--ion-safe-area-right:unset;--ion-safe-area-left:0px}@supports selector(:dir(rtl)){:host(.menu-side-start:dir(rtl)) .menu-inner{--ion-safe-area-right:unset;--ion-safe-area-left:0px}}:host(.menu-side-end) .menu-inner{--ion-safe-area-left:0px;top:0;bottom:0}:host(.menu-side-end) .menu-inner{inset-inline-start:auto;inset-inline-end:0}:host-context([dir=rtl]):host(.menu-side-end) .menu-inner,:host-context([dir=rtl]).menu-side-end .menu-inner{--ion-safe-area-left:unset;--ion-safe-area-right:0px}@supports selector(:dir(rtl)){:host(.menu-side-end:dir(rtl)) .menu-inner{--ion-safe-area-left:unset;--ion-safe-area-right:0px}}ion-backdrop{display:none;opacity:0.01;z-index:-1}@media (max-width: 340px){.menu-inner{--width:264px}}:host(.menu-type-reveal){z-index:0}:host(.menu-type-reveal.show-menu) .menu-inner{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}:host(.menu-type-overlay){z-index:1000}:host(.menu-type-overlay) .show-backdrop{display:block;cursor:pointer}:host(.menu-pane-visible){-ms-flex:0 1 auto;flex:0 1 auto;width:var(--side-width, var(--width));min-width:var(--side-min-width, var(--min-width));max-width:var(--side-max-width, var(--max-width))}:host(.menu-pane-visible.split-pane-side){left:0;right:0;top:0;bottom:0;position:relative;-webkit-box-shadow:none;box-shadow:none;z-index:0}:host(.menu-pane-visible.split-pane-side.menu-enabled){display:-ms-flexbox;display:flex;-ms-flex-negative:0;flex-shrink:0}:host(.menu-pane-visible.split-pane-side){-ms-flex-order:-1;order:-1}:host(.menu-pane-visible.split-pane-side[side=end]){-ms-flex-order:1;order:1}:host(.menu-pane-visible) .menu-inner{left:0;right:0;width:auto;-webkit-transform:none;transform:none;-webkit-box-shadow:none;box-shadow:none}:host(.menu-pane-visible) ion-backdrop{display:hidden !important}:host(.menu-pane-visible.split-pane-side){-webkit-border-start:0;border-inline-start:0;-webkit-border-end:var(--border);border-inline-end:var(--border);border-top:0;border-bottom:0;min-width:var(--side-min-width);max-width:var(--side-max-width)}:host(.menu-pane-visible.split-pane-side[side=end]){-webkit-border-start:var(--border);border-inline-start:var(--border);-webkit-border-end:0;border-inline-end:0;border-top:0;border-bottom:0;min-width:var(--side-min-width);max-width:var(--side-max-width)}:host(.menu-type-overlay) .menu-inner{-webkit-box-shadow:4px 0px 16px rgba(0, 0, 0, 0.18);box-shadow:4px 0px 16px rgba(0, 0, 0, 0.18)}";
const iosEasing = 'cubic-bezier(0.32,0.72,0,1)';
const mdEasing = 'cubic-bezier(0.0,0.0,0.2,1)';
const iosEasingReverse = 'cubic-bezier(1, 0, 0.68, 0.28)';
const mdEasingReverse = 'cubic-bezier(0.4, 0, 0.6, 1)';
/**
* @part container - The container for the menu content.
* @part backdrop - The backdrop that appears over the main content when the menu is open.
*/
class Menu {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionWillOpen = createEvent(this, "ionWillOpen", 7);
this.ionWillClose = createEvent(this, "ionWillClose", 7);
this.ionDidOpen = createEvent(this, "ionDidOpen", 7);
this.ionDidClose = createEvent(this, "ionDidClose", 7);
this.ionMenuChange = createEvent(this, "ionMenuChange", 7);
this.lastOnEnd = 0;
this.blocker = GESTURE_CONTROLLER.createBlocker({ disableScroll: true });
this.didLoad = false;
/**
* Flag used to determine if an open/close
* operation was cancelled. For example, if
* an app calls "menu.open" then disables the menu
* part way through the animation, then this would
* be considered a cancelled operation.
*/
this.operationCancelled = false;
this.isAnimating = false;
this._isOpen = false;
this.inheritedAttributes = {};
this.handleFocus = (ev) => {
/**
* Overlays have their own focus trapping listener
* so we do not want the two listeners to conflict
* with each other. If the top-most overlay that is
* open does not contain this ion-menu, then ion-menu's
* focus trapping should not run.
*/
const lastOverlay = getPresentedOverlay(document);
if (lastOverlay && !lastOverlay.contains(this.el)) {
return;
}
this.trapKeyboardFocus(ev, document);
};
/**
* If true, then the menu should be
* visible within a split pane.
* If false, then the menu is hidden.
* However, the menu-button/menu-toggle
* components can be used to open the
* menu.
*/
this.isPaneVisible = false;
this.isEndSide = false;
/**
* If `true`, the menu is disabled.
*/
this.disabled = false;
/**
* Which side of the view the menu should be placed.
*/
this.side = 'start';
/**
* If `true`, swiping the menu is enabled.
*/
this.swipeGesture = true;
/**
* The edge threshold for dragging the menu open.
* If a drag/swipe happens over this value, the menu is not triggered.
*/
this.maxEdgeStart = 50;
}
typeChanged(type, oldType) {
const contentEl = this.contentEl;
if (contentEl) {
if (oldType !== undefined) {
contentEl.classList.remove(`menu-content-${oldType}`);
}
contentEl.classList.add(`menu-content-${type}`);
contentEl.removeAttribute('style');
}
if (this.menuInnerEl) {
// Remove effects of previous animations
this.menuInnerEl.removeAttribute('style');
}
this.animation = undefined;
}
disabledChanged() {
this.updateState();
this.ionMenuChange.emit({
disabled: this.disabled,
open: this._isOpen,
});
}
sideChanged() {
this.isEndSide = isEndSide(this.side);
/**
* Menu direction animation is calculated based on the document direction.
* If the document direction changes, we need to create a new animation.
*/
this.animation = undefined;
}
swipeGestureChanged() {
this.updateState();
}
async connectedCallback() {
// TODO: connectedCallback is fired in CE build
// before WC is defined. This needs to be fixed in Stencil.
if (typeof customElements !== 'undefined' && customElements != null) {
await customElements.whenDefined('ion-menu');
}
if (this.type === undefined) {
this.type = config.get('menuType', 'overlay');
}
{
return;
}
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
async componentDidLoad() {
this.didLoad = true;
/**
* A menu inside of a split pane is assumed
* to be a side pane.
*
* When the menu is loaded it needs to
* see if it should be considered visible inside
* of the split pane. If the split pane is
* hidden then the menu should be too.
*/
const splitPane = this.el.closest('ion-split-pane');
if (splitPane !== null) {
this.isPaneVisible = await splitPane.isVisible();
}
this.menuChanged();
this.updateState();
}
menuChanged() {
/**
* Inform dependent components such as ion-menu-button
* that the menu is ready. Note that we only want to do this
* once the menu has been rendered which is why we check for didLoad.
*/
if (this.didLoad) {
this.ionMenuChange.emit({ disabled: this.disabled, open: this._isOpen });
}
}
async disconnectedCallback() {
/**
* The menu should be closed when it is
* unmounted from the DOM.
* This is an async call, so we need to wait for
* this to finish otherwise contentEl
* will not have MENU_CONTENT_OPEN removed.
*/
await this.close(false);
this.blocker.destroy();
menuController._unregister(this);
if (this.animation) {
this.animation.destroy();
}
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
this.animation = undefined;
this.contentEl = undefined;
}
onSplitPaneChanged(ev) {
const closestSplitPane = this.el.closest('ion-split-pane');
if (closestSplitPane !== null && closestSplitPane === ev.target) {
this.isPaneVisible = ev.detail.visible;
this.updateState();
}
}
onBackdropClick(ev) {
// TODO(FW-2832): type (CustomEvent triggers errors which should be sorted)
if (this._isOpen && this.lastOnEnd < ev.timeStamp - 100) {
const shouldClose = ev.composedPath ? !ev.composedPath().includes(this.menuInnerEl) : false;
if (shouldClose) {
ev.preventDefault();
ev.stopPropagation();
this.close(undefined, BACKDROP);
}
}
}
onKeydown(ev) {
if (ev.key === 'Escape') {
this.close(undefined, BACKDROP);
}
}
/**
* Returns `true` is the menu is open.
*/
isOpen() {
return Promise.resolve(this._isOpen);
}
/**
* Returns `true` if the menu is active.
*
* A menu is active when it can be opened or closed, meaning it's enabled
* and it's not part of a `ion-split-pane`.
*/
isActive() {
return Promise.resolve(this._isActive());
}
/**
* Opens the menu. If the menu is already open or it can't be opened,
* it returns `false`.
*
* @param animated If `true`, the menu will animate when opening.
* If `false`, the menu will open instantly without animation.
* Defaults to `true`.
*/
open(animated = true) {
return this.setOpen(true, animated);
}
/**
* Closes the menu. If the menu is already closed or it can't be closed,
* it returns `false`.
*
* @param animated If `true`, the menu will animate when closing. If `false`,
* the menu will close instantly without animation. Defaults to `true`.
* @param role The role of the element that is closing the menu.
* This can be useful in a button handler for determining which button was
* clicked to close the menu. Some examples include:
* `"cancel"`, `"destructive"`, `"selected"`, and `"backdrop"`.
*/
close(animated = true, role) {
return this.setOpen(false, animated, role);
}
/**
* Toggles the menu. If the menu is already open, it will try to close,
* otherwise it will try to open it.
* If the operation can't be completed successfully, it returns `false`.
*
* @param animated If `true`, the menu will animate when opening/closing.
* If `false`, the menu will open/close instantly without animation.
* Defaults to `true`.
*/
toggle(animated = true) {
return this.setOpen(!this._isOpen, animated);
}
/**
* Opens or closes the menu.
* If the operation can't be completed successfully, it returns `false`.
*
* @param shouldOpen If `true`, the menu will open. If `false`, the menu
* will close.
* @param animated If `true`, the menu will animate when opening/closing.
* If `false`, the menu will open/close instantly without animation.
* @param role The role of the element that is closing the menu.
*/
setOpen(shouldOpen, animated = true, role) {
var _a;
// Blur the active element to prevent it from being kept focused inside an element that will be set with aria-hidden="true"
(_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.blur();
return menuController._setOpen(this, shouldOpen, animated, role);
}
trapKeyboardFocus(ev, doc) {
const target = ev.target;
if (!target) {
return;
}
/**
* If the target is inside the menu contents, let the browser
* focus as normal and keep a log of the last focused element.
*/
if (this.el.contains(target)) {
this.lastFocus = target;
}
else {
/**
* Otherwise, we are about to have focus go out of the menu.
* Wrap the focus to either the first or last element.
*/
const { el } = this;
/**
* Once we call `focusFirstDescendant`, another focus event
* will fire, which will cause `lastFocus` to be updated
* before we can run the code after that. We cache the value
* here to avoid that.
*/
focusFirstDescendant(el);
/**
* If the cached last focused element is the same as the now-
* active element, that means the user was on the first element
* already and pressed Shift + Tab, so we need to wrap to the
* last descendant.
*/
if (this.lastFocus === doc.activeElement) {
focusLastDescendant(el);
}
}
}
async _setOpen(shouldOpen, animated = true, role) {
// If the menu is disabled or it is currently being animated, let's do nothing
if (!this._isActive() || this.isAnimating || shouldOpen === this._isOpen) {
return false;
}
this.beforeAnimation(shouldOpen, role);
await this.loadAnimation();
await this.startAnimation(shouldOpen, animated);
/**
* If the animation was cancelled then
* return false because the operation
* did not succeed.
*/
if (this.operationCancelled) {
this.operationCancelled = false;
return false;
}
this.afterAnimation(shouldOpen, role);
return true;
}
async loadAnimation() {
// Menu swipe animation takes the menu's inner width as parameter,
// If `offsetWidth` changes, we need to create a new animation.
const width = this.menuInnerEl.offsetWidth;
/**
* Menu direction animation is calculated based on the document direction.
* If the document direction changes, we need to create a new animation.
*/
const isEndSide$1 = isEndSide(this.side);
if (width === this.width && this.animation !== undefined && isEndSide$1 === this.isEndSide) {
return;
}
this.width = width;
this.isEndSide = isEndSide$1;
// Destroy existing animation
if (this.animation) {
this.animation.destroy();
this.animation = undefined;
}
// Create new animation
const animation = (this.animation = await menuController._createAnimation(this.type, this));
if (!config.getBoolean('animated', true)) {
animation.duration(0);
}
animation.fill('both');
}
async startAnimation(shouldOpen, animated) {
const isReversed = !shouldOpen;
const mode = getIonMode$1(this);
const easing = mode === 'ios' ? iosEasing : mdEasing;
const easingReverse = mode === 'ios' ? iosEasingReverse : mdEasingReverse;
const ani = this.animation
.direction(isReversed ? 'reverse' : 'normal')
.easing(isReversed ? easingReverse : easing);
if (animated) {
await ani.play();
}
else {
ani.play({ sync: true });
}
/**
* We run this after the play invocation
* instead of using ani.onFinish so that
* multiple onFinish callbacks do not get
* run if an animation is played, stopped,
* and then played again.
*/
if (ani.getDirection() === 'reverse') {
ani.direction('normal');
}
}
_isActive() {
return !this.disabled && !this.isPaneVisible;
}
canSwipe() {
return this.swipeGesture && !this.isAnimating && this._isActive();
}
canStart(detail) {
// Do not allow swipe gesture if a modal is open
const isModalPresented = !!document.querySelector('ion-modal.show-modal');
if (isModalPresented || !this.canSwipe()) {
return false;
}
if (this._isOpen) {
return true;
}
else if (menuController._getOpenSync()) {
return false;
}
return checkEdgeSide(window, detail.currentX, this.isEndSide, this.maxEdgeStart);
}
onWillStart() {
this.beforeAnimation(!this._isOpen, GESTURE);
return this.loadAnimation();
}
onStart() {
if (!this.isAnimating || !this.animation) {
assert(false, 'isAnimating has to be true');
return;
}
// the cloned animation should not use an easing curve during seek
this.animation.progressStart(true, this._isOpen ? 1 : 0);
}
onMove(detail) {
if (!this.isAnimating || !this.animation) {
assert(false, 'isAnimating has to be true');
return;
}
const delta = computeDelta(detail.deltaX, this._isOpen, this.isEndSide);
const stepValue = delta / this.width;
this.animation.progressStep(this._isOpen ? 1 - stepValue : stepValue);
}
onEnd(detail) {
if (!this.isAnimating || !this.animation) {
assert(false, 'isAnimating has to be true');
return;
}
const isOpen = this._isOpen;
const isEndSide = this.isEndSide;
const delta = computeDelta(detail.deltaX, isOpen, isEndSide);
const width = this.width;
const stepValue = delta / width;
const velocity = detail.velocityX;
const z = width / 2.0;
const shouldCompleteRight = velocity >= 0 && (velocity > 0.2 || detail.deltaX > z);
const shouldCompleteLeft = velocity <= 0 && (velocity < -0.2 || detail.deltaX < -z);
const shouldComplete = isOpen
? isEndSide
? shouldCompleteRight
: shouldCompleteLeft
: isEndSide
? shouldCompleteLeft
: shouldCompleteRight;
let shouldOpen = !isOpen && shouldComplete;
if (isOpen && !shouldComplete) {
shouldOpen = true;
}
this.lastOnEnd = detail.currentTime;
// Account for rounding errors in JS
let newStepValue = shouldComplete ? 0.001 : -1e-3;
/**
* stepValue can sometimes return a negative
* value, but you can't have a negative time value
* for the cubic bezier curve (at least with web animations)
*/
const adjustedStepValue = stepValue < 0 ? 0.01 : stepValue;
/**
* Animation will be reversed here, so need to
* reverse the easing curve as well
*
* Additionally, we need to account for the time relative
* to the new easing curve, as `stepValue` is going to be given
* in terms of a linear curve.
*/
newStepValue +=
getTimeGivenProgression([0, 0], [0.4, 0], [0.6, 1], [1, 1], clamp(0, adjustedStepValue, 0.9999))[0] || 0;
const playTo = this._isOpen ? !shouldComplete : shouldComplete;
this.animation
.easing('cubic-bezier(0.4, 0.0, 0.6, 1)')
.onFinish(() => this.afterAnimation(shouldOpen, GESTURE), { oneTimeCallback: true })
.progressEnd(playTo ? 1 : 0, this._isOpen ? 1 - newStepValue : newStepValue, 300);
}
beforeAnimation(shouldOpen, role) {
assert(!this.isAnimating, '_before() should not be called while animating');
/**
* When the menu is presented on an Android device, TalkBack's focus rings
* may appear in the wrong position due to the transition (specifically
* `transform` styles). This occurs because the focus rings are initially
* displayed at the starting position of the elements before the transition
* begins. This workaround ensures the focus rings do not appear in the
* incorrect location.
*
* If this solution is applied to iOS devices, then it leads to a bug where
* the overlays cannot be accessed by screen readers. This is due to
* VoiceOver not being able to update the accessibility tree when the
* `aria-hidden` is removed.
*/
if (isPlatform('android')) {
this.el.setAttribute('aria-hidden', 'true');
}
// this places the menu into the correct location before it animates in
// this css class doesn't actually kick off any animations
this.el.classList.add(SHOW_MENU);
/**
* We add a tabindex here so that focus trapping
* still works even if the menu does not have
* any focusable elements slotted inside. The
* focus trapping utility will fallback to focusing
* the menu so focus does not leave when the menu
* is open.
*/
this.el.setAttribute('tabindex', '0');
if (this.backdropEl) {
this.backdropEl.classList.add(SHOW_BACKDROP);
}
// add css class and hide content behind menu from screen readers
if (this.contentEl) {
this.contentEl.classList.add(MENU_CONTENT_OPEN);
/**
* When the menu is open and overlaying the main
* content, the main content should not be announced
* by the screenreader as the menu is the main
* focus. This is useful with screenreaders that have
* "read from top" gestures that read the entire
* page from top to bottom when activated.
* This should be done before the animation starts
* so that users cannot accidentally scroll
* the content while dragging a menu open.
*/
this.contentEl.setAttribute('aria-hidden', 'true');
}
this.blocker.block();
this.isAnimating = true;
if (shouldOpen) {
this.ionWillOpen.emit();
}
else {
this.ionWillClose.emit({ role });
}
}
afterAnimation(isOpen, role) {
var _a;
// keep opening/closing the menu disabled for a touch more yet
// only add listeners/css if it's enabled and isOpen
// and only remove listeners/css if it's not open
// emit opened/closed events
this._isOpen = isOpen;
this.isAnimating = false;
if (!this._isOpen) {
this.blocker.unblock();
}
if (isOpen) {
/**
* When the menu is presented on an Android device, TalkBack's focus rings
* may appear in the wrong position due to the transition (specifically
* `transform` styles). The menu is hidden from screen readers during the
* transition to prevent this. Once the transition is complete, the menu
* is shown again.
*/
if (isPlatform('android')) {
this.el.removeAttribute('aria-hidden');
}
// emit open event
this.ionDidOpen.emit();
/**
* Move focus to the menu to prepare focus trapping, as long as
* it isn't already focused. Use the host element instead of the
* first descendant to avoid the scroll position jumping around.
*/
const focusedMenu = (_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.closest('ion-menu');
if (focusedMenu !== this.el) {
this.el.focus();
}
// start focus trapping
document.addEventListener('focus', this.handleFocus, true);
}
else {
this.el.removeAttribute('aria-hidden');
// remove css classes and unhide content from screen readers
this.el.classList.remove(SHOW_MENU);
/**
* Remove tabindex from the menu component
* so that is cannot be tabbed to.
*/
this.el.removeAttribute('tabindex');
if (this.contentEl) {
this.contentEl.classList.remove(MENU_CONTENT_OPEN);
/**
* Remove aria-hidden so screen readers
* can announce the main content again
* now that the menu is not the main focus.
*/
this.contentEl.removeAttribute('aria-hidden');
}
if (this.backdropEl) {
this.backdropEl.classList.remove(SHOW_BACKDROP);
}
if (this.animation) {
this.animation.stop();
}
// emit close event
this.ionDidClose.emit({ role });
// undo focus trapping so multiple menus don't collide
document.removeEventListener('focus', this.handleFocus, true);
}
}
updateState() {
const isActive = this._isActive();
if (this.gesture) {
this.gesture.enable(isActive && this.swipeGesture);
}
/**
* If the menu is disabled but it is still open
* then we should close the menu immediately.
* Additionally, if the menu is in the process
* of animating {open, close} and the menu is disabled
* then it should still be closed immediately.
*/
if (!isActive) {
/**
* It is possible to disable the menu while
* it is mid-animation. When this happens, we
* need to set the operationCancelled flag
* so that this._setOpen knows to return false
* and not run the "afterAnimation" callback.
*/
if (this.isAnimating) {
this.operationCancelled = true;
}
/**
* If the menu is disabled then we should
* forcibly close the menu even if it is open.
*/
this.afterAnimation(false, GESTURE);
}
}
render() {
const { type, disabled, el, isPaneVisible, inheritedAttributes, side } = this;
const mode = getIonMode$1(this);
/**
* If the Close Watcher is enabled then
* the ionBackButton listener in the menu controller
* will handle closing the menu when Escape is pressed.
*/
return (hAsync(Host, { key: '70a427f3414a476414c3386efe6c8723fd37eccf', onKeyDown: shouldUseCloseWatcher() ? null : this.onKeydown, role: "navigation", "aria-label": inheritedAttributes['aria-label'] || 'menu', class: {
[mode]: true,
[`menu-type-${type}`]: true,
'menu-enabled': !disabled,
[`menu-side-${side}`]: true,
'menu-pane-visible': isPaneVisible,
'split-pane-side': hostContext('ion-split-pane', el),
} }, hAsync("div", { key: '83af04e5a47d5a92caafaf06088a7114ae61984b', class: "menu-inner", part: "container", ref: (el) => (this.menuInnerEl = el) }, hAsync("slot", { key: '7b35048642864bd0f30de9f6b61c949c1b601692' })), hAsync("ion-backdrop", { key: '347af516c7970d80dd11c6d1ed61e9a040ceb5fb', ref: (el) => (this.backdropEl = el), class: "menu-backdrop", tappable: false, stopPropagation: false, part: "backdrop" })));
}
get el() { return getElement(this); }
static get watchers() { return {
"type": ["typeChanged"],
"disabled": ["disabledChanged"],
"side": ["sideChanged"],
"swipeGesture": ["swipeGestureChanged"]
}; }
static get style() { return {
ios: menuIosCss,
md: menuMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-menu",
"$members$": {
"contentId": [513, "content-id"],
"menuId": [513, "menu-id"],
"type": [1025],
"disabled": [1028],
"side": [513],
"swipeGesture": [4, "swipe-gesture"],
"maxEdgeStart": [2, "max-edge-start"],
"isPaneVisible": [32],
"isEndSide": [32],
"isOpen": [64],
"isActive": [64],
"open": [64],
"close": [64],
"toggle": [64],
"setOpen": [64]
},
"$listeners$": [[16, "ionSplitPaneVisible", "onSplitPaneChanged"], [2, "click", "onBackdropClick"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["contentId", "content-id"], ["menuId", "menu-id"], ["side", "side"]]
}; }
}
const computeDelta = (deltaX, isOpen, isEndSide) => {
return Math.max(0, isOpen !== isEndSide ? -deltaX : deltaX);
};
const checkEdgeSide = (win, posX, isEndSide, maxEdgeStart) => {
if (isEndSide) {
return posX >= win.innerWidth - maxEdgeStart;
}
else {
return posX <= maxEdgeStart;
}
};
const SHOW_MENU = 'show-menu';
const SHOW_BACKDROP = 'show-backdrop';
const MENU_CONTENT_OPEN = 'menu-content-open';
// Given a menu, return whether or not the menu toggle should be visible
const updateVisibility = async (menu) => {
const menuEl = await menuController.get(menu);
return !!(menuEl && (await menuEl.isActive()));
};
const menuButtonIosCss = ":host{--background:transparent;--color-focused:currentColor;--border-radius:initial;--padding-top:0;--padding-bottom:0;color:var(--color);text-align:center;text-decoration:none;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:var(--border-radius);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;min-height:inherit;border:0;outline:none;background:var(--background);line-height:1;cursor:pointer;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;min-height:inherit;z-index:1}ion-icon{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;pointer-events:none}:host(.menu-button-hidden){display:none}:host(.menu-button-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity, 0)}}:host(.ion-color) .button-native{color:var(--ion-color-base)}:host(.in-toolbar:not(.in-toolbar-color)){color:var(--ion-toolbar-color, var(--color))}:host{--background-focused:currentColor;--background-focused-opacity:.1;--border-radius:4px;--color:var(--ion-color-primary, #0054e9);--padding-start:5px;--padding-end:5px;min-height:32px;font-size:clamp(31px, 1.9375rem, 38.13px)}:host(.ion-activated){opacity:0.4}@media (any-hover: hover){:host(:hover){opacity:0.6}}";
const menuButtonMdCss = ":host{--background:transparent;--color-focused:currentColor;--border-radius:initial;--padding-top:0;--padding-bottom:0;color:var(--color);text-align:center;text-decoration:none;text-overflow:ellipsis;text-transform:none;white-space:nowrap;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:var(--border-radius);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;min-height:inherit;border:0;outline:none;background:var(--background);line-height:1;cursor:pointer;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:row nowrap;flex-flow:row nowrap;-ms-flex-negative:0;flex-shrink:0;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;min-height:inherit;z-index:1}ion-icon{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;pointer-events:none}:host(.menu-button-hidden){display:none}:host(.menu-button-disabled){cursor:default;opacity:0.5;pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity, 0)}}:host(.ion-color) .button-native{color:var(--ion-color-base)}:host(.in-toolbar:not(.in-toolbar-color)){color:var(--ion-toolbar-color, var(--color))}:host{--background-focused:currentColor;--background-focused-opacity:.12;--background-hover:currentColor;--background-hover-opacity:.04;--border-radius:50%;--color:initial;--padding-start:8px;--padding-end:8px;width:3rem;height:3rem;font-size:1.5rem}:host(.ion-color.ion-focused)::after{background:var(--ion-color-base)}@media (any-hover: hover){:host(.ion-color:hover) .button-native::after{background:var(--ion-color-base)}}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML button element that wraps all child elements.
* @part icon - The menu button icon (uses ion-icon).
*/
class MenuButton {
constructor(hostRef) {
registerInstance(this, hostRef);
this.inheritedAttributes = {};
this.visible = false;
/**
* If `true`, the user cannot interact with the menu button.
*/
this.disabled = false;
/**
* Automatically hides the menu button when the corresponding menu is not active
*/
this.autoHide = true;
/**
* The type of the button.
*/
this.type = 'button';
this.onClick = async () => {
return menuController.toggle(this.menu);
};
}
componentWillLoad() {
this.inheritedAttributes = inheritAriaAttributes(this.el);
}
componentDidLoad() {
this.visibilityChanged();
}
async visibilityChanged() {
this.visible = await updateVisibility(this.menu);
}
render() {
const { color, disabled, inheritedAttributes } = this;
const mode = getIonMode$1(this);
const menuIcon = config.get('menuIcon', mode === 'ios' ? menuOutline : menuSharp);
const hidden = this.autoHide && !this.visible;
const attrs = {
type: this.type,
};
const ariaLabel = inheritedAttributes['aria-label'] || 'menu';
return (hAsync(Host, { key: '9f0f0e50d39a6872508220c58e64bb2092a0d7ef', onClick: this.onClick, "aria-disabled": disabled ? 'true' : null, "aria-hidden": hidden ? 'true' : null, class: createColorClasses$1(color, {
[mode]: true,
button: true, // ion-buttons target .button
'menu-button-hidden': hidden,
'menu-button-disabled': disabled,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'ion-activatable': true,
'ion-focusable': true,
}) }, hAsync("button", Object.assign({ key: 'ffebf7083d23501839970059ef8e411b571de197' }, attrs, { disabled: disabled, class: "button-native", part: "native", "aria-label": ariaLabel }), hAsync("span", { key: 'cab0c1c763b3ce33ef11dba1d230f66126e59424', class: "button-inner" }, hAsync("slot", { key: 'ccfd2be8479b75b5c63e97e1ca7dfe203e9b36ee' }, hAsync("ion-icon", { key: 'ac254fe7f327b08f1ae3fcea89d5cf0e83c9a96c', part: "icon", icon: menuIcon, mode: mode, lazy: false, "aria-hidden": "true" }))), mode === 'md' && hAsync("ion-ripple-effect", { key: 'f0f17c4ca96e3eed3c1727ee00578d40af8f0115', type: "unbounded" }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: menuButtonIosCss,
md: menuButtonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-menu-button",
"$members$": {
"color": [513],
"disabled": [4],
"menu": [1],
"autoHide": [4, "auto-hide"],
"type": [1],
"visible": [32]
},
"$listeners$": [[16, "ionMenuChange", "visibilityChanged"], [16, "ionSplitPaneVisible", "visibilityChanged"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const menuToggleCss = ":host(.menu-toggle-hidden){display:none}";
/**
* @slot - Content is placed inside the toggle to act as the click target.
*/
class MenuToggle {
constructor(hostRef) {
registerInstance(this, hostRef);
this.visible = false;
/**
* Automatically hides the content when the corresponding menu is not active.
*
* By default, it's `true`. Change it to `false` in order to
* keep `ion-menu-toggle` always visible regardless the state of the menu.
*/
this.autoHide = true;
this.onClick = () => {
return menuController.toggle(this.menu);
};
}
connectedCallback() {
this.visibilityChanged();
}
async visibilityChanged() {
this.visible = await updateVisibility(this.menu);
}
render() {
const mode = getIonMode$1(this);
const hidden = this.autoHide && !this.visible;
return (hAsync(Host, { key: 'cd567114769a30bd3871ed5d15bf42aed39956e1', onClick: this.onClick, "aria-hidden": hidden ? 'true' : null, class: {
[mode]: true,
'menu-toggle-hidden': hidden,
} }, hAsync("slot", { key: '773d4cff95ca75f23578b1e1dca53c9933f28a33' })));
}
static get style() { return menuToggleCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-menu-toggle",
"$members$": {
"menu": [1],
"autoHide": [4, "auto-hide"],
"visible": [32]
},
"$listeners$": [[16, "ionMenuChange", "visibilityChanged"], [16, "ionSplitPaneVisible", "visibilityChanged"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
var Style;
(function (Style) {
Style["Dark"] = "DARK";
Style["Light"] = "LIGHT";
Style["Default"] = "DEFAULT";
})(Style || (Style = {}));
const StatusBar = {
getEngine() {
const capacitor = getCapacitor();
if (capacitor === null || capacitor === void 0 ? void 0 : capacitor.isPluginAvailable('StatusBar')) {
return capacitor.Plugins.StatusBar;
}
return undefined;
},
setStyle(options) {
const engine = this.getEngine();
if (!engine) {
return;
}
engine.setStyle(options);
},
getStyle: async function () {
const engine = this.getEngine();
if (!engine) {
return Style.Default;
}
const { style } = await engine.getInfo();
return style;
},
};
const LIFECYCLE_WILL_ENTER = 'ionViewWillEnter';
const LIFECYCLE_DID_ENTER = 'ionViewDidEnter';
const LIFECYCLE_WILL_LEAVE = 'ionViewWillLeave';
const LIFECYCLE_DID_LEAVE = 'ionViewDidLeave';
const LIFECYCLE_WILL_UNLOAD = 'ionViewWillUnload';
/**
* Moves focus to a specified element. Note that we do not remove the tabindex
* because that can result in an unintentional blur. Non-focusables can't be
* focused, so the body will get focused again.
*/
const moveFocus = (el) => {
el.tabIndex = -1;
el.focus();
};
/**
* Elements that are hidden using `display: none` should not be focused even if
* they are present in the DOM.
*/
const isVisible = (el) => {
return el.offsetParent !== null;
};
/**
* The focus controller allows us to manage focus within a view so assistive
* technologies can inform users of changes to the navigation state. Traditional
* native apps have a way of informing assistive technology about a navigation
* state change. Mobile browsers have this too, but only when doing a full page
* load. In a single page app we do not do that, so we need to build this
* integration ourselves.
*/
const createFocusController = () => {
const saveViewFocus = (referenceEl) => {
const focusManagerEnabled = config.get('focusManagerPriority', false);
/**
* When going back to a previously visited page focus should typically be moved
* back to the element that was last focused when the user was on this view.
*/
if (focusManagerEnabled) {
const activeEl = document.activeElement;
if (activeEl !== null && (referenceEl === null || referenceEl === void 0 ? void 0 : referenceEl.contains(activeEl))) {
activeEl.setAttribute(LAST_FOCUS, 'true');
}
}
};
const setViewFocus = (referenceEl) => {
const focusManagerPriorities = config.get('focusManagerPriority', false);
/**
* If the focused element is a descendant of the referenceEl then it's possible
* that the app developer manually moved focus, so we do not want to override that.
* This can happen with inputs the are focused when a view transitions in.
*/
if (Array.isArray(focusManagerPriorities) && !referenceEl.contains(document.activeElement)) {
/**
* When going back to a previously visited view focus should always be moved back
* to the element that the user was last focused on when they were on this view.
*/
const lastFocus = referenceEl.querySelector(`[${LAST_FOCUS}]`);
if (lastFocus && isVisible(lastFocus)) {
moveFocus(lastFocus);
return;
}
for (const priority of focusManagerPriorities) {
/**
* For each recognized case (excluding the default case) make sure to return
* so that the fallback focus behavior does not run.
*
* We intentionally query for specific roles/semantic elements so that the
* transition manager can work with both Ionic and non-Ionic UI components.
*
* If new selectors are added, be sure to remove the outline ring by adding
* new selectors to rule in core.scss.
*/
switch (priority) {
case 'content':
const content = referenceEl.querySelector('main, [role="main"]');
if (content && isVisible(content)) {
moveFocus(content);
return;
}
break;
case 'heading':
const headingOne = referenceEl.querySelector('h1, [role="heading"][aria-level="1"]');
if (headingOne && isVisible(headingOne)) {
moveFocus(headingOne);
return;
}
break;
case 'banner':
const header = referenceEl.querySelector('header, [role="banner"]');
if (header && isVisible(header)) {
moveFocus(header);
return;
}
break;
default:
printIonWarning(`Unrecognized focus manager priority value ${priority}`);
break;
}
}
/**
* If there is nothing to focus then focus the page so focus at least moves to
* the correct view. The browser will then determine where within the page to
* move focus to.
*/
moveFocus(referenceEl);
}
};
return {
saveViewFocus,
setViewFocus,
};
};
const LAST_FOCUS = 'ion-last-focus';
const iosTransitionAnimation$1 = () => Promise.resolve().then(function () { return ios_transition; });
const mdTransitionAnimation$1 = () => Promise.resolve().then(function () { return md_transition; });
const focusController = createFocusController();
// TODO(FW-2832): types
/**
* Executes the main page transition.
* It also manages the lifecycle of header visibility (if any)
* to prevent visual flickering in iOS. The flickering only
* occurs for a condensed header that is placed above the content.
*
* @param opts Options for the transition.
* @returns A promise that resolves when the transition is complete.
*/
const transition = (opts) => {
return new Promise((resolve, reject) => {
writeTask(() => {
const transitioningInactiveHeader = getIosIonHeader(opts);
beforeTransition(opts, transitioningInactiveHeader);
runTransition(opts)
.then((result) => {
if (result.animation) {
result.animation.destroy();
}
afterTransition(opts);
resolve(result);
}, (error) => {
afterTransition(opts);
reject(error);
})
.finally(() => {
// Ensure that the header is restored to its original state.
setHeaderTransitionClass(transitioningInactiveHeader, false);
});
});
});
};
const beforeTransition = (opts, transitioningInactiveHeader) => {
const enteringEl = opts.enteringEl;
const leavingEl = opts.leavingEl;
focusController.saveViewFocus(leavingEl);
setZIndex(enteringEl, leavingEl, opts.direction);
// Prevent flickering of the header by adding a class.
setHeaderTransitionClass(transitioningInactiveHeader, true);
if (opts.showGoBack) {
enteringEl.classList.add('can-go-back');
}
else {
enteringEl.classList.remove('can-go-back');
}
setPageHidden(enteringEl, false);
/**
* When transitioning, the page should not
* respond to click events. This resolves small
* issues like users double tapping the ion-back-button.
* These pointer events are removed in `afterTransition`.
*/
enteringEl.style.setProperty('pointer-events', 'none');
if (leavingEl) {
setPageHidden(leavingEl, false);
leavingEl.style.setProperty('pointer-events', 'none');
}
};
const runTransition = async (opts) => {
const animationBuilder = await getAnimationBuilder(opts);
const ani = animationBuilder && Build.isBrowser ? animation(animationBuilder, opts) : noAnimation(opts); // fast path for no animation
return ani;
};
const afterTransition = (opts) => {
const enteringEl = opts.enteringEl;
const leavingEl = opts.leavingEl;
enteringEl.classList.remove('ion-page-invisible');
enteringEl.style.removeProperty('pointer-events');
if (leavingEl !== undefined) {
leavingEl.classList.remove('ion-page-invisible');
leavingEl.style.removeProperty('pointer-events');
}
focusController.setViewFocus(enteringEl);
};
const getAnimationBuilder = async (opts) => {
if (!opts.leavingEl || !opts.animated || opts.duration === 0) {
return undefined;
}
if (opts.animationBuilder) {
return opts.animationBuilder;
}
const getAnimation = opts.mode === 'ios'
? (await iosTransitionAnimation$1()).iosTransitionAnimation
: (await mdTransitionAnimation$1()).mdTransitionAnimation;
return getAnimation;
};
const animation = async (animationBuilder, opts) => {
await waitForReady(opts, true);
const trans = animationBuilder(opts.baseEl, opts);
fireWillEvents(opts.enteringEl, opts.leavingEl);
const didComplete = await playTransition(trans, opts);
if (opts.progressCallback) {
opts.progressCallback(undefined);
}
if (didComplete) {
fireDidEvents(opts.enteringEl, opts.leavingEl);
}
return {
hasCompleted: didComplete,
animation: trans,
};
};
const noAnimation = async (opts) => {
const enteringEl = opts.enteringEl;
const leavingEl = opts.leavingEl;
const focusManagerEnabled = config.get('focusManagerPriority', false);
/**
* If the focus manager is enabled then we need to wait for Ionic components to be
* rendered otherwise the component to focus may not be focused because it is hidden.
*/
await waitForReady(opts, focusManagerEnabled);
fireWillEvents(enteringEl, leavingEl);
fireDidEvents(enteringEl, leavingEl);
return {
hasCompleted: true,
};
};
const waitForReady = async (opts, defaultDeep) => {
const deep = opts.deepWait !== undefined ? opts.deepWait : defaultDeep;
if (deep) {
await Promise.all([deepReady(opts.enteringEl), deepReady(opts.leavingEl)]);
}
await notifyViewReady(opts.viewIsReady, opts.enteringEl);
};
const notifyViewReady = async (viewIsReady, enteringEl) => {
if (viewIsReady) {
await viewIsReady(enteringEl);
}
};
const playTransition = (trans, opts) => {
const progressCallback = opts.progressCallback;
const promise = new Promise((resolve) => {
trans.onFinish((currentStep) => resolve(currentStep === 1));
});
// cool, let's do this, start the transition
if (progressCallback) {
// this is a swipe to go back, just get the transition progress ready
// kick off the swipe animation start
trans.progressStart(true);
progressCallback(trans);
}
else {
// only the top level transition should actually start "play"
// kick it off and let it play through
// ******** DOM WRITE ****************
trans.play();
}
// create a callback for when the animation is done
return promise;
};
const fireWillEvents = (enteringEl, leavingEl) => {
lifecycle(leavingEl, LIFECYCLE_WILL_LEAVE);
lifecycle(enteringEl, LIFECYCLE_WILL_ENTER);
};
const fireDidEvents = (enteringEl, leavingEl) => {
lifecycle(enteringEl, LIFECYCLE_DID_ENTER);
lifecycle(leavingEl, LIFECYCLE_DID_LEAVE);
};
const lifecycle = (el, eventName) => {
if (el) {
const ev = new CustomEvent(eventName, {
bubbles: false,
cancelable: false,
});
el.dispatchEvent(ev);
}
};
/**
* Wait two request animation frame loops.
* This allows the framework implementations enough time to mount
* the user-defined contents. This is often needed when using inline
* modals and popovers that accept user components. For popover,
* the contents must be mounted for the popover to be sized correctly.
* For modals, the contents must be mounted for iOS to run the
* transition correctly.
*
* On Angular and React, a single raf is enough time, but for Vue
* we need to wait two rafs. As a result we are using two rafs for
* all frameworks to ensure contents are mounted.
*/
const waitForMount = () => {
return new Promise((resolve) => raf(() => raf(() => resolve())));
};
const deepReady = async (el) => {
const element = el;
if (element) {
if (element.componentOnReady != null) {
// eslint-disable-next-line custom-rules/no-component-on-ready-method
const stencilEl = await element.componentOnReady();
if (stencilEl != null) {
return;
}
/**
* Custom elements in Stencil will have __registerHost.
*/
}
else if (element.__registerHost != null) {
/**
* Non-lazy loaded custom elements need to wait
* one frame for component to be loaded.
*/
const waitForCustomElement = new Promise((resolve) => raf(resolve));
await waitForCustomElement;
return;
}
await Promise.all(Array.from(element.children).map(deepReady));
}
};
const setPageHidden = (el, hidden) => {
if (hidden) {
el.setAttribute('aria-hidden', 'true');
el.classList.add('ion-page-hidden');
}
else {
el.hidden = false;
el.removeAttribute('aria-hidden');
el.classList.remove('ion-page-hidden');
}
};
const setZIndex = (enteringEl, leavingEl, direction) => {
if (enteringEl !== undefined) {
enteringEl.style.zIndex = direction === 'back' ? '99' : '101';
}
if (leavingEl !== undefined) {
leavingEl.style.zIndex = '100';
}
};
/**
* Add a class to ensure that the header (if any)
* does not flicker during the transition. By adding the
* transitioning class, we ensure that the header has
* the necessary styles to prevent the following flickers:
* 1. When entering a page with a condensed header, the
* header should never be visible. However,
* it briefly renders the background color while
* the transition is occurring.
* 2. When leaving a page with a condensed header, the
* header has an opacity of 0 and the pages
* have a z-index which causes the entering page to
* briefly show it's content underneath the leaving page.
* 3. When entering a page or leaving a page with a fade
* header, the header should not have a background color.
* However, it briefly shows the background color while
* the transition is occurring.
*
* @param header The header element to modify.
* @param isTransitioning Whether the transition is occurring.
*/
const setHeaderTransitionClass = (header, isTransitioning) => {
if (!header) {
return;
}
const transitionClass = 'header-transitioning';
if (isTransitioning) {
header.classList.add(transitionClass);
}
else {
header.classList.remove(transitionClass);
}
};
const getIonPageElement = (element) => {
if (element.classList.contains('ion-page')) {
return element;
}
const ionPage = element.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs');
if (ionPage) {
return ionPage;
}
// idk, return the original element so at least something animates and we don't have a null pointer
return element;
};
/**
* Retrieves the ion-header element from a page based on the
* direction of the transition.
*
* @param opts Options for the transition.
* @returns The ion-header element or null if not found or not in 'ios' mode.
*/
const getIosIonHeader = (opts) => {
const enteringEl = opts.enteringEl;
const leavingEl = opts.leavingEl;
const direction = opts.direction;
const mode = opts.mode;
if (mode !== 'ios') {
return null;
}
const element = direction === 'back' ? leavingEl : enteringEl;
if (!element) {
return null;
}
return element.querySelector('ion-header');
};
const KEYBOARD_DID_OPEN = 'ionKeyboardDidShow';
/**
* Use y = mx + b to
* figure out the backdrop value
* at a particular x coordinate. This
* is useful when the backdrop does
* not begin to fade in until after
* the 0 breakpoint.
*/
const getBackdropValueForSheet = (x, backdropBreakpoint) => {
/**
* We will use these points:
* (backdropBreakpoint, 0)
* (maxBreakpoint, 1)
* We know that at the beginning breakpoint,
* the backdrop will be hidden. We also
* know that at the maxBreakpoint, the backdrop
* must be fully visible. maxBreakpoint should
* always be 1 even if the maximum value
* of the breakpoints array is not 1 since
* the animation runs from a progress of 0
* to a progress of 1.
* m = (y2 - y1) / (x2 - x1)
*
* This is simplified from:
* m = (1 - 0) / (maxBreakpoint - backdropBreakpoint)
*
* If the backdropBreakpoint is 1, we return 0 as the
* backdrop is completely hidden.
*
*/
if (backdropBreakpoint === 1) {
return 0;
}
const slope = 1 / (1 - backdropBreakpoint);
/**
* From here, compute b which is
* the backdrop opacity if the offset
* is 0. If the backdrop does not
* begin to fade in until after the
* 0 breakpoint, this b value will be
* negative. This is fine as we never pass
* b directly into the animation keyframes.
* b = y - mx
* Use a known point: (backdropBreakpoint, 0)
* This is simplified from:
* b = 0 - (backdropBreakpoint * slope)
*/
const b = -(backdropBreakpoint * slope);
/**
* Finally, we can now determine the
* backdrop offset given an arbitrary
* gesture offset.
*/
return x * slope + b;
};
/**
* The tablet/desktop card modal activates
* when the window width is >= 768.
* At that point, the presenting element
* is not transformed, so we do not need to
* adjust the status bar color.
*
*/
const setCardStatusBarDark = () => {
if (!win$1 || win$1.innerWidth >= 768) {
return;
}
StatusBar.setStyle({ style: Style.Dark });
};
const setCardStatusBarDefault = (defaultStyle = Style.Default) => {
if (!win$1 || win$1.innerWidth >= 768) {
return;
}
StatusBar.setStyle({ style: defaultStyle });
};
const handleCanDismiss = async (el, animation) => {
/**
* If canDismiss is not a function
* then we can return early. If canDismiss is `true`,
* then canDismissBlocksGesture is `false` as canDismiss
* will never interrupt the gesture. As a result,
* this code block is never reached. If canDismiss is `false`,
* then we never dismiss.
*/
if (typeof el.canDismiss !== 'function') {
return;
}
/**
* Run the canDismiss callback.
* If the function returns `true`,
* then we can proceed with dismiss.
*/
const shouldDismiss = await el.canDismiss(undefined, GESTURE);
if (!shouldDismiss) {
return;
}
/**
* If canDismiss resolved after the snap
* back animation finished, we can
* dismiss immediately.
*
* If canDismiss resolved before the snap
* back animation finished, we need to
* wait until the snap back animation is
* done before dismissing.
*/
if (animation.isRunning()) {
animation.onFinish(() => {
el.dismiss(undefined, 'handler');
}, { oneTimeCallback: true });
}
else {
el.dismiss(undefined, 'handler');
}
};
/**
* This function lets us simulate a realistic spring-like animation
* when swiping down on the modal.
* There are two forces that we need to use to compute the spring physics:
*
* 1. Stiffness, k: This is a measure of resistance applied a spring.
* 2. Dampening, c: This value has the effect of reducing or preventing oscillation.
*
* Using these two values, we can calculate the Spring Force and the Dampening Force
* to compute the total force applied to a spring.
*
* Spring Force: This force pulls a spring back into its equilibrium position.
* Hooke's Law tells us that that spring force (FS) = kX.
* k is the stiffness of a spring, and X is the displacement of the spring from its
* equilibrium position. In this case, it is the amount by which the free end
* of a spring was displaced (stretched/pushed) from its "relaxed" position.
*
* Dampening Force: This force slows down motion. Without it, a spring would oscillate forever.
* The dampening force, FD, can be found via this formula: FD = -cv
* where c the dampening value and v is velocity.
*
* Therefore, the resulting force that is exerted on the block is:
* F = FS + FD = -kX - cv
*
* Newton's 2nd Law tells us that F = ma:
* ma = -kX - cv.
*
* For Ionic's purposes, we can assume that m = 1:
* a = -kX - cv
*
* Imagine a block attached to the end of a spring. At equilibrium
* the block is at position x = 1.
* Pressing on the block moves it to position x = 0;
* So, to calculate the displacement, we need to take the
* current position and subtract the previous position from it.
* X = x - x0 = 0 - 1 = -1.
*
* For Ionic's purposes, we are only pushing on the spring modal
* so we have a max position of 1.
* As a result, we can expand displacement to this formula:
* X = x - 1
*
* a = -k(x - 1) - cv
*
* We can represent the motion of something as a function of time: f(t) = x.
* The derivative of position gives us the velocity: f'(t)
* The derivative of the velocity gives us the acceleration: f''(t)
*
* We can substitute the formula above with these values:
*
* f"(t) = -k * (f(t) - 1) - c * f'(t)
*
* This is called a differential equation.
*
* We know that at t = 0, we are at x = 0 because the modal does not move: f(0) = 0
* This means our velocity is also zero: f'(0) = 0.
*
* We can cheat a bit and plug the formula into Wolfram Alpha.
* However, we need to pick stiffness and dampening values:
* k = 0.57
* c = 15
*
* I picked these as they are fairly close to native iOS's spring effect
* with the modal.
*
* What we plug in is this: f(0) = 0; f'(0) = 0; f''(t) = -0.57(f(t) - 1) - 15f'(t)
*
* The result is a formula that lets us calculate the acceleration
* for a given time t.
* Note: This is the approximate form of the solution. Wolfram Alpha will
* give you a complex differential equation too.
*/
const calculateSpringStep = (t) => {
return 0.00255275 * 2.71828 ** (-14.9619 * t) - 1.00255 * 2.71828 ** (-0.0380968 * t) + 1;
};
// Defaults for the card swipe animation
const SwipeToCloseDefaults = {
MIN_PRESENTING_SCALE: 0.915,
};
const createSwipeToCloseGesture = (el, animation, statusBarStyle, onDismiss) => {
/**
* The step value at which a card modal
* is eligible for dismissing via gesture.
*/
const DISMISS_THRESHOLD = 0.5;
const height = el.offsetHeight;
let isOpen = false;
let canDismissBlocksGesture = false;
let contentEl = null;
let scrollEl = null;
const canDismissMaxStep = 0.2;
let initialScrollY = true;
let lastStep = 0;
const getScrollY = () => {
if (contentEl && isIonContent(contentEl)) {
return contentEl.scrollY;
/**
* Custom scroll containers are intended to be
* used with virtual scrolling, so we assume
* there is scrolling in this case.
*/
}
else {
return true;
}
};
const canStart = (detail) => {
const target = detail.event.target;
if (target === null || !target.closest) {
return true;
}
/**
* If we are swiping on the content,
* swiping should only be possible if
* the content is scrolled all the way
* to the top so that we do not interfere
* with scrolling.
*
* We cannot assume that the `ion-content`
* target will remain consistent between
* swipes. For example, when using
* ion-nav within a card modal it is
* possible to swipe, push a view, and then
* swipe again. The target content will not
* be the same between swipes.
*/
contentEl = findClosestIonContent(target);
if (contentEl) {
/**
* The card should never swipe to close
* on the content with a refresher.
* Note: We cannot solve this by making the
* swipeToClose gesture have a higher priority
* than the refresher gesture as the iOS native
* refresh gesture uses a scroll listener in
* addition to a gesture.
*
* Note: Do not use getScrollElement here
* because we need this to be a synchronous
* operation, and getScrollElement is
* asynchronous.
*/
if (isIonContent(contentEl)) {
const root = getElementRoot(contentEl);
scrollEl = root.querySelector('.inner-scroll');
}
else {
scrollEl = contentEl;
}
const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
return !hasRefresherInContent && scrollEl.scrollTop === 0;
}
/**
* Card should be swipeable on all
* parts of the modal except for the footer.
*/
const footer = target.closest('ion-footer');
if (footer === null) {
return true;
}
return false;
};
const onStart = (detail) => {
const { deltaY } = detail;
/**
* Get the initial scrollY value so
* that we can correctly reset the scrollY
* prop when the gesture ends.
*/
initialScrollY = getScrollY();
/**
* If canDismiss is anything other than `true`
* then users should be able to swipe down
* until a threshold is hit. At that point,
* the card modal should not proceed any further.
* TODO (FW-937)
* Remove undefined check
*/
canDismissBlocksGesture = el.canDismiss !== undefined && el.canDismiss !== true;
/**
* If we are pulling down, then
* it is possible we are pulling on the
* content. We do not want scrolling to
* happen at the same time as the gesture.
*/
if (deltaY > 0 && contentEl) {
disableContentScrollY(contentEl);
}
animation.progressStart(true, isOpen ? 1 : 0);
};
const onMove = (detail) => {
const { deltaY } = detail;
/**
* If we are pulling down, then
* it is possible we are pulling on the
* content. We do not want scrolling to
* happen at the same time as the gesture.
*/
if (deltaY > 0 && contentEl) {
disableContentScrollY(contentEl);
}
/**
* If we are swiping on the content
* then the swipe gesture should only
* happen if we are pulling down.
*
* However, if we pull up and
* then down such that the scroll position
* returns to 0, we should be able to swipe
* the card.
*/
const step = detail.deltaY / height;
/**
* Check if user is swiping down and
* if we have a canDismiss value that
* should block the gesture from
* proceeding,
*/
const isAttemptingDismissWithCanDismiss = step >= 0 && canDismissBlocksGesture;
/**
* If we are blocking the gesture from dismissing,
* set the max step value so that the sheet cannot be
* completely hidden.
*/
const maxStep = isAttemptingDismissWithCanDismiss ? canDismissMaxStep : 0.9999;
/**
* If we are blocking the gesture from
* dismissing, calculate the spring modifier value
* this will be added to the starting breakpoint
* value to give the gesture a spring-like feeling.
* Note that the starting breakpoint is always 0,
* so we omit adding 0 to the result.
*/
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
const clampedStep = clamp(0.0001, processedStep, maxStep);
animation.progressStep(clampedStep);
/**
* When swiping down half way, the status bar style
* should be reset to its default value.
*
* We track lastStep so that we do not fire these
* functions on every onMove, only when the user has
* crossed a certain threshold.
*/
if (clampedStep >= DISMISS_THRESHOLD && lastStep < DISMISS_THRESHOLD) {
setCardStatusBarDefault(statusBarStyle);
/**
* However, if we swipe back up, then the
* status bar style should be set to have light
* text on a dark background.
*/
}
else if (clampedStep < DISMISS_THRESHOLD && lastStep >= DISMISS_THRESHOLD) {
setCardStatusBarDark();
}
lastStep = clampedStep;
};
const onEnd = (detail) => {
const velocity = detail.velocityY;
const step = detail.deltaY / height;
const isAttemptingDismissWithCanDismiss = step >= 0 && canDismissBlocksGesture;
const maxStep = isAttemptingDismissWithCanDismiss ? canDismissMaxStep : 0.9999;
const processedStep = isAttemptingDismissWithCanDismiss ? calculateSpringStep(step / maxStep) : step;
const clampedStep = clamp(0.0001, processedStep, maxStep);
const threshold = (detail.deltaY + velocity * 1000) / height;
/**
* If canDismiss blocks
* the swipe gesture, then the
* animation can never complete until
* canDismiss is checked.
*/
const shouldComplete = !isAttemptingDismissWithCanDismiss && threshold >= DISMISS_THRESHOLD;
let newStepValue = shouldComplete ? -1e-3 : 0.001;
if (!shouldComplete) {
animation.easing('cubic-bezier(1, 0, 0.68, 0.28)');
newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], clampedStep)[0];
}
else {
animation.easing('cubic-bezier(0.32, 0.72, 0, 1)');
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], clampedStep)[0];
}
const duration = shouldComplete
? computeDuration(step * height, velocity)
: computeDuration((1 - clampedStep) * height, velocity);
isOpen = shouldComplete;
gesture.enable(false);
if (contentEl) {
resetContentScrollY(contentEl, initialScrollY);
}
animation
.onFinish(() => {
if (!shouldComplete) {
gesture.enable(true);
}
})
.progressEnd(shouldComplete ? 1 : 0, newStepValue, duration);
/**
* If the canDismiss value blocked the gesture
* from proceeding, then we should ignore whatever
* shouldComplete is. Whether or not the modal
* animation should complete is now determined by
* canDismiss.
*
* If the user swiped >25% of the way
* to the max step, then we should
* check canDismiss. 25% was chosen
* to avoid accidental swipes.
*/
if (isAttemptingDismissWithCanDismiss && clampedStep > maxStep / 4) {
handleCanDismiss(el, animation);
}
else if (shouldComplete) {
onDismiss();
}
};
const gesture = createGesture({
el,
gestureName: 'modalSwipeToClose',
gesturePriority: OVERLAY_GESTURE_PRIORITY,
direction: 'y',
threshold: 10,
canStart,
onStart,
onMove,
onEnd,
});
return gesture;
};
const computeDuration = (remaining, velocity) => {
return clamp(400, remaining / Math.abs(velocity * 1.1), 500);
};
const createSheetEnterAnimation = (opts) => {
const { currentBreakpoint, backdropBreakpoint, expandToScroll } = opts;
/**
* If the backdropBreakpoint is undefined, then the backdrop
* should always fade in. If the backdropBreakpoint came before the
* current breakpoint, then the backdrop should be fading in.
*/
const shouldShowBackdrop = backdropBreakpoint === undefined || backdropBreakpoint < currentBreakpoint;
const initialBackdrop = shouldShowBackdrop ? `calc(var(--backdrop-opacity) * ${currentBreakpoint})` : '0';
const backdropAnimation = createAnimation('backdropAnimation').fromTo('opacity', 0, initialBackdrop);
if (shouldShowBackdrop) {
backdropAnimation
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
}
const wrapperAnimation = createAnimation('wrapperAnimation').keyframes([
{ offset: 0, opacity: 1, transform: 'translateY(100%)' },
{ offset: 1, opacity: 1, transform: `translateY(${100 - currentBreakpoint * 100}%)` },
]);
/**
* This allows the content to be scrollable at any breakpoint.
*/
const contentAnimation = !expandToScroll
? createAnimation('contentAnimation').keyframes([
{ offset: 0, opacity: 1, maxHeight: `${(1 - currentBreakpoint) * 100}%` },
{ offset: 1, opacity: 1, maxHeight: `${currentBreakpoint * 100}%` },
])
: undefined;
return { wrapperAnimation, backdropAnimation, contentAnimation };
};
const createSheetLeaveAnimation = (opts) => {
const { currentBreakpoint, backdropBreakpoint } = opts;
/**
* Backdrop does not always fade in from 0 to 1 if backdropBreakpoint
* is defined, so we need to account for that offset by figuring out
* what the current backdrop value should be.
*/
const backdropValue = `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(currentBreakpoint, backdropBreakpoint)})`;
const defaultBackdrop = [
{ offset: 0, opacity: backdropValue },
{ offset: 1, opacity: 0 },
];
const customBackdrop = [
{ offset: 0, opacity: backdropValue },
{ offset: backdropBreakpoint, opacity: 0 },
{ offset: 1, opacity: 0 },
];
const backdropAnimation = createAnimation('backdropAnimation').keyframes(backdropBreakpoint !== 0 ? customBackdrop : defaultBackdrop);
const wrapperAnimation = createAnimation('wrapperAnimation').keyframes([
{ offset: 0, opacity: 1, transform: `translateY(${100 - currentBreakpoint * 100}%)` },
{ offset: 1, opacity: 1, transform: `translateY(100%)` },
]);
return { wrapperAnimation, backdropAnimation };
};
const createEnterAnimation$1 = () => {
const backdropAnimation = createAnimation()
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
const wrapperAnimation = createAnimation().fromTo('transform', 'translateY(100vh)', 'translateY(0vh)');
return { backdropAnimation, wrapperAnimation, contentAnimation: undefined };
};
/**
* iOS Modal Enter Animation for the Card presentation style
*/
const iosEnterAnimation$3 = (baseEl, opts) => {
const { presentingEl, currentBreakpoint, expandToScroll } = opts;
const root = getElementRoot(baseEl);
const { wrapperAnimation, backdropAnimation, contentAnimation } = currentBreakpoint !== undefined ? createSheetEnterAnimation(opts) : createEnterAnimation$1();
backdropAnimation.addElement(root.querySelector('ion-backdrop'));
wrapperAnimation.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow')).beforeStyles({ opacity: 1 });
// The content animation is only added if scrolling is enabled for
// all the breakpoints.
!expandToScroll && (contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.addElement(baseEl.querySelector('.ion-page')));
const baseAnimation = createAnimation('entering-base')
.addElement(baseEl)
.easing('cubic-bezier(0.32,0.72,0,1)')
.duration(500)
.addAnimation([wrapperAnimation]);
if (contentAnimation) {
baseAnimation.addAnimation(contentAnimation);
}
if (presentingEl) {
const isPortrait = window.innerWidth < 768;
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
const presentingElRoot = getElementRoot(presentingEl);
const presentingAnimation = createAnimation().beforeStyles({
transform: 'translateY(0)',
'transform-origin': 'top center',
overflow: 'hidden',
});
const bodyEl = document.body;
if (isPortrait) {
/**
* Fallback for browsers that does not support `max()` (ex: Firefox)
* No need to worry about statusbar padding since engines like Gecko
* are not used as the engine for standalone Cordova/Capacitor apps
*/
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
const modalTransform = hasCardModal ? '-10px' : transformOffset;
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const finalTransform = `translateY(${modalTransform}) scale(${toPresentingScale})`;
presentingAnimation
.afterStyles({
transform: finalTransform,
})
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
.addElement(presentingEl)
.keyframes([
{ offset: 0, filter: 'contrast(1)', transform: 'translateY(0px) scale(1)', borderRadius: '0px' },
{ offset: 1, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' },
]);
baseAnimation.addAnimation(presentingAnimation);
}
else {
baseAnimation.addAnimation(backdropAnimation);
if (!hasCardModal) {
wrapperAnimation.fromTo('opacity', '0', '1');
}
else {
const toPresentingScale = hasCardModal ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
const finalTransform = `translateY(-10px) scale(${toPresentingScale})`;
presentingAnimation
.afterStyles({
transform: finalTransform,
})
.addElement(presentingElRoot.querySelector('.modal-wrapper'))
.keyframes([
{ offset: 0, filter: 'contrast(1)', transform: 'translateY(0) scale(1)' },
{ offset: 1, filter: 'contrast(0.85)', transform: finalTransform },
]);
const shadowAnimation = createAnimation()
.afterStyles({
transform: finalTransform,
})
.addElement(presentingElRoot.querySelector('.modal-shadow'))
.keyframes([
{ offset: 0, opacity: '1', transform: 'translateY(0) scale(1)' },
{ offset: 1, opacity: '0', transform: finalTransform },
]);
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
}
}
}
else {
baseAnimation.addAnimation(backdropAnimation);
}
return baseAnimation;
};
const createLeaveAnimation$1 = () => {
const backdropAnimation = createAnimation().fromTo('opacity', 'var(--backdrop-opacity)', 0);
const wrapperAnimation = createAnimation().fromTo('transform', 'translateY(0vh)', 'translateY(100vh)');
return { backdropAnimation, wrapperAnimation };
};
/**
* iOS Modal Leave Animation
*/
const iosLeaveAnimation$3 = (baseEl, opts, duration = 500) => {
const { presentingEl, currentBreakpoint } = opts;
const root = getElementRoot(baseEl);
const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation$1();
backdropAnimation.addElement(root.querySelector('ion-backdrop'));
wrapperAnimation.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow')).beforeStyles({ opacity: 1 });
const baseAnimation = createAnimation('leaving-base')
.addElement(baseEl)
.easing('cubic-bezier(0.32,0.72,0,1)')
.duration(duration)
.addAnimation(wrapperAnimation);
if (presentingEl) {
const isPortrait = window.innerWidth < 768;
const hasCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
const presentingElRoot = getElementRoot(presentingEl);
const presentingAnimation = createAnimation()
.beforeClearStyles(['transform'])
.afterClearStyles(['transform'])
.onFinish((currentStep) => {
// only reset background color if this is the last card-style modal
if (currentStep !== 1) {
return;
}
presentingEl.style.setProperty('overflow', '');
const numModals = Array.from(bodyEl.querySelectorAll('ion-modal:not(.overlay-hidden)')).filter((m) => m.presentingElement !== undefined).length;
if (numModals <= 1) {
bodyEl.style.setProperty('background-color', '');
}
});
const bodyEl = document.body;
if (isPortrait) {
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
const modalTransform = hasCardModal ? '-10px' : transformOffset;
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const finalTransform = `translateY(${modalTransform}) scale(${toPresentingScale})`;
presentingAnimation.addElement(presentingEl).keyframes([
{ offset: 0, filter: 'contrast(0.85)', transform: finalTransform, borderRadius: '10px 10px 0 0' },
{ offset: 1, filter: 'contrast(1)', transform: 'translateY(0px) scale(1)', borderRadius: '0px' },
]);
baseAnimation.addAnimation(presentingAnimation);
}
else {
baseAnimation.addAnimation(backdropAnimation);
if (!hasCardModal) {
wrapperAnimation.fromTo('opacity', '1', '0');
}
else {
const toPresentingScale = hasCardModal ? SwipeToCloseDefaults.MIN_PRESENTING_SCALE : 1;
const finalTransform = `translateY(-10px) scale(${toPresentingScale})`;
presentingAnimation
.addElement(presentingElRoot.querySelector('.modal-wrapper'))
.afterStyles({
transform: 'translate3d(0, 0, 0)',
})
.keyframes([
{ offset: 0, filter: 'contrast(0.85)', transform: finalTransform },
{ offset: 1, filter: 'contrast(1)', transform: 'translateY(0) scale(1)' },
]);
const shadowAnimation = createAnimation()
.addElement(presentingElRoot.querySelector('.modal-shadow'))
.afterStyles({
transform: 'translateY(0) scale(1)',
})
.keyframes([
{ offset: 0, opacity: '0', transform: finalTransform },
{ offset: 1, opacity: '1', transform: 'translateY(0) scale(1)' },
]);
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
}
}
}
else {
baseAnimation.addAnimation(backdropAnimation);
}
return baseAnimation;
};
/**
* Transition animation from portrait view to landscape view
* This handles the case where a card modal is open in portrait view
* and the user switches to landscape view
*/
const portraitToLandscapeTransition = (baseEl, opts, duration = 300) => {
const { presentingEl } = opts;
if (!presentingEl) {
// No transition needed for non-card modals
return createAnimation('portrait-to-landscape-transition');
}
const presentingElIsCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
const presentingElRoot = getElementRoot(presentingEl);
const bodyEl = document.body;
const baseAnimation = createAnimation('portrait-to-landscape-transition')
.addElement(baseEl)
.easing('cubic-bezier(0.32,0.72,0,1)')
.duration(duration);
const presentingAnimation = createAnimation().beforeStyles({
transform: 'translateY(0)',
'transform-origin': 'top center',
overflow: 'hidden',
});
if (!presentingElIsCardModal) {
// The presenting element is not a card modal, so we do not
// need to care about layering and modal-specific styles.
const root = getElementRoot(baseEl);
const wrapperAnimation = createAnimation()
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
.fromTo('opacity', '1', '1'); // Keep wrapper visible in landscape
const backdropAnimation = createAnimation()
.addElement(root.querySelector('ion-backdrop'))
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
// Animate presentingEl from portrait state back to normal
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const fromTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
presentingAnimation
.addElement(presentingEl)
.afterStyles({
transform: 'translateY(0px) scale(1)',
'border-radius': '0px',
})
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', ''))
.fromTo('transform', fromTransform, 'translateY(0px) scale(1)')
.fromTo('filter', 'contrast(0.85)', 'contrast(1)')
.fromTo('border-radius', '10px 10px 0 0', '0px');
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
}
else {
// The presenting element is a card modal, so we do
// need to care about layering and modal-specific styles.
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
const toTransform = `translateY(0px) scale(1)`;
presentingAnimation
.addElement(presentingEl)
.afterStyles({
transform: toTransform,
})
.fromTo('transform', fromTransform, toTransform)
.fromTo('filter', 'contrast(0.85)', 'contrast(1)');
const shadowAnimation = createAnimation()
.addElement(presentingElRoot.querySelector('.modal-shadow'))
.afterStyles({
transform: toTransform,
opacity: '0',
})
.fromTo('transform', fromTransform, toTransform);
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
}
return baseAnimation;
};
/**
* Transition animation from landscape view to portrait view
* This handles the case where a card modal is open in landscape view
* and the user switches to portrait view
*/
const landscapeToPortraitTransition = (baseEl, opts, duration = 300) => {
const { presentingEl } = opts;
if (!presentingEl) {
// No transition needed for non-card modals
return createAnimation('landscape-to-portrait-transition');
}
const presentingElIsCardModal = presentingEl.tagName === 'ION-MODAL' && presentingEl.presentingElement !== undefined;
const presentingElRoot = getElementRoot(presentingEl);
const bodyEl = document.body;
const baseAnimation = createAnimation('landscape-to-portrait-transition')
.addElement(baseEl)
.easing('cubic-bezier(0.32,0.72,0,1)')
.duration(duration);
const presentingAnimation = createAnimation().beforeStyles({
transform: 'translateY(0)',
'transform-origin': 'top center',
overflow: 'hidden',
});
if (!presentingElIsCardModal) {
// The presenting element is not a card modal, so we do not
// need to care about layering and modal-specific styles.
const root = getElementRoot(baseEl);
const wrapperAnimation = createAnimation()
.addElement(root.querySelectorAll('.modal-wrapper, .modal-shadow'))
.fromTo('opacity', '1', '1'); // Keep wrapper visible
const backdropAnimation = createAnimation()
.addElement(root.querySelector('ion-backdrop'))
.fromTo('opacity', 'var(--backdrop-opacity)', 'var(--backdrop-opacity)'); // Keep backdrop visible
// Animate presentingEl from normal state to portrait state
const transformOffset = !CSS.supports('width', 'max(0px, 1px)') ? '30px' : 'max(30px, var(--ion-safe-area-top))';
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const toTransform = `translateY(${transformOffset}) scale(${toPresentingScale})`;
presentingAnimation
.addElement(presentingEl)
.afterStyles({
transform: toTransform,
})
.beforeAddWrite(() => bodyEl.style.setProperty('background-color', 'black'))
.keyframes([
{ offset: 0, transform: 'translateY(0px) scale(1)', filter: 'contrast(1)', borderRadius: '0px' },
{ offset: 0.2, transform: 'translateY(0px) scale(1)', filter: 'contrast(1)', borderRadius: '10px 10px 0 0' },
{ offset: 1, transform: toTransform, filter: 'contrast(0.85)', borderRadius: '10px 10px 0 0' },
]);
baseAnimation.addAnimation([presentingAnimation, wrapperAnimation, backdropAnimation]);
}
else {
// The presenting element is also a card modal, so we need
// to handle layering and modal-specific styles.
const toPresentingScale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
const fromTransform = `translateY(-10px) scale(${toPresentingScale})`;
const toTransform = `translateY(0) scale(1)`;
presentingAnimation
.addElement(presentingEl)
.afterStyles({
transform: toTransform,
})
.fromTo('transform', fromTransform, toTransform);
const shadowAnimation = createAnimation()
.addElement(presentingElRoot.querySelector('.modal-shadow'))
.afterStyles({
transform: toTransform,
opacity: '0',
})
.fromTo('transform', fromTransform, toTransform);
baseAnimation.addAnimation([presentingAnimation, shadowAnimation]);
}
return baseAnimation;
};
const createEnterAnimation = () => {
const backdropAnimation = createAnimation()
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
const wrapperAnimation = createAnimation().keyframes([
{ offset: 0, opacity: 0.01, transform: 'translateY(40px)' },
{ offset: 1, opacity: 1, transform: `translateY(0px)` },
]);
return { backdropAnimation, wrapperAnimation, contentAnimation: undefined };
};
/**
* Md Modal Enter Animation
*/
const mdEnterAnimation$2 = (baseEl, opts) => {
const { currentBreakpoint, expandToScroll } = opts;
const root = getElementRoot(baseEl);
const { wrapperAnimation, backdropAnimation, contentAnimation } = currentBreakpoint !== undefined ? createSheetEnterAnimation(opts) : createEnterAnimation();
backdropAnimation.addElement(root.querySelector('ion-backdrop'));
wrapperAnimation.addElement(root.querySelector('.modal-wrapper'));
// The content animation is only added if scrolling is enabled for
// all the breakpoints.
!expandToScroll && (contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.addElement(baseEl.querySelector('.ion-page')));
const baseAnimation = createAnimation()
.addElement(baseEl)
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(280)
.addAnimation([backdropAnimation, wrapperAnimation]);
if (contentAnimation) {
baseAnimation.addAnimation(contentAnimation);
}
return baseAnimation;
};
const createLeaveAnimation = () => {
const backdropAnimation = createAnimation().fromTo('opacity', 'var(--backdrop-opacity)', 0);
const wrapperAnimation = createAnimation().keyframes([
{ offset: 0, opacity: 0.99, transform: `translateY(0px)` },
{ offset: 1, opacity: 0, transform: 'translateY(40px)' },
]);
return { backdropAnimation, wrapperAnimation };
};
/**
* Md Modal Leave Animation
*/
const mdLeaveAnimation$2 = (baseEl, opts) => {
const { currentBreakpoint } = opts;
const root = getElementRoot(baseEl);
const { wrapperAnimation, backdropAnimation } = currentBreakpoint !== undefined ? createSheetLeaveAnimation(opts) : createLeaveAnimation();
backdropAnimation.addElement(root.querySelector('ion-backdrop'));
wrapperAnimation.addElement(root.querySelector('.modal-wrapper'));
const baseAnimation = createAnimation()
.easing('cubic-bezier(0.47,0,0.745,0.715)')
.duration(200)
.addAnimation([backdropAnimation, wrapperAnimation]);
return baseAnimation;
};
const createSheetGesture = (baseEl, backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, animation, breakpoints = [], expandToScroll, getCurrentBreakpoint, onDismiss, onBreakpointChange) => {
// Defaults for the sheet swipe animation
const defaultBackdrop = [
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
{ offset: 1, opacity: 0.01 },
];
const customBackdrop = [
{ offset: 0, opacity: 'var(--backdrop-opacity)' },
{ offset: 1 - backdropBreakpoint, opacity: 0 },
{ offset: 1, opacity: 0 },
];
const SheetDefaults = {
WRAPPER_KEYFRAMES: [
{ offset: 0, transform: 'translateY(0%)' },
{ offset: 1, transform: 'translateY(100%)' },
],
BACKDROP_KEYFRAMES: backdropBreakpoint !== 0 ? customBackdrop : defaultBackdrop,
CONTENT_KEYFRAMES: [
{ offset: 0, maxHeight: '100%' },
{ offset: 1, maxHeight: '0%' },
],
};
const contentEl = baseEl.querySelector('ion-content');
const height = wrapperEl.clientHeight;
let currentBreakpoint = initialBreakpoint;
let offset = 0;
let canDismissBlocksGesture = false;
let cachedScrollEl = null;
let cachedFooterEls = null;
let cachedFooterYPosition = null;
let currentFooterState = null;
const canDismissMaxStep = 0.95;
const maxBreakpoint = breakpoints[breakpoints.length - 1];
const minBreakpoint = breakpoints[0];
const wrapperAnimation = animation.childAnimations.find((ani) => ani.id === 'wrapperAnimation');
const backdropAnimation = animation.childAnimations.find((ani) => ani.id === 'backdropAnimation');
const contentAnimation = animation.childAnimations.find((ani) => ani.id === 'contentAnimation');
const enableBackdrop = () => {
// Respect explicit opt-out of focus trapping/backdrop interactions
// If focusTrap is false or showBackdrop is false, do not enable the backdrop or re-enable focus trap
const el = baseEl;
if (el.focusTrap === false || el.showBackdrop === false) {
return;
}
baseEl.style.setProperty('pointer-events', 'auto');
backdropEl.style.setProperty('pointer-events', 'auto');
/**
* When the backdrop is enabled, elements such
* as inputs should not be focusable outside
* the sheet.
*/
baseEl.classList.remove(FOCUS_TRAP_DISABLE_CLASS);
};
const disableBackdrop = () => {
baseEl.style.setProperty('pointer-events', 'none');
backdropEl.style.setProperty('pointer-events', 'none');
/**
* When the backdrop is enabled, elements such
* as inputs should not be focusable outside
* the sheet.
* Adding this class disables focus trapping
* for the sheet temporarily.
*/
baseEl.classList.add(FOCUS_TRAP_DISABLE_CLASS);
};
/**
* Toggles the footer to an absolute position while moving to prevent
* it from shaking while the sheet is being dragged.
* @param newPosition Whether the footer is in a moving or stationary position.
*/
const swapFooterPosition = (newPosition) => {
if (!cachedFooterEls) {
cachedFooterEls = Array.from(baseEl.querySelectorAll('ion-footer'));
if (!cachedFooterEls.length) {
return;
}
}
const page = baseEl.querySelector('.ion-page');
currentFooterState = newPosition;
if (newPosition === 'stationary') {
cachedFooterEls.forEach((cachedFooterEl) => {
// Reset positioning styles to allow normal document flow
cachedFooterEl.classList.remove('modal-footer-moving');
cachedFooterEl.style.removeProperty('position');
cachedFooterEl.style.removeProperty('width');
cachedFooterEl.style.removeProperty('height');
cachedFooterEl.style.removeProperty('top');
cachedFooterEl.style.removeProperty('left');
page === null || page === void 0 ? void 0 : page.style.removeProperty('padding-bottom');
// Move to page
page === null || page === void 0 ? void 0 : page.appendChild(cachedFooterEl);
});
}
else {
let footerHeights = 0;
cachedFooterEls.forEach((cachedFooterEl, index) => {
// Get both the footer and document body positions
const cachedFooterElRect = cachedFooterEl.getBoundingClientRect();
const bodyRect = document.body.getBoundingClientRect();
// Calculate the total height of all footers
// so we can add padding to the page element
footerHeights += cachedFooterEl.clientHeight;
// Calculate absolute position relative to body
// We need to subtract the body's offsetTop to get true position within document.body
const absoluteTop = cachedFooterElRect.top - bodyRect.top;
const absoluteLeft = cachedFooterElRect.left - bodyRect.left;
// Capture the footer's current dimensions and store them in CSS variables for
// later use when applying absolute positioning.
cachedFooterEl.style.setProperty('--pinned-width', `${cachedFooterEl.clientWidth}px`);
cachedFooterEl.style.setProperty('--pinned-height', `${cachedFooterEl.clientHeight}px`);
cachedFooterEl.style.setProperty('--pinned-top', `${absoluteTop}px`);
cachedFooterEl.style.setProperty('--pinned-left', `${absoluteLeft}px`);
// Only cache the first footer's Y position
// This is used to determine if the sheet has been moved below the footer
// and needs to be swapped back to stationary so it collapses correctly.
if (index === 0) {
cachedFooterYPosition = absoluteTop;
// If there's a header, we need to combine the header height with the footer position
// because the header moves with the drag handle, so when it starts overlapping the footer,
// we need to account for that.
const header = baseEl.querySelector('ion-header');
if (header) {
cachedFooterYPosition -= header.clientHeight;
}
}
});
// Apply the pinning of styles after we've calculated everything
// so that we don't cause layouts to shift while calculating the footer positions.
// Otherwise, with multiple footers we'll end up capturing the wrong positions.
cachedFooterEls.forEach((cachedFooterEl) => {
// Add padding to the parent element to prevent content from being hidden
// when the footer is positioned absolutely. This has to be done before we
// make the footer absolutely positioned or we may accidentally cause the
// sheet to scroll.
page === null || page === void 0 ? void 0 : page.style.setProperty('padding-bottom', `${footerHeights}px`);
// Apply positioning styles to keep footer at bottom
cachedFooterEl.classList.add('modal-footer-moving');
// Apply our preserved styles to pin the footer
cachedFooterEl.style.setProperty('position', 'absolute');
cachedFooterEl.style.setProperty('width', 'var(--pinned-width)');
cachedFooterEl.style.setProperty('height', 'var(--pinned-height)');
cachedFooterEl.style.setProperty('top', 'var(--pinned-top)');
cachedFooterEl.style.setProperty('left', 'var(--pinned-left)');
// Move the element to the body when everything else is done
document.body.appendChild(cachedFooterEl);
});
}
};
/**
* After the entering animation completes,
* we need to set the animation to go from
* offset 0 to offset 1 so that users can
* swipe in any direction. We then set the
* animation offset to the current breakpoint
* so there is no flickering.
*/
if (wrapperAnimation && backdropAnimation) {
wrapperAnimation.keyframes([...SheetDefaults.WRAPPER_KEYFRAMES]);
backdropAnimation.keyframes([...SheetDefaults.BACKDROP_KEYFRAMES]);
contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.keyframes([...SheetDefaults.CONTENT_KEYFRAMES]);
animation.progressStart(true, 1 - currentBreakpoint);
/**
* If backdrop is not enabled, then content
* behind modal should be clickable. To do this, we need
* to remove pointer-events from ion-modal as a whole.
* ion-backdrop and .modal-wrapper always have pointer-events: auto
* applied, so the modal content can still be interacted with.
*/
const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint &&
baseEl.focusTrap !== false &&
baseEl.showBackdrop !== false;
if (shouldEnableBackdrop) {
enableBackdrop();
}
else {
disableBackdrop();
}
}
if (contentEl && currentBreakpoint !== maxBreakpoint && expandToScroll) {
contentEl.scrollY = false;
}
const canStart = (detail) => {
/**
* If we are swiping on the content, swiping should only be possible if the content
* is scrolled all the way to the top so that we do not interfere with scrolling.
*
* We cannot assume that the `ion-content` target will remain consistent between swipes.
* For example, when using ion-nav within a modal it is possible to swipe, push a view,
* and then swipe again. The target content will not be the same between swipes.
*/
const contentEl = findClosestIonContent(detail.event.target);
currentBreakpoint = getCurrentBreakpoint();
/**
* If `expandToScroll` is disabled, we should not allow the swipe gesture
* to start if the content is not scrolled to the top.
*/
if (!expandToScroll && contentEl) {
const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
return scrollEl.scrollTop === 0;
}
if (currentBreakpoint === 1 && contentEl) {
/**
* The modal should never swipe to close on the content with a refresher.
* Note 1: We cannot solve this by making this gesture have a higher priority than
* the refresher gesture as the iOS native refresh gesture uses a scroll listener in
* addition to a gesture.
*
* Note 2: Do not use getScrollElement here because we need this to be a synchronous
* operation, and getScrollElement is asynchronous.
*/
const scrollEl = isIonContent(contentEl) ? getElementRoot(contentEl).querySelector('.inner-scroll') : contentEl;
const hasRefresherInContent = !!contentEl.querySelector('ion-refresher');
return !hasRefresherInContent && scrollEl.scrollTop === 0;
}
return true;
};
const onStart = (detail) => {
/**
* If canDismiss is anything other than `true`
* then users should be able to swipe down
* until a threshold is hit. At that point,
* the card modal should not proceed any further.
*
* canDismiss is never fired via gesture if there is
* no 0 breakpoint. However, it can be fired if the user
* presses Esc or the hardware back button.
* TODO (FW-937)
* Remove undefined check
*/
canDismissBlocksGesture = baseEl.canDismiss !== undefined && baseEl.canDismiss !== true && minBreakpoint === 0;
/**
* Cache the scroll element reference when the gesture starts,
* this allows us to avoid querying the DOM for the target in onMove,
* which would impact performance significantly.
*/
if (!expandToScroll) {
const targetEl = findClosestIonContent(detail.event.target);
cachedScrollEl =
targetEl && isIonContent(targetEl) ? getElementRoot(targetEl).querySelector('.inner-scroll') : targetEl;
}
/**
* If expandToScroll is disabled, we need to swap
* the footer position to moving so that it doesn't shake
* while the sheet is being dragged.
*/
if (!expandToScroll) {
swapFooterPosition('moving');
}
/**
* If we are pulling down, then it is possible we are pulling on the content.
* We do not want scrolling to happen at the same time as the gesture.
*/
if (detail.deltaY > 0 && contentEl) {
contentEl.scrollY = false;
}
raf(() => {
/**
* Dismisses the open keyboard when the sheet drag gesture is started.
* Sets the focus onto the modal element.
*/
baseEl.focus();
});
animation.progressStart(true, 1 - currentBreakpoint);
};
const onMove = (detail) => {
/**
* If `expandToScroll` is disabled, we need to see if we're currently below
* the footer element and the footer is in a stationary position. If so,
* we need to make the stationary the original position so that the footer
* collapses with the sheet.
*/
if (!expandToScroll && cachedFooterYPosition !== null && currentFooterState !== null) {
// Check if we need to swap the footer position
if (detail.currentY >= cachedFooterYPosition && currentFooterState === 'moving') {
swapFooterPosition('stationary');
}
else if (detail.currentY < cachedFooterYPosition && currentFooterState === 'stationary') {
swapFooterPosition('moving');
}
}
/**
* If `expandToScroll` is disabled, and an upwards swipe gesture is done within
* the scrollable content, we should not allow the swipe gesture to continue.
*/
if (!expandToScroll && detail.deltaY <= 0 && cachedScrollEl) {
return;
}
/**
* If we are pulling down, then it is possible we are pulling on the content.
* We do not want scrolling to happen at the same time as the gesture.
* This accounts for when the user scrolls down, scrolls all the way up, and then
* pulls down again such that the modal should start to move.
*/
if (detail.deltaY > 0 && contentEl) {
contentEl.scrollY = false;
}
/**
* Given the change in gesture position on the Y axis,
* compute where the offset of the animation should be
* relative to where the user dragged.
*/
const initialStep = 1 - currentBreakpoint;
const secondToLastBreakpoint = breakpoints.length > 1 ? 1 - breakpoints[1] : undefined;
const step = initialStep + detail.deltaY / height;
const isAttemptingDismissWithCanDismiss = secondToLastBreakpoint !== undefined && step >= secondToLastBreakpoint && canDismissBlocksGesture;
/**
* If we are blocking the gesture from dismissing,
* set the max step value so that the sheet cannot be
* completely hidden.
*/
const maxStep = isAttemptingDismissWithCanDismiss ? canDismissMaxStep : 0.9999;
/**
* If we are blocking the gesture from
* dismissing, calculate the spring modifier value
* this will be added to the starting breakpoint
* value to give the gesture a spring-like feeling.
* Note that when isAttemptingDismissWithCanDismiss is true,
* the modifier is always added to the breakpoint that
* appears right after the 0 breakpoint.
*
* Note that this modifier is essentially the progression
* between secondToLastBreakpoint and maxStep which is
* why we subtract secondToLastBreakpoint. This lets us get
* the result as a value from 0 to 1.
*/
const processedStep = isAttemptingDismissWithCanDismiss && secondToLastBreakpoint !== undefined
? secondToLastBreakpoint +
calculateSpringStep((step - secondToLastBreakpoint) / (maxStep - secondToLastBreakpoint))
: step;
offset = clamp(0.0001, processedStep, maxStep);
animation.progressStep(offset);
};
const onEnd = (detail) => {
/**
* If expandToScroll is disabled, we should not allow the moveSheetToBreakpoint
* function to be called if the user is trying to swipe content upwards and the content
* is not scrolled to the top.
*/
if (!expandToScroll && detail.deltaY <= 0 && cachedScrollEl && cachedScrollEl.scrollTop > 0) {
/**
* If expand to scroll is disabled, we need to make sure we swap the footer position
* back to stationary so that it will collapse correctly if the modal is dismissed without
* dragging (e.g. through a dismiss button).
* This can cause issues if the user has a modal with content that can be dragged, as we'll
* swap to moving on drag and if we don't swap back here then the footer will get stuck.
*/
swapFooterPosition('stationary');
return;
}
/**
* When the gesture releases, we need to determine
* the closest breakpoint to snap to.
*/
const velocity = detail.velocityY;
const threshold = (detail.deltaY + velocity * 350) / height;
const diff = currentBreakpoint - threshold;
const closest = breakpoints.reduce((a, b) => {
return Math.abs(b - diff) < Math.abs(a - diff) ? b : a;
});
moveSheetToBreakpoint({
breakpoint: closest,
breakpointOffset: offset,
canDismiss: canDismissBlocksGesture,
/**
* The swipe is user-driven, so we should
* always animate when the gesture ends.
*/
animated: true,
});
};
const moveSheetToBreakpoint = (options) => {
const { breakpoint, canDismiss, breakpointOffset, animated } = options;
/**
* canDismiss should only prevent snapping
* when users are trying to dismiss. If canDismiss
* is present but the user is trying to swipe upwards,
* we should allow that to happen,
*/
const shouldPreventDismiss = canDismiss && breakpoint === 0;
const snapToBreakpoint = shouldPreventDismiss ? currentBreakpoint : breakpoint;
const shouldRemainOpen = snapToBreakpoint !== 0;
currentBreakpoint = 0;
/**
* Update the animation so that it plays from
* the last offset to the closest snap point.
*/
if (wrapperAnimation && backdropAnimation) {
wrapperAnimation.keyframes([
{ offset: 0, transform: `translateY(${breakpointOffset * 100}%)` },
{ offset: 1, transform: `translateY(${(1 - snapToBreakpoint) * 100}%)` },
]);
backdropAnimation.keyframes([
{
offset: 0,
opacity: `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(1 - breakpointOffset, backdropBreakpoint)})`,
},
{
offset: 1,
opacity: `calc(var(--backdrop-opacity) * ${getBackdropValueForSheet(snapToBreakpoint, backdropBreakpoint)})`,
},
]);
if (contentAnimation) {
/**
* The modal content should scroll at any breakpoint when expandToScroll
* is disabled. In order to do this, the content needs to be completely
* viewable so scrolling can access everything. Otherwise, the default
* behavior would show the content off the screen and only allow
* scrolling when the sheet is fully expanded.
*/
contentAnimation.keyframes([
{ offset: 0, maxHeight: `${(1 - breakpointOffset) * 100}%` },
{ offset: 1, maxHeight: `${snapToBreakpoint * 100}%` },
]);
}
animation.progressStep(0);
}
/**
* Gesture should remain disabled until the
* snapping animation completes.
*/
gesture.enable(false);
if (shouldPreventDismiss) {
handleCanDismiss(baseEl, animation);
}
else if (!shouldRemainOpen) {
onDismiss();
}
/**
* Enables scrolling immediately if the sheet is about to fully expand
* or if it allows scrolling at any breakpoint. Without this, there would
* be a ~500ms delay while the modal animation completes, causing a
* noticeable lag. Native iOS allows scrolling as soon as the gesture is
* released, so we align with that behavior.
*/
if (contentEl && (snapToBreakpoint === breakpoints[breakpoints.length - 1] || !expandToScroll)) {
contentEl.scrollY = true;
}
/**
* If expandToScroll is disabled and we're animating
* to close the sheet, we need to swap
* the footer position to stationary so that it
* will collapse correctly. We cannot just always swap
* here or it'll be jittery while animating movement.
*/
if (!expandToScroll && snapToBreakpoint === 0) {
swapFooterPosition('stationary');
}
return new Promise((resolve) => {
animation
.onFinish(() => {
if (shouldRemainOpen) {
/**
* If expandToScroll is disabled, we need to swap
* the footer position to stationary so that it
* will act as it would by default.
*/
if (!expandToScroll) {
swapFooterPosition('stationary');
}
/**
* Once the snapping animation completes,
* we need to reset the animation to go
* from 0 to 1 so users can swipe in any direction.
* We then set the animation offset to the current
* breakpoint so that it starts at the snapped position.
*/
if (wrapperAnimation && backdropAnimation) {
raf(() => {
wrapperAnimation.keyframes([...SheetDefaults.WRAPPER_KEYFRAMES]);
backdropAnimation.keyframes([...SheetDefaults.BACKDROP_KEYFRAMES]);
contentAnimation === null || contentAnimation === void 0 ? void 0 : contentAnimation.keyframes([...SheetDefaults.CONTENT_KEYFRAMES]);
animation.progressStart(true, 1 - snapToBreakpoint);
currentBreakpoint = snapToBreakpoint;
onBreakpointChange(currentBreakpoint);
/**
* Backdrop should become enabled
* after the backdropBreakpoint value
*/
const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint &&
baseEl.focusTrap !== false &&
baseEl.showBackdrop !== false;
if (shouldEnableBackdrop) {
enableBackdrop();
}
else {
disableBackdrop();
}
gesture.enable(true);
resolve();
});
}
else {
gesture.enable(true);
resolve();
}
}
else {
resolve();
}
/**
* This must be a one time callback
* otherwise a new callback will
* be added every time onEnd runs.
*/
}, { oneTimeCallback: true })
.progressEnd(1, 0, animated ? 500 : 0);
});
};
const gesture = createGesture({
el: wrapperEl,
gestureName: 'modalSheet',
gesturePriority: 40,
direction: 'y',
threshold: 10,
canStart,
onStart,
onMove,
onEnd,
});
return {
gesture,
moveSheetToBreakpoint,
};
};
const modalIosCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.4)}:host(.modal-card),:host(.modal-sheet){--border-radius:10px}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:10px}}.modal-wrapper{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0)}@media screen and (max-width: 767px){@supports (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - max(30px, var(--ion-safe-area-top)) - 10px)}}@supports not (width: max(0px, 1px)){:host(.modal-card){--height:calc(100% - 40px)}}:host(.modal-card) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}:host(.modal-card){--backdrop-opacity:0;--width:100%;-ms-flex-align:end;align-items:flex-end}:host(.modal-card) .modal-shadow{display:none}:host(.modal-card) ion-backdrop{pointer-events:none}}@media screen and (min-width: 768px){:host(.modal-card){--width:calc(100% - 120px);--height:calc(100% - (120px + var(--ion-safe-area-top) + var(--ion-safe-area-bottom)));--max-width:720px;--max-height:1000px;--backdrop-opacity:0;--box-shadow:0px 0px 30px 10px rgba(0, 0, 0, 0.1);-webkit-transition:all 0.5s ease-in-out;transition:all 0.5s ease-in-out}:host(.modal-card) .modal-wrapper{-webkit-box-shadow:none;box-shadow:none}:host(.modal-card) .modal-shadow{-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow)}}:host(.modal-sheet) .modal-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0;border-end-start-radius:0}";
const modalMdCss = ":host{--width:100%;--min-width:auto;--max-width:auto;--height:100%;--min-height:auto;--max-height:auto;--overflow:hidden;--border-radius:0;--border-width:0;--border-style:none;--border-color:transparent;--background:var(--ion-background-color, #fff);--box-shadow:none;--backdrop-opacity:0;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);contain:strict}.modal-wrapper,ion-backdrop{pointer-events:auto}:host(.overlay-hidden){display:none}.modal-wrapper,.modal-shadow{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:var(--overflow);z-index:10}.modal-shadow{position:absolute;background:transparent}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--width:600px;--height:500px;--ion-safe-area-top:0px;--ion-safe-area-bottom:0px;--ion-safe-area-right:0px;--ion-safe-area-left:0px}}@media only screen and (min-width: 768px) and (min-height: 768px){:host{--width:600px;--height:600px}}.modal-handle{left:0px;right:0px;top:5px;border-radius:8px;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;position:absolute;width:36px;height:5px;-webkit-transform:translateZ(0);transform:translateZ(0);border:0;background:var(--ion-color-step-350, var(--ion-background-color-step-350, #c0c0be));cursor:pointer;z-index:11}.modal-handle::before{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:4px;padding-bottom:4px;position:absolute;width:36px;height:5px;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);content:\"\"}:host(.modal-sheet){--height:calc(100% - (var(--ion-safe-area-top) + 10px))}:host(.modal-sheet) .modal-wrapper,:host(.modal-sheet) .modal-shadow{position:absolute;bottom:0}:host(.modal-sheet.modal-no-expand-scroll) ion-footer{position:absolute;bottom:0;width:var(--width)}:host{--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}@media only screen and (min-width: 768px) and (min-height: 600px){:host{--border-radius:2px;--box-shadow:0 28px 48px rgba(0, 0, 0, 0.4)}}.modal-wrapper{-webkit-transform:translate3d(0, 40px, 0);transform:translate3d(0, 40px, 0);opacity:0.01}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed inside of the `.modal-content` element.
*
* @part backdrop - The `ion-backdrop` element.
* @part content - The wrapper element for the default slot.
* @part handle - The handle that is displayed at the top of the sheet modal when `handle="true"`.
*/
class Modal {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionModalDidPresent", 7);
this.willPresent = createEvent(this, "ionModalWillPresent", 7);
this.willDismiss = createEvent(this, "ionModalWillDismiss", 7);
this.didDismiss = createEvent(this, "ionModalDidDismiss", 7);
this.ionBreakpointDidChange = createEvent(this, "ionBreakpointDidChange", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.ionMount = createEvent(this, "ionMount", 7);
this.lockController = createLockController();
this.triggerController = createTriggerController();
this.coreDelegate = CoreDelegate();
this.isSheetModal = false;
this.inheritedAttributes = {};
this.inline = false;
// Whether or not modal is being dismissed via gesture
this.gestureAnimationDismissing = false;
this.presented = false;
/** @internal */
this.hasController = false;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = true;
/**
* Controls whether scrolling or dragging within the sheet modal expands
* it to a larger breakpoint. This only takes effect when `breakpoints`
* and `initialBreakpoint` are set.
*
* If `true`, scrolling or dragging anywhere in the modal will first expand
* it to the next breakpoint. Once fully expanded, scrolling will affect the
* content.
* If `false`, scrolling will always affect the content. The modal will
* only expand when dragging the header or handle. The modal will close when
* dragging the header or handle. It can also be closed when dragging the
* content, but only if the content is scrolled to the top.
*/
this.expandToScroll = true;
/**
* A decimal value between 0 and 1 that indicates the
* point after which the backdrop will begin to fade in
* when using a sheet modal. Prior to this point, the
* backdrop will be hidden and the content underneath
* the sheet can be interacted with. This value is exclusive
* meaning the backdrop will become active after the value
* specified.
*/
this.backdropBreakpoint = 0;
/**
* The interaction behavior for the sheet modal when the handle is pressed.
*
* Defaults to `"none"`, which means the modal will not change size or position when the handle is pressed.
* Set to `"cycle"` to let the modal cycle between available breakpoints when pressed.
*
* Handle behavior is unavailable when the `handle` property is set to `false` or
* when the `breakpoints` property is not set (using a fullscreen or card modal).
*/
this.handleBehavior = 'none';
/**
* If `true`, the modal will be dismissed when the backdrop is clicked.
*/
this.backdropDismiss = true;
/**
* If `true`, a backdrop will be displayed behind the modal.
* This property controls whether or not the backdrop
* darkens the screen when the modal is presented.
* It does not control whether or not the backdrop
* is active or present in the DOM.
*/
this.showBackdrop = true;
/**
* If `true`, the modal will animate.
*/
this.animated = true;
/**
* If `true`, the modal will open. If `false`, the modal will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the modalController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the modal dismisses. You will need to do that in your code.
*/
this.isOpen = false;
/**
* If `true`, the component passed into `ion-modal` will
* automatically be mounted when the modal is created. The
* component will remain mounted even when the modal is dismissed.
* However, the component will be destroyed when the modal is
* destroyed. This property is not reactive and should only be
* used when initially creating a modal.
*
* Note: This feature only applies to inline modals in JavaScript
* frameworks such as Angular, React, and Vue.
*/
this.keepContentsMounted = false;
/**
* If `true`, focus will not be allowed to move outside of this overlay.
* If `false`, focus will be allowed to move outside of the overlay.
*
* In most scenarios this property should remain set to `true`. Setting
* this property to `false` can cause severe accessibility issues as users
* relying on assistive technologies may be able to move focus into
* a confusing state. We recommend only setting this to `false` when
* absolutely necessary.
*
* Developers may want to consider disabling focus trapping if this
* overlay presents a non-Ionic overlay from a 3rd party library.
* Developers would disable focus trapping on the Ionic overlay
* when presenting the 3rd party overlay and then re-enable
* focus trapping when dismissing the 3rd party overlay and moving
* focus back to the Ionic overlay.
*/
this.focusTrap = true;
/**
* Determines whether or not a modal can dismiss
* when calling the `dismiss` method.
*
* If the value is `true` or the value's function returns `true`, the modal will close when trying to dismiss.
* If the value is `false` or the value's function returns `false`, the modal will not close when trying to dismiss.
*
* See https://ionicframework.com/docs/troubleshooting/runtime#accessing-this
* if you need to access `this` from within the callback.
*/
this.canDismiss = true;
this.onHandleClick = () => {
const { sheetTransition, handleBehavior } = this;
if (handleBehavior !== 'cycle' || sheetTransition !== undefined) {
/**
* The sheet modal should not advance to the next breakpoint
* if the handle behavior is not `cycle` or if the handle
* is clicked while the sheet is moving to a breakpoint.
*/
return;
}
this.moveToNextBreakpoint();
};
this.onBackdropTap = () => {
const { sheetTransition } = this;
if (sheetTransition !== undefined) {
/**
* When the handle is double clicked at the largest breakpoint,
* it will start to move to the first breakpoint. While transitioning,
* the backdrop will often receive the second click. We prevent the
* backdrop from dismissing the modal while moving between breakpoints.
*/
return;
}
this.dismiss(undefined, BACKDROP);
};
this.onLifecycle = (modalEvent) => {
const el = this.usersElement;
const name = LIFECYCLE_MAP$1[modalEvent.type];
if (el && name) {
const ev = new CustomEvent(name, {
bubbles: false,
cancelable: false,
detail: modalEvent.detail,
});
el.dispatchEvent(ev);
}
};
/**
* When the modal receives focus directly, pass focus to the handle
* if it exists and is focusable, otherwise let the focus trap handle it.
*/
this.onModalFocus = (ev) => {
const { dragHandleEl, el } = this;
// Only handle focus if the modal itself was focused (not a child element)
if (ev.target === el && dragHandleEl && dragHandleEl.tabIndex !== -1) {
dragHandleEl.focus();
}
};
/**
* When the slot changes, we need to find all the modals in the slot
* and set the data-parent-ion-modal attribute on them so we can find them
* and dismiss them when we get dismissed.
* We need to do it this way because when a modal is opened, it's moved to
* the end of the body and is no longer an actual child of the modal.
*/
this.onSlotChange = ({ target }) => {
const slot = target;
slot.assignedElements().forEach((el) => {
el.querySelectorAll('ion-modal').forEach((childModal) => {
// We don't need to write to the DOM if the modal is already tagged
// If this is a deeply nested modal, this effect should cascade so we don't
// need to worry about another modal claiming the same child.
if (childModal.getAttribute('data-parent-ion-modal') === null) {
childModal.setAttribute('data-parent-ion-modal', this.el.id);
}
});
});
};
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
triggerChanged() {
const { trigger, el, triggerController } = this;
if (trigger) {
triggerController.addClickListener(el, trigger);
}
}
onWindowResize() {
// Only handle resize for iOS card modals when no custom animations are provided
if (getIonMode$1(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
return;
}
clearTimeout(this.resizeTimeout);
this.resizeTimeout = setTimeout(() => {
this.handleViewTransition();
}, 50); // Debounce to avoid excessive calls during active resizing
}
breakpointsChanged(breakpoints) {
if (breakpoints !== undefined) {
this.sortedBreakpoints = breakpoints.sort((a, b) => a - b);
}
}
connectedCallback() {
const { el } = this;
prepareOverlay(el);
this.triggerChanged();
}
disconnectedCallback() {
this.triggerController.removeClickListener();
this.cleanupViewTransitionListener();
this.cleanupParentRemovalObserver();
}
componentWillLoad() {
var _a;
const { breakpoints, initialBreakpoint, el, htmlAttributes } = this;
const isSheetModal = (this.isSheetModal = breakpoints !== undefined && initialBreakpoint !== undefined);
const attributesToInherit = ['aria-label', 'role'];
this.inheritedAttributes = inheritAttributes$1(el, attributesToInherit);
// Cache original parent before modal gets moved to body during presentation
if (el.parentNode) {
this.cachedOriginalParent = el.parentNode;
}
/**
* When using a controller modal you can set attributes
* using the htmlAttributes property. Since the above attributes
* need to be inherited inside of the modal, we need to look
* and see if these attributes are being set via htmlAttributes.
*
* We could alternatively move this to componentDidLoad to simplify the work
* here, but we'd then need to make inheritedAttributes a State variable,
* thus causing another render to always happen after the first render.
*/
if (htmlAttributes !== undefined) {
attributesToInherit.forEach((attribute) => {
const attributeValue = htmlAttributes[attribute];
if (attributeValue) {
/**
* If an attribute we need to inherit was
* set using htmlAttributes then add it to
* inheritedAttributes and remove it from htmlAttributes.
* This ensures the attribute is inherited and not
* set on the host.
*
* In this case, if an inherited attribute is set
* on the host element and using htmlAttributes then
* htmlAttributes wins, but that's not a pattern that we recommend.
* The only time you'd need htmlAttributes is when using modalController.
*/
this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { [attribute]: htmlAttributes[attribute] });
delete htmlAttributes[attribute];
}
});
}
if (isSheetModal) {
this.currentBreakpoint = this.initialBreakpoint;
}
if (breakpoints !== undefined && initialBreakpoint !== undefined && !breakpoints.includes(initialBreakpoint)) {
printIonWarning('[ion-modal] - Your breakpoints array must include the initialBreakpoint value.');
}
if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
setOverlayId(this.el);
}
}
componentDidLoad() {
/**
* If modal was rendered with isOpen="true"
* then we should open modal immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
this.breakpointsChanged(this.breakpoints);
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.triggerChanged();
}
/**
* Determines whether or not an overlay
* is being used inline or via a controller/JS
* and returns the correct delegate.
* By default, subsequent calls to getDelegate
* will use a cached version of the delegate.
* This is useful for calling dismiss after
* present so that the correct delegate is given.
*/
getDelegate(force = false) {
if (this.workingDelegate && !force) {
return {
delegate: this.workingDelegate,
inline: this.inline,
};
}
/**
* If using overlay inline
* we potentially need to use the coreDelegate
* so that this works in vanilla JS apps.
* If a developer has presented this component
* via a controller, then we can assume
* the component is already in the
* correct place.
*/
const parentEl = this.el.parentNode;
const inline = (this.inline = parentEl !== null && !this.hasController);
const delegate = (this.workingDelegate = inline ? this.delegate || this.coreDelegate : this.delegate);
return { inline, delegate };
}
/**
* Determines whether or not the
* modal is allowed to dismiss based
* on the state of the canDismiss prop.
*/
async checkCanDismiss(data, role) {
const { canDismiss } = this;
if (typeof canDismiss === 'function') {
return canDismiss(data, role);
}
return canDismiss;
}
/**
* Present the modal overlay after it has been created.
*/
async present() {
const unlock = await this.lockController.lock();
if (this.presented) {
unlock();
return;
}
const { presentingElement, el } = this;
/**
* If the modal is presented multiple times (inline modals), we
* need to reset the current breakpoint to the initial breakpoint.
*/
this.currentBreakpoint = this.initialBreakpoint;
const { inline, delegate } = this.getDelegate(true);
/**
* Emit ionMount so JS Frameworks have an opportunity
* to add the child component to the DOM. The child
* component will be assigned to this.usersElement below.
*/
this.ionMount.emit();
this.usersElement = await attachComponent(delegate, el, this.component, ['ion-page'], this.componentProps, inline);
/**
* When using the lazy loaded build of Stencil, we need to wait
* for every Stencil component instance to be ready before presenting
* otherwise there can be a flash of unstyled content. With the
* custom elements bundle we need to wait for the JS framework
* mount the inner contents of the overlay otherwise WebKit may
* get the transition incorrect.
*/
if (hasLazyBuild(el)) {
await deepReady(this.usersElement);
/**
* If keepContentsMounted="true" then the
* JS Framework has already mounted the inner
* contents so there is no need to wait.
* Otherwise, we need to wait for the JS
* Framework to mount the inner contents
* of this component.
*/
}
else if (!this.keepContentsMounted) {
await waitForMount();
}
writeTask(() => this.el.classList.add('show-modal'));
const hasCardModal = presentingElement !== undefined;
/**
* We need to change the status bar at the
* start of the animation so that it completes
* by the time the card animation is done.
*/
if (hasCardModal && getIonMode$1(this) === 'ios') {
// Cache the original status bar color before the modal is presented
this.statusBarStyle = await StatusBar.getStyle();
setCardStatusBarDark();
}
await present(this, 'modalEnter', iosEnterAnimation$3, mdEnterAnimation$2, {
presentingEl: presentingElement,
currentBreakpoint: this.initialBreakpoint,
backdropBreakpoint: this.backdropBreakpoint,
expandToScroll: this.expandToScroll,
});
/* tslint:disable-next-line */
if (typeof window !== 'undefined') {
/**
* This needs to be setup before any
* non-transition async work so it can be dereferenced
* in the dismiss method. The dismiss method
* only waits for the entering transition
* to finish. It does not wait for all of the `present`
* method to resolve.
*/
this.keyboardOpenCallback = () => {
if (this.gesture) {
/**
* When the native keyboard is opened and the webview
* is resized, the gesture implementation will become unresponsive
* and enter a free-scroll mode.
*
* When the keyboard is opened, we disable the gesture for
* a single frame and re-enable once the contents have repositioned
* from the keyboard placement.
*/
this.gesture.enable(false);
raf(() => {
if (this.gesture) {
this.gesture.enable(true);
}
});
}
};
window.addEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
}
if (this.isSheetModal) {
this.initSheetGesture();
}
else if (hasCardModal) {
this.initSwipeToClose();
}
// Initialize view transition listener for iOS card modals
this.initViewTransitionListener();
// Initialize parent removal observer
this.initParentRemovalObserver();
unlock();
}
initSwipeToClose() {
var _a;
if (getIonMode$1(this) !== 'ios') {
return;
}
const { el } = this;
// All of the elements needed for the swipe gesture
// should be in the DOM and referenced by now, except
// for the presenting el
const animationBuilder = this.leaveAnimation || config.get('modalLeave', iosLeaveAnimation$3);
const ani = (this.animation = animationBuilder(el, {
presentingEl: this.presentingElement,
expandToScroll: this.expandToScroll,
}));
const contentEl = findIonContent(el);
if (!contentEl) {
printIonContentErrorMsg(el);
return;
}
const statusBarStyle = (_a = this.statusBarStyle) !== null && _a !== void 0 ? _a : Style.Default;
this.gesture = createSwipeToCloseGesture(el, ani, statusBarStyle, () => {
/**
* While the gesture animation is finishing
* it is possible for a user to tap the backdrop.
* This would result in the dismiss animation
* being played again. Typically this is avoided
* by setting `presented = false` on the overlay
* component; however, we cannot do that here as
* that would prevent the element from being
* removed from the DOM.
*/
this.gestureAnimationDismissing = true;
/**
* Reset the status bar style as the dismiss animation
* starts otherwise the status bar will be the wrong
* color for the duration of the dismiss animation.
* The dismiss method does this as well, but
* in this case it's only called once the animation
* has finished.
*/
setCardStatusBarDefault(this.statusBarStyle);
this.animation.onFinish(async () => {
await this.dismiss(undefined, GESTURE);
this.gestureAnimationDismissing = false;
});
});
this.gesture.enable(true);
}
initSheetGesture() {
const { wrapperEl, initialBreakpoint, backdropBreakpoint } = this;
if (!wrapperEl || initialBreakpoint === undefined) {
return;
}
const animationBuilder = this.enterAnimation || config.get('modalEnter', iosEnterAnimation$3);
const ani = (this.animation = animationBuilder(this.el, {
presentingEl: this.presentingElement,
currentBreakpoint: initialBreakpoint,
backdropBreakpoint,
expandToScroll: this.expandToScroll,
}));
ani.progressStart(true, 1);
const { gesture, moveSheetToBreakpoint } = createSheetGesture(this.el, this.backdropEl, wrapperEl, initialBreakpoint, backdropBreakpoint, ani, this.sortedBreakpoints, this.expandToScroll, () => { var _a; return (_a = this.currentBreakpoint) !== null && _a !== void 0 ? _a : 0; }, () => this.sheetOnDismiss(), (breakpoint) => {
if (this.currentBreakpoint !== breakpoint) {
this.currentBreakpoint = breakpoint;
this.ionBreakpointDidChange.emit({ breakpoint });
}
});
this.gesture = gesture;
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
this.gesture.enable(true);
}
sheetOnDismiss() {
/**
* While the gesture animation is finishing
* it is possible for a user to tap the backdrop.
* This would result in the dismiss animation
* being played again. Typically this is avoided
* by setting `presented = false` on the overlay
* component; however, we cannot do that here as
* that would prevent the element from being
* removed from the DOM.
*/
this.gestureAnimationDismissing = true;
this.animation.onFinish(async () => {
this.currentBreakpoint = 0;
this.ionBreakpointDidChange.emit({ breakpoint: this.currentBreakpoint });
await this.dismiss(undefined, GESTURE);
this.gestureAnimationDismissing = false;
});
}
/**
* Dismiss the modal overlay after it has been presented.
* This is a no-op if the overlay has not been presented yet. If you want
* to remove an overlay from the DOM that was never presented, use the
* [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the modal.
* For example, `cancel` or `backdrop`.
*/
async dismiss(data, role) {
var _a;
if (this.gestureAnimationDismissing && role !== GESTURE) {
return false;
}
/**
* Because the canDismiss check below is async,
* we need to claim a lock before the check happens,
* in case the dismiss transition does run.
*/
const unlock = await this.lockController.lock();
/**
* Dismiss all child modals. This is especially important in
* Angular and React because it's possible to lose control of a child
* modal when the parent modal is dismissed.
*/
await this.dismissNestedModals();
/**
* If a canDismiss handler is responsible
* for calling the dismiss method, we should
* not run the canDismiss check again.
*/
if (role !== 'handler' && !(await this.checkCanDismiss(data, role))) {
unlock();
return false;
}
const { presentingElement } = this;
/**
* We need to start the status bar change
* before the animation so that the change
* finishes when the dismiss animation does.
*/
const hasCardModal = presentingElement !== undefined;
if (hasCardModal && getIonMode$1(this) === 'ios') {
setCardStatusBarDefault(this.statusBarStyle);
}
/* tslint:disable-next-line */
if (typeof window !== 'undefined' && this.keyboardOpenCallback) {
window.removeEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
this.keyboardOpenCallback = undefined;
}
const dismissed = await dismiss(this, data, role, 'modalLeave', iosLeaveAnimation$3, mdLeaveAnimation$2, {
presentingEl: presentingElement,
currentBreakpoint: (_a = this.currentBreakpoint) !== null && _a !== void 0 ? _a : this.initialBreakpoint,
backdropBreakpoint: this.backdropBreakpoint,
expandToScroll: this.expandToScroll,
});
if (dismissed) {
const { delegate } = this.getDelegate();
await detachComponent(delegate, this.usersElement);
writeTask(() => this.el.classList.remove('show-modal'));
if (this.animation) {
this.animation.destroy();
}
if (this.gesture) {
this.gesture.destroy();
}
this.cleanupViewTransitionListener();
this.cleanupParentRemovalObserver();
}
this.currentBreakpoint = undefined;
this.animation = undefined;
unlock();
return dismissed;
}
/**
* Returns a promise that resolves when the modal did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionModalDidDismiss');
}
/**
* Returns a promise that resolves when the modal will dismiss.
*/
onWillDismiss() {
return eventMethod(this.el, 'ionModalWillDismiss');
}
/**
* Move a sheet style modal to a specific breakpoint.
*
* @param breakpoint The breakpoint value to move the sheet modal to.
* Must be a value defined in your `breakpoints` array.
*/
async setCurrentBreakpoint(breakpoint) {
if (!this.isSheetModal) {
printIonWarning('[ion-modal] - setCurrentBreakpoint is only supported on sheet modals.');
return;
}
if (!this.breakpoints.includes(breakpoint)) {
printIonWarning(`[ion-modal] - Attempted to set invalid breakpoint value ${breakpoint}. Please double check that the breakpoint value is part of your defined breakpoints.`);
return;
}
const { currentBreakpoint, moveSheetToBreakpoint, canDismiss, breakpoints, animated } = this;
if (currentBreakpoint === breakpoint) {
return;
}
if (moveSheetToBreakpoint) {
this.sheetTransition = moveSheetToBreakpoint({
breakpoint,
breakpointOffset: 1 - currentBreakpoint,
canDismiss: canDismiss !== undefined && canDismiss !== true && breakpoints[0] === 0,
animated,
});
await this.sheetTransition;
this.sheetTransition = undefined;
}
}
/**
* Returns the current breakpoint of a sheet style modal
*/
async getCurrentBreakpoint() {
return this.currentBreakpoint;
}
async moveToNextBreakpoint() {
const { breakpoints, currentBreakpoint } = this;
if (!breakpoints || currentBreakpoint == null) {
/**
* If the modal does not have breakpoints and/or the current
* breakpoint is not set, we can't move to the next breakpoint.
*/
return false;
}
const allowedBreakpoints = breakpoints.filter((b) => b !== 0);
const currentBreakpointIndex = allowedBreakpoints.indexOf(currentBreakpoint);
const nextBreakpointIndex = (currentBreakpointIndex + 1) % allowedBreakpoints.length;
const nextBreakpoint = allowedBreakpoints[nextBreakpointIndex];
/**
* Sets the current breakpoint to the next available breakpoint.
* If the current breakpoint is the last breakpoint, we set the current
* breakpoint to the first non-zero breakpoint to avoid dismissing the sheet.
*/
await this.setCurrentBreakpoint(nextBreakpoint);
return true;
}
initViewTransitionListener() {
// Only enable for iOS card modals when no custom animations are provided
if (getIonMode$1(this) !== 'ios' || !this.presentingElement || this.enterAnimation || this.leaveAnimation) {
return;
}
// Set initial view state
this.currentViewIsPortrait = window.innerWidth < 768;
}
handleViewTransition() {
const isPortrait = window.innerWidth < 768;
// Only transition if view state actually changed
if (this.currentViewIsPortrait === isPortrait) {
return;
}
// Cancel any ongoing transition animation
if (this.viewTransitionAnimation) {
this.viewTransitionAnimation.destroy();
this.viewTransitionAnimation = undefined;
}
const { presentingElement } = this;
if (!presentingElement) {
return;
}
// Create transition animation
let transitionAnimation;
if (this.currentViewIsPortrait && !isPortrait) {
// Portrait to landscape transition
transitionAnimation = portraitToLandscapeTransition(this.el, {
presentingEl: presentingElement});
}
else {
// Landscape to portrait transition
transitionAnimation = landscapeToPortraitTransition(this.el, {
presentingEl: presentingElement});
}
// Update state and play animation
this.currentViewIsPortrait = isPortrait;
this.viewTransitionAnimation = transitionAnimation;
transitionAnimation.play().then(() => {
this.viewTransitionAnimation = undefined;
// After orientation transition, recreate the swipe-to-close gesture
// with updated animation that reflects the new presenting element state
this.reinitSwipeToClose();
});
}
cleanupViewTransitionListener() {
// Clear any pending resize timeout
if (this.resizeTimeout) {
clearTimeout(this.resizeTimeout);
this.resizeTimeout = undefined;
}
if (this.viewTransitionAnimation) {
this.viewTransitionAnimation.destroy();
this.viewTransitionAnimation = undefined;
}
}
reinitSwipeToClose() {
// Only reinitialize if we have a presenting element and are on iOS
if (getIonMode$1(this) !== 'ios' || !this.presentingElement) {
return;
}
// Clean up existing gesture and animation
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
if (this.animation) {
// Properly end the progress-based animation at initial state before destroying
// to avoid leaving modal in intermediate swipe position
this.animation.progressEnd(0, 0, 0);
this.animation.destroy();
this.animation = undefined;
}
// Force the modal back to the correct position or it could end up
// in a weird state after destroying the animation
raf(() => {
this.ensureCorrectModalPosition();
this.initSwipeToClose();
});
}
ensureCorrectModalPosition() {
const { el, presentingElement } = this;
const root = getElementRoot(el);
const wrapperEl = root.querySelector('.modal-wrapper');
if (wrapperEl) {
wrapperEl.style.transform = 'translateY(0vh)';
wrapperEl.style.opacity = '1';
}
if ((presentingElement === null || presentingElement === void 0 ? void 0 : presentingElement.tagName) === 'ION-MODAL') {
const isPortrait = window.innerWidth < 768;
if (isPortrait) {
const transformOffset = !CSS.supports('width', 'max(0px, 1px)')
? '30px'
: 'max(30px, var(--ion-safe-area-top))';
const scale = SwipeToCloseDefaults.MIN_PRESENTING_SCALE;
presentingElement.style.transform = `translateY(${transformOffset}) scale(${scale})`;
}
else {
presentingElement.style.transform = 'translateY(0px) scale(1)';
}
}
}
async dismissNestedModals() {
const nestedModals = document.querySelectorAll(`ion-modal[data-parent-ion-modal="${this.el.id}"]`);
nestedModals === null || nestedModals === void 0 ? void 0 : nestedModals.forEach(async (modal) => {
await modal.dismiss(undefined, 'parent-dismissed');
});
}
initParentRemovalObserver() {
if (typeof MutationObserver === 'undefined') {
return;
}
// Only observe if we have a cached parent and are in browser environment
if (typeof window === 'undefined' || !this.cachedOriginalParent) {
return;
}
// Don't observe document or fragment nodes as they can't be "removed"
if (this.cachedOriginalParent.nodeType === Node.DOCUMENT_NODE ||
this.cachedOriginalParent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
return;
}
this.parentRemovalObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
// Check if our cached original parent was removed
const cachedParentWasRemoved = Array.from(mutation.removedNodes).some((node) => {
var _a, _b;
const isDirectMatch = node === this.cachedOriginalParent;
const isContainedMatch = this.cachedOriginalParent
? (_b = (_a = node).contains) === null || _b === void 0 ? void 0 : _b.call(_a, this.cachedOriginalParent)
: false;
return isDirectMatch || isContainedMatch;
});
// Also check if parent is no longer connected to DOM
const cachedParentDisconnected = this.cachedOriginalParent && !this.cachedOriginalParent.isConnected;
if (cachedParentWasRemoved || cachedParentDisconnected) {
this.dismiss(undefined, 'parent-removed');
// Release the reference to the cached original parent
// so we don't have a memory leak
this.cachedOriginalParent = undefined;
}
}
});
});
// Observe document body with subtree to catch removals at any level
this.parentRemovalObserver.observe(document.body, {
childList: true,
subtree: true,
});
}
cleanupParentRemovalObserver() {
var _a;
(_a = this.parentRemovalObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
this.parentRemovalObserver = undefined;
}
render() {
const { handle, isSheetModal, presentingElement, htmlAttributes, handleBehavior, inheritedAttributes, focusTrap, expandToScroll, } = this;
const showHandle = handle !== false && isSheetModal;
const mode = getIonMode$1(this);
const isCardModal = presentingElement !== undefined && mode === 'ios';
const isHandleCycle = handleBehavior === 'cycle';
const isSheetModalWithHandle = isSheetModal && showHandle;
return (hAsync(Host, Object.assign({ key: '9e9a7bd591eb17a225a00b4fa2e379e94601d17f', "no-router": true,
// Allow the modal to be navigable when the handle is focusable
tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
zIndex: `${20000 + this.overlayIndex}`,
}, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), hAsync("ion-backdrop", { key: 'e5eae2c14f830f75e308fcd7f4c10c86fac5b962', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && hAsync("div", { key: 'e268f9cd310c3cf4e051b5b92524ce4fb70d005e', class: "modal-shadow" }), hAsync("div", Object.assign({ key: '9c380f36c18144c153077b15744d1c3346bce63e',
/*
role and aria-modal must be used on the
same element. They must also be set inside the
shadow DOM otherwise ion-button will not be highlighted
when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
*/
role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (hAsync("button", { key: '2d5ee6d5959d97309c306e8ce72eb0f2c19be144', class: "modal-handle",
// Prevents the handle from receiving keyboard focus when it does not cycle
tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), hAsync("slot", { key: '5590434c35ea04c42fc006498bc189038e15a298', onSlotchange: this.onSlotChange }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"isOpen": ["onIsOpenChange"],
"trigger": ["triggerChanged"]
}; }
static get style() { return {
ios: modalIosCss,
md: modalMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-modal",
"$members$": {
"hasController": [4, "has-controller"],
"overlayIndex": [2, "overlay-index"],
"delegate": [16],
"keyboardClose": [4, "keyboard-close"],
"enterAnimation": [16],
"leaveAnimation": [16],
"breakpoints": [16],
"expandToScroll": [4, "expand-to-scroll"],
"initialBreakpoint": [2, "initial-breakpoint"],
"backdropBreakpoint": [2, "backdrop-breakpoint"],
"handle": [4],
"handleBehavior": [1, "handle-behavior"],
"component": [1],
"componentProps": [16],
"cssClass": [1, "css-class"],
"backdropDismiss": [4, "backdrop-dismiss"],
"showBackdrop": [4, "show-backdrop"],
"animated": [4],
"presentingElement": [16],
"htmlAttributes": [16],
"isOpen": [4, "is-open"],
"trigger": [1],
"keepContentsMounted": [4, "keep-contents-mounted"],
"focusTrap": [4, "focus-trap"],
"canDismiss": [4, "can-dismiss"],
"presented": [32],
"present": [64],
"dismiss": [64],
"onDidDismiss": [64],
"onWillDismiss": [64],
"setCurrentBreakpoint": [64],
"getCurrentBreakpoint": [64]
},
"$listeners$": [[9, "resize", "onWindowResize"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const LIFECYCLE_MAP$1 = {
ionModalDidPresent: 'ionViewDidEnter',
ionModalWillPresent: 'ionViewWillEnter',
ionModalWillDismiss: 'ionViewWillLeave',
ionModalDidDismiss: 'ionViewDidLeave',
};
const VIEW_STATE_NEW = 1;
const VIEW_STATE_ATTACHED = 2;
const VIEW_STATE_DESTROYED = 3;
// TODO(FW-2832): types
class ViewController {
constructor(component, params) {
this.component = component;
this.params = params;
this.state = VIEW_STATE_NEW;
}
async init(container) {
this.state = VIEW_STATE_ATTACHED;
if (!this.element) {
const component = this.component;
this.element = await attachComponent(this.delegate, container, component, ['ion-page', 'ion-page-invisible'], this.params);
}
}
/**
* DOM WRITE
*/
_destroy() {
assert(this.state !== VIEW_STATE_DESTROYED, 'view state must be ATTACHED');
const element = this.element;
if (element) {
if (this.delegate) {
this.delegate.removeViewFromDom(element.parentElement, element);
}
else {
element.remove();
}
}
this.nav = undefined;
this.state = VIEW_STATE_DESTROYED;
}
}
const matches = (view, id, params) => {
if (!view) {
return false;
}
if (view.component !== id) {
return false;
}
return shallowEqualStringMap(view.params, params);
};
const convertToView = (page, params) => {
if (!page) {
return null;
}
if (page instanceof ViewController) {
return page;
}
return new ViewController(page, params);
};
const convertToViews = (pages) => {
return pages
.map((page) => {
if (page instanceof ViewController) {
return page;
}
if ('component' in page) {
return convertToView(page.component, page.componentProps === null ? undefined : page.componentProps);
}
return convertToView(page, undefined);
})
.filter((v) => v !== null);
};
const navCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;z-index:0}";
class Nav {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionNavWillLoad = createEvent(this, "ionNavWillLoad", 7);
this.ionNavWillChange = createEvent(this, "ionNavWillChange", 3);
this.ionNavDidChange = createEvent(this, "ionNavDidChange", 3);
this.transInstr = [];
this.gestureOrAnimationInProgress = false;
this.useRouter = false;
this.isTransitioning = false;
this.destroyed = false;
this.views = [];
this.didLoad = false;
/**
* If `true`, the nav should animate the transition of components.
*/
this.animated = true;
}
swipeGestureChanged() {
if (this.gesture) {
this.gesture.enable(this.swipeGesture === true);
}
}
rootChanged() {
if (this.root === undefined) {
return;
}
if (this.didLoad === false) {
/**
* If the component has not loaded yet, we can skip setting up the root component.
* It will be called when `componentDidLoad` fires.
*/
return;
}
if (!this.useRouter) {
if (this.root !== undefined) {
this.setRoot(this.root, this.rootParams);
}
}
}
componentWillLoad() {
this.useRouter = document.querySelector('ion-router') !== null && this.el.closest('[no-router]') === null;
if (this.swipeGesture === undefined) {
const mode = getIonMode$1(this);
this.swipeGesture = config.getBoolean('swipeBackEnabled', mode === 'ios');
}
this.ionNavWillLoad.emit();
}
async componentDidLoad() {
// We want to set this flag before any watch callbacks are manually called
this.didLoad = true;
this.rootChanged();
this.gesture = (await Promise.resolve().then(function () { return swipeBack; })).createSwipeBackGesture(this.el, this.canStart.bind(this), this.onStart.bind(this), this.onMove.bind(this), this.onEnd.bind(this));
this.swipeGestureChanged();
}
connectedCallback() {
this.destroyed = false;
}
disconnectedCallback() {
for (const view of this.views) {
lifecycle(view.element, LIFECYCLE_WILL_UNLOAD);
view._destroy();
}
// Release swipe back gesture and transition.
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
this.transInstr.length = 0;
this.views.length = 0;
this.destroyed = true;
}
/**
* Push a new component onto the current navigation stack. Pass any additional
* information along as an object. This additional information is accessible
* through NavParams.
*
* @param component The component to push onto the navigation stack.
* @param componentProps Any properties of the component.
* @param opts The navigation options.
* @param done The transition complete function.
*/
push(component, componentProps, opts, done) {
return this.insert(-1, component, componentProps, opts, done);
}
/**
* Inserts a component into the navigation stack at the specified index.
* This is useful to add a component at any point in the navigation stack.
*
* @param insertIndex The index to insert the component at in the stack.
* @param component The component to insert into the navigation stack.
* @param componentProps Any properties of the component.
* @param opts The navigation options.
* @param done The transition complete function.
*/
insert(insertIndex, component, componentProps, opts, done) {
return this.insertPages(insertIndex, [{ component, componentProps }], opts, done);
}
/**
* Inserts an array of components into the navigation stack at the specified index.
* The last component in the array will become instantiated as a view, and animate
* in to become the active view.
*
* @param insertIndex The index to insert the components at in the stack.
* @param insertComponents The components to insert into the navigation stack.
* @param opts The navigation options.
* @param done The transition complete function.
*/
insertPages(insertIndex, insertComponents, opts, done) {
return this.queueTrns({
insertStart: insertIndex,
insertViews: insertComponents,
opts,
}, done);
}
/**
* Pop a component off of the navigation stack. Navigates back from the current
* component.
*
* @param opts The navigation options.
* @param done The transition complete function.
*/
pop(opts, done) {
return this.removeIndex(-1, 1, opts, done);
}
/**
* Pop to a specific index in the navigation stack.
*
* @param indexOrViewCtrl The index or view controller to pop to.
* @param opts The navigation options.
* @param done The transition complete function.
*/
popTo(indexOrViewCtrl, opts, done) {
const ti = {
removeStart: -1,
removeCount: -1,
opts,
};
if (typeof indexOrViewCtrl === 'object' && indexOrViewCtrl.component) {
ti.removeView = indexOrViewCtrl;
ti.removeStart = 1;
}
else if (typeof indexOrViewCtrl === 'number') {
ti.removeStart = indexOrViewCtrl + 1;
}
return this.queueTrns(ti, done);
}
/**
* Navigate back to the root of the stack, no matter how far back that is.
*
* @param opts The navigation options.
* @param done The transition complete function.
*/
popToRoot(opts, done) {
return this.removeIndex(1, -1, opts, done);
}
/**
* Removes a component from the navigation stack at the specified index.
*
* @param startIndex The number to begin removal at.
* @param removeCount The number of components to remove.
* @param opts The navigation options.
* @param done The transition complete function.
*/
removeIndex(startIndex, removeCount = 1, opts, done) {
return this.queueTrns({
removeStart: startIndex,
removeCount,
opts,
}, done);
}
/**
* Set the root for the current navigation stack to a component.
*
* @param component The component to set as the root of the navigation stack.
* @param componentProps Any properties of the component.
* @param opts The navigation options.
* @param done The transition complete function.
*/
setRoot(component, componentProps, opts, done) {
return this.setPages([{ component, componentProps }], opts, done);
}
/**
* Set the views of the current navigation stack and navigate to the last view.
* By default animations are disabled, but they can be enabled by passing options
* to the navigation controller. Navigation parameters can also be passed to the
* individual pages in the array.
*
* @param views The list of views to set as the navigation stack.
* @param opts The navigation options.
* @param done The transition complete function.
*/
setPages(views, opts, done) {
opts !== null && opts !== void 0 ? opts : (opts = {});
// if animation wasn't set to true then default it to NOT animate
if (opts.animated !== true) {
opts.animated = false;
}
return this.queueTrns({
insertStart: 0,
insertViews: views,
removeStart: 0,
removeCount: -1,
opts,
}, done);
}
/**
* Called by the router to update the view.
*
* @param id The component tag.
* @param params The component params.
* @param direction A direction hint.
* @param animation an AnimationBuilder.
*
* @return the status.
* @internal
*/
setRouteId(id, params, direction, animation) {
const active = this.getActiveSync();
if (matches(active, id, params)) {
return Promise.resolve({
changed: false,
element: active.element,
});
}
let resolve;
const promise = new Promise((r) => (resolve = r));
let finish;
const commonOpts = {
updateURL: false,
viewIsReady: (enteringEl) => {
let mark;
const p = new Promise((r) => (mark = r));
resolve({
changed: true,
element: enteringEl,
markVisible: async () => {
mark();
await finish;
},
});
return p;
},
};
if (direction === 'root') {
finish = this.setRoot(id, params, commonOpts);
}
else {
// Look for a view matching the target in the view stack.
const viewController = this.views.find((v) => matches(v, id, params));
if (viewController) {
finish = this.popTo(viewController, Object.assign(Object.assign({}, commonOpts), { direction: 'back', animationBuilder: animation }));
}
else if (direction === 'forward') {
finish = this.push(id, params, Object.assign(Object.assign({}, commonOpts), { animationBuilder: animation }));
}
else if (direction === 'back') {
finish = this.setRoot(id, params, Object.assign(Object.assign({}, commonOpts), { direction: 'back', animated: true, animationBuilder: animation }));
}
}
return promise;
}
/**
* Called by <ion-router> to retrieve the current component.
*
* @internal
*/
async getRouteId() {
const active = this.getActiveSync();
if (active) {
return {
id: active.element.tagName,
params: active.params,
element: active.element,
};
}
return undefined;
}
/**
* Get the active view.
*/
async getActive() {
return this.getActiveSync();
}
/**
* Get the view at the specified index.
*
* @param index The index of the view.
*/
async getByIndex(index) {
return this.views[index];
}
/**
* Returns `true` if the current view can go back.
*
* @param view The view to check.
*/
async canGoBack(view) {
return this.canGoBackSync(view);
}
/**
* Get the previous view.
*
* @param view The view to get.
*/
async getPrevious(view) {
return this.getPreviousSync(view);
}
/**
* Returns the number of views in the stack.
*/
async getLength() {
return Promise.resolve(this.views.length);
}
getActiveSync() {
return this.views[this.views.length - 1];
}
canGoBackSync(view = this.getActiveSync()) {
return !!(view && this.getPreviousSync(view));
}
getPreviousSync(view = this.getActiveSync()) {
if (!view) {
return undefined;
}
const views = this.views;
const index = views.indexOf(view);
return index > 0 ? views[index - 1] : undefined;
}
/**
* Adds a navigation stack change to the queue and schedules it to run.
*
* @returns Whether the transition succeeds.
*/
async queueTrns(ti, done) {
var _a, _b;
if (this.isTransitioning && ((_a = ti.opts) === null || _a === void 0 ? void 0 : _a.skipIfBusy)) {
return false;
}
const promise = new Promise((resolve, reject) => {
ti.resolve = resolve;
ti.reject = reject;
});
ti.done = done;
/**
* If using router, check to see if navigation hooks
* will allow us to perform this transition. This
* is required in order for hooks to work with
* the ion-back-button or swipe to go back.
*/
if (ti.opts && ti.opts.updateURL !== false && this.useRouter) {
const router = document.querySelector('ion-router');
if (router) {
const canTransition = await router.canTransition();
if (canTransition === false) {
return false;
}
if (typeof canTransition === 'string') {
router.push(canTransition, ti.opts.direction || 'back');
return false;
}
}
}
// Normalize empty
if (((_b = ti.insertViews) === null || _b === void 0 ? void 0 : _b.length) === 0) {
ti.insertViews = undefined;
}
// Enqueue transition instruction
this.transInstr.push(ti);
// if there isn't a transition already happening
// then this will kick off this transition
this.nextTrns();
return promise;
}
success(result, ti) {
if (this.destroyed) {
this.fireError('nav controller was destroyed', ti);
return;
}
if (ti.done) {
ti.done(result.hasCompleted, result.requiresTransition, result.enteringView, result.leavingView, result.direction);
}
ti.resolve(result.hasCompleted);
if (ti.opts.updateURL !== false && this.useRouter) {
const router = document.querySelector('ion-router');
if (router) {
const direction = result.direction === 'back' ? 'back' : 'forward';
router.navChanged(direction);
}
}
}
failed(rejectReason, ti) {
if (this.destroyed) {
this.fireError('nav controller was destroyed', ti);
return;
}
this.transInstr.length = 0;
this.fireError(rejectReason, ti);
}
fireError(rejectReason, ti) {
if (ti.done) {
ti.done(false, false, rejectReason);
}
if (ti.reject && !this.destroyed) {
ti.reject(rejectReason);
}
else {
ti.resolve(false);
}
}
/**
* Consumes the next transition in the queue.
*
* @returns whether the transition is executed.
*/
nextTrns() {
// this is the framework's bread 'n butta function
// only one transition is allowed at any given time
if (this.isTransitioning) {
return false;
}
// there is no transition happening right now, executes the next instructions.
const ti = this.transInstr.shift();
if (!ti) {
return false;
}
this.runTransition(ti);
return true;
}
/** Executes all the transition instruction from the queue. */
async runTransition(ti) {
try {
// set that this nav is actively transitioning
this.ionNavWillChange.emit();
this.isTransitioning = true;
this.prepareTI(ti);
const leavingView = this.getActiveSync();
const enteringView = this.getEnteringView(ti, leavingView);
if (!leavingView && !enteringView) {
throw new Error('no views in the stack to be removed');
}
if (enteringView && enteringView.state === VIEW_STATE_NEW) {
await enteringView.init(this.el);
}
this.postViewInit(enteringView, leavingView, ti);
// Needs transition?
const requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView;
if (requiresTransition && ti.opts && leavingView) {
const isBackDirection = ti.opts.direction === 'back';
/**
* If heading back, use the entering page's animation
* unless otherwise specified by the developer.
*/
if (isBackDirection) {
ti.opts.animationBuilder = ti.opts.animationBuilder || (enteringView === null || enteringView === void 0 ? void 0 : enteringView.animationBuilder);
}
leavingView.animationBuilder = ti.opts.animationBuilder;
}
let result;
if (requiresTransition) {
result = await this.transition(enteringView, leavingView, ti);
}
else {
// transition is not required, so we are already done!
// they're inserting/removing the views somewhere in the middle or
// beginning, so visually nothing needs to animate/transition
// resolve immediately because there's no animation that's happening
result = {
hasCompleted: true,
requiresTransition: false,
};
}
this.success(result, ti);
this.ionNavDidChange.emit();
}
catch (rejectReason) {
this.failed(rejectReason, ti);
}
this.isTransitioning = false;
this.nextTrns();
}
prepareTI(ti) {
var _a, _b;
var _c;
const viewsLength = this.views.length;
(_a = ti.opts) !== null && _a !== void 0 ? _a : (ti.opts = {});
(_b = (_c = ti.opts).delegate) !== null && _b !== void 0 ? _b : (_c.delegate = this.delegate);
if (ti.removeView !== undefined) {
assert(ti.removeStart !== undefined, 'removeView needs removeStart');
assert(ti.removeCount !== undefined, 'removeView needs removeCount');
const index = this.views.indexOf(ti.removeView);
if (index < 0) {
throw new Error('removeView was not found');
}
ti.removeStart += index;
}
if (ti.removeStart !== undefined) {
if (ti.removeStart < 0) {
ti.removeStart = viewsLength - 1;
}
if (ti.removeCount < 0) {
ti.removeCount = viewsLength - ti.removeStart;
}
ti.leavingRequiresTransition = ti.removeCount > 0 && ti.removeStart + ti.removeCount === viewsLength;
}
if (ti.insertViews) {
// allow -1 to be passed in to auto push it on the end
// and clean up the index if it's larger then the size of the stack
if (ti.insertStart < 0 || ti.insertStart > viewsLength) {
ti.insertStart = viewsLength;
}
ti.enteringRequiresTransition = ti.insertStart === viewsLength;
}
const insertViews = ti.insertViews;
if (!insertViews) {
return;
}
assert(insertViews.length > 0, 'length can not be zero');
const viewControllers = convertToViews(insertViews);
if (viewControllers.length === 0) {
throw new Error('invalid views to insert');
}
// Check all the inserted view are correct
for (const view of viewControllers) {
view.delegate = ti.opts.delegate;
const nav = view.nav;
if (nav && nav !== this) {
throw new Error('inserted view was already inserted');
}
if (view.state === VIEW_STATE_DESTROYED) {
throw new Error('inserted view was already destroyed');
}
}
ti.insertViews = viewControllers;
}
/**
* Returns the view that will be entered considering the transition instructions.
*
* @param ti The instructions.
* @param leavingView The view being left or undefined if none.
*
* @returns The view that will be entered, undefined if none.
*/
getEnteringView(ti, leavingView) {
// The last inserted view will be entered when view are inserted.
const insertViews = ti.insertViews;
if (insertViews !== undefined) {
return insertViews[insertViews.length - 1];
}
// When views are deleted, we will enter the last view that is not removed and not the view being left.
const removeStart = ti.removeStart;
if (removeStart !== undefined) {
const views = this.views;
const removeEnd = removeStart + ti.removeCount;
for (let i = views.length - 1; i >= 0; i--) {
const view = views[i];
if ((i < removeStart || i >= removeEnd) && view !== leavingView) {
return view;
}
}
}
return undefined;
}
/**
* Adds and Removes the views from the navigation stack.
*
* @param enteringView The view being entered.
* @param leavingView The view being left.
* @param ti The instructions.
*/
postViewInit(enteringView, leavingView, ti) {
var _a, _b, _c;
assert(leavingView || enteringView, 'Both leavingView and enteringView are null');
assert(ti.resolve, 'resolve must be valid');
assert(ti.reject, 'reject must be valid');
// Compute the views to remove.
const opts = ti.opts;
const { insertViews, removeStart, removeCount } = ti;
/** Records the view to destroy */
let destroyQueue;
// there are views to remove
if (removeStart !== undefined && removeCount !== undefined) {
assert(removeStart >= 0, 'removeStart can not be negative');
assert(removeCount >= 0, 'removeCount can not be negative');
destroyQueue = [];
for (let i = removeStart; i < removeStart + removeCount; i++) {
const view = this.views[i];
if (view !== undefined && view !== enteringView && view !== leavingView) {
destroyQueue.push(view);
}
}
// default the direction to "back"
(_a = opts.direction) !== null && _a !== void 0 ? _a : (opts.direction = 'back');
}
const finalNumViews = this.views.length + ((_b = insertViews === null || insertViews === void 0 ? void 0 : insertViews.length) !== null && _b !== void 0 ? _b : 0) - (removeCount !== null && removeCount !== void 0 ? removeCount : 0);
assert(finalNumViews >= 0, 'final balance can not be negative');
if (finalNumViews === 0) {
printIonWarning(`[ion-nav] - You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.`, this, this.el);
throw new Error('navigation stack needs at least one root page');
}
// At this point the transition can not be rejected, any throw should be an error
// Insert the new views in the stack.
if (insertViews) {
// add the views to the
let insertIndex = ti.insertStart;
for (const view of insertViews) {
this.insertViewAt(view, insertIndex);
insertIndex++;
}
if (ti.enteringRequiresTransition) {
// default to forward if not already set
(_c = opts.direction) !== null && _c !== void 0 ? _c : (opts.direction = 'forward');
}
}
// if the views to be removed are in the beginning or middle
// and there is not a view that needs to visually transition out
// then just destroy them and don't transition anything
// batch all of lifecycles together
// let's make sure, callbacks are zoned
if (destroyQueue && destroyQueue.length > 0) {
for (const view of destroyQueue) {
lifecycle(view.element, LIFECYCLE_WILL_LEAVE);
lifecycle(view.element, LIFECYCLE_DID_LEAVE);
lifecycle(view.element, LIFECYCLE_WILL_UNLOAD);
}
// once all lifecycle events has been delivered, we can safely detroy the views
for (const view of destroyQueue) {
this.destroyView(view);
}
}
}
async transition(enteringView, leavingView, ti) {
// we should animate (duration > 0) if the pushed page is not the first one (startup)
// or if it is a portal (modal, actionsheet, etc.)
const opts = ti.opts;
const progressCallback = opts.progressAnimation
? (ani) => {
/**
* Because this progress callback is called asynchronously
* it is possible for the gesture to start and end before
* the animation is ever set. In that scenario, we should
* immediately call progressEnd so that the transition promise
* resolves and the gesture does not get locked up.
*/
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
this.gestureOrAnimationInProgress = true;
ani.onFinish(() => {
this.gestureOrAnimationInProgress = false;
}, { oneTimeCallback: true });
/**
* Playing animation to beginning
* with a duration of 0 prevents
* any flickering when the animation
* is later cleaned up.
*/
ani.progressEnd(0, 0, 0);
}
else {
this.sbAni = ani;
}
}
: undefined;
const mode = getIonMode$1(this);
const enteringEl = enteringView.element;
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const leavingEl = leavingView && leavingView.element;
const animationOpts = Object.assign(Object.assign({ mode, showGoBack: this.canGoBackSync(enteringView), baseEl: this.el, progressCallback, animated: this.animated && config.getBoolean('animated', true), enteringEl,
leavingEl }, opts), { animationBuilder: opts.animationBuilder || this.animation || config.get('navAnimation') });
const { hasCompleted } = await transition(animationOpts);
return this.transitionFinish(hasCompleted, enteringView, leavingView, opts);
}
transitionFinish(hasCompleted, enteringView, leavingView, opts) {
/**
* If the transition did not complete, the leavingView will still be the active
* view on the stack. Otherwise unmount all the views after the enteringView.
*/
const activeView = hasCompleted ? enteringView : leavingView;
if (activeView) {
this.unmountInactiveViews(activeView);
}
return {
hasCompleted,
requiresTransition: true,
enteringView,
leavingView,
direction: opts.direction,
};
}
/**
* Inserts a view at the specified index.
*
* When the view already is in the stack it will be moved to the new position.
*
* @param view The view to insert.
* @param index The index where to insert the view.
*/
insertViewAt(view, index) {
const views = this.views;
const existingIndex = views.indexOf(view);
if (existingIndex > -1) {
assert(view.nav === this, 'view is not part of the nav');
// The view already in the stack, removes it.
views.splice(existingIndex, 1);
// and add it back at the requested index.
views.splice(index, 0, view);
}
else {
assert(!view.nav, 'nav is used');
// this is a new view to add to the stack
// create the new entering view
view.nav = this;
views.splice(index, 0, view);
}
}
/**
* Removes a view from the stack.
*
* @param view The view to remove.
*/
removeView(view) {
assert(view.state === VIEW_STATE_ATTACHED || view.state === VIEW_STATE_DESTROYED, 'view state should be loaded or destroyed');
const views = this.views;
const index = views.indexOf(view);
assert(index > -1, 'view must be part of the stack');
if (index >= 0) {
views.splice(index, 1);
}
}
destroyView(view) {
view._destroy();
this.removeView(view);
}
/**
* Unmounts all inactive views after the specified active view.
*
* DOM WRITE
*
* @param activeView The view that is actively visible in the stack. Used to calculate which views to unmount.
*/
unmountInactiveViews(activeView) {
// ok, cleanup time!! Destroy all of the views that are
// INACTIVE and come after the active view
// only do this if the views exist, though
if (this.destroyed) {
return;
}
const views = this.views;
const activeViewIndex = views.indexOf(activeView);
for (let i = views.length - 1; i >= 0; i--) {
const view = views[i];
/**
* When inserting multiple views via insertPages
* the last page will be transitioned to, but the
* others will not be. As a result, a DOM element
* will only be created for the last page inserted.
* As a result, it is possible to have views in the
* stack that do not have `view.element` yet.
*/
const element = view.element;
if (element) {
if (i > activeViewIndex) {
// this view comes after the active view
// let's unload it
lifecycle(element, LIFECYCLE_WILL_UNLOAD);
this.destroyView(view);
}
else if (i < activeViewIndex) {
// this view comes before the active view
// and it is not a portal then ensure it is hidden
setPageHidden(element, true);
}
}
}
}
canStart() {
return (!this.gestureOrAnimationInProgress &&
!!this.swipeGesture &&
!this.isTransitioning &&
this.transInstr.length === 0 &&
this.canGoBackSync());
}
onStart() {
this.gestureOrAnimationInProgress = true;
this.pop({ direction: 'back', progressAnimation: true });
}
onMove(stepValue) {
if (this.sbAni) {
this.sbAni.progressStep(stepValue);
}
}
onEnd(shouldComplete, stepValue, dur) {
if (this.sbAni) {
this.sbAni.onFinish(() => {
this.gestureOrAnimationInProgress = false;
}, { oneTimeCallback: true });
// Account for rounding errors in JS
let newStepValue = shouldComplete ? -1e-3 : 0.001;
/**
* Animation will be reversed here, so need to
* reverse the easing curve as well
*
* Additionally, we need to account for the time relative
* to the new easing curve, as `stepValue` is going to be given
* in terms of a linear curve.
*/
if (!shouldComplete) {
this.sbAni.easing('cubic-bezier(1, 0, 0.68, 0.28)');
newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], stepValue)[0];
}
else {
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], stepValue)[0];
}
this.sbAni.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
}
else {
this.gestureOrAnimationInProgress = false;
}
}
render() {
return hAsync("slot", { key: '8067c9835d255daec61f33dba200fd3a6ff839a0' });
}
get el() { return getElement(this); }
static get watchers() { return {
"swipeGesture": ["swipeGestureChanged"],
"root": ["rootChanged"]
}; }
static get style() { return navCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-nav",
"$members$": {
"delegate": [16],
"swipeGesture": [1028, "swipe-gesture"],
"animated": [4],
"animation": [16],
"rootParams": [16],
"root": [1],
"push": [64],
"insert": [64],
"insertPages": [64],
"pop": [64],
"popTo": [64],
"popToRoot": [64],
"removeIndex": [64],
"setRoot": [64],
"setPages": [64],
"setRouteId": [64],
"getRouteId": [64],
"getActive": [64],
"getByIndex": [64],
"canGoBack": [64],
"getPrevious": [64],
"getLength": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const navLink = (el, routerDirection, component, componentProps, routerAnimation) => {
const nav = el.closest('ion-nav');
if (nav) {
if (routerDirection === 'forward') {
if (component !== undefined) {
return nav.push(component, componentProps, { skipIfBusy: true, animationBuilder: routerAnimation });
}
}
else if (routerDirection === 'root') {
if (component !== undefined) {
return nav.setRoot(component, componentProps, { skipIfBusy: true, animationBuilder: routerAnimation });
}
}
else if (routerDirection === 'back') {
return nav.pop({ skipIfBusy: true, animationBuilder: routerAnimation });
}
}
return Promise.resolve(false);
};
class NavLink {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* The transition direction when navigating to another page.
*/
this.routerDirection = 'forward';
this.onClick = () => {
return navLink(this.el, this.routerDirection, this.component, this.componentProps, this.routerAnimation);
};
}
render() {
return hAsync(Host, { key: '6dbb1ad4f351e9215375aac11ab9b53762e07a08', onClick: this.onClick });
}
get el() { return getElement(this); }
static get cmpMeta() { return {
"$flags$": 256,
"$tagName$": "ion-nav-link",
"$members$": {
"component": [1],
"componentProps": [16],
"routerDirection": [1, "router-direction"],
"routerAnimation": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const noteIosCss = ":host{color:var(--color);font-family:var(--ion-font-family, inherit);-webkit-box-sizing:border-box;box-sizing:border-box}:host(.ion-color){color:var(--ion-color-base)}:host{--color:var(--ion-color-step-350, var(--ion-text-color-step-650, #a6a6a6));font-size:max(14px, 1rem)}";
const noteMdCss = ":host{color:var(--color);font-family:var(--ion-font-family, inherit);-webkit-box-sizing:border-box;box-sizing:border-box}:host(.ion-color){color:var(--ion-color-base)}:host{--color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));font-size:0.875rem}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Note {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '0ec2ef7367d867fd7588611953f696eecdf3221e', class: createColorClasses$1(this.color, {
[mode]: true,
}) }, hAsync("slot", { key: 'a200b94ddffb29cf6dabe6e984220930ea7efdef' })));
}
static get style() { return {
ios: noteIosCss,
md: noteMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-note",
"$members$": {
"color": [513]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const pickerIosCss$1 = ":host{display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:200px;direction:ltr;z-index:0}:host .picker-before,:host .picker-after{position:absolute;width:100%;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:1;pointer-events:none}:host .picker-before{top:0;height:83px}:host .picker-before{inset-inline-start:0}:host .picker-after{top:116px;height:84px}:host .picker-after{inset-inline-start:0}:host .picker-highlight{border-radius:var(--highlight-border-radius, 8px);left:0;right:0;top:50%;bottom:0;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;position:absolute;width:calc(100% - 16px);height:34px;-webkit-transform:translateY(-50%);transform:translateY(-50%);background:var(--highlight-background);z-index:-1}:host input{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}:host ::slotted(ion-picker-column:first-of-type){text-align:start}:host ::slotted(ion-picker-column:last-of-type){text-align:end}:host ::slotted(ion-picker-column:only-child){text-align:center}:host .picker-before{background:-webkit-gradient(linear, left top, left bottom, color-stop(20%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1)), to(rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0.8)));background:linear-gradient(to bottom, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1) 20%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0.8) 100%)}:host .picker-after{background:-webkit-gradient(linear, left bottom, left top, color-stop(20%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1)), to(rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0.8)));background:linear-gradient(to top, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1) 20%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0.8) 100%)}:host .picker-highlight{background:var(--highlight-background, var(--ion-color-step-150, var(--ion-background-color-step-150, #eeeeef)))}";
const pickerMdCss$1 = ":host{display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:200px;direction:ltr;z-index:0}:host .picker-before,:host .picker-after{position:absolute;width:100%;-webkit-transform:translateZ(0);transform:translateZ(0);z-index:1;pointer-events:none}:host .picker-before{top:0;height:83px}:host .picker-before{inset-inline-start:0}:host .picker-after{top:116px;height:84px}:host .picker-after{inset-inline-start:0}:host .picker-highlight{border-radius:var(--highlight-border-radius, 8px);left:0;right:0;top:50%;bottom:0;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;position:absolute;width:calc(100% - 16px);height:34px;-webkit-transform:translateY(-50%);transform:translateY(-50%);background:var(--highlight-background);z-index:-1}:host input{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}:host ::slotted(ion-picker-column:first-of-type){text-align:start}:host ::slotted(ion-picker-column:last-of-type){text-align:end}:host ::slotted(ion-picker-column:only-child){text-align:center}:host .picker-before{background:-webkit-gradient(linear, left top, left bottom, color-stop(20%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1)), color-stop(90%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0)));background:linear-gradient(to bottom, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1) 20%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0) 90%)}:host .picker-after{background:-webkit-gradient(linear, left bottom, left top, color-stop(30%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1)), color-stop(90%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0)));background:linear-gradient(to top, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 1) 30%, rgba(var(--fade-background-rgb, var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255))), 0) 90%)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
let Picker$1 = class Picker {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionInputModeChange = createEvent(this, "ionInputModeChange", 7);
this.useInputMode = false;
this.isInHighlightBounds = (ev) => {
const { highlightEl } = this;
if (!highlightEl) {
return false;
}
const bbox = highlightEl.getBoundingClientRect();
/**
* Check to see if the user clicked
* outside the bounds of the highlight.
*/
const outsideX = ev.clientX < bbox.left || ev.clientX > bbox.right;
const outsideY = ev.clientY < bbox.top || ev.clientY > bbox.bottom;
if (outsideX || outsideY) {
return false;
}
return true;
};
/**
* If we are no longer focused
* on a picker column, then we should
* exit input mode. An exception is made
* for the input in the picker since having
* that focused means we are still in input mode.
*/
this.onFocusOut = (ev) => {
// TODO(FW-2832): type
const { relatedTarget } = ev;
if (!relatedTarget || (relatedTarget.tagName !== 'ION-PICKER-COLUMN' && relatedTarget !== this.inputEl)) {
this.exitInputMode();
}
};
/**
* When picker columns receive focus
* the parent picker needs to determine
* whether to enter/exit input mode.
*/
this.onFocusIn = (ev) => {
// TODO(FW-2832): type
const { target } = ev;
/**
* Due to browser differences in how/when focus
* is dispatched on certain elements, we need to
* make sure that this function only ever runs when
* focusing a picker column.
*/
if (target.tagName !== 'ION-PICKER-COLUMN') {
return;
}
/**
* If we have actionOnClick
* then this means the user focused
* a picker column via mouse or
* touch (i.e. a PointerEvent). As a result,
* we should not enter/exit input mode
* until the click event has fired, which happens
* after the `focusin` event.
*
* Otherwise, the user likely focused
* the column using their keyboard and
* we should enter/exit input mode automatically.
*/
if (!this.actionOnClick) {
const columnEl = target;
const allowInput = columnEl.numericInput;
if (allowInput) {
this.enterInputMode(columnEl, false);
}
else {
this.exitInputMode();
}
}
};
/**
* On click we need to run an actionOnClick
* function that has been set in onPointerDown
* so that we enter/exit input mode correctly.
*/
this.onClick = () => {
const { actionOnClick } = this;
if (actionOnClick) {
actionOnClick();
this.actionOnClick = undefined;
}
};
/**
* Clicking a column also focuses the column on
* certain browsers, so we use onPointerDown
* to tell the onFocusIn function that users
* are trying to click the column rather than
* focus the column using the keyboard. When the
* user completes the click, the onClick function
* runs and runs the actionOnClick callback.
*/
this.onPointerDown = (ev) => {
const { useInputMode, inputModeColumn, el } = this;
if (this.isInHighlightBounds(ev)) {
/**
* If we were already in
* input mode, then we should determine
* if we tapped a particular column and
* should switch to input mode for
* that specific column.
*/
if (useInputMode) {
/**
* If we tapped a picker column
* then we should either switch to input
* mode for that column or all columns.
* Otherwise we should exit input mode
* since we just tapped the highlight and
* not a column.
*/
if (ev.target.tagName === 'ION-PICKER-COLUMN') {
/**
* If user taps 2 different columns
* then we should just switch to input mode
* for the new column rather than switching to
* input mode for all columns.
*/
if (inputModeColumn && inputModeColumn === ev.target) {
this.actionOnClick = () => {
this.enterInputMode();
};
}
else {
this.actionOnClick = () => {
this.enterInputMode(ev.target);
};
}
}
else {
this.actionOnClick = () => {
this.exitInputMode();
};
}
/**
* If we were not already in
* input mode, then we should
* enter input mode for all columns.
*/
}
else {
/**
* If there is only 1 numeric input column
* then we should skip multi column input.
*/
const columns = el.querySelectorAll('ion-picker-column.picker-column-numeric-input');
const columnEl = columns.length === 1 ? ev.target : undefined;
this.actionOnClick = () => {
this.enterInputMode(columnEl);
};
}
return;
}
this.actionOnClick = () => {
this.exitInputMode();
};
};
/**
* Enters input mode to allow
* for text entry of numeric values.
* If on mobile, we focus a hidden input
* field so that the on screen keyboard
* is brought up. When tabbing using a
* keyboard, picker columns receive an outline
* to indicate they are focused. As a result,
* we should not focus the hidden input as it
* would cause the outline to go away, preventing
* users from having any visual indication of which
* column is focused.
*/
this.enterInputMode = (columnEl, focusInput = true) => {
const { inputEl, el } = this;
if (!inputEl) {
return;
}
/**
* Only active input mode if there is at
* least one column that accepts numeric input.
*/
const hasInputColumn = el.querySelector('ion-picker-column.picker-column-numeric-input');
if (!hasInputColumn) {
return;
}
/**
* If columnEl is undefined then
* it is assumed that all numeric pickers
* are eligible for text entry.
* (i.e. hour and minute columns)
*/
this.useInputMode = true;
this.inputModeColumn = columnEl;
/**
* Users with a keyboard and mouse can
* activate input mode where the input is
* focused as well as when it is not focused,
* so we need to make sure we clean up any
* old listeners.
*/
if (focusInput) {
if (this.destroyKeypressListener) {
this.destroyKeypressListener();
this.destroyKeypressListener = undefined;
}
inputEl.focus();
}
else {
// TODO FW-5900 Use keydown instead
el.addEventListener('keypress', this.onKeyPress);
this.destroyKeypressListener = () => {
el.removeEventListener('keypress', this.onKeyPress);
};
}
this.emitInputModeChange();
};
this.onKeyPress = (ev) => {
const { inputEl } = this;
if (!inputEl) {
return;
}
const parsedValue = parseInt(ev.key, 10);
/**
* Only numbers should be allowed
*/
if (!Number.isNaN(parsedValue)) {
inputEl.value += ev.key;
this.onInputChange();
}
};
this.selectSingleColumn = () => {
const { inputEl, inputModeColumn, singleColumnSearchTimeout } = this;
if (!inputEl || !inputModeColumn) {
return;
}
const options = Array.from(inputModeColumn.querySelectorAll('ion-picker-column-option')).filter((el) => el.disabled !== true);
/**
* If users pause for a bit, the search
* value should be reset similar to how a
* <select> behaves. So typing "34", waiting,
* then typing "5" should select "05".
*/
if (singleColumnSearchTimeout) {
clearTimeout(singleColumnSearchTimeout);
}
this.singleColumnSearchTimeout = setTimeout(() => {
inputEl.value = '';
this.singleColumnSearchTimeout = undefined;
}, 1000);
/**
* For values that are longer than 2 digits long
* we should shift the value over 1 character
* to the left. So typing "456" would result in "56".
* TODO: If we want to support more than just
* time entry, we should update this value to be
* the max length of all of the picker items.
*/
if (inputEl.value.length >= 3) {
const startIndex = inputEl.value.length - 2;
const newString = inputEl.value.substring(startIndex);
inputEl.value = newString;
this.selectSingleColumn();
return;
}
/**
* Checking the value of the input gets priority
* first. For example, if the value of the input
* is "1" and we entered "2", then the complete value
* is "12" and we should select hour 12.
*
* Regex removes any leading zeros from values like "02",
* but it keeps a single zero if there are only zeros in the string.
* 0+(?=[1-9]) --> Match 1 or more zeros that are followed by 1-9
* 0+(?=0$) --> Match 1 or more zeros that must be followed by one 0 and end.
*/
const findItemFromCompleteValue = options.find(({ textContent }) => {
/**
* Keyboard entry is currently only used inside of Datetime
* where we guarantee textContent is set.
* If we end up exposing this feature publicly we should revisit this assumption.
*/
const parsedText = textContent.replace(/^0+(?=[1-9])|0+(?=0$)/, '');
return parsedText === inputEl.value;
});
if (findItemFromCompleteValue) {
inputModeColumn.setValue(findItemFromCompleteValue.value);
return;
}
/**
* If we typed "56" to get minute 56, then typed "7",
* we should select "07" as "567" is not a valid minute.
*/
if (inputEl.value.length === 2) {
const changedCharacter = inputEl.value.substring(inputEl.value.length - 1);
inputEl.value = changedCharacter;
this.selectSingleColumn();
}
};
/**
* Searches a list of column items for a particular
* value. This is currently used for numeric values.
* The zeroBehavior can be set to account for leading
* or trailing zeros when looking at the item text.
*/
this.searchColumn = (colEl, value, zeroBehavior = 'start') => {
if (!value) {
return false;
}
const behavior = zeroBehavior === 'start' ? /^0+/ : /0$/;
value = value.replace(behavior, '');
const option = Array.from(colEl.querySelectorAll('ion-picker-column-option')).find((el) => {
return el.disabled !== true && el.textContent.replace(behavior, '') === value;
});
if (option) {
colEl.setValue(option.value);
}
return !!option;
};
/**
* Attempts to intelligently search the first and second
* column as if they're number columns for the provided numbers
* where the first two numbers are the first column
* and the last 2 are the last column. Tries to allow for the first
* number to be ignored for situations where typos occurred.
*/
this.multiColumnSearch = (firstColumn, secondColumn, input) => {
if (input.length === 0) {
return;
}
const inputArray = input.split('');
const hourValue = inputArray.slice(0, 2).join('');
// Try to find a match for the first two digits in the first column
const foundHour = this.searchColumn(firstColumn, hourValue);
// If we have more than 2 digits and found a match for hours,
// use the remaining digits for the second column (minutes)
if (inputArray.length > 2 && foundHour) {
const minuteValue = inputArray.slice(2, 4).join('');
this.searchColumn(secondColumn, minuteValue);
}
// If we couldn't find a match for the two-digit hour, try single digit approaches
else if (!foundHour && inputArray.length >= 1) {
// First try the first digit as a single-digit hour
let singleDigitHour = inputArray[0];
let singleDigitFound = this.searchColumn(firstColumn, singleDigitHour);
// If that didn't work, try the second digit as a single-digit hour
// (handles case where user made a typo in the first digit, or they typed over themselves)
if (!singleDigitFound) {
inputArray.shift();
singleDigitHour = inputArray[0];
singleDigitFound = this.searchColumn(firstColumn, singleDigitHour);
}
// If we found a single-digit hour and have remaining digits,
// use up to 2 of the remaining digits for the second column
if (singleDigitFound && inputArray.length > 1) {
const remainingDigits = inputArray.slice(1, 3).join('');
this.searchColumn(secondColumn, remainingDigits);
}
}
};
this.selectMultiColumn = () => {
const { inputEl, el } = this;
if (!inputEl) {
return;
}
const numericPickers = Array.from(el.querySelectorAll('ion-picker-column')).filter((col) => col.numericInput);
const firstColumn = numericPickers[0];
const lastColumn = numericPickers[1];
let value = inputEl.value;
if (value.length > 4) {
const startIndex = inputEl.value.length - 4;
const newString = inputEl.value.substring(startIndex);
inputEl.value = newString;
value = newString;
}
this.multiColumnSearch(firstColumn, lastColumn, value);
};
/**
* Searches the value of the active column
* to determine which value users are trying
* to select
*/
this.onInputChange = () => {
const { useInputMode, inputEl, inputModeColumn } = this;
if (!useInputMode || !inputEl) {
return;
}
if (inputModeColumn) {
this.selectSingleColumn();
}
else {
this.selectMultiColumn();
}
};
/**
* Emit ionInputModeChange. Picker columns
* listen for this event to determine whether
* or not their column is "active" for text input.
*/
this.emitInputModeChange = () => {
const { useInputMode, inputModeColumn } = this;
this.ionInputModeChange.emit({
useInputMode,
inputModeColumn,
});
};
}
/**
* When the picker is interacted with
* we need to prevent touchstart so other
* gestures do not fire. For example,
* scrolling on the wheel picker
* in ion-datetime should not cause
* a card modal to swipe to close.
*/
preventTouchStartPropagation(ev) {
ev.stopPropagation();
}
componentWillLoad() {
getElementRoot(this.el).addEventListener('focusin', this.onFocusIn);
getElementRoot(this.el).addEventListener('focusout', this.onFocusOut);
}
/**
* @internal
* Exits text entry mode for the picker
* This method blurs the hidden input
* and cause the keyboard to dismiss.
*/
async exitInputMode() {
const { inputEl, useInputMode } = this;
if (!useInputMode || !inputEl) {
return;
}
this.useInputMode = false;
this.inputModeColumn = undefined;
inputEl.blur();
inputEl.value = '';
if (this.destroyKeypressListener) {
this.destroyKeypressListener();
this.destroyKeypressListener = undefined;
}
this.emitInputModeChange();
}
render() {
return (hAsync(Host, { key: '28f81e4ed44a633178561757c5199c2c98f94b74', onPointerDown: (ev) => this.onPointerDown(ev), onClick: () => this.onClick() }, hAsync("input", { key: 'abb3d1ad25ef63856af7804111175a4d50008bc0', "aria-hidden": "true", tabindex: -1, inputmode: "numeric", type: "number", onKeyDown: (ev) => {
var _a;
/**
* The "Enter" key represents
* the user submitting their time
* selection, so we should blur the
* input (and therefore close the keyboard)
*
* Updating the picker's state to no longer
* be in input mode is handled in the onBlur
* callback below.
*/
if (ev.key === 'Enter') {
(_a = this.inputEl) === null || _a === void 0 ? void 0 : _a.blur();
}
}, ref: (el) => (this.inputEl = el), onInput: () => this.onInputChange(), onBlur: () => this.exitInputMode() }), hAsync("div", { key: '334a5abdc02e6b127c57177f626d7e4ff5526183', class: "picker-before" }), hAsync("div", { key: 'ffd6271931129e88fc7c820e919d684899e420c5', class: "picker-after" }), hAsync("div", { key: '78d1d95fd09e04f154ea59f24a1cece72c47ed7b', class: "picker-highlight", ref: (el) => (this.highlightEl = el) }), hAsync("slot", { key: '0bd5b9f875d3c71f6cbbde2054baeb1b0a2e8cd5' })));
}
get el() { return getElement(this); }
static get style() { return {
ios: pickerIosCss$1,
md: pickerMdCss$1
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-picker",
"$members$": {
"exitInputMode": [64]
},
"$listeners$": [[1, "touchstart", "preventTouchStartPropagation"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
};
/**
* iOS Picker Enter Animation
*/
const iosEnterAnimation$2 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation
.addElement(baseEl.querySelector('.picker-wrapper'))
.fromTo('transform', 'translateY(100%)', 'translateY(0%)');
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(.36,.66,.04,1)')
.duration(400)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
/**
* iOS Picker Leave Animation
*/
const iosLeaveAnimation$2 = (baseEl) => {
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation
.addElement(baseEl.querySelector('ion-backdrop'))
.fromTo('opacity', 'var(--backdrop-opacity)', 0.01);
wrapperAnimation
.addElement(baseEl.querySelector('.picker-wrapper'))
.fromTo('transform', 'translateY(0%)', 'translateY(100%)');
return baseAnimation
.addElement(baseEl)
.easing('cubic-bezier(.36,.66,.04,1)')
.duration(400)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
const pickerIosCss = ".sc-ion-picker-legacy-ios-h{--border-radius:0;--border-style:solid;--min-width:auto;--width:100%;--max-width:500px;--min-height:auto;--max-height:auto;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;top:0;display:block;position:absolute;width:100%;height:100%;outline:none;font-family:var(--ion-font-family, inherit);contain:strict;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.sc-ion-picker-legacy-ios-h{inset-inline-start:0}.overlay-hidden.sc-ion-picker-legacy-ios-h{display:none}.picker-wrapper.sc-ion-picker-legacy-ios{border-radius:var(--border-radius);left:0;right:0;bottom:0;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);contain:strict;overflow:hidden;z-index:10}.picker-toolbar.sc-ion-picker-legacy-ios{width:100%;background:transparent;contain:strict;z-index:1}.picker-button.sc-ion-picker-legacy-ios{border:0;font-family:inherit}.picker-button.sc-ion-picker-legacy-ios:active,.picker-button.sc-ion-picker-legacy-ios:focus{outline:none}.picker-columns.sc-ion-picker-legacy-ios{display:-ms-flexbox;display:flex;position:relative;-ms-flex-pack:center;justify-content:center;margin-bottom:var(--ion-safe-area-bottom, 0);contain:strict;overflow:hidden}.picker-above-highlight.sc-ion-picker-legacy-ios,.picker-below-highlight.sc-ion-picker-legacy-ios{display:none;pointer-events:none}.sc-ion-picker-legacy-ios-h{--background:var(--ion-background-color, #fff);--border-width:1px 0 0;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));--height:260px;--backdrop-opacity:var(--ion-backdrop-opacity, 0.26);color:var(--ion-item-color, var(--ion-text-color, #000))}.picker-toolbar.sc-ion-picker-legacy-ios{display:-ms-flexbox;display:flex;height:44px;border-bottom:0.55px solid var(--border-color)}.picker-toolbar-button.sc-ion-picker-legacy-ios{-ms-flex:1;flex:1;text-align:end}.picker-toolbar-button.sc-ion-picker-legacy-ios:last-child .picker-button.sc-ion-picker-legacy-ios{font-weight:600}.picker-toolbar-button.sc-ion-picker-legacy-ios:first-child{font-weight:normal;text-align:start}.picker-button.sc-ion-picker-legacy-ios,.picker-button.ion-activated.sc-ion-picker-legacy-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:1em;padding-inline-start:1em;-webkit-padding-end:1em;padding-inline-end:1em;padding-top:0;padding-bottom:0;height:44px;background:transparent;color:var(--ion-color-primary, #0054e9);font-size:16px}.picker-columns.sc-ion-picker-legacy-ios{height:215px;-webkit-perspective:1000px;perspective:1000px}.picker-above-highlight.sc-ion-picker-legacy-ios{top:0;-webkit-transform:translate3d(0, 0, 90px);transform:translate3d(0, 0, 90px);display:block;position:absolute;width:100%;height:81px;border-bottom:1px solid var(--border-color);background:-webkit-gradient(linear, left top, left bottom, color-stop(20%, var(--background, var(--ion-background-color, #fff))), to(rgba(var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255)), 0.8)));background:linear-gradient(to bottom, var(--background, var(--ion-background-color, #fff)) 20%, rgba(var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255)), 0.8) 100%);z-index:10}.picker-above-highlight.sc-ion-picker-legacy-ios{inset-inline-start:0}.picker-below-highlight.sc-ion-picker-legacy-ios{top:115px;-webkit-transform:translate3d(0, 0, 90px);transform:translate3d(0, 0, 90px);display:block;position:absolute;width:100%;height:119px;border-top:1px solid var(--border-color);background:-webkit-gradient(linear, left bottom, left top, color-stop(30%, var(--background, var(--ion-background-color, #fff))), to(rgba(var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255)), 0.8)));background:linear-gradient(to top, var(--background, var(--ion-background-color, #fff)) 30%, rgba(var(--background-rgb, var(--ion-background-color-rgb, 255, 255, 255)), 0.8) 100%);z-index:11}.picker-below-highlight.sc-ion-picker-legacy-ios{inset-inline-start:0}";
const pickerMdCss = ".sc-ion-picker-legacy-md-h{--border-radius:0;--border-style:solid;--min-width:auto;--width:100%;--max-width:500px;--min-height:auto;--max-height:auto;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;top:0;display:block;position:absolute;width:100%;height:100%;outline:none;font-family:var(--ion-font-family, inherit);contain:strict;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:1001}.sc-ion-picker-legacy-md-h{inset-inline-start:0}.overlay-hidden.sc-ion-picker-legacy-md-h{display:none}.picker-wrapper.sc-ion-picker-legacy-md{border-radius:var(--border-radius);left:0;right:0;bottom:0;-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);contain:strict;overflow:hidden;z-index:10}.picker-toolbar.sc-ion-picker-legacy-md{width:100%;background:transparent;contain:strict;z-index:1}.picker-button.sc-ion-picker-legacy-md{border:0;font-family:inherit}.picker-button.sc-ion-picker-legacy-md:active,.picker-button.sc-ion-picker-legacy-md:focus{outline:none}.picker-columns.sc-ion-picker-legacy-md{display:-ms-flexbox;display:flex;position:relative;-ms-flex-pack:center;justify-content:center;margin-bottom:var(--ion-safe-area-bottom, 0);contain:strict;overflow:hidden}.picker-above-highlight.sc-ion-picker-legacy-md,.picker-below-highlight.sc-ion-picker-legacy-md{display:none;pointer-events:none}.sc-ion-picker-legacy-md-h{--background:var(--ion-background-color, #fff);--border-width:0.55px 0 0;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));--height:260px;--backdrop-opacity:var(--ion-backdrop-opacity, 0.26);color:var(--ion-item-color, var(--ion-text-color, #000))}.picker-toolbar.sc-ion-picker-legacy-md{display:-ms-flexbox;display:flex;-ms-flex-pack:end;justify-content:flex-end;height:44px}.picker-button.sc-ion-picker-legacy-md,.picker-button.ion-activated.sc-ion-picker-legacy-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:1.1em;padding-inline-start:1.1em;-webkit-padding-end:1.1em;padding-inline-end:1.1em;padding-top:0;padding-bottom:0;height:44px;background:transparent;color:var(--ion-color-primary, #0054e9);font-size:14px;font-weight:500;text-transform:uppercase;-webkit-box-shadow:none;box-shadow:none}.picker-columns.sc-ion-picker-legacy-md{height:216px;-webkit-perspective:1800px;perspective:1800px}.picker-above-highlight.sc-ion-picker-legacy-md{top:0;-webkit-transform:translate3d(0, 0, 90px);transform:translate3d(0, 0, 90px);position:absolute;width:100%;height:81px;border-bottom:1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));background:-webkit-gradient(linear, left top, left bottom, color-stop(20%, var(--ion-background-color, #fff)), to(rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8)));background:linear-gradient(to bottom, var(--ion-background-color, #fff) 20%, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8) 100%);z-index:10}.picker-above-highlight.sc-ion-picker-legacy-md{inset-inline-start:0}.picker-below-highlight.sc-ion-picker-legacy-md{top:115px;-webkit-transform:translate3d(0, 0, 90px);transform:translate3d(0, 0, 90px);position:absolute;width:100%;height:119px;border-top:1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));background:-webkit-gradient(linear, left bottom, left top, color-stop(30%, var(--ion-background-color, #fff)), to(rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8)));background:linear-gradient(to top, var(--ion-background-color, #fff) 30%, rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8) 100%);z-index:11}.picker-below-highlight.sc-ion-picker-legacy-md{inset-inline-start:0}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Picker {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionPickerDidPresent", 7);
this.willPresent = createEvent(this, "ionPickerWillPresent", 7);
this.willDismiss = createEvent(this, "ionPickerWillDismiss", 7);
this.didDismiss = createEvent(this, "ionPickerDidDismiss", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.delegateController = createDelegateController(this);
this.lockController = createLockController();
this.triggerController = createTriggerController();
this.presented = false;
/** @internal */
this.hasController = false;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = true;
/**
* Array of buttons to be displayed at the top of the picker.
*/
this.buttons = [];
/**
* Array of columns to be displayed in the picker.
*/
this.columns = [];
/**
* Number of milliseconds to wait before dismissing the picker.
*/
this.duration = 0;
/**
* If `true`, a backdrop will be displayed behind the picker.
*/
this.showBackdrop = true;
/**
* If `true`, the picker will be dismissed when the backdrop is clicked.
*/
this.backdropDismiss = true;
/**
* If `true`, the picker will animate.
*/
this.animated = true;
/**
* If `true`, the picker will open. If `false`, the picker will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the pickerController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the picker dismisses. You will need to do that in your code.
*/
this.isOpen = false;
this.onBackdropTap = () => {
this.dismiss(undefined, BACKDROP);
};
this.dispatchCancelHandler = (ev) => {
const role = ev.detail.role;
if (isCancel(role)) {
const cancelButton = this.buttons.find((b) => b.role === 'cancel');
this.callButtonHandler(cancelButton);
}
};
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
triggerChanged() {
const { trigger, el, triggerController } = this;
if (trigger) {
triggerController.addClickListener(el, trigger);
}
}
connectedCallback() {
prepareOverlay(this.el);
this.triggerChanged();
}
disconnectedCallback() {
this.triggerController.removeClickListener();
}
componentWillLoad() {
var _a;
if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
setOverlayId(this.el);
}
}
componentDidLoad() {
printIonWarning('[ion-picker-legacy] - ion-picker-legacy and ion-picker-legacy-column have been deprecated in favor of new versions of the ion-picker and ion-picker-column components. These new components display inline with your page content allowing for more presentation flexibility than before.', this.el);
/**
* If picker was rendered with isOpen="true"
* then we should open picker immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.triggerChanged();
}
/**
* Present the picker overlay after it has been created.
*/
async present() {
const unlock = await this.lockController.lock();
await this.delegateController.attachViewToDom();
await present(this, 'pickerEnter', iosEnterAnimation$2, iosEnterAnimation$2, undefined);
if (this.duration > 0) {
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration);
}
unlock();
}
/**
* Dismiss the picker overlay after it has been presented.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the picker.
* This can be useful in a button handler for determining which button was
* clicked to dismiss the picker.
* Some examples include: ``"cancel"`, `"destructive"`, "selected"`, and `"backdrop"`.
*/
async dismiss(data, role) {
const unlock = await this.lockController.lock();
if (this.durationTimeout) {
clearTimeout(this.durationTimeout);
}
const dismissed = await dismiss(this, data, role, 'pickerLeave', iosLeaveAnimation$2, iosLeaveAnimation$2);
if (dismissed) {
this.delegateController.removeViewFromDom();
}
unlock();
return dismissed;
}
/**
* Returns a promise that resolves when the picker did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionPickerDidDismiss');
}
/**
* Returns a promise that resolves when the picker will dismiss.
*/
onWillDismiss() {
return eventMethod(this.el, 'ionPickerWillDismiss');
}
/**
* Get the column that matches the specified name.
*
* @param name The name of the column.
*/
getColumn(name) {
return Promise.resolve(this.columns.find((column) => column.name === name));
}
async buttonClick(button) {
const role = button.role;
if (isCancel(role)) {
return this.dismiss(undefined, role);
}
const shouldDismiss = await this.callButtonHandler(button);
if (shouldDismiss) {
return this.dismiss(this.getSelected(), button.role);
}
return Promise.resolve();
}
async callButtonHandler(button) {
if (button) {
// a handler has been provided, execute it
// pass the handler the values from the inputs
const rtn = await safeCall(button.handler, this.getSelected());
if (rtn === false) {
// if the return value of the handler is false then do not dismiss
return false;
}
}
return true;
}
getSelected() {
const selected = {};
this.columns.forEach((col, index) => {
const selectedColumn = col.selectedIndex !== undefined ? col.options[col.selectedIndex] : undefined;
selected[col.name] = {
text: selectedColumn ? selectedColumn.text : undefined,
value: selectedColumn ? selectedColumn.value : undefined,
columnIndex: index,
};
});
return selected;
}
render() {
const { htmlAttributes } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, Object.assign({ key: 'b95440747eb80cba23ae676d399d5e5816722c58', "aria-modal": "true", tabindex: "-1" }, htmlAttributes, { style: {
zIndex: `${20000 + this.overlayIndex}`,
}, class: Object.assign({ [mode]: true,
// Used internally for styling
[`picker-${mode}`]: true, 'overlay-hidden': true }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonPickerWillDismiss: this.dispatchCancelHandler }), hAsync("ion-backdrop", { key: '169d1c83ef40e7fcb134219a585298b403a70b0f', visible: this.showBackdrop, tappable: this.backdropDismiss }), hAsync("div", { key: '98518e5f5cea2dfb8dfa63d9545e9ae3a5765023', tabindex: "0", "aria-hidden": "true" }), hAsync("div", { key: '151755ab8eb23f9adafbfe201349398f5a69dee7', class: "picker-wrapper ion-overlay-wrapper", role: "dialog" }, hAsync("div", { key: '5dcf93b2f4fe8f4fce7c7aec8f85ef45a03ef470', class: "picker-toolbar" }, this.buttons.map((b) => (hAsync("div", { class: buttonWrapperClass(b) }, hAsync("button", { type: "button", onClick: () => this.buttonClick(b), class: buttonClass$1(b) }, b.text))))), hAsync("div", { key: 'fd5d66708edd38adc5a4d2fad7298969398a05e3', class: "picker-columns" }, hAsync("div", { key: '1b5830fd6cef1016af7736792c514965d6cb38a8', class: "picker-above-highlight" }), this.presented && this.columns.map((c) => hAsync("ion-picker-legacy-column", { col: c })), hAsync("div", { key: 'c6edeca7afd69e13c9c66ba36f261974fd0f8f78', class: "picker-below-highlight" }))), hAsync("div", { key: 'e2a4b24710e30579b14b82dbfd3761b2187797b5', tabindex: "0", "aria-hidden": "true" })));
}
get el() { return getElement(this); }
static get watchers() { return {
"isOpen": ["onIsOpenChange"],
"trigger": ["triggerChanged"]
}; }
static get style() { return {
ios: pickerIosCss,
md: pickerMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-picker-legacy",
"$members$": {
"overlayIndex": [2, "overlay-index"],
"delegate": [16],
"hasController": [4, "has-controller"],
"keyboardClose": [4, "keyboard-close"],
"enterAnimation": [16],
"leaveAnimation": [16],
"buttons": [16],
"columns": [16],
"cssClass": [1, "css-class"],
"duration": [2],
"showBackdrop": [4, "show-backdrop"],
"backdropDismiss": [4, "backdrop-dismiss"],
"animated": [4],
"htmlAttributes": [16],
"isOpen": [4, "is-open"],
"trigger": [1],
"presented": [32],
"present": [64],
"dismiss": [64],
"onDidDismiss": [64],
"onWillDismiss": [64],
"getColumn": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const buttonWrapperClass = (button) => {
return {
[`picker-toolbar-${button.role}`]: button.role !== undefined,
'picker-toolbar-button': true,
};
};
const buttonClass$1 = (button) => {
return Object.assign({ 'picker-button': true, 'ion-activatable': true }, getClassMap(button.cssClass));
};
const pickerColumnCss = ":host{display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;max-width:100%;height:200px;font-size:22px;text-align:center}.assistive-focusable{left:0;right:0;top:0;bottom:0;position:absolute;z-index:1;pointer-events:none}.assistive-focusable:focus{outline:none}.picker-opts{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:0px;padding-bottom:0px;min-width:26px;max-height:200px;outline:none;text-align:inherit;-webkit-scroll-snap-type:y mandatory;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;overflow-x:hidden;overflow-y:scroll;scrollbar-width:none}.picker-item-empty{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:block;width:100%;height:34px;border:0px;outline:none;background:transparent;color:inherit;font-family:var(--ion-font-family, inherit);font-size:inherit;line-height:34px;text-align:inherit;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.picker-opts::-webkit-scrollbar{display:none}::slotted(ion-picker-column-option){display:block;scroll-snap-align:center}.picker-item-empty,:host(:not([disabled])) ::slotted(ion-picker-column-option.option-disabled){scroll-snap-align:none}::slotted([slot=prefix]),::slotted([slot=suffix]){max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}::slotted([slot=prefix]){-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:0;padding-bottom:0;-ms-flex-pack:end;justify-content:end}::slotted([slot=suffix]){-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:0;padding-bottom:0;-ms-flex-pack:start;justify-content:start}:host(.picker-column-disabled) .picker-opts{overflow-y:hidden}:host(.picker-column-disabled) ::slotted(ion-picker-column-option){cursor:default;opacity:0.4;pointer-events:none}@media (any-hover: hover){:host(:focus) .picker-opts{outline:none;background:rgba(var(--ion-color-base-rgb), 0.2)}}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot prefix - Content to show on the left side of the picker options.
* @slot suffix - Content to show on the right side of the picker options.
*/
class PickerColumn {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.isScrolling = false;
this.isColumnVisible = false;
this.canExitInputMode = true;
this.updateValueTextOnScroll = false;
this.ariaLabel = null;
this.isActive = false;
/**
* If `true`, the user cannot interact with the picker.
*/
this.disabled = false;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
this.color = 'primary';
/**
* If `true`, tapping the picker will
* reveal a number input keyboard that lets
* the user type in values for each picker
* column. This is useful when working
* with time pickers.
*
* @internal
*/
this.numericInput = false;
this.centerPickerItemInView = (target, smooth = true, canExitInputMode = true) => {
const { isColumnVisible, scrollEl } = this;
if (isColumnVisible && scrollEl) {
// (Vertical offset from parent) - (three empty picker rows) + (half the height of the target to ensure the scroll triggers)
const top = target.offsetTop - 3 * target.clientHeight + target.clientHeight / 2;
if (scrollEl.scrollTop !== top) {
/**
* Setting this flag prevents input
* mode from exiting in the picker column's
* scroll callback. This is useful when the user manually
* taps an item or types on the keyboard as both
* of these can cause a scroll to occur.
*/
this.canExitInputMode = canExitInputMode;
this.updateValueTextOnScroll = false;
scrollEl.scroll({
top,
left: 0,
behavior: smooth ? 'smooth' : undefined,
});
}
}
};
this.setPickerItemActiveState = (item, isActive) => {
if (isActive) {
item.classList.add(PICKER_ITEM_ACTIVE_CLASS);
}
else {
item.classList.remove(PICKER_ITEM_ACTIVE_CLASS);
}
};
/**
* When ionInputModeChange is emitted, each column
* needs to check if it is the one being made available
* for text entry.
*/
this.inputModeChange = (ev) => {
if (!this.numericInput) {
return;
}
const { useInputMode, inputModeColumn } = ev.detail;
/**
* If inputModeColumn is undefined then this means
* all numericInput columns are being selected.
*/
const isColumnActive = inputModeColumn === undefined || inputModeColumn === this.el;
if (!useInputMode || !isColumnActive) {
this.setInputModeActive(false);
return;
}
this.setInputModeActive(true);
};
/**
* Setting isActive will cause a re-render.
* As a result, we do not want to cause the
* re-render mid scroll as this will cause
* the picker column to jump back to
* whatever value was selected at the
* start of the scroll interaction.
*/
this.setInputModeActive = (state) => {
if (this.isScrolling) {
this.scrollEndCallback = () => {
this.isActive = state;
};
return;
}
this.isActive = state;
};
/**
* When the column scrolls, the component
* needs to determine which item is centered
* in the view and will emit an ionChange with
* the item object.
*/
this.initializeScrollListener = () => {
/**
* The haptics for the wheel picker are
* an iOS-only feature. As a result, they should
* be disabled on Android.
*/
const enableHaptics = isPlatform('ios');
const { el, scrollEl } = this;
let timeout;
let activeEl = this.activeItem;
const scrollCallback = () => {
raf(() => {
var _a;
if (!scrollEl)
return;
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
if (!this.isScrolling) {
enableHaptics && hapticSelectionStart();
this.isScrolling = true;
}
/**
* Select item in the center of the column
* which is the month/year that we want to select
*/
const bbox = scrollEl.getBoundingClientRect();
const centerX = bbox.x + bbox.width / 2;
const centerY = bbox.y + bbox.height / 2;
/**
* elementFromPoint returns the top-most element.
* This means that if an ion-backdrop is overlaying the
* picker then the appropriate picker column option will
* not be selected. To account for this, we use elementsFromPoint
* and use an Array.find to find the appropriate column option
* at that point.
*
* Additionally, the picker column could be used in the
* Shadow DOM (i.e. in ion-datetime) so we need to make
* sure we are choosing the correct host otherwise
* the elements returns by elementsFromPoint will be
* retargeted. To account for this, we check to see
* if the picker column has a parent shadow root. If
* so, we use that shadow root when doing elementsFromPoint.
* Otherwise, we just use the document.
*/
const rootNode = el.getRootNode();
const hasParentShadow = rootNode instanceof ShadowRoot;
const referenceNode = hasParentShadow ? rootNode : doc;
/**
* If the reference node is undefined
* then it's likely that doc is undefined
* due to being in an SSR environment.
*/
if (referenceNode === undefined) {
return;
}
const elementsAtPoint = referenceNode.elementsFromPoint(centerX, centerY);
/**
* elementsFromPoint can returns multiple elements
* so find the relevant picker column option if one exists.
*/
let newActiveElement = elementsAtPoint.find((el) => el.tagName === 'ION-PICKER-COLUMN-OPTION');
/**
* TODO(FW-6594): Remove this workaround when iOS 16 is no longer
* supported.
*
* If `elementsFromPoint` failed to find the active element (a known
* issue on iOS 16 when elements are in a Shadow DOM and the
* referenceNode is the document), a fallback to `elementFromPoint`
* is used. While `elementsFromPoint` returns all elements,
* `elementFromPoint` returns only the top-most, which is sufficient
* for this use case and appears to handle Shadow DOM retargeting
* more reliably in this specific iOS bug.
*/
if (newActiveElement === undefined) {
const fallbackActiveElement = referenceNode.elementFromPoint(centerX, centerY);
if ((fallbackActiveElement === null || fallbackActiveElement === void 0 ? void 0 : fallbackActiveElement.tagName) === 'ION-PICKER-COLUMN-OPTION') {
newActiveElement = fallbackActiveElement;
}
}
if (activeEl !== undefined) {
this.setPickerItemActiveState(activeEl, false);
}
if (newActiveElement === undefined || newActiveElement.disabled) {
return;
}
/**
* If we are selecting a new value,
* we need to run haptics again.
*/
if (newActiveElement !== activeEl) {
enableHaptics && hapticSelectionChanged();
if (this.canExitInputMode) {
/**
* The native iOS wheel picker
* only dismisses the keyboard
* once the selected item has changed
* as a result of a swipe
* from the user. If `canExitInputMode` is
* `false` then this means that the
* scroll is happening as a result of
* the `value` property programmatically changing
* either by an application or by the user via the keyboard.
*/
this.exitInputMode();
}
}
activeEl = newActiveElement;
this.setPickerItemActiveState(newActiveElement, true);
/**
* Set the aria-valuetext even though the value prop has not been updated yet.
* This enables some screen readers to announce the value as the users drag
* as opposed to when their release their pointer from the screen.
*
* When the value is programmatically updated, we will smoothly scroll
* to the new option. However, we do not want to update aria-valuetext mid-scroll
* as that can cause the old value to be briefly set before being set to the
* correct option. This will cause some screen readers to announce the old value
* again before announcing the new value. The correct valuetext will be set on render.
*/
if (this.updateValueTextOnScroll) {
(_a = this.assistiveFocusable) === null || _a === void 0 ? void 0 : _a.setAttribute('aria-valuetext', this.getOptionValueText(newActiveElement));
}
timeout = setTimeout(() => {
this.isScrolling = false;
this.updateValueTextOnScroll = true;
enableHaptics && hapticSelectionEnd();
/**
* Certain tasks (such as those that
* cause re-renders) should only be done
* once scrolling has finished, otherwise
* flickering may occur.
*/
const { scrollEndCallback } = this;
if (scrollEndCallback) {
scrollEndCallback();
this.scrollEndCallback = undefined;
}
/**
* Reset this flag as the
* next scroll interaction could
* be a scroll from the user. In this
* case, we should exit input mode.
*/
this.canExitInputMode = true;
this.setValue(newActiveElement.value);
}, 250);
});
};
/**
* Wrap this in an raf so that the scroll callback
* does not fire when component is initially shown.
*/
raf(() => {
if (!scrollEl)
return;
scrollEl.addEventListener('scroll', scrollCallback);
this.destroyScrollListener = () => {
scrollEl.removeEventListener('scroll', scrollCallback);
};
});
};
/**
* Tells the parent picker to
* exit text entry mode. This is only called
* when the selected item changes during scroll, so
* we know that the user likely wants to scroll
* instead of type.
*/
this.exitInputMode = () => {
const { parentEl } = this;
if (parentEl == null)
return;
parentEl.exitInputMode();
/**
* setInputModeActive only takes
* effect once scrolling stops to avoid
* a component re-render while scrolling.
* However, we want the visual active
* indicator to go away immediately, so
* we call classList.remove here.
*/
this.el.classList.remove('picker-column-active');
};
/**
* Find the next enabled option after the active option.
* @param stride - How many options to "jump" over in order to select the next option.
* This can be used to implement PageUp/PageDown behaviors where pressing these keys
* scrolls the picker by more than 1 option. For example, a stride of 5 means select
* the enabled option 5 options after the active one. Note that the actual option selected
* may be past the stride if the option at the stride is disabled.
*/
this.findNextOption = (stride = 1) => {
const { activeItem } = this;
if (!activeItem)
return null;
let prevNode = activeItem;
let node = activeItem.nextElementSibling;
while (node != null) {
if (stride > 0) {
stride--;
}
if (node.tagName === 'ION-PICKER-COLUMN-OPTION' && !node.disabled && stride === 0) {
return node;
}
prevNode = node;
// Use nextElementSibling instead of nextSibling to avoid text/comment nodes
node = node.nextElementSibling;
}
return prevNode;
};
/**
* Find the next enabled option after the active option.
* @param stride - How many options to "jump" over in order to select the next option.
* This can be used to implement PageUp/PageDown behaviors where pressing these keys
* scrolls the picker by more than 1 option. For example, a stride of 5 means select
* the enabled option 5 options before the active one. Note that the actual option selected
* may be past the stride if the option at the stride is disabled.
*/
this.findPreviousOption = (stride = 1) => {
const { activeItem } = this;
if (!activeItem)
return null;
let nextNode = activeItem;
let node = activeItem.previousElementSibling;
while (node != null) {
if (stride > 0) {
stride--;
}
if (node.tagName === 'ION-PICKER-COLUMN-OPTION' && !node.disabled && stride === 0) {
return node;
}
nextNode = node;
// Use previousElementSibling instead of previousSibling to avoid text/comment nodes
node = node.previousElementSibling;
}
return nextNode;
};
this.onKeyDown = (ev) => {
/**
* The below operations should be inverted when running on a mobile device.
* For example, swiping up will dispatch an "ArrowUp" event. On desktop,
* this should cause the previous option to be selected. On mobile, swiping
* up causes a view to scroll down. As a result, swiping up on mobile should
* cause the next option to be selected. The Home/End operations remain
* unchanged because those always represent the first/last options, respectively.
*/
const mobile = isPlatform('mobile');
let newOption = null;
switch (ev.key) {
case 'ArrowDown':
newOption = mobile ? this.findPreviousOption() : this.findNextOption();
break;
case 'ArrowUp':
newOption = mobile ? this.findNextOption() : this.findPreviousOption();
break;
case 'PageUp':
newOption = mobile ? this.findNextOption(5) : this.findPreviousOption(5);
break;
case 'PageDown':
newOption = mobile ? this.findPreviousOption(5) : this.findNextOption(5);
break;
case 'Home':
/**
* There is no guarantee that the first child will be an ion-picker-column-option,
* so we do not use firstElementChild.
*/
newOption = this.el.querySelector('ion-picker-column-option:first-of-type');
break;
case 'End':
/**
* There is no guarantee that the last child will be an ion-picker-column-option,
* so we do not use lastElementChild.
*/
newOption = this.el.querySelector('ion-picker-column-option:last-of-type');
break;
}
if (newOption !== null) {
this.setValue(newOption.value);
// This stops any default browser behavior such as scrolling
ev.preventDefault();
}
};
/**
* Utility to generate the correct text for aria-valuetext.
*/
this.getOptionValueText = (el) => {
var _a;
return el ? (_a = el.getAttribute('aria-label')) !== null && _a !== void 0 ? _a : el.innerText : '';
};
}
ariaLabelChanged(newValue) {
this.ariaLabel = newValue;
}
valueChange() {
if (this.isColumnVisible) {
/**
* Only scroll the active item into view when the picker column
* is actively visible to the user.
*/
this.scrollActiveItemIntoView(true);
}
}
/**
* Only setup scroll listeners
* when the picker is visible, otherwise
* the container will have a scroll
* height of 0px.
*/
componentWillLoad() {
/**
* We cache parentEl in a local variable
* so we don't need to keep accessing
* the class variable (which comes with
* a small performance hit)
*/
const parentEl = (this.parentEl = this.el.closest('ion-picker'));
const visibleCallback = (entries) => {
/**
* Browsers will sometimes group multiple IO events into a single callback.
* As a result, we want to grab the last/most recent event in case there are multiple events.
*/
const ev = entries[entries.length - 1];
if (ev.isIntersecting) {
const { activeItem, el } = this;
this.isColumnVisible = true;
/**
* Because this initial call to scrollActiveItemIntoView has to fire before
* the scroll listener is set up, we need to manage the active class manually.
*/
const oldActive = getElementRoot(el).querySelector(`.${PICKER_ITEM_ACTIVE_CLASS}`);
if (oldActive) {
this.setPickerItemActiveState(oldActive, false);
}
this.scrollActiveItemIntoView();
if (activeItem) {
this.setPickerItemActiveState(activeItem, true);
}
this.initializeScrollListener();
}
else {
this.isColumnVisible = false;
if (this.destroyScrollListener) {
this.destroyScrollListener();
this.destroyScrollListener = undefined;
}
}
};
/**
* Set the root to be the parent picker element
* This causes the IO callback
* to be fired in WebKit as soon as the element
* is visible. If we used the default root value
* then WebKit would only fire the IO callback
* after any animations (such as a modal transition)
* finished, and there would potentially be a flicker.
*/
new IntersectionObserver(visibleCallback, { threshold: 0.001, root: this.parentEl }).observe(this.el);
if (parentEl !== null) {
// TODO(FW-2832): type
parentEl.addEventListener('ionInputModeChange', (ev) => this.inputModeChange(ev));
}
}
componentDidRender() {
const { el, activeItem, isColumnVisible, value } = this;
if (isColumnVisible && !activeItem) {
const firstOption = el.querySelector('ion-picker-column-option');
/**
* If the picker column does not have an active item and the current value
* does not match the first item in the picker column, that means
* the value is out of bounds. In this case, we assign the value to the
* first item to match the scroll position of the column.
*
*/
if (firstOption !== null && firstOption.value !== value) {
this.setValue(firstOption.value);
}
}
}
/** @internal */
async scrollActiveItemIntoView(smooth = false) {
const activeEl = this.activeItem;
if (activeEl) {
this.centerPickerItemInView(activeEl, smooth, false);
}
}
/**
* Sets the value prop and fires the ionChange event.
* This is used when we need to fire ionChange from
* user-generated events that cannot be caught with normal
* input/change event listeners.
* @internal
*/
async setValue(value) {
if (this.disabled === true || this.value === value) {
return;
}
this.value = value;
this.ionChange.emit({ value });
}
/**
* Sets focus on the scrollable container within the picker column.
* Use this method instead of the global `pickerColumn.focus()`.
*/
async setFocus() {
if (this.assistiveFocusable) {
this.assistiveFocusable.focus();
}
}
connectedCallback() {
var _a;
this.ariaLabel = (_a = this.el.getAttribute('aria-label')) !== null && _a !== void 0 ? _a : 'Select a value';
}
get activeItem() {
const { value } = this;
const options = Array.from(this.el.querySelectorAll('ion-picker-column-option'));
return options.find((option) => {
/**
* If the whole picker column is disabled, the current value should appear active
* If the current value item is specifically disabled, it should not appear active
*/
if (!this.disabled && option.disabled) {
return false;
}
return option.value === value;
});
}
render() {
const { color, disabled, isActive, numericInput } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'db903fd415f8a2d91994dececca481c1af8ba6a9', class: createColorClasses$1(color, {
[mode]: true,
['picker-column-active']: isActive,
['picker-column-numeric-input']: numericInput,
['picker-column-disabled']: disabled,
}) }, hAsync("slot", { key: '02ce9e1dd7df91afcd50b06416552bcffb5dec98', name: "prefix" }), hAsync("div", { key: '6dfd7d2429bec19244a6b1afb4448121963a031b', class: "picker-opts", ref: (el) => {
this.scrollEl = el;
}, role: "slider", tabindex: this.disabled ? undefined : 0, "aria-label": this.ariaLabel, "aria-valuemin": 0, "aria-valuemax": 0, "aria-valuenow": 0, "aria-valuetext": this.getOptionValueText(this.activeItem), "aria-orientation": "vertical", onKeyDown: (ev) => this.onKeyDown(ev) }, hAsync("div", { key: 'e30ce0b9cefbfe4d4441fa33acf595da31855c3f', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), hAsync("div", { key: '8be2bd293c12c6ba720d9b31d0d561a96f42e97d', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), hAsync("div", { key: '8afdcddddabbf646fbb55cb0ba4448309a2c1dd9', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), hAsync("slot", { key: '6aa0dacc34d6848575ad5b122b9046982308ca43' }), hAsync("div", { key: '92ec8a357414c1b779b11d1dd18fb87a7ee63982', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), hAsync("div", { key: 'b89457cb74b5907c25594ff6720ac54ca537e933', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0"), hAsync("div", { key: '5bbc92e6bc24de08e39873bf08c5b668373ac0f8', class: "picker-item-empty", "aria-hidden": "true" }, "\u00A0")), hAsync("slot", { key: 'd7bf2b519214f0f3576a4ca79844ad97827dd97f', name: "suffix" })));
}
get el() { return getElement(this); }
static get watchers() { return {
"aria-label": ["ariaLabelChanged"],
"value": ["valueChange"]
}; }
static get style() { return pickerColumnCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-picker-column",
"$members$": {
"disabled": [4],
"value": [1032],
"color": [513],
"numericInput": [4, "numeric-input"],
"ariaLabel": [32],
"isActive": [32],
"scrollActiveItemIntoView": [64],
"setValue": [64],
"setFocus": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const PICKER_ITEM_ACTIVE_CLASS = 'option-active';
const pickerColumnIosCss = ".picker-col{display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-pack:center;justify-content:center;height:100%;-webkit-box-sizing:content-box;box-sizing:content-box;contain:content}.picker-opts{position:relative;-ms-flex:1;flex:1;max-width:100%}.picker-opt{top:0;display:block;position:absolute;width:100%;border:0;text-align:center;text-overflow:ellipsis;white-space:nowrap;contain:strict;overflow:hidden;will-change:transform}.picker-opt{inset-inline-start:0}.picker-opt.picker-opt-disabled{pointer-events:none}.picker-opt-disabled{opacity:0}.picker-opts-left{-ms-flex-pack:start;justify-content:flex-start}.picker-opts-right{-ms-flex-pack:end;justify-content:flex-end}.picker-opt:active,.picker-opt:focus{outline:none}.picker-prefix{position:relative;-ms-flex:1;flex:1;text-align:end;white-space:nowrap}.picker-suffix{position:relative;-ms-flex:1;flex:1;text-align:start;white-space:nowrap}.picker-col{-webkit-padding-start:4px;padding-inline-start:4px;-webkit-padding-end:4px;padding-inline-end:4px;padding-top:0;padding-bottom:0;-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.picker-prefix,.picker-suffix,.picker-opts{top:77px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;color:inherit;font-size:20px;line-height:42px;pointer-events:none}.picker-opt{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-transform-origin:center center;transform-origin:center center;height:46px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;background:transparent;color:inherit;font-size:20px;line-height:42px;-webkit-backface-visibility:hidden;backface-visibility:hidden;pointer-events:auto}:host-context([dir=rtl]) .picker-opt{-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}[dir=rtl] .picker-opt{-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}@supports selector(:dir(rtl)){.picker-opt:dir(rtl){-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}}";
const pickerColumnMdCss = ".picker-col{display:-ms-flexbox;display:flex;position:relative;-ms-flex:1;flex:1;-ms-flex-pack:center;justify-content:center;height:100%;-webkit-box-sizing:content-box;box-sizing:content-box;contain:content}.picker-opts{position:relative;-ms-flex:1;flex:1;max-width:100%}.picker-opt{top:0;display:block;position:absolute;width:100%;border:0;text-align:center;text-overflow:ellipsis;white-space:nowrap;contain:strict;overflow:hidden;will-change:transform}.picker-opt{inset-inline-start:0}.picker-opt.picker-opt-disabled{pointer-events:none}.picker-opt-disabled{opacity:0}.picker-opts-left{-ms-flex-pack:start;justify-content:flex-start}.picker-opts-right{-ms-flex-pack:end;justify-content:flex-end}.picker-opt:active,.picker-opt:focus{outline:none}.picker-prefix{position:relative;-ms-flex:1;flex:1;text-align:end;white-space:nowrap}.picker-suffix{position:relative;-ms-flex:1;flex:1;text-align:start;white-space:nowrap}.picker-col{-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:0;padding-bottom:0;-webkit-transform-style:preserve-3d;transform-style:preserve-3d}.picker-prefix,.picker-suffix,.picker-opts{top:77px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;color:inherit;font-size:22px;line-height:42px;pointer-events:none}.picker-opt{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;height:43px;-webkit-transition-timing-function:ease-out;transition-timing-function:ease-out;background:transparent;color:inherit;font-size:22px;line-height:42px;-webkit-backface-visibility:hidden;backface-visibility:hidden;pointer-events:auto}.picker-prefix,.picker-suffix,.picker-opt.picker-opt-selected{color:var(--ion-color-primary, #0054e9)}";
/**
* @internal
*/
class PickerColumnCmp {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionPickerColChange = createEvent(this, "ionPickerColChange", 7);
this.optHeight = 0;
this.rotateFactor = 0;
this.scaleFactor = 1;
this.velocity = 0;
this.y = 0;
this.noAnimate = true;
// `colDidChange` is a flag that gets set when the column is changed
// dynamically. When this flag is set, the column will refresh
// after the component re-renders to incorporate the new column data.
// This is necessary because `this.refresh` queries for the option elements,
// so it needs to wait for the latest elements to be available in the DOM.
// Ex: column is created with 3 options. User updates the column data
// to have 5 options. The column will still think it only has 3 options.
this.colDidChange = false;
}
colChanged() {
this.colDidChange = true;
}
async connectedCallback() {
let pickerRotateFactor = 0;
let pickerScaleFactor = 0.81;
const mode = getIonMode$1(this);
if (mode === 'ios') {
pickerRotateFactor = -0.46;
pickerScaleFactor = 1;
}
this.rotateFactor = pickerRotateFactor;
this.scaleFactor = pickerScaleFactor;
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: this.el,
gestureName: 'picker-swipe',
gesturePriority: 100,
threshold: 0,
passive: false,
onStart: (ev) => this.onStart(ev),
onMove: (ev) => this.onMove(ev),
onEnd: (ev) => this.onEnd(ev),
});
this.gesture.enable();
// Options have not been initialized yet
// Animation must be disabled through the `noAnimate` flag
// Otherwise, the options will render
// at the top of the column and transition down
this.tmrId = setTimeout(() => {
this.noAnimate = false;
// After initialization, `refresh()` will be called
// At this point, animation will be enabled. The options will
// animate as they are being selected.
this.refresh(true);
}, 250);
}
componentDidLoad() {
this.onDomChange();
}
componentDidUpdate() {
// Options may have changed since last update.
if (this.colDidChange) {
// Animation must be disabled through the `onDomChange` parameter.
// Otherwise, the recently added options will render
// at the top of the column and transition down
this.onDomChange(true, false);
this.colDidChange = false;
}
}
disconnectedCallback() {
if (this.rafId !== undefined)
cancelAnimationFrame(this.rafId);
if (this.tmrId)
clearTimeout(this.tmrId);
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
emitColChange() {
this.ionPickerColChange.emit(this.col);
}
setSelected(selectedIndex, duration) {
// if there is a selected index, then figure out it's y position
// if there isn't a selected index, then just use the top y position
const y = selectedIndex > -1 ? -(selectedIndex * this.optHeight) : 0;
this.velocity = 0;
// set what y position we're at
if (this.rafId !== undefined)
cancelAnimationFrame(this.rafId);
this.update(y, duration, true);
this.emitColChange();
}
update(y, duration, saveY) {
if (!this.optsEl) {
return;
}
// ensure we've got a good round number :)
let translateY = 0;
let translateZ = 0;
const { col, rotateFactor } = this;
const prevSelected = col.selectedIndex;
const selectedIndex = (col.selectedIndex = this.indexForY(-y));
const durationStr = duration === 0 ? '' : duration + 'ms';
const scaleStr = `scale(${this.scaleFactor})`;
const children = this.optsEl.children;
for (let i = 0; i < children.length; i++) {
const button = children[i];
const opt = col.options[i];
const optOffset = i * this.optHeight + y;
let transform = '';
if (rotateFactor !== 0) {
const rotateX = optOffset * rotateFactor;
if (Math.abs(rotateX) <= 90) {
translateY = 0;
translateZ = 90;
transform = `rotateX(${rotateX}deg) `;
}
else {
translateY = -9999;
}
}
else {
translateZ = 0;
translateY = optOffset;
}
const selected = selectedIndex === i;
transform += `translate3d(0px,${translateY}px,${translateZ}px) `;
if (this.scaleFactor !== 1 && !selected) {
transform += scaleStr;
}
// Update transition duration
if (this.noAnimate) {
opt.duration = 0;
button.style.transitionDuration = '';
}
else if (duration !== opt.duration) {
opt.duration = duration;
button.style.transitionDuration = durationStr;
}
// Update transform
if (transform !== opt.transform) {
opt.transform = transform;
}
button.style.transform = transform;
/**
* Ensure that the select column
* item has the selected class
*/
opt.selected = selected;
if (selected) {
button.classList.add(PICKER_OPT_SELECTED);
}
else {
button.classList.remove(PICKER_OPT_SELECTED);
}
}
this.col.prevSelected = prevSelected;
if (saveY) {
this.y = y;
}
if (this.lastIndex !== selectedIndex) {
// have not set a last index yet
hapticSelectionChanged();
this.lastIndex = selectedIndex;
}
}
decelerate() {
if (this.velocity !== 0) {
// still decelerating
this.velocity *= DECELERATION_FRICTION;
// do not let it go slower than a velocity of 1
this.velocity = this.velocity > 0 ? Math.max(this.velocity, 1) : Math.min(this.velocity, -1);
let y = this.y + this.velocity;
if (y > this.minY) {
// whoops, it's trying to scroll up farther than the options we have!
y = this.minY;
this.velocity = 0;
}
else if (y < this.maxY) {
// gahh, it's trying to scroll down farther than we can!
y = this.maxY;
this.velocity = 0;
}
this.update(y, 0, true);
const notLockedIn = Math.round(y) % this.optHeight !== 0 || Math.abs(this.velocity) > 1;
if (notLockedIn) {
// isn't locked in yet, keep decelerating until it is
this.rafId = requestAnimationFrame(() => this.decelerate());
}
else {
this.velocity = 0;
this.emitColChange();
hapticSelectionEnd();
}
}
else if (this.y % this.optHeight !== 0) {
// needs to still get locked into a position so options line up
const currentPos = Math.abs(this.y % this.optHeight);
// create a velocity in the direction it needs to scroll
this.velocity = currentPos > this.optHeight / 2 ? 1 : -1;
this.decelerate();
}
}
indexForY(y) {
return Math.min(Math.max(Math.abs(Math.round(y / this.optHeight)), 0), this.col.options.length - 1);
}
onStart(detail) {
// We have to prevent default in order to block scrolling under the picker
// but we DO NOT have to stop propagation, since we still want
// some "click" events to capture
if (detail.event.cancelable) {
detail.event.preventDefault();
}
detail.event.stopPropagation();
hapticSelectionStart();
// reset everything
if (this.rafId !== undefined)
cancelAnimationFrame(this.rafId);
const options = this.col.options;
let minY = options.length - 1;
let maxY = 0;
for (let i = 0; i < options.length; i++) {
if (!options[i].disabled) {
minY = Math.min(minY, i);
maxY = Math.max(maxY, i);
}
}
this.minY = -(minY * this.optHeight);
this.maxY = -(maxY * this.optHeight);
}
onMove(detail) {
if (detail.event.cancelable) {
detail.event.preventDefault();
}
detail.event.stopPropagation();
// update the scroll position relative to pointer start position
let y = this.y + detail.deltaY;
if (y > this.minY) {
// scrolling up higher than scroll area
y = Math.pow(y, 0.8);
this.bounceFrom = y;
}
else if (y < this.maxY) {
// scrolling down below scroll area
y += Math.pow(this.maxY - y, 0.9);
this.bounceFrom = y;
}
else {
this.bounceFrom = 0;
}
this.update(y, 0, false);
}
onEnd(detail) {
if (this.bounceFrom > 0) {
// bounce back up
this.update(this.minY, 100, true);
this.emitColChange();
return;
}
else if (this.bounceFrom < 0) {
// bounce back down
this.update(this.maxY, 100, true);
this.emitColChange();
return;
}
this.velocity = clamp(-90, detail.velocityY * 23, MAX_PICKER_SPEED);
if (this.velocity === 0 && detail.deltaY === 0) {
const opt = detail.event.target.closest('.picker-opt');
if (opt === null || opt === void 0 ? void 0 : opt.hasAttribute('opt-index')) {
this.setSelected(parseInt(opt.getAttribute('opt-index'), 10), TRANSITION_DURATION);
}
}
else {
this.y += detail.deltaY;
if (Math.abs(detail.velocityY) < 0.05) {
const isScrollingUp = detail.deltaY > 0;
const optHeightFraction = (Math.abs(this.y) % this.optHeight) / this.optHeight;
if (isScrollingUp && optHeightFraction > 0.5) {
this.velocity = Math.abs(this.velocity) * -1;
}
else if (!isScrollingUp && optHeightFraction <= 0.5) {
this.velocity = Math.abs(this.velocity);
}
}
this.decelerate();
}
}
refresh(forceRefresh, animated) {
var _a;
let min = this.col.options.length - 1;
let max = 0;
const options = this.col.options;
for (let i = 0; i < options.length; i++) {
if (!options[i].disabled) {
min = Math.min(min, i);
max = Math.max(max, i);
}
}
/**
* Only update selected value if column has a
* velocity of 0. If it does not, then the
* column is animating might land on
* a value different than the value at
* selectedIndex
*/
if (this.velocity !== 0) {
return;
}
const selectedIndex = clamp(min, (_a = this.col.selectedIndex) !== null && _a !== void 0 ? _a : 0, max);
if (this.col.prevSelected !== selectedIndex || forceRefresh) {
const y = selectedIndex * this.optHeight * -1;
const duration = animated ? TRANSITION_DURATION : 0;
this.velocity = 0;
this.update(y, duration, true);
}
}
onDomChange(forceRefresh, animated) {
const colEl = this.optsEl;
if (colEl) {
// DOM READ
// We perfom a DOM read over a rendered item, this needs to happen after the first render or after the column has changed
this.optHeight = colEl.firstElementChild ? colEl.firstElementChild.clientHeight : 0;
}
this.refresh(forceRefresh, animated);
}
render() {
const col = this.col;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'ed32d108dd94f0302fb453c31a3497ebae65ec37', class: Object.assign({ [mode]: true, 'picker-col': true, 'picker-opts-left': this.col.align === 'left', 'picker-opts-right': this.col.align === 'right' }, getClassMap(col.cssClass)), style: {
'max-width': this.col.columnWidth,
} }, col.prefix && (hAsync("div", { key: '9f0634890e66fd4ae74f826d1eea3431de121393', class: "picker-prefix", style: { width: col.prefixWidth } }, col.prefix)), hAsync("div", { key: '337e996e5be91af16446085fe22436f213b771eb', class: "picker-opts", style: { maxWidth: col.optionsWidth }, ref: (el) => (this.optsEl = el) }, col.options.map((o, index) => (hAsync("button", { "aria-label": o.ariaLabel, class: { 'picker-opt': true, 'picker-opt-disabled': !!o.disabled }, "opt-index": index }, o.text)))), col.suffix && (hAsync("div", { key: 'd69a132599d78d9e5107f12228978cfce4e43098', class: "picker-suffix", style: { width: col.suffixWidth } }, col.suffix))));
}
get el() { return getElement(this); }
static get watchers() { return {
"col": ["colChanged"]
}; }
static get style() { return {
ios: pickerColumnIosCss,
md: pickerColumnMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-picker-legacy-column",
"$members$": {
"col": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const PICKER_OPT_SELECTED = 'picker-opt-selected';
const DECELERATION_FRICTION = 0.97;
const MAX_PICKER_SPEED = 90;
const TRANSITION_DURATION = 150;
const pickerColumnOptionIosCss = ".picker-column-option-button{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;width:100%;height:34px;border:0px;outline:none;background:transparent;color:inherit;font-family:var(--ion-font-family, inherit);font-size:inherit;line-height:34px;text-align:inherit;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;overflow:hidden}:host(.option-disabled){opacity:0.4}:host(.option-disabled) .picker-column-option-button{cursor:default}";
const pickerColumnOptionMdCss = ".picker-column-option-button{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;width:100%;height:34px;border:0px;outline:none;background:transparent;color:inherit;font-family:var(--ion-font-family, inherit);font-size:inherit;line-height:34px;text-align:inherit;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;overflow:hidden}:host(.option-disabled){opacity:0.4}:host(.option-disabled) .picker-column-option-button{cursor:default}:host(.option-active){color:var(--ion-color-base)}";
class PickerColumnOption {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* We keep track of the parent picker column
* so we can update the value of it when
* clicking an enable option.
*/
this.pickerColumn = null;
/**
* The aria-label of the option.
*
* If the value changes, then it will trigger a
* re-render of the picker since it's a @State variable.
* Otherwise, the `aria-label` attribute cannot be updated
* after the component is loaded.
*/
this.ariaLabel = null;
/**
* If `true`, the user cannot interact with the picker column option.
*/
this.disabled = false;
/**
* The color to use from your application's color palette.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information on colors, see [theming](/docs/theming/basics).
*/
this.color = 'primary';
}
/**
* The aria-label of the option has changed after the
* first render and needs to be updated within the component.
*
* @param ariaLbl The new aria-label value.
*/
onAriaLabelChange(ariaLbl) {
this.ariaLabel = ariaLbl;
}
componentWillLoad() {
const inheritedAttributes = inheritAttributes$1(this.el, ['aria-label']);
/**
* The initial value of `aria-label` needs to be set for
* the first render.
*/
this.ariaLabel = inheritedAttributes['aria-label'] || null;
}
connectedCallback() {
this.pickerColumn = this.el.closest('ion-picker-column');
}
disconnectedCallback() {
this.pickerColumn = null;
}
/**
* The column options can load at any time
* so the options needs to tell the
* parent picker column when it is loaded
* so the picker column can ensure it is
* centered in the view.
*
* We intentionally run this for every
* option. If we only ran this from
* the selected option then if the newly
* loaded options were not selected then
* scrollActiveItemIntoView would not be called.
*/
componentDidLoad() {
const { pickerColumn } = this;
if (pickerColumn !== null) {
pickerColumn.scrollActiveItemIntoView();
}
}
/**
* When an option is clicked, update the
* parent picker column value. This
* component will handle centering the option
* in the column view.
*/
onClick() {
const { pickerColumn } = this;
if (pickerColumn !== null) {
pickerColumn.setValue(this.value);
}
}
render() {
const { color, disabled, ariaLabel } = this;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'f816729941aabcb31ddfdce3ffe2e2139030d715', class: createColorClasses$1(color, {
[mode]: true,
['option-disabled']: disabled,
}) }, hAsync("div", { key: 'd942de84fd14d7dc06b1e5cf4f7920d1dc3c6371', class: 'picker-column-option-button', role: "button", "aria-label": ariaLabel, onClick: () => this.onClick() }, hAsync("slot", { key: 'b0df5717b42209e649097209a01476e1a66f5c5c' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"aria-label": ["onAriaLabelChange"]
}; }
static get style() { return {
ios: pickerColumnOptionIosCss,
md: pickerColumnOptionMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-picker-column-option",
"$members$": {
"disabled": [4],
"value": [8],
"color": [513],
"ariaLabel": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
/**
* Returns the dimensions of the popover
* arrow on `ios` mode. If arrow is disabled
* returns (0, 0).
*/
const getArrowDimensions = (arrowEl) => {
if (!arrowEl) {
return { arrowWidth: 0, arrowHeight: 0 };
}
const { width, height } = arrowEl.getBoundingClientRect();
return { arrowWidth: width, arrowHeight: height };
};
/**
* Returns the recommended dimensions of the popover
* that takes into account whether or not the width
* should match the trigger width.
*/
const getPopoverDimensions = (size, contentEl, triggerEl) => {
const contentDimentions = contentEl.getBoundingClientRect();
const contentHeight = contentDimentions.height;
let contentWidth = contentDimentions.width;
if (size === 'cover' && triggerEl) {
const triggerDimensions = triggerEl.getBoundingClientRect();
contentWidth = triggerDimensions.width;
}
return {
contentWidth,
contentHeight,
};
};
const configureDismissInteraction = (triggerEl, triggerAction, popoverEl, parentPopoverEl) => {
let dismissCallbacks = [];
const root = getElementRoot(parentPopoverEl);
const parentContentEl = root.querySelector('.popover-content');
switch (triggerAction) {
case 'hover':
dismissCallbacks = [
{
/**
* Do not use mouseover here
* as this will causes the event to
* be dispatched on each underlying
* element rather than on the popover
* content as a whole.
*/
eventName: 'mouseenter',
callback: (ev) => {
/**
* Do not dismiss the popover is we
* are hovering over its trigger.
* This would be easier if we used mouseover
* but this would cause the event to be dispatched
* more often than we would like, potentially
* causing performance issues.
*/
const element = document.elementFromPoint(ev.clientX, ev.clientY);
if (element === triggerEl) {
return;
}
popoverEl.dismiss(undefined, undefined, false);
},
},
];
break;
case 'context-menu':
case 'click':
default:
dismissCallbacks = [
{
eventName: 'click',
callback: (ev) => {
/**
* Do not dismiss the popover is we
* are hovering over its trigger.
*/
const target = ev.target;
const closestTrigger = target.closest('[data-ion-popover-trigger]');
if (closestTrigger === triggerEl) {
/**
* stopPropagation here so if the
* popover has dismissOnSelect="true"
* the popover does not dismiss since
* we just clicked a trigger element.
*/
ev.stopPropagation();
return;
}
popoverEl.dismiss(undefined, undefined, false);
},
},
];
break;
}
dismissCallbacks.forEach(({ eventName, callback }) => parentContentEl.addEventListener(eventName, callback));
return () => {
dismissCallbacks.forEach(({ eventName, callback }) => parentContentEl.removeEventListener(eventName, callback));
};
};
/**
* Configures the triggerEl to respond
* to user interaction based upon the triggerAction
* prop that devs have defined.
*/
const configureTriggerInteraction = (triggerEl, triggerAction, popoverEl) => {
let triggerCallbacks = [];
/**
* Based upon the kind of trigger interaction
* the user wants, we setup the correct event
* listeners.
*/
switch (triggerAction) {
case 'hover':
let hoverTimeout;
triggerCallbacks = [
{
eventName: 'mouseenter',
callback: async (ev) => {
ev.stopPropagation();
if (hoverTimeout) {
clearTimeout(hoverTimeout);
}
/**
* Hovering over a trigger should not
* immediately open the next popover.
*/
hoverTimeout = setTimeout(() => {
raf(() => {
popoverEl.presentFromTrigger(ev);
hoverTimeout = undefined;
});
}, 100);
},
},
{
eventName: 'mouseleave',
callback: (ev) => {
if (hoverTimeout) {
clearTimeout(hoverTimeout);
}
/**
* If mouse is over another popover
* that is not this popover then we should
* close this popover.
*/
const target = ev.relatedTarget;
if (!target) {
return;
}
if (target.closest('ion-popover') !== popoverEl) {
popoverEl.dismiss(undefined, undefined, false);
}
},
},
{
/**
* stopPropagation here prevents the popover
* from dismissing when dismiss-on-select="true".
*/
eventName: 'click',
callback: (ev) => ev.stopPropagation(),
},
{
eventName: 'ionPopoverActivateTrigger',
callback: (ev) => popoverEl.presentFromTrigger(ev, true),
},
];
break;
case 'context-menu':
triggerCallbacks = [
{
eventName: 'contextmenu',
callback: (ev) => {
/**
* Prevents the platform context
* menu from appearing.
*/
ev.preventDefault();
popoverEl.presentFromTrigger(ev);
},
},
{
eventName: 'click',
callback: (ev) => ev.stopPropagation(),
},
{
eventName: 'ionPopoverActivateTrigger',
callback: (ev) => popoverEl.presentFromTrigger(ev, true),
},
];
break;
case 'click':
default:
triggerCallbacks = [
{
/**
* Do not do a stopPropagation() here
* because if you had two click triggers
* then clicking the first trigger and then
* clicking the second trigger would not cause
* the first popover to dismiss.
*/
eventName: 'click',
callback: (ev) => popoverEl.presentFromTrigger(ev),
},
{
eventName: 'ionPopoverActivateTrigger',
callback: (ev) => popoverEl.presentFromTrigger(ev, true),
},
];
break;
}
triggerCallbacks.forEach(({ eventName, callback }) => triggerEl.addEventListener(eventName, callback));
triggerEl.setAttribute('data-ion-popover-trigger', 'true');
return () => {
triggerCallbacks.forEach(({ eventName, callback }) => triggerEl.removeEventListener(eventName, callback));
triggerEl.removeAttribute('data-ion-popover-trigger');
};
};
/**
* Returns the index of an ion-item in an array of ion-items.
*/
const getIndexOfItem = (items, item) => {
if (!item || item.tagName !== 'ION-ITEM') {
return -1;
}
return items.findIndex((el) => el === item);
};
/**
* Given an array of elements and a currently focused ion-item
* returns the next ion-item relative to the focused one or
* undefined.
*/
const getNextItem = (items, currentItem) => {
const currentItemIndex = getIndexOfItem(items, currentItem);
return items[currentItemIndex + 1];
};
/**
* Given an array of elements and a currently focused ion-item
* returns the previous ion-item relative to the focused one or
* undefined.
*/
const getPrevItem = (items, currentItem) => {
const currentItemIndex = getIndexOfItem(items, currentItem);
return items[currentItemIndex - 1];
};
/** Focus the internal button of the ion-item */
const focusItem = (item) => {
const root = getElementRoot(item);
const button = root.querySelector('button');
if (button) {
raf(() => button.focus());
}
};
/**
* Returns `true` if `el` has been designated
* as a trigger element for an ion-popover.
*/
const isTriggerElement = (el) => el.hasAttribute('data-ion-popover-trigger');
const configureKeyboardInteraction = (popoverEl) => {
const callback = async (ev) => {
var _a;
const activeElement = document.activeElement;
let items = [];
const targetTagName = (_a = ev.target) === null || _a === void 0 ? void 0 : _a.tagName;
/**
* Only handle custom keyboard interactions for the host popover element
* and children ion-item elements.
*/
if (targetTagName !== 'ION-POPOVER' && targetTagName !== 'ION-ITEM') {
return;
}
/**
* Complex selectors with :not() are :not supported
* in older versions of Chromium so we need to do a
* try/catch here so errors are not thrown.
*/
try {
/**
* Select all ion-items that are not children of child popovers.
* i.e. only select ion-item elements that are part of this popover
*/
items = Array.from(popoverEl.querySelectorAll('ion-item:not(ion-popover ion-popover *):not([disabled])'));
/* eslint-disable-next-line */
}
catch (_b) { }
switch (ev.key) {
/**
* If we are in a child popover
* then pressing the left arrow key
* should close this popover and move
* focus to the popover that presented
* this one.
*/
case 'ArrowLeft':
const parentPopover = await popoverEl.getParentPopover();
if (parentPopover) {
popoverEl.dismiss(undefined, undefined, false);
}
break;
/**
* ArrowDown should move focus to the next focusable ion-item.
*/
case 'ArrowDown':
// Disable movement/scroll with keyboard
ev.preventDefault();
const nextItem = getNextItem(items, activeElement);
if (nextItem !== undefined) {
focusItem(nextItem);
}
break;
/**
* ArrowUp should move focus to the previous focusable ion-item.
*/
case 'ArrowUp':
// Disable movement/scroll with keyboard
ev.preventDefault();
const prevItem = getPrevItem(items, activeElement);
if (prevItem !== undefined) {
focusItem(prevItem);
}
break;
/**
* Home should move focus to the first focusable ion-item.
*/
case 'Home':
ev.preventDefault();
const firstItem = items[0];
if (firstItem !== undefined) {
focusItem(firstItem);
}
break;
/**
* End should move focus to the last focusable ion-item.
*/
case 'End':
ev.preventDefault();
const lastItem = items[items.length - 1];
if (lastItem !== undefined) {
focusItem(lastItem);
}
break;
/**
* ArrowRight, Spacebar, or Enter should activate
* the currently focused trigger item to open a
* popover if the element is a trigger item.
*/
case 'ArrowRight':
case ' ':
case 'Enter':
if (activeElement && isTriggerElement(activeElement)) {
const rightEvent = new CustomEvent('ionPopoverActivateTrigger');
activeElement.dispatchEvent(rightEvent);
}
break;
}
};
popoverEl.addEventListener('keydown', callback);
return () => popoverEl.removeEventListener('keydown', callback);
};
/**
* Positions a popover by taking into account
* the reference point, preferred side, alignment
* and viewport dimensions.
*/
const getPopoverPosition = (isRTL, contentWidth, contentHeight, arrowWidth, arrowHeight, reference, side, align, defaultPosition, triggerEl, event) => {
var _a;
let referenceCoordinates = {
top: 0,
left: 0,
width: 0,
height: 0,
};
/**
* Calculate position relative to the
* x-y coordinates in the event that
* was passed in
*/
switch (reference) {
case 'event':
if (!event) {
return defaultPosition;
}
const mouseEv = event;
referenceCoordinates = {
top: mouseEv.clientY,
left: mouseEv.clientX,
width: 1,
height: 1,
};
break;
/**
* Calculate position relative to the bounding
* box on either the trigger element
* specified via the `trigger` prop or
* the target specified on the event
* that was passed in.
*/
case 'trigger':
default:
const customEv = event;
/**
* ionShadowTarget is used when we need to align the
* popover with an element inside of the shadow root
* of an Ionic component. Ex: Presenting a popover
* by clicking on the collapsed indicator inside
* of `ion-breadcrumb` and centering it relative
* to the indicator rather than `ion-breadcrumb`
* as a whole.
*/
const actualTriggerEl = (triggerEl ||
((_a = customEv === null || customEv === void 0 ? void 0 : customEv.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) ||
(customEv === null || customEv === void 0 ? void 0 : customEv.target));
if (!actualTriggerEl) {
return defaultPosition;
}
const triggerBoundingBox = actualTriggerEl.getBoundingClientRect();
referenceCoordinates = {
top: triggerBoundingBox.top,
left: triggerBoundingBox.left,
width: triggerBoundingBox.width,
height: triggerBoundingBox.height,
};
break;
}
/**
* Get top/left offset that would allow
* popover to be positioned on the
* preferred side of the reference.
*/
const coordinates = calculatePopoverSide(side, referenceCoordinates, contentWidth, contentHeight, arrowWidth, arrowHeight, isRTL);
/**
* Get the top/left adjustments that
* would allow the popover content
* to have the correct alignment.
*/
const alignedCoordinates = calculatePopoverAlign(align, side, referenceCoordinates, contentWidth, contentHeight);
const top = coordinates.top + alignedCoordinates.top;
const left = coordinates.left + alignedCoordinates.left;
const { arrowTop, arrowLeft } = calculateArrowPosition(side, arrowWidth, arrowHeight, top, left, contentWidth, contentHeight, isRTL);
const { originX, originY } = calculatePopoverOrigin(side, align, isRTL);
return { top, left, referenceCoordinates, arrowTop, arrowLeft, originX, originY };
};
/**
* Determines the transform-origin
* of the popover animation so that it
* is in line with what the side and alignment
* prop values are. Currently only used
* with the MD animation.
*/
const calculatePopoverOrigin = (side, align, isRTL) => {
switch (side) {
case 'top':
return { originX: getOriginXAlignment(align), originY: 'bottom' };
case 'bottom':
return { originX: getOriginXAlignment(align), originY: 'top' };
case 'left':
return { originX: 'right', originY: getOriginYAlignment(align) };
case 'right':
return { originX: 'left', originY: getOriginYAlignment(align) };
case 'start':
return { originX: isRTL ? 'left' : 'right', originY: getOriginYAlignment(align) };
case 'end':
return { originX: isRTL ? 'right' : 'left', originY: getOriginYAlignment(align) };
}
};
const getOriginXAlignment = (align) => {
switch (align) {
case 'start':
return 'left';
case 'center':
return 'center';
case 'end':
return 'right';
}
};
const getOriginYAlignment = (align) => {
switch (align) {
case 'start':
return 'top';
case 'center':
return 'center';
case 'end':
return 'bottom';
}
};
/**
* Calculates where the arrow positioning
* should be relative to the popover content.
*/
const calculateArrowPosition = (side, arrowWidth, arrowHeight, top, left, contentWidth, contentHeight, isRTL) => {
/**
* Note: When side is left, right, start, or end, the arrow is
* been rotated using a `transform`, so to move the arrow up or down
* by its dimension, you need to use `arrowWidth`.
*/
const leftPosition = {
arrowTop: top + contentHeight / 2 - arrowWidth / 2,
arrowLeft: left + contentWidth - arrowWidth / 2,
};
/**
* Move the arrow to the left by arrowWidth and then
* again by half of its width because we have rotated
* the arrow using a transform.
*/
const rightPosition = { arrowTop: top + contentHeight / 2 - arrowWidth / 2, arrowLeft: left - arrowWidth * 1.5 };
switch (side) {
case 'top':
return { arrowTop: top + contentHeight, arrowLeft: left + contentWidth / 2 - arrowWidth / 2 };
case 'bottom':
return { arrowTop: top - arrowHeight, arrowLeft: left + contentWidth / 2 - arrowWidth / 2 };
case 'left':
return leftPosition;
case 'right':
return rightPosition;
case 'start':
return isRTL ? rightPosition : leftPosition;
case 'end':
return isRTL ? leftPosition : rightPosition;
default:
return { arrowTop: 0, arrowLeft: 0 };
}
};
/**
* Calculates the required top/left
* values needed to position the popover
* content on the side specified in the
* `side` prop.
*/
const calculatePopoverSide = (side, triggerBoundingBox, contentWidth, contentHeight, arrowWidth, arrowHeight, isRTL) => {
const sideLeft = {
top: triggerBoundingBox.top,
left: triggerBoundingBox.left - contentWidth - arrowWidth,
};
const sideRight = {
top: triggerBoundingBox.top,
left: triggerBoundingBox.left + triggerBoundingBox.width + arrowWidth,
};
switch (side) {
case 'top':
return {
top: triggerBoundingBox.top - contentHeight - arrowHeight,
left: triggerBoundingBox.left,
};
case 'right':
return sideRight;
case 'bottom':
return {
top: triggerBoundingBox.top + triggerBoundingBox.height + arrowHeight,
left: triggerBoundingBox.left,
};
case 'left':
return sideLeft;
case 'start':
return isRTL ? sideRight : sideLeft;
case 'end':
return isRTL ? sideLeft : sideRight;
}
};
/**
* Calculates the required top/left
* offset values needed to provide the
* correct alignment regardless while taking
* into account the side the popover is on.
*/
const calculatePopoverAlign = (align, side, triggerBoundingBox, contentWidth, contentHeight) => {
switch (align) {
case 'center':
return calculatePopoverCenterAlign(side, triggerBoundingBox, contentWidth, contentHeight);
case 'end':
return calculatePopoverEndAlign(side, triggerBoundingBox, contentWidth, contentHeight);
case 'start':
default:
return { top: 0, left: 0 };
}
};
/**
* Calculate the end alignment for
* the popover. If side is on the x-axis
* then the align values refer to the top
* and bottom margins of the content.
* If side is on the y-axis then the
* align values refer to the left and right
* margins of the content.
*/
const calculatePopoverEndAlign = (side, triggerBoundingBox, contentWidth, contentHeight) => {
switch (side) {
case 'start':
case 'end':
case 'left':
case 'right':
return {
top: -(contentHeight - triggerBoundingBox.height),
left: 0,
};
case 'top':
case 'bottom':
default:
return {
top: 0,
left: -(contentWidth - triggerBoundingBox.width),
};
}
};
/**
* Calculate the center alignment for
* the popover. If side is on the x-axis
* then the align values refer to the top
* and bottom margins of the content.
* If side is on the y-axis then the
* align values refer to the left and right
* margins of the content.
*/
const calculatePopoverCenterAlign = (side, triggerBoundingBox, contentWidth, contentHeight) => {
switch (side) {
case 'start':
case 'end':
case 'left':
case 'right':
return {
top: -(contentHeight / 2 - triggerBoundingBox.height / 2),
left: 0,
};
case 'top':
case 'bottom':
default:
return {
top: 0,
left: -(contentWidth / 2 - triggerBoundingBox.width / 2),
};
}
};
/**
* Adjusts popover positioning coordinates
* such that popover does not appear offscreen
* or overlapping safe area bounds.
*/
const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding, bodyWidth, bodyHeight, contentWidth, contentHeight, safeAreaMargin, contentOriginX, contentOriginY, triggerCoordinates, coordArrowTop = 0, coordArrowLeft = 0, arrowHeight = 0) => {
let arrowTop = coordArrowTop;
const arrowLeft = coordArrowLeft;
let left = coordLeft;
let top = coordTop;
let bottom;
let originX = contentOriginX;
let originY = contentOriginY;
let checkSafeAreaLeft = false;
let checkSafeAreaRight = false;
const triggerTop = triggerCoordinates
? triggerCoordinates.top + triggerCoordinates.height
: bodyHeight / 2 - contentHeight / 2;
const triggerHeight = triggerCoordinates ? triggerCoordinates.height : 0;
let addPopoverBottomClass = false;
/**
* Adjust popover so it does not
* go off the left of the screen.
*/
if (left < bodyPadding + safeAreaMargin) {
left = bodyPadding;
checkSafeAreaLeft = true;
originX = 'left';
/**
* Adjust popover so it does not
* go off the right of the screen.
*/
}
else if (contentWidth + bodyPadding + left + safeAreaMargin > bodyWidth) {
checkSafeAreaRight = true;
left = bodyWidth - contentWidth - bodyPadding;
originX = 'right';
}
/**
* Adjust popover so it does not
* go off the top of the screen.
* If popover is on the left or the right of
* the trigger, then we should not adjust top
* margins.
*/
if (triggerTop + triggerHeight + contentHeight > bodyHeight && (side === 'top' || side === 'bottom')) {
if (triggerTop - contentHeight > 0) {
/**
* While we strive to align the popover with the trigger
* on smaller screens this is not always possible. As a result,
* we adjust the popover up so that it does not hang
* off the bottom of the screen. However, we do not want to move
* the popover up so much that it goes off the top of the screen.
*
* We chose 12 here so that the popover position looks a bit nicer as
* it is not right up against the edge of the screen.
*/
top = Math.max(12, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1));
arrowTop = top + contentHeight;
originY = 'bottom';
addPopoverBottomClass = true;
/**
* If not enough room for popover to appear
* above trigger, then cut it off.
*/
}
else {
bottom = bodyPadding;
}
}
return {
top,
left,
bottom,
originX,
originY,
checkSafeAreaLeft,
checkSafeAreaRight,
arrowTop,
arrowLeft,
addPopoverBottomClass,
};
};
const shouldShowArrow = (side, didAdjustBounds = false, ev, trigger) => {
/**
* If no event provided and
* we do not have a trigger,
* then this popover was likely
* presented via the popoverController
* or users called `present` manually.
* In this case, the arrow should not be
* shown as we do not have a reference.
*/
if (!ev && !trigger) {
return false;
}
/**
* If popover is on the left or the right
* of a trigger, but we needed to adjust the
* popover due to screen bounds, then we should
* hide the arrow as it will never be pointing
* at the trigger.
*/
if (side !== 'top' && side !== 'bottom' && didAdjustBounds) {
return false;
}
return true;
};
const POPOVER_IOS_BODY_PADDING = 5;
/**
* iOS Popover Enter Animation
*/
// TODO(FW-2832): types
const iosEnterAnimation$1 = (baseEl, opts) => {
var _a;
const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl';
const bodyWidth = doc.defaultView.innerWidth;
const bodyHeight = doc.defaultView.innerHeight;
const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content');
const arrowEl = root.querySelector('.popover-arrow');
const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target);
const { contentWidth, contentHeight } = getPopoverDimensions(size, contentEl, referenceSizeEl);
const { arrowWidth, arrowHeight } = getArrowDimensions(arrowEl);
const defaultPosition = {
top: bodyHeight / 2 - contentHeight / 2,
left: bodyWidth / 2 - contentWidth / 2,
originX: isRTL ? 'right' : 'left',
originY: 'top',
};
const results = getPopoverPosition(isRTL, contentWidth, contentHeight, arrowWidth, arrowHeight, reference, side, align, defaultPosition, trigger, ev);
const padding = size === 'cover' ? 0 : POPOVER_IOS_BODY_PADDING;
const margin = size === 'cover' ? 0 : 25;
const { originX, originY, top, left, bottom, checkSafeAreaLeft, checkSafeAreaRight, arrowTop, arrowLeft, addPopoverBottomClass, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, margin, results.originX, results.originY, results.referenceCoordinates, results.arrowTop, results.arrowLeft, arrowHeight);
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const contentAnimation = createAnimation();
backdropAnimation
.addElement(root.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
// In Chromium, if the wrapper animates, the backdrop filter doesn't work.
// The Chromium team stated that this behavior is expected and not a bug. The element animating opacity creates a backdrop root for the backdrop-filter.
// To get around this, instead of animating the wrapper, animate both the arrow and content.
// https://bugs.chromium.org/p/chromium/issues/detail?id=1148826
contentAnimation
.addElement(root.querySelector('.popover-arrow'))
.addElement(root.querySelector('.popover-content'))
.fromTo('opacity', 0.01, 1);
// TODO(FW-4376) Ensure that arrow also blurs when translucent
return baseAnimation
.easing('ease')
.duration(100)
.beforeAddWrite(() => {
if (size === 'cover') {
baseEl.style.setProperty('--width', `${contentWidth}px`);
}
if (addPopoverBottomClass) {
baseEl.classList.add('popover-bottom');
}
if (bottom !== undefined) {
contentEl.style.setProperty('bottom', `${bottom}px`);
}
const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
let leftValue = `${left}px`;
if (checkSafeAreaLeft) {
leftValue = `${left}px${safeAreaLeft}`;
}
if (checkSafeAreaRight) {
leftValue = `${left}px${safeAreaRight}`;
}
contentEl.style.setProperty('top', `calc(${top}px + var(--offset-y, 0))`);
contentEl.style.setProperty('left', `calc(${leftValue} + var(--offset-x, 0))`);
contentEl.style.setProperty('transform-origin', `${originY} ${originX}`);
if (arrowEl !== null) {
const didAdjustBounds = results.top !== top || results.left !== left;
const showArrow = shouldShowArrow(side, didAdjustBounds, ev, trigger);
if (showArrow) {
arrowEl.style.setProperty('top', `calc(${arrowTop}px + var(--offset-y, 0))`);
arrowEl.style.setProperty('left', `calc(${arrowLeft}px + var(--offset-x, 0))`);
}
else {
arrowEl.style.setProperty('display', 'none');
}
}
})
.addAnimation([backdropAnimation, contentAnimation]);
};
/**
* iOS Popover Leave Animation
*/
const iosLeaveAnimation$1 = (baseEl) => {
const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content');
const arrowEl = root.querySelector('.popover-arrow');
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const contentAnimation = createAnimation();
backdropAnimation.addElement(root.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
contentAnimation
.addElement(root.querySelector('.popover-arrow'))
.addElement(root.querySelector('.popover-content'))
.fromTo('opacity', 0.99, 0);
return baseAnimation
.easing('ease')
.afterAddWrite(() => {
baseEl.style.removeProperty('--width');
baseEl.classList.remove('popover-bottom');
contentEl.style.removeProperty('top');
contentEl.style.removeProperty('left');
contentEl.style.removeProperty('bottom');
contentEl.style.removeProperty('transform-origin');
if (arrowEl) {
arrowEl.style.removeProperty('top');
arrowEl.style.removeProperty('left');
arrowEl.style.removeProperty('display');
}
})
.duration(300)
.addAnimation([backdropAnimation, contentAnimation]);
};
const POPOVER_MD_BODY_PADDING = 12;
/**
* Md Popover Enter Animation
*/
// TODO(FW-2832): types
const mdEnterAnimation$1 = (baseEl, opts) => {
var _a;
const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl';
const bodyWidth = doc.defaultView.innerWidth;
const bodyHeight = doc.defaultView.innerHeight;
const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content');
const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target);
const { contentWidth, contentHeight } = getPopoverDimensions(size, contentEl, referenceSizeEl);
const defaultPosition = {
top: bodyHeight / 2 - contentHeight / 2,
left: bodyWidth / 2 - contentWidth / 2,
originX: isRTL ? 'right' : 'left',
originY: 'top',
};
const results = getPopoverPosition(isRTL, contentWidth, contentHeight, 0, 0, reference, side, align, defaultPosition, trigger, ev);
const padding = size === 'cover' ? 0 : POPOVER_MD_BODY_PADDING;
const { originX, originY, top, left, bottom } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
const contentAnimation = createAnimation();
const viewportAnimation = createAnimation();
backdropAnimation
.addElement(root.querySelector('ion-backdrop'))
.fromTo('opacity', 0.01, 'var(--backdrop-opacity)')
.beforeStyles({
'pointer-events': 'none',
})
.afterClearStyles(['pointer-events']);
wrapperAnimation.addElement(root.querySelector('.popover-wrapper')).duration(150).fromTo('opacity', 0.01, 1);
contentAnimation
.addElement(contentEl)
.beforeStyles({
top: `calc(${top}px + var(--offset-y, 0px))`,
left: `calc(${left}px + var(--offset-x, 0px))`,
'transform-origin': `${originY} ${originX}`,
})
.beforeAddWrite(() => {
if (bottom !== undefined) {
contentEl.style.setProperty('bottom', `${bottom}px`);
}
})
.fromTo('transform', 'scale(0.8)', 'scale(1)');
viewportAnimation.addElement(root.querySelector('.popover-viewport')).fromTo('opacity', 0.01, 1);
return baseAnimation
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.duration(300)
.beforeAddWrite(() => {
if (size === 'cover') {
baseEl.style.setProperty('--width', `${contentWidth}px`);
}
if (originY === 'bottom') {
baseEl.classList.add('popover-bottom');
}
})
.addAnimation([backdropAnimation, wrapperAnimation, contentAnimation, viewportAnimation]);
};
/**
* Md Popover Leave Animation
*/
const mdLeaveAnimation$1 = (baseEl) => {
const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content');
const baseAnimation = createAnimation();
const backdropAnimation = createAnimation();
const wrapperAnimation = createAnimation();
backdropAnimation.addElement(root.querySelector('ion-backdrop')).fromTo('opacity', 'var(--backdrop-opacity)', 0);
wrapperAnimation.addElement(root.querySelector('.popover-wrapper')).fromTo('opacity', 0.99, 0);
return baseAnimation
.easing('ease')
.afterAddWrite(() => {
baseEl.style.removeProperty('--width');
baseEl.classList.remove('popover-bottom');
contentEl.style.removeProperty('top');
contentEl.style.removeProperty('left');
contentEl.style.removeProperty('bottom');
contentEl.style.removeProperty('transform-origin');
})
.duration(150)
.addAnimation([backdropAnimation, wrapperAnimation]);
};
const popoverIosCss = ":host{--background:var(--ion-background-color, #fff);--min-width:0;--min-height:0;--max-width:auto;--height:auto;--offset-x:0px;--offset-y:0px;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:fixed;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);z-index:1001}:host(.popover-nested){pointer-events:none}:host(.popover-nested) .popover-wrapper{pointer-events:auto}:host(.overlay-hidden){display:none}.popover-wrapper{z-index:10}.popover-content{display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:auto;z-index:10}::slotted(.popover-viewport){--ion-safe-area-top:0px;--ion-safe-area-right:0px;--ion-safe-area-bottom:0px;--ion-safe-area-left:0px;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}:host(.popover-nested.popover-side-left){--offset-x:5px}:host(.popover-nested.popover-side-right){--offset-x:-5px}:host(.popover-nested.popover-side-start){--offset-x:5px}:host-context([dir=rtl]):host(.popover-nested.popover-side-start),:host-context([dir=rtl]).popover-nested.popover-side-start{--offset-x:-5px}@supports selector(:dir(rtl)){:host(.popover-nested.popover-side-start:dir(rtl)){--offset-x:-5px}}:host(.popover-nested.popover-side-end){--offset-x:-5px}:host-context([dir=rtl]):host(.popover-nested.popover-side-end),:host-context([dir=rtl]).popover-nested.popover-side-end{--offset-x:5px}@supports selector(:dir(rtl)){:host(.popover-nested.popover-side-end:dir(rtl)){--offset-x:5px}}:host{--width:200px;--max-height:90%;--box-shadow:none;--backdrop-opacity:var(--ion-backdrop-opacity, 0.08)}:host(.popover-desktop){--box-shadow:0px 4px 16px 0px rgba(0, 0, 0, 0.12)}.popover-content{border-radius:10px}:host(.popover-desktop) .popover-content{border:0.5px solid var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}.popover-arrow{display:block;position:absolute;width:20px;height:10px;overflow:hidden;z-index:11}.popover-arrow::after{top:3px;border-radius:3px;position:absolute;width:14px;height:14px;-webkit-transform:rotate(45deg);transform:rotate(45deg);background:var(--background);content:\"\";z-index:10}.popover-arrow::after{inset-inline-start:3px}:host(.popover-bottom) .popover-arrow{top:auto;bottom:-10px}:host(.popover-bottom) .popover-arrow::after{top:-6px}:host(.popover-side-left) .popover-arrow{-webkit-transform:rotate(90deg);transform:rotate(90deg)}:host(.popover-side-right) .popover-arrow{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}:host(.popover-side-top) .popover-arrow{-webkit-transform:rotate(180deg);transform:rotate(180deg)}:host(.popover-side-start) .popover-arrow{-webkit-transform:rotate(90deg);transform:rotate(90deg)}:host-context([dir=rtl]):host(.popover-side-start) .popover-arrow,:host-context([dir=rtl]).popover-side-start .popover-arrow{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}@supports selector(:dir(rtl)){:host(.popover-side-start:dir(rtl)) .popover-arrow{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}}:host(.popover-side-end) .popover-arrow{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}:host-context([dir=rtl]):host(.popover-side-end) .popover-arrow,:host-context([dir=rtl]).popover-side-end .popover-arrow{-webkit-transform:rotate(90deg);transform:rotate(90deg)}@supports selector(:dir(rtl)){:host(.popover-side-end:dir(rtl)) .popover-arrow{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}.popover-arrow,.popover-content{opacity:0}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.popover-translucent) .popover-content,:host(.popover-translucent) .popover-arrow::after{background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}}";
const popoverMdCss = ":host{--background:var(--ion-background-color, #fff);--min-width:0;--min-height:0;--max-width:auto;--height:auto;--offset-x:0px;--offset-y:0px;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:fixed;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;outline:none;color:var(--ion-text-color, #000);z-index:1001}:host(.popover-nested){pointer-events:none}:host(.popover-nested) .popover-wrapper{pointer-events:auto}:host(.overlay-hidden){display:none}.popover-wrapper{z-index:10}.popover-content{display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);overflow:auto;z-index:10}::slotted(.popover-viewport){--ion-safe-area-top:0px;--ion-safe-area-right:0px;--ion-safe-area-bottom:0px;--ion-safe-area-left:0px;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column}:host(.popover-nested.popover-side-left){--offset-x:5px}:host(.popover-nested.popover-side-right){--offset-x:-5px}:host(.popover-nested.popover-side-start){--offset-x:5px}:host-context([dir=rtl]):host(.popover-nested.popover-side-start),:host-context([dir=rtl]).popover-nested.popover-side-start{--offset-x:-5px}@supports selector(:dir(rtl)){:host(.popover-nested.popover-side-start:dir(rtl)){--offset-x:-5px}}:host(.popover-nested.popover-side-end){--offset-x:-5px}:host-context([dir=rtl]):host(.popover-nested.popover-side-end),:host-context([dir=rtl]).popover-nested.popover-side-end{--offset-x:5px}@supports selector(:dir(rtl)){:host(.popover-nested.popover-side-end:dir(rtl)){--offset-x:5px}}:host{--width:250px;--max-height:90%;--box-shadow:0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);--backdrop-opacity:var(--ion-backdrop-opacity, 0.32)}.popover-content{border-radius:4px;-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]) .popover-content{-webkit-transform-origin:right top;transform-origin:right top}[dir=rtl] .popover-content{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.popover-content:dir(rtl){-webkit-transform-origin:right top;transform-origin:right top}}.popover-viewport{-webkit-transition-delay:100ms;transition-delay:100ms}.popover-wrapper{opacity:0}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed inside of the `.popover-content` element.
*
* @part backdrop - The `ion-backdrop` element.
* @part arrow - The arrow that points to the reference element. Only applies on `ios` mode.
* @part content - The wrapper element for the default slot.
*/
class Popover {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionPopoverDidPresent", 7);
this.willPresent = createEvent(this, "ionPopoverWillPresent", 7);
this.willDismiss = createEvent(this, "ionPopoverWillDismiss", 7);
this.didDismiss = createEvent(this, "ionPopoverDidDismiss", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.ionMount = createEvent(this, "ionMount", 7);
this.parentPopover = null;
this.coreDelegate = CoreDelegate();
this.lockController = createLockController();
this.inline = false;
this.focusDescendantOnPresent = false;
this.presented = false;
/** @internal */
this.hasController = false;
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = true;
/**
* If `true`, the popover will be dismissed when the backdrop is clicked.
*/
this.backdropDismiss = true;
/**
* If `true`, a backdrop will be displayed behind the popover.
* This property controls whether or not the backdrop
* darkens the screen when the popover is presented.
* It does not control whether or not the backdrop
* is active or present in the DOM.
*/
this.showBackdrop = true;
/**
* If `true`, the popover will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
/**
* If `true`, the popover will animate.
*/
this.animated = true;
/**
* Describes what kind of interaction with the trigger that
* should cause the popover to open. Does not apply when the `trigger`
* property is `undefined`.
* If `"click"`, the popover will be presented when the trigger is left clicked.
* If `"hover"`, the popover will be presented when a pointer hovers over the trigger.
* If `"context-menu"`, the popover will be presented when the trigger is right
* clicked on desktop and long pressed on mobile. This will also prevent your
* device's normal context menu from appearing.
*/
this.triggerAction = 'click';
/**
* Describes how to calculate the popover width.
* If `"cover"`, the popover width will match the width of the trigger.
* If `"auto"`, the popover width will be set to a static default value.
*/
this.size = 'auto';
/**
* If `true`, the popover will be automatically
* dismissed when the content has been clicked.
*/
this.dismissOnSelect = false;
/**
* Describes what to position the popover relative to.
* If `"trigger"`, the popover will be positioned relative
* to the trigger button. If passing in an event, this is
* determined via event.target.
* If `"event"`, the popover will be positioned relative
* to the x/y coordinates of the trigger action. If passing
* in an event, this is determined via event.clientX and event.clientY.
*/
this.reference = 'trigger';
/**
* Describes which side of the `reference` point to position
* the popover on. The `"start"` and `"end"` values are RTL-aware,
* and the `"left"` and `"right"` values are not.
*/
this.side = 'bottom';
/**
* If `true`, the popover will display an arrow that points at the
* `reference` when running in `ios` mode. Does not apply in `md` mode.
*/
this.arrow = true;
/**
* If `true`, the popover will open. If `false`, the popover will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the popoverController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the popover dismisses. You will need to do that in your code.
*/
this.isOpen = false;
/**
* @internal
*
* If `true` the popover will not register its own keyboard event handlers.
* This allows the contents of the popover to handle their own keyboard interactions.
*
* If `false`, the popover will register its own keyboard event handlers for
* navigating `ion-list` items within a popover (up/down/home/end/etc.).
* This will also cancel browser keyboard event bindings to prevent scroll
* behavior in a popover using a list of items.
*/
this.keyboardEvents = false;
/**
* If `true`, focus will not be allowed to move outside of this overlay.
* If `false`, focus will be allowed to move outside of the overlay.
*
* In most scenarios this property should remain set to `true`. Setting
* this property to `false` can cause severe accessibility issues as users
* relying on assistive technologies may be able to move focus into
* a confusing state. We recommend only setting this to `false` when
* absolutely necessary.
*
* Developers may want to consider disabling focus trapping if this
* overlay presents a non-Ionic overlay from a 3rd party library.
* Developers would disable focus trapping on the Ionic overlay
* when presenting the 3rd party overlay and then re-enable
* focus trapping when dismissing the 3rd party overlay and moving
* focus back to the Ionic overlay.
*/
this.focusTrap = true;
/**
* If `true`, the component passed into `ion-popover` will
* automatically be mounted when the popover is created. The
* component will remain mounted even when the popover is dismissed.
* However, the component will be destroyed when the popover is
* destroyed. This property is not reactive and should only be
* used when initially creating a popover.
*
* Note: This feature only applies to inline popovers in JavaScript
* frameworks such as Angular, React, and Vue.
*/
this.keepContentsMounted = false;
this.onBackdropTap = () => {
this.dismiss(undefined, BACKDROP);
};
this.onLifecycle = (modalEvent) => {
const el = this.usersElement;
const name = LIFECYCLE_MAP[modalEvent.type];
if (el && name) {
const event = new CustomEvent(name, {
bubbles: false,
cancelable: false,
detail: modalEvent.detail,
});
el.dispatchEvent(event);
}
};
this.configureTriggerInteraction = () => {
const { trigger, triggerAction, el, destroyTriggerInteraction } = this;
if (destroyTriggerInteraction) {
destroyTriggerInteraction();
}
if (trigger === undefined) {
return;
}
const triggerEl = (this.triggerEl = trigger !== undefined ? document.getElementById(trigger) : null);
if (!triggerEl) {
printIonWarning(`[ion-popover] - A trigger element with the ID "${trigger}" was not found in the DOM. The trigger element must be in the DOM when the "trigger" property is set on ion-popover.`, this.el);
return;
}
this.destroyTriggerInteraction = configureTriggerInteraction(triggerEl, triggerAction, el);
};
this.configureKeyboardInteraction = () => {
const { destroyKeyboardInteraction, el } = this;
if (destroyKeyboardInteraction) {
destroyKeyboardInteraction();
}
this.destroyKeyboardInteraction = configureKeyboardInteraction(el);
};
this.configureDismissInteraction = () => {
const { destroyDismissInteraction, parentPopover, triggerAction, triggerEl, el } = this;
if (!parentPopover || !triggerEl) {
return;
}
if (destroyDismissInteraction) {
destroyDismissInteraction();
}
this.destroyDismissInteraction = configureDismissInteraction(triggerEl, triggerAction, el, parentPopover);
};
}
onTriggerChange() {
this.configureTriggerInteraction();
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
connectedCallback() {
const { configureTriggerInteraction, el } = this;
prepareOverlay(el);
configureTriggerInteraction();
}
disconnectedCallback() {
const { destroyTriggerInteraction } = this;
if (destroyTriggerInteraction) {
destroyTriggerInteraction();
}
}
componentWillLoad() {
var _a, _b;
const { el } = this;
const popoverId = (_b = (_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : setOverlayId(el);
this.parentPopover = el.closest(`ion-popover:not(#${popoverId})`);
if (this.alignment === undefined) {
this.alignment = getIonMode$1(this) === 'ios' ? 'center' : 'start';
}
}
componentDidLoad() {
const { parentPopover, isOpen } = this;
/**
* If popover was rendered with isOpen="true"
* then we should open popover immediately.
*/
if (isOpen === true) {
raf(() => this.present());
}
if (parentPopover) {
addEventListener$1(parentPopover, 'ionPopoverWillDismiss', () => {
this.dismiss(undefined, undefined, false);
});
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.configureTriggerInteraction();
}
/**
* When opening a popover from a trigger, we should not be
* modifying the `event` prop from inside the component.
* Additionally, when pressing the "Right" arrow key, we need
* to shift focus to the first descendant in the newly presented
* popover.
*
* @internal
*/
async presentFromTrigger(event, focusDescendant = false) {
this.focusDescendantOnPresent = focusDescendant;
await this.present(event);
this.focusDescendantOnPresent = false;
}
/**
* Determines whether or not an overlay
* is being used inline or via a controller/JS
* and returns the correct delegate.
* By default, subsequent calls to getDelegate
* will use a cached version of the delegate.
* This is useful for calling dismiss after
* present so that the correct delegate is given.
*/
getDelegate(force = false) {
if (this.workingDelegate && !force) {
return {
delegate: this.workingDelegate,
inline: this.inline,
};
}
/**
* If using overlay inline
* we potentially need to use the coreDelegate
* so that this works in vanilla JS apps.
* If a developer has presented this component
* via a controller, then we can assume
* the component is already in the
* correct place.
*/
const parentEl = this.el.parentNode;
const inline = (this.inline = parentEl !== null && !this.hasController);
const delegate = (this.workingDelegate = inline ? this.delegate || this.coreDelegate : this.delegate);
return { inline, delegate };
}
/**
* Present the popover overlay after it has been created.
* Developers can pass a mouse, touch, or pointer event
* to position the popover relative to where that event
* was dispatched.
*
* @param event The event to position the popover relative to.
*/
async present(event) {
const unlock = await this.lockController.lock();
if (this.presented) {
unlock();
return;
}
const { el } = this;
const { inline, delegate } = this.getDelegate(true);
/**
* Emit ionMount so JS Frameworks have an opportunity
* to add the child component to the DOM. The child
* component will be assigned to this.usersElement below.
*/
this.ionMount.emit();
this.usersElement = await attachComponent(delegate, el, this.component, ['popover-viewport'], this.componentProps, inline);
if (!this.keyboardEvents) {
this.configureKeyboardInteraction();
}
this.configureDismissInteraction();
/**
* When using the lazy loaded build of Stencil, we need to wait
* for every Stencil component instance to be ready before presenting
* otherwise there can be a flash of unstyled content. With the
* custom elements bundle we need to wait for the JS framework
* mount the inner contents of the overlay otherwise WebKit may
* get the transition incorrect.
*/
if (hasLazyBuild(el)) {
await deepReady(this.usersElement);
/**
* If keepContentsMounted="true" then the
* JS Framework has already mounted the inner
* contents so there is no need to wait.
* Otherwise, we need to wait for the JS
* Framework to mount the inner contents
* of this component.
*/
}
else if (!this.keepContentsMounted) {
await waitForMount();
}
await present(this, 'popoverEnter', iosEnterAnimation$1, mdEnterAnimation$1, {
event: event || this.event,
size: this.size,
trigger: this.triggerEl,
reference: this.reference,
side: this.side,
align: this.alignment,
});
/**
* If popover is nested and was
* presented using the "Right" arrow key,
* we need to move focus to the first
* descendant inside of the popover.
*/
if (this.focusDescendantOnPresent) {
focusFirstDescendant(el);
}
unlock();
}
/**
* Dismiss the popover overlay after it has been presented.
* This is a no-op if the overlay has not been presented yet. If you want
* to remove an overlay from the DOM that was never presented, use the
* [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the popover. For example, `cancel` or `backdrop`.
* @param dismissParentPopover If `true`, dismissing this popover will also dismiss
* a parent popover if this popover is nested. Defaults to `true`.
*/
async dismiss(data, role, dismissParentPopover = true) {
const unlock = await this.lockController.lock();
const { destroyKeyboardInteraction, destroyDismissInteraction } = this;
if (dismissParentPopover && this.parentPopover) {
this.parentPopover.dismiss(data, role, dismissParentPopover);
}
const shouldDismiss = await dismiss(this, data, role, 'popoverLeave', iosLeaveAnimation$1, mdLeaveAnimation$1, this.event);
if (shouldDismiss) {
if (destroyKeyboardInteraction) {
destroyKeyboardInteraction();
this.destroyKeyboardInteraction = undefined;
}
if (destroyDismissInteraction) {
destroyDismissInteraction();
this.destroyDismissInteraction = undefined;
}
/**
* If using popover inline
* we potentially need to use the coreDelegate
* so that this works in vanilla JS apps
*/
const { delegate } = this.getDelegate();
await detachComponent(delegate, this.usersElement);
}
unlock();
return shouldDismiss;
}
/**
* @internal
*/
async getParentPopover() {
return this.parentPopover;
}
/**
* Returns a promise that resolves when the popover did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionPopoverDidDismiss');
}
/**
* Returns a promise that resolves when the popover will dismiss.
*/
onWillDismiss() {
return eventMethod(this.el, 'ionPopoverWillDismiss');
}
render() {
const mode = getIonMode$1(this);
const { onLifecycle, parentPopover, dismissOnSelect, side, arrow, htmlAttributes, focusTrap } = this;
const desktop = isPlatform('desktop');
const enableArrow = arrow && !parentPopover;
return (hAsync(Host, Object.assign({ key: '16866c02534968c982cf4730d2936d03a5107c8b', "aria-modal": "true", "no-router": true, tabindex: "-1" }, htmlAttributes, { style: {
zIndex: `${20000 + this.overlayIndex}`,
}, class: Object.assign(Object.assign({}, getClassMap(this.cssClass)), { [mode]: true, 'popover-translucent': this.translucent, 'overlay-hidden': true, 'popover-desktop': desktop, [`popover-side-${side}`]: true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false, 'popover-nested': !!parentPopover }), onIonPopoverDidPresent: onLifecycle, onIonPopoverWillPresent: onLifecycle, onIonPopoverWillDismiss: onLifecycle, onIonPopoverDidDismiss: onLifecycle, onIonBackdropTap: this.onBackdropTap }), !parentPopover && hAsync("ion-backdrop", { key: '0df258601a4d30df3c27aa8234a7d5e056c3ecbb', tappable: this.backdropDismiss, visible: this.showBackdrop, part: "backdrop" }), hAsync("div", { key: 'f94e80ed996b957b5cd09b826472b4f60e8fcc78', class: "popover-wrapper ion-overlay-wrapper", onClick: dismissOnSelect ? () => this.dismiss() : undefined }, enableArrow && hAsync("div", { key: '185ce22f6386e8444a9cc7b8818dbfc16c463c99', class: "popover-arrow", part: "arrow" }), hAsync("div", { key: '206202b299404e110de5397b229678cca18568d3', class: "popover-content", part: "content" }, hAsync("slot", { key: 'ee543a0b92d6e35a837c0a0e4617c7b0fc4ad0b0' })))));
}
get el() { return getElement(this); }
static get watchers() { return {
"trigger": ["onTriggerChange"],
"triggerAction": ["onTriggerChange"],
"isOpen": ["onIsOpenChange"]
}; }
static get style() { return {
ios: popoverIosCss,
md: popoverMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-popover",
"$members$": {
"hasController": [4, "has-controller"],
"delegate": [16],
"overlayIndex": [2, "overlay-index"],
"enterAnimation": [16],
"leaveAnimation": [16],
"component": [1],
"componentProps": [16],
"keyboardClose": [4, "keyboard-close"],
"cssClass": [1, "css-class"],
"backdropDismiss": [4, "backdrop-dismiss"],
"event": [8],
"showBackdrop": [4, "show-backdrop"],
"translucent": [4],
"animated": [4],
"htmlAttributes": [16],
"triggerAction": [1, "trigger-action"],
"trigger": [1],
"size": [1],
"dismissOnSelect": [4, "dismiss-on-select"],
"reference": [1],
"side": [1],
"alignment": [1025],
"arrow": [4],
"isOpen": [4, "is-open"],
"keyboardEvents": [4, "keyboard-events"],
"focusTrap": [4, "focus-trap"],
"keepContentsMounted": [4, "keep-contents-mounted"],
"presented": [32],
"presentFromTrigger": [64],
"present": [64],
"dismiss": [64],
"getParentPopover": [64],
"onDidDismiss": [64],
"onWillDismiss": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const LIFECYCLE_MAP = {
ionPopoverDidPresent: 'ionViewDidEnter',
ionPopoverWillPresent: 'ionViewWillEnter',
ionPopoverWillDismiss: 'ionViewWillLeave',
ionPopoverDidDismiss: 'ionViewDidLeave',
};
const progressBarIosCss = ":host{--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.3);--progress-background:var(--ion-color-primary, #0054e9);display:block;position:relative;width:100%;contain:strict;direction:ltr;overflow:hidden}.progress,.progress-indeterminate,.indeterminate-bar-primary,.indeterminate-bar-secondary,.progress-buffer-bar{left:0;right:0;top:0;bottom:0;position:absolute;width:100%;height:100%}.buffer-circles-container,.buffer-circles{left:0;right:0;top:0;bottom:0;position:absolute}.buffer-circles{right:-10px;left:-10px;}.progress,.progress-buffer-bar,.buffer-circles-container{-webkit-transform-origin:left top;transform-origin:left top;-webkit-transition:-webkit-transform 150ms linear;transition:-webkit-transform 150ms linear;transition:transform 150ms linear;transition:transform 150ms linear, -webkit-transform 150ms linear}.progress,.progress-indeterminate{background:var(--progress-background);z-index:2}.progress-buffer-bar{background:var(--background);z-index:1}.buffer-circles-container{overflow:hidden}.indeterminate-bar-primary{top:0;right:0;bottom:0;left:-145.166611%;-webkit-animation:primary-indeterminate-translate 2s infinite linear;animation:primary-indeterminate-translate 2s infinite linear}.indeterminate-bar-primary .progress-indeterminate{-webkit-animation:primary-indeterminate-scale 2s infinite linear;animation:primary-indeterminate-scale 2s infinite linear;-webkit-animation-play-state:inherit;animation-play-state:inherit}.indeterminate-bar-secondary{top:0;right:0;bottom:0;left:-54.888891%;-webkit-animation:secondary-indeterminate-translate 2s infinite linear;animation:secondary-indeterminate-translate 2s infinite linear}.indeterminate-bar-secondary .progress-indeterminate{-webkit-animation:secondary-indeterminate-scale 2s infinite linear;animation:secondary-indeterminate-scale 2s infinite linear;-webkit-animation-play-state:inherit;animation-play-state:inherit}.buffer-circles{background-image:radial-gradient(ellipse at center, var(--background) 0%, var(--background) 30%, transparent 30%);background-repeat:repeat-x;background-position:5px center;background-size:10px 10px;z-index:0;-webkit-animation:buffering 450ms infinite linear;animation:buffering 450ms infinite linear}:host(.progress-bar-reversed){-webkit-transform:scaleX(-1);transform:scaleX(-1)}:host(.progress-paused) .indeterminate-bar-secondary,:host(.progress-paused) .indeterminate-bar-primary,:host(.progress-paused) .buffer-circles{-webkit-animation-play-state:paused;animation-play-state:paused}:host(.ion-color) .buffer-circles{background-image:radial-gradient(ellipse at center, rgba(var(--ion-color-base-rgb), 0.3) 0%, rgba(var(--ion-color-base-rgb), 0.3) 30%, transparent 30%)}:host(.ion-color) .progress,:host(.ion-color) .progress-indeterminate{background:var(--ion-color-base)}@-webkit-keyframes primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%)}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%)}}@keyframes primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%)}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%)}}@-webkit-keyframes primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%)}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%)}}@keyframes secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%)}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%)}}@-webkit-keyframes secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes buffering{to{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}@keyframes buffering{to{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}:host{border-radius:9999px;height:4px}:host(.progress-bar-solid){--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6))}";
const progressBarMdCss = ":host{--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.3);--progress-background:var(--ion-color-primary, #0054e9);display:block;position:relative;width:100%;contain:strict;direction:ltr;overflow:hidden}.progress,.progress-indeterminate,.indeterminate-bar-primary,.indeterminate-bar-secondary,.progress-buffer-bar{left:0;right:0;top:0;bottom:0;position:absolute;width:100%;height:100%}.buffer-circles-container,.buffer-circles{left:0;right:0;top:0;bottom:0;position:absolute}.buffer-circles{right:-10px;left:-10px;}.progress,.progress-buffer-bar,.buffer-circles-container{-webkit-transform-origin:left top;transform-origin:left top;-webkit-transition:-webkit-transform 150ms linear;transition:-webkit-transform 150ms linear;transition:transform 150ms linear;transition:transform 150ms linear, -webkit-transform 150ms linear}.progress,.progress-indeterminate{background:var(--progress-background);z-index:2}.progress-buffer-bar{background:var(--background);z-index:1}.buffer-circles-container{overflow:hidden}.indeterminate-bar-primary{top:0;right:0;bottom:0;left:-145.166611%;-webkit-animation:primary-indeterminate-translate 2s infinite linear;animation:primary-indeterminate-translate 2s infinite linear}.indeterminate-bar-primary .progress-indeterminate{-webkit-animation:primary-indeterminate-scale 2s infinite linear;animation:primary-indeterminate-scale 2s infinite linear;-webkit-animation-play-state:inherit;animation-play-state:inherit}.indeterminate-bar-secondary{top:0;right:0;bottom:0;left:-54.888891%;-webkit-animation:secondary-indeterminate-translate 2s infinite linear;animation:secondary-indeterminate-translate 2s infinite linear}.indeterminate-bar-secondary .progress-indeterminate{-webkit-animation:secondary-indeterminate-scale 2s infinite linear;animation:secondary-indeterminate-scale 2s infinite linear;-webkit-animation-play-state:inherit;animation-play-state:inherit}.buffer-circles{background-image:radial-gradient(ellipse at center, var(--background) 0%, var(--background) 30%, transparent 30%);background-repeat:repeat-x;background-position:5px center;background-size:10px 10px;z-index:0;-webkit-animation:buffering 450ms infinite linear;animation:buffering 450ms infinite linear}:host(.progress-bar-reversed){-webkit-transform:scaleX(-1);transform:scaleX(-1)}:host(.progress-paused) .indeterminate-bar-secondary,:host(.progress-paused) .indeterminate-bar-primary,:host(.progress-paused) .buffer-circles{-webkit-animation-play-state:paused;animation-play-state:paused}:host(.ion-color) .buffer-circles{background-image:radial-gradient(ellipse at center, rgba(var(--ion-color-base-rgb), 0.3) 0%, rgba(var(--ion-color-base-rgb), 0.3) 30%, transparent 30%)}:host(.ion-color) .progress,:host(.ion-color) .progress-indeterminate{background:var(--ion-color-base)}@-webkit-keyframes primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%)}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%)}}@keyframes primary-indeterminate-translate{0%{-webkit-transform:translateX(0);transform:translateX(0)}20%{-webkit-animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);animation-timing-function:cubic-bezier(0.5, 0, 0.701732, 0.495819);-webkit-transform:translateX(0);transform:translateX(0)}59.15%{-webkit-animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);animation-timing-function:cubic-bezier(0.302435, 0.381352, 0.55, 0.956352);-webkit-transform:translateX(83.67142%);transform:translateX(83.67142%)}100%{-webkit-transform:translateX(200.611057%);transform:translateX(200.611057%)}}@-webkit-keyframes primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes primary-indeterminate-scale{0%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}36.65%{-webkit-animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);animation-timing-function:cubic-bezier(0.334731, 0.12482, 0.785844, 1);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}69.15%{-webkit-animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);animation-timing-function:cubic-bezier(0.06, 0.11, 0.6, 1);-webkit-transform:scaleX(0.661479);transform:scaleX(0.661479)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%)}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%)}}@keyframes secondary-indeterminate-translate{0%{-webkit-animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);animation-timing-function:cubic-bezier(0.15, 0, 0.515058, 0.409685);-webkit-transform:translateX(0);transform:translateX(0)}25%{-webkit-animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);animation-timing-function:cubic-bezier(0.31033, 0.284058, 0.8, 0.733712);-webkit-transform:translateX(37.651913%);transform:translateX(37.651913%)}48.35%{-webkit-animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);animation-timing-function:cubic-bezier(0.4, 0.627035, 0.6, 0.902026);-webkit-transform:translateX(84.386165%);transform:translateX(84.386165%)}100%{-webkit-transform:translateX(160.277782%);transform:translateX(160.277782%)}}@-webkit-keyframes secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@keyframes secondary-indeterminate-scale{0%{-webkit-animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);animation-timing-function:cubic-bezier(0.205028, 0.057051, 0.57661, 0.453971);-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}19.15%{-webkit-animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);animation-timing-function:cubic-bezier(0.152313, 0.196432, 0.648374, 1.004315);-webkit-transform:scaleX(0.457104);transform:scaleX(0.457104)}44.15%{-webkit-animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);animation-timing-function:cubic-bezier(0.257759, -0.003163, 0.211762, 1.38179);-webkit-transform:scaleX(0.72796);transform:scaleX(0.72796)}100%{-webkit-transform:scaleX(0.08);transform:scaleX(0.08)}}@-webkit-keyframes buffering{to{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}@keyframes buffering{to{-webkit-transform:translateX(-10px);transform:translateX(-10px)}}:host{height:4px}:host(.ion-color) .progress-buffer-bar{background:rgba(var(--ion-color-base-rgb), 0.3)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part progress - The progress bar that shows the current value when `type` is `"determinate"` and slides back and forth when `type` is `"indeterminate"`.
* @part stream - The animated circles that appear while buffering. This only shows when `buffer` is set and `type` is `"determinate"`.
* @part track - The track bar behind the progress bar. If the `buffer` property is set and `type` is `"determinate"` the track will be the
* width of the `buffer` value.
*/
class ProgressBar {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* The state of the progress bar, based on if the time the process takes is known or not.
* Default options are: `"determinate"` (no animation), `"indeterminate"` (animate from left to right).
*/
this.type = 'determinate';
/**
* If true, reverse the progress bar direction.
*/
this.reversed = false;
/**
* The value determines how much of the active bar should display when the
* `type` is `"determinate"`.
* The value should be between [0, 1].
*/
this.value = 0;
/**
* If the buffer and value are smaller than 1, the buffer circles will show.
* The buffer should be between [0, 1].
*/
this.buffer = 1;
}
render() {
const { color, type, reversed, value, buffer } = this;
const paused = config.getBoolean('_testing');
const mode = getIonMode$1(this);
// If the progress is displayed as a solid bar.
const progressSolid = buffer === 1;
return (hAsync(Host, { key: 'dc69693b5d2dcb2b6e4296d7cb85bc27507f3fa6', role: "progressbar", "aria-valuenow": type === 'determinate' ? value : null, "aria-valuemin": "0", "aria-valuemax": "1", class: createColorClasses$1(color, {
[mode]: true,
[`progress-bar-${type}`]: true,
'progress-paused': paused,
'progress-bar-reversed': document.dir === 'rtl' ? !reversed : reversed,
'progress-bar-solid': progressSolid,
}) }, type === 'indeterminate' ? renderIndeterminate() : renderProgress(value, buffer)));
}
static get style() { return {
ios: progressBarIosCss,
md: progressBarMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-progress-bar",
"$members$": {
"type": [1],
"reversed": [4],
"value": [2],
"buffer": [2],
"color": [513]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const renderIndeterminate = () => {
return (hAsync("div", { part: "track", class: "progress-buffer-bar" }, hAsync("div", { class: "indeterminate-bar-primary" }, hAsync("span", { part: "progress", class: "progress-indeterminate" })), hAsync("div", { class: "indeterminate-bar-secondary" }, hAsync("span", { part: "progress", class: "progress-indeterminate" }))));
};
const renderProgress = (value, buffer) => {
const finalValue = clamp(0, value, 1);
const finalBuffer = clamp(0, buffer, 1);
return [
hAsync("div", { part: "progress", class: "progress", style: { transform: `scaleX(${finalValue})` } }),
/**
* Buffer circles with two container to move
* the circles behind the buffer progress
* with respecting the animation.
* When finalBuffer === 1, we use display: none
* instead of removing the element to avoid flickering.
*/
// TODO(FW-6697): change `ion-hide` class to `ion-display-none` or another class
hAsync("div", { class: { 'buffer-circles-container': true, 'ion-hide': finalBuffer === 1 }, style: { transform: `translateX(${finalBuffer * 100}%)` } }, hAsync("div", { class: "buffer-circles-container", style: { transform: `translateX(-${finalBuffer * 100}%)` } }, hAsync("div", { part: "stream", class: "buffer-circles" }))),
hAsync("div", { part: "track", class: "progress-buffer-bar", style: { transform: `scaleX(${finalBuffer})` } }),
];
};
const radioIosCss = ":host{--inner-border-radius:50%;display:inline-block;position:relative;max-width:100%;min-height:inherit;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.radio-disabled){pointer-events:none}.radio-icon{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;contain:layout size style}.radio-icon,.radio-inner{-webkit-box-sizing:border-box;box-sizing:border-box}input{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}:host(:focus){outline:none}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}.radio-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;min-height:inherit;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.radio-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.radio-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}:host(.radio-justify-space-between) .radio-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.radio-justify-start) .radio-wrapper{-ms-flex-pack:start;justify-content:start}:host(.radio-justify-end) .radio-wrapper{-ms-flex-pack:end;justify-content:end}:host(.radio-alignment-start) .radio-wrapper{-ms-flex-align:start;align-items:start}:host(.radio-alignment-center) .radio-wrapper{-ms-flex-align:center;align-items:center}:host(.radio-justify-space-between),:host(.radio-justify-start),:host(.radio-justify-end),:host(.radio-alignment-start),:host(.radio-alignment-center){display:block}:host(.radio-label-placement-start) .radio-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.radio-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.radio-label-placement-end) .radio-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.radio-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.radio-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.radio-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px}:host(.radio-label-placement-stacked) .radio-wrapper{-ms-flex-direction:column;flex-direction:column}:host(.radio-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.radio-label-placement-stacked.radio-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.radio-label-placement-stacked.radio-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).radio-label-placement-stacked.radio-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.radio-label-placement-stacked.radio-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.radio-label-placement-stacked.radio-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.radio-label-placement-stacked.radio-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).radio-label-placement-stacked.radio-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.radio-label-placement-stacked.radio-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host{--color-checked:var(--ion-color-primary, #0054e9)}:host(.ion-color.radio-checked) .radio-inner{border-color:var(--ion-color-base)}.item-radio.item-ios ion-label{-webkit-margin-start:0;margin-inline-start:0}.radio-inner{width:33%;height:50%}:host(.radio-checked) .radio-inner{-webkit-transform:rotate(45deg);transform:rotate(45deg);border-width:0.125rem;border-top-width:0;border-left-width:0;border-style:solid;border-color:var(--color-checked)}:host(.radio-disabled){opacity:0.3}:host(.ion-focused) .radio-icon::after{border-radius:var(--inner-border-radius);top:-8px;display:block;position:absolute;width:36px;height:36px;background:var(--ion-color-primary-tint, #1a65eb);content:\"\";opacity:0.2}:host(.ion-focused) .radio-icon::after{inset-inline-start:-9px}.native-wrapper .radio-icon{width:0.9375rem;height:1.5rem}";
const radioMdCss = ":host{--inner-border-radius:50%;display:inline-block;position:relative;max-width:100%;min-height:inherit;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.radio-disabled){pointer-events:none}.radio-icon{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;contain:layout size style}.radio-icon,.radio-inner{-webkit-box-sizing:border-box;box-sizing:border-box}input{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}:host(:focus){outline:none}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}.radio-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;min-height:inherit;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.radio-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.radio-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}:host(.radio-justify-space-between) .radio-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.radio-justify-start) .radio-wrapper{-ms-flex-pack:start;justify-content:start}:host(.radio-justify-end) .radio-wrapper{-ms-flex-pack:end;justify-content:end}:host(.radio-alignment-start) .radio-wrapper{-ms-flex-align:start;align-items:start}:host(.radio-alignment-center) .radio-wrapper{-ms-flex-align:center;align-items:center}:host(.radio-justify-space-between),:host(.radio-justify-start),:host(.radio-justify-end),:host(.radio-alignment-start),:host(.radio-alignment-center){display:block}:host(.radio-label-placement-start) .radio-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.radio-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.radio-label-placement-end) .radio-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.radio-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.radio-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.radio-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px}:host(.radio-label-placement-stacked) .radio-wrapper{-ms-flex-direction:column;flex-direction:column}:host(.radio-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.radio-label-placement-stacked.radio-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.radio-label-placement-stacked.radio-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).radio-label-placement-stacked.radio-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.radio-label-placement-stacked.radio-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.radio-label-placement-stacked.radio-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.radio-label-placement-stacked.radio-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).radio-label-placement-stacked.radio-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.radio-label-placement-stacked.radio-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host{--color:rgb(var(--ion-text-color-rgb, 0, 0, 0), 0.6);--color-checked:var(--ion-color-primary, #0054e9);--border-width:0.125rem;--border-style:solid;--border-radius:50%}:host(.ion-color) .radio-inner{background:var(--ion-color-base)}:host(.ion-color.radio-checked) .radio-icon{border-color:var(--ion-color-base)}.radio-icon{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;border-radius:var(--border-radius);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--color)}.radio-inner{border-radius:var(--inner-border-radius);width:calc(50% + var(--border-width));height:calc(50% + var(--border-width));-webkit-transform:scale3d(0, 0, 0);transform:scale3d(0, 0, 0);-webkit-transition:-webkit-transform 280ms cubic-bezier(0.4, 0, 0.2, 1);transition:-webkit-transform 280ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 280ms cubic-bezier(0.4, 0, 0.2, 1);transition:transform 280ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 280ms cubic-bezier(0.4, 0, 0.2, 1);background:var(--color-checked)}:host(.radio-checked) .radio-icon{border-color:var(--color-checked)}:host(.radio-checked) .radio-inner{-webkit-transform:scale3d(1, 1, 1);transform:scale3d(1, 1, 1)}:host(.radio-disabled) .label-text-wrapper{opacity:0.38}:host(.radio-disabled) .native-wrapper{opacity:0.63}:host(.ion-focused) .radio-icon::after{border-radius:var(--inner-border-radius);display:block;position:absolute;width:36px;height:36px;background:var(--ion-color-primary-tint, #1a65eb);content:\"\";opacity:0.2}.native-wrapper .radio-icon{width:1.25rem;height:1.25rem}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - The label text to associate with the radio. Use the "labelPlacement" property to control where the label is placed relative to the radio.
*
* @part container - The container for the radio mark.
* @part label - The label text describing the radio.
* @part mark - The checkmark or dot used to indicate the checked state.
*/
class Radio {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.inputId = `ion-rb-${radioButtonIds++}`;
this.radioGroup = null;
/**
* If `true`, the radio is selected.
*/
this.checked = false;
/**
* The tabindex of the radio button.
* @internal
*/
this.buttonTabindex = -1;
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* If `true`, the user cannot interact with the radio.
*/
this.disabled = false;
/**
* Where to place the label relative to the radio.
* `"start"`: The label will appear to the left of the radio in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the radio in LTR and to the left in RTL.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
* `"stacked"`: The label will appear above the radio regardless of the direction. The alignment of the label can be controlled with the `alignment` property.
*/
this.labelPlacement = 'start';
this.updateState = () => {
if (this.radioGroup) {
const { compareWith, value: radioGroupValue } = this.radioGroup;
this.checked = isOptionSelected(radioGroupValue, this.value, compareWith);
}
};
this.onClick = () => {
const { radioGroup, checked, disabled } = this;
if (disabled) {
return;
}
/**
* The modern control does not use a native input
* inside of the radio host, so we cannot rely on the
* ev.preventDefault() behavior above. If the radio
* is checked and the parent radio group allows for empty
* selection, then we can set the checked state to false.
* Otherwise, the checked state should always be set
* to true because the checked state cannot be toggled.
*/
if (checked && (radioGroup === null || radioGroup === void 0 ? void 0 : radioGroup.allowEmptySelection)) {
this.checked = false;
}
else {
this.checked = true;
}
};
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
}
valueChanged() {
/**
* The new value of the radio may
* match the radio group's value,
* so we see if it should be checked.
*/
this.updateState();
}
componentDidLoad() {
/**
* The value may be `undefined` if it
* gets set before the radio is
* rendered. This ensures that the radio
* is checked if the value matches. This
* happens most often when Angular is
* rendering the radio.
*/
this.updateState();
}
/** @internal */
async setFocus(ev) {
if (ev !== undefined) {
ev.stopPropagation();
ev.preventDefault();
}
this.el.focus();
}
/** @internal */
async setButtonTabindex(value) {
this.buttonTabindex = value;
}
connectedCallback() {
if (this.value === undefined) {
this.value = this.inputId;
}
const radioGroup = (this.radioGroup = this.el.closest('ion-radio-group'));
if (radioGroup) {
this.updateState();
addEventListener$1(radioGroup, 'ionValueChange', this.updateState);
}
}
disconnectedCallback() {
const radioGroup = this.radioGroup;
if (radioGroup) {
removeEventListener(radioGroup, 'ionValueChange', this.updateState);
this.radioGroup = null;
}
}
get hasLabel() {
return this.el.textContent !== '';
}
renderRadioControl() {
return (hAsync("div", { class: "radio-icon", part: "container" }, hAsync("div", { class: "radio-inner", part: "mark" }), hAsync("div", { class: "radio-ripple" })));
}
render() {
const { checked, disabled, color, el, justify, labelPlacement, hasLabel, buttonTabindex, alignment } = this;
const mode = getIonMode$1(this);
const inItem = hostContext('ion-item', el);
return (hAsync(Host, { key: '3353b28172b7f837d4b38964169b5b5f4ba02788', onFocus: this.onFocus, onBlur: this.onBlur, onClick: this.onClick, class: createColorClasses$1(color, {
[mode]: true,
'in-item': inItem,
'radio-checked': checked,
'radio-disabled': disabled,
[`radio-justify-${justify}`]: justify !== undefined,
[`radio-alignment-${alignment}`]: alignment !== undefined,
[`radio-label-placement-${labelPlacement}`]: true,
// Focus and active styling should not apply when the radio is in an item
'ion-activatable': !inItem,
'ion-focusable': !inItem,
}), role: "radio", "aria-checked": checked ? 'true' : 'false', "aria-disabled": disabled ? 'true' : null, tabindex: buttonTabindex }, hAsync("label", { key: '418a0a48366ff900e97da123abf665bbbda87fb7', class: "radio-wrapper" }, hAsync("div", { key: '6e5acdd8c8f5d0ad26632a65396afef8094153d1', class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !hasLabel,
}, part: "label" }, hAsync("slot", { key: '10b157162cd283d624153c747679609cf0bbf11e' })), hAsync("div", { key: '4c45cca95cb105cd6df1025a26e3c045272184a0', class: "native-wrapper" }, this.renderRadioControl()))));
}
get el() { return getElement(this); }
static get watchers() { return {
"value": ["valueChanged"]
}; }
static get style() { return {
ios: radioIosCss,
md: radioMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-radio",
"$members$": {
"color": [513],
"name": [1],
"disabled": [4],
"value": [8],
"labelPlacement": [1, "label-placement"],
"justify": [1],
"alignment": [1],
"checked": [32],
"buttonTabindex": [32],
"setFocus": [64],
"setButtonTabindex": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
let radioButtonIds = 0;
const radioGroupIosCss = "ion-radio-group{vertical-align:top}.radio-group-wrapper{display:inline}.radio-group-top{line-height:1.5}.radio-group-top .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.radio-group-top .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid .radio-group-top .error-text{display:block}.ion-touched.ion-invalid .radio-group-top .helper-text{display:none}ion-list .radio-group-top{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}";
const radioGroupMdCss = "ion-radio-group{vertical-align:top}.radio-group-wrapper{display:inline}.radio-group-top{line-height:1.5}.radio-group-top .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.radio-group-top .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid .radio-group-top .error-text{display:block}.ion-touched.ion-invalid .radio-group-top .helper-text{display:none}ion-list .radio-group-top{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px}";
class RadioGroup {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionValueChange = createEvent(this, "ionValueChange", 7);
this.inputId = `ion-rg-${radioGroupIds++}`;
this.helperTextId = `${this.inputId}-helper-text`;
this.errorTextId = `${this.inputId}-error-text`;
this.labelId = `${this.inputId}-lbl`;
/**
* If `true`, the radios can be deselected.
*/
this.allowEmptySelection = false;
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
this.setRadioTabindex = (value) => {
const radios = this.getRadios();
// Get the first radio that is not disabled and the checked one
const first = radios.find((radio) => !radio.disabled);
const checked = radios.find((radio) => radio.value === value && !radio.disabled);
if (!first && !checked) {
return;
}
// If an enabled checked radio exists, set it to be the focusable radio
// otherwise we default to focus the first radio
const focusable = checked || first;
for (const radio of radios) {
const tabindex = radio === focusable ? 0 : -1;
radio.setButtonTabindex(tabindex);
}
};
this.onClick = (ev) => {
ev.preventDefault();
/**
* The Radio Group component mandates that only one radio button
* within the group can be selected at any given time. Since `ion-radio`
* is a shadow DOM component, it cannot natively perform this behavior
* using the `name` attribute.
*/
const selectedRadio = ev.target && ev.target.closest('ion-radio');
/**
* Our current disabled prop definition causes Stencil to mark it
* as optional. While this is not desired, fixing this behavior
* in Stencil is a significant breaking change, so this effort is
* being de-risked in STENCIL-917. Until then, we compromise
* here by checking for falsy `disabled` values instead of strictly
* checking `disabled === false`.
*/
if (selectedRadio && !selectedRadio.disabled) {
const currentValue = this.value;
const newValue = selectedRadio.value;
if (newValue !== currentValue) {
this.value = newValue;
this.emitValueChange(ev);
}
else if (this.allowEmptySelection) {
this.value = undefined;
this.emitValueChange(ev);
}
}
};
}
valueChanged(value) {
this.setRadioTabindex(value);
this.ionValueChange.emit({ value });
}
componentDidLoad() {
/**
* There's an issue when assigning a value to the radio group
* within the Angular primary content (rendering within the
* app component template). When the template is isolated to a route,
* the value is assigned correctly.
* To address this issue, we need to ensure that the watcher is
* called after the component has finished loading,
* allowing the emit to be dispatched correctly.
*/
this.valueChanged(this.value);
}
async connectedCallback() {
// Get the list header if it exists and set the id
// this is used to set aria-labelledby
const header = this.el.querySelector('ion-list-header') || this.el.querySelector('ion-item-divider');
if (header) {
const label = (this.label = header.querySelector('ion-label'));
if (label) {
this.labelId = label.id = this.name + '-lbl';
}
}
}
getRadios() {
return Array.from(this.el.querySelectorAll('ion-radio'));
}
/**
* Emits an `ionChange` event.
*
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitValueChange(event) {
const { value } = this;
this.ionChange.emit({ value, event });
}
onKeydown(ev) {
// We don't want the value to automatically change/emit when the radio group is part of a select interface
// as this will cause the interface to close when navigating through the radio group options
const inSelectInterface = !!this.el.closest('ion-select-popover') || !!this.el.closest('ion-select-modal');
if (ev.target && !this.el.contains(ev.target)) {
return;
}
// Get all radios inside of the radio group and then
// filter out disabled radios since we need to skip those
const radios = this.getRadios().filter((radio) => !radio.disabled);
// Only move the radio if the current focus is in the radio group
if (ev.target && radios.includes(ev.target)) {
const index = radios.findIndex((radio) => radio === ev.target);
const current = radios[index];
let next;
// If hitting arrow down or arrow right, move to the next radio
// If we're on the last radio, move to the first radio
if (['ArrowDown', 'ArrowRight'].includes(ev.key)) {
next = index === radios.length - 1 ? radios[0] : radios[index + 1];
}
// If hitting arrow up or arrow left, move to the previous radio
// If we're on the first radio, move to the last radio
if (['ArrowUp', 'ArrowLeft'].includes(ev.key)) {
next = index === 0 ? radios[radios.length - 1] : radios[index - 1];
}
if (next && radios.includes(next)) {
next.setFocus(ev);
if (!inSelectInterface) {
this.value = next.value;
this.emitValueChange(ev);
}
}
// Update the radio group value when a user presses the
// space bar on top of a selected radio
if ([' '].includes(ev.key)) {
const previousValue = this.value;
this.value = this.allowEmptySelection && this.value !== undefined ? undefined : current.value;
if (previousValue !== this.value || this.allowEmptySelection) {
/**
* Value change should only be emitted if the value is different,
* such as selecting a new radio with the space bar or if
* the radio group allows for empty selection and the user
* is deselecting a checked radio.
*/
this.emitValueChange(ev);
}
// Prevent browsers from jumping
// to the bottom of the screen
ev.preventDefault();
}
}
}
/** @internal */
async setFocus() {
const radioToFocus = this.getRadios().find((r) => r.tabIndex !== -1);
radioToFocus === null || radioToFocus === void 0 ? void 0 : radioToFocus.setFocus();
}
/**
* Renders the helper text or error text values
*/
renderHintText() {
const { helperText, errorText, helperTextId, errorTextId } = this;
const hasHintText = !!helperText || !!errorText;
if (!hasHintText) {
return;
}
return (hAsync("div", { class: "radio-group-top" }, hAsync("div", { id: helperTextId, class: "helper-text" }, helperText), hAsync("div", { id: errorTextId, class: "error-text" }, errorText)));
}
getHintTextID() {
const { el, helperText, errorText, helperTextId, errorTextId } = this;
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
render() {
const { label, labelId, el, name, value } = this;
const mode = getIonMode$1(this);
renderHiddenInput(true, el, name, value, false);
return (hAsync(Host, { key: '81b8ebc96b2f383c36717f290d2959cc921ad6e8', role: "radiogroup", "aria-labelledby": label ? labelId : null, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === this.errorTextId, onClick: this.onClick, class: mode }, this.renderHintText(), hAsync("div", { key: '45b09efc10776b889a8f372cba80d25a3fc849da', class: "radio-group-wrapper" }, hAsync("slot", { key: '58714934542c2fdd7396de160364f3f06b32e8f8' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"value": ["valueChanged"]
}; }
static get style() { return {
ios: radioGroupIosCss,
md: radioGroupMdCss
}; }
static get cmpMeta() { return {
"$flags$": 292,
"$tagName$": "ion-radio-group",
"$members$": {
"allowEmptySelection": [4, "allow-empty-selection"],
"compareWith": [1, "compare-with"],
"name": [1],
"value": [1032],
"helperText": [1, "helper-text"],
"errorText": [1, "error-text"],
"setFocus": [64]
},
"$listeners$": [[4, "keydown", "onKeydown"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
let radioGroupIds = 0;
function getDecimalPlaces(n) {
if (!isSafeNumber(n))
return 0;
if (n % 1 === 0)
return 0;
return n.toString().split('.')[1].length;
}
/**
* Fixes floating point rounding errors in a result by rounding
* to the same specificity, or number of decimal places (*not*
* significant figures) as provided reference numbers. If multiple
* references are provided, the highest number of decimal places
* between them will be used.
*
* The main use case is when numbers x and y are added to produce n,
* but x and y are floats, so n may have rounding errors (such as
* 3.1000000004 instead of 3.1). As long as only addition/subtraction
* occurs between x and y, the specificity of the result will never
* increase, so x and y should be passed in as the references.
*
* If multiplication, division, or other operations were used to
* calculate n, the rounded result may have less specificity than
* desired. For example, 1 / 3 = 0.33333(...), but
* roundToMaxDecimalPlaces((1 / 3), 1, 3) will return 0, since both
* 1 and 3 are whole numbers.
*
* Note that extremely precise reference numbers may lead to rounding
* errors not being trimmed, due to the error result having the same or
* fewer decimal places as the reference(s). This is acceptable as we
* would not be able to tell the difference between a rounding error
* and correct value in this case, but it does mean there is an implicit
* precision limit. If precision that high is needed, it is recommended
* to use a third party data type designed to handle floating point
* errors instead.
*
* @param n The number to round.
* @param references Number(s) used to calculate n, or that should otherwise
* be used as a reference for the desired specificity.
*/
function roundToMaxDecimalPlaces(n, ...references) {
if (!isSafeNumber(n))
return 0;
const maxPlaces = Math.max(...references.map((r) => getDecimalPlaces(r)));
return Number(n.toFixed(maxPlaces));
}
const rangeIosCss = ":host{--knob-handle-size:calc(var(--knob-size) * 2);display:-ms-flexbox;display:flex;position:relative;-ms-flex:3;flex:3;-ms-flex-align:center;align-items:center;font-family:var(--ion-font-family, inherit);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.range-disabled){pointer-events:none}::slotted(ion-label){-ms-flex:initial;flex:initial}::slotted(ion-icon[slot]){font-size:24px}.range-slider{position:relative;-ms-flex:1;flex:1;width:100%;height:var(--height);contain:size layout style;cursor:-webkit-grab;cursor:grab;-ms-touch-action:pan-y;touch-action:pan-y}:host(.range-pressed) .range-slider{cursor:-webkit-grabbing;cursor:grabbing}.range-pin{position:absolute;background:var(--ion-color-base);color:var(--ion-color-contrast);text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box}.range-knob-handle{top:calc((var(--height) - var(--knob-handle-size)) / 2);-webkit-margin-start:calc(0px - var(--knob-handle-size) / 2);margin-inline-start:calc(0px - var(--knob-handle-size) / 2);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-pack:center;justify-content:center;width:var(--knob-handle-size);height:var(--knob-handle-size);text-align:center}.range-knob-handle{inset-inline-start:0}:host-context([dir=rtl]) .range-knob-handle{left:unset}[dir=rtl] .range-knob-handle{left:unset}@supports selector(:dir(rtl)){.range-knob-handle:dir(rtl){left:unset}}.range-knob-handle:active,.range-knob-handle:focus{outline:none}.range-bar-container{border-radius:var(--bar-border-radius);top:calc((var(--height) - var(--bar-height)) / 2);position:absolute;width:100%;height:var(--bar-height)}.range-bar-container{inset-inline-start:0}:host-context([dir=rtl]) .range-bar-container{left:unset}[dir=rtl] .range-bar-container{left:unset}@supports selector(:dir(rtl)){.range-bar-container:dir(rtl){left:unset}}.range-bar{border-radius:var(--bar-border-radius);position:absolute;width:100%;height:var(--bar-height);background:var(--bar-background);pointer-events:none}.range-knob{border-radius:var(--knob-border-radius);top:calc(50% - var(--knob-size) / 2);position:absolute;width:var(--knob-size);height:var(--knob-size);background:var(--knob-background);-webkit-box-shadow:var(--knob-box-shadow);box-shadow:var(--knob-box-shadow);z-index:2;pointer-events:none}.range-knob{inset-inline-start:calc(50% - var(--knob-size) / 2)}:host-context([dir=rtl]) .range-knob{left:unset}[dir=rtl] .range-knob{left:unset}@supports selector(:dir(rtl)){.range-knob:dir(rtl){left:unset}}:host(.range-pressed) .range-bar-active{will-change:left, right}:host(.in-item){width:100%}:host([slot=start]),:host([slot=end]){width:auto}:host(.in-item) ::slotted(ion-label){-ms-flex-item-align:center;align-self:center}.range-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;height:inherit}::slotted([slot=label]){max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}:host(.range-label-placement-start) .range-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.range-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.range-label-placement-end) .range-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.range-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}:host(.range-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.range-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.range-label-placement-stacked) .range-wrapper{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch}:host(.range-label-placement-stacked) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host-context([dir=rtl]):host(.range-label-placement-stacked) .label-text-wrapper,:host-context([dir=rtl]).range-label-placement-stacked .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.range-label-placement-stacked:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.in-item.range-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.range-label-placement-stacked) .native-wrapper{margin-bottom:0px}:host{--knob-border-radius:50%;--knob-background:#ffffff;--knob-box-shadow:0px 0.5px 4px rgba(0, 0, 0, 0.12), 0px 6px 13px rgba(0, 0, 0, 0.12);--knob-size:26px;--bar-height:4px;--bar-background:var(--ion-color-step-900, var(--ion-background-color-step-900, #e6e6e6));--bar-background-active:var(--ion-color-primary, #0054e9);--bar-border-radius:2px;--height:42px}:host(.range-item-start-adjustment){-webkit-padding-start:24px;padding-inline-start:24px}:host(.range-item-end-adjustment){-webkit-padding-end:24px;padding-inline-end:24px}:host(.ion-color) .range-bar-active,:host(.ion-color) .range-tick-active{background:var(--ion-color-base)}::slotted([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}::slotted([slot=end]){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}:host(.range-has-pin:not(.range-label-placement-stacked)){padding-top:calc(8px + 0.75rem)}:host(.range-has-pin.range-label-placement-stacked) .label-text-wrapper{margin-bottom:calc(8px + 0.75rem)}.range-bar-active{bottom:0;width:auto;background:var(--bar-background-active)}.range-bar-active.has-ticks{border-radius:0;-webkit-margin-start:-2px;margin-inline-start:-2px;-webkit-margin-end:-2px;margin-inline-end:-2px}.range-tick{-webkit-margin-start:-2px;margin-inline-start:-2px;border-radius:0;position:absolute;top:17px;width:4px;height:8px;background:var(--ion-color-step-900, var(--ion-background-color-step-900, #e6e6e6));pointer-events:none}.range-tick-active{background:var(--bar-background-active)}.range-pin{-webkit-transform:translate3d(0, 100%, 0) scale(0.01);transform:translate3d(0, 100%, 0) scale(0.01);-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:8px;padding-bottom:8px;min-width:28px;-webkit-transition:-webkit-transform 120ms ease;transition:-webkit-transform 120ms ease;transition:transform 120ms ease;transition:transform 120ms ease, -webkit-transform 120ms ease;background:transparent;color:var(--ion-text-color, #000);font-size:0.75rem;text-align:center}.range-knob-pressed .range-pin,.range-knob-handle.ion-focused .range-pin{-webkit-transform:translate3d(0, calc(-100% + 11px), 0) scale(1);transform:translate3d(0, calc(-100% + 11px), 0) scale(1)}:host(.range-disabled){opacity:0.3}";
const rangeMdCss = ":host{--knob-handle-size:calc(var(--knob-size) * 2);display:-ms-flexbox;display:flex;position:relative;-ms-flex:3;flex:3;-ms-flex-align:center;align-items:center;font-family:var(--ion-font-family, inherit);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.range-disabled){pointer-events:none}::slotted(ion-label){-ms-flex:initial;flex:initial}::slotted(ion-icon[slot]){font-size:24px}.range-slider{position:relative;-ms-flex:1;flex:1;width:100%;height:var(--height);contain:size layout style;cursor:-webkit-grab;cursor:grab;-ms-touch-action:pan-y;touch-action:pan-y}:host(.range-pressed) .range-slider{cursor:-webkit-grabbing;cursor:grabbing}.range-pin{position:absolute;background:var(--ion-color-base);color:var(--ion-color-contrast);text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box}.range-knob-handle{top:calc((var(--height) - var(--knob-handle-size)) / 2);-webkit-margin-start:calc(0px - var(--knob-handle-size) / 2);margin-inline-start:calc(0px - var(--knob-handle-size) / 2);display:-ms-flexbox;display:flex;position:absolute;-ms-flex-pack:center;justify-content:center;width:var(--knob-handle-size);height:var(--knob-handle-size);text-align:center}.range-knob-handle{inset-inline-start:0}:host-context([dir=rtl]) .range-knob-handle{left:unset}[dir=rtl] .range-knob-handle{left:unset}@supports selector(:dir(rtl)){.range-knob-handle:dir(rtl){left:unset}}.range-knob-handle:active,.range-knob-handle:focus{outline:none}.range-bar-container{border-radius:var(--bar-border-radius);top:calc((var(--height) - var(--bar-height)) / 2);position:absolute;width:100%;height:var(--bar-height)}.range-bar-container{inset-inline-start:0}:host-context([dir=rtl]) .range-bar-container{left:unset}[dir=rtl] .range-bar-container{left:unset}@supports selector(:dir(rtl)){.range-bar-container:dir(rtl){left:unset}}.range-bar{border-radius:var(--bar-border-radius);position:absolute;width:100%;height:var(--bar-height);background:var(--bar-background);pointer-events:none}.range-knob{border-radius:var(--knob-border-radius);top:calc(50% - var(--knob-size) / 2);position:absolute;width:var(--knob-size);height:var(--knob-size);background:var(--knob-background);-webkit-box-shadow:var(--knob-box-shadow);box-shadow:var(--knob-box-shadow);z-index:2;pointer-events:none}.range-knob{inset-inline-start:calc(50% - var(--knob-size) / 2)}:host-context([dir=rtl]) .range-knob{left:unset}[dir=rtl] .range-knob{left:unset}@supports selector(:dir(rtl)){.range-knob:dir(rtl){left:unset}}:host(.range-pressed) .range-bar-active{will-change:left, right}:host(.in-item){width:100%}:host([slot=start]),:host([slot=end]){width:auto}:host(.in-item) ::slotted(ion-label){-ms-flex-item-align:center;align-self:center}.range-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;height:inherit}::slotted([slot=label]){max-width:200px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center}:host(.range-label-placement-start) .range-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.range-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.range-label-placement-end) .range-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.range-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}:host(.range-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.range-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.range-label-placement-stacked) .range-wrapper{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:stretch;align-items:stretch}:host(.range-label-placement-stacked) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host-context([dir=rtl]):host(.range-label-placement-stacked) .label-text-wrapper,:host-context([dir=rtl]).range-label-placement-stacked .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.range-label-placement-stacked:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.in-item.range-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.range-label-placement-stacked) .native-wrapper{margin-bottom:0px}:host{--knob-border-radius:50%;--knob-background:var(--bar-background-active);--knob-box-shadow:none;--knob-size:18px;--bar-height:2px;--bar-background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.26);--bar-background-active:var(--ion-color-primary, #0054e9);--bar-border-radius:0;--height:42px;--pin-background:var(--ion-color-primary, #0054e9);--pin-color:var(--ion-color-primary-contrast, #fff)}::slotted(:not(ion-icon)[slot=start]),::slotted(:not(ion-icon)[slot=end]),.native-wrapper{font-size:0.75rem}:host(.range-item-start-adjustment){-webkit-padding-start:18px;padding-inline-start:18px}:host(.range-item-end-adjustment){-webkit-padding-end:18px;padding-inline-end:18px}:host(.ion-color) .range-bar{background:rgba(var(--ion-color-base-rgb), 0.26)}:host(.ion-color) .range-bar-active,:host(.ion-color) .range-knob,:host(.ion-color) .range-knob::before,:host(.ion-color) .range-pin,:host(.ion-color) .range-pin::before,:host(.ion-color) .range-tick{background:var(--ion-color-base);color:var(--ion-color-contrast)}::slotted([slot=start]){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:14px;margin-inline-end:14px;margin-top:0;margin-bottom:0}::slotted([slot=end]){-webkit-margin-start:14px;margin-inline-start:14px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}:host(.range-has-pin:not(.range-label-placement-stacked)){padding-top:1.75rem}:host(.range-has-pin.range-label-placement-stacked) .label-text-wrapper{margin-bottom:1.75rem}.range-bar-active{bottom:0;width:auto;background:var(--bar-background-active)}.range-knob{-webkit-transform:scale(0.67);transform:scale(0.67);-webkit-transition-duration:120ms;transition-duration:120ms;-webkit-transition-property:background-color, border, -webkit-transform;transition-property:background-color, border, -webkit-transform;transition-property:transform, background-color, border;transition-property:transform, background-color, border, -webkit-transform;-webkit-transition-timing-function:ease;transition-timing-function:ease;z-index:2}.range-knob::before{border-radius:50%;position:absolute;width:var(--knob-size);height:var(--knob-size);-webkit-transform:scale(1);transform:scale(1);-webkit-transition:0.267s cubic-bezier(0, 0, 0.58, 1);transition:0.267s cubic-bezier(0, 0, 0.58, 1);background:var(--knob-background);content:\"\";opacity:0.13;pointer-events:none}.range-knob::before{inset-inline-start:0}.range-tick{position:absolute;top:calc((var(--height) - var(--bar-height)) / 2);width:var(--bar-height);height:var(--bar-height);background:var(--bar-background-active);z-index:1;pointer-events:none}.range-tick-active{background:transparent}.range-pin{padding-left:0;padding-right:0;padding-top:8px;padding-bottom:8px;border-radius:50%;-webkit-transform:translate3d(0, 0, 0) scale(0.01);transform:translate3d(0, 0, 0) scale(0.01);display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:1.75rem;height:1.75rem;-webkit-transition:background 120ms ease, -webkit-transform 120ms ease;transition:background 120ms ease, -webkit-transform 120ms ease;transition:transform 120ms ease, background 120ms ease;transition:transform 120ms ease, background 120ms ease, -webkit-transform 120ms ease;background:var(--pin-background);color:var(--pin-color)}.range-pin::before{bottom:-1px;-webkit-margin-start:-13px;margin-inline-start:-13px;border-radius:50% 50% 50% 0;position:absolute;width:26px;height:26px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transition:background 120ms ease;transition:background 120ms ease;background:var(--pin-background);content:\"\";z-index:-1}.range-pin::before{inset-inline-start:50%}:host-context([dir=rtl]) .range-pin::before{left:unset}[dir=rtl] .range-pin::before{left:unset}@supports selector(:dir(rtl)){.range-pin::before:dir(rtl){left:unset}}.range-knob-pressed .range-pin,.range-knob-handle.ion-focused .range-pin{-webkit-transform:translate3d(0, calc(-100% + 4px), 0) scale(1);transform:translate3d(0, calc(-100% + 4px), 0) scale(1)}@media (any-hover: hover){.range-knob-handle:hover .range-knob:before{-webkit-transform:scale(2);transform:scale(2);opacity:0.13}}.range-knob-handle.ion-activated .range-knob:before,.range-knob-handle.ion-focused .range-knob:before,.range-knob-handle.range-knob-pressed .range-knob:before{-webkit-transform:scale(2);transform:scale(2)}.range-knob-handle.ion-focused .range-knob::before{opacity:0.13}.range-knob-handle.ion-activated .range-knob::before,.range-knob-handle.range-knob-pressed .range-knob::before{opacity:0.25}:host(:not(.range-has-pin)) .range-knob-pressed .range-knob,:host(:not(.range-has-pin)) .range-knob-handle.ion-focused .range-knob{-webkit-transform:scale(1);transform:scale(1)}:host(.range-disabled) .range-bar-active,:host(.range-disabled) .range-bar,:host(.range-disabled) .range-tick{background-color:var(--ion-color-step-250, var(--ion-background-color-step-250, #bfbfbf))}:host(.range-disabled) .range-knob{-webkit-transform:scale(0.55);transform:scale(0.55);outline:5px solid #fff;background-color:var(--ion-color-step-250, var(--ion-background-color-step-250, #bfbfbf))}:host(.range-disabled) .label-text-wrapper,:host(.range-disabled) ::slotted([slot=start]),:host(.range-disabled) ::slotted([slot=end]){opacity:0.38}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot label - The label text to associate with the range. Use the "labelPlacement" property to control where the label is placed relative to the range.
* @slot start - Content is placed to the left of the range slider in LTR, and to the right in RTL.
* @slot end - Content is placed to the right of the range slider in LTR, and to the left in RTL.
*
* @part tick - An inactive tick mark.
* @part tick-active - An active tick mark.
* @part pin - The counter that appears above a knob.
* @part knob - The handle that is used to drag the range.
* @part bar - The inactive part of the bar.
* @part bar-active - The active part of the bar.
* @part label - The label text describing the range.
*/
class Range {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionInput = createEvent(this, "ionInput", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionKnobMoveStart = createEvent(this, "ionKnobMoveStart", 7);
this.ionKnobMoveEnd = createEvent(this, "ionKnobMoveEnd", 7);
this.rangeId = `ion-r-${rangeIds++}`;
this.didLoad = false;
this.noUpdate = false;
this.hasFocus = false;
this.inheritedAttributes = {};
this.contentEl = null;
this.initialContentScrollY = true;
this.ratioA = 0;
this.ratioB = 0;
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.rangeId;
/**
* Show two knobs.
*/
this.dualKnobs = false;
/**
* Minimum integer value of the range.
*/
this.min = 0;
/**
* Maximum integer value of the range.
*/
this.max = 100;
/**
* If `true`, a pin with integer value is shown when the knob
* is pressed.
*/
this.pin = false;
/**
* A callback used to format the pin text.
* By default the pin text is set to `Math.round(value)`.
*
* See https://ionicframework.com/docs/troubleshooting/runtime#accessing-this
* if you need to access `this` from within the callback.
*/
this.pinFormatter = (value) => Math.round(value);
/**
* If `true`, the knob snaps to tick marks evenly spaced based
* on the step property value.
*/
this.snaps = false;
/**
* Specifies the value granularity.
*/
this.step = 1;
/**
* If `true`, tick marks are displayed based on the step value.
* Only applies when `snaps` is `true`.
*/
this.ticks = true;
/**
* If `true`, the user cannot interact with the range.
*/
this.disabled = false;
/**
* the value of the range.
*/
this.value = 0;
/**
* Compares two RangeValue inputs to determine if they are different.
*
* @param newVal - The new value.
* @param oldVal - The old value.
* @returns `true` if the values are different, `false` otherwise.
*/
this.compareValues = (newVal, oldVal) => {
if (typeof newVal === 'object' && typeof oldVal === 'object') {
return newVal.lower !== oldVal.lower || newVal.upper !== oldVal.upper;
}
return newVal !== oldVal;
};
this.clampBounds = (value) => {
return clamp(this.min, value, this.max);
};
this.ensureValueInBounds = (value) => {
if (this.dualKnobs) {
return {
lower: this.clampBounds(value.lower),
upper: this.clampBounds(value.upper),
};
}
else {
return this.clampBounds(value);
}
};
/**
* Where to place the label relative to the range.
* `"start"`: The label will appear to the left of the range in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the range in LTR and to the left in RTL.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
* `"stacked"`: The label will appear above the range regardless of the direction.
*/
this.labelPlacement = 'start';
this.setupGesture = async () => {
const rangeSlider = this.rangeSlider;
if (rangeSlider) {
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: rangeSlider,
gestureName: 'range',
gesturePriority: 100,
/**
* Provide a threshold since the drag movement
* might be a user scrolling the view.
* If this is true, then the range
* should not move.
*/
threshold: 10,
onStart: () => this.onStart(),
onMove: (ev) => this.onMove(ev),
onEnd: (ev) => this.onEnd(ev),
});
this.gesture.enable(!this.disabled);
}
};
this.handleKeyboard = (knob, isIncrease) => {
const { ensureValueInBounds } = this;
let step = this.step;
step = step > 0 ? step : 1;
step = step / (this.max - this.min);
if (!isIncrease) {
step *= -1;
}
if (knob === 'A') {
this.ratioA = clamp(0, this.ratioA + step, 1);
}
else {
this.ratioB = clamp(0, this.ratioB + step, 1);
}
this.ionKnobMoveStart.emit({ value: ensureValueInBounds(this.value) });
this.updateValue();
this.emitValueChange();
this.ionKnobMoveEnd.emit({ value: ensureValueInBounds(this.value) });
};
this.onBlur = () => {
if (this.hasFocus) {
this.hasFocus = false;
this.ionBlur.emit();
}
};
this.onFocus = () => {
if (!this.hasFocus) {
this.hasFocus = true;
this.ionFocus.emit();
}
};
this.onKnobFocus = (knob) => {
if (!this.hasFocus) {
this.hasFocus = true;
this.ionFocus.emit();
}
// Manually manage ion-focused class for dual knobs
if (this.dualKnobs && this.el.shadowRoot) {
const knobA = this.el.shadowRoot.querySelector('.range-knob-a');
const knobB = this.el.shadowRoot.querySelector('.range-knob-b');
// Remove ion-focused from both knobs first
knobA === null || knobA === void 0 ? void 0 : knobA.classList.remove('ion-focused');
knobB === null || knobB === void 0 ? void 0 : knobB.classList.remove('ion-focused');
// Add ion-focused only to the focused knob
const focusedKnobEl = knob === 'A' ? knobA : knobB;
focusedKnobEl === null || focusedKnobEl === void 0 ? void 0 : focusedKnobEl.classList.add('ion-focused');
}
};
this.onKnobBlur = () => {
// Check if focus is moving to another knob within the same range
// by delaying the reset to allow the new focus to register
setTimeout(() => {
var _a;
const activeElement = (_a = this.el.shadowRoot) === null || _a === void 0 ? void 0 : _a.activeElement;
const isStillFocusedOnKnob = activeElement && activeElement.classList.contains('range-knob-handle');
if (!isStillFocusedOnKnob) {
if (this.hasFocus) {
this.hasFocus = false;
this.ionBlur.emit();
}
// Remove ion-focused from both knobs when focus leaves the range
if (this.dualKnobs && this.el.shadowRoot) {
const knobA = this.el.shadowRoot.querySelector('.range-knob-a');
const knobB = this.el.shadowRoot.querySelector('.range-knob-b');
knobA === null || knobA === void 0 ? void 0 : knobA.classList.remove('ion-focused');
knobB === null || knobB === void 0 ? void 0 : knobB.classList.remove('ion-focused');
}
}
}, 0);
};
}
debounceChanged() {
const { ionInput, debounce, originalIonInput } = this;
/**
* If debounce is undefined, we have to manually revert the ionInput emitter in case
* debounce used to be set to a number. Otherwise, the event would stay debounced.
*/
this.ionInput = debounce === undefined ? originalIonInput !== null && originalIonInput !== void 0 ? originalIonInput : ionInput : debounceEvent(ionInput, debounce);
}
minChanged(newValue) {
if (!isSafeNumber(newValue)) {
this.min = 0;
}
if (!this.noUpdate) {
this.updateRatio();
}
}
maxChanged(newValue) {
if (!isSafeNumber(newValue)) {
this.max = 100;
}
if (!this.noUpdate) {
this.updateRatio();
}
}
stepChanged(newValue) {
if (!isSafeNumber(newValue)) {
this.step = 1;
}
}
activeBarStartChanged() {
const { activeBarStart } = this;
if (activeBarStart !== undefined) {
if (activeBarStart > this.max) {
printIonWarning(`[ion-range] - The value of activeBarStart (${activeBarStart}) is greater than the max (${this.max}). Valid values are greater than or equal to the min value and less than or equal to the max value.`, this.el);
this.activeBarStart = this.max;
}
else if (activeBarStart < this.min) {
printIonWarning(`[ion-range] - The value of activeBarStart (${activeBarStart}) is less than the min (${this.min}). Valid values are greater than or equal to the min value and less than or equal to the max value.`, this.el);
this.activeBarStart = this.min;
}
}
}
disabledChanged() {
if (this.gesture) {
this.gesture.enable(!this.disabled);
}
}
valueChanged(newValue, oldValue) {
const valuesChanged = this.compareValues(newValue, oldValue);
if (valuesChanged) {
this.ionInput.emit({ value: this.value });
}
if (!this.noUpdate) {
this.updateRatio();
}
}
componentWillLoad() {
/**
* If user has custom ID set then we should
* not assign the default incrementing ID.
*/
if (this.el.hasAttribute('id')) {
this.rangeId = this.el.getAttribute('id');
}
this.inheritedAttributes = inheritAriaAttributes(this.el);
// If min, max, or step are not safe, set them to 0, 100, and 1, respectively.
// Each watch does this, but not before the initial load.
this.min = isSafeNumber(this.min) ? this.min : 0;
this.max = isSafeNumber(this.max) ? this.max : 100;
this.step = isSafeNumber(this.step) ? this.step : 1;
}
componentDidLoad() {
this.originalIonInput = this.ionInput;
this.setupGesture();
this.updateRatio();
this.didLoad = true;
}
connectedCallback() {
var _a;
this.updateRatio();
this.debounceChanged();
this.disabledChanged();
this.activeBarStartChanged();
/**
* If we have not yet rendered
* ion-range, then rangeSlider is not defined.
* But if we are moving ion-range via appendChild,
* then rangeSlider will be defined.
*/
if (this.didLoad) {
this.setupGesture();
}
const ionContent = findClosestIonContent(this.el);
this.contentEl = (_a = ionContent === null || ionContent === void 0 ? void 0 : ionContent.querySelector('.ion-content-scroll-host')) !== null && _a !== void 0 ? _a : ionContent;
}
disconnectedCallback() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
getValue() {
var _a;
const value = (_a = this.value) !== null && _a !== void 0 ? _a : 0;
if (this.dualKnobs) {
if (typeof value === 'object') {
return value;
}
return {
lower: 0,
upper: value,
};
}
else {
if (typeof value === 'object') {
return value.upper;
}
return value;
}
}
/**
* Emits an `ionChange` event.
*
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitValueChange() {
this.value = this.ensureValueInBounds(this.value);
this.ionChange.emit({ value: this.value });
}
/**
* The value should be updated on touch end or
* when the component is being dragged.
* This follows the native behavior of mobile devices.
*
* For example: When the user lifts their finger from the
* screen after tapping the bar or dragging the bar or knob.
*/
onStart() {
this.ionKnobMoveStart.emit({ value: this.ensureValueInBounds(this.value) });
}
/**
* The value should be updated while dragging the
* bar or knob.
*
* While the user is dragging, the view
* should not scroll. This is to prevent the user from
* feeling disoriented while dragging.
*
* The user can scroll on the view if the knob or
* bar is not being dragged.
*
* @param detail The details of the gesture event.
*/
onMove(detail) {
const { contentEl, pressedKnob } = this;
const currentX = detail.currentX;
/**
* Since the user is dragging on the bar or knob, the view should not scroll.
*
* This only needs to be done once.
*/
if (contentEl && this.pressedKnob === undefined) {
this.initialContentScrollY = disableContentScrollY(contentEl);
}
/**
* The `pressedKnob` can be undefined if the user just
* started dragging the knob.
*
* This is necessary to determine which knob the user is dragging,
* especially when it's a dual knob.
* Plus, it determines when to apply certain styles.
*
* This only needs to be done once since the knob won't change
* while the user is dragging.
*/
if (pressedKnob === undefined) {
this.setPressedKnob(currentX);
}
this.update(currentX);
}
/**
* The value should be updated on touch end:
* - When the user lifts their finger from the screen after
* tapping the bar.
*
* @param detail The details of the gesture or mouse event.
*/
onEnd(detail) {
var _a;
const { contentEl, initialContentScrollY } = this;
const currentX = (_a = detail.currentX) !== null && _a !== void 0 ? _a : detail.clientX;
/**
* The `pressedKnob` can be undefined if the user never
* dragged the knob. They just tapped on the bar.
*
* This is necessary to determine which knob the user is changing,
* especially when it's a dual knob.
* Plus, it determines when to apply certain styles.
*/
if (this.pressedKnob === undefined) {
this.setPressedKnob(currentX);
}
/**
* The user is no longer dragging the bar or
* knob (if they were dragging it).
*
* The user can now scroll on the view in the next gesture event.
*/
if (contentEl && this.pressedKnob !== undefined) {
resetContentScrollY(contentEl, initialContentScrollY);
}
// update the active knob's position
this.update(currentX);
/**
* Reset the pressed knob to undefined since the user
* may start dragging a different knob in the next gesture event.
*/
this.pressedKnob = undefined;
this.emitValueChange();
this.ionKnobMoveEnd.emit({ value: this.ensureValueInBounds(this.value) });
}
update(currentX) {
// figure out where the pointer is currently at
// update the knob being interacted with
const rect = this.rect;
let ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
if (isRTL$1(this.el)) {
ratio = 1 - ratio;
}
if (this.snaps) {
// snaps the ratio to the current value
ratio = valueToRatio(ratioToValue(ratio, this.min, this.max, this.step), this.min, this.max);
}
// update which knob is pressed
if (this.pressedKnob === 'A') {
this.ratioA = ratio;
}
else {
this.ratioB = ratio;
}
// Update input value
this.updateValue();
}
setPressedKnob(currentX) {
const rect = (this.rect = this.rangeSlider.getBoundingClientRect());
// figure out which knob they started closer to
let ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
if (isRTL$1(this.el)) {
ratio = 1 - ratio;
}
this.pressedKnob = !this.dualKnobs || Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio) ? 'A' : 'B';
this.setFocus(this.pressedKnob);
}
get valA() {
return ratioToValue(this.ratioA, this.min, this.max, this.step);
}
get valB() {
return ratioToValue(this.ratioB, this.min, this.max, this.step);
}
get ratioLower() {
if (this.dualKnobs) {
return Math.min(this.ratioA, this.ratioB);
}
const { activeBarStart } = this;
if (activeBarStart == null) {
return 0;
}
return valueToRatio(activeBarStart, this.min, this.max);
}
get ratioUpper() {
if (this.dualKnobs) {
return Math.max(this.ratioA, this.ratioB);
}
return this.ratioA;
}
updateRatio() {
const value = this.getValue();
const { min, max } = this;
if (this.dualKnobs) {
this.ratioA = valueToRatio(value.lower, min, max);
this.ratioB = valueToRatio(value.upper, min, max);
}
else {
this.ratioA = valueToRatio(value, min, max);
}
}
updateValue() {
this.noUpdate = true;
const { valA, valB } = this;
this.value = !this.dualKnobs
? valA
: {
lower: Math.min(valA, valB),
upper: Math.max(valA, valB),
};
this.noUpdate = false;
}
setFocus(knob) {
if (this.el.shadowRoot) {
const knobEl = this.el.shadowRoot.querySelector(knob === 'A' ? '.range-knob-a' : '.range-knob-b');
if (knobEl) {
knobEl.focus();
}
}
}
/**
* Returns true if content was passed to the "start" slot
*/
get hasStartSlotContent() {
return this.el.querySelector('[slot="start"]') !== null;
}
/**
* Returns true if content was passed to the "end" slot
*/
get hasEndSlotContent() {
return this.el.querySelector('[slot="end"]') !== null;
}
get hasLabel() {
return this.label !== undefined || this.el.querySelector('[slot="label"]') !== null;
}
renderRangeSlider() {
var _a;
const { min, max, step, handleKeyboard, pressedKnob, disabled, pin, ratioLower, ratioUpper, pinFormatter, inheritedAttributes, } = this;
let barStart = `${ratioLower * 100}%`;
let barEnd = `${100 - ratioUpper * 100}%`;
const rtl = isRTL$1(this.el);
const start = rtl ? 'right' : 'left';
const end = rtl ? 'left' : 'right';
const tickStyle = (tick) => {
return {
[start]: tick[start],
};
};
if (this.dualKnobs === false) {
/**
* When the value is less than the activeBarStart or the min value,
* the knob will display at the start of the active bar.
*/
if (this.valA < ((_a = this.activeBarStart) !== null && _a !== void 0 ? _a : this.min)) {
/**
* Sets the bar positions relative to the upper and lower limits.
* Converts the ratio values into percentages, used as offsets for left/right styles.
*
* The ratioUpper refers to the knob position on the bar.
* The ratioLower refers to the end position of the active bar (the value).
*/
barStart = `${ratioUpper * 100}%`;
barEnd = `${100 - ratioLower * 100}%`;
}
else {
/**
* Otherwise, the knob will display at the end of the active bar.
*
* The ratioLower refers to the start position of the active bar (the value).
* The ratioUpper refers to the knob position on the bar.
*/
barStart = `${ratioLower * 100}%`;
barEnd = `${100 - ratioUpper * 100}%`;
}
}
const barStyle = {
[start]: barStart,
[end]: barEnd,
};
const ticks = [];
if (this.snaps && this.ticks) {
for (let value = min; value <= max; value += step) {
const ratio = valueToRatio(value, min, max);
const ratioMin = Math.min(ratioLower, ratioUpper);
const ratioMax = Math.max(ratioLower, ratioUpper);
const tick = {
ratio,
/**
* Sets the tick mark as active when the tick is between the min bounds and the knob.
* When using activeBarStart, the tick mark will be active between the knob and activeBarStart.
*/
active: ratio >= ratioMin && ratio <= ratioMax,
};
tick[start] = `${ratio * 100}%`;
ticks.push(tick);
}
}
return (hAsync("div", { class: "range-slider", ref: (rangeEl) => (this.rangeSlider = rangeEl),
/**
* Since the gesture has a threshold, the value
* won't change until the user has dragged past
* the threshold. This is to prevent the range
* from moving when the user is scrolling.
*
* This results in the value not being updated
* and the event emitters not being triggered
* if the user taps on the range. This is why
* we need to listen for the "pointerUp" event.
*/
onPointerUp: (ev) => {
/**
* If the user drags the knob on the web
* version (does not occur on mobile),
* the "pointerUp" event will be triggered
* along with the gesture's events.
* This leads to duplicate events.
*
* By checking if the pressedKnob is undefined,
* we can determine if the "pointerUp" event was
* triggered by a tap or a drag. If it was
* dragged, the pressedKnob will be defined.
*/
if (this.pressedKnob === undefined) {
this.onStart();
this.onEnd(ev);
}
} }, ticks.map((tick) => (hAsync("div", { style: tickStyle(tick), role: "presentation", class: {
'range-tick': true,
'range-tick-active': tick.active,
}, part: tick.active ? 'tick-active' : 'tick' }))), hAsync("div", { class: "range-bar-container" }, hAsync("div", { class: "range-bar", role: "presentation", part: "bar" }), hAsync("div", { class: {
'range-bar': true,
'range-bar-active': true,
'has-ticks': ticks.length > 0,
}, role: "presentation", style: barStyle, part: "bar-active" })), renderKnob(rtl, {
knob: 'A',
pressed: pressedKnob === 'A',
value: this.valA,
ratio: this.ratioA,
pin,
pinFormatter,
disabled,
handleKeyboard,
min,
max,
inheritedAttributes,
onKnobFocus: this.onKnobFocus,
onKnobBlur: this.onKnobBlur,
}), this.dualKnobs &&
renderKnob(rtl, {
knob: 'B',
pressed: pressedKnob === 'B',
value: this.valB,
ratio: this.ratioB,
pin,
pinFormatter,
disabled,
handleKeyboard,
min,
max,
inheritedAttributes,
onKnobFocus: this.onKnobFocus,
onKnobBlur: this.onKnobBlur,
})));
}
render() {
const { disabled, el, hasLabel, rangeId, pin, pressedKnob, labelPlacement, label } = this;
const inItem = hostContext('ion-item', el);
/**
* If there is no start content then the knob at
* the min value will be cut off by the item margin.
*/
const hasStartContent = (hasLabel && (labelPlacement === 'start' || labelPlacement === 'fixed')) || this.hasStartSlotContent;
const needsStartAdjustment = inItem && !hasStartContent;
/**
* If there is no end content then the knob at
* the max value will be cut off by the item margin.
*/
const hasEndContent = (hasLabel && labelPlacement === 'end') || this.hasEndSlotContent;
const needsEndAdjustment = inItem && !hasEndContent;
const mode = getIonMode$1(this);
renderHiddenInput(true, el, this.name, JSON.stringify(this.getValue()), disabled);
return (hAsync(Host, { key: 'ef7b01f80515bcaeb2983934ad7f10a6bd5d13ec', onFocusin: this.onFocus, onFocusout: this.onBlur, id: rangeId, class: createColorClasses$1(this.color, {
[mode]: true,
'in-item': inItem,
'range-disabled': disabled,
'range-pressed': pressedKnob !== undefined,
'range-has-pin': pin,
[`range-label-placement-${labelPlacement}`]: true,
'range-item-start-adjustment': needsStartAdjustment,
'range-item-end-adjustment': needsEndAdjustment,
}) }, hAsync("label", { key: 'fd8aa90a9d52be9da024b907e68858dae424449d', class: "range-wrapper", id: "range-label" }, hAsync("div", { key: '2172b4f329c22017dd23475c80aac25ba6e753eb', class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !hasLabel,
}, part: "label" }, label !== undefined ? hAsync("div", { class: "label-text" }, label) : hAsync("slot", { name: "label" })), hAsync("div", { key: '3c318bf2ea0576646d4c010bf44573fd0f483186', class: "native-wrapper" }, hAsync("slot", { key: '6586fd6fc96271e73f8a86c202d1913ad1a26f96', name: "start" }), this.renderRangeSlider(), hAsync("slot", { key: '74ac0bc2d2cb66ef708bb729f88b6ecbc1b2155d', name: "end" })))));
}
get el() { return getElement(this); }
static get watchers() { return {
"debounce": ["debounceChanged"],
"min": ["minChanged"],
"max": ["maxChanged"],
"step": ["stepChanged"],
"activeBarStart": ["activeBarStartChanged"],
"disabled": ["disabledChanged"],
"value": ["valueChanged"]
}; }
static get style() { return {
ios: rangeIosCss,
md: rangeMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-range",
"$members$": {
"color": [513],
"debounce": [2],
"name": [1],
"label": [1],
"dualKnobs": [4, "dual-knobs"],
"min": [2],
"max": [2],
"pin": [4],
"pinFormatter": [16],
"snaps": [4],
"step": [2],
"ticks": [4],
"activeBarStart": [1026, "active-bar-start"],
"disabled": [4],
"value": [1026],
"labelPlacement": [1, "label-placement"],
"ratioA": [32],
"ratioB": [32],
"pressedKnob": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const renderKnob = (rtl, { knob, value, ratio, min, max, disabled, pressed, pin, handleKeyboard, pinFormatter, inheritedAttributes, onKnobFocus, onKnobBlur, }) => {
const start = rtl ? 'right' : 'left';
const knobStyle = () => {
const style = {};
style[start] = `${ratio * 100}%`;
return style;
};
// The aria label should be preferred over visible text if both are specified
const ariaLabel = inheritedAttributes['aria-label'];
return (hAsync("div", { onKeyDown: (ev) => {
const key = ev.key;
if (key === 'ArrowLeft' || key === 'ArrowDown') {
handleKeyboard(knob, false);
ev.preventDefault();
ev.stopPropagation();
}
else if (key === 'ArrowRight' || key === 'ArrowUp') {
handleKeyboard(knob, true);
ev.preventDefault();
ev.stopPropagation();
}
}, onFocus: () => onKnobFocus(knob), onBlur: onKnobBlur, class: {
'range-knob-handle': true,
'range-knob-a': knob === 'A',
'range-knob-b': knob === 'B',
'range-knob-pressed': pressed,
'range-knob-min': value === min,
'range-knob-max': value === max,
'ion-activatable': true,
'ion-focusable': true,
}, style: knobStyle(), role: "slider", tabindex: disabled ? -1 : 0, "aria-label": ariaLabel !== undefined ? ariaLabel : null, "aria-labelledby": ariaLabel === undefined ? 'range-label' : null, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled ? 'true' : null, "aria-valuenow": value }, pin && (hAsync("div", { class: "range-pin", role: "presentation", part: "pin" }, pinFormatter(value))), hAsync("div", { class: "range-knob", role: "presentation", part: "knob" })));
};
const ratioToValue = (ratio, min, max, step) => {
let value = (max - min) * ratio;
if (step > 0) {
// round to nearest multiple of step, then add min
value = Math.round(value / step) * step + min;
}
const clampedValue = clamp(min, value, max);
return roundToMaxDecimalPlaces(clampedValue, min, max, step);
};
const valueToRatio = (value, min, max) => {
return clamp(0, (value - min) / (max - min), 1);
};
let rangeIds = 0;
const getRefresherAnimationType = (contentEl) => {
const previousSibling = contentEl.previousElementSibling;
const hasHeader = previousSibling !== null && previousSibling.tagName === 'ION-HEADER';
return hasHeader ? 'translate' : 'scale';
};
const createPullingAnimation = (type, pullingSpinner, refresherEl) => {
return type === 'scale'
? createScaleAnimation(pullingSpinner, refresherEl)
: createTranslateAnimation(pullingSpinner, refresherEl);
};
const createBaseAnimation = (pullingRefresherIcon) => {
const spinner = pullingRefresherIcon.querySelector('ion-spinner');
const circle = spinner.shadowRoot.querySelector('circle');
const spinnerArrowContainer = pullingRefresherIcon.querySelector('.spinner-arrow-container');
const arrowContainer = pullingRefresherIcon.querySelector('.arrow-container');
const arrow = arrowContainer ? arrowContainer.querySelector('ion-icon') : null;
const baseAnimation = createAnimation().duration(1000).easing('ease-out');
const spinnerArrowContainerAnimation = createAnimation()
.addElement(spinnerArrowContainer)
.keyframes([
{ offset: 0, opacity: '0.3' },
{ offset: 0.45, opacity: '0.3' },
{ offset: 0.55, opacity: '1' },
{ offset: 1, opacity: '1' },
]);
const circleInnerAnimation = createAnimation()
.addElement(circle)
.keyframes([
{ offset: 0, strokeDasharray: '1px, 200px' },
{ offset: 0.2, strokeDasharray: '1px, 200px' },
{ offset: 0.55, strokeDasharray: '100px, 200px' },
{ offset: 1, strokeDasharray: '100px, 200px' },
]);
const circleOuterAnimation = createAnimation()
.addElement(spinner)
.keyframes([
{ offset: 0, transform: 'rotate(-90deg)' },
{ offset: 1, transform: 'rotate(210deg)' },
]);
/**
* Only add arrow animation if present
* this allows users to customize the spinners
* without errors being thrown
*/
if (arrowContainer && arrow) {
const arrowContainerAnimation = createAnimation()
.addElement(arrowContainer)
.keyframes([
{ offset: 0, transform: 'rotate(0deg)' },
{ offset: 0.3, transform: 'rotate(0deg)' },
{ offset: 0.55, transform: 'rotate(280deg)' },
{ offset: 1, transform: 'rotate(400deg)' },
]);
const arrowAnimation = createAnimation()
.addElement(arrow)
.keyframes([
{ offset: 0, transform: 'translateX(2px) scale(0)' },
{ offset: 0.3, transform: 'translateX(2px) scale(0)' },
{ offset: 0.55, transform: 'translateX(-1.5px) scale(1)' },
{ offset: 1, transform: 'translateX(-1.5px) scale(1)' },
]);
baseAnimation.addAnimation([arrowContainerAnimation, arrowAnimation]);
}
return baseAnimation.addAnimation([spinnerArrowContainerAnimation, circleInnerAnimation, circleOuterAnimation]);
};
const createScaleAnimation = (pullingRefresherIcon, refresherEl) => {
/**
* Do not take the height of the refresher icon
* because at this point the DOM has not updated,
* so the refresher icon is still hidden with
* display: none.
* The `ion-refresher` container height
* is roughly the amount we need to offset
* the icon by when pulling down.
*/
const height = refresherEl.clientHeight;
const spinnerAnimation = createAnimation()
.addElement(pullingRefresherIcon)
.keyframes([
{ offset: 0, transform: `scale(0) translateY(-${height}px)` },
{ offset: 1, transform: 'scale(1) translateY(100px)' },
]);
return createBaseAnimation(pullingRefresherIcon).addAnimation([spinnerAnimation]);
};
const createTranslateAnimation = (pullingRefresherIcon, refresherEl) => {
/**
* Do not take the height of the refresher icon
* because at this point the DOM has not updated,
* so the refresher icon is still hidden with
* display: none.
* The `ion-refresher` container height
* is roughly the amount we need to offset
* the icon by when pulling down.
*/
const height = refresherEl.clientHeight;
const spinnerAnimation = createAnimation()
.addElement(pullingRefresherIcon)
.keyframes([
{ offset: 0, transform: `translateY(-${height}px)` },
{ offset: 1, transform: 'translateY(100px)' },
]);
return createBaseAnimation(pullingRefresherIcon).addAnimation([spinnerAnimation]);
};
const createSnapBackAnimation = (pullingRefresherIcon) => {
return createAnimation()
.duration(125)
.addElement(pullingRefresherIcon)
.fromTo('transform', 'translateY(var(--ion-pulling-refresher-translate, 100px))', 'translateY(0px)');
};
// iOS Native Refresher
// -----------------------------
const setSpinnerOpacity = (spinner, opacity) => {
spinner.style.setProperty('opacity', opacity.toString());
};
const handleScrollWhilePulling = (ticks, numTicks, pullAmount) => {
const max = 1;
writeTask(() => {
ticks.forEach((el, i) => {
/**
* Compute the opacity of each tick
* mark as a percentage of the pullAmount
* offset by max / numTicks so
* the tick marks are shown staggered.
*/
const min = i * (max / numTicks);
const range = max - min;
const start = pullAmount - min;
const progression = clamp(0, start / range, 1);
el.style.setProperty('opacity', progression.toString());
});
});
};
const handleScrollWhileRefreshing = (spinner, lastVelocityY) => {
writeTask(() => {
// If user pulls down quickly, the spinner should spin faster
spinner.style.setProperty('--refreshing-rotation-duration', lastVelocityY >= 1.0 ? '0.5s' : '2s');
spinner.style.setProperty('opacity', '1');
});
};
const translateElement = (el, value, duration = 200) => {
if (!el) {
return Promise.resolve();
}
const trans = transitionEndAsync(el, duration);
writeTask(() => {
el.style.setProperty('transition', `${duration}ms all ease-out`);
if (value === undefined) {
el.style.removeProperty('transform');
}
else {
el.style.setProperty('transform', `translate3d(0px, ${value}, 0px)`);
}
});
return trans;
};
// Utils
// -----------------------------
/**
* In order to use the native iOS refresher the device must support rubber band scrolling.
* As part of this, we need to exclude Desktop Safari because it has a slightly different rubber band effect that is not compatible with the native refresher in Ionic.
*
* We also need to be careful not to include devices that spoof their user agent.
* For example, when using iOS emulation in Chrome the user agent will be spoofed such that
* navigator.maxTouchPointer > 0. To work around this,
* we check to see if the apple-pay-logo is supported as a named image which is only
* true on Apple devices.
*
* We previously checked referencEl.style.webkitOverflowScrolling to explicitly check
* for rubber band support. However, this property was removed on iPadOS and it's possible
* that this will be removed on iOS in the future too.
*
*/
const supportsRubberBandScrolling = () => {
return navigator.maxTouchPoints > 0 && CSS.supports('background: -webkit-named-image(apple-pay-logo-black)');
};
const shouldUseNativeRefresher = async (referenceEl, mode) => {
const refresherContent = referenceEl.querySelector('ion-refresher-content');
if (!refresherContent) {
return Promise.resolve(false);
}
await new Promise((resolve) => componentOnReady(refresherContent, resolve));
const pullingSpinner = referenceEl.querySelector('ion-refresher-content .refresher-pulling ion-spinner');
const refreshingSpinner = referenceEl.querySelector('ion-refresher-content .refresher-refreshing ion-spinner');
return (pullingSpinner !== null &&
refreshingSpinner !== null &&
((mode === 'ios' && supportsRubberBandScrolling()) || mode === 'md'));
};
const refresherIosCss = "ion-refresher{top:0;display:none;position:absolute;width:100%;height:60px;pointer-events:none;z-index:-1}ion-refresher{inset-inline-start:0}ion-refresher.refresher-active{display:block}ion-refresher-content{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.refresher-pulling,.refresher-refreshing{display:none;width:100%}.refresher-pulling-icon,.refresher-refreshing-icon{-webkit-transform-origin:center;transform-origin:center;-webkit-transition:200ms;transition:200ms;font-size:30px;text-align:center}:host-context([dir=rtl]) .refresher-pulling-icon,:host-context([dir=rtl]) .refresher-refreshing-icon{-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}[dir=rtl] .refresher-pulling-icon,[dir=rtl] .refresher-refreshing-icon{-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}@supports selector(:dir(rtl)){.refresher-pulling-icon:dir(rtl),.refresher-refreshing-icon:dir(rtl){-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}}.refresher-pulling-text,.refresher-refreshing-text{font-size:16px;text-align:center}ion-refresher-content .arrow-container{display:none}.refresher-pulling ion-refresher-content .refresher-pulling{display:block}.refresher-ready ion-refresher-content .refresher-pulling{display:block}.refresher-ready ion-refresher-content .refresher-pulling-icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.refresher-refreshing ion-refresher-content .refresher-refreshing{display:block}.refresher-cancelling ion-refresher-content .refresher-pulling{display:block}.refresher-cancelling ion-refresher-content .refresher-pulling-icon{-webkit-transform:scale(0);transform:scale(0)}.refresher-completing ion-refresher-content .refresher-refreshing{display:block}.refresher-completing ion-refresher-content .refresher-refreshing-icon{-webkit-transform:scale(0);transform:scale(0)}.refresher-native .refresher-pulling-text,.refresher-native .refresher-refreshing-text{display:none}.refresher-ios .refresher-pulling-icon,.refresher-ios .refresher-refreshing-icon{color:var(--ion-text-color, #000)}.refresher-ios .refresher-pulling-text,.refresher-ios .refresher-refreshing-text{color:var(--ion-text-color, #000)}.refresher-ios .refresher-refreshing .spinner-lines-ios line,.refresher-ios .refresher-refreshing .spinner-lines-small-ios line,.refresher-ios .refresher-refreshing .spinner-crescent circle{stroke:var(--ion-text-color, #000)}.refresher-ios .refresher-refreshing .spinner-bubbles circle,.refresher-ios .refresher-refreshing .spinner-circles circle,.refresher-ios .refresher-refreshing .spinner-dots circle{fill:var(--ion-text-color, #000)}ion-refresher.refresher-native{display:block;z-index:1}ion-refresher.refresher-native ion-spinner{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0}.refresher-native .refresher-refreshing ion-spinner{--refreshing-rotation-duration:2s;display:none;-webkit-animation:var(--refreshing-rotation-duration) ease-out refresher-rotate forwards;animation:var(--refreshing-rotation-duration) ease-out refresher-rotate forwards}.refresher-native .refresher-refreshing{display:none;-webkit-animation:250ms linear refresher-pop forwards;animation:250ms linear refresher-pop forwards}.refresher-native ion-spinner{width:32px;height:32px;color:var(--ion-color-step-450, var(--ion-background-color-step-450, #747577))}.refresher-native.refresher-refreshing .refresher-pulling ion-spinner,.refresher-native.refresher-completing .refresher-pulling ion-spinner{display:none}.refresher-native.refresher-refreshing .refresher-refreshing ion-spinner,.refresher-native.refresher-completing .refresher-refreshing ion-spinner{display:block}.refresher-native.refresher-pulling .refresher-pulling ion-spinner{display:block}.refresher-native.refresher-pulling .refresher-refreshing ion-spinner{display:none}.refresher-native.refresher-completing ion-refresher-content .refresher-refreshing-icon{-webkit-transform:scale(0) rotate(180deg);transform:scale(0) rotate(180deg);-webkit-transition:300ms;transition:300ms}@-webkit-keyframes refresher-pop{0%{-webkit-transform:scale(1);transform:scale(1);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}50%{-webkit-transform:scale(1.2);transform:scale(1.2);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}100%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes refresher-pop{0%{-webkit-transform:scale(1);transform:scale(1);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}50%{-webkit-transform:scale(1.2);transform:scale(1.2);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}100%{-webkit-transform:scale(1);transform:scale(1)}}@-webkit-keyframes refresher-rotate{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(180deg);transform:rotate(180deg)}}@keyframes refresher-rotate{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(180deg);transform:rotate(180deg)}}";
const refresherMdCss = "ion-refresher{top:0;display:none;position:absolute;width:100%;height:60px;pointer-events:none;z-index:-1}ion-refresher{inset-inline-start:0}ion-refresher.refresher-active{display:block}ion-refresher-content{display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;height:100%}.refresher-pulling,.refresher-refreshing{display:none;width:100%}.refresher-pulling-icon,.refresher-refreshing-icon{-webkit-transform-origin:center;transform-origin:center;-webkit-transition:200ms;transition:200ms;font-size:30px;text-align:center}:host-context([dir=rtl]) .refresher-pulling-icon,:host-context([dir=rtl]) .refresher-refreshing-icon{-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}[dir=rtl] .refresher-pulling-icon,[dir=rtl] .refresher-refreshing-icon{-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}@supports selector(:dir(rtl)){.refresher-pulling-icon:dir(rtl),.refresher-refreshing-icon:dir(rtl){-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}}.refresher-pulling-text,.refresher-refreshing-text{font-size:16px;text-align:center}ion-refresher-content .arrow-container{display:none}.refresher-pulling ion-refresher-content .refresher-pulling{display:block}.refresher-ready ion-refresher-content .refresher-pulling{display:block}.refresher-ready ion-refresher-content .refresher-pulling-icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.refresher-refreshing ion-refresher-content .refresher-refreshing{display:block}.refresher-cancelling ion-refresher-content .refresher-pulling{display:block}.refresher-cancelling ion-refresher-content .refresher-pulling-icon{-webkit-transform:scale(0);transform:scale(0)}.refresher-completing ion-refresher-content .refresher-refreshing{display:block}.refresher-completing ion-refresher-content .refresher-refreshing-icon{-webkit-transform:scale(0);transform:scale(0)}.refresher-native .refresher-pulling-text,.refresher-native .refresher-refreshing-text{display:none}.refresher-md .refresher-pulling-icon,.refresher-md .refresher-refreshing-icon{color:var(--ion-text-color, #000)}.refresher-md .refresher-pulling-text,.refresher-md .refresher-refreshing-text{color:var(--ion-text-color, #000)}.refresher-md .refresher-refreshing .spinner-lines-md line,.refresher-md .refresher-refreshing .spinner-lines-small-md line,.refresher-md .refresher-refreshing .spinner-crescent circle{stroke:var(--ion-text-color, #000)}.refresher-md .refresher-refreshing .spinner-bubbles circle,.refresher-md .refresher-refreshing .spinner-circles circle,.refresher-md .refresher-refreshing .spinner-dots circle{fill:var(--ion-text-color, #000)}ion-refresher.refresher-native{display:block;z-index:1}ion-refresher.refresher-native ion-spinner{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;width:24px;height:24px;color:var(--ion-color-primary, #0054e9)}ion-refresher.refresher-native .spinner-arrow-container{display:inherit}ion-refresher.refresher-native .arrow-container{display:block;position:absolute;width:24px;height:24px}ion-refresher.refresher-native .arrow-container ion-icon{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;left:0;right:0;bottom:-4px;position:absolute;color:var(--ion-color-primary, #0054e9);font-size:12px}ion-refresher.refresher-native.refresher-pulling ion-refresher-content .refresher-pulling,ion-refresher.refresher-native.refresher-ready ion-refresher-content .refresher-pulling{display:-ms-flexbox;display:flex}ion-refresher.refresher-native.refresher-refreshing ion-refresher-content .refresher-refreshing,ion-refresher.refresher-native.refresher-completing ion-refresher-content .refresher-refreshing,ion-refresher.refresher-native.refresher-cancelling ion-refresher-content .refresher-refreshing{display:-ms-flexbox;display:flex}ion-refresher.refresher-native .refresher-pulling-icon{-webkit-transform:translateY(calc(-100% - 10px));transform:translateY(calc(-100% - 10px))}ion-refresher.refresher-native .refresher-pulling-icon,ion-refresher.refresher-native .refresher-refreshing-icon{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;border-radius:100%;-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:8px;padding-bottom:8px;display:-ms-flexbox;display:flex;border:1px solid var(--ion-color-step-200, var(--ion-background-color-step-200, #ececec));background:var(--ion-color-step-250, var(--ion-background-color-step-250, #ffffff));-webkit-box-shadow:0px 1px 6px rgba(0, 0, 0, 0.1);box-shadow:0px 1px 6px rgba(0, 0, 0, 0.1)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Refresher {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionRefresh = createEvent(this, "ionRefresh", 7);
this.ionPull = createEvent(this, "ionPull", 7);
this.ionStart = createEvent(this, "ionStart", 7);
this.appliedStyles = false;
this.didStart = false;
this.progress = 0;
this.pointerDown = false;
this.needsCompletion = false;
this.didRefresh = false;
this.contentFullscreen = false;
this.lastVelocityY = 0;
this.animations = [];
this.nativeRefresher = false;
/**
* The current state which the refresher is in. The refresher's states include:
*
* - `inactive` - The refresher is not being pulled down or refreshing and is currently hidden.
* - `pulling` - The user is actively pulling down the refresher, but has not reached the point yet that if the user lets go, it'll refresh.
* - `cancelling` - The user pulled down the refresher and let go, but did not pull down far enough to kick off the `refreshing` state. After letting go, the refresher is in the `cancelling` state while it is closing, and will go back to the `inactive` state once closed.
* - `ready` - The user has pulled down the refresher far enough that if they let go, it'll begin the `refreshing` state.
* - `refreshing` - The refresher is actively waiting on the async operation to end. Once the refresh handler calls `complete()` it will begin the `completing` state.
* - `completing` - The `refreshing` state has finished and the refresher is in the way of closing itself. Once closed, the refresher will go back to the `inactive` state.
*/
this.state = 1 /* RefresherState.Inactive */;
/**
* The minimum distance the user must pull down until the
* refresher will go into the `refreshing` state.
* Does not apply when the refresher content uses a spinner,
* enabling the native refresher.
*/
this.pullMin = 60;
/**
* The maximum distance of the pull until the refresher
* will automatically go into the `refreshing` state.
* Defaults to the result of `pullMin + 60`.
* Does not apply when the refresher content uses a spinner,
* enabling the native refresher.
*/
this.pullMax = this.pullMin + 60;
/**
* Time it takes to close the refresher.
* Does not apply when the refresher content uses a spinner,
* enabling the native refresher.
*/
this.closeDuration = '280ms';
/**
* Time it takes the refresher to snap back to the `refreshing` state.
* Does not apply when the refresher content uses a spinner,
* enabling the native refresher.
*/
this.snapbackDuration = '280ms';
/**
* How much to multiply the pull speed by. To slow the pull animation down,
* pass a number less than `1`. To speed up the pull, pass a number greater
* than `1`. The default value is `1` which is equal to the speed of the cursor.
* If a negative value is passed in, the factor will be `1` instead.
*
* For example: If the value passed is `1.2` and the content is dragged by
* `10` pixels, instead of `10` pixels the content will be pulled by `12` pixels
* (an increase of 20 percent). If the value passed is `0.8`, the dragged amount
* will be `8` pixels, less than the amount the cursor has moved.
*
* Does not apply when the refresher content uses a spinner,
* enabling the native refresher.
*/
this.pullFactor = 1;
/**
* If `true`, the refresher will be hidden.
*/
this.disabled = false;
}
disabledChanged() {
if (this.gesture) {
this.gesture.enable(!this.disabled);
}
}
async checkNativeRefresher() {
const useNativeRefresher = await shouldUseNativeRefresher(this.el, getIonMode$1(this));
if (useNativeRefresher && !this.nativeRefresher) {
const contentEl = this.el.closest('ion-content');
this.setupNativeRefresher(contentEl);
}
else if (!useNativeRefresher) {
this.destroyNativeRefresher();
}
}
destroyNativeRefresher() {
if (this.scrollEl && this.scrollListenerCallback) {
this.scrollEl.removeEventListener('scroll', this.scrollListenerCallback);
this.scrollListenerCallback = undefined;
}
this.nativeRefresher = false;
}
async resetNativeRefresher(el, state) {
this.state = state;
if (getIonMode$1(this) === 'ios') {
await translateElement(el, undefined, 300);
}
else {
await transitionEndAsync(this.el.querySelector('.refresher-refreshing-icon'), 200);
}
this.didRefresh = false;
this.needsCompletion = false;
this.pointerDown = false;
this.animations.forEach((ani) => ani.destroy());
this.animations = [];
this.progress = 0;
this.state = 1 /* RefresherState.Inactive */;
}
async setupiOSNativeRefresher(pullingSpinner, refreshingSpinner) {
this.elementToTransform = this.scrollEl;
const ticks = pullingSpinner.shadowRoot.querySelectorAll('svg');
let MAX_PULL = this.scrollEl.clientHeight * 0.16;
const NUM_TICKS = ticks.length;
writeTask(() => ticks.forEach((el) => el.style.setProperty('animation', 'none')));
this.scrollListenerCallback = () => {
// If pointer is not on screen or refresher is not active, ignore scroll
if (!this.pointerDown && this.state === 1 /* RefresherState.Inactive */) {
return;
}
readTask(() => {
// PTR should only be active when overflow scrolling at the top
const scrollTop = this.scrollEl.scrollTop;
const refresherHeight = this.el.clientHeight;
if (scrollTop > 0) {
/**
* If refresher is refreshing and user tries to scroll
* progressively fade refresher out/in
*/
if (this.state === 8 /* RefresherState.Refreshing */) {
const ratio = clamp(0, scrollTop / (refresherHeight * 0.5), 1);
writeTask(() => setSpinnerOpacity(refreshingSpinner, 1 - ratio));
return;
}
return;
}
if (this.pointerDown) {
if (!this.didStart) {
this.didStart = true;
this.ionStart.emit();
}
// emit "pulling" on every move
if (this.pointerDown) {
this.ionPull.emit();
}
}
/**
* We want to delay the start of this gesture by ~30px
* when initially pulling down so the refresher does not
* overlap with the content. But when letting go of the
* gesture before the refresher completes, we want the
* refresher tick marks to quickly fade out.
*/
const offset = this.didStart ? 30 : 0;
const pullAmount = (this.progress = clamp(0, (Math.abs(scrollTop) - offset) / MAX_PULL, 1));
const shouldShowRefreshingSpinner = this.state === 8 /* RefresherState.Refreshing */ || pullAmount === 1;
if (shouldShowRefreshingSpinner) {
if (this.pointerDown) {
handleScrollWhileRefreshing(refreshingSpinner, this.lastVelocityY);
}
if (!this.didRefresh) {
this.beginRefresh();
this.didRefresh = true;
hapticImpact({ style: ImpactStyle.Light });
/**
* Clear focus from any active element to prevent scroll jumps
* when the refresh completes
*/
const activeElement = document.activeElement;
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
activeElement.blur();
}
/**
* Translate the content element otherwise when pointer is removed
* from screen the scroll content will bounce back over the refresher
*/
if (!this.pointerDown) {
translateElement(this.elementToTransform, `${refresherHeight}px`);
}
}
}
else {
this.state = 2 /* RefresherState.Pulling */;
handleScrollWhilePulling(ticks, NUM_TICKS, pullAmount);
}
});
};
this.scrollEl.addEventListener('scroll', this.scrollListenerCallback);
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: this.scrollEl,
gestureName: 'refresher',
gesturePriority: 31,
direction: 'y',
threshold: 5,
onStart: () => {
this.pointerDown = true;
if (!this.didRefresh) {
translateElement(this.elementToTransform, '0px');
}
/**
* If the content had `display: none` when
* the refresher was initialized, its clientHeight
* will be 0. When the gesture starts, the content
* will be visible, so try to get the correct
* client height again. This is most common when
* using the refresher in an ion-menu.
*/
if (MAX_PULL === 0) {
MAX_PULL = this.scrollEl.clientHeight * 0.16;
}
},
onMove: (ev) => {
this.lastVelocityY = ev.velocityY;
},
onEnd: () => {
this.pointerDown = false;
this.didStart = false;
if (this.needsCompletion) {
this.resetNativeRefresher(this.elementToTransform, 32 /* RefresherState.Completing */);
this.needsCompletion = false;
}
else if (this.didRefresh) {
readTask(() => translateElement(this.elementToTransform, `${this.el.clientHeight}px`));
}
},
});
this.disabledChanged();
}
async setupMDNativeRefresher(contentEl, pullingSpinner, refreshingSpinner) {
const circle = getElementRoot(pullingSpinner).querySelector('circle');
const pullingRefresherIcon = this.el.querySelector('ion-refresher-content .refresher-pulling-icon');
const refreshingCircle = getElementRoot(refreshingSpinner).querySelector('circle');
if (circle !== null && refreshingCircle !== null) {
writeTask(() => {
circle.style.setProperty('animation', 'none');
// This lines up the animation on the refreshing spinner with the pulling spinner
refreshingSpinner.style.setProperty('animation-delay', '-655ms');
refreshingCircle.style.setProperty('animation-delay', '-655ms');
});
}
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: this.scrollEl,
gestureName: 'refresher',
gesturePriority: 31,
direction: 'y',
threshold: 5,
canStart: () => this.state !== 8 /* RefresherState.Refreshing */ &&
this.state !== 32 /* RefresherState.Completing */ &&
this.scrollEl.scrollTop === 0,
onStart: (ev) => {
this.progress = 0;
ev.data = { animation: undefined, didStart: false, cancelled: false };
},
onMove: (ev) => {
if ((ev.velocityY < 0 && this.progress === 0 && !ev.data.didStart) || ev.data.cancelled) {
ev.data.cancelled = true;
return;
}
if (!ev.data.didStart) {
ev.data.didStart = true;
this.state = 2 /* RefresherState.Pulling */;
// When ion-refresher is being used with a custom scroll target, the overflow styles need to be applied directly instead of via a css variable
const { scrollEl } = this;
const overflowProperty = scrollEl.matches(ION_CONTENT_CLASS_SELECTOR) ? 'overflow' : '--overflow';
writeTask(() => scrollEl.style.setProperty(overflowProperty, 'hidden'));
const animationType = getRefresherAnimationType(contentEl);
const animation = createPullingAnimation(animationType, pullingRefresherIcon, this.el);
ev.data.animation = animation;
animation.progressStart(false, 0);
this.ionStart.emit();
this.animations.push(animation);
return;
}
// Since we are using an easing curve, slow the gesture tracking down a bit
this.progress = clamp(0, (ev.deltaY / 180) * 0.5, 1);
ev.data.animation.progressStep(this.progress);
this.ionPull.emit();
},
onEnd: (ev) => {
if (!ev.data.didStart) {
return;
}
this.gesture.enable(false);
const { scrollEl } = this;
const overflowProperty = scrollEl.matches(ION_CONTENT_CLASS_SELECTOR) ? 'overflow' : '--overflow';
writeTask(() => scrollEl.style.removeProperty(overflowProperty));
if (this.progress <= 0.4) {
ev.data.animation.progressEnd(0, this.progress, 500).onFinish(() => {
this.animations.forEach((ani) => ani.destroy());
this.animations = [];
this.gesture.enable(true);
this.state = 1 /* RefresherState.Inactive */;
});
return;
}
const progress = getTimeGivenProgression([0, 0], [0, 0], [1, 1], [1, 1], this.progress)[0];
const snapBackAnimation = createSnapBackAnimation(pullingRefresherIcon);
this.animations.push(snapBackAnimation);
writeTask(async () => {
pullingRefresherIcon.style.setProperty('--ion-pulling-refresher-translate', `${progress * 100}px`);
ev.data.animation.progressEnd();
await snapBackAnimation.play();
this.beginRefresh();
ev.data.animation.destroy();
this.gesture.enable(true);
});
},
});
this.disabledChanged();
}
async setupNativeRefresher(contentEl) {
if (this.scrollListenerCallback || !contentEl || this.nativeRefresher || !this.scrollEl) {
return;
}
/**
* If using non-native refresher before make sure
* we clean up any old CSS. This can happen when
* a user manually calls the refresh method in a
* component create callback before the native
* refresher is setup.
*/
this.setCss(0, '', false, '');
this.nativeRefresher = true;
const pullingSpinner = this.el.querySelector('ion-refresher-content .refresher-pulling ion-spinner');
const refreshingSpinner = this.el.querySelector('ion-refresher-content .refresher-refreshing ion-spinner');
if (getIonMode$1(this) === 'ios') {
this.setupiOSNativeRefresher(pullingSpinner, refreshingSpinner);
}
else {
this.setupMDNativeRefresher(contentEl, pullingSpinner, refreshingSpinner);
}
}
componentDidUpdate() {
this.checkNativeRefresher();
}
async connectedCallback() {
if (this.el.getAttribute('slot') !== 'fixed') {
printIonError('[ion-refresher] - Make sure you use: <ion-refresher slot="fixed">');
return;
}
const contentEl = this.el.closest(ION_CONTENT_ELEMENT_SELECTOR);
if (!contentEl) {
printIonContentErrorMsg(this.el);
return;
}
/**
* Waits for the content to be ready before querying the scroll
* or the background content element.
*/
componentOnReady(contentEl, async () => {
const customScrollTarget = contentEl.querySelector(ION_CONTENT_CLASS_SELECTOR);
/**
* Query the custom scroll target (if available), first. In refresher implementations,
* the ion-refresher element will always be a direct child of ion-content (slot="fixed"). By
* querying the custom scroll target first and falling back to the ion-content element,
* the correct scroll element will be returned by the implementation.
*/
this.scrollEl = await getScrollElement(customScrollTarget !== null && customScrollTarget !== void 0 ? customScrollTarget : contentEl);
/**
* Query the background content element from the host ion-content element directly.
*/
this.backgroundContentEl = await contentEl.getBackgroundElement();
/**
* Check if the content element is fullscreen to apply the correct styles
* when the refresher is refreshing. Otherwise, the refresher will be
* hidden because it is positioned behind the background content element.
*/
this.contentFullscreen = contentEl.fullscreen;
if (await shouldUseNativeRefresher(this.el, getIonMode$1(this))) {
this.setupNativeRefresher(contentEl);
}
else {
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: contentEl,
gestureName: 'refresher',
gesturePriority: 31,
direction: 'y',
threshold: 20,
passive: false,
canStart: () => this.canStart(),
onStart: () => this.onStart(),
onMove: (ev) => this.onMove(ev),
onEnd: () => this.onEnd(),
});
this.disabledChanged();
}
});
}
disconnectedCallback() {
this.destroyNativeRefresher();
this.scrollEl = undefined;
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
/**
* Call `complete()` when your async operation has completed.
* For example, the `refreshing` state is while the app is performing
* an asynchronous operation, such as receiving more data from an
* AJAX request. Once the data has been received, you then call this
* method to signify that the refreshing has completed and to close
* the refresher. This method also changes the refresher's state from
* `refreshing` to `completing`.
*/
async complete() {
if (this.nativeRefresher) {
this.needsCompletion = true;
// Do not reset scroll el until user removes pointer from screen
if (!this.pointerDown) {
raf(() => raf(() => this.resetNativeRefresher(this.elementToTransform, 32 /* RefresherState.Completing */)));
}
}
else {
this.close(32 /* RefresherState.Completing */, '120ms');
}
}
/**
* Changes the refresher's state from `refreshing` to `cancelling`.
*/
async cancel() {
if (this.nativeRefresher) {
// Do not reset scroll el until user removes pointer from screen
if (!this.pointerDown) {
raf(() => raf(() => this.resetNativeRefresher(this.elementToTransform, 16 /* RefresherState.Cancelling */)));
}
}
else {
this.close(16 /* RefresherState.Cancelling */, '');
}
}
/**
* A number representing how far down the user has pulled.
* The number `0` represents the user hasn't pulled down at all. The
* number `1`, and anything greater than `1`, represents that the user
* has pulled far enough down that when they let go then the refresh will
* happen. If they let go and the number is less than `1`, then the
* refresh will not happen, and the content will return to it's original
* position.
*/
getProgress() {
return Promise.resolve(this.progress);
}
canStart() {
if (!this.scrollEl) {
return false;
}
if (this.state !== 1 /* RefresherState.Inactive */) {
return false;
}
// if the scrollTop is greater than zero then it's
// not possible to pull the content down yet
if (this.scrollEl.scrollTop > 0) {
return false;
}
return true;
}
onStart() {
this.progress = 0;
this.state = 1 /* RefresherState.Inactive */;
this.memoizeOverflowStyle();
/**
* If the content is fullscreen, then we need to
* set the offset-top style on the background content
* element to ensure that the refresher is shown.
*/
if (this.contentFullscreen && this.backgroundContentEl) {
this.backgroundContentEl.style.setProperty('--offset-top', '0px');
}
}
onMove(detail) {
if (!this.scrollEl) {
return;
}
// this method can get called like a bazillion times per second,
// so it's built to be as efficient as possible, and does its
// best to do any DOM read/writes only when absolutely necessary
// if multi-touch then get out immediately
const ev = detail.event;
if (ev.touches !== undefined && ev.touches.length > 1) {
return;
}
// do nothing if it's actively refreshing
// or it's in the way of closing
// or this was never a startY
if ((this.state & 56 /* RefresherState._BUSY_ */) !== 0) {
return;
}
const pullFactor = Number.isNaN(this.pullFactor) || this.pullFactor < 0 ? 1 : this.pullFactor;
const deltaY = detail.deltaY * pullFactor;
// don't bother if they're scrolling up
// and have not already started dragging
if (deltaY <= 0) {
// the current Y is higher than the starting Y
// so they scrolled up enough to be ignored
this.progress = 0;
this.state = 1 /* RefresherState.Inactive */;
if (this.appliedStyles) {
// reset the styles only if they were applied
this.setCss(0, '', false, '');
return;
}
return;
}
if (this.state === 1 /* RefresherState.Inactive */) {
// this refresh is not already actively pulling down
// get the content's scrollTop
const scrollHostScrollTop = this.scrollEl.scrollTop;
// if the scrollTop is greater than zero then it's
// not possible to pull the content down yet
if (scrollHostScrollTop > 0) {
this.progress = 0;
return;
}
// content scrolled all the way to the top, and dragging down
this.state = 2 /* RefresherState.Pulling */;
}
// prevent native scroll events
if (ev.cancelable) {
ev.preventDefault();
}
// the refresher is actively pulling at this point
// move the scroll element within the content element
this.setCss(deltaY, '0ms', true, '');
if (deltaY === 0) {
// don't continue if there's no delta yet
this.progress = 0;
return;
}
const pullMin = this.pullMin;
// set pull progress
this.progress = deltaY / pullMin;
// emit "start" if it hasn't started yet
if (!this.didStart) {
this.didStart = true;
this.ionStart.emit();
}
// emit "pulling" on every move
this.ionPull.emit();
// do nothing if the delta is less than the pull threshold
if (deltaY < pullMin) {
// ensure it stays in the pulling state, cuz its not ready yet
this.state = 2 /* RefresherState.Pulling */;
return;
}
if (deltaY > this.pullMax) {
// they pulled farther than the max, so kick off the refresh
this.beginRefresh();
return;
}
// pulled farther than the pull min!!
// it is now in the `ready` state!!
// if they let go then it'll refresh, kerpow!!
this.state = 4 /* RefresherState.Ready */;
return;
}
onEnd() {
// only run in a zone when absolutely necessary
if (this.state === 4 /* RefresherState.Ready */) {
// they pulled down far enough, so it's ready to refresh
this.beginRefresh();
}
else if (this.state === 2 /* RefresherState.Pulling */) {
// they were pulling down, but didn't pull down far enough
// set the content back to it's original location
// and close the refresher
// set that the refresh is actively cancelling
this.cancel();
}
else if (this.state === 1 /* RefresherState.Inactive */) {
/**
* The pull to refresh gesture was aborted
* so we should immediately restore any overflow styles
* that have been modified. Do not call this.cancel
* because the styles will only be reset after a timeout.
* If the gesture is aborted then scrolling should be
* available right away.
*/
this.restoreOverflowStyle();
}
}
beginRefresh() {
// assumes we're already back in a zone
// they pulled down far enough, so it's ready to refresh
this.state = 8 /* RefresherState.Refreshing */;
// place the content in a hangout position while it thinks
this.setCss(this.pullMin, this.snapbackDuration, true, '');
/**
* Clear focus from any active element to prevent the browser
* from restoring focus and causing scroll jumps after refresh.
* This ensures the view stays at the top after refresh completes.
*/
const activeElement = document.activeElement;
if ((activeElement === null || activeElement === void 0 ? void 0 : activeElement.blur) !== undefined) {
activeElement.blur();
}
// emit "refresh" because it was pulled down far enough
// and they let go to begin refreshing
this.ionRefresh.emit({
complete: this.complete.bind(this),
});
}
close(state, delay) {
// create fallback timer incase something goes wrong with transitionEnd event
setTimeout(() => {
var _a;
this.state = 1 /* RefresherState.Inactive */;
this.progress = 0;
this.didStart = false;
/**
* Reset any overflow styles so the
* user can scroll again.
*/
this.setCss(0, '0ms', false, '', true);
/**
* Reset the offset-top style on the background content
* when the refresher is no longer refreshing and the
* content is fullscreen.
*
* This ensures that the behavior of background content
* does not change when refreshing is complete.
*/
if (this.contentFullscreen && this.backgroundContentEl) {
(_a = this.backgroundContentEl) === null || _a === void 0 ? void 0 : _a.style.removeProperty('--offset-top');
}
}, 600);
// reset the styles on the scroll element
// set that the refresh is actively cancelling/completing
this.state = state;
this.setCss(0, this.closeDuration, true, delay);
}
setCss(y, duration, overflowVisible, delay, shouldRestoreOverflowStyle = false) {
if (this.nativeRefresher) {
return;
}
this.appliedStyles = y > 0;
writeTask(() => {
if (this.scrollEl && this.backgroundContentEl) {
const scrollStyle = this.scrollEl.style;
const backgroundStyle = this.backgroundContentEl.style;
scrollStyle.transform = backgroundStyle.transform = y > 0 ? `translateY(${y}px) translateZ(0px)` : '';
scrollStyle.transitionDuration = backgroundStyle.transitionDuration = duration;
scrollStyle.transitionDelay = backgroundStyle.transitionDelay = delay;
scrollStyle.overflow = overflowVisible ? 'hidden' : '';
}
/**
* Reset the overflow styles only once
* the pull to refresh effect has been closed.
* This ensures that the gesture is done
* and the refresh operation has either
* been aborted or has completed.
*/
if (shouldRestoreOverflowStyle) {
this.restoreOverflowStyle();
}
});
}
memoizeOverflowStyle() {
if (this.scrollEl) {
const { overflow, overflowX, overflowY } = this.scrollEl.style;
this.overflowStyles = {
overflow: overflow !== null && overflow !== void 0 ? overflow : '',
overflowX: overflowX !== null && overflowX !== void 0 ? overflowX : '',
overflowY: overflowY !== null && overflowY !== void 0 ? overflowY : '',
};
}
}
restoreOverflowStyle() {
if (this.overflowStyles !== undefined && this.scrollEl !== undefined) {
const { overflow, overflowX, overflowY } = this.overflowStyles;
this.scrollEl.style.overflow = overflow;
this.scrollEl.style.overflowX = overflowX;
this.scrollEl.style.overflowY = overflowY;
this.overflowStyles = undefined;
}
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '2d1bd880877b698604542ab2d602d38b9504d975', slot: "fixed", class: {
[mode]: true,
// Used internally for styling
[`refresher-${mode}`]: true,
'refresher-native': this.nativeRefresher,
'refresher-active': this.state !== 1 /* RefresherState.Inactive */,
'refresher-pulling': this.state === 2 /* RefresherState.Pulling */,
'refresher-ready': this.state === 4 /* RefresherState.Ready */,
'refresher-refreshing': this.state === 8 /* RefresherState.Refreshing */,
'refresher-cancelling': this.state === 16 /* RefresherState.Cancelling */,
'refresher-completing': this.state === 32 /* RefresherState.Completing */,
} }));
}
get el() { return getElement(this); }
static get watchers() { return {
"disabled": ["disabledChanged"]
}; }
static get style() { return {
ios: refresherIosCss,
md: refresherMdCss
}; }
static get cmpMeta() { return {
"$flags$": 288,
"$tagName$": "ion-refresher",
"$members$": {
"pullMin": [2, "pull-min"],
"pullMax": [2, "pull-max"],
"closeDuration": [1, "close-duration"],
"snapbackDuration": [1, "snapback-duration"],
"pullFactor": [2, "pull-factor"],
"disabled": [4],
"nativeRefresher": [32],
"state": [32],
"complete": [64],
"cancel": [64],
"getProgress": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const spinners = {
bubbles: {
dur: 1000,
circles: 9,
fn: (dur, index, total) => {
const animationDelay = `${(dur * index) / total - dur}ms`;
const angle = (2 * Math.PI * index) / total;
return {
r: 5,
style: {
top: `${32 * Math.sin(angle)}%`,
left: `${32 * Math.cos(angle)}%`,
'animation-delay': animationDelay,
},
};
},
},
circles: {
dur: 1000,
circles: 8,
fn: (dur, index, total) => {
const step = index / total;
const animationDelay = `${dur * step - dur}ms`;
const angle = 2 * Math.PI * step;
return {
r: 5,
style: {
top: `${32 * Math.sin(angle)}%`,
left: `${32 * Math.cos(angle)}%`,
'animation-delay': animationDelay,
},
};
},
},
circular: {
dur: 1400,
elmDuration: true,
circles: 1,
fn: () => {
return {
r: 20,
cx: 48,
cy: 48,
fill: 'none',
viewBox: '24 24 48 48',
transform: 'translate(0,0)',
style: {},
};
},
},
crescent: {
dur: 750,
circles: 1,
fn: () => {
return {
r: 26,
style: {},
};
},
},
dots: {
dur: 750,
circles: 3,
fn: (_, index) => {
const animationDelay = -(110 * index) + 'ms';
return {
r: 6,
style: {
left: `${32 - 32 * index}%`,
'animation-delay': animationDelay,
},
};
},
},
lines: {
dur: 1000,
lines: 8,
fn: (dur, index, total) => {
const transform = `rotate(${(360 / total) * index + (index < total / 2 ? 180 : -180)}deg)`;
const animationDelay = `${(dur * index) / total - dur}ms`;
return {
y1: 14,
y2: 26,
style: {
transform: transform,
'animation-delay': animationDelay,
},
};
},
},
'lines-small': {
dur: 1000,
lines: 8,
fn: (dur, index, total) => {
const transform = `rotate(${(360 / total) * index + (index < total / 2 ? 180 : -180)}deg)`;
const animationDelay = `${(dur * index) / total - dur}ms`;
return {
y1: 12,
y2: 20,
style: {
transform: transform,
'animation-delay': animationDelay,
},
};
},
},
'lines-sharp': {
dur: 1000,
lines: 12,
fn: (dur, index, total) => {
const transform = `rotate(${30 * index + (index < 6 ? 180 : -180)}deg)`;
const animationDelay = `${(dur * index) / total - dur}ms`;
return {
y1: 17,
y2: 29,
style: {
transform: transform,
'animation-delay': animationDelay,
},
};
},
},
'lines-sharp-small': {
dur: 1000,
lines: 12,
fn: (dur, index, total) => {
const transform = `rotate(${30 * index + (index < 6 ? 180 : -180)}deg)`;
const animationDelay = `${(dur * index) / total - dur}ms`;
return {
y1: 12,
y2: 20,
style: {
transform: transform,
'animation-delay': animationDelay,
},
};
},
},
};
const SPINNERS = spinners;
class RefresherContent {
constructor(hostRef) {
registerInstance(this, hostRef);
this.customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
}
componentWillLoad() {
if (this.pullingIcon === undefined) {
/**
* The native iOS refresher uses a spinner instead of
* an icon, so we need to see if this device supports
* the native iOS refresher.
*/
const hasRubberBandScrolling = supportsRubberBandScrolling();
const mode = getIonMode$1(this);
const overflowRefresher = hasRubberBandScrolling ? 'lines' : arrowDown;
this.pullingIcon = config.get('refreshingIcon', mode === 'ios' && hasRubberBandScrolling ? config.get('spinner', overflowRefresher) : 'circular');
}
if (this.refreshingSpinner === undefined) {
const mode = getIonMode$1(this);
this.refreshingSpinner = config.get('refreshingSpinner', config.get('spinner', mode === 'ios' ? 'lines' : 'circular'));
}
}
renderPullingText() {
const { customHTMLEnabled, pullingText } = this;
if (customHTMLEnabled) {
return hAsync("div", { class: "refresher-pulling-text", innerHTML: sanitizeDOMString(pullingText) });
}
return hAsync("div", { class: "refresher-pulling-text" }, pullingText);
}
renderRefreshingText() {
const { customHTMLEnabled, refreshingText } = this;
if (customHTMLEnabled) {
return hAsync("div", { class: "refresher-refreshing-text", innerHTML: sanitizeDOMString(refreshingText) });
}
return hAsync("div", { class: "refresher-refreshing-text" }, refreshingText);
}
render() {
const pullingIcon = this.pullingIcon;
const hasSpinner = pullingIcon != null && SPINNERS[pullingIcon] !== undefined;
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'e235f8a9a84070ece2e2066ced234a64663bfa1d', class: mode }, hAsync("div", { key: '9121691818ddaa35801a5f442e144ac27686cf19', class: "refresher-pulling" }, this.pullingIcon && hasSpinner && (hAsync("div", { key: 'c8d65d740f1575041bd3b752c789077927397fe4', class: "refresher-pulling-icon" }, hAsync("div", { key: '309dd904977eaa788b09ea95b7fa4996a73bec5b', class: "spinner-arrow-container" }, hAsync("ion-spinner", { key: 'a2a1480f67775d56ca7822e76be1e9f983bca2f9', name: this.pullingIcon, paused: true }), mode === 'md' && this.pullingIcon === 'circular' && (hAsync("div", { key: '811d7e06d324bf4b6a18a31427a43e5177f3ae3a', class: "arrow-container" }, hAsync("ion-icon", { key: '86cc48e2e8dc054ff6ff1299094da35b524be63d', icon: caretBackSharp, "aria-hidden": "true" })))))), this.pullingIcon && !hasSpinner && (hAsync("div", { key: '464ae097dbc95c18a2dd7dfd03f8489153dab719', class: "refresher-pulling-icon" }, hAsync("ion-icon", { key: 'ed6875978b9035add562caa743a68353743d978f', icon: this.pullingIcon, lazy: false, "aria-hidden": "true" }))), this.pullingText !== undefined && this.renderPullingText()), hAsync("div", { key: 'aff891924e44354543fec484e5cde1ca92e69904', class: "refresher-refreshing" }, this.refreshingSpinner && (hAsync("div", { key: '842d7ac4ff10a1058775493d62f31cbdcd34f7a0', class: "refresher-refreshing-icon" }, hAsync("ion-spinner", { key: '8c3e6195501e7e78d5cde1e3ad1fef90fd4a953f', name: this.refreshingSpinner }))), this.refreshingText !== undefined && this.renderRefreshingText())));
}
get el() { return getElement(this); }
static get cmpMeta() { return {
"$flags$": 256,
"$tagName$": "ion-refresher-content",
"$members$": {
"pullingIcon": [1025, "pulling-icon"],
"pullingText": [1, "pulling-text"],
"refreshingSpinner": [1025, "refreshing-spinner"],
"refreshingText": [1, "refreshing-text"]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const reorderIosCss = ":host([slot]){display:none;line-height:0;z-index:100}.reorder-icon{display:block}::slotted(ion-icon){font-size:dynamic-font(16px)}.reorder-icon{font-size:2.125rem;opacity:0.4}";
const reorderMdCss = ":host([slot]){display:none;line-height:0;z-index:100}.reorder-icon{display:block}::slotted(ion-icon){font-size:dynamic-font(16px)}.reorder-icon{font-size:1.9375rem;opacity:0.3}";
/**
* @part icon - The icon of the reorder handle (uses ion-icon).
*/
class Reorder {
constructor(hostRef) {
registerInstance(this, hostRef);
}
onClick(ev) {
const reorderGroup = this.el.closest('ion-reorder-group');
ev.preventDefault();
// Only stop event propagation if the reorder is inside of an enabled
// reorder group. This allows interaction with clickable children components.
if (!reorderGroup || !reorderGroup.disabled) {
ev.stopImmediatePropagation();
}
}
render() {
const mode = getIonMode$1(this);
const reorderIcon = mode === 'ios' ? reorderThreeOutline : reorderTwoSharp;
return (hAsync(Host, { key: 'e6807bb349725682e99e791ac65e729a360d64e8', class: mode }, hAsync("slot", { key: '1c691cdbffa6427ba08dc12184c69559ed5d5506' }, hAsync("ion-icon", { key: '8b4150302cdca475379582b2251737b5e74079b1', icon: reorderIcon, lazy: false, class: "reorder-icon", part: "icon", "aria-hidden": "true" }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: reorderIosCss,
md: reorderMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-reorder",
"$members$": undefined,
"$listeners$": [[2, "click", "onClick"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const reorderGroupCss = ".reorder-list-active>*{display:block;-webkit-transition:-webkit-transform 300ms;transition:-webkit-transform 300ms;transition:transform 300ms;transition:transform 300ms, -webkit-transform 300ms;will-change:transform}.reorder-enabled{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.reorder-enabled ion-reorder{display:block;cursor:-webkit-grab;cursor:grab;pointer-events:all;-ms-touch-action:none;touch-action:none}.reorder-selected,.reorder-selected ion-reorder{cursor:-webkit-grabbing;cursor:grabbing}.reorder-selected{position:relative;-webkit-transition:none !important;transition:none !important;-webkit-box-shadow:0 0 10px rgba(0, 0, 0, 0.4);box-shadow:0 0 10px rgba(0, 0, 0, 0.4);opacity:0.8;z-index:100}.reorder-visible ion-reorder .reorder-icon{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0)}";
class ReorderGroup {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionItemReorder = createEvent(this, "ionItemReorder", 7);
this.ionReorderStart = createEvent(this, "ionReorderStart", 7);
this.ionReorderMove = createEvent(this, "ionReorderMove", 7);
this.ionReorderEnd = createEvent(this, "ionReorderEnd", 7);
this.lastToIndex = -1;
this.cachedHeights = [];
this.scrollElTop = 0;
this.scrollElBottom = 0;
this.scrollElInitial = 0;
this.containerTop = 0;
this.containerBottom = 0;
this.state = 0 /* ReorderGroupState.Idle */;
/**
* If `true`, the reorder will be hidden.
*/
this.disabled = true;
}
disabledChanged() {
if (this.gesture) {
this.gesture.enable(!this.disabled);
}
}
async connectedCallback() {
const contentEl = findClosestIonContent(this.el);
if (contentEl) {
this.scrollEl = await getScrollElement(contentEl);
}
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: this.el,
gestureName: 'reorder',
gesturePriority: 110,
threshold: 0,
direction: 'y',
passive: false,
canStart: (detail) => this.canStart(detail),
onStart: (ev) => this.onStart(ev),
onMove: (ev) => this.onMove(ev),
onEnd: () => this.onEnd(),
});
this.disabledChanged();
}
disconnectedCallback() {
this.onEnd();
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
/**
* Completes the reorder operation. Must be called by the `ionReorderEnd` event.
*
* If a list of items is passed, the list will be reordered and returned in the
* proper order.
*
* If no parameters are passed or if `true` is passed in, the reorder will complete
* and the item will remain in the position it was dragged to. If `false` is passed,
* the reorder will complete and the item will bounce back to its original position.
*
* @param listOrReorder A list of items to be sorted and returned in the new order or a
* boolean of whether or not the reorder should reposition the item.
*/
complete(listOrReorder) {
return Promise.resolve(this.completeReorder(listOrReorder));
}
canStart(ev) {
if (this.selectedItemEl || this.state !== 0 /* ReorderGroupState.Idle */) {
return false;
}
const target = ev.event.target;
const reorderEl = target.closest('ion-reorder');
if (!reorderEl) {
return false;
}
const item = findReorderItem(reorderEl, this.el);
if (!item) {
return false;
}
ev.data = item;
return true;
}
onStart(ev) {
ev.event.preventDefault();
const item = (this.selectedItemEl = ev.data);
const heights = this.cachedHeights;
heights.length = 0;
const el = this.el;
const children = el.__children || el.children;
if (!children || children.length === 0) {
return;
}
let sum = 0;
for (let i = 0; i < children.length; i++) {
const child = children[i];
sum += child.offsetHeight;
heights.push(sum);
child.$ionIndex = i;
}
const box = el.getBoundingClientRect();
this.containerTop = box.top;
this.containerBottom = box.bottom;
if (this.scrollEl) {
const scrollBox = this.scrollEl.getBoundingClientRect();
this.scrollElInitial = this.scrollEl.scrollTop;
this.scrollElTop = scrollBox.top + AUTO_SCROLL_MARGIN;
this.scrollElBottom = scrollBox.bottom - AUTO_SCROLL_MARGIN;
}
else {
this.scrollElInitial = 0;
this.scrollElTop = 0;
this.scrollElBottom = 0;
}
this.lastToIndex = indexForItem(item);
this.selectedItemHeight = item.offsetHeight;
this.state = 1 /* ReorderGroupState.Active */;
item.classList.add(ITEM_REORDER_SELECTED);
hapticSelectionStart();
this.ionReorderStart.emit();
}
onMove(ev) {
const selectedItem = this.selectedItemEl;
if (!selectedItem) {
return;
}
// Scroll if we reach the scroll margins
const scroll = this.autoscroll(ev.currentY);
// // Get coordinate
const top = this.containerTop - scroll;
const bottom = this.containerBottom - scroll;
const currentY = Math.max(top, Math.min(ev.currentY, bottom));
const deltaY = scroll + currentY - ev.startY;
const normalizedY = currentY - top;
const fromIndex = this.lastToIndex;
const toIndex = this.itemIndexForTop(normalizedY);
if (toIndex !== this.lastToIndex) {
const fromIndex = indexForItem(selectedItem);
this.lastToIndex = toIndex;
hapticSelectionChanged();
this.reorderMove(fromIndex, toIndex);
}
// Update selected item position
selectedItem.style.transform = `translateY(${deltaY}px)`;
this.ionReorderMove.emit({
from: fromIndex,
to: toIndex,
});
}
onEnd() {
const selectedItemEl = this.selectedItemEl;
this.state = 2 /* ReorderGroupState.Complete */;
if (!selectedItemEl) {
this.state = 0 /* ReorderGroupState.Idle */;
return;
}
const toIndex = this.lastToIndex;
const fromIndex = indexForItem(selectedItemEl);
if (toIndex === fromIndex) {
this.completeReorder();
}
else {
// TODO(FW-6590): Remove this once the deprecated event is removed
this.ionItemReorder.emit({
from: fromIndex,
to: toIndex,
complete: this.completeReorder.bind(this),
});
}
hapticSelectionEnd();
this.ionReorderEnd.emit({
from: fromIndex,
to: toIndex,
complete: this.completeReorder.bind(this),
});
}
completeReorder(listOrReorder) {
const selectedItemEl = this.selectedItemEl;
if (selectedItemEl && this.state === 2 /* ReorderGroupState.Complete */) {
const children = this.el.__children || this.el.children;
const len = children.length;
const toIndex = this.lastToIndex;
const fromIndex = indexForItem(selectedItemEl);
/**
* insertBefore and setting the transform
* needs to happen in the same frame otherwise
* there will be a duplicate transition. This primarily
* impacts Firefox where insertBefore and transform operations
* are happening in two separate frames.
*/
raf(() => {
if (toIndex !== fromIndex && (listOrReorder === undefined || listOrReorder === true)) {
const ref = fromIndex < toIndex ? children[toIndex + 1] : children[toIndex];
this.el.insertBefore(selectedItemEl, ref);
}
for (let i = 0; i < len; i++) {
children[i].style['transform'] = '';
}
});
if (Array.isArray(listOrReorder)) {
listOrReorder = reorderArray(listOrReorder, fromIndex, toIndex);
}
selectedItemEl.style.transition = '';
selectedItemEl.classList.remove(ITEM_REORDER_SELECTED);
this.selectedItemEl = undefined;
this.state = 0 /* ReorderGroupState.Idle */;
}
return listOrReorder;
}
itemIndexForTop(deltaY) {
const heights = this.cachedHeights;
for (let i = 0; i < heights.length; i++) {
if (heights[i] > deltaY) {
return i;
}
}
return heights.length - 1;
}
/********* DOM WRITE ********* */
reorderMove(fromIndex, toIndex) {
const itemHeight = this.selectedItemHeight;
const children = this.el.__children || this.el.children;
for (let i = 0; i < children.length; i++) {
const style = children[i].style;
let value = '';
if (i > fromIndex && i <= toIndex) {
value = `translateY(${-itemHeight}px)`;
}
else if (i < fromIndex && i >= toIndex) {
value = `translateY(${itemHeight}px)`;
}
style['transform'] = value;
}
}
autoscroll(posY) {
if (!this.scrollEl) {
return 0;
}
let amount = 0;
if (posY < this.scrollElTop) {
amount = -10;
}
else if (posY > this.scrollElBottom) {
amount = SCROLL_JUMP;
}
if (amount !== 0) {
this.scrollEl.scrollBy(0, amount);
}
return this.scrollEl.scrollTop - this.scrollElInitial;
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'b9641f3061d67fbfe68317b901ec33267046e073', class: {
[mode]: true,
'reorder-enabled': !this.disabled,
'reorder-list-active': this.state !== 0 /* ReorderGroupState.Idle */,
} }));
}
get el() { return getElement(this); }
static get watchers() { return {
"disabled": ["disabledChanged"]
}; }
static get style() { return reorderGroupCss; }
static get cmpMeta() { return {
"$flags$": 256,
"$tagName$": "ion-reorder-group",
"$members$": {
"disabled": [4],
"state": [32],
"complete": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const indexForItem = (element) => {
return element['$ionIndex'];
};
const findReorderItem = (node, container) => {
let parent;
while (node) {
parent = node.parentElement;
if (parent === container) {
return node;
}
node = parent;
}
return undefined;
};
const AUTO_SCROLL_MARGIN = 60;
const SCROLL_JUMP = 10;
const ITEM_REORDER_SELECTED = 'reorder-selected';
const reorderArray = (array, from, to) => {
const element = array[from];
array.splice(from, 1);
array.splice(to, 0, element);
return array.slice();
};
const rippleEffectCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:strict;pointer-events:none}:host(.unbounded){contain:layout size style}.ripple-effect{border-radius:50%;position:absolute;background-color:currentColor;color:inherit;contain:strict;opacity:0;-webkit-animation:225ms rippleAnimation forwards, 75ms fadeInAnimation forwards;animation:225ms rippleAnimation forwards, 75ms fadeInAnimation forwards;will-change:transform, opacity;pointer-events:none}.fade-out{-webkit-transform:translate(var(--translate-end)) scale(var(--final-scale, 1));transform:translate(var(--translate-end)) scale(var(--final-scale, 1));-webkit-animation:150ms fadeOutAnimation forwards;animation:150ms fadeOutAnimation forwards}@-webkit-keyframes rippleAnimation{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:translate(var(--translate-end)) scale(var(--final-scale, 1));transform:translate(var(--translate-end)) scale(var(--final-scale, 1))}}@keyframes rippleAnimation{from{-webkit-animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);animation-timing-function:cubic-bezier(0.4, 0, 0.2, 1);-webkit-transform:scale(1);transform:scale(1)}to{-webkit-transform:translate(var(--translate-end)) scale(var(--final-scale, 1));transform:translate(var(--translate-end)) scale(var(--final-scale, 1))}}@-webkit-keyframes fadeInAnimation{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0}to{opacity:0.16}}@keyframes fadeInAnimation{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0}to{opacity:0.16}}@-webkit-keyframes fadeOutAnimation{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0.16}to{opacity:0}}@keyframes fadeOutAnimation{from{-webkit-animation-timing-function:linear;animation-timing-function:linear;opacity:0.16}to{opacity:0}}";
class RippleEffect {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* Sets the type of ripple-effect:
*
* - `bounded`: the ripple effect expands from the user's click position
* - `unbounded`: the ripple effect expands from the center of the button and overflows the container.
*
* NOTE: Surfaces for bounded ripples should have the overflow property set to hidden,
* while surfaces for unbounded ripples should have it set to visible.
*/
this.type = 'bounded';
}
/**
* Adds the ripple effect to the parent element.
*
* @param x The horizontal coordinate of where the ripple should start.
* @param y The vertical coordinate of where the ripple should start.
*/
async addRipple(x, y) {
return new Promise((resolve) => {
readTask(() => {
const rect = this.el.getBoundingClientRect();
const width = rect.width;
const height = rect.height;
const hypotenuse = Math.sqrt(width * width + height * height);
const maxDim = Math.max(height, width);
const maxRadius = this.unbounded ? maxDim : hypotenuse + PADDING;
const initialSize = Math.floor(maxDim * INITIAL_ORIGIN_SCALE);
const finalScale = maxRadius / initialSize;
let posX = x - rect.left;
let posY = y - rect.top;
if (this.unbounded) {
posX = width * 0.5;
posY = height * 0.5;
}
const styleX = posX - initialSize * 0.5;
const styleY = posY - initialSize * 0.5;
const moveX = width * 0.5 - posX;
const moveY = height * 0.5 - posY;
writeTask(() => {
const div = document.createElement('div');
div.classList.add('ripple-effect');
const style = div.style;
style.top = styleY + 'px';
style.left = styleX + 'px';
style.width = style.height = initialSize + 'px';
style.setProperty('--final-scale', `${finalScale}`);
style.setProperty('--translate-end', `${moveX}px, ${moveY}px`);
const container = this.el.shadowRoot || this.el;
container.appendChild(div);
setTimeout(() => {
resolve(() => {
removeRipple(div);
});
}, 225 + 100);
});
});
});
}
get unbounded() {
return this.type === 'unbounded';
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'ae9d3b1ed6773a9b9bb2267129f7e9af23b6c9fc', role: "presentation", class: {
[mode]: true,
unbounded: this.unbounded,
} }));
}
get el() { return getElement(this); }
static get style() { return rippleEffectCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-ripple-effect",
"$members$": {
"type": [1],
"addRipple": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const removeRipple = (ripple) => {
ripple.classList.add('fade-out');
setTimeout(() => {
ripple.remove();
}, 200);
};
const PADDING = 10;
const INITIAL_ORIGIN_SCALE = 0.5;
// TODO(FW-2832): types
class Route {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionRouteDataChanged = createEvent(this, "ionRouteDataChanged", 7);
/**
* Relative path that needs to match in order for this route to apply.
*
* Accepts paths similar to expressjs so that you can define parameters
* in the url /foo/:bar where bar would be available in incoming props.
*/
this.url = '';
}
onUpdate(newValue) {
this.ionRouteDataChanged.emit(newValue);
}
onComponentProps(newValue, oldValue) {
if (newValue === oldValue) {
return;
}
const keys1 = newValue ? Object.keys(newValue) : [];
const keys2 = oldValue ? Object.keys(oldValue) : [];
if (keys1.length !== keys2.length) {
this.onUpdate(newValue);
return;
}
for (const key of keys1) {
if (newValue[key] !== oldValue[key]) {
this.onUpdate(newValue);
return;
}
}
}
connectedCallback() {
this.ionRouteDataChanged.emit();
}
static get watchers() { return {
"url": ["onUpdate"],
"component": ["onUpdate"],
"componentProps": ["onComponentProps"]
}; }
static get cmpMeta() { return {
"$flags$": 0,
"$tagName$": "ion-route",
"$members$": {
"url": [1],
"component": [1],
"componentProps": [16],
"beforeLeave": [16],
"beforeEnter": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
class RouteRedirect {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionRouteRedirectChanged = createEvent(this, "ionRouteRedirectChanged", 7);
}
propDidChange() {
this.ionRouteRedirectChanged.emit();
}
connectedCallback() {
this.ionRouteRedirectChanged.emit();
}
static get watchers() { return {
"from": ["propDidChange"],
"to": ["propDidChange"]
}; }
static get cmpMeta() { return {
"$flags$": 0,
"$tagName$": "ion-route-redirect",
"$members$": {
"from": [1],
"to": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const ROUTER_INTENT_NONE = 'root';
const ROUTER_INTENT_FORWARD = 'forward';
const ROUTER_INTENT_BACK = 'back';
/** Join the non empty segments with "/". */
const generatePath = (segments) => {
const path = segments.filter((s) => s.length > 0).join('/');
return '/' + path;
};
const generateUrl = (segments, useHash, queryString) => {
let url = generatePath(segments);
if (useHash) {
url = '#' + url;
}
if (queryString !== undefined) {
url += '?' + queryString;
}
return url;
};
const writeSegments = (history, root, useHash, segments, direction, state, queryString) => {
const url = generateUrl([...parsePath(root).segments, ...segments], useHash, queryString);
if (direction === ROUTER_INTENT_FORWARD) {
history.pushState(state, '', url);
}
else {
history.replaceState(state, '', url);
}
};
/**
* Transforms a chain to a list of segments.
*
* Notes:
* - parameter segments of the form :param are replaced with their value,
* - null is returned when a value is missing for any parameter segment.
*/
const chainToSegments = (chain) => {
const segments = [];
for (const route of chain) {
for (const segment of route.segments) {
if (segment[0] === ':') {
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const param = route.params && route.params[segment.slice(1)];
if (!param) {
return null;
}
segments.push(param);
}
else if (segment !== '') {
segments.push(segment);
}
}
}
return segments;
};
/**
* Removes the prefix segments from the path segments.
*
* Return:
* - null when the path segments do not start with the passed prefix,
* - the path segments after the prefix otherwise.
*/
const removePrefix = (prefix, segments) => {
if (prefix.length > segments.length) {
return null;
}
if (prefix.length <= 1 && prefix[0] === '') {
return segments;
}
for (let i = 0; i < prefix.length; i++) {
if (prefix[i] !== segments[i]) {
return null;
}
}
if (segments.length === prefix.length) {
return [''];
}
return segments.slice(prefix.length);
};
const readSegments = (loc, root, useHash) => {
const prefix = parsePath(root).segments;
const pathname = useHash ? loc.hash.slice(1) : loc.pathname;
const segments = parsePath(pathname).segments;
return removePrefix(prefix, segments);
};
/**
* Parses the path to:
* - segments an array of '/' separated parts,
* - queryString (undefined when no query string).
*/
const parsePath = (path) => {
let segments = [''];
let queryString;
if (path != null) {
const qsStart = path.indexOf('?');
if (qsStart > -1) {
queryString = path.substring(qsStart + 1);
path = path.substring(0, qsStart);
}
segments = path
.split('/')
.map((s) => s.trim())
.filter((s) => s.length > 0);
if (segments.length === 0) {
segments = [''];
}
}
return { segments, queryString };
};
const printRoutes = (routes) => {
console.group(`[ion-core] ROUTES[${routes.length}]`);
for (const chain of routes) {
const segments = [];
chain.forEach((r) => segments.push(...r.segments));
const ids = chain.map((r) => r.id);
console.debug(`%c ${generatePath(segments)}`, 'font-weight: bold; padding-left: 20px', '=>\t', `(${ids.join(', ')})`);
}
console.groupEnd();
};
const printRedirects = (redirects) => {
console.group(`[ion-core] REDIRECTS[${redirects.length}]`);
for (const redirect of redirects) {
if (redirect.to) {
console.debug('FROM: ', `$c ${generatePath(redirect.from)}`, 'font-weight: bold', ' TO: ', `$c ${generatePath(redirect.to.segments)}`, 'font-weight: bold');
}
}
console.groupEnd();
};
/**
* Activates the passed route chain.
*
* There must be exactly one outlet per route entry in the chain.
*
* The methods calls setRouteId on each of the outlet with the corresponding route entry in the chain.
* setRouteId will create or select the view in the outlet.
*/
const writeNavState = async (root, chain, direction, index, changed = false, animation) => {
try {
// find next navigation outlet in the DOM
const outlet = searchNavNode(root);
// make sure we can continue interacting the DOM, otherwise abort
if (index >= chain.length || !outlet) {
return changed;
}
await new Promise((resolve) => componentOnReady(outlet, resolve));
const route = chain[index];
const result = await outlet.setRouteId(route.id, route.params, direction, animation);
// if the outlet changed the page, reset navigation to neutral (no direction)
// this means nested outlets will not animate
if (result.changed) {
direction = ROUTER_INTENT_NONE;
changed = true;
}
// recursively set nested outlets
changed = await writeNavState(result.element, chain, direction, index + 1, changed, animation);
// once all nested outlets are visible let's make the parent visible too,
// using markVisible prevents flickering
if (result.markVisible) {
await result.markVisible();
}
return changed;
}
catch (e) {
printIonError('[ion-router] - Exception in writeNavState:', e);
return false;
}
};
/**
* Recursively walks the outlet in the DOM.
*
* The function returns a list of RouteID corresponding to each of the outlet and the last outlet without a RouteID.
*/
const readNavState = async (root) => {
const ids = [];
let outlet;
let node = root;
// eslint-disable-next-line no-cond-assign
while ((outlet = searchNavNode(node))) {
const id = await outlet.getRouteId();
if (id) {
node = id.element;
id.element = undefined;
ids.push(id);
}
else {
break;
}
}
return { ids, outlet };
};
const waitUntilNavNode = () => {
if (searchNavNode(document.body)) {
return Promise.resolve();
}
return new Promise((resolve) => {
window.addEventListener('ionNavWillLoad', () => resolve(), { once: true });
});
};
/** Selector for all the outlets supported by the router. */
const OUTLET_SELECTOR = ':not([no-router]) ion-nav, :not([no-router]) ion-tabs, :not([no-router]) ion-router-outlet';
const searchNavNode = (root) => {
if (!root) {
return undefined;
}
if (root.matches(OUTLET_SELECTOR)) {
return root;
}
const outlet = root.querySelector(OUTLET_SELECTOR);
return outlet !== null && outlet !== void 0 ? outlet : undefined;
};
/**
* Returns whether the given redirect matches the given path segments.
*
* A redirect matches when the segments of the path and redirect.from are equal.
* Note that segments are only checked until redirect.from contains a '*' which matches any path segment.
* The path ['some', 'path', 'to', 'page'] matches both ['some', 'path', 'to', 'page'] and ['some', 'path', '*'].
*/
const matchesRedirect = (segments, redirect) => {
const { from, to } = redirect;
if (to === undefined) {
return false;
}
if (from.length > segments.length) {
return false;
}
for (let i = 0; i < from.length; i++) {
const expected = from[i];
if (expected === '*') {
return true;
}
if (expected !== segments[i]) {
return false;
}
}
return from.length === segments.length;
};
/** Returns the first redirect matching the path segments or undefined when no match found. */
const findRouteRedirect = (segments, redirects) => {
return redirects.find((redirect) => matchesRedirect(segments, redirect));
};
const matchesIDs = (ids, chain) => {
const len = Math.min(ids.length, chain.length);
let score = 0;
for (let i = 0; i < len; i++) {
const routeId = ids[i];
const routeChain = chain[i];
// Skip results where the route id does not match the chain at the same index
if (routeId.id.toLowerCase() !== routeChain.id) {
break;
}
if (routeId.params) {
const routeIdParams = Object.keys(routeId.params);
// Only compare routes with the chain that have the same number of parameters.
if (routeIdParams.length === routeChain.segments.length) {
// Maps the route's params into a path based on the path variable names,
// to compare against the route chain format.
//
// Before:
// ```ts
// {
// params: {
// s1: 'a',
// s2: 'b'
// }
// }
// ```
//
// After:
// ```ts
// [':s1',':s2']
// ```
//
const pathWithParams = routeIdParams.map((key) => `:${key}`);
for (let j = 0; j < pathWithParams.length; j++) {
// Skip results where the path variable is not a match
if (pathWithParams[j].toLowerCase() !== routeChain.segments[j]) {
break;
}
// Weight path matches for the same index higher.
score++;
}
}
}
// Weight id matches
score++;
}
return score;
};
/**
* Matches the segments against the chain.
*
* Returns:
* - null when there is no match,
* - a chain with the params properties updated with the parameter segments on match.
*/
const matchesSegments = (segments, chain) => {
const inputSegments = new RouterSegments(segments);
let matchesDefault = false;
let allparams;
for (let i = 0; i < chain.length; i++) {
const chainSegments = chain[i].segments;
if (chainSegments[0] === '') {
matchesDefault = true;
}
else {
for (const segment of chainSegments) {
const data = inputSegments.next();
// data param
if (segment[0] === ':') {
if (data === '') {
return null;
}
allparams = allparams || [];
const params = allparams[i] || (allparams[i] = {});
params[segment.slice(1)] = data;
}
else if (data !== segment) {
return null;
}
}
matchesDefault = false;
}
}
const matches = matchesDefault ? matchesDefault === (inputSegments.next() === '') : true;
if (!matches) {
return null;
}
if (allparams) {
return chain.map((route, i) => ({
id: route.id,
segments: route.segments,
params: mergeParams(route.params, allparams[i]),
beforeEnter: route.beforeEnter,
beforeLeave: route.beforeLeave,
}));
}
return chain;
};
/**
* Merges the route parameter objects.
* Returns undefined when both parameters are undefined.
*/
const mergeParams = (a, b) => {
return a || b ? Object.assign(Object.assign({}, a), b) : undefined;
};
/**
* Finds the best match for the ids in the chains.
*
* Returns the best match or null when no match is found.
* When a chain is returned the parameters are updated from the RouteIDs.
* That is they contain both the componentProps of the <ion-route> and the parameter segment.
*/
const findChainForIDs = (ids, chains) => {
let match = null;
let maxMatches = 0;
for (const chain of chains) {
const score = matchesIDs(ids, chain);
if (score > maxMatches) {
match = chain;
maxMatches = score;
}
}
if (match) {
return match.map((route, i) => {
var _a;
return ({
id: route.id,
segments: route.segments,
params: mergeParams(route.params, (_a = ids[i]) === null || _a === void 0 ? void 0 : _a.params),
});
});
}
return null;
};
/**
* Finds the best match for the segments in the chains.
*
* Returns the best match or null when no match is found.
* When a chain is returned the parameters are updated from the segments.
* That is they contain both the componentProps of the <ion-route> and the parameter segments.
*/
const findChainForSegments = (segments, chains) => {
let match = null;
let bestScore = 0;
for (const chain of chains) {
const matchedChain = matchesSegments(segments, chain);
if (matchedChain !== null) {
const score = computePriority(matchedChain);
if (score > bestScore) {
bestScore = score;
match = matchedChain;
}
}
}
return match;
};
/**
* Computes the priority of a chain.
*
* Parameter segments are given a lower priority over fixed segments.
*
* Considering the following 2 chains matching the path /path/to/page:
* - /path/to/:where
* - /path/to/page
*
* The second one will be given a higher priority because "page" is a fixed segment (vs ":where", a parameter segment).
*/
const computePriority = (chain) => {
let score = 1;
let level = 1;
for (const route of chain) {
for (const segment of route.segments) {
if (segment[0] === ':') {
score += Math.pow(1, level);
}
else if (segment !== '') {
score += Math.pow(2, level);
}
level++;
}
}
return score;
};
class RouterSegments {
constructor(segments) {
this.segments = segments.slice();
}
next() {
if (this.segments.length > 0) {
return this.segments.shift();
}
return '';
}
}
const readProp = (el, prop) => {
if (prop in el) {
return el[prop];
}
if (el.hasAttribute(prop)) {
return el.getAttribute(prop);
}
return null;
};
/**
* Extracts the redirects (that is <ion-route-redirect> elements inside the root).
*
* The redirects are returned as a list of RouteRedirect.
*/
const readRedirects = (root) => {
return Array.from(root.children)
.filter((el) => el.tagName === 'ION-ROUTE-REDIRECT')
.map((el) => {
const to = readProp(el, 'to');
return {
from: parsePath(readProp(el, 'from')).segments,
to: to == null ? undefined : parsePath(to),
};
});
};
/**
* Extracts all the routes (that is <ion-route> elements inside the root).
*
* The routes are returned as a list of chains - the flattened tree.
*/
const readRoutes = (root) => {
return flattenRouterTree(readRouteNodes(root));
};
/**
* Reads the route nodes as a tree modeled after the DOM tree of <ion-route> elements.
*
* Note: routes without a component are ignored together with their children.
*/
const readRouteNodes = (node) => {
return Array.from(node.children)
.filter((el) => el.tagName === 'ION-ROUTE' && el.component)
.map((el) => {
const component = readProp(el, 'component');
return {
segments: parsePath(readProp(el, 'url')).segments,
id: component.toLowerCase(),
params: el.componentProps,
beforeLeave: el.beforeLeave,
beforeEnter: el.beforeEnter,
children: readRouteNodes(el),
};
});
};
/**
* Flattens a RouterTree in a list of chains.
*
* Each chain represents a path from the root node to a terminal node.
*/
const flattenRouterTree = (nodes) => {
const chains = [];
for (const node of nodes) {
flattenNode([], chains, node);
}
return chains;
};
/** Flattens a route node recursively and push each branch to the chains list. */
const flattenNode = (chain, chains, node) => {
chain = [
...chain,
{
id: node.id,
segments: node.segments,
params: node.params,
beforeLeave: node.beforeLeave,
beforeEnter: node.beforeEnter,
},
];
if (node.children.length === 0) {
chains.push(chain);
return;
}
for (const child of node.children) {
flattenNode(chain, chains, child);
}
};
class Router {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionRouteWillChange = createEvent(this, "ionRouteWillChange", 7);
this.ionRouteDidChange = createEvent(this, "ionRouteDidChange", 7);
this.previousPath = null;
this.busy = false;
this.state = 0;
this.lastState = 0;
/**
* The root path to use when matching URLs. By default, this is set to "/", but you can specify
* an alternate prefix for all URL paths.
*/
this.root = '/';
/**
* The router can work in two "modes":
* - With hash: `/index.html#/path/to/page`
* - Without hash: `/path/to/page`
*
* Using one or another might depend in the requirements of your app and/or where it's deployed.
*
* Usually "hash-less" navigation works better for SEO and it's more user friendly too, but it might
* requires additional server-side configuration in order to properly work.
*
* On the other side hash-navigation is much easier to deploy, it even works over the file protocol.
*
* By default, this property is `true`, change to `false` to allow hash-less URLs.
*/
this.useHash = true;
}
async componentWillLoad() {
await waitUntilNavNode();
const canProceed = await this.runGuards(this.getSegments());
if (canProceed !== true) {
if (typeof canProceed === 'object') {
const { redirect } = canProceed;
const path = parsePath(redirect);
this.setSegments(path.segments, ROUTER_INTENT_NONE, path.queryString);
await this.writeNavStateRoot(path.segments, ROUTER_INTENT_NONE);
}
}
else {
await this.onRoutesChanged();
}
}
componentDidLoad() {
window.addEventListener('ionRouteRedirectChanged', debounce(this.onRedirectChanged.bind(this), 10));
window.addEventListener('ionRouteDataChanged', debounce(this.onRoutesChanged.bind(this), 100));
}
async onPopState() {
const direction = this.historyDirection();
let segments = this.getSegments();
const canProceed = await this.runGuards(segments);
if (canProceed !== true) {
if (typeof canProceed === 'object') {
segments = parsePath(canProceed.redirect).segments;
}
else {
return false;
}
}
return this.writeNavStateRoot(segments, direction);
}
onBackButton(ev) {
ev.detail.register(0, (processNextHandler) => {
this.back();
processNextHandler();
});
}
/** @internal */
async canTransition() {
const canProceed = await this.runGuards();
if (canProceed !== true) {
if (typeof canProceed === 'object') {
return canProceed.redirect;
}
else {
return false;
}
}
return true;
}
/**
* Navigate to the specified path.
*
* @param path The path to navigate to.
* @param direction The direction of the animation. Defaults to `"forward"`.
* @param animation A custom animation to use for the transition.
*/
async push(path, direction = 'forward', animation) {
var _a;
if (path.startsWith('.')) {
const currentPath = (_a = this.previousPath) !== null && _a !== void 0 ? _a : '/';
// Convert currentPath to an URL by pre-pending a protocol and a host to resolve the relative path.
const url = new URL(path, `https://host/${currentPath}`);
path = url.pathname + url.search;
}
let parsedPath = parsePath(path);
const canProceed = await this.runGuards(parsedPath.segments);
if (canProceed !== true) {
if (typeof canProceed === 'object') {
parsedPath = parsePath(canProceed.redirect);
}
else {
return false;
}
}
this.setSegments(parsedPath.segments, direction, parsedPath.queryString);
return this.writeNavStateRoot(parsedPath.segments, direction, animation);
}
/** Go back to previous page in the window.history. */
back() {
window.history.back();
return Promise.resolve(this.waitPromise);
}
/** @internal */
async printDebug() {
printRoutes(readRoutes(this.el));
printRedirects(readRedirects(this.el));
}
/** @internal */
async navChanged(direction) {
if (this.busy) {
printIonWarning('[ion-router] - Router is busy, navChanged was cancelled.');
return false;
}
const { ids, outlet } = await readNavState(window.document.body);
const routes = readRoutes(this.el);
const chain = findChainForIDs(ids, routes);
if (!chain) {
printIonWarning('[ion-router] - No matching URL for', ids.map((i) => i.id));
return false;
}
const segments = chainToSegments(chain);
if (!segments) {
printIonWarning('[ion-router] - Router could not match path because some required param is missing.');
return false;
}
this.setSegments(segments, direction);
await this.safeWriteNavState(outlet, chain, ROUTER_INTENT_NONE, segments, null, ids.length);
return true;
}
/** This handler gets called when a `ion-route-redirect` component is added to the DOM or if the from or to property of such node changes. */
onRedirectChanged() {
const segments = this.getSegments();
if (segments && findRouteRedirect(segments, readRedirects(this.el))) {
this.writeNavStateRoot(segments, ROUTER_INTENT_NONE);
}
}
/** This handler gets called when a `ion-route` component is added to the DOM or if the from or to property of such node changes. */
onRoutesChanged() {
return this.writeNavStateRoot(this.getSegments(), ROUTER_INTENT_NONE);
}
historyDirection() {
var _a;
const win = window;
if (win.history.state === null) {
this.state++;
win.history.replaceState(this.state, win.document.title, (_a = win.document.location) === null || _a === void 0 ? void 0 : _a.href);
}
const state = win.history.state;
const lastState = this.lastState;
this.lastState = state;
if (state > lastState || (state >= lastState && lastState > 0)) {
return ROUTER_INTENT_FORWARD;
}
if (state < lastState) {
return ROUTER_INTENT_BACK;
}
return ROUTER_INTENT_NONE;
}
async writeNavStateRoot(segments, direction, animation) {
if (!segments) {
printIonError('[ion-router] - URL is not part of the routing set.');
return false;
}
// lookup redirect rule
const redirects = readRedirects(this.el);
const redirect = findRouteRedirect(segments, redirects);
let redirectFrom = null;
if (redirect) {
const { segments: toSegments, queryString } = redirect.to;
this.setSegments(toSegments, direction, queryString);
redirectFrom = redirect.from;
segments = toSegments;
}
// lookup route chain
const routes = readRoutes(this.el);
const chain = findChainForSegments(segments, routes);
if (!chain) {
printIonError('[ion-router] - The path does not match any route.');
return false;
}
// write DOM give
return this.safeWriteNavState(document.body, chain, direction, segments, redirectFrom, 0, animation);
}
async safeWriteNavState(node, chain, direction, segments, redirectFrom, index = 0, animation) {
const unlock = await this.lock();
let changed = false;
try {
changed = await this.writeNavState(node, chain, direction, segments, redirectFrom, index, animation);
}
catch (e) {
printIonError('[ion-router] - Exception in safeWriteNavState:', e);
}
unlock();
return changed;
}
async lock() {
const p = this.waitPromise;
let resolve;
this.waitPromise = new Promise((r) => (resolve = r));
if (p !== undefined) {
await p;
}
return resolve;
}
/**
* Executes the beforeLeave hook of the source route and the beforeEnter hook of the target route if they exist.
*
* When the beforeLeave hook does not return true (to allow navigating) then that value is returned early and the beforeEnter is executed.
* Otherwise the beforeEnterHook hook of the target route is executed.
*/
async runGuards(to = this.getSegments(), from) {
if (from === undefined) {
from = parsePath(this.previousPath).segments;
}
if (!to || !from) {
return true;
}
const routes = readRoutes(this.el);
const fromChain = findChainForSegments(from, routes);
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const beforeLeaveHook = fromChain && fromChain[fromChain.length - 1].beforeLeave;
const canLeave = beforeLeaveHook ? await beforeLeaveHook() : true;
if (canLeave === false || typeof canLeave === 'object') {
return canLeave;
}
const toChain = findChainForSegments(to, routes);
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
const beforeEnterHook = toChain && toChain[toChain.length - 1].beforeEnter;
return beforeEnterHook ? beforeEnterHook() : true;
}
async writeNavState(node, chain, direction, segments, redirectFrom, index = 0, animation) {
if (this.busy) {
printIonWarning('[ion-router] - Router is busy, transition was cancelled.');
return false;
}
this.busy = true;
// generate route event and emit will change
const routeEvent = this.routeChangeEvent(segments, redirectFrom);
if (routeEvent) {
this.ionRouteWillChange.emit(routeEvent);
}
const changed = await writeNavState(node, chain, direction, index, false, animation);
this.busy = false;
// emit did change
if (routeEvent) {
this.ionRouteDidChange.emit(routeEvent);
}
return changed;
}
setSegments(segments, direction, queryString) {
this.state++;
writeSegments(window.history, this.root, this.useHash, segments, direction, this.state, queryString);
}
getSegments() {
return readSegments(window.location, this.root, this.useHash);
}
routeChangeEvent(toSegments, redirectFromSegments) {
const from = this.previousPath;
const to = generatePath(toSegments);
this.previousPath = to;
if (to === from) {
return null;
}
const redirectedFrom = redirectFromSegments ? generatePath(redirectFromSegments) : null;
return {
from,
redirectedFrom,
to,
};
}
get el() { return getElement(this); }
static get cmpMeta() { return {
"$flags$": 0,
"$tagName$": "ion-router",
"$members$": {
"root": [1],
"useHash": [4, "use-hash"],
"canTransition": [64],
"push": [64],
"back": [64],
"printDebug": [64],
"navChanged": [64]
},
"$listeners$": [[8, "popstate", "onPopState"], [4, "ionBackButton", "onBackButton"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const routerLinkCss = ":host{--background:transparent;--color:var(--ion-color-primary, #0054e9);background:var(--background);color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}a{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit}";
class RouterLink {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* When using a router, it specifies the transition direction when navigating to
* another page using `href`.
*/
this.routerDirection = 'forward';
this.onClick = (ev) => {
openURL(this.href, ev, this.routerDirection, this.routerAnimation);
};
}
render() {
const mode = getIonMode$1(this);
const attrs = {
href: this.href,
rel: this.rel,
target: this.target,
};
return (hAsync(Host, { key: 'd7f2affcde45c5fbb6cb46cd1c30008ee92a68c5', onClick: this.onClick, class: createColorClasses$1(this.color, {
[mode]: true,
'ion-activatable': true,
}) }, hAsync("a", Object.assign({ key: 'babafae85ca5c6429958d383feff0493ff8cf33e' }, attrs), hAsync("slot", { key: '50314e9555bbf6dffa0c50c3f763009dee59b10b' }))));
}
static get style() { return routerLinkCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-router-link",
"$members$": {
"color": [513],
"href": [1],
"rel": [1],
"routerDirection": [1, "router-direction"],
"routerAnimation": [16],
"target": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const routerOutletCss = ":host{left:0;right:0;top:0;bottom:0;position:absolute;contain:layout size style;z-index:0}";
class RouterOutlet {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionNavWillLoad = createEvent(this, "ionNavWillLoad", 7);
this.ionNavWillChange = createEvent(this, "ionNavWillChange", 3);
this.ionNavDidChange = createEvent(this, "ionNavDidChange", 3);
this.lockController = createLockController();
this.gestureOrAnimationInProgress = false;
/**
* The mode determines which platform styles to use.
*/
this.mode = getIonMode$1(this);
/**
* If `true`, the router-outlet should animate the transition of components.
*/
this.animated = true;
}
swipeHandlerChanged() {
if (this.gesture) {
this.gesture.enable(this.swipeHandler !== undefined);
}
}
async connectedCallback() {
const onStart = () => {
this.gestureOrAnimationInProgress = true;
if (this.swipeHandler) {
this.swipeHandler.onStart();
}
};
this.gesture = (await Promise.resolve().then(function () { return swipeBack; })).createSwipeBackGesture(this.el, () => !this.gestureOrAnimationInProgress && !!this.swipeHandler && this.swipeHandler.canStart(), () => onStart(), (step) => { var _a; return (_a = this.ani) === null || _a === void 0 ? void 0 : _a.progressStep(step); }, (shouldComplete, step, dur) => {
if (this.ani) {
this.ani.onFinish(() => {
this.gestureOrAnimationInProgress = false;
if (this.swipeHandler) {
this.swipeHandler.onEnd(shouldComplete);
}
}, { oneTimeCallback: true });
// Account for rounding errors in JS
let newStepValue = shouldComplete ? -1e-3 : 0.001;
/**
* Animation will be reversed here, so need to
* reverse the easing curve as well
*
* Additionally, we need to account for the time relative
* to the new easing curve, as `stepValue` is going to be given
* in terms of a linear curve.
*/
if (!shouldComplete) {
this.ani.easing('cubic-bezier(1, 0, 0.68, 0.28)');
newStepValue += getTimeGivenProgression([0, 0], [1, 0], [0.68, 0.28], [1, 1], step)[0];
}
else {
newStepValue += getTimeGivenProgression([0, 0], [0.32, 0.72], [0, 1], [1, 1], step)[0];
}
this.ani.progressEnd(shouldComplete ? 1 : 0, newStepValue, dur);
}
else {
this.gestureOrAnimationInProgress = false;
}
});
this.swipeHandlerChanged();
}
componentWillLoad() {
this.ionNavWillLoad.emit();
}
disconnectedCallback() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
/** @internal */
async commit(enteringEl, leavingEl, opts) {
const unlock = await this.lockController.lock();
let changed = false;
try {
changed = await this.transition(enteringEl, leavingEl, opts);
}
catch (e) {
printIonError('[ion-router-outlet] - Exception in commit:', e);
}
unlock();
return changed;
}
/** @internal */
async setRouteId(id, params, direction, animation) {
const changed = await this.setRoot(id, params, {
duration: direction === 'root' ? 0 : undefined,
direction: direction === 'back' ? 'back' : 'forward',
animationBuilder: animation,
});
return {
changed,
element: this.activeEl,
};
}
/** @internal */
async getRouteId() {
const active = this.activeEl;
return active
? {
id: active.tagName,
element: active,
params: this.activeParams,
}
: undefined;
}
async setRoot(component, params, opts) {
if (this.activeComponent === component && shallowEqualStringMap(params, this.activeParams)) {
return false;
}
// attach entering view to DOM
const leavingEl = this.activeEl;
const enteringEl = await attachComponent(this.delegate, this.el, component, ['ion-page', 'ion-page-invisible'], params);
this.activeComponent = component;
this.activeEl = enteringEl;
this.activeParams = params;
// commit animation
await this.commit(enteringEl, leavingEl, opts);
await detachComponent(this.delegate, leavingEl);
return true;
}
async transition(enteringEl, leavingEl, opts = {}) {
if (leavingEl === enteringEl) {
return false;
}
// emit nav will change event
this.ionNavWillChange.emit();
const { el, mode } = this;
const animated = this.animated && config.getBoolean('animated', true);
const animationBuilder = opts.animationBuilder || this.animation || config.get('navAnimation');
await transition(Object.assign(Object.assign({ mode,
animated,
enteringEl,
leavingEl, baseEl: el,
/**
* We need to wait for all Stencil components
* to be ready only when using the lazy
* loaded bundle.
*/
deepWait: hasLazyBuild(el), progressCallback: opts.progressAnimation
? (ani) => {
/**
* Because this progress callback is called asynchronously
* it is possible for the gesture to start and end before
* the animation is ever set. In that scenario, we should
* immediately call progressEnd so that the transition promise
* resolves and the gesture does not get locked up.
*/
if (ani !== undefined && !this.gestureOrAnimationInProgress) {
this.gestureOrAnimationInProgress = true;
ani.onFinish(() => {
this.gestureOrAnimationInProgress = false;
if (this.swipeHandler) {
this.swipeHandler.onEnd(false);
}
}, { oneTimeCallback: true });
/**
* Playing animation to beginning
* with a duration of 0 prevents
* any flickering when the animation
* is later cleaned up.
*/
ani.progressEnd(0, 0, 0);
}
else {
this.ani = ani;
}
}
: undefined }, opts), { animationBuilder }));
// emit nav changed event
this.ionNavDidChange.emit();
return true;
}
render() {
return hAsync("slot", { key: '84b50f1155b0d780dff802ee13223287259fd525' });
}
get el() { return getElement(this); }
static get watchers() { return {
"swipeHandler": ["swipeHandlerChanged"]
}; }
static get style() { return routerOutletCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-router-outlet",
"$members$": {
"mode": [1025],
"delegate": [16],
"animated": [4],
"animation": [16],
"swipeHandler": [16],
"commit": [64],
"setRouteId": [64],
"getRouteId": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const rowCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}";
class Row {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
return (hAsync(Host, { key: '65592a79621bd8f75f9566db3e8c05a4b8fc6048', class: getIonMode$1(this) }, hAsync("slot", { key: '56f09784db7a0299c9ce76dfcede185b295251ff' })));
}
static get style() { return rowCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-row",
"$members$": undefined,
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const searchbarIosCss = ".sc-ion-searchbar-ios-h{--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;width:100%;color:var(--color);font-family:var(--ion-font-family, inherit);-webkit-box-sizing:border-box;box-sizing:border-box}.ion-color.sc-ion-searchbar-ios-h{color:var(--ion-color-contrast)}.ion-color.sc-ion-searchbar-ios-h .searchbar-input.sc-ion-searchbar-ios{background:var(--ion-color-base)}.ion-color.sc-ion-searchbar-ios-h .searchbar-clear-button.sc-ion-searchbar-ios,.ion-color.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios,.ion-color.sc-ion-searchbar-ios-h .searchbar-search-icon.sc-ion-searchbar-ios{color:inherit}.searchbar-search-icon.sc-ion-searchbar-ios{color:var(--icon-color);pointer-events:none}.searchbar-input-container.sc-ion-searchbar-ios{display:block;position:relative;-ms-flex-negative:1;flex-shrink:1;width:100%}.searchbar-input.sc-ion-searchbar-ios{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;border-radius:var(--border-radius);display:block;width:100%;min-height:inherit;border:0;outline:none;background:var(--background);font-family:inherit;-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbar-input.sc-ion-searchbar-ios::-webkit-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-ios::-moz-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-ios:-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-ios::-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-ios::placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-ios::-webkit-search-cancel-button,.searchbar-input.sc-ion-searchbar-ios::-ms-clear{display:none}.searchbar-cancel-button.sc-ion-searchbar-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:none;height:100%;border:0;outline:none;color:var(--cancel-button-color);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbar-cancel-button.sc-ion-searchbar-ios>div.sc-ion-searchbar-ios{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%}.searchbar-clear-button.sc-ion-searchbar-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:none;min-height:0;outline:none;color:var(--clear-button-color);-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbar-clear-button.sc-ion-searchbar-ios:focus{opacity:0.5}.searchbar-has-value.searchbar-should-show-clear.sc-ion-searchbar-ios-h .searchbar-clear-button.sc-ion-searchbar-ios{display:block}.searchbar-disabled.sc-ion-searchbar-ios-h{cursor:default;opacity:0.4;pointer-events:none}.sc-ion-searchbar-ios-h{--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.07);--border-radius:10px;--box-shadow:none;--cancel-button-color:var(--ion-color-primary, #0054e9);--clear-button-color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));--color:var(--ion-text-color, #000);--icon-color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:12px;padding-bottom:12px;min-height:60px;contain:content}.searchbar-input-container.sc-ion-searchbar-ios{min-height:36px}.searchbar-search-icon.sc-ion-searchbar-ios{-webkit-margin-start:calc(50% - 60px);margin-inline-start:calc(50% - 60px);top:0;position:absolute;width:1.375rem;height:100%;contain:strict}.searchbar-search-icon.sc-ion-searchbar-ios{inset-inline-start:5px}.searchbar-input.sc-ion-searchbar-ios{-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:6px;padding-bottom:6px;height:100%;font-size:1.0625rem;font-weight:400;contain:strict}.searchbar-has-value.searchbar-should-show-clear.sc-ion-searchbar-ios-h .searchbar-input.sc-ion-searchbar-ios{-webkit-padding-start:1.75rem;padding-inline-start:1.75rem;-webkit-padding-end:1.75rem;padding-inline-end:1.75rem}.searchbar-clear-button.sc-ion-searchbar-ios{top:0;background-position:center;position:absolute;width:1.875rem;height:100%;border:0;background-color:transparent}.searchbar-clear-button.sc-ion-searchbar-ios{inset-inline-end:0}.searchbar-clear-icon.sc-ion-searchbar-ios{width:1.125rem;height:100%}.searchbar-cancel-button.sc-ion-searchbar-ios{-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:0;padding-inline-end:0;padding-top:0;padding-bottom:0;-ms-flex-negative:0;flex-shrink:0;background-color:transparent;font-size:17px}.searchbar-left-aligned.sc-ion-searchbar-ios-h .searchbar-search-icon.sc-ion-searchbar-ios{-webkit-margin-start:0;margin-inline-start:0}.searchbar-left-aligned.sc-ion-searchbar-ios-h .searchbar-input.sc-ion-searchbar-ios{-webkit-padding-start:1.875rem;padding-inline-start:1.875rem}.searchbar-has-focus.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios,.searchbar-should-show-cancel.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios,.searchbar-animated.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios{display:block}.searchbar-animated.sc-ion-searchbar-ios-h .searchbar-search-icon.sc-ion-searchbar-ios,.searchbar-animated.sc-ion-searchbar-ios-h .searchbar-input.sc-ion-searchbar-ios{-webkit-transition:all 300ms ease;transition:all 300ms ease}.searchbar-animated.searchbar-has-focus.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios,.searchbar-animated.searchbar-should-show-cancel.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios{opacity:1;pointer-events:auto}.searchbar-animated.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios{-webkit-margin-end:-100%;margin-inline-end:-100%;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transition:all 300ms ease;transition:all 300ms ease;opacity:0;pointer-events:none}.searchbar-no-animate.sc-ion-searchbar-ios-h .searchbar-search-icon.sc-ion-searchbar-ios,.searchbar-no-animate.sc-ion-searchbar-ios-h .searchbar-input.sc-ion-searchbar-ios,.searchbar-no-animate.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios{-webkit-transition-duration:0ms;transition-duration:0ms}.ion-color.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios{color:var(--ion-color-base)}@media (any-hover: hover){.ion-color.sc-ion-searchbar-ios-h .searchbar-cancel-button.sc-ion-searchbar-ios:hover{color:var(--ion-color-tint)}}ion-toolbar.sc-ion-searchbar-ios-h,ion-toolbar .sc-ion-searchbar-ios-h{padding-top:1px;padding-bottom:15px;min-height:52px}ion-toolbar.ion-color.sc-ion-searchbar-ios-h:not(.ion-color),ion-toolbar.ion-color .sc-ion-searchbar-ios-h:not(.ion-color){color:inherit}ion-toolbar.ion-color.sc-ion-searchbar-ios-h:not(.ion-color) .searchbar-cancel-button.sc-ion-searchbar-ios,ion-toolbar.ion-color .sc-ion-searchbar-ios-h:not(.ion-color) .searchbar-cancel-button.sc-ion-searchbar-ios{color:currentColor}ion-toolbar.ion-color.sc-ion-searchbar-ios-h .searchbar-search-icon.sc-ion-searchbar-ios,ion-toolbar.ion-color .sc-ion-searchbar-ios-h .searchbar-search-icon.sc-ion-searchbar-ios{color:currentColor;opacity:0.5}ion-toolbar.ion-color.sc-ion-searchbar-ios-h:not(.ion-color) .searchbar-input.sc-ion-searchbar-ios,ion-toolbar.ion-color .sc-ion-searchbar-ios-h:not(.ion-color) .searchbar-input.sc-ion-searchbar-ios{background:rgba(var(--ion-color-contrast-rgb), 0.07);color:currentColor}ion-toolbar.ion-color.sc-ion-searchbar-ios-h:not(.ion-color) .searchbar-clear-button.sc-ion-searchbar-ios,ion-toolbar.ion-color .sc-ion-searchbar-ios-h:not(.ion-color) .searchbar-clear-button.sc-ion-searchbar-ios{color:currentColor;opacity:0.5}";
const searchbarMdCss = ".sc-ion-searchbar-md-h{--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;width:100%;color:var(--color);font-family:var(--ion-font-family, inherit);-webkit-box-sizing:border-box;box-sizing:border-box}.ion-color.sc-ion-searchbar-md-h{color:var(--ion-color-contrast)}.ion-color.sc-ion-searchbar-md-h .searchbar-input.sc-ion-searchbar-md{background:var(--ion-color-base)}.ion-color.sc-ion-searchbar-md-h .searchbar-clear-button.sc-ion-searchbar-md,.ion-color.sc-ion-searchbar-md-h .searchbar-cancel-button.sc-ion-searchbar-md,.ion-color.sc-ion-searchbar-md-h .searchbar-search-icon.sc-ion-searchbar-md{color:inherit}.searchbar-search-icon.sc-ion-searchbar-md{color:var(--icon-color);pointer-events:none}.searchbar-input-container.sc-ion-searchbar-md{display:block;position:relative;-ms-flex-negative:1;flex-shrink:1;width:100%}.searchbar-input.sc-ion-searchbar-md{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;border-radius:var(--border-radius);display:block;width:100%;min-height:inherit;border:0;outline:none;background:var(--background);font-family:inherit;-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbar-input.sc-ion-searchbar-md::-webkit-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-md::-moz-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-md:-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-md::-ms-input-placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-md::placeholder{color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.searchbar-input.sc-ion-searchbar-md::-webkit-search-cancel-button,.searchbar-input.sc-ion-searchbar-md::-ms-clear{display:none}.searchbar-cancel-button.sc-ion-searchbar-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;display:none;height:100%;border:0;outline:none;color:var(--cancel-button-color);cursor:pointer;-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbar-cancel-button.sc-ion-searchbar-md>div.sc-ion-searchbar-md{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%}.searchbar-clear-button.sc-ion-searchbar-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:none;min-height:0;outline:none;color:var(--clear-button-color);-webkit-appearance:none;-moz-appearance:none;appearance:none}.searchbar-clear-button.sc-ion-searchbar-md:focus{opacity:0.5}.searchbar-has-value.searchbar-should-show-clear.sc-ion-searchbar-md-h .searchbar-clear-button.sc-ion-searchbar-md{display:block}.searchbar-disabled.sc-ion-searchbar-md-h{cursor:default;opacity:0.4;pointer-events:none}.sc-ion-searchbar-md-h{--background:var(--ion-background-color, #fff);--border-radius:2px;--box-shadow:0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 1px 5px 0 rgba(0, 0, 0, 0.12);--cancel-button-color:var(--ion-color-step-900, var(--ion-text-color-step-100, #1a1a1a));--clear-button-color:initial;--color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));--icon-color:var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));-webkit-padding-start:8px;padding-inline-start:8px;-webkit-padding-end:8px;padding-inline-end:8px;padding-top:8px;padding-bottom:8px;background:inherit}.searchbar-search-icon.sc-ion-searchbar-md{top:11px;width:1.3125rem;height:1.3125rem}.searchbar-search-icon.sc-ion-searchbar-md{inset-inline-start:16px}.searchbar-cancel-button.sc-ion-searchbar-md{top:0;background-color:transparent;font-size:1.5em}.searchbar-cancel-button.sc-ion-searchbar-md{inset-inline-start:9px}.searchbar-search-icon.sc-ion-searchbar-md,.searchbar-cancel-button.sc-ion-searchbar-md{position:absolute}.searchbar-search-icon.ion-activated.sc-ion-searchbar-md,.searchbar-cancel-button.ion-activated.sc-ion-searchbar-md{background-color:transparent}.searchbar-input.sc-ion-searchbar-md{-webkit-padding-start:3.4375rem;padding-inline-start:3.4375rem;-webkit-padding-end:3.4375rem;padding-inline-end:3.4375rem;padding-top:0.375rem;padding-bottom:0.375rem;background-position:left 8px center;height:auto;font-size:1rem;font-weight:400;line-height:30px}[dir=rtl].sc-ion-searchbar-md-h .searchbar-input.sc-ion-searchbar-md,[dir=rtl] .sc-ion-searchbar-md-h .searchbar-input.sc-ion-searchbar-md{background-position:right 8px center}[dir=rtl].sc-ion-searchbar-md .searchbar-input.sc-ion-searchbar-md{background-position:right 8px center}@supports selector(:dir(rtl)){.searchbar-input.sc-ion-searchbar-md:dir(rtl){background-position:right 8px center}}.searchbar-clear-button.sc-ion-searchbar-md{top:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;position:absolute;height:100%;border:0;background-color:transparent}.searchbar-clear-button.sc-ion-searchbar-md{inset-inline-end:13px}.searchbar-clear-button.ion-activated.sc-ion-searchbar-md{background-color:transparent}.searchbar-clear-icon.sc-ion-searchbar-md{width:1.375rem;height:100%}.searchbar-has-focus.sc-ion-searchbar-md-h .searchbar-search-icon.sc-ion-searchbar-md{display:block}.searchbar-has-focus.sc-ion-searchbar-md-h .searchbar-cancel-button.sc-ion-searchbar-md,.searchbar-should-show-cancel.sc-ion-searchbar-md-h .searchbar-cancel-button.sc-ion-searchbar-md{display:block}.searchbar-has-focus.sc-ion-searchbar-md-h .searchbar-cancel-button.sc-ion-searchbar-md+.searchbar-search-icon.sc-ion-searchbar-md,.searchbar-should-show-cancel.sc-ion-searchbar-md-h .searchbar-cancel-button.sc-ion-searchbar-md+.searchbar-search-icon.sc-ion-searchbar-md{display:none}ion-toolbar.sc-ion-searchbar-md-h,ion-toolbar .sc-ion-searchbar-md-h{-webkit-padding-start:7px;padding-inline-start:7px;-webkit-padding-end:7px;padding-inline-end:7px;padding-top:3px;padding-bottom:3px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Searchbar {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionInput = createEvent(this, "ionInput", 7);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionCancel = createEvent(this, "ionCancel", 7);
this.ionClear = createEvent(this, "ionClear", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionStyle = createEvent(this, "ionStyle", 7);
this.isCancelVisible = false;
this.shouldAlignLeft = true;
this.inputId = `ion-searchbar-${searchbarIds++}`;
this.inheritedAttributes = {};
this.focused = false;
this.noAnimate = true;
/**
* If `true`, enable searchbar animation.
*/
this.animated = false;
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
this.autocapitalize = 'off';
/**
* Set the input's autocomplete property.
*/
this.autocomplete = 'off';
/**
* Set the input's autocorrect property.
*/
this.autocorrect = 'off';
/**
* Set the cancel button icon. Only applies to `md` mode.
* Defaults to `arrow-back-sharp`.
*/
this.cancelButtonIcon = config.get('backButtonIcon', arrowBackSharp);
/**
* Set the cancel button text. Only applies to `ios` mode.
*/
this.cancelButtonText = 'Cancel';
/**
* If `true`, the user cannot interact with the input.
*/
this.disabled = false;
/**
* If used in a form, set the name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* Set the input's placeholder.
* `placeholder` can accept either plaintext or HTML as a string.
* To display characters normally reserved for HTML, they
* must be escaped. For example `<Ionic>` would become
* `&lt;Ionic&gt;`
*
* For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
this.placeholder = 'Search';
/**
* Sets the behavior for the cancel button. Defaults to `"never"`.
* Setting to `"focus"` shows the cancel button on focus.
* Setting to `"never"` hides the cancel button.
* Setting to `"always"` shows the cancel button regardless
* of focus state.
*/
this.showCancelButton = 'never';
/**
* Sets the behavior for the clear button. Defaults to `"focus"`.
* Setting to `"focus"` shows the clear button on focus if the
* input is not empty.
* Setting to `"never"` hides the clear button.
* Setting to `"always"` shows the clear button regardless
* of focus state, but only if the input is not empty.
*/
this.showClearButton = 'always';
/**
* If `true`, enable spellcheck on the input.
*/
this.spellcheck = false;
/**
* Set the type of the input.
*/
this.type = 'search';
/**
* the value of the searchbar.
*/
this.value = '';
/**
* Clears the input field and triggers the control change.
*/
this.onClearInput = async (shouldFocus) => {
this.ionClear.emit();
return new Promise((resolve) => {
// setTimeout() fixes https://github.com/ionic-team/ionic-framework/issues/7527
// wait for 4 frames
setTimeout(() => {
const value = this.getValue();
if (value !== '') {
this.value = '';
this.emitInputChange();
/**
* When tapping clear button
* ensure input is focused after
* clearing input so users
* can quickly start typing.
*/
if (shouldFocus && !this.focused) {
this.setFocus();
/**
* The setFocus call above will clear focusedValue,
* but ionChange will never have gotten a chance to
* fire. Manually revert focusedValue so onBlur can
* compare against what was in the box before the clear.
*/
this.focusedValue = value;
}
}
resolve();
}, 16 * 4);
});
};
/**
* Clears the input field and tells the input to blur since
* the clearInput function doesn't want the input to blur
* then calls the custom cancel function if the user passed one in.
*/
this.onCancelSearchbar = async (ev) => {
if (ev) {
ev.preventDefault();
ev.stopPropagation();
}
this.ionCancel.emit();
// get cached values before clearing the input
const value = this.getValue();
const focused = this.focused;
await this.onClearInput();
/**
* If there used to be something in the box, and we weren't focused
* beforehand (meaning no blur fired that would already handle this),
* manually fire ionChange.
*/
if (value && !focused) {
this.emitValueChange(ev);
}
if (this.nativeInput) {
this.nativeInput.blur();
}
};
/**
* Update the Searchbar input value when the input changes
*/
this.onInput = (ev) => {
const input = ev.target;
if (input) {
this.value = input.value;
}
this.emitInputChange(ev);
};
this.onChange = (ev) => {
this.emitValueChange(ev);
};
/**
* Sets the Searchbar to not focused and checks if it should align left
* based on whether there is a value in the searchbar or not.
*/
this.onBlur = (ev) => {
this.focused = false;
this.ionBlur.emit();
this.positionElements();
if (this.focusedValue !== this.value) {
this.emitValueChange(ev);
}
this.focusedValue = undefined;
};
/**
* Sets the Searchbar to focused and active on input focus.
*/
this.onFocus = () => {
this.focused = true;
this.focusedValue = this.value;
this.ionFocus.emit();
this.positionElements();
};
}
/**
* lang and dir are globally enumerated attributes.
* As a result, creating these as properties
* can have unintended side effects. Instead, we
* listen for attribute changes and inherit them
* to the inner `<input>` element.
*/
onLangChanged(newValue) {
this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { lang: newValue });
}
onDirChanged(newValue) {
this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { dir: newValue });
}
debounceChanged() {
const { ionInput, debounce, originalIonInput } = this;
/**
* If debounce is undefined, we have to manually revert the ionInput emitter in case
* debounce used to be set to a number. Otherwise, the event would stay debounced.
*/
this.ionInput = debounce === undefined ? originalIonInput !== null && originalIonInput !== void 0 ? originalIonInput : ionInput : debounceEvent(ionInput, debounce);
}
valueChanged() {
const inputEl = this.nativeInput;
const value = this.getValue();
if (inputEl && inputEl.value !== value) {
inputEl.value = value;
}
}
showCancelButtonChanged() {
requestAnimationFrame(() => {
this.positionElements();
});
}
connectedCallback() {
this.emitStyle();
}
componentWillLoad() {
this.inheritedAttributes = Object.assign({}, inheritAttributes$1(this.el, ['lang', 'dir']));
}
componentDidLoad() {
this.originalIonInput = this.ionInput;
this.positionElements();
this.debounceChanged();
setTimeout(() => {
this.noAnimate = false;
}, 300);
}
emitStyle() {
this.ionStyle.emit({
searchbar: true,
});
}
/**
* Sets focus on the native `input` in `ion-searchbar`. Use this method instead of the global
* `input.focus()`.
* Developers who wish to focus an input when a page enters
* should call `setFocus()` in the `ionViewDidEnter()` lifecycle method.
* Developers who wish to focus an input when an overlay is presented
* should call `setFocus` after `didPresent` has resolved.
*
* See [managing focus](/docs/developing/managing-focus) for more information.
*/
async setFocus() {
if (this.nativeInput) {
this.nativeInput.focus();
}
}
/**
* Returns the native `<input>` element used under the hood.
*/
async getInputElement() {
/**
* If this gets called in certain early lifecycle hooks (ex: Vue onMounted),
* nativeInput won't be defined yet with the custom elements build, so wait for it to load in.
*/
if (!this.nativeInput) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.nativeInput);
}
/**
* Emits an `ionChange` event.
*
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitValueChange(event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
// Emitting a value change should update the internal state for tracking the focused value
this.focusedValue = newValue;
this.ionChange.emit({ value: newValue, event });
}
/**
* Emits an `ionInput` event.
*/
emitInputChange(event) {
const { value } = this;
this.ionInput.emit({ value, event });
}
/**
* Positions the input search icon, placeholder, and the cancel button
* based on the input value and if it is focused. (ios only)
*/
positionElements() {
const value = this.getValue();
const prevAlignLeft = this.shouldAlignLeft;
const mode = getIonMode$1(this);
const shouldAlignLeft = !this.animated || value.trim() !== '' || !!this.focused;
this.shouldAlignLeft = shouldAlignLeft;
if (mode !== 'ios') {
return;
}
if (prevAlignLeft !== shouldAlignLeft) {
this.positionPlaceholder();
}
if (this.animated) {
this.positionCancelButton();
}
}
/**
* Positions the input placeholder
*/
positionPlaceholder() {
const inputEl = this.nativeInput;
if (!inputEl) {
return;
}
const rtl = isRTL$1(this.el);
const iconEl = (this.el.shadowRoot || this.el).querySelector('.searchbar-search-icon');
if (this.shouldAlignLeft) {
inputEl.removeAttribute('style');
iconEl.removeAttribute('style');
}
else {
// Create a dummy span to get the placeholder width
const doc = document;
const tempSpan = doc.createElement('span');
tempSpan.innerText = this.placeholder || '';
doc.body.appendChild(tempSpan);
// Get the width of the span then remove it
raf(() => {
const textWidth = tempSpan.offsetWidth;
tempSpan.remove();
// Calculate the input padding
const inputLeft = 'calc(50% - ' + textWidth / 2 + 'px)';
// Calculate the icon margin
/**
* We take the icon width to account
* for any text scales applied to the icon
* such as Dynamic Type on iOS as well as 8px
* of padding.
*/
const iconLeft = 'calc(50% - ' + (textWidth / 2 + iconEl.clientWidth + 8) + 'px)';
// Set the input padding start and icon margin start
if (rtl) {
inputEl.style.paddingRight = inputLeft;
iconEl.style.marginRight = iconLeft;
}
else {
inputEl.style.paddingLeft = inputLeft;
iconEl.style.marginLeft = iconLeft;
}
});
}
}
/**
* Show the iOS Cancel button on focus, hide it offscreen otherwise
*/
positionCancelButton() {
const rtl = isRTL$1(this.el);
const cancelButton = (this.el.shadowRoot || this.el).querySelector('.searchbar-cancel-button');
const shouldShowCancel = this.shouldShowCancelButton();
if (cancelButton !== null && shouldShowCancel !== this.isCancelVisible) {
const cancelStyle = cancelButton.style;
this.isCancelVisible = shouldShowCancel;
if (shouldShowCancel) {
if (rtl) {
cancelStyle.marginLeft = '0';
}
else {
cancelStyle.marginRight = '0';
}
}
else {
const offset = cancelButton.offsetWidth;
if (offset > 0) {
if (rtl) {
cancelStyle.marginLeft = -offset + 'px';
}
else {
cancelStyle.marginRight = -offset + 'px';
}
}
}
}
}
getValue() {
return this.value || '';
}
hasValue() {
return this.getValue() !== '';
}
/**
* Determines whether or not the cancel button should be visible onscreen.
* Cancel button should be shown if one of two conditions applies:
* 1. `showCancelButton` is set to `always`.
* 2. `showCancelButton` is set to `focus`, and the searchbar has been focused.
*/
shouldShowCancelButton() {
if (this.showCancelButton === 'never' || (this.showCancelButton === 'focus' && !this.focused)) {
return false;
}
return true;
}
/**
* Determines whether or not the clear button should be visible onscreen.
* Clear button should be shown if one of two conditions applies:
* 1. `showClearButton` is set to `always`.
* 2. `showClearButton` is set to `focus`, and the searchbar has been focused.
*/
shouldShowClearButton() {
if (this.showClearButton === 'never' || (this.showClearButton === 'focus' && !this.focused)) {
return false;
}
return true;
}
render() {
const { cancelButtonText, autocapitalize } = this;
const animated = this.animated && config.getBoolean('animated', true);
const mode = getIonMode$1(this);
const clearIcon = this.clearIcon || (mode === 'ios' ? closeCircle : closeSharp);
const searchIcon = this.searchIcon || (mode === 'ios' ? searchOutline : searchSharp);
const shouldShowCancelButton = this.shouldShowCancelButton();
const cancelButton = this.showCancelButton !== 'never' && (hAsync("button", { key: '19e18775856db87daeb4b9e3d7bca0461915a0df', "aria-label": cancelButtonText, "aria-hidden": shouldShowCancelButton ? undefined : 'true', type: "button", tabIndex: mode === 'ios' && !shouldShowCancelButton ? -1 : undefined, onMouseDown: this.onCancelSearchbar, onTouchStart: this.onCancelSearchbar, class: "searchbar-cancel-button" }, hAsync("div", { key: 'b3bbdcc033f3bd3441d619e4a252cef0dad4d07e', "aria-hidden": "true" }, mode === 'md' ? (hAsync("ion-icon", { "aria-hidden": "true", mode: mode, icon: this.cancelButtonIcon, lazy: false })) : (cancelButtonText))));
return (hAsync(Host, { key: '074aa60e051bfb3225e87d44bbb6346c59c73574', role: "search", "aria-disabled": this.disabled ? 'true' : null, class: createColorClasses$1(this.color, {
[mode]: true,
'searchbar-animated': animated,
'searchbar-disabled': this.disabled,
'searchbar-no-animate': animated && this.noAnimate,
'searchbar-has-value': this.hasValue(),
'searchbar-left-aligned': this.shouldAlignLeft,
'searchbar-has-focus': this.focused,
'searchbar-should-show-clear': this.shouldShowClearButton(),
'searchbar-should-show-cancel': this.shouldShowCancelButton(),
}) }, hAsync("div", { key: '54f58a79fe36e85d9295157303f1be89c98bbdaf', class: "searchbar-input-container" }, hAsync("input", Object.assign({ key: 'f991a37fcf54d26b7ad10d89084764e03d97b9de', "aria-label": "search text", disabled: this.disabled, ref: (el) => (this.nativeInput = el), class: "searchbar-input", inputMode: this.inputmode, enterKeyHint: this.enterkeyhint, name: this.name, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, minLength: this.minlength, maxLength: this.maxlength, placeholder: this.placeholder, type: this.type, value: this.getValue(), autoCapitalize: autocapitalize === 'default' ? undefined : autocapitalize, autoComplete: this.autocomplete, autoCorrect: this.autocorrect, spellcheck: this.spellcheck }, this.inheritedAttributes)), mode === 'md' && cancelButton, hAsync("ion-icon", { key: '8b44dd90a3292c5cf872ef16a8520675f5673494', "aria-hidden": "true", mode: mode, icon: searchIcon, lazy: false, class: "searchbar-search-icon" }), hAsync("button", { key: '79d9cfed8f01268044f82811a35d323a12dca749', "aria-label": "reset", type: "button", "no-blur": true, class: "searchbar-clear-button", onPointerDown: (ev) => {
/**
* This prevents mobile browsers from
* blurring the input when the clear
* button is activated.
*/
ev.preventDefault();
}, onClick: () => this.onClearInput(true) }, hAsync("ion-icon", { key: 'aa3b9fa8a61f853236783ac7bcd0b113ea65ece2', "aria-hidden": "true", mode: mode, icon: clearIcon, lazy: false, class: "searchbar-clear-icon" }))), mode === 'ios' && cancelButton));
}
get el() { return getElement(this); }
static get watchers() { return {
"lang": ["onLangChanged"],
"dir": ["onDirChanged"],
"debounce": ["debounceChanged"],
"value": ["valueChanged"],
"showCancelButton": ["showCancelButtonChanged"]
}; }
static get style() { return {
ios: searchbarIosCss,
md: searchbarMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-searchbar",
"$members$": {
"color": [513],
"animated": [4],
"autocapitalize": [1],
"autocomplete": [1],
"autocorrect": [1],
"cancelButtonIcon": [1, "cancel-button-icon"],
"cancelButtonText": [1, "cancel-button-text"],
"clearIcon": [1, "clear-icon"],
"debounce": [2],
"disabled": [4],
"inputmode": [1],
"enterkeyhint": [1],
"maxlength": [2],
"minlength": [2],
"name": [1],
"placeholder": [1],
"searchIcon": [1, "search-icon"],
"showCancelButton": [1, "show-cancel-button"],
"showClearButton": [1, "show-clear-button"],
"spellcheck": [4],
"type": [1],
"value": [1025],
"focused": [32],
"noAnimate": [32],
"setFocus": [64],
"getInputElement": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
let searchbarIds = 0;
const segmentIosCss = ":host{--ripple-color:currentColor;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:grid;grid-auto-columns:1fr;position:relative;-ms-flex-align:stretch;align-items:stretch;-ms-flex-pack:center;justify-content:center;width:100%;background:var(--background);font-family:var(--ion-font-family, inherit);text-align:center;contain:paint;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:host(.segment-scrollable){-ms-flex-pack:start;justify-content:start;width:auto;overflow-x:auto;grid-auto-columns:minmax(-webkit-min-content, 1fr);grid-auto-columns:minmax(min-content, 1fr)}:host(.segment-scrollable::-webkit-scrollbar){display:none}:host{--background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.065);border-radius:8px;overflow:hidden;z-index:0}:host(.ion-color){background:rgba(var(--ion-color-base-rgb), 0.065)}:host(.in-toolbar){-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:0;margin-bottom:0;width:auto}:host(.in-toolbar:not(.ion-color)){background:var(--ion-toolbar-segment-background, var(--background))}:host(.in-toolbar-color:not(.ion-color)){background:rgba(var(--ion-color-contrast-rgb), 0.11)}";
const segmentMdCss = ":host{--ripple-color:currentColor;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:grid;grid-auto-columns:1fr;position:relative;-ms-flex-align:stretch;align-items:stretch;-ms-flex-pack:center;justify-content:center;width:100%;background:var(--background);font-family:var(--ion-font-family, inherit);text-align:center;contain:paint;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:host(.segment-scrollable){-ms-flex-pack:start;justify-content:start;width:auto;overflow-x:auto;grid-auto-columns:minmax(-webkit-min-content, 1fr);grid-auto-columns:minmax(min-content, 1fr)}:host(.segment-scrollable::-webkit-scrollbar){display:none}:host{--background:transparent;grid-auto-columns:minmax(auto, 360px)}:host(.in-toolbar){min-height:var(--min-height)}:host(.segment-scrollable) ::slotted(ion-segment-button){min-width:auto}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Segment {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionSelect = createEvent(this, "ionSelect", 7);
this.ionStyle = createEvent(this, "ionStyle", 7);
this.segmentViewEl = null;
this.activated = false;
/**
* If `true`, the user cannot interact with the segment.
*/
this.disabled = false;
/**
* If `true`, the segment buttons will overflow and the user can swipe to see them.
* In addition, this will disable the gesture to drag the indicator between the buttons
* in order to swipe to see hidden buttons.
*/
this.scrollable = false;
/**
* If `true`, users will be able to swipe between segment buttons to activate them.
*/
this.swipeGesture = true;
/**
* If `true`, navigating to an `ion-segment-button` with the keyboard will focus and select the element.
* If `false`, keyboard navigation will only focus the `ion-segment-button` element.
*/
this.selectOnFocus = false;
this.onClick = (ev) => {
const current = ev.target;
const previous = this.checked;
// If the current element is a segment then that means
// the user tried to swipe to a segment button and
// click a segment button at the same time so we should
// not update the checked segment button
if (current.tagName === 'ION-SEGMENT') {
return;
}
this.value = current.value;
if (current !== previous) {
this.emitValueChange();
}
if (this.segmentViewEl) {
this.updateSegmentView();
if (this.scrollable && previous) {
this.checkButton(previous, current);
}
}
else if (this.scrollable || !this.swipeGesture) {
if (previous) {
this.checkButton(previous, current);
}
else {
this.setCheckedClasses();
}
}
};
this.onSlottedItemsChange = () => {
/**
* When the slotted segment buttons change we need to
* ensure that the new segment buttons are checked if
* the value matches the segment button value.
*/
this.valueChanged(this.value);
};
this.getSegmentButton = (selector) => {
var _a, _b;
const buttons = this.getButtons().filter((button) => !button.disabled);
const currIndex = buttons.findIndex((button) => button === document.activeElement);
switch (selector) {
case 'first':
return buttons[0];
case 'last':
return buttons[buttons.length - 1];
case 'next':
return (_a = buttons[currIndex + 1]) !== null && _a !== void 0 ? _a : buttons[0];
case 'previous':
return (_b = buttons[currIndex - 1]) !== null && _b !== void 0 ? _b : buttons[buttons.length - 1];
default:
return null;
}
};
}
colorChanged(value, oldValue) {
/**
* If color is set after not having
* previously been set (or vice versa),
* we need to emit style so the segment-buttons
* can apply their color classes properly.
*/
if ((oldValue === undefined && value !== undefined) || (oldValue !== undefined && value === undefined)) {
this.emitStyle();
}
}
swipeGestureChanged() {
this.gestureChanged();
}
valueChanged(value, oldValue) {
// Force a value to exist if we're using a segment view
if (this.segmentViewEl && value === undefined) {
this.value = this.getButtons()[0].value;
return;
}
if (oldValue !== undefined && value !== undefined) {
const buttons = this.getButtons();
const previous = buttons.find((button) => button.value === oldValue);
const current = buttons.find((button) => button.value === value);
if (previous && current) {
if (!this.segmentViewEl) {
this.checkButton(previous, current);
}
else if (this.triggerScrollOnValueChange !== false) {
this.updateSegmentView();
}
}
}
else if (value !== undefined && oldValue === undefined && this.segmentViewEl) {
this.updateSegmentView();
}
/**
* `ionSelect` is emitted every time the value changes (internal or external changes).
* Used by `ion-segment-button` to determine if the button should be checked.
*/
this.ionSelect.emit({ value });
// The scroll listener should handle scrolling the active button into view as needed
if (!this.segmentViewEl) {
this.scrollActiveButtonIntoView();
}
this.triggerScrollOnValueChange = undefined;
}
disabledChanged() {
this.gestureChanged();
if (!this.segmentViewEl) {
const buttons = this.getButtons();
for (const button of buttons) {
button.disabled = this.disabled;
}
}
else {
this.segmentViewEl.disabled = this.disabled;
}
}
gestureChanged() {
if (this.gesture) {
this.gesture.enable(!this.scrollable && !this.disabled && this.swipeGesture);
}
}
connectedCallback() {
this.emitStyle();
this.segmentViewEl = this.getSegmentView();
}
disconnectedCallback() {
this.segmentViewEl = null;
}
componentWillLoad() {
this.emitStyle();
}
async componentDidLoad() {
this.segmentViewEl = this.getSegmentView();
this.setCheckedClasses();
/**
* We need to wait for the buttons to all be rendered
* before we can scroll.
*/
raf(() => {
/**
* When the segment loads for the first
* time we just want to snap the active button into
* place instead of scroll. Smooth scrolling should only
* happen when the user interacts with the segment.
*/
this.scrollActiveButtonIntoView(false);
});
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: this.el,
gestureName: 'segment',
gesturePriority: 100,
threshold: 0,
passive: false,
onStart: (ev) => this.onStart(ev),
onMove: (ev) => this.onMove(ev),
onEnd: (ev) => this.onEnd(ev),
});
this.gestureChanged();
if (this.disabled) {
this.disabledChanged();
}
// Update segment view based on the initial value,
// but do not animate the scroll
this.updateSegmentView(false);
}
onStart(detail) {
this.valueBeforeGesture = this.value;
this.activate(detail);
}
onMove(detail) {
this.setNextIndex(detail);
}
onEnd(detail) {
this.setActivated(false);
this.setNextIndex(detail, true);
detail.event.stopImmediatePropagation();
const value = this.value;
if (value !== undefined) {
if (this.valueBeforeGesture !== value) {
this.emitValueChange();
this.updateSegmentView();
}
}
this.valueBeforeGesture = undefined;
}
/**
* Emits an `ionChange` event.
*
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitValueChange() {
const { value } = this;
this.ionChange.emit({ value });
}
getButtons() {
return Array.from(this.el.querySelectorAll('ion-segment-button'));
}
get checked() {
return this.getButtons().find((button) => button.value === this.value);
}
/*
* Activate both the segment and the buttons
* due to a bug with ::slotted in Safari
*/
setActivated(activated) {
const buttons = this.getButtons();
buttons.forEach((button) => {
button.classList.toggle('segment-button-activated', activated);
});
this.activated = activated;
}
activate(detail) {
const clicked = detail.event.target;
const buttons = this.getButtons();
const checked = buttons.find((button) => button.value === this.value);
// Make sure we are only checking for activation on a segment button
// since disabled buttons will get the click on the segment
if (clicked.tagName !== 'ION-SEGMENT-BUTTON') {
return;
}
// If there are no checked buttons, set the current button to checked
if (!checked) {
this.value = clicked.value;
this.setCheckedClasses();
}
// If the gesture began on the clicked button with the indicator
// then we should activate the indicator
if (this.value === clicked.value) {
this.setActivated(true);
}
}
getIndicator(button) {
const root = button.shadowRoot || button;
return root.querySelector('.segment-button-indicator');
}
checkButton(previous, current) {
const previousIndicator = this.getIndicator(previous);
const currentIndicator = this.getIndicator(current);
if (previousIndicator === null || currentIndicator === null) {
return;
}
const previousClientRect = previousIndicator.getBoundingClientRect();
const currentClientRect = currentIndicator.getBoundingClientRect();
const widthDelta = previousClientRect.width / currentClientRect.width;
const xPosition = previousClientRect.left - currentClientRect.left;
// Scale the indicator width to match the previous indicator width
// and translate it on top of the previous indicator
const transform = `translate3d(${xPosition}px, 0, 0) scaleX(${widthDelta})`;
writeTask(() => {
// Remove the transition before positioning on top of the previous indicator
currentIndicator.classList.remove('segment-button-indicator-animated');
currentIndicator.style.setProperty('transform', transform);
// Force a repaint to ensure the transform happens
currentIndicator.getBoundingClientRect();
// Add the transition to move the indicator into place
currentIndicator.classList.add('segment-button-indicator-animated');
// Remove the transform to slide the indicator back to the button clicked
currentIndicator.style.setProperty('transform', '');
this.scrollActiveButtonIntoView(true);
});
this.value = current.value;
this.setCheckedClasses();
}
setCheckedClasses() {
const buttons = this.getButtons();
const index = buttons.findIndex((button) => button.value === this.value);
const next = index + 1;
for (const button of buttons) {
button.classList.remove('segment-button-after-checked');
}
if (next < buttons.length) {
buttons[next].classList.add('segment-button-after-checked');
}
}
getSegmentView() {
const buttons = this.getButtons();
// Get the first button with a contentId
const firstContentId = buttons.find((button) => button.contentId);
// Get the segment content with an id matching the button's contentId
const segmentContent = document.querySelector(`ion-segment-content[id="${firstContentId === null || firstContentId === void 0 ? void 0 : firstContentId.contentId}"]`);
// Return the segment view for that matching segment content
return segmentContent === null || segmentContent === void 0 ? void 0 : segmentContent.closest('ion-segment-view');
}
handleSegmentViewScroll(ev) {
const { scrollRatio, isManualScroll } = ev.detail;
if (!isManualScroll) {
return;
}
const dispatchedFrom = ev.target;
const segmentViewEl = this.segmentViewEl;
const segmentEl = this.el;
// Only update the indicator if the event was dispatched from the correct segment view
if (ev.composedPath().includes(segmentViewEl) || (dispatchedFrom === null || dispatchedFrom === void 0 ? void 0 : dispatchedFrom.contains(segmentEl))) {
const buttons = this.getButtons();
// If no buttons are found or there is no value set then do nothing
if (!buttons.length)
return;
const index = buttons.findIndex((button) => button.value === this.value);
const current = buttons[index];
const nextIndex = Math.round(scrollRatio * (buttons.length - 1));
if (this.lastNextIndex === undefined || this.lastNextIndex !== nextIndex) {
this.lastNextIndex = nextIndex;
this.triggerScrollOnValueChange = false;
this.checkButton(current, buttons[nextIndex]);
this.emitValueChange();
}
}
}
/**
* Finds the related segment view and sets its current content
* based on the selected segment button. This method
* should be called on initial load of the segment,
* after the gesture is completed (if dragging between segments)
* and when a segment button is clicked directly.
*/
updateSegmentView(smoothScroll = true) {
const buttons = this.getButtons();
const button = buttons.find((btn) => btn.value === this.value);
// If the button does not have a contentId then there is
// no associated segment view to update
if (!(button === null || button === void 0 ? void 0 : button.contentId)) {
return;
}
const segmentView = this.segmentViewEl;
if (segmentView) {
segmentView.setContent(button.contentId, smoothScroll);
}
}
scrollActiveButtonIntoView(smoothScroll = true) {
const { scrollable, value, el } = this;
if (scrollable) {
const buttons = this.getButtons();
const activeButton = buttons.find((button) => button.value === value);
if (activeButton !== undefined) {
const scrollContainerBox = el.getBoundingClientRect();
const activeButtonBox = activeButton.getBoundingClientRect();
/**
* Subtract the active button x position from the scroll
* container x position. This will give us the x position
* of the active button within the scroll container.
*/
const activeButtonLeft = activeButtonBox.x - scrollContainerBox.x;
/**
* If we just used activeButtonLeft, then the active button
* would be aligned with the left edge of the scroll container.
* Instead, we want the segment button to be centered. As a result,
* we subtract half of the scroll container width. This will position
* the left edge of the active button at the midpoint of the scroll container.
* We then add half of the active button width. This will position the active
* button such that the midpoint of the active button is at the midpoint of the
* scroll container.
*/
const centeredX = activeButtonLeft - scrollContainerBox.width / 2 + activeButtonBox.width / 2;
/**
* newScrollPosition is the absolute scroll position that the
* container needs to move to in order to center the active button.
* It is calculated by adding the current scroll position
* (scrollLeft) to the offset needed to center the button
* (centeredX).
*/
const newScrollPosition = el.scrollLeft + centeredX;
/**
* We intentionally use scrollTo here instead of scrollIntoView
* to avoid a WebKit bug where accelerated animations break
* when using scrollIntoView. Using scrollIntoView will cause the
* segment container to jump during the transition and then snap into place.
* This is because scrollIntoView can potentially cause parent element
* containers to also scroll. scrollTo does not have this same behavior, so
* we use this API instead.
*
* scrollTo is used instead of scrollBy because there is a
* Webkit bug that causes scrollBy to not work smoothly when
* the active button is near the edge of the scroll container.
* This leads to the buttons to jump around during the transition.
*
* Note that if there is not enough scrolling space to center the element
* within the scroll container, the browser will attempt
* to center by as much as it can.
*/
el.scrollTo({
top: 0,
left: newScrollPosition,
behavior: smoothScroll ? 'smooth' : 'instant',
});
}
}
}
setNextIndex(detail, isEnd = false) {
const rtl = isRTL$1(this.el);
const activated = this.activated;
const buttons = this.getButtons();
const index = buttons.findIndex((button) => button.value === this.value);
const previous = buttons[index];
let current;
let nextIndex;
if (index === -1) {
return;
}
// Get the element that the touch event started on in case
// it was the checked button, then we will move the indicator
const rect = previous.getBoundingClientRect();
const left = rect.left;
const width = rect.width;
// Get the element that the gesture is on top of based on the currentX of the
// gesture event and the Y coordinate of the starting element, since the gesture
// can move up and down off of the segment
const currentX = detail.currentX;
const previousY = rect.top + rect.height / 2;
/**
* Segment can be used inside the shadow dom
* so doing document.elementFromPoint would never
* return a segment button in that instance.
* We use getRootNode to which will return the parent
* shadow root if used inside a shadow component and
* returns document otherwise.
*/
const root = this.el.getRootNode();
const nextEl = root.elementFromPoint(currentX, previousY);
const decreaseIndex = rtl ? currentX > left + width : currentX < left;
const increaseIndex = rtl ? currentX < left : currentX > left + width;
// If the indicator is currently activated then we have started the gesture
// on top of the checked button so we need to slide the indicator
// by checking the button next to it as we move
if (activated && !isEnd) {
// Decrease index, move left in LTR & right in RTL
if (decreaseIndex) {
const newIndex = index - 1;
if (newIndex >= 0) {
nextIndex = newIndex;
}
// Increase index, moves right in LTR & left in RTL
}
else if (increaseIndex) {
if (activated && !isEnd) {
const newIndex = index + 1;
if (newIndex < buttons.length) {
nextIndex = newIndex;
}
}
}
if (nextIndex !== undefined && !buttons[nextIndex].disabled) {
current = buttons[nextIndex];
}
}
// If the indicator is not activated then we will just set the indicator
// to the element where the gesture ended
if (!activated && isEnd) {
current = nextEl;
}
if (current != null) {
/**
* If current element is ion-segment then that means
* user tried to select a disabled ion-segment-button,
* and we should not update the ripple.
*/
if (current.tagName === 'ION-SEGMENT') {
return false;
}
if (previous !== current) {
this.checkButton(previous, current);
}
}
return true;
}
emitStyle() {
this.ionStyle.emit({
segment: true,
});
}
onKeyDown(ev) {
const rtl = isRTL$1(this.el);
let keyDownSelectsButton = this.selectOnFocus;
let current;
switch (ev.key) {
case 'ArrowRight':
ev.preventDefault();
current = rtl ? this.getSegmentButton('previous') : this.getSegmentButton('next');
break;
case 'ArrowLeft':
ev.preventDefault();
current = rtl ? this.getSegmentButton('next') : this.getSegmentButton('previous');
break;
case 'Home':
ev.preventDefault();
current = this.getSegmentButton('first');
break;
case 'End':
ev.preventDefault();
current = this.getSegmentButton('last');
break;
case ' ':
case 'Enter':
ev.preventDefault();
current = document.activeElement;
keyDownSelectsButton = true;
}
if (!current) {
return;
}
if (keyDownSelectsButton) {
const previous = this.checked;
this.checkButton(previous || current, current);
if (current !== previous) {
this.emitValueChange();
}
}
current.setFocus();
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'e67ed512739cf2cfe657b0c44ebc3dfb1e9fbb79', role: "tablist", onClick: this.onClick, class: createColorClasses$1(this.color, {
[mode]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'segment-activated': this.activated,
'segment-disabled': this.disabled,
'segment-scrollable': this.scrollable,
}) }, hAsync("slot", { key: '804d8acfcb9abfeeee38244b015fbc5c36330b9e', onSlotchange: this.onSlottedItemsChange })));
}
get el() { return getElement(this); }
static get watchers() { return {
"color": ["colorChanged"],
"swipeGesture": ["swipeGestureChanged"],
"value": ["valueChanged"],
"disabled": ["disabledChanged"]
}; }
static get style() { return {
ios: segmentIosCss,
md: segmentMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-segment",
"$members$": {
"color": [513],
"disabled": [4],
"scrollable": [4],
"swipeGesture": [4, "swipe-gesture"],
"value": [1032],
"selectOnFocus": [4, "select-on-focus"],
"activated": [32]
},
"$listeners$": [[16, "ionSegmentViewScroll", "handleSegmentViewScroll"], [0, "keydown", "onKeyDown"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const segmentButtonIosCss = ":host{--color:initial;--color-hover:var(--color);--color-checked:var(--color);--color-disabled:var(--color);--padding-start:0;--padding-end:0;--padding-top:0;--padding-bottom:0;border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:column;flex-direction:column;height:auto;background:var(--background);color:var(--color);text-decoration:none;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;grid-row:1;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:0;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;min-width:inherit;max-width:inherit;height:auto;min-height:inherit;max-height:inherit;-webkit-transition:var(--transition);transition:var(--transition);border:none;outline:none;background:transparent;contain:content;pointer-events:none;overflow:hidden;z-index:2}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:inherit;flex-flow:inherit;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}:host(.segment-button-checked){background:var(--background-checked);color:var(--color-checked)}:host(.segment-button-disabled){cursor:default;pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}:host(:focus){outline:none}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}:host(.segment-button-checked:hover) .button-native{color:var(--color-checked)}}::slotted(ion-icon){-ms-flex-negative:0;flex-shrink:0;-ms-flex-order:-1;order:-1;pointer-events:none}::slotted(ion-label){display:block;-ms-flex-item-align:center;align-self:center;max-width:100%;line-height:22px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;pointer-events:none}:host(.segment-button-layout-icon-top) .button-native{-ms-flex-direction:column;flex-direction:column}:host(.segment-button-layout-icon-start) .button-native{-ms-flex-direction:row;flex-direction:row}:host(.segment-button-layout-icon-end) .button-native{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.segment-button-layout-icon-bottom) .button-native{-ms-flex-direction:column-reverse;flex-direction:column-reverse}:host(.segment-button-layout-icon-hide) ::slotted(ion-icon){display:none}:host(.segment-button-layout-label-hide) ::slotted(ion-label){display:none}ion-ripple-effect{color:var(--ripple-color, var(--color-checked))}.segment-button-indicator{-webkit-transform-origin:left;transform-origin:left;position:absolute;opacity:0;-webkit-box-sizing:border-box;box-sizing:border-box;will-change:transform, opacity;pointer-events:none}.segment-button-indicator-background{width:100%;height:var(--indicator-height);-webkit-transform:var(--indicator-transform);transform:var(--indicator-transform);-webkit-box-shadow:var(--indicator-box-shadow);box-shadow:var(--indicator-box-shadow);pointer-events:none}.segment-button-indicator-animated{-webkit-transition:var(--indicator-transition);transition:var(--indicator-transition)}:host(.segment-button-checked) .segment-button-indicator{opacity:1}@media (prefers-reduced-motion: reduce){.segment-button-indicator-background{-webkit-transform:none;transform:none}.segment-button-indicator-animated{-webkit-transition:none;transition:none}}:host{--background:none;--background-checked:none;--background-hover:none;--background-hover-opacity:0;--background-focused:none;--background-focused-opacity:0;--border-radius:7px;--border-width:1px;--border-color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.12);--border-style:solid;--indicator-box-shadow:0 0 5px rgba(0, 0, 0, 0.16);--indicator-color:var(--ion-color-step-350, var(--ion-background-color-step-350, var(--ion-background-color, #fff)));--indicator-height:100%;--indicator-transition:transform 260ms cubic-bezier(0.4, 0, 0.2, 1);--indicator-transform:none;--transition:100ms all linear;--padding-top:0;--padding-end:13px;--padding-bottom:0;--padding-start:13px;margin-top:2px;margin-bottom:2px;position:relative;-ms-flex-direction:row;flex-direction:row;min-width:70px;min-height:28px;-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);font-size:13px;font-weight:450;line-height:37px}:host::before{margin-left:0;margin-right:0;margin-top:5px;margin-bottom:5px;-webkit-transition:160ms opacity ease-in-out;transition:160ms opacity ease-in-out;-webkit-transition-delay:100ms;transition-delay:100ms;border-left:var(--border-width) var(--border-style) var(--border-color);content:\"\";opacity:1;will-change:opacity}:host(:first-of-type)::before{border-left-color:transparent}:host(.segment-button-disabled){opacity:0.3}::slotted(ion-icon){font-size:24px}:host(.segment-button-layout-icon-start) ::slotted(ion-label){-webkit-margin-start:2px;margin-inline-start:2px;-webkit-margin-end:0;margin-inline-end:0}:host(.segment-button-layout-icon-end) ::slotted(ion-label){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:2px;margin-inline-end:2px}.segment-button-indicator{-webkit-padding-start:2px;padding-inline-start:2px;-webkit-padding-end:2px;padding-inline-end:2px;left:0;right:0;top:0;bottom:0}.segment-button-indicator-background{border-radius:var(--border-radius);background:var(--indicator-color)}.segment-button-indicator-background{-webkit-transition:var(--indicator-transition);transition:var(--indicator-transition)}:host(.segment-button-checked)::before,:host(.segment-button-after-checked)::before{opacity:0}:host(.segment-button-checked){z-index:-1}:host(.segment-button-activated){--indicator-transform:scale(0.95)}:host(.ion-focused) .button-native{opacity:0.7}@media (any-hover: hover){:host(:hover) .button-native{opacity:0.5}:host(.segment-button-checked:hover) .button-native{opacity:1}}:host(.in-segment-color){background:none;color:var(--ion-text-color, #000)}:host(.in-segment-color) .segment-button-indicator-background{background:var(--ion-color-step-350, var(--ion-background-color-step-350, var(--ion-background-color, #fff)))}@media (any-hover: hover){:host(.in-segment-color:hover) .button-native,:host(.in-segment-color.segment-button-checked:hover) .button-native{color:var(--ion-text-color, #000)}}:host(.in-toolbar:not(.in-segment-color)){--background-checked:var(--ion-toolbar-segment-background-checked, none);--color:var(--ion-toolbar-segment-color, var(--ion-toolbar-color), initial);--color-checked:var(--ion-toolbar-segment-color-checked, var(--ion-toolbar-color), initial);--indicator-color:var(--ion-toolbar-segment-indicator-color, var(--ion-color-step-350, var(--ion-background-color-step-350, var(--ion-background-color, #fff))))}:host(.in-toolbar-color) .segment-button-indicator-background{background:var(--ion-color-contrast)}:host(.in-toolbar-color:not(.in-segment-color)) .button-native{color:var(--ion-color-contrast)}:host(.in-toolbar-color.segment-button-checked:not(.in-segment-color)) .button-native{color:var(--ion-color-base)}@media (any-hover: hover){:host(.in-toolbar-color:not(.in-segment-color):hover) .button-native{color:var(--ion-color-contrast)}:host(.in-toolbar-color.segment-button-checked:not(.in-segment-color):hover) .button-native{color:var(--ion-color-base)}}";
const segmentButtonMdCss = ":host{--color:initial;--color-hover:var(--color);--color-checked:var(--color);--color-disabled:var(--color);--padding-start:0;--padding-end:0;--padding-top:0;--padding-bottom:0;border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:column;flex-direction:column;height:auto;background:var(--background);color:var(--color);text-decoration:none;text-overflow:ellipsis;white-space:nowrap;cursor:pointer;grid-row:1;-webkit-font-kerning:none;font-kerning:none}.button-native{border-radius:0;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;-webkit-margin-start:var(--margin-start);margin-inline-start:var(--margin-start);-webkit-margin-end:var(--margin-end);margin-inline-end:var(--margin-end);margin-top:var(--margin-top);margin-bottom:var(--margin-bottom);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;min-width:inherit;max-width:inherit;height:auto;min-height:inherit;max-height:inherit;-webkit-transition:var(--transition);transition:var(--transition);border:none;outline:none;background:transparent;contain:content;pointer-events:none;overflow:hidden;z-index:2}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:inherit;flex-flow:inherit;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;z-index:1}:host(.segment-button-checked){background:var(--background-checked);color:var(--color-checked)}:host(.segment-button-disabled){cursor:default;pointer-events:none}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}:host(:focus){outline:none}@media (any-hover: hover){:host(:hover) .button-native{color:var(--color-hover)}:host(:hover) .button-native::after{background:var(--background-hover);opacity:var(--background-hover-opacity)}:host(.segment-button-checked:hover) .button-native{color:var(--color-checked)}}::slotted(ion-icon){-ms-flex-negative:0;flex-shrink:0;-ms-flex-order:-1;order:-1;pointer-events:none}::slotted(ion-label){display:block;-ms-flex-item-align:center;align-self:center;max-width:100%;line-height:22px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;pointer-events:none}:host(.segment-button-layout-icon-top) .button-native{-ms-flex-direction:column;flex-direction:column}:host(.segment-button-layout-icon-start) .button-native{-ms-flex-direction:row;flex-direction:row}:host(.segment-button-layout-icon-end) .button-native{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.segment-button-layout-icon-bottom) .button-native{-ms-flex-direction:column-reverse;flex-direction:column-reverse}:host(.segment-button-layout-icon-hide) ::slotted(ion-icon){display:none}:host(.segment-button-layout-label-hide) ::slotted(ion-label){display:none}ion-ripple-effect{color:var(--ripple-color, var(--color-checked))}.segment-button-indicator{-webkit-transform-origin:left;transform-origin:left;position:absolute;opacity:0;-webkit-box-sizing:border-box;box-sizing:border-box;will-change:transform, opacity;pointer-events:none}.segment-button-indicator-background{width:100%;height:var(--indicator-height);-webkit-transform:var(--indicator-transform);transform:var(--indicator-transform);-webkit-box-shadow:var(--indicator-box-shadow);box-shadow:var(--indicator-box-shadow);pointer-events:none}.segment-button-indicator-animated{-webkit-transition:var(--indicator-transition);transition:var(--indicator-transition)}:host(.segment-button-checked) .segment-button-indicator{opacity:1}@media (prefers-reduced-motion: reduce){.segment-button-indicator-background{-webkit-transform:none;transform:none}.segment-button-indicator-animated{-webkit-transition:none;transition:none}}:host{--background:none;--background-checked:none;--background-hover:var(--color-checked);--background-focused:var(--color-checked);--background-activated-opacity:0;--background-focused-opacity:.12;--background-hover-opacity:.04;--color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.6);--color-checked:var(--ion-color-primary, #0054e9);--indicator-box-shadow:none;--indicator-color:var(--color-checked);--indicator-height:2px;--indicator-transition:transform 250ms cubic-bezier(0.4, 0, 0.2, 1);--indicator-transform:none;--padding-top:0;--padding-end:16px;--padding-bottom:0;--padding-start:16px;--transition:color 0.15s linear 0s, opacity 0.15s linear 0s;min-width:90px;min-height:48px;border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);font-size:14px;font-weight:500;letter-spacing:0.06em;line-height:40px;text-transform:uppercase}:host(.segment-button-disabled){opacity:0.3}:host(.in-segment-color){background:none;color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.6)}:host(.in-segment-color) ion-ripple-effect{color:var(--ion-color-base)}:host(.in-segment-color) .segment-button-indicator-background{background:var(--ion-color-base)}:host(.in-segment-color.segment-button-checked) .button-native{color:var(--ion-color-base)}:host(.in-segment-color.ion-focused) .button-native::after{background:var(--ion-color-base)}@media (any-hover: hover){:host(.in-segment-color:hover) .button-native{color:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.6)}:host(.in-segment-color:hover) .button-native::after{background:var(--ion-color-base)}:host(.in-segment-color.segment-button-checked:hover) .button-native{color:var(--ion-color-base)}}:host(.in-toolbar:not(.in-segment-color)){--background:var(--ion-toolbar-segment-background, none);--background-checked:var(--ion-toolbar-segment-background-checked, none);--color:var(--ion-toolbar-segment-color, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.6));--color-checked:var(--ion-toolbar-segment-color-checked, var(--ion-color-primary, #0054e9));--indicator-color:var(--ion-toolbar-segment-color-checked, var(--color-checked))}:host(.in-toolbar-color:not(.in-segment-color)) .button-native{color:rgba(var(--ion-color-contrast-rgb), 0.6)}:host(.in-toolbar-color.segment-button-checked:not(.in-segment-color)) .button-native{color:var(--ion-color-contrast)}@media (any-hover: hover){:host(.in-toolbar-color:not(.in-segment-color)) .button-native::after{background:var(--ion-color-contrast)}}::slotted(ion-icon){margin-top:12px;margin-bottom:12px;font-size:24px}::slotted(ion-label){margin-top:12px;margin-bottom:12px}:host(.segment-button-layout-icon-top) ::slotted(ion-label),:host(.segment-button-layout-icon-bottom) ::slotted(ion-icon){margin-top:0}:host(.segment-button-layout-icon-top) ::slotted(ion-icon),:host(.segment-button-layout-icon-bottom) ::slotted(ion-label){margin-bottom:0}:host(.segment-button-layout-icon-start) ::slotted(ion-label){-webkit-margin-start:8px;margin-inline-start:8px;-webkit-margin-end:0;margin-inline-end:0}:host(.segment-button-layout-icon-end) ::slotted(ion-label){-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:8px;margin-inline-end:8px}:host(.segment-button-has-icon-only) ::slotted(ion-icon){margin-top:12px;margin-bottom:12px}:host(.segment-button-has-label-only) ::slotted(ion-label){margin-top:12px;margin-bottom:12px}.segment-button-indicator{left:0;right:0;bottom:0}.segment-button-indicator-background{background:var(--indicator-color)}:host(.in-toolbar:not(.in-segment-color)) .segment-button-indicator-background{background:var(--ion-toolbar-segment-indicator-color, var(--indicator-color))}:host(.in-toolbar-color:not(.in-segment-color)) .segment-button-indicator-background{background:var(--ion-color-contrast)}";
let ids = 0;
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML button element that wraps all child elements.
* @part indicator - The indicator displayed on the checked segment button.
* @part indicator-background - The background element for the indicator displayed on the checked segment button.
*/
class SegmentButton {
constructor(hostRef) {
registerInstance(this, hostRef);
this.segmentEl = null;
this.inheritedAttributes = {};
this.checked = false;
/**
* If `true`, the user cannot interact with the segment button.
*/
this.disabled = false;
/**
* Set the layout of the text and icon in the segment.
*/
this.layout = 'icon-top';
/**
* The type of the button.
*/
this.type = 'button';
/**
* The value of the segment button.
*/
this.value = 'ion-sb-' + ids++;
this.updateStyle = () => {
};
this.updateState = () => {
const { segmentEl } = this;
if (segmentEl) {
this.checked = segmentEl.value === this.value;
if (segmentEl.disabled) {
this.disabled = true;
}
}
};
}
valueChanged() {
this.updateState();
}
connectedCallback() {
const segmentEl = (this.segmentEl = this.el.closest('ion-segment'));
if (segmentEl) {
this.updateState();
addEventListener$1(segmentEl, 'ionSelect', this.updateState);
addEventListener$1(segmentEl, 'ionStyle', this.updateStyle);
}
// Prevent buttons from being disabled when associated with segment content
if (this.contentId && this.disabled) {
printIonWarning(`[ion-segment-button] - Segment buttons cannot be disabled when associated with an <ion-segment-content>.`);
this.disabled = false;
}
}
disconnectedCallback() {
const segmentEl = this.segmentEl;
if (segmentEl) {
removeEventListener(segmentEl, 'ionSelect', this.updateState);
removeEventListener(segmentEl, 'ionStyle', this.updateStyle);
this.segmentEl = null;
}
}
componentWillLoad() {
this.inheritedAttributes = Object.assign({}, inheritAttributes$1(this.el, ['aria-label']));
// Return if there is no contentId defined
if (!this.contentId)
return;
// Attempt to find the Segment Content by its contentId
const segmentContent = document.getElementById(this.contentId);
// If no associated Segment Content exists, log an error and return
if (!segmentContent) {
printIonError(`[ion-segment-button] - Unable to find Segment Content with id="${this.contentId}".`);
return;
}
// Ensure the found element is a valid ION-SEGMENT-CONTENT
if (segmentContent.tagName !== 'ION-SEGMENT-CONTENT') {
printIonError(`[ion-segment-button] - Element with id="${this.contentId}" is not an <ion-segment-content> element.`);
return;
}
}
get hasLabel() {
return !!this.el.querySelector('ion-label');
}
get hasIcon() {
return !!this.el.querySelector('ion-icon');
}
/**
* @internal
* Focuses the native <button> element
* inside of ion-segment-button.
*/
async setFocus() {
const { nativeEl } = this;
if (nativeEl !== undefined) {
nativeEl.focus();
}
}
render() {
const { checked, type, disabled, hasIcon, hasLabel, layout, segmentEl } = this;
const mode = getIonMode$1(this);
const hasSegmentColor = () => (segmentEl === null || segmentEl === void 0 ? void 0 : segmentEl.color) !== undefined;
return (hAsync(Host, { key: '26cb7ee90455bcaa6416125802d7e5729fa05b5b', class: {
[mode]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
'in-toolbar-color': hostContext('ion-toolbar[color]', this.el),
'in-segment': hostContext('ion-segment', this.el),
'in-segment-color': hasSegmentColor(),
'segment-button-has-label': hasLabel,
'segment-button-has-icon': hasIcon,
'segment-button-has-label-only': hasLabel && !hasIcon,
'segment-button-has-icon-only': hasIcon && !hasLabel,
'segment-button-disabled': disabled,
'segment-button-checked': checked,
[`segment-button-layout-${layout}`]: true,
'ion-activatable': true,
'ion-activatable-instant': true,
'ion-focusable': true,
} }, hAsync("button", Object.assign({ key: '75add37f11c107d1e2cfdb154e08004e9579e863', "aria-selected": checked ? 'true' : 'false', role: "tab", ref: (el) => (this.nativeEl = el), type: type, class: "button-native", part: "native", disabled: disabled }, this.inheritedAttributes), hAsync("span", { key: '8e720d2a3e304903685bf09d226a64e944d78a22', class: "button-inner" }, hAsync("slot", { key: 'c8e7b3ebf8f03042a1001155643b585283c73c65' })), mode === 'md' && hAsync("ion-ripple-effect", { key: '3586ac317b8d82c92b0ccfbfae42f8778612321b' })), hAsync("div", { key: '9cf93957da9e8dc333c8b05327bb903385b1c5f4', part: "indicator", class: "segment-button-indicator segment-button-indicator-animated" }, hAsync("div", { key: 'd3b6f0b3860ec6896b46703f64ed1cc8c75612e3', part: "indicator-background", class: "segment-button-indicator-background" }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"value": ["valueChanged"]
}; }
static get style() { return {
ios: segmentButtonIosCss,
md: segmentButtonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-segment-button",
"$members$": {
"contentId": [513, "content-id"],
"disabled": [1028],
"layout": [1],
"type": [1],
"value": [8],
"checked": [32],
"setFocus": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["contentId", "content-id"]]
}; }
}
const segmentContentCss = ":host{scroll-snap-align:center;scroll-snap-stop:always;-ms-flex-negative:0;flex-shrink:0;width:100%;min-height:1px;overflow-y:scroll;scrollbar-width:none;-ms-overflow-style:none;}:host::-webkit-scrollbar{display:none}";
class SegmentContent {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
return (hAsync(Host, { key: 'db6876f2aee7afa1ea8bc147337670faa68fae1c' }, hAsync("slot", { key: 'bc05714a973a5655668679033f5809a1da6db8cc' })));
}
static get style() { return segmentContentCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-segment-content",
"$members$": undefined,
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const segmentViewIosCss = ":host{display:-ms-flexbox;display:flex;height:100%;overflow-x:scroll;-webkit-scroll-snap-type:x mandatory;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;scrollbar-width:none;-ms-overflow-style:none}:host::-webkit-scrollbar{display:none}:host(.segment-view-disabled){-ms-touch-action:none;touch-action:none;overflow-x:hidden}:host(.segment-view-scroll-disabled){pointer-events:none}:host(.segment-view-disabled){opacity:0.3}";
const segmentViewMdCss = ":host{display:-ms-flexbox;display:flex;height:100%;overflow-x:scroll;-webkit-scroll-snap-type:x mandatory;-ms-scroll-snap-type:x mandatory;scroll-snap-type:x mandatory;scrollbar-width:none;-ms-overflow-style:none}:host::-webkit-scrollbar{display:none}:host(.segment-view-disabled){-ms-touch-action:none;touch-action:none;overflow-x:hidden}:host(.segment-view-scroll-disabled){pointer-events:none}:host(.segment-view-disabled){opacity:0.3}";
class SegmentView {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionSegmentViewScroll = createEvent(this, "ionSegmentViewScroll", 7);
this.scrollEndTimeout = null;
this.isTouching = false;
/**
* If `true`, the segment view cannot be interacted with.
*/
this.disabled = false;
}
handleScroll(ev) {
var _a;
const { scrollLeft, scrollWidth, clientWidth } = ev.target;
const max = scrollWidth - clientWidth;
const scrollRatio = (isRTL$1(this.el) ? -1 : 1) * (scrollLeft / max);
this.ionSegmentViewScroll.emit({
scrollRatio,
isManualScroll: (_a = this.isManualScroll) !== null && _a !== void 0 ? _a : true,
});
// Reset the timeout to check for scroll end
this.resetScrollEndTimeout();
}
/**
* Handle touch start event to know when the user is actively dragging the segment view.
*/
handleScrollStart() {
if (this.scrollEndTimeout) {
clearTimeout(this.scrollEndTimeout);
this.scrollEndTimeout = null;
}
this.isTouching = true;
}
/**
* Handle touch end event to know when the user is no longer dragging the segment view.
*/
handleTouchEnd() {
this.isTouching = false;
}
/**
* Reset the scroll end detection timer. This is called on every scroll event.
*/
resetScrollEndTimeout() {
if (this.scrollEndTimeout) {
clearTimeout(this.scrollEndTimeout);
this.scrollEndTimeout = null;
}
this.scrollEndTimeout = setTimeout(() => {
this.checkForScrollEnd();
},
// Setting this to a lower value may result in inconsistencies in behavior
// across browsers (particularly Firefox).
// Ideally, all of this logic is removed once the scroll end event is
// supported on all browsers (https://caniuse.com/?search=scrollend)
100);
}
/**
* Check if the scroll has ended and the user is not actively touching.
* If the conditions are met (active content is enabled and no active touch),
* reset the scroll position and emit the scroll end event.
*/
checkForScrollEnd() {
// Only emit scroll end event if the active content is not disabled and
// the user is not touching the segment view
if (!this.isTouching) {
this.isManualScroll = undefined;
}
}
/**
* @internal
*
* This method is used to programmatically set the displayed segment content
* in the segment view. Calling this method will update the `value` of the
* corresponding segment button.
*
* @param id: The id of the segment content to display.
* @param smoothScroll: Whether to animate the scroll transition.
*/
async setContent(id, smoothScroll = true) {
const contents = this.getSegmentContents();
const index = contents.findIndex((content) => content.id === id);
if (index === -1)
return;
this.isManualScroll = false;
this.resetScrollEndTimeout();
const contentWidth = this.el.offsetWidth;
const offset = index * contentWidth;
this.el.scrollTo({
top: 0,
left: (isRTL$1(this.el) ? -1 : 1) * offset,
behavior: smoothScroll ? 'smooth' : 'instant',
});
}
getSegmentContents() {
return Array.from(this.el.querySelectorAll('ion-segment-content'));
}
render() {
const { disabled, isManualScroll } = this;
return (hAsync(Host, { key: 'e180b67bb3143a5f4611fb358c037be6fc782a8f', class: {
'segment-view-disabled': disabled,
'segment-view-scroll-disabled': isManualScroll === false,
} }, hAsync("slot", { key: '41c11d6a7406a10f5c64a2e73abfc072afd8fc73' })));
}
get el() { return getElement(this); }
static get style() { return {
ios: segmentViewIosCss,
md: segmentViewMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-segment-view",
"$members$": {
"disabled": [4],
"isManualScroll": [32],
"setContent": [64]
},
"$listeners$": [[1, "scroll", "handleScroll"], [1, "touchstart", "handleScrollStart"], [1, "touchend", "handleTouchEnd"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const selectIosCss = ":host{--padding-top:0px;--padding-end:0px;--padding-bottom:0px;--padding-start:0px;--placeholder-color:currentColor;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);--background:transparent;--border-style:solid;--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;width:100%;min-height:44px;font-family:var(--ion-font-family, inherit);white-space:nowrap;cursor:pointer;z-index:2}:host(.select-label-placement-floating),:host(.select-label-placement-stacked){min-height:56px}:host(.ion-color){--highlight-color-focused:var(--ion-color-base)}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0}:host(.select-disabled){pointer-events:none}:host(.has-focus) button{border:2px solid #5e9ed6}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}.select-placeholder{color:var(--placeholder-color);opacity:var(--placeholder-opacity)}button{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}.select-icon{-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0;position:relative;-ms-flex-negative:0;flex-shrink:0}:host(.in-item-color) .select-icon{color:inherit}:host(.select-label-placement-stacked) .select-icon,:host(.select-label-placement-floating) .select-icon{position:absolute;height:100%}:host(.select-ltr.select-label-placement-stacked) .select-icon,:host(.select-ltr.select-label-placement-floating) .select-icon{right:var(--padding-end, 0)}:host(.select-rtl.select-label-placement-stacked) .select-icon,:host(.select-rtl.select-label-placement-floating) .select-icon{left:var(--padding-start, 0)}.select-text{-ms-flex:1;flex:1;min-width:16px;font-size:inherit;text-overflow:ellipsis;white-space:inherit;overflow:hidden}.select-wrapper{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;min-height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;background:var(--background);line-height:normal;cursor:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}.select-wrapper .select-placeholder{-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.select-wrapper-inner{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;overflow:hidden}:host(.select-label-placement-stacked) .select-wrapper-inner,:host(.select-label-placement-floating) .select-wrapper-inner{-ms-flex-positive:1;flex-grow:1}:host(.ion-touched.ion-invalid){--highlight-color:var(--highlight-color-invalid)}:host(.ion-valid){--highlight-color:var(--highlight-color-valid)}.select-bottom{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:5px;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-top:var(--border-width) var(--border-style) var(--border-color);font-size:0.75rem;white-space:normal}:host(.has-focus.ion-valid),:host(.select-expanded.ion-valid),:host(.ion-touched.ion-invalid),:host(.select-expanded.ion-touched.ion-invalid){--border-color:var(--highlight-color)}.select-bottom .error-text{display:none;color:var(--highlight-color-invalid)}.select-bottom .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}:host(.ion-touched.ion-invalid) .select-bottom .error-text{display:block}:host(.ion-touched.ion-invalid) .select-bottom .helper-text{display:none}.label-text-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;max-width:200px;-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.label-text,::slotted([slot=label]){text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden,.select-outline-notch-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);overflow:hidden}:host(.select-justify-space-between) .select-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.select-justify-start) .select-wrapper{-ms-flex-pack:start;justify-content:start}:host(.select-justify-end) .select-wrapper{-ms-flex-pack:end;justify-content:end}:host(.select-label-placement-start) .select-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.select-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.select-label-placement-end) .select-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.select-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}:host(.select-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.select-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.select-label-placement-stacked) .select-wrapper,:host(.select-label-placement-floating) .select-wrapper{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:start}:host(.select-label-placement-stacked) .label-text-wrapper,:host(.select-label-placement-floating) .label-text-wrapper{max-width:100%}:host(.select-ltr.select-label-placement-stacked) .label-text-wrapper,:host(.select-ltr.select-label-placement-floating) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host(.select-rtl.select-label-placement-stacked) .label-text-wrapper,:host(.select-rtl.select-label-placement-floating) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}:host(.select-label-placement-stacked) .native-wrapper,:host(.select-label-placement-floating) .native-wrapper{margin-left:0;margin-right:0;margin-top:1px;margin-bottom:0;-ms-flex-positive:1;flex-grow:1;width:100%}:host(.select-label-placement-floating) .label-text-wrapper{-webkit-transform:translateY(100%) scale(1);transform:translateY(100%) scale(1)}:host(.select-label-placement-floating:not(.label-floating)) .native-wrapper .select-placeholder{opacity:0}:host(.select-expanded.select-label-placement-floating) .native-wrapper .select-placeholder,:host(.has-focus.select-label-placement-floating) .native-wrapper .select-placeholder,:host(.has-value.select-label-placement-floating) .native-wrapper .select-placeholder{opacity:1}:host(.label-floating) .label-text-wrapper{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);max-width:calc(100% / 0.75)}::slotted([slot=start]),::slotted([slot=end]){-ms-flex-negative:0;flex-shrink:0}::slotted([slot=start]:last-of-type){-webkit-margin-end:16px;margin-inline-end:16px;-webkit-margin-start:0;margin-inline-start:0}::slotted([slot=end]:first-of-type){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host{--border-width:0.55px;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));--highlight-height:0px}.select-icon{width:1.125rem;height:1.125rem;color:var(--ion-color-step-650, var(--ion-text-color-step-350, #595959))}:host(.select-label-placement-stacked) .select-wrapper-inner,:host(.select-label-placement-floating) .select-wrapper-inner{width:calc(100% - 1.125rem - 4px)}:host(.select-disabled){opacity:0.3}::slotted(ion-button[slot=start].button-has-icon-only),::slotted(ion-button[slot=end].button-has-icon-only){--border-radius:50%;--padding-start:0;--padding-end:0;--padding-top:0;--padding-bottom:0;aspect-ratio:1}";
const selectMdCss = ":host{--padding-top:0px;--padding-end:0px;--padding-bottom:0px;--padding-start:0px;--placeholder-color:currentColor;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);--background:transparent;--border-style:solid;--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;width:100%;min-height:44px;font-family:var(--ion-font-family, inherit);white-space:nowrap;cursor:pointer;z-index:2}:host(.select-label-placement-floating),:host(.select-label-placement-stacked){min-height:56px}:host(.ion-color){--highlight-color-focused:var(--ion-color-base)}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0}:host(.select-disabled){pointer-events:none}:host(.has-focus) button{border:2px solid #5e9ed6}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}.select-placeholder{color:var(--placeholder-color);opacity:var(--placeholder-opacity)}button{position:absolute;top:0;left:0;right:0;bottom:0;width:100%;height:100%;margin:0;padding:0;border:0;outline:0;clip:rect(0 0 0 0);opacity:0;overflow:hidden;-webkit-appearance:none;-moz-appearance:none}.select-icon{-webkit-margin-start:4px;margin-inline-start:4px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0;position:relative;-ms-flex-negative:0;flex-shrink:0}:host(.in-item-color) .select-icon{color:inherit}:host(.select-label-placement-stacked) .select-icon,:host(.select-label-placement-floating) .select-icon{position:absolute;height:100%}:host(.select-ltr.select-label-placement-stacked) .select-icon,:host(.select-ltr.select-label-placement-floating) .select-icon{right:var(--padding-end, 0)}:host(.select-rtl.select-label-placement-stacked) .select-icon,:host(.select-rtl.select-label-placement-floating) .select-icon{left:var(--padding-start, 0)}.select-text{-ms-flex:1;flex:1;min-width:16px;font-size:inherit;text-overflow:ellipsis;white-space:inherit;overflow:hidden}.select-wrapper{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;min-height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;background:var(--background);line-height:normal;cursor:inherit;-webkit-box-sizing:border-box;box-sizing:border-box}.select-wrapper .select-placeholder{-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.select-wrapper-inner{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;overflow:hidden}:host(.select-label-placement-stacked) .select-wrapper-inner,:host(.select-label-placement-floating) .select-wrapper-inner{-ms-flex-positive:1;flex-grow:1}:host(.ion-touched.ion-invalid){--highlight-color:var(--highlight-color-invalid)}:host(.ion-valid){--highlight-color:var(--highlight-color-valid)}.select-bottom{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:5px;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-top:var(--border-width) var(--border-style) var(--border-color);font-size:0.75rem;white-space:normal}:host(.has-focus.ion-valid),:host(.select-expanded.ion-valid),:host(.ion-touched.ion-invalid),:host(.select-expanded.ion-touched.ion-invalid){--border-color:var(--highlight-color)}.select-bottom .error-text{display:none;color:var(--highlight-color-invalid)}.select-bottom .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}:host(.ion-touched.ion-invalid) .select-bottom .error-text{display:block}:host(.ion-touched.ion-invalid) .select-bottom .helper-text{display:none}.label-text-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;max-width:200px;-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.label-text,::slotted([slot=label]){text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden,.select-outline-notch-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);overflow:hidden}:host(.select-justify-space-between) .select-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.select-justify-start) .select-wrapper{-ms-flex-pack:start;justify-content:start}:host(.select-justify-end) .select-wrapper{-ms-flex-pack:end;justify-content:end}:host(.select-label-placement-start) .select-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.select-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.select-label-placement-end) .select-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.select-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}:host(.select-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}:host(.select-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.select-label-placement-stacked) .select-wrapper,:host(.select-label-placement-floating) .select-wrapper{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:start}:host(.select-label-placement-stacked) .label-text-wrapper,:host(.select-label-placement-floating) .label-text-wrapper{max-width:100%}:host(.select-ltr.select-label-placement-stacked) .label-text-wrapper,:host(.select-ltr.select-label-placement-floating) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host(.select-rtl.select-label-placement-stacked) .label-text-wrapper,:host(.select-rtl.select-label-placement-floating) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}:host(.select-label-placement-stacked) .native-wrapper,:host(.select-label-placement-floating) .native-wrapper{margin-left:0;margin-right:0;margin-top:1px;margin-bottom:0;-ms-flex-positive:1;flex-grow:1;width:100%}:host(.select-label-placement-floating) .label-text-wrapper{-webkit-transform:translateY(100%) scale(1);transform:translateY(100%) scale(1)}:host(.select-label-placement-floating:not(.label-floating)) .native-wrapper .select-placeholder{opacity:0}:host(.select-expanded.select-label-placement-floating) .native-wrapper .select-placeholder,:host(.has-focus.select-label-placement-floating) .native-wrapper .select-placeholder,:host(.has-value.select-label-placement-floating) .native-wrapper .select-placeholder{opacity:1}:host(.label-floating) .label-text-wrapper{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);max-width:calc(100% / 0.75)}::slotted([slot=start]),::slotted([slot=end]){-ms-flex-negative:0;flex-shrink:0}::slotted([slot=start]:last-of-type){-webkit-margin-end:16px;margin-inline-end:16px;-webkit-margin-start:0;margin-inline-start:0}::slotted([slot=end]:first-of-type){-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.select-fill-solid){--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-500, var(--ion-background-color-step-500, gray));--border-radius:4px;--padding-start:16px;--padding-end:16px;min-height:56px}:host(.select-fill-solid) .select-wrapper{border-bottom:var(--border-width) var(--border-style) var(--border-color)}:host(.select-expanded.select-fill-solid.ion-valid),:host(.has-focus.select-fill-solid.ion-valid),:host(.select-fill-solid.ion-touched.ion-invalid){--border-color:var(--highlight-color)}:host(.select-fill-solid) .select-bottom{border-top:none}@media (any-hover: hover){:host(.select-fill-solid:hover){--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}}:host(.select-fill-solid.select-expanded),:host(.select-fill-solid.has-focus){--background:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--border-color:var(--highlight-color)}:host(.select-fill-solid) .select-wrapper{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0px;border-end-start-radius:0px}:host(.label-floating.select-fill-solid) .label-text-wrapper{max-width:calc(100% / 0.75)}:host(.in-item.select-expanded.select-fill-solid) .select-wrapper .select-icon,:host(.in-item.has-focus.select-fill-solid) .select-wrapper .select-icon,:host(.in-item.has-focus.ion-valid.select-fill-solid) .select-wrapper .select-icon,:host(.in-item.ion-touched.ion-invalid.select-fill-solid) .select-wrapper .select-icon{color:var(--highlight-color)}:host(.select-fill-outline){--border-color:var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3));--border-radius:4px;--padding-start:16px;--padding-end:16px;min-height:56px}:host(.select-fill-outline.select-shape-round){--border-radius:28px;--padding-start:32px;--padding-end:32px}:host(.has-focus.select-fill-outline.ion-valid),:host(.select-fill-outline.ion-touched.ion-invalid){--border-color:var(--highlight-color)}@media (any-hover: hover){:host(.select-fill-outline:hover){--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}}:host(.select-fill-outline.select-expanded),:host(.select-fill-outline.has-focus){--border-width:var(--highlight-height);--border-color:var(--highlight-color)}:host(.select-fill-outline) .select-bottom{border-top:none}:host(.select-fill-outline) .select-wrapper{border-bottom:none}:host(.select-ltr.select-fill-outline.select-label-placement-stacked) .label-text-wrapper,:host(.select-ltr.select-fill-outline.select-label-placement-floating) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host(.select-rtl.select-fill-outline.select-label-placement-stacked) .label-text-wrapper,:host(.select-rtl.select-fill-outline.select-label-placement-floating) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}:host(.select-fill-outline.select-label-placement-stacked) .label-text-wrapper,:host(.select-fill-outline.select-label-placement-floating) .label-text-wrapper{position:absolute;max-width:calc(100% - var(--padding-start) - var(--padding-end))}:host(.select-fill-outline) .label-text-wrapper{position:relative;z-index:1}:host(.label-floating.select-fill-outline) .label-text-wrapper{-webkit-transform:translateY(-32%) scale(0.75);transform:translateY(-32%) scale(0.75);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;max-width:calc((100% - var(--padding-start) - var(--padding-end) - 8px) / 0.75)}:host(.select-fill-outline.select-label-placement-stacked) select,:host(.select-fill-outline.select-label-placement-floating) select{margin-left:0;margin-right:0;margin-top:6px;margin-bottom:6px}:host(.select-fill-outline) .select-outline-container{left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;width:100%;height:100%}:host(.select-fill-outline) .select-outline-start,:host(.select-fill-outline) .select-outline-end{pointer-events:none}:host(.select-fill-outline) .select-outline-start,:host(.select-fill-outline) .select-outline-notch,:host(.select-fill-outline) .select-outline-end{border-top:var(--border-width) var(--border-style) var(--border-color);border-bottom:var(--border-width) var(--border-style) var(--border-color);-webkit-box-sizing:border-box;box-sizing:border-box}:host(.select-fill-outline) .select-outline-notch{max-width:calc(100% - var(--padding-start) - var(--padding-end))}:host(.select-fill-outline) .notch-spacer{-webkit-padding-end:8px;padding-inline-end:8px;font-size:calc(1em * 0.75);opacity:0;pointer-events:none}:host(.select-fill-outline) .select-outline-start{-webkit-border-start:var(--border-width) var(--border-style) var(--border-color);border-inline-start:var(--border-width) var(--border-style) var(--border-color)}:host(.select-fill-outline) .select-outline-start{border-start-start-radius:var(--border-radius);border-start-end-radius:0px;border-end-end-radius:0px;border-end-start-radius:var(--border-radius)}:host(.select-fill-outline) .select-outline-start{width:calc(var(--padding-start) - 4px)}:host(.select-fill-outline) .select-outline-end{-webkit-border-end:var(--border-width) var(--border-style) var(--border-color);border-inline-end:var(--border-width) var(--border-style) var(--border-color)}:host(.select-fill-outline) .select-outline-end{border-start-start-radius:0px;border-start-end-radius:var(--border-radius);border-end-end-radius:var(--border-radius);border-end-start-radius:0px}:host(.select-fill-outline) .select-outline-end{-ms-flex-positive:1;flex-grow:1}:host(.label-floating.select-fill-outline) .select-outline-notch{border-top:none}:host(.in-item.select-expanded.select-fill-outline) .select-wrapper .select-icon,:host(.in-item.has-focus.select-fill-outline) .select-wrapper .select-icon,:host(.in-item.has-focus.ion-valid.select-fill-outline) .select-wrapper .select-icon,:host(.in-item.ion-touched.ion-invalid.select-fill-outline) .select-wrapper .select-icon{color:var(--highlight-color)}:host{--border-width:1px;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));--highlight-height:2px}:host(.select-label-placement-floating.select-expanded) .label-text-wrapper,:host(.select-label-placement-floating.has-focus) .label-text-wrapper,:host(.select-label-placement-stacked.select-expanded) .label-text-wrapper,:host(.select-label-placement-stacked.has-focus) .label-text-wrapper{color:var(--highlight-color)}:host(.has-focus.select-label-placement-floating.ion-valid) .label-text-wrapper,:host(.select-label-placement-floating.ion-touched.ion-invalid) .label-text-wrapper,:host(.has-focus.select-label-placement-stacked.ion-valid) .label-text-wrapper,:host(.select-label-placement-stacked.ion-touched.ion-invalid) .label-text-wrapper{color:var(--highlight-color)}.select-highlight{bottom:-1px;position:absolute;width:100%;height:var(--highlight-height);-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform 200ms;transition:-webkit-transform 200ms;transition:transform 200ms;transition:transform 200ms, -webkit-transform 200ms;background:var(--highlight-color)}.select-highlight{inset-inline-start:0}:host(.select-expanded) .select-highlight,:host(.has-focus) .select-highlight{-webkit-transform:scale(1);transform:scale(1)}:host(.in-item) .select-highlight{bottom:0}:host(.in-item) .select-highlight{inset-inline-start:0}.select-icon{width:0.8125rem;-webkit-transition:-webkit-transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);transition:-webkit-transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);transition:transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);transition:transform 0.15s cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 0.15s cubic-bezier(0.4, 0, 0.2, 1);color:var(--ion-color-step-500, var(--ion-text-color-step-500, gray))}:host(.select-expanded:not(.has-expanded-icon)) .select-icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}:host(.in-item.select-expanded) .select-wrapper .select-icon,:host(.in-item.has-focus) .select-wrapper .select-icon,:host(.in-item.has-focus.ion-valid) .select-wrapper .select-icon,:host(.in-item.ion-touched.ion-invalid) .select-wrapper .select-icon{color:var(--ion-color-step-500, var(--ion-text-color-step-500, gray))}:host(.select-expanded) .select-wrapper .select-icon,:host(.has-focus.ion-valid) .select-wrapper .select-icon,:host(.ion-touched.ion-invalid) .select-wrapper .select-icon,:host(.has-focus) .select-wrapper .select-icon{color:var(--highlight-color)}:host(.select-shape-round){--border-radius:16px}:host(.select-label-placement-stacked) .select-wrapper-inner,:host(.select-label-placement-floating) .select-wrapper-inner{width:calc(100% - 0.8125rem - 4px)}:host(.select-disabled){opacity:0.38}::slotted(ion-button[slot=start].button-has-icon-only),::slotted(ion-button[slot=end].button-has-icon-only){--border-radius:50%;--padding-start:8px;--padding-end:8px;--padding-top:8px;--padding-bottom:8px;aspect-ratio:1;min-height:40px}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot label - The label text to associate with the select. Use the `labelPlacement` property to control where the label is placed relative to the select. Use this if you need to render a label with custom HTML.
* @slot start - Content to display at the leading edge of the select.
* @slot end - Content to display at the trailing edge of the select.
*
* @part placeholder - The text displayed in the select when there is no value.
* @part text - The displayed value of the select.
* @part icon - The select icon container.
* @part container - The container for the selected text or placeholder.
* @part label - The label text describing the select.
* @part supporting-text - Supporting text displayed beneath the select.
* @part helper-text - Supporting text displayed beneath the select when the select is valid.
* @part error-text - Supporting text displayed beneath the select when the select is invalid and touched.
*/
class Select {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionCancel = createEvent(this, "ionCancel", 7);
this.ionDismiss = createEvent(this, "ionDismiss", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionStyle = createEvent(this, "ionStyle", 7);
this.inputId = `ion-sel-${selectIds++}`;
this.helperTextId = `${this.inputId}-helper-text`;
this.errorTextId = `${this.inputId}-error-text`;
this.inheritedAttributes = {};
this.isExpanded = false;
/**
* The `hasFocus` state ensures the focus class is
* added regardless of how the element is focused.
* The `ion-focused` class only applies when focused
* via tabbing, not by clicking.
* The `has-focus` logic was added to ensure the class
* is applied in both cases.
*/
this.hasFocus = false;
/**
* Track validation state for proper aria-live announcements.
*/
this.isInvalid = false;
/**
* The text to display on the cancel button.
*/
this.cancelText = 'Cancel';
/**
* If `true`, the user cannot interact with the select.
*/
this.disabled = false;
/**
* The interface the select should use: `action-sheet`, `popover`, `alert`, or `modal`.
*/
this.interface = 'alert';
/**
* Any additional options that the `alert`, `action-sheet` or `popover` interface
* can take. See the [ion-alert docs](./alert), the
* [ion-action-sheet docs](./action-sheet), the
* [ion-popover docs](./popover), and the [ion-modal docs](./modal) for the
* create options for each interface.
*
* Note: `interfaceOptions` will not override `inputs` or `buttons` with the `alert` interface.
*/
this.interfaceOptions = {};
/**
* Where to place the label relative to the select.
* `"start"`: The label will appear to the left of the select in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the select in LTR and to the left in RTL.
* `"floating"`: The label will appear smaller and above the select when the select is focused or it has a value. Otherwise it will appear on top of the select.
* `"stacked"`: The label will appear smaller and above the select regardless even when the select is blurred or has no value.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
* When using `"floating"` or `"stacked"` we recommend initializing the select with either a `value` or a `placeholder`.
*/
this.labelPlacement = 'start';
/**
* If `true`, the select can accept multiple values.
*/
this.multiple = false;
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* The text to display on the ok button.
*/
this.okText = 'OK';
/**
* If true, screen readers will announce it as a required field. This property
* works only for accessibility purposes, it will not prevent the form from
* submitting if the value is invalid.
*/
this.required = false;
this.onClick = (ev) => {
const target = ev.target;
const closestSlot = target.closest('[slot="start"], [slot="end"]');
if (target === this.el || closestSlot === null) {
this.setFocus();
this.open(ev);
}
else {
/**
* Prevent clicks to the start/end slots from opening the select.
* We ensure the target isn't this element in case the select is slotted
* in, for example, an item. This would prevent the select from ever
* being opened since the element itself has slot="start"/"end".
*
* Clicking a slotted element also causes a click
* on the <label> element (since it wraps the slots).
* Clicking <label> dispatches another click event on
* the native form control that then bubbles up to this
* listener. This additional event targets the host
* element, so the select overlay is opened.
*
* When the slotted elements are clicked (and therefore
* the ancestor <label> element) we want to prevent the label
* from dispatching another click event.
*
* Do not call stopPropagation() because this will cause
* click handlers on the slotted elements to never fire in React.
* When developers do onClick in React a native "click" listener
* is added on the root element, not the slotted element. When that
* native click listener fires, React then dispatches the synthetic
* click event on the slotted element. However, if stopPropagation
* is called then the native click event will never bubble up
* to the root element.
*/
ev.preventDefault();
}
};
this.onFocus = () => {
this.hasFocus = true;
this.ionFocus.emit();
};
this.onBlur = () => {
this.hasFocus = false;
this.ionBlur.emit();
};
/**
* Stops propagation when the label is clicked,
* otherwise, two clicks will be triggered.
*/
this.onLabelClick = (ev) => {
// Only stop propagation if the click was directly on the label
// and not on the input or other child elements
if (ev.target === ev.currentTarget) {
ev.stopPropagation();
}
};
}
styleChanged() {
this.emitStyle();
}
setValue(value) {
this.value = value;
this.ionChange.emit({ value });
}
async connectedCallback() {
const { el } = this;
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
this.updateOverlayOptions();
this.emitStyle();
this.mutationO = watchForOptions(this.el, 'ion-select-option', async () => {
this.updateOverlayOptions();
});
// Always set initial state
this.isInvalid = checkInvalidState(this.el);
}
componentWillLoad() {
this.inheritedAttributes = inheritAttributes$1(this.el, ['aria-label']);
this.hintTextID = this.getHintTextID();
}
componentDidLoad() {
/**
* If any of the conditions that trigger the styleChanged callback
* are met on component load, it is possible the event emitted
* prior to a parent web component registering an event listener.
*
* To ensure the parent web component receives the event, we
* emit the style event again after the component has loaded.
*
* This is often seen in Angular with the `dist` output target.
*/
this.emitStyle();
}
disconnectedCallback() {
if (this.mutationO) {
this.mutationO.disconnect();
this.mutationO = undefined;
}
if (this.notchController) {
this.notchController.destroy();
this.notchController = undefined;
}
// Clean up validation observer to prevent memory leaks.
if (this.validationObserver) {
this.validationObserver.disconnect();
this.validationObserver = undefined;
}
}
/**
* Open the select overlay. The overlay is either an alert, action sheet, or popover,
* depending on the `interface` property on the `ion-select`.
*
* @param event The user interface event that called the open.
*/
async open(event) {
if (this.disabled || this.isExpanded) {
return undefined;
}
this.isExpanded = true;
const overlay = (this.overlay = await this.createOverlay(event));
// Add logic to scroll selected item into view before presenting
const scrollSelectedIntoView = () => {
const indexOfSelected = this.childOpts.findIndex((o) => o.value === this.value);
if (indexOfSelected > -1) {
const selectedItem = overlay.querySelector(`.select-interface-option:nth-of-type(${indexOfSelected + 1})`);
if (selectedItem) {
/**
* Browsers such as Firefox do not
* correctly delegate focus when manually
* focusing an element with delegatesFocus.
* We work around this by manually focusing
* the interactive element.
* ion-radio and ion-checkbox are the only
* elements that ion-select-popover uses, so
* we only need to worry about those two components
* when focusing.
*/
const interactiveEl = selectedItem.querySelector('ion-radio, ion-checkbox');
if (interactiveEl) {
selectedItem.scrollIntoView({ block: 'nearest' });
// Needs to be called before `focusVisibleElement` to prevent issue with focus event bubbling
// and removing `ion-focused` style
interactiveEl.setFocus();
}
focusVisibleElement(selectedItem);
}
}
else {
/**
* If no value is set then focus the first enabled option.
*/
const firstEnabledOption = overlay.querySelector('ion-radio:not(.radio-disabled), ion-checkbox:not(.checkbox-disabled)');
if (firstEnabledOption) {
/**
* Focus the option for the same reason as we do above.
*
* Needs to be called before `focusVisibleElement` to prevent issue with focus event bubbling
* and removing `ion-focused` style
*/
firstEnabledOption.setFocus();
focusVisibleElement(firstEnabledOption.closest('ion-item'));
}
}
};
// For modals and popovers, we can scroll before they're visible
if (this.interface === 'modal') {
overlay.addEventListener('ionModalWillPresent', scrollSelectedIntoView, { once: true });
}
else if (this.interface === 'popover') {
overlay.addEventListener('ionPopoverWillPresent', scrollSelectedIntoView, { once: true });
}
else {
/**
* For alerts and action sheets, we need to wait a frame after willPresent
* because these overlays don't have their content in the DOM immediately
* when willPresent fires. By waiting a frame, we ensure the content is
* rendered and can be properly scrolled into view.
*/
const scrollAfterRender = () => {
requestAnimationFrame(() => {
scrollSelectedIntoView();
});
};
if (this.interface === 'alert') {
overlay.addEventListener('ionAlertWillPresent', scrollAfterRender, { once: true });
}
else if (this.interface === 'action-sheet') {
overlay.addEventListener('ionActionSheetWillPresent', scrollAfterRender, { once: true });
}
}
overlay.onDidDismiss().then(() => {
this.overlay = undefined;
this.isExpanded = false;
this.ionDismiss.emit();
this.setFocus();
});
await overlay.present();
return overlay;
}
createOverlay(ev) {
let selectInterface = this.interface;
if (selectInterface === 'action-sheet' && this.multiple) {
printIonWarning(`[ion-select] - Interface cannot be "${selectInterface}" with a multi-value select. Using the "alert" interface instead.`);
selectInterface = 'alert';
}
if (selectInterface === 'popover' && !ev) {
printIonWarning(`[ion-select] - Interface cannot be a "${selectInterface}" without passing an event. Using the "alert" interface instead.`);
selectInterface = 'alert';
}
if (selectInterface === 'action-sheet') {
return this.openActionSheet();
}
if (selectInterface === 'popover') {
return this.openPopover(ev);
}
if (selectInterface === 'modal') {
return this.openModal();
}
return this.openAlert();
}
updateOverlayOptions() {
const overlay = this.overlay;
if (!overlay) {
return;
}
const childOpts = this.childOpts;
const value = this.value;
switch (this.interface) {
case 'action-sheet':
overlay.buttons = this.createActionSheetButtons(childOpts, value);
break;
case 'popover':
const popover = overlay.querySelector('ion-select-popover');
if (popover) {
popover.options = this.createOverlaySelectOptions(childOpts, value);
}
break;
case 'modal':
const modal = overlay.querySelector('ion-select-modal');
if (modal) {
modal.options = this.createOverlaySelectOptions(childOpts, value);
}
break;
case 'alert':
const inputType = this.multiple ? 'checkbox' : 'radio';
overlay.inputs = this.createAlertInputs(childOpts, inputType, value);
break;
}
}
createActionSheetButtons(data, selectValue) {
const actionSheetButtons = data.map((option) => {
const value = getOptionValue(option);
// Remove hydrated before copying over classes
const copyClasses = Array.from(option.classList)
.filter((cls) => cls !== 'hydrated')
.join(' ');
const optClass = `${OPTION_CLASS} ${copyClasses}`;
return {
role: isOptionSelected(selectValue, value, this.compareWith) ? 'selected' : '',
text: option.textContent,
cssClass: optClass,
handler: () => {
this.setValue(value);
},
};
});
// Add "cancel" button
actionSheetButtons.push({
text: this.cancelText,
role: 'cancel',
handler: () => {
this.ionCancel.emit();
},
});
return actionSheetButtons;
}
createAlertInputs(data, inputType, selectValue) {
const alertInputs = data.map((option) => {
const value = getOptionValue(option);
// Remove hydrated before copying over classes
const copyClasses = Array.from(option.classList)
.filter((cls) => cls !== 'hydrated')
.join(' ');
const optClass = `${OPTION_CLASS} ${copyClasses}`;
return {
type: inputType,
cssClass: optClass,
label: option.textContent || '',
value,
checked: isOptionSelected(selectValue, value, this.compareWith),
disabled: option.disabled,
};
});
return alertInputs;
}
createOverlaySelectOptions(data, selectValue) {
const popoverOptions = data.map((option) => {
const value = getOptionValue(option);
// Remove hydrated before copying over classes
const copyClasses = Array.from(option.classList)
.filter((cls) => cls !== 'hydrated')
.join(' ');
const optClass = `${OPTION_CLASS} ${copyClasses}`;
return {
text: option.textContent || '',
cssClass: optClass,
value,
checked: isOptionSelected(selectValue, value, this.compareWith),
disabled: option.disabled,
handler: (selected) => {
this.setValue(selected);
if (!this.multiple) {
this.close();
}
},
};
});
return popoverOptions;
}
async openPopover(ev) {
const { fill, labelPlacement } = this;
const interfaceOptions = this.interfaceOptions;
const mode = getIonMode$1(this);
const showBackdrop = mode === 'md' ? false : true;
const multiple = this.multiple;
const value = this.value;
let event = ev;
let size = 'auto';
const hasFloatingOrStackedLabel = labelPlacement === 'floating' || labelPlacement === 'stacked';
/**
* The popover should take up the full width
* when using a fill in MD mode or if the
* label is floating/stacked.
*/
if (hasFloatingOrStackedLabel || (mode === 'md' && fill !== undefined)) {
size = 'cover';
/**
* Otherwise the popover
* should be positioned relative
* to the native element.
*/
}
else {
event = Object.assign(Object.assign({}, ev), { detail: {
ionShadowTarget: this.nativeWrapperEl,
} });
}
const popoverOpts = Object.assign(Object.assign({ mode,
event, alignment: 'center', size,
showBackdrop }, interfaceOptions), { component: 'ion-select-popover', cssClass: ['select-popover', interfaceOptions.cssClass], componentProps: {
header: interfaceOptions.header,
subHeader: interfaceOptions.subHeader,
message: interfaceOptions.message,
multiple,
value,
options: this.createOverlaySelectOptions(this.childOpts, value),
} });
return popoverController.create(popoverOpts);
}
async openActionSheet() {
const mode = getIonMode$1(this);
const interfaceOptions = this.interfaceOptions;
const actionSheetOpts = Object.assign(Object.assign({ mode }, interfaceOptions), { buttons: this.createActionSheetButtons(this.childOpts, this.value), cssClass: ['select-action-sheet', interfaceOptions.cssClass] });
return actionSheetController.create(actionSheetOpts);
}
async openAlert() {
const interfaceOptions = this.interfaceOptions;
const inputType = this.multiple ? 'checkbox' : 'radio';
const mode = getIonMode$1(this);
const alertOpts = Object.assign(Object.assign({ mode }, interfaceOptions), { header: interfaceOptions.header ? interfaceOptions.header : this.labelText, inputs: this.createAlertInputs(this.childOpts, inputType, this.value), buttons: [
{
text: this.cancelText,
role: 'cancel',
handler: () => {
this.ionCancel.emit();
},
},
{
text: this.okText,
handler: (selectedValues) => {
this.setValue(selectedValues);
},
},
], cssClass: [
'select-alert',
interfaceOptions.cssClass,
this.multiple ? 'multiple-select-alert' : 'single-select-alert',
] });
return alertController.create(alertOpts);
}
openModal() {
const { multiple, value, interfaceOptions } = this;
const mode = getIonMode$1(this);
const modalOpts = Object.assign(Object.assign({}, interfaceOptions), { mode, cssClass: ['select-modal', interfaceOptions.cssClass], component: 'ion-select-modal', componentProps: {
header: interfaceOptions.header,
multiple,
value,
options: this.createOverlaySelectOptions(this.childOpts, value),
} });
return modalController.create(modalOpts);
}
/**
* Close the select interface.
*/
close() {
if (!this.overlay) {
return Promise.resolve(false);
}
return this.overlay.dismiss();
}
hasValue() {
return this.getText() !== '';
}
get childOpts() {
return Array.from(this.el.querySelectorAll('ion-select-option'));
}
/**
* Returns any plaintext associated with
* the label (either prop or slot).
* Note: This will not return any custom
* HTML. Use the `hasLabel` getter if you
* want to know if any slotted label content
* was passed.
*/
get labelText() {
const { label } = this;
if (label !== undefined) {
return label;
}
const { labelSlot } = this;
if (labelSlot !== null) {
return labelSlot.textContent;
}
return;
}
getText() {
const selectedText = this.selectedText;
if (selectedText != null && selectedText !== '') {
return selectedText;
}
return generateText(this.childOpts, this.value, this.compareWith);
}
setFocus() {
if (this.focusEl) {
this.focusEl.focus();
}
}
emitStyle() {
const { disabled } = this;
const style = {
'interactive-disabled': disabled,
};
this.ionStyle.emit(style);
}
renderLabel() {
const { label } = this;
return (hAsync("div", { class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !this.hasLabel,
}, part: "label" }, label === undefined ? hAsync("slot", { name: "label" }) : hAsync("div", { class: "label-text" }, label)));
}
componentDidRender() {
var _a;
(_a = this.notchController) === null || _a === void 0 ? void 0 : _a.calculateNotchWidth();
}
/**
* Gets any content passed into the `label` slot,
* not the <slot> definition.
*/
get labelSlot() {
return this.el.querySelector('[slot="label"]');
}
/**
* Returns `true` if label content is provided
* either by a prop or a content. If you want
* to get the plaintext value of the label use
* the `labelText` getter instead.
*/
get hasLabel() {
return this.label !== undefined || this.labelSlot !== null;
}
/**
* Renders the border container
* when fill="outline".
*/
renderLabelContainer() {
const mode = getIonMode$1(this);
const hasOutlineFill = mode === 'md' && this.fill === 'outline';
if (hasOutlineFill) {
/**
* The outline fill has a special outline
* that appears around the select and the label.
* Certain stacked and floating label placements cause the
* label to translate up and create a "cut out"
* inside of that border by using the notch-spacer element.
*/
return [
hAsync("div", { class: "select-outline-container" }, hAsync("div", { class: "select-outline-start" }), hAsync("div", { class: {
'select-outline-notch': true,
'select-outline-notch-hidden': !this.hasLabel,
} }, hAsync("div", { class: "notch-spacer", "aria-hidden": "true", ref: (el) => (this.notchSpacerEl = el) }, this.label)), hAsync("div", { class: "select-outline-end" })),
this.renderLabel(),
];
}
/**
* If not using the outline style,
* we can render just the label.
*/
return this.renderLabel();
}
/**
* Renders either the placeholder
* or the selected values based on
* the state of the select.
*/
renderSelectText() {
const { placeholder } = this;
const displayValue = this.getText();
let addPlaceholderClass = false;
let selectText = displayValue;
if (selectText === '' && placeholder !== undefined) {
selectText = placeholder;
addPlaceholderClass = true;
}
const selectTextClasses = {
'select-text': true,
'select-placeholder': addPlaceholderClass,
};
const textPart = addPlaceholderClass ? 'placeholder' : 'text';
return (hAsync("div", { "aria-hidden": "true", class: selectTextClasses, part: textPart }, selectText));
}
/**
* Renders the chevron icon
* next to the select text.
*/
renderSelectIcon() {
const mode = getIonMode$1(this);
const { isExpanded, toggleIcon, expandedIcon } = this;
let icon;
if (isExpanded && expandedIcon !== undefined) {
icon = expandedIcon;
}
else {
const defaultIcon = mode === 'ios' ? chevronExpand : caretDownSharp;
icon = toggleIcon !== null && toggleIcon !== void 0 ? toggleIcon : defaultIcon;
}
return hAsync("ion-icon", { class: "select-icon", part: "icon", "aria-hidden": "true", icon: icon });
}
get ariaLabel() {
var _a;
const { placeholder, inheritedAttributes } = this;
const displayValue = this.getText();
// The aria label should be preferred over visible text if both are specified
const definedLabel = (_a = inheritedAttributes['aria-label']) !== null && _a !== void 0 ? _a : this.labelText;
/**
* If developer has specified a placeholder
* and there is nothing selected, the selectText
* should have the placeholder value.
*/
let renderedLabel = displayValue;
if (renderedLabel === '' && placeholder !== undefined) {
renderedLabel = placeholder;
}
/**
* If there is a developer-defined label,
* then we need to concatenate the developer label
* string with the current current value.
* The label for the control should be read
* before the values of the control.
*/
if (definedLabel !== undefined) {
renderedLabel = renderedLabel === '' ? definedLabel : `${definedLabel}, ${renderedLabel}`;
}
return renderedLabel;
}
renderListbox() {
const { disabled, inputId, isExpanded, required } = this;
return (hAsync("button", { disabled: disabled, id: inputId, "aria-label": this.ariaLabel, "aria-haspopup": "dialog", "aria-expanded": `${isExpanded}`, "aria-describedby": this.hintTextID, "aria-invalid": this.isInvalid ? 'true' : undefined, "aria-required": `${required}`, onFocus: this.onFocus, onBlur: this.onBlur, ref: (focusEl) => (this.focusEl = focusEl) }));
}
getHintTextID() {
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
if (isInvalid && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
/**
* Renders the helper text or error text values
*/
renderHintText() {
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
return [
hAsync("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
hAsync("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text", role: "alert" }, isInvalid ? errorText : null),
];
}
/**
* Responsible for rendering helper text, and error text. This element
* should only be rendered if hint text is set.
*/
renderBottomContent() {
const { helperText, errorText } = this;
/**
* undefined and empty string values should
* be treated as not having helper/error text.
*/
const hasHintText = !!helperText || !!errorText;
if (!hasHintText) {
return;
}
return hAsync("div", { class: "select-bottom" }, this.renderHintText());
}
render() {
const { disabled, el, isExpanded, expandedIcon, labelPlacement, justify, placeholder, fill, shape, name, value, hasFocus, } = this;
const mode = getIonMode$1(this);
const hasFloatingOrStackedLabel = labelPlacement === 'floating' || labelPlacement === 'stacked';
const justifyEnabled = !hasFloatingOrStackedLabel && justify !== undefined;
const rtl = isRTL$1(el) ? 'rtl' : 'ltr';
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
renderHiddenInput(true, el, name, parseValue(value), disabled);
/**
* If the label is stacked, it should always sit above the select.
* For floating labels, the label should move above the select if
* the select has a value, is open, or has anything in either
* the start or end slot.
*
* If there is content in the start slot, the label would overlap
* it if not forced to float. This is also applied to the end slot
* because with the default or solid fills, the select is not
* vertically centered in the container, but the label is. This
* causes the slots and label to appear vertically offset from each
* other when the label isn't floating above the input. This doesn't
* apply to the outline fill, but this was not accounted for to keep
* things consistent.
*
* TODO(FW-5592): Remove hasStartEndSlots condition
*/
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || isExpanded || hasStartEndSlots));
return (hAsync(Host, { key: '35b5e18e6f79a802ff2d46d1242e80ff755cc0b9', onClick: this.onClick, class: createColorClasses$1(this.color, {
[mode]: true,
'in-item': inItem,
'in-item-color': hostContext('ion-item.ion-color', el),
'select-disabled': disabled,
'select-expanded': isExpanded,
'has-expanded-icon': expandedIcon !== undefined,
'has-value': hasValue,
'label-floating': labelShouldFloat,
'has-placeholder': placeholder !== undefined,
'has-focus': hasFocus,
// TODO(FW-6451): Remove `ion-focusable` class in favor of `has-focus`.
'ion-focusable': true,
[`select-${rtl}`]: true,
[`select-fill-${fill}`]: fill !== undefined,
[`select-justify-${justify}`]: justifyEnabled,
[`select-shape-${shape}`]: shape !== undefined,
[`select-label-placement-${labelPlacement}`]: true,
}) }, hAsync("label", { key: '6005b34a0c50bc4d7653a4276bc232ecd02e083c', class: "select-wrapper", id: "select-label", onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: 'c7e07aa81ae856c057f16275dd058f37c5670a47', class: "select-wrapper-inner" }, hAsync("slot", { key: '7fc2deefe0424404caacdbbd9e08ed43ba55d28a', name: "start" }), hAsync("div", { key: '157d74ee717b1bc30b5f1c233a09b0c8456aa68e', class: "native-wrapper", ref: (el) => (this.nativeWrapperEl = el), part: "container" }, this.renderSelectText(), this.renderListbox()), hAsync("slot", { key: 'ea66db304528b82bf9317730b6dce3db2612f235', name: "end" }), !hasFloatingOrStackedLabel && this.renderSelectIcon()), hasFloatingOrStackedLabel && this.renderSelectIcon(), shouldRenderHighlight && hAsync("div", { key: '786eb1530b7476f0615d4e7c0bf4e7e4dc66509c', class: "select-highlight" })), this.renderBottomContent()));
}
get el() { return getElement(this); }
static get watchers() { return {
"disabled": ["styleChanged"],
"isExpanded": ["styleChanged"],
"placeholder": ["styleChanged"],
"value": ["styleChanged"]
}; }
static get style() { return {
ios: selectIosCss,
md: selectMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-select",
"$members$": {
"cancelText": [1, "cancel-text"],
"color": [513],
"compareWith": [1, "compare-with"],
"disabled": [4],
"fill": [1],
"errorText": [1, "error-text"],
"helperText": [1, "helper-text"],
"interface": [1],
"interfaceOptions": [8, "interface-options"],
"justify": [1],
"label": [1],
"labelPlacement": [1, "label-placement"],
"multiple": [4],
"name": [1],
"okText": [1, "ok-text"],
"placeholder": [1],
"selectedText": [1, "selected-text"],
"toggleIcon": [1, "toggle-icon"],
"expandedIcon": [1, "expanded-icon"],
"shape": [1],
"value": [1032],
"required": [4],
"isExpanded": [32],
"hasFocus": [32],
"isInvalid": [32],
"hintTextID": [32],
"open": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const getOptionValue = (el) => {
const value = el.value;
return value === undefined ? el.textContent || '' : value;
};
const parseValue = (value) => {
if (value == null) {
return undefined;
}
if (Array.isArray(value)) {
return value.join(',');
}
return value.toString();
};
const generateText = (opts, value, compareWith) => {
if (value === undefined) {
return '';
}
if (Array.isArray(value)) {
return value
.map((v) => textForValue(opts, v, compareWith))
.filter((opt) => opt !== null)
.join(', ');
}
else {
return textForValue(opts, value, compareWith) || '';
}
};
const textForValue = (opts, value, compareWith) => {
const selectOpt = opts.find((opt) => {
return compareOptions(value, getOptionValue(opt), compareWith);
});
return selectOpt ? selectOpt.textContent : null;
};
let selectIds = 0;
const OPTION_CLASS = 'select-interface-option';
const ionicSelectModalMdCss = ".sc-ion-select-modal-ionic-h{height:100%}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(container),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"container\"]{display:none}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~=\"label\"]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-item.sc-ion-select-modal-ionic{--inner-border-width:0}.item-radio-checked.sc-ion-select-modal-ionic{--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.08);--background-focused:var(--ion-color-primary, #0054e9);--background-focused-opacity:0.2;--background-hover:var(--ion-color-primary, #0054e9);--background-hover-opacity:0.12}.item-checkbox-checked.sc-ion-select-modal-ionic{--background-activated:var(--ion-item-color, var(--ion-text-color, #000));--background-focused:var(--ion-item-color, var(--ion-text-color, #000));--background-hover:var(--ion-item-color, var(--ion-text-color, #000));--color:var(--ion-color-primary, #0054e9)}";
const selectModalIosCss = ".sc-ion-select-modal-ios-h{height:100%}ion-item.sc-ion-select-modal-ios{--inner-padding-end:0}ion-radio.sc-ion-select-modal-ios::after{bottom:0;position:absolute;width:calc(100% - 0.9375rem - 16px);border-width:0px 0px 0.55px 0px;border-style:solid;border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));content:\"\"}ion-radio.sc-ion-select-modal-ios::after{inset-inline-start:calc(0.9375rem + 16px)}";
const selectModalMdCss = ".sc-ion-select-modal-md-h{height:100%}ion-list.sc-ion-select-modal-md ion-radio.sc-ion-select-modal-md::part(container),ion-list.sc-ion-select-modal-md ion-radio.sc-ion-select-modal-md [part~=\"container\"]{display:none}ion-list.sc-ion-select-modal-md ion-radio.sc-ion-select-modal-md::part(label),ion-list.sc-ion-select-modal-md ion-radio.sc-ion-select-modal-md [part~=\"label\"]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-item.sc-ion-select-modal-md{--inner-border-width:0}.item-radio-checked.sc-ion-select-modal-md{--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.08);--background-focused:var(--ion-color-primary, #0054e9);--background-focused-opacity:0.2;--background-hover:var(--ion-color-primary, #0054e9);--background-hover-opacity:0.12}.item-checkbox-checked.sc-ion-select-modal-md{--background-activated:var(--ion-item-color, var(--ion-text-color, #000));--background-focused:var(--ion-item-color, var(--ion-text-color, #000));--background-hover:var(--ion-item-color, var(--ion-text-color, #000));--color:var(--ion-color-primary, #0054e9)}";
class SelectModal {
constructor(hostRef) {
registerInstance(this, hostRef);
this.options = [];
}
closeModal() {
const modal = this.el.closest('ion-modal');
if (modal) {
modal.dismiss();
}
}
findOptionFromEvent(ev) {
const { options } = this;
return options.find((o) => o.value === ev.target.value);
}
getValues(ev) {
const { multiple, options } = this;
if (multiple) {
// this is a modal with checkboxes (multiple value select)
// return an array of all the checked values
return options.filter((o) => o.checked).map((o) => o.value);
}
// this is a modal with radio buttons (single value select)
// return the value that was clicked, otherwise undefined
const option = ev ? this.findOptionFromEvent(ev) : null;
return option ? option.value : undefined;
}
callOptionHandler(ev) {
const option = this.findOptionFromEvent(ev);
const values = this.getValues(ev);
if (option === null || option === void 0 ? void 0 : option.handler) {
safeCall(option.handler, values);
}
}
setChecked(ev) {
const { multiple } = this;
const option = this.findOptionFromEvent(ev);
// this is a modal with checkboxes (multiple value select)
// we need to set the checked value for this option
if (multiple && option) {
option.checked = ev.detail.checked;
}
}
renderRadioOptions() {
const checked = this.options.filter((o) => o.checked).map((o) => o.value)[0];
return (hAsync("ion-radio-group", { value: checked, onIonChange: (ev) => this.callOptionHandler(ev) }, this.options.map((option) => (hAsync("ion-item", { lines: "none", class: Object.assign({
// TODO FW-4784
'item-radio-checked': option.value === checked
}, getClassMap(option.cssClass)) }, hAsync("ion-radio", { value: option.value, disabled: option.disabled, justify: "start", labelPlacement: "end", onClick: () => this.closeModal(), onKeyUp: (ev) => {
if (ev.key === ' ') {
/**
* Selecting a radio option with keyboard navigation,
* either through the Enter or Space keys, should
* dismiss the modal.
*/
this.closeModal();
}
} }, option.text))))));
}
renderCheckboxOptions() {
return this.options.map((option) => (hAsync("ion-item", { class: Object.assign({
// TODO FW-4784
'item-checkbox-checked': option.checked
}, getClassMap(option.cssClass)) }, hAsync("ion-checkbox", { value: option.value, disabled: option.disabled, checked: option.checked, justify: "start", labelPlacement: "end", onIonChange: (ev) => {
this.setChecked(ev);
this.callOptionHandler(ev);
} }, option.text))));
}
render() {
return (hAsync(Host, { key: 'b6c0dec240b2e41985b15fdf4e5a6d3a145c1567', class: getIonMode$1(this) }, hAsync("ion-header", { key: 'cd177e85ee0f62a60a3a708342d6ab6eb19a44dc' }, hAsync("ion-toolbar", { key: 'aee8222a5a4daa540ad202b2e4cac1ef93d9558c' }, this.header !== undefined && hAsync("ion-title", { key: '5f8fecc764d97bf840d3d4cfddeeccd118ab4436' }, this.header), hAsync("ion-buttons", { key: '919033950d7c2b0101f96a9c9698219de9f568ea', slot: "end" }, hAsync("ion-button", { key: '34b571cab6dced4bde555a077a21e91800829931', onClick: () => this.closeModal() }, "Close")))), hAsync("ion-content", { key: '3c9153d26ba7a5a03d3b20fcd628d0c3031661a7' }, hAsync("ion-list", { key: 'e00b222c071bc97c82ad1bba4db95a8a5c43ed6d' }, this.multiple === true ? this.renderCheckboxOptions() : this.renderRadioOptions()))));
}
get el() { return getElement(this); }
static get style() { return {
ionic: ionicSelectModalMdCss,
ios: selectModalIosCss,
md: selectModalMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-select-modal",
"$members$": {
"header": [1],
"multiple": [4],
"options": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const selectOptionCss = ":host{display:none}";
class SelectOption {
constructor(hostRef) {
registerInstance(this, hostRef);
this.inputId = `ion-selopt-${selectOptionIds++}`;
/**
* If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
*/
this.disabled = false;
}
render() {
return hAsync(Host, { key: '3a70eea9fa03a9acba582180761d18347c72acee', role: "option", id: this.inputId, class: getIonMode$1(this) });
}
get el() { return getElement(this); }
static get style() { return selectOptionCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-select-option",
"$members$": {
"disabled": [4],
"value": [8]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
let selectOptionIds = 0;
const selectPopoverIosCss = ".sc-ion-select-popover-ios-h ion-list.sc-ion-select-popover-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-list-header.sc-ion-select-popover-ios,ion-label.sc-ion-select-popover-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.sc-ion-select-popover-ios-h{overflow-y:auto}";
const selectPopoverMdCss = ".sc-ion-select-popover-md-h ion-list.sc-ion-select-popover-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-list-header.sc-ion-select-popover-md,ion-label.sc-ion-select-popover-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}.sc-ion-select-popover-md-h{overflow-y:auto}ion-list.sc-ion-select-popover-md ion-radio.sc-ion-select-popover-md::part(container),ion-list.sc-ion-select-popover-md ion-radio.sc-ion-select-popover-md [part~=\"container\"]{display:none}ion-list.sc-ion-select-popover-md ion-radio.sc-ion-select-popover-md::part(label),ion-list.sc-ion-select-popover-md ion-radio.sc-ion-select-popover-md [part~=\"label\"]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-item.sc-ion-select-popover-md{--inner-border-width:0}.item-radio-checked.sc-ion-select-popover-md{--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.08);--background-focused:var(--ion-color-primary, #0054e9);--background-focused-opacity:0.2;--background-hover:var(--ion-color-primary, #0054e9);--background-hover-opacity:0.12}.item-checkbox-checked.sc-ion-select-popover-md{--background-activated:var(--ion-item-color, var(--ion-text-color, #000));--background-focused:var(--ion-item-color, var(--ion-text-color, #000));--background-hover:var(--ion-item-color, var(--ion-text-color, #000));--color:var(--ion-color-primary, #0054e9)}";
/**
* @internal
*/
class SelectPopover {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* An array of options for the popover
*/
this.options = [];
}
findOptionFromEvent(ev) {
const { options } = this;
return options.find((o) => o.value === ev.target.value);
}
/**
* When an option is selected we need to get the value(s)
* of the selected option(s) and return it in the option
* handler
*/
callOptionHandler(ev) {
const option = this.findOptionFromEvent(ev);
const values = this.getValues(ev);
if (option === null || option === void 0 ? void 0 : option.handler) {
safeCall(option.handler, values);
}
}
/**
* Dismisses the host popover that the `ion-select-popover`
* is rendered within.
*/
dismissParentPopover() {
const popover = this.el.closest('ion-popover');
if (popover) {
popover.dismiss();
}
}
setChecked(ev) {
const { multiple } = this;
const option = this.findOptionFromEvent(ev);
// this is a popover with checkboxes (multiple value select)
// we need to set the checked value for this option
if (multiple && option) {
option.checked = ev.detail.checked;
}
}
getValues(ev) {
const { multiple, options } = this;
if (multiple) {
// this is a popover with checkboxes (multiple value select)
// return an array of all the checked values
return options.filter((o) => o.checked).map((o) => o.value);
}
// this is a popover with radio buttons (single value select)
// return the value that was clicked, otherwise undefined
const option = this.findOptionFromEvent(ev);
return option ? option.value : undefined;
}
renderOptions(options) {
const { multiple } = this;
switch (multiple) {
case true:
return this.renderCheckboxOptions(options);
default:
return this.renderRadioOptions(options);
}
}
renderCheckboxOptions(options) {
return options.map((option) => (hAsync("ion-item", { class: Object.assign({
// TODO FW-4784
'item-checkbox-checked': option.checked
}, getClassMap(option.cssClass)) }, hAsync("ion-checkbox", { value: option.value, disabled: option.disabled, checked: option.checked, justify: "start", labelPlacement: "end", onIonChange: (ev) => {
this.setChecked(ev);
this.callOptionHandler(ev);
} }, option.text))));
}
renderRadioOptions(options) {
const checked = options.filter((o) => o.checked).map((o) => o.value)[0];
return (hAsync("ion-radio-group", { value: checked, onIonChange: (ev) => this.callOptionHandler(ev) }, options.map((option) => (hAsync("ion-item", { class: Object.assign({
// TODO FW-4784
'item-radio-checked': option.value === checked
}, getClassMap(option.cssClass)) }, hAsync("ion-radio", { value: option.value, disabled: option.disabled, onClick: () => this.dismissParentPopover(), onKeyUp: (ev) => {
if (ev.key === ' ') {
/**
* Selecting a radio option with keyboard navigation,
* either through the Enter or Space keys, should
* dismiss the popover.
*/
this.dismissParentPopover();
}
} }, option.text))))));
}
render() {
const { header, message, options, subHeader } = this;
const hasSubHeaderOrMessage = subHeader !== undefined || message !== undefined;
return (hAsync(Host, { key: 'ab931b49b59283825bd2afa3f7f995b0e6e05bef', class: getIonMode$1(this) }, hAsync("ion-list", { key: '3bd12b67832607596b912a73d5b3ae9b954b244d' }, header !== undefined && hAsync("ion-list-header", { key: '97da930246edf7423a039c030d40e3ff7a5148a3' }, header), hasSubHeaderOrMessage && (hAsync("ion-item", { key: 'c579df6ea8fac07bb0c59d34c69b149656863224' }, hAsync("ion-label", { key: 'af699c5f465710ccb13b8cf8e7be66f0e8acfad1', class: "ion-text-wrap" }, subHeader !== undefined && hAsync("h3", { key: 'df9a936d42064b134e843c7229f314a2a3ec7e80' }, subHeader), message !== undefined && hAsync("p", { key: '9c3ddad378df00f106afa94e9928cf68c17124dd' }, message)))), this.renderOptions(options))));
}
get el() { return getElement(this); }
static get style() { return {
ios: selectPopoverIosCss,
md: selectPopoverMdCss
}; }
static get cmpMeta() { return {
"$flags$": 290,
"$tagName$": "ion-select-popover",
"$members$": {
"header": [1],
"subHeader": [1, "sub-header"],
"message": [1],
"multiple": [4],
"options": [16]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const skeletonTextCss = ":host{--background:rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.065);border-radius:var(--border-radius, inherit);display:block;width:100%;height:inherit;margin-top:4px;margin-bottom:4px;background:var(--background);line-height:10px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;pointer-events:none}span{display:inline-block}:host(.in-media){margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;height:100%}:host(.skeleton-text-animated){position:relative;background:-webkit-gradient(linear, left top, right top, color-stop(8%, rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.065)), color-stop(18%, rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.135)), color-stop(33%, rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.065)));background:linear-gradient(to right, rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.065) 8%, rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.135) 18%, rgba(var(--background-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.065) 33%);background-size:800px 104px;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-name:shimmer;animation-name:shimmer;-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes shimmer{0%{background-position:-400px 0}100%{background-position:400px 0}}@keyframes shimmer{0%{background-position:-400px 0}100%{background-position:400px 0}}";
class SkeletonText {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionStyle = createEvent(this, "ionStyle", 7);
/**
* If `true`, the skeleton text will animate.
*/
this.animated = false;
}
componentWillLoad() {
this.emitStyle();
}
emitStyle() {
// The emitted property is used by item in order
// to add the item-skeleton-text class which applies
// overflow: hidden to its label
const style = {
'skeleton-text': true,
};
this.ionStyle.emit(style);
}
render() {
const animated = this.animated && config.getBoolean('animated', true);
const inMedia = hostContext('ion-avatar', this.el) || hostContext('ion-thumbnail', this.el);
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd86ef7392507cdbf48dfd3a71f02d7a83eda4aae', class: {
[mode]: true,
'skeleton-text-animated': animated,
'in-media': inMedia,
} }, hAsync("span", { key: '8e8b5a232a6396d2bba691b05f9de4da44b2965c' }, "\u00A0")));
}
get el() { return getElement(this); }
static get style() { return skeletonTextCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-skeleton-text",
"$members$": {
"animated": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const spinnerCss = ":host{display:inline-block;position:relative;width:28px;height:28px;color:var(--color);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}:host(.ion-color){color:var(--ion-color-base)}svg{-webkit-transform-origin:center;transform-origin:center;position:absolute;top:0;left:0;width:100%;height:100%;-webkit-transform:translateZ(0);transform:translateZ(0)}:host-context([dir=rtl]) svg{-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}[dir=rtl] svg{-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}@supports selector(:dir(rtl)){svg:dir(rtl){-webkit-transform-origin:calc(100% - center);transform-origin:calc(100% - center)}}:host(.spinner-lines) line,:host(.spinner-lines-small) line{stroke-width:7px}:host(.spinner-lines-sharp) line,:host(.spinner-lines-sharp-small) line{stroke-width:4px}:host(.spinner-lines) line,:host(.spinner-lines-small) line,:host(.spinner-lines-sharp) line,:host(.spinner-lines-sharp-small) line{stroke-linecap:round;stroke:currentColor}:host(.spinner-lines) svg,:host(.spinner-lines-small) svg,:host(.spinner-lines-sharp) svg,:host(.spinner-lines-sharp-small) svg{-webkit-animation:spinner-fade-out 1s linear infinite;animation:spinner-fade-out 1s linear infinite}:host(.spinner-bubbles) svg{-webkit-animation:spinner-scale-out 1s linear infinite;animation:spinner-scale-out 1s linear infinite;fill:currentColor}:host(.spinner-circles) svg{-webkit-animation:spinner-fade-out 1s linear infinite;animation:spinner-fade-out 1s linear infinite;fill:currentColor}:host(.spinner-crescent) circle{fill:transparent;stroke-width:4px;stroke-dasharray:128px;stroke-dashoffset:82px;stroke:currentColor}:host(.spinner-crescent) svg{-webkit-animation:spinner-rotate 1s linear infinite;animation:spinner-rotate 1s linear infinite}:host(.spinner-dots) circle{stroke-width:0;fill:currentColor}:host(.spinner-dots) svg{-webkit-animation:spinner-dots 1s linear infinite;animation:spinner-dots 1s linear infinite}:host(.spinner-circular) svg{-webkit-animation:spinner-circular linear infinite;animation:spinner-circular linear infinite}:host(.spinner-circular) circle{-webkit-animation:spinner-circular-inner ease-in-out infinite;animation:spinner-circular-inner ease-in-out infinite;stroke:currentColor;stroke-dasharray:80px, 200px;stroke-dashoffset:0px;stroke-width:5.6;fill:none}:host(.spinner-paused),:host(.spinner-paused) svg,:host(.spinner-paused) circle{-webkit-animation-play-state:paused;animation-play-state:paused}@-webkit-keyframes spinner-fade-out{0%{opacity:1}100%{opacity:0}}@keyframes spinner-fade-out{0%{opacity:1}100%{opacity:0}}@-webkit-keyframes spinner-scale-out{0%{-webkit-transform:scale(1, 1);transform:scale(1, 1)}100%{-webkit-transform:scale(0, 0);transform:scale(0, 0)}}@keyframes spinner-scale-out{0%{-webkit-transform:scale(1, 1);transform:scale(1, 1)}100%{-webkit-transform:scale(0, 0);transform:scale(0, 0)}}@-webkit-keyframes spinner-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-rotate{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner-dots{0%{-webkit-transform:scale(1, 1);transform:scale(1, 1);opacity:0.9}50%{-webkit-transform:scale(0.4, 0.4);transform:scale(0.4, 0.4);opacity:0.3}100%{-webkit-transform:scale(1, 1);transform:scale(1, 1);opacity:0.9}}@keyframes spinner-dots{0%{-webkit-transform:scale(1, 1);transform:scale(1, 1);opacity:0.9}50%{-webkit-transform:scale(0.4, 0.4);transform:scale(0.4, 0.4);opacity:0.3}100%{-webkit-transform:scale(1, 1);transform:scale(1, 1);opacity:0.9}}@-webkit-keyframes spinner-circular{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes spinner-circular{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes spinner-circular-inner{0%{stroke-dasharray:1px, 200px;stroke-dashoffset:0px}50%{stroke-dasharray:100px, 200px;stroke-dashoffset:-15px}100%{stroke-dasharray:100px, 200px;stroke-dashoffset:-125px}}@keyframes spinner-circular-inner{0%{stroke-dasharray:1px, 200px;stroke-dashoffset:0px}50%{stroke-dasharray:100px, 200px;stroke-dashoffset:-15px}100%{stroke-dasharray:100px, 200px;stroke-dashoffset:-125px}}";
class Spinner {
constructor(hostRef) {
registerInstance(this, hostRef);
/**
* If `true`, the spinner's animation will be paused.
*/
this.paused = false;
}
getName() {
const spinnerName = this.name || config.get('spinner');
const mode = getIonMode$1(this);
if (spinnerName) {
return spinnerName;
}
return mode === 'ios' ? 'lines' : 'circular';
}
render() {
var _a;
const self = this;
const mode = getIonMode$1(self);
const spinnerName = self.getName();
const spinner = (_a = SPINNERS[spinnerName]) !== null && _a !== void 0 ? _a : SPINNERS['lines'];
const duration = typeof self.duration === 'number' && self.duration > 10 ? self.duration : spinner.dur;
const svgs = [];
if (spinner.circles !== undefined) {
for (let i = 0; i < spinner.circles; i++) {
svgs.push(buildCircle(spinner, duration, i, spinner.circles));
}
}
else if (spinner.lines !== undefined) {
for (let i = 0; i < spinner.lines; i++) {
svgs.push(buildLine(spinner, duration, i, spinner.lines));
}
}
return (hAsync(Host, { key: 'a33d6421fcc885995fbc7a348516525f68ca496c', class: createColorClasses$1(self.color, {
[mode]: true,
[`spinner-${spinnerName}`]: true,
'spinner-paused': self.paused || config.getBoolean('_testing'),
}), role: "progressbar", style: spinner.elmDuration ? { animationDuration: duration + 'ms' } : {} }, svgs));
}
static get style() { return spinnerCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-spinner",
"$members$": {
"color": [513],
"duration": [2],
"name": [1],
"paused": [4]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const buildCircle = (spinner, duration, index, total) => {
const data = spinner.fn(duration, index, total);
data.style['animation-duration'] = duration + 'ms';
return (hAsync("svg", { viewBox: data.viewBox || '0 0 64 64', style: data.style }, hAsync("circle", { transform: data.transform || 'translate(32,32)', cx: data.cx, cy: data.cy, r: data.r, style: spinner.elmDuration ? { animationDuration: duration + 'ms' } : {} })));
};
const buildLine = (spinner, duration, index, total) => {
const data = spinner.fn(duration, index, total);
data.style['animation-duration'] = duration + 'ms';
return (hAsync("svg", { viewBox: data.viewBox || '0 0 64 64', style: data.style }, hAsync("line", { transform: "translate(32,32)", y1: data.y1, y2: data.y2 })));
};
const splitPaneIosCss = ":host{--side-width:100%;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;contain:strict}:host(.split-pane-visible) ::slotted(.split-pane-main){left:0;right:0;top:0;bottom:0;position:relative;-ms-flex:1;flex:1;-webkit-box-shadow:none;box-shadow:none;overflow:hidden;z-index:0}::slotted(.split-pane-side:not(ion-menu)){display:none}:host{--border:0.55px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));--side-min-width:270px;--side-max-width:28%}";
const splitPaneMdCss = ":host{--side-width:100%;left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:nowrap;flex-wrap:nowrap;contain:strict}:host(.split-pane-visible) ::slotted(.split-pane-main){left:0;right:0;top:0;bottom:0;position:relative;-ms-flex:1;flex:1;-webkit-box-shadow:none;box-shadow:none;overflow:hidden;z-index:0}::slotted(.split-pane-side:not(ion-menu)){display:none}:host{--border:1px solid var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));--side-min-width:270px;--side-max-width:28%}";
const QUERY = {
lg: '(min-width: 992px)'};
class SplitPane {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionSplitPaneVisible = createEvent(this, "ionSplitPaneVisible", 7);
this.visible = false;
/**
* If `true`, the split pane will be hidden.
*/
this.disabled = false;
/**
* When the split-pane should be shown.
* Can be a CSS media query expression, or a shortcut expression.
* Can also be a boolean expression.
*/
this.when = QUERY['lg'];
}
visibleChanged(visible) {
this.ionSplitPaneVisible.emit({ visible });
}
/**
* @internal
*/
async isVisible() {
return Promise.resolve(this.visible);
}
async connectedCallback() {
// TODO: connectedCallback is fired in CE build
// before WC is defined. This needs to be fixed in Stencil.
if (typeof customElements !== 'undefined' && customElements != null) {
await customElements.whenDefined('ion-split-pane');
}
this.styleMainElement();
this.updateState();
}
disconnectedCallback() {
if (this.rmL) {
this.rmL();
this.rmL = undefined;
}
}
updateState() {
{
return;
}
}
/**
* Attempt to find the main content
* element inside of the split pane.
* If found, set it as the main node.
*
* We assume that the main node
* is available in the DOM on split
* pane load.
*/
styleMainElement() {
{
return;
}
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: 'd5e30df12f1f1f855da4c66f98076b9dce762c59', class: {
[mode]: true,
// Used internally for styling
[`split-pane-${mode}`]: true,
'split-pane-visible': this.visible,
} }, hAsync("slot", { key: '3e30d7cf3bc1cf434e16876a0cb2a36377b8e00f' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"visible": ["visibleChanged"],
"disabled": ["updateState"],
"when": ["updateState"]
}; }
static get style() { return {
ios: splitPaneIosCss,
md: splitPaneMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-split-pane",
"$members$": {
"contentId": [513, "content-id"],
"disabled": [4],
"when": [8],
"visible": [32],
"isVisible": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["contentId", "content-id"]]
}; }
}
const tabCss = ":host(.tab-hidden){display:none !important}";
class Tab {
constructor(hostRef) {
registerInstance(this, hostRef);
this.loaded = false;
/** @internal */
this.active = false;
}
async componentWillLoad() {
if (this.active) {
await this.setActive();
}
}
/** Set the active component for the tab */
async setActive() {
await this.prepareLazyLoaded();
this.active = true;
}
changeActive(isActive) {
if (isActive) {
this.prepareLazyLoaded();
}
}
prepareLazyLoaded() {
if (!this.loaded && this.component != null) {
this.loaded = true;
try {
return attachComponent(this.delegate, this.el, this.component, ['ion-page']);
}
catch (e) {
printIonError('[ion-tab] - Exception in prepareLazyLoaded:', e);
}
}
return Promise.resolve(undefined);
}
render() {
const { tab, active, component } = this;
return (hAsync(Host, { key: 'dbad8fe9f1566277d14647626308eaf1601ab01f', role: "tabpanel", "aria-hidden": !active ? 'true' : null, "aria-labelledby": `tab-button-${tab}`, class: {
'ion-page': component === undefined,
'tab-hidden': !active,
} }, hAsync("slot", { key: '3be64f4e7161f6769aaf8e4dcb5293fcaa09af45' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"active": ["changeActive"]
}; }
static get style() { return tabCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-tab",
"$members$": {
"active": [1028],
"delegate": [16],
"tab": [1],
"component": [1],
"setActive": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const tabBarIosCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-right:var(--ion-safe-area-right);padding-bottom:var(--ion-safe-area-bottom, 0);padding-left:var(--ion-safe-area-left);border-top:var(--border);background:var(--background);color:var(--color);text-align:center;contain:strict;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:10;-webkit-box-sizing:content-box !important;box-sizing:content-box !important}:host(.ion-color) ::slotted(ion-tab-button){--background-focused:var(--ion-color-shade);--color-selected:var(--ion-color-contrast)}:host(.ion-color) ::slotted(.tab-selected){color:var(--ion-color-contrast)}:host(.ion-color),:host(.ion-color) ::slotted(ion-tab-button){color:rgba(var(--ion-color-contrast-rgb), 0.7)}:host(.ion-color),:host(.ion-color) ::slotted(ion-tab-button){background:var(--ion-color-base)}:host(.ion-color) ::slotted(ion-tab-button.ion-focused),:host(.tab-bar-translucent) ::slotted(ion-tab-button.ion-focused){background:var(--background-focused)}:host(.tab-bar-translucent) ::slotted(ion-tab-button){background:transparent}:host([slot=top]){padding-top:var(--ion-safe-area-top, 0);padding-bottom:0;border-top:0;border-bottom:var(--border)}:host(.tab-bar-hidden){display:none !important}:host{--background:var(--ion-tab-bar-background, var(--ion-color-step-50, var(--ion-background-color-step-50, #f7f7f7)));--background-focused:var(--ion-tab-bar-background-focused, #e0e0e0);--border:0.55px solid var(--ion-tab-bar-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.2)))));--color:var(--ion-tab-bar-color, var(--ion-color-step-600, var(--ion-text-color-step-400, #666666)));--color-selected:var(--ion-tab-bar-color-selected, var(--ion-color-primary, #0054e9));height:50px}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.tab-bar-translucent){--background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8);-webkit-backdrop-filter:saturate(210%) blur(20px);backdrop-filter:saturate(210%) blur(20px)}:host(.ion-color.tab-bar-translucent){background:rgba(var(--ion-color-base-rgb), 0.8)}:host(.tab-bar-translucent) ::slotted(ion-tab-button.ion-focused){background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.6)}}";
const tabBarMdCss = ":host{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;width:auto;padding-right:var(--ion-safe-area-right);padding-bottom:var(--ion-safe-area-bottom, 0);padding-left:var(--ion-safe-area-left);border-top:var(--border);background:var(--background);color:var(--color);text-align:center;contain:strict;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:10;-webkit-box-sizing:content-box !important;box-sizing:content-box !important}:host(.ion-color) ::slotted(ion-tab-button){--background-focused:var(--ion-color-shade);--color-selected:var(--ion-color-contrast)}:host(.ion-color) ::slotted(.tab-selected){color:var(--ion-color-contrast)}:host(.ion-color),:host(.ion-color) ::slotted(ion-tab-button){color:rgba(var(--ion-color-contrast-rgb), 0.7)}:host(.ion-color),:host(.ion-color) ::slotted(ion-tab-button){background:var(--ion-color-base)}:host(.ion-color) ::slotted(ion-tab-button.ion-focused),:host(.tab-bar-translucent) ::slotted(ion-tab-button.ion-focused){background:var(--background-focused)}:host(.tab-bar-translucent) ::slotted(ion-tab-button){background:transparent}:host([slot=top]){padding-top:var(--ion-safe-area-top, 0);padding-bottom:0;border-top:0;border-bottom:var(--border)}:host(.tab-bar-hidden){display:none !important}:host{--background:var(--ion-tab-bar-background, var(--ion-background-color, #fff));--background-focused:var(--ion-tab-bar-background-focused, #e0e0e0);--border:1px solid var(--ion-tab-bar-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.07)))));--color:var(--ion-tab-bar-color, var(--ion-color-step-650, var(--ion-text-color-step-350, #595959)));--color-selected:var(--ion-tab-bar-color-selected, var(--ion-color-primary, #0054e9));height:56px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class TabBar {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionTabBarChanged = createEvent(this, "ionTabBarChanged", 7);
this.ionTabBarLoaded = createEvent(this, "ionTabBarLoaded", 7);
this.keyboardCtrl = null;
this.didLoad = false;
this.keyboardVisible = false;
/**
* If `true`, the tab bar will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
}
selectedTabChanged() {
// Skip the initial watcher call that happens during component load
// We handle that in componentDidLoad to ensure children are ready
if (!this.didLoad) {
return;
}
if (this.selectedTab !== undefined) {
this.ionTabBarChanged.emit({
tab: this.selectedTab,
});
}
}
componentDidLoad() {
this.ionTabBarLoaded.emit();
// Set the flag to indicate the component has loaded
// This allows the watcher to emit changes from this point forward
this.didLoad = true;
// Emit the initial selected tab after the component is fully loaded
// This ensures all child components (ion-tab-button) are ready
if (this.selectedTab !== undefined) {
this.ionTabBarChanged.emit({
tab: this.selectedTab,
});
}
}
async connectedCallback() {
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
/**
* If the keyboard is hiding, then we need to wait
* for the webview to resize. Otherwise, the tab bar
* will flicker before the webview resizes.
*/
if (keyboardOpen === false && waitForResize !== undefined) {
await waitForResize;
}
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
});
}
disconnectedCallback() {
if (this.keyboardCtrl) {
this.keyboardCtrl.destroy();
}
}
render() {
const { color, translucent, keyboardVisible } = this;
const mode = getIonMode$1(this);
const shouldHide = keyboardVisible && this.el.getAttribute('slot') !== 'top';
return (hAsync(Host, { key: '388ec37ce308035bab78d6c9a016bb616e9517a9', role: "tablist", "aria-hidden": shouldHide ? 'true' : null, class: createColorClasses$1(color, {
[mode]: true,
'tab-bar-translucent': translucent,
'tab-bar-hidden': shouldHide,
}) }, hAsync("slot", { key: 'ce10ade2b86725e24f3254516483eeedd8ecb16a' })));
}
get el() { return getElement(this); }
static get watchers() { return {
"selectedTab": ["selectedTabChanged"]
}; }
static get style() { return {
ios: tabBarIosCss,
md: tabBarMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-tab-bar",
"$members$": {
"color": [513],
"selectedTab": [1, "selected-tab"],
"translucent": [4],
"keyboardVisible": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const tabButtonIosCss = ":host{--ripple-color:var(--color-selected);--background-focused-opacity:1;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;height:100%;outline:none;background:var(--background);color:var(--color)}.button-native{border-radius:inherit;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:100%;height:100%;border:0;outline:none;background:transparent;text-decoration:none;cursor:pointer;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-drag:none}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:inherit;flex-flow:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:100%;height:100%;z-index:1}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}@media (any-hover: hover){a:hover{color:var(--color-selected)}}:host(.tab-selected){color:var(--color-selected)}:host(.tab-hidden){display:none !important}:host(.tab-disabled){pointer-events:none;opacity:0.4}::slotted(ion-label),::slotted(ion-icon){display:block;-ms-flex-item-align:center;align-self:center;max-width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}::slotted(ion-label){-ms-flex-order:0;order:0}::slotted(ion-icon){-ms-flex-order:-1;order:-1;height:1em}:host(.tab-has-label-only) ::slotted(ion-label){white-space:normal}::slotted(ion-badge){-webkit-box-sizing:border-box;box-sizing:border-box;position:absolute;z-index:1}:host(.tab-layout-icon-start){-ms-flex-direction:row;flex-direction:row}:host(.tab-layout-icon-end){-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.tab-layout-icon-bottom){-ms-flex-direction:column-reverse;flex-direction:column-reverse}:host(.tab-layout-icon-hide) ::slotted(ion-icon){display:none}:host(.tab-layout-label-hide) ::slotted(ion-label){display:none}ion-ripple-effect{color:var(--ripple-color)}:host{--padding-top:0;--padding-end:2px;--padding-bottom:0;--padding-start:2px;max-width:240px;font-size:10px}::slotted(ion-badge){-webkit-padding-start:6px;padding-inline-start:6px;-webkit-padding-end:6px;padding-inline-end:6px;padding-top:1px;padding-bottom:1px;top:4px;height:auto;font-size:12px;line-height:16px}::slotted(ion-badge){inset-inline-start:calc(50% + 6px)}::slotted(ion-icon){margin-top:2px;margin-bottom:2px;font-size:24px}::slotted(ion-icon::before){vertical-align:top}::slotted(ion-label){margin-top:0;margin-bottom:1px;min-height:11px;font-weight:500}:host(.tab-has-label-only) ::slotted(ion-label){margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;font-size:12px;font-size:14px;line-height:1.1}:host(.tab-layout-icon-end) ::slotted(ion-label),:host(.tab-layout-icon-start) ::slotted(ion-label),:host(.tab-layout-icon-hide) ::slotted(ion-label){margin-top:2px;margin-bottom:2px;font-size:14px;line-height:1.1}:host(.tab-layout-icon-end) ::slotted(ion-icon),:host(.tab-layout-icon-start) ::slotted(ion-icon){min-width:24px;height:26px;margin-top:2px;margin-bottom:1px;font-size:24px}:host(.tab-layout-icon-bottom) ::slotted(ion-badge){inset-inline-start:calc(50% + 12px)}:host(.tab-layout-icon-bottom) ::slotted(ion-icon){margin-top:0;margin-bottom:1px}:host(.tab-layout-icon-bottom) ::slotted(ion-label){margin-top:4px}:host(.tab-layout-icon-start) ::slotted(ion-badge),:host(.tab-layout-icon-end) ::slotted(ion-badge){top:10px}:host(.tab-layout-icon-start) ::slotted(ion-badge),:host(.tab-layout-icon-end) ::slotted(ion-badge){inset-inline-start:calc(50% + 35px)}:host(.tab-layout-icon-hide) ::slotted(ion-badge),:host(.tab-has-label-only) ::slotted(ion-badge){top:10px}:host(.tab-layout-icon-hide) ::slotted(ion-badge),:host(.tab-has-label-only) ::slotted(ion-badge){inset-inline-start:calc(50% + 30px)}:host(.tab-layout-label-hide) ::slotted(ion-badge),:host(.tab-has-icon-only) ::slotted(ion-badge){top:10px}:host(.tab-layout-label-hide) ::slotted(ion-icon){margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}:host(.tab-layout-label-hide) ::slotted(ion-icon),:host(.tab-has-icon-only) ::slotted(ion-icon){font-size:30px}";
const tabButtonMdCss = ":host{--ripple-color:var(--color-selected);--background-focused-opacity:1;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;height:100%;outline:none;background:var(--background);color:var(--color)}.button-native{border-radius:inherit;margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;text-align:inherit;white-space:inherit;color:inherit;display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:inherit;flex-direction:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:100%;height:100%;border:0;outline:none;background:transparent;text-decoration:none;cursor:pointer;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-drag:none}.button-native::after{left:0;right:0;top:0;bottom:0;position:absolute;content:\"\";opacity:0}.button-inner{display:-ms-flexbox;display:flex;position:relative;-ms-flex-flow:inherit;flex-flow:inherit;-ms-flex-align:inherit;align-items:inherit;-ms-flex-pack:inherit;justify-content:inherit;width:100%;height:100%;z-index:1}:host(.ion-focused) .button-native{color:var(--color-focused)}:host(.ion-focused) .button-native::after{background:var(--background-focused);opacity:var(--background-focused-opacity)}@media (any-hover: hover){a:hover{color:var(--color-selected)}}:host(.tab-selected){color:var(--color-selected)}:host(.tab-hidden){display:none !important}:host(.tab-disabled){pointer-events:none;opacity:0.4}::slotted(ion-label),::slotted(ion-icon){display:block;-ms-flex-item-align:center;align-self:center;max-width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box}::slotted(ion-label){-ms-flex-order:0;order:0}::slotted(ion-icon){-ms-flex-order:-1;order:-1;height:1em}:host(.tab-has-label-only) ::slotted(ion-label){white-space:normal}::slotted(ion-badge){-webkit-box-sizing:border-box;box-sizing:border-box;position:absolute;z-index:1}:host(.tab-layout-icon-start){-ms-flex-direction:row;flex-direction:row}:host(.tab-layout-icon-end){-ms-flex-direction:row-reverse;flex-direction:row-reverse}:host(.tab-layout-icon-bottom){-ms-flex-direction:column-reverse;flex-direction:column-reverse}:host(.tab-layout-icon-hide) ::slotted(ion-icon){display:none}:host(.tab-layout-label-hide) ::slotted(ion-label){display:none}ion-ripple-effect{color:var(--ripple-color)}:host{--padding-top:0;--padding-end:12px;--padding-bottom:0;--padding-start:12px;max-width:168px;font-size:12px;font-weight:normal;letter-spacing:0.03em}::slotted(ion-label){margin-left:0;margin-right:0;margin-top:2px;margin-bottom:2px;text-transform:none}::slotted(ion-icon){margin-left:0;margin-right:0;margin-top:16px;margin-bottom:16px;-webkit-transform-origin:center center;transform-origin:center center;font-size:22px}:host-context([dir=rtl]) ::slotted(ion-icon){-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}[dir=rtl] ::slotted(ion-icon){-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}@supports selector(:dir(rtl)){::slotted(ion-icon):dir(rtl){-webkit-transform-origin:calc(100% - center) center;transform-origin:calc(100% - center) center}}::slotted(ion-badge){border-radius:8px;-webkit-padding-start:2px;padding-inline-start:2px;-webkit-padding-end:2px;padding-inline-end:2px;padding-top:3px;padding-bottom:2px;top:8px;min-width:12px;font-size:8px;font-weight:normal}::slotted(ion-badge){inset-inline-start:calc(50% + 6px)}::slotted(ion-badge:empty){display:block;min-width:8px;height:8px}:host(.tab-layout-icon-top) ::slotted(ion-icon){margin-top:6px;margin-bottom:2px}:host(.tab-layout-icon-top) ::slotted(ion-label){margin-top:0;margin-bottom:6px}:host(.tab-layout-icon-bottom) ::slotted(ion-badge){top:8px}:host(.tab-layout-icon-bottom) ::slotted(ion-badge){inset-inline-start:70%}:host(.tab-layout-icon-bottom) ::slotted(ion-icon){margin-top:0;margin-bottom:6px}:host(.tab-layout-icon-bottom) ::slotted(ion-label){margin-top:6px;margin-bottom:0}:host(.tab-layout-icon-start) ::slotted(ion-badge),:host(.tab-layout-icon-end) ::slotted(ion-badge){top:16px}:host(.tab-layout-icon-start) ::slotted(ion-badge),:host(.tab-layout-icon-end) ::slotted(ion-badge){inset-inline-start:80%}:host(.tab-layout-icon-start) ::slotted(ion-icon){-webkit-margin-end:6px;margin-inline-end:6px}:host(.tab-layout-icon-end) ::slotted(ion-icon){-webkit-margin-start:6px;margin-inline-start:6px}:host(.tab-layout-icon-hide) ::slotted(ion-badge),:host(.tab-has-label-only) ::slotted(ion-badge){top:16px}:host(.tab-layout-icon-hide) ::slotted(ion-badge),:host(.tab-has-label-only) ::slotted(ion-badge){inset-inline-start:70%}:host(.tab-layout-icon-hide) ::slotted(ion-label),:host(.tab-has-label-only) ::slotted(ion-label){margin-top:0;margin-bottom:0}:host(.tab-layout-label-hide) ::slotted(ion-badge),:host(.tab-has-icon-only) ::slotted(ion-badge){top:16px}:host(.tab-layout-label-hide) ::slotted(ion-icon),:host(.tab-has-icon-only) ::slotted(ion-icon){margin-top:0;margin-bottom:0;font-size:24px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part native - The native HTML anchor element that wraps all child elements.
*/
class TabButton {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionTabButtonClick = createEvent(this, "ionTabButtonClick", 7);
this.inheritedAttributes = {};
/**
* If `true`, the user cannot interact with the tab button.
*/
this.disabled = false;
/**
* The selected tab component
*/
this.selected = false;
this.onKeyUp = (ev) => {
if (ev.key === 'Enter' || ev.key === ' ') {
this.selectTab(ev);
}
};
this.onClick = (ev) => {
this.selectTab(ev);
};
}
onTabBarChanged(ev) {
const dispatchedFrom = ev.target;
const parent = this.el.parentElement;
if (ev.composedPath().includes(parent) || (dispatchedFrom === null || dispatchedFrom === void 0 ? void 0 : dispatchedFrom.contains(this.el))) {
this.selected = this.tab === ev.detail.tab;
}
}
componentWillLoad() {
this.inheritedAttributes = Object.assign({}, inheritAttributes$1(this.el, ['aria-label']));
if (this.layout === undefined) {
this.layout = config.get('tabButtonLayout', 'icon-top');
}
}
selectTab(ev) {
if (this.tab !== undefined) {
if (!this.disabled) {
this.ionTabButtonClick.emit({
tab: this.tab,
href: this.href,
selected: this.selected,
});
}
ev.preventDefault();
}
}
get hasLabel() {
return !!this.el.querySelector('ion-label');
}
get hasIcon() {
return !!this.el.querySelector('ion-icon');
}
render() {
const { disabled, hasIcon, hasLabel, href, rel, target, layout, selected, tab, inheritedAttributes } = this;
const mode = getIonMode$1(this);
const attrs = {
download: this.download,
href,
rel,
target,
};
return (hAsync(Host, { key: 'ce9d29ced0c781d6b2fa62cd5feb801c11fc42e8', onClick: this.onClick, onKeyup: this.onKeyUp, id: tab !== undefined ? `tab-button-${tab}` : null, class: {
[mode]: true,
'tab-selected': selected,
'tab-disabled': disabled,
'tab-has-label': hasLabel,
'tab-has-icon': hasIcon,
'tab-has-label-only': hasLabel && !hasIcon,
'tab-has-icon-only': hasIcon && !hasLabel,
[`tab-layout-${layout}`]: true,
'ion-activatable': true,
'ion-selectable': true,
'ion-focusable': true,
} }, hAsync("a", Object.assign({ key: '01cb0ed2e77c5c1a8abd48da1bb07ac1b305d0b6' }, attrs, { class: "button-native", part: "native", role: "tab", "aria-selected": selected ? 'true' : null, "aria-disabled": disabled ? 'true' : null, tabindex: disabled ? '-1' : undefined }, inheritedAttributes), hAsync("span", { key: 'd0240c05f42217cfb186b86ff8a0c9cd70b9c8df', class: "button-inner" }, hAsync("slot", { key: '0a20b84925037dbaa8bb4a495b813d3f7c2e58ac' })), mode === 'md' && hAsync("ion-ripple-effect", { key: '4c92c27178cdac89d69cffef8d2c39c3644914e8', type: "unbounded" }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: tabButtonIosCss,
md: tabButtonMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-tab-button",
"$members$": {
"disabled": [4],
"download": [1],
"href": [1],
"rel": [1],
"layout": [1025],
"selected": [1028],
"tab": [1],
"target": [1]
},
"$listeners$": [[8, "ionTabBarChanged", "onTabBarChanged"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const tabsCss = ":host{left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;-ms-flex-direction:column;flex-direction:column;width:100%;height:100%;contain:layout size style;z-index:0}.tabs-inner{position:relative;-ms-flex:1;flex:1;contain:layout size style}";
/**
* @slot - Content is placed between the named slots if provided without a slot.
* @slot top - Content is placed at the top of the screen.
* @slot bottom - Content is placed at the bottom of the screen.
*/
class Tabs {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionNavWillLoad = createEvent(this, "ionNavWillLoad", 7);
this.ionTabsWillChange = createEvent(this, "ionTabsWillChange", 3);
this.ionTabsDidChange = createEvent(this, "ionTabsDidChange", 3);
this.transitioning = false;
/** @internal */
this.useRouter = false;
this.onTabClicked = (ev) => {
const { href, tab } = ev.detail;
if (this.useRouter && href !== undefined) {
const router = document.querySelector('ion-router');
if (router) {
router.push(href);
}
}
else {
this.select(tab);
}
};
}
async componentWillLoad() {
if (!this.useRouter) {
/**
* JavaScript and StencilJS use `ion-router`, while
* the other frameworks use `ion-router-outlet`.
*
* If either component is present then tabs will not use
* a basic tab-based navigation. It will use the history
* stack or URL updates associated with the router.
*/
this.useRouter =
(!!this.el.querySelector('ion-router-outlet') || !!document.querySelector('ion-router')) &&
!this.el.closest('[no-router]');
}
if (!this.useRouter) {
const tabs = this.tabs;
if (tabs.length > 0) {
await this.select(tabs[0]);
}
}
this.ionNavWillLoad.emit();
}
componentDidLoad() {
this.updateTabBar();
}
componentDidUpdate() {
this.updateTabBar();
}
updateTabBar() {
const tabBar = this.el.querySelector('ion-tab-bar');
if (!tabBar) {
return;
}
const tab = this.selectedTab ? this.selectedTab.tab : undefined;
// If tabs has no selected tab but tab-bar already has a selected-tab set,
// don't overwrite it. This handles cases where tab-bar is used without ion-tab elements.
if (tab === undefined) {
return;
}
if (tabBar.selectedTab === tab) {
return;
}
tabBar.selectedTab = tab;
}
/**
* Select a tab by the value of its `tab` property or an element reference. This method is only available for vanilla JavaScript projects. The Angular, React, and Vue implementations of tabs are coupled to each framework's router.
*
* @param tab The tab instance to select. If passed a string, it should be the value of the tab's `tab` property.
*/
async select(tab) {
const selectedTab = getTab(this.tabs, tab);
if (!this.shouldSwitch(selectedTab)) {
return false;
}
await this.setActive(selectedTab);
await this.notifyRouter();
this.tabSwitch();
return true;
}
/**
* Get a specific tab by the value of its `tab` property or an element reference. This method is only available for vanilla JavaScript projects. The Angular, React, and Vue implementations of tabs are coupled to each framework's router.
*
* @param tab The tab instance to select. If passed a string, it should be the value of the tab's `tab` property.
*/
async getTab(tab) {
return getTab(this.tabs, tab);
}
/**
* Get the currently selected tab. This method is only available for vanilla JavaScript projects. The Angular, React, and Vue implementations of tabs are coupled to each framework's router.
*/
getSelected() {
return Promise.resolve(this.selectedTab ? this.selectedTab.tab : undefined);
}
/** @internal */
async setRouteId(id) {
const selectedTab = getTab(this.tabs, id);
if (!this.shouldSwitch(selectedTab)) {
return { changed: false, element: this.selectedTab };
}
await this.setActive(selectedTab);
return {
changed: true,
element: this.selectedTab,
markVisible: () => this.tabSwitch(),
};
}
/** @internal */
async getRouteId() {
var _a;
const tabId = (_a = this.selectedTab) === null || _a === void 0 ? void 0 : _a.tab;
return tabId !== undefined ? { id: tabId, element: this.selectedTab } : undefined;
}
setActive(selectedTab) {
if (this.transitioning) {
return Promise.reject('transitioning already happening');
}
this.transitioning = true;
this.leavingTab = this.selectedTab;
this.selectedTab = selectedTab;
this.ionTabsWillChange.emit({ tab: selectedTab.tab });
selectedTab.active = true;
this.updateTabBar();
return Promise.resolve();
}
tabSwitch() {
const selectedTab = this.selectedTab;
const leavingTab = this.leavingTab;
this.leavingTab = undefined;
this.transitioning = false;
if (!selectedTab) {
return;
}
if (leavingTab !== selectedTab) {
if (leavingTab) {
leavingTab.active = false;
}
this.ionTabsDidChange.emit({ tab: selectedTab.tab });
}
}
notifyRouter() {
if (this.useRouter) {
const router = document.querySelector('ion-router');
if (router) {
return router.navChanged('forward');
}
}
return Promise.resolve(false);
}
shouldSwitch(selectedTab) {
const leavingTab = this.selectedTab;
return selectedTab !== undefined && selectedTab !== leavingTab && !this.transitioning;
}
get tabs() {
return Array.from(this.el.querySelectorAll('ion-tab'));
}
render() {
return (hAsync(Host, { key: '7b4b302f2942d8d131f6fc24e817989a8be08867', onIonTabButtonClick: this.onTabClicked }, hAsync("slot", { key: '2c51cf14c0f17a8ddf2d879858c984cdf8fd3147', name: "top" }), hAsync("div", { key: '7e9d6055092d41bd9bc80ae15965f77e216feb84', class: "tabs-inner" }, hAsync("slot", { key: 'c308a787e37ff7f6653531d70deca597a7602d26' })), hAsync("slot", { key: 'd5f5e693710c853570811602f859cf3e88272684', name: "bottom" })));
}
get el() { return getElement(this); }
static get style() { return tabsCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-tabs",
"$members$": {
"useRouter": [1028, "use-router"],
"selectedTab": [32],
"select": [64],
"getTab": [64],
"getSelected": [64],
"setRouteId": [64],
"getRouteId": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
const getTab = (tabs, tab) => {
const tabEl = typeof tab === 'string' ? tabs.find((t) => t.tab === tab) : tab;
if (!tabEl) {
printIonError(`[ion-tabs] - Tab with id: "${tabEl}" does not exist`);
}
return tabEl;
};
const textCss = ":host(.ion-color){color:var(--ion-color-base)}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*/
class Text {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
const mode = getIonMode$1(this);
return (hAsync(Host, { key: '361035eae7b92dc109794348d39bad2f596eb6be', class: createColorClasses$1(this.color, {
[mode]: true,
}) }, hAsync("slot", { key: 'c7b8835cf485ba9ecd73298f0529276ce1ea0852' })));
}
static get style() { return textCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-text",
"$members$": {
"color": [513]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const textareaIosCss = ".sc-ion-textarea-ios-h{--background:initial;--color:initial;--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);--padding-top:0;--padding-end:0;--padding-bottom:8px;--padding-start:0;--border-radius:0;--border-style:solid;--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;width:100%;min-height:44px;color:var(--color);font-family:var(--ion-font-family, inherit);z-index:2;-webkit-box-sizing:border-box;box-sizing:border-box}.textarea-label-placement-floating.sc-ion-textarea-ios-h,.textarea-label-placement-stacked.sc-ion-textarea-ios-h{--padding-top:0px;min-height:56px}[cols].sc-ion-textarea-ios-h:not([auto-grow]){width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.ion-color.sc-ion-textarea-ios-h{--highlight-color-focused:var(--ion-color-base);background:initial}ion-item.sc-ion-textarea-ios-h,ion-item .sc-ion-textarea-ios-h{-ms-flex-item-align:baseline;align-self:baseline}ion-item[slot=start].sc-ion-textarea-ios-h,ion-item [slot=start].sc-ion-textarea-ios-h,ion-item[slot=end].sc-ion-textarea-ios-h,ion-item [slot=end].sc-ion-textarea-ios-h{width:auto}.native-textarea.sc-ion-textarea-ios{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:block;position:relative;-ms-flex:1;flex:1;width:100%;max-width:100%;max-height:100%;border:0;outline:none;background:transparent;white-space:pre-wrap;z-index:1;-webkit-box-sizing:border-box;box-sizing:border-box;resize:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.native-textarea.sc-ion-textarea-ios::-webkit-input-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-ios::-moz-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-ios:-ms-input-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-ios::-ms-input-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-ios::placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-ios{color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-align:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;grid-area:1/1/2/2;word-break:break-word}.cloned-input.sc-ion-textarea-ios{top:0;bottom:0;position:absolute;pointer-events:none}.cloned-input.sc-ion-textarea-ios{inset-inline-start:0}.cloned-input.sc-ion-textarea-ios:disabled{opacity:1}[auto-grow].sc-ion-textarea-ios-h .cloned-input.sc-ion-textarea-ios{height:100%}[auto-grow].sc-ion-textarea-ios-h .native-textarea.sc-ion-textarea-ios{overflow:hidden}.textarea-wrapper.sc-ion-textarea-ios{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:0px;padding-bottom:0px;border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:start;align-items:flex-start;height:inherit;min-height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;background:var(--background);line-height:normal}.native-wrapper.sc-ion-textarea-ios{position:relative;width:100%;height:100%}.has-focus.sc-ion-textarea-ios-h textarea.sc-ion-textarea-ios{caret-color:var(--highlight-color)}.native-wrapper.sc-ion-textarea-ios textarea.sc-ion-textarea-ios{-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom)}.native-wrapper.sc-ion-textarea-ios{display:grid;min-width:inherit;max-width:inherit;min-height:inherit;max-height:inherit;grid-auto-rows:100%}.native-wrapper.sc-ion-textarea-ios::after{white-space:pre-wrap;content:attr(data-replicated-value) \" \";visibility:hidden}.native-wrapper.sc-ion-textarea-ios::after{padding-left:0;padding-right:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;border-radius:var(--border-radius);color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-align:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;grid-area:1/1/2/2;word-break:break-word}.textarea-wrapper-inner.sc-ion-textarea-ios{display:-ms-flexbox;display:flex;width:100%;min-height:inherit}.ion-touched.ion-invalid.sc-ion-textarea-ios-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-textarea-ios-h{--highlight-color:var(--highlight-color-valid)}.textarea-bottom.sc-ion-textarea-ios{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:5px;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-top:var(--border-width) var(--border-style) var(--border-color);font-size:0.75rem;white-space:normal}.has-focus.ion-valid.sc-ion-textarea-ios-h,.ion-touched.ion-invalid.sc-ion-textarea-ios-h{--border-color:var(--highlight-color)}.textarea-bottom.sc-ion-textarea-ios .error-text.sc-ion-textarea-ios{display:none;color:var(--highlight-color-invalid)}.textarea-bottom.sc-ion-textarea-ios .helper-text.sc-ion-textarea-ios{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid.sc-ion-textarea-ios-h .textarea-bottom.sc-ion-textarea-ios .error-text.sc-ion-textarea-ios{display:block}.ion-touched.ion-invalid.sc-ion-textarea-ios-h .textarea-bottom.sc-ion-textarea-ios .helper-text.sc-ion-textarea-ios{display:none}.textarea-bottom.sc-ion-textarea-ios .counter.sc-ion-textarea-ios{-webkit-margin-start:auto;margin-inline-start:auto;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));white-space:nowrap;-webkit-padding-start:16px;padding-inline-start:16px}.label-text-wrapper.sc-ion-textarea-ios{-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);max-width:200px;-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.label-text.sc-ion-textarea-ios,.sc-ion-textarea-ios-s>[slot=label]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden.sc-ion-textarea-ios,.textarea-outline-notch-hidden.sc-ion-textarea-ios{display:none}.textarea-wrapper.sc-ion-textarea-ios textarea.sc-ion-textarea-ios{-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.textarea-label-placement-start.sc-ion-textarea-ios-h .textarea-wrapper.sc-ion-textarea-ios{-ms-flex-direction:row;flex-direction:row}.textarea-label-placement-start.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.textarea-label-placement-end.sc-ion-textarea-ios-h .textarea-wrapper.sc-ion-textarea-ios{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.textarea-label-placement-end.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}.textarea-label-placement-fixed.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.textarea-label-placement-fixed.sc-ion-textarea-ios-h .label-text.sc-ion-textarea-ios{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.textarea-label-placement-stacked.sc-ion-textarea-ios-h .textarea-wrapper.sc-ion-textarea-ios,.textarea-label-placement-floating.sc-ion-textarea-ios-h .textarea-wrapper.sc-ion-textarea-ios{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:start}.textarea-label-placement-stacked.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,.textarea-label-placement-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-transform-origin:left top;transform-origin:left top;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:0px;padding-bottom:0px;max-width:100%;z-index:2}[dir=rtl].sc-ion-textarea-ios-h -no-combinator.textarea-label-placement-stacked.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl] .sc-ion-textarea-ios-h -no-combinator.textarea-label-placement-stacked.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl].textarea-label-placement-stacked.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl] .textarea-label-placement-stacked.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl].sc-ion-textarea-ios-h -no-combinator.textarea-label-placement-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl] .sc-ion-textarea-ios-h -no-combinator.textarea-label-placement-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl].textarea-label-placement-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios,[dir=rtl] .textarea-label-placement-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.textarea-label-placement-stacked.sc-ion-textarea-ios-h:dir(rtl) .label-text-wrapper.sc-ion-textarea-ios,.textarea-label-placement-floating.sc-ion-textarea-ios-h:dir(rtl) .label-text-wrapper.sc-ion-textarea-ios{-webkit-transform-origin:right top;transform-origin:right top}}.textarea-label-placement-stacked.sc-ion-textarea-ios-h textarea.sc-ion-textarea-ios,.textarea-label-placement-floating.sc-ion-textarea-ios-h textarea.sc-ion-textarea-ios,.textarea-label-placement-stacked[auto-grow].sc-ion-textarea-ios-h .native-wrapper.sc-ion-textarea-ios::after,.textarea-label-placement-floating[auto-grow].sc-ion-textarea-ios-h .native-wrapper.sc-ion-textarea-ios::after{-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;margin-top:8px;margin-bottom:0px}.sc-ion-textarea-ios-h.textarea-label-placement-stacked.sc-ion-textarea-ios-s>[slot=start],.sc-ion-textarea-ios-h.textarea-label-placement-stacked .sc-ion-textarea-ios-s>[slot=start],.sc-ion-textarea-ios-h.textarea-label-placement-stacked.sc-ion-textarea-ios-s>[slot=end],.sc-ion-textarea-ios-h.textarea-label-placement-stacked .sc-ion-textarea-ios-s>[slot=end],.sc-ion-textarea-ios-h.textarea-label-placement-floating.sc-ion-textarea-ios-s>[slot=start],.sc-ion-textarea-ios-h.textarea-label-placement-floating .sc-ion-textarea-ios-s>[slot=start],.sc-ion-textarea-ios-h.textarea-label-placement-floating.sc-ion-textarea-ios-s>[slot=end],.sc-ion-textarea-ios-h.textarea-label-placement-floating .sc-ion-textarea-ios-s>[slot=end]{margin-top:8px}.textarea-label-placement-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-transform:translateY(100%) scale(1);transform:translateY(100%) scale(1)}.textarea-label-placement-floating.sc-ion-textarea-ios-h textarea.sc-ion-textarea-ios{opacity:0}.has-focus.textarea-label-placement-floating.sc-ion-textarea-ios-h textarea.sc-ion-textarea-ios,.has-value.textarea-label-placement-floating.sc-ion-textarea-ios-h textarea.sc-ion-textarea-ios{opacity:1}.label-floating.sc-ion-textarea-ios-h .label-text-wrapper.sc-ion-textarea-ios{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);max-width:calc(100% / 0.75)}.start-slot-wrapper.sc-ion-textarea-ios,.end-slot-wrapper.sc-ion-textarea-ios{padding-left:0;padding-right:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-negative:0;flex-shrink:0;-ms-flex-item-align:start;align-self:start}.sc-ion-textarea-ios-s>[slot=start],.sc-ion-textarea-ios-s>[slot=end]{margin-top:0}.sc-ion-textarea-ios-s>[slot=start]:last-of-type{-webkit-margin-end:16px;margin-inline-end:16px;-webkit-margin-start:0;margin-inline-start:0}.sc-ion-textarea-ios-s>[slot=end]:first-of-type{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}.sc-ion-textarea-ios-h{--border-width:0.55px;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));--padding-top:10px;--padding-end:0px;--padding-bottom:8px;--padding-start:0px;--highlight-height:0px;font-size:inherit}.textarea-disabled.sc-ion-textarea-ios-h{opacity:0.3}.sc-ion-textarea-ios-s>ion-button[slot=start].button-has-icon-only,.sc-ion-textarea-ios-s>ion-button[slot=end].button-has-icon-only{--border-radius:50%;--padding-start:0;--padding-end:0;--padding-top:0;--padding-bottom:0;aspect-ratio:1}";
const textareaMdCss = ".sc-ion-textarea-md-h{--background:initial;--color:initial;--placeholder-color:initial;--placeholder-font-style:initial;--placeholder-font-weight:initial;--placeholder-opacity:var(--ion-placeholder-opacity, 0.6);--padding-top:0;--padding-end:0;--padding-bottom:8px;--padding-start:0;--border-radius:0;--border-style:solid;--highlight-color-focused:var(--ion-color-primary, #0054e9);--highlight-color-valid:var(--ion-color-success, #2dd55b);--highlight-color-invalid:var(--ion-color-danger, #c5000f);--highlight-color:var(--highlight-color-focused);display:block;position:relative;width:100%;min-height:44px;color:var(--color);font-family:var(--ion-font-family, inherit);z-index:2;-webkit-box-sizing:border-box;box-sizing:border-box}.textarea-label-placement-floating.sc-ion-textarea-md-h,.textarea-label-placement-stacked.sc-ion-textarea-md-h{--padding-top:0px;min-height:56px}[cols].sc-ion-textarea-md-h:not([auto-grow]){width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.ion-color.sc-ion-textarea-md-h{--highlight-color-focused:var(--ion-color-base);background:initial}ion-item.sc-ion-textarea-md-h,ion-item .sc-ion-textarea-md-h{-ms-flex-item-align:baseline;align-self:baseline}ion-item[slot=start].sc-ion-textarea-md-h,ion-item [slot=start].sc-ion-textarea-md-h,ion-item[slot=end].sc-ion-textarea-md-h,ion-item [slot=end].sc-ion-textarea-md-h{width:auto}.native-textarea.sc-ion-textarea-md{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;display:block;position:relative;-ms-flex:1;flex:1;width:100%;max-width:100%;max-height:100%;border:0;outline:none;background:transparent;white-space:pre-wrap;z-index:1;-webkit-box-sizing:border-box;box-sizing:border-box;resize:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.native-textarea.sc-ion-textarea-md::-webkit-input-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-md::-moz-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-md:-ms-input-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-md::-ms-input-placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-md::placeholder{padding-left:0;padding-right:0;padding-top:0;padding-bottom:0;color:var(--placeholder-color);font-family:inherit;font-style:var(--placeholder-font-style);font-weight:var(--placeholder-font-weight);opacity:var(--placeholder-opacity)}.native-textarea.sc-ion-textarea-md{color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-align:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;grid-area:1/1/2/2;word-break:break-word}.cloned-input.sc-ion-textarea-md{top:0;bottom:0;position:absolute;pointer-events:none}.cloned-input.sc-ion-textarea-md{inset-inline-start:0}.cloned-input.sc-ion-textarea-md:disabled{opacity:1}[auto-grow].sc-ion-textarea-md-h .cloned-input.sc-ion-textarea-md{height:100%}[auto-grow].sc-ion-textarea-md-h .native-textarea.sc-ion-textarea-md{overflow:hidden}.textarea-wrapper.sc-ion-textarea-md{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:0px;padding-bottom:0px;border-radius:var(--border-radius);display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:start;align-items:flex-start;height:inherit;min-height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;background:var(--background);line-height:normal}.native-wrapper.sc-ion-textarea-md{position:relative;width:100%;height:100%}.has-focus.sc-ion-textarea-md-h textarea.sc-ion-textarea-md{caret-color:var(--highlight-color)}.native-wrapper.sc-ion-textarea-md textarea.sc-ion-textarea-md{-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom)}.native-wrapper.sc-ion-textarea-md{display:grid;min-width:inherit;max-width:inherit;min-height:inherit;max-height:inherit;grid-auto-rows:100%}.native-wrapper.sc-ion-textarea-md::after{white-space:pre-wrap;content:attr(data-replicated-value) \" \";visibility:hidden}.native-wrapper.sc-ion-textarea-md::after{padding-left:0;padding-right:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;border-radius:var(--border-radius);color:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;letter-spacing:inherit;text-align:inherit;text-decoration:inherit;text-indent:inherit;text-overflow:inherit;text-transform:inherit;grid-area:1/1/2/2;word-break:break-word}.textarea-wrapper-inner.sc-ion-textarea-md{display:-ms-flexbox;display:flex;width:100%;min-height:inherit}.ion-touched.ion-invalid.sc-ion-textarea-md-h{--highlight-color:var(--highlight-color-invalid)}.ion-valid.sc-ion-textarea-md-h{--highlight-color:var(--highlight-color-valid)}.textarea-bottom.sc-ion-textarea-md{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:5px;padding-bottom:0;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;border-top:var(--border-width) var(--border-style) var(--border-color);font-size:0.75rem;white-space:normal}.has-focus.ion-valid.sc-ion-textarea-md-h,.ion-touched.ion-invalid.sc-ion-textarea-md-h{--border-color:var(--highlight-color)}.textarea-bottom.sc-ion-textarea-md .error-text.sc-ion-textarea-md{display:none;color:var(--highlight-color-invalid)}.textarea-bottom.sc-ion-textarea-md .helper-text.sc-ion-textarea-md{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}.ion-touched.ion-invalid.sc-ion-textarea-md-h .textarea-bottom.sc-ion-textarea-md .error-text.sc-ion-textarea-md{display:block}.ion-touched.ion-invalid.sc-ion-textarea-md-h .textarea-bottom.sc-ion-textarea-md .helper-text.sc-ion-textarea-md{display:none}.textarea-bottom.sc-ion-textarea-md .counter.sc-ion-textarea-md{-webkit-margin-start:auto;margin-inline-start:auto;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));white-space:nowrap;-webkit-padding-start:16px;padding-inline-start:16px}.label-text-wrapper.sc-ion-textarea-md{-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);max-width:200px;-webkit-transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:color 150ms cubic-bezier(0.4, 0, 0.2, 1), transform 150ms cubic-bezier(0.4, 0, 0.2, 1), -webkit-transform 150ms cubic-bezier(0.4, 0, 0.2, 1);pointer-events:none}.label-text.sc-ion-textarea-md,.sc-ion-textarea-md-s>[slot=label]{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.label-text-wrapper-hidden.sc-ion-textarea-md,.textarea-outline-notch-hidden.sc-ion-textarea-md{display:none}.textarea-wrapper.sc-ion-textarea-md textarea.sc-ion-textarea-md{-webkit-transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);transition:opacity 150ms cubic-bezier(0.4, 0, 0.2, 1)}.textarea-label-placement-start.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md{-ms-flex-direction:row;flex-direction:row}.textarea-label-placement-start.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.textarea-label-placement-end.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md{-ms-flex-direction:row-reverse;flex-direction:row-reverse}.textarea-label-placement-end.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0;margin-top:0;margin-bottom:0}.textarea-label-placement-fixed.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px;margin-top:0;margin-bottom:0}.textarea-label-placement-fixed.sc-ion-textarea-md-h .label-text.sc-ion-textarea-md{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}.textarea-label-placement-stacked.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md,.textarea-label-placement-floating.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md{-ms-flex-direction:column;flex-direction:column;-ms-flex-align:start;align-items:start}.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform-origin:left top;transform-origin:left top;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;padding-top:0px;padding-bottom:0px;max-width:100%;z-index:2}[dir=rtl].sc-ion-textarea-md-h -no-combinator.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .sc-ion-textarea-md-h -no-combinator.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl].textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl].sc-ion-textarea-md-h -no-combinator.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .sc-ion-textarea-md-h -no-combinator.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl].textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.textarea-label-placement-stacked.sc-ion-textarea-md-h:dir(rtl) .label-text-wrapper.sc-ion-textarea-md,.textarea-label-placement-floating.sc-ion-textarea-md-h:dir(rtl) .label-text-wrapper.sc-ion-textarea-md{-webkit-transform-origin:right top;transform-origin:right top}}.textarea-label-placement-stacked.sc-ion-textarea-md-h textarea.sc-ion-textarea-md,.textarea-label-placement-floating.sc-ion-textarea-md-h textarea.sc-ion-textarea-md,.textarea-label-placement-stacked[auto-grow].sc-ion-textarea-md-h .native-wrapper.sc-ion-textarea-md::after,.textarea-label-placement-floating[auto-grow].sc-ion-textarea-md-h .native-wrapper.sc-ion-textarea-md::after{-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;margin-top:8px;margin-bottom:0px}.sc-ion-textarea-md-h.textarea-label-placement-stacked.sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-label-placement-stacked .sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-label-placement-stacked.sc-ion-textarea-md-s>[slot=end],.sc-ion-textarea-md-h.textarea-label-placement-stacked .sc-ion-textarea-md-s>[slot=end],.sc-ion-textarea-md-h.textarea-label-placement-floating.sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-label-placement-floating .sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-label-placement-floating.sc-ion-textarea-md-s>[slot=end],.sc-ion-textarea-md-h.textarea-label-placement-floating .sc-ion-textarea-md-s>[slot=end]{margin-top:8px}.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform:translateY(100%) scale(1);transform:translateY(100%) scale(1)}.textarea-label-placement-floating.sc-ion-textarea-md-h textarea.sc-ion-textarea-md{opacity:0}.has-focus.textarea-label-placement-floating.sc-ion-textarea-md-h textarea.sc-ion-textarea-md,.has-value.textarea-label-placement-floating.sc-ion-textarea-md-h textarea.sc-ion-textarea-md{opacity:1}.label-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform:translateY(50%) scale(0.75);transform:translateY(50%) scale(0.75);max-width:calc(100% / 0.75)}.start-slot-wrapper.sc-ion-textarea-md,.end-slot-wrapper.sc-ion-textarea-md{padding-left:0;padding-right:0;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;-ms-flex-negative:0;flex-shrink:0;-ms-flex-item-align:start;align-self:start}.sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-s>[slot=end]{margin-top:0}.sc-ion-textarea-md-s>[slot=start]:last-of-type{-webkit-margin-end:16px;margin-inline-end:16px;-webkit-margin-start:0;margin-inline-start:0}.sc-ion-textarea-md-s>[slot=end]:first-of-type{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}.textarea-fill-solid.sc-ion-textarea-md-h{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-color:var(--ion-color-step-500, var(--ion-background-color-step-500, gray));--border-radius:4px;--padding-start:16px;--padding-end:16px;min-height:56px}.textarea-fill-solid.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md{border-bottom:var(--border-width) var(--border-style) var(--border-color)}.has-focus.textarea-fill-solid.ion-valid.sc-ion-textarea-md-h,.textarea-fill-solid.ion-touched.ion-invalid.sc-ion-textarea-md-h{--border-color:var(--highlight-color)}.textarea-fill-solid.sc-ion-textarea-md-h .textarea-bottom.sc-ion-textarea-md{border-top:none}@media (any-hover: hover){.textarea-fill-solid.sc-ion-textarea-md-h:hover{--background:var(--ion-color-step-100, var(--ion-background-color-step-100, #e6e6e6));--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}}.textarea-fill-solid.has-focus.sc-ion-textarea-md-h{--background:var(--ion-color-step-150, var(--ion-background-color-step-150, #d9d9d9));--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}.textarea-fill-solid.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md{border-start-start-radius:var(--border-radius);border-start-end-radius:var(--border-radius);border-end-end-radius:0px;border-end-start-radius:0px}.label-floating.textarea-fill-solid.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{max-width:calc(100% / 0.75)}.textarea-fill-outline.sc-ion-textarea-md-h{--border-color:var(--ion-color-step-300, var(--ion-background-color-step-300, #b3b3b3));--border-radius:4px;--padding-start:16px;--padding-end:16px;min-height:56px}.textarea-fill-outline.textarea-shape-round.sc-ion-textarea-md-h{--border-radius:28px;--padding-start:32px;--padding-end:32px}.has-focus.textarea-fill-outline.ion-valid.sc-ion-textarea-md-h,.textarea-fill-outline.ion-touched.ion-invalid.sc-ion-textarea-md-h{--border-color:var(--highlight-color)}@media (any-hover: hover){.textarea-fill-outline.sc-ion-textarea-md-h:hover{--border-color:var(--ion-color-step-750, var(--ion-background-color-step-750, #404040))}}.textarea-fill-outline.has-focus.sc-ion-textarea-md-h{--border-width:var(--highlight-height);--border-color:var(--highlight-color)}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-bottom.sc-ion-textarea-md{border-top:none}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-wrapper.sc-ion-textarea-md{border-bottom:none}.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform-origin:left top;transform-origin:left top;position:absolute;max-width:calc(100% - var(--padding-start) - var(--padding-end))}[dir=rtl].sc-ion-textarea-md-h -no-combinator.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .sc-ion-textarea-md-h -no-combinator.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl].textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl].sc-ion-textarea-md-h -no-combinator.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .sc-ion-textarea-md-h -no-combinator.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl].textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,[dir=rtl] .textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h:dir(rtl) .label-text-wrapper.sc-ion-textarea-md,.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h:dir(rtl) .label-text-wrapper.sc-ion-textarea-md{-webkit-transform-origin:right top;transform-origin:right top}}.textarea-fill-outline.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{position:relative}.label-floating.textarea-fill-outline.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{-webkit-transform:translateY(-32%) scale(0.75);transform:translateY(-32%) scale(0.75);margin-left:0;margin-right:0;margin-top:0;margin-bottom:0;max-width:calc(\n (100% - var(--padding-start) - var(--padding-end) - 8px) / 0.75\n )}.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-h textarea.sc-ion-textarea-md,.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-h textarea.sc-ion-textarea-md,.textarea-fill-outline.textarea-label-placement-stacked[auto-grow].sc-ion-textarea-md-h .native-wrapper.sc-ion-textarea-md::after,.textarea-fill-outline.textarea-label-placement-floating[auto-grow].sc-ion-textarea-md-h .native-wrapper.sc-ion-textarea-md::after{-webkit-margin-start:0px;margin-inline-start:0px;-webkit-margin-end:0px;margin-inline-end:0px;margin-top:12px;margin-bottom:0px}.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-stacked .sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-stacked.sc-ion-textarea-md-s>[slot=end],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-stacked .sc-ion-textarea-md-s>[slot=end],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-floating .sc-ion-textarea-md-s>[slot=start],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-floating.sc-ion-textarea-md-s>[slot=end],.sc-ion-textarea-md-h.textarea-fill-outline.textarea-label-placement-floating .sc-ion-textarea-md-s>[slot=end]{margin-top:12px}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-container.sc-ion-textarea-md{left:0;right:0;top:0;bottom:0;display:-ms-flexbox;display:flex;position:absolute;width:100%;height:100%}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-start.sc-ion-textarea-md,.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-end.sc-ion-textarea-md{pointer-events:none}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-start.sc-ion-textarea-md,.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-notch.sc-ion-textarea-md,.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-end.sc-ion-textarea-md{border-top:var(--border-width) var(--border-style) var(--border-color);border-bottom:var(--border-width) var(--border-style) var(--border-color)}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-notch.sc-ion-textarea-md{max-width:calc(100% - var(--padding-start) - var(--padding-end))}.textarea-fill-outline.sc-ion-textarea-md-h .notch-spacer.sc-ion-textarea-md{-webkit-padding-end:8px;padding-inline-end:8px;font-size:calc(1em * 0.75);opacity:0;pointer-events:none;-webkit-box-sizing:content-box;box-sizing:content-box}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-start.sc-ion-textarea-md{border-start-start-radius:var(--border-radius);border-start-end-radius:0px;border-end-end-radius:0px;border-end-start-radius:var(--border-radius);-webkit-border-start:var(--border-width) var(--border-style) var(--border-color);border-inline-start:var(--border-width) var(--border-style) var(--border-color);width:calc(var(--padding-start) - 4px)}.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-end.sc-ion-textarea-md{-webkit-border-end:var(--border-width) var(--border-style) var(--border-color);border-inline-end:var(--border-width) var(--border-style) var(--border-color);border-start-start-radius:0px;border-start-end-radius:var(--border-radius);border-end-end-radius:var(--border-radius);border-end-start-radius:0px;-ms-flex-positive:1;flex-grow:1}.label-floating.textarea-fill-outline.sc-ion-textarea-md-h .textarea-outline-notch.sc-ion-textarea-md{border-top:none}.sc-ion-textarea-md-h{--border-width:1px;--border-color:var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.13)))));--padding-top:18px;--padding-end:0px;--padding-bottom:8px;--padding-start:0px;--highlight-height:2px;font-size:inherit}.textarea-bottom.sc-ion-textarea-md .counter.sc-ion-textarea-md{letter-spacing:0.0333333333em}.textarea-label-placement-floating.has-focus.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,.textarea-label-placement-stacked.has-focus.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{color:var(--highlight-color)}.has-focus.textarea-label-placement-floating.ion-valid.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,.textarea-label-placement-floating.ion-touched.ion-invalid.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,.has-focus.textarea-label-placement-stacked.ion-valid.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md,.textarea-label-placement-stacked.ion-touched.ion-invalid.sc-ion-textarea-md-h .label-text-wrapper.sc-ion-textarea-md{color:var(--highlight-color)}.textarea-disabled.sc-ion-textarea-md-h{opacity:0.38}.textarea-highlight.sc-ion-textarea-md{bottom:-1px;position:absolute;width:100%;height:var(--highlight-height);-webkit-transform:scale(0);transform:scale(0);-webkit-transition:-webkit-transform 200ms;transition:-webkit-transform 200ms;transition:transform 200ms;transition:transform 200ms, -webkit-transform 200ms;background:var(--highlight-color)}.textarea-highlight.sc-ion-textarea-md{inset-inline-start:0}.has-focus.sc-ion-textarea-md-h .textarea-highlight.sc-ion-textarea-md{-webkit-transform:scale(1);transform:scale(1)}.in-item.sc-ion-textarea-md-h .textarea-highlight.sc-ion-textarea-md{bottom:0}.in-item.sc-ion-textarea-md-h .textarea-highlight.sc-ion-textarea-md{inset-inline-start:0}.textarea-shape-round.sc-ion-textarea-md-h{--border-radius:16px}.sc-ion-textarea-md-s>ion-button[slot=start].button-has-icon-only,.sc-ion-textarea-md-s>ion-button[slot=end].button-has-icon-only{--border-radius:50%;--padding-start:8px;--padding-end:8px;--padding-top:8px;--padding-bottom:8px;aspect-ratio:1;min-height:40px}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot label - The label text to associate with the textarea. Use the `labelPlacement` property to control where the label is placed relative to the textarea. Use this if you need to render a label with custom HTML. (EXPERIMENTAL)
* @slot start - Content to display at the leading edge of the textarea. (EXPERIMENTAL)
* @slot end - Content to display at the trailing edge of the textarea. (EXPERIMENTAL)
*/
class Textarea {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionInput = createEvent(this, "ionInput", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.inputId = `ion-textarea-${textareaIds++}`;
this.helperTextId = `${this.inputId}-helper-text`;
this.errorTextId = `${this.inputId}-error-text`;
/**
* `true` if the textarea was cleared as a result of the user typing
* with `clearOnEdit` enabled.
*
* Resets when the textarea loses focus.
*/
this.didTextareaClearOnEdit = false;
this.inheritedAttributes = {};
/**
* The `hasFocus` state ensures the focus class is
* added regardless of how the element is focused.
* The `ion-focused` class only applies when focused
* via tabbing, not by clicking.
* The `has-focus` logic was added to ensure the class
* is applied in both cases.
*/
this.hasFocus = false;
/**
* Track validation state for proper aria-live announcements
*/
this.isInvalid = false;
/**
* Indicates whether and how the text value should be automatically capitalized as it is entered/edited by the user.
* Available options: `"off"`, `"none"`, `"on"`, `"sentences"`, `"words"`, `"characters"`.
*/
this.autocapitalize = 'none';
/**
* Sets the [`autofocus` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) on the native input element.
*
* This may not be sufficient for the element to be focused on page load. See [managing focus](/docs/developing/managing-focus) for more information.
*/
this.autofocus = false;
/**
* If `true`, the value will be cleared after focus upon edit.
*/
this.clearOnEdit = false;
/**
* If `true`, the user cannot interact with the textarea.
*/
this.disabled = false;
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* If `true`, the user cannot modify the value.
*/
this.readonly = false;
/**
* If `true`, the user must fill in a value before submitting a form.
*/
this.required = false;
/**
* If `true`, the element will have its spelling and grammar checked.
*/
this.spellcheck = false;
/**
* If `true`, the textarea container will grow and shrink based
* on the contents of the textarea.
*/
this.autoGrow = false;
/**
* The value of the textarea.
*/
this.value = '';
/**
* If `true`, a character counter will display the ratio of characters used and the total character limit.
* Developers must also set the `maxlength` property for the counter to be calculated correctly.
*/
this.counter = false;
/**
* Where to place the label relative to the textarea.
* `"start"`: The label will appear to the left of the textarea in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the textarea in LTR and to the left in RTL.
* `"floating"`: The label will appear smaller and above the textarea when the textarea is focused or it has a value. Otherwise it will appear on top of the textarea.
* `"stacked"`: The label will appear smaller and above the textarea regardless even when the textarea is blurred or has no value.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
*/
this.labelPlacement = 'start';
// `Event` type is used instead of `InputEvent`
// since the types from Stencil are not derived
// from the element (e.g. textarea and input
// should be InputEvent, but all other elements
// should be Event).
this.onInput = (ev) => {
const input = ev.target;
if (input) {
this.value = input.value || '';
}
this.emitInputChange(ev);
};
this.onChange = (ev) => {
this.emitValueChange(ev);
};
this.onFocus = (ev) => {
this.hasFocus = true;
this.focusedValue = this.value;
this.ionFocus.emit(ev);
};
this.onBlur = (ev) => {
this.hasFocus = false;
if (this.focusedValue !== this.value) {
/**
* Emits the `ionChange` event when the textarea value
* is different than the value when the textarea was focused.
*/
this.emitValueChange(ev);
}
this.didTextareaClearOnEdit = false;
this.ionBlur.emit(ev);
};
this.onKeyDown = (ev) => {
this.checkClearOnEdit(ev);
};
/**
* Stops propagation when the label is clicked,
* otherwise, two clicks will be triggered.
*/
this.onLabelClick = (ev) => {
// Only stop propagation if the click was directly on the label
// and not on the input or other child elements
if (ev.target === ev.currentTarget) {
ev.stopPropagation();
}
};
}
debounceChanged() {
const { ionInput, debounce, originalIonInput } = this;
/**
* If debounce is undefined, we have to manually revert the ionInput emitter in case
* debounce used to be set to a number. Otherwise, the event would stay debounced.
*/
this.ionInput = debounce === undefined ? originalIonInput !== null && originalIonInput !== void 0 ? originalIonInput : ionInput : debounceEvent(ionInput, debounce);
}
/**
* Update the native input element when the value changes
*/
valueChanged() {
const nativeInput = this.nativeInput;
const value = this.getValue();
if (nativeInput && nativeInput.value !== value) {
nativeInput.value = value;
}
this.runAutoGrow();
}
/**
* dir is a globally enumerated attribute.
* As a result, creating these as properties
* can have unintended side effects. Instead, we
* listen for attribute changes and inherit them
* to the inner `<textarea>` element.
*/
onDirChanged(newValue) {
this.inheritedAttributes = Object.assign(Object.assign({}, this.inheritedAttributes), { dir: newValue });
}
/**
* This prevents the native input from emitting the click event.
* Instead, the click event from the ion-textarea is emitted.
*/
onClickCapture(ev) {
const nativeInput = this.nativeInput;
if (nativeInput && ev.target === nativeInput) {
ev.stopPropagation();
this.el.click();
}
}
connectedCallback() {
const { el } = this;
this.slotMutationController = createSlotMutationController(el, ['label', 'start', 'end'], () => forceUpdate());
this.notchController = createNotchController(el, () => this.notchSpacerEl, () => this.labelSlot);
// Always set initial state
this.isInvalid = checkInvalidState(this.el);
this.debounceChanged();
}
disconnectedCallback() {
if (this.slotMutationController) {
this.slotMutationController.destroy();
this.slotMutationController = undefined;
}
if (this.notchController) {
this.notchController.destroy();
this.notchController = undefined;
}
// Clean up validation observer to prevent memory leaks
if (this.validationObserver) {
this.validationObserver.disconnect();
this.validationObserver = undefined;
}
}
componentWillLoad() {
this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes$1(this.el, ['data-form-type', 'title', 'tabindex', 'dir']));
}
componentDidLoad() {
this.originalIonInput = this.ionInput;
this.runAutoGrow();
}
componentDidRender() {
var _a;
(_a = this.notchController) === null || _a === void 0 ? void 0 : _a.calculateNotchWidth();
}
/**
* Sets focus on the native `textarea` in `ion-textarea`. Use this method instead of the global
* `textarea.focus()`.
*
* See [managing focus](/docs/developing/managing-focus) for more information.
*/
async setFocus() {
if (this.nativeInput) {
this.nativeInput.focus();
}
}
/**
* Returns the native `<textarea>` element used under the hood.
*/
async getInputElement() {
/**
* If this gets called in certain early lifecycle hooks (ex: Vue onMounted),
* nativeInput won't be defined yet with the custom elements build, so wait for it to load in.
*/
if (!this.nativeInput) {
await new Promise((resolve) => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.nativeInput);
}
/**
* Emits an `ionChange` event.
*
* This API should be called for user committed changes.
* This API should not be used for external value changes.
*/
emitValueChange(event) {
const { value } = this;
// Checks for both null and undefined values
const newValue = value == null ? value : value.toString();
// Emitting a value change should update the internal state for tracking the focused value
this.focusedValue = newValue;
this.ionChange.emit({ value: newValue, event });
}
/**
* Emits an `ionInput` event.
*/
emitInputChange(event) {
const { value } = this;
this.ionInput.emit({ value, event });
}
runAutoGrow() {
if (this.nativeInput && this.autoGrow) {
writeTask(() => {
var _a;
if (this.textareaWrapper) {
// Replicated value is an attribute to be used in the stylesheet
// to set the inner contents of a pseudo element.
this.textareaWrapper.dataset.replicatedValue = (_a = this.value) !== null && _a !== void 0 ? _a : '';
}
});
}
}
/**
* Check if we need to clear the text input if clearOnEdit is enabled
*/
checkClearOnEdit(ev) {
if (!this.clearOnEdit) {
return;
}
/**
* The following keys do not modify the
* contents of the input. As a result, pressing
* them should not edit the textarea.
*
* We can't check to see if the value of the textarea
* was changed because we call checkClearOnEdit
* in a keydown listener, and the key has not yet
* been added to the textarea.
*
* Unlike ion-input, the "Enter" key does modify the
* textarea by adding a new line, so "Enter" is not
* included in the IGNORED_KEYS array.
*/
const IGNORED_KEYS = ['Tab', 'Shift', 'Meta', 'Alt', 'Control'];
const pressedIgnoredKey = IGNORED_KEYS.includes(ev.key);
/**
* Clear the textarea if the control has not been previously cleared
* during focus.
*/
if (!this.didTextareaClearOnEdit && this.hasValue() && !pressedIgnoredKey) {
this.value = '';
this.emitInputChange(ev);
}
/**
* Pressing an IGNORED_KEYS first and
* then an allowed key will cause the input to not
* be cleared.
*/
if (!pressedIgnoredKey) {
this.didTextareaClearOnEdit = true;
}
}
hasValue() {
return this.getValue() !== '';
}
getValue() {
return this.value || '';
}
renderLabel() {
const { label } = this;
return (hAsync("div", { class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !this.hasLabel,
} }, label === undefined ? hAsync("slot", { name: "label" }) : hAsync("div", { class: "label-text" }, label)));
}
/**
* Gets any content passed into the `label` slot,
* not the <slot> definition.
*/
get labelSlot() {
return this.el.querySelector('[slot="label"]');
}
/**
* Returns `true` if label content is provided
* either by a prop or a content. If you want
* to get the plaintext value of the label use
* the `labelText` getter instead.
*/
get hasLabel() {
return this.label !== undefined || this.labelSlot !== null;
}
/**
* Renders the border container when fill="outline".
*/
renderLabelContainer() {
const mode = getIonMode$1(this);
const hasOutlineFill = mode === 'md' && this.fill === 'outline';
if (hasOutlineFill) {
/**
* The outline fill has a special outline
* that appears around the textarea and the label.
* Certain stacked and floating label placements cause the
* label to translate up and create a "cut out"
* inside of that border by using the notch-spacer element.
*/
return [
hAsync("div", { class: "textarea-outline-container" }, hAsync("div", { class: "textarea-outline-start" }), hAsync("div", { class: {
'textarea-outline-notch': true,
'textarea-outline-notch-hidden': !this.hasLabel,
} }, hAsync("div", { class: "notch-spacer", "aria-hidden": "true", ref: (el) => (this.notchSpacerEl = el) }, this.label)), hAsync("div", { class: "textarea-outline-end" })),
this.renderLabel(),
];
}
/**
* If not using the outline style,
* we can render just the label.
*/
return this.renderLabel();
}
/**
* Renders the helper text or error text values
*/
renderHintText() {
const { helperText, errorText, helperTextId, errorTextId, isInvalid } = this;
return [
hAsync("div", { id: helperTextId, class: "helper-text", "aria-live": "polite" }, !isInvalid ? helperText : null),
hAsync("div", { id: errorTextId, class: "error-text", role: "alert" }, isInvalid ? errorText : null),
];
}
getHintTextID() {
const { isInvalid, helperText, errorText, helperTextId, errorTextId } = this;
if (isInvalid && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
renderCounter() {
const { counter, maxlength, counterFormatter, value } = this;
if (counter !== true || maxlength === undefined) {
return;
}
return hAsync("div", { class: "counter" }, getCounterText(value, maxlength, counterFormatter));
}
/**
* Responsible for rendering helper text,
* error text, and counter. This element should only
* be rendered if hint text is set or counter is enabled.
*/
renderBottomContent() {
const { counter, helperText, errorText, maxlength } = this;
/**
* undefined and empty string values should
* be treated as not having helper/error text.
*/
const hasHintText = !!helperText || !!errorText;
const hasCounter = counter === true && maxlength !== undefined;
if (!hasHintText && !hasCounter) {
return;
}
return (hAsync("div", { class: "textarea-bottom" }, this.renderHintText(), this.renderCounter()));
}
render() {
const { inputId, disabled, fill, shape, labelPlacement, el, hasFocus } = this;
const mode = getIonMode$1(this);
const value = this.getValue();
const inItem = hostContext('ion-item', this.el);
const shouldRenderHighlight = mode === 'md' && fill !== 'outline' && !inItem;
const hasValue = this.hasValue();
const hasStartEndSlots = el.querySelector('[slot="start"], [slot="end"]') !== null;
/**
* If the label is stacked, it should always sit above the textarea.
* For floating labels, the label should move above the textarea if
* the textarea has a value, is focused, or has anything in either
* the start or end slot.
*
* If there is content in the start slot, the label would overlap
* it if not forced to float. This is also applied to the end slot
* because with the default or solid fills, the textarea is not
* vertically centered in the container, but the label is. This
* causes the slots and label to appear vertically offset from each
* other when the label isn't floating above the input. This doesn't
* apply to the outline fill, but this was not accounted for to keep
* things consistent.
*
* TODO(FW-5592): Remove hasStartEndSlots condition
*/
const labelShouldFloat = labelPlacement === 'stacked' || (labelPlacement === 'floating' && (hasValue || hasFocus || hasStartEndSlots));
return (hAsync(Host, { key: 'a70a62d7aae3831a50acd74f60b930925ada1326', class: createColorClasses$1(this.color, {
[mode]: true,
'has-value': hasValue,
'has-focus': hasFocus,
'label-floating': labelShouldFloat,
[`textarea-fill-${fill}`]: fill !== undefined,
[`textarea-shape-${shape}`]: shape !== undefined,
[`textarea-label-placement-${labelPlacement}`]: true,
'textarea-disabled': disabled,
}) }, hAsync("label", { key: '8a2dd59a60f7469df84018eb0ede3a9ec3862703', class: "textarea-wrapper", htmlFor: inputId, onClick: this.onLabelClick }, this.renderLabelContainer(), hAsync("div", { key: '1bfc368236e3da7a225a45118c27fbfc1fe5fa46', class: "textarea-wrapper-inner" }, hAsync("div", { key: '215cbb2635ff52e31a8973376989b85e7245d40f', class: "start-slot-wrapper" }, hAsync("slot", { key: '9f6b461cdee9d629deb695d2bea054ece2f32305', name: "start" })), hAsync("div", { key: 'c1af35a2d5bc452bebe0b22a26d15ff52b4e9fc8', class: "native-wrapper", ref: (el) => (this.textareaWrapper = el) }, hAsync("textarea", Object.assign({ key: '69a69b3cf0932baafbe37e6e846f1a571608d3f2', class: "native-textarea", ref: (el) => (this.nativeInput = el), id: inputId, disabled: disabled, autoCapitalize: this.autocapitalize, autoFocus: this.autofocus, enterKeyHint: this.enterkeyhint, inputMode: this.inputmode, minLength: this.minlength, maxLength: this.maxlength, name: this.name, placeholder: this.placeholder || '', readOnly: this.readonly, required: this.required, spellcheck: this.spellcheck, cols: this.cols, rows: this.rows, wrap: this.wrap, onInput: this.onInput, onChange: this.onChange, onBlur: this.onBlur, onFocus: this.onFocus, onKeyDown: this.onKeyDown, "aria-describedby": this.getHintTextID(), "aria-invalid": this.isInvalid ? 'true' : undefined }, this.inheritedAttributes), value)), hAsync("div", { key: 'c053ea8b865d0e29763aed2e4939cc9c9e374c15', class: "end-slot-wrapper" }, hAsync("slot", { key: '930aa641833b0df54b9ea10368fc2f46d5f491f6', name: "end" }))), shouldRenderHighlight && hAsync("div", { key: '8d12597d15f5f429d80e8272ea99e64ed924e482', class: "textarea-highlight" })), this.renderBottomContent()));
}
get el() { return getElement(this); }
static get watchers() { return {
"debounce": ["debounceChanged"],
"value": ["valueChanged"],
"dir": ["onDirChanged"]
}; }
static get style() { return {
ios: textareaIosCss,
md: textareaMdCss
}; }
static get cmpMeta() { return {
"$flags$": 294,
"$tagName$": "ion-textarea",
"$members$": {
"color": [513],
"autocapitalize": [1],
"autofocus": [4],
"clearOnEdit": [4, "clear-on-edit"],
"debounce": [2],
"disabled": [4],
"fill": [1],
"inputmode": [1],
"enterkeyhint": [1],
"maxlength": [2],
"minlength": [2],
"name": [1],
"placeholder": [1],
"readonly": [4],
"required": [4],
"spellcheck": [4],
"cols": [514],
"rows": [2],
"wrap": [1],
"autoGrow": [516, "auto-grow"],
"value": [1025],
"counter": [4],
"counterFormatter": [16],
"errorText": [1, "error-text"],
"helperText": [1, "helper-text"],
"label": [1],
"labelPlacement": [1, "label-placement"],
"shape": [1],
"hasFocus": [32],
"isInvalid": [32],
"setFocus": [64],
"getInputElement": [64]
},
"$listeners$": [[2, "click", "onClickCapture"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"], ["cols", "cols"], ["autoGrow", "auto-grow"]]
}; }
}
let textareaIds = 0;
const thumbnailCss = ":host{--size:48px;--border-radius:0;border-radius:var(--border-radius);display:block;width:var(--size);height:var(--size)}::slotted(ion-img),::slotted(img){border-radius:var(--border-radius);width:100%;height:100%;-o-object-fit:cover;object-fit:cover;overflow:hidden}";
class Thumbnail {
constructor(hostRef) {
registerInstance(this, hostRef);
}
render() {
return (hAsync(Host, { key: '70ada828e8cf541ab3b47f94b7e56ce34114ef88', class: getIonMode$1(this) }, hAsync("slot", { key: 'c43e105669d2bae123619b616f3af8ca2f722d61' })));
}
static get style() { return thumbnailCss; }
static get cmpMeta() { return {
"$flags$": 265,
"$tagName$": "ion-thumbnail",
"$members$": undefined,
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": []
}; }
}
/**
* Calculate the CSS top and bottom position of the toast, to be used
* as starting points for the animation keyframes.
*
* The default animations for both MD and iOS
* use translateY, which calculates from the
* top edge of the screen. This behavior impacts
* how we compute the offset when a toast has
* position='bottom' since we need to calculate from
* the bottom edge of the screen instead.
*
* @param position The value of the toast's position prop.
* @param positionAnchor The element the toast should be anchored to,
* if applicable.
* @param mode The toast component's mode (md, ios, etc).
* @param toast A reference to the toast element itself.
*/
function getAnimationPosition(position, positionAnchor, mode, toast) {
/**
* Start with a predefined offset from the edge the toast will be
* positioned relative to, whether on the screen or anchor element.
*/
let offset;
if (mode === 'md') {
offset = position === 'top' ? 8 : -8;
}
else {
offset = position === 'top' ? 10 : -10;
}
/**
* If positionAnchor is defined, add in the distance from the target
* screen edge to the target anchor edge. For position="top", the
* bottom anchor edge is targeted. For position="bottom", the top
* anchor edge is targeted.
*/
if (positionAnchor && win$1) {
warnIfAnchorIsHidden(positionAnchor, toast);
const box = positionAnchor.getBoundingClientRect();
if (position === 'top') {
offset += box.bottom;
}
else if (position === 'bottom') {
/**
* Just box.top is the distance from the top edge of the screen
* to the top edge of the anchor. We want to calculate from the
* bottom edge of the screen instead.
*/
offset -= win$1.innerHeight - box.top;
}
/**
* We don't include safe area here because that should already be
* accounted for when checking the position of the anchor.
*/
return {
top: `${offset}px`,
bottom: `${offset}px`,
};
}
else {
return {
top: `calc(${offset}px + var(--ion-safe-area-top, 0px))`,
bottom: `calc(${offset}px - var(--ion-safe-area-bottom, 0px))`,
};
}
}
/**
* If the anchor element is hidden, getBoundingClientRect()
* will return all 0s for it, which can cause unexpected
* results in the position calculation when animating.
*/
function warnIfAnchorIsHidden(positionAnchor, toast) {
if (positionAnchor.offsetParent === null) {
printIonWarning('[ion-toast] - The positionAnchor element for ion-toast was found in the DOM, but appears to be hidden. This may lead to unexpected positioning of the toast.', toast);
}
}
/**
* Returns the top offset required to place
* the toast in the middle of the screen.
* Only needed when position="toast".
* @param toastHeight - The height of the ion-toast element
* @param wrapperHeight - The height of the .toast-wrapper element
* inside the toast's shadow root.
*/
const getOffsetForMiddlePosition = (toastHeight, wrapperHeight) => {
return Math.floor(toastHeight / 2 - wrapperHeight / 2);
};
/**
* iOS Toast Enter Animation
*/
const iosEnterAnimation = (baseEl, opts) => {
const baseAnimation = createAnimation();
const wrapperAnimation = createAnimation();
const { position, top, bottom } = opts;
const root = getElementRoot(baseEl);
const wrapperEl = root.querySelector('.toast-wrapper');
wrapperAnimation.addElement(wrapperEl);
switch (position) {
case 'top':
wrapperAnimation.fromTo('transform', 'translateY(-100%)', `translateY(${top})`);
break;
case 'middle':
const topPosition = getOffsetForMiddlePosition(baseEl.clientHeight, wrapperEl.clientHeight);
wrapperEl.style.top = `${topPosition}px`;
wrapperAnimation.fromTo('opacity', 0.01, 1);
break;
default:
wrapperAnimation.fromTo('transform', 'translateY(100%)', `translateY(${bottom})`);
break;
}
return baseAnimation.easing('cubic-bezier(.155,1.105,.295,1.12)').duration(400).addAnimation(wrapperAnimation);
};
/**
* iOS Toast Leave Animation
*/
const iosLeaveAnimation = (baseEl, opts) => {
const baseAnimation = createAnimation();
const wrapperAnimation = createAnimation();
const { position, top, bottom } = opts;
const root = getElementRoot(baseEl);
const wrapperEl = root.querySelector('.toast-wrapper');
wrapperAnimation.addElement(wrapperEl);
switch (position) {
case 'top':
wrapperAnimation.fromTo('transform', `translateY(${top})`, 'translateY(-100%)');
break;
case 'middle':
wrapperAnimation.fromTo('opacity', 0.99, 0);
break;
default:
wrapperAnimation.fromTo('transform', `translateY(${bottom})`, 'translateY(100%)');
break;
}
return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
};
/**
* MD Toast Enter Animation
*/
const mdEnterAnimation = (baseEl, opts) => {
const baseAnimation = createAnimation();
const wrapperAnimation = createAnimation();
const { position, top, bottom } = opts;
const root = getElementRoot(baseEl);
const wrapperEl = root.querySelector('.toast-wrapper');
wrapperAnimation.addElement(wrapperEl);
switch (position) {
case 'top':
wrapperEl.style.setProperty('transform', `translateY(${top})`);
wrapperAnimation.fromTo('opacity', 0.01, 1);
break;
case 'middle':
const topPosition = getOffsetForMiddlePosition(baseEl.clientHeight, wrapperEl.clientHeight);
wrapperEl.style.top = `${topPosition}px`;
wrapperAnimation.fromTo('opacity', 0.01, 1);
break;
default:
wrapperEl.style.setProperty('transform', `translateY(${bottom})`);
wrapperAnimation.fromTo('opacity', 0.01, 1);
break;
}
return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(400).addAnimation(wrapperAnimation);
};
/**
* md Toast Leave Animation
*/
const mdLeaveAnimation = (baseEl) => {
const baseAnimation = createAnimation();
const wrapperAnimation = createAnimation();
const root = getElementRoot(baseEl);
const wrapperEl = root.querySelector('.toast-wrapper');
wrapperAnimation.addElement(wrapperEl).fromTo('opacity', 0.99, 0);
return baseAnimation.easing('cubic-bezier(.36,.66,.04,1)').duration(300).addAnimation(wrapperAnimation);
};
/**
* Create a gesture that allows the Toast
* to be swiped to dismiss.
* @param el - The Toast element
* @param toastPosition - The last computed position of the Toast. This is computed in the "present" method.
* @param onDismiss - A callback to fire when the Toast was swiped to dismiss.
*/
const createSwipeToDismissGesture = (el, toastPosition, onDismiss) => {
/**
* Users should swipe on the visible toast wrapper
* rather than on ion-toast which covers the entire screen.
* When testing the class instance the inner wrapper will not
* be defined. As a result, we use a placeholder element in those environments.
*/
const wrapperEl = getElementRoot(el).querySelector('.toast-wrapper');
const hostElHeight = el.clientHeight;
const wrapperElBox = wrapperEl.getBoundingClientRect();
/**
* The maximum amount that
* the toast can be swiped. This should
* account for the wrapper element's height
* too so the toast can be swiped offscreen
* completely.
*/
let MAX_SWIPE_DISTANCE = 0;
/**
* The step value at which a toast
* is eligible for dismissing via gesture.
*/
const DISMISS_THRESHOLD = 0.5;
/**
* The middle position Toast starts 50% of the way
* through the animation, so we need to use this
* as the starting point for our step values.
*/
const STEP_OFFSET = el.position === 'middle' ? 0.5 : 0;
/**
* When the Toast is at the top users will be
* swiping up. As a result, the delta values will be
* negative numbers which will result in negative steps
* and thresholds. As a result, we need to make those numbers
* positive.
*/
const INVERSION_FACTOR = el.position === 'top' ? -1 : 1;
/**
* The top offset that places the
* toast in the middle of the screen.
* Only needed when position="middle".
*/
const topPosition = getOffsetForMiddlePosition(hostElHeight, wrapperElBox.height);
const SWIPE_UP_DOWN_KEYFRAMES = [
{ offset: 0, transform: `translateY(-${topPosition + wrapperElBox.height}px)` },
{ offset: 0.5, transform: `translateY(0px)` },
{ offset: 1, transform: `translateY(${topPosition + wrapperElBox.height}px)` },
];
const swipeAnimation = createAnimation('toast-swipe-to-dismiss-animation')
.addElement(wrapperEl)
/**
* The specific value here does not actually
* matter. We just need this to be a positive
* value so the animation does not jump
* to the end when the user beings to drag.
*/
.duration(100);
switch (el.position) {
case 'middle':
MAX_SWIPE_DISTANCE = hostElHeight + wrapperElBox.height;
swipeAnimation.keyframes(SWIPE_UP_DOWN_KEYFRAMES);
/**
* Toast can be swiped up or down but
* should start in the middle of the screen.
*/
swipeAnimation.progressStart(true, 0.5);
break;
case 'top':
/**
* The bottom edge of the wrapper
* includes the distance between the top
* of the screen and the top of the wrapper
* as well as the wrapper height so the wrapper
* can be dragged fully offscreen.
*/
MAX_SWIPE_DISTANCE = wrapperElBox.bottom;
swipeAnimation.keyframes([
{ offset: 0, transform: `translateY(${toastPosition.top})` },
{ offset: 1, transform: 'translateY(-100%)' },
]);
swipeAnimation.progressStart(true, 0);
break;
case 'bottom':
default:
/**
* This computes the distance between the
* top of the wrapper and the bottom of the
* screen including the height of the wrapper
* element so it can be dragged fully offscreen.
*/
MAX_SWIPE_DISTANCE = hostElHeight - wrapperElBox.top;
swipeAnimation.keyframes([
{ offset: 0, transform: `translateY(${toastPosition.bottom})` },
{ offset: 1, transform: 'translateY(100%)' },
]);
swipeAnimation.progressStart(true, 0);
break;
}
const computeStep = (delta) => {
return (delta * INVERSION_FACTOR) / MAX_SWIPE_DISTANCE;
};
const onMove = (detail) => {
const step = STEP_OFFSET + computeStep(detail.deltaY);
swipeAnimation.progressStep(step);
};
const onEnd = (detail) => {
const velocity = detail.velocityY;
const threshold = ((detail.deltaY + velocity * 1000) / MAX_SWIPE_DISTANCE) * INVERSION_FACTOR;
/**
* Disable the gesture for the remainder of the animation.
* It will be re-enabled if the toast animates back to
* its initial presented position.
*/
gesture.enable(false);
let shouldDismiss = true;
let playTo = 1;
let step = 0;
let remainingDistance = 0;
if (el.position === 'middle') {
/**
* A middle positioned Toast appears
* in the middle of the screen (at animation offset 0.5).
* As a result, the threshold will be calculated relative
* to this starting position. In other words at animation offset 0.5
* the threshold will be 0. We want the middle Toast to be eligible
* for dismiss when the user has swiped either half way up or down the
* screen. As a result, we divide DISMISS_THRESHOLD in half. We also
* consider when the threshold is a negative in the event the
* user drags up (since the deltaY will also be negative).
*/
shouldDismiss = threshold >= DISMISS_THRESHOLD / 2 || threshold <= -0.5 / 2;
/**
* Since we are replacing the keyframes
* below the animation always starts from
* the beginning of the new keyframes.
* Similarly, we are always playing to
* the end of the new keyframes.
*/
playTo = 1;
step = 0;
/**
* The Toast should animate from wherever its
* current position is to the desired end state.
*
* To begin, we get the current position of the
* Toast for its starting state.
*/
const wrapperElBox = wrapperEl.getBoundingClientRect();
const startOffset = wrapperElBox.top - topPosition;
const startPosition = `${startOffset}px`;
/**
* If the deltaY is negative then the user is swiping
* up, so the Toast should animate to the top of the screen.
* If the deltaY is positive then the user is swiping
* down, so the Toast should animate to the bottom of the screen.
* We also account for when the deltaY is 0, but realistically
* that should never happen because it means the user did not drag
* the toast.
*/
const offsetFactor = detail.deltaY <= 0 ? -1 : 1;
const endOffset = (topPosition + wrapperElBox.height) * offsetFactor;
/**
* If the Toast should dismiss
* then we need to figure out which edge of
* the screen it should animate towards.
* By default, the Toast will come
* back to its default state in the
* middle of the screen.
*/
const endPosition = shouldDismiss ? `${endOffset}px` : '0px';
const KEYFRAMES = [
{ offset: 0, transform: `translateY(${startPosition})` },
{ offset: 1, transform: `translateY(${endPosition})` },
];
swipeAnimation.keyframes(KEYFRAMES);
/**
* Compute the remaining amount of pixels the
* toast needs to move to be fully dismissed.
*/
remainingDistance = endOffset - startOffset;
}
else {
shouldDismiss = threshold >= DISMISS_THRESHOLD;
playTo = shouldDismiss ? 1 : 0;
step = computeStep(detail.deltaY);
/**
* Compute the remaining amount of pixels the
* toast needs to move to be fully dismissed.
*/
const remainingStepAmount = shouldDismiss ? 1 - step : step;
remainingDistance = remainingStepAmount * MAX_SWIPE_DISTANCE;
}
/**
* The animation speed should depend on how quickly
* the user flicks the toast across the screen. However,
* it should be no slower than 200ms.
* We use Math.abs on the remainingDistance because that value
* can be negative when swiping up on a middle position toast.
*/
const duration = Math.min(Math.abs(remainingDistance) / Math.abs(velocity), 200);
swipeAnimation
.onFinish(() => {
if (shouldDismiss) {
onDismiss();
swipeAnimation.destroy();
}
else {
if (el.position === 'middle') {
/**
* If the toast snapped back to
* the middle of the screen we need
* to reset the keyframes
* so the toast can be swiped
* up or down again.
*/
swipeAnimation.keyframes(SWIPE_UP_DOWN_KEYFRAMES).progressStart(true, 0.5);
}
else {
swipeAnimation.progressStart(true, 0);
}
/**
* If the toast did not dismiss then
* the user should be able to swipe again.
*/
gesture.enable(true);
}
/**
* This must be a one time callback
* otherwise a new callback will
* be added every time onEnd runs.
*/
}, { oneTimeCallback: true })
.progressEnd(playTo, step, duration);
};
const gesture = createGesture({
el: wrapperEl,
gestureName: 'toast-swipe-to-dismiss',
gesturePriority: OVERLAY_GESTURE_PRIORITY,
/**
* Toast only supports vertical swipes.
* This needs to be updated if we later
* support horizontal swipes.
*/
direction: 'y',
onMove,
onEnd,
});
return gesture;
};
const toastIosCss = ":host{--border-width:0;--border-style:none;--border-color:initial;--box-shadow:none;--min-width:auto;--width:auto;--min-height:auto;--height:auto;--max-height:auto;--white-space:normal;top:0;display:block;position:absolute;width:100%;height:100%;outline:none;color:var(--color);font-family:var(--ion-font-family, inherit);contain:strict;z-index:1001;pointer-events:none}:host{inset-inline-start:0}:host(.overlay-hidden){display:none}:host(.ion-color){--button-color:inherit;color:var(--ion-color-contrast)}:host(.ion-color) .toast-button-cancel{color:inherit}:host(.ion-color) .toast-wrapper{background:var(--ion-color-base)}.toast-wrapper{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);pointer-events:auto}.toast-wrapper{inset-inline-start:var(--start);inset-inline-end:var(--end)}.toast-wrapper.toast-top{-webkit-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0);top:0}.toast-wrapper.toast-bottom{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);bottom:0}.toast-container{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;height:inherit;min-height:inherit;max-height:inherit;contain:content}.toast-layout-stacked .toast-container{-ms-flex-wrap:wrap;flex-wrap:wrap}.toast-layout-baseline .toast-content{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center}.toast-icon{-webkit-margin-start:16px;margin-inline-start:16px}.toast-content{min-width:0}.toast-message{-ms-flex:1;flex:1;white-space:var(--white-space)}.toast-button-group{display:-ms-flexbox;display:flex}.toast-layout-stacked .toast-button-group{-ms-flex-pack:end;justify-content:end;width:100%}.toast-button{border:0;outline:none;color:var(--button-color);z-index:0}.toast-icon,.toast-button-icon{font-size:1.4em}.toast-button-inner{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}@media (any-hover: hover){.toast-button:hover{cursor:pointer}}:host{--background:var(--ion-color-step-50, var(--ion-background-color-step-50, #f2f2f2));--border-radius:14px;--button-color:var(--ion-color-primary, #0054e9);--color:var(--ion-color-step-850, var(--ion-text-color-step-150, #262626));--max-width:700px;--max-height:478px;--start:10px;--end:10px;font-size:clamp(14px, 0.875rem, 43.4px)}.toast-wrapper{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;display:block;position:absolute;z-index:10}@supports ((-webkit-backdrop-filter: blur(0)) or (backdrop-filter: blur(0))){:host(.toast-translucent) .toast-wrapper{background:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.8);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px)}:host(.ion-color.toast-translucent) .toast-wrapper{background:rgba(var(--ion-color-base-rgb), 0.8)}}.toast-wrapper.toast-middle{opacity:0.01}.toast-content{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px;padding-top:15px;padding-bottom:15px}.toast-header{margin-bottom:2px;font-weight:500}.toast-button{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px;padding-top:10px;padding-bottom:10px;min-height:44px;-webkit-transition:background-color, opacity 100ms linear;transition:background-color, opacity 100ms linear;border:0;background-color:transparent;font-family:var(--ion-font-family);font-size:clamp(17px, 1.0625rem, 21.998px);font-weight:500;overflow:hidden}.toast-button.ion-activated{opacity:0.4}@media (any-hover: hover){.toast-button:hover{opacity:0.6}}";
const toastMdCss = ":host{--border-width:0;--border-style:none;--border-color:initial;--box-shadow:none;--min-width:auto;--width:auto;--min-height:auto;--height:auto;--max-height:auto;--white-space:normal;top:0;display:block;position:absolute;width:100%;height:100%;outline:none;color:var(--color);font-family:var(--ion-font-family, inherit);contain:strict;z-index:1001;pointer-events:none}:host{inset-inline-start:0}:host(.overlay-hidden){display:none}:host(.ion-color){--button-color:inherit;color:var(--ion-color-contrast)}:host(.ion-color) .toast-button-cancel{color:inherit}:host(.ion-color) .toast-wrapper{background:var(--ion-color-base)}.toast-wrapper{border-radius:var(--border-radius);width:var(--width);min-width:var(--min-width);max-width:var(--max-width);height:var(--height);min-height:var(--min-height);max-height:var(--max-height);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);-webkit-box-shadow:var(--box-shadow);box-shadow:var(--box-shadow);pointer-events:auto}.toast-wrapper{inset-inline-start:var(--start);inset-inline-end:var(--end)}.toast-wrapper.toast-top{-webkit-transform:translate3d(0, -100%, 0);transform:translate3d(0, -100%, 0);top:0}.toast-wrapper.toast-bottom{-webkit-transform:translate3d(0, 100%, 0);transform:translate3d(0, 100%, 0);bottom:0}.toast-container{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;height:inherit;min-height:inherit;max-height:inherit;contain:content}.toast-layout-stacked .toast-container{-ms-flex-wrap:wrap;flex-wrap:wrap}.toast-layout-baseline .toast-content{display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center}.toast-icon{-webkit-margin-start:16px;margin-inline-start:16px}.toast-content{min-width:0}.toast-message{-ms-flex:1;flex:1;white-space:var(--white-space)}.toast-button-group{display:-ms-flexbox;display:flex}.toast-layout-stacked .toast-button-group{-ms-flex-pack:end;justify-content:end;width:100%}.toast-button{border:0;outline:none;color:var(--button-color);z-index:0}.toast-icon,.toast-button-icon{font-size:1.4em}.toast-button-inner{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}@media (any-hover: hover){.toast-button:hover{cursor:pointer}}:host{--background:var(--ion-color-step-800, var(--ion-background-color-step-800, #333333));--border-radius:4px;--box-shadow:0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12);--button-color:var(--ion-color-primary, #0054e9);--color:var(--ion-color-step-50, var(--ion-text-color-step-950, #f2f2f2));--max-width:700px;--start:8px;--end:8px;font-size:0.875rem}.toast-wrapper{-webkit-margin-start:auto;margin-inline-start:auto;-webkit-margin-end:auto;margin-inline-end:auto;margin-top:auto;margin-bottom:auto;display:block;position:absolute;opacity:0.01;z-index:10}.toast-content{-webkit-padding-start:16px;padding-inline-start:16px;-webkit-padding-end:16px;padding-inline-end:16px;padding-top:14px;padding-bottom:14px}.toast-header{margin-bottom:2px;font-weight:500;line-height:1.25rem}.toast-message{line-height:1.25rem}.toast-layout-baseline .toast-button-group-start{-webkit-margin-start:8px;margin-inline-start:8px}.toast-layout-stacked .toast-button-group-start{-webkit-margin-end:8px;margin-inline-end:8px;margin-top:8px}.toast-layout-baseline .toast-button-group-end{-webkit-margin-end:8px;margin-inline-end:8px}.toast-layout-stacked .toast-button-group-end{-webkit-margin-end:8px;margin-inline-end:8px;margin-bottom:8px}.toast-button{-webkit-padding-start:15px;padding-inline-start:15px;-webkit-padding-end:15px;padding-inline-end:15px;padding-top:10px;padding-bottom:10px;position:relative;background-color:transparent;font-family:var(--ion-font-family);font-size:0.875rem;font-weight:500;letter-spacing:0.84px;text-transform:uppercase;overflow:hidden}.toast-button-cancel{color:var(--ion-color-step-100, var(--ion-text-color-step-900, #e6e6e6))}.toast-button-icon-only{border-radius:50%;-webkit-padding-start:9px;padding-inline-start:9px;-webkit-padding-end:9px;padding-inline-end:9px;padding-top:9px;padding-bottom:9px;width:36px;height:36px}@media (any-hover: hover){.toast-button:hover{background-color:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.08)}.toast-button-cancel:hover{background-color:rgba(var(--ion-background-color-rgb, 255, 255, 255), 0.08)}}";
// TODO(FW-2832): types
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @part button - Any button element that is displayed inside of the toast.
* @part button cancel - Any button element with role "cancel" that is displayed inside of the toast.
* @part container - The element that wraps all child elements.
* @part header - The header text of the toast.
* @part message - The body text of the toast.
* @part icon - The icon that appears next to the toast content.
*/
class Toast {
constructor(hostRef) {
registerInstance(this, hostRef);
this.didPresent = createEvent(this, "ionToastDidPresent", 7);
this.willPresent = createEvent(this, "ionToastWillPresent", 7);
this.willDismiss = createEvent(this, "ionToastWillDismiss", 7);
this.didDismiss = createEvent(this, "ionToastDidDismiss", 7);
this.didPresentShorthand = createEvent(this, "didPresent", 7);
this.willPresentShorthand = createEvent(this, "willPresent", 7);
this.willDismissShorthand = createEvent(this, "willDismiss", 7);
this.didDismissShorthand = createEvent(this, "didDismiss", 7);
this.delegateController = createDelegateController(this);
this.lockController = createLockController();
this.triggerController = createTriggerController();
this.customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
this.presented = false;
/**
* When `true`, content inside of .toast-content
* will have aria-hidden elements removed causing
* screen readers to announce the remaining content.
*/
this.revealContentToScreenReader = false;
/** @internal */
this.hasController = false;
/**
* How many milliseconds to wait before hiding the toast. By default, it will show
* until `dismiss()` is called.
*/
this.duration = config.getNumber('toastDuration', 0);
/**
* Defines how the message and buttons are laid out in the toast.
* 'baseline': The message and the buttons will appear on the same line.
* Message text may wrap within the message container.
* 'stacked': The buttons containers and message will stack on top
* of each other. Use this if you have long text in your buttons.
*/
this.layout = 'baseline';
/**
* If `true`, the keyboard will be automatically dismissed when the overlay is presented.
*/
this.keyboardClose = false;
/**
* The starting position of the toast on the screen. Can be tweaked further
* using the `positionAnchor` property.
*/
this.position = 'bottom';
/**
* If `true`, the toast will be translucent.
* Only applies when the mode is `"ios"` and the device supports
* [`backdrop-filter`](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter#Browser_compatibility).
*/
this.translucent = false;
/**
* If `true`, the toast will animate.
*/
this.animated = true;
/**
* If `true`, the toast will open. If `false`, the toast will close.
* Use this if you need finer grained control over presentation, otherwise
* just use the toastController or the `trigger` property.
* Note: `isOpen` will not automatically be set back to `false` when
* the toast dismisses. You will need to do that in your code.
*/
this.isOpen = false;
this.dispatchCancelHandler = (ev) => {
const role = ev.detail.role;
if (isCancel(role)) {
const cancelButton = this.getButtons().find((b) => b.role === 'cancel');
this.callButtonHandler(cancelButton);
}
};
/**
* Create a new swipe gesture so Toast
* can be swiped to dismiss.
*/
this.createSwipeGesture = (toastPosition) => {
const gesture = (this.gesture = createSwipeToDismissGesture(this.el, toastPosition, () => {
/**
* If the gesture completed then
* we should dismiss the toast.
*/
this.dismiss(undefined, GESTURE);
}));
gesture.enable(true);
};
/**
* Destroy an existing swipe gesture
* so Toast can no longer be swiped to dismiss.
*/
this.destroySwipeGesture = () => {
const { gesture } = this;
if (gesture === undefined) {
return;
}
gesture.destroy();
this.gesture = undefined;
};
/**
* Returns `true` if swipeGesture
* is configured to a value that enables the swipe behavior.
* Returns `false` otherwise.
*/
this.prefersSwipeGesture = () => {
const { swipeGesture } = this;
return swipeGesture === 'vertical';
};
}
swipeGestureChanged() {
/**
* If the Toast is presented, then we need to destroy
* any actives gestures before a new gesture is potentially
* created below.
*
* If the Toast is dismissed, then no gesture should be available
* since the Toast is not visible. This case should never
* happen since the "dismiss" method handles destroying
* any active swipe gestures, but we keep this code
* around to handle the first case.
*/
this.destroySwipeGesture();
/**
* A new swipe gesture should only be created
* if the Toast is presented. If the Toast is not
* yet presented then the "present" method will
* handle calling the swipe gesture setup function.
*/
if (this.presented && this.prefersSwipeGesture()) {
/**
* If the Toast is presented then
* lastPresentedPosition is defined.
*/
this.createSwipeGesture(this.lastPresentedPosition);
}
}
onIsOpenChange(newValue, oldValue) {
if (newValue === true && oldValue === false) {
this.present();
}
else if (newValue === false && oldValue === true) {
this.dismiss();
}
}
triggerChanged() {
const { trigger, el, triggerController } = this;
if (trigger) {
triggerController.addClickListener(el, trigger);
}
}
connectedCallback() {
prepareOverlay(this.el);
this.triggerChanged();
}
disconnectedCallback() {
this.triggerController.removeClickListener();
}
componentWillLoad() {
var _a;
if (!((_a = this.htmlAttributes) === null || _a === void 0 ? void 0 : _a.id)) {
setOverlayId(this.el);
}
}
componentDidLoad() {
/**
* If toast was rendered with isOpen="true"
* then we should open toast immediately.
*/
if (this.isOpen === true) {
raf(() => this.present());
}
/**
* When binding values in frameworks such as Angular
* it is possible for the value to be set after the Web Component
* initializes but before the value watcher is set up in Stencil.
* As a result, the watcher callback may not be fired.
* We work around this by manually calling the watcher
* callback when the component has loaded and the watcher
* is configured.
*/
this.triggerChanged();
}
/**
* Present the toast overlay after it has been created.
*/
async present() {
const unlock = await this.lockController.lock();
await this.delegateController.attachViewToDom();
const { el, position } = this;
const anchor = this.getAnchorElement();
const animationPosition = getAnimationPosition(position, anchor, getIonMode$1(this), el);
/**
* Cache the calculated position of the toast, so we can re-use it
* in the dismiss animation.
*/
this.lastPresentedPosition = animationPosition;
await present(this, 'toastEnter', iosEnterAnimation, mdEnterAnimation, {
position,
top: animationPosition.top,
bottom: animationPosition.bottom,
});
/**
* Content is revealed to screen readers after
* the transition to avoid jank since this
* state updates will cause a re-render.
*/
this.revealContentToScreenReader = true;
if (this.duration > 0) {
this.durationTimeout = setTimeout(() => this.dismiss(undefined, 'timeout'), this.duration);
}
/**
* If the Toast has a swipe gesture then we can
* create the gesture so users can swipe the
* presented Toast.
*/
if (this.prefersSwipeGesture()) {
this.createSwipeGesture(animationPosition);
}
unlock();
}
/**
* Dismiss the toast overlay after it has been presented.
* This is a no-op if the overlay has not been presented yet. If you want
* to remove an overlay from the DOM that was never presented, use the
* [remove](https://developer.mozilla.org/en-US/docs/Web/API/Element/remove) method.
*
* @param data Any data to emit in the dismiss events.
* @param role The role of the element that is dismissing the toast.
* This can be useful in a button handler for determining which button was
* clicked to dismiss the toast.
* Some examples include: `"cancel"`, `"destructive"`, `"selected"`, and `"backdrop"`.
*/
async dismiss(data, role) {
var _a, _b;
const unlock = await this.lockController.lock();
const { durationTimeout, position, lastPresentedPosition } = this;
if (durationTimeout) {
clearTimeout(durationTimeout);
}
const dismissed = await dismiss(this, data, role, 'toastLeave', iosLeaveAnimation, mdLeaveAnimation,
/**
* Fetch the cached position that was calculated back in the present
* animation. We always want to animate the dismiss from the same
* position the present stopped at, so the animation looks continuous.
*/
{
position,
top: (_a = lastPresentedPosition === null || lastPresentedPosition === void 0 ? void 0 : lastPresentedPosition.top) !== null && _a !== void 0 ? _a : '',
bottom: (_b = lastPresentedPosition === null || lastPresentedPosition === void 0 ? void 0 : lastPresentedPosition.bottom) !== null && _b !== void 0 ? _b : '',
});
if (dismissed) {
this.delegateController.removeViewFromDom();
this.revealContentToScreenReader = false;
}
this.lastPresentedPosition = undefined;
/**
* If the Toast has a swipe gesture then we can
* safely destroy it now that it is dismissed.
*/
this.destroySwipeGesture();
unlock();
return dismissed;
}
/**
* Returns a promise that resolves when the toast did dismiss.
*/
onDidDismiss() {
return eventMethod(this.el, 'ionToastDidDismiss');
}
/**
* Returns a promise that resolves when the toast will dismiss.
*/
onWillDismiss() {
return eventMethod(this.el, 'ionToastWillDismiss');
}
getButtons() {
const buttons = this.buttons
? this.buttons.map((b) => {
return typeof b === 'string' ? { text: b } : b;
})
: [];
return buttons;
}
/**
* Returns the element specified by the positionAnchor prop,
* or undefined if prop's value is an ID string and the element
* is not found in the DOM.
*/
getAnchorElement() {
const { position, positionAnchor, el } = this;
/**
* If positionAnchor is undefined then
* no anchor should be used when presenting the toast.
*/
if (positionAnchor === undefined) {
return;
}
if (position === 'middle' && positionAnchor !== undefined) {
printIonWarning('[ion-toast] - The positionAnchor property is ignored when using position="middle".', this.el);
return undefined;
}
if (typeof positionAnchor === 'string') {
/**
* If the anchor is defined as an ID, find the element.
* We do this on every present so the toast doesn't need
* to account for the surrounding DOM changing since the
* last time it was presented.
*/
const foundEl = document.getElementById(positionAnchor);
if (foundEl === null) {
printIonWarning(`[ion-toast] - An anchor element with an ID of "${positionAnchor}" was not found in the DOM.`, el);
return undefined;
}
return foundEl;
}
if (positionAnchor instanceof HTMLElement) {
return positionAnchor;
}
printIonWarning('[ion-toast] - Invalid positionAnchor value:', positionAnchor, el);
return undefined;
}
async buttonClick(button) {
const role = button.role;
if (isCancel(role)) {
return this.dismiss(undefined, role);
}
const shouldDismiss = await this.callButtonHandler(button);
if (shouldDismiss) {
return this.dismiss(undefined, role);
}
return Promise.resolve();
}
async callButtonHandler(button) {
if (button === null || button === void 0 ? void 0 : button.handler) {
// a handler has been provided, execute it
// pass the handler the values from the inputs
try {
const rtn = await safeCall(button.handler);
if (rtn === false) {
// if the return value of the handler is false then do not dismiss
return false;
}
}
catch (e) {
printIonError('[ion-toast] - Exception in callButtonHandler:', e);
}
}
return true;
}
renderButtons(buttons, side) {
if (buttons.length === 0) {
return;
}
const mode = getIonMode$1(this);
const buttonGroupsClasses = {
'toast-button-group': true,
[`toast-button-group-${side}`]: true,
};
return (hAsync("div", { class: buttonGroupsClasses }, buttons.map((b) => (hAsync("button", Object.assign({}, b.htmlAttributes, { type: "button", class: buttonClass(b), tabIndex: 0, onClick: () => this.buttonClick(b), part: buttonPart(b) }), hAsync("div", { class: "toast-button-inner" }, b.icon && (hAsync("ion-icon", { "aria-hidden": "true", icon: b.icon, slot: b.text === undefined ? 'icon-only' : undefined, class: "toast-button-icon" })), b.text), mode === 'md' && (hAsync("ion-ripple-effect", { type: b.icon !== undefined && b.text === undefined ? 'unbounded' : 'bounded' })))))));
}
/**
* Render the `message` property.
* @param key - A key to give the element a stable identity. This is used to improve compatibility with screen readers.
* @param ariaHidden - If "true" then content will be hidden from screen readers.
*/
renderToastMessage(key, ariaHidden = null) {
const { customHTMLEnabled, message } = this;
if (customHTMLEnabled) {
return (hAsync("div", { key: key, "aria-hidden": ariaHidden, class: "toast-message", part: "message", innerHTML: sanitizeDOMString(message) }));
}
return (hAsync("div", { key: key, "aria-hidden": ariaHidden, class: "toast-message", part: "message" }, message));
}
/**
* Render the `header` property.
* @param key - A key to give the element a stable identity. This is used to improve compatibility with screen readers.
* @param ariaHidden - If "true" then content will be hidden from screen readers.
*/
renderHeader(key, ariaHidden = null) {
return (hAsync("div", { key: key, class: "toast-header", "aria-hidden": ariaHidden, part: "header" }, this.header));
}
render() {
const { layout, el, revealContentToScreenReader, header, message } = this;
const allButtons = this.getButtons();
const startButtons = allButtons.filter((b) => b.side === 'start');
const endButtons = allButtons.filter((b) => b.side !== 'start');
const mode = getIonMode$1(this);
const wrapperClass = {
'toast-wrapper': true,
[`toast-${this.position}`]: true,
[`toast-layout-${layout}`]: true,
};
/**
* Stacked buttons are only meant to be
* used with one type of button.
*/
if (layout === 'stacked' && startButtons.length > 0 && endButtons.length > 0) {
printIonWarning('[ion-toast] - This toast is using start and end buttons with the stacked toast layout. We recommend following the best practice of using either start or end buttons with the stacked toast layout.', el);
}
return (hAsync(Host, Object.assign({ key: 'd1ecd90c87700aad4685e230cdd430aa286b8791', tabindex: "-1" }, this.htmlAttributes, { style: {
zIndex: `${60000 + this.overlayIndex}`,
}, class: createColorClasses$1(this.color, Object.assign(Object.assign({ [mode]: true }, getClassMap(this.cssClass)), { 'overlay-hidden': true, 'toast-translucent': this.translucent })), onIonToastWillDismiss: this.dispatchCancelHandler }), hAsync("div", { key: '4bfc863417324de69e222054d5cf9c452038b41e', class: wrapperClass }, hAsync("div", { key: '3417940afec0392e81b7d54c7cb00f3ab6c30d47', class: "toast-container", part: "container" }, this.renderButtons(startButtons, 'start'), this.icon !== undefined && (hAsync("ion-icon", { key: '6bf878fbc85c01e1e5faa9d97d46255a6511a952', class: "toast-icon", part: "icon", icon: this.icon, lazy: false, "aria-hidden": "true" })), hAsync("div", { key: '54b500348a9c37660c3aff37436d9188e4374947', class: "toast-content", role: "status", "aria-atomic": "true", "aria-live": "polite" }, !revealContentToScreenReader && header !== undefined && this.renderHeader('oldHeader', 'true'), !revealContentToScreenReader && message !== undefined && this.renderToastMessage('oldMessage', 'true'), revealContentToScreenReader && header !== undefined && this.renderHeader('header'), revealContentToScreenReader && message !== undefined && this.renderToastMessage('header')), this.renderButtons(endButtons, 'end')))));
}
get el() { return getElement(this); }
static get watchers() { return {
"swipeGesture": ["swipeGestureChanged"],
"isOpen": ["onIsOpenChange"],
"trigger": ["triggerChanged"]
}; }
static get style() { return {
ios: toastIosCss,
md: toastMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-toast",
"$members$": {
"overlayIndex": [2, "overlay-index"],
"delegate": [16],
"hasController": [4, "has-controller"],
"color": [513],
"enterAnimation": [16],
"leaveAnimation": [16],
"cssClass": [1, "css-class"],
"duration": [2],
"header": [1],
"layout": [1],
"message": [1],
"keyboardClose": [4, "keyboard-close"],
"position": [1],
"positionAnchor": [1, "position-anchor"],
"buttons": [16],
"translucent": [4],
"animated": [4],
"icon": [1],
"htmlAttributes": [16],
"swipeGesture": [1, "swipe-gesture"],
"isOpen": [4, "is-open"],
"trigger": [1],
"revealContentToScreenReader": [32],
"present": [64],
"dismiss": [64],
"onDidDismiss": [64],
"onWillDismiss": [64]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const buttonClass = (button) => {
return {
'toast-button': true,
'toast-button-icon-only': button.icon !== undefined && button.text === undefined,
[`toast-button-${button.role}`]: button.role !== undefined,
'ion-focusable': true,
'ion-activatable': true,
};
};
const buttonPart = (button) => {
return isCancel(button.role) ? 'button cancel' : 'button';
};
const toggleIosCss = ":host{-webkit-box-sizing:content-box !important;box-sizing:content-box !important;display:inline-block;position:relative;max-width:100%;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}:host(.ion-focused) input{border:2px solid #5e9ed6}:host(.toggle-disabled){pointer-events:none}input{display:none}.toggle-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.toggle-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.toggle-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.toggle-bottom{padding-top:4px;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;font-size:0.75rem;white-space:normal}:host(.toggle-label-placement-stacked) .toggle-bottom{font-size:1rem}.toggle-bottom .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.toggle-bottom .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}:host(.ion-touched.ion-invalid) .toggle-bottom .error-text{display:block}:host(.ion-touched.ion-invalid) .toggle-bottom .helper-text{display:none}:host(.toggle-label-placement-start) .toggle-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.toggle-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.toggle-label-placement-end) .toggle-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse;-ms-flex-pack:start;justify-content:start}:host(.toggle-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.toggle-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.toggle-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.toggle-label-placement-stacked) .toggle-wrapper{-ms-flex-direction:column;flex-direction:column;text-align:center}:host(.toggle-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.toggle-label-placement-stacked.toggle-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.toggle-label-placement-stacked.toggle-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).toggle-label-placement-stacked.toggle-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.toggle-label-placement-stacked.toggle-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.toggle-label-placement-stacked.toggle-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.toggle-label-placement-stacked.toggle-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).toggle-label-placement-stacked.toggle-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.toggle-label-placement-stacked.toggle-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host(.toggle-justify-space-between) .toggle-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.toggle-justify-start) .toggle-wrapper{-ms-flex-pack:start;justify-content:start}:host(.toggle-justify-end) .toggle-wrapper{-ms-flex-pack:end;justify-content:end}:host(.toggle-alignment-start) .toggle-wrapper{-ms-flex-align:start;align-items:start}:host(.toggle-alignment-center) .toggle-wrapper{-ms-flex-align:center;align-items:center}:host(.toggle-justify-space-between),:host(.toggle-justify-start),:host(.toggle-justify-end),:host(.toggle-alignment-start),:host(.toggle-alignment-center){display:block}.toggle-icon-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;width:100%;height:100%;-webkit-transition:var(--handle-transition);transition:var(--handle-transition);will-change:transform}.toggle-icon{border-radius:var(--border-radius);display:block;position:relative;width:100%;height:100%;background:var(--track-background);overflow:inherit}:host(.toggle-checked) .toggle-icon{background:var(--track-background-checked)}.toggle-inner{border-radius:var(--handle-border-radius);position:absolute;left:var(--handle-spacing);width:var(--handle-width);height:var(--handle-height);max-height:var(--handle-max-height);-webkit-transition:var(--handle-transition);transition:var(--handle-transition);background:var(--handle-background);-webkit-box-shadow:var(--handle-box-shadow);box-shadow:var(--handle-box-shadow);contain:strict}:host(.toggle-ltr) .toggle-inner{left:var(--handle-spacing)}:host(.toggle-rtl) .toggle-inner{right:var(--handle-spacing)}:host(.toggle-ltr.toggle-checked) .toggle-icon-wrapper{-webkit-transform:translate3d(calc(100% - var(--handle-width)), 0, 0);transform:translate3d(calc(100% - var(--handle-width)), 0, 0)}:host(.toggle-rtl.toggle-checked) .toggle-icon-wrapper{-webkit-transform:translate3d(calc(-100% + var(--handle-width)), 0, 0);transform:translate3d(calc(-100% + var(--handle-width)), 0, 0)}:host(.toggle-checked) .toggle-inner{background:var(--handle-background-checked)}:host(.toggle-ltr.toggle-checked) .toggle-inner{-webkit-transform:translate3d(calc(var(--handle-spacing) * -2), 0, 0);transform:translate3d(calc(var(--handle-spacing) * -2), 0, 0)}:host(.toggle-rtl.toggle-checked) .toggle-inner{-webkit-transform:translate3d(calc(var(--handle-spacing) * 2), 0, 0);transform:translate3d(calc(var(--handle-spacing) * 2), 0, 0)}:host{--track-background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.088);--track-background-checked:var(--ion-color-primary, #0054e9);--border-radius:15.5px;--handle-background:#ffffff;--handle-background-checked:#ffffff;--handle-border-radius:25.5px;--handle-box-shadow:0 3px 4px rgba(0, 0, 0, 0.06), 0 3px 8px rgba(0, 0, 0, 0.06);--handle-height:calc(31px - (2px * 2));--handle-max-height:calc(100% - var(--handle-spacing) * 2);--handle-width:calc(31px - (2px * 2));--handle-spacing:2px;--handle-transition:transform 300ms, width 120ms ease-in-out 80ms, left 110ms ease-in-out 80ms, right 110ms ease-in-out 80ms}.native-wrapper .toggle-icon{width:51px;height:31px;overflow:hidden}:host(.ion-color.toggle-checked) .toggle-icon{background:var(--ion-color-base)}:host(.toggle-activated) .toggle-switch-icon{opacity:0}.toggle-icon{-webkit-transform:translate3d(0, 0, 0);transform:translate3d(0, 0, 0);-webkit-transition:background-color 300ms;transition:background-color 300ms}.toggle-inner{will-change:transform}.toggle-switch-icon{position:absolute;top:50%;width:11px;height:11px;-webkit-transform:translateY(-50%);transform:translateY(-50%);-webkit-transition:opacity 300ms, color 300ms;transition:opacity 300ms, color 300ms}.toggle-switch-icon{position:absolute;color:var(--ion-color-dark, #222428)}:host(.toggle-ltr) .toggle-switch-icon{right:6px}:host(.toggle-rtl) .toggle-switch-icon{right:initial;left:6px;}:host(.toggle-checked) .toggle-switch-icon.toggle-switch-icon-checked{color:var(--ion-color-contrast, #fff)}:host(.toggle-checked) .toggle-switch-icon:not(.toggle-switch-icon-checked){opacity:0}.toggle-switch-icon-checked{position:absolute;width:15px;height:15px;-webkit-transform:translateY(-50%) rotate(90deg);transform:translateY(-50%) rotate(90deg)}:host(.toggle-ltr) .toggle-switch-icon-checked{right:initial;left:4px;}:host(.toggle-rtl) .toggle-switch-icon-checked{right:4px}:host(.toggle-activated) .toggle-icon::before,:host(.toggle-checked) .toggle-icon::before{-webkit-transform:scale3d(0, 0, 0);transform:scale3d(0, 0, 0)}:host(.toggle-activated.toggle-checked) .toggle-inner::before{-webkit-transform:scale3d(0, 0, 0);transform:scale3d(0, 0, 0)}:host(.toggle-activated) .toggle-inner{width:calc(var(--handle-width) + 6px)}:host(.toggle-ltr.toggle-activated.toggle-checked) .toggle-icon-wrapper{-webkit-transform:translate3d(calc(100% - var(--handle-width) - 6px), 0, 0);transform:translate3d(calc(100% - var(--handle-width) - 6px), 0, 0)}:host(.toggle-rtl.toggle-activated.toggle-checked) .toggle-icon-wrapper{-webkit-transform:translate3d(calc(-100% + var(--handle-width) + 6px), 0, 0);transform:translate3d(calc(-100% + var(--handle-width) + 6px), 0, 0)}:host(.toggle-disabled){opacity:0.3}";
const toggleMdCss = ":host{-webkit-box-sizing:content-box !important;box-sizing:content-box !important;display:inline-block;position:relative;max-width:100%;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:2}:host(.in-item){-ms-flex:1 1 0px;flex:1 1 0;width:100%;height:100%}:host([slot=start]),:host([slot=end]){-ms-flex:initial;flex:initial;width:auto}:host(.ion-focused) input{border:2px solid #5e9ed6}:host(.toggle-disabled){pointer-events:none}input{display:none}.toggle-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-positive:1;flex-grow:1;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;height:inherit;-webkit-transition:background-color 15ms linear;transition:background-color 15ms linear;cursor:inherit}.label-text-wrapper{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}:host(.in-item) .label-text-wrapper{margin-top:10px;margin-bottom:10px}:host(.in-item.toggle-label-placement-stacked) .label-text-wrapper{margin-top:10px;margin-bottom:16px}:host(.in-item.toggle-label-placement-stacked) .native-wrapper{margin-bottom:10px}.label-text-wrapper-hidden{display:none}.native-wrapper{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.toggle-bottom{padding-top:4px;display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;font-size:0.75rem;white-space:normal}:host(.toggle-label-placement-stacked) .toggle-bottom{font-size:1rem}.toggle-bottom .error-text{display:none;color:var(--ion-color-danger, #c5000f)}.toggle-bottom .helper-text{display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d))}:host(.ion-touched.ion-invalid) .toggle-bottom .error-text{display:block}:host(.ion-touched.ion-invalid) .toggle-bottom .helper-text{display:none}:host(.toggle-label-placement-start) .toggle-wrapper{-ms-flex-direction:row;flex-direction:row}:host(.toggle-label-placement-start) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.toggle-label-placement-end) .toggle-wrapper{-ms-flex-direction:row-reverse;flex-direction:row-reverse;-ms-flex-pack:start;justify-content:start}:host(.toggle-label-placement-end) .label-text-wrapper{-webkit-margin-start:16px;margin-inline-start:16px;-webkit-margin-end:0;margin-inline-end:0}:host(.toggle-label-placement-fixed) .label-text-wrapper{-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:16px;margin-inline-end:16px}:host(.toggle-label-placement-fixed) .label-text-wrapper{-ms-flex:0 0 100px;flex:0 0 100px;width:100px;min-width:100px;max-width:200px}:host(.toggle-label-placement-stacked) .toggle-wrapper{-ms-flex-direction:column;flex-direction:column;text-align:center}:host(.toggle-label-placement-stacked) .label-text-wrapper{-webkit-transform:scale(0.75);transform:scale(0.75);margin-left:0;margin-right:0;margin-bottom:16px;max-width:calc(100% / 0.75)}:host(.toggle-label-placement-stacked.toggle-alignment-start) .label-text-wrapper{-webkit-transform-origin:left top;transform-origin:left top}:host-context([dir=rtl]):host(.toggle-label-placement-stacked.toggle-alignment-start) .label-text-wrapper,:host-context([dir=rtl]).toggle-label-placement-stacked.toggle-alignment-start .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}@supports selector(:dir(rtl)){:host(.toggle-label-placement-stacked.toggle-alignment-start:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:right top;transform-origin:right top}}:host(.toggle-label-placement-stacked.toggle-alignment-center) .label-text-wrapper{-webkit-transform-origin:center top;transform-origin:center top}:host-context([dir=rtl]):host(.toggle-label-placement-stacked.toggle-alignment-center) .label-text-wrapper,:host-context([dir=rtl]).toggle-label-placement-stacked.toggle-alignment-center .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}@supports selector(:dir(rtl)){:host(.toggle-label-placement-stacked.toggle-alignment-center:dir(rtl)) .label-text-wrapper{-webkit-transform-origin:calc(100% - center) top;transform-origin:calc(100% - center) top}}:host(.toggle-justify-space-between) .toggle-wrapper{-ms-flex-pack:justify;justify-content:space-between}:host(.toggle-justify-start) .toggle-wrapper{-ms-flex-pack:start;justify-content:start}:host(.toggle-justify-end) .toggle-wrapper{-ms-flex-pack:end;justify-content:end}:host(.toggle-alignment-start) .toggle-wrapper{-ms-flex-align:start;align-items:start}:host(.toggle-alignment-center) .toggle-wrapper{-ms-flex-align:center;align-items:center}:host(.toggle-justify-space-between),:host(.toggle-justify-start),:host(.toggle-justify-end),:host(.toggle-alignment-start),:host(.toggle-alignment-center){display:block}.toggle-icon-wrapper{display:-ms-flexbox;display:flex;position:relative;-ms-flex-align:center;align-items:center;width:100%;height:100%;-webkit-transition:var(--handle-transition);transition:var(--handle-transition);will-change:transform}.toggle-icon{border-radius:var(--border-radius);display:block;position:relative;width:100%;height:100%;background:var(--track-background);overflow:inherit}:host(.toggle-checked) .toggle-icon{background:var(--track-background-checked)}.toggle-inner{border-radius:var(--handle-border-radius);position:absolute;left:var(--handle-spacing);width:var(--handle-width);height:var(--handle-height);max-height:var(--handle-max-height);-webkit-transition:var(--handle-transition);transition:var(--handle-transition);background:var(--handle-background);-webkit-box-shadow:var(--handle-box-shadow);box-shadow:var(--handle-box-shadow);contain:strict}:host(.toggle-ltr) .toggle-inner{left:var(--handle-spacing)}:host(.toggle-rtl) .toggle-inner{right:var(--handle-spacing)}:host(.toggle-ltr.toggle-checked) .toggle-icon-wrapper{-webkit-transform:translate3d(calc(100% - var(--handle-width)), 0, 0);transform:translate3d(calc(100% - var(--handle-width)), 0, 0)}:host(.toggle-rtl.toggle-checked) .toggle-icon-wrapper{-webkit-transform:translate3d(calc(-100% + var(--handle-width)), 0, 0);transform:translate3d(calc(-100% + var(--handle-width)), 0, 0)}:host(.toggle-checked) .toggle-inner{background:var(--handle-background-checked)}:host(.toggle-ltr.toggle-checked) .toggle-inner{-webkit-transform:translate3d(calc(var(--handle-spacing) * -2), 0, 0);transform:translate3d(calc(var(--handle-spacing) * -2), 0, 0)}:host(.toggle-rtl.toggle-checked) .toggle-inner{-webkit-transform:translate3d(calc(var(--handle-spacing) * 2), 0, 0);transform:translate3d(calc(var(--handle-spacing) * 2), 0, 0)}:host{--track-background:rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.39);--track-background-checked:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.5);--border-radius:14px;--handle-background:#ffffff;--handle-background-checked:var(--ion-color-primary, #0054e9);--handle-border-radius:50%;--handle-box-shadow:0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);--handle-width:20px;--handle-height:20px;--handle-max-height:calc(100% + 6px);--handle-spacing:0;--handle-transition:transform 160ms cubic-bezier(0.4, 0, 0.2, 1), background-color 160ms cubic-bezier(0.4, 0, 0.2, 1)}.native-wrapper .toggle-icon{width:36px;height:14px}:host(.ion-color.toggle-checked) .toggle-icon{background:rgba(var(--ion-color-base-rgb), 0.5)}:host(.ion-color.toggle-checked) .toggle-inner{background:var(--ion-color-base)}:host(.toggle-checked) .toggle-inner{color:var(--ion-color-contrast, #fff)}.toggle-icon{-webkit-transition:background-color 160ms;transition:background-color 160ms}.toggle-inner{will-change:background-color, transform;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center;color:#000}.toggle-inner .toggle-switch-icon{-webkit-padding-start:1px;padding-inline-start:1px;-webkit-padding-end:1px;padding-inline-end:1px;padding-top:1px;padding-bottom:1px;width:100%;height:100%}:host(.toggle-disabled){opacity:0.38}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - The label text to associate with the toggle. Use the "labelPlacement" property to control where the label is placed relative to the toggle.
*
* @part track - The background track of the toggle.
* @part handle - The toggle handle, or knob, used to change the checked state.
* @part label - The label text describing the toggle.
* @part supporting-text - Supporting text displayed beneath the toggle label.
* @part helper-text - Supporting text displayed beneath the toggle label when the toggle is valid.
* @part error-text - Supporting text displayed beneath the toggle label when the toggle is invalid and touched.
*/
class Toggle {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionChange = createEvent(this, "ionChange", 7);
this.ionFocus = createEvent(this, "ionFocus", 7);
this.ionBlur = createEvent(this, "ionBlur", 7);
this.inputId = `ion-tg-${toggleIds++}`;
this.inputLabelId = `${this.inputId}-lbl`;
this.helperTextId = `${this.inputId}-helper-text`;
this.errorTextId = `${this.inputId}-error-text`;
this.lastDrag = 0;
this.inheritedAttributes = {};
this.didLoad = false;
this.activated = false;
/**
* The name of the control, which is submitted with the form data.
*/
this.name = this.inputId;
/**
* If `true`, the toggle is selected.
*/
this.checked = false;
/**
* If `true`, the user cannot interact with the toggle.
*/
this.disabled = false;
/**
* The value of the toggle does not mean if it's checked or not, use the `checked`
* property for that.
*
* The value of a toggle is analogous to the value of a `<input type="checkbox">`,
* it's only used when the toggle participates in a native `<form>`.
*/
this.value = 'on';
/**
* Enables the on/off accessibility switch labels within the toggle.
*/
this.enableOnOffLabels = config.get('toggleOnOffLabels');
/**
* Where to place the label relative to the input.
* `"start"`: The label will appear to the left of the toggle in LTR and to the right in RTL.
* `"end"`: The label will appear to the right of the toggle in LTR and to the left in RTL.
* `"fixed"`: The label has the same behavior as `"start"` except it also has a fixed width. Long text will be truncated with ellipses ("...").
* `"stacked"`: The label will appear above the toggle regardless of the direction. The alignment of the label can be controlled with the `alignment` property.
*/
this.labelPlacement = 'start';
/**
* If true, screen readers will announce it as a required field. This property
* works only for accessibility purposes, it will not prevent the form from
* submitting if the value is invalid.
*/
this.required = false;
this.setupGesture = async () => {
const { toggleTrack } = this;
if (toggleTrack) {
this.gesture = (await Promise.resolve().then(function () { return index; })).createGesture({
el: toggleTrack,
gestureName: 'toggle',
gesturePriority: 100,
threshold: 5,
passive: false,
onStart: () => this.onStart(),
onMove: (ev) => this.onMove(ev),
onEnd: (ev) => this.onEnd(ev),
});
this.disabledChanged();
}
};
this.onKeyDown = (ev) => {
if (ev.key === ' ') {
ev.preventDefault();
if (!this.disabled) {
this.toggleChecked();
}
}
};
this.onClick = (ev) => {
/**
* The haptics for the toggle on tap is
* an iOS-only feature. As such, it should
* only trigger on iOS.
*/
const enableHaptics = isPlatform('ios');
if (this.disabled) {
return;
}
ev.preventDefault();
if (this.lastDrag + 300 < Date.now()) {
this.toggleChecked();
enableHaptics && hapticSelection();
}
};
/**
* Stops propagation when the display label is clicked,
* otherwise, two clicks will be triggered.
*/
this.onDivLabelClick = (ev) => {
ev.stopPropagation();
};
this.onFocus = () => {
this.ionFocus.emit();
};
this.onBlur = () => {
this.ionBlur.emit();
};
this.getSwitchLabelIcon = (mode, checked) => {
if (mode === 'md') {
return checked ? checkmarkOutline : removeOutline;
}
return checked ? removeOutline : ellipseOutline;
};
}
disabledChanged() {
if (this.gesture) {
this.gesture.enable(!this.disabled);
}
}
toggleChecked() {
const { checked, value } = this;
const isNowChecked = !checked;
this.checked = isNowChecked;
this.ionChange.emit({
checked: isNowChecked,
value,
});
}
async connectedCallback() {
/**
* If we have not yet rendered
* ion-toggle, then toggleTrack is not defined.
* But if we are moving ion-toggle via appendChild,
* then toggleTrack will be defined.
*/
if (this.didLoad) {
this.setupGesture();
}
}
componentDidLoad() {
this.setupGesture();
this.didLoad = true;
}
disconnectedCallback() {
if (this.gesture) {
this.gesture.destroy();
this.gesture = undefined;
}
}
componentWillLoad() {
this.inheritedAttributes = Object.assign({}, inheritAriaAttributes(this.el));
}
onStart() {
this.activated = true;
// touch-action does not work in iOS
this.setFocus();
}
onMove(detail) {
if (shouldToggle(isRTL$1(this.el), this.checked, detail.deltaX, -10)) {
this.toggleChecked();
hapticSelection();
}
}
onEnd(ev) {
this.activated = false;
this.lastDrag = Date.now();
ev.event.preventDefault();
ev.event.stopImmediatePropagation();
}
getValue() {
return this.value || '';
}
setFocus() {
this.el.focus();
}
renderOnOffSwitchLabels(mode, checked) {
const icon = this.getSwitchLabelIcon(mode, checked);
return (hAsync("ion-icon", { class: {
'toggle-switch-icon': true,
'toggle-switch-icon-checked': checked,
}, icon: icon, "aria-hidden": "true" }));
}
renderToggleControl() {
const mode = getIonMode$1(this);
const { enableOnOffLabels, checked } = this;
return (hAsync("div", { class: "toggle-icon", part: "track", ref: (el) => (this.toggleTrack = el) }, enableOnOffLabels &&
mode === 'ios' && [this.renderOnOffSwitchLabels(mode, true), this.renderOnOffSwitchLabels(mode, false)], hAsync("div", { class: "toggle-icon-wrapper" }, hAsync("div", { class: "toggle-inner", part: "handle" }, enableOnOffLabels && mode === 'md' && this.renderOnOffSwitchLabels(mode, checked)))));
}
get hasLabel() {
return this.el.textContent !== '';
}
getHintTextID() {
const { el, helperText, errorText, helperTextId, errorTextId } = this;
if (el.classList.contains('ion-touched') && el.classList.contains('ion-invalid') && errorText) {
return errorTextId;
}
if (helperText) {
return helperTextId;
}
return undefined;
}
/**
* Responsible for rendering helper text and error text.
* This element should only be rendered if hint text is set.
*/
renderHintText() {
const { helperText, errorText, helperTextId, errorTextId } = this;
/**
* undefined and empty string values should
* be treated as not having helper/error text.
*/
const hasHintText = !!helperText || !!errorText;
if (!hasHintText) {
return;
}
return (hAsync("div", { class: "toggle-bottom" }, hAsync("div", { id: helperTextId, class: "helper-text", part: "supporting-text helper-text" }, helperText), hAsync("div", { id: errorTextId, class: "error-text", part: "supporting-text error-text" }, errorText)));
}
render() {
const { activated, alignment, checked, color, disabled, el, errorTextId, hasLabel, inheritedAttributes, inputId, inputLabelId, justify, labelPlacement, name, required, } = this;
const mode = getIonMode$1(this);
const value = this.getValue();
const rtl = isRTL$1(el) ? 'rtl' : 'ltr';
renderHiddenInput(true, el, name, checked ? value : '', disabled);
return (hAsync(Host, { key: '17bbbc8d229868e5c872b2bc5a3faf579780c5e0', role: "switch", "aria-checked": `${checked}`, "aria-describedby": this.getHintTextID(), "aria-invalid": this.getHintTextID() === errorTextId, onClick: this.onClick, "aria-labelledby": hasLabel ? inputLabelId : null, "aria-label": inheritedAttributes['aria-label'] || null, "aria-disabled": disabled ? 'true' : null, tabindex: disabled ? undefined : 0, onKeyDown: this.onKeyDown, onFocus: this.onFocus, onBlur: this.onBlur, class: createColorClasses$1(color, {
[mode]: true,
'in-item': hostContext('ion-item', el),
'toggle-activated': activated,
'toggle-checked': checked,
'toggle-disabled': disabled,
[`toggle-justify-${justify}`]: justify !== undefined,
[`toggle-alignment-${alignment}`]: alignment !== undefined,
[`toggle-label-placement-${labelPlacement}`]: true,
[`toggle-${rtl}`]: true,
}) }, hAsync("label", { key: '673625b62a2c909e95dccb642c91312967a6cd1c', class: "toggle-wrapper", htmlFor: inputId }, hAsync("input", Object.assign({ key: '7dc3f357b4708116663970047765da9f8f845bf0', type: "checkbox", role: "switch", "aria-checked": `${checked}`, checked: checked, disabled: disabled, id: inputId, required: required }, inheritedAttributes)), hAsync("div", { key: '8f1c6a182031e8cbc6727e5f4ac0e00ad4247447', class: {
'label-text-wrapper': true,
'label-text-wrapper-hidden': !hasLabel,
}, part: "label", id: inputLabelId, onClick: this.onDivLabelClick }, hAsync("slot", { key: '8322b9d54dc7edeb4e16fefcde9f7ebca8d5c3e1' }), this.renderHintText()), hAsync("div", { key: 'fe6984143db817a7b3020a3f57cf5418fc3dcc0e', class: "native-wrapper" }, this.renderToggleControl()))));
}
get el() { return getElement(this); }
static get watchers() { return {
"disabled": ["disabledChanged"]
}; }
static get style() { return {
ios: toggleIosCss,
md: toggleMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-toggle",
"$members$": {
"color": [513],
"name": [1],
"checked": [1028],
"disabled": [4],
"errorText": [1, "error-text"],
"helperText": [1, "helper-text"],
"value": [1],
"enableOnOffLabels": [4, "enable-on-off-labels"],
"labelPlacement": [1, "label-placement"],
"justify": [1],
"alignment": [1],
"required": [4],
"activated": [32]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const shouldToggle = (rtl, checked, deltaX, margin) => {
if (checked) {
return (!rtl && margin > deltaX) || (rtl && 10 < deltaX);
}
else {
return (!rtl && 10 < deltaX) || (rtl && margin > deltaX);
}
};
let toggleIds = 0;
const toolbarIosCss = ":host{--border-width:0;--border-style:solid;--opacity:1;--opacity-scale:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:block;position:relative;width:100%;padding-right:var(--ion-safe-area-right);padding-left:var(--ion-safe-area-left);color:var(--color);font-family:var(--ion-font-family, inherit);contain:content;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.ion-color){color:var(--ion-color-contrast)}:host(.ion-color) .toolbar-background{background:var(--ion-color-base)}.toolbar-container{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;min-height:var(--min-height);contain:content;overflow:hidden;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}.toolbar-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);contain:strict;opacity:calc(var(--opacity) * var(--opacity-scale));z-index:-1;pointer-events:none}::slotted(ion-progress-bar){left:0;right:0;bottom:0;position:absolute}:host{--background:var(--ion-toolbar-background, var(--ion-color-step-50, var(--ion-background-color-step-50, #f7f7f7)));--color:var(--ion-toolbar-color, var(--ion-text-color, #000));--border-color:var(--ion-toolbar-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, rgba(0, 0, 0, 0.2)))));--padding-top:3px;--padding-bottom:3px;--padding-start:4px;--padding-end:4px;--min-height:44px}.toolbar-content{-ms-flex:1;flex:1;-ms-flex-order:4;order:4;min-width:0}:host(.toolbar-segment) .toolbar-content{display:-ms-inline-flexbox;display:inline-flex}:host(.toolbar-searchbar) .toolbar-container{padding-top:0;padding-bottom:0}:host(.toolbar-searchbar) ::slotted(*){-ms-flex-item-align:start;align-self:start}:host(.toolbar-searchbar) ::slotted(ion-chip){margin-top:3px}::slotted(ion-buttons){min-height:38px}::slotted([slot=start]){-ms-flex-order:2;order:2}::slotted([slot=secondary]){-ms-flex-order:3;order:3}::slotted([slot=primary]){-ms-flex-order:5;order:5;text-align:end}::slotted([slot=end]){-ms-flex-order:6;order:6;text-align:end}:host(.toolbar-title-large) .toolbar-container{-ms-flex-wrap:wrap;flex-wrap:wrap;-ms-flex-align:start;align-items:flex-start}:host(.toolbar-title-large) .toolbar-content ion-title{-ms-flex:1;flex:1;-ms-flex-order:8;order:8;min-width:100%}";
const toolbarMdCss = ":host{--border-width:0;--border-style:solid;--opacity:1;--opacity-scale:1;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:block;position:relative;width:100%;padding-right:var(--ion-safe-area-right);padding-left:var(--ion-safe-area-left);color:var(--color);font-family:var(--ion-font-family, inherit);contain:content;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}:host(.ion-color){color:var(--ion-color-contrast)}:host(.ion-color) .toolbar-background{background:var(--ion-color-base)}.toolbar-container{-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);display:-ms-flexbox;display:flex;position:relative;-ms-flex-direction:row;flex-direction:row;-ms-flex-align:center;align-items:center;-ms-flex-pack:justify;justify-content:space-between;width:100%;min-height:var(--min-height);contain:content;overflow:hidden;z-index:10;-webkit-box-sizing:border-box;box-sizing:border-box}.toolbar-background{left:0;right:0;top:0;bottom:0;position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0);border-width:var(--border-width);border-style:var(--border-style);border-color:var(--border-color);background:var(--background);contain:strict;opacity:calc(var(--opacity) * var(--opacity-scale));z-index:-1;pointer-events:none}::slotted(ion-progress-bar){left:0;right:0;bottom:0;position:absolute}:host{--background:var(--ion-toolbar-background, var(--ion-background-color, #fff));--color:var(--ion-toolbar-color, var(--ion-text-color, #424242));--border-color:var(--ion-toolbar-border-color, var(--ion-border-color, var(--ion-color-step-150, var(--ion-background-color-step-150, #c1c4cd))));--padding-top:0;--padding-bottom:0;--padding-start:0;--padding-end:0;--min-height:56px}.toolbar-content{-ms-flex:1;flex:1;-ms-flex-order:3;order:3;min-width:0;max-width:100%}::slotted(.buttons-first-slot){-webkit-margin-start:4px;margin-inline-start:4px}::slotted(.buttons-last-slot){-webkit-margin-end:4px;margin-inline-end:4px}::slotted([slot=start]){-ms-flex-order:2;order:2}::slotted([slot=secondary]){-ms-flex-order:4;order:4}::slotted([slot=primary]){-ms-flex-order:5;order:5;text-align:end}::slotted([slot=end]){-ms-flex-order:6;order:6;text-align:end}";
/**
* @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use.
*
* @slot - Content is placed between the named slots if provided without a slot.
* @slot start - Content is placed to the left of the toolbar text in LTR, and to the right in RTL.
* @slot secondary - Content is placed to the left of the toolbar text in `ios` mode, and directly to the right in `md` mode.
* @slot primary - Content is placed to the right of the toolbar text in `ios` mode, and to the far right in `md` mode.
* @slot end - Content is placed to the right of the toolbar text in LTR, and to the left in RTL.
*
* @part background - The background of the toolbar, covering the entire area behind the toolbar content.
* @part container - The container that wraps all toolbar content, including the default slot and named slot content.
* @part content - The container for the default slot, wrapping content provided without a named slot.
*/
class Toolbar {
constructor(hostRef) {
registerInstance(this, hostRef);
this.childrenStyles = new Map();
}
componentWillLoad() {
const buttons = Array.from(this.el.querySelectorAll('ion-buttons'));
const firstButtons = buttons.find((button) => {
return button.slot === 'start';
});
if (firstButtons) {
firstButtons.classList.add('buttons-first-slot');
}
const buttonsReversed = buttons.reverse();
const lastButtons = buttonsReversed.find((button) => button.slot === 'end') ||
buttonsReversed.find((button) => button.slot === 'primary') ||
buttonsReversed.find((button) => button.slot === 'secondary');
if (lastButtons) {
lastButtons.classList.add('buttons-last-slot');
}
}
childrenStyle(ev) {
ev.stopPropagation();
const tagName = ev.target.tagName;
const updatedStyles = ev.detail;
const newStyles = {};
const childStyles = this.childrenStyles.get(tagName) || {};
let hasStyleChange = false;
Object.keys(updatedStyles).forEach((key) => {
const childKey = `toolbar-${key}`;
const newValue = updatedStyles[key];
if (newValue !== childStyles[childKey]) {
hasStyleChange = true;
}
if (newValue) {
newStyles[childKey] = true;
}
});
if (hasStyleChange) {
this.childrenStyles.set(tagName, newStyles);
}
}
render() {
const mode = getIonMode$1(this);
const childStyles = {};
this.childrenStyles.forEach((value) => {
Object.assign(childStyles, value);
});
return (hAsync(Host, { key: 'f6c4f669a6a61c5eac4cbb5ea0aa97c48ae5bd46', class: Object.assign(Object.assign({}, childStyles), createColorClasses$1(this.color, {
[mode]: true,
'in-toolbar': hostContext('ion-toolbar', this.el),
})) }, hAsync("div", { key: '9c81742ffa02de9ba7417025b077d05e67305074', class: "toolbar-background", part: "background" }), hAsync("div", { key: '5fc96d166fa47894a062e41541a9beee38078a36', class: "toolbar-container", part: "container" }, hAsync("slot", { key: 'b62c0d9d59a70176bdbf769aec6090d7a166853b', name: "start" }), hAsync("slot", { key: 'd01d3cc2c50e5aaa49c345b209fe8dbdf3d48131', name: "secondary" }), hAsync("div", { key: '3aaa3a2810aedd38c37eb616158ec7b9638528fc', class: "toolbar-content", part: "content" }, hAsync("slot", { key: '357246690f8d5e1cc3ca369611d4845a79edf610' })), hAsync("slot", { key: '06ed3cca4f7ebff4a54cd877dad3cc925ccf9f75', name: "primary" }), hAsync("slot", { key: 'e453d43d14a26b0d72f41e1b81a554bab8ece811', name: "end" }))));
}
get el() { return getElement(this); }
static get style() { return {
ios: toolbarIosCss,
md: toolbarMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-toolbar",
"$members$": {
"color": [513]
},
"$listeners$": [[0, "ionStyle", "childrenStyle"]],
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
const titleIosCss = ":host{--color:initial;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}.toolbar-title{display:block;width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;pointer-events:auto}:host(.title-small) .toolbar-title{white-space:normal}:host{top:0;-webkit-padding-start:90px;padding-inline-start:90px;-webkit-padding-end:90px;padding-inline-end:90px;padding-top:var(--padding-top);padding-bottom:var(--padding-bottom);position:absolute;width:100%;height:100%;-webkit-transform:translateZ(0);transform:translateZ(0);font-size:min(1.0625rem, 20.4px);font-weight:600;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;pointer-events:none}:host{inset-inline-start:0}:host(.title-small){-webkit-padding-start:9px;padding-inline-start:9px;-webkit-padding-end:9px;padding-inline-end:9px;padding-top:6px;padding-bottom:16px;position:relative;font-size:min(0.8125rem, 23.4px);font-weight:normal}:host(.title-large){-webkit-padding-start:12px;padding-inline-start:12px;-webkit-padding-end:12px;padding-inline-end:12px;padding-top:2px;padding-bottom:4px;-webkit-transform-origin:left center;transform-origin:left center;position:static;-ms-flex-align:end;align-items:flex-end;min-width:100%;font-size:min(2.125rem, 61.2px);font-weight:700;text-align:start}:host(.title-large.title-rtl){-webkit-transform-origin:right center;transform-origin:right center}:host(.title-large.ion-cloned-element){--color:var(--ion-text-color, #000);font-family:var(--ion-font-family)}:host(.title-large) .toolbar-title{-webkit-transform-origin:inherit;transform-origin:inherit;width:auto}:host-context([dir=rtl]):host(.title-large) .toolbar-title,:host-context([dir=rtl]).title-large .toolbar-title{-webkit-transform-origin:calc(100% - inherit);transform-origin:calc(100% - inherit)}@supports selector(:dir(rtl)){:host(.title-large:dir(rtl)) .toolbar-title{-webkit-transform-origin:calc(100% - inherit);transform-origin:calc(100% - inherit)}}";
const titleMdCss = ":host{--color:initial;display:-ms-flexbox;display:flex;-ms-flex:1;flex:1;-ms-flex-align:center;align-items:center;-webkit-transform:translateZ(0);transform:translateZ(0);color:var(--color)}:host(.ion-color){color:var(--ion-color-base)}.toolbar-title{display:block;width:100%;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;pointer-events:auto}:host(.title-small) .toolbar-title{white-space:normal}:host{-webkit-padding-start:20px;padding-inline-start:20px;-webkit-padding-end:20px;padding-inline-end:20px;padding-top:0;padding-bottom:0;font-size:1.25rem;font-weight:500;letter-spacing:0.0125em}:host(.title-small){width:100%;height:100%;font-size:0.9375rem;font-weight:normal}";
class ToolbarTitle {
constructor(hostRef) {
registerInstance(this, hostRef);
this.ionStyle = createEvent(this, "ionStyle", 7);
}
sizeChanged() {
this.emitStyle();
}
connectedCallback() {
this.emitStyle();
}
emitStyle() {
const size = this.getSize();
this.ionStyle.emit({
[`title-${size}`]: true,
});
}
getSize() {
return this.size !== undefined ? this.size : 'default';
}
render() {
const mode = getIonMode$1(this);
const size = this.getSize();
return (hAsync(Host, { key: 'e599c0bf1b0817df3fa8360bdcd6d787f751c371', class: createColorClasses$1(this.color, {
[mode]: true,
[`title-${size}`]: true,
'title-rtl': document.dir === 'rtl',
}) }, hAsync("div", { key: '6e7eee9047d6759876bb31d7305b76efc7c4338c', class: "toolbar-title" }, hAsync("slot", { key: 'bf790eb4c83dd0af4f2fd1f85ab4af5819f46ff4' }))));
}
get el() { return getElement(this); }
static get watchers() { return {
"size": ["sizeChanged"]
}; }
static get style() { return {
ios: titleIosCss,
md: titleMdCss
}; }
static get cmpMeta() { return {
"$flags$": 297,
"$tagName$": "ion-title",
"$members$": {
"color": [513],
"size": [1]
},
"$listeners$": undefined,
"$lazyBundleId$": "-",
"$attrsToReflect$": [["color", "color"]]
}; }
}
registerComponents([
Accordion,
AccordionGroup,
ActionSheet,
Alert,
App,
Avatar,
BackButton,
Backdrop,
Badge,
Breadcrumb,
Breadcrumbs,
Button,
Buttons,
Card,
CardContent,
CardHeader,
CardSubtitle,
CardTitle,
Checkbox,
Chip,
Col,
Content,
Datetime,
DatetimeButton,
Fab,
FabButton,
FabList,
Footer,
Grid,
Header,
Icon,
Img,
InfiniteScroll,
InfiniteScrollContent,
Input,
InputOTP,
InputPasswordToggle,
Item,
ItemDivider,
ItemGroup,
ItemOption,
ItemOptions,
ItemSliding,
Label,
List,
ListHeader,
Loading,
Menu,
MenuButton,
MenuToggle,
Modal,
Nav,
NavLink,
Note,
Picker$1,
Picker,
PickerColumn,
PickerColumnCmp,
PickerColumnOption,
Popover,
ProgressBar,
Radio,
RadioGroup,
Range,
Refresher,
RefresherContent,
Reorder,
ReorderGroup,
RippleEffect,
Route,
RouteRedirect,
Router,
RouterLink,
RouterOutlet,
Row,
Searchbar,
Segment,
SegmentButton,
SegmentContent,
SegmentView,
Select,
SelectModal,
SelectOption,
SelectPopover,
SkeletonText,
Spinner,
SplitPane,
Tab,
TabBar,
TabButton,
Tabs,
Text,
Textarea,
Thumbnail,
Toast,
Toggle,
Toolbar,
ToolbarTitle,
]);
const DURATION = 540;
// TODO(FW-2832): types
const getClonedElement = (tagName) => {
return document.querySelector(`${tagName}.ion-cloned-element`);
};
const shadow = (el) => {
return el.shadowRoot || el;
};
const getLargeTitle = (refEl) => {
const tabs = refEl.tagName === 'ION-TABS' ? refEl : refEl.querySelector('ion-tabs');
const query = 'ion-content ion-header:not(.header-collapse-condense-inactive) ion-title.title-large';
if (tabs != null) {
const activeTab = tabs.querySelector('ion-tab:not(.tab-hidden), .ion-page:not(.ion-page-hidden)');
return activeTab != null ? activeTab.querySelector(query) : null;
}
return refEl.querySelector(query);
};
const getBackButton = (refEl, backDirection) => {
const tabs = refEl.tagName === 'ION-TABS' ? refEl : refEl.querySelector('ion-tabs');
let buttonsList = [];
if (tabs != null) {
const activeTab = tabs.querySelector('ion-tab:not(.tab-hidden), .ion-page:not(.ion-page-hidden)');
if (activeTab != null) {
buttonsList = activeTab.querySelectorAll('ion-buttons');
}
}
else {
buttonsList = refEl.querySelectorAll('ion-buttons');
}
for (const buttons of buttonsList) {
const parentHeader = buttons.closest('ion-header');
const activeHeader = parentHeader && !parentHeader.classList.contains('header-collapse-condense-inactive');
const backButton = buttons.querySelector('ion-back-button');
const buttonsCollapse = buttons.classList.contains('buttons-collapse');
const startSlot = buttons.slot === 'start' || buttons.slot === '';
if (backButton !== null && startSlot && ((buttonsCollapse && activeHeader && backDirection) || !buttonsCollapse)) {
return backButton;
}
}
return null;
};
const createLargeTitleTransition = (rootAnimation, rtl, backDirection, enteringEl, leavingEl) => {
const enteringBackButton = getBackButton(enteringEl, backDirection);
const leavingLargeTitle = getLargeTitle(leavingEl);
const enteringLargeTitle = getLargeTitle(enteringEl);
const leavingBackButton = getBackButton(leavingEl, backDirection);
const shouldAnimationForward = enteringBackButton !== null && leavingLargeTitle !== null && !backDirection;
const shouldAnimationBackward = enteringLargeTitle !== null && leavingBackButton !== null && backDirection;
if (shouldAnimationForward) {
const leavingLargeTitleBox = leavingLargeTitle.getBoundingClientRect();
const enteringBackButtonBox = enteringBackButton.getBoundingClientRect();
const enteringBackButtonTextEl = shadow(enteringBackButton).querySelector('.button-text');
// Text element not rendered if developers pass text="" to the back button
const enteringBackButtonTextBox = enteringBackButtonTextEl === null || enteringBackButtonTextEl === void 0 ? void 0 : enteringBackButtonTextEl.getBoundingClientRect();
const leavingLargeTitleTextEl = shadow(leavingLargeTitle).querySelector('.toolbar-title');
const leavingLargeTitleTextBox = leavingLargeTitleTextEl.getBoundingClientRect();
animateLargeTitle(rootAnimation, rtl, backDirection, leavingLargeTitle, leavingLargeTitleBox, leavingLargeTitleTextBox, enteringBackButtonBox, enteringBackButtonTextEl, enteringBackButtonTextBox);
animateBackButton(rootAnimation, rtl, backDirection, enteringBackButton, enteringBackButtonBox, enteringBackButtonTextEl, enteringBackButtonTextBox, leavingLargeTitle, leavingLargeTitleTextBox);
}
else if (shouldAnimationBackward) {
const enteringLargeTitleBox = enteringLargeTitle.getBoundingClientRect();
const leavingBackButtonBox = leavingBackButton.getBoundingClientRect();
const leavingBackButtonTextEl = shadow(leavingBackButton).querySelector('.button-text');
// Text element not rendered if developers pass text="" to the back button
const leavingBackButtonTextBox = leavingBackButtonTextEl === null || leavingBackButtonTextEl === void 0 ? void 0 : leavingBackButtonTextEl.getBoundingClientRect();
const enteringLargeTitleTextEl = shadow(enteringLargeTitle).querySelector('.toolbar-title');
const enteringLargeTitleTextBox = enteringLargeTitleTextEl.getBoundingClientRect();
animateLargeTitle(rootAnimation, rtl, backDirection, enteringLargeTitle, enteringLargeTitleBox, enteringLargeTitleTextBox, leavingBackButtonBox, leavingBackButtonTextEl, leavingBackButtonTextBox);
animateBackButton(rootAnimation, rtl, backDirection, leavingBackButton, leavingBackButtonBox, leavingBackButtonTextEl, leavingBackButtonTextBox, enteringLargeTitle, enteringLargeTitleTextBox);
}
return {
forward: shouldAnimationForward,
backward: shouldAnimationBackward,
};
};
const animateBackButton = (rootAnimation, rtl, backDirection, backButtonEl, backButtonBox, backButtonTextEl, backButtonTextBox, largeTitleEl, largeTitleTextBox) => {
var _a, _b;
const BACK_BUTTON_START_OFFSET = rtl ? `calc(100% - ${backButtonBox.right + 4}px)` : `${backButtonBox.left - 4}px`;
const TEXT_ORIGIN_X = rtl ? 'right' : 'left';
const ICON_ORIGIN_X = rtl ? 'left' : 'right';
const CONTAINER_ORIGIN_X = rtl ? 'right' : 'left';
let WIDTH_SCALE = 1;
let HEIGHT_SCALE = 1;
let TEXT_START_SCALE = `scale(${HEIGHT_SCALE})`;
const TEXT_END_SCALE = 'scale(1)';
if (backButtonTextEl && backButtonTextBox) {
/**
* When the title and back button texts match then they should overlap during the
* page transition. If the texts do not match up then the back button text scale
* adjusts to not perfectly match the large title text otherwise the proportions
* will be incorrect. When the texts match we scale both the width and height to
* account for font weight differences between the title and back button.
*/
const doTitleAndButtonTextsMatch = ((_a = backButtonTextEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = largeTitleEl.textContent) === null || _b === void 0 ? void 0 : _b.trim());
WIDTH_SCALE = largeTitleTextBox.width / backButtonTextBox.width;
/**
* Subtract an offset to account for slight sizing/padding differences between the
* title and the back button.
*/
HEIGHT_SCALE = (largeTitleTextBox.height - LARGE_TITLE_SIZE_OFFSET) / backButtonTextBox.height;
/**
* Even though we set TEXT_START_SCALE to HEIGHT_SCALE above, we potentially need
* to re-compute this here since the HEIGHT_SCALE may have changed.
*/
TEXT_START_SCALE = doTitleAndButtonTextsMatch ? `scale(${WIDTH_SCALE}, ${HEIGHT_SCALE})` : `scale(${HEIGHT_SCALE})`;
}
const backButtonIconEl = shadow(backButtonEl).querySelector('ion-icon');
const backButtonIconBox = backButtonIconEl.getBoundingClientRect();
/**
* We need to offset the container by the icon dimensions
* so that the back button text aligns with the large title
* text. Otherwise, the back button icon will align with the
* large title text but the back button text will not.
*/
const CONTAINER_START_TRANSLATE_X = rtl
? `${backButtonIconBox.width / 2 - (backButtonIconBox.right - backButtonBox.right)}px`
: `${backButtonBox.left - backButtonIconBox.width / 2}px`;
const CONTAINER_END_TRANSLATE_X = rtl ? `-${window.innerWidth - backButtonBox.right}px` : `${backButtonBox.left}px`;
/**
* Back button container should be
* aligned to the top of the title container
* so the texts overlap as the back button
* text begins to fade in.
*/
const CONTAINER_START_TRANSLATE_Y = `${largeTitleTextBox.top}px`;
/**
* The cloned back button should align exactly with the
* real back button on the entering page otherwise there will
* be a layout shift.
*/
const CONTAINER_END_TRANSLATE_Y = `${backButtonBox.top}px`;
/**
* In the forward direction, the cloned back button
* container should translate from over the large title
* to over the back button. In the backward direction,
* it should translate from over the back button to over
* the large title.
*/
const FORWARD_CONTAINER_KEYFRAMES = [
{ offset: 0, transform: `translate3d(${CONTAINER_START_TRANSLATE_X}, ${CONTAINER_START_TRANSLATE_Y}, 0)` },
{ offset: 1, transform: `translate3d(${CONTAINER_END_TRANSLATE_X}, ${CONTAINER_END_TRANSLATE_Y}, 0)` },
];
const BACKWARD_CONTAINER_KEYFRAMES = [
{ offset: 0, transform: `translate3d(${CONTAINER_END_TRANSLATE_X}, ${CONTAINER_END_TRANSLATE_Y}, 0)` },
{ offset: 1, transform: `translate3d(${CONTAINER_START_TRANSLATE_X}, ${CONTAINER_START_TRANSLATE_Y}, 0)` },
];
const CONTAINER_KEYFRAMES = backDirection ? BACKWARD_CONTAINER_KEYFRAMES : FORWARD_CONTAINER_KEYFRAMES;
/**
* In the forward direction, the text in the cloned back button
* should start to be (roughly) the size of the large title
* and then scale down to be the size of the actual back button.
* The text should also translate, but that translate is handled
* by the container keyframes.
*/
const FORWARD_TEXT_KEYFRAMES = [
{ offset: 0, opacity: 0, transform: TEXT_START_SCALE },
{ offset: 1, opacity: 1, transform: TEXT_END_SCALE },
];
const BACKWARD_TEXT_KEYFRAMES = [
{ offset: 0, opacity: 1, transform: TEXT_END_SCALE },
{ offset: 1, opacity: 0, transform: TEXT_START_SCALE },
];
const TEXT_KEYFRAMES = backDirection ? BACKWARD_TEXT_KEYFRAMES : FORWARD_TEXT_KEYFRAMES;
/**
* The icon should scale in/out in the second
* half of the animation. The icon should also
* translate, but that translate is handled by the
* container keyframes.
*/
const FORWARD_ICON_KEYFRAMES = [
{ offset: 0, opacity: 0, transform: 'scale(0.6)' },
{ offset: 0.6, opacity: 0, transform: 'scale(0.6)' },
{ offset: 1, opacity: 1, transform: 'scale(1)' },
];
const BACKWARD_ICON_KEYFRAMES = [
{ offset: 0, opacity: 1, transform: 'scale(1)' },
{ offset: 0.2, opacity: 0, transform: 'scale(0.6)' },
{ offset: 1, opacity: 0, transform: 'scale(0.6)' },
];
const ICON_KEYFRAMES = backDirection ? BACKWARD_ICON_KEYFRAMES : FORWARD_ICON_KEYFRAMES;
const enteringBackButtonTextAnimation = createAnimation();
const enteringBackButtonIconAnimation = createAnimation();
const enteringBackButtonAnimation = createAnimation();
const clonedBackButtonEl = getClonedElement('ion-back-button');
const clonedBackButtonTextEl = shadow(clonedBackButtonEl).querySelector('.button-text');
const clonedBackButtonIconEl = shadow(clonedBackButtonEl).querySelector('ion-icon');
clonedBackButtonEl.text = backButtonEl.text;
clonedBackButtonEl.mode = backButtonEl.mode;
clonedBackButtonEl.icon = backButtonEl.icon;
clonedBackButtonEl.color = backButtonEl.color;
clonedBackButtonEl.disabled = backButtonEl.disabled;
clonedBackButtonEl.style.setProperty('display', 'block');
clonedBackButtonEl.style.setProperty('position', 'fixed');
enteringBackButtonIconAnimation.addElement(clonedBackButtonIconEl);
enteringBackButtonTextAnimation.addElement(clonedBackButtonTextEl);
enteringBackButtonAnimation.addElement(clonedBackButtonEl);
enteringBackButtonAnimation
.beforeStyles({
position: 'absolute',
top: '0px',
[CONTAINER_ORIGIN_X]: '0px',
})
/**
* The write hooks must be set on this animation as it is guaranteed to run. Other
* animations such as the back button text animation will not run if the back button
* has no visible text.
*/
.beforeAddWrite(() => {
backButtonEl.style.setProperty('display', 'none');
clonedBackButtonEl.style.setProperty(TEXT_ORIGIN_X, BACK_BUTTON_START_OFFSET);
})
.afterAddWrite(() => {
backButtonEl.style.setProperty('display', '');
clonedBackButtonEl.style.setProperty('display', 'none');
clonedBackButtonEl.style.removeProperty(TEXT_ORIGIN_X);
})
.keyframes(CONTAINER_KEYFRAMES);
enteringBackButtonTextAnimation
.beforeStyles({
'transform-origin': `${TEXT_ORIGIN_X} top`,
})
.keyframes(TEXT_KEYFRAMES);
enteringBackButtonIconAnimation
.beforeStyles({
'transform-origin': `${ICON_ORIGIN_X} center`,
})
.keyframes(ICON_KEYFRAMES);
rootAnimation.addAnimation([
enteringBackButtonTextAnimation,
enteringBackButtonIconAnimation,
enteringBackButtonAnimation,
]);
};
const animateLargeTitle = (rootAnimation, rtl, backDirection, largeTitleEl, largeTitleBox, largeTitleTextBox, backButtonBox, backButtonTextEl, backButtonTextBox) => {
var _a, _b;
/**
* The horizontal transform origin for the large title
*/
const ORIGIN_X = rtl ? 'right' : 'left';
const TITLE_START_OFFSET = rtl ? `calc(100% - ${largeTitleBox.right}px)` : `${largeTitleBox.left}px`;
/**
* The cloned large should align exactly with the
* real large title on the leaving page otherwise there will
* be a layout shift.
*/
const START_TRANSLATE_X = '0px';
const START_TRANSLATE_Y = `${largeTitleBox.top}px`;
/**
* How much to offset the large title translation by.
* This accounts for differences in sizing between the large
* title and the back button due to padding and font weight.
*/
const LARGE_TITLE_TRANSLATION_OFFSET = 8;
let END_TRANSLATE_X = rtl
? `-${window.innerWidth - backButtonBox.right - LARGE_TITLE_TRANSLATION_OFFSET}px`
: `${backButtonBox.x + LARGE_TITLE_TRANSLATION_OFFSET}px`;
/**
* How much to scale the large title up/down by.
*/
let HEIGHT_SCALE = 0.5;
/**
* The large title always starts full size.
*/
const START_SCALE = 'scale(1)';
/**
* By default, we don't worry about having the large title scaled to perfectly
* match the back button because we don't know if the back button's text matches
* the large title's text.
*/
let END_SCALE = `scale(${HEIGHT_SCALE})`;
// Text element not rendered if developers pass text="" to the back button
if (backButtonTextEl && backButtonTextBox) {
/**
* The scaled title should (roughly) overlap the back button. This ensures that
* the back button and title overlap during the animation. Note that since both
* elements either fade in or fade out over the course of the animation, neither
* element will be fully visible on top of the other. As a result, the overlap
* does not need to be perfect, so approximate values are acceptable here.
*/
END_TRANSLATE_X = rtl
? `-${window.innerWidth - backButtonTextBox.right - LARGE_TITLE_TRANSLATION_OFFSET}px`
: `${backButtonTextBox.x - LARGE_TITLE_TRANSLATION_OFFSET}px`;
/**
* In the forward direction, the large title should start at its normal size and
* then scale down to be (roughly) the size of the back button on the other view.
* In the backward direction, the large title should start at (roughly) the size
* of the back button and then scale up to its original size.
* Note that since both elements either fade in or fade out over the course of the
* animation, neither element will be fully visible on top of the other. As a result,
* the overlap does not need to be perfect, so approximate values are acceptable here.
*/
/**
* When the title and back button texts match then they should overlap during the
* page transition. If the texts do not match up then the large title text scale
* adjusts to not perfectly match the back button text otherwise the proportions
* will be incorrect. When the texts match we scale both the width and height to
* account for font weight differences between the title and back button.
*/
const doTitleAndButtonTextsMatch = ((_a = backButtonTextEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = largeTitleEl.textContent) === null || _b === void 0 ? void 0 : _b.trim());
const WIDTH_SCALE = backButtonTextBox.width / largeTitleTextBox.width;
HEIGHT_SCALE = backButtonTextBox.height / (largeTitleTextBox.height - LARGE_TITLE_SIZE_OFFSET);
/**
* Even though we set TEXT_START_SCALE to HEIGHT_SCALE above, we potentially need
* to re-compute this here since the HEIGHT_SCALE may have changed.
*/
END_SCALE = doTitleAndButtonTextsMatch ? `scale(${WIDTH_SCALE}, ${HEIGHT_SCALE})` : `scale(${HEIGHT_SCALE})`;
}
/**
* The midpoints of the back button and the title should align such that the back
* button and title appear to be centered with each other.
*/
const backButtonMidPoint = backButtonBox.top + backButtonBox.height / 2;
const titleMidPoint = (largeTitleBox.height * HEIGHT_SCALE) / 2;
const END_TRANSLATE_Y = `${backButtonMidPoint - titleMidPoint}px`;
const BACKWARDS_KEYFRAMES = [
{ offset: 0, opacity: 0, transform: `translate3d(${END_TRANSLATE_X}, ${END_TRANSLATE_Y}, 0) ${END_SCALE}` },
{ offset: 0.1, opacity: 0 },
{ offset: 1, opacity: 1, transform: `translate3d(${START_TRANSLATE_X}, ${START_TRANSLATE_Y}, 0) ${START_SCALE}` },
];
const FORWARDS_KEYFRAMES = [
{
offset: 0,
opacity: 0.99,
transform: `translate3d(${START_TRANSLATE_X}, ${START_TRANSLATE_Y}, 0) ${START_SCALE}`,
},
{ offset: 0.6, opacity: 0 },
{ offset: 1, opacity: 0, transform: `translate3d(${END_TRANSLATE_X}, ${END_TRANSLATE_Y}, 0) ${END_SCALE}` },
];
const KEYFRAMES = backDirection ? BACKWARDS_KEYFRAMES : FORWARDS_KEYFRAMES;
const clonedTitleEl = getClonedElement('ion-title');
const clonedLargeTitleAnimation = createAnimation();
clonedTitleEl.innerText = largeTitleEl.innerText;
clonedTitleEl.size = largeTitleEl.size;
clonedTitleEl.color = largeTitleEl.color;
clonedLargeTitleAnimation.addElement(clonedTitleEl);
clonedLargeTitleAnimation
.beforeStyles({
'transform-origin': `${ORIGIN_X} top`,
/**
* Since font size changes will cause
* the dimension of the large title to change
* we need to set the cloned title height
* equal to that of the original large title height.
*/
height: `${largeTitleBox.height}px`,
display: '',
position: 'relative',
[ORIGIN_X]: TITLE_START_OFFSET,
})
.beforeAddWrite(() => {
largeTitleEl.style.setProperty('opacity', '0');
})
.afterAddWrite(() => {
largeTitleEl.style.setProperty('opacity', '');
clonedTitleEl.style.setProperty('display', 'none');
})
.keyframes(KEYFRAMES);
rootAnimation.addAnimation(clonedLargeTitleAnimation);
};
const iosTransitionAnimation = (navEl, opts) => {
var _a;
try {
const EASING = 'cubic-bezier(0.32,0.72,0,1)';
const OPACITY = 'opacity';
const TRANSFORM = 'transform';
const CENTER = '0%';
const OFF_OPACITY = 0.8;
const isRTL = navEl.ownerDocument.dir === 'rtl';
const OFF_RIGHT = isRTL ? '-99.5%' : '99.5%';
const OFF_LEFT = isRTL ? '33%' : '-33%';
const enteringEl = opts.enteringEl;
const leavingEl = opts.leavingEl;
const backDirection = opts.direction === 'back';
const contentEl = enteringEl.querySelector(':scope > ion-content');
const headerEls = enteringEl.querySelectorAll(':scope > ion-header > *:not(ion-toolbar), :scope > ion-footer > *');
const enteringToolBarEls = enteringEl.querySelectorAll(':scope > ion-header > ion-toolbar');
const rootAnimation = createAnimation();
const enteringContentAnimation = createAnimation();
rootAnimation
.addElement(enteringEl)
.duration(((_a = opts.duration) !== null && _a !== void 0 ? _a : 0) || DURATION)
.easing(opts.easing || EASING)
.fill('both')
.beforeRemoveClass('ion-page-invisible');
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
if (leavingEl && navEl !== null && navEl !== undefined) {
const navDecorAnimation = createAnimation();
navDecorAnimation.addElement(navEl);
rootAnimation.addAnimation(navDecorAnimation);
}
if (!contentEl && enteringToolBarEls.length === 0 && headerEls.length === 0) {
enteringContentAnimation.addElement(enteringEl.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs')); // REVIEW
}
else {
enteringContentAnimation.addElement(contentEl); // REVIEW
enteringContentAnimation.addElement(headerEls);
}
rootAnimation.addAnimation(enteringContentAnimation);
if (backDirection) {
enteringContentAnimation
.beforeClearStyles([OPACITY])
.fromTo('transform', `translateX(${OFF_LEFT})`, `translateX(${CENTER})`)
.fromTo(OPACITY, OFF_OPACITY, 1);
}
else {
// entering content, forward direction
enteringContentAnimation
.beforeClearStyles([OPACITY])
.fromTo('transform', `translateX(${OFF_RIGHT})`, `translateX(${CENTER})`);
}
if (contentEl) {
const enteringTransitionEffectEl = shadow(contentEl).querySelector('.transition-effect');
if (enteringTransitionEffectEl) {
const enteringTransitionCoverEl = enteringTransitionEffectEl.querySelector('.transition-cover');
const enteringTransitionShadowEl = enteringTransitionEffectEl.querySelector('.transition-shadow');
const enteringTransitionEffect = createAnimation();
const enteringTransitionCover = createAnimation();
const enteringTransitionShadow = createAnimation();
enteringTransitionEffect
.addElement(enteringTransitionEffectEl)
.beforeStyles({ opacity: '1', display: 'block' })
.afterStyles({ opacity: '', display: '' });
enteringTransitionCover
.addElement(enteringTransitionCoverEl) // REVIEW
.beforeClearStyles([OPACITY])
.fromTo(OPACITY, 0, 0.1);
enteringTransitionShadow
.addElement(enteringTransitionShadowEl) // REVIEW
.beforeClearStyles([OPACITY])
.fromTo(OPACITY, 0.03, 0.7);
enteringTransitionEffect.addAnimation([enteringTransitionCover, enteringTransitionShadow]);
enteringContentAnimation.addAnimation([enteringTransitionEffect]);
}
}
const enteringContentHasLargeTitle = enteringEl.querySelector('ion-header.header-collapse-condense');
const { forward, backward } = createLargeTitleTransition(rootAnimation, isRTL, backDirection, enteringEl, leavingEl);
enteringToolBarEls.forEach((enteringToolBarEl) => {
const enteringToolBar = createAnimation();
enteringToolBar.addElement(enteringToolBarEl);
rootAnimation.addAnimation(enteringToolBar);
const enteringTitle = createAnimation();
enteringTitle.addElement(enteringToolBarEl.querySelector('ion-title')); // REVIEW
const enteringToolBarButtons = createAnimation();
const buttons = Array.from(enteringToolBarEl.querySelectorAll('ion-buttons,[menuToggle]'));
const parentHeader = enteringToolBarEl.closest('ion-header');
const inactiveHeader = parentHeader === null || parentHeader === void 0 ? void 0 : parentHeader.classList.contains('header-collapse-condense-inactive');
let buttonsToAnimate;
if (backDirection) {
buttonsToAnimate = buttons.filter((button) => {
const isCollapseButton = button.classList.contains('buttons-collapse');
return (isCollapseButton && !inactiveHeader) || !isCollapseButton;
});
}
else {
buttonsToAnimate = buttons.filter((button) => !button.classList.contains('buttons-collapse'));
}
enteringToolBarButtons.addElement(buttonsToAnimate);
const enteringToolBarItems = createAnimation();
enteringToolBarItems.addElement(enteringToolBarEl.querySelectorAll(':scope > *:not(ion-title):not(ion-buttons):not([menuToggle])'));
const enteringToolBarBg = createAnimation();
enteringToolBarBg.addElement(shadow(enteringToolBarEl).querySelector('.toolbar-background')); // REVIEW
const enteringBackButton = createAnimation();
const backButtonEl = enteringToolBarEl.querySelector('ion-back-button');
if (backButtonEl) {
enteringBackButton.addElement(backButtonEl);
}
enteringToolBar.addAnimation([
enteringTitle,
enteringToolBarButtons,
enteringToolBarItems,
enteringToolBarBg,
enteringBackButton,
]);
enteringToolBarButtons.fromTo(OPACITY, 0.01, 1);
enteringToolBarItems.fromTo(OPACITY, 0.01, 1);
if (backDirection) {
if (!inactiveHeader) {
enteringTitle
.fromTo('transform', `translateX(${OFF_LEFT})`, `translateX(${CENTER})`)
.fromTo(OPACITY, 0.01, 1);
}
enteringToolBarItems.fromTo('transform', `translateX(${OFF_LEFT})`, `translateX(${CENTER})`);
// back direction, entering page has a back button
enteringBackButton.fromTo(OPACITY, 0.01, 1);
}
else {
// entering toolbar, forward direction
if (!enteringContentHasLargeTitle) {
enteringTitle
.fromTo('transform', `translateX(${OFF_RIGHT})`, `translateX(${CENTER})`)
.fromTo(OPACITY, 0.01, 1);
}
enteringToolBarItems.fromTo('transform', `translateX(${OFF_RIGHT})`, `translateX(${CENTER})`);
enteringToolBarBg.beforeClearStyles([OPACITY, 'transform']);
const translucentHeader = parentHeader === null || parentHeader === void 0 ? void 0 : parentHeader.translucent;
if (!translucentHeader) {
enteringToolBarBg.fromTo(OPACITY, 0.01, 'var(--opacity)');
}
else {
enteringToolBarBg.fromTo('transform', isRTL ? 'translateX(-100%)' : 'translateX(100%)', 'translateX(0px)');
}
// forward direction, entering page has a back button
if (!forward) {
enteringBackButton.fromTo(OPACITY, 0.01, 1);
}
if (backButtonEl && !forward) {
const enteringBackBtnText = createAnimation();
enteringBackBtnText
.addElement(shadow(backButtonEl).querySelector('.button-text')) // REVIEW
.fromTo(`transform`, isRTL ? 'translateX(-100px)' : 'translateX(100px)', 'translateX(0px)');
enteringToolBar.addAnimation(enteringBackBtnText);
}
}
});
// setup leaving view
if (leavingEl) {
const leavingContent = createAnimation();
const leavingContentEl = leavingEl.querySelector(':scope > ion-content');
const leavingToolBarEls = leavingEl.querySelectorAll(':scope > ion-header > ion-toolbar');
const leavingHeaderEls = leavingEl.querySelectorAll(':scope > ion-header > *:not(ion-toolbar), :scope > ion-footer > *');
if (!leavingContentEl && leavingToolBarEls.length === 0 && leavingHeaderEls.length === 0) {
leavingContent.addElement(leavingEl.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs')); // REVIEW
}
else {
leavingContent.addElement(leavingContentEl); // REVIEW
leavingContent.addElement(leavingHeaderEls);
}
rootAnimation.addAnimation(leavingContent);
if (backDirection) {
// leaving content, back direction
leavingContent
.beforeClearStyles([OPACITY])
.fromTo('transform', `translateX(${CENTER})`, isRTL ? 'translateX(-100%)' : 'translateX(100%)');
const leavingPage = getIonPageElement(leavingEl);
rootAnimation.afterAddWrite(() => {
if (rootAnimation.getDirection() === 'normal') {
leavingPage.style.setProperty('display', 'none');
}
});
}
else {
// leaving content, forward direction
leavingContent
.fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`)
.fromTo(OPACITY, 1, OFF_OPACITY);
}
if (leavingContentEl) {
const leavingTransitionEffectEl = shadow(leavingContentEl).querySelector('.transition-effect');
if (leavingTransitionEffectEl) {
const leavingTransitionCoverEl = leavingTransitionEffectEl.querySelector('.transition-cover');
const leavingTransitionShadowEl = leavingTransitionEffectEl.querySelector('.transition-shadow');
const leavingTransitionEffect = createAnimation();
const leavingTransitionCover = createAnimation();
const leavingTransitionShadow = createAnimation();
leavingTransitionEffect
.addElement(leavingTransitionEffectEl)
.beforeStyles({ opacity: '1', display: 'block' })
.afterStyles({ opacity: '', display: '' });
leavingTransitionCover
.addElement(leavingTransitionCoverEl) // REVIEW
.beforeClearStyles([OPACITY])
.fromTo(OPACITY, 0.1, 0);
leavingTransitionShadow
.addElement(leavingTransitionShadowEl) // REVIEW
.beforeClearStyles([OPACITY])
.fromTo(OPACITY, 0.7, 0.03);
leavingTransitionEffect.addAnimation([leavingTransitionCover, leavingTransitionShadow]);
leavingContent.addAnimation([leavingTransitionEffect]);
}
}
leavingToolBarEls.forEach((leavingToolBarEl) => {
const leavingToolBar = createAnimation();
leavingToolBar.addElement(leavingToolBarEl);
const leavingTitle = createAnimation();
leavingTitle.addElement(leavingToolBarEl.querySelector('ion-title')); // REVIEW
const leavingToolBarButtons = createAnimation();
const buttons = leavingToolBarEl.querySelectorAll('ion-buttons,[menuToggle]');
const parentHeader = leavingToolBarEl.closest('ion-header');
const inactiveHeader = parentHeader === null || parentHeader === void 0 ? void 0 : parentHeader.classList.contains('header-collapse-condense-inactive');
const buttonsToAnimate = Array.from(buttons).filter((button) => {
const isCollapseButton = button.classList.contains('buttons-collapse');
return (isCollapseButton && !inactiveHeader) || !isCollapseButton;
});
leavingToolBarButtons.addElement(buttonsToAnimate);
const leavingToolBarItems = createAnimation();
const leavingToolBarItemEls = leavingToolBarEl.querySelectorAll(':scope > *:not(ion-title):not(ion-buttons):not([menuToggle])');
if (leavingToolBarItemEls.length > 0) {
leavingToolBarItems.addElement(leavingToolBarItemEls);
}
const leavingToolBarBg = createAnimation();
leavingToolBarBg.addElement(shadow(leavingToolBarEl).querySelector('.toolbar-background')); // REVIEW
const leavingBackButton = createAnimation();
const backButtonEl = leavingToolBarEl.querySelector('ion-back-button');
if (backButtonEl) {
leavingBackButton.addElement(backButtonEl);
}
leavingToolBar.addAnimation([
leavingTitle,
leavingToolBarButtons,
leavingToolBarItems,
leavingBackButton,
leavingToolBarBg,
]);
rootAnimation.addAnimation(leavingToolBar);
// fade out leaving toolbar items
leavingBackButton.fromTo(OPACITY, 0.99, 0);
leavingToolBarButtons.fromTo(OPACITY, 0.99, 0);
leavingToolBarItems.fromTo(OPACITY, 0.99, 0);
if (backDirection) {
if (!inactiveHeader) {
// leaving toolbar, back direction
leavingTitle
.fromTo('transform', `translateX(${CENTER})`, isRTL ? 'translateX(-100%)' : 'translateX(100%)')
.fromTo(OPACITY, 0.99, 0);
}
leavingToolBarItems.fromTo('transform', `translateX(${CENTER})`, isRTL ? 'translateX(-100%)' : 'translateX(100%)');
leavingToolBarBg.beforeClearStyles([OPACITY, 'transform']);
// leaving toolbar, back direction, and there's no entering toolbar
// should just slide out, no fading out
const translucentHeader = parentHeader === null || parentHeader === void 0 ? void 0 : parentHeader.translucent;
if (!translucentHeader) {
leavingToolBarBg.fromTo(OPACITY, 'var(--opacity)', 0);
}
else {
leavingToolBarBg.fromTo('transform', 'translateX(0px)', isRTL ? 'translateX(-100%)' : 'translateX(100%)');
}
if (backButtonEl && !backward) {
const leavingBackBtnText = createAnimation();
leavingBackBtnText
.addElement(shadow(backButtonEl).querySelector('.button-text')) // REVIEW
.fromTo('transform', `translateX(${CENTER})`, `translateX(${(isRTL ? -124 : 124) + 'px'})`);
leavingToolBar.addAnimation(leavingBackBtnText);
}
}
else {
// leaving toolbar, forward direction
if (!inactiveHeader) {
leavingTitle
.fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`)
.fromTo(OPACITY, 0.99, 0)
.afterClearStyles([TRANSFORM, OPACITY]);
}
leavingToolBarItems
.fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`)
.afterClearStyles([TRANSFORM, OPACITY]);
leavingBackButton.afterClearStyles([OPACITY]);
leavingTitle.afterClearStyles([OPACITY]);
leavingToolBarButtons.afterClearStyles([OPACITY]);
}
});
}
return rootAnimation;
}
catch (err) {
throw err;
}
};
/**
* The scale of the back button during the animation
* is computed based on the scale of the large title
* and vice versa. However, we need to account for slight
* variations in the size of the large title due to
* padding and font weight. This value should be used to subtract
* a small amount from the large title height when computing scales
* to get more accurate scale results.
*/
const LARGE_TITLE_SIZE_OFFSET = 10;
var ios_transition = /*#__PURE__*/Object.freeze({
__proto__: null,
iosTransitionAnimation: iosTransitionAnimation,
shadow: shadow
});
const mdTransitionAnimation = (_, opts) => {
var _a, _b, _c;
const OFF_BOTTOM = '40px';
const CENTER = '0px';
const backDirection = opts.direction === 'back';
const enteringEl = opts.enteringEl;
const leavingEl = opts.leavingEl;
const ionPageElement = getIonPageElement(enteringEl);
const enteringToolbarEle = ionPageElement.querySelector('ion-toolbar');
const rootTransition = createAnimation();
rootTransition.addElement(ionPageElement).fill('both').beforeRemoveClass('ion-page-invisible');
// animate the component itself
if (backDirection) {
rootTransition.duration(((_a = opts.duration) !== null && _a !== void 0 ? _a : 0) || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
}
else {
rootTransition
.duration(((_b = opts.duration) !== null && _b !== void 0 ? _b : 0) || 280)
.easing('cubic-bezier(0.36,0.66,0.04,1)')
.fromTo('transform', `translateY(${OFF_BOTTOM})`, `translateY(${CENTER})`)
.fromTo('opacity', 0.01, 1);
}
// Animate toolbar if it's there
if (enteringToolbarEle) {
const enteringToolBar = createAnimation();
enteringToolBar.addElement(enteringToolbarEle);
rootTransition.addAnimation(enteringToolBar);
}
// setup leaving view
if (leavingEl && backDirection) {
// leaving content
rootTransition.duration(((_c = opts.duration) !== null && _c !== void 0 ? _c : 0) || 200).easing('cubic-bezier(0.47,0,0.745,0.715)');
const leavingPage = createAnimation();
leavingPage
.addElement(getIonPageElement(leavingEl))
.onFinish((currentStep) => {
if (currentStep === 1 && leavingPage.elements.length > 0) {
leavingPage.elements[0].style.setProperty('display', 'none');
}
})
.fromTo('transform', `translateY(${CENTER})`, `translateY(${OFF_BOTTOM})`)
.fromTo('opacity', 1, 0);
rootTransition.addAnimation(leavingPage);
}
return rootTransition;
};
var md_transition = /*#__PURE__*/Object.freeze({
__proto__: null,
mdTransitionAnimation: mdTransitionAnimation
});
const createSwipeBackGesture = (el, canStartHandler, onStartHandler, onMoveHandler, onEndHandler) => {
const win = el.ownerDocument.defaultView;
let rtl = isRTL$1(el);
/**
* Determine if a gesture is near the edge
* of the screen. If true, then the swipe
* to go back gesture should proceed.
*/
const isAtEdge = (detail) => {
const threshold = 50;
const { startX } = detail;
if (rtl) {
return startX >= win.innerWidth - threshold;
}
return startX <= threshold;
};
const getDeltaX = (detail) => {
return rtl ? -detail.deltaX : detail.deltaX;
};
const getVelocityX = (detail) => {
return rtl ? -detail.velocityX : detail.velocityX;
};
const canStart = (detail) => {
/**
* The user's locale can change mid-session,
* so we need to check text direction at
* the beginning of every gesture.
*/
rtl = isRTL$1(el);
return isAtEdge(detail) && canStartHandler();
};
const onMove = (detail) => {
// set the transition animation's progress
const delta = getDeltaX(detail);
const stepValue = delta / win.innerWidth;
onMoveHandler(stepValue);
};
const onEnd = (detail) => {
// the swipe back gesture has ended
const delta = getDeltaX(detail);
const width = win.innerWidth;
const stepValue = delta / width;
const velocity = getVelocityX(detail);
const z = width / 2.0;
const shouldComplete = velocity >= 0 && (velocity > 0.2 || delta > z);
const missing = shouldComplete ? 1 - stepValue : stepValue;
const missingDistance = missing * width;
let realDur = 0;
if (missingDistance > 5) {
const dur = missingDistance / Math.abs(velocity);
realDur = Math.min(dur, 540);
}
onEndHandler(shouldComplete, stepValue <= 0 ? 0.01 : clamp(0, stepValue, 0.9999), realDur);
};
return createGesture({
el,
gestureName: 'goback-swipe',
/**
* Swipe to go back should have priority over other horizontal swipe
* gestures. These gestures have a priority of 100 which is why 101 was chosen here.
*/
gesturePriority: 101,
threshold: 10,
canStart,
onStart: onStartHandler,
onMove,
onEnd,
});
};
var swipeBack = /*#__PURE__*/Object.freeze({
__proto__: null,
createSwipeBackGesture: createSwipeBackGesture
});
exports.hydrateApp = hydrateApp;
/*hydrateAppClosure end*/
hydrateApp(window, $stencilHydrateOpts, $stencilHydrateResults, $stencilAfterHydrate, $stencilHydrateResolve);
}
hydrateAppClosure($stencilWindow);
}
// src/app-data/index.ts
var BUILD = {
allRenderFn: false,
element: true,
event: true,
hasRenderFn: true,
hostListener: true,
hostListenerTargetWindow: true,
hostListenerTargetDocument: true,
hostListenerTargetBody: true,
hostListenerTargetParent: false,
hostListenerTarget: true,
member: true,
method: true,
mode: true,
observeAttribute: true,
prop: true,
propMutable: true,
reflect: true,
scoped: true,
shadowDom: true,
slot: true,
cssAnnotations: true,
state: true,
style: true,
formAssociated: false,
svg: true,
updatable: true,
vdomAttribute: true,
vdomXlink: true,
vdomClass: true,
vdomFunctional: true,
vdomKey: true,
vdomListener: true,
vdomRef: true,
vdomPropOrAttr: true,
vdomRender: true,
vdomStyle: true,
vdomText: true,
propChangeCallback: true,
taskQueue: true,
hotModuleReplacement: false,
isDebug: false,
isDev: false,
isTesting: false,
hydrateServerSide: false,
hydrateClientSide: false,
lifecycleDOMEvents: false,
lazyLoad: false,
profile: false,
slotRelocation: true,
// TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
appendChildSlotFix: false,
// TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
cloneNodeFix: false,
hydratedAttribute: false,
hydratedClass: true,
// TODO(STENCIL-1305): remove this option
scriptDataOpts: false,
// TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
scopedSlotTextContentFix: false,
// TODO(STENCIL-854): Remove code related to legacy shadowDomShim field
shadowDomShim: false,
// TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
slotChildNodesFix: false,
invisiblePrehydration: true,
propBoolean: true,
propNumber: true,
propString: true,
constructableCSS: true,
devTools: false,
shadowDelegatesFocus: true,
initializeNextTick: false,
asyncLoading: true,
asyncQueue: false,
transformTagName: false,
attachStyles: true,
// TODO(STENCIL-914): remove this option when `experimentalSlotFixes` is the default behavior
experimentalSlotFixes: false
};
var Env = {};
var NAMESPACE = (
/* default */
"app"
);
/*
Stencil Hydrate Runner v4.38.0 | MIT Licensed | https://stenciljs.com
*/
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// src/runtime/runtime-constants.ts
var CONTENT_REF_ID = "r";
var ORG_LOCATION_ID = "o";
var SLOT_NODE_ID = "s";
var TEXT_NODE_ID = "t";
var HYDRATE_ID = "s-id";
var HYDRATED_STYLE_ID = "sty-id";
var STENCIL_DOC_DATA = "_stencilDocData";
var XLINK_NS = "http://www.w3.org/1999/xlink";
// src/mock-doc/attribute.ts
var attrHandler = {
get(obj, prop) {
if (prop in obj) {
return obj[prop];
}
if (typeof prop !== "symbol" && !isNaN(prop)) {
return obj.__items[prop];
}
return void 0;
}
};
var createAttributeProxy = (caseInsensitive) => new Proxy(new MockAttributeMap(caseInsensitive), attrHandler);
var MockAttributeMap = class {
constructor(caseInsensitive = false) {
this.caseInsensitive = caseInsensitive;
this.__items = [];
}
get length() {
return this.__items.length;
}
item(index) {
return this.__items[index] || null;
}
setNamedItem(attr) {
attr.namespaceURI = null;
this.setNamedItemNS(attr);
}
setNamedItemNS(attr) {
if (attr != null && attr.value != null) {
attr.value = String(attr.value);
}
const existingAttr = this.__items.find((a) => a.name === attr.name && a.namespaceURI === attr.namespaceURI);
if (existingAttr != null) {
existingAttr.value = attr.value;
} else {
this.__items.push(attr);
}
}
getNamedItem(attrName) {
if (this.caseInsensitive) {
attrName = attrName.toLowerCase();
}
return this.getNamedItemNS(null, attrName);
}
getNamedItemNS(namespaceURI, attrName) {
namespaceURI = getNamespaceURI(namespaceURI);
return this.__items.find((attr) => attr.name === attrName && getNamespaceURI(attr.namespaceURI) === namespaceURI) || null;
}
removeNamedItem(attr) {
this.removeNamedItemNS(attr);
}
removeNamedItemNS(attr) {
for (let i = 0, ii = this.__items.length; i < ii; i++) {
if (this.__items[i].name === attr.name && this.__items[i].namespaceURI === attr.namespaceURI) {
this.__items.splice(i, 1);
break;
}
}
}
[Symbol.iterator]() {
let i = 0;
return {
next: () => ({
done: i === this.length,
value: this.item(i++)
})
};
}
get [Symbol.toStringTag]() {
return "MockAttributeMap";
}
};
function getNamespaceURI(namespaceURI) {
return namespaceURI === XLINK_NS ? null : namespaceURI;
}
function cloneAttributes(srcAttrs, sortByName = false) {
const dstAttrs = new MockAttributeMap(srcAttrs.caseInsensitive);
if (srcAttrs != null) {
const attrLen = srcAttrs.length;
if (sortByName && attrLen > 1) {
const sortedAttrs = [];
for (let i = 0; i < attrLen; i++) {
const srcAttr = srcAttrs.item(i);
const dstAttr = new MockAttr(srcAttr.name, srcAttr.value, srcAttr.namespaceURI);
sortedAttrs.push(dstAttr);
}
sortedAttrs.sort(sortAttributes).forEach((attr) => {
dstAttrs.setNamedItemNS(attr);
});
} else {
for (let i = 0; i < attrLen; i++) {
const srcAttr = srcAttrs.item(i);
const dstAttr = new MockAttr(srcAttr.name, srcAttr.value, srcAttr.namespaceURI);
dstAttrs.setNamedItemNS(dstAttr);
}
}
}
return dstAttrs;
}
function sortAttributes(a, b) {
if (a.name < b.name) return -1;
if (a.name > b.name) return 1;
return 0;
}
var MockAttr = class {
constructor(attrName, attrValue, namespaceURI = null) {
this._name = attrName;
this._value = String(attrValue);
this._namespaceURI = namespaceURI;
}
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
get value() {
return this._value;
}
set value(value) {
this._value = String(value);
}
get nodeName() {
return this._name;
}
set nodeName(value) {
this._name = value;
}
get nodeValue() {
return this._value;
}
set nodeValue(value) {
this._value = String(value);
}
get namespaceURI() {
return this._namespaceURI;
}
set namespaceURI(namespaceURI) {
this._namespaceURI = namespaceURI;
}
};
// src/mock-doc/class-list.ts
var MockClassList = class {
constructor(elm) {
this.elm = elm;
}
add(...classNames) {
const clsNames = getItems(this.elm);
let updated = false;
classNames.forEach((className) => {
className = String(className);
validateClass(className);
if (clsNames.includes(className) === false) {
clsNames.push(className);
updated = true;
}
});
if (updated) {
this.elm.setAttributeNS(null, "class", clsNames.join(" "));
}
}
remove(...classNames) {
const clsNames = getItems(this.elm);
let updated = false;
classNames.forEach((className) => {
className = String(className);
validateClass(className);
const index = clsNames.indexOf(className);
if (index > -1) {
clsNames.splice(index, 1);
updated = true;
}
});
if (updated) {
this.elm.setAttributeNS(null, "class", clsNames.filter((c) => c.length > 0).join(" "));
}
}
contains(className) {
className = String(className);
return getItems(this.elm).includes(className);
}
toggle(className) {
className = String(className);
if (this.contains(className) === true) {
this.remove(className);
} else {
this.add(className);
}
}
get length() {
return getItems(this.elm).length;
}
item(index) {
return getItems(this.elm)[index];
}
toString() {
return getItems(this.elm).join(" ");
}
};
function validateClass(className) {
if (className === "") {
throw new Error("The token provided must not be empty.");
}
if (/\s/.test(className)) {
throw new Error(
`The token provided ('${className}') contains HTML space characters, which are not valid in tokens.`
);
}
}
function getItems(elm) {
const className = elm.getAttribute("class");
if (typeof className === "string" && className.length > 0) {
return className.trim().split(" ").filter((c) => c.length > 0);
}
return [];
}
// src/mock-doc/css-style-declaration.ts
var MockCSSStyleDeclaration = class {
constructor() {
this._styles = /* @__PURE__ */ new Map();
}
setProperty(prop, value) {
prop = jsCaseToCssCase(prop);
if (value == null || value === "") {
this._styles.delete(prop);
} else {
this._styles.set(prop, String(value));
}
}
getPropertyValue(prop) {
prop = jsCaseToCssCase(prop);
return String(this._styles.get(prop) || "");
}
removeProperty(prop) {
prop = jsCaseToCssCase(prop);
this._styles.delete(prop);
}
get length() {
return this._styles.size;
}
get cssText() {
const cssText = [];
this._styles.forEach((value, prop) => {
cssText.push(`${prop}: ${value};`);
});
return cssText.join(" ").trim();
}
set cssText(cssText) {
if (cssText == null || cssText === "") {
this._styles.clear();
return;
}
cssText.split(";").forEach((rule) => {
rule = rule.trim();
if (rule.length > 0) {
const splt = rule.split(":");
if (splt.length > 1) {
const prop = splt[0].trim();
const value = splt.slice(1).join(":").trim();
if (prop !== "" && value !== "") {
this._styles.set(jsCaseToCssCase(prop), value);
}
}
}
});
}
};
function createCSSStyleDeclaration() {
return new Proxy(new MockCSSStyleDeclaration(), cssProxyHandler);
}
var cssProxyHandler = {
get(cssStyle, prop) {
if (prop in cssStyle) {
return cssStyle[prop];
}
prop = cssCaseToJsCase(prop);
return cssStyle.getPropertyValue(prop);
},
set(cssStyle, prop, value) {
if (prop in cssStyle) {
cssStyle[prop] = value;
} else {
cssStyle.setProperty(prop, value);
}
return true;
}
};
function cssCaseToJsCase(str) {
if (str.length > 1 && str.includes("-") === true) {
str = str.toLowerCase().split("-").map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1)).join("");
str = str.slice(0, 1).toLowerCase() + str.slice(1);
}
return str;
}
function jsCaseToCssCase(str) {
if (str.length > 1 && str.includes("-") === false && /[A-Z]/.test(str) === true) {
str = str.replace(/([A-Z])/g, (g) => " " + g[0]).trim().replace(/ /g, "-").toLowerCase();
}
return str;
}
// src/mock-doc/custom-element-registry.ts
var MockCustomElementRegistry = class {
constructor(win2) {
this.win = win2;
}
define(tagName, cstr, options) {
if (tagName.toLowerCase() !== tagName) {
throw new Error(
`Failed to execute 'define' on 'CustomElementRegistry': "${tagName}" is not a valid custom element name`
);
}
if (this.__registry == null) {
this.__registry = /* @__PURE__ */ new Map();
}
this.__registry.set(tagName, { cstr, options });
if (this.__whenDefined != null) {
const whenDefinedResolveFns = this.__whenDefined.get(tagName);
if (whenDefinedResolveFns != null) {
whenDefinedResolveFns.forEach((whenDefinedResolveFn) => {
whenDefinedResolveFn();
});
whenDefinedResolveFns.length = 0;
this.__whenDefined.delete(tagName);
}
}
const doc = this.win.document;
if (doc != null) {
const hosts = doc.querySelectorAll(tagName);
hosts.forEach((host) => {
if (upgradedElements.has(host) === false) {
tempDisableCallbacks.add(doc);
const upgradedCmp = createCustomElement(this, doc, tagName);
for (let i = 0; i < host.childNodes.length; i++) {
const childNode = host.childNodes[i];
childNode.remove();
upgradedCmp.appendChild(childNode);
}
tempDisableCallbacks.delete(doc);
if (proxyElements.has(host)) {
proxyElements.set(host, upgradedCmp);
}
}
fireConnectedCallback(host);
});
}
}
get(tagName) {
if (this.__registry != null) {
const def = this.__registry.get(tagName.toLowerCase());
if (def != null) {
return def.cstr;
}
}
return void 0;
}
getName(cstr) {
for (const [tagName, def] of this.__registry.entries()) {
if (def.cstr === cstr) {
return tagName;
}
}
return void 0;
}
upgrade(_rootNode) {
}
clear() {
if (this.__registry != null) {
this.__registry.clear();
}
if (this.__whenDefined != null) {
this.__whenDefined.clear();
}
}
whenDefined(tagName) {
tagName = tagName.toLowerCase();
if (this.__registry != null && this.__registry.has(tagName) === true) {
return Promise.resolve(this.__registry.get(tagName).cstr);
}
return new Promise((resolve) => {
if (this.__whenDefined == null) {
this.__whenDefined = /* @__PURE__ */ new Map();
}
let whenDefinedResolveFns = this.__whenDefined.get(tagName);
if (whenDefinedResolveFns == null) {
whenDefinedResolveFns = [];
this.__whenDefined.set(tagName, whenDefinedResolveFns);
}
whenDefinedResolveFns.push(resolve);
});
}
};
function createCustomElement(customElements2, ownerDocument, tagName) {
const Cstr = customElements2.get(tagName);
if (Cstr != null) {
const cmp = new Cstr(ownerDocument);
cmp.nodeName = tagName.toUpperCase();
upgradedElements.add(cmp);
return cmp;
}
const host = new Proxy(
{},
{
get(obj, prop) {
const elm2 = proxyElements.get(host);
if (elm2 != null) {
return elm2[prop];
}
return obj[prop];
},
set(obj, prop, val) {
const elm2 = proxyElements.get(host);
if (elm2 != null) {
elm2[prop] = val;
} else {
obj[prop] = val;
}
return true;
},
has(obj, prop) {
const elm2 = proxyElements.get(host);
if (prop in elm2) {
return true;
}
if (prop in obj) {
return true;
}
return false;
}
}
);
const elm = new MockHTMLElement(ownerDocument, tagName);
proxyElements.set(host, elm);
return host;
}
var proxyElements = /* @__PURE__ */ new WeakMap();
var upgradedElements = /* @__PURE__ */ new WeakSet();
function connectNode(ownerDocument, node) {
node.ownerDocument = ownerDocument;
if (node.nodeType === 1 /* ELEMENT_NODE */) {
if (ownerDocument != null && node.nodeName.includes("-")) {
const win2 = ownerDocument.defaultView;
if (win2 != null && typeof node.connectedCallback === "function" && node.isConnected) {
fireConnectedCallback(node);
}
const shadowRoot = node.shadowRoot;
if (shadowRoot != null) {
shadowRoot.childNodes.forEach((childNode) => {
connectNode(ownerDocument, childNode);
});
}
}
node.childNodes.forEach((childNode) => {
connectNode(ownerDocument, childNode);
});
} else {
node.childNodes.forEach((childNode) => {
childNode.ownerDocument = ownerDocument;
});
}
}
function fireConnectedCallback(node) {
if (typeof node.connectedCallback === "function") {
if (tempDisableCallbacks.has(node.ownerDocument) === false) {
try {
node.connectedCallback();
} catch (e) {
console.error(e);
}
}
}
}
function disconnectNode(node) {
if (node.nodeType === 1 /* ELEMENT_NODE */) {
if (node.nodeName.includes("-") === true && typeof node.disconnectedCallback === "function") {
if (tempDisableCallbacks.has(node.ownerDocument) === false) {
try {
node.disconnectedCallback();
} catch (e) {
console.error(e);
}
}
}
node.childNodes.forEach(disconnectNode);
}
}
function attributeChanged(node, attrName, oldValue, newValue) {
attrName = attrName.toLowerCase();
const observedAttributes = node.constructor.observedAttributes;
if (Array.isArray(observedAttributes) === true && observedAttributes.some((obs) => obs.toLowerCase() === attrName) === true) {
try {
node.attributeChangedCallback(attrName, oldValue, newValue);
} catch (e) {
console.error(e);
}
}
}
function checkAttributeChanged(node) {
return node.nodeName.includes("-") === true && typeof node.attributeChangedCallback === "function";
}
var tempDisableCallbacks = /* @__PURE__ */ new Set();
// src/mock-doc/dataset.ts
function dataset(elm) {
const ds = {};
const attributes = elm.attributes;
const attrLen = attributes.length;
for (let i = 0; i < attrLen; i++) {
const attr = attributes.item(i);
const nodeName = attr.nodeName;
if (nodeName.startsWith("data-")) {
ds[dashToPascalCase(nodeName)] = attr.nodeValue;
}
}
return new Proxy(ds, {
get(_obj, camelCaseProp) {
return ds[camelCaseProp];
},
set(_obj, camelCaseProp, value) {
const dataAttr = toDataAttribute(camelCaseProp);
elm.setAttribute(dataAttr, value);
return true;
}
});
}
function toDataAttribute(str) {
return "data-" + String(str).replace(/([A-Z0-9])/g, (g) => " " + g[0]).trim().replace(/ /g, "-").toLowerCase();
}
function dashToPascalCase(str) {
str = String(str).slice(5);
return str.split("-").map((segment, index) => {
if (index === 0) {
return segment.charAt(0).toLowerCase() + segment.slice(1);
}
return segment.charAt(0).toUpperCase() + segment.slice(1);
}).join("");
}
// src/mock-doc/event.ts
var MockEvent = class {
constructor(type, eventInitDict) {
this.bubbles = false;
this.cancelBubble = false;
this.cancelable = false;
this.composed = false;
this.currentTarget = null;
this.defaultPrevented = false;
this.srcElement = null;
this.target = null;
if (typeof type !== "string") {
throw new Error(`Event type required`);
}
this.type = type;
this.timeStamp = Date.now();
if (eventInitDict != null) {
Object.assign(this, eventInitDict);
}
}
preventDefault() {
this.defaultPrevented = true;
}
stopPropagation() {
this.cancelBubble = true;
}
stopImmediatePropagation() {
this.cancelBubble = true;
}
/**
* @ref https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath
* @returns a composed path of the event
*/
composedPath() {
const composedPath = [];
let currentElement = this.target;
while (currentElement) {
composedPath.push(currentElement);
if (!currentElement.parentElement && currentElement.nodeName === "#document" /* DOCUMENT_NODE */) {
composedPath.push(currentElement.defaultView);
break;
}
if (currentElement.parentElement == null && currentElement.tagName === "HTML") {
currentElement = currentElement.ownerDocument;
} else {
currentElement = currentElement.parentElement;
}
}
return composedPath;
}
};
var MockCustomEvent = class extends MockEvent {
constructor(type, customEventInitDic) {
super(type);
this.detail = null;
if (customEventInitDic != null) {
Object.assign(this, customEventInitDic);
}
}
};
var MockKeyboardEvent = class extends MockEvent {
constructor(type, keyboardEventInitDic) {
super(type);
this.code = "";
this.key = "";
this.altKey = false;
this.ctrlKey = false;
this.metaKey = false;
this.shiftKey = false;
this.location = 0;
this.repeat = false;
if (keyboardEventInitDic != null) {
Object.assign(this, keyboardEventInitDic);
}
}
};
var MockMouseEvent = class extends MockEvent {
constructor(type, mouseEventInitDic) {
super(type);
this.screenX = 0;
this.screenY = 0;
this.clientX = 0;
this.clientY = 0;
this.ctrlKey = false;
this.shiftKey = false;
this.altKey = false;
this.metaKey = false;
this.button = 0;
this.buttons = 0;
this.relatedTarget = null;
if (mouseEventInitDic != null) {
Object.assign(this, mouseEventInitDic);
}
}
};
var MockUIEvent = class extends MockEvent {
constructor(type, uiEventInitDic) {
super(type);
this.detail = null;
this.view = null;
if (uiEventInitDic != null) {
Object.assign(this, uiEventInitDic);
}
}
};
var MockFocusEvent = class extends MockUIEvent {
constructor(type, focusEventInitDic) {
super(type);
this.relatedTarget = null;
if (focusEventInitDic != null) {
Object.assign(this, focusEventInitDic);
}
}
};
var MockEventListener = class {
constructor(type, handler) {
this.type = type;
this.handler = handler;
}
};
function addEventListener(elm, type, handler) {
const target = elm;
if (target.__listeners == null) {
target.__listeners = [];
}
target.__listeners.push(new MockEventListener(type, handler));
}
function removeEventListener(elm, type, handler) {
const target = elm;
if (target != null && Array.isArray(target.__listeners) === true) {
const elmListener = target.__listeners.find((e) => e.type === type && e.handler === handler);
if (elmListener != null) {
const index = target.__listeners.indexOf(elmListener);
target.__listeners.splice(index, 1);
}
}
}
function resetEventListeners(target) {
if (target != null && target.__listeners != null) {
target.__listeners = null;
}
}
function triggerEventListener(elm, ev) {
if (elm == null || ev.cancelBubble === true) {
return;
}
const target = elm;
ev.currentTarget = elm;
if (Array.isArray(target.__listeners) === true) {
const listeners = target.__listeners.filter((e) => e.type === ev.type);
listeners.forEach((listener) => {
try {
listener.handler.call(target, ev);
} catch (err2) {
console.error(err2);
}
});
}
if (ev.bubbles === false) {
return;
}
if (elm.nodeName === "#document" /* DOCUMENT_NODE */) {
triggerEventListener(elm.defaultView, ev);
} else if (elm.parentElement == null && elm.tagName === "HTML") {
triggerEventListener(elm.ownerDocument, ev);
} else {
const nextTarget = getNextEventTarget(elm, ev);
triggerEventListener(nextTarget, ev);
}
}
function getNextEventTarget(elm, ev) {
if (elm.parentElement) {
return elm.parentElement;
}
if (elm.host && ev.composed) {
return elm.host;
}
if (ev.composed && elm.parentNode && elm.parentNode.host) {
return elm.parentNode.host;
}
return null;
}
function dispatchEvent(currentTarget, ev) {
ev.target = currentTarget;
triggerEventListener(currentTarget, ev);
return true;
}
// node_modules/parse5/dist/common/unicode.js
var UNDEFINED_CODE_POINTS = /* @__PURE__ */ new Set([
65534,
65535,
131070,
131071,
196606,
196607,
262142,
262143,
327678,
327679,
393214,
393215,
458750,
458751,
524286,
524287,
589822,
589823,
655358,
655359,
720894,
720895,
786430,
786431,
851966,
851967,
917502,
917503,
983038,
983039,
1048574,
1048575,
1114110,
1114111
]);
var REPLACEMENT_CHARACTER = "\uFFFD";
var CODE_POINTS;
(function(CODE_POINTS2) {
CODE_POINTS2[CODE_POINTS2["EOF"] = -1] = "EOF";
CODE_POINTS2[CODE_POINTS2["NULL"] = 0] = "NULL";
CODE_POINTS2[CODE_POINTS2["TABULATION"] = 9] = "TABULATION";
CODE_POINTS2[CODE_POINTS2["CARRIAGE_RETURN"] = 13] = "CARRIAGE_RETURN";
CODE_POINTS2[CODE_POINTS2["LINE_FEED"] = 10] = "LINE_FEED";
CODE_POINTS2[CODE_POINTS2["FORM_FEED"] = 12] = "FORM_FEED";
CODE_POINTS2[CODE_POINTS2["SPACE"] = 32] = "SPACE";
CODE_POINTS2[CODE_POINTS2["EXCLAMATION_MARK"] = 33] = "EXCLAMATION_MARK";
CODE_POINTS2[CODE_POINTS2["QUOTATION_MARK"] = 34] = "QUOTATION_MARK";
CODE_POINTS2[CODE_POINTS2["AMPERSAND"] = 38] = "AMPERSAND";
CODE_POINTS2[CODE_POINTS2["APOSTROPHE"] = 39] = "APOSTROPHE";
CODE_POINTS2[CODE_POINTS2["HYPHEN_MINUS"] = 45] = "HYPHEN_MINUS";
CODE_POINTS2[CODE_POINTS2["SOLIDUS"] = 47] = "SOLIDUS";
CODE_POINTS2[CODE_POINTS2["DIGIT_0"] = 48] = "DIGIT_0";
CODE_POINTS2[CODE_POINTS2["DIGIT_9"] = 57] = "DIGIT_9";
CODE_POINTS2[CODE_POINTS2["SEMICOLON"] = 59] = "SEMICOLON";
CODE_POINTS2[CODE_POINTS2["LESS_THAN_SIGN"] = 60] = "LESS_THAN_SIGN";
CODE_POINTS2[CODE_POINTS2["EQUALS_SIGN"] = 61] = "EQUALS_SIGN";
CODE_POINTS2[CODE_POINTS2["GREATER_THAN_SIGN"] = 62] = "GREATER_THAN_SIGN";
CODE_POINTS2[CODE_POINTS2["QUESTION_MARK"] = 63] = "QUESTION_MARK";
CODE_POINTS2[CODE_POINTS2["LATIN_CAPITAL_A"] = 65] = "LATIN_CAPITAL_A";
CODE_POINTS2[CODE_POINTS2["LATIN_CAPITAL_Z"] = 90] = "LATIN_CAPITAL_Z";
CODE_POINTS2[CODE_POINTS2["RIGHT_SQUARE_BRACKET"] = 93] = "RIGHT_SQUARE_BRACKET";
CODE_POINTS2[CODE_POINTS2["GRAVE_ACCENT"] = 96] = "GRAVE_ACCENT";
CODE_POINTS2[CODE_POINTS2["LATIN_SMALL_A"] = 97] = "LATIN_SMALL_A";
CODE_POINTS2[CODE_POINTS2["LATIN_SMALL_Z"] = 122] = "LATIN_SMALL_Z";
})(CODE_POINTS || (CODE_POINTS = {}));
var SEQUENCES = {
DASH_DASH: "--",
CDATA_START: "[CDATA[",
DOCTYPE: "doctype",
SCRIPT: "script",
PUBLIC: "public",
SYSTEM: "system"
};
function isSurrogate(cp) {
return cp >= 55296 && cp <= 57343;
}
function isSurrogatePair(cp) {
return cp >= 56320 && cp <= 57343;
}
function getSurrogatePairCodePoint(cp1, cp2) {
return (cp1 - 55296) * 1024 + 9216 + cp2;
}
function isControlCodePoint(cp) {
return cp !== 32 && cp !== 10 && cp !== 13 && cp !== 9 && cp !== 12 && cp >= 1 && cp <= 31 || cp >= 127 && cp <= 159;
}
function isUndefinedCodePoint(cp) {
return cp >= 64976 && cp <= 65007 || UNDEFINED_CODE_POINTS.has(cp);
}
// node_modules/parse5/dist/common/error-codes.js
var ERR;
(function(ERR2) {
ERR2["controlCharacterInInputStream"] = "control-character-in-input-stream";
ERR2["noncharacterInInputStream"] = "noncharacter-in-input-stream";
ERR2["surrogateInInputStream"] = "surrogate-in-input-stream";
ERR2["nonVoidHtmlElementStartTagWithTrailingSolidus"] = "non-void-html-element-start-tag-with-trailing-solidus";
ERR2["endTagWithAttributes"] = "end-tag-with-attributes";
ERR2["endTagWithTrailingSolidus"] = "end-tag-with-trailing-solidus";
ERR2["unexpectedSolidusInTag"] = "unexpected-solidus-in-tag";
ERR2["unexpectedNullCharacter"] = "unexpected-null-character";
ERR2["unexpectedQuestionMarkInsteadOfTagName"] = "unexpected-question-mark-instead-of-tag-name";
ERR2["invalidFirstCharacterOfTagName"] = "invalid-first-character-of-tag-name";
ERR2["unexpectedEqualsSignBeforeAttributeName"] = "unexpected-equals-sign-before-attribute-name";
ERR2["missingEndTagName"] = "missing-end-tag-name";
ERR2["unexpectedCharacterInAttributeName"] = "unexpected-character-in-attribute-name";
ERR2["unknownNamedCharacterReference"] = "unknown-named-character-reference";
ERR2["missingSemicolonAfterCharacterReference"] = "missing-semicolon-after-character-reference";
ERR2["unexpectedCharacterAfterDoctypeSystemIdentifier"] = "unexpected-character-after-doctype-system-identifier";
ERR2["unexpectedCharacterInUnquotedAttributeValue"] = "unexpected-character-in-unquoted-attribute-value";
ERR2["eofBeforeTagName"] = "eof-before-tag-name";
ERR2["eofInTag"] = "eof-in-tag";
ERR2["missingAttributeValue"] = "missing-attribute-value";
ERR2["missingWhitespaceBetweenAttributes"] = "missing-whitespace-between-attributes";
ERR2["missingWhitespaceAfterDoctypePublicKeyword"] = "missing-whitespace-after-doctype-public-keyword";
ERR2["missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers"] = "missing-whitespace-between-doctype-public-and-system-identifiers";
ERR2["missingWhitespaceAfterDoctypeSystemKeyword"] = "missing-whitespace-after-doctype-system-keyword";
ERR2["missingQuoteBeforeDoctypePublicIdentifier"] = "missing-quote-before-doctype-public-identifier";
ERR2["missingQuoteBeforeDoctypeSystemIdentifier"] = "missing-quote-before-doctype-system-identifier";
ERR2["missingDoctypePublicIdentifier"] = "missing-doctype-public-identifier";
ERR2["missingDoctypeSystemIdentifier"] = "missing-doctype-system-identifier";
ERR2["abruptDoctypePublicIdentifier"] = "abrupt-doctype-public-identifier";
ERR2["abruptDoctypeSystemIdentifier"] = "abrupt-doctype-system-identifier";
ERR2["cdataInHtmlContent"] = "cdata-in-html-content";
ERR2["incorrectlyOpenedComment"] = "incorrectly-opened-comment";
ERR2["eofInScriptHtmlCommentLikeText"] = "eof-in-script-html-comment-like-text";
ERR2["eofInDoctype"] = "eof-in-doctype";
ERR2["nestedComment"] = "nested-comment";
ERR2["abruptClosingOfEmptyComment"] = "abrupt-closing-of-empty-comment";
ERR2["eofInComment"] = "eof-in-comment";
ERR2["incorrectlyClosedComment"] = "incorrectly-closed-comment";
ERR2["eofInCdata"] = "eof-in-cdata";
ERR2["absenceOfDigitsInNumericCharacterReference"] = "absence-of-digits-in-numeric-character-reference";
ERR2["nullCharacterReference"] = "null-character-reference";
ERR2["surrogateCharacterReference"] = "surrogate-character-reference";
ERR2["characterReferenceOutsideUnicodeRange"] = "character-reference-outside-unicode-range";
ERR2["controlCharacterReference"] = "control-character-reference";
ERR2["noncharacterCharacterReference"] = "noncharacter-character-reference";
ERR2["missingWhitespaceBeforeDoctypeName"] = "missing-whitespace-before-doctype-name";
ERR2["missingDoctypeName"] = "missing-doctype-name";
ERR2["invalidCharacterSequenceAfterDoctypeName"] = "invalid-character-sequence-after-doctype-name";
ERR2["duplicateAttribute"] = "duplicate-attribute";
ERR2["nonConformingDoctype"] = "non-conforming-doctype";
ERR2["missingDoctype"] = "missing-doctype";
ERR2["misplacedDoctype"] = "misplaced-doctype";
ERR2["endTagWithoutMatchingOpenElement"] = "end-tag-without-matching-open-element";
ERR2["closingOfElementWithOpenChildElements"] = "closing-of-element-with-open-child-elements";
ERR2["disallowedContentInNoscriptInHead"] = "disallowed-content-in-noscript-in-head";
ERR2["openElementsLeftAfterEof"] = "open-elements-left-after-eof";
ERR2["abandonedHeadElementChild"] = "abandoned-head-element-child";
ERR2["misplacedStartTagForHeadElement"] = "misplaced-start-tag-for-head-element";
ERR2["nestedNoscriptInHead"] = "nested-noscript-in-head";
ERR2["eofInElementThatCanContainOnlyText"] = "eof-in-element-that-can-contain-only-text";
})(ERR || (ERR = {}));
// node_modules/parse5/dist/tokenizer/preprocessor.js
var DEFAULT_BUFFER_WATERLINE = 1 << 16;
var Preprocessor = class {
constructor(handler) {
this.handler = handler;
this.html = "";
this.pos = -1;
this.lastGapPos = -2;
this.gapStack = [];
this.skipNextNewLine = false;
this.lastChunkWritten = false;
this.endOfChunkHit = false;
this.bufferWaterline = DEFAULT_BUFFER_WATERLINE;
this.isEol = false;
this.lineStartPos = 0;
this.droppedBufferSize = 0;
this.line = 1;
this.lastErrOffset = -1;
}
/** The column on the current line. If we just saw a gap (eg. a surrogate pair), return the index before. */
get col() {
return this.pos - this.lineStartPos + Number(this.lastGapPos !== this.pos);
}
get offset() {
return this.droppedBufferSize + this.pos;
}
getError(code, cpOffset) {
const { line, col, offset } = this;
const startCol = col + cpOffset;
const startOffset = offset + cpOffset;
return {
code,
startLine: line,
endLine: line,
startCol,
endCol: startCol,
startOffset,
endOffset: startOffset
};
}
_err(code) {
if (this.handler.onParseError && this.lastErrOffset !== this.offset) {
this.lastErrOffset = this.offset;
this.handler.onParseError(this.getError(code, 0));
}
}
_addGap() {
this.gapStack.push(this.lastGapPos);
this.lastGapPos = this.pos;
}
_processSurrogate(cp) {
if (this.pos !== this.html.length - 1) {
const nextCp = this.html.charCodeAt(this.pos + 1);
if (isSurrogatePair(nextCp)) {
this.pos++;
this._addGap();
return getSurrogatePairCodePoint(cp, nextCp);
}
} else if (!this.lastChunkWritten) {
this.endOfChunkHit = true;
return CODE_POINTS.EOF;
}
this._err(ERR.surrogateInInputStream);
return cp;
}
willDropParsedChunk() {
return this.pos > this.bufferWaterline;
}
dropParsedChunk() {
if (this.willDropParsedChunk()) {
this.html = this.html.substring(this.pos);
this.lineStartPos -= this.pos;
this.droppedBufferSize += this.pos;
this.pos = 0;
this.lastGapPos = -2;
this.gapStack.length = 0;
}
}
write(chunk, isLastChunk) {
if (this.html.length > 0) {
this.html += chunk;
} else {
this.html = chunk;
}
this.endOfChunkHit = false;
this.lastChunkWritten = isLastChunk;
}
insertHtmlAtCurrentPos(chunk) {
this.html = this.html.substring(0, this.pos + 1) + chunk + this.html.substring(this.pos + 1);
this.endOfChunkHit = false;
}
startsWith(pattern, caseSensitive) {
if (this.pos + pattern.length > this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return false;
}
if (caseSensitive) {
return this.html.startsWith(pattern, this.pos);
}
for (let i = 0; i < pattern.length; i++) {
const cp = this.html.charCodeAt(this.pos + i) | 32;
if (cp !== pattern.charCodeAt(i)) {
return false;
}
}
return true;
}
peek(offset) {
const pos = this.pos + offset;
if (pos >= this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return CODE_POINTS.EOF;
}
const code = this.html.charCodeAt(pos);
return code === CODE_POINTS.CARRIAGE_RETURN ? CODE_POINTS.LINE_FEED : code;
}
advance() {
this.pos++;
if (this.isEol) {
this.isEol = false;
this.line++;
this.lineStartPos = this.pos;
}
if (this.pos >= this.html.length) {
this.endOfChunkHit = !this.lastChunkWritten;
return CODE_POINTS.EOF;
}
let cp = this.html.charCodeAt(this.pos);
if (cp === CODE_POINTS.CARRIAGE_RETURN) {
this.isEol = true;
this.skipNextNewLine = true;
return CODE_POINTS.LINE_FEED;
}
if (cp === CODE_POINTS.LINE_FEED) {
this.isEol = true;
if (this.skipNextNewLine) {
this.line--;
this.skipNextNewLine = false;
this._addGap();
return this.advance();
}
}
this.skipNextNewLine = false;
if (isSurrogate(cp)) {
cp = this._processSurrogate(cp);
}
const isCommonValidRange = this.handler.onParseError === null || cp > 31 && cp < 127 || cp === CODE_POINTS.LINE_FEED || cp === CODE_POINTS.CARRIAGE_RETURN || cp > 159 && cp < 64976;
if (!isCommonValidRange) {
this._checkForProblematicCharacters(cp);
}
return cp;
}
_checkForProblematicCharacters(cp) {
if (isControlCodePoint(cp)) {
this._err(ERR.controlCharacterInInputStream);
} else if (isUndefinedCodePoint(cp)) {
this._err(ERR.noncharacterInInputStream);
}
}
retreat(count) {
this.pos -= count;
while (this.pos < this.lastGapPos) {
this.lastGapPos = this.gapStack.pop();
this.pos--;
}
this.isEol = false;
}
};
// node_modules/parse5/dist/common/token.js
var token_exports = {};
__export(token_exports, {
TokenType: () => TokenType,
getTokenAttr: () => getTokenAttr
});
var TokenType;
(function(TokenType2) {
TokenType2[TokenType2["CHARACTER"] = 0] = "CHARACTER";
TokenType2[TokenType2["NULL_CHARACTER"] = 1] = "NULL_CHARACTER";
TokenType2[TokenType2["WHITESPACE_CHARACTER"] = 2] = "WHITESPACE_CHARACTER";
TokenType2[TokenType2["START_TAG"] = 3] = "START_TAG";
TokenType2[TokenType2["END_TAG"] = 4] = "END_TAG";
TokenType2[TokenType2["COMMENT"] = 5] = "COMMENT";
TokenType2[TokenType2["DOCTYPE"] = 6] = "DOCTYPE";
TokenType2[TokenType2["EOF"] = 7] = "EOF";
TokenType2[TokenType2["HIBERNATION"] = 8] = "HIBERNATION";
})(TokenType || (TokenType = {}));
function getTokenAttr(token, attrName) {
for (let i = token.attrs.length - 1; i >= 0; i--) {
if (token.attrs[i].name === attrName) {
return token.attrs[i].value;
}
}
return null;
}
// node_modules/entities/lib/esm/generated/decode-data-html.js
var decode_data_html_default = new Uint16Array(
// prettier-ignore
'\u1D41<\xD5\u0131\u028A\u049D\u057B\u05D0\u0675\u06DE\u07A2\u07D6\u080F\u0A4A\u0A91\u0DA1\u0E6D\u0F09\u0F26\u10CA\u1228\u12E1\u1415\u149D\u14C3\u14DF\u1525\0\0\0\0\0\0\u156B\u16CD\u198D\u1C12\u1DDD\u1F7E\u2060\u21B0\u228D\u23C0\u23FB\u2442\u2824\u2912\u2D08\u2E48\u2FCE\u3016\u32BA\u3639\u37AC\u38FE\u3A28\u3A71\u3AE0\u3B2E\u0800EMabcfglmnoprstu\\bfms\x7F\x84\x8B\x90\x95\x98\xA6\xB3\xB9\xC8\xCFlig\u803B\xC6\u40C6P\u803B&\u4026cute\u803B\xC1\u40C1reve;\u4102\u0100iyx}rc\u803B\xC2\u40C2;\u4410r;\uC000\u{1D504}rave\u803B\xC0\u40C0pha;\u4391acr;\u4100d;\u6A53\u0100gp\x9D\xA1on;\u4104f;\uC000\u{1D538}plyFunction;\u6061ing\u803B\xC5\u40C5\u0100cs\xBE\xC3r;\uC000\u{1D49C}ign;\u6254ilde\u803B\xC3\u40C3ml\u803B\xC4\u40C4\u0400aceforsu\xE5\xFB\xFE\u0117\u011C\u0122\u0127\u012A\u0100cr\xEA\xF2kslash;\u6216\u0176\xF6\xF8;\u6AE7ed;\u6306y;\u4411\u0180crt\u0105\u010B\u0114ause;\u6235noullis;\u612Ca;\u4392r;\uC000\u{1D505}pf;\uC000\u{1D539}eve;\u42D8c\xF2\u0113mpeq;\u624E\u0700HOacdefhilorsu\u014D\u0151\u0156\u0180\u019E\u01A2\u01B5\u01B7\u01BA\u01DC\u0215\u0273\u0278\u027Ecy;\u4427PY\u803B\xA9\u40A9\u0180cpy\u015D\u0162\u017Aute;\u4106\u0100;i\u0167\u0168\u62D2talDifferentialD;\u6145leys;\u612D\u0200aeio\u0189\u018E\u0194\u0198ron;\u410Cdil\u803B\xC7\u40C7rc;\u4108nint;\u6230ot;\u410A\u0100dn\u01A7\u01ADilla;\u40B8terDot;\u40B7\xF2\u017Fi;\u43A7rcle\u0200DMPT\u01C7\u01CB\u01D1\u01D6ot;\u6299inus;\u6296lus;\u6295imes;\u6297o\u0100cs\u01E2\u01F8kwiseContourIntegral;\u6232eCurly\u0100DQ\u0203\u020FoubleQuote;\u601Duote;\u6019\u0200lnpu\u021E\u0228\u0247\u0255on\u0100;e\u0225\u0226\u6237;\u6A74\u0180git\u022F\u0236\u023Aruent;\u6261nt;\u622FourIntegral;\u622E\u0100fr\u024C\u024E;\u6102oduct;\u6210nterClockwiseContourIntegral;\u6233oss;\u6A2Fcr;\uC000\u{1D49E}p\u0100;C\u0284\u0285\u62D3ap;\u624D\u0580DJSZacefios\u02A0\u02AC\u02B0\u02B4\u02B8\u02CB\u02D7\u02E1\u02E6\u0333\u048D\u0100;o\u0179\u02A5trahd;\u6911cy;\u4402cy;\u4405cy;\u440F\u0180grs\u02BF\u02C4\u02C7ger;\u6021r;\u61A1hv;\u6AE4\u0100ay\u02D0\u02D5ron;\u410E;\u4414l\u0100;t\u02DD\u02DE\u6207a;\u4394r;\uC000\u{1D507}\u0100af\u02EB\u0327\u0100cm\u02F0\u0322ritical\u0200ADGT\u0300\u0306\u0316\u031Ccute;\u40B4o\u0174\u030B\u030D;\u42D9bleAcute;\u42DDrave;\u4060ilde;\u42DCond;\u62C4ferentialD;\u6146\u0470\u033D\0\0\0\u0342\u0354\0\u0405f;\uC000\u{1D53B}\u0180;DE\u0348\u0349\u034D\u40A8ot;\u60DCqual;\u6250ble\u0300CDLRUV\u0363\u0372\u0382\u03CF\u03E2\u03F8ontourIntegra\xEC\u0239o\u0274\u0379\0\0\u037B\xBB\u0349nArrow;\u61D3\u0100eo\u0387\u03A4ft\u0180ART\u0390\u0396\u03A1rrow;\u61D0ightArrow;\u61D4e\xE5\u02CAng\u0100LR\u03AB\u03C4eft\u0100AR\u03B3\u03B9rrow;\u67F8ightArrow;\u67FAightArrow;\u67F9ight\u0100AT\u03D8\u03DErrow;\u61D2ee;\u62A8p\u0241\u03E9\0\0\u03EFrrow;\u61D1ownArrow;\u61D5erticalBar;\u6225n\u0300ABLRTa\u0412\u042A\u0430\u045E\u047F\u037Crrow\u0180;BU\u041D\u041E\u0422\u6193ar;\u6913pArrow;\u61F5reve;\u4311eft\u02D2\u043A\0\u0446\0\u0450ightVector;\u6950eeVector;\u695Eector\u0100;B\u0459\u045A\u61BDar;\u6956ight\u01D4\u0467\0\u0471eeVector;\u695Fector\u0100;B\u047A\u047B\u61C1ar;\u6957ee\u0100;A\u0486\u0487\u62A4rrow;\u61A7\u0100ct\u0492\u0497r;\uC000\u{1D49F}rok;\u4110\u0800NTacdfglmopqstux\u04BD\u04C0\u04C4\u04CB\u04DE\u04E2\u04E7\u04EE\u04F5\u0521\u052F\u0536\u0552\u055D\u0560\u0565G;\u414AH\u803B\xD0\u40D0cute\u803B\xC9\u40C9\u0180aiy\u04D2\u04D7\u04DCron;\u411Arc\u803B\xCA\u40CA;\u442Dot;\u4116r;\uC000\u{1D508}rave\u803B\xC8\u40C8ement;\u6208\u0100ap\u04FA\u04FEcr;\u4112ty\u0253\u0506\0\0\u0512mallSquare;\u65FBerySmallSquare;\u65AB\u0100gp\u0526\u052Aon;\u4118f;\uC000\u{1D53C}silon;\u4395u\u0100ai\u053C\u0549l\u0100;T\u0542\u0543\u6A75ilde;\u6242librium;\u61CC\u0100ci\u0557\u055Ar;\u6130m;\u6A73a;\u4397ml\u803B\xCB\u40CB\u0100ip\u056A\u056Fsts;\u6203onentialE;\u6147\u0280cfios\u0585\u0588\u058D\u05B2\u05CCy;\u4424r;\uC000\u{1D509}lled\u0253\u0597\0\0\u05A3mallSquare;\u65FCerySmallSquare;\u65AA\u0370\u05BA\0\u05BF\0\0\u05C4f;\uC000\u{1D53D}All;\u6200riertrf;\u6131c\xF2\u05CB\u0600JTabcdfgorst\u05E8\u05EC\u05EF\u05FA\u0600\u0612\u0616\u061B\u061D\u0623\u066C\u0672cy;\u4403\u803B>\u403Emma\u0100;d\u05F7\u05F8\u4393;\u43DCreve;\u411E\u0180eiy\u0607\u060C\u0610dil;\u4122rc;\u411C;\u4413ot;\u4120r;\uC000\u{1D50A};\u62D9pf;\uC000\u{1D53E}eater\u0300EFGLST\u0635\u0644\u064E\u0656\u065B\u0666qual\u0100;L\u063E\u063F\u6265ess;\u62DBullEqual;\u6267reater;\u6AA2ess;\u6277lantEqual;\u6A7Eilde;\u6273cr;\uC000\u{1D4A2};\u626B\u0400Aacfiosu\u0685\u068B\u0696\u069B\u069E\u06AA\u06BE\u06CARDcy;\u442A\u0100ct\u0690\u0694ek;\u42C7;\u405Eirc;\u4124r;\u610ClbertSpace;\u610B\u01F0\u06AF\0\u06B2f;\u610DizontalLine;\u6500\u0100ct\u06C3\u06C5\xF2\u06A9rok;\u4126mp\u0144\u06D0\u06D8ownHum\xF0\u012Fqual;\u624F\u0700EJOacdfgmnostu\u06FA\u06FE\u0703\u0707\u070E\u071A\u071E\u0721\u0728\u0744\u0778\u078B\u078F\u0795cy;\u4415lig;\u4132cy;\u4401cute\u803B\xCD\u40CD\u0100iy\u0713\u0718rc\u803B\xCE\u40CE;\u4418ot;\u4130r;\u6111rave\u803B\xCC\u40CC\u0180;ap\u0720\u072F\u073F\u0100cg\u0734\u0737r;\u412AinaryI;\u6148lie\xF3\u03DD\u01F4\u0749\0\u0762\u0100;e\u074D\u074E\u622C\u0100gr\u0753\u0758ral;\u622Bsection;\u62C2isible\u0100CT\u076C\u0772omma;\u6063imes;\u6062\u0180gpt\u077F\u0783\u0788on;\u412Ef;\uC000\u{1D540}a;\u4399cr;\u6110ilde;\u4128\u01EB\u079A\0\u079Ecy;\u4406l\u803B\xCF\u40CF\u0280cfosu\u07AC\u07B7\u07BC\u07C2\u07D0\u0100iy\u07B1\u07B5rc;\u4134;\u4419r;\uC000\u{1D50D}pf;\uC000\u{1D541}\u01E3\u07C7\0\u07CCr;\uC000\u{1D4A5}rcy;\u4408kcy;\u4404\u0380HJacfos\u07E4\u07E8\u07EC\u07F1\u07FD\u0802\u0808cy;\u4425cy;\u440Cppa;\u439A\u0100ey\u07F6\u07FBdil;\u4136;\u441Ar;\uC000\u{1D50E}pf;\uC000\u{1D542}cr;\uC000\u{1D4A6}\u0580JTaceflmost\u0825\u0829\u082C\u0850\u0863\u09B3\u09B8\u09C7\u09CD\u0A37\u0A47cy;\u4409\u803B<\u403C\u0280cmnpr\u0837\u083C\u0841\u0844\u084Dute;\u4139bda;\u439Bg;\u67EAlacetrf;\u6112r;\u619E\u0180aey\u0857\u085C\u0861ron;\u413Ddil;\u413B;\u441B\u0100fs\u0868\u0970t\u0500ACDFRTUVar\u087E\u08A9\u08B1\u08E0\u08E6\u08FC\u092F\u095B\u0390\u096A\u0100nr\u0883\u088FgleBracket;\u67E8row\u0180;BR\u0899\u089A\u089E\u6190ar;\u61E4ightArrow;\u61C6eiling;\u6308o\u01F5\u08B7\0\u08C3bleBracket;\u67E6n\u01D4\u08C8\0\u08D2eeVector;\u6961ector\u0100;B\u08DB\u08DC\u61C3ar;\u6959loor;\u630Aight\u0100AV\u08EF\u08F5rrow;\u6194ector;\u694E\u0100er\u0901\u0917e\u0180;AV\u0909\u090A\u0910\u62A3rrow;\u61A4ector;\u695Aiangle\u0180;BE\u0924\u0925\u0929\u62B2ar;\u69CFqual;\u62B4p\u0180DTV\u0937\u0942\u094CownVector;\u6951eeVector;\u6960ector\u0100;B\u0956\u0957\u61BFar;\u6958ector\u0100;B\u0965\u0966\u61BCar;\u6952ight\xE1\u039Cs\u0300EFGLST\u097E\u098B\u0995\u099D\u09A2\u09ADqualGreater;\u62DAullEqual;\u6266reater;\u6276ess;\u6AA1lantEqual;\u6A7Dilde;\u6272r;\uC000\u{1D50F}\u0100;e\u09BD\u09BE\u62D8ftarrow;\u61DAidot;\u413F\u0180npw\u09D4\u0A16\u0A1Bg\u0200LRlr\u09DE\u09F7\u0A02\u0A10eft\u0100AR\u09E6\u09ECrrow;\u67F5ightArrow;\u67F7ightArrow;\u67F6eft\u0100ar\u03B3\u0A0Aight\xE1\u03BFight\xE1\u03CAf;\uC000\u{1D543}er\u0100LR\u0A22\u0A2CeftArrow;\u6199ightArrow;\u6198\u0180cht\u0A3E\u0A40\u0A42\xF2\u084C;\u61B0rok;\u4141;\u626A\u0400acefiosu\u0A5A\u0A5D\u0A60\u0A77\u0A7C\u0A85\u0A8B\u0A8Ep;\u6905y;\u441C\u0100dl\u0A65\u0A6FiumSpace;\u605Flintrf;\u6133r;\uC000\u{1D510}nusPlus;\u6213pf;\uC000\u{1D544}c\xF2\u0A76;\u439C\u0480Jacefostu\u0AA3\u0AA7\u0AAD\u0AC0\u0B14\u0B19\u0D91\u0D97\u0D9Ecy;\u440Acute;\u4143\u0180aey\u0AB4\u0AB9\u0ABEron;\u4147dil;\u4145;\u441D\u0180gsw\u0AC7\u0AF0\u0B0Eative\u0180MTV\u0AD3\u0ADF\u0AE8ediumSpace;\u600Bhi\u0100cn\u0AE6\u0AD8\xEB\u0AD9eryThi\xEE\u0AD9ted\u0100GL\u0AF8\u0B06reaterGreate\xF2\u0673essLes\xF3\u0A48Line;\u400Ar;\uC000\u{1D511}\u0200Bnpt\u0B22\u0B28\u0B37\u0B3Areak;\u6060BreakingSpace;\u40A0f;\u6115\u0680;CDEGHLNPRSTV\u0B55\u0B56\u0B6A\u0B7C\u0BA1\u0BEB\u0C04\u0C5E\u0C84\u0CA6\u0CD8\u0D61\u0D85\u6AEC\u0100ou\u0B5B\u0B64ngruent;\u6262pCap;\u626DoubleVerticalBar;\u6226\u0180lqx\u0B83\u0B8A\u0B9Bement;\u6209ual\u0100;T\u0B92\u0B93\u6260ilde;\uC000\u2242\u0338ists;\u6204reater\u0380;EFGLST\u0BB6\u0BB7\u0BBD\u0BC9\u0BD3\u0BD8\u0BE5\u626Fqual;\u6271ullEqual;\uC000\u2267\u0338reater;\uC000\u226B\u0338ess;\u6279lantEqual;\uC000\u2A7E\u0338ilde;\u6275ump\u0144\u0BF2\u0BFDownHump;\uC000\u224E\u0338qual;\uC000\u224F\u0338e\u0100fs\u0C0A\u0C27tTriangle\u0180;BE\u0C1A\u0C1B\u0C21\u62EAar;\uC000\u29CF\u0338qual;\u62ECs\u0300;EGLST\u0C35\u0C36\u0C3C\u0C44\u0C4B\u0C58\u626Equal;\u6270reater;\u6278ess;\uC000\u226A\u0338lantEqual;\uC000\u2A7D\u0338ilde;\u6274ested\u0100GL\u0C68\u0C79reaterGreater;\uC000\u2AA2\u0338essLess;\uC000\u2AA1\u0338recedes\u0180;ES\u0C92\u0C93\u0C9B\u6280qual;\uC000\u2AAF\u0338lantEqual;\u62E0\u0100ei\u0CAB\u0CB9verseElement;\u620CghtTriangle\u0180;BE\u0CCB\u0CCC\u0CD2\u62EBar;\uC000\u29D0\u0338qual;\u62ED\u0100qu\u0CDD\u0D0CuareSu\u0100bp\u0CE8\u0CF9set\u0100;E\u0CF0\u0CF3\uC000\u228F\u0338qual;\u62E2erset\u0100;E\u0D03\u0D06\uC000\u2290\u0338qual;\u62E3\u0180bcp\u0D13\u0D24\u0D4Eset\u0100;E\u0D1B\u0D1E\uC000\u2282\u20D2qual;\u6288ceeds\u0200;EST\u0D32\u0D33\u0D3B\u0D46\u6281qual;\uC000\u2AB0\u0338lantEqual;\u62E1ilde;\uC000\u227F\u0338erset\u0100;E\u0D58\u0D5B\uC000\u2283\u20D2qual;\u6289ilde\u0200;EFT\u0D6E\u0D6F\u0D75\u0D7F\u6241qual;\u6244ullEqual;\u6247ilde;\u6249erticalBar;\u6224cr;\uC000\u{1D4A9}ilde\u803B\xD1\u40D1;\u439D\u0700Eacdfgmoprstuv\u0DBD\u0DC2\u0DC9\u0DD5\u0DDB\u0DE0\u0DE7\u0DFC\u0E02\u0E20\u0E22\u0E32\u0E3F\u0E44lig;\u4152cute\u803B\xD3\u40D3\u0100iy\u0DCE\u0DD3rc\u803B\xD4\u40D4;\u441Eblac;\u4150r;\uC000\u{1D512}rave\u803B\xD2\u40D2\u0180aei\u0DEE\u0DF2\u0DF6cr;\u414Cga;\u43A9cron;\u439Fpf;\uC000\u{1D546}enCurly\u0100DQ\u0E0E\u0E1AoubleQuote;\u601Cuote;\u6018;\u6A54\u0100cl\u0E27\u0E2Cr;\uC000\u{1D4AA}ash\u803B\xD8\u40D8i\u016C\u0E37\u0E3Cde\u803B\xD5\u40D5es;\u6A37ml\u803B\xD6\u40D6er\u0100BP\u0E4B\u0E60\u0100ar\u0E50\u0E53r;\u603Eac\u0100ek\u0E5A\u0E5C;\u63DEet;\u63B4arenthesis;\u63DC\u0480acfhilors\u0E7F\u0E87\u0E8A\u0E8F\u0E92\u0E94\u0E9D\u0EB0\u0EFCrtialD;\u6202y;\u441Fr;\uC000\u{1D513}i;\u43A6;\u43A0usMinus;\u40B1\u0100ip\u0EA2\u0EADncareplan\xE5\u069Df;\u6119\u0200;eio\u0EB9\u0EBA\u0EE0\u0EE4\u6ABBcedes\u0200;EST\u0EC8\u0EC9\u0ECF\u0EDA\u627Aqual;\u6AAFlantEqual;\u627Cilde;\u627Eme;\u6033\u0100dp\u0EE9\u0EEEuct;\u620Fortion\u0100;a\u0225\u0EF9l;\u621D\u0100ci\u0F01\u0F06r;\uC000\u{1D4AB};\u43A8\u0200Ufos\u0F11\u0F16\u0F1B\u0F1FOT\u803B"\u4022r;\uC000\u{1D514}pf;\u611Acr;\uC000\u{1D4AC}\u0600BEacefhiorsu\u0F3E\u0F43\u0F47\u0F60\u0F73\u0FA7\u0FAA\u0FAD\u1096\u10A9\u10B4\u10BEarr;\u6910G\u803B\xAE\u40AE\u0180cnr\u0F4E\u0F53\u0F56ute;\u4154g;\u67EBr\u0100;t\u0F5C\u0F5D\u61A0l;\u6916\u0180aey\u0F67\u0F6C\u0F71ron;\u4158dil;\u4156;\u4420\u0100;v\u0F78\u0F79\u611Cerse\u0100EU\u0F82\u0F99\u0100lq\u0F87\u0F8Eement;\u620Builibrium;\u61CBpEquilibrium;\u696Fr\xBB\u0F79o;\u43A1ght\u0400ACDFTUVa\u0FC1\u0FEB\u0FF3\u1022\u1028\u105B\u1087\u03D8\u0100nr\u0FC6\u0FD2gleBracket;\u67E9row\u0180;BL\u0FDC\u0FDD\u0FE1\u6192ar;\u61E5eftArrow;\u61C4eiling;\u6309o\u01F5\u0FF9\0\u1005bleBracket;\u67E7n\u01D4\u100A\0\u1014eeVector;\u695Dector\u0100;B\u101D\u101E\u61C2ar;\u6955loor;\u630B\u0100er\u102D\u1043e\u0180;AV\u1035\u1036\u103C\u62A2rrow;\u61A6ector;\u695Biangle\u0180;BE\u1050\u1051\u1055\u62B3ar;\u69D0qual;\u62B5p\u0180DTV\u1063\u106E\u1078ownVector;\u694FeeVector;\u695Cector\u0100;B\u1082\u1083\u61BEar;\u6954ector\u0100;B\u1091\u1092\u61C0ar;\u6953\u0100pu\u109B\u109Ef;\u611DndImplies;\u6970ightarrow;\u61DB\u0100ch\u10B9\u10BCr;\u611B;\u61B1leDelayed;\u69F4\u0680HOacfhimoqstu\u10E4\u10F1\u10F7\u10FD\u1119\u111E\u1151\u1156\u1161\u1167\u11B5\u11BB\u11BF\u0100Cc\u10E9\u10EEHcy;\u4429y;\u4428FTcy;\u442Ccute;\u415A\u0280;aeiy\u1108\u1109\u110E\u1113\u1117\u6ABCron;\u4160dil;\u415Erc;\u415C;\u4421r;\uC000\u{1D516}ort\u0200DLRU\u112A\u1134\u113E\u1149ownArrow\xBB\u041EeftArrow\xBB\u089AightArrow\xBB\u0FDDpArrow;\u6191gma;\u43A3allCircle;\u6218pf;\uC000\u{1D54A}\u0272\u116D\0\0\u1170t;\u621Aare\u0200;ISU\u117B\u117C\u1189\u11AF\u65A1ntersection;\u6293u\u0100bp\u118F\u119Eset\u0100;E\u1197\u1198\u628Fqual;\u6291erset\u0100;E\u11A8\u11A9\u6290qual;\u6292nion;\u6294cr;\uC000\u{1D4AE}ar;\u62C6\u0200bcmp\u11C8\u11DB\u1209\u120B\u0100;s\u11CD\u11CE\u62D0et\u0100;E\u11CD\u11D5qual;\u6286\u0100ch\u11E0\u1205eeds\u0200;EST\u11ED\u11EE\u11F4\u11FF\u627Bqual;\u6AB0lantEqual;\u627Dilde;\u627FTh\xE1\u0F8C;\u6211\u0180;es\u1212\u1213\u1223\u62D1rset\u0100;E\u121C\u121D\u6283qual;\u6287et\xBB\u1213\u0580HRSacfhiors\u123E\u1244\u1249\u1255\u125E\u1271\u1276\u129F\u12C2\u12C8\u12D1ORN\u803B\xDE\u40DEADE;\u6122\u0100Hc\u124E\u1252cy;\u440By;\u4426\u0100bu\u125A\u125C;\u4009;\u43A4\u0180aey\u1265\u126A\u126Fron;\u4164dil;\u4162;\u4422r;\uC000\u{1D517}\u0100ei\u127B\u1289\u01F2\u1280\0\u1287efore;\u6234a;\u4398\u0100cn\u128E\u1298kSpace;\uC000\u205F\u200ASpace;\u6009lde\u0200;EFT\u12AB\u12AC\u12B2\u12BC\u623Cqual;\u6243ullEqual;\u6245ilde;\u6248pf;\uC000\u{1D54B}ipleDot;\u60DB\u0100ct\u12D6\u12DBr;\uC000\u{1D4AF}rok;\u4166\u0AE1\u12F7\u130E\u131A\u1326\0\u132C\u1331\0\0\0\0\0\u1338\u133D\u1377\u1385\0\u13FF\u1404\u140A\u1410\u0100cr\u12FB\u1301ute\u803B\xDA\u40DAr\u0100;o\u1307\u1308\u619Fcir;\u6949r\u01E3\u1313\0\u1316y;\u440Eve;\u416C\u0100iy\u131E\u1323rc\u803B\xDB\u40DB;\u4423blac;\u4170r;\uC000\u{1D518}rave\u803B\xD9\u40D9acr;\u416A\u0100di\u1341\u1369er\u0100BP\u1348\u135D\u0100ar\u134D\u1350r;\u405Fac\u0100ek\u1357\u1359;\u63DFet;\u63B5arenthesis;\u63DDon\u0100;P\u1370\u1371\u62C3lus;\u628E\u0100gp\u137B\u137Fon;\u4172f;\uC000\u{1D54C}\u0400ADETadps\u1395\u13AE\u13B8\u13C4\u03E8\u13D2\u13D7\u13F3rrow\u0180;BD\u1150\u13A0\u13A4ar;\u6912ownArrow;\u61C5ownArrow;\u6195quilibrium;\u696Eee\u0100;A\u13CB\u13CC\u62A5rrow;\u61A5own\xE1\u03F3er\u0100LR\u13DE\u13E8eftArrow;\u6196ightArrow;\u6197i\u0100;l\u13F9\u13FA\u43D2on;\u43A5ing;\u416Ecr;\uC000\u{1D4B0}ilde;\u4168ml\u803B\xDC\u40DC\u0480Dbcdefosv\u1427\u142C\u1430\u1433\u143E\u1485\u148A\u1490\u1496ash;\u62ABar;\u6AEBy;\u4412ash\u0100;l\u143B\u143C\u62A9;\u6AE6\u0100er\u1443\u1445;\u62C1\u0180bty\u144C\u1450\u147Aar;\u6016\u0100;i\u144F\u1455cal\u0200BLST\u1461\u1465\u146A\u1474ar;\u6223ine;\u407Ceparator;\u6758ilde;\u6240ThinSpace;\u600Ar;\uC000\u{1D519}pf;\uC000\u{1D54D}cr;\uC000\u{1D4B1}dash;\u62AA\u0280cefos\u14A7\u14AC\u14B1\u14B6\u14BCirc;\u4174dge;\u62C0r;\uC000\u{1D51A}pf;\uC000\u{1D54E}cr;\uC000\u{1D4B2}\u0200fios\u14CB\u14D0\u14D2\u14D8r;\uC000\u{1D51B};\u439Epf;\uC000\u{1D54F}cr;\uC000\u{1D4B3}\u0480AIUacfosu\u14F1\u14F5\u14F9\u14FD\u1504\u150F\u1514\u151A\u1520cy;\u442Fcy;\u4407cy;\u442Ecute\u803B\xDD\u40DD\u0100iy\u1509\u150Drc;\u4176;\u442Br;\uC000\u{1D51C}pf;\uC000\u{1D550}cr;\uC000\u{1D4B4}ml;\u4178\u0400Hacdefos\u1535\u1539\u153F\u154B\u154F\u155D\u1560\u1564cy;\u4416cute;\u4179\u0100ay\u1544\u1549ron;\u417D;\u4417ot;\u417B\u01F2\u1554\0\u155BoWidt\xE8\u0AD9a;\u4396r;\u6128pf;\u6124cr;\uC000\u{1D4B5}\u0BE1\u1583\u158A\u1590\0\u15B0\u15B6\u15BF\0\0\0\0\u15C6\u15DB\u15EB\u165F\u166D\0\u1695\u169B\u16B2\u16B9\0\u16BEcute\u803B\xE1\u40E1reve;\u4103\u0300;Ediuy\u159C\u159D\u15A1\u15A3\u15A8\u15AD\u623E;\uC000\u223E\u0333;\u623Frc\u803B\xE2\u40E2te\u80BB\xB4\u0306;\u4430lig\u803B\xE6\u40E6\u0100;r\xB2\u15BA;\uC000\u{1D51E}rave\u803B\xE0\u40E0\u0100ep\u15CA\u15D6\u0100fp\u15CF\u15D4sym;\u6135\xE8\u15D3ha;\u43B1\u0100ap\u15DFc\u0100cl\u15E4\u15E7r;\u4101g;\u6A3F\u0264\u15F0\0\0\u160A\u0280;adsv\u15FA\u15FB\u15FF\u1601\u1607\u6227nd;\u6A55;\u6A5Clope;\u6A58;\u6A5A\u0380;elmrsz\u1618\u1619\u161B\u161E\u163F\u164F\u1659\u6220;\u69A4e\xBB\u1619sd\u0100;a\u1625\u1626\u6221\u0461\u1630\u1632\u1634\u1636\u1638\u163A\u163C\u163E;\u69A8;\u69A9;\u69AA;\u69AB;\u69AC;\u69AD;\u69AE;\u69AFt\u0100;v\u1645\u1646\u621Fb\u0100;d\u164C\u164D\u62BE;\u699D\u0100pt\u1654\u1657h;\u6222\xBB\xB9arr;\u637C\u0100gp\u1663\u1667on;\u4105f;\uC000\u{1D552}\u0380;Eaeiop\u12C1\u167B\u167D\u1682\u1684\u1687\u168A;\u6A70cir;\u6A6F;\u624Ad;\u624Bs;\u4027rox\u0100;e\u12C1\u1692\xF1\u1683ing\u803B\xE5\u40E5\u0180cty\u16A1\u16A6\u16A8r;\uC000\u{1D4B6};\u402Amp\u0100;e\u12C1\u16AF\xF1\u0288ilde\u803B\xE3\u40E3ml\u803B\xE4\u40E4\u0100ci\u16C2\u16C8onin\xF4\u0272nt;\u6A11\u0800Nabcdefiklnoprsu\u16ED\u16F1\u1730\u173C\u1743\u1748\u1778\u177D\u17E0\u17E6\u1839\u1850\u170D\u193D\u1948\u1970ot;\u6AED\u0100cr\u16F6\u171Ek\u0200ceps\u1700\u1705\u170D\u1713ong;\u624Cpsilon;\u43F6rime;\u6035im\u0100;e\u171A\u171B\u623Dq;\u62CD\u0176\u1722\u1726ee;\u62BDed\u0100;g\u172C\u172D\u6305e\xBB\u172Drk\u0100;t\u135C\u1737brk;\u63B6\u0100oy\u1701\u1741;\u4431quo;\u601E\u0280cmprt\u1753\u175B\u1761\u1764\u1768aus\u0100;e\u010A\u0109ptyv;\u69B0s\xE9\u170Cno\xF5\u0113\u0180ahw\u176F\u1771\u1773;\u43B2;\u6136een;\u626Cr;\uC000\u{1D51F}g\u0380costuvw\u178D\u179D\u17B3\u17C1\u17D5\u17DB\u17DE\u0180aiu\u1794\u1796\u179A\xF0\u0760rc;\u65EFp\xBB\u1371\u0180dpt\u17A4\u17A8\u17ADot;\u6A00lus;\u6A01imes;\u6A02\u0271\u17B9\0\0\u17BEcup;\u6A06ar;\u6605riangle\u0100du\u17CD\u17D2own;\u65BDp;\u65B3plus;\u6A04e\xE5\u1444\xE5\u14ADarow;\u690D\u0180ako\u17ED\u1826\u1835\u0100cn\u17F2\u1823k\u0180lst\u17FA\u05AB\u1802ozenge;\u69EBriangle\u0200;dlr\u1812\u1813\u1818\u181D\u65B4own;\u65BEeft;\u65C2ight;\u65B8k;\u6423\u01B1\u182B\0\u1833\u01B2\u182F\0\u1831;\u6592;\u65914;\u6593ck;\u6588\u0100eo\u183E\u184D\u0100;q\u1843\u1846\uC000=\u20E5uiv;\uC000\u2261\u20E5t;\u6310\u0200ptwx\u1859\u185E\u1867\u186Cf;\uC000\u{1D553}\u0100;t\u13CB\u1863om\xBB\u13CCtie;\u62C8\u0600DHUVbdhmptuv\u1885\u1896\u18AA\u18BB\u18D7\u18DB\u18EC\u18FF\u1905\u190A\u1910\u1921\u0200LRlr\u188E\u1890\u1892\u1894;\u6557;\u6554;\u6556;\u6553\u0280;DUdu\u18A1\u18A2\u18A4\u18A6\u18A8\u6550;\u6566;\u6569;\u6564;\u6567\u0200LRlr\u18B3\u18B5\u18B7\u18B9;\u655D;\u655A;\u655C;\u6559\u0380;HLRhlr\u18CA\u18CB\u18CD\u18CF\u18D1\u18D3\u18D5\u6551;\u656C;\u6563;\u6560;\u656B;\u6562;\u655Fox;\u69C9\u0200LRlr\u18E4\u18E6\u18E8\u18EA;\u6555;\u6552;\u6510;\u650C\u0280;DUdu\u06BD\u18F7\u18F9\u18FB\u18FD;\u6565;\u6568;\u652C;\u6534inus;\u629Flus;\u629Eimes;\u62A0\u0200LRlr\u1919\u191B\u191D\u191F;\u655B;\u6558;\u6518;\u6514\u0380;HLRhlr\u1930\u1931\u1933\u1935\u1937\u1939\u193B\u6502;\u656A;\u6561;\u655E;\u653C;\u6524;\u651C\u0100ev\u0123\u1942bar\u803B\xA6\u40A6\u0200ceio\u1951\u1956\u195A\u1960r;\uC000\u{1D4B7}mi;\u604Fm\u0100;e\u171A\u171Cl\u0180;bh\u1968\u1969\u196B\u405C;\u69C5sub;\u67C8\u016C\u1974\u197El\u0100;e\u1979\u197A\u6022t\xBB\u197Ap\u0180;Ee\u012F\u1985\u1987;\u6AAE\u0100;q\u06DC\u06DB\u0CE1\u19A7\0\u19E8\u1A11\u1A15\u1A32\0\u1A37\u1A50\0\0\u1AB4\0\0\u1AC1\0\0\u1B21\u1B2E\u1B4D\u1B52\0\u1BFD\0\u1C0C\u0180cpr\u19AD\u19B2\u19DDute;\u4107\u0300;abcds\u19BF\u19C0\u19C4\u19CA\u19D5\u19D9\u6229nd;\u6A44rcup;\u6A49\u0100au\u19CF\u19D2p;\u6A4Bp;\u6A47ot;\u6A40;\uC000\u2229\uFE00\u0100eo\u19E2\u19E5t;\u6041\xEE\u0693\u0200aeiu\u19F0\u19FB\u1A01\u1A05\u01F0\u19F5\0\u19F8s;\u6A4Don;\u410Ddil\u803B\xE7\u40E7rc;\u4109ps\u0100;s\u1A0C\u1A0D\u6A4Cm;\u6A50ot;\u410B\u0180dmn\u1A1B\u1A20\u1A26il\u80BB\xB8\u01ADptyv;\u69B2t\u8100\xA2;e\u1A2D\u1A2E\u40A2r\xE4\u01B2r;\uC000\u{1D520}\u0180cei\u1A3D\u1A40\u1A4Dy;\u4447ck\u0100;m\u1A47\u1A48\u6713ark\xBB\u1A48;\u43C7r\u0380;Ecefms\u1A5F\u1A60\u1A62\u1A6B\u1AA4\u1AAA\u1AAE\u65CB;\u69C3\u0180;el\u1A69\u1A6A\u1A6D\u42C6q;\u6257e\u0261\u1A74\0\0\u1A88rrow\u0100lr\u1A7C\u1A81eft;\u61BAight;\u61BB\u0280RSacd\u1A92\u1A94\u1A96\u1A9A\u1A9F\xBB\u0F47;\u64C8st;\u629Birc;\u629Aash;\u629Dnint;\u6A10id;\u6AEFcir;\u69C2ubs\u0100;u\u1ABB\u1ABC\u6663it\xBB\u1ABC\u02EC\u1AC7\u1AD4\u1AFA\0\u1B0Aon\u0100;e\u1ACD\u1ACE\u403A\u0100;q\xC7\xC6\u026D\u1AD9\0\0\u1AE2a\u0100;t\u1ADE\u1ADF\u402C;\u4040\u0180;fl\u1AE8\u1AE9\u1AEB\u6201\xEE\u1160e\u0100mx\u1AF1\u1AF6ent\xBB\u1AE9e\xF3\u024D\u01E7\u1AFE\0\u1B07\u0100;d\u12BB\u1B02ot;\u6A6Dn\xF4\u0246\u0180fry\u1B10\u1B14\u1B17;\uC000\u{1D554}o\xE4\u0254\u8100\xA9;s\u0155\u1B1Dr;\u6117\u0100ao\u1B25\u1B29rr;\u61B5ss;\u6717\u0100cu\u1B32\u1B37r;\uC000\u{1D4B8}\u0100bp\u1B3C\u1B44\u0100;e\u1B41\u1B42\u6ACF;\u6AD1\u0100;e\u1B49\u1B4A\u6AD0;\u6AD2dot;\u62EF\u0380delprvw\u1B60\u1B6C\u1B77\u1B82\u1BAC\u1BD4\u1BF9arr\u0100lr\u1B68\u1B6A;\u6938;\u6935\u0270\u1B72\0\0\u1B75r;\u62DEc;\u62DFarr\u0100;p\u1B7F\u1B80\u61B6;\u693D\u0300;bcdos\u1B8F\u1B90\u1B96\u1BA1\u1BA5\u1BA8\u622Arcap;\u6A48\u0100au\u1B9B\u1B9Ep;\u6A46p;\u6A4Aot;\u628Dr;\u6A45;\uC000\u222A\uFE00\u0200alrv\u1BB5\u1BBF\u1BDE\u1BE3rr\u0100;m\u1BBC\u1BBD\u61B7;\u693Cy\u0180evw\u1BC7\u1BD4\u1BD8q\u0270\u1BCE\0\0\u1BD2re\xE3\u1B73u\xE3\u1B75ee;\u62CEedge;\u62CFen\u803B\xA4\u40A4earrow\u0100lr\u1BEE\u1BF3eft\xBB\u1B80ight\xBB\u1BBDe\xE4\u1BDD\u0100ci\u1C01\u1C07onin\xF4\u01F7nt;\u6231lcty;\u632D\u0980AHabcdefhijlorstuwz\u1C38\u1C3B\u1C3F\u1C5D\u1C69\u1C75\u1C8A\u1C9E\u1CAC\u1CB7\u1CFB\u1CFF\u1D0D\u1D7B\u1D91\u1DAB\u1DBB\u1DC6\u1DCDr\xF2\u0381ar;\u6965\u0200glrs\u1C48\u1C4D\u1C52\u1C54ger;\u6020eth;\u6138\xF2\u1133h\u0100;v\u1C5A\u1C5B\u6010\xBB\u090A\u016B\u1C61\u1C67arow;\u690Fa\xE3\u0315\u0100ay\u1C6E\u1C73ron;\u410F;\u4434\u0180;ao\u0332\u1C7C\u1C84\u0100gr\u02BF\u1C81r;\u61CAtseq;\u6A77\u0180glm\u1C91\u1C94\u1C98\u803B\xB0\u40B0ta;\u43B4ptyv;\u69B1\u0100ir\u1CA3\u1CA8sht;\u697F;\uC000\u{1D521}ar\u0100lr\u1CB3\u1CB5\xBB\u08DC\xBB\u101E\u0280aegsv\u1CC2\u0378\u1CD6\u1CDC\u1CE0m\u0180;os\u0326\u1CCA\u1CD4nd\u0100;s\u0326\u1CD1uit;\u6666amma;\u43DDin;\u62F2\u0180;io\u1CE7\u1CE8\u1CF8\u40F7de\u8100\xF7;o\u1CE7\u1CF0ntimes;\u62C7n\xF8\u1CF7cy;\u4452c\u026F\u1D06\0\0\u1D0Arn;\u631Eop;\u630D\u0280lptuw\u1D18\u1D1D\u1D22\u1D49\u1D55lar;\u4024f;\uC000\u{1D555}\u0280;emps\u030B\u1D2D\u1D37\u1D3D\u1D42q\u0100;d\u0352\u1D33ot;\u6251inus;\u6238lus;\u6214quare;\u62A1blebarwedg\xE5\xFAn\u0180adh\u112E\u1D5D\u1D67ownarrow\xF3\u1C83arpoon\u0100lr\u1D72\u1D76ef\xF4\u1CB4igh\xF4\u1CB6\u0162\u1D7F\u1D85karo\xF7\u0F42\u026F\u1D8A\0\0\u1D8Ern;\u631Fop;\u630C\u0180cot\u1D98\u1DA3\u1DA6\u0100ry\u1D9D\u1DA1;\uC000\u{1D4B9};\u4455l;\u69F6rok;\u4111\u0100dr\u1DB0\u1DB4ot;\u62F1i\u0100;f\u1DBA\u1816\u65BF\u0100ah\u1DC0\u1DC3r\xF2\u0429a\xF2\u0FA6angle;\u69A6\u0100ci\u1DD2\u1DD5y;\u445Fgrarr;\u67FF\u0900Dacdefglmnopqrstux\u1E01\u1E09\u1E19\u1E38\u0578\u1E3C\u1E49\u1E61\u1E7E\u1EA5\u1EAF\u1EBD\u1EE1\u1F2A\u1F37\u1F44\u1F4E\u1F5A\u0100Do\u1E06\u1D34o\xF4\u1C89\u0100cs\u1E0E\u1E14ute\u803B\xE9\u40E9ter;\u6A6E\u0200aioy\u1E22\u1E27\u1E31\u1E36ron;\u411Br\u0100;c\u1E2D\u1E2E\u6256\u803B\xEA\u40EAlon;\u6255;\u444Dot;\u4117\u0100Dr\u1E41\u1E45ot;\u6252;\uC000\u{1D522}\u0180;rs\u1E50\u1E51\u1E57\u6A9Aave\u803B\xE8\u40E8\u0100;d\u1E5C\u1E5D\u6A96ot;\u6A98\u0200;ils\u1E6A\u1E6B\u1E72\u1E74\u6A99nters;\u63E7;\u6113\u0100;d\u1E79\u1E7A\u6A95ot;\u6A97\u0180aps\u1E85\u1E89\u1E97cr;\u4113ty\u0180;sv\u1E92\u1E93\u1E95\u6205et\xBB\u1E93p\u01001;\u1E9D\u1EA4\u0133\u1EA1\u1EA3;\u6004;\u6005\u6003\u0100gs\u1EAA\u1EAC;\u414Bp;\u6002\u0100gp\u1EB4\u1EB8on;\u4119f;\uC000\u{1D556}\u0180als\u1EC4\u1ECE\u1ED2r\u0100;s\u1ECA\u1ECB\u62D5l;\u69E3us;\u6A71i\u0180;lv\u1EDA\u1EDB\u1EDF\u43B5on\xBB\u1EDB;\u43F5\u0200csuv\u1EEA\u1EF3\u1F0B\u1F23\u0100io\u1EEF\u1E31rc\xBB\u1E2E\u0269\u1EF9\0\0\u1EFB\xED\u0548ant\u0100gl\u1F02\u1F06tr\xBB\u1E5Dess\xBB\u1E7A\u0180aei\u1F12\u1F16\u1F1Als;\u403Dst;\u625Fv\u0100;D\u0235\u1F20D;\u6A78parsl;\u69E5\u0100Da\u1F2F\u1F33ot;\u6253rr;\u6971\u0180cdi\u1F3E\u1F41\u1EF8r;\u612Fo\xF4\u0352\u0100ah\u1F49\u1F4B;\u43B7\u803B\xF0\u40F0\u0100mr\u1F53\u1F57l\u803B\xEB\u40EBo;\u60AC\u0180cip\u1F61\u1F64\u1F67l;\u4021s\xF4\u056E\u0100eo\u1F6C\u1F74ctatio\xEE\u0559nential\xE5\u0579\u09E1\u1F92\0\u1F9E\0\u1FA1\u1FA7\0\0\u1FC6\u1FCC\0\u1FD3\0\u1FE6\u1FEA\u2000\0\u2008\u205Allingdotse\xF1\u1E44y;\u4444male;\u6640\u0180ilr\u1FAD\u1FB3\u1FC1lig;\u8000\uFB03\u0269\u1FB9\0\0\u1FBDg;\u8000\uFB00ig;\u8000\uFB04;\uC000\u{1D523}lig;\u8000\uFB01lig;\uC000fj\u0180alt\u1FD9\u1FDC\u1FE1t;\u666Dig;\u8000\uFB02ns;\u65B1of;\u4192\u01F0\u1FEE\0\u1FF3f;\uC000\u{1D557}\u0100ak\u05BF\u1FF7\u0100;v\u1FFC\u1FFD\u62D4;\u6AD9artint;\u6A0D\u0100ao\u200C\u2055\u0100cs\u2011\u2052\u03B1\u201A\u2030\u2038\u2045\u2048\0\u2050\u03B2\u2022\u2025\u2027\u202A\u202C\0\u202E\u803B\xBD\u40BD;\u6153\u803B\xBC\u40BC;\u6155;\u6159;\u615B\u01B3\u2034\0\u2036;\u6154;\u6156\u02B4\u203E\u2041\0\0\u2043\u803B\xBE\u40BE;\u6157;\u615C5;\u6158\u01B6\u204C\0\u204E;\u615A;\u615D8;\u615El;\u6044wn;\u6322cr;\uC000\u{1D4BB}\u0880Eabcdefgijlnorstv\u2082\u2089\u209F\u20A5\u20B0\u20B4\u20F0\u20F5\u20FA\u20FF\u2103\u2112\u2138\u0317\u213E\u2152\u219E\u0100;l\u064D\u2087;\u6A8C\u0180cmp\u2090\u2095\u209Dute;\u41F5ma\u0100;d\u209C\u1CDA\u43B3;\u6A86reve;\u411F\u0100iy\u20AA\u20AErc;\u411D;\u4433ot;\u4121\u0200;lqs\u063E\u0642\u20BD\u20C9\u0180;qs\u063E\u064C\u20C4lan\xF4\u0665\u0200;cdl\u0665\u20D2\u20D5\u20E5c;\u6AA9ot\u0100;o\u20DC\u20DD\u6A80\u0100;l\u20E2\u20E3\u6A82;\u6A84\u0100;e\u20EA\u20ED\uC000\u22DB\uFE00s;\u6A94r;\uC000\u{1D524}\u0100;g\u0673\u061Bmel;\u6137cy;\u4453\u0200;Eaj\u065A\u210C\u210E\u2110;\u6A92;\u6AA5;\u6AA4\u0200Eaes\u211B\u211D\u2129\u2134;\u6269p\u0100;p\u2123\u2124\u6A8Arox\xBB\u2124\u0100;q\u212E\u212F\u6A88\u0100;q\u212E\u211Bim;\u62E7pf;\uC000\u{1D558}\u0100ci\u2143\u2146r;\u610Am\u0180;el\u066B\u214E\u2150;\u6A8E;\u6A90\u8300>;cdlqr\u05EE\u2160\u216A\u216E\u2173\u2179\u0100ci\u2165\u2167;\u6AA7r;\u6A7Aot;\u62D7Par;\u6995uest;\u6A7C\u0280adels\u2184\u216A\u2190\u0656\u219B\u01F0\u2189\0\u218Epro\xF8\u209Er;\u6978q\u0100lq\u063F\u2196les\xF3\u2088i\xED\u066B\u0100en\u21A3\u21ADrtneqq;\uC000\u2269\uFE00\xC5\u21AA\u0500Aabcefkosy\u21C4\u21C7\u21F1\u21F5\u21FA\u2218\u221D\u222F\u2268\u227Dr\xF2\u03A0\u0200ilmr\u21D0\u21D4\u21D7\u21DBrs\xF0\u1484f\xBB\u2024il\xF4\u06A9\u0100dr\u21E0\u21E4cy;\u444A\u0180;cw\u08F4\u21EB\u21EFir;\u6948;\u61ADar;\u610Firc;\u4125\u0180alr\u2201\u220E\u2213rts\u0100;u\u2209\u220A\u6665it\xBB\u220Alip;\u6026con;\u62B9r;\uC000\u{1D525}s\u0100ew\u2223\u2229arow;\u6925arow;\u6926\u0280amopr\u223A\u223E\u2243\u225E\u2263rr;\u61FFtht;\u623Bk\u0100lr\u2249\u2253eftarrow;\u61A9ightarrow;\u61AAf;\uC000\u{1D559}bar;\u6015\u0180clt\u226F\u2274\u2278r;\uC000\u{1D4BD}as\xE8\u21F4rok;\u4127\u0100bp\u2282\u2287ull;\u6043hen\xBB\u1C5B\u0AE1\u22A3\0\u22AA\0\u22B8\u22C5\u22CE\0\u22D5\u22F3\0\0\u22F8\u2322\u2367\u2362\u237F\0\u2386\u23AA\u23B4cute\u803B\xED\u40ED\u0180;iy\u0771\u22B0\u22B5rc\u803B\xEE\u40EE;\u4438\u0100cx\u22BC\u22BFy;\u4435cl\u803B\xA1\u40A1\u0100fr\u039F\u22C9;\uC000\u{1D526}rave\u803B\xEC\u40EC\u0200;ino\u073E\u22DD\u22E9\u22EE\u0100in\u22E2\u22E6nt;\u6A0Ct;\u622Dfin;\u69DCta;\u6129lig;\u4133\u0180aop\u22FE\u231A\u231D\u0180cgt\u2305\u2308\u2317r;\u412B\u0180elp\u071F\u230F\u2313in\xE5\u078Ear\xF4\u0720h;\u4131f;\u62B7ed;\u41B5\u0280;cfot\u04F4\u232C\u2331\u233D\u2341are;\u6105in\u0100;t\u2338\u2339\u621Eie;\u69DDdo\xF4\u2319\u0280;celp\u0757\u234C\u2350\u235B\u2361al;\u62BA\u0100gr\u2355\u2359er\xF3\u1563\xE3\u234Darhk;\u6A17rod;\u6A3C\u0200cgpt\u236F\u2372\u2376\u237By;\u4451on;\u412Ff;\uC000\u{1D55A}a;\u43B9uest\u803B\xBF\u40BF\u0100ci\u238A\u238Fr;\uC000\u{1D4BE}n\u0280;Edsv\u04F4\u239B\u239D\u23A1\u04F3;\u62F9ot;\u62F5\u0100;v\u23A6\u23A7\u62F4;\u62F3\u0100;i\u0777\u23AElde;\u4129\u01EB\u23B8\0\u23BCcy;\u4456l\u803B\xEF\u40EF\u0300cfmosu\u23CC\u23D7\u23DC\u23E1\u23E7\u23F5\u0100iy\u23D1\u23D5rc;\u4135;\u4439r;\uC000\u{1D527}ath;\u4237pf;\uC000\u{1D55B}\u01E3\u23EC\0\u23F1r;\uC000\u{1D4BF}rcy;\u4458kcy;\u4454\u0400acfghjos\u240B\u2416\u2422\u2427\u242D\u2431\u2435\u243Bppa\u0100;v\u2413\u2414\u43BA;\u43F0\u0100ey\u241B\u2420dil;\u4137;\u443Ar;\uC000\u{1D528}reen;\u4138cy;\u4445cy;\u445Cpf;\uC000\u{1D55C}cr;\uC000\u{1D4C0}\u0B80ABEHabcdefghjlmnoprstuv\u2470\u2481\u2486\u248D\u2491\u250E\u253D\u255A\u2580\u264E\u265E\u2665\u2679\u267D\u269A\u26B2\u26D8\u275D\u2768\u278B\u27C0\u2801\u2812\u0180art\u2477\u247A\u247Cr\xF2\u09C6\xF2\u0395ail;\u691Barr;\u690E\u0100;g\u0994\u248B;\u6A8Bar;\u6962\u0963\u24A5\0\u24AA\0\u24B1\0\0\0\0\0\u24B5\u24BA\0\u24C6\u24C8\u24CD\0\u24F9ute;\u413Amptyv;\u69B4ra\xEE\u084Cbda;\u43BBg\u0180;dl\u088E\u24C1\u24C3;\u6991\xE5\u088E;\u6A85uo\u803B\xAB\u40ABr\u0400;bfhlpst\u0899\u24DE\u24E6\u24E9\u24EB\u24EE\u24F1\u24F5\u0100;f\u089D\u24E3s;\u691Fs;\u691D\xEB\u2252p;\u61ABl;\u6939im;\u6973l;\u61A2\u0180;ae\u24FF\u2500\u2504\u6AABil;\u6919\u0100;s\u2509\u250A\u6AAD;\uC000\u2AAD\uFE00\u0180abr\u2515\u2519\u251Drr;\u690Crk;\u6772\u0100ak\u2522\u252Cc\u0100ek\u2528\u252A;\u407B;\u405B\u0100es\u2531\u2533;\u698Bl\u0100du\u2539\u253B;\u698F;\u698D\u0200aeuy\u2546\u254B\u2556\u2558ron;\u413E\u0100di\u2550\u2554il;\u413C\xEC\u08B0\xE2\u2529;\u443B\u0200cqrs\u2563\u2566\u256D\u257Da;\u6936uo\u0100;r\u0E19\u1746\u0100du\u2572\u2577har;\u6967shar;\u694Bh;\u61B2\u0280;fgqs\u258B\u258C\u0989\u25F3\u25FF\u6264t\u0280ahlrt\u2598\u25A4\u25B7\u25C2\u25E8rrow\u0100;t\u0899\u25A1a\xE9\u24F6arpoon\u0100du\u25AF\u25B4own\xBB\u045Ap\xBB\u0966eftarrows;\u61C7ight\u0180ahs\u25CD\u25D6\u25DErrow\u0100;s\u08F4\u08A7arpoon\xF3\u0F98quigarro\xF7\u21F0hreetimes;\u62CB\u0180;qs\u258B\u0993\u25FAlan\xF4\u09AC\u0280;cdgs\u09AC\u260A\u260D\u261D\u2628c;\u6AA8ot\u0100;o\u2614\u2615\u6A7F\u0100;r\u261A\u261B\u6A81;\u6A83\u0100;e\u2622\u2625\uC000\u22DA\uFE00s;\u6A93\u0280adegs\u2633\u2639\u263D\u2649\u264Bppro\xF8\u24C6ot;\u62D6q\u0100gq\u2643\u2645\xF4\u0989gt\xF2\u248C\xF4\u099Bi\xED\u09B2\u0180ilr\u2655\u08E1\u265Asht;\u697C;\uC000\u{1D529}\u0100;E\u099C\u2663;\u6A91\u0161\u2669\u2676r\u0100du\u25B2\u266E\u0100;l\u0965\u2673;\u696Alk;\u6584cy;\u4459\u0280;acht\u0A48\u2688\u268B\u2691\u2696r\xF2\u25C1orne\xF2\u1D08ard;\u696Bri;\u65FA\u0100io\u269F\u26A4dot;\u4140ust\u0100;a\u26AC\u26AD\u63B0che\xBB\u26AD\u0200Eaes\u26BB\u26BD\u26C9\u26D4;\u6268p\u0100;p\u26C3\u26C4\u6A89rox\xBB\u26C4\u0100;q\u26CE\u26CF\u6A87\u0100;q\u26CE\u26BBim;\u62E6\u0400abnoptwz\u26E9\u26F4\u26F7\u271A\u272F\u2741\u2747\u2750\u0100nr\u26EE\u26F1g;\u67ECr;\u61FDr\xEB\u08C1g\u0180lmr\u26FF\u270D\u2714eft\u0100ar\u09E6\u2707ight\xE1\u09F2apsto;\u67FCight\xE1\u09FDparrow\u0100lr\u2725\u2729ef\xF4\u24EDight;\u61AC\u0180afl\u2736\u2739\u273Dr;\u6985;\uC000\u{1D55D}us;\u6A2Dimes;\u6A34\u0161\u274B\u274Fst;\u6217\xE1\u134E\u0180;ef\u2757\u2758\u1800\u65CAnge\xBB\u2758ar\u0100;l\u2764\u2765\u4028t;\u6993\u0280achmt\u2773\u2776\u277C\u2785\u2787r\xF2\u08A8orne\xF2\u1D8Car\u0100;d\u0F98\u2783;\u696D;\u600Eri;\u62BF\u0300achiqt\u2798\u279D\u0A40\u27A2\u27AE\u27BBquo;\u6039r;\uC000\u{1D4C1}m\u0180;eg\u09B2\u27AA\u27AC;\u6A8D;\u6A8F\u0100bu\u252A\u27B3o\u0100;r\u0E1F\u27B9;\u601Arok;\u4142\u8400<;cdhilqr\u082B\u27D2\u2639\u27DC\u27E0\u27E5\u27EA\u27F0\u0100ci\u27D7\u27D9;\u6AA6r;\u6A79re\xE5\u25F2mes;\u62C9arr;\u6976uest;\u6A7B\u0100Pi\u27F5\u27F9ar;\u6996\u0180;ef\u2800\u092D\u181B\u65C3r\u0100du\u2807\u280Dshar;\u694Ahar;\u6966\u0100en\u2817\u2821rtneqq;\uC000\u2268\uFE00\xC5\u281E\u0700Dacdefhilnopsu\u2840\u2845\u2882\u288E\u2893\u28A0\u28A5\u28A8\u28DA\u28E2\u28E4\u0A83\u28F3\u2902Dot;\u623A\u0200clpr\u284E\u2852\u2863\u287Dr\u803B\xAF\u40AF\u0100et\u2857\u2859;\u6642\u0100;e\u285E\u285F\u6720se\xBB\u285F\u0100;s\u103B\u2868to\u0200;dlu\u103B\u2873\u2877\u287Bow\xEE\u048Cef\xF4\u090F\xF0\u13D1ker;\u65AE\u0100oy\u2887\u288Cmma;\u6A29;\u443Cash;\u6014asuredangle\xBB\u1626r;\uC000\u{1D52A}o;\u6127\u0180cdn\u28AF\u28B4\u28C9ro\u803B\xB5\u40B5\u0200;acd\u1464\u28BD\u28C0\u28C4s\xF4\u16A7ir;\u6AF0ot\u80BB\xB7\u01B5us\u0180;bd\u28D2\u1903\u28D3\u6212\u0100;u\u1D3C\u28D8;\u6A2A\u0163\u28DE\u28E1p;\u6ADB\xF2\u2212\xF0\u0A81\u0100dp\u28E9\u28EEels;\u62A7f;\uC000\u{1D55E}\u0100ct\u28F8\u28FDr;\uC000\u{1D4C2}pos\xBB\u159D\u0180;lm\u2909\u290A\u290D\u43BCtimap;\u62B8\u0C00GLRVabcdefghijlmoprstuvw\u2942\u2953\u297E\u2989\u2998\u29DA\u29E9\u2A15\u2A1A\u2A58\u2A5D\u2A83\u2A95\u2AA4\u2AA8\u2B04\u2B07\u2B44\u2B7F\u2BAE\u2C34\u2C67\u2C7C\u2CE9\u0100gt\u2947\u294B;\uC000\u22D9\u0338\u0100;v\u2950\u0BCF\uC000\u226B\u20D2\u0180elt\u295A\u2972\u2976ft\u0100ar\u2961\u2967rrow;\u61CDightarrow;\u61CE;\uC000\u22D8\u0338\u0100;v\u297B\u0C47\uC000\u226A\u20D2ightarrow;\u61CF\u0100Dd\u298E\u2993ash;\u62AFash;\u62AE\u0280bcnpt\u29A3\u29A7\u29AC\u29B1\u29CCla\xBB\u02DEute;\u4144g;\uC000\u2220\u20D2\u0280;Eiop\u0D84\u29BC\u29C0\u29C5\u29C8;\uC000\u2A70\u0338d;\uC000\u224B\u0338s;\u4149ro\xF8\u0D84ur\u0100;a\u29D3\u29D4\u666El\u0100;s\u29D3\u0B38\u01F3\u29DF\0\u29E3p\u80BB\xA0\u0B37mp\u0100;e\u0BF9\u0C00\u0280aeouy\u29F4\u29FE\u2A03\u2A10\u2A13\u01F0\u29F9\0\u29FB;\u6A43on;\u4148dil;\u4146ng\u0100;d\u0D7E\u2A0Aot;\uC000\u2A6D\u0338p;\u6A42;\u443Dash;\u6013\u0380;Aadqsx\u0B92\u2A29\u2A2D\u2A3B\u2A41\u2A45\u2A50rr;\u61D7r\u0100hr\u2A33\u2A36k;\u6924\u0100;o\u13F2\u13F0ot;\uC000\u2250\u0338ui\xF6\u0B63\u0100ei\u2A4A\u2A4Ear;\u6928\xED\u0B98ist\u0100;s\u0BA0\u0B9Fr;\uC000\u{1D52B}\u0200Eest\u0BC5\u2A66\u2A79\u2A7C\u0180;qs\u0BBC\u2A6D\u0BE1\u0180;qs\u0BBC\u0BC5\u2A74lan\xF4\u0BE2i\xED\u0BEA\u0100;r\u0BB6\u2A81\xBB\u0BB7\u0180Aap\u2A8A\u2A8D\u2A91r\xF2\u2971rr;\u61AEar;\u6AF2\u0180;sv\u0F8D\u2A9C\u0F8C\u0100;d\u2AA1\u2AA2\u62FC;\u62FAcy;\u445A\u0380AEadest\u2AB7\u2ABA\u2ABE\u2AC2\u2AC5\u2AF6\u2AF9r\xF2\u2966;\uC000\u2266\u0338rr;\u619Ar;\u6025\u0200;fqs\u0C3B\u2ACE\u2AE3\u2AEFt\u0100ar\u2AD4\u2AD9rro\xF7\u2AC1ightarro\xF7\u2A90\u0180;qs\u0C3B\u2ABA\u2AEAlan\xF4\u0C55\u0100;s\u0C55\u2AF4\xBB\u0C36i\xED\u0C5D\u0100;r\u0C35\u2AFEi\u0100;e\u0C1A\u0C25i\xE4\u0D90\u0100pt\u2B0C\u2B11f;\uC000\u{1D55F}\u8180\xAC;in\u2B19\u2B1A\u2B36\u40ACn\u0200;Edv\u0B89\u2B24\u2B28\u2B2E;\uC000\u22F9\u0338ot;\uC000\u22F5\u0338\u01E1\u0B89\u2B33\u2B35;\u62F7;\u62F6i\u0100;v\u0CB8\u2B3C\u01E1\u0CB8\u2B41\u2B43;\u62FE;\u62FD\u0180aor\u2B4B\u2B63\u2B69r\u0200;ast\u0B7B\u2B55\u2B5A\u2B5Flle\xEC\u0B7Bl;\uC000\u2AFD\u20E5;\uC000\u2202\u0338lint;\u6A14\u0180;ce\u0C92\u2B70\u2B73u\xE5\u0CA5\u0100;c\u0C98\u2B78\u0100;e\u0C92\u2B7D\xF1\u0C98\u0200Aait\u2B88\u2B8B\u2B9D\u2BA7r\xF2\u2988rr\u0180;cw\u2B94\u2B95\u2B99\u619B;\uC000\u2933\u0338;\uC000\u219D\u0338ghtarrow\xBB\u2B95ri\u0100;e\u0CCB\u0CD6\u0380chimpqu\u2BBD\u2BCD\u2BD9\u2B04\u0B78\u2BE4\u2BEF\u0200;cer\u0D32\u2BC6\u0D37\u2BC9u\xE5\u0D45;\uC000\u{1D4C3}ort\u026D\u2B05\0\0\u2BD6ar\xE1\u2B56m\u0100;e\u0D6E\u2BDF\u0100;q\u0D74\u0D73su\u0100bp\u2BEB\u2BED\xE5\u0CF8\xE5\u0D0B\u0180bcp\u2BF6\u2C11\u2C19\u0200;Ees\u2BFF\u2C00\u0D22\u2C04\u6284;\uC000\u2AC5\u0338et\u0100;e\u0D1B\u2C0Bq\u0100;q\u0D23\u2C00c\u0100;e\u0D32\u2C17\xF1\u0D38\u0200;Ees\u2C22\u2C23\u0D5F\u2C27\u6285;\uC000\u2AC6\u0338et\u0100;e\u0D58\u2C2Eq\u0100;q\u0D60\u2C23\u0200gilr\u2C3D\u2C3F\u2C45\u2C47\xEC\u0BD7lde\u803B\xF1\u40F1\xE7\u0C43iangle\u0100lr\u2C52\u2C5Ceft\u0100;e\u0C1A\u2C5A\xF1\u0C26ight\u0100;e\u0CCB\u2C65\xF1\u0CD7\u0100;m\u2C6C\u2C6D\u43BD\u0180;es\u2C74\u2C75\u2C79\u4023ro;\u6116p;\u6007\u0480DHadgilrs\u2C8F\u2C94\u2C99\u2C9E\u2CA3\u2CB0\u2CB6\u2CD3\u2CE3ash;\u62ADarr;\u6904p;\uC000\u224D\u20D2ash;\u62AC\u0100et\u2CA8\u2CAC;\uC000\u2265\u20D2;\uC000>\u20D2nfin;\u69DE\u0180Aet\u2CBD\u2CC1\u2CC5rr;\u6902;\uC000\u2264\u20D2\u0100;r\u2CCA\u2CCD\uC000<\u20D2ie;\uC000\u22B4\u20D2\u0100At\u2CD8\u2CDCrr;\u6903rie;\uC000\u22B5\u20D2im;\uC000\u223C\u20D2\u0180Aan\u2CF0\u2CF4\u2D02rr;\u61D6r\u0100hr\u2CFA\u2CFDk;\u6923\u0100;o\u13E7\u13E5ear;\u6927\u1253\u1A95\0\0\0\0\0\0\0\0\0\0\0\0\0\u2D2D\0\u2D38\u2D48\u2D60\u2D65\u2D72\u2D84\u1B07\0\0\u2D8D\u2DAB\0\u2DC8\u2DCE\0\u2DDC\u2E19\u2E2B\u2E3E\u2E43\u0100cs\u2D31\u1A97ute\u803B\xF3\u40F3\u0100iy\u2D3C\u2D45r\u0100;c\u1A9E\u2D42\u803B\xF4\u40F4;\u443E\u0280abios\u1AA0\u2D52\u2D57\u01C8\u2D5Alac;\u4151v;\u6A38old;\u69BClig;\u4153\u0100cr\u2D69\u2D6Dir;\u69BF;\uC000\u{1D52C}\u036F\u2D79\0\0\u2D7C\0\u2D82n;\u42DBave\u803B\xF2\u40F2;\u69C1\u0100bm\u2D88\u0DF4ar;\u69B5\u0200acit\u2D95\u2D98\u2DA5\u2DA8r\xF2\u1A80\u0100ir\u2D9D\u2DA0r;\u69BEoss;\u69BBn\xE5\u0E52;\u69C0\u0180aei\u2DB1\u2DB5\u2DB9cr;\u414Dga;\u43C9\u0180cdn\u2DC0\u2DC5\u01CDron;\u43BF;\u69B6pf;\uC000\u{1D560}\u0180ael\u2DD4\u2DD7\u01D2r;\u69B7rp;\u69B9\u0380;adiosv\u2DEA\u2DEB\u2DEE\u2E08\u2E0D\u2E10\u2E16\u6228r\xF2\u1A86\u0200;efm\u2DF7\u2DF8\u2E02\u2E05\u6A5Dr\u0100;o\u2DFE\u2DFF\u6134f\xBB\u2DFF\u803B\xAA\u40AA\u803B\xBA\u40BAgof;\u62B6r;\u6A56lope;\u6A57;\u6A5B\u0180clo\u2E1F\u2E21\u2E27\xF2\u2E01ash\u803B\xF8\u40F8l;\u6298i\u016C\u2E2F\u2E34de\u803B\xF5\u40F5es\u0100;a\u01DB\u2E3As;\u6A36ml\u803B\xF6\u40F6bar;\u633D\u0AE1\u2E5E\0\u2E7D\0\u2E80\u2E9D\0\u2EA2\u2EB9\0\0\u2ECB\u0E9C\0\u2F13\0\0\u2F2B\u2FBC\0\u2FC8r\u0200;ast\u0403\u2E67\u2E72\u0E85\u8100\xB6;l\u2E6D\u2E6E\u40B6le\xEC\u0403\u0269\u2E78\0\0\u2E7Bm;\u6AF3;\u6AFDy;\u443Fr\u0280cimpt\u2E8B\u2E8F\u2E93\u1865\u2E97nt;\u4025od;\u402Eil;\u6030enk;\u6031r;\uC000\u{1D52D}\u0180imo\u2EA8\u2EB0\u2EB4\u0100;v\u2EAD\u2EAE\u43C6;\u43D5ma\xF4\u0A76ne;\u660E\u0180;tv\u2EBF\u2EC0\u2EC8\u43C0chfork\xBB\u1FFD;\u43D6\u0100au\u2ECF\u2EDFn\u0100ck\u2ED5\u2EDDk\u0100;h\u21F4\u2EDB;\u610E\xF6\u21F4s\u0480;abcdemst\u2EF3\u2EF4\u1908\u2EF9\u2EFD\u2F04\u2F06\u2F0A\u2F0E\u402Bcir;\u6A23ir;\u6A22\u0100ou\u1D40\u2F02;\u6A25;\u6A72n\u80BB\xB1\u0E9Dim;\u6A26wo;\u6A27\u0180ipu\u2F19\u2F20\u2F25ntint;\u6A15f;\uC000\u{1D561}nd\u803B\xA3\u40A3\u0500;Eaceinosu\u0EC8\u2F3F\u2F41\u2F44\u2F47\u2F81\u2F89\u2F92\u2F7E\u2FB6;\u6AB3p;\u6AB7u\xE5\u0ED9\u0100;c\u0ECE\u2F4C\u0300;acens\u0EC8\u2F59\u2F5F\u2F66\u2F68\u2F7Eppro\xF8\u2F43urlye\xF1\u0ED9\xF1\u0ECE\u0180aes\u2F6F\u2F76\u2F7Approx;\u6AB9qq;\u6AB5im;\u62E8i\xED\u0EDFme\u0100;s\u2F88\u0EAE\u6032\u0180Eas\u2F78\u2F90\u2F7A\xF0\u2F75\u0180dfp\u0EEC\u2F99\u2FAF\u0180als\u2FA0\u2FA5\u2FAAlar;\u632Eine;\u6312urf;\u6313\u0100;t\u0EFB\u2FB4\xEF\u0EFBrel;\u62B0\u0100ci\u2FC0\u2FC5r;\uC000\u{1D4C5};\u43C8ncsp;\u6008\u0300fiopsu\u2FDA\u22E2\u2FDF\u2FE5\u2FEB\u2FF1r;\uC000\u{1D52E}pf;\uC000\u{1D562}rime;\u6057cr;\uC000\u{1D4C6}\u0180aeo\u2FF8\u3009\u3013t\u0100ei\u2FFE\u3005rnion\xF3\u06B0nt;\u6A16st\u0100;e\u3010\u3011\u403F\xF1\u1F19\xF4\u0F14\u0A80ABHabcdefhilmnoprstux\u3040\u3051\u3055\u3059\u30E0\u310E\u312B\u3147\u3162\u3172\u318E\u3206\u3215\u3224\u3229\u3258\u326E\u3272\u3290\u32B0\u32B7\u0180art\u3047\u304A\u304Cr\xF2\u10B3\xF2\u03DDail;\u691Car\xF2\u1C65ar;\u6964\u0380cdenqrt\u3068\u3075\u3078\u307F\u308F\u3094\u30CC\u0100eu\u306D\u3071;\uC000\u223D\u0331te;\u4155i\xE3\u116Emptyv;\u69B3g\u0200;del\u0FD1\u3089\u308B\u308D;\u6992;\u69A5\xE5\u0FD1uo\u803B\xBB\u40BBr\u0580;abcfhlpstw\u0FDC\u30AC\u30AF\u30B7\u30B9\u30BC\u30BE\u30C0\u30C3\u30C7\u30CAp;\u6975\u0100;f\u0FE0\u30B4s;\u6920;\u6933s;\u691E\xEB\u225D\xF0\u272El;\u6945im;\u6974l;\u61A3;\u619D\u0100ai\u30D1\u30D5il;\u691Ao\u0100;n\u30DB\u30DC\u6236al\xF3\u0F1E\u0180abr\u30E7\u30EA\u30EEr\xF2\u17E5rk;\u6773\u0100ak\u30F3\u30FDc\u0100ek\u30F9\u30FB;\u407D;\u405D\u0100es\u3102\u3104;\u698Cl\u0100du\u310A\u310C;\u698E;\u6990\u0200aeuy\u3117\u311C\u3127\u3129ron;\u4159\u0100di\u3121\u3125il;\u4157\xEC\u0FF2\xE2\u30FA;\u4440\u0200clqs\u3134\u3137\u313D\u3144a;\u6937dhar;\u6969uo\u0100;r\u020E\u020Dh;\u61B3\u0180acg\u314E\u315F\u0F44l\u0200;ips\u0F78\u3158\u315B\u109Cn\xE5\u10BBar\xF4\u0FA9t;\u65AD\u0180ilr\u3169\u1023\u316Esht;\u697D;\uC000\u{1D52F}\u0100ao\u3177\u3186r\u0100du\u317D\u317F\xBB\u047B\u0100;l\u1091\u3184;\u696C\u0100;v\u318B\u318C\u43C1;\u43F1\u0180gns\u3195\u31F9\u31FCht\u0300ahlrst\u31A4\u31B0\u31C2\u31D8\u31E4\u31EErrow\u0100;t\u0FDC\u31ADa\xE9\u30C8arpoon\u0100du\u31BB\u31BFow\xEE\u317Ep\xBB\u1092eft\u0100ah\u31CA\u31D0rrow\xF3\u0FEAarpoon\xF3\u0551ightarrows;\u61C9quigarro\xF7\u30CBhreetimes;\u62CCg;\u42DAingdotse\xF1\u1F32\u0180ahm\u320D\u3210\u3213r\xF2\u0FEAa\xF2\u0551;\u600Foust\u0100;a\u321E\u321F\u63B1che\xBB\u321Fmid;\u6AEE\u0200abpt\u3232\u323D\u3240\u3252\u0100nr\u3237\u323Ag;\u67EDr;\u61FEr\xEB\u1003\u0180afl\u3247\u324A\u324Er;\u6986;\uC000\u{1D563}us;\u6A2Eimes;\u6A35\u0100ap\u325D\u3267r\u0100;g\u3263\u3264\u4029t;\u6994olint;\u6A12ar\xF2\u31E3\u0200achq\u327B\u3280\u10BC\u3285quo;\u603Ar;\uC000\u{1D4C7}\u0100bu\u30FB\u328Ao\u0100;r\u0214\u0213\u0180hir\u3297\u329B\u32A0re\xE5\u31F8mes;\u62CAi\u0200;efl\u32AA\u1059\u1821\u32AB\u65B9tri;\u69CEluhar;\u6968;\u611E\u0D61\u32D5\u32DB\u32DF\u332C\u3338\u3371\0\u337A\u33A4\0\0\u33EC\u33F0\0\u3428\u3448\u345A\u34AD\u34B1\u34CA\u34F1\0\u3616\0\0\u3633cute;\u415Bqu\xEF\u27BA\u0500;Eaceinpsy\u11ED\u32F3\u32F5\u32FF\u3302\u330B\u330F\u331F\u3326\u3329;\u6AB4\u01F0\u32FA\0\u32FC;\u6AB8on;\u4161u\xE5\u11FE\u0100;d\u11F3\u3307il;\u415Frc;\u415D\u0180Eas\u3316\u3318\u331B;\u6AB6p;\u6ABAim;\u62E9olint;\u6A13i\xED\u1204;\u4441ot\u0180;be\u3334\u1D47\u3335\u62C5;\u6A66\u0380Aacmstx\u3346\u334A\u3357\u335B\u335E\u3363\u336Drr;\u61D8r\u0100hr\u3350\u3352\xEB\u2228\u0100;o\u0A36\u0A34t\u803B\xA7\u40A7i;\u403Bwar;\u6929m\u0100in\u3369\xF0nu\xF3\xF1t;\u6736r\u0100;o\u3376\u2055\uC000\u{1D530}\u0200acoy\u3382\u3386\u3391\u33A0rp;\u666F\u0100hy\u338B\u338Fcy;\u4449;\u4448rt\u026D\u3399\0\0\u339Ci\xE4\u1464ara\xEC\u2E6F\u803B\xAD\u40AD\u0100gm\u33A8\u33B4ma\u0180;fv\u33B1\u33B2\u33B2\u43C3;\u43C2\u0400;deglnpr\u12AB\u33C5\u33C9\u33CE\u33D6\u33DE\u33E1\u33E6ot;\u6A6A\u0100;q\u12B1\u12B0\u0100;E\u33D3\u33D4\u6A9E;\u6AA0\u0100;E\u33DB\u33DC\u6A9D;\u6A9Fe;\u6246lus;\u6A24arr;\u6972ar\xF2\u113D\u0200aeit\u33F8\u3408\u340F\u3417\u0100ls\u33FD\u3404lsetm\xE9\u336Ahp;\u6A33parsl;\u69E4\u0100dl\u1463\u3414e;\u6323\u0100;e\u341C\u341D\u6AAA\u0100;s\u3422\u3423\u6AAC;\uC000\u2AAC\uFE00\u0180flp\u342E\u3433\u3442tcy;\u444C\u0100;b\u3438\u3439\u402F\u0100;a\u343E\u343F\u69C4r;\u633Ff;\uC000\u{1D564}a\u0100dr\u344D\u0402es\u0100;u\u3454\u3455\u6660it\xBB\u3455\u0180csu\u3460\u3479\u349F\u0100au\u3465\u346Fp\u0100;s\u1188\u346B;\uC000\u2293\uFE00p\u0100;s\u11B4\u3475;\uC000\u2294\uFE00u\u0100bp\u347F\u348F\u0180;es\u1197\u119C\u3486et\u0100;e\u1197\u348D\xF1\u119D\u0180;es\u11A8\u11AD\u3496et\u0100;e\u11A8\u349D\xF1\u11AE\u0180;af\u117B\u34A6\u05B0r\u0165\u34AB\u05B1\xBB\u117Car\xF2\u1148\u0200cemt\u34B9\u34BE\u34C2\u34C5r;\uC000\u{1D4C8}tm\xEE\xF1i\xEC\u3415ar\xE6\u11BE\u0100ar\u34CE\u34D5r\u0100;f\u34D4\u17BF\u6606\u0100an\u34DA\u34EDight\u0100ep\u34E3\u34EApsilo\xEE\u1EE0h\xE9\u2EAFs\xBB\u2852\u0280bcmnp\u34FB\u355E\u1209\u358B\u358E\u0480;Edemnprs\u350E\u350F\u3511\u3515\u351E\u3523\u352C\u3531\u3536\u6282;\u6AC5ot;\u6ABD\u0100;d\u11DA\u351Aot;\u6AC3ult;\u6AC1\u0100Ee\u3528\u352A;\u6ACB;\u628Alus;\u6ABFarr;\u6979\u0180eiu\u353D\u3552\u3555t\u0180;en\u350E\u3545\u354Bq\u0100;q\u11DA\u350Feq\u0100;q\u352B\u3528m;\u6AC7\u0100bp\u355A\u355C;\u6AD5;\u6AD3c\u0300;acens\u11ED\u356C\u3572\u3579\u357B\u3326ppro\xF8\u32FAurlye\xF1\u11FE\xF1\u11F3\u0180aes\u3582\u3588\u331Bppro\xF8\u331Aq\xF1\u3317g;\u666A\u0680123;Edehlmnps\u35A9\u35AC\u35AF\u121C\u35B2\u35B4\u35C0\u35C9\u35D5\u35DA\u35DF\u35E8\u35ED\u803B\xB9\u40B9\u803B\xB2\u40B2\u803B\xB3\u40B3;\u6AC6\u0100os\u35B9\u35BCt;\u6ABEub;\u6AD8\u0100;d\u1222\u35C5ot;\u6AC4s\u0100ou\u35CF\u35D2l;\u67C9b;\u6AD7arr;\u697Bult;\u6AC2\u0100Ee\u35E4\u35E6;\u6ACC;\u628Blus;\u6AC0\u0180eiu\u35F4\u3609\u360Ct\u0180;en\u121C\u35FC\u3602q\u0100;q\u1222\u35B2eq\u0100;q\u35E7\u35E4m;\u6AC8\u0100bp\u3611\u3613;\u6AD4;\u6AD6\u0180Aan\u361C\u3620\u362Drr;\u61D9r\u0100hr\u3626\u3628\xEB\u222E\u0100;o\u0A2B\u0A29war;\u692Alig\u803B\xDF\u40DF\u0BE1\u3651\u365D\u3660\u12CE\u3673\u3679\0\u367E\u36C2\0\0\0\0\0\u36DB\u3703\0\u3709\u376C\0\0\0\u3787\u0272\u3656\0\0\u365Bget;\u6316;\u43C4r\xEB\u0E5F\u0180aey\u3666\u366B\u3670ron;\u4165dil;\u4163;\u4442lrec;\u6315r;\uC000\u{1D531}\u0200eiko\u3686\u369D\u36B5\u36BC\u01F2\u368B\0\u3691e\u01004f\u1284\u1281a\u0180;sv\u3698\u3699\u369B\u43B8ym;\u43D1\u0100cn\u36A2\u36B2k\u0100as\u36A8\u36AEppro\xF8\u12C1im\xBB\u12ACs\xF0\u129E\u0100as\u36BA\u36AE\xF0\u12C1rn\u803B\xFE\u40FE\u01EC\u031F\u36C6\u22E7es\u8180\xD7;bd\u36CF\u36D0\u36D8\u40D7\u0100;a\u190F\u36D5r;\u6A31;\u6A30\u0180eps\u36E1\u36E3\u3700\xE1\u2A4D\u0200;bcf\u0486\u36EC\u36F0\u36F4ot;\u6336ir;\u6AF1\u0100;o\u36F9\u36FC\uC000\u{1D565}rk;\u6ADA\xE1\u3362rime;\u6034\u0180aip\u370F\u3712\u3764d\xE5\u1248\u0380adempst\u3721\u374D\u3740\u3751\u3757\u375C\u375Fngle\u0280;dlqr\u3730\u3731\u3736\u3740\u3742\u65B5own\xBB\u1DBBeft\u0100;e\u2800\u373E\xF1\u092E;\u625Cight\u0100;e\u32AA\u374B\xF1\u105Aot;\u65ECinus;\u6A3Alus;\u6A39b;\u69CDime;\u6A3Bezium;\u63E2\u0180cht\u3772\u377D\u3781\u0100ry\u3777\u377B;\uC000\u{1D4C9};\u4446cy;\u445Brok;\u4167\u0100io\u378B\u378Ex\xF4\u1777head\u0100lr\u3797\u37A0eftarro\xF7\u084Fightarrow\xBB\u0F5D\u0900AHabcdfghlmoprstuw\u37D0\u37D3\u37D7\u37E4\u37F0\u37FC\u380E\u381C\u3823\u3834\u3851\u385D\u386B\u38A9\u38CC\u38D2\u38EA\u38F6r\xF2\u03EDar;\u6963\u0100cr\u37DC\u37E2ute\u803B\xFA\u40FA\xF2\u1150r\u01E3\u37EA\0\u37EDy;\u445Eve;\u416D\u0100iy\u37F5\u37FArc\u803B\xFB\u40FB;\u4443\u0180abh\u3803\u3806\u380Br\xF2\u13ADlac;\u4171a\xF2\u13C3\u0100ir\u3813\u3818sht;\u697E;\uC000\u{1D532}rave\u803B\xF9\u40F9\u0161\u3827\u3831r\u0100lr\u382C\u382E\xBB\u0957\xBB\u1083lk;\u6580\u0100ct\u3839\u384D\u026F\u383F\0\0\u384Arn\u0100;e\u3845\u3846\u631Cr\xBB\u3846op;\u630Fri;\u65F8\u0100al\u3856\u385Acr;\u416B\u80BB\xA8\u0349\u0100gp\u3862\u3866on;\u4173f;\uC000\u{1D566}\u0300adhlsu\u114B\u3878\u387D\u1372\u3891\u38A0own\xE1\u13B3arpoon\u0100lr\u3888\u388Cef\xF4\u382Digh\xF4\u382Fi\u0180;hl\u3899\u389A\u389C\u43C5\xBB\u13FAon\xBB\u389Aparrows;\u61C8\u0180cit\u38B0\u38C4\u38C8\u026F\u38B6\0\0\u38C1rn\u0100;e\u38BC\u38BD\u631Dr\xBB\u38BDop;\u630Eng;\u416Fri;\u65F9cr;\uC000\u{1D4CA}\u0180dir\u38D9\u38DD\u38E2ot;\u62F0lde;\u4169i\u0100;f\u3730\u38E8\xBB\u1813\u0100am\u38EF\u38F2r\xF2\u38A8l\u803B\xFC\u40FCangle;\u69A7\u0780ABDacdeflnoprsz\u391C\u391F\u3929\u392D\u39B5\u39B8\u39BD\u39DF\u39E4\u39E8\u39F3\u39F9\u39FD\u3A01\u3A20r\xF2\u03F7ar\u0100;v\u3926\u3927\u6AE8;\u6AE9as\xE8\u03E1\u0100nr\u3932\u3937grt;\u699C\u0380eknprst\u34E3\u3946\u394B\u3952\u395D\u3964\u3996app\xE1\u2415othin\xE7\u1E96\u0180hir\u34EB\u2EC8\u3959op\xF4\u2FB5\u0100;h\u13B7\u3962\xEF\u318D\u0100iu\u3969\u396Dgm\xE1\u33B3\u0100bp\u3972\u3984setneq\u0100;q\u397D\u3980\uC000\u228A\uFE00;\uC000\u2ACB\uFE00setneq\u0100;q\u398F\u3992\uC000\u228B\uFE00;\uC000\u2ACC\uFE00\u0100hr\u399B\u399Fet\xE1\u369Ciangle\u0100lr\u39AA\u39AFeft\xBB\u0925ight\xBB\u1051y;\u4432ash\xBB\u1036\u0180elr\u39C4\u39D2\u39D7\u0180;be\u2DEA\u39CB\u39CFar;\u62BBq;\u625Alip;\u62EE\u0100bt\u39DC\u1468a\xF2\u1469r;\uC000\u{1D533}tr\xE9\u39AEsu\u0100bp\u39EF\u39F1\xBB\u0D1C\xBB\u0D59pf;\uC000\u{1D567}ro\xF0\u0EFBtr\xE9\u39B4\u0100cu\u3A06\u3A0Br;\uC000\u{1D4CB}\u0100bp\u3A10\u3A18n\u0100Ee\u3980\u3A16\xBB\u397En\u0100Ee\u3992\u3A1E\xBB\u3990igzag;\u699A\u0380cefoprs\u3A36\u3A3B\u3A56\u3A5B\u3A54\u3A61\u3A6Airc;\u4175\u0100di\u3A40\u3A51\u0100bg\u3A45\u3A49ar;\u6A5Fe\u0100;q\u15FA\u3A4F;\u6259erp;\u6118r;\uC000\u{1D534}pf;\uC000\u{1D568}\u0100;e\u1479\u3A66at\xE8\u1479cr;\uC000\u{1D4CC}\u0AE3\u178E\u3A87\0\u3A8B\0\u3A90\u3A9B\0\0\u3A9D\u3AA8\u3AAB\u3AAF\0\0\u3AC3\u3ACE\0\u3AD8\u17DC\u17DFtr\xE9\u17D1r;\uC000\u{1D535}\u0100Aa\u3A94\u3A97r\xF2\u03C3r\xF2\u09F6;\u43BE\u0100Aa\u3AA1\u3AA4r\xF2\u03B8r\xF2\u09EBa\xF0\u2713is;\u62FB\u0180dpt\u17A4\u3AB5\u3ABE\u0100fl\u3ABA\u17A9;\uC000\u{1D569}im\xE5\u17B2\u0100Aa\u3AC7\u3ACAr\xF2\u03CEr\xF2\u0A01\u0100cq\u3AD2\u17B8r;\uC000\u{1D4CD}\u0100pt\u17D6\u3ADCr\xE9\u17D4\u0400acefiosu\u3AF0\u3AFD\u3B08\u3B0C\u3B11\u3B15\u3B1B\u3B21c\u0100uy\u3AF6\u3AFBte\u803B\xFD\u40FD;\u444F\u0100iy\u3B02\u3B06rc;\u4177;\u444Bn\u803B\xA5\u40A5r;\uC000\u{1D536}cy;\u4457pf;\uC000\u{1D56A}cr;\uC000\u{1D4CE}\u0100cm\u3B26\u3B29y;\u444El\u803B\xFF\u40FF\u0500acdefhiosw\u3B42\u3B48\u3B54\u3B58\u3B64\u3B69\u3B6D\u3B74\u3B7A\u3B80cute;\u417A\u0100ay\u3B4D\u3B52ron;\u417E;\u4437ot;\u417C\u0100et\u3B5D\u3B61tr\xE6\u155Fa;\u43B6r;\uC000\u{1D537}cy;\u4436grarr;\u61DDpf;\uC000\u{1D56B}cr;\uC000\u{1D4CF}\u0100jn\u3B85\u3B87;\u600Dj;\u600C'.split("").map((c) => c.charCodeAt(0))
);
// node_modules/entities/lib/esm/generated/decode-data-xml.js
var decode_data_xml_default = new Uint16Array(
// prettier-ignore
"\u0200aglq \x1B\u026D\0\0p;\u4026os;\u4027t;\u403Et;\u403Cuot;\u4022".split("").map((c) => c.charCodeAt(0))
);
// node_modules/entities/lib/esm/decode_codepoint.js
var _a;
var decodeMap = /* @__PURE__ */ new Map([
[0, 65533],
// C1 Unicode control character reference replacements
[128, 8364],
[130, 8218],
[131, 402],
[132, 8222],
[133, 8230],
[134, 8224],
[135, 8225],
[136, 710],
[137, 8240],
[138, 352],
[139, 8249],
[140, 338],
[142, 381],
[145, 8216],
[146, 8217],
[147, 8220],
[148, 8221],
[149, 8226],
[150, 8211],
[151, 8212],
[152, 732],
[153, 8482],
[154, 353],
[155, 8250],
[156, 339],
[158, 382],
[159, 376]
]);
var fromCodePoint = (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, node/no-unsupported-features/es-builtins
(_a = String.fromCodePoint) !== null && _a !== void 0 ? _a : function(codePoint) {
let output = "";
if (codePoint > 65535) {
codePoint -= 65536;
output += String.fromCharCode(codePoint >>> 10 & 1023 | 55296);
codePoint = 56320 | codePoint & 1023;
}
output += String.fromCharCode(codePoint);
return output;
}
);
function replaceCodePoint(codePoint) {
var _a2;
if (codePoint >= 55296 && codePoint <= 57343 || codePoint > 1114111) {
return 65533;
}
return (_a2 = decodeMap.get(codePoint)) !== null && _a2 !== void 0 ? _a2 : codePoint;
}
// node_modules/entities/lib/esm/decode.js
var CharCodes;
(function(CharCodes2) {
CharCodes2[CharCodes2["NUM"] = 35] = "NUM";
CharCodes2[CharCodes2["SEMI"] = 59] = "SEMI";
CharCodes2[CharCodes2["EQUALS"] = 61] = "EQUALS";
CharCodes2[CharCodes2["ZERO"] = 48] = "ZERO";
CharCodes2[CharCodes2["NINE"] = 57] = "NINE";
CharCodes2[CharCodes2["LOWER_A"] = 97] = "LOWER_A";
CharCodes2[CharCodes2["LOWER_F"] = 102] = "LOWER_F";
CharCodes2[CharCodes2["LOWER_X"] = 120] = "LOWER_X";
CharCodes2[CharCodes2["LOWER_Z"] = 122] = "LOWER_Z";
CharCodes2[CharCodes2["UPPER_A"] = 65] = "UPPER_A";
CharCodes2[CharCodes2["UPPER_F"] = 70] = "UPPER_F";
CharCodes2[CharCodes2["UPPER_Z"] = 90] = "UPPER_Z";
})(CharCodes || (CharCodes = {}));
var TO_LOWER_BIT = 32;
var BinTrieFlags;
(function(BinTrieFlags2) {
BinTrieFlags2[BinTrieFlags2["VALUE_LENGTH"] = 49152] = "VALUE_LENGTH";
BinTrieFlags2[BinTrieFlags2["BRANCH_LENGTH"] = 16256] = "BRANCH_LENGTH";
BinTrieFlags2[BinTrieFlags2["JUMP_TABLE"] = 127] = "JUMP_TABLE";
})(BinTrieFlags || (BinTrieFlags = {}));
function isNumber(code) {
return code >= CharCodes.ZERO && code <= CharCodes.NINE;
}
function isHexadecimalCharacter(code) {
return code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_F || code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_F;
}
function isAsciiAlphaNumeric(code) {
return code >= CharCodes.UPPER_A && code <= CharCodes.UPPER_Z || code >= CharCodes.LOWER_A && code <= CharCodes.LOWER_Z || isNumber(code);
}
function isEntityInAttributeInvalidEnd(code) {
return code === CharCodes.EQUALS || isAsciiAlphaNumeric(code);
}
var EntityDecoderState;
(function(EntityDecoderState2) {
EntityDecoderState2[EntityDecoderState2["EntityStart"] = 0] = "EntityStart";
EntityDecoderState2[EntityDecoderState2["NumericStart"] = 1] = "NumericStart";
EntityDecoderState2[EntityDecoderState2["NumericDecimal"] = 2] = "NumericDecimal";
EntityDecoderState2[EntityDecoderState2["NumericHex"] = 3] = "NumericHex";
EntityDecoderState2[EntityDecoderState2["NamedEntity"] = 4] = "NamedEntity";
})(EntityDecoderState || (EntityDecoderState = {}));
var DecodingMode;
(function(DecodingMode2) {
DecodingMode2[DecodingMode2["Legacy"] = 0] = "Legacy";
DecodingMode2[DecodingMode2["Strict"] = 1] = "Strict";
DecodingMode2[DecodingMode2["Attribute"] = 2] = "Attribute";
})(DecodingMode || (DecodingMode = {}));
var EntityDecoder = class {
constructor(decodeTree, emitCodePoint, errors) {
this.decodeTree = decodeTree;
this.emitCodePoint = emitCodePoint;
this.errors = errors;
this.state = EntityDecoderState.EntityStart;
this.consumed = 1;
this.result = 0;
this.treeIndex = 0;
this.excess = 1;
this.decodeMode = DecodingMode.Strict;
}
/** Resets the instance to make it reusable. */
startEntity(decodeMode) {
this.decodeMode = decodeMode;
this.state = EntityDecoderState.EntityStart;
this.result = 0;
this.treeIndex = 0;
this.excess = 1;
this.consumed = 1;
}
/**
* Write an entity to the decoder. This can be called multiple times with partial entities.
* If the entity is incomplete, the decoder will return -1.
*
* Mirrors the implementation of `getDecoder`, but with the ability to stop decoding if the
* entity is incomplete, and resume when the next string is written.
*
* @param string The string containing the entity (or a continuation of the entity).
* @param offset The offset at which the entity begins. Should be 0 if this is not the first call.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
write(str, offset) {
switch (this.state) {
case EntityDecoderState.EntityStart: {
if (str.charCodeAt(offset) === CharCodes.NUM) {
this.state = EntityDecoderState.NumericStart;
this.consumed += 1;
return this.stateNumericStart(str, offset + 1);
}
this.state = EntityDecoderState.NamedEntity;
return this.stateNamedEntity(str, offset);
}
case EntityDecoderState.NumericStart: {
return this.stateNumericStart(str, offset);
}
case EntityDecoderState.NumericDecimal: {
return this.stateNumericDecimal(str, offset);
}
case EntityDecoderState.NumericHex: {
return this.stateNumericHex(str, offset);
}
case EntityDecoderState.NamedEntity: {
return this.stateNamedEntity(str, offset);
}
}
}
/**
* Switches between the numeric decimal and hexadecimal states.
*
* Equivalent to the `Numeric character reference state` in the HTML spec.
*
* @param str The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNumericStart(str, offset) {
if (offset >= str.length) {
return -1;
}
if ((str.charCodeAt(offset) | TO_LOWER_BIT) === CharCodes.LOWER_X) {
this.state = EntityDecoderState.NumericHex;
this.consumed += 1;
return this.stateNumericHex(str, offset + 1);
}
this.state = EntityDecoderState.NumericDecimal;
return this.stateNumericDecimal(str, offset);
}
addToNumericResult(str, start, end, base) {
if (start !== end) {
const digitCount = end - start;
this.result = this.result * Math.pow(base, digitCount) + parseInt(str.substr(start, digitCount), base);
this.consumed += digitCount;
}
}
/**
* Parses a hexadecimal numeric entity.
*
* Equivalent to the `Hexademical character reference state` in the HTML spec.
*
* @param str The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNumericHex(str, offset) {
const startIdx = offset;
while (offset < str.length) {
const char = str.charCodeAt(offset);
if (isNumber(char) || isHexadecimalCharacter(char)) {
offset += 1;
} else {
this.addToNumericResult(str, startIdx, offset, 16);
return this.emitNumericEntity(char, 3);
}
}
this.addToNumericResult(str, startIdx, offset, 16);
return -1;
}
/**
* Parses a decimal numeric entity.
*
* Equivalent to the `Decimal character reference state` in the HTML spec.
*
* @param str The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNumericDecimal(str, offset) {
const startIdx = offset;
while (offset < str.length) {
const char = str.charCodeAt(offset);
if (isNumber(char)) {
offset += 1;
} else {
this.addToNumericResult(str, startIdx, offset, 10);
return this.emitNumericEntity(char, 2);
}
}
this.addToNumericResult(str, startIdx, offset, 10);
return -1;
}
/**
* Validate and emit a numeric entity.
*
* Implements the logic from the `Hexademical character reference start
* state` and `Numeric character reference end state` in the HTML spec.
*
* @param lastCp The last code point of the entity. Used to see if the
* entity was terminated with a semicolon.
* @param expectedLength The minimum number of characters that should be
* consumed. Used to validate that at least one digit
* was consumed.
* @returns The number of characters that were consumed.
*/
emitNumericEntity(lastCp, expectedLength) {
var _a2;
if (this.consumed <= expectedLength) {
(_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.absenceOfDigitsInNumericCharacterReference(this.consumed);
return 0;
}
if (lastCp === CharCodes.SEMI) {
this.consumed += 1;
} else if (this.decodeMode === DecodingMode.Strict) {
return 0;
}
this.emitCodePoint(replaceCodePoint(this.result), this.consumed);
if (this.errors) {
if (lastCp !== CharCodes.SEMI) {
this.errors.missingSemicolonAfterCharacterReference();
}
this.errors.validateNumericCharacterReference(this.result);
}
return this.consumed;
}
/**
* Parses a named entity.
*
* Equivalent to the `Named character reference state` in the HTML spec.
*
* @param str The string containing the entity (or a continuation of the entity).
* @param offset The current offset.
* @returns The number of characters that were consumed, or -1 if the entity is incomplete.
*/
stateNamedEntity(str, offset) {
const { decodeTree } = this;
let current = decodeTree[this.treeIndex];
let valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
for (; offset < str.length; offset++, this.excess++) {
const char = str.charCodeAt(offset);
this.treeIndex = determineBranch(decodeTree, current, this.treeIndex + Math.max(1, valueLength), char);
if (this.treeIndex < 0) {
return this.result === 0 || // If we are parsing an attribute
this.decodeMode === DecodingMode.Attribute && // We shouldn't have consumed any characters after the entity,
(valueLength === 0 || // And there should be no invalid characters.
isEntityInAttributeInvalidEnd(char)) ? 0 : this.emitNotTerminatedNamedEntity();
}
current = decodeTree[this.treeIndex];
valueLength = (current & BinTrieFlags.VALUE_LENGTH) >> 14;
if (valueLength !== 0) {
if (char === CharCodes.SEMI) {
return this.emitNamedEntityData(this.treeIndex, valueLength, this.consumed + this.excess);
}
if (this.decodeMode !== DecodingMode.Strict) {
this.result = this.treeIndex;
this.consumed += this.excess;
this.excess = 0;
}
}
}
return -1;
}
/**
* Emit a named entity that was not terminated with a semicolon.
*
* @returns The number of characters consumed.
*/
emitNotTerminatedNamedEntity() {
var _a2;
const { result, decodeTree } = this;
const valueLength = (decodeTree[result] & BinTrieFlags.VALUE_LENGTH) >> 14;
this.emitNamedEntityData(result, valueLength, this.consumed);
(_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.missingSemicolonAfterCharacterReference();
return this.consumed;
}
/**
* Emit a named entity.
*
* @param result The index of the entity in the decode tree.
* @param valueLength The number of bytes in the entity.
* @param consumed The number of characters consumed.
*
* @returns The number of characters consumed.
*/
emitNamedEntityData(result, valueLength, consumed) {
const { decodeTree } = this;
this.emitCodePoint(valueLength === 1 ? decodeTree[result] & ~BinTrieFlags.VALUE_LENGTH : decodeTree[result + 1], consumed);
if (valueLength === 3) {
this.emitCodePoint(decodeTree[result + 2], consumed);
}
return consumed;
}
/**
* Signal to the parser that the end of the input was reached.
*
* Remaining data will be emitted and relevant errors will be produced.
*
* @returns The number of characters consumed.
*/
end() {
var _a2;
switch (this.state) {
case EntityDecoderState.NamedEntity: {
return this.result !== 0 && (this.decodeMode !== DecodingMode.Attribute || this.result === this.treeIndex) ? this.emitNotTerminatedNamedEntity() : 0;
}
// Otherwise, emit a numeric entity if we have one.
case EntityDecoderState.NumericDecimal: {
return this.emitNumericEntity(0, 2);
}
case EntityDecoderState.NumericHex: {
return this.emitNumericEntity(0, 3);
}
case EntityDecoderState.NumericStart: {
(_a2 = this.errors) === null || _a2 === void 0 ? void 0 : _a2.absenceOfDigitsInNumericCharacterReference(this.consumed);
return 0;
}
case EntityDecoderState.EntityStart: {
return 0;
}
}
}
};
function getDecoder(decodeTree) {
let ret = "";
const decoder = new EntityDecoder(decodeTree, (str) => ret += fromCodePoint(str));
return function decodeWithTrie(str, decodeMode) {
let lastIndex = 0;
let offset = 0;
while ((offset = str.indexOf("&", offset)) >= 0) {
ret += str.slice(lastIndex, offset);
decoder.startEntity(decodeMode);
const len = decoder.write(
str,
// Skip the "&"
offset + 1
);
if (len < 0) {
lastIndex = offset + decoder.end();
break;
}
lastIndex = offset + len;
offset = len === 0 ? lastIndex + 1 : lastIndex;
}
const result = ret + str.slice(lastIndex);
ret = "";
return result;
};
}
function determineBranch(decodeTree, current, nodeIdx, char) {
const branchCount = (current & BinTrieFlags.BRANCH_LENGTH) >> 7;
const jumpOffset = current & BinTrieFlags.JUMP_TABLE;
if (branchCount === 0) {
return jumpOffset !== 0 && char === jumpOffset ? nodeIdx : -1;
}
if (jumpOffset) {
const value = char - jumpOffset;
return value < 0 || value >= branchCount ? -1 : decodeTree[nodeIdx + value] - 1;
}
let lo = nodeIdx;
let hi = lo + branchCount - 1;
while (lo <= hi) {
const mid = lo + hi >>> 1;
const midVal = decodeTree[mid];
if (midVal < char) {
lo = mid + 1;
} else if (midVal > char) {
hi = mid - 1;
} else {
return decodeTree[mid + branchCount];
}
}
return -1;
}
var htmlDecoder = getDecoder(decode_data_html_default);
var xmlDecoder = getDecoder(decode_data_xml_default);
// node_modules/parse5/dist/common/html.js
var html_exports = {};
__export(html_exports, {
ATTRS: () => ATTRS,
DOCUMENT_MODE: () => DOCUMENT_MODE,
NS: () => NS,
NUMBERED_HEADERS: () => NUMBERED_HEADERS,
SPECIAL_ELEMENTS: () => SPECIAL_ELEMENTS,
TAG_ID: () => TAG_ID,
TAG_NAMES: () => TAG_NAMES,
getTagID: () => getTagID,
hasUnescapedText: () => hasUnescapedText
});
var NS;
(function(NS2) {
NS2["HTML"] = "http://www.w3.org/1999/xhtml";
NS2["MATHML"] = "http://www.w3.org/1998/Math/MathML";
NS2["SVG"] = "http://www.w3.org/2000/svg";
NS2["XLINK"] = "http://www.w3.org/1999/xlink";
NS2["XML"] = "http://www.w3.org/XML/1998/namespace";
NS2["XMLNS"] = "http://www.w3.org/2000/xmlns/";
})(NS || (NS = {}));
var ATTRS;
(function(ATTRS2) {
ATTRS2["TYPE"] = "type";
ATTRS2["ACTION"] = "action";
ATTRS2["ENCODING"] = "encoding";
ATTRS2["PROMPT"] = "prompt";
ATTRS2["NAME"] = "name";
ATTRS2["COLOR"] = "color";
ATTRS2["FACE"] = "face";
ATTRS2["SIZE"] = "size";
})(ATTRS || (ATTRS = {}));
var DOCUMENT_MODE;
(function(DOCUMENT_MODE2) {
DOCUMENT_MODE2["NO_QUIRKS"] = "no-quirks";
DOCUMENT_MODE2["QUIRKS"] = "quirks";
DOCUMENT_MODE2["LIMITED_QUIRKS"] = "limited-quirks";
})(DOCUMENT_MODE || (DOCUMENT_MODE = {}));
var TAG_NAMES;
(function(TAG_NAMES2) {
TAG_NAMES2["A"] = "a";
TAG_NAMES2["ADDRESS"] = "address";
TAG_NAMES2["ANNOTATION_XML"] = "annotation-xml";
TAG_NAMES2["APPLET"] = "applet";
TAG_NAMES2["AREA"] = "area";
TAG_NAMES2["ARTICLE"] = "article";
TAG_NAMES2["ASIDE"] = "aside";
TAG_NAMES2["B"] = "b";
TAG_NAMES2["BASE"] = "base";
TAG_NAMES2["BASEFONT"] = "basefont";
TAG_NAMES2["BGSOUND"] = "bgsound";
TAG_NAMES2["BIG"] = "big";
TAG_NAMES2["BLOCKQUOTE"] = "blockquote";
TAG_NAMES2["BODY"] = "body";
TAG_NAMES2["BR"] = "br";
TAG_NAMES2["BUTTON"] = "button";
TAG_NAMES2["CAPTION"] = "caption";
TAG_NAMES2["CENTER"] = "center";
TAG_NAMES2["CODE"] = "code";
TAG_NAMES2["COL"] = "col";
TAG_NAMES2["COLGROUP"] = "colgroup";
TAG_NAMES2["DD"] = "dd";
TAG_NAMES2["DESC"] = "desc";
TAG_NAMES2["DETAILS"] = "details";
TAG_NAMES2["DIALOG"] = "dialog";
TAG_NAMES2["DIR"] = "dir";
TAG_NAMES2["DIV"] = "div";
TAG_NAMES2["DL"] = "dl";
TAG_NAMES2["DT"] = "dt";
TAG_NAMES2["EM"] = "em";
TAG_NAMES2["EMBED"] = "embed";
TAG_NAMES2["FIELDSET"] = "fieldset";
TAG_NAMES2["FIGCAPTION"] = "figcaption";
TAG_NAMES2["FIGURE"] = "figure";
TAG_NAMES2["FONT"] = "font";
TAG_NAMES2["FOOTER"] = "footer";
TAG_NAMES2["FOREIGN_OBJECT"] = "foreignObject";
TAG_NAMES2["FORM"] = "form";
TAG_NAMES2["FRAME"] = "frame";
TAG_NAMES2["FRAMESET"] = "frameset";
TAG_NAMES2["H1"] = "h1";
TAG_NAMES2["H2"] = "h2";
TAG_NAMES2["H3"] = "h3";
TAG_NAMES2["H4"] = "h4";
TAG_NAMES2["H5"] = "h5";
TAG_NAMES2["H6"] = "h6";
TAG_NAMES2["HEAD"] = "head";
TAG_NAMES2["HEADER"] = "header";
TAG_NAMES2["HGROUP"] = "hgroup";
TAG_NAMES2["HR"] = "hr";
TAG_NAMES2["HTML"] = "html";
TAG_NAMES2["I"] = "i";
TAG_NAMES2["IMG"] = "img";
TAG_NAMES2["IMAGE"] = "image";
TAG_NAMES2["INPUT"] = "input";
TAG_NAMES2["IFRAME"] = "iframe";
TAG_NAMES2["KEYGEN"] = "keygen";
TAG_NAMES2["LABEL"] = "label";
TAG_NAMES2["LI"] = "li";
TAG_NAMES2["LINK"] = "link";
TAG_NAMES2["LISTING"] = "listing";
TAG_NAMES2["MAIN"] = "main";
TAG_NAMES2["MALIGNMARK"] = "malignmark";
TAG_NAMES2["MARQUEE"] = "marquee";
TAG_NAMES2["MATH"] = "math";
TAG_NAMES2["MENU"] = "menu";
TAG_NAMES2["META"] = "meta";
TAG_NAMES2["MGLYPH"] = "mglyph";
TAG_NAMES2["MI"] = "mi";
TAG_NAMES2["MO"] = "mo";
TAG_NAMES2["MN"] = "mn";
TAG_NAMES2["MS"] = "ms";
TAG_NAMES2["MTEXT"] = "mtext";
TAG_NAMES2["NAV"] = "nav";
TAG_NAMES2["NOBR"] = "nobr";
TAG_NAMES2["NOFRAMES"] = "noframes";
TAG_NAMES2["NOEMBED"] = "noembed";
TAG_NAMES2["NOSCRIPT"] = "noscript";
TAG_NAMES2["OBJECT"] = "object";
TAG_NAMES2["OL"] = "ol";
TAG_NAMES2["OPTGROUP"] = "optgroup";
TAG_NAMES2["OPTION"] = "option";
TAG_NAMES2["P"] = "p";
TAG_NAMES2["PARAM"] = "param";
TAG_NAMES2["PLAINTEXT"] = "plaintext";
TAG_NAMES2["PRE"] = "pre";
TAG_NAMES2["RB"] = "rb";
TAG_NAMES2["RP"] = "rp";
TAG_NAMES2["RT"] = "rt";
TAG_NAMES2["RTC"] = "rtc";
TAG_NAMES2["RUBY"] = "ruby";
TAG_NAMES2["S"] = "s";
TAG_NAMES2["SCRIPT"] = "script";
TAG_NAMES2["SEARCH"] = "search";
TAG_NAMES2["SECTION"] = "section";
TAG_NAMES2["SELECT"] = "select";
TAG_NAMES2["SOURCE"] = "source";
TAG_NAMES2["SMALL"] = "small";
TAG_NAMES2["SPAN"] = "span";
TAG_NAMES2["STRIKE"] = "strike";
TAG_NAMES2["STRONG"] = "strong";
TAG_NAMES2["STYLE"] = "style";
TAG_NAMES2["SUB"] = "sub";
TAG_NAMES2["SUMMARY"] = "summary";
TAG_NAMES2["SUP"] = "sup";
TAG_NAMES2["TABLE"] = "table";
TAG_NAMES2["TBODY"] = "tbody";
TAG_NAMES2["TEMPLATE"] = "template";
TAG_NAMES2["TEXTAREA"] = "textarea";
TAG_NAMES2["TFOOT"] = "tfoot";
TAG_NAMES2["TD"] = "td";
TAG_NAMES2["TH"] = "th";
TAG_NAMES2["THEAD"] = "thead";
TAG_NAMES2["TITLE"] = "title";
TAG_NAMES2["TR"] = "tr";
TAG_NAMES2["TRACK"] = "track";
TAG_NAMES2["TT"] = "tt";
TAG_NAMES2["U"] = "u";
TAG_NAMES2["UL"] = "ul";
TAG_NAMES2["SVG"] = "svg";
TAG_NAMES2["VAR"] = "var";
TAG_NAMES2["WBR"] = "wbr";
TAG_NAMES2["XMP"] = "xmp";
})(TAG_NAMES || (TAG_NAMES = {}));
var TAG_ID;
(function(TAG_ID2) {
TAG_ID2[TAG_ID2["UNKNOWN"] = 0] = "UNKNOWN";
TAG_ID2[TAG_ID2["A"] = 1] = "A";
TAG_ID2[TAG_ID2["ADDRESS"] = 2] = "ADDRESS";
TAG_ID2[TAG_ID2["ANNOTATION_XML"] = 3] = "ANNOTATION_XML";
TAG_ID2[TAG_ID2["APPLET"] = 4] = "APPLET";
TAG_ID2[TAG_ID2["AREA"] = 5] = "AREA";
TAG_ID2[TAG_ID2["ARTICLE"] = 6] = "ARTICLE";
TAG_ID2[TAG_ID2["ASIDE"] = 7] = "ASIDE";
TAG_ID2[TAG_ID2["B"] = 8] = "B";
TAG_ID2[TAG_ID2["BASE"] = 9] = "BASE";
TAG_ID2[TAG_ID2["BASEFONT"] = 10] = "BASEFONT";
TAG_ID2[TAG_ID2["BGSOUND"] = 11] = "BGSOUND";
TAG_ID2[TAG_ID2["BIG"] = 12] = "BIG";
TAG_ID2[TAG_ID2["BLOCKQUOTE"] = 13] = "BLOCKQUOTE";
TAG_ID2[TAG_ID2["BODY"] = 14] = "BODY";
TAG_ID2[TAG_ID2["BR"] = 15] = "BR";
TAG_ID2[TAG_ID2["BUTTON"] = 16] = "BUTTON";
TAG_ID2[TAG_ID2["CAPTION"] = 17] = "CAPTION";
TAG_ID2[TAG_ID2["CENTER"] = 18] = "CENTER";
TAG_ID2[TAG_ID2["CODE"] = 19] = "CODE";
TAG_ID2[TAG_ID2["COL"] = 20] = "COL";
TAG_ID2[TAG_ID2["COLGROUP"] = 21] = "COLGROUP";
TAG_ID2[TAG_ID2["DD"] = 22] = "DD";
TAG_ID2[TAG_ID2["DESC"] = 23] = "DESC";
TAG_ID2[TAG_ID2["DETAILS"] = 24] = "DETAILS";
TAG_ID2[TAG_ID2["DIALOG"] = 25] = "DIALOG";
TAG_ID2[TAG_ID2["DIR"] = 26] = "DIR";
TAG_ID2[TAG_ID2["DIV"] = 27] = "DIV";
TAG_ID2[TAG_ID2["DL"] = 28] = "DL";
TAG_ID2[TAG_ID2["DT"] = 29] = "DT";
TAG_ID2[TAG_ID2["EM"] = 30] = "EM";
TAG_ID2[TAG_ID2["EMBED"] = 31] = "EMBED";
TAG_ID2[TAG_ID2["FIELDSET"] = 32] = "FIELDSET";
TAG_ID2[TAG_ID2["FIGCAPTION"] = 33] = "FIGCAPTION";
TAG_ID2[TAG_ID2["FIGURE"] = 34] = "FIGURE";
TAG_ID2[TAG_ID2["FONT"] = 35] = "FONT";
TAG_ID2[TAG_ID2["FOOTER"] = 36] = "FOOTER";
TAG_ID2[TAG_ID2["FOREIGN_OBJECT"] = 37] = "FOREIGN_OBJECT";
TAG_ID2[TAG_ID2["FORM"] = 38] = "FORM";
TAG_ID2[TAG_ID2["FRAME"] = 39] = "FRAME";
TAG_ID2[TAG_ID2["FRAMESET"] = 40] = "FRAMESET";
TAG_ID2[TAG_ID2["H1"] = 41] = "H1";
TAG_ID2[TAG_ID2["H2"] = 42] = "H2";
TAG_ID2[TAG_ID2["H3"] = 43] = "H3";
TAG_ID2[TAG_ID2["H4"] = 44] = "H4";
TAG_ID2[TAG_ID2["H5"] = 45] = "H5";
TAG_ID2[TAG_ID2["H6"] = 46] = "H6";
TAG_ID2[TAG_ID2["HEAD"] = 47] = "HEAD";
TAG_ID2[TAG_ID2["HEADER"] = 48] = "HEADER";
TAG_ID2[TAG_ID2["HGROUP"] = 49] = "HGROUP";
TAG_ID2[TAG_ID2["HR"] = 50] = "HR";
TAG_ID2[TAG_ID2["HTML"] = 51] = "HTML";
TAG_ID2[TAG_ID2["I"] = 52] = "I";
TAG_ID2[TAG_ID2["IMG"] = 53] = "IMG";
TAG_ID2[TAG_ID2["IMAGE"] = 54] = "IMAGE";
TAG_ID2[TAG_ID2["INPUT"] = 55] = "INPUT";
TAG_ID2[TAG_ID2["IFRAME"] = 56] = "IFRAME";
TAG_ID2[TAG_ID2["KEYGEN"] = 57] = "KEYGEN";
TAG_ID2[TAG_ID2["LABEL"] = 58] = "LABEL";
TAG_ID2[TAG_ID2["LI"] = 59] = "LI";
TAG_ID2[TAG_ID2["LINK"] = 60] = "LINK";
TAG_ID2[TAG_ID2["LISTING"] = 61] = "LISTING";
TAG_ID2[TAG_ID2["MAIN"] = 62] = "MAIN";
TAG_ID2[TAG_ID2["MALIGNMARK"] = 63] = "MALIGNMARK";
TAG_ID2[TAG_ID2["MARQUEE"] = 64] = "MARQUEE";
TAG_ID2[TAG_ID2["MATH"] = 65] = "MATH";
TAG_ID2[TAG_ID2["MENU"] = 66] = "MENU";
TAG_ID2[TAG_ID2["META"] = 67] = "META";
TAG_ID2[TAG_ID2["MGLYPH"] = 68] = "MGLYPH";
TAG_ID2[TAG_ID2["MI"] = 69] = "MI";
TAG_ID2[TAG_ID2["MO"] = 70] = "MO";
TAG_ID2[TAG_ID2["MN"] = 71] = "MN";
TAG_ID2[TAG_ID2["MS"] = 72] = "MS";
TAG_ID2[TAG_ID2["MTEXT"] = 73] = "MTEXT";
TAG_ID2[TAG_ID2["NAV"] = 74] = "NAV";
TAG_ID2[TAG_ID2["NOBR"] = 75] = "NOBR";
TAG_ID2[TAG_ID2["NOFRAMES"] = 76] = "NOFRAMES";
TAG_ID2[TAG_ID2["NOEMBED"] = 77] = "NOEMBED";
TAG_ID2[TAG_ID2["NOSCRIPT"] = 78] = "NOSCRIPT";
TAG_ID2[TAG_ID2["OBJECT"] = 79] = "OBJECT";
TAG_ID2[TAG_ID2["OL"] = 80] = "OL";
TAG_ID2[TAG_ID2["OPTGROUP"] = 81] = "OPTGROUP";
TAG_ID2[TAG_ID2["OPTION"] = 82] = "OPTION";
TAG_ID2[TAG_ID2["P"] = 83] = "P";
TAG_ID2[TAG_ID2["PARAM"] = 84] = "PARAM";
TAG_ID2[TAG_ID2["PLAINTEXT"] = 85] = "PLAINTEXT";
TAG_ID2[TAG_ID2["PRE"] = 86] = "PRE";
TAG_ID2[TAG_ID2["RB"] = 87] = "RB";
TAG_ID2[TAG_ID2["RP"] = 88] = "RP";
TAG_ID2[TAG_ID2["RT"] = 89] = "RT";
TAG_ID2[TAG_ID2["RTC"] = 90] = "RTC";
TAG_ID2[TAG_ID2["RUBY"] = 91] = "RUBY";
TAG_ID2[TAG_ID2["S"] = 92] = "S";
TAG_ID2[TAG_ID2["SCRIPT"] = 93] = "SCRIPT";
TAG_ID2[TAG_ID2["SEARCH"] = 94] = "SEARCH";
TAG_ID2[TAG_ID2["SECTION"] = 95] = "SECTION";
TAG_ID2[TAG_ID2["SELECT"] = 96] = "SELECT";
TAG_ID2[TAG_ID2["SOURCE"] = 97] = "SOURCE";
TAG_ID2[TAG_ID2["SMALL"] = 98] = "SMALL";
TAG_ID2[TAG_ID2["SPAN"] = 99] = "SPAN";
TAG_ID2[TAG_ID2["STRIKE"] = 100] = "STRIKE";
TAG_ID2[TAG_ID2["STRONG"] = 101] = "STRONG";
TAG_ID2[TAG_ID2["STYLE"] = 102] = "STYLE";
TAG_ID2[TAG_ID2["SUB"] = 103] = "SUB";
TAG_ID2[TAG_ID2["SUMMARY"] = 104] = "SUMMARY";
TAG_ID2[TAG_ID2["SUP"] = 105] = "SUP";
TAG_ID2[TAG_ID2["TABLE"] = 106] = "TABLE";
TAG_ID2[TAG_ID2["TBODY"] = 107] = "TBODY";
TAG_ID2[TAG_ID2["TEMPLATE"] = 108] = "TEMPLATE";
TAG_ID2[TAG_ID2["TEXTAREA"] = 109] = "TEXTAREA";
TAG_ID2[TAG_ID2["TFOOT"] = 110] = "TFOOT";
TAG_ID2[TAG_ID2["TD"] = 111] = "TD";
TAG_ID2[TAG_ID2["TH"] = 112] = "TH";
TAG_ID2[TAG_ID2["THEAD"] = 113] = "THEAD";
TAG_ID2[TAG_ID2["TITLE"] = 114] = "TITLE";
TAG_ID2[TAG_ID2["TR"] = 115] = "TR";
TAG_ID2[TAG_ID2["TRACK"] = 116] = "TRACK";
TAG_ID2[TAG_ID2["TT"] = 117] = "TT";
TAG_ID2[TAG_ID2["U"] = 118] = "U";
TAG_ID2[TAG_ID2["UL"] = 119] = "UL";
TAG_ID2[TAG_ID2["SVG"] = 120] = "SVG";
TAG_ID2[TAG_ID2["VAR"] = 121] = "VAR";
TAG_ID2[TAG_ID2["WBR"] = 122] = "WBR";
TAG_ID2[TAG_ID2["XMP"] = 123] = "XMP";
})(TAG_ID || (TAG_ID = {}));
var TAG_NAME_TO_ID = /* @__PURE__ */ new Map([
[TAG_NAMES.A, TAG_ID.A],
[TAG_NAMES.ADDRESS, TAG_ID.ADDRESS],
[TAG_NAMES.ANNOTATION_XML, TAG_ID.ANNOTATION_XML],
[TAG_NAMES.APPLET, TAG_ID.APPLET],
[TAG_NAMES.AREA, TAG_ID.AREA],
[TAG_NAMES.ARTICLE, TAG_ID.ARTICLE],
[TAG_NAMES.ASIDE, TAG_ID.ASIDE],
[TAG_NAMES.B, TAG_ID.B],
[TAG_NAMES.BASE, TAG_ID.BASE],
[TAG_NAMES.BASEFONT, TAG_ID.BASEFONT],
[TAG_NAMES.BGSOUND, TAG_ID.BGSOUND],
[TAG_NAMES.BIG, TAG_ID.BIG],
[TAG_NAMES.BLOCKQUOTE, TAG_ID.BLOCKQUOTE],
[TAG_NAMES.BODY, TAG_ID.BODY],
[TAG_NAMES.BR, TAG_ID.BR],
[TAG_NAMES.BUTTON, TAG_ID.BUTTON],
[TAG_NAMES.CAPTION, TAG_ID.CAPTION],
[TAG_NAMES.CENTER, TAG_ID.CENTER],
[TAG_NAMES.CODE, TAG_ID.CODE],
[TAG_NAMES.COL, TAG_ID.COL],
[TAG_NAMES.COLGROUP, TAG_ID.COLGROUP],
[TAG_NAMES.DD, TAG_ID.DD],
[TAG_NAMES.DESC, TAG_ID.DESC],
[TAG_NAMES.DETAILS, TAG_ID.DETAILS],
[TAG_NAMES.DIALOG, TAG_ID.DIALOG],
[TAG_NAMES.DIR, TAG_ID.DIR],
[TAG_NAMES.DIV, TAG_ID.DIV],
[TAG_NAMES.DL, TAG_ID.DL],
[TAG_NAMES.DT, TAG_ID.DT],
[TAG_NAMES.EM, TAG_ID.EM],
[TAG_NAMES.EMBED, TAG_ID.EMBED],
[TAG_NAMES.FIELDSET, TAG_ID.FIELDSET],
[TAG_NAMES.FIGCAPTION, TAG_ID.FIGCAPTION],
[TAG_NAMES.FIGURE, TAG_ID.FIGURE],
[TAG_NAMES.FONT, TAG_ID.FONT],
[TAG_NAMES.FOOTER, TAG_ID.FOOTER],
[TAG_NAMES.FOREIGN_OBJECT, TAG_ID.FOREIGN_OBJECT],
[TAG_NAMES.FORM, TAG_ID.FORM],
[TAG_NAMES.FRAME, TAG_ID.FRAME],
[TAG_NAMES.FRAMESET, TAG_ID.FRAMESET],
[TAG_NAMES.H1, TAG_ID.H1],
[TAG_NAMES.H2, TAG_ID.H2],
[TAG_NAMES.H3, TAG_ID.H3],
[TAG_NAMES.H4, TAG_ID.H4],
[TAG_NAMES.H5, TAG_ID.H5],
[TAG_NAMES.H6, TAG_ID.H6],
[TAG_NAMES.HEAD, TAG_ID.HEAD],
[TAG_NAMES.HEADER, TAG_ID.HEADER],
[TAG_NAMES.HGROUP, TAG_ID.HGROUP],
[TAG_NAMES.HR, TAG_ID.HR],
[TAG_NAMES.HTML, TAG_ID.HTML],
[TAG_NAMES.I, TAG_ID.I],
[TAG_NAMES.IMG, TAG_ID.IMG],
[TAG_NAMES.IMAGE, TAG_ID.IMAGE],
[TAG_NAMES.INPUT, TAG_ID.INPUT],
[TAG_NAMES.IFRAME, TAG_ID.IFRAME],
[TAG_NAMES.KEYGEN, TAG_ID.KEYGEN],
[TAG_NAMES.LABEL, TAG_ID.LABEL],
[TAG_NAMES.LI, TAG_ID.LI],
[TAG_NAMES.LINK, TAG_ID.LINK],
[TAG_NAMES.LISTING, TAG_ID.LISTING],
[TAG_NAMES.MAIN, TAG_ID.MAIN],
[TAG_NAMES.MALIGNMARK, TAG_ID.MALIGNMARK],
[TAG_NAMES.MARQUEE, TAG_ID.MARQUEE],
[TAG_NAMES.MATH, TAG_ID.MATH],
[TAG_NAMES.MENU, TAG_ID.MENU],
[TAG_NAMES.META, TAG_ID.META],
[TAG_NAMES.MGLYPH, TAG_ID.MGLYPH],
[TAG_NAMES.MI, TAG_ID.MI],
[TAG_NAMES.MO, TAG_ID.MO],
[TAG_NAMES.MN, TAG_ID.MN],
[TAG_NAMES.MS, TAG_ID.MS],
[TAG_NAMES.MTEXT, TAG_ID.MTEXT],
[TAG_NAMES.NAV, TAG_ID.NAV],
[TAG_NAMES.NOBR, TAG_ID.NOBR],
[TAG_NAMES.NOFRAMES, TAG_ID.NOFRAMES],
[TAG_NAMES.NOEMBED, TAG_ID.NOEMBED],
[TAG_NAMES.NOSCRIPT, TAG_ID.NOSCRIPT],
[TAG_NAMES.OBJECT, TAG_ID.OBJECT],
[TAG_NAMES.OL, TAG_ID.OL],
[TAG_NAMES.OPTGROUP, TAG_ID.OPTGROUP],
[TAG_NAMES.OPTION, TAG_ID.OPTION],
[TAG_NAMES.P, TAG_ID.P],
[TAG_NAMES.PARAM, TAG_ID.PARAM],
[TAG_NAMES.PLAINTEXT, TAG_ID.PLAINTEXT],
[TAG_NAMES.PRE, TAG_ID.PRE],
[TAG_NAMES.RB, TAG_ID.RB],
[TAG_NAMES.RP, TAG_ID.RP],
[TAG_NAMES.RT, TAG_ID.RT],
[TAG_NAMES.RTC, TAG_ID.RTC],
[TAG_NAMES.RUBY, TAG_ID.RUBY],
[TAG_NAMES.S, TAG_ID.S],
[TAG_NAMES.SCRIPT, TAG_ID.SCRIPT],
[TAG_NAMES.SEARCH, TAG_ID.SEARCH],
[TAG_NAMES.SECTION, TAG_ID.SECTION],
[TAG_NAMES.SELECT, TAG_ID.SELECT],
[TAG_NAMES.SOURCE, TAG_ID.SOURCE],
[TAG_NAMES.SMALL, TAG_ID.SMALL],
[TAG_NAMES.SPAN, TAG_ID.SPAN],
[TAG_NAMES.STRIKE, TAG_ID.STRIKE],
[TAG_NAMES.STRONG, TAG_ID.STRONG],
[TAG_NAMES.STYLE, TAG_ID.STYLE],
[TAG_NAMES.SUB, TAG_ID.SUB],
[TAG_NAMES.SUMMARY, TAG_ID.SUMMARY],
[TAG_NAMES.SUP, TAG_ID.SUP],
[TAG_NAMES.TABLE, TAG_ID.TABLE],
[TAG_NAMES.TBODY, TAG_ID.TBODY],
[TAG_NAMES.TEMPLATE, TAG_ID.TEMPLATE],
[TAG_NAMES.TEXTAREA, TAG_ID.TEXTAREA],
[TAG_NAMES.TFOOT, TAG_ID.TFOOT],
[TAG_NAMES.TD, TAG_ID.TD],
[TAG_NAMES.TH, TAG_ID.TH],
[TAG_NAMES.THEAD, TAG_ID.THEAD],
[TAG_NAMES.TITLE, TAG_ID.TITLE],
[TAG_NAMES.TR, TAG_ID.TR],
[TAG_NAMES.TRACK, TAG_ID.TRACK],
[TAG_NAMES.TT, TAG_ID.TT],
[TAG_NAMES.U, TAG_ID.U],
[TAG_NAMES.UL, TAG_ID.UL],
[TAG_NAMES.SVG, TAG_ID.SVG],
[TAG_NAMES.VAR, TAG_ID.VAR],
[TAG_NAMES.WBR, TAG_ID.WBR],
[TAG_NAMES.XMP, TAG_ID.XMP]
]);
function getTagID(tagName) {
var _a2;
return (_a2 = TAG_NAME_TO_ID.get(tagName)) !== null && _a2 !== void 0 ? _a2 : TAG_ID.UNKNOWN;
}
var $ = TAG_ID;
var SPECIAL_ELEMENTS = {
[NS.HTML]: /* @__PURE__ */ new Set([
$.ADDRESS,
$.APPLET,
$.AREA,
$.ARTICLE,
$.ASIDE,
$.BASE,
$.BASEFONT,
$.BGSOUND,
$.BLOCKQUOTE,
$.BODY,
$.BR,
$.BUTTON,
$.CAPTION,
$.CENTER,
$.COL,
$.COLGROUP,
$.DD,
$.DETAILS,
$.DIR,
$.DIV,
$.DL,
$.DT,
$.EMBED,
$.FIELDSET,
$.FIGCAPTION,
$.FIGURE,
$.FOOTER,
$.FORM,
$.FRAME,
$.FRAMESET,
$.H1,
$.H2,
$.H3,
$.H4,
$.H5,
$.H6,
$.HEAD,
$.HEADER,
$.HGROUP,
$.HR,
$.HTML,
$.IFRAME,
$.IMG,
$.INPUT,
$.LI,
$.LINK,
$.LISTING,
$.MAIN,
$.MARQUEE,
$.MENU,
$.META,
$.NAV,
$.NOEMBED,
$.NOFRAMES,
$.NOSCRIPT,
$.OBJECT,
$.OL,
$.P,
$.PARAM,
$.PLAINTEXT,
$.PRE,
$.SCRIPT,
$.SECTION,
$.SELECT,
$.SOURCE,
$.STYLE,
$.SUMMARY,
$.TABLE,
$.TBODY,
$.TD,
$.TEMPLATE,
$.TEXTAREA,
$.TFOOT,
$.TH,
$.THEAD,
$.TITLE,
$.TR,
$.TRACK,
$.UL,
$.WBR,
$.XMP
]),
[NS.MATHML]: /* @__PURE__ */ new Set([$.MI, $.MO, $.MN, $.MS, $.MTEXT, $.ANNOTATION_XML]),
[NS.SVG]: /* @__PURE__ */ new Set([$.TITLE, $.FOREIGN_OBJECT, $.DESC]),
[NS.XLINK]: /* @__PURE__ */ new Set(),
[NS.XML]: /* @__PURE__ */ new Set(),
[NS.XMLNS]: /* @__PURE__ */ new Set()
};
var NUMBERED_HEADERS = /* @__PURE__ */ new Set([$.H1, $.H2, $.H3, $.H4, $.H5, $.H6]);
var UNESCAPED_TEXT = /* @__PURE__ */ new Set([
TAG_NAMES.STYLE,
TAG_NAMES.SCRIPT,
TAG_NAMES.XMP,
TAG_NAMES.IFRAME,
TAG_NAMES.NOEMBED,
TAG_NAMES.NOFRAMES,
TAG_NAMES.PLAINTEXT
]);
function hasUnescapedText(tn, scriptingEnabled) {
return UNESCAPED_TEXT.has(tn) || scriptingEnabled && tn === TAG_NAMES.NOSCRIPT;
}
// node_modules/parse5/dist/tokenizer/index.js
var State;
(function(State2) {
State2[State2["DATA"] = 0] = "DATA";
State2[State2["RCDATA"] = 1] = "RCDATA";
State2[State2["RAWTEXT"] = 2] = "RAWTEXT";
State2[State2["SCRIPT_DATA"] = 3] = "SCRIPT_DATA";
State2[State2["PLAINTEXT"] = 4] = "PLAINTEXT";
State2[State2["TAG_OPEN"] = 5] = "TAG_OPEN";
State2[State2["END_TAG_OPEN"] = 6] = "END_TAG_OPEN";
State2[State2["TAG_NAME"] = 7] = "TAG_NAME";
State2[State2["RCDATA_LESS_THAN_SIGN"] = 8] = "RCDATA_LESS_THAN_SIGN";
State2[State2["RCDATA_END_TAG_OPEN"] = 9] = "RCDATA_END_TAG_OPEN";
State2[State2["RCDATA_END_TAG_NAME"] = 10] = "RCDATA_END_TAG_NAME";
State2[State2["RAWTEXT_LESS_THAN_SIGN"] = 11] = "RAWTEXT_LESS_THAN_SIGN";
State2[State2["RAWTEXT_END_TAG_OPEN"] = 12] = "RAWTEXT_END_TAG_OPEN";
State2[State2["RAWTEXT_END_TAG_NAME"] = 13] = "RAWTEXT_END_TAG_NAME";
State2[State2["SCRIPT_DATA_LESS_THAN_SIGN"] = 14] = "SCRIPT_DATA_LESS_THAN_SIGN";
State2[State2["SCRIPT_DATA_END_TAG_OPEN"] = 15] = "SCRIPT_DATA_END_TAG_OPEN";
State2[State2["SCRIPT_DATA_END_TAG_NAME"] = 16] = "SCRIPT_DATA_END_TAG_NAME";
State2[State2["SCRIPT_DATA_ESCAPE_START"] = 17] = "SCRIPT_DATA_ESCAPE_START";
State2[State2["SCRIPT_DATA_ESCAPE_START_DASH"] = 18] = "SCRIPT_DATA_ESCAPE_START_DASH";
State2[State2["SCRIPT_DATA_ESCAPED"] = 19] = "SCRIPT_DATA_ESCAPED";
State2[State2["SCRIPT_DATA_ESCAPED_DASH"] = 20] = "SCRIPT_DATA_ESCAPED_DASH";
State2[State2["SCRIPT_DATA_ESCAPED_DASH_DASH"] = 21] = "SCRIPT_DATA_ESCAPED_DASH_DASH";
State2[State2["SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN"] = 22] = "SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN";
State2[State2["SCRIPT_DATA_ESCAPED_END_TAG_OPEN"] = 23] = "SCRIPT_DATA_ESCAPED_END_TAG_OPEN";
State2[State2["SCRIPT_DATA_ESCAPED_END_TAG_NAME"] = 24] = "SCRIPT_DATA_ESCAPED_END_TAG_NAME";
State2[State2["SCRIPT_DATA_DOUBLE_ESCAPE_START"] = 25] = "SCRIPT_DATA_DOUBLE_ESCAPE_START";
State2[State2["SCRIPT_DATA_DOUBLE_ESCAPED"] = 26] = "SCRIPT_DATA_DOUBLE_ESCAPED";
State2[State2["SCRIPT_DATA_DOUBLE_ESCAPED_DASH"] = 27] = "SCRIPT_DATA_DOUBLE_ESCAPED_DASH";
State2[State2["SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH"] = 28] = "SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH";
State2[State2["SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN"] = 29] = "SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN";
State2[State2["SCRIPT_DATA_DOUBLE_ESCAPE_END"] = 30] = "SCRIPT_DATA_DOUBLE_ESCAPE_END";
State2[State2["BEFORE_ATTRIBUTE_NAME"] = 31] = "BEFORE_ATTRIBUTE_NAME";
State2[State2["ATTRIBUTE_NAME"] = 32] = "ATTRIBUTE_NAME";
State2[State2["AFTER_ATTRIBUTE_NAME"] = 33] = "AFTER_ATTRIBUTE_NAME";
State2[State2["BEFORE_ATTRIBUTE_VALUE"] = 34] = "BEFORE_ATTRIBUTE_VALUE";
State2[State2["ATTRIBUTE_VALUE_DOUBLE_QUOTED"] = 35] = "ATTRIBUTE_VALUE_DOUBLE_QUOTED";
State2[State2["ATTRIBUTE_VALUE_SINGLE_QUOTED"] = 36] = "ATTRIBUTE_VALUE_SINGLE_QUOTED";
State2[State2["ATTRIBUTE_VALUE_UNQUOTED"] = 37] = "ATTRIBUTE_VALUE_UNQUOTED";
State2[State2["AFTER_ATTRIBUTE_VALUE_QUOTED"] = 38] = "AFTER_ATTRIBUTE_VALUE_QUOTED";
State2[State2["SELF_CLOSING_START_TAG"] = 39] = "SELF_CLOSING_START_TAG";
State2[State2["BOGUS_COMMENT"] = 40] = "BOGUS_COMMENT";
State2[State2["MARKUP_DECLARATION_OPEN"] = 41] = "MARKUP_DECLARATION_OPEN";
State2[State2["COMMENT_START"] = 42] = "COMMENT_START";
State2[State2["COMMENT_START_DASH"] = 43] = "COMMENT_START_DASH";
State2[State2["COMMENT"] = 44] = "COMMENT";
State2[State2["COMMENT_LESS_THAN_SIGN"] = 45] = "COMMENT_LESS_THAN_SIGN";
State2[State2["COMMENT_LESS_THAN_SIGN_BANG"] = 46] = "COMMENT_LESS_THAN_SIGN_BANG";
State2[State2["COMMENT_LESS_THAN_SIGN_BANG_DASH"] = 47] = "COMMENT_LESS_THAN_SIGN_BANG_DASH";
State2[State2["COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH"] = 48] = "COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH";
State2[State2["COMMENT_END_DASH"] = 49] = "COMMENT_END_DASH";
State2[State2["COMMENT_END"] = 50] = "COMMENT_END";
State2[State2["COMMENT_END_BANG"] = 51] = "COMMENT_END_BANG";
State2[State2["DOCTYPE"] = 52] = "DOCTYPE";
State2[State2["BEFORE_DOCTYPE_NAME"] = 53] = "BEFORE_DOCTYPE_NAME";
State2[State2["DOCTYPE_NAME"] = 54] = "DOCTYPE_NAME";
State2[State2["AFTER_DOCTYPE_NAME"] = 55] = "AFTER_DOCTYPE_NAME";
State2[State2["AFTER_DOCTYPE_PUBLIC_KEYWORD"] = 56] = "AFTER_DOCTYPE_PUBLIC_KEYWORD";
State2[State2["BEFORE_DOCTYPE_PUBLIC_IDENTIFIER"] = 57] = "BEFORE_DOCTYPE_PUBLIC_IDENTIFIER";
State2[State2["DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED"] = 58] = "DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED";
State2[State2["DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED"] = 59] = "DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED";
State2[State2["AFTER_DOCTYPE_PUBLIC_IDENTIFIER"] = 60] = "AFTER_DOCTYPE_PUBLIC_IDENTIFIER";
State2[State2["BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS"] = 61] = "BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS";
State2[State2["AFTER_DOCTYPE_SYSTEM_KEYWORD"] = 62] = "AFTER_DOCTYPE_SYSTEM_KEYWORD";
State2[State2["BEFORE_DOCTYPE_SYSTEM_IDENTIFIER"] = 63] = "BEFORE_DOCTYPE_SYSTEM_IDENTIFIER";
State2[State2["DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED"] = 64] = "DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED";
State2[State2["DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED"] = 65] = "DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED";
State2[State2["AFTER_DOCTYPE_SYSTEM_IDENTIFIER"] = 66] = "AFTER_DOCTYPE_SYSTEM_IDENTIFIER";
State2[State2["BOGUS_DOCTYPE"] = 67] = "BOGUS_DOCTYPE";
State2[State2["CDATA_SECTION"] = 68] = "CDATA_SECTION";
State2[State2["CDATA_SECTION_BRACKET"] = 69] = "CDATA_SECTION_BRACKET";
State2[State2["CDATA_SECTION_END"] = 70] = "CDATA_SECTION_END";
State2[State2["CHARACTER_REFERENCE"] = 71] = "CHARACTER_REFERENCE";
State2[State2["AMBIGUOUS_AMPERSAND"] = 72] = "AMBIGUOUS_AMPERSAND";
})(State || (State = {}));
var TokenizerMode = {
DATA: State.DATA,
RCDATA: State.RCDATA,
RAWTEXT: State.RAWTEXT,
SCRIPT_DATA: State.SCRIPT_DATA,
PLAINTEXT: State.PLAINTEXT,
CDATA_SECTION: State.CDATA_SECTION
};
function isAsciiDigit(cp) {
return cp >= CODE_POINTS.DIGIT_0 && cp <= CODE_POINTS.DIGIT_9;
}
function isAsciiUpper(cp) {
return cp >= CODE_POINTS.LATIN_CAPITAL_A && cp <= CODE_POINTS.LATIN_CAPITAL_Z;
}
function isAsciiLower(cp) {
return cp >= CODE_POINTS.LATIN_SMALL_A && cp <= CODE_POINTS.LATIN_SMALL_Z;
}
function isAsciiLetter(cp) {
return isAsciiLower(cp) || isAsciiUpper(cp);
}
function isAsciiAlphaNumeric2(cp) {
return isAsciiLetter(cp) || isAsciiDigit(cp);
}
function toAsciiLower(cp) {
return cp + 32;
}
function isWhitespace(cp) {
return cp === CODE_POINTS.SPACE || cp === CODE_POINTS.LINE_FEED || cp === CODE_POINTS.TABULATION || cp === CODE_POINTS.FORM_FEED;
}
function isScriptDataDoubleEscapeSequenceEnd(cp) {
return isWhitespace(cp) || cp === CODE_POINTS.SOLIDUS || cp === CODE_POINTS.GREATER_THAN_SIGN;
}
function getErrorForNumericCharacterReference(code) {
if (code === CODE_POINTS.NULL) {
return ERR.nullCharacterReference;
} else if (code > 1114111) {
return ERR.characterReferenceOutsideUnicodeRange;
} else if (isSurrogate(code)) {
return ERR.surrogateCharacterReference;
} else if (isUndefinedCodePoint(code)) {
return ERR.noncharacterCharacterReference;
} else if (isControlCodePoint(code) || code === CODE_POINTS.CARRIAGE_RETURN) {
return ERR.controlCharacterReference;
}
return null;
}
var Tokenizer = class {
constructor(options, handler) {
this.options = options;
this.handler = handler;
this.paused = false;
this.inLoop = false;
this.inForeignNode = false;
this.lastStartTagName = "";
this.active = false;
this.state = State.DATA;
this.returnState = State.DATA;
this.entityStartPos = 0;
this.consumedAfterSnapshot = -1;
this.currentCharacterToken = null;
this.currentToken = null;
this.currentAttr = { name: "", value: "" };
this.preprocessor = new Preprocessor(handler);
this.currentLocation = this.getCurrentLocation(-1);
this.entityDecoder = new EntityDecoder(decode_data_html_default, (cp, consumed) => {
this.preprocessor.pos = this.entityStartPos + consumed - 1;
this._flushCodePointConsumedAsCharacterReference(cp);
}, handler.onParseError ? {
missingSemicolonAfterCharacterReference: () => {
this._err(ERR.missingSemicolonAfterCharacterReference, 1);
},
absenceOfDigitsInNumericCharacterReference: (consumed) => {
this._err(ERR.absenceOfDigitsInNumericCharacterReference, this.entityStartPos - this.preprocessor.pos + consumed);
},
validateNumericCharacterReference: (code) => {
const error = getErrorForNumericCharacterReference(code);
if (error)
this._err(error, 1);
}
} : void 0);
}
//Errors
_err(code, cpOffset = 0) {
var _a2, _b;
(_b = (_a2 = this.handler).onParseError) === null || _b === void 0 ? void 0 : _b.call(_a2, this.preprocessor.getError(code, cpOffset));
}
// NOTE: `offset` may never run across line boundaries.
getCurrentLocation(offset) {
if (!this.options.sourceCodeLocationInfo) {
return null;
}
return {
startLine: this.preprocessor.line,
startCol: this.preprocessor.col - offset,
startOffset: this.preprocessor.offset - offset,
endLine: -1,
endCol: -1,
endOffset: -1
};
}
_runParsingLoop() {
if (this.inLoop)
return;
this.inLoop = true;
while (this.active && !this.paused) {
this.consumedAfterSnapshot = 0;
const cp = this._consume();
if (!this._ensureHibernation()) {
this._callState(cp);
}
}
this.inLoop = false;
}
//API
pause() {
this.paused = true;
}
resume(writeCallback) {
if (!this.paused) {
throw new Error("Parser was already resumed");
}
this.paused = false;
if (this.inLoop)
return;
this._runParsingLoop();
if (!this.paused) {
writeCallback === null || writeCallback === void 0 ? void 0 : writeCallback();
}
}
write(chunk, isLastChunk, writeCallback) {
this.active = true;
this.preprocessor.write(chunk, isLastChunk);
this._runParsingLoop();
if (!this.paused) {
writeCallback === null || writeCallback === void 0 ? void 0 : writeCallback();
}
}
insertHtmlAtCurrentPos(chunk) {
this.active = true;
this.preprocessor.insertHtmlAtCurrentPos(chunk);
this._runParsingLoop();
}
//Hibernation
_ensureHibernation() {
if (this.preprocessor.endOfChunkHit) {
this.preprocessor.retreat(this.consumedAfterSnapshot);
this.consumedAfterSnapshot = 0;
this.active = false;
return true;
}
return false;
}
//Consumption
_consume() {
this.consumedAfterSnapshot++;
return this.preprocessor.advance();
}
_advanceBy(count) {
this.consumedAfterSnapshot += count;
for (let i = 0; i < count; i++) {
this.preprocessor.advance();
}
}
_consumeSequenceIfMatch(pattern, caseSensitive) {
if (this.preprocessor.startsWith(pattern, caseSensitive)) {
this._advanceBy(pattern.length - 1);
return true;
}
return false;
}
//Token creation
_createStartTagToken() {
this.currentToken = {
type: TokenType.START_TAG,
tagName: "",
tagID: TAG_ID.UNKNOWN,
selfClosing: false,
ackSelfClosing: false,
attrs: [],
location: this.getCurrentLocation(1)
};
}
_createEndTagToken() {
this.currentToken = {
type: TokenType.END_TAG,
tagName: "",
tagID: TAG_ID.UNKNOWN,
selfClosing: false,
ackSelfClosing: false,
attrs: [],
location: this.getCurrentLocation(2)
};
}
_createCommentToken(offset) {
this.currentToken = {
type: TokenType.COMMENT,
data: "",
location: this.getCurrentLocation(offset)
};
}
_createDoctypeToken(initialName) {
this.currentToken = {
type: TokenType.DOCTYPE,
name: initialName,
forceQuirks: false,
publicId: null,
systemId: null,
location: this.currentLocation
};
}
_createCharacterToken(type, chars) {
this.currentCharacterToken = {
type,
chars,
location: this.currentLocation
};
}
//Tag attributes
_createAttr(attrNameFirstCh) {
this.currentAttr = {
name: attrNameFirstCh,
value: ""
};
this.currentLocation = this.getCurrentLocation(0);
}
_leaveAttrName() {
var _a2;
var _b;
const token = this.currentToken;
if (getTokenAttr(token, this.currentAttr.name) === null) {
token.attrs.push(this.currentAttr);
if (token.location && this.currentLocation) {
const attrLocations = (_a2 = (_b = token.location).attrs) !== null && _a2 !== void 0 ? _a2 : _b.attrs = /* @__PURE__ */ Object.create(null);
attrLocations[this.currentAttr.name] = this.currentLocation;
this._leaveAttrValue();
}
} else {
this._err(ERR.duplicateAttribute);
}
}
_leaveAttrValue() {
if (this.currentLocation) {
this.currentLocation.endLine = this.preprocessor.line;
this.currentLocation.endCol = this.preprocessor.col;
this.currentLocation.endOffset = this.preprocessor.offset;
}
}
//Token emission
prepareToken(ct) {
this._emitCurrentCharacterToken(ct.location);
this.currentToken = null;
if (ct.location) {
ct.location.endLine = this.preprocessor.line;
ct.location.endCol = this.preprocessor.col + 1;
ct.location.endOffset = this.preprocessor.offset + 1;
}
this.currentLocation = this.getCurrentLocation(-1);
}
emitCurrentTagToken() {
const ct = this.currentToken;
this.prepareToken(ct);
ct.tagID = getTagID(ct.tagName);
if (ct.type === TokenType.START_TAG) {
this.lastStartTagName = ct.tagName;
this.handler.onStartTag(ct);
} else {
if (ct.attrs.length > 0) {
this._err(ERR.endTagWithAttributes);
}
if (ct.selfClosing) {
this._err(ERR.endTagWithTrailingSolidus);
}
this.handler.onEndTag(ct);
}
this.preprocessor.dropParsedChunk();
}
emitCurrentComment(ct) {
this.prepareToken(ct);
this.handler.onComment(ct);
this.preprocessor.dropParsedChunk();
}
emitCurrentDoctype(ct) {
this.prepareToken(ct);
this.handler.onDoctype(ct);
this.preprocessor.dropParsedChunk();
}
_emitCurrentCharacterToken(nextLocation) {
if (this.currentCharacterToken) {
if (nextLocation && this.currentCharacterToken.location) {
this.currentCharacterToken.location.endLine = nextLocation.startLine;
this.currentCharacterToken.location.endCol = nextLocation.startCol;
this.currentCharacterToken.location.endOffset = nextLocation.startOffset;
}
switch (this.currentCharacterToken.type) {
case TokenType.CHARACTER: {
this.handler.onCharacter(this.currentCharacterToken);
break;
}
case TokenType.NULL_CHARACTER: {
this.handler.onNullCharacter(this.currentCharacterToken);
break;
}
case TokenType.WHITESPACE_CHARACTER: {
this.handler.onWhitespaceCharacter(this.currentCharacterToken);
break;
}
}
this.currentCharacterToken = null;
}
}
_emitEOFToken() {
const location2 = this.getCurrentLocation(0);
if (location2) {
location2.endLine = location2.startLine;
location2.endCol = location2.startCol;
location2.endOffset = location2.startOffset;
}
this._emitCurrentCharacterToken(location2);
this.handler.onEof({ type: TokenType.EOF, location: location2 });
this.active = false;
}
//Characters emission
//OPTIMIZATION: The specification uses only one type of character token (one token per character).
//This causes a huge memory overhead and a lot of unnecessary parser loops. parse5 uses 3 groups of characters.
//If we have a sequence of characters that belong to the same group, the parser can process it
//as a single solid character token.
//So, there are 3 types of character tokens in parse5:
//1)TokenType.NULL_CHARACTER - \u0000-character sequences (e.g. '\u0000\u0000\u0000')
//2)TokenType.WHITESPACE_CHARACTER - any whitespace/new-line character sequences (e.g. '\n \r\t \f')
//3)TokenType.CHARACTER - any character sequence which don't belong to groups 1 and 2 (e.g. 'abcdef1234@@#$%^')
_appendCharToCurrentCharacterToken(type, ch) {
if (this.currentCharacterToken) {
if (this.currentCharacterToken.type === type) {
this.currentCharacterToken.chars += ch;
return;
} else {
this.currentLocation = this.getCurrentLocation(0);
this._emitCurrentCharacterToken(this.currentLocation);
this.preprocessor.dropParsedChunk();
}
}
this._createCharacterToken(type, ch);
}
_emitCodePoint(cp) {
const type = isWhitespace(cp) ? TokenType.WHITESPACE_CHARACTER : cp === CODE_POINTS.NULL ? TokenType.NULL_CHARACTER : TokenType.CHARACTER;
this._appendCharToCurrentCharacterToken(type, String.fromCodePoint(cp));
}
//NOTE: used when we emit characters explicitly.
//This is always for non-whitespace and non-null characters, which allows us to avoid additional checks.
_emitChars(ch) {
this._appendCharToCurrentCharacterToken(TokenType.CHARACTER, ch);
}
// Character reference helpers
_startCharacterReference() {
this.returnState = this.state;
this.state = State.CHARACTER_REFERENCE;
this.entityStartPos = this.preprocessor.pos;
this.entityDecoder.startEntity(this._isCharacterReferenceInAttribute() ? DecodingMode.Attribute : DecodingMode.Legacy);
}
_isCharacterReferenceInAttribute() {
return this.returnState === State.ATTRIBUTE_VALUE_DOUBLE_QUOTED || this.returnState === State.ATTRIBUTE_VALUE_SINGLE_QUOTED || this.returnState === State.ATTRIBUTE_VALUE_UNQUOTED;
}
_flushCodePointConsumedAsCharacterReference(cp) {
if (this._isCharacterReferenceInAttribute()) {
this.currentAttr.value += String.fromCodePoint(cp);
} else {
this._emitCodePoint(cp);
}
}
// Calling states this way turns out to be much faster than any other approach.
_callState(cp) {
switch (this.state) {
case State.DATA: {
this._stateData(cp);
break;
}
case State.RCDATA: {
this._stateRcdata(cp);
break;
}
case State.RAWTEXT: {
this._stateRawtext(cp);
break;
}
case State.SCRIPT_DATA: {
this._stateScriptData(cp);
break;
}
case State.PLAINTEXT: {
this._statePlaintext(cp);
break;
}
case State.TAG_OPEN: {
this._stateTagOpen(cp);
break;
}
case State.END_TAG_OPEN: {
this._stateEndTagOpen(cp);
break;
}
case State.TAG_NAME: {
this._stateTagName(cp);
break;
}
case State.RCDATA_LESS_THAN_SIGN: {
this._stateRcdataLessThanSign(cp);
break;
}
case State.RCDATA_END_TAG_OPEN: {
this._stateRcdataEndTagOpen(cp);
break;
}
case State.RCDATA_END_TAG_NAME: {
this._stateRcdataEndTagName(cp);
break;
}
case State.RAWTEXT_LESS_THAN_SIGN: {
this._stateRawtextLessThanSign(cp);
break;
}
case State.RAWTEXT_END_TAG_OPEN: {
this._stateRawtextEndTagOpen(cp);
break;
}
case State.RAWTEXT_END_TAG_NAME: {
this._stateRawtextEndTagName(cp);
break;
}
case State.SCRIPT_DATA_LESS_THAN_SIGN: {
this._stateScriptDataLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_END_TAG_OPEN: {
this._stateScriptDataEndTagOpen(cp);
break;
}
case State.SCRIPT_DATA_END_TAG_NAME: {
this._stateScriptDataEndTagName(cp);
break;
}
case State.SCRIPT_DATA_ESCAPE_START: {
this._stateScriptDataEscapeStart(cp);
break;
}
case State.SCRIPT_DATA_ESCAPE_START_DASH: {
this._stateScriptDataEscapeStartDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED: {
this._stateScriptDataEscaped(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_DASH: {
this._stateScriptDataEscapedDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_DASH_DASH: {
this._stateScriptDataEscapedDashDash(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN: {
this._stateScriptDataEscapedLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN: {
this._stateScriptDataEscapedEndTagOpen(cp);
break;
}
case State.SCRIPT_DATA_ESCAPED_END_TAG_NAME: {
this._stateScriptDataEscapedEndTagName(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPE_START: {
this._stateScriptDataDoubleEscapeStart(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED: {
this._stateScriptDataDoubleEscaped(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH: {
this._stateScriptDataDoubleEscapedDash(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH: {
this._stateScriptDataDoubleEscapedDashDash(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN: {
this._stateScriptDataDoubleEscapedLessThanSign(cp);
break;
}
case State.SCRIPT_DATA_DOUBLE_ESCAPE_END: {
this._stateScriptDataDoubleEscapeEnd(cp);
break;
}
case State.BEFORE_ATTRIBUTE_NAME: {
this._stateBeforeAttributeName(cp);
break;
}
case State.ATTRIBUTE_NAME: {
this._stateAttributeName(cp);
break;
}
case State.AFTER_ATTRIBUTE_NAME: {
this._stateAfterAttributeName(cp);
break;
}
case State.BEFORE_ATTRIBUTE_VALUE: {
this._stateBeforeAttributeValue(cp);
break;
}
case State.ATTRIBUTE_VALUE_DOUBLE_QUOTED: {
this._stateAttributeValueDoubleQuoted(cp);
break;
}
case State.ATTRIBUTE_VALUE_SINGLE_QUOTED: {
this._stateAttributeValueSingleQuoted(cp);
break;
}
case State.ATTRIBUTE_VALUE_UNQUOTED: {
this._stateAttributeValueUnquoted(cp);
break;
}
case State.AFTER_ATTRIBUTE_VALUE_QUOTED: {
this._stateAfterAttributeValueQuoted(cp);
break;
}
case State.SELF_CLOSING_START_TAG: {
this._stateSelfClosingStartTag(cp);
break;
}
case State.BOGUS_COMMENT: {
this._stateBogusComment(cp);
break;
}
case State.MARKUP_DECLARATION_OPEN: {
this._stateMarkupDeclarationOpen(cp);
break;
}
case State.COMMENT_START: {
this._stateCommentStart(cp);
break;
}
case State.COMMENT_START_DASH: {
this._stateCommentStartDash(cp);
break;
}
case State.COMMENT: {
this._stateComment(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN: {
this._stateCommentLessThanSign(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG: {
this._stateCommentLessThanSignBang(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG_DASH: {
this._stateCommentLessThanSignBangDash(cp);
break;
}
case State.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH: {
this._stateCommentLessThanSignBangDashDash(cp);
break;
}
case State.COMMENT_END_DASH: {
this._stateCommentEndDash(cp);
break;
}
case State.COMMENT_END: {
this._stateCommentEnd(cp);
break;
}
case State.COMMENT_END_BANG: {
this._stateCommentEndBang(cp);
break;
}
case State.DOCTYPE: {
this._stateDoctype(cp);
break;
}
case State.BEFORE_DOCTYPE_NAME: {
this._stateBeforeDoctypeName(cp);
break;
}
case State.DOCTYPE_NAME: {
this._stateDoctypeName(cp);
break;
}
case State.AFTER_DOCTYPE_NAME: {
this._stateAfterDoctypeName(cp);
break;
}
case State.AFTER_DOCTYPE_PUBLIC_KEYWORD: {
this._stateAfterDoctypePublicKeyword(cp);
break;
}
case State.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER: {
this._stateBeforeDoctypePublicIdentifier(cp);
break;
}
case State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED: {
this._stateDoctypePublicIdentifierDoubleQuoted(cp);
break;
}
case State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED: {
this._stateDoctypePublicIdentifierSingleQuoted(cp);
break;
}
case State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER: {
this._stateAfterDoctypePublicIdentifier(cp);
break;
}
case State.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS: {
this._stateBetweenDoctypePublicAndSystemIdentifiers(cp);
break;
}
case State.AFTER_DOCTYPE_SYSTEM_KEYWORD: {
this._stateAfterDoctypeSystemKeyword(cp);
break;
}
case State.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER: {
this._stateBeforeDoctypeSystemIdentifier(cp);
break;
}
case State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED: {
this._stateDoctypeSystemIdentifierDoubleQuoted(cp);
break;
}
case State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED: {
this._stateDoctypeSystemIdentifierSingleQuoted(cp);
break;
}
case State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER: {
this._stateAfterDoctypeSystemIdentifier(cp);
break;
}
case State.BOGUS_DOCTYPE: {
this._stateBogusDoctype(cp);
break;
}
case State.CDATA_SECTION: {
this._stateCdataSection(cp);
break;
}
case State.CDATA_SECTION_BRACKET: {
this._stateCdataSectionBracket(cp);
break;
}
case State.CDATA_SECTION_END: {
this._stateCdataSectionEnd(cp);
break;
}
case State.CHARACTER_REFERENCE: {
this._stateCharacterReference();
break;
}
case State.AMBIGUOUS_AMPERSAND: {
this._stateAmbiguousAmpersand(cp);
break;
}
default: {
throw new Error("Unknown state");
}
}
}
// State machine
// Data state
//------------------------------------------------------------------
_stateData(cp) {
switch (cp) {
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.TAG_OPEN;
break;
}
case CODE_POINTS.AMPERSAND: {
this._startCharacterReference();
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitCodePoint(cp);
break;
}
case CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// RCDATA state
//------------------------------------------------------------------
_stateRcdata(cp) {
switch (cp) {
case CODE_POINTS.AMPERSAND: {
this._startCharacterReference();
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.RCDATA_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// RAWTEXT state
//------------------------------------------------------------------
_stateRawtext(cp) {
switch (cp) {
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.RAWTEXT_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data state
//------------------------------------------------------------------
_stateScriptData(cp) {
switch (cp) {
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// PLAINTEXT state
//------------------------------------------------------------------
_statePlaintext(cp) {
switch (cp) {
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Tag open state
//------------------------------------------------------------------
_stateTagOpen(cp) {
if (isAsciiLetter(cp)) {
this._createStartTagToken();
this.state = State.TAG_NAME;
this._stateTagName(cp);
} else
switch (cp) {
case CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.MARKUP_DECLARATION_OPEN;
break;
}
case CODE_POINTS.SOLIDUS: {
this.state = State.END_TAG_OPEN;
break;
}
case CODE_POINTS.QUESTION_MARK: {
this._err(ERR.unexpectedQuestionMarkInsteadOfTagName);
this._createCommentToken(1);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofBeforeTagName);
this._emitChars("<");
this._emitEOFToken();
break;
}
default: {
this._err(ERR.invalidFirstCharacterOfTagName);
this._emitChars("<");
this.state = State.DATA;
this._stateData(cp);
}
}
}
// End tag open state
//------------------------------------------------------------------
_stateEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this._createEndTagToken();
this.state = State.TAG_NAME;
this._stateTagName(cp);
} else
switch (cp) {
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingEndTagName);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofBeforeTagName);
this._emitChars("</");
this._emitEOFToken();
break;
}
default: {
this._err(ERR.invalidFirstCharacterOfTagName);
this._createCommentToken(2);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
}
}
}
// Tag name state
//------------------------------------------------------------------
_stateTagName(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case CODE_POINTS.SOLIDUS: {
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.tagName += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
token.tagName += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// RCDATA less-than sign state
//------------------------------------------------------------------
_stateRcdataLessThanSign(cp) {
if (cp === CODE_POINTS.SOLIDUS) {
this.state = State.RCDATA_END_TAG_OPEN;
} else {
this._emitChars("<");
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
// RCDATA end tag open state
//------------------------------------------------------------------
_stateRcdataEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.RCDATA_END_TAG_NAME;
this._stateRcdataEndTagName(cp);
} else {
this._emitChars("</");
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
handleSpecialEndTag(_cp) {
if (!this.preprocessor.startsWith(this.lastStartTagName, false)) {
return !this._ensureHibernation();
}
this._createEndTagToken();
const token = this.currentToken;
token.tagName = this.lastStartTagName;
const cp = this.preprocessor.peek(this.lastStartTagName.length);
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this._advanceBy(this.lastStartTagName.length);
this.state = State.BEFORE_ATTRIBUTE_NAME;
return false;
}
case CODE_POINTS.SOLIDUS: {
this._advanceBy(this.lastStartTagName.length);
this.state = State.SELF_CLOSING_START_TAG;
return false;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._advanceBy(this.lastStartTagName.length);
this.emitCurrentTagToken();
this.state = State.DATA;
return false;
}
default: {
return !this._ensureHibernation();
}
}
}
// RCDATA end tag name state
//------------------------------------------------------------------
_stateRcdataEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars("</");
this.state = State.RCDATA;
this._stateRcdata(cp);
}
}
// RAWTEXT less-than sign state
//------------------------------------------------------------------
_stateRawtextLessThanSign(cp) {
if (cp === CODE_POINTS.SOLIDUS) {
this.state = State.RAWTEXT_END_TAG_OPEN;
} else {
this._emitChars("<");
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// RAWTEXT end tag open state
//------------------------------------------------------------------
_stateRawtextEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.RAWTEXT_END_TAG_NAME;
this._stateRawtextEndTagName(cp);
} else {
this._emitChars("</");
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// RAWTEXT end tag name state
//------------------------------------------------------------------
_stateRawtextEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars("</");
this.state = State.RAWTEXT;
this._stateRawtext(cp);
}
}
// Script data less-than sign state
//------------------------------------------------------------------
_stateScriptDataLessThanSign(cp) {
switch (cp) {
case CODE_POINTS.SOLIDUS: {
this.state = State.SCRIPT_DATA_END_TAG_OPEN;
break;
}
case CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.SCRIPT_DATA_ESCAPE_START;
this._emitChars("<!");
break;
}
default: {
this._emitChars("<");
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
}
// Script data end tag open state
//------------------------------------------------------------------
_stateScriptDataEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.SCRIPT_DATA_END_TAG_NAME;
this._stateScriptDataEndTagName(cp);
} else {
this._emitChars("</");
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data end tag name state
//------------------------------------------------------------------
_stateScriptDataEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars("</");
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escape start state
//------------------------------------------------------------------
_stateScriptDataEscapeStart(cp) {
if (cp === CODE_POINTS.HYPHEN_MINUS) {
this.state = State.SCRIPT_DATA_ESCAPE_START_DASH;
this._emitChars("-");
} else {
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escape start dash state
//------------------------------------------------------------------
_stateScriptDataEscapeStartDash(cp) {
if (cp === CODE_POINTS.HYPHEN_MINUS) {
this.state = State.SCRIPT_DATA_ESCAPED_DASH_DASH;
this._emitChars("-");
} else {
this.state = State.SCRIPT_DATA;
this._stateScriptData(cp);
}
}
// Script data escaped state
//------------------------------------------------------------------
_stateScriptDataEscaped(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_ESCAPED_DASH;
this._emitChars("-");
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data escaped dash state
//------------------------------------------------------------------
_stateScriptDataEscapedDash(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_ESCAPED_DASH_DASH;
this._emitChars("-");
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data escaped dash dash state
//------------------------------------------------------------------
_stateScriptDataEscapedDashDash(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this._emitChars("-");
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_ESCAPED_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.SCRIPT_DATA;
this._emitChars(">");
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data escaped less-than sign state
//------------------------------------------------------------------
_stateScriptDataEscapedLessThanSign(cp) {
if (cp === CODE_POINTS.SOLIDUS) {
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_OPEN;
} else if (isAsciiLetter(cp)) {
this._emitChars("<");
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_START;
this._stateScriptDataDoubleEscapeStart(cp);
} else {
this._emitChars("<");
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data escaped end tag open state
//------------------------------------------------------------------
_stateScriptDataEscapedEndTagOpen(cp) {
if (isAsciiLetter(cp)) {
this.state = State.SCRIPT_DATA_ESCAPED_END_TAG_NAME;
this._stateScriptDataEscapedEndTagName(cp);
} else {
this._emitChars("</");
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data escaped end tag name state
//------------------------------------------------------------------
_stateScriptDataEscapedEndTagName(cp) {
if (this.handleSpecialEndTag(cp)) {
this._emitChars("</");
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data double escape start state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapeStart(cp) {
if (this.preprocessor.startsWith(SEQUENCES.SCRIPT, false) && isScriptDataDoubleEscapeSequenceEnd(this.preprocessor.peek(SEQUENCES.SCRIPT.length))) {
this._emitCodePoint(cp);
for (let i = 0; i < SEQUENCES.SCRIPT.length; i++) {
this._emitCodePoint(this._consume());
}
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
} else if (!this._ensureHibernation()) {
this.state = State.SCRIPT_DATA_ESCAPED;
this._stateScriptDataEscaped(cp);
}
}
// Script data double escaped state
//------------------------------------------------------------------
_stateScriptDataDoubleEscaped(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH;
this._emitChars("-");
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars("<");
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// Script data double escaped dash state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedDash(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_DASH_DASH;
this._emitChars("-");
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars("<");
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data double escaped dash dash state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedDashDash(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this._emitChars("-");
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED_LESS_THAN_SIGN;
this._emitChars("<");
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.SCRIPT_DATA;
this._emitChars(">");
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitChars(REPLACEMENT_CHARACTER);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInScriptHtmlCommentLikeText);
this._emitEOFToken();
break;
}
default: {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._emitCodePoint(cp);
}
}
}
// Script data double escaped less-than sign state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapedLessThanSign(cp) {
if (cp === CODE_POINTS.SOLIDUS) {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPE_END;
this._emitChars("/");
} else {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._stateScriptDataDoubleEscaped(cp);
}
}
// Script data double escape end state
//------------------------------------------------------------------
_stateScriptDataDoubleEscapeEnd(cp) {
if (this.preprocessor.startsWith(SEQUENCES.SCRIPT, false) && isScriptDataDoubleEscapeSequenceEnd(this.preprocessor.peek(SEQUENCES.SCRIPT.length))) {
this._emitCodePoint(cp);
for (let i = 0; i < SEQUENCES.SCRIPT.length; i++) {
this._emitCodePoint(this._consume());
}
this.state = State.SCRIPT_DATA_ESCAPED;
} else if (!this._ensureHibernation()) {
this.state = State.SCRIPT_DATA_DOUBLE_ESCAPED;
this._stateScriptDataDoubleEscaped(cp);
}
}
// Before attribute name state
//------------------------------------------------------------------
_stateBeforeAttributeName(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.SOLIDUS:
case CODE_POINTS.GREATER_THAN_SIGN:
case CODE_POINTS.EOF: {
this.state = State.AFTER_ATTRIBUTE_NAME;
this._stateAfterAttributeName(cp);
break;
}
case CODE_POINTS.EQUALS_SIGN: {
this._err(ERR.unexpectedEqualsSignBeforeAttributeName);
this._createAttr("=");
this.state = State.ATTRIBUTE_NAME;
break;
}
default: {
this._createAttr("");
this.state = State.ATTRIBUTE_NAME;
this._stateAttributeName(cp);
}
}
}
// Attribute name state
//------------------------------------------------------------------
_stateAttributeName(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED:
case CODE_POINTS.SOLIDUS:
case CODE_POINTS.GREATER_THAN_SIGN:
case CODE_POINTS.EOF: {
this._leaveAttrName();
this.state = State.AFTER_ATTRIBUTE_NAME;
this._stateAfterAttributeName(cp);
break;
}
case CODE_POINTS.EQUALS_SIGN: {
this._leaveAttrName();
this.state = State.BEFORE_ATTRIBUTE_VALUE;
break;
}
case CODE_POINTS.QUOTATION_MARK:
case CODE_POINTS.APOSTROPHE:
case CODE_POINTS.LESS_THAN_SIGN: {
this._err(ERR.unexpectedCharacterInAttributeName);
this.currentAttr.name += String.fromCodePoint(cp);
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.currentAttr.name += REPLACEMENT_CHARACTER;
break;
}
default: {
this.currentAttr.name += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// After attribute name state
//------------------------------------------------------------------
_stateAfterAttributeName(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.SOLIDUS: {
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case CODE_POINTS.EQUALS_SIGN: {
this.state = State.BEFORE_ATTRIBUTE_VALUE;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._createAttr("");
this.state = State.ATTRIBUTE_NAME;
this._stateAttributeName(cp);
}
}
}
// Before attribute value state
//------------------------------------------------------------------
_stateBeforeAttributeValue(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.QUOTATION_MARK: {
this.state = State.ATTRIBUTE_VALUE_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
this.state = State.ATTRIBUTE_VALUE_SINGLE_QUOTED;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingAttributeValue);
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
default: {
this.state = State.ATTRIBUTE_VALUE_UNQUOTED;
this._stateAttributeValueUnquoted(cp);
}
}
}
// Attribute value (double-quoted) state
//------------------------------------------------------------------
_stateAttributeValueDoubleQuoted(cp) {
switch (cp) {
case CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_ATTRIBUTE_VALUE_QUOTED;
break;
}
case CODE_POINTS.AMPERSAND: {
this._startCharacterReference();
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.currentAttr.value += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// Attribute value (single-quoted) state
//------------------------------------------------------------------
_stateAttributeValueSingleQuoted(cp) {
switch (cp) {
case CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_ATTRIBUTE_VALUE_QUOTED;
break;
}
case CODE_POINTS.AMPERSAND: {
this._startCharacterReference();
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.currentAttr.value += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// Attribute value (unquoted) state
//------------------------------------------------------------------
_stateAttributeValueUnquoted(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this._leaveAttrValue();
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case CODE_POINTS.AMPERSAND: {
this._startCharacterReference();
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._leaveAttrValue();
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this.currentAttr.value += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.QUOTATION_MARK:
case CODE_POINTS.APOSTROPHE:
case CODE_POINTS.LESS_THAN_SIGN:
case CODE_POINTS.EQUALS_SIGN:
case CODE_POINTS.GRAVE_ACCENT: {
this._err(ERR.unexpectedCharacterInUnquotedAttributeValue);
this.currentAttr.value += String.fromCodePoint(cp);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this.currentAttr.value += String.fromCodePoint(cp);
}
}
}
// After attribute value (quoted) state
//------------------------------------------------------------------
_stateAfterAttributeValueQuoted(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this._leaveAttrValue();
this.state = State.BEFORE_ATTRIBUTE_NAME;
break;
}
case CODE_POINTS.SOLIDUS: {
this._leaveAttrValue();
this.state = State.SELF_CLOSING_START_TAG;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._leaveAttrValue();
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingWhitespaceBetweenAttributes);
this.state = State.BEFORE_ATTRIBUTE_NAME;
this._stateBeforeAttributeName(cp);
}
}
}
// Self-closing start tag state
//------------------------------------------------------------------
_stateSelfClosingStartTag(cp) {
switch (cp) {
case CODE_POINTS.GREATER_THAN_SIGN: {
const token = this.currentToken;
token.selfClosing = true;
this.state = State.DATA;
this.emitCurrentTagToken();
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInTag);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.unexpectedSolidusInTag);
this.state = State.BEFORE_ATTRIBUTE_NAME;
this._stateBeforeAttributeName(cp);
}
}
}
// Bogus comment state
//------------------------------------------------------------------
_stateBogusComment(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case CODE_POINTS.EOF: {
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.data += REPLACEMENT_CHARACTER;
break;
}
default: {
token.data += String.fromCodePoint(cp);
}
}
}
// Markup declaration open state
//------------------------------------------------------------------
_stateMarkupDeclarationOpen(cp) {
if (this._consumeSequenceIfMatch(SEQUENCES.DASH_DASH, true)) {
this._createCommentToken(SEQUENCES.DASH_DASH.length + 1);
this.state = State.COMMENT_START;
} else if (this._consumeSequenceIfMatch(SEQUENCES.DOCTYPE, false)) {
this.currentLocation = this.getCurrentLocation(SEQUENCES.DOCTYPE.length + 1);
this.state = State.DOCTYPE;
} else if (this._consumeSequenceIfMatch(SEQUENCES.CDATA_START, true)) {
if (this.inForeignNode) {
this.state = State.CDATA_SECTION;
} else {
this._err(ERR.cdataInHtmlContent);
this._createCommentToken(SEQUENCES.CDATA_START.length + 1);
this.currentToken.data = "[CDATA[";
this.state = State.BOGUS_COMMENT;
}
} else if (!this._ensureHibernation()) {
this._err(ERR.incorrectlyOpenedComment);
this._createCommentToken(2);
this.state = State.BOGUS_COMMENT;
this._stateBogusComment(cp);
}
}
// Comment start state
//------------------------------------------------------------------
_stateCommentStart(cp) {
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_START_DASH;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.abruptClosingOfEmptyComment);
this.state = State.DATA;
const token = this.currentToken;
this.emitCurrentComment(token);
break;
}
default: {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment start dash state
//------------------------------------------------------------------
_stateCommentStartDash(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.abruptClosingOfEmptyComment);
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += "-";
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment state
//------------------------------------------------------------------
_stateComment(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END_DASH;
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
token.data += "<";
this.state = State.COMMENT_LESS_THAN_SIGN;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.data += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += String.fromCodePoint(cp);
}
}
}
// Comment less-than sign state
//------------------------------------------------------------------
_stateCommentLessThanSign(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.EXCLAMATION_MARK: {
token.data += "!";
this.state = State.COMMENT_LESS_THAN_SIGN_BANG;
break;
}
case CODE_POINTS.LESS_THAN_SIGN: {
token.data += "<";
break;
}
default: {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment less-than sign bang state
//------------------------------------------------------------------
_stateCommentLessThanSignBang(cp) {
if (cp === CODE_POINTS.HYPHEN_MINUS) {
this.state = State.COMMENT_LESS_THAN_SIGN_BANG_DASH;
} else {
this.state = State.COMMENT;
this._stateComment(cp);
}
}
// Comment less-than sign bang dash state
//------------------------------------------------------------------
_stateCommentLessThanSignBangDash(cp) {
if (cp === CODE_POINTS.HYPHEN_MINUS) {
this.state = State.COMMENT_LESS_THAN_SIGN_BANG_DASH_DASH;
} else {
this.state = State.COMMENT_END_DASH;
this._stateCommentEndDash(cp);
}
}
// Comment less-than sign bang dash dash state
//------------------------------------------------------------------
_stateCommentLessThanSignBangDashDash(cp) {
if (cp !== CODE_POINTS.GREATER_THAN_SIGN && cp !== CODE_POINTS.EOF) {
this._err(ERR.nestedComment);
}
this.state = State.COMMENT_END;
this._stateCommentEnd(cp);
}
// Comment end dash state
//------------------------------------------------------------------
_stateCommentEndDash(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
this.state = State.COMMENT_END;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += "-";
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment end state
//------------------------------------------------------------------
_stateCommentEnd(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case CODE_POINTS.EXCLAMATION_MARK: {
this.state = State.COMMENT_END_BANG;
break;
}
case CODE_POINTS.HYPHEN_MINUS: {
token.data += "-";
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += "--";
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// Comment end bang state
//------------------------------------------------------------------
_stateCommentEndBang(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.HYPHEN_MINUS: {
token.data += "--!";
this.state = State.COMMENT_END_DASH;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.incorrectlyClosedComment);
this.state = State.DATA;
this.emitCurrentComment(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInComment);
this.emitCurrentComment(token);
this._emitEOFToken();
break;
}
default: {
token.data += "--!";
this.state = State.COMMENT;
this._stateComment(cp);
}
}
}
// DOCTYPE state
//------------------------------------------------------------------
_stateDoctype(cp) {
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_NAME;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.BEFORE_DOCTYPE_NAME;
this._stateBeforeDoctypeName(cp);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingWhitespaceBeforeDoctypeName);
this.state = State.BEFORE_DOCTYPE_NAME;
this._stateBeforeDoctypeName(cp);
}
}
}
// Before DOCTYPE name state
//------------------------------------------------------------------
_stateBeforeDoctypeName(cp) {
if (isAsciiUpper(cp)) {
this._createDoctypeToken(String.fromCharCode(toAsciiLower(cp)));
this.state = State.DOCTYPE_NAME;
} else
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
this._createDoctypeToken(REPLACEMENT_CHARACTER);
this.state = State.DOCTYPE_NAME;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingDoctypeName);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
this._createDoctypeToken(null);
const token = this.currentToken;
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._createDoctypeToken(String.fromCodePoint(cp));
this.state = State.DOCTYPE_NAME;
}
}
}
// DOCTYPE name state
//------------------------------------------------------------------
_stateDoctypeName(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this.state = State.AFTER_DOCTYPE_NAME;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.name += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.name += String.fromCodePoint(isAsciiUpper(cp) ? toAsciiLower(cp) : cp);
}
}
}
// After DOCTYPE name state
//------------------------------------------------------------------
_stateAfterDoctypeName(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
if (this._consumeSequenceIfMatch(SEQUENCES.PUBLIC, false)) {
this.state = State.AFTER_DOCTYPE_PUBLIC_KEYWORD;
} else if (this._consumeSequenceIfMatch(SEQUENCES.SYSTEM, false)) {
this.state = State.AFTER_DOCTYPE_SYSTEM_KEYWORD;
} else if (!this._ensureHibernation()) {
this._err(ERR.invalidCharacterSequenceAfterDoctypeName);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
}
// After DOCTYPE public keyword state
//------------------------------------------------------------------
_stateAfterDoctypePublicKeyword(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case CODE_POINTS.QUOTATION_MARK: {
this._err(ERR.missingWhitespaceAfterDoctypePublicKeyword);
token.publicId = "";
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
this._err(ERR.missingWhitespaceAfterDoctypePublicKeyword);
token.publicId = "";
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingQuoteBeforeDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Before DOCTYPE public identifier state
//------------------------------------------------------------------
_stateBeforeDoctypePublicIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.QUOTATION_MARK: {
token.publicId = "";
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
token.publicId = "";
this.state = State.DOCTYPE_PUBLIC_IDENTIFIER_SINGLE_QUOTED;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingQuoteBeforeDoctypePublicIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// DOCTYPE public identifier (double-quoted) state
//------------------------------------------------------------------
_stateDoctypePublicIdentifierDoubleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.publicId += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.abruptDoctypePublicIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.publicId += String.fromCodePoint(cp);
}
}
}
// DOCTYPE public identifier (single-quoted) state
//------------------------------------------------------------------
_stateDoctypePublicIdentifierSingleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_DOCTYPE_PUBLIC_IDENTIFIER;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.publicId += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.abruptDoctypePublicIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.publicId += String.fromCodePoint(cp);
}
}
}
// After DOCTYPE public identifier state
//------------------------------------------------------------------
_stateAfterDoctypePublicIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this.state = State.BETWEEN_DOCTYPE_PUBLIC_AND_SYSTEM_IDENTIFIERS;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.QUOTATION_MARK: {
this._err(ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
this._err(ERR.missingWhitespaceBetweenDoctypePublicAndSystemIdentifiers);
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Between DOCTYPE public and system identifiers state
//------------------------------------------------------------------
_stateBetweenDoctypePublicAndSystemIdentifiers(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.QUOTATION_MARK: {
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// After DOCTYPE system keyword state
//------------------------------------------------------------------
_stateAfterDoctypeSystemKeyword(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
this.state = State.BEFORE_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case CODE_POINTS.QUOTATION_MARK: {
this._err(ERR.missingWhitespaceAfterDoctypeSystemKeyword);
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
this._err(ERR.missingWhitespaceAfterDoctypeSystemKeyword);
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Before DOCTYPE system identifier state
//------------------------------------------------------------------
_stateBeforeDoctypeSystemIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.QUOTATION_MARK: {
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_DOUBLE_QUOTED;
break;
}
case CODE_POINTS.APOSTROPHE: {
token.systemId = "";
this.state = State.DOCTYPE_SYSTEM_IDENTIFIER_SINGLE_QUOTED;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.missingDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.DATA;
this.emitCurrentDoctype(token);
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.missingQuoteBeforeDoctypeSystemIdentifier);
token.forceQuirks = true;
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// DOCTYPE system identifier (double-quoted) state
//------------------------------------------------------------------
_stateDoctypeSystemIdentifierDoubleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.QUOTATION_MARK: {
this.state = State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.systemId += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.abruptDoctypeSystemIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.systemId += String.fromCodePoint(cp);
}
}
}
// DOCTYPE system identifier (single-quoted) state
//------------------------------------------------------------------
_stateDoctypeSystemIdentifierSingleQuoted(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.APOSTROPHE: {
this.state = State.AFTER_DOCTYPE_SYSTEM_IDENTIFIER;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
token.systemId += REPLACEMENT_CHARACTER;
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this._err(ERR.abruptDoctypeSystemIdentifier);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
token.systemId += String.fromCodePoint(cp);
}
}
}
// After DOCTYPE system identifier state
//------------------------------------------------------------------
_stateAfterDoctypeSystemIdentifier(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.SPACE:
case CODE_POINTS.LINE_FEED:
case CODE_POINTS.TABULATION:
case CODE_POINTS.FORM_FEED: {
break;
}
case CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInDoctype);
token.forceQuirks = true;
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default: {
this._err(ERR.unexpectedCharacterAfterDoctypeSystemIdentifier);
this.state = State.BOGUS_DOCTYPE;
this._stateBogusDoctype(cp);
}
}
}
// Bogus DOCTYPE state
//------------------------------------------------------------------
_stateBogusDoctype(cp) {
const token = this.currentToken;
switch (cp) {
case CODE_POINTS.GREATER_THAN_SIGN: {
this.emitCurrentDoctype(token);
this.state = State.DATA;
break;
}
case CODE_POINTS.NULL: {
this._err(ERR.unexpectedNullCharacter);
break;
}
case CODE_POINTS.EOF: {
this.emitCurrentDoctype(token);
this._emitEOFToken();
break;
}
default:
}
}
// CDATA section state
//------------------------------------------------------------------
_stateCdataSection(cp) {
switch (cp) {
case CODE_POINTS.RIGHT_SQUARE_BRACKET: {
this.state = State.CDATA_SECTION_BRACKET;
break;
}
case CODE_POINTS.EOF: {
this._err(ERR.eofInCdata);
this._emitEOFToken();
break;
}
default: {
this._emitCodePoint(cp);
}
}
}
// CDATA section bracket state
//------------------------------------------------------------------
_stateCdataSectionBracket(cp) {
if (cp === CODE_POINTS.RIGHT_SQUARE_BRACKET) {
this.state = State.CDATA_SECTION_END;
} else {
this._emitChars("]");
this.state = State.CDATA_SECTION;
this._stateCdataSection(cp);
}
}
// CDATA section end state
//------------------------------------------------------------------
_stateCdataSectionEnd(cp) {
switch (cp) {
case CODE_POINTS.GREATER_THAN_SIGN: {
this.state = State.DATA;
break;
}
case CODE_POINTS.RIGHT_SQUARE_BRACKET: {
this._emitChars("]");
break;
}
default: {
this._emitChars("]]");
this.state = State.CDATA_SECTION;
this._stateCdataSection(cp);
}
}
}
// Character reference state
//------------------------------------------------------------------
_stateCharacterReference() {
let length = this.entityDecoder.write(this.preprocessor.html, this.preprocessor.pos);
if (length < 0) {
if (this.preprocessor.lastChunkWritten) {
length = this.entityDecoder.end();
} else {
this.active = false;
this.preprocessor.pos = this.preprocessor.html.length - 1;
this.consumedAfterSnapshot = 0;
this.preprocessor.endOfChunkHit = true;
return;
}
}
if (length === 0) {
this.preprocessor.pos = this.entityStartPos;
this._flushCodePointConsumedAsCharacterReference(CODE_POINTS.AMPERSAND);
this.state = !this._isCharacterReferenceInAttribute() && isAsciiAlphaNumeric2(this.preprocessor.peek(1)) ? State.AMBIGUOUS_AMPERSAND : this.returnState;
} else {
this.state = this.returnState;
}
}
// Ambiguos ampersand state
//------------------------------------------------------------------
_stateAmbiguousAmpersand(cp) {
if (isAsciiAlphaNumeric2(cp)) {
this._flushCodePointConsumedAsCharacterReference(cp);
} else {
if (cp === CODE_POINTS.SEMICOLON) {
this._err(ERR.unknownNamedCharacterReference);
}
this.state = this.returnState;
this._callState(cp);
}
}
};
// node_modules/parse5/dist/parser/open-element-stack.js
var IMPLICIT_END_TAG_REQUIRED = /* @__PURE__ */ new Set([TAG_ID.DD, TAG_ID.DT, TAG_ID.LI, TAG_ID.OPTGROUP, TAG_ID.OPTION, TAG_ID.P, TAG_ID.RB, TAG_ID.RP, TAG_ID.RT, TAG_ID.RTC]);
var IMPLICIT_END_TAG_REQUIRED_THOROUGHLY = /* @__PURE__ */ new Set([
...IMPLICIT_END_TAG_REQUIRED,
TAG_ID.CAPTION,
TAG_ID.COLGROUP,
TAG_ID.TBODY,
TAG_ID.TD,
TAG_ID.TFOOT,
TAG_ID.TH,
TAG_ID.THEAD,
TAG_ID.TR
]);
var SCOPING_ELEMENTS_HTML = /* @__PURE__ */ new Set([
TAG_ID.APPLET,
TAG_ID.CAPTION,
TAG_ID.HTML,
TAG_ID.MARQUEE,
TAG_ID.OBJECT,
TAG_ID.TABLE,
TAG_ID.TD,
TAG_ID.TEMPLATE,
TAG_ID.TH
]);
var SCOPING_ELEMENTS_HTML_LIST = /* @__PURE__ */ new Set([...SCOPING_ELEMENTS_HTML, TAG_ID.OL, TAG_ID.UL]);
var SCOPING_ELEMENTS_HTML_BUTTON = /* @__PURE__ */ new Set([...SCOPING_ELEMENTS_HTML, TAG_ID.BUTTON]);
var SCOPING_ELEMENTS_MATHML = /* @__PURE__ */ new Set([TAG_ID.ANNOTATION_XML, TAG_ID.MI, TAG_ID.MN, TAG_ID.MO, TAG_ID.MS, TAG_ID.MTEXT]);
var SCOPING_ELEMENTS_SVG = /* @__PURE__ */ new Set([TAG_ID.DESC, TAG_ID.FOREIGN_OBJECT, TAG_ID.TITLE]);
var TABLE_ROW_CONTEXT = /* @__PURE__ */ new Set([TAG_ID.TR, TAG_ID.TEMPLATE, TAG_ID.HTML]);
var TABLE_BODY_CONTEXT = /* @__PURE__ */ new Set([TAG_ID.TBODY, TAG_ID.TFOOT, TAG_ID.THEAD, TAG_ID.TEMPLATE, TAG_ID.HTML]);
var TABLE_CONTEXT = /* @__PURE__ */ new Set([TAG_ID.TABLE, TAG_ID.TEMPLATE, TAG_ID.HTML]);
var TABLE_CELLS = /* @__PURE__ */ new Set([TAG_ID.TD, TAG_ID.TH]);
var OpenElementStack = class {
get currentTmplContentOrNode() {
return this._isInTemplate() ? this.treeAdapter.getTemplateContent(this.current) : this.current;
}
constructor(document2, treeAdapter, handler) {
this.treeAdapter = treeAdapter;
this.handler = handler;
this.items = [];
this.tagIDs = [];
this.stackTop = -1;
this.tmplCount = 0;
this.currentTagId = TAG_ID.UNKNOWN;
this.current = document2;
}
//Index of element
_indexOf(element) {
return this.items.lastIndexOf(element, this.stackTop);
}
//Update current element
_isInTemplate() {
return this.currentTagId === TAG_ID.TEMPLATE && this.treeAdapter.getNamespaceURI(this.current) === NS.HTML;
}
_updateCurrentElement() {
this.current = this.items[this.stackTop];
this.currentTagId = this.tagIDs[this.stackTop];
}
//Mutations
push(element, tagID) {
this.stackTop++;
this.items[this.stackTop] = element;
this.current = element;
this.tagIDs[this.stackTop] = tagID;
this.currentTagId = tagID;
if (this._isInTemplate()) {
this.tmplCount++;
}
this.handler.onItemPush(element, tagID, true);
}
pop() {
const popped = this.current;
if (this.tmplCount > 0 && this._isInTemplate()) {
this.tmplCount--;
}
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(popped, true);
}
replace(oldElement, newElement) {
const idx = this._indexOf(oldElement);
this.items[idx] = newElement;
if (idx === this.stackTop) {
this.current = newElement;
}
}
insertAfter(referenceElement, newElement, newElementID) {
const insertionIdx = this._indexOf(referenceElement) + 1;
this.items.splice(insertionIdx, 0, newElement);
this.tagIDs.splice(insertionIdx, 0, newElementID);
this.stackTop++;
if (insertionIdx === this.stackTop) {
this._updateCurrentElement();
}
this.handler.onItemPush(this.current, this.currentTagId, insertionIdx === this.stackTop);
}
popUntilTagNamePopped(tagName) {
let targetIdx = this.stackTop + 1;
do {
targetIdx = this.tagIDs.lastIndexOf(tagName, targetIdx - 1);
} while (targetIdx > 0 && this.treeAdapter.getNamespaceURI(this.items[targetIdx]) !== NS.HTML);
this.shortenToLength(targetIdx < 0 ? 0 : targetIdx);
}
shortenToLength(idx) {
while (this.stackTop >= idx) {
const popped = this.current;
if (this.tmplCount > 0 && this._isInTemplate()) {
this.tmplCount -= 1;
}
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(popped, this.stackTop < idx);
}
}
popUntilElementPopped(element) {
const idx = this._indexOf(element);
this.shortenToLength(idx < 0 ? 0 : idx);
}
popUntilPopped(tagNames, targetNS) {
const idx = this._indexOfTagNames(tagNames, targetNS);
this.shortenToLength(idx < 0 ? 0 : idx);
}
popUntilNumberedHeaderPopped() {
this.popUntilPopped(NUMBERED_HEADERS, NS.HTML);
}
popUntilTableCellPopped() {
this.popUntilPopped(TABLE_CELLS, NS.HTML);
}
popAllUpToHtmlElement() {
this.tmplCount = 0;
this.shortenToLength(1);
}
_indexOfTagNames(tagNames, namespace) {
for (let i = this.stackTop; i >= 0; i--) {
if (tagNames.has(this.tagIDs[i]) && this.treeAdapter.getNamespaceURI(this.items[i]) === namespace) {
return i;
}
}
return -1;
}
clearBackTo(tagNames, targetNS) {
const idx = this._indexOfTagNames(tagNames, targetNS);
this.shortenToLength(idx + 1);
}
clearBackToTableContext() {
this.clearBackTo(TABLE_CONTEXT, NS.HTML);
}
clearBackToTableBodyContext() {
this.clearBackTo(TABLE_BODY_CONTEXT, NS.HTML);
}
clearBackToTableRowContext() {
this.clearBackTo(TABLE_ROW_CONTEXT, NS.HTML);
}
remove(element) {
const idx = this._indexOf(element);
if (idx >= 0) {
if (idx === this.stackTop) {
this.pop();
} else {
this.items.splice(idx, 1);
this.tagIDs.splice(idx, 1);
this.stackTop--;
this._updateCurrentElement();
this.handler.onItemPop(element, false);
}
}
}
//Search
tryPeekProperlyNestedBodyElement() {
return this.stackTop >= 1 && this.tagIDs[1] === TAG_ID.BODY ? this.items[1] : null;
}
contains(element) {
return this._indexOf(element) > -1;
}
getCommonAncestor(element) {
const elementIdx = this._indexOf(element) - 1;
return elementIdx >= 0 ? this.items[elementIdx] : null;
}
isRootHtmlElementCurrent() {
return this.stackTop === 0 && this.tagIDs[0] === TAG_ID.HTML;
}
//Element in scope
hasInDynamicScope(tagName, htmlScope) {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
switch (this.treeAdapter.getNamespaceURI(this.items[i])) {
case NS.HTML: {
if (tn === tagName)
return true;
if (htmlScope.has(tn))
return false;
break;
}
case NS.SVG: {
if (SCOPING_ELEMENTS_SVG.has(tn))
return false;
break;
}
case NS.MATHML: {
if (SCOPING_ELEMENTS_MATHML.has(tn))
return false;
break;
}
}
}
return true;
}
hasInScope(tagName) {
return this.hasInDynamicScope(tagName, SCOPING_ELEMENTS_HTML);
}
hasInListItemScope(tagName) {
return this.hasInDynamicScope(tagName, SCOPING_ELEMENTS_HTML_LIST);
}
hasInButtonScope(tagName) {
return this.hasInDynamicScope(tagName, SCOPING_ELEMENTS_HTML_BUTTON);
}
hasNumberedHeaderInScope() {
for (let i = this.stackTop; i >= 0; i--) {
const tn = this.tagIDs[i];
switch (this.treeAdapter.getNamespaceURI(this.items[i])) {
case NS.HTML: {
if (NUMBERED_HEADERS.has(tn))
return true;
if (SCOPING_ELEMENTS_HTML.has(tn))
return false;
break;
}
case NS.SVG: {
if (SCOPING_ELEMENTS_SVG.has(tn))
return false;
break;
}
case NS.MATHML: {
if (SCOPING_ELEMENTS_MATHML.has(tn))
return false;
break;
}
}
}
return true;
}
hasInTableScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
if (this.treeAdapter.getNamespaceURI(this.items[i]) !== NS.HTML) {
continue;
}
switch (this.tagIDs[i]) {
case tagName: {
return true;
}
case TAG_ID.TABLE:
case TAG_ID.HTML: {
return false;
}
}
}
return true;
}
hasTableBodyContextInTableScope() {
for (let i = this.stackTop; i >= 0; i--) {
if (this.treeAdapter.getNamespaceURI(this.items[i]) !== NS.HTML) {
continue;
}
switch (this.tagIDs[i]) {
case TAG_ID.TBODY:
case TAG_ID.THEAD:
case TAG_ID.TFOOT: {
return true;
}
case TAG_ID.TABLE:
case TAG_ID.HTML: {
return false;
}
}
}
return true;
}
hasInSelectScope(tagName) {
for (let i = this.stackTop; i >= 0; i--) {
if (this.treeAdapter.getNamespaceURI(this.items[i]) !== NS.HTML) {
continue;
}
switch (this.tagIDs[i]) {
case tagName: {
return true;
}
case TAG_ID.OPTION:
case TAG_ID.OPTGROUP: {
break;
}
default: {
return false;
}
}
}
return true;
}
//Implied end tags
generateImpliedEndTags() {
while (IMPLICIT_END_TAG_REQUIRED.has(this.currentTagId)) {
this.pop();
}
}
generateImpliedEndTagsThoroughly() {
while (IMPLICIT_END_TAG_REQUIRED_THOROUGHLY.has(this.currentTagId)) {
this.pop();
}
}
generateImpliedEndTagsWithExclusion(exclusionId) {
while (this.currentTagId !== exclusionId && IMPLICIT_END_TAG_REQUIRED_THOROUGHLY.has(this.currentTagId)) {
this.pop();
}
}
};
// node_modules/parse5/dist/parser/formatting-element-list.js
var NOAH_ARK_CAPACITY = 3;
var EntryType;
(function(EntryType2) {
EntryType2[EntryType2["Marker"] = 0] = "Marker";
EntryType2[EntryType2["Element"] = 1] = "Element";
})(EntryType || (EntryType = {}));
var MARKER = { type: EntryType.Marker };
var FormattingElementList = class {
constructor(treeAdapter) {
this.treeAdapter = treeAdapter;
this.entries = [];
this.bookmark = null;
}
//Noah Ark's condition
//OPTIMIZATION: at first we try to find possible candidates for exclusion using
//lightweight heuristics without thorough attributes check.
_getNoahArkConditionCandidates(newElement, neAttrs) {
const candidates = [];
const neAttrsLength = neAttrs.length;
const neTagName = this.treeAdapter.getTagName(newElement);
const neNamespaceURI = this.treeAdapter.getNamespaceURI(newElement);
for (let i = 0; i < this.entries.length; i++) {
const entry = this.entries[i];
if (entry.type === EntryType.Marker) {
break;
}
const { element } = entry;
if (this.treeAdapter.getTagName(element) === neTagName && this.treeAdapter.getNamespaceURI(element) === neNamespaceURI) {
const elementAttrs = this.treeAdapter.getAttrList(element);
if (elementAttrs.length === neAttrsLength) {
candidates.push({ idx: i, attrs: elementAttrs });
}
}
}
return candidates;
}
_ensureNoahArkCondition(newElement) {
if (this.entries.length < NOAH_ARK_CAPACITY)
return;
const neAttrs = this.treeAdapter.getAttrList(newElement);
const candidates = this._getNoahArkConditionCandidates(newElement, neAttrs);
if (candidates.length < NOAH_ARK_CAPACITY)
return;
const neAttrsMap = new Map(neAttrs.map((neAttr) => [neAttr.name, neAttr.value]));
let validCandidates = 0;
for (let i = 0; i < candidates.length; i++) {
const candidate = candidates[i];
if (candidate.attrs.every((cAttr) => neAttrsMap.get(cAttr.name) === cAttr.value)) {
validCandidates += 1;
if (validCandidates >= NOAH_ARK_CAPACITY) {
this.entries.splice(candidate.idx, 1);
}
}
}
}
//Mutations
insertMarker() {
this.entries.unshift(MARKER);
}
pushElement(element, token) {
this._ensureNoahArkCondition(element);
this.entries.unshift({
type: EntryType.Element,
element,
token
});
}
insertElementAfterBookmark(element, token) {
const bookmarkIdx = this.entries.indexOf(this.bookmark);
this.entries.splice(bookmarkIdx, 0, {
type: EntryType.Element,
element,
token
});
}
removeEntry(entry) {
const entryIndex = this.entries.indexOf(entry);
if (entryIndex >= 0) {
this.entries.splice(entryIndex, 1);
}
}
/**
* Clears the list of formatting elements up to the last marker.
*
* @see https://html.spec.whatwg.org/multipage/parsing.html#clear-the-list-of-active-formatting-elements-up-to-the-last-marker
*/
clearToLastMarker() {
const markerIdx = this.entries.indexOf(MARKER);
if (markerIdx >= 0) {
this.entries.splice(0, markerIdx + 1);
} else {
this.entries.length = 0;
}
}
//Search
getElementEntryInScopeWithTagName(tagName) {
const entry = this.entries.find((entry2) => entry2.type === EntryType.Marker || this.treeAdapter.getTagName(entry2.element) === tagName);
return entry && entry.type === EntryType.Element ? entry : null;
}
getElementEntry(element) {
return this.entries.find((entry) => entry.type === EntryType.Element && entry.element === element);
}
};
// node_modules/parse5/dist/tree-adapters/default.js
var defaultTreeAdapter = {
//Node construction
createDocument() {
return {
nodeName: "#document",
mode: DOCUMENT_MODE.NO_QUIRKS,
childNodes: []
};
},
createDocumentFragment() {
return {
nodeName: "#document-fragment",
childNodes: []
};
},
createElement(tagName, namespaceURI, attrs) {
return {
nodeName: tagName,
tagName,
attrs,
namespaceURI,
childNodes: [],
parentNode: null
};
},
createCommentNode(data) {
return {
nodeName: "#comment",
data,
parentNode: null
};
},
createTextNode(value) {
return {
nodeName: "#text",
value,
parentNode: null
};
},
//Tree mutation
appendChild(parentNode, newNode) {
parentNode.childNodes.push(newNode);
newNode.parentNode = parentNode;
},
insertBefore(parentNode, newNode, referenceNode) {
const insertionIdx = parentNode.childNodes.indexOf(referenceNode);
parentNode.childNodes.splice(insertionIdx, 0, newNode);
newNode.parentNode = parentNode;
},
setTemplateContent(templateElement, contentElement) {
templateElement.content = contentElement;
},
getTemplateContent(templateElement) {
return templateElement.content;
},
setDocumentType(document2, name, publicId, systemId) {
const doctypeNode = document2.childNodes.find((node) => node.nodeName === "#documentType");
if (doctypeNode) {
doctypeNode.name = name;
doctypeNode.publicId = publicId;
doctypeNode.systemId = systemId;
} else {
const node = {
nodeName: "#documentType",
name,
publicId,
systemId,
parentNode: null
};
defaultTreeAdapter.appendChild(document2, node);
}
},
setDocumentMode(document2, mode) {
document2.mode = mode;
},
getDocumentMode(document2) {
return document2.mode;
},
detachNode(node) {
if (node.parentNode) {
const idx = node.parentNode.childNodes.indexOf(node);
node.parentNode.childNodes.splice(idx, 1);
node.parentNode = null;
}
},
insertText(parentNode, text) {
if (parentNode.childNodes.length > 0) {
const prevNode = parentNode.childNodes[parentNode.childNodes.length - 1];
if (defaultTreeAdapter.isTextNode(prevNode)) {
prevNode.value += text;
return;
}
}
defaultTreeAdapter.appendChild(parentNode, defaultTreeAdapter.createTextNode(text));
},
insertTextBefore(parentNode, text, referenceNode) {
const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1];
if (prevNode && defaultTreeAdapter.isTextNode(prevNode)) {
prevNode.value += text;
} else {
defaultTreeAdapter.insertBefore(parentNode, defaultTreeAdapter.createTextNode(text), referenceNode);
}
},
adoptAttributes(recipient, attrs) {
const recipientAttrsMap = new Set(recipient.attrs.map((attr) => attr.name));
for (let j = 0; j < attrs.length; j++) {
if (!recipientAttrsMap.has(attrs[j].name)) {
recipient.attrs.push(attrs[j]);
}
}
},
//Tree traversing
getFirstChild(node) {
return node.childNodes[0];
},
getChildNodes(node) {
return node.childNodes;
},
getParentNode(node) {
return node.parentNode;
},
getAttrList(element) {
return element.attrs;
},
//Node data
getTagName(element) {
return element.tagName;
},
getNamespaceURI(element) {
return element.namespaceURI;
},
getTextNodeContent(textNode) {
return textNode.value;
},
getCommentNodeContent(commentNode) {
return commentNode.data;
},
getDocumentTypeNodeName(doctypeNode) {
return doctypeNode.name;
},
getDocumentTypeNodePublicId(doctypeNode) {
return doctypeNode.publicId;
},
getDocumentTypeNodeSystemId(doctypeNode) {
return doctypeNode.systemId;
},
//Node types
isTextNode(node) {
return node.nodeName === "#text";
},
isCommentNode(node) {
return node.nodeName === "#comment";
},
isDocumentTypeNode(node) {
return node.nodeName === "#documentType";
},
isElementNode(node) {
return Object.prototype.hasOwnProperty.call(node, "tagName");
},
// Source code location
setNodeSourceCodeLocation(node, location2) {
node.sourceCodeLocation = location2;
},
getNodeSourceCodeLocation(node) {
return node.sourceCodeLocation;
},
updateNodeSourceCodeLocation(node, endLocation) {
node.sourceCodeLocation = { ...node.sourceCodeLocation, ...endLocation };
}
};
// node_modules/parse5/dist/common/doctype.js
var VALID_DOCTYPE_NAME = "html";
var VALID_SYSTEM_ID = "about:legacy-compat";
var QUIRKS_MODE_SYSTEM_ID = "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd";
var QUIRKS_MODE_PUBLIC_ID_PREFIXES = [
"+//silmaril//dtd html pro v0r11 19970101//",
"-//as//dtd html 3.0 aswedit + extensions//",
"-//advasoft ltd//dtd html 3.0 aswedit + extensions//",
"-//ietf//dtd html 2.0 level 1//",
"-//ietf//dtd html 2.0 level 2//",
"-//ietf//dtd html 2.0 strict level 1//",
"-//ietf//dtd html 2.0 strict level 2//",
"-//ietf//dtd html 2.0 strict//",
"-//ietf//dtd html 2.0//",
"-//ietf//dtd html 2.1e//",
"-//ietf//dtd html 3.0//",
"-//ietf//dtd html 3.2 final//",
"-//ietf//dtd html 3.2//",
"-//ietf//dtd html 3//",
"-//ietf//dtd html level 0//",
"-//ietf//dtd html level 1//",
"-//ietf//dtd html level 2//",
"-//ietf//dtd html level 3//",
"-//ietf//dtd html strict level 0//",
"-//ietf//dtd html strict level 1//",
"-//ietf//dtd html strict level 2//",
"-//ietf//dtd html strict level 3//",
"-//ietf//dtd html strict//",
"-//ietf//dtd html//",
"-//metrius//dtd metrius presentational//",
"-//microsoft//dtd internet explorer 2.0 html strict//",
"-//microsoft//dtd internet explorer 2.0 html//",
"-//microsoft//dtd internet explorer 2.0 tables//",
"-//microsoft//dtd internet explorer 3.0 html strict//",
"-//microsoft//dtd internet explorer 3.0 html//",
"-//microsoft//dtd internet explorer 3.0 tables//",
"-//netscape comm. corp.//dtd html//",
"-//netscape comm. corp.//dtd strict html//",
"-//o'reilly and associates//dtd html 2.0//",
"-//o'reilly and associates//dtd html extended 1.0//",
"-//o'reilly and associates//dtd html extended relaxed 1.0//",
"-//sq//dtd html 2.0 hotmetal + extensions//",
"-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//",
"-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//",
"-//spyglass//dtd html 2.0 extended//",
"-//sun microsystems corp.//dtd hotjava html//",
"-//sun microsystems corp.//dtd hotjava strict html//",
"-//w3c//dtd html 3 1995-03-24//",
"-//w3c//dtd html 3.2 draft//",
"-//w3c//dtd html 3.2 final//",
"-//w3c//dtd html 3.2//",
"-//w3c//dtd html 3.2s draft//",
"-//w3c//dtd html 4.0 frameset//",
"-//w3c//dtd html 4.0 transitional//",
"-//w3c//dtd html experimental 19960712//",
"-//w3c//dtd html experimental 970421//",
"-//w3c//dtd w3 html//",
"-//w3o//dtd w3 html 3.0//",
"-//webtechs//dtd mozilla html 2.0//",
"-//webtechs//dtd mozilla html//"
];
var QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES = [
...QUIRKS_MODE_PUBLIC_ID_PREFIXES,
"-//w3c//dtd html 4.01 frameset//",
"-//w3c//dtd html 4.01 transitional//"
];
var QUIRKS_MODE_PUBLIC_IDS = /* @__PURE__ */ new Set([
"-//w3o//dtd w3 html strict 3.0//en//",
"-/w3c/dtd html 4.0 transitional/en",
"html"
]);
var LIMITED_QUIRKS_PUBLIC_ID_PREFIXES = ["-//w3c//dtd xhtml 1.0 frameset//", "-//w3c//dtd xhtml 1.0 transitional//"];
var LIMITED_QUIRKS_WITH_SYSTEM_ID_PUBLIC_ID_PREFIXES = [
...LIMITED_QUIRKS_PUBLIC_ID_PREFIXES,
"-//w3c//dtd html 4.01 frameset//",
"-//w3c//dtd html 4.01 transitional//"
];
function hasPrefix(publicId, prefixes) {
return prefixes.some((prefix) => publicId.startsWith(prefix));
}
function isConforming(token) {
return token.name === VALID_DOCTYPE_NAME && token.publicId === null && (token.systemId === null || token.systemId === VALID_SYSTEM_ID);
}
function getDocumentMode(token) {
if (token.name !== VALID_DOCTYPE_NAME) {
return DOCUMENT_MODE.QUIRKS;
}
const { systemId } = token;
if (systemId && systemId.toLowerCase() === QUIRKS_MODE_SYSTEM_ID) {
return DOCUMENT_MODE.QUIRKS;
}
let { publicId } = token;
if (publicId !== null) {
publicId = publicId.toLowerCase();
if (QUIRKS_MODE_PUBLIC_IDS.has(publicId)) {
return DOCUMENT_MODE.QUIRKS;
}
let prefixes = systemId === null ? QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES : QUIRKS_MODE_PUBLIC_ID_PREFIXES;
if (hasPrefix(publicId, prefixes)) {
return DOCUMENT_MODE.QUIRKS;
}
prefixes = systemId === null ? LIMITED_QUIRKS_PUBLIC_ID_PREFIXES : LIMITED_QUIRKS_WITH_SYSTEM_ID_PUBLIC_ID_PREFIXES;
if (hasPrefix(publicId, prefixes)) {
return DOCUMENT_MODE.LIMITED_QUIRKS;
}
}
return DOCUMENT_MODE.NO_QUIRKS;
}
// node_modules/parse5/dist/common/foreign-content.js
var foreign_content_exports = {};
__export(foreign_content_exports, {
SVG_TAG_NAMES_ADJUSTMENT_MAP: () => SVG_TAG_NAMES_ADJUSTMENT_MAP,
adjustTokenMathMLAttrs: () => adjustTokenMathMLAttrs,
adjustTokenSVGAttrs: () => adjustTokenSVGAttrs,
adjustTokenSVGTagName: () => adjustTokenSVGTagName,
adjustTokenXMLAttrs: () => adjustTokenXMLAttrs,
causesExit: () => causesExit,
isIntegrationPoint: () => isIntegrationPoint
});
var MIME_TYPES = {
TEXT_HTML: "text/html",
APPLICATION_XML: "application/xhtml+xml"
};
var DEFINITION_URL_ATTR = "definitionurl";
var ADJUSTED_DEFINITION_URL_ATTR = "definitionURL";
var SVG_ATTRS_ADJUSTMENT_MAP = new Map([
"attributeName",
"attributeType",
"baseFrequency",
"baseProfile",
"calcMode",
"clipPathUnits",
"diffuseConstant",
"edgeMode",
"filterUnits",
"glyphRef",
"gradientTransform",
"gradientUnits",
"kernelMatrix",
"kernelUnitLength",
"keyPoints",
"keySplines",
"keyTimes",
"lengthAdjust",
"limitingConeAngle",
"markerHeight",
"markerUnits",
"markerWidth",
"maskContentUnits",
"maskUnits",
"numOctaves",
"pathLength",
"patternContentUnits",
"patternTransform",
"patternUnits",
"pointsAtX",
"pointsAtY",
"pointsAtZ",
"preserveAlpha",
"preserveAspectRatio",
"primitiveUnits",
"refX",
"refY",
"repeatCount",
"repeatDur",
"requiredExtensions",
"requiredFeatures",
"specularConstant",
"specularExponent",
"spreadMethod",
"startOffset",
"stdDeviation",
"stitchTiles",
"surfaceScale",
"systemLanguage",
"tableValues",
"targetX",
"targetY",
"textLength",
"viewBox",
"viewTarget",
"xChannelSelector",
"yChannelSelector",
"zoomAndPan"
].map((attr) => [attr.toLowerCase(), attr]));
var XML_ATTRS_ADJUSTMENT_MAP = /* @__PURE__ */ new Map([
["xlink:actuate", { prefix: "xlink", name: "actuate", namespace: NS.XLINK }],
["xlink:arcrole", { prefix: "xlink", name: "arcrole", namespace: NS.XLINK }],
["xlink:href", { prefix: "xlink", name: "href", namespace: NS.XLINK }],
["xlink:role", { prefix: "xlink", name: "role", namespace: NS.XLINK }],
["xlink:show", { prefix: "xlink", name: "show", namespace: NS.XLINK }],
["xlink:title", { prefix: "xlink", name: "title", namespace: NS.XLINK }],
["xlink:type", { prefix: "xlink", name: "type", namespace: NS.XLINK }],
["xml:lang", { prefix: "xml", name: "lang", namespace: NS.XML }],
["xml:space", { prefix: "xml", name: "space", namespace: NS.XML }],
["xmlns", { prefix: "", name: "xmlns", namespace: NS.XMLNS }],
["xmlns:xlink", { prefix: "xmlns", name: "xlink", namespace: NS.XMLNS }]
]);
var SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map([
"altGlyph",
"altGlyphDef",
"altGlyphItem",
"animateColor",
"animateMotion",
"animateTransform",
"clipPath",
"feBlend",
"feColorMatrix",
"feComponentTransfer",
"feComposite",
"feConvolveMatrix",
"feDiffuseLighting",
"feDisplacementMap",
"feDistantLight",
"feFlood",
"feFuncA",
"feFuncB",
"feFuncG",
"feFuncR",
"feGaussianBlur",
"feImage",
"feMerge",
"feMergeNode",
"feMorphology",
"feOffset",
"fePointLight",
"feSpecularLighting",
"feSpotLight",
"feTile",
"feTurbulence",
"foreignObject",
"glyphRef",
"linearGradient",
"radialGradient",
"textPath"
].map((tn) => [tn.toLowerCase(), tn]));
var EXITS_FOREIGN_CONTENT = /* @__PURE__ */ new Set([
TAG_ID.B,
TAG_ID.BIG,
TAG_ID.BLOCKQUOTE,
TAG_ID.BODY,
TAG_ID.BR,
TAG_ID.CENTER,
TAG_ID.CODE,
TAG_ID.DD,
TAG_ID.DIV,
TAG_ID.DL,
TAG_ID.DT,
TAG_ID.EM,
TAG_ID.EMBED,
TAG_ID.H1,
TAG_ID.H2,
TAG_ID.H3,
TAG_ID.H4,
TAG_ID.H5,
TAG_ID.H6,
TAG_ID.HEAD,
TAG_ID.HR,
TAG_ID.I,
TAG_ID.IMG,
TAG_ID.LI,
TAG_ID.LISTING,
TAG_ID.MENU,
TAG_ID.META,
TAG_ID.NOBR,
TAG_ID.OL,
TAG_ID.P,
TAG_ID.PRE,
TAG_ID.RUBY,
TAG_ID.S,
TAG_ID.SMALL,
TAG_ID.SPAN,
TAG_ID.STRONG,
TAG_ID.STRIKE,
TAG_ID.SUB,
TAG_ID.SUP,
TAG_ID.TABLE,
TAG_ID.TT,
TAG_ID.U,
TAG_ID.UL,
TAG_ID.VAR
]);
function causesExit(startTagToken) {
const tn = startTagToken.tagID;
const isFontWithAttrs = tn === TAG_ID.FONT && startTagToken.attrs.some(({ name }) => name === ATTRS.COLOR || name === ATTRS.SIZE || name === ATTRS.FACE);
return isFontWithAttrs || EXITS_FOREIGN_CONTENT.has(tn);
}
function adjustTokenMathMLAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
if (token.attrs[i].name === DEFINITION_URL_ATTR) {
token.attrs[i].name = ADJUSTED_DEFINITION_URL_ATTR;
break;
}
}
}
function adjustTokenSVGAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
const adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name);
if (adjustedAttrName != null) {
token.attrs[i].name = adjustedAttrName;
}
}
}
function adjustTokenXMLAttrs(token) {
for (let i = 0; i < token.attrs.length; i++) {
const adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP.get(token.attrs[i].name);
if (adjustedAttrEntry) {
token.attrs[i].prefix = adjustedAttrEntry.prefix;
token.attrs[i].name = adjustedAttrEntry.name;
token.attrs[i].namespace = adjustedAttrEntry.namespace;
}
}
}
function adjustTokenSVGTagName(token) {
const adjustedTagName = SVG_TAG_NAMES_ADJUSTMENT_MAP.get(token.tagName);
if (adjustedTagName != null) {
token.tagName = adjustedTagName;
token.tagID = getTagID(token.tagName);
}
}
function isMathMLTextIntegrationPoint(tn, ns) {
return ns === NS.MATHML && (tn === TAG_ID.MI || tn === TAG_ID.MO || tn === TAG_ID.MN || tn === TAG_ID.MS || tn === TAG_ID.MTEXT);
}
function isHtmlIntegrationPoint(tn, ns, attrs) {
if (ns === NS.MATHML && tn === TAG_ID.ANNOTATION_XML) {
for (let i = 0; i < attrs.length; i++) {
if (attrs[i].name === ATTRS.ENCODING) {
const value = attrs[i].value.toLowerCase();
return value === MIME_TYPES.TEXT_HTML || value === MIME_TYPES.APPLICATION_XML;
}
}
}
return ns === NS.SVG && (tn === TAG_ID.FOREIGN_OBJECT || tn === TAG_ID.DESC || tn === TAG_ID.TITLE);
}
function isIntegrationPoint(tn, ns, attrs, foreignNS) {
return (!foreignNS || foreignNS === NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs) || (!foreignNS || foreignNS === NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns);
}
// node_modules/parse5/dist/parser/index.js
var HIDDEN_INPUT_TYPE = "hidden";
var AA_OUTER_LOOP_ITER = 8;
var AA_INNER_LOOP_ITER = 3;
var InsertionMode;
(function(InsertionMode2) {
InsertionMode2[InsertionMode2["INITIAL"] = 0] = "INITIAL";
InsertionMode2[InsertionMode2["BEFORE_HTML"] = 1] = "BEFORE_HTML";
InsertionMode2[InsertionMode2["BEFORE_HEAD"] = 2] = "BEFORE_HEAD";
InsertionMode2[InsertionMode2["IN_HEAD"] = 3] = "IN_HEAD";
InsertionMode2[InsertionMode2["IN_HEAD_NO_SCRIPT"] = 4] = "IN_HEAD_NO_SCRIPT";
InsertionMode2[InsertionMode2["AFTER_HEAD"] = 5] = "AFTER_HEAD";
InsertionMode2[InsertionMode2["IN_BODY"] = 6] = "IN_BODY";
InsertionMode2[InsertionMode2["TEXT"] = 7] = "TEXT";
InsertionMode2[InsertionMode2["IN_TABLE"] = 8] = "IN_TABLE";
InsertionMode2[InsertionMode2["IN_TABLE_TEXT"] = 9] = "IN_TABLE_TEXT";
InsertionMode2[InsertionMode2["IN_CAPTION"] = 10] = "IN_CAPTION";
InsertionMode2[InsertionMode2["IN_COLUMN_GROUP"] = 11] = "IN_COLUMN_GROUP";
InsertionMode2[InsertionMode2["IN_TABLE_BODY"] = 12] = "IN_TABLE_BODY";
InsertionMode2[InsertionMode2["IN_ROW"] = 13] = "IN_ROW";
InsertionMode2[InsertionMode2["IN_CELL"] = 14] = "IN_CELL";
InsertionMode2[InsertionMode2["IN_SELECT"] = 15] = "IN_SELECT";
InsertionMode2[InsertionMode2["IN_SELECT_IN_TABLE"] = 16] = "IN_SELECT_IN_TABLE";
InsertionMode2[InsertionMode2["IN_TEMPLATE"] = 17] = "IN_TEMPLATE";
InsertionMode2[InsertionMode2["AFTER_BODY"] = 18] = "AFTER_BODY";
InsertionMode2[InsertionMode2["IN_FRAMESET"] = 19] = "IN_FRAMESET";
InsertionMode2[InsertionMode2["AFTER_FRAMESET"] = 20] = "AFTER_FRAMESET";
InsertionMode2[InsertionMode2["AFTER_AFTER_BODY"] = 21] = "AFTER_AFTER_BODY";
InsertionMode2[InsertionMode2["AFTER_AFTER_FRAMESET"] = 22] = "AFTER_AFTER_FRAMESET";
})(InsertionMode || (InsertionMode = {}));
var BASE_LOC = {
startLine: -1,
startCol: -1,
startOffset: -1,
endLine: -1,
endCol: -1,
endOffset: -1
};
var TABLE_STRUCTURE_TAGS = /* @__PURE__ */ new Set([TAG_ID.TABLE, TAG_ID.TBODY, TAG_ID.TFOOT, TAG_ID.THEAD, TAG_ID.TR]);
var defaultParserOptions = {
scriptingEnabled: true,
sourceCodeLocationInfo: false,
treeAdapter: defaultTreeAdapter,
onParseError: null
};
var Parser = class {
constructor(options, document2, fragmentContext = null, scriptHandler = null) {
this.fragmentContext = fragmentContext;
this.scriptHandler = scriptHandler;
this.currentToken = null;
this.stopped = false;
this.insertionMode = InsertionMode.INITIAL;
this.originalInsertionMode = InsertionMode.INITIAL;
this.headElement = null;
this.formElement = null;
this.currentNotInHTML = false;
this.tmplInsertionModeStack = [];
this.pendingCharacterTokens = [];
this.hasNonWhitespacePendingCharacterToken = false;
this.framesetOk = true;
this.skipNextNewLine = false;
this.fosterParentingEnabled = false;
this.options = {
...defaultParserOptions,
...options
};
this.treeAdapter = this.options.treeAdapter;
this.onParseError = this.options.onParseError;
if (this.onParseError) {
this.options.sourceCodeLocationInfo = true;
}
this.document = document2 !== null && document2 !== void 0 ? document2 : this.treeAdapter.createDocument();
this.tokenizer = new Tokenizer(this.options, this);
this.activeFormattingElements = new FormattingElementList(this.treeAdapter);
this.fragmentContextID = fragmentContext ? getTagID(this.treeAdapter.getTagName(fragmentContext)) : TAG_ID.UNKNOWN;
this._setContextModes(fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : this.document, this.fragmentContextID);
this.openElements = new OpenElementStack(this.document, this.treeAdapter, this);
}
// API
static parse(html, options) {
const parser = new this(options);
parser.tokenizer.write(html, true);
return parser.document;
}
static getFragmentParser(fragmentContext, options) {
const opts = {
...defaultParserOptions,
...options
};
fragmentContext !== null && fragmentContext !== void 0 ? fragmentContext : fragmentContext = opts.treeAdapter.createElement(TAG_NAMES.TEMPLATE, NS.HTML, []);
const documentMock = opts.treeAdapter.createElement("documentmock", NS.HTML, []);
const parser = new this(opts, documentMock, fragmentContext);
if (parser.fragmentContextID === TAG_ID.TEMPLATE) {
parser.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
}
parser._initTokenizerForFragmentParsing();
parser._insertFakeRootElement();
parser._resetInsertionMode();
parser._findFormInFragmentContext();
return parser;
}
getFragment() {
const rootElement = this.treeAdapter.getFirstChild(this.document);
const fragment = this.treeAdapter.createDocumentFragment();
this._adoptNodes(rootElement, fragment);
return fragment;
}
//Errors
/** @internal */
_err(token, code, beforeToken) {
var _a2;
if (!this.onParseError)
return;
const loc = (_a2 = token.location) !== null && _a2 !== void 0 ? _a2 : BASE_LOC;
const err2 = {
code,
startLine: loc.startLine,
startCol: loc.startCol,
startOffset: loc.startOffset,
endLine: beforeToken ? loc.startLine : loc.endLine,
endCol: beforeToken ? loc.startCol : loc.endCol,
endOffset: beforeToken ? loc.startOffset : loc.endOffset
};
this.onParseError(err2);
}
//Stack events
/** @internal */
onItemPush(node, tid, isTop) {
var _a2, _b;
(_b = (_a2 = this.treeAdapter).onItemPush) === null || _b === void 0 ? void 0 : _b.call(_a2, node);
if (isTop && this.openElements.stackTop > 0)
this._setContextModes(node, tid);
}
/** @internal */
onItemPop(node, isTop) {
var _a2, _b;
if (this.options.sourceCodeLocationInfo) {
this._setEndLocation(node, this.currentToken);
}
(_b = (_a2 = this.treeAdapter).onItemPop) === null || _b === void 0 ? void 0 : _b.call(_a2, node, this.openElements.current);
if (isTop) {
let current;
let currentTagId;
if (this.openElements.stackTop === 0 && this.fragmentContext) {
current = this.fragmentContext;
currentTagId = this.fragmentContextID;
} else {
({ current, currentTagId } = this.openElements);
}
this._setContextModes(current, currentTagId);
}
}
_setContextModes(current, tid) {
const isHTML = current === this.document || this.treeAdapter.getNamespaceURI(current) === NS.HTML;
this.currentNotInHTML = !isHTML;
this.tokenizer.inForeignNode = !isHTML && !this._isIntegrationPoint(tid, current);
}
/** @protected */
_switchToTextParsing(currentToken, nextTokenizerState) {
this._insertElement(currentToken, NS.HTML);
this.tokenizer.state = nextTokenizerState;
this.originalInsertionMode = this.insertionMode;
this.insertionMode = InsertionMode.TEXT;
}
switchToPlaintextParsing() {
this.insertionMode = InsertionMode.TEXT;
this.originalInsertionMode = InsertionMode.IN_BODY;
this.tokenizer.state = TokenizerMode.PLAINTEXT;
}
//Fragment parsing
/** @protected */
_getAdjustedCurrentElement() {
return this.openElements.stackTop === 0 && this.fragmentContext ? this.fragmentContext : this.openElements.current;
}
/** @protected */
_findFormInFragmentContext() {
let node = this.fragmentContext;
while (node) {
if (this.treeAdapter.getTagName(node) === TAG_NAMES.FORM) {
this.formElement = node;
break;
}
node = this.treeAdapter.getParentNode(node);
}
}
_initTokenizerForFragmentParsing() {
if (!this.fragmentContext || this.treeAdapter.getNamespaceURI(this.fragmentContext) !== NS.HTML) {
return;
}
switch (this.fragmentContextID) {
case TAG_ID.TITLE:
case TAG_ID.TEXTAREA: {
this.tokenizer.state = TokenizerMode.RCDATA;
break;
}
case TAG_ID.STYLE:
case TAG_ID.XMP:
case TAG_ID.IFRAME:
case TAG_ID.NOEMBED:
case TAG_ID.NOFRAMES:
case TAG_ID.NOSCRIPT: {
this.tokenizer.state = TokenizerMode.RAWTEXT;
break;
}
case TAG_ID.SCRIPT: {
this.tokenizer.state = TokenizerMode.SCRIPT_DATA;
break;
}
case TAG_ID.PLAINTEXT: {
this.tokenizer.state = TokenizerMode.PLAINTEXT;
break;
}
default:
}
}
//Tree mutation
/** @protected */
_setDocumentType(token) {
const name = token.name || "";
const publicId = token.publicId || "";
const systemId = token.systemId || "";
this.treeAdapter.setDocumentType(this.document, name, publicId, systemId);
if (token.location) {
const documentChildren = this.treeAdapter.getChildNodes(this.document);
const docTypeNode = documentChildren.find((node) => this.treeAdapter.isDocumentTypeNode(node));
if (docTypeNode) {
this.treeAdapter.setNodeSourceCodeLocation(docTypeNode, token.location);
}
}
}
/** @protected */
_attachElementToTree(element, location2) {
if (this.options.sourceCodeLocationInfo) {
const loc = location2 && {
...location2,
startTag: location2
};
this.treeAdapter.setNodeSourceCodeLocation(element, loc);
}
if (this._shouldFosterParentOnInsertion()) {
this._fosterParentElement(element);
} else {
const parent = this.openElements.currentTmplContentOrNode;
this.treeAdapter.appendChild(parent, element);
}
}
/**
* For self-closing tags. Add an element to the tree, but skip adding it
* to the stack.
*/
/** @protected */
_appendElement(token, namespaceURI) {
const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
this._attachElementToTree(element, token.location);
}
/** @protected */
_insertElement(token, namespaceURI) {
const element = this.treeAdapter.createElement(token.tagName, namespaceURI, token.attrs);
this._attachElementToTree(element, token.location);
this.openElements.push(element, token.tagID);
}
/** @protected */
_insertFakeElement(tagName, tagID) {
const element = this.treeAdapter.createElement(tagName, NS.HTML, []);
this._attachElementToTree(element, null);
this.openElements.push(element, tagID);
}
/** @protected */
_insertTemplate(token) {
const tmpl = this.treeAdapter.createElement(token.tagName, NS.HTML, token.attrs);
const content = this.treeAdapter.createDocumentFragment();
this.treeAdapter.setTemplateContent(tmpl, content);
this._attachElementToTree(tmpl, token.location);
this.openElements.push(tmpl, token.tagID);
if (this.options.sourceCodeLocationInfo)
this.treeAdapter.setNodeSourceCodeLocation(content, null);
}
/** @protected */
_insertFakeRootElement() {
const element = this.treeAdapter.createElement(TAG_NAMES.HTML, NS.HTML, []);
if (this.options.sourceCodeLocationInfo)
this.treeAdapter.setNodeSourceCodeLocation(element, null);
this.treeAdapter.appendChild(this.openElements.current, element);
this.openElements.push(element, TAG_ID.HTML);
}
/** @protected */
_appendCommentNode(token, parent) {
const commentNode = this.treeAdapter.createCommentNode(token.data);
this.treeAdapter.appendChild(parent, commentNode);
if (this.options.sourceCodeLocationInfo) {
this.treeAdapter.setNodeSourceCodeLocation(commentNode, token.location);
}
}
/** @protected */
_insertCharacters(token) {
let parent;
let beforeElement;
if (this._shouldFosterParentOnInsertion()) {
({ parent, beforeElement } = this._findFosterParentingLocation());
if (beforeElement) {
this.treeAdapter.insertTextBefore(parent, token.chars, beforeElement);
} else {
this.treeAdapter.insertText(parent, token.chars);
}
} else {
parent = this.openElements.currentTmplContentOrNode;
this.treeAdapter.insertText(parent, token.chars);
}
if (!token.location)
return;
const siblings = this.treeAdapter.getChildNodes(parent);
const textNodeIdx = beforeElement ? siblings.lastIndexOf(beforeElement) : siblings.length;
const textNode = siblings[textNodeIdx - 1];
const tnLoc = this.treeAdapter.getNodeSourceCodeLocation(textNode);
if (tnLoc) {
const { endLine, endCol, endOffset } = token.location;
this.treeAdapter.updateNodeSourceCodeLocation(textNode, { endLine, endCol, endOffset });
} else if (this.options.sourceCodeLocationInfo) {
this.treeAdapter.setNodeSourceCodeLocation(textNode, token.location);
}
}
/** @protected */
_adoptNodes(donor, recipient) {
for (let child = this.treeAdapter.getFirstChild(donor); child; child = this.treeAdapter.getFirstChild(donor)) {
this.treeAdapter.detachNode(child);
this.treeAdapter.appendChild(recipient, child);
}
}
/** @protected */
_setEndLocation(element, closingToken) {
if (this.treeAdapter.getNodeSourceCodeLocation(element) && closingToken.location) {
const ctLoc = closingToken.location;
const tn = this.treeAdapter.getTagName(element);
const endLoc = (
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing
// tag and for cases like <td> <p> </td> - 'p' closes without a closing tag.
closingToken.type === TokenType.END_TAG && tn === closingToken.tagName ? {
endTag: { ...ctLoc },
endLine: ctLoc.endLine,
endCol: ctLoc.endCol,
endOffset: ctLoc.endOffset
} : {
endLine: ctLoc.startLine,
endCol: ctLoc.startCol,
endOffset: ctLoc.startOffset
}
);
this.treeAdapter.updateNodeSourceCodeLocation(element, endLoc);
}
}
//Token processing
shouldProcessStartTagTokenInForeignContent(token) {
if (!this.currentNotInHTML)
return false;
let current;
let currentTagId;
if (this.openElements.stackTop === 0 && this.fragmentContext) {
current = this.fragmentContext;
currentTagId = this.fragmentContextID;
} else {
({ current, currentTagId } = this.openElements);
}
if (token.tagID === TAG_ID.SVG && this.treeAdapter.getTagName(current) === TAG_NAMES.ANNOTATION_XML && this.treeAdapter.getNamespaceURI(current) === NS.MATHML) {
return false;
}
return (
// Check that `current` is not an integration point for HTML or MathML elements.
this.tokenizer.inForeignNode || // If it _is_ an integration point, then we might have to check that it is not an HTML
// integration point.
(token.tagID === TAG_ID.MGLYPH || token.tagID === TAG_ID.MALIGNMARK) && !this._isIntegrationPoint(currentTagId, current, NS.HTML)
);
}
/** @protected */
_processToken(token) {
switch (token.type) {
case TokenType.CHARACTER: {
this.onCharacter(token);
break;
}
case TokenType.NULL_CHARACTER: {
this.onNullCharacter(token);
break;
}
case TokenType.COMMENT: {
this.onComment(token);
break;
}
case TokenType.DOCTYPE: {
this.onDoctype(token);
break;
}
case TokenType.START_TAG: {
this._processStartTag(token);
break;
}
case TokenType.END_TAG: {
this.onEndTag(token);
break;
}
case TokenType.EOF: {
this.onEof(token);
break;
}
case TokenType.WHITESPACE_CHARACTER: {
this.onWhitespaceCharacter(token);
break;
}
}
}
//Integration points
/** @protected */
_isIntegrationPoint(tid, element, foreignNS) {
const ns = this.treeAdapter.getNamespaceURI(element);
const attrs = this.treeAdapter.getAttrList(element);
return isIntegrationPoint(tid, ns, attrs, foreignNS);
}
//Active formatting elements reconstruction
/** @protected */
_reconstructActiveFormattingElements() {
const listLength = this.activeFormattingElements.entries.length;
if (listLength) {
const endIndex = this.activeFormattingElements.entries.findIndex((entry) => entry.type === EntryType.Marker || this.openElements.contains(entry.element));
const unopenIdx = endIndex < 0 ? listLength - 1 : endIndex - 1;
for (let i = unopenIdx; i >= 0; i--) {
const entry = this.activeFormattingElements.entries[i];
this._insertElement(entry.token, this.treeAdapter.getNamespaceURI(entry.element));
entry.element = this.openElements.current;
}
}
}
//Close elements
/** @protected */
_closeTableCell() {
this.openElements.generateImpliedEndTags();
this.openElements.popUntilTableCellPopped();
this.activeFormattingElements.clearToLastMarker();
this.insertionMode = InsertionMode.IN_ROW;
}
/** @protected */
_closePElement() {
this.openElements.generateImpliedEndTagsWithExclusion(TAG_ID.P);
this.openElements.popUntilTagNamePopped(TAG_ID.P);
}
//Insertion modes
/** @protected */
_resetInsertionMode() {
for (let i = this.openElements.stackTop; i >= 0; i--) {
switch (i === 0 && this.fragmentContext ? this.fragmentContextID : this.openElements.tagIDs[i]) {
case TAG_ID.TR: {
this.insertionMode = InsertionMode.IN_ROW;
return;
}
case TAG_ID.TBODY:
case TAG_ID.THEAD:
case TAG_ID.TFOOT: {
this.insertionMode = InsertionMode.IN_TABLE_BODY;
return;
}
case TAG_ID.CAPTION: {
this.insertionMode = InsertionMode.IN_CAPTION;
return;
}
case TAG_ID.COLGROUP: {
this.insertionMode = InsertionMode.IN_COLUMN_GROUP;
return;
}
case TAG_ID.TABLE: {
this.insertionMode = InsertionMode.IN_TABLE;
return;
}
case TAG_ID.BODY: {
this.insertionMode = InsertionMode.IN_BODY;
return;
}
case TAG_ID.FRAMESET: {
this.insertionMode = InsertionMode.IN_FRAMESET;
return;
}
case TAG_ID.SELECT: {
this._resetInsertionModeForSelect(i);
return;
}
case TAG_ID.TEMPLATE: {
this.insertionMode = this.tmplInsertionModeStack[0];
return;
}
case TAG_ID.HTML: {
this.insertionMode = this.headElement ? InsertionMode.AFTER_HEAD : InsertionMode.BEFORE_HEAD;
return;
}
case TAG_ID.TD:
case TAG_ID.TH: {
if (i > 0) {
this.insertionMode = InsertionMode.IN_CELL;
return;
}
break;
}
case TAG_ID.HEAD: {
if (i > 0) {
this.insertionMode = InsertionMode.IN_HEAD;
return;
}
break;
}
}
}
this.insertionMode = InsertionMode.IN_BODY;
}
/** @protected */
_resetInsertionModeForSelect(selectIdx) {
if (selectIdx > 0) {
for (let i = selectIdx - 1; i > 0; i--) {
const tn = this.openElements.tagIDs[i];
if (tn === TAG_ID.TEMPLATE) {
break;
} else if (tn === TAG_ID.TABLE) {
this.insertionMode = InsertionMode.IN_SELECT_IN_TABLE;
return;
}
}
}
this.insertionMode = InsertionMode.IN_SELECT;
}
//Foster parenting
/** @protected */
_isElementCausesFosterParenting(tn) {
return TABLE_STRUCTURE_TAGS.has(tn);
}
/** @protected */
_shouldFosterParentOnInsertion() {
return this.fosterParentingEnabled && this._isElementCausesFosterParenting(this.openElements.currentTagId);
}
/** @protected */
_findFosterParentingLocation() {
for (let i = this.openElements.stackTop; i >= 0; i--) {
const openElement = this.openElements.items[i];
switch (this.openElements.tagIDs[i]) {
case TAG_ID.TEMPLATE: {
if (this.treeAdapter.getNamespaceURI(openElement) === NS.HTML) {
return { parent: this.treeAdapter.getTemplateContent(openElement), beforeElement: null };
}
break;
}
case TAG_ID.TABLE: {
const parent = this.treeAdapter.getParentNode(openElement);
if (parent) {
return { parent, beforeElement: openElement };
}
return { parent: this.openElements.items[i - 1], beforeElement: null };
}
default:
}
}
return { parent: this.openElements.items[0], beforeElement: null };
}
/** @protected */
_fosterParentElement(element) {
const location2 = this._findFosterParentingLocation();
if (location2.beforeElement) {
this.treeAdapter.insertBefore(location2.parent, element, location2.beforeElement);
} else {
this.treeAdapter.appendChild(location2.parent, element);
}
}
//Special elements
/** @protected */
_isSpecialElement(element, id) {
const ns = this.treeAdapter.getNamespaceURI(element);
return SPECIAL_ELEMENTS[ns].has(id);
}
/** @internal */
onCharacter(token) {
this.skipNextNewLine = false;
if (this.tokenizer.inForeignNode) {
characterInForeignContent(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_CELL:
case InsertionMode.IN_TEMPLATE: {
characterInBody(this, token);
break;
}
case InsertionMode.TEXT:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
characterInTableText(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
tokenInColumnGroup(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
tokenAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
default:
}
}
/** @internal */
onNullCharacter(token) {
this.skipNextNewLine = false;
if (this.tokenizer.inForeignNode) {
nullCharacterInForeignContent(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.TEXT: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
tokenInColumnGroup(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
tokenAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
default:
}
}
/** @internal */
onComment(token) {
this.skipNextNewLine = false;
if (this.currentNotInHTML) {
appendComment(this, token);
return;
}
switch (this.insertionMode) {
case InsertionMode.INITIAL:
case InsertionMode.BEFORE_HTML:
case InsertionMode.BEFORE_HEAD:
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD:
case InsertionMode.IN_BODY:
case InsertionMode.IN_TABLE:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW:
case InsertionMode.IN_CELL:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE:
case InsertionMode.IN_TEMPLATE:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET: {
appendComment(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
appendCommentToRootHtmlElement(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
appendCommentToDocument(this, token);
break;
}
default:
}
}
/** @internal */
onDoctype(token) {
this.skipNextNewLine = false;
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
doctypeInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HEAD:
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD: {
this._err(token, ERR.misplacedDoctype);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
default:
}
}
/** @internal */
onStartTag(token) {
this.skipNextNewLine = false;
this.currentToken = token;
this._processStartTag(token);
if (token.selfClosing && !token.ackSelfClosing) {
this._err(token, ERR.nonVoidHtmlElementStartTagWithTrailingSolidus);
}
}
/**
* Processes a given start tag.
*
* `onStartTag` checks if a self-closing tag was recognized. When a token
* is moved inbetween multiple insertion modes, this check for self-closing
* could lead to false positives. To avoid this, `_processStartTag` is used
* for nested calls.
*
* @param token The token to process.
* @protected
*/
_processStartTag(token) {
if (this.shouldProcessStartTagTokenInForeignContent(token)) {
startTagInForeignContent(this, token);
} else {
this._startTagOutsideForeignContent(token);
}
}
/** @protected */
_startTagOutsideForeignContent(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
startTagBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
startTagBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
startTagInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
startTagInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
startTagAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY: {
startTagInBody(this, token);
break;
}
case InsertionMode.IN_TABLE: {
startTagInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_CAPTION: {
startTagInCaption(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
startTagInColumnGroup(this, token);
break;
}
case InsertionMode.IN_TABLE_BODY: {
startTagInTableBody(this, token);
break;
}
case InsertionMode.IN_ROW: {
startTagInRow(this, token);
break;
}
case InsertionMode.IN_CELL: {
startTagInCell(this, token);
break;
}
case InsertionMode.IN_SELECT: {
startTagInSelect(this, token);
break;
}
case InsertionMode.IN_SELECT_IN_TABLE: {
startTagInSelectInTable(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
startTagInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
startTagAfterBody(this, token);
break;
}
case InsertionMode.IN_FRAMESET: {
startTagInFrameset(this, token);
break;
}
case InsertionMode.AFTER_FRAMESET: {
startTagAfterFrameset(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
startTagAfterAfterBody(this, token);
break;
}
case InsertionMode.AFTER_AFTER_FRAMESET: {
startTagAfterAfterFrameset(this, token);
break;
}
default:
}
}
/** @internal */
onEndTag(token) {
this.skipNextNewLine = false;
this.currentToken = token;
if (this.currentNotInHTML) {
endTagInForeignContent(this, token);
} else {
this._endTagOutsideForeignContent(token);
}
}
/** @protected */
_endTagOutsideForeignContent(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
endTagBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
endTagBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
endTagInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
endTagInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
endTagAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY: {
endTagInBody(this, token);
break;
}
case InsertionMode.TEXT: {
endTagInText(this, token);
break;
}
case InsertionMode.IN_TABLE: {
endTagInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_CAPTION: {
endTagInCaption(this, token);
break;
}
case InsertionMode.IN_COLUMN_GROUP: {
endTagInColumnGroup(this, token);
break;
}
case InsertionMode.IN_TABLE_BODY: {
endTagInTableBody(this, token);
break;
}
case InsertionMode.IN_ROW: {
endTagInRow(this, token);
break;
}
case InsertionMode.IN_CELL: {
endTagInCell(this, token);
break;
}
case InsertionMode.IN_SELECT: {
endTagInSelect(this, token);
break;
}
case InsertionMode.IN_SELECT_IN_TABLE: {
endTagInSelectInTable(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
endTagInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY: {
endTagAfterBody(this, token);
break;
}
case InsertionMode.IN_FRAMESET: {
endTagInFrameset(this, token);
break;
}
case InsertionMode.AFTER_FRAMESET: {
endTagAfterFrameset(this, token);
break;
}
case InsertionMode.AFTER_AFTER_BODY: {
tokenAfterAfterBody(this, token);
break;
}
default:
}
}
/** @internal */
onEof(token) {
switch (this.insertionMode) {
case InsertionMode.INITIAL: {
tokenInInitialMode(this, token);
break;
}
case InsertionMode.BEFORE_HTML: {
tokenBeforeHtml(this, token);
break;
}
case InsertionMode.BEFORE_HEAD: {
tokenBeforeHead(this, token);
break;
}
case InsertionMode.IN_HEAD: {
tokenInHead(this, token);
break;
}
case InsertionMode.IN_HEAD_NO_SCRIPT: {
tokenInHeadNoScript(this, token);
break;
}
case InsertionMode.AFTER_HEAD: {
tokenAfterHead(this, token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_TABLE:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW:
case InsertionMode.IN_CELL:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE: {
eofInBody(this, token);
break;
}
case InsertionMode.TEXT: {
eofInText(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
tokenInTableText(this, token);
break;
}
case InsertionMode.IN_TEMPLATE: {
eofInTemplate(this, token);
break;
}
case InsertionMode.AFTER_BODY:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET:
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
stopParsing(this, token);
break;
}
default:
}
}
/** @internal */
onWhitespaceCharacter(token) {
if (this.skipNextNewLine) {
this.skipNextNewLine = false;
if (token.chars.charCodeAt(0) === CODE_POINTS.LINE_FEED) {
if (token.chars.length === 1) {
return;
}
token.chars = token.chars.substr(1);
}
}
if (this.tokenizer.inForeignNode) {
this._insertCharacters(token);
return;
}
switch (this.insertionMode) {
case InsertionMode.IN_HEAD:
case InsertionMode.IN_HEAD_NO_SCRIPT:
case InsertionMode.AFTER_HEAD:
case InsertionMode.TEXT:
case InsertionMode.IN_COLUMN_GROUP:
case InsertionMode.IN_SELECT:
case InsertionMode.IN_SELECT_IN_TABLE:
case InsertionMode.IN_FRAMESET:
case InsertionMode.AFTER_FRAMESET: {
this._insertCharacters(token);
break;
}
case InsertionMode.IN_BODY:
case InsertionMode.IN_CAPTION:
case InsertionMode.IN_CELL:
case InsertionMode.IN_TEMPLATE:
case InsertionMode.AFTER_BODY:
case InsertionMode.AFTER_AFTER_BODY:
case InsertionMode.AFTER_AFTER_FRAMESET: {
whitespaceCharacterInBody(this, token);
break;
}
case InsertionMode.IN_TABLE:
case InsertionMode.IN_TABLE_BODY:
case InsertionMode.IN_ROW: {
characterInTable(this, token);
break;
}
case InsertionMode.IN_TABLE_TEXT: {
whitespaceCharacterInTableText(this, token);
break;
}
default:
}
}
};
function aaObtainFormattingElementEntry(p, token) {
let formattingElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(token.tagName);
if (formattingElementEntry) {
if (!p.openElements.contains(formattingElementEntry.element)) {
p.activeFormattingElements.removeEntry(formattingElementEntry);
formattingElementEntry = null;
} else if (!p.openElements.hasInScope(token.tagID)) {
formattingElementEntry = null;
}
} else {
genericEndTagInBody(p, token);
}
return formattingElementEntry;
}
function aaObtainFurthestBlock(p, formattingElementEntry) {
let furthestBlock = null;
let idx = p.openElements.stackTop;
for (; idx >= 0; idx--) {
const element = p.openElements.items[idx];
if (element === formattingElementEntry.element) {
break;
}
if (p._isSpecialElement(element, p.openElements.tagIDs[idx])) {
furthestBlock = element;
}
}
if (!furthestBlock) {
p.openElements.shortenToLength(idx < 0 ? 0 : idx);
p.activeFormattingElements.removeEntry(formattingElementEntry);
}
return furthestBlock;
}
function aaInnerLoop(p, furthestBlock, formattingElement) {
let lastElement = furthestBlock;
let nextElement = p.openElements.getCommonAncestor(furthestBlock);
for (let i = 0, element = nextElement; element !== formattingElement; i++, element = nextElement) {
nextElement = p.openElements.getCommonAncestor(element);
const elementEntry = p.activeFormattingElements.getElementEntry(element);
const counterOverflow = elementEntry && i >= AA_INNER_LOOP_ITER;
const shouldRemoveFromOpenElements = !elementEntry || counterOverflow;
if (shouldRemoveFromOpenElements) {
if (counterOverflow) {
p.activeFormattingElements.removeEntry(elementEntry);
}
p.openElements.remove(element);
} else {
element = aaRecreateElementFromEntry(p, elementEntry);
if (lastElement === furthestBlock) {
p.activeFormattingElements.bookmark = elementEntry;
}
p.treeAdapter.detachNode(lastElement);
p.treeAdapter.appendChild(element, lastElement);
lastElement = element;
}
}
return lastElement;
}
function aaRecreateElementFromEntry(p, elementEntry) {
const ns = p.treeAdapter.getNamespaceURI(elementEntry.element);
const newElement = p.treeAdapter.createElement(elementEntry.token.tagName, ns, elementEntry.token.attrs);
p.openElements.replace(elementEntry.element, newElement);
elementEntry.element = newElement;
return newElement;
}
function aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement) {
const tn = p.treeAdapter.getTagName(commonAncestor);
const tid = getTagID(tn);
if (p._isElementCausesFosterParenting(tid)) {
p._fosterParentElement(lastElement);
} else {
const ns = p.treeAdapter.getNamespaceURI(commonAncestor);
if (tid === TAG_ID.TEMPLATE && ns === NS.HTML) {
commonAncestor = p.treeAdapter.getTemplateContent(commonAncestor);
}
p.treeAdapter.appendChild(commonAncestor, lastElement);
}
}
function aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry) {
const ns = p.treeAdapter.getNamespaceURI(formattingElementEntry.element);
const { token } = formattingElementEntry;
const newElement = p.treeAdapter.createElement(token.tagName, ns, token.attrs);
p._adoptNodes(furthestBlock, newElement);
p.treeAdapter.appendChild(furthestBlock, newElement);
p.activeFormattingElements.insertElementAfterBookmark(newElement, token);
p.activeFormattingElements.removeEntry(formattingElementEntry);
p.openElements.remove(formattingElementEntry.element);
p.openElements.insertAfter(furthestBlock, newElement, token.tagID);
}
function callAdoptionAgency(p, token) {
for (let i = 0; i < AA_OUTER_LOOP_ITER; i++) {
const formattingElementEntry = aaObtainFormattingElementEntry(p, token);
if (!formattingElementEntry) {
break;
}
const furthestBlock = aaObtainFurthestBlock(p, formattingElementEntry);
if (!furthestBlock) {
break;
}
p.activeFormattingElements.bookmark = formattingElementEntry;
const lastElement = aaInnerLoop(p, furthestBlock, formattingElementEntry.element);
const commonAncestor = p.openElements.getCommonAncestor(formattingElementEntry.element);
p.treeAdapter.detachNode(lastElement);
if (commonAncestor)
aaInsertLastNodeInCommonAncestor(p, commonAncestor, lastElement);
aaReplaceFormattingElement(p, furthestBlock, formattingElementEntry);
}
}
function appendComment(p, token) {
p._appendCommentNode(token, p.openElements.currentTmplContentOrNode);
}
function appendCommentToRootHtmlElement(p, token) {
p._appendCommentNode(token, p.openElements.items[0]);
}
function appendCommentToDocument(p, token) {
p._appendCommentNode(token, p.document);
}
function stopParsing(p, token) {
p.stopped = true;
if (token.location) {
const target = p.fragmentContext ? 0 : 2;
for (let i = p.openElements.stackTop; i >= target; i--) {
p._setEndLocation(p.openElements.items[i], token);
}
if (!p.fragmentContext && p.openElements.stackTop >= 0) {
const htmlElement = p.openElements.items[0];
const htmlLocation = p.treeAdapter.getNodeSourceCodeLocation(htmlElement);
if (htmlLocation && !htmlLocation.endTag) {
p._setEndLocation(htmlElement, token);
if (p.openElements.stackTop >= 1) {
const bodyElement = p.openElements.items[1];
const bodyLocation = p.treeAdapter.getNodeSourceCodeLocation(bodyElement);
if (bodyLocation && !bodyLocation.endTag) {
p._setEndLocation(bodyElement, token);
}
}
}
}
}
}
function doctypeInInitialMode(p, token) {
p._setDocumentType(token);
const mode = token.forceQuirks ? DOCUMENT_MODE.QUIRKS : getDocumentMode(token);
if (!isConforming(token)) {
p._err(token, ERR.nonConformingDoctype);
}
p.treeAdapter.setDocumentMode(p.document, mode);
p.insertionMode = InsertionMode.BEFORE_HTML;
}
function tokenInInitialMode(p, token) {
p._err(token, ERR.missingDoctype, true);
p.treeAdapter.setDocumentMode(p.document, DOCUMENT_MODE.QUIRKS);
p.insertionMode = InsertionMode.BEFORE_HTML;
p._processToken(token);
}
function startTagBeforeHtml(p, token) {
if (token.tagID === TAG_ID.HTML) {
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.BEFORE_HEAD;
} else {
tokenBeforeHtml(p, token);
}
}
function endTagBeforeHtml(p, token) {
const tn = token.tagID;
if (tn === TAG_ID.HTML || tn === TAG_ID.HEAD || tn === TAG_ID.BODY || tn === TAG_ID.BR) {
tokenBeforeHtml(p, token);
}
}
function tokenBeforeHtml(p, token) {
p._insertFakeRootElement();
p.insertionMode = InsertionMode.BEFORE_HEAD;
p._processToken(token);
}
function startTagBeforeHead(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.HEAD: {
p._insertElement(token, NS.HTML);
p.headElement = p.openElements.current;
p.insertionMode = InsertionMode.IN_HEAD;
break;
}
default: {
tokenBeforeHead(p, token);
}
}
}
function endTagBeforeHead(p, token) {
const tn = token.tagID;
if (tn === TAG_ID.HEAD || tn === TAG_ID.BODY || tn === TAG_ID.HTML || tn === TAG_ID.BR) {
tokenBeforeHead(p, token);
} else {
p._err(token, ERR.endTagWithoutMatchingOpenElement);
}
}
function tokenBeforeHead(p, token) {
p._insertFakeElement(TAG_NAMES.HEAD, TAG_ID.HEAD);
p.headElement = p.openElements.current;
p.insertionMode = InsertionMode.IN_HEAD;
p._processToken(token);
}
function startTagInHead(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.BASE:
case TAG_ID.BASEFONT:
case TAG_ID.BGSOUND:
case TAG_ID.LINK:
case TAG_ID.META: {
p._appendElement(token, NS.HTML);
token.ackSelfClosing = true;
break;
}
case TAG_ID.TITLE: {
p._switchToTextParsing(token, TokenizerMode.RCDATA);
break;
}
case TAG_ID.NOSCRIPT: {
if (p.options.scriptingEnabled) {
p._switchToTextParsing(token, TokenizerMode.RAWTEXT);
} else {
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_HEAD_NO_SCRIPT;
}
break;
}
case TAG_ID.NOFRAMES:
case TAG_ID.STYLE: {
p._switchToTextParsing(token, TokenizerMode.RAWTEXT);
break;
}
case TAG_ID.SCRIPT: {
p._switchToTextParsing(token, TokenizerMode.SCRIPT_DATA);
break;
}
case TAG_ID.TEMPLATE: {
p._insertTemplate(token);
p.activeFormattingElements.insertMarker();
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_TEMPLATE;
p.tmplInsertionModeStack.unshift(InsertionMode.IN_TEMPLATE);
break;
}
case TAG_ID.HEAD: {
p._err(token, ERR.misplacedStartTagForHeadElement);
break;
}
default: {
tokenInHead(p, token);
}
}
}
function endTagInHead(p, token) {
switch (token.tagID) {
case TAG_ID.HEAD: {
p.openElements.pop();
p.insertionMode = InsertionMode.AFTER_HEAD;
break;
}
case TAG_ID.BODY:
case TAG_ID.BR:
case TAG_ID.HTML: {
tokenInHead(p, token);
break;
}
case TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
p._err(token, ERR.endTagWithoutMatchingOpenElement);
}
}
}
function templateEndTagInHead(p, token) {
if (p.openElements.tmplCount > 0) {
p.openElements.generateImpliedEndTagsThoroughly();
if (p.openElements.currentTagId !== TAG_ID.TEMPLATE) {
p._err(token, ERR.closingOfElementWithOpenChildElements);
}
p.openElements.popUntilTagNamePopped(TAG_ID.TEMPLATE);
p.activeFormattingElements.clearToLastMarker();
p.tmplInsertionModeStack.shift();
p._resetInsertionMode();
} else {
p._err(token, ERR.endTagWithoutMatchingOpenElement);
}
}
function tokenInHead(p, token) {
p.openElements.pop();
p.insertionMode = InsertionMode.AFTER_HEAD;
p._processToken(token);
}
function startTagInHeadNoScript(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.BASEFONT:
case TAG_ID.BGSOUND:
case TAG_ID.HEAD:
case TAG_ID.LINK:
case TAG_ID.META:
case TAG_ID.NOFRAMES:
case TAG_ID.STYLE: {
startTagInHead(p, token);
break;
}
case TAG_ID.NOSCRIPT: {
p._err(token, ERR.nestedNoscriptInHead);
break;
}
default: {
tokenInHeadNoScript(p, token);
}
}
}
function endTagInHeadNoScript(p, token) {
switch (token.tagID) {
case TAG_ID.NOSCRIPT: {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_HEAD;
break;
}
case TAG_ID.BR: {
tokenInHeadNoScript(p, token);
break;
}
default: {
p._err(token, ERR.endTagWithoutMatchingOpenElement);
}
}
}
function tokenInHeadNoScript(p, token) {
const errCode = token.type === TokenType.EOF ? ERR.openElementsLeftAfterEof : ERR.disallowedContentInNoscriptInHead;
p._err(token, errCode);
p.openElements.pop();
p.insertionMode = InsertionMode.IN_HEAD;
p._processToken(token);
}
function startTagAfterHead(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.BODY: {
p._insertElement(token, NS.HTML);
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_BODY;
break;
}
case TAG_ID.FRAMESET: {
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_FRAMESET;
break;
}
case TAG_ID.BASE:
case TAG_ID.BASEFONT:
case TAG_ID.BGSOUND:
case TAG_ID.LINK:
case TAG_ID.META:
case TAG_ID.NOFRAMES:
case TAG_ID.SCRIPT:
case TAG_ID.STYLE:
case TAG_ID.TEMPLATE:
case TAG_ID.TITLE: {
p._err(token, ERR.abandonedHeadElementChild);
p.openElements.push(p.headElement, TAG_ID.HEAD);
startTagInHead(p, token);
p.openElements.remove(p.headElement);
break;
}
case TAG_ID.HEAD: {
p._err(token, ERR.misplacedStartTagForHeadElement);
break;
}
default: {
tokenAfterHead(p, token);
}
}
}
function endTagAfterHead(p, token) {
switch (token.tagID) {
case TAG_ID.BODY:
case TAG_ID.HTML:
case TAG_ID.BR: {
tokenAfterHead(p, token);
break;
}
case TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
p._err(token, ERR.endTagWithoutMatchingOpenElement);
}
}
}
function tokenAfterHead(p, token) {
p._insertFakeElement(TAG_NAMES.BODY, TAG_ID.BODY);
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
function modeInBody(p, token) {
switch (token.type) {
case TokenType.CHARACTER: {
characterInBody(p, token);
break;
}
case TokenType.WHITESPACE_CHARACTER: {
whitespaceCharacterInBody(p, token);
break;
}
case TokenType.COMMENT: {
appendComment(p, token);
break;
}
case TokenType.START_TAG: {
startTagInBody(p, token);
break;
}
case TokenType.END_TAG: {
endTagInBody(p, token);
break;
}
case TokenType.EOF: {
eofInBody(p, token);
break;
}
default:
}
}
function whitespaceCharacterInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertCharacters(token);
}
function characterInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertCharacters(token);
p.framesetOk = false;
}
function htmlStartTagInBody(p, token) {
if (p.openElements.tmplCount === 0) {
p.treeAdapter.adoptAttributes(p.openElements.items[0], token.attrs);
}
}
function bodyStartTagInBody(p, token) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (bodyElement && p.openElements.tmplCount === 0) {
p.framesetOk = false;
p.treeAdapter.adoptAttributes(bodyElement, token.attrs);
}
}
function framesetStartTagInBody(p, token) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (p.framesetOk && bodyElement) {
p.treeAdapter.detachNode(bodyElement);
p.openElements.popAllUpToHtmlElement();
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_FRAMESET;
}
}
function addressStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, NS.HTML);
}
function numberedHeaderStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
if (NUMBERED_HEADERS.has(p.openElements.currentTagId)) {
p.openElements.pop();
}
p._insertElement(token, NS.HTML);
}
function preStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, NS.HTML);
p.skipNextNewLine = true;
p.framesetOk = false;
}
function formStartTagInBody(p, token) {
const inTemplate = p.openElements.tmplCount > 0;
if (!p.formElement || inTemplate) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, NS.HTML);
if (!inTemplate) {
p.formElement = p.openElements.current;
}
}
}
function listItemStartTagInBody(p, token) {
p.framesetOk = false;
const tn = token.tagID;
for (let i = p.openElements.stackTop; i >= 0; i--) {
const elementId = p.openElements.tagIDs[i];
if (tn === TAG_ID.LI && elementId === TAG_ID.LI || (tn === TAG_ID.DD || tn === TAG_ID.DT) && (elementId === TAG_ID.DD || elementId === TAG_ID.DT)) {
p.openElements.generateImpliedEndTagsWithExclusion(elementId);
p.openElements.popUntilTagNamePopped(elementId);
break;
}
if (elementId !== TAG_ID.ADDRESS && elementId !== TAG_ID.DIV && elementId !== TAG_ID.P && p._isSpecialElement(p.openElements.items[i], elementId)) {
break;
}
}
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, NS.HTML);
}
function plaintextStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, NS.HTML);
p.tokenizer.state = TokenizerMode.PLAINTEXT;
}
function buttonStartTagInBody(p, token) {
if (p.openElements.hasInScope(TAG_ID.BUTTON)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(TAG_ID.BUTTON);
}
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
p.framesetOk = false;
}
function aStartTagInBody(p, token) {
const activeElementEntry = p.activeFormattingElements.getElementEntryInScopeWithTagName(TAG_NAMES.A);
if (activeElementEntry) {
callAdoptionAgency(p, token);
p.openElements.remove(activeElementEntry.element);
p.activeFormattingElements.removeEntry(activeElementEntry);
}
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function bStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function nobrStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
if (p.openElements.hasInScope(TAG_ID.NOBR)) {
callAdoptionAgency(p, token);
p._reconstructActiveFormattingElements();
}
p._insertElement(token, NS.HTML);
p.activeFormattingElements.pushElement(p.openElements.current, token);
}
function appletStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
p.activeFormattingElements.insertMarker();
p.framesetOk = false;
}
function tableStartTagInBody(p, token) {
if (p.treeAdapter.getDocumentMode(p.document) !== DOCUMENT_MODE.QUIRKS && p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._insertElement(token, NS.HTML);
p.framesetOk = false;
p.insertionMode = InsertionMode.IN_TABLE;
}
function areaStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._appendElement(token, NS.HTML);
p.framesetOk = false;
token.ackSelfClosing = true;
}
function isHiddenInput(token) {
const inputType = getTokenAttr(token, ATTRS.TYPE);
return inputType != null && inputType.toLowerCase() === HIDDEN_INPUT_TYPE;
}
function inputStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._appendElement(token, NS.HTML);
if (!isHiddenInput(token)) {
p.framesetOk = false;
}
token.ackSelfClosing = true;
}
function paramStartTagInBody(p, token) {
p._appendElement(token, NS.HTML);
token.ackSelfClosing = true;
}
function hrStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._appendElement(token, NS.HTML);
p.framesetOk = false;
token.ackSelfClosing = true;
}
function imageStartTagInBody(p, token) {
token.tagName = TAG_NAMES.IMG;
token.tagID = TAG_ID.IMG;
areaStartTagInBody(p, token);
}
function textareaStartTagInBody(p, token) {
p._insertElement(token, NS.HTML);
p.skipNextNewLine = true;
p.tokenizer.state = TokenizerMode.RCDATA;
p.originalInsertionMode = p.insertionMode;
p.framesetOk = false;
p.insertionMode = InsertionMode.TEXT;
}
function xmpStartTagInBody(p, token) {
if (p.openElements.hasInButtonScope(TAG_ID.P)) {
p._closePElement();
}
p._reconstructActiveFormattingElements();
p.framesetOk = false;
p._switchToTextParsing(token, TokenizerMode.RAWTEXT);
}
function iframeStartTagInBody(p, token) {
p.framesetOk = false;
p._switchToTextParsing(token, TokenizerMode.RAWTEXT);
}
function rawTextStartTagInBody(p, token) {
p._switchToTextParsing(token, TokenizerMode.RAWTEXT);
}
function selectStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
p.framesetOk = false;
p.insertionMode = p.insertionMode === InsertionMode.IN_TABLE || p.insertionMode === InsertionMode.IN_CAPTION || p.insertionMode === InsertionMode.IN_TABLE_BODY || p.insertionMode === InsertionMode.IN_ROW || p.insertionMode === InsertionMode.IN_CELL ? InsertionMode.IN_SELECT_IN_TABLE : InsertionMode.IN_SELECT;
}
function optgroupStartTagInBody(p, token) {
if (p.openElements.currentTagId === TAG_ID.OPTION) {
p.openElements.pop();
}
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
}
function rbStartTagInBody(p, token) {
if (p.openElements.hasInScope(TAG_ID.RUBY)) {
p.openElements.generateImpliedEndTags();
}
p._insertElement(token, NS.HTML);
}
function rtStartTagInBody(p, token) {
if (p.openElements.hasInScope(TAG_ID.RUBY)) {
p.openElements.generateImpliedEndTagsWithExclusion(TAG_ID.RTC);
}
p._insertElement(token, NS.HTML);
}
function mathStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
adjustTokenMathMLAttrs(token);
adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, NS.MATHML);
} else {
p._insertElement(token, NS.MATHML);
}
token.ackSelfClosing = true;
}
function svgStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
adjustTokenSVGAttrs(token);
adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, NS.SVG);
} else {
p._insertElement(token, NS.SVG);
}
token.ackSelfClosing = true;
}
function genericStartTagInBody(p, token) {
p._reconstructActiveFormattingElements();
p._insertElement(token, NS.HTML);
}
function startTagInBody(p, token) {
switch (token.tagID) {
case TAG_ID.I:
case TAG_ID.S:
case TAG_ID.B:
case TAG_ID.U:
case TAG_ID.EM:
case TAG_ID.TT:
case TAG_ID.BIG:
case TAG_ID.CODE:
case TAG_ID.FONT:
case TAG_ID.SMALL:
case TAG_ID.STRIKE:
case TAG_ID.STRONG: {
bStartTagInBody(p, token);
break;
}
case TAG_ID.A: {
aStartTagInBody(p, token);
break;
}
case TAG_ID.H1:
case TAG_ID.H2:
case TAG_ID.H3:
case TAG_ID.H4:
case TAG_ID.H5:
case TAG_ID.H6: {
numberedHeaderStartTagInBody(p, token);
break;
}
case TAG_ID.P:
case TAG_ID.DL:
case TAG_ID.OL:
case TAG_ID.UL:
case TAG_ID.DIV:
case TAG_ID.DIR:
case TAG_ID.NAV:
case TAG_ID.MAIN:
case TAG_ID.MENU:
case TAG_ID.ASIDE:
case TAG_ID.CENTER:
case TAG_ID.FIGURE:
case TAG_ID.FOOTER:
case TAG_ID.HEADER:
case TAG_ID.HGROUP:
case TAG_ID.DIALOG:
case TAG_ID.DETAILS:
case TAG_ID.ADDRESS:
case TAG_ID.ARTICLE:
case TAG_ID.SEARCH:
case TAG_ID.SECTION:
case TAG_ID.SUMMARY:
case TAG_ID.FIELDSET:
case TAG_ID.BLOCKQUOTE:
case TAG_ID.FIGCAPTION: {
addressStartTagInBody(p, token);
break;
}
case TAG_ID.LI:
case TAG_ID.DD:
case TAG_ID.DT: {
listItemStartTagInBody(p, token);
break;
}
case TAG_ID.BR:
case TAG_ID.IMG:
case TAG_ID.WBR:
case TAG_ID.AREA:
case TAG_ID.EMBED:
case TAG_ID.KEYGEN: {
areaStartTagInBody(p, token);
break;
}
case TAG_ID.HR: {
hrStartTagInBody(p, token);
break;
}
case TAG_ID.RB:
case TAG_ID.RTC: {
rbStartTagInBody(p, token);
break;
}
case TAG_ID.RT:
case TAG_ID.RP: {
rtStartTagInBody(p, token);
break;
}
case TAG_ID.PRE:
case TAG_ID.LISTING: {
preStartTagInBody(p, token);
break;
}
case TAG_ID.XMP: {
xmpStartTagInBody(p, token);
break;
}
case TAG_ID.SVG: {
svgStartTagInBody(p, token);
break;
}
case TAG_ID.HTML: {
htmlStartTagInBody(p, token);
break;
}
case TAG_ID.BASE:
case TAG_ID.LINK:
case TAG_ID.META:
case TAG_ID.STYLE:
case TAG_ID.TITLE:
case TAG_ID.SCRIPT:
case TAG_ID.BGSOUND:
case TAG_ID.BASEFONT:
case TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
case TAG_ID.BODY: {
bodyStartTagInBody(p, token);
break;
}
case TAG_ID.FORM: {
formStartTagInBody(p, token);
break;
}
case TAG_ID.NOBR: {
nobrStartTagInBody(p, token);
break;
}
case TAG_ID.MATH: {
mathStartTagInBody(p, token);
break;
}
case TAG_ID.TABLE: {
tableStartTagInBody(p, token);
break;
}
case TAG_ID.INPUT: {
inputStartTagInBody(p, token);
break;
}
case TAG_ID.PARAM:
case TAG_ID.TRACK:
case TAG_ID.SOURCE: {
paramStartTagInBody(p, token);
break;
}
case TAG_ID.IMAGE: {
imageStartTagInBody(p, token);
break;
}
case TAG_ID.BUTTON: {
buttonStartTagInBody(p, token);
break;
}
case TAG_ID.APPLET:
case TAG_ID.OBJECT:
case TAG_ID.MARQUEE: {
appletStartTagInBody(p, token);
break;
}
case TAG_ID.IFRAME: {
iframeStartTagInBody(p, token);
break;
}
case TAG_ID.SELECT: {
selectStartTagInBody(p, token);
break;
}
case TAG_ID.OPTION:
case TAG_ID.OPTGROUP: {
optgroupStartTagInBody(p, token);
break;
}
case TAG_ID.NOEMBED:
case TAG_ID.NOFRAMES: {
rawTextStartTagInBody(p, token);
break;
}
case TAG_ID.FRAMESET: {
framesetStartTagInBody(p, token);
break;
}
case TAG_ID.TEXTAREA: {
textareaStartTagInBody(p, token);
break;
}
case TAG_ID.NOSCRIPT: {
if (p.options.scriptingEnabled) {
rawTextStartTagInBody(p, token);
} else {
genericStartTagInBody(p, token);
}
break;
}
case TAG_ID.PLAINTEXT: {
plaintextStartTagInBody(p, token);
break;
}
case TAG_ID.COL:
case TAG_ID.TH:
case TAG_ID.TD:
case TAG_ID.TR:
case TAG_ID.HEAD:
case TAG_ID.FRAME:
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD:
case TAG_ID.CAPTION:
case TAG_ID.COLGROUP: {
break;
}
default: {
genericStartTagInBody(p, token);
}
}
}
function bodyEndTagInBody(p, token) {
if (p.openElements.hasInScope(TAG_ID.BODY)) {
p.insertionMode = InsertionMode.AFTER_BODY;
if (p.options.sourceCodeLocationInfo) {
const bodyElement = p.openElements.tryPeekProperlyNestedBodyElement();
if (bodyElement) {
p._setEndLocation(bodyElement, token);
}
}
}
}
function htmlEndTagInBody(p, token) {
if (p.openElements.hasInScope(TAG_ID.BODY)) {
p.insertionMode = InsertionMode.AFTER_BODY;
endTagAfterBody(p, token);
}
}
function addressEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
}
}
function formEndTagInBody(p) {
const inTemplate = p.openElements.tmplCount > 0;
const { formElement } = p;
if (!inTemplate) {
p.formElement = null;
}
if ((formElement || inTemplate) && p.openElements.hasInScope(TAG_ID.FORM)) {
p.openElements.generateImpliedEndTags();
if (inTemplate) {
p.openElements.popUntilTagNamePopped(TAG_ID.FORM);
} else if (formElement) {
p.openElements.remove(formElement);
}
}
}
function pEndTagInBody(p) {
if (!p.openElements.hasInButtonScope(TAG_ID.P)) {
p._insertFakeElement(TAG_NAMES.P, TAG_ID.P);
}
p._closePElement();
}
function liEndTagInBody(p) {
if (p.openElements.hasInListItemScope(TAG_ID.LI)) {
p.openElements.generateImpliedEndTagsWithExclusion(TAG_ID.LI);
p.openElements.popUntilTagNamePopped(TAG_ID.LI);
}
}
function ddEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTagsWithExclusion(tn);
p.openElements.popUntilTagNamePopped(tn);
}
}
function numberedHeaderEndTagInBody(p) {
if (p.openElements.hasNumberedHeaderInScope()) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilNumberedHeaderPopped();
}
}
function appletEndTagInBody(p, token) {
const tn = token.tagID;
if (p.openElements.hasInScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
p.activeFormattingElements.clearToLastMarker();
}
}
function brEndTagInBody(p) {
p._reconstructActiveFormattingElements();
p._insertFakeElement(TAG_NAMES.BR, TAG_ID.BR);
p.openElements.pop();
p.framesetOk = false;
}
function genericEndTagInBody(p, token) {
const tn = token.tagName;
const tid = token.tagID;
for (let i = p.openElements.stackTop; i > 0; i--) {
const element = p.openElements.items[i];
const elementId = p.openElements.tagIDs[i];
if (tid === elementId && (tid !== TAG_ID.UNKNOWN || p.treeAdapter.getTagName(element) === tn)) {
p.openElements.generateImpliedEndTagsWithExclusion(tid);
if (p.openElements.stackTop >= i)
p.openElements.shortenToLength(i);
break;
}
if (p._isSpecialElement(element, elementId)) {
break;
}
}
}
function endTagInBody(p, token) {
switch (token.tagID) {
case TAG_ID.A:
case TAG_ID.B:
case TAG_ID.I:
case TAG_ID.S:
case TAG_ID.U:
case TAG_ID.EM:
case TAG_ID.TT:
case TAG_ID.BIG:
case TAG_ID.CODE:
case TAG_ID.FONT:
case TAG_ID.NOBR:
case TAG_ID.SMALL:
case TAG_ID.STRIKE:
case TAG_ID.STRONG: {
callAdoptionAgency(p, token);
break;
}
case TAG_ID.P: {
pEndTagInBody(p);
break;
}
case TAG_ID.DL:
case TAG_ID.UL:
case TAG_ID.OL:
case TAG_ID.DIR:
case TAG_ID.DIV:
case TAG_ID.NAV:
case TAG_ID.PRE:
case TAG_ID.MAIN:
case TAG_ID.MENU:
case TAG_ID.ASIDE:
case TAG_ID.BUTTON:
case TAG_ID.CENTER:
case TAG_ID.FIGURE:
case TAG_ID.FOOTER:
case TAG_ID.HEADER:
case TAG_ID.HGROUP:
case TAG_ID.DIALOG:
case TAG_ID.ADDRESS:
case TAG_ID.ARTICLE:
case TAG_ID.DETAILS:
case TAG_ID.SEARCH:
case TAG_ID.SECTION:
case TAG_ID.SUMMARY:
case TAG_ID.LISTING:
case TAG_ID.FIELDSET:
case TAG_ID.BLOCKQUOTE:
case TAG_ID.FIGCAPTION: {
addressEndTagInBody(p, token);
break;
}
case TAG_ID.LI: {
liEndTagInBody(p);
break;
}
case TAG_ID.DD:
case TAG_ID.DT: {
ddEndTagInBody(p, token);
break;
}
case TAG_ID.H1:
case TAG_ID.H2:
case TAG_ID.H3:
case TAG_ID.H4:
case TAG_ID.H5:
case TAG_ID.H6: {
numberedHeaderEndTagInBody(p);
break;
}
case TAG_ID.BR: {
brEndTagInBody(p);
break;
}
case TAG_ID.BODY: {
bodyEndTagInBody(p, token);
break;
}
case TAG_ID.HTML: {
htmlEndTagInBody(p, token);
break;
}
case TAG_ID.FORM: {
formEndTagInBody(p);
break;
}
case TAG_ID.APPLET:
case TAG_ID.OBJECT:
case TAG_ID.MARQUEE: {
appletEndTagInBody(p, token);
break;
}
case TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default: {
genericEndTagInBody(p, token);
}
}
}
function eofInBody(p, token) {
if (p.tmplInsertionModeStack.length > 0) {
eofInTemplate(p, token);
} else {
stopParsing(p, token);
}
}
function endTagInText(p, token) {
var _a2;
if (token.tagID === TAG_ID.SCRIPT) {
(_a2 = p.scriptHandler) === null || _a2 === void 0 ? void 0 : _a2.call(p, p.openElements.current);
}
p.openElements.pop();
p.insertionMode = p.originalInsertionMode;
}
function eofInText(p, token) {
p._err(token, ERR.eofInElementThatCanContainOnlyText);
p.openElements.pop();
p.insertionMode = p.originalInsertionMode;
p.onEof(token);
}
function characterInTable(p, token) {
if (TABLE_STRUCTURE_TAGS.has(p.openElements.currentTagId)) {
p.pendingCharacterTokens.length = 0;
p.hasNonWhitespacePendingCharacterToken = false;
p.originalInsertionMode = p.insertionMode;
p.insertionMode = InsertionMode.IN_TABLE_TEXT;
switch (token.type) {
case TokenType.CHARACTER: {
characterInTableText(p, token);
break;
}
case TokenType.WHITESPACE_CHARACTER: {
whitespaceCharacterInTableText(p, token);
break;
}
}
} else {
tokenInTable(p, token);
}
}
function captionStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p.activeFormattingElements.insertMarker();
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_CAPTION;
}
function colgroupStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
}
function colStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertFakeElement(TAG_NAMES.COLGROUP, TAG_ID.COLGROUP);
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
startTagInColumnGroup(p, token);
}
function tbodyStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_TABLE_BODY;
}
function tdStartTagInTable(p, token) {
p.openElements.clearBackToTableContext();
p._insertFakeElement(TAG_NAMES.TBODY, TAG_ID.TBODY);
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
}
function tableStartTagInTable(p, token) {
if (p.openElements.hasInTableScope(TAG_ID.TABLE)) {
p.openElements.popUntilTagNamePopped(TAG_ID.TABLE);
p._resetInsertionMode();
p._processStartTag(token);
}
}
function inputStartTagInTable(p, token) {
if (isHiddenInput(token)) {
p._appendElement(token, NS.HTML);
} else {
tokenInTable(p, token);
}
token.ackSelfClosing = true;
}
function formStartTagInTable(p, token) {
if (!p.formElement && p.openElements.tmplCount === 0) {
p._insertElement(token, NS.HTML);
p.formElement = p.openElements.current;
p.openElements.pop();
}
}
function startTagInTable(p, token) {
switch (token.tagID) {
case TAG_ID.TD:
case TAG_ID.TH:
case TAG_ID.TR: {
tdStartTagInTable(p, token);
break;
}
case TAG_ID.STYLE:
case TAG_ID.SCRIPT:
case TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
case TAG_ID.COL: {
colStartTagInTable(p, token);
break;
}
case TAG_ID.FORM: {
formStartTagInTable(p, token);
break;
}
case TAG_ID.TABLE: {
tableStartTagInTable(p, token);
break;
}
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD: {
tbodyStartTagInTable(p, token);
break;
}
case TAG_ID.INPUT: {
inputStartTagInTable(p, token);
break;
}
case TAG_ID.CAPTION: {
captionStartTagInTable(p, token);
break;
}
case TAG_ID.COLGROUP: {
colgroupStartTagInTable(p, token);
break;
}
default: {
tokenInTable(p, token);
}
}
}
function endTagInTable(p, token) {
switch (token.tagID) {
case TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(TAG_ID.TABLE)) {
p.openElements.popUntilTagNamePopped(TAG_ID.TABLE);
p._resetInsertionMode();
}
break;
}
case TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
case TAG_ID.BODY:
case TAG_ID.CAPTION:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.HTML:
case TAG_ID.TBODY:
case TAG_ID.TD:
case TAG_ID.TFOOT:
case TAG_ID.TH:
case TAG_ID.THEAD:
case TAG_ID.TR: {
break;
}
default: {
tokenInTable(p, token);
}
}
}
function tokenInTable(p, token) {
const savedFosterParentingState = p.fosterParentingEnabled;
p.fosterParentingEnabled = true;
modeInBody(p, token);
p.fosterParentingEnabled = savedFosterParentingState;
}
function whitespaceCharacterInTableText(p, token) {
p.pendingCharacterTokens.push(token);
}
function characterInTableText(p, token) {
p.pendingCharacterTokens.push(token);
p.hasNonWhitespacePendingCharacterToken = true;
}
function tokenInTableText(p, token) {
let i = 0;
if (p.hasNonWhitespacePendingCharacterToken) {
for (; i < p.pendingCharacterTokens.length; i++) {
tokenInTable(p, p.pendingCharacterTokens[i]);
}
} else {
for (; i < p.pendingCharacterTokens.length; i++) {
p._insertCharacters(p.pendingCharacterTokens[i]);
}
}
p.insertionMode = p.originalInsertionMode;
p._processToken(token);
}
var TABLE_VOID_ELEMENTS = /* @__PURE__ */ new Set([TAG_ID.CAPTION, TAG_ID.COL, TAG_ID.COLGROUP, TAG_ID.TBODY, TAG_ID.TD, TAG_ID.TFOOT, TAG_ID.TH, TAG_ID.THEAD, TAG_ID.TR]);
function startTagInCaption(p, token) {
const tn = token.tagID;
if (TABLE_VOID_ELEMENTS.has(tn)) {
if (p.openElements.hasInTableScope(TAG_ID.CAPTION)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(TAG_ID.CAPTION);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
}
} else {
startTagInBody(p, token);
}
}
function endTagInCaption(p, token) {
const tn = token.tagID;
switch (tn) {
case TAG_ID.CAPTION:
case TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(TAG_ID.CAPTION)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(TAG_ID.CAPTION);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_TABLE;
if (tn === TAG_ID.TABLE) {
endTagInTable(p, token);
}
}
break;
}
case TAG_ID.BODY:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.HTML:
case TAG_ID.TBODY:
case TAG_ID.TD:
case TAG_ID.TFOOT:
case TAG_ID.TH:
case TAG_ID.THEAD:
case TAG_ID.TR: {
break;
}
default: {
endTagInBody(p, token);
}
}
}
function startTagInColumnGroup(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.COL: {
p._appendElement(token, NS.HTML);
token.ackSelfClosing = true;
break;
}
case TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
default: {
tokenInColumnGroup(p, token);
}
}
}
function endTagInColumnGroup(p, token) {
switch (token.tagID) {
case TAG_ID.COLGROUP: {
if (p.openElements.currentTagId === TAG_ID.COLGROUP) {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
}
break;
}
case TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
case TAG_ID.COL: {
break;
}
default: {
tokenInColumnGroup(p, token);
}
}
}
function tokenInColumnGroup(p, token) {
if (p.openElements.currentTagId === TAG_ID.COLGROUP) {
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
p._processToken(token);
}
}
function startTagInTableBody(p, token) {
switch (token.tagID) {
case TAG_ID.TR: {
p.openElements.clearBackToTableBodyContext();
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_ROW;
break;
}
case TAG_ID.TH:
case TAG_ID.TD: {
p.openElements.clearBackToTableBodyContext();
p._insertFakeElement(TAG_NAMES.TR, TAG_ID.TR);
p.insertionMode = InsertionMode.IN_ROW;
startTagInRow(p, token);
break;
}
case TAG_ID.CAPTION:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD: {
if (p.openElements.hasTableBodyContextInTableScope()) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
}
break;
}
default: {
startTagInTable(p, token);
}
}
}
function endTagInTableBody(p, token) {
const tn = token.tagID;
switch (token.tagID) {
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD: {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
}
break;
}
case TAG_ID.TABLE: {
if (p.openElements.hasTableBodyContextInTableScope()) {
p.openElements.clearBackToTableBodyContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE;
endTagInTable(p, token);
}
break;
}
case TAG_ID.BODY:
case TAG_ID.CAPTION:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.HTML:
case TAG_ID.TD:
case TAG_ID.TH:
case TAG_ID.TR: {
break;
}
default: {
endTagInTable(p, token);
}
}
}
function startTagInRow(p, token) {
switch (token.tagID) {
case TAG_ID.TH:
case TAG_ID.TD: {
p.openElements.clearBackToTableRowContext();
p._insertElement(token, NS.HTML);
p.insertionMode = InsertionMode.IN_CELL;
p.activeFormattingElements.insertMarker();
break;
}
case TAG_ID.CAPTION:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD:
case TAG_ID.TR: {
if (p.openElements.hasInTableScope(TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
}
break;
}
default: {
startTagInTable(p, token);
}
}
}
function endTagInRow(p, token) {
switch (token.tagID) {
case TAG_ID.TR: {
if (p.openElements.hasInTableScope(TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
}
break;
}
case TAG_ID.TABLE: {
if (p.openElements.hasInTableScope(TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
endTagInTableBody(p, token);
}
break;
}
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD: {
if (p.openElements.hasInTableScope(token.tagID) || p.openElements.hasInTableScope(TAG_ID.TR)) {
p.openElements.clearBackToTableRowContext();
p.openElements.pop();
p.insertionMode = InsertionMode.IN_TABLE_BODY;
endTagInTableBody(p, token);
}
break;
}
case TAG_ID.BODY:
case TAG_ID.CAPTION:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.HTML:
case TAG_ID.TD:
case TAG_ID.TH: {
break;
}
default: {
endTagInTable(p, token);
}
}
}
function startTagInCell(p, token) {
const tn = token.tagID;
if (TABLE_VOID_ELEMENTS.has(tn)) {
if (p.openElements.hasInTableScope(TAG_ID.TD) || p.openElements.hasInTableScope(TAG_ID.TH)) {
p._closeTableCell();
startTagInRow(p, token);
}
} else {
startTagInBody(p, token);
}
}
function endTagInCell(p, token) {
const tn = token.tagID;
switch (tn) {
case TAG_ID.TD:
case TAG_ID.TH: {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.generateImpliedEndTags();
p.openElements.popUntilTagNamePopped(tn);
p.activeFormattingElements.clearToLastMarker();
p.insertionMode = InsertionMode.IN_ROW;
}
break;
}
case TAG_ID.TABLE:
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD:
case TAG_ID.TR: {
if (p.openElements.hasInTableScope(tn)) {
p._closeTableCell();
endTagInRow(p, token);
}
break;
}
case TAG_ID.BODY:
case TAG_ID.CAPTION:
case TAG_ID.COL:
case TAG_ID.COLGROUP:
case TAG_ID.HTML: {
break;
}
default: {
endTagInBody(p, token);
}
}
}
function startTagInSelect(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.OPTION: {
if (p.openElements.currentTagId === TAG_ID.OPTION) {
p.openElements.pop();
}
p._insertElement(token, NS.HTML);
break;
}
case TAG_ID.OPTGROUP: {
if (p.openElements.currentTagId === TAG_ID.OPTION) {
p.openElements.pop();
}
if (p.openElements.currentTagId === TAG_ID.OPTGROUP) {
p.openElements.pop();
}
p._insertElement(token, NS.HTML);
break;
}
case TAG_ID.HR: {
if (p.openElements.currentTagId === TAG_ID.OPTION) {
p.openElements.pop();
}
if (p.openElements.currentTagId === TAG_ID.OPTGROUP) {
p.openElements.pop();
}
p._appendElement(token, NS.HTML);
token.ackSelfClosing = true;
break;
}
case TAG_ID.INPUT:
case TAG_ID.KEYGEN:
case TAG_ID.TEXTAREA:
case TAG_ID.SELECT: {
if (p.openElements.hasInSelectScope(TAG_ID.SELECT)) {
p.openElements.popUntilTagNamePopped(TAG_ID.SELECT);
p._resetInsertionMode();
if (token.tagID !== TAG_ID.SELECT) {
p._processStartTag(token);
}
}
break;
}
case TAG_ID.SCRIPT:
case TAG_ID.TEMPLATE: {
startTagInHead(p, token);
break;
}
default:
}
}
function endTagInSelect(p, token) {
switch (token.tagID) {
case TAG_ID.OPTGROUP: {
if (p.openElements.stackTop > 0 && p.openElements.currentTagId === TAG_ID.OPTION && p.openElements.tagIDs[p.openElements.stackTop - 1] === TAG_ID.OPTGROUP) {
p.openElements.pop();
}
if (p.openElements.currentTagId === TAG_ID.OPTGROUP) {
p.openElements.pop();
}
break;
}
case TAG_ID.OPTION: {
if (p.openElements.currentTagId === TAG_ID.OPTION) {
p.openElements.pop();
}
break;
}
case TAG_ID.SELECT: {
if (p.openElements.hasInSelectScope(TAG_ID.SELECT)) {
p.openElements.popUntilTagNamePopped(TAG_ID.SELECT);
p._resetInsertionMode();
}
break;
}
case TAG_ID.TEMPLATE: {
templateEndTagInHead(p, token);
break;
}
default:
}
}
function startTagInSelectInTable(p, token) {
const tn = token.tagID;
if (tn === TAG_ID.CAPTION || tn === TAG_ID.TABLE || tn === TAG_ID.TBODY || tn === TAG_ID.TFOOT || tn === TAG_ID.THEAD || tn === TAG_ID.TR || tn === TAG_ID.TD || tn === TAG_ID.TH) {
p.openElements.popUntilTagNamePopped(TAG_ID.SELECT);
p._resetInsertionMode();
p._processStartTag(token);
} else {
startTagInSelect(p, token);
}
}
function endTagInSelectInTable(p, token) {
const tn = token.tagID;
if (tn === TAG_ID.CAPTION || tn === TAG_ID.TABLE || tn === TAG_ID.TBODY || tn === TAG_ID.TFOOT || tn === TAG_ID.THEAD || tn === TAG_ID.TR || tn === TAG_ID.TD || tn === TAG_ID.TH) {
if (p.openElements.hasInTableScope(tn)) {
p.openElements.popUntilTagNamePopped(TAG_ID.SELECT);
p._resetInsertionMode();
p.onEndTag(token);
}
} else {
endTagInSelect(p, token);
}
}
function startTagInTemplate(p, token) {
switch (token.tagID) {
// First, handle tags that can start without a mode change
case TAG_ID.BASE:
case TAG_ID.BASEFONT:
case TAG_ID.BGSOUND:
case TAG_ID.LINK:
case TAG_ID.META:
case TAG_ID.NOFRAMES:
case TAG_ID.SCRIPT:
case TAG_ID.STYLE:
case TAG_ID.TEMPLATE:
case TAG_ID.TITLE: {
startTagInHead(p, token);
break;
}
// Re-process the token in the appropriate mode
case TAG_ID.CAPTION:
case TAG_ID.COLGROUP:
case TAG_ID.TBODY:
case TAG_ID.TFOOT:
case TAG_ID.THEAD: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE;
p.insertionMode = InsertionMode.IN_TABLE;
startTagInTable(p, token);
break;
}
case TAG_ID.COL: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_COLUMN_GROUP;
p.insertionMode = InsertionMode.IN_COLUMN_GROUP;
startTagInColumnGroup(p, token);
break;
}
case TAG_ID.TR: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_TABLE_BODY;
p.insertionMode = InsertionMode.IN_TABLE_BODY;
startTagInTableBody(p, token);
break;
}
case TAG_ID.TD:
case TAG_ID.TH: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_ROW;
p.insertionMode = InsertionMode.IN_ROW;
startTagInRow(p, token);
break;
}
default: {
p.tmplInsertionModeStack[0] = InsertionMode.IN_BODY;
p.insertionMode = InsertionMode.IN_BODY;
startTagInBody(p, token);
}
}
}
function endTagInTemplate(p, token) {
if (token.tagID === TAG_ID.TEMPLATE) {
templateEndTagInHead(p, token);
}
}
function eofInTemplate(p, token) {
if (p.openElements.tmplCount > 0) {
p.openElements.popUntilTagNamePopped(TAG_ID.TEMPLATE);
p.activeFormattingElements.clearToLastMarker();
p.tmplInsertionModeStack.shift();
p._resetInsertionMode();
p.onEof(token);
} else {
stopParsing(p, token);
}
}
function startTagAfterBody(p, token) {
if (token.tagID === TAG_ID.HTML) {
startTagInBody(p, token);
} else {
tokenAfterBody(p, token);
}
}
function endTagAfterBody(p, token) {
var _a2;
if (token.tagID === TAG_ID.HTML) {
if (!p.fragmentContext) {
p.insertionMode = InsertionMode.AFTER_AFTER_BODY;
}
if (p.options.sourceCodeLocationInfo && p.openElements.tagIDs[0] === TAG_ID.HTML) {
p._setEndLocation(p.openElements.items[0], token);
const bodyElement = p.openElements.items[1];
if (bodyElement && !((_a2 = p.treeAdapter.getNodeSourceCodeLocation(bodyElement)) === null || _a2 === void 0 ? void 0 : _a2.endTag)) {
p._setEndLocation(bodyElement, token);
}
}
} else {
tokenAfterBody(p, token);
}
}
function tokenAfterBody(p, token) {
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
function startTagInFrameset(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.FRAMESET: {
p._insertElement(token, NS.HTML);
break;
}
case TAG_ID.FRAME: {
p._appendElement(token, NS.HTML);
token.ackSelfClosing = true;
break;
}
case TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
default:
}
}
function endTagInFrameset(p, token) {
if (token.tagID === TAG_ID.FRAMESET && !p.openElements.isRootHtmlElementCurrent()) {
p.openElements.pop();
if (!p.fragmentContext && p.openElements.currentTagId !== TAG_ID.FRAMESET) {
p.insertionMode = InsertionMode.AFTER_FRAMESET;
}
}
}
function startTagAfterFrameset(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
default:
}
}
function endTagAfterFrameset(p, token) {
if (token.tagID === TAG_ID.HTML) {
p.insertionMode = InsertionMode.AFTER_AFTER_FRAMESET;
}
}
function startTagAfterAfterBody(p, token) {
if (token.tagID === TAG_ID.HTML) {
startTagInBody(p, token);
} else {
tokenAfterAfterBody(p, token);
}
}
function tokenAfterAfterBody(p, token) {
p.insertionMode = InsertionMode.IN_BODY;
modeInBody(p, token);
}
function startTagAfterAfterFrameset(p, token) {
switch (token.tagID) {
case TAG_ID.HTML: {
startTagInBody(p, token);
break;
}
case TAG_ID.NOFRAMES: {
startTagInHead(p, token);
break;
}
default:
}
}
function nullCharacterInForeignContent(p, token) {
token.chars = REPLACEMENT_CHARACTER;
p._insertCharacters(token);
}
function characterInForeignContent(p, token) {
p._insertCharacters(token);
p.framesetOk = false;
}
function popUntilHtmlOrIntegrationPoint(p) {
while (p.treeAdapter.getNamespaceURI(p.openElements.current) !== NS.HTML && !p._isIntegrationPoint(p.openElements.currentTagId, p.openElements.current)) {
p.openElements.pop();
}
}
function startTagInForeignContent(p, token) {
if (causesExit(token)) {
popUntilHtmlOrIntegrationPoint(p);
p._startTagOutsideForeignContent(token);
} else {
const current = p._getAdjustedCurrentElement();
const currentNs = p.treeAdapter.getNamespaceURI(current);
if (currentNs === NS.MATHML) {
adjustTokenMathMLAttrs(token);
} else if (currentNs === NS.SVG) {
adjustTokenSVGTagName(token);
adjustTokenSVGAttrs(token);
}
adjustTokenXMLAttrs(token);
if (token.selfClosing) {
p._appendElement(token, currentNs);
} else {
p._insertElement(token, currentNs);
}
token.ackSelfClosing = true;
}
}
function endTagInForeignContent(p, token) {
if (token.tagID === TAG_ID.P || token.tagID === TAG_ID.BR) {
popUntilHtmlOrIntegrationPoint(p);
p._endTagOutsideForeignContent(token);
return;
}
for (let i = p.openElements.stackTop; i > 0; i--) {
const element = p.openElements.items[i];
if (p.treeAdapter.getNamespaceURI(element) === NS.HTML) {
p._endTagOutsideForeignContent(token);
break;
}
const tagName = p.treeAdapter.getTagName(element);
if (tagName.toLowerCase() === token.tagName) {
token.tagName = tagName;
p.openElements.shortenToLength(i);
break;
}
}
}
// node_modules/entities/lib/esm/escape.js
var xmlCodeMap = /* @__PURE__ */ new Map([
[34, "&quot;"],
[38, "&amp;"],
[39, "&apos;"],
[60, "&lt;"],
[62, "&gt;"]
]);
var getCodePoint = (
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
String.prototype.codePointAt != null ? (str, index) => str.codePointAt(index) : (
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
(c, index) => (c.charCodeAt(index) & 64512) === 55296 ? (c.charCodeAt(index) - 55296) * 1024 + c.charCodeAt(index + 1) - 56320 + 65536 : c.charCodeAt(index)
)
);
function getEscaper(regex, map2) {
return function escape(data) {
let match;
let lastIdx = 0;
let result = "";
while (match = regex.exec(data)) {
if (lastIdx !== match.index) {
result += data.substring(lastIdx, match.index);
}
result += map2.get(match[0].charCodeAt(0));
lastIdx = match.index + 1;
}
return result + data.substring(lastIdx);
};
}
var escapeUTF8 = getEscaper(/[&<>'"]/g, xmlCodeMap);
var escapeAttribute = getEscaper(/["&\u00A0]/g, /* @__PURE__ */ new Map([
[34, "&quot;"],
[38, "&amp;"],
[160, "&nbsp;"]
]));
var escapeText = getEscaper(/[&<>\u00A0]/g, /* @__PURE__ */ new Map([
[38, "&amp;"],
[60, "&lt;"],
[62, "&gt;"],
[160, "&nbsp;"]
]));
// node_modules/parse5/dist/serializer/index.js
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
TAG_NAMES.AREA,
TAG_NAMES.BASE,
TAG_NAMES.BASEFONT,
TAG_NAMES.BGSOUND,
TAG_NAMES.BR,
TAG_NAMES.COL,
TAG_NAMES.EMBED,
TAG_NAMES.FRAME,
TAG_NAMES.HR,
TAG_NAMES.IMG,
TAG_NAMES.INPUT,
TAG_NAMES.KEYGEN,
TAG_NAMES.LINK,
TAG_NAMES.META,
TAG_NAMES.PARAM,
TAG_NAMES.SOURCE,
TAG_NAMES.TRACK,
TAG_NAMES.WBR
]);
// node_modules/parse5/dist/index.js
function parse(html, options) {
return Parser.parse(html, options);
}
function parseFragment(fragmentContext, html, options) {
if (typeof fragmentContext === "string") {
options = html;
html = fragmentContext;
fragmentContext = null;
}
const parser = Parser.getFragmentParser(fragmentContext, options);
parser.tokenizer.write(html, true);
return parser.getFragment();
}
// src/mock-doc/parse-util.ts
var docParser = /* @__PURE__ */ new WeakMap();
function parseDocumentUtil(ownerDocument, html) {
const doc = parse(html.trim(), getParser(ownerDocument));
doc.documentElement = doc.firstElementChild;
doc.head = doc.documentElement.firstElementChild;
doc.body = doc.head.nextElementSibling;
return doc;
}
function parseFragmentUtil(ownerDocument, html) {
if (typeof html === "string") {
html = html.trim();
} else {
html = "";
}
const frag = parseFragment(html, getParser(ownerDocument));
return frag;
}
function getParser(ownerDocument) {
let parseOptions = docParser.get(ownerDocument);
if (parseOptions != null) {
return parseOptions;
}
const treeAdapter = {
createDocument() {
const doc = ownerDocument.createElement("#document" /* DOCUMENT_NODE */);
doc["x-mode"] = "no-quirks";
return doc;
},
setNodeSourceCodeLocation(node, location2) {
node.sourceCodeLocation = location2;
},
getNodeSourceCodeLocation(node) {
return node.sourceCodeLocation;
},
createDocumentFragment() {
return ownerDocument.createDocumentFragment();
},
createElement(tagName, namespaceURI, attrs) {
const elm = ownerDocument.createElementNS(namespaceURI, tagName);
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i];
if (attr.namespace == null || attr.namespace === "http://www.w3.org/1999/xhtml") {
elm.setAttribute(attr.name, attr.value);
} else {
elm.setAttributeNS(attr.namespace, attr.name, attr.value);
}
}
return elm;
},
createCommentNode(data) {
return ownerDocument.createComment(data);
},
appendChild(parentNode, newNode) {
parentNode.appendChild(newNode);
},
insertBefore(parentNode, newNode, referenceNode) {
parentNode.insertBefore(newNode, referenceNode);
},
setTemplateContent(templateElement, contentElement) {
templateElement.content = contentElement;
},
getTemplateContent(templateElement) {
return templateElement.content;
},
setDocumentType(doc, name, publicId, systemId) {
let doctypeNode = doc.childNodes.find((n) => n.nodeType === 10 /* DOCUMENT_TYPE_NODE */);
if (doctypeNode == null) {
doctypeNode = ownerDocument.createDocumentTypeNode();
doc.insertBefore(doctypeNode, doc.firstChild);
}
doctypeNode.nodeValue = "!DOCTYPE";
doctypeNode["x-name"] = name;
doctypeNode["x-publicId"] = publicId;
doctypeNode["x-systemId"] = systemId;
},
setDocumentMode(doc, mode) {
doc["x-mode"] = mode;
},
getDocumentMode(doc) {
return doc["x-mode"];
},
detachNode(node) {
node.remove();
},
insertText(parentNode, text) {
const lastChild = parentNode.lastChild;
if (lastChild != null && lastChild.nodeType === 3 /* TEXT_NODE */) {
lastChild.nodeValue += text;
} else {
parentNode.appendChild(ownerDocument.createTextNode(text));
}
},
insertTextBefore(parentNode, text, referenceNode) {
const prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1];
if (prevNode != null && prevNode.nodeType === 3 /* TEXT_NODE */) {
prevNode.nodeValue += text;
} else {
parentNode.insertBefore(ownerDocument.createTextNode(text), referenceNode);
}
},
adoptAttributes(recipient, attrs) {
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i];
if (recipient.hasAttributeNS(attr.namespace, attr.name) === false) {
recipient.setAttributeNS(attr.namespace, attr.name, attr.value);
}
}
},
getFirstChild(node) {
return node.childNodes[0];
},
getChildNodes(node) {
return node.childNodes;
},
getParentNode(node) {
return node.parentNode;
},
getAttrList(element) {
const attrs = element.attributes.__items.map((attr) => {
return {
name: attr.name,
value: attr.value,
namespace: attr.namespaceURI,
prefix: null
};
});
return attrs;
},
getTagName(element) {
if (element.namespaceURI === "http://www.w3.org/1999/xhtml") {
return element.nodeName.toLowerCase();
} else {
return element.nodeName;
}
},
getNamespaceURI(element) {
return element.namespaceURI;
},
getTextNodeContent(textNode) {
return textNode.nodeValue;
},
getCommentNodeContent(commentNode) {
return commentNode.nodeValue;
},
getDocumentTypeNodeName(doctypeNode) {
return doctypeNode["x-name"];
},
getDocumentTypeNodePublicId(doctypeNode) {
return doctypeNode["x-publicId"];
},
getDocumentTypeNodeSystemId(doctypeNode) {
return doctypeNode["x-systemId"];
},
// @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['text']`. As a result, we cannot
// complete this function signature
isTextNode(node) {
return node.nodeType === 3 /* TEXT_NODE */;
},
// @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['comment']`. As a result, we cannot
// complete this function signature (which requires its return type to be a type predicate)
isCommentNode(node) {
return node.nodeType === 8 /* COMMENT_NODE */;
},
// @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['document']`. As a result, we cannot
// complete this function signature (which requires its return type to be a type predicate)
isDocumentTypeNode(node) {
return node.nodeType === 10 /* DOCUMENT_TYPE_NODE */;
},
// @ts-ignore - a `MockNode` will never be assignable to a `TreeAdapterTypeMap['element']`. As a result, we cannot
// complete this function signature (which requires its return type to be a type predicate)
isElementNode(node) {
return node.nodeType === 1 /* ELEMENT_NODE */;
}
};
parseOptions = {
treeAdapter
};
docParser.set(ownerDocument, parseOptions);
return parseOptions;
}
// src/mock-doc/third-party/jquery.ts
var jquery_default = (
/*!
* jQuery JavaScript Library v4.0.0-pre+9352011a7.dirty +selector
* https://jquery.com/
*
* Copyright OpenJS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2023-12-11T17:55Z
*/
function(global2, factory) {
"use strict";
if (true) {
return factory(global2, true);
} else {
factory(global2);
}
}({
document: {
createElement() {
return {};
},
nodeType: 9,
documentElement: {
nodeType: 1,
nodeName: "HTML"
}
}
}, function(window2, noGlobal) {
"use strict";
if (!window2.document) {
throw new Error("jQuery requires a window with a document");
}
var arr = [];
var getProto = Object.getPrototypeOf;
var slice = arr.slice;
var flat = arr.flat ? function(array) {
return arr.flat.call(array);
} : function(array) {
return arr.concat.apply([], array);
};
var push = arr.push;
var indexOf = arr.indexOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call(Object);
var support = {};
function toType(obj) {
if (obj == null) {
return obj + "";
}
return typeof obj === "object" ? class2type[toString.call(obj)] || "object" : typeof obj;
}
function isWindow(obj) {
return obj != null && obj === obj.window;
}
function isArrayLike(obj) {
var length = !!obj && obj.length, type = toType(obj);
if (typeof obj === "function" || isWindow(obj)) {
return false;
}
return type === "array" || length === 0 || typeof length === "number" && length > 0 && length - 1 in obj;
}
var document2 = window2.document;
var preservedScriptAttributes = {
type: true,
src: true,
nonce: true,
noModule: true
};
function DOMEval(code, node, doc) {
doc = doc || document2;
var i2, script = doc.createElement("script");
script.text = code;
if (node) {
for (i2 in preservedScriptAttributes) {
if (node[i2]) {
script[i2] = node[i2];
}
}
}
doc.head.appendChild(script).parentNode.removeChild(script);
}
const jQuery = {};
var version = "4.0.0-pre+9352011a7.dirty +selector", rhtmlSuffix = /HTML$/i, jQueryOrig = function(selector, context) {
return new jQuery.fn.init(selector, context);
};
jQuery.fn = jQuery.prototype = {
// The current version of jQuery being used
jquery: version,
constructor: jQuery,
// The default length of a jQuery object is 0
length: 0,
toArray: function() {
return slice.call(this);
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function(num) {
if (num == null) {
return slice.call(this);
}
return num < 0 ? this[num + this.length] : this[num];
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function(elems) {
var ret = jQuery.merge(this.constructor(), elems);
ret.prevObject = this;
return ret;
},
// Execute a callback for every element in the matched set.
each: function(callback) {
return jQuery.each(this, callback);
},
map: function(callback) {
return this.pushStack(jQuery.map(this, function(elem, i2) {
return callback.call(elem, i2, elem);
}));
},
slice: function() {
return this.pushStack(slice.apply(this, arguments));
},
first: function() {
return this.eq(0);
},
last: function() {
return this.eq(-1);
},
even: function() {
return this.pushStack(jQuery.grep(this, function(_elem, i2) {
return (i2 + 1) % 2;
}));
},
odd: function() {
return this.pushStack(jQuery.grep(this, function(_elem, i2) {
return i2 % 2;
}));
},
eq: function(i2) {
var len = this.length, j = +i2 + (i2 < 0 ? len : 0);
return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
},
end: function() {
return this.prevObject || this.constructor();
}
};
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i2 = 1, length = arguments.length, deep = false;
if (typeof target === "boolean") {
deep = target;
target = arguments[i2] || {};
i2++;
}
if (typeof target !== "object" && typeof target !== "function") {
target = {};
}
if (i2 === length) {
target = this;
i2--;
}
for (; i2 < length; i2++) {
if ((options = arguments[i2]) != null) {
for (name in options) {
copy = options[name];
if (name === "__proto__" || target === copy) {
continue;
}
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
src = target[name];
if (copyIsArray && !Array.isArray(src)) {
clone = [];
} else if (!copyIsArray && !jQuery.isPlainObject(src)) {
clone = {};
} else {
clone = src;
}
copyIsArray = false;
target[name] = jQuery.extend(deep, clone, copy);
} else if (copy !== void 0) {
target[name] = copy;
}
}
}
}
return target;
};
jQuery.extend({
// Unique for each copy of jQuery on the page
expando: "jQuery" + (version + Math.random()).replace(/\D/g, ""),
// Assume jQuery is ready without the ready module
isReady: true,
error: function(msg) {
throw new Error(msg);
},
noop: function() {
},
isPlainObject: function(obj) {
var proto, Ctor;
if (!obj || toString.call(obj) !== "[object Object]") {
return false;
}
proto = getProto(obj);
if (!proto) {
return true;
}
Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString;
},
isEmptyObject: function(obj) {
var name;
for (name in obj) {
return false;
}
return true;
},
// Evaluates a script in a provided context; falls back to the global one
// if not specified.
globalEval: function(code, options, doc) {
DOMEval(code, { nonce: options && options.nonce }, doc);
},
each: function(obj, callback) {
var length, i2 = 0;
if (isArrayLike(obj)) {
length = obj.length;
for (; i2 < length; i2++) {
if (callback.call(obj[i2], i2, obj[i2]) === false) {
break;
}
}
} else {
for (i2 in obj) {
if (callback.call(obj[i2], i2, obj[i2]) === false) {
break;
}
}
}
return obj;
},
// Retrieve the text value of an array of DOM nodes
text: function(elem) {
var node, ret = "", i2 = 0, nodeType = elem.nodeType;
if (!nodeType) {
while (node = elem[i2++]) {
ret += jQuery.text(node);
}
}
if (nodeType === 1 || nodeType === 11) {
return elem.textContent;
}
if (nodeType === 9) {
return elem.documentElement.textContent;
}
if (nodeType === 3 || nodeType === 4) {
return elem.nodeValue;
}
return ret;
},
// results is for internal usage only
makeArray: function(arr2, results) {
var ret = results || [];
if (arr2 != null) {
if (isArrayLike(Object(arr2))) {
jQuery.merge(
ret,
typeof arr2 === "string" ? [arr2] : arr2
);
} else {
push.call(ret, arr2);
}
}
return ret;
},
inArray: function(elem, arr2, i2) {
return arr2 == null ? -1 : indexOf.call(arr2, elem, i2);
},
isXMLDoc: function(elem) {
var namespace = elem && elem.namespaceURI, docElem = elem && (elem.ownerDocument || elem).documentElement;
return !rhtmlSuffix.test(namespace || docElem && docElem.nodeName || "HTML");
},
// Note: an element does not contain itself
contains: function(a, b) {
var bup = b && b.parentNode;
return a === bup || !!(bup && bup.nodeType === 1 && // Support: IE 9 - 11+
// IE doesn't have `contains` on SVG.
(a.contains ? a.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16));
},
merge: function(first, second) {
var len = +second.length, j = 0, i2 = first.length;
for (; j < len; j++) {
first[i2++] = second[j];
}
first.length = i2;
return first;
},
grep: function(elems, callback, invert) {
var callbackInverse, matches3 = [], i2 = 0, length = elems.length, callbackExpect = !invert;
for (; i2 < length; i2++) {
callbackInverse = !callback(elems[i2], i2);
if (callbackInverse !== callbackExpect) {
matches3.push(elems[i2]);
}
}
return matches3;
},
// arg is for internal usage only
map: function(elems, callback, arg) {
var length, value, i2 = 0, ret = [];
if (isArrayLike(elems)) {
length = elems.length;
for (; i2 < length; i2++) {
value = callback(elems[i2], i2, arg);
if (value != null) {
ret.push(value);
}
}
} else {
for (i2 in elems) {
value = callback(elems[i2], i2, arg);
if (value != null) {
ret.push(value);
}
}
}
return flat(ret);
},
// A global GUID counter for objects
guid: 1,
// jQuery.support is not used in Core but other projects attach their
// properties to it so it needs to exist.
support
});
if (typeof Symbol === "function") {
jQuery.fn[Symbol.iterator] = arr[Symbol.iterator];
}
jQuery.each(
"Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),
function(_i, name) {
class2type["[object " + name + "]"] = name.toLowerCase();
}
);
function nodeName(elem, name) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
}
var pop = arr.pop;
var whitespace = "[\\x20\\t\\r\\n\\f]";
var isIE = document2.documentMode;
try {
document2.querySelector(":has(*,:jqfake)");
support.cssHas = false;
} catch (e) {
support.cssHas = true;
}
var rbuggyQSA = [];
if (isIE) {
rbuggyQSA.push(
// Support: IE 9 - 11+
// IE's :disabled selector does not pick up the children of disabled fieldsets
":enabled",
":disabled",
// Support: IE 11+
// IE 11 doesn't find elements on a `[name='']` query in some cases.
// Adding a temporary attribute to the document before the selection works
// around the issue.
"\\[" + whitespace + "*name" + whitespace + "*=" + whitespace + `*(?:''|"")`
);
}
if (!support.cssHas) {
rbuggyQSA.push(":has");
}
rbuggyQSA = rbuggyQSA.length && new RegExp(rbuggyQSA.join("|"));
var rtrimCSS = new RegExp(
"^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$",
"g"
);
var identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+";
var booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped";
var rleadingCombinator = new RegExp("^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*");
var rdescend = new RegExp(whitespace + "|>");
var rsibling = /[+~]/;
var documentElement = document2.documentElement;
var matches2 = documentElement.matches || documentElement.msMatchesSelector;
function createCache() {
var keys = [];
function cache(key, value) {
if (keys.push(key + " ") > jQuery.expr.cacheLength) {
delete cache[keys.shift()];
}
return cache[key + " "] = value;
}
return cache;
}
function testContext(context) {
return context && typeof context.getElementsByTagName !== "undefined" && context;
}
var attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + // Operator (capture 2)
"*([*^$|!~]?=)" + whitespace + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
`*(?:'((?:\\\\.|[^\\\\'])*)'|"((?:\\\\.|[^\\\\"])*)"|(` + identifier + "))|)" + whitespace + "*\\]";
var pseudos = ":(" + identifier + `)(?:\\((('((?:\\\\.|[^\\\\'])*)'|"((?:\\\\.|[^\\\\"])*)")|((?:\\\\.|[^\\\\()[\\]]|` + attributes + ")*)|.*)\\)|)";
var filterMatchExpr = {
ID: new RegExp("^#(" + identifier + ")"),
CLASS: new RegExp("^\\.(" + identifier + ")"),
TAG: new RegExp("^(" + identifier + "|[*])"),
ATTR: new RegExp("^" + attributes),
PSEUDO: new RegExp("^" + pseudos),
CHILD: new RegExp(
"^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)",
"i"
)
};
var rpseudo = new RegExp(pseudos);
var runescape = new RegExp("\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g"), funescape = function(escape, nonHex) {
var high = "0x" + escape.slice(1) - 65536;
if (nonHex) {
return nonHex;
}
return high < 0 ? String.fromCharCode(high + 65536) : String.fromCharCode(high >> 10 | 55296, high & 1023 | 56320);
};
function unescapeSelector(sel) {
return sel.replace(runescape, funescape);
}
function selectorError(msg) {
jQuery.error("Syntax error, unrecognized expression: " + msg);
}
var rcomma = new RegExp("^" + whitespace + "*," + whitespace + "*");
var tokenCache = createCache();
function tokenize(selector, parseOnly) {
var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[selector + " "];
if (cached) {
return parseOnly ? 0 : cached.slice(0);
}
soFar = selector;
groups = [];
preFilters = jQuery.expr.preFilter;
while (soFar) {
if (!matched || (match = rcomma.exec(soFar))) {
if (match) {
soFar = soFar.slice(match[0].length) || soFar;
}
groups.push(tokens = []);
}
matched = false;
if (match = rleadingCombinator.exec(soFar)) {
matched = match.shift();
tokens.push({
value: matched,
// Cast descendant combinators to space
type: match[0].replace(rtrimCSS, " ")
});
soFar = soFar.slice(matched.length);
}
for (type in filterMatchExpr) {
if ((match = jQuery.expr.match[type].exec(soFar)) && (!preFilters[type] || (match = preFilters[type](match)))) {
matched = match.shift();
tokens.push({
value: matched,
type,
matches: match
});
soFar = soFar.slice(matched.length);
}
}
if (!matched) {
break;
}
}
if (parseOnly) {
return soFar.length;
}
return soFar ? selectorError(selector) : (
// Cache the tokens
tokenCache(selector, groups).slice(0)
);
}
var preFilter = {
ATTR: function(match) {
match[1] = unescapeSelector(match[1]);
match[3] = unescapeSelector(match[3] || match[4] || match[5] || "");
if (match[2] === "~=") {
match[3] = " " + match[3] + " ";
}
return match.slice(0, 4);
},
CHILD: function(match) {
match[1] = match[1].toLowerCase();
if (match[1].slice(0, 3) === "nth") {
if (!match[3]) {
selectorError(match[0]);
}
match[4] = +(match[4] ? match[5] + (match[6] || 1) : 2 * (match[3] === "even" || match[3] === "odd"));
match[5] = +(match[7] + match[8] || match[3] === "odd");
} else if (match[3]) {
selectorError(match[0]);
}
return match;
},
PSEUDO: function(match) {
var excess, unquoted = !match[6] && match[2];
if (filterMatchExpr.CHILD.test(match[0])) {
return null;
}
if (match[3]) {
match[2] = match[4] || match[5] || "";
} else if (unquoted && rpseudo.test(unquoted) && // Get excess from tokenize (recursively)
(excess = tokenize(unquoted, true)) && // advance to the next closing parenthesis
(excess = unquoted.indexOf(")", unquoted.length - excess) - unquoted.length)) {
match[0] = match[0].slice(0, excess);
match[2] = unquoted.slice(0, excess);
}
return match.slice(0, 3);
}
};
function toSelector(tokens) {
var i2 = 0, len = tokens.length, selector = "";
for (; i2 < len; i2++) {
selector += tokens[i2].value;
}
return selector;
}
var rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;
function fcssescape(ch, asCodePoint) {
if (asCodePoint) {
if (ch === "\0") {
return "\uFFFD";
}
return ch.slice(0, -1) + "\\" + ch.charCodeAt(ch.length - 1).toString(16) + " ";
}
return "\\" + ch;
}
jQuery.escapeSelector = function(sel) {
return (sel + "").replace(rcssescape, fcssescape);
};
var sort = arr.sort;
var splice = arr.splice;
var hasDuplicate;
function sortOrder(a, b) {
if (a === b) {
hasDuplicate = true;
return 0;
}
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
if (compare) {
return compare;
}
compare = (a.ownerDocument || a) == (b.ownerDocument || b) ? a.compareDocumentPosition(b) : (
// Otherwise we know they are disconnected
1
);
if (compare & 1) {
if (a == document2 || a.ownerDocument == document2 && jQuery.contains(document2, a)) {
return -1;
}
if (b == document2 || b.ownerDocument == document2 && jQuery.contains(document2, b)) {
return 1;
}
return 0;
}
return compare & 4 ? -1 : 1;
}
jQuery.uniqueSort = function(results) {
var elem, duplicates = [], j = 0, i2 = 0;
hasDuplicate = false;
sort.call(results, sortOrder);
if (hasDuplicate) {
while (elem = results[i2++]) {
if (elem === results[i2]) {
j = duplicates.push(i2);
}
}
while (j--) {
splice.call(results, duplicates[j], 1);
}
}
return results;
};
jQuery.fn.uniqueSort = function() {
return this.pushStack(jQuery.uniqueSort(slice.apply(this)));
};
var i, outermostContext, document$1, documentElement$1, documentIsHTML, dirruns = 0, done = 0, classCache = createCache(), compilerCache = createCache(), nonnativeSelectorCache = createCache(), rwhitespace = new RegExp(whitespace + "+", "g"), ridentifier = new RegExp("^" + identifier + "$"), matchExpr = jQuery.extend({
bool: new RegExp("^(?:" + booleans + ")$", "i"),
// For use in libraries implementing .is()
// We use this for POS matching in `select`
needsContext: new RegExp("^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i")
}, filterMatchExpr), rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, unloadHandler = function() {
setDocument();
}, inDisabledFieldset = addCombinator(
function(elem) {
return elem.disabled === true && nodeName(elem, "fieldset");
},
{ dir: "parentNode", next: "legend" }
);
function find(selector, context, results, seed) {
var m, i2, elem, nid, match, groups, newSelector, newContext = context && context.ownerDocument, nodeType = context ? context.nodeType : 9;
results = results || [];
if (typeof selector !== "string" || !selector || nodeType !== 1 && nodeType !== 9 && nodeType !== 11) {
return results;
}
if (false) {
setDocument(context);
context = context || document$1;
if (documentIsHTML) {
if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
if (m = match[1]) {
if (nodeType === 9) {
if (elem = context.getElementById(m)) {
push.call(results, elem);
}
return results;
} else {
if (newContext && (elem = newContext.getElementById(m)) && jQuery.contains(context, elem)) {
push.call(results, elem);
return results;
}
}
} else if (match[2]) {
push.apply(results, context.getElementsByTagName(selector));
return results;
} else if ((m = match[3]) && context.getElementsByClassName) {
push.apply(results, context.getElementsByClassName(m));
return results;
}
}
if (!nonnativeSelectorCache[selector + " "] && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
newSelector = selector;
newContext = context;
if (nodeType === 1 && (rdescend.test(selector) || rleadingCombinator.test(selector))) {
newContext = rsibling.test(selector) && testContext(context.parentNode) || context;
if (newContext != context || isIE) {
if (nid = context.getAttribute("id")) {
nid = jQuery.escapeSelector(nid);
} else {
context.setAttribute("id", nid = jQuery.expando);
}
}
groups = tokenize(selector);
i2 = groups.length;
while (i2--) {
groups[i2] = (nid ? "#" + nid : ":scope") + " " + toSelector(groups[i2]);
}
newSelector = groups.join(",");
}
try {
push.apply(
results,
newContext.querySelectorAll(newSelector)
);
return results;
} catch (qsaError) {
nonnativeSelectorCache(selector, true);
} finally {
if (nid === jQuery.expando) {
context.removeAttribute("id");
}
}
}
}
}
return select(selector.replace(rtrimCSS, "$1"), context, results, seed);
}
function markFunction(fn) {
fn[jQuery.expando] = true;
return fn;
}
function createInputPseudo(type) {
return function(elem) {
return nodeName(elem, "input") && elem.type === type;
};
}
function createButtonPseudo(type) {
return function(elem) {
return (nodeName(elem, "input") || nodeName(elem, "button")) && elem.type === type;
};
}
function createDisabledPseudo(disabled) {
return function(elem) {
if ("form" in elem) {
if (elem.parentNode && elem.disabled === false) {
if ("label" in elem) {
if ("label" in elem.parentNode) {
return elem.parentNode.disabled === disabled;
} else {
return elem.disabled === disabled;
}
}
return elem.isDisabled === disabled || // Where there is no isDisabled, check manually
elem.isDisabled !== !disabled && inDisabledFieldset(elem) === disabled;
}
return elem.disabled === disabled;
} else if ("label" in elem) {
return elem.disabled === disabled;
}
return false;
};
}
function createPositionalPseudo(fn) {
return markFunction(function(argument) {
argument = +argument;
return markFunction(function(seed, matches3) {
var j, matchIndexes = fn([], seed.length, argument), i2 = matchIndexes.length;
while (i2--) {
if (seed[j = matchIndexes[i2]]) {
seed[j] = !(matches3[j] = seed[j]);
}
}
});
});
}
function setDocument(node) {
var subWindow, doc = node ? node.ownerDocument || node : document2;
if (doc == document$1 || doc.nodeType !== 9) {
return;
}
document$1 = doc;
documentElement$1 = document$1.documentElement;
documentIsHTML = !jQuery.isXMLDoc(document$1);
if (isIE && document2 != document$1 && (subWindow = document$1.defaultView) && subWindow.top !== subWindow) {
subWindow.addEventListener("unload", unloadHandler);
}
}
find.matches = function(expr, elements) {
return find(expr, null, null, elements);
};
find.matchesSelector = function(elem, expr) {
setDocument(elem);
if (documentIsHTML && !nonnativeSelectorCache[expr + " "] && (!rbuggyQSA || !rbuggyQSA.test(expr))) {
try {
return matches2.call(elem, expr);
} catch (e) {
nonnativeSelectorCache(expr, true);
}
}
return find(expr, document$1, null, [elem]).length > 0;
};
jQuery.expr = {
// Can be adjusted by the user
cacheLength: 50,
createPseudo: markFunction,
match: matchExpr,
find: {
ID: function(id, context) {
if (typeof context.getElementById !== "undefined" && documentIsHTML) {
var elem = context.getElementById(id);
return elem ? [elem] : [];
}
},
TAG: function(tag, context) {
if (typeof context.getElementsByTagName !== "undefined") {
return context.getElementsByTagName(tag);
} else {
return context.querySelectorAll(tag);
}
},
CLASS: function(className, context) {
if (typeof context.getElementsByClassName !== "undefined" && documentIsHTML) {
return context.getElementsByClassName(className);
}
}
},
relative: {
">": { dir: "parentNode", first: true },
" ": { dir: "parentNode" },
"+": { dir: "previousSibling", first: true },
"~": { dir: "previousSibling" }
},
preFilter,
filter: {
ID: function(id) {
var attrId = unescapeSelector(id);
return function(elem) {
return elem.getAttribute("id") === attrId;
};
},
TAG: function(nodeNameSelector) {
var expectedNodeName = unescapeSelector(nodeNameSelector).toLowerCase();
return nodeNameSelector === "*" ? function() {
return true;
} : function(elem) {
return nodeName(elem, expectedNodeName);
};
},
CLASS: function(className) {
var pattern = classCache[className + " "];
return pattern || (pattern = new RegExp("(^|" + whitespace + ")" + className + "(" + whitespace + "|$)")) && classCache(className, function(elem) {
return pattern.test(
typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || ""
);
});
},
ATTR: function(name, operator, check) {
return function(elem) {
var result = elem.getAttribute(name);
if (result == null) {
return operator === "!=";
}
if (!operator) {
return true;
}
result += "";
if (operator === "=") {
return result === check;
}
if (operator === "!=") {
return result !== check;
}
if (operator === "^=") {
return check && result.indexOf(check) === 0;
}
if (operator === "*=") {
return check && result.indexOf(check) > -1;
}
if (operator === "$=") {
return check && result.slice(-check.length) === check;
}
if (operator === "~=") {
return (" " + result.replace(rwhitespace, " ") + " ").indexOf(check) > -1;
}
if (operator === "|=") {
return result === check || result.slice(0, check.length + 1) === check + "-";
}
return false;
};
},
CHILD: function(type, what, _argument, first, last) {
var simple = type.slice(0, 3) !== "nth", forward = type.slice(-4) !== "last", ofType = what === "of-type";
return first === 1 && last === 0 ? (
// Shortcut for :nth-*(n)
function(elem) {
return !!elem.parentNode;
}
) : function(elem, _context, xml) {
var cache, outerCache, node, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType, diff = false;
if (parent) {
if (simple) {
while (dir) {
node = elem;
while (node = node[dir]) {
if (ofType ? nodeName(node, name) : node.nodeType === 1) {
return false;
}
}
start = dir = type === "only" && !start && "nextSibling";
}
return true;
}
start = [forward ? parent.firstChild : parent.lastChild];
if (forward && useCache) {
outerCache = parent[jQuery.expando] || (parent[jQuery.expando] = {});
cache = outerCache[type] || [];
nodeIndex = cache[0] === dirruns && cache[1];
diff = nodeIndex && cache[2];
node = nodeIndex && parent.childNodes[nodeIndex];
while (node = ++nodeIndex && node && node[dir] || // Fallback to seeking `elem` from the start
(diff = nodeIndex = 0) || start.pop()) {
if (node.nodeType === 1 && ++diff && node === elem) {
outerCache[type] = [dirruns, nodeIndex, diff];
break;
}
}
} else {
if (useCache) {
outerCache = elem[jQuery.expando] || (elem[jQuery.expando] = {});
cache = outerCache[type] || [];
nodeIndex = cache[0] === dirruns && cache[1];
diff = nodeIndex;
}
if (diff === false) {
while (node = ++nodeIndex && node && node[dir] || (diff = nodeIndex = 0) || start.pop()) {
if ((ofType ? nodeName(node, name) : node.nodeType === 1) && ++diff) {
if (useCache) {
outerCache = node[jQuery.expando] || (node[jQuery.expando] = {});
outerCache[type] = [dirruns, diff];
}
if (node === elem) {
break;
}
}
}
}
}
diff -= last;
return diff === first || diff % first === 0 && diff / first >= 0;
}
};
},
PSEUDO: function(pseudo, argument) {
var fn = jQuery.expr.pseudos[pseudo] || jQuery.expr.setFilters[pseudo.toLowerCase()] || selectorError("unsupported pseudo: " + pseudo);
if (fn[jQuery.expando]) {
return fn(argument);
}
return fn;
}
},
pseudos: {
// Potentially complex pseudos
not: markFunction(function(selector) {
var input = [], results = [], matcher = compile(selector.replace(rtrimCSS, "$1"));
return matcher[jQuery.expando] ? markFunction(function(seed, matches3, _context, xml) {
var elem, unmatched = matcher(seed, null, xml, []), i2 = seed.length;
while (i2--) {
if (elem = unmatched[i2]) {
seed[i2] = !(matches3[i2] = elem);
}
}
}) : function(elem, _context, xml) {
input[0] = elem;
matcher(input, null, xml, results);
input[0] = null;
return !results.pop();
};
}),
has: markFunction(function(selector) {
return function(elem) {
return find(selector, elem).length > 0;
};
}),
contains: markFunction(function(text) {
text = unescapeSelector(text);
return function(elem) {
return (elem.textContent || jQuery.text(elem)).indexOf(text) > -1;
};
}),
// "Whether an element is represented by a :lang() selector
// is based solely on the element's language value
// being equal to the identifier C,
// or beginning with the identifier C immediately followed by "-".
// The matching of C against the element's language value is performed case-insensitively.
// The identifier C does not have to be a valid language name."
// https://www.w3.org/TR/selectors/#lang-pseudo
lang: markFunction(function(lang) {
if (!ridentifier.test(lang || "")) {
selectorError("unsupported lang: " + lang);
}
lang = unescapeSelector(lang).toLowerCase();
return function(elem) {
var elemLang;
do {
if (elemLang = documentIsHTML ? elem.lang : elem.getAttribute("xml:lang") || elem.getAttribute("lang")) {
elemLang = elemLang.toLowerCase();
return elemLang === lang || elemLang.indexOf(lang + "-") === 0;
}
} while ((elem = elem.parentNode) && elem.nodeType === 1);
return false;
};
}),
// Miscellaneous
target: function(elem) {
var hash = window2.location && window2.location.hash;
return hash && hash.slice(1) === elem.id;
},
root: function(elem) {
return elem === documentElement$1;
},
focus: function(elem) {
return elem === document$1.activeElement && document$1.hasFocus() && !!(elem.type || elem.href || ~elem.tabIndex);
},
// Boolean properties
enabled: createDisabledPseudo(false),
disabled: createDisabledPseudo(true),
checked: function(elem) {
return nodeName(elem, "input") && !!elem.checked || nodeName(elem, "option") && !!elem.selected;
},
selected: function(elem) {
if (isIE && elem.parentNode) {
elem.parentNode.selectedIndex;
}
return elem.selected === true;
},
// Contents
empty: function(elem) {
for (elem = elem.firstChild; elem; elem = elem.nextSibling) {
if (elem.nodeType < 6) {
return false;
}
}
return true;
},
parent: function(elem) {
return !jQuery.expr.pseudos.empty(elem);
},
// Element/input types
header: function(elem) {
return rheader.test(elem.nodeName);
},
input: function(elem) {
return rinputs.test(elem.nodeName);
},
button: function(elem) {
return nodeName(elem, "input") && elem.type === "button" || nodeName(elem, "button");
},
text: function(elem) {
return nodeName(elem, "input") && elem.type === "text";
},
// Position-in-collection
first: createPositionalPseudo(function() {
return [0];
}),
last: createPositionalPseudo(function(_matchIndexes, length) {
return [length - 1];
}),
eq: createPositionalPseudo(function(_matchIndexes, length, argument) {
return [argument < 0 ? argument + length : argument];
}),
even: createPositionalPseudo(function(matchIndexes, length) {
var i2 = 0;
for (; i2 < length; i2 += 2) {
matchIndexes.push(i2);
}
return matchIndexes;
}),
odd: createPositionalPseudo(function(matchIndexes, length) {
var i2 = 1;
for (; i2 < length; i2 += 2) {
matchIndexes.push(i2);
}
return matchIndexes;
}),
lt: createPositionalPseudo(function(matchIndexes, length, argument) {
var i2;
if (argument < 0) {
i2 = argument + length;
} else if (argument > length) {
i2 = length;
} else {
i2 = argument;
}
for (; --i2 >= 0; ) {
matchIndexes.push(i2);
}
return matchIndexes;
}),
gt: createPositionalPseudo(function(matchIndexes, length, argument) {
var i2 = argument < 0 ? argument + length : argument;
for (; ++i2 < length; ) {
matchIndexes.push(i2);
}
return matchIndexes;
})
}
};
jQuery.expr.pseudos.nth = jQuery.expr.pseudos.eq;
for (i in { radio: true, checkbox: true, file: true, password: true, image: true }) {
jQuery.expr.pseudos[i] = createInputPseudo(i);
}
for (i in { submit: true, reset: true }) {
jQuery.expr.pseudos[i] = createButtonPseudo(i);
}
function setFilters() {
}
setFilters.prototype = jQuery.expr.filters = jQuery.expr.pseudos;
jQuery.expr.setFilters = new setFilters();
function addCombinator(matcher, combinator, base) {
var dir = combinator.dir, skip = combinator.next, key = skip || dir, checkNonElements = base && key === "parentNode", doneName = done++;
return combinator.first ? (
// Check against closest ancestor/preceding element
function(elem, context, xml) {
while (elem = elem[dir]) {
if (elem.nodeType === 1 || checkNonElements) {
return matcher(elem, context, xml);
}
}
return false;
}
) : (
// Check against all ancestor/preceding elements
function(elem, context, xml) {
var oldCache, outerCache, newCache = [dirruns, doneName];
if (xml) {
while (elem = elem[dir]) {
if (elem.nodeType === 1 || checkNonElements) {
if (matcher(elem, context, xml)) {
return true;
}
}
}
} else {
while (elem = elem[dir]) {
if (elem.nodeType === 1 || checkNonElements) {
outerCache = elem[jQuery.expando] || (elem[jQuery.expando] = {});
if (skip && nodeName(elem, skip)) {
elem = elem[dir] || elem;
} else if ((oldCache = outerCache[key]) && oldCache[0] === dirruns && oldCache[1] === doneName) {
return newCache[2] = oldCache[2];
} else {
outerCache[key] = newCache;
if (newCache[2] = matcher(elem, context, xml)) {
return true;
}
}
}
}
}
return false;
}
);
}
function elementMatcher(matchers) {
return matchers.length > 1 ? function(elem, context, xml) {
var i2 = matchers.length;
while (i2--) {
if (!matchers[i2](elem, context, xml)) {
return false;
}
}
return true;
} : matchers[0];
}
function multipleContexts(selector, contexts, results) {
var i2 = 0, len = contexts.length;
for (; i2 < len; i2++) {
find(selector, contexts[i2], results);
}
return results;
}
function condense(unmatched, map2, filter, context, xml) {
var elem, newUnmatched = [], i2 = 0, len = unmatched.length, mapped = map2 != null;
for (; i2 < len; i2++) {
if (elem = unmatched[i2]) {
if (!filter || filter(elem, context, xml)) {
newUnmatched.push(elem);
if (mapped) {
map2.push(i2);
}
}
}
}
return newUnmatched;
}
function setMatcher(preFilter2, selector, matcher, postFilter, postFinder, postSelector) {
if (postFilter && !postFilter[jQuery.expando]) {
postFilter = setMatcher(postFilter);
}
if (postFinder && !postFinder[jQuery.expando]) {
postFinder = setMatcher(postFinder, postSelector);
}
return markFunction(function(seed, results, context, xml) {
var temp, i2, elem, matcherOut, preMap = [], postMap = [], preexisting = results.length, elems = seed || multipleContexts(
selector || "*",
context.nodeType ? [context] : context,
[]
), matcherIn = preFilter2 && (seed || !selector) ? condense(elems, preMap, preFilter2, context, xml) : elems;
if (matcher) {
matcherOut = postFinder || (seed ? preFilter2 : preexisting || postFilter) ? (
// ...intermediate processing is necessary
[]
) : (
// ...otherwise use results directly
results
);
matcher(matcherIn, matcherOut, context, xml);
} else {
matcherOut = matcherIn;
}
if (postFilter) {
temp = condense(matcherOut, postMap);
postFilter(temp, [], context, xml);
i2 = temp.length;
while (i2--) {
if (elem = temp[i2]) {
matcherOut[postMap[i2]] = !(matcherIn[postMap[i2]] = elem);
}
}
}
if (seed) {
if (postFinder || preFilter2) {
if (postFinder) {
temp = [];
i2 = matcherOut.length;
while (i2--) {
if (elem = matcherOut[i2]) {
temp.push(matcherIn[i2] = elem);
}
}
postFinder(null, matcherOut = [], temp, xml);
}
i2 = matcherOut.length;
while (i2--) {
if ((elem = matcherOut[i2]) && (temp = postFinder ? indexOf.call(seed, elem) : preMap[i2]) > -1) {
seed[temp] = !(results[temp] = elem);
}
}
}
} else {
matcherOut = condense(
matcherOut === results ? matcherOut.splice(preexisting, matcherOut.length) : matcherOut
);
if (postFinder) {
postFinder(null, results, matcherOut, xml);
} else {
push.apply(results, matcherOut);
}
}
});
}
function matcherFromTokens(tokens) {
var checkContext, matcher, j, len = tokens.length, leadingRelative = jQuery.expr.relative[tokens[0].type], implicitRelative = leadingRelative || jQuery.expr.relative[" "], i2 = leadingRelative ? 1 : 0, matchContext = addCombinator(function(elem) {
return elem === checkContext;
}, implicitRelative, true), matchAnyContext = addCombinator(function(elem) {
return indexOf.call(checkContext, elem) > -1;
}, implicitRelative, true), matchers = [function(elem, context, xml) {
var ret = !leadingRelative && (xml || context != outermostContext) || ((checkContext = context).nodeType ? matchContext(elem, context, xml) : matchAnyContext(elem, context, xml));
checkContext = null;
return ret;
}];
for (; i2 < len; i2++) {
if (matcher = jQuery.expr.relative[tokens[i2].type]) {
matchers = [addCombinator(elementMatcher(matchers), matcher)];
} else {
matcher = jQuery.expr.filter[tokens[i2].type].apply(null, tokens[i2].matches);
if (matcher[jQuery.expando]) {
j = ++i2;
for (; j < len; j++) {
if (jQuery.expr.relative[tokens[j].type]) {
break;
}
}
return setMatcher(
i2 > 1 && elementMatcher(matchers),
i2 > 1 && toSelector(
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
tokens.slice(0, i2 - 1).concat({ value: tokens[i2 - 2].type === " " ? "*" : "" })
).replace(rtrimCSS, "$1"),
matcher,
i2 < j && matcherFromTokens(tokens.slice(i2, j)),
j < len && matcherFromTokens(tokens = tokens.slice(j)),
j < len && toSelector(tokens)
);
}
matchers.push(matcher);
}
}
return elementMatcher(matchers);
}
function matcherFromGroupMatchers(elementMatchers, setMatchers) {
var bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function(seed, context, xml, results, outermost) {
var elem, j, matcher, matchedCount = 0, i2 = "0", unmatched = seed && [], setMatched = [], contextBackup = outermostContext, elems = seed || byElement && jQuery.expr.find.TAG("*", outermost), dirrunsUnique = dirruns += contextBackup == null ? 1 : Math.random() || 0.1;
if (outermost) {
outermostContext = context == document$1 || context || outermost;
}
for (; (elem = elems[i2]) != null; i2++) {
if (byElement && elem) {
j = 0;
if (!context && elem.ownerDocument != document$1) {
setDocument(elem);
xml = !documentIsHTML;
}
while (matcher = elementMatchers[j++]) {
if (matcher(elem, context || document$1, xml)) {
push.call(results, elem);
break;
}
}
if (outermost) {
dirruns = dirrunsUnique;
}
}
if (bySet) {
if (elem = !matcher && elem) {
matchedCount--;
}
if (seed) {
unmatched.push(elem);
}
}
}
matchedCount += i2;
if (bySet && i2 !== matchedCount) {
j = 0;
while (matcher = setMatchers[j++]) {
matcher(unmatched, setMatched, context, xml);
}
if (seed) {
if (matchedCount > 0) {
while (i2--) {
if (!(unmatched[i2] || setMatched[i2])) {
setMatched[i2] = pop.call(results);
}
}
}
setMatched = condense(setMatched);
}
push.apply(results, setMatched);
if (outermost && !seed && setMatched.length > 0 && matchedCount + setMatchers.length > 1) {
jQuery.uniqueSort(results);
}
}
if (outermost) {
dirruns = dirrunsUnique;
outermostContext = contextBackup;
}
return unmatched;
};
return bySet ? markFunction(superMatcher) : superMatcher;
}
function compile(selector, match) {
var i2, setMatchers = [], elementMatchers = [], cached = compilerCache[selector + " "];
if (!cached) {
if (!match) {
match = tokenize(selector);
}
i2 = match.length;
while (i2--) {
cached = matcherFromTokens(match[i2]);
if (cached[jQuery.expando]) {
setMatchers.push(cached);
} else {
elementMatchers.push(cached);
}
}
cached = compilerCache(
selector,
matcherFromGroupMatchers(elementMatchers, setMatchers)
);
cached.selector = selector;
}
return cached;
}
function select(selector, context, results, seed) {
var i2, tokens, token, type, find2, compiled = typeof selector === "function" && selector, match = !seed && tokenize(selector = compiled.selector || selector);
results = results || [];
if (match.length === 1) {
tokens = match[0] = match[0].slice(0);
if (tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && documentIsHTML && jQuery.expr.relative[tokens[1].type]) {
context = (jQuery.expr.find.ID(
unescapeSelector(token.matches[0]),
context
) || [])[0];
if (!context) {
return results;
} else if (compiled) {
context = context.parentNode;
}
selector = selector.slice(tokens.shift().value.length);
}
i2 = matchExpr.needsContext.test(selector) ? 0 : tokens.length;
while (i2--) {
token = tokens[i2];
if (jQuery.expr.relative[type = token.type]) {
break;
}
if (find2 = jQuery.expr.find[type]) {
if (seed = find2(
unescapeSelector(token.matches[0]),
rsibling.test(tokens[0].type) && testContext(context.parentNode) || context
)) {
tokens.splice(i2, 1);
selector = seed.length && toSelector(tokens);
if (!selector) {
push.apply(results, seed);
return results;
}
break;
}
}
}
}
(compiled || compile(selector, match))(
seed,
context,
!documentIsHTML,
results,
!context || rsibling.test(selector) && testContext(context.parentNode) || context
);
return results;
}
setDocument();
jQuery.find = find;
find.compile = compile;
find.select = select;
find.setDocument = setDocument;
find.tokenize = tokenize;
return jQuery;
})
);
// src/mock-doc/selector.ts
function matches(selector, elm) {
try {
const r = jquery_default.find(selector, void 0, void 0, [elm]);
return r.length > 0;
} catch (e) {
updateSelectorError(selector, e);
throw e;
}
}
function selectOne(selector, elm) {
try {
const r = jquery_default.find(selector, elm, void 0, void 0);
return r[0] || null;
} catch (e) {
updateSelectorError(selector, e);
throw e;
}
}
function selectAll(selector, elm) {
try {
return jquery_default.find(selector, elm, void 0, void 0);
} catch (e) {
updateSelectorError(selector, e);
throw e;
}
}
var PROBLEMATIC_SELECTORS = [":scope", ":where", ":is"];
function updateSelectorError(selector, e) {
const selectorsPresent = PROBLEMATIC_SELECTORS.filter((s) => selector.includes(s));
if (selectorsPresent.length > 0 && e.message) {
e.message = `At present jQuery does not support the ${humanReadableList(selectorsPresent)} ${selectorsPresent.length === 1 ? "selector" : "selectors"}.
If you need this in your test, consider writing an end-to-end test instead.
` + e.message;
}
}
function humanReadableList(items) {
if (items.length <= 1) {
return items.join("");
}
return `${items.slice(0, items.length - 1).join(", ")} and ${items[items.length - 1]}`;
}
// src/mock-doc/serialize-node.ts
function normalizeSerializationOptions(opts = {}) {
return {
...opts,
outerHtml: typeof opts.outerHtml !== "boolean" ? false : opts.outerHtml,
...opts.prettyHtml ? {
indentSpaces: typeof opts.indentSpaces !== "number" ? 2 : opts.indentSpaces,
newLines: typeof opts.newLines !== "boolean" ? true : opts.newLines
} : {
prettyHtml: false,
indentSpaces: typeof opts.indentSpaces !== "number" ? 0 : opts.indentSpaces,
newLines: typeof opts.newLines !== "boolean" ? false : opts.newLines
},
approximateLineWidth: typeof opts.approximateLineWidth !== "number" ? -1 : opts.approximateLineWidth,
removeEmptyAttributes: typeof opts.removeEmptyAttributes !== "boolean" ? true : opts.removeEmptyAttributes,
removeAttributeQuotes: typeof opts.removeAttributeQuotes !== "boolean" ? false : opts.removeAttributeQuotes,
removeBooleanAttributeQuotes: typeof opts.removeBooleanAttributeQuotes !== "boolean" ? false : opts.removeBooleanAttributeQuotes,
removeHtmlComments: typeof opts.removeHtmlComments !== "boolean" ? false : opts.removeHtmlComments,
serializeShadowRoot: typeof opts.serializeShadowRoot === "undefined" ? "declarative-shadow-dom" : opts.serializeShadowRoot,
fullDocument: typeof opts.fullDocument !== "boolean" ? true : opts.fullDocument
};
}
function serializeNodeToHtml(elm, serializationOptions = {}) {
const opts = normalizeSerializationOptions(serializationOptions);
const output = {
currentLineWidth: 0,
indent: 0,
isWithinBody: false,
text: []
};
let renderedNode = "";
const children = !opts.fullDocument && elm.body ? Array.from(elm.body.childNodes) : opts.outerHtml ? [elm] : Array.from(getChildNodes(elm));
for (let i = 0, ii = children.length; i < ii; i++) {
const child = children[i];
const chunks = Array.from(streamToHtml(child, opts, output));
renderedNode += chunks.join("");
}
return renderedNode.trim();
}
var shadowRootTag = "mock:shadow-root";
function* streamToHtml(node, opts, output) {
var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
const isShadowRoot = node.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE */;
if (node.nodeType === 1 /* ELEMENT_NODE */ || isShadowRoot) {
const tagName = isShadowRoot ? shadowRootTag : getTagName(node);
if (tagName === "body") {
output.isWithinBody = true;
}
const ignoreTag = opts.excludeTags != null && opts.excludeTags.includes(tagName);
if (ignoreTag === false) {
const isWithinWhitespaceSensitiveNode = opts.newLines || ((_a2 = opts.indentSpaces) != null ? _a2 : 0) > 0 ? isWithinWhitespaceSensitive(node) : false;
if (opts.newLines && !isWithinWhitespaceSensitiveNode) {
yield "\n";
output.currentLineWidth = 0;
}
if (((_b = opts.indentSpaces) != null ? _b : 0) > 0 && !isWithinWhitespaceSensitiveNode) {
for (let i = 0; i < output.indent; i++) {
yield " ";
}
output.currentLineWidth += output.indent;
}
const tag = tagName === shadowRootTag ? "template" : tagName;
yield "<" + tag;
output.currentLineWidth += tag.length + 1;
if (tag === "template" && (!node.getAttribute || !node.getAttribute("shadowrootmode")) && /**
* If the node is a shadow root, we want to add the `shadowrootmode` attribute
*/
("host" in node || node.nodeName.toLocaleLowerCase() === shadowRootTag)) {
const mode = ` shadowrootmode="open"`;
yield mode;
output.currentLineWidth += mode.length;
if (node.delegatesFocus) {
const delegatesFocusAttr = " shadowrootdelegatesfocus";
yield delegatesFocusAttr;
output.currentLineWidth += delegatesFocusAttr.length;
}
}
const attrsLength = node.attributes.length;
const attributes = opts.prettyHtml && attrsLength > 1 ? cloneAttributes(node.attributes, true) : node.attributes;
for (let i = 0; i < attrsLength; i++) {
const attr = attributes.item(i);
const attrName = attr.name;
if (attrName === "style") {
continue;
}
let attrValue = attr.value;
if (opts.removeEmptyAttributes && attrValue === "" && REMOVE_EMPTY_ATTR.has(attrName)) {
continue;
}
const attrNamespaceURI = attr.namespaceURI;
if (attrNamespaceURI == null) {
output.currentLineWidth += attrName.length + 1;
if (opts.approximateLineWidth && opts.approximateLineWidth > 0 && output.currentLineWidth > opts.approximateLineWidth) {
yield "\n" + attrName;
output.currentLineWidth = 0;
} else {
yield " " + attrName;
}
} else if (attrNamespaceURI === "http://www.w3.org/XML/1998/namespace") {
yield " xml:" + attrName;
output.currentLineWidth += attrName.length + 5;
} else if (attrNamespaceURI === "http://www.w3.org/2000/xmlns/") {
if (attrName !== "xmlns") {
yield " xmlns:" + attrName;
output.currentLineWidth += attrName.length + 7;
} else {
yield " " + attrName;
output.currentLineWidth += attrName.length + 1;
}
} else if (attrNamespaceURI === XLINK_NS) {
yield " xlink:" + attrName;
output.currentLineWidth += attrName.length + 7;
} else {
yield " " + attrNamespaceURI + ":" + attrName;
output.currentLineWidth += attrNamespaceURI.length + attrName.length + 2;
}
if (opts.prettyHtml && attrName === "class") {
attrValue = attr.value = attrValue.split(" ").filter((t) => t !== "").sort().join(" ").trim();
}
if (attrValue === "") {
if (opts.removeBooleanAttributeQuotes && BOOLEAN_ATTR.has(attrName)) {
continue;
}
if (opts.removeEmptyAttributes && attrName.startsWith("data-")) {
continue;
}
}
if (opts.removeAttributeQuotes && CAN_REMOVE_ATTR_QUOTES.test(attrValue)) {
yield "=" + escapeString(attrValue, true);
output.currentLineWidth += attrValue.length + 1;
} else {
yield '="' + escapeString(attrValue, true) + '"';
output.currentLineWidth += attrValue.length + 3;
}
}
if (node.hasAttribute("style")) {
const cssText = node.style.cssText;
if (opts.approximateLineWidth && opts.approximateLineWidth > 0 && output.currentLineWidth + cssText.length + 10 > opts.approximateLineWidth) {
yield `
style="${cssText}">`;
output.currentLineWidth = 0;
} else {
yield ` style="${cssText}">`;
output.currentLineWidth += cssText.length + 10;
}
} else {
yield ">";
output.currentLineWidth += 1;
}
}
if (EMPTY_ELEMENTS.has(tagName) === false) {
const shadowRoot = node.shadowRoot;
if (shadowRoot != null && opts.serializeShadowRoot !== false) {
output.indent = output.indent + ((_c = opts.indentSpaces) != null ? _c : 0);
yield* streamToHtml(shadowRoot, opts, output);
output.indent = output.indent - ((_d = opts.indentSpaces) != null ? _d : 0);
const childNodes = getChildNodes(node);
if (opts.newLines && (childNodes.length === 0 || childNodes.length === 1 && childNodes[0].nodeType === 3 /* TEXT_NODE */ && ((_e = childNodes[0].nodeValue) == null ? void 0 : _e.trim()) === "")) {
yield "\n";
output.currentLineWidth = 0;
for (let i = 0; i < output.indent; i++) {
yield " ";
}
output.currentLineWidth += output.indent;
}
}
if (opts.excludeTagContent == null || opts.excludeTagContent.includes(tagName) === false) {
const tag = tagName === shadowRootTag ? "template" : tagName;
const childNodes = tagName === "template" ? node.content.childNodes : getChildNodes(node);
const childNodeLength = childNodes.length;
if (childNodeLength > 0) {
if (childNodeLength === 1 && childNodes[0].nodeType === 3 /* TEXT_NODE */ && (typeof childNodes[0].nodeValue !== "string" || childNodes[0].nodeValue.trim() === "")) {
} else {
const isWithinWhitespaceSensitiveNode = opts.newLines || ((_f = opts.indentSpaces) != null ? _f : 0) > 0 ? isWithinWhitespaceSensitive(node) : false;
if (!isWithinWhitespaceSensitiveNode && ((_g = opts.indentSpaces) != null ? _g : 0) > 0 && ignoreTag === false) {
output.indent = output.indent + ((_h = opts.indentSpaces) != null ? _h : 0);
}
for (let i = 0; i < childNodeLength; i++) {
const sId = node.attributes.getNamedItem(HYDRATE_ID);
const isStencilDeclarativeShadowDOM = childNodes[i].nodeName.toLowerCase() === "template" && sId;
if (isStencilDeclarativeShadowDOM) {
yield `
${" ".repeat(output.indent)}<!--r.${sId.value}-->`;
continue;
}
yield* streamToHtml(childNodes[i], opts, output);
}
if (ignoreTag === false) {
if (opts.newLines && !isWithinWhitespaceSensitiveNode) {
yield "\n";
output.currentLineWidth = 0;
}
if (((_i = opts.indentSpaces) != null ? _i : 0) > 0 && !isWithinWhitespaceSensitiveNode) {
output.indent = output.indent - ((_j = opts.indentSpaces) != null ? _j : 0);
for (let i = 0; i < output.indent; i++) {
yield " ";
}
output.currentLineWidth += output.indent;
}
}
}
}
if (ignoreTag === false) {
yield "</" + tag + ">";
output.currentLineWidth += tag.length + 3;
}
}
}
if (((_k = opts.approximateLineWidth) != null ? _k : 0) > 0 && STRUCTURE_ELEMENTS.has(tagName)) {
yield "\n";
output.currentLineWidth = 0;
}
if (tagName === "body") {
output.isWithinBody = false;
}
} else if (node.nodeType === 3 /* TEXT_NODE */) {
let textContent = node.nodeValue;
if (typeof textContent === "string") {
const trimmedTextContent = textContent.trim();
if (trimmedTextContent === "") {
if (isWithinWhitespaceSensitive(node)) {
yield textContent;
output.currentLineWidth += textContent.length;
} else if (((_l = opts.approximateLineWidth) != null ? _l : 0) > 0 && !output.isWithinBody) {
} else if (!opts.prettyHtml) {
output.currentLineWidth += 1;
if (opts.approximateLineWidth && opts.approximateLineWidth > 0 && output.currentLineWidth > opts.approximateLineWidth) {
yield "\n";
output.currentLineWidth = 0;
} else {
yield " ";
}
}
} else {
const isWithinWhitespaceSensitiveNode = opts.newLines || ((_m = opts.indentSpaces) != null ? _m : 0) > 0 || opts.prettyHtml ? isWithinWhitespaceSensitive(node) : false;
if (opts.newLines && !isWithinWhitespaceSensitiveNode) {
yield "\n";
output.currentLineWidth = 0;
}
if (((_n = opts.indentSpaces) != null ? _n : 0) > 0 && !isWithinWhitespaceSensitiveNode) {
for (let i = 0; i < output.indent; i++) {
yield " ";
}
output.currentLineWidth += output.indent;
}
let textContentLength = textContent.length;
if (textContentLength > 0) {
const parentTagName = node.parentNode != null && node.parentNode.nodeType === 1 /* ELEMENT_NODE */ ? node.parentNode.nodeName : null;
if (typeof parentTagName === "string" && NON_ESCAPABLE_CONTENT.has(parentTagName)) {
if (isWithinWhitespaceSensitive(node)) {
yield textContent;
} else {
yield trimmedTextContent;
textContentLength = trimmedTextContent.length;
}
output.currentLineWidth += textContentLength;
} else {
if (opts.prettyHtml && !isWithinWhitespaceSensitiveNode) {
yield escapeString(textContent.replace(/\s\s+/g, " ").trim(), false);
output.currentLineWidth += textContentLength;
} else {
if (isWithinWhitespaceSensitive(node)) {
output.currentLineWidth += textContentLength;
} else {
if (/\s/.test(textContent.charAt(0))) {
textContent = " " + textContent.trimLeft();
}
textContentLength = textContent.length;
if (textContentLength > 1) {
if (/\s/.test(textContent.charAt(textContentLength - 1))) {
if (opts.approximateLineWidth && opts.approximateLineWidth > 0 && output.currentLineWidth + textContentLength > opts.approximateLineWidth) {
textContent = textContent.trimRight() + "\n";
output.currentLineWidth = 0;
} else {
textContent = textContent.trimRight() + " ";
}
}
}
output.currentLineWidth += textContentLength;
}
yield escapeString(textContent, false);
}
}
}
}
}
} else if (node.nodeType === 8 /* COMMENT_NODE */) {
const nodeValue = node.nodeValue;
const isHydrateAnnotation = (nodeValue == null ? void 0 : nodeValue.startsWith(CONTENT_REF_ID + ".")) || (nodeValue == null ? void 0 : nodeValue.startsWith(ORG_LOCATION_ID + ".")) || (nodeValue == null ? void 0 : nodeValue.startsWith(SLOT_NODE_ID + ".")) || (nodeValue == null ? void 0 : nodeValue.startsWith(TEXT_NODE_ID + "."));
if (opts.removeHtmlComments && !isHydrateAnnotation) {
return;
}
const isWithinWhitespaceSensitiveNode = opts.newLines || ((_o = opts.indentSpaces) != null ? _o : 0) > 0 ? isWithinWhitespaceSensitive(node) : false;
if (opts.newLines && !isWithinWhitespaceSensitiveNode) {
yield "\n";
output.currentLineWidth = 0;
}
if (((_p = opts.indentSpaces) != null ? _p : 0) > 0 && !isWithinWhitespaceSensitiveNode) {
for (let i = 0; i < output.indent; i++) {
yield " ";
}
output.currentLineWidth += output.indent;
}
yield "<!--" + nodeValue + "-->";
if (nodeValue) {
output.currentLineWidth += nodeValue.length + 7;
}
} else if (node.nodeType === 10 /* DOCUMENT_TYPE_NODE */) {
yield "<!doctype html>";
}
}
var AMP_REGEX = /&/g;
var NBSP_REGEX = /\u00a0/g;
var DOUBLE_QUOTE_REGEX = /"/g;
var LT_REGEX = /</g;
var GT_REGEX = />/g;
var CAN_REMOVE_ATTR_QUOTES = /^[^ \t\n\f\r"'`=<>\/\\-]+$/;
function getTagName(element) {
if (element.namespaceURI === "http://www.w3.org/1999/xhtml") {
return element.nodeName.toLowerCase();
} else {
return element.nodeName;
}
}
function escapeString(str, attrMode) {
str = str.replace(AMP_REGEX, "&amp;").replace(NBSP_REGEX, "&nbsp;");
if (attrMode) {
return str.replace(DOUBLE_QUOTE_REGEX, "&quot;");
}
return str.replace(LT_REGEX, "&lt;").replace(GT_REGEX, "&gt;");
}
function isWithinWhitespaceSensitive(node) {
let _node = node;
while (_node == null ? void 0 : _node.nodeName) {
if (WHITESPACE_SENSITIVE.has(_node.nodeName)) {
return true;
}
_node = _node.parentNode;
}
return false;
}
function getChildNodes(node) {
return node.__childNodes || node.childNodes;
}
var NON_ESCAPABLE_CONTENT = /* @__PURE__ */ new Set([
"STYLE",
"SCRIPT",
"IFRAME",
"NOSCRIPT",
"XMP",
"NOEMBED",
"NOFRAMES",
"PLAINTEXT"
]);
var WHITESPACE_SENSITIVE = /* @__PURE__ */ new Set([
"CODE",
"OUTPUT",
"PLAINTEXT",
"PRE",
"SCRIPT",
"TEMPLATE",
"TEXTAREA"
]);
var EMPTY_ELEMENTS = /* @__PURE__ */ new Set([
"area",
"base",
"basefont",
"bgsound",
"br",
"col",
"embed",
"frame",
"hr",
"img",
"input",
"keygen",
"link",
"meta",
"param",
"source",
"trace",
"track",
"wbr"
]);
var REMOVE_EMPTY_ATTR = /* @__PURE__ */ new Set(["class", "dir", "id", "lang", "name", "title"]);
var BOOLEAN_ATTR = /* @__PURE__ */ new Set([
"allowfullscreen",
"async",
"autofocus",
"autoplay",
"checked",
"compact",
"controls",
"declare",
"default",
"defaultchecked",
"defaultmuted",
"defaultselected",
"defer",
"disabled",
"enabled",
"formnovalidate",
"hidden",
"indeterminate",
"inert",
"ismap",
"itemscope",
"loop",
"multiple",
"muted",
"nohref",
"nomodule",
"noresize",
"noshade",
"novalidate",
"nowrap",
"open",
"pauseonexit",
"readonly",
"required",
"reversed",
"scoped",
"seamless",
"selected",
"sortable",
"truespeed",
"typemustmatch",
"visible"
]);
var STRUCTURE_ELEMENTS = /* @__PURE__ */ new Set([
"html",
"body",
"head",
"iframe",
"meta",
"link",
"base",
"title",
"script",
"style"
]);
// src/mock-doc/node.ts
var MockNode2 = class {
constructor(ownerDocument, nodeType, nodeName, nodeValue) {
this.ownerDocument = ownerDocument;
this.nodeType = nodeType;
this.nodeName = nodeName;
this._nodeValue = nodeValue;
this.parentNode = null;
this.childNodes = [];
}
appendChild(newNode) {
if (newNode.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE */) {
const nodes = newNode.childNodes.slice();
for (const child of nodes) {
this.appendChild(child);
}
} else {
newNode.remove();
newNode.parentNode = this;
this.childNodes.push(newNode);
connectNode(this.ownerDocument, newNode);
}
return newNode;
}
append(...items) {
items.forEach((item) => {
const isNode = typeof item === "object" && item !== null && "nodeType" in item;
this.appendChild(isNode ? item : this.ownerDocument.createTextNode(String(item)));
});
}
prepend(...items) {
const firstChild = this.firstChild;
items.forEach((item) => {
const isNode = typeof item === "object" && item !== null && "nodeType" in item;
if (firstChild) {
this.insertBefore(isNode ? item : this.ownerDocument.createTextNode(String(item)), firstChild);
}
});
}
cloneNode(deep) {
throw new Error(`invalid node type to clone: ${this.nodeType}, deep: ${deep}`);
}
compareDocumentPosition(_other) {
return -1;
}
get firstChild() {
return this.childNodes[0] || null;
}
insertBefore(newNode, referenceNode) {
if (newNode.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE */) {
for (let i = 0, ii = newNode.childNodes.length; i < ii; i++) {
insertBefore(this, newNode.childNodes[i], referenceNode);
}
} else {
insertBefore(this, newNode, referenceNode);
}
return newNode;
}
get isConnected() {
let node = this;
while (node != null) {
if (node.nodeType === 9 /* DOCUMENT_NODE */) {
return true;
}
node = node.parentNode;
if (node != null && node.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE */) {
node = node.host;
}
}
return false;
}
isSameNode(node) {
return this === node;
}
get lastChild() {
return this.childNodes[this.childNodes.length - 1] || null;
}
get nextSibling() {
if (this.parentNode != null) {
const index = this.parentNode.childNodes.indexOf(this) + 1;
return this.parentNode.childNodes[index] || null;
}
return null;
}
get nodeValue() {
var _a2;
return (_a2 = this._nodeValue) != null ? _a2 : "";
}
set nodeValue(value) {
this._nodeValue = value;
}
get parentElement() {
return this.parentNode || null;
}
set parentElement(value) {
this.parentNode = value;
}
get previousSibling() {
if (this.parentNode != null) {
const index = this.parentNode.childNodes.indexOf(this) - 1;
return this.parentNode.childNodes[index] || null;
}
return null;
}
contains(otherNode) {
if (otherNode === this) {
return true;
}
const childNodes = Array.from(this.childNodes);
if (childNodes.includes(otherNode)) {
return true;
}
return childNodes.some((node) => this.contains.bind(node)(otherNode));
}
removeChild(childNode) {
const index = this.childNodes.indexOf(childNode);
if (index > -1) {
this.childNodes.splice(index, 1);
if (this.nodeType === 1 /* ELEMENT_NODE */) {
const wasConnected = this.isConnected;
childNode.parentNode = null;
if (wasConnected === true) {
disconnectNode(childNode);
}
} else {
childNode.parentNode = null;
}
} else {
throw new Error(`node not found within childNodes during removeChild`);
}
return childNode;
}
remove() {
if (this.parentNode != null) {
this.__parentNode ? this.__parentNode.removeChild(this) : this.parentNode.removeChild(this);
}
}
replaceChild(newChild, oldChild) {
if (oldChild.parentNode === this) {
this.insertBefore(newChild, oldChild);
oldChild.remove();
return newChild;
}
return null;
}
get textContent() {
var _a2;
return (_a2 = this._nodeValue) != null ? _a2 : "";
}
set textContent(value) {
this._nodeValue = String(value);
}
addEventListener(type, handler) {
addEventListener(this, type, handler);
}
removeEventListener(type, handler) {
removeEventListener(this, type, handler);
}
dispatchEvent(ev) {
return dispatchEvent(this, ev);
}
};
MockNode2.ELEMENT_NODE = 1;
MockNode2.TEXT_NODE = 3;
MockNode2.PROCESSING_INSTRUCTION_NODE = 7;
MockNode2.COMMENT_NODE = 8;
MockNode2.DOCUMENT_NODE = 9;
MockNode2.DOCUMENT_TYPE_NODE = 10;
MockNode2.DOCUMENT_FRAGMENT_NODE = 11;
var MockNodeList = class {
constructor(ownerDocument, childNodes, length) {
this.ownerDocument = ownerDocument;
this.childNodes = childNodes;
this.length = length;
}
};
var MockElement = class extends MockNode2 {
attachInternals() {
return new Proxy({}, {
get: function(_target, prop, _receiver) {
if ("process" in globalThis && globalThis.process.env.__STENCIL_SPEC_TESTS__) {
console.error(
`NOTE: Property ${String(prop)} was accessed on ElementInternals, but this property is not implemented.
Testing components with ElementInternals is fully supported in e2e tests.`
);
}
}
});
}
constructor(ownerDocument, nodeName, namespaceURI = null) {
super(ownerDocument, 1 /* ELEMENT_NODE */, typeof nodeName === "string" ? nodeName : null, null);
this.__namespaceURI = namespaceURI;
this.__shadowRoot = null;
this.__attributeMap = null;
}
addEventListener(type, handler) {
addEventListener(this, type, handler);
}
attachShadow(_opts) {
var _a2;
const shadowRoot = this.ownerDocument.createDocumentFragment();
shadowRoot.delegatesFocus = (_a2 = _opts.delegatesFocus) != null ? _a2 : false;
this.shadowRoot = shadowRoot;
return shadowRoot;
}
blur() {
if (isCurrentlyDispatching(this, "blur")) {
return;
}
markAsDispatching(this, "blur");
try {
dispatchEvent(
this,
new MockFocusEvent("blur", { relatedTarget: null, bubbles: true, cancelable: true, composed: true })
);
} finally {
unmarkAsDispatching(this, "blur");
}
}
get localName() {
if (!this.nodeName) {
throw new Error(`Can't compute elements localName without nodeName`);
}
return this.nodeName.toLocaleLowerCase();
}
get namespaceURI() {
return this.__namespaceURI;
}
get shadowRoot() {
return this.__shadowRoot || null;
}
/**
* Set shadow root for element
* @param shadowRoot - ShadowRoot to set
*/
set shadowRoot(shadowRoot) {
if (shadowRoot != null) {
shadowRoot.host = this;
this.__shadowRoot = shadowRoot;
} else {
delete this.__shadowRoot;
}
}
get attributes() {
if (this.__attributeMap == null) {
const attrMap = createAttributeProxy(false);
this.__attributeMap = attrMap;
return attrMap;
}
return this.__attributeMap;
}
set attributes(attrs) {
this.__attributeMap = attrs;
}
get children() {
return this.childNodes.filter((n) => n.nodeType === 1 /* ELEMENT_NODE */);
}
get childElementCount() {
return this.childNodes.filter((n) => n.nodeType === 1 /* ELEMENT_NODE */).length;
}
get className() {
return this.getAttributeNS(null, "class") || "";
}
set className(value) {
this.setAttributeNS(null, "class", value);
}
get classList() {
return new MockClassList(this);
}
click() {
dispatchEvent(this, new MockEvent("click", { bubbles: true, cancelable: true, composed: true }));
}
cloneNode(_deep) {
return null;
}
closest(selector) {
let elm = this;
while (elm != null) {
if (elm.matches(selector)) {
return elm;
}
elm = elm.parentNode;
}
return null;
}
get dataset() {
return dataset(this);
}
get dir() {
return this.getAttributeNS(null, "dir") || "";
}
set dir(value) {
this.setAttributeNS(null, "dir", value);
}
dispatchEvent(ev) {
return dispatchEvent(this, ev);
}
get firstElementChild() {
return this.children[0] || null;
}
focus(_options) {
dispatchEvent(
this,
new MockFocusEvent("focus", { relatedTarget: null, bubbles: true, cancelable: true, composed: true })
);
}
getAttribute(attrName) {
if (attrName === "style") {
if (this.__style != null && this.__style.length > 0) {
return this.style.cssText;
}
return null;
}
const attr = this.attributes.getNamedItem(attrName);
if (attr != null) {
return attr.value;
}
return null;
}
getAttributeNS(namespaceURI, attrName) {
const attr = this.attributes.getNamedItemNS(namespaceURI, attrName);
if (attr != null) {
return attr.value;
}
return null;
}
getAttributeNode(attrName) {
if (!this.hasAttribute(attrName)) {
return null;
}
return new MockAttr(attrName, this.getAttribute(attrName));
}
getBoundingClientRect() {
return { bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0, x: 0, y: 0 };
}
getRootNode(opts) {
const isComposed = opts != null && opts.composed === true;
let node = this;
while (node.parentNode != null) {
node = node.parentNode;
if (isComposed === true && node.parentNode == null && node.host != null) {
node = node.host;
}
}
return node;
}
get draggable() {
return this.getAttributeNS(null, "draggable") === "true";
}
set draggable(value) {
this.setAttributeNS(null, "draggable", value);
}
hasChildNodes() {
return this.childNodes.length > 0;
}
get id() {
return this.getAttributeNS(null, "id") || "";
}
set id(value) {
this.setAttributeNS(null, "id", value);
}
get innerHTML() {
if (this.childNodes.length === 0) {
return "";
}
return serializeNodeToHtml(this, {
newLines: false,
indentSpaces: 0
});
}
set innerHTML(html) {
var _a2;
if (NON_ESCAPABLE_CONTENT.has((_a2 = this.nodeName) != null ? _a2 : "") === true) {
setTextContent(this, html);
} else {
for (let i = this.childNodes.length - 1; i >= 0; i--) {
this.removeChild(this.childNodes[i]);
}
if (typeof html === "string") {
const frag = parseFragmentUtil(this.ownerDocument, html);
while (frag.childNodes.length > 0) {
this.appendChild(frag.childNodes[0]);
}
}
}
}
get innerText() {
const text = [];
getTextContent(this.childNodes, text);
return text.join("");
}
set innerText(value) {
setTextContent(this, value);
}
insertAdjacentElement(position, elm) {
if (position === "beforebegin" && this.parentNode) {
insertBefore(this.parentNode, elm, this);
} else if (position === "afterbegin") {
this.prepend(elm);
} else if (position === "beforeend") {
this.appendChild(elm);
} else if (position === "afterend" && this.parentNode) {
insertBefore(this.parentNode, elm, this.nextSibling);
}
return elm;
}
insertAdjacentHTML(position, html) {
const frag = parseFragmentUtil(this.ownerDocument, html);
if (position === "beforebegin") {
while (frag.childNodes.length > 0) {
if (this.parentNode) {
insertBefore(this.parentNode, frag.childNodes[0], this);
}
}
} else if (position === "afterbegin") {
while (frag.childNodes.length > 0) {
this.prepend(frag.childNodes[frag.childNodes.length - 1]);
}
} else if (position === "beforeend") {
while (frag.childNodes.length > 0) {
this.appendChild(frag.childNodes[0]);
}
} else if (position === "afterend") {
while (frag.childNodes.length > 0) {
if (this.parentNode) {
insertBefore(this.parentNode, frag.childNodes[frag.childNodes.length - 1], this.nextSibling);
}
}
}
}
insertAdjacentText(position, text) {
const elm = this.ownerDocument.createTextNode(text);
if (position === "beforebegin" && this.parentNode) {
insertBefore(this.parentNode, elm, this);
} else if (position === "afterbegin") {
this.prepend(elm);
} else if (position === "beforeend") {
this.appendChild(elm);
} else if (position === "afterend" && this.parentNode) {
insertBefore(this.parentNode, elm, this.nextSibling);
}
}
hasAttribute(attrName) {
if (attrName === "style") {
return this.__style != null && this.__style.length > 0;
}
return this.getAttribute(attrName) !== null;
}
hasAttributeNS(namespaceURI, name) {
return this.getAttributeNS(namespaceURI, name) !== null;
}
get hidden() {
return this.hasAttributeNS(null, "hidden");
}
set hidden(isHidden) {
if (isHidden === true) {
this.setAttributeNS(null, "hidden", "");
} else {
this.removeAttributeNS(null, "hidden");
}
}
get lang() {
return this.getAttributeNS(null, "lang") || "";
}
set lang(value) {
this.setAttributeNS(null, "lang", value);
}
get lastElementChild() {
const children = this.children;
return children[children.length - 1] || null;
}
matches(selector) {
return matches(selector, this);
}
get nextElementSibling() {
const parentElement = this.parentElement;
if (parentElement != null && (parentElement.nodeType === 1 /* ELEMENT_NODE */ || parentElement.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE */ || parentElement.nodeType === 9 /* DOCUMENT_NODE */)) {
const children = parentElement.children;
const index = children.indexOf(this) + 1;
return parentElement.children[index] || null;
}
return null;
}
get outerHTML() {
return serializeNodeToHtml(this, {
newLines: false,
outerHtml: true,
indentSpaces: 0
});
}
get previousElementSibling() {
const parentElement = this.parentElement;
if (parentElement != null && (parentElement.nodeType === 1 /* ELEMENT_NODE */ || parentElement.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE */ || parentElement.nodeType === 9 /* DOCUMENT_NODE */)) {
const children = parentElement.children;
const index = children.indexOf(this) - 1;
return parentElement.children[index] || null;
}
return null;
}
getElementsByClassName(classNames) {
const classes = classNames.trim().split(" ").filter((c) => c.length > 0);
const results = [];
getElementsByClassName(this, classes, results);
return results;
}
getElementsByTagName(tagName) {
const results = [];
getElementsByTagName(this, tagName.toLowerCase(), results);
return results;
}
querySelector(selector) {
return selectOne(selector, this);
}
querySelectorAll(selector) {
return selectAll(selector, this);
}
removeAttribute(attrName) {
if (attrName === "style") {
delete this.__style;
} else {
const attr = this.attributes.getNamedItem(attrName);
if (attr != null) {
this.attributes.removeNamedItemNS(attr);
if (checkAttributeChanged(this) === true) {
attributeChanged(this, attrName, attr.value, null);
}
}
}
}
removeAttributeNS(namespaceURI, attrName) {
const attr = this.attributes.getNamedItemNS(namespaceURI, attrName);
if (attr != null) {
this.attributes.removeNamedItemNS(attr);
if (checkAttributeChanged(this) === true) {
attributeChanged(this, attrName, attr.value, null);
}
}
}
removeEventListener(type, handler) {
removeEventListener(this, type, handler);
}
setAttribute(attrName, value) {
if (attrName === "style") {
this.style = value;
} else {
const attributes = this.attributes;
let attr = attributes.getNamedItem(attrName);
const checkAttrChanged = checkAttributeChanged(this);
if (attr != null) {
if (checkAttrChanged === true) {
const oldValue = attr.value;
attr.value = value;
if (oldValue !== attr.value) {
attributeChanged(this, attr.name, oldValue, attr.value);
}
} else {
attr.value = value;
}
} else {
if (attributes.caseInsensitive) {
attrName = attrName.toLowerCase();
}
attr = new MockAttr(attrName, value);
attributes.__items.push(attr);
if (checkAttrChanged === true) {
attributeChanged(this, attrName, null, attr.value);
}
}
}
}
setAttributeNS(namespaceURI, attrName, value) {
const attributes = this.attributes;
let attr = attributes.getNamedItemNS(namespaceURI, attrName);
const checkAttrChanged = checkAttributeChanged(this);
if (attr != null) {
if (checkAttrChanged === true) {
const oldValue = attr.value;
attr.value = value;
if (oldValue !== attr.value) {
attributeChanged(this, attr.name, oldValue, attr.value);
}
} else {
attr.value = value;
}
} else {
attr = new MockAttr(attrName, value, namespaceURI);
attributes.__items.push(attr);
if (checkAttrChanged === true) {
attributeChanged(this, attrName, null, attr.value);
}
}
}
get style() {
if (this.__style == null) {
this.__style = createCSSStyleDeclaration();
}
return this.__style;
}
set style(val) {
if (typeof val === "string") {
if (this.__style == null) {
this.__style = createCSSStyleDeclaration();
}
this.__style.cssText = val;
} else {
this.__style = val;
}
}
get tabIndex() {
return parseInt(this.getAttributeNS(null, "tabindex") || "-1", 10);
}
set tabIndex(value) {
this.setAttributeNS(null, "tabindex", value);
}
get tagName() {
var _a2;
return (_a2 = this.nodeName) != null ? _a2 : "";
}
set tagName(value) {
this.nodeName = value;
}
get textContent() {
const text = [];
getTextContent(this.childNodes, text);
return text.join("");
}
set textContent(value) {
setTextContent(this, value);
}
get title() {
return this.getAttributeNS(null, "title") || "";
}
set title(value) {
this.setAttributeNS(null, "title", value);
}
animate() {
}
onanimationstart() {
}
onanimationend() {
}
onanimationiteration() {
}
onabort() {
}
onauxclick() {
}
onbeforecopy() {
}
onbeforecut() {
}
onbeforepaste() {
}
onblur() {
}
oncancel() {
}
oncanplay() {
}
oncanplaythrough() {
}
onchange() {
}
onclick() {
}
onclose() {
}
oncontextmenu() {
}
oncopy() {
}
oncuechange() {
}
oncut() {
}
ondblclick() {
}
ondrag() {
}
ondragend() {
}
ondragenter() {
}
ondragleave() {
}
ondragover() {
}
ondragstart() {
}
ondrop() {
}
ondurationchange() {
}
onemptied() {
}
onended() {
}
onerror() {
}
onfocus() {
}
onfocusin() {
}
onfocusout() {
}
onformdata() {
}
onfullscreenchange() {
}
onfullscreenerror() {
}
ongotpointercapture() {
}
oninput() {
}
oninvalid() {
}
onkeydown() {
}
onkeypress() {
}
onkeyup() {
}
onload() {
}
onloadeddata() {
}
onloadedmetadata() {
}
onloadstart() {
}
onlostpointercapture() {
}
onmousedown() {
}
onmouseenter() {
}
onmouseleave() {
}
onmousemove() {
}
onmouseout() {
}
onmouseover() {
}
onmouseup() {
}
onmousewheel() {
}
onpaste() {
}
onpause() {
}
onplay() {
}
onplaying() {
}
onpointercancel() {
}
onpointerdown() {
}
onpointerenter() {
}
onpointerleave() {
}
onpointermove() {
}
onpointerout() {
}
onpointerover() {
}
onpointerup() {
}
onprogress() {
}
onratechange() {
}
onreset() {
}
onresize() {
}
onscroll() {
}
onsearch() {
}
onseeked() {
}
onseeking() {
}
onselect() {
}
onselectstart() {
}
onstalled() {
}
onsubmit() {
}
onsuspend() {
}
ontimeupdate() {
}
ontoggle() {
}
onvolumechange() {
}
onwaiting() {
}
onwebkitfullscreenchange() {
}
onwebkitfullscreenerror() {
}
onwheel() {
}
requestFullscreen() {
}
scrollBy() {
}
scrollTo() {
}
scrollIntoView() {
}
toString(opts) {
return serializeNodeToHtml(this, opts);
}
};
function getElementsByClassName(elm, classNames, foundElms) {
const children = elm.children;
for (let i = 0, ii = children.length; i < ii; i++) {
const childElm = children[i];
for (let j = 0, jj = classNames.length; j < jj; j++) {
if (childElm.classList.contains(classNames[j])) {
foundElms.push(childElm);
}
}
getElementsByClassName(childElm, classNames, foundElms);
}
}
function getElementsByTagName(elm, tagName, foundElms) {
var _a2;
const children = elm.children;
for (let i = 0, ii = children.length; i < ii; i++) {
const childElm = children[i];
if (tagName === "*" || ((_a2 = childElm.nodeName) != null ? _a2 : "").toLowerCase() === tagName) {
foundElms.push(childElm);
}
getElementsByTagName(childElm, tagName, foundElms);
}
}
function resetElement(elm) {
resetEventListeners(elm);
delete elm.__attributeMap;
delete elm.__shadowRoot;
delete elm.__style;
}
function insertBefore(parentNode, newNode, referenceNode) {
if (newNode !== referenceNode) {
newNode.remove();
newNode.parentNode = parentNode;
newNode.ownerDocument = parentNode.ownerDocument;
if (referenceNode != null) {
const index = parentNode.childNodes.indexOf(referenceNode);
if (index > -1) {
parentNode.childNodes.splice(index, 0, newNode);
} else {
throw new Error(`referenceNode not found in parentNode.childNodes`);
}
} else {
parentNode.childNodes.push(newNode);
}
connectNode(parentNode.ownerDocument, newNode);
}
return newNode;
}
var MockHTMLElement = class extends MockElement {
constructor(ownerDocument, nodeName) {
super(ownerDocument, typeof nodeName === "string" ? nodeName.toUpperCase() : null);
this.__namespaceURI = "http://www.w3.org/1999/xhtml";
}
get tagName() {
var _a2;
return (_a2 = this.nodeName) != null ? _a2 : "";
}
set tagName(value) {
this.nodeName = value;
}
/**
* A node’s parent of type Element is known as its parent element.
* If the node has a parent of a different type, its parent element
* is null.
* @returns MockElement
*/
get parentElement() {
if (this.nodeName === "HTML") {
return null;
}
return super.parentElement;
}
get attributes() {
if (this.__attributeMap == null) {
const attrMap = createAttributeProxy(true);
this.__attributeMap = attrMap;
return attrMap;
}
return this.__attributeMap;
}
set attributes(attrs) {
this.__attributeMap = attrs;
}
};
var MockTextNode = class _MockTextNode extends MockNode2 {
constructor(ownerDocument, text) {
super(ownerDocument, 3 /* TEXT_NODE */, "#text" /* TEXT_NODE */, text);
}
cloneNode(_deep) {
return new _MockTextNode(null, this.nodeValue);
}
get textContent() {
return this.nodeValue;
}
set textContent(text) {
this.nodeValue = text;
}
get data() {
return this.nodeValue;
}
set data(text) {
this.nodeValue = text;
}
get wholeText() {
if (this.parentNode != null) {
const text = [];
for (let i = 0, ii = this.parentNode.childNodes.length; i < ii; i++) {
const childNode = this.parentNode.childNodes[i];
if (childNode.nodeType === 3 /* TEXT_NODE */) {
text.push(childNode.nodeValue);
}
}
return text.join("");
}
return this.nodeValue;
}
};
function getTextContent(childNodes, text) {
for (let i = 0, ii = childNodes.length; i < ii; i++) {
const childNode = childNodes[i];
if (childNode.nodeType === 3 /* TEXT_NODE */) {
text.push(childNode.nodeValue);
} else if (childNode.nodeType === 1 /* ELEMENT_NODE */) {
getTextContent(childNode.childNodes, text);
}
}
}
function setTextContent(elm, text) {
for (let i = elm.childNodes.length - 1; i >= 0; i--) {
elm.removeChild(elm.childNodes[i]);
}
const textNode = new MockTextNode(elm.ownerDocument, text);
elm.appendChild(textNode);
}
var currentlyDispatching = /* @__PURE__ */ new WeakMap();
function isCurrentlyDispatching(target, eventType) {
const dispatchingEvents = currentlyDispatching.get(target);
return dispatchingEvents != null && dispatchingEvents.has(eventType);
}
function markAsDispatching(target, eventType) {
let dispatchingEvents = currentlyDispatching.get(target);
if (dispatchingEvents == null) {
dispatchingEvents = /* @__PURE__ */ new Set();
currentlyDispatching.set(target, dispatchingEvents);
}
dispatchingEvents.add(eventType);
}
function unmarkAsDispatching(target, eventType) {
const dispatchingEvents = currentlyDispatching.get(target);
if (dispatchingEvents != null) {
dispatchingEvents.delete(eventType);
if (dispatchingEvents.size === 0) {
currentlyDispatching.delete(target);
}
}
}
// src/mock-doc/comment-node.ts
var MockComment = class _MockComment extends MockNode2 {
constructor(ownerDocument, data) {
super(ownerDocument, 8 /* COMMENT_NODE */, "#comment" /* COMMENT_NODE */, data);
}
cloneNode(_deep) {
return new _MockComment(null, this.nodeValue);
}
get textContent() {
return this.nodeValue;
}
set textContent(text) {
this.nodeValue = text;
}
};
// src/mock-doc/document-fragment.ts
var MockDocumentFragment = class _MockDocumentFragment extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, null);
this.nodeName = "#document-fragment" /* DOCUMENT_FRAGMENT_NODE */;
this.nodeType = 11 /* DOCUMENT_FRAGMENT_NODE */;
}
getElementById(id) {
return getElementById(this, id);
}
get adoptedStyleSheets() {
return [];
}
set adoptedStyleSheets(_adoptedStyleSheets) {
throw new Error("Unimplemented");
}
cloneNode(deep) {
const cloned = new _MockDocumentFragment(null);
if (deep) {
for (let i = 0, ii = this.childNodes.length; i < ii; i++) {
const childNode = this.childNodes[i];
if (childNode.nodeType === 1 /* ELEMENT_NODE */ || childNode.nodeType === 3 /* TEXT_NODE */ || childNode.nodeType === 8 /* COMMENT_NODE */) {
const clonedChildNode = this.childNodes[i].cloneNode(true);
cloned.appendChild(clonedChildNode);
}
}
}
return cloned;
}
};
// src/mock-doc/document-type-node.ts
var MockDocumentTypeNode = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "!DOCTYPE");
this.nodeType = 10 /* DOCUMENT_TYPE_NODE */;
this.setAttribute("html", "");
}
};
// src/mock-doc/css-style-sheet.ts
var MockCSSRule = class {
constructor(parentStyleSheet) {
this.parentStyleSheet = parentStyleSheet;
this.cssText = "";
this.type = 0;
}
};
var MockCSSStyleSheet = class {
constructor(ownerNode) {
this.type = "text/css";
this.parentStyleSheet = null;
this.cssRules = [];
this.ownerNode = ownerNode;
}
get rules() {
return this.cssRules;
}
set rules(rules) {
this.cssRules = rules;
}
deleteRule(index) {
if (index >= 0 && index < this.cssRules.length) {
this.cssRules.splice(index, 1);
if (this.ownerNode) {
updateStyleTextNode(this.ownerNode);
}
}
}
insertRule(rule, index = 0) {
if (typeof index !== "number") {
index = 0;
}
if (index < 0) {
index = 0;
}
if (index > this.cssRules.length) {
index = this.cssRules.length;
}
const cssRule = new MockCSSRule(this);
cssRule.cssText = rule;
this.cssRules.splice(index, 0, cssRule);
if (this.ownerNode) {
updateStyleTextNode(this.ownerNode);
}
return index;
}
replaceSync(cssText) {
this.cssRules = [];
const rules = cssText.split("}").map((rule) => rule.trim()).filter(Boolean).map((rule) => rule + "}");
for (const rule of rules) {
const cssRule = new MockCSSRule(this);
cssRule.cssText = rule;
this.cssRules.push(cssRule);
}
if (this.ownerNode) {
updateStyleTextNode(this.ownerNode);
}
}
};
function getStyleElementText(styleElm) {
const output = [];
for (let i = 0; i < styleElm.childNodes.length; i++) {
output.push(styleElm.childNodes[i].nodeValue);
}
return output.join("");
}
function setStyleElementText(styleElm, text) {
const sheet = styleElm.sheet;
sheet.cssRules.length = 0;
sheet.insertRule(text);
updateStyleTextNode(styleElm);
}
function updateStyleTextNode(styleElm) {
const childNodeLen = styleElm.childNodes.length;
if (childNodeLen > 1) {
for (let i = childNodeLen - 1; i >= 1; i--) {
styleElm.removeChild(styleElm.childNodes[i]);
}
} else if (childNodeLen < 1) {
styleElm.appendChild(styleElm.ownerDocument.createTextNode(""));
}
const textNode = styleElm.childNodes[0];
textNode.nodeValue = styleElm.sheet.cssRules.map((r) => r.cssText).join("\n");
}
// src/mock-doc/element.ts
function createElement(ownerDocument, tagName) {
if (typeof tagName !== "string" || tagName === "" || !/^[a-z0-9-_:]+$/i.test(tagName)) {
throw new Error(`The tag name provided (${tagName}) is not a valid name.`);
}
tagName = tagName.toLowerCase();
switch (tagName) {
case "a":
return new MockAnchorElement(ownerDocument);
case "base":
return new MockBaseElement(ownerDocument);
case "button":
return new MockButtonElement(ownerDocument);
case "canvas":
return new MockCanvasElement(ownerDocument);
case "form":
return new MockFormElement(ownerDocument);
case "img":
return new MockImageElement(ownerDocument);
case "input":
return new MockInputElement(ownerDocument);
case "link":
return new MockLinkElement(ownerDocument);
case "meta":
return new MockMetaElement(ownerDocument);
case "script":
return new MockScriptElement(ownerDocument);
case "slot":
return new MockSlotElement(ownerDocument);
case "slot-fb":
return new MockHTMLElement(ownerDocument, tagName);
case "style":
return new MockStyleElement(ownerDocument);
case "template":
return new MockTemplateElement(ownerDocument);
case "title":
return new MockTitleElement(ownerDocument);
case "ul":
return new MockUListElement(ownerDocument);
}
if (ownerDocument != null && tagName.includes("-")) {
const win2 = ownerDocument.defaultView;
if (win2 != null && win2.customElements != null) {
return createCustomElement(win2.customElements, ownerDocument, tagName);
}
}
return new MockHTMLElement(ownerDocument, tagName);
}
function createElementNS(ownerDocument, namespaceURI, tagName) {
if (namespaceURI === "http://www.w3.org/1999/xhtml") {
return createElement(ownerDocument, tagName);
} else if (namespaceURI === "http://www.w3.org/2000/svg") {
switch (tagName.toLowerCase()) {
case "text":
case "tspan":
case "tref":
case "altglyph":
case "textpath":
return new MockSVGTextContentElement(ownerDocument, tagName);
case "circle":
case "ellipse":
case "image":
case "line":
case "path":
case "polygon":
case "polyline":
case "rect":
case "use":
return new MockSVGGraphicsElement(ownerDocument, tagName);
case "svg":
return new MockSVGSVGElement(ownerDocument, tagName);
default:
return new MockSVGElement(ownerDocument, tagName);
}
} else {
return new MockElement(ownerDocument, tagName, namespaceURI);
}
}
var MockAnchorElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "a");
}
get href() {
return fullUrl(this, "href");
}
set href(value) {
this.setAttribute("href", value);
}
get pathname() {
if (!this.href) {
return "";
}
return new URL(this.href).pathname;
}
};
var MockButtonElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "button");
}
};
patchPropAttributes(
MockButtonElement.prototype,
{
type: String
},
{
type: "submit"
}
);
Object.defineProperty(MockButtonElement.prototype, "form", {
get() {
return this.hasAttribute("form") ? this.getAttribute("form") : null;
}
});
var MockImageElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "img");
}
get draggable() {
return this.getAttributeNS(null, "draggable") !== "false";
}
set draggable(value) {
this.setAttributeNS(null, "draggable", value);
}
get src() {
return fullUrl(this, "src");
}
set src(value) {
this.setAttribute("src", value);
}
};
patchPropAttributes(MockImageElement.prototype, {
height: Number,
width: Number
});
var MockInputElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "input");
}
get list() {
const listId = this.getAttribute("list");
if (listId) {
return this.ownerDocument.getElementById(listId);
}
return null;
}
};
patchPropAttributes(
MockInputElement.prototype,
{
accept: String,
autocomplete: String,
autofocus: Boolean,
capture: String,
checked: Boolean,
disabled: Boolean,
form: String,
formaction: String,
formenctype: String,
formmethod: String,
formnovalidate: String,
formtarget: String,
height: Number,
inputmode: String,
max: String,
maxLength: Number,
min: String,
minLength: Number,
multiple: Boolean,
name: String,
pattern: String,
placeholder: String,
required: Boolean,
readOnly: Boolean,
size: Number,
spellCheck: Boolean,
src: String,
step: String,
type: String,
value: String,
width: Number
},
{
type: "text"
}
);
var MockFormElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "form");
}
};
patchPropAttributes(MockFormElement.prototype, {
name: String
});
var MockLinkElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "link");
}
get href() {
return fullUrl(this, "href");
}
set href(value) {
this.setAttribute("href", value);
}
};
patchPropAttributes(MockLinkElement.prototype, {
crossorigin: String,
media: String,
rel: String,
type: String
});
var MockMetaElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "meta");
}
};
patchPropAttributes(MockMetaElement.prototype, {
charset: String,
content: String,
name: String
});
var MockScriptElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "script");
}
get src() {
return fullUrl(this, "src");
}
set src(value) {
this.setAttribute("src", value);
}
};
patchPropAttributes(MockScriptElement.prototype, {
type: String
});
var MockDOMMatrix = class _MockDOMMatrix {
constructor() {
this.a = 1;
this.b = 0;
this.c = 0;
this.d = 1;
this.e = 0;
this.f = 0;
this.m11 = 1;
this.m12 = 0;
this.m13 = 0;
this.m14 = 0;
this.m21 = 0;
this.m22 = 1;
this.m23 = 0;
this.m24 = 0;
this.m31 = 0;
this.m32 = 0;
this.m33 = 1;
this.m34 = 0;
this.m41 = 0;
this.m42 = 0;
this.m43 = 0;
this.m44 = 1;
this.is2D = true;
this.isIdentity = true;
}
static fromMatrix() {
return new _MockDOMMatrix();
}
inverse() {
return new _MockDOMMatrix();
}
flipX() {
return new _MockDOMMatrix();
}
flipY() {
return new _MockDOMMatrix();
}
multiply() {
return new _MockDOMMatrix();
}
rotate() {
return new _MockDOMMatrix();
}
rotateAxisAngle() {
return new _MockDOMMatrix();
}
rotateFromVector() {
return new _MockDOMMatrix();
}
scale() {
return new _MockDOMMatrix();
}
scaleNonUniform() {
return new _MockDOMMatrix();
}
skewX() {
return new _MockDOMMatrix();
}
skewY() {
return new _MockDOMMatrix();
}
toJSON() {
}
toString() {
}
transformPoint() {
return new MockDOMPoint();
}
translate() {
return new _MockDOMMatrix();
}
};
var MockDOMPoint = class {
constructor() {
this.w = 1;
this.x = 0;
this.y = 0;
this.z = 0;
}
toJSON() {
}
matrixTransform() {
return new MockDOMMatrix();
}
};
var MockSVGRect = class {
constructor() {
this.height = 10;
this.width = 10;
this.x = 0;
this.y = 0;
}
};
var MockStyleElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "style");
this.sheet = new MockCSSStyleSheet(this);
}
get innerHTML() {
return getStyleElementText(this);
}
set innerHTML(value) {
setStyleElementText(this, value);
}
get innerText() {
return getStyleElementText(this);
}
set innerText(value) {
setStyleElementText(this, value);
}
get textContent() {
return getStyleElementText(this);
}
set textContent(value) {
setStyleElementText(this, value);
}
};
var MockSVGElement = class extends MockElement {
constructor() {
super(...arguments);
this.__namespaceURI = "http://www.w3.org/2000/svg";
}
// SVGElement properties and methods
get ownerSVGElement() {
return null;
}
get viewportElement() {
return null;
}
onunload() {
}
// SVGGeometryElement properties and methods
get pathLength() {
return 0;
}
isPointInFill(_pt) {
return false;
}
isPointInStroke(_pt) {
return false;
}
getTotalLength() {
return 0;
}
};
var MockSVGGraphicsElement = class extends MockSVGElement {
getBBox(_options) {
return new MockSVGRect();
}
getCTM() {
return new MockDOMMatrix();
}
getScreenCTM() {
return new MockDOMMatrix();
}
};
var MockSVGSVGElement = class extends MockSVGGraphicsElement {
createSVGPoint() {
return new MockDOMPoint();
}
};
var MockSVGTextContentElement = class extends MockSVGGraphicsElement {
getComputedTextLength() {
return 0;
}
};
var MockBaseElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "base");
}
get href() {
return fullUrl(this, "href");
}
set href(value) {
this.setAttribute("href", value);
}
};
var MockTemplateElement = class _MockTemplateElement extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "template");
this.content = new MockDocumentFragment(ownerDocument);
}
get innerHTML() {
return this.content.innerHTML;
}
set innerHTML(html) {
this.content.innerHTML = html;
}
cloneNode(deep) {
const cloned = new _MockTemplateElement(null);
cloned.attributes = cloneAttributes(this.attributes);
const styleCssText = this.getAttribute("style");
if (styleCssText != null && styleCssText.length > 0) {
cloned.setAttribute("style", styleCssText);
}
cloned.content = this.content.cloneNode(deep);
if (deep) {
for (let i = 0, ii = this.childNodes.length; i < ii; i++) {
const clonedChildNode = this.childNodes[i].cloneNode(true);
cloned.appendChild(clonedChildNode);
}
}
return cloned;
}
};
var MockTitleElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "title");
}
get text() {
return this.textContent;
}
set text(value) {
this.textContent = value;
}
};
var MockUListElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "ul");
}
};
var MockSlotElement = class _MockSlotElement extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "slot");
}
assignedNodes(opts) {
let nodesToReturn = [];
const ownerHost = this.getRootNode().host;
if (!ownerHost) return nodesToReturn;
if (ownerHost.childNodes.length) {
if (this.name) {
nodesToReturn = ownerHost.childNodes.filter(
(n) => n.nodeType === 1 /* ELEMENT_NODE */ && n.getAttribute("slot") === this.name
);
} else {
nodesToReturn = ownerHost.childNodes.filter(
(n) => n.nodeType === 1 /* ELEMENT_NODE */ && !n.getAttribute("slot") || n.nodeType !== 1 /* ELEMENT_NODE */
);
}
if (nodesToReturn.length) return nodesToReturn;
}
if (!(opts == null ? void 0 : opts.flatten)) return this.childNodes.filter((n) => !(n instanceof _MockSlotElement));
return this.childNodes.reduce(
(acc, node) => {
if (node instanceof _MockSlotElement) {
acc.push(...node.assignedNodes(opts));
} else {
acc.push(node);
}
return acc;
},
[]
);
}
assignedElements(opts) {
let elesToReturn = [];
const ownerHost = this.getRootNode().host;
if (!ownerHost) return elesToReturn;
if (ownerHost.children.length) {
if (this.name) {
elesToReturn = ownerHost.children.filter((n) => n.getAttribute("slot") == this.name);
} else {
elesToReturn = ownerHost.children.filter((n) => !n.getAttribute("slot"));
}
if (elesToReturn.length) return elesToReturn;
}
if (!(opts == null ? void 0 : opts.flatten)) return this.children.filter((n) => !(n instanceof _MockSlotElement));
return this.children.reduce(
(acc, node) => {
if (node instanceof _MockSlotElement) {
acc.push(...node.assignedElements(opts));
} else {
acc.push(node);
}
return acc;
},
[]
);
}
};
patchPropAttributes(MockSlotElement.prototype, {
name: String
});
var CanvasRenderingContext = class {
constructor(context, contextAttributes) {
this.context = context;
this.contextAttributes = contextAttributes;
}
fillRect() {
return;
}
clearRect() {
}
getImageData(_, __, w, h2) {
return {
data: new Array(w * h2 * 4)
};
}
toDataURL() {
return "data:,";
}
putImageData() {
}
createImageData() {
return {};
}
setTransform() {
}
drawImage() {
}
save() {
}
fillText() {
}
restore() {
}
beginPath() {
}
moveTo() {
}
lineTo() {
}
closePath() {
}
stroke() {
}
translate() {
}
scale() {
}
rotate() {
}
arc() {
}
fill() {
}
measureText() {
return { width: 0 };
}
transform() {
}
rect() {
}
clip() {
}
};
var MockCanvasElement = class extends MockHTMLElement {
constructor(ownerDocument) {
super(ownerDocument, "canvas");
}
getContext(context, contextAttributes) {
return new CanvasRenderingContext(context, contextAttributes);
}
};
function fullUrl(elm, attrName) {
const val = elm.getAttribute(attrName) || "";
if (elm.ownerDocument != null) {
const win2 = elm.ownerDocument.defaultView;
if (win2 != null) {
const loc = win2.location;
if (loc != null) {
try {
const url = new URL(val, loc.href);
return url.href;
} catch (e) {
}
}
}
}
return val.replace(/\'|\"/g, "").trim();
}
function patchPropAttributes(prototype, attrs, defaults = {}) {
Object.keys(attrs).forEach((propName) => {
const attr = attrs[propName];
const defaultValue = defaults[propName];
if (attr === Boolean) {
Object.defineProperty(prototype, propName, {
get() {
return this.hasAttribute(propName);
},
set(value) {
if (value) {
this.setAttribute(propName, "");
} else {
this.removeAttribute(propName);
}
}
});
} else if (attr === Number) {
Object.defineProperty(prototype, propName, {
get() {
const value = this.getAttribute(propName);
return value ? parseInt(value, 10) : defaultValue === void 0 ? 0 : defaultValue;
},
set(value) {
this.setAttribute(propName, value);
}
});
} else {
Object.defineProperty(prototype, propName, {
get() {
return this.hasAttribute(propName) ? this.getAttribute(propName) : defaultValue || "";
},
set(value) {
this.setAttribute(propName, value);
}
});
}
});
}
MockElement.prototype.cloneNode = function(deep) {
const cloned = createElement(this.ownerDocument, this.nodeName);
cloned.attributes = cloneAttributes(this.attributes);
const styleCssText = this.getAttribute("style");
if (styleCssText != null && styleCssText.length > 0) {
cloned.setAttribute("style", styleCssText);
}
if (deep) {
for (let i = 0, ii = this.childNodes.length; i < ii; i++) {
const clonedChildNode = this.childNodes[i].cloneNode(true);
cloned.appendChild(clonedChildNode);
}
}
return cloned;
};
// src/mock-doc/parse-html.ts
var sharedDocument;
function parseHtmlToDocument(html, ownerDocument = null) {
if (ownerDocument == null) {
if (sharedDocument == null) {
sharedDocument = new MockDocument();
}
ownerDocument = sharedDocument;
}
return parseDocumentUtil(ownerDocument, html);
}
// src/mock-doc/console.ts
var consoleNoop = () => {
};
function createConsole() {
return {
debug: consoleNoop,
error: consoleNoop,
info: consoleNoop,
log: consoleNoop,
warn: consoleNoop,
dir: consoleNoop,
dirxml: consoleNoop,
table: consoleNoop,
trace: consoleNoop,
group: consoleNoop,
groupCollapsed: consoleNoop,
groupEnd: consoleNoop,
clear: consoleNoop,
count: consoleNoop,
countReset: consoleNoop,
assert: consoleNoop,
profile: consoleNoop,
profileEnd: consoleNoop,
time: consoleNoop,
timeLog: consoleNoop,
timeEnd: consoleNoop,
timeStamp: consoleNoop,
context: consoleNoop,
memory: consoleNoop
};
}
// src/mock-doc/headers.ts
var MockHeaders = class {
constructor(init) {
this._values = [];
if (typeof init === "object") {
if (typeof init[Symbol.iterator] === "function") {
const kvs = [];
for (const kv of init) {
if (typeof kv[Symbol.iterator] === "function") {
kvs.push([...kv]);
}
}
for (const kv of kvs) {
this.append(kv[0], kv[1]);
}
} else {
for (const key in init) {
this.append(key, init[key]);
}
}
}
}
append(key, value) {
this._values.push([key, value + ""]);
}
delete(key) {
key = key.toLowerCase();
for (let i = this._values.length - 1; i >= 0; i--) {
if (this._values[i][0].toLowerCase() === key) {
this._values.splice(i, 1);
}
}
}
entries() {
const entries = [];
for (const kv of this.keys()) {
entries.push([kv, this.get(kv)]);
}
let index = -1;
return {
next() {
index++;
return {
value: entries[index],
done: !entries[index]
};
},
[Symbol.iterator]() {
return this;
}
};
}
forEach(cb) {
for (const kv of this.entries()) {
cb(kv[1], kv[0]);
}
}
get(key) {
const rtn = [];
key = key.toLowerCase();
for (const kv of this._values) {
if (kv[0].toLowerCase() === key) {
rtn.push(kv[1]);
}
}
return rtn.length > 0 ? rtn.join(", ") : null;
}
has(key) {
key = key.toLowerCase();
for (const kv of this._values) {
if (kv[0].toLowerCase() === key) {
return true;
}
}
return false;
}
keys() {
const keys = [];
for (const kv of this._values) {
const key = kv[0].toLowerCase();
if (!keys.includes(key)) {
keys.push(key);
}
}
let index = -1;
return {
next() {
index++;
return {
value: keys[index],
done: !keys[index]
};
},
[Symbol.iterator]() {
return this;
}
};
}
set(key, value) {
for (const kv of this._values) {
if (kv[0].toLowerCase() === key.toLowerCase()) {
kv[1] = value + "";
return;
}
}
this.append(key, value);
}
values() {
const values = this._values;
let index = -1;
return {
next() {
index++;
const done = !values[index];
return {
value: done ? void 0 : values[index][1],
done
};
},
[Symbol.iterator]() {
return this;
}
};
}
[Symbol.iterator]() {
return this.entries();
}
};
// src/mock-doc/parser.ts
var MockDOMParser = class {
parseFromString(htmlToParse, mimeType) {
if (mimeType !== "text/html") {
console.error("XML parsing not implemented yet, continuing as html");
}
return parseHtmlToDocument(htmlToParse);
}
};
// src/mock-doc/request-response.ts
var MockRequest = class _MockRequest {
constructor(input, init = {}) {
this._method = "GET";
this._url = "/";
this.bodyUsed = false;
this.cache = "default";
this.credentials = "same-origin";
this.integrity = "";
this.keepalive = false;
this.mode = "cors";
this.redirect = "follow";
this.referrer = "about:client";
this.referrerPolicy = "";
if (typeof input === "string") {
this.url = input;
} else if (input) {
Object.assign(this, input);
this.headers = new MockHeaders(input.headers);
}
Object.assign(this, init);
if (init.headers) {
this.headers = new MockHeaders(init.headers);
}
if (!this.headers) {
this.headers = new MockHeaders();
}
}
get url() {
if (typeof this._url === "string") {
return new URL(this._url, location.href).href;
}
return new URL("/", location.href).href;
}
set url(value) {
this._url = value;
}
get method() {
if (typeof this._method === "string") {
return this._method.toUpperCase();
}
return "GET";
}
set method(value) {
this._method = value;
}
clone() {
const clone = { ...this };
clone.headers = new MockHeaders(this.headers);
return new _MockRequest(clone);
}
};
var MockResponse = class _MockResponse {
constructor(body, init = {}) {
this.ok = true;
this.status = 200;
this.statusText = "";
this.type = "default";
this.url = "";
this._body = body;
if (init) {
Object.assign(this, init);
}
this.headers = new MockHeaders(init.headers);
}
async json() {
return JSON.parse(this._body);
}
async text() {
return this._body;
}
clone() {
const initClone = { ...this };
initClone.headers = new MockHeaders(this.headers);
return new _MockResponse(this._body, initClone);
}
};
// src/mock-doc/global.ts
function patchWindow(winToBePatched) {
const mockWin = new MockWindow(false);
WINDOW_FUNCTIONS.forEach((fnName) => {
if (typeof winToBePatched[fnName] !== "function") {
winToBePatched[fnName] = mockWin[fnName].bind(mockWin);
}
});
WINDOW_PROPS.forEach((propName) => {
if (winToBePatched === void 0) {
Object.defineProperty(winToBePatched, propName, {
get() {
return mockWin[propName];
},
set(val) {
mockWin[propName] = val;
},
configurable: true,
enumerable: true
});
}
});
}
function addGlobalsToWindowPrototype(mockWinPrototype) {
GLOBAL_CONSTRUCTORS.forEach(([cstrName, Cstr]) => {
Object.defineProperty(mockWinPrototype, cstrName, {
get() {
return this["__" + cstrName] || Cstr;
},
set(cstr) {
this["__" + cstrName] = cstr;
},
configurable: true,
enumerable: true
});
});
}
var WINDOW_FUNCTIONS = [
"addEventListener",
"alert",
"blur",
"cancelAnimationFrame",
"cancelIdleCallback",
"clearInterval",
"clearTimeout",
"close",
"confirm",
"dispatchEvent",
"focus",
"getComputedStyle",
"matchMedia",
"open",
"prompt",
"removeEventListener",
"requestAnimationFrame",
"requestIdleCallback",
"URL"
];
var WINDOW_PROPS = [
"customElements",
"devicePixelRatio",
"document",
"history",
"innerHeight",
"innerWidth",
"localStorage",
"location",
"navigator",
"pageXOffset",
"pageYOffset",
"performance",
"screenLeft",
"screenTop",
"screenX",
"screenY",
"scrollX",
"scrollY",
"sessionStorage",
"CSS",
"CustomEvent",
"Event",
"Element",
"HTMLElement",
"Node",
"NodeList",
"FocusEvent",
"KeyboardEvent",
"MouseEvent",
"CSSStyleSheet"
];
var GLOBAL_CONSTRUCTORS = [
["CSSStyleSheet", MockCSSStyleSheet],
["CustomEvent", MockCustomEvent],
["DocumentFragment", MockDocumentFragment],
["DOMParser", MockDOMParser],
["Event", MockEvent],
["FocusEvent", MockFocusEvent],
["Headers", MockHeaders],
["KeyboardEvent", MockKeyboardEvent],
["MouseEvent", MockMouseEvent],
["Request", MockRequest],
["Response", MockResponse],
["ShadowRoot", MockDocumentFragment],
["HTMLAnchorElement", MockAnchorElement],
["HTMLBaseElement", MockBaseElement],
["HTMLButtonElement", MockButtonElement],
["HTMLCanvasElement", MockCanvasElement],
["HTMLFormElement", MockFormElement],
["HTMLImageElement", MockImageElement],
["HTMLInputElement", MockInputElement],
["HTMLLinkElement", MockLinkElement],
["HTMLMetaElement", MockMetaElement],
["HTMLScriptElement", MockScriptElement],
["HTMLStyleElement", MockStyleElement],
["HTMLTemplateElement", MockTemplateElement],
["HTMLTitleElement", MockTitleElement],
["HTMLUListElement", MockUListElement]
];
// src/mock-doc/history.ts
var MockHistory = class {
constructor() {
this.items = [];
}
get length() {
return this.items.length;
}
back() {
this.go(-1);
}
forward() {
this.go(1);
}
go(_value) {
}
pushState(_state, _title, _url) {
}
replaceState(_state, _title, _url) {
}
};
// src/mock-doc/intersection-observer.ts
var MockIntersectionObserver = class {
constructor() {
}
disconnect() {
}
observe() {
}
takeRecords() {
return [];
}
unobserve() {
}
};
// src/mock-doc/location.ts
var MockLocation = class {
constructor() {
this.ancestorOrigins = null;
this.protocol = "";
this.host = "";
this.hostname = "";
this.port = "";
this.pathname = "";
this.search = "";
this.hash = "";
this.username = "";
this.password = "";
this.origin = "";
this._href = "";
}
get href() {
return this._href;
}
set href(value) {
const url = new URL(value, "http://mockdoc.stenciljs.com");
this._href = url.href;
this.protocol = url.protocol;
this.host = url.host;
this.hostname = url.hostname;
this.port = url.port;
this.pathname = url.pathname;
this.search = url.search;
this.hash = url.hash;
this.username = url.username;
this.password = url.password;
this.origin = url.origin;
}
assign(_url) {
}
reload(_forcedReload) {
}
replace(_url) {
}
toString() {
return this.href;
}
};
// src/mock-doc/navigator.ts
var MockNavigator = class {
constructor() {
this.appCodeName = "MockNavigator";
this.appName = "MockNavigator";
this.appVersion = "MockNavigator";
this.platform = "MockNavigator";
this.userAgent = "MockNavigator";
}
};
// src/mock-doc/performance.ts
var MockPerformance = class {
constructor() {
this.timeOrigin = Date.now();
this.eventCounts = /* @__PURE__ */ new Map();
}
addEventListener() {
}
clearMarks() {
}
clearMeasures() {
}
clearResourceTimings() {
}
dispatchEvent() {
return true;
}
getEntries() {
return [];
}
getEntriesByName() {
return [];
}
getEntriesByType() {
return [];
}
// Stencil's implementation of `mark` is non-compliant with the `Performance` interface. Because Stencil will
// instantiate an instance of this class and may attempt to assign it to a variable of type `Performance`, the return
// type must match the `Performance` interface (rather than typing this function as returning `void` and ignoring the
// associated errors returned by the type checker)
// @ts-ignore
mark() {
}
// Stencil's implementation of `measure` is non-compliant with the `Performance` interface. Because Stencil will
// instantiate an instance of this class and may attempt to assign it to a variable of type `Performance`, the return
// type must match the `Performance` interface (rather than typing this function as returning `void` and ignoring the
// associated errors returned by the type checker)
// @ts-ignore
measure() {
}
get navigation() {
return {};
}
now() {
return Date.now() - this.timeOrigin;
}
get onresourcetimingbufferfull() {
return null;
}
removeEventListener() {
}
setResourceTimingBufferSize() {
}
get timing() {
return {};
}
toJSON() {
}
};
function resetPerformance(perf) {
if (perf != null) {
try {
perf.timeOrigin = Date.now();
} catch (e) {
}
}
}
// src/mock-doc/resize-observer.ts
var MockResizeObserver = class {
constructor() {
}
disconnect() {
}
observe() {
}
takeRecords() {
return [];
}
unobserve() {
}
};
// src/mock-doc/shadow-root.ts
var MockShadowRoot = class extends MockDocumentFragment {
get activeElement() {
return null;
}
get cloneable() {
return false;
}
get delegatesFocus() {
return false;
}
get fullscreenElement() {
return null;
}
get host() {
let parent = this.parentElement();
while (parent) {
if (parent.nodeType === 11) {
return parent;
}
parent = parent.parentElement();
}
return null;
}
get mode() {
return "open";
}
get pictureInPictureElement() {
return null;
}
get pointerLockElement() {
return null;
}
get serializable() {
return false;
}
get slotAssignment() {
return "named";
}
get styleSheets() {
return [];
}
};
// src/mock-doc/storage.ts
var MockStorage = class {
constructor() {
this.items = /* @__PURE__ */ new Map();
}
key(_value) {
}
getItem(key) {
key = String(key);
if (this.items.has(key)) {
return this.items.get(key);
}
return null;
}
setItem(key, value) {
if (value == null) {
value = "null";
}
this.items.set(String(key), String(value));
}
removeItem(key) {
this.items.delete(String(key));
}
clear() {
this.items.clear();
}
};
// src/mock-doc/window.ts
var nativeClearInterval = globalThis.clearInterval;
var nativeClearTimeout = globalThis.clearTimeout;
var nativeSetInterval = globalThis.setInterval;
var nativeSetTimeout = globalThis.setTimeout;
var nativeURL = globalThis.URL;
var nativeWindow = globalThis.window;
var MockWindow = class {
constructor(html = null) {
if (html !== false) {
this.document = new MockDocument(html, this);
} else {
this.document = null;
}
this.performance = new MockPerformance();
this.customElements = new MockCustomElementRegistry(this);
this.console = createConsole();
resetWindowDefaults(this);
resetWindowDimensions(this);
}
addEventListener(type, handler) {
addEventListener(this, type, handler);
}
alert(msg) {
if (this.console) {
this.console.debug(msg);
} else {
console.debug(msg);
}
}
blur() {
}
cancelAnimationFrame(id) {
this.__clearTimeout.call(nativeWindow || this, id);
}
cancelIdleCallback(id) {
this.__clearTimeout.call(nativeWindow || this, id);
}
get CharacterData() {
if (this.__charDataCstr == null) {
const ownerDocument = this.document;
this.__charDataCstr = class extends MockNode2 {
constructor() {
super(ownerDocument, 0, "test", "");
throw new Error("Illegal constructor: cannot construct CharacterData");
}
};
}
return this.__charDataCstr;
}
set CharacterData(charDataCstr) {
this.__charDataCstr = charDataCstr;
}
clearInterval(id) {
this.__clearInterval.call(nativeWindow || this, id);
}
clearTimeout(id) {
this.__clearTimeout.call(nativeWindow || this, id);
}
close() {
resetWindow(this);
}
confirm() {
return false;
}
get CSS() {
return {
supports: () => true
};
}
get Document() {
if (this.__docCstr == null) {
const win2 = this;
this.__docCstr = class extends MockDocument {
constructor() {
super(false, win2);
throw new Error("Illegal constructor: cannot construct Document");
}
};
}
return this.__docCstr;
}
set Document(docCstr) {
this.__docCstr = docCstr;
}
get DocumentFragment() {
if (this.__docFragCstr == null) {
const ownerDocument = this.document;
this.__docFragCstr = class extends MockDocumentFragment {
constructor() {
super(ownerDocument);
throw new Error("Illegal constructor: cannot construct DocumentFragment");
}
};
}
return this.__docFragCstr;
}
set DocumentFragment(docFragCstr) {
this.__docFragCstr = docFragCstr;
}
get ShadowRoot() {
return MockShadowRoot;
}
get DocumentType() {
if (this.__docTypeCstr == null) {
const ownerDocument = this.document;
this.__docTypeCstr = class extends MockNode2 {
constructor() {
super(ownerDocument, 0, "test", "");
throw new Error("Illegal constructor: cannot construct DocumentType");
}
};
}
return this.__docTypeCstr;
}
set DocumentType(docTypeCstr) {
this.__docTypeCstr = docTypeCstr;
}
get DOMTokenList() {
if (this.__domTokenListCstr == null) {
this.__domTokenListCstr = class MockDOMTokenList {
};
}
return this.__domTokenListCstr;
}
set DOMTokenList(domTokenListCstr) {
this.__domTokenListCstr = domTokenListCstr;
}
dispatchEvent(ev) {
return dispatchEvent(this, ev);
}
get Element() {
if (this.__elementCstr == null) {
const ownerDocument = this.document;
this.__elementCstr = class extends MockElement {
constructor() {
super(ownerDocument, "");
throw new Error("Illegal constructor: cannot construct Element");
}
};
}
return this.__elementCstr;
}
fetch(input, init) {
if (typeof fetch === "function") {
return fetch(input, init);
}
throw new Error(`fetch() not implemented`);
}
focus() {
}
getComputedStyle(_) {
return {
cssText: "",
length: 0,
parentRule: null,
getPropertyPriority() {
return null;
},
getPropertyValue() {
return "";
},
item() {
return null;
},
removeProperty() {
return null;
},
setProperty() {
return null;
}
};
}
get globalThis() {
return this;
}
get history() {
if (this.__history == null) {
this.__history = new MockHistory();
}
return this.__history;
}
set history(hsty) {
this.__history = hsty;
}
get JSON() {
return JSON;
}
get HTMLElement() {
if (this.__htmlElementCstr == null) {
const ownerDocument = this.document;
this.__htmlElementCstr = class extends MockHTMLElement {
constructor() {
super(ownerDocument, "");
const observedAttributes = this.constructor.observedAttributes;
if (Array.isArray(observedAttributes) && typeof this.attributeChangedCallback === "function") {
observedAttributes.forEach((attrName) => {
const attrValue = this.getAttribute(attrName);
if (attrValue != null) {
this.attributeChangedCallback(attrName, null, attrValue);
}
});
}
}
};
}
return this.__htmlElementCstr;
}
set HTMLElement(htmlElementCstr) {
this.__htmlElementCstr = htmlElementCstr;
}
get IntersectionObserver() {
return MockIntersectionObserver;
}
get ResizeObserver() {
return MockResizeObserver;
}
get localStorage() {
if (this.__localStorage == null) {
this.__localStorage = new MockStorage();
}
return this.__localStorage;
}
set localStorage(locStorage) {
this.__localStorage = locStorage;
}
get location() {
if (this.__location == null) {
this.__location = new MockLocation();
}
return this.__location;
}
set location(val) {
if (typeof val === "string") {
if (this.__location == null) {
this.__location = new MockLocation();
}
this.__location.href = val;
} else {
this.__location = val;
}
}
matchMedia(media) {
return {
media,
matches: false,
addListener: (_handler) => {
},
removeListener: (_handler) => {
},
addEventListener: (_type, _handler) => {
},
removeEventListener: (_type, _handler) => {
},
dispatchEvent: (_ev) => {
},
onchange: null
};
}
get Node() {
if (this.__nodeCstr == null) {
const ownerDocument = this.document;
this.__nodeCstr = class extends MockNode2 {
constructor() {
super(ownerDocument, 0, "test", "");
throw new Error("Illegal constructor: cannot construct Node");
}
};
}
return this.__nodeCstr;
}
get NodeList() {
if (this.__nodeListCstr == null) {
const ownerDocument = this.document;
this.__nodeListCstr = class extends MockNodeList {
constructor() {
super(ownerDocument, [], 0);
throw new Error("Illegal constructor: cannot construct NodeList");
}
};
}
return this.__nodeListCstr;
}
get navigator() {
if (this.__navigator == null) {
this.__navigator = new MockNavigator();
}
return this.__navigator;
}
set navigator(nav) {
this.__navigator = nav;
}
get parent() {
return null;
}
prompt() {
return "";
}
open() {
return null;
}
get origin() {
return this.location.origin;
}
removeEventListener(type, handler) {
removeEventListener(this, type, handler);
}
requestAnimationFrame(callback) {
return this.setTimeout(() => {
callback(Date.now());
}, 0);
}
requestIdleCallback(callback) {
return this.setTimeout(() => {
callback({
didTimeout: false,
timeRemaining: () => 0
});
}, 0);
}
scroll(_x, _y) {
}
scrollBy(_x, _y) {
}
scrollTo(_x, _y) {
}
get self() {
return this;
}
get sessionStorage() {
if (this.__sessionStorage == null) {
this.__sessionStorage = new MockStorage();
}
return this.__sessionStorage;
}
set sessionStorage(locStorage) {
this.__sessionStorage = locStorage;
}
setInterval(callback, ms, ...args) {
if (this.__timeouts == null) {
this.__timeouts = /* @__PURE__ */ new Set();
}
ms = Math.min(ms, this.__maxTimeout);
if (this.__allowInterval) {
const intervalId = this.__setInterval(() => {
if (this.__timeouts) {
this.__timeouts.delete(intervalId);
try {
callback(...args);
} catch (e) {
if (this.console) {
this.console.error(e);
} else {
console.error(e);
}
}
}
}, ms);
if (this.__timeouts) {
this.__timeouts.add(intervalId);
}
return intervalId;
}
const timeoutId = this.__setTimeout.call(
nativeWindow || this,
() => {
if (this.__timeouts) {
this.__timeouts.delete(timeoutId);
try {
callback(...args);
} catch (e) {
if (this.console) {
this.console.error(e);
} else {
console.error(e);
}
}
}
},
ms
);
if (this.__timeouts) {
this.__timeouts.add(timeoutId);
}
return timeoutId;
}
setTimeout(callback, ms, ...args) {
if (this.__timeouts == null) {
this.__timeouts = /* @__PURE__ */ new Set();
}
ms = Math.min(ms, this.__maxTimeout);
const timeoutId = this.__setTimeout.call(
nativeWindow || this,
() => {
if (this.__timeouts) {
this.__timeouts.delete(timeoutId);
try {
callback(...args);
} catch (e) {
if (this.console) {
this.console.error(e);
} else {
console.error(e);
}
}
}
},
ms
);
if (this.__timeouts) {
this.__timeouts.add(timeoutId);
}
return timeoutId;
}
get top() {
return this;
}
get window() {
return this;
}
onanimationstart() {
}
onanimationend() {
}
onanimationiteration() {
}
onabort() {
}
onauxclick() {
}
onbeforecopy() {
}
onbeforecut() {
}
onbeforepaste() {
}
onblur() {
}
oncancel() {
}
oncanplay() {
}
oncanplaythrough() {
}
onchange() {
}
onclick() {
}
onclose() {
}
oncontextmenu() {
}
oncopy() {
}
oncuechange() {
}
oncut() {
}
ondblclick() {
}
ondrag() {
}
ondragend() {
}
ondragenter() {
}
ondragleave() {
}
ondragover() {
}
ondragstart() {
}
ondrop() {
}
ondurationchange() {
}
onemptied() {
}
onended() {
}
onerror() {
}
onfocus() {
}
onfocusin() {
}
onfocusout() {
}
onformdata() {
}
onfullscreenchange() {
}
onfullscreenerror() {
}
ongotpointercapture() {
}
oninput() {
}
oninvalid() {
}
onkeydown() {
}
onkeypress() {
}
onkeyup() {
}
onload() {
}
onloadeddata() {
}
onloadedmetadata() {
}
onloadstart() {
}
onlostpointercapture() {
}
onmousedown() {
}
onmouseenter() {
}
onmouseleave() {
}
onmousemove() {
}
onmouseout() {
}
onmouseover() {
}
onmouseup() {
}
onmousewheel() {
}
onpaste() {
}
onpause() {
}
onplay() {
}
onplaying() {
}
onpointercancel() {
}
onpointerdown() {
}
onpointerenter() {
}
onpointerleave() {
}
onpointermove() {
}
onpointerout() {
}
onpointerover() {
}
onpointerup() {
}
onprogress() {
}
onratechange() {
}
onreset() {
}
onresize() {
}
onscroll() {
}
onsearch() {
}
onseeked() {
}
onseeking() {
}
onselect() {
}
onselectstart() {
}
onstalled() {
}
onsubmit() {
}
onsuspend() {
}
ontimeupdate() {
}
ontoggle() {
}
onvolumechange() {
}
onwaiting() {
}
onwebkitfullscreenchange() {
}
onwebkitfullscreenerror() {
}
onwheel() {
}
};
addGlobalsToWindowPrototype(MockWindow.prototype);
function resetWindowDefaults(win2) {
win2.__clearInterval = nativeClearInterval;
win2.__clearTimeout = nativeClearTimeout;
win2.__setInterval = nativeSetInterval;
win2.__setTimeout = nativeSetTimeout;
win2.__maxTimeout = 6e4;
win2.__allowInterval = true;
win2.URL = nativeURL;
}
function cloneWindow(srcWin, opts = {}) {
if (srcWin == null) {
return null;
}
const clonedWin = new MockWindow(false);
if (!opts.customElementProxy) {
srcWin.customElements = null;
}
if (srcWin.document != null) {
const clonedDoc = new MockDocument(false, clonedWin);
clonedWin.document = clonedDoc;
clonedDoc.documentElement = srcWin.document.documentElement.cloneNode(true);
} else {
clonedWin.document = new MockDocument(null, clonedWin);
}
return clonedWin;
}
function constrainTimeouts(win2) {
win2.__allowInterval = false;
win2.__maxTimeout = 0;
}
function resetWindow(win2) {
if (win2 != null) {
if (win2.__timeouts) {
win2.__timeouts.forEach((timeoutId) => {
nativeClearInterval(timeoutId);
nativeClearTimeout(timeoutId);
});
win2.__timeouts.clear();
}
if (win2.customElements && win2.customElements.clear) {
win2.customElements.clear();
}
resetDocument(win2.document);
resetPerformance(win2.performance);
for (const key in win2) {
if (win2.hasOwnProperty(key) && key !== "document" && key !== "performance" && key !== "customElements") {
delete win2[key];
}
}
resetWindowDefaults(win2);
resetWindowDimensions(win2);
resetEventListeners(win2);
if (win2.document != null) {
try {
win2.document.defaultView = win2;
} catch (e) {
}
}
win2.fetch = null;
win2.Headers = null;
win2.Request = null;
win2.Response = null;
win2.FetchError = null;
}
}
function resetWindowDimensions(win2) {
try {
win2.devicePixelRatio = 1;
win2.innerHeight = 768;
win2.innerWidth = 1366;
win2.pageXOffset = 0;
win2.pageYOffset = 0;
win2.screenLeft = 0;
win2.screenTop = 0;
win2.screenX = 0;
win2.screenY = 0;
win2.scrollX = 0;
win2.scrollY = 0;
win2.screen = {
availHeight: win2.innerHeight,
availLeft: 0,
availTop: 0,
availWidth: win2.innerWidth,
colorDepth: 24,
height: win2.innerHeight,
keepAwake: false,
orientation: {
angle: 0,
type: "portrait-primary"
},
pixelDepth: 24,
width: win2.innerWidth
};
} catch (e) {
}
}
// src/mock-doc/document.ts
var MockDocument = class _MockDocument extends MockHTMLElement {
constructor(html = null, win2 = null) {
super(null, null);
this.nodeName = "#document" /* DOCUMENT_NODE */;
this.nodeType = 9 /* DOCUMENT_NODE */;
this.defaultView = win2;
this.cookie = "";
this.referrer = "";
this.appendChild(this.createDocumentTypeNode());
if (typeof html === "string") {
const parsedDoc = parseDocumentUtil(this, html);
const documentElement = parsedDoc.children.find((elm) => elm.nodeName === "HTML");
if (documentElement != null) {
this.appendChild(documentElement);
setOwnerDocument(documentElement, this);
}
} else if (html !== false) {
const documentElement = new MockHTMLElement(this, "html");
this.appendChild(documentElement);
documentElement.appendChild(new MockHTMLElement(this, "head"));
documentElement.appendChild(new MockHTMLElement(this, "body"));
}
}
get dir() {
return this.documentElement.dir;
}
set dir(value) {
this.documentElement.dir = value;
}
get localName() {
throw new Error("Unimplemented");
}
get location() {
if (this.defaultView != null) {
return this.defaultView.location;
}
return null;
}
set location(val) {
if (this.defaultView != null) {
this.defaultView.location = val;
}
}
get baseURI() {
const baseNode = this.head.childNodes.find((node) => node.nodeName === "BASE");
if (baseNode) {
return baseNode.href;
}
return this.URL;
}
get URL() {
return this.location.href;
}
get styleSheets() {
return this.querySelectorAll("style");
}
get scripts() {
return this.querySelectorAll("script");
}
get forms() {
return this.querySelectorAll("form");
}
get images() {
return this.querySelectorAll("img");
}
get scrollingElement() {
return this.documentElement;
}
get documentElement() {
for (let i = this.childNodes.length - 1; i >= 0; i--) {
if (this.childNodes[i].nodeName === "HTML") {
return this.childNodes[i];
}
}
const documentElement = new MockHTMLElement(this, "html");
this.appendChild(documentElement);
return documentElement;
}
set documentElement(documentElement) {
for (let i = this.childNodes.length - 1; i >= 0; i--) {
if (this.childNodes[i].nodeType !== 10 /* DOCUMENT_TYPE_NODE */) {
this.childNodes[i].remove();
}
}
if (documentElement != null) {
this.appendChild(documentElement);
setOwnerDocument(documentElement, this);
}
}
get head() {
const documentElement = this.documentElement;
for (let i = 0; i < documentElement.childNodes.length; i++) {
if (documentElement.childNodes[i].nodeName === "HEAD") {
return documentElement.childNodes[i];
}
}
const head = new MockHTMLElement(this, "head");
documentElement.insertBefore(head, documentElement.firstChild);
return head;
}
set head(head) {
const documentElement = this.documentElement;
for (let i = documentElement.childNodes.length - 1; i >= 0; i--) {
if (documentElement.childNodes[i].nodeName === "HEAD") {
documentElement.childNodes[i].remove();
}
}
if (head != null) {
documentElement.insertBefore(head, documentElement.firstChild);
setOwnerDocument(head, this);
}
}
get body() {
const documentElement = this.documentElement;
for (let i = documentElement.childNodes.length - 1; i >= 0; i--) {
if (documentElement.childNodes[i].nodeName === "BODY") {
return documentElement.childNodes[i];
}
}
const body = new MockHTMLElement(this, "body");
documentElement.appendChild(body);
return body;
}
set body(body) {
const documentElement = this.documentElement;
for (let i = documentElement.childNodes.length - 1; i >= 0; i--) {
if (documentElement.childNodes[i].nodeName === "BODY") {
documentElement.childNodes[i].remove();
}
}
if (body != null) {
documentElement.appendChild(body);
setOwnerDocument(body, this);
}
}
appendChild(newNode) {
newNode.remove();
newNode.parentNode = this;
this.childNodes.push(newNode);
return newNode;
}
createComment(data) {
return new MockComment(this, data);
}
createAttribute(attrName) {
return new MockAttr(attrName.toLowerCase(), "");
}
createAttributeNS(namespaceURI, attrName) {
return new MockAttr(attrName, "", namespaceURI);
}
createElement(tagName) {
if (tagName === "#document" /* DOCUMENT_NODE */) {
const doc = new _MockDocument(false);
doc.nodeName = tagName;
doc.parentNode = null;
return doc;
}
return createElement(this, tagName);
}
createElementNS(namespaceURI, tagName) {
const elmNs = createElementNS(this, namespaceURI, tagName);
return elmNs;
}
createTextNode(text) {
return new MockTextNode(this, text);
}
createDocumentFragment() {
return new MockDocumentFragment(this);
}
createDocumentTypeNode() {
return new MockDocumentTypeNode(this);
}
getElementById(id) {
return getElementById(this, id);
}
getElementsByName(elmName) {
return getElementsByName(this, elmName.toLowerCase());
}
get title() {
const title = this.head.childNodes.find((elm) => elm.nodeName === "TITLE");
if (title != null && typeof title.textContent === "string") {
return title.textContent.trim();
}
return "";
}
set title(value) {
const head = this.head;
let title = head.childNodes.find((elm) => elm.nodeName === "TITLE");
if (title == null) {
title = this.createElement("title");
head.appendChild(title);
}
title.textContent = value;
}
};
function resetDocument(doc) {
if (doc != null) {
resetEventListeners(doc);
const documentElement = doc.documentElement;
if (documentElement != null) {
resetElement(documentElement);
for (let i = 0, ii = documentElement.childNodes.length; i < ii; i++) {
const childNode = documentElement.childNodes[i];
resetElement(childNode);
childNode.childNodes.length = 0;
}
}
for (const key in doc) {
if (doc.hasOwnProperty(key) && !DOC_KEY_KEEPERS.has(key)) {
delete doc[key];
}
}
try {
doc.nodeName = "#document" /* DOCUMENT_NODE */;
} catch (e) {
}
try {
doc.nodeType = 9 /* DOCUMENT_NODE */;
} catch (e) {
}
try {
doc.cookie = "";
} catch (e) {
}
try {
doc.referrer = "";
} catch (e) {
}
}
}
var DOC_KEY_KEEPERS = /* @__PURE__ */ new Set([
"nodeName",
"nodeType",
"nodeValue",
"ownerDocument",
"parentNode",
"childNodes",
"_shadowRoot"
]);
function getElementById(elm, id) {
const children = elm.children;
for (let i = 0, ii = children.length; i < ii; i++) {
const childElm = children[i];
if (childElm.id === id) {
return childElm;
}
const childElmFound = getElementById(childElm, id);
if (childElmFound != null) {
return childElmFound;
}
}
return null;
}
function getElementsByName(elm, elmName, foundElms = []) {
const children = elm.children;
for (let i = 0, ii = children.length; i < ii; i++) {
const childElm = children[i];
if (childElm.name && childElm.name.toLowerCase() === elmName) {
foundElms.push(childElm);
}
getElementsByName(childElm, elmName, foundElms);
}
return foundElms;
}
function setOwnerDocument(elm, ownerDocument) {
for (let i = 0, ii = elm.childNodes.length; i < ii; i++) {
elm.childNodes[i].ownerDocument = ownerDocument;
if (elm.childNodes[i].nodeType === 1 /* ELEMENT_NODE */) {
setOwnerDocument(elm.childNodes[i], ownerDocument);
}
}
}
// src/hydrate/runner/create-window.ts
var templateWindows = /* @__PURE__ */ new Map();
function createWindowFromHtml(templateHtml, uniqueId) {
let templateWindow = templateWindows.get(uniqueId);
if (templateWindow == null) {
templateWindow = new MockWindow(templateHtml);
templateWindows.set(uniqueId, templateWindow);
}
const win2 = cloneWindow(templateWindow);
return win2;
}
var Build = {
isDev: BUILD.isDev ? true : false,
isBrowser: true,
isServer: false,
isTesting: BUILD.isTesting ? true : false
};
// src/utils/constants.ts
var PrimitiveType = /* @__PURE__ */ ((PrimitiveType2) => {
PrimitiveType2["Undefined"] = "undefined";
PrimitiveType2["Null"] = "null";
PrimitiveType2["String"] = "string";
PrimitiveType2["Number"] = "number";
PrimitiveType2["SpecialNumber"] = "number";
PrimitiveType2["Boolean"] = "boolean";
PrimitiveType2["BigInt"] = "bigint";
return PrimitiveType2;
})(PrimitiveType || {});
var NonPrimitiveType = /* @__PURE__ */ ((NonPrimitiveType2) => {
NonPrimitiveType2["Array"] = "array";
NonPrimitiveType2["Date"] = "date";
NonPrimitiveType2["Map"] = "map";
NonPrimitiveType2["Object"] = "object";
NonPrimitiveType2["RegularExpression"] = "regexp";
NonPrimitiveType2["Set"] = "set";
NonPrimitiveType2["Channel"] = "channel";
NonPrimitiveType2["Symbol"] = "symbol";
return NonPrimitiveType2;
})(NonPrimitiveType || {});
var TYPE_CONSTANT = "type";
var VALUE_CONSTANT = "value";
var SERIALIZED_PREFIX = "serialized:";
var STENCIL_DEV_MODE = BUILD.isTesting ? ["STENCIL:"] : [
"%cstencil",
"color: white;background:#4c47ff;font-weight: bold; font-size:10px; padding:2px 6px; border-radius: 5px"
];
var win = typeof window !== "undefined" ? window : {};
var H = win.HTMLElement || class {
};
var supportsShadow = BUILD.shadowDom;
var supportsConstructableStylesheets = BUILD.constructableCSS ? /* @__PURE__ */ (() => {
try {
new CSSStyleSheet();
return typeof new CSSStyleSheet().replaceSync === "function";
} catch (e) {
}
return false;
})() : false;
// src/utils/helpers.ts
var isString = (v) => typeof v === "string";
// src/utils/local-value.ts
var LocalValue = class _LocalValue {
constructor(type, value) {
if (type === "undefined" /* Undefined */ || type === "null" /* Null */) {
this.type = type;
} else {
this.type = type;
this.value = value;
}
}
/**
* Creates a new LocalValue object with a string value.
*
* @param {string} value - The string value to be stored in the LocalValue object.
* @returns {LocalValue} - The created LocalValue object.
*/
static createStringValue(value) {
return new _LocalValue("string" /* String */, value);
}
/**
* Creates a new LocalValue object with a number value.
*
* @param {number} value - The number value.
* @returns {LocalValue} - The created LocalValue object.
*/
static createNumberValue(value) {
return new _LocalValue("number" /* Number */, value);
}
/**
* Creates a new LocalValue object with a special number value.
*
* @param {number} value - The value of the special number.
* @returns {LocalValue} - The created LocalValue object.
*/
static createSpecialNumberValue(value) {
if (Number.isNaN(value)) {
return new _LocalValue("number" /* SpecialNumber */, "NaN");
}
if (Object.is(value, -0)) {
return new _LocalValue("number" /* SpecialNumber */, "-0");
}
if (value === Infinity) {
return new _LocalValue("number" /* SpecialNumber */, "Infinity");
}
if (value === -Infinity) {
return new _LocalValue("number" /* SpecialNumber */, "-Infinity");
}
return new _LocalValue("number" /* SpecialNumber */, value);
}
/**
* Creates a new LocalValue object with an undefined value.
* @returns {LocalValue} - The created LocalValue object.
*/
static createUndefinedValue() {
return new _LocalValue("undefined" /* Undefined */);
}
/**
* Creates a new LocalValue object with a null value.
* @returns {LocalValue} - The created LocalValue object.
*/
static createNullValue() {
return new _LocalValue("null" /* Null */);
}
/**
* Creates a new LocalValue object with a boolean value.
*
* @param {boolean} value - The boolean value.
* @returns {LocalValue} - The created LocalValue object.
*/
static createBooleanValue(value) {
return new _LocalValue("boolean" /* Boolean */, value);
}
/**
* Creates a new LocalValue object with a BigInt value.
*
* @param {BigInt} value - The BigInt value.
* @returns {LocalValue} - The created LocalValue object.
*/
static createBigIntValue(value) {
return new _LocalValue("bigint" /* BigInt */, value.toString());
}
/**
* Creates a new LocalValue object with an array.
*
* @param {Array} value - The array.
* @returns {LocalValue} - The created LocalValue object.
*/
static createArrayValue(value) {
return new _LocalValue("array" /* Array */, value);
}
/**
* Creates a new LocalValue object with date value.
*
* @param {string} value - The date.
* @returns {LocalValue} - The created LocalValue object.
*/
static createDateValue(value) {
return new _LocalValue("date" /* Date */, value);
}
/**
* Creates a new LocalValue object of map value.
* @param {Map} map - The map.
* @returns {LocalValue} - The created LocalValue object.
*/
static createMapValue(map2) {
const value = [];
Array.from(map2.entries()).forEach(([key, val]) => {
value.push([_LocalValue.getArgument(key), _LocalValue.getArgument(val)]);
});
return new _LocalValue("map" /* Map */, value);
}
/**
* Creates a new LocalValue object from the passed object.
*
* @param object the object to create a LocalValue from
* @returns {LocalValue} - The created LocalValue object.
*/
static createObjectValue(object) {
const value = [];
Object.entries(object).forEach(([key, val]) => {
value.push([key, _LocalValue.getArgument(val)]);
});
return new _LocalValue("object" /* Object */, value);
}
/**
* Creates a new LocalValue object of regular expression value.
*
* @param {string} value - The value of the regular expression.
* @returns {LocalValue} - The created LocalValue object.
*/
static createRegularExpressionValue(value) {
return new _LocalValue("regexp" /* RegularExpression */, value);
}
/**
* Creates a new LocalValue object with the specified value.
* @param {Set} value - The value to be set.
* @returns {LocalValue} - The created LocalValue object.
*/
static createSetValue(value) {
return new _LocalValue("set" /* Set */, value);
}
/**
* Creates a new LocalValue object with the given channel value
*
* @param {ChannelValue} value - The channel value.
* @returns {LocalValue} - The created LocalValue object.
*/
static createChannelValue(value) {
return new _LocalValue("channel" /* Channel */, value);
}
/**
* Creates a new LocalValue object with a Symbol value.
*
* @param {Symbol} symbol - The Symbol value
* @returns {LocalValue} - The created LocalValue object
*/
static createSymbolValue(symbol) {
const description = symbol.description || "Symbol()";
return new _LocalValue("symbol" /* Symbol */, description);
}
static getArgument(argument) {
const type = typeof argument;
switch (type) {
case "string" /* String */:
return _LocalValue.createStringValue(argument);
case "number" /* Number */:
if (Number.isNaN(argument) || Object.is(argument, -0) || !Number.isFinite(argument)) {
return _LocalValue.createSpecialNumberValue(argument);
}
return _LocalValue.createNumberValue(argument);
case "boolean" /* Boolean */:
return _LocalValue.createBooleanValue(argument);
case "bigint" /* BigInt */:
return _LocalValue.createBigIntValue(argument);
case "undefined" /* Undefined */:
return _LocalValue.createUndefinedValue();
case "symbol" /* Symbol */:
return _LocalValue.createSymbolValue(argument);
case "object" /* Object */:
if (argument === null) {
return _LocalValue.createNullValue();
}
if (argument instanceof Date) {
return _LocalValue.createDateValue(argument);
}
if (argument instanceof Map) {
const map2 = [];
argument.forEach((value, key) => {
const objectKey = typeof key === "string" ? key : _LocalValue.getArgument(key);
const objectValue = _LocalValue.getArgument(value);
map2.push([objectKey, objectValue]);
});
return _LocalValue.createMapValue(argument);
}
if (argument instanceof Set) {
const set = [];
argument.forEach((value) => {
set.push(_LocalValue.getArgument(value));
});
return _LocalValue.createSetValue(set);
}
if (argument instanceof Array) {
const arr = [];
argument.forEach((value) => {
arr.push(_LocalValue.getArgument(value));
});
return _LocalValue.createArrayValue(arr);
}
if (argument instanceof RegExp) {
return _LocalValue.createRegularExpressionValue({
pattern: argument.source,
flags: argument.flags
});
}
return _LocalValue.createObjectValue(argument);
}
throw new Error(`Unsupported type: ${type}`);
}
asMap() {
return {
[TYPE_CONSTANT]: this.type,
...!(this.type === "null" /* Null */ || this.type === "undefined" /* Undefined */) ? { [VALUE_CONSTANT]: this.value } : {}
};
}
};
// src/utils/message-utils.ts
var catchError = (diagnostics, err2, msg) => {
const diagnostic = {
level: "error",
type: "build",
header: "Build Error",
messageText: "build error",
lines: []
};
if (isString(msg)) {
diagnostic.messageText = msg.length ? msg : "UNKNOWN ERROR";
} else if (err2 != null) {
if (err2.stack != null) {
diagnostic.messageText = err2.stack.toString();
} else {
if (err2.message != null) {
diagnostic.messageText = err2.message.length ? err2.message : "UNKNOWN ERROR";
} else {
diagnostic.messageText = err2.toString();
}
}
}
if (diagnostics != null && !shouldIgnoreError(diagnostic.messageText)) {
diagnostics.push(diagnostic);
}
return diagnostic;
};
var hasError = (diagnostics) => {
if (diagnostics == null || diagnostics.length === 0) {
return false;
}
return diagnostics.some((d) => d.level === "error" && d.type !== "runtime");
};
var shouldIgnoreError = (msg) => {
return msg === TASK_CANCELED_MSG;
};
var TASK_CANCELED_MSG = `task canceled`;
// src/utils/regular-expression.ts
var escapeRegExpSpecialCharacters = (text) => {
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};
// src/utils/remote-value.ts
var RemoteValue = class _RemoteValue {
/**
* Deserializes a LocalValue serialized object back to its original JavaScript representation
*
* @param serialized The serialized LocalValue object
* @returns The original JavaScript value/object
*/
static fromLocalValue(serialized) {
const type = serialized[TYPE_CONSTANT];
const value = VALUE_CONSTANT in serialized ? serialized[VALUE_CONSTANT] : void 0;
switch (type) {
case "string" /* String */:
return value;
case "boolean" /* Boolean */:
return value;
case "bigint" /* BigInt */:
return BigInt(value);
case "undefined" /* Undefined */:
return void 0;
case "null" /* Null */:
return null;
case "number" /* Number */:
if (value === "NaN") return NaN;
if (value === "-0") return -0;
if (value === "Infinity") return Infinity;
if (value === "-Infinity") return -Infinity;
return value;
case "array" /* Array */:
return value.map((item) => _RemoteValue.fromLocalValue(item));
case "date" /* Date */:
return new Date(value);
case "map" /* Map */:
const map2 = /* @__PURE__ */ new Map();
for (const [key, val] of value) {
const deserializedKey = typeof key === "object" && key !== null ? _RemoteValue.fromLocalValue(key) : key;
const deserializedValue = _RemoteValue.fromLocalValue(val);
map2.set(deserializedKey, deserializedValue);
}
return map2;
case "object" /* Object */:
const obj = {};
for (const [key, val] of value) {
obj[key] = _RemoteValue.fromLocalValue(val);
}
return obj;
case "regexp" /* RegularExpression */:
const { pattern, flags } = value;
return new RegExp(pattern, flags);
case "set" /* Set */:
const set = /* @__PURE__ */ new Set();
for (const item of value) {
set.add(_RemoteValue.fromLocalValue(item));
}
return set;
case "symbol" /* Symbol */:
return Symbol(value);
default:
throw new Error(`Unsupported type: ${type}`);
}
}
/**
* Utility method to deserialize multiple LocalValues at once
*
* @param serializedValues Array of serialized LocalValue objects
* @returns Array of deserialized JavaScript values
*/
static fromLocalValueArray(serializedValues) {
return serializedValues.map((value) => _RemoteValue.fromLocalValue(value));
}
/**
* Verifies if the given object matches the structure of a serialized LocalValue
*
* @param obj Object to verify
* @returns boolean indicating if the object has LocalValue structure
*/
static isLocalValueObject(obj) {
if (typeof obj !== "object" || obj === null) {
return false;
}
if (!obj.hasOwnProperty(TYPE_CONSTANT)) {
return false;
}
const type = obj[TYPE_CONSTANT];
const hasTypeProperty = Object.values({ ...PrimitiveType, ...NonPrimitiveType }).includes(type);
if (!hasTypeProperty) {
return false;
}
if (type !== "null" /* Null */ && type !== "undefined" /* Undefined */) {
return obj.hasOwnProperty(VALUE_CONSTANT);
}
return true;
}
};
// src/utils/result.ts
var result_exports = {};
__export(result_exports, {
err: () => err,
map: () => map,
ok: () => ok,
unwrap: () => unwrap,
unwrapErr: () => unwrapErr
});
var ok = (value) => ({
isOk: true,
isErr: false,
value
});
var err = (value) => ({
isOk: false,
isErr: true,
value
});
function map(result, fn) {
if (result.isOk) {
const val = fn(result.value);
if (val instanceof Promise) {
return val.then((newVal) => ok(newVal));
} else {
return ok(val);
}
}
if (result.isErr) {
const value = result.value;
return err(value);
}
throw "should never get here";
}
var unwrap = (result) => {
if (result.isOk) {
return result.value;
} else {
throw result.value;
}
};
var unwrapErr = (result) => {
if (result.isErr) {
return result.value;
} else {
throw result.value;
}
};
// src/utils/serialize.ts
function serializeProperty(value) {
if (["string", "boolean", "undefined"].includes(typeof value) || typeof value === "number" && value !== Infinity && value !== -Infinity && !isNaN(value)) {
return value;
}
const arg = LocalValue.getArgument(value);
return SERIALIZED_PREFIX + btoa(JSON.stringify(arg));
}
function deserializeProperty(value) {
if (typeof value !== "string" || !value.startsWith(SERIALIZED_PREFIX)) {
return value;
}
return RemoteValue.fromLocalValue(JSON.parse(atob(value.slice(SERIALIZED_PREFIX.length))));
}
// src/utils/util.ts
var lowerPathParam = (fn) => (p) => fn(p.toLowerCase());
var isDtsFile = lowerPathParam((p) => p.endsWith(".d.ts") || p.endsWith(".d.mts") || p.endsWith(".d.cts"));
var isTsFile = lowerPathParam(
(p) => !isDtsFile(p) && (p.endsWith(".ts") || p.endsWith(".mts") || p.endsWith(".cts"))
);
var isTsxFile = lowerPathParam(
(p) => p.endsWith(".tsx") || p.endsWith(".mtsx") || p.endsWith(".ctsx")
);
var isJsxFile = lowerPathParam(
(p) => p.endsWith(".jsx") || p.endsWith(".mjsx") || p.endsWith(".cjsx")
);
var isJsFile = lowerPathParam((p) => p.endsWith(".js") || p.endsWith(".mjs") || p.endsWith(".cjs"));
// src/utils/shadow-css.ts
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*
* This file is a port of shadowCSS from `webcomponents.js` to TypeScript.
* https://github.com/webcomponents/webcomponentsjs/blob/4efecd7e0e/src/ShadowCSS/ShadowCSS.js
* https://github.com/angular/angular/blob/master/packages/compiler/src/shadow_css.ts
*/
var _polyfillHost = "-shadowcsshost";
var _polyfillSlotted = "-shadowcssslotted";
var _polyfillHostContext = "-shadowcsscontext";
var _parenSuffix = ")(?:\\(((?:\\([^)(]*\\)|[^)(]*)+?)\\))?([^,{]*)";
var _cssColonHostRe = new RegExp("(" + _polyfillHost + _parenSuffix, "gim");
var _cssColonHostContextRe = new RegExp("(" + _polyfillHostContext + _parenSuffix, "gim");
var _cssColonSlottedRe = new RegExp("(" + _polyfillSlotted + _parenSuffix, "gim");
var _polyfillHostNoCombinator = _polyfillHost + "-no-combinator";
var createSupportsRuleRe = (selector) => {
const safeSelector = escapeRegExpSpecialCharacters(selector);
return new RegExp(
// First capture group: match any context before the selector that's not inside @supports selector()
// Using negative lookahead to avoid matching inside @supports selector(...) condition
`(^|[^@]|@(?!supports\\s+selector\\s*\\([^{]*?${safeSelector}))(${safeSelector}\\b)`,
"g"
);
};
var _colonSlottedRe = createSupportsRuleRe("::slotted");
var _colonHostRe = createSupportsRuleRe(":host");
var _colonHostContextRe = createSupportsRuleRe(":host-context");
// src/runtime/mode.ts
var setMode = (handler) => modeResolutionChain.push(handler);
var CAPTURE_EVENT_SUFFIX = "Capture";
var CAPTURE_EVENT_REGEX = new RegExp(CAPTURE_EVENT_SUFFIX + "$");
var baseClass = BUILD.lazyLoad ? class {
} : globalThis.HTMLElement || class {
};
// src/compiler/html/canonical-link.ts
var updateCanonicalLink = (doc, href) => {
var _a2;
let canonicalLinkElm = doc.head.querySelector('link[rel="canonical"]');
if (typeof href === "string") {
if (canonicalLinkElm == null) {
canonicalLinkElm = doc.createElement("link");
canonicalLinkElm.setAttribute("rel", "canonical");
doc.head.appendChild(canonicalLinkElm);
}
canonicalLinkElm.setAttribute("href", href);
} else {
if (canonicalLinkElm != null) {
const existingHref = canonicalLinkElm.getAttribute("href");
if (!existingHref) {
(_a2 = canonicalLinkElm.parentNode) == null ? void 0 : _a2.removeChild(canonicalLinkElm);
}
}
}
};
// src/compiler/html/relocate-meta-charset.ts
var relocateMetaCharset = (doc) => {
const head = doc.head;
let charsetElm = head.querySelector("meta[charset]");
if (charsetElm == null) {
charsetElm = doc.createElement("meta");
charsetElm.setAttribute("charset", "utf-8");
} else {
charsetElm.remove();
}
head.insertBefore(charsetElm, head.firstChild);
};
// src/compiler/style/css-parser/parse-css.ts
var parseCss = (css, filePath) => {
let lineno = 1;
let column = 1;
const diagnostics = [];
const updatePosition = (str) => {
const lines = str.match(/\n/g);
if (lines) lineno += lines.length;
const i = str.lastIndexOf("\n");
column = ~i ? str.length - i : column + str.length;
};
const position = () => {
const start = { line: lineno, column };
return (node) => {
node.position = new ParsePosition(start);
whitespace();
return node;
};
};
const error = (msg) => {
const srcLines = css.split("\n");
const d = {
level: "error",
type: "css",
language: "css",
header: "CSS Parse",
messageText: msg,
absFilePath: filePath,
lines: [
{
lineIndex: lineno - 1,
lineNumber: lineno,
errorCharStart: column,
text: css[lineno - 1]
}
]
};
if (lineno > 1) {
const previousLine = {
lineIndex: lineno - 1,
lineNumber: lineno - 1,
text: css[lineno - 2],
errorCharStart: -1,
errorLength: -1
};
d.lines.unshift(previousLine);
}
if (lineno + 2 < srcLines.length) {
const nextLine = {
lineIndex: lineno,
lineNumber: lineno + 1,
text: srcLines[lineno],
errorCharStart: -1,
errorLength: -1
};
d.lines.push(nextLine);
}
diagnostics.push(d);
return null;
};
const stylesheet = () => {
const rulesList = rules();
return {
type: 14 /* StyleSheet */,
stylesheet: {
source: filePath,
rules: rulesList
}
};
};
const open = () => match(/^{\s*/);
const close = () => match(/^}/);
const match = (re) => {
const m = re.exec(css);
if (!m) return;
const str = m[0];
updatePosition(str);
css = css.slice(str.length);
return m;
};
const rules = () => {
let node;
const rules2 = [];
whitespace();
comments(rules2);
while (css.length && css.charAt(0) !== "}" && (node = atrule() || rule())) {
rules2.push(node);
comments(rules2);
}
return rules2;
};
const whitespace = () => match(/^\s*/);
const comments = (rules2) => {
let c;
rules2 = rules2 || [];
while (c = comment()) {
rules2.push(c);
}
return rules2;
};
const comment = () => {
const pos = position();
if ("/" !== css.charAt(0) || "*" !== css.charAt(1)) return null;
let i = 2;
while ("" !== css.charAt(i) && ("*" !== css.charAt(i) || "/" !== css.charAt(i + 1))) ++i;
i += 2;
if ("" === css.charAt(i - 1)) {
return error("End of comment missing");
}
const comment2 = css.slice(2, i - 2);
column += 2;
updatePosition(comment2);
css = css.slice(i);
column += 2;
return pos({
type: 1 /* Comment */,
comment: comment2
});
};
const selector = () => {
const m = match(/^([^{]+)/);
if (!m) return null;
return trim(m[0]).replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, "").replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, function(m2) {
return m2.replace(/,/g, "\u200C");
}).split(/\s*(?![^(]*\)),\s*/).map(function(s) {
return s.replace(/\u200C/g, ",");
});
};
const declaration = () => {
const pos = position();
let prop = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
if (!prop) return null;
prop = trim(prop[0]);
if (!match(/^:\s*/)) return error(`property missing ':'`);
const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/);
const ret = pos({
type: 4 /* Declaration */,
property: prop.replace(commentre, ""),
value: val ? trim(val[0]).replace(commentre, "") : ""
});
match(/^[;\s]*/);
return ret;
};
const declarations = () => {
const decls = [];
if (!open()) return error(`missing '{'`);
comments(decls);
let decl;
while (decl = declaration()) {
decls.push(decl);
comments(decls);
}
if (!close()) return error(`missing '}'`);
return decls;
};
const keyframe = () => {
let m;
const values = [];
const pos = position();
while (m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)) {
values.push(m[1]);
match(/^,\s*/);
}
if (!values.length) return null;
return pos({
type: 9 /* KeyFrame */,
values,
declarations: declarations()
});
};
const atkeyframes = () => {
const pos = position();
let m = match(/^@([-\w]+)?keyframes\s*/);
if (!m) return null;
const vendor = m[1];
m = match(/^([-\w]+)\s*/);
if (!m) return error(`@keyframes missing name`);
const name = m[1];
if (!open()) return error(`@keyframes missing '{'`);
let frame;
let frames = comments();
while (frame = keyframe()) {
frames.push(frame);
frames = frames.concat(comments());
}
if (!close()) return error(`@keyframes missing '}'`);
return pos({
type: 8 /* KeyFrames */,
name,
vendor,
keyframes: frames
});
};
const atsupports = () => {
const pos = position();
const m = match(/^@supports *([^{]+)/);
if (!m) return null;
const supports = trim(m[1]);
if (!open()) return error(`@supports missing '{'`);
const style = comments().concat(rules());
if (!close()) return error(`@supports missing '}'`);
return pos({
type: 15 /* Supports */,
supports,
rules: style
});
};
const athost = () => {
const pos = position();
const m = match(/^@host\s*/);
if (!m) return null;
if (!open()) return error(`@host missing '{'`);
const style = comments().concat(rules());
if (!close()) return error(`@host missing '}'`);
return pos({
type: 6 /* Host */,
rules: style
});
};
const atmedia = () => {
const pos = position();
const m = match(/^@media *([^{]+)/);
if (!m) return null;
const media = trim(m[1]);
if (!open()) return error(`@media missing '{'`);
const style = comments().concat(rules());
if (!close()) return error(`@media missing '}'`);
return pos({
type: 10 /* Media */,
media,
rules: style
});
};
const atcustommedia = () => {
const pos = position();
const m = match(/^@custom-media\s+(--[^\s]+)\s*([^{;]+);/);
if (!m) return null;
return pos({
type: 2 /* CustomMedia */,
name: trim(m[1]),
media: trim(m[2])
});
};
const atpage = () => {
const pos = position();
const m = match(/^@page */);
if (!m) return null;
const sel = selector() || [];
if (!open()) return error(`@page missing '{'`);
let decls = comments();
let decl;
while (decl = declaration()) {
decls.push(decl);
decls = decls.concat(comments());
}
if (!close()) return error(`@page missing '}'`);
return pos({
type: 12 /* Page */,
selectors: sel,
declarations: decls
});
};
const atdocument = () => {
const pos = position();
const m = match(/^@([-\w]+)?document *([^{]+)/);
if (!m) return null;
const vendor = trim(m[1]);
const doc = trim(m[2]);
if (!open()) return error(`@document missing '{'`);
const style = comments().concat(rules());
if (!close()) return error(`@document missing '}'`);
return pos({
type: 3 /* Document */,
document: doc,
vendor,
rules: style
});
};
const atfontface = () => {
const pos = position();
const m = match(/^@font-face\s*/);
if (!m) return null;
if (!open()) return error(`@font-face missing '{'`);
let decls = comments();
let decl;
while (decl = declaration()) {
decls.push(decl);
decls = decls.concat(comments());
}
if (!close()) return error(`@font-face missing '}'`);
return pos({
type: 5 /* FontFace */,
declarations: decls
});
};
const compileAtrule = (nodeName, nodeType) => {
const re = new RegExp("^@" + nodeName + "\\s*([^;]+);");
return () => {
const pos = position();
const m = match(re);
if (!m) return null;
const node = {
type: nodeType
};
node[nodeName] = m[1].trim();
return pos(node);
};
};
const atimport = compileAtrule("import", 7 /* Import */);
const atcharset = compileAtrule("charset", 0 /* Charset */);
const atnamespace = compileAtrule("namespace", 11 /* Namespace */);
const atrule = () => {
if (css[0] !== "@") return null;
return atkeyframes() || atmedia() || atcustommedia() || atsupports() || atimport() || atcharset() || atnamespace() || atdocument() || atpage() || athost() || atfontface();
};
const rule = () => {
const pos = position();
const sel = selector();
if (!sel) return error("selector missing");
comments();
return pos({
type: 13 /* Rule */,
selectors: sel,
declarations: declarations()
});
};
class ParsePosition {
constructor(start) {
this.start = start;
this.end = { line: lineno, column };
this.source = filePath;
}
}
ParsePosition.prototype.content = css;
return {
diagnostics,
...addParent(stylesheet())
};
};
var trim = (str) => str ? str.trim() : "";
var addParent = (obj, parent) => {
const isNode = obj && typeof obj.type === "string";
const childParent = isNode ? obj : parent;
for (const k in obj) {
const value = obj[k];
if (Array.isArray(value)) {
value.forEach(function(v) {
addParent(v, childParent);
});
} else if (value && typeof value === "object") {
addParent(value, childParent);
}
}
if (isNode) {
Object.defineProperty(obj, "parent", {
configurable: true,
writable: true,
enumerable: false,
value: parent || null
});
}
return obj;
};
var commentre = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g;
// src/compiler/style/css-parser/get-css-selectors.ts
var getCssSelectors = (sel) => {
SELECTORS.all.length = SELECTORS.tags.length = SELECTORS.classNames.length = SELECTORS.ids.length = SELECTORS.attrs.length = 0;
sel = sel.replace(/\./g, " .").replace(/\#/g, " #").replace(/\[/g, " [").replace(/\>/g, " > ").replace(/\+/g, " + ").replace(/\~/g, " ~ ").replace(/\*/g, " * ").replace(/\:not\((.*?)\)/g, " ");
const items = sel.split(" ");
for (let i = 0, l = items.length; i < l; i++) {
items[i] = items[i].split(":")[0];
if (items[i].length === 0) continue;
if (items[i].charAt(0) === ".") {
SELECTORS.classNames.push(items[i].slice(1));
} else if (items[i].charAt(0) === "#") {
SELECTORS.ids.push(items[i].slice(1));
} else if (items[i].charAt(0) === "[") {
items[i] = items[i].slice(1).split("=")[0].split("]")[0].trim();
SELECTORS.attrs.push(items[i].toLowerCase());
} else if (/[a-z]/g.test(items[i].charAt(0))) {
SELECTORS.tags.push(items[i].toLowerCase());
}
}
SELECTORS.classNames = SELECTORS.classNames.sort((a, b) => {
if (a.length < b.length) return -1;
if (a.length > b.length) return 1;
return 0;
});
return SELECTORS;
};
var SELECTORS = {
all: [],
tags: [],
classNames: [],
ids: [],
attrs: []
};
// src/compiler/style/css-parser/serialize-css.ts
var serializeCss = (stylesheet, serializeOpts) => {
const usedSelectors = serializeOpts.usedSelectors || null;
const opts = {
usedSelectors: usedSelectors || null,
hasUsedAttrs: !!usedSelectors && usedSelectors.attrs.size > 0,
hasUsedClassNames: !!usedSelectors && usedSelectors.classNames.size > 0,
hasUsedIds: !!usedSelectors && usedSelectors.ids.size > 0,
hasUsedTags: !!usedSelectors && usedSelectors.tags.size > 0
};
const rules = stylesheet.rules;
if (!rules) {
return "";
}
const rulesLen = rules.length;
const out = [];
for (let i = 0; i < rulesLen; i++) {
out.push(serializeCssVisitNode(opts, rules[i], i, rulesLen));
}
return out.join("");
};
var serializeCssVisitNode = (opts, node, index, len) => {
var _a2;
const nodeType = node.type;
if (nodeType === 4 /* Declaration */) {
return serializeCssDeclaration(node, index, len);
}
if (nodeType === 13 /* Rule */) {
return serializeCssRule(opts, node);
}
if (nodeType === 1 /* Comment */) {
if (((_a2 = node.comment) == null ? void 0 : _a2[0]) === "!") {
return `/*${node.comment}*/`;
} else {
return "";
}
}
if (nodeType === 10 /* Media */) {
return serializeCssMedia(opts, node);
}
if (nodeType === 8 /* KeyFrames */) {
return serializeCssKeyframes(opts, node);
}
if (nodeType === 9 /* KeyFrame */) {
return serializeCssKeyframe(opts, node);
}
if (nodeType === 5 /* FontFace */) {
return serializeCssFontFace(opts, node);
}
if (nodeType === 15 /* Supports */) {
return serializeCssSupports(opts, node);
}
if (nodeType === 7 /* Import */) {
return "@import " + node.import + ";";
}
if (nodeType === 0 /* Charset */) {
return "@charset " + node.charset + ";";
}
if (nodeType === 12 /* Page */) {
return serializeCssPage(opts, node);
}
if (nodeType === 6 /* Host */) {
return "@host{" + serializeCssMapVisit(opts, node.rules) + "}";
}
if (nodeType === 2 /* CustomMedia */) {
return "@custom-media " + node.name + " " + node.media + ";";
}
if (nodeType === 3 /* Document */) {
return serializeCssDocument(opts, node);
}
if (nodeType === 11 /* Namespace */) {
return "@namespace " + node.namespace + ";";
}
return "";
};
var serializeCssRule = (opts, node) => {
var _a2, _b;
const decls = node.declarations;
const usedSelectors = opts.usedSelectors;
const selectors = (_b = (_a2 = node.selectors) == null ? void 0 : _a2.slice()) != null ? _b : [];
if (decls == null || decls.length === 0) {
return "";
}
if (usedSelectors) {
let i;
let j;
let include = true;
for (i = selectors.length - 1; i >= 0; i--) {
const sel = getCssSelectors(selectors[i]);
include = true;
let jlen = sel.classNames.length;
if (jlen > 0 && opts.hasUsedClassNames) {
for (j = 0; j < jlen; j++) {
if (!usedSelectors.classNames.has(sel.classNames[j])) {
include = false;
break;
}
}
}
if (include && opts.hasUsedTags) {
jlen = sel.tags.length;
if (jlen > 0) {
for (j = 0; j < jlen; j++) {
if (!usedSelectors.tags.has(sel.tags[j])) {
include = false;
break;
}
}
}
}
if (include && opts.hasUsedAttrs) {
jlen = sel.attrs.length;
if (jlen > 0) {
for (j = 0; j < jlen; j++) {
if (!usedSelectors.attrs.has(sel.attrs[j])) {
include = false;
break;
}
}
}
}
if (include && opts.hasUsedIds) {
jlen = sel.ids.length;
if (jlen > 0) {
for (j = 0; j < jlen; j++) {
if (!usedSelectors.ids.has(sel.ids[j])) {
include = false;
break;
}
}
}
}
if (!include) {
selectors.splice(i, 1);
}
}
}
if (selectors.length === 0) {
return "";
}
const cleanedSelectors = [];
let cleanedSelector = "";
if (node.selectors) {
for (const selector of node.selectors) {
cleanedSelector = removeSelectorWhitespace(selector);
if (!cleanedSelectors.includes(cleanedSelector)) {
cleanedSelectors.push(cleanedSelector);
}
}
}
return `${cleanedSelectors}{${serializeCssMapVisit(opts, decls)}}`;
};
var serializeCssDeclaration = (node, index, len) => {
if (node.value === "") {
return "";
}
if (len - 1 === index) {
return node.property + ":" + node.value;
}
return node.property + ":" + node.value + ";";
};
var serializeCssMedia = (opts, node) => {
const mediaCss = serializeCssMapVisit(opts, node.rules);
if (mediaCss === "") {
return "";
}
return "@media " + removeMediaWhitespace(node.media) + "{" + mediaCss + "}";
};
var serializeCssKeyframes = (opts, node) => {
const keyframesCss = serializeCssMapVisit(opts, node.keyframes);
if (keyframesCss === "") {
return "";
}
return "@" + (node.vendor || "") + "keyframes " + node.name + "{" + keyframesCss + "}";
};
var serializeCssKeyframe = (opts, node) => {
var _a2, _b;
return ((_b = (_a2 = node.values) == null ? void 0 : _a2.join(",")) != null ? _b : "") + "{" + serializeCssMapVisit(opts, node.declarations) + "}";
};
var serializeCssFontFace = (opts, node) => {
const fontCss = serializeCssMapVisit(opts, node.declarations);
if (fontCss === "") {
return "";
}
return "@font-face{" + fontCss + "}";
};
var serializeCssSupports = (opts, node) => {
const supportsCss = serializeCssMapVisit(opts, node.rules);
if (supportsCss === "") {
return "";
}
return "@supports " + node.supports + "{" + supportsCss + "}";
};
var serializeCssPage = (opts, node) => {
var _a2, _b;
const sel = (_b = (_a2 = node.selectors) == null ? void 0 : _a2.join(", ")) != null ? _b : "";
return "@page " + sel + "{" + serializeCssMapVisit(opts, node.declarations) + "}";
};
var serializeCssDocument = (opts, node) => {
const documentCss = serializeCssMapVisit(opts, node.rules);
const doc = "@" + (node.vendor || "") + "document " + node.document;
if (documentCss === "") {
return "";
}
return doc + "{" + documentCss + "}";
};
var serializeCssMapVisit = (opts, nodes) => {
let rtn = "";
if (nodes) {
for (let i = 0, len = nodes.length; i < len; i++) {
rtn += serializeCssVisitNode(opts, nodes[i], i, len);
}
}
return rtn;
};
var removeSelectorWhitespace = (selector) => {
let rtn = "";
let char = "";
let inAttr = false;
selector = selector.trim();
for (let i = 0, l = selector.length; i < l; i++) {
char = selector[i];
if (char === "[" && rtn[rtn.length - 1] !== "\\") {
inAttr = true;
} else if (char === "]" && rtn[rtn.length - 1] !== "\\") {
inAttr = false;
}
if (!inAttr && CSS_WS_REG.test(char)) {
if (CSS_NEXT_CHAR_REG.test(selector[i + 1])) {
continue;
}
if (CSS_PREV_CHAR_REG.test(rtn[rtn.length - 1])) {
continue;
}
rtn += " ";
} else {
rtn += char;
}
}
return rtn;
};
var removeMediaWhitespace = (media) => {
var _a2;
let rtn = "";
let char = "";
media = (_a2 = media == null ? void 0 : media.trim()) != null ? _a2 : "";
for (let i = 0, l = media.length; i < l; i++) {
char = media[i];
if (CSS_WS_REG.test(char)) {
if (CSS_WS_REG.test(rtn[rtn.length - 1])) {
continue;
}
rtn += " ";
} else {
rtn += char;
}
}
return rtn;
};
var CSS_WS_REG = /\s/;
var CSS_NEXT_CHAR_REG = /[>\(\)\~\,\+\s]/;
var CSS_PREV_CHAR_REG = /[>\(\~\,\+]/;
// src/compiler/style/css-parser/used-selectors.ts
var getUsedSelectors = (elm) => {
const usedSelectors = {
attrs: /* @__PURE__ */ new Set(),
classNames: /* @__PURE__ */ new Set(),
ids: /* @__PURE__ */ new Set(),
tags: /* @__PURE__ */ new Set()
};
collectUsedSelectors(usedSelectors, elm);
return usedSelectors;
};
var collectUsedSelectors = (usedSelectors, elm) => {
if (elm != null && elm.nodeType === 1) {
const children = elm.children;
const tagName = elm.nodeName.toLowerCase();
usedSelectors.tags.add(tagName);
const attributes = elm.attributes;
for (let i = 0, l = attributes.length; i < l; i++) {
const attr = attributes.item(i);
const attrName = attr.name.toLowerCase();
usedSelectors.attrs.add(attrName);
if (attrName === "class") {
const classList = elm.classList;
for (let i2 = 0, l2 = classList.length; i2 < l2; i2++) {
usedSelectors.classNames.add(classList.item(i2));
}
} else if (attrName === "id") {
usedSelectors.ids.add(attr.value);
}
}
if (children) {
for (let i = 0, l = children.length; i < l; i++) {
collectUsedSelectors(usedSelectors, children[i]);
}
}
}
};
// src/compiler/html/remove-unused-styles.ts
var removeUnusedStyles = (doc, diagnostics) => {
try {
const styleElms = doc.head.querySelectorAll(`style[data-styles]`);
const styleLen = styleElms.length;
if (styleLen > 0) {
const usedSelectors = getUsedSelectors(doc.documentElement);
for (let i = 0; i < styleLen; i++) {
removeUnusedStyleText(usedSelectors, diagnostics, styleElms[i]);
}
}
} catch (e) {
catchError(diagnostics, e);
}
};
var removeUnusedStyleText = (usedSelectors, diagnostics, styleElm) => {
try {
const parseResults = parseCss(styleElm.innerHTML);
diagnostics.push(...parseResults.diagnostics);
if (hasError(diagnostics)) {
return;
}
try {
styleElm.innerHTML = serializeCss(parseResults.stylesheet, {
usedSelectors
});
} catch (e) {
diagnostics.push({
level: "warn",
type: "css",
header: "CSS Stringify",
messageText: e,
lines: []
});
}
} catch (e) {
diagnostics.push({
level: "warn",
type: "css",
header: "CSS Parse",
messageText: e,
lines: []
});
}
};
// src/hydrate/runner/inspect-element.ts
function inspectElement(results, elm, depth) {
const children = [...Array.from(elm.children), ...Array.from(elm.shadowRoot ? elm.shadowRoot.children : [])];
for (let i = 0, ii = children.length; i < ii; i++) {
const childElm = children[i];
const tagName = childElm.nodeName.toLowerCase();
if (tagName.includes("-")) {
const cmp = results.components.find((c) => c.tag === tagName);
if (cmp != null) {
cmp.count++;
if (depth > cmp.depth) {
cmp.depth = depth;
}
}
} else {
switch (tagName) {
case "a":
const anchor = collectAttributes(childElm);
anchor.href = childElm.href;
if (typeof anchor.href === "string") {
if (!results.anchors.some((a) => a.href === anchor.href)) {
results.anchors.push(anchor);
}
}
break;
case "img":
const img = collectAttributes(childElm);
img.src = childElm.src;
if (typeof img.src === "string") {
if (!results.imgs.some((a) => a.src === img.src)) {
results.imgs.push(img);
}
}
break;
case "link":
const link = collectAttributes(childElm);
link.href = childElm.href;
if (typeof link.rel === "string" && link.rel.toLowerCase() === "stylesheet") {
if (typeof link.href === "string") {
if (!results.styles.some((s) => s.link === link.href)) {
delete link.rel;
delete link.type;
results.styles.push(link);
}
}
}
break;
case "script":
const script = collectAttributes(childElm);
if (childElm.hasAttribute("src")) {
script.src = childElm.src;
if (typeof script.src === "string") {
if (!results.scripts.some((s) => s.src === script.src)) {
results.scripts.push(script);
}
}
} else {
const staticDataKey = childElm.getAttribute("data-stencil-static");
if (staticDataKey) {
results.staticData.push({
id: staticDataKey,
type: childElm.getAttribute("type"),
content: childElm.textContent
});
}
}
break;
}
}
depth++;
inspectElement(results, childElm, depth);
}
}
function collectAttributes(node) {
const parsedElm = {};
const attrs = node.attributes;
for (let i = 0, ii = attrs.length; i < ii; i++) {
const attr = attrs.item(i);
const attrName = attr.nodeName.toLowerCase();
if (SKIP_ATTRS.has(attrName)) {
continue;
}
const attrValue = attr.nodeValue;
if (attrName === "class" && attrValue === "") {
continue;
}
parsedElm[attrName] = attrValue;
}
return parsedElm;
}
var SKIP_ATTRS = /* @__PURE__ */ new Set(["s-id", "c-id"]);
// src/hydrate/runner/patch-dom-implementation.ts
function patchDomImplementation(doc, opts) {
let win2;
if (doc.defaultView != null) {
opts.destroyWindow = true;
patchWindow(doc.defaultView);
win2 = doc.defaultView;
} else {
opts.destroyWindow = true;
opts.destroyDocument = false;
win2 = new MockWindow(false);
}
if (win2.document !== doc) {
win2.document = doc;
}
if (doc.defaultView !== win2) {
doc.defaultView = win2;
}
const HTMLElement2 = doc.documentElement.constructor.prototype;
if (typeof HTMLElement2.getRootNode !== "function") {
const elm = doc.createElement("unknown-element");
const HTMLUnknownElement = elm.constructor.prototype;
HTMLUnknownElement.getRootNode = getRootNode;
}
if (typeof doc.createEvent === "function") {
const CustomEvent2 = doc.createEvent("CustomEvent").constructor;
if (win2.CustomEvent !== CustomEvent2) {
win2.CustomEvent = CustomEvent2;
}
}
try {
win2.__stencil_baseURI = doc.baseURI;
} catch (e) {
Object.defineProperty(doc, "baseURI", {
get() {
const baseElm = doc.querySelector("base[href]");
if (baseElm) {
return new URL(baseElm.getAttribute("href"), win2.location.href).href;
}
return win2.location.href;
}
});
}
return win2;
}
function getRootNode(opts) {
const isComposed = opts != null && opts.composed === true;
let node = this;
while (node.parentNode != null) {
node = node.parentNode;
if (isComposed === true && node.parentNode == null && node.host != null) {
node = node.host;
}
}
return node;
}
// src/hydrate/runner/render-utils.ts
function normalizeHydrateOptions(inputOpts) {
const outputOpts = Object.assign(
{
serializeToHtml: false,
destroyWindow: false,
destroyDocument: false
},
inputOpts || {}
);
if (typeof outputOpts.clientHydrateAnnotations !== "boolean") {
outputOpts.clientHydrateAnnotations = true;
}
if (typeof outputOpts.constrainTimeouts !== "boolean") {
outputOpts.constrainTimeouts = true;
}
if (typeof outputOpts.maxHydrateCount !== "number") {
outputOpts.maxHydrateCount = 300;
}
if (typeof outputOpts.runtimeLogging !== "boolean") {
outputOpts.runtimeLogging = false;
}
if (typeof outputOpts.timeout !== "number") {
outputOpts.timeout = 15e3;
}
if (Array.isArray(outputOpts.excludeComponents)) {
outputOpts.excludeComponents = outputOpts.excludeComponents.filter(filterValidTags).map(mapValidTags);
} else {
outputOpts.excludeComponents = [];
}
if (Array.isArray(outputOpts.staticComponents)) {
outputOpts.staticComponents = outputOpts.staticComponents.filter(filterValidTags).map(mapValidTags);
} else {
outputOpts.staticComponents = [];
}
return outputOpts;
}
function filterValidTags(tag) {
return typeof tag === "string" && tag.includes("-");
}
function mapValidTags(tag) {
return tag.trim().toLowerCase();
}
function generateHydrateResults(opts) {
if (typeof opts.url !== "string") {
opts.url = `https://hydrate.stenciljs.com/`;
}
if (typeof opts.buildId !== "string") {
opts.buildId = createHydrateBuildId();
}
const results = {
buildId: opts.buildId,
diagnostics: [],
url: opts.url,
host: null,
hostname: null,
href: null,
pathname: null,
port: null,
search: null,
hash: null,
html: null,
httpStatus: null,
hydratedCount: 0,
anchors: [],
components: [],
imgs: [],
scripts: [],
staticData: [],
styles: [],
title: null
};
try {
const url = new URL(opts.url, `https://hydrate.stenciljs.com/`);
results.url = url.href;
results.host = url.host;
results.hostname = url.hostname;
results.href = url.href;
results.port = url.port;
results.pathname = url.pathname;
results.search = url.search;
results.hash = url.hash;
} catch (e) {
renderCatchError(results, e);
}
return results;
}
var createHydrateBuildId = () => {
let chars = "abcdefghijklmnopqrstuvwxyz";
let buildId = "";
while (buildId.length < 8) {
const char = chars[Math.floor(Math.random() * chars.length)];
buildId += char;
if (buildId.length === 1) {
chars += "0123456789";
}
}
return buildId;
};
function renderBuildDiagnostic(results, level, header, msg) {
const diagnostic = {
level,
type: "build",
header,
messageText: msg,
relFilePath: void 0,
absFilePath: void 0,
lines: []
};
if (results.pathname) {
if (results.pathname !== "/") {
diagnostic.header += ": " + results.pathname;
}
} else if (results.url) {
diagnostic.header += ": " + results.url;
}
results.diagnostics.push(diagnostic);
return diagnostic;
}
function renderBuildError(results, msg) {
return renderBuildDiagnostic(results, "error", "Hydrate Error", msg || "");
}
function renderCatchError(results, err2) {
const diagnostic = renderBuildError(results);
if (err2 != null) {
if (err2.stack != null) {
diagnostic.messageText = err2.stack.toString();
} else {
if (err2.message != null) {
diagnostic.messageText = err2.message.toString();
} else {
diagnostic.messageText = err2.toString();
}
}
}
return diagnostic;
}
// src/hydrate/runner/runtime-log.ts
function runtimeLogging(win2, opts, results) {
try {
const pathname = win2.location.pathname;
win2.console.error = (...msgs) => {
const errMsg = msgs.reduce((errMsg2, m) => {
if (m) {
if (m.stack != null) {
return errMsg2 + " " + String(m.stack);
} else {
if (m.message != null) {
return errMsg2 + " " + String(m.message);
}
}
}
return String(m);
}, "").trim();
if (errMsg !== "") {
renderCatchError(results, errMsg);
if (opts.runtimeLogging) {
runtimeLog(pathname, "error", [errMsg]);
}
}
};
win2.console.debug = (...msgs) => {
renderBuildDiagnostic(results, "debug", "Hydrate Debug", [...msgs].join(", "));
if (opts.runtimeLogging) {
runtimeLog(pathname, "debug", msgs);
}
};
if (opts.runtimeLogging) {
["log", "warn", "assert", "info", "trace"].forEach((type) => {
win2.console[type] = (...msgs) => {
runtimeLog(pathname, type, msgs);
};
});
}
} catch (e) {
renderCatchError(results, e);
}
}
function runtimeLog(pathname, type, msgs) {
global.console[type].apply(global.console, [`[ ${pathname} ${type} ] `, ...msgs]);
}
// src/hydrate/runner/window-initialize.ts
var docData = {
hostIds: 0,
rootLevelIds: 0,
staticComponents: /* @__PURE__ */ new Set()
};
function initializeWindow(win2, doc, opts, results) {
if (typeof opts.url === "string") {
try {
win2.location.href = opts.url;
} catch (e) {
}
}
if (typeof opts.userAgent === "string") {
try {
win2.navigator.userAgent = opts.userAgent;
} catch (e) {
}
}
if (typeof opts.cookie === "string") {
try {
doc.cookie = opts.cookie;
} catch (e) {
}
}
if (typeof opts.referrer === "string") {
try {
doc.referrer = opts.referrer;
} catch (e) {
}
}
if (typeof opts.direction === "string") {
try {
doc.documentElement.setAttribute("dir", opts.direction);
} catch (e) {
}
}
if (typeof opts.language === "string") {
try {
doc.documentElement.setAttribute("lang", opts.language);
} catch (e) {
}
}
if (typeof opts.buildId === "string") {
try {
doc.documentElement.setAttribute("data-stencil-build", opts.buildId);
} catch (e) {
}
}
try {
win2.customElements = null;
} catch (e) {
}
if (opts.constrainTimeouts) {
constrainTimeouts(win2);
}
runtimeLogging(win2, opts, results);
doc[STENCIL_DOC_DATA] = docData;
return win2;
}
// src/hydrate/runner/render.ts
var NOOP = () => {
};
function streamToString(html, option) {
return renderToString(html, option, true);
}
function renderToString(html, options, asStream) {
const opts = normalizeHydrateOptions(options);
opts.serializeToHtml = true;
opts.fullDocument = typeof opts.fullDocument === "boolean" ? opts.fullDocument : true;
opts.serializeShadowRoot = typeof opts.serializeShadowRoot === "undefined" ? "declarative-shadow-dom" : opts.serializeShadowRoot;
opts.constrainTimeouts = false;
return hydrateDocument(html, opts, asStream);
}
function hydrateDocument(doc, options, asStream) {
const opts = normalizeHydrateOptions(options);
opts.serializeShadowRoot = typeof opts.serializeShadowRoot === "undefined" ? "declarative-shadow-dom" : opts.serializeShadowRoot;
let win2 = null;
const results = generateHydrateResults(opts);
if (hasError(results.diagnostics)) {
return Promise.resolve(results);
}
if (typeof doc === "string") {
try {
opts.destroyWindow = true;
opts.destroyDocument = true;
win2 = new MockWindow(doc);
if (!asStream) {
return render2(win2, opts, results).then(() => results);
}
return renderStream(win2, opts, results);
} catch (e) {
if (win2 && win2.close) {
win2.close();
}
win2 = null;
renderCatchError(results, e);
return Promise.resolve(results);
}
}
if (isValidDocument(doc)) {
try {
opts.destroyDocument = false;
win2 = patchDomImplementation(doc, opts);
if (!asStream) {
return render2(win2, opts, results).then(() => results);
}
return renderStream(win2, opts, results);
} catch (e) {
if (win2 && win2.close) {
win2.close();
}
win2 = null;
renderCatchError(results, e);
return Promise.resolve(results);
}
}
renderBuildError(results, `Invalid html or document. Must be either a valid "html" string, or DOM "document".`);
return Promise.resolve(results);
}
async function render2(win2, opts, results) {
if ("process" in globalThis && typeof process.on === "function" && !process.__stencilErrors) {
process.__stencilErrors = true;
process.on("unhandledRejection", (e) => {
console.log("unhandledRejection", e);
});
}
initializeWindow(win2, win2.document, opts, results);
const beforeHydrateFn = typeof opts.beforeHydrate === "function" ? opts.beforeHydrate : NOOP;
try {
await Promise.resolve(beforeHydrateFn(win2.document));
return new Promise((resolve) => {
if (Array.isArray(opts.modes)) {
modeResolutionChain.length = 0;
opts.modes.forEach((mode) => setMode(mode));
}
return hydrateFactory(win2, opts, results, afterHydrate, resolve);
});
} catch (e) {
renderCatchError(results, e);
return finalizeHydrate(win2, win2.document, opts, results);
}
}
function renderStream(win2, opts, results) {
async function* processRender() {
const renderResult = await render2(win2, opts, results);
yield renderResult.html;
}
return stream.Readable.from(processRender());
}
async function afterHydrate(win2, opts, results, resolve) {
const afterHydrateFn = typeof opts.afterHydrate === "function" ? opts.afterHydrate : NOOP;
try {
await Promise.resolve(afterHydrateFn(win2.document));
return resolve(finalizeHydrate(win2, win2.document, opts, results));
} catch (e) {
renderCatchError(results, e);
return resolve(finalizeHydrate(win2, win2.document, opts, results));
}
}
function finalizeHydrate(win2, doc, opts, results) {
try {
inspectElement(results, doc.documentElement, 0);
if (opts.removeUnusedStyles !== false) {
try {
removeUnusedStyles(doc, results.diagnostics);
} catch (e) {
renderCatchError(results, e);
}
}
if (typeof opts.title === "string") {
try {
doc.title = opts.title;
} catch (e) {
renderCatchError(results, e);
}
}
results.title = doc.title;
if (opts.removeScripts) {
removeScripts(doc.documentElement);
}
const styles2 = doc.querySelectorAll("head style");
if (styles2.length > 0) {
results.styles.push(
...Array.from(styles2).map((style) => ({
href: style.getAttribute("href"),
id: style.getAttribute(HYDRATED_STYLE_ID),
content: style.textContent
}))
);
}
try {
updateCanonicalLink(doc, opts.canonicalUrl);
} catch (e) {
renderCatchError(results, e);
}
try {
relocateMetaCharset(doc);
} catch (e) {
}
if (!hasError(results.diagnostics)) {
results.httpStatus = 200;
}
try {
const metaStatus = doc.head.querySelector('meta[http-equiv="status"]');
if (metaStatus != null) {
const metaStatusContent = metaStatus.getAttribute("content");
if (metaStatusContent && metaStatusContent.length > 0) {
results.httpStatus = parseInt(metaStatusContent, 10);
}
}
} catch (e) {
}
if (opts.clientHydrateAnnotations) {
doc.documentElement.classList.add("hydrated");
}
if (opts.serializeToHtml) {
results.html = serializeDocumentToString(doc, opts);
}
} catch (e) {
renderCatchError(results, e);
}
destroyWindow(win2, doc, opts, results);
return results;
}
function destroyWindow(win2, doc, opts, results) {
if (!opts.destroyWindow) {
return;
}
try {
if (!opts.destroyDocument) {
win2.document = null;
doc.defaultView = null;
}
if (win2.close) {
win2.close();
}
} catch (e) {
renderCatchError(results, e);
}
}
function serializeDocumentToString(doc, opts) {
return serializeNodeToHtml(doc, {
approximateLineWidth: opts.approximateLineWidth,
outerHtml: false,
prettyHtml: opts.prettyHtml,
removeAttributeQuotes: opts.removeAttributeQuotes,
removeBooleanAttributeQuotes: opts.removeBooleanAttributeQuotes,
removeEmptyAttributes: opts.removeEmptyAttributes,
removeHtmlComments: opts.removeHtmlComments,
serializeShadowRoot: opts.serializeShadowRoot,
fullDocument: opts.fullDocument
});
}
function isValidDocument(doc) {
return doc != null && doc.nodeType === 9 && doc.documentElement != null && doc.documentElement.nodeType === 1 && doc.body != null && doc.body.nodeType === 1;
}
function removeScripts(elm) {
const children = elm.children;
for (let i = children.length - 1; i >= 0; i--) {
const child = children[i];
removeScripts(child);
if (child.nodeName === "SCRIPT" || child.nodeName === "LINK" && child.getAttribute("rel") === "modulepreload") {
child.remove();
}
}
}
exports.createWindowFromHtml = createWindowFromHtml;
exports.deserializeProperty = deserializeProperty;
exports.hydrateDocument = hydrateDocument;
exports.renderToString = renderToString;
exports.serializeDocumentToString = serializeDocumentToString;
exports.serializeProperty = serializeProperty;
exports.streamToString = streamToString;