native-document 1.0.94 → 1.0.98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{src/devtools/hrm → devtools}/ComponentRegistry.js +2 -2
- package/devtools/index.js +8 -0
- package/{src/devtools/plugin.js → devtools/plugin/dev-tools-plugin.js} +2 -2
- package/{src/devtools/hrm/nd-vite-hot-reload.js → devtools/transformers/nd-vite-devtools.js} +16 -6
- package/devtools/transformers/src/transformComponentForHrm.js +74 -0
- package/devtools/transformers/src/transformJsFile.js +9 -0
- package/devtools/transformers/src/utils.js +79 -0
- package/devtools/widget/Widget.js +48 -0
- package/devtools/widget/widget.css +81 -0
- package/devtools/widget.js +23 -0
- package/dist/native-document.components.min.js +2441 -1191
- package/dist/native-document.dev.js +2710 -1359
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.devtools.min.js +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/cache.md +1 -1
- package/docs/core-concepts.md +1 -1
- package/docs/native-document-element.md +51 -15
- package/docs/observables.md +310 -306
- package/docs/state-management.md +198 -193
- package/index.def.js +762 -26
- package/package.json +1 -1
- package/readme.md +1 -1
- package/src/core/data/ObservableChecker.js +2 -0
- package/src/core/data/ObservableItem.js +97 -0
- package/src/core/data/ObservableObject.js +182 -0
- package/src/core/data/Store.js +364 -34
- package/src/core/data/observable-helpers/object.js +2 -166
- package/src/core/elements/anchor.js +28 -20
- package/src/core/elements/control/for-each.js +1 -1
- package/src/core/utils/formatters.js +91 -0
- package/src/core/utils/localstorage.js +57 -0
- package/src/core/utils/validator.js +0 -2
- package/src/core/wrappers/DocumentObserver.js +102 -31
- package/src/core/wrappers/ElementCreator.js +5 -0
- package/src/core/wrappers/NDElement.js +32 -1
- package/src/core/wrappers/prototypes/nd-element.transition.extensions.js +83 -0
- package/src/devtools.js +9 -0
- package/src/fetch/NativeFetch.js +5 -2
- package/types/elements.d.ts +580 -2
- package/types/nd-element.d.ts +6 -0
- package/types/observable.d.ts +71 -15
- package/types/plugins-manager.d.ts +1 -1
- package/types/store.d.ts +33 -6
- package/hrm.js +0 -7
- package/src/devtools/app/App.js +0 -66
- package/src/devtools/app/app.css +0 -0
- package/src/devtools/hrm/transformComponent.js +0 -129
- package/src/devtools/index.js +0 -18
- package/src/devtools/widget/DevToolsWidget.js +0 -26
- /package/{src/devtools/hrm → devtools/transformers/templates}/hrm.hook.template.js +0 -0
- /package/{src/devtools/hrm → devtools/transformers/templates}/hrm.orbservable.hook.template.js +0 -0
|
@@ -15,6 +15,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
15
15
|
|
|
16
16
|
anchorFragment.nativeInsertBefore = anchorFragment.insertBefore;
|
|
17
17
|
anchorFragment.nativeAppendChild = anchorFragment.appendChild;
|
|
18
|
+
anchorFragment.nativeAppend = anchorFragment.append;
|
|
18
19
|
|
|
19
20
|
const isParentUniqueChild = (parent) => (isUniqueChild || (parent.firstChild === anchorStart && parent.lastChild === anchorEnd))
|
|
20
21
|
|
|
@@ -50,59 +51,66 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
50
51
|
before = before ?? anchorEnd;
|
|
51
52
|
insertBefore(parent, child, before);
|
|
52
53
|
};
|
|
54
|
+
|
|
53
55
|
anchorFragment.append = function(...args ) {
|
|
54
56
|
return anchorFragment.appendChild(args);
|
|
55
|
-
}
|
|
57
|
+
};
|
|
56
58
|
|
|
57
|
-
anchorFragment.removeChildren = function() {
|
|
59
|
+
anchorFragment.removeChildren = async function() {
|
|
58
60
|
const parent = anchorEnd.parentNode;
|
|
59
61
|
if(parent === anchorFragment) {
|
|
60
62
|
return;
|
|
61
63
|
}
|
|
62
|
-
if(isParentUniqueChild(parent)) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
64
|
+
// if(isParentUniqueChild(parent)) {
|
|
65
|
+
// parent.replaceChildren(anchorStart, anchorEnd);
|
|
66
|
+
// return;
|
|
67
|
+
// }
|
|
66
68
|
|
|
67
69
|
let itemToRemove = anchorStart.nextSibling, tempItem;
|
|
68
|
-
const
|
|
70
|
+
const removes = [];
|
|
69
71
|
while(itemToRemove && itemToRemove !== anchorEnd) {
|
|
70
72
|
tempItem = itemToRemove.nextSibling;
|
|
71
|
-
|
|
73
|
+
removes.push(itemToRemove.remove());
|
|
72
74
|
itemToRemove = tempItem;
|
|
73
75
|
}
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
76
|
+
await Promise.all(removes);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
anchorFragment.remove = async function() {
|
|
77
80
|
const parent = anchorEnd.parentNode;
|
|
78
81
|
if(parent === anchorFragment) {
|
|
79
82
|
return;
|
|
80
83
|
}
|
|
81
84
|
let itemToRemove = anchorStart.nextSibling, tempItem;
|
|
85
|
+
const allItemToRemove = [];
|
|
86
|
+
const removes = [];
|
|
82
87
|
while(itemToRemove && itemToRemove !== anchorEnd) {
|
|
83
88
|
tempItem = itemToRemove.nextSibling;
|
|
84
|
-
|
|
89
|
+
allItemToRemove.push(itemToRemove);
|
|
90
|
+
removes.push(itemToRemove.remove());
|
|
85
91
|
itemToRemove = tempItem;
|
|
86
92
|
}
|
|
93
|
+
await Promise.all(removes);
|
|
94
|
+
anchorFragment.nativeAppend(...allItemToRemove);
|
|
87
95
|
};
|
|
88
96
|
|
|
89
|
-
anchorFragment.removeWithAnchors = function() {
|
|
90
|
-
anchorFragment.removeChildren();
|
|
97
|
+
anchorFragment.removeWithAnchors = async function() {
|
|
98
|
+
await anchorFragment.removeChildren();
|
|
91
99
|
anchorStart.remove();
|
|
92
100
|
anchorEnd.remove();
|
|
93
101
|
};
|
|
94
102
|
|
|
95
|
-
anchorFragment.replaceContent = function(child) {
|
|
103
|
+
anchorFragment.replaceContent = async function(child) {
|
|
96
104
|
const childElement = Validator.isElement(child) ? child : ElementCreator.getChild(child);
|
|
97
105
|
const parent = anchorEnd.parentNode;
|
|
98
106
|
if(!parent) {
|
|
99
107
|
return;
|
|
100
108
|
}
|
|
101
|
-
if(isParentUniqueChild(parent)) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
anchorFragment.removeChildren();
|
|
109
|
+
// if(isParentUniqueChild(parent)) {
|
|
110
|
+
// parent.replaceChildren(anchorStart, childElement, anchorEnd);
|
|
111
|
+
// return;
|
|
112
|
+
// }
|
|
113
|
+
await anchorFragment.removeChildren();
|
|
106
114
|
parent.insertBefore(childElement, anchorEnd);
|
|
107
115
|
};
|
|
108
116
|
|
|
@@ -50,7 +50,7 @@ export function ForEach(data, callback, key, { shouldKeepItemsInCache = false }
|
|
|
50
50
|
}
|
|
51
51
|
const child = cacheItem.child?.deref();
|
|
52
52
|
if(parent && child) {
|
|
53
|
-
|
|
53
|
+
child.remove();
|
|
54
54
|
}
|
|
55
55
|
cacheItem.indexObserver?.cleanup();
|
|
56
56
|
cacheItem.child = null;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const $parseDateParts = (value, locale) => {
|
|
2
|
+
const d = new Date(value);
|
|
3
|
+
return {
|
|
4
|
+
d,
|
|
5
|
+
parts: new Intl.DateTimeFormat(locale, {
|
|
6
|
+
year: 'numeric',
|
|
7
|
+
month: 'long',
|
|
8
|
+
day: '2-digit',
|
|
9
|
+
hour: '2-digit',
|
|
10
|
+
minute: '2-digit',
|
|
11
|
+
second: '2-digit',
|
|
12
|
+
}).formatToParts(d).reduce((acc, { type, value }) => {
|
|
13
|
+
acc[type] = value;
|
|
14
|
+
return acc;
|
|
15
|
+
}, {})
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const $applyDatePattern = (pattern, d, parts) => {
|
|
20
|
+
const pad = n => String(n).padStart(2, '0');
|
|
21
|
+
return pattern
|
|
22
|
+
.replace('YYYY', parts.year)
|
|
23
|
+
.replace('YY', parts.year.slice(-2))
|
|
24
|
+
.replace('MMMM', parts.month)
|
|
25
|
+
.replace('MMM', parts.month.slice(0, 3))
|
|
26
|
+
.replace('MM', pad(d.getMonth() + 1))
|
|
27
|
+
.replace('DD', pad(d.getDate()))
|
|
28
|
+
.replace('D', d.getDate())
|
|
29
|
+
.replace('HH', parts.hour)
|
|
30
|
+
.replace('mm', parts.minute)
|
|
31
|
+
.replace('ss', parts.second);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const Formatters = {
|
|
35
|
+
|
|
36
|
+
currency: (value, locale, { currency = 'XOF', notation, minimumFractionDigits, maximumFractionDigits } = {}) =>
|
|
37
|
+
new Intl.NumberFormat(locale, {
|
|
38
|
+
style: 'currency',
|
|
39
|
+
currency,
|
|
40
|
+
notation,
|
|
41
|
+
minimumFractionDigits,
|
|
42
|
+
maximumFractionDigits
|
|
43
|
+
}).format(value),
|
|
44
|
+
|
|
45
|
+
number: (value, locale, { notation, minimumFractionDigits, maximumFractionDigits } = {}) =>
|
|
46
|
+
new Intl.NumberFormat(locale, {
|
|
47
|
+
notation,
|
|
48
|
+
minimumFractionDigits,
|
|
49
|
+
maximumFractionDigits
|
|
50
|
+
}).format(value),
|
|
51
|
+
|
|
52
|
+
percent: (value, locale, { decimals = 1 } = {}) =>
|
|
53
|
+
new Intl.NumberFormat(locale, {
|
|
54
|
+
style: 'percent',
|
|
55
|
+
maximumFractionDigits: decimals
|
|
56
|
+
}).format(value),
|
|
57
|
+
|
|
58
|
+
date: (value, locale, { format, dateStyle = 'long' } = {}) => {
|
|
59
|
+
if (format) {
|
|
60
|
+
const { d, parts } = $parseDateParts(value, locale);
|
|
61
|
+
return $applyDatePattern(format, d, parts);
|
|
62
|
+
}
|
|
63
|
+
return new Intl.DateTimeFormat(locale, { dateStyle }).format(new Date(value));
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
time: (value, locale, { format, hour = '2-digit', minute = '2-digit', second } = {}) => {
|
|
67
|
+
if (format) {
|
|
68
|
+
const { d, parts } = $parseDateParts(value, locale);
|
|
69
|
+
return $applyDatePattern(format, d, parts);
|
|
70
|
+
}
|
|
71
|
+
return new Intl.DateTimeFormat(locale, { hour, minute, second }).format(new Date(value));
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
datetime: (value, locale, { format, dateStyle = 'long', hour = '2-digit', minute = '2-digit', second } = {}) => {
|
|
75
|
+
if (format) {
|
|
76
|
+
const { d, parts } = $parseDateParts(value, locale);
|
|
77
|
+
return $applyDatePattern(format, d, parts);
|
|
78
|
+
}
|
|
79
|
+
return new Intl.DateTimeFormat(locale, { dateStyle, hour, minute, second }).format(new Date(value));
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
relative: (value, locale, { unit = 'day', numeric = 'auto' } = {}) => {
|
|
83
|
+
const diff = Math.round((value - Date.now()) / (1000 * 60 * 60 * 24));
|
|
84
|
+
return new Intl.RelativeTimeFormat(locale, { numeric }).format(diff, unit);
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
plural: (value, locale, { singular, plural } = {}) => {
|
|
88
|
+
const rule = new Intl.PluralRules(locale).select(value);
|
|
89
|
+
return `${value} ${rule === 'one' ? singular : plural}`;
|
|
90
|
+
},
|
|
91
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import NativeDocumentError from "../errors/NativeDocumentError";
|
|
2
|
+
|
|
3
|
+
export const LocalStorage = {
|
|
4
|
+
getJson(key) {
|
|
5
|
+
let value = localStorage.getItem(key);
|
|
6
|
+
try {
|
|
7
|
+
return JSON.parse(value);
|
|
8
|
+
} catch (e) {
|
|
9
|
+
throw new NativeDocumentError('invalid_json:'+key);
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
getNumber(key) {
|
|
13
|
+
return Number(this.get(key));
|
|
14
|
+
},
|
|
15
|
+
getBool(key) {
|
|
16
|
+
const value = this.get(key);
|
|
17
|
+
return value === 'true' || value === '1';
|
|
18
|
+
},
|
|
19
|
+
setJson(key, value) {
|
|
20
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
21
|
+
},
|
|
22
|
+
setBool(key, value) {
|
|
23
|
+
localStorage.setItem(key, value ? 'true' : 'false');
|
|
24
|
+
},
|
|
25
|
+
get(key, defaultValue = null) {
|
|
26
|
+
return localStorage.getItem(key) || defaultValue;
|
|
27
|
+
},
|
|
28
|
+
set(key, value) {
|
|
29
|
+
return localStorage.setItem(key, value);
|
|
30
|
+
},
|
|
31
|
+
remove(key) {
|
|
32
|
+
localStorage.removeItem(key);
|
|
33
|
+
},
|
|
34
|
+
has(key) {
|
|
35
|
+
return localStorage.getItem(key) != null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const $getFromStorage = (key, value) => {
|
|
40
|
+
if(!LocalStorage.has(key)) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
switch (typeof value) {
|
|
44
|
+
case 'object': return LocalStorage.getJson(key) ?? value;
|
|
45
|
+
case 'boolean': return LocalStorage.getBool(key) ?? value;
|
|
46
|
+
case 'number': return LocalStorage.getNumber(key) ?? value;
|
|
47
|
+
default: return LocalStorage.get(key, value) ?? value;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const $saveToStorage = (value) => {
|
|
52
|
+
switch (typeof value) {
|
|
53
|
+
case 'object': return LocalStorage.setJson;
|
|
54
|
+
case 'boolean': return LocalStorage.setBool;
|
|
55
|
+
default: return LocalStorage.set;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import ObservableItem from "../data/ObservableItem";
|
|
2
1
|
import DebugManager from "./debug-manager";
|
|
3
2
|
import NativeDocumentError from "../errors/NativeDocumentError";
|
|
4
3
|
import ObservableChecker from "../data/ObservableChecker";
|
|
5
4
|
import {NDElement} from "../wrappers/NDElement";
|
|
6
|
-
import TemplateBinding from "../wrappers/TemplateBinding";
|
|
7
5
|
|
|
8
6
|
const COMMON_NODE_TYPES = {
|
|
9
7
|
ELEMENT: 1,
|
|
@@ -1,97 +1,167 @@
|
|
|
1
|
-
|
|
2
1
|
const DocumentObserver = {
|
|
3
2
|
mounted: new WeakMap(),
|
|
3
|
+
beforeUnmount: new WeakMap(),
|
|
4
4
|
mountedSupposedSize: 0,
|
|
5
5
|
unmounted: new WeakMap(),
|
|
6
6
|
unmountedSupposedSize: 0,
|
|
7
7
|
observer: null,
|
|
8
|
+
|
|
8
9
|
executeMountedCallback(node) {
|
|
9
10
|
const data = DocumentObserver.mounted.get(node);
|
|
10
11
|
if(!data) {
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
13
14
|
data.inDom = true;
|
|
14
|
-
data.mounted
|
|
15
|
+
if(!data.mounted) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if(Array.isArray(data.mounted)) {
|
|
19
|
+
for(const cb of data.mounted) {
|
|
20
|
+
cb(node);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
data.mounted(node);
|
|
15
25
|
},
|
|
26
|
+
|
|
16
27
|
executeUnmountedCallback(node) {
|
|
17
28
|
const data = DocumentObserver.unmounted.get(node);
|
|
18
29
|
if(!data) {
|
|
19
30
|
return;
|
|
20
31
|
}
|
|
21
|
-
|
|
22
32
|
data.inDom = false;
|
|
23
|
-
if(data.unmounted
|
|
33
|
+
if(!data.unmounted) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let shouldRemove = false;
|
|
38
|
+
if(Array.isArray(data.unmounted)) {
|
|
39
|
+
for(const cb of data.unmounted) {
|
|
40
|
+
if(cb(node) === true) {
|
|
41
|
+
shouldRemove = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
shouldRemove = data.unmounted(node) === true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if(shouldRemove) {
|
|
24
49
|
data.disconnect();
|
|
25
50
|
node.nd?.remove();
|
|
26
51
|
}
|
|
27
52
|
},
|
|
53
|
+
|
|
28
54
|
checkMutation: function(mutationsList) {
|
|
29
|
-
let i = 0;
|
|
30
55
|
for(const mutation of mutationsList) {
|
|
31
|
-
if(DocumentObserver.mountedSupposedSize > 0
|
|
56
|
+
if(DocumentObserver.mountedSupposedSize > 0) {
|
|
32
57
|
for(const node of mutation.addedNodes) {
|
|
33
58
|
DocumentObserver.executeMountedCallback(node);
|
|
34
59
|
if(!node.querySelectorAll) {
|
|
35
|
-
|
|
60
|
+
continue;
|
|
36
61
|
}
|
|
37
62
|
const children = node.querySelectorAll('[data--nd-mounted]');
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
for(const node of children) {
|
|
42
|
-
DocumentObserver.executeMountedCallback(node);
|
|
63
|
+
for(const child of children) {
|
|
64
|
+
DocumentObserver.executeMountedCallback(child);
|
|
43
65
|
}
|
|
44
66
|
}
|
|
45
67
|
}
|
|
46
68
|
|
|
47
|
-
if(DocumentObserver.unmountedSupposedSize > 0
|
|
48
|
-
for(const node of mutation.removedNodes) {
|
|
69
|
+
if (DocumentObserver.unmountedSupposedSize > 0) {
|
|
70
|
+
for (const node of mutation.removedNodes) {
|
|
49
71
|
DocumentObserver.executeUnmountedCallback(node);
|
|
50
72
|
if(!node.querySelectorAll) {
|
|
51
|
-
|
|
73
|
+
continue;
|
|
52
74
|
}
|
|
53
75
|
const children = node.querySelectorAll('[data--nd-unmounted]');
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
for(const node of children) {
|
|
58
|
-
DocumentObserver.executeUnmountedCallback(node);
|
|
76
|
+
for(const child of children) {
|
|
77
|
+
DocumentObserver.executeUnmountedCallback(child);
|
|
59
78
|
}
|
|
60
79
|
}
|
|
61
80
|
}
|
|
62
81
|
}
|
|
63
82
|
},
|
|
83
|
+
|
|
64
84
|
/**
|
|
65
|
-
*
|
|
66
85
|
* @param {HTMLElement} element
|
|
67
86
|
* @param {boolean} inDom
|
|
68
|
-
* @returns {{
|
|
87
|
+
* @returns {{ disconnect: Function, mounted: Function, unmounted: Function, off: Function }}
|
|
69
88
|
*/
|
|
70
89
|
watch: function(element, inDom = false) {
|
|
90
|
+
let mountedRegistered = false;
|
|
91
|
+
let unmountedRegistered = false;
|
|
92
|
+
|
|
71
93
|
let data = {
|
|
72
94
|
inDom,
|
|
73
95
|
mounted: null,
|
|
74
96
|
unmounted: null,
|
|
75
97
|
disconnect: () => {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
98
|
+
if (mountedRegistered) {
|
|
99
|
+
DocumentObserver.mounted.delete(element);
|
|
100
|
+
DocumentObserver.mountedSupposedSize--;
|
|
101
|
+
}
|
|
102
|
+
if (unmountedRegistered) {
|
|
103
|
+
DocumentObserver.unmounted.delete(element);
|
|
104
|
+
DocumentObserver.unmountedSupposedSize--;
|
|
105
|
+
}
|
|
80
106
|
data = null;
|
|
81
107
|
}
|
|
82
108
|
};
|
|
83
109
|
|
|
110
|
+
const addListener = (type, callback) => {
|
|
111
|
+
if (!data[type]) {
|
|
112
|
+
data[type] = callback;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(data[type])) {
|
|
116
|
+
data[type] = [data[type], callback];
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
data[type].push(callback);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const removeListener = (type, callback) => {
|
|
123
|
+
if(!data?.[type]) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if(Array.isArray(data[type])) {
|
|
127
|
+
const index = data[type].indexOf(callback);
|
|
128
|
+
if(index > -1) {
|
|
129
|
+
data[type].splice(index, 1);
|
|
130
|
+
}
|
|
131
|
+
if(data[type].length === 1) {
|
|
132
|
+
data[type] = data[type][0];
|
|
133
|
+
}
|
|
134
|
+
if(data[type].length === 0) {
|
|
135
|
+
data[type] = null;
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
data[type] = null;
|
|
140
|
+
};
|
|
141
|
+
|
|
84
142
|
return {
|
|
85
|
-
disconnect: data
|
|
143
|
+
disconnect: () => data?.disconnect(),
|
|
144
|
+
|
|
86
145
|
mounted: (callback) => {
|
|
87
|
-
|
|
146
|
+
addListener('mounted', callback);
|
|
88
147
|
DocumentObserver.mounted.set(element, data);
|
|
89
|
-
|
|
148
|
+
if (!mountedRegistered) {
|
|
149
|
+
DocumentObserver.mountedSupposedSize++;
|
|
150
|
+
mountedRegistered = true;
|
|
151
|
+
}
|
|
90
152
|
},
|
|
153
|
+
|
|
91
154
|
unmounted: (callback) => {
|
|
92
|
-
|
|
155
|
+
addListener('unmounted', callback);
|
|
93
156
|
DocumentObserver.unmounted.set(element, data);
|
|
94
|
-
|
|
157
|
+
if (!unmountedRegistered) {
|
|
158
|
+
DocumentObserver.unmountedSupposedSize++;
|
|
159
|
+
unmountedRegistered = true;
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
off: (type, callback) => {
|
|
164
|
+
removeListener(type, callback);
|
|
95
165
|
}
|
|
96
166
|
};
|
|
97
167
|
}
|
|
@@ -102,4 +172,5 @@ DocumentObserver.observer.observe(document.body, {
|
|
|
102
172
|
childList: true,
|
|
103
173
|
subtree: true,
|
|
104
174
|
});
|
|
175
|
+
|
|
105
176
|
export default DocumentObserver;
|
|
@@ -3,6 +3,7 @@ import Validator from "../utils/validator";
|
|
|
3
3
|
import AttributesWrapper from "./AttributesWrapper";
|
|
4
4
|
import PluginsManager from "../utils/plugins-manager";
|
|
5
5
|
import './prototypes/nd-element-extensions';
|
|
6
|
+
import './prototypes/nd-element.transition.extensions';
|
|
6
7
|
import './prototypes/attributes-extensions';
|
|
7
8
|
|
|
8
9
|
const $nodeCache = new Map();
|
|
@@ -95,6 +96,10 @@ export const ElementCreator = {
|
|
|
95
96
|
PluginsManager.emit('AfterProcessChildren', parent);
|
|
96
97
|
}
|
|
97
98
|
},
|
|
99
|
+
async safeRemove(element) {
|
|
100
|
+
await element.remove();
|
|
101
|
+
|
|
102
|
+
},
|
|
98
103
|
getChild(child) {
|
|
99
104
|
if(child == null) {
|
|
100
105
|
return null;
|
|
@@ -73,6 +73,37 @@ NDElement.prototype.unmounted = function(callback) {
|
|
|
73
73
|
return this.lifecycle({ unmounted: callback });
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
+
NDElement.prototype.beforeUnmount = function(id, callback) {
|
|
77
|
+
const el = this.$element;
|
|
78
|
+
|
|
79
|
+
if(!DocumentObserver.beforeUnmount.has(el)) {
|
|
80
|
+
DocumentObserver.beforeUnmount.set(el, new Map());
|
|
81
|
+
const originalRemove = el.remove.bind(el);
|
|
82
|
+
|
|
83
|
+
let $isUnmounting = false
|
|
84
|
+
|
|
85
|
+
el.remove = async () => {
|
|
86
|
+
if($isUnmounting) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
$isUnmounting = true;
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const callbacks = DocumentObserver.beforeUnmount.get(el);
|
|
93
|
+
for (const cb of callbacks.values()) {
|
|
94
|
+
await cb.call(this, el);
|
|
95
|
+
}
|
|
96
|
+
} finally {
|
|
97
|
+
originalRemove();
|
|
98
|
+
$isUnmounting = false;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
DocumentObserver.beforeUnmount.get(el).set(id, callback);
|
|
104
|
+
return this;
|
|
105
|
+
};
|
|
106
|
+
|
|
76
107
|
NDElement.prototype.htmlElement = function() {
|
|
77
108
|
return this.$element;
|
|
78
109
|
};
|
|
@@ -160,7 +191,7 @@ NDElement.prototype.with = function(methods) {
|
|
|
160
191
|
}
|
|
161
192
|
|
|
162
193
|
return this;
|
|
163
|
-
}
|
|
194
|
+
};
|
|
164
195
|
|
|
165
196
|
/**
|
|
166
197
|
* Extends the NDElement prototype with new methods available to all NDElement instances.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {NDElement} from "../NDElement";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {HTMLElement} el
|
|
5
|
+
* @param {number} timeout
|
|
6
|
+
*/
|
|
7
|
+
const waitForVisualEnd = (el, timeout = 1000) => {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
let isResolved = false;
|
|
10
|
+
|
|
11
|
+
const cleanupAndResolve = (e) => {
|
|
12
|
+
if (e && e.target !== el) return;
|
|
13
|
+
if (isResolved) return;
|
|
14
|
+
|
|
15
|
+
isResolved = true;
|
|
16
|
+
el.removeEventListener('transitionend', cleanupAndResolve);
|
|
17
|
+
el.removeEventListener('animationend', cleanupAndResolve);
|
|
18
|
+
clearTimeout(timer);
|
|
19
|
+
resolve();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
el.addEventListener('transitionend', cleanupAndResolve);
|
|
23
|
+
el.addEventListener('animationend', cleanupAndResolve);
|
|
24
|
+
|
|
25
|
+
const timer = setTimeout(cleanupAndResolve, timeout);
|
|
26
|
+
|
|
27
|
+
const style = window.getComputedStyle(el);
|
|
28
|
+
const hasTransition = style.transitionDuration !== '0s';
|
|
29
|
+
const hasAnimation = style.animationDuration !== '0s';
|
|
30
|
+
|
|
31
|
+
if (!hasTransition && !hasAnimation) {
|
|
32
|
+
cleanupAndResolve();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
NDElement.prototype.transitionOut = function(transitionName) {
|
|
38
|
+
const exitClass = transitionName + '-exit';
|
|
39
|
+
this.beforeUnmount('transition-exit', async function() {
|
|
40
|
+
this.$element.classes.add(exitClass);
|
|
41
|
+
await waitForVisualEnd(this.$element);
|
|
42
|
+
this.$element.classes.remove(exitClass);
|
|
43
|
+
});
|
|
44
|
+
return this;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
NDElement.prototype.transitionIn = function(transitionName) {
|
|
48
|
+
const startClass = transitionName + '-enter-from';
|
|
49
|
+
const endClass = transitionName + '-enter-to';
|
|
50
|
+
|
|
51
|
+
this.$element.classes.add(startClass);
|
|
52
|
+
|
|
53
|
+
this.mounted(() => {
|
|
54
|
+
requestAnimationFrame(() => {
|
|
55
|
+
requestAnimationFrame(() => {
|
|
56
|
+
this.$element.classes.remove(startClass);
|
|
57
|
+
this.$element.classes.add(endClass);
|
|
58
|
+
|
|
59
|
+
waitForVisualEnd(this.$element).then(() => {
|
|
60
|
+
this.$element.classes.remove(endClass);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
return this;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
NDElement.prototype.transition = function (transitionName) {
|
|
70
|
+
this.transitionIn(transitionName);
|
|
71
|
+
this.transitionOut(transitionName);
|
|
72
|
+
return this;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
NDElement.prototype.animate = function(animationName) {
|
|
76
|
+
this.$element.classes.add(animationName);
|
|
77
|
+
|
|
78
|
+
waitForVisualEnd(this.$element).then(() => {
|
|
79
|
+
this.$element.classes.remove(animationName);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return this;
|
|
83
|
+
};
|
package/src/devtools.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Devtools from './devtools';
|
|
2
|
+
import NdViteDevtools from "../devtools/transformers/nd-vite-devtools.js";
|
|
3
|
+
import transformComponentForHrm from "../devtools/transformers/src/transformComponentForHrm.js";
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
transformComponentForHrm,
|
|
7
|
+
NdViteDevtools,
|
|
8
|
+
Devtools,
|
|
9
|
+
};
|
package/src/fetch/NativeFetch.js
CHANGED
|
@@ -36,11 +36,14 @@ export default function NativeFetch($baseUrl) {
|
|
|
36
36
|
configs.body = params;
|
|
37
37
|
}
|
|
38
38
|
else {
|
|
39
|
-
configs.headers['Content-Type'] = 'application/json';
|
|
40
39
|
if(method !== 'GET') {
|
|
40
|
+
configs.headers['Content-Type'] = 'application/json';
|
|
41
41
|
configs.body = JSON.stringify(params);
|
|
42
42
|
} else {
|
|
43
|
-
|
|
43
|
+
const queryString = new URLSearchParams(params).toString();
|
|
44
|
+
if (queryString) {
|
|
45
|
+
endpoint = endpoint + (endpoint.includes('?') ? '&' : '?') + queryString;
|
|
46
|
+
}
|
|
44
47
|
}
|
|
45
48
|
}
|
|
46
49
|
}
|