virtual-dom: create a Patch tag union

This commit is contained in:
Brian Carroll 2022-12-21 20:22:12 +00:00
parent 0cf9ba647c
commit 823aaa2c52
No known key found for this signature in database
GPG Key ID: 5C7B2EC4101703C0
4 changed files with 64 additions and 29 deletions

View File

@ -1,12 +1,15 @@
hosted Effect
exposes [
Effect,
NodeId,
EventHandlerId,
TagName,
AttrType,
EventType,
after,
always,
map,
NodeId,
EventHandlerId,
eventHandlerId,
createElement,
createTextNode,
updateTextNode,
@ -24,22 +27,21 @@ hosted Effect
imports []
generates Effect with [after, always, map]
# TODO: private type
# TODO: private types
NodeId : Nat
EventHandlerId := Nat
eventHandlerId = \id -> @EventHandlerId id
EventHandlerId : Nat
# TODO: make these tag unions to avoid encoding/decoding standard names
# but for now, this is much easier to code and debug!
TagName : Str
AttrType : Str
EventType : Str
## createElement tagName
createElement : TagName -> Effect NodeId
createElement : NodeId, TagName -> Effect {}
## createTextNode content
createTextNode : Str -> Effect NodeId
createTextNode : NodeId, Str -> Effect {}
## updateTextNode content
updateTextNode : NodeId, Str -> Effect {}

View File

@ -515,7 +515,8 @@ createSubTree = \previousEffects, node ->
{ newHandlers, renderedNodes } <- previousEffects |> Effect.after
when node is
Element name size attrs children ->
nodeIndex <- Effect.createElement name |> Effect.after
nodeIndex = 0 # TODO: temporary hacks
_ <- Effect.createElement nodeIndex name |> Effect.after
{ style, newHandlers: newHandlersAttrs, renderedAttrs, effects: attrEffects } =
List.walk attrs { nodeIndex, style: "", newHandlers, renderedAttrs: [], effects: Effect.always {} } addAttribute
@ -533,10 +534,9 @@ createSubTree = \previousEffects, node ->
}
Text content ->
Effect.createTextNode content
|> Effect.map \nodeIndex ->
{ newHandlers, renderedNodes: List.append renderedNodes (RenderedText nodeIndex content) }
nodeIndex = 0 # TODO: temporary hacks
_ <- Effect.createTextNode nodeIndex content |> Effect.after
Effect.always { newHandlers, renderedNodes: List.append renderedNodes (RenderedText nodeIndex content) }
None -> Effect.always { newHandlers, renderedNodes: List.append renderedNodes RenderedNone }

View File

@ -0,0 +1,43 @@
interface Html.Patch
exposes [
Patch,
]
imports [
Effect.{
Effect,
NodeId,
EventHandlerId,
TagName,
AttrType,
EventType,
},
]
Patch : [
CreateElement NodeId TagName,
CreateTextNode NodeId Str,
UpdateTextNode NodeId Str,
AppendChild NodeId NodeId,
RemoveNode NodeId,
SetAttribute NodeId AttrType Str,
RemoveAttribute NodeId AttrType,
SetProperty NodeId Str (List U8),
RemoveProperty NodeId Str,
SetListener NodeId EventType EventHandlerId,
RemoveListener NodeId EventType,
]
apply : Patch -> Effect {}
apply = \patch ->
when patch is
CreateElement nodeId tagName -> Effect.createElement nodeId tagName
CreateTextNode nodeId content -> Effect.createTextNode nodeId content
UpdateTextNode content -> Effect.updateTextNode content
AppendChild parentId childId -> Effect.appendChild parentId childId
RemoveNode id -> Effect.removeNode id
SetAttribute nodeId attrName value -> Effect.setAttribute nodeId attrName value
RemoveAttribute nodeId attrName -> Effect.removeAttribute nodeId attrName
SetProperty nodeId propName json -> Effect.setProperty nodeId propName json
RemoveProperty nodeId propName -> Effect.removeProperty nodeId propName
SetListener nodeId eventType handlerId -> Effect.setListener nodeId eventType handlerId
RemoveListener nodeId eventType -> Effect.removeListener nodeId eventType

View File

@ -30,20 +30,22 @@ const roc_init = async (initData, wasmUrl) => {
const effects = {
/**
* @param {number} tagAddr
* @param {number} id
*/
createElement: (tagAddr) => {
createElement: (tagAddr, id) => {
const tagName = decodeRocStr(tagAddr);
const node = document.createElement(tagName);
return insertNode(node);
nodes[id] = node;
},
/**
* @param {number} contentAddr
* @param {number} id
*/
createTextNode: (contentAddr) => {
createTextNode: (contentAddr, id) => {
const content = decodeRocStr(contentAddr);
const node = document.createTextNode(content);
return insertNode(node);
nodes[id] = node;
},
/**
@ -239,18 +241,6 @@ const roc_init = async (initData, wasmUrl) => {
return utf8Decoder.decode(bytes);
};
/**
* @param {Node} node
*/
const insertNode = (node) => {
let i = 0;
for (; i < nodes.length; i++) {
if (!nodes[i]) break;
}
nodes[i] = node;
return i;
};
/**
* @param {CyclicStructureAccessor} accessor
* @param {any} structure