Skip to content

Commit

Permalink
Add React and Vue components, examples, and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
davidyuk committed Nov 30, 2020
1 parent e6b7bde commit 0c49ed9
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 17 deletions.
9 changes: 8 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
language: node_js
node_js: 12

script: npm run build
install:
- npm i
- npm i --prefix examples/react-webpack
- npm i --prefix examples/vue-webpack

script:
- npm run build
- npm run build:examples

deploy:
- provider: script
Expand Down
29 changes: 27 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@ You can import and process styles manually by importing `dist/index.css` and
`dist/index-without-styles.js` separately. Or even you can don't import styles at
all, and write your own instead.

### React and Vue versions
By default `dist/index.js` is imported, instead of this, you can import a specific
version for React or Vue by importing `dist/react-without-styles.js` or
`dist/vue-without-styles.js` accordingly. The framework-specific version contains
all features available in the default one plus specific for particular framework wrappers.

## Usage

### Button (`superheroUtils.createButton`)
### Button

#### `superheroUtils.createButton`
This library exports a function that creates buttons. This function accepts arguments:
- class name of nodes that should become buttons, or the DOM node itself
(this option simplifies integration into Frontend frameworks like Vue/React)
- options object

Option | Description
Expand Down Expand Up @@ -58,6 +65,24 @@ Size value | Screenshot
`medium` | <img width="189" alt="medium" src="https://user-images.githubusercontent.com/13139371/96836937-56ba8100-144e-11eb-9e3b-4e4c92b9bbb4.png">
`large` | <img width="140" alt="large" src="https://user-images.githubusercontent.com/13139371/81780943-0387ee00-9500-11ea-8108-2e5939821a7b.png">

#### `superheroUtils.createButtonByDiv`

The same function as the previous one except that the first argument should be an
instance of `HTMLDivElement`. The button content will be added to that node instead of
the DOM node replacing. The function with this interface simplifies integration into
Frontend frameworks like Vue and React.

#### `superheroUtils.Button` (only in React and Vue versions)

