├── .gitignore
├── .prettierrc
├── .travis.yml
├── .vscode
└── launch.json
├── LICENSE
├── README.md
├── docs
├── assets.json
├── index.html
└── static
│ └── js
│ ├── 15.854c9d6f.js
│ ├── 15.e2ac49079e2d157a0b49.js.map
│ ├── app.c7d38faa.js
│ ├── app.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-00-about.33cb42e7.js
│ ├── docs-source-0-introduction-00-about.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-05-installation.a5841abe.js
│ ├── docs-source-0-introduction-05-installation.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-10-getting-started.2b91f695.js
│ ├── docs-source-0-introduction-10-getting-started.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-20-objects-and-factories.0928d7eb.js
│ ├── docs-source-0-introduction-20-objects-and-factories.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-30-with-react.7cb56417.js
│ ├── docs-source-0-introduction-30-with-react.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-40-philosophy.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-0-introduction-40-philosophy.fea48fa9.js
│ ├── docs-source-1-advanced-examples.85d2c45c.js
│ ├── docs-source-1-advanced-examples.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-1-advanced-models.d824a22c.js
│ ├── docs-source-1-advanced-models.e2ac49079e2d157a0b49.js.map
│ ├── docs-source-1-advanced-preprocessors.2cd0bb51.js
│ ├── docs-source-1-advanced-preprocessors.e2ac49079e2d157a0b49.js.map
│ ├── pkgs-core-readme.4285a63b.js
│ ├── pkgs-core-readme.e2ac49079e2d157a0b49.js.map
│ ├── pkgs-react-readme.e1c9a28e.js
│ ├── pkgs-react-readme.e2ac49079e2d157a0b49.js.map
│ ├── pkgs-updaters-readme.429519e2.js
│ ├── pkgs-updaters-readme.e2ac49079e2d157a0b49.js.map
│ ├── runtime~app.e2ac49079e2d157a0b49.js
│ ├── runtime~app.e2ac49079e2d157a0b49.js.map
│ ├── vendors.15c669d7.js
│ └── vendors.e2ac49079e2d157a0b49.js.map
├── docs_source
├── 0_introduction
│ ├── 00_about.mdx
│ ├── 05_installation.mdx
│ ├── 10_getting-started.mdx
│ ├── 20_objects-and-factories.mdx
│ ├── 30_with-react.mdx
│ └── 60_philosophy.mdx
├── 1_convenience
│ ├── 40_preprocessors.mdx
│ ├── 50_updaters.mdx
│ └── models.mdx
└── 2_advanced
│ ├── examples.mdx
│ ├── mobx.mdx
│ ├── organizing_state.mdx
│ └── performance.mdx
├── doczrc.js
├── examples
└── boxes
│ ├── .babelrc
│ ├── .env
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ └── index.html
│ ├── src
│ ├── components
│ │ ├── arrow-view.js
│ │ ├── box-view.js
│ │ ├── canvas.js
│ │ ├── fun-stuff.js
│ │ └── sidebar.js
│ ├── index.css
│ ├── index.js
│ └── stores
│ │ ├── domain-state.js
│ │ └── time.js
│ └── yarn.lock
├── jest.config.json
├── jest.config.test.json
├── lerna.json
├── package.json
├── pkgs
├── core
│ ├── README.mdx
│ ├── core.ts
│ ├── package.json
│ └── tests
│ │ ├── base.spec.ts
│ │ ├── config.spec.ts
│ │ ├── object.spec.ts
│ │ ├── perf
│ │ ├── index.js
│ │ ├── perf.js
│ │ └── perf.txt
│ │ └── scheduling.spec.ts
├── models
│ ├── README.mdx
│ ├── models.ts
│ ├── package.json
│ └── tests
│ │ └── model.spec.ts
├── react
│ ├── README.mdx
│ ├── package.json
│ ├── react.ts
│ └── tests
│ │ ├── rview.spec.tsx
│ │ └── useval.spec.tsx
├── types
│ ├── README.mdx
│ ├── package.json
│ ├── tests
│ │ ├── __snapshots__
│ │ │ ├── sarcastic.spec.ts.snap
│ │ │ └── types.spec.ts.snap
│ │ ├── sarcastic.spec.ts
│ │ └── types.spec.ts
│ └── types.ts
├── updaters
│ ├── README.mdx
│ ├── package.json
│ ├── tests
│ │ └── updaters.spec.ts
│ └── updaters.ts
└── utils
│ ├── README.mdx
│ ├── package.json
│ ├── tests
│ └── utils.spec.ts
│ └── utils.ts
├── scripts
├── build.js
├── link.js
└── package-template.json
├── tsconfig.json
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | yarn-error.log
3 | dist
4 | .rpt2_cache
5 | .rts2_cache*
6 | /coverage
7 | .docz
8 | mangle.json
9 | lerna-debug.log
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": false,
5 | "singleQuote": true,
6 | "printWidth": 120
7 | }
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '10'
4 | env:
5 | - NODE_ENV=TEST
6 | cache:
7 | yarn: true
8 | directories:
9 | - 'node_modules'
10 | script:
11 | - yarn coverage
12 | - yarn build
13 | - yarn test
14 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | // Note; this config requires node 8.4 or higher
9 | "type": "node",
10 | "protocol": "auto",
11 | "request": "launch",
12 | "name": "debug unit test",
13 | "stopOnEntry": false,
14 | "program": "${workspaceRoot}/node_modules/jest-cli/bin/jest.js",
15 | "args": ["--verbose", "--runInBand", "--config", "jest.config.json", "-i", "${fileBasename}"],
16 | "windows": {
17 | "program": "${workspaceRoot}\\node_modules\\jest-cli\\bin\\jest.js"
18 |
19 | // "args": ["--verbose", "--runInBand", "--config", "jest.config.json"]
20 | },
21 | "runtimeArgs": ["--nolazy"]
22 | },
23 | {
24 | // Note; this config requires node 8.4 or higher
25 | "type": "node",
26 | "protocol": "inspector",
27 | "request": "launch",
28 | "name": "debug unit test - minified",
29 | "stopOnEntry": false,
30 | "program": "${workspaceRoot}/node_modules/jest-cli/bin/jest.js",
31 | "windows": {
32 | "program": "${workspaceRoot}\\node_modules\\jest-cli\\bin\\jest.js"
33 | },
34 | "outFiles": ["pkgs/core/"],
35 | "args": ["--verbose", "--runInBand", "--config", "jest.config.test.json", "-i", "${fileBasename}"],
36 | "runtimeArgs": ["--nolazy"],
37 | "sourceMaps": true
38 | },
39 | {
40 | "type": "node",
41 | "request": "launch",
42 | "name": "Launch Program",
43 | "program": "${file}",
44 | "sourceMaps": true
45 | }
46 | ]
47 | }
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Michel Weststrate
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RVal
2 |
3 |
4 | [](https://www.npmjs.com/package/rval) [](http://img.badgesize.io/https://unpkg.com/rval/dist/core.mjs?compression=gzip) [](https://travis-ci.org/mweststrate/rval) [](https://coveralls.io/github/mweststrate/rval?branch=master) [](https://www.paypal.me/michelweststrate) [](https://www.buymeacoffee.com/mweststrate)
5 |
6 |
7 | Docs in progress:
8 |
9 | https://mweststrate.github.io/rval
10 |
11 | STATE DESIGN
12 |
13 | mutability granularity
14 | refs
15 |
16 | preprocessor validation
17 |
18 | preprocessor objects
19 |
20 | preprocessors
21 | - validation
22 | - conversion
23 | - equality checks
24 | - models
25 | - combing them
26 |
27 |
28 | models
29 |
30 |
31 | async
32 |
33 |
34 | # Api
35 |
36 | ## `val`
37 |
38 | ## `sub`
39 |
40 | ## `drv`
41 |
42 | ## `batch`
43 |
44 | ## batched:
45 |
46 | ## effect
47 |
48 | ## Immutability and freezing
49 |
50 | ## Working with objects
51 |
52 | ## Working with arrays
53 |
54 | ## Object models
55 |
56 | ## Scheduling details
57 |
58 | ## Private context
59 |
60 | ## Strictness options
61 |
62 | # API
63 |
64 |
65 | Tips:
66 | - subscribe before read, or use `fireImmediately`
67 | - typing self-object referring derivations
68 | - share methouds by pulling out / `this` / prototype or Object.create (add tests!)
69 | - dependency injection through type generation in closure
70 | - maps versus array entries
71 | - comparison preprocessors
72 |
73 | Differences with MobX:
74 |
75 | - No 2 phase tracking, slower, but enables custom scheduling of computations
76 | - Clear mutability / immutablility story
77 | - No object modification, decorators, cloning
78 | - small, with isolated tracking, fit for in-library usage
79 |
80 | Patterns
81 |
82 | - objects
83 | - objects with models
84 | - arrays
85 | - maps
86 | - serialization, deserialization
87 | - capturing parent ref (see test "todostore - with parent")
88 | - with react
89 | - with immer (`v(p(v(), draft => { })))`)
90 | - working with references
91 |
92 | Comparison with mobx
93 | - factory + getter / setters -> observable. More convenient, but, pit of success
94 | - sub(drv(x), noop) === autorun(x)
95 | - more scheduling control; effect
96 |
97 | Comparison with Rx
98 | - focus on values, not events
99 | - push / pull vs. push
100 | - transparent tracking
101 |
102 | Todo:
103 |
104 | * [x] build all the packages
105 | * [x] generate types `yarn tsc index.ts -t es2015 -d --outDir dist && mv dist/index.d.ts dist/rval.d.ts && rm dist/index.js &&`
106 | * [x] test against generated packages
107 | * [x] setup CI
108 | * [x] ~`sub({ scheduler, onInvalidate(f (track)))})`~ -> `effect`
109 | * [x] setup coveralls
110 | * [x] rval-models
111 | * [x] rval-react
112 | * [x] rval-immer
113 | * [x] custom schedulers
114 | * [x] custom preprocessors
115 | * [x] eliminate Reaction class
116 | * [x] setup minification with minified class members
117 | * [x] swap export statement in `tests/rval.ts` in CI to test minified build
118 | * [x] mobx like evaluation order of drv
119 | * [x] `drv` with setter
120 | * [x] combine preprocessor array
121 | * [x] support currying for sub: `sub(listener)(val)`
122 | * [x] rename RvalContext to RvalInstance
123 | * [x] support `this.rvalProps(this.rvalProps() + 1)` -> `this.rvalProps(x => x + 1)`?
124 | * [x] re-enable minification ootb
125 | * [x] fix sourcemaps for minified builds
126 | * [x] use prop mangling for smaller builds
127 | * [x] fast class / object test
128 | * [x] updaters `inc1`, `inc`, `push`, `set`, `delete`, `assign`, `toggle`
129 | * [x] utils `assignVals`, `toJS
130 | * [x] setter for `drv`?
131 | * [x] host docs
132 | * [x] check https://reactpixi.org/#/stage / https://docs.setprotocol.com/#/#support-and-community- for setup of edit button, menu nesting, hosting
133 | * [x] `sub`, pass in previous value as second argument
134 | * [x] implement `SubscribeOptions`
135 | * [x] keepAlive drv option, using effect
136 | * [x] publish all script
137 | * [x] tests and types for utils
138 | * [x] kill with-immmer?
139 | * [x] improve updaters typings
140 | * [x] verify callign actions in reactions work correctly
141 | * [x] move `invariant` to preprocessors?
142 | * [x] add `toJS` on all model types
143 | * [x] rval-validation
144 | * [x] kill `run`
145 | * [x] fix debugging with minification
146 | * [x] use yalc? https://www.google.com/url?q=https%3A%2F%2Fgithub.com%2Fwhitecolor%2Fyalc%2F&sa=D&sntz=1&usg=AFQjCNGCTXoCduIMdVHx5xm-uAs_REX3MA
147 | * [ ] add missing mobx optimizations
148 | * [ ] contributing and debugging
149 | * [ ] docs
150 | * [ ] add `reference` to models?
151 | * [ ] contributing & debugging guide. `reserved` section in package.json!
152 | * [ ] add (mobx like) performance tests
153 | * [ ] rval.js.org CDN
154 | * [ ] smart lack of act detection. Only have `act`, no `run`?
155 | * [ ] rename MDX files to md
156 | * [ ] rview as wrapper
157 | * [ ] deep merge model tree?
158 | * [ ] RVAL return this in setter for chaining?
159 | * [ ] cheat sheet
160 | * [ ] efficient map structure
161 | * [ ] find neat solution to globally shared instance
162 |
163 | Later
164 | * [ ] rval-remote
165 | * [ ] config: warn on unbatched writes
166 | * [ ] config: warn on untracked, stale reads
167 | * [ ] strict mode: only reads from actions or reactions. Only updates from actions.
168 | * [ ] eliminate classes from code base
169 | * [ ] `drv(( tick ) => ())` to communicate staleness from inside drv (probably also needs onHot / onCold callback in such case)
170 | * [ ] dynamically switch between hook and non-hook implementations (and explain differences)
171 | * [ ] support name option
172 | * [ ] abstraction for creating drv / vals and subscribing in hook based component automatically?
173 | * [ ] MobX global state compatibility?
--------------------------------------------------------------------------------
/docs/assets.json:
--------------------------------------------------------------------------------
1 | {
2 | "app.js": "/rval/static/js/app.c7d38faa.js",
3 | "app.js.map": "/rval/static/js/app.e2ac49079e2d157a0b49.js.map",
4 | "docs-source-0-introduction-00-about.js": "/rval/static/js/docs-source-0-introduction-00-about.33cb42e7.js",
5 | "docs-source-0-introduction-00-about.js.map": "/rval/static/js/docs-source-0-introduction-00-about.e2ac49079e2d157a0b49.js.map",
6 | "docs-source-0-introduction-05-installation.js": "/rval/static/js/docs-source-0-introduction-05-installation.a5841abe.js",
7 | "docs-source-0-introduction-05-installation.js.map": "/rval/static/js/docs-source-0-introduction-05-installation.e2ac49079e2d157a0b49.js.map",
8 | "docs-source-0-introduction-10-getting-started.js": "/rval/static/js/docs-source-0-introduction-10-getting-started.2b91f695.js",
9 | "docs-source-0-introduction-10-getting-started.js.map": "/rval/static/js/docs-source-0-introduction-10-getting-started.e2ac49079e2d157a0b49.js.map",
10 | "docs-source-0-introduction-20-objects-and-factories.js": "/rval/static/js/docs-source-0-introduction-20-objects-and-factories.0928d7eb.js",
11 | "docs-source-0-introduction-20-objects-and-factories.js.map": "/rval/static/js/docs-source-0-introduction-20-objects-and-factories.e2ac49079e2d157a0b49.js.map",
12 | "docs-source-0-introduction-30-with-react.js": "/rval/static/js/docs-source-0-introduction-30-with-react.7cb56417.js",
13 | "docs-source-0-introduction-30-with-react.js.map": "/rval/static/js/docs-source-0-introduction-30-with-react.e2ac49079e2d157a0b49.js.map",
14 | "docs-source-0-introduction-40-philosophy.js": "/rval/static/js/docs-source-0-introduction-40-philosophy.fea48fa9.js",
15 | "docs-source-0-introduction-40-philosophy.js.map": "/rval/static/js/docs-source-0-introduction-40-philosophy.e2ac49079e2d157a0b49.js.map",
16 | "docs-source-1-advanced-examples.js": "/rval/static/js/docs-source-1-advanced-examples.85d2c45c.js",
17 | "docs-source-1-advanced-examples.js.map": "/rval/static/js/docs-source-1-advanced-examples.e2ac49079e2d157a0b49.js.map",
18 | "docs-source-1-advanced-models.js": "/rval/static/js/docs-source-1-advanced-models.d824a22c.js",
19 | "docs-source-1-advanced-models.js.map": "/rval/static/js/docs-source-1-advanced-models.e2ac49079e2d157a0b49.js.map",
20 | "docs-source-1-advanced-preprocessors.js": "/rval/static/js/docs-source-1-advanced-preprocessors.2cd0bb51.js",
21 | "docs-source-1-advanced-preprocessors.js.map": "/rval/static/js/docs-source-1-advanced-preprocessors.e2ac49079e2d157a0b49.js.map",
22 | "pkgs-core-readme.js": "/rval/static/js/pkgs-core-readme.4285a63b.js",
23 | "pkgs-core-readme.js.map": "/rval/static/js/pkgs-core-readme.e2ac49079e2d157a0b49.js.map",
24 | "pkgs-react-readme.js": "/rval/static/js/pkgs-react-readme.e1c9a28e.js",
25 | "pkgs-react-readme.js.map": "/rval/static/js/pkgs-react-readme.e2ac49079e2d157a0b49.js.map",
26 | "pkgs-updaters-readme.js": "/rval/static/js/pkgs-updaters-readme.429519e2.js",
27 | "pkgs-updaters-readme.js.map": "/rval/static/js/pkgs-updaters-readme.e2ac49079e2d157a0b49.js.map",
28 | "runtime~app.js": "/rval/static/js/runtime~app.e2ac49079e2d157a0b49.js",
29 | "runtime~app.js.map": "/rval/static/js/runtime~app.e2ac49079e2d157a0b49.js.map",
30 | "vendors.js": "/rval/static/js/vendors.15c669d7.js",
31 | "vendors.js.map": "/rval/static/js/vendors.e2ac49079e2d157a0b49.js.map",
32 | "static/js/15.854c9d6f.js": "/rval/static/js/15.854c9d6f.js",
33 | "static/js/15.e2ac49079e2d157a0b49.js.map": "/rval/static/js/15.e2ac49079e2d157a0b49.js.map",
34 | "index.html": "/rval/index.html"
35 | }
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
Rval
--------------------------------------------------------------------------------
/docs/static/js/15.854c9d6f.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[15],{"./.docz/app/imports.js":function(n,o,t){"use strict";t.r(o),t.d(o,"imports",function(){return d});var d={"docs_source/0_introduction/00_about.mdx":function(){return t.e(1).then(t.bind(null,"./docs_source/0_introduction/00_about.mdx"))},"docs_source/0_introduction/05_installation.mdx":function(){return t.e(2).then(t.bind(null,"./docs_source/0_introduction/05_installation.mdx"))},"docs_source/0_introduction/10_getting-started.mdx":function(){return t.e(3).then(t.bind(null,"./docs_source/0_introduction/10_getting-started.mdx"))},"docs_source/0_introduction/20_objects-and-factories.mdx":function(){return t.e(4).then(t.bind(null,"./docs_source/0_introduction/20_objects-and-factories.mdx"))},"docs_source/0_introduction/30_with-react.mdx":function(){return t.e(5).then(t.bind(null,"./docs_source/0_introduction/30_with-react.mdx"))},"docs_source/0_introduction/40_philosophy.mdx":function(){return t.e(6).then(t.bind(null,"./docs_source/0_introduction/40_philosophy.mdx"))},"docs_source/1_advanced/examples.mdx":function(){return t.e(7).then(t.bind(null,"./docs_source/1_advanced/examples.mdx"))},"docs_source/1_advanced/models.mdx":function(){return t.e(8).then(t.bind(null,"./docs_source/1_advanced/models.mdx"))},"docs_source/1_advanced/preprocessors.mdx":function(){return t.e(9).then(t.bind(null,"./docs_source/1_advanced/preprocessors.mdx"))},"pkgs/core/README.mdx":function(){return t.e(10).then(t.bind(null,"./pkgs/core/README.mdx"))},"pkgs/react/README.mdx":function(){return t.e(11).then(t.bind(null,"./pkgs/react/README.mdx"))},"pkgs/updaters/README.mdx":function(){return t.e(12).then(t.bind(null,"./pkgs/updaters/README.mdx"))}}}},0,[1,2,3,4,5,6,7,8,9,10,11,12]]);
2 | //# sourceMappingURL=15.e2ac49079e2d157a0b49.js.map
--------------------------------------------------------------------------------
/docs/static/js/15.e2ac49079e2d157a0b49.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./.docz/app/imports.js"],"names":["__webpack_require__","r","__webpack_exports__","d","imports","docs_source/0_introduction/00_about.mdx","e","then","bind","docs_source/0_introduction/05_installation.mdx","docs_source/0_introduction/10_getting-started.mdx","docs_source/0_introduction/20_objects-and-factories.mdx","docs_source/0_introduction/30_with-react.mdx","docs_source/0_introduction/40_philosophy.mdx","docs_source/1_advanced/examples.mdx","docs_source/1_advanced/models.mdx","docs_source/1_advanced/preprocessors.mdx","pkgs/core/README.mdx","pkgs/react/README.mdx","pkgs/updaters/README.mdx"],"mappings":"gHAAAA,EAAAC,EAAAC,GAAAF,EAAAG,EAAAD,EAAA,4BAAAE,IAAO,IAAMA,EAAU,CACrBC,0CAA2C,kBACzCL,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,oDACFC,iDAAkD,kBAChDT,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,2DACFE,oDAAqD,kBACnDV,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,8DACFG,0DAA2D,kBACzDX,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,oEACFI,+CAAgD,kBAC9CZ,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,yDACFK,+CAAgD,kBAC9Cb,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,yDACFM,sCAAuC,kBACrCd,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,gDACFO,oCAAqC,kBACnCf,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,8CACFQ,2CAA4C,kBAC1ChB,EAAAM,EAAA,GAAAC,KAAAP,EAAAQ,KAAA,qDACFS,uBAAwB,kBACtBjB,EAAAM,EAAA,IAAAC,KAAAP,EAAAQ,KAAA,iCACFU,wBAAyB,kBACvBlB,EAAAM,EAAA,IAAAC,KAAAP,EAAAQ,KAAA,kCACFW,2BAA4B,kBAC1BnB,EAAAM,EAAA,IAAAC,KAAAP,EAAAQ,KAAA","file":"static/js/15.854c9d6f.js","sourcesContent":["export const imports = {\n 'docs_source/0_introduction/00_about.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-0-introduction-00-about\" */ 'docs_source/0_introduction/00_about.mdx'),\n 'docs_source/0_introduction/05_installation.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-0-introduction-05-installation\" */ 'docs_source/0_introduction/05_installation.mdx'),\n 'docs_source/0_introduction/10_getting-started.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-0-introduction-10-getting-started\" */ 'docs_source/0_introduction/10_getting-started.mdx'),\n 'docs_source/0_introduction/20_objects-and-factories.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-0-introduction-20-objects-and-factories\" */ 'docs_source/0_introduction/20_objects-and-factories.mdx'),\n 'docs_source/0_introduction/30_with-react.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-0-introduction-30-with-react\" */ 'docs_source/0_introduction/30_with-react.mdx'),\n 'docs_source/0_introduction/40_philosophy.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-0-introduction-40-philosophy\" */ 'docs_source/0_introduction/40_philosophy.mdx'),\n 'docs_source/1_advanced/examples.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-1-advanced-examples\" */ 'docs_source/1_advanced/examples.mdx'),\n 'docs_source/1_advanced/models.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-1-advanced-models\" */ 'docs_source/1_advanced/models.mdx'),\n 'docs_source/1_advanced/preprocessors.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"docs-source-1-advanced-preprocessors\" */ 'docs_source/1_advanced/preprocessors.mdx'),\n 'pkgs/core/README.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"pkgs-core-readme\" */ 'pkgs/core/README.mdx'),\n 'pkgs/react/README.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"pkgs-react-readme\" */ 'pkgs/react/README.mdx'),\n 'pkgs/updaters/README.mdx': () =>\n import(/* webpackPrefetch: true, webpackChunkName: \"pkgs-updaters-readme\" */ 'pkgs/updaters/README.mdx'),\n}\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/app.c7d38faa.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{"./.docz/app/db.json":function(e){e.exports={config:{title:"Rval",description:"My awesome app using docz",menu:[],ordering:"descending",version:"0.0.1",repository:"https://github.com/mweststrate/rval",native:!1,codeSandbox:!0,themeConfig:{},base:"/rval/",dest:"docs",propsParser:!1,hashRouter:!0},entries:{"docs_source/0_introduction/00_about.mdx":{name:"About RVal",order:0,menu:"Introduction",route:"/",id:"40e7c723e6cd44e2fb55eed5fa5b8126",filepath:"docs_source/0_introduction/00_about.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/0_introduction/00_about.mdx",slug:"docs-source-0-introduction-00-about",headings:[{depth:1,slug:"about-rval",value:"About RVal"},{depth:2,slug:"quick-example",value:"Quick example"},{depth:2,slug:"philosophy",value:"Philosophy"}]},"docs_source/0_introduction/05_installation.mdx":{name:"Installation",order:1,menu:"Introduction",route:"/introduction/installation",id:"8c812cec5cfa47c09046c0ad4028d9e9",filepath:"docs_source/0_introduction/05_installation.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/0_introduction/05_installation.mdx",slug:"docs-source-0-introduction-05-installation",headings:[{depth:2,slug:"packages",value:"Packages"}]},"docs_source/0_introduction/10_getting-started.mdx":{name:"The Basics",order:2,menu:"Introduction",route:"/introduction/the-basics",id:"881f0239ef16525c0578edcfeec12cfe",filepath:"docs_source/0_introduction/10_getting-started.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/0_introduction/10_getting-started.mdx",slug:"docs-source-0-introduction-10-getting-started",headings:[{depth:1,slug:"getting-started-with-rval",value:"Getting started with RVal"},{depth:2,slug:"val-reactive-values",value:"val : reactive values"},{depth:2,slug:"drv-derived-values",value:"drv : derived values"},{depth:2,slug:"sub-listing-to-changes",value:"sub : listing to changes"},{depth:2,slug:"act-batching-updates",value:"act : batching updates"}]},"docs_source/0_introduction/20_objects-and-factories.mdx":{name:"Working with objects",order:3,menu:"Introduction",route:"/introduction/factories",id:"f11a1014b5943e7acc23512d5c0f57f0",filepath:"docs_source/0_introduction/20_objects-and-factories.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/0_introduction/20_objects-and-factories.mdx",slug:"docs-source-0-introduction-20-objects-and-factories",headings:[{depth:1,slug:"working-with-objects-and-arrays",value:"Working with objects and arrays"},{depth:2,slug:"a-first-object-factory",value:"A first object factory"},{depth:2,slug:"creating-collections",value:"Creating collections"},{depth:2,slug:"simplifying-updates-with-updaters",value:"Simplifying updates with updaters"},{depth:2,slug:"next-steps",value:"Next steps"},{depth:2,slug:"background-what-about-classes",value:"Background: what about classes?"}]},"docs_source/0_introduction/30_with-react.mdx":{name:"Using react",order:4,menu:"Introduction",route:"/introduction/react",id:"ec224d754815113334362af6422d0f07",filepath:"docs_source/0_introduction/30_with-react.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/0_introduction/30_with-react.mdx",slug:"docs-source-0-introduction-30-with-react",headings:[]},"docs_source/0_introduction/40_philosophy.mdx":{name:"Philosophy",order:5,menu:"Introduction",route:"/introduction/philosophy",id:"7fb81491976fe813a74bb7d04fe1ee76",filepath:"docs_source/0_introduction/40_philosophy.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/0_introduction/40_philosophy.mdx",slug:"docs-source-0-introduction-40-philosophy",headings:[{depth:1,slug:"the-philosophy-of-rval",value:"The Philosophy of RVal"},{depth:2,slug:"functions-solidify-state",value:"Functions solidify state"}]},"docs_source/1_advanced/examples.mdx":{name:"Examples",order:3,menu:"Advanced",route:"/advanced/examples",id:"852af60ceb032d002177699d60ea205a",filepath:"docs_source/1_advanced/examples.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/1_advanced/examples.mdx",slug:"docs-source-1-advanced-examples",headings:[]},"docs_source/1_advanced/models.mdx":{name:"Working with models",order:1,menu:"Advanced",route:"/advanced/models",id:"8e346cafc38eaef81418b120d0433853",filepath:"docs_source/1_advanced/models.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/1_advanced/models.mdx",slug:"docs-source-1-advanced-models",headings:[]},"docs_source/1_advanced/preprocessors.mdx":{name:"Using preprocessors",order:0,menu:"Advanced",route:"/advanced/preprocessors",id:"2c3f02cbe7776436e609ca868dd69c16",filepath:"docs_source/1_advanced/preprocessors.mdx",link:"https://github.com/mweststrate/rval/edit/master/docs_source/1_advanced/preprocessors.mdx",slug:"docs-source-1-advanced-preprocessors",headings:[]},"pkgs/core/README.mdx":{name:"Core api",order:1,menu:"API",route:"/api/core",id:"b36d139fb3bf841133c7e5bb2f02087a",filepath:"pkgs/core/README.mdx",link:"https://github.com/mweststrate/rval/edit/master/pkgs/core/README.mdx",slug:"pkgs-core-readme",headings:[{depth:1,slug:"r-valcore-api",value:"@r-val/core api"},{depth:2,slug:"val",value:"val"}]},"pkgs/react/README.mdx":{name:"React bindings",order:1,menu:"API",route:"/api/react",id:"36aa066c925eb504a630abe2dc46d199",filepath:"pkgs/react/README.mdx",link:"https://github.com/mweststrate/rval/edit/master/pkgs/react/README.mdx",slug:"pkgs-react-readme",headings:[]},"pkgs/updaters/README.mdx":{name:"Updaters",order:1,menu:"API",route:"/api/updaters",id:"0645ac7f29fb88970c6bd085191b5c70",filepath:"pkgs/updaters/README.mdx",link:"https://github.com/mweststrate/rval/edit/master/pkgs/updaters/README.mdx",slug:"pkgs-updaters-readme",headings:[{depth:1,slug:"r-valupdaters",value:"@r-val/updaters"},{depth:2,slug:"inc1",value:"inc1"}]}}}},"./.docz/app/index.jsx":function(e,t,o){"use strict";o.r(t);var s=o("./node_modules/react/index.js"),d=o.n(s),a=o("./node_modules/react-dom/index.js"),r=o.n(a),c=o("./.docz/app/root.jsx"),i=[],n=[],u=function(){return n.forEach(function(e){return e&&e()})},l=document.querySelector("#root");!function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:c.a;i.forEach(function(e){return e&&e()}),r.a.render(d.a.createElement(e,null),l,u)}(c.a)},"./.docz/app/root.jsx":function(e,t,o){"use strict";(function(e){var s=o("./node_modules/react/index.js"),d=o.n(s),a=o("./node_modules/react-hot-loader/index.js"),r=o("./node_modules/docz-theme-default/dist/index.m.js");t.a=Object(a.hot)(e)(function(){return d.a.createElement(r.a,null)})}).call(this,o("./node_modules/webpack/buildin/harmony-module.js")(e))},0:function(e,t,o){o("./node_modules/react-dev-utils/webpackHotDevClient.js"),o("./node_modules/@babel/polyfill/lib/index.js"),e.exports=o("./.docz/app/index.jsx")}},[[0,13,14]]]);
2 | //# sourceMappingURL=app.e2ac49079e2d157a0b49.js.map
--------------------------------------------------------------------------------
/docs/static/js/app.e2ac49079e2d157a0b49.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./.docz/app/index.jsx","webpack:///./.docz/app/root.jsx"],"names":["__webpack_require__","r","__webpack_exports__","react__WEBPACK_IMPORTED_MODULE_0__","react__WEBPACK_IMPORTED_MODULE_0___default","n","react_dom__WEBPACK_IMPORTED_MODULE_1__","react_dom__WEBPACK_IMPORTED_MODULE_1___default","_root__WEBPACK_IMPORTED_MODULE_2__","_onPreRenders","_onPostRenders","onPostRender","forEach","f","root","document","querySelector","Component","arguments","length","undefined","Root","ReactDOM","render","a","createElement","module","react_hot_loader__WEBPACK_IMPORTED_MODULE_1__","docz_theme_default__WEBPACK_IMPORTED_MODULE_2__","hot"],"mappings":"uxLAAAA,EAAAC,EAAAC,GAAA,IAAAC,EAAAH,EAAA,iCAAAI,EAAAJ,EAAAK,EAAAF,GAAAG,EAAAN,EAAA,qCAAAO,EAAAP,EAAAK,EAAAC,GAAAE,EAAAR,EAAA,wBAIMS,EAAgB,GAChBC,EAAiB,GAGjBC,EAAe,kBAAMD,EAAeE,QAAQ,SAAAC,GAAC,OAAIA,GAAKA,OAEtDC,EAAOC,SAASC,cAAc,UACrB,WAAsB,IAArBC,EAAqBC,UAAAC,OAAA,QAAAC,IAAAF,UAAA,GAAAA,UAAA,GAATG,IAJFZ,EAAcG,QAAQ,SAAAC,GAAC,OAAIA,GAAKA,MAMxDS,IAASC,OAAOnB,EAAAoB,EAAAC,cAACR,EAAD,MAAeH,EAAMH,GAGvCY,CAAOF,2DChBP,SAAAK,GAAA,IAAAvB,EAAAH,EAAA,iCAAAI,EAAAJ,EAAAK,EAAAF,GAAAwB,EAAA3B,EAAA,4CAAA4B,EAAA5B,EAAA,qDAMe6B,kBAAIH,EAAJG,CAFF,kBAAMzB,EAAAoB,EAAAC,cAACG,EAAA,EAAD","file":"static/js/app.c7d38faa.js","sourcesContent":["import React from 'react'\nimport ReactDOM from 'react-dom'\nimport Root from './root'\n\nconst _onPreRenders = []\nconst _onPostRenders = []\n\nconst onPreRender = () => _onPreRenders.forEach(f => f && f())\nconst onPostRender = () => _onPostRenders.forEach(f => f && f())\n\nconst root = document.querySelector('#root')\nconst render = (Component = Root) => {\n onPreRender()\n ReactDOM.render(, root, onPostRender)\n}\n\nrender(Root)\n","import React from 'react'\nimport { hot } from 'react-hot-loader'\nimport Theme from 'docz-theme-default'\n\nconst Root = () => \n\nexport default hot(module)(Root)\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/docs-source-0-introduction-00-about.33cb42e7.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[1],{"./docs_source/0_introduction/00_about.mdx":function(e,n,t){"use strict";t.r(n),t.d(n,"default",function(){return u});var a=t("./node_modules/react/index.js"),o=t.n(a),r=t("./node_modules/@mdx-js/tag/dist/index.js");function i(e){return(i="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function m(e,n){if(null==e)return{};var t,a,o=function(e,n){if(null==e)return{};var t,a,o={},r=Object.keys(e);for(a=0;a=0||(o[t]=e[t]);return o}(e,n);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}function l(e,n){for(var t=0;t{`About RVal`}\n{`RVal is a minimalistic, transparent reactive programming library, heavily inspired by `}{`MobX`}{`,\nwith the same core principle: `}{`Everything that can be derived from state, should be derived. Automatically`}{`.`}\n{`However, the goals are slightly different and the library is in terms of API surface and bundle size `}{`much`}{` smaller.\nRVal core principles include:`}\n\n{`🍭 `}{`Minimalistic`}{` A very simple, minimalistic core API`}\n{`🛅 `}{`Functions + immutable objects`}{`: Functions and (stateful) immutable objects as the primary means to organize state`}\n{`🎯 `}{`Convention driven`}{`: An idiomatic way of working, that guides devs into the `}{`Pit of Success`}\n{`📦 `}{`Embeddable`}{`: A low level building block, that is small (~2KB minified gzipped) so that it can easily be embedded in existing libraries and frameworks as state management libraries.`}\n{`🐆 `}{`Fast`}{`: Rock solid performance, leveraging the battle tested algorithms of MobX.`}\n{`☔ `}{`Versatile`}{`: no dependencies, no modern syntax or language requirements, non-intrusive, applicable in any ES5 JavaScript stack`}\n{`🎓 `}{`Gradual learning curve`}{`: Opt-in utilities that help with applying best practices`}\n{`💪 `}{`Strongly typed`}{`: Shouldn't need further explanation in 2019`}\n\n{`Ok, that is a pretty vague, generic list of things that sound positive. Hardly saying anything.\nIt boils down to this: RVal, is small, conceptually simple and powerful.\nBut mostly: `}\n{`The proof of the pudding is in the eating.`}{`.`}\n{`Here is a term that you will encounter when reading the introduction:\nIt's all about `}{`reactive values`}{` and `}{`immutable stateful objects`}{`.\nRead the introduction to find out what that abomination of seemingly conflicting concepts means.\nBut at least: you won't be needing `}{`this`}{`, `}{`let`}{`, `}{`var`}{` or `}{`class`}{`.`}\n{`Quick example`}\n{`TODO`}\n{`Sandbox link`}\n{`Philosophy`}\n{`TODO link`}\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/docs-source-0-introduction-05-installation.a5841abe.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[2],{"./docs_source/0_introduction/05_installation.mdx":function(e,n,t){"use strict";t.r(n),t.d(n,"default",function(){return s});var o=t("./node_modules/react/index.js"),r=t.n(o),a=t("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function u(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}function i(e,n){for(var t=0;t{`Yarn / NPM`}\n{`CDN`}\n{`Packages`}\n{`TODO`}\n{`Table, with name, goal, cdn, umdname, bundlesize`}\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/docs-source-0-introduction-30-with-react.7cb56417.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[5],{"./docs_source/0_introduction/30_with-react.mdx":function(t,e,n){"use strict";n.r(e),n.d(e,"default",function(){return s});var o=n("./node_modules/react/index.js"),r=n.n(o),u=n("./node_modules/@mdx-js/tag/dist/index.js");function c(t){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"===typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function i(t,e){if(null==t)return{};var n,o,r=function(t,e){if(null==t)return{};var n,o,r={},u=Object.keys(t);for(o=0;o=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(t);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}function f(t,e){for(var n=0;n\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/docs-source-1-advanced-examples.85d2c45c.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{"./docs_source/1_advanced/examples.mdx":function(e,t,n){"use strict";n.r(t),n.d(t,"default",function(){return s});var o=n("./node_modules/react/index.js"),r=n.n(o),u=n("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},u=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}function f(e,t){for(var n=0;n\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/docs-source-1-advanced-models.d824a22c.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[8],{"./docs_source/1_advanced/models.mdx":function(e,t,n){"use strict";n.r(t),n.d(t,"default",function(){return s});var o=n("./node_modules/react/index.js"),r=n.n(o),u=n("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},u=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}function f(e,t){for(var n=0;n\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/docs-source-1-advanced-preprocessors.2cd0bb51.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[9],{"./docs_source/1_advanced/preprocessors.mdx":function(e,t,n){"use strict";n.r(t),n.d(t,"default",function(){return s});var o=n("./node_modules/react/index.js"),r=n.n(o),u=n("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(null==e)return{};var n,o,r=function(e,t){if(null==e)return{};var n,o,r={},u=Object.keys(e);for(o=0;o=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}function f(e,t){for(var n=0;n\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/pkgs-core-readme.4285a63b.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[10],{"./pkgs/core/README.mdx":function(e,n,t){"use strict";t.r(n),t.d(n,"default",function(){return s});var o=t("./node_modules/react/index.js"),r=t.n(o),a=t("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}function u(e,n){for(var t=0;t fn)")," or ",r.a.createElement(a.MDXTag,{name:"inlineCode",components:n,parentName:"p"},"fnHolder(replace(fn))")))}}])&&u(t.prototype,o),c&&u(t,c),n}()}}]);
2 | //# sourceMappingURL=pkgs-core-readme.e2ac49079e2d157a0b49.js.map
--------------------------------------------------------------------------------
/docs/static/js/pkgs-core-readme.e2ac49079e2d157a0b49.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["webpack:///./pkgs/core/README.mdx"],"names":["MDXContent","props","_this","_classCallCheck","this","_possibleConstructorReturn","_getPrototypeOf","call","layout","React","Component","_this$props","components","_objectWithoutProperties","react__WEBPACK_IMPORTED_MODULE_0___default","a","createElement","_mdx_js_tag__WEBPACK_IMPORTED_MODULE_1__","name","id","parentName"],"mappings":"k6CAKqBA,cACnB,SAAAA,EAAYC,GAAO,IAAAC,EAAA,mGAAAC,CAAAC,KAAAJ,IACjBE,EAAAG,EAAAD,KAAAE,EAAAN,GAAAO,KAAAH,KAAMH,KACDO,OAAS,KAFGN,yPADmBO,IAAMC,kDAKnC,IAAAC,EAC0BP,KAAKH,MAA9BW,EADDD,EACCC,WADDC,EAAAF,EAAA,gBAGP,OAAOG,EAAAC,EAAAC,cAACC,EAAA,OAAD,CACEC,KAAK,UAELN,WAAYA,GAAYE,EAAAC,EAAAC,cAACC,EAAA,OAAD,CAAQC,KAAK,KAAKN,WAAYA,EAAYX,MAAO,CAACkB,GAAK,kBAAvD,mBACrCL,EAAAC,EAAAC,cAACC,EAAA,OAAD,CAAQC,KAAK,KAAKN,WAAYA,EAAYX,MAAO,CAACkB,GAAK,QAAvD,OACAL,EAAAC,EAAAC,cAACC,EAAA,OAAD,CAAQC,KAAK,IAAIN,WAAYA,GAA7B,0BAAoEE,EAAAC,EAAAC,cAACC,EAAA,OAAD,CAAQC,KAAK,aAAaN,WAAYA,EAAYQ,WAAW,KAA7D,sBAApE,OAA4KN,EAAAC,EAAAC,cAACC,EAAA,OAAD,CAAQC,KAAK,aAAaN,WAAYA,EAAYQ,WAAW,KAA7D","file":"static/js/pkgs-core-readme.4285a63b.js","sourcesContent":["\n import React from 'react'\n import { MDXTag } from '@mdx-js/tag'\n \n\nexport default class MDXContent extends React.Component {\n constructor(props) {\n super(props)\n this.layout = null\n }\n render() {\n const { components, ...props } = this.props\n\n return {`@r-val/core api`}\n{`val`}\n{`How to set a function? `}{`fnHolder(() => fn)`}{` or `}{`fnHolder(replace(fn))`}\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/pkgs-react-readme.e1c9a28e.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[11],{"./pkgs/react/README.mdx":function(e,n,t){"use strict";t.r(n),t.d(n,"default",function(){return s});var o=t("./node_modules/react/index.js"),r=t.n(o),a=t("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function l(e,n){if(null==e)return{};var t,o,r=function(e,n){if(null==e)return{};var t,o,r={},a=Object.keys(e);for(o=0;o=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}function u(e,n){for(var t=0;t{`useVal`}\n\n{`context`}\n\n{`useLocalVal`}\n\n{`context`}\n\n{`useLocalDrv`}\n\n{`inputs`}\n{`context`}\n\n{`rview`}\n\n{`chidren`}\n{`memo (true, false, array)`}\n{`context`}\n\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/pkgs-updaters-readme.429519e2.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[12],{"./pkgs/updaters/README.mdx":function(e,t,n){"use strict";n.r(t),n.d(t,"default",function(){return s});var r=n("./node_modules/react/index.js"),o=n.n(r),u=n("./node_modules/@mdx-js/tag/dist/index.js");function c(e){return(c="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function i(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},u=Object.keys(e);for(r=0;r=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var u=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){for(var n=0;n{`@r-val/updaters`}\n{`inc1`}\n \n }\n}\n "],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/runtime~app.e2ac49079e2d157a0b49.js:
--------------------------------------------------------------------------------
1 | !function(e){function r(r){for(var t,o,c=r[0],i=r[1],d=r[2],a=r[3]||[],s=0,u=[];s=0&&r._disposeHandlers.splice(n,1)},check:E,apply:x,status:function(e){if(!e)return f;p.push(e)},addStatusHandler:function(e){p.push(e)},removeStatusHandler:function(e){var r=p.indexOf(e);r>=0&&p.splice(r,1)},data:a[e]};return o=void 0,r}var p=[],f="idle";function h(e){f=e;for(var r=0;r0;){var o=t.pop(),i=o.id,d=o.chain;if((c=H[i])&&!c.hot._selfAccepted){if(c.hot._selfDeclined)return{type:"self-declined",chain:d,moduleId:i};if(c.hot._main)return{type:"unaccepted",chain:d,moduleId:i};for(var a=0;a ")),O.type){case"self-declined":r.onDeclined&&r.onDeclined(O),r.ignoreDeclined||(E=new Error("Aborted because of self decline: "+O.moduleId+x));break;case"declined":r.onDeclined&&r.onDeclined(O),r.ignoreDeclined||(E=new Error("Aborted because of declined dependency: "+O.moduleId+" in "+O.parentId+x));break;case"unaccepted":r.onUnaccepted&&r.onUnaccepted(O),r.ignoreUnaccepted||(E=new Error("Aborted because "+d+" is not accepted"+x));break;case"accepted":r.onAccepted&&r.onAccepted(O),D=!0;break;case"disposed":r.onDisposed&&r.onDisposed(O),P=!0;break;default:throw new Error("Unexception type "+O.type)}if(E)return h("abort"),Promise.reject(E);if(D)for(d in b[d]=y[d],l(v,O.outdatedModules),O.outdatedDependencies)Object.prototype.hasOwnProperty.call(O.outdatedDependencies,d)&&(p[d]||(p[d]=[]),l(p[d],O.outdatedDependencies[d]));P&&(l(v,[O.moduleId]),b[d]=g)}var I,A=[];for(t=0;t0;)if(d=q.pop(),c=H[d]){var U={},N=c.hot._disposeHandlers;for(o=0;o=0&&R.parents.splice(I,1))}}for(d in p)if(Object.prototype.hasOwnProperty.call(p,d)&&(c=H[d]))for(T=p[d],o=0;o=0&&c.children.splice(I,1);for(d in h("apply"),i=m,b)Object.prototype.hasOwnProperty.call(b,d)&&(e[d]=b[d]);var B=null;for(d in p)if(Object.prototype.hasOwnProperty.call(p,d)&&(c=H[d])){T=p[d];var C=[];for(t=0;t rview(() => (
51 | <>
52 | {counter()}
53 |
54 | >
55 | ))
56 |
57 | setInterval(() => {
58 | counter(c => c + 1)
59 | }, 1000)
60 |
61 | render(, document.body)
62 | ```
63 |
64 | This example can be tried in [code sandbox](https://codesandbox.io/s/m297j6w38). Some quick highlights:
65 |
66 | 1. This application has a single _reactive value_, called `counter`, initialized to `0`.
67 | 2. The component is reading the current value, by calling `counter()`, that simply returns the current state.
68 | 3. The `onClick` handler replaces the internal state of the `counter` with the value `0` again.
69 | 4. The `setInterval` updates the `counter` every second, using a function that takes the current state of the `counter`, and produces a new state.
70 | 5. The [`rview`](#/introduction/react) function creates a _reactive view_, which takes a render callback, and re-render's automatically when any of the reactive values inside it's function body changes. That is why we see the counter actually ticking (Note that the `counter` is neither part of the state or props of the component).
71 |
72 | Hopefully this example will strike you as slightly boring. Good, this library wasn't build to write counters.
73 | The following example is slightly more elaborate. Or you can just jump ahead to all the [core concepts](#/introduction/the-basics).
74 |
75 | ## Slightly more elaborate example
76 |
77 | TODO
78 |
79 | ## More examples
80 |
81 | An overview of more examples can be found in the [examples](#/advanced/examples) section.
82 |
83 | ## Philosophy
84 |
85 | Interesting in the _why_ of RVal? In that case check out the [philosophy](#/introduction/philosophy) section.
86 |
87 | [^1]: Compared to Mobx, the goals are slightly different and the library is in terms of API surface and bundle size _much_ smaller.
--------------------------------------------------------------------------------
/docs_source/0_introduction/05_installation.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Installation
3 | order: 1
4 | menu: Introduction
5 | route: /introduction/installation
6 | ---
7 |
8 | Yarn / NPM
9 |
10 | CDN
11 |
12 | ## Packages
13 |
14 | TODO
15 |
16 | Table, with name, goal, cdn, umdname, bundlesize
17 |
--------------------------------------------------------------------------------
/docs_source/0_introduction/10_getting-started.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: The Basics
3 | order: 2
4 | menu: Introduction
5 | route: /introduction/the-basics
6 | ---
7 |
8 | # Getting started with RVal
9 |
10 | The core of `RVal` is four functions which have all a very simple contract: `val`, `drv`, `sub` and `act`.
11 | Yes, they all have three-letter names. That's kind of cool I think. Not sure yet why.
12 |
13 | ## `val`: reactive values
14 |
15 | _“Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.” — John Carmack_
16 |
17 | In RVal, the universe revolves around _reactive values_.
18 | Creating your first reactive value is easy by leveraging `val(initialValue)`:
19 |
20 | ```javascript
21 | import { val } from "@r-val/core";
22 |
23 | const myLuckyNumber = val(13)
24 | ```
25 |
26 | `val` returns a function that returns any **value** you've put into it.
27 | So `myLuckyNumber` is now a function, returning the original number, and we can call it:
28 |
29 | ```javascript
30 | console.log(myLuckyNumber())
31 | // prints: 13
32 | ```
33 |
34 | Fancy! But what use is it to create a function that just returns the original value?
35 | We'll find out in a bit.
36 | First, there is another trick the function can do: We can call it with a new lucky number,
37 | (in case `13` didn't work out after all):
38 |
39 | ```javascript
40 | myLuckyNumber(42)
41 |
42 | console.log(myLuckyNumber())
43 | // prints: 42
44 | ```
45 |
46 | By passing an argument to the function, we can update it's internal state.
47 | When calling the reactive value function without argumens, it will always return the value we've passed into it the last time.
48 |
49 | You can put any value you like into a reactive value.
50 | But, for all practical purposes, you've should consider this value to be immutable.
51 | This will greatly benefit the understanding of the code base once it grows big enough.
52 | But, more on that later.
53 |
54 | See the [Philosophy](docs-philosophy) for some more background on this idea.
55 |
56 | ## `drv`: derived values
57 |
58 | _“No, officer 👮♀️, I didn't drv(thunk)!” — Erik Rasmussen_
59 |
60 | In my humble opinion, good lucky numbers should at least be odd. So we can quickly run a check for that:
61 |
62 | ```javascript
63 | const myLuckyNumber = val(13)
64 | const isGoodLuckyNumber = myLuckyNumber() % 2 === 1
65 | ```
66 |
67 | That works. But is a bit limited, if we update `myLuckyNumber` later on, this change won't be reflected
68 | in `isGoodLuckyNumber`.
69 | But, using `drv` we can repeat a similar trick as we did for `val`:
70 | Instead of capturing some state, `drv` captures a computation.
71 | It returns a function, that, when invoked, runs the computation once.
72 |
73 | ```javascript
74 | const myLuckyNumber = val(13)
75 | const isGoodLuckyNumber = drv(() => myLuckyNumber() % 2 === 1)
76 |
77 | console.log(isGoodLuckyNumber()) // true
78 | myLuckyNumber(42)
79 | console.log(isGoodLuckyNumber()) // false
80 | ```
81 |
82 | `drv` can be used to **derive** arbitrarly simple or complex values based on other reactive values, created by either `drv` or `val`.
83 |
84 | The critical reader might think at this point: “That's nice and dandy, but you couldn't we just have used `const isGoodLuckyNumber = () => myLuckyNumber() % 2 === 1`?”.
85 | And that is true, glad you ask. That would indeed have yielded the same output.
86 | But! Using `drv` brings in a few new possiblities:
87 |
88 | First, `drv` will memoize[^(usually)] it's results. That is: as long as `myLuckyNumber` doesn't change, invoking `isGoodLuckyNumber()` multiple times won't actually re-evaluate the original expression, but just return a memoized result.
89 |
90 | Secondly, and more importantly. So far we having been pulling values through our system by explicitly calling `myLuckyNumber()` or `isGoodLuckyNumber()`.
91 | But in a reactive system, the control flow is inversed[^(a.k.a. inversion of control)].
92 | To build a reactive system, we have to push our values to consumers and actively _notify_ them.
93 |
94 | ## `sub`: listing to changes
95 |
96 | _“If a tree falls in a forest and no one is around to hear it, does it make a sound?” — The Chautauquan, 1883_
97 |
98 | And that is where `sub` comes in!
99 | With `sub`, one can create a consumer of a reactive value created using `val` or `drv`.
100 | In other words, it sets up a **subscription**.
101 | This creates a _we'll call you_ basis of operation:
102 |
103 | ```javascript
104 | const myLuckyNumber = val(13)
105 | const isGoodLuckyNumber = drv(() => myLuckyNumber() % 2 === 1)
106 |
107 | const cancelPrint = sub(isGoodLuckyNumber, isGood => {
108 | console.log(isGood)
109 | })
110 |
111 | myLuckyNumber(42) // prints: 'false'
112 | myLuckyNumber(33) // prints: 'true'
113 | myLuckyNumber(55) // (doesn't print, isGoodLuckyNumber didn't produce a new value)
114 | myLuckyNumber(2) // prints: 'false'
115 |
116 | cancelPrint() // stop listening to future updates
117 | ```
118 |
119 | Finally, we did something that we couldn't have achieved by using just plain functions and omitting `drv` or `val`.
120 | What `drv` and `val` achieve is that they set up a dependency system, so that when we update state, this state is propagated through the derived values, to the subscriptions.
121 | Transparent reactive programming is used to determine the optimal program flow, and based on the [MobX](https://mobx.js.org) package.
122 |
123 | Note that we didn't pass `isGoodLuckyNumber()`! We want to subscribe to the function's future output, not to it's current value (`13`).
124 | Also note that `sub` returns a function. This function has only one purpose: cancelling future executions of the subscription.
125 |
126 | A remarkable property about `sub` is that you don't need them as often as you would initially think.
127 | They are not needed to propagate values through your system. `drv` can take care of that.
128 | `sub` is generally only need to achieve side effects; visible output from your system.
129 | Such as updating the UI, logging, making network effects etc.
130 |
131 |
132 | ## `act`: batching updates
133 |
134 | _“No act of kindness, no matter how small, is ever wasted...” — Aesop_
135 |
136 | You might have noticed that in the previous listening or side effects where immediately fired when emitting an update to `myLuckyNumber`.
137 | This is just the default behavior and there are several ways to influence it.
138 | First of all, we can use techniques like debounce to roun our subscriptions less frequently.
139 | But more importantly, we can hold of the reactive system to wait a bit until we've done all our updates,
140 | so that changes will be broadcased as one atomic update.
141 | To express that, there is `act` to group multiple changes into a single **activity**.
142 | `act` takes accepts a function, and returns a function with the same signature, that, when invoked, will batch the updates.
143 |
144 | ```javascript
145 | const cancelPrint = sub(isGoodLuckyNumber, isGood => {
146 | console.log(isGood)
147 | })
148 |
149 | const assignNumbers = act(() => {
150 | myLuckyNumber(42)
151 | myLuckyNumber(33)
152 | myLuckyNumber(55)
153 | myLuckyNumber(2)
154 | })
155 |
156 | assignNumbers()// prints only once, at the end of the activity: 'false'
157 | ```
158 |
159 | That's all! Note that `act` only batches _synchronosly_ run updates. Passing an `async` function to `act` is in that regard mostly useless.
160 |
161 | ---
162 |
163 | Your system will most probably not be expressible in a single `val`, `drv` and `sub`.
164 | But, we've now covered the entire basic mechanism of "rval"!
165 | In the next sections we will focus on organizing many different values, objects etc.
166 | And see how we can hook up the UI.
167 |
168 | [^(usually)]: `drv` will by default memoize as long as there is at least one active subscription. Without subscriptions, memoization will be disabled to avoid accidentally leaking memory. The behavior can be overriden by using the `keepAlive` option. (TODO).
169 | [^(a.k.a. inversion of control)]: Wiki: [Inversion of control](https://en.wikipedia.org/wiki/Inversion_of_control)
--------------------------------------------------------------------------------
/docs_source/0_introduction/30_with-react.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Using react
3 | order: 4
4 | menu: Introduction
5 | route: /introduction/react
6 | ---
7 |
8 | # Using RVal with React
9 |
10 | RVal is in essence framework agnostic.
11 | But, official bindings for React are available through the `@r-val/react` package.
12 | (This package is a very thin layer around the `effect` function).
13 |
14 | ## `useVal`: Subscribe with hooks
15 |
16 | The simplest way to consume a reactive value in a component is to use the `useVal` hook.
17 | Note that `useVal` uses React hooks, which aren't officially released yet!
18 | We just start with those because they are conceptually the most straight-forward, but RVal will work with any version of React 16.
19 |
20 | The `useVal` hook can be passed any reactive value (either an `val` or `drv`), and makes sure the component subscribes to the changes in this value.
21 | It simply returns the current state of the reactive value passed.
22 | Note that `useVal` doesn't return a setter function! To update the reactive value, just call the reactive value directly with a new value, as shown below in the `onClick` handler:
23 |
24 | ```javascript
25 | import React from "react"
26 | import { render } from "react-dom"
27 | import { val } from "@r-val/core"
28 | import { useVal } from "@r-val/react"
29 |
30 | const counter = val(0)
31 |
32 | const Counter = () => {
33 | const c = useVal(counter)
34 | return (<>
35 | {c}
36 |
39 | >)
40 | }
41 |
42 | setInterval(() => {
43 | counter(c => c + 1)
44 | }, 1000);
45 |
46 | render(, document.body)
47 | ```
48 |
49 | [Try online](https://codesandbox.io/s/m297j6w38)
50 |
51 | ## `rview`: Reactive views
52 |
53 | With `useVal`, we can pick one by one all the reactive values we wan't to subscribe to.
54 | This is quite explicit, but it easy to subscribe to to few, or too many reactive values.
55 | And more important, `useVal` is quite limited; due to the nature of hooks it is not possible to
56 | conditionally subscribe to reactive values.
57 | While in practice not all values might always be relevant in all states of the component!
58 |
59 | So, that is where `rview` comes in!
60 | `rview` is conceptually very similar to `drv`, except that it is specialized to produce and update React components.
61 | `rview` takes a render callback (without arguments) and returns an `RView` component instance.
62 | The neat thing is that `rview` will automatically keep track of all the reactive values that are used in the render callback, and subscribes to them,
63 | so that you don't have to.
64 | (And it will even unsubscribe from reactive values that are (temporarily) unused).
65 | So with `rview`, our previous counter simply boils down to the following, and note that `counter()` can be called directly in the render callback:
66 |
67 |
68 | ```javascript
69 | import React from "react"
70 | import { render } from "react-dom"
71 | import { val } from "@r-val/core"
72 | import { useVal } from "@r-val/react"
73 |
74 | const counter = val(0)
75 |
76 | const Counter = () => rview(() => (
77 | <>
78 | {counter()}
79 |
82 | >
83 | ))
84 |
85 | setInterval(() => {
86 | counter(c => c + 1)
87 | }, 1000);
88 |
89 | render(, document.body)
90 | ```
91 | as [code sandbox](https://codesandbox.io/s/m297j6w38)
92 |
93 | _Tip: `rview` doesn't require hooks, so it works in any React 16.+ version._
94 |
95 | Note that `rview` is quite optimized out of the box. When using RVal with `rview`, you shouldn't need `shouldComponentUpdate` hooks, and it is recommended to write `PureComponent` / `memo` based components.
96 |
97 | ## Further details
98 |
99 | ...can be found in the [API reference for the React bindings](#/api/react).
100 |
--------------------------------------------------------------------------------
/docs_source/0_introduction/60_philosophy.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Philosophy
3 | order: 6
4 | menu: Introduction
5 | route: /introduction/philosophy
6 | ---
7 |
8 | # The Philosophy of RVal
9 |
10 | ## Reactive values, why?
11 |
12 | Why reactive values? In essence most of our programming work consists of transfering in-memory information from one place to another, transforming the information into new information, that is either human or machine digestable.
13 | Data tranformations always introduces reduces redundant copies of data that need to be kept in sync with the original data.
14 | In very trivial example of this problem might look like:
15 |
16 | ```javascript
17 | const user = {
18 | firstName: "Jane",
19 | lastName: "Stanford",
20 | fullName: "Jane Stanford"
21 | }
22 |
23 | document.body.innerHTML = `
Hello ${user.fullName}
24 | ```
25 |
26 | This simple snippet introduces a redundant copy of the original user's name in the `fullName` property, and in the DOM.
27 | Now it has become the programmers responsibility to make sure any futher changes to the `user` are propagated properly:
28 |
29 | ```javascript
30 | function updateFirstName(newName) {
31 | user.firstName = newName
32 | user.fullName = user.firstName + " " + user.lastName
33 | document.body.innerHTML = `
Hello ${user.fullName}
34 | }
35 | ```
36 |
37 | This is the problem that any state management abstraction, regardless the framework or paradigm that is used, is trying to solve.
38 | RVal introduces a handful of primitives that help you to solve this problem in any context, by automating the question:
39 | _when_ should _which_ transformation be applied?
40 |
41 | Here is a quick overview in how RVal helps solving that problem.
42 | First, we should recognize that imperatively computing new information, such as the DOM represantation, introduces stale values.
43 | However, we can avoid ever storing such information by storing _computations_, rather than _values_.
44 | The process for that is as simple as creating a _thunk_ (argumentless function) that capture the computation, rather than imperatively producing new values:
45 |
46 | ```javascript
47 | const user = {
48 | firstName: "Jane",
49 | lastName: "Stanford",
50 | fullName: () => user.firstName + " " + user.lastName
51 | }
52 |
53 | const rendering = () => `
Hello ${user.fullName()}
`
54 |
55 | document.body.innerHTML = rendering()
56 |
57 | function updateFirstName(newName) {
58 | user.firstName = newName
59 | document.body.innerHTML = rendering()
60 | }
61 | ```
62 |
63 | We've made things slightly better now; we don't have to imperatively update `user.fullName` anymore if the name changes.
64 | Similarly, we could captured the rendered representation of the user in the thunk called `rendering`.
65 |
66 | By storing computations instead of values, we have reduced the amount of redundant information.
67 | However, we still have to make sure that our changes are propagated, for example by updating the DOM whenever we change the `firstName` property.
68 |
69 | But, what if we could _subscribe_ to our thunks? And thereby avoid the need to manually propagate state changes, and increasing decoupling in the process?
70 | In other words, what if we could write something like:
71 |
72 | ```javascript
73 | const user = { /* as-is */ }
74 | const rendering = () => `
Hello ${user.fullName()}
`
75 |
76 | on(rendering, () => {
77 | document.body.innerHTML = rendering()
78 | })
79 |
80 | function updateFirstName(newName) {
81 | user.firstName = newName
82 | }
83 | ```
84 |
85 | Well, here is the good news: This is exactly the kind of things RVal allows you to write, by introducing three concepts:
86 |
87 | 1. `val(value)` to create pieces of information that can change over time
88 | 2. `drv(thunk)` to create thunks that can be subscribed to
89 | 3. `sub(something, listener)` to create a listener that fires whenever the provided reactive value or thunk changes
90 |
91 | With those concepts, we can rewrite our above listing as a combination of reactive values and thunks, that propagate the changes when needed!
92 |
93 | ```javascript
94 | import { val, drv, sub } from "@r-val/core"
95 |
96 | const user = {
97 | firstName: val("Jane"),
98 | lastName: val("Stanford"),
99 | fullName: drv(() => user.firstName() + " " + user.lastName())
100 | }
101 |
102 | const rendering = drv(`
Hello ${user.fullName()}
`)
103 |
104 | // subscribe to the 'rendering' thunk
105 | sub(rendering, () => {
106 | document.body.innerHTML = rendering()
107 | })
108 |
109 | function updateFirstName(newName) {
110 | // change the `firstName` reactive value to 'newName'
111 | // rval will make sure that any derivation and subscription impacted by this
112 | // change will be re-evaluated (and nothing more).
113 | user.firstName(newName)
114 | }
115 | ```
116 |
117 |
118 | ## Functions solidify state
119 |
120 | At this point you might be wondering:
121 | "But _why_ is it interesting to trap our state inside these `val` functions?"
122 |
123 | By trapping all our pieces of state inside `val` functions,
124 | we achieved a very interesting property:
125 | We've practically forced ourselfs to have a single source of truth.
126 | Instead of passing the _values of our state_ around, we can now pass a _references to our state_ around.
127 | The benefit of this that it will stop us from accidentally creating redundant copies of our state.
128 |
129 | Take for example the following contrived function.
130 | It creates a random number generator, which is more likely to generate our lucky number than any other number:
131 |
132 | ```javascript
133 | function createNumberGenerator(luckyNumber) {
134 | return function numberGenerator() {
135 | return Math.random() < 0.5 ? luckyNumber : Math.round(Math.random() * 100)
136 | }
137 | }
138 |
139 | let luckyNumber = 13
140 | const generator = createNumberGenerator(luckyNumber)
141 | console.log(generator()) // 13
142 | console.log(generator()) // 50
143 | console.log(generator()) // 49
144 |
145 | luckyNumber = 42
146 | console.log(generator()) // 28
147 | console.log(generator()) // 13
148 | console.log(generator()) // 13
149 | ```
150 |
151 | Now at this point, updating our `luckyNumber` variable doesn't get reflected in the `numberGenerator` anymore.
152 | We are forced now to create a new number generator to reflect the change in our preference.
153 | The problem is that the `luckyNumber` has been "trapped" as argument to `createNumberGenerator`.
154 | The argument is basically a _copy_ of the original `luckyNumber` variable.
155 |
156 | However, it is easy to see that by passing _functions_ around, we avoid this whole problem.
157 | Because `luckyNumber` itself now becomes a `const` reference to the function that traps our lucky number.
158 | (Yes, `let` and `var` really become anti-patterns when using `rval`).
159 |
160 |
161 | ```javascript
162 | function createNumberGenerator(luckyNumber) {
163 | return function numberGenerator() {
164 | // luckyNumber get's evaluated lazily when generating numbers
165 | return Math.random() < 0.5 ? luckyNumber() : Math.round(Math.random() * 100)
166 | }
167 | }
168 |
169 | const luckyNumber = val(13) // luckyNumber is a const now!
170 | const generator = createNumberGenerator(luckyNumber)
171 | console.log(generator()) // 13
172 | console.log(generator()) // 13
173 | console.log(generator()) // 22
174 |
175 | luckyNumber(42) // change our minds
176 | console.log(generator()) // 42
177 | console.log(generator()) // 8
178 | console.log(generator()) // 42
179 | ```
180 |
181 | By capturing values in functions, it becomes much more explicit when we want to pass a _reference_, and when a _value_.
182 | If we want our number generator to take a one-time snapshot of the state as `luckyNumber` we can be explicit about it and _explicitly_ pass a copy of the current state `createNumberGenerator(luckyNumber())`.
183 | On the other hand, we can also explicitly pass a reference to the state by just passing the `luckyNumber` function itself as we did above.
184 |
185 | As it turns out, in many cases it is very intersting to pass around a reference instead of a value.
186 | Especially when we are building systems that are supposed to be reactive, such as a user interface.
187 | But that for later sections.
188 |
189 | ---
190 |
191 | Note that the essence of `val` is simply this:
192 |
193 | ```javascript
194 | function val(initial) {
195 | let state = initial
196 | return function() {
197 | if (!arguments.length)
198 | return state
199 | state = arguments[0]
200 | }
201 | }
202 | ```
203 |
204 | RVal's implementation is a little more involved, but that is because it is possible to subscribe to the `state` of a `val`.
205 | But the above is how you can conceptually think about reactive values.
206 |
207 | But, let's [get started](#/introduction/the-basics) with the core "rval" api first if you didn't check it out yet!
208 |
--------------------------------------------------------------------------------
/docs_source/1_convenience/40_preprocessors.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Using preprocessors
3 | order: 6
4 | menu: Introduction
5 | route: /introduction/preprocessors
6 | ---
7 |
8 |
9 | # Pre-processors
10 |
11 | By default, any new value state stored in a `val` is automatically deeply frozen, even the value is a plain array or object.
12 |
13 | The `preProcessor` argument to apply some preprocessing on the values that are being stored, or perform validations.
14 | The signature of a pre-processor is: `(newValue, currentValue, rvalInstance) -> newValue`. Where:
15 | * `newValue` the value that is about to be stored
16 | * `currentValue` the value that is currently stored
17 | * `rvalInstance` the current RVal instance (see the `rval()` function)
18 | * The return value is the value that will be passed to the next pre-processor, or if there is none, that will be stored.
19 |
20 | It is possible to chain multiple pre processors, by simply passing an array of preprocessors to `val`.
21 |
22 | `val` uses pointer equality to detect and propagate updates. So if your previous detects that the current update can or needs to be aborted, just `return currentValue`.
23 |
24 | For example, the following reactive value `profit` has two pre-processors.
25 | The first one automatically converts new values to strings,
26 | the second one performs some validation, refusing to store numbers that
27 | are smaller then the previous value.
28 |
29 | ```javascript
30 | function convertToNumber(newValue) {
31 | if (typeof newValue === "number")
32 | return newValue
33 | else
34 | return parseFloat(newValue)
35 | }
36 |
37 | const profit = val(0, [
38 | // convert input to number
39 | convertToNumber,
40 | // check if profits increase
41 | (newValue, currentValue) => {
42 | if (newValue < currentValue)
43 | throw new Error("Invariant failed! Profits should increase")
44 | return newValue
45 | }
46 | ])
47 |
48 | profit(-5) // Throws exception: Profits should increase
49 |
50 | profit("7") // Parses the number, and sets profit to number 7
51 | ```
52 |
53 |
54 | ## Type checking
55 |
56 | sarcastic
57 | @r-val/types
58 |
59 | ## Type conversio
60 |
61 | ## Factories
62 |
63 | ## Debugging / logging
64 |
65 | ## Side effects
66 |
--------------------------------------------------------------------------------
/docs_source/1_convenience/50_updaters.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Using updaters
3 | order: 5
4 | menu: Introduction
5 | route: /introduction/updaters
6 | ---
--------------------------------------------------------------------------------
/docs_source/1_convenience/models.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Working with models
3 | order: 1
4 | menu: Advanced
5 | route: /advanced/models
6 | ---
7 |
8 |
--------------------------------------------------------------------------------
/docs_source/2_advanced/examples.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Examples
3 | order: 3
4 | menu: Advanced
5 | route: /advanced/examples
6 | ---
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs_source/2_advanced/mobx.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Relation to MobX
3 | order: 3
4 | menu: Advanced
5 | route: /advanced/mobx
6 | ---
7 |
8 | - much smaller api
9 | - easier to grok: make it clearer what we are reacting to, and what thigns are reactive. While still supporting transparent reactivy
10 | - no messing, patching or wrapping of objects and arrays
11 | - no decorators
12 | - easier build requirements
13 | - generally better interoperability with other libraries, especially functional ones
14 | - modular
15 | - fewer, but clearer customization hooks
16 |
17 |
18 | - lightweight version of mobx-state-tree
19 | - thin react bindings, inspired by mobx-react-lite
20 |
--------------------------------------------------------------------------------
/docs_source/2_advanced/organizing_state.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | name: Designing the state shape
3 | order: 3
4 | menu: Advanced
5 | route: /advanced/state-design
6 | ---
7 |
8 | # Designing the state shape
9 |
10 | ## Trees, everywhere
11 |
12 | ## Choosing immutability granularity level
13 |
14 | ## Composition, normalization and association
15 |
16 | ## Working with references
17 |
--------------------------------------------------------------------------------
/docs_source/2_advanced/performance.mdx:
--------------------------------------------------------------------------------
1 |
2 |
3 | group mutations of collections
--------------------------------------------------------------------------------
/doczrc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | // menu: [
3 | // {
4 | // name: "Introduction"
5 | // },
6 | // {
7 | // name: "Advanced"
8 | // },
9 | // {
10 | // name: "API"
11 | // }
12 | // ],
13 | base: '/rval/',
14 | dest: 'docs',
15 | propsParser: false,
16 | hashRouter: true
17 | }
--------------------------------------------------------------------------------
/examples/boxes/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env", "@babel/preset-react"],
3 | "plugins": ["@babel/plugin-proposal-class-properties"]
4 | }
5 |
--------------------------------------------------------------------------------
/examples/boxes/.env:
--------------------------------------------------------------------------------
1 | SKIP_PREFLIGHT_CHECK=true
--------------------------------------------------------------------------------
/examples/boxes/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 | /.cache
3 |
4 | # dependencies
5 | /node_modules
6 |
7 | # testing
8 | /coverage
9 |
10 | # production
11 | /build
12 |
13 | # misc
14 | .DS_Store
15 | .env.local
16 | .env.development.local
17 | .env.test.local
18 | .env.production.local
19 |
20 | npm-debug.log*
21 | yarn-debug.log*
22 | yarn-error.log*
23 |
--------------------------------------------------------------------------------
/examples/boxes/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | Make sure to run `yarn build && yarn link-examples` in the root folder of this repository to make sure the latest version of the r-val sources are linked into the example.
--------------------------------------------------------------------------------
/examples/boxes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "boxes",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "@babel/core": "^7.2.2",
7 | "parcel-bundler": "^1.11.0"
8 | },
9 | "dependencies": {
10 | "@r-val/core": "^0.0.4",
11 | "@r-val/react": "^0.0.4",
12 | "@r-val/utils": "^0.0.4",
13 | "node-uuid": "^1.4.8",
14 | "react": "16.8.0-alpha.1",
15 | "react-dom": "16.8.0-alpha.1",
16 | "react-draggable": "^3.0.5"
17 | },
18 | "scripts": {
19 | "start": "parcel public/index.html"
20 | },
21 | "browserslist": [
22 | ">0.2%",
23 | "not dead",
24 | "not ie <= 11",
25 | "not op_mini all"
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/examples/boxes/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | RVal boxes demo
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/boxes/src/components/arrow-view.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { rview, useLocalDrv } from '@r-val/react'
3 |
4 | // TODO: when adding a new box, all arrow views will respond due to the lookup!
5 | const ArrowView = ({ arrow, store }) => {
6 | const from = useLocalDrv(() => store.boxes()[arrow.from])
7 | const to = useLocalDrv(() => store.boxes()[arrow.to])
8 | return rview(() => {
9 | const [x1, y1, x2, y2] = [from.x() + from.width() / 2, from.y() + 30, to.x() + to.width() / 2, to.y() + 30]
10 | console.log('rendering arrow ' + arrow.id)
11 | return
12 | }, true)
13 | }
14 |
15 | export default ArrowView
16 |
--------------------------------------------------------------------------------
/examples/boxes/src/components/box-view.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from 'react'
2 | import { DraggableCore } from 'react-draggable'
3 | import { act } from '@r-val/core'
4 | import { rview } from '@r-val/react'
5 |
6 | class BoxView extends PureComponent {
7 | render() {
8 | const { box } = this.props
9 | return rview(() => {
10 | console.log('rendering box ' + box.id)
11 | return (
12 |
13 |