Socket
Socket
Sign inDemoInstall

@conform-to/dom

Package Overview
Dependencies
Maintainers
1
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@conform-to/dom - npm Package Compare versions

Comparing version 0.5.0-pre.0 to 0.5.0

56

index.d.ts
export declare type Primitive = null | undefined | string | number | boolean | Date;
export declare type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement;
export interface FieldConfig<Schema = unknown> extends FieldConstraint<Schema> {
id?: string;
name: string;

@@ -8,2 +9,3 @@ defaultValue?: FieldValue<Schema>;

form?: string;
errorId?: string;
}

@@ -32,2 +34,7 @@ export declare type FieldValue<Schema> = Schema extends Primitive ? string : Schema extends File ? File : Schema extends Array<infer InnerType> ? Array<FieldValue<InnerType>> : Schema extends Record<string, any> ? {

};
export interface CommandButtonProps<Name extends string = string> {
name: `conform/${Name}`;
value: string;
formNoValidate?: boolean;
}
export declare function isFieldElement(element: unknown): element is FieldElement;

@@ -38,16 +45,26 @@ export declare function getFormElements(form: HTMLFormElement): FieldElement[];

export declare function getName(paths: Array<string | number>): string;
export declare function shouldValidate(submission: Submission, name?: string): boolean;
export declare function shouldValidate(submission: Submission, name: string): boolean;
export declare function hasError(error: Array<[string, string]>, name?: string): boolean;
export declare function reportSubmission(form: HTMLFormElement, submission: Submission): void;
export declare function setValue<T>(target: any, paths: Array<string | number>, valueFn: (prev?: T) => T): void;
/**
* The ponyfill of `HTMLFormElement.requestSubmit()`
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
* @see https://caniuse.com/?search=requestSubmit
*/
export declare function requestSubmit(form: HTMLFormElement, submitter?: HTMLButtonElement | HTMLInputElement): void;
export declare function requestValidate(form: HTMLFormElement, field?: string): void;
/**
* Creates a command button on demand and trigger a form submit by clicking it.
*/
export declare function requestCommand(form: HTMLFormElement | undefined, buttonProps: CommandButtonProps): void;
/**
* Returns the properties required to configure a command button for validation
*
* @see https://conform.guide/api/react#validate
*/
export declare function validate(field?: string): CommandButtonProps<'validate'>;
export declare function getFormElement(element: HTMLFormElement | HTMLFieldSetElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement | null): HTMLFormElement | null;
export declare function focusFirstInvalidField(form: HTMLFormElement): void;
export declare function focus(field: FieldElement): void;
export declare function getSubmissionType(name: string): string | null;
export declare function parse<Schema extends Record<string, any>>(payload: FormData | URLSearchParams): Submission<Schema>;
export declare type Command = {
name: string;
value: string;
};
export declare type ListCommand<Schema = unknown> = {

@@ -89,1 +106,26 @@ type: 'prepend';

export declare function handleList<Schema>(submission: Submission<Schema>): Submission<Schema>;
export interface ListCommandButtonBuilder {
append<Schema>(name: string, payload?: {
defaultValue: Schema;
}): CommandButtonProps<'list'>;
prepend<Schema>(name: string, payload?: {
defaultValue: Schema;
}): CommandButtonProps<'list'>;
replace<Schema>(name: string, payload: {
defaultValue: Schema;
index: number;
}): CommandButtonProps<'list'>;
remove(name: string, payload: {
index: number;
}): CommandButtonProps<'list'>;
reorder(name: string, payload: {
from: number;
to: number;
}): CommandButtonProps<'list'>;
}
/**
* Helpers to configure a command button for modifying a list
*
* @see https://conform.guide/api/react#list
*/
export declare const list: ListCommandButtonBuilder;

138

index.js

@@ -48,3 +48,3 @@ 'use strict';

function shouldValidate(submission, name) {
return submission.type === 'submit' || submission.type === 'validate' && (typeof name === 'undefined' || submission.intent === name);
return submission.type === 'submit' || submission.type === 'validate' && (submission.intent === '' || submission.intent === name);
}

@@ -59,14 +59,17 @@ function hasError(error, name) {

var messageByName = new Map();
var nameByInput = new Map();
for (var [name, message] of submission.error) {
if (!messageByName.has(name)) {
for (var [_name, message] of submission.error) {
if (!messageByName.has(_name)) {
// Only keep the first error message (for now)
messageByName.set(name, message);
messageByName.set(_name, message);
// We can't use empty string as button name
// As `form.element.namedItem('')` will always returns null
var elementName = name ? name : '__form__';
var elementName = _name ? _name : '__form__';
var item = form.elements.namedItem(elementName);
if (item instanceof RadioNodeList) {
throw new Error('Repeated field name is not supported');
for (var field of item) {
if (field.type !== 'radio') {
throw new Error('Repeated field name is not supported');
}
}
}

@@ -82,3 +85,2 @@ if (item === null) {

}
nameByInput.set(item, name);
}

@@ -88,6 +90,9 @@ }

if (isFieldElement(element) && element.willValidate) {
var _nameByInput$get;
var _name = (_nameByInput$get = nameByInput.get(element)) !== null && _nameByInput$get !== void 0 ? _nameByInput$get : element.name;
var _message = messageByName.get(_name);
if (typeof _message !== 'undefined' || shouldValidate(submission, _name)) {
var _elementName = element.name !== '__form__' ? element.name : '';
var _message = messageByName.get(_elementName);
var elementShouldValidate = shouldValidate(submission, _elementName);
if (elementShouldValidate) {
element.dataset.conformTouched = 'true';
}
if (typeof _message !== 'undefined' || elementShouldValidate) {
var invalidEvent = new Event('invalid', {

@@ -99,5 +104,7 @@ cancelable: true

}
if (elementShouldValidate && !element.validity.valid) {
focus(element);
}
}
}
focusFirstInvalidField(form);
}

@@ -118,2 +125,8 @@ function setValue(target, paths, valueFn) {

}
/**
* The ponyfill of `HTMLFormElement.requestSubmit()`
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
* @see https://caniuse.com/?search=requestSubmit
*/
function requestSubmit(form, submitter) {

@@ -127,12 +140,35 @@ var submitEvent = new SubmitEvent('submit', {

}
function requestValidate(form, field) {
/**
* Creates a command button on demand and trigger a form submit by clicking it.
*/
function requestCommand(form, buttonProps) {
if (!form) {
console.warn('No form element is provided');
return;
}
var button = document.createElement('button');
button.name = 'conform/validate';
button.value = field !== null && field !== void 0 ? field : '';
button.formNoValidate = true;
button.name = buttonProps.name;
button.value = buttonProps.value;
button.hidden = true;
if (buttonProps.formNoValidate) {
button.formNoValidate = true;
}
form.appendChild(button);
requestSubmit(form, button);
button.click();
form.removeChild(button);
}
/**
* Returns the properties required to configure a command button for validation
*
* @see https://conform.guide/api/react#validate
*/
function validate(field) {
return {
name: 'conform/validate',
value: field !== null && field !== void 0 ? field : '',
formNoValidate: true
};
}
function getFormElement(element) {

@@ -145,16 +181,8 @@ var form = element instanceof HTMLFormElement ? element : element === null || element === void 0 ? void 0 : element.form;

}
function focusFirstInvalidField(form) {
function focus(field) {
var currentFocus = document.activeElement;
if (!isFieldElement(currentFocus) || currentFocus.tagName !== 'BUTTON' || currentFocus.form !== form) {
if (!isFieldElement(currentFocus) || currentFocus.tagName !== 'BUTTON' || currentFocus.form !== field.form) {
return;
}
for (var field of form.elements) {
if (isFieldElement(field)) {
// Focus on the first non button field
if (!field.validity.valid && field.dataset.conformTouched && field.tagName !== 'BUTTON') {
field.focus();
break;
}
}
}
field.focus();
}

@@ -176,4 +204,4 @@ function getSubmissionType(name) {

try {
var _loop = function _loop(name, value) {
var submissionType = getSubmissionType(name);
var _loop = function _loop(value, _name2) {
var submissionType = getSubmissionType(_name2);
if (submissionType) {

@@ -192,3 +220,3 @@ if (typeof value !== 'string') {

} else {
var paths = getPaths(name);
var paths = getPaths(_name2);
setValue(submission.value, paths, prev => {

@@ -205,4 +233,4 @@ if (!prev) {

};
for (var [name, value] of payload.entries()) {
_loop(name, value);
for (var [_name2, value] of payload.entries()) {
_loop(value, _name2);
}

@@ -222,4 +250,4 @@ switch (submission.type) {

var command = JSON.parse(data);
if (typeof command.type !== 'string' || !['prepend', 'append', 'replace', 'remove', 'reorder'].includes(command.type)) {
throw new Error('Unsupported list command type');
if (typeof command.type !== 'string' || !['prepend', 'append', 'replace', 'remove', 'reorder', 'combine'].includes(command.type)) {
throw new Error("Unknown list command received: ".concat(command.type));
}

@@ -267,11 +295,39 @@ return command;

setValue(submission.value, paths, list => {
if (!Array.isArray(list)) {
if (typeof list !== 'undefined' && !Array.isArray(list)) {
throw new Error('The list command can only be applied to a list');
}
return updateList(list, command);
return updateList(list !== null && list !== void 0 ? list : [], command);
});
return submission;
}
/**
* Helpers to configure a command button for modifying a list
*
* @see https://conform.guide/api/react#list
*/
var list = new Proxy({}, {
get(_target, type) {
switch (type) {
case 'append':
case 'prepend':
case 'replace':
case 'remove':
case 'reorder':
return function (scope) {
var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return {
name: 'conform/list',
value: JSON.stringify({
type,
scope,
payload
}),
formNoValidate: true
};
};
}
}
});
exports.focusFirstInvalidField = focusFirstInvalidField;
exports.focus = focus;
exports.getFormData = getFormData;

@@ -286,9 +342,11 @@ exports.getFormElement = getFormElement;

exports.isFieldElement = isFieldElement;
exports.list = list;
exports.parse = parse;
exports.parseListCommand = parseListCommand;
exports.reportSubmission = reportSubmission;
exports.requestCommand = requestCommand;
exports.requestSubmit = requestSubmit;
exports.requestValidate = requestValidate;
exports.setValue = setValue;
exports.shouldValidate = shouldValidate;
exports.updateList = updateList;
exports.validate = validate;

@@ -44,3 +44,3 @@ import { objectSpread2 as _objectSpread2 } from './_virtual/_rollupPluginBabelHelpers.js';

function shouldValidate(submission, name) {
return submission.type === 'submit' || submission.type === 'validate' && (typeof name === 'undefined' || submission.intent === name);
return submission.type === 'submit' || submission.type === 'validate' && (submission.intent === '' || submission.intent === name);
}

@@ -55,14 +55,17 @@ function hasError(error, name) {

var messageByName = new Map();
var nameByInput = new Map();
for (var [name, message] of submission.error) {
if (!messageByName.has(name)) {
for (var [_name, message] of submission.error) {
if (!messageByName.has(_name)) {
// Only keep the first error message (for now)
messageByName.set(name, message);
messageByName.set(_name, message);
// We can't use empty string as button name
// As `form.element.namedItem('')` will always returns null
var elementName = name ? name : '__form__';
var elementName = _name ? _name : '__form__';
var item = form.elements.namedItem(elementName);
if (item instanceof RadioNodeList) {
throw new Error('Repeated field name is not supported');
for (var field of item) {
if (field.type !== 'radio') {
throw new Error('Repeated field name is not supported');
}
}
}

@@ -78,3 +81,2 @@ if (item === null) {

}
nameByInput.set(item, name);
}

@@ -84,6 +86,9 @@ }

if (isFieldElement(element) && element.willValidate) {
var _nameByInput$get;
var _name = (_nameByInput$get = nameByInput.get(element)) !== null && _nameByInput$get !== void 0 ? _nameByInput$get : element.name;
var _message = messageByName.get(_name);
if (typeof _message !== 'undefined' || shouldValidate(submission, _name)) {
var _elementName = element.name !== '__form__' ? element.name : '';
var _message = messageByName.get(_elementName);
var elementShouldValidate = shouldValidate(submission, _elementName);
if (elementShouldValidate) {
element.dataset.conformTouched = 'true';
}
if (typeof _message !== 'undefined' || elementShouldValidate) {
var invalidEvent = new Event('invalid', {

@@ -95,5 +100,7 @@ cancelable: true

}
if (elementShouldValidate && !element.validity.valid) {
focus(element);
}
}
}
focusFirstInvalidField(form);
}

@@ -114,2 +121,8 @@ function setValue(target, paths, valueFn) {

}
/**
* The ponyfill of `HTMLFormElement.requestSubmit()`
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit
* @see https://caniuse.com/?search=requestSubmit
*/
function requestSubmit(form, submitter) {

@@ -123,12 +136,35 @@ var submitEvent = new SubmitEvent('submit', {

}
function requestValidate(form, field) {
/**
* Creates a command button on demand and trigger a form submit by clicking it.
*/
function requestCommand(form, buttonProps) {
if (!form) {
console.warn('No form element is provided');
return;
}
var button = document.createElement('button');
button.name = 'conform/validate';
button.value = field !== null && field !== void 0 ? field : '';
button.formNoValidate = true;
button.name = buttonProps.name;
button.value = buttonProps.value;
button.hidden = true;
if (buttonProps.formNoValidate) {
button.formNoValidate = true;
}
form.appendChild(button);
requestSubmit(form, button);
button.click();
form.removeChild(button);
}
/**
* Returns the properties required to configure a command button for validation
*
* @see https://conform.guide/api/react#validate
*/
function validate(field) {
return {
name: 'conform/validate',
value: field !== null && field !== void 0 ? field : '',
formNoValidate: true
};
}
function getFormElement(element) {

@@ -141,16 +177,8 @@ var form = element instanceof HTMLFormElement ? element : element === null || element === void 0 ? void 0 : element.form;

}
function focusFirstInvalidField(form) {
function focus(field) {
var currentFocus = document.activeElement;
if (!isFieldElement(currentFocus) || currentFocus.tagName !== 'BUTTON' || currentFocus.form !== form) {
if (!isFieldElement(currentFocus) || currentFocus.tagName !== 'BUTTON' || currentFocus.form !== field.form) {
return;
}
for (var field of form.elements) {
if (isFieldElement(field)) {
// Focus on the first non button field
if (!field.validity.valid && field.dataset.conformTouched && field.tagName !== 'BUTTON') {
field.focus();
break;
}
}
}
field.focus();
}

@@ -172,4 +200,4 @@ function getSubmissionType(name) {

try {
var _loop = function _loop(name, value) {
var submissionType = getSubmissionType(name);
var _loop = function _loop(value, _name2) {
var submissionType = getSubmissionType(_name2);
if (submissionType) {

@@ -188,3 +216,3 @@ if (typeof value !== 'string') {

} else {
var paths = getPaths(name);
var paths = getPaths(_name2);
setValue(submission.value, paths, prev => {

@@ -201,4 +229,4 @@ if (!prev) {

};
for (var [name, value] of payload.entries()) {
_loop(name, value);
for (var [_name2, value] of payload.entries()) {
_loop(value, _name2);
}

@@ -218,4 +246,4 @@ switch (submission.type) {

var command = JSON.parse(data);
if (typeof command.type !== 'string' || !['prepend', 'append', 'replace', 'remove', 'reorder'].includes(command.type)) {
throw new Error('Unsupported list command type');
if (typeof command.type !== 'string' || !['prepend', 'append', 'replace', 'remove', 'reorder', 'combine'].includes(command.type)) {
throw new Error("Unknown list command received: ".concat(command.type));
}

@@ -263,10 +291,38 @@ return command;

setValue(submission.value, paths, list => {
if (!Array.isArray(list)) {
if (typeof list !== 'undefined' && !Array.isArray(list)) {
throw new Error('The list command can only be applied to a list');
}
return updateList(list, command);
return updateList(list !== null && list !== void 0 ? list : [], command);
});
return submission;
}
/**
* Helpers to configure a command button for modifying a list
*
* @see https://conform.guide/api/react#list
*/
var list = new Proxy({}, {
get(_target, type) {
switch (type) {
case 'append':
case 'prepend':
case 'replace':
case 'remove':
case 'reorder':
return function (scope) {
var payload = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
return {
name: 'conform/list',
value: JSON.stringify({
type,
scope,
payload
}),
formNoValidate: true
};
};
}
}
});
export { focusFirstInvalidField, getFormData, getFormElement, getFormElements, getName, getPaths, getSubmissionType, handleList, hasError, isFieldElement, parse, parseListCommand, reportSubmission, requestSubmit, requestValidate, setValue, shouldValidate, updateList };
export { focus, getFormData, getFormElement, getFormElements, getName, getPaths, getSubmissionType, handleList, hasError, isFieldElement, list, parse, parseListCommand, reportSubmission, requestCommand, requestSubmit, setValue, shouldValidate, updateList, validate };

@@ -5,3 +5,3 @@ {

"license": "MIT",
"version": "0.5.0-pre.0",
"version": "0.5.0",
"main": "index.js",

@@ -8,0 +8,0 @@ "module": "module/index.js",

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc