added a new way for native DOM <-> virtual DOM interop, see nativenodes.nim example

This commit is contained in:
Araq 2018-12-12 15:02:58 +01:00
commit 18b5a12d1e
5 changed files with 36 additions and 30 deletions

View file

@ -1 +1,2 @@
--path: "../karax" --path: "../karax"
--path: ".."

View file

@ -0,0 +1,18 @@
include karax / prelude
import karax / kdom
proc myInput: VNode =
result = buildHtml:
input()
var inp = vnodeToDom(myInput())
proc myAwesomeComponent(x: Node): VNode =
result = dthunk(x)
proc main: VNode =
result = myAwesomeComponent(inp)
setRenderer main

View file

@ -8,18 +8,15 @@ import macros, vdom, tables, strutils, kbase
when defined(js): when defined(js):
var var
vcomponents* = newJDict[cstring, proc(args: seq[VNode]): VNode]() vcomponents* = newJDict[cstring, proc(args: seq[VNode]): VNode]()
dcomponents* = newJDict[cstring, proc(args: seq[VNode]): Node]()
else: else:
var var
vcomponents* = newTable[kstring, proc(args: seq[VNode]): VNode]() vcomponents* = newTable[kstring, proc(args: seq[VNode]): VNode]()
dcomponents* = newTable[kstring, proc(args: seq[VNode]): Node]()
type type
ComponentKind* {.pure.} = enum ComponentKind* {.pure.} = enum
None, None,
Tag, Tag,
VNode, VNode
Node
var var
allcomponents {.compileTime.} = initTable[string, ComponentKind]() allcomponents {.compileTime.} = initTable[string, ComponentKind]()
@ -84,10 +81,8 @@ when defined(js):
var isvirtual = ComponentKind.None var isvirtual = ComponentKind.None
if rettype == "VNode": if rettype == "VNode":
isvirtual = ComponentKind.VNode isvirtual = ComponentKind.VNode
elif rettype == "Node":
isvirtual = ComponentKind.Node
else: else:
error "component must return VNode or Node", params[0] error "component must return VNode", params[0]
let realName = if name.kind == nnkPostfix: name[1] else: name let realName = if name.kind == nnkPostfix: name[1] else: name
let nn = $realName let nn = $realName
n[0] = ident("inner" & nn) n[0] = ident("inner" & nn)
@ -105,26 +100,15 @@ when defined(js):
proc pname(args: seq[VNode]): VNode = proc pname(args: seq[VNode]): VNode =
unpackCall unpackCall
template dwrapper(pname, unpackCall) {.dirty.} =
proc pname(args: seq[VNode]): Node =
unpackCall
template vregister(key, val) = template vregister(key, val) =
bind jdict.`[]=` bind jdict.`[]=`
`[]=`(vcomponents, kstring(key), val) `[]=`(vcomponents, kstring(key), val)
template dregister(key, val) =
bind jdict.`[]=`
`[]=`(dcomponents, kstring(key), val)
result = newTree(nnkStmtList, n) result = newTree(nnkStmtList, n)
if isvirtual == ComponentKind.VNode: if isvirtual == ComponentKind.VNode:
result.add getAst(vwrapper(newname name, unpackCall)) result.add getAst(vwrapper(newname name, unpackCall))
result.add getAst(vregister(newLit(nn), realName)) result.add getAst(vregister(newLit(nn), realName))
else:
result.add getAst(dwrapper(newname name, unpackCall))
result.add getAst(dregister(newLit(nn), realName))
allcomponents[nn] = isvirtual allcomponents[nn] = isvirtual
when defined(debugKaraxDsl): when defined(debugKaraxDsl):
echo repr result echo repr result

View file

