Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New component function, refactor TodoMVC #111

Merged
merged 9 commits into from
Aug 24, 2019
56 changes: 22 additions & 34 deletions examples/counters/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,26 @@
import { Behavior, combine, stepper, Stream } from "@funkia/hareactive";
import { Behavior, stepper, Stream } from "@funkia/hareactive";
import { go } from "@funkia/jabz";
import { elements, fgo, modelView, runComponent } from "../../../src";
import { elements, fgo, runComponent, view, component } from "../../../src";
import { main1 } from "./version1";
import { main2 } from "./version2";
import { main3 } from "./version3";
import { counterList as main4 } from "./version4";
import { main4 } from "./version4";

const { button, div } = elements;

const numberToApp = {
"1": main1,
"2": main2,
"3": main3,
"4": main4
};
const numberToApp = { "1": main1, "2": main2, "3": main3, "4": main4 };

type AppId = keyof (typeof numberToApp);

function selectorButton(n: AppId, selected: Behavior<AppId>) {
return button(
{
class: ["btn btn-default", { active: selected.map((m) => n === m) }]
},
`Version ${n}`
).map(({ click }) => ({
select: click.mapTo(n)
}));
}
const selectorButton = (n: AppId, selected: Behavior<AppId>) =>
view(
button(
{
class: ["btn btn-default", { active: selected.map((m) => n === m) }]
},
`Version ${n}`
).output((o) => ({ selectVersion: o.click.mapTo(n).log(n) }))
);

type FromView = {
selectVersion: Stream<AppId>;
Expand All @@ -36,26 +30,20 @@ type FromModel = {
selected: Behavior<AppId>;
};

const versionSelector = modelView<FromModel, FromView>(
const versionSelector = component<FromView, FromModel>(
fgo(function*({ selectVersion }) {
const selected = yield stepper("1", selectVersion);
return { selected };
}),
({ selected }) =>
div({ class: "btn-group" }, [
selectorButton("1", selected).output({ select1: "select" }),
selectorButton("2", selected).output({ select2: "select" }),
selectorButton("3", selected).output({ select3: "select" }),
selectorButton("4", selected).output({ select4: "select" })
])
.map((o) => ({
selectVersion: combine(o.select1, o.select2, o.select3, o.select4)
}))
.output({ selectVersion: "selectVersion" })
return div({ class: "btn-group" }, [
selectorButton("1", selected).output({ selectVersion: "selectVersion" }),
selectorButton("2", selected).output({ selectVersion: "selectVersion" }),
selectorButton("3", selected).output({ selectVersion: "selectVersion" }),
selectorButton("4", selected).output({ selectVersion: "selectVersion" })
]).result({ selected });
})
);

