npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

mdx-observable

v0.2.0

Published

Global state for MDX documents

Downloads

888

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 document

  • Declarative React automatically updates observers when data changes
  • Write with Markdown store documents in plain text that can be revision-controlled

Examples

git clone [email protected]:alexkrolick/mdx-observable.git
cd mdx-observable
yarn install
yarn run demo
// notebook.mdx
import { Init, Observe } from 'mdx-observable';

# Counter

<State initialState={{ count: 0 }}>

<Observe>
  {({ setState }) => (
    <button onClick={() => setState(s => ({ count: s.count + 1 }))}>
      Click me
    </button>
  )}
</Observe>

The button has been clicked:

<Observe>
  { ({...state}) => (<span>{state.count} times</span>) }
</Observe>

</State>

Example with a form, table, and graph running in 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

Note: whitespace is sensitive in MDX, so the awkward spacing below is important. This PR may make this easier: https://github.com/mdx-js/mdx/pull/226

<State initialState={{}}>
{({setState, ...state}) => <React.Fragment>

<h1>Hello, World!</h1>

Some markdown

## Some header

- item a
- item b

</React.Fragment>}
</State>

Using context to connect Observe components

<State initialState={{}}>

...child nodes...

<Observe>
  {({ ...state}) => <h1>Hello, World!</h1>}
</Observe>

...more child nodes...

</State>

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
<Observe>
  {({ setState, ...state }) => {
    return <div>{state.something}</div>;
  }}
</Observe>

<Observe>
  {({ setState, something }) => {
    return <div>{something</div>;
  }}
</Observe>

Alternatives

Notebooks

Advantages of MDX-Observable over Jupyter or ObservableHQ:

  • 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, 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-values

However the whitespace sensitivity may make them difficult to use.

Roadmap

  • [x] See if <Init /> could work as a wrapper instead of sibling of <Observer />. 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:

<Init state={} selectors={{ selectCheapest: state => {/* 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.~~

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