jaxs 0.2.0
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/.env +1 -0
- package/.parcel-cache/6f14daf302269614-BundleGraph-0 +0 -0
- package/.parcel-cache/7d3d872b02d671a6-AssetGraph-0 +0 -0
- package/.parcel-cache/8e029bb14f8992df-RequestGraph-0 +0 -0
- package/.parcel-cache/a5394978e4ece10b-AssetGraph-0 +0 -0
- package/.parcel-cache/b5686051ae060930.txt +2 -0
- package/.parcel-cache/data.mdb +0 -0
- package/.parcel-cache/lock.mdb +0 -0
- package/README.md +15 -0
- package/bun.lockb +0 -0
- package/bundle.ts +5 -0
- package/bunfig.toml +0 -0
- package/cypress/e2e/add-remove-nested-children.cy.js +39 -0
- package/cypress/e2e/add-remove-root-children.cy.js +37 -0
- package/cypress/jaxs-apps/add-remove-nested-children.html +12 -0
- package/cypress/jaxs-apps/add-remove-nested-children.jsx +84 -0
- package/cypress/jaxs-apps/add-remove-root-children.html +15 -0
- package/cypress/jaxs-apps/add-remove-root-children.jsx +53 -0
- package/cypress/jaxs-apps/dist/add-remove-nested-children.afcab974.js +717 -0
- package/cypress/jaxs-apps/dist/add-remove-nested-children.afcab974.js.map +1 -0
- package/cypress/jaxs-apps/dist/add-remove-nested-children.html +12 -0
- package/cypress/jaxs-apps/dist/add-remove-root-children.3bb9b3f5.js +1682 -0
- package/cypress/jaxs-apps/dist/add-remove-root-children.3bb9b3f5.js.map +1 -0
- package/cypress/jaxs-apps/dist/add-remove-root-children.fbb4ec9b.js +706 -0
- package/cypress/jaxs-apps/dist/add-remove-root-children.fbb4ec9b.js.map +1 -0
- package/cypress/jaxs-apps/dist/add-remove-root-children.html +15 -0
- package/cypress/support/commands.js +25 -0
- package/cypress/support/e2e.js +20 -0
- package/cypress.config.js +10 -0
- package/dist/jaxs.js +1154 -0
- package/package.json +38 -0
- package/src/app.ts +64 -0
- package/src/debugging.js +5 -0
- package/src/jaxs.ts +8 -0
- package/src/jsx.js +27 -0
- package/src/messageBus.ts +70 -0
- package/src/navigation/findHref.js +10 -0
- package/src/navigation/routeState.js +15 -0
- package/src/navigation/setupHistory.js +38 -0
- package/src/navigation/setupNavigation.js +25 -0
- package/src/navigation.ts +2 -0
- package/src/rendering/change/compile.ts +1 -0
- package/src/rendering/change/instructions/attributes.ts +78 -0
- package/src/rendering/change/instructions/children.ts +128 -0
- package/src/rendering/change/instructions/element.ts +42 -0
- package/src/rendering/change/instructions/events.ts +51 -0
- package/src/rendering/change/instructions/generate.ts +122 -0
- package/src/rendering/change/instructions/idMap.js +55 -0
- package/src/rendering/change/instructions/node.ts +38 -0
- package/src/rendering/change/instructions/text.ts +10 -0
- package/src/rendering/change.ts +131 -0
- package/src/rendering/dom/attributesAndEvents.ts +33 -0
- package/src/rendering/dom/create.ts +68 -0
- package/src/rendering/templates/bound.js +55 -0
- package/src/rendering/templates/children.ts +91 -0
- package/src/rendering/templates/root.ts +55 -0
- package/src/rendering/templates/tag.ts +70 -0
- package/src/rendering/templates/text.ts +17 -0
- package/src/state/equality.js +36 -0
- package/src/state/stores.js +63 -0
- package/src/state/testingTypes.js +6 -0
- package/src/state.js +89 -0
- package/src/types.ts +149 -0
- package/src/views/conditionals.jsx +18 -0
- package/src/views/link.jsx +5 -0
- package/src/views.js +7 -0
- package/tsconfig.json +26 -0
package/dist/jaxs.js
ADDED
|
@@ -0,0 +1,1154 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/rendering/dom/create.ts
|
|
13
|
+
var setAttributesOnElement = (element, attributes) => {
|
|
14
|
+
for (const key in attributes) {
|
|
15
|
+
if (key === "__self")
|
|
16
|
+
continue;
|
|
17
|
+
if (key === "value") {
|
|
18
|
+
element.value = attributes[key];
|
|
19
|
+
} else {
|
|
20
|
+
element.setAttribute(key, attributes[key]);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var setEventsOnElement = (element, events, publish) => {
|
|
25
|
+
const eventMaps = {};
|
|
26
|
+
for (const domEvent in events) {
|
|
27
|
+
const eventName = events[domEvent];
|
|
28
|
+
const listener = (event) => publish(eventName, event);
|
|
29
|
+
element.addEventListener(domEvent, listener);
|
|
30
|
+
eventMaps[domEvent] = {
|
|
31
|
+
domEvent,
|
|
32
|
+
busEvent: eventName,
|
|
33
|
+
listener
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
element.eventMaps = eventMaps;
|
|
37
|
+
};
|
|
38
|
+
var createNode = (type, document) => {
|
|
39
|
+
document = document || window.document;
|
|
40
|
+
return document.createElement(type);
|
|
41
|
+
};
|
|
42
|
+
var createTextNode = (value, document) => {
|
|
43
|
+
document = document || window.document;
|
|
44
|
+
return document.createTextNode(value);
|
|
45
|
+
};
|
|
46
|
+
var createDecoratedNode = (type, attributes, events, renderKit) => {
|
|
47
|
+
const dom = createNode(type, renderKit.document);
|
|
48
|
+
setAttributesOnElement(dom, attributes);
|
|
49
|
+
setEventsOnElement(dom, events, renderKit.publish);
|
|
50
|
+
return dom;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// src/rendering/dom/attributesAndEvents.ts
|
|
54
|
+
var separateAttrsAndEvents = (combined, defaultValue = "") => {
|
|
55
|
+
const attributes = {};
|
|
56
|
+
const events = {};
|
|
57
|
+
for (const key in combined) {
|
|
58
|
+
const value = combined[key];
|
|
59
|
+
if (key.match(/^on.+/i)) {
|
|
60
|
+
const eventKey = key.slice(2).toLowerCase();
|
|
61
|
+
events[eventKey] = value;
|
|
62
|
+
} else {
|
|
63
|
+
attributes[key] = normalizeValueForKey(combined, key, defaultValue);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
attributes,
|
|
68
|
+
events
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
var normalizeValueForKey = (object, key, defaultValue = "") => {
|
|
72
|
+
if (object[key] === undefined)
|
|
73
|
+
return defaultValue;
|
|
74
|
+
return object[key];
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/rendering/templates/text.ts
|
|
78
|
+
class TextTemplate {
|
|
79
|
+
value;
|
|
80
|
+
constructor(content) {
|
|
81
|
+
this.value = content.toString();
|
|
82
|
+
}
|
|
83
|
+
render(renderKit) {
|
|
84
|
+
const textNode = createTextNode(this.value, renderKit.document);
|
|
85
|
+
if (!textNode)
|
|
86
|
+
return [];
|
|
87
|
+
textNode.__jsx = "TextNode";
|
|
88
|
+
return [textNode];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/rendering/templates/children.ts
|
|
93
|
+
var ensureArray = (children) => {
|
|
94
|
+
if (Array.isArray(children)) {
|
|
95
|
+
return children.flat();
|
|
96
|
+
}
|
|
97
|
+
if (!children) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
return [children];
|
|
101
|
+
};
|
|
102
|
+
var recursiveRender = (children, renderKit, rendered = []) => children.reduce(renderReducer(renderKit), rendered).flat();
|
|
103
|
+
var renderReducer = (renderKit) => (aggregate, view) => {
|
|
104
|
+
if (!view)
|
|
105
|
+
return aggregate;
|
|
106
|
+
if (Array.isArray(view)) {
|
|
107
|
+
const dom = recursiveRender(view, renderKit, aggregate);
|
|
108
|
+
return dom;
|
|
109
|
+
}
|
|
110
|
+
view.render(renderKit).forEach((template) => aggregate.push(template));
|
|
111
|
+
return aggregate;
|
|
112
|
+
};
|
|
113
|
+
var replaceTextNodes = (child) => {
|
|
114
|
+
if (isTextNode(child)) {
|
|
115
|
+
return textNode(child);
|
|
116
|
+
}
|
|
117
|
+
return child;
|
|
118
|
+
};
|
|
119
|
+
var isTextNode = (child) => {
|
|
120
|
+
return typeof child === "string" || typeof child === "number";
|
|
121
|
+
};
|
|
122
|
+
var textNode = (content) => {
|
|
123
|
+
return new TextTemplate(content);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
class Children {
|
|
127
|
+
collection;
|
|
128
|
+
parentElement;
|
|
129
|
+
constructor(jsxChildren) {
|
|
130
|
+
this.collection = ensureArray(jsxChildren);
|
|
131
|
+
this.collection = this.collection.map(replaceTextNodes);
|
|
132
|
+
this.collection = this.collection.flat();
|
|
133
|
+
}
|
|
134
|
+
render(renderKit, parentElement) {
|
|
135
|
+
this.parentElement = parentElement;
|
|
136
|
+
const dom = this.generateDom(renderKit);
|
|
137
|
+
this.attachToParent(dom);
|
|
138
|
+
return dom;
|
|
139
|
+
}
|
|
140
|
+
generateDom(renderKit) {
|
|
141
|
+
return recursiveRender(this.collection, renderKit);
|
|
142
|
+
}
|
|
143
|
+
attachToParent(dom) {
|
|
144
|
+
if (this.parentElement === undefined)
|
|
145
|
+
return;
|
|
146
|
+
const parent = this.parentElement;
|
|
147
|
+
dom.forEach((node) => parent.appendChild(node));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// src/rendering/templates/tag.ts
|
|
152
|
+
class Tag {
|
|
153
|
+
type;
|
|
154
|
+
events;
|
|
155
|
+
attributes;
|
|
156
|
+
children;
|
|
157
|
+
constructor(tagType, combinedAttributes, children2) {
|
|
158
|
+
this.type = tagType;
|
|
159
|
+
const { events, attributes } = separateAttrsAndEvents(combinedAttributes);
|
|
160
|
+
this.events = events;
|
|
161
|
+
this.attributes = attributes;
|
|
162
|
+
this.children = new Children(children2);
|
|
163
|
+
}
|
|
164
|
+
render(renderKit) {
|
|
165
|
+
const dom = this.generateDom(renderKit);
|
|
166
|
+
if (!dom)
|
|
167
|
+
return [];
|
|
168
|
+
this.children.render(renderKit, dom);
|
|
169
|
+
return [dom];
|
|
170
|
+
}
|
|
171
|
+
generateDom(renderKit) {
|
|
172
|
+
const node = createDecoratedNode(this.type, this.attributes, this.events, renderKit);
|
|
173
|
+
node.__jsx = this.key();
|
|
174
|
+
return node;
|
|
175
|
+
}
|
|
176
|
+
key() {
|
|
177
|
+
return this.attributes.key || this.source() || this.createKey();
|
|
178
|
+
}
|
|
179
|
+
source() {
|
|
180
|
+
if (this.attributes.__source) {
|
|
181
|
+
const { fileName, lineNumber, columnNumber } = this.attributes.__source;
|
|
182
|
+
return `${fileName}:${lineNumber}:${columnNumber}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
createKey() {
|
|
186
|
+
const id = this.attributes.id ? `#${this.attributes.id}` : "";
|
|
187
|
+
const type = this.attributes.type ? `[type=${this.attributes.type}]` : "";
|
|
188
|
+
const name = this.attributes.name ? `[name=${this.attributes.name}]` : "";
|
|
189
|
+
return `${this.type}${id}${type}${name}`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/jsx.js
|
|
194
|
+
var ensureChildrenArray = (maybeChildren, attributes) => maybeChildren || attributes.children || [];
|
|
195
|
+
var packageAttributes = (maybeAttributes, maybeChildren) => {
|
|
196
|
+
const attributes = maybeAttributes || {};
|
|
197
|
+
const children3 = ensureChildrenArray(maybeChildren, attributes);
|
|
198
|
+
attributes.children = attributes.children || children3;
|
|
199
|
+
return attributes;
|
|
200
|
+
};
|
|
201
|
+
var jsx = (type, attributes, ...children3) => {
|
|
202
|
+
if (typeof type === "string") {
|
|
203
|
+
return new Tag(type, attributes, children3);
|
|
204
|
+
}
|
|
205
|
+
return type(packageAttributes(attributes, children3));
|
|
206
|
+
};
|
|
207
|
+
jsx.fragment = (attributes, maybeChildren) => {
|
|
208
|
+
const children3 = ensureChildrenArray(maybeChildren, attributes);
|
|
209
|
+
return new Children(children3);
|
|
210
|
+
};
|
|
211
|
+
var jsx_default = jsx;
|
|
212
|
+
// src/rendering/templates/root.ts
|
|
213
|
+
class Root {
|
|
214
|
+
template;
|
|
215
|
+
selector;
|
|
216
|
+
renderKit;
|
|
217
|
+
dom;
|
|
218
|
+
parentElement;
|
|
219
|
+
constructor(template, selector, renderKit) {
|
|
220
|
+
this.template = template;
|
|
221
|
+
this.selector = selector;
|
|
222
|
+
this.renderKit = renderKit;
|
|
223
|
+
this.dom = [];
|
|
224
|
+
this.parentElement = null;
|
|
225
|
+
}
|
|
226
|
+
renderAndAttach(renderKit) {
|
|
227
|
+
this.parentElement = this.getParentElement();
|
|
228
|
+
this.dom = this.render({ ...renderKit, parent: this.parentElement });
|
|
229
|
+
if (this.parentElement) {
|
|
230
|
+
this.attach();
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
render(renderKit) {
|
|
234
|
+
return this.template.render(renderKit);
|
|
235
|
+
}
|
|
236
|
+
attach() {
|
|
237
|
+
this.parentElement && (this.parentElement.innerHTML = "");
|
|
238
|
+
this.dom.forEach((element) => {
|
|
239
|
+
this.parentElement && this.parentElement.appendChild(element);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
getParentElement() {
|
|
243
|
+
return this.renderKit.document.querySelector(this.selector);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
var render = (template, selector, renderKit) => {
|
|
247
|
+
const root = new Root(template, selector, renderKit);
|
|
248
|
+
root.renderAndAttach(renderKit);
|
|
249
|
+
return root;
|
|
250
|
+
};
|
|
251
|
+
// src/state/testingTypes.js
|
|
252
|
+
var isBoolean = (value) => typeof value === "boolean";
|
|
253
|
+
var isNumber = (value) => typeof value === "number";
|
|
254
|
+
var isString = (value) => typeof value === "string";
|
|
255
|
+
var isArray = (value) => Array.isArray(value);
|
|
256
|
+
var isObject = (value) => value !== null && !isArray(value) && typeof value === "object";
|
|
257
|
+
|
|
258
|
+
// src/state/equality.js
|
|
259
|
+
var areElementEqual = (oldValue, newValue) => oldValue === newValue;
|
|
260
|
+
var keyLengthSame = (oldValue, newValue) => Object.keys(oldValue).length === Object.keys(newValue).length;
|
|
261
|
+
var areObjectsEqual = (oldValue, newValue) => {
|
|
262
|
+
if (!(isObject(oldValue) && isObject(newValue)))
|
|
263
|
+
return false;
|
|
264
|
+
if (!keyLengthSame(oldValue, newValue))
|
|
265
|
+
return false;
|
|
266
|
+
Object.keys(oldValue).every((key) => {
|
|
267
|
+
const oldInnerValue = oldValue[key];
|
|
268
|
+
const newInnerValue = newValue[key];
|
|
269
|
+
return areEqual(oldInnerValue, newInnerValue);
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
var areArraysEqual = (oldValue, newValue) => {
|
|
273
|
+
if (!(isArray(oldValue) && isArray(newValue)))
|
|
274
|
+
return false;
|
|
275
|
+
if (oldValue.length !== newValue.length)
|
|
276
|
+
return false;
|
|
277
|
+
oldValue.every((oldInnerValue, index) => {
|
|
278
|
+
const newInnerValue = newValue[index];
|
|
279
|
+
return areEqual(oldInnerValue, newInnerValue);
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
var areEqual = (oldValue, newValue) => {
|
|
283
|
+
if (isObject(oldValue))
|
|
284
|
+
return areObjectsEqual(oldValue, newValue);
|
|
285
|
+
if (isArray(oldValue))
|
|
286
|
+
return areArraysEqual(oldValue, newValue);
|
|
287
|
+
return areElementEqual(oldValue, newValue);
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
// src/state/stores.js
|
|
291
|
+
class GeneralStore {
|
|
292
|
+
nullEvent = {};
|
|
293
|
+
constructor({ name, value, parent }) {
|
|
294
|
+
this.name = name;
|
|
295
|
+
this.value = value;
|
|
296
|
+
this.parent = parent;
|
|
297
|
+
this.initialState = value;
|
|
298
|
+
}
|
|
299
|
+
update(newValue) {
|
|
300
|
+
if (this.isEqual(newValue))
|
|
301
|
+
return;
|
|
302
|
+
this.value = newValue;
|
|
303
|
+
return this.parent.publish(this.event());
|
|
304
|
+
}
|
|
305
|
+
reset() {
|
|
306
|
+
this.update(this.initialState);
|
|
307
|
+
}
|
|
308
|
+
isEqual(newValue) {
|
|
309
|
+
return areElementEqual(this.value, newValue);
|
|
310
|
+
}
|
|
311
|
+
event() {
|
|
312
|
+
return {
|
|
313
|
+
name: this.name,
|
|
314
|
+
value: this.value
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
class BooleanStore extends GeneralStore {
|
|
320
|
+
toggle() {
|
|
321
|
+
this.update(!this.value);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
class NumericStore extends GeneralStore {
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
class StringStore extends GeneralStore {
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
class ListStore extends GeneralStore {
|
|
332
|
+
isEqual(newValue) {
|
|
333
|
+
return areArraysEqual(this.value, newValue);
|
|
334
|
+
}
|
|
335
|
+
push(newValue) {
|
|
336
|
+
const value = [...this.value, newValue];
|
|
337
|
+
this.update(value);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
class RecordStore extends GeneralStore {
|
|
342
|
+
isEqual(newValue) {
|
|
343
|
+
return areObjectsEqual(this.value, newValue);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/state.js
|
|
348
|
+
var eventPrefix = "state-change";
|
|
349
|
+
var eventName = (name) => `${eventPrefix}:${name}`;
|
|
350
|
+
|
|
351
|
+
class State {
|
|
352
|
+
constructor(publish) {
|
|
353
|
+
this.publisher = publish;
|
|
354
|
+
this.stores = {};
|
|
355
|
+
this.events = [];
|
|
356
|
+
this.transacting = false;
|
|
357
|
+
}
|
|
358
|
+
create(name, value) {
|
|
359
|
+
const StoreClass = this.storeTypeFor(value);
|
|
360
|
+
const store = new StoreClass({ name, value, parent: this });
|
|
361
|
+
this.addStore(name, store);
|
|
362
|
+
}
|
|
363
|
+
add(store) {
|
|
364
|
+
const name = store.name;
|
|
365
|
+
this.addStore(name, store);
|
|
366
|
+
}
|
|
367
|
+
getStore(name) {
|
|
368
|
+
return this.stores[name];
|
|
369
|
+
}
|
|
370
|
+
addStore(name, store) {
|
|
371
|
+
this.stores[name] = store;
|
|
372
|
+
this[name] = store;
|
|
373
|
+
}
|
|
374
|
+
storeTypeFor(value) {
|
|
375
|
+
if (isArray(value))
|
|
376
|
+
return ListStore;
|
|
377
|
+
if (isObject(value))
|
|
378
|
+
return RecordStore;
|
|
379
|
+
if (isNumber(value))
|
|
380
|
+
return NumericStore;
|
|
381
|
+
if (isBoolean(value))
|
|
382
|
+
return BooleanStore;
|
|
383
|
+
if (isString(value))
|
|
384
|
+
return StringStore;
|
|
385
|
+
return GeneralStore;
|
|
386
|
+
}
|
|
387
|
+
publish(event) {
|
|
388
|
+
this.events.push(event);
|
|
389
|
+
if (!this.transacting)
|
|
390
|
+
this.publishAll();
|
|
391
|
+
}
|
|
392
|
+
publishAll() {
|
|
393
|
+
const publishedStores = [];
|
|
394
|
+
this.events.reverse().forEach((event) => {
|
|
395
|
+
const { name, value } = event;
|
|
396
|
+
if (!publishedStores.includes(name)) {
|
|
397
|
+
publishedStores.push(name);
|
|
398
|
+
this.publisher(`${eventPrefix}:${name}`, value);
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
this.events = [];
|
|
402
|
+
}
|
|
403
|
+
transaction(setter) {
|
|
404
|
+
this.transacting = true;
|
|
405
|
+
setter(this);
|
|
406
|
+
this.transacting = false;
|
|
407
|
+
this.publishAll();
|
|
408
|
+
}
|
|
409
|
+
value() {
|
|
410
|
+
return Object.keys(this.stores).reduce((valueObject, key) => {
|
|
411
|
+
valueObject[key] = this.stores[key].value;
|
|
412
|
+
return valueObject;
|
|
413
|
+
}, {});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/types.ts
|
|
418
|
+
var ChangeInstructions;
|
|
419
|
+
(function(ChangeInstructions2) {
|
|
420
|
+
ChangeInstructions2[ChangeInstructions2["removeNode"] = 0] = "removeNode";
|
|
421
|
+
ChangeInstructions2[ChangeInstructions2["insertNode"] = 1] = "insertNode";
|
|
422
|
+
ChangeInstructions2[ChangeInstructions2["replaceNode"] = 2] = "replaceNode";
|
|
423
|
+
ChangeInstructions2[ChangeInstructions2["removeAttribute"] = 3] = "removeAttribute";
|
|
424
|
+
ChangeInstructions2[ChangeInstructions2["addAttribute"] = 4] = "addAttribute";
|
|
425
|
+
ChangeInstructions2[ChangeInstructions2["updateAttribute"] = 5] = "updateAttribute";
|
|
426
|
+
ChangeInstructions2[ChangeInstructions2["removeEvent"] = 6] = "removeEvent";
|
|
427
|
+
ChangeInstructions2[ChangeInstructions2["addEvent"] = 7] = "addEvent";
|
|
428
|
+
ChangeInstructions2[ChangeInstructions2["updateEvent"] = 8] = "updateEvent";
|
|
429
|
+
ChangeInstructions2[ChangeInstructions2["changeValue"] = 9] = "changeValue";
|
|
430
|
+
ChangeInstructions2[ChangeInstructions2["changeText"] = 10] = "changeText";
|
|
431
|
+
})(ChangeInstructions || (ChangeInstructions = {}));
|
|
432
|
+
|
|
433
|
+
// src/rendering/change/instructions/generate.ts
|
|
434
|
+
var changeText = (source, target) => ({
|
|
435
|
+
source,
|
|
436
|
+
target,
|
|
437
|
+
type: ChangeInstructions.changeText,
|
|
438
|
+
data: {}
|
|
439
|
+
});
|
|
440
|
+
var replaceNode = (source, target) => ({
|
|
441
|
+
source,
|
|
442
|
+
target,
|
|
443
|
+
type: ChangeInstructions.replaceNode,
|
|
444
|
+
data: {}
|
|
445
|
+
});
|
|
446
|
+
var removeAttribute = (source, target, data) => ({
|
|
447
|
+
source,
|
|
448
|
+
target,
|
|
449
|
+
data,
|
|
450
|
+
type: ChangeInstructions.removeAttribute
|
|
451
|
+
});
|
|
452
|
+
var addAttribute = (source, target, data) => ({
|
|
453
|
+
source,
|
|
454
|
+
target,
|
|
455
|
+
data,
|
|
456
|
+
type: ChangeInstructions.addAttribute
|
|
457
|
+
});
|
|
458
|
+
var updateAttribute = (source, target, data) => ({
|
|
459
|
+
source,
|
|
460
|
+
target,
|
|
461
|
+
data,
|
|
462
|
+
type: ChangeInstructions.updateAttribute
|
|
463
|
+
});
|
|
464
|
+
var removeEvent = (source, target, data) => ({
|
|
465
|
+
source,
|
|
466
|
+
target,
|
|
467
|
+
data,
|
|
468
|
+
type: ChangeInstructions.removeEvent
|
|
469
|
+
});
|
|
470
|
+
var addEvent = (source, target, data) => ({
|
|
471
|
+
source,
|
|
472
|
+
target,
|
|
473
|
+
data,
|
|
474
|
+
type: ChangeInstructions.addEvent
|
|
475
|
+
});
|
|
476
|
+
var updateEvent = (source, target, data) => ({
|
|
477
|
+
source,
|
|
478
|
+
target,
|
|
479
|
+
data,
|
|
480
|
+
type: ChangeInstructions.updateEvent
|
|
481
|
+
});
|
|
482
|
+
var removeNode = (source) => ({
|
|
483
|
+
source,
|
|
484
|
+
target: source,
|
|
485
|
+
type: ChangeInstructions.removeNode,
|
|
486
|
+
data: {}
|
|
487
|
+
});
|
|
488
|
+
var insertNode = (target, data) => ({
|
|
489
|
+
target,
|
|
490
|
+
source: target,
|
|
491
|
+
type: ChangeInstructions.insertNode,
|
|
492
|
+
data
|
|
493
|
+
});
|
|
494
|
+
var changeValue = (source, target, data) => ({
|
|
495
|
+
source,
|
|
496
|
+
target,
|
|
497
|
+
type: ChangeInstructions.changeValue,
|
|
498
|
+
data
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// src/rendering/change/instructions/idMap.js
|
|
502
|
+
var nullMatch = { index: -1 };
|
|
503
|
+
|
|
504
|
+
class IdMap {
|
|
505
|
+
constructor() {
|
|
506
|
+
this.map = {};
|
|
507
|
+
}
|
|
508
|
+
populate(list) {
|
|
509
|
+
list.forEach((element, i) => {
|
|
510
|
+
const id = element.__jsx;
|
|
511
|
+
if (id) {
|
|
512
|
+
this.map[id] = this.map[id] || [];
|
|
513
|
+
this.map[id].push({
|
|
514
|
+
element,
|
|
515
|
+
index: i
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
pullMatch(element) {
|
|
521
|
+
const id = element && element.__jsx;
|
|
522
|
+
if (!id)
|
|
523
|
+
return nullMatch;
|
|
524
|
+
if (!(this.map[id] && this.map[id].length))
|
|
525
|
+
return nullMatch;
|
|
526
|
+
return this.map[id].shift();
|
|
527
|
+
}
|
|
528
|
+
clear(element) {
|
|
529
|
+
const id = element && element.__jsx;
|
|
530
|
+
if (!(id && this.map[id] && this.map[id].length))
|
|
531
|
+
return;
|
|
532
|
+
const matches = this.map[id];
|
|
533
|
+
this.map[id] = matches.reduce((collection, possibleMatch) => {
|
|
534
|
+
if (possibleMatch.element !== element)
|
|
535
|
+
collection.push(possibleMatch);
|
|
536
|
+
return collection;
|
|
537
|
+
}, []);
|
|
538
|
+
}
|
|
539
|
+
check(element) {
|
|
540
|
+
const id = element && element.__jsx;
|
|
541
|
+
if (!(id && this.map[id]))
|
|
542
|
+
return false;
|
|
543
|
+
return this.map[id].length > 0;
|
|
544
|
+
}
|
|
545
|
+
remaining() {
|
|
546
|
+
return Object.values(this.map).flat();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
var createIdMap = (list) => {
|
|
550
|
+
const map = new IdMap;
|
|
551
|
+
map.populate(list);
|
|
552
|
+
return map;
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
// src/rendering/change/instructions/attributes.ts
|
|
556
|
+
var compileForAttributes = (source, target) => {
|
|
557
|
+
const instructions = [];
|
|
558
|
+
const sourceAttributes = source.attributes;
|
|
559
|
+
const sourceLength = sourceAttributes.length;
|
|
560
|
+
const targetAttributes = target.attributes;
|
|
561
|
+
const targetLength = targetAttributes.length;
|
|
562
|
+
let index;
|
|
563
|
+
let innerIndex;
|
|
564
|
+
let matchingAttribute;
|
|
565
|
+
for (index = 0;index < sourceLength; index++) {
|
|
566
|
+
matchingAttribute = null;
|
|
567
|
+
const sourceAttribute = sourceAttributes.item(index);
|
|
568
|
+
if (!sourceAttribute)
|
|
569
|
+
continue;
|
|
570
|
+
for (innerIndex = 0;innerIndex < targetLength; innerIndex++) {
|
|
571
|
+
const targetAttribute = targetAttributes.item(innerIndex);
|
|
572
|
+
if (!targetAttribute)
|
|
573
|
+
continue;
|
|
574
|
+
if (sourceAttribute.name == targetAttribute.name) {
|
|
575
|
+
matchingAttribute = targetAttribute;
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
if (!matchingAttribute) {
|
|
580
|
+
instructions.push(removeAttribute(source, target, { name: sourceAttribute.name }));
|
|
581
|
+
} else if (sourceAttribute.value !== matchingAttribute.value) {
|
|
582
|
+
instructions.push(updateAttribute(source, target, {
|
|
583
|
+
name: sourceAttribute.name,
|
|
584
|
+
value: matchingAttribute.value
|
|
585
|
+
}));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
for (index = 0;index < targetLength; index++) {
|
|
589
|
+
matchingAttribute = null;
|
|
590
|
+
const targetAttribute = targetAttributes.item(index);
|
|
591
|
+
if (!targetAttribute)
|
|
592
|
+
continue;
|
|
593
|
+
for (innerIndex = 0;innerIndex < sourceLength; innerIndex++) {
|
|
594
|
+
const sourceAttribute = sourceAttributes.item(innerIndex);
|
|
595
|
+
if (!sourceAttribute)
|
|
596
|
+
continue;
|
|
597
|
+
if (sourceAttribute.name == targetAttribute.name) {
|
|
598
|
+
matchingAttribute = sourceAttribute;
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (!matchingAttribute) {
|
|
603
|
+
instructions.push(addAttribute(source, target, {
|
|
604
|
+
name: targetAttribute.name,
|
|
605
|
+
value: targetAttribute.value
|
|
606
|
+
}));
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return instructions;
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
// src/rendering/change/instructions/events.ts
|
|
613
|
+
var compileForEvents = (source, target) => {
|
|
614
|
+
const instructions = [];
|
|
615
|
+
const sourceEventMaps = source.eventMaps;
|
|
616
|
+
const targetEventMaps = target.eventMaps;
|
|
617
|
+
const sourceDomEvents = Object.keys(sourceEventMaps);
|
|
618
|
+
const targetDomEvents = Object.keys(targetEventMaps);
|
|
619
|
+
sourceDomEvents.forEach((domEvent) => {
|
|
620
|
+
const sourceEventMap = sourceEventMaps[domEvent];
|
|
621
|
+
const targetEventMap = targetEventMaps[domEvent];
|
|
622
|
+
if (!targetEventMap) {
|
|
623
|
+
instructions.push(removeEvent(source, target, {
|
|
624
|
+
name: sourceEventMap.domEvent,
|
|
625
|
+
value: sourceEventMap.listener
|
|
626
|
+
}));
|
|
627
|
+
} else if (targetEventMap.busEvent !== sourceEventMap.busEvent) {
|
|
628
|
+
instructions.push(updateEvent(source, target, {
|
|
629
|
+
name: domEvent,
|
|
630
|
+
targetValue: targetEventMap.listener,
|
|
631
|
+
sourceValue: sourceEventMap.listener
|
|
632
|
+
}));
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
targetDomEvents.forEach((domEvent) => {
|
|
636
|
+
const sourceEventMap = sourceEventMaps[domEvent];
|
|
637
|
+
const targetEventMap = targetEventMaps[domEvent];
|
|
638
|
+
if (!sourceEventMap) {
|
|
639
|
+
instructions.push(addEvent(source, target, {
|
|
640
|
+
name: targetEventMap.domEvent,
|
|
641
|
+
value: targetEventMap.listener
|
|
642
|
+
}));
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
return instructions;
|
|
646
|
+
};
|
|
647
|
+
|
|
648
|
+
// src/rendering/change/instructions/element.ts
|
|
649
|
+
var compileForElement = (source, target) => {
|
|
650
|
+
const attributeInstructions = compileForAttributes(source, target);
|
|
651
|
+
const eventInstructions = compileForEvents(source, target);
|
|
652
|
+
const valueInstructions = compileForInputValue(source, target);
|
|
653
|
+
return attributeInstructions.concat(eventInstructions).concat(valueInstructions);
|
|
654
|
+
};
|
|
655
|
+
var compileForInputValue = (sourceElement, targetElement) => {
|
|
656
|
+
const instructions = [];
|
|
657
|
+
if (sourceElement.tagName !== "INPUT") {
|
|
658
|
+
return instructions;
|
|
659
|
+
}
|
|
660
|
+
const source = sourceElement;
|
|
661
|
+
const target = targetElement;
|
|
662
|
+
if (source.value !== target.value) {
|
|
663
|
+
instructions.push(changeValue(source, target, { name: "value", value: target.value }));
|
|
664
|
+
}
|
|
665
|
+
return instructions;
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
// src/rendering/change/instructions/text.ts
|
|
669
|
+
var compileForText = (source, target) => {
|
|
670
|
+
if (source.textContent !== target.textContent) {
|
|
671
|
+
return [changeText(source, target)];
|
|
672
|
+
}
|
|
673
|
+
return [];
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
// src/rendering/change/instructions/node.ts
|
|
677
|
+
var NodeTypes;
|
|
678
|
+
(function(NodeTypes2) {
|
|
679
|
+
NodeTypes2[NodeTypes2["ElementNode"] = 1] = "ElementNode";
|
|
680
|
+
NodeTypes2[NodeTypes2["TextNode"] = 3] = "TextNode";
|
|
681
|
+
})(NodeTypes || (NodeTypes = {}));
|
|
682
|
+
var compileForNodeGenerator = (compileForCollection) => (source, target) => {
|
|
683
|
+
let instructions = [];
|
|
684
|
+
if (source.nodeType === NodeTypes.ElementNode) {
|
|
685
|
+
const sourceElement = source;
|
|
686
|
+
const targetElement = target;
|
|
687
|
+
const baseInstructions = compileForElement(sourceElement, targetElement);
|
|
688
|
+
const childrenInstructions = compileForCollection(sourceElement.childNodes, targetElement.childNodes, sourceElement);
|
|
689
|
+
instructions = baseInstructions.concat(childrenInstructions);
|
|
690
|
+
} else if (source.nodeType === NodeTypes.TextNode) {
|
|
691
|
+
instructions = compileForText(source, target);
|
|
692
|
+
}
|
|
693
|
+
return instructions;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// src/debugging.js
|
|
697
|
+
var debug = (...message) => {
|
|
698
|
+
if (process.env.DEBUG === "true") {
|
|
699
|
+
console.log(...message);
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
// src/rendering/change/instructions/children.ts
|
|
704
|
+
var compileChildren = (sourceList, targetList, parent) => {
|
|
705
|
+
const baseInstructions = [];
|
|
706
|
+
const length = largerLength(sourceList, targetList);
|
|
707
|
+
const sourceMap = createIdMap(sourceList);
|
|
708
|
+
const targetMap = createIdMap(targetList);
|
|
709
|
+
const nodesPairsToDiff = [];
|
|
710
|
+
let index = 0;
|
|
711
|
+
for (;index < length; index++) {
|
|
712
|
+
const source = sourceList[index];
|
|
713
|
+
const target = targetList[index];
|
|
714
|
+
debug("\n", "loop index", index, source && source.__jsx, target && target.__jsx);
|
|
715
|
+
if (target && targetMap.check(target)) {
|
|
716
|
+
debug("target", target.__jsx, "index", index);
|
|
717
|
+
const matchingSource = sourceMap.pullMatch(target);
|
|
718
|
+
targetMap.clear(target);
|
|
719
|
+
if (matchingSource.element) {
|
|
720
|
+
debug("matching source found for target");
|
|
721
|
+
if (matchingSource.index !== index) {
|
|
722
|
+
debug("moving source", matchingSource.element.__jsx, index);
|
|
723
|
+
baseInstructions.push(insertNode(matchingSource.element, { parent, index }));
|
|
724
|
+
}
|
|
725
|
+
debug("updating to match target", matchingSource.element.__jsx, matchingSource.element.classList, target.__jsx, target.classList);
|
|
726
|
+
nodesPairsToDiff.push({
|
|
727
|
+
source: matchingSource.element,
|
|
728
|
+
target
|
|
729
|
+
});
|
|
730
|
+
} else if (source) {
|
|
731
|
+
debug("NO matching source for target but source in slot", source.__jsx);
|
|
732
|
+
if (targetMap.check(source)) {
|
|
733
|
+
debug("adding", target.__jsx, "at", index);
|
|
734
|
+
baseInstructions.push(insertNode(target, { parent, index }));
|
|
735
|
+
} else {
|
|
736
|
+
debug("replacing", source.__jsx, target.__jsx, "at", index);
|
|
737
|
+
sourceMap.clear(source);
|
|
738
|
+
baseInstructions.push(replaceNode(source, target));
|
|
739
|
+
}
|
|
740
|
+
} else {
|
|
741
|
+
debug("adding target to end", target.__jsx);
|
|
742
|
+
baseInstructions.push(insertNode(target, { parent, index }));
|
|
743
|
+
}
|
|
744
|
+
} else if (source) {
|
|
745
|
+
const matchingSource = sourceMap.pullMatch(source);
|
|
746
|
+
if (matchingSource.element) {
|
|
747
|
+
debug("removing", source.__jsx);
|
|
748
|
+
baseInstructions.push(removeNode(source));
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
sourceMap.remaining().forEach(({ element: element2 }) => {
|
|
753
|
+
debug("removing", element2.__jsx);
|
|
754
|
+
baseInstructions.push(removeNode(element2));
|
|
755
|
+
});
|
|
756
|
+
const nodeInstructions = nodesPairsToDiff.reduce((collection, { source, target }) => {
|
|
757
|
+
return collection.concat(compileForNode(source, target));
|
|
758
|
+
}, []);
|
|
759
|
+
return baseInstructions.concat(nodeInstructions).sort(instructionsSorter);
|
|
760
|
+
};
|
|
761
|
+
var instructionsSorter = (left, right) => {
|
|
762
|
+
if (left.type > right.type)
|
|
763
|
+
return 1;
|
|
764
|
+
if (left.type < right.type)
|
|
765
|
+
return -1;
|
|
766
|
+
return 0;
|
|
767
|
+
};
|
|
768
|
+
var largerLength = (sourceList, targetList) => {
|
|
769
|
+
const sourceLength = Array.from(sourceList).length;
|
|
770
|
+
const targetLength = Array.from(targetList).length;
|
|
771
|
+
return sourceLength > targetLength ? sourceLength : targetLength;
|
|
772
|
+
};
|
|
773
|
+
var compileForNode = compileForNodeGenerator(compileChildren);
|
|
774
|
+
// src/rendering/change.ts
|
|
775
|
+
var change = (source, target, parent) => {
|
|
776
|
+
const instructions = compileChildren(source, target, parent);
|
|
777
|
+
debug("instructions", instructions.map((instruction) => instruction.type));
|
|
778
|
+
instructions.forEach((instruction) => {
|
|
779
|
+
performInstruction(instruction);
|
|
780
|
+
});
|
|
781
|
+
};
|
|
782
|
+
var performInstruction = (instruction) => {
|
|
783
|
+
const performer = performers[instruction.type] || noop;
|
|
784
|
+
performer(instruction);
|
|
785
|
+
};
|
|
786
|
+
var noop = (_instruction) => {
|
|
787
|
+
};
|
|
788
|
+
var changeText2 = (instruction) => {
|
|
789
|
+
const { source, target } = instruction;
|
|
790
|
+
source.nodeValue = target.textContent;
|
|
791
|
+
};
|
|
792
|
+
var removeNode2 = (instruction) => {
|
|
793
|
+
const { source } = instruction;
|
|
794
|
+
source.remove();
|
|
795
|
+
debug("removeNode called on", source.nodeName);
|
|
796
|
+
};
|
|
797
|
+
var insertNode2 = (instruction) => {
|
|
798
|
+
const { target, data } = instruction;
|
|
799
|
+
const { parent, index } = data;
|
|
800
|
+
const sibling = parent.childNodes[index];
|
|
801
|
+
if (!sibling) {
|
|
802
|
+
parent.appendChild(target);
|
|
803
|
+
} else if (sibling && sibling !== target) {
|
|
804
|
+
parent.insertBefore(target, sibling);
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
var replaceNode2 = (instruction) => {
|
|
808
|
+
const { source, target } = instruction;
|
|
809
|
+
source.replaceWith(target);
|
|
810
|
+
debug("replaceNode called on", source.nodeName, "with", target.nodeName);
|
|
811
|
+
debug("parent", source.parentElement);
|
|
812
|
+
};
|
|
813
|
+
var removeAttribute2 = (instruction) => {
|
|
814
|
+
const { source, data } = instruction;
|
|
815
|
+
const { name } = data;
|
|
816
|
+
source.removeAttribute(name);
|
|
817
|
+
};
|
|
818
|
+
var addAttribute2 = (instruction) => {
|
|
819
|
+
const { source, data } = instruction;
|
|
820
|
+
const { name, value } = data;
|
|
821
|
+
source.setAttribute(name, value);
|
|
822
|
+
};
|
|
823
|
+
var updateAttribute2 = (instruction) => {
|
|
824
|
+
addAttribute2(instruction);
|
|
825
|
+
};
|
|
826
|
+
var removeEvent2 = (instruction) => {
|
|
827
|
+
const data = instruction.data;
|
|
828
|
+
const source = instruction.source;
|
|
829
|
+
const { name, value } = data;
|
|
830
|
+
source.removeEventListener(name, value);
|
|
831
|
+
};
|
|
832
|
+
var addEvent2 = (instruction) => {
|
|
833
|
+
const data = instruction.data;
|
|
834
|
+
const source = instruction.source;
|
|
835
|
+
const { name, value } = data;
|
|
836
|
+
source.addEventListener(name, value);
|
|
837
|
+
};
|
|
838
|
+
var updateEvent2 = (instruction) => {
|
|
839
|
+
const data = instruction.data;
|
|
840
|
+
const source = instruction.source;
|
|
841
|
+
const { name, sourceValue, targetValue } = data;
|
|
842
|
+
source.removeEventListener(name, sourceValue);
|
|
843
|
+
source.addEventListener(name, targetValue);
|
|
844
|
+
};
|
|
845
|
+
var changeValue2 = (instruction) => {
|
|
846
|
+
const data = instruction.data;
|
|
847
|
+
const source = instruction.source;
|
|
848
|
+
const { value } = data;
|
|
849
|
+
source.value = value;
|
|
850
|
+
};
|
|
851
|
+
var performers = {
|
|
852
|
+
[ChangeInstructions.changeText]: changeText2,
|
|
853
|
+
[ChangeInstructions.removeNode]: removeNode2,
|
|
854
|
+
[ChangeInstructions.insertNode]: insertNode2,
|
|
855
|
+
[ChangeInstructions.replaceNode]: replaceNode2,
|
|
856
|
+
[ChangeInstructions.removeAttribute]: removeAttribute2,
|
|
857
|
+
[ChangeInstructions.addAttribute]: addAttribute2,
|
|
858
|
+
[ChangeInstructions.updateAttribute]: updateAttribute2,
|
|
859
|
+
[ChangeInstructions.removeEvent]: removeEvent2,
|
|
860
|
+
[ChangeInstructions.addEvent]: addEvent2,
|
|
861
|
+
[ChangeInstructions.updateEvent]: updateEvent2,
|
|
862
|
+
[ChangeInstructions.changeValue]: changeValue2
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
// src/rendering/templates/bound.js
|
|
866
|
+
class Bound {
|
|
867
|
+
constructor(TemplateClass, viewModel, subscriptions, attributes2) {
|
|
868
|
+
this.TemplateClass = TemplateClass;
|
|
869
|
+
this.viewModel = viewModel;
|
|
870
|
+
this.attributes = attributes2 || {};
|
|
871
|
+
this.subscriptions = subscriptions;
|
|
872
|
+
this.dom = [];
|
|
873
|
+
}
|
|
874
|
+
render(renderKit) {
|
|
875
|
+
this.parentElement = renderKit.parent;
|
|
876
|
+
this.renderKit = renderKit;
|
|
877
|
+
this.subscribeForRerender();
|
|
878
|
+
this.dom = this._render(renderKit);
|
|
879
|
+
return this.dom;
|
|
880
|
+
}
|
|
881
|
+
_render(renderKit) {
|
|
882
|
+
const props = {
|
|
883
|
+
...this.attributes,
|
|
884
|
+
...this.viewModel(renderKit.state.value())
|
|
885
|
+
};
|
|
886
|
+
const template = this.TemplateClass(props);
|
|
887
|
+
const dom = !template ? [] : template.render(renderKit);
|
|
888
|
+
return dom;
|
|
889
|
+
}
|
|
890
|
+
rerender() {
|
|
891
|
+
if (!this.parentElement) {
|
|
892
|
+
this.parentElement = this.dom[0] && this.dom[0].parentElement;
|
|
893
|
+
}
|
|
894
|
+
const newDom = this._render(this.renderKit);
|
|
895
|
+
change(this.dom, newDom, this.parentElement);
|
|
896
|
+
if (this.parentElement) {
|
|
897
|
+
this.dom = Array.from(this.parentElement.childNodes);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
subscribeForRerender() {
|
|
901
|
+
this.subscriptions.forEach((storeName) => {
|
|
902
|
+
this.renderKit.subscribe(eventName(storeName), () => this.rerender());
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
var bind = ({ Template, viewModel, subscriptions }) => {
|
|
907
|
+
subscriptions = subscriptions || [];
|
|
908
|
+
return (attributes2) => new Bound(Template, viewModel, subscriptions, attributes2);
|
|
909
|
+
};
|
|
910
|
+
// src/messageBus.ts
|
|
911
|
+
class MessageBus {
|
|
912
|
+
listeners;
|
|
913
|
+
options;
|
|
914
|
+
constructor() {
|
|
915
|
+
this.options = {};
|
|
916
|
+
this.listeners = {};
|
|
917
|
+
}
|
|
918
|
+
subscribe(eventName2, listener) {
|
|
919
|
+
this.ensureListenerCollection(eventName2);
|
|
920
|
+
this.listeners[eventName2].push(listener);
|
|
921
|
+
}
|
|
922
|
+
publish(eventName2, payload) {
|
|
923
|
+
const listeners = this.listeners[eventName2];
|
|
924
|
+
if (!listeners)
|
|
925
|
+
return false;
|
|
926
|
+
listeners.forEach((listener) => {
|
|
927
|
+
listener(payload, this.buildListenerKit(eventName2));
|
|
928
|
+
});
|
|
929
|
+
return true;
|
|
930
|
+
}
|
|
931
|
+
ensureListenerCollection(eventName2) {
|
|
932
|
+
if (this.listeners[eventName2])
|
|
933
|
+
return;
|
|
934
|
+
this.listeners[eventName2] = [];
|
|
935
|
+
}
|
|
936
|
+
buildListenerKit(eventName2) {
|
|
937
|
+
return {
|
|
938
|
+
eventName: eventName2,
|
|
939
|
+
publish: this.publish.bind(this),
|
|
940
|
+
...this.options
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
addListenerOptions(options) {
|
|
944
|
+
this.options = {
|
|
945
|
+
...this.options,
|
|
946
|
+
...options
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
var createBus = () => {
|
|
951
|
+
const bus = new MessageBus;
|
|
952
|
+
const publish = bus.publish.bind(bus);
|
|
953
|
+
const subscribe = bus.subscribe.bind(bus);
|
|
954
|
+
return {
|
|
955
|
+
bus,
|
|
956
|
+
publish,
|
|
957
|
+
subscribe
|
|
958
|
+
};
|
|
959
|
+
};
|
|
960
|
+
// src/navigation/routeState.js
|
|
961
|
+
var createRouteState = (state2) => {
|
|
962
|
+
const store = new RecordStore({
|
|
963
|
+
name: "route",
|
|
964
|
+
value: {
|
|
965
|
+
host: "",
|
|
966
|
+
path: "",
|
|
967
|
+
query: ""
|
|
968
|
+
},
|
|
969
|
+
parent: state2
|
|
970
|
+
});
|
|
971
|
+
state2.add(store);
|
|
972
|
+
};
|
|
973
|
+
|
|
974
|
+
// src/navigation/setupHistory.js
|
|
975
|
+
var locationChangeEvent = "locationChange";
|
|
976
|
+
var routeChangeEvent = "routeChange";
|
|
977
|
+
var extractQueryParams = (queryString) => {
|
|
978
|
+
return queryString.replace(/^\?/, "").split("&").reduce((aggregate, pairString) => {
|
|
979
|
+
if (!pairString)
|
|
980
|
+
return aggregate;
|
|
981
|
+
const pair = pairString.split("=");
|
|
982
|
+
aggregate[pair[0]] = pair[1];
|
|
983
|
+
return aggregate;
|
|
984
|
+
}, {});
|
|
985
|
+
};
|
|
986
|
+
var onLocationChange = (_payload, { publish, state: state2 }) => {
|
|
987
|
+
const { host, pathname, search } = window.location;
|
|
988
|
+
const path = pathname;
|
|
989
|
+
const query = extractQueryParams(search);
|
|
990
|
+
state2.route.update({
|
|
991
|
+
host,
|
|
992
|
+
path,
|
|
993
|
+
query
|
|
994
|
+
});
|
|
995
|
+
publish(routeChangeEvent, { host, path, query });
|
|
996
|
+
};
|
|
997
|
+
var setupHistory = (app) => {
|
|
998
|
+
const { publish, subscribe, state: state2 } = app;
|
|
999
|
+
createRouteState(state2);
|
|
1000
|
+
window.addEventListener("popstate", () => publish(locationChangeEvent));
|
|
1001
|
+
subscribe(locationChangeEvent, onLocationChange);
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
// src/navigation/findHref.js
|
|
1005
|
+
var findHref = (node2) => {
|
|
1006
|
+
if (!node2 || !node2.getAttribute)
|
|
1007
|
+
return "";
|
|
1008
|
+
while (!node2.getAttribute("href")) {
|
|
1009
|
+
node2 = node2.parentNode;
|
|
1010
|
+
if (!node2 || !node2.getAttribute)
|
|
1011
|
+
return "";
|
|
1012
|
+
}
|
|
1013
|
+
return node2.getAttribute("href");
|
|
1014
|
+
};
|
|
1015
|
+
|
|
1016
|
+
// src/navigation/setupNavigation.js
|
|
1017
|
+
var linkNavigationEvent = "goToHref";
|
|
1018
|
+
var programmaticNavigationEvent = "navigate";
|
|
1019
|
+
var navigate = (path, { publish }) => {
|
|
1020
|
+
window.history.pushState(null, "", path);
|
|
1021
|
+
publish(locationChangeEvent);
|
|
1022
|
+
};
|
|
1023
|
+
var onLinkClick = (domEvent, { publish }) => {
|
|
1024
|
+
if (!domEvent || !domEvent.target)
|
|
1025
|
+
return;
|
|
1026
|
+
domEvent.preventDefault();
|
|
1027
|
+
const href = findHref(domEvent.target);
|
|
1028
|
+
navigate(href, { publish });
|
|
1029
|
+
};
|
|
1030
|
+
var setupNavigation = (app) => {
|
|
1031
|
+
const { subscribe } = app;
|
|
1032
|
+
subscribe(linkNavigationEvent, onLinkClick);
|
|
1033
|
+
subscribe(programmaticNavigationEvent, navigate);
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
// src/app.ts
|
|
1037
|
+
var setupBus = (app) => {
|
|
1038
|
+
const { publish, subscribe, bus } = createBus();
|
|
1039
|
+
app.publish = publish;
|
|
1040
|
+
app.subscribe = subscribe;
|
|
1041
|
+
app.bus = bus;
|
|
1042
|
+
};
|
|
1043
|
+
var setupState = (app) => {
|
|
1044
|
+
const state3 = new State(app.publish);
|
|
1045
|
+
app.state = state3;
|
|
1046
|
+
};
|
|
1047
|
+
var connectBusToState = (app) => {
|
|
1048
|
+
const { bus } = app;
|
|
1049
|
+
bus.addListenerOptions({ state: app.state });
|
|
1050
|
+
};
|
|
1051
|
+
var setupRenderKit = (app, document) => {
|
|
1052
|
+
app.renderKit = {
|
|
1053
|
+
publish: app.publish,
|
|
1054
|
+
subscribe: app.subscribe,
|
|
1055
|
+
state: app.state,
|
|
1056
|
+
document
|
|
1057
|
+
};
|
|
1058
|
+
};
|
|
1059
|
+
var triggerRoute = (app) => {
|
|
1060
|
+
const publish = app.publish;
|
|
1061
|
+
setTimeout(() => {
|
|
1062
|
+
publish(locationChangeEvent, null);
|
|
1063
|
+
}, 0);
|
|
1064
|
+
};
|
|
1065
|
+
var addRender = (app) => {
|
|
1066
|
+
app.render = (template, selector) => {
|
|
1067
|
+
return render(template, selector, app.renderKit);
|
|
1068
|
+
};
|
|
1069
|
+
};
|
|
1070
|
+
var createApp = (document = window.document) => {
|
|
1071
|
+
const app = {};
|
|
1072
|
+
setupBus(app);
|
|
1073
|
+
setupState(app);
|
|
1074
|
+
connectBusToState(app);
|
|
1075
|
+
setupRenderKit(app, document);
|
|
1076
|
+
setupHistory(app);
|
|
1077
|
+
setupNavigation(app);
|
|
1078
|
+
triggerRoute(app);
|
|
1079
|
+
addRender(app);
|
|
1080
|
+
return app;
|
|
1081
|
+
};
|
|
1082
|
+
// src/navigation.ts
|
|
1083
|
+
var exports_navigation = {};
|
|
1084
|
+
__export(exports_navigation, {
|
|
1085
|
+
setupNavigation: () => {
|
|
1086
|
+
{
|
|
1087
|
+
return setupNavigation;
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
setupHistory: () => {
|
|
1091
|
+
{
|
|
1092
|
+
return setupHistory;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
// src/views/conditionals.jsx
|
|
1097
|
+
var exports_conditionals = {};
|
|
1098
|
+
__export(exports_conditionals, {
|
|
1099
|
+
Unless: () => {
|
|
1100
|
+
{
|
|
1101
|
+
return Unless;
|
|
1102
|
+
}
|
|
1103
|
+
},
|
|
1104
|
+
IfElse: () => {
|
|
1105
|
+
{
|
|
1106
|
+
return IfElse;
|
|
1107
|
+
}
|
|
1108
|
+
},
|
|
1109
|
+
If: () => {
|
|
1110
|
+
{
|
|
1111
|
+
return If;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
});
|
|
1115
|
+
var If = ({ condition, children: children3 }) => {
|
|
1116
|
+
if (!condition)
|
|
1117
|
+
return;
|
|
1118
|
+
return jsx_default(jsx_default.fragment, null, children3);
|
|
1119
|
+
};
|
|
1120
|
+
var Unless = ({ condition, children: children3 }) => {
|
|
1121
|
+
if (condition)
|
|
1122
|
+
return;
|
|
1123
|
+
return jsx_default(jsx_default.fragment, null, children3);
|
|
1124
|
+
};
|
|
1125
|
+
var IfElse = ({ condition, children: children3 }) => {
|
|
1126
|
+
const [first, ...rest] = children3;
|
|
1127
|
+
if (condition)
|
|
1128
|
+
return jsx_default(jsx_default.fragment, null, first);
|
|
1129
|
+
return jsx_default(jsx_default.fragment, null, rest);
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// src/views/link.jsx
|
|
1133
|
+
var Link = ({ children: children3, ...props }) => {
|
|
1134
|
+
return jsx_default("a", {
|
|
1135
|
+
...props,
|
|
1136
|
+
onClick: "goToHref"
|
|
1137
|
+
}, children3);
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
// src/views.js
|
|
1141
|
+
var views = {
|
|
1142
|
+
...exports_conditionals,
|
|
1143
|
+
Link
|
|
1144
|
+
};
|
|
1145
|
+
export {
|
|
1146
|
+
views,
|
|
1147
|
+
render,
|
|
1148
|
+
exports_navigation as navigation,
|
|
1149
|
+
jsx_default as jsx,
|
|
1150
|
+
createBus,
|
|
1151
|
+
createApp,
|
|
1152
|
+
bind,
|
|
1153
|
+
State
|
|
1154
|
+
};
|