native-document 1.0.17-1.7 → 1.0.17-1.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-document",
3
- "version": "1.0.171.7",
3
+ "version": "1.0.171.9",
4
4
  "description": "A reactive JavaScript framework that preserves native DOM simplicity without sacrificing modern features",
5
5
  "author": "AfroCodeur <https://github.com/afrocodeur>",
6
6
  "license": "MIT",
@@ -23,7 +23,12 @@ const MemoryManager = (function() {
23
23
  $observables.delete(id);
24
24
  },
25
25
  getObservableById(id) {
26
- return $observables.get(id)?.deref();
26
+ const observable = $observables.get(id);
27
+ if(!observable) {
28
+ $observables.delete(id);
29
+ return null;
30
+ }
31
+ return observable.deref();
27
32
  },
28
33
  cleanup() {
29
34
  for (const [_, weakObservableRef] of $observables) {
@@ -556,7 +556,12 @@ ObservableItem.prototype.reset = function() {
556
556
  * @returns {string} String representation of the current value
557
557
  */
558
558
  ObservableItem.prototype.toString = function() {
559
- return String(this.$currentValue);
559
+ if(this.$id) {
560
+ return this.$id.toString();
561
+ }
562
+ const id = MemoryManager.register(this);
563
+ this.$id = id;
564
+ return '{{obs:'+id+'}}';
560
565
  };
561
566
 
562
567
  /**
@@ -24,6 +24,25 @@ export const Label = HtmlElementWrapper('label');
24
24
  */
25
25
  export const P = HtmlElementWrapper('p');
26
26
 
27
+
28
+ /**
29
+ * Parses a string containing Observable placeholders and returns an array
30
+ * of strings and Observable instances ready to be used as NativeDocument children.
31
+ *
32
+ * Observable placeholders are generated automatically when an ObservableItem
33
+ * is interpolated in a template string via its toString() method.
34
+ *
35
+ * @param {string} string - Template string with optional Observable placeholders
36
+ * @returns {Array<string|ObservableItem>} Mixed array of static strings and resolved Observables
37
+ * @example
38
+ * const name = Observable('John');
39
+ * const count = Observable(5);
40
+ *
41
+ * Text(`Hello ${name}, count: ${count}`)
42
+ * // → ['Hello ', ObservableItem(John), ', count: ', ObservableItem(5)]
43
+ */
44
+ export const Text = (string) => string.toNdChildren();
45
+
27
46
  /**
28
47
  * Alias for {@link P}.
29
48
  * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLParagraphElement}
@@ -176,11 +176,11 @@ export function ForEachArray(data, callback, configs = {}) {
176
176
  }
177
177
  },
178
178
  add: (items) => {
179
- Actions.appendToElement(items)
179
+ Actions.appendToElement(items);
180
180
  },
181
181
  replace: (items) => {
182
182
  clear(items);
183
- Actions.appendToElement(items)
183
+ Actions.appendToElement(items);
184
184
  },
185
185
  set,
186
186
  reOrder: (items) => {
@@ -1,8 +1,9 @@
1
1
  import Validator from '../utils/validator';
2
- import NativeDocumentError from '../errors/NativeDocumentError';
3
2
  import {BOOL_ATTRIBUTES_NAME, BOOLEAN_ATTRIBUTES} from './constants.js';
4
3
  import {Observable} from '../data/Observable';
5
4
 
5
+
6
+
6
7
  /**
7
8
  * Applies a reactive class map to an HTMLElement.
8
9
  * Each key is a CSS class name; each value is a boolean or ObservableItem<boolean>.
@@ -14,7 +15,6 @@ import {Observable} from '../data/Observable';
14
15
  export const bindClassAttribute = (element, data) => {
15
16
  for(const className in data) {
16
17
  const value = data[className];
17
-
18
18
  if (value.__$isObservableChecker) {
19
19
  let lastClass = value.val();
20
20
  if (typeof lastClass === 'string') {
@@ -24,19 +24,19 @@ export const bindClassAttribute = (element, data) => {
24
24
  element.classes.toggle(currentValue, true);
25
25
  lastClass = currentValue;
26
26
  });
27
- continue;
27
+ return;
28
28
  }
29
29
  }
30
30
 
31
31
  if (value.__$Observable) {
32
32
  element.classes.toggle(className, value.val());
33
33
  value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
34
- continue;
34
+ return;
35
35
  }
36
36
 
37
37
  if (value.$hydrate) {
38
38
  value.$hydrate(element, className);
39
- continue;
39
+ return;
40
40
  }
41
41
 
42
42
  element.classes.toggle(className, value);
@@ -88,6 +88,16 @@ export const ElementCreator = {
88
88
  if(process.env.NODE_ENV === 'development') {
89
89
  PluginsManager.emit('BeforeProcessChildren', parent);
90
90
  }
91
+ if(Array.isArray(children)) {
92
+ for(let i = 0, length = children.length; i < length; i++) {
93
+ const child = ElementCreator.getChild(children[i]);
94
+ if(child === null) {
95
+ continue;
96
+ }
97
+ parent.appendChild(child);
98
+ }
99
+ return;
100
+ }
91
101
  const child = ElementCreator.getChild(children);
92
102
  parent.appendChild(child);
93
103
  if(process.env.NODE_ENV === 'development') {
@@ -54,7 +54,7 @@ const OBJECT_PROTOTYPE = Object.prototype;
54
54
  */
55
55
  export const createHtmlElement = (element, _attributes, _children = null) => {
56
56
  let attributes = _attributes, children = _children;
57
- if(_attributes.__$isValidNdChild) { // If attributes is a ValidChild
57
+ if(_attributes?.__$isValidNdChild) { // If attributes is a ValidChild
58
58
  attributes = _children;
59
59
  children = _attributes;
60
60
  }
@@ -434,7 +434,6 @@ NDElement.prototype.style = function(style) {
434
434
  return this;
435
435
  };
436
436
 
437
-
438
437
  /**
439
438
  * Extends the NDElement prototype with new methods available to all NDElement instances.
440
439
  * Use this to add global methods to all NDElements.
@@ -20,13 +20,17 @@ Object.defineProperty(NDElement.prototype, 'nd', {
20
20
  });
21
21
 
22
22
 
23
-
24
23
  // ----------------------------------------------------------------
25
24
  // Events helpers
26
25
  // ----------------------------------------------------------------
27
26
  EVENTS.forEach(eventSourceName => {
28
27
  const eventName = eventSourceName.toLowerCase();
29
- NDElement.prototype['on'+eventSourceName] = function(callback = null, options = {}) {
28
+ const inlineHandler = 'on'+eventName;
29
+ NDElement.prototype['on'+eventSourceName] = function(callback = null, options = null) {
30
+ if(!this.$element[inlineHandler] && !options) {
31
+ this.$element[inlineHandler] = callback;
32
+ return this;
33
+ }
30
34
  this.$element.addEventListener(eventName, callback, options);
31
35
  return this;
32
36
  };
@@ -34,11 +38,11 @@ EVENTS.forEach(eventSourceName => {
34
38
 
35
39
  EVENTS_WITH_STOP.forEach(eventSourceName => {
36
40
  const eventName = eventSourceName.toLowerCase();
37
- NDElement.prototype['onStop'+eventSourceName] = function(callback = null, options = {}) {
41
+ NDElement.prototype['onStop'+eventSourceName] = function(callback = null, options = null) {
38
42
  _stop(this.$element, eventName, callback, options);
39
43
  return this;
40
44
  };
41
- NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null, options = {}) {
45
+ NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null, options = null) {
42
46
  _preventStop(this.$element, eventName, callback, options);
43
47
  return this;
44
48
  };
@@ -46,7 +50,7 @@ EVENTS_WITH_STOP.forEach(eventSourceName => {
46
50
 
47
51
  EVENTS_WITH_PREVENT.forEach(eventSourceName => {
48
52
  const eventName = eventSourceName.toLowerCase();
49
- NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null, options = {}) {
53
+ NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null, options = null) {
50
54
  _prevent(this.$element, eventName, callback, options);
51
55
  return this;
52
56
  };
@@ -122,8 +126,13 @@ const _prevent = function(element, eventName, callback, options) {
122
126
  event.preventDefault();
123
127
  callback && callback.call(element, event);
124
128
  };
129
+
130
+ const inlineHandler = 'on' + eventName;
131
+ if(!element[inlineHandler] && !options) {
132
+ element[inlineHandler] = handler;
133
+ return;
134
+ }
125
135
  element.addEventListener(eventName, handler, options);
126
- return this;
127
136
  };
128
137
 
129
138
  const _stop = function(element, eventName, callback, options) {
@@ -131,6 +140,13 @@ const _stop = function(element, eventName, callback, options) {
131
140
  event.stopPropagation();
132
141
  callback && callback.call(element, event);
133
142
  };
143
+
144
+ const inlineHandler = 'on' + eventName;
145
+ if(!element[inlineHandler] && !options) {
146
+ element[inlineHandler] = handler;
147
+ return;
148
+ }
149
+
134
150
  element.addEventListener(eventName, handler, options);
135
151
  return this;
136
152
  };
@@ -141,6 +157,11 @@ const _preventStop = function(element, eventName, callback, options) {
141
157
  event.preventDefault();
142
158
  callback && callback.call(element, event);
143
159
  };
160
+ const inlineHandler = 'on' + eventName;
161
+ if(!element[inlineHandler] && !options) {
162
+ element[inlineHandler] = handler;
163
+ return;
164
+ }
144
165
  element.addEventListener(eventName, handler, options);
145
166
  return this;
146
167
  };
@@ -4,6 +4,43 @@ import TemplateBinding from '../TemplateBinding';
4
4
  import { ElementCreator } from '../ElementCreator';
5
5
  import PluginsManager from '../../utils/plugins-manager';
6
6
  import ObservableChecker from '../../data/ObservableChecker';
7
+ import MemoryManager from '../../data/MemoryManager';
8
+
9
+
10
+
11
+ const OBS_PATTERN = /({{obs:\d+}})/;
12
+ const OBS_ID_PATTERN = /\d+/;
13
+
14
+
15
+ /**
16
+ * Parses a string containing Observable placeholders and returns an array
17
+ * of strings and Observable instances.
18
+ *
19
+ * Placeholders are generated automatically when an ObservableItem is interpolated
20
+ * in a template string via its toString() method.
21
+ *
22
+ * @returns {Array<string|ObservableItem>} Mixed array of static strings and resolved Observables
23
+ * @example
24
+ * const name = Observable('John');
25
+ * const count = Observable(5);
26
+ *
27
+ * `Hello ${name}, count: ${count}`.toNdChildren()
28
+ * // → ['Hello ', ObservableItem(John), ', count: ', ObservableItem(5)]
29
+ */
30
+ Object.defineProperty(String.prototype, 'toNdChildren', {
31
+ value: function() {
32
+ return this.split(OBS_PATTERN).filter(Boolean).map((item) => {
33
+ if(OBS_PATTERN.test(item)) {
34
+ const id = item.match(OBS_ID_PATTERN)[0];
35
+ return MemoryManager.getObservableById(Number(id));
36
+ }
37
+ return item;
38
+ });
39
+ },
40
+ writable: true,
41
+ configurable: true,
42
+ enumerable: false,
43
+ });
7
44
 
8
45
  /**
9
46
  * Registers a non-enumerable toNdElement method on a prototype.
@@ -2,6 +2,9 @@
2
2
  import { ObservableItem } from './observable';
3
3
  import { BindingHydrator } from './template-cloner';
4
4
  import { NDElement } from './nd-element';
5
+ import {AnchorAttributes,
6
+ AudioAttributes, CanvasAttributes, DetailsAttributes, DialogAttributes, GlobalAttributes, OlAttributes,
7
+ SourceAttributes, SvgAttributes, TrackAttributes, VideoAttributes, ThAttributes, ModAttributes, TdAttributes, TimeAttributes } from './globals';
5
8
 
6
9
  // - Re-export all attribute types and utilities from globals
7
10
  export type {
@@ -75,6 +78,8 @@ export type NdHTMLElement<T extends HTMLElement = HTMLElement> = T & { nd: NDEle
75
78
  // Text & structural elements
76
79
  // ---------------------------------------------------------
77
80
 
81
+
82
+ export declare function Text(string: string): string | Array<string | ObservableItem>;
78
83
  export declare const Div: ElementFunction<GlobalAttributes, HTMLDivElement>;
79
84
  export declare const Span: ElementFunction<GlobalAttributes, HTMLSpanElement>;
80
85
  export declare const P: ElementFunction<GlobalAttributes, HTMLParagraphElement>;