open-index/open-npm huggingface dataset:
npm package: @ryanmorr/amble
Description: A stupid simple CSS lexer and walker
Author: Ryan Morr
Latest version: 0.2.0

# amble

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> A stupid simple CSS lexer and walker

## Install

Download the [CJS](https://github.com/ryanmorr/amble/raw/master/dist/cjs/amble.js), [ESM](https://github.com/ryanmorr/amble/raw/master/dist/esm/amble.js), [UMD](https://github.com/ryanmorr/amble/raw/master/dist/umd/amble.js) versions or install via NPM:

```sh
npm install @ryanmorr/amble
```

## Usage

Given a string of CSS, amble will break it into logical segments such as a selector, an at-rule, or a declaration and sequentially walks them by calling a function. The function is provided the segment of CSS and the ending character used to indicate the type of segment as the only two parameters. The ending character is one of an opening brace (`{`) to indicate the start of a block, a semi-colon (`;`) to indicate a declaration, or a closing brace (`}`) to indicate the end of a block. For example:

```javascript
import { walk } from '@ryanmorr/amble';

const css = `
    .foo {
        color: red;
    }

    @media screen and (max-width: 480px) {
        .foo {
            color: blue;
        }
    }
`;

walk(css, (style, char) => {
    console.log([style, char]);
});
```

Prints the following to the console:

```javascript
[".foo", "{"]
["color:red", ";"]
["", "}"]
["@media screen and (max-width: 480px)", "{"]
[".foo", "{"]
["color:blue", ";"]
["", "}"]
["", "}"]
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/amble
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/amble?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/amble/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/amble/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/amble?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/baseline.css
Description: Just another CSS reset, normalization, and optimization library
Author: Ryan Morr
Latest version: 2.0.0

# baseline.css

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Just another CSS reset, normalization, and optimization library.

## Install

Download [baseline.css](http://github.com/ryanmorr/baseline.css/raw/master/baseline.min.css) directly or install via NPM:

``` sh
npm install @ryanmorr/baseline.css
```

## Features

A mixture of both opinionated and unopinionated normalizations and resets to create a consistent baseline for any project. Some of the features include:

* Many of the normalizations from [normalize.css](https://github.com/necolas/normalize.css) and [sanitize.css](https://github.com/csstools/sanitize.css)
* Resets the box model to `border-box`
* Removes the margin, padding, and border of all elements
* Remove the focus outline for mouse/pointer based interactions
* Improves consistency of default fonts
* Sets a consistent and sensible line height
* Enables percentage-based heights
* Removes transitions and animations when the user prefers reduced motion
* Removes list styles
* Images and other media elements are responsive by default
* Removes the default styling of form elements
* Accessibility helpers

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/baseline.css
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/baseline.css?color=blue&style=flat-square
[build-url]: https://travis-ci.com/github/ryanmorr/baseline.css
[build-image]: https://img.shields.io/travis/com/ryanmorr/baseline.css?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/baseline.css?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/csscope
Description: A simple and lightweight scoped CSS solution
Author: Ryan Morr
Latest version: 0.1.2

# csscope

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> A simple and lightweight scoped CSS solution

## Install

Download the [CJS](https://github.com/ryanmorr/csscope/raw/master/dist/cjs/csscope.js), [ESM](https://github.com/ryanmorr/csscope/raw/master/dist/esm/csscope.js), [UMD](https://github.com/ryanmorr/csscope/raw/master/dist/umd/csscope.js) versions or install via NPM:

``` sh
npm install @ryanmorr/csscope
```

## Usage

Provide a unique ID and CSS as a string and get a transformed CSS string with the unique ID inserted as an attribute selector for each CSS selector sequence. It supports media queries, including prefixing keyframe and animation names, and deep combinators (`>>>`) to add styles targeting child components. For example:

```javascript
import csscope from '@ryanmorr/csscope';

const css = csscope('foo', `
    .foo {
        animation: grow 3s linear 1s infinite running;
    }

    .bar + [attr=value], :empty {
        background-color: red;
    }

    .component >>> .sub-component {
        margin-bottom: 1em;
    }

    @media screen and (max-width: 480px) {
        .foo {
            color: red;
        }
    }

    @keyframes grow {
        from {
            width: 0;
            height: 0
        }

        to {
            width: 100px;
            height: 100px
        }
    }
`);
```

Generates the following CSS as a string:

```css
.foo[foo] {
    animation: foo-grow 3s linear 1s infinite running;
}

.bar[foo] + [foo][attr=value], [foo]:empty {
    background-color: red;
}

.component[foo] .sub-component {
    margin-bottom: 1em;
}

@media screen and (max-width: 480px) {
    div[foo] {
        color: red;
    }
}

@keyframes foo-grow {
    from {
        width: 0;
    }

    to {
        width: 100%;
    }
}
```

Use the transformed CSS string to create a stylesheet client-side or server-side. To apply those styles to a DOM tree (component), add the unique ID as an attribute to every element in a DOM tree that should be influenced by the scoped styles.

**Beware of descandant selectors for recursive components!** For a CSS rule with the selector ".foo .bar", if the ".foo" element contains a recursive child component, than all ".bar" elements in that child component will be matched by the rule.

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/csscope
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/csscope?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/csscope/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/csscope/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/csscope?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/dominate
Description: Declarative DOM building
Author: Ryan Morr
Latest version: 1.1.2

# dominate

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Declarative DOM building

## Install

Download the [CJS](https://github.com/ryanmorr/dominate/raw/master/dist/cjs/dominate.js), [ESM](https://github.com/ryanmorr/dominate/raw/master/dist/esm/dominate.js), [UMD](https://github.com/ryanmorr/dominate/raw/master/dist/umd/dominate.js) versions or install via NPM:

``` sh
npm install @ryanmorr/dominate
```

## Usage

Import the library:

``` javascript
import dominate from '@ryanmorr/dominate';
```

Convert a single element HTML string into a DOM element:

``` javascript
const div = dominate`<div></div>`;
```

Convert multiple elements into a document fragment:

``` javascript
const fragment = dominate`<div></div><span></span>`;
```

Convert plain text to a DOM text node:

``` javascript
const text = dominate`This is plain text.`;
```

Supports self-closing and auto-closing tags:

``` javascript
const div = dominate`<div />`;
const span = dominate`<span><//>`;
```

Set attributes:

``` javascript
const div = dominate`<div id="foo" class=${'bar'} />`;
```

Set the class with an array or object:

``` javascript
const div = dominate`<div class=${['foo', 'bar', 'baz']}></div>`;
const span = dominate`<span class=${{foo: true, bar: false, baz: true}}></span>`;
```

Set CSS styles as a string or an object:

``` javascript
const div = dominate`<div style=${{width: '100px', height: '100px'}}></div>`;
const span = dominate`<span style=${'color: red; position: static;'}></span>`;
```

Add event listeners:

``` javascript
const div = dominate`<div onclick=${(e) => console.log('clicked!')}></div>`;
```

Inject DOM nodes:

``` javascript
const div = dominate`<div>${dominate`<span />`}</div>`;
```

Supports SVG elements:

``` javascript
const rect = dominate`<rect x="10" y="10" width="100" height="100"/>`;
```

Supports functional components:

``` javascript
const Component = (attributes, children) => {
    return dominate`<div ...${attributes}>${children}</div>`
};

const div = dominate`<${Component} id="foo">bar<//>`;
```

Can return multiple element references via the `ref` attribute:

``` javascript
const { foo, bar, baz } = dominate`
    <div ref="foo">
        <span ref="bar"></span>
        <em ref="baz"></em>
    </div>
`;
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/dominate
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/dominate?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/dominate/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/dominate/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/dominate?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/parselector
Description: Parse a CSS selector string
Author: Ryan Morr
Latest version: 1.0.2

# parselector

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Parse a CSS selector string

## Install

Download the [CJS](https://github.com/ryanmorr/parselector/raw/master/dist/cjs/parselector.js), [ESM](https://github.com/ryanmorr/parselector/raw/master/dist/esm/parselector.js), [UMD](https://github.com/ryanmorr/parselector/raw/master/dist/umd/parselector.js) versions or install via NPM:

```sh
npm install @ryanmorr/parselector
```

## Usage

Provide a selector string and get a two-dimensional array composed of each selector group in the first array and the tokens for a selector sequence in the second array.

```javascript
import parselector from '@ryanmorr/parselector';

parselector('#foo[attr$="value" i] > div:not(.bar), .baz span::before');
```

Generates the following AST structure:

```javascript
[
    [
        {
            nodeName: null,
            attributes: [
                {
                    name: 'id',
                    operator: '=',
                    value: 'foo',
                    ignoreCase: false
                },
                {
                    name: 'attr',
                    operator: '$=',
                    value: 'value',
                    ignoreCase: true
                }
            ],
            pseudoClasses: [],
            pseudoElement: null
        },
        '>',
        {
            nodeName: 'div',
            attributes: [],
            pseudoClasses: [
                {
                    name: 'not',
                    value: '.bar'
                }
            ],
            pseudoElement: null
        }
    ],
    [
        {
            nodeName: null,
            attributes: [
                {
                    name: 'class',
                    operator: '~=',
                    value: 'baz',
                    ignoreCase: false
                }
            ],
            pseudoClasses: [],
            pseudoElement: null
        },
        ' ',
        {
            nodeName: 'span',
            attributes: [],
            pseudoClasses: [],
            pseudoElement: 'before'
        }
    ]
]
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/parselector
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/parselector?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/parselector/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/parselector/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/parselector?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/ready
Description: Detect element availability on the initial page load and those dynamically appended to the DOM
Author: Ryan Morr
Latest version: 1.4.1

# ready

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Detect element availability on the initial page load and those dynamically appended to the DOM

## Install

Download the [CJS](https://github.com/ryanmorr/ready/raw/master/dist/cjs/ready.js), [ESM](https://github.com/ryanmorr/ready/raw/master/dist/esm/ready.js), [UMD](https://github.com/ryanmorr/ready/raw/master/dist/umd/ready.js) versions or install via NPM:

``` sh
npm install @ryanmorr/ready
```

## Usage

Provide a selector string for the element(s) you want to target as the first argument and a callback function as the second argument. It returns a function that stops observing for new elements only for that particular selector/callback combination:

``` javascript
const stop = ready('.foo', (element) => {
    stop(); // Stop observing for ".foo" elements
});
```

When any element matching the selector becomes available, the callback is invoked in the context of the element as well as passing it as the only parameter. If multiple elements are found, the callback is invoked in succession for each element in document order.

Alternatively, provide just the callback function as the only argument to add a generic DOM ready event listener:

``` javascript
ready((doc) => {
    // The DOM is ready
});
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/ready
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/ready?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/ready/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/ready/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/ready?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/remotion
Description: Animate elements before removing them from the DOM
Author: Ryan Morr
Latest version: 1.0.1

# remotion

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Animate elements before removing them from the DOM

## Install

Download the [CJS](https://github.com/ryanmorr/remotion/raw/master/dist/cjs/remotion.js), [ESM](https://github.com/ryanmorr/remotion/raw/master/dist/esm/remotion.js), [UMD](https://github.com/ryanmorr/remotion/raw/master/dist/umd/remotion.js) versions or install via NPM:

```sh
npm install @ryanmorr/remotion
```

## Usage

Import the library:

```javascript
import remotion from '@ryanmorr/remotion';
```

Provide an element, nodelist, or selector string as the first argument and a CSS class name as the second argument that triggers a CSS transition or keyframe animation. It returns a promise that is resolved when the transition/animation is complete and the element has been removed from the DOM:

```javascript
remotion(element, 'fade-out').then(() => console.log('element removed'));
```

Supports a function as the second argument that is provided the element reference and returns the class name:

```javascript
remotion('.item', (element) => 'fade-out');
```

If the function returns a promise, it can now be used to fully customize the removal process. You can perform a custom animation, execute side effects, and/or explicitly remove the element from the DOM yourself, then simply resolve the promise when your done:

```javascript
remotion(nodelist, (element) => {
    return new Promise((resolve) => {
        fadeOut(element).then(() => {
            executeSideEffect(element);
            element.remove();
            resolve();
        });
    });
});
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/remotion
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/remotion?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/remotion/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/remotion/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/remotion?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/router
Description: A minimalist universal router for web applications
Author: Ryan Morr
Latest version: 3.0.4

# router

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> A minimalist universal router for web applications

## Install

Download the [CJS](https://github.com/ryanmorr/router/raw/master/dist/cjs/router.js), [ESM](https://github.com/ryanmorr/router/raw/master/dist/esm/router.js), [UMD](https://github.com/ryanmorr/router/raw/master/dist/umd/router.js) versions or install via NPM:

``` sh
npm install @ryanmorr/router
```

## Usage

Create a router that matches different routes and extracts the parameters to pass to the callback function:

```javascript
import Router from '@ryanmorr/router';

const router = Router({
    '/': () => {
        // Handle home page 
    },
    '/foo': () => {
        // Handle "/foo"
    },
    '/foo/:bar': ({bar}) => {
        // Parameters are indicated by a prefixed colon
    },
    '/foo/:bar/:baz?': ({bar, baz}) => {
        // Optional parameters are indicated by a suffixed question mark
    },
    '/foo/qux/*': ({wildcard}) => {
        // An asterisk indicates a wildcard that will match anything
    }
});

// Finds the first matching route and invokes the callback function
router.dispatch('/foo');
```

Use in a browser:

```javascript
window.addEventListener('popstate', () => {
    router.dispatch(window.location.pathname);
});
```

Use in Node.js:

```javascript
const http = require('http');
const url = require('url');
 
const server = http.createServer((req, res) => {
    const path = url.parse(req.url).pathname;
    router.dispatch(path);
});

server.listen(8888);
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/router
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/router?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/router/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/router/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/router?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/schedule-render
Description: Deferred DOM rendering optimized for 60fps
Author: Ryan Morr
Latest version: 3.0.3

# schedule-render

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Deferred DOM rendering optimized for 60fps

## Install

Download the [CJS](https://github.com/ryanmorr/schedule-render/raw/master/dist/cjs/schedule-render.js), [ESM](https://github.com/ryanmorr/schedule-render/raw/master/dist/esm/schedule-render.js), [UMD](https://github.com/ryanmorr/schedule-render/raw/master/dist/umd/schedule-render.js) versions or install via NPM:

``` sh
npm install @ryanmorr/schedule-render
```

## Usage

Schedule a callback function that manipulates the DOM. The callback is entered into a queue and run within a frame to maintain 60fps and prevent dropping the frame which could result in jank. When the frame rate budget has been exceeded and more callbacks still exist within the queue, a new frame will be automatically scheduled until every function in the queue has been executed. It returns a promise that is fulfilled when rendering is complete:

``` javascript
import scheduleRender from '@ryanmorr/schedule-render';

scheduleRender(() => {
    // Manipulate the DOM within the callback function
    // The return value is provided to all thenables
}).then((value) => {
    // Rendering complete
});
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/schedule-render
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/schedule-render?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/schedule-render/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/schedule-render/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/schedule-render?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/scoped
Description: Scoped CSS for DOM trees
Author: Ryan Morr
Latest version: 0.1.3

# scoped

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Scoped CSS for DOM trees

## Install

Download the [CJS](https://github.com/ryanmorr/scoped/raw/master/dist/cjs/scoped.js), [ESM](https://github.com/ryanmorr/scoped/raw/master/dist/esm/scoped.js), [UMD](https://github.com/ryanmorr/scoped/raw/master/dist/umd/scoped.js) versions or install via NPM:

```sh
npm install @ryanmorr/scoped
```

## Usage

Import the library:

```javascript
import scoped from '@ryanmorr/scoped';
```

Create a scoped stylesheet by providing the CSS as a string. The selectors of the CSS will be automatically converted to include a unique attribute. The styles can only take affect when an element also possesses that unique attribute. It returns a function that will apply the unique attribute to all elements of a DOM tree:

```javascript
const applyStyles = scoped(`
    .foo {
        width: 100px;
        height: 100px;
    }

    .bar {
        width: 200px;
        height: 200px;
    }
`);

applyStyles(element);
```

You can provide the unique attribute yourself via an optional second argument:

```javascript
const applyStyles = scoped(`
    div {
        color: red;
    }
`, 'scoped');

applyStyles(element);
element.hasAttribute('scoped'); //=> true
```

It supports all CSS selectors, properties, and at-rules, including keyframes and media queries:

```javascript
const applyStyles = scoped(`
    .foo {
        background-color: red;
        animation-name: slide-in 1s ease-in;
    }

    @keyframes slide-in {
        from {
            transform: translateX(0%);
        }
        to {
            transform: translateX(100%);
        }
    }

    @media screen and (max-width: 600px) {
        .foo {
            background-color: blue;
        }
    }
`);
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/scoped
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/scoped?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/scoped/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/scoped/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/scoped?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/typed
Description: Statically typed properties for object literals
Author: Ryan Morr
Latest version: 2.0.2

# typed

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> Statically typed properties for object literals

## Install

Download the [CJS](https://github.com/ryanmorr/typed/raw/master/dist/cjs/typed.js), [ESM](https://github.com/ryanmorr/typed/raw/master/dist/esm/typed.js), [UMD](https://github.com/ryanmorr/typed/raw/master/dist/umd/typed.js) versions or install via NPM:

```sh
npm install @ryanmorr/typed
```

## Usage

Restrict properties to a native data type:

```javascript
import typed from '@ryanmorr/typed';

const object = typed({
    foo: String,
    bar: Number 
});

object.foo = 'foo';
object.bar = 123;
```

Constrain a property to a user-defined constructor:

```javascript
function Foo() {}

const object = typed({
    foo: Foo
});

object.foo = new Foo();
```

If a value of the wrong type is assigned to a property, a `TypeError` will be thrown:

```javascript
const object = typed({
    foo: String
});

object.foo = 123 // throws: Invalid value assignment on "foo", expected: String, actual: Number
```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/typed
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/typed?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/typed/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/typed/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/typed?color=blue&style=flat-square
[license-url]: UNLICENSE
npm package: @ryanmorr/voodoo
Description: An experimental reactive execution context inspired by Svelte
Author: Ryan Morr
Latest version: 0.1.1

# voodoo

[![Version Badge][version-image]][project-url]
[![License][license-image]][license-url]
[![Build Status][build-image]][build-url]

> An experimental reactive execution context inspired by Svelte

## Description

If you're familiar with Svelte 3, you're probably an admirer of its reactivity. Just change a variable and the DOM is automatically updated. It's so elegantly simple, don't you wish you could do it in vanilla JavaScript? Well, as it turns out, you can. By supplying a proxied object to a `with` statement, you can alter the properties as if they were variables and use the proxy's traps to be notified of changes. This project is a proof of concept (not recommended for production) to demonstrate this functionality with a layer of abstraction to avoid some obstacles and for ease of use.

## Install

Download the [CJS](https://github.com/ryanmorr/voodoo/raw/master/dist/cjs/voodoo.js), [ESM](https://github.com/ryanmorr/voodoo/raw/master/dist/esm/voodoo.js), [UMD](https://github.com/ryanmorr/voodoo/raw/master/dist/umd/voodoo.js) versions or install via NPM:

```sh
npm install @ryanmorr/voodoo
```

## Usage

Provide code (as a function or a string) in which you manipulate state variables. A function is returned that is used to execute the code in an isolated context, passing the initial state and observable functions that are called when a state variable is accessed, reassigned, or even deleted (it will actually just set the property value to undefined). The executor function returns the proxied state object that will remain in sync with the state variables:

```javascript
import voodoo from '@ryanmorr/voodoo';

const exec = voodoo((foo, bar, baz) => {
    foo = foo + 10;
    setTimeout(() => (bar = 20), 1000);
    delete baz;
    const qux = baz;
});

const state = exec({foo: 1, bar: 2, baz: 3}, {
    get(name, value) {
        console.log(`get "${name}" with value of ${value}`);
    },
    set(name, nextValue, prevValue) {
        console.log(`set "${name}" value to ${nextValue} from ${prevValue}`);
    },
    delete(name, prevValue) {
        console.log(`delete "${name}" with value of ${prevValue}`);
    }
});

state.bar = 5;
```

Writes the following to the console:

```
get "foo" with value of 1
set "foo" value to 11 from 1
delete "baz" with value of 3
get "baz" with value of undefined
set "bar" value to 5 from 2
set "bar" value to 20 from 5
 ```

## License

This project is dedicated to the public domain as described by the [Unlicense](http://unlicense.org/).

[project-url]: https://github.com/ryanmorr/voodoo
[version-image]: https://img.shields.io/github/package-json/v/ryanmorr/voodoo?color=blue&style=flat-square
[build-url]: https://github.com/ryanmorr/voodoo/actions
[build-image]: https://img.shields.io/github/actions/workflow/status/ryanmorr/voodoo/node.js.yml?style=flat-square
[license-image]: https://img.shields.io/github/license/ryanmorr/voodoo?color=blue&style=flat-square
[license-url]: UNLICENSE