From 823aaa2c52b3e67acc5785a10cf884dde63bdbf8 Mon Sep 17 00:00:00 2001 From: Brian Carroll Date: Wed, 21 Dec 2022 20:22:12 +0000 Subject: [PATCH] virtual-dom: create a Patch tag union --- examples/virtual-dom-wip/platform/Effect.roc | 18 ++++---- .../platform/Html/Internal.roc | 10 ++--- .../virtual-dom-wip/platform/Html/Patch.roc | 43 +++++++++++++++++++ .../platform/src/client-side/host.js | 22 +++------- 4 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 examples/virtual-dom-wip/platform/Html/Patch.roc diff --git a/examples/virtual-dom-wip/platform/Effect.roc b/examples/virtual-dom-wip/platform/Effect.roc index 9da4558031..c1b2106944 100644 --- a/examples/virtual-dom-wip/platform/Effect.roc +++ b/examples/virtual-dom-wip/platform/Effect.roc @@ -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 {} diff --git a/examples/virtual-dom-wip/platform/Html/Internal.roc b/examples/virtual-dom-wip/platform/Html/Internal.roc index b51aa0afb2..b0003ae94c 100644 --- a/examples/virtual-dom-wip/platform/Html/Internal.roc +++ b/examples/virtual-dom-wip/platform/Html/Internal.roc @@ -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 } diff --git a/examples/virtual-dom-wip/platform/Html/Patch.roc b/examples/virtual-dom-wip/platform/Html/Patch.roc new file mode 100644 index 0000000000..7f92fd6d4c --- /dev/null +++ b/examples/virtual-dom-wip/platform/Html/Patch.roc @@ -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 diff --git a/examples/virtual-dom-wip/platform/src/client-side/host.js b/examples/virtual-dom-wip/platform/src/client-side/host.js index 6d6755f111..82fdc2bd7c 100644 --- a/examples/virtual-dom-wip/platform/src/client-side/host.js +++ b/examples/virtual-dom-wip/platform/src/client-side/host.js @@ -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