0.10.4 • Published 3 years ago

@cdoublev/react-utils v0.10.4

Weekly downloads
12
License
MIT
Repository
github
Last release
3 years ago

CircleCI

React Utils

About

This package contains common hooks and components to use in a React application.

Installation

npm i @cdoublev/react-utils

@cdoublev/react-utils is built to run in the current version of NodeJS, which means it should be transpiled with your application using its own targets.

API

Hooks

useAnimate

useAnimate abstracts using Element.animate() from the Web Animation API (MDN).

useAnimate :: Ref -> Animate

Ref should be a React reference object containing an Element, ie. Ref => { current: Element }.

Animate is a Function that has the following signature: Animate :: (Keyframes -> Options?|Number?) -> Animation.

Animation (W3C) will be cancelled if it's still running when the component unmounts.

Example: CodePen

useAnimateCustom

useAnimateCustom abstracts using animate(), a lightweight alternative to Element.animate() or its official polyfill, with some extra features.

Note: this hook relies on @cdoublev/animate as an optional dependency to install manually.

useAnimateCustom :: Ref -> Animate

Ref should be a React reference object containing an Element, ie. Ref => { current: Element }.

Animate is a Function that has the following signature: Animate :: (Keyframes|MotionPath -> Options?|Number?) -> Animation.

Animation conforms to the native Animation (W3C). It will be cancelled if it's still running when the component unmouts.

Example: CodePen

Related:

useIntersectionObserver

useIntersectionObserver abstracts using an IntersectionObserver to execute a function when an Element intersects an ancestor, ie. when it enters in or exits from its viewport.

useIntersectionObserver :: Configuration -> [CallbackRef, Identifier -> CallbackRef, Ref]

The first CallbackRef should be used to define root, ie. an ancestor containing the Elements to observe, defined with the second callback ref obtained by executing the higher order function with an Identifier (String|Number|Symbol) for each Element to observe.

Both should be used. root will default to null (ie. document) when the corresponding callback ref is executed without an argument. null can't be used to set root to document because React will execute the callback ref with null before unmount, if it's used as a ref prop.

Ref is a React object ref containing the current IntersectionObserver. It can be used eg. to manually unobserve a target after a first intersection.

Each observed Element will be unobserved before unmount, and the current IntersectionObserver will be disconnected before root unmounts, except if root corresponds to document, as it could be shared with other components. Only one IntersectionObserver will be created for each unique set of intersection options.

Example: CodePen

Configuration:

  • rootMargin and threshold are two of the three IntersectionObserver options (W3C), the third being root
  • onEnter and onExit are optional callbacks executed with the arguments received from the IntersectionObserver callback when an Element enters in or exits from the viewport of its ancestor

Note: make sure to use a memoized value for threshold if it's an Array, as well as for onEnter and onExit.

useInterval

Credit: Dan Abramov.

useInterval abstracts using setInterval() and clearInterval() to schedule and repeat the execution of a function over time, without worrying about cancelling the timer to avoid a memory leak such as a React state update on an unmounted component.

useInterval :: [Function, Number] -> void

It will stop executing Function if:

  • the component unmounts
  • the reference to Function has changed
  • the delay (Number) has changed

useGatherMemo

useGatherMemo abstracts gathering (merging) and/or picking (destructuring) properties from object(s) while memoizing the result to avoid unneeded updates in the component and its children.

It's a low level hook that can be usefull eg. when you want to merge options or props received in a hook or a component with a large default options object, instead of listing each option argument with a default value and/or listing each one as a dependency of a hook.

useGatherMemo :: (Object -> ...String|Symbol) -> [x, Object]

Example:

const options = { color: 'red', size: 'large' }

/**
 * 1. Pick prop(s) and gather the rest
 *
 * Both constants will be defined with a memoized value/reference, if `options`
 * shallow equals its previous render value
 */

// Write this:
const [color, subOptions] = useGatherMemo(options, 'color')
// Instead of this:
const { color, ...subOptions } = options

/**
 * 2. Gather properties
 *
 * `allOptions` will be defined with a memoized reference, if `subOptions`
 * shallow equals its previous render value.
 */

