ripple
Version:
Ripple is an elegant TypeScript UI framework
56 lines (48 loc) • 1.7 kB
JavaScript
import { on } from './internal/client/events.js';
import { get, safe_scope, set, tracked, with_scope } from './internal/client/index.js';
import { ReactiveValue } from './reactive-value.js';
/** @typedef {import('#public').ReactiveValue<boolean>} ReactiveValueBoolean */
const parenthesis_regex = /\(.+\)/;
const non_parenthesized_keywords = new Set(['all', 'print', 'screen', 'and', 'or', 'not', 'only']);
/**
* @type {new (query: string, fallback?: boolean | undefined) => ReactiveValueBoolean}
*/
export const MediaQuery = /** @type {any} */ (
function MediaQuery(/** @type {string} */ query, /** @type {boolean | undefined} */ fallback) {
if (!new.target) {
throw new TypeError('MediaQuery must be called with new');
}
var block = safe_scope();
let final_query =
parenthesis_regex.test(query) ||
// we need to use `some` here because technically this `window.matchMedia('random,screen')` still returns true
query.split(/[\s,]+/).some((keyword) => non_parenthesized_keywords.has(keyword.trim()))
? query
: `(${query})`;
const q = window.matchMedia(final_query);
const matches = tracked(q.matches, block);
return new ReactiveValue(
() => get(matches),
() =>
on(
q,
'change',
() => {
// skip wrapping in untrack as createSubscriber already does it
if (q.matches !== get(matches)) {
set(matches, q.matches);
}
},
{ delegated: false },
),
);
}
);
/**
* @param {import('#client').Block} block
* @param {string} query
* @param {boolean | undefined} [fallback]
*/
export function media_query(block, query, fallback) {
return with_scope(block, () => new MediaQuery(query, fallback));
}