The component that is compatible with the corresponding framework. Accepts the same
properties as [`superheroUtils.createButton`](#superheroutilscreatebutton)'s options.

#### Example

```html
<Button size="large" account="example.chain" url="https://example.com" />
```

### Paywall (`superheroUtils.ensurePaid`)
This function asks the user to send a tip to the specified page. It won't ask to send a
tip if it was sent before using the current browser. The function accepts options object.
Expand Down
9 changes: 9 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
<h3>superhero-utils example using plain js</h3>

Other examples:
<a href="/react-unpkg.html">react unpkg</a>,
<a href="/react-webpack/build">react webpack</a>,
<a href="/vue-unpkg.html">vue unpkg</a>,
<a href="/vue-webpack/dist">vue webpack</a>

<hr>
<div class="icon">Donate</div>
<div class="small">Donate</div>
<div class="medium">Donate</div>
Expand Down
22 changes: 22 additions & 0 deletions examples/react-unpkg.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div id="app"></div>

<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/prop-types@15/prop-types.min.js"></script>
<script src="./superhero-utils/react-without-styles.js"></script>
<link rel="stylesheet" href="./superhero-utils/index.css">
<script>
class App extends React.Component {
render() {
return React.createElement('div', {}, [
React.createElement('h3', {}, ['superhero-utils example using react, script tag']),
React.createElement(
superheroUtils.Button,
{ size: 'medium', account: 'ak_... or .chain name' },
),
]);
}
}

ReactDOM.render(React.createElement(App), document.querySelector('#app'));
</script>
6 changes: 5 additions & 1 deletion examples/react-webpack/src/App.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import './superhero-utils/index.css';
import { Button as SuperheroButton } from './superhero-utils/react-without-styles.js';

function App() {
return (
<div>
Example payload
<h3>superhero-utils example using react, webpack</h3>
<SuperheroButton size="medium" account="ak_... or .chain name" />
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions examples/react-webpack/src/superhero-utils
22 changes: 22 additions & 0 deletions examples/vue-unpkg.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div id="app"></div>

<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="./superhero-utils/vue-without-styles.js"></script>
<link rel="stylesheet" href="./superhero-utils/index.css">
<script>
const App = {
components: {
SuperheroButton: superheroUtils.Button,
},
template: `
<div>
<h3>superhero-utils example using vue, script tag</h3>
<SuperheroButton size="medium" account="ak_... or .chain name" />
</div>
`,
};

new Vue({
render: h => h(App),
}).$mount('#app');
</script>
14 changes: 13 additions & 1 deletion examples/vue-webpack/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
<template>
<div>
Example payload
<h3>superhero-utils example using vue, webpack</h3>
<SuperheroButton size="medium" account="ak_... or .chain name" />
</div>
</template>

<script>
import '../../superhero-utils/index.css';
import { Button } from '../../superhero-utils/vue-without-styles.js';
export default {
components: {
SuperheroButton: Button,
},
}
</script>
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
"webpack": "^5.9.0",
"webpack-cli": "^4.2.0"
},
"optionalDependencies": {
"prop-types": "^15.7.2",
"react": "^17.0.1"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "npm run build && serve examples",
Expand Down
13 changes: 6 additions & 7 deletions src/button/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const getTipAmount = async (url) => {
return tips.find(u => u.url === url)?.total_amount_ae || 0;
};

const createButtonInstance = ({ size = 'icon', url = window.location.href, account, ...options }) => {
export const createButtonByDiv = (divElement, { size = 'icon', url = window.location.href, account, ...options }) => {
// data-account attribute is needed claiming
const genLink = (text = '') => `
<a
Expand All @@ -45,16 +45,15 @@ const createButtonInstance = ({ size = 'icon', url = window.location.href, accou
};

if (!templates[size]) throw new Error('Unsupported size');
const button = document.createElement('div');
button.innerHTML = templates[size];
button.className = `superhero-utils-button ${size}`;
divElement.innerHTML = templates[size];
divElement.className = `superhero-utils-button ${size}`;

(async () => {
const tipsEl = button.querySelector('.tips');
const tipsEl = divElement.querySelector('.tips');
if (tipsEl) tipsEl.innerHTML = await getTipAmount(url);
})();

return button;
return divElement;
};

export default (selectorOrElement, options = {}) => {
Expand All @@ -63,7 +62,7 @@ export default (selectorOrElement, options = {}) => {
: selectorOrElement;

const handleElement = element => {
const instance = createButtonInstance(options);
const instance = createButtonByDiv(document.createElement('div'), options);
element.replaceWith(instance);
return instance;
};
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import './global.scss';
export { default as createButton } from './button';
export { default as createButton, createButtonByDiv } from './button';
export { default as ensurePaid } from './paywall';
23 changes: 23 additions & 0 deletions src/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export * from './index';
import React from 'react';
import PropTypes from 'prop-types';
import { createButtonByDiv } from './index';

export class Button extends React.Component {
constructor(props) {
super(props);
this.button = React.createRef();
this.componentDidMount = this.componentDidUpdate = () =>
createButtonByDiv(this.button.current, this.props);
}

render() {
return React.createElement('div', { ref: this.button });
}
}

Button.propTypes = {
size: PropTypes.oneOf(['icon', 'small', 'medium', 'large']),
url: PropTypes.string,
account: PropTypes.string,
};
23 changes: 23 additions & 0 deletions src/vue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export * from './index';
import { createButtonByDiv } from './index';

export const Button = {
props: {
size: {
validator: value => ['icon', 'small', 'medium', 'large'].includes(value),
default: undefined,
},
url: { type: String, default: undefined },
account: { type: String, default: undefined },
},
mounted() {
this.$watch(
({ size, url, account }) => ({ size, url, account }),
(props) => createButtonByDiv(this.$refs.button, props),
{ immediate: true },
);
},
render(createElement) {
return createElement('div', { ref: 'button' });
},
};
25 changes: 21 additions & 4 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,29 @@ const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const genConfig = (filename, { inlineCss } = {}) => ({
const genConfig = (name, { inlineCss } = {}) => ({
output: {
path: path.resolve(__dirname, 'dist'),
filename,
filename: `${name}${inlineCss ? '' : '-without-styles'}.js`,
library: 'superheroUtils',
libraryTarget: 'umd'
},
entry: path.resolve(__dirname, 'src', `${name}.js`),
target: 'web',
externals: {
'prop-types': {
commonjs: 'prop-types',
commonjs2: 'prop-types',
amd: 'prop-types',
root: 'PropTypes',
},
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
root: 'React',
},
},
module: {
rules: [
{
Expand Down Expand Up @@ -38,6 +53,8 @@ const genConfig = (filename, { inlineCss } = {}) => ({
});

module.exports = [
genConfig('index-without-styles.js'),
genConfig('index.js', { inlineCss: true }),
genConfig('index'),
genConfig('index', { inlineCss: true }),
genConfig('react'),
genConfig('vue'),
];

0 comments on commit 0c49ed9

Please sign in to comment.