vanilla_project 2.0.0 → 3.0.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/dist/vanilla_project.js +314 -124
- package/package.json +4 -2
package/dist/vanilla_project.js
CHANGED
|
@@ -136,13 +136,15 @@ const DOM_TYPES = {
|
|
|
136
136
|
TEXT: 'text',
|
|
137
137
|
ELEMENT: 'element',
|
|
138
138
|
FRAGMENT: 'fragment',
|
|
139
|
+
COMPONENT: 'component',
|
|
139
140
|
};
|
|
140
141
|
function h(tag, props = {}, children = []) {
|
|
142
|
+
const type = typeof tag === 'string' ? DOM_TYPES.ELEMENT : DOM_TYPES.COMPONENT;
|
|
141
143
|
return {
|
|
142
144
|
tag,
|
|
143
145
|
props,
|
|
146
|
+
type,
|
|
144
147
|
children: mapTextNodes(withoutNulls(children)),
|
|
145
|
-
type: DOM_TYPES.ELEMENT,
|
|
146
148
|
}
|
|
147
149
|
}
|
|
148
150
|
function mapTextNodes(children) {
|
|
@@ -172,14 +174,17 @@ function extractChildren(v_dom){
|
|
|
172
174
|
return children
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
function addEventListener(eventName, handler, el) {
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
function addEventListener(eventName, handler, el,hostComponent = null) {
|
|
178
|
+
function boundHandler() {
|
|
179
|
+
hostComponent ? handler.apply(hostComponent,arguments) : handler(...arguments);
|
|
180
|
+
}
|
|
181
|
+
el.addEventListener(eventName,boundHandler);
|
|
182
|
+
return boundHandler
|
|
178
183
|
}
|
|
179
|
-
function addEventListeners(listeners = {}, el) {
|
|
184
|
+
function addEventListeners(listeners = {}, el,hostComponent = null) {
|
|
180
185
|
const addedListeners = {};
|
|
181
186
|
Object.entries(listeners).forEach(([eventName, handler]) => {
|
|
182
|
-
const listener = addEventListener(eventName, handler, el);
|
|
187
|
+
const listener = addEventListener(eventName, handler, el,hostComponent);
|
|
183
188
|
addedListeners[eventName] = listener;
|
|
184
189
|
});
|
|
185
190
|
return addedListeners
|
|
@@ -205,6 +210,10 @@ function destroyDOM(v_dom) {
|
|
|
205
210
|
removeFragmentNodes(v_dom);
|
|
206
211
|
break
|
|
207
212
|
}
|
|
213
|
+
case DOM_TYPES.COMPONENT: {
|
|
214
|
+
v_dom.component.unmount();
|
|
215
|
+
break
|
|
216
|
+
}
|
|
208
217
|
default: {
|
|
209
218
|
throw new Error(`Can't destroy DOM of type: ${type}`)
|
|
210
219
|
}
|
|
@@ -230,7 +239,7 @@ function removeFragmentNodes(v_dom) {
|
|
|
230
239
|
}
|
|
231
240
|
|
|
232
241
|
function setAttributes(el, attrs) {
|
|
233
|
-
const {class: className, style, ...otherAttrs} = attrs;
|
|
242
|
+
const {class: className, style,focus, ...otherAttrs} = attrs;
|
|
234
243
|
if (className) {
|
|
235
244
|
setClass(el, className);
|
|
236
245
|
}
|
|
@@ -272,18 +281,28 @@ function removeAttribute(el, name) {
|
|
|
272
281
|
el.removeAttribute(name);
|
|
273
282
|
}
|
|
274
283
|
|
|
275
|
-
function
|
|
284
|
+
function extractPropsAndEvents(v_dom) {
|
|
285
|
+
const {on: events = {}, ...props} = v_dom.props;
|
|
286
|
+
delete props.key;
|
|
287
|
+
return {props, events}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function mountDOM(v_dom, parentEl, index = null, hostComponent = null) {
|
|
276
291
|
switch (v_dom.type) {
|
|
277
292
|
case DOM_TYPES.TEXT: {
|
|
278
|
-
createTextNode(v_dom, parentEl,index);
|
|
293
|
+
createTextNode(v_dom, parentEl, index);
|
|
279
294
|
break
|
|
280
295
|
}
|
|
281
296
|
case DOM_TYPES.ELEMENT: {
|
|
282
|
-
createElementNode(v_dom, parentEl,index);
|
|
297
|
+
createElementNode(v_dom, parentEl, index, hostComponent);
|
|
283
298
|
break
|
|
284
299
|
}
|
|
285
300
|
case DOM_TYPES.FRAGMENT: {
|
|
286
|
-
createFragmentNodes(v_dom, parentEl,index);
|
|
301
|
+
createFragmentNodes(v_dom, parentEl, index, hostComponent);
|
|
302
|
+
break
|
|
303
|
+
}
|
|
304
|
+
case DOM_TYPES.COMPONENT: {
|
|
305
|
+
createComponentNode(v_dom, parentEl, index, hostComponent);
|
|
287
306
|
break
|
|
288
307
|
}
|
|
289
308
|
default: {
|
|
@@ -291,79 +310,84 @@ function mountDOM(v_dom, parentEl,index) {
|
|
|
291
310
|
}
|
|
292
311
|
}
|
|
293
312
|
}
|
|
294
|
-
function createTextNode(v_dom, parentEl,index) {
|
|
295
|
-
const {
|
|
313
|
+
function createTextNode(v_dom, parentEl, index) {
|
|
314
|
+
const {value} = v_dom;
|
|
296
315
|
const textNode = document.createTextNode(value);
|
|
297
316
|
v_dom.el = textNode;
|
|
298
|
-
insert(textNode,parentEl,index);
|
|
317
|
+
insert(textNode, parentEl, index);
|
|
299
318
|
}
|
|
300
|
-
function createFragmentNodes(v_dom, parentEl,index) {
|
|
319
|
+
function createFragmentNodes(v_dom, parentEl, index, hostComponent) {
|
|
301
320
|
const {children} = v_dom;
|
|
302
321
|
v_dom.el = parentEl;
|
|
303
|
-
children.forEach((child,i) => mountDOM(child, parentEl,index ? index + i : null));
|
|
322
|
+
children.forEach((child, i) => mountDOM(child, parentEl, index ? index + i : null, hostComponent));
|
|
304
323
|
}
|
|
305
|
-
function createElementNode(v_dom, parentEl,index) {
|
|
306
|
-
const {
|
|
324
|
+
function createElementNode(v_dom, parentEl, index, hostComponent) {
|
|
325
|
+
const {tag, children} = v_dom;
|
|
307
326
|
const element = document.createElement(tag);
|
|
308
|
-
addProps(element,
|
|
327
|
+
addProps(element, v_dom, hostComponent);
|
|
309
328
|
v_dom.el = element;
|
|
310
|
-
children.forEach((child) => mountDOM(child, element));
|
|
311
|
-
insert(element,parentEl,index);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
329
|
+
children.forEach((child) => mountDOM(child, element, null, hostComponent));
|
|
330
|
+
insert(element, parentEl, index);
|
|
331
|
+
const {props} = extractPropsAndEvents(v_dom);
|
|
332
|
+
if (props.focus && props.focus === true) {
|
|
333
|
+
element.focus();
|
|
334
|
+
element.select();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function createComponentNode(v_dom, parentEl, index, hostComponent) {
|
|
338
|
+
const Component = v_dom.tag;
|
|
339
|
+
const {props, events} = extractPropsAndEvents(v_dom);
|
|
340
|
+
const component = new Component(props, events, hostComponent);
|
|
341
|
+
component.mount(parentEl, index);
|
|
342
|
+
v_dom.component = component;
|
|
343
|
+
v_dom.el = component.firstElement;
|
|
344
|
+
}
|
|
345
|
+
function addProps(el, v_dom, hostComponent) {
|
|
346
|
+
const {props: attrs, events} = extractPropsAndEvents(v_dom);
|
|
347
|
+
v_dom.listeners = addEventListeners(events, el, hostComponent);
|
|
316
348
|
setAttributes(el, attrs);
|
|
317
349
|
}
|
|
318
|
-
function insert(el,parentEl,index){
|
|
319
|
-
if(index == null){
|
|
350
|
+
function insert(el, parentEl, index) {
|
|
351
|
+
if (index == null) {
|
|
320
352
|
parentEl.append(el);
|
|
321
353
|
return
|
|
322
354
|
}
|
|
323
|
-
if(index < 0
|
|
355
|
+
if (index < 0) {
|
|
324
356
|
throw new Error(`Index must be positive,got ${index}`)
|
|
325
357
|
}
|
|
326
358
|
const children = parentEl.childNodes;
|
|
327
|
-
if(index >= children.length){
|
|
359
|
+
if (index >= children.length) {
|
|
328
360
|
parentEl.append(el);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
parentEl.insertBefore(el,children[index]);
|
|
361
|
+
} else {
|
|
362
|
+
parentEl.insertBefore(el, children[index]);
|
|
332
363
|
}
|
|
333
364
|
}
|
|
334
365
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
if (handlers.includes(handler)) {
|
|
344
|
-
return () => {
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
handlers.push(handler);
|
|
348
|
-
return () => {
|
|
349
|
-
const id = handlers.indexOf(handler);
|
|
350
|
-
handlers.splice(id, 1);
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
afterEveryCommand(handler) {
|
|
354
|
-
this.#afterHandlers.push(handler);
|
|
355
|
-
return () => {
|
|
356
|
-
const id = this.#afterHandlers.indexOf(handler);
|
|
357
|
-
this.#afterHandlers.splice(id, 1);
|
|
358
|
-
}
|
|
366
|
+
function createApp(RootComponent, props = {}) {
|
|
367
|
+
let parentEl = null;
|
|
368
|
+
let isMounted = false;
|
|
369
|
+
let v_dom = null;
|
|
370
|
+
function reset() {
|
|
371
|
+
parentEl = null;
|
|
372
|
+
isMounted = false;
|
|
373
|
+
v_dom = null;
|
|
359
374
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
375
|
+
return {
|
|
376
|
+
mount(_parentEl) {
|
|
377
|
+
if (isMounted) {
|
|
378
|
+
throw new Error("The application is already mounted");
|
|
379
|
+
}
|
|
380
|
+
parentEl = _parentEl;
|
|
381
|
+
v_dom = h(RootComponent, props);
|
|
382
|
+
mountDOM(v_dom, parentEl);
|
|
383
|
+
isMounted = true;
|
|
384
|
+
},
|
|
385
|
+
unmount() {
|
|
386
|
+
destroyDOM(v_dom);
|
|
387
|
+
v_dom = null;
|
|
388
|
+
destroyDOM(v_dom);
|
|
389
|
+
reset();
|
|
365
390
|
}
|
|
366
|
-
this.#afterHandlers.forEach((handler) => handler());
|
|
367
391
|
}
|
|
368
392
|
}
|
|
369
393
|
|
|
@@ -372,9 +396,14 @@ function areNodesEqual(nodeOne,nodeTwo){
|
|
|
372
396
|
return false
|
|
373
397
|
}
|
|
374
398
|
if(nodeOne.type === DOM_TYPES.ELEMENT){
|
|
375
|
-
const {tag: tagOne} = nodeOne;
|
|
376
|
-
const {tag: tagTwo} = nodeTwo;
|
|
377
|
-
return tagOne === tagTwo
|
|
399
|
+
const {tag: tagOne,props: {key: keyOne}} = nodeOne;
|
|
400
|
+
const {tag: tagTwo,props: {key: keyTwo}} = nodeTwo;
|
|
401
|
+
return tagOne === tagTwo && keyOne === keyTwo
|
|
402
|
+
}
|
|
403
|
+
if (nodeOne.type === DOM_TYPES.COMPONENT) {
|
|
404
|
+
const {tag: componentOne, props: {key: keyOne}} = nodeOne;
|
|
405
|
+
const {tag: componentTwo, props: {key: keyTwo}} = nodeOne;
|
|
406
|
+
return componentOne === componentTwo && keyOne === keyTwo
|
|
378
407
|
}
|
|
379
408
|
return true
|
|
380
409
|
}
|
|
@@ -398,6 +427,9 @@ function objectsDiff(oldObj, newObj) {
|
|
|
398
427
|
updated: updated
|
|
399
428
|
}
|
|
400
429
|
}
|
|
430
|
+
function hasOwnProperty(obj,prop){
|
|
431
|
+
return Object.prototype.hasOwnProperty.call(obj,prop)
|
|
432
|
+
}
|
|
401
433
|
|
|
402
434
|
function isNotEmptyString(str){
|
|
403
435
|
return str !== ''
|
|
@@ -406,11 +438,11 @@ function isNotBlankOrEmptyString(str){
|
|
|
406
438
|
return isNotEmptyString(str.trim())
|
|
407
439
|
}
|
|
408
440
|
|
|
409
|
-
function patchDom(oldV_dom, newV_dom, parentEl) {
|
|
441
|
+
function patchDom(oldV_dom, newV_dom, parentEl, hostComponent = null) {
|
|
410
442
|
if (!areNodesEqual(oldV_dom, newV_dom)) {
|
|
411
443
|
const index = findIndexInParent(parentEl, oldV_dom.el);
|
|
412
444
|
destroyDOM(oldV_dom);
|
|
413
|
-
mountDOM(newV_dom, parentEl, index);
|
|
445
|
+
mountDOM(newV_dom, parentEl, index, hostComponent);
|
|
414
446
|
return newV_dom
|
|
415
447
|
}
|
|
416
448
|
newV_dom.el = oldV_dom.el;
|
|
@@ -420,11 +452,15 @@ function patchDom(oldV_dom, newV_dom, parentEl) {
|
|
|
420
452
|
return newV_dom
|
|
421
453
|
}
|
|
422
454
|
case DOM_TYPES.ELEMENT: {
|
|
423
|
-
patchElement(oldV_dom, newV_dom);
|
|
455
|
+
patchElement(oldV_dom, newV_dom, hostComponent);
|
|
456
|
+
break
|
|
457
|
+
}
|
|
458
|
+
case DOM_TYPES.COMPONENT: {
|
|
459
|
+
patchComponent(oldV_dom, newV_dom);
|
|
424
460
|
break
|
|
425
461
|
}
|
|
426
462
|
}
|
|
427
|
-
patchChildren(oldV_dom,newV_dom);
|
|
463
|
+
patchChildren(oldV_dom, newV_dom, hostComponent);
|
|
428
464
|
return newV_dom
|
|
429
465
|
}
|
|
430
466
|
function findIndexInParent(parentEl, el) {
|
|
@@ -442,7 +478,7 @@ function patchText(oldV_dom, newV_dom) {
|
|
|
442
478
|
el.nodeValue = newText;
|
|
443
479
|
}
|
|
444
480
|
}
|
|
445
|
-
function patchElement(oldV_dom, newV_dom) {
|
|
481
|
+
function patchElement(oldV_dom, newV_dom, hostComponent) {
|
|
446
482
|
const el = oldV_dom.el;
|
|
447
483
|
const {
|
|
448
484
|
class: oldClass,
|
|
@@ -460,7 +496,14 @@ function patchElement(oldV_dom, newV_dom) {
|
|
|
460
496
|
patchAttrs(el, oldAttrs, newAttrs);
|
|
461
497
|
patchClasses(el, oldClass, newClass);
|
|
462
498
|
patchStyles(el, oldStyle, newStyle);
|
|
463
|
-
newV_dom.listeners = patchEvents(el, oldListeners, oldEvents, newEvents);
|
|
499
|
+
newV_dom.listeners = patchEvents(el, oldListeners, oldEvents, newEvents, hostComponent);
|
|
500
|
+
}
|
|
501
|
+
function patchComponent(oldV_dom, newV_dom) {
|
|
502
|
+
const {component} = oldV_dom;
|
|
503
|
+
const {props} = extractPropsAndEvents(newV_dom);
|
|
504
|
+
component.updateProps(props);
|
|
505
|
+
newV_dom.component = component;
|
|
506
|
+
newV_dom.el = component.firstElement;
|
|
464
507
|
}
|
|
465
508
|
function patchAttrs(el, oldAttrs, newAttrs) {
|
|
466
509
|
const {added, removed, updated} = objectsDiff(oldAttrs, newAttrs);
|
|
@@ -488,36 +531,36 @@ function toClassList(classes = '') {
|
|
|
488
531
|
classes.split("/(\s+)/").filter(isNotBlankOrEmptyString)
|
|
489
532
|
}
|
|
490
533
|
function patchStyles(el, oldStyle = {}, newStyle = {}) {
|
|
491
|
-
const {added,removed,updated} = objectsDiff(oldStyle,newStyle);
|
|
492
|
-
for (const style of removed){
|
|
493
|
-
removeStyle(el,style);
|
|
534
|
+
const {added, removed, updated} = objectsDiff(oldStyle, newStyle);
|
|
535
|
+
for (const style of removed) {
|
|
536
|
+
removeStyle(el, style);
|
|
494
537
|
}
|
|
495
|
-
for(const style of added.concat(updated)){
|
|
496
|
-
setStyle(el,style,newStyle[style]);
|
|
538
|
+
for (const style of added.concat(updated)) {
|
|
539
|
+
setStyle(el, style, newStyle[style]);
|
|
497
540
|
}
|
|
498
541
|
}
|
|
499
|
-
function patchEvents(el, oldListeners = {}, oldEvents = {}, newEvents = {}) {
|
|
500
|
-
const {removed, added, updated} = objectsDiff(oldEvents,newEvents);
|
|
501
|
-
for(const eventName of removed.concat(updated)){
|
|
502
|
-
el.removeEventListener(eventName,oldListeners[eventName]);
|
|
542
|
+
function patchEvents(el, oldListeners = {}, oldEvents = {}, newEvents = {}, hostComponent) {
|
|
543
|
+
const {removed, added, updated} = objectsDiff(oldEvents, newEvents);
|
|
544
|
+
for (const eventName of removed.concat(updated)) {
|
|
545
|
+
el.removeEventListener(eventName, oldListeners[eventName]);
|
|
503
546
|
}
|
|
504
547
|
const addedListeners = {};
|
|
505
|
-
for(const eventName of added.concat(updated)){
|
|
506
|
-
|
|
507
|
-
addedListeners[eventName] = listener;
|
|
548
|
+
for (const eventName of added.concat(updated)) {
|
|
549
|
+
addedListeners[eventName] = addEventListener(eventName, newEvents[eventName], el, hostComponent);
|
|
508
550
|
}
|
|
509
551
|
return addedListeners
|
|
510
552
|
}
|
|
511
|
-
function patchChildren(oldV_dom, newV_dom) {
|
|
553
|
+
function patchChildren(oldV_dom, newV_dom, hostComponent) {
|
|
512
554
|
const oldChildren = extractChildren(oldV_dom);
|
|
513
555
|
const newChildren = extractChildren(newV_dom);
|
|
514
556
|
const parentEl = oldV_dom.el;
|
|
515
|
-
const diffSeq = arraysDiffSequence(oldChildren,newChildren,areNodesEqual);
|
|
516
|
-
for(const operation of diffSeq){
|
|
557
|
+
const diffSeq = arraysDiffSequence(oldChildren, newChildren, areNodesEqual);
|
|
558
|
+
for (const operation of diffSeq) {
|
|
517
559
|
const {originalIndex, index, item} = operation;
|
|
560
|
+
const offset = hostComponent?.offset ?? 0;
|
|
518
561
|
switch (operation.op) {
|
|
519
562
|
case ARRAY_DIFF_OP.ADD: {
|
|
520
|
-
mountDOM(item,parentEl,index);
|
|
563
|
+
mountDOM(item, parentEl, index + offset, hostComponent);
|
|
521
564
|
break
|
|
522
565
|
}
|
|
523
566
|
case ARRAY_DIFF_OP.REMOVE: {
|
|
@@ -528,57 +571,204 @@ function patchChildren(oldV_dom, newV_dom) {
|
|
|
528
571
|
const oldChild = oldChildren[originalIndex];
|
|
529
572
|
const newChild = newChildren[index];
|
|
530
573
|
const el = oldChild.el;
|
|
531
|
-
const elAtTargetIndex = parentEl.childNodes[index];
|
|
532
|
-
parentEl.insertBefore(el,elAtTargetIndex);
|
|
533
|
-
patchDom(oldChild,newChild,parentEl);
|
|
574
|
+
const elAtTargetIndex = parentEl.childNodes[index + offset];
|
|
575
|
+
parentEl.insertBefore(el, elAtTargetIndex);
|
|
576
|
+
patchDom(oldChild, newChild, parentEl, hostComponent);
|
|
534
577
|
break
|
|
535
578
|
}
|
|
536
579
|
case ARRAY_DIFF_OP.NOOP: {
|
|
537
|
-
patchDom(oldChildren[originalIndex],newChildren[index],parentEl);
|
|
580
|
+
patchDom(oldChildren[originalIndex], newChildren[index], parentEl, hostComponent);
|
|
538
581
|
break
|
|
539
582
|
}
|
|
540
583
|
}
|
|
541
584
|
}
|
|
542
585
|
}
|
|
543
586
|
|
|
544
|
-
function
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
587
|
+
function getDefaultExportFromCjs (x) {
|
|
588
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
var fastDeepEqual;
|
|
592
|
+
var hasRequiredFastDeepEqual;
|
|
593
|
+
function requireFastDeepEqual () {
|
|
594
|
+
if (hasRequiredFastDeepEqual) return fastDeepEqual;
|
|
595
|
+
hasRequiredFastDeepEqual = 1;
|
|
596
|
+
fastDeepEqual = function equal(a, b) {
|
|
597
|
+
if (a === b) return true;
|
|
598
|
+
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
|
599
|
+
if (a.constructor !== b.constructor) return false;
|
|
600
|
+
var length, i, keys;
|
|
601
|
+
if (Array.isArray(a)) {
|
|
602
|
+
length = a.length;
|
|
603
|
+
if (length != b.length) return false;
|
|
604
|
+
for (i = length; i-- !== 0;)
|
|
605
|
+
if (!equal(a[i], b[i])) return false;
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
609
|
+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
610
|
+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
611
|
+
keys = Object.keys(a);
|
|
612
|
+
length = keys.length;
|
|
613
|
+
if (length !== Object.keys(b).length) return false;
|
|
614
|
+
for (i = length; i-- !== 0;)
|
|
615
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
616
|
+
for (i = length; i-- !== 0;) {
|
|
617
|
+
var key = keys[i];
|
|
618
|
+
if (!equal(a[key], b[key])) return false;
|
|
619
|
+
}
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
return a!==a && b!==b;
|
|
623
|
+
};
|
|
624
|
+
return fastDeepEqual;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
var fastDeepEqualExports = requireFastDeepEqual();
|
|
628
|
+
var equal = /*@__PURE__*/getDefaultExportFromCjs(fastDeepEqualExports);
|
|
629
|
+
|
|
630
|
+
class Dispatcher {
|
|
631
|
+
#subs = new Map()
|
|
632
|
+
#afterHandlers = []
|
|
633
|
+
subscribe(commandName, handler) {
|
|
634
|
+
if (!this.#subs.has(commandName)) {
|
|
635
|
+
this.#subs.set(commandName, []);
|
|
636
|
+
}
|
|
637
|
+
const handlers = this.#subs.get(commandName);
|
|
638
|
+
if (handlers.includes(handler)) {
|
|
639
|
+
return () => {
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
handlers.push(handler);
|
|
643
|
+
return () => {
|
|
644
|
+
const id = handlers.indexOf(handler);
|
|
645
|
+
handlers.splice(id, 1);
|
|
646
|
+
}
|
|
559
647
|
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
648
|
+
afterEveryCommand(handler) {
|
|
649
|
+
this.#afterHandlers.push(handler);
|
|
650
|
+
return () => {
|
|
651
|
+
const id = this.#afterHandlers.indexOf(handler);
|
|
652
|
+
this.#afterHandlers.splice(id, 1);
|
|
653
|
+
}
|
|
564
654
|
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
655
|
+
dispatch(commandName, payload) {
|
|
656
|
+
if (this.#subs.has(commandName)) {
|
|
657
|
+
this.#subs.get(commandName).forEach((handler) => handler(payload));
|
|
658
|
+
} else {
|
|
659
|
+
console.warn(`No handlers for command ${commandName}`);
|
|
660
|
+
}
|
|
661
|
+
this.#afterHandlers.forEach((handler) => handler());
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function defineComponent({render, state, ...methods}) {
|
|
666
|
+
class Component {
|
|
667
|
+
#isMounted = false
|
|
668
|
+
#v_dom = null
|
|
669
|
+
#hostEl = null
|
|
670
|
+
#eventHandlers = null
|
|
671
|
+
#parentComponent = null
|
|
672
|
+
#dispatcher = new Dispatcher()
|
|
673
|
+
#subscriptions = []
|
|
674
|
+
constructor(props = {}, eventHandlers = {}, parentComponent = {}) {
|
|
675
|
+
this.props = props;
|
|
676
|
+
this.state = state ? state(props) : {};
|
|
677
|
+
this.#eventHandlers = eventHandlers;
|
|
678
|
+
this.#parentComponent = parentComponent;
|
|
679
|
+
}
|
|
680
|
+
#wireEventHandlers() {
|
|
681
|
+
this.#subscriptions = Object.entries(this.#eventHandlers)
|
|
682
|
+
.map(
|
|
683
|
+
([eventName, handler]) => this.#wireEventHandler(eventName, handler)
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
#wireEventHandler(eventName, handler) {
|
|
687
|
+
return this.#dispatcher.subscribe(eventName, (payload) => {
|
|
688
|
+
if (this.#parentComponent) {
|
|
689
|
+
handler.call(this.#parentComponent, payload);
|
|
690
|
+
} else {
|
|
691
|
+
handler(payload);
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
emit(eventName,payload){
|
|
696
|
+
this.#dispatcher.dispatch(eventName,payload);
|
|
697
|
+
}
|
|
698
|
+
get elements() {
|
|
699
|
+
if (this.#v_dom == null) {
|
|
700
|
+
return []
|
|
569
701
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
702
|
+
if (this.#v_dom.type === DOM_TYPES.FRAGMENT) {
|
|
703
|
+
return extractChildren(this.#v_dom).flatMap((child) => {
|
|
704
|
+
if (child.type === DOM_TYPES.COMPONENT) {
|
|
705
|
+
return child.component.elements
|
|
706
|
+
}
|
|
707
|
+
return [child.el]
|
|
708
|
+
})
|
|
709
|
+
}
|
|
710
|
+
return [this.#v_dom.el]
|
|
711
|
+
}
|
|
712
|
+
get firstElement() {
|
|
713
|
+
return this.elements[0]
|
|
714
|
+
}
|
|
715
|
+
get offset() {
|
|
716
|
+
if (this.#v_dom.type === DOM_TYPES.FRAGMENT) {
|
|
717
|
+
return Array.from(this.#hostEl.children).indexOf(this.firstElement)
|
|
718
|
+
}
|
|
719
|
+
return 0
|
|
720
|
+
}
|
|
721
|
+
updateState(state) {
|
|
722
|
+
this.state = {...this.state, ...state};
|
|
723
|
+
this.#patch();
|
|
724
|
+
}
|
|
725
|
+
updateProps(props) {
|
|
726
|
+
const newProps = {...this.props, ...props};
|
|
727
|
+
if (equal(this.props, newProps)) {
|
|
728
|
+
return
|
|
729
|
+
}
|
|
730
|
+
this.props = newProps;
|
|
731
|
+
this.#patch();
|
|
732
|
+
}
|
|
733
|
+
render() {
|
|
734
|
+
return render.call(this)
|
|
735
|
+
}
|
|
736
|
+
mount(hostEl, index = null) {
|
|
737
|
+
if (this.#isMounted) {
|
|
738
|
+
throw new Error("Component is already mounted")
|
|
739
|
+
}
|
|
740
|
+
this.#v_dom = this.render();
|
|
741
|
+
mountDOM(this.#v_dom, hostEl, index, this);
|
|
742
|
+
this.#wireEventHandlers();
|
|
743
|
+
this.#hostEl = hostEl;
|
|
744
|
+
this.#isMounted = true;
|
|
745
|
+
}
|
|
575
746
|
unmount() {
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
747
|
+
if (!this.#isMounted) {
|
|
748
|
+
throw new Error('Component is not mounted')
|
|
749
|
+
}
|
|
750
|
+
destroyDOM(this.#v_dom);
|
|
751
|
+
this.#subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
752
|
+
this.#v_dom = null;
|
|
753
|
+
this.#hostEl = null;
|
|
754
|
+
this.#isMounted = false;
|
|
755
|
+
this.#subscriptions = [];
|
|
756
|
+
}
|
|
757
|
+
#patch() {
|
|
758
|
+
if (!this.#isMounted) {
|
|
759
|
+
throw new Error('Component is not mounted')
|
|
760
|
+
}
|
|
761
|
+
const v_dom = this.render();
|
|
762
|
+
this.#v_dom = patchDom(this.#v_dom, v_dom, this.#hostEl, this);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
for (const methodName in methods) {
|
|
766
|
+
if (hasOwnProperty(Component, methodName)) {
|
|
767
|
+
throw new Error(`Method ${methodName} already exists in the component`)
|
|
580
768
|
}
|
|
769
|
+
Component.prototype[methodName] = methods[methodName];
|
|
581
770
|
}
|
|
771
|
+
return Component
|
|
582
772
|
}
|
|
583
773
|
|
|
584
|
-
export { createApp, h, hFragment, hString };
|
|
774
|
+
export { createApp, defineComponent, h, hFragment, hString };
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vanilla_project",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"main": "dist/vanilla_project.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/vanilla_project.js"
|
|
7
7
|
],
|
|
8
8
|
"devDependencies": {
|
|
9
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
10
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
9
11
|
"eslint": "^9.39.2",
|
|
10
12
|
"jsdom": "^27.4.0",
|
|
11
13
|
"rollup": "^4.55.1",
|
|
@@ -21,10 +23,10 @@
|
|
|
21
23
|
"test": "vitest",
|
|
22
24
|
"test:run": "vitest run"
|
|
23
25
|
},
|
|
24
|
-
"type": "commonjs",
|
|
25
26
|
"dependencies": {
|
|
26
27
|
"@eslint/eslintrc": "^3.3.3",
|
|
27
28
|
"@eslint/js": "^9.39.2",
|
|
29
|
+
"fast-deep-equal": "^3.1.3",
|
|
28
30
|
"globals": "^14.0.0"
|
|
29
31
|
}
|
|
30
32
|
}
|