ks-fwork 3.0.1 → 3.0.2

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.
Files changed (2) hide show
  1. package/dist/ks-fwork.js +61 -32
  2. package/package.json +1 -1
package/dist/ks-fwork.js CHANGED
@@ -315,6 +315,12 @@ function removeAttribute(el, name) {
315
315
  el.removeAttribute(name);
316
316
  }
317
317
 
318
+ function extractPropsAndEvents(vNode) {
319
+ const { on: events = {}, ...props } = vNode.props;
320
+ delete props.key;
321
+ return { props, events }
322
+ }
323
+
318
324
  function mountDOM(vNode, parentEl, index, hostComponent = null) {
319
325
  switch (vNode.type) {
320
326
  case DOM_TYPES.TEXT: {
@@ -330,7 +336,7 @@ function mountDOM(vNode, parentEl, index, hostComponent = null) {
330
336
  break;
331
337
  }
332
338
  case DOM_TYPES.COMPONENT: {
333
- createComponentNode(vNode, parentEl, index);
339
+ createComponentNode(vNode, parentEl, index, hostComponent);
334
340
  }
335
341
  default: {
336
342
  throw new Error(`Can't mount virtual node of type: ${vNode.type}`);
@@ -344,9 +350,9 @@ function createTextNode(vNode, parentEl, index) {
344
350
  insert(textNode, parentEl, index);
345
351
  }
346
352
  function createElementNode(vNode, parentEl, index, hostComponent) {
347
- const { tag, props, children } = vNode;
353
+ const { tag, children } = vNode;
348
354
  const el = document.createElement(tag);
349
- addProps(el, props, vNode, hostComponent);
355
+ addProps(el, vNode, hostComponent);
350
356
  vNode.el = el;
351
357
  children.forEach((child) => mountDOM(child, el, null, hostComponent));
352
358
  insert(el, parentEl, index);
@@ -360,14 +366,14 @@ function createFragmentNode(vNode, parentEl, index, hostComponent) {
360
366
  }
361
367
  function createComponentNode(vNode, parentEl, index, hostComponent) {
362
368
  const Component = vNode.tag;
363
- const props = vNode.props;
364
- const component = new Component(props);
369
+ const { props, events } = extractPropsAndEvents(vNode);
370
+ const component = new Component(props, events, hostComponent);
365
371
  component.mount(parentEl, index);
366
372
  vNode.component = component;
367
373
  vNode.el = component.firstElement;
368
374
  }
369
- function addProps(el, props, vNode, hostComponent) {
370
- const { on: events, ...attrs} = props;
375
+ function addProps(el, vNode, hostComponent) {
376
+ const { props: attrs, events} = extractPropsAndEvents(vNode);
371
377
  vNode.listeners = addEventListeners(events, el, hostComponent);
372
378
  setAttributes(el, attrs);
373
379
  }
@@ -390,7 +396,14 @@ function insert(el, parentEl, index) {
390
396
  function areNodesEqual(nodeOne, nodeTwo) {
391
397
  if (nodeOne.type !== nodeTwo.type) return false;
392
398
  if (nodeOne.type === DOM_TYPES.ELEMENT) {
393
- return nodeOne.tag === nodeTwo.tag;
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 } } = nodeTwo;
406
+ return componentOne === componentTwo && keyOne === keyTwo;
394
407
  }
395
408
  return true;
396
409
  }
@@ -477,7 +490,7 @@ function patchElement(oldVNode, newVNode, hostComponent) {
477
490
  }
478
491
  function patchComponent(oldVNode, newVNode) {
479
492
  const { component } = oldVNode;
480
- const { props } = newVNode;
493
+ const { props } = extractPropsAndEvents(newVNode);
481
494
  component.updateProps(props);
482
495
  newVNode.component = component;
483
496
  newVNode.el = component.firstElement;
@@ -559,40 +572,29 @@ function patchChildren(oldVNode, newVNode, hostComponent) {
559
572
  }
560
573
  }
561
574
 
562
- function createApp({state, view, reducers = {} }) {
575
+ function createApp(RootComponent, props = {}) {
563
576
  let parentEl = null;
564
577
  let rootNode = null;
565
578
  let isMounted = false;
566
579
  const dispatcher = new Dispatcher();
567
- const unsubscribers = [dispatcher.afterEveryCommand(renderApp)];
568
- for (const actionName in reducers) {
569
- const reducer = reducers[actionName];
570
- const unsubscribe = dispatcher.subscribe(actionName, (payload) => {
571
- state = reducer(state, payload);
572
- });
573
- unsubscribers.push(unsubscribe);
574
- }
575
- function emit(actionName, payload) {
576
- dispatcher.dispatch(actionName, payload);
577
- }
578
- function renderApp() {
579
- const newRootNode = view(state, emit);
580
- rootNode = patchDOM(rootNode, newRootNode, parentEl);
580
+ [dispatcher.afterEveryCommand(renderApp)];
581
+ function reset() {
582
+ parentEl = null;
583
+ rootNode = null;
584
+ isMounted = false;
581
585
  }
582
586
  return {
583
587
  mount(_parentEl) {
584
588
  if (isMounted) throw new Error('The application is already mounted');
585
589
  parentEl = _parentEl;
586
- rootNode = view(state, emit);
590
+ rootNode = h(RootComponent, props);
587
591
  mountDOM(rootNode, parentEl);
592
+ isMounted = true;
588
593
  },
589
594
  unmount() {
590
- if (rootNode) {
591
- destroyDOM(rootNode);
592
- }
593
- rootNode = null;
594
- unsubscribers.forEach((unsubscribe) => unsubscribe());
595
- isMounted = false;
595
+ if (!isMounted) throw new Error('The application is not mounted');
596
+ destroyDOM(rootNode);
597
+ reset();
596
598
  },
597
599
  }
598
600
  }
@@ -645,9 +647,15 @@ function defineComponent({ render, state, ...methods }) {
645
647
  #isMounted = false;
646
648
  #vNode = null;
647
649
  #hostEl = null;
648
- constructor(props = {}) {
650
+ #eventHandlers = null;
651
+ #parentComponent = null;
652
+ #dispatcher = new Dispatcher();
653
+ #subscriptions = [];
654
+ constructor(props = {}, eventHandlers = {}, parentComponent = null) {
649
655
  this.props = props;
650
656
  this.state = state ? state(props) : {};
657
+ this.#eventHandlers = eventHandlers;
658
+ this.#parentComponent = parentComponent;
651
659
  }
652
660
  get elements() {
653
661
  if (this.#vNode == null) {
@@ -687,12 +695,16 @@ function defineComponent({ render, state, ...methods }) {
687
695
  render() {
688
696
  return render.call(this);
689
697
  }
698
+ emit(eventName, payload) {
699
+ this.#dispatcher.dispatch(eventName, payload);
700
+ }
690
701
  mount(hostEl, index = null) {
691
702
  if (this.#isMounted) {
692
703
  throw new Error('Component is already mounted');
693
704
  }
694
705
  this.#vNode = this.render();
695
706
  mountDOM(this.#vNode, hostEl, index, this);
707
+ this.#wireEventHandlers();
696
708
  this.#hostEl = hostEl;
697
709
  this.#isMounted = true;
698
710
  }
@@ -701,9 +713,11 @@ function defineComponent({ render, state, ...methods }) {
701
713
  throw new Error('Component is not mounted');
702
714
  }
703
715
  destroyDOM(this.#vNode);
716
+ this.#subscriptions.forEach((unsubscribe) => unsubscribe());
704
717
  this.#vNode = null;
705
718
  this.#hostEl = null;
706
719
  this.#isMounted = false;
720
+ this.#subscriptions = [];
707
721
  }
708
722
  #patch() {
709
723
  if (!this.#isMounted) {
@@ -712,6 +726,21 @@ function defineComponent({ render, state, ...methods }) {
712
726
  const vNode = this.render();
713
727
  this.#vNode = patchDOM(this.#vNode, vNode, this.#hostEl, this);
714
728
  }
729
+ #wireEventHandlers() {
730
+ this.#subscriptions = Object.entries(this.#eventHandlers).map(
731
+ ([eventName, handler]) =>
732
+ this.#wireEventHandler(eventName, handler)
733
+ );
734
+ }
735
+ #wireEventHandler(eventName, handler) {
736
+ return this.#dispatcher.subscribe(eventName, (payload) => {
737
+ if (this.#parentComponent) {
738
+ handler.call(this.#parentComponent, payload);
739
+ } else {
740
+ handler(payload);
741
+ }
742
+ })
743
+ }
715
744
  }
716
745
  for (const methodName in methods) {
717
746
  if (hasOwnProperty(Component, methodName)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ks-fwork",
3
- "version": "3.0.1",
3
+ "version": "3.0.2",
4
4
  "description": "Demo Frontend Framework",
5
5
  "license": "ISC",
6
6
  "author": "",