diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1eae0cf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..43b2f37 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,29 @@ +{ + "name": "web-components", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "web-components", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "typescript": "^5.9.2" + } + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..964c3b7 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "name": "web-components", + "version": "1.0.0", + "description": "A collection of useful web components and functionality.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Austin Smith", + "license": "ISC", + "devDependencies": { + "typescript": "^5.9.2" + } +} diff --git a/src/declaform/README.md b/src/declaform/README.md new file mode 100644 index 0000000..4aee5c0 --- /dev/null +++ b/src/declaform/README.md @@ -0,0 +1 @@ +# Declaform diff --git a/src/declaform/declaform.ts b/src/declaform/declaform.ts new file mode 100644 index 0000000..77fe085 --- /dev/null +++ b/src/declaform/declaform.ts @@ -0,0 +1,68 @@ +export class Declaform extends HTMLElement { + + static observedAttributes = [ + 'customInputs', // Lets user specify additional inputs to be considered "fields" by the form. Example: + ] + + private _fields: Field[]; + private _form: HTMLFormElement; + + constructor() { + super(); + + this.attachInternals(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot!.innerHTML = '
'; + this._fields = []; + this._form = this.shadowRoot!.querySelector('form')!; + } + + connectedCallback() { + const customInputs = this.getAttribute('customInputs')?.split(',').map(x => x.trim()) ?? []; + const selectors = ['input', 'select'].concat(customInputs).map(x => `${x}[name]`).join(','); + const inputs = Array.from(this.querySelectorAll(selectors)); + // group inputs by name + const inputGroups = new Map(); + for (const input of inputs) { + const name = input.getAttribute('name'); + if (name) { + const group = inputGroups.get(name); + if (group) { + inputGroups.set(name, group.concat(input)) + } else { + inputGroups.set(name, [input]); + } + } + } + + for (const [name, inputs] of inputGroups.entries()) { + this._fields.push(new Field(name, inputs)) + } + } + + get form() { + return this._form; + } + + get fields() { + return this._fields; + } +} + +customElements.define('decla-form', Declaform); + +class Field { + constructor(private name: string, private _inputs: Element[]) { + } + + get value() { + return ''; + } + + set value(x: any) { + } + + get type() { + return ''; + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..94debee --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,44 @@ +{ + // Visit https://aka.ms/tsconfig to read more about this file + "compilerOptions": { + // File Layout + "rootDir": "./src", + "outDir": "./dist", + + // Environment Settings + // See also https://aka.ms/tsconfig/module + "module": "esnext", + "target": "es6", + "types": [], + // For nodejs: + // "lib": ["esnext"], + // "types": ["node"], + // and npm install -D @types/node + + // Other Outputs + "sourceMap": true, + "declaration": true, + "declarationMap": true, + + // Stricter Typechecking Options + "noUncheckedIndexedAccess": true, + "exactOptionalPropertyTypes": true, + + // Style Options + // "noImplicitReturns": true, + // "noImplicitOverride": true, + // "noUnusedLocals": true, + // "noUnusedParameters": true, + // "noFallthroughCasesInSwitch": true, + // "noPropertyAccessFromIndexSignature": true, + + // Recommended Options + "strict": true, + // "jsx": "react-jsx", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "noUncheckedSideEffectImports": true, + "moduleDetection": "force", + "skipLibCheck": true, + } +}