diff --git a/cssAnimation.js b/cssAnimation.js new file mode 100644 index 0000000..8f94d59 --- /dev/null +++ b/cssAnimation.js @@ -0,0 +1,174 @@ +import Event from './Event'; +const isCssAnimationSupported = Event.endEvents.length !== 0; +import classes from 'component-classes'; + +const capitalPrefixes = ['Webkit', + 'Moz', + 'O', + // ms is special .... ! + 'ms']; +const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', '']; + +function getStyleProperty(node, name) { + const style = window.getComputedStyle(node); + + let ret = ''; + for (let i = 0; i < prefixes.length; i++) { + ret = style.getPropertyValue(prefixes[i] + name); + if (ret) { + break; + } + } + return (ret); +} + +function fixBrowserByTimeout(node) { + if (isCssAnimationSupported) { + const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0; + const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0; + const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0; + const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0; + const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay); + // sometimes, browser bug + node.rcEndAnimTimeout = setTimeout(() => { + node.rcEndAnimTimeout = null; + if (node.rcEndListener) { + node.rcEndListener(); + } + }, (time) * 1000 + 200); + } +} + +function clearBrowserBugTimeout(node) { + if (node.rcEndAnimTimeout) { + clearTimeout(node.rcEndAnimTimeout); + node.rcEndAnimTimeout = null; + } +} + +const cssAnimation = (node, transitionName, endCallback) => { + const nameIsObj = typeof transitionName === 'object'; + const className = nameIsObj ? transitionName.name : transitionName; + const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`; + let end = endCallback; + let start; + let active; + const nodeClasses = classes(node); + + if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') { + end = endCallback.end; + start = endCallback.start; + active = endCallback.active; + } + + if (node.rcEndListener) { + node.rcEndListener(); + } + + node.rcEndListener = (e) => { + if (e && e.target !== node) { + return; + } + + if (node.rcAnimTimeout) { + clearTimeout(node.rcAnimTimeout); + node.rcAnimTimeout = null; + } + + clearBrowserBugTimeout(node); + + nodeClasses.remove(className); + nodeClasses.remove(activeClassName); + + Event.removeEndEventListener(node, node.rcEndListener); + node.rcEndListener = null; + + // Usually this optional end is used for informing an owner of + // a leave animation and telling it to remove the child. + if (end) { + end(); + } + }; + + Event.addEndEventListener(node, node.rcEndListener); + + if (start) { + start(); + } + nodeClasses.add(className); + + node.rcAnimTimeout = setTimeout(() => { + node.rcAnimTimeout = null; + nodeClasses.add(activeClassName); + if (active) { + setTimeout(active, 0); + } + fixBrowserByTimeout(node); + // 30ms for firefox + }, 30); + + return { + stop() { + if (node.rcEndListener) { + node.rcEndListener(); + } + }, + }; +}; + +cssAnimation.style = (node, style, callback) => { + if (node.rcEndListener) { + node.rcEndListener(); + } + + node.rcEndListener = (e) => { + if (e && e.target !== node) { + return; + } + + if (node.rcAnimTimeout) { + clearTimeout(node.rcAnimTimeout); + node.rcAnimTimeout = null; + } + + clearBrowserBugTimeout(node); + + Event.removeEndEventListener(node, node.rcEndListener); + node.rcEndListener = null; + + // Usually this optional callback is used for informing an owner of + // a leave animation and telling it to remove the child. + if (callback) { + callback(); + } + }; + + Event.addEndEventListener(node, node.rcEndListener); + + node.rcAnimTimeout = setTimeout(() => { + for (const s in style) { + if (style.hasOwnProperty(s)) { + node.style[s] = style[s]; + } + } + node.rcAnimTimeout = null; + fixBrowserByTimeout(node); + }, 0); +}; + +cssAnimation.setTransition = (node, p, value) => { + let property = p; + let v = value; + if (value === undefined) { + v = property; + property = ''; + } + property = property || ''; + capitalPrefixes.forEach((prefix) => { + node.style[`${prefix}Transition${property}`] = v; + }); +}; + +cssAnimation.isCssAnimationSupported = isCssAnimationSupported; + +export default cssAnimation; \ No newline at end of file diff --git a/js/Event.js b/js/Event.js new file mode 100644 index 0000000..7d44575 --- /dev/null +++ b/js/Event.js @@ -0,0 +1,81 @@ +const EVENT_NAME_MAP = { + transitionend: { + transition: 'transitionend', + WebkitTransition: 'webkitTransitionEnd', + MozTransition: 'mozTransitionEnd', + OTransition: 'oTransitionEnd', + msTransition: 'MSTransitionEnd', + }, + + animationend: { + animation: 'animationend', + WebkitAnimation: 'webkitAnimationEnd', + MozAnimation: 'mozAnimationEnd', + OAnimation: 'oAnimationEnd', + msAnimation: 'MSAnimationEnd', + }, +}; + +const endEvents = []; + +function detectEvents() { + const testEl = document.createElement('div'); + const style = testEl.style; + + if (!('AnimationEvent' in window)) { + delete EVENT_NAME_MAP.animationend.animation; + } + + if (!('TransitionEvent' in window)) { + delete EVENT_NAME_MAP.transitionend.transition; + } + + for (const baseEventName in EVENT_NAME_MAP) { + if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) { + const baseEvents = EVENT_NAME_MAP[baseEventName]; + for (const styleName in baseEvents) { + if (styleName in style) { + endEvents.push(baseEvents[styleName]); + break; + } + } + } + } +} + +if (typeof window !== 'undefined' && typeof document !== 'undefined') { + detectEvents(); +} + +function addEventListener(node, eventName, eventListener) { + node.addEventListener(eventName, eventListener, false); +} + +function removeEventListener(node, eventName, eventListener) { + node.removeEventListener(eventName, eventListener, false); +} + +const TransitionEvents = { + addEndEventListener(node, eventListener) { + if (endEvents.length === 0) { + window.setTimeout(eventListener, 0); + return; + } + endEvents.forEach((endEvent) => { + addEventListener(node, endEvent, eventListener); + }); + }, + + endEvents, + + removeEndEventListener(node, eventListener) { + if (endEvents.length === 0) { + return; + } + endEvents.forEach((endEvent) => { + removeEventListener(node, endEvent, eventListener); + }); + }, +}; + +export default TransitionEvents; \ No newline at end of file diff --git a/js/addEventListener.js b/js/addEventListener.js new file mode 100644 index 0000000..4a642e0 --- /dev/null +++ b/js/addEventListener.js @@ -0,0 +1,10 @@ +import addDOMEventListener from 'add-dom-event-listener'; +import ReactDOM from 'react-dom'; + +export default function addEventListenerWrap(target, eventType, cb) { + /* eslint camelcase: 2 */ + const callback = ReactDOM.unstable_batchedUpdates ? function run(e) { + ReactDOM.unstable_batchedUpdates(cb, e); + } : cb; + return addDOMEventListener(target, eventType, callback); +} \ No newline at end of file diff --git a/js/contains.js b/js/contains.js new file mode 100644 index 0000000..eff6ae4 --- /dev/null +++ b/js/contains.js @@ -0,0 +1,11 @@ +export default function contains(root, n) { + let node = n; + while (node) { + if (node === root) { + return true; + } + node = node.parentNode; + } + + return false; +} \ No newline at end of file diff --git a/js/cssAnimation.js b/js/cssAnimation.js new file mode 100644 index 0000000..8f94d59 --- /dev/null +++ b/js/cssAnimation.js @@ -0,0 +1,174 @@ +import Event from './Event'; +const isCssAnimationSupported = Event.endEvents.length !== 0; +import classes from 'component-classes'; + +const capitalPrefixes = ['Webkit', + 'Moz', + 'O', + // ms is special .... ! + 'ms']; +const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', '']; + +function getStyleProperty(node, name) { + const style = window.getComputedStyle(node); + + let ret = ''; + for (let i = 0; i < prefixes.length; i++) { + ret = style.getPropertyValue(prefixes[i] + name); + if (ret) { + break; + } + } + return (ret); +} + +function fixBrowserByTimeout(node) { + if (isCssAnimationSupported) { + const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0; + const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0; + const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0; + const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0; + const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay); + // sometimes, browser bug + node.rcEndAnimTimeout = setTimeout(() => { + node.rcEndAnimTimeout = null; + if (node.rcEndListener) { + node.rcEndListener(); + } + }, (time) * 1000 + 200); + } +} + +function clearBrowserBugTimeout(node) { + if (node.rcEndAnimTimeout) { + clearTimeout(node.rcEndAnimTimeout); + node.rcEndAnimTimeout = null; + } +} + +const cssAnimation = (node, transitionName, endCallback) => { + const nameIsObj = typeof transitionName === 'object'; + const className = nameIsObj ? transitionName.name : transitionName; + const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`; + let end = endCallback; + let start; + let active; + const nodeClasses = classes(node); + + if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') { + end = endCallback.end; + start = endCallback.start; + active = endCallback.active; + } + + if (node.rcEndListener) { + node.rcEndListener(); + } + + node.rcEndListener = (e) => { + if (e && e.target !== node) { + return; + } + + if (node.rcAnimTimeout) { + clearTimeout(node.rcAnimTimeout); + node.rcAnimTimeout = null; + } + + clearBrowserBugTimeout(node); + + nodeClasses.remove(className); + nodeClasses.remove(activeClassName); + + Event.removeEndEventListener(node, node.rcEndListener); + node.rcEndListener = null; + + // Usually this optional end is used for informing an owner of + // a leave animation and telling it to remove the child. + if (end) { + end(); + } + }; + + Event.addEndEventListener(node, node.rcEndListener); + + if (start) { + start(); + } + nodeClasses.add(className); + + node.rcAnimTimeout = setTimeout(() => { + node.rcAnimTimeout = null; + nodeClasses.add(activeClassName); + if (active) { + setTimeout(active, 0); + } + fixBrowserByTimeout(node); + // 30ms for firefox + }, 30); + + return { + stop() { + if (node.rcEndListener) { + node.rcEndListener(); + } + }, + }; +}; + +cssAnimation.style = (node, style, callback) => { + if (node.rcEndListener) { + node.rcEndListener(); + } + + node.rcEndListener = (e) => { + if (e && e.target !== node) { + return; + } + + if (node.rcAnimTimeout) { + clearTimeout(node.rcAnimTimeout); + node.rcAnimTimeout = null; + } + + clearBrowserBugTimeout(node); + + Event.removeEndEventListener(node, node.rcEndListener); + node.rcEndListener = null; + + // Usually this optional callback is used for informing an owner of + // a leave animation and telling it to remove the child. + if (callback) { + callback(); + } + }; + + Event.addEndEventListener(node, node.rcEndListener); + + node.rcAnimTimeout = setTimeout(() => { + for (const s in style) { + if (style.hasOwnProperty(s)) { + node.style[s] = style[s]; + } + } + node.rcAnimTimeout = null; + fixBrowserByTimeout(node); + }, 0); +}; + +cssAnimation.setTransition = (node, p, value) => { + let property = p; + let v = value; + if (value === undefined) { + v = property; + property = ''; + } + property = property || ''; + capitalPrefixes.forEach((prefix) => { + node.style[`${prefix}Transition${property}`] = v; + }); +}; + +cssAnimation.isCssAnimationSupported = isCssAnimationSupported; + +export default cssAnimation; \ No newline at end of file diff --git a/js/index.js b/js/index.js index 0799b1f..e003f92 100644 --- a/js/index.js +++ b/js/index.js @@ -5,3 +5,7 @@ export elementType from './elementType'; export isRequiredForA11y from './isRequiredForA11y'; export splitComponent from './splitComponent'; export createChainedFunction from './createChainedFunction'; +export KeyCode from './keyCode'; +export contains from './contains'; +export addEventListener from './addEventListener'; +export cssAnimation from './cssAnimation'; diff --git a/js/keyCode.js b/js/keyCode.js new file mode 100644 index 0000000..d3f44f8 --- /dev/null +++ b/js/keyCode.js @@ -0,0 +1,520 @@ +'use strict'; + +/** + * @ignore + * some key-codes definition and utils from closure-library + * @author yiminghe@gmail.com + */ + +var KeyCode = { + /** + * MAC_ENTER + */ + MAC_ENTER: 3, + /** + * BACKSPACE + */ + BACKSPACE: 8, + /** + * TAB + */ + TAB: 9, + /** + * NUMLOCK on FF/Safari Mac + */ + NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac + /** + * ENTER + */ + ENTER: 13, + /** + * SHIFT + */ + SHIFT: 16, + /** + * CTRL + */ + CTRL: 17, + /** + * ALT + */ + ALT: 18, + /** + * PAUSE + */ + PAUSE: 19, + /** + * CAPS_LOCK + */ + CAPS_LOCK: 20, + /** + * ESC + */ + ESC: 27, + /** + * SPACE + */ + SPACE: 32, + /** + * PAGE_UP + */ + PAGE_UP: 33, // also NUM_NORTH_EAST + /** + * PAGE_DOWN + */ + PAGE_DOWN: 34, // also NUM_SOUTH_EAST + /** + * END + */ + END: 35, // also NUM_SOUTH_WEST + /** + * HOME + */ + HOME: 36, // also NUM_NORTH_WEST + /** + * LEFT + */ + LEFT: 37, // also NUM_WEST + /** + * UP + */ + UP: 38, // also NUM_NORTH + /** + * RIGHT + */ + RIGHT: 39, // also NUM_EAST + /** + * DOWN + */ + DOWN: 40, // also NUM_SOUTH + /** + * PRINT_SCREEN + */ + PRINT_SCREEN: 44, + /** + * INSERT + */ + INSERT: 45, // also NUM_INSERT + /** + * DELETE + */ + DELETE: 46, // also NUM_DELETE + /** + * ZERO + */ + ZERO: 48, + /** + * ONE + */ + ONE: 49, + /** + * TWO + */ + TWO: 50, + /** + * THREE + */ + THREE: 51, + /** + * FOUR + */ + FOUR: 52, + /** + * FIVE + */ + FIVE: 53, + /** + * SIX + */ + SIX: 54, + /** + * SEVEN + */ + SEVEN: 55, + /** + * EIGHT + */ + EIGHT: 56, + /** + * NINE + */ + NINE: 57, + /** + * QUESTION_MARK + */ + QUESTION_MARK: 63, // needs localization + /** + * A + */ + A: 65, + /** + * B + */ + B: 66, + /** + * C + */ + C: 67, + /** + * D + */ + D: 68, + /** + * E + */ + E: 69, + /** + * F + */ + F: 70, + /** + * G + */ + G: 71, + /** + * H + */ + H: 72, + /** + * I + */ + I: 73, + /** + * J + */ + J: 74, + /** + * K + */ + K: 75, + /** + * L + */ + L: 76, + /** + * M + */ + M: 77, + /** + * N + */ + N: 78, + /** + * O + */ + O: 79, + /** + * P + */ + P: 80, + /** + * Q + */ + Q: 81, + /** + * R + */ + R: 82, + /** + * S + */ + S: 83, + /** + * T + */ + T: 84, + /** + * U + */ + U: 85, + /** + * V + */ + V: 86, + /** + * W + */ + W: 87, + /** + * X + */ + X: 88, + /** + * Y + */ + Y: 89, + /** + * Z + */ + Z: 90, + /** + * META + */ + META: 91, // WIN_KEY_LEFT + /** + * WIN_KEY_RIGHT + */ + WIN_KEY_RIGHT: 92, + /** + * CONTEXT_MENU + */ + CONTEXT_MENU: 93, + /** + * NUM_ZERO + */ + NUM_ZERO: 96, + /** + * NUM_ONE + */ + NUM_ONE: 97, + /** + * NUM_TWO + */ + NUM_TWO: 98, + /** + * NUM_THREE + */ + NUM_THREE: 99, + /** + * NUM_FOUR + */ + NUM_FOUR: 100, + /** + * NUM_FIVE + */ + NUM_FIVE: 101, + /** + * NUM_SIX + */ + NUM_SIX: 102, + /** + * NUM_SEVEN + */ + NUM_SEVEN: 103, + /** + * NUM_EIGHT + */ + NUM_EIGHT: 104, + /** + * NUM_NINE + */ + NUM_NINE: 105, + /** + * NUM_MULTIPLY + */ + NUM_MULTIPLY: 106, + /** + * NUM_PLUS + */ + NUM_PLUS: 107, + /** + * NUM_MINUS + */ + NUM_MINUS: 109, + /** + * NUM_PERIOD + */ + NUM_PERIOD: 110, + /** + * NUM_DIVISION + */ + NUM_DIVISION: 111, + /** + * F1 + */ + F1: 112, + /** + * F2 + */ + F2: 113, + /** + * F3 + */ + F3: 114, + /** + * F4 + */ + F4: 115, + /** + * F5 + */ + F5: 116, + /** + * F6 + */ + F6: 117, + /** + * F7 + */ + F7: 118, + /** + * F8 + */ + F8: 119, + /** + * F9 + */ + F9: 120, + /** + * F10 + */ + F10: 121, + /** + * F11 + */ + F11: 122, + /** + * F12 + */ + F12: 123, + /** + * NUMLOCK + */ + NUMLOCK: 144, + /** + * SEMICOLON + */ + SEMICOLON: 186, // needs localization + /** + * DASH + */ + DASH: 189, // needs localization + /** + * EQUALS + */ + EQUALS: 187, // needs localization + /** + * COMMA + */ + COMMA: 188, // needs localization + /** + * PERIOD + */ + PERIOD: 190, // needs localization + /** + * SLASH + */ + SLASH: 191, // needs localization + /** + * APOSTROPHE + */ + APOSTROPHE: 192, // needs localization + /** + * SINGLE_QUOTE + */ + SINGLE_QUOTE: 222, // needs localization + /** + * OPEN_SQUARE_BRACKET + */ + OPEN_SQUARE_BRACKET: 219, // needs localization + /** + * BACKSLASH + */ + BACKSLASH: 220, // needs localization + /** + * CLOSE_SQUARE_BRACKET + */ + CLOSE_SQUARE_BRACKET: 221, // needs localization + /** + * WIN_KEY + */ + WIN_KEY: 224, + /** + * MAC_FF_META + */ + MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91 + /** + * WIN_IME + */ + WIN_IME: 229 +}; + +/* + whether text and modified key is entered at the same time. + */ +KeyCode.isTextModifyingKeyEvent = function isTextModifyingKeyEvent(e) { + var keyCode = e.keyCode; + if (e.altKey && !e.ctrlKey || e.metaKey || + // Function keys don't generate text + keyCode >= KeyCode.F1 && keyCode <= KeyCode.F12) { + return false; + } + + // The following keys are quite harmless, even in combination with + // CTRL, ALT or SHIFT. + switch (keyCode) { + case KeyCode.ALT: + case KeyCode.CAPS_LOCK: + case KeyCode.CONTEXT_MENU: + case KeyCode.CTRL: + case KeyCode.DOWN: + case KeyCode.END: + case KeyCode.ESC: + case KeyCode.HOME: + case KeyCode.INSERT: + case KeyCode.LEFT: + case KeyCode.MAC_FF_META: + case KeyCode.META: + case KeyCode.NUMLOCK: + case KeyCode.NUM_CENTER: + case KeyCode.PAGE_DOWN: + case KeyCode.PAGE_UP: + case KeyCode.PAUSE: + case KeyCode.PRINT_SCREEN: + case KeyCode.RIGHT: + case KeyCode.SHIFT: + case KeyCode.UP: + case KeyCode.WIN_KEY: + case KeyCode.WIN_KEY_RIGHT: + return false; + default: + return true; + } +}; + +/* + whether character is entered. + */ +KeyCode.isCharacterKey = function isCharacterKey(keyCode) { + if (keyCode >= KeyCode.ZERO && keyCode <= KeyCode.NINE) { + return true; + } + + if (keyCode >= KeyCode.NUM_ZERO && keyCode <= KeyCode.NUM_MULTIPLY) { + return true; + } + + if (keyCode >= KeyCode.A && keyCode <= KeyCode.Z) { + return true; + } + + // Safari sends zero key code for non-latin characters. + if (window.navigation.userAgent.indexOf('WebKit') !== -1 && keyCode === 0) { + return true; + } + + switch (keyCode) { + case KeyCode.SPACE: + case KeyCode.QUESTION_MARK: + case KeyCode.NUM_PLUS: + case KeyCode.NUM_MINUS: + case KeyCode.NUM_PERIOD: + case KeyCode.NUM_DIVISION: + case KeyCode.SEMICOLON: + case KeyCode.DASH: + case KeyCode.EQUALS: + case KeyCode.COMMA: + case KeyCode.PERIOD: + case KeyCode.SLASH: + case KeyCode.APOSTROPHE: + case KeyCode.SINGLE_QUOTE: + case KeyCode.OPEN_SQUARE_BRACKET: + case KeyCode.BACKSLASH: + case KeyCode.CLOSE_SQUARE_BRACKET: + return true; + default: + return false; + } +}; + +module.exports = KeyCode; \ No newline at end of file diff --git a/lib/Event.js b/lib/Event.js new file mode 100644 index 0000000..06c007f --- /dev/null +++ b/lib/Event.js @@ -0,0 +1,85 @@ +'use strict'; + +exports.__esModule = true; +var EVENT_NAME_MAP = { + transitionend: { + transition: 'transitionend', + WebkitTransition: 'webkitTransitionEnd', + MozTransition: 'mozTransitionEnd', + OTransition: 'oTransitionEnd', + msTransition: 'MSTransitionEnd' + }, + + animationend: { + animation: 'animationend', + WebkitAnimation: 'webkitAnimationEnd', + MozAnimation: 'mozAnimationEnd', + OAnimation: 'oAnimationEnd', + msAnimation: 'MSAnimationEnd' + } +}; + +var endEvents = []; + +function detectEvents() { + var testEl = document.createElement('div'); + var style = testEl.style; + + if (!('AnimationEvent' in window)) { + delete EVENT_NAME_MAP.animationend.animation; + } + + if (!('TransitionEvent' in window)) { + delete EVENT_NAME_MAP.transitionend.transition; + } + + for (var baseEventName in EVENT_NAME_MAP) { + if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) { + var baseEvents = EVENT_NAME_MAP[baseEventName]; + for (var styleName in baseEvents) { + if (styleName in style) { + endEvents.push(baseEvents[styleName]); + break; + } + } + } + } +} + +if (typeof window !== 'undefined' && typeof document !== 'undefined') { + detectEvents(); +} + +function addEventListener(node, eventName, eventListener) { + node.addEventListener(eventName, eventListener, false); +} + +function removeEventListener(node, eventName, eventListener) { + node.removeEventListener(eventName, eventListener, false); +} + +var TransitionEvents = { + addEndEventListener: function addEndEventListener(node, eventListener) { + if (endEvents.length === 0) { + window.setTimeout(eventListener, 0); + return; + } + endEvents.forEach(function (endEvent) { + addEventListener(node, endEvent, eventListener); + }); + }, + + + endEvents: endEvents, + + removeEndEventListener: function removeEndEventListener(node, eventListener) { + if (endEvents.length === 0) { + return; + } + endEvents.forEach(function (endEvent) { + removeEventListener(node, endEvent, eventListener); + }); + } +}; + +exports.default = TransitionEvents; \ No newline at end of file diff --git a/lib/addEventListener.js b/lib/addEventListener.js new file mode 100644 index 0000000..706f795 --- /dev/null +++ b/lib/addEventListener.js @@ -0,0 +1,22 @@ +'use strict'; + +exports.__esModule = true; +exports.default = addEventListenerWrap; + +var _addDomEventListener = require('add-dom-event-listener'); + +var _addDomEventListener2 = _interopRequireDefault(_addDomEventListener); + +var _reactDom = require('react-dom'); + +var _reactDom2 = _interopRequireDefault(_reactDom); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function addEventListenerWrap(target, eventType, cb) { + /* eslint camelcase: 2 */ + var callback = _reactDom2.default.unstable_batchedUpdates ? function run(e) { + _reactDom2.default.unstable_batchedUpdates(cb, e); + } : cb; + return (0, _addDomEventListener2.default)(target, eventType, callback); +} \ No newline at end of file diff --git a/lib/contains.js b/lib/contains.js new file mode 100644 index 0000000..73d59b6 --- /dev/null +++ b/lib/contains.js @@ -0,0 +1,15 @@ +"use strict"; + +exports.__esModule = true; +exports.default = contains; +function contains(root, n) { + var node = n; + while (node) { + if (node === root) { + return true; + } + node = node.parentNode; + } + + return false; +} \ No newline at end of file diff --git a/lib/cssAnimation.js b/lib/cssAnimation.js new file mode 100644 index 0000000..ea54ec6 --- /dev/null +++ b/lib/cssAnimation.js @@ -0,0 +1,187 @@ +'use strict'; + +exports.__esModule = true; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _Event = require('./Event'); + +var _Event2 = _interopRequireDefault(_Event); + +var _componentClasses = require('component-classes'); + +var _componentClasses2 = _interopRequireDefault(_componentClasses); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var isCssAnimationSupported = _Event2.default.endEvents.length !== 0; + + +var capitalPrefixes = ['Webkit', 'Moz', 'O', +// ms is special .... ! +'ms']; +var prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', '']; + +function getStyleProperty(node, name) { + var style = window.getComputedStyle(node); + + var ret = ''; + for (var i = 0; i < prefixes.length; i++) { + ret = style.getPropertyValue(prefixes[i] + name); + if (ret) { + break; + } + } + return ret; +} + +function fixBrowserByTimeout(node) { + if (isCssAnimationSupported) { + var transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0; + var transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0; + var animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0; + var animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0; + var time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay); + // sometimes, browser bug + node.rcEndAnimTimeout = setTimeout(function () { + node.rcEndAnimTimeout = null; + if (node.rcEndListener) { + node.rcEndListener(); + } + }, time * 1000 + 200); + } +} + +function clearBrowserBugTimeout(node) { + if (node.rcEndAnimTimeout) { + clearTimeout(node.rcEndAnimTimeout); + node.rcEndAnimTimeout = null; + } +} + +var cssAnimation = function cssAnimation(node, transitionName, endCallback) { + var nameIsObj = (typeof transitionName === 'undefined' ? 'undefined' : _typeof(transitionName)) === 'object'; + var className = nameIsObj ? transitionName.name : transitionName; + var activeClassName = nameIsObj ? transitionName.active : transitionName + '-active'; + var end = endCallback; + var start = void 0; + var active = void 0; + var nodeClasses = (0, _componentClasses2.default)(node); + + if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') { + end = endCallback.end; + start = endCallback.start; + active = endCallback.active; + } + + if (node.rcEndListener) { + node.rcEndListener(); + } + + node.rcEndListener = function (e) { + if (e && e.target !== node) { + return; + } + + if (node.rcAnimTimeout) { + clearTimeout(node.rcAnimTimeout); + node.rcAnimTimeout = null; + } + + clearBrowserBugTimeout(node); + + nodeClasses.remove(className); + nodeClasses.remove(activeClassName); + + _Event2.default.removeEndEventListener(node, node.rcEndListener); + node.rcEndListener = null; + + // Usually this optional end is used for informing an owner of + // a leave animation and telling it to remove the child. + if (end) { + end(); + } + }; + + _Event2.default.addEndEventListener(node, node.rcEndListener); + + if (start) { + start(); + } + nodeClasses.add(className); + + node.rcAnimTimeout = setTimeout(function () { + node.rcAnimTimeout = null; + nodeClasses.add(activeClassName); + if (active) { + setTimeout(active, 0); + } + fixBrowserByTimeout(node); + // 30ms for firefox + }, 30); + + return { + stop: function stop() { + if (node.rcEndListener) { + node.rcEndListener(); + } + } + }; +}; + +cssAnimation.style = function (node, style, callback) { + if (node.rcEndListener) { + node.rcEndListener(); + } + + node.rcEndListener = function (e) { + if (e && e.target !== node) { + return; + } + + if (node.rcAnimTimeout) { + clearTimeout(node.rcAnimTimeout); + node.rcAnimTimeout = null; + } + + clearBrowserBugTimeout(node); + + _Event2.default.removeEndEventListener(node, node.rcEndListener); + node.rcEndListener = null; + + // Usually this optional callback is used for informing an owner of + // a leave animation and telling it to remove the child. + if (callback) { + callback(); + } + }; + + _Event2.default.addEndEventListener(node, node.rcEndListener); + + node.rcAnimTimeout = setTimeout(function () { + for (var s in style) { + if (style.hasOwnProperty(s)) { + node.style[s] = style[s]; + } + } + node.rcAnimTimeout = null; + fixBrowserByTimeout(node); + }, 0); +}; + +cssAnimation.setTransition = function (node, p, value) { + var property = p; + var v = value; + if (value === undefined) { + v = property; + property = ''; + } + property = property || ''; + capitalPrefixes.forEach(function (prefix) { + node.style[prefix + 'Transition' + property] = v; + }); +}; + +cssAnimation.isCssAnimationSupported = isCssAnimationSupported; + +exports.default = cssAnimation; \ No newline at end of file diff --git a/lib/index.js b/lib/index.js index 3c01702..8f2225c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,7 +1,7 @@ 'use strict'; exports.__esModule = true; -exports.createChainedFunction = exports.splitComponent = exports.isRequiredForA11y = exports.elementType = exports.deprecated = exports.componentOrElement = exports.all = undefined; +exports.cssAnimation = exports.addEventListener = exports.contains = exports.KeyCode = exports.createChainedFunction = exports.splitComponent = exports.isRequiredForA11y = exports.elementType = exports.deprecated = exports.componentOrElement = exports.all = undefined; var _all2 = require('./all'); @@ -31,6 +31,22 @@ var _createChainedFunction2 = require('./createChainedFunction'); var _createChainedFunction3 = _interopRequireDefault(_createChainedFunction2); +var _keyCode = require('./keyCode'); + +var _keyCode2 = _interopRequireDefault(_keyCode); + +var _contains2 = require('./contains'); + +var _contains3 = _interopRequireDefault(_contains2); + +var _addEventListener2 = require('./addEventListener'); + +var _addEventListener3 = _interopRequireDefault(_addEventListener2); + +var _cssAnimation2 = require('./cssAnimation'); + +var _cssAnimation3 = _interopRequireDefault(_cssAnimation2); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.all = _all3.default; @@ -39,4 +55,8 @@ exports.deprecated = _deprecated3.default; exports.elementType = _elementType3.default; exports.isRequiredForA11y = _isRequiredForA11y3.default; exports.splitComponent = _splitComponent3.default; -exports.createChainedFunction = _createChainedFunction3.default; \ No newline at end of file +exports.createChainedFunction = _createChainedFunction3.default; +exports.KeyCode = _keyCode2.default; +exports.contains = _contains3.default; +exports.addEventListener = _addEventListener3.default; +exports.cssAnimation = _cssAnimation3.default; \ No newline at end of file diff --git a/lib/keyCode.js b/lib/keyCode.js new file mode 100644 index 0000000..d3f44f8 --- /dev/null +++ b/lib/keyCode.js @@ -0,0 +1,520 @@ +'use strict'; + +/** + * @ignore + * some key-codes definition and utils from closure-library + * @author yiminghe@gmail.com + */ + +var KeyCode = { + /** + * MAC_ENTER + */ + MAC_ENTER: 3, + /** + * BACKSPACE + */ + BACKSPACE: 8, + /** + * TAB + */ + TAB: 9, + /** + * NUMLOCK on FF/Safari Mac + */ + NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac + /** + * ENTER + */ + ENTER: 13, + /** + * SHIFT + */ + SHIFT: 16, + /** + * CTRL + */ + CTRL: 17, + /** + * ALT + */ + ALT: 18, + /** + * PAUSE + */ + PAUSE: 19, + /** + * CAPS_LOCK + */ + CAPS_LOCK: 20, + /** + * ESC + */ + ESC: 27, + /** + * SPACE + */ + SPACE: 32, + /** + * PAGE_UP + */ + PAGE_UP: 33, // also NUM_NORTH_EAST + /** + * PAGE_DOWN + */ + PAGE_DOWN: 34, // also NUM_SOUTH_EAST + /** + * END + */ + END: 35, // also NUM_SOUTH_WEST + /** + * HOME + */ + HOME: 36, // also NUM_NORTH_WEST + /** + * LEFT + */ + LEFT: 37, // also NUM_WEST + /** + * UP + */ + UP: 38, // also NUM_NORTH + /** + * RIGHT + */ + RIGHT: 39, // also NUM_EAST + /** + * DOWN + */ + DOWN: 40, // also NUM_SOUTH + /** + * PRINT_SCREEN + */ + PRINT_SCREEN: 44, + /** + * INSERT + */ + INSERT: 45, // also NUM_INSERT + /** + * DELETE + */ + DELETE: 46, // also NUM_DELETE + /** + * ZERO + */ + ZERO: 48, + /** + * ONE + */ + ONE: 49, + /** + * TWO + */ + TWO: 50, + /** + * THREE + */ + THREE: 51, + /** + * FOUR + */ + FOUR: 52, + /** + * FIVE + */ + FIVE: 53, + /** + * SIX + */ + SIX: 54, + /** + * SEVEN + */ + SEVEN: 55, + /** + * EIGHT + */ + EIGHT: 56, + /** + * NINE + */ + NINE: 57, + /** + * QUESTION_MARK + */ + QUESTION_MARK: 63, // needs localization + /** + * A + */ + A: 65, + /** + * B + */ + B: 66, + /** + * C + */ + C: 67, + /** + * D + */ + D: 68, + /** + * E + */ + E: 69, + /** + * F + */ + F: 70, + /** + * G + */ + G: 71, + /** + * H + */ + H: 72, + /** + * I + */ + I: 73, + /** + * J + */ + J: 74, + /** + * K + */ + K: 75, + /** + * L + */ + L: 76, + /** + * M + */ + M: 77, + /** + * N + */ + N: 78, + /** + * O + */ + O: 79, + /** + * P + */ + P: 80, + /** + * Q + */ + Q: 81, + /** + * R + */ + R: 82, + /** + * S + */ + S: 83, + /** + * T + */ + T: 84, + /** + * U + */ + U: 85, + /** + * V + */ + V: 86, + /** + * W + */ + W: 87, + /** + * X + */ + X: 88, + /** + * Y + */ + Y: 89, + /** + * Z + */ + Z: 90, + /** + * META + */ + META: 91, // WIN_KEY_LEFT + /** + * WIN_KEY_RIGHT + */ + WIN_KEY_RIGHT: 92, + /** + * CONTEXT_MENU + */ + CONTEXT_MENU: 93, + /** + * NUM_ZERO + */ + NUM_ZERO: 96, + /** + * NUM_ONE + */ + NUM_ONE: 97, + /** + * NUM_TWO + */ + NUM_TWO: 98, + /** + * NUM_THREE + */ + NUM_THREE: 99, + /** + * NUM_FOUR + */ + NUM_FOUR: 100, + /** + * NUM_FIVE + */ + NUM_FIVE: 101, + /** + * NUM_SIX + */ + NUM_SIX: 102, + /** + * NUM_SEVEN + */ + NUM_SEVEN: 103, + /** + * NUM_EIGHT + */ + NUM_EIGHT: 104, + /** + * NUM_NINE + */ + NUM_NINE: 105, + /** + * NUM_MULTIPLY + */ + NUM_MULTIPLY: 106, + /** + * NUM_PLUS + */ + NUM_PLUS: 107, + /** + * NUM_MINUS + */ + NUM_MINUS: 109, + /** + * NUM_PERIOD + */ + NUM_PERIOD: 110, + /** + * NUM_DIVISION + */ + NUM_DIVISION: 111, + /** + * F1 + */ + F1: 112, + /** + * F2 + */ + F2: 113, + /** + * F3 + */ + F3: 114, + /** + * F4 + */ + F4: 115, + /** + * F5 + */ + F5: 116, + /** + * F6 + */ + F6: 117, + /** + * F7 + */ + F7: 118, + /** + * F8 + */ + F8: 119, + /** + * F9 + */ + F9: 120, + /** + * F10 + */ + F10: 121, + /** + * F11 + */ + F11: 122, + /** + * F12 + */ + F12: 123, + /** + * NUMLOCK + */ + NUMLOCK: 144, + /** + * SEMICOLON + */ + SEMICOLON: 186, // needs localization + /** + * DASH + */ + DASH: 189, // needs localization + /** + * EQUALS + */ + EQUALS: 187, // needs localization + /** + * COMMA + */ + COMMA: 188, // needs localization + /** + * PERIOD + */ + PERIOD: 190, // needs localization + /** + * SLASH + */ + SLASH: 191, // needs localization + /** + * APOSTROPHE + */ + APOSTROPHE: 192, // needs localization + /** + * SINGLE_QUOTE + */ + SINGLE_QUOTE: 222, // needs localization + /** + * OPEN_SQUARE_BRACKET + */ + OPEN_SQUARE_BRACKET: 219, // needs localization + /** + * BACKSLASH + */ + BACKSLASH: 220, // needs localization + /** + * CLOSE_SQUARE_BRACKET + */ + CLOSE_SQUARE_BRACKET: 221, // needs localization + /** + * WIN_KEY + */ + WIN_KEY: 224, + /** + * MAC_FF_META + */ + MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91 + /** + * WIN_IME + */ + WIN_IME: 229 +}; + +/* + whether text and modified key is entered at the same time. + */ +KeyCode.isTextModifyingKeyEvent = function isTextModifyingKeyEvent(e) { + var keyCode = e.keyCode; + if (e.altKey && !e.ctrlKey || e.metaKey || + // Function keys don't generate text + keyCode >= KeyCode.F1 && keyCode <= KeyCode.F12) { + return false; + } + + // The following keys are quite harmless, even in combination with + // CTRL, ALT or SHIFT. + switch (keyCode) { + case KeyCode.ALT: + case KeyCode.CAPS_LOCK: + case KeyCode.CONTEXT_MENU: + case KeyCode.CTRL: + case KeyCode.DOWN: + case KeyCode.END: + case KeyCode.ESC: + case KeyCode.HOME: + case KeyCode.INSERT: + case KeyCode.LEFT: + case KeyCode.MAC_FF_META: + case KeyCode.META: + case KeyCode.NUMLOCK: + case KeyCode.NUM_CENTER: + case KeyCode.PAGE_DOWN: + case KeyCode.PAGE_UP: + case KeyCode.PAUSE: + case KeyCode.PRINT_SCREEN: + case KeyCode.RIGHT: + case KeyCode.SHIFT: + case KeyCode.UP: + case KeyCode.WIN_KEY: + case KeyCode.WIN_KEY_RIGHT: + return false; + default: + return true; + } +}; + +/* + whether character is entered. + */ +KeyCode.isCharacterKey = function isCharacterKey(keyCode) { + if (keyCode >= KeyCode.ZERO && keyCode <= KeyCode.NINE) { + return true; + } + + if (keyCode >= KeyCode.NUM_ZERO && keyCode <= KeyCode.NUM_MULTIPLY) { + return true; + } + + if (keyCode >= KeyCode.A && keyCode <= KeyCode.Z) { + return true; + } + + // Safari sends zero key code for non-latin characters. + if (window.navigation.userAgent.indexOf('WebKit') !== -1 && keyCode === 0) { + return true; + } + + switch (keyCode) { + case KeyCode.SPACE: + case KeyCode.QUESTION_MARK: + case KeyCode.NUM_PLUS: + case KeyCode.NUM_MINUS: + case KeyCode.NUM_PERIOD: + case KeyCode.NUM_DIVISION: + case KeyCode.SEMICOLON: + case KeyCode.DASH: + case KeyCode.EQUALS: + case KeyCode.COMMA: + case KeyCode.PERIOD: + case KeyCode.SLASH: + case KeyCode.APOSTROPHE: + case KeyCode.SINGLE_QUOTE: + case KeyCode.OPEN_SQUARE_BRACKET: + case KeyCode.BACKSLASH: + case KeyCode.CLOSE_SQUARE_BRACKET: + return true; + default: + return false; + } +}; + +module.exports = KeyCode; \ No newline at end of file diff --git a/package.json b/package.json index b3c9723..1d3d1bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tinper-bee-core", - "version": "0.0.9", + "version": "0.0.10", "description": "style core and js util for tinper-bee", "main": "lib/index.js", "engines": { @@ -16,6 +16,8 @@ }, "license": "MIT", "dependencies": { + "add-dom-event-listener": "^1.0.1", + "component-classes": "^1.2.6", "warning": "^3.0.0" }, "devDependencies": {