{"id":16256812,"url":"https://github.com/johnlindquist/vue-streams","last_synced_at":"2025-03-19T21:31:15.778Z","repository":{"id":136551979,"uuid":"127768991","full_name":"johnlindquist/vue-streams","owner":"johnlindquist","description":"Simple Streams for Vue","archived":false,"fork":false,"pushed_at":"2018-04-03T02:34:19.000Z","size":17,"stargazers_count":14,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-23T10:32:40.955Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnlindquist.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-02T14:41:23.000Z","updated_at":"2019-10-11T12:42:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"cc94f0ed-4de6-46c6-af3b-a8f3f4f38f3b","html_url":"https://github.com/johnlindquist/vue-streams","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnlindquist%2Fvue-streams","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnlindquist%2Fvue-streams/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnlindquist%2Fvue-streams/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnlindquist%2Fvue-streams/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnlindquist","download_url":"https://codeload.github.com/johnlindquist/vue-streams/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244056428,"owners_count":20390720,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T15:46:24.918Z","updated_at":"2025-03-19T21:31:15.770Z","avatar_url":"https://github.com/johnlindquist.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⛲️ vue-streams ⛲️\n\nA simplified approach to using streams with Vue.\n\n## Install\n\n```bash\nnpm i vue-streams rxjs@rc\n```\n\nrxjs v6 is recommended (currently in Release Candidate)\n\n## Setup\n\nInstall as a plugin:\n\n```js\nimport VueStreams from \"vue-streams\"\nimport { Subject, BehaviorSubject } from \"rxjs\"\nVue.use(VueStreams, { Subject, BehaviorSubject })\n```\n\n## Usage\n\n### Simple Example\n\n[![Simple Example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/yv37425lox)\n\n```js\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003cbutton @click=\"click$\"\u003eClick me\u003c/button\u003e\n    {{random$}}\n  \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nimport { fromMethod } from \"vue-streams\";\nimport { map } from \"rxjs/operators\";\n\nexport default {\n  sources: {\n    click$: fromMethod //infer the method name \"click$\" from the key\n  },\n  subscriptions: ({ click$ }) =\u003e ({\n    random$: click$.pipe(map(() =\u003e Math.random()))\n  }) //template subscribes to each key of the returned object\n};\n\u003c/script\u003e\n```\n\n### Standard Example\n\n[![Standard Example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/ov6yk15w26)\n\n```js\n\u003ctemplate\u003e\n  \u003cdiv id=\"demo\"\u003e\n    \u003clabel\u003eSearch \u003cinput type=\"text\" v-model=\"term\"\u003e\u003c/label\u003e\n    \u003cbutton @click=\"term = ''\"\u003eClear\u003c/button\u003e\n    \u003ch2 v-if=\"noResults$\"\u003e\n      {{message$}}\n    \u003c/h2\u003e\n    \u003ctransition-group tag=\"div\" name=\"fade\" class=\"people\"\u003e\n      \u003cdiv v-for=\"person of people$\" :key=\"person.id\"\u003e\n        \u003ch2\u003e{{person.name}}\u003c/h2\u003e\n        \u003cimg :src=\"`${URL}/${person.image}`\" alt=\"\"\u003e\n      \u003c/div\u003e\n\n    \u003c/transition-group\u003e\n\n  \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nimport { fromWatch } from \"vue-streams\"\nimport { merge } from \"rxjs\"\nimport {\n  switchMap,\n  map,\n  mapTo,\n  pluck,\n  partition,\n  debounceTime,\n  share\n} from \"rxjs/operators\"\nimport { ajax } from \"rxjs/ajax\"\n\nconst URL = `https://foamy-closet.glitch.me`\n\nexport default {\n  data() {\n    return { URL, term: \"sky\" }\n  },\n  sources: {\n    term$: fromWatch(\"term\")\n  },\n  subscriptions: ({ term$ }) =\u003e {\n    const [search$, empty$] = term$.pipe(\n      debounceTime(250),\n      partition(term =\u003e term.length)\n    )\n\n    const people$ = merge(\n      search$.pipe(\n        switchMap(term =\u003e\n          ajax(`${URL}/people?name_like=${term}`).pipe(\n            share(),\n            pluck(\"response\")\n          )\n        )\n      ),\n      empty$.pipe(map(() =\u003e []))\n    )\n\n    const noResults$ = people$.pipe(map(result =\u003e result.length === 0))\n    const message$ = merge(\n      noResults$.pipe(mapTo(\"No results 😢\")),\n      empty$.pipe(mapTo(\"Please type something 👍\"))\n    )\n\n    return { people$, noResults$, message$ }\n  }\n}\n\u003c/script\u003e\n\u003cstyle\u003e\n#demo {\n  font-family: \"Avenir\";\n}\n.people {\n  display: flex;\n  flex-wrap: wrap;\n}\n\n.people \u003e * {\n  padding: 0.25rem;\n}\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.5s;\n}\n.fade-enter,\n.fade-leave-to {\n  opacity: 0;\n}\n\u003c/style\u003e\n```\n\n### Crazy Example\n\n[![Crazy Example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/48jyk13nm7)\n\n```js\n\u003ctemplate\u003e\n  \u003cdiv id=\"demo\" @mousemove=\"x = $event.x\"\u003e\n    \u003ch3\u003e{{x$}}\u003c/h3\u003e\n    \u003cbutton @click=\"one$\"\u003eOne\u003c/button\u003e\n    \u003cbutton @click=\"two\"\u003eTwo\u003c/button\u003e\n    \u003cbutton @click=\"load$\"\u003eLoad Random\u003c/button\u003e\n    \u003cinput type=\"text\" v-model=\"text\"\u003e\n    \u003cbutton v-on:click=\"show = !show\"\u003e\n      Toggle\n    \u003c/button\u003e\n    \u003ctransition name=\"fade\" @enter=\"enter$\"\u003e\n      \u003cp v-if=\"show\"\u003ehello\u003c/p\u003e\n    \u003c/transition\u003e\n    \u003ch2\u003e\n      {{message$}}\n    \u003c/h2\u003e\n    \u003cMiniComp v-if=\"show\"\u003e\u003c/MiniComp\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n\u003cscript\u003e\nimport { merge, interval } from \"rxjs\"\nimport { ajax } from \"rxjs/ajax\"\nimport { map, mapTo, switchMap, pluck, throttleTime } from \"rxjs/operators\"\nimport { fromMethod, fromWatch, fromEmit } from \"vue-streams\"\n\nconst MiniComp = {\n  sources: {\n    mounted$: fromEmit(\"hook:mounted\"),\n    beforeDestroy$: fromEmit(\"hook:beforeDestroy\")\n  },\n  subscriptions: ({ mounted$, beforeDestroy$ }) =\u003e {\n    mounted$.subscribe(value =\u003e console.log(\"hello!\"))\n    beforeDestroy$.subscribe(value =\u003e console.log(\"BYE! 🤪\"))\n  },\n  render(h) {\n    return (\n      \u003cdiv\u003e\n        \u003ch2\u003eMiniComp\u003c/h2\u003e\n      \u003c/div\u003e\n    )\n  }\n}\n\nexport default {\n  components: {\n    MiniComp\n  },\n  data() {\n    return {\n      show: false,\n      text: \"john\"\n    }\n  },\n  sources: {\n    one$: fromMethod,\n    two$: fromMethod(\"two\"),\n    load$: fromMethod,\n    enter$: fromMethod,\n    text$: fromWatch(\"text\"),\n    x: fromWatch\n  },\n\n  subscriptions: ({ one$, two$, load$, enter$, text$, x }) =\u003e {\n    const buttons$ = merge(\n      one$.pipe(mapTo(1)),\n      two$.pipe(mapTo(2)),\n      enter$.pipe(mapTo(\"fade in...\"))\n    )\n    const date$ = interval(4000).pipe(map(() =\u003e new Date().toString()))\n    const person$ = load$.pipe(\n      switchMap(() =\u003e\n        ajax(\n          `https://foamy-closet.glitch.me/people/${Math.floor(\n            Math.random() * 10\n          )}`\n        ).pipe(pluck(\"response\", \"name\"))\n      )\n    )\n\n    const message$ = merge(person$, text$, date$, buttons$)\n\n    return {\n      message$,\n      x$: x.pipe(throttleTime(100))\n    }\n  }\n}\n\u003c/script\u003e\n\u003cstyle\u003e\n#demo {\n  font-family: \"Avenir\";\n}\n.fade-enter-active,\n.fade-leave-active {\n  transition: opacity 0.5s;\n}\n.fade-enter,\n.fade-leave-to {\n  opacity: 0;\n}\n\u003c/style\u003e\n```\n\n## Other Demos\n\n### Basic Vue Counter with JSX\n\n[![Basic Vue Counter](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/21zv0jqz40)\n\n### Basic Form with `.prevent`\n\n[![Edit Vue Template](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/mjr6x6o888?module=%2Fsrc%2FApp.vue)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnlindquist%2Fvue-streams","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnlindquist%2Fvue-streams","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnlindquist%2Fvue-streams/lists"}