Skip to content

Commit

Permalink
feat: return an unregister fn with on and allow local registration of…
Browse files Browse the repository at this point in the history
… listeners
  • Loading branch information
Honoré Nintunze committed Dec 12, 2020
1 parent 3037041 commit 1ece0dc
Show file tree
Hide file tree
Showing 8 changed files with 1,281 additions and 76 deletions.
786 changes: 786 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 53,9 @@
"doc:html": "typedoc src/ --exclude **/*.spec.ts --target ES6 --mode file --out build/docs",
"doc:json": "typedoc src/ --exclude **/*.spec.ts --target ES6 --mode file --json build/docs/typedoc.json",
"doc:publish": "gh-pages -m \"[ci skip] Updates\" -d build/docs",
"version": "npx standard-version --no-verify -a",
"version": "npx standard-version --no-verify -a -t ''",
"reset-hard": "git clean -dfx && git reset --hard && npm i",
"prepare-release": "run-s reset-hard test doc:html version doc:publish",
"prepare-release": "run-s reset-hard build test doc:html doc:json version doc:publish",
"commit": "./node_modules/cz-customizable/standalone.js",
"clean": "rm -rf build .nyc_output"
},
Expand All @@ -71,9 71,12 @@
"@commitlint/cli": "^11.0.0",
"@commitlint/config-conventional": "^11.0.0",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/node": "^14.14.12",
"@types/sinon": "^9.0.9",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"ava": "^3.12.1",
"browser-env": "^3.3.0",
"codecov": "^3.5.0",
"commitlint-config-cz": "^0.13.2",
"cspell": "^4.1.0",
Expand All @@ -90,6 93,7 @@
"nyc": "^15.1.0",
"open-cli": "^6.0.1",
"prettier": "^2.1.1",
"sinon": "^9.2.2",
"standard-version": "^9.0.0",
"ts-node": "^9.0.0",
"typedoc": "^0.19.2",
Expand Down Expand Up @@ -118,6 122,9 @@
"./test/**/*.spec.ts",
"./tests/**/*.spec.ts",
"!build/module/**"
],
"require": [
"./test/_setup-browser-environment.js"
]
},
"lint-staged": {
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1 1,2 @@
export * from './lib/fine-mq'
export { FineMqPlugin } from './vue/plugin'
101 changes: 29 additions & 72 deletions src/lib/fine-mq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 4,6 @@ import { aliases2mq, json2mq } from './helpers'
import {
FineMediaQueries,
MatchingAliases,
MediaQueryAliases,
MediaQueryMatcherHandler,
MediaQueryMatchListener,
MediaQueryObject,
Expand All @@ -28,17 27,19 @@ export const getMatchListener = (mq: Mq, aliasOrMediaQuery: string): MediaQueryM

export const setMatchingAliases = (mq: Mq, matchingAliases: MatchingAliases = {}) => (mq.matchingAliases = matchingAliases)

export const createNewMediaQueryMatchListener = (
export const createMediaQueryMatchListener = (
mq: Mq,
aliasOrMediaQuery: string,
callback: MediaQueryMatcherHandler
callback?: MediaQueryMatcherHandler,
forceRegistration?: boolean
): MediaQueryMatchListener => {
if (typeof callback !== 'function')
throw new TypeError('The callback function needs to be defined in order to create a new match listener')

let mediaQuery = getMediaQueryString(mq, aliasOrMediaQuery)
if (!mediaQuery) {
mediaQuery = json2mq(aliasOrMediaQuery)
}
if (typeof callback !== 'function')
throw new TypeError('The callback function needs to be defined in order to create a new match listener')

const mqMatcher: MediaQueryMatchListener = {
handlers: [],
Expand Down Expand Up @@ -67,6 68,13 @@ export const createNewMediaQueryMatchListener = (
},
}

if (forceRegistration) {
if (!(aliasOrMediaQuery in mq.aliases)) {
mq.aliases = { ...mq.aliases, [mediaQuery]: mediaQuery }
}
mq.matchers[mediaQuery] = mqMatcher
}

mqMatcher.handlers.push(callback)
mqMatcher.listener.call(undefined, { matches: mqMatcher.matcher.matches, mediaQuery, alias: aliasOrMediaQuery }) // trigger listener immediately
mqMatcher.matcher.addEventListener('change', mqMatcher.listener)
Expand All @@ -82,15 90,6 @@ export const removeMediaQueryMatchListener = (mq: Mq, aliasOrMediaQuery: string)
}
}

export const on = (mq: Mq, aliasOrMediaQuery: string, callback: MediaQueryMatcherHandler): void => {
const mediaQuery = getMediaQueryString(mq, aliasOrMediaQuery)
const mqMatcher = mq.matchers[mediaQuery] || createNewMediaQueryMatchListener(mq, aliasOrMediaQuery, callback)
mq.matchers = {
...mq.matchers,
[mediaQuery]: mqMatcher,
}
}

export const off = (mq: Mq, aliasOrMediaQuery?: string, callback?: MediaQueryMatcherHandler): void => {
if (!aliasOrMediaQuery) {
// remove all listeners
Expand All @@ -116,6 115,17 @@ export const off = (mq: Mq, aliasOrMediaQuery?: string, callback?: MediaQueryMat
}
}

export const on = (mq: Mq, aliasOrMediaQuery: string, callback: MediaQueryMatcherHandler): (() => void) => {
const mediaQuery = getMediaQueryString(mq, aliasOrMediaQuery)
const mqMatcher = mq.matchers[mediaQuery] || createMediaQueryMatchListener(mq, aliasOrMediaQuery, callback)
mq.matchers = {
...mq.matchers,
[mediaQuery]: mqMatcher,
}

return () => off(mq, aliasOrMediaQuery, callback)
}

export const addAlias = (mq: Mq, alias: string | { [key: string]: MediaQueryObject }, mediaQuery?: MediaQueryObject): void => {
if (typeof alias === 'string' && mediaQuery) {
mq.aliases = {
Expand All @@ -127,10 137,14 @@ export const addAlias = (mq: Mq, alias: string | { [key: string]: MediaQueryObje
...mq.aliases,
...aliases2mq(alias),
}
}
} // else Trying to register alias "${alias}" with no media query associated. Nothing to do.
}

export const removeAlias = (mq: Mq, alias: string): void => {
if (!(alias in mq.aliases)) {
// Trying to unregister inexistant alias "${alias}". Nothing to do.
return
}
const mqMatcher = getMatchListener(mq, alias)
if (mqMatcher) off(mq, alias)

Expand Down Expand Up @@ -161,60 175,3 @@ export const createFineMediaQueries = (
removeAlias: (alias: string) => removeAlias(mq, alias),
}
}

export const FineMqPlugin = {
install(app: any, options: { aliases?: MediaQueryAliases; defaultMatchingAliases?: MatchingAliases } = {}) {
let hasSetupListeners = false
const defaultLastActiveAlias = Object.keys(options.defaultMatchingAliases ?? {})[0]

const reactiveSource = app.observable({
// replace with app.reactive in the next major version to support vue3
matchingAliases: {},
lastActiveAlias: defaultLastActiveAlias,
})

const fineMq = createFineMediaQueries(
options.aliases || { sm: 680, md: [681, 1024], lg: [1025] },
options.defaultMatchingAliases
)

const onMqMatchEvent: MediaQueryMatcherHandler = ({ matches, alias, mediaQuery }) => {
const aliases = getAliasesForMediaQuery(fineMq.mq, mediaQuery)
const matchingAliases: MatchingAliases = {}
for (const _alias of aliases) {
matchingAliases[_alias] = matches
}
reactiveSource.matchingAliases = { ...reactiveSource.matchingAliases, ...matchingAliases }
if (matches) reactiveSource.lastActiveAlias = alias
}

app.mixin({
computed: {
$mq() {
return reactiveSource.matchingAliases
},
$mqLastActiveAlias() {
return reactiveSource.lastActiveAlias
},
},
created() {
if (this.$isServer) {
reactiveSource.matchingAliases = options.defaultMatchingAliases
reactiveSource.lastActiveAlias = defaultLastActiveAlias
}
},
mounted() {
if (!hasSetupListeners) {
Object.keys(fineMq.mq.aliases).forEach((alias) => fineMq.on(alias, onMqMatchEvent))
hasSetupListeners = true
}
},
})

// remove this in the next major version to support vue3
app.prototype.$fineMq = fineMq

// uncomment this in the next major version to support vue3
// app.config.globalProperties.$fineMq = fineMq
},
}
Loading

0 comments on commit 1ece0dc

Please sign in to comment.