@fruit-ui/core 1.3.3 → 1.3.4

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/package.json +1 -1
  2. package/src/index.js +64 -69
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fruit-ui/core",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "A vanilla JS toolkit for reactive UI",
5
5
  "main": "src/index.js",
6
6
  "homepage": "https://asantagata.github.io/fruit-ui/",
package/src/index.js CHANGED
@@ -132,6 +132,7 @@ function createThis(component) {
132
132
  */
133
133
  function initializeThis(element, producer) {
134
134
  this.element = element;
135
+ if (producer === null) return;
135
136
  this.producer = producer;
136
137
  this.rerender = rerender.bind(this);
137
138
  this.setState = new Proxy({}, {
@@ -142,6 +143,14 @@ function initializeThis(element, producer) {
142
143
  }
143
144
  }
144
145
  });
146
+ this.bindings = new Proxy({}, {
147
+ get: (o, p, r) => {
148
+ return {
149
+ element: findSubelement(this.element, p),
150
+ rerender: () => rerenderByBinding.call(this, p)
151
+ }
152
+ }
153
+ });
145
154
  }
146
155
 
147
156
  /**
@@ -153,20 +162,26 @@ function initializeThis(element, producer) {
153
162
  * @returns {HTMLElement} - An HTMLElement.
154
163
  */
