reakit-utils
Advanced tools
Comparing version 0.7.3 to 0.8.0
@@ -6,2 +6,21 @@ # Change Log | ||
# [0.8.0](https://github.com/reakit/reakit/tree/master/packages/reakit-utils/compare/reakit-utils@0.7.3...reakit-utils@0.8.0) (2020-02-05) | ||
### Features | ||
* **reakit-utils:** Add `getActiveElement` method ([a252fcd](https://github.com/reakit/reakit/tree/master/packages/reakit-utils/commit/a252fcd)) | ||
* **reakit-utils:** Add `isButton` method ([8ff86fc](https://github.com/reakit/reakit/tree/master/packages/reakit-utils/commit/8ff86fc)) | ||
* **reakit-utils:** Add `isPlainObject` function ([faeb26f](https://github.com/reakit/reakit/tree/master/packages/reakit-utils/commit/faeb26f)) | ||
* **reakit-utils:** Remove `Omit` type ([24797e0](https://github.com/reakit/reakit/tree/master/packages/reakit-utils/commit/24797e0)) | ||
### BREAKING CHANGES | ||
* **reakit-utils:** `Omit` has been removed from `reakit-utils/types`. [TypeScript now supports it natively](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittk). | ||
## [0.7.3](https://github.com/reakit/reakit/tree/master/packages/reakit-utils/compare/reakit-utils@0.7.2...reakit-utils@0.7.3) (2019-12-18) | ||
@@ -8,0 +27,0 @@ |
@@ -1,1 +0,1 @@ | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e=e||self).ReakitUtils={},e.React)}(this,function(e,n){"use strict";function t(e,n){return"matches"in e?e.matches(n):"msMatchesSelector"in e?e.msMatchesSelector(n):e.webkitMatchesSelector(n)}function r(e,n){if("closest"in e)return e.closest(n);do{if(t(e,n))return e;e=e.parentElement||e.parentNode}while(null!==e&&1===e.nodeType);return null}function o(e){return e?e.ownerDocument||e:window.document}function u(e){return"object"==typeof e&&null!=e}function i(e,n){return-1===n?e:[].concat(e.slice(0,n),e.slice(n+1))}var a="input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], iframe, object, embed, area[href], audio[controls], video[controls], [contenteditable]:not([contenteditable='false'])";function c(e){return e.matches(a)&&function(e){return e.offsetWidth>0||e.offsetHeight>0||e.getClientRects().length>0}(e)}function f(e){return c(e)&&!function(e){return parseInt(e.getAttribute("tabIndex")||"0",10)<0}(e)}function l(e){var n=Array.from(e.querySelectorAll(a));return n.unshift(e),n.filter(c)}function s(e,n){var t=Array.from(e.querySelectorAll(a)),r=t.filter(f);return f(e)&&r.unshift(e),!r.length&&n?t:r}function d(e){return(e.ownerDocument||document).activeElement===e}var v="id-",b=n.createContext(function(e){return void 0===e&&(e=v),""+e+Math.random().toString(32).substr(2,6)});e.IdProvider=function(e){var t=e.children,r=e.unstable_prefix,o=void 0===r?"":r,u=n.useRef(0),i=n.useMemo(function(){return function(e){return void 0===e&&(e=v),""+o+e+ ++u.current}},[o]);return n.createElement(b.Provider,{value:i},t)},e.closest=r,e.createOnKeyDown=function(e){var n=void 0===e?{}:e,t=n.keyMap,r=n.onKey,o=n.stopPropagation,u=n.onKeyDown,i=n.shouldKeyDown,a=void 0===i?function(){return!0}:i,c=n.preventDefault,f=void 0===c||c;return function(e){if(t){var n="function"==typeof t?t(e):t,i="function"==typeof f?f(e):f,c="function"==typeof o?o(e):o;if(e.key in n){var l=n[e.key];if("function"==typeof l&&a(e))return i&&e.preventDefault(),c&&e.stopPropagation(),r&&r(e),void l(e)}u&&u(e)}}},e.cx=function(){for(var e=arguments.length,n=new Array(e),t=0;t<e;t++)n[t]=arguments[t];return n.filter(Boolean).join(" ")||void 0},e.ensureFocus=function(e,n){var t=void 0===n?{}:n,r=t.isActive,o=void 0===r?d:r,u=t.preventScroll;return o(e)?-1:(e.focus({preventScroll:u}),o(e)?-1:requestAnimationFrame(function(){e.focus({preventScroll:u})}))},e.getAllFocusableIn=l,e.getAllTabbableIn=s,e.getClosestFocusable=function(e){var n=null;do{n=r(e,a)}while(n&&!c(n));return n},e.getDocument=o,e.getFirstFocusableIn=function(e){var n=l(e);return n.length?n[0]:null},e.getFirstTabbableIn=function(e,n){return s(e,n)[0]||null},e.getLastTabbableIn=function(e,n){var t=s(e,n);return t[t.length-1]||null},e.getNextTabbableIn=function(e,n){var t=(e.ownerDocument||document).activeElement,r=l(e),o=r.indexOf(t),u=r.slice(o+1);return u.find(f)||r.find(f)||(n?u[0]:null)},e.getPreviousTabbableIn=function(e,n){var t=(e.ownerDocument||document).activeElement,r=l(e).reverse(),o=r.indexOf(t),u=r.slice(o+1);return u.find(f)||r.find(f)||(n?u[0]:null)},e.hasFocusWithin=function(e){var n=o(e);return!!n.activeElement&&e.contains(n.activeElement)},e.isEmpty=function(e){return Array.isArray(e)?!e.length:u(e)?!Object.keys(e).length:null==e||""===e},e.isFocusable=c,e.isInteger=function(e){return"number"==typeof e?Math.floor(e)===e:String(Math.floor(Number(e)))===e},e.isObject=u,e.isPromise=function(e){return Boolean(e&&e.then)},e.isTabbable=f,e.mergeRefs=function(){for(var e=arguments.length,n=new Array(e),t=0;t<e;t++)n[t]=arguments[t];var r=n.filter(Boolean);return r.length?1===r.length?r[0]:function(e){var n=r,t=Array.isArray(n),o=0;for(n=t?n:n[Symbol.iterator]();;){var u;if(t){if(o>=n.length)break;u=n[o++]}else{if((o=n.next()).done)break;u=o.value}var i=u;"function"==typeof i?i(e):i&&(i.current=e)}}:null},e.omit=function(e,n){for(var t=Object.keys(e),r={},o=0;o<t.length;o+=1){var u=t[o];-1===n.indexOf(u)&&(r[u]=e[u])}return r},e.pick=function(e,n){for(var t=Object.keys(e),r={},o=0;o<t.length;o+=1){var u=t[o];n.indexOf(u)>=0&&(r[u]=e[u])}return r},e.removeIndexFromArray=i,e.removeItemFromArray=function(e,n){var t=e.indexOf(n);return i(e,t)},e.splitProps=function(e,n){for(var t={},r={},o=0,u=Object.keys(e);o<u.length;o++){var i=u[o];n.indexOf(i)>=0?t[i]=e[i]:r[i]=e[i]}return[t,r]},e.toArray=function(e){return Array.isArray(e)?e:void 0!==e?[e]:[]},e.useAllCallbacks=function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return n.useCallback(function(){var e=t.filter(Boolean),n=e,r=Array.isArray(n),o=0;for(n=r?n:n[Symbol.iterator]();;){var u;if(r){if(o>=n.length)break;u=n[o++]}else{if((o=n.next()).done)break;u=o.value}var i=u;i.apply(void 0,arguments)}},t)},e.useId=function(e){void 0===e&&(e=v);var t=n.useContext(b);return n.useState(function(){return t(e)})[0]},e.useLiveRef=function(e){var t=n.useRef(e);return n.useEffect(function(){t.current=e}),t},e.usePipe=function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];return n.useCallback(function(e){return t.filter(Boolean).reduce(function(e,n){return n(e)},e)},t)},e.useSealedState=function(e){return n.useState(e)[0]},e.useUpdateEffect=function(e,t){var r=n.useRef(!1);n.useEffect(function(){if(r.current)return e();r.current=!0},t)},e.warning=function(e){},Object.defineProperty(e,"__esModule",{value:!0})}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e=e||self).ReakitUtils={},e.React)}(this,(function(e,t){"use strict";function n(e,t){return"matches"in e?e.matches(t):"msMatchesSelector"in e?e.msMatchesSelector(t):e.webkitMatchesSelector(t)}function r(e,t){if("closest"in e)return e.closest(t);do{if(n(e,t))return e;e=e.parentElement||e.parentNode}while(null!==e&&1===e.nodeType);return null}function o(e){return e?e.ownerDocument||e:window.document}var i=["button","color","file","image","reset","submit"];function u(e){return"object"==typeof e&&null!=e}function a(e,t){return-1===t?e:[].concat(e.slice(0,t),e.slice(t+1))}function f(e){return o(e).activeElement}var c="input:not([type='hidden']):not([disabled]), select:not([disabled]), textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], iframe, object, embed, area[href], audio[controls], video[controls], [contenteditable]:not([contenteditable='false'])";function l(e){return e.matches(c)&&function(e){return e.offsetWidth>0||e.offsetHeight>0||e.getClientRects().length>0}(e)}function s(e){return l(e)&&!function(e){return parseInt(e.getAttribute("tabIndex")||"0",10)<0}(e)}function v(e){var t=Array.from(e.querySelectorAll(c));return t.unshift(e),t.filter(l)}function d(e,t){var n=Array.from(e.querySelectorAll(c)),r=n.filter(s);return s(e)&&r.unshift(e),!r.length&&t?n:r}function b(e){return f(e)===e}var y=t.createContext((function(e){return void 0===e&&(e="id-"),""+e+Math.random().toString(32).substr(2,6)}));e.IdProvider=function(e){var n=e.children,r=e.unstable_prefix,o=void 0===r?"":r,i=t.useRef(0),u=t.useMemo((function(){return function(e){return void 0===e&&(e="id-"),""+o+e+ ++i.current}}),[o]);return t.createElement(y.Provider,{value:u},n)},e.closest=r,e.createOnKeyDown=function(e){var t=void 0===e?{}:e,n=t.keyMap,r=t.onKey,o=t.stopPropagation,i=t.onKeyDown,u=t.shouldKeyDown,a=void 0===u?function(){return!0}:u,f=t.preventDefault,c=void 0===f||f;return function(e){if(n){var t="function"==typeof n?n(e):n,u="function"==typeof c?c(e):c,f="function"==typeof o?o(e):o;if(e.key in t){var l=t[e.key];if("function"==typeof l&&a(e))return u&&e.preventDefault(),f&&e.stopPropagation(),r&&r(e),void l(e)}i&&i(e)}}},e.cx=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.filter(Boolean).join(" ")||void 0},e.ensureFocus=function(e,t){var n=void 0===t?{}:t,r=n.isActive,o=void 0===r?b:r,i=n.preventScroll;return o(e)?-1:(e.focus({preventScroll:i}),o(e)?-1:requestAnimationFrame((function(){e.focus({preventScroll:i})})))},e.getAllFocusableIn=v,e.getAllTabbableIn=d,e.getClosestFocusable=function(e){var t=null;do{t=r(e,c)}while(t&&!l(t));return t},e.getDocument=o,e.getFirstFocusableIn=function(e){var t=v(e);return t.length?t[0]:null},e.getFirstTabbableIn=function(e,t){return d(e,t)[0]||null},e.getLastTabbableIn=function(e,t){var n=d(e,t);return n[n.length-1]||null},e.getNextTabbableIn=function(e,t){var n=f(e),r=v(e),o=r.indexOf(n),i=r.slice(o+1);return i.find(s)||r.find(s)||(t?i[0]:null)},e.getPreviousTabbableIn=function(e,t){var n=f(e),r=v(e).reverse(),o=r.indexOf(n),i=r.slice(o+1);return i.find(s)||r.find(s)||(t?i[0]:null)},e.hasFocusWithin=function(e){var t=o(e);return!!t.activeElement&&e.contains(t.activeElement)},e.isButton=function(e){if("BUTTON"===e.tagName)return!0;if("INPUT"===e.tagName){var t=e;return-1!==i.indexOf(t.type)}return!1},e.isEmpty=function(e){return Array.isArray(e)?!e.length:u(e)?!Object.keys(e).length:null==e||""===e},e.isFocusable=l,e.isInteger=function(e){return"number"==typeof e?Math.floor(e)===e:String(Math.floor(Number(e)))===e},e.isObject=u,e.isPlainObject=function(e){var t;if(!u(e))return!1;var n=Object.getPrototypeOf(e);return null==n||(null===(t=n.constructor)||void 0===t?void 0:t.toString())===Object.toString()},e.isPromise=function(e){return Boolean(e&&e.then)},e.isTabbable=s,e.mergeRefs=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];var r=t.filter(Boolean);return r.length?1===r.length?r[0]:function(e){var t=r,n=Array.isArray(t),o=0;for(t=n?t:t[Symbol.iterator]();;){var i;if(n){if(o>=t.length)break;i=t[o++]}else{if((o=t.next()).done)break;i=o.value}var u=i;"function"==typeof u?u(e):u&&(u.current=e)}}:null},e.omit=function(e,t){for(var n=Object.keys(e),r={},o=0;o<n.length;o+=1){var i=n[o];-1===t.indexOf(i)&&(r[i]=e[i])}return r},e.pick=function(e,t){for(var n=Object.keys(e),r={},o=0;o<n.length;o+=1){var i=n[o];t.indexOf(i)>=0&&(r[i]=e[i])}return r},e.removeIndexFromArray=a,e.removeItemFromArray=function(e,t){var n=e.indexOf(t);return a(e,n)},e.splitProps=function(e,t){for(var n={},r={},o=0,i=Object.keys(e);o<i.length;o++){var u=i[o];t.indexOf(u)>=0?n[u]=e[u]:r[u]=e[u]}return[n,r]},e.toArray=function(e){return Array.isArray(e)?e:void 0!==e?[e]:[]},e.useAllCallbacks=function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];return t.useCallback((function(){var e=n.filter(Boolean),t=e,r=Array.isArray(t),o=0;for(t=r?t:t[Symbol.iterator]();;){var i;if(r){if(o>=t.length)break;i=t[o++]}else{if((o=t.next()).done)break;i=o.value}var u=i;u.apply(void 0,arguments)}}),n)},e.useId=function(e){void 0===e&&(e="id-");var n=t.useContext(y);return t.useState((function(){return n(e)}))[0]},e.useLiveRef=function(e){var n=t.useRef(e);return t.useEffect((function(){n.current=e})),n},e.usePipe=function(){for(var e=arguments.length,n=new Array(e),r=0;r<e;r++)n[r]=arguments[r];return t.useCallback((function(e){return n.filter(Boolean).reduce((function(e,t){return t(e)}),e)}),n)},e.useSealedState=function(e){return t.useState(e)[0]},e.useUpdateEffect=function(e,n){var r=t.useRef(!1);t.useEffect((function(){if(r.current)return e();r.current=!0}),n)},e.warning=function(e){},Object.defineProperty(e,"__esModule",{value:!0})})); |
@@ -1,2 +0,1 @@ | ||
// closest ponyfill | ||
function matches(element, selectors) { | ||
@@ -8,2 +7,12 @@ if ("matches" in element) return element.matches(selectors); | ||
/** | ||
* Ponyfill for `Element.prototype.closest` | ||
* | ||
* @example | ||
* import { closest } from "reakit-utils"; | ||
* | ||
* closest(document.getElementById("id"), "div"); | ||
* // same as | ||
* document.getElementById("id").closest("div"); | ||
*/ | ||
function closest(element, selectors) { | ||
@@ -10,0 +19,0 @@ if ("closest" in element) return element.closest(selectors); |
@@ -0,1 +1,6 @@ | ||
/** | ||
* Returns an `onKeyDown` handler to be passed to a component. | ||
* | ||
* @param options | ||
*/ | ||
function createOnKeyDown(_temp) { | ||
@@ -2,0 +7,0 @@ var _ref = _temp === void 0 ? {} : _temp, |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Returns a string with truthy class names separated by space. | ||
* | ||
* @example | ||
* import { cx } from "reakit-utils"; | ||
* | ||
* const className = cx("a", "b", false, true && "c"); | ||
*/ | ||
function cx() { | ||
@@ -2,0 +10,0 @@ for (var _len = arguments.length, classes = new Array(_len), _key = 0; _key < _len; _key++) { |
@@ -0,1 +1,4 @@ | ||
/** | ||
* Returns `element.ownerDocument || window.document`. | ||
*/ | ||
function getDocument(element) { | ||
@@ -2,0 +5,0 @@ return element ? element.ownerDocument || element : window.document; |
import { getDocument } from './getDocument.js'; | ||
/** | ||
* Checks if `element` has focus. | ||
* | ||
* @example | ||
* import { hasFocusWithin } from "reakit-utils"; | ||
* | ||
* hasFocusWithin(document.getElementById("id")); | ||
*/ | ||
function hasFocusWithin(element) { | ||
@@ -4,0 +13,0 @@ var document = getDocument(element); |
@@ -11,2 +11,4 @@ export { warning } from './warning.js'; | ||
export { closest } from './closest.js'; | ||
export { getDocument } from './getDocument.js'; | ||
import './getActiveElement.js'; | ||
export { ensureFocus, getAllFocusableIn, getAllTabbableIn, getClosestFocusable, getFirstFocusableIn, getFirstTabbableIn, getLastTabbableIn, getNextTabbableIn, getPreviousTabbableIn, isFocusable, isTabbable } from './tabbable.js'; | ||
@@ -21,7 +23,8 @@ export { splitProps } from './splitProps.js'; | ||
export { isObject } from './isObject.js'; | ||
export { isPlainObject } from './isPlainObject.js'; | ||
export { isInteger } from './isInteger.js'; | ||
export { isEmpty } from './isEmpty.js'; | ||
export { isButton } from './isButton.js'; | ||
export { createOnKeyDown } from './createOnKeyDown.js'; | ||
export { cx } from './cx.js'; | ||
export { getDocument } from './getDocument.js'; | ||
export { hasFocusWithin } from './hasFocusWithin.js'; |
import { isObject } from './isObject.js'; | ||
/** | ||
* Checks whether `arg` is empty or not. | ||
* | ||
* @example | ||
* import { isEmpty } from "reakit-utils"; | ||
* | ||
* isEmpty([]); // true | ||
* isEmpty(["a"]); // false | ||
* isEmpty({}); // true | ||
* isEmpty({ a: "a" }); // false | ||
* isEmpty(); // true | ||
* isEmpty(null); // true | ||
* isEmpty(undefined); // true | ||
* isEmpty(""); // true | ||
*/ | ||
function isEmpty(arg) { | ||
@@ -4,0 +20,0 @@ if (Array.isArray(arg)) return !arg.length; |
@@ -1,9 +0,20 @@ | ||
function isInteger(obj) { | ||
if (typeof obj === "number") { | ||
return Math.floor(obj) === obj; | ||
/** | ||
* Checks whether `arg` is an integer or not. | ||
* | ||
* @example | ||
* import { isInteger } from "reakit-utils"; | ||
* | ||
* isInteger(1); // true | ||
* isInteger(1.5); // false | ||
* isInteger("1"); // true | ||
* isInteger("1.5"); // false | ||
*/ | ||
function isInteger(arg) { | ||
if (typeof arg === "number") { | ||
return Math.floor(arg) === arg; | ||
} | ||
return String(Math.floor(Number(obj))) === obj; | ||
return String(Math.floor(Number(arg))) === arg; | ||
} | ||
export { isInteger }; |
@@ -0,1 +1,6 @@ | ||
/** | ||
* Checks whether `arg` is an object or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
function isObject(arg) { | ||
@@ -2,0 +7,0 @@ return typeof arg === "object" && arg != null; |
@@ -0,1 +1,6 @@ | ||
/** | ||
* Checks whether `arg` is a promise or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
function isPromise(arg) { | ||
@@ -2,0 +7,0 @@ return Boolean(arg && arg.then); |
@@ -0,1 +1,14 @@ | ||
/** | ||
* Merges multiple React ref props into a single value that can be passed to | ||
* a component. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { mergeRefs } from "reakit-utils"; | ||
* | ||
* const Component = React.forwardRef((props, ref) => { | ||
* const internalRef = React.useRef(); | ||
* return <div ref={mergeRefs(internalRef, ref)} {...props} />; | ||
* }); | ||
*/ | ||
function mergeRefs() { | ||
@@ -2,0 +15,0 @@ for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) { |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Omits specific keys from an object. | ||
* | ||
* @example | ||
* import { omit } from "reakit-utils"; | ||
* | ||
* omit({ a: "a", b: "b" }, ["a"]); // { b: "b" } | ||
*/ | ||
function omit(object, paths) { | ||
@@ -2,0 +10,0 @@ var keys = Object.keys(object); |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Picks specific keys from an object. | ||
* | ||
* @example | ||
* import { pick } from "reakit-utils"; | ||
* | ||
* pick({ a: "a", b: "b" }, ["a"]); // { a: "a" } | ||
*/ | ||
function pick(object, paths) { | ||
@@ -2,0 +10,0 @@ var keys = Object.keys(object); |
@@ -0,1 +1,11 @@ | ||
/** | ||
* Immutably removes an index from an array. | ||
* | ||
* @example | ||
* import { removeIndexFromArray } from "reakit-utils"; | ||
* | ||
* removeIndexFromArray(["a", "b", "c"], 1); // ["a", "c"] | ||
* | ||
* @returns {Array} A new array without the item in the passed index. | ||
*/ | ||
function removeIndexFromArray(array, idx) { | ||
@@ -2,0 +12,0 @@ if (idx === -1) return array; |
import { removeIndexFromArray } from './removeIndexFromArray.js'; | ||
/** | ||
* Immutably removes an item from an array. | ||
* | ||
* @example | ||
* import { removeItemFromArray } from "reakit-utils"; | ||
* | ||
* removeItemFromArray(["a", "b", "c"], "b"); // ["a", "c"] | ||
* | ||
* // This only works by reference | ||
* const obj = {}; | ||
* removeItemFromArray([obj], {}); // [obj] | ||
* removeItemFromArray([obj], obj); // [] | ||
* | ||
* @returns {Array} A new array without the passed item. | ||
*/ | ||
function removeItemFromArray(array, item) { | ||
@@ -4,0 +20,0 @@ var idx = array.indexOf(item); |
@@ -0,1 +1,11 @@ | ||
/** | ||
* Splits an object (`props`) into a tuple where the first item is an object | ||
* with the passed `keys`, and the second item is an object with these keys | ||
* omitted. | ||
* | ||
* @example | ||
* import { splitProps } from "reakit-utils"; | ||
* | ||
* splitProps({ a: "a", b: "b" }, ["a"]); // [{ a: "a" }, { b: "b" }] | ||
*/ | ||
function splitProps(props, keys) { | ||
@@ -2,0 +12,0 @@ var propsKeys = Object.keys(props); |
import { closest } from './closest.js'; | ||
import './getDocument.js'; | ||
import { getActiveElement } from './getActiveElement.js'; | ||
/** @module tabbable */ | ||
var selector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), " + "textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], " + "iframe, object, embed, area[href], audio[controls], video[controls], " + "[contenteditable]:not([contenteditable='false'])"; | ||
@@ -13,9 +16,47 @@ | ||
} | ||
/** | ||
* Checks whether `element` is focusable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isFocusable } from "reakit-utils"; | ||
* | ||
* isFocusable(document.querySelector("input")); // true | ||
* isFocusable(document.querySelector("input[tabindex='-1']")); // true | ||
* isFocusable(document.querySelector("input[hidden]")); // false | ||
* isFocusable(document.querySelector("input:disabled")); // false | ||
*/ | ||
function isFocusable(element) { | ||
return element.matches(selector) && isVisible(element); | ||
} | ||
/** | ||
* Checks whether `element` is tabbable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isTabbable } from "reakit-utils"; | ||
* | ||
* isTabbable(document.querySelector("input")); // true | ||
* isTabbable(document.querySelector("input[tabindex='-1']")); // false | ||
* isTabbable(document.querySelector("input[hidden]")); // false | ||
* isTabbable(document.querySelector("input:disabled")); // false | ||
*/ | ||
function isTabbable(element) { | ||
return isFocusable(element) && !hasNegativeTabIndex(element); | ||
} | ||
/** | ||
* Returns all the focusable elements in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
function getAllFocusableIn(container) { | ||
@@ -26,2 +67,12 @@ var allFocusable = Array.from(container.querySelectorAll(selector)); | ||
} | ||
/** | ||
* Returns the first focusable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getFirstFocusableIn(container) { | ||
@@ -31,2 +82,14 @@ var allFocusable = getAllFocusableIn(container); | ||
} | ||
/** | ||
* Returns all the tabbable elements in `container`, including the container | ||
* itself. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return focusable elements if there are no tabbable ones. | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
function getAllTabbableIn(container, fallbackToFocusable) { | ||
@@ -46,2 +109,14 @@ var allFocusable = Array.from(container.querySelectorAll(selector)); | ||
} | ||
/** | ||
* Returns the first tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the first focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getFirstTabbableIn(container, fallbackToFocusable) { | ||
@@ -53,2 +128,14 @@ var _getAllTabbableIn = getAllTabbableIn(container, fallbackToFocusable), | ||
} | ||
/** | ||
* Returns the last tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the last focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getLastTabbableIn(container, fallbackToFocusable) { | ||
@@ -58,6 +145,15 @@ var allTabbable = getAllTabbableIn(container, fallbackToFocusable); | ||
} | ||
/** | ||
* Returns the next tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the next focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getNextTabbableIn(container, fallbackToFocusable) { | ||
var _ref = container.ownerDocument || document, | ||
activeElement = _ref.activeElement; | ||
var activeElement = getActiveElement(container); | ||
var allFocusable = getAllFocusableIn(container); | ||
@@ -68,6 +164,15 @@ var index = allFocusable.indexOf(activeElement); | ||
} | ||
/** | ||
* Returns the previous tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the previous focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getPreviousTabbableIn(container, fallbackToFocusable) { | ||
var _ref2 = container.ownerDocument || document, | ||
activeElement = _ref2.activeElement; | ||
var activeElement = getActiveElement(container); | ||
var allFocusable = getAllFocusableIn(container).reverse(); | ||
@@ -78,2 +183,12 @@ var index = allFocusable.indexOf(activeElement); | ||
} | ||
/** | ||
* Returns the closest focusable parent of `element`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getClosestFocusable(element) { | ||
@@ -90,13 +205,33 @@ var container = null; | ||
function defaultIsActive(element) { | ||
var _ref3 = element.ownerDocument || document, | ||
activeElement = _ref3.activeElement; | ||
return activeElement === element; | ||
return getActiveElement(element) === element; | ||
} | ||
/** | ||
* Ensures `element` will receive focus if it's not already. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { ensureFocus } from "reakit-utils"; | ||
* | ||
* ensureFocus(document.activeElement); // does nothing | ||
* | ||
* const element = document.querySelector("input"); | ||
* | ||
* ensureFocus(element); // focuses element | ||
* ensureFocus(element, { preventScroll: true }); // focuses element preventing scroll jump | ||
* | ||
* function isActive(el) { | ||
* return el.dataset.active === "true"; | ||
* } | ||
* | ||
* ensureFocus(document.querySelector("[data-active='true']"), { isActive }); // does nothing | ||
* | ||
* @returns {number} `requestAnimationFrame` call ID so it can be passed to `cancelAnimationFrame` if needed. | ||
*/ | ||
function ensureFocus(element, _temp) { | ||
var _ref4 = _temp === void 0 ? {} : _temp, | ||
_ref4$isActive = _ref4.isActive, | ||
isActive = _ref4$isActive === void 0 ? defaultIsActive : _ref4$isActive, | ||
preventScroll = _ref4.preventScroll; | ||
var _ref = _temp === void 0 ? {} : _temp, | ||
_ref$isActive = _ref.isActive, | ||
isActive = _ref$isActive === void 0 ? defaultIsActive : _ref$isActive, | ||
preventScroll = _ref.preventScroll; | ||
@@ -103,0 +238,0 @@ if (isActive(element)) return -1; |
@@ -0,1 +1,10 @@ | ||
/** | ||
* Transforms `arg` into an array if it's not already. | ||
* | ||
* @example | ||
* import { toArray } from "reakit-utils"; | ||
* | ||
* toArray("a"); // ["a"] | ||
* toArray(["a"]); // ["a"] | ||
*/ | ||
function toArray(arg) { | ||
@@ -2,0 +11,0 @@ if (Array.isArray(arg)) { |
import { useCallback } from 'react'; | ||
/** | ||
* React custom hook that combines multiple callbacks into one. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { useAllCallbacks } from "reakit-utils"; | ||
* | ||
* function Component(props) { | ||
* const onClick = () => {}; | ||
* return ( | ||
* <button onClick={useAllCallbacks(onClick, props.onClick)}>Button</button> | ||
* ); | ||
* } | ||
*/ | ||
function useAllCallbacks() { | ||
@@ -4,0 +18,0 @@ for (var _len = arguments.length, callbacks = new Array(_len), _key = 0; _key < _len; _key++) { |
import { useEffect, useLayoutEffect } from 'react'; | ||
/** | ||
* `React.useLayoutEffect` that fallbacks to `React.useEffect` on server side | ||
* rendering. | ||
*/ | ||
var useIsomorphicEffect = typeof window === "undefined" ? useEffect : useLayoutEffect; | ||
export { useIsomorphicEffect }; |
import { useRef, useEffect } from 'react'; | ||
/** | ||
* A `React.Ref` that keeps track of the passed `value`. | ||
*/ | ||
function useLiveRef(value) { | ||
@@ -4,0 +8,0 @@ var ref = useRef(value); |
import { useCallback } from 'react'; | ||
/** | ||
* A React custom hook similar to [`useAllCallbacks`](#useallcallbacks), but | ||
* it'll pass the returned value from a function to the next function. | ||
*/ | ||
function usePipe() { | ||
@@ -4,0 +8,0 @@ for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { |
import { useState } from 'react'; | ||
/** | ||
* React custom hook that returns the very first value passed to `initialState`, | ||
* even if it changes between re-renders. | ||
*/ | ||
function useSealedState(initialState) { | ||
@@ -4,0 +8,0 @@ var _React$useState = useState(initialState), |
import { useRef, useEffect } from 'react'; | ||
// https://github.com/reach/reach-ui/blob/34e52b029ba8330fa705804e6b71048267c46283/packages/tabs/src/index.js#L267-L276 | ||
/** | ||
* A `React.useEffect` that will not run on the first render. | ||
*/ | ||
function useUpdateEffect(effect, deps) { | ||
@@ -5,0 +8,0 @@ var mounted = useRef(false); |
@@ -0,1 +1,10 @@ | ||
/** | ||
* Logs `messages` to the console using `console.warn` based on a `condition`. | ||
* | ||
* @example | ||
* import { warning } from "reakit-utils"; | ||
* | ||
* warning(true, "a", "b"); // console.warn("a\nb") | ||
* warning(false, "a", "b"); // does nothing | ||
*/ | ||
function warning(condition) { | ||
@@ -2,0 +11,0 @@ if (process.env.NODE_ENV !== "production") { |
@@ -5,3 +5,2 @@ 'use strict'; | ||
// closest ponyfill | ||
function matches(element, selectors) { | ||
@@ -13,2 +12,12 @@ if ("matches" in element) return element.matches(selectors); | ||
/** | ||
* Ponyfill for `Element.prototype.closest` | ||
* | ||
* @example | ||
* import { closest } from "reakit-utils"; | ||
* | ||
* closest(document.getElementById("id"), "div"); | ||
* // same as | ||
* document.getElementById("id").closest("div"); | ||
*/ | ||
function closest(element, selectors) { | ||
@@ -15,0 +24,0 @@ if ("closest" in element) return element.closest(selectors); |
@@ -5,2 +5,7 @@ 'use strict'; | ||
/** | ||
* Returns an `onKeyDown` handler to be passed to a component. | ||
* | ||
* @param options | ||
*/ | ||
function createOnKeyDown(_temp) { | ||
@@ -7,0 +12,0 @@ var _ref = _temp === void 0 ? {} : _temp, |
@@ -5,2 +5,10 @@ 'use strict'; | ||
/** | ||
* Returns a string with truthy class names separated by space. | ||
* | ||
* @example | ||
* import { cx } from "reakit-utils"; | ||
* | ||
* const className = cx("a", "b", false, true && "c"); | ||
*/ | ||
function cx() { | ||
@@ -7,0 +15,0 @@ for (var _len = arguments.length, classes = new Array(_len), _key = 0; _key < _len; _key++) { |
@@ -5,2 +5,5 @@ 'use strict'; | ||
/** | ||
* Returns `element.ownerDocument || window.document`. | ||
*/ | ||
function getDocument(element) { | ||
@@ -7,0 +10,0 @@ return element ? element.ownerDocument || element : window.document; |
@@ -7,2 +7,11 @@ 'use strict'; | ||
/** | ||
* Checks if `element` has focus. | ||
* | ||
* @example | ||
* import { hasFocusWithin } from "reakit-utils"; | ||
* | ||
* hasFocusWithin(document.getElementById("id")); | ||
*/ | ||
function hasFocusWithin(element) { | ||
@@ -9,0 +18,0 @@ var document = getDocument.getDocument(element); |
@@ -15,2 +15,4 @@ 'use strict'; | ||
var closest = require('./closest.js'); | ||
var getDocument = require('./getDocument.js'); | ||
require('./getActiveElement.js'); | ||
var tabbable = require('./tabbable.js'); | ||
@@ -25,7 +27,8 @@ var splitProps = require('./splitProps.js'); | ||
var isObject = require('./isObject.js'); | ||
var isPlainObject = require('./isPlainObject.js'); | ||
var isInteger = require('./isInteger.js'); | ||
var isEmpty = require('./isEmpty.js'); | ||
var isButton = require('./isButton.js'); | ||
var createOnKeyDown = require('./createOnKeyDown.js'); | ||
var cx = require('./cx.js'); | ||
var getDocument = require('./getDocument.js'); | ||
var hasFocusWithin = require('./hasFocusWithin.js'); | ||
@@ -45,2 +48,3 @@ | ||
exports.closest = closest.closest; | ||
exports.getDocument = getDocument.getDocument; | ||
exports.ensureFocus = tabbable.ensureFocus; | ||
@@ -65,7 +69,8 @@ exports.getAllFocusableIn = tabbable.getAllFocusableIn; | ||
exports.isObject = isObject.isObject; | ||
exports.isPlainObject = isPlainObject.isPlainObject; | ||
exports.isInteger = isInteger.isInteger; | ||
exports.isEmpty = isEmpty.isEmpty; | ||
exports.isButton = isButton.isButton; | ||
exports.createOnKeyDown = createOnKeyDown.createOnKeyDown; | ||
exports.cx = cx.cx; | ||
exports.getDocument = getDocument.getDocument; | ||
exports.hasFocusWithin = hasFocusWithin.hasFocusWithin; |
@@ -7,2 +7,18 @@ 'use strict'; | ||
/** | ||
* Checks whether `arg` is empty or not. | ||
* | ||
* @example | ||
* import { isEmpty } from "reakit-utils"; | ||
* | ||
* isEmpty([]); // true | ||
* isEmpty(["a"]); // false | ||
* isEmpty({}); // true | ||
* isEmpty({ a: "a" }); // false | ||
* isEmpty(); // true | ||
* isEmpty(null); // true | ||
* isEmpty(undefined); // true | ||
* isEmpty(""); // true | ||
*/ | ||
function isEmpty(arg) { | ||
@@ -9,0 +25,0 @@ if (Array.isArray(arg)) return !arg.length; |
@@ -5,10 +5,21 @@ 'use strict'; | ||
function isInteger(obj) { | ||
if (typeof obj === "number") { | ||
return Math.floor(obj) === obj; | ||
/** | ||
* Checks whether `arg` is an integer or not. | ||
* | ||
* @example | ||
* import { isInteger } from "reakit-utils"; | ||
* | ||
* isInteger(1); // true | ||
* isInteger(1.5); // false | ||
* isInteger("1"); // true | ||
* isInteger("1.5"); // false | ||
*/ | ||
function isInteger(arg) { | ||
if (typeof arg === "number") { | ||
return Math.floor(arg) === arg; | ||
} | ||
return String(Math.floor(Number(obj))) === obj; | ||
return String(Math.floor(Number(arg))) === arg; | ||
} | ||
exports.isInteger = isInteger; |
@@ -5,2 +5,7 @@ 'use strict'; | ||
/** | ||
* Checks whether `arg` is an object or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
function isObject(arg) { | ||
@@ -7,0 +12,0 @@ return typeof arg === "object" && arg != null; |
@@ -5,2 +5,7 @@ 'use strict'; | ||
/** | ||
* Checks whether `arg` is a promise or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
function isPromise(arg) { | ||
@@ -7,0 +12,0 @@ return Boolean(arg && arg.then); |
@@ -5,2 +5,15 @@ 'use strict'; | ||
/** | ||
* Merges multiple React ref props into a single value that can be passed to | ||
* a component. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { mergeRefs } from "reakit-utils"; | ||
* | ||
* const Component = React.forwardRef((props, ref) => { | ||
* const internalRef = React.useRef(); | ||
* return <div ref={mergeRefs(internalRef, ref)} {...props} />; | ||
* }); | ||
*/ | ||
function mergeRefs() { | ||
@@ -7,0 +20,0 @@ for (var _len = arguments.length, refs = new Array(_len), _key = 0; _key < _len; _key++) { |
@@ -5,2 +5,10 @@ 'use strict'; | ||
/** | ||
* Omits specific keys from an object. | ||
* | ||
* @example | ||
* import { omit } from "reakit-utils"; | ||
* | ||
* omit({ a: "a", b: "b" }, ["a"]); // { b: "b" } | ||
*/ | ||
function omit(object, paths) { | ||
@@ -7,0 +15,0 @@ var keys = Object.keys(object); |
@@ -5,2 +5,10 @@ 'use strict'; | ||
/** | ||
* Picks specific keys from an object. | ||
* | ||
* @example | ||
* import { pick } from "reakit-utils"; | ||
* | ||
* pick({ a: "a", b: "b" }, ["a"]); // { a: "a" } | ||
*/ | ||
function pick(object, paths) { | ||
@@ -7,0 +15,0 @@ var keys = Object.keys(object); |
@@ -5,2 +5,12 @@ 'use strict'; | ||
/** | ||
* Immutably removes an index from an array. | ||
* | ||
* @example | ||
* import { removeIndexFromArray } from "reakit-utils"; | ||
* | ||
* removeIndexFromArray(["a", "b", "c"], 1); // ["a", "c"] | ||
* | ||
* @returns {Array} A new array without the item in the passed index. | ||
*/ | ||
function removeIndexFromArray(array, idx) { | ||
@@ -7,0 +17,0 @@ if (idx === -1) return array; |
@@ -7,2 +7,18 @@ 'use strict'; | ||
/** | ||
* Immutably removes an item from an array. | ||
* | ||
* @example | ||
* import { removeItemFromArray } from "reakit-utils"; | ||
* | ||
* removeItemFromArray(["a", "b", "c"], "b"); // ["a", "c"] | ||
* | ||
* // This only works by reference | ||
* const obj = {}; | ||
* removeItemFromArray([obj], {}); // [obj] | ||
* removeItemFromArray([obj], obj); // [] | ||
* | ||
* @returns {Array} A new array without the passed item. | ||
*/ | ||
function removeItemFromArray(array, item) { | ||
@@ -9,0 +25,0 @@ var idx = array.indexOf(item); |
@@ -5,2 +5,12 @@ 'use strict'; | ||
/** | ||
* Splits an object (`props`) into a tuple where the first item is an object | ||
* with the passed `keys`, and the second item is an object with these keys | ||
* omitted. | ||
* | ||
* @example | ||
* import { splitProps } from "reakit-utils"; | ||
* | ||
* splitProps({ a: "a", b: "b" }, ["a"]); // [{ a: "a" }, { b: "b" }] | ||
*/ | ||
function splitProps(props, keys) { | ||
@@ -7,0 +17,0 @@ var propsKeys = Object.keys(props); |
@@ -6,3 +6,6 @@ 'use strict'; | ||
var closest = require('./closest.js'); | ||
require('./getDocument.js'); | ||
var getActiveElement = require('./getActiveElement.js'); | ||
/** @module tabbable */ | ||
var selector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), " + "textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], " + "iframe, object, embed, area[href], audio[controls], video[controls], " + "[contenteditable]:not([contenteditable='false'])"; | ||
@@ -18,9 +21,47 @@ | ||
} | ||
/** | ||
* Checks whether `element` is focusable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isFocusable } from "reakit-utils"; | ||
* | ||
* isFocusable(document.querySelector("input")); // true | ||
* isFocusable(document.querySelector("input[tabindex='-1']")); // true | ||
* isFocusable(document.querySelector("input[hidden]")); // false | ||
* isFocusable(document.querySelector("input:disabled")); // false | ||
*/ | ||
function isFocusable(element) { | ||
return element.matches(selector) && isVisible(element); | ||
} | ||
/** | ||
* Checks whether `element` is tabbable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isTabbable } from "reakit-utils"; | ||
* | ||
* isTabbable(document.querySelector("input")); // true | ||
* isTabbable(document.querySelector("input[tabindex='-1']")); // false | ||
* isTabbable(document.querySelector("input[hidden]")); // false | ||
* isTabbable(document.querySelector("input:disabled")); // false | ||
*/ | ||
function isTabbable(element) { | ||
return isFocusable(element) && !hasNegativeTabIndex(element); | ||
} | ||
/** | ||
* Returns all the focusable elements in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
function getAllFocusableIn(container) { | ||
@@ -31,2 +72,12 @@ var allFocusable = Array.from(container.querySelectorAll(selector)); | ||
} | ||
/** | ||
* Returns the first focusable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getFirstFocusableIn(container) { | ||
@@ -36,2 +87,14 @@ var allFocusable = getAllFocusableIn(container); | ||
} | ||
/** | ||
* Returns all the tabbable elements in `container`, including the container | ||
* itself. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return focusable elements if there are no tabbable ones. | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
function getAllTabbableIn(container, fallbackToFocusable) { | ||
@@ -51,2 +114,14 @@ var allFocusable = Array.from(container.querySelectorAll(selector)); | ||
} | ||
/** | ||
* Returns the first tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the first focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getFirstTabbableIn(container, fallbackToFocusable) { | ||
@@ -58,2 +133,14 @@ var _getAllTabbableIn = getAllTabbableIn(container, fallbackToFocusable), | ||
} | ||
/** | ||
* Returns the last tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the last focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getLastTabbableIn(container, fallbackToFocusable) { | ||
@@ -63,6 +150,15 @@ var allTabbable = getAllTabbableIn(container, fallbackToFocusable); | ||
} | ||
/** | ||
* Returns the next tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the next focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getNextTabbableIn(container, fallbackToFocusable) { | ||
var _ref = container.ownerDocument || document, | ||
activeElement = _ref.activeElement; | ||
var activeElement = getActiveElement.getActiveElement(container); | ||
var allFocusable = getAllFocusableIn(container); | ||
@@ -73,6 +169,15 @@ var index = allFocusable.indexOf(activeElement); | ||
} | ||
/** | ||
* Returns the previous tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the previous focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getPreviousTabbableIn(container, fallbackToFocusable) { | ||
var _ref2 = container.ownerDocument || document, | ||
activeElement = _ref2.activeElement; | ||
var activeElement = getActiveElement.getActiveElement(container); | ||
var allFocusable = getAllFocusableIn(container).reverse(); | ||
@@ -83,2 +188,12 @@ var index = allFocusable.indexOf(activeElement); | ||
} | ||
/** | ||
* Returns the closest focusable parent of `element`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
function getClosestFocusable(element) { | ||
@@ -95,13 +210,33 @@ var container = null; | ||
function defaultIsActive(element) { | ||
var _ref3 = element.ownerDocument || document, | ||
activeElement = _ref3.activeElement; | ||
return activeElement === element; | ||
return getActiveElement.getActiveElement(element) === element; | ||
} | ||
/** | ||
* Ensures `element` will receive focus if it's not already. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { ensureFocus } from "reakit-utils"; | ||
* | ||
* ensureFocus(document.activeElement); // does nothing | ||
* | ||
* const element = document.querySelector("input"); | ||
* | ||
* ensureFocus(element); // focuses element | ||
* ensureFocus(element, { preventScroll: true }); // focuses element preventing scroll jump | ||
* | ||
* function isActive(el) { | ||
* return el.dataset.active === "true"; | ||
* } | ||
* | ||
* ensureFocus(document.querySelector("[data-active='true']"), { isActive }); // does nothing | ||
* | ||
* @returns {number} `requestAnimationFrame` call ID so it can be passed to `cancelAnimationFrame` if needed. | ||
*/ | ||
function ensureFocus(element, _temp) { | ||
var _ref4 = _temp === void 0 ? {} : _temp, | ||
_ref4$isActive = _ref4.isActive, | ||
isActive = _ref4$isActive === void 0 ? defaultIsActive : _ref4$isActive, | ||
preventScroll = _ref4.preventScroll; | ||
var _ref = _temp === void 0 ? {} : _temp, | ||
_ref$isActive = _ref.isActive, | ||
isActive = _ref$isActive === void 0 ? defaultIsActive : _ref$isActive, | ||
preventScroll = _ref.preventScroll; | ||
@@ -108,0 +243,0 @@ if (isActive(element)) return -1; |
@@ -5,2 +5,11 @@ 'use strict'; | ||
/** | ||
* Transforms `arg` into an array if it's not already. | ||
* | ||
* @example | ||
* import { toArray } from "reakit-utils"; | ||
* | ||
* toArray("a"); // ["a"] | ||
* toArray(["a"]); // ["a"] | ||
*/ | ||
function toArray(arg) { | ||
@@ -7,0 +16,0 @@ if (Array.isArray(arg)) { |
@@ -7,2 +7,16 @@ 'use strict'; | ||
/** | ||
* React custom hook that combines multiple callbacks into one. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { useAllCallbacks } from "reakit-utils"; | ||
* | ||
* function Component(props) { | ||
* const onClick = () => {}; | ||
* return ( | ||
* <button onClick={useAllCallbacks(onClick, props.onClick)}>Button</button> | ||
* ); | ||
* } | ||
*/ | ||
function useAllCallbacks() { | ||
@@ -9,0 +23,0 @@ for (var _len = arguments.length, callbacks = new Array(_len), _key = 0; _key < _len; _key++) { |
@@ -7,4 +7,9 @@ 'use strict'; | ||
/** | ||
* `React.useLayoutEffect` that fallbacks to `React.useEffect` on server side | ||
* rendering. | ||
*/ | ||
var useIsomorphicEffect = typeof window === "undefined" ? React.useEffect : React.useLayoutEffect; | ||
exports.useIsomorphicEffect = useIsomorphicEffect; |
@@ -7,2 +7,6 @@ 'use strict'; | ||
/** | ||
* A `React.Ref` that keeps track of the passed `value`. | ||
*/ | ||
function useLiveRef(value) { | ||
@@ -9,0 +13,0 @@ var ref = React.useRef(value); |
@@ -7,2 +7,6 @@ 'use strict'; | ||
/** | ||
* A React custom hook similar to [`useAllCallbacks`](#useallcallbacks), but | ||
* it'll pass the returned value from a function to the next function. | ||
*/ | ||
function usePipe() { | ||
@@ -9,0 +13,0 @@ for (var _len = arguments.length, fns = new Array(_len), _key = 0; _key < _len; _key++) { |
@@ -7,2 +7,6 @@ 'use strict'; | ||
/** | ||
* React custom hook that returns the very first value passed to `initialState`, | ||
* even if it changes between re-renders. | ||
*/ | ||
function useSealedState(initialState) { | ||
@@ -9,0 +13,0 @@ var _React$useState = React.useState(initialState), |
@@ -7,3 +7,6 @@ 'use strict'; | ||
// https://github.com/reach/reach-ui/blob/34e52b029ba8330fa705804e6b71048267c46283/packages/tabs/src/index.js#L267-L276 | ||
/** | ||
* A `React.useEffect` that will not run on the first render. | ||
*/ | ||
function useUpdateEffect(effect, deps) { | ||
@@ -10,0 +13,0 @@ var mounted = React.useRef(false); |
@@ -5,2 +5,11 @@ 'use strict'; | ||
/** | ||
* Logs `messages` to the console using `console.warn` based on a `condition`. | ||
* | ||
* @example | ||
* import { warning } from "reakit-utils"; | ||
* | ||
* warning(true, "a", "b"); // console.warn("a\nb") | ||
* warning(false, "a", "b"); // does nothing | ||
*/ | ||
function warning(condition) { | ||
@@ -7,0 +16,0 @@ if (process.env.NODE_ENV !== "production") { |
{ | ||
"name": "reakit-utils", | ||
"version": "0.7.3", | ||
"version": "0.8.0", | ||
"description": "Reakit utils", | ||
@@ -24,4 +24,4 @@ "sideEffects": false, | ||
"build": "../../scripts/build/build.js", | ||
"docs": "../../scripts/build/docs.js", | ||
"preversion": "yarn lint && yarn test && yarn build", | ||
"docs": "documentation readme src --section=API --parse-extension ts", | ||
"preversion": "yarn lint && yarn test && yarn docs && yarn build", | ||
"postpublish": "yarn clean" | ||
@@ -38,3 +38,3 @@ }, | ||
}, | ||
"gitHead": "63114a85bbd57ab969763d5d7755969ea2d25c85" | ||
"gitHead": "fe9685838d8dbc746122bbfff6b8630b7d4d6b9e" | ||
} |
760
README.md
@@ -10,2 +10,3 @@ # reakit-utils | ||
npm: | ||
```sh | ||
@@ -16,2 +17,3 @@ npm i reakit-utils | ||
Yarn: | ||
```sh | ||
@@ -21,4 +23,762 @@ yarn add reakit-utils | ||
## API | ||
<!-- Generated by documentation.js. Update this documentation by updating the source code. --> | ||
#### Table of Contents | ||
- [closest](#closest) | ||
- [Parameters](#parameters) | ||
- [Examples](#examples) | ||
- [createOnKeyDown](#createonkeydown) | ||
- [Parameters](#parameters-1) | ||
- [cx](#cx) | ||
- [Parameters](#parameters-2) | ||
- [Examples](#examples-1) | ||
- [getActiveElement](#getactiveelement) | ||
- [Parameters](#parameters-3) | ||
- [getDocument](#getdocument) | ||
- [Parameters](#parameters-4) | ||
- [hasFocusWithin](#hasfocuswithin) | ||
- [Parameters](#parameters-5) | ||
- [Examples](#examples-2) | ||
- [isButton](#isbutton) | ||
- [Parameters](#parameters-6) | ||
- [Examples](#examples-3) | ||
- [isEmpty](#isempty) | ||
- [Parameters](#parameters-7) | ||
- [Examples](#examples-4) | ||
- [isInteger](#isinteger) | ||
- [Parameters](#parameters-8) | ||
- [Examples](#examples-5) | ||
- [isObject](#isobject) | ||
- [Parameters](#parameters-9) | ||
- [isPlainObject](#isplainobject) | ||
- [Parameters](#parameters-10) | ||
- [isPromise](#ispromise) | ||
- [Parameters](#parameters-11) | ||
- [mergeRefs](#mergerefs) | ||
- [Parameters](#parameters-12) | ||
- [Examples](#examples-6) | ||
- [omit](#omit) | ||
- [Parameters](#parameters-13) | ||
- [Examples](#examples-7) | ||
- [pick](#pick) | ||
- [Parameters](#parameters-14) | ||
- [Examples](#examples-8) | ||
- [removeIndexFromArray](#removeindexfromarray) | ||
- [Parameters](#parameters-15) | ||
- [Examples](#examples-9) | ||
- [removeItemFromArray](#removeitemfromarray) | ||
- [Parameters](#parameters-16) | ||
- [Examples](#examples-10) | ||
- [splitProps](#splitprops) | ||
- [Parameters](#parameters-17) | ||
- [Examples](#examples-11) | ||
- [tabbable](#tabbable) | ||
- [isFocusable](#isfocusable) | ||
- [Parameters](#parameters-18) | ||
- [Examples](#examples-12) | ||
- [isTabbable](#istabbable) | ||
- [Parameters](#parameters-19) | ||
- [Examples](#examples-13) | ||
- [getAllFocusableIn](#getallfocusablein) | ||
- [Parameters](#parameters-20) | ||
- [getFirstFocusableIn](#getfirstfocusablein) | ||
- [Parameters](#parameters-21) | ||
- [getAllTabbableIn](#getalltabbablein) | ||
- [Parameters](#parameters-22) | ||
- [getFirstTabbableIn](#getfirsttabbablein) | ||
- [Parameters](#parameters-23) | ||
- [getLastTabbableIn](#getlasttabbablein) | ||
- [Parameters](#parameters-24) | ||
- [getNextTabbableIn](#getnexttabbablein) | ||
- [Parameters](#parameters-25) | ||
- [getPreviousTabbableIn](#getprevioustabbablein) | ||
- [Parameters](#parameters-26) | ||
- [getClosestFocusable](#getclosestfocusable) | ||
- [Parameters](#parameters-27) | ||
- [ensureFocus](#ensurefocus) | ||
- [Parameters](#parameters-28) | ||
- [Examples](#examples-14) | ||
- [toArray](#toarray) | ||
- [Parameters](#parameters-29) | ||
- [Examples](#examples-15) | ||
- [types](#types) | ||
- [RenderProp](#renderprop) | ||
- [As](#as) | ||
- [ElementType](#elementtype) | ||
- [HTMLAttributesWithRef](#htmlattributeswithref) | ||
- [ExtractHTMLAttributes](#extracthtmlattributes) | ||
- [UnionToIntersection](#uniontointersection) | ||
- [PickByValue](#pickbyvalue) | ||
- [PropsWithAs](#propswithas) | ||
- [ArrayValue](#arrayvalue) | ||
- [AnyFunction](#anyfunction) | ||
- [useAllCallbacks](#useallcallbacks) | ||
- [Parameters](#parameters-30) | ||
- [Examples](#examples-16) | ||
- [useIsomorphicEffect](#useisomorphiceffect) | ||
- [useLiveRef](#useliveref) | ||
- [Parameters](#parameters-31) | ||
- [usePipe](#usepipe) | ||
- [Parameters](#parameters-32) | ||
- [useSealedState](#usesealedstate) | ||
- [Parameters](#parameters-33) | ||
- [useUpdateEffect](#useupdateeffect) | ||
- [Parameters](#parameters-34) | ||
- [warning](#warning) | ||
- [Parameters](#parameters-35) | ||
- [Examples](#examples-17) | ||
### closest | ||
Ponyfill for `Element.prototype.closest` | ||
#### Parameters | ||
- `element` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
- `selectors` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** | ||
#### Examples | ||
```javascript | ||
import { closest } from "reakit-utils"; | ||
closest(document.getElementById("id"), "div"); | ||
// same as | ||
document.getElementById("id").closest("div"); | ||
``` | ||
### createOnKeyDown | ||
Returns an `onKeyDown` handler to be passed to a component. | ||
#### Parameters | ||
- `options` **Options** (optional, default `{}`) | ||
- `options.keyMap` | ||
- `options.onKey` | ||
- `options.stopPropagation` | ||
- `options.onKeyDown` | ||
- `options.shouldKeyDown` (optional, default `()=>true`) | ||
- `options.preventDefault` (optional, default `true`) | ||
Returns **React.KeyboardEventHandler** | ||
### cx | ||
Returns a string with truthy class names separated by space. | ||
#### Parameters | ||
- `classes` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined) | null | `false`)>** | ||
#### Examples | ||
```javascript | ||
import { cx } from "reakit-utils"; | ||
const className = cx("a", "b", false, true && "c"); | ||
``` | ||
Returns **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) \| [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))** | ||
### getActiveElement | ||
Returns `element.ownerDocument.activeElement`. | ||
#### Parameters | ||
- `element` **([Element](https://developer.mozilla.org/docs/Web/API/Element) \| [Document](https://developer.mozilla.org/docs/Web/API/Document) | null)?** | ||
### getDocument | ||
Returns `element.ownerDocument || window.document`. | ||
#### Parameters | ||
- `element` **([Element](https://developer.mozilla.org/docs/Web/API/Element) \| [Document](https://developer.mozilla.org/docs/Web/API/Document) | null)?** | ||
Returns **[Document](https://developer.mozilla.org/docs/Web/API/Document)** | ||
### hasFocusWithin | ||
Checks if `element` has focus. | ||
#### Parameters | ||
- `element` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
#### Examples | ||
```javascript | ||
import { hasFocusWithin } from "reakit-utils"; | ||
hasFocusWithin(document.getElementById("id")); | ||
``` | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### isButton | ||
Checks whether `element` is a native HTML button element or not. | ||
#### Parameters | ||
- `element` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
#### Examples | ||
```javascript | ||
import { isButton } from "reakit-utils"; | ||
isButton(document.querySelector("button")); // true | ||
isButton(document.querySelector("input[type='button']")); // true | ||
isButton(document.querySelector("div")); // false | ||
isButton(document.querySelector("input[type='text']")); // false | ||
``` | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### isEmpty | ||
Checks whether `arg` is empty or not. | ||
#### Parameters | ||
- `arg` **any** | ||
#### Examples | ||
```javascript | ||
import { isEmpty } from "reakit-utils"; | ||
isEmpty([]); // true | ||
isEmpty(["a"]); // false | ||
isEmpty({}); // true | ||
isEmpty({ a: "a" }); // false | ||
isEmpty(); // true | ||
isEmpty(null); // true | ||
isEmpty(undefined); // true | ||
isEmpty(""); // true | ||
``` | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### isInteger | ||
Checks whether `arg` is an integer or not. | ||
#### Parameters | ||
- `arg` **any** | ||
#### Examples | ||
```javascript | ||
import { isInteger } from "reakit-utils"; | ||
isInteger(1); // true | ||
isInteger(1.5); // false | ||
isInteger("1"); // true | ||
isInteger("1.5"); // false | ||
``` | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### isObject | ||
Checks whether `arg` is an object or not. | ||
#### Parameters | ||
- `arg` **any** | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### isPlainObject | ||
Checks whether `arg` is a plain object or not. | ||
#### Parameters | ||
- `arg` **any** | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### isPromise | ||
Checks whether `arg` is a promise or not. | ||
#### Parameters | ||
- `arg` **(T | [Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)<T>)** | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
### mergeRefs | ||
Merges multiple React ref props into a single value that can be passed to | ||
a component. | ||
#### Parameters | ||
- `refs` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<(React.Ref<any> | [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))>** | ||
#### Examples | ||
```javascript | ||
import React from "react"; | ||
import { mergeRefs } from "reakit-utils"; | ||
const Component = React.forwardRef((props, ref) => { | ||
const internalRef = React.useRef(); | ||
return <div ref={mergeRefs(internalRef, ref)} {...props} />; | ||
}); | ||
``` | ||
Returns **(React.Ref<any> | [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))** | ||
### omit | ||
Omits specific keys from an object. | ||
#### Parameters | ||
- `object` **T** | ||
- `paths` **(ReadonlyArray<K> | [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<K>)** | ||
#### Examples | ||
```javascript | ||
import { omit } from "reakit-utils"; | ||
omit({ a: "a", b: "b" }, ["a"]); // { b: "b" } | ||
``` | ||
Returns **Omit<T, K>** | ||
### pick | ||
Picks specific keys from an object. | ||
#### Parameters | ||
- `object` **T** | ||
- `paths` **(ReadonlyArray<K> | [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<K>)** | ||
#### Examples | ||
```javascript | ||
import { pick } from "reakit-utils"; | ||
pick({ a: "a", b: "b" }, ["a"]); // { a: "a" } | ||
``` | ||
### removeIndexFromArray | ||
Immutably removes an index from an array. | ||
#### Parameters | ||
- `array` **A** | ||
- `idx` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** | ||
#### Examples | ||
```javascript | ||
import { removeIndexFromArray } from "reakit-utils"; | ||
removeIndexFromArray(["a", "b", "c"], 1); // ["a", "c"] | ||
``` | ||
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** A new array without the item in the passed index. | ||
### removeItemFromArray | ||
Immutably removes an item from an array. | ||
#### Parameters | ||
- `array` **A** | ||
- `item` **any** | ||
#### Examples | ||
```javascript | ||
import { removeItemFromArray } from "reakit-utils"; | ||
removeItemFromArray(["a", "b", "c"], "b"); // ["a", "c"] | ||
// This only works by reference | ||
const obj = {}; | ||
removeItemFromArray([obj], {}); // [obj] | ||
removeItemFromArray([obj], obj); // [] | ||
``` | ||
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)** A new array without the passed item. | ||
### splitProps | ||
Splits an object (`props`) into a tuple where the first item is an object | ||
with the passed `keys`, and the second item is an object with these keys | ||
omitted. | ||
#### Parameters | ||
- `props` **T** | ||
- `keys` **(ReadonlyArray<K> | [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<K>)** | ||
#### Examples | ||
```javascript | ||
import { splitProps } from "reakit-utils"; | ||
splitProps({ a: "a", b: "b" }, ["a"]); // [{ a: "a" }, { b: "b" }] | ||
``` | ||
Returns **\[any, Omit<T, K>]** | ||
### tabbable | ||
#### isFocusable | ||
Checks whether `element` is focusable or not. | ||
##### Parameters | ||
- `element` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
##### Examples | ||
```javascript | ||
import { isFocusable } from "reakit-utils"; | ||
isFocusable(document.querySelector("input")); // true | ||
isFocusable(document.querySelector("input[tabindex='-1']")); // true | ||
isFocusable(document.querySelector("input[hidden]")); // false | ||
isFocusable(document.querySelector("input:disabled")); // false | ||
``` | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
#### isTabbable | ||
Checks whether `element` is tabbable or not. | ||
##### Parameters | ||
- `element` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
##### Examples | ||
```javascript | ||
import { isTabbable } from "reakit-utils"; | ||
isTabbable(document.querySelector("input")); // true | ||
isTabbable(document.querySelector("input[tabindex='-1']")); // false | ||
isTabbable(document.querySelector("input[hidden]")); // false | ||
isTabbable(document.querySelector("input:disabled")); // false | ||
``` | ||
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
#### getAllFocusableIn | ||
Returns all the focusable elements in `container`. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Element](https://developer.mozilla.org/docs/Web/API/Element)>** | ||
#### getFirstFocusableIn | ||
Returns the first focusable element in `container`. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
Returns **([Element](https://developer.mozilla.org/docs/Web/API/Element) | null)** | ||
#### getAllTabbableIn | ||
Returns all the tabbable elements in `container`, including the container | ||
itself. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
- `fallbackToFocusable` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** If `true`, it'll return focusable elements if there are no tabbable ones. | ||
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Element](https://developer.mozilla.org/docs/Web/API/Element)>** | ||
#### getFirstTabbableIn | ||
Returns the first tabbable element in `container`, including the container | ||
itself if it's tabbable. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
- `fallbackToFocusable` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** If `true`, it'll return the first focusable element if there are no tabbable ones. | ||
Returns **([Element](https://developer.mozilla.org/docs/Web/API/Element) | null)** | ||
#### getLastTabbableIn | ||
Returns the last tabbable element in `container`, including the container | ||
itself if it's tabbable. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
- `fallbackToFocusable` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** If `true`, it'll return the last focusable element if there are no tabbable ones. | ||
Returns **([Element](https://developer.mozilla.org/docs/Web/API/Element) | null)** | ||
#### getNextTabbableIn | ||
Returns the next tabbable element in `container`. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
- `fallbackToFocusable` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** If `true`, it'll return the next focusable element if there are no tabbable ones. | ||
Returns **([Element](https://developer.mozilla.org/docs/Web/API/Element) | null)** | ||
#### getPreviousTabbableIn | ||
Returns the previous tabbable element in `container`. | ||
##### Parameters | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
- `fallbackToFocusable` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)?** If `true`, it'll return the previous focusable element if there are no tabbable ones. | ||
Returns **([Element](https://developer.mozilla.org/docs/Web/API/Element) | null)** | ||
#### getClosestFocusable | ||
Returns the closest focusable parent of `element`. | ||
##### Parameters | ||
- `element` **T** | ||
- `container` **[Element](https://developer.mozilla.org/docs/Web/API/Element)** | ||
Returns **([Element](https://developer.mozilla.org/docs/Web/API/Element) | null)** | ||
#### ensureFocus | ||
Ensures `element` will receive focus if it's not already. | ||
##### Parameters | ||
- `element` **[HTMLElement](https://developer.mozilla.org/docs/Web/HTML/Element)** | ||
- `$1` **EnsureFocusOptions** (optional, default `{}`) | ||
- `$1.isActive` (optional, default `defaultIsActive`) | ||
- `$1.preventScroll` | ||
##### Examples | ||
```javascript | ||
import { ensureFocus } from "reakit-utils"; | ||
ensureFocus(document.activeElement); // does nothing | ||
const element = document.querySelector("input"); | ||
ensureFocus(element); // focuses element | ||
ensureFocus(element, { preventScroll: true }); // focuses element preventing scroll jump | ||
function isActive(el) { | ||
return el.dataset.active === "true"; | ||
} | ||
ensureFocus(document.querySelector("[data-active='true']"), { isActive }); // does nothing | ||
``` | ||
Returns **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** `requestAnimationFrame` call ID so it can be passed to `cancelAnimationFrame` if needed. | ||
### toArray | ||
Transforms `arg` into an array if it's not already. | ||
#### Parameters | ||
- `arg` **any** | ||
#### Examples | ||
```javascript | ||
import { toArray } from "reakit-utils"; | ||
toArray("a"); // ["a"] | ||
toArray(["a"]); // ["a"] | ||
``` | ||
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<any>** | ||
### types | ||
#### RenderProp | ||
Render prop type | ||
Type: function (props: P): React.ReactElement<any> | ||
#### As | ||
"as" prop | ||
Type: React.ReactType<P> | ||
#### ElementType | ||
Converts T to its element type | ||
```ts | ||
type HTMLDivElement = ElementType<"div">; | ||
type FunctionalComponent = ElementType<() => null>; | ||
type Never = ElementType<"foo">; | ||
``` | ||
Type: any | ||
#### HTMLAttributesWithRef | ||
Type: any | ||
#### ExtractHTMLAttributes | ||
Returns only the HTML attributes inside P | ||
```ts | ||
type OnlyId = ExtractHTMLAttributes<{ id: string; foo: string }>; | ||
type HTMLAttributes = ExtractHTMLAttributes<any>; | ||
``` | ||
Type: Pick<HTMLAttributesWithRef, Extract<any, any>> | ||
#### UnionToIntersection | ||
Transforms `"a" | "b"` into `"a" & "b"` | ||
Type: any | ||
#### PickByValue | ||
Same as Pick, but with value types instead of key | ||
Type: Pick<T, any> | ||
#### PropsWithAs | ||
Generic component props with "as" prop | ||
Type: any | ||
#### ArrayValue | ||
Returns the type of the items in an array | ||
Type: any | ||
#### AnyFunction | ||
Any function | ||
Type: function (...args: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<any>): any | ||
### useAllCallbacks | ||
React custom hook that combines multiple callbacks into one. | ||
#### Parameters | ||
- `callbacks` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<(AnyFunction | null | [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))>** | ||
#### Examples | ||
```javascript | ||
import React from "react"; | ||
import { useAllCallbacks } from "reakit-utils"; | ||
function Component(props) { | ||
const onClick = () => {}; | ||
return ( | ||
<button onClick={useAllCallbacks(onClick, props.onClick)}>Button</button> | ||
); | ||
} | ||
``` | ||
Returns **AnyFunction** | ||
### useIsomorphicEffect | ||
`React.useLayoutEffect` that fallbacks to `React.useEffect` on server side | ||
rendering. | ||
### useLiveRef | ||
A `React.Ref` that keeps track of the passed `value`. | ||
#### Parameters | ||
- `value` **T** | ||
Returns **React.MutableRefObject<T>** | ||
### usePipe | ||
A React custom hook similar to [`useAllCallbacks`](#useallcallbacks), but | ||
it'll pass the returned value from a function to the next function. | ||
#### Parameters | ||
- `fns` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<(AnyFunction | null | [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))>** | ||
### useSealedState | ||
React custom hook that returns the very first value passed to `initialState`, | ||
even if it changes between re-renders. | ||
#### Parameters | ||
- `initialState` **SealedInitialState<T>** | ||
### useUpdateEffect | ||
A `React.useEffect` that will not run on the first render. | ||
#### Parameters | ||
- `effect` **React.EffectCallback** | ||
- `deps` **(ReadonlyArray<any> | [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))?** | ||
### warning | ||
Logs `messages` to the console using `console.warn` based on a `condition`. | ||
#### Parameters | ||
- `condition` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** | ||
- `messages` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>** | ||
#### Examples | ||
```javascript | ||
import { warning } from "reakit-utils"; | ||
warning(true, "a", "b"); // console.warn("a\nb") | ||
warning(false, "a", "b"); // does nothing | ||
``` | ||
## License | ||
MIT © [Diego Haz](https://github.com/diegohaz) |
@@ -1,3 +0,1 @@ | ||
// closest ponyfill | ||
function matches(element: Element, selectors: string): boolean { | ||
@@ -25,2 +23,12 @@ if ("matches" in element) return element.matches(selectors); | ||
/** | ||
* Ponyfill for `Element.prototype.closest` | ||
* | ||
* @example | ||
* import { closest } from "reakit-utils"; | ||
* | ||
* closest(document.getElementById("id"), "div"); | ||
* // same as | ||
* document.getElementById("id").closest("div"); | ||
*/ | ||
export function closest(element: Element, selectors: string) { | ||
@@ -27,0 +35,0 @@ if ("closest" in element) return element.closest(selectors); |
@@ -20,2 +20,7 @@ import * as React from "react"; | ||
/** | ||
* Returns an `onKeyDown` handler to be passed to a component. | ||
* | ||
* @param options | ||
*/ | ||
export function createOnKeyDown({ | ||
@@ -28,4 +33,4 @@ keyMap, | ||
preventDefault = true | ||
}: Options = {}) { | ||
return (event: React.KeyboardEvent) => { | ||
}: Options = {}): React.KeyboardEventHandler { | ||
return event => { | ||
if (!keyMap) return; | ||
@@ -32,0 +37,0 @@ |
@@ -1,3 +0,13 @@ | ||
export function cx(...classes: Array<string | undefined | null | false>) { | ||
/** | ||
* Returns a string with truthy class names separated by space. | ||
* | ||
* @example | ||
* import { cx } from "reakit-utils"; | ||
* | ||
* const className = cx("a", "b", false, true && "c"); | ||
*/ | ||
export function cx( | ||
...classes: Array<string | undefined | null | false> | ||
): string | undefined { | ||
return classes.filter(Boolean).join(" ") || undefined; | ||
} |
@@ -1,2 +0,5 @@ | ||
export function getDocument(element?: Element | Document) { | ||
/** | ||
* Returns `element.ownerDocument || window.document`. | ||
*/ | ||
export function getDocument(element?: Element | Document | null): Document { | ||
return element | ||
@@ -3,0 +6,0 @@ ? element.ownerDocument || (element as Document) |
import { getDocument } from "./getDocument"; | ||
export function hasFocusWithin(element: Element) { | ||
/** | ||
* Checks if `element` has focus. | ||
* | ||
* @example | ||
* import { hasFocusWithin } from "reakit-utils"; | ||
* | ||
* hasFocusWithin(document.getElementById("id")); | ||
*/ | ||
export function hasFocusWithin(element: Element): boolean { | ||
const document = getDocument(element); | ||
@@ -5,0 +13,0 @@ if (!document.activeElement) return false; |
@@ -6,5 +6,7 @@ export * from "./closest"; | ||
export * from "./hasFocusWithin"; | ||
export * from "./isButton"; | ||
export * from "./isEmpty"; | ||
export * from "./isInteger"; | ||
export * from "./isObject"; | ||
export * from "./isPlainObject"; | ||
export * from "./isPromise"; | ||
@@ -11,0 +13,0 @@ export * from "./mergeRefs"; |
import { isObject } from "./isObject"; | ||
export function isEmpty(arg: any) { | ||
/** | ||
* Checks whether `arg` is empty or not. | ||
* | ||
* @example | ||
* import { isEmpty } from "reakit-utils"; | ||
* | ||
* isEmpty([]); // true | ||
* isEmpty(["a"]); // false | ||
* isEmpty({}); // true | ||
* isEmpty({ a: "a" }); // false | ||
* isEmpty(); // true | ||
* isEmpty(null); // true | ||
* isEmpty(undefined); // true | ||
* isEmpty(""); // true | ||
*/ | ||
export function isEmpty(arg: any): boolean { | ||
if (Array.isArray(arg)) return !arg.length; | ||
@@ -5,0 +20,0 @@ if (isObject(arg)) return !Object.keys(arg).length; |
@@ -1,6 +0,17 @@ | ||
export function isInteger(obj: any) { | ||
if (typeof obj === "number") { | ||
return Math.floor(obj) === obj; | ||
/** | ||
* Checks whether `arg` is an integer or not. | ||
* | ||
* @example | ||
* import { isInteger } from "reakit-utils"; | ||
* | ||
* isInteger(1); // true | ||
* isInteger(1.5); // false | ||
* isInteger("1"); // true | ||
* isInteger("1.5"); // false | ||
*/ | ||
export function isInteger(arg: any): boolean { | ||
if (typeof arg === "number") { | ||
return Math.floor(arg) === arg; | ||
} | ||
return String(Math.floor(Number(obj))) === obj; | ||
return String(Math.floor(Number(arg))) === arg; | ||
} |
@@ -0,3 +1,8 @@ | ||
/** | ||
* Checks whether `arg` is an object or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function isObject(arg: any): arg is object { | ||
return typeof arg === "object" && arg != null; | ||
} |
@@ -0,3 +1,8 @@ | ||
/** | ||
* Checks whether `arg` is a promise or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export function isPromise<T>(arg: T | Promise<T>): arg is Promise<T> { | ||
return Boolean(arg && (arg as Promise<T>).then); | ||
} |
import * as React from "react"; | ||
export function mergeRefs(...refs: Array<React.Ref<any> | undefined>) { | ||
/** | ||
* Merges multiple React ref props into a single value that can be passed to | ||
* a component. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { mergeRefs } from "reakit-utils"; | ||
* | ||
* const Component = React.forwardRef((props, ref) => { | ||
* const internalRef = React.useRef(); | ||
* return <div ref={mergeRefs(internalRef, ref)} {...props} />; | ||
* }); | ||
*/ | ||
export function mergeRefs( | ||
...refs: Array<React.Ref<any> | undefined> | ||
): React.Ref<any> | undefined { | ||
const filteredRefs = refs.filter(Boolean); | ||
@@ -5,0 +20,0 @@ if (!filteredRefs.length) return null; |
@@ -1,7 +0,13 @@ | ||
import { Omit } from "./types"; | ||
/** | ||
* Omits specific keys from an object. | ||
* | ||
* @example | ||
* import { omit } from "reakit-utils"; | ||
* | ||
* omit({ a: "a", b: "b" }, ["a"]); // { b: "b" } | ||
*/ | ||
export function omit<T extends Record<string, any>, K extends keyof T>( | ||
object: T, | ||
paths: ReadonlyArray<K> | K[] | ||
) { | ||
): Omit<T, K> { | ||
const keys = Object.keys(object); | ||
@@ -8,0 +14,0 @@ const result = {} as Omit<T, K>; |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Picks specific keys from an object. | ||
* | ||
* @example | ||
* import { pick } from "reakit-utils"; | ||
* | ||
* pick({ a: "a", b: "b" }, ["a"]); // { a: "a" } | ||
*/ | ||
export function pick<T extends Record<string, any>, K extends keyof T>( | ||
@@ -2,0 +10,0 @@ object: T, |
@@ -0,1 +1,11 @@ | ||
/** | ||
* Immutably removes an index from an array. | ||
* | ||
* @example | ||
* import { removeIndexFromArray } from "reakit-utils"; | ||
* | ||
* removeIndexFromArray(["a", "b", "c"], 1); // ["a", "c"] | ||
* | ||
* @returns {Array} A new array without the item in the passed index. | ||
*/ | ||
export function removeIndexFromArray<A extends any[]>(array: A, idx: number) { | ||
@@ -2,0 +12,0 @@ if (idx === -1) return array; |
import { removeIndexFromArray } from "./removeIndexFromArray"; | ||
/** | ||
* Immutably removes an item from an array. | ||
* | ||
* @example | ||
* import { removeItemFromArray } from "reakit-utils"; | ||
* | ||
* removeItemFromArray(["a", "b", "c"], "b"); // ["a", "c"] | ||
* | ||
* // This only works by reference | ||
* const obj = {}; | ||
* removeItemFromArray([obj], {}); // [obj] | ||
* removeItemFromArray([obj], obj); // [] | ||
* | ||
* @returns {Array} A new array without the passed item. | ||
*/ | ||
export function removeItemFromArray<A extends any[]>( | ||
@@ -4,0 +19,0 @@ array: A, |
@@ -1,7 +0,15 @@ | ||
import { Omit } from "./types"; | ||
/** | ||
* Splits an object (`props`) into a tuple where the first item is an object | ||
* with the passed `keys`, and the second item is an object with these keys | ||
* omitted. | ||
* | ||
* @example | ||
* import { splitProps } from "reakit-utils"; | ||
* | ||
* splitProps({ a: "a", b: "b" }, ["a"]); // [{ a: "a" }, { b: "b" }] | ||
*/ | ||
export function splitProps<T extends Record<string, any>, K extends keyof T>( | ||
props: T, | ||
keys: ReadonlyArray<K> | Array<K> | ||
) { | ||
): [{ [P in K]: T[P] }, Omit<T, K>] { | ||
const propsKeys = Object.keys(props); | ||
@@ -19,3 +27,3 @@ const picked = {} as { [P in K]: T[P] }; | ||
return [picked, omitted] as [typeof picked, typeof omitted]; | ||
return [picked, omitted]; | ||
} |
@@ -0,2 +1,4 @@ | ||
/** @module tabbable */ | ||
import { closest } from "./closest"; | ||
import { getActiveElement } from "./getActiveElement"; | ||
@@ -22,10 +24,45 @@ const selector = | ||
export function isFocusable(element: Element) { | ||
/** | ||
* Checks whether `element` is focusable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isFocusable } from "reakit-utils"; | ||
* | ||
* isFocusable(document.querySelector("input")); // true | ||
* isFocusable(document.querySelector("input[tabindex='-1']")); // true | ||
* isFocusable(document.querySelector("input[hidden]")); // false | ||
* isFocusable(document.querySelector("input:disabled")); // false | ||
*/ | ||
export function isFocusable(element: Element): boolean { | ||
return element.matches(selector) && isVisible(element); | ||
} | ||
export function isTabbable(element: Element) { | ||
/** | ||
* Checks whether `element` is tabbable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isTabbable } from "reakit-utils"; | ||
* | ||
* isTabbable(document.querySelector("input")); // true | ||
* isTabbable(document.querySelector("input[tabindex='-1']")); // false | ||
* isTabbable(document.querySelector("input[hidden]")); // false | ||
* isTabbable(document.querySelector("input:disabled")); // false | ||
*/ | ||
export function isTabbable(element: Element): boolean { | ||
return isFocusable(element) && !hasNegativeTabIndex(element); | ||
} | ||
/** | ||
* Returns all the focusable elements in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
export function getAllFocusableIn<T extends Element>(container: T) { | ||
@@ -37,2 +74,11 @@ const allFocusable = Array.from(container.querySelectorAll<T>(selector)); | ||
/** | ||
* Returns the first focusable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export function getFirstFocusableIn<T extends Element>(container: T) { | ||
@@ -43,2 +89,13 @@ const allFocusable = getAllFocusableIn(container); | ||
/** | ||
* Returns all the tabbable elements in `container`, including the container | ||
* itself. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return focusable elements if there are no tabbable ones. | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
export function getAllTabbableIn<T extends Element>( | ||
@@ -61,2 +118,13 @@ container: T, | ||
/** | ||
* Returns the first tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the first focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export function getFirstTabbableIn<T extends Element>( | ||
@@ -70,2 +138,13 @@ container: T, | ||
/** | ||
* Returns the last tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the last focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export function getLastTabbableIn<T extends Element>( | ||
@@ -79,2 +158,12 @@ container: T, | ||
/** | ||
* Returns the next tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the next focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export function getNextTabbableIn<T extends Element>( | ||
@@ -84,3 +173,3 @@ container: T, | ||
): T | null { | ||
const { activeElement } = container.ownerDocument || document; | ||
const activeElement = getActiveElement(container); | ||
const allFocusable = getAllFocusableIn(container); | ||
@@ -96,2 +185,12 @@ const index = allFocusable.indexOf(activeElement as T); | ||
/** | ||
* Returns the previous tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the previous focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export function getPreviousTabbableIn<T extends Element>( | ||
@@ -101,3 +200,3 @@ container: T, | ||
): T | null { | ||
const { activeElement } = container.ownerDocument || document; | ||
const activeElement = getActiveElement(container); | ||
const allFocusable = getAllFocusableIn(container).reverse(); | ||
@@ -113,2 +212,11 @@ const index = allFocusable.indexOf(activeElement as T); | ||
/** | ||
* Returns the closest focusable parent of `element`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export function getClosestFocusable<T extends Element>(element: T): T | null { | ||
@@ -125,4 +233,3 @@ let container: T | null = null; | ||
function defaultIsActive(element: Element) { | ||
const { activeElement } = element.ownerDocument || document; | ||
return activeElement === element; | ||
return getActiveElement(element) === element; | ||
} | ||
@@ -134,2 +241,25 @@ | ||
/** | ||
* Ensures `element` will receive focus if it's not already. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { ensureFocus } from "reakit-utils"; | ||
* | ||
* ensureFocus(document.activeElement); // does nothing | ||
* | ||
* const element = document.querySelector("input"); | ||
* | ||
* ensureFocus(element); // focuses element | ||
* ensureFocus(element, { preventScroll: true }); // focuses element preventing scroll jump | ||
* | ||
* function isActive(el) { | ||
* return el.dataset.active === "true"; | ||
* } | ||
* | ||
* ensureFocus(document.querySelector("[data-active='true']"), { isActive }); // does nothing | ||
* | ||
* @returns {number} `requestAnimationFrame` call ID so it can be passed to `cancelAnimationFrame` if needed. | ||
*/ | ||
export function ensureFocus( | ||
@@ -136,0 +266,0 @@ element: HTMLElement, |
@@ -1,2 +0,11 @@ | ||
export function toArray(arg: any) { | ||
/** | ||
* Transforms `arg` into an array if it's not already. | ||
* | ||
* @example | ||
* import { toArray } from "reakit-utils"; | ||
* | ||
* toArray("a"); // ["a"] | ||
* toArray(["a"]); // ["a"] | ||
*/ | ||
export function toArray(arg: any): any[] { | ||
if (Array.isArray(arg)) { | ||
@@ -3,0 +12,0 @@ return arg; |
@@ -0,11 +1,7 @@ | ||
/** @module types */ | ||
import * as React from "react"; | ||
/** | ||
* @template T Object | ||
* @template K Union of T keys | ||
*/ | ||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||
/** | ||
* Render prop type | ||
* @memberof types | ||
* @template P Props | ||
@@ -17,2 +13,3 @@ */ | ||
* "as" prop | ||
* @memberof types | ||
* @template P Props | ||
@@ -24,6 +21,8 @@ */ | ||
* Converts T to its element type | ||
* @example | ||
* ```ts | ||
* type HTMLDivElement = ElementType<"div">; | ||
* type FunctionalComponent = ElementType<() => null>; | ||
* type Never = ElementType<"foo">; | ||
* ``` | ||
* @memberof types | ||
* @template T Component type or string tag | ||
@@ -43,2 +42,3 @@ */ | ||
/** | ||
* @memberof types | ||
* @template T Element type | ||
@@ -51,5 +51,7 @@ */ | ||
* Returns only the HTML attributes inside P | ||
* @example | ||
* ```ts | ||
* type OnlyId = ExtractHTMLAttributes<{ id: string; foo: string }>; | ||
* type HTMLAttributes = ExtractHTMLAttributes<any>; | ||
* ``` | ||
* @memberof types | ||
* @template P Props | ||
@@ -63,3 +65,4 @@ */ | ||
/** | ||
* Transform `"a" | "b"` into `"a" & "b"` | ||
* Transforms `"a" | "b"` into `"a" & "b"` | ||
* @memberof types | ||
* @template U Union | ||
@@ -75,2 +78,3 @@ */ | ||
* Same as Pick, but with value types instead of key | ||
* @memberof types | ||
* @template T Object | ||
@@ -86,2 +90,3 @@ * @template V Value | ||
* Generic component props with "as" prop | ||
* @memberof types | ||
* @template P Additional props | ||
@@ -92,5 +97,2 @@ * @template T React component or string element | ||
Omit<React.ComponentProps<T>, "as" | keyof P> & { | ||
/** | ||
* Replaces the underlying element | ||
*/ | ||
as?: T; | ||
@@ -102,2 +104,3 @@ children?: React.ReactNode | RenderProp<ExtractHTMLAttributes<any>>; | ||
* Returns the type of the items in an array | ||
* @memberof types | ||
* @template T Array | ||
@@ -109,3 +112,4 @@ */ | ||
* Any function | ||
* @memberof types | ||
*/ | ||
export type AnyFunction = (...args: any[]) => any; |
import * as React from "react"; | ||
import { AnyFunction } from "./types"; | ||
/** | ||
* React custom hook that combines multiple callbacks into one. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { useAllCallbacks } from "reakit-utils"; | ||
* | ||
* function Component(props) { | ||
* const onClick = () => {}; | ||
* return ( | ||
* <button onClick={useAllCallbacks(onClick, props.onClick)}>Button</button> | ||
* ); | ||
* } | ||
*/ | ||
export function useAllCallbacks( | ||
...callbacks: Array<AnyFunction | null | undefined> | ||
) { | ||
): AnyFunction { | ||
return React.useCallback((...args: any[]) => { | ||
@@ -8,0 +22,0 @@ const fns = callbacks.filter(Boolean) as Array<AnyFunction>; |
import * as React from "react"; | ||
/** | ||
* `React.useLayoutEffect` that fallbacks to `React.useEffect` on server side | ||
* rendering. | ||
*/ | ||
export const useIsomorphicEffect = | ||
typeof window === "undefined" ? React.useEffect : React.useLayoutEffect; |
import * as React from "react"; | ||
export function useLiveRef<T>(value: T) { | ||
/** | ||
* A `React.Ref` that keeps track of the passed `value`. | ||
*/ | ||
export function useLiveRef<T>(value: T): React.MutableRefObject<T> { | ||
const ref = React.useRef(value); | ||
@@ -5,0 +8,0 @@ |
import * as React from "react"; | ||
import { AnyFunction } from "./types"; | ||
/** | ||
* A React custom hook similar to [`useAllCallbacks`](#useallcallbacks), but | ||
* it'll pass the returned value from a function to the next function. | ||
*/ | ||
export function usePipe(...fns: Array<AnyFunction | null | undefined>) { | ||
@@ -5,0 +9,0 @@ return React.useCallback(arg => { |
@@ -5,2 +5,6 @@ import * as React from "react"; | ||
/** | ||
* React custom hook that returns the very first value passed to `initialState`, | ||
* even if it changes between re-renders. | ||
*/ | ||
export function useSealedState<T>(initialState: SealedInitialState<T>) { | ||
@@ -7,0 +11,0 @@ const [sealed] = React.useState(initialState); |
@@ -1,4 +0,6 @@ | ||
// https://github.com/reach/reach-ui/blob/34e52b029ba8330fa705804e6b71048267c46283/packages/tabs/src/index.js#L267-L276 | ||
import * as React from "react"; | ||
/** | ||
* A `React.useEffect` that will not run on the first render. | ||
*/ | ||
export function useUpdateEffect( | ||
@@ -5,0 +7,0 @@ effect: React.EffectCallback, |
@@ -0,1 +1,10 @@ | ||
/** | ||
* Logs `messages` to the console using `console.warn` based on a `condition`. | ||
* | ||
* @example | ||
* import { warning } from "reakit-utils"; | ||
* | ||
* warning(true, "a", "b"); // console.warn("a\nb") | ||
* warning(false, "a", "b"); // does nothing | ||
*/ | ||
export function warning(condition: boolean, ...messages: string[]) { | ||
@@ -2,0 +11,0 @@ if (process.env.NODE_ENV !== "production") { |
@@ -13,3 +13,8 @@ import * as React from "react"; | ||
}; | ||
export declare function createOnKeyDown({ keyMap, onKey, stopPropagation, onKeyDown, shouldKeyDown, preventDefault }?: Options): (event: React.KeyboardEvent<Element>) => void; | ||
/** | ||
* Returns an `onKeyDown` handler to be passed to a component. | ||
* | ||
* @param options | ||
*/ | ||
export declare function createOnKeyDown({ keyMap, onKey, stopPropagation, onKeyDown, shouldKeyDown, preventDefault }?: Options): React.KeyboardEventHandler; | ||
export {}; |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Returns a string with truthy class names separated by space. | ||
* | ||
* @example | ||
* import { cx } from "reakit-utils"; | ||
* | ||
* const className = cx("a", "b", false, true && "c"); | ||
*/ | ||
export declare function cx(...classes: Array<string | undefined | null | false>): string | undefined; |
@@ -1,1 +0,4 @@ | ||
export declare function getDocument(element?: Element | Document): Document; | ||
/** | ||
* Returns `element.ownerDocument || window.document`. | ||
*/ | ||
export declare function getDocument(element?: Element | Document | null): Document; |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Checks if `element` has focus. | ||
* | ||
* @example | ||
* import { hasFocusWithin } from "reakit-utils"; | ||
* | ||
* hasFocusWithin(document.getElementById("id")); | ||
*/ | ||
export declare function hasFocusWithin(element: Element): boolean; |
@@ -6,5 +6,7 @@ export * from "./closest"; | ||
export * from "./hasFocusWithin"; | ||
export * from "./isButton"; | ||
export * from "./isEmpty"; | ||
export * from "./isInteger"; | ||
export * from "./isObject"; | ||
export * from "./isPlainObject"; | ||
export * from "./isPromise"; | ||
@@ -11,0 +13,0 @@ export * from "./mergeRefs"; |
@@ -0,1 +1,16 @@ | ||
/** | ||
* Checks whether `arg` is empty or not. | ||
* | ||
* @example | ||
* import { isEmpty } from "reakit-utils"; | ||
* | ||
* isEmpty([]); // true | ||
* isEmpty(["a"]); // false | ||
* isEmpty({}); // true | ||
* isEmpty({ a: "a" }); // false | ||
* isEmpty(); // true | ||
* isEmpty(null); // true | ||
* isEmpty(undefined); // true | ||
* isEmpty(""); // true | ||
*/ | ||
export declare function isEmpty(arg: any): boolean; |
@@ -1,1 +0,12 @@ | ||
export declare function isInteger(obj: any): boolean; | ||
/** | ||
* Checks whether `arg` is an integer or not. | ||
* | ||
* @example | ||
* import { isInteger } from "reakit-utils"; | ||
* | ||
* isInteger(1); // true | ||
* isInteger(1.5); // false | ||
* isInteger("1"); // true | ||
* isInteger("1.5"); // false | ||
*/ | ||
export declare function isInteger(arg: any): boolean; |
@@ -0,1 +1,6 @@ | ||
/** | ||
* Checks whether `arg` is an object or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export declare function isObject(arg: any): arg is object; |
@@ -0,1 +1,6 @@ | ||
/** | ||
* Checks whether `arg` is a promise or not. | ||
* | ||
* @returns {boolean} | ||
*/ | ||
export declare function isPromise<T>(arg: T | Promise<T>): arg is Promise<T>; |
import * as React from "react"; | ||
export declare function mergeRefs(...refs: Array<React.Ref<any> | undefined>): ((instance: any) => void) | React.RefObject<any> | null | undefined; | ||
/** | ||
* Merges multiple React ref props into a single value that can be passed to | ||
* a component. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { mergeRefs } from "reakit-utils"; | ||
* | ||
* const Component = React.forwardRef((props, ref) => { | ||
* const internalRef = React.useRef(); | ||
* return <div ref={mergeRefs(internalRef, ref)} {...props} />; | ||
* }); | ||
*/ | ||
export declare function mergeRefs(...refs: Array<React.Ref<any> | undefined>): React.Ref<any> | undefined; |
@@ -1,1 +0,9 @@ | ||
export declare function omit<T extends Record<string, any>, K extends keyof T>(object: T, paths: ReadonlyArray<K> | K[]): Pick<T, Exclude<keyof T, K>>; | ||
/** | ||
* Omits specific keys from an object. | ||
* | ||
* @example | ||
* import { omit } from "reakit-utils"; | ||
* | ||
* omit({ a: "a", b: "b" }, ["a"]); // { b: "b" } | ||
*/ | ||
export declare function omit<T extends Record<string, any>, K extends keyof T>(object: T, paths: ReadonlyArray<K> | K[]): Omit<T, K>; |
@@ -0,1 +1,9 @@ | ||
/** | ||
* Picks specific keys from an object. | ||
* | ||
* @example | ||
* import { pick } from "reakit-utils"; | ||
* | ||
* pick({ a: "a", b: "b" }, ["a"]); // { a: "a" } | ||
*/ | ||
export declare function pick<T extends Record<string, any>, K extends keyof T>(object: T, paths: ReadonlyArray<K> | K[]): { [P in K]: T[P]; }; |
@@ -0,1 +1,11 @@ | ||
/** | ||
* Immutably removes an index from an array. | ||
* | ||
* @example | ||
* import { removeIndexFromArray } from "reakit-utils"; | ||
* | ||
* removeIndexFromArray(["a", "b", "c"], 1); // ["a", "c"] | ||
* | ||
* @returns {Array} A new array without the item in the passed index. | ||
*/ | ||
export declare function removeIndexFromArray<A extends any[]>(array: A, idx: number): A; |
@@ -0,1 +1,16 @@ | ||
/** | ||
* Immutably removes an item from an array. | ||
* | ||
* @example | ||
* import { removeItemFromArray } from "reakit-utils"; | ||
* | ||
* removeItemFromArray(["a", "b", "c"], "b"); // ["a", "c"] | ||
* | ||
* // This only works by reference | ||
* const obj = {}; | ||
* removeItemFromArray([obj], {}); // [obj] | ||
* removeItemFromArray([obj], obj); // [] | ||
* | ||
* @returns {Array} A new array without the passed item. | ||
*/ | ||
export declare function removeItemFromArray<A extends any[]>(array: A, item: A[number]): A; |
@@ -1,1 +0,13 @@ | ||
export declare function splitProps<T extends Record<string, any>, K extends keyof T>(props: T, keys: ReadonlyArray<K> | Array<K>): [{ [P in K]: T[P]; }, Pick<T, Exclude<keyof T, K>>]; | ||
/** | ||
* Splits an object (`props`) into a tuple where the first item is an object | ||
* with the passed `keys`, and the second item is an object with these keys | ||
* omitted. | ||
* | ||
* @example | ||
* import { splitProps } from "reakit-utils"; | ||
* | ||
* splitProps({ a: "a", b: "b" }, ["a"]); // [{ a: "a" }, { b: "b" }] | ||
*/ | ||
export declare function splitProps<T extends Record<string, any>, K extends keyof T>(props: T, keys: ReadonlyArray<K> | Array<K>): [{ | ||
[P in K]: T[P]; | ||
}, Omit<T, K>]; |
@@ -0,10 +1,116 @@ | ||
/** | ||
* Checks whether `element` is focusable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isFocusable } from "reakit-utils"; | ||
* | ||
* isFocusable(document.querySelector("input")); // true | ||
* isFocusable(document.querySelector("input[tabindex='-1']")); // true | ||
* isFocusable(document.querySelector("input[hidden]")); // false | ||
* isFocusable(document.querySelector("input:disabled")); // false | ||
*/ | ||
export declare function isFocusable(element: Element): boolean; | ||
/** | ||
* Checks whether `element` is tabbable or not. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { isTabbable } from "reakit-utils"; | ||
* | ||
* isTabbable(document.querySelector("input")); // true | ||
* isTabbable(document.querySelector("input[tabindex='-1']")); // false | ||
* isTabbable(document.querySelector("input[hidden]")); // false | ||
* isTabbable(document.querySelector("input:disabled")); // false | ||
*/ | ||
export declare function isTabbable(element: Element): boolean; | ||
/** | ||
* Returns all the focusable elements in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
export declare function getAllFocusableIn<T extends Element>(container: T): T[]; | ||
/** | ||
* Returns the first focusable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export declare function getFirstFocusableIn<T extends Element>(container: T): T | null; | ||
/** | ||
* Returns all the tabbable elements in `container`, including the container | ||
* itself. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return focusable elements if there are no tabbable ones. | ||
* | ||
* @returns {Element[]} | ||
*/ | ||
export declare function getAllTabbableIn<T extends Element>(container: T, fallbackToFocusable?: boolean): T[]; | ||
/** | ||
* Returns the first tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the first focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export declare function getFirstTabbableIn<T extends Element>(container: T, fallbackToFocusable?: boolean): T | null; | ||
/** | ||
* Returns the last tabbable element in `container`, including the container | ||
* itself if it's tabbable. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the last focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export declare function getLastTabbableIn<T extends Element>(container: T, fallbackToFocusable?: boolean): T | null; | ||
/** | ||
* Returns the next tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the next focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export declare function getNextTabbableIn<T extends Element>(container: T, fallbackToFocusable?: boolean): T | null; | ||
/** | ||
* Returns the previous tabbable element in `container`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* @param fallbackToFocusable If `true`, it'll return the previous focusable element if there are no tabbable ones. | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export declare function getPreviousTabbableIn<T extends Element>(container: T, fallbackToFocusable?: boolean): T | null; | ||
/** | ||
* Returns the closest focusable parent of `element`. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @param {Element} container | ||
* | ||
* @returns {Element|null} | ||
*/ | ||
export declare function getClosestFocusable<T extends Element>(element: T): T | null; | ||
@@ -15,3 +121,26 @@ declare function defaultIsActive(element: Element): boolean; | ||
}; | ||
/** | ||
* Ensures `element` will receive focus if it's not already. | ||
* | ||
* @memberof tabbable | ||
* | ||
* @example | ||
* import { ensureFocus } from "reakit-utils"; | ||
* | ||
* ensureFocus(document.activeElement); // does nothing | ||
* | ||
* const element = document.querySelector("input"); | ||
* | ||
* ensureFocus(element); // focuses element | ||
* ensureFocus(element, { preventScroll: true }); // focuses element preventing scroll jump | ||
* | ||
* function isActive(el) { | ||
* return el.dataset.active === "true"; | ||
* } | ||
* | ||
* ensureFocus(document.querySelector("[data-active='true']"), { isActive }); // does nothing | ||
* | ||
* @returns {number} `requestAnimationFrame` call ID so it can be passed to `cancelAnimationFrame` if needed. | ||
*/ | ||
export declare function ensureFocus(element: HTMLElement, { isActive, preventScroll }?: EnsureFocusOptions): number; | ||
export {}; |
@@ -0,1 +1,10 @@ | ||
/** | ||
* Transforms `arg` into an array if it's not already. | ||
* | ||
* @example | ||
* import { toArray } from "reakit-utils"; | ||
* | ||
* toArray("a"); // ["a"] | ||
* toArray(["a"]); // ["a"] | ||
*/ | ||
export declare function toArray(arg: any): any[]; |
@@ -0,9 +1,6 @@ | ||
/** @module types */ | ||
import * as React from "react"; | ||
/** | ||
* @template T Object | ||
* @template K Union of T keys | ||
*/ | ||
export declare type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||
/** | ||
* Render prop type | ||
* @memberof types | ||
* @template P Props | ||
@@ -14,2 +11,3 @@ */ | ||
* "as" prop | ||
* @memberof types | ||
* @template P Props | ||
@@ -20,6 +18,8 @@ */ | ||
* Converts T to its element type | ||
* @example | ||
* ```ts | ||
* type HTMLDivElement = ElementType<"div">; | ||
* type FunctionalComponent = ElementType<() => null>; | ||
* type Never = ElementType<"foo">; | ||
* ``` | ||
* @memberof types | ||
* @template T Component type or string tag | ||
@@ -29,2 +29,3 @@ */ | ||
/** | ||
* @memberof types | ||
* @template T Element type | ||
@@ -35,5 +36,7 @@ */ | ||
* Returns only the HTML attributes inside P | ||
* @example | ||
* ```ts | ||
* type OnlyId = ExtractHTMLAttributes<{ id: string; foo: string }>; | ||
* type HTMLAttributes = ExtractHTMLAttributes<any>; | ||
* ``` | ||
* @memberof types | ||
* @template P Props | ||
@@ -43,3 +46,4 @@ */ | ||
/** | ||
* Transform `"a" | "b"` into `"a" & "b"` | ||
* Transforms `"a" | "b"` into `"a" & "b"` | ||
* @memberof types | ||
* @template U Union | ||
@@ -50,2 +54,3 @@ */ | ||
* Same as Pick, but with value types instead of key | ||
* @memberof types | ||
* @template T Object | ||
@@ -59,2 +64,3 @@ * @template V Value | ||
* Generic component props with "as" prop | ||
* @memberof types | ||
* @template P Additional props | ||
@@ -64,5 +70,2 @@ * @template T React component or string element | ||
export declare type PropsWithAs<P, T extends As> = P & Omit<React.ComponentProps<T>, "as" | keyof P> & { | ||
/** | ||
* Replaces the underlying element | ||
*/ | ||
as?: T; | ||
@@ -73,2 +76,3 @@ children?: React.ReactNode | RenderProp<ExtractHTMLAttributes<any>>; | ||
* Returns the type of the items in an array | ||
* @memberof types | ||
* @template T Array | ||
@@ -79,3 +83,4 @@ */ | ||
* Any function | ||
* @memberof types | ||
*/ | ||
export declare type AnyFunction = (...args: any[]) => any; |
import { AnyFunction } from "./types"; | ||
export declare function useAllCallbacks(...callbacks: Array<AnyFunction | null | undefined>): (...args: any[]) => void; | ||
/** | ||
* React custom hook that combines multiple callbacks into one. | ||
* | ||
* @example | ||
* import React from "react"; | ||
* import { useAllCallbacks } from "reakit-utils"; | ||
* | ||
* function Component(props) { | ||
* const onClick = () => {}; | ||
* return ( | ||
* <button onClick={useAllCallbacks(onClick, props.onClick)}>Button</button> | ||
* ); | ||
* } | ||
*/ | ||
export declare function useAllCallbacks(...callbacks: Array<AnyFunction | null | undefined>): AnyFunction; |
import * as React from "react"; | ||
/** | ||
* `React.useLayoutEffect` that fallbacks to `React.useEffect` on server side | ||
* rendering. | ||
*/ | ||
export declare const useIsomorphicEffect: typeof React.useEffect; |
import * as React from "react"; | ||
/** | ||
* A `React.Ref` that keeps track of the passed `value`. | ||
*/ | ||
export declare function useLiveRef<T>(value: T): React.MutableRefObject<T>; |
import { AnyFunction } from "./types"; | ||
/** | ||
* A React custom hook similar to [`useAllCallbacks`](#useallcallbacks), but | ||
* it'll pass the returned value from a function to the next function. | ||
*/ | ||
export declare function usePipe(...fns: Array<AnyFunction | null | undefined>): (arg: any) => any; |
export declare type SealedInitialState<T> = T | (() => T); | ||
/** | ||
* React custom hook that returns the very first value passed to `initialState`, | ||
* even if it changes between re-renders. | ||
*/ | ||
export declare function useSealedState<T>(initialState: SealedInitialState<T>): T; |
import * as React from "react"; | ||
/** | ||
* A `React.useEffect` that will not run on the first render. | ||
*/ | ||
export declare function useUpdateEffect(effect: React.EffectCallback, deps?: ReadonlyArray<any> | undefined): void; |
@@ -0,1 +1,10 @@ | ||
/** | ||
* Logs `messages` to the console using `console.warn` based on a `condition`. | ||
* | ||
* @example | ||
* import { warning } from "reakit-utils"; | ||
* | ||
* warning(true, "a", "b"); // console.warn("a\nb") | ||
* warning(false, "a", "b"); // does nothing | ||
*/ | ||
export declare function warning(condition: boolean, ...messages: string[]): void; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
383716
193
3296
782