mock-match-media
Version:
mock window.matchMedia for tests or node
1 lines • 12.3 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { match, parse, Feature, Query, MediaState } from \"css-mediaquery\";\n\nlet state: MediaState = {};\n\nconst now = Date.now();\n\n// Event was added in node 15, so until we drop the support for versions before it, we need to use this\nclass EventLegacy {\n type: \"change\";\n timeStamp: number;\n\n bubbles = false;\n cancelBubble = false;\n cancelable = false;\n composed = false;\n target = null;\n currentTarget = null;\n defaultPrevented = false;\n eventPhase = 0;\n isTrusted = false;\n initEvent = () => {};\n composedPath = () => [];\n preventDefault = () => {};\n stopImmediatePropagation = () => {};\n stopPropagation = () => {};\n returnValue = true;\n srcElement = null;\n // See https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase\n NONE = 0;\n CAPTURING_PHASE = 1;\n AT_TARGET = 2;\n BUBBLING_PHASE = 3;\n constructor(type: \"change\") {\n this.type = type;\n this.timeStamp = Date.now() - now; // See https://developer.mozilla.org/en-US/docs/Web/API/Event/timeStamp#value\n }\n}\n\n// @ts-expect-error\nconst EventCompat: typeof Event = typeof Event === \"undefined\" ? EventLegacy : Event;\n\nconst getFeaturesFromQuery = (query: Query): Set<Feature> => {\n const parsedQuery = parse(query);\n const features = new Set<Feature>();\n parsedQuery.forEach((subQuery) => {\n subQuery.expressions.forEach((expression) => {\n features.add(expression.feature);\n });\n });\n return features;\n};\n\ntype Callback = (event: MediaQueryListEvent) => void;\ntype MQL = ReturnType<typeof matchMedia>;\n\nconst MQLs = new Map<MQL, { clear: () => void; previousMatched: boolean; features: Set<Feature> }>();\n\nexport const matchMedia: typeof window.matchMedia = (query: string) => {\n let queryTyped = query as Query;\n let previousMatched;\n try {\n previousMatched = match(queryTyped, state);\n } catch (e) {\n queryTyped = \"not all\" as Query;\n previousMatched = false;\n }\n const callbacks = new Set<Callback>();\n const onces = new WeakSet<Callback>();\n\n const clear = () => {\n for (const callback of callbacks) {\n onces.delete(callback);\n }\n callbacks.clear();\n };\n\n const removeListener = (callback: Callback) => {\n callbacks.delete(callback);\n onces.delete(callback);\n };\n\n const mql: MQL = {\n get matches() {\n return match(queryTyped, state);\n },\n media: query,\n onchange: null,\n addEventListener: (event, callback, options) => {\n if (event === \"change\" && callback) {\n const isAlreadyListed = callbacks.has(callback);\n callbacks.add(callback);\n\n const hasOnce = typeof options === \"object\" && options?.once;\n\n // If it doesn’t have `once: true`, but it was previously added with one, the `once` status should be lifted\n if (!hasOnce) {\n onces.delete(callback);\n return;\n }\n\n // If the callback is already listed in the list of callback to call, but not as a `once`,\n // it means that it was added without the flag and thus shouldn’t be treated as such.\n if (isAlreadyListed && !onces.has(callback)) {\n return;\n }\n\n // Otherwise, use the `once` flag\n onces.add(callback);\n }\n },\n removeEventListener: (event, callback) => {\n if (event === \"change\") removeListener(callback);\n },\n dispatchEvent: (event: MediaQueryListEvent) => {\n if (!event) {\n throw new TypeError(\n `Failed to execute 'dispatchEvent' on 'EventTarget': 1 argument required, but only 0 present.`,\n );\n }\n if (!(event instanceof EventCompat)) {\n throw new TypeError(\n `Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`,\n );\n }\n if (event.type !== \"change\") {\n return true;\n }\n mql.onchange?.(event);\n callbacks.forEach((callback) => {\n callback(event);\n if (onces.has(callback)) {\n removeListener(callback);\n }\n });\n // TODO: target and currentTarget\n // Object.defineProperty(event, \"target\", { value: mql });\n return true;\n },\n addListener: (callback) => {\n if (!callback) return;\n callbacks.add(callback);\n },\n removeListener: (callback) => {\n if (!callback) return;\n removeListener(callback);\n },\n };\n\n MQLs.set(mql, {\n previousMatched,\n clear,\n features: getFeaturesFromQuery(queryTyped),\n });\n\n return mql;\n};\n\nexport class MediaQueryListEvent extends EventCompat {\n readonly media: string;\n readonly matches: boolean;\n constructor(\n type: \"change\",\n options: {\n media?: string;\n matches?: boolean;\n } = {},\n ) {\n super(type);\n this.media = options.media || \"\";\n this.matches = options.matches || false;\n }\n}\n\n// Cannot use MediaState here as setMedia is exposed in the API\nexport const setMedia = (media: Record<string, string>) => {\n const changedFeatures = new Set<Feature>();\n Object.keys(media).forEach((feature) => {\n changedFeatures.add(feature as Feature);\n state[feature] = media[feature];\n });\n for (const [MQL, cache] of MQLs) {\n let found = false;\n for (const feature of cache.features) {\n if (changedFeatures.has(feature)) {\n found = true;\n break;\n }\n }\n if (!found) {\n continue;\n }\n const matches = match(MQL.media as Query, state);\n if (matches === cache.previousMatched) {\n continue;\n }\n cache.previousMatched = matches;\n MQL.dispatchEvent(new MediaQueryListEvent(\"change\", { matches, media: MQL.media }));\n }\n};\n\nexport const cleanupListeners = () => {\n for (const { clear } of MQLs.values()) {\n clear();\n }\n MQLs.clear();\n};\n\nexport const cleanupMedia = () => {\n state = {};\n};\n\nexport const cleanup = () => {\n cleanupListeners();\n cleanupMedia();\n};\n"],"names":["state","now","Date","EventLegacy","constructor","type","timeStamp","bubbles","cancelBubble","cancelable","composed","target","currentTarget","defaultPrevented","eventPhase","isTrusted","initEvent","composedPath","preventDefault","stopImmediatePropagation","stopPropagation","returnValue","srcElement","NONE","CAPTURING_PHASE","AT_TARGET","BUBBLING_PHASE","EventCompat","Event","getFeaturesFromQuery","query","parsedQuery","parse","features","Set","forEach","subQuery","expressions","expression","add","feature","MQLs","Map","matchMedia","queryTyped","previousMatched","match","e","callbacks","onces","WeakSet","clear","callback","delete","removeListener","mql","matches","media","onchange","addEventListener","event","options","isAlreadyListed","has","hasOnce","once","removeEventListener","dispatchEvent","TypeError","addListener","set","MediaQueryListEvent","setMedia","changedFeatures","Object","keys","MQL","cache","found","cleanupListeners","values","cleanupMedia","cleanup"],"mappings":"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"}