native-document 1.0.168 → 1.0.172
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/CHANGELOG.md +99 -4
- package/components.js +3 -1
- package/dist/native-document.components.min.js +197 -171
- package/dist/native-document.dev.js +92 -75
- package/dist/native-document.dev.js.map +1 -1
- package/dist/native-document.min.js +1 -1
- package/docs/components/icons.md +321 -0
- package/docs/vitepress-conventions.md +2 -2
- package/package.json +11 -4
- package/src/components/BaseComponent.js +43 -1
- package/src/components/accordion/Accordion.js +1 -0
- package/src/components/accordion/AccordionItem.js +1 -0
- package/src/components/alert/Alert.js +4 -0
- package/src/components/avatar/Avatar.js +1 -0
- package/src/components/avatar/AvatarGroup.js +1 -0
- package/src/components/badge/Badge.js +1 -0
- package/src/components/breadcrumb/BreadCrumb.js +4 -0
- package/src/components/button/Button.js +1 -0
- package/src/components/card/Card.js +1 -0
- package/src/components/context-menu/ContextMenu.js +2 -0
- package/src/components/context-menu/ContextMenuGroup.js +2 -0
- package/src/components/context-menu/ContextMenuItem.js +2 -0
- package/src/components/divider/Divider.js +2 -0
- package/src/components/dropdown/Dropdown.js +1 -0
- package/src/components/dropdown/DropdownDivider.js +1 -0
- package/src/components/dropdown/DropdownGroup.js +1 -0
- package/src/components/dropdown/DropdownItem.js +1 -0
- package/src/components/dropdown/DropdownTrigger.js +1 -0
- package/src/components/form/FormControl.js +1 -0
- package/src/components/form/field/Field.js +1 -0
- package/src/components/form/field/types/FileField.js +3 -3
- package/src/components/form/field/types/StringField.js +1 -1
- package/src/components/icon/Icon.js +108 -0
- package/src/components/icon/icon-getters.js +142 -0
- package/src/components/icon/icons.js +171 -0
- package/src/components/icon/index.js +17 -0
- package/src/components/icon/types/Icon.d.ts +191 -0
- package/src/components/index.d.ts +6 -1
- package/src/components/list/ListItem.js +1 -0
- package/src/components/list/types/List.d.ts +45 -32
- package/src/components/list/types/ListDivider.ts +16 -0
- package/src/components/list/types/ListGroup.d.ts +51 -29
- package/src/components/list/types/ListItem.d.ts +20 -21
- package/src/components/menu/Menu.js +3 -0
- package/src/components/menu/MenuDivider.js +1 -0
- package/src/components/menu/MenuGroup.js +1 -0
- package/src/components/menu/MenuItem.js +1 -0
- package/src/components/menu/MenuLink.js +1 -0
- package/src/components/modal/Modal.js +4 -0
- package/src/components/pagination/Pagination.js +1 -0
- package/src/components/popover/Popover.js +1 -0
- package/src/components/popover/PopoverFooter.js +1 -0
- package/src/components/popover/PopoverHeader.js +1 -0
- package/src/components/progress/Progress.js +5 -0
- package/src/components/skeleton/Skeleton.js +4 -0
- package/src/components/slider/Slider.js +1 -0
- package/src/components/spacer/Spacer.js +1 -0
- package/src/components/spinner/Spinner.js +1 -0
- package/src/components/splitter/Splitter.js +1 -0
- package/src/components/splitter/SplitterGutter.js +6 -0
- package/src/components/splitter/SplitterPanel.js +1 -0
- package/src/components/stacks/AbsoluteStack.js +1 -0
- package/src/components/stacks/FixedStack.js +1 -0
- package/src/components/stacks/HStack.js +1 -0
- package/src/components/stacks/PositionStack.js +1 -0
- package/src/components/stacks/RelativeStack.js +1 -0
- package/src/components/stacks/Stack.js +1 -0
- package/src/components/stacks/VStack.js +1 -0
- package/src/components/stepper/Stepper.js +1 -0
- package/src/components/stepper/StepperStep.js +1 -0
- package/src/components/switch/Switch.js +1 -0
- package/src/components/table/DataTable.js +1 -0
- package/src/components/table/SimpleTable.js +1 -0
- package/src/components/tabs/Tabs.js +1 -0
- package/src/components/toast/Toast.js +1 -0
- package/src/components/tooltip/Tooltip.js +1 -0
- package/src/core/data/MemoryManager.js +6 -1
- package/src/core/data/ObservableItem.js +28 -10
- package/src/core/elements/anchor/anchor.js +4 -3
- package/src/core/elements/anchor/one-child-anchor-overwriting.js +4 -4
- package/src/core/elements/content-formatter.js +35 -2
- package/src/core/elements/control/for-each-array-cache.js +59 -0
- package/src/core/elements/control/for-each-array.js +15 -23
- package/src/core/elements/form.js +1 -1
- package/src/core/elements/img.js +1 -1
- package/src/core/elements/medias.js +2 -2
- package/src/core/elements/meta-data.js +1 -1
- package/src/core/wrappers/AttributesWrapper.js +44 -29
- package/src/core/wrappers/ElementCreator.js +38 -22
- package/src/core/wrappers/HtmlElementWrapper.js +33 -9
- package/src/core/wrappers/NDElement.js +35 -9
- package/src/core/wrappers/NdPrototype.js +31 -39
- package/src/core/wrappers/constants.js +12 -12
- package/src/core/wrappers/prototypes/attributes-extensions.js +24 -24
- package/src/core/wrappers/prototypes/nd-element-extensions.js +128 -65
- package/src/ui/components/accordion/AccordionItemRender.js +29 -7
- package/src/ui/components/alert/AlertRender.js +6 -0
- package/src/ui/components/breadcrumb/BreadcrumbRender.js +9 -1
- package/src/ui/components/button/ButtonRender.js +3 -0
- package/src/ui/components/contextmenu/ContextmenuRender.js +2 -0
- package/src/ui/components/dropdown/DropdownRender.js +3 -0
- package/src/ui/components/dropdown/item/DropdownItemRender.js +6 -1
- package/src/ui/components/form/FieldCollectionRender.js +4 -0
- package/src/ui/components/form/fields/CheckboxFieldRender.js +4 -0
- package/src/ui/components/form/fields/CheckboxGroupFieldRender.js +4 -0
- package/src/ui/components/form/fields/RadioFieldRender.js +4 -0
- package/src/ui/components/form/fields/RangeFieldRender.js +4 -0
- package/src/ui/components/form/fields/SelectFieldRender.js +5 -0
- package/src/ui/components/form/fields/SliderFieldRender.js +3 -0
- package/src/ui/components/icon/material/MaterialIconRender.js +71 -0
- package/src/ui/components/icon/material/material.css +15 -0
- package/src/ui/components/icon/material/material.map.js +170 -0
- package/src/ui/components/icon/phosphor/PhosphorIconRender.js +71 -0
- package/src/ui/components/icon/phosphor/phosphor.css +17 -0
- package/src/ui/components/icon/phosphor/phosphor.map.js +165 -0
- package/src/ui/components/icon/tabler/TablerIconRender.js +58 -0
- package/src/ui/components/icon/tabler/tabler.css +14 -0
- package/src/ui/components/icon/tabler/tabler.map.js +165 -0
- package/src/ui/components/list/item/ListItemRender.js +4 -0
- package/src/ui/components/menu/MenuItemRender.js +8 -0
- package/src/ui/components/menu/MenuLinkRender.js +11 -0
- package/src/ui/components/menu/MenuRender.js +5 -0
- package/src/ui/components/menu/helpers.js +2 -1
- package/src/ui/components/modal/ModalRender.js +8 -2
- package/src/ui/components/progress/ProgressRender.js +9 -0
- package/src/ui/components/skeleton/SkeletonRender.js +2 -0
- package/src/ui/components/spinner/SpinnerRender.js +3 -0
- package/src/ui/components/splitter/SplitterGutterRender.js +4 -0
- package/src/ui/components/splitter/SplitterPanelRender.js +4 -0
- package/src/ui/components/splitter/SplitterRender.js +2 -0
- package/src/ui/components/stepper/StepperRender.js +2 -1
- package/src/ui/components/stepper/StepperStepRender.js +8 -1
- package/src/ui/components/switch/SwitchRender.js +3 -0
- package/src/ui/components/table/data-table/DataTableRender.js +4 -0
- package/src/ui/components/table/simple-table/SimpleTableRender.js +2 -0
- package/src/ui/components/toast/ToastRender.js +4 -0
- package/src/ui/index.js +5 -0
- package/src/ui/utils/aria.js +19 -0
- package/tests/integration/ui/attributes-wrapper.test.js +177 -0
- package/tests/integration/ui/for-each-array.test.js +167 -0
- package/tests/integration/ui/lifecycle.test.js +146 -0
- package/tests/integration/ui/show-if.test.js +168 -0
- package/tests/unit/core/observable-array.test.js +404 -0
- package/tests/unit/core/observable-item.test.js +428 -0
- package/tests/unit/core/observable-object.test.js +239 -0
- package/tests/unit/core/observable-resource.test.js +323 -0
- package/tests/unit/core/store.test.js +347 -0
- package/tests/unit/router/route-matching.test.js +169 -0
- package/tests/unit/router/router-guards.test.js +189 -0
- package/tests/unit/utils/cache.test.js +120 -0
- package/tests/unit/utils/filters.test.js +394 -0
- package/types/elements.d.ts +5 -0
- package/vitest.config.js +15 -0
|
@@ -124,6 +124,9 @@ ObservableItem.prototype.triggerListeners = function(operations) {
|
|
|
124
124
|
* @param {{ action?: string, args?: any[], result?: any }} [operations] - Mutation metadata
|
|
125
125
|
*/
|
|
126
126
|
ObservableItem.prototype.triggerWatchers = function(operations) {
|
|
127
|
+
if(!this.$watchers) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
127
130
|
const $watchers = this.$watchers;
|
|
128
131
|
const $previousValue = this.$previousValue;
|
|
129
132
|
const $currentValue = this.$currentValue;
|
|
@@ -160,6 +163,7 @@ ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations)
|
|
|
160
163
|
this.triggerFirstListener(operations);
|
|
161
164
|
};
|
|
162
165
|
|
|
166
|
+
|
|
163
167
|
/**
|
|
164
168
|
* Selects and assigns the optimal trigger strategy based on the current
|
|
165
169
|
* combination of listeners and watchers (internal).
|
|
@@ -167,31 +171,40 @@ ObservableItem.prototype.triggerWatchersAndFirstListener = function(operations)
|
|
|
167
171
|
*
|
|
168
172
|
* @internal
|
|
169
173
|
*/
|
|
170
|
-
ObservableItem.prototype
|
|
174
|
+
ObservableItem.prototype.$runAssocTrigger = function() {
|
|
171
175
|
this.$firstListener = null;
|
|
172
176
|
if(this.$watchers?.size && this.$listeners?.length) {
|
|
173
|
-
this.$
|
|
174
|
-
this.trigger = this.$firstListener.length === 0 ? this.$firstListener : this.triggerFirstListener;
|
|
175
|
-
this.trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
|
|
177
|
+
this.$trigger = (this.$listeners.length === 1) ? this.triggerWatchersAndFirstListener : this.triggerAll;
|
|
176
178
|
return;
|
|
177
179
|
}
|
|
178
180
|
if(this.$listeners?.length) {
|
|
179
181
|
if(this.$listeners.length === 1) {
|
|
180
182
|
this.$firstListener = this.$listeners[0];
|
|
181
|
-
this
|
|
183
|
+
this.$trigger = this.$firstListener.length === 0 ? this.$firstListener : this.triggerFirstListener;
|
|
182
184
|
}
|
|
183
185
|
else {
|
|
184
|
-
this
|
|
186
|
+
this.$trigger = this.triggerListeners;
|
|
185
187
|
}
|
|
186
188
|
return;
|
|
187
189
|
}
|
|
188
190
|
if(this.$watchers?.size) {
|
|
189
|
-
this
|
|
191
|
+
this.$trigger = this.triggerWatchers;
|
|
190
192
|
return;
|
|
191
193
|
}
|
|
192
|
-
this
|
|
194
|
+
this.$trigger = noneTrigger;
|
|
193
195
|
};
|
|
194
|
-
ObservableItem.prototype.
|
|
196
|
+
ObservableItem.prototype.assocTrigger = function() {
|
|
197
|
+
this.$trigger = null;
|
|
198
|
+
};
|
|
199
|
+
Object.defineProperty(ObservableItem.prototype, 'trigger', {
|
|
200
|
+
value: function (operations) {
|
|
201
|
+
if(!this.$trigger) {
|
|
202
|
+
this.$runAssocTrigger();
|
|
203
|
+
}
|
|
204
|
+
return this.$trigger(operations);
|
|
205
|
+
},
|
|
206
|
+
configurable: false,
|
|
207
|
+
});
|
|
195
208
|
|
|
196
209
|
|
|
197
210
|
const $setOperation = { action: 'set' };
|
|
@@ -543,7 +556,12 @@ ObservableItem.prototype.reset = function() {
|
|
|
543
556
|
* @returns {string} String representation of the current value
|
|
544
557
|
*/
|
|
545
558
|
ObservableItem.prototype.toString = function() {
|
|
546
|
-
|
|
559
|
+
if(this.$id) {
|
|
560
|
+
return this.$id.toString();
|
|
561
|
+
}
|
|
562
|
+
const id = MemoryManager.register(this);
|
|
563
|
+
this.$id = id;
|
|
564
|
+
return '{{obs:'+id+'}}';
|
|
547
565
|
};
|
|
548
566
|
|
|
549
567
|
/**
|
|
@@ -2,6 +2,7 @@ import Validator from '../../utils/validator';
|
|
|
2
2
|
import {ElementCreator} from '../../wrappers/ElementCreator';
|
|
3
3
|
import AnchorWithSentinel from './anchor-with-sentinel';
|
|
4
4
|
import oneChildAnchorOverwriting from './one-child-anchor-overwriting';
|
|
5
|
+
import DebugManager from '../../utils/debug-manager';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Creates an anchor fragment — a managed DocumentFragment delimited by comment sentinels.
|
|
@@ -34,7 +35,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
34
35
|
? () => true: (parent) => (parent.firstChild === anchorStart && parent.lastChild === anchorEnd);
|
|
35
36
|
|
|
36
37
|
const insertBefore = (parent, child, target) => {
|
|
37
|
-
const childElement =
|
|
38
|
+
const childElement = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
38
39
|
insertBeforeRaw(parent, childElement, target);
|
|
39
40
|
};
|
|
40
41
|
|
|
@@ -84,7 +85,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
84
85
|
anchorFragment.appendRaw = anchorFragment.appendChildRaw;
|
|
85
86
|
|
|
86
87
|
anchorFragment.insertAtStart = function(child) {
|
|
87
|
-
child =
|
|
88
|
+
child = child.__$isNativeNode? child : ElementCreator.getChild(child);
|
|
88
89
|
anchorFragment.insertAtStartRaw(child);
|
|
89
90
|
};
|
|
90
91
|
|
|
@@ -141,7 +142,7 @@ export default function Anchor(name, isUniqueChild = false) {
|
|
|
141
142
|
anchorFragment.delete = anchorFragment.removeWithAnchors;
|
|
142
143
|
|
|
143
144
|
anchorFragment.replaceContent = function(child) {
|
|
144
|
-
const childElement =
|
|
145
|
+
const childElement = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
145
146
|
anchorFragment.replaceContentRaw(childElement);
|
|
146
147
|
};
|
|
147
148
|
|
|
@@ -10,7 +10,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
10
10
|
anchor.getParent = () => parent;
|
|
11
11
|
|
|
12
12
|
anchor.appendChild = (child) => {
|
|
13
|
-
child =
|
|
13
|
+
child = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
14
14
|
parent.appendChild(child);
|
|
15
15
|
};
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
19
19
|
anchor.appendRaw = anchor.appendChildRaw;
|
|
20
20
|
|
|
21
21
|
anchor.insertAtStart = (child) => {
|
|
22
|
-
child =
|
|
22
|
+
child = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
23
23
|
parent.firstChild ? parent.insertBefore(child, parent.firstChild) : parent.appendChild(child);
|
|
24
24
|
};
|
|
25
25
|
anchor.insertAtStartRaw = (child) => {
|
|
@@ -33,7 +33,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
anchor.replaceContent = function(content) {
|
|
36
|
-
const child =
|
|
36
|
+
const child = (content && content.__$isNativeNode) ? content : ElementCreator.getChild(content);
|
|
37
37
|
parent.replaceChildren(child);
|
|
38
38
|
};
|
|
39
39
|
|
|
@@ -43,7 +43,7 @@ export default function oneChildAnchorOverwriting(anchor, parent) {
|
|
|
43
43
|
anchor.setContent = anchor.replaceContent;
|
|
44
44
|
|
|
45
45
|
anchor.insertBefore = (child, anchor) => {
|
|
46
|
-
child =
|
|
46
|
+
child = child.__$isNativeNode ? child : ElementCreator.getChild(child);
|
|
47
47
|
parent.insertBefore(child, anchor);
|
|
48
48
|
};
|
|
49
49
|
anchor.insertBeforeRaw = (child, anchor) => {
|
|
@@ -24,18 +24,51 @@ export const Label = HtmlElementWrapper('label');
|
|
|
24
24
|
*/
|
|
25
25
|
export const P = HtmlElementWrapper('p');
|
|
26
26
|
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Parses a string containing Observable placeholders and returns an array
|
|
30
|
+
* of strings and Observable instances ready to be used as NativeDocument children.
|
|
31
|
+
*
|
|
32
|
+
* Observable placeholders are generated automatically when an ObservableItem
|
|
33
|
+
* is interpolated in a template string via its toString() method.
|
|
34
|
+
*
|
|
35
|
+
* @param {string} string - Template string with optional Observable placeholders
|
|
36
|
+
* @returns {Array<string|ObservableItem>} Mixed array of static strings and resolved Observables
|
|
37
|
+
* @example
|
|
38
|
+
* const name = Observable('John');
|
|
39
|
+
* const count = Observable(5);
|
|
40
|
+
*
|
|
41
|
+
* Text(`Hello ${name}, count: ${count}`)
|
|
42
|
+
* // → ['Hello ', ObservableItem(John), ', count: ', ObservableItem(5)]
|
|
43
|
+
*/
|
|
44
|
+
export const Text = (string) => string.toNdChildren();
|
|
45
|
+
|
|
27
46
|
/**
|
|
28
47
|
* Alias for {@link P}.
|
|
29
48
|
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLParagraphElement}
|
|
30
49
|
*/
|
|
31
50
|
export const Paragraph = P;
|
|
32
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Creates a `<i>` element.
|
|
54
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
55
|
+
*/
|
|
56
|
+
export const I = HtmlElementWrapper('i');
|
|
57
|
+
export const Italic = I;
|
|
58
|
+
|
|
33
59
|
/**
|
|
34
60
|
* Creates a `<strong>` element.
|
|
35
61
|
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
36
62
|
*/
|
|
37
63
|
export const Strong = HtmlElementWrapper('strong');
|
|
38
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Creates a `<strong>` element.
|
|
67
|
+
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLElement}
|
|
68
|
+
*/
|
|
69
|
+
export const B = HtmlElementWrapper('b');
|
|
70
|
+
export const Bold = B;
|
|
71
|
+
|
|
39
72
|
/**
|
|
40
73
|
* Creates a `<h1>` element.
|
|
41
74
|
* @type {function(GlobalAttributes=, NdChild|NdChild[]=): HTMLHeadingElement}
|
|
@@ -76,7 +109,7 @@ export const H6 = HtmlElementWrapper('h6');
|
|
|
76
109
|
* Creates a `<br>` element.
|
|
77
110
|
* @type {function(GlobalAttributes=): HTMLBRElement}
|
|
78
111
|
*/
|
|
79
|
-
export const Br = HtmlElementWrapper('br');
|
|
112
|
+
export const Br = HtmlElementWrapper('br', null, true);
|
|
80
113
|
|
|
81
114
|
/**
|
|
82
115
|
* Creates an `<a>` element.
|
|
@@ -106,7 +139,7 @@ export const Blockquote = HtmlElementWrapper('blockquote');
|
|
|
106
139
|
* Creates an `<hr>` element.
|
|
107
140
|
* @type {function(GlobalAttributes=): HTMLHRElement}
|
|
108
141
|
*/
|
|
109
|
-
export const Hr = HtmlElementWrapper('hr');
|
|
142
|
+
export const Hr = HtmlElementWrapper('hr', null, true);
|
|
110
143
|
|
|
111
144
|
/**
|
|
112
145
|
* Creates an `<em>` element.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
export default function ForEachArrayCache(isIndexesRequired) {
|
|
4
|
+
this.$nodes = new Map();
|
|
5
|
+
this.$indexes = isIndexesRequired ? new Map() : null;
|
|
6
|
+
|
|
7
|
+
this.has = this.$nodes.has.bind(this.$nodes);
|
|
8
|
+
|
|
9
|
+
this.keys = function() {
|
|
10
|
+
return Array.from(this.$nodes.keys());
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
if(isIndexesRequired) {
|
|
14
|
+
this.delete = function(item) {
|
|
15
|
+
this.$nodes.get(item)?.nd.destroy();
|
|
16
|
+
this.$nodes.delete(item);
|
|
17
|
+
this.$indexes.delete(item);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
this.set = function(item, child, index) {
|
|
21
|
+
this.$nodes.set(item, child);
|
|
22
|
+
this.$indexes.set(item, index);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
this.clear = function() {
|
|
26
|
+
for(const [_, node] in this.$nodes.entries()) {
|
|
27
|
+
node.nd.destroy();
|
|
28
|
+
}
|
|
29
|
+
this.$nodes.clear();
|
|
30
|
+
this.$indexes.clear();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
this.get = function(item) {
|
|
34
|
+
return {
|
|
35
|
+
child: this.$nodes.get(item),
|
|
36
|
+
indexObserver: this.$indexes.get(item),
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
} else {
|
|
40
|
+
|
|
41
|
+
this.delete = (item) => {
|
|
42
|
+
this.$nodes.get(item)?.nd.destroy();
|
|
43
|
+
this.$nodes.delete(item);
|
|
44
|
+
};
|
|
45
|
+
this.set = this.$nodes.set.bind(this.$nodes);
|
|
46
|
+
this.clear = function() {
|
|
47
|
+
for(const [_, node] in this.$nodes.entries()) {
|
|
48
|
+
node.nd.destroy();
|
|
49
|
+
}
|
|
50
|
+
this.$nodes.clear();
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.get = function(item) {
|
|
54
|
+
return { child: this.$nodes.get(item), indexObserver: null };
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
}
|
|
59
|
+
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Anchor from '../anchor/anchor';
|
|
2
2
|
import { ElementCreator } from '../../wrappers/ElementCreator';
|
|
3
3
|
import NativeDocumentError from '../../errors/NativeDocumentError';
|
|
4
|
+
import ForEachArrayCache from './for-each-array-cache';
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
const CREATE_AND_CACHE_ACTIONS = new Set(['clear', 'push', 'unshift', 'replace']);
|
|
@@ -30,9 +31,9 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
30
31
|
const element = Anchor('ForEach Array', configs.isParentUniqueChild);
|
|
31
32
|
const blockEnd = element.endElement();
|
|
32
33
|
|
|
33
|
-
const cache = new Map();
|
|
34
34
|
let lastNumberOfItems = 0;
|
|
35
35
|
const isIndexRequired = callback.length >= 2;
|
|
36
|
+
const cache = new ForEachArrayCache(isIndexRequired);
|
|
36
37
|
|
|
37
38
|
const clear = (items) => {
|
|
38
39
|
element.removeChildren();
|
|
@@ -64,7 +65,7 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
64
65
|
throw new NativeDocumentError('ForEachArray child can\'t be null or undefined!');
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
cache.set(item,
|
|
68
|
+
cache.set(item, child);
|
|
68
69
|
return child;
|
|
69
70
|
};
|
|
70
71
|
|
|
@@ -76,7 +77,7 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
76
77
|
throw new NativeDocumentError('ForEachArray child can\'t be null or undefined!');
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
|
-
cache.set(item,
|
|
80
|
+
cache.set(item, child, indexObserver);
|
|
80
81
|
return child;
|
|
81
82
|
};
|
|
82
83
|
if(!data.__$Observable) {
|
|
@@ -87,7 +88,7 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
87
88
|
throw new NativeDocumentError('ForEachArray child can\'t be null or undefined!');
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
|
-
cache.set(item,
|
|
91
|
+
cache.set(item, child);
|
|
91
92
|
return child;
|
|
92
93
|
};
|
|
93
94
|
}
|
|
@@ -150,14 +151,14 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
150
151
|
if(Array.isArray(data)) {
|
|
151
152
|
set = () => {
|
|
152
153
|
clear(data);
|
|
153
|
-
|
|
154
|
+
Actions.appendToElement(data);
|
|
154
155
|
};
|
|
155
156
|
}
|
|
156
157
|
else {
|
|
157
158
|
set = () => {
|
|
158
159
|
const items = data.val();
|
|
159
160
|
clear(items);
|
|
160
|
-
|
|
161
|
+
Actions.appendToElement(items);
|
|
161
162
|
};
|
|
162
163
|
}
|
|
163
164
|
|
|
@@ -166,45 +167,36 @@ export function ForEachArray(data, callback, configs = {}) {
|
|
|
166
167
|
const fragment = document.createDocumentFragment();
|
|
167
168
|
for(let i = 0, length = items.length; i < length; i++) {
|
|
168
169
|
fragment.appendChild(buildItem(items[i], lastNumberOfItems));
|
|
169
|
-
lastNumberOfItems++;
|
|
170
170
|
}
|
|
171
171
|
return fragment;
|
|
172
172
|
},
|
|
173
|
+
appendToElement: (items) => {
|
|
174
|
+
for(let i = 0, length = items.length; i < length; i++) {
|
|
175
|
+
element.appendChild(buildItem(items[i], i));
|
|
176
|
+
}
|
|
177
|
+
},
|
|
173
178
|
add: (items) => {
|
|
174
|
-
|
|
179
|
+
Actions.appendToElement(items);
|
|
175
180
|
},
|
|
176
181
|
replace: (items) => {
|
|
177
182
|
clear(items);
|
|
178
|
-
|
|
183
|
+
Actions.appendToElement(items);
|
|
179
184
|
},
|
|
180
185
|
set,
|
|
181
186
|
reOrder: (items) => {
|
|
182
187
|
let child = null;
|
|
183
|
-
const fragment = document.createDocumentFragment();
|
|
184
188
|
for(const item of items) {
|
|
185
189
|
child = getItemChild(item);
|
|
186
190
|
if(child) {
|
|
187
|
-
|
|
191
|
+
element.appendChild(child);
|
|
188
192
|
}
|
|
189
193
|
}
|
|
190
194
|
child = null;
|
|
191
|
-
element.appendChildRaw(fragment);
|
|
192
195
|
},
|
|
193
196
|
removeOne: (element, index) => {
|
|
194
197
|
removeCacheItem(element, true);
|
|
195
198
|
},
|
|
196
199
|
clear,
|
|
197
|
-
populate: ([target, iteration, callback]) => {
|
|
198
|
-
const fragment = document.createDocumentFragment();
|
|
199
|
-
for (let i = 0; i < iteration; i++) {
|
|
200
|
-
const data = callback(i);
|
|
201
|
-
target.push(data);
|
|
202
|
-
fragment.append(buildItem(data, i));
|
|
203
|
-
lastNumberOfItems++;
|
|
204
|
-
}
|
|
205
|
-
element.appendChildRaw(fragment);
|
|
206
|
-
fragment.replaceChildren();
|
|
207
|
-
},
|
|
208
200
|
unshift: (values) => {
|
|
209
201
|
element.insertAtStartRaw(Actions.toFragment(values));
|
|
210
202
|
},
|
|
@@ -44,7 +44,7 @@ export const Form = HtmlElementWrapper('form', (el) => {
|
|
|
44
44
|
* Creates an `<input>` element.
|
|
45
45
|
* @type {function(InputAttributes=): HTMLInputElement}
|
|
46
46
|
*/
|
|
47
|
-
export const Input = HtmlElementWrapper('input');
|
|
47
|
+
export const Input = HtmlElementWrapper('input', null, true);
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Creates a `<textarea>` element.
|
package/src/core/elements/img.js
CHANGED
|
@@ -6,7 +6,7 @@ import NativeDocumentError from '../errors/NativeDocumentError';
|
|
|
6
6
|
* Creates an `<img>` element.
|
|
7
7
|
* @type {function(ImgAttributes=): HTMLImageElement}
|
|
8
8
|
*/
|
|
9
|
-
export const BaseImage = HtmlElementWrapper('img');
|
|
9
|
+
export const BaseImage = HtmlElementWrapper('img', null, true);
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Creates an `<img>` element.
|
|
@@ -16,13 +16,13 @@ export const Video = HtmlElementWrapper('video');
|
|
|
16
16
|
* Creates a `<source>` element.
|
|
17
17
|
* @type {function(SourceAttributes=): HTMLSourceElement}
|
|
18
18
|
*/
|
|
19
|
-
export const Source = HtmlElementWrapper('source');
|
|
19
|
+
export const Source = HtmlElementWrapper('source', null, true);
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Creates a `<track>` element.
|
|
23
23
|
* @type {function(TrackAttributes=): HTMLTrackElement}
|
|
24
24
|
*/
|
|
25
|
-
export const Track = HtmlElementWrapper('track');
|
|
25
|
+
export const Track = HtmlElementWrapper('track', null, true);
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* Creates a `<canvas>` element.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import Validator from '../utils/validator';
|
|
2
|
-
import NativeDocumentError from '../errors/NativeDocumentError';
|
|
3
2
|
import {BOOL_ATTRIBUTES_NAME, BOOLEAN_ATTRIBUTES} from './constants.js';
|
|
4
3
|
import {Observable} from '../data/Observable';
|
|
5
4
|
|
|
5
|
+
|
|
6
|
+
|
|
6
7
|
/**
|
|
7
8
|
* Applies a reactive class map to an HTMLElement.
|
|
8
9
|
* Each key is a CSS class name; each value is a boolean or ObservableItem<boolean>.
|
|
@@ -14,27 +15,30 @@ import {Observable} from '../data/Observable';
|
|
|
14
15
|
export const bindClassAttribute = (element, data) => {
|
|
15
16
|
for(const className in data) {
|
|
16
17
|
const value = data[className];
|
|
17
|
-
if(value.__$
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
18
|
+
if (value.__$isObservableChecker) {
|
|
19
|
+
let lastClass = value.val();
|
|
20
|
+
if (typeof lastClass === 'string') {
|
|
21
|
+
element.classes.toggle(lastClass, true);
|
|
22
|
+
value.subscribe((currentValue) => {
|
|
23
|
+
element.classes.remove(lastClass);
|
|
24
|
+
element.classes.toggle(currentValue, true);
|
|
25
|
+
lastClass = currentValue;
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
29
28
|
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (value.__$Observable) {
|
|
30
32
|
element.classes.toggle(className, value.val());
|
|
31
33
|
value.subscribe((shouldAdd) => element.classes.toggle(className, shouldAdd));
|
|
32
|
-
|
|
34
|
+
return;
|
|
33
35
|
}
|
|
34
|
-
|
|
36
|
+
|
|
37
|
+
if (value.$hydrate) {
|
|
35
38
|
value.$hydrate(element, className);
|
|
36
|
-
|
|
39
|
+
return;
|
|
37
40
|
}
|
|
41
|
+
|
|
38
42
|
element.classes.toggle(className, value);
|
|
39
43
|
}
|
|
40
44
|
};
|
|
@@ -92,12 +96,12 @@ export const bindStyleAttribute = (element, data) => {
|
|
|
92
96
|
* @param {boolean|number|Observable} value
|
|
93
97
|
*/
|
|
94
98
|
export const bindBooleanAttribute = (element, attributeName, value) => {
|
|
95
|
-
const isObservable = value.__$
|
|
99
|
+
const isObservable = value.__$Observable;
|
|
96
100
|
const defaultValue = isObservable? value.val() : value;
|
|
97
101
|
|
|
98
|
-
const attributeRealName = BOOL_ATTRIBUTES_NAME[attributeName];
|
|
102
|
+
const attributeRealName = BOOL_ATTRIBUTES_NAME[attributeName] || attributeName;
|
|
99
103
|
|
|
100
|
-
if(
|
|
104
|
+
if(typeof defaultValue === 'boolean') {
|
|
101
105
|
element[attributeRealName] = defaultValue;
|
|
102
106
|
}
|
|
103
107
|
else {
|
|
@@ -126,15 +130,14 @@ export const bindBooleanAttribute = (element, attributeName, value) => {
|
|
|
126
130
|
* @param {Observable} value
|
|
127
131
|
*/
|
|
128
132
|
export const bindAttributeWithObservable = (element, attributeName, value) => {
|
|
129
|
-
const applyValue = attributeName === 'value' ? (newValue) => element.value = newValue : (newValue) => element.setAttribute(attributeName, newValue);
|
|
130
|
-
value.subscribe(applyValue);
|
|
131
|
-
|
|
132
133
|
if(attributeName === 'value') {
|
|
133
134
|
element.value = value.val();
|
|
134
135
|
element.addEventListener('input', () => value.set(element.value));
|
|
136
|
+
value.subscribe((newValue) => element.value = newValue);
|
|
135
137
|
return;
|
|
136
138
|
}
|
|
137
139
|
element.setAttribute(attributeName, value.val());
|
|
140
|
+
value.subscribe((newValue) => element.setAttribute(attributeName, newValue));
|
|
138
141
|
};
|
|
139
142
|
|
|
140
143
|
/**
|
|
@@ -142,23 +145,32 @@ export const bindAttributeWithObservable = (element, attributeName, value) => {
|
|
|
142
145
|
* @param {HTMLElement} element
|
|
143
146
|
* @param {Object} attributes
|
|
144
147
|
*/
|
|
145
|
-
const AttributesWrapper = (element, attributes) => {
|
|
148
|
+
const AttributesWrapper = (element, attributes = {}) => {
|
|
146
149
|
|
|
147
150
|
if(process.env.NODE_ENV === 'development') {
|
|
148
151
|
Validator.validateAttributes(attributes);
|
|
149
152
|
}
|
|
150
153
|
|
|
151
|
-
for(const
|
|
152
|
-
const
|
|
153
|
-
const value = attributes[originalAttributeName];
|
|
154
|
+
for(const attributeName in attributes) {
|
|
155
|
+
const value = attributes[attributeName];
|
|
154
156
|
if(value == null) {
|
|
155
157
|
continue;
|
|
156
158
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
+
const type = typeof value;
|
|
160
|
+
if(type === 'string' || type === 'number') {
|
|
161
|
+
element.setAttribute(attributeName, value);
|
|
159
162
|
continue;
|
|
160
163
|
}
|
|
161
|
-
|
|
164
|
+
// const attributeName = originalAttributeName.toLowerCase();
|
|
165
|
+
if(value.__$Observable) {
|
|
166
|
+
if(BOOLEAN_ATTRIBUTES.has(attributeName)) {
|
|
167
|
+
bindBooleanAttribute(element, attributeName, value);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
bindAttributeWithObservable(element, attributeName, value);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if(type === 'object') {
|
|
162
174
|
if(attributeName === 'class') {
|
|
163
175
|
bindClassAttribute(element, value);
|
|
164
176
|
continue;
|
|
@@ -172,6 +184,9 @@ const AttributesWrapper = (element, attributes) => {
|
|
|
172
184
|
bindBooleanAttribute(element, attributeName, value);
|
|
173
185
|
continue;
|
|
174
186
|
}
|
|
187
|
+
if(value.__$isTemplateBinding) {
|
|
188
|
+
value.$hydrate(element, attributeName);
|
|
189
|
+
}
|
|
175
190
|
|
|
176
191
|
element.setAttribute(attributeName, value);
|
|
177
192
|
}
|