apexcharts
Version:
A JavaScript Chart Library
116 lines (115 loc) • 3.99 kB
JavaScript
/*!
* ApexCharts v6.6.1
* (c) 2018-2026 ApexCharts
*/
import * as _core from "apexcharts/core";
import _core__default from "apexcharts/core";
import { default as default2 } from "apexcharts/core";
const Environment = _core.__apex_Environment_Environment;
const BrowserAPIs = _core.__apex_BrowserAPIs_BrowserAPIs;
const DARK_QUERY = "(prefers-color-scheme: dark)";
const CONTRAST_QUERY = "(prefers-contrast: more)";
class OSThemeWatcher {
/**
* @param {any} w @param {any} ctx
*/
constructor(w, ctx) {
this.w = w;
this.ctx = ctx;
if (w.config.theme.follow !== "os" || !Environment.isBrowser()) return;
const media = this._ensureMedia();
if (!media) return;
this._applyToConfig(media);
this._ensureListeners(media);
}
/**
* Create (once per instance) the MediaQueryLists and stash them on `ctx` so
* they persist across the re-render that `updateOptions` triggers.
* @returns {{dark: MediaQueryList|null, contrast: MediaQueryList|null, handler: null|(()=>void)}|null}
*/
_ensureMedia() {
if (!this.ctx._osThemeMedia) {
const dark = BrowserAPIs.matchMedia(DARK_QUERY);
const contrast = BrowserAPIs.matchMedia(CONTRAST_QUERY);
if (!dark && !contrast) return null;
this.ctx._osThemeMedia = { dark, contrast, handler: null };
}
return this.ctx._osThemeMedia;
}
/**
* Write the OS-resolved mode / high-contrast onto the live `w.config.theme`.
* @param {{dark: MediaQueryList|null, contrast: MediaQueryList|null}} media
*/
_applyToConfig(media) {
const theme = this.w.config.theme;
if (media.dark) {
theme.mode = media.dark.matches ? "dark" : "light";
}
if (media.contrast && media.contrast.matches) {
theme.accessibility = theme.accessibility || {};
theme.accessibility.colorBlindMode = "highContrast";
}
}
/**
* Attach the `change` listener once. The handler closes over `ctx` + `media`
* (both stable across re-renders), NOT over `this` (a fresh watcher is built
* each create), so it never goes stale.
* @param {{dark: MediaQueryList|null, contrast: MediaQueryList|null, handler: null|(()=>void)}} media
*/
_ensureListeners(media) {
if (media.handler) return;
const ctx = this.ctx;
const handler = () => {
const m = ctx._osThemeMedia;
if (!m) return;
const themeOpt = { mode: m.dark && m.dark.matches ? "dark" : "light" };
if (m.contrast && m.contrast.matches) {
themeOpt.accessibility = { colorBlindMode: "highContrast" };
} else {
themeOpt.accessibility = { colorBlindMode: "" };
}
ctx.updateOptions({ theme: themeOpt }, false, true, false);
};
OSThemeWatcher._add(media.dark, handler);
OSThemeWatcher._add(media.contrast, handler);
media.handler = handler;
}
/** Remove the listeners and drop the stashed media. Called on full destroy. */
teardown() {
const media = this.ctx._osThemeMedia;
if (!media) return;
if (media.handler) {
OSThemeWatcher._remove(media.dark, media.handler);
OSThemeWatcher._remove(media.contrast, media.handler);
}
this.ctx._osThemeMedia = null;
}
/**
* @param {MediaQueryList|null} mql @param {()=>void} handler
*/
static _add(mql, handler) {
if (!mql) return;
if (typeof mql.addEventListener === "function") {
mql.addEventListener("change", handler);
} else if (typeof /** @type {any} */
mql.addListener === "function") {
mql.addListener(handler);
}
}
/**
* @param {MediaQueryList|null} mql @param {()=>void} handler
*/
static _remove(mql, handler) {
if (!mql) return;
if (typeof mql.removeEventListener === "function") {
mql.removeEventListener("change", handler);
} else if (typeof /** @type {any} */
mql.removeListener === "function") {
mql.removeListener(handler);
}
}
}
_core__default.registerFeatures({ osThemeWatcher: OSThemeWatcher });
export {
default2 as default
};