Socket
Socket
Sign inDemoInstall

svelte-formula

Package Overview
Dependencies
21
Maintainers
1
Versions
30
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.8.7 to 0.9.0

21

CHANGELOG.md

@@ -8,2 +8,23 @@ # Changelog

## [0.9.0] - 2021-03-08
### Removed
- Group `reset` method - instead to reset a group of form instances call `group.init` with the initial data that was
used to create the group.
### Changed
- Beaker now accepts `defaultValues` as an array (`group.init` will always overide this)
- Internal refactoring to improve group handling
- Removed global state stores for initial values, now only generated internally for reset methods
- Touched and Dirty and Invalid fields now have attributes set
### Fixed
- `formValidity` in Beaker stores is now an array
- Group stores no longer emit twice on changes
- Groups correctly now use `MutationRecord` added and removed nodes to be the reference to form instances when adding
and removing data
## [0.8.7] - 2021-02-23

@@ -10,0 +31,0 @@

4

index.d.ts

@@ -1,2 +0,2 @@

import { Beaker, BeakerStores, Formula, FormulaError, FormulaOptions, FormulaStores } from './types';
import { Beaker, BeakerOptions, BeakerStores, Formula, FormulaError, FormulaOptions, FormulaStores } from './types';
export { Beaker, BeakerStores, Formula, FormulaError, FormulaOptions, FormulaStores };

@@ -29,2 +29,2 @@ /**

*/
export declare function beaker<T extends Record<string, unknown | unknown[]>>(options?: FormulaOptions): Beaker<T>;
export declare function beaker<T extends Record<string, unknown | unknown[]>>(options?: BeakerOptions): Beaker<T>;

@@ -17,5 +17,4 @@ import { FormEl, FormulaField, FormulaOptions, FormulaStores } from '../../types';

* @param options
* @param isGroup
*/
export declare function createHandler<T extends Record<string, unknown | unknown[]>>(name: string, eventName: string, element: FormEl, groupElements: FormEl[], stores: FormulaStores<T>, options: FormulaOptions, isGroup?: boolean): () => void;
export declare function createHandler<T extends Record<string, unknown | unknown[]>>(name: string, eventName: string, element: FormEl, groupElements: FormEl[], stores: FormulaStores<T>, options: FormulaOptions): () => void;
/**

@@ -22,0 +21,0 @@ * Create a handler for a form element submission, when called it copies the contents

@@ -6,3 +6,4 @@ import { Formula, FormulaOptions, FormulaStores } from '../../types';

* @param globalStore
* @param groupName
*/
export declare function createForm<T extends Record<string, unknown | unknown[]>>(options: FormulaOptions, globalStore?: Map<string, FormulaStores<T>>): Formula<T>;
export declare function createForm<T extends Record<string, unknown | unknown[]>>(options: FormulaOptions, globalStore?: Map<string, FormulaStores<T>>, groupName?: string): Formula<T>;
import { FormEl, FormulaOptions, FormulaStores } from '../../types';
/**
* Initialise the stores with data from the form, it will also use any default values provided
* @param node
* @param allGroups
* @param stores
* @param options
*/
export declare function getInitialFormValues<T extends Record<string, unknown | unknown[]>>(node: HTMLElement, allGroups: [string, FormEl[]][], stores: FormulaStores<T>, options: FormulaOptions): void;
/**
* Create the form reset method

@@ -15,2 +7,1 @@

export declare function createReset<T extends Record<string, unknown | unknown[]>>(node: HTMLElement, allGroups: [string, FormEl[]][], stores: FormulaStores<T>, options: FormulaOptions): () => void;
export declare function cleanupDefaultValues(node: HTMLElement): void;

@@ -1,2 +0,2 @@

import { Beaker, BeakerStores, FormulaOptions } from '../../types';
import { Beaker, BeakerOptions, BeakerStores } from '../../types';
/**

@@ -7,2 +7,2 @@ * Creates a group, which is really just a collection of forms for row data

*/
export declare function createGroup<T extends Record<string, unknown | unknown[]>>(options: FormulaOptions, beakerStores: Map<string, BeakerStores<T>>): Beaker<T>;
export declare function createGroup<T extends Record<string, unknown | unknown[]>>(options: BeakerOptions, beakerStores: Map<string, BeakerStores<T>>): Beaker<T>;

@@ -9,3 +9,3 @@ import { FormEl } from '../../types';

