Skip to content

Commit d54c6ba

Browse files
authored
Merge pull request #8 from MailOnline/feat/various
Feat/various
2 parents 61e4d98 + 4f91f47 commit d54c6ba

35 files changed

+954
-14
lines changed

.travis.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
language: node_js
2+
os:
3+
- linux
4+
cache:
5+
yarn: true
6+
directories:
7+
- ~/.npm
8+
notifications:
9+
email: false
10+
node_js:
11+
- '9'
12+
- '8'
13+
script:
14+
- npm run test
15+
- npm run build
16+
matrix:
17+
allow_failures: []
18+
fast_finish: true
19+
after_success:
20+
- npm run semantic-release
21+
branches:
22+
except:
23+
- /^v\d+\.\d+\.\d+$/

README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
![libreact logo](./docs/libreact.png)
2+
13
# libreact
24

35
[![][npm-badge]][npm-url] [![][travis-badge]][travis-url]
@@ -39,13 +41,15 @@ const MyComponent = mock();
3941
- [`<NetworkSensor>`](./docs/NetworkSensor.md) and [`withNetwork()`](./docs/NetworkSensor.md#withnetwork)
4042
- [`<LightSensor>`](./docs/LightSensor.md)
4143
- [`<LocationSensor>`](./docs/LocationSensor.md)
44+
- [`<OrientationSensor>`](./docs/OrientationSensor.md) and [`withOrientation()`](./docs/OrientationSensor.md#withorientation)
4245
- [`<ScrollSensor>`](./docs/ScrollSensor.md)
4346
- [`<SizeSensor>`](./docs/SizeSensor.md)
44-
- `<ViewportSensor>`
47+
- [`<ViewportSensor>`](./docs/ViewportSensor.md), `<ViewportScrollSensor>`, and `<ViewportObserverSensor>`
4548
- [`<WidthSensor>`](./docs/WidthSensor.md)
4649
- [`<WindowScrollSensor>`](./docs/WindowScrollSensor.md)
4750
- [`<WindowSizeSensor>`](./docs/WindowSizeSensor.md)
4851
- Generators
52+
- [`<Alert>`](./docs/Alert.md)
4953
- [`<Audio>`](./docs/Audio.md)
5054
- [`<LocalStorage>`](./docs/LocalStorage.md)
5155
- `<Redirect>`

docs/Alert.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# `<Alert>`
2+
3+
Uses [`Window.alert()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) to display message ot a user.
4+
5+
## Usage
6+
7+
```jsx
8+
import {Alert} from 'libreact/lib/Alert';
9+
10+
<Alert show text='Hello world' />
11+
```
12+
13+
## Props
14+
15+
- `show` - boolean, optional, whether to show the alert.
16+
- `text` - string, require, string message to display to the user.

docs/LocalStorage.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import {LocalStorage} from 'libreact/lib/LocalStorage';
2424
- `onMount` - optional, callback that receives stored data on component mount. Useful to persist and
2525
re-hydrate form data, for example.
2626

27-
# Example
27+
## Example
2828

2929
In the below example form inputs are stored in `localStorage` and re-hydrated when user
3030
comes back and form renders for the first time.

docs/OrientationSensor.md

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# `<OrientationSensor>`
2+
3+
Tracks screen orientation using [`orientationchange` event](https://developer.mozilla.org/en-US/docs/Web/Events/orientationchange).
4+
5+
## Usage
6+
7+
```jsx
8+
import {OrientationSensor} from 'libreact/lib/OrientationSensor';
9+
10+
<OrientationSensor>(state) =>
11+
<pre>{JSON.stringify(state, null, 4)}</pre>
12+
</OrientationSensor>
13+
```
14+
15+
## Props
16+
17+
None.
18+
19+
## State
20+
21+
Has signature
22+
23+
```ts
24+
interface IOrientationSensorState {
25+
angle: number;
26+
type: string;
27+
}
28+
```
29+
30+
, where
31+
32+
- `angle` - screen rotation angle in degrees.
33+
- `type` - is one of `portrait-primary`, `portrait-secondary`, `landscape-primary`, or `landscape-secondary`.
34+
35+
36+
## `withOrientation()`
37+
38+
HOC that injects `orientation` object into your component.
39+
40+
41+
```js
42+
import {withOrientation} from 'libreact/lib/OrientationSensor';
43+
44+
const MyCompWithOrientation = withOrientation(MyComp);
45+
```

docs/Prompt.md

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# `<Prompt>`
2+
3+
Uses [`Window.prompt()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt) to get user input.
4+
5+
## Usage
6+
7+
Use it as a standalone compnent that returns result in `onResult` handler
8+
9+
```jsx
10+
import {Prompt} from 'libreact/lib/Prompt';
11+
12+
<Prompt
13+
show
14+
message='Hello world'
15+
default='hello back'
16+
onResult={console.log}
17+
/>
18+
```
19+
20+
Or use it as a FaCC
21+
22+
```jsx
23+
<Prompt
24+
show
25+
message='Hello world'
26+
default='hello back'
27+
onResult={console.log}
28+
>{(result) => <div>{result}</div>}</Prompt>
29+
```
30+
31+
## Props
32+
33+
- `show` - boolean, optional, whether to show the prompt modal.
34+
- `message` - string, optional, string message to display to the user.
35+
- `default` - string, optional, default text to pre-fill the user's response input.
36+
- `onResult` - function, optional, function that receives prompt result string as a single argument.

docs/ViewportSensor.md

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# `<ViewportSensor>`
2+
3+
Tracks if `children` are in viewport. Can be used as FaCC or a regular component.
4+
5+
Under-the-hood it uses `<ViewportObserverSensor>`, which in turn uses [`IntersectionObserver`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) API
6+
to detect if your component is in viewport.
7+
8+
If `IntersectionObserver` API is not available it falls back and lazily downloads `<ViewportScrollSensor>`,
9+
which uses document's scroll event to track if your component is in viewport.
10+
11+
## Usage
12+
13+
```jsx
14+
import {ViewportSensor} from 'libreact/lib/ViewportSensor';
15+
16+
<ViewportSensor threshold={1} onChange={console.log}>{(state) =>
17+
<pre>{JSON.stringify(state, null, 4)}</pre>
18+
}</ViewportSensor>
19+
```
20+
21+
## Props
22+
23+
Sensor's props have the following signature
24+
25+
```ts
26+
interface IViewportSensorProps {
27+
threshold?: number;
28+
onChange?: (state: IViewportObserverSensorState) => void;
29+
}
30+
```
31+
32+
, where
33+
34+
- `threshold` - optional, number, percentage how much does your component have to intersect with viewport
35+
to be considered visible. Defaults to `0`.
36+
- `onChange` - optional, callback called when sensor changes its state, receives the state of the sensor as
37+
a single argument.
38+
39+
## State
40+
41+
Sensor's state has the following signature
42+
43+
```ts
44+
interface IViewportSensorState {
45+
visible: boolean;
46+
}
47+
```
48+
49+
## `<ViewportScrollSensor>`
50+
51+
The `<ViewportScrollSensor>` has an additional prop `throttle`, which is a number in milliseconds specifying
52+
how much to throttle document's `scroll` event.

docs/getDisplayName.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# `getDisplayName()`
2+
3+
Returns display name of a React component.
4+
5+
```jsx
6+
import getDisplayName from 'libreact/lib/util/getDisplayName';
7+
8+
const name = getDisplayName(MyComponent);
9+
```
10+
11+
Accepts a single argument, which can be a stateful or stateless React component, or element. Returns a string.

docs/libreact.png

34.9 KB
Loading

package.json

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "libreact",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "React standard library",
55
"main": "lib/index.js",
66
"keywords": [
@@ -55,7 +55,8 @@
5555
"ts-loader": "3.2.0",
5656
"ts-node": "4.1.0",
5757
"typescript": "2.6.2",
58-
"webpack": "3.10.0"
58+
"webpack": "3.10.0",
59+
"semantic-release": "^12.2.4"
5960
},
6061
"config": {
6162
"commitizen": {
@@ -72,7 +73,8 @@
7273
"test:watch": "jest --watch",
7374
"storybook": "start-storybook -p 6007",
7475
"build-storybook": "build-storybook",
75-
"start": "npm run storybook"
76+
"start": "npm run storybook",
77+
"semantic-release": "semantic-release"
7678
},
7779
"jest": {
7880
"moduleFileExtensions": [

src/Alert/__story__/story.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import {createElement as h} from 'react';
2+
import {storiesOf} from '@storybook/react';
3+
import {action} from '@storybook/addon-actions';
4+
import {linkTo} from '@storybook/addon-links';
5+
import {Alert} from '..';
6+
import ShowDocs from '../../../.storybook/ShowDocs'
7+
8+
storiesOf('Generators/Alert', module)
9+
.add('Documentation', () => h(ShowDocs, {name: 'Alert'}))
10+
.add('Basic example', () => <Alert show text='Hello world' />)
11+
.add('Don\'t show', () => <Alert show={false} text='You shall not see this' />);

src/Alert/index.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {PureComponent} from 'react';
2+
import {noop, isClient} from '../util';
3+
4+
export interface IAlertProps {
5+
show?: boolean;
6+
text?: string;
7+
}
8+
9+
export class Alert extends PureComponent<IAlertProps, any> {
10+
componentDidMount () {
11+
this.alert();
12+
}
13+
14+
componentDidUpdate () {
15+
this.alert();
16+
}
17+
18+
alert () {
19+
const {show, text} = this.props;
20+
21+
if (show) {
22+
alert(text);
23+
}
24+
}
25+
26+
render () {
27+
return null;
28+
}
29+
}

src/LocationSensor/__tests__/index.test.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ describe('<LocationSensor>', () => {
3434
);
3535
});
3636

37-
3837
describe('re-renders on', () => {
3938
const events = [
4039
'pushstate',
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {createElement as h} from 'react';
2+
import {storiesOf} from '@storybook/react';
3+
import {action} from '@storybook/addon-actions';
4+
import {linkTo} from '@storybook/addon-links';
5+
import {OrientationSensor, withOrientation} from '..';
6+
import ShowDocs from '../../../.storybook/ShowDocs'
7+
8+
const Print = ({orientation}) =>
9+
<pre style={{fontFamily: 'monospace'}}>
10+
{JSON.stringify(orientation, null, 4)}
11+
</pre>;
12+
13+
const PrintOrientation = withOrientation(Print);
14+
15+
storiesOf('Sensors/OrientationSensor', module)
16+
.add('Documentation', () => h(ShowDocs, {name: 'OrientationSensor'}))
17+
.add('FaCC', () =>
18+
<OrientationSensor>{(state) =>
19+
<pre style={{fontFamily: 'monospace'}}>{JSON.stringify(state, null, 4)}</pre>
20+
}</OrientationSensor>
21+
)
22+
.add('HOC', () => <PrintOrientation />);

src/OrientationSensor/index.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import {Component} from 'react';
2+
import {SyncSensor} from '../SyncSensor';
3+
import {h, on, off, isClient} from '../util';
4+
5+
export interface IOrientationSensorProps {
6+
children?: (state: IOrientationSensorState) => React.ReactElement<any>;
7+
}
8+
9+
export interface IOrientationSensorState {
10+
angle: number;
11+
type: string;
12+
}
13+
14+
const DEFAULT = {
15+
angle: 0,
16+
type: 'landscape-primary'
17+
};
18+
19+
const addListener = (handler) => on(window, 'orientationchange', handler);
20+
const removeListener = (handler) => off(window, 'orientationchange', handler);
21+
const onEvent = () => {
22+
const {orientation} = screen as any;
23+
24+
if (!orientation) {
25+
return DEFAULT;
26+
}
27+
28+
const {
29+
angle,
30+
type
31+
} = orientation;
32+
33+
return {
34+
angle,
35+
type
36+
};
37+
};
38+
39+
const getInitialState = () => {
40+
return isClient ? onEvent() : DEFAULT;
41+
};
42+
43+
export class OrientationSensor extends Component<IOrientationSensorProps, any> {
44+
initial = getInitialState();
45+
46+
render () {
47+
return h(SyncSensor, {
48+
children: this.props.children,
49+
initial: this.initial,
50+
addListener,
51+
removeListener,
52+
onEvent
53+
});
54+
}
55+
}
56+
57+
export const withOrientation = (Comp) =>
58+
(props) =>
59+
h(OrientationSensor, null, (orientation) =>
60+
h(Comp, {
61+
...props,
62+
orientation
63+
})
64+
);

0 commit comments

Comments
 (0)