1.1.0 • Published 6 years ago

@vcnkit/decorators v1.1.0

Weekly downloads
1
License
MIT
Repository
-
Last release
6 years ago

VCNKit/Decorators

@vcnkit/decorators provides decorators for common functionality, like generating unique id='s and managing hover, focused and collapsed state.

Installation

NPM

$ npm install --save @vcnkit/decorators

Yarn

$ yarn add @vcnkit/decorators

Usage

uniqueId

Passes a getId function through props to the decorated component.
getId(identifier: string) returns the provided argument concatenated with a unique identifier for the component instance.

Subsequent calls to getId() with the same identifier within the same component instance will return the same generated id.

import * as React from 'react';
import { uniqueId } from '@vcnkit/decorators';

@uniqueId()
class SomeClassComponent extends React.Component {
    render() {
        const { getId, ...rest } = this.props;

        return (
            <div { ...rest }>
                <label htmlFor={ getId('input') }>Label</label>
                <input
                    id={ getId('input') }
                    type="text"
                />
            </div>
        );
    }
}

Stateless components can use the decorator by wrapping itself.

import { uniqueId } from '@vcnkit/decorators';

const SomeComponent = ({ getId, ...rest ) => (
    <div { ...rest }>
        <label htmlFor={ getId('input') }>Label</label>
        <input
            id={ getId('input') }
            type="text"
        />
    </div>
);

export default uniqueId()(SomeComponent);

hoverable

Provides decorated components with a hovering-prop. This prop tells the component if the user is currently hovering over the element.

import * as React from 'react';
import { hoverable } from '@vcnkit/decorators';

@hoverable()
class SomeClassComponent extends React.Component {
    render() {
        const { hovering, onMouseEnter, onMouseOut, ...rest } = this.props;

        return (
            <div
                onMouseEnter={ onMouseEnter }
                onMouseOut={ onMouseOut }
                { ...rest }
            >
                { hovering ? 'User is hovering over this div!' : 'User is not hovering over this div' }
            </div>
        );
    }
}

Stateless components can use the decorator by wrapping itself.

import { hoverable } from '@vcnkit/decorators';

const SomeComponent = ({ hovering, onMouseEnter, onMouseOut, ...rest ) => (
    <div
        onMouseEnter={ onMouseEnter }
        onMouseOut={ onMouseOut }
        { ...rest }
    >
        { hovering ? 'User is hovering over this element!' : 'User is not hovering over this element' }
    </div>
);

export default hoverable()(SomeComponent);    

focusable

Provides decorated components with a focused-prop. This prop tells the component if the component currently has focus, or if focusOnChildFocus is true if a child component has focus.

focusable(focusOnChildFocus: bool)

This decorator will not provide a tabIndex prop, the component itself is responsible for giving itself or it's children a tabIndex prop.

import * as React from 'react';
import { focusable } from '@vcnkit/decorators';

@focusable()
class SomeClassComponent extends React.Component {
    render() {
        const { focused, onFocus, onBlur, ...rest } = this.props;

        return (
            <div
                onFocus={ onFocus }
                onBlur={ onBlur }
                tabIndex={ 0 }
                { ...rest }
            >
                { focused ? 'Element has focus' : 'Element does not have focus' }
            </div>
        );
    }
}

Stateless components can use the decorator by wrapping itself.

import { focusable } from '@vcnkit/decorators';

const SomeComponent = ({ hovering, onMouseEnter, onMouseOut, ...rest ) => (
    <div
        onFocus={ onFocus }
        onBlur={ onBlur }
        tabIndex={ 0 }
        { ...rest }
    >
        { focused ? 'Element has focus' : 'Element does not have focus' }
    </div>
);

export default focusable()(SomeComponent);    

expandable

Provides decorated components with a collapsed-prop. This can either by controlled by internal state or managed by parent components by attaching an onChange-prop to the decorated component. The current and initial state can be defined by attaching an collapsed-prop to the decorated component.

import * as React from 'react';
import { expandable } from '@vcnkit/decorators';

@expandale()
class SomeClassComponent extends React.Component {
    render() {
        const { collapsed, onChange, ...rest } = this.props;

        return (
            <div
                { ...rest }
            >
                <h1 onClick={ onChange }>Click here to toggle</h1>
                { !collapsed && <p>Expanded</p> }
            </div>
        )
    }
}

Stateless components can use the decorator by wrapping itself.

import { expandable } from '@vcnkit/decorators';

const SomeComponent = ({ collapsed, onChange, ...rest ) => (
    <div
        { ...rest }
    >
        <h1 onClick={ onChange }>Click here to toggle</h1>
        { !collapsed && <p>Expanded</p> }
    </div>
);

export default expandable()(SomeComponent);    

Decorating a class or stateless component with multiple decorators

If you want a component to have both the hoverable and focusable decorators, you can simply chain them.

import * as React from 'react';
import { hoverable, focusable } from '@vcnkit/decorators';

@focusable()
@hoverable()
class SomeClassComponent extends React.Component {
    render() {
        const { hovering, focused, ...rest } = this.props;

        return (
            <div
                tabIndex={ 0 }
                { ...rest }
            >
                { hovering ? 'User is hovering over this element!' : 'User is not hovering over this element' }
                { focused ? 'Element has focus' : 'Element does not have focus' }
            </div>            
        )
    }
}

And for stateless components

import { hoverable, focusable } from '@vcnkit/decorators';

/*
 * ...rest will contain all the necessary event handlers. onMouseEnter, onMouseOut, onFocus and onBlur
 */
const SomeComponent = ({ hovering, focused, ...rest }) => (
    <div
        tabIndex={ 0 }
        { ...rest }
    >
        { hovering ? 'User is hovering over this element!' : 'User is not hovering over this element' }
        { focused ? 'Element has focus' : 'Element does not have focus' }
    </div>
);

export default focusable()(hoverable()(SomeComponent))

Attaching refs to decorated components

The decorators in @vcnkit/decorators utilize React's forwardRef API to pass refs to the decorated components.

Using React's createRef API:

import * as React from 'react';
import { hoverable } from '@vcnkit/decorators';

@hoverable()
class MyDecoratedComponent extends React.Component {
    ...
}

class MyComponent extends React.Component {
    constructor(props) {
        super(props);

        // This will hold a ref to 'MyDecoratedComponent' instead of the decorator itself.
        this.ref = React.createRef();
    }

    render() {
        return (
            <MyDecoratedComponent
                ref={ this.ref }
            />
        )
    }
}

Or, using a callback ref:

import * as React from 'react';
import { hoverable } from '@vcnkit/decorators';

@hoverable()
class MyDecoratedComponent extends React.Component {
    ...
}

class MyComponent extends React.Component {
    render() {
        return (
            <MyDecoratedComponent
                ref={ ref => { this.ref = ref; } }
            />
        )
    }
}
1.1.0

6 years ago

1.0.0

6 years ago

0.1.0

6 years ago

0.0.1

6 years ago

0.0.0

6 years ago