@3sln/dodo 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -111
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Dodo
|
|
2
2
|
|
|
3
3
|
> [!WARNING]
|
|
4
4
|
> This is a work-in-progress project and is not yet ready for production use.
|
|
5
5
|
|
|
6
6
|
A minimal, configurable virtual DOM library.
|
|
7
7
|
|
|
8
|
+
## Documentation
|
|
9
|
+
|
|
10
|
+
For detailed documentation, live demos, and advanced usage examples, please check out the [Dodo Deck](https://dodo.3sln.com).
|
|
11
|
+
|
|
8
12
|
## Quick Start
|
|
9
13
|
|
|
14
|
+
Installation:
|
|
15
|
+
```shell
|
|
16
|
+
npm install @3sln/dodo
|
|
17
|
+
# or
|
|
18
|
+
bun add @3sln/dodo
|
|
19
|
+
# or
|
|
20
|
+
yarn add @3sln/dodo
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Basic usage:
|
|
10
24
|
```javascript
|
|
11
25
|
import { reconcile, h1, p, div } from '@3sln/dodo';
|
|
12
26
|
|
|
@@ -16,118 +30,9 @@ const container = document.getElementById('root');
|
|
|
16
30
|
// The props object is optional.
|
|
17
31
|
const myVdom = div({ id: 'app' },
|
|
18
32
|
h1('Hello, dodo!'),
|
|
19
|
-
p(
|
|
33
|
+
p('This is a paragraph.')
|
|
20
34
|
);
|
|
21
35
|
|
|
22
36
|
// Reconcile the virtual DOM with the real DOM.
|
|
23
37
|
reconcile(container, [myVdom]);
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Core Concepts
|
|
27
|
-
|
|
28
|
-
## Core Concepts
|
|
29
|
-
|
|
30
|
-
- **Factories for Customization:** Dodo is built around a factory pattern. While you can import and use a pre-configured default instance, you can also create custom instances for advanced use cases (like interoperating with ClojureScript). The library exports three factories:
|
|
31
|
-
- `dodo(settings)`: A unified factory that returns a complete API with VDOM functions, HTML helpers, and the scheduler.
|
|
32
|
-
- `vdom(settings)`: Creates just the core VDOM API (`h`, `alias`, `special`, `reconcile`, `settings`).
|
|
33
|
-
- `html({ h })`: Creates the HTML helper functions (`div`, `p`, etc.) bound to a specific `h` function.
|
|
34
|
-
- **HTML Helpers:** Simple functions like `div()`, `p()`, `span()` are exported for convenience.
|
|
35
|
-
- **`$`-Prefixed Props:** Special props that `dodo` intercepts are prefixed with a `$` to avoid conflicts with standard properties (e.g., `$classes`, `$styling`, `$attrs`, `$dataset`).
|
|
36
|
-
- **`.key()`:** Chain `.key('unique-id')` to any VNode in a list to enable efficient, keyed reconciliation.
|
|
37
|
-
- **`.on()`:** Chain `.on({ event: handler })` to any VNode to attach event listeners or lifecycle hooks (`$attach`, `$detach`, `$update`).
|
|
38
|
-
- **`.opaque()`**: Marks an element node as opaque, meaning `dodo` will manage its props but not its children.
|
|
39
|
-
|
|
40
|
-
## Keys for List Reconciliation
|
|
41
|
-
|
|
42
|
-
When rendering lists of elements, always use the `.key()` method to ensure efficient updates and reordering.
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
import { reconcile, div } from '@3sln/dodo';
|
|
46
|
-
|
|
47
|
-
const data = [{id: 1, text: 'A'}, {id: 2, text: 'B'}, {id: 3, text: 'C'}];
|
|
48
|
-
const container = document.getElementById('list');
|
|
49
|
-
|
|
50
|
-
// Chain .key() to the VNode returned by the helper function.
|
|
51
|
-
reconcile(container, data.map(item => div(item.text).key(item.id)));
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## Event Listeners and Lifecycle Hooks
|
|
55
|
-
|
|
56
|
-
Use the `.on()` method to attach event listeners and lifecycle hooks.
|
|
57
|
-
|
|
58
|
-
```javascript
|
|
59
|
-
import { reconcile, button } from '@3sln/dodo';
|
|
60
|
-
|
|
61
|
-
const myButton = button('Hover over me').on({
|
|
62
|
-
// Simple function handler
|
|
63
|
-
mouseover: () => console.log('Mouse entered!'),
|
|
64
|
-
|
|
65
|
-
// Object handler for more options
|
|
66
|
-
mouseleave: {
|
|
67
|
-
listener: () => console.log('Mouse left!'),
|
|
68
|
-
capture: true
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
// Lifecycle hooks
|
|
72
|
-
$attach: (domNode) => console.log('Button node was created.'),
|
|
73
|
-
$detach: (domNode) => console.log('Button has been removed.')
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const container = document.getElementById('event-container');
|
|
77
|
-
reconcile(container, myButton);
|
|
78
|
-
reconcile(container, null); // Triggers $detach
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Understanding `reconcile()`
|
|
82
|
-
|
|
83
|
-
The `reconcile` function has two distinct modes of operation:
|
|
84
|
-
|
|
85
|
-
- **`reconcile(target, vnode)` (Onto):** Modifies the `target` element itself to match the `vnode`. This requires the `target`'s tag name to be compatible with the `vnode`'s tag (unless the `vnode` is an `alias` or `special`).
|
|
86
|
-
|
|
87
|
-
- **`reconcile(target, [vnodes...])` (Into):** Modifies the *children* of the `target` element to match the array of `vnodes`. The `target` element's own properties are not changed.
|
|
88
|
-
|
|
89
|
-
- **`reconcile(target, null)` (Cleanup):** Detaches `dodo` from the `target` and its descendants, running all necessary cleanup logic.
|
|
90
|
-
|
|
91
|
-
## Advanced: Web Components with `special`
|
|
92
|
-
|
|
93
|
-
The `special` component is a powerful tool for integrating with other libraries or, as shown here, for providing the rendering logic for a standard Web Component.
|
|
94
|
-
|
|
95
|
-
```javascript
|
|
96
|
-
import { reconcile, special, p, h, alias } from '@3sln/dodo';
|
|
97
|
-
|
|
98
|
-
// 1. Create a special component to manage a shadow root.
|
|
99
|
-
const shadowComponent = special({
|
|
100
|
-
attach: (domNode) => {
|
|
101
|
-
// Create a shadow root on the host element once.
|
|
102
|
-
domNode.attachShadow({ mode: 'open' });
|
|
103
|
-
},
|
|
104
|
-
update: (domNode, newContent) => {
|
|
105
|
-
// Reconcile the provided content into the shadow root.
|
|
106
|
-
reconcile(domNode.shadowRoot, newContent);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
// 2. Define a standard Web Component class.
|
|
111
|
-
class MyComponent extends HTMLElement {
|
|
112
|
-
connectedCallback() {
|
|
113
|
-
// When the element is added to the DOM, render the special component ONTO it.
|
|
114
|
-
// Pass some initial content into the special component's `update` hook.
|
|
115
|
-
reconcile(this, shadowComponent(p('Hello from inside a web component!')));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
disconnectedCallback() {
|
|
119
|
-
// When the element is removed, clean up the dodo instance.
|
|
120
|
-
reconcile(this, null);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// You can add attributeChangedCallback, properties, etc.
|
|
124
|
-
// to re-reconcile with new content.
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// 3. Register the custom element.
|
|
128
|
-
customElements.define('my-component', MyComponent);
|
|
129
|
-
|
|
130
|
-
// 4. Use your new custom element with dodo!
|
|
131
|
-
const container = document.getElementById('my-component-container');
|
|
132
|
-
reconcile(container, h('my-component'));
|
|
133
38
|
```
|