1 | <a href="#about"><img alt="logo" width="1016" alt="2017-07-02 1 46 12" src="https://user-images.githubusercontent.com/8784712/27764289-6ffb8ab8-5ec8-11e7-8b30-9b59ecc1d47d.png"></a>
|
2 |
|
3 | ## About
|
4 |
|
5 | This is not yet another minimalistic React implementation, the main use case is to create actual dom with a single function and JSX directly, but there're opt-in component lifecycle hooks.
|
6 |
|
7 | ## Features
|
8 |
|
9 | - [x] Insanely small: 2kB minified
|
10 | - [x] One API: JSX is transformed to vNode, use `mount(vNode)` to get actual DOM.
|
11 | - [x] SVG support
|
12 | - [x] Protection from XSS injections
|
13 | - [x] Automatically joining classNames, styles
|
14 |
|
15 | ## Install
|
16 |
|
17 | ```bash
|
18 | yarn add dom-dom
|
19 | ```
|
20 |
|
21 | CDN: [UNPKG](https://unpkg.com/dom-dom/dist/) | [jsDelivr](https://cdn.jsdelivr.net/npm/dom-dom/dist/)
|
22 |
|
23 | ## Usage
|
24 |
|
25 | With a transpiler like `babel+babel-plugin-transform-react-jsx` or `typescript` or `buble`:
|
26 |
|
27 | ```js
|
28 | /* @jsx h */
|
29 | import { h, mount } from 'dom-dom/tiny'
|
30 |
|
31 | // With only first arg
|
32 | const button = mount(<button>click me</button>)
|
33 | // button.outerHTML:
|
34 | // => '<button>click me</button>'
|
35 |
|
36 | // With second arg
|
37 | // replacce `#root` with created element
|
38 | mount(
|
39 | <button>hello</button>,
|
40 | document.getElementById('root')
|
41 | )
|
42 | ```
|
43 |
|
44 | Note that while using CDN version you can access `d2.h` `d2.mount` instead.
|
45 |
|
46 | ### className
|
47 |
|
48 | `className` can be `string` `Array` or `Object`:
|
49 |
|
50 | ```js
|
51 | <div className="foo"></div>
|
52 | <div className={['foo', 'bar']}></div>
|
53 | <div className={{foo: false, [`bar-${index}`]: true}}></div>
|
54 | ```
|
55 |
|
56 | You can also directly use `class` instead of react-specific `className` as you please:
|
57 |
|
58 | ```js
|
59 | <div class="foo"></div>
|
60 | ```
|
61 |
|
62 | ### style
|
63 |
|
64 | `style` supports `string` and `Object`:
|
65 |
|
66 | ```js
|
67 | <div style="color: red"></div>
|
68 | // both kebab-case and camelCase are supported here
|
69 | // default unit is `px`
|
70 | <div style={{ fontSize: 14, 'background-color': 'red' }}></div>
|
71 | ```
|
72 |
|
73 | ### innerHTML
|
74 |
|
75 | ```js
|
76 | <div dangerouslySetInnerHTML={{__html: '<strong>hey</strong>'}}></div>
|
77 | ```
|
78 |
|
79 | ### Events
|
80 |
|
81 | React-like events are supports:
|
82 |
|
83 | ```js
|
84 | <button onClick={handleClick}></button>
|
85 | ```
|
86 |
|
87 | ---
|
88 |
|
89 | > **WARNING:** If you only want a function to transform vNode to actual dom, please stop reading!!! Above features would be enough for your use case. Following features may not be what you want :D
|
90 | > To use full build you should `import { xxx } from 'dom-dom'` instead.
|
91 |
|
92 | <details><summary>Create your own React with <strong>dom-dom</strong></summary><br>
|
93 |
|
94 | ```js
|
95 | // @jsx h
|
96 |
|
97 | import { h, mount, unmount } from 'dom-dom'
|
98 |
|
99 | class Component {
|
100 | setState(state) {
|
101 | if (typeof state === 'function') {
|
102 | state = state(this.state)
|
103 | }
|
104 | for (const key in state) {
|
105 | this.state[key] = state[key]
|
106 | }
|
107 | this.mount()
|
108 | }
|
109 |
|
110 | mount(root = this.$root) {
|
111 | this.$root = mount(this, root)
|
112 | return this.$root
|
113 | }
|
114 |
|
115 | destroy = () => {
|
116 | unmount(this, this.$root)
|
117 | }
|
118 |
|
119 | }
|
120 |
|
121 | class Counter extends Component {
|
122 | state = { count: 0 }
|
123 |
|
124 | handleClick = () => {
|
125 | this.setState(prevState => ({
|
126 | count: prevState.count + 1
|
127 | }))
|
128 | }
|
129 |
|
130 | componentDidMount() {
|
131 | console.log('app mounted!', this)
|
132 | }
|
133 |
|
134 | render() {
|
135 | return (<div>
|
136 | <button onClick={this.handleClick}>
|
137 | clicked: {this.state.count} times
|
138 | </button>
|
139 | <button onClick={this.destroy}>destroy</button>
|
140 | </div>)
|
141 | }
|
142 | }
|
143 |
|
144 | const counter = new Counter()
|
145 | counter.mount(document.getElementById('root'))
|
146 | ```
|
147 |
|
148 | [![Edit 9Q4n4XxAP](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/VyGn0DP5)
|
149 | </details><br>
|
150 |
|
151 | You can `mount` `unmount` a object or class instance which has a `render` method that returns `vNode`.
|
152 |
|
153 | ```js
|
154 | import { h, mount } from 'dom-dom'
|
155 |
|
156 | const A = {
|
157 | render() {
|
158 | return <div>a</div>
|
159 | }
|
160 | }
|
161 |
|
162 | const B = class {
|
163 | render() {
|
164 | return <div>{A}</div>
|
165 | }
|
166 | }
|
167 |
|
168 | mount(new B, document.getElementById('root'))
|
169 | ```
|
170 |
|
171 | Object and class instance with render function can also be one of your JSX children.
|
172 |
|
173 | This is designed for using lifecycle hooks, currently we have `componentDidMount` `componentWillMount` and `componentWillUnmount`.
|
174 |
|
175 | ```js
|
176 | const App = {
|
177 | componentDidMount() {
|
178 | console.log('hi')
|
179 | },
|
180 | componentWillUnmount() {
|
181 | console.log('bye')
|
182 | },
|
183 | render() {
|
184 | return <div>hi</div>
|
185 | }
|
186 | }
|
187 |
|
188 | const root = mount(App, document.getElementById('root'))
|
189 | //=> hi
|
190 | unmount(App, root)
|
191 | //=> bye
|
192 | ```
|
193 |
|
194 | ## Prior Art
|
195 |
|
196 | This project is heavily inspired by [preact](https://github.com/developit/preact) and [dom-chef](https://github.com/vadimdemedes/dom-chef).
|
197 |
|
198 | ## Contributing
|
199 |
|
200 | 1. Fork it!
|
201 | 2. Create your feature branch: `git checkout -b my-new-feature`
|
202 | 3. Commit your changes: `git commit -am 'Add some feature'`
|
203 | 4. Push to the branch: `git push origin my-new-feature`
|
204 | 5. Submit a pull request :D
|
205 |
|
206 | ## Badges
|
207 |
|
208 | [![NPM version](https://img.shields.io/npm/v/dom-dom.svg?style=flat)](https://npmjs.com/package/dom-dom) [![NPM downloads](https://img.shields.io/npm/dm/dom-dom.svg?style=flat)](https://npmjs.com/package/dom-dom) [![CircleCI](https://circleci.com/gh/egoist/dom-dom/tree/master.svg?style=shield&circle-token=1b6201de2b133f5b995fe2730a24b497768d85c6)](https://circleci.com/gh/egoist/dom-dom/tree/master) [![donate](https://img.shields.io/badge/$-donate-ff69b4.svg?maxAge=2592000&style=flat)](https://github.com/egoist/donate)
|
209 |
|
210 | ## Author
|
211 |
|
212 | **dom-dom** © [egoist](https://github.com/egoist), Released under the [MIT](./LICENSE) License.<br>
|
213 | Authored and maintained by egoist with help from contributors ([list](https://github.com/egoist/dom-dom/contributors)).
|
214 |
|
215 | > [egoistian.com](https://egoistian.com) · GitHub [@egoist](https://github.com/egoist) · Twitter [@rem_rin_rin](https://twitter.com/rem_rin_rin)
|