@vcnkit/decorators v1.1.0
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/decoratorsYarn
$ yarn add @vcnkit/decoratorsUsage
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; } }
/>
)
}
}