native-document 1.0.92 → 1.0.94

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 (85) hide show
  1. package/dist/native-document.components.min.js +1088 -65
  2. package/dist/native-document.dev.js +695 -142
  3. package/dist/native-document.dev.js.map +1 -1
  4. package/dist/native-document.devtools.min.js +1 -1
  5. package/dist/native-document.min.js +1 -1
  6. package/docs/advanced-components.md +814 -0
  7. package/docs/anchor.md +71 -11
  8. package/docs/cache.md +888 -0
  9. package/docs/conditional-rendering.md +91 -1
  10. package/docs/core-concepts.md +9 -2
  11. package/docs/elements.md +127 -2
  12. package/docs/extending-native-document-element.md +7 -1
  13. package/docs/filters.md +1216 -0
  14. package/docs/getting-started.md +12 -3
  15. package/docs/lifecycle-events.md +10 -2
  16. package/docs/list-rendering.md +453 -54
  17. package/docs/memory-management.md +9 -7
  18. package/docs/native-document-element.md +30 -9
  19. package/docs/native-fetch.md +744 -0
  20. package/docs/observables.md +135 -6
  21. package/docs/routing.md +7 -1
  22. package/docs/state-management.md +7 -1
  23. package/docs/validation.md +8 -1
  24. package/elements.js +1 -0
  25. package/eslint.config.js +3 -3
  26. package/index.def.js +350 -0
  27. package/package.json +3 -2
  28. package/readme.md +53 -14
  29. package/src/components/$traits/HasItems.js +42 -1
  30. package/src/components/BaseComponent.js +4 -1
  31. package/src/components/accordion/Accordion.js +112 -8
  32. package/src/components/accordion/AccordionItem.js +93 -4
  33. package/src/components/alert/Alert.js +164 -4
  34. package/src/components/avatar/Avatar.js +236 -22
  35. package/src/components/menu/index.js +1 -2
  36. package/src/core/data/ObservableArray.js +120 -2
  37. package/src/core/data/ObservableChecker.js +50 -0
  38. package/src/core/data/ObservableItem.js +124 -4
  39. package/src/core/data/ObservableWhen.js +36 -6
  40. package/src/core/data/observable-helpers/array.js +12 -3
  41. package/src/core/data/observable-helpers/computed.js +17 -4
  42. package/src/core/data/observable-helpers/object.js +19 -3
  43. package/src/core/elements/content-formatter.js +138 -1
  44. package/src/core/elements/control/for-each-array.js +20 -2
  45. package/src/core/elements/control/for-each.js +17 -5
  46. package/src/core/elements/control/show-if.js +31 -15
  47. package/src/core/elements/control/show-when.js +23 -0
  48. package/src/core/elements/control/switch.js +40 -10
  49. package/src/core/elements/description-list.js +14 -0
  50. package/src/core/elements/form.js +188 -4
  51. package/src/core/elements/html5-semantics.js +44 -1
  52. package/src/core/elements/img.js +22 -10
  53. package/src/core/elements/index.js +5 -0
  54. package/src/core/elements/interactive.js +19 -1
  55. package/src/core/elements/list.js +28 -1
  56. package/src/core/elements/medias.js +29 -0
  57. package/src/core/elements/meta-data.js +34 -0
  58. package/src/core/elements/table.js +59 -0
  59. package/src/core/utils/cache.js +5 -0
  60. package/src/core/utils/helpers.js +7 -2
  61. package/src/core/utils/memoize.js +25 -16
  62. package/src/core/utils/prototypes.js +3 -2
  63. package/src/core/wrappers/AttributesWrapper.js +1 -1
  64. package/src/core/wrappers/HtmlElementWrapper.js +2 -2
  65. package/src/core/wrappers/NDElement.js +42 -2
  66. package/src/core/wrappers/NdPrototype.js +4 -0
  67. package/src/core/wrappers/TemplateCloner.js +14 -11
  68. package/src/core/wrappers/prototypes/bind-class-extensions.js +1 -1
  69. package/src/core/wrappers/prototypes/nd-element-extensions.js +3 -0
  70. package/src/router/Route.js +9 -4
  71. package/src/router/Router.js +28 -9
  72. package/src/router/errors/RouterError.js +0 -1
  73. package/types/control-flow.d.ts +9 -6
  74. package/types/elements.d.ts +496 -111
  75. package/types/filters/index.d.ts +4 -0
  76. package/types/forms.d.ts +85 -48
  77. package/types/images.d.ts +16 -9
  78. package/types/nd-element.d.ts +5 -238
  79. package/types/observable.d.ts +9 -3
  80. package/types/router.d.ts +5 -1
  81. package/types/template-cloner.ts +1 -0
  82. package/types/validator.ts +11 -1
  83. package/utils.d.ts +2 -1
  84. package/utils.js +4 -4
  85. package/src/core/utils/service.js +0 -6