const main = go(function*() {
const { selected } = yield versionSelector();
const { selected } = yield versionSelector.output({ selected: "selected" });
const currentApp = selected.map((n: AppId) => numberToApp[n]);
yield div(currentApp);
return {};
Expand Down
55 changes: 23 additions & 32 deletions examples/counters/src/version2.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,32 @@
import { Behavior, accum, Stream, combine } from "@funkia/hareactive";
import { elements, modelView, fgo } from "../../../src";
import { elements, fgo, component } from "../../../src";
const { div, button } = elements;

type CounterModelInput = {
type On = {
incrementClick: Stream<any>;
decrementClick: Stream<any>;
};

type CounterViewInput = {
count: Behavior<number>;
};

const counterModel = fgo(function*({
incrementClick,
decrementClick
}: CounterModelInput) {
const increment = incrementClick.mapTo(1);
const decrement = decrementClick.mapTo(-1);
const changes = combine(increment, decrement);
const count = yield accum((n, m) => n + m, 0, changes);
return { count };
});

const counterView = ({ count }: CounterViewInput) =>
div([
"Counter ",
count,
" ",
button({ class: "btn btn-default" }, " + ").output({
incrementClick: "click"
}),
" ",
button({ class: "btn btn-default" }, " - ").output({
decrementClick: "click"
})
]);
const counter = component<On>(
fgo(function*({ incrementClick, decrementClick }) {
const increment = incrementClick.mapTo(1);
const decrement = decrementClick.mapTo(-1);
const changes = combine(increment, decrement);
const count = yield accum((n, m) => n + m, 0, changes);

const counter = modelView(counterModel, counterView);
return div([
"Counter ",
count,
" ",
button({ class: "btn btn-default" }, " + ").output({
incrementClick: "click"
}),
" ",
button({ class: "btn btn-default" }, " - ").output({
decrementClick: "click"
})
]);
})
);

export const main2 = counter();
export const main2 = counter;
108 changes: 44 additions & 64 deletions examples/counters/src/version3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import {
Behavior,
combine,
map,
Now,
accum,
scan,
Stream
} from "@funkia/hareactive";

import { elements, fgo, list, ModelReturn, modelView } from "../../../src";
import { elements, fgo, list, component } from "../../../src";
const { br, div, button, h1, ul } = elements;

const add = (n: number, m: number) => n + m;
Expand All @@ -19,76 +18,57 @@ type CounterModelInput = {
decrementClick: Stream<any>;
};

type CounterViewInput = {
count: Behavior<number>;
};

type CounterOutput = {
count: Behavior<number>;
};

const counterModel = fgo(function*({
incrementClick,
decrementClick
}: CounterModelInput): ModelReturn<CounterViewInput> {
const increment = incrementClick.mapTo(1);
const decrement = decrementClick.mapTo(-1);
const count = yield accum(add, 0, combine(increment, decrement));
return { count };
});
const counter = () =>
component<CounterModelInput, CounterOutput>(
fgo(function*(on) {
const increment = on.incrementClick.mapTo(1);
const decrement = on.decrementClick.mapTo(-1);
const count = yield accum(add, 0, combine(increment, decrement));

const counterView = ({ count }: CounterViewInput) =>
div([
"Counter ",
count,
" ",
button({ class: "btn btn-default" }, " + ").output({
incrementClick: "click"
}),
" ",
button({ class: "btn btn-default" }, " - ").output({
decrementClick: "click"
return div([
"Counter ",
count,
" ",
button({ class: "btn btn-default" }, " + ").output({
incrementClick: "click"
}),
" ",
button({ class: "btn btn-default" }, " - ").output({
decrementClick: "click"
})
]).result({ count });
})
]);

const counter = modelView(counterModel, counterView);

type ViewInput = {
counterIds: Behavior<number[]>;
sum: Behavior<number>;
};
);

type ModelInput = {
type ListOn = {
addCounter: Stream<Event>;
listOut: Behavior<CounterOutput[]>;
};

const counterListModel = fgo(function*({
addCounter,
listOut
}: ModelInput): Iterator<Now<any>> {
const nextId: Stream<number> = yield scan(add, 2, addCounter.mapTo(1));
const appendCounterFn = map(
(id) => (ids: number[]) => ids.concat([id]),
nextId
);
const counterIds = yield accum<(a: number[]) => number[], number[]>(
apply,
[0],
appendCounterFn
);
return { counterIds };
});

const counterListView = ({ sum, counterIds }: ViewInput) => [
h1("Counters"),
button({ class: "btn btn-primary" }, "Add counter").output({
addCounter: "click"
}),
br,
ul(list(counter, counterIds).output((o) => ({ listOut: o })))
];

const counterList = modelView(counterListModel, counterListView);
const counterList = component<ListOn>(
fgo(function*({ addCounter }) {
const nextId: Stream<number> = yield scan(add, 2, addCounter.mapTo(1));
const appendCounterFn = map(
(id) => (ids: number[]) => ids.concat([id]),
nextId
);
const counterIds = yield accum<(a: number[]) => number[], number[]>(
apply,
[0],
appendCounterFn
);
return [
h1("Counters"),
button({ class: "btn btn-primary" }, "Add counter").output({
addCounter: "click"
}),
br,
ul(list(counter, counterIds))
];
})
);

export const main3 = counterList();
export const main3 = counterList;
Loading