Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@vaadin/field-base

Package Overview
Dependencies
Maintainers
19
Versions
412
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vaadin/field-base - npm Package Compare versions

Comparing version 23.0.0-alpha2 to 23.0.0-alpha3

src/helper-controller.d.ts

6

package.json
{
"name": "@vaadin/field-base",
"version": "23.0.0-alpha2",
"version": "23.0.0-alpha3",
"publishConfig": {

@@ -34,3 +34,3 @@ "access": "public"

"@polymer/polymer": "^3.0.0",
"@vaadin/component-base": "23.0.0-alpha2",
"@vaadin/component-base": "23.0.0-alpha3",
"lit": "^2.0.0"

@@ -43,3 +43,3 @@ },

},
"gitHead": "070f586dead02ca41b66717820c647f48bf1665f"
"gitHead": "490037919a9e054cc002c1b3be0c94a1603e1a44"
}
/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -8,2 +8,3 @@ */

import { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
import { SlotMixinClass } from '@vaadin/component-base/src/slot-mixin.js';
import { LabelMixinClass } from './label-mixin.js';

@@ -21,2 +22,3 @@ import { ValidateMixinClass } from './validate-mixin.js';

Constructor<LabelMixinClass> &
Constructor<SlotMixinClass> &
Constructor<ValidateMixinClass>;

@@ -23,0 +25,0 @@

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { FlattenedNodesObserver } from '@polymer/polymer/lib/utils/flattened-nodes-observer.js';
import { animationFrame } from '@vaadin/component-base/src/async.js';
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { SlotMixin } from '@vaadin/component-base/src/slot-mixin.js';
import { FieldAriaController } from './field-aria-controller.js';
import { HelperController } from './helper-controller.js';
import { LabelMixin } from './label-mixin.js';

@@ -20,6 +19,7 @@ import { ValidateMixin } from './validate-mixin.js';

* @mixes LabelMixin
* @mixes SlotMixin
* @mixes ValidateMixin
*/
export const FieldMixin = (superclass) =>
class FieldMixinClass extends ValidateMixin(LabelMixin(ControllerMixin(superclass))) {
class FieldMixinClass extends ValidateMixin(LabelMixin(ControllerMixin(SlotMixin(superclass)))) {
static get properties() {

@@ -72,9 +72,3 @@ return {

static get observers() {
return [
'__observeOffsetHeight(errorMessage, invalid, label, helperText)',
'_updateErrorMessage(invalid, errorMessage)',
'_invalidChanged(invalid)',
'_requiredChanged(required)',
'_helperIdChanged(_helperId)'
];
return ['_updateErrorMessage(invalid, errorMessage)', '_invalidChanged(invalid)', '_requiredChanged(required)'];
}

@@ -90,2 +84,7 @@

/** @protected */
get _helperId() {
return this._helperController.helperId;
}
/**

@@ -96,3 +95,3 @@ * @protected

get _helperNode() {
return this._getDirectSlotChild('helper');
return this._helperController.node;
}

@@ -106,8 +105,18 @@

this._errorId = `error-${this.localName}-${uniqueId}`;
this._helperId = `helper-${this.localName}-${uniqueId}`;
// Save generated ID to restore later
this.__savedHelperId = this._helperId;
this._fieldAriaController = new FieldAriaController(this);
this._helperController = new HelperController(this);
this._fieldAriaController = new FieldAriaController(this);
this.addController(this._fieldAriaController);
this.addController(this._helperController);
this._labelController.addEventListener('label-changed', (event) => {
const { hasLabel, node } = event.detail;
this.__labelChanged(hasLabel, node);
});
this._helperController.addEventListener('helper-changed', (event) => {
const { hasHelper, node } = event.detail;
this.__helperChanged(hasHelper, node);
});
}

@@ -127,50 +136,2 @@

}
const helper = this._helperNode;
if (helper) {
this.__applyCustomHelper(helper);
}
this.__helperSlot = this.shadowRoot.querySelector('[name="helper"]');
this.__helperSlotObserver = new FlattenedNodesObserver(this.__helperSlot, (info) => {
const helper = this._currentHelper;
const newHelper = info.addedNodes.find((node) => node !== helper);
const oldHelper = info.removedNodes.find((node) => node === helper);
if (newHelper) {
// Custom helper is added, remove the previous one.
if (helper && helper.isConnected) {
this.removeChild(helper);
}
this.__applyCustomHelper(newHelper);
this.__helperIdObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
// only handle helper nodes
if (
mutation.type === 'attributes' &&
mutation.attributeName === 'id' &&
mutation.target === this._currentHelper &&
mutation.target.id !== this.__savedHelperId
) {
this.__updateHelperId(mutation.target);
}
});
});
this.__helperIdObserver.observe(newHelper, { attributes: true });
} else if (oldHelper) {
// The observer does not exist when default helper is removed.
if (this.__helperIdObserver) {
this.__helperIdObserver.disconnect();
}
this.__applyDefaultHelper(this.helperText);
}
});
this.addController(this._fieldAriaController);
}

@@ -187,103 +148,17 @@

/**
* @param {HTMLElement} helper
* @private
*/
__applyCustomHelper(helper) {
this.__updateHelperId(helper);
this._currentHelper = helper;
this.__toggleHasHelper(helper.children.length > 0 || this.__isNotEmpty(helper.textContent));
}
/**
* @param {string} helperText
* @private
*/
__isNotEmpty(helperText) {
return helperText && helperText.trim() !== '';
}
/** @private */
__attachDefaultHelper() {
let helper = this.__defaultHelper;
if (!helper) {
helper = document.createElement('div');
helper.setAttribute('slot', 'helper');
this.__defaultHelper = helper;
__helperChanged(hasHelper, helperNode) {
if (hasHelper) {
this._fieldAriaController.setHelperId(helperNode.id);
} else {
this._fieldAriaController.setHelperId(null);
}
helper.id = this.__savedHelperId;
this._helperId = helper.id;
this.appendChild(helper);
this._currentHelper = helper;
return helper;
}
/**
* @param {string} helperText
* @private
*/
__applyDefaultHelper(helperText) {
let helper = this._helperNode;
const hasHelperText = this.__isNotEmpty(helperText);
if (hasHelperText && !helper) {
// Create helper lazily
helper = this.__attachDefaultHelper();
}
// Only set text content for default helper
if (helper && helper === this.__defaultHelper) {
helper.textContent = helperText;
}
this.__toggleHasHelper(hasHelperText);
}
/**
* @param {boolean} hasHelper
* @private
*/
__toggleHasHelper(hasHelper) {
this.toggleAttribute('has-helper', hasHelper);
}
/**
* Dispatch an event if a specific size measurement property has changed.
* Supporting multiple properties here is needed for `vaadin-text-area`.
* @protected
*/
_dispatchIronResizeEventIfNeeded(prop, value) {
const oldSize = '__old' + prop;
if (this[oldSize] !== undefined && this[oldSize] !== value) {
this.dispatchEvent(new CustomEvent('iron-resize', { bubbles: true, composed: true }));
}
this[oldSize] = value;
}
/** @private */
__observeOffsetHeight() {
this.__observeOffsetHeightDebouncer = Debouncer.debounce(
this.__observeOffsetHeightDebouncer,
animationFrame,
() => {
this._dispatchIronResizeEventIfNeeded('Height', this.offsetHeight);
}
);
}
/**
* @protected
* @override
*/
_toggleHasLabelAttribute() {
super._toggleHasLabelAttribute();
__labelChanged(hasLabel, labelNode) {
// Label ID should be only added when the label content is present.
// Otherwise, it may conflict with an `aria-label` attribute possibly added by the user.
if (this.hasAttribute('has-label')) {
this._fieldAriaController.setLabelId(this._labelId);
if (hasLabel) {
this._fieldAriaController.setLabelId(labelNode.id);
} else {

@@ -324,19 +199,2 @@ this._fieldAriaController.setLabelId(null);

/**
* @param {HTMLElement} customHelper
* @private
*/
__updateHelperId(customHelper) {
let newId;
if (customHelper.id) {
newId = customHelper.id;
} else {
newId = this.__savedHelperId;
customHelper.id = newId;
}
this._helperId = newId;
}
/**
* @param {string} helperText

@@ -346,3 +204,3 @@ * @protected

_helperTextChanged(helperText) {
this.__applyDefaultHelper(helperText);
this._helperController.setHelperText(helperText);
}

@@ -369,10 +227,2 @@

/**
* @param {string} helperId
* @protected
*/
_helperIdChanged(helperId) {
this._fieldAriaController.setHelperId(helperId);
}
/**
* @param {boolean} required

@@ -379,0 +229,0 @@ * @protected

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -8,2 +8,3 @@ */

import { SlotMixinClass } from '@vaadin/component-base/src/slot-mixin.js';
import { LabelController } from './label-controller.js';

@@ -25,5 +26,5 @@ /**

protected _labelController: LabelController;
protected _labelChanged(label: string | null | undefined): void;
protected _toggleHasLabelAttribute(): void;
}
/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
import { SlotMixin } from '@vaadin/component-base/src/slot-mixin.js';
import { ControllerMixin } from '@vaadin/component-base/src/controller-mixin.js';
import { LabelController } from './label-controller.js';

@@ -17,3 +18,3 @@ /**

(superclass) =>
class LabelMixinClass extends SlotMixin(superclass) {
class LabelMixinClass extends ControllerMixin(superclass) {
static get properties() {

@@ -33,11 +34,4 @@ return {

/** @protected */
get slots() {
return {
...super.slots,
label: () => {
const label = document.createElement('label');
label.textContent = this.label;
return label;
}
};
get _labelId() {
return this._labelController.labelId;
}

@@ -47,3 +41,3 @@

get _labelNode() {
return this._getDirectSlotChild('label');
return this._labelController.node;
}

@@ -54,44 +48,11 @@

// Ensure every instance has unique ID
const uniqueId = (LabelMixinClass._uniqueLabelId = 1 + LabelMixinClass._uniqueLabelId || 0);
this._labelId = `label-${this.localName}-${uniqueId}`;
/**
* @type {MutationObserver}
* @private
*/
this.__labelNodeObserver = new MutationObserver(() => {
this._toggleHasLabelAttribute();
});
this._labelController = new LabelController(this);
this.addController(this._labelController);
}
/** @protected */
ready() {
super.ready();
if (this._labelNode) {
this._labelNode.id = this._labelId;
this._toggleHasLabelAttribute();
this.__labelNodeObserver.observe(this._labelNode, { childList: true, subtree: true, characterData: true });
}
}
/** @protected */
_labelChanged(label) {
if (this._labelNode) {
this._labelNode.textContent = label;
this._toggleHasLabelAttribute();
}
this._labelController.setLabel(label);
}
/** @protected */
_toggleHasLabelAttribute() {
if (this._labelNode) {
const hasLabel = this._labelNode.children.length > 0 || this._labelNode.textContent.trim() !== '';
this.toggleAttribute('has-label', hasLabel);
}
}
}
);
/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -11,11 +11,24 @@ */

export class LabelledInputController {
constructor(input, label) {
constructor(input, labelController) {
this.input = input;
this.__preventDuplicateLabelClick = this.__preventDuplicateLabelClick.bind(this);
labelController.addEventListener('label-changed', (event) => {
this.__initLabel(event.detail.node);
});
// Initialize the default label element
this.__initLabel(labelController.node);
}
/**
* @param {HTMLElement} label
* @private
*/
__initLabel(label) {
if (label) {
label.addEventListener('click', this.__preventDuplicateLabelClick);
if (input) {
label.setAttribute('for', input.id);
if (this.input) {
label.setAttribute('for', this.input.id);
}

@@ -22,0 +35,0 @@ }

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -24,16 +24,3 @@ */

}
/** @protected */
ready() {
super.ready();
if (this._labelNode) {
// The default slot's content is moved to the label node
// only after `LabelMixin` is initialized which means
// we should manually toggle the `has-label` attribute
// respecting the new label content.
this._toggleHasLabelAttribute();
}
}
}
);
/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd..
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

/**
* @license
* Copyright (c) 2021 Vaadin Ltd.
* Copyright (c) 2021 - 2022 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/

@@ -5,0 +5,0 @@ */

Sorry, the diff of this file is not supported yet

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