const _emptyNodeList = [];
function isTouchable() {
  return window.matchMedia("(pointer: coarse)").matches;
}
function isDark() {
  return window.matchMedia("(prefers-color-scheme: dark)").matches;
}
async function wait(milliseconds) {
  await new Promise((resolve) => setTimeout(resolve, milliseconds));
}
function guid() {
  return "fxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
    const r = Math.random() * 16 | 0;
    const v = c === "x" ? r : r & 3 | 8;
    return v.toString(16);
  });
}
function query(selector, element) {
  try {
    return typeof selector === "string" ? (element ?? document).querySelector(selector) : selector;
  } catch {
    return null;
  }
}
function queryAll(selector, element) {
  try {
    return typeof selector === "string" ? (element ?? document).querySelectorAll(selector) : selector ?? _emptyNodeList;
  } catch {
    return _emptyNodeList;
  }
}
function hasClass(element, name) {
  return (element == null ? void 0 : element.classList.contains(name)) ?? false;
}
function hasTag(element, name) {
  var _a;
  return ((_a = element == null ? void 0 : element.tagName) == null ? void 0 : _a.toLowerCase()) === name;
}
function hasType(element, name) {
  var _a;
  return ((_a = element == null ? void 0 : element.type) == null ? void 0 : _a.toLowerCase()) === name;
}
function addClass(element, name) {
  if (element instanceof NodeList)
    for (let i = 0; i < element.length; i++)
      element[i].classList.add(name);
  else
    element == null ? void 0 : element.classList.add(name);
}
function removeClass(element, name) {
  if (element instanceof NodeList)
    for (let i = 0; i < element.length; i++)
      element[i].classList.remove(name);
  else
    element == null ? void 0 : element.classList.remove(name);
}
function on(element, name, callback, useCapture = true) {
  if (element == null ? void 0 : element.addEventListener)
    element.addEventListener(name, callback, useCapture);
}
function off(element, name, callback, useCapture = true) {
  if (element == null ? void 0 : element.removeEventListener)
    element.removeEventListener(name, callback, useCapture);
}
function insertBefore(newElement, element) {
  var _a;
  (_a = element == null ? void 0 : element.parentNode) == null ? void 0 : _a.insertBefore(newElement, element);
}
function prev(element) {
  return element == null ? void 0 : element.previousElementSibling;
}
function next(element) {
  return element == null ? void 0 : element.nextElementSibling;
}
function parent(element) {
  return element == null ? void 0 : element.parentElement;
}
function create(htmlAttributesAsJson) {
  const element = document.createElement("div");
  for (let i = 0, keys = Object.keys(htmlAttributesAsJson), n = keys.length; i < n; i++) {
    const key = keys[i];
    const value = htmlAttributesAsJson[key];
    element.setAttribute(key, value);
  }
  return element;
}
function blurActiveElement() {
  var _a;
  (_a = document.activeElement) == null ? void 0 : _a.blur();
}
function queryAllDataUi(id) {
  return queryAll('[data-ui="#' + id + '"]');
}
function queryDataUi(id) {
  return query('[data-ui="#' + id + '"]');
}
function updateAllClickable(element) {
  if (element.id && hasClass(element, "page"))
    element = queryDataUi(element.id) ?? element;
  const container = parent(element);
  if (!hasClass(container, "tabs") && !hasClass(container, "tabbed") && !hasTag(container, "nav"))
    return;
  const as = queryAll("a", container);
  for (let i = 0; i < as.length; i++)
    removeClass(as[i], "active");
  addClass(element, "active");
}
function updatePlaceholder(element) {
  if (!element.placeholder)
    element.placeholder = " ";
}
function onClickLabel(e) {
  const label = e.currentTarget;
  const field = parent(label);
  const input = query("input:not([type=file], [type=checkbox], [type=radio]), select, textarea", field);
  if (input)
    input.focus();
}
function onFocusInput(e) {
  const input = e.currentTarget;
  updateInput(input);
}
function onBlurInput(e) {
  const input = e.currentTarget;
  updateInput(input);
}
function onChangeFile(e) {
  const input = e.currentTarget;
  updateFile(input);
}
function onChangeColor(e) {
  const input = e.currentTarget;
  updateColor(input);
}
function onKeydownFile(e) {
  const input = e.currentTarget;
  updateFile(input, e);
}
function onKeydownColor(e) {
  const input = e.currentTarget;
  updateColor(input, e);
}
function onInputTextarea(e) {
  const textarea = e.currentTarget;
  updateTextarea(textarea);
}
function onPasswordIconClick(e) {
  var _a;
  const icon = e.currentTarget;
  const input = query("input", parent(icon));
  if (input && ((_a = icon.textContent) == null ? void 0 : _a.includes("visibility")))
    input.type = input.type === "password" ? "text" : "password";
}
function updateAllLabels() {
  const labels = queryAll(".field > label");
  for (let i = 0; i < labels.length; i++)
    on(labels[i], "click", onClickLabel);
}
function updateAllInputs() {
  const inputs = queryAll(".field > input:not([type=file], [type=color], [type=range])");
  for (let i = 0; i < inputs.length; i++) {
    on(inputs[i], "focus", onFocusInput);
    on(inputs[i], "blur", onBlurInput);
    updateInput(inputs[i]);
  }
}
function updateAllSelects() {
  const selects = queryAll(".field > select");
  for (let i = 0; i < selects.length; i++) {
    on(selects[i], "focus", onFocusInput);
    on(selects[i], "blur", onBlurInput);
  }
}
function updateAllFiles() {
  const files = queryAll(".field > input[type=file]");
  for (let i = 0; i < files.length; i++) {
    on(files[i], "change", onChangeFile);
    updateFile(files[i]);
  }
}
function updateAllColors() {
  const colors = queryAll(".field > input[type=color]");
  for (let i = 0; i < colors.length; i++) {
    on(colors[i], "change", onChangeColor);
    updateColor(colors[i]);
  }
}
function updateAllTextareas() {
  const textareas = queryAll(".field.textarea > textarea");
  for (let i = 0; i < textareas.length; i++) {
    on(textareas[i], "focus", onFocusInput);
    on(textareas[i], "blur", onBlurInput);
    on(textareas[i], "input", onInputTextarea);
    updateTextarea(textareas[i]);
  }
}
function updateAllPasswordIcons() {
  const icons = queryAll("input[type=password] ~ :is(i, a)");
  for (let i = 0; i < icons.length; i++)
    on(icons[i], "click", onPasswordIconClick);
}
function updateInput(input) {
  if (hasType(input, "number") && !input.value)
    input.value = "";
  updatePlaceholder(input);
}
function updateFile(input, e) {
  if ((e == null ? void 0 : e.key) === "Enter") {
    const previousInput = prev(input);
    if (!hasType(previousInput, "file"))
      return;
    previousInput.click();
    return;
  }
  const nextInput = next(input);
  if (!hasType(nextInput, "text"))
    return;
  nextInput.value = input.files ? Array.from(input.files).map((x) => x.name).join(", ") : "";
  nextInput.readOnly = true;
  on(nextInput, "keydown", onKeydownFile, false);
  updateInput(nextInput);
}
function updateColor(input, e) {
  if ((e == null ? void 0 : e.key) === "Enter") {
    const previousInput = prev(input);
    if (!hasType(previousInput, "color"))
      return;
    previousInput.click();
    return;
  }
  const nextInput = next(input);
  if (!hasType(nextInput, "text"))
    return;
  nextInput.readOnly = true;
  nextInput.value = input.value;
  on(nextInput, "keydown", onKeydownColor, false);
  updateInput(nextInput);
}
function updateTextarea(textarea) {
  updatePlaceholder(textarea);
  const field = parent(textarea);
  field.removeAttribute("style");
  if (hasClass(field, "min"))
    field.style.setProperty("---size", `${Math.max(textarea.scrollHeight, field.offsetHeight)}px`);
}
function updateAllFields() {
  updateAllLabels();
  updateAllInputs();
  updateAllSelects();
  updateAllFiles();
  updateAllColors();
  updateAllTextareas();
  updateAllPasswordIcons();
}
function onInputDocument(e) {
  const input = e.target;
  if (!hasTag(input, "input") && !hasTag(input, "select"))
    return;
  if (input.type === "range") {
    input.focus();
    updateRange(input);
  } else {
    updateAllRanges();
  }
}
function onFocusRange(e) {
  if (!isTouchable())
    return;
  const input = e.target;
  const label = parent(input);
  if (hasClass(label, "vertical"))
    document.body.classList.add("no-scroll");
}
function onBlurRange(e) {
  if (!isTouchable())
    return;
  const input = e.target;
  const label = parent(input);
  if (hasClass(label, "vertical"))
    document.body.classList.remove("no-scroll");
}
function updateAllRanges() {
  const body = document.body;
  const ranges = queryAll(".slider > input[type=range]");
  if (!ranges.length)
    off(body, "input", onInputDocument, false);
  else
    on(body, "input", onInputDocument, false);
  for (let i = 0; i < ranges.length; i++)
    updateRange(ranges[i]);
}
function updateRange(input) {
  on(input, "focus", onFocusRange);
  on(input, "blur", onBlurRange);
  const label = parent(input);
  const bar = query("span", label);
  const inputs = queryAll("input", label);
  if (!inputs.length || !bar)
    return;
  const rootSize = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--size")) || 16;
  const thumb = hasClass(label, "max") ? 0 : 0.25 * rootSize * 100 / inputs[0].offsetWidth;
  const percents = [];
  const values = [];
  for (let i = 0, n = inputs.length; i < n; i++) {
    const min = parseFloat(inputs[i].min) || 0;
    const max = parseFloat(inputs[i].max) || 100;
    const value = parseFloat(inputs[i].value) || 0;
    const percent2 = (value - min) * 100 / (max - min);
    const fix = thumb / 2 - thumb * percent2 / 100;
    percents.push(percent2 + fix);
    values.push(value);
  }
  let percent = percents[0];
  let start2 = 0;
  let end = 100 - start2 - percent;
  let value1 = values[0];
  let value2 = values[1] || 0;
  if (inputs.length > 1) {
    percent = Math.abs(percents[1] - percents[0]);
    start2 = percents[1] > percents[0] ? percents[0] : percents[1];
    end = 100 - start2 - percent;
    if (value2 > value1) {
      value1 = values[1] || 0;
      value2 = values[0];
    }
  }
  label.style.setProperty("---start", `${start2}%`);
  label.style.setProperty("---end", `${end}%`);
  label.style.setProperty("---value1", `'${value1}'`);
  label.style.setProperty("---value2", `'${value2}'`);
}
function updateAllSliders() {
  updateAllRanges();
}
const _lastTheme = {
  light: "",
  dark: ""
};
function getMode() {
  var _a;
  return ((_a = document == null ? void 0 : document.body) == null ? void 0 : _a.classList.contains("dark")) ? "dark" : "light";
}
function lastTheme() {
  if (_lastTheme.light && _lastTheme.dark)
    return _lastTheme;
  const body = document.body;
  const light = document.createElement("body");
  light.className = "light";
  body.appendChild(light);
  const dark = document.createElement("body");
  dark.className = "dark";
  body.appendChild(dark);
  const fromLight = getComputedStyle(light);
  const fromDark = getComputedStyle(dark);
  const variables = ["--primary", "--on-primary", "--primary-container", "--on-primary-container", "--secondary", "--on-secondary", "--secondary-container", "--on-secondary-container", "--tertiary", "--on-tertiary", "--tertiary-container", "--on-tertiary-container", "--error", "--on-error", "--error-container", "--on-error-container", "--background", "--on-background", "--surface", "--on-surface", "--surface-variant", "--on-surface-variant", "--outline", "--outline-variant", "--shadow", "--scrim", "--inverse-surface", "--inverse-on-surface", "--inverse-primary", "--surface-dim", "--surface-bright", "--surface-container-lowest", "--surface-container-low", "--surface-container", "--surface-container-high", "--surface-container-highest"];
  for (let i = 0, n = variables.length; i < n; i++) {
    _lastTheme.light += variables[i] + ":" + fromLight.getPropertyValue(variables[i]) + ";";
    _lastTheme.dark += variables[i] + ":" + fromDark.getPropertyValue(variables[i]) + ";";
  }
  body.removeChild(light);
  body.removeChild(dark);
  return _lastTheme;
}
function updateTheme(source) {
  const context = globalThis;
  const body = document.body;
  if (!source || !context.materialDynamicColors)
    return lastTheme();
  const mode = getMode();
  if (source.light && source.dark) {
    _lastTheme.light = source.light;
    _lastTheme.dark = source.dark;
    body.setAttribute("style", source[mode]);
    return source;
  }
  return context.materialDynamicColors(source).then((theme) => {
    const toCss = (data) => {
      let style = "";
      for (let i = 0, keys = Object.keys(data), n = keys.length; i < n; i++) {
        const key = keys[i];
        const value = data[key];
        const kebabCase = key.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase();
        style += "--" + kebabCase + ":" + value + ";";
      }
      return style;
    };
    _lastTheme.light = toCss(theme.light);
    _lastTheme.dark = toCss(theme.dark);
    body.setAttribute("style", _lastTheme[mode]);
    return _lastTheme;
  });
}
function updateMode(value) {
  const context = globalThis;
  const body = document.body;
  if (!body)
    return value;
  if (!value)
    return getMode();
  if (value === "auto")
    value = isDark() ? "dark" : "light";
  body.classList.remove("light", "dark");
  body.classList.add(value);
  const lastThemeStyle = value === "light" ? _lastTheme.light : _lastTheme.dark;
  if (context.materialDynamicColors)
    body.setAttribute("style", lastThemeStyle);
  return getMode();
}
const _dialogs = [];
function onKeydownDialog(e) {
  if (e.key === "Escape") {
    const dialog = e.currentTarget;
    void updateDialog(dialog, dialog);
  }
}
function focusOnDialogOrElement(dialog) {
  const element = query("[autofocus]", dialog) ?? dialog;
  element.focus();
}
function closeDialog(dialog, overlay) {
  removeClass(queryAllDataUi(dialog.id), "active");
  removeClass(dialog, "active");
  removeClass(overlay, "active");
  dialog.close();
  _dialogs.pop();
  const previousDialog = _dialogs[_dialogs.length - 1];
  if (previousDialog)
    previousDialog.focus();
  else if (isTouchable())
    document.body.classList.remove("no-scroll");
}
async function openDialog(dialog, overlay, isModal, from) {
  if (!hasTag(from, "button") && !hasClass(from, "button") && !hasClass(from, "chip"))
    addClass(from, "active");
  addClass(overlay, "active");
  addClass(dialog, "active");
  if (isModal)
    dialog.showModal();
  else
    dialog.show();
  await wait(90);
  if (!isModal)
    on(dialog, "keydown", onKeydownDialog, false);
  _dialogs.push(dialog);
  if (isTouchable())
    document.body.classList.add("no-scroll");
  focusOnDialogOrElement(dialog);
}
function onClickOverlay(e) {
  const overlay = e.currentTarget;
  const dialog = next(overlay);
  if (hasTag(dialog, "dialog"))
    closeDialog(dialog, overlay);
}
async function updateDialog(from, dialog) {
  blurActiveElement();
  let overlay = prev(dialog);
  const isActive = hasClass(dialog, "active") || dialog.open;
  const isModal = hasClass(dialog, "modal");
  if (!isModal)
    off(dialog, "keydown", onKeydownDialog, false);
  if (!hasClass(overlay, "overlay")) {
    overlay = create({ class: "overlay" });
    insertBefore(overlay, dialog);
    await wait(90);
  }
  if (!isModal)
    on(overlay, "click", onClickOverlay, false);
  if (isActive)
    closeDialog(dialog, overlay);
  else
    void openDialog(dialog, overlay, isModal, from);
}
let _timeoutMenu;
function onClickDocument(e) {
  off(document.body, "click", onClickDocument);
  const body = e.target;
  const menus = queryAll("menu.active");
  for (let i = 0; i < menus.length; i++)
    updateMenu(body, menus[i], e);
}
function focusOnMenuOrInput(menu) {
  setTimeout(() => {
    const input = query(".field > input", menu);
    if (input)
      input.focus();
    else
      menu.focus();
  }, 90);
}
function updateMenu(from, menu, e) {
  if (_timeoutMenu)
    clearTimeout(_timeoutMenu);
  _timeoutMenu = setTimeout(() => {
    on(document.body, "click", onClickDocument);
    if (!hasTag(document.activeElement, "input"))
      blurActiveElement();
    const isActive = hasClass(menu, "active");
    const isEvent = (e == null ? void 0 : e.target) === from;
    const isChild = !!from.closest("menu");
    if (!isActive && isChild || isActive && isEvent) {
      removeClass(menu, "active");
      return;
    }
    removeClass(queryAll("menu.active"), "active");
    addClass(menu, "active");
    focusOnMenuOrInput(menu);
  }, 90);
}
let _timeoutSnackbar;
function onClickSnackbar(e) {
  const snackbar = e.currentTarget;
  removeClass(snackbar, "active");
  if (_timeoutSnackbar)
    clearTimeout(_timeoutSnackbar);
}
function updateSnackbar(snackbar, milliseconds) {
  blurActiveElement();
  const activeSnackbars = queryAll(".snackbar.active");
  for (let i = 0; i < activeSnackbars.length; i++)
    removeClass(activeSnackbars[i], "active");
  addClass(snackbar, "active");
  on(snackbar, "click", onClickSnackbar);
  if (_timeoutSnackbar)
    clearTimeout(_timeoutSnackbar);
  if (milliseconds === -1)
    return;
  _timeoutSnackbar = setTimeout(() => {
    removeClass(snackbar, "active");
  }, milliseconds ?? 6e3);
}
function updatePage(page) {
  const container = parent(page);
  if (container)
    removeClass(queryAll(":scope > .page", container), "active");
  addClass(page, "active");
}
function onPointerDownRipple(e) {
  updateRipple(e);
}
function updateRipple(e) {
  const element = e.currentTarget;
  const rect = element.getBoundingClientRect();
  const diameter = Math.max(rect.width, rect.height);
  const radius = diameter / 2;
  const x = e.clientX - rect.left - radius;
  const y = e.clientY - rect.top - radius;
  const rippleContainer = document.createElement("div");
  rippleContainer.className = "ripple-js";
  const ripple = document.createElement("div");
  ripple.style.inlineSize = ripple.style.blockSize = `${diameter}px`;
  ripple.style.left = `${x}px`;
  ripple.style.top = `${y}px`;
  ripple.addEventListener("animationend", () => {
    rippleContainer.remove();
  });
  rippleContainer.appendChild(ripple);
  element.appendChild(rippleContainer);
}
function updateAllRipples() {
  const ripples = queryAll(".slow-ripple, .ripple, .fast-ripple");
  for (let i = 0; i < ripples.length; i++)
    on(ripples[i], "pointerdown", onPointerDownRipple);
}
let _timeoutMutation;
let _mutation;
function onMutation() {
  if (_timeoutMutation)
    clearTimeout(_timeoutMutation);
  _timeoutMutation = setTimeout(async () => await ui(), 180);
}
async function run(from, to, options, e) {
  if (!to) {
    to = query(from.getAttribute("data-ui"));
    if (!to)
      return;
  }
  updateAllClickable(from);
  if (hasTag(to, "dialog")) {
    await updateDialog(from, to);
    return;
  }
  if (hasTag(to, "menu")) {
    updateMenu(from, to, e);
    return;
  }
  if (hasClass(to, "snackbar")) {
    updateSnackbar(to, options);
    return;
  }
  if (hasClass(to, "page")) {
    updatePage(to);
    return;
  }
  if (hasClass(to, "active")) {
    removeClass(from, "active");
    removeClass(to, "active");
    return;
  }
  addClass(to, "active");
}
function onClickElement(e) {
  void run(e.currentTarget, null, null, e);
}
function onKeydownElement(e) {
  if (e.key === "Enter")
    void run(e.currentTarget, null, null, e);
}
function setup() {
  if (_mutation)
    return;
  _mutation = new MutationObserver(onMutation);
  _mutation.observe(document.body, { childList: true, subtree: true });
  onMutation();
}
function updateAllDataUis() {
  const elements = queryAll("[data-ui]");
  for (let i = 0, n = elements.length; i < n; i++) {
    on(elements[i], "click", onClickElement);
    if (hasTag(elements[i], "a") && !elements[i].getAttribute("href"))
      on(elements[i], "keydown", onKeydownElement);
  }
}
function ui(selector, options) {
  if (selector) {
    if (selector === "setup") {
      setup();
      return;
    }
    if (selector === "guid")
      return guid();
    if (selector === "mode")
      return updateMode(options);
    if (selector === "theme")
      return updateTheme(options);
    const to = query(selector);
    if (!to)
      return;
    void run(to, to, options);
  }
  updateAllDataUis();
  updateAllFields();
  updateAllSliders();
  updateAllRipples();
}
function start() {
  var _a;
  const context = globalThis;
  const body = (_a = context == null ? void 0 : context.document) == null ? void 0 : _a.body;
  if (body && !body.classList.contains("dark") && !body.classList.contains("light"))
    updateMode("auto");
  on(context, "load", setup, false);
  context.ui = ui;
}
start();
export {
  ui as default,
  ui
};
