Skip to content

Commit 527a3be

Browse files
authored
Updating Simple Pattern Documentation (#354)
1 parent 5005742 commit 527a3be

File tree

7 files changed

+199
-17
lines changed

7 files changed

+199
-17
lines changed

docs/docs/examples/simple-carousel.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function reducer(state: CarouselState, action: CarouselAction): CarouselState {
8686

8787
Then, building upon the reducer logic, the `<Carousel>` is constructed. We hold the number of items within a count of `numItems`. We utilize the reducer within the `React.useReducer` hook.
8888

89-
By creating `slide`, as a `const`, we can utilize that later in the component, calling it within `useSwipeable`: called upon `slide(NEXT)` and `slide(PREV)`, invoking the `dispatch` and the `timeout` we built within `slide`. Within the use of `useSwippeable`, we set `swipeDuration` to `500ms`. We set `preventScrollOnSwipe` to `true`, and `trackMouse` to `true`.
89+
By creating `slide`, as a `const`, we can utilize that later in the component, calling it within `useSwipeable`: called upon `slide(NEXT)` and `slide(PREV)`, invoking the `dispatch` and the `timeout` we built within `slide`. Within the use of `useSwipeable`, we set `swipeDuration` to `500ms`. We set `preventScrollOnSwipe` to `true`, and `trackMouse` to `true`.
9090

9191
At the end, we return the component itself, built with the components we've created, with `handlers` passed into the wrapping `<div>` around the surrounding container. The `<CarouselContainer>` holds the directional and sliding state, and within that container the items we want to display are mapped as `React.Children`, utilizing `getOrder`.
9292

docs/docs/examples/simple-pattern.mdx

+189
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,194 @@ import SimplePattern from '@site/src/components/examples/SimplePattern'
44

55
# Simple Pattern
66

7+
Below is an example implementation of a simple pattern which utilizes the hooks provided by `react-swipeable` within a TypeScript context.
8+
9+
## Simple Pattern Code Source
10+
11+
You can see this full example as pure code within the [Pattern.tsx](https://github.com/FormidableLabs/react-swipeable/blob/main/examples/app/SimplePattern/pattern.tsx) file within the React-Swipeable repo directly.
12+
13+
## Simple Pattern Live Preview
14+
715
<SimplePattern />
816

17+
## Simple Pattern Code Explained
18+
19+
Import the hook directly from the `react-swipeable` library, along with the directions from the library, and the `SwipeEventData`. In our example, we built and imported a local set of UI components: you can utilize your own UI and styling, or use your favorite UI component library of choice.
20+
21+
```typescript
22+
import React, { FunctionComponent, ReactNode } from 'react';
23+
import { useSwipeable, UP, DOWN, SwipeEventData } from 'react-swipeable';
24+
import {
25+
Wrapper,
26+
CarouselContainer,
27+
CarouselSlot,
28+
PatternBox,
29+
PREV,
30+
NEXT,
31+
D
32+
} from '../components';
33+
```
34+
35+
In our example, we utilize SVGs for our `UpArrow` and `DownArrow` to give indications of when someone is successfully activating the pattern for user feedback, but know you can use whatever UI library of your choice, or stylize your own!
36+
37+
```typescript
38+
const UpArrow = ({active}: {active: boolean}) => (
39+
<svg viewBox="0 0 16 16" version="1.1" style={{width: '15px'}}>
40+
<g transform="translate(-35.399 -582.91)">
41+
<path style={{fill: active ? '#EEEE00' : '#000000'}} d="m40.836 598.91v-6.75h-5.4375l4-4.625 4-4.625 4 4.625 4 4.625h-5.0938v6.75h-5.4688z" />
42+
</g>
43+
</svg>
44+
);
45+
46+
const DownArrow = ({active}: {active: boolean}) => (
47+
<svg viewBox="0 0 16 16" version="1.1" style={{width: '15px'}}>
48+
<g transform="translate(-35.399 -598.91)">
49+
<path style={{fill: active ? '#EEEE00' : '#000000'}} d="m40.836 598.91v6.75h-5.4375l4 4.625 4 4.625 4-4.625 4-4.625h-5.0938v-6.75h-5.4688z" />
50+
</g>
51+
</svg>
52+
);
53+
```
54+
55+
Next, we set up our types for the `Directions`, `CarouselState`, and `CarouselAction`.
56+
57+
```typescript
58+
type Direction = typeof PREV | typeof NEXT;
59+
60+
interface CarouselState {
61+
pos: number;
62+
sliding: boolean;
63+
dir: Direction;
64+
}
65+
66+
type CarouselAction =
67+
| { type: Direction, numItems: number }
68+
| { type: 'stopSliding' };
69+
```
70+
71+
Below, we create a function called `getOrder`, which drives the position of each item in the carousel, and what order of position each will be displayed in the context of the carousel. Then, we set a `pattern` as an array of the pattern we want the user to follow to unlock the slide action. Finally here, we then set `getInitialState`, setting the position of the initial items, the `sliding`, as false, and the direction.
72+
73+
```typescript
74+
75+
const getOrder = (index: number, pos: number, numItems: number) => {
76+
return index - pos < 0 ? numItems - Math.abs(index - pos) : index - pos;
77+
};
78+
79+
const pattern = [UP, DOWN, UP, DOWN];
80+
81+
const getInitialState = (numItems: number): CarouselState => ({ pos: numItems - 1, sliding: false, dir: NEXT });
82+
83+
```
84+
85+
At the bottom of the file, we set up a reducer for controlling the action of the Carousel utilizing a switch to set the `CarouselState` logic.
86+
87+
```typescript
88+
function reducer(state: CarouselState, action: CarouselAction): CarouselState {
89+
switch (action.type) {
90+
case PREV:
91+
return {
92+
...state,
93+
dir: PREV,
94+
sliding: true,
95+
pos: state.pos === 0 ? action.numItems - 1 : state.pos - 1
96+
};
97+
case NEXT:
98+
return {
99+
...state,
100+
dir: NEXT,
101+
sliding: true,
102+
pos: state.pos === action.numItems - 1 ? 0 : state.pos + 1
103+
};
104+
case 'stopSliding':
105+
return { ...state, sliding: false };
106+
default:
107+
return state;
108+
}
109+
}
110+
```
111+
112+
Then, building upon the reducer logic, the `<Carousel>` is constructed. We hold the number of items within `numItems`, and utilize the reducer within the `React.useReducer` hook.
113+
114+
By creating the `slide`, as a `const`, we can utilize that to call within `handleSwiped` as an action that is called upon the user successfully execution of the pattern.
115+
116+
It may help to briefly look at the `handlers` for a moment, and how we utilize `useSwipeable`. Within this, with each `onSwiped`, we call `handleSwiped`. So for each swipe the user takes within the text box above the carousel, we execute `handleSwiped` and pass along the `eventData`. If the `eventData.dir` matches the pattern for this indexed (`pIdx`) item, and the direction indicated, then we `setPIdx` to a greater number.
117+
118+
What does this do? Two things: it helps us know when the user successfully got to the end of the pattern, and activate the `slide` action, and it also controls the arrows activating the color within the `<PatternBox>` to give feedback to the user that they were successful in activating the steps of the pattern!
119+
120+
Two other important items to note: we utilized `onTouchStartOrOnMouseDown` to pass through `event.preventDefault()` as a callback, and used `touchEventOptions: {passive: false}` in case certain browsers ignored the `preventDefault()` callback bubbling up.
121+
122+
From there, the rest of the UI of the component is built. The `<PatternBox>` holds where the user swipes in order to interact with the Carousel itself, along with the arrows that give the feedback to the user that the pattern was successful. The `<CarouselContainer>` holds the Carousel display and items. Our Simple Pattern is complete!
123+
124+
```typescript
125+
const Carousel: FunctionComponent<{children: ReactNode}> = (props) => {
126+
const numItems = React.Children.count(props.children);
127+
const [state, dispatch] = React.useReducer(reducer, getInitialState(numItems));
128+
129+
const slide = (dir: Direction) => {
130+
dispatch({ type: dir, numItems });
131+
setTimeout(() => {
132+
dispatch({ type: 'stopSliding' });
133+
}, 50);
134+
};
135+
136+
const [pIdx, setPIdx] = React.useState(0);
137+
138+
const handleSwiped = (eventData: SwipeEventData) => {
139+
if (eventData.dir === pattern[pIdx]) {
140+
// user successfully got to the end of the pattern!
141+
if (pIdx + 1 === pattern.length) {
142+
setPIdx(pattern.length);
143+
slide(NEXT);
144+
setTimeout(() => {
145+
setPIdx(0);
146+
}, 50);
147+
} else {
148+
// user is cont. with the pattern
149+
setPIdx((i) => (i += 1));
150+
}
151+
} else {
152+
// user got the next pattern step wrong, reset pattern
153+
setPIdx(0);
154+
}
155+
};
156+
157+
const handlers = useSwipeable({
158+
onSwiped: handleSwiped,
159+
onTouchStartOrOnMouseDown: (({ event }) => event.preventDefault()),
160+
touchEventOptions: { passive: false },
161+
preventScrollOnSwipe: true,
162+
trackMouse: true
163+
});
164+
165+
return (
166+
<>
167+
<PatternBox {...handlers}>
168+
Swipe the pattern below, within this box, to make the carousel go to the next
169+
slide
170+
{`\n`}
171+
<p style={{textAlign: 'center', paddingTop: '15px'}}>
172+
Swipe:
173+
<D><UpArrow active={pIdx > 0} /></D>
174+
<D><DownArrow active={pIdx > 1} /></D>
175+
<D><UpArrow active={pIdx > 2} /></D>
176+
<D><DownArrow active={pIdx > 3} /></D>
177+
</p>
178+
</PatternBox>
179+
<div style={{paddingBottom: '15px'}}>
180+
<Wrapper>
181+
<CarouselContainer dir={state.dir} sliding={state.sliding}>
182+
{React.Children.map(props.children, (child, index) => (
183+
<CarouselSlot
184+
key={index}
185+
order={getOrder(index, state.pos, numItems)}
186+
>
187+
{child}
188+
</CarouselSlot>
189+
))}
190+
</CarouselContainer>
191+
</Wrapper>
192+
</div>
193+
</>
194+
);
195+
};
196+
```
197+

docs/src/components/examples/SimplePattern/index.tsx

-7
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@ function SimplePattern() {
1515
<Item src={Product4} />
1616
<Item src={Product5} />
1717
</Carousel>
18-
<h6>
19-
<a href="https://github.com/FormidableLabs/react-swipeable/blob/main/examples/app/SimplePattern/pattern.tsx">
20-
See code
21-
</a>{" "}
22-
for example usage of <code>onTouchStartOrMouseDown</code> and{" "}
23-
<code>touchEventOptions</code>
24-
</h6>
2518
</div>
2619
);
2720
}

docs/src/components/examples/SimplePattern/pattern.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ const Carousel: FunctionComponent<{ children: ReactNode }> = (props) => {
102102
return (
103103
<>
104104
<PatternBox {...handlers}>
105-
Swipe the pattern below, within this box, to make the carousel go to the
106-
next slide
105+
Within this text area container, swipe the pattern seen below to make
106+
the carousel navigate to the next slide.
107107
{`\n`}
108108
<p style={{ textAlign: "center", paddingTop: "15px" }}>
109109
Swipe:

docs/src/components/examples/components.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,10 @@ export const SlideButton = styled.button<{ float: "left" | "right" }>`
6565
`;
6666

6767
export const PatternBox = styled.div`
68-
padding: 30px;
68+
padding: 10px;
69+
border: 1px solid black;
70+
margin: 10px auto 20px auto;
71+
text-align: center;
6972
`;
7073

7174
export const D = styled.span`

examples/app/SimplePattern/index.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Carousel from './pattern';
77
function SimplePattern() {
88
return (
99
<div>
10-
<h5 style={{ marginBottom: '20px' }}>
10+
<h5 style={{ marginBottom: '20px'}}>
1111
<strong>👉 Swipe pattern</strong>
1212
</h5>
1313
<Carousel>
@@ -17,9 +17,6 @@ function SimplePattern() {
1717
<Item img="https://unsplash.it/478/205" />
1818
<Item img="https://unsplash.it/479/205" />
1919
</Carousel>
20-
<h6>
21-
<a href="https://github.com/FormidableLabs/react-swipeable/blob/main/examples/app/SimplePattern/pattern.tsx">See code</a> for example usage of <code>onTouchStartOrMouseDown</code> and <code>touchEventOptions</code>
22-
</h6>
2320
</div>
2421
);
2522
}

examples/app/SimplePattern/pattern.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ const Carousel: FunctionComponent<{children: ReactNode}> = (props) => {
9090
return (
9191
<>
9292
<PatternBox {...handlers}>
93-
Swipe the pattern below, within this box, to make the carousel go to the next
94-
slide
93+
Within this text area container, swipe the pattern seen below to make
94+
the carousel navigate to the next slide.
9595
{`\n`}
9696
<p style={{textAlign: 'center', paddingTop: '15px'}}>
9797
Swipe:

0 commit comments

Comments
 (0)