Repo restructure.
This commit is contained in:
100
package-lock.json
generated
100
package-lock.json
generated
@@ -8,6 +8,9 @@
|
|||||||
"name": "web-components",
|
"name": "web-components",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"jest": "^30.2.0",
|
"jest": "^30.2.0",
|
||||||
@@ -1530,6 +1533,37 @@
|
|||||||
"node": ">= 14"
|
"node": ">= 14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ajv": {
|
||||||
|
"version": "8.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"fast-uri": "^3.0.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ajv": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ansi-escapes": {
|
"node_modules/ansi-escapes": {
|
||||||
"version": "4.3.2",
|
"version": "4.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
|
||||||
@@ -2049,6 +2083,10 @@
|
|||||||
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
|
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/declaform": {
|
||||||
|
"resolved": "packages/declaform",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/dedent": {
|
"node_modules/dedent": {
|
||||||
"version": "1.7.0",
|
"version": "1.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz",
|
||||||
@@ -2218,12 +2256,32 @@
|
|||||||
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
|
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-deep-equal": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
|
||||||
|
},
|
||||||
"node_modules/fast-json-stable-stringify": {
|
"node_modules/fast-json-stable-stringify": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
|
||||||
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-uri": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fastify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/fastify"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/fb-watchman": {
|
"node_modules/fb-watchman": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
|
||||||
@@ -3326,6 +3384,15 @@
|
|||||||
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/json-schema": {
|
||||||
|
"resolved": "packages/json-schema",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
|
"node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||||
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "2.2.3",
|
"version": "2.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||||
@@ -3820,6 +3887,14 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/require-from-string": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve-cwd": {
|
"node_modules/resolve-cwd": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
|
||||||
@@ -4799,6 +4874,31 @@
|
|||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"packages/declaform": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"packages/json-schema": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.17.1",
|
||||||
|
"ajv-formats": "^3.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"src/declaform": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"src/json-schema": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"extraneous": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv-formats": "^3.0.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
},
|
},
|
||||||
"author": "Austin Smith",
|
"author": "Austin Smith",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"workspaces": [
|
||||||
|
"packages/*"
|
||||||
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"jest": "^30.2.0",
|
"jest": "^30.2.0",
|
||||||
|
|||||||
14
packages/declaform/package.json
Normal file
14
packages/declaform/package.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "declaform",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Web component which maps a form to a JSON object",
|
||||||
|
"main": "index.js",
|
||||||
|
"directories": {
|
||||||
|
"test": "tests"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "npx jest"
|
||||||
|
},
|
||||||
|
"author": "Austin Smith",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
||||||
@@ -150,6 +150,11 @@ export class Declaform extends HTMLElement {
|
|||||||
if (src) {
|
if (src) {
|
||||||
this.hydrateFromEndpoint(src);
|
this.hydrateFromEndpoint(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._form.addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await this.submit();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
get form() {
|
get form() {
|
||||||
@@ -202,6 +207,20 @@ export class Declaform extends HTMLElement {
|
|||||||
const obj = await response.json();
|
const obj = await response.json();
|
||||||
this.hydrate(obj);
|
this.hydrate(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async submit(): Promise<void> {
|
||||||
|
const method = this.getAttribute('method') ?? 'POST';
|
||||||
|
const endpoint = new URL(this.getAttribute('action') ?? '');
|
||||||
|
const obj = this.toObject();
|
||||||
|
|
||||||
|
const response = await fetch(endpoint, {
|
||||||
|
method,
|
||||||
|
body: JSON.stringify(obj),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('decla-form', Declaform);
|
customElements.define('decla-form', Declaform);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Declaform } from '../declaform';
|
import { Declaform } from '../src';
|
||||||
|
|
||||||
const MOVIE_FORM_NO_SRC = `
|
const MOVIE_FORM_NO_SRC = `
|
||||||
<decla-form id="form">
|
<decla-form id="form">
|
||||||
@@ -32,7 +32,7 @@ const MOVIE_FORM_NO_SRC = `
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const MOVIE_FORM_HTTP = `
|
const MOVIE_FORM_HTTP = `
|
||||||
<decla-form id="form" src="get-movie/jaws">
|
<decla-form id="form" src="movie/jaws" action="movie/jaws" method="PUT">
|
||||||
<form slot="form">
|
<form slot="form">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
@@ -108,7 +108,7 @@ describe('Declaform', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('Supplying "src" attribute should hydrate form with the supplied endpoint.', async () => {
|
it('Supplying "src" attribute should hydrate form with the supplied endpoint.', async () => {
|
||||||
global.fetch = jest.fn().mockResolvedValue({
|
globalThis.fetch = jest.fn().mockResolvedValue({
|
||||||
status: 200,
|
status: 200,
|
||||||
ok: true,
|
ok: true,
|
||||||
json: () => Promise.resolve({
|
json: () => Promise.resolve({
|
||||||
9
packages/declaform/tsconfig.json
Normal file
9
packages/declaform/tsconfig.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./",
|
||||||
|
"outDir": "../../dist/declaform",
|
||||||
|
"types": ["jest"]
|
||||||
|
},
|
||||||
|
"include": ["src", "tests"]
|
||||||
|
}
|
||||||
15
packages/json-schema/package.json
Normal file
15
packages/json-schema/package.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "json-schema",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Web component which validates a form against a JSON Schema.",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "npx jest"
|
||||||
|
},
|
||||||
|
"author": "Austin Smith",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.17.1",
|
||||||
|
"ajv-formats": "^3.0.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
46
packages/json-schema/src/index.ts
Normal file
46
packages/json-schema/src/index.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Validates a form against a JSON Schema validated by Ajv.
|
||||||
|
*
|
||||||
|
* Emits CustomEvents:
|
||||||
|
* - validationSuccess
|
||||||
|
* - validationFailure
|
||||||
|
*/
|
||||||
|
import Ajv from 'ajv';
|
||||||
|
import addFormats from 'ajv-formats';
|
||||||
|
|
||||||
|
const ajv = new Ajv();
|
||||||
|
addFormats(ajv);
|
||||||
|
|
||||||
|
export class JsonSchema extends HTMLElement {
|
||||||
|
static observedAttributes = [
|
||||||
|
'src', // url of remote schema
|
||||||
|
'for', // id of form the schema is applied to`
|
||||||
|
]
|
||||||
|
|
||||||
|
private form: HTMLFormElement | null;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.attachShadow({ mode: 'open' });
|
||||||
|
this.shadowRoot!.innerHTML = '<div><slot name="schema"></slot></div>';
|
||||||
|
this.form = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async connectedCallback() {
|
||||||
|
const for_attr = this.getAttribute('for');
|
||||||
|
if (!for_attr) {
|
||||||
|
throw new Error('[Json-Schema] Error: "for" attribute must be defined');
|
||||||
|
}
|
||||||
|
this.form = document.getElementById(for_attr) as HTMLFormElement;
|
||||||
|
this.form.addEventListener('submit', () => {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
validate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('json-schema', JsonSchema);
|
||||||
8
packages/json-schema/tsconfig.json
Normal file
8
packages/json-schema/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "../../dist/json-schema"
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
@@ -1,20 +1,11 @@
|
|||||||
{
|
{
|
||||||
// Visit https://aka.ms/tsconfig to read more about this file
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
// File Layout
|
|
||||||
"rootDir": "./src",
|
|
||||||
"outDir": "./dist",
|
|
||||||
|
|
||||||
// Environment Settings
|
// Environment Settings
|
||||||
// See also https://aka.ms/tsconfig/module
|
// See also https://aka.ms/tsconfig/module
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"target": "es6",
|
"target": "es6",
|
||||||
"types": [],
|
"types": [],
|
||||||
// For nodejs:
|
|
||||||
// "lib": ["esnext"],
|
|
||||||
// "types": ["node"],
|
|
||||||
// and npm install -D @types/node
|
|
||||||
|
|
||||||
// Other Outputs
|
// Other Outputs
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
@@ -24,6 +15,7 @@
|
|||||||
// Stricter Typechecking Options
|
// Stricter Typechecking Options
|
||||||
"noUncheckedIndexedAccess": true,
|
"noUncheckedIndexedAccess": true,
|
||||||
"exactOptionalPropertyTypes": true,
|
"exactOptionalPropertyTypes": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
|
||||||
// Style Options
|
// Style Options
|
||||||
// "noImplicitReturns": true,
|
// "noImplicitReturns": true,
|
||||||
@@ -41,6 +33,5 @@
|
|||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true,
|
||||||
"moduleDetection": "force",
|
"moduleDetection": "force",
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
},
|
}
|
||||||
"exclude": ["./src/**/*.test.ts"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user