Skip to content

Commit

Permalink
Refactors code, adds documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
akolson committed Oct 4, 2022
1 parent 8fe1519 commit 2d1351e
Showing 1 changed file with 88 additions and 43 deletions.
131 changes: 88 additions & 43 deletions lib/useKResponsiveWindow.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { computed, onBeforeUnmount, onMounted, ref, watchEffect } from 'vue';
import { computed, onBeforeUnmount, onMounted, ref } from 'kolibri.lib.vueCompositionApi';

/**
* Returns window inner width and height
* @returns {Object} The window's inner width and height
*/
function windowMetrics() {
return {
width: window.innerWidth,
height: window.innerHeight,
};
}

/**
* Add a media query
* @param {String} query
* @param {requestCallback} callback
* @returns {Object} The mediaQueryList, eventHandler, and stopListening
*/
function addMediaQuery(query, callback) {
const mediaQueryList = window.matchMedia(query);
const eventHandler = event => {
Expand All @@ -15,7 +25,6 @@ function addMediaQuery(query, callback) {
const stopListening = () => {
mediaQueryList.removeEventListener('change', eventHandler);
};

mediaQueryList.addEventListener('change', eventHandler);

return {
Expand All @@ -25,43 +34,44 @@ function addMediaQuery(query, callback) {
};
}

/**
* Export window properties
* @returns {Object} Window properties
*/
export default function useKResponsiveWindow() {
/** Window properties */
const windowWidth = ref(null);
const windowHeight = ref(null);
const windowBreakpoint = ref(null);
const windowIsPortrait = ref(false);
const windowIsLandscape = ref(false);
const windowGutter = ref(16);
const windowIsShort = ref(false);

const windowIsLarge = computed(() => windowBreakpoint.value > 2);
const windowIsMedium = computed(() => windowBreakpoint.value === 2);
const windowIsSmall = computed(() => windowBreakpoint.value < 2);

const stopWatchOrientation = watchEffect(onInvalidate => {
const { stopListening } = addMediaQuery(`(orientation: portrait)`, event => {
_updateOrientation(event.matches);
_updateWindow();
_updateGutter();
});

onInvalidate(() => {
stopListening();
});
/**
* @function addMediaQuery
*/
const orientationQuery = addMediaQuery(`(orientation: portrait)`, event => {
updateOrientation(event.matches);
updateWindow();
updateGutter();
});

const stopWatchWindowHeight = watchEffect(onInvalidate => {
const { stopListening } = addMediaQuery(`(max-height: 600px)`, event => {
windowIsShort.value = event.matches;
_updateWindow();
});

onInvalidate(() => {
stopListening();
});
/**
* @function addMediaQuery
*/
const heightQuery = addMediaQuery(`(max-height: 600px)`, event => {
windowIsShort.value = event.matches;
updateWindow();
});

const stopWatchWindowWidth = watchEffect(onInvalidate => {
/**
* Generate width media queries
*/
const widthQueries = (() => {
const SCROLL_BAR = 16;
const queries = [
'(max-width: 480px)',
Expand All @@ -73,58 +83,93 @@ export default function useKResponsiveWindow() {
`(max-width: ${1600 - SCROLL_BAR}px)`,
`(min-width: 1601px)`,
];
const listeners = [];

const mediaQueries = [];
queries.forEach((query, index) => {
const { stopListening } = addMediaQuery(query, () => {
const widthQuery = addMediaQuery(query, () => {
windowBreakpoint.value = index;
_updateWindow();
_updateGutter();
updateWindow();
updateGutter();
});
listeners.push({ stopListening });
mediaQueries.push(widthQuery);
});
return mediaQueries;
})();

/**
* Initialize properties
*/
const initProps = () => {
orientationQuery.eventHandler(orientationQuery.mediaQueryList);
heightQuery.eventHandler(heightQuery.mediaQueryList);
widthQueries.every(widthQuery => {
if (widthQuery.mediaQueryList.matches) {
widthQuery.eventHandler(widthQuery.mediaQueryList);
return false;
}
return true;
});
};

onInvalidate(() => {
listeners.forEach(listener => {
const { stopListening } = listener;
stopListening();
});
/**
* Stop listening to media query changes
*/
const stopListening = () => {
orientationQuery.stopListening();
heightQuery.stopListening();
widthQueries.forEach(mediaQuery => {
const { stopListening } = mediaQuery;
stopListening();
});
});
};

const _updateGutter = () => {
/**
* Update window gutter
*/
const updateGutter = () => {
if (windowIsSmall.value) {
windowGutter.value = 16;
} else if (_smallestWindowDimensionIsLessThan(600)) {
} else if (smallestWindowDimensionIsLessThan(600)) {
windowGutter.value = 16;
} else {
windowGutter.value = 24;
}
};

const _smallestWindowDimensionIsLessThan = dimension => {
/**
* Check if the smallest window dimension(width or height) is smaller than the specified dimension
* @param {Number} dimension in px
* @returns {Boolean}
*/
const smallestWindowDimensionIsLessThan = dimension => {
return (
windowBreakpoint.value < 4 && Math.min(windowWidth.value, windowHeight.value) < dimension
);
};

const _updateOrientation = portrait => {
/**
* Update window orientation
* @param {Boolean} portrait
*/
const updateOrientation = portrait => {
windowIsPortrait.value = portrait;
windowIsLandscape.value = !windowIsPortrait.value;
};

const _updateWindow = () => {
/**
* Update window width and height
*/
const updateWindow = () => {
const metrics = windowMetrics();
windowWidth.value = metrics.width;
windowHeight.value = metrics.height;
};

onMounted(() => {
_updateWindow();
initProps();
});
onBeforeUnmount(() => {
stopWatchOrientation();
stopWatchWindowHeight();
stopWatchWindowWidth();
stopListening();
});

return {
Expand Down

0 comments on commit 2d1351e

Please sign in to comment.