@github/auto-check-element
Advanced tools
Comparing version 5.3.0 to 5.4.0
@@ -1,23 +0,4 @@ | ||
export default class AutoCheckElement extends HTMLElement { | ||
connectedCallback(): void; | ||
disconnectedCallback(): void; | ||
attributeChangedCallback(name: string): void; | ||
static get observedAttributes(): string[]; | ||
get input(): HTMLInputElement | null; | ||
get src(): string; | ||
set src(value: string); | ||
get csrf(): string; | ||
set csrf(value: string); | ||
get required(): boolean; | ||
set required(required: boolean); | ||
get csrfField(): string; | ||
set csrfField(value: string); | ||
} | ||
declare global { | ||
interface Window { | ||
AutoCheckElement: typeof AutoCheckElement; | ||
} | ||
interface HTMLElementTagNameMap { | ||
'auto-check': AutoCheckElement; | ||
} | ||
} | ||
import { AutoCheckElement } from './auto-check-element.js'; | ||
export { AutoCheckElement }; | ||
export default AutoCheckElement; | ||
export * from './auto-check-element-define.js'; |
@@ -1,248 +0,4 @@ | ||
function throttle(callback, wait = 0, { start = true, middle = true, once = false } = {}) { | ||
let last = 0; | ||
let timer; | ||
let cancelled = false; | ||
function fn(...args) { | ||
if (cancelled) | ||
return; | ||
const delta = Date.now() - last; | ||
last = Date.now(); | ||
if (start) { | ||
start = false; | ||
callback.apply(this, args); | ||
if (once) | ||
fn.cancel(); | ||
} | ||
else if ((middle && delta < wait) || !middle) { | ||
clearTimeout(timer); | ||
timer = setTimeout(() => { | ||
last = Date.now(); | ||
callback.apply(this, args); | ||
if (once) | ||
fn.cancel(); | ||
}, !middle ? wait : wait - delta); | ||
} | ||
} | ||
fn.cancel = () => { | ||
clearTimeout(timer); | ||
cancelled = true; | ||
}; | ||
return fn; | ||
} | ||
function debounce(callback, wait = 0, { start = false, middle = false, once = false } = {}) { | ||
return throttle(callback, wait, { start, middle, once }); | ||
} | ||
const states = new WeakMap(); | ||
class AutoCheckElement extends HTMLElement { | ||
connectedCallback() { | ||
const input = this.input; | ||
if (!input) | ||
return; | ||
const checker = debounce(check.bind(null, this), 300); | ||
const state = { check: checker, controller: null }; | ||
states.set(this, state); | ||
input.addEventListener('input', setLoadingState); | ||
input.addEventListener('input', checker); | ||
input.autocomplete = 'off'; | ||
input.spellcheck = false; | ||
} | ||
disconnectedCallback() { | ||
const input = this.input; | ||
if (!input) | ||
return; | ||
const state = states.get(this); | ||
if (!state) | ||
return; | ||
states.delete(this); | ||
input.removeEventListener('input', setLoadingState); | ||
input.removeEventListener('input', state.check); | ||
input.setCustomValidity(''); | ||
} | ||
attributeChangedCallback(name) { | ||
if (name === 'required') { | ||
const input = this.input; | ||
if (!input) | ||
return; | ||
input.required = this.required; | ||
} | ||
} | ||
static get observedAttributes() { | ||
return ['required']; | ||
} | ||
get input() { | ||
return this.querySelector('input'); | ||
} | ||
get src() { | ||
const src = this.getAttribute('src'); | ||
if (!src) | ||
return ''; | ||
const link = this.ownerDocument.createElement('a'); | ||
link.href = src; | ||
return link.href; | ||
} | ||
set src(value) { | ||
this.setAttribute('src', value); | ||
} | ||
get csrf() { | ||
const csrfElement = this.querySelector('[data-csrf]'); | ||
return this.getAttribute('csrf') || (csrfElement instanceof HTMLInputElement && csrfElement.value) || ''; | ||
} | ||
set csrf(value) { | ||
this.setAttribute('csrf', value); | ||
} | ||
get required() { | ||
return this.hasAttribute('required'); | ||
} | ||
set required(required) { | ||
if (required) { | ||
this.setAttribute('required', ''); | ||
} | ||
else { | ||
this.removeAttribute('required'); | ||
} | ||
} | ||
get csrfField() { | ||
return this.getAttribute('csrf-field') || 'authenticity_token'; | ||
} | ||
set csrfField(value) { | ||
this.setAttribute('csrf-field', value); | ||
} | ||
} | ||
function setLoadingState(event) { | ||
const input = event.currentTarget; | ||
if (!(input instanceof HTMLInputElement)) | ||
return; | ||
const autoCheckElement = input.closest('auto-check'); | ||
if (!(autoCheckElement instanceof AutoCheckElement)) | ||
return; | ||
const src = autoCheckElement.src; | ||
const csrf = autoCheckElement.csrf; | ||
const state = states.get(autoCheckElement); | ||
if (!src || !csrf || !state) { | ||
return; | ||
} | ||
let message = 'Verifying…'; | ||
const setValidity = (text) => (message = text); | ||
input.dispatchEvent(new CustomEvent('auto-check-start', { | ||
bubbles: true, | ||
detail: { setValidity } | ||
})); | ||
if (autoCheckElement.required) { | ||
input.setCustomValidity(message); | ||
} | ||
} | ||
function makeAbortController() { | ||
if ('AbortController' in window) { | ||
return new AbortController(); | ||
} | ||
return { | ||
signal: null, | ||
abort() { | ||
} | ||
}; | ||
} | ||
async function fetchWithNetworkEvents(el, url, options) { | ||
try { | ||
const response = await fetch(url, options); | ||
el.dispatchEvent(new CustomEvent('load')); | ||
el.dispatchEvent(new CustomEvent('loadend')); | ||
return response; | ||
} | ||
catch (error) { | ||
if (error.name !== 'AbortError') { | ||
el.dispatchEvent(new CustomEvent('error')); | ||
el.dispatchEvent(new CustomEvent('loadend')); | ||
} | ||
throw error; | ||
} | ||
} | ||
async function check(autoCheckElement) { | ||
const input = autoCheckElement.input; | ||
if (!input) { | ||
return; | ||
} | ||
const csrfField = autoCheckElement.csrfField; | ||
const src = autoCheckElement.src; | ||
const csrf = autoCheckElement.csrf; | ||
const state = states.get(autoCheckElement); | ||
if (!src || !csrf || !state) { | ||
if (autoCheckElement.required) { | ||
input.setCustomValidity(''); | ||
} | ||
return; | ||
} | ||
if (!input.value.trim()) { | ||
if (autoCheckElement.required) { | ||
input.setCustomValidity(''); | ||
} | ||
return; | ||
} | ||
const body = new FormData(); | ||
body.append(csrfField, csrf); | ||
body.append('value', input.value); | ||
input.dispatchEvent(new CustomEvent('auto-check-send', { | ||
bubbles: true, | ||
detail: { body } | ||
})); | ||
if (state.controller) { | ||
state.controller.abort(); | ||
} | ||
else { | ||
autoCheckElement.dispatchEvent(new CustomEvent('loadstart')); | ||
} | ||
state.controller = makeAbortController(); | ||
try { | ||
const response = await fetchWithNetworkEvents(autoCheckElement, src, { | ||
credentials: 'same-origin', | ||
signal: state.controller.signal, | ||
method: 'POST', | ||
body | ||
}); | ||
if (response.ok) { | ||
processSuccess(response, input, autoCheckElement.required); | ||
} | ||
else { | ||
processFailure(response, input, autoCheckElement.required); | ||
} | ||
state.controller = null; | ||
input.dispatchEvent(new CustomEvent('auto-check-complete', { bubbles: true })); | ||
} | ||
catch (error) { | ||
if (error.name !== 'AbortError') { | ||
state.controller = null; | ||
input.dispatchEvent(new CustomEvent('auto-check-complete', { bubbles: true })); | ||
} | ||
} | ||
} | ||
function processSuccess(response, input, required) { | ||
if (required) { | ||
input.setCustomValidity(''); | ||
} | ||
input.dispatchEvent(new CustomEvent('auto-check-success', { | ||
bubbles: true, | ||
detail: { | ||
response: response.clone() | ||
} | ||
})); | ||
} | ||
function processFailure(response, input, required) { | ||
let message = 'Validation failed'; | ||
const setValidity = (text) => (message = text); | ||
input.dispatchEvent(new CustomEvent('auto-check-error', { | ||
bubbles: true, | ||
detail: { | ||
response: response.clone(), | ||
setValidity | ||
} | ||
})); | ||
if (required) { | ||
input.setCustomValidity(message); | ||
} | ||
} | ||
if (!window.customElements.get('auto-check')) { | ||
window.AutoCheckElement = AutoCheckElement; | ||
window.customElements.define('auto-check', AutoCheckElement); | ||
} | ||
import { AutoCheckElement } from './auto-check-element.js'; | ||
export { AutoCheckElement }; | ||
export default AutoCheckElement; | ||
export * from './auto-check-element-define.js'; |
107
package.json
{ | ||
"name": "@github/auto-check-element", | ||
"version": "5.3.0", | ||
"description": "An input element that validates its value with a server endpoint.", | ||
"repository": "github/auto-check-element", | ||
"files": [ | ||
"dist" | ||
], | ||
"main": "dist/index.js", | ||
"module": "dist/index.js", | ||
"type": "module", | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"clean": "rm -rf dist/", | ||
"lint": "eslint . --ext .js,.ts && tsc --noEmit", | ||
"prebuild": "npm run clean && npm run lint", | ||
"build": "tsc && rollup -c", | ||
"pretest": "npm run build", | ||
"test": "karma start test/karma.config.cjs", | ||
"prepublishOnly": "npm run build", | ||
"postpublish": "npm publish --ignore-scripts --@github:registry='https://npm.pkg.github.com'" | ||
}, | ||
"keywords": [ | ||
"custom element", | ||
"web component", | ||
"auto-check", | ||
"input" | ||
], | ||
"license": "MIT", | ||
"prettier": "@github/prettier-config", | ||
"devDependencies": { | ||
"@github/prettier-config": "0.0.4", | ||
"chai": "^4.3.4", | ||
"chromium": "^3.0.3", | ||
"eslint": "^7.25.0", | ||
"eslint-plugin-custom-elements": "^0.0.2", | ||
"eslint-plugin-github": "^4.1.3", | ||
"karma": "^6.3.2", | ||
"karma-chai": "^0.1.0", | ||
"karma-chrome-launcher": "^3.1.0", | ||
"karma-mocha": "^2.0.1", | ||
"karma-mocha-reporter": "^2.2.5", | ||
"mocha": "^8.3.2", | ||
"rollup": "^2.45.2", | ||
"rollup-plugin-node-resolve": "^5.2.0", | ||
"typescript": "^4.2.4" | ||
}, | ||
"dependencies": { | ||
"@github/mini-throttle": "^2.1.0" | ||
} | ||
"name": "@github/auto-check-element", | ||
"version": "5.4.0", | ||
"description": "An input element that validates its value with a server endpoint.", | ||
"repository": "github/auto-check-element", | ||
"files": [ | ||
"dist" | ||
], | ||
"main": "dist/bundle.js", | ||
"module": "dist/index.js", | ||
"type": "module", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
".": "./dist/index.js", | ||
"./define": "./dist/index.js", | ||
"./auto-check": "./dist/auto-check-element.js", | ||
"./auto-check/define": "./dist/auto-check-element-define.js" | ||
}, | ||
"scripts": { | ||
"clean": "rm -rf dist/", | ||
"lint": "eslint . --ext .js,.ts && tsc --noEmit", | ||
"lint:fix": "npm run lint -- --fix", | ||
"prebuild": "npm run clean && npm run lint && mkdir dist", | ||
"bundle": "esbuild --bundle dist/index.js --keep-names --outfile=dist/bundle.js --format=esm", | ||
"build": "tsc && npm run bundle && npm run manifest", | ||
"prepublishOnly": "npm run build", | ||
"pretest": "npm run build", | ||
"test": "web-test-runner", | ||
"postpublish": "npm publish --ignore-scripts --@github:registry='https://npm.pkg.github.com'", | ||
"manifest": "custom-elements-manifest analyze" | ||
}, | ||
"keywords": [ | ||
"custom element", | ||
"web component", | ||
"auto-check", | ||
"input" | ||
], | ||
"license": "MIT", | ||
"prettier": "@github/prettier-config", | ||
"devDependencies": { | ||
"@custom-elements-manifest/analyzer": "^0.8.0", | ||
"@github/prettier-config": "^0.0.6", | ||
"@open-wc/testing": "^3.1.8", | ||
"@web/dev-server-esbuild": "^0.3.6", | ||
"@web/test-runner": "^0.15.3", | ||
"@web/test-runner-playwright": "^0.9.0", | ||
"esbuild": "^0.17.17", | ||
"eslint": "^8.38.0", | ||
"eslint-plugin-custom-elements": "^0.0.8", | ||
"eslint-plugin-github": "^4.7.0", | ||
"typescript": "^5.0.4" | ||
}, | ||
"eslintIgnore": [ | ||
"dist/" | ||
], | ||
"dependencies": { | ||
"@github/mini-throttle": "^2.1.0" | ||
}, | ||
"customElements": "custom-elements.json" | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
30125
11
10
687
3