UNPKG

viewport-extra

Version:

Enable setting minimum and maximum viewport width

122 lines (109 loc) 6.56 kB
/*! Viewport Extra v3.0.0 | (c) dsktschy | MIT License */ var ViewportExtra = (function (exports) { 'use strict'; const ensureViewportMetaElement = (doc) => { const viewportMetaElement = doc.querySelector('meta[name="viewport"]'); if (viewportMetaElement) return viewportMetaElement; const htmlMetaElement = doc.createElement("meta"); htmlMetaElement.setAttribute("name", "viewport"); doc.head.appendChild(htmlMetaElement); return htmlMetaElement; }; const getDocumentClientWidth = (doc) => doc.documentElement.clientWidth; const kebabizeCamelCaseString = (str) => str .replace(/\s+/g, "") .replace(/[A-Z]+/g, (s) => `-${s[0]}`) .toLowerCase(); const mathTrunc = /* eslint-disable-next-line compat/compat */ Math.trunc ; const truncateDecimalNumber = (num, decimalPlaces) => // biome-ignore lint/suspicious/noGlobalIsFinite: isFinite is safe to use here isFinite(decimalPlaces) ? mathTrunc(num * 10 ** decimalPlaces) / 10 ** decimalPlaces : num; const defaultContent = { width: "device-width", initialScale: 1, minimumWidth: 0, maximumWidth: Infinity, }; const createContent = (partialContent = {}) => ({ ...defaultContent, ...partialContent, }); const mergeOptionalPartialContent = (precedingOptionalPartialContent, followingOptionalPartialContent) => precedingOptionalPartialContent ? { ...precedingOptionalPartialContent, ...(followingOptionalPartialContent ?? {}), } : followingOptionalPartialContent; const createContentAttribute$1 = (content = { ...defaultContent }, // biome-ignore lint/style/noInferrableTypes: number type cannot be inferred from initialization documentClientWidth = 0, decimalPlaces = 0) => { const { width, initialScale } = content; const { minimumWidth: _minimumWidth, maximumWidth: _maximumWidth, minWidth, maxWidth, ...contentWithoutExtraProperties } = content; const minimumWidth = minWidth ?? _minimumWidth; const maximumWidth = maxWidth ?? _maximumWidth; if (minimumWidth <= maximumWidth && width === "device-width") { if (documentClientWidth < minimumWidth) { contentWithoutExtraProperties.width = minimumWidth; contentWithoutExtraProperties.initialScale = (documentClientWidth / minimumWidth) * initialScale; } else if (documentClientWidth > maximumWidth) { contentWithoutExtraProperties.width = maximumWidth; contentWithoutExtraProperties.initialScale = (documentClientWidth / maximumWidth) * initialScale; } } return Object.keys(contentWithoutExtraProperties) .map((key) => `${kebabizeCamelCaseString(key)}=${typeof contentWithoutExtraProperties[key] === "number" ? truncateDecimalNumber(contentWithoutExtraProperties[key], decimalPlaces) : contentWithoutExtraProperties[key]}`) .sort() .join(","); }; const defaultMedia = ""; const createMedia = (optionalMedia) => optionalMedia ?? defaultMedia; const mergeOptionalMedia = (precedingOptionalMedia, followingOptionalMedia) => followingOptionalMedia ?? precedingOptionalMedia; const createMediaSpecificParameters = (partialMediaSpecificParameters = {}) => ({ content: createContent(partialMediaSpecificParameters.content), media: createMedia(partialMediaSpecificParameters.media), }); const mergePartialMediaSpecificParameters = (precedingPartialMediaSpecificParameters, followingPartialMediaSpecificParameters) => { const partialMediaSpecificParameters = {}; const optionalPartialContent = mergeOptionalPartialContent(precedingPartialMediaSpecificParameters.content, followingPartialMediaSpecificParameters.content); const optionalMedia = mergeOptionalMedia(precedingPartialMediaSpecificParameters.media, followingPartialMediaSpecificParameters.media); if (optionalPartialContent) partialMediaSpecificParameters.content = optionalPartialContent; if (typeof optionalMedia !== "undefined") partialMediaSpecificParameters.media = optionalMedia; return partialMediaSpecificParameters; }; const createContentAttribute = (optionalMediaSpecificParameters, optionalDocumentClientWidth, optionalDecimalPlaces) => optionalMediaSpecificParameters && typeof optionalDocumentClientWidth !== "undefined" && typeof optionalDecimalPlaces !== "undefined" ? createContentAttribute$1(optionalMediaSpecificParameters.content, optionalDocumentClientWidth, optionalDecimalPlaces) : createContentAttribute$1(); const createPartialMediaSpecificParametersMerger = (isMatchingCurrentViewport) => (precedingPartialMediaSpecificParameters, followingPartialMediaSpecificParameters) => isMatchingCurrentViewport(followingPartialMediaSpecificParameters.media) ? mergePartialMediaSpecificParameters(precedingPartialMediaSpecificParameters, followingPartialMediaSpecificParameters) : precedingPartialMediaSpecificParameters; const setContentAttribute = (htmlMetaElement, contentAttribute) => htmlMetaElement.setAttribute("content", contentAttribute); const applyMediaSpecificParameters = (htmlMetaElement, getDocumentClientWidth, getMediaSpecificParameters) => { setContentAttribute(htmlMetaElement, createContentAttribute()); setContentAttribute(htmlMetaElement, createContentAttribute(getMediaSpecificParameters(), getDocumentClientWidth(), Infinity)); }; const createMatchMediaPredicate = (mm) => (media) => typeof media !== "undefined" ? mm(media).matches : true; const setMediaSpecificParametersList = (partialMediaSpecificParametersList) => { if (typeof window === "undefined") return; applyMediaSpecificParameters(ensureViewportMetaElement(document), () => getDocumentClientWidth(document), () => createMediaSpecificParameters(partialMediaSpecificParametersList.reduce(createPartialMediaSpecificParametersMerger(createMatchMediaPredicate(matchMedia)), // Value that does not need to check matching current viewport createMediaSpecificParameters()))); }; exports.apply = setMediaSpecificParametersList; return exports; })({}); //# sourceMappingURL=viewport-extra.js.map