*/
export declare function getAllFieldsWithValidity(rootEl: HTMLElement): FormEl[];
export declare function getFormFields(rootEl: HTMLElement): FormEl[];
/**

@@ -12,0 +12,0 @@ * Extract all fields from a group that are valid inputs with `name` property

@@ -1,2 +0,2 @@

import { BeakerStores, FormulaOptions, FormulaStores } from '../../types';
import { BeakerOptions, BeakerStores, FormulaOptions, FormulaStores } from '../../types';
/**

@@ -14,2 +14,2 @@ * Create the stores for the the form instance, these can be set using the `defaultValue` property

*/
export declare function createGroupStores<T extends Record<string, unknown | unknown[]>>(options?: FormulaOptions): BeakerStores<T>;
export declare function createGroupStores<T extends Record<string, unknown | unknown[]>>(options?: BeakerOptions): BeakerStores<T>;
{
"name": "svelte-formula",
"description": "Reactive Forms for Svelte",
"version": "0.8.7",
"version": "0.9.0",
"keywords": [

@@ -6,0 +6,0 @@ "svelte",

@@ -1,5 +0,11 @@

# Svelte Formula
<div style='text-align: center'>
![The Svelte Formula Logo](https://raw.githubusercontent.com/tanepiper/svelte-plugins/main/packages/docs-site/static/img/logo_256.png)
# Formula + Beaker Δ→
**Reactive Forms for Svelte**
![The Svelte Formula Logo](https://formula.svelte.codes/img/logo_256.png)
</div>
[![svelte-formula](https://img.shields.io/npm/v/svelte-formula?label=svelte-formula)](https://www.npmjs.com/package/svelte-formula)

@@ -10,12 +16,5 @@

Formula is a library for [Svelte](https://svelte.dev) with features for creating **Zero Configuration** reactive forms
and fully data-driven applications.
`svelte-formula` is a Library for use with [Svelte](https://svelte.dev) that super-charges your ability to create rich
data-driven for applications.
Out-of-the box it's designed to work with HTML5 forms. Configuring your forms validation is as easy as setting
attributes, and doesn't get in the way of things like Accessibility. You can also add additional validations, custom
messages and computed values through optional configuration to enhance your forms and their UI.
Formula also supports multi-row forms with [Beaker](https://formula.svelte.codes/docs/groups/beaker) - an API for working
with rich forms for collections of data.
## Install Instructions

@@ -30,46 +29,61 @@

[Live Demo](https://svelte.dev/repl/3c3fe78a258a45779bd122d399560f19)
```svelte
<script>
import { createEventDispatcher } from 'svelte';
import { get } from 'svelte/store'
import { formula } from 'svelte-formula@0.8.2'
const { form, isFormValid, validity, touched, submitValues } = formula();
Visit the [documentation](https://formula.svelte.codes) for more details API instructions.
const dispatcher = createEventDispatcher()
## Formula
// Allow components to accept value that can be used as default values
export let userName = '';
[Demo](https://svelte.dev/repl/dda29ae516284147871b58a4f1966315)
// You can calculate values for valid UI states
$: usernameInvalid = $touched?.userName && $validity?.userName?.invalid
<div style='text-align: center; float: left; margin-right: 20px'>
// Handle submission of data easily to parent components or services
function submitForm() {
dispatch('updateUser', {
user: get(submitValues)
})
}
</script>
![The Svelte Formula Logo](https://formula.svelte.codes/img/formula-small.png)
<!-- Use as form element to get full form submission validation-->
<form use:form on:submit|preventDefault={submitForm}>
<div class="form-field">
<label for="userName">User Name</label>
<input type="text" id="userName" name="userName" required minlength="8" class:error={usernameInvalid} bind:value={userName} />
<span hidden={!usernameInvalid}>{$validity?.userName?.message}</span>
</div>
<button disabled={!$isFormValid} type="submit">Update User Name</button>
</form>
</div>
<style>
.error {
border: 1px solid hotpink;
}
</style>
```
**Formula** is a library for creating _Zero Configuration_ reactive form components, and fully data-driven applications.
**Zero-Configuration** means you need nothing more than a well-defined HTML5 form element to have fully reactive stores
of data and form states.
Visit the [documentation](https://formula.svelte.codes) for more details API instructions.
Accessing the input requires only setting the `name` property, and for validation providing attributes like `require`
or `minlength`. Formula supports single and multi-value inputs across all widely supported HTML inputs and extends them
with checkbox groups and radio groups, and composite fields of values like text or number.
Formula creates a form instance that contains Svelte [stores](https://formula.svelte.codes/docs/stores/stores) that
contain value and validation information, and some
additional [lifecycle methods](https://formula.svelte.codes/docs/lifecycle) that allow your to dynamically add and
remove customisations, and reset or destroy the form. It also attempts to apply ARIA attributes to help with
accessibility.
### Extending Formula
Formula also supports a bunch of [powerful options](https://formula.svelte.codes/docs/options) that provide additional
validation, enrichment and custom messages.
For example with the `enrich` [option](https://formula.svelte.codes/docs/options#enrich)
and `enrichment` [store](https://formula.svelte.codes/docs/stores/stores-enrichment) you can provide functions that
calculate additional computed values based on user input - for example calculating a password strength, or the length of
text a user has entered. These are useful.
Validations can be provided at the form and field level, and integrate with in-built browser validations to provide
native messages, which can be customised for localisation.
### Beaker
[Demo](https://svelte.dev/repl/c146c7976360405cba9a696e3fee853b)
<div style='text-align: center; float: left; margin-right: 20px'>
![The Svelte Formula Logo](https://formula.svelte.codes/img/beaker-small.png)
</div>
**Beaker** take Formula and adds another layer for working with collections of data.
Using row-based input you can create full form instances per row that are also fully reactive and feed into Beaker's
collection store.
Beaker also provides methods for setting, adding and removing items from the in-built stores, when can be used with
Svelte's `{#each}{/each}` blocks to create a re-usable template in the component
With this you can build applications such as multi-row editable tables or lists. See
the [documentation](https://formula.svelte.codes/docs/groups/beaker) for more details and examples.

@@ -83,3 +83,3 @@ import { get, writable } from 'svelte/store';

*/
function getAllFieldsWithValidity(rootEl) {
function getFormFields(rootEl) {
var nodeList = rootEl.querySelectorAll('*[name]:not([data-in-group])');

@@ -220,3 +220,4 @@ return Array.from(nodeList).filter(function (el) {

el.setCustomValidity(''); // If there's no options, just return the current error
el.setCustomValidity('');
el.removeAttribute('data-formula-invalid'); // If there's no options, just return the current error

@@ -257,2 +258,7 @@ if (!options) {

var valid = el.checkValidity();
if (!valid) {
el.setAttribute('data-formula-invalid', 'true');
}
return {

@@ -648,7 +654,6 @@ valid: valid,

* @param options
* @param isGroup
*/
function createHandler(name, eventName, element, groupElements, stores, options, isGroup) {
function createHandler(name, eventName, element, groupElements, stores, options) {
var _a;

@@ -683,5 +688,2 @@

var initialValues = new Map();
var initialValidity = new Map();
var initialEnrichment = new Map();
/**

@@ -744,5 +746,3 @@ * Initialise the stores with data from the form, it will also use any default values provided

stores.enrichment.set(__assign({}, enrichmentValues));
initialValues.set(node, __assign({}, formValues));
initialValidity.set(node, __assign({}, validityValues));
initialEnrichment.set(node, __assign({}, enrichmentValues));
return [formValues, validityValues, enrichmentValues];
}

@@ -754,12 +754,16 @@ /**

function createReset(node, allGroups, stores, options) {
var _a = __read(getInitialFormValues(node, allGroups, stores, options), 3),
formValues = _a[0],
validityValues = _a[1],
enrichmentValues = _a[2];
/**
* Resets the form to the initial values
*/
return function () {
var e_2, _a;
var formValues = initialValues.get(node);
var validityValues = initialValidity.get(node);
var enrichment = initialEnrichment.get(node);
stores.formValues.set(formValues);

@@ -770,5 +774,5 @@ stores.validity.set(validityValues);

}));
stores.enrichment.set(enrichment); // Also override touched and dirty
stores.enrichment.set(enrichmentValues); // Also override touched and dirty
stores.touched.set(Object.keys(initialValues).reduce(function (val, key) {
stores.touched.set(Object.keys(formValues).reduce(function (val, key) {
var _a;

@@ -778,3 +782,3 @@

}, {}));
stores.dirty.set(Object.keys(initialValues).reduce(function (val, key) {
stores.dirty.set(Object.keys(formValues).reduce(function (val, key) {
var _a;

@@ -808,16 +812,3 @@

}
function cleanupDefaultValues(node) {
if (initialValues.has(node)) {
initialValues["delete"](node);
}
if (initialValidity.has(node)) {
initialValidity["delete"](node);
}
if (initialEnrichment.has(node)) {
initialEnrichment["delete"](node);
}
}
/**

@@ -857,2 +848,3 @@ * Creates the handler for a group of elements for the touch event on the group name, once an

el.setAttribute('data-formula-touched', 'true');
el.removeEventListener('focus', handler);

@@ -966,2 +958,3 @@ }

el.setAttribute('data-formula-dirty', 'true');
el.removeEventListener('blur', handler);

@@ -1142,13 +1135,40 @@ }

function createGroupStores(options) {
var _a;
var initialValues = [];
var initialFieldState = [];
var initialValidity = [];
var initialEnrichment = [];
var initialFormValidity = [];
if (((_a = options === null || options === void 0 ? void 0 : options.defaultValues) === null || _a === void 0 ? void 0 : _a.length) > 0) {
var defaultValues = options.defaultValues,
rest_1 = __rest(options, ["defaultValues"]);
var eachState = defaultValues.map(function (d) {
return createFirstState(__assign(__assign({}, rest_1), {
defaultValues: d
}));
});
for (var i = 0; i < eachState.length; i++) {
initialValues = __spread(initialValues, [eachState[i].initialValues]);
initialFieldState = __spread(initialFieldState, [eachState[i].initialFieldState]);
initialValidity = __spread(initialValidity, [eachState[i].initialValidity]);
initialEnrichment = __spread(initialEnrichment, [eachState[i].initialEnrichment]);
initialFormValidity = __spread(initialFormValidity, [eachState[i].initialFormValidity]);
}
}
return {
formValues: writable([]),
formValues: writable(initialValues),
submitValues: writable([]),
initialValues: writable([]),
touched: writable([]),
dirty: writable([]),
validity: writable([]),
formValidity: writable({}),
initialValues: writable(initialValues),
touched: writable(initialFieldState),
dirty: writable(initialFieldState),
validity: writable(initialValidity),
formValidity: writable(initialFormValidity),
isFormValid: writable(false),
isFormReady: writable(false),
enrichment: writable([])
enrichment: writable(initialEnrichment)
};

@@ -1161,5 +1181,6 @@ }

* @param globalStore
* @param groupName
*/
function createForm(options, globalStore) {
function createForm(options, globalStore, groupName) {
/**

@@ -1173,2 +1194,3 @@ * Store for all keyup handlers than need removed when destroyed

var stores = createFormStores(options);
var isGroup = typeof groupName !== 'undefined';
var initialOptions = options;

@@ -1183,7 +1205,6 @@ var submitHandler = undefined;

* @param innerOpt
* @param isGroup
*/
function bindElements(node, innerOpt, isGroup) {
var formElements = isGroup ? getGroupFields(node) : getAllFieldsWithValidity(node);
function bindElements(node, innerOpt) {
var formElements = isGroup ? getGroupFields(node) : getFormFields(node);
node.setAttribute("data-beaker-" + (isGroup ? 'row' : 'form'), 'true');

@@ -1197,3 +1218,2 @@ setAriaContainer(node, isGroup);

}, new Map()));
getInitialFormValues(node, groupedMap, stores, innerOpt);
innerReset = createReset(node, groupedMap, stores, innerOpt); // Loop over each group and setup up their initial touch and dirty handlers,

@@ -1212,3 +1232,3 @@ // also get initial values

if (isGroup) {
el.setAttribute('data-in-group', 'true');
el.setAttribute('data-in-group', groupName);
}

@@ -1297,7 +1317,6 @@

* @param node
* @param isGroup
*/
form: function form(node, isGroup) {
form: function form(node) {
currentNode = node;
bindElements(node, options, isGroup);
bindElements(node, options);
return {

@@ -1329,3 +1348,2 @@ destroy: function destroy() {

currentNode.id && globalStore && globalStore["delete"](name);
cleanupDefaultValues(currentNode);
},

@@ -1356,2 +1374,3 @@

var groupCounter = 0;
/**

@@ -1364,68 +1383,64 @@ * Creates a group, which is really just a collection of forms for row data

function createGroup(options, beakerStores) {
var stores = createGroupStores();
var groupId;
var stores = createGroupStores(options);
var groupName;
var globalObserver;
var formSet = new Set();
var instanceSet = new Set();
var subscriptions = new Map();
function destroyGroup() {
__spread(subscriptions).forEach(function (_a) {
var _b = __read(_a, 2),
key = _b[0],
subs = _b[1];
var _a = options || {},
defaultValues = _a.defaultValues,
formulaOptions = __rest(_a, ["defaultValues"]);
if (key === 'isFormValid' || key === 'isFormReady') {
stores[key].set(false);
} else {
stores[key].set([]);
}
var formulaInstances = new Map();
var formInstances = new Map();
/**
* Called when the group forms need destroyed
*/
subs.forEach(function (sub) {
return sub();
});
});
subscriptions.clear();
instanceSet.forEach(function (instance) {
function destroyGroup() {
formInstances.forEach(function (instance) {
return instance.destroy();
});
formSet.clear();
formInstances.clear();
formulaInstances.clear();
}
/**
* Called when a node it removed, it destroys it's form instance
* @param removedNodes
*/
function groupHasChanged(rows) {
rows.forEach(function (row, i) {
var form = createForm(options);
var instance = form.form(row, true);
formSet.add(form);
instanceSet.add(instance);
Object.entries(form.stores).forEach(function (_a) {
var _b = __read(_a, 2),
key = _b[0],
store = _b[1];
var unsub = store.subscribe(function (value) {
stores[key].update(function (state) {
if (Array.isArray(state)) {
state.splice(i, 1, value);
} else {
state = value;
}
function nodesRemoved(removedNodes) {
for (var i = 0; i < removedNodes.length; i++) {
var row = removedNodes[i];
var instance = formInstances.get(row);
return state;
});
});
if (instance) {
instance.destroy();
}
if (!subscriptions.has(key)) {
subscriptions.set(key, [unsub]);
} else {
var subs = subscriptions.get(key);
subs.push(unsub);
subscriptions.set(key, subs);
}
});
});
formInstances["delete"](row);
formulaInstances["delete"](row);
}
stores.isFormReady.set(true);
}
/**
* Called when a node is added, creates a new instance of a form for the row
* @param addedNodes
*/
function nodesAdded(addedNodes) {
for (var i = 0; i < addedNodes.length; i++) {
var row = addedNodes[i];
var form = createForm(__assign(__assign({}, formulaOptions), {
defaultValues: defaultValues[i]
}), undefined, groupName);
formulaInstances.set(row, form);
var instance = form.form(row, true);
formInstances.set(row, instance);
}
stores.isFormReady.set(true);
}
/**
* Set up the Observer for the group

@@ -1437,6 +1452,10 @@ * @param node

function setupGroupContainer(node) {
globalObserver = new MutationObserver(function (mutations) {
destroyGroup();
var rows = node.querySelectorAll(':scope > *');
groupHasChanged(Array.from(rows));
globalObserver = new MutationObserver(function (records) {
stores.isFormReady.set(false);
if (records[0].addedNodes.length > 0) {
nodesAdded(Array.from(records[0].addedNodes));
} else if (records[0].removedNodes.length > 0) {
nodesRemoved(Array.from(records[0].removedNodes));
}
});

@@ -1447,3 +1466,3 @@ globalObserver.observe(node, {

var rows = node.querySelectorAll(':scope > *');
groupHasChanged(Array.from(rows));
nodesAdded(Array.from(rows));
}

@@ -1453,7 +1472,10 @@

group: function group(node) {
groupId = node.id;
if (node.id) {
groupName = node.id;
beakerStores.set(groupName, stores);
} else {
groupName = "beaker-group-" + groupCounter++;
node.id = groupName;
}
if (groupId) {
beakerStores.set(groupId, stores);
}
node.setAttribute('data-beaker-group', 'true');

@@ -1464,4 +1486,4 @@ node.setAttribute('aria-role', 'group');

destroy: function destroy() {
if (groupId) {
beakerStores["delete"](groupId);
if (groupName) {
beakerStores["delete"](groupName);
}

@@ -1475,14 +1497,13 @@

update: function update(options) {
__spread(formSet).forEach(function (form) {
__spread(formulaInstances).forEach(function (_a) {
var _b = __read(_a, 2),
_ = _b[0],
form = _b[1];
return form.updateForm(options);
});
},
reset: function reset() {
__spread(formSet).forEach(function (form) {
return form.resetForm();
});
},
destroy: function destroy() {
if (groupId) {
beakerStores["delete"](groupId);
if (groupName) {
beakerStores["delete"](groupName);
}

@@ -1493,3 +1514,3 @@

},
forms: formSet,
forms: formulaInstances,
stores: stores,

@@ -1504,2 +1525,8 @@ init: function init(items) {

},
set: function set(index, item) {
return stores.formValues.update(function (state) {
state.splice(index, 1, item);
return state;
});
},
"delete": function _delete(index) {

@@ -1506,0 +1533,0 @@ return stores.formValues.update(function (state) {

@@ -87,3 +87,3 @@ (function (global, factory) {

*/
function getAllFieldsWithValidity(rootEl) {
function getFormFields(rootEl) {
var nodeList = rootEl.querySelectorAll('*[name]:not([data-in-group])');

@@ -224,3 +224,4 @@ return Array.from(nodeList).filter(function (el) {

el.setCustomValidity(''); // If there's no options, just return the current error
el.setCustomValidity('');
el.removeAttribute('data-formula-invalid'); // If there's no options, just return the current error

@@ -261,2 +262,7 @@ if (!options) {

var valid = el.checkValidity();
if (!valid) {
el.setAttribute('data-formula-invalid', 'true');
}
return {

@@ -652,7 +658,6 @@ valid: valid,

* @param options
* @param isGroup
*/
function createHandler(name, eventName, element, groupElements, stores, options, isGroup) {
function createHandler(name, eventName, element, groupElements, stores, options) {
var _a;

@@ -687,5 +692,2 @@

var initialValues = new Map();
var initialValidity = new Map();
var initialEnrichment = new Map();
/**

@@ -748,5 +750,3 @@ * Initialise the stores with data from the form, it will also use any default values provided

stores.enrichment.set(__assign({}, enrichmentValues));
initialValues.set(node, __assign({}, formValues));
initialValidity.set(node, __assign({}, validityValues));
initialEnrichment.set(node, __assign({}, enrichmentValues));
return [formValues, validityValues, enrichmentValues];
}

@@ -758,12 +758,16 @@ /**

function createReset(node, allGroups, stores, options) {
var _a = __read(getInitialFormValues(node, allGroups, stores, options), 3),
formValues = _a[0],
validityValues = _a[1],
enrichmentValues = _a[2];
/**
* Resets the form to the initial values
*/
return function () {
var e_2, _a;
var formValues = initialValues.get(node);
var validityValues = initialValidity.get(node);
var enrichment = initialEnrichment.get(node);
stores.formValues.set(formValues);

@@ -774,5 +778,5 @@ stores.validity.set(validityValues);

}));
stores.enrichment.set(enrichment); // Also override touched and dirty
stores.enrichment.set(enrichmentValues); // Also override touched and dirty
stores.touched.set(Object.keys(initialValues).reduce(function (val, key) {
stores.touched.set(Object.keys(formValues).reduce(function (val, key) {
var _a;

@@ -782,3 +786,3 @@

}, {}));
stores.dirty.set(Object.keys(initialValues).reduce(function (val, key) {
stores.dirty.set(Object.keys(formValues).reduce(function (val, key) {
var _a;

@@ -812,16 +816,3 @@

}
function cleanupDefaultValues(node) {
if (initialValues.has(node)) {
initialValues["delete"](node);
}
if (initialValidity.has(node)) {
initialValidity["delete"](node);
}
if (initialEnrichment.has(node)) {
initialEnrichment["delete"](node);
}
}
/**

@@ -861,2 +852,3 @@ * Creates the handler for a group of elements for the touch event on the group name, once an

el.setAttribute('data-formula-touched', 'true');
el.removeEventListener('focus', handler);

@@ -970,2 +962,3 @@ }

el.setAttribute('data-formula-dirty', 'true');
el.removeEventListener('blur', handler);

@@ -1146,13 +1139,40 @@ }

function createGroupStores(options) {
var _a;
var initialValues = [];
var initialFieldState = [];
var initialValidity = [];
var initialEnrichment = [];
var initialFormValidity = [];
if (((_a = options === null || options === void 0 ? void 0 : options.defaultValues) === null || _a === void 0 ? void 0 : _a.length) > 0) {
var defaultValues = options.defaultValues,
rest_1 = __rest(options, ["defaultValues"]);
var eachState = defaultValues.map(function (d) {
return createFirstState(__assign(__assign({}, rest_1), {
defaultValues: d
}));
});
for (var i = 0; i < eachState.length; i++) {
initialValues = __spread(initialValues, [eachState[i].initialValues]);
initialFieldState = __spread(initialFieldState, [eachState[i].initialFieldState]);
initialValidity = __spread(initialValidity, [eachState[i].initialValidity]);
initialEnrichment = __spread(initialEnrichment, [eachState[i].initialEnrichment]);
initialFormValidity = __spread(initialFormValidity, [eachState[i].initialFormValidity]);
}
}
return {
formValues: store.writable([]),
formValues: store.writable(initialValues),
submitValues: store.writable([]),
initialValues: store.writable([]),
touched: store.writable([]),
dirty: store.writable([]),
validity: store.writable([]),
formValidity: store.writable({}),
initialValues: store.writable(initialValues),
touched: store.writable(initialFieldState),
dirty: store.writable(initialFieldState),
validity: store.writable(initialValidity),
formValidity: store.writable(initialFormValidity),
isFormValid: store.writable(false),
isFormReady: store.writable(false),
enrichment: store.writable([])
enrichment: store.writable(initialEnrichment)
};

@@ -1165,5 +1185,6 @@ }

* @param globalStore
* @param groupName
*/
function createForm(options, globalStore) {
function createForm(options, globalStore, groupName) {
/**

@@ -1177,2 +1198,3 @@ * Store for all keyup handlers than need removed when destroyed

var stores = createFormStores(options);
var isGroup = typeof groupName !== 'undefined';
var initialOptions = options;

@@ -1187,7 +1209,6 @@ var submitHandler = undefined;

* @param innerOpt
* @param isGroup
*/
function bindElements(node, innerOpt, isGroup) {
var formElements = isGroup ? getGroupFields(node) : getAllFieldsWithValidity(node);
function bindElements(node, innerOpt) {
var formElements = isGroup ? getGroupFields(node) : getFormFields(node);
node.setAttribute("data-beaker-" + (isGroup ? 'row' : 'form'), 'true');

@@ -1201,3 +1222,2 @@ setAriaContainer(node, isGroup);

}, new Map()));
getInitialFormValues(node, groupedMap, stores, innerOpt);
innerReset = createReset(node, groupedMap, stores, innerOpt); // Loop over each group and setup up their initial touch and dirty handlers,

@@ -1216,3 +1236,3 @@ // also get initial values

if (isGroup) {
el.setAttribute('data-in-group', 'true');
el.setAttribute('data-in-group', groupName);
}

@@ -1301,7 +1321,6 @@

* @param node
* @param isGroup
*/
form: function form(node, isGroup) {
form: function form(node) {
currentNode = node;
bindElements(node, options, isGroup);
bindElements(node, options);
return {

@@ -1333,3 +1352,2 @@ destroy: function destroy() {

currentNode.id && globalStore && globalStore["delete"](name);
cleanupDefaultValues(currentNode);
},

@@ -1360,2 +1378,3 @@

var groupCounter = 0;
/**

@@ -1368,68 +1387,64 @@ * Creates a group, which is really just a collection of forms for row data

function createGroup(options, beakerStores) {
var stores = createGroupStores();
var groupId;
var stores = createGroupStores(options);
var groupName;
var globalObserver;
var formSet = new Set();
var instanceSet = new Set();
var subscriptions = new Map();
function destroyGroup() {
__spread(subscriptions).forEach(function (_a) {
var _b = __read(_a, 2),
key = _b[0],
subs = _b[1];
var _a = options || {},
defaultValues = _a.defaultValues,
formulaOptions = __rest(_a, ["defaultValues"]);
if (key === 'isFormValid' || key === 'isFormReady') {
stores[key].set(false);
} else {
stores[key].set([]);
}
var formulaInstances = new Map();
var formInstances = new Map();
/**
* Called when the group forms need destroyed
*/
subs.forEach(function (sub) {
return sub();
});
});
subscriptions.clear();
instanceSet.forEach(function (instance) {
function destroyGroup() {
formInstances.forEach(function (instance) {
return instance.destroy();
});
formSet.clear();
formInstances.clear();
formulaInstances.clear();
}
/**
* Called when a node it removed, it destroys it's form instance
* @param removedNodes
*/
function groupHasChanged(rows) {
rows.forEach(function (row, i) {
var form = createForm(options);
var instance = form.form(row, true);
formSet.add(form);
instanceSet.add(instance);
Object.entries(form.stores).forEach(function (_a) {
var _b = __read(_a, 2),
key = _b[0],
store = _b[1];
var unsub = store.subscribe(function (value) {
stores[key].update(function (state) {
if (Array.isArray(state)) {
state.splice(i, 1, value);
} else {
state = value;
}
function nodesRemoved(removedNodes) {
for (var i = 0; i < removedNodes.length; i++) {
var row = removedNodes[i];
var instance = formInstances.get(row);
return state;
});
});
if (instance) {
instance.destroy();
}
if (!subscriptions.has(key)) {
subscriptions.set(key, [unsub]);
} else {
var subs = subscriptions.get(key);
subs.push(unsub);
subscriptions.set(key, subs);
}
});
});
formInstances["delete"](row);
formulaInstances["delete"](row);
}
stores.isFormReady.set(true);
}
/**
* Called when a node is added, creates a new instance of a form for the row
* @param addedNodes
*/
function nodesAdded(addedNodes) {
for (var i = 0; i < addedNodes.length; i++) {
var row = addedNodes[i];
var form = createForm(__assign(__assign({}, formulaOptions), {
defaultValues: defaultValues[i]
}), undefined, groupName);
formulaInstances.set(row, form);
var instance = form.form(row, true);
formInstances.set(row, instance);
}
stores.isFormReady.set(true);
}
/**
* Set up the Observer for the group

@@ -1441,6 +1456,10 @@ * @param node

function setupGroupContainer(node) {
globalObserver = new MutationObserver(function (mutations) {
destroyGroup();
var rows = node.querySelectorAll(':scope > *');
groupHasChanged(Array.from(rows));
globalObserver = new MutationObserver(function (records) {
stores.isFormReady.set(false);
if (records[0].addedNodes.length > 0) {
nodesAdded(Array.from(records[0].addedNodes));
} else if (records[0].removedNodes.length > 0) {
nodesRemoved(Array.from(records[0].removedNodes));
}
});

@@ -1451,3 +1470,3 @@ globalObserver.observe(node, {

var rows = node.querySelectorAll(':scope > *');
groupHasChanged(Array.from(rows));
nodesAdded(Array.from(rows));
}

@@ -1457,7 +1476,10 @@

group: function group(node) {
groupId = node.id;
if (node.id) {
groupName = node.id;
beakerStores.set(groupName, stores);
} else {
groupName = "beaker-group-" + groupCounter++;
node.id = groupName;
}
if (groupId) {
beakerStores.set(groupId, stores);
}
node.setAttribute('data-beaker-group', 'true');

@@ -1468,4 +1490,4 @@ node.setAttribute('aria-role', 'group');

destroy: function destroy() {
if (groupId) {
beakerStores["delete"](groupId);
if (groupName) {
beakerStores["delete"](groupName);
}

@@ -1479,14 +1501,13 @@

update: function update(options) {
__spread(formSet).forEach(function (form) {
__spread(formulaInstances).forEach(function (_a) {
var _b = __read(_a, 2),
_ = _b[0],
form = _b[1];
return form.updateForm(options);
});
},
reset: function reset() {
__spread(formSet).forEach(function (form) {
return form.resetForm();
});
},
destroy: function destroy() {
if (groupId) {
beakerStores["delete"](groupId);
if (groupName) {
beakerStores["delete"](groupName);
}

@@ -1497,3 +1518,3 @@

},
forms: formSet,
forms: formulaInstances,
stores: stores,

@@ -1508,2 +1529,8 @@ init: function init(items) {

},
set: function set(index, item) {
return stores.formValues.update(function (state) {
state.splice(index, 1, item);
return state;
});
},
"delete": function _delete(index) {

@@ -1510,0 +1537,0 @@ return stores.formValues.update(function (state) {

@@ -34,3 +34,3 @@ import { Writable } from 'svelte/store';

*/
formValidity: Writable<Record<string, string | null>>;
formValidity: Writable<Record<string, string | null>[]>;
/**

@@ -69,9 +69,5 @@ * A store containing a boolean value if the form is overall valid

/**
* Reset
*/
reset: () => void;
/**
* Instance forms
*/
forms: Set<Formula<T>>;
forms: Map<HTMLElement, Formula<T>>;
/**

@@ -91,2 +87,6 @@ * Stores

/**
* Add an item to the group store
*/
set: (index: number, item: T) => void;
/**
* Remove and item from the group store

@@ -93,0 +93,0 @@ */

import { CustomValidationMessages, ValidationRule, ValidationRules } from './validation';
import { EnrichFields } from './enrich';
/**
* Optional settings for Formula
*/
export interface FormulaOptions {
interface BaseOptions {
/**
* Locale for i18n - currently not used
*/
locale?: string;
/**
* Provide customised messages to the application, these messages replace the default browser messages for the provided

@@ -31,2 +24,7 @@ * error types and are useful for internationalisation or custom domain messages

enrich?: EnrichFields;
}
/**
* Optional settings for Formula
*/
export interface FormulaOptions extends BaseOptions {
/**

@@ -37,1 +35,11 @@ * Default values are used as initial values for the form fields if there is no value already set on the form

}
/**
* Optional settings for Beaker
*/
export interface BeakerOptions extends BaseOptions {
/**
* Default values are used as initial values for the form fields if there is no value already set on the form
*/
defaultValues?: Record<string, unknown | unknown[]>[];
}
export {};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc