npm package: @ranji94/instant
Description: <p align="center">     <img alt="InstantLibrary" src="/images/logo.jpeg" width="60" /> </p> <h1 align="center">   Instant </h1>
Author: ranji94
Latest version: 0.0.8

<p align="center">
    <img alt="InstantLibrary" src="/images/logo.jpeg" width="60" />
</p>
<h1 align="center">
  Instant
</h1>

React library providing easy-to-use tools to simplify most popular implementation cases in react apps, in order to speed up development process and save time.

## 🚀 Quick start

## Install library
Just simply add library to your project using package manager:

```shell
npm install @ranji94/instant
```

Or using yarn:

```shell
yarn add @ranji94/instant
```


## Tools usage

1. **useClickOutside hook**
```jsx
import React, { useRef } from 'react'
import { useClickOutside } from '@ranji94/instant'

const FooComponent = () => {
    const checkedElementReference = useRef()

    // You can put multiple refs of elements to check
    const { isClickedOutside } = useClickOutside([checkedElementReference])

    return (<>
        // Clicking in referenced element sets "isClickedOutside" state to false
        <div ref={checkedElementReference}>
            <h1>Checked element</h1>
        </div>

        // Clicking here (or somewhere else) sets "isClickedOutside" state to true
        <div>
            <h1>Outside element</h1>
        </div>

        <div>
            Is user clicked outside of checked element: {isClickedOutside ? 'Yes' : 'No'}
        </div>
    </>)
}
```

2. **useFetch hook**
```jsx
import React from 'react'
import { useFetch, FETCH_STATUS } from '@ranji94/instant'

const FOO_API = 'https://foo-api.com'
const FOO_ENDPOINT = 'resources'

const FooComponent = ({ payload }) => {
    const exampleOptions = {
        credentials: 'same-origin',
        body: JSON.stringify(payload),
        headers: {
            'Custom-Header': 'custom header value',
        }
    }

    // Options parameters are optional. Method GET and standard headers are set by default
    const { status, data } = useFetch(`${FOO_API}/${FOO_ENDPOINT}`, exampleOptions)

    const { FETCHING, FETCHED, FAILED, ABORTED } = FETCH_STATUS

    if (status === FETCHING) {
        return <>Loading data</>
    }

    if (status === FETCHED) {
        return <>Fetched data ... {data}</>
    }

    if (status === FAILED) {
        return <>Error handler ... {data}</>
    }

    if (status === ABORTED) {
        return <>Request aborted ... {data}</>
    }
}
```

Triggered fetch example (combined with Switch/Case/Default component):

```jsx
import React, { useState } from 'react'
import { useFetch, FETCH_STATUS } from '@ranji94/instant'
import { Switch, Case, Default } from '@ranji94/components'

const DOG_API_BASE = 'https://dog.ceo/api/breed'
const DOG_IMAGE_SUFFIX = 'images/random'

const FooComponent = ({ payload }) => {
    /*  
        Null as default value stops initial-fetch 
        In given example hook listens to changes on url parameter.
        
        useFetch hook also listening to changes on options parameter, so
        you can simply put body payload or headers and result will be
        re-fetched.
    */
    const [url, setUrl] = useState(null)
    const { status, data } = useFetch(url)

    const { FETCHING, FETCHED, FAILED, ABORTED, IDLE } = FETCH_STATUS

    const onFetchDogImageClick = (dogRace) => {
        setUrl(`${DOG_API_BASE}/${dogRace}/${DOG_IMAGE_SUFFIX}`)
    }

    return (<>
        <button onClick={() => onFetchDogImageClick('terrier-yorkshire')}>Fetch Yorkshire Terrier image </button>
        <button onClick={() => onFetchDogImageClick('shihtzu')}>Fetch Shihtzu image </button>
        <button onClick={() => onFetchDogImageClick('borzoi')}>Fetch Yorkshire Terrier image </button>

        <Switch value={status}>
            <Case case={FETCHING}>Loading data ...</Case>
            <Case case={FETCHED}>
                <h1>Dog image:</h1>
                <img src={data.message} />
            </Case>
            <Case case={FAILED}>Error while fetching data: {data}...</Case>
            <Case case={ABORTED}>Fetching aborted</Case>
            <Case case={IDLE}>Press click to button, to fetch data</Case>
            <Default>Other status</Default>
        </Switch>
    </>)
}
```