// Write this:
const allOptions = useGatherMemo({ ...subOptions, display: 'fullscreen' })
// Instead of this:
const allOptions = { ...subOptions, display: 'fullscreen' }

Warning: don't over use it, ie. use it only with large objects, otherwise it will negatively impact performances by increasing the call stack as well as the amount of data stored in memory.

useLazyStateUpdate

useLazyStateUpdate abstracts delaying a state update.

Give it a state value and a delay (default to 100 ms) and it will update the component and return the corresponding state when delay is over.

It could be used eg. to delay the render of an error notice after validating an input value updated on each user input.

useLazyStateUpdate :: [a, Number] -> a

useMediaQuery

useMediaQuery abstracts using windows.matchMedia() to observe a match against a query, eg. (min-width: 50em).

useMediaQuery :: String -> Boolean

useScrollIntoView

useScrollIntoView abstracts using Element.scrollIntoView() when a scroll event is emitted.

Depending on the scroll direction, it prevents the default scroll behavior and scrolls into view the next or previous Element, on:

  • ✅ touch (finger or stylus) move
  • ✅ wheel (rolling)
  • ❌ wheel (button)

useScrollIntoView :: Configuration -> [CallbackRef, Identifier -> CallbackRef, Ref]

The first CallbackRef should be used to define root, ie. an ancestor containing the Elements to scroll into view, defined with the second callback ref, obtained by executing the higher order function with a unique Identifier (String|Number|Symbol) for each Element.

Both should be used. To set document as root, the corresponding callback ref should be executed without an argument. See useIntersectionObserver to know why, since this hook is used to set the previous/next Element to scroll into view when an Element enters in the viewport of root.

Ref is a React object ref containing the current IntersectionObserver.

Example:

Configuration:

  • beforeScroll is an optional callback executed before scrolling, that can be used to set the Element to scroll into view (by returning its index value in targets) or eg. to set a CSS transition classname before scrolling, and receiving as arguments (1) the index of the target that will be scrolled into view, (2) the current target index and (3) the scrolling direction (up, down, left, or right)
  • delay (default to 200 ms) is a timeout value before scrolling
  • directions (default to both) is the scroll direction to listen on (x, y, or both)
  • wait (default to 1000 ms) is a timeout value between two authorized scroll events
  • mode (default to auto) is the scrolling behavior
  • onEnter and onExit are optional callbacks defined in useIntersectionObserver
  • touchSensitivity (default to 150) is a distance in pixels that the finger or stylus should move to be handled as a scroll event

useSVGMousePosition

useSVGMousePosition abstracts translating the position of the mouse relative to an <svg> in document, into a position relative to its viewBox.

It could be used eg. to animate the position of a child SVGElement (paths, filters, clips, masks, gradients, etc...).

useSVGMousePosition :: Configuration -> [Position, CallbackRef, CallbackRef]

Position are the coordinates of the mouse: Position => { x: Float, y: Float }.

The first CallbackRef should be used to define the <svg>. Using both callbacks is usefull to listen mousemove events in an ancestor Element containing the <svg> and animate the position of a child SVGElement outside of the <svg>.

Note: the <svg> should preserve its aspect ratio, otherwise Position will be incorrect, as the current implementation is using Element.getBoundingClientRect() to compute its dimensions.

Example: CodePen

Configuration:

  • hasRoot (default to false) is an optional boolean to make sure that the mouseover event listener will be registered only when the <svg> is mounted, eg. if it's conditionally rendered in its root component
  • initial (default to { x: 0, y: 0 }) is an optional initial position
  • isFixed (default to false) is an optional Boolean to flag the target as having a fixed position in the viewport of document, ie. in window
  • precision (default to 2) is an optional number to round Position values

useTimeout

useTimeout abstracts using setTimeout() and clearTimeout() to schedule the execution of a Function, without worrying about cancelling the timer to avoid a memory leak such as a React state update on an unmounted component.

useTimeout :: [Function, Number] -> void

It will stop executing Function if:

  • the component unmounts
  • the reference to Function has changed
  • the delay (Number) has changed

useTransition

useTransition abstracts scheduling multiple state updates over time using different delays and durations.

