Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/alexkrolick/mdx-observable
Global state for Markdown documents
https://github.com/alexkrolick/mdx-observable
callbag jsx markdown md mdx observable react state
Last synced: 6 days ago
JSON representation
Global state for Markdown documents
- Host: GitHub
- URL: https://github.com/alexkrolick/mdx-observable
- Owner: alexkrolick
- License: mit
- Created: 2018-08-25T23:43:16.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2024-08-29T08:11:58.000Z (2 months ago)
- Last Synced: 2024-10-13T16:42:11.642Z (23 days ago)
- Topics: callbag, jsx, markdown, md, mdx, observable, react, state
- Language: JavaScript
- Homepage: https://mdx-observable.netlify.com/
- Size: 1.35 MB
- Stars: 45
- Watchers: 3
- Forks: 2
- Open Issues: 18
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# MDX-Observable
_**alpha project**, API may change significantly_
_0.2.0 does not actually use observables so the name may change 😬_
Interactive documents powered by Markdown, React, ~~and Observables~~
Share state between JSX blocks in a [MDX](https://mdxjs.com/) document
- **Declarative** React automatically updates observers when data changes
- **Write with Markdown** store documents in plain text that can be revision-controlled- [Examples](#examples)
- [Dev Server](#dev-server)
- [Static Build](#static-build)
- [API](#api)
- [State](#state)
- [Using render prop](#using-render-prop)
- [Using context to connect Observe components](#using-context-to-connect-observe-components)
- [Observe](#observe)
- [Alternatives](#alternatives)
- [Notebooks](#notebooks)
- [Other state management libraries for JS](#other-state-management-libraries-for-js)
- [Roadmap](#roadmap)
- [Potential Issues](#potential-issues)
- [Usage outside MDX](#usage-outside-mdx)
- [Warning about blank lines in JSX](#warning-about-blank-lines-in-jsx)
- [License](#license)## Examples
See demos: https://mdx-observable.netlify.app/
- [Counter w/Observer](./demo/counter.mdx)
- [Counter w/Render Prop](./demo/counter-child-function.mdx)
- [Toggle](./demo/toggle.mdx)
- [Dataviz](./demo/dataviz.mdx)```
git clone [email protected]:alexkrolick/mdx-observable.git
cd mdx-observable
yarn install
```### Dev Server
Start the dev server with live reloading
```sh
yarn run demo:parcel:dev
```### Static Build
The output files in `dist/` can be hosted on a static web server
```
yarn run build:parcel
``````jsx
// notebook.mdx
import { State, Observe } from 'mdx-observable';# Counter
{({ setState }) => (
setState(s => ({ count: s.count + 1 }))}>
Click me
)}The button has been clicked:
{ ({...state}) => ({state.count} times) }
```
Example with a form, table, and graph running in [OK-MDX](https://github.com/jxnblk/ok-mdx):
## API
### State
State container component
Props:
- `initialState: Object` - initial state
- `children: React.Children | function` Can either be:
- React children: JSX or Markdown node(s)
- A render prop: a single function that gets called with `{...state, setState}` as the argument#### Using render prop
_Very similar to [React Powerplug's State](https://github.com/renatorib/react-powerplug/blob/master/docs/components/State.md)_
_Note: whitespace is sensitive in MDX,
so the awkward spacing below is important._```mdx
{({setState, ...state}) =>
Hello, World!
Some markdown
## Some header
- item a
- item b}
```
#### Using context to connect Observe components
```mdx
...child nodes...
{({ ...state}) =>
Hello, World!
}...more child nodes...
```
### Observe
Component that re-renders when the global state changes.
Props:
- `children: ({...state, setState}) => React.Node`
function that accepts an object with:
- `setState`: function like React `setState`, can take an object or an updater function (`state => patch`); result is _shallow merged_ with current state
- the rest of the global state```js
{({ setState, ...state }) => {
return{state.something};
}}{({ setState, something }) => {
return{something;
}}```
## Alternatives
### Notebooks
Advantages of MDX-Observable over [Jupyter](https://jupyter.org/) or [ObservableHQ](https://beta.observablehq.com/scratchpad):
- No cells to run; entire document is live
- Interactivity powered by predictable one-way data flow
- Use standard JS imports and any React component
- Produces static bundles
- Edit using preferred JS tooling
- Bundle with anything that supports [MDX](https://mdxjs.com/getting-started/), like Webpack, Gatsby, Parcel, etc.### Other state management libraries for JS
Most state management libraries don't work with MDX because you can't define variables, meaning APIs like `const myStore = createStore();` are inaccessible. You can work around this by doing this work in another JS file and importing it, but the logic is hard to follow.
Some renderless/headless libraries thatwork fully inline are:
- https://github.com/renatorib/react-powerplug
- https://github.com/ianstormtaylor/react-valuesHowever the whitespace sensitivity may make them difficult to use.
## Roadmap
- [x] See if `` could work as a wrapper instead of sibling of ``. This would allow better scoping and safer setup/teardown.
- [ ] Some way to define functions inline. This might map well to the concept of "selectors" from Redux. Currently you can work around this gap by defining utilities in external JS files, but this makes it hard to write self-contained notebooks.
Possible API:
```js
{/* compute */} }}>
```- [x] Better live-reload support. MDX utils like `ok-mdx` do a full remount when the live editor changes or navigation occures; we could add a `restoreKey` to persist a namespaced cache within the module.
- [ ] **Add tests**
## Potential Issues
### Usage outside MDX
~~Technically `mdx-observable` doesn't depend on MDX for anything, but since it uses a singleton for a cache, it is not a good fit for state management in an app.~~ Fixed
### Warning about blank lines in JSX
Currently (Aug 2018) the MDX parser doesn't allow putting blank lines inside of JSX blocks. If you see an error about "adjacent elements", this is probably why.
## License
See [LICENSE](./LICENSE)