3. **useScrollPosition hook**

```jsx
import React from 'react'
import { useScrollPosition } from '@ranji94/instant'

const FooComponent = () => {
    const scrollPosition = useScrollPosition()

    return <>
        Current Y scroll position: {scrollPosition}
    </>
}
```

4. **useValidation hook**
```jsx
import React from 'react'
import { useValidation, Validator } from '@ranji94/instant'
import { TextInput } from 'any-ui-library'

const FooComponent = () => {
    const [text, setText] = useState('')

    /* Sequence of provided validators matters.
       Lower index in validators array = higher validation priority */
    const validators = [
        new Validator(text.length < 10, 'Text should contains at least 10 characters'),
        new Validator(!isNaN(text), 'Text cannot be numeric value')
    ]

    const validation = useValidation(text, validators)

    const onChange = (event) => {
        setText(event.target.value)
    }

    return <>
        <TextInput onChange={onChange} value={text} isError={validation.isError} />
        
        {/* No error = null error message */}
        <div>{validation.message}</div>
    </>
}
```

5. **Object manipulator utility**
```js

function fooFunction () {
    const person = {
        name: 'Jan',
        surName: 'Kowalski',
        address: {
            postalCode: '68-200',
            city: 'Zary'
            street: {
                name: 'Okrzei',
                number: 1
            }
        }
    }
    const personManipulator = objectManipulator(person)

    // Sets street number to null
    personManipulator.clear('address.street.number')

    // Update name
    personManipulator.update('name', 'Janusz')

    // Remove surname
    personManipulator.remove('surName')

    // You can also extract FIELD enum and use them to manipulate object:
    const PERSON_FIELD = personManipulator.fields()
    const PERSON_ADDRESS_FIELD = personManipulator.fields(PERSON_FIELD.ADDRESS)

    // Update using built FIELD enums
    personManipulator.update(PERSON_FIELD.NAME, 'Dariusz')
    personManipulator.update(`${PERSON_FIELD.ADDRESS}.${PERSON_ADDRESS_FIELD.CITY}`, 'Kalisz')

    // Is object contains parameter
    const isPersonAgeAvailable = personManipulator.contains('age')

    // Get nested object/array/value
    const nestedObject = personManipulator.get('address.street')

    // Get immutable result:
    console.log(personManipulator.get())
    // or mutable modified person object:
    console.log(person)
    /*
        Returned result:
        {
            name: 'Dariusz',
            address: {
                postalCode: '68-200',
                city: 'Kalisz'
                street: {
                    name: 'Okrzei',
                    number: null
                }
            }
        }
    */
}
```

6. **Switch-case conditional render**
```jsx
import React, { useState } from 'react'
import { Switch, Case, Default } from '@ranji94/components'


const FooComponent = ({ payload }) => {
    const [case, setCase] = useState(null)

    const CASE = Object.freeze({
        ONE: 'ONE',
        TWO: 'TWO',
        THREE: 'THREE'
    })

    return (<>
        <button onClick={() => setCase(CASE.ONE)}>SET CASE ONE</button>
        <button onClick={() => setCase(CASE.TWO)}>SET CASE TWO</button>
        <button onClick={() => setCase(CASE.THREE)}>SET CASE THREE</button>

        <Switch value={case}>
            <Case case={CASE.ONE}>Showing case 1</Case>
            <Case case={CASE.TWO}>Showing case 2</Case>
            <Case case={CASE.THREE}>Showing case 3</Case>
            <Default>Showing default</Default>
        </Switch>
    </>)
}
```