Skip to content

Commit

Permalink
Merge pull request #15 from palmerhq/feature/stylesheet
Browse files Browse the repository at this point in the history
Add Stylesheet, standardize errors, remove attribute copying, export element resources
  • Loading branch information
jaredpalmer authored Aug 18, 2018
2 parents b9fe78a + 0afeae3 commit ba9cdd4
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 94 deletions.
1 change: 0 additions & 1 deletion Audio.js

This file was deleted.

1 change: 0 additions & 1 deletion Img.js

This file was deleted.

2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,6 @@ export default App;

- [ ] `<IFrame>`
- [ ] `<Embed>`
- [ ] `<Stylesheet>`
- [ ] Better error handling

## Playing with Suspense

Expand Down
1 change: 0 additions & 1 deletion Script.js

This file was deleted.

1 change: 0 additions & 1 deletion Video.js

This file was deleted.

40 changes: 19 additions & 21 deletions example/App.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
import React from 'react';
import { Img, Script, Video, Audio } from 'react-async-elements';
import { Img, Script, Video, Audio, Stylesheet } from 'react-async-elements';
import { ErrorBoundary } from './ErrorBoundary';

function App() {
return (
<div className="App">
<h1>React Async Elements</h1>
<React.Placeholder delayMs={300} fallback={<div>loading....</div>}>
<Video
src="https://video.twimg.com/ext_tw_video/1029780437437014016/pu/vid/360x640/QLNTqYaYtkx9AbeH.mp4?tag=5"
autoPlay
style={{ maxWidth: '100%', margin: '2rem auto', display: 'block' }}
/>
<ErrorBoundary>
<Video
src="https://video.twimg.com/ext_tw_video/1029780437437014016/pu/vid/360x640/QLNTqYaYtkx9AbeH.mp4?tag=5"
autoPlay
style={{ maxWidth: '100%', margin: '2rem auto', display: 'block' }}
/>

<Audio
src="https://file-dnzavydoqu.now.sh/"
controls
/>
<Audio src="https://file-dnzavydoqu.now.sh/" controls />

<Img
src="https://source.unsplash.com/random/2000x1000"
style={{ maxWidth: '100%', margin: '2rem auto', display: 'block' }}
/>
<Img
src="https://source.unsplash.com/random/2000x1000"
style={{ maxWidth: '100%', margin: '2rem auto', display: 'block' }}
/>

<Script src="https://js.stripe.com/v3/" async>
{() =>
console.log(window.Stripe) || (
<h2>Oh, and Stripe.js has loaded too.</h2>
)
}
</Script>
<Script src="https://js.stripe.com/v3/" async>
{() => <h2>Oh, and Stripe.js has loaded too.</h2>}
</Script>

<Stylesheet href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.css" />
</ErrorBoundary>
</React.Placeholder>
</div>
);
Expand Down
18 changes: 18 additions & 0 deletions example/ErrorBoundary.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

export class ErrorBoundary extends React.Component {
state = { error: null };

componentDidCatch(error) {
this.setState({ error });
}
reset() {
this.setState({ error: null });
}
render() {
if (this.state.error !== null) {
return <span>Error!</span>;
}
return this.props.children;
}
}
28 changes: 14 additions & 14 deletions src/Audio.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import React from 'react';
import { createResource } from 'simple-cache-provider';
import { cache, waitForReadyState } from './shared';
import { createCache, createResource } from 'simple-cache-provider';
import { isBrowser } from './utils';

export const audioCache = createCache();
export const AudioResource = createResource(load, ({ src }) => src);

function load({ src }) {
const audio = document.createElement('audio');

function load(attributes) {
const { src, ...attrs } = attributes;
return new Promise((resolve, reject) => {
const audio = document.createElement('audio');
audio.oncanplay = resolve;
audio.onerror = reject;
audio.src = src;
Object.keys(attrs).forEach(name => audio.setAttribute(name, attrs[name]));
waitForReadyState(audio, resolve.bind(null, src));
});
}

const resource = createResource(load, ({ src }) => src);
export const Audio = props => {
if (isBrowser) {
AudioResource.read(audioCache, props);
}

export const Audio = ({ cache, ...props }) => {
resource.read(cache, props);
return <audio {...props} />;
};

Audio.defaultProps = {
cache,
};
24 changes: 12 additions & 12 deletions src/Img.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import React from 'react';
import { createResource } from 'simple-cache-provider';
import { cache } from './shared';
import { createCache, createResource } from 'simple-cache-provider';
import { isBrowser } from './utils';

export const imgCache = createCache();
export const ImgResource = createResource(load, ({ src }) => src);

function load({ src }) {
const image = new Image();

function load(image) {
const { src } = image;
return new Promise((resolve, reject) => {
const image = new Image();
image.onload = resolve;
image.onerror = reject;
image.src = src;
});
}

const resource = createResource(load, ({ src }) => src);
export const Img = props => {
if (isBrowser) {
ImgResource.read(imgCache, props);
}

export const Img = ({ cache, ...props }) => {
resource.read(cache, props);
return <img {...props} />;
};

Img.defaultProps = {
cache,
};
35 changes: 35 additions & 0 deletions src/Preload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react';
import { createCache, createResource } from 'simple-cache-provider';
import { isBrowser } from './utils';

export const preloadCache = createCache();
export const PreloadResource = createResource(
load,
({ href, as }) => `${href}.${as}`
);

function load({ href, as, media = 'all' }) {
const link = document.createElement('link');
link.rel = 'preload';
link.as = as;
link.media = media;
link.href = href;

return new Promise((resolve, reject) => {
link.onload = resolve;
link.onerror = reject;
document.body.appendChild(link);
});
}

export const Preload = ({ children, ...rest }) => {
if (isBrowser) {
PreloadResource.read(preloadCache, rest);
}

if (typeof children === 'function') {
return children();
}

return children;
};
25 changes: 11 additions & 14 deletions src/Script.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from 'react';
import { createResource } from 'simple-cache-provider';
import { cache } from './shared';
import { createCache, createResource } from 'simple-cache-provider';
import { isBrowser } from './utils';

function load(attributes) {
export const scriptCache = createCache();
export const ScriptResource = createResource(load, ({ src }) => src);

function load({ src }) {
const script = document.createElement('script');
Object.keys(attributes).forEach(name =>
script.setAttribute(name, attributes[name])
);
script.src = src;

return new Promise((resolve, reject) => {
script.onload = resolve;
Expand All @@ -17,18 +18,14 @@ function load(attributes) {
});
}

const resource = createResource(load, ({ src }) => src);

export const Script = ({ cache, children, ...props }) => {
resource.read(cache, props);
export const Script = ({ children, ...rest }) => {
if (isBrowser) {
ScriptResource.read(scriptCache, rest);
}

if (typeof children === 'function') {
return children();
}

return children;
};

Script.defaultProps = {
cache,
};
30 changes: 30 additions & 0 deletions src/Stylesheet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { createCache, createResource } from 'simple-cache-provider';
import { isBrowser } from './utils';

export const stylesheetCache = createCache();
export const StylesheetResource = createResource(
load,
({ href, media }) => `${href}.${media}`
);

function load({ href, media = 'all' }) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
link.media = media;

return new Promise((resolve, reject) => {
link.onload = resolve;
link.onerror = reject;
document.body.appendChild(link);
});
}

export const Stylesheet = props => {
if (isBrowser) {
StylesheetResource.read(stylesheetCache, props);
}

return <link {...props} />;
};
28 changes: 14 additions & 14 deletions src/Video.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import React from 'react';
import { createResource } from 'simple-cache-provider';
import { cache, waitForReadyState } from './shared';
import { createCache, createResource } from 'simple-cache-provider';
import { isBrowser } from './utils';

export const videoCache = createCache();
export const VideoResource = createResource(load, ({ src }) => src);

function load({ src }) {
const video = document.createElement('video');

function load(attributes) {
const { src, ...attrs } = attributes;
return new Promise((resolve, reject) => {
const video = document.createElement('video');
video.oncanplay = resolve;
video.onerror = reject;
video.src = src;
Object.keys(attrs).forEach(name => video.setAttribute(name, attrs[name]));
waitForReadyState(video, resolve.bind(null, src));
});
}

const resource = createResource(load, ({ src }) => src);
export const Video = props => {
if (isBrowser) {
VideoResource.read(videoCache, props);
}

export const Video = ({ cache, ...props }) => {
resource.read(cache, props);
return <video {...props} />;
};

Video.defaultProps = {
cache,
};
6 changes: 4 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from './Video';
export * from './Audio';
export * from './Img';
export * from './Preload';
export * from './Script';
export * from './Audio';
export * from './Stylesheet';
export * from './Video';
11 changes: 0 additions & 11 deletions src/shared.js

This file was deleted.

1 change: 1 addition & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isBrowser = typeof window !== 'undefined';

0 comments on commit ba9cdd4

Please sign in to comment.