<div id="app"></div>
window.xs = window.xstream.default;
window.xs.fromEvent = window.fromEvent.default;
const { div, label, input, button, p, makeDOMDriver } = CycleDOM;
function view(state$) {
return state$.map(state => {
return div(".labeled-slider", [
label(".label", `${state.label}: ${state.value} ${state.unit}`),
input(".slider", {
attrs: {
type: "range",
min: state.min,
max: state.max,
value: state.value
}
})
]);
});
}
function intent(sources) {
const domSource = sources.DOM;
const value$ = domSource
.select(".slider")
.events("input")
.map(ev => ev.target.value);
return { value: value$ };
}
function model(intents, props) {
const { value } = intents;
return props
.map(props =>
value.startWith(props.init).map(value => ({ ...props, value }))
)
.flatten();
}
function Slider(sources) {
const actions = intent(sources);
const state$ = model(actions, sources.props);
const vdom$ = view(state$);
return { DOM: vdom$ };
}
function main(sources) {
const { isolateSource, isolateSink } = sources.DOM;
const weightProps = xs.of({
label: "Weight",
min: 40,
max: 100,
init: 58,
unit: "kg"
});
const weightDOMSource = isolateSource(sources.DOM, ".weight");
const weightSinks = Slider({
...sources,
DOM: weightDOMSource,
props: weightProps
});
const weightVDOM$ = isolateSink(weightSinks.DOM, ".weight");
const heightProps = xs.of({
label: "Height",
min: 140,
max: 220,
init: 165,
unit: "cm"
});
const heightDOMSource = isolateSource(sources.DOM, ".height");
const heightSinks = Slider({
...sources,
DOM: heightDOMSource,
props: heightProps
});
const heightVDOM$ = isolateSink(heightSinks.DOM, ".height");
const vdom$ = xs
.combine(weightVDOM$, heightVDOM$)
.map(([weightVDOM, heightVDOM]) => div([weightVDOM, heightVDOM]));
return { DOM: vdom$ };
}
const drivers = {
DOM: makeDOMDriver("#app")
};
Cycle.run(main, drivers);
View Compiled
This Pen doesn't use any external CSS resources.