it('takes an object of additional sources to be passed to the item', () => { const props$ = xs.empty(); const collectionWithOneItemWithProps = collection.add({props$}); assert.equal(props$, collectionWithOneItemWithProps.asArray()[0].state$); });
export default function ColorPicker ({DOM, props$ = xs.empty()}) { const initialState = { activeInput: either(['none', 'hue', 'saturation', 'alpha'], 'none'), saturationContainer: {width: 0, height: 0}, hueContainer: {width: 0}, alphaContainer: {width: 0}, color: {h: 0, s: 0, v: 1, a: 1}, colorInputFormat: either(['hex', 'rgba', 'hsla'], 'hex') }; const action$ = makeReducer$({DOM, props$}); const state$ = action$ .fold((state, action) => action(state), initialState) .compose(dropRepeats((a, b) => JSON.stringify(a) === JSON.stringify(b))) // TODO do this better .remember(); const color$ = state$ .map(state => { return tinycolor.fromRatio(state.color).toRgbString(); }); return { DOM: state$.map(view), color$ }; }
function Collection (component, sources = {}, sourceAdd$ = xs.empty(), removeSelector = noop) { const removeProxy$ = xs.create(); const add$ = xs.fromObservable(sourceAdd$); const addReducer$ = add$.map(sourcesList => collection => { if (Array.isArray(sourcesList)) { // multiple items return sourcesList.reduce((collection, sources) => collection.add(sources), collection); } else { // single item return collection.add(sourcesList); } }); const removeReducer$ = removeProxy$.map(item => collection => collection.remove(item)); const reducer$ = xs.merge(removeReducer$, addReducer$); const emptyCollection = collection({ component, sources, removeSelector }); const collection$ = reducer$ .fold((collection, reducer) => reducer(collection), emptyCollection) .map(collection => collection.asArray()); const remove$ = Collection.merge(collection$, item => item._remove$, true); removeProxy$.imitate(remove$); return adapt(collection$); }
it('takes an object of sources to pass to each item', () => { const props$ = xs.empty(); const collection = Collection(Widget, {props$}); assert.equal(collection.add().asArray()[0].state$, props$); });
/** * Responsible for wrapping a generic component with an authentication layer * Will also decorate all http sinks of the child component with the user's tokens * * @param {Object} sources sources (that will also be used by the child component) * @returns {Object} sinks */ function AuthenticationWrapper(sources) { const { auth0 } = sources; const { Child = () => { throw new Error("[Auth0Wrapper] missing child component") }, auth0ShowParams = defaultAuth0ShowParams, decorators = {} } = sources.props.authWrapperParams; const tokens$ = auth0.tokens$; const childSources = { ...sources, props: { ...sources.props, tokens$ }}; const sinks = Child(childSources); const showLoginRequest$ = tokens$ .filter(tokens => !tokens) .mapTo({ action: "show", params: auth0ShowParams }); return decorateSinks({ ...sinks, auth0: xs.merge(showLoginRequest$, sinks.auth0 || xs.empty()) }, tokens$, decorators); }
function collection (options, items = []) { const { component, sources, removeSelector } = options; return { add (additionalSources = {}) { const newItem = makeItem(component, {...sources, ...additionalSources}); const selectedSink = removeSelector(newItem) || xs.empty(); const removeSink = xs.fromObservable(selectedSink); newItem._remove$ = removeSink.take(1).mapTo(newItem); return collection( options, [...items, newItem] ); }, remove (itemForRemoval) { return collection( options, items.filter(item => item !== itemForRemoval) ); }, asArray () { return items.slice(); // returns a copy of items to avoid mutation } }; }
.map((action) => { switch (action.type) { case 'videolink': return xs.fromArray([ {type: 'switch', vref: action.vref, time: action.time || null}, {type: action.play ? 'play' : 'pause'} ]); default: return xs.empty() } })
.map(action => { var actionFn = actions[action.action]; if (!actionFn) { console.error(`[Auth0Driver] not available method: ${action.action}`); return false; } var promise = actionFn(lock, action.params); return { action: action.action, response$: promise ? xs.fromPromise(promise) : xs.empty() } })
function auth0Driver(action$, streamAdapter) { const noop = () => {}; const actionDone$ = action$ .map(action => { var actionFn = actions[action.action]; if (!actionFn) { console.error(`[Auth0Driver] not available method: ${action.action}`); return false; } var promise = actionFn(lock, action.params); return { action: action.action, response$: promise ? xs.fromPromise(promise) : xs.empty() } }) .remember() const select = responseSelector(lock, actionDone$); actionDone$.addListener({ next: noop, error: noop, complete: noop }) //if the location contains an id_token, do not send any initial token //because the lock will parse the token in hash and the initial token //will be given by either the authenticated event of any of the errors const initialToken$ = location.hash.indexOf("id_token") > -1 ? xs.empty() : xs.of(null).map(() => JSON.parse(localStorage.getItem(storageKey))); const removeToken$ = select("logout, unrecoverable_error, authorization_error") .map(() => { localStorage.removeItem(storageKey) return null; }); const storeToken$ = select("authenticated") .map(({ response }) => { var tokens = { accessToken: response.accessToken, idToken: response.idToken } localStorage.setItem(storageKey, JSON.stringify(tokens)) return tokens; }); return { select: select, tokens$: xs .merge(initialToken$, storeToken$, removeToken$) .remember() }; }
export default function focusDriver(targets$) { targets$.addListener({ next(element) { if (element) { element.focus(); } }, error: _.noop, complete: _.noop, }); return xs.empty(); }
function preventDefaultSinkDriver(prevented$) { prevented$.addListener({ next: ev => { ev.preventDefault() if (ev.type === 'blur') { ev.target.focus() } }, error: () => {}, complete: () => {}, }) return xs.empty() }
export default function UserCard({DOM}, user) { // intent const edit$ = DOM.select('.edit-user').events('click') .map(editUserAction) const delete$ = DOM.select('.delete-user').events('click') .map(deleteUserAction) const state$ = xs.merge(edit$, delete$) .fold(reducer, user) const view$ = state$.map(view) return { DOM: view$, HTTP: xs.empty() } }
it('returns object containing "events" method, which accepts an event name and returns stream of such events on the canvas', done => { const jsdom = new JSDOM('<!DOCTYPE html><html><body><canvas></canvas></body></html>') root.document = jsdom.window.document const canvasEl = root.document.querySelector('canvas') canvasEl.getContext = methodSpy() const Canvas = makeCanvasDriver('canvas')(xs.empty()) const click$ = Canvas.events('click') const event = new jsdom.window.MouseEvent('click') click$.addListener({ next: clickEvent => { assert.strictEqual(clickEvent, event) done() } }) canvasEl.dispatchEvent(event) })
it('takes an object of additional sources to be passed to the item', (done) => { const props$ = xs.empty(); const collection$ = Collection(Widget, {}, xs.of({props$})); const expected = [[], [props$]] collection$.take(expected.length).addListener({ next (items) { const expectedItems = expected.shift(); assert.equal(items.length, expectedItems.length); items.forEach(item => { assert.equal(item.state$, expectedItems.shift()); }); }, error (err) {done(err)}, complete () { assert.equal(expected.length, 0); done(); } }); });
path: () => xs.empty(),
} from 'xstream'; const producer = { start: (listener) => { listener.next(1); listener.next(2); listener.next(3); listener.complete(); }, stop: console.log }; const create: Stream<number> = xs.create(producer); const createWithMemory: MemoryStream<number> = xs.createWithMemory(producer); const never: Stream<*> = xs.never(); const empty: Stream<*> = xs.empty(); const _throw: Stream<*> = xs.throw(new Error(123)); const from1: Stream<number> = xs.from([1]); const from2: Stream<number> = xs.from(Promise.resolve(1)); const of: Stream<number> = xs.of(1); const fromArray: Stream<number> = xs.fromArray([1,2,3]); const fromPromise: Stream<number> = xs.from(Promise.resolve(1)); const periodic: Stream<number> = xs.periodic(123); const merge: Stream<number> = xs.merge(of, of); const merge2: Stream<number> = xs.merge(of, of, of, of); const combine: Stream<number[]> = xs.combine(of, of); const combine2: Stream<number[]> = xs.combine(of, of, of, of); const listener = { next: console.log, error: console.error,