jaxs 0.3.2 → 0.4.2
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/dist/jaxs.d.ts +648 -0
- package/dist/jaxs.js +810 -1071
- package/dist/jaxs.umd.cjs +1 -0
- package/package.json +41 -34
- package/.env +0 -1
- package/README.md +0 -15
- package/bun.lockb +0 -0
- package/bundle.ts +0 -5
- package/bunfig.toml +0 -0
- package/cypress/e2e/add-remove-nested-children.cy.js +0 -39
- package/cypress/e2e/add-remove-root-children.cy.js +0 -37
- package/cypress/e2e/svg-renders.cy.js +0 -10
- package/cypress/jaxs-apps/add-remove-nested-children.html +0 -12
- package/cypress/jaxs-apps/add-remove-nested-children.jsx +0 -85
- package/cypress/jaxs-apps/add-remove-root-children.html +0 -15
- package/cypress/jaxs-apps/add-remove-root-children.jsx +0 -54
- package/cypress/jaxs-apps/dist/add-remove-nested-children.afcab974.js +0 -1022
- package/cypress/jaxs-apps/dist/add-remove-nested-children.afcab974.js.map +0 -1
- package/cypress/jaxs-apps/dist/add-remove-nested-children.html +0 -12
- package/cypress/jaxs-apps/dist/add-remove-root-children.3bb9b3f5.js +0 -1665
- package/cypress/jaxs-apps/dist/add-remove-root-children.3bb9b3f5.js.map +0 -1
- package/cypress/jaxs-apps/dist/add-remove-root-children.fbb4ec9b.js +0 -1011
- package/cypress/jaxs-apps/dist/add-remove-root-children.fbb4ec9b.js.map +0 -1
- package/cypress/jaxs-apps/dist/add-remove-root-children.html +0 -15
- package/cypress/jaxs-apps/dist/svg.04290504.js +0 -644
- package/cypress/jaxs-apps/dist/svg.04290504.js.map +0 -1
- package/cypress/jaxs-apps/dist/svg.html +0 -11
- package/cypress/jaxs-apps/svg.html +0 -11
- package/cypress/jaxs-apps/svg.jsx +0 -15
- package/cypress/support/commands.js +0 -25
- package/cypress/support/e2e.js +0 -20
- package/cypress.config.js +0 -10
- package/src/app.ts +0 -84
- package/src/debugging.js +0 -5
- package/src/jaxs.ts +0 -7
- package/src/jsx.js +0 -27
- package/src/messageBus.ts +0 -70
- package/src/navigation/findHref.js +0 -10
- package/src/navigation/routeState.js +0 -15
- package/src/navigation/setupHistory.js +0 -38
- package/src/navigation/setupNavigation.js +0 -25
- package/src/navigation.ts +0 -2
- package/src/rendering/change/compile.ts +0 -1
- package/src/rendering/change/instructions/attributes.ts +0 -81
- package/src/rendering/change/instructions/children.ts +0 -127
- package/src/rendering/change/instructions/element.ts +0 -49
- package/src/rendering/change/instructions/events.ts +0 -51
- package/src/rendering/change/instructions/generate.ts +0 -122
- package/src/rendering/change/instructions/idMap.js +0 -55
- package/src/rendering/change/instructions/node.ts +0 -55
- package/src/rendering/change/instructions/text.ts +0 -10
- package/src/rendering/change.ts +0 -139
- package/src/rendering/dom/attributesAndEvents.ts +0 -33
- package/src/rendering/dom/create.ts +0 -66
- package/src/rendering/dom/svg.ts +0 -18
- package/src/rendering/templates/bound.js +0 -56
- package/src/rendering/templates/children.ts +0 -99
- package/src/rendering/templates/root.ts +0 -55
- package/src/rendering/templates/tag.ts +0 -92
- package/src/rendering/templates/text.ts +0 -17
- package/src/state/equality.js +0 -36
- package/src/state/stores.js +0 -63
- package/src/state/testingTypes.js +0 -6
- package/src/state.js +0 -89
- package/src/types.ts +0 -160
- package/src/views/conditionals.jsx +0 -18
- package/src/views/link.jsx +0 -5
- package/src/views.js +0 -7
- package/tsconfig.json +0 -26
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Dom,
|
|
3
|
-
ExpandedElement,
|
|
4
|
-
HtmlChildren,
|
|
5
|
-
Instruction,
|
|
6
|
-
Instructions,
|
|
7
|
-
} from '../../../types';
|
|
8
|
-
import { insertNode, removeNode, replaceNode } from './generate';
|
|
9
|
-
import { createIdMap } from './idMap';
|
|
10
|
-
import { compileForNodeGenerator } from './node';
|
|
11
|
-
|
|
12
|
-
type DiffPair = {
|
|
13
|
-
source: Dom;
|
|
14
|
-
target: Dom;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export const compileChildren = (
|
|
18
|
-
sourceList: HtmlChildren,
|
|
19
|
-
targetList: HtmlChildren,
|
|
20
|
-
parent: ExpandedElement,
|
|
21
|
-
) => {
|
|
22
|
-
const baseInstructions = [] as Instructions;
|
|
23
|
-
const length = largerLength(sourceList, targetList);
|
|
24
|
-
const sourceMap = createIdMap(sourceList);
|
|
25
|
-
const targetMap = createIdMap(targetList);
|
|
26
|
-
const nodesPairsToDiff = [] as DiffPair[];
|
|
27
|
-
|
|
28
|
-
let index = 0;
|
|
29
|
-
for (; index < length; index++) {
|
|
30
|
-
const source = sourceList[index] as ExpandedElement;
|
|
31
|
-
const target = targetList[index] as ExpandedElement;
|
|
32
|
-
// debug(
|
|
33
|
-
// '\n',
|
|
34
|
-
// 'loop index',
|
|
35
|
-
// index,
|
|
36
|
-
// source && source.__jsx,
|
|
37
|
-
// target && target.__jsx,
|
|
38
|
-
// );
|
|
39
|
-
|
|
40
|
-
// This algorithm uses the target as the source of truth, iterating
|
|
41
|
-
// through it first figuring out what to do. The length could be larger than
|
|
42
|
-
// the target length, which means that there are unresolved sources to remove.
|
|
43
|
-
// Part of the goal of this flow is to ensure that insertions happen in
|
|
44
|
-
// accending order.
|
|
45
|
-
if (target && targetMap.check(target)) {
|
|
46
|
-
// debug('target', target.__jsx, 'index', index);
|
|
47
|
-
const matchingSource = sourceMap.pullMatch(target);
|
|
48
|
-
targetMap.clear(target); // mark target as resolved
|
|
49
|
-
|
|
50
|
-
if (matchingSource.element) {
|
|
51
|
-
// debug('matching source found for target');
|
|
52
|
-
if (matchingSource.index !== index) {
|
|
53
|
-
// move source to index
|
|
54
|
-
// debug('moving source', matchingSource.element.__jsx, index);
|
|
55
|
-
baseInstructions.push(
|
|
56
|
-
insertNode(matchingSource.element, { parent, index }),
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
// update element for attribute, event and child changes
|
|
60
|
-
// debug('updating to match target',
|
|
61
|
-
// matchingSource.element.__jsx,
|
|
62
|
-
// matchingSource.element.classList,
|
|
63
|
-
// target.__jsx,
|
|
64
|
-
// target.classList
|
|
65
|
-
// );
|
|
66
|
-
nodesPairsToDiff.push({
|
|
67
|
-
source: matchingSource.element,
|
|
68
|
-
target,
|
|
69
|
-
});
|
|
70
|
-
} else if (source) {
|
|
71
|
-
// debug('NO matching source for target but source in slot', source.__jsx);
|
|
72
|
-
|
|
73
|
-
if (targetMap.check(source)) {
|
|
74
|
-
// the source is somewhere else in the target, so just add this
|
|
75
|
-
// target element and assume the source will get resolved later.
|
|
76
|
-
// debug('adding', target.__jsx, 'at', index);
|
|
77
|
-
baseInstructions.push(insertNode(target, { parent, index }));
|
|
78
|
-
} else {
|
|
79
|
-
// no matching target, but something is in the index/slot ... so swap
|
|
80
|
-
// debug('replacing', source.__jsx, target.__jsx, 'at', index);
|
|
81
|
-
sourceMap.clear(source); // resolve source
|
|
82
|
-
baseInstructions.push(replaceNode(source as Dom, target as Dom));
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
// extra targets, add these to the end of the parent in order received
|
|
86
|
-
// debug('adding target to end', target.__jsx);
|
|
87
|
-
baseInstructions.push(insertNode(target, { parent, index }));
|
|
88
|
-
}
|
|
89
|
-
} else if (source) {
|
|
90
|
-
// stuff has been remove from the target
|
|
91
|
-
// check to see if source has been resolved in map
|
|
92
|
-
// if not remove from dom
|
|
93
|
-
const matchingSource = sourceMap.pullMatch(source);
|
|
94
|
-
if (matchingSource.element) {
|
|
95
|
-
// debug('removing', source.__jsx);
|
|
96
|
-
baseInstructions.push(removeNode(source));
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// deal with unresolved sources
|
|
102
|
-
sourceMap.remaining().forEach(({ element }) => {
|
|
103
|
-
// debug('removing', element.__jsx);
|
|
104
|
-
baseInstructions.push(removeNode(element));
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
const nodeInstructions = nodesPairsToDiff
|
|
108
|
-
.reduce((collection, { source, target }) => {
|
|
109
|
-
return collection.concat(compileForNode(source, target));
|
|
110
|
-
}, [] as Instructions);
|
|
111
|
-
|
|
112
|
-
return baseInstructions.concat(nodeInstructions).sort(instructionsSorter);
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
const instructionsSorter = (left: Instruction, right: Instruction) => {
|
|
116
|
-
if (left.type > right.type) return 1;
|
|
117
|
-
if (left.type < right.type) return -1;
|
|
118
|
-
return 0;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const largerLength = (sourceList: HtmlChildren, targetList: HtmlChildren) => {
|
|
122
|
-
const sourceLength = Array.from(sourceList).length;
|
|
123
|
-
const targetLength = Array.from(targetList).length;
|
|
124
|
-
return sourceLength > targetLength ? sourceLength : targetLength;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const compileForNode = compileForNodeGenerator(compileChildren);
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import type { ExpandedElement, InputElement, Instructions } from '../../../types';
|
|
2
|
-
import { changeValue } from './generate';
|
|
3
|
-
import { compileForAttributes } from './attributes';
|
|
4
|
-
import { compileForEvents } from './events';
|
|
5
|
-
|
|
6
|
-
export const compileForElement = (
|
|
7
|
-
source: ExpandedElement,
|
|
8
|
-
target: ExpandedElement,
|
|
9
|
-
) => {
|
|
10
|
-
const attributeInstructions = compileForAttributes(source, target);
|
|
11
|
-
const eventInstructions = compileForEvents(source, target);
|
|
12
|
-
const valueInstructions = compileForInputValue(source, target);
|
|
13
|
-
|
|
14
|
-
return attributeInstructions
|
|
15
|
-
.concat(eventInstructions)
|
|
16
|
-
.concat(valueInstructions);
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const compileForSvg = (
|
|
20
|
-
source: ExpandedElement,
|
|
21
|
-
target: ExpandedElement,
|
|
22
|
-
) => {
|
|
23
|
-
return compileForAttributes(source, target, true);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const compileForInputValue = (
|
|
27
|
-
sourceElement: ExpandedElement,
|
|
28
|
-
targetElement: ExpandedElement,
|
|
29
|
-
) => {
|
|
30
|
-
const instructions = [] as Instructions;
|
|
31
|
-
if (sourceElement.tagName !== 'INPUT') {
|
|
32
|
-
return instructions;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const source = sourceElement as InputElement;
|
|
36
|
-
const target = targetElement as InputElement;
|
|
37
|
-
|
|
38
|
-
if (source.value !== target.value) {
|
|
39
|
-
instructions.push(
|
|
40
|
-
changeValue(
|
|
41
|
-
source,
|
|
42
|
-
target,
|
|
43
|
-
{ name: 'value', value: target.value },
|
|
44
|
-
),
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return instructions;
|
|
49
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { ExpandedElement, Instructions } from '../../../types';
|
|
2
|
-
import { addEvent, removeEvent, updateEvent } from './generate';
|
|
3
|
-
|
|
4
|
-
export const compileForEvents = (
|
|
5
|
-
source: ExpandedElement,
|
|
6
|
-
target: ExpandedElement,
|
|
7
|
-
) => {
|
|
8
|
-
const instructions = [] as Instructions;
|
|
9
|
-
const sourceEventMaps = source.eventMaps;
|
|
10
|
-
const targetEventMaps = target.eventMaps;
|
|
11
|
-
const sourceDomEvents = Object.keys(sourceEventMaps);
|
|
12
|
-
const targetDomEvents = Object.keys(targetEventMaps);
|
|
13
|
-
|
|
14
|
-
sourceDomEvents.forEach((domEvent) => {
|
|
15
|
-
const sourceEventMap = sourceEventMaps[domEvent];
|
|
16
|
-
const targetEventMap = targetEventMaps[domEvent];
|
|
17
|
-
|
|
18
|
-
if (!targetEventMap) {
|
|
19
|
-
instructions.push(
|
|
20
|
-
removeEvent(source, target, {
|
|
21
|
-
name: sourceEventMap.domEvent,
|
|
22
|
-
value: sourceEventMap.listener,
|
|
23
|
-
}),
|
|
24
|
-
);
|
|
25
|
-
} else if (targetEventMap.busEvent !== sourceEventMap.busEvent) {
|
|
26
|
-
instructions.push(
|
|
27
|
-
updateEvent(source, target, {
|
|
28
|
-
name: domEvent,
|
|
29
|
-
targetValue: targetEventMap.listener,
|
|
30
|
-
sourceValue: sourceEventMap.listener,
|
|
31
|
-
}),
|
|
32
|
-
);
|
|
33
|
-
} // else events the same
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
targetDomEvents.forEach((domEvent) => {
|
|
37
|
-
const sourceEventMap = sourceEventMaps[domEvent];
|
|
38
|
-
const targetEventMap = targetEventMaps[domEvent];
|
|
39
|
-
|
|
40
|
-
if (!sourceEventMap) {
|
|
41
|
-
instructions.push(
|
|
42
|
-
addEvent(source, target, {
|
|
43
|
-
name: targetEventMap.domEvent,
|
|
44
|
-
value: targetEventMap.listener,
|
|
45
|
-
}),
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
return instructions;
|
|
51
|
-
};
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AttributeInstructionData,
|
|
3
|
-
Dom,
|
|
4
|
-
EventInstructionData,
|
|
5
|
-
ExpandedElement,
|
|
6
|
-
InputElement,
|
|
7
|
-
InsertNodeData,
|
|
8
|
-
Instruction,
|
|
9
|
-
RemoveInstructionData,
|
|
10
|
-
UpdateEventInstructionData,
|
|
11
|
-
} from '../../../types';
|
|
12
|
-
import { ChangeInstructions } from '../../../types'
|
|
13
|
-
|
|
14
|
-
export const changeText = (source: Text, target: Text): Instruction => ({
|
|
15
|
-
source,
|
|
16
|
-
target,
|
|
17
|
-
type: ChangeInstructions.changeText,
|
|
18
|
-
data: {},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
export const replaceNode = (source: Dom, target: Dom): Instruction => ({
|
|
22
|
-
source,
|
|
23
|
-
target,
|
|
24
|
-
type: ChangeInstructions.replaceNode,
|
|
25
|
-
data: {},
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
export const removeAttribute = (
|
|
29
|
-
source: ExpandedElement,
|
|
30
|
-
target: ExpandedElement,
|
|
31
|
-
data: RemoveInstructionData,
|
|
32
|
-
): Instruction => ({
|
|
33
|
-
source,
|
|
34
|
-
target,
|
|
35
|
-
data,
|
|
36
|
-
type: ChangeInstructions.removeAttribute,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
export const addAttribute = (
|
|
40
|
-
source: ExpandedElement,
|
|
41
|
-
target: ExpandedElement,
|
|
42
|
-
data: AttributeInstructionData,
|
|
43
|
-
): Instruction => ({
|
|
44
|
-
source,
|
|
45
|
-
target,
|
|
46
|
-
data,
|
|
47
|
-
type: ChangeInstructions.addAttribute,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
export const updateAttribute = (
|
|
51
|
-
source: ExpandedElement,
|
|
52
|
-
target: ExpandedElement,
|
|
53
|
-
data: AttributeInstructionData,
|
|
54
|
-
): Instruction => ({
|
|
55
|
-
source,
|
|
56
|
-
target,
|
|
57
|
-
data,
|
|
58
|
-
type: ChangeInstructions.updateAttribute,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
export const removeEvent = (
|
|
62
|
-
source: ExpandedElement,
|
|
63
|
-
target: ExpandedElement,
|
|
64
|
-
data: EventInstructionData,
|
|
65
|
-
): Instruction => ({
|
|
66
|
-
source,
|
|
67
|
-
target,
|
|
68
|
-
data,
|
|
69
|
-
type: ChangeInstructions.removeEvent,
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
export const addEvent = (
|
|
73
|
-
source: ExpandedElement,
|
|
74
|
-
target: ExpandedElement,
|
|
75
|
-
data: EventInstructionData,
|
|
76
|
-
): Instruction => ({
|
|
77
|
-
source,
|
|
78
|
-
target,
|
|
79
|
-
data,
|
|
80
|
-
type: ChangeInstructions.addEvent,
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
export const updateEvent = (
|
|
84
|
-
source: ExpandedElement,
|
|
85
|
-
target: ExpandedElement,
|
|
86
|
-
data: UpdateEventInstructionData,
|
|
87
|
-
): Instruction => ({
|
|
88
|
-
source,
|
|
89
|
-
target,
|
|
90
|
-
data,
|
|
91
|
-
type: ChangeInstructions.updateEvent,
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
export const removeNode = (
|
|
95
|
-
source: ExpandedElement,
|
|
96
|
-
) => ({
|
|
97
|
-
source,
|
|
98
|
-
target: source, // for type crap only
|
|
99
|
-
type: ChangeInstructions.removeNode,
|
|
100
|
-
data: {},
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
export const insertNode = (
|
|
104
|
-
target: ExpandedElement,
|
|
105
|
-
data: InsertNodeData,
|
|
106
|
-
) => ({
|
|
107
|
-
target,
|
|
108
|
-
source: target, // for type crap only
|
|
109
|
-
type: ChangeInstructions.insertNode,
|
|
110
|
-
data,
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
export const changeValue = (
|
|
114
|
-
source: InputElement,
|
|
115
|
-
target: InputElement,
|
|
116
|
-
data: AttributeInstructionData,
|
|
117
|
-
) => ({
|
|
118
|
-
source,
|
|
119
|
-
target,
|
|
120
|
-
type: ChangeInstructions.changeValue,
|
|
121
|
-
data,
|
|
122
|
-
});
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
const nullMatch = { index: -1 }
|
|
2
|
-
|
|
3
|
-
export class IdMap {
|
|
4
|
-
constructor () {
|
|
5
|
-
this.map = {}
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
populate (list) {
|
|
9
|
-
list.forEach((element, i) => {
|
|
10
|
-
const id = element.__jsx
|
|
11
|
-
if (id) {
|
|
12
|
-
this.map[id] = this.map[id] || []
|
|
13
|
-
this.map[id].push({
|
|
14
|
-
element,
|
|
15
|
-
index: i
|
|
16
|
-
})
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
pullMatch (element) {
|
|
22
|
-
const id = element && element.__jsx
|
|
23
|
-
if (!id) return nullMatch
|
|
24
|
-
if (!(this.map[id] && this.map[id].length)) return nullMatch
|
|
25
|
-
|
|
26
|
-
return this.map[id].shift()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
clear (element) {
|
|
30
|
-
const id = element && element.__jsx
|
|
31
|
-
if (!(id && this.map[id] && this.map[id].length)) return
|
|
32
|
-
|
|
33
|
-
const matches = this.map[id]
|
|
34
|
-
this.map[id] = matches.reduce((collection, possibleMatch) => {
|
|
35
|
-
if (possibleMatch.element !== element) collection.push(possibleMatch)
|
|
36
|
-
return collection
|
|
37
|
-
}, [])
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
check (element) {
|
|
41
|
-
const id = element && element.__jsx
|
|
42
|
-
if (!(id && this.map[id])) return false
|
|
43
|
-
return this.map[id].length > 0
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
remaining () {
|
|
47
|
-
return Object.values(this.map).flat()
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export const createIdMap = (list) => {
|
|
52
|
-
const map = new IdMap()
|
|
53
|
-
map.populate(list)
|
|
54
|
-
return map
|
|
55
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { Dom, ExpandedElement, Instructions } from '../../../types';
|
|
2
|
-
import { compileForElement, compileForSvg } from './element';
|
|
3
|
-
import { compileForText } from './text';
|
|
4
|
-
import { isSvg } from '../../dom/svg'
|
|
5
|
-
|
|
6
|
-
enum NodeTypes {
|
|
7
|
-
ElementNode = 1,
|
|
8
|
-
TextNode = 3,
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export const compileForNodeGenerator =
|
|
12
|
-
(compileForCollection: any) => (source: Dom, target: Dom) => {
|
|
13
|
-
let instructions = [] as Instructions;
|
|
14
|
-
|
|
15
|
-
if (source.nodeType === NodeTypes.ElementNode &&
|
|
16
|
-
isSvg(source as SVGElement)) {
|
|
17
|
-
const sourceElement = source as ExpandedElement;
|
|
18
|
-
const targetElement = target as ExpandedElement;
|
|
19
|
-
const baseInstructions = compileForSvg(
|
|
20
|
-
sourceElement,
|
|
21
|
-
targetElement
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
const childrenInstructions = compileForCollection(
|
|
25
|
-
sourceElement.childNodes,
|
|
26
|
-
targetElement.childNodes,
|
|
27
|
-
sourceElement,
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
instructions = baseInstructions.concat(childrenInstructions);
|
|
31
|
-
} else if (source.nodeType === NodeTypes.ElementNode) {
|
|
32
|
-
const sourceElement = source as ExpandedElement;
|
|
33
|
-
const targetElement = target as ExpandedElement;
|
|
34
|
-
|
|
35
|
-
const baseInstructions = compileForElement(
|
|
36
|
-
sourceElement,
|
|
37
|
-
targetElement,
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const childrenInstructions = compileForCollection(
|
|
41
|
-
sourceElement.childNodes,
|
|
42
|
-
targetElement.childNodes,
|
|
43
|
-
sourceElement,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
instructions = baseInstructions.concat(childrenInstructions);
|
|
47
|
-
} else if (source.nodeType === NodeTypes.TextNode) {
|
|
48
|
-
instructions = compileForText(
|
|
49
|
-
source as Text,
|
|
50
|
-
target as Text,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return instructions;
|
|
55
|
-
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Instructions } from '../../../types';
|
|
2
|
-
import { changeText } from './generate';
|
|
3
|
-
|
|
4
|
-
export const compileForText = (source: Text, target: Text) => {
|
|
5
|
-
if (source.textContent !== target.textContent) {
|
|
6
|
-
return [changeText(source, target)];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
return [] as Instructions;
|
|
10
|
-
};
|
package/src/rendering/change.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AttributeInstructionData,
|
|
3
|
-
EventInstructionData,
|
|
4
|
-
ExpandedElement,
|
|
5
|
-
HtmlChildren,
|
|
6
|
-
InputElement,
|
|
7
|
-
InsertNodeData,
|
|
8
|
-
Instruction,
|
|
9
|
-
RemoveInstructionData,
|
|
10
|
-
UpdateEventInstructionData,
|
|
11
|
-
Updater,
|
|
12
|
-
} from '../types';
|
|
13
|
-
import { ChangeInstructions } from '../types'
|
|
14
|
-
import { compileChange } from './change/compile';
|
|
15
|
-
// import { debug } from '../debugging';
|
|
16
|
-
|
|
17
|
-
export const change = (
|
|
18
|
-
source: HtmlChildren,
|
|
19
|
-
target: HtmlChildren,
|
|
20
|
-
parent: ExpandedElement,
|
|
21
|
-
) => {
|
|
22
|
-
const instructions = compileChange(source, target, parent);
|
|
23
|
-
|
|
24
|
-
// debug('instructions', instructions.map((instruction) => instruction.type))
|
|
25
|
-
|
|
26
|
-
instructions.forEach((instruction) => {
|
|
27
|
-
performInstruction(instruction);
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const performInstruction = (instruction: Instruction) => {
|
|
32
|
-
const performer = performers[instruction.type] || noop;
|
|
33
|
-
performer(instruction);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const noop: Updater = (_instruction: Instruction) => {};
|
|
37
|
-
|
|
38
|
-
const changeText: Updater = (instruction: Instruction) => {
|
|
39
|
-
const { source, target } = instruction;
|
|
40
|
-
source.nodeValue = target.textContent;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const removeNode: Updater = (instruction: Instruction) => {
|
|
44
|
-
const { source } = instruction;
|
|
45
|
-
source.remove();
|
|
46
|
-
// debug('removeNode called on', source.nodeName)
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const insertNode: Updater = (instruction: Instruction) => {
|
|
50
|
-
const { target, data } = instruction;
|
|
51
|
-
const { parent, index } = data as InsertNodeData;
|
|
52
|
-
const sibling = parent.childNodes[index];
|
|
53
|
-
if (!sibling) {
|
|
54
|
-
parent.appendChild(target);
|
|
55
|
-
} else if (sibling && sibling !== target) {
|
|
56
|
-
parent.insertBefore(target, sibling);
|
|
57
|
-
}
|
|
58
|
-
// else case, sibling is target and so it is moving to the same place: no-op.
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const replaceNode: Updater = (instruction: Instruction) => {
|
|
62
|
-
const { source, target } = instruction;
|
|
63
|
-
source.replaceWith(target);
|
|
64
|
-
// debug('replaceNode called on', source.nodeName, 'with', target.nodeName)
|
|
65
|
-
// debug('parent', source.parentElement)
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const removeAttribute: Updater = (instruction: Instruction) => {
|
|
69
|
-
const { source, data } = instruction;
|
|
70
|
-
const { name, isSvg } = data as RemoveInstructionData;
|
|
71
|
-
|
|
72
|
-
if (isSvg) {
|
|
73
|
-
(source as SVGElement).removeAttributeNS(null, name)
|
|
74
|
-
} else {
|
|
75
|
-
(source as ExpandedElement).removeAttribute(name);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const addAttribute: Updater = (instruction: Instruction) => {
|
|
80
|
-
const { source, data } = instruction;
|
|
81
|
-
const { name, value, isSvg } = data as AttributeInstructionData;
|
|
82
|
-
|
|
83
|
-
if (isSvg) {
|
|
84
|
-
(source as SVGElement).setAttributeNS(null, name, value)
|
|
85
|
-
} else {
|
|
86
|
-
(source as ExpandedElement).setAttribute(name, value);
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
const updateAttribute: Updater = (instruction: Instruction) => {
|
|
91
|
-
addAttribute(instruction);
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const removeEvent: Updater = (instruction: Instruction) => {
|
|
95
|
-
const data = instruction.data as EventInstructionData;
|
|
96
|
-
const source = instruction.source as ExpandedElement;
|
|
97
|
-
const { name, value } = data;
|
|
98
|
-
(source as ExpandedElement).removeEventListener(name, value);
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const addEvent: Updater = (instruction: Instruction) => {
|
|
102
|
-
const data = instruction.data as EventInstructionData;
|
|
103
|
-
const source = instruction.source as ExpandedElement;
|
|
104
|
-
const { name, value } = data;
|
|
105
|
-
(source as ExpandedElement).addEventListener(name, value);
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const updateEvent: Updater = (instruction: Instruction) => {
|
|
109
|
-
const data = instruction.data as UpdateEventInstructionData;
|
|
110
|
-
const source = instruction.source as ExpandedElement;
|
|
111
|
-
|
|
112
|
-
const { name, sourceValue, targetValue } = data;
|
|
113
|
-
|
|
114
|
-
source.removeEventListener(name, sourceValue);
|
|
115
|
-
source.addEventListener(name, targetValue);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const changeValue: Updater = (instruction: Instruction) => {
|
|
119
|
-
const data = instruction.data as AttributeInstructionData;
|
|
120
|
-
const source = instruction.source as InputElement;
|
|
121
|
-
|
|
122
|
-
const { value } = data;
|
|
123
|
-
|
|
124
|
-
source.value = value;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const performers = {
|
|
128
|
-
[ChangeInstructions.changeText]: changeText,
|
|
129
|
-
[ChangeInstructions.removeNode]: removeNode,
|
|
130
|
-
[ChangeInstructions.insertNode]: insertNode,
|
|
131
|
-
[ChangeInstructions.replaceNode]: replaceNode,
|
|
132
|
-
[ChangeInstructions.removeAttribute]: removeAttribute,
|
|
133
|
-
[ChangeInstructions.addAttribute]: addAttribute,
|
|
134
|
-
[ChangeInstructions.updateAttribute]: updateAttribute,
|
|
135
|
-
[ChangeInstructions.removeEvent]: removeEvent,
|
|
136
|
-
[ChangeInstructions.addEvent]: addEvent,
|
|
137
|
-
[ChangeInstructions.updateEvent]: updateEvent,
|
|
138
|
-
[ChangeInstructions.changeValue]: changeValue,
|
|
139
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { Attributes, AttributesAndEvents } from '../../types';
|
|
2
|
-
|
|
3
|
-
export const separateAttrsAndEvents = (
|
|
4
|
-
combined: Attributes,
|
|
5
|
-
defaultValue = '',
|
|
6
|
-
): AttributesAndEvents => {
|
|
7
|
-
const attributes: Attributes = {};
|
|
8
|
-
const events: Attributes = {};
|
|
9
|
-
|
|
10
|
-
for (const key in combined) {
|
|
11
|
-
const value = combined[key];
|
|
12
|
-
if (key.match(/^on.+/i)) {
|
|
13
|
-
const eventKey = key.slice(2).toLowerCase();
|
|
14
|
-
events[eventKey] = value;
|
|
15
|
-
} else {
|
|
16
|
-
attributes[key] = normalizeValueForKey(combined, key, defaultValue);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return {
|
|
21
|
-
attributes,
|
|
22
|
-
events,
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const normalizeValueForKey = (
|
|
27
|
-
object: Attributes,
|
|
28
|
-
key: string,
|
|
29
|
-
defaultValue = '',
|
|
30
|
-
) => {
|
|
31
|
-
if (object[key] === undefined) return defaultValue;
|
|
32
|
-
return object[key];
|
|
33
|
-
};
|