{"version":3,"file":"ssm.min.js","sources":["../src/utils.js","../src/state.js","../src/ssm.js"],"sourcesContent":["export function filterStates(states, key, value) {\n return states.filter(state => state[key] && state[key] === value);\n}\n\nexport function makeID() {\n return Math.random().toString(36).substr(2, 9);\n}\n\nexport function fireAllMethodsInArray(arr, event) {\n arr.forEach(method => method(event));\n}\n\nexport function funcToArray(func) {\n return typeof func === 'function' ? [func] : func;\n}\n\nexport function debounce(func) {\n let timeout;\n\n return (...args) => {\n const later = () => {\n timeout = null;\n func.apply(this, args);\n };\n\n if (timeout) {\n window.cancelAnimationFrame(timeout);\n }\n\n timeout = window.requestAnimationFrame(later);\n };\n}\n","import {\n fireAllMethodsInArray,\n makeID,\n} from './utils';\n\nconst configOptions = [];\nlet stateChangeMethod = () => { };\n\nexport default class State {\n constructor(options) {\n this.id = options.id || makeID();\n this.query = options.query || 'all';\n\n const defaultOptions = {\n onEnter: [],\n onLeave: [],\n onResize: [],\n onFirstRun: [],\n };\n\n // Merge options with defaults to make the state\n this.options = Object.assign({}, defaultOptions, options);\n\n // Migrate methods into an array, this is to enable future functionality of adding extra methods to an existing state\n if (typeof this.options.onEnter === 'function') {\n this.options.onEnter = [this.options.onEnter];\n }\n\n if (typeof this.options.onLeave === 'function') {\n this.options.onLeave = [this.options.onLeave];\n }\n\n if (typeof this.options.onResize === 'function') {\n this.options.onResize = [this.options.onResize];\n }\n\n if (typeof this.options.onFirstRun === 'function') {\n this.options.onFirstRun = [this.options.onFirstRun];\n }\n\n // Test the one time tests first, if the test is invalid we wont create the config option\n if (this.testConfigOptions('once') === false) {\n this.valid = false;\n return false;\n }\n\n this.valid = true;\n this.active = false;\n this.init();\n }\n\n init() {\n this.test = window.matchMedia(this.query);\n\n if (this.test.matches && this.testConfigOptions('match')) {\n this.enterState();\n }\n\n this.listener = (test) => {\n let changed = false;\n\n if (test.matches) {\n if (this.testConfigOptions('match')) {\n this.enterState();\n changed = true;\n }\n } else {\n this.leaveState();\n changed = true;\n }\n\n if (changed) {\n stateChangeMethod();\n }\n };\n\n this.test.addListener(this.listener);\n }\n\n // Handle entering a state\n enterState() {\n fireAllMethodsInArray(this.options.onFirstRun, this.eventData('firstRun'));\n fireAllMethodsInArray(this.options.onEnter, this.eventData('enter'));\n this.options.onFirstRun = [];\n this.active = true;\n }\n\n // Handle leaving a state\n leaveState() {\n fireAllMethodsInArray(this.options.onLeave, this.eventData('leave'));\n this.active = false;\n }\n\n // Handle the user resizing the browser\n resizeState() {\n if (this.testConfigOptions('resize')) {\n fireAllMethodsInArray(this.options.onResize, this.eventData('resize'));\n }\n }\n\n // When the StateManager removes a state we want to remove the event listener\n destroy() {\n this.test.removeListener(this.listener);\n }\n\n attachCallback(type, callback, runIfActive) {\n switch (type) {\n case 'enter':\n this.options.onEnter.push(callback);\n break;\n case 'leave':\n this.options.onLeave.push(callback);\n break;\n case 'resize':\n this.options.onResize.push(callback);\n break;\n default:\n break;\n }\n\n if (type === 'enter' && runIfActive && this.active) {\n callback(this.eventData(type));\n }\n }\n\n testConfigOptions(when) {\n let test = true;\n\n configOptions.forEach((configOption) => {\n if (typeof this.options[configOption.name] !== 'undefined') {\n if (configOption.when === when && configOption.test.bind(this)() === false) {\n test = false;\n }\n }\n });\n\n return test;\n }\n\n eventData(eventType) {\n return {\n eventType,\n state: this,\n };\n }\n\n static addConfigOption(configOption) {\n configOptions.push(configOption);\n }\n\n static getConfigOptions() {\n return configOptions;\n }\n\n static removeConfigOption(name) {\n configOptions.forEach((item, index) => {\n if (item.name === name) {\n configOptions.splice(index, 1);\n }\n });\n }\n\n static setStateChangeMethod(func) {\n if (typeof func === 'function') {\n stateChangeMethod = func;\n } else {\n throw new Error('Not a function');\n }\n }\n}\n","import State from './state';\nimport {\n debounce,\n filterStates,\n} from './utils';\n\n// State Manager Constructor\nclass StateManager {\n constructor() {\n this.states = [];\n this.resizeTimer = null;\n this.configOptions = [];\n\n window.addEventListener('resize', debounce(this.resizeBrowser.bind(this), 25), true);\n }\n\n addState(options) {\n const newState = new State(options);\n\n if (newState.valid) {\n this.states.push(newState);\n }\n\n return newState;\n }\n\n addStates(statesArray) {\n statesArray.forEach(state => this.addState(state));\n }\n\n getState(id) {\n const selectedState = this.states.filter(state => state.id === id);\n\n return selectedState[0] || false;\n }\n\n isActive(id) {\n const selectedState = this.getState(id) || {};\n\n return selectedState.active || false;\n }\n\n getStates(idArr) {\n if (typeof (idArr) === 'undefined') {\n return this.states;\n }\n\n return idArr.map(id => this.getState(id));\n }\n\n removeState(id) {\n this.states.forEach((state, index) => {\n if (state.id === id) {\n state.destroy();\n this.states.splice(index, 1);\n }\n });\n }\n\n removeStates(idArray) {\n idArray.forEach(id => this.removeState(id));\n }\n\n removeAllStates() {\n this.states.forEach(state => state.destroy());\n this.states = [];\n }\n\n addConfigOption({\n name = '', // name, this is used to apply to a state\n test = null, // function which will perform the test\n when = 'resize', // resize or match (match will mean that resize will never fire either), or once (which will test once, then delete state if test doesnt pass)\n }) {\n if (name !== '' && test !== null) {\n State.addConfigOption({\n name,\n test,\n when,\n });\n }\n }\n\n removeConfigOption(name) {\n State.removeConfigOption(name);\n }\n\n getConfigOptions(name) {\n const configOptions = State.getConfigOptions();\n\n if (typeof name === 'string') {\n return configOptions.filter(configOption => configOption.name === name);\n }\n\n return configOptions;\n }\n\n resizeBrowser() {\n const activeStates = filterStates(this.states, 'active', true);\n\n activeStates.forEach((state) => {\n state.resizeState();\n });\n }\n\n stateChange(func) {\n State.setStateChangeMethod(func);\n }\n}\n\nexport default new StateManager();\n"],"names":["fireAllMethodsInArray","arr","event","forEach","method","configOptions","stateChangeMethod","State","options","id","Math","random","toString","substr","query","Object","assign","this","onEnter","onLeave","onResize","onFirstRun","testConfigOptions","valid","active","init","test","window","matchMedia","matches","enterState","listener","changed","_this","leaveState","addListener","eventData","removeListener","type","callback","runIfActive","push","when","configOption","_this2","name","bind","eventType","item","index","splice","func","Error","states","resizeTimer","addEventListener","timeout","args","cancelAnimationFrame","requestAnimationFrame","apply","debounce","resizeBrowser","newState","statesArray","addState","state","filter","getState","idArr","map","destroy","idArray","_this4","removeState","addConfigOption","removeConfigOption","getConfigOptions","key","value","resizeState","setStateChangeMethod"],"mappings":"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"}