@@ -1,12 +1,55 @@
1
1
  import HtmlElementWrapper from "../wrappers/HtmlElementWrapper";
2
2
 
3
+ /**
4
+ * Creates a `<main>` element.
5
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
6
+ */
3
7
  export const Main = HtmlElementWrapper('main');
8
+
9
+ /**
10
+ * Creates a `<section>` element.
11
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
12
+ */
4
13
  export const Section = HtmlElementWrapper('section');
14
+
15
+ /**
16
+ * Creates an `<article>` element.
17
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
18
+ */
5
19
  export const Article = HtmlElementWrapper('article');
20
+
21
+ /**
22
+ * Creates an `<aside>` element.
23
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
24
+ */
6
25
  export const Aside = HtmlElementWrapper('aside');
26
+
27
+ /**
28
+ * Creates a `<nav>` element.
29
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
30
+ */
7
31
  export const Nav = HtmlElementWrapper('nav');
32
+
33
+ /**
34
+ * Creates a `<figure>` element.
35
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
36
+ */
8
37
  export const Figure = HtmlElementWrapper('figure');
38
+
39
+ /**
40
+ * Creates a `<figcaption>` element.
41
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
42
+ */
9
43
  export const FigCaption = HtmlElementWrapper('figcaption');
10
44
 
45
+ /**
46
+ * Creates a `<header>` element.
47
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
48
+ */
11
49
  export const Header = HtmlElementWrapper('header');
12
- export const Footer = HtmlElementWrapper('footer');
50
+
51
+ /**
52
+ * Creates a `<footer>` element.
53
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
54
+ */
55
+ export const Footer = HtmlElementWrapper('footer');
@@ -2,18 +2,30 @@ import HtmlElementWrapper from "../wrappers/HtmlElementWrapper"
2
2
  import Validator from "../utils/validator";
3
3
  import NativeDocumentError from "../errors/NativeDocumentError";
4
4
 
5
+ /**
6
+ * Creates an `<img>` element.
7
+ * @type {function(ImgAttributes=): HTMLImageElement}
8
+ */
5
9
  export const BaseImage = HtmlElementWrapper('img');
10
+
11
+ /**
12
+ * Creates an `<img>` element.
13
+ * @param {Observable<string>|string} src
14
+ * @param {Omit<ImgAttributes, 'src'>} [attributes]
15
+ * @returns {HTMLImageElement}
16
+ */
6
17
  export const Img = function(src, attributes) {
7
18
  return BaseImage({ src, ...attributes });
8
19
  };
9
20
 
10
21
  /**
11
- *
12
- * @param {string} src
13
- * @param {string|null} defaultImage
14
- * @param {Object} attributes
15
- * @param {?Function} callback
16
- * @returns {Image}
22
+ * Creates an `<img>` that loads asynchronously, showing a placeholder until the image is ready.
23
+ * Supports reactive `src` — automatically updates when the observable changes.
24
+ * @param {Observable<string>|string} src - Final image URL
25
+ * @param {string|null} defaultImage - Placeholder shown while loading
26
+ * @param {Omit<ImgAttributes, 'src'>} attributes
27
+ * @param {(error: NativeDocumentError|null, img: HTMLImageElement) => void} [callback]
28
+ * @returns {HTMLImageElement}
17
29
  */
