Commit e08cb114 authored by Tasso Evangelista's avatar Tasso Evangelista Committed by Guilherme Gazzo
Browse files

Add Flow (#82)

parent 2524e531
[ignore]
[include]
[libs]
flow-typed
[lints]
[options]
[strict]
......@@ -54,7 +54,7 @@ Hook to generate a BEM-compatible `className` value for a component.
- `componentClassName` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the style class which identifies the component
- `modifiers` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the modifiers applied to the style class (optional, default `{}`)
- `classNames` **...[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the additional style classes appended to the `className`
- `classNames` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>** the additional style classes appended to the `className`
Returns **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** a BEM-compatible `className` in the format
`(<block>|<block>__<element>) [...(<block>--<modifier>|<block>__<element>--<modifier>)] [...classNames]`
......@@ -65,12 +65,12 @@ Hook to debounce the state updater function returned by hooks like `useState()`
#### Parameters
- `pair` **\[any, [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)]** the state and updater pair which will be debounced
- `pair.0` **any** the state value
- `pair.1` **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** the state updater function
- `pair` **\[any, function (): any]** the state and updater pair which will be debounced
- `pair.0` the state value
- `pair.1` the state updater function
- `delay` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of milliseconds to delay the updater
Returns **\[any, [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)]** a state value and debounced updater pair
Returns **any** a state value and debounced updater pair
### useDebouncedReducer
......@@ -78,12 +78,12 @@ Hook to create a reduced state with a debounced `dispatch()` function.
#### Parameters
- `reducer` **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** the reducer function
- `reducer` **function (any, any): any** the reducer function
- `initializerArg` **any** the initial state value or the argument passed to the initial state generator function
- `initializer` **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** the initial state generator function
- `initializer` **function (any): any** the initial state generator function
- `delay` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of milliseconds to delay the updater
Returns **\[any, [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)]** a state and debounced `dispatch()` function
Returns **any** a state and debounced `dispatch()` function
### useDebouncedState
......@@ -91,10 +91,10 @@ Hook to create a state with a debounced setter function.
#### Parameters
- `initialValue` **(any | [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function))** the initial state value or the initial state generator function
- `initialValue` **(any | function (): any)** the initial state value or the initial state generator function
- `delay` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of milliseconds to delay the updater
Returns **\[any, [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)]** a state and debounced setter function
Returns **any** a state and debounced setter function
### useDebouncedCallback
......@@ -102,11 +102,11 @@ Hook to memoize a debounced version of a callback.
#### Parameters
- `callback` **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** the callback to debounce
- `callback` **function (): any** the callback to debounce
- `delay` **[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)** the number of milliseconds to delay
- `deps` **([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;any> | [undefined](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/undefined))** the hook dependencies
- `deps` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;any>?** the hook dependencies
Returns **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** a memoized and debounced callback
Returns **function (): any** a memoized and debounced callback
### useExclusiveBooleanProps
......@@ -118,7 +118,7 @@ to choose styling variants.
- `props` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** the mutually exclusive boolean props
- Throws **[Error](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Error)** if two or more booleans props are set as true
- Throws **any** if two or more booleans props are set as true
### useMediaQuery
......@@ -126,9 +126,9 @@ Hook to listen to a media query.
#### Parameters
- `query` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)?** the CSS3 media query expression
- `query` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** the CSS3 media query expression
Returns **bool** `true` if the media query matches; `false` is it does not match or the query is not defined
Returns **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** `true` if the media query matches; `false` is it does not match or the query is not defined
### useMergedRefs
......@@ -137,9 +137,9 @@ while receiving a forwared ref.
#### Parameters
- `refs` **...([Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object) \| [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function))** the refs and callback refs that should be merged
- `refs` **...[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)&lt;Ref&lt;any>>** the refs and callback refs that should be merged
Returns **[function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)** a merged callback ref
Returns **any** a merged callback ref
### useToggle
......@@ -147,9 +147,9 @@ Hook to create a toggleable boolean state.
#### Parameters
- `initialValue` **(any | [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function))** the initial value or the initial state generator function
- `initialValue` **(any | function (): any)** the initial value or the initial state generator function
Returns **\[any, [function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/function)]** a state boolean value and a state toggler function
Returns **any** a state boolean value and a state toggler function
## Author
......
......@@ -2,6 +2,7 @@ module.exports = {
presets: [
'@babel/preset-env',
'@babel/preset-react',
'@babel/preset-flow',
],
plugins: [
'@babel/plugin-proposal-class-properties',
......
// flow-typed signature: 4daa25492655417e7c0763d1d0b30fbb
// flow-typed version: c6154227d1/invariant_v2.x.x/flow_>=v0.104.x
declare module invariant {
declare module.exports: (condition: boolean, message: string) => void;
}
......@@ -37,12 +37,14 @@
"@babel/core": "^7.6.4",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/preset-env": "^7.6.3",
"@babel/preset-flow": "^7.0.0",
"@rocket.chat/eslint-config": "^0.4.0",
"babel-eslint": "^10.0.3",
"documentation": "^12.1.2",
"eslint": "^6.5.1",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-react": "^7.16.0",
"flow-bin": "^0.110.1",
"invariant": "^2.2.4",
"jest": "^24.9.0",
"lint-staged": "^9.4.2",
......
export const fromCamelToKebabCase = (camelCaseString) =>
// @flow
export const fromCamelToKebabCase = (camelCaseString: string) =>
camelCaseString.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
export const debounce = (fn, delay) => {
export const debounce = (fn: (...Array<any>) => any, delay: number) => {
let timer;
let callback;
function f(...args) {
function f(...args: Array<any>) {
const context = this;
clearTimeout(timer);
callback = () => fn.apply(context, args);
......
// @flow
export * from './useClassName';
export * from './useDebouncedUpdates';
export * from './useDebouncedCallback';
......
// @flow
import { useMemo } from 'react';
import { fromCamelToKebabCase } from './helpers';
......@@ -5,25 +7,30 @@ import { fromCamelToKebabCase } from './helpers';
/**
* Hook to generate a BEM-compatible `className` value for a component.
*
* @param {string} componentClassName - the style class which identifies the component
* @param {Object} modifiers - the modifiers applied to the style class
* @param {...string} classNames - the additional style classes appended to the `className`
* @return {string} - a BEM-compatible `className` in the format
* @param componentClassName - the style class which identifies the component
* @param modifiers - the modifiers applied to the style class
* @param classNames - the additional style classes appended to the `className`
* @return a BEM-compatible `className` in the format
* `(<block>|<block>__<element>) [...(<block>--<modifier>|<block>__<element>--<modifier>)] [...classNames]`
*/
export const useClassName = (componentClassName, modifiers = {}, ...classNames) => useMemo(
() => [
componentClassName,
...Object.entries(modifiers)
.filter(([, value]) => !!value)
.map(([key, value]) => (typeof value === 'boolean'
? `${ componentClassName }--${ fromCamelToKebabCase(key) }`
: `${ componentClassName }--${ fromCamelToKebabCase(key) }-${ fromCamelToKebabCase(String(value)) }`)),
...classNames,
].filter(Boolean).join(' '),
[
componentClassName,
Object.entries(modifiers).reduce((deps, [name, value]) => [...deps, name, value], []),
JSON.stringify(classNames),
]
);
export const useClassName = (
componentClassName : string,
modifiers: Object = {},
...classNames: Array<string>
): string =>
useMemo(
() => [
componentClassName,
...Object.entries(modifiers)
.filter(([, value]) => !!value)
.map(([key, value]) => (typeof value === 'boolean'
? `${ componentClassName }--${ fromCamelToKebabCase(key) }`
: `${ componentClassName }--${ fromCamelToKebabCase(key) }-${ fromCamelToKebabCase(String(value)) }`)),
...classNames,
].filter(Boolean).join(' '),
[
componentClassName,
Object.entries(modifiers).reduce((deps, [name, value]) => [...deps, name, value], []),
JSON.stringify(classNames),
]
);
// @flow
import { useMemo } from 'react';
import { debounce } from './helpers';
......@@ -5,10 +7,14 @@ import { debounce } from './helpers';
/**
* Hook to memoize a debounced version of a callback.
*
* @param {function} callback the callback to debounce
* @param {number} delay the number of milliseconds to delay
* @param {*[]|undefined} deps the hook dependencies
* @return {function} a memoized and debounced callback
* @param callback the callback to debounce
* @param delay the number of milliseconds to delay
* @param deps the hook dependencies
* @return a memoized and debounced callback
*/
export const useDebouncedCallback = (callback, delay, deps) =>
export const useDebouncedCallback = (
callback: (...Array<any>) => any,
delay: number,
deps?: Array<any>
): ((...Array<any>) => any) =>
useMemo(() => debounce(callback, delay), Array.isArray(deps) ? [delay, ...deps] : undefined);
// @flow
import { useReducer, useState } from 'react';
import { useDebouncedCallback } from './useDebouncedCallback';
......@@ -5,31 +7,42 @@ import { useDebouncedCallback } from './useDebouncedCallback';
/**
* Hook to debounce the state updater function returned by hooks like `useState()` and `useReducer()`.
*
* @param {[*,function]} pair - the state and updater pair which will be debounced
* @param {*} pair.0 - the state value
* @param {function} pair.1 - the state updater function
* @param {number} delay - the number of milliseconds to delay the updater
* @return {[any,function]} - a state value and debounced updater pair
* @param pair - the state and updater pair which will be debounced
* @param pair.0 - the state value
* @param pair.1 - the state updater function
* @param delay - the number of milliseconds to delay the updater
* @return a state value and debounced updater pair
*/
export const useDebouncedUpdates = ([value, update], delay) => [value, useDebouncedCallback(update, delay, [])];
export const useDebouncedUpdates = (
[value, update]: [any, () => any],
delay: number
) => [value, useDebouncedCallback(update, delay, [])];
/**
* Hook to create a reduced state with a debounced `dispatch()` function.
*
* @param {function} reducer - the reducer function
* @param {*} initializerArg - the initial state value or the argument passed to the initial state generator function
* @param {function} initializer - the initial state generator function
* @param {number} delay - the number of milliseconds to delay the updater
* @return {[any,function]} - a state and debounced `dispatch()` function
* @param reducer - the reducer function
* @param initializerArg - the initial state value or the argument passed to the initial state generator function
* @param initializer - the initial state generator function
* @param delay - the number of milliseconds to delay the updater
* @return a state and debounced `dispatch()` function
*/
export const useDebouncedReducer = (reducer, initializerArg, initializer, delay) =>
export const useDebouncedReducer = (
reducer: (any, any) => any,
initializerArg: any,
initializer: (any) => any,
delay: number
) =>
useDebouncedUpdates(useReducer(reducer, initializerArg, initializer), delay);
/**
* Hook to create a state with a debounced setter function.
*
* @param {*|function} initialValue - the initial state value or the initial state generator function
* @param {number} delay - the number of milliseconds to delay the updater
* @return {[any,function]} - a state and debounced setter function
* @param initialValue - the initial state value or the initial state generator function
* @param delay - the number of milliseconds to delay the updater
* @return a state and debounced setter function
*/
export const useDebouncedState = (initialValue, delay) => useDebouncedUpdates(useState(initialValue), delay);
export const useDebouncedState = (
initialValue: any | () => any,
delay: number
) => useDebouncedUpdates(useState(initialValue), delay);
// @flow
import invariant from 'invariant';
/**
* Hook for asserting mutually exclusive boolean props. Useful for components that use boolean props
* to choose styling variants.
*
* @param {Object} props - the mutually exclusive boolean props
* @throws {Error} if two or more booleans props are set as true
* @param props - the mutually exclusive boolean props
* @throws if two or more booleans props are set as true
*/
export const useExclusiveBooleanProps = (props) =>
export const useExclusiveBooleanProps = (props: Object) =>
invariant(
Object.values(props).filter(Boolean).length <= 1,
`Only one property of [${ Object.keys(props).join(', ') }] should be true`
......
// @flow
import { useLayoutEffect, useState } from 'react';
/**
* Hook to listen to a media query.
*
* @param {string} [query] - the CSS3 media query expression
* @return {bool} - `true` if the media query matches; `false` is it does not match or the query is not defined
* @param [query] - the CSS3 media query expression
* @return `true` if the media query matches; `false` is it does not match or the query is not defined
*/
export const useMediaQuery = (query) => {
export const useMediaQuery = (query: string): bool => {
const [matches, setMatches] = useState(() => {
if (!query) {
return false;
......
// @flow
import { useCallback } from 'react';
import type { Ref } from 'react';
/**
* Hook to merge refs and callbacks refs into a single callback ref. Useful when your component need a internal ref
* while receiving a forwared ref.
*
* @param {...(Object|function)} refs - the refs and callback refs that should be merged
* @return {function} - a merged callback ref
* @param refs - the refs and callback refs that should be merged
* @return a merged callback ref
*/
export const useMergedRefs = (...refs) => useCallback((refValue) => {
export const useMergedRefs = (...refs: Array<Ref<any>>) => useCallback((refValue: any) => {
refs.filter(Boolean).forEach((ref) => {
if (typeof ref === 'function') {
ref(refValue);
return;
}
ref.current = refValue;
if (typeof ref === 'object') {
ref.current = refValue;
}
});
}, refs);
// @flow
import { useState } from 'react';
/**
* Hook to create a toggleable boolean state.
*
* @param {*|function} initialValue - the initial value or the initial state generator function
* @return {[*,function]} - a state boolean value and a state toggler function
* @param initialValue - the initial value or the initial state generator function
* @return a state boolean value and a state toggler function
*/
export const useToggle = (initialValue) => {
export const useToggle = (initialValue: any | () => any) => {
const [value, setValue] = useState(() => (typeof initialValue === 'function' ? !!initialValue() : !!initialValue));
return [value, (forcedValue) => setValue(typeof forcedValue !== 'undefined' ? forcedValue : !value)];
return [value, (forcedValue: any | () => any) => setValue(typeof forcedValue !== 'undefined' ? forcedValue : !value)];
};
// @flow
import { useMemo } from 'react';
export const useUniqueId = () => useMemo(() => Math.random().toString(36).slice(2), []);
export const useUniqueId = (): string =>
useMemo(() => Math.random().toString(36).slice(2), []);
......@@ -7311,6 +7311,11 @@ flatted@^2.0.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
 
flow-bin@^0.110.1:
version "0.110.1"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.110.1.tgz#24ac70bf0871a5d6bc181ba99801ded4d5e3b442"
integrity sha512-6FhvNKNvPQ523mx7sqNxTQvI/HgAWa/pbIsQuCst53qRqs387EFfYqgm4I3Zae5HLaVFacBwgWKmjKd92vf19w==
flush-write-stream@^1.0.0, flush-write-stream@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment