mise 3.0.0 → 2026.6.0

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/src/vdom/vdom.js DELETED
@@ -1,141 +0,0 @@
1
- import { getUniques } from '../utils';
2
- import { types } from './fiber';
3
-
4
- const setProp = (element, attribute, previous, next) => {
5
- if (attribute === 'value') {
6
- element[attribute] = next;
7
- return;
8
- }
9
-
10
- if (typeof next === 'boolean') {
11
- if (next) {
12
- element.setAttribute(attribute, next);
13
- element[attribute] = next;
14
- }
15
- return;
16
- }
17
-
18
- if (typeof next === 'function') {
19
- try {
20
- element[attribute] = next;
21
- } catch (e) {
22
- /* sometimes lifecycle methods throw. we don't particularly care */
23
- }
24
-
25
- return;
26
- }
27
-
28
- if (!next || (typeof next === 'object' && !Object.keys(next).length)) {
29
- element.removeAttribute(attribute);
30
- return;
31
- }
32
-
33
- if (attribute === 'style') {
34
- const styles = getUniques(next, previous);
35
-
36
- for (const style of styles) {
37
- if (!next[style]) {
38
- element.style[style] = '';
39
- } else if (!previous || !previous[style] || previous[style] !== next[style]) {
40
- element.style[style] = next[style];
41
- }
42
- }
43
-
44
- return;
45
- }
46
-
47
- element.setAttribute(attribute, next);
48
- };
49
-
50
- const setProps = (element, props) => {
51
- for (const [attribute, value] of Object.entries(props)) {
52
- setProp(element, attribute, {}, value);
53
- }
54
- };
55
-
56
- const createElement = (node) => {
57
- if (typeof node === 'string') {
58
- return document.createTextNode(node);
59
- }
60
-
61
- const { type, props, children } = node;
62
- const element = document.createElement(type);
63
- setProps(element, props);
64
-
65
- children
66
- .map(createElement)
67
- .forEach(child => element.appendChild(child));
68
-
69
- return element;
70
- };
71
-
72
- const updateProps = (element, previous, next) => {
73
- const props = getUniques(previous, next);
74
-
75
- for (const prop of props) {
76
- setProp(element, prop, previous[prop], next[prop]);
77
- }
78
- };
79
-
80
- const paint = (fibers) => {
81
- for (const fiber of fibers) {
82
- const {
83
- action,
84
- next,
85
- previous,
86
- lifecycle,
87
- parent,
88
- } = fiber;
89
-
90
- switch (action) {
91
- case (types.create): {
92
- parent.appendChild(next.element);
93
-
94
- if (lifecycle) {
95
- lifecycle(next.element);
96
- }
97
-
98
- break;
99
- }
100
-
101
- case (types.remove): {
102
- if (lifecycle) {
103
- lifecycle(next.element)(previous.element.remove.bind(previous.element));
104
- } else {
105
- previous.element.remove();
106
- }
107
-
108
- break;
109
- }
110
-
111
- case (types.replace): {
112
- if (lifecycle) {
113
- lifecycle(next.element)(previous.props);
114
- }
115
-
116
- parent.replaceChild(
117
- next.element,
118
- previous.element,
119
- );
120
-
121
- break;
122
- }
123
-
124
- case (types.update): {
125
- if (lifecycle) {
126
- lifecycle(next.element)(previous.props);
127
- }
128
-
129
- updateProps(previous.element, previous.tree.props, next.tree.props);
130
-
131
- break;
132
- }
133
-
134
- default: {
135
- return;
136
- }
137
- }
138
- }
139
- };
140
-
141
- export { paint, createElement };
@@ -1,85 +0,0 @@
1
- import { dom, component } from '../../src';
2
- import { requestAnimationFrame, requestIdleCallback } from '../utils';
3
-
4
- window.requestAnimationFrame = requestAnimationFrame;
5
- window.requestIdleCallback = requestIdleCallback;
6
-
7
- describe('counter example', () => {
8
- let body;
9
-
10
- beforeEach(() => {
11
- document.body.innerHTML = '';
12
-
13
- component({
14
- template: state => actions =>
15
- dom('div', null, [
16
-
17
- dom(
18
- 'span', {
19
- id: 'counter',
20
- },
21
- state.counter,
22
- ),
23
-
24
- dom('button', {
25
- id: 'up',
26
- onclick() {
27
- actions.increment();
28
- },
29
- }),
30
-
31
- dom('button', {
32
- id: 'down',
33
- onclick() {
34
- actions.decrement();
35
- },
36
- }),
37
- ]),
38
- state: {
39
- counter: 0,
40
- },
41
- actions: {
42
- increment: state => ({ counter: state.counter + 1 }),
43
- decrement: state => ({ counter: state.counter - 1 }),
44
- },
45
- });
46
-
47
- body = document.body;
48
- });
49
-
50
- it('should load a counter', (done) => {
51
- setTimeout(() => {
52
- expect(body.innerHTML).not.toBe('');
53
- done();
54
- }, 200);
55
- });
56
-
57
- it('should have the proper initial state attached', (done) => {
58
- setTimeout(() => {
59
- expect(body.querySelector('#counter').innerHTML).toEqual('0');
60
- done();
61
- }, 100);
62
- });
63
-
64
- it('should respond correctly to an increment action', (done) => {
65
- setTimeout(() => {
66
- body.querySelector('#up').click();
67
-
68
- setTimeout(() => {
69
- expect(body.querySelector('#counter').innerHTML).toEqual('1');
70
- done();
71
- }, 100);
72
- }, 100);
73
- });
74
-
75
- it('should respond correctly to an decrement action', (done) => {
76
- setTimeout(() => {
77
- body.querySelector('#down').click();
78
-
79
- setTimeout(() => {
80
- expect(body.querySelector('#counter').innerHTML).toEqual('-1');
81
- done();
82
- }, 100);
83
- }, 100);
84
- });
85
- });
@@ -1,263 +0,0 @@
1
- import { dom, component } from '../../src';
2
- import { requestAnimationFrame, requestIdleCallback } from '../utils';
3
-
4
- window.requestAnimationFrame = requestAnimationFrame;
5
- window.requestIdleCallback = requestIdleCallback;
6
-
7
- const TodoItem = ({
8
- id, text, done, toggle, clear, create, remove, update,
9
- }) =>
10
- dom(
11
- 'li',
12
- {
13
- oncreate: create,
14
- onremove: remove,
15
- onupdate: update,
16
- },
17
- dom(
18
- 'span',
19
- {
20
- onclick: function onclick() {
21
- return toggle({ id });
22
- },
23
- style: done ? { fontSize: '18px', textDecoration: 'line-through' } : { fontSize: '18px' },
24
- },
25
- text,
26
- ),
27
- dom(
28
- 'span',
29
- {
30
- onclick: function onclick() {
31
- return clear({ id });
32
- },
33
- style: {
34
- marginLeft: '10px',
35
- color: 'red',
36
- },
37
- },
38
- 'x',
39
- ),
40
- );
41
-
42
- describe('counter example', () => {
43
- let body;
44
- let input;
45
- let addTodo;
46
-
47
- beforeEach(() => {
48
- document.body.innerHTML = '';
49
-
50
- component({
51
- template: state => actions => (
52
- dom(
53
- 'div',
54
- null,
55
- dom(
56
- 'h1',
57
- null,
58
- 'Todos',
59
- ),
60
- dom(
61
- 'ul',
62
- {
63
- id: 'todos',
64
- className: 'todos',
65
- },
66
- state.todos.map(todo => dom(TodoItem, {
67
- create: function create() {
68
-
69
- },
70
- remove: function remove() {
71
- return function finish(done) {
72
- done();
73
- };
74
- },
75
- update: function update() {
76
- return function checkOldProps(oldProps) {
77
- return oldProps;
78
- };
79
- },
80
- text: todo.text,
81
- id: todo.id,
82
- done: todo.done,
83
- toggle: actions.toggle,
84
- clear: actions.remove,
85
- })),
86
- ),
87
- dom('input', {
88
- type: 'text',
89
- value: state.input,
90
- oninput: function oninput(e) {
91
- return actions.input({ value: e.target.value });
92
- },
93
- }),
94
- dom(
95
- 'button',
96
- {
97
- onclick: actions.add,
98
- id: 'add',
99
- },
100
- 'Add Todo',
101
- ),
102
- dom(
103
- 'button',
104
- {
105
- onclick: actions.clearTodos,
106
- id: 'clear',
107
- },
108
- 'Clear All Todos',
109
- ),
110
- )
111
- ),
112
- state: {
113
- todos: [],
114
- input: '',
115
- id: 0,
116
- },
117
- actions: {
118
- add: (state, actions) => {
119
- const text = state.input;
120
- actions.clearInput();
121
- return {
122
- todos: [
123
- ...state.todos,
124
- {
125
- text,
126
- id: state.id,
127
- done: false,
128
- },
129
- ],
130
- id: state.id + 1,
131
- };
132
- },
133
- input: (state, actions, { value }) => ({ input: value }),
134
- toggle: (state, actions, { id }) => ({
135
- todos: state.todos.map(todo => (
136
- todo.id === id ? { ...todo, done: !todo.done } : todo)),
137
- }),
138
- remove: (state, actions, { id }) => ({ todos: state.todos.filter(todo => todo.id !== id) }),
139
- clearInput: () => ({ input: '' }),
140
- clearTodos: () => ({ todos: [] }),
141
- },
142
- });
143
-
144
- body = document.body;
145
-
146
- addTodo = (text = 'new todo') => {
147
- input = document.body.querySelector('input');
148
- input.value = text;
149
-
150
- input.dispatchEvent(new Event('input'));
151
- body.querySelector('#add').click();
152
- };
153
- });
154
-
155
- it('should load', (done) => {
156
- setTimeout(() => {
157
- expect(body.innerHTML).not.toBe('');
158
- done();
159
- }, 100);
160
- });
161
-
162
- it('the initial state to not have any todos', (done) => {
163
- setTimeout(() => {
164
- expect(body.querySelector('#todos').childNodes.length).toBe(0);
165
- done();
166
- }, 25);
167
- });
168
-
169
- it('should add a todo', (done) => {
170
- setTimeout(() => {
171
- addTodo();
172
-
173
- setTimeout(() => {
174
- expect(body.querySelector('#todos').childNodes.length).toBe(1);
175
- done();
176
- }, 25);
177
- }, 25);
178
- });
179
-
180
- it('should clear the input after adding a todo', (done) => {
181
- setTimeout(() => {
182
- addTodo();
183
-
184
- setTimeout(() => {
185
- expect(input.value).toBe('');
186
- done();
187
- }, 25);
188
- }, 25);
189
- });
190
-
191
- it('should remove the todo', (done) => {
192
- setTimeout(() => {
193
- addTodo();
194
-
195
- setTimeout(() => {
196
- body.querySelector('#todos span:last-child').click();
197
-
198
- setTimeout(() => {
199
- expect(body.querySelector('#todos').childNodes.length).toBe(0);
200
- done();
201
- }, 25);
202
- }, 25);
203
- }, 25);
204
- });
205
-
206
- it('should set the todo to done', (done) => {
207
- const firstTodoSpanSelector = '#todos li:first-child span:first-child';
208
-
209
- setTimeout(() => {
210
- addTodo();
211
-
212
- setTimeout(() => {
213
- body.querySelector(firstTodoSpanSelector).click();
214
-
215
- setTimeout(() => {
216
- expect(body.querySelector(firstTodoSpanSelector).outerHTML).toEqual('<span style="font-size: 18px; text-decoration: line-through;">new todo</span>');
217
- done();
218
- }, 25);
219
- }, 25);
220
- }, 25);
221
- });
222
-
223
- it('should set the todo to done, then unset it', (done) => {
224
- const firstTodoSpanSelector = '#todos li:first-child span:first-child';
225
-
226
- setTimeout(() => {
227
- addTodo();
228
-
229
- setTimeout(() => {
230
- body.querySelector(firstTodoSpanSelector).click();
231
-
232
- setTimeout(() => {
233
- expect(body.querySelector(firstTodoSpanSelector).outerHTML).toEqual('<span style="font-size: 18px; text-decoration: line-through;">new todo</span>');
234
-
235
- body.querySelector(firstTodoSpanSelector).click();
236
-
237
- setTimeout(() => {
238
- expect(body.querySelector(firstTodoSpanSelector).outerHTML).toEqual('<span style="font-size: 18px;">new todo</span>');
239
- done();
240
- }, 25);
241
- }, 25);
242
- }, 25);
243
- }, 25);
244
- });
245
-
246
- it('should remove all todos', (done) => {
247
- setTimeout(() => {
248
- addTodo();
249
- addTodo();
250
- addTodo();
251
-
252
- setTimeout(() => {
253
- expect(body.querySelector('#todos').childNodes.length).toBe(3);
254
- body.querySelector('#clear').click();
255
-
256
- setTimeout(() => {
257
- expect(body.querySelector('#todos').childNodes.length).toBe(0);
258
- done();
259
- }, 25);
260
- }, 25);
261
- }, 25);
262
- });
263
- });
@@ -1,80 +0,0 @@
1
- import { component, dom } from '../../src';
2
- import { requestAnimationFrame, requestIdleCallback } from '../utils';
3
-
4
- window.requestAnimationFrame = requestAnimationFrame;
5
- window.requestIdleCallback = requestIdleCallback;
6
-
7
- describe('component tests', () => {
8
- let body;
9
-
10
- beforeEach(() => {
11
- document.body.innerHTML = '';
12
-
13
- component({
14
- template: state => actions =>
15
- dom('div', null, [
16
- dom('span', { id: 'text' }, state.text),
17
- dom('button', { id: 'update', onclick() { actions.update(); } }),
18
- dom('button', { id: 'async', onclick() { actions.asyncUpdate(); } }),
19
- dom('div', null, [
20
- dom('div', null, [
21
- dom('div', null, [
22
- dom('div', null, ['hey']),
23
- ]),
24
- ]),
25
- ]),
26
- ]),
27
- state: {
28
- text: 'hello, world',
29
- },
30
- actions: {
31
- update: state => ({ text: `${state.text}!` }),
32
- asyncUpdate: state => (update) => {
33
- setTimeout(() => {
34
- update({ text: `${state.text}!!` });
35
- }, 50);
36
- },
37
- },
38
- });
39
-
40
- body = document.body;
41
- });
42
-
43
- it('should properly render', (done) => {
44
- setTimeout(() => {
45
- expect(body.innerHTML).not.toEqual('');
46
-
47
- done();
48
- }, 50);
49
- });
50
-
51
- it('should properly render the state', (done) => {
52
- setTimeout(() => {
53
- expect(body.querySelector('#text').innerHTML).toEqual('hello, world');
54
-
55
- done();
56
- }, 50);
57
- });
58
-
59
- it('should properly handle an update action', (done) => {
60
- setTimeout(() => {
61
- body.querySelector('#update').click();
62
-
63
- setTimeout(() => {
64
- expect(body.querySelector('#text').innerHTML).toEqual('hello, world!');
65
- done();
66
- }, 25);
67
- }, 25);
68
- });
69
-
70
- it('should handle a thunk', (done) => {
71
- setTimeout(() => {
72
- body.querySelector('#async').click();
73
-
74
- setTimeout(() => {
75
- expect(body.querySelector('#text').innerHTML).toEqual('hello, world!!');
76
- done();
77
- }, 100);
78
- }, 25);
79
- });
80
- });
@@ -1,111 +0,0 @@
1
- import { dom } from '../../src/';
2
-
3
- describe('DOM jsx tests', () => {
4
- it('should be defined', () => {
5
- expect(dom).toBeDefined();
6
- });
7
-
8
- it('should properly handle a tag with no children or props', () => {
9
- const element = dom('main');
10
-
11
- expect(element).toEqual({
12
- type: 'main',
13
- props: {},
14
- children: [],
15
- });
16
- });
17
-
18
- it('should properly handle a tag with a null prop', () => {
19
- const element = dom('main', null);
20
-
21
- expect(element).toEqual({
22
- type: 'main',
23
- props: {},
24
- children: [],
25
- });
26
- });
27
-
28
- it('should properly handle a tag with children but no props', () => {
29
- const children = ['article', 'aside', 'section'];
30
- const element = dom('main', {}, ...children);
31
-
32
- expect(element).toEqual({
33
- type: 'main',
34
- props: {},
35
- children,
36
- });
37
- });
38
-
39
- it('should properly handle a tag with props but no children', () => {
40
- const props = {
41
- id: 'news',
42
- className: 'main-section',
43
- };
44
-
45
- const element = dom('main', props);
46
-
47
- expect(element).toEqual({
48
- type: 'main',
49
- props,
50
- children: [],
51
- });
52
- });
53
-
54
- it('should handle a child being a number', () => {
55
- const element = dom('li', {}, 0);
56
-
57
- expect(element).toEqual({
58
- type: 'li',
59
- props: {},
60
- children: ['0'],
61
- });
62
- });
63
-
64
- it('should properly handle children being an array', () => {
65
- const children = ['article', 'aside', 'section'];
66
- const element = dom('main', {}, children);
67
-
68
- expect(element).toEqual({
69
- type: 'main',
70
- props: {},
71
- children,
72
- });
73
- });
74
-
75
- it('should handle a function as a type', () => {
76
- const statelessComponent = (props, children) => dom('div', props, children);
77
- let element = dom(statelessComponent);
78
-
79
- expect(element).toEqual({
80
- type: 'div',
81
- props: {},
82
- children: [],
83
- });
84
-
85
- const props = { id: 'thing', className: 'thing-haver' };
86
- element = dom(statelessComponent, props);
87
-
88
- expect(element).toEqual({
89
- type: 'div',
90
- props,
91
- children: [],
92
- });
93
-
94
- const secondProps = { id: 'second-thing', className: 'thing-haver' };
95
- element = dom(statelessComponent, props, [
96
- dom(statelessComponent, secondProps, []),
97
- ]);
98
-
99
- expect(element).toEqual({
100
- type: 'div',
101
- props,
102
- children: [
103
- {
104
- type: 'div',
105
- props: secondProps,
106
- children: [],
107
- },
108
- ],
109
- });
110
- });
111
- });
@@ -1,26 +0,0 @@
1
- import { getUniques } from '../../src/utils';
2
-
3
- describe('get uniques', () => {
4
- it('should properly find the uniques', () => {
5
- const first = { a: '', b: '', c: '' };
6
- const second = { a: '', b: '', d: '' };
7
-
8
- const uniques = getUniques(first, second);
9
- expect(uniques.size).toBe(4);
10
- expect([...uniques.values()]).toEqual(['a', 'b', 'c', 'd']);
11
- });
12
-
13
- it('should handle undef/null as well', () => {
14
- const real = { a: '', b: '' };
15
- const fake = null;
16
-
17
- const first = getUniques(real, fake);
18
- const second = getUniques(fake, real);
19
-
20
- const set = new Set(['a', 'b']);
21
- expect(first).toEqual(set);
22
- expect(second).toEqual(set);
23
-
24
- expect(first).toEqual(second);
25
- });
26
- });