native-document 1.0.151 → 1.0.152

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.
@@ -1,16 +1,16 @@
1
1
  var NativeComponents = (function (exports) {
2
2
  'use strict';
3
3
 
4
- let DebugManager$1 = {};
4
+ let DebugManager$2 = {};
5
5
  {
6
- DebugManager$1 = {
6
+ DebugManager$2 = {
7
7
  log() {},
8
8
  warn() {},
9
9
  error() {},
10
10
  disable() {}
11
11
  };
12
12
  }
13
- var DebugManager$2 = DebugManager$1;
13
+ var DebugManager$1 = DebugManager$2;
14
14
 
15
15
  class NativeDocumentError extends Error {
16
16
  constructor(message, context = {}) {
@@ -21,6 +21,213 @@ var NativeComponents = (function (exports) {
21
21
  }
22
22
  }
23
23
 
24
+ const COMMON_NODE_TYPES = {
25
+ ELEMENT: 1,
26
+ TEXT: 3,
27
+ COMMENT: 8,
28
+ DOCUMENT_FRAGMENT: 11
29
+ };
30
+
31
+ const VALID_TYPES = [];
32
+ VALID_TYPES[COMMON_NODE_TYPES.ELEMENT] = true;
33
+ VALID_TYPES[COMMON_NODE_TYPES.TEXT] = true;
34
+ VALID_TYPES[COMMON_NODE_TYPES.DOCUMENT_FRAGMENT] = true;
35
+ VALID_TYPES[COMMON_NODE_TYPES.COMMENT] = true;
36
+
37
+ const Validator = {
38
+ isObservable(value) {
39
+ return value && (value.__$isObservable || value.__$Observable);
40
+ },
41
+ isTemplateBinding(value) {
42
+ return value?.__$isTemplateBinding;
43
+ },
44
+ isObservableWhenResult(value) {
45
+ return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
46
+ },
47
+ isArrayObservable(value) {
48
+ return value?.__$isObservableArray;
49
+ },
50
+ isProxy(value) {
51
+ return value?.__isProxy__
52
+ },
53
+ isObservableOrProxy(value) {
54
+ return Validator.isObservable(value) || Validator.isProxy(value);
55
+ },
56
+ isAnchor(value) {
57
+ return value?.__Anchor__
58
+ },
59
+ isObservableChecker(value) {
60
+ return value?.__$isObservableChecker;
61
+ },
62
+ isArray(value) {
63
+ return Array.isArray(value);
64
+ },
65
+ isString(value) {
66
+ return typeof value === 'string';
67
+ },
68
+ isNumber(value) {
69
+ return typeof value === 'number';
70
+ },
71
+ isBoolean(value) {
72
+ return typeof value === 'boolean';
73
+ },
74
+ isFunction(value) {
75
+ return typeof value === 'function';
76
+ },
77
+ isAsyncFunction(value) {
78
+ return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
79
+ },
80
+ isObject(value) {
81
+ return typeof value === 'object' && value !== null;
82
+ },
83
+ isJson(value) {
84
+ return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
85
+ },
86
+ isElement(value) {
87
+ return value && VALID_TYPES[value.nodeType];
88
+ },
89
+ isDOMNode(value) {
90
+ return VALID_TYPES[value.nodeType];
91
+ },
92
+ isFragment(value) {
93
+ return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
94
+ },
95
+ isStringOrObservable(value) {
96
+ return this.isString(value) || this.isObservable(value);
97
+ },
98
+ isValidChild(child) {
99
+ return child === null ||
100
+ this.isElement(child) ||
101
+ child.__$Observable ||
102
+ child?.__$isNDElement ||
103
+ ['string', 'number', 'boolean'].includes(typeof child);
104
+ },
105
+ isNDElement(child) {
106
+ return child?.__$isNDElement;
107
+ },
108
+ isValidChildren(children) {
109
+ if (!Array.isArray(children)) {
110
+ children = [children];
111
+ }
112
+
113
+ const invalid = children.filter(child => !this.isValidChild(child));
114
+ return invalid.length === 0;
115
+ },
116
+ validateChildren(children) {
117
+ if (!Array.isArray(children)) {
118
+ children = [children];
119
+ }
120
+
121
+ const invalid = children.filter(child => !this.isValidChild(child));
122
+ if (invalid.length > 0) {
123
+ throw new NativeDocumentError(`Invalid children detected: ${invalid.map(i => typeof i).join(', ')}`);
124
+ }
125
+
126
+ return children;
127
+ },
128
+ /**
129
+ * Check if the data contains observables.
130
+ * @param {Array|Object} data
131
+ * @returns {boolean}
132
+ */
133
+ containsObservables(data) {
134
+ if(!data) {
135
+ return false;
136
+ }
137
+ return Validator.isObject(data)
138
+ && Object.values(data).some(value => Validator.isObservable(value));
139
+ },
140
+ /**
141
+ * Check if the data contains an observable reference.
142
+ * @param {string} data
143
+ * @returns {boolean}
144
+ */
145
+ containsObservableReference(data) {
146
+ if(!data || typeof data !== 'string') {
147
+ return false;
148
+ }
149
+ return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
150
+ },
151
+ validateAttributes(attributes) {},
152
+
153
+ validateEventCallback(callback) {
154
+ if (typeof callback !== 'function') {
155
+ throw new NativeDocumentError('Event callback must be a function');
156
+ }
157
+ }
158
+ };
159
+
160
+ const cssPropertyAccumulator = function(initialValue = {}) {
161
+ let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
162
+
163
+ return {
164
+ add(key, value) {
165
+ if(Array.isArray(data)) {
166
+ data.push(key+': '+value);
167
+ return;
168
+ }
169
+ if(Validator.isObject(key)) {
170
+ value = key;
171
+ for(const property in value) {
172
+ data[property] = value[property];
173
+ }
174
+ return;
175
+ }
176
+ data[key] = value;
177
+ },
178
+ value() {
179
+ if(Array.isArray(data)) {
180
+ return data.join(';').concat(';');
181
+ }
182
+ return { ...data };
183
+ },
184
+ };
185
+ };
186
+
187
+ const classPropertyAccumulator = function(initialValue = []) {
188
+ let data = Validator.isString(initialValue) ? initialValue.split(" ").filter(Boolean) : initialValue;
189
+
190
+ return {
191
+ add(key, value = true) {
192
+ if(Validator.isJson(key)) {
193
+ for(const property in key) {
194
+ if(key[property]) {
195
+ data[property] = key[property];
196
+ }
197
+ }
198
+ return;
199
+ }
200
+ if(value != null || key.__$Observable) {
201
+ if(Array.isArray(data)) {
202
+ data = data.reduce((acc, item) => {
203
+ acc[item] = true;
204
+ return acc;
205
+ }, {});
206
+ }
207
+ if(key.__$Observable) {
208
+ const uniqueId = `obs-${Math.random().toString(36).substr(2, 9)}`;
209
+ data[uniqueId] = key;
210
+ }
211
+ else {
212
+ data[key] = value;
213
+ }
214
+ return;
215
+ }
216
+ if(Array.isArray(data)) {
217
+ data.push(key);
218
+ return;
219
+ }
220
+ data[key] = value;
221
+ },
222
+ value() {
223
+ if(Array.isArray(data)) {
224
+ return data.join(' ');
225
+ }
226
+ return { ...data };
227
+ },
228
+ };
229
+ };
230
+
24
231
  const MemoryManager = (function() {
25
232
 
26
233
  let $nextObserverId = 0;
@@ -68,66 +275,12 @@ var NativeComponents = (function (exports) {
68
275
  }
69
276
  }
70
277
  if (cleanedCount > 0) {
71
- DebugManager$2.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
278
+ DebugManager$1.log('Memory Auto Clean', `🧹 Cleaned ${cleanedCount} orphaned observables`);
72
279
  }
73
280
  }
74
281
  };
75
282
  }());
76
283
 
77
- /**
78
- * Creates an ObservableWhen that tracks whether an observable equals a specific value.
79
- *
80
- * @param {ObservableItem} observer - The observable to watch
81
- * @param {*} value - The value to compare against
82
- * @class ObservableWhen
83
- */
84
- const ObservableWhen = function(observer, value) {
85
- this.$target = value;
86
- this.$observer = observer;
87
- };
88
-
89
- ObservableWhen.prototype.__$Observable = true;
90
- ObservableWhen.prototype.__$isObservableWhen = true;
91
-
92
- /**
93
- * Subscribes to changes in the match status (true when observable equals target value).
94
- *
95
- * @param {Function} callback - Function called with boolean indicating if values match
96
- * @returns {Function} Unsubscribe function
97
- * @example
98
- * const status = Observable('idle');
99
- * const isLoading = status.when('loading');
100
- * isLoading.subscribe(active => console.log('Loading:', active));
101
- */
102
- ObservableWhen.prototype.subscribe = function(callback) {
103
- return this.$observer.on(this.$target, callback);
104
- };
105
-
106
- /**
107
- * Returns true if the observable's current value equals the target value.
108
- *
109
- * @returns {boolean} True if observable value matches target value
110
- */
111
- ObservableWhen.prototype.val = function() {
112
- return this.$observer.$currentValue === this.$target;
113
- };
114
-
115
- /**
116
- * Returns true if the observable's current value equals the target value.
117
- * Alias for val().
118
- *
119
- * @returns {boolean} True if observable value matches target value
120
- */
121
- ObservableWhen.prototype.isMatch = ObservableWhen.prototype.val;
122
-
123
- /**
124
- * Returns true if the observable's current value equals the target value.
125
- * Alias for val().
126
- *
127
- * @returns {boolean} True if observable value matches target value
128
- */
129
- ObservableWhen.prototype.isActive = ObservableWhen.prototype.val;
130
-
131
284
  const invoke = function(fn, args, context) {
132
285
  if(context) {
133
286
  fn.apply(context, args);
@@ -196,187 +349,27 @@ var NativeComponents = (function (exports) {
196
349
  return cloned;
197
350
  };
198
351
 
199
- const $parseDateParts = (value, locale) => {
200
- const d = new Date(value);
201
- return {
202
- d,
203
- parts: new Intl.DateTimeFormat(locale, {
204
- year: 'numeric',
205
- month: 'long',
206
- day: '2-digit',
207
- hour: '2-digit',
208
- minute: '2-digit',
209
- second: '2-digit',
210
- }).formatToParts(d).reduce((acc, { type, value }) => {
211
- acc[type] = value;
212
- return acc;
213
- }, {})
214
- };
215
- };
216
-
217
- const $applyDatePattern = (pattern, d, parts) => {
218
- const pad = n => String(n).padStart(2, '0');
219
- return pattern
220
- .replace('YYYY', parts.year)
221
- .replace('YY', parts.year.slice(-2))
222
- .replace('MMMM', parts.month)
223
- .replace('MMM', parts.month.slice(0, 3))
224
- .replace('MM', pad(d.getMonth() + 1))
225
- .replace('DD', pad(d.getDate()))
226
- .replace('D', d.getDate())
227
- .replace('HH', parts.hour)
228
- .replace('mm', parts.minute)
229
- .replace('ss', parts.second);
230
- };
231
-
232
- const Formatters = {
233
- currency: (value, locale, { currency = 'XOF', notation, minimumFractionDigits, maximumFractionDigits } = {}) =>
234
- new Intl.NumberFormat(locale, {
235
- style: 'currency',
236
- currency,
237
- notation,
238
- minimumFractionDigits,
239
- maximumFractionDigits
240
- }).format(value),
241
-
242
- number: (value, locale, { notation, minimumFractionDigits, maximumFractionDigits } = {}) =>
243
- new Intl.NumberFormat(locale, {
244
- notation,
245
- minimumFractionDigits,
246
- maximumFractionDigits
247
- }).format(value),
248
-
249
- percent: (value, locale, { decimals = 1 } = {}) =>
250
- new Intl.NumberFormat(locale, {
251
- style: 'percent',
252
- maximumFractionDigits: decimals
253
- }).format(value),
254
-
255
- date: (value, locale, { format, dateStyle = 'long' } = {}) => {
256
- if (format) {
257
- const { d, parts } = $parseDateParts(value, locale);
258
- return $applyDatePattern(format, d, parts);
352
+ const LocalStorage = {
353
+ getJson(key) {
354
+ let value = localStorage.getItem(key);
355
+ try {
356
+ return JSON.parse(value);
357
+ } catch (e) {
358
+ throw new NativeDocumentError('invalid_json:'+key);
259
359
  }
260
- return new Intl.DateTimeFormat(locale, { dateStyle }).format(new Date(value));
261
360
  },
262
-
263
- time: (value, locale, { format, hour = '2-digit', minute = '2-digit', second } = {}) => {
264
- if (format) {
265
- const { d, parts } = $parseDateParts(value, locale);
266
- return $applyDatePattern(format, d, parts);
267
- }
268
- return new Intl.DateTimeFormat(locale, { hour, minute, second }).format(new Date(value));
361
+ getNumber(key) {
362
+ return Number(this.get(key));
269
363
  },
270
-
271
- datetime: (value, locale, { format, dateStyle = 'long', hour = '2-digit', minute = '2-digit', second } = {}) => {
272
- if (format) {
273
- const { d, parts } = $parseDateParts(value, locale);
274
- return $applyDatePattern(format, d, parts);
275
- }
276
- return new Intl.DateTimeFormat(locale, { dateStyle, hour, minute, second }).format(new Date(value));
364
+ getBool(key) {
365
+ const value = this.get(key);
366
+ return value === 'true' || value === '1';
277
367
  },
278
-
279
- relative: (value, locale, { unit = 'day', numeric = 'auto' } = {}) => {
280
- const diff = Math.round((value - Date.now()) / (1000 * 60 * 60 * 24));
281
- return new Intl.RelativeTimeFormat(locale, { numeric }).format(diff, unit);
368
+ setJson(key, value) {
369
+ localStorage.setItem(key, JSON.stringify(value));
282
370
  },
283
-
284
- plural: (value, locale, { singular, plural } = {}) => {
285
- const rule = new Intl.PluralRules(locale).select(value);
286
- return `${value} ${rule === 'one' ? singular : plural}`;
287
- },
288
- };
289
-
290
- /**
291
- *
292
- * @param {*} value
293
- * @param {{ propagation: boolean, reset: boolean} | null} configs
294
- * @returns {ObservableItem}
295
- * @constructor
296
- */
297
- function Observable(value, configs = null) {
298
- return new ObservableItem(value, configs);
299
- }
300
-
301
- const $$1 = Observable;
302
-
303
- /**
304
- *
305
- * @param {string} propertyName
306
- */
307
- Observable.useValueProperty = function(propertyName = 'value') {
308
- Object.defineProperty(ObservableItem.prototype, propertyName, {
309
- get() {
310
- return this.$currentValue;
311
- },
312
- set(value) {
313
- this.set(value);
314
- },
315
- configurable: true,
316
- });
317
- };
318
-
319
-
320
- /**
321
- *
322
- * @param id
323
- * @returns {ObservableItem|null}
324
- */
325
- Observable.getById = function(id) {
326
- const item = MemoryManager.getObservableById(parseInt(id));
327
- if(!item) {
328
- throw new NativeDocumentError('Observable.getById : No observable found with id ' + id);
329
- }
330
- return item;
331
- };
332
-
333
- /**
334
- *
335
- * @param {ObservableItem} observable
336
- */
337
- Observable.cleanup = function(observable) {
338
- observable.cleanup();
339
- };
340
-
341
- /**
342
- * Enable auto cleanup of observables.
343
- * @param {Boolean} enable
344
- * @param {{interval:Boolean, threshold:number}} options
345
- */
346
- Observable.autoCleanup = function(enable = false, options = {}) {
347
- if(!enable) {
348
- return;
349
- }
350
- const { interval = 60000, threshold = 100 } = options;
351
-
352
- window.addEventListener('beforeunload', () => {
353
- MemoryManager.cleanup();
354
- });
355
-
356
- setInterval(() => MemoryManager.cleanObservables(threshold), interval);
357
- };
358
-
359
- const LocalStorage = {
360
- getJson(key) {
361
- let value = localStorage.getItem(key);
362
- try {
363
- return JSON.parse(value);
364
- } catch (e) {
365
- throw new NativeDocumentError('invalid_json:'+key);
366
- }
367
- },
368
- getNumber(key) {
369
- return Number(this.get(key));
370
- },
371
- getBool(key) {
372
- const value = this.get(key);
373
- return value === 'true' || value === '1';
374
- },
375
- setJson(key, value) {
376
- localStorage.setItem(key, JSON.stringify(value));
377
- },
378
- setBool(key, value) {
379
- localStorage.setItem(key, value ? 'true' : 'false');
371
+ setBool(key, value) {
372
+ localStorage.setItem(key, value ? 'true' : 'false');
380
373
  },
381
374
  get(key, defaultValue = null) {
382
375
  return localStorage.getItem(key) || defaultValue;
@@ -735,27 +728,6 @@ var NativeComponents = (function (exports) {
735
728
  this.assocTrigger();
736
729
  };
737
730
 
738
- /**
739
- * Create an Observable checker instance
740
- * @param callback
741
- * @returns {ObservableChecker}
742
- */
743
- ObservableItem.prototype.check = function(callback) {
744
- return new ObservableChecker(this, callback)
745
- };
746
-
747
- ObservableItem.prototype.transform = ObservableItem.prototype.check;
748
- ObservableItem.prototype.pluck = function(property) {
749
- return new ObservableChecker(this, (value) => value[property]);
750
- };
751
- ObservableItem.prototype.is = function(callbackOrValue) {
752
- if(typeof callbackOrValue === 'function') {
753
- return new ObservableChecker(this, callbackOrValue);
754
- }
755
- return new ObservableChecker(this, (value) => value === callbackOrValue);
756
- };
757
- ObservableItem.prototype.select = ObservableItem.prototype.check;
758
-
759
731
 
760
732
 
761
733
 
@@ -775,21 +747,6 @@ var NativeComponents = (function (exports) {
775
747
  return Validator.isObservable(item) ? item.val() : item;
776
748
  };
777
749
 
778
- /**
779
- * Creates an ObservableWhen that represents whether the observable equals a specific value.
780
- * Returns an object that can be subscribed to and will emit true/false.
781
- *
782
- * @param {*} value - The value to compare against
783
- * @returns {ObservableWhen} An ObservableWhen instance that tracks when the observable equals the value
784
- * @example
785
- * const status = Observable('idle');
786
- * const isLoading = status.when('loading');
787
- * isLoading.subscribe(active => console.log('Loading:', active));
788
- * status.set('loading'); // Logs: "Loading: true"
789
- */
790
- ObservableItem.prototype.when = function(value) {
791
- return new ObservableWhen(this, value);
792
- };
793
750
 
794
751
  /**
795
752
  * Compares the observable's current value with another value or observable.
@@ -877,71 +834,6 @@ var NativeComponents = (function (exports) {
877
834
  };
878
835
 
879
836
 
880
- /**
881
- * Creates a derived observable that formats the current value using Intl.
882
- * Automatically reacts to both value changes and locale changes (Store.__nd.locale).
883
- *
884
- * @param {string | Function} type - Format type or custom formatter function
885
- * @param {Object} [options={}] - Options passed to the formatter
886
- * @returns {ObservableItem<string>}
887
- *
888
- * @example
889
- * // Currency
890
- * price.format('currency') // "15 000 FCFA"
891
- * price.format('currency', { currency: 'EUR' }) // "15 000,00 €"
892
- * price.format('currency', { notation: 'compact' }) // "15 K FCFA"
893
- *
894
- * // Number
895
- * count.format('number') // "15 000"
896
- *
897
- * // Percent
898
- * rate.format('percent') // "15,0 %"
899
- * rate.format('percent', { decimals: 2 }) // "15,00 %"
900
- *
901
- * // Date
902
- * date.format('date') // "3 mars 2026"
903
- * date.format('date', { dateStyle: 'full' }) // "mardi 3 mars 2026"
904
- * date.format('date', { format: 'DD/MM/YYYY' }) // "03/03/2026"
905
- * date.format('date', { format: 'DD MMM YYYY' }) // "03 mar 2026"
906
- * date.format('date', { format: 'DD MMMM YYYY' }) // "03 mars 2026"
907
- *
908
- * // Time
909
- * date.format('time') // "20:30"
910
- * date.format('time', { second: '2-digit' }) // "20:30:00"
911
- * date.format('time', { format: 'HH:mm:ss' }) // "20:30:00"
912
- *
913
- * // Datetime
914
- * date.format('datetime') // "3 mars 2026, 20:30"
915
- * date.format('datetime', { dateStyle: 'full' }) // "mardi 3 mars 2026, 20:30"
916
- * date.format('datetime', { format: 'DD/MM/YYYY HH:mm' }) // "03/03/2026 20:30"
917
- *
918
- * // Relative
919
- * date.format('relative') // "dans 11 jours"
920
- * date.format('relative', { unit: 'month' }) // "dans 1 mois"
921
- *
922
- * // Plural
923
- * count.format('plural', { singular: 'billet', plural: 'billets' }) // "3 billets"
924
- *
925
- * // Custom formatter
926
- * price.format(value => `${value.toLocaleString()} FCFA`)
927
- *
928
- * // Reacts to locale changes automatically
929
- * Store.setLocale('en-US');
930
- */
931
- ObservableItem.prototype.format = function(type, options = {}) {
932
- const self = this;
933
-
934
- if (typeof type === 'function') {
935
- return new ObservableChecker(self, type);
936
- }
937
-
938
- const formatter = Formatters[type];
939
- const localeObservable = Formatters.locale;
940
-
941
- return Observable.computed(() => formatter(self.val(), localeObservable.val(), options),
942
- [self, localeObservable]
943
- );
944
- };
945
837
 
946
838
  ObservableItem.prototype.persist = function(key, options = {}) {
947
839
  let value = $getFromStorage(key, this.$currentValue);
@@ -972,218 +864,72 @@ var NativeComponents = (function (exports) {
972
864
 
973
865
  /**
974
866
  *
975
- * @param {ObservableItem} $observable
976
- * @param {Function} $checker
977
- * @class ObservableChecker
867
+ * @param {*} value
868
+ * @param {{ propagation: boolean, reset: boolean} | null} configs
869
+ * @returns {ObservableItem}
870
+ * @constructor
978
871
  */
979
- function ObservableChecker($observable, $checker) {
980
- this.observable = $observable;
981
-
982
- ObservableItem.call(this);
872
+ function Observable(value, configs = null) {
873
+ return new ObservableItem(value, configs);
874
+ }
983
875
 
984
- this.$mutation = $checker;
876
+ const $$1 = Observable;
985
877
 
986
- $observable.subscribe((newValue) => {
987
- this.$updateWithMutation(newValue);
878
+ /**
879
+ *
880
+ * @param {string} propertyName
881
+ */
882
+ Observable.useValueProperty = function(propertyName = 'value') {
883
+ Object.defineProperty(ObservableItem.prototype, propertyName, {
884
+ get() {
885
+ return this.$currentValue;
886
+ },
887
+ set(value) {
888
+ this.set(value);
889
+ },
890
+ configurable: true,
988
891
  });
989
-
990
- this.$updateWithMutation($observable.val());
991
- }
992
-
993
- ObservableChecker.prototype = Object.create(ObservableItem.prototype);
994
- ObservableChecker.prototype.constructor = ObservableChecker;
995
- ObservableChecker.prototype.__$Observable = true;
996
- ObservableChecker.prototype.__$isObservableChecker = true;
892
+ };
997
893
 
998
894
 
999
- const ObservablePipe = ObservableChecker;
1000
- ObservablePipe.prototype.constructor = ObservablePipe;
895
+ /**
896
+ *
897
+ * @param id
898
+ * @returns {ObservableItem|null}
899
+ */
900
+ Observable.getById = function(id) {
901
+ const item = MemoryManager.getObservableById(parseInt(id));
902
+ if(!item) {
903
+ throw new NativeDocumentError('Observable.getById : No observable found with id ' + id);
904
+ }
905
+ return item;
906
+ };
1001
907
 
1002
- ObservableChecker.prototype.$updateWithMutation = function(newValue) {
1003
- newValue = this.$mutation(newValue);
1004
- return this.set(newValue);
908
+ /**
909
+ *
910
+ * @param {ObservableItem} observable
911
+ */
912
+ Observable.cleanup = function(observable) {
913
+ observable.cleanup();
1005
914
  };
1006
915
 
1007
- const DocumentObserver = {
1008
- mounted: new WeakMap(),
1009
- beforeUnmount: new WeakMap(),
1010
- mountedSupposedSize: 0,
1011
- unmounted: new WeakMap(),
1012
- unmountedSupposedSize: 0,
1013
- observer: null,
1014
- initObserver: () => {
1015
- if(DocumentObserver.observer) {
1016
- return;
1017
- }
1018
- DocumentObserver.observer = new MutationObserver(DocumentObserver.checkMutation);
1019
- DocumentObserver.observer.observe(document.body, {
1020
- childList: true,
1021
- subtree: true,
1022
- });
1023
- },
916
+ /**
917
+ * Enable auto cleanup of observables.
918
+ * @param {Boolean} enable
919
+ * @param {{interval:Boolean, threshold:number}} options
920
+ */
921
+ Observable.autoCleanup = function(enable = false, options = {}) {
922
+ if(!enable) {
923
+ return;
924
+ }
925
+ const { interval = 60000, threshold = 100 } = options;
1024
926
 
1025
- executeMountedCallback(node) {
1026
- const data = DocumentObserver.mounted.get(node);
1027
- if(!data) {
1028
- return;
1029
- }
1030
- data.inDom = true;
1031
- if(!data.mounted) {
1032
- return;
1033
- }
1034
- if(Array.isArray(data.mounted)) {
1035
- for(const cb of data.mounted) {
1036
- cb(node);
1037
- }
1038
- return;
1039
- }
1040
- data.mounted(node);
1041
- },
927
+ window.addEventListener('beforeunload', () => {
928
+ MemoryManager.cleanup();
929
+ });
1042
930
 
1043
- executeUnmountedCallback(node) {
1044
- const data = DocumentObserver.unmounted.get(node);
1045
- if(!data) {
1046
- return;
1047
- }
1048
- data.inDom = false;
1049
- if(!data.unmounted) {
1050
- return;
1051
- }
1052
-
1053
- let shouldRemove = false;
1054
- if(Array.isArray(data.unmounted)) {
1055
- for(const cb of data.unmounted) {
1056
- if(cb(node) === true) {
1057
- shouldRemove = true;
1058
- }
1059
- }
1060
- } else {
1061
- shouldRemove = data.unmounted(node) === true;
1062
- }
1063
-
1064
- if(shouldRemove) {
1065
- data.disconnect();
1066
- node.nd?.remove();
1067
- }
1068
- },
1069
-
1070
- checkMutation: function(mutationsList) {
1071
- for(const mutation of mutationsList) {
1072
- if(DocumentObserver.mountedSupposedSize > 0) {
1073
- for(const node of mutation.addedNodes) {
1074
- DocumentObserver.executeMountedCallback(node);
1075
- if(!node.querySelectorAll) {
1076
- continue;
1077
- }
1078
- const children = node.querySelectorAll('[data--nd-mounted]');
1079
- for(const child of children) {
1080
- DocumentObserver.executeMountedCallback(child);
1081
- }
1082
- }
1083
- }
1084
-
1085
- if (DocumentObserver.unmountedSupposedSize > 0) {
1086
- for (const node of mutation.removedNodes) {
1087
- DocumentObserver.executeUnmountedCallback(node);
1088
- if(!node.querySelectorAll) {
1089
- continue;
1090
- }
1091
- const children = node.querySelectorAll('[data--nd-unmounted]');
1092
- for(const child of children) {
1093
- DocumentObserver.executeUnmountedCallback(child);
1094
- }
1095
- }
1096
- }
1097
- }
1098
- },
1099
-
1100
- /**
1101
- * @param {HTMLElement} element
1102
- * @param {boolean} inDom
1103
- * @returns {{ disconnect: Function, mounted: Function, unmounted: Function, off: Function }}
1104
- */
1105
- watch: function(element, inDom = false) {
1106
- let mountedRegistered = false;
1107
- let unmountedRegistered = false;
1108
-
1109
- DocumentObserver.initObserver();
1110
-
1111
- let data = {
1112
- inDom,
1113
- mounted: null,
1114
- unmounted: null,
1115
- disconnect: () => {
1116
- if (mountedRegistered) {
1117
- DocumentObserver.mounted.delete(element);
1118
- DocumentObserver.mountedSupposedSize--;
1119
- }
1120
- if (unmountedRegistered) {
1121
- DocumentObserver.unmounted.delete(element);
1122
- DocumentObserver.unmountedSupposedSize--;
1123
- }
1124
- data = null;
1125
- }
1126
- };
1127
-
1128
- const addListener = (type, callback) => {
1129
- if (!data[type]) {
1130
- data[type] = callback;
1131
- return;
1132
- }
1133
- if (!Array.isArray(data[type])) {
1134
- data[type] = [data[type], callback];
1135
- return;
1136
- }
1137
- data[type].push(callback);
1138
- };
1139
-
1140
- const removeListener = (type, callback) => {
1141
- if(!data?.[type]) {
1142
- return;
1143
- }
1144
- if(Array.isArray(data[type])) {
1145
- const index = data[type].indexOf(callback);
1146
- if(index > -1) {
1147
- data[type].splice(index, 1);
1148
- }
1149
- if(data[type].length === 1) {
1150
- data[type] = data[type][0];
1151
- }
1152
- if(data[type].length === 0) {
1153
- data[type] = null;
1154
- }
1155
- return;
1156
- }
1157
- data[type] = null;
1158
- };
1159
-
1160
- return {
1161
- disconnect: () => data?.disconnect(),
1162
-
1163
- mounted: (callback) => {
1164
- addListener('mounted', callback);
1165
- DocumentObserver.mounted.set(element, data);
1166
- if (!mountedRegistered) {
1167
- DocumentObserver.mountedSupposedSize++;
1168
- mountedRegistered = true;
1169
- }
1170
- },
1171
-
1172
- unmounted: (callback) => {
1173
- addListener('unmounted', callback);
1174
- DocumentObserver.unmounted.set(element, data);
1175
- if (!unmountedRegistered) {
1176
- DocumentObserver.unmountedSupposedSize++;
1177
- unmountedRegistered = true;
1178
- }
1179
- },
1180
-
1181
- off: (type, callback) => {
1182
- removeListener(type, callback);
1183
- }
1184
- };
1185
- }
1186
- };
931
+ setInterval(() => MemoryManager.cleanObservables(threshold), interval);
932
+ };
1187
933
 
1188
934
  const BOOLEAN_ATTRIBUTES = new Set([
1189
935
  'checked',
@@ -1379,253 +1125,97 @@ var NativeComponents = (function (exports) {
1379
1125
  return element;
1380
1126
  };
1381
1127
 
1382
- String.prototype.toNdElement = function () {
1383
- return ElementCreator.createStaticTextNode(null, this);
1384
- };
1385
-
1386
- Number.prototype.toNdElement = function () {
1387
- return ElementCreator.createStaticTextNode(null, this.toString());
1388
- };
1389
-
1390
- Element.prototype.toNdElement = function () {
1391
- return this;
1392
- };
1393
- Text.prototype.toNdElement = function () {
1394
- return this;
1395
- };
1396
- Comment.prototype.toNdElement = function () {
1397
- return this;
1398
- };
1399
- Document.prototype.toNdElement = function () {
1400
- return this;
1401
- };
1402
- DocumentFragment.prototype.toNdElement = function () {
1403
- return this;
1404
- };
1128
+ let $textNodeCache = null;
1405
1129
 
1406
- ObservableItem.prototype.toNdElement = function () {
1407
- return ElementCreator.createObservableNode(null, this);
1408
- };
1130
+ const ElementCreator = {
1131
+ createTextNode() {
1132
+ if(!$textNodeCache) {
1133
+ $textNodeCache = document.createTextNode('');
1134
+ ElementCreator.createTextNode = () => $textNodeCache.cloneNode();
1135
+ }
1136
+ return $textNodeCache.cloneNode();
1137
+ },
1138
+ /**
1139
+ *
1140
+ * @param {HTMLElement|DocumentFragment} parent
1141
+ * @param {ObservableItem} observable
1142
+ * @returns {Text}
1143
+ */
1144
+ createObservableNode: (parent, observable) => {
1145
+ const text = ElementCreator.createTextNode();
1146
+ observable.subscribe(value => text.nodeValue = value);
1147
+ text.nodeValue = observable.val();
1148
+ parent && parent.appendChild(text);
1149
+ return text;
1150
+ },
1151
+ /**
1152
+ *
1153
+ * @param {HTMLElement|DocumentFragment} parent
1154
+ * @param {{$hydrate: Function}} item
1155
+ * @returns {Text}
1156
+ */
1157
+ createHydratableNode: (parent, item) => {
1158
+ const text = ElementCreator.createTextNode();
1159
+ item.$hydrate(text);
1160
+ return text;
1161
+ },
1409
1162
 
1410
- ObservableChecker.prototype.toNdElement = ObservableItem.prototype.toNdElement;
1163
+ /**
1164
+ *
1165
+ * @param {HTMLElement|DocumentFragment} parent
1166
+ * @param {*} value
1167
+ * @returns {Text}
1168
+ */
1169
+ createStaticTextNode: (parent, value) => {
1170
+ let text = ElementCreator.createTextNode();
1171
+ text.nodeValue = value;
1172
+ parent && parent.appendChild(text);
1173
+ return text;
1174
+ },
1175
+ /**
1176
+ *
1177
+ * @param {string} name
1178
+ * @returns {HTMLElement|DocumentFragment}
1179
+ */
1180
+ createElement: (name) => {
1181
+ const node = document.createElement(name);
1182
+ return node.cloneNode();
1183
+ },
1184
+ bindTextNode: (textNode, value) => {
1185
+ if(value?.__$isObservable) {
1186
+ value.subscribe(newValue => textNode.nodeValue = newValue);
1187
+ textNode.nodeValue = value.val();
1188
+ return;
1189
+ }
1190
+ textNode.nodeValue = value;
1191
+ },
1192
+ /**
1193
+ *
1194
+ * @param {*} children
1195
+ * @param {HTMLElement|DocumentFragment} parent
1196
+ */
1197
+ processChildren: (children, parent) => {
1198
+ if(children === null) return;
1199
+ let child = ElementCreator.getChild(children);
1200
+ if(child) {
1201
+ parent.appendChild(child);
1202
+ }
1203
+ },
1204
+ async safeRemove(element) {
1205
+ await element.remove();
1411
1206
 
1412
- NDElement.prototype.toNdElement = function () {
1413
- const element = this.$element ?? this.$build?.() ?? this.build?.() ?? null;
1414
- if(this.$attachements) {
1415
- if(!this.$attachements.contains(this.$element)) {
1416
- this.$attachements.append(this.$element);
1417
- }
1418
- return this.$attachements;
1419
- }
1420
- return element;
1421
- };
1422
-
1423
- Array.prototype.toNdElement = function () {
1424
- const fragment = document.createDocumentFragment();
1425
- for(let i = 0, length = this.length; i < length; i++) {
1426
- const child = ElementCreator.getChild(this[i]);
1427
- if(child === null) continue;
1428
- fragment.appendChild(child);
1429
- }
1430
- return fragment;
1431
- };
1432
-
1433
- Function.prototype.toNdElement = function () {
1434
- const child = this;
1435
- return ElementCreator.getChild(child());
1436
- };
1437
-
1438
- /**
1439
- * @param {HTMLElement} el
1440
- * @param {number} timeout
1441
- */
1442
- const waitForVisualEnd = (el, timeout = 1000) => {
1443
- return new Promise((resolve) => {
1444
- let isResolved = false;
1445
-
1446
- const cleanupAndResolve = (e) => {
1447
- if (e && e.target !== el) return;
1448
- if (isResolved) return;
1449
-
1450
- isResolved = true;
1451
- el.removeEventListener('transitionend', cleanupAndResolve);
1452
- el.removeEventListener('animationend', cleanupAndResolve);
1453
- clearTimeout(timer);
1454
- resolve();
1455
- };
1456
-
1457
- el.addEventListener('transitionend', cleanupAndResolve);
1458
- el.addEventListener('animationend', cleanupAndResolve);
1459
-
1460
- const timer = setTimeout(cleanupAndResolve, timeout);
1461
-
1462
- const style = window.getComputedStyle(el);
1463
- const hasTransition = style.transitionDuration !== '0s';
1464
- const hasAnimation = style.animationDuration !== '0s';
1465
-
1466
- if (!hasTransition && !hasAnimation) {
1467
- cleanupAndResolve();
1468
- }
1469
- });
1470
- };
1471
-
1472
- NDElement.prototype.transitionOut = function(transitionName) {
1473
- const exitClass = transitionName + '-exit';
1474
- const el = this.$element;
1475
- this.beforeUnmount('transition-exit', async function() {
1476
- el.classes.add(exitClass);
1477
- await waitForVisualEnd(el);
1478
- el.classes.remove(exitClass);
1479
- });
1480
- return this;
1481
- };
1482
-
1483
- NDElement.prototype.transitionIn = function(transitionName) {
1484
- const startClass = transitionName + '-enter-from';
1485
- const endClass = transitionName + '-enter-to';
1486
-
1487
- const el = this.$element;
1488
-
1489
- el.classes.add(startClass);
1490
-
1491
- this.mounted(() => {
1492
- requestAnimationFrame(() => {
1493
- requestAnimationFrame(() => {
1494
- el.classes.remove(startClass);
1495
- el.classes.add(endClass);
1496
-
1497
- waitForVisualEnd(el).then(() => {
1498
- el.classes.remove(endClass);
1499
- });
1500
- });
1501
- });
1502
- });
1503
- return this;
1504
- };
1505
-
1506
-
1507
- NDElement.prototype.transition = function (transitionName) {
1508
- this.transitionIn(transitionName);
1509
- this.transitionOut(transitionName);
1510
- return this;
1511
- };
1512
-
1513
- NDElement.prototype.animate = function(animationName) {
1514
- const el = this.$element;
1515
- el.classes.add(animationName);
1516
-
1517
- waitForVisualEnd(el).then(() => {
1518
- el.classes.remove(animationName);
1519
- });
1520
-
1521
- return this;
1522
- };
1523
-
1524
- ObservableItem.prototype.handleNdAttribute = function(element, attributeName) {
1525
- if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
1526
- bindBooleanAttribute(element, attributeName, this);
1527
- return;
1528
- }
1529
-
1530
- bindAttributeWithObservable(element, attributeName, this);
1531
- };
1532
-
1533
- ObservableChecker.prototype.handleNdAttribute = ObservableItem.prototype.handleNdAttribute;
1534
-
1535
- let $textNodeCache = null;
1536
-
1537
- const ElementCreator = {
1538
- createTextNode() {
1539
- if(!$textNodeCache) {
1540
- $textNodeCache = document.createTextNode('');
1541
- ElementCreator.createTextNode = () => $textNodeCache.cloneNode();
1542
- }
1543
- return $textNodeCache.cloneNode();
1544
- },
1545
- /**
1546
- *
1547
- * @param {HTMLElement|DocumentFragment} parent
1548
- * @param {ObservableItem} observable
1549
- * @returns {Text}
1550
- */
1551
- createObservableNode: (parent, observable) => {
1552
- const text = ElementCreator.createTextNode();
1553
- observable.subscribe(value => text.nodeValue = value);
1554
- text.nodeValue = observable.val();
1555
- parent && parent.appendChild(text);
1556
- return text;
1557
- },
1558
- /**
1559
- *
1560
- * @param {HTMLElement|DocumentFragment} parent
1561
- * @param {{$hydrate: Function}} item
1562
- * @returns {Text}
1563
- */
1564
- createHydratableNode: (parent, item) => {
1565
- const text = ElementCreator.createTextNode();
1566
- item.$hydrate(text);
1567
- return text;
1568
- },
1569
-
1570
- /**
1571
- *
1572
- * @param {HTMLElement|DocumentFragment} parent
1573
- * @param {*} value
1574
- * @returns {Text}
1575
- */
1576
- createStaticTextNode: (parent, value) => {
1577
- let text = ElementCreator.createTextNode();
1578
- text.nodeValue = value;
1579
- parent && parent.appendChild(text);
1580
- return text;
1581
- },
1582
- /**
1583
- *
1584
- * @param {string} name
1585
- * @returns {HTMLElement|DocumentFragment}
1586
- */
1587
- createElement: (name) => {
1588
- const node = document.createElement(name);
1589
- return node.cloneNode();
1590
- },
1591
- createFragment: (name) => {
1592
- return Anchor('Fragment');
1593
- },
1594
- bindTextNode: (textNode, value) => {
1595
- if(value?.__$isObservable) {
1596
- value.subscribe(newValue => textNode.nodeValue = newValue);
1597
- textNode.nodeValue = value.val();
1598
- return;
1599
- }
1600
- textNode.nodeValue = value;
1601
- },
1602
- /**
1603
- *
1604
- * @param {*} children
1605
- * @param {HTMLElement|DocumentFragment} parent
1606
- */
1607
- processChildren: (children, parent) => {
1608
- if(children === null) return;
1609
- let child = ElementCreator.getChild(children);
1610
- if(child) {
1611
- parent.appendChild(child);
1612
- }
1613
- },
1614
- async safeRemove(element) {
1615
- await element.remove();
1616
-
1617
- },
1618
- getChild: (child) => {
1619
- if(child == null) {
1620
- return null;
1621
- }
1622
- if(child.toNdElement) {
1623
- do {
1624
- child = child.toNdElement();
1625
- if(Validator.isElement(child)) {
1626
- return child;
1627
- }
1628
- } while (child.toNdElement);
1207
+ },
1208
+ getChild: (child) => {
1209
+ if(child == null) {
1210
+ return null;
1211
+ }
1212
+ if(child.toNdElement) {
1213
+ do {
1214
+ child = child.toNdElement();
1215
+ if(Validator.isElement(child)) {
1216
+ return child;
1217
+ }
1218
+ } while (child.toNdElement);
1629
1219
  }
1630
1220
 
1631
1221
  return ElementCreator.createStaticTextNode(null, child);
@@ -1938,36 +1528,272 @@ var NativeComponents = (function (exports) {
1938
1528
  }
1939
1529
  DocumentFragment.prototype.setAttribute = () => {};
1940
1530
 
1941
- function NDElement(element) {
1942
- this.$element = element;
1943
- this.$attachements = null;
1944
- }
1945
-
1946
- NDElement.prototype.__$isNDElement = true;
1531
+ /**
1532
+ * Conditionally shows an element based on an observable condition.
1533
+ * The element is mounted/unmounted from the DOM as the condition changes.
1534
+ *
1535
+ * @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
1536
+ * @param {NdChild|(() => NdChild)} child - Element or content to show/hide
1537
+ * @param {Object} [options={}] - Configuration options
1538
+ * @param {string|null} [options.comment=null] - Comment for debugging
1539
+ * @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
1540
+ * @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
1541
+ * @example
1542
+ * const isVisible = Observable(false);
1543
+ * ShowIf(isVisible, Div({}, 'Hello World'));
1544
+ */
1545
+ const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
1546
+ if(!Validator.isObservable(condition)) {
1547
+ if(typeof condition === "boolean") {
1548
+ return condition ? ElementCreator.getChild(child) : null;
1549
+ }
1947
1550
 
1948
- NDElement.prototype.ghostDom = function(element) {
1949
- if(!this.$attachements) {
1950
- this.$attachements = document.createDocumentFragment();
1551
+ return DebugManager$1.warn('ShowIf', "ShowIf : condition must be an Observable or boolean / "+comment, condition);
1951
1552
  }
1952
- this.$attachements.appendChild(ElementCreator.getChild(element));
1953
- return this;
1954
- };
1553
+ const element = Anchor('Show if : '+(comment || ''));
1955
1554
 
1956
- NDElement.prototype.valueOf = function() {
1957
- return this.$element;
1958
- };
1555
+ let childElement = null;
1556
+ const getChildElement = () => {
1557
+ if(childElement && shouldKeepInCache) {
1558
+ return childElement;
1559
+ }
1560
+ childElement = ElementCreator.getChild(child);
1561
+ if(Validator.isFragment(childElement)) {
1562
+ childElement = Array.from(childElement.childNodes);
1563
+ }
1564
+ return childElement;
1565
+ };
1959
1566
 
1960
- NDElement.prototype.ref = function(target, name) {
1961
- target[name] = this.$element;
1962
- return this;
1963
- };
1567
+ const currentValue = condition.val();
1964
1568
 
1965
- NDElement.prototype.refSelf = function(target, name) {
1966
- target[name] = this;
1967
- // TODO: @DIM to check
1968
- // target[name] = new NDElement(this.$element);
1969
- return this;
1970
- };
1569
+ if(currentValue) {
1570
+ element.appendChild(getChildElement());
1571
+ }
1572
+
1573
+ condition.subscribe((value) => {
1574
+ if(!!value) {
1575
+ element.appendChild(getChildElement());
1576
+ return;
1577
+ }
1578
+ element.remove();
1579
+ });
1580
+
1581
+ return element;
1582
+ };
1583
+
1584
+ const DocumentObserver = {
1585
+ mounted: new WeakMap(),
1586
+ beforeUnmount: new WeakMap(),
1587
+ mountedSupposedSize: 0,
1588
+ unmounted: new WeakMap(),
1589
+ unmountedSupposedSize: 0,
1590
+ observer: null,
1591
+ initObserver: () => {
1592
+ if(DocumentObserver.observer) {
1593
+ return;
1594
+ }
1595
+ DocumentObserver.observer = new MutationObserver(DocumentObserver.checkMutation);
1596
+ DocumentObserver.observer.observe(document.body, {
1597
+ childList: true,
1598
+ subtree: true,
1599
+ });
1600
+ },
1601
+
1602
+ executeMountedCallback(node) {
1603
+ const data = DocumentObserver.mounted.get(node);
1604
+ if(!data) {
1605
+ return;
1606
+ }
1607
+ data.inDom = true;
1608
+ if(!data.mounted) {
1609
+ return;
1610
+ }
1611
+ if(Array.isArray(data.mounted)) {
1612
+ for(const cb of data.mounted) {
1613
+ cb(node);
1614
+ }
1615
+ return;
1616
+ }
1617
+ data.mounted(node);
1618
+ },
1619
+
1620
+ executeUnmountedCallback(node) {
1621
+ const data = DocumentObserver.unmounted.get(node);
1622
+ if(!data) {
1623
+ return;
1624
+ }
1625
+ data.inDom = false;
1626
+ if(!data.unmounted) {
1627
+ return;
1628
+ }
1629
+
1630
+ let shouldRemove = false;
1631
+ if(Array.isArray(data.unmounted)) {
1632
+ for(const cb of data.unmounted) {
1633
+ if(cb(node) === true) {
1634
+ shouldRemove = true;
1635
+ }
1636
+ }
1637
+ } else {
1638
+ shouldRemove = data.unmounted(node) === true;
1639
+ }
1640
+
1641
+ if(shouldRemove) {
1642
+ data.disconnect();
1643
+ node.nd?.remove();
1644
+ }
1645
+ },
1646
+
1647
+ checkMutation: function(mutationsList) {
1648
+ for(const mutation of mutationsList) {
1649
+ if(DocumentObserver.mountedSupposedSize > 0) {
1650
+ for(const node of mutation.addedNodes) {
1651
+ DocumentObserver.executeMountedCallback(node);
1652
+ if(!node.querySelectorAll) {
1653
+ continue;
1654
+ }
1655
+ const children = node.querySelectorAll('[data--nd-mounted]');
1656
+ for(const child of children) {
1657
+ DocumentObserver.executeMountedCallback(child);
1658
+ }
1659
+ }
1660
+ }
1661
+
1662
+ if (DocumentObserver.unmountedSupposedSize > 0) {
1663
+ for (const node of mutation.removedNodes) {
1664
+ DocumentObserver.executeUnmountedCallback(node);
1665
+ if(!node.querySelectorAll) {
1666
+ continue;
1667
+ }
1668
+ const children = node.querySelectorAll('[data--nd-unmounted]');
1669
+ for(const child of children) {
1670
+ DocumentObserver.executeUnmountedCallback(child);
1671
+ }
1672
+ }
1673
+ }
1674
+ }
1675
+ },
1676
+
1677
+ /**
1678
+ * @param {HTMLElement} element
1679
+ * @param {boolean} inDom
1680
+ * @returns {{ disconnect: Function, mounted: Function, unmounted: Function, off: Function }}
1681
+ */
1682
+ watch: function(element, inDom = false) {
1683
+ let mountedRegistered = false;
1684
+ let unmountedRegistered = false;
1685
+
1686
+ DocumentObserver.initObserver();
1687
+
1688
+ let data = {
1689
+ inDom,
1690
+ mounted: null,
1691
+ unmounted: null,
1692
+ disconnect: () => {
1693
+ if (mountedRegistered) {
1694
+ DocumentObserver.mounted.delete(element);
1695
+ DocumentObserver.mountedSupposedSize--;
1696
+ }
1697
+ if (unmountedRegistered) {
1698
+ DocumentObserver.unmounted.delete(element);
1699
+ DocumentObserver.unmountedSupposedSize--;
1700
+ }
1701
+ data = null;
1702
+ }
1703
+ };
1704
+
1705
+ const addListener = (type, callback) => {
1706
+ if (!data[type]) {
1707
+ data[type] = callback;
1708
+ return;
1709
+ }
1710
+ if (!Array.isArray(data[type])) {
1711
+ data[type] = [data[type], callback];
1712
+ return;
1713
+ }
1714
+ data[type].push(callback);
1715
+ };
1716
+
1717
+ const removeListener = (type, callback) => {
1718
+ if(!data?.[type]) {
1719
+ return;
1720
+ }
1721
+ if(Array.isArray(data[type])) {
1722
+ const index = data[type].indexOf(callback);
1723
+ if(index > -1) {
1724
+ data[type].splice(index, 1);
1725
+ }
1726
+ if(data[type].length === 1) {
1727
+ data[type] = data[type][0];
1728
+ }
1729
+ if(data[type].length === 0) {
1730
+ data[type] = null;
1731
+ }
1732
+ return;
1733
+ }
1734
+ data[type] = null;
1735
+ };
1736
+
1737
+ return {
1738
+ disconnect: () => data?.disconnect(),
1739
+
1740
+ mounted: (callback) => {
1741
+ addListener('mounted', callback);
1742
+ DocumentObserver.mounted.set(element, data);
1743
+ if (!mountedRegistered) {
1744
+ DocumentObserver.mountedSupposedSize++;
1745
+ mountedRegistered = true;
1746
+ }
1747
+ },
1748
+
1749
+ unmounted: (callback) => {
1750
+ addListener('unmounted', callback);
1751
+ DocumentObserver.unmounted.set(element, data);
1752
+ if (!unmountedRegistered) {
1753
+ DocumentObserver.unmountedSupposedSize++;
1754
+ unmountedRegistered = true;
1755
+ }
1756
+ },
1757
+
1758
+ off: (type, callback) => {
1759
+ removeListener(type, callback);
1760
+ }
1761
+ };
1762
+ }
1763
+ };
1764
+
1765
+ function NDElement(element) {
1766
+ this.$element = element;
1767
+ this.$attachements = null;
1768
+ }
1769
+
1770
+ NDElement.prototype.__$isNDElement = true;
1771
+
1772
+ NDElement.$getChild = (el) => el;
1773
+
1774
+ NDElement.prototype.ghostDom = function(element) {
1775
+ if(!this.$attachements) {
1776
+ this.$attachements = document.createDocumentFragment();
1777
+ }
1778
+ this.$attachements.appendChild(NDElement.$getChild(element));
1779
+ return this;
1780
+ };
1781
+
1782
+ NDElement.prototype.valueOf = function() {
1783
+ return this.$element;
1784
+ };
1785
+
1786
+ NDElement.prototype.ref = function(target, name) {
1787
+ target[name] = this.$element;
1788
+ return this;
1789
+ };
1790
+
1791
+ NDElement.prototype.refSelf = function(target, name) {
1792
+ target[name] = this;
1793
+ // TODO: @DIM to check
1794
+ // target[name] = new NDElement(this.$element);
1795
+ return this;
1796
+ };
1971
1797
 
1972
1798
  NDElement.prototype.unmountChildren = function() {
1973
1799
  let element = this.$element;
@@ -2104,7 +1930,7 @@ var NativeComponents = (function (exports) {
2104
1930
  const method = methods[name];
2105
1931
 
2106
1932
  if (typeof method !== 'function') {
2107
- DebugManager$2.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
1933
+ DebugManager$1.warn(`⚠️ extends(): "${name}" is not a function, skipping`);
2108
1934
  continue;
2109
1935
  }
2110
1936
 
@@ -2154,17 +1980,17 @@ var NativeComponents = (function (exports) {
2154
1980
  const method = methods[name];
2155
1981
 
2156
1982
  if (typeof method !== 'function') {
2157
- DebugManager$2.warn('NDElement.extend', `"${name}" is not a function, skipping`);
1983
+ DebugManager$1.warn('NDElement.extend', `"${name}" is not a function, skipping`);
2158
1984
  continue;
2159
1985
  }
2160
1986
 
2161
1987
  if (protectedMethods.has(name)) {
2162
- DebugManager$2.error('NDElement.extend', `Cannot override protected method "${name}"`);
1988
+ DebugManager$1.error('NDElement.extend', `Cannot override protected method "${name}"`);
2163
1989
  throw new NativeDocumentError(`Cannot override protected method "${name}"`);
2164
1990
  }
2165
1991
 
2166
1992
  if (NDElement.prototype[name]) {
2167
- DebugManager$2.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
1993
+ DebugManager$1.warn('NDElement.extend', `Overwriting existing prototype method "${name}"`);
2168
1994
  }
2169
1995
 
2170
1996
  NDElement.prototype[name] = method;
@@ -2173,628 +1999,15 @@ var NativeComponents = (function (exports) {
2173
1999
  return NDElement;
2174
2000
  };
2175
2001
 
2176
- const COMMON_NODE_TYPES = {
2177
- ELEMENT: 1,
2178
- TEXT: 3,
2179
- COMMENT: 8,
2180
- DOCUMENT_FRAGMENT: 11
2181
- };
2182
-
2183
- const VALID_TYPES = [];
2184
- VALID_TYPES[COMMON_NODE_TYPES.ELEMENT] = true;
2185
- VALID_TYPES[COMMON_NODE_TYPES.TEXT] = true;
2186
- VALID_TYPES[COMMON_NODE_TYPES.DOCUMENT_FRAGMENT] = true;
2187
- VALID_TYPES[COMMON_NODE_TYPES.COMMENT] = true;
2188
-
2189
- const Validator = {
2190
- isObservable(value) {
2191
- return value && (value.__$isObservable || value.__$Observable);
2192
- },
2193
- isTemplateBinding(value) {
2194
- return value?.__$isTemplateBinding;
2195
- },
2196
- isObservableWhenResult(value) {
2197
- return value && (value.__$isObservableWhen || (typeof value === 'object' && '$target' in value && '$observer' in value));
2198
- },
2199
- isArrayObservable(value) {
2200
- return value?.__$isObservableArray;
2201
- },
2202
- isProxy(value) {
2203
- return value?.__isProxy__
2204
- },
2205
- isObservableOrProxy(value) {
2206
- return Validator.isObservable(value) || Validator.isProxy(value);
2207
- },
2208
- isAnchor(value) {
2209
- return value?.__Anchor__
2210
- },
2211
- isObservableChecker(value) {
2212
- return value?.__$isObservableChecker || value instanceof ObservableChecker;
2213
- },
2214
- isArray(value) {
2215
- return Array.isArray(value);
2216
- },
2217
- isString(value) {
2218
- return typeof value === 'string';
2219
- },
2220
- isNumber(value) {
2221
- return typeof value === 'number';
2222
- },
2223
- isBoolean(value) {
2224
- return typeof value === 'boolean';
2225
- },
2226
- isFunction(value) {
2227
- return typeof value === 'function';
2228
- },
2229
- isAsyncFunction(value) {
2230
- return typeof value === 'function' && value.constructor.name === 'AsyncFunction';
2231
- },
2232
- isObject(value) {
2233
- return typeof value === 'object' && value !== null;
2234
- },
2235
- isJson(value) {
2236
- return !(typeof value !== 'object' || value === null || Array.isArray(value) || value.constructor.name !== 'Object')
2237
- },
2238
- isElement(value) {
2239
- return value && VALID_TYPES[value.nodeType];
2240
- },
2241
- isDOMNode(value) {
2242
- return VALID_TYPES[value.nodeType];
2243
- },
2244
- isFragment(value) {
2245
- return value?.nodeType === COMMON_NODE_TYPES.DOCUMENT_FRAGMENT;
2246
- },
2247
- isStringOrObservable(value) {
2248
- return this.isString(value) || this.isObservable(value);
2249
- },
2250
- isValidChild(child) {
2251
- return child === null ||
2252
- this.isElement(child) ||
2253
- this.isObservable(child) ||
2254
- this.isNDElement(child) ||
2255
- ['string', 'number', 'boolean'].includes(typeof child);
2256
- },
2257
- isNDElement(child) {
2258
- return child?.__$isNDElement || child instanceof NDElement;
2259
- },
2260
- isValidChildren(children) {
2261
- if (!Array.isArray(children)) {
2262
- children = [children];
2263
- }
2264
-
2265
- const invalid = children.filter(child => !this.isValidChild(child));
2266
- return invalid.length === 0;
2267
- },
2268
- validateChildren(children) {
2269
- if (!Array.isArray(children)) {
2270
- children = [children];
2271
- }
2272
-
2273
- const invalid = children.filter(child => !this.isValidChild(child));
2274
- if (invalid.length > 0) {
2275
- throw new NativeDocumentError(`Invalid children detected: ${invalid.map(i => typeof i).join(', ')}`);
2276
- }
2277
-
2278
- return children;
2279
- },
2280
- /**
2281
- * Check if the data contains observables.
2282
- * @param {Array|Object} data
2283
- * @returns {boolean}
2284
- */
2285
- containsObservables(data) {
2286
- if(!data) {
2287
- return false;
2288
- }
2289
- return Validator.isObject(data)
2290
- && Object.values(data).some(value => Validator.isObservable(value));
2291
- },
2292
- /**
2293
- * Check if the data contains an observable reference.
2294
- * @param {string} data
2295
- * @returns {boolean}
2296
- */
2297
- containsObservableReference(data) {
2298
- if(!data || typeof data !== 'string') {
2299
- return false;
2300
- }
2301
- return /\{\{#ObItem::\([0-9]+\)\}\}/.test(data);
2302
- },
2303
- validateAttributes(attributes) {},
2304
-
2305
- validateEventCallback(callback) {
2306
- if (typeof callback !== 'function') {
2307
- throw new NativeDocumentError('Event callback must be a function');
2308
- }
2309
- }
2310
- };
2311
-
2312
- const cssPropertyAccumulator = function(initialValue = {}) {
2313
- let data = Validator.isString(initialValue) ? initialValue.split(';').filter(Boolean) : initialValue;
2314
-
2315
- return {
2316
- add(key, value) {
2317
- if(Array.isArray(data)) {
2318
- data.push(key+': '+value);
2319
- return;
2320
- }
2321
- if(Validator.isObject(key)) {
2322
- value = key;
2323
- for(const property in value) {
2324
- data[property] = value[property];
2325
- }
2326
- return;
2327
- }
2328
- data[key] = value;
2329
- },
2330
- value() {
2331
- if(Array.isArray(data)) {
2332
- return data.join(';').concat(';');
2333
- }
2334
- return { ...data };
2335
- },
2336
- };
2337
- };
2338
-
2339
- const classPropertyAccumulator = function(initialValue = []) {
2340
- let data = Validator.isString(initialValue) ? initialValue.split(" ").filter(Boolean) : initialValue;
2341
-
2342
- return {
2343
- add(key, value = true) {
2344
- if(Validator.isJson(key)) {
2345
- for(const property in key) {
2346
- if(key[property]) {
2347
- data[property] = key[property];
2348
- }
2349
- }
2350
- return;
2351
- }
2352
- if(value != null || key.__$Observable) {
2353
- if(Array.isArray(data)) {
2354
- data = data.reduce((acc, item) => {
2355
- acc[item] = true;
2356
- return acc;
2357
- }, {});
2358
- }
2359
- if(key.__$Observable) {
2360
- const uniqueId = `obs-${Math.random().toString(36).substr(2, 9)}`;
2361
- data[uniqueId] = key;
2362
- }
2363
- else {
2364
- data[key] = value;
2365
- }
2366
- return;
2367
- }
2368
- if(Array.isArray(data)) {
2369
- data.push(key);
2370
- return;
2371
- }
2372
- data[key] = value;
2373
- },
2374
- value() {
2375
- if(Array.isArray(data)) {
2376
- return data.join(' ');
2377
- }
2378
- return { ...data };
2379
- },
2380
- };
2381
- };
2382
-
2383
- /**
2384
- * Conditionally shows an element based on an observable condition.
2385
- * The element is mounted/unmounted from the DOM as the condition changes.
2386
- *
2387
- * @param {ObservableItem<boolean>|ObservableChecker<boolean>|ObservableWhen} condition - Observable condition to watch
2388
- * @param {NdChild|(() => NdChild)} child - Element or content to show/hide
2389
- * @param {Object} [options={}] - Configuration options
2390
- * @param {string|null} [options.comment=null] - Comment for debugging
2391
- * @param {boolean} [options.shouldKeepInCache=true] - Whether to cache the element when hidden
2392
- * @returns {AnchorDocumentFragment} Anchor fragment managing the conditional content
2393
- * @example
2394
- * const isVisible = Observable(false);
2395
- * ShowIf(isVisible, Div({}, 'Hello World'));
2396
- */
2397
- const ShowIf = function(condition, child, { comment = null, shouldKeepInCache = true} = {}) {
2398
- if(!Validator.isObservable(condition)) {
2399
- if(typeof condition === "boolean") {
2400
- return condition ? ElementCreator.getChild(child) : null;
2401
- }
2402
-
2403
- return DebugManager$2.warn('ShowIf', "ShowIf : condition must be an Observable or boolean / "+comment, condition);
2404
- }
2405
- const element = Anchor('Show if : '+(comment || ''));
2406
-
2407
- let childElement = null;
2408
- const getChildElement = () => {
2409
- if(childElement && shouldKeepInCache) {
2410
- return childElement;
2411
- }
2412
- childElement = ElementCreator.getChild(child);
2413
- if(Validator.isFragment(childElement)) {
2414
- childElement = Array.from(childElement.childNodes);
2415
- }
2416
- return childElement;
2417
- };
2418
-
2419
- const currentValue = condition.val();
2420
-
2421
- if(currentValue) {
2422
- element.appendChild(getChildElement());
2423
- }
2424
-
2425
- condition.subscribe((value) => {
2426
- if(!!value) {
2427
- element.appendChild(getChildElement());
2428
- return;
2429
- }
2430
- element.remove();
2431
- });
2432
-
2433
- return element;
2434
- };
2435
-
2436
- const EVENTS = [
2437
- "Click",
2438
- "DblClick",
2439
- "MouseDown",
2440
- "MouseEnter",
2441
- "MouseLeave",
2442
- "MouseMove",
2443
- "MouseOut",
2444
- "MouseOver",
2445
- "MouseUp",
2446
- "Wheel",
2447
- "KeyDown",
2448
- "KeyPress",
2449
- "KeyUp",
2450
- "Blur",
2451
- "Change",
2452
- "Focus",
2453
- "Input",
2454
- "Invalid",
2455
- "Reset",
2456
- "Search",
2457
- "Select",
2458
- "Submit",
2459
- "Drag",
2460
- "DragEnd",
2461
- "DragEnter",
2462
- "DragLeave",
2463
- "DragOver",
2464
- "DragStart",
2465
- "Drop",
2466
- "AfterPrint",
2467
- "BeforePrint",
2468
- "BeforeUnload",
2469
- "Error",
2470
- "HashChange",
2471
- "Load",
2472
- "Offline",
2473
- "Online",
2474
- "PageHide",
2475
- "PageShow",
2476
- "Resize",
2477
- "Scroll",
2478
- "Unload",
2479
- "Abort",
2480
- "CanPlay",
2481
- "CanPlayThrough",
2482
- "DurationChange",
2483
- "Emptied",
2484
- "Ended",
2485
- "LoadedData",
2486
- "LoadedMetadata",
2487
- "LoadStart",
2488
- "Pause",
2489
- "Play",
2490
- "Playing",
2491
- "Progress",
2492
- "RateChange",
2493
- "Seeked",
2494
- "Seeking",
2495
- "Stalled",
2496
- "Suspend",
2497
- "TimeUpdate",
2498
- "VolumeChange",
2499
- "Waiting",
2500
-
2501
- "TouchCancel",
2502
- "TouchEnd",
2503
- "TouchMove",
2504
- "TouchStart",
2505
- "AnimationEnd",
2506
- "AnimationIteration",
2507
- "AnimationStart",
2508
- "TransitionEnd",
2509
- "Copy",
2510
- "Cut",
2511
- "Paste",
2512
- "FocusIn",
2513
- "FocusOut",
2514
- "ContextMenu"
2515
- ];
2516
-
2517
- const EVENTS_WITH_PREVENT = [
2518
- "Click",
2519
- "DblClick",
2520
- "MouseDown",
2521
- "MouseUp",
2522
- "Wheel",
2523
- "KeyDown",
2524
- "KeyPress",
2525
- "Invalid",
2526
- "Reset",
2527
- "Submit",
2528
- "DragOver",
2529
- "Drop",
2530
- "BeforeUnload",
2531
- "TouchCancel",
2532
- "TouchEnd",
2533
- "TouchMove",
2534
- "TouchStart",
2535
- "Copy",
2536
- "Cut",
2537
- "Paste",
2538
- "ContextMenu"
2539
- ];
2540
-
2541
- const EVENTS_WITH_STOP = [
2542
- "Click",
2543
- "DblClick",
2544
- "MouseDown",
2545
- "MouseMove",
2546
- "MouseOut",
2547
- "MouseOver",
2548
- "MouseUp",
2549
- "Wheel",
2550
- "KeyDown",
2551
- "KeyPress",
2552
- "KeyUp",
2553
- "Change",
2554
- "Input",
2555
- "Invalid",
2556
- "Reset",
2557
- "Search",
2558
- "Select",
2559
- "Submit",
2560
- "Drag",
2561
- "DragEnd",
2562
- "DragEnter",
2563
- "DragLeave",
2564
- "DragOver",
2565
- "DragStart",
2566
- "Drop",
2567
- "BeforeUnload",
2568
- "HashChange",
2569
- "TouchCancel",
2570
- "TouchEnd",
2571
- "TouchMove",
2572
- "TouchStart",
2573
- "AnimationEnd",
2574
- "AnimationIteration",
2575
- "AnimationStart",
2576
- "TransitionEnd",
2577
- "Copy",
2578
- "Cut",
2579
- "Paste",
2580
- "FocusIn",
2581
- "FocusOut",
2582
- "ContextMenu"
2583
- ];
2584
-
2585
- const property = {
2586
- configurable: true,
2587
- get() {
2588
- return new NDElement(this);
2589
- }
2590
- };
2591
-
2592
- Object.defineProperty(HTMLElement.prototype, 'nd', property);
2593
-
2594
- Object.defineProperty(DocumentFragment.prototype, 'nd', property);
2595
-
2596
- Object.defineProperty(NDElement.prototype, 'nd', {
2597
- configurable: true,
2598
- get: function() {
2599
- return this;
2600
- }
2601
- });
2602
-
2603
-
2604
-
2605
- // ----------------------------------------------------------------
2606
- // Events helpers
2607
- // ----------------------------------------------------------------
2608
- EVENTS.forEach(eventSourceName => {
2609
- const eventName = eventSourceName.toLowerCase();
2610
- NDElement.prototype['on'+eventSourceName] = function(callback = null) {
2611
- this.$element.addEventListener(eventName, callback);
2612
- return this;
2613
- };
2614
- });
2615
-
2616
- EVENTS_WITH_STOP.forEach(eventSourceName => {
2617
- const eventName = eventSourceName.toLowerCase();
2618
- NDElement.prototype['onStop'+eventSourceName] = function(callback = null) {
2619
- _stop(this.$element, eventName, callback);
2620
- return this;
2621
- };
2622
- NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
2623
- _preventStop(this.$element, eventName, callback);
2624
- return this;
2625
- };
2626
- });
2627
-
2628
- EVENTS_WITH_PREVENT.forEach(eventSourceName => {
2629
- const eventName = eventSourceName.toLowerCase();
2630
- NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null) {
2631
- _prevent(this.$element, eventName, callback);
2632
- return this;
2633
- };
2634
- });
2635
-
2636
- NDElement.prototype.on = function(name, callback, options) {
2637
- this.$element.addEventListener(name.toLowerCase(), callback, options);
2638
- return this;
2639
- };
2640
-
2641
- const _prevent = function(element, eventName, callback) {
2642
- const handler = (event) => {
2643
- event.preventDefault();
2644
- callback && callback.call(element, event);
2645
- };
2646
- element.addEventListener(eventName, handler);
2647
- return this;
2648
- };
2649
-
2650
- const _stop = function(element, eventName, callback) {
2651
- const handler = (event) => {
2652
- event.stopPropagation();
2653
- callback && callback.call(element, event);
2654
- };
2655
- element.addEventListener(eventName, handler);
2656
- return this;
2657
- };
2658
-
2659
- const _preventStop = function(element, eventName, callback) {
2660
- const handler = (event) => {
2661
- event.stopPropagation();
2662
- event.preventDefault();
2663
- callback && callback.call(element, event);
2664
- };
2665
- element.addEventListener(eventName, handler);
2666
- return this;
2667
- };
2668
-
2669
-
2670
-
2671
- // ----------------------------------------------------------------
2672
- // Class attributes binder
2673
- // ----------------------------------------------------------------
2674
- const classListMethods = {
2675
- getClasses() {
2676
- return this.$element.className?.split(' ').filter(Boolean);
2677
- },
2678
- add(value) {
2679
- const classes = this.getClasses();
2680
- if(classes.indexOf(value) >= 0) {
2681
- return;
2682
- }
2683
- classes.push(value);
2684
- this.$element.className = classes.join(' ');
2685
- },
2686
- remove(value) {
2687
- const classes = this.getClasses();
2688
- const index = classes.indexOf(value);
2689
- if(index < 0) {
2690
- return;
2691
- }
2692
- classes.splice(index, 1);
2693
- this.$element.className = classes.join(' ');
2694
- },
2695
- toggle(value, force = undefined) {
2696
- const classes = this.getClasses();
2697
- const index = classes.indexOf(value);
2698
- if(index >= 0) {
2699
- if(force === true) {
2700
- return;
2701
- }
2702
- classes.splice(index, 1);
2703
- }
2704
- else {
2705
- if(force === false) {
2706
- return;
2707
- }
2708
- classes.push(value);
2709
- }
2710
- this.$element.className = classes.join(' ');
2711
- },
2712
- contains(value) {
2713
- return this.getClasses().indexOf(value) >= 0;
2714
- }
2715
- };
2716
-
2717
- Object.defineProperty(HTMLElement.prototype, 'classes', {
2718
- configurable: true,
2719
- get() {
2720
- return {
2721
- $element: this,
2722
- ...classListMethods
2723
- };
2724
- }
2725
- });
2726
-
2727
- const normalizeComponentArgs = function(props, children = null) {
2728
- if(props && children) {
2729
- return { props, children };
2730
- }
2731
- if(typeof props !== 'object' || Array.isArray(props) || props === null || props.constructor.name !== 'Object' || props.$hydrate) { // IF it's not a JSON
2732
- return { props: children, children: props }
2733
- }
2734
- return { props, children };
2735
- };
2736
-
2737
- const createHtmlElement = (element, _attributes, _children = null) => {
2738
- let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
2739
-
2740
- ElementCreator.processAttributes(element, attributes);
2741
- ElementCreator.processChildren(children, element);
2742
- return element;
2743
- };
2744
-
2745
- /**
2746
- *
2747
- * @param {string} name
2748
- * @param {?Function=} customWrapper
2749
- * @returns {Function}
2750
- */
2751
- function HtmlElementWrapper(name, customWrapper = null) {
2752
- if(name) {
2753
- if(customWrapper) {
2754
- let node = null;
2755
- let createElement = (attr, children) => {
2756
- node = document.createElement(name);
2757
- createElement = (attr, children) => {
2758
- return createHtmlElement(customWrapper(node.cloneNode()), attr, children);
2759
- };
2760
- return createHtmlElement(customWrapper(node.cloneNode()), attr, children); };
2761
-
2762
- return (attr, children) => createElement(attr, children)
2763
- }
2764
-
2765
- let node = null;
2766
- let createElement = (attr, children) => {
2767
- node = document.createElement(name);
2768
- createElement = (attr, children) => {
2769
- return createHtmlElement(node.cloneNode(), attr, children);
2770
- };
2771
- return createHtmlElement(node.cloneNode(), attr, children);
2772
- };
2773
-
2774
- return (attr, children) => createElement(attr, children)
2775
- }
2776
- return (children, name = '') => {
2777
- const anchor = Anchor(name);
2778
- anchor.append(children);
2779
- return anchor;
2780
- };
2781
- }
2782
-
2783
- /**
2784
- * Creates a `<div>` element.
2785
- * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDivElement}
2786
- */
2787
- const Div = HtmlElementWrapper('div');
2788
-
2789
- /**
2790
- *
2791
- * @class
2792
- */
2793
- function BaseComponent() {
2794
- this.$description = {};
2795
- this.$editableProps = null;
2796
- this.$attachements = null;
2797
- }
2002
+ /**
2003
+ *
2004
+ * @class
2005
+ */
2006
+ function BaseComponent() {
2007
+ this.$description = {};
2008
+ this.$editableProps = null;
2009
+ this.$attachements = null;
2010
+ }
2798
2011
 
2799
2012
  Object.defineProperty( BaseComponent.prototype, 'nd', {
2800
2013
  get: function() {
@@ -3499,7 +2712,7 @@ var NativeComponents = (function (exports) {
3499
2712
 
3500
2713
  Alert.preset = function(name, callback) {
3501
2714
  if (Alert.prototype[name] || Alert[name]) {
3502
- DebugManager$2.warn(`Warning: the ${name} method already exist in Alert.`);
2715
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Alert.`);
3503
2716
  return;
3504
2717
  }
3505
2718
  Alert[name] = (content, props) => callback(new Alert(content, props));
@@ -3813,7 +3026,7 @@ var NativeComponents = (function (exports) {
3813
3026
 
3814
3027
  Avatar.preset = function(name, callback) {
3815
3028
  if (Avatar.prototype[name] || Avatar[name]) {
3816
- DebugManager$2.warn(`Warning: the ${name} method already exists in Avatar.`);
3029
+ DebugManager$1.warn(`Warning: the ${name} method already exists in Avatar.`);
3817
3030
  return;
3818
3031
  }
3819
3032
  Avatar[name] = (label, props) => callback(new Avatar(label, props));
@@ -4235,7 +3448,7 @@ var NativeComponents = (function (exports) {
4235
3448
 
4236
3449
  Badge.preset = function(name, callback) {
4237
3450
  if (Badge.prototype[name] || Badge[name]) {
4238
- DebugManager$2.warn(`Warning: the ${name} method already exists in Badge.`);
3451
+ DebugManager$1.warn(`Warning: the ${name} method already exists in Badge.`);
4239
3452
  return;
4240
3453
  }
4241
3454
  Badge[name] = (content, props) => callback(new Badge(content, props));
@@ -4353,7 +3566,7 @@ var NativeComponents = (function (exports) {
4353
3566
 
4354
3567
  Breadcrumb.preset = function(name, callback) {
4355
3568
  if (Breadcrumb.prototype[name] || Breadcrumb[name]) {
4356
- DebugManager$2.warn(`Warning: the ${name} method already exist in Breadcrumb.`);
3569
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Breadcrumb.`);
4357
3570
  return;
4358
3571
  }
4359
3572
  Breadcrumb[name] = (props) => callback(new Breadcrumb(props));
@@ -4443,7 +3656,7 @@ var NativeComponents = (function (exports) {
4443
3656
 
4444
3657
  Button.preset = function(name, callback) {
4445
3658
  if (Button.prototype[name] || Button[name]) {
4446
- DebugManager$2.warn(`Warning: the ${name} method already exist in Button.`);
3659
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Button.`);
4447
3660
  return;
4448
3661
  }
4449
3662
  Button[name] = (label, props) => callback(new Button(label, props));
@@ -5325,7 +4538,7 @@ var NativeComponents = (function (exports) {
5325
4538
 
5326
4539
  Divider.preset = function(name, callback) {
5327
4540
  if (Divider.prototype[name] || Divider[name]) {
5328
- DebugManager$2.warn(`Warning: the ${name} method already exists in Divider.`);
4541
+ DebugManager$1.warn(`Warning: the ${name} method already exists in Divider.`);
5329
4542
  return;
5330
4543
  }
5331
4544
  Divider[name] = (label, props) => callback(new Divider(label, props));
@@ -5744,7 +4957,7 @@ var NativeComponents = (function (exports) {
5744
4957
 
5745
4958
  Dropdown.preset = function(name, callback) {
5746
4959
  if (Dropdown.prototype[name] || Dropdown[name]) {
5747
- DebugManager$2.warn(`Warning: the ${name} method already exist in Dropdown.`);
4960
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Dropdown.`);
5748
4961
  return;
5749
4962
  }
5750
4963
  Dropdown[name] = (props) => callback(new Dropdown(props));
@@ -9799,7 +9012,7 @@ var NativeComponents = (function (exports) {
9799
9012
 
9800
9013
  Modal.preset = function(name, callback) {
9801
9014
  if (Modal.prototype[name] || Modal[name]) {
9802
- DebugManager$2.warn(`Warning: the ${name} method already exist in Modal.`);
9015
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Modal.`);
9803
9016
  return;
9804
9017
  }
9805
9018
  Modal[name] = (content, props) => callback(new Modal(content, props));
@@ -10050,7 +9263,7 @@ var NativeComponents = (function (exports) {
10050
9263
 
10051
9264
  Pagination.preset = function(name, callback) {
10052
9265
  if (Pagination.prototype[name] || Pagination[name]) {
10053
- DebugManager$2.warn(`Warning: the ${name} method already exist in Pagination.`);
9266
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Pagination.`);
10054
9267
  return;
10055
9268
  }
10056
9269
  Pagination[name] = (props) => callback(new Pagination(props));
@@ -10345,7 +9558,7 @@ var NativeComponents = (function (exports) {
10345
9558
 
10346
9559
  Popover.preset = function(name, callback) {
10347
9560
  if (Popover.prototype[name] || Popover[name]) {
10348
- DebugManager$2.warn(`Warning: the ${name} method already exist in Popover.`);
9561
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Popover.`);
10349
9562
  return;
10350
9563
  }
10351
9564
  Popover[name] = (content, props) => callback(new Popover(content, props));
@@ -10647,7 +9860,7 @@ var NativeComponents = (function (exports) {
10647
9860
 
10648
9861
  Progress.preset = function(name, callback) {
10649
9862
  if (Progress.prototype[name] || Progress[name]) {
10650
- DebugManager$2.warn(`Warning: the ${name} method already exists in Progress.`);
9863
+ DebugManager$1.warn(`Warning: the ${name} method already exists in Progress.`);
10651
9864
  return;
10652
9865
  }
10653
9866
  Progress[name] = (props) => callback(new Progress(props));
@@ -10936,298 +10149,651 @@ var NativeComponents = (function (exports) {
10936
10149
  }
10937
10150
 
10938
10151
  Stack.call(this, content, props);
10939
-
10940
- this.$description.orientation = 'vertical';
10941
- this.$description.alignment = 'leading';
10152
+
10153
+ this.$description.orientation = 'vertical';
10154
+ this.$description.alignment = 'leading';
10155
+ }
10156
+ BaseComponent.extends(VStack, Stack);
10157
+
10158
+ VStack.defaultTemplate = null;
10159
+ VStack.use = function(template) {
10160
+ VStack.defaultTemplate = template;
10161
+ };
10162
+
10163
+ VStack.preset = function(name, callback) {
10164
+ if (VStack.prototype[name] || VStack[name]) {
10165
+ DebugManager$1.warn(`Warning: the ${name} method already exists in VStack.`);
10166
+ return;
10167
+ }
10168
+ VStack[name] = (content, props) => callback(new VStack(content, props));
10169
+ };
10170
+
10171
+ VStack.presets = function(presets) {
10172
+ for (const name in presets) {
10173
+ VStack.preset(name, presets[name]);
10174
+ }
10175
+ };
10176
+
10177
+ function PositionStack(content, props = {}) {
10178
+ if(!(this instanceof PositionStack)) {
10179
+ return new PositionStack(content, props);
10180
+ }
10181
+
10182
+ BaseComponent.call(this, props);
10183
+
10184
+ this.$description = {
10185
+ position: 'absolute',
10186
+ content: content,
10187
+ top: null,
10188
+ right: null,
10189
+ bottom: null,
10190
+ left: null,
10191
+ width: null,
10192
+ height: null,
10193
+ zIndex: null,
10194
+ anchor: null,
10195
+ props
10196
+ };
10197
+ }
10198
+
10199
+ BaseComponent.extends(PositionStack);
10200
+
10201
+ PositionStack.defaultTemplate = null;
10202
+ PositionStack.use = function(template) {
10203
+ PositionStack.defaultTemplate = template;
10204
+ };
10205
+
10206
+ PositionStack.prototype.top = function(value) {
10207
+ this.$description.top = value;
10208
+ return this;
10209
+ };
10210
+
10211
+ PositionStack.prototype.right = function(value) {
10212
+ this.$description.right = value;
10213
+ return this;
10214
+ };
10215
+
10216
+ PositionStack.prototype.bottom = function(value) {
10217
+ this.$description.bottom = value;
10218
+ return this;
10219
+ };
10220
+
10221
+ PositionStack.prototype.left = function(value) {
10222
+ this.$description.left = value;
10223
+ return this;
10224
+ };
10225
+
10226
+ PositionStack.prototype.fill = function() {
10227
+ this.$description.anchor = 'fill';
10228
+ return this;
10229
+ };
10230
+ PositionStack.prototype.topLeading = function() {
10231
+ this.$description.anchor = 'top-leading';
10232
+ return this;
10233
+ };
10234
+
10235
+ PositionStack.prototype.atTopCenter = function() {
10236
+ this.$description.anchor = 'top-center';
10237
+ return this;
10238
+ };
10239
+
10240
+ PositionStack.prototype.atTopTrailing = function() {
10241
+ this.$description.anchor = 'top-trailing';
10242
+ return this;
10243
+ };
10244
+
10245
+ PositionStack.prototype.atCenterLeading = function() {
10246
+ this.$description.anchor = 'center-leading';
10247
+ return this;
10248
+ };
10249
+
10250
+ PositionStack.prototype.atCenter = function() {
10251
+ this.$description.anchor = 'center';
10252
+ return this;
10253
+ };
10254
+
10255
+ PositionStack.prototype.atCenterTrailing = function() {
10256
+ this.$description.anchor = 'center-trailing';
10257
+ return this;
10258
+ };
10259
+
10260
+ PositionStack.prototype.atBottomLeading = function() {
10261
+ this.$description.anchor = 'bottom-leading';
10262
+ return this;
10263
+ };
10264
+
10265
+ PositionStack.prototype.atBottomCenter = function() {
10266
+ this.$description.anchor = 'bottom-center';
10267
+ return this;
10268
+ };
10269
+
10270
+ PositionStack.prototype.atBottomTrailing = function() {
10271
+ this.$description.anchor = 'bottom-trailing';
10272
+ return this;
10273
+ };
10274
+
10275
+ PositionStack.prototype.width = function(value) {
10276
+ this.$description.width = value;
10277
+ return this;
10278
+ };
10279
+
10280
+ PositionStack.prototype.height = function(value) {
10281
+ this.$description.height = value;
10282
+ return this;
10283
+ };
10284
+
10285
+ PositionStack.prototype.size = function(width, height) {
10286
+ this.$description.width = width;
10287
+ this.$description.height = height ?? width;
10288
+ return this;
10289
+ };
10290
+
10291
+ PositionStack.prototype.fullWidth = function() {
10292
+ this.$description.width = '100%';
10293
+ return this;
10294
+ };
10295
+
10296
+ PositionStack.prototype.fullHeight = function() {
10297
+ this.$description.height = '100%';
10298
+ return this;
10299
+ };
10300
+
10301
+ PositionStack.prototype.fullSize = function() {
10302
+ this.$description.width = '100%';
10303
+ this.$description.height = '100%';
10304
+ return this;
10305
+ };
10306
+
10307
+ PositionStack.prototype.zIndex = function(value) {
10308
+ this.$description.zIndex = value;
10309
+ return this;
10310
+ };
10311
+
10312
+ PositionStack.prototype.above = function(zIndex = 100) {
10313
+ this.$description.zIndex = zIndex;
10314
+ return this;
10315
+ };
10316
+
10317
+ PositionStack.prototype.below = function() {
10318
+ this.$description.zIndex = -1;
10319
+ return this;
10320
+ };
10321
+
10322
+ function FixedStack(content, props = {}) {
10323
+ if(!(this instanceof FixedStack)) {
10324
+ return new FixedStack(content, props);
10325
+ }
10326
+ PositionStack.call(this, content, props);
10327
+ this.$description.position = 'fixed';
10328
+ }
10329
+
10330
+ BaseComponent.extends(FixedStack, PositionStack);
10331
+
10332
+ FixedStack.defaultTemplate = null;
10333
+
10334
+ FixedStack.use = function(template) {
10335
+ FixedStack.defaultTemplate = template;
10336
+ };
10337
+
10338
+ FixedStack.preset = function(name, callback) {
10339
+ if(FixedStack.prototype[name] || FixedStack[name]) {
10340
+ DebugManager$1.warn(`Warning: the ${name} method already exists in FixedStack.`);
10341
+ return;
10342
+ }
10343
+ FixedStack[name] = (content, props) => callback(new FixedStack(content, props));
10344
+ };
10345
+
10346
+ FixedStack.presets = function(presets) {
10347
+ for(const name in presets) {
10348
+ FixedStack.preset(name, presets[name]);
10349
+ }
10350
+ };
10351
+
10352
+ function HStack(content, props = {}) {
10353
+ if (!(this instanceof HStack)) {
10354
+ return new HStack(content, props);
10355
+ }
10356
+
10357
+ Stack.call(this, content, props);
10358
+ this.$description.orientation = 'horizontal';
10942
10359
  }
10943
- BaseComponent.extends(VStack, Stack);
10944
10360
 
10945
- VStack.defaultTemplate = null;
10946
- VStack.use = function(template) {
10947
- VStack.defaultTemplate = template;
10361
+ BaseComponent.extends(HStack, Stack);
10362
+
10363
+ HStack.defaultTemplate = null;
10364
+ HStack.use = function(template) {
10365
+ HStack.defaultTemplate = template;
10948
10366
  };
10949
10367
 
10950
- VStack.preset = function(name, callback) {
10951
- if (VStack.prototype[name] || VStack[name]) {
10952
- DebugManager$2.warn(`Warning: the ${name} method already exists in VStack.`);
10368
+ HStack.preset = function(name, callback) {
10369
+ if (HStack.prototype[name] || HStack[name]) {
10370
+ DebugManager$1.warn(`Warning: the ${name} method already exists in HStack.`);
10953
10371
  return;
10954
10372
  }
10955
- VStack[name] = (content, props) => callback(new VStack(content, props));
10373
+ HStack[name] = (content, props) => callback(new HStack(content, props));
10956
10374
  };
10957
10375
 
10958
- VStack.presets = function(presets) {
10376
+ HStack.presets = function(presets) {
10959
10377
  for (const name in presets) {
10960
- VStack.preset(name, presets[name]);
10378
+ HStack.preset(name, presets[name]);
10961
10379
  }
10962
10380
  };
10963
10381
 
10964
- function PositionStack(content, props = {}) {
10965
- if(!(this instanceof PositionStack)) {
10966
- return new PositionStack(content, props);
10382
+ function AbsoluteStack(content, props = {}) {
10383
+ if(!(this instanceof AbsoluteStack)) {
10384
+ return new AbsoluteStack(content, props);
10967
10385
  }
10968
-
10969
- BaseComponent.call(this, props);
10970
-
10971
- this.$description = {
10972
- position: 'absolute',
10973
- content: content,
10974
- top: null,
10975
- right: null,
10976
- bottom: null,
10977
- left: null,
10978
- width: null,
10979
- height: null,
10980
- zIndex: null,
10981
- anchor: null,
10982
- props
10983
- };
10386
+ PositionStack.call(this, content, props);
10387
+ this.$description.position = 'absolute';
10984
10388
  }
10985
10389
 
10986
- BaseComponent.extends(PositionStack);
10390
+ BaseComponent.extends(AbsoluteStack, PositionStack);
10987
10391
 
10988
- PositionStack.defaultTemplate = null;
10989
- PositionStack.use = function(template) {
10990
- PositionStack.defaultTemplate = template;
10991
- };
10392
+ AbsoluteStack.defaultTemplate = null;
10992
10393
 
10993
- PositionStack.prototype.top = function(value) {
10994
- this.$description.top = value;
10995
- return this;
10394
+ AbsoluteStack.use = function(template) {
10395
+ AbsoluteStack.defaultTemplate = template;
10996
10396
  };
10997
10397
 
10998
- PositionStack.prototype.right = function(value) {
10999
- this.$description.right = value;
11000
- return this;
10398
+ AbsoluteStack.preset = function(name, callback) {
10399
+ if(AbsoluteStack.prototype[name] || AbsoluteStack[name]) {
10400
+ DebugManager$1.warn(`Warning: the ${name} method already exists in AbsoluteStack.`);
10401
+ return;
10402
+ }
10403
+ AbsoluteStack[name] = (content, props) => callback(new AbsoluteStack(content, props));
11001
10404
  };
11002
10405
 
11003
- PositionStack.prototype.bottom = function(value) {
11004
- this.$description.bottom = value;
11005
- return this;
10406
+ AbsoluteStack.presets = function(presets) {
10407
+ for(const name in presets) {
10408
+ AbsoluteStack.preset(name, presets[name]);
10409
+ }
11006
10410
  };
11007
10411
 
11008
- PositionStack.prototype.left = function(value) {
11009
- this.$description.left = value;
11010
- return this;
11011
- };
10412
+ function RelativeStack(content, props = {}) {
10413
+ if(!(this instanceof RelativeStack)) {
10414
+ return new RelativeStack(content, props);
10415
+ }
10416
+ PositionStack.call(this, content, props);
10417
+ this.$description.position = 'relative';
10418
+ }
11012
10419
 
11013
- PositionStack.prototype.fill = function() {
11014
- this.$description.anchor = 'fill';
11015
- return this;
11016
- };
11017
- PositionStack.prototype.topLeading = function() {
11018
- this.$description.anchor = 'top-leading';
11019
- return this;
11020
- };
10420
+ BaseComponent.extends(RelativeStack, PositionStack);
11021
10421
 
11022
- PositionStack.prototype.atTopCenter = function() {
11023
- this.$description.anchor = 'top-center';
11024
- return this;
11025
- };
10422
+ RelativeStack.defaultTemplate = null;
11026
10423
 
11027
- PositionStack.prototype.atTopTrailing = function() {
11028
- this.$description.anchor = 'top-trailing';
11029
- return this;
10424
+ RelativeStack.use = function(template) {
10425
+ RelativeStack.defaultTemplate = template;
11030
10426
  };
11031
10427
 
11032
- PositionStack.prototype.atCenterLeading = function() {
11033
- this.$description.anchor = 'center-leading';
11034
- return this;
10428
+ RelativeStack.preset = function(name, callback) {
10429
+ if(RelativeStack.prototype[name] || RelativeStack[name]) {
10430
+ DebugManager$1.warn(`Warning: the ${name} method already exists in RelativeStack.`);
10431
+ return;
10432
+ }
10433
+ RelativeStack[name] = (content, props) => callback(new RelativeStack(content, props));
11035
10434
  };
11036
10435
 
11037
- PositionStack.prototype.atCenter = function() {
11038
- this.$description.anchor = 'center';
11039
- return this;
10436
+ RelativeStack.presets = function(presets) {
10437
+ for(const name in presets) {
10438
+ RelativeStack.preset(name, presets[name]);
10439
+ }
11040
10440
  };
11041
10441
 
11042
- PositionStack.prototype.atCenterTrailing = function() {
11043
- this.$description.anchor = 'center-trailing';
11044
- return this;
10442
+ const Row = HStack;
10443
+ const Col = VStack;
10444
+
10445
+ const EVENTS = [
10446
+ "Click",
10447
+ "DblClick",
10448
+ "MouseDown",
10449
+ "MouseEnter",
10450
+ "MouseLeave",
10451
+ "MouseMove",
10452
+ "MouseOut",
10453
+ "MouseOver",
10454
+ "MouseUp",
10455
+ "Wheel",
10456
+ "KeyDown",
10457
+ "KeyPress",
10458
+ "KeyUp",
10459
+ "Blur",
10460
+ "Change",
10461
+ "Focus",
10462
+ "Input",
10463
+ "Invalid",
10464
+ "Reset",
10465
+ "Search",
10466
+ "Select",
10467
+ "Submit",
10468
+ "Drag",
10469
+ "DragEnd",
10470
+ "DragEnter",
10471
+ "DragLeave",
10472
+ "DragOver",
10473
+ "DragStart",
10474
+ "Drop",
10475
+ "AfterPrint",
10476
+ "BeforePrint",
10477
+ "BeforeUnload",
10478
+ "Error",
10479
+ "HashChange",
10480
+ "Load",
10481
+ "Offline",
10482
+ "Online",
10483
+ "PageHide",
10484
+ "PageShow",
10485
+ "Resize",
10486
+ "Scroll",
10487
+ "Unload",
10488
+ "Abort",
10489
+ "CanPlay",
10490
+ "CanPlayThrough",
10491
+ "DurationChange",
10492
+ "Emptied",
10493
+ "Ended",
10494
+ "LoadedData",
10495
+ "LoadedMetadata",
10496
+ "LoadStart",
10497
+ "Pause",
10498
+ "Play",
10499
+ "Playing",
10500
+ "Progress",
10501
+ "RateChange",
10502
+ "Seeked",
10503
+ "Seeking",
10504
+ "Stalled",
10505
+ "Suspend",
10506
+ "TimeUpdate",
10507
+ "VolumeChange",
10508
+ "Waiting",
10509
+
10510
+ "TouchCancel",
10511
+ "TouchEnd",
10512
+ "TouchMove",
10513
+ "TouchStart",
10514
+ "AnimationEnd",
10515
+ "AnimationIteration",
10516
+ "AnimationStart",
10517
+ "TransitionEnd",
10518
+ "Copy",
10519
+ "Cut",
10520
+ "Paste",
10521
+ "FocusIn",
10522
+ "FocusOut",
10523
+ "ContextMenu"
10524
+ ];
10525
+
10526
+ const EVENTS_WITH_PREVENT = [
10527
+ "Click",
10528
+ "DblClick",
10529
+ "MouseDown",
10530
+ "MouseUp",
10531
+ "Wheel",
10532
+ "KeyDown",
10533
+ "KeyPress",
10534
+ "Invalid",
10535
+ "Reset",
10536
+ "Submit",
10537
+ "DragOver",
10538
+ "Drop",
10539
+ "BeforeUnload",
10540
+ "TouchCancel",
10541
+ "TouchEnd",
10542
+ "TouchMove",
10543
+ "TouchStart",
10544
+ "Copy",
10545
+ "Cut",
10546
+ "Paste",
10547
+ "ContextMenu"
10548
+ ];
10549
+
10550
+ const EVENTS_WITH_STOP = [
10551
+ "Click",
10552
+ "DblClick",
10553
+ "MouseDown",
10554
+ "MouseMove",
10555
+ "MouseOut",
10556
+ "MouseOver",
10557
+ "MouseUp",
10558
+ "Wheel",
10559
+ "KeyDown",
10560
+ "KeyPress",
10561
+ "KeyUp",
10562
+ "Change",
10563
+ "Input",
10564
+ "Invalid",
10565
+ "Reset",
10566
+ "Search",
10567
+ "Select",
10568
+ "Submit",
10569
+ "Drag",
10570
+ "DragEnd",
10571
+ "DragEnter",
10572
+ "DragLeave",
10573
+ "DragOver",
10574
+ "DragStart",
10575
+ "Drop",
10576
+ "BeforeUnload",
10577
+ "HashChange",
10578
+ "TouchCancel",
10579
+ "TouchEnd",
10580
+ "TouchMove",
10581
+ "TouchStart",
10582
+ "AnimationEnd",
10583
+ "AnimationIteration",
10584
+ "AnimationStart",
10585
+ "TransitionEnd",
10586
+ "Copy",
10587
+ "Cut",
10588
+ "Paste",
10589
+ "FocusIn",
10590
+ "FocusOut",
10591
+ "ContextMenu"
10592
+ ];
10593
+
10594
+ const property = {
10595
+ configurable: true,
10596
+ get() {
10597
+ return new NDElement(this);
10598
+ }
11045
10599
  };
11046
10600
 
11047
- PositionStack.prototype.atBottomLeading = function() {
11048
- this.$description.anchor = 'bottom-leading';
11049
- return this;
11050
- };
10601
+ Object.defineProperty(HTMLElement.prototype, 'nd', property);
11051
10602
 
11052
- PositionStack.prototype.atBottomCenter = function() {
11053
- this.$description.anchor = 'bottom-center';
11054
- return this;
11055
- };
10603
+ Object.defineProperty(DocumentFragment.prototype, 'nd', property);
11056
10604
 
11057
- PositionStack.prototype.atBottomTrailing = function() {
11058
- this.$description.anchor = 'bottom-trailing';
11059
- return this;
11060
- };
10605
+ Object.defineProperty(NDElement.prototype, 'nd', {
10606
+ configurable: true,
10607
+ get: function() {
10608
+ return this;
10609
+ }
10610
+ });
11061
10611
 
11062
- PositionStack.prototype.width = function(value) {
11063
- this.$description.width = value;
11064
- return this;
11065
- };
11066
10612
 
11067
- PositionStack.prototype.height = function(value) {
11068
- this.$description.height = value;
11069
- return this;
11070
- };
11071
10613
 
11072
- PositionStack.prototype.size = function(width, height) {
11073
- this.$description.width = width;
11074
- this.$description.height = height ?? width;
11075
- return this;
11076
- };
10614
+ // ----------------------------------------------------------------
10615
+ // Events helpers
10616
+ // ----------------------------------------------------------------
10617
+ EVENTS.forEach(eventSourceName => {
10618
+ const eventName = eventSourceName.toLowerCase();
10619
+ NDElement.prototype['on'+eventSourceName] = function(callback = null) {
10620
+ this.$element.addEventListener(eventName, callback);
10621
+ return this;
10622
+ };
10623
+ });
11077
10624
 
11078
- PositionStack.prototype.fullWidth = function() {
11079
- this.$description.width = '100%';
11080
- return this;
11081
- };
10625
+ EVENTS_WITH_STOP.forEach(eventSourceName => {
10626
+ const eventName = eventSourceName.toLowerCase();
10627
+ NDElement.prototype['onStop'+eventSourceName] = function(callback = null) {
10628
+ _stop(this.$element, eventName, callback);
10629
+ return this;
10630
+ };
10631
+ NDElement.prototype['onPreventStop'+eventSourceName] = function(callback = null) {
10632
+ _preventStop(this.$element, eventName, callback);
10633
+ return this;
10634
+ };
10635
+ });
11082
10636
 
11083
- PositionStack.prototype.fullHeight = function() {
11084
- this.$description.height = '100%';
11085
- return this;
11086
- };
10637
+ EVENTS_WITH_PREVENT.forEach(eventSourceName => {
10638
+ const eventName = eventSourceName.toLowerCase();
10639
+ NDElement.prototype['onPrevent'+eventSourceName] = function(callback = null) {
10640
+ _prevent(this.$element, eventName, callback);
10641
+ return this;
10642
+ };
10643
+ });
11087
10644
 
11088
- PositionStack.prototype.fullSize = function() {
11089
- this.$description.width = '100%';
11090
- this.$description.height = '100%';
10645
+ NDElement.prototype.on = function(name, callback, options) {
10646
+ this.$element.addEventListener(name.toLowerCase(), callback, options);
11091
10647
  return this;
11092
10648
  };
11093
10649
 
11094
- PositionStack.prototype.zIndex = function(value) {
11095
- this.$description.zIndex = value;
10650
+ const _prevent = function(element, eventName, callback) {
10651
+ const handler = (event) => {
10652
+ event.preventDefault();
10653
+ callback && callback.call(element, event);
10654
+ };
10655
+ element.addEventListener(eventName, handler);
11096
10656
  return this;
11097
10657
  };
11098
10658
 
11099
- PositionStack.prototype.above = function(zIndex = 100) {
11100
- this.$description.zIndex = zIndex;
10659
+ const _stop = function(element, eventName, callback) {
10660
+ const handler = (event) => {
10661
+ event.stopPropagation();
10662
+ callback && callback.call(element, event);
10663
+ };
10664
+ element.addEventListener(eventName, handler);
11101
10665
  return this;
11102
10666
  };
11103
10667
 
11104
- PositionStack.prototype.below = function() {
11105
- this.$description.zIndex = -1;
10668
+ const _preventStop = function(element, eventName, callback) {
10669
+ const handler = (event) => {
10670
+ event.stopPropagation();
10671
+ event.preventDefault();
10672
+ callback && callback.call(element, event);
10673
+ };
10674
+ element.addEventListener(eventName, handler);
11106
10675
  return this;
11107
10676
  };
11108
10677
 
11109
- function FixedStack(content, props = {}) {
11110
- if(!(this instanceof FixedStack)) {
11111
- return new FixedStack(content, props);
11112
- }
11113
- PositionStack.call(this, content, props);
11114
- this.$description.position = 'fixed';
11115
- }
11116
-
11117
- BaseComponent.extends(FixedStack, PositionStack);
11118
-
11119
- FixedStack.defaultTemplate = null;
11120
-
11121
- FixedStack.use = function(template) {
11122
- FixedStack.defaultTemplate = template;
11123
- };
11124
-
11125
- FixedStack.preset = function(name, callback) {
11126
- if(FixedStack.prototype[name] || FixedStack[name]) {
11127
- DebugManager$2.warn(`Warning: the ${name} method already exists in FixedStack.`);
11128
- return;
11129
- }
11130
- FixedStack[name] = (content, props) => callback(new FixedStack(content, props));
11131
- };
11132
-
11133
- FixedStack.presets = function(presets) {
11134
- for(const name in presets) {
11135
- FixedStack.preset(name, presets[name]);
11136
- }
11137
- };
11138
-
11139
- function HStack(content, props = {}) {
11140
- if (!(this instanceof HStack)) {
11141
- return new HStack(content, props);
11142
- }
11143
-
11144
- Stack.call(this, content, props);
11145
- this.$description.orientation = 'horizontal';
11146
- }
11147
-
11148
- BaseComponent.extends(HStack, Stack);
11149
-
11150
- HStack.defaultTemplate = null;
11151
- HStack.use = function(template) {
11152
- HStack.defaultTemplate = template;
11153
- };
11154
10678
 
11155
- HStack.preset = function(name, callback) {
11156
- if (HStack.prototype[name] || HStack[name]) {
11157
- DebugManager$2.warn(`Warning: the ${name} method already exists in HStack.`);
11158
- return;
11159
- }
11160
- HStack[name] = (content, props) => callback(new HStack(content, props));
11161
- };
11162
10679
 
11163
- HStack.presets = function(presets) {
11164
- for (const name in presets) {
11165
- HStack.preset(name, presets[name]);
10680
+ // ----------------------------------------------------------------
10681
+ // Class attributes binder
10682
+ // ----------------------------------------------------------------
10683
+ const classListMethods = {
10684
+ getClasses() {
10685
+ return this.$element.className?.split(' ').filter(Boolean);
10686
+ },
10687
+ add(value) {
10688
+ const classes = this.getClasses();
10689
+ if(classes.indexOf(value) >= 0) {
10690
+ return;
10691
+ }
10692
+ classes.push(value);
10693
+ this.$element.className = classes.join(' ');
10694
+ },
10695
+ remove(value) {
10696
+ const classes = this.getClasses();
10697
+ const index = classes.indexOf(value);
10698
+ if(index < 0) {
10699
+ return;
10700
+ }
10701
+ classes.splice(index, 1);
10702
+ this.$element.className = classes.join(' ');
10703
+ },
10704
+ toggle(value, force = undefined) {
10705
+ const classes = this.getClasses();
10706
+ const index = classes.indexOf(value);
10707
+ if(index >= 0) {
10708
+ if(force === true) {
10709
+ return;
10710
+ }
10711
+ classes.splice(index, 1);
10712
+ }
10713
+ else {
10714
+ if(force === false) {
10715
+ return;
10716
+ }
10717
+ classes.push(value);
10718
+ }
10719
+ this.$element.className = classes.join(' ');
10720
+ },
10721
+ contains(value) {
10722
+ return this.getClasses().indexOf(value) >= 0;
11166
10723
  }
11167
10724
  };
11168
10725
 
11169
- function AbsoluteStack(content, props = {}) {
11170
- if(!(this instanceof AbsoluteStack)) {
11171
- return new AbsoluteStack(content, props);
10726
+ Object.defineProperty(HTMLElement.prototype, 'classes', {
10727
+ configurable: true,
10728
+ get() {
10729
+ return {
10730
+ $element: this,
10731
+ ...classListMethods
10732
+ };
11172
10733
  }
11173
- PositionStack.call(this, content, props);
11174
- this.$description.position = 'absolute';
11175
- }
11176
-
11177
- BaseComponent.extends(AbsoluteStack, PositionStack);
11178
-
11179
- AbsoluteStack.defaultTemplate = null;
11180
-
11181
- AbsoluteStack.use = function(template) {
11182
- AbsoluteStack.defaultTemplate = template;
11183
- };
10734
+ });
11184
10735
 
11185
- AbsoluteStack.preset = function(name, callback) {
11186
- if(AbsoluteStack.prototype[name] || AbsoluteStack[name]) {
11187
- DebugManager$2.warn(`Warning: the ${name} method already exists in AbsoluteStack.`);
11188
- return;
10736
+ const normalizeComponentArgs = function(props, children = null) {
10737
+ if(props && children) {
10738
+ return { props, children };
11189
10739
  }
11190
- AbsoluteStack[name] = (content, props) => callback(new AbsoluteStack(content, props));
11191
- };
11192
-
11193
- AbsoluteStack.presets = function(presets) {
11194
- for(const name in presets) {
11195
- AbsoluteStack.preset(name, presets[name]);
10740
+ if(typeof props !== 'object' || Array.isArray(props) || props === null || props.constructor.name !== 'Object' || props.$hydrate) { // IF it's not a JSON
10741
+ return { props: children, children: props }
11196
10742
  }
10743
+ return { props, children };
11197
10744
  };
11198
10745
 
11199
- function RelativeStack(content, props = {}) {
11200
- if(!(this instanceof RelativeStack)) {
11201
- return new RelativeStack(content, props);
11202
- }
11203
- PositionStack.call(this, content, props);
11204
- this.$description.position = 'relative';
11205
- }
10746
+ const createHtmlElement = (element, _attributes, _children = null) => {
10747
+ let { props: attributes, children = null } = normalizeComponentArgs(_attributes, _children);
11206
10748
 
11207
- BaseComponent.extends(RelativeStack, PositionStack);
10749
+ ElementCreator.processAttributes(element, attributes);
10750
+ ElementCreator.processChildren(children, element);
10751
+ return element;
10752
+ };
11208
10753
 
11209
- RelativeStack.defaultTemplate = null;
10754
+ /**
10755
+ *
10756
+ * @param {string} name
10757
+ * @param {?Function=} customWrapper
10758
+ * @returns {Function}
10759
+ */
10760
+ function HtmlElementWrapper(name, customWrapper = null) {
10761
+ if(name) {
10762
+ if(customWrapper) {
10763
+ let node = null;
10764
+ let createElement = (attr, children) => {
10765
+ node = document.createElement(name);
10766
+ createElement = (attr, children) => {
10767
+ return createHtmlElement(customWrapper(node.cloneNode()), attr, children);
10768
+ };
10769
+ return createHtmlElement(customWrapper(node.cloneNode()), attr, children); };
11210
10770
 
11211
- RelativeStack.use = function(template) {
11212
- RelativeStack.defaultTemplate = template;
11213
- };
10771
+ return (attr, children) => createElement(attr, children)
10772
+ }
11214
10773
 
11215
- RelativeStack.preset = function(name, callback) {
11216
- if(RelativeStack.prototype[name] || RelativeStack[name]) {
11217
- DebugManager$2.warn(`Warning: the ${name} method already exists in RelativeStack.`);
11218
- return;
11219
- }
11220
- RelativeStack[name] = (content, props) => callback(new RelativeStack(content, props));
11221
- };
10774
+ let node = null;
10775
+ let createElement = (attr, children) => {
10776
+ node = document.createElement(name);
10777
+ createElement = (attr, children) => {
10778
+ return createHtmlElement(node.cloneNode(), attr, children);
10779
+ };
10780
+ return createHtmlElement(node.cloneNode(), attr, children);
10781
+ };
11222
10782
 
11223
- RelativeStack.presets = function(presets) {
11224
- for(const name in presets) {
11225
- RelativeStack.preset(name, presets[name]);
10783
+ return (attr, children) => createElement(attr, children)
11226
10784
  }
11227
- };
10785
+ return (children, name = '') => {
10786
+ const anchor = Anchor(name);
10787
+ anchor.append(children);
10788
+ return anchor;
10789
+ };
10790
+ }
11228
10791
 
11229
- const Row = HStack;
11230
- const Col = VStack;
10792
+ /**
10793
+ * Creates a `<div>` element.
10794
+ * @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLDivElement}
10795
+ */
10796
+ const Div = HtmlElementWrapper('div');
11231
10797
 
11232
10798
  function Skeleton(props = {}) {
11233
10799
  if (!(this instanceof Skeleton)) {
@@ -11259,7 +10825,7 @@ var NativeComponents = (function (exports) {
11259
10825
 
11260
10826
  Skeleton.preset = function(name, callback) {
11261
10827
  if (Skeleton.prototype[name] || Skeleton[name]) {
11262
- DebugManager$2.warn(`Warning: the ${name} method already exists in Skeleton.`);
10828
+ DebugManager$1.warn(`Warning: the ${name} method already exists in Skeleton.`);
11263
10829
  return;
11264
10830
  }
11265
10831
  Skeleton[name] = (props) => callback(new Skeleton(props));
@@ -11623,7 +11189,7 @@ var NativeComponents = (function (exports) {
11623
11189
 
11624
11190
  Spinner.preset = function(name, callback) {
11625
11191
  if (Spinner.prototype[name] || Spinner[name]) {
11626
- DebugManager$2.warn(`Warning: the ${name} method already exists in Spinner.`);
11192
+ DebugManager$1.warn(`Warning: the ${name} method already exists in Spinner.`);
11627
11193
  return;
11628
11194
  }
11629
11195
  Spinner[name] = (props) => callback(new Spinner(props));
@@ -12193,7 +11759,7 @@ var NativeComponents = (function (exports) {
12193
11759
 
12194
11760
  Stepper.preset = function(name, callback) {
12195
11761
  if (Stepper.prototype[name] || Stepper[name]) {
12196
- DebugManager$2.warn(`Warning: the ${name} method already exist in Stepper.`);
11762
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Stepper.`);
12197
11763
  return;
12198
11764
  }
12199
11765
  Stepper[name] = (props) => callback(new Stepper(props));
@@ -12708,6 +12274,195 @@ var NativeComponents = (function (exports) {
12708
12274
  return this;
12709
12275
  };
12710
12276
 
12277
+ /**
12278
+ *
12279
+ * @param {ObservableItem} $observable
12280
+ * @param {Function} $checker
12281
+ * @class ObservableChecker
12282
+ */
12283
+ function ObservableChecker($observable, $checker) {
12284
+ this.observable = $observable;
12285
+
12286
+ ObservableItem.call(this);
12287
+
12288
+ this.$mutation = $checker;
12289
+
12290
+ $observable.subscribe((newValue) => {
12291
+ this.$updateWithMutation(newValue);
12292
+ });
12293
+
12294
+ this.$updateWithMutation($observable.val());
12295
+ }
12296
+
12297
+ ObservableChecker.prototype = Object.create(ObservableItem.prototype);
12298
+ ObservableChecker.prototype.constructor = ObservableChecker;
12299
+ ObservableChecker.prototype.__$Observable = true;
12300
+ ObservableChecker.prototype.__$isObservableChecker = true;
12301
+
12302
+
12303
+ const ObservablePipe = ObservableChecker;
12304
+ ObservablePipe.prototype.constructor = ObservablePipe;
12305
+
12306
+ ObservableChecker.prototype.$updateWithMutation = function(newValue) {
12307
+ newValue = this.$mutation(newValue);
12308
+ return this.set(newValue);
12309
+ };
12310
+
12311
+ NDElement.$getChild = ElementCreator.getChild;
12312
+
12313
+ String.prototype.toNdElement = function () {
12314
+ return ElementCreator.createStaticTextNode(null, this);
12315
+ };
12316
+
12317
+ Number.prototype.toNdElement = function () {
12318
+ return ElementCreator.createStaticTextNode(null, this.toString());
12319
+ };
12320
+
12321
+ Element.prototype.toNdElement = function () {
12322
+ return this;
12323
+ };
12324
+ Text.prototype.toNdElement = function () {
12325
+ return this;
12326
+ };
12327
+ Comment.prototype.toNdElement = function () {
12328
+ return this;
12329
+ };
12330
+ Document.prototype.toNdElement = function () {
12331
+ return this;
12332
+ };
12333
+ DocumentFragment.prototype.toNdElement = function () {
12334
+ return this;
12335
+ };
12336
+
12337
+ ObservableItem.prototype.toNdElement = function () {
12338
+ return ElementCreator.createObservableNode(null, this);
12339
+ };
12340
+
12341
+ ObservableChecker.prototype.toNdElement = ObservableItem.prototype.toNdElement;
12342
+
12343
+ NDElement.prototype.toNdElement = function () {
12344
+ const element = this.$element ?? this.$build?.() ?? this.build?.() ?? null;
12345
+ if(this.$attachements) {
12346
+ if(!this.$attachements.contains(this.$element)) {
12347
+ this.$attachements.append(this.$element);
12348
+ }
12349
+ return this.$attachements;
12350
+ }
12351
+ return element;
12352
+ };
12353
+
12354
+ Array.prototype.toNdElement = function () {
12355
+ const fragment = document.createDocumentFragment();
12356
+ for(let i = 0, length = this.length; i < length; i++) {
12357
+ const child = ElementCreator.getChild(this[i]);
12358
+ if(child === null) continue;
12359
+ fragment.appendChild(child);
12360
+ }
12361
+ return fragment;
12362
+ };
12363
+
12364
+ Function.prototype.toNdElement = function () {
12365
+ const child = this;
12366
+ return ElementCreator.getChild(child());
12367
+ };
12368
+
12369
+ /**
12370
+ * @param {HTMLElement} el
12371
+ * @param {number} timeout
12372
+ */
12373
+ const waitForVisualEnd = (el, timeout = 1000) => {
12374
+ return new Promise((resolve) => {
12375
+ let isResolved = false;
12376
+
12377
+ const cleanupAndResolve = (e) => {
12378
+ if (e && e.target !== el) return;
12379
+ if (isResolved) return;
12380
+
12381
+ isResolved = true;
12382
+ el.removeEventListener('transitionend', cleanupAndResolve);
12383
+ el.removeEventListener('animationend', cleanupAndResolve);
12384
+ clearTimeout(timer);
12385
+ resolve();
12386
+ };
12387
+
12388
+ el.addEventListener('transitionend', cleanupAndResolve);
12389
+ el.addEventListener('animationend', cleanupAndResolve);
12390
+
12391
+ const timer = setTimeout(cleanupAndResolve, timeout);
12392
+
12393
+ const style = window.getComputedStyle(el);
12394
+ const hasTransition = style.transitionDuration !== '0s';
12395
+ const hasAnimation = style.animationDuration !== '0s';
12396
+
12397
+ if (!hasTransition && !hasAnimation) {
12398
+ cleanupAndResolve();
12399
+ }
12400
+ });
12401
+ };
12402
+
12403
+ NDElement.prototype.transitionOut = function(transitionName) {
12404
+ const exitClass = transitionName + '-exit';
12405
+ const el = this.$element;
12406
+ this.beforeUnmount('transition-exit', async function() {
12407
+ el.classes.add(exitClass);
12408
+ await waitForVisualEnd(el);
12409
+ el.classes.remove(exitClass);
12410
+ });
12411
+ return this;
12412
+ };
12413
+
12414
+ NDElement.prototype.transitionIn = function(transitionName) {
12415
+ const startClass = transitionName + '-enter-from';
12416
+ const endClass = transitionName + '-enter-to';
12417
+
12418
+ const el = this.$element;
12419
+
12420
+ el.classes.add(startClass);
12421
+
12422
+ this.mounted(() => {
12423
+ requestAnimationFrame(() => {
12424
+ requestAnimationFrame(() => {
12425
+ el.classes.remove(startClass);
12426
+ el.classes.add(endClass);
12427
+
12428
+ waitForVisualEnd(el).then(() => {
12429
+ el.classes.remove(endClass);
12430
+ });
12431
+ });
12432
+ });
12433
+ });
12434
+ return this;
12435
+ };
12436
+
12437
+
12438
+ NDElement.prototype.transition = function (transitionName) {
12439
+ this.transitionIn(transitionName);
12440
+ this.transitionOut(transitionName);
12441
+ return this;
12442
+ };
12443
+
12444
+ NDElement.prototype.animate = function(animationName) {
12445
+ const el = this.$element;
12446
+ el.classes.add(animationName);
12447
+
12448
+ waitForVisualEnd(el).then(() => {
12449
+ el.classes.remove(animationName);
12450
+ });
12451
+
12452
+ return this;
12453
+ };
12454
+
12455
+ ObservableItem.prototype.handleNdAttribute = function(element, attributeName) {
12456
+ if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
12457
+ bindBooleanAttribute(element, attributeName, this);
12458
+ return;
12459
+ }
12460
+
12461
+ bindAttributeWithObservable(element, attributeName, this);
12462
+ };
12463
+
12464
+ ObservableChecker.prototype.handleNdAttribute = ObservableItem.prototype.handleNdAttribute;
12465
+
12711
12466
  function ColumnGroup(title, props = {}) {
12712
12467
  this.$description = {
12713
12468
  header: title,
@@ -13146,7 +12901,7 @@ var NativeComponents = (function (exports) {
13146
12901
 
13147
12902
  DataTable.prototype.selectedRows = function($obs) {
13148
12903
  if(!$obs.__$isObservableArray) {
13149
- DebugManager$2.warn('Database', 'selectedRow should take an Observable array');
12904
+ DebugManager$1.warn('Database', 'selectedRow should take an Observable array');
13150
12905
  }
13151
12906
  this.$description.$selectedRows = $obs;
13152
12907
  return this;
@@ -13693,7 +13448,7 @@ var NativeComponents = (function (exports) {
13693
13448
 
13694
13449
  Tooltip.preset = function(name, callback) {
13695
13450
  if (Tooltip.prototype[name] || Tooltip[name]) {
13696
- DebugManager$2.warn(`Warning: the ${name} method already exist in Tooltip.`);
13451
+ DebugManager$1.warn(`Warning: the ${name} method already exist in Tooltip.`);
13697
13452
  return;
13698
13453
  }
13699
13454
  Tooltip[name] = (content, props) => callback(new Tooltip(content, props));