It will always return the current state as a collection, which can be conceptualized as a box whose values are entering and exiting in and out over time. It can be used eg. to transition between CSS classnames when a component did mount or before unmouting.

useTransition :: { transitions: [Transition], onExit?: Transition } -> [[x], Restart, Exit?, Boolean?, Enter?]

A Transition ([x, Number, Number?]) is a collection of a state value (x) and one or two Numbers: the first value is the delay before applying the given state, and the second value is the duration during which it should be applied, except for the Transition defined on onExit, defined only with a duration.

Note: transitions should be memoized, otherwhise the inital state will always be applied.

Exit, Enter, and the Boolean are returned only when onExit is provided. Exit is a Function to execute the Transition defined on onExit before toggling the Boolean value to false, indicating that the component can be considered as unmounted. Enter is a Function to toggle this value back to true.

Demo: CodePen.

Related packages:

useValidation

useValidation abstracts using the Constraint Validation API (MDN) to validate a form field on blur (default) or on change.

useValidation :: { onChange?: Function, onBlur?: Function, validateOnChange?: Boolean } -> [String, Props]

It returns any error message from the Constraint Validation API, and a collection of component properties such as onChange and onBlur event handlers, to assign to an <input>, <select> or <textarea>. Each of those handlers will be composed with a corresponding handler given as argument.

Components

Filter

<Filter> provides common filter effects to use in a SVGElement.

Usage for a single filter effect:

<svg viewBox='0 0 100 100'>
  <Filter id='glow-large' name='glow' blur='10' spread='3' opacity='0.3' />
  <Filter id='glow-small' name='glow' blur='5'  spread='2' opacity='0.7' />
  <circle filter='url(#glow-large)' cx='25' cy='25' r='25'>
  <circle filter='url(#glow-small)' cx='75' cy='75' r='25'>
</svg>

When used alone, <Filter> should not have a in or result and it will automatically be wrapped in a <filter> with the following default prop values:

  • 'colorInterpolation' (for the color-interpolation-filter attribute): 'sRGB'
  • 'id': 'name'
  • 'width' and 'height': based on 'name'
  • 'x' and 'y': based on 'width' and 'height'

'width', 'height', 'x', 'y' should be provided as percentage values.

All effect's names are listed further below.

Usage for composing filter effects:

<svg viewBox='0 0 100 100'>
  <filter id='glow-noise' x='-100%' y='-100%' height='300%' width='300%'>
    <Filter name='glow' blur='10' spread='3' />
    <Filter name='noise' in='glow' opacity='0.2' frequency='0.2' />
  </filter>
  <circle filter='url(#glow-noise)' cx='50' cy='50' r='25'>
</svg>

When composed, <Filter>s should have a in and eventually a result prop (defaults to name and not required for the last <Filter> in the composition).

Effect names and props:

NameProps
color-correctionlightness, opacity, saturation
glowblur, spread, lightness, opacity
glow-insetblur, threshold, lightness, opacity
gooeytolerance
noisefrequency, blend, color, lightness, opacity
shadowcolor, offsetX, offsetY, blur, spread, threshold, opacity, saturation
shadow-insetcolor, offsetX, offsetY, blur, spread, threshold, opacity, saturation

Default values:

  • color: 'black'
  • lightness: 1
  • opacity: 0.5
  • offsetX: 0
  • offsetY: 0
  • saturation: 1
  • spread: 0
  • threshold: 0

All props require a number, except blend (CSS blend mode) and color (CSS color).

0.10.4

3 years ago

0.10.3

3 years ago

0.10.2

3 years ago

0.10.1

3 years ago

0.10.0

3 years ago

0.9.1

3 years ago

0.9.0

3 years ago

0.8.2

3 years ago

0.8.1

4 years ago

0.8.0

4 years ago

0.7.4

4 years ago

0.7.3

4 years ago

0.7.2

4 years ago

0.7.1

4 years ago

0.7.0

4 years ago

0.6.4

4 years ago

0.6.3

4 years ago

0.6.2

4 years ago

0.6.1

4 years ago

0.6.0

4 years ago

0.5.4

4 years ago

0.5.3

4 years ago

0.5.2

4 years ago

0.5.1

4 years ago

0.5.0

5 years ago

0.4.0

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.0

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago