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 🙏

© 2026 – Pkg Stats / Ryan Hefner

ov-configurator

v1.1.1

Published

Universal frontend product configurator module

Downloads

130

Readme

ov-configurator

Universal frontend product configurator module. Exports Calculator and initConfigurator.

The package ships two complementary tools:

  • Calculator — a low-level class that renders a form, tracks selected values and computes derived fields (price, labels, etc.). Configure everything in JS.
  • initConfigurator — a higher-level helper that reads an inline JS config from the DOM ([data-configurator-options]) and builds a fully wired Calculator for a product element. Designed for server-rendered pages where the config lives in HTML.

Installation

npm install ov-configurator

CDN

No build step required — include directly via jsDelivr or unpkg:

<script src="https://cdn.jsdelivr.net/npm/ov-configurator/dist/ov-configurator.iife.js"></script>
<script>
    const { Calculator, initConfigurator } = OvConfiurator
</script>

The IIFE bundle exposes a global OvConfiurator with Calculator and initConfigurator.


Calculator

Renders a <form> with radio/checkbox sections and recomputes fields on every change.

Basic usage

import { Calculator } from 'ov-configurator'

interface ProductData {
    sizes: Array<{ label: string; value: string; price: number }>
}

const calc = new Calculator<ProductData>({
    id: 'my-product',
    parentSelector: '#product-card',
    data: { sizes: [{ label: 'S', value: 's', price: 100 }] },
    sectionsOptions: [
        {
            title: 'Size',
            type: 'size',
            inputs: [{ label: 'S', value: 's' }],
        },
    ],
})

calc.addField({
    selector: 'price',
    calculateFunction(values, data) {
        return data.sizes.find(s => s.value === values.size)?.price ?? 0
    },
})

calc.renderInNode(document.getElementById('form-place')!)
calc.init()

The form is rendered into the given node. On each change event all fields are recomputed and written to matching [data-calc="<selector>"] elements inside parentSelector.

CalculatorOptions

| option | type | default | description | |---|---|---|---| | id | string | — | unique identifier for the instance | | parentSelector | string | — | CSS selector of the container element | | data | TData \| null | null | arbitrary data object passed to calculateFunction | | editableFields | FieldOptions[] | [] | fields to register on construction | | sectionsOptions | SectionOptions[] | [] | sections to render in the form | | prefix | string | 'card' | input name prefix ({prefix}-{id}-{type}) | | stylePrefix | string | 'calculator' | BEM block name for generated HTML | | dataAttributePrefix | string | 'calc' | prefix for data-{prefix}="<selector>" attributes |

FieldOptions

| option | type | default | description | |---|---|---|---| | selector | string | — | matches data-{dataAttributePrefix}="<selector>" in the DOM | | calculateFunction | (values, data) => unknown | () => null | returns the new value; null is ignored | | attribute | boolean | false | write value as an attribute instead of innerHTML (reads data-calc-attribute from the node) | | animated | boolean | false | animate block on value change (requires Animate.css) | | animatedNode | 'parent' \| 'self' \| 'closest' | 'parent' | which node to animate | | animatedNodeSelector | string | — | selector for closest() when animatedNode='closest' | | animation | string[] | ['animate__faster', 'animate__pulse'] | Animate.css classes | | duration | number | 800 | number animation duration (ms) | | dots | number | 0 | decimal places for number animation |

SectionOptions

| option | type | default | description | |---|---|---|---| | type | string | — | key used in values object and input name | | title | string | — | section heading | | inputs | SectionInput[] \| (data) => SectionInput[] | — | static list or factory function | | className | string | '' | extra class on each .{stylePrefix}__section-col | | checked | boolean | true | pre-select first matching value | | inputType | string | 'radio' | input type ('radio' or 'checkbox') |

Instance methods

| method | description | |---|---| | addField(options) | register a new field | | addSection(options) | add a section to the form | | init() | attach DOM nodes to fields and wire the change listener | | renderInNode(node) | write generated HTML into node and store a reference | | refresh() | re-render HTML and re-init (use when inputs change dynamically) | | getValues() | return current { [type]: value } map | | getValue(key) | return the last saved value for a field selector | | saveValue(key, value) | manually persist a value accessible via getValue |


initConfigurator

Higher-level helper for server-rendered pages. Reads the config from an inline <script type="text/plain" data-configurator-options> element, receives product data externally, and builds a Calculator with standard fields (price, old-price, params, per-section value/view fields, and mirrored attribute fields).

HTML structure

<div data-calc-id="product-a">
    <!-- output fields -->
    <span data-calc="price"></span>
    <span data-calc="old-price"></span>
    <span data-calc="params"></span>

    <!-- Calculator renders the form here -->
    <div data-calc-place="product-a"></div>

    <!-- inline config (JS object syntax, functions allowed) -->
    <script type="text/plain" data-configurator-options>
    {
        oldPricePercent: 20,
        getPrice: function(values, item) {
            return item.basePrice + (item.sizePrices[values.size] || 0)
        },
        sections: [
            {
                key: 'size',
                title: 'Size',
                path: '$.sizes[*]',
                postfix: ' m'
            }
        ]
    }
    </script>
</div>

JS initialization

import { initConfigurator } from 'ov-configurator'
import type { DataSource } from 'ov-configurator'

const data: DataSource = {
    'product-a': {
        basePrice: 45_000,
        sizes: ['3x4', '3x6'],
        sizePrices: { '3x4': 0, '3x6': 15_000 },
    },
}

document.querySelectorAll<HTMLElement>('[data-calc-id]').forEach((el) => {
    initConfigurator(data, el)
})

initConfigurator is also exported as Configurator (alias).

ConfiguratorOptions (inline config object)

| key | type | description | |---|---|---| | getPrice | (values, item, id) => number | returns the current price | | oldPricePercent | number | discount % — old price = price / ((100 - n) / 100) | | sections | ConfiguratorSection[] | sections to build | | fields | ConfiguratorField[] | optional extra fields |

ConfiguratorSection

| key | type | description | |---|---|---| | key | string | field selector and value key in values | | title | string | section heading | | path | string | JSONPath / pipe expression to extract inputs from item data | | postfix | string | suffix appended to values in labels and params | | inputs | SectionInput[] | static inputs list (overrides path) | | labelMapping | Record<string, string> | map raw values to display labels | | selectorDisplay | (selected, sectionData) => string | custom display for the *-view field |

Built-in fields registered by initConfigurator

For each section with key k the following data-calc targets are populated:

| selector | content | |---|---| | price | result of getPrice | | old-price | price before discount | | params | space-joined value + postfix for every section | | params-view | newline-joined title: value + postfix | | k | selected raw value | | k-view | display label (via labelMapping / selectorDisplay) | | price (attr) | same value written as an HTML attribute | | old-price (attr) | same | | k (attr) | same |

queryByPath

Utility used internally by initConfigurator to traverse item data. Available as a named export for advanced custom fields.

import { queryByPath } from 'ov-configurator'

// JSONPath
queryByPath(data, '$.sizes[*]')

// chained operations
queryByPath(data, '$.variants > $first')

// fallback chain
queryByPath(data, '$.primary || $.fallback')

// save/get across operations
queryByPath(data, '$save:key > $.next')

Supported special operations: $root, $first, $last, $save:<key>, $get:<key>, any JSONPath expression.