155
164
  function createElementFromTemplate(template, onMounts, producer = null) {
156
- if (template.cloneFrom) {
165
+ if ('cloneFrom' in template) {
157
166
  const element = template.cloneFrom.cloneNode(true);
158
- if (this && !this.element) {
167
+ if (template.componentId !== undefined) {
168
+ element.dataset.componentId = template.componentId;
159
169
  initializeThis.call(this, element, producer);
160
170
  }
161
171
  return element;
162
- } else if (template.HTML) {
172
+ } else if ('HTML' in template) {
163
173
  const div = document.createElement('div');
164
174
  div.innerHTML = template.HTML;
165
- return div.firstChild;
175
+ const element = div.firstChild;
176
+ if (template.componentId !== undefined) {
177
+ element.dataset.componentId = template.componentId;
178
+ initializeThis.call(this, element, producer);
179
+ }
180
+ return element;
166
181
  }
167
182
  const {tag, class: c, style, on, componentId, children, cloneFrom, dataset, key, binding, innerHTML, xmlns, ...rest} = template;
168
183
  const element = template.xmlns ? document.createElementNS(template.xmlns, template.tag) : document.createElement(template.tag || 'div');
169
- if (template.class) {
184
+ if ('class' in template) {
170
185
  switch (typeof template.class) {
171
186
  case 'string':
172
187
  element.className = template.class;
@@ -180,12 +195,12 @@ function createElementFromTemplate(template, onMounts, producer = null) {
180
195
  }
181
196
  }
182
197
  }
183
- if (template.style) {
198
+ if ('style' in template) {
184
199
  for (const k in template.style) {
185
200
  element.style.setProperty(k, template.style[k]);
186
201
  }
187
202
  }
188
- if (template.on) {
203
+ if ('on' in template) {
189
204
  const {mount: onMount, ...listeners} = template.on;
190
205
  for (const type in listeners) {
191
206
  if (!listeners[type]) continue;
@@ -201,43 +216,30 @@ function createElementFromTemplate(template, onMounts, producer = null) {
201
216
  else
202
217
  element.setAttribute(attribute, template[attribute]);
203
218
  }
204
- if (template.dataset) {
219
+ if ('dataset' in template) {
205
220
  for (const k in template.dataset) {
206
221
  element.dataset[k] = template.dataset[k];
207
222
  }
208
223
  }
209
- if (template.componentId) {
210
- element.dataset.componentId = template.componentId;
211
- }
212
- if (template.key) {
224
+ if (template.key !== undefined) {
213
225
  element.dataset.key = template.key;
214
226
  }
215
- if (template.binding) {
227
+ if (template.binding !== undefined) {
216
228
  element.dataset.binding = template.binding;
217
229
  }
218
- if (this && !this.element) {
230
+ if (template.componentId !== undefined) {
231
+ element.dataset.componentId = template.componentId;
219
232
  initializeThis.call(this, element, producer);
220
233
  }
221
- if (template.innerHTML) {
234
+ if ('innerHTML' in template) {
222
235
  element.innerHTML = template.innerHTML;
223
- } else if (template.children !== undefined) {
236
+ } else if ('children' in template) {
224
237
  if (Array.isArray(template.children)) {
225
238
  element.replaceChildren(
226
239
  ...template.children.map(ct => createElementFromElementable.call(this, ct, onMounts))
227
240
  );
228
- // handle bindings
229
- for (let i = 0; i < template.children.length; i++) {
230
- const childTm = template.children[i];
231
- if (childTm.binding && this) {
232
- setBinding.call(this, childTm.binding, element.childNodes[i]);
233
- }
234
- }
235
241
  } else {
236
242
  element.replaceChildren(createElementFromElementable.call(this, template.children, onMounts));
237
- // handle binding
238
- if (template.children.binding && this) {
239
- setBinding.call(this, template.children.binding, element.childNodes[0]);
240
- }
241
243
  }
242
244
  }
243
245
  return element;
@@ -333,7 +335,7 @@ function doOnMountHandling(func) {
333
335
  function rerender() {
334
336
  doOnMountHandling((onMounts) => {
335
337
  const template = this.producer();
336
- rerenderElementFromTemplate.call(this, this.element, giveTemplateComponentMetadata(template, this.producer.componentId), onMounts);
338
+ rerenderElementFromTemplate.call(this, this.element, giveTemplateComponentMetadata(template, this.element.dataset.componentId, this.element.dataset.key, this.element.dataset.binding), onMounts);
337
339
  });
338
340
  }
339
341
 
@@ -372,7 +374,11 @@ function findSubelement(element, bindingName, atRoot = true) {
372
374
  } else if (!atRoot && 'componentId' in element.dataset) {
373
375
  return undefined;
374
376
  }
375
- return Array.from(element.children).find(c => !!findSubelement(c, bindingName, false));
377
+ for (const child of element.children) {
378
+ const found = findSubelement(child, bindingName, false);
379
+ if (found) return found;
380
+ }
381
+ return undefined;
376
382
  }
377
383
 
378
384
  /**
@@ -389,7 +395,10 @@ function findSubtemplate(template, bindingName, atRoot = true) {
389
395
  }
390
396
  if (template.children) {
391
397
  if (Array.isArray(template.children)) {
392
- return template.children.find(c => findSubtemplate(c, bindingName, false));
398
+ for (const child of template.children) {
399
+ const found = findSubtemplate(child, bindingName, false);
400
+ if (found) return found;
401
+ }
393
402
  } else {
394
403
  return findSubtemplate(template.children, bindingName, false);
395
404
  }
@@ -406,20 +415,32 @@ function findSubtemplate(template, bindingName, atRoot = true) {
406
415
  */
407
416
  function rerenderElementFromTemplate(element, template, onMounts) {
408
417
  if (typeof template !== 'object') {
409
- return element.replaceWith(template.toString());
418
+ element.replaceWith(template.toString());
410
419
  }
411
- if (template.cloneFrom && !element.isEqualNode(template.cloneFrom)) {
412
- return element.replaceWith(template.cloneFrom.cloneNode(true));
413
- } else if (template.HTML) {
420
+ if ('cloneFrom' in template && !element.isEqualNode(template.cloneFrom)) {
421
+ const newElement = template.cloneFrom.cloneNode(true);
422
+ if (template.componentId !== undefined) {
423
+ newElement.dataset.componentId = template.componentId;
424
+ this.element = newElement;
425
+ }
426
+ return element.replaceWith(newElement);
427
+ } else if ('HTML' in template) {
414
428
  const div = document.createElement('div');
415
429
  div.innerHTML = template.HTML;
416
- return element.replaceWith(div.firstChild);
430
+ const newElement = div.firstChild;
431
+ if (template.componentId !== undefined) {
432
+ newElement.dataset.componentId = template.componentId;
433
+ this.element = newElement;
434
+ }
435
+ return element.replaceWith(newElement);
417
436
  }
418
- if ((template.tag?.toUpperCase() || 'DIV') !== element.tagName) {
419
- // tag cannot be changed
420
- return element.replaceWith(createElementFromElementable.call(this, template, onMounts));
437
+ if ((template.tag?.toUpperCase() || 'DIV') !== element.tagName.toUpperCase()) {
438
+ const newElement = createElementFromElementable.call(this, template, onMounts);
439
+ if ('componentId' in template)
440
+ this.element = newElement;
441
+ return element.replaceWith(newElement);
421
442
  }
422
- if (template.class) {
443
+ if ('class' in template) {
423
444
  if (typeof template.class === 'string') {
424
445
  element.className = template.class;
425
446
  } else if (Array.isArray(template)) {
@@ -434,12 +455,12 @@ function rerenderElementFromTemplate(element, template, onMounts) {
434
455
  }
435
456
  }
436
457
  }
437
- if (template.style) {
458
+ if ('style' in template) {
438
459
  for (const k in template.style) {
439
460
  element.style.setProperty(k, template.style[k]);
440
461
  }
441
462
  }
442
- if (template.dataset) {
463
+ if ('dataset' in template) {
443
464
  for (let key in template.dataset) {
444
465
  element.dataset[key] = template.dataset[key];
445
466
  }
@@ -451,7 +472,7 @@ function rerenderElementFromTemplate(element, template, onMounts) {
451
472
  else
452
473
  element.setAttribute(attribute, template[attribute]);
453
474
  }
454
- if (template.innerHTML) {
475
+ if ('innerHTML' in template) {
455
476
  element.innerHTML = template.innerHTML;
456
477
  } else if (template.children === undefined || template.children.length === 0) {
457
478
  element.innerHTML = "";
@@ -533,7 +554,7 @@ function rerenderChildComponent(element, component, onMounts) {
533
554
  return;
534
555
  }
535
556
  cmpThis.producer = component.render.bind(cmpThis);
536
- rerenderElementFromTemplate.call(cmpThis, element, cmpThis.producer(), onMounts);
557
+ rerenderElementFromTemplate.call(cmpThis, element, giveTemplateComponentMetadata(cmpThis.producer(), element.dataset.componentId, component.key, component.binding), onMounts);
537
558
  }
538
559
 
539
560
  /**
@@ -612,7 +633,6 @@ function rerenderChildren(element, template, onMounts) {
612
633
  delete thisRecord[childEl.dataset.componentId];
613
634
  }
614
635
  }
615
- if ('binding' in childEl.dataset) delete this.bindings[childEl.dataset.binding];
616
636
  childEl.remove();
617
637
  }
618
638
  }
@@ -641,8 +661,6 @@ function rerenderChildren(element, template, onMounts) {
641
661
  // handle first Min(M,N) elements
642
662
  for (let i = 0; i < Math.min(elChildrenArray.length, tmChildrenArray.length); i++) {
643
663
  let childEl = elChildrenArray[i], childTm = tmChildrenArray[i];
644
- if ('binding' in childEl.dataset && childEl.dataset.binding !== childTm.binding)
645
- delete this.bindings[childEl.dataset.binding];
646
664
  if (elementableIsComponent(childTm)) {
647
665
  if ('componentId' in childEl.dataset) rerenderChildComponent(childEl, childTm, onMounts);
648
666
  else childEl.replaceWith(createElementFromComponent(childTm, onMounts));
@@ -663,7 +681,6 @@ function rerenderChildren(element, template, onMounts) {
663
681
  for (let i = elChildrenArray.length - 1; i >= tmChildrenArray.length; i--) {
664
682
  let childEl = elChildrenArray[i];
665
683
  if ('componentId' in childEl.dataset) delete thisRecord[childEl.dataset.componentId];
666
- if ('binding' in childEl.dataset) delete this.bindings[childEl.dataset.binding];
667
684
  childEl.remove();
668
685
  }
669
686
  }
@@ -672,7 +689,6 @@ function rerenderChildren(element, template, onMounts) {
672
689
  for (let i = elChildrenArray.length - 1; i >= 0; i--) {
673
690
  let childEl = elChildrenArray[i];
674
691
  if ('componentId' in childEl.dataset) delete thisRecord[childEl.dataset.componentId];
675
- if ('binding' in childEl.dataset) delete this.bindings[childEl.dataset.binding];
676
692
  childEl.remove();
677
693
  }
678
694
  } else if (tmChildrenArray.length > 0 && elChildrenArray.length === 0) {
@@ -684,14 +700,6 @@ function rerenderChildren(element, template, onMounts) {
684
700
  }
685
701
  }
686
702
 
687
- // handle bindings
688
- for (let i = 0; i < tmChildrenArray.length; i++) {
689
- const childTm = tmChildrenArray[i];
690
- if (childTm.binding) {
691
- setBinding.call(this, childTm.binding, element.children[i]);
692
- }
693
- }
694
-
695
703
  // handle text nodes
696
704
  for (let i = 0; i < tmChildNodeArray.length; i++) {
697
705
  if (i >= element.childNodes.length) {
@@ -748,19 +756,6 @@ function LIS(arr) {
748
756
  return S;
749
757
  }
750
758
 
751
- /**
752
- * Sets a binding in a This.
753
- * @param {This} this - the This.
754
- * @param {string} bindingName - the name of the binding.
755
- * @param {HTMLElement} element - the element being bound.
756
- */
757
- function setBinding(bindingName, element) {
758
- this.bindings[bindingName] = {
759
- element,
760
- rerender: () => rerenderByBinding.call(this, bindingName)
761
- };
762
- }
763
-
764
759
  /**
765
760
  * Creates an HTMLElement given an Elementable.
766
761
  * @param {Elementable} elementable - the Elementable.