diff --git a/haxe_libraries/coconut.data.hxml b/haxe_libraries/coconut.data.hxml index 4cd16f2..27a45cb 100644 --- a/haxe_libraries/coconut.data.hxml +++ b/haxe_libraries/coconut.data.hxml @@ -1,8 +1,7 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.data#587d2c2dbc57cc24ecb52303c5e22eb97fed12cd" into coconut.data/0.12.1/github/587d2c2dbc57cc24ecb52303c5e22eb97fed12cd +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.data#ca17dc7efb408b8032116493fb2e02f362382956" into coconut.data/0.12.1/github/ca17dc7efb408b8032116493fb2e02f362382956 -lib tink_anon -lib tink_priority -lib tink_pure -lib tink_state --cp ${HAXE_LIBCACHE}/coconut.data/0.12.1/github/587d2c2dbc57cc24ecb52303c5e22eb97fed12cd/src --D coconut.data=0.12.1 ---macro coconut.data.macros.Setup.run() \ No newline at end of file +-cp ${HAXE_LIBCACHE}/coconut.data/0.12.1/github/ca17dc7efb408b8032116493fb2e02f362382956/src +-D coconut.data=0.12.1 \ No newline at end of file diff --git a/haxe_libraries/coconut.diffing.hxml b/haxe_libraries/coconut.diffing.hxml index 8b2cab8..de58808 100644 --- a/haxe_libraries/coconut.diffing.hxml +++ b/haxe_libraries/coconut.diffing.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.diffing#867b48ea374077d1ff15b05de4e07430637217ea" into coconut.diffing/0.2.1/github/867b48ea374077d1ff15b05de4e07430637217ea +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.diffing#499d62647c2ff68ad1336a311005f9f9d8cdf332" into coconut.diffing/0.5.0/github/499d62647c2ff68ad1336a311005f9f9d8cdf332 -lib coconut.ui --cp ${HAXE_LIBCACHE}/coconut.diffing/0.2.1/github/867b48ea374077d1ff15b05de4e07430637217ea/src --D coconut.diffing=0.2.1 \ No newline at end of file +-cp ${HAXE_LIBCACHE}/coconut.diffing/0.5.0/github/499d62647c2ff68ad1336a311005f9f9d8cdf332/src +-D coconut.diffing=0.5.0 \ No newline at end of file diff --git a/haxe_libraries/coconut.react-core.hxml b/haxe_libraries/coconut.react-core.hxml index 30d01c6..47f6224 100644 --- a/haxe_libraries/coconut.react-core.hxml +++ b/haxe_libraries/coconut.react-core.hxml @@ -1,8 +1,8 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-core#e2d2eab146d79940dfd253700efb94ad033504ca" into coconut.react-core/0.2.2/github/e2d2eab146d79940dfd253700efb94ad033504ca +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-core#84f0f5b150699de2e27ce2e19c9063d1a1ba3732" into coconut.react-core/0.3.0/github/84f0f5b150699de2e27ce2e19c9063d1a1ba3732 -lib coconut.ui -lib react-next -lib tink_priority --cp ${HAXE_LIBCACHE}/coconut.react-core/0.2.2/github/e2d2eab146d79940dfd253700efb94ad033504ca/src --D coconut.react-core=0.2.2 +-cp ${HAXE_LIBCACHE}/coconut.react-core/0.3.0/github/84f0f5b150699de2e27ce2e19c9063d1a1ba3732/src +-D coconut.react-core=0.3.0 --macro coconut.react.macros.Setup.all() -D coconut_react_core \ No newline at end of file diff --git a/haxe_libraries/coconut.react-dom.hxml b/haxe_libraries/coconut.react-dom.hxml index fb6ddca..ff8ae07 100644 --- a/haxe_libraries/coconut.react-dom.hxml +++ b/haxe_libraries/coconut.react-dom.hxml @@ -1,6 +1,6 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-dom#23744776318ac391d8613d521649660253e11964" into coconut.react-dom/0.1.0/github/23744776318ac391d8613d521649660253e11964 +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.react-dom#f569d03939e1b6035d7453723ef66e97deb410b1" into coconut.react-dom/0.3.0/github/f569d03939e1b6035d7453723ef66e97deb410b1 -lib coconut.react-core --lib xDOM --cp ${HAXE_LIBCACHE}/coconut.react-dom/0.1.0/github/23744776318ac391d8613d521649660253e11964/src --D coconut.react-dom=0.1.0 ---macro coconut.react.macros.Html.registerTags() \ No newline at end of file +-lib tink_domspec +-cp ${HAXE_LIBCACHE}/coconut.react-dom/0.3.0/github/f569d03939e1b6035d7453723ef66e97deb410b1/src +-D coconut.react-dom=0.3.0 +--macro coconut.react.Html.init() \ No newline at end of file diff --git a/haxe_libraries/coconut.vdom.hxml b/haxe_libraries/coconut.vdom.hxml index 2c8611b..1280eeb 100644 --- a/haxe_libraries/coconut.vdom.hxml +++ b/haxe_libraries/coconut.vdom.hxml @@ -1,5 +1,5 @@ -# @install: lix --silent download "gh://github.com/MVCoconut/coconut.vdom#98cb1bf86b63312f3e0507f3b6e7bd79835861e6" into coconut.vdom/0.8.1/github/98cb1bf86b63312f3e0507f3b6e7bd79835861e6 +# @install: lix --silent download "gh://github.com/MVCoconut/coconut.vdom#710301040bf6da83530a182e25e24af4d4c31884" into coconut.vdom/0.10.0/github/710301040bf6da83530a182e25e24af4d4c31884 -lib coconut.diffing -lib xDOM --cp ${HAXE_LIBCACHE}/coconut.vdom/0.8.1/github/98cb1bf86b63312f3e0507f3b6e7bd79835861e6/src --D coconut.vdom=0.8.1 \ No newline at end of file +-cp ${HAXE_LIBCACHE}/coconut.vdom/0.10.0/github/710301040bf6da83530a182e25e24af4d4c31884/src +-D coconut.vdom=0.10.0 \ No newline at end of file diff --git a/haxe_libraries/tink_anon.hxml b/haxe_libraries/tink_anon.hxml index 58a2b3d..6046e27 100644 --- a/haxe_libraries/tink_anon.hxml +++ b/haxe_libraries/tink_anon.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_anon#a44bdda9caa41d461f9b0a43366ea9c320260963" into tink_anon/0.7.0/github/a44bdda9caa41d461f9b0a43366ea9c320260963 +# @install: lix --silent download "gh://github.com/haxetink/tink_anon#0277e6e3f97a7878f1aa9aeeccc4b7be0e9c82bc" into tink_anon/0.7.0/github/0277e6e3f97a7878f1aa9aeeccc4b7be0e9c82bc -lib tink_macro --cp ${HAXE_LIBCACHE}/tink_anon/0.7.0/github/a44bdda9caa41d461f9b0a43366ea9c320260963/src +-cp ${HAXE_LIBCACHE}/tink_anon/0.7.0/github/0277e6e3f97a7878f1aa9aeeccc4b7be0e9c82bc/src -D tink_anon=0.7.0 \ No newline at end of file diff --git a/haxe_libraries/tink_core.hxml b/haxe_libraries/tink_core.hxml index 13d5bed..37d612f 100644 --- a/haxe_libraries/tink_core.hxml +++ b/haxe_libraries/tink_core.hxml @@ -1,3 +1,3 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_core#83032eb4327a73d8dd90a36d720d0d30154bb300" into tink_core/2.0.1/github/83032eb4327a73d8dd90a36d720d0d30154bb300 --cp ${HAXE_LIBCACHE}/tink_core/2.0.1/github/83032eb4327a73d8dd90a36d720d0d30154bb300/src --D tink_core=2.0.1 \ No newline at end of file +# @install: lix --silent download "gh://github.com/haxetink/tink_core#f500203b657859bfde36c49e54f95a0b1fc2b165" into tink_core/2.0.2/github/f500203b657859bfde36c49e54f95a0b1fc2b165 +-cp ${HAXE_LIBCACHE}/tink_core/2.0.2/github/f500203b657859bfde36c49e54f95a0b1fc2b165/src +-D tink_core=2.0.2 \ No newline at end of file diff --git a/haxe_libraries/tink_hxx.hxml b/haxe_libraries/tink_hxx.hxml index 2739de7..9a6edb0 100644 --- a/haxe_libraries/tink_hxx.hxml +++ b/haxe_libraries/tink_hxx.hxml @@ -1,6 +1,6 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#0d6cda883d5ef4c1186dbad476e016b98aad68b8" into tink_hxx/0.25.0/github/0d6cda883d5ef4c1186dbad476e016b98aad68b8 +# @install: lix --silent download "gh://github.com/haxetink/tink_hxx#783a4606516582567d9f6f12505740ba48334c39" into tink_hxx/0.25.0/github/783a4606516582567d9f6f12505740ba48334c39 -lib html-entities -lib tink_anon -lib tink_parse --cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/0d6cda883d5ef4c1186dbad476e016b98aad68b8/src +-cp ${HAXE_LIBCACHE}/tink_hxx/0.25.0/github/783a4606516582567d9f6f12505740ba48334c39/src -D tink_hxx=0.25.0 \ No newline at end of file diff --git a/haxe_libraries/tink_state.hxml b/haxe_libraries/tink_state.hxml index 58a8f3d..5a1702b 100644 --- a/haxe_libraries/tink_state.hxml +++ b/haxe_libraries/tink_state.hxml @@ -1,4 +1,4 @@ -# @install: lix --silent download "gh://github.com/haxetink/tink_state#b01eb8bd47f7264420604b5f8816dde69e5dec55" into tink_state/1.0.0-beta.3/github/b01eb8bd47f7264420604b5f8816dde69e5dec55 +# @install: lix --silent download "gh://github.com/haxetink/tink_state#9fda3b07ea27e299e7f53720d6e349787477268e" into tink_state/1.0.0-beta.3/github/9fda3b07ea27e299e7f53720d6e349787477268e -lib tink_core --cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/b01eb8bd47f7264420604b5f8816dde69e5dec55/src +-cp ${HAXE_LIBCACHE}/tink_state/1.0.0-beta.3/github/9fda3b07ea27e299e7f53720d6e349787477268e/src -D tink_state=1.0.0-beta.3 \ No newline at end of file diff --git a/haxe_libraries/travix.hxml b/haxe_libraries/travix.hxml index 29c0d68..0870b65 100644 --- a/haxe_libraries/travix.hxml +++ b/haxe_libraries/travix.hxml @@ -1,7 +1,7 @@ -# @install: lix --silent download "gh://github.com/back2dos/travix#63b230b854c6f02cf2ac04bb758c09751f28b8e8" into travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8 -# @post-install: cd ${HAXE_LIBCACHE}/travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8 && haxe -cp src --run travix.PostDownload -# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8 +# @install: lix --silent download "haxelib:/travix#0.15.0" into travix/0.15.0/haxelib +# @post-install: cd ${HAXE_LIBCACHE}/travix/0.15.0/haxelib && haxe -cp src --run travix.PostDownload +# @run: haxelib run-dir travix ${HAXE_LIBCACHE}/travix/0.15.0/haxelib -lib tink_cli --cp ${HAXE_LIBCACHE}/travix/0.15.0/github/63b230b854c6f02cf2ac04bb758c09751f28b8e8/src +-cp ${HAXE_LIBCACHE}/travix/0.15.0/haxelib/src -D travix=0.15.0 --macro travix.Macro.setup() \ No newline at end of file diff --git a/src/coconut/ui/internal/Attribute.hx b/src/coconut/ui/internal/Attribute.hx new file mode 100644 index 0000000..6fc278f --- /dev/null +++ b/src/coconut/ui/internal/Attribute.hx @@ -0,0 +1,31 @@ +package coconut.ui.internal; + +import tink.state.*; +import tink.state.internal.*; + +@:forward(value, assign) +abstract Attribute(Impl) { + + public inline function new(compute, ?comparator #if tink_state.debug , toString #end) + this = new Impl(compute, comparator); +} + +private class Impl extends AutoObservable { + final dFault:()->T; + final state:State<()->T>; + + public function new(compute:()->T, ?comparator) { + this.state = new State(this.dFault = compute); + super(() -> switch state.value { + case null: dFault(); + case f: switch f() { + case null: dFault(); + case v: v; + } + }, comparator); + } + + public function assign(c:Null<()->T>) + state.set(c); + +} \ No newline at end of file diff --git a/src/coconut/ui/internal/Children.hx b/src/coconut/ui/internal/Children.hx index 11b08b1..2071df3 100644 --- a/src/coconut/ui/internal/Children.hx +++ b/src/coconut/ui/internal/Children.hx @@ -32,4 +32,9 @@ abstract Children(Array) from Array { } @:from macro static function ofOther(e:haxe.macro.Expr); + + static final EMPTY = new Array(); + + public inline function keyValueIterator() + return (if (this != null) this else EMPTY).keyValueIterator(); } diff --git a/src/coconut/ui/internal/Controlled.hx b/src/coconut/ui/internal/Controlled.hx new file mode 100644 index 0000000..063a81e --- /dev/null +++ b/src/coconut/ui/internal/Controlled.hx @@ -0,0 +1,52 @@ +package coconut.ui.internal; + +import tink.state.*; +import tink.state.internal.*; + +@:forward(value, assign) +abstract Controlled(Impl) { + + public inline function new(compute, ?comparator) + this = new Impl(compute, comparator); +} + +private class Impl implements ObservableObject extends Dispatcher { + + final fallback:tink.core.Lazy>; + var cur:Null>; + final comparator:Comparator; + + public var value(get, set):T; + inline function get_value():T + return state().value; + + inline function set_value(param):T + return state().value = param; + + inline function state() + return switch cur { + case null: fallback.get(); + case v: v; + } + + public function new(fallback, ?comparator) { + super(); + this.comparator = comparator; + this.fallback = fallback; + } + + public function assign(c:Null>) + if (c != cur) { + cur = c; + fire(this); + } + + public function getValue():T + return state().value; + + public function isValid():Bool + return false;//TODO: implement + + public function getComparator():Comparator + return comparator; +} \ No newline at end of file diff --git a/src/coconut/ui/internal/ImplicitContext.hx b/src/coconut/ui/internal/ImplicitContext.hx index cb91426..2e2a937 100644 --- a/src/coconut/ui/internal/ImplicitContext.hx +++ b/src/coconut/ui/internal/ImplicitContext.hx @@ -1,16 +1,14 @@ package coconut.ui.internal; import tink.state.*; -import coconut.data.Value; using tink.CoreApi; #if macro using tink.MacroApi; #end - class ImplicitContext { final parent:Lazy>; - final slots = new Map, Slot>>(); + final slots = new Mapping>(); public function new(?parent) { this.parent = switch parent { @@ -20,41 +18,32 @@ class ImplicitContext { } static final ORPHAN:Lazy> = (null:ImplicitContext); - static final NONE = Observable.const(new ImplicitValues([])); public function get(key:TypeKey):Null - return switch [getSlot(key).value, parent.get()] { - case [null, null]: null; - case [null, p]: p.get(key); - case [v, _]: v; + return switch getSlot(key).value { + case null: + switch parent.get() { + case null: null; + case ctx: ctx.get(key); + } + case v: v; } function getSlot(key) return switch slots[key] { - case null: slots[key] = new Slot(this);// in theory, creating slots and never destroying them leaks ... in practice, the key set for every context should always be small and well-bound, and typically constant + case null: slots[key] = new Attribute(() -> Noise);// in theory, creating slots and never destroying them leaks ... in practice, the key set for every context should always be small and well-bound, and typically constant case v: v; } public function update(values:ImplicitValues) { - - for (k => slot in slots) - if (!values.exists(k)) slot.setData(null); - - for (k => v in values) - getSlot(k).setData(v); + slots.forEach((slot, k, _) -> if (!values.exists(k)) slot.assign(null)); + values.forEach((v, k, _) -> getSlot(k).assign(v)); } - static public macro function with(e) { - var exprs = switch e.expr { case EArrayDecl(a): a; default: [e]; }; - var entries = [for (e in exprs) switch e { - case macro $k => $v: - macro @:pos(e.pos) new coconut.ui.internal.ImplicitContext.SingleImplicit($k, $v); - default: e.reject('expected key => value'); - }]; - return macro new coconut.ui.internal.ImplicitContext.ImplicitValues([$a{entries}]); - } + static public macro function with(e); } +private typedef Mapping = tink.state.internal.ObjectMap, T>; abstract TypeKey({}) to {} { @:from static function ofClass(t:Class):TypeKey return cast t; @@ -63,19 +52,22 @@ abstract TypeKey({}) to {} { } @:pure -@:forward(exists, get, keyValueIterator) +@:forward(exists, get, forEach) @:fromHxx( transform = coconut.ui.internal.ImplicitContext.with(_) ) -abstract ImplicitValues(Map, Value>) { - public function new(a:Array) this = [for (o in a) o.key => o.val]; +abstract ImplicitValues(Mapping>) { + public function new(a:Array) { + this = new Mapping(); + for (o in a) this[o.key] = o.val; + } } class SingleImplicit { public final key:TypeKey; - public final val:Value; + public final val:tink.hxx.Expression; - public function new(key:TypeKey, val:Value) { + public function new(key:TypeKey, val:tink.hxx.Expression) { this.key = key; this.val = val; } diff --git a/src/coconut/ui/internal/ImplicitContext.macro.hx b/src/coconut/ui/internal/ImplicitContext.macro.hx new file mode 100644 index 0000000..5f925b1 --- /dev/null +++ b/src/coconut/ui/internal/ImplicitContext.macro.hx @@ -0,0 +1,21 @@ +package coconut.ui.internal; + +import haxe.macro.Expr; +using tink.MacroApi; + +class ImplicitContext { + + static function with(e:Expr) { + switch e { + case macro ($v): e = v; + default: + } + var exprs = switch e.expr { case EArrayDecl(a): a; default: [e]; }; + var entries = [for (e in exprs) switch e { + case macro $k => $v: + macro @:pos(e.pos) new coconut.ui.internal.ImplicitContext.SingleImplicit($k, function () return $v); + default: e.reject('expected key => value, but got ${e.toString()}'); + }]; + return macro new coconut.ui.internal.ImplicitContext.ImplicitValues([$a{entries}]); + } +} \ No newline at end of file diff --git a/src/coconut/ui/internal/Slot.hx b/src/coconut/ui/internal/Slot.hx deleted file mode 100644 index 1dd5d74..0000000 --- a/src/coconut/ui/internal/Slot.hx +++ /dev/null @@ -1,89 +0,0 @@ -package coconut.ui.internal; - -import tink.state.*; -import tink.state.internal.*; - -using tink.CoreApi; - -class Slot> - extends Invalidatable.Invalidator implements Invalidatable implements ObservableObject { - - var data:Container; - var link:CallbackLink; - - final defaultData:Container;//TODO: this should be lazy - #if tink_state.debug - final owner:{}; - #end - final comparator:Comparator; - - public var value(get, never):T; - inline function get_value() - return observe().value; - - public function new(owner:{}, ?comparator, ?defaultData, ?toString) { - super(toString); - #if tink_state.debug - this.owner = owner; - #end - this.comparator = comparator; - this.data = this.defaultData = defaultData; - list.ondrain = () -> link.cancel(); - list.onfill = () -> heatup(); - } - - function heatup() - if (data != null) link = data.onInvalidate(this); - - public inline function observe():Observable - return this; - - public function invalidate() - fire(); - - public function getComparator():Comparator - return comparator; - - override public function getRevision() { - var ret = revision; - if (data != null) ret *= data.getRevision(); - if (defaultData != null) ret *= defaultData.getRevision(); - return ret; - } - - public function getValue() - return switch [data, defaultData] { - case [null, null]: null; - case [v, null] | [null, v]: v.getValue(); - case [_.getValue() => ret, v]: - if (ret == null) v.getValue(); - else ret; - } - - public function isValid() - return this.data == null || this.data.isValid(); - - public function setData(data:Container) { - if (data == null) - data = defaultData; - if (data == this.data) return; - - this.data = data; - if (list.length > 0) { - link.cancel(); - heatup(); - } - fire(); - } - - #if tink_state.debug - public function getDependencies() { - var ret = new Array>(); - if (data != null) - ret.push(cast data); - if (defaultData != data && defaultData != null) - ret.push(cast defaultData); - return ret.iterator(); - } - #end -} \ No newline at end of file diff --git a/src/coconut/ui/internal/Variable.hx b/src/coconut/ui/internal/Variable.hx new file mode 100644 index 0000000..abc7a35 --- /dev/null +++ b/src/coconut/ui/internal/Variable.hx @@ -0,0 +1,14 @@ +package coconut.ui.internal; + +import tink.state.*; + +@:fromHxx( + transform = coconut.ui.internal.Variable.make(_) +) +@:forward +abstract Variable(State) from State to State { + public inline function new(init) + this = new State(init); + + static public macro function make(e); +} \ No newline at end of file diff --git a/src/coconut/ui/internal/Variable.macro.hx b/src/coconut/ui/internal/Variable.macro.hx new file mode 100644 index 0000000..d7ff8e5 --- /dev/null +++ b/src/coconut/ui/internal/Variable.macro.hx @@ -0,0 +1,68 @@ +package coconut.ui.internal; + +import haxe.macro.Context.*; +import haxe.macro.Expr; + +using haxe.macro.Tools; +using tink.MacroApi; + +abstract Variable(Dynamic) { + static function shouldCheck(e:Expr) + return switch e { + case { expr: ECheckType(e, _)} | macro ($e): shouldCheck(e); + case macro @:skipCheck $_: false; + default: true; + } + + static public function make(e:Expr) + return (switch typeExpr(e) { + case done = followWithAbstracts(_.t) => TInst(_.get() => { module: 'tink.state.State', name: 'StateObject' }, _): + storeTypedExpr(done); + case te: + while (true) + switch e { + case macro (${v}): e = v; + default: break; + } + switch e { + case macro $i{name}: + e = macro @:pos(e.pos) this.$name; + default: + } + switch e { + case macro ${owner}.$name: + + var v = typeExpr(owner); + if (v.hasThis()) + v = typeExpr(macro @:pos(owner.pos) (function () return $owner)()); + + var ret = storeTypedExpr(v); + + if (shouldCheck(e)) { + var ownerT = v.t, + pos = e.pos; + + coconut.data.macros.Models.afterChecking(function () { + switch coconut.data.macros.Models.check(ownerT) { + case []: + case v: + pos.error('Target not observable: ${v[0]}'); + } + }); + } + + typeof(macro @:pos(e.pos) $ret.$name = cast null); + + macro @:pos(e.pos) { + var target = tink.state.Observable.auto(function () return $ret); + @:pos(e.pos) tink.state.State.compound( + tink.state.Observable.auto(function () return target.value.$name), // consider using .map here + function (value) target.value.$name = value + ); + } + + default: + e.reject('expression should be a field or of type State (found ${te.t.toString()})'); + } + }); +} \ No newline at end of file diff --git a/src/coconut/ui/macros/Helpers.hx b/src/coconut/ui/macros/Helpers.hx index ac9802e..7407e80 100644 --- a/src/coconut/ui/macros/Helpers.hx +++ b/src/coconut/ui/macros/Helpers.hx @@ -27,7 +27,6 @@ class Helpers { defaultExtension: 'hxx', noControlStructures: false, defaultSwitchTarget: macro __data__, - isVoid: ctx.isVoid, fragment: fragment, treatNested: function (children) return ctx.generateRoot.bind(children).bounce(), }) diff --git a/src/coconut/ui/macros/ViewBuilder.hx b/src/coconut/ui/macros/ViewBuilder.hx index eb2529e..10a98cc 100644 --- a/src/coconut/ui/macros/ViewBuilder.hx +++ b/src/coconut/ui/macros/ViewBuilder.hx @@ -180,21 +180,37 @@ class ViewBuilder { function slotName(name) return '__coco_$name'; - function addAttribute(pos, a, expr:Expr, type:ComplexType, publicType:ComplexType, optional:Bool, comparator, ?meta) { + function addAttribute(pos, a, expr:Expr, type:ComplexType, publicType:ComplexType, optional:Bool, comparator, ?meta, ?container = 'Attribute') { + var container = 'coconut.ui.internal.$container'.asTypePath([TPType(type)]); + var name = a.name; var data = macro @:pos(a.pos) attributes.$name, slotName = slotName(a.name); if (!display) { - initSlots.push(macro @:pos(a.pos) this.$slotName.setData($data)); + initSlots.push(macro @:pos(a.pos) this.$slotName.assign($data)); if (expr == null) expr = macro @:pos(a.pos) null; + var args = [ + expr, + comparator, + #if tink_state.debug (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end + ]; + + #if !tink.state.debug + switch comparator { + case macro null: args.pop(); + default: + } + #end + + initField(slotName, macro new $container($a{args})); + var container = TPath(container); add(macro class { - @:noCompletion private final $slotName:coconut.ui.internal.Slot<$type, $publicType>; + @:noCompletion private final $slotName:$container; }); - initField(slotName, macro new coconut.ui.internal.Slot<$type, $publicType>(this, ${comparator}, $expr #if tink_state.debug , (_) -> $v{c.target.name} + '#' + this.viewId + '.' + $v{a.name} #end)); } switch a.pos.getOutcome(type.toType()).reduce() { @@ -230,10 +246,10 @@ class ViewBuilder { var slotName = slotName(name); - if (optional && expr == null) + if (expr == null) expr = macro @:pos(a.pos) null; - addAttribute(attr.pos, a, expr, type, macro : coconut.data.Value<$type>, optional, + addAttribute(attr.pos, a, macro @:pos(expr.pos) function ():$type return $expr, type, macro : tink.hxx.Expression<$type>, optional, attr.meta.comparator, a.metaNamed(':children') .concat(a.metaNamed(':child')) @@ -351,7 +367,7 @@ class ViewBuilder { true; } - addAttribute(c.pos, c.member, e, t, macro : coconut.data.Variable<$t>, optional, macro @:pos(c.pos) null); + addAttribute(c.pos, c.member, e, t, macro : coconut.ui.internal.Variable<$t>, optional, macro @:pos(c.pos) null, 'Controlled'); c.member.kind = FProp('get', 'set', t); @@ -364,13 +380,8 @@ class ViewBuilder { add(macro class { inline function $getter():$t return this.$slotName.value; - function $setter(param:$t):$t { - switch @:privateAccess this.$slotName.data {//TODO: this is quite hideous - case null: //should probably never happen - case v: v.set(param); - } - return param; - } + inline function $setter(param:$t):$t + return this.$slotName.value = param; }); case _.match(FFun(_)) => isFunc: c.pos.error('controlled attributes cannot be ${if (isFunc) 'functions' else 'properties'}'); @@ -414,12 +425,12 @@ class ViewBuilder { macro { var fallback = tink.core.Lazy.ofFunc(() -> $fallback); - tink.state.Observable.auto(() -> switch $i{implicits}.get($p{t.toString().split('.')}) { + () -> switch $i{implicits}.get($p{t.toString().split('.')}) { case null: fallback.get(); case v: v; - }); + }; } - }, t, macro : coconut.data.Value<$t>, true, macro null); + }, t, macro : tink.hxx.Expression<$t>, true, macro null); m.publish(); m.kind = FProp('get', 'never', t); @@ -524,7 +535,12 @@ class ViewBuilder { } }); - initField(internal, macro new tink.state.State<$t>(${v.expr}, ${state.meta.comparator})); + var args = [v.expr]; + switch state.meta.comparator { + case macro null: + case v: args.push(v); + } + initField(internal, macro new tink.state.State<$t>($a{args})); s.kind = FProp('get', 'set', t, null); } diff --git a/tests/Tests.hx b/tests/Tests.hx index 8302a9c..b40b2aa 100644 --- a/tests/Tests.hx +++ b/tests/Tests.hx @@ -54,35 +54,6 @@ class Tests extends haxe.unit.TestCase { assertEquals(beforeInner + 1, Example4.redraws); } - function testSlot() { - var s = new coconut.ui.internal.Slot(this, Observable.const(123)), - s1 = new State(0), - s2 = new State(1000); - var log = []; - s.observe().bind(log.push); - s.setData(Observable.const(42)); - assertEquals('123', log.join(',')); - Renderer.updateAll(); - assertEquals('123,42', log.join(',')); - s.setData(Observable.const(0)); - Renderer.updateAll(); - assertEquals('123,42,0', log.join(',')); - s.setData(s1); - Renderer.updateAll(); - assertEquals('123,42,0', log.join(',')); - s1.set(1000); - Renderer.updateAll(); - assertEquals('123,42,0,1000', log.join(',')); - s.setData(s2); - Renderer.updateAll(); - assertEquals('123,42,0,1000', log.join(',')); - - s1.set(1001); - s2.set(1002); - Renderer.updateAll(); - assertEquals('123,42,0,1000,1002', log.join(',')); - } - function testCustom() { var s = new State(4); diff --git a/tests/cases/Base.hx b/tests/cases/Base.hx index 5ca19fe..4961f51 100644 --- a/tests/cases/Base.hx +++ b/tests/cases/Base.hx @@ -8,7 +8,8 @@ class Base { Wrapper.mount(o); } - @:after function teardown() { + @:after public function teardown() { Wrapper.clear(); + return Promise.NOISE; } } \ No newline at end of file diff --git a/tests/import.hx b/tests/import.hx index ff7fc1a..09bf4a7 100644 --- a/tests/import.hx +++ b/tests/import.hx @@ -1,9 +1,11 @@ import js.Browser.*; import coconut.Ui.hxx; +using tink.hxx.FunctionSugar; using tink.CoreApi; import tink.state.*; import coconut.ui.*; import coconut.data.*; import views.*; -import models.*; \ No newline at end of file +import models.*; +import coconut.ui.Html.*; \ No newline at end of file diff --git a/tests/views/Wrapper.hx b/tests/views/Wrapper.hx index 2859f11..6608539 100644 --- a/tests/views/Wrapper.hx +++ b/tests/views/Wrapper.hx @@ -6,9 +6,19 @@ class Wrapper { document.body.appendChild(e); e; } - static public function clear() - mount(null); - static public function mount(o) + static public function clear() { + container.remove(); + container = { + var e = document.createElement('wrapper-element'); + document.body.appendChild(e); + e; + } + // trace('yo!'); + // mount(null); + } + + static public function mount(o) { coconut.ui.Renderer.mount(container, o); + } } \ No newline at end of file