Skip to content

Commit

Permalink
Add useDebounceEvent stories (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
sahariko committed Dec 27, 2021
1 parent 08592e3 commit 6e92948
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 1 deletion.
4 changes: 4 additions & 0 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
ComponentRules,
ComponentName,
UsageGuidelines,
FunctionArguments,
FunctionArgument,
RelatedComponents,
DocFooter,
MultipleStoryElementsWrapper,
Expand Down Expand Up @@ -37,6 +39,8 @@ addParameters({
Tip,
ComponentRules,
UsageGuidelines,
FunctionArguments,
FunctionArgument,
RelatedComponents
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ exports[`TextField renders correctly when disabled 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -102,6 +103,7 @@ exports[`TextField renders correctly when loading 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__loader--container"
Expand Down Expand Up @@ -200,6 +202,7 @@ exports[`TextField renders correctly when readonly 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -271,6 +274,7 @@ exports[`TextField renders correctly when required 1`] = `
required={true}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -342,6 +346,7 @@ exports[`TextField renders correctly with another type 1`] = `
required={false}
role=""
type="password"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -413,6 +418,7 @@ exports[`TextField renders correctly with className 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -484,6 +490,7 @@ exports[`TextField renders correctly with className 2`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -555,6 +562,7 @@ exports[`TextField renders correctly with icon 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-has-icon input-component__icon--container-active"
Expand Down Expand Up @@ -634,6 +642,7 @@ exports[`TextField renders correctly with iconsNames 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -705,6 +714,7 @@ exports[`TextField renders correctly with id 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -776,6 +786,7 @@ exports[`TextField renders correctly with labelIconName 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -847,6 +858,7 @@ exports[`TextField renders correctly with large size 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -918,6 +930,7 @@ exports[`TextField renders correctly with placeholder 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -989,6 +1002,7 @@ exports[`TextField renders correctly with role 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -1060,6 +1074,7 @@ exports[`TextField renders correctly with secondaryIconName 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-has-icon input-component__icon--container-active"
Expand Down Expand Up @@ -1139,6 +1154,7 @@ exports[`TextField renders correctly with showCharCount 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -1220,6 +1236,7 @@ exports[`TextField renders correctly with validation 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down Expand Up @@ -1373,6 +1390,7 @@ exports[`TextField renders correctly with wrapperClassName 1`] = `
required={false}
role=""
type="text"
value=""
/>
<div
className="input-component__icon--container input-component__icon--container-active"
Expand Down
125 changes: 125 additions & 0 deletions src/hooks/useDebounceEvent/__stories__/useDebounceEvent.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { useState } from 'react';
import { Story, Canvas, Meta, ArgsTable } from "@storybook/addon-docs";
import useDebounceEvent from "..";
import "../../__stories__/general-hooks-stories.scss";

<Meta title="Hooks/useDebounceEvent" />

# useDebounceEvent

- [Overview](#overview)
- [Arguments](#arguments)
- [Returns](#returns)
- [Usage](#usage)
- [Use cases and examples](#use-cases-and-examples)
- [Feedback](#feedback)

## Overview

This hook generates an easy to use debounced value updater.

<Canvas>
<Story name="Overview">
{() => {
const { inputValue, onEventChanged } = useDebounceEvent({ delay: 100 });
return (
<input type="text" value={inputValue} onChange={onEventChanged}/>
);
}}
</Story>
</Canvas>

## Arguments

<FunctionArguments>
<FunctionArgument name="options" type="Object">
<FunctionArgument name="trim" type="boolean" description="Whether to trim the value or not." default="false" />
<FunctionArgument
name="onChange"
type="(value: string) => void"
description="Callback function to execute on changes."
default="() => null"
/>
<FunctionArgument
name="delay"
type="number"
description="The amount of time (in ms) to delay the value's update."
default="0"
/>
<FunctionArgument name="initialStateValue" type="any" description="The initial value." />
</FunctionArgument>
</FunctionArguments>

## Returns

<FunctionArguments>
<FunctionArgument name="result" type="Object">
<FunctionArgument name="inputValue" type="any" description="The hook's value." />
<FunctionArgument
name="onEventChanged"
type="(event: Event) => void"
description={<>A wrapper around the passed <code>onChange</code> function.</>}
/>
<FunctionArgument
name="clearValue"
type="() => void"
description="Clears the current value."
/>
<FunctionArgument
name="updateValue"
type="(value: any) => void"
description="Updates the current value."
/>
</FunctionArgument>
</FunctionArguments>

## Usage

<UsageGuidelines
guidelines={["Use this hook when you need to debounce value updates (for example, text inputs)."]}
/>

## Use cases and examples

### Passing an initial value

<Canvas>
<Story name="Passing an initial value">
{() => {
const { inputValue, onEventChanged } = useDebounceEvent({ initialStateValue: 'bla bla bla' });
return (
<input type="text" value={inputValue} onChange={onEventChanged}/>
);
}}
</Story>
</Canvas>

### Passing an `onChange` handler

<Canvas>
<Story name="Passing an `onChange` handler">
{() => {
const [length, setLength] = useState(0);
const { inputValue, onEventChanged } = useDebounceEvent({ onChange: (value) => setLength(value.length) });
return (
<>
<input type="text" value={inputValue} onChange={onEventChanged}/>
{ <span>Input has {length} characters</span> }
</>
);
}}
</Story>
</Canvas>

### Trimming the value

<Canvas>
<Story name="With trim">
{() => {
const { inputValue, onEventChanged } = useDebounceEvent({ trim: true });
return (
<input type="text" value={inputValue} onChange={onEventChanged}/>
);
}}
</Story>
</Canvas>
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useMemo, useCallback, useState, useRef, useEffect } from "react";
import debounce from "lodash/debounce";
import noop from "lodash/noop";

export default function useDebounceEvent({ delay = 0, onChange, initialStateValue, trim }) {
export default function useDebounceEvent({ delay = 0, onChange = noop, initialStateValue = "", trim }) {
const [inputValue, setValue] = useState(initialStateValue);
const previousValue = useRef(null);

Expand Down
13 changes: 13 additions & 0 deletions src/storybook/components/function-arguments/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# FunctionArguments

A list that documents a function's signature.

## Guidelines

- There is no unique syntax for creating a UsageGuideline component in MDX files. Therefore, use the component as you would in a regular JSX file.

## Props

| Prop | Description |
| ---------- | ------------------------------------------------ |
| `children` | `<li>`s that represent the function's arguments. |
31 changes: 31 additions & 0 deletions src/storybook/components/function-arguments/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";
import PropTypes from "prop-types";
import { Code } from "@storybook/components"; // eslint-disable-line import/no-extraneous-dependencies
import classes from "./index.module.scss";

export const FunctionArgument = ({ children, name, type, description, default: defaultValue }) => (
<li className={classes.argument}>
<code className={classes["argument-name"]}>{name}</code>
<code className={classes["argument-type"]}>{type}</code>
{description && <> - {description}</>}
{defaultValue && (
<>
{" "}
Defaults to: <Code>{defaultValue}</Code>
</>
)}
{children && <ul>{children}</ul>}
</li>
);

export const FunctionArguments = ({ children }) => {
return <ul>{children}</ul>;
};

FunctionArguments.propTypes = {
children: PropTypes.oneOfType([FunctionArgument, PropTypes.arrayOf(FunctionArgument)])
};

FunctionArguments.defaultProps = {
children: []
};
41 changes: 41 additions & 0 deletions src/storybook/components/function-arguments/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@import "../../../styles/global-css-settings.scss";
@import "../../styles/content-spacing";
@import "../../styles/typography";

.argument {
ul {
padding: 0;
}

.argument {
margin-left: 20px;
}
}

.argument-name,
.argument-type,
.default-value {
font-family: monaco, monospace;
font-size: 85%;
}

.argument-name {
margin-right: 5px;
}

.argument-type {
color: var(--color-purple);

&:before,
&:after {
color: var(--color-winter);
}

&:before {
content: "<";
}

&:after {
content: ">";
}
}
1 change: 1 addition & 0 deletions src/storybook/components/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Frame } from "./frame/frame";
import { VisualDescription } from "./visual-description/visual-description";
import { ColorsDescription } from "./colors-description/colors-description";

export * from "./function-arguments";
export {
SectionName,
Title,
Expand Down

0 comments on commit 6e92948

Please sign in to comment.