-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnotes.txt
611 lines (587 loc) · 31 KB
/
notes.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
# 2023-08-20
- Added default super constructor for Component to start off with a null model.
- Added rojs.js file that just re-exports everything public in the Rojs library so clients don't need to figure out which library file to import.
- Updated all examples to use it.
# 2023-08-18
- Thinking about how to style components.
- Looking up how Vue JS does it.
- Vue component templates must have a root element.
- This doesn't work so well with Rojs which doesn't have that restriction.
- Vue doesn't seem to use shadowDom either, it must do a compile rewrite to uncollide ids and class names.
- Want to use shadowDom to scope stylesheets to a component's view.
- Maybe add a cssScope(stylesheet, children) render primitive.
- This can create an element with a shadow DOM.
- What about defining the element's properties?
- Maybe this should be part of the element template API, to define shadow DOM children separate to DOM children.
- Creating a style sheet in this will be just adding a regular tag('style', stylesheetContents) element.
- Added 'shadow' property to element template.
- It just works.
- Cleaned up element template a bit:
- Stopped passing insertBeforeNode to inner renders.
- This is only needed for adding nodes inside a list of nodes, within an element there's a new flat tree so the insert before shouldn't reference something in a different flat tree.
- Made the element template properties default to null instead of "zero" versions of their types and added if checks for each.
- Made the children rendering not detect if it's an array or not, there's no need as renderImpl is capable of splatting out an array exactly the same as it was doing.
- This also saves a redundant flat tree level by removing `children = [children]`.
- Added 'class' property to element template.
- Turns out element.class = 'class' doesn't set the element's class.
- Needs to use the classList member.
- `class` is a special keyword but is okay to use as object keys.
- Added special behaviour for 'class' property to have it set classList.
- Updated https://rojs.dev to point to https://randfur.github.io/rojs instead of using Google Sites.
- Readme needs updating.
- Documenting render() is quite a lot to write, overwhelming to read also probably.
- Maybe break it up into general rendering and reactive rendering with links to examples.
- Started rewriting the entire thing.
- Creating multiline tables in markdown requires HTML.
# 2023-08-17
- Tweaked component example a bit, added flex box and separator divs.
- Added index page for examples directory.
- Added ul() and ol() render helper functions.
# 2023-08-16
- Added Component class to render.js.
- Added component.html example.
- Just recursing render down component.view seems to work fine.
# 2023-08-15
- Maybe rename ObservableJsonProxy to Model.
- Have createModel() instead of createObservableJsonProxy().
- Component class idea.
- class Component { model: Model; view: UiTemplate }
- render() will detect Component instances and use their view.
- read/write/etc() will detect Component instances and recurse down their model.
- Maybe too magical, should maybe instead auto read/write inside nested models.
- What happens with event handlers in their view? How do they access the component?
- Sketch:
class Test extends Component {
constructor() {
this.model = createModel({
a: 1,
b: 2,
});
this.view = [{
textContent: this.model.a,
}, {
textContent: this.model.b,
}, {
tag: 'button',
events: {
click: event => {
readWrite(this.model.a, a => a + Math.floor(Math.random() * 10));
readWrite(this.model.b, b => b + Math.floor(Math.random() * 10));
},
},
}];
}
}
render(document.body, Test());
- Should work probably??
- Need to sketch a component composing another one:
class TestA extends Component {
constructor() {
this.model = createModel({
text: 'Hello',
});
this.view = this.model.text;
}
}
class TestB extends Component {
constructor() {
this.model = createModel({
a: new TestA(),
});
this.view = [
this.model.a,
{
tag: 'button',
events: {
click: event => {
readWrite(this.model.a.model.text, text => test + '.');
},
},
},
];
}
}
render(document.body, new TestB());
- Alternate version where component models are auto traversed:
class TestA extends Component {
constructor() {
this.model = createModel({
text: 'Hello',
});
this.view = this.text;
}
}
class TestB extends Component {
constructor() {
this.model = createModel({
a: new TestA(),
});
this.view = [
this.a,
{
tag: 'button',
events: {
click: event => {
readWrite(this.a.text, text => text + '.');
},
},
},
];
}
}
render(document.body, new TestB());
- Might be a bit too magical but it does look nicer...
- No this doesn't work because `this` isn't a proxy.
# 2023-06-16
- renderInsertNode() had a problem where a reparented element would get removed from its destination at the end of a new render.
- Problem:
- This was due to the flatTree bookkeeping.
- The inserted element would be put in the flatTree somewhere.
- Later when the proxy changes and a different template is rendered the element could be inserted into a different flatTree position but is still there in the old position.
- When whatever needs to render in that position will remove the stuff there from the DOM, this removes our inserted element even though it got removed from that place in the DOM already.
- We need to update its place in the flatTree whenever it gets reinserted somewhere else.
- Solution:
- Abstracted out setInFlatTree() which was copy pasted 3 times.
- Made it store the flatTree position on the node (if it was a node).
- Updated renderInsertNode() to check for an existing flatTree location on the node and set that to null.
- This means later when whatever template needs to render in that spot in the flatTree the element won't get erroneously removed from the DOM.
- Yay it works.
# 2023-06-15
- Added renderInsertNode().
- Ability to provide your own HTMLElements or Nodes to insert into the render.
- Should be useful for creating a canvas separately that you manage the state of and have inserted into the rendered HTML layout.
- Refactored renderString(), renderProxy() and renderElement() to reuse renderInsertNode().
- Removes a bunch of copy paste code, turns out to be a generally useful abstraction internally as well as externally.
# 2023-04-09
- Referencing elements during template constructon.
- Add { ref: string | symbol } field to element template.
- Add ref(name: string | symbol) global function.
- Add/remove elements in global map that ref() looks up as elements are attached and detached.
- List manipulation is going to need special functions.
- Having list templates completely re-render as items are added/removed is not going to work well.
- It disrupts focus traversal state.
- It will probably reset scroll state.
- Can maybe implement something in the base observable-json.js layer by having special writeListAppend() and writeListRemove() functions that trigger different watcher events.
- Could have a watchList() method that takes multiple callbacks for the different types of mutations.
- render.js can use these to recycle the child elements of htmlMap.
- Getting a bit messy but will probably be a necessary addition.
- Example page.
- Want to split out the different examples and be able to show their source code along side their execution in a generic example showcase page.
- Split out helper template functions into render-helpers.js.
- Working on making the TypeScript interface doc comments match the latest render.js code.
- Considering renaming the ObservableJsonProxy type to something like ModelProxy.
- Have to rename Rojs to Romp?? Nah.
- Maybe keep ObservableJsonProxy...
# 2023-04-08
- Added tag(tag, ...children) as a shorthand for an element with text in it.
- A little better than defining `function h1(...children) { return { tag: 'h1', children }; }` all the time.
# 2023-04-07
- Changed htmlMapRead() to do an htmlRead on the individual items, having it just use the concrete types would be a footgun that users can do themselves via htmlRead(listProxy, list => list.map(itemTemplateFunction)).
- Updating lists is easy to get wrong and will probably need more helper functions.
- Will add them as more examples are made.
- Next examples to make:
- Example gallery.
- Pull out the debug view into its own component that all examples use.
- Tic tac toe game.
- Note taking app.
- Terrible and stale, maybe something that's a parody of this.
- All letters are replaced by emoji.
- Removed old non reactive example.
- Added readWrite() for additive mutations e.g. readWrite(model.count, count => count + 1).
- Registered https://rojs.dev and put a placeholder site up.
- Maybe will use this as an official landing page one day.
- Created a rojs logo, looks like a Pacman tennis ball looking away from the camera with mouth open.
- Came up with some tag lines to use in first impression documentation:
- HTML templating without the HTML.
- Deeply nested data binding.
- Direct re-rendering, no virtual DOM.
- Experimental. Not production ready. Probably performs terribly and hard to use at scale.
- Moved files into directory structure:
- src for library source files.
- examples for example source.
- docs for README.md resources.
- Big WIP on the README.md file adding concrete examples.
- Created a the basic note taking app.
- How to have elements reference each other in their event handlers?
- Example is using getElementById().
- Doesn't scale well to many instances of a component that wants to reference hardcoded ids within its own namespace.
- Still writing out examples for all the template types.
- Need to explain ReadingValue to be able to use its type in helper funciton signatures.
# 2023-04-06
- Got a broken implementation working.
- Updated flatTree reactive example to be resizingSiblings.
- Adjacent arrays that update their contents and may be empty.
- Broken because a0 can be seen after c0 when it should statically be before it.
- Need to create minimal test case to debug.
- Fixed bug in renderElement, it wasn't creating a flatTreeRoot for itself to be used by all its children.
- Implementation seems to be working.
- Yay.
- Updated resizing siblings example to use colours and more functional JS to be generic for a list of colours.
- Made write() check for primitive equality and not notify watchers if no change.
- Made array() join up consecutive strings.
- Implemented htmlIf, htmlSwitch and htmlMap in terms of htmlRead.
- Added a null template for if to use, could have used empty array but decided to support null.
- Created dogCat example that uses all htmlX branching templates.
- Seems to just work.
- Added htmlMapRead() vs htmlMap().
- htmlMap's item template function takes an item proxy while htmlMapRead takes concrete items.
- htmlMap would be used if the items should continue to be independently reactive to changes in the items.
# 2023-04-05
- Trying implementation.
- Shape of the FlatNodeTree interface unknown, working it out.
- Not quite sure what each render function's responsibilities are re creating, clearing, adding to, updating the FlatNodeTree.
- Example:
- Template:
- [htmlMap(model.as), htmlMap(model.bs)]
- htmlMap should use the identity function as the default consumer function.
- Good for auto reading inner proxy values.
- Expected FlatNodeTree construction:
- null render()
- [] renderArray()
- [[]] renderHtmlMap()
- [[a0]] renderProxy()
- [[a0, a1]] renderProxy()
- [[a0, a1], []] renderHtmlMap()
- [[a0, a1], [b0]] renderProxy()
- [[a0, a1], [b0, b1]] renderProxy()
- Expected update to model.as as [a0]:
- [[a0, a1], [b0, b1]] renderHtmlMap()
- [[a0, a1], [b0, b1]] remove dom nodes [a0, a1]
- [[a0], [b0, b1]] set [0] to [a0]
- [[a0], [b0, b1]] insert dom nodes of [a0] behind b0
- Maybe it would be good to build up the FlatNodeTree before inserting it into the DOM.
- How does this mesh with watched proxy update re-renders?
- Experiment with an attach phase separate from template instantiation phase.
- This is kind of like a virtual DOM now.
- Not convinced this is necessary.
- Trying implementing each render function and waiting to see a pattern to abstract out of all of them.
- Added insertBefore parameter to save on looking up the next node.
- Implemented "find next node" in the list tree.
- Added number type as supported by renderString.
# 2023-04-03
- Returning a FlatNodeTree isn't enough.
- How to find which node to insertBefore?
- Pathological case:
- [[NodeA], [], [], [], [NodeC]] -> [[NodeA], [], [NodeB], [], [NodeC]]
- Inserting NodeB needs to search across multiple siblings to find NodeC to insert before.
- Update render() to take a FlatNodeTree and an index path into it where it should live.
- Unfortunate cost of an index path array for every call.
# 2023-04-01
- Current re-render implementation incorrect.
- New nodes are always appended to the container.
- Need to replace in place.
- Instead of removing all nodes use replacement and insertion based on the existing list.
- Node has insertBefore() and nextSibling and replaceChild.
# 2023-03-31
- Came up with idea for tracking flat elements in the tree of template instantiations.
- Have render() return a live list of nodes it created.
- If the template instantiation rerenders itself it will update its list.
- The outer caller of the render can clear this list when it wants to do an outer re-render.
- This list is really a tree. It's either a single node or a list of lists or nodes.
- type NodeTree = Array<NodeTree> | Node;
- Implemented this and it seems to work!
- Far far simpler than the index span approach I was attempting before.
- Fits with the Node.removeChild(node) API which doesn't take an index.
- This API seems like it would be slow for large numbers of elements (quadratic).
- Maybe elements know their index?
- If they recorded that data then as things were removed they'd need to update many element indexes.
- No easy alternative to remove a large batch of elements it seems.
- Seems more straightforward to support inplace updating (rather than wipe and rerender) for list proxies.
- Test examples
- Currently have dedicated divs in the index.html.
- Could be rendering into their own created divs.
- Compose examples together in one larger test render example that splits them into separate columns.
- Omg it works really well.
- onCreate
- Added callback parameter to element template to be called once created.
- Used to let template functions control the rendered template elements before they're instantiated.
- Used in Dog cow example to access a debug div and set its textContent on an interval.
- A bit dangerous in terms of memory leaks, no clean up callback currently should the element be replaced by another one.
- Template literals for proxies
- Added array() function to use as template literal like array`Hello ${model.name}`.
- Turns the template literal into an array of the string and values in order specified.
- Useful for splicing strings between proxies and anything else.
# 2023-03-28
- Created tree example instead of dogs.
- Just uses functions, arrays and strings.
- These should be suitable primitives to work out this flat nesting.
- Came up with htmlRead.
- Function was too limited.
- It would read and create a template in the same block scope.
- This meant that all the inner reads were part of the top level read.
- HtmlRead is basically a call to watch().
- Takes a ReadingValue (value or proxy or function) to watch on.
- Takes a template consumer that consumes the read value and produces a template to be rendered.
- This way if things inside the inner templates are triggered by a model change it won't re-invoke the outer watch.
- This split is required to avoid unwanted watch triggering.
- Is that right?
- Watcher.run() puts itself on the watcher stack even for the consumer() call.
- Not sure if this is actually any different to what function rendering does...
- Actually it is, the consumer creates an htmlRead which creates a separate watch stack entry which... because read()s only add themselves to the top of the stack the outer htmlReads are untouched.
- The nested read and template callback is very very deep, was hard to write and is hard to read.
div(htmlRead(model.a, a => {
return range(a).map(i => {
return htmlRead(model.b, b => {
return range(b).map(j => {
return htmlRead(model.c, c => {
return range(c).map(k => {
return div(`a:${i} b:${j} c:${k}`);
});
});
});
});
});
})),
- htmlMap should fix the readability here by hiding the map() call.
htmlMap(model.aList, a => {
htmlMap(model.bList, b => {
htmlMap(model.cList, c => {
div(read`a:${a} b:${b} c:${c}`);
});
});
});
- Not entirely the same thing but.
# 2023-03-08
- Pulled dogcow example out into separate function to preserve while other examples are created.
- Started creating a data type to store on the container element to keep track of template instantiation segments.
- Unsure if it should be a tree structure or flat.
- If it's flat it will be a tree structure anyway with parent pointers.
- Should probably just be a tree, this makes subtree updates easier.
- Keeping track of the span tree and where the span nodes exist as elements in the container is tricky.
# 2023-03-07
- Template types.
- Came up with a few more types to support.
- String: Needed for element children since they can be text nodes.
- Function: Needed for reactive strings, should be able to support being any kind of template type.
- Proxy: Shorthand for reading the proxy, should behave like a reactive string.
- Array: Since branch template nodes can flat insert an arbitrary number of children it should also be possible with literals (not reading from a proxy), as in to hard code a list of templates to flat inject in as children.
- Example usage:
render(app, [
'Dogs',
htmlMap(model.dogs, dog => [
read`Dog ${dog.name} is ${dog.size} big.`,
htmlMap(dog.legs, leg => leg),
]),
]);
- Full set of template types:
- Singular:
- Element
- String
- Proxy
- Plural:
- htmlIf
- htmlSwitch
- htmlMap
- Array
- Function
- Plural types:
- Inject their child templates into their parent's element, which may be their parent's parent's parent's element etc.
- Need to be able to update their child templates in place amongst all the other flat mapped elements.
- Function is probably the most general form of the plurals
# 2023-03-06
- Refactored ObservableJsonProxy to store all its internals in the handler and have a dummy object as the target instead.
- The handler is now instantiated for each proxy rather than being shared.
- This means the logic and data aren't split up and the handler and it can be written like a regular class.
- Renamed the handler to be ProxyInternal.
- Removed "internals" as a singular term as it made having sets of ProxyInternals difficult to name.
- Made Watcher contain a set of ProxyInternals rather than a set of Proxies, it had no need for the outer Proxy object.
- Split obserable-json.js file in two sections, public and private.
- Started attempting to implement htmlMap.
- Added childrenLog to container element to track what index the htmlMap child nodes start at and how many there are.
- Can be used to replace existing children with new ones later when watch() retriggers.
- Ran into problem, htmlMap's child templates could be more htmlMaps.
- Need to represent this nested structure somehow to ensure the nested maps get cleaned up properly.
# 2023-03-05
- Removed global notifyingWatchers and notifyingWatchersWaitingRoom in favour of resetting the internals.watchers and saving the set to iterate over as a local variable.
- Not 100% sure it's okay to clear the internals.watchers here but it probably should be okay.
- Much better than having those two globals used in 3 places.
- No this adds a bug. When watchers are removed from the proxy they won't be removed from the notifyingWatchers set.
- Maybe just need to pop from this set instead of looping over it.
- Implemented this.
- Added TS types for observable-json.js.
- Project name idea: Render Observable JSON (ROJ).
- Renamed rendering.js to render.js to match.
- Fixed up naming of proxy internals for consistency.
- Removed the lockAccessing() and lockMutating calls in render(), it would be nice to have but eh, it's nicer to avoid the layering and having to have two functions named so similarly. Add it back if it's really needed.
- No more lock on accessing anymore, deleted that code.
- Inlined lockMutating() into watch() and notifyWatchers(), no more lock methods.
- Made render() handle all template values, not just element templates.
- Make it append the template to the container element.
- Managing containers' templated children.
- Add an internal value to the element to track the range of children that different child templates manage.
- As child templates are rerendered they can use this data to remove/re-order the children they originally appended.
- Removed the use of popKeys(), it was mutating the original template which would bite us later as we try to re-render these templates.
- Implemented waiting until the next animation before notifying watchers.
# 2023-02-27 Monday
- Added watcher tree view.
- Added notify count to proxies and run count to watchers for debug print.
- Confirmed mutations on proxies that used to be watched doesn't notify anything and shouldn't run UI mutating code once hooked up with rendering.
# 2023-02-23 Thursday
- Split up the reactive code.
- Pulled JSON observation into observable-json.js, includes reading, mutation and watching.
- Pulled rendering into rendering.js that mainly calls watch().
- Implemented generic nested watching.
- Seem to need fancy htmlBranches to test it with DOM.
- Can test it out on just style though.
- Made dog cow style demo, seems to work.
- Oops it doesn't work, I read the values in the style object creation function instead of making the property values nested functions themselves.
- Adding actual watch nesting shows it doesn't work, the watchers accumulate infinitely and old watchers erroneously execute. They're not removing properly.
- Created debug output to monitor number of watchers.
# 2023-02-21 Tuesday
- Created helper function watch().
- Takes two parameters:
- A readingValue which may be a JSON proxy to be read, a function that read()s a proxy object or a normal value.
- A setter function that's called whenever the readingValue is evaluated.
- The readingValue gets re-evaluated whenever a mutation happens on anything it read().
- Registers the setter as a write observer for any proxy value that gets read.
- Noticed a generalisation over htmlBranch observations.
- This applies to the style property on an element, the style value could be a function and so could the inner style property values.
- The inner style property values are dependent on the outer style value computation and need to be wiped if the outer computation gets redone.
- The generalisation is in nested calls to watch() within the setter function.
- This is a primitive of the JSON proxy separate to HTML rendering.
- This is very similar to an effect in Solid JS, not sure if effects can be nested.
# 2023-02-16 Thursday
- Render observation updating.
- HTML render output is a tree.
- Not of DOM nodes, more fine grained, nodes are the values on the DOM elements themselves as well as child DOM nodes.
- E.g. the value of CSS properties and XML attributes in addition to the DOM children.
- Nested content with nested observations.
- Every observation corresponds to a node in the tree getting re-rendered and replacing the previous node.
- Need to ensure observation notifications happen top down in the tree.
- Natural DFS registration is probably fine?
- How do element events work with model observer registration?
- Hopefully fine to just replace them whenever they update like any other render tree node.
- The entire subtree needs cleaning up on re-render.
- Need to be able to wipe those inner observers so they don't fire if they're listening to the same thing.
- Need data structure of observers on model to reflect render tree.
- Maybe model points back to template nodes?
- What does branching look like in the template?
- Need if, switch and map (list and dict).
- Element is {...}.
- Branch point can be class instance.
- htmlIf(condition, trueBranch, falseBranch=null);
- htmlSwitch(value, { value: branch, ... });
- htmlList(list, item => branch);
- Filters on the list?
- sort, map, filter.
- htmlMap(object, ([key, value]) => branch);
- Example:
const model = createObservableJson({
mode: 'pony',
ponies: [{
name: 'twigl',
attack: 100,
}, {
name: 'flutpants',
attack: 300,
thievery: 86,
}],
barks: 6,
});
render(container, () => group(
h1(() => capitalise(read(model.mode)), ' mode'),
htmlSwitch(model.mode, {
pony: group(
group('You are ambushed by ', model.ponies.length, ' ponies.'),
htmlList(model.ponies, pony => group(
group(pony.name, ' hits you for ', pony.attack, ' damage.'),
htmlIf(
() => (read(pony.thievery) ?? 0) > 0,
group(pony.name, ' steals ', pony.thievery, ' coins.'),
),
),
),
dog: group(
'Dog go ',
() => 'bark '.repeat(read(model.barks)),
),
}
));
- And again with $ at the start of each observation/rerender point:
render(container, () => group(
h1($ () => capitalise(read(model.mode)), ' mode'),
$ htmlSwitch(model.mode, {
pony: group(
group('You are ambushed by ', $ model.ponies.length, ' ponies.'),
$ htmlList(model.ponies, pony => group(
group($ pony.name, ' hits you for ', $ pony.attack, ' damage.'),
$ htmlIf(
() => (read(pony.thievery) ?? 0) > 0,
group($ pony.name, ' steals ', $ pony.thievery, ' coins.'),
),
),
),
dog: group(
'Dog go ',
$ () => 'bark '.repeat(read(model.barks)),
),
}
));
- Rerender points appear at every model proxy, lambda and htmlBranch node.
- Rerender observation tree for the active model:
$0 model.mode
$1 model.mode
$2 model.ponies.length
$3 model.ponies
$4 model.ponies[0]
$5 model.ponies[0].name
$6 model.ponies[0].attack
$7 model.ponies[0].thievery
$8 model.ponies[1]
$9 model.ponies[1].name
$10 model.ponies[1].attack
$11 model.ponies[1].thievery
$12 model.ponies[1].name
$13 model.ponies[1].thievery
- thievery is used at two levels in ponies[1], $11 and $13.
- Changes to $11 should wipe out $13 since that render node will be rerendered entirely and a new observation will be established.
- How to structure the observation registrations to enable render subtree clearing?
- Model tree with observations:
const model = createObservableJson({
mode: 'pony', $0 $1
ponies: [ $3
{ $4
name: 'twigl', $5
attack: 100, $6
thievery: undefined, $7
}, { $8
name: 'flutpants', $9 $12
attack: 300, $10
thievery: 86, $11 $13
}
],
barks: 6,
});
- Perhaps the observations at each model node can be its own tree and invoking each one returns whether to wipe the subtree or invoke it.
- The problem with this is the observation subtree can be for different points in the model rather than the one being mutated.
- A mutation at one point in the model tree needs to clear observations of a different part of the model tree based on the observation tree.
- The observation tree is like a less granular version of the render tree.
- How best to wipe the subtree of observations from the model?
- Maybe start with an expensive solution for now. Store lots of references to observations everywhere.
- Model with heavy weight observation data where $n{$a, $b, $c} is an observation $n with references to its immediate subtree children $a, $b, $c:
const model = createObservableJson({
mode: 'pony', $0{} $1{$2, $3}
ponies: [ $3{$4, $8}
{ $4{$5, $6, $7}
name: 'twigl', $5{}
attack: 100, $6{}
thievery: undefined, $7{}
}, { $8{$9, $10, $11}
name: 'flutpants', $9{} $12{}
attack: 300, $10{}
thievery: 86, $11{$12, $13} $13{}
}
],
barks: 6,
});
- When a model node mutates it invokes its observations which return whether to wipe the sub observations from the rest of the model.
- It may not wipe e.g. for an htmlIf condition that doesn't change its value even though the model it reads from changes e.g. htmlIf(() => read(model.value) > 10) is true/false for many values.
- Either the sub observation references will need to point to the proxy on which the observations live or all observations have a back link to the proxy on which they live.
- When there are multiple batched mutations at the same time how to know which observation to trigger first?
- Want to trigger the highest one.
- Maybe doesn't have to be highest of them all, just has to be a root, any root, probably.
- Perhaps observation references need back links to the observation referencing them.
- Do all observations have only one parent referencing observation? Probably, due to tree shape of observations.
- All htmlBranch observations are what define subtrees of other observations as they are the only thing that can cause a render branch to be deleted/replaced.
# 2023-02-10 Friday
- Goal: Solid JS but with JS DOM API instead of XML parsing and with signals being entire JSON objects that can be observed at any inner level.