@ -123,7 +123,7 @@ template attach(n: VNode) =
n.dom = result n.dom = result
if n.id != nil: kxi.byId[n.id] = n if n.id != nil: kxi.byId[n.id] = n
proc applyEvents(n: VNode; kxi: KaraxInstance) = proc applyEvents(n: VNode) =
let dest = n.dom let dest = n.dom
for i in 0..<len(n.events): for i in 0..<len(n.events):
n.events[i][2] = wrapEvent(dest, n, n.events[i][0], n.events[i][1]) n.events[i][2] = wrapEvent(dest, n, n.events[i][0], n.events[i][1])
@ -134,7 +134,7 @@ proc getVNodeById*(id: cstring; kxi: KaraxInstance = kxi): VNode =
if kxi.byId.contains(id): if kxi.byId.contains(id):
result = kxi.byId[id] result = kxi.byId[id]
proc vnodeToDom*(n: VNode; kxi: KaraxInstance): Node = proc vnodeToDom*(n: VNode; kxi: KaraxInstance = nil): Node =
if n.kind == VNodeKind.text: if n.kind == VNodeKind.text:
result = document.createTextNode(n.text) result = document.createTextNode(n.text)
attach n attach n
@ -150,7 +150,8 @@ proc vnodeToDom*(n: VNode; kxi: KaraxInstance): Node =
attach n attach n
return result return result
elif n.kind == VNodeKind.dthunk: elif n.kind == VNodeKind.dthunk:
result = callThunk(dcomponents[n.text], n) result = n.dom #callThunk(dcomponents[n.text], n)
assert result != nil
#n.key = result.key #n.key = result.key
attach n attach n
return result return result
@ -182,8 +183,8 @@ proc vnodeToDom*(n: VNode; kxi: KaraxInstance): Node =
for k, v in attrs(n): for k, v in attrs(n):
if v != nil: if v != nil:
result.setAttr(k, v) result.setAttr(k, v)
applyEvents(n, kxi) applyEvents(n)
if n == kxi.toFocusV and kxi.toFocus.isNil: if kxi != nil and n == kxi.toFocusV and kxi.toFocus.isNil:
kxi.toFocus = result kxi.toFocus = result
if not n.style.isNil: applyStyle(result, n.style) if not n.style.isNil: applyStyle(result, n.style)
@ -194,7 +195,7 @@ proc same(n: VNode, e: Node; nesting = 0): bool =
elif n.kind == VNodeKind.verbatim: elif n.kind == VNodeKind.verbatim:
result = true result = true
elif n.kind == VNodeKind.vthunk or n.kind == VNodeKind.dthunk: elif n.kind == VNodeKind.vthunk or n.kind == VNodeKind.dthunk:
# we don't check these for now: # we don't check these:
result = true result = true
elif toTag[n.kind] == e.nodename: elif toTag[n.kind] == e.nodename:
result = true result = true
@ -245,11 +246,13 @@ proc eq(a, b: VNode): EqResult =
if a.text != b.text: if a.text != b.text:
when defined(profileKarax): inc reasons[deText] when defined(profileKarax): inc reasons[deText]
return different # similar return different # similar
elif a.kind == VNodeKind.vthunk or a.kind == VNodeKind.dthunk: elif a.kind == VNodeKind.vthunk:
if a.text != b.text: return different if a.text != b.text: return different
if a.len != b.len: return different if a.len != b.len: return different
for i in 0..<a.len: for i in 0..<a.len:
if eq(a[i], b[i]) == different: return different if eq(a[i], b[i]) == different: return different
elif a.kind == VNodeKind.dthunk:
return identical
elif a.kind == VNodeKind.verbatim: elif a.kind == VNodeKind.verbatim:
if a.text != b.text: if a.text != b.text:
return different return different
@ -302,7 +305,7 @@ proc mergeEvents(newNode, oldNode: VNode; kxi: KaraxInstance) =
else: toEventName[k] else: toEventName[k]
d.removeEventListener(name, oldNode.events[i][2]) d.removeEventListener(name, oldNode.events[i][2])
shallowCopy(oldNode.events, newNode.events) shallowCopy(oldNode.events, newNode.events)
applyEvents(oldNode, kxi) applyEvents(oldNode)
when false: when false:
proc printV(n: VNode; depth: cstring = "") = proc printV(n: VNode; depth: cstring = "") =

View file

@ -14,13 +14,13 @@ type
VNodeKind* {.pure.} = enum VNodeKind* {.pure.} = enum
text = "#text", int = "#int", bool = "#bool", text = "#text", int = "#int", bool = "#bool",
vthunk = "#vthunk", dthunk = "#dthunk", vthunk = "#vthunk", dthunk = "#dthunk",
component = "#component", verbatim="#verbatim", component = "#component", verbatim = "#verbatim",
html, head, title, base, link, meta, style, html, head, title, base, link, meta, style,
script, noscript, script, noscript,
body, section, nav, article, aside, body, section, nav, article, aside,
h1, h2, h3, h4, h5, h6, h1, h2, h3, h4, h5, h6,
header, footer, address, main header, footer, address, main,
p, hr, pre, blockquote, ol, ul, li, p, hr, pre, blockquote, ol, ul, li,
dl, dt, dd, dl, dt, dd,
@ -167,8 +167,8 @@ template callThunk*(fn: typed; n: VNode): untyped =
proc vthunk*(name: kstring; args: varargs[VNode, vn]): VNode = proc vthunk*(name: kstring; args: varargs[VNode, vn]): VNode =
VNode(kind: VNodeKind.vthunk, text: name, index: -1, kids: @args) VNode(kind: VNodeKind.vthunk, text: name, index: -1, kids: @args)
proc dthunk*(name: kstring; args: varargs[VNode, vn]): VNode = proc dthunk*(dom: Node): VNode =
VNode(kind: VNodeKind.dthunk, text: name, index: -1, kids: @args) VNode(kind: VNodeKind.dthunk, dom: dom)
proc setEventIfNoConflict(v: VNode; kind: EventKind; handler: EventHandler) = proc setEventIfNoConflict(v: VNode; kind: EventKind; handler: EventHandler) =
assert handler != nil assert handler != nil