18
30
  export const AsyncImg = function(src, defaultImage, attributes, callback) {
19
31
  const defaultSrc = Validator.isObservable(src) ? src.val() : src;
@@ -37,10 +49,10 @@ export const AsyncImg = function(src, defaultImage, attributes, callback) {
37
49
  };
38
50
 
39
51
  /**
40
- *
41
- * @param {string} src
42
- * @param {Object} attributes
43
- * @returns {Image}
52
+ * Creates an `<img loading="lazy">` element.
53
+ * @param {Observable<string>|string} src
54
+ * @param {Omit<ImgAttributes, 'src'|'loading'>} [attributes]
55
+ * @returns {HTMLImageElement}
44
56
  */
45
57
  export const LazyImg = function(src, attributes) {
46
58
  return Img(src, { ...attributes, loading: 'lazy' });
@@ -16,6 +16,11 @@ export * from './medias';
16
16
  export * from './meta-data';
17
17
  export * from './table';
18
18
 
19
+ /**
20
+ * Creates an empty `DocumentFragment` wrapper.
21
+ * Useful for grouping elements without adding a DOM node.
22
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): DocumentFragment}
23
+ */
19
24
  export const Fragment = HtmlElementWrapper('');
20
25
 
21
26
 
@@ -1,7 +1,25 @@
1
1
  import HtmlElementWrapper from "../wrappers/HtmlElementWrapper";
2
2
 
3
-
3
+ /**
4
+ * Creates a `<details>` element.
5
+ * @type {function(DetailsAttributes=, NdChild|NdChild[]=): HTMLDetailsElement}
6
+ */
4
7
  export const Details = HtmlElementWrapper('details');
8
+
9
+ /**
10
+ * Creates a `<summary>` element.
11
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
12
+ */
5
13
  export const Summary = HtmlElementWrapper('summary');
14
+
15
+ /**
16
+ * Creates a `<dialog>` element.
17
+ * @type {function(DialogAttributes=, NdChild|NdChild[]=): HTMLDialogElement}
18
+ */
6
19
  export const Dialog = HtmlElementWrapper('dialog');
20
+
21
+ /**
22
+ * Creates a `<menu>` element.
23
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLMenuElement}
24
+ */
7
25
  export const Menu = HtmlElementWrapper('menu');
@@ -1,10 +1,37 @@
1
1
  import HtmlElementWrapper from "../wrappers/HtmlElementWrapper";
2
2
 
3
+ /**
4
+ * Creates an `<ol>` element.
5
+ * @type {function(OlAttributes=, NdChild|NdChild[]=): HTMLOListElement}
6
+ */
3
7
  export const OrderedList = HtmlElementWrapper('ol');
8
+
9
+ /**
10
+ * Creates a `<ul>` element.
11
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLUListElement}
12
+ */
4
13
  export const UnorderedList = HtmlElementWrapper('ul');
14
+
15
+ /**
16
+ * Creates a `<li>` element.
17
+ * @type {function(GlobalAttributes & { value?: number }=, NdChild|NdChild[]=): HTMLLIElement}
18
+ */
5
19
  export const ListItem = HtmlElementWrapper('li');
6
20
 
21
+ /**
22
+ * Alias for {@link ListItem}.
23
+ * @type {typeof ListItem}
24
+ */
7
25
  export const Li = ListItem;
26
+
27
+ /**
28
+ * Alias for {@link OrderedList}.
29
+ * @type {typeof OrderedList}
30
+ */
8
31
  export const Ol = OrderedList;
9
- export const Ul = UnorderedList;
10
32
 
33
+ /**
34
+ * Alias for {@link UnorderedList}.
35
+ * @type {typeof UnorderedList}
36
+ */
37
+ export const Ul = UnorderedList;
@@ -1,8 +1,37 @@
1
1
  import HtmlElementWrapper from "../wrappers/HtmlElementWrapper";
2
2
 
3
+ /**
4
+ * Creates an `<audio>` element.
5
+ * @type {function(AudioAttributes=, NdChild|NdChild[]=): HTMLAudioElement}
6
+ */
3
7
  export const Audio = HtmlElementWrapper('audio');
8
+
9
+ /**
10
+ * Creates a `<video>` element.
11
+ * @type {function(VideoAttributes=, NdChild|NdChild[]=): HTMLVideoElement}
12
+ */
4
13
  export const Video = HtmlElementWrapper('video');
14
+
15
+ /**
16
+ * Creates a `<source>` element.
17
+ * @type {function(SourceAttributes=): HTMLSourceElement}
18
+ */
5
19
  export const Source = HtmlElementWrapper('source');
20
+
21
+ /**
22
+ * Creates a `<track>` element.
23
+ * @type {function(TrackAttributes=): HTMLTrackElement}
24
+ */
6
25
  export const Track = HtmlElementWrapper('track');
26
+
27
+ /**
28
+ * Creates a `<canvas>` element.
29
+ * @type {function(CanvasAttributes=, NdChild|NdChild[]=): HTMLCanvasElement}
30
+ */
7
31
  export const Canvas = HtmlElementWrapper('canvas');
32
+
33
+ /**
34
+ * Creates an `<svg>` element.
35
+ * @type {function(SvgAttributes=, NdChild|NdChild[]=): SVGSVGElement}
36
+ */
8
37
  export const Svg = HtmlElementWrapper('svg');
@@ -1,9 +1,43 @@
1
1
  import HtmlElementWrapper from "../wrappers/HtmlElementWrapper";
2
2
 
3
+ /**
4
+ * Creates a `<time>` element.
5
+ * @type {function(TimeAttributes=, NdChild|NdChild[]=): HTMLTimeElement}
6
+ */
3
7
  export const Time = HtmlElementWrapper('time');
8
+
9
+ /**
10
+ * Creates a `<data>` element.
11
+ * @type {function(GlobalAttributes & { value?: Observable<string>|string }=, NdChild|NdChild[]=): HTMLDataElement}
12
+ */
4
13
  export const Data = HtmlElementWrapper('data');
14
+
15
+ /**
16
+ * Creates an `<address>` element.
17
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
18
+ */
5
19
  export const Address = HtmlElementWrapper('address');
20
+
21
+ /**
22
+ * Creates a `<kbd>` element.
23
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
24
+ */
6
25
  export const Kbd = HtmlElementWrapper('kbd');
26
+
27
+ /**
28
+ * Creates a `<samp>` element.
29
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
30
+ */
7
31
  export const Samp = HtmlElementWrapper('samp');
32
+
33
+ /**
34
+ * Creates a `<var>` element.
35
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
36
+ */
8
37
  export const Var = HtmlElementWrapper('var');
38
+
39
+ /**
40
+ * Creates a `<wbr>` element.
41
+ * @type {function(GlobalAttributes=): HTMLElement}
42
+ */
9
43
  export const Wbr = HtmlElementWrapper('wbr');
@@ -1,14 +1,73 @@
1
1
  import HtmlElementWrapper from "../wrappers/HtmlElementWrapper";
2
2
 
3
+ /**
4
+ * Creates a `<caption>` element.
5
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableCaptionElement}
6
+ */
3
7
  export const Caption = HtmlElementWrapper('caption');
8
+
9
+ /**
10
+ * Creates a `<table>` element.
11
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableElement}
12
+ */
4
13
  export const Table = HtmlElementWrapper('table');
14
+
15
+ /**
16
+ * Creates a `<thead>` element.
17
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableSectionElement}
18
+ */
5
19
  export const THead = HtmlElementWrapper('thead');
20
+
21
+ /**
22
+ * Creates a `<tfoot>` element.
23
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableSectionElement}
24
+ */
6
25
  export const TFoot = HtmlElementWrapper('tfoot');
26
+
27
+ /**
28
+ * Creates a `<tbody>` element.
29
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableSectionElement}
30
+ */
7
31
  export const TBody = HtmlElementWrapper('tbody');
32
+
33
+ /**
34
+ * Creates a `<tr>` element.
35
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLTableRowElement}
36
+ */
8
37
  export const Tr = HtmlElementWrapper('tr');
38
+
39
+ /**
40
+ * Alias for {@link Tr}.
41
+ * @type {typeof Tr}
42
+ */
9
43
  export const TRow = Tr;
44
+
45
+ /**
46
+ * Creates a `<th>` element.
47
+ * @type {function(ThAttributes=, NdChild|NdChild[]=): HTMLTableCellElement}
48
+ */
10
49
  export const Th = HtmlElementWrapper('th');
50
+
51
+ /**
52
+ * Alias for {@link Th}.
53
+ * @type {typeof Th}
54
+ */
11
55
  export const THeadCell = Th;
56
+
57
+ /**
58
+ * Alias for {@link Th}.
59
+ * @type {typeof Th}
60
+ */
12
61
  export const TFootCell = Th;
62
+
63
+ /**
64
+ * Creates a `<td>` element.
65
+ * @type {function(TdAttributes=, NdChild|NdChild[]=): HTMLTableCellElement}
66
+ */
13
67
  export const Td = HtmlElementWrapper('td');
68
+
69
+ /**
70
+ * Alias for {@link Td}.
71
+ * @type {typeof Td}
72
+ */
14
73
  export const TBodyCell = Td;
@@ -0,0 +1,5 @@
1
+ import { once as _once, autoMemoize, autoOnce } from "./memoize.js";
2
+
3
+ export const once = fn => autoOnce(fn);
4
+ export const singleton = fn => _once(fn);
5
+ export const memoize = fn => autoMemoize(fn);
@@ -75,7 +75,12 @@ export const trim = function(str, char) {
75
75
  }
76
76
 
77
77
  export const deepClone = (value, onObservableFound) => {
78
- // Primitives
78
+ try {
79
+ if(window.structuredClone !== undefined) {
80
+ return window.structuredClone(value);
81
+ }
82
+ } catch (e){}
83
+
79
84
  if (value === null || typeof value !== 'object') {
80
85
  return value;
81
86
  }
@@ -99,7 +104,7 @@ export const deepClone = (value, onObservableFound) => {
99
104
  // Objects
100
105
  const cloned = {};
101
106
  for (const key in value) {
102
- if (value.hasOwnProperty(key)) {
107
+ if (Object.hasOwn(value, key)) {
103
108
  cloned[key] = deepClone(value[key]);
104
109
  }
105
110
  }
@@ -3,9 +3,10 @@
3
3
  export const once = (fn) => {
4
4
  let result = null;
5
5
  return (...args) => {
6
- if(result === null) {
7
- result = fn(...args);
6
+ if(result != null) {
7
+ return result;
8
8
  }
9
+ result = fn(...args);
9
10
  return result;
10
11
  };
11
12
  };
@@ -14,9 +15,10 @@ export const autoOnce = (fn) => {
14
15
  let target = null;
15
16
  return new Proxy({}, {
16
17
  get: (_, key) => {
17
- if(target === null) {
18
- target = fn();
18
+ if(target) {
19
+ return target[key];
19
20
  }
21
+ target = fn();
20
22
  return target[key];
21
23
  }
22
24
  });
@@ -26,10 +28,13 @@ export const memoize = (fn) => {
26
28
  const cache = new Map();
27
29
  return (...args) => {
28
30
  const [key, ...rest] = args;
29
- if(!cache.has(key)) {
30
- cache.set(key, fn(...rest));
31
+ const cached = cache.get(key);
32
+ if(cached) {
33
+ return cached;
31
34
  }
32
- return cache.get(key);
35
+ const result = fn(...rest);
36
+ cache.set(key, result);
37
+ return result;
33
38
  };
34
39
  };
35
40
 
@@ -37,17 +42,21 @@ export const autoMemoize = (fn) => {
37
42
  const cache = new Map();
38
43
  return new Proxy({}, {
39
44
  get: (_, key) => {
40
- if(!cache.has(key)) {
41
- if(fn.length > 0) {
42
- return (...args) => {
43
- const result = fn(...args);
44
- cache.set(key, result);
45
- return result;
46
- }
45
+ const cached = cache.get(key);
46
+ if(cached) {
47
+ return cached;
48
+ }
49
+
50
+ if(fn.length > 0) {
51
+ return (...args) => {
52
+ const result = fn(...args, key);
53
+ cache.set(key, result);
54
+ return result;
47
55
  }
48
- cache.set(key, fn());
49
56
  }
50
- return cache.get(key);
57
+ const result = fn(key);
58
+ cache.set(key, result);
59
+ return result;
51
60
  }
52
61
  });
53
62
  };
@@ -27,13 +27,14 @@ Function.prototype.cached = function(...args) {
27
27
  };
28
28
 
29
29
  Function.prototype.errorBoundary = function(callback) {
30
- return (...args) => {
30
+ const handler = (...args) => {
31
31
  try {
32
32
  return this.apply(this, args);
33
33
  } catch(e) {
34
- return callback(e);
34
+ return callback(e, {caller: handler, args: args });
35
35
  }
36
36
  };
37
+ return handler;
37
38
  };
38
39
 
39
40
  String.prototype.use = function(args) {
@@ -17,7 +17,7 @@ export function bindClassAttribute(element, data) {
17
17
  continue;
18
18
  }
19
19
  if(value.__$isObservableWhen) {
20
- element.classes.toggle(className, value.isMath());
20
+ element.classes.toggle(className, value.isActive());
21
21
  value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
22
22
  continue;
23
23
  }
@@ -28,10 +28,10 @@ function createHtmlElement($tagName, customWrapper, _attributes, _children = nul
28
28
  /**
29
29
  *
30
30
  * @param {string} name
31
- * @param {?Function} customWrapper
31
+ * @param {?Function=} customWrapper
32
32
  * @returns {Function}
33
33
  */
34
- export default function HtmlElementWrapper(name, customWrapper) {
34
+ export default function HtmlElementWrapper(name, customWrapper = null) {
35
35
  return createHtmlElement.bind(null, name, customWrapper);
36
36
  };
37
37
 
@@ -103,12 +103,35 @@ NDElement.prototype.closedShadow = function(style = null) {
103
103
  return this.shadow('closed', style);
104
104
  };
105
105
 
106
+ /**
107
+ * Attaches a template binding to the element by hydrating it with the specified method.
108
+ *
109
+ * @param {string} methodName - Name of the hydration method to call
110
+ * @param {BindingHydrator} bindingHydrator - Template binding with $hydrate method
111
+ * @returns {HTMLElement} The underlying HTML element
112
+ * @example
113
+ * const onClick = $binder.attach((event, data) => console.log(data));
114
+ * element.nd.attach('onClick', onClick);
115
+ */
106
116
  NDElement.prototype.attach = function(methodName, bindingHydrator) {
107
117
  bindingHydrator.$hydrate(this.$element, methodName);
108
118
  return this.$element;
109
119
  };
110
120
 
111
-
121
+ /**
122
+ * Extends the current NDElement instance with custom methods.
123
+ * Methods are bound to the instance and available for chaining.
124
+ *
125
+ * @param {Object} methods - Object containing method definitions
126
+ * @returns {this} The NDElement instance with added methods for chaining
127
+ * @example
128
+ * element.nd.with({
129
+ * highlight() {
130
+ * this.$element.style.background = 'yellow';
131
+ * return this;
132
+ * }
133
+ * }).highlight().onClick(() => console.log('Clicked'));
134
+ */
112
135
  NDElement.prototype.with = function(methods) {
113
136
  if (!methods || typeof methods !== 'object') {
114
137
  throw new NativeDocumentError('extend() requires an object of methods');
@@ -139,6 +162,23 @@ NDElement.prototype.with = function(methods) {
139
162
  return this;
140
163
  }
141
164
 
165
+ /**
166
+ * Extends the NDElement prototype with new methods available to all NDElement instances.
167
+ * Use this to add global methods to all NDElements.
168
+ *
169
+ * @param {Object} methods - Object containing method definitions to add to prototype
170
+ * @returns {typeof NDElement} The NDElement constructor
171
+ * @throws {NativeDocumentError} If methods is not an object or contains non-function values
172
+ * @example
173
+ * NDElement.extend({
174
+ * fadeIn() {
175
+ * this.$element.style.opacity = '1';
176
+ * return this;
177
+ * }
178
+ * });
179
+ * // Now all NDElements have .fadeIn() method
180
+ * Div().nd.fadeIn();
181
+ */
142
182
  NDElement.extend = function(methods) {
143
183
  if (!methods || typeof methods !== 'object') {
144
184
  throw new NativeDocumentError('NDElement.extend() requires an object of methods');
@@ -155,7 +195,7 @@ NDElement.extend = function(methods) {
155
195
  ]);
156
196
 
157
197
  for (const name in methods) {
158
- if (!methods.hasOwnProperty(name)) {
198
+ if (!Object.hasOwn(methods, name)) {
159
199
  continue;
160
200
  }
161
201
 
@@ -38,6 +38,10 @@ EVENTS_WITH_STOP.forEach(eventSourceName => {
38
38
  _stop(this.$element, eventName, callback);
39
39
  return this;
40
40
  };
41
+ NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
42
+ _preventStop(this.$element, eventName, callback);
43
+ return this;
44
+ };
41
45
  });
42
46
 
43
47
  EVENTS_WITH_PREVENT.forEach(eventSourceName => {
@@ -51,7 +51,7 @@ const $hydrateFn = function(hydrateFunction, targetType, element, property) {
51
51
  hydrationState[targetType][property] = hydrateFunction;
52
52
  }
53
53
 
54
- const bindAttachMethods = function(node, bindDingData, data) {
54
+ const bindAttachMethods = (node, bindDingData, data) => {
55
55
  if(!bindDingData.attach) {
56
56
  return null;
57
57
  }
@@ -65,7 +65,12 @@ const bindAttachMethods = function(node, bindDingData, data) {
65
65
 
66
66
  const applyBindingTreePath = (root, target, data, path) => {
67
67
  if(path.fn) {
68
- path.fn(data, target, root);
68
+ if(typeof path.fn === 'string') {
69
+ ElementCreator.bindTextNode(target, data[0][path.fn]);
70
+ }
71
+ else {
72
+ path.fn(data, target, root);
73
+ }
69
74
  }
70
75
  if(path.children) {
71
76
  for(let i = 0, length = path.children.length; i < length; i++) {
@@ -91,15 +96,16 @@ export function TemplateCloner($fn) {
91
96
  if(bindDingData && bindDingData.value) {
92
97
  currentPath.fn = bindDingData.value;
93
98
  const textNode = node.cloneNode();
99
+ if(typeof bindDingData.value === 'string') {
100
+ ElementCreator.bindTextNode(textNode, data[0][bindDingData.value]);
101
+ return textNode;
102
+ }
94
103
  bindDingData.value(data, textNode);
95
104
  return textNode;
96
105
  }
97
106
  return node.cloneNode(true);
98
107
  }
99
- const nodeCloned = node.cloneNode(node.fullCloneNode);
100
- if(node.fullCloneNode) {
101
- return nodeCloned;
102
- }
108
+ const nodeCloned = node.cloneNode();
103
109
  if(bindDingData) {
104
110
  bindAttributes(nodeCloned, bindDingData, data);
105
111
  bindAttachMethods(nodeCloned, bindDingData, data);
@@ -164,12 +170,9 @@ export function TemplateCloner($fn) {
164
170
  }
165
171
  this.value = (callbackOrProperty) => {
166
172
  if(typeof callbackOrProperty !== 'function') {
167
- return createBinding(function(data, textNode) {
168
- const firstArgument = data[0];
169
- ElementCreator.bindTextNode(textNode, firstArgument[callbackOrProperty]);
170
- }, 'value');
173
+ return createBinding(callbackOrProperty, 'value');
171
174
  }
172
- return createBinding(function(data, textNode) {
175
+ return createBinding((data, textNode) => {
173
176
  ElementCreator.bindTextNode(textNode, callbackOrProperty(...data));
174
177
  }, 'value');
175
178
  };
@@ -9,7 +9,7 @@ ObservableItem.prototype.bindNdClass = function(element, className) {
9
9
  };
10
10
 
11
11
  ObservableWhen.prototype.bindNdClass = function(element, className) {
12
- element.classes.toggle(className, this.isMath());
12
+ element.classes.toggle(className, this.isMatch());
13
13
  this.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
14
14
  };
15
15
 
@@ -4,6 +4,7 @@ import TemplateBinding from "../TemplateBinding";
4
4
  import {ElementCreator} from "../ElementCreator";
5
5
  import PluginsManager from "../../utils/plugins-manager";
6
6
  import Validator from "../../utils/validator";
7
+ import ObservableChecker from "../../data/ObservableChecker";
7
8
 
8
9
  String.prototype.toNdElement = function () {
9
10
  const formattedChild = this.resolveObservableTemplate ? this.resolveObservableTemplate() : this;
@@ -33,6 +34,8 @@ ObservableItem.prototype.toNdElement = function () {
33
34
  return ElementCreator.createObservableNode(null, this);
34
35
  };
35
36
 
37
+ ObservableChecker.prototype.toNdElement = ObservableItem.prototype.toNdElement;
38
+
36
39
  NDElement.prototype.toNdElement = function () {
37
40
  return this.$element ?? this.$build?.() ?? this.build?.() ?? null